blob: e5f2749f78ec287bd1e066e80e297dacf13ec313 [file] [log] [blame]
ethannicholasb3058bd2016-07-01 08:22:01 -07001/*
2 * Copyright 2016 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
Mike Klein6ad99092016-10-26 10:35:22 -04007
Mike Kleinc0bd9f92019-04-23 12:05:21 -05008#include "src/sksl/SkSLCompiler.h"
ethannicholasb3058bd2016-07-01 08:22:01 -07009
John Stilesfbd050b2020-08-03 13:21:46 -040010#include <memory>
John Stilesb8e010c2020-08-11 18:05:39 -040011#include <unordered_set>
John Stilesfbd050b2020-08-03 13:21:46 -040012
John Stilesb92641c2020-08-31 18:09:01 -040013#include "src/sksl/SkSLAnalysis.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050014#include "src/sksl/SkSLCFGGenerator.h"
15#include "src/sksl/SkSLCPPCodeGenerator.h"
16#include "src/sksl/SkSLGLSLCodeGenerator.h"
17#include "src/sksl/SkSLHCodeGenerator.h"
18#include "src/sksl/SkSLIRGenerator.h"
19#include "src/sksl/SkSLMetalCodeGenerator.h"
Brian Osman00185012021-02-04 16:07:11 -050020#include "src/sksl/SkSLOperators.h"
Ethan Nicholasc18bb512020-07-28 14:46:53 -040021#include "src/sksl/SkSLRehydrator.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050022#include "src/sksl/SkSLSPIRVCodeGenerator.h"
Brian Osmanc0243912020-02-19 15:35:26 -050023#include "src/sksl/SkSLSPIRVtoHLSL.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050024#include "src/sksl/ir/SkSLEnum.h"
25#include "src/sksl/ir/SkSLExpression.h"
26#include "src/sksl/ir/SkSLExpressionStatement.h"
27#include "src/sksl/ir/SkSLFunctionCall.h"
28#include "src/sksl/ir/SkSLIntLiteral.h"
29#include "src/sksl/ir/SkSLModifiersDeclaration.h"
30#include "src/sksl/ir/SkSLNop.h"
31#include "src/sksl/ir/SkSLSymbolTable.h"
32#include "src/sksl/ir/SkSLTernaryExpression.h"
33#include "src/sksl/ir/SkSLUnresolvedFunction.h"
34#include "src/sksl/ir/SkSLVarDeclarations.h"
John Stilese6150002020-10-05 12:03:53 -040035#include "src/utils/SkBitSet.h"
ethannicholasb3058bd2016-07-01 08:22:01 -070036
Ethan Nicholasb33fa3f2020-08-06 13:00:19 -040037#include <fstream>
38
Ethan Nicholasa11035b2019-11-26 16:27:47 -050039#if !defined(SKSL_STANDALONE) & SK_SUPPORT_GPU
40#include "include/gpu/GrContextOptions.h"
41#include "src/gpu/GrShaderCaps.h"
42#endif
43
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -040044#ifdef SK_ENABLE_SPIRV_VALIDATION
45#include "spirv-tools/libspirv.hpp"
46#endif
47
Brian Osman3d87e9f2020-10-08 11:50:22 -040048#if defined(SKSL_STANDALONE)
Ethan Nicholasc18bb512020-07-28 14:46:53 -040049
Brian Osman3d87e9f2020-10-08 11:50:22 -040050// In standalone mode, we load the textual sksl source files. GN generates or copies these files
51// to the skslc executable directory. The "data" in this mode is just the filename.
52#define MODULE_DATA(name) MakeModulePath("sksl_" #name ".sksl")
53
54#else
55
56// At runtime, we load the dehydrated sksl data files. The data is a (pointer, size) pair.
Ethan Nicholasc18bb512020-07-28 14:46:53 -040057#include "src/sksl/generated/sksl_fp.dehydrated.sksl"
58#include "src/sksl/generated/sksl_frag.dehydrated.sksl"
59#include "src/sksl/generated/sksl_geom.dehydrated.sksl"
60#include "src/sksl/generated/sksl_gpu.dehydrated.sksl"
Brian Osmanb06301e2020-11-06 11:45:36 -050061#include "src/sksl/generated/sksl_public.dehydrated.sksl"
Brian Osman91946752020-12-21 13:20:40 -050062#include "src/sksl/generated/sksl_runtime.dehydrated.sksl"
Ethan Nicholasc18bb512020-07-28 14:46:53 -040063#include "src/sksl/generated/sksl_vert.dehydrated.sksl"
64
Brian Osman3d87e9f2020-10-08 11:50:22 -040065#define MODULE_DATA(name) MakeModuleData(SKSL_INCLUDE_sksl_##name,\
66 SKSL_INCLUDE_sksl_##name##_LENGTH)
Ethan Nicholasc18bb512020-07-28 14:46:53 -040067
68#endif
Ethan Nicholas0d997662019-04-08 09:46:01 -040069
ethannicholasb3058bd2016-07-01 08:22:01 -070070namespace SkSL {
71
John Stiles47c0a742021-02-09 09:30:35 -050072using RefKind = VariableReference::RefKind;
73
Brian Osman88cda172020-10-09 12:05:16 -040074class AutoSource {
75public:
76 AutoSource(Compiler* compiler, const String* source)
77 : fCompiler(compiler), fOldSource(fCompiler->fSource) {
78 fCompiler->fSource = source;
79 }
80
81 ~AutoSource() { fCompiler->fSource = fOldSource; }
82
83 Compiler* fCompiler;
84 const String* fOldSource;
85};
86
Brian Osmand7e76592020-11-02 12:26:22 -050087Compiler::Compiler(const ShaderCapsClass* caps, Flags flags)
John Stilesb30151e2021-01-11 16:13:08 -050088 : fContext(std::make_shared<Context>(/*errors=*/*this))
Brian Osman0006ad02020-11-18 15:38:39 -050089 , fCaps(caps)
John Stiles7b920442020-12-17 10:43:41 -050090 , fInliner(fContext.get())
Brian Osman0006ad02020-11-18 15:38:39 -050091 , fFlags(flags)
92 , fErrorCount(0) {
93 SkASSERT(fCaps);
John Stiles7c3515b2020-10-16 18:38:39 -040094 fRootSymbolTable = std::make_shared<SymbolTable>(this, /*builtin=*/true);
Brian Osmanb06301e2020-11-06 11:45:36 -050095 fPrivateSymbolTable = std::make_shared<SymbolTable>(fRootSymbolTable, /*builtin=*/true);
John Stilesb30151e2021-01-11 16:13:08 -050096 fIRGenerator = std::make_unique<IRGenerator>(fContext.get(), fCaps);
ethannicholasb3058bd2016-07-01 08:22:01 -070097
John Stiles54e7c052021-01-11 14:22:36 -050098#define TYPE(t) fContext->fTypes.f ## t .get()
ethannicholasb3058bd2016-07-01 08:22:01 -070099
Brian Osmanb06301e2020-11-06 11:45:36 -0500100 const SkSL::Symbol* rootTypes[] = {
101 TYPE(Void),
Brian Salomonbf7b6202016-11-11 16:08:03 -0500102
Brian Osmanb06301e2020-11-06 11:45:36 -0500103 TYPE( Float), TYPE( Float2), TYPE( Float3), TYPE( Float4),
104 TYPE( Half), TYPE( Half2), TYPE( Half3), TYPE( Half4),
105 TYPE( Int), TYPE( Int2), TYPE( Int3), TYPE( Int4),
Brian Osmanb06301e2020-11-06 11:45:36 -0500106 TYPE( Bool), TYPE( Bool2), TYPE( Bool3), TYPE( Bool4),
Brian Salomon2a51de82016-11-16 12:06:01 -0500107
Brian Osmanc0f2b642020-12-22 13:35:55 -0500108 TYPE(Float2x2), TYPE(Float3x3), TYPE(Float4x4),
Brian Osmanc63f4312020-12-23 11:44:14 -0500109 TYPE( Half2x2), TYPE( Half3x3), TYPE(Half4x4),
Greg Daniel64773e62016-11-22 09:44:03 -0500110
Brian Osmanc63f4312020-12-23 11:44:14 -0500111 TYPE(SquareMat), TYPE(SquareHMat),
ethannicholasb3058bd2016-07-01 08:22:01 -0700112
Brian Osman20fad322020-12-23 12:42:33 -0500113 TYPE(GenType), TYPE(GenHType), TYPE(GenIType), TYPE(GenBType),
114 TYPE(Vec), TYPE(HVec), TYPE(IVec), TYPE(BVec),
Brian Osmanb06301e2020-11-06 11:45:36 -0500115
116 TYPE(FragmentProcessor),
117 };
118
119 const SkSL::Symbol* privateTypes[] = {
Brian Osman20fad322020-12-23 12:42:33 -0500120 TYPE( UInt), TYPE( UInt2), TYPE( UInt3), TYPE( UInt4),
121 TYPE( Short), TYPE( Short2), TYPE( Short3), TYPE( Short4),
122 TYPE(UShort), TYPE(UShort2), TYPE(UShort3), TYPE(UShort4),
123 TYPE( Byte), TYPE( Byte2), TYPE( Byte3), TYPE( Byte4),
124 TYPE( UByte), TYPE( UByte2), TYPE( UByte3), TYPE( UByte4),
125
126 TYPE(GenUType), TYPE(UVec),
127 TYPE(SVec), TYPE(USVec), TYPE(ByteVec), TYPE(UByteVec),
128
Brian Osmanc0f2b642020-12-22 13:35:55 -0500129 TYPE(Float2x3), TYPE(Float2x4),
130 TYPE(Float3x2), TYPE(Float3x4),
131 TYPE(Float4x2), TYPE(Float4x3),
132
Brian Osmanc63f4312020-12-23 11:44:14 -0500133 TYPE(Half2x3), TYPE(Half2x4),
134 TYPE(Half3x2), TYPE(Half3x4),
135 TYPE(Half4x2), TYPE(Half4x3),
136
Brian Osmanc0f2b642020-12-22 13:35:55 -0500137 TYPE(Mat), TYPE(HMat),
138
Brian Osmanb06301e2020-11-06 11:45:36 -0500139 TYPE(Sampler1D), TYPE(Sampler2D), TYPE(Sampler3D),
140 TYPE(SamplerExternalOES),
Brian Osmanb06301e2020-11-06 11:45:36 -0500141 TYPE(Sampler2DRect),
Brian Osmanb06301e2020-11-06 11:45:36 -0500142
143 TYPE(ISampler2D),
144 TYPE(Image2D), TYPE(IImage2D),
145 TYPE(SubpassInput), TYPE(SubpassInputMS),
146
Brian Osmanb06301e2020-11-06 11:45:36 -0500147 TYPE(Sampler),
148 TYPE(Texture2D),
149 };
150
151 for (const SkSL::Symbol* type : rootTypes) {
152 fRootSymbolTable->addWithoutOwnership(type);
153 }
154 for (const SkSL::Symbol* type : privateTypes) {
155 fPrivateSymbolTable->addWithoutOwnership(type);
156 }
157
158#undef TYPE
ethannicholasb3058bd2016-07-01 08:22:01 -0700159
Brian Osman3887a012020-09-30 13:22:27 -0400160 // sk_Caps is "builtin", but all references to it are resolved to Settings, so we don't need to
161 // treat it as builtin (ie, no need to clone it into the Program).
Brian Osmanb06301e2020-11-06 11:45:36 -0500162 fPrivateSymbolTable->add(
163 std::make_unique<Variable>(/*offset=*/-1,
John Stiles586df952020-11-12 18:27:13 -0500164 fIRGenerator->fModifiers->addToPool(Modifiers()),
Brian Osmanb06301e2020-11-06 11:45:36 -0500165 "sk_Caps",
John Stiles54e7c052021-01-11 14:22:36 -0500166 fContext->fTypes.fSkCaps.get(),
Brian Osmanb06301e2020-11-06 11:45:36 -0500167 /*builtin=*/false,
168 Variable::Storage::kGlobal));
Ethan Nicholas3605ace2016-11-21 15:59:48 -0500169
Brian Osman3d87e9f2020-10-08 11:50:22 -0400170 fRootModule = {fRootSymbolTable, /*fIntrinsics=*/nullptr};
Brian Osmanb06301e2020-11-06 11:45:36 -0500171 fPrivateModule = {fPrivateSymbolTable, /*fIntrinsics=*/nullptr};
ethannicholasb3058bd2016-07-01 08:22:01 -0700172}
173
John Stilesdd13dba2020-10-29 10:45:34 -0400174Compiler::~Compiler() {}
ethannicholasb3058bd2016-07-01 08:22:01 -0700175
Brian Osman56269982020-11-20 12:38:07 -0500176const ParsedModule& Compiler::loadGPUModule() {
177 if (!fGPUModule.fSymbols) {
178 fGPUModule = this->parseModule(Program::kFragment_Kind, MODULE_DATA(gpu), fPrivateModule);
179 }
180 return fGPUModule;
181}
182
183const ParsedModule& Compiler::loadFragmentModule() {
184 if (!fFragmentModule.fSymbols) {
185 fFragmentModule = this->parseModule(Program::kFragment_Kind, MODULE_DATA(frag),
186 this->loadGPUModule());
187 }
188 return fFragmentModule;
189}
190
191const ParsedModule& Compiler::loadVertexModule() {
192 if (!fVertexModule.fSymbols) {
193 fVertexModule = this->parseModule(Program::kVertex_Kind, MODULE_DATA(vert),
194 this->loadGPUModule());
195 }
196 return fVertexModule;
197}
198
Brian Osman88cda172020-10-09 12:05:16 -0400199const ParsedModule& Compiler::loadGeometryModule() {
Brian Osman3d87e9f2020-10-08 11:50:22 -0400200 if (!fGeometryModule.fSymbols) {
Brian Osman56269982020-11-20 12:38:07 -0500201 fGeometryModule = this->parseModule(Program::kGeometry_Kind, MODULE_DATA(geom),
202 this->loadGPUModule());
Ethan Nicholasc18bb512020-07-28 14:46:53 -0400203 }
Brian Osman88cda172020-10-09 12:05:16 -0400204 return fGeometryModule;
Ethan Nicholasc18bb512020-07-28 14:46:53 -0400205}
206
Brian Osman88cda172020-10-09 12:05:16 -0400207const ParsedModule& Compiler::loadFPModule() {
Brian Osman3d87e9f2020-10-08 11:50:22 -0400208 if (!fFPModule.fSymbols) {
Brian Osman56269982020-11-20 12:38:07 -0500209 fFPModule = this->parseModule(Program::kFragmentProcessor_Kind, MODULE_DATA(fp),
210 this->loadGPUModule());
Brian Osman8e2ef022020-09-30 13:26:43 -0400211 }
Brian Osman88cda172020-10-09 12:05:16 -0400212 return fFPModule;
Brian Osman8e2ef022020-09-30 13:26:43 -0400213}
214
Brian Osmanb06301e2020-11-06 11:45:36 -0500215const ParsedModule& Compiler::loadPublicModule() {
216 if (!fPublicModule.fSymbols) {
217 fPublicModule = this->parseModule(Program::kGeneric_Kind, MODULE_DATA(public), fRootModule);
218 }
219 return fPublicModule;
220}
221
Brian Osman91946752020-12-21 13:20:40 -0500222const ParsedModule& Compiler::loadRuntimeEffectModule() {
223 if (!fRuntimeEffectModule.fSymbols) {
224 fRuntimeEffectModule = this->parseModule(Program::kRuntimeEffect_Kind, MODULE_DATA(runtime),
225 this->loadPublicModule());
Brian Osmanf1319c32020-10-13 09:34:23 -0400226
Brian Osman91946752020-12-21 13:20:40 -0500227 // Add some aliases to the runtime effect module so that it's friendlier, and more like GLSL
John Stiles54e7c052021-01-11 14:22:36 -0500228 fRuntimeEffectModule.fSymbols->addAlias("shader", fContext->fTypes.fFragmentProcessor.get());
Brian Osmanf1319c32020-10-13 09:34:23 -0400229
John Stiles54e7c052021-01-11 14:22:36 -0500230 fRuntimeEffectModule.fSymbols->addAlias("vec2", fContext->fTypes.fFloat2.get());
231 fRuntimeEffectModule.fSymbols->addAlias("vec3", fContext->fTypes.fFloat3.get());
232 fRuntimeEffectModule.fSymbols->addAlias("vec4", fContext->fTypes.fFloat4.get());
Brian Osmanf1319c32020-10-13 09:34:23 -0400233
John Stiles54e7c052021-01-11 14:22:36 -0500234 fRuntimeEffectModule.fSymbols->addAlias("bvec2", fContext->fTypes.fBool2.get());
235 fRuntimeEffectModule.fSymbols->addAlias("bvec3", fContext->fTypes.fBool3.get());
236 fRuntimeEffectModule.fSymbols->addAlias("bvec4", fContext->fTypes.fBool4.get());
Brian Osmanf1319c32020-10-13 09:34:23 -0400237
John Stiles54e7c052021-01-11 14:22:36 -0500238 fRuntimeEffectModule.fSymbols->addAlias("mat2", fContext->fTypes.fFloat2x2.get());
239 fRuntimeEffectModule.fSymbols->addAlias("mat3", fContext->fTypes.fFloat3x3.get());
240 fRuntimeEffectModule.fSymbols->addAlias("mat4", fContext->fTypes.fFloat4x4.get());
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
Brian Osman88cda172020-10-09 12:05:16 -0400245const ParsedModule& Compiler::moduleForProgramKind(Program::Kind kind) {
246 switch (kind) {
Brian Osman91946752020-12-21 13:20:40 -0500247 case Program::kVertex_Kind: return this->loadVertexModule(); break;
248 case Program::kFragment_Kind: return this->loadFragmentModule(); break;
249 case Program::kGeometry_Kind: return this->loadGeometryModule(); break;
250 case Program::kFragmentProcessor_Kind: return this->loadFPModule(); break;
251 case Program::kRuntimeEffect_Kind: return this->loadRuntimeEffectModule(); break;
Brian Osmance750362021-01-21 16:33:06 -0500252 case Program::kGeneric_Kind: return this->loadPublicModule(); break;
Brian Osman88cda172020-10-09 12:05:16 -0400253 }
254 SkUNREACHABLE;
Ethan Nicholasc18bb512020-07-28 14:46:53 -0400255}
256
Brian Osman3d87e9f2020-10-08 11:50:22 -0400257LoadedModule Compiler::loadModule(Program::Kind kind,
258 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;
Brian Osman88cda172020-10-09 12:05:16 -0400285 ParsedModule baseModule = {base, /*fIntrinsics=*/nullptr};
Brian Osmand7e76592020-11-02 12:26:22 -0500286 IRGenerator::IRBundle ir =
Brian Osman0006ad02020-11-18 15:38:39 -0500287 fIRGenerator->convertProgram(kind, &settings, baseModule,
Brian Osmand7e76592020-11-02 12:26:22 -0500288 /*isBuiltinCode=*/true, source->c_str(), source->length(),
Brian Osmanbe0b3b72021-01-06 14:27:35 -0500289 /*externalFunctions=*/nullptr);
Brian Osman133724c2020-10-28 14:14:39 -0400290 SkASSERT(ir.fSharedElements.empty());
Brian Osman0006ad02020-11-18 15:38:39 -0500291 LoadedModule module = { kind, std::move(ir.fSymbolTable), std::move(ir.fElements) };
John Stiles881a10c2020-09-19 10:13:24 -0400292 fIRGenerator->fCanInline = true;
Ethan Nicholas8da1e652019-05-24 11:01:59 -0400293 if (this->fErrorCount) {
294 printf("Unexpected errors: %s\n", this->fErrorText.c_str());
Brian Osman3d87e9f2020-10-08 11:50:22 -0400295 SkDEBUGFAILF("%s %s\n", data.fPath, this->fErrorText.c_str());
Ethan Nicholas8da1e652019-05-24 11:01:59 -0400296 }
Brian Osman88cda172020-10-09 12:05:16 -0400297 fModifiers.push_back(std::move(ir.fModifiers));
Brian Osman3d87e9f2020-10-08 11:50:22 -0400298#else
299 SkASSERT(data.fData && (data.fSize != 0));
300 Rehydrator rehydrator(fContext.get(), fIRGenerator->fModifiers.get(), base, this,
301 data.fData, data.fSize);
Brian Osman0006ad02020-11-18 15:38:39 -0500302 LoadedModule module = { kind, rehydrator.symbolTable(), rehydrator.elements() };
Brian Osman3d87e9f2020-10-08 11:50:22 -0400303 fModifiers.push_back(fIRGenerator->releaseModifiers());
304#endif
305
306 return module;
307}
308
309ParsedModule Compiler::parseModule(Program::Kind kind, ModuleData data, const ParsedModule& base) {
Brian Osman0006ad02020-11-18 15:38:39 -0500310 LoadedModule module = this->loadModule(kind, data, base.fSymbols);
311 this->optimize(module);
Brian Osman3d87e9f2020-10-08 11:50:22 -0400312
313 // For modules that just declare (but don't define) intrinsic functions, there will be no new
314 // program elements. In that case, we can share our parent's intrinsic map:
Brian Osman0006ad02020-11-18 15:38:39 -0500315 if (module.fElements.empty()) {
316 return {module.fSymbols, base.fIntrinsics};
Brian Osman3d87e9f2020-10-08 11:50:22 -0400317 }
318
319 auto intrinsics = std::make_shared<IRIntrinsicMap>(base.fIntrinsics.get());
320
321 // Now, transfer all of the program elements to an intrinsic map. This maps certain types of
322 // global objects to the declaring ProgramElement.
Brian Osman0006ad02020-11-18 15:38:39 -0500323 for (std::unique_ptr<ProgramElement>& element : module.fElements) {
Brian Osman3d87e9f2020-10-08 11:50:22 -0400324 switch (element->kind()) {
325 case ProgramElement::Kind::kFunction: {
326 const FunctionDefinition& f = element->as<FunctionDefinition>();
Ethan Nicholas0a5d0962020-10-14 13:33:18 -0400327 SkASSERT(f.declaration().isBuiltin());
328 intrinsics->insertOrDie(f.declaration().description(), std::move(element));
Brian Osman3d87e9f2020-10-08 11:50:22 -0400329 break;
330 }
John Stiles569249b2020-11-03 12:18:22 -0500331 case ProgramElement::Kind::kFunctionPrototype: {
332 // These are already in the symbol table.
333 break;
334 }
Brian Osman3d87e9f2020-10-08 11:50:22 -0400335 case ProgramElement::Kind::kEnum: {
336 const Enum& e = element->as<Enum>();
337 SkASSERT(e.isBuiltin());
338 intrinsics->insertOrDie(e.typeName(), std::move(element));
339 break;
340 }
341 case ProgramElement::Kind::kGlobalVar: {
Ethan Nicholasc51f33e2020-10-13 13:49:44 -0400342 const GlobalVarDeclaration& global = element->as<GlobalVarDeclaration>();
343 const Variable& var = global.declaration()->as<VarDeclaration>().var();
344 SkASSERT(var.isBuiltin());
345 intrinsics->insertOrDie(var.name(), std::move(element));
Brian Osman3d87e9f2020-10-08 11:50:22 -0400346 break;
347 }
348 case ProgramElement::Kind::kInterfaceBlock: {
Ethan Nicholaseaf47882020-10-15 10:10:08 -0400349 const Variable& var = element->as<InterfaceBlock>().variable();
350 SkASSERT(var.isBuiltin());
351 intrinsics->insertOrDie(var.name(), std::move(element));
Brian Osman3d87e9f2020-10-08 11:50:22 -0400352 break;
353 }
354 default:
355 printf("Unsupported element: %s\n", element->description().c_str());
356 SkASSERT(false);
357 break;
358 }
359 }
360
Brian Osman0006ad02020-11-18 15:38:39 -0500361 return {module.fSymbols, std::move(intrinsics)};
Ethan Nicholas8da1e652019-05-24 11:01:59 -0400362}
363
John Stilese6150002020-10-05 12:03:53 -0400364void Compiler::scanCFG(CFG* cfg, BlockId blockId, SkBitSet* processedSet) {
ethannicholas22f939e2016-10-13 13:25:34 -0700365 BasicBlock& block = cfg->fBlocks[blockId];
366
367 // compute definitions after this block
Ethan Nicholas86a43402017-01-19 13:32:00 -0500368 DefinitionMap after = block.fBefore;
ethannicholas22f939e2016-10-13 13:25:34 -0700369 for (const BasicBlock::Node& n : block.fNodes) {
John Stilese8a24922021-02-08 17:54:08 -0500370 after.addDefinitions(*fContext, n);
ethannicholas22f939e2016-10-13 13:25:34 -0700371 }
372
373 // propagate definitions to exits
374 for (BlockId exitId : block.fExits) {
Ethan Nicholas26a9aad2018-03-27 14:10:52 -0400375 if (exitId == blockId) {
376 continue;
377 }
ethannicholas22f939e2016-10-13 13:25:34 -0700378 BasicBlock& exit = cfg->fBlocks[exitId];
John Stiles65b48272020-12-22 17:18:34 -0500379 for (const auto& [var, e1] : after) {
John Stiles796cdb72020-10-08 12:06:53 -0400380 std::unique_ptr<Expression>** exitDef = exit.fBefore.find(var);
381 if (!exitDef) {
John Stilese6150002020-10-05 12:03:53 -0400382 // exit has no definition for it, just copy it and reprocess exit block
383 processedSet->reset(exitId);
John Stilese8a24922021-02-08 17:54:08 -0500384 exit.fBefore.set(var, e1);
ethannicholas22f939e2016-10-13 13:25:34 -0700385 } else {
Ethan Nicholas86a43402017-01-19 13:32:00 -0500386 // exit has a (possibly different) value already defined
John Stiles796cdb72020-10-08 12:06:53 -0400387 std::unique_ptr<Expression>* e2 = *exitDef;
ethannicholas22f939e2016-10-13 13:25:34 -0700388 if (e1 != e2) {
John Stilese6150002020-10-05 12:03:53 -0400389 // definition has changed, merge and reprocess the exit block
390 processedSet->reset(exitId);
Ethan Nicholasaf197692017-02-27 13:26:45 -0500391 if (e1 && e2) {
John Stiles796cdb72020-10-08 12:06:53 -0400392 *exitDef = (std::unique_ptr<Expression>*)&fContext->fDefined_Expression;
Ethan Nicholasaf197692017-02-27 13:26:45 -0500393 } else {
John Stiles796cdb72020-10-08 12:06:53 -0400394 *exitDef = nullptr;
Ethan Nicholasaf197692017-02-27 13:26:45 -0500395 }
ethannicholas22f939e2016-10-13 13:25:34 -0700396 }
397 }
John Stiles65b48272020-12-22 17:18:34 -0500398 }
ethannicholas22f939e2016-10-13 13:25:34 -0700399 }
400}
401
Ethan Nicholascb670962017-04-20 19:31:52 -0400402/**
403 * Returns true if assigning to this lvalue has no effect.
404 */
Brian Osman010ce6a2020-10-19 16:34:10 -0400405static bool is_dead(const Expression& lvalue, ProgramUsage* usage) {
Ethan Nicholase6592142020-09-08 10:22:09 -0400406 switch (lvalue.kind()) {
407 case Expression::Kind::kVariableReference:
Brian Osman010ce6a2020-10-19 16:34:10 -0400408 return usage->isDead(*lvalue.as<VariableReference>().variable());
Ethan Nicholase6592142020-09-08 10:22:09 -0400409 case Expression::Kind::kSwizzle:
Brian Osman010ce6a2020-10-19 16:34:10 -0400410 return is_dead(*lvalue.as<Swizzle>().base(), usage);
Ethan Nicholase6592142020-09-08 10:22:09 -0400411 case Expression::Kind::kFieldAccess:
Brian Osman010ce6a2020-10-19 16:34:10 -0400412 return is_dead(*lvalue.as<FieldAccess>().base(), usage);
Ethan Nicholase6592142020-09-08 10:22:09 -0400413 case Expression::Kind::kIndex: {
John Stilesa5a97b42020-08-18 11:19:07 -0400414 const IndexExpression& idx = lvalue.as<IndexExpression>();
Brian Osman010ce6a2020-10-19 16:34:10 -0400415 return is_dead(*idx.base(), usage) &&
Ethan Nicholas2a4952d2020-10-08 15:35:56 -0400416 !idx.index()->hasProperty(Expression::Property::kSideEffects);
Ethan Nicholascb670962017-04-20 19:31:52 -0400417 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400418 case Expression::Kind::kTernary: {
John Stilesa5a97b42020-08-18 11:19:07 -0400419 const TernaryExpression& t = lvalue.as<TernaryExpression>();
Brian Osman010ce6a2020-10-19 16:34:10 -0400420 return !t.test()->hasSideEffects() &&
421 is_dead(*t.ifTrue(), usage) &&
422 is_dead(*t.ifFalse(), usage);
Ethan Nicholasa583b812018-01-18 13:32:11 -0500423 }
Ethan Nicholascb670962017-04-20 19:31:52 -0400424 default:
John Stileseada7bc2021-02-02 16:29:32 -0500425 SkDEBUGFAILF("invalid lvalue: %s\n", lvalue.description().c_str());
Ethan Nicholas2a099da2020-01-02 14:40:54 -0500426 return false;
Ethan Nicholascb670962017-04-20 19:31:52 -0400427 }
428}
ethannicholas22f939e2016-10-13 13:25:34 -0700429
Ethan Nicholascb670962017-04-20 19:31:52 -0400430/**
431 * Returns true if this is an assignment which can be collapsed down to just the right hand side due
432 * to a dead target and lack of side effects on the left hand side.
433 */
Brian Osman010ce6a2020-10-19 16:34:10 -0400434static bool dead_assignment(const BinaryExpression& b, ProgramUsage* usage) {
Brian Osman00185012021-02-04 16:07:11 -0500435 if (!Operators::IsAssignment(b.getOperator())) {
Ethan Nicholascb670962017-04-20 19:31:52 -0400436 return false;
437 }
John Stiles2d4f9592020-10-30 10:29:12 -0400438 return is_dead(*b.left(), usage);
Ethan Nicholascb670962017-04-20 19:31:52 -0400439}
440
John Stiles0ac6c152021-02-10 14:04:24 -0500441/**
442 * Returns true if both expression trees are the same. The left side is expected to be an lvalue.
443 * This only needs to check for trees that can plausibly terminate in a variable, so some basic
444 * candidates like `FloatLiteral` are missing.
445 */
446static bool is_matching_expression_tree(const Expression& left, const Expression& right) {
447 if (left.kind() != right.kind() || left.type() != right.type()) {
448 return false;
449 }
450
451 switch (left.kind()) {
452 case Expression::Kind::kIntLiteral:
453 return left.as<IntLiteral>().value() == right.as<IntLiteral>().value();
454
455 case Expression::Kind::kFieldAccess:
456 return left.as<FieldAccess>().fieldIndex() == right.as<FieldAccess>().fieldIndex() &&
457 is_matching_expression_tree(*left.as<FieldAccess>().base(),
458 *right.as<FieldAccess>().base());
459
460 case Expression::Kind::kIndex:
461 return is_matching_expression_tree(*left.as<IndexExpression>().index(),
462 *right.as<IndexExpression>().index()) &&
463 is_matching_expression_tree(*left.as<IndexExpression>().base(),
464 *right.as<IndexExpression>().base());
465
466 case Expression::Kind::kSwizzle:
467 return left.as<Swizzle>().components() == right.as<Swizzle>().components() &&
468 is_matching_expression_tree(*left.as<Swizzle>().base(),
469 *right.as<Swizzle>().base());
470
471 case Expression::Kind::kVariableReference:
472 return left.as<VariableReference>().variable() ==
473 right.as<VariableReference>().variable();
474
475 default:
476 return false;
477 }
478}
479
480static bool self_assignment(const BinaryExpression& b) {
481 return b.getOperator() == Token::Kind::TK_EQ &&
482 is_matching_expression_tree(*b.left(), *b.right());
483}
484
Ethan Nicholascb670962017-04-20 19:31:52 -0400485void Compiler::computeDataFlow(CFG* cfg) {
John Stilese8a24922021-02-08 17:54:08 -0500486 cfg->fBlocks[cfg->fStart].fBefore.computeStartState(*cfg);
John Stilese6150002020-10-05 12:03:53 -0400487
488 // We set bits in the "processed" set after a block has been scanned.
489 SkBitSet processedSet(cfg->fBlocks.size());
490 while (SkBitSet::OptionalIndex blockId = processedSet.findFirstUnset()) {
491 processedSet.set(*blockId);
492 this->scanCFG(cfg, *blockId, &processedSet);
ethannicholas22f939e2016-10-13 13:25:34 -0700493 }
Ethan Nicholascb670962017-04-20 19:31:52 -0400494}
495
496/**
497 * Attempts to replace the expression pointed to by iter with a new one (in both the CFG and the
498 * IR). If the expression can be cleanly removed, returns true and updates the iterator to point to
499 * the newly-inserted element. Otherwise updates only the IR and returns false (and the CFG will
500 * need to be regenerated).
501 */
John Stilesafbf8992020-08-18 10:08:21 -0400502static bool try_replace_expression(BasicBlock* b,
503 std::vector<BasicBlock::Node>::iterator* iter,
504 std::unique_ptr<Expression>* newExpression) {
Ethan Nicholascb670962017-04-20 19:31:52 -0400505 std::unique_ptr<Expression>* target = (*iter)->expression();
506 if (!b->tryRemoveExpression(iter)) {
507 *target = std::move(*newExpression);
508 return false;
509 }
510 *target = std::move(*newExpression);
511 return b->tryInsertExpression(iter, target);
512}
513
514/**
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400515 * Returns true if the expression is a constant numeric literal with the specified value, or a
516 * constant vector with all elements equal to the specified value.
Ethan Nicholascb670962017-04-20 19:31:52 -0400517 */
Ethan Nicholasa3f22f12020-10-01 12:13:17 -0400518template <typename T = SKSL_FLOAT>
John Stiles9d944232020-08-19 09:56:49 -0400519static bool is_constant(const Expression& expr, T value) {
Ethan Nicholase6592142020-09-08 10:22:09 -0400520 switch (expr.kind()) {
521 case Expression::Kind::kIntLiteral:
Ethan Nicholase96cdd12020-09-28 16:27:18 -0400522 return expr.as<IntLiteral>().value() == value;
John Stiles9d944232020-08-19 09:56:49 -0400523
Ethan Nicholase6592142020-09-08 10:22:09 -0400524 case Expression::Kind::kFloatLiteral:
Ethan Nicholasa3f22f12020-10-01 12:13:17 -0400525 return expr.as<FloatLiteral>().value() == value;
John Stiles9d944232020-08-19 09:56:49 -0400526
Ethan Nicholase6592142020-09-08 10:22:09 -0400527 case Expression::Kind::kConstructor: {
John Stiles9d944232020-08-19 09:56:49 -0400528 const Constructor& constructor = expr.as<Constructor>();
529 if (constructor.isCompileTimeConstant()) {
Ethan Nicholas30d30222020-09-11 12:27:26 -0400530 const Type& constructorType = constructor.type();
Ethan Nicholas30d30222020-09-11 12:27:26 -0400531 switch (constructorType.typeKind()) {
Ethan Nicholase6592142020-09-08 10:22:09 -0400532 case Type::TypeKind::kVector:
John Stilesbc75ebb2020-11-24 12:04:47 -0500533 if (constructor.componentType().isFloat()) {
534 for (int i = 0; i < constructorType.columns(); ++i) {
John Stiles9d944232020-08-19 09:56:49 -0400535 if (constructor.getFVecComponent(i) != value) {
536 return false;
537 }
John Stilesbc75ebb2020-11-24 12:04:47 -0500538 }
539 return true;
540 } else if (constructor.componentType().isInteger()) {
541 for (int i = 0; i < constructorType.columns(); ++i) {
John Stiles9d944232020-08-19 09:56:49 -0400542 if (constructor.getIVecComponent(i) != value) {
543 return false;
544 }
545 }
John Stilesbc75ebb2020-11-24 12:04:47 -0500546 return true;
Ethan Nicholasd188c182019-06-10 15:55:38 -0400547 }
John Stilesbc75ebb2020-11-24 12:04:47 -0500548 // Other types (e.g. boolean) might occur, but aren't supported here.
549 return false;
John Stiles9d944232020-08-19 09:56:49 -0400550
Ethan Nicholase6592142020-09-08 10:22:09 -0400551 case Type::TypeKind::kScalar:
Ethan Nicholasf70f0442020-09-29 12:41:35 -0400552 SkASSERT(constructor.arguments().size() == 1);
553 return is_constant<T>(*constructor.arguments()[0], value);
John Stiles9d944232020-08-19 09:56:49 -0400554
555 default:
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400556 return false;
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400557 }
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400558 }
559 return false;
560 }
Ethan Nicholascb670962017-04-20 19:31:52 -0400561 default:
562 return false;
563 }
564}
565
566/**
567 * Collapses the binary expression pointed to by iter down to just the right side (in both the IR
568 * and CFG structures).
569 */
John Stilesafbf8992020-08-18 10:08:21 -0400570static void delete_left(BasicBlock* b,
571 std::vector<BasicBlock::Node>::iterator* iter,
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400572 Compiler::OptimizationContext* optimizationContext) {
573 optimizationContext->fUpdated = true;
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400574 std::unique_ptr<Expression>* target = (*iter)->expression();
John Stilesa5a97b42020-08-18 11:19:07 -0400575 BinaryExpression& bin = (*target)->as<BinaryExpression>();
John Stiles2d4f9592020-10-30 10:29:12 -0400576 Expression& left = *bin.left();
577 std::unique_ptr<Expression>& rightPointer = bin.right();
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400578 SkASSERT(!left.hasSideEffects());
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400579 bool result;
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400580 if (bin.getOperator() == Token::Kind::TK_EQ) {
581 result = b->tryRemoveLValueBefore(iter, &left);
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400582 } else {
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400583 result = b->tryRemoveExpressionBefore(iter, &left);
Ethan Nicholascb670962017-04-20 19:31:52 -0400584 }
Brian Osman010ce6a2020-10-19 16:34:10 -0400585 // Remove references within LHS.
586 optimizationContext->fUsage->remove(&left);
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400587 *target = std::move(rightPointer);
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400588 if (!result) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400589 optimizationContext->fNeedsRescan = true;
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400590 return;
591 }
592 if (*iter == b->fNodes.begin()) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400593 optimizationContext->fNeedsRescan = true;
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400594 return;
595 }
596 --(*iter);
John Stiles70025e52020-09-28 16:08:58 -0400597 if (!(*iter)->isExpression() || (*iter)->expression() != &rightPointer) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400598 optimizationContext->fNeedsRescan = true;
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400599 return;
600 }
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400601 *iter = b->fNodes.erase(*iter);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400602 SkASSERT((*iter)->expression() == target);
Ethan Nicholascb670962017-04-20 19:31:52 -0400603}
604
605/**
606 * Collapses the binary expression pointed to by iter down to just the left side (in both the IR and
607 * CFG structures).
608 */
John Stilesafbf8992020-08-18 10:08:21 -0400609static void delete_right(BasicBlock* b,
610 std::vector<BasicBlock::Node>::iterator* iter,
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400611 Compiler::OptimizationContext* optimizationContext) {
612 optimizationContext->fUpdated = true;
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400613 std::unique_ptr<Expression>* target = (*iter)->expression();
John Stilesa5a97b42020-08-18 11:19:07 -0400614 BinaryExpression& bin = (*target)->as<BinaryExpression>();
John Stiles2d4f9592020-10-30 10:29:12 -0400615 std::unique_ptr<Expression>& leftPointer = bin.left();
616 Expression& right = *bin.right();
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400617 SkASSERT(!right.hasSideEffects());
Brian Osman010ce6a2020-10-19 16:34:10 -0400618 // Remove references within RHS.
619 optimizationContext->fUsage->remove(&right);
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400620 if (!b->tryRemoveExpressionBefore(iter, &right)) {
621 *target = std::move(leftPointer);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400622 optimizationContext->fNeedsRescan = true;
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400623 return;
Ethan Nicholascb670962017-04-20 19:31:52 -0400624 }
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400625 *target = std::move(leftPointer);
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400626 if (*iter == b->fNodes.begin()) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400627 optimizationContext->fNeedsRescan = true;
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400628 return;
629 }
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400630 --(*iter);
John Stiles70025e52020-09-28 16:08:58 -0400631 if ((!(*iter)->isExpression() || (*iter)->expression() != &leftPointer)) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400632 optimizationContext->fNeedsRescan = true;
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400633 return;
634 }
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400635 *iter = b->fNodes.erase(*iter);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400636 SkASSERT((*iter)->expression() == target);
Ethan Nicholascb670962017-04-20 19:31:52 -0400637}
638
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400639/**
640 * Constructs the specified type using a single argument.
641 */
Ethan Nicholas30d30222020-09-11 12:27:26 -0400642static std::unique_ptr<Expression> construct(const Type* type, std::unique_ptr<Expression> v) {
John Stiles8e3b6be2020-10-13 11:14:08 -0400643 ExpressionArray args;
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400644 args.push_back(std::move(v));
Ethan Nicholase6592142020-09-08 10:22:09 -0400645 std::unique_ptr<Expression> result = std::make_unique<Constructor>(-1, type, std::move(args));
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400646 return result;
647}
648
649/**
650 * Used in the implementations of vectorize_left and vectorize_right. Given a vector type and an
651 * expression x, deletes the expression pointed to by iter and replaces it with <type>(x).
652 */
653static void vectorize(BasicBlock* b,
654 std::vector<BasicBlock::Node>::iterator* iter,
655 const Type& type,
656 std::unique_ptr<Expression>* otherExpression,
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400657 Compiler::OptimizationContext* optimizationContext) {
Ethan Nicholase6592142020-09-08 10:22:09 -0400658 SkASSERT((*(*iter)->expression())->kind() == Expression::Kind::kBinary);
John Stiles9aeed132020-11-24 17:36:06 -0500659 SkASSERT(type.isVector());
660 SkASSERT((*otherExpression)->type().isScalar());
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400661 optimizationContext->fUpdated = true;
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400662 std::unique_ptr<Expression>* target = (*iter)->expression();
663 if (!b->tryRemoveExpression(iter)) {
Ethan Nicholas30d30222020-09-11 12:27:26 -0400664 *target = construct(&type, std::move(*otherExpression));
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400665 optimizationContext->fNeedsRescan = true;
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400666 } else {
Ethan Nicholas30d30222020-09-11 12:27:26 -0400667 *target = construct(&type, std::move(*otherExpression));
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400668 if (!b->tryInsertExpression(iter, target)) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400669 optimizationContext->fNeedsRescan = true;
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400670 }
671 }
672}
673
674/**
675 * Given a binary expression of the form x <op> vec<n>(y), deletes the right side and vectorizes the
676 * left to yield vec<n>(x).
677 */
678static void vectorize_left(BasicBlock* b,
679 std::vector<BasicBlock::Node>::iterator* iter,
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400680 Compiler::OptimizationContext* optimizationContext) {
John Stilesa5a97b42020-08-18 11:19:07 -0400681 BinaryExpression& bin = (*(*iter)->expression())->as<BinaryExpression>();
Brian Osman010ce6a2020-10-19 16:34:10 -0400682 // Remove references within RHS. Vectorization of LHS doesn't change reference counts.
John Stiles2d4f9592020-10-30 10:29:12 -0400683 optimizationContext->fUsage->remove(bin.right().get());
684 vectorize(b, iter, bin.right()->type(), &bin.left(), optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400685}
686
687/**
688 * Given a binary expression of the form vec<n>(x) <op> y, deletes the left side and vectorizes the
689 * right to yield vec<n>(y).
690 */
691static void vectorize_right(BasicBlock* b,
692 std::vector<BasicBlock::Node>::iterator* iter,
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400693 Compiler::OptimizationContext* optimizationContext) {
John Stilesa5a97b42020-08-18 11:19:07 -0400694 BinaryExpression& bin = (*(*iter)->expression())->as<BinaryExpression>();
Brian Osman010ce6a2020-10-19 16:34:10 -0400695 // Remove references within LHS. Vectorization of RHS doesn't change reference counts.
John Stiles2d4f9592020-10-30 10:29:12 -0400696 optimizationContext->fUsage->remove(bin.left().get());
697 vectorize(b, iter, bin.left()->type(), &bin.right(), optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400698}
699
Ethan Nicholascb670962017-04-20 19:31:52 -0400700void Compiler::simplifyExpression(DefinitionMap& definitions,
701 BasicBlock& b,
702 std::vector<BasicBlock::Node>::iterator* iter,
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400703 OptimizationContext* optimizationContext) {
Ethan Nicholascb670962017-04-20 19:31:52 -0400704 Expression* expr = (*iter)->expression()->get();
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400705 SkASSERT(expr);
John Stiles108bbe22020-11-18 11:10:38 -0500706
Ethan Nicholascb670962017-04-20 19:31:52 -0400707 if ((*iter)->fConstantPropagation) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400708 std::unique_ptr<Expression> optimized = expr->constantPropagate(*fIRGenerator,
709 definitions);
Ethan Nicholascb670962017-04-20 19:31:52 -0400710 if (optimized) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400711 optimizationContext->fUpdated = true;
Ethan Nicholas30d30222020-09-11 12:27:26 -0400712 optimized = fIRGenerator->coerce(std::move(optimized), expr->type());
Ethan Nicholas1d881522020-09-11 09:32:54 -0400713 SkASSERT(optimized);
Brian Osman010ce6a2020-10-19 16:34:10 -0400714 // Remove references within 'expr', add references within 'optimized'
715 optimizationContext->fUsage->replace(expr, optimized.get());
Ethan Nicholascb670962017-04-20 19:31:52 -0400716 if (!try_replace_expression(&b, iter, &optimized)) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400717 optimizationContext->fNeedsRescan = true;
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400718 return;
Ethan Nicholascb670962017-04-20 19:31:52 -0400719 }
John Stiles70025e52020-09-28 16:08:58 -0400720 SkASSERT((*iter)->isExpression());
Ethan Nicholascb670962017-04-20 19:31:52 -0400721 expr = (*iter)->expression()->get();
Ethan Nicholascb670962017-04-20 19:31:52 -0400722 }
723 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400724 switch (expr->kind()) {
725 case Expression::Kind::kVariableReference: {
John Stilesa5a97b42020-08-18 11:19:07 -0400726 const VariableReference& ref = expr->as<VariableReference>();
Ethan Nicholas78686922020-10-08 06:46:27 -0400727 const Variable* var = ref.variable();
Ethan Nicholas453f67f2020-10-09 10:43:45 -0400728 if (ref.refKind() != VariableReference::RefKind::kWrite &&
729 ref.refKind() != VariableReference::RefKind::kPointer &&
John Stilese8a24922021-02-08 17:54:08 -0500730 var->storage() == Variable::Storage::kLocal && !definitions.get(var) &&
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400731 optimizationContext->fSilences.find(var) == optimizationContext->fSilences.end()) {
732 optimizationContext->fSilences.insert(var);
Ethan Nicholas82a62d22017-11-07 14:42:10 +0000733 this->error(expr->fOffset,
Ethan Nicholase2c49992020-10-05 11:49:11 -0400734 "'" + var->name() + "' has not been assigned");
Ethan Nicholascb670962017-04-20 19:31:52 -0400735 }
736 break;
737 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400738 case Expression::Kind::kTernary: {
John Stiles403a3632020-08-20 12:11:48 -0400739 TernaryExpression* t = &expr->as<TernaryExpression>();
Ethan Nicholasdd218162020-10-08 05:48:01 -0400740 if (t->test()->is<BoolLiteral>()) {
Ethan Nicholascb670962017-04-20 19:31:52 -0400741 // ternary has a constant test, replace it with either the true or
742 // false branch
Ethan Nicholasdd218162020-10-08 05:48:01 -0400743 if (t->test()->as<BoolLiteral>().value()) {
Brian Osman010ce6a2020-10-19 16:34:10 -0400744 (*iter)->setExpression(std::move(t->ifTrue()), optimizationContext->fUsage);
Ethan Nicholascb670962017-04-20 19:31:52 -0400745 } else {
Brian Osman010ce6a2020-10-19 16:34:10 -0400746 (*iter)->setExpression(std::move(t->ifFalse()), optimizationContext->fUsage);
Ethan Nicholascb670962017-04-20 19:31:52 -0400747 }
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400748 optimizationContext->fUpdated = true;
749 optimizationContext->fNeedsRescan = true;
Ethan Nicholascb670962017-04-20 19:31:52 -0400750 }
751 break;
752 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400753 case Expression::Kind::kBinary: {
John Stiles403a3632020-08-20 12:11:48 -0400754 BinaryExpression* bin = &expr->as<BinaryExpression>();
John Stiles0ac6c152021-02-10 14:04:24 -0500755 if (dead_assignment(*bin, optimizationContext->fUsage) || self_assignment(*bin)) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400756 delete_left(&b, iter, optimizationContext);
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400757 break;
758 }
John Stiles2d4f9592020-10-30 10:29:12 -0400759 Expression& left = *bin->left();
760 Expression& right = *bin->right();
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400761 const Type& leftType = left.type();
762 const Type& rightType = right.type();
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400763 // collapse useless expressions like x * 1 or x + 0
John Stiles9aeed132020-11-24 17:36:06 -0500764 if ((!leftType.isScalar() && !leftType.isVector()) ||
765 (!rightType.isScalar() && !rightType.isVector())) {
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400766 break;
767 }
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400768 switch (bin->getOperator()) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400769 case Token::Kind::TK_STAR:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400770 if (is_constant(left, 1)) {
John Stiles9aeed132020-11-24 17:36:06 -0500771 if (leftType.isVector() && rightType.isScalar()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400772 // float4(1) * x -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400773 vectorize_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400774 } else {
775 // 1 * x -> x
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400776 // 1 * float4(x) -> float4(x)
777 // float4(1) * float4(x) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400778 delete_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400779 }
780 }
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400781 else if (is_constant(left, 0)) {
John Stiles9aeed132020-11-24 17:36:06 -0500782 if (leftType.isScalar() && rightType.isVector() &&
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400783 !right.hasSideEffects()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400784 // 0 * float4(x) -> float4(0)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400785 vectorize_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400786 } else {
787 // 0 * x -> 0
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400788 // float4(0) * x -> float4(0)
789 // float4(0) * float4(x) -> float4(0)
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400790 if (!right.hasSideEffects()) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400791 delete_right(&b, iter, optimizationContext);
Ethan Nicholas51493ee2017-12-11 12:34:33 -0500792 }
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400793 }
Ethan Nicholascb670962017-04-20 19:31:52 -0400794 }
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400795 else if (is_constant(right, 1)) {
John Stiles9aeed132020-11-24 17:36:06 -0500796 if (leftType.isScalar() && rightType.isVector()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400797 // x * float4(1) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400798 vectorize_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400799 } else {
800 // x * 1 -> x
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400801 // float4(x) * 1 -> float4(x)
802 // float4(x) * float4(1) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400803 delete_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400804 }
805 }
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400806 else if (is_constant(right, 0)) {
John Stiles9aeed132020-11-24 17:36:06 -0500807 if (leftType.isVector() && rightType.isScalar() && !left.hasSideEffects()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400808 // float4(x) * 0 -> float4(0)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400809 vectorize_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400810 } else {
811 // x * 0 -> 0
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400812 // x * float4(0) -> float4(0)
813 // float4(x) * float4(0) -> float4(0)
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400814 if (!left.hasSideEffects()) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400815 delete_left(&b, iter, optimizationContext);
Ethan Nicholas51493ee2017-12-11 12:34:33 -0500816 }
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400817 }
Ethan Nicholascb670962017-04-20 19:31:52 -0400818 }
819 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400820 case Token::Kind::TK_PLUS:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400821 if (is_constant(left, 0)) {
John Stiles9aeed132020-11-24 17:36:06 -0500822 if (leftType.isVector() && rightType.isScalar()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400823 // float4(0) + x -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400824 vectorize_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400825 } else {
826 // 0 + x -> x
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400827 // 0 + float4(x) -> float4(x)
828 // float4(0) + float4(x) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400829 delete_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400830 }
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400831 } else if (is_constant(right, 0)) {
John Stiles9aeed132020-11-24 17:36:06 -0500832 if (leftType.isScalar() && rightType.isVector()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400833 // x + float4(0) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400834 vectorize_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400835 } else {
836 // x + 0 -> x
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400837 // float4(x) + 0 -> float4(x)
838 // float4(x) + float4(0) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400839 delete_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400840 }
Ethan Nicholas56e42712017-04-21 10:23:37 -0400841 }
842 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400843 case Token::Kind::TK_MINUS:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400844 if (is_constant(right, 0)) {
John Stiles9aeed132020-11-24 17:36:06 -0500845 if (leftType.isScalar() && rightType.isVector()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400846 // x - float4(0) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400847 vectorize_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400848 } else {
849 // x - 0 -> x
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400850 // float4(x) - 0 -> float4(x)
851 // float4(x) - float4(0) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400852 delete_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400853 }
Ethan Nicholascb670962017-04-20 19:31:52 -0400854 }
855 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400856 case Token::Kind::TK_SLASH:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400857 if (is_constant(right, 1)) {
John Stiles9aeed132020-11-24 17:36:06 -0500858 if (leftType.isScalar() && rightType.isVector()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400859 // x / float4(1) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400860 vectorize_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400861 } else {
862 // x / 1 -> x
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400863 // float4(x) / 1 -> float4(x)
864 // float4(x) / float4(1) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400865 delete_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400866 }
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400867 } else if (is_constant(left, 0)) {
John Stiles9aeed132020-11-24 17:36:06 -0500868 if (leftType.isScalar() && rightType.isVector() &&
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400869 !right.hasSideEffects()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400870 // 0 / float4(x) -> float4(0)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400871 vectorize_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400872 } else {
873 // 0 / x -> 0
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400874 // float4(0) / x -> float4(0)
875 // float4(0) / float4(x) -> float4(0)
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400876 if (!right.hasSideEffects()) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400877 delete_right(&b, iter, optimizationContext);
Ethan Nicholas51493ee2017-12-11 12:34:33 -0500878 }
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400879 }
880 }
881 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400882 case Token::Kind::TK_PLUSEQ:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400883 if (is_constant(right, 0)) {
John Stiles47c0a742021-02-09 09:30:35 -0500884 Analysis::UpdateRefKind(&left, RefKind::kRead);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400885 delete_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400886 }
887 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400888 case Token::Kind::TK_MINUSEQ:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400889 if (is_constant(right, 0)) {
John Stiles47c0a742021-02-09 09:30:35 -0500890 Analysis::UpdateRefKind(&left, RefKind::kRead);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400891 delete_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400892 }
893 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400894 case Token::Kind::TK_STAREQ:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400895 if (is_constant(right, 1)) {
John Stiles47c0a742021-02-09 09:30:35 -0500896 Analysis::UpdateRefKind(&left, RefKind::kRead);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400897 delete_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400898 }
899 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400900 case Token::Kind::TK_SLASHEQ:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400901 if (is_constant(right, 1)) {
John Stiles47c0a742021-02-09 09:30:35 -0500902 Analysis::UpdateRefKind(&left, RefKind::kRead);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400903 delete_right(&b, iter, optimizationContext);
Ethan Nicholascb670962017-04-20 19:31:52 -0400904 }
905 break;
906 default:
907 break;
908 }
Ethan Nicholas409f6f02019-09-17 12:34:39 -0400909 break;
910 }
John Stilesf5c1d042020-11-21 23:26:07 -0500911 case Expression::Kind::kConstructor: {
912 // Find constructors embedded inside constructors and flatten them out where possible.
913 // - float4(float2(1, 2), 3, 4) --> float4(1, 2, 3, 4)
914 // - float4(w, float3(sin(x), cos(y), tan(z))) --> float4(w, sin(x), cos(y), tan(z))
915 // Leave single-argument constructors alone, though. These might be casts or splats.
916 Constructor& c = expr->as<Constructor>();
917 if (c.type().columns() > 1) {
918 // Inspect each constructor argument to see if it's a candidate for flattening.
919 // Remember matched arguments in a bitfield, "argsToOptimize".
920 int argsToOptimize = 0;
921 int currBit = 1;
922 for (const std::unique_ptr<Expression>& arg : c.arguments()) {
923 if (arg->is<Constructor>()) {
924 Constructor& inner = arg->as<Constructor>();
925 if (inner.arguments().size() > 1 &&
926 inner.type().componentType() == c.type().componentType()) {
927 argsToOptimize |= currBit;
928 }
929 }
930 currBit <<= 1;
931 }
932 if (argsToOptimize) {
933 // We found at least one argument that could be flattened out. Re-walk the
934 // constructor args and flatten the candidates we found during our initial pass.
935 ExpressionArray flattened;
936 flattened.reserve_back(c.type().columns());
937 currBit = 1;
938 for (const std::unique_ptr<Expression>& arg : c.arguments()) {
939 if (argsToOptimize & currBit) {
940 Constructor& inner = arg->as<Constructor>();
941 for (const std::unique_ptr<Expression>& innerArg : inner.arguments()) {
942 flattened.push_back(innerArg->clone());
943 }
944 } else {
945 flattened.push_back(arg->clone());
946 }
947 currBit <<= 1;
948 }
John Stiles1b91c0e2021-02-11 11:43:09 -0500949 std::unique_ptr<Expression> replacement(new Constructor(c.fOffset, &c.type(),
950 std::move(flattened)));
951 // We're replacing an expression with a cloned version; we'll need a rescan.
952 // No fUsage change: `float2(float(x), y)` and `float2(x, y)` have equivalent
953 // reference counts.
954 try_replace_expression(&b, iter, &replacement);
John Stilesf5c1d042020-11-21 23:26:07 -0500955 optimizationContext->fUpdated = true;
John Stiles1b91c0e2021-02-11 11:43:09 -0500956 optimizationContext->fNeedsRescan = true;
John Stilesf5c1d042020-11-21 23:26:07 -0500957 break;
958 }
959 }
960 break;
961 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400962 case Expression::Kind::kSwizzle: {
John Stiles403a3632020-08-20 12:11:48 -0400963 Swizzle& s = expr->as<Swizzle>();
John Stiles108bbe22020-11-18 11:10:38 -0500964 // Detect identity swizzles like `foo.rgba`.
Ethan Nicholas6b4d5812020-10-12 16:11:51 -0400965 if ((int) s.components().size() == s.base()->type().columns()) {
Ethan Nicholas409f6f02019-09-17 12:34:39 -0400966 bool identity = true;
Ethan Nicholas6b4d5812020-10-12 16:11:51 -0400967 for (int i = 0; i < (int) s.components().size(); ++i) {
968 if (s.components()[i] != i) {
Ethan Nicholas409f6f02019-09-17 12:34:39 -0400969 identity = false;
970 break;
971 }
972 }
973 if (identity) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400974 optimizationContext->fUpdated = true;
Brian Osman010ce6a2020-10-19 16:34:10 -0400975 // No fUsage change: foo.rgba and foo have equivalent reference counts
Ethan Nicholas6b4d5812020-10-12 16:11:51 -0400976 if (!try_replace_expression(&b, iter, &s.base())) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400977 optimizationContext->fNeedsRescan = true;
Ethan Nicholas409f6f02019-09-17 12:34:39 -0400978 return;
979 }
John Stiles70025e52020-09-28 16:08:58 -0400980 SkASSERT((*iter)->isExpression());
Ethan Nicholas409f6f02019-09-17 12:34:39 -0400981 break;
982 }
983 }
John Stiles108bbe22020-11-18 11:10:38 -0500984 // Detect swizzles of swizzles, e.g. replace `foo.argb.r000` with `foo.a000`.
985 if (s.base()->is<Swizzle>()) {
Ethan Nicholas6b4d5812020-10-12 16:11:51 -0400986 Swizzle& base = s.base()->as<Swizzle>();
John Stiles750109b2020-10-30 13:45:46 -0400987 ComponentArray final;
Ethan Nicholas6b4d5812020-10-12 16:11:51 -0400988 for (int c : s.components()) {
989 final.push_back(base.components()[c]);
Ethan Nicholas409f6f02019-09-17 12:34:39 -0400990 }
Ethan Nicholas6b4d5812020-10-12 16:11:51 -0400991 std::unique_ptr<Expression> replacement(new Swizzle(*fContext, base.base()->clone(),
John Stiles750109b2020-10-30 13:45:46 -0400992 final));
John Stilesd2f51b12021-01-07 18:12:31 -0500993 // We're replacing an expression with a cloned version; we'll need a rescan.
John Stiles108bbe22020-11-18 11:10:38 -0500994 // No fUsage change: `foo.gbr.gbr` and `foo.brg` have equivalent reference counts
John Stilesd2f51b12021-01-07 18:12:31 -0500995 try_replace_expression(&b, iter, &replacement);
996 optimizationContext->fUpdated = true;
997 optimizationContext->fNeedsRescan = true;
John Stiles108bbe22020-11-18 11:10:38 -0500998 break;
999 }
1000 // Optimize swizzles of constructors.
1001 if (s.base()->is<Constructor>()) {
1002 Constructor& base = s.base()->as<Constructor>();
1003 std::unique_ptr<Expression> replacement;
1004 const Type& componentType = base.type().componentType();
1005 int swizzleSize = s.components().size();
1006
1007 // The IR generator has already converted any zero/one swizzle components into
1008 // constructors containing zero/one args. Confirm that this is true by checking that
1009 // our swizzle components are all `xyzw` (values 0 through 3).
1010 SkASSERT(std::all_of(s.components().begin(), s.components().end(),
1011 [](int8_t c) { return c >= 0 && c <= 3; }));
1012
John Stiles9aeed132020-11-24 17:36:06 -05001013 if (base.arguments().size() == 1 && base.arguments().front()->type().isScalar()) {
John Stiles108bbe22020-11-18 11:10:38 -05001014 // `half4(scalar).zyy` can be optimized to `half3(scalar)`. The swizzle
1015 // components don't actually matter since all fields are the same.
John Stilesf0cb7332021-01-08 18:39:00 -05001016 const Expression& argument = *base.arguments().front();
1017 const Type& constructorType = componentType.toCompound(*fContext, swizzleSize,
1018 /*rows=*/1);
1019 replacement = Constructor::SimplifyConversion(constructorType, argument);
1020 if (!replacement) {
1021 ExpressionArray newArgs;
1022 newArgs.push_back(argument.clone());
1023 replacement = std::make_unique<Constructor>(base.fOffset, &constructorType,
1024 std::move(newArgs));
1025 }
John Stiles108bbe22020-11-18 11:10:38 -05001026
John Stilesa60ac0c2020-12-22 08:59:51 -05001027 // We're replacing an expression with a cloned version; we'll need a rescan.
1028 // There's no fUsage change: `half4(foo).xy` and `half2(foo)` have equivalent
1029 // reference counts.
1030 try_replace_expression(&b, iter, &replacement);
John Stiles0777ac42020-11-19 11:06:47 -05001031 optimizationContext->fUpdated = true;
John Stilesa60ac0c2020-12-22 08:59:51 -05001032 optimizationContext->fNeedsRescan = true;
John Stiles108bbe22020-11-18 11:10:38 -05001033 break;
1034 }
1035
John Stiles0777ac42020-11-19 11:06:47 -05001036 // Swizzles can duplicate some elements and discard others, e.g.
1037 // `half4(1, 2, 3, 4).xxz` --> `half3(1, 1, 3)`. However, there are constraints:
1038 // - Expressions with side effects need to occur exactly once, even if they
1039 // would otherwise be swizzle-eliminated
1040 // - Non-trivial expressions should not be repeated, but elimination is OK.
1041 //
1042 // Look up the argument for the constructor at each index. This is typically simple
1043 // but for weird cases like `half4(bar.yz, half2(foo))`, it can be harder than it
1044 // seems. This example would result in:
1045 // argMap[0] = {.fArgIndex = 0, .fComponent = 0} (bar.yz .x)
1046 // argMap[1] = {.fArgIndex = 0, .fComponent = 1} (bar.yz .y)
1047 // argMap[2] = {.fArgIndex = 1, .fComponent = 0} (half2(foo) .x)
1048 // argMap[3] = {.fArgIndex = 1, .fComponent = 1} (half2(foo) .y)
1049 struct ConstructorArgMap {
1050 int8_t fArgIndex;
1051 int8_t fComponent;
1052 };
1053
1054 int numConstructorArgs = base.type().columns();
1055 ConstructorArgMap argMap[4] = {};
1056 int writeIdx = 0;
1057 for (int argIdx = 0; argIdx < (int) base.arguments().size(); ++argIdx) {
1058 const Expression& expr = *base.arguments()[argIdx];
1059 int argWidth = expr.type().columns();
1060 for (int componentIdx = 0; componentIdx < argWidth; ++componentIdx) {
1061 argMap[writeIdx].fArgIndex = argIdx;
1062 argMap[writeIdx].fComponent = componentIdx;
1063 ++writeIdx;
1064 }
1065 }
1066 SkASSERT(writeIdx == numConstructorArgs);
1067
1068 // Count up the number of times each constructor argument is used by the
1069 // swizzle.
1070 // `half4(bar.yz, half2(foo)).xwxy` -> { 3, 1 }
1071 // - bar.yz is referenced 3 times, by `.x_xy`
1072 // - half(foo) is referenced 1 time, by `._w__`
1073 int8_t exprUsed[4] = {};
1074 for (int c : s.components()) {
1075 exprUsed[argMap[c].fArgIndex]++;
1076 }
1077
1078 bool safeToOptimize = true;
1079 for (int index = 0; index < numConstructorArgs; ++index) {
1080 int8_t constructorArgIndex = argMap[index].fArgIndex;
1081 const Expression& baseArg = *base.arguments()[constructorArgIndex];
1082
1083 // Check that non-trivial expressions are not swizzled in more than once.
John Stilesc30fbca2020-11-19 16:25:49 -05001084 if (exprUsed[constructorArgIndex] > 1 &&
1085 !Analysis::IsTrivialExpression(baseArg)) {
John Stiles0777ac42020-11-19 11:06:47 -05001086 safeToOptimize = false;
1087 break;
1088 }
1089 // Check that side-effect-bearing expressions are swizzled in exactly once.
1090 if (exprUsed[constructorArgIndex] != 1 && baseArg.hasSideEffects()) {
1091 safeToOptimize = false;
1092 break;
1093 }
1094 }
1095
1096 if (safeToOptimize) {
John Stilesd9076cb2020-11-19 12:18:36 -05001097 struct ReorderedArgument {
1098 int8_t fArgIndex;
1099 ComponentArray fComponents;
1100 };
1101 SkSTArray<4, ReorderedArgument> reorderedArgs;
John Stiles0777ac42020-11-19 11:06:47 -05001102 for (int c : s.components()) {
1103 const ConstructorArgMap& argument = argMap[c];
1104 const Expression& baseArg = *base.arguments()[argument.fArgIndex];
1105
John Stiles9aeed132020-11-24 17:36:06 -05001106 if (baseArg.type().isScalar()) {
John Stilesd9076cb2020-11-19 12:18:36 -05001107 // This argument is a scalar; add it to the list as-is.
John Stiles0777ac42020-11-19 11:06:47 -05001108 SkASSERT(argument.fComponent == 0);
John Stilesd9076cb2020-11-19 12:18:36 -05001109 reorderedArgs.push_back({argument.fArgIndex,
1110 ComponentArray{}});
John Stiles0777ac42020-11-19 11:06:47 -05001111 } else {
John Stilesd9076cb2020-11-19 12:18:36 -05001112 // This argument is a component from a vector.
John Stiles0777ac42020-11-19 11:06:47 -05001113 SkASSERT(argument.fComponent < baseArg.type().columns());
John Stilesd9076cb2020-11-19 12:18:36 -05001114 if (reorderedArgs.empty() ||
1115 reorderedArgs.back().fArgIndex != argument.fArgIndex) {
1116 // This can't be combined with the previous argument. Add a new one.
1117 reorderedArgs.push_back({argument.fArgIndex,
1118 ComponentArray{argument.fComponent}});
1119 } else {
1120 // Since we know this argument uses components, it should already
1121 // have at least one component set.
1122 SkASSERT(!reorderedArgs.back().fComponents.empty());
1123 // Build up the current argument with one more component.
1124 reorderedArgs.back().fComponents.push_back(argument.fComponent);
1125 }
John Stiles0777ac42020-11-19 11:06:47 -05001126 }
1127 }
John Stilesd9076cb2020-11-19 12:18:36 -05001128
1129 // Convert our reordered argument list to an actual array of expressions, with
1130 // the new order and any new inner swizzles that need to be applied. Note that
1131 // we expect followup passes to clean up the inner swizzles.
1132 ExpressionArray newArgs;
1133 newArgs.reserve_back(swizzleSize);
1134 for (const ReorderedArgument& reorderedArg : reorderedArgs) {
1135 const Expression& baseArg = *base.arguments()[reorderedArg.fArgIndex];
1136 if (reorderedArg.fComponents.empty()) {
1137 newArgs.push_back(baseArg.clone());
1138 } else {
1139 newArgs.push_back(std::make_unique<Swizzle>(*fContext, baseArg.clone(),
1140 reorderedArg.fComponents));
1141 }
1142 }
1143
1144 // Create a new constructor.
John Stiles0777ac42020-11-19 11:06:47 -05001145 replacement = std::make_unique<Constructor>(
1146 base.fOffset,
1147 &componentType.toCompound(*fContext, swizzleSize, /*rows=*/1),
1148 std::move(newArgs));
1149
John Stilesa60ac0c2020-12-22 08:59:51 -05001150 // Remove references within 'expr', add references within 'replacement.'
John Stiles0777ac42020-11-19 11:06:47 -05001151 optimizationContext->fUsage->replace(expr, replacement.get());
John Stilesa60ac0c2020-12-22 08:59:51 -05001152
1153 // We're replacing an expression with a cloned version; we'll need a rescan.
1154 try_replace_expression(&b, iter, &replacement);
1155 optimizationContext->fUpdated = true;
1156 optimizationContext->fNeedsRescan = true;
John Stiles0777ac42020-11-19 11:06:47 -05001157 }
John Stiles108bbe22020-11-18 11:10:38 -05001158 break;
Ethan Nicholas409f6f02019-09-17 12:34:39 -04001159 }
John Stiles30212b72020-06-11 17:55:07 -04001160 break;
Ethan Nicholascb670962017-04-20 19:31:52 -04001161 }
1162 default:
1163 break;
1164 }
1165}
1166
John Stiles92219b42020-06-15 12:32:24 -04001167// Returns true if this statement could potentially execute a break at the current level. We ignore
1168// nested loops and switches, since any breaks inside of them will merely break the loop / switch.
John Stilesb92641c2020-08-31 18:09:01 -04001169static bool contains_conditional_break(Statement& stmt) {
1170 class ContainsConditionalBreak : public ProgramVisitor {
1171 public:
1172 bool visitStatement(const Statement& stmt) override {
Ethan Nicholase6592142020-09-08 10:22:09 -04001173 switch (stmt.kind()) {
1174 case Statement::Kind::kBlock:
John Stilesb92641c2020-08-31 18:09:01 -04001175 return this->INHERITED::visitStatement(stmt);
1176
Ethan Nicholase6592142020-09-08 10:22:09 -04001177 case Statement::Kind::kBreak:
John Stilesb92641c2020-08-31 18:09:01 -04001178 return fInConditional > 0;
1179
Ethan Nicholase6592142020-09-08 10:22:09 -04001180 case Statement::Kind::kIf: {
John Stilesb92641c2020-08-31 18:09:01 -04001181 ++fInConditional;
1182 bool result = this->INHERITED::visitStatement(stmt);
1183 --fInConditional;
1184 return result;
1185 }
1186
1187 default:
1188 return false;
1189 }
1190 }
1191
1192 int fInConditional = 0;
1193 using INHERITED = ProgramVisitor;
1194 };
1195
1196 return ContainsConditionalBreak{}.visitStatement(stmt);
John Stiles92219b42020-06-15 12:32:24 -04001197}
1198
Ethan Nicholas5005a222018-08-24 13:06:27 -04001199// returns true if this statement definitely executes a break at the current level (we ignore
1200// nested loops and switches, since any breaks inside of them will merely break the loop / switch)
John Stilesb92641c2020-08-31 18:09:01 -04001201static bool contains_unconditional_break(Statement& stmt) {
1202 class ContainsUnconditionalBreak : public ProgramVisitor {
1203 public:
1204 bool visitStatement(const Statement& stmt) override {
Ethan Nicholase6592142020-09-08 10:22:09 -04001205 switch (stmt.kind()) {
1206 case Statement::Kind::kBlock:
John Stilesb92641c2020-08-31 18:09:01 -04001207 return this->INHERITED::visitStatement(stmt);
1208
Ethan Nicholase6592142020-09-08 10:22:09 -04001209 case Statement::Kind::kBreak:
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001210 return true;
John Stilesb92641c2020-08-31 18:09:01 -04001211
1212 default:
1213 return false;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001214 }
John Stilesb92641c2020-08-31 18:09:01 -04001215 }
John Stiles92219b42020-06-15 12:32:24 -04001216
John Stilesb92641c2020-08-31 18:09:01 -04001217 using INHERITED = ProgramVisitor;
1218 };
John Stiles92219b42020-06-15 12:32:24 -04001219
John Stilesb92641c2020-08-31 18:09:01 -04001220 return ContainsUnconditionalBreak{}.visitStatement(stmt);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001221}
1222
John Stiles8f2a0cf2020-10-13 12:48:21 -04001223static void move_all_but_break(std::unique_ptr<Statement>& stmt, StatementArray* target) {
Ethan Nicholase6592142020-09-08 10:22:09 -04001224 switch (stmt->kind()) {
1225 case Statement::Kind::kBlock: {
John Stiles92219b42020-06-15 12:32:24 -04001226 // Recurse into the block.
1227 Block& block = static_cast<Block&>(*stmt);
1228
John Stiles8f2a0cf2020-10-13 12:48:21 -04001229 StatementArray blockStmts;
John Stilesf4bda742020-10-14 16:57:41 -04001230 blockStmts.reserve_back(block.children().size());
Ethan Nicholas7bd60432020-09-25 14:31:59 -04001231 for (std::unique_ptr<Statement>& stmt : block.children()) {
1232 move_all_but_break(stmt, &blockStmts);
Ethan Nicholas739e1ca2020-06-11 12:16:14 -04001233 }
John Stiles92219b42020-06-15 12:32:24 -04001234
1235 target->push_back(std::make_unique<Block>(block.fOffset, std::move(blockStmts),
Ethan Nicholas7bd60432020-09-25 14:31:59 -04001236 block.symbolTable(), block.isScope()));
Ethan Nicholas739e1ca2020-06-11 12:16:14 -04001237 break;
John Stiles92219b42020-06-15 12:32:24 -04001238 }
1239
Ethan Nicholase6592142020-09-08 10:22:09 -04001240 case Statement::Kind::kBreak:
John Stiles92219b42020-06-15 12:32:24 -04001241 // Do not append a break to the target.
1242 break;
1243
Ethan Nicholas739e1ca2020-06-11 12:16:14 -04001244 default:
John Stiles92219b42020-06-15 12:32:24 -04001245 // Append normal statements to the target.
1246 target->push_back(std::move(stmt));
1247 break;
Ethan Nicholas739e1ca2020-06-11 12:16:14 -04001248 }
1249}
1250
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001251// Returns a block containing all of the statements that will be run if the given case matches
1252// (which, owing to the statements being owned by unique_ptrs, means the switch itself will be
1253// broken by this call and must then be discarded).
1254// Returns null (and leaves the switch unmodified) if no such simple reduction is possible, such as
1255// when break statements appear inside conditionals.
John Stiles92219b42020-06-15 12:32:24 -04001256static std::unique_ptr<Statement> block_for_case(SwitchStatement* switchStatement,
1257 SwitchCase* caseToCapture) {
1258 // We have to be careful to not move any of the pointers until after we're sure we're going to
1259 // succeed, so before we make any changes at all, we check the switch-cases to decide on a plan
1260 // of action. First, find the switch-case we are interested in.
Ethan Nicholas01b05e52020-10-22 15:53:41 -04001261 auto iter = switchStatement->cases().begin();
1262 for (; iter != switchStatement->cases().end(); ++iter) {
John Stiles2d4f9592020-10-30 10:29:12 -04001263 if (iter->get() == caseToCapture) {
John Stiles92219b42020-06-15 12:32:24 -04001264 break;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001265 }
John Stiles92219b42020-06-15 12:32:24 -04001266 }
1267
1268 // Next, walk forward through the rest of the switch. If we find a conditional break, we're
1269 // stuck and can't simplify at all. If we find an unconditional break, we have a range of
1270 // statements that we can use for simplification.
1271 auto startIter = iter;
1272 Statement* unconditionalBreakStmt = nullptr;
Ethan Nicholas01b05e52020-10-22 15:53:41 -04001273 for (; iter != switchStatement->cases().end(); ++iter) {
John Stiles2d4f9592020-10-30 10:29:12 -04001274 for (std::unique_ptr<Statement>& stmt : (*iter)->statements()) {
John Stiles92219b42020-06-15 12:32:24 -04001275 if (contains_conditional_break(*stmt)) {
1276 // We can't reduce switch-cases to a block when they have conditional breaks.
1277 return nullptr;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001278 }
John Stiles92219b42020-06-15 12:32:24 -04001279
1280 if (contains_unconditional_break(*stmt)) {
1281 // We found an unconditional break. We can use this block, but we need to strip
1282 // out the break statement.
1283 unconditionalBreakStmt = stmt.get();
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001284 break;
1285 }
1286 }
John Stiles92219b42020-06-15 12:32:24 -04001287
1288 if (unconditionalBreakStmt != nullptr) {
1289 break;
1290 }
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001291 }
John Stiles92219b42020-06-15 12:32:24 -04001292
1293 // We fell off the bottom of the switch or encountered a break. We know the range of statements
1294 // that we need to move over, and we know it's safe to do so.
John Stiles8f2a0cf2020-10-13 12:48:21 -04001295 StatementArray caseStmts;
John Stiles92219b42020-06-15 12:32:24 -04001296
1297 // We can move over most of the statements as-is.
1298 while (startIter != iter) {
John Stiles2d4f9592020-10-30 10:29:12 -04001299 for (std::unique_ptr<Statement>& stmt : (*startIter)->statements()) {
John Stiles92219b42020-06-15 12:32:24 -04001300 caseStmts.push_back(std::move(stmt));
1301 }
1302 ++startIter;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001303 }
John Stiles92219b42020-06-15 12:32:24 -04001304
1305 // If we found an unconditional break at the end, we need to move what we can while avoiding
1306 // that break.
1307 if (unconditionalBreakStmt != nullptr) {
John Stiles2d4f9592020-10-30 10:29:12 -04001308 for (std::unique_ptr<Statement>& stmt : (*startIter)->statements()) {
John Stiles92219b42020-06-15 12:32:24 -04001309 if (stmt.get() == unconditionalBreakStmt) {
1310 move_all_but_break(stmt, &caseStmts);
1311 unconditionalBreakStmt = nullptr;
1312 break;
1313 }
1314
1315 caseStmts.push_back(std::move(stmt));
1316 }
1317 }
1318
1319 SkASSERT(unconditionalBreakStmt == nullptr); // Verify that we fixed the unconditional break.
1320
1321 // Return our newly-synthesized block.
Ethan Nicholas01b05e52020-10-22 15:53:41 -04001322 return std::make_unique<Block>(/*offset=*/-1, std::move(caseStmts), switchStatement->symbols());
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001323}
1324
Ethan Nicholascb670962017-04-20 19:31:52 -04001325void Compiler::simplifyStatement(DefinitionMap& definitions,
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001326 BasicBlock& b,
1327 std::vector<BasicBlock::Node>::iterator* iter,
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001328 OptimizationContext* optimizationContext) {
Brian Osman010ce6a2020-10-19 16:34:10 -04001329 ProgramUsage* usage = optimizationContext->fUsage;
Ethan Nicholascb670962017-04-20 19:31:52 -04001330 Statement* stmt = (*iter)->statement()->get();
Ethan Nicholase6592142020-09-08 10:22:09 -04001331 switch (stmt->kind()) {
1332 case Statement::Kind::kVarDeclaration: {
John Stilesa5a97b42020-08-18 11:19:07 -04001333 const auto& varDecl = stmt->as<VarDeclaration>();
Brian Osman010ce6a2020-10-19 16:34:10 -04001334 if (usage->isDead(varDecl.var()) &&
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04001335 (!varDecl.value() ||
1336 !varDecl.value()->hasSideEffects())) {
1337 if (varDecl.value()) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001338 SkASSERT((*iter)->statement()->get() == stmt);
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04001339 if (!b.tryRemoveExpressionBefore(iter, varDecl.value().get())) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001340 optimizationContext->fNeedsRescan = true;
Ethan Nicholascb670962017-04-20 19:31:52 -04001341 }
Ethan Nicholascb670962017-04-20 19:31:52 -04001342 }
Ethan Nicholas5b9b0db2021-01-21 13:12:01 -05001343 // There can still be (soon to be removed) references to the variable at this point.
1344 // Allowing the VarDeclaration to be destroyed here will break those variable's
1345 // initialValue()s, so we hang on to them until optimization is finished.
1346 std::unique_ptr<Statement> old = (*iter)->setStatement(std::make_unique<Nop>(),
1347 usage);
1348 optimizationContext->fOwnedStatements.push_back(std::move(old));
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001349 optimizationContext->fUpdated = true;
Ethan Nicholascb670962017-04-20 19:31:52 -04001350 }
1351 break;
1352 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001353 case Statement::Kind::kIf: {
John Stilesa5a97b42020-08-18 11:19:07 -04001354 IfStatement& i = stmt->as<IfStatement>();
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001355 if (i.test()->kind() == Expression::Kind::kBoolLiteral) {
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001356 // constant if, collapse down to a single branch
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001357 if (i.test()->as<BoolLiteral>().value()) {
1358 SkASSERT(i.ifTrue());
Brian Osman010ce6a2020-10-19 16:34:10 -04001359 (*iter)->setStatement(std::move(i.ifTrue()), usage);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001360 } else {
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001361 if (i.ifFalse()) {
Brian Osman010ce6a2020-10-19 16:34:10 -04001362 (*iter)->setStatement(std::move(i.ifFalse()), usage);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001363 } else {
Brian Osman010ce6a2020-10-19 16:34:10 -04001364 (*iter)->setStatement(std::make_unique<Nop>(), usage);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001365 }
1366 }
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001367 optimizationContext->fUpdated = true;
1368 optimizationContext->fNeedsRescan = true;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001369 break;
1370 }
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001371 if (i.ifFalse() && i.ifFalse()->isEmpty()) {
Ethan Nicholascb670962017-04-20 19:31:52 -04001372 // else block doesn't do anything, remove it
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001373 i.ifFalse().reset();
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001374 optimizationContext->fUpdated = true;
1375 optimizationContext->fNeedsRescan = true;
Ethan Nicholascb670962017-04-20 19:31:52 -04001376 }
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001377 if (!i.ifFalse() && i.ifTrue()->isEmpty()) {
Ethan Nicholascb670962017-04-20 19:31:52 -04001378 // if block doesn't do anything, no else block
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001379 if (i.test()->hasSideEffects()) {
Ethan Nicholascb670962017-04-20 19:31:52 -04001380 // test has side effects, keep it
Brian Osman010ce6a2020-10-19 16:34:10 -04001381 (*iter)->setStatement(
1382 std::make_unique<ExpressionStatement>(std::move(i.test())), usage);
Ethan Nicholascb670962017-04-20 19:31:52 -04001383 } else {
1384 // no if, no else, no test side effects, kill the whole if
1385 // statement
Brian Osman010ce6a2020-10-19 16:34:10 -04001386 (*iter)->setStatement(std::make_unique<Nop>(), usage);
Ethan Nicholascb670962017-04-20 19:31:52 -04001387 }
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001388 optimizationContext->fUpdated = true;
1389 optimizationContext->fNeedsRescan = true;
Ethan Nicholascb670962017-04-20 19:31:52 -04001390 }
1391 break;
1392 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001393 case Statement::Kind::kSwitch: {
John Stilesa5a97b42020-08-18 11:19:07 -04001394 SwitchStatement& s = stmt->as<SwitchStatement>();
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001395 int64_t switchValue;
Ethan Nicholasc0f98152021-02-05 16:21:10 -05001396 if (ConstantFolder::GetConstantInt(*s.value(), &switchValue)) {
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001397 // switch is constant, replace it with the case that matches
1398 bool found = false;
1399 SwitchCase* defaultCase = nullptr;
John Stiles2d4f9592020-10-30 10:29:12 -04001400 for (const std::unique_ptr<SwitchCase>& c : s.cases()) {
1401 if (!c->value()) {
1402 defaultCase = c.get();
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001403 continue;
1404 }
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001405 int64_t caseValue;
Ethan Nicholasc0f98152021-02-05 16:21:10 -05001406 SkAssertResult(ConstantFolder::GetConstantInt(*c->value(), &caseValue));
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001407 if (caseValue == switchValue) {
John Stiles2d4f9592020-10-30 10:29:12 -04001408 std::unique_ptr<Statement> newBlock = block_for_case(&s, c.get());
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001409 if (newBlock) {
Brian Osman010ce6a2020-10-19 16:34:10 -04001410 (*iter)->setStatement(std::move(newBlock), usage);
John Stiles9d944232020-08-19 09:56:49 -04001411 found = true;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001412 break;
1413 } else {
Ethan Nicholas01b05e52020-10-22 15:53:41 -04001414 if (s.isStatic() && !(fFlags & kPermitInvalidStaticTests_Flag) &&
1415 optimizationContext->fSilences.find(&s) ==
1416 optimizationContext->fSilences.end()) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001417 this->error(s.fOffset,
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001418 "static switch contains non-static conditional break");
Ethan Nicholas01b05e52020-10-22 15:53:41 -04001419 optimizationContext->fSilences.insert(&s);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001420 }
1421 return; // can't simplify
1422 }
1423 }
1424 }
1425 if (!found) {
1426 // no matching case. use default if it exists, or kill the whole thing
1427 if (defaultCase) {
1428 std::unique_ptr<Statement> newBlock = block_for_case(&s, defaultCase);
1429 if (newBlock) {
Brian Osman010ce6a2020-10-19 16:34:10 -04001430 (*iter)->setStatement(std::move(newBlock), usage);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001431 } else {
Ethan Nicholas01b05e52020-10-22 15:53:41 -04001432 if (s.isStatic() && !(fFlags & kPermitInvalidStaticTests_Flag) &&
1433 optimizationContext->fSilences.find(&s) ==
1434 optimizationContext->fSilences.end()) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001435 this->error(s.fOffset,
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001436 "static switch contains non-static conditional break");
Ethan Nicholas01b05e52020-10-22 15:53:41 -04001437 optimizationContext->fSilences.insert(&s);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001438 }
1439 return; // can't simplify
1440 }
1441 } else {
Brian Osman010ce6a2020-10-19 16:34:10 -04001442 (*iter)->setStatement(std::make_unique<Nop>(), usage);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001443 }
1444 }
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001445 optimizationContext->fUpdated = true;
1446 optimizationContext->fNeedsRescan = true;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001447 }
1448 break;
1449 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001450 case Statement::Kind::kExpression: {
John Stilesa5a97b42020-08-18 11:19:07 -04001451 ExpressionStatement& e = stmt->as<ExpressionStatement>();
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001452 SkASSERT((*iter)->statement()->get() == &e);
Ethan Nicholasd503a5a2020-09-30 09:29:55 -04001453 if (!e.expression()->hasSideEffects()) {
Ethan Nicholascb670962017-04-20 19:31:52 -04001454 // Expression statement with no side effects, kill it
Ethan Nicholasd503a5a2020-09-30 09:29:55 -04001455 if (!b.tryRemoveExpressionBefore(iter, e.expression().get())) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001456 optimizationContext->fNeedsRescan = true;
Ethan Nicholascb670962017-04-20 19:31:52 -04001457 }
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001458 SkASSERT((*iter)->statement()->get() == stmt);
Brian Osman010ce6a2020-10-19 16:34:10 -04001459 (*iter)->setStatement(std::make_unique<Nop>(), usage);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001460 optimizationContext->fUpdated = true;
Ethan Nicholascb670962017-04-20 19:31:52 -04001461 }
1462 break;
1463 }
1464 default:
1465 break;
1466 }
1467}
1468
Brian Osman010ce6a2020-10-19 16:34:10 -04001469bool Compiler::scanCFG(FunctionDefinition& f, ProgramUsage* usage) {
John Stiles0cc193a2020-09-09 09:39:34 -04001470 bool madeChanges = false;
1471
Ethan Nicholascb670962017-04-20 19:31:52 -04001472 CFG cfg = CFGGenerator().getCFG(f);
1473 this->computeDataFlow(&cfg);
ethannicholas22f939e2016-10-13 13:25:34 -07001474
1475 // check for unreachable code
1476 for (size_t i = 0; i < cfg.fBlocks.size(); i++) {
John Stiles0cc193a2020-09-09 09:39:34 -04001477 const BasicBlock& block = cfg.fBlocks[i];
John Stiles40525102020-12-16 18:10:44 -05001478 if (!block.fIsReachable && !block.fAllowUnreachable && block.fNodes.size()) {
John Stiles0cc193a2020-09-09 09:39:34 -04001479 const BasicBlock::Node& node = block.fNodes[0];
John Stilesc1129322021-02-03 10:13:42 -05001480 int offset = node.isStatement() ? (*node.statement())->fOffset
1481 : (*node.expression())->fOffset;
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001482 this->error(offset, String("unreachable"));
ethannicholas22f939e2016-10-13 13:25:34 -07001483 }
1484 }
1485 if (fErrorCount) {
John Stiles0cc193a2020-09-09 09:39:34 -04001486 return madeChanges;
ethannicholas22f939e2016-10-13 13:25:34 -07001487 }
1488
Ethan Nicholascb670962017-04-20 19:31:52 -04001489 // check for dead code & undefined variables, perform constant propagation
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001490 OptimizationContext optimizationContext;
Brian Osman010ce6a2020-10-19 16:34:10 -04001491 optimizationContext.fUsage = usage;
John Stiles7d3f0892020-11-03 11:35:01 -05001492 SkBitSet eliminatedBlockIds(cfg.fBlocks.size());
Ethan Nicholascb670962017-04-20 19:31:52 -04001493 do {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001494 if (optimizationContext.fNeedsRescan) {
Ethan Nicholascb670962017-04-20 19:31:52 -04001495 cfg = CFGGenerator().getCFG(f);
1496 this->computeDataFlow(&cfg);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001497 optimizationContext.fNeedsRescan = false;
Ethan Nicholas113628d2017-02-02 16:11:39 -05001498 }
Ethan Nicholascb670962017-04-20 19:31:52 -04001499
John Stiles7d3f0892020-11-03 11:35:01 -05001500 eliminatedBlockIds.reset();
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001501 optimizationContext.fUpdated = false;
John Stiles7d3f0892020-11-03 11:35:01 -05001502
1503 for (BlockId blockId = 0; blockId < cfg.fBlocks.size(); ++blockId) {
1504 if (eliminatedBlockIds.test(blockId)) {
1505 // We reached a block ID that might have been eliminated. Be cautious and rescan.
1506 optimizationContext.fUpdated = true;
1507 optimizationContext.fNeedsRescan = true;
1508 break;
1509 }
1510
1511 BasicBlock& b = cfg.fBlocks[blockId];
1512 if (blockId > 0 && !b.fIsReachable) {
Ethan Nicholas1de14812020-06-19 15:32:49 -04001513 // Block was reachable before optimization, but has since become unreachable. In
1514 // addition to being dead code, it's broken - since control flow can't reach it, no
1515 // prior variable definitions can reach it, and therefore variables might look to
Brian Osmanc0213602020-10-06 14:43:32 -04001516 // have not been properly assigned. Kill it by replacing all statements with Nops.
Ethan Nicholas1de14812020-06-19 15:32:49 -04001517 for (BasicBlock::Node& node : b.fNodes) {
John Stiles70025e52020-09-28 16:08:58 -04001518 if (node.isStatement() && !(*node.statement())->is<Nop>()) {
John Stiles7d3f0892020-11-03 11:35:01 -05001519 // Eliminating a node runs the risk of eliminating that node's exits as
1520 // well. Keep track of this and do a rescan if we are about to access one
1521 // of these.
1522 for (BlockId id : b.fExits) {
1523 eliminatedBlockIds.set(id);
1524 }
Brian Osman010ce6a2020-10-19 16:34:10 -04001525 node.setStatement(std::make_unique<Nop>(), usage);
John Stiles0cc193a2020-09-09 09:39:34 -04001526 madeChanges = true;
Ethan Nicholas1de14812020-06-19 15:32:49 -04001527 }
1528 }
1529 continue;
1530 }
Ethan Nicholascb670962017-04-20 19:31:52 -04001531 DefinitionMap definitions = b.fBefore;
1532
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001533 for (auto iter = b.fNodes.begin(); iter != b.fNodes.end() &&
1534 !optimizationContext.fNeedsRescan; ++iter) {
John Stiles70025e52020-09-28 16:08:58 -04001535 if (iter->isExpression()) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001536 this->simplifyExpression(definitions, b, &iter, &optimizationContext);
Ethan Nicholascb670962017-04-20 19:31:52 -04001537 } else {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001538 this->simplifyStatement(definitions, b, &iter, &optimizationContext);
Ethan Nicholascb670962017-04-20 19:31:52 -04001539 }
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001540 if (optimizationContext.fNeedsRescan) {
Ethan Nicholas4b330df2017-05-17 10:52:55 -04001541 break;
1542 }
John Stilese8a24922021-02-08 17:54:08 -05001543 definitions.addDefinitions(*fContext, *iter);
Ethan Nicholascb670962017-04-20 19:31:52 -04001544 }
Brian Osman01a3eb42020-09-14 11:32:49 -04001545
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001546 if (optimizationContext.fNeedsRescan) {
Brian Osman01a3eb42020-09-14 11:32:49 -04001547 break;
1548 }
Ethan Nicholascb670962017-04-20 19:31:52 -04001549 }
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001550 madeChanges |= optimizationContext.fUpdated;
1551 } while (optimizationContext.fUpdated);
1552 SkASSERT(!optimizationContext.fNeedsRescan);
ethannicholas22f939e2016-10-13 13:25:34 -07001553
Ethan Nicholas91a10532017-06-22 11:24:38 -04001554 // verify static ifs & switches, clean up dead variable decls
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001555 for (BasicBlock& b : cfg.fBlocks) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001556 for (auto iter = b.fNodes.begin(); iter != b.fNodes.end() &&
1557 !optimizationContext.fNeedsRescan;) {
John Stiles70025e52020-09-28 16:08:58 -04001558 if (iter->isStatement()) {
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001559 const Statement& s = **iter->statement();
Ethan Nicholase6592142020-09-08 10:22:09 -04001560 switch (s.kind()) {
1561 case Statement::Kind::kIf:
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001562 if (s.as<IfStatement>().isStatic() &&
Ethan Nicholas6e1cbc02017-07-14 10:12:15 -04001563 !(fFlags & kPermitInvalidStaticTests_Flag)) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001564 this->error(s.fOffset, "static if has non-static test");
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001565 }
Ethan Nicholas91a10532017-06-22 11:24:38 -04001566 ++iter;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001567 break;
Ethan Nicholase6592142020-09-08 10:22:09 -04001568 case Statement::Kind::kSwitch:
Ethan Nicholas01b05e52020-10-22 15:53:41 -04001569 if (s.as<SwitchStatement>().isStatic() &&
1570 !(fFlags & kPermitInvalidStaticTests_Flag) &&
1571 optimizationContext.fSilences.find(&s) ==
1572 optimizationContext.fSilences.end()) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001573 this->error(s.fOffset, "static switch has non-static test");
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001574 }
Ethan Nicholas91a10532017-06-22 11:24:38 -04001575 ++iter;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001576 break;
1577 default:
Ethan Nicholas91a10532017-06-22 11:24:38 -04001578 ++iter;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001579 break;
1580 }
Ethan Nicholas91a10532017-06-22 11:24:38 -04001581 } else {
1582 ++iter;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001583 }
1584 }
1585 }
1586
ethannicholas22f939e2016-10-13 13:25:34 -07001587 // check for missing return
John Stiles54e7c052021-01-11 14:22:36 -05001588 if (f.declaration().returnType() != *fContext->fTypes.fVoid) {
John Stiles61e75e32020-10-01 15:42:37 -04001589 if (cfg.fBlocks[cfg.fExit].fIsReachable) {
Ethan Nicholas0a5d0962020-10-14 13:33:18 -04001590 this->error(f.fOffset, String("function '" + String(f.declaration().name()) +
Ethan Nicholasdb80f692019-11-22 14:06:12 -05001591 "' can exit without returning a value"));
ethannicholas22f939e2016-10-13 13:25:34 -07001592 }
1593 }
John Stiles0cc193a2020-09-09 09:39:34 -04001594
1595 return madeChanges;
ethannicholas22f939e2016-10-13 13:25:34 -07001596}
1597
Brian Osman32d53552020-09-23 13:55:20 -04001598std::unique_ptr<Program> Compiler::convertProgram(
1599 Program::Kind kind,
1600 String text,
1601 const Program::Settings& settings,
Brian Osmanbe0b3b72021-01-06 14:27:35 -05001602 const std::vector<std::unique_ptr<ExternalFunction>>* externalFunctions) {
1603 SkASSERT(!externalFunctions || (kind == Program::kGeneric_Kind));
Ethan Nicholas91164d12019-05-15 15:29:54 -04001604
Brian Osman0006ad02020-11-18 15:38:39 -05001605 // Loading and optimizing our base module might reset the inliner, so do that first,
1606 // *then* configure the inliner with the settings for this program.
1607 const ParsedModule& baseModule = this->moduleForProgramKind(kind);
1608
ethannicholasb3058bd2016-07-01 08:22:01 -07001609 fErrorText = "";
1610 fErrorCount = 0;
Brian Osman0006ad02020-11-18 15:38:39 -05001611 fInliner.reset(fIRGenerator->fModifiers.get(), &settings);
Brian Osman88cda172020-10-09 12:05:16 -04001612
1613 // Not using AutoSource, because caller is likely to call errorText() if we fail to compile
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001614 std::unique_ptr<String> textPtr(new String(std::move(text)));
1615 fSource = textPtr.get();
Brian Osman88cda172020-10-09 12:05:16 -04001616
John Stiles5c7bb322020-10-22 11:09:15 -04001617 // Enable node pooling while converting and optimizing the program for a performance boost.
1618 // The Program will take ownership of the pool.
Brian Osman28f702c2021-02-02 11:52:07 -05001619 std::unique_ptr<Pool> pool;
1620 if (fCaps->useNodePools()) {
1621 pool = Pool::Create();
1622 pool->attachToThread();
1623 }
Brian Osman0006ad02020-11-18 15:38:39 -05001624 IRGenerator::IRBundle ir =
1625 fIRGenerator->convertProgram(kind, &settings, baseModule, /*isBuiltinCode=*/false,
Brian Osmanbe0b3b72021-01-06 14:27:35 -05001626 textPtr->c_str(), textPtr->size(), externalFunctions);
John Stiles5c7bb322020-10-22 11:09:15 -04001627 auto program = std::make_unique<Program>(kind,
1628 std::move(textPtr),
1629 settings,
Brian Osmand7e76592020-11-02 12:26:22 -05001630 fCaps,
John Stiles5c7bb322020-10-22 11:09:15 -04001631 fContext,
1632 std::move(ir.fElements),
Brian Osman133724c2020-10-28 14:14:39 -04001633 std::move(ir.fSharedElements),
John Stiles5c7bb322020-10-22 11:09:15 -04001634 std::move(ir.fModifiers),
1635 std::move(ir.fSymbolTable),
1636 std::move(pool),
1637 ir.fInputs);
1638 bool success = false;
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001639 if (fErrorCount) {
John Stiles5c7bb322020-10-22 11:09:15 -04001640 // Do not return programs that failed to compile.
1641 } else if (settings.fOptimize && !this->optimize(*program)) {
1642 // Do not return programs that failed to optimize.
1643 } else {
1644 // We have a successful program!
1645 success = true;
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001646 }
John Stiles5c7bb322020-10-22 11:09:15 -04001647
Brian Osman28f702c2021-02-02 11:52:07 -05001648 if (program->fPool) {
1649 program->fPool->detachFromThread();
1650 }
John Stiles5c7bb322020-10-22 11:09:15 -04001651 return success ? std::move(program) : nullptr;
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001652}
1653
Brian Osman0006ad02020-11-18 15:38:39 -05001654bool Compiler::optimize(LoadedModule& module) {
1655 SkASSERT(!fErrorCount);
1656 Program::Settings settings;
1657 fIRGenerator->fKind = module.fKind;
1658 fIRGenerator->fSettings = &settings;
1659 std::unique_ptr<ProgramUsage> usage = Analysis::GetUsage(module);
1660
1661 fInliner.reset(fModifiers.back().get(), &settings);
1662
1663 while (fErrorCount == 0) {
1664 bool madeChanges = false;
1665
1666 // Scan and optimize based on the control-flow graph for each function.
1667 for (const auto& element : module.fElements) {
1668 if (element->is<FunctionDefinition>()) {
1669 madeChanges |= this->scanCFG(element->as<FunctionDefinition>(), usage.get());
1670 }
1671 }
1672
1673 // Perform inline-candidate analysis and inline any functions deemed suitable.
John Stiles78047582020-12-16 16:17:41 -05001674 madeChanges |= fInliner.analyze(module.fElements, module.fSymbols, usage.get());
Brian Osman0006ad02020-11-18 15:38:39 -05001675
1676 if (!madeChanges) {
1677 break;
1678 }
1679 }
1680 return fErrorCount == 0;
1681}
1682
Ethan Nicholas00543112018-07-31 09:44:36 -04001683bool Compiler::optimize(Program& program) {
1684 SkASSERT(!fErrorCount);
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001685 fIRGenerator->fKind = program.fKind;
1686 fIRGenerator->fSettings = &program.fSettings;
Brian Osman010ce6a2020-10-19 16:34:10 -04001687 ProgramUsage* usage = program.fUsage.get();
John Stiles7954d6c2020-09-01 10:53:02 -04001688
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001689 while (fErrorCount == 0) {
1690 bool madeChanges = false;
John Stiles7954d6c2020-09-01 10:53:02 -04001691
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001692 // Scan and optimize based on the control-flow graph for each function.
Brian Osman133724c2020-10-28 14:14:39 -04001693 for (const auto& element : program.ownedElements()) {
Brian Osman1179fcf2020-10-08 16:04:40 -04001694 if (element->is<FunctionDefinition>()) {
Brian Osman010ce6a2020-10-19 16:34:10 -04001695 madeChanges |= this->scanCFG(element->as<FunctionDefinition>(), usage);
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001696 }
1697 }
1698
1699 // Perform inline-candidate analysis and inline any functions deemed suitable.
John Stiles78047582020-12-16 16:17:41 -05001700 madeChanges |= fInliner.analyze(program.ownedElements(), program.fSymbols, usage);
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001701
1702 // Remove dead functions. We wait until after analysis so that we still report errors,
1703 // even in unused code.
1704 if (program.fSettings.fRemoveDeadFunctions) {
Brian Osman133724c2020-10-28 14:14:39 -04001705 auto isDeadFunction = [&](const ProgramElement* element) {
1706 if (!element->is<FunctionDefinition>()) {
1707 return false;
1708 }
1709 const FunctionDefinition& fn = element->as<FunctionDefinition>();
1710 if (fn.declaration().name() != "main" && usage->get(fn.declaration()) == 0) {
1711 usage->remove(*element);
1712 madeChanges = true;
1713 return true;
1714 }
1715 return false;
1716 };
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001717 program.fElements.erase(
Brian Osman133724c2020-10-28 14:14:39 -04001718 std::remove_if(program.fElements.begin(), program.fElements.end(),
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001719 [&](const std::unique_ptr<ProgramElement>& element) {
Brian Osman133724c2020-10-28 14:14:39 -04001720 return isDeadFunction(element.get());
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001721 }),
1722 program.fElements.end());
Brian Osman133724c2020-10-28 14:14:39 -04001723 program.fSharedElements.erase(
1724 std::remove_if(program.fSharedElements.begin(), program.fSharedElements.end(),
1725 isDeadFunction),
1726 program.fSharedElements.end());
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001727 }
1728
1729 if (program.fKind != Program::kFragmentProcessor_Kind) {
Brian Osmanc0213602020-10-06 14:43:32 -04001730 // Remove declarations of dead global variables
Brian Osman133724c2020-10-28 14:14:39 -04001731 auto isDeadVariable = [&](const ProgramElement* element) {
1732 if (!element->is<GlobalVarDeclaration>()) {
1733 return false;
1734 }
1735 const GlobalVarDeclaration& global = element->as<GlobalVarDeclaration>();
1736 const VarDeclaration& varDecl = global.declaration()->as<VarDeclaration>();
1737 if (usage->isDead(varDecl.var())) {
1738 madeChanges = true;
1739 return true;
1740 }
1741 return false;
1742 };
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001743 program.fElements.erase(
1744 std::remove_if(program.fElements.begin(), program.fElements.end(),
1745 [&](const std::unique_ptr<ProgramElement>& element) {
Brian Osman133724c2020-10-28 14:14:39 -04001746 return isDeadVariable(element.get());
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001747 }),
1748 program.fElements.end());
Brian Osman133724c2020-10-28 14:14:39 -04001749 program.fSharedElements.erase(
1750 std::remove_if(program.fSharedElements.begin(), program.fSharedElements.end(),
1751 isDeadVariable),
1752 program.fSharedElements.end());
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001753 }
John Stiles73a6bff2020-09-09 13:40:37 -04001754
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001755 if (!madeChanges) {
1756 break;
Ethan Nicholas0dc80872019-02-08 15:46:24 -05001757 }
Ethan Nicholas00543112018-07-31 09:44:36 -04001758 }
1759 return fErrorCount == 0;
1760}
1761
Brian Osmanfb32ddf2019-06-18 10:14:20 -04001762#if defined(SKSL_STANDALONE) || SK_SUPPORT_GPU
1763
Ethan Nicholas00543112018-07-31 09:44:36 -04001764bool Compiler::toSPIRV(Program& program, OutputStream& out) {
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001765#ifdef SK_ENABLE_SPIRV_VALIDATION
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001766 StringStream buffer;
Brian Osman88cda172020-10-09 12:05:16 -04001767 AutoSource as(this, program.fSource.get());
Brian Osman8b43dad2020-10-09 13:31:42 -04001768 SPIRVCodeGenerator cg(fContext.get(), &program, this, &buffer);
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001769 bool result = cg.generateCode();
Ethan Nicholasba9a04f2020-11-06 09:28:04 -05001770 if (result && program.fSettings.fValidateSPIRV) {
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001771 spvtools::SpirvTools tools(SPV_ENV_VULKAN_1_0);
Ethan Nicholas762466e2017-06-29 10:03:38 -04001772 const String& data = buffer.str();
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001773 SkASSERT(0 == data.size() % 4);
Brian Osman8d09d4a2020-11-24 15:51:06 -05001774 String errors;
1775 auto dumpmsg = [&errors](spv_message_level_t, const char*, const spv_position_t&,
1776 const char* m) {
1777 errors.appendf("SPIR-V validation error: %s\n", m);
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001778 };
1779 tools.SetMessageConsumer(dumpmsg);
Brian Osman8d09d4a2020-11-24 15:51:06 -05001780
1781 // Verify that the SPIR-V we produced is valid. At runtime, we will abort() with a message
1782 // explaining the error. In standalone mode (skslc), we will send the message, plus the
1783 // entire disassembled SPIR-V (for easier context & debugging) as *our* error message.
1784 result = tools.Validate((const uint32_t*) data.c_str(), data.size() / 4);
1785
1786 if (!result) {
1787#if defined(SKSL_STANDALONE)
1788 // Convert the string-stream to a SPIR-V disassembly.
1789 std::string disassembly;
1790 if (tools.Disassemble((const uint32_t*)data.data(), data.size() / 4, &disassembly)) {
1791 errors.append(disassembly);
1792 }
1793 this->error(-1, errors);
1794#else
1795 SkDEBUGFAILF("%s", errors.c_str());
1796#endif
1797 }
Ethan Nicholas762466e2017-06-29 10:03:38 -04001798 out.write(data.c_str(), data.size());
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001799 }
1800#else
Brian Osman88cda172020-10-09 12:05:16 -04001801 AutoSource as(this, program.fSource.get());
Brian Osman8b43dad2020-10-09 13:31:42 -04001802 SPIRVCodeGenerator cg(fContext.get(), &program, this, &out);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001803 bool result = cg.generateCode();
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001804#endif
Ethan Nicholasce33f102016-12-09 17:22:59 -05001805 return result;
1806}
1807
Ethan Nicholas00543112018-07-31 09:44:36 -04001808bool Compiler::toSPIRV(Program& program, String* out) {
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001809 StringStream buffer;
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001810 bool result = this->toSPIRV(program, buffer);
1811 if (result) {
Ethan Nicholas762466e2017-06-29 10:03:38 -04001812 *out = buffer.str();
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001813 }
1814 return result;
1815}
1816
Ethan Nicholas00543112018-07-31 09:44:36 -04001817bool Compiler::toGLSL(Program& program, OutputStream& out) {
Brian Osman88cda172020-10-09 12:05:16 -04001818 AutoSource as(this, program.fSource.get());
Ethan Nicholas26a9aad2018-03-27 14:10:52 -04001819 GLSLCodeGenerator cg(fContext.get(), &program, this, &out);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001820 bool result = cg.generateCode();
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001821 return result;
1822}
1823
Ethan Nicholas00543112018-07-31 09:44:36 -04001824bool Compiler::toGLSL(Program& program, String* out) {
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001825 StringStream buffer;
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001826 bool result = this->toGLSL(program, buffer);
1827 if (result) {
Ethan Nicholas762466e2017-06-29 10:03:38 -04001828 *out = buffer.str();
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001829 }
1830 return result;
1831}
1832
Brian Osmanc0243912020-02-19 15:35:26 -05001833bool Compiler::toHLSL(Program& program, String* out) {
1834 String spirv;
1835 if (!this->toSPIRV(program, &spirv)) {
1836 return false;
1837 }
1838
1839 return SPIRVtoHLSL(spirv, out);
1840}
1841
Ethan Nicholas00543112018-07-31 09:44:36 -04001842bool Compiler::toMetal(Program& program, OutputStream& out) {
Ethan Nicholas26a9aad2018-03-27 14:10:52 -04001843 MetalCodeGenerator cg(fContext.get(), &program, this, &out);
Ethan Nicholascc305772017-10-13 16:17:45 -04001844 bool result = cg.generateCode();
Ethan Nicholascc305772017-10-13 16:17:45 -04001845 return result;
1846}
1847
Ethan Nicholas00543112018-07-31 09:44:36 -04001848bool Compiler::toMetal(Program& program, String* out) {
Timothy Liangb8eeb802018-07-23 16:46:16 -04001849 StringStream buffer;
1850 bool result = this->toMetal(program, buffer);
1851 if (result) {
1852 *out = buffer.str();
1853 }
1854 return result;
1855}
1856
Greg Daniela28ea672020-09-25 11:12:56 -04001857#if defined(SKSL_STANDALONE) || GR_TEST_UTILS
Ethan Nicholas00543112018-07-31 09:44:36 -04001858bool Compiler::toCPP(Program& program, String name, OutputStream& out) {
Brian Osman88cda172020-10-09 12:05:16 -04001859 AutoSource as(this, program.fSource.get());
Ethan Nicholas26a9aad2018-03-27 14:10:52 -04001860 CPPCodeGenerator cg(fContext.get(), &program, this, name, &out);
Ethan Nicholas762466e2017-06-29 10:03:38 -04001861 bool result = cg.generateCode();
Ethan Nicholas762466e2017-06-29 10:03:38 -04001862 return result;
1863}
1864
Ethan Nicholas00543112018-07-31 09:44:36 -04001865bool Compiler::toH(Program& program, String name, OutputStream& out) {
Brian Osman88cda172020-10-09 12:05:16 -04001866 AutoSource as(this, program.fSource.get());
Ethan Nicholas26a9aad2018-03-27 14:10:52 -04001867 HCodeGenerator cg(fContext.get(), &program, this, name, &out);
Ethan Nicholas762466e2017-06-29 10:03:38 -04001868 bool result = cg.generateCode();
Ethan Nicholas00543112018-07-31 09:44:36 -04001869 return result;
1870}
Greg Daniela28ea672020-09-25 11:12:56 -04001871#endif // defined(SKSL_STANDALONE) || GR_TEST_UTILS
Ethan Nicholas00543112018-07-31 09:44:36 -04001872
Ethan Nicholas2a479a52020-08-18 16:29:45 -04001873#endif // defined(SKSL_STANDALONE) || SK_SUPPORT_GPU
Brian Osman2e29ab52019-09-20 12:19:11 -04001874
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001875Position Compiler::position(int offset) {
Ethan Nicholas3c729892020-12-07 12:47:17 -05001876 if (fSource && offset >= 0) {
1877 int line = 1;
1878 int column = 1;
1879 for (int i = 0; i < offset; i++) {
1880 if ((*fSource)[i] == '\n') {
1881 ++line;
1882 column = 1;
1883 }
1884 else {
1885 ++column;
1886 }
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001887 }
Ethan Nicholas3c729892020-12-07 12:47:17 -05001888 return Position(line, column);
1889 } else {
1890 return Position(-1, -1);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001891 }
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001892}
1893
1894void Compiler::error(int offset, String msg) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001895 fErrorCount++;
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001896 Position pos = this->position(offset);
John Stiles8d3642e2021-01-22 09:50:04 -05001897 fErrorTextLength.push_back(fErrorText.length());
Ethan Nicholas3c729892020-12-07 12:47:17 -05001898 fErrorText += "error: " + (pos.fLine >= 1 ? to_string(pos.fLine) + ": " : "") + msg + "\n";
ethannicholasb3058bd2016-07-01 08:22:01 -07001899}
1900
John Stiles8d3642e2021-01-22 09:50:04 -05001901void Compiler::setErrorCount(int c) {
1902 if (c < fErrorCount) {
1903 fErrorText.resize(fErrorTextLength[c]);
1904 fErrorTextLength.resize(c);
1905 fErrorCount = c;
1906 }
1907}
1908
Ethan Nicholas95046142021-01-07 10:57:27 -05001909String Compiler::errorText(bool showCount) {
1910 if (showCount) {
1911 this->writeErrorCount();
1912 }
Ethan Nicholas00543112018-07-31 09:44:36 -04001913 fErrorCount = 0;
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001914 String result = fErrorText;
Ethan Nicholas95046142021-01-07 10:57:27 -05001915 fErrorText = "";
ethannicholasb3058bd2016-07-01 08:22:01 -07001916 return result;
1917}
1918
1919void Compiler::writeErrorCount() {
1920 if (fErrorCount) {
1921 fErrorText += to_string(fErrorCount) + " error";
1922 if (fErrorCount > 1) {
1923 fErrorText += "s";
1924 }
1925 fErrorText += "\n";
1926 }
1927}
1928
John Stilesa6841be2020-08-06 14:11:56 -04001929} // namespace SkSL