blob: 40800b691d174b55c934192c1246765eae633413 [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
John Stilesd6a5f4492021-02-11 15:46:11 -050087Compiler::Compiler(const ShaderCapsClass* caps)
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 , fErrorCount(0) {
92 SkASSERT(fCaps);
John Stiles7c3515b2020-10-16 18:38:39 -040093 fRootSymbolTable = std::make_shared<SymbolTable>(this, /*builtin=*/true);
Brian Osmanb06301e2020-11-06 11:45:36 -050094 fPrivateSymbolTable = std::make_shared<SymbolTable>(fRootSymbolTable, /*builtin=*/true);
John Stilesb30151e2021-01-11 16:13:08 -050095 fIRGenerator = std::make_unique<IRGenerator>(fContext.get(), fCaps);
ethannicholasb3058bd2016-07-01 08:22:01 -070096
John Stiles54e7c052021-01-11 14:22:36 -050097#define TYPE(t) fContext->fTypes.f ## t .get()
ethannicholasb3058bd2016-07-01 08:22:01 -070098
Brian Osmanb06301e2020-11-06 11:45:36 -050099 const SkSL::Symbol* rootTypes[] = {
100 TYPE(Void),
Brian Salomonbf7b6202016-11-11 16:08:03 -0500101
Brian Osmanb06301e2020-11-06 11:45:36 -0500102 TYPE( Float), TYPE( Float2), TYPE( Float3), TYPE( Float4),
103 TYPE( Half), TYPE( Half2), TYPE( Half3), TYPE( Half4),
104 TYPE( Int), TYPE( Int2), TYPE( Int3), TYPE( Int4),
Brian Osmanb06301e2020-11-06 11:45:36 -0500105 TYPE( Bool), TYPE( Bool2), TYPE( Bool3), TYPE( Bool4),
Brian Salomon2a51de82016-11-16 12:06:01 -0500106
Brian Osmanc0f2b642020-12-22 13:35:55 -0500107 TYPE(Float2x2), TYPE(Float3x3), TYPE(Float4x4),
Brian Osmanc63f4312020-12-23 11:44:14 -0500108 TYPE( Half2x2), TYPE( Half3x3), TYPE(Half4x4),
Greg Daniel64773e62016-11-22 09:44:03 -0500109
Brian Osmanc63f4312020-12-23 11:44:14 -0500110 TYPE(SquareMat), TYPE(SquareHMat),
ethannicholasb3058bd2016-07-01 08:22:01 -0700111
Brian Osman20fad322020-12-23 12:42:33 -0500112 TYPE(GenType), TYPE(GenHType), TYPE(GenIType), TYPE(GenBType),
113 TYPE(Vec), TYPE(HVec), TYPE(IVec), TYPE(BVec),
Brian Osmanb06301e2020-11-06 11:45:36 -0500114
115 TYPE(FragmentProcessor),
116 };
117
118 const SkSL::Symbol* privateTypes[] = {
Brian Osman20fad322020-12-23 12:42:33 -0500119 TYPE( UInt), TYPE( UInt2), TYPE( UInt3), TYPE( UInt4),
120 TYPE( Short), TYPE( Short2), TYPE( Short3), TYPE( Short4),
121 TYPE(UShort), TYPE(UShort2), TYPE(UShort3), TYPE(UShort4),
122 TYPE( Byte), TYPE( Byte2), TYPE( Byte3), TYPE( Byte4),
123 TYPE( UByte), TYPE( UByte2), TYPE( UByte3), TYPE( UByte4),
124
125 TYPE(GenUType), TYPE(UVec),
126 TYPE(SVec), TYPE(USVec), TYPE(ByteVec), TYPE(UByteVec),
127
Brian Osmanc0f2b642020-12-22 13:35:55 -0500128 TYPE(Float2x3), TYPE(Float2x4),
129 TYPE(Float3x2), TYPE(Float3x4),
130 TYPE(Float4x2), TYPE(Float4x3),
131
Brian Osmanc63f4312020-12-23 11:44:14 -0500132 TYPE(Half2x3), TYPE(Half2x4),
133 TYPE(Half3x2), TYPE(Half3x4),
134 TYPE(Half4x2), TYPE(Half4x3),
135
Brian Osmanc0f2b642020-12-22 13:35:55 -0500136 TYPE(Mat), TYPE(HMat),
137
Brian Osmanb06301e2020-11-06 11:45:36 -0500138 TYPE(Sampler1D), TYPE(Sampler2D), TYPE(Sampler3D),
139 TYPE(SamplerExternalOES),
Brian Osmanb06301e2020-11-06 11:45:36 -0500140 TYPE(Sampler2DRect),
Brian Osmanb06301e2020-11-06 11:45:36 -0500141
142 TYPE(ISampler2D),
143 TYPE(Image2D), TYPE(IImage2D),
144 TYPE(SubpassInput), TYPE(SubpassInputMS),
145
Brian Osmanb06301e2020-11-06 11:45:36 -0500146 TYPE(Sampler),
147 TYPE(Texture2D),
148 };
149
150 for (const SkSL::Symbol* type : rootTypes) {
151 fRootSymbolTable->addWithoutOwnership(type);
152 }
153 for (const SkSL::Symbol* type : privateTypes) {
154 fPrivateSymbolTable->addWithoutOwnership(type);
155 }
156
157#undef TYPE
ethannicholasb3058bd2016-07-01 08:22:01 -0700158
Brian Osman3887a012020-09-30 13:22:27 -0400159 // sk_Caps is "builtin", but all references to it are resolved to Settings, so we don't need to
160 // treat it as builtin (ie, no need to clone it into the Program).
Brian Osmanb06301e2020-11-06 11:45:36 -0500161 fPrivateSymbolTable->add(
162 std::make_unique<Variable>(/*offset=*/-1,
John Stiles586df952020-11-12 18:27:13 -0500163 fIRGenerator->fModifiers->addToPool(Modifiers()),
Brian Osmanb06301e2020-11-06 11:45:36 -0500164 "sk_Caps",
John Stiles54e7c052021-01-11 14:22:36 -0500165 fContext->fTypes.fSkCaps.get(),
Brian Osmanb06301e2020-11-06 11:45:36 -0500166 /*builtin=*/false,
167 Variable::Storage::kGlobal));
Ethan Nicholas3605ace2016-11-21 15:59:48 -0500168
Brian Osman3d87e9f2020-10-08 11:50:22 -0400169 fRootModule = {fRootSymbolTable, /*fIntrinsics=*/nullptr};
Brian Osmanb06301e2020-11-06 11:45:36 -0500170 fPrivateModule = {fPrivateSymbolTable, /*fIntrinsics=*/nullptr};
ethannicholasb3058bd2016-07-01 08:22:01 -0700171}
172
John Stilesdd13dba2020-10-29 10:45:34 -0400173Compiler::~Compiler() {}
ethannicholasb3058bd2016-07-01 08:22:01 -0700174
Brian Osman56269982020-11-20 12:38:07 -0500175const ParsedModule& Compiler::loadGPUModule() {
176 if (!fGPUModule.fSymbols) {
177 fGPUModule = this->parseModule(Program::kFragment_Kind, MODULE_DATA(gpu), fPrivateModule);
178 }
179 return fGPUModule;
180}
181
182const ParsedModule& Compiler::loadFragmentModule() {
183 if (!fFragmentModule.fSymbols) {
184 fFragmentModule = this->parseModule(Program::kFragment_Kind, MODULE_DATA(frag),
185 this->loadGPUModule());
186 }
187 return fFragmentModule;
188}
189
190const ParsedModule& Compiler::loadVertexModule() {
191 if (!fVertexModule.fSymbols) {
192 fVertexModule = this->parseModule(Program::kVertex_Kind, MODULE_DATA(vert),
193 this->loadGPUModule());
194 }
195 return fVertexModule;
196}
197
Brian Osman88cda172020-10-09 12:05:16 -0400198const ParsedModule& Compiler::loadGeometryModule() {
Brian Osman3d87e9f2020-10-08 11:50:22 -0400199 if (!fGeometryModule.fSymbols) {
Brian Osman56269982020-11-20 12:38:07 -0500200 fGeometryModule = this->parseModule(Program::kGeometry_Kind, MODULE_DATA(geom),
201 this->loadGPUModule());
Ethan Nicholasc18bb512020-07-28 14:46:53 -0400202 }
Brian Osman88cda172020-10-09 12:05:16 -0400203 return fGeometryModule;
Ethan Nicholasc18bb512020-07-28 14:46:53 -0400204}
205
Brian Osman88cda172020-10-09 12:05:16 -0400206const ParsedModule& Compiler::loadFPModule() {
Brian Osman3d87e9f2020-10-08 11:50:22 -0400207 if (!fFPModule.fSymbols) {
Brian Osman56269982020-11-20 12:38:07 -0500208 fFPModule = this->parseModule(Program::kFragmentProcessor_Kind, MODULE_DATA(fp),
209 this->loadGPUModule());
Brian Osman8e2ef022020-09-30 13:26:43 -0400210 }
Brian Osman88cda172020-10-09 12:05:16 -0400211 return fFPModule;
Brian Osman8e2ef022020-09-30 13:26:43 -0400212}
213
Brian Osmanb06301e2020-11-06 11:45:36 -0500214const ParsedModule& Compiler::loadPublicModule() {
215 if (!fPublicModule.fSymbols) {
216 fPublicModule = this->parseModule(Program::kGeneric_Kind, MODULE_DATA(public), fRootModule);
217 }
218 return fPublicModule;
219}
220
Brian Osman91946752020-12-21 13:20:40 -0500221const ParsedModule& Compiler::loadRuntimeEffectModule() {
222 if (!fRuntimeEffectModule.fSymbols) {
223 fRuntimeEffectModule = this->parseModule(Program::kRuntimeEffect_Kind, MODULE_DATA(runtime),
224 this->loadPublicModule());
Brian Osmanf1319c32020-10-13 09:34:23 -0400225
Brian Osman91946752020-12-21 13:20:40 -0500226 // Add some aliases to the runtime effect module so that it's friendlier, and more like GLSL
John Stiles54e7c052021-01-11 14:22:36 -0500227 fRuntimeEffectModule.fSymbols->addAlias("shader", fContext->fTypes.fFragmentProcessor.get());
Brian Osmanf1319c32020-10-13 09:34:23 -0400228
John Stiles54e7c052021-01-11 14:22:36 -0500229 fRuntimeEffectModule.fSymbols->addAlias("vec2", fContext->fTypes.fFloat2.get());
230 fRuntimeEffectModule.fSymbols->addAlias("vec3", fContext->fTypes.fFloat3.get());
231 fRuntimeEffectModule.fSymbols->addAlias("vec4", fContext->fTypes.fFloat4.get());
Brian Osmanf1319c32020-10-13 09:34:23 -0400232
John Stiles54e7c052021-01-11 14:22:36 -0500233 fRuntimeEffectModule.fSymbols->addAlias("bvec2", fContext->fTypes.fBool2.get());
234 fRuntimeEffectModule.fSymbols->addAlias("bvec3", fContext->fTypes.fBool3.get());
235 fRuntimeEffectModule.fSymbols->addAlias("bvec4", fContext->fTypes.fBool4.get());
Brian Osmanf1319c32020-10-13 09:34:23 -0400236
John Stiles54e7c052021-01-11 14:22:36 -0500237 fRuntimeEffectModule.fSymbols->addAlias("mat2", fContext->fTypes.fFloat2x2.get());
238 fRuntimeEffectModule.fSymbols->addAlias("mat3", fContext->fTypes.fFloat3x3.get());
239 fRuntimeEffectModule.fSymbols->addAlias("mat4", fContext->fTypes.fFloat4x4.get());
Ethan Nicholasc18bb512020-07-28 14:46:53 -0400240 }
Brian Osman91946752020-12-21 13:20:40 -0500241 return fRuntimeEffectModule;
Ethan Nicholasc18bb512020-07-28 14:46:53 -0400242}
243
Brian Osman88cda172020-10-09 12:05:16 -0400244const ParsedModule& Compiler::moduleForProgramKind(Program::Kind kind) {
245 switch (kind) {
Brian Osman91946752020-12-21 13:20:40 -0500246 case Program::kVertex_Kind: return this->loadVertexModule(); break;
247 case Program::kFragment_Kind: return this->loadFragmentModule(); break;
248 case Program::kGeometry_Kind: return this->loadGeometryModule(); break;
249 case Program::kFragmentProcessor_Kind: return this->loadFPModule(); break;
250 case Program::kRuntimeEffect_Kind: return this->loadRuntimeEffectModule(); break;
Brian Osmance750362021-01-21 16:33:06 -0500251 case Program::kGeneric_Kind: return this->loadPublicModule(); break;
Brian Osman88cda172020-10-09 12:05:16 -0400252 }
253 SkUNREACHABLE;
Ethan Nicholasc18bb512020-07-28 14:46:53 -0400254}
255
Brian Osman3d87e9f2020-10-08 11:50:22 -0400256LoadedModule Compiler::loadModule(Program::Kind kind,
257 ModuleData data,
258 std::shared_ptr<SymbolTable> base) {
Brian Osman3d87e9f2020-10-08 11:50:22 -0400259 if (!base) {
Brian Osmanb06301e2020-11-06 11:45:36 -0500260 // NOTE: This is a workaround. The only time 'base' is null is when dehydrating includes.
261 // In that case, skslc doesn't know which module it's preparing, nor what the correct base
262 // module is. We can't use 'Root', because many GPU intrinsics reference private types,
263 // like samplers or textures. Today, 'Private' does contain the union of all known types,
264 // so this is safe. If we ever have types that only exist in 'Public' (for example), this
265 // logic needs to be smarter (by choosing the correct base for the module we're compiling).
266 base = fPrivateSymbolTable;
Brian Osman3d87e9f2020-10-08 11:50:22 -0400267 }
268
269#if defined(SKSL_STANDALONE)
270 SkASSERT(data.fPath);
271 std::ifstream in(data.fPath);
Brian Osmane498b3c2020-09-23 14:42:11 -0400272 std::unique_ptr<String> text = std::make_unique<String>(std::istreambuf_iterator<char>(in),
273 std::istreambuf_iterator<char>());
Ethan Nicholasb33fa3f2020-08-06 13:00:19 -0400274 if (in.rdstate()) {
Brian Osman3d87e9f2020-10-08 11:50:22 -0400275 printf("error reading %s\n", data.fPath);
Ethan Nicholasb33fa3f2020-08-06 13:00:19 -0400276 abort();
277 }
Brian Osmane498b3c2020-09-23 14:42:11 -0400278 const String* source = fRootSymbolTable->takeOwnershipOfString(std::move(text));
Brian Osman88cda172020-10-09 12:05:16 -0400279 AutoSource as(this, source);
Ethan Nicholas8da1e652019-05-24 11:01:59 -0400280 Program::Settings settings;
John Stiles881a10c2020-09-19 10:13:24 -0400281 SkASSERT(fIRGenerator->fCanInline);
282 fIRGenerator->fCanInline = false;
Brian Osmanf4738962021-02-11 11:17:36 -0500283 settings.fReplaceSettings = false;
Brian Osman88cda172020-10-09 12:05:16 -0400284 ParsedModule baseModule = {base, /*fIntrinsics=*/nullptr};
Brian Osmand7e76592020-11-02 12:26:22 -0500285 IRGenerator::IRBundle ir =
Brian Osman0006ad02020-11-18 15:38:39 -0500286 fIRGenerator->convertProgram(kind, &settings, baseModule,
Brian Osmand7e76592020-11-02 12:26:22 -0500287 /*isBuiltinCode=*/true, source->c_str(), source->length(),
Brian Osmanbe0b3b72021-01-06 14:27:35 -0500288 /*externalFunctions=*/nullptr);
Brian Osman133724c2020-10-28 14:14:39 -0400289 SkASSERT(ir.fSharedElements.empty());
Brian Osman0006ad02020-11-18 15:38:39 -0500290 LoadedModule module = { kind, std::move(ir.fSymbolTable), std::move(ir.fElements) };
John Stiles881a10c2020-09-19 10:13:24 -0400291 fIRGenerator->fCanInline = true;
Ethan Nicholas8da1e652019-05-24 11:01:59 -0400292 if (this->fErrorCount) {
293 printf("Unexpected errors: %s\n", this->fErrorText.c_str());
Brian Osman3d87e9f2020-10-08 11:50:22 -0400294 SkDEBUGFAILF("%s %s\n", data.fPath, this->fErrorText.c_str());
Ethan Nicholas8da1e652019-05-24 11:01:59 -0400295 }
Brian Osman88cda172020-10-09 12:05:16 -0400296 fModifiers.push_back(std::move(ir.fModifiers));
Brian Osman3d87e9f2020-10-08 11:50:22 -0400297#else
298 SkASSERT(data.fData && (data.fSize != 0));
299 Rehydrator rehydrator(fContext.get(), fIRGenerator->fModifiers.get(), base, this,
300 data.fData, data.fSize);
Brian Osman0006ad02020-11-18 15:38:39 -0500301 LoadedModule module = { kind, rehydrator.symbolTable(), rehydrator.elements() };
Brian Osman3d87e9f2020-10-08 11:50:22 -0400302 fModifiers.push_back(fIRGenerator->releaseModifiers());
303#endif
304
305 return module;
306}
307
308ParsedModule Compiler::parseModule(Program::Kind kind, ModuleData data, const ParsedModule& base) {
Brian Osman0006ad02020-11-18 15:38:39 -0500309 LoadedModule module = this->loadModule(kind, data, base.fSymbols);
310 this->optimize(module);
Brian Osman3d87e9f2020-10-08 11:50:22 -0400311
312 // For modules that just declare (but don't define) intrinsic functions, there will be no new
313 // program elements. In that case, we can share our parent's intrinsic map:
Brian Osman0006ad02020-11-18 15:38:39 -0500314 if (module.fElements.empty()) {
315 return {module.fSymbols, base.fIntrinsics};
Brian Osman3d87e9f2020-10-08 11:50:22 -0400316 }
317
318 auto intrinsics = std::make_shared<IRIntrinsicMap>(base.fIntrinsics.get());
319
320 // Now, transfer all of the program elements to an intrinsic map. This maps certain types of
321 // global objects to the declaring ProgramElement.
Brian Osman0006ad02020-11-18 15:38:39 -0500322 for (std::unique_ptr<ProgramElement>& element : module.fElements) {
Brian Osman3d87e9f2020-10-08 11:50:22 -0400323 switch (element->kind()) {
324 case ProgramElement::Kind::kFunction: {
325 const FunctionDefinition& f = element->as<FunctionDefinition>();
Ethan Nicholas0a5d0962020-10-14 13:33:18 -0400326 SkASSERT(f.declaration().isBuiltin());
327 intrinsics->insertOrDie(f.declaration().description(), std::move(element));
Brian Osman3d87e9f2020-10-08 11:50:22 -0400328 break;
329 }
John Stiles569249b2020-11-03 12:18:22 -0500330 case ProgramElement::Kind::kFunctionPrototype: {
331 // These are already in the symbol table.
332 break;
333 }
Brian Osman3d87e9f2020-10-08 11:50:22 -0400334 case ProgramElement::Kind::kEnum: {
335 const Enum& e = element->as<Enum>();
336 SkASSERT(e.isBuiltin());
337 intrinsics->insertOrDie(e.typeName(), std::move(element));
338 break;
339 }
340 case ProgramElement::Kind::kGlobalVar: {
Ethan Nicholasc51f33e2020-10-13 13:49:44 -0400341 const GlobalVarDeclaration& global = element->as<GlobalVarDeclaration>();
342 const Variable& var = global.declaration()->as<VarDeclaration>().var();
343 SkASSERT(var.isBuiltin());
344 intrinsics->insertOrDie(var.name(), std::move(element));
Brian Osman3d87e9f2020-10-08 11:50:22 -0400345 break;
346 }
347 case ProgramElement::Kind::kInterfaceBlock: {
Ethan Nicholaseaf47882020-10-15 10:10:08 -0400348 const Variable& var = element->as<InterfaceBlock>().variable();
349 SkASSERT(var.isBuiltin());
350 intrinsics->insertOrDie(var.name(), std::move(element));
Brian Osman3d87e9f2020-10-08 11:50:22 -0400351 break;
352 }
353 default:
354 printf("Unsupported element: %s\n", element->description().c_str());
355 SkASSERT(false);
356 break;
357 }
358 }
359
Brian Osman0006ad02020-11-18 15:38:39 -0500360 return {module.fSymbols, std::move(intrinsics)};
Ethan Nicholas8da1e652019-05-24 11:01:59 -0400361}
362
John Stilese6150002020-10-05 12:03:53 -0400363void Compiler::scanCFG(CFG* cfg, BlockId blockId, SkBitSet* processedSet) {
ethannicholas22f939e2016-10-13 13:25:34 -0700364 BasicBlock& block = cfg->fBlocks[blockId];
365
366 // compute definitions after this block
Ethan Nicholas86a43402017-01-19 13:32:00 -0500367 DefinitionMap after = block.fBefore;
ethannicholas22f939e2016-10-13 13:25:34 -0700368 for (const BasicBlock::Node& n : block.fNodes) {
John Stilese8a24922021-02-08 17:54:08 -0500369 after.addDefinitions(*fContext, n);
ethannicholas22f939e2016-10-13 13:25:34 -0700370 }
371
372 // propagate definitions to exits
373 for (BlockId exitId : block.fExits) {
Ethan Nicholas26a9aad2018-03-27 14:10:52 -0400374 if (exitId == blockId) {
375 continue;
376 }
ethannicholas22f939e2016-10-13 13:25:34 -0700377 BasicBlock& exit = cfg->fBlocks[exitId];
John Stiles65b48272020-12-22 17:18:34 -0500378 for (const auto& [var, e1] : after) {
John Stiles796cdb72020-10-08 12:06:53 -0400379 std::unique_ptr<Expression>** exitDef = exit.fBefore.find(var);
380 if (!exitDef) {
John Stilese6150002020-10-05 12:03:53 -0400381 // exit has no definition for it, just copy it and reprocess exit block
382 processedSet->reset(exitId);
John Stilese8a24922021-02-08 17:54:08 -0500383 exit.fBefore.set(var, e1);
ethannicholas22f939e2016-10-13 13:25:34 -0700384 } else {
Ethan Nicholas86a43402017-01-19 13:32:00 -0500385 // exit has a (possibly different) value already defined
John Stiles796cdb72020-10-08 12:06:53 -0400386 std::unique_ptr<Expression>* e2 = *exitDef;
ethannicholas22f939e2016-10-13 13:25:34 -0700387 if (e1 != e2) {
John Stilese6150002020-10-05 12:03:53 -0400388 // definition has changed, merge and reprocess the exit block
389 processedSet->reset(exitId);
Ethan Nicholasaf197692017-02-27 13:26:45 -0500390 if (e1 && e2) {
John Stiles796cdb72020-10-08 12:06:53 -0400391 *exitDef = (std::unique_ptr<Expression>*)&fContext->fDefined_Expression;
Ethan Nicholasaf197692017-02-27 13:26:45 -0500392 } else {
John Stiles796cdb72020-10-08 12:06:53 -0400393 *exitDef = nullptr;
Ethan Nicholasaf197692017-02-27 13:26:45 -0500394 }
ethannicholas22f939e2016-10-13 13:25:34 -0700395 }
396 }
John Stiles65b48272020-12-22 17:18:34 -0500397 }
ethannicholas22f939e2016-10-13 13:25:34 -0700398 }
399}
400
Ethan Nicholascb670962017-04-20 19:31:52 -0400401/**
402 * Returns true if assigning to this lvalue has no effect.
403 */
Brian Osman010ce6a2020-10-19 16:34:10 -0400404static bool is_dead(const Expression& lvalue, ProgramUsage* usage) {
Ethan Nicholase6592142020-09-08 10:22:09 -0400405 switch (lvalue.kind()) {
406 case Expression::Kind::kVariableReference:
Brian Osman010ce6a2020-10-19 16:34:10 -0400407 return usage->isDead(*lvalue.as<VariableReference>().variable());
Ethan Nicholase6592142020-09-08 10:22:09 -0400408 case Expression::Kind::kSwizzle:
Brian Osman010ce6a2020-10-19 16:34:10 -0400409 return is_dead(*lvalue.as<Swizzle>().base(), usage);
Ethan Nicholase6592142020-09-08 10:22:09 -0400410 case Expression::Kind::kFieldAccess:
Brian Osman010ce6a2020-10-19 16:34:10 -0400411 return is_dead(*lvalue.as<FieldAccess>().base(), usage);
Ethan Nicholase6592142020-09-08 10:22:09 -0400412 case Expression::Kind::kIndex: {
John Stilesa5a97b42020-08-18 11:19:07 -0400413 const IndexExpression& idx = lvalue.as<IndexExpression>();
Brian Osman010ce6a2020-10-19 16:34:10 -0400414 return is_dead(*idx.base(), usage) &&
Ethan Nicholas2a4952d2020-10-08 15:35:56 -0400415 !idx.index()->hasProperty(Expression::Property::kSideEffects);
Ethan Nicholascb670962017-04-20 19:31:52 -0400416 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400417 case Expression::Kind::kTernary: {
John Stilesa5a97b42020-08-18 11:19:07 -0400418 const TernaryExpression& t = lvalue.as<TernaryExpression>();
Brian Osman010ce6a2020-10-19 16:34:10 -0400419 return !t.test()->hasSideEffects() &&
420 is_dead(*t.ifTrue(), usage) &&
421 is_dead(*t.ifFalse(), usage);
Ethan Nicholasa583b812018-01-18 13:32:11 -0500422 }
Ethan Nicholascb670962017-04-20 19:31:52 -0400423 default:
John Stileseada7bc2021-02-02 16:29:32 -0500424 SkDEBUGFAILF("invalid lvalue: %s\n", lvalue.description().c_str());
Ethan Nicholas2a099da2020-01-02 14:40:54 -0500425 return false;
Ethan Nicholascb670962017-04-20 19:31:52 -0400426 }
427}
ethannicholas22f939e2016-10-13 13:25:34 -0700428
Ethan Nicholascb670962017-04-20 19:31:52 -0400429/**
430 * Returns true if this is an assignment which can be collapsed down to just the right hand side due
431 * to a dead target and lack of side effects on the left hand side.
432 */
Brian Osman010ce6a2020-10-19 16:34:10 -0400433static bool dead_assignment(const BinaryExpression& b, ProgramUsage* usage) {
Brian Osman00185012021-02-04 16:07:11 -0500434 if (!Operators::IsAssignment(b.getOperator())) {
Ethan Nicholascb670962017-04-20 19:31:52 -0400435 return false;
436 }
John Stiles2d4f9592020-10-30 10:29:12 -0400437 return is_dead(*b.left(), usage);
Ethan Nicholascb670962017-04-20 19:31:52 -0400438}
439
John Stiles0ac6c152021-02-10 14:04:24 -0500440/**
441 * Returns true if both expression trees are the same. The left side is expected to be an lvalue.
442 * This only needs to check for trees that can plausibly terminate in a variable, so some basic
443 * candidates like `FloatLiteral` are missing.
444 */
445static bool is_matching_expression_tree(const Expression& left, const Expression& right) {
446 if (left.kind() != right.kind() || left.type() != right.type()) {
447 return false;
448 }
449
450 switch (left.kind()) {
451 case Expression::Kind::kIntLiteral:
452 return left.as<IntLiteral>().value() == right.as<IntLiteral>().value();
453
454 case Expression::Kind::kFieldAccess:
455 return left.as<FieldAccess>().fieldIndex() == right.as<FieldAccess>().fieldIndex() &&
456 is_matching_expression_tree(*left.as<FieldAccess>().base(),
457 *right.as<FieldAccess>().base());
458
459 case Expression::Kind::kIndex:
460 return is_matching_expression_tree(*left.as<IndexExpression>().index(),
461 *right.as<IndexExpression>().index()) &&
462 is_matching_expression_tree(*left.as<IndexExpression>().base(),
463 *right.as<IndexExpression>().base());
464
465 case Expression::Kind::kSwizzle:
466 return left.as<Swizzle>().components() == right.as<Swizzle>().components() &&
467 is_matching_expression_tree(*left.as<Swizzle>().base(),
468 *right.as<Swizzle>().base());
469
470 case Expression::Kind::kVariableReference:
471 return left.as<VariableReference>().variable() ==
472 right.as<VariableReference>().variable();
473
474 default:
475 return false;
476 }
477}
478
479static bool self_assignment(const BinaryExpression& b) {
480 return b.getOperator() == Token::Kind::TK_EQ &&
481 is_matching_expression_tree(*b.left(), *b.right());
482}
483
Ethan Nicholascb670962017-04-20 19:31:52 -0400484void Compiler::computeDataFlow(CFG* cfg) {
John Stilese8a24922021-02-08 17:54:08 -0500485 cfg->fBlocks[cfg->fStart].fBefore.computeStartState(*cfg);
John Stilese6150002020-10-05 12:03:53 -0400486
487 // We set bits in the "processed" set after a block has been scanned.
488 SkBitSet processedSet(cfg->fBlocks.size());
489 while (SkBitSet::OptionalIndex blockId = processedSet.findFirstUnset()) {
490 processedSet.set(*blockId);
491 this->scanCFG(cfg, *blockId, &processedSet);
ethannicholas22f939e2016-10-13 13:25:34 -0700492 }
Ethan Nicholascb670962017-04-20 19:31:52 -0400493}
494
495/**
496 * Attempts to replace the expression pointed to by iter with a new one (in both the CFG and the
497 * IR). If the expression can be cleanly removed, returns true and updates the iterator to point to
498 * the newly-inserted element. Otherwise updates only the IR and returns false (and the CFG will
499 * need to be regenerated).
500 */
John Stilesafbf8992020-08-18 10:08:21 -0400501static bool try_replace_expression(BasicBlock* b,
502 std::vector<BasicBlock::Node>::iterator* iter,
503 std::unique_ptr<Expression>* newExpression) {
Ethan Nicholascb670962017-04-20 19:31:52 -0400504 std::unique_ptr<Expression>* target = (*iter)->expression();
505 if (!b->tryRemoveExpression(iter)) {
506 *target = std::move(*newExpression);
507 return false;
508 }
509 *target = std::move(*newExpression);
510 return b->tryInsertExpression(iter, target);
511}
512
513/**
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400514 * Returns true if the expression is a constant numeric literal with the specified value, or a
515 * constant vector with all elements equal to the specified value.
Ethan Nicholascb670962017-04-20 19:31:52 -0400516 */
Ethan Nicholasa3f22f12020-10-01 12:13:17 -0400517template <typename T = SKSL_FLOAT>
John Stiles9d944232020-08-19 09:56:49 -0400518static bool is_constant(const Expression& expr, T value) {
Ethan Nicholase6592142020-09-08 10:22:09 -0400519 switch (expr.kind()) {
520 case Expression::Kind::kIntLiteral:
Ethan Nicholase96cdd12020-09-28 16:27:18 -0400521 return expr.as<IntLiteral>().value() == value;
John Stiles9d944232020-08-19 09:56:49 -0400522
Ethan Nicholase6592142020-09-08 10:22:09 -0400523 case Expression::Kind::kFloatLiteral:
Ethan Nicholasa3f22f12020-10-01 12:13:17 -0400524 return expr.as<FloatLiteral>().value() == value;
John Stiles9d944232020-08-19 09:56:49 -0400525
Ethan Nicholase6592142020-09-08 10:22:09 -0400526 case Expression::Kind::kConstructor: {
John Stiles9d944232020-08-19 09:56:49 -0400527 const Constructor& constructor = expr.as<Constructor>();
528 if (constructor.isCompileTimeConstant()) {
Ethan Nicholas30d30222020-09-11 12:27:26 -0400529 const Type& constructorType = constructor.type();
Ethan Nicholas30d30222020-09-11 12:27:26 -0400530 switch (constructorType.typeKind()) {
Ethan Nicholase6592142020-09-08 10:22:09 -0400531 case Type::TypeKind::kVector:
John Stilesbc75ebb2020-11-24 12:04:47 -0500532 if (constructor.componentType().isFloat()) {
533 for (int i = 0; i < constructorType.columns(); ++i) {
John Stiles9d944232020-08-19 09:56:49 -0400534 if (constructor.getFVecComponent(i) != value) {
535 return false;
536 }
John Stilesbc75ebb2020-11-24 12:04:47 -0500537 }
538 return true;
539 } else if (constructor.componentType().isInteger()) {
540 for (int i = 0; i < constructorType.columns(); ++i) {
John Stiles9d944232020-08-19 09:56:49 -0400541 if (constructor.getIVecComponent(i) != value) {
542 return false;
543 }
544 }
John Stilesbc75ebb2020-11-24 12:04:47 -0500545 return true;
Ethan Nicholasd188c182019-06-10 15:55:38 -0400546 }
John Stilesbc75ebb2020-11-24 12:04:47 -0500547 // Other types (e.g. boolean) might occur, but aren't supported here.
548 return false;
John Stiles9d944232020-08-19 09:56:49 -0400549
Ethan Nicholase6592142020-09-08 10:22:09 -0400550 case Type::TypeKind::kScalar:
Ethan Nicholasf70f0442020-09-29 12:41:35 -0400551 SkASSERT(constructor.arguments().size() == 1);
552 return is_constant<T>(*constructor.arguments()[0], value);
John Stiles9d944232020-08-19 09:56:49 -0400553
554 default:
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400555 return false;
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400556 }
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400557 }
558 return false;
559 }
Ethan Nicholascb670962017-04-20 19:31:52 -0400560 default:
561 return false;
562 }
563}
564
565/**
566 * Collapses the binary expression pointed to by iter down to just the right side (in both the IR
567 * and CFG structures).
568 */
John Stilesafbf8992020-08-18 10:08:21 -0400569static void delete_left(BasicBlock* b,
570 std::vector<BasicBlock::Node>::iterator* iter,
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400571 Compiler::OptimizationContext* optimizationContext) {
572 optimizationContext->fUpdated = true;
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400573 std::unique_ptr<Expression>* target = (*iter)->expression();
John Stilesa5a97b42020-08-18 11:19:07 -0400574 BinaryExpression& bin = (*target)->as<BinaryExpression>();
John Stiles2d4f9592020-10-30 10:29:12 -0400575 Expression& left = *bin.left();
576 std::unique_ptr<Expression>& rightPointer = bin.right();
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400577 SkASSERT(!left.hasSideEffects());
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400578 bool result;
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400579 if (bin.getOperator() == Token::Kind::TK_EQ) {
580 result = b->tryRemoveLValueBefore(iter, &left);
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400581 } else {
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400582 result = b->tryRemoveExpressionBefore(iter, &left);
Ethan Nicholascb670962017-04-20 19:31:52 -0400583 }
Brian Osman010ce6a2020-10-19 16:34:10 -0400584 // Remove references within LHS.
585 optimizationContext->fUsage->remove(&left);
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400586 *target = std::move(rightPointer);
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400587 if (!result) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400588 optimizationContext->fNeedsRescan = true;
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400589 return;
590 }
591 if (*iter == b->fNodes.begin()) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400592 optimizationContext->fNeedsRescan = true;
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400593 return;
594 }
595 --(*iter);
John Stiles70025e52020-09-28 16:08:58 -0400596 if (!(*iter)->isExpression() || (*iter)->expression() != &rightPointer) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400597 optimizationContext->fNeedsRescan = true;
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400598 return;
599 }
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400600 *iter = b->fNodes.erase(*iter);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400601 SkASSERT((*iter)->expression() == target);
Ethan Nicholascb670962017-04-20 19:31:52 -0400602}
603
604/**
605 * Collapses the binary expression pointed to by iter down to just the left side (in both the IR and
606 * CFG structures).
607 */
John Stilesafbf8992020-08-18 10:08:21 -0400608static void delete_right(BasicBlock* b,
609 std::vector<BasicBlock::Node>::iterator* iter,
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400610 Compiler::OptimizationContext* optimizationContext) {
611 optimizationContext->fUpdated = true;
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400612 std::unique_ptr<Expression>* target = (*iter)->expression();
John Stilesa5a97b42020-08-18 11:19:07 -0400613 BinaryExpression& bin = (*target)->as<BinaryExpression>();
John Stiles2d4f9592020-10-30 10:29:12 -0400614 std::unique_ptr<Expression>& leftPointer = bin.left();
615 Expression& right = *bin.right();
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400616 SkASSERT(!right.hasSideEffects());
Brian Osman010ce6a2020-10-19 16:34:10 -0400617 // Remove references within RHS.
618 optimizationContext->fUsage->remove(&right);
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400619 if (!b->tryRemoveExpressionBefore(iter, &right)) {
620 *target = std::move(leftPointer);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400621 optimizationContext->fNeedsRescan = true;
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400622 return;
Ethan Nicholascb670962017-04-20 19:31:52 -0400623 }
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400624 *target = std::move(leftPointer);
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400625 if (*iter == b->fNodes.begin()) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400626 optimizationContext->fNeedsRescan = true;
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400627 return;
628 }
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400629 --(*iter);
John Stiles70025e52020-09-28 16:08:58 -0400630 if ((!(*iter)->isExpression() || (*iter)->expression() != &leftPointer)) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400631 optimizationContext->fNeedsRescan = true;
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400632 return;
633 }
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400634 *iter = b->fNodes.erase(*iter);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400635 SkASSERT((*iter)->expression() == target);
Ethan Nicholascb670962017-04-20 19:31:52 -0400636}
637
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400638/**
639 * Constructs the specified type using a single argument.
640 */
Ethan Nicholas30d30222020-09-11 12:27:26 -0400641static std::unique_ptr<Expression> construct(const Type* type, std::unique_ptr<Expression> v) {
John Stiles8e3b6be2020-10-13 11:14:08 -0400642 ExpressionArray args;
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400643 args.push_back(std::move(v));
Ethan Nicholase6592142020-09-08 10:22:09 -0400644 std::unique_ptr<Expression> result = std::make_unique<Constructor>(-1, type, std::move(args));
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400645 return result;
646}
647
648/**
649 * Used in the implementations of vectorize_left and vectorize_right. Given a vector type and an
650 * expression x, deletes the expression pointed to by iter and replaces it with <type>(x).
651 */
652static void vectorize(BasicBlock* b,
653 std::vector<BasicBlock::Node>::iterator* iter,
654 const Type& type,
655 std::unique_ptr<Expression>* otherExpression,
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400656 Compiler::OptimizationContext* optimizationContext) {
Ethan Nicholase6592142020-09-08 10:22:09 -0400657 SkASSERT((*(*iter)->expression())->kind() == Expression::Kind::kBinary);
John Stiles9aeed132020-11-24 17:36:06 -0500658 SkASSERT(type.isVector());
659 SkASSERT((*otherExpression)->type().isScalar());
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400660 optimizationContext->fUpdated = true;
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400661 std::unique_ptr<Expression>* target = (*iter)->expression();
662 if (!b->tryRemoveExpression(iter)) {
Ethan Nicholas30d30222020-09-11 12:27:26 -0400663 *target = construct(&type, std::move(*otherExpression));
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400664 optimizationContext->fNeedsRescan = true;
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400665 } else {
Ethan Nicholas30d30222020-09-11 12:27:26 -0400666 *target = construct(&type, std::move(*otherExpression));
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400667 if (!b->tryInsertExpression(iter, target)) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400668 optimizationContext->fNeedsRescan = true;
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400669 }
670 }
671}
672
673/**
674 * Given a binary expression of the form x <op> vec<n>(y), deletes the right side and vectorizes the
675 * left to yield vec<n>(x).
676 */
677static void vectorize_left(BasicBlock* b,
678 std::vector<BasicBlock::Node>::iterator* iter,
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400679 Compiler::OptimizationContext* optimizationContext) {
John Stilesa5a97b42020-08-18 11:19:07 -0400680 BinaryExpression& bin = (*(*iter)->expression())->as<BinaryExpression>();
Brian Osman010ce6a2020-10-19 16:34:10 -0400681 // Remove references within RHS. Vectorization of LHS doesn't change reference counts.
John Stiles2d4f9592020-10-30 10:29:12 -0400682 optimizationContext->fUsage->remove(bin.right().get());
683 vectorize(b, iter, bin.right()->type(), &bin.left(), optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400684}
685
686/**
687 * Given a binary expression of the form vec<n>(x) <op> y, deletes the left side and vectorizes the
688 * right to yield vec<n>(y).
689 */
690static void vectorize_right(BasicBlock* b,
691 std::vector<BasicBlock::Node>::iterator* iter,
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400692 Compiler::OptimizationContext* optimizationContext) {
John Stilesa5a97b42020-08-18 11:19:07 -0400693 BinaryExpression& bin = (*(*iter)->expression())->as<BinaryExpression>();
Brian Osman010ce6a2020-10-19 16:34:10 -0400694 // Remove references within LHS. Vectorization of RHS doesn't change reference counts.
John Stiles2d4f9592020-10-30 10:29:12 -0400695 optimizationContext->fUsage->remove(bin.left().get());
696 vectorize(b, iter, bin.left()->type(), &bin.right(), optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400697}
698
Ethan Nicholascb670962017-04-20 19:31:52 -0400699void Compiler::simplifyExpression(DefinitionMap& definitions,
700 BasicBlock& b,
701 std::vector<BasicBlock::Node>::iterator* iter,
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400702 OptimizationContext* optimizationContext) {
Ethan Nicholascb670962017-04-20 19:31:52 -0400703 Expression* expr = (*iter)->expression()->get();
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400704 SkASSERT(expr);
John Stiles108bbe22020-11-18 11:10:38 -0500705
Ethan Nicholascb670962017-04-20 19:31:52 -0400706 if ((*iter)->fConstantPropagation) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400707 std::unique_ptr<Expression> optimized = expr->constantPropagate(*fIRGenerator,
708 definitions);
Ethan Nicholascb670962017-04-20 19:31:52 -0400709 if (optimized) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400710 optimizationContext->fUpdated = true;
Ethan Nicholas30d30222020-09-11 12:27:26 -0400711 optimized = fIRGenerator->coerce(std::move(optimized), expr->type());
Ethan Nicholas1d881522020-09-11 09:32:54 -0400712 SkASSERT(optimized);
Brian Osman010ce6a2020-10-19 16:34:10 -0400713 // Remove references within 'expr', add references within 'optimized'
714 optimizationContext->fUsage->replace(expr, optimized.get());
Ethan Nicholascb670962017-04-20 19:31:52 -0400715 if (!try_replace_expression(&b, iter, &optimized)) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400716 optimizationContext->fNeedsRescan = true;
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400717 return;
Ethan Nicholascb670962017-04-20 19:31:52 -0400718 }
John Stiles70025e52020-09-28 16:08:58 -0400719 SkASSERT((*iter)->isExpression());
Ethan Nicholascb670962017-04-20 19:31:52 -0400720 expr = (*iter)->expression()->get();
Ethan Nicholascb670962017-04-20 19:31:52 -0400721 }
722 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400723 switch (expr->kind()) {
724 case Expression::Kind::kVariableReference: {
John Stilesa5a97b42020-08-18 11:19:07 -0400725 const VariableReference& ref = expr->as<VariableReference>();
Ethan Nicholas78686922020-10-08 06:46:27 -0400726 const Variable* var = ref.variable();
Ethan Nicholas453f67f2020-10-09 10:43:45 -0400727 if (ref.refKind() != VariableReference::RefKind::kWrite &&
728 ref.refKind() != VariableReference::RefKind::kPointer &&
John Stilese8a24922021-02-08 17:54:08 -0500729 var->storage() == Variable::Storage::kLocal && !definitions.get(var) &&
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400730 optimizationContext->fSilences.find(var) == optimizationContext->fSilences.end()) {
731 optimizationContext->fSilences.insert(var);
Ethan Nicholas82a62d22017-11-07 14:42:10 +0000732 this->error(expr->fOffset,
Ethan Nicholase2c49992020-10-05 11:49:11 -0400733 "'" + var->name() + "' has not been assigned");
Ethan Nicholascb670962017-04-20 19:31:52 -0400734 }
735 break;
736 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400737 case Expression::Kind::kTernary: {
John Stiles403a3632020-08-20 12:11:48 -0400738 TernaryExpression* t = &expr->as<TernaryExpression>();
Ethan Nicholasdd218162020-10-08 05:48:01 -0400739 if (t->test()->is<BoolLiteral>()) {
Ethan Nicholascb670962017-04-20 19:31:52 -0400740 // ternary has a constant test, replace it with either the true or
741 // false branch
Ethan Nicholasdd218162020-10-08 05:48:01 -0400742 if (t->test()->as<BoolLiteral>().value()) {
Brian Osman010ce6a2020-10-19 16:34:10 -0400743 (*iter)->setExpression(std::move(t->ifTrue()), optimizationContext->fUsage);
Ethan Nicholascb670962017-04-20 19:31:52 -0400744 } else {
Brian Osman010ce6a2020-10-19 16:34:10 -0400745 (*iter)->setExpression(std::move(t->ifFalse()), optimizationContext->fUsage);
Ethan Nicholascb670962017-04-20 19:31:52 -0400746 }
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400747 optimizationContext->fUpdated = true;
748 optimizationContext->fNeedsRescan = true;
Ethan Nicholascb670962017-04-20 19:31:52 -0400749 }
750 break;
751 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400752 case Expression::Kind::kBinary: {
John Stiles403a3632020-08-20 12:11:48 -0400753 BinaryExpression* bin = &expr->as<BinaryExpression>();
John Stiles0ac6c152021-02-10 14:04:24 -0500754 if (dead_assignment(*bin, optimizationContext->fUsage) || self_assignment(*bin)) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400755 delete_left(&b, iter, optimizationContext);
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400756 break;
757 }
John Stiles2d4f9592020-10-30 10:29:12 -0400758 Expression& left = *bin->left();
759 Expression& right = *bin->right();
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400760 const Type& leftType = left.type();
761 const Type& rightType = right.type();
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400762 // collapse useless expressions like x * 1 or x + 0
John Stiles9aeed132020-11-24 17:36:06 -0500763 if ((!leftType.isScalar() && !leftType.isVector()) ||
764 (!rightType.isScalar() && !rightType.isVector())) {
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400765 break;
766 }
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400767 switch (bin->getOperator()) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400768 case Token::Kind::TK_STAR:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400769 if (is_constant(left, 1)) {
John Stiles9aeed132020-11-24 17:36:06 -0500770 if (leftType.isVector() && rightType.isScalar()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400771 // float4(1) * x -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400772 vectorize_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400773 } else {
774 // 1 * x -> x
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400775 // 1 * float4(x) -> float4(x)
776 // float4(1) * float4(x) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400777 delete_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400778 }
779 }
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400780 else if (is_constant(left, 0)) {
John Stiles9aeed132020-11-24 17:36:06 -0500781 if (leftType.isScalar() && rightType.isVector() &&
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400782 !right.hasSideEffects()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400783 // 0 * float4(x) -> float4(0)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400784 vectorize_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400785 } else {
786 // 0 * x -> 0
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400787 // float4(0) * x -> float4(0)
788 // float4(0) * float4(x) -> float4(0)
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400789 if (!right.hasSideEffects()) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400790 delete_right(&b, iter, optimizationContext);
Ethan Nicholas51493ee2017-12-11 12:34:33 -0500791 }
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400792 }
Ethan Nicholascb670962017-04-20 19:31:52 -0400793 }
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400794 else if (is_constant(right, 1)) {
John Stiles9aeed132020-11-24 17:36:06 -0500795 if (leftType.isScalar() && rightType.isVector()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400796 // x * float4(1) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400797 vectorize_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400798 } else {
799 // x * 1 -> x
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400800 // float4(x) * 1 -> float4(x)
801 // float4(x) * float4(1) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400802 delete_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400803 }
804 }
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400805 else if (is_constant(right, 0)) {
John Stiles9aeed132020-11-24 17:36:06 -0500806 if (leftType.isVector() && rightType.isScalar() && !left.hasSideEffects()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400807 // float4(x) * 0 -> float4(0)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400808 vectorize_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400809 } else {
810 // x * 0 -> 0
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400811 // x * float4(0) -> float4(0)
812 // float4(x) * float4(0) -> float4(0)
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400813 if (!left.hasSideEffects()) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400814 delete_left(&b, iter, optimizationContext);
Ethan Nicholas51493ee2017-12-11 12:34:33 -0500815 }
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400816 }
Ethan Nicholascb670962017-04-20 19:31:52 -0400817 }
818 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400819 case Token::Kind::TK_PLUS:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400820 if (is_constant(left, 0)) {
John Stiles9aeed132020-11-24 17:36:06 -0500821 if (leftType.isVector() && rightType.isScalar()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400822 // float4(0) + x -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400823 vectorize_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400824 } else {
825 // 0 + x -> x
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400826 // 0 + float4(x) -> float4(x)
827 // float4(0) + float4(x) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400828 delete_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400829 }
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400830 } else if (is_constant(right, 0)) {
John Stiles9aeed132020-11-24 17:36:06 -0500831 if (leftType.isScalar() && rightType.isVector()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400832 // x + float4(0) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400833 vectorize_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400834 } else {
835 // x + 0 -> x
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400836 // float4(x) + 0 -> float4(x)
837 // float4(x) + float4(0) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400838 delete_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400839 }
Ethan Nicholas56e42712017-04-21 10:23:37 -0400840 }
841 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400842 case Token::Kind::TK_MINUS:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400843 if (is_constant(right, 0)) {
John Stiles9aeed132020-11-24 17:36:06 -0500844 if (leftType.isScalar() && rightType.isVector()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400845 // x - float4(0) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400846 vectorize_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400847 } else {
848 // x - 0 -> x
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400849 // float4(x) - 0 -> float4(x)
850 // float4(x) - float4(0) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400851 delete_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400852 }
Ethan Nicholascb670962017-04-20 19:31:52 -0400853 }
854 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400855 case Token::Kind::TK_SLASH:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400856 if (is_constant(right, 1)) {
John Stiles9aeed132020-11-24 17:36:06 -0500857 if (leftType.isScalar() && rightType.isVector()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400858 // x / float4(1) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400859 vectorize_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400860 } else {
861 // x / 1 -> x
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400862 // float4(x) / 1 -> float4(x)
863 // float4(x) / float4(1) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400864 delete_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400865 }
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400866 } else if (is_constant(left, 0)) {
John Stiles9aeed132020-11-24 17:36:06 -0500867 if (leftType.isScalar() && rightType.isVector() &&
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400868 !right.hasSideEffects()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400869 // 0 / float4(x) -> float4(0)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400870 vectorize_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400871 } else {
872 // 0 / x -> 0
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400873 // float4(0) / x -> float4(0)
874 // float4(0) / float4(x) -> float4(0)
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400875 if (!right.hasSideEffects()) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400876 delete_right(&b, iter, optimizationContext);
Ethan Nicholas51493ee2017-12-11 12:34:33 -0500877 }
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400878 }
879 }
880 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400881 case Token::Kind::TK_PLUSEQ:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400882 if (is_constant(right, 0)) {
John Stiles47c0a742021-02-09 09:30:35 -0500883 Analysis::UpdateRefKind(&left, RefKind::kRead);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400884 delete_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400885 }
886 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400887 case Token::Kind::TK_MINUSEQ:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400888 if (is_constant(right, 0)) {
John Stiles47c0a742021-02-09 09:30:35 -0500889 Analysis::UpdateRefKind(&left, RefKind::kRead);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400890 delete_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400891 }
892 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400893 case Token::Kind::TK_STAREQ:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400894 if (is_constant(right, 1)) {
John Stiles47c0a742021-02-09 09:30:35 -0500895 Analysis::UpdateRefKind(&left, RefKind::kRead);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400896 delete_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400897 }
898 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400899 case Token::Kind::TK_SLASHEQ:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400900 if (is_constant(right, 1)) {
John Stiles47c0a742021-02-09 09:30:35 -0500901 Analysis::UpdateRefKind(&left, RefKind::kRead);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400902 delete_right(&b, iter, optimizationContext);
Ethan Nicholascb670962017-04-20 19:31:52 -0400903 }
904 break;
905 default:
906 break;
907 }
Ethan Nicholas409f6f02019-09-17 12:34:39 -0400908 break;
909 }
John Stilesf5c1d042020-11-21 23:26:07 -0500910 case Expression::Kind::kConstructor: {
911 // Find constructors embedded inside constructors and flatten them out where possible.
912 // - float4(float2(1, 2), 3, 4) --> float4(1, 2, 3, 4)
913 // - float4(w, float3(sin(x), cos(y), tan(z))) --> float4(w, sin(x), cos(y), tan(z))
914 // Leave single-argument constructors alone, though. These might be casts or splats.
915 Constructor& c = expr->as<Constructor>();
916 if (c.type().columns() > 1) {
917 // Inspect each constructor argument to see if it's a candidate for flattening.
918 // Remember matched arguments in a bitfield, "argsToOptimize".
919 int argsToOptimize = 0;
920 int currBit = 1;
921 for (const std::unique_ptr<Expression>& arg : c.arguments()) {
922 if (arg->is<Constructor>()) {
923 Constructor& inner = arg->as<Constructor>();
924 if (inner.arguments().size() > 1 &&
925 inner.type().componentType() == c.type().componentType()) {
926 argsToOptimize |= currBit;
927 }
928 }
929 currBit <<= 1;
930 }
931 if (argsToOptimize) {
932 // We found at least one argument that could be flattened out. Re-walk the
933 // constructor args and flatten the candidates we found during our initial pass.
934 ExpressionArray flattened;
935 flattened.reserve_back(c.type().columns());
936 currBit = 1;
937 for (const std::unique_ptr<Expression>& arg : c.arguments()) {
938 if (argsToOptimize & currBit) {
939 Constructor& inner = arg->as<Constructor>();
940 for (const std::unique_ptr<Expression>& innerArg : inner.arguments()) {
941 flattened.push_back(innerArg->clone());
942 }
943 } else {
944 flattened.push_back(arg->clone());
945 }
946 currBit <<= 1;
947 }
John Stiles1b91c0e2021-02-11 11:43:09 -0500948 std::unique_ptr<Expression> replacement(new Constructor(c.fOffset, &c.type(),
949 std::move(flattened)));
950 // We're replacing an expression with a cloned version; we'll need a rescan.
951 // No fUsage change: `float2(float(x), y)` and `float2(x, y)` have equivalent
952 // reference counts.
953 try_replace_expression(&b, iter, &replacement);
John Stilesf5c1d042020-11-21 23:26:07 -0500954 optimizationContext->fUpdated = true;
John Stiles1b91c0e2021-02-11 11:43:09 -0500955 optimizationContext->fNeedsRescan = true;
John Stilesf5c1d042020-11-21 23:26:07 -0500956 break;
957 }
958 }
959 break;
960 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400961 case Expression::Kind::kSwizzle: {
John Stiles403a3632020-08-20 12:11:48 -0400962 Swizzle& s = expr->as<Swizzle>();
John Stiles108bbe22020-11-18 11:10:38 -0500963 // Detect identity swizzles like `foo.rgba`.
Ethan Nicholas6b4d5812020-10-12 16:11:51 -0400964 if ((int) s.components().size() == s.base()->type().columns()) {
Ethan Nicholas409f6f02019-09-17 12:34:39 -0400965 bool identity = true;
Ethan Nicholas6b4d5812020-10-12 16:11:51 -0400966 for (int i = 0; i < (int) s.components().size(); ++i) {
967 if (s.components()[i] != i) {
Ethan Nicholas409f6f02019-09-17 12:34:39 -0400968 identity = false;
969 break;
970 }
971 }
972 if (identity) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400973 optimizationContext->fUpdated = true;
Brian Osman010ce6a2020-10-19 16:34:10 -0400974 // No fUsage change: foo.rgba and foo have equivalent reference counts
Ethan Nicholas6b4d5812020-10-12 16:11:51 -0400975 if (!try_replace_expression(&b, iter, &s.base())) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400976 optimizationContext->fNeedsRescan = true;
Ethan Nicholas409f6f02019-09-17 12:34:39 -0400977 return;
978 }
John Stiles70025e52020-09-28 16:08:58 -0400979 SkASSERT((*iter)->isExpression());
Ethan Nicholas409f6f02019-09-17 12:34:39 -0400980 break;
981 }
982 }
John Stiles108bbe22020-11-18 11:10:38 -0500983 // Detect swizzles of swizzles, e.g. replace `foo.argb.r000` with `foo.a000`.
984 if (s.base()->is<Swizzle>()) {
Ethan Nicholas6b4d5812020-10-12 16:11:51 -0400985 Swizzle& base = s.base()->as<Swizzle>();
John Stiles750109b2020-10-30 13:45:46 -0400986 ComponentArray final;
Ethan Nicholas6b4d5812020-10-12 16:11:51 -0400987 for (int c : s.components()) {
988 final.push_back(base.components()[c]);
Ethan Nicholas409f6f02019-09-17 12:34:39 -0400989 }
Ethan Nicholas6b4d5812020-10-12 16:11:51 -0400990 std::unique_ptr<Expression> replacement(new Swizzle(*fContext, base.base()->clone(),
John Stiles750109b2020-10-30 13:45:46 -0400991 final));
John Stilesd2f51b12021-01-07 18:12:31 -0500992 // We're replacing an expression with a cloned version; we'll need a rescan.
John Stiles108bbe22020-11-18 11:10:38 -0500993 // No fUsage change: `foo.gbr.gbr` and `foo.brg` have equivalent reference counts
John Stilesd2f51b12021-01-07 18:12:31 -0500994 try_replace_expression(&b, iter, &replacement);
995 optimizationContext->fUpdated = true;
996 optimizationContext->fNeedsRescan = true;
John Stiles108bbe22020-11-18 11:10:38 -0500997 break;
998 }
999 // Optimize swizzles of constructors.
1000 if (s.base()->is<Constructor>()) {
1001 Constructor& base = s.base()->as<Constructor>();
1002 std::unique_ptr<Expression> replacement;
1003 const Type& componentType = base.type().componentType();
1004 int swizzleSize = s.components().size();
1005
1006 // The IR generator has already converted any zero/one swizzle components into
1007 // constructors containing zero/one args. Confirm that this is true by checking that
1008 // our swizzle components are all `xyzw` (values 0 through 3).
1009 SkASSERT(std::all_of(s.components().begin(), s.components().end(),
1010 [](int8_t c) { return c >= 0 && c <= 3; }));
1011
John Stiles9aeed132020-11-24 17:36:06 -05001012 if (base.arguments().size() == 1 && base.arguments().front()->type().isScalar()) {
John Stiles108bbe22020-11-18 11:10:38 -05001013 // `half4(scalar).zyy` can be optimized to `half3(scalar)`. The swizzle
1014 // components don't actually matter since all fields are the same.
John Stilesf0cb7332021-01-08 18:39:00 -05001015 const Expression& argument = *base.arguments().front();
1016 const Type& constructorType = componentType.toCompound(*fContext, swizzleSize,
1017 /*rows=*/1);
1018 replacement = Constructor::SimplifyConversion(constructorType, argument);
1019 if (!replacement) {
1020 ExpressionArray newArgs;
1021 newArgs.push_back(argument.clone());
1022 replacement = std::make_unique<Constructor>(base.fOffset, &constructorType,
1023 std::move(newArgs));
1024 }
John Stiles108bbe22020-11-18 11:10:38 -05001025
John Stilesa60ac0c2020-12-22 08:59:51 -05001026 // We're replacing an expression with a cloned version; we'll need a rescan.
1027 // There's no fUsage change: `half4(foo).xy` and `half2(foo)` have equivalent
1028 // reference counts.
1029 try_replace_expression(&b, iter, &replacement);
John Stiles0777ac42020-11-19 11:06:47 -05001030 optimizationContext->fUpdated = true;
John Stilesa60ac0c2020-12-22 08:59:51 -05001031 optimizationContext->fNeedsRescan = true;
John Stiles108bbe22020-11-18 11:10:38 -05001032 break;
1033 }
1034
John Stiles0777ac42020-11-19 11:06:47 -05001035 // Swizzles can duplicate some elements and discard others, e.g.
1036 // `half4(1, 2, 3, 4).xxz` --> `half3(1, 1, 3)`. However, there are constraints:
1037 // - Expressions with side effects need to occur exactly once, even if they
1038 // would otherwise be swizzle-eliminated
1039 // - Non-trivial expressions should not be repeated, but elimination is OK.
1040 //
1041 // Look up the argument for the constructor at each index. This is typically simple
1042 // but for weird cases like `half4(bar.yz, half2(foo))`, it can be harder than it
1043 // seems. This example would result in:
1044 // argMap[0] = {.fArgIndex = 0, .fComponent = 0} (bar.yz .x)
1045 // argMap[1] = {.fArgIndex = 0, .fComponent = 1} (bar.yz .y)
1046 // argMap[2] = {.fArgIndex = 1, .fComponent = 0} (half2(foo) .x)
1047 // argMap[3] = {.fArgIndex = 1, .fComponent = 1} (half2(foo) .y)
1048 struct ConstructorArgMap {
1049 int8_t fArgIndex;
1050 int8_t fComponent;
1051 };
1052
1053 int numConstructorArgs = base.type().columns();
1054 ConstructorArgMap argMap[4] = {};
1055 int writeIdx = 0;
1056 for (int argIdx = 0; argIdx < (int) base.arguments().size(); ++argIdx) {
1057 const Expression& expr = *base.arguments()[argIdx];
1058 int argWidth = expr.type().columns();
1059 for (int componentIdx = 0; componentIdx < argWidth; ++componentIdx) {
1060 argMap[writeIdx].fArgIndex = argIdx;
1061 argMap[writeIdx].fComponent = componentIdx;
1062 ++writeIdx;
1063 }
1064 }
1065 SkASSERT(writeIdx == numConstructorArgs);
1066
1067 // Count up the number of times each constructor argument is used by the
1068 // swizzle.
1069 // `half4(bar.yz, half2(foo)).xwxy` -> { 3, 1 }
1070 // - bar.yz is referenced 3 times, by `.x_xy`
1071 // - half(foo) is referenced 1 time, by `._w__`
1072 int8_t exprUsed[4] = {};
1073 for (int c : s.components()) {
1074 exprUsed[argMap[c].fArgIndex]++;
1075 }
1076
1077 bool safeToOptimize = true;
1078 for (int index = 0; index < numConstructorArgs; ++index) {
1079 int8_t constructorArgIndex = argMap[index].fArgIndex;
1080 const Expression& baseArg = *base.arguments()[constructorArgIndex];
1081
1082 // Check that non-trivial expressions are not swizzled in more than once.
John Stilesc30fbca2020-11-19 16:25:49 -05001083 if (exprUsed[constructorArgIndex] > 1 &&
1084 !Analysis::IsTrivialExpression(baseArg)) {
John Stiles0777ac42020-11-19 11:06:47 -05001085 safeToOptimize = false;
1086 break;
1087 }
1088 // Check that side-effect-bearing expressions are swizzled in exactly once.
1089 if (exprUsed[constructorArgIndex] != 1 && baseArg.hasSideEffects()) {
1090 safeToOptimize = false;
1091 break;
1092 }
1093 }
1094
1095 if (safeToOptimize) {
John Stilesd9076cb2020-11-19 12:18:36 -05001096 struct ReorderedArgument {
1097 int8_t fArgIndex;
1098 ComponentArray fComponents;
1099 };
1100 SkSTArray<4, ReorderedArgument> reorderedArgs;
John Stiles0777ac42020-11-19 11:06:47 -05001101 for (int c : s.components()) {
1102 const ConstructorArgMap& argument = argMap[c];
1103 const Expression& baseArg = *base.arguments()[argument.fArgIndex];
1104
John Stiles9aeed132020-11-24 17:36:06 -05001105 if (baseArg.type().isScalar()) {
John Stilesd9076cb2020-11-19 12:18:36 -05001106 // This argument is a scalar; add it to the list as-is.
John Stiles0777ac42020-11-19 11:06:47 -05001107 SkASSERT(argument.fComponent == 0);
John Stilesd9076cb2020-11-19 12:18:36 -05001108 reorderedArgs.push_back({argument.fArgIndex,
1109 ComponentArray{}});
John Stiles0777ac42020-11-19 11:06:47 -05001110 } else {
John Stilesd9076cb2020-11-19 12:18:36 -05001111 // This argument is a component from a vector.
John Stiles0777ac42020-11-19 11:06:47 -05001112 SkASSERT(argument.fComponent < baseArg.type().columns());
John Stilesd9076cb2020-11-19 12:18:36 -05001113 if (reorderedArgs.empty() ||
1114 reorderedArgs.back().fArgIndex != argument.fArgIndex) {
1115 // This can't be combined with the previous argument. Add a new one.
1116 reorderedArgs.push_back({argument.fArgIndex,
1117 ComponentArray{argument.fComponent}});
1118 } else {
1119 // Since we know this argument uses components, it should already
1120 // have at least one component set.
1121 SkASSERT(!reorderedArgs.back().fComponents.empty());
1122 // Build up the current argument with one more component.
1123 reorderedArgs.back().fComponents.push_back(argument.fComponent);
1124 }
John Stiles0777ac42020-11-19 11:06:47 -05001125 }
1126 }
John Stilesd9076cb2020-11-19 12:18:36 -05001127
1128 // Convert our reordered argument list to an actual array of expressions, with
1129 // the new order and any new inner swizzles that need to be applied. Note that
1130 // we expect followup passes to clean up the inner swizzles.
1131 ExpressionArray newArgs;
1132 newArgs.reserve_back(swizzleSize);
1133 for (const ReorderedArgument& reorderedArg : reorderedArgs) {
1134 const Expression& baseArg = *base.arguments()[reorderedArg.fArgIndex];
1135 if (reorderedArg.fComponents.empty()) {
1136 newArgs.push_back(baseArg.clone());
1137 } else {
1138 newArgs.push_back(std::make_unique<Swizzle>(*fContext, baseArg.clone(),
1139 reorderedArg.fComponents));
1140 }
1141 }
1142
1143 // Create a new constructor.
John Stiles0777ac42020-11-19 11:06:47 -05001144 replacement = std::make_unique<Constructor>(
1145 base.fOffset,
1146 &componentType.toCompound(*fContext, swizzleSize, /*rows=*/1),
1147 std::move(newArgs));
1148
John Stilesa60ac0c2020-12-22 08:59:51 -05001149 // Remove references within 'expr', add references within 'replacement.'
John Stiles0777ac42020-11-19 11:06:47 -05001150 optimizationContext->fUsage->replace(expr, replacement.get());
John Stilesa60ac0c2020-12-22 08:59:51 -05001151
1152 // We're replacing an expression with a cloned version; we'll need a rescan.
1153 try_replace_expression(&b, iter, &replacement);
1154 optimizationContext->fUpdated = true;
1155 optimizationContext->fNeedsRescan = true;
John Stiles0777ac42020-11-19 11:06:47 -05001156 }
John Stiles108bbe22020-11-18 11:10:38 -05001157 break;
Ethan Nicholas409f6f02019-09-17 12:34:39 -04001158 }
John Stiles30212b72020-06-11 17:55:07 -04001159 break;
Ethan Nicholascb670962017-04-20 19:31:52 -04001160 }
1161 default:
1162 break;
1163 }
1164}
1165
John Stiles92219b42020-06-15 12:32:24 -04001166// Returns true if this statement could potentially execute a break at the current level. We ignore
1167// nested loops and switches, since any breaks inside of them will merely break the loop / switch.
John Stilesb92641c2020-08-31 18:09:01 -04001168static bool contains_conditional_break(Statement& stmt) {
1169 class ContainsConditionalBreak : public ProgramVisitor {
1170 public:
1171 bool visitStatement(const Statement& stmt) override {
Ethan Nicholase6592142020-09-08 10:22:09 -04001172 switch (stmt.kind()) {
1173 case Statement::Kind::kBlock:
John Stilesb92641c2020-08-31 18:09:01 -04001174 return this->INHERITED::visitStatement(stmt);
1175
Ethan Nicholase6592142020-09-08 10:22:09 -04001176 case Statement::Kind::kBreak:
John Stilesb92641c2020-08-31 18:09:01 -04001177 return fInConditional > 0;
1178
Ethan Nicholase6592142020-09-08 10:22:09 -04001179 case Statement::Kind::kIf: {
John Stilesb92641c2020-08-31 18:09:01 -04001180 ++fInConditional;
1181 bool result = this->INHERITED::visitStatement(stmt);
1182 --fInConditional;
1183 return result;
1184 }
1185
1186 default:
1187 return false;
1188 }
1189 }
1190
1191 int fInConditional = 0;
1192 using INHERITED = ProgramVisitor;
1193 };
1194
1195 return ContainsConditionalBreak{}.visitStatement(stmt);
John Stiles92219b42020-06-15 12:32:24 -04001196}
1197
Ethan Nicholas5005a222018-08-24 13:06:27 -04001198// returns true if this statement definitely executes a break at the current level (we ignore
1199// nested loops and switches, since any breaks inside of them will merely break the loop / switch)
John Stilesb92641c2020-08-31 18:09:01 -04001200static bool contains_unconditional_break(Statement& stmt) {
1201 class ContainsUnconditionalBreak : public ProgramVisitor {
1202 public:
1203 bool visitStatement(const Statement& stmt) override {
Ethan Nicholase6592142020-09-08 10:22:09 -04001204 switch (stmt.kind()) {
1205 case Statement::Kind::kBlock:
John Stilesb92641c2020-08-31 18:09:01 -04001206 return this->INHERITED::visitStatement(stmt);
1207
Ethan Nicholase6592142020-09-08 10:22:09 -04001208 case Statement::Kind::kBreak:
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001209 return true;
John Stilesb92641c2020-08-31 18:09:01 -04001210
1211 default:
1212 return false;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001213 }
John Stilesb92641c2020-08-31 18:09:01 -04001214 }
John Stiles92219b42020-06-15 12:32:24 -04001215
John Stilesb92641c2020-08-31 18:09:01 -04001216 using INHERITED = ProgramVisitor;
1217 };
John Stiles92219b42020-06-15 12:32:24 -04001218
John Stilesb92641c2020-08-31 18:09:01 -04001219 return ContainsUnconditionalBreak{}.visitStatement(stmt);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001220}
1221
John Stiles8f2a0cf2020-10-13 12:48:21 -04001222static void move_all_but_break(std::unique_ptr<Statement>& stmt, StatementArray* target) {
Ethan Nicholase6592142020-09-08 10:22:09 -04001223 switch (stmt->kind()) {
1224 case Statement::Kind::kBlock: {
John Stiles92219b42020-06-15 12:32:24 -04001225 // Recurse into the block.
1226 Block& block = static_cast<Block&>(*stmt);
1227
John Stiles8f2a0cf2020-10-13 12:48:21 -04001228 StatementArray blockStmts;
John Stilesf4bda742020-10-14 16:57:41 -04001229 blockStmts.reserve_back(block.children().size());
Ethan Nicholas7bd60432020-09-25 14:31:59 -04001230 for (std::unique_ptr<Statement>& stmt : block.children()) {
1231 move_all_but_break(stmt, &blockStmts);
Ethan Nicholas739e1ca2020-06-11 12:16:14 -04001232 }
John Stiles92219b42020-06-15 12:32:24 -04001233
1234 target->push_back(std::make_unique<Block>(block.fOffset, std::move(blockStmts),
Ethan Nicholas7bd60432020-09-25 14:31:59 -04001235 block.symbolTable(), block.isScope()));
Ethan Nicholas739e1ca2020-06-11 12:16:14 -04001236 break;
John Stiles92219b42020-06-15 12:32:24 -04001237 }
1238
Ethan Nicholase6592142020-09-08 10:22:09 -04001239 case Statement::Kind::kBreak:
John Stiles92219b42020-06-15 12:32:24 -04001240 // Do not append a break to the target.
1241 break;
1242
Ethan Nicholas739e1ca2020-06-11 12:16:14 -04001243 default:
John Stiles92219b42020-06-15 12:32:24 -04001244 // Append normal statements to the target.
1245 target->push_back(std::move(stmt));
1246 break;
Ethan Nicholas739e1ca2020-06-11 12:16:14 -04001247 }
1248}
1249
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001250// Returns a block containing all of the statements that will be run if the given case matches
1251// (which, owing to the statements being owned by unique_ptrs, means the switch itself will be
1252// broken by this call and must then be discarded).
1253// Returns null (and leaves the switch unmodified) if no such simple reduction is possible, such as
1254// when break statements appear inside conditionals.
John Stiles92219b42020-06-15 12:32:24 -04001255static std::unique_ptr<Statement> block_for_case(SwitchStatement* switchStatement,
1256 SwitchCase* caseToCapture) {
1257 // We have to be careful to not move any of the pointers until after we're sure we're going to
1258 // succeed, so before we make any changes at all, we check the switch-cases to decide on a plan
1259 // of action. First, find the switch-case we are interested in.
Ethan Nicholas01b05e52020-10-22 15:53:41 -04001260 auto iter = switchStatement->cases().begin();
1261 for (; iter != switchStatement->cases().end(); ++iter) {
John Stiles2d4f9592020-10-30 10:29:12 -04001262 if (iter->get() == caseToCapture) {
John Stiles92219b42020-06-15 12:32:24 -04001263 break;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001264 }
John Stiles92219b42020-06-15 12:32:24 -04001265 }
1266
1267 // Next, walk forward through the rest of the switch. If we find a conditional break, we're
1268 // stuck and can't simplify at all. If we find an unconditional break, we have a range of
1269 // statements that we can use for simplification.
1270 auto startIter = iter;
1271 Statement* unconditionalBreakStmt = nullptr;
Ethan Nicholas01b05e52020-10-22 15:53:41 -04001272 for (; iter != switchStatement->cases().end(); ++iter) {
John Stiles2d4f9592020-10-30 10:29:12 -04001273 for (std::unique_ptr<Statement>& stmt : (*iter)->statements()) {
John Stiles92219b42020-06-15 12:32:24 -04001274 if (contains_conditional_break(*stmt)) {
1275 // We can't reduce switch-cases to a block when they have conditional breaks.
1276 return nullptr;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001277 }
John Stiles92219b42020-06-15 12:32:24 -04001278
1279 if (contains_unconditional_break(*stmt)) {
1280 // We found an unconditional break. We can use this block, but we need to strip
1281 // out the break statement.
1282 unconditionalBreakStmt = stmt.get();
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001283 break;
1284 }
1285 }
John Stiles92219b42020-06-15 12:32:24 -04001286
1287 if (unconditionalBreakStmt != nullptr) {
1288 break;
1289 }
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001290 }
John Stiles92219b42020-06-15 12:32:24 -04001291
1292 // We fell off the bottom of the switch or encountered a break. We know the range of statements
1293 // that we need to move over, and we know it's safe to do so.
John Stiles8f2a0cf2020-10-13 12:48:21 -04001294 StatementArray caseStmts;
John Stiles92219b42020-06-15 12:32:24 -04001295
1296 // We can move over most of the statements as-is.
1297 while (startIter != iter) {
John Stiles2d4f9592020-10-30 10:29:12 -04001298 for (std::unique_ptr<Statement>& stmt : (*startIter)->statements()) {
John Stiles92219b42020-06-15 12:32:24 -04001299 caseStmts.push_back(std::move(stmt));
1300 }
1301 ++startIter;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001302 }
John Stiles92219b42020-06-15 12:32:24 -04001303
1304 // If we found an unconditional break at the end, we need to move what we can while avoiding
1305 // that break.
1306 if (unconditionalBreakStmt != nullptr) {
John Stiles2d4f9592020-10-30 10:29:12 -04001307 for (std::unique_ptr<Statement>& stmt : (*startIter)->statements()) {
John Stiles92219b42020-06-15 12:32:24 -04001308 if (stmt.get() == unconditionalBreakStmt) {
1309 move_all_but_break(stmt, &caseStmts);
1310 unconditionalBreakStmt = nullptr;
1311 break;
1312 }
1313
1314 caseStmts.push_back(std::move(stmt));
1315 }
1316 }
1317
1318 SkASSERT(unconditionalBreakStmt == nullptr); // Verify that we fixed the unconditional break.
1319
1320 // Return our newly-synthesized block.
Ethan Nicholas01b05e52020-10-22 15:53:41 -04001321 return std::make_unique<Block>(/*offset=*/-1, std::move(caseStmts), switchStatement->symbols());
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001322}
1323
Ethan Nicholascb670962017-04-20 19:31:52 -04001324void Compiler::simplifyStatement(DefinitionMap& definitions,
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001325 BasicBlock& b,
1326 std::vector<BasicBlock::Node>::iterator* iter,
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001327 OptimizationContext* optimizationContext) {
Brian Osman010ce6a2020-10-19 16:34:10 -04001328 ProgramUsage* usage = optimizationContext->fUsage;
Ethan Nicholascb670962017-04-20 19:31:52 -04001329 Statement* stmt = (*iter)->statement()->get();
Ethan Nicholase6592142020-09-08 10:22:09 -04001330 switch (stmt->kind()) {
1331 case Statement::Kind::kVarDeclaration: {
John Stilesa5a97b42020-08-18 11:19:07 -04001332 const auto& varDecl = stmt->as<VarDeclaration>();
Brian Osman010ce6a2020-10-19 16:34:10 -04001333 if (usage->isDead(varDecl.var()) &&
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04001334 (!varDecl.value() ||
1335 !varDecl.value()->hasSideEffects())) {
1336 if (varDecl.value()) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001337 SkASSERT((*iter)->statement()->get() == stmt);
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04001338 if (!b.tryRemoveExpressionBefore(iter, varDecl.value().get())) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001339 optimizationContext->fNeedsRescan = true;
Ethan Nicholascb670962017-04-20 19:31:52 -04001340 }
Ethan Nicholascb670962017-04-20 19:31:52 -04001341 }
Ethan Nicholas5b9b0db2021-01-21 13:12:01 -05001342 // There can still be (soon to be removed) references to the variable at this point.
1343 // Allowing the VarDeclaration to be destroyed here will break those variable's
1344 // initialValue()s, so we hang on to them until optimization is finished.
1345 std::unique_ptr<Statement> old = (*iter)->setStatement(std::make_unique<Nop>(),
1346 usage);
1347 optimizationContext->fOwnedStatements.push_back(std::move(old));
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001348 optimizationContext->fUpdated = true;
Ethan Nicholascb670962017-04-20 19:31:52 -04001349 }
1350 break;
1351 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001352 case Statement::Kind::kIf: {
John Stilesa5a97b42020-08-18 11:19:07 -04001353 IfStatement& i = stmt->as<IfStatement>();
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001354 if (i.test()->kind() == Expression::Kind::kBoolLiteral) {
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001355 // constant if, collapse down to a single branch
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001356 if (i.test()->as<BoolLiteral>().value()) {
1357 SkASSERT(i.ifTrue());
Brian Osman010ce6a2020-10-19 16:34:10 -04001358 (*iter)->setStatement(std::move(i.ifTrue()), usage);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001359 } else {
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001360 if (i.ifFalse()) {
Brian Osman010ce6a2020-10-19 16:34:10 -04001361 (*iter)->setStatement(std::move(i.ifFalse()), usage);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001362 } else {
Brian Osman010ce6a2020-10-19 16:34:10 -04001363 (*iter)->setStatement(std::make_unique<Nop>(), usage);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001364 }
1365 }
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001366 optimizationContext->fUpdated = true;
1367 optimizationContext->fNeedsRescan = true;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001368 break;
1369 }
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001370 if (i.ifFalse() && i.ifFalse()->isEmpty()) {
Ethan Nicholascb670962017-04-20 19:31:52 -04001371 // else block doesn't do anything, remove it
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001372 i.ifFalse().reset();
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001373 optimizationContext->fUpdated = true;
1374 optimizationContext->fNeedsRescan = true;
Ethan Nicholascb670962017-04-20 19:31:52 -04001375 }
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001376 if (!i.ifFalse() && i.ifTrue()->isEmpty()) {
Ethan Nicholascb670962017-04-20 19:31:52 -04001377 // if block doesn't do anything, no else block
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001378 if (i.test()->hasSideEffects()) {
Ethan Nicholascb670962017-04-20 19:31:52 -04001379 // test has side effects, keep it
Brian Osman010ce6a2020-10-19 16:34:10 -04001380 (*iter)->setStatement(
1381 std::make_unique<ExpressionStatement>(std::move(i.test())), usage);
Ethan Nicholascb670962017-04-20 19:31:52 -04001382 } else {
1383 // no if, no else, no test side effects, kill the whole if
1384 // statement
Brian Osman010ce6a2020-10-19 16:34:10 -04001385 (*iter)->setStatement(std::make_unique<Nop>(), usage);
Ethan Nicholascb670962017-04-20 19:31:52 -04001386 }
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001387 optimizationContext->fUpdated = true;
1388 optimizationContext->fNeedsRescan = true;
Ethan Nicholascb670962017-04-20 19:31:52 -04001389 }
1390 break;
1391 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001392 case Statement::Kind::kSwitch: {
John Stilesa5a97b42020-08-18 11:19:07 -04001393 SwitchStatement& s = stmt->as<SwitchStatement>();
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001394 int64_t switchValue;
Ethan Nicholasc0f98152021-02-05 16:21:10 -05001395 if (ConstantFolder::GetConstantInt(*s.value(), &switchValue)) {
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001396 // switch is constant, replace it with the case that matches
1397 bool found = false;
1398 SwitchCase* defaultCase = nullptr;
John Stiles2d4f9592020-10-30 10:29:12 -04001399 for (const std::unique_ptr<SwitchCase>& c : s.cases()) {
1400 if (!c->value()) {
1401 defaultCase = c.get();
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001402 continue;
1403 }
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001404 int64_t caseValue;
Ethan Nicholasc0f98152021-02-05 16:21:10 -05001405 SkAssertResult(ConstantFolder::GetConstantInt(*c->value(), &caseValue));
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001406 if (caseValue == switchValue) {
John Stiles2d4f9592020-10-30 10:29:12 -04001407 std::unique_ptr<Statement> newBlock = block_for_case(&s, c.get());
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001408 if (newBlock) {
Brian Osman010ce6a2020-10-19 16:34:10 -04001409 (*iter)->setStatement(std::move(newBlock), usage);
John Stiles9d944232020-08-19 09:56:49 -04001410 found = true;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001411 break;
1412 } else {
John Stilesd6a5f4492021-02-11 15:46:11 -05001413 if (s.isStatic() &&
1414 !fIRGenerator->fSettings->fPermitInvalidStaticTests) {
1415 auto [iter, didInsert] = optimizationContext->fSilences.insert(&s);
1416 if (didInsert) {
1417 this->error(s.fOffset, "static switch contains non-static "
1418 "conditional break");
1419 }
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 {
John Stilesd6a5f4492021-02-11 15:46:11 -05001432 if (s.isStatic() &&
1433 !fIRGenerator->fSettings->fPermitInvalidStaticTests) {
1434 auto [iter, didInsert] = optimizationContext->fSilences.insert(&s);
1435 if (didInsert) {
1436 this->error(s.fOffset, "static switch contains non-static "
1437 "conditional break");
1438 }
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001439 }
1440 return; // can't simplify
1441 }
1442 } else {
Brian Osman010ce6a2020-10-19 16:34:10 -04001443 (*iter)->setStatement(std::make_unique<Nop>(), usage);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001444 }
1445 }
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001446 optimizationContext->fUpdated = true;
1447 optimizationContext->fNeedsRescan = true;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001448 }
1449 break;
1450 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001451 case Statement::Kind::kExpression: {
John Stilesa5a97b42020-08-18 11:19:07 -04001452 ExpressionStatement& e = stmt->as<ExpressionStatement>();
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001453 SkASSERT((*iter)->statement()->get() == &e);
Ethan Nicholasd503a5a2020-09-30 09:29:55 -04001454 if (!e.expression()->hasSideEffects()) {
Ethan Nicholascb670962017-04-20 19:31:52 -04001455 // Expression statement with no side effects, kill it
Ethan Nicholasd503a5a2020-09-30 09:29:55 -04001456 if (!b.tryRemoveExpressionBefore(iter, e.expression().get())) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001457 optimizationContext->fNeedsRescan = true;
Ethan Nicholascb670962017-04-20 19:31:52 -04001458 }
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001459 SkASSERT((*iter)->statement()->get() == stmt);
Brian Osman010ce6a2020-10-19 16:34:10 -04001460 (*iter)->setStatement(std::make_unique<Nop>(), usage);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001461 optimizationContext->fUpdated = true;
Ethan Nicholascb670962017-04-20 19:31:52 -04001462 }
1463 break;
1464 }
1465 default:
1466 break;
1467 }
1468}
1469
Brian Osman010ce6a2020-10-19 16:34:10 -04001470bool Compiler::scanCFG(FunctionDefinition& f, ProgramUsage* usage) {
John Stiles0cc193a2020-09-09 09:39:34 -04001471 bool madeChanges = false;
1472
Ethan Nicholascb670962017-04-20 19:31:52 -04001473 CFG cfg = CFGGenerator().getCFG(f);
1474 this->computeDataFlow(&cfg);
ethannicholas22f939e2016-10-13 13:25:34 -07001475
1476 // check for unreachable code
1477 for (size_t i = 0; i < cfg.fBlocks.size(); i++) {
John Stiles0cc193a2020-09-09 09:39:34 -04001478 const BasicBlock& block = cfg.fBlocks[i];
John Stiles40525102020-12-16 18:10:44 -05001479 if (!block.fIsReachable && !block.fAllowUnreachable && block.fNodes.size()) {
John Stiles0cc193a2020-09-09 09:39:34 -04001480 const BasicBlock::Node& node = block.fNodes[0];
John Stilesc1129322021-02-03 10:13:42 -05001481 int offset = node.isStatement() ? (*node.statement())->fOffset
1482 : (*node.expression())->fOffset;
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001483 this->error(offset, String("unreachable"));
ethannicholas22f939e2016-10-13 13:25:34 -07001484 }
1485 }
1486 if (fErrorCount) {
John Stiles0cc193a2020-09-09 09:39:34 -04001487 return madeChanges;
ethannicholas22f939e2016-10-13 13:25:34 -07001488 }
1489
Ethan Nicholascb670962017-04-20 19:31:52 -04001490 // check for dead code & undefined variables, perform constant propagation
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001491 OptimizationContext optimizationContext;
Brian Osman010ce6a2020-10-19 16:34:10 -04001492 optimizationContext.fUsage = usage;
John Stiles7d3f0892020-11-03 11:35:01 -05001493 SkBitSet eliminatedBlockIds(cfg.fBlocks.size());
Ethan Nicholascb670962017-04-20 19:31:52 -04001494 do {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001495 if (optimizationContext.fNeedsRescan) {
Ethan Nicholascb670962017-04-20 19:31:52 -04001496 cfg = CFGGenerator().getCFG(f);
1497 this->computeDataFlow(&cfg);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001498 optimizationContext.fNeedsRescan = false;
Ethan Nicholas113628d2017-02-02 16:11:39 -05001499 }
Ethan Nicholascb670962017-04-20 19:31:52 -04001500
John Stiles7d3f0892020-11-03 11:35:01 -05001501 eliminatedBlockIds.reset();
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001502 optimizationContext.fUpdated = false;
John Stiles7d3f0892020-11-03 11:35:01 -05001503
1504 for (BlockId blockId = 0; blockId < cfg.fBlocks.size(); ++blockId) {
1505 if (eliminatedBlockIds.test(blockId)) {
1506 // We reached a block ID that might have been eliminated. Be cautious and rescan.
1507 optimizationContext.fUpdated = true;
1508 optimizationContext.fNeedsRescan = true;
1509 break;
1510 }
1511
1512 BasicBlock& b = cfg.fBlocks[blockId];
1513 if (blockId > 0 && !b.fIsReachable) {
Ethan Nicholas1de14812020-06-19 15:32:49 -04001514 // Block was reachable before optimization, but has since become unreachable. In
1515 // addition to being dead code, it's broken - since control flow can't reach it, no
1516 // prior variable definitions can reach it, and therefore variables might look to
Brian Osmanc0213602020-10-06 14:43:32 -04001517 // have not been properly assigned. Kill it by replacing all statements with Nops.
Ethan Nicholas1de14812020-06-19 15:32:49 -04001518 for (BasicBlock::Node& node : b.fNodes) {
John Stiles70025e52020-09-28 16:08:58 -04001519 if (node.isStatement() && !(*node.statement())->is<Nop>()) {
John Stiles7d3f0892020-11-03 11:35:01 -05001520 // Eliminating a node runs the risk of eliminating that node's exits as
1521 // well. Keep track of this and do a rescan if we are about to access one
1522 // of these.
1523 for (BlockId id : b.fExits) {
1524 eliminatedBlockIds.set(id);
1525 }
Brian Osman010ce6a2020-10-19 16:34:10 -04001526 node.setStatement(std::make_unique<Nop>(), usage);
John Stiles0cc193a2020-09-09 09:39:34 -04001527 madeChanges = true;
Ethan Nicholas1de14812020-06-19 15:32:49 -04001528 }
1529 }
1530 continue;
1531 }
Ethan Nicholascb670962017-04-20 19:31:52 -04001532 DefinitionMap definitions = b.fBefore;
1533
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001534 for (auto iter = b.fNodes.begin(); iter != b.fNodes.end() &&
1535 !optimizationContext.fNeedsRescan; ++iter) {
John Stiles70025e52020-09-28 16:08:58 -04001536 if (iter->isExpression()) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001537 this->simplifyExpression(definitions, b, &iter, &optimizationContext);
Ethan Nicholascb670962017-04-20 19:31:52 -04001538 } else {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001539 this->simplifyStatement(definitions, b, &iter, &optimizationContext);
Ethan Nicholascb670962017-04-20 19:31:52 -04001540 }
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001541 if (optimizationContext.fNeedsRescan) {
Ethan Nicholas4b330df2017-05-17 10:52:55 -04001542 break;
1543 }
John Stilese8a24922021-02-08 17:54:08 -05001544 definitions.addDefinitions(*fContext, *iter);
Ethan Nicholascb670962017-04-20 19:31:52 -04001545 }
Brian Osman01a3eb42020-09-14 11:32:49 -04001546
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001547 if (optimizationContext.fNeedsRescan) {
Brian Osman01a3eb42020-09-14 11:32:49 -04001548 break;
1549 }
Ethan Nicholascb670962017-04-20 19:31:52 -04001550 }
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001551 madeChanges |= optimizationContext.fUpdated;
1552 } while (optimizationContext.fUpdated);
1553 SkASSERT(!optimizationContext.fNeedsRescan);
ethannicholas22f939e2016-10-13 13:25:34 -07001554
Ethan Nicholas91a10532017-06-22 11:24:38 -04001555 // verify static ifs & switches, clean up dead variable decls
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001556 for (BasicBlock& b : cfg.fBlocks) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001557 for (auto iter = b.fNodes.begin(); iter != b.fNodes.end() &&
1558 !optimizationContext.fNeedsRescan;) {
John Stiles70025e52020-09-28 16:08:58 -04001559 if (iter->isStatement()) {
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001560 const Statement& s = **iter->statement();
Ethan Nicholase6592142020-09-08 10:22:09 -04001561 switch (s.kind()) {
1562 case Statement::Kind::kIf:
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001563 if (s.as<IfStatement>().isStatic() &&
John Stilesd6a5f4492021-02-11 15:46:11 -05001564 !fIRGenerator->fSettings->fPermitInvalidStaticTests) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001565 this->error(s.fOffset, "static if has non-static test");
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001566 }
Ethan Nicholas91a10532017-06-22 11:24:38 -04001567 ++iter;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001568 break;
Ethan Nicholase6592142020-09-08 10:22:09 -04001569 case Statement::Kind::kSwitch:
Ethan Nicholas01b05e52020-10-22 15:53:41 -04001570 if (s.as<SwitchStatement>().isStatic() &&
John Stilesd6a5f4492021-02-11 15:46:11 -05001571 !fIRGenerator->fSettings->fPermitInvalidStaticTests &&
Ethan Nicholas01b05e52020-10-22 15:53:41 -04001572 optimizationContext.fSilences.find(&s) ==
John Stilesd6a5f4492021-02-11 15:46:11 -05001573 optimizationContext.fSilences.end()) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001574 this->error(s.fOffset, "static switch has non-static test");
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001575 }
Ethan Nicholas91a10532017-06-22 11:24:38 -04001576 ++iter;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001577 break;
1578 default:
Ethan Nicholas91a10532017-06-22 11:24:38 -04001579 ++iter;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001580 break;
1581 }
Ethan Nicholas91a10532017-06-22 11:24:38 -04001582 } else {
1583 ++iter;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001584 }
1585 }
1586 }
1587
ethannicholas22f939e2016-10-13 13:25:34 -07001588 // check for missing return
John Stiles54e7c052021-01-11 14:22:36 -05001589 if (f.declaration().returnType() != *fContext->fTypes.fVoid) {
John Stiles61e75e32020-10-01 15:42:37 -04001590 if (cfg.fBlocks[cfg.fExit].fIsReachable) {
Ethan Nicholas0a5d0962020-10-14 13:33:18 -04001591 this->error(f.fOffset, String("function '" + String(f.declaration().name()) +
Ethan Nicholasdb80f692019-11-22 14:06:12 -05001592 "' can exit without returning a value"));
ethannicholas22f939e2016-10-13 13:25:34 -07001593 }
1594 }
John Stiles0cc193a2020-09-09 09:39:34 -04001595
1596 return madeChanges;
ethannicholas22f939e2016-10-13 13:25:34 -07001597}
1598
Brian Osman32d53552020-09-23 13:55:20 -04001599std::unique_ptr<Program> Compiler::convertProgram(
1600 Program::Kind kind,
1601 String text,
1602 const Program::Settings& settings,
Brian Osmanbe0b3b72021-01-06 14:27:35 -05001603 const std::vector<std::unique_ptr<ExternalFunction>>* externalFunctions) {
1604 SkASSERT(!externalFunctions || (kind == Program::kGeneric_Kind));
Ethan Nicholas91164d12019-05-15 15:29:54 -04001605
Brian Osman0006ad02020-11-18 15:38:39 -05001606 // Loading and optimizing our base module might reset the inliner, so do that first,
1607 // *then* configure the inliner with the settings for this program.
1608 const ParsedModule& baseModule = this->moduleForProgramKind(kind);
1609
ethannicholasb3058bd2016-07-01 08:22:01 -07001610 fErrorText = "";
1611 fErrorCount = 0;
Brian Osman0006ad02020-11-18 15:38:39 -05001612 fInliner.reset(fIRGenerator->fModifiers.get(), &settings);
Brian Osman88cda172020-10-09 12:05:16 -04001613
1614 // Not using AutoSource, because caller is likely to call errorText() if we fail to compile
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001615 std::unique_ptr<String> textPtr(new String(std::move(text)));
1616 fSource = textPtr.get();
Brian Osman88cda172020-10-09 12:05:16 -04001617
John Stiles5c7bb322020-10-22 11:09:15 -04001618 // Enable node pooling while converting and optimizing the program for a performance boost.
1619 // The Program will take ownership of the pool.
Brian Osman28f702c2021-02-02 11:52:07 -05001620 std::unique_ptr<Pool> pool;
1621 if (fCaps->useNodePools()) {
1622 pool = Pool::Create();
1623 pool->attachToThread();
1624 }
Brian Osman0006ad02020-11-18 15:38:39 -05001625 IRGenerator::IRBundle ir =
1626 fIRGenerator->convertProgram(kind, &settings, baseModule, /*isBuiltinCode=*/false,
Brian Osmanbe0b3b72021-01-06 14:27:35 -05001627 textPtr->c_str(), textPtr->size(), externalFunctions);
John Stiles5c7bb322020-10-22 11:09:15 -04001628 auto program = std::make_unique<Program>(kind,
1629 std::move(textPtr),
1630 settings,
Brian Osmand7e76592020-11-02 12:26:22 -05001631 fCaps,
John Stiles5c7bb322020-10-22 11:09:15 -04001632 fContext,
1633 std::move(ir.fElements),
Brian Osman133724c2020-10-28 14:14:39 -04001634 std::move(ir.fSharedElements),
John Stiles5c7bb322020-10-22 11:09:15 -04001635 std::move(ir.fModifiers),
1636 std::move(ir.fSymbolTable),
1637 std::move(pool),
1638 ir.fInputs);
1639 bool success = false;
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001640 if (fErrorCount) {
John Stiles5c7bb322020-10-22 11:09:15 -04001641 // Do not return programs that failed to compile.
1642 } else if (settings.fOptimize && !this->optimize(*program)) {
1643 // Do not return programs that failed to optimize.
1644 } else {
1645 // We have a successful program!
1646 success = true;
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001647 }
John Stiles5c7bb322020-10-22 11:09:15 -04001648
Brian Osman28f702c2021-02-02 11:52:07 -05001649 if (program->fPool) {
1650 program->fPool->detachFromThread();
1651 }
John Stiles5c7bb322020-10-22 11:09:15 -04001652 return success ? std::move(program) : nullptr;
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001653}
1654
Brian Osman0006ad02020-11-18 15:38:39 -05001655bool Compiler::optimize(LoadedModule& module) {
1656 SkASSERT(!fErrorCount);
1657 Program::Settings settings;
1658 fIRGenerator->fKind = module.fKind;
1659 fIRGenerator->fSettings = &settings;
1660 std::unique_ptr<ProgramUsage> usage = Analysis::GetUsage(module);
1661
1662 fInliner.reset(fModifiers.back().get(), &settings);
1663
1664 while (fErrorCount == 0) {
1665 bool madeChanges = false;
1666
1667 // Scan and optimize based on the control-flow graph for each function.
1668 for (const auto& element : module.fElements) {
1669 if (element->is<FunctionDefinition>()) {
1670 madeChanges |= this->scanCFG(element->as<FunctionDefinition>(), usage.get());
1671 }
1672 }
1673
1674 // Perform inline-candidate analysis and inline any functions deemed suitable.
John Stiles78047582020-12-16 16:17:41 -05001675 madeChanges |= fInliner.analyze(module.fElements, module.fSymbols, usage.get());
Brian Osman0006ad02020-11-18 15:38:39 -05001676
1677 if (!madeChanges) {
1678 break;
1679 }
1680 }
1681 return fErrorCount == 0;
1682}
1683
Ethan Nicholas00543112018-07-31 09:44:36 -04001684bool Compiler::optimize(Program& program) {
1685 SkASSERT(!fErrorCount);
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001686 fIRGenerator->fKind = program.fKind;
1687 fIRGenerator->fSettings = &program.fSettings;
Brian Osman010ce6a2020-10-19 16:34:10 -04001688 ProgramUsage* usage = program.fUsage.get();
John Stiles7954d6c2020-09-01 10:53:02 -04001689
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001690 while (fErrorCount == 0) {
1691 bool madeChanges = false;
John Stiles7954d6c2020-09-01 10:53:02 -04001692
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001693 // Scan and optimize based on the control-flow graph for each function.
Brian Osman133724c2020-10-28 14:14:39 -04001694 for (const auto& element : program.ownedElements()) {
Brian Osman1179fcf2020-10-08 16:04:40 -04001695 if (element->is<FunctionDefinition>()) {
Brian Osman010ce6a2020-10-19 16:34:10 -04001696 madeChanges |= this->scanCFG(element->as<FunctionDefinition>(), usage);
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001697 }
1698 }
1699
1700 // Perform inline-candidate analysis and inline any functions deemed suitable.
John Stiles78047582020-12-16 16:17:41 -05001701 madeChanges |= fInliner.analyze(program.ownedElements(), program.fSymbols, usage);
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001702
1703 // Remove dead functions. We wait until after analysis so that we still report errors,
1704 // even in unused code.
1705 if (program.fSettings.fRemoveDeadFunctions) {
Brian Osman133724c2020-10-28 14:14:39 -04001706 auto isDeadFunction = [&](const ProgramElement* element) {
1707 if (!element->is<FunctionDefinition>()) {
1708 return false;
1709 }
1710 const FunctionDefinition& fn = element->as<FunctionDefinition>();
1711 if (fn.declaration().name() != "main" && usage->get(fn.declaration()) == 0) {
1712 usage->remove(*element);
1713 madeChanges = true;
1714 return true;
1715 }
1716 return false;
1717 };
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001718 program.fElements.erase(
Brian Osman133724c2020-10-28 14:14:39 -04001719 std::remove_if(program.fElements.begin(), program.fElements.end(),
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001720 [&](const std::unique_ptr<ProgramElement>& element) {
Brian Osman133724c2020-10-28 14:14:39 -04001721 return isDeadFunction(element.get());
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001722 }),
1723 program.fElements.end());
Brian Osman133724c2020-10-28 14:14:39 -04001724 program.fSharedElements.erase(
1725 std::remove_if(program.fSharedElements.begin(), program.fSharedElements.end(),
1726 isDeadFunction),
1727 program.fSharedElements.end());
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001728 }
1729
1730 if (program.fKind != Program::kFragmentProcessor_Kind) {
Brian Osmanc0213602020-10-06 14:43:32 -04001731 // Remove declarations of dead global variables
Brian Osman133724c2020-10-28 14:14:39 -04001732 auto isDeadVariable = [&](const ProgramElement* element) {
1733 if (!element->is<GlobalVarDeclaration>()) {
1734 return false;
1735 }
1736 const GlobalVarDeclaration& global = element->as<GlobalVarDeclaration>();
1737 const VarDeclaration& varDecl = global.declaration()->as<VarDeclaration>();
1738 if (usage->isDead(varDecl.var())) {
1739 madeChanges = true;
1740 return true;
1741 }
1742 return false;
1743 };
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001744 program.fElements.erase(
1745 std::remove_if(program.fElements.begin(), program.fElements.end(),
1746 [&](const std::unique_ptr<ProgramElement>& element) {
Brian Osman133724c2020-10-28 14:14:39 -04001747 return isDeadVariable(element.get());
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001748 }),
1749 program.fElements.end());
Brian Osman133724c2020-10-28 14:14:39 -04001750 program.fSharedElements.erase(
1751 std::remove_if(program.fSharedElements.begin(), program.fSharedElements.end(),
1752 isDeadVariable),
1753 program.fSharedElements.end());
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001754 }
John Stiles73a6bff2020-09-09 13:40:37 -04001755
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001756 if (!madeChanges) {
1757 break;
Ethan Nicholas0dc80872019-02-08 15:46:24 -05001758 }
Ethan Nicholas00543112018-07-31 09:44:36 -04001759 }
1760 return fErrorCount == 0;
1761}
1762
Brian Osmanfb32ddf2019-06-18 10:14:20 -04001763#if defined(SKSL_STANDALONE) || SK_SUPPORT_GPU
1764
Ethan Nicholas00543112018-07-31 09:44:36 -04001765bool Compiler::toSPIRV(Program& program, OutputStream& out) {
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001766#ifdef SK_ENABLE_SPIRV_VALIDATION
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001767 StringStream buffer;
Brian Osman88cda172020-10-09 12:05:16 -04001768 AutoSource as(this, program.fSource.get());
Brian Osman8b43dad2020-10-09 13:31:42 -04001769 SPIRVCodeGenerator cg(fContext.get(), &program, this, &buffer);
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001770 bool result = cg.generateCode();
Ethan Nicholasba9a04f2020-11-06 09:28:04 -05001771 if (result && program.fSettings.fValidateSPIRV) {
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001772 spvtools::SpirvTools tools(SPV_ENV_VULKAN_1_0);
Ethan Nicholas762466e2017-06-29 10:03:38 -04001773 const String& data = buffer.str();
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001774 SkASSERT(0 == data.size() % 4);
Brian Osman8d09d4a2020-11-24 15:51:06 -05001775 String errors;
1776 auto dumpmsg = [&errors](spv_message_level_t, const char*, const spv_position_t&,
1777 const char* m) {
1778 errors.appendf("SPIR-V validation error: %s\n", m);
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001779 };
1780 tools.SetMessageConsumer(dumpmsg);
Brian Osman8d09d4a2020-11-24 15:51:06 -05001781
1782 // Verify that the SPIR-V we produced is valid. At runtime, we will abort() with a message
1783 // explaining the error. In standalone mode (skslc), we will send the message, plus the
1784 // entire disassembled SPIR-V (for easier context & debugging) as *our* error message.
1785 result = tools.Validate((const uint32_t*) data.c_str(), data.size() / 4);
1786
1787 if (!result) {
1788#if defined(SKSL_STANDALONE)
1789 // Convert the string-stream to a SPIR-V disassembly.
1790 std::string disassembly;
1791 if (tools.Disassemble((const uint32_t*)data.data(), data.size() / 4, &disassembly)) {
1792 errors.append(disassembly);
1793 }
1794 this->error(-1, errors);
1795#else
1796 SkDEBUGFAILF("%s", errors.c_str());
1797#endif
1798 }
Ethan Nicholas762466e2017-06-29 10:03:38 -04001799 out.write(data.c_str(), data.size());
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001800 }
1801#else
Brian Osman88cda172020-10-09 12:05:16 -04001802 AutoSource as(this, program.fSource.get());
Brian Osman8b43dad2020-10-09 13:31:42 -04001803 SPIRVCodeGenerator cg(fContext.get(), &program, this, &out);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001804 bool result = cg.generateCode();
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001805#endif
Ethan Nicholasce33f102016-12-09 17:22:59 -05001806 return result;
1807}
1808
Ethan Nicholas00543112018-07-31 09:44:36 -04001809bool Compiler::toSPIRV(Program& program, String* out) {
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001810 StringStream buffer;
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001811 bool result = this->toSPIRV(program, buffer);
1812 if (result) {
Ethan Nicholas762466e2017-06-29 10:03:38 -04001813 *out = buffer.str();
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001814 }
1815 return result;
1816}
1817
Ethan Nicholas00543112018-07-31 09:44:36 -04001818bool Compiler::toGLSL(Program& program, OutputStream& out) {
Brian Osman88cda172020-10-09 12:05:16 -04001819 AutoSource as(this, program.fSource.get());
Ethan Nicholas26a9aad2018-03-27 14:10:52 -04001820 GLSLCodeGenerator cg(fContext.get(), &program, this, &out);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001821 bool result = cg.generateCode();
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001822 return result;
1823}
1824
Ethan Nicholas00543112018-07-31 09:44:36 -04001825bool Compiler::toGLSL(Program& program, String* out) {
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001826 StringStream buffer;
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001827 bool result = this->toGLSL(program, buffer);
1828 if (result) {
Ethan Nicholas762466e2017-06-29 10:03:38 -04001829 *out = buffer.str();
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001830 }
1831 return result;
1832}
1833
Brian Osmanc0243912020-02-19 15:35:26 -05001834bool Compiler::toHLSL(Program& program, String* out) {
1835 String spirv;
1836 if (!this->toSPIRV(program, &spirv)) {
1837 return false;
1838 }
1839
1840 return SPIRVtoHLSL(spirv, out);
1841}
1842
Ethan Nicholas00543112018-07-31 09:44:36 -04001843bool Compiler::toMetal(Program& program, OutputStream& out) {
Ethan Nicholas26a9aad2018-03-27 14:10:52 -04001844 MetalCodeGenerator cg(fContext.get(), &program, this, &out);
Ethan Nicholascc305772017-10-13 16:17:45 -04001845 bool result = cg.generateCode();
Ethan Nicholascc305772017-10-13 16:17:45 -04001846 return result;
1847}
1848
Ethan Nicholas00543112018-07-31 09:44:36 -04001849bool Compiler::toMetal(Program& program, String* out) {
Timothy Liangb8eeb802018-07-23 16:46:16 -04001850 StringStream buffer;
1851 bool result = this->toMetal(program, buffer);
1852 if (result) {
1853 *out = buffer.str();
1854 }
1855 return result;
1856}
1857
Greg Daniela28ea672020-09-25 11:12:56 -04001858#if defined(SKSL_STANDALONE) || GR_TEST_UTILS
Ethan Nicholas00543112018-07-31 09:44:36 -04001859bool Compiler::toCPP(Program& program, String name, OutputStream& out) {
Brian Osman88cda172020-10-09 12:05:16 -04001860 AutoSource as(this, program.fSource.get());
Ethan Nicholas26a9aad2018-03-27 14:10:52 -04001861 CPPCodeGenerator cg(fContext.get(), &program, this, name, &out);
Ethan Nicholas762466e2017-06-29 10:03:38 -04001862 bool result = cg.generateCode();
Ethan Nicholas762466e2017-06-29 10:03:38 -04001863 return result;
1864}
1865
Ethan Nicholas00543112018-07-31 09:44:36 -04001866bool Compiler::toH(Program& program, String name, OutputStream& out) {
Brian Osman88cda172020-10-09 12:05:16 -04001867 AutoSource as(this, program.fSource.get());
Ethan Nicholas26a9aad2018-03-27 14:10:52 -04001868 HCodeGenerator cg(fContext.get(), &program, this, name, &out);
Ethan Nicholas762466e2017-06-29 10:03:38 -04001869 bool result = cg.generateCode();
Ethan Nicholas00543112018-07-31 09:44:36 -04001870 return result;
1871}
Greg Daniela28ea672020-09-25 11:12:56 -04001872#endif // defined(SKSL_STANDALONE) || GR_TEST_UTILS
Ethan Nicholas00543112018-07-31 09:44:36 -04001873
Ethan Nicholas2a479a52020-08-18 16:29:45 -04001874#endif // defined(SKSL_STANDALONE) || SK_SUPPORT_GPU
Brian Osman2e29ab52019-09-20 12:19:11 -04001875
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001876Position Compiler::position(int offset) {
Ethan Nicholas3c729892020-12-07 12:47:17 -05001877 if (fSource && offset >= 0) {
1878 int line = 1;
1879 int column = 1;
1880 for (int i = 0; i < offset; i++) {
1881 if ((*fSource)[i] == '\n') {
1882 ++line;
1883 column = 1;
1884 }
1885 else {
1886 ++column;
1887 }
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001888 }
Ethan Nicholas3c729892020-12-07 12:47:17 -05001889 return Position(line, column);
1890 } else {
1891 return Position(-1, -1);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001892 }
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001893}
1894
1895void Compiler::error(int offset, String msg) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001896 fErrorCount++;
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001897 Position pos = this->position(offset);
John Stiles8d3642e2021-01-22 09:50:04 -05001898 fErrorTextLength.push_back(fErrorText.length());
Ethan Nicholas3c729892020-12-07 12:47:17 -05001899 fErrorText += "error: " + (pos.fLine >= 1 ? to_string(pos.fLine) + ": " : "") + msg + "\n";
ethannicholasb3058bd2016-07-01 08:22:01 -07001900}
1901
John Stiles8d3642e2021-01-22 09:50:04 -05001902void Compiler::setErrorCount(int c) {
1903 if (c < fErrorCount) {
1904 fErrorText.resize(fErrorTextLength[c]);
1905 fErrorTextLength.resize(c);
1906 fErrorCount = c;
1907 }
1908}
1909
Ethan Nicholas95046142021-01-07 10:57:27 -05001910String Compiler::errorText(bool showCount) {
1911 if (showCount) {
1912 this->writeErrorCount();
1913 }
Ethan Nicholas00543112018-07-31 09:44:36 -04001914 fErrorCount = 0;
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001915 String result = fErrorText;
Ethan Nicholas95046142021-01-07 10:57:27 -05001916 fErrorText = "";
ethannicholasb3058bd2016-07-01 08:22:01 -07001917 return result;
1918}
1919
1920void Compiler::writeErrorCount() {
1921 if (fErrorCount) {
1922 fErrorText += to_string(fErrorCount) + " error";
1923 if (fErrorCount > 1) {
1924 fErrorText += "s";
1925 }
1926 fErrorText += "\n";
1927 }
1928}
1929
John Stilesa6841be2020-08-06 14:11:56 -04001930} // namespace SkSL