blob: e331470a542ad307d3a36e150eef40728b649d05 [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) {
John Stilesdbd4e6f2021-02-16 13:29:15 -0500177 fGPUModule = this->parseModule(ProgramKind::kFragment, MODULE_DATA(gpu), fPrivateModule);
Brian Osman56269982020-11-20 12:38:07 -0500178 }
179 return fGPUModule;
180}
181
182const ParsedModule& Compiler::loadFragmentModule() {
183 if (!fFragmentModule.fSymbols) {
John Stilesdbd4e6f2021-02-16 13:29:15 -0500184 fFragmentModule = this->parseModule(ProgramKind::kFragment, MODULE_DATA(frag),
Brian Osman56269982020-11-20 12:38:07 -0500185 this->loadGPUModule());
186 }
187 return fFragmentModule;
188}
189
190const ParsedModule& Compiler::loadVertexModule() {
191 if (!fVertexModule.fSymbols) {
John Stilesdbd4e6f2021-02-16 13:29:15 -0500192 fVertexModule = this->parseModule(ProgramKind::kVertex, MODULE_DATA(vert),
Brian Osman56269982020-11-20 12:38:07 -0500193 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) {
John Stilesdbd4e6f2021-02-16 13:29:15 -0500200 fGeometryModule = this->parseModule(ProgramKind::kGeometry, MODULE_DATA(geom),
Brian Osman56269982020-11-20 12:38:07 -0500201 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) {
John Stilesdbd4e6f2021-02-16 13:29:15 -0500208 fFPModule = this->parseModule(ProgramKind::kFragmentProcessor, MODULE_DATA(fp),
Brian Osman56269982020-11-20 12:38:07 -0500209 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) {
John Stilesdbd4e6f2021-02-16 13:29:15 -0500216 fPublicModule = this->parseModule(ProgramKind::kGeneric, MODULE_DATA(public), fRootModule);
Brian Osmanb06301e2020-11-06 11:45:36 -0500217 }
218 return fPublicModule;
219}
220
Brian Osman91946752020-12-21 13:20:40 -0500221const ParsedModule& Compiler::loadRuntimeEffectModule() {
222 if (!fRuntimeEffectModule.fSymbols) {
John Stilesdbd4e6f2021-02-16 13:29:15 -0500223 fRuntimeEffectModule = this->parseModule(ProgramKind::kRuntimeEffect, MODULE_DATA(runtime),
Brian Osman91946752020-12-21 13:20:40 -0500224 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
John Stilesdbd4e6f2021-02-16 13:29:15 -0500244const ParsedModule& Compiler::moduleForProgramKind(ProgramKind kind) {
Brian Osman88cda172020-10-09 12:05:16 -0400245 switch (kind) {
John Stilesdbd4e6f2021-02-16 13:29:15 -0500246 case ProgramKind::kVertex: return this->loadVertexModule(); break;
247 case ProgramKind::kFragment: return this->loadFragmentModule(); break;
248 case ProgramKind::kGeometry: return this->loadGeometryModule(); break;
249 case ProgramKind::kFragmentProcessor: return this->loadFPModule(); break;
250 case ProgramKind::kRuntimeEffect: return this->loadRuntimeEffectModule(); break;
251 case ProgramKind::kGeneric: return this->loadPublicModule(); break;
Brian Osman88cda172020-10-09 12:05:16 -0400252 }
253 SkUNREACHABLE;
Ethan Nicholasc18bb512020-07-28 14:46:53 -0400254}
255
John Stilesdbd4e6f2021-02-16 13:29:15 -0500256LoadedModule Compiler::loadModule(ProgramKind kind,
Brian Osman3d87e9f2020-10-08 11:50:22 -0400257 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;
John Stilesdbd4e6f2021-02-16 13:29:15 -0500284
Brian Osman88cda172020-10-09 12:05:16 -0400285 ParsedModule baseModule = {base, /*fIntrinsics=*/nullptr};
Brian Osmand7e76592020-11-02 12:26:22 -0500286 IRGenerator::IRBundle ir =
Brian Osman0006ad02020-11-18 15:38:39 -0500287 fIRGenerator->convertProgram(kind, &settings, baseModule,
Brian Osmand7e76592020-11-02 12:26:22 -0500288 /*isBuiltinCode=*/true, source->c_str(), source->length(),
Brian Osmanbe0b3b72021-01-06 14:27:35 -0500289 /*externalFunctions=*/nullptr);
Brian Osman133724c2020-10-28 14:14:39 -0400290 SkASSERT(ir.fSharedElements.empty());
Brian Osman0006ad02020-11-18 15:38:39 -0500291 LoadedModule module = { kind, std::move(ir.fSymbolTable), std::move(ir.fElements) };
John Stiles881a10c2020-09-19 10:13:24 -0400292 fIRGenerator->fCanInline = true;
Ethan Nicholas8da1e652019-05-24 11:01:59 -0400293 if (this->fErrorCount) {
294 printf("Unexpected errors: %s\n", this->fErrorText.c_str());
Brian Osman3d87e9f2020-10-08 11:50:22 -0400295 SkDEBUGFAILF("%s %s\n", data.fPath, this->fErrorText.c_str());
Ethan Nicholas8da1e652019-05-24 11:01:59 -0400296 }
Brian Osman88cda172020-10-09 12:05:16 -0400297 fModifiers.push_back(std::move(ir.fModifiers));
Brian Osman3d87e9f2020-10-08 11:50:22 -0400298#else
299 SkASSERT(data.fData && (data.fSize != 0));
300 Rehydrator rehydrator(fContext.get(), fIRGenerator->fModifiers.get(), base, this,
301 data.fData, data.fSize);
Brian Osman0006ad02020-11-18 15:38:39 -0500302 LoadedModule module = { kind, rehydrator.symbolTable(), rehydrator.elements() };
Brian Osman3d87e9f2020-10-08 11:50:22 -0400303 fModifiers.push_back(fIRGenerator->releaseModifiers());
304#endif
305
306 return module;
307}
308
John Stilesdbd4e6f2021-02-16 13:29:15 -0500309ParsedModule Compiler::parseModule(ProgramKind kind, ModuleData data, const ParsedModule& base) {
Brian Osman0006ad02020-11-18 15:38:39 -0500310 LoadedModule module = this->loadModule(kind, data, base.fSymbols);
311 this->optimize(module);
Brian Osman3d87e9f2020-10-08 11:50:22 -0400312
313 // For modules that just declare (but don't define) intrinsic functions, there will be no new
314 // program elements. In that case, we can share our parent's intrinsic map:
Brian Osman0006ad02020-11-18 15:38:39 -0500315 if (module.fElements.empty()) {
316 return {module.fSymbols, base.fIntrinsics};
Brian Osman3d87e9f2020-10-08 11:50:22 -0400317 }
318
319 auto intrinsics = std::make_shared<IRIntrinsicMap>(base.fIntrinsics.get());
320
321 // Now, transfer all of the program elements to an intrinsic map. This maps certain types of
322 // global objects to the declaring ProgramElement.
Brian Osman0006ad02020-11-18 15:38:39 -0500323 for (std::unique_ptr<ProgramElement>& element : module.fElements) {
Brian Osman3d87e9f2020-10-08 11:50:22 -0400324 switch (element->kind()) {
325 case ProgramElement::Kind::kFunction: {
326 const FunctionDefinition& f = element->as<FunctionDefinition>();
Ethan Nicholas0a5d0962020-10-14 13:33:18 -0400327 SkASSERT(f.declaration().isBuiltin());
328 intrinsics->insertOrDie(f.declaration().description(), std::move(element));
Brian Osman3d87e9f2020-10-08 11:50:22 -0400329 break;
330 }
John Stiles569249b2020-11-03 12:18:22 -0500331 case ProgramElement::Kind::kFunctionPrototype: {
332 // These are already in the symbol table.
333 break;
334 }
Brian Osman3d87e9f2020-10-08 11:50:22 -0400335 case ProgramElement::Kind::kEnum: {
336 const Enum& e = element->as<Enum>();
337 SkASSERT(e.isBuiltin());
338 intrinsics->insertOrDie(e.typeName(), std::move(element));
339 break;
340 }
341 case ProgramElement::Kind::kGlobalVar: {
Ethan Nicholasc51f33e2020-10-13 13:49:44 -0400342 const GlobalVarDeclaration& global = element->as<GlobalVarDeclaration>();
343 const Variable& var = global.declaration()->as<VarDeclaration>().var();
344 SkASSERT(var.isBuiltin());
345 intrinsics->insertOrDie(var.name(), std::move(element));
Brian Osman3d87e9f2020-10-08 11:50:22 -0400346 break;
347 }
348 case ProgramElement::Kind::kInterfaceBlock: {
Ethan Nicholaseaf47882020-10-15 10:10:08 -0400349 const Variable& var = element->as<InterfaceBlock>().variable();
350 SkASSERT(var.isBuiltin());
351 intrinsics->insertOrDie(var.name(), std::move(element));
Brian Osman3d87e9f2020-10-08 11:50:22 -0400352 break;
353 }
354 default:
355 printf("Unsupported element: %s\n", element->description().c_str());
356 SkASSERT(false);
357 break;
358 }
359 }
360
Brian Osman0006ad02020-11-18 15:38:39 -0500361 return {module.fSymbols, std::move(intrinsics)};
Ethan Nicholas8da1e652019-05-24 11:01:59 -0400362}
363
John Stilese6150002020-10-05 12:03:53 -0400364void Compiler::scanCFG(CFG* cfg, BlockId blockId, SkBitSet* processedSet) {
ethannicholas22f939e2016-10-13 13:25:34 -0700365 BasicBlock& block = cfg->fBlocks[blockId];
366
367 // compute definitions after this block
Ethan Nicholas86a43402017-01-19 13:32:00 -0500368 DefinitionMap after = block.fBefore;
ethannicholas22f939e2016-10-13 13:25:34 -0700369 for (const BasicBlock::Node& n : block.fNodes) {
John Stilese8a24922021-02-08 17:54:08 -0500370 after.addDefinitions(*fContext, n);
ethannicholas22f939e2016-10-13 13:25:34 -0700371 }
372
373 // propagate definitions to exits
374 for (BlockId exitId : block.fExits) {
Ethan Nicholas26a9aad2018-03-27 14:10:52 -0400375 if (exitId == blockId) {
376 continue;
377 }
ethannicholas22f939e2016-10-13 13:25:34 -0700378 BasicBlock& exit = cfg->fBlocks[exitId];
John Stiles65b48272020-12-22 17:18:34 -0500379 for (const auto& [var, e1] : after) {
John Stiles796cdb72020-10-08 12:06:53 -0400380 std::unique_ptr<Expression>** exitDef = exit.fBefore.find(var);
381 if (!exitDef) {
John Stilese6150002020-10-05 12:03:53 -0400382 // exit has no definition for it, just copy it and reprocess exit block
383 processedSet->reset(exitId);
John Stilese8a24922021-02-08 17:54:08 -0500384 exit.fBefore.set(var, e1);
ethannicholas22f939e2016-10-13 13:25:34 -0700385 } else {
Ethan Nicholas86a43402017-01-19 13:32:00 -0500386 // exit has a (possibly different) value already defined
John Stiles796cdb72020-10-08 12:06:53 -0400387 std::unique_ptr<Expression>* e2 = *exitDef;
ethannicholas22f939e2016-10-13 13:25:34 -0700388 if (e1 != e2) {
John Stilese6150002020-10-05 12:03:53 -0400389 // definition has changed, merge and reprocess the exit block
390 processedSet->reset(exitId);
Ethan Nicholasaf197692017-02-27 13:26:45 -0500391 if (e1 && e2) {
John Stiles796cdb72020-10-08 12:06:53 -0400392 *exitDef = (std::unique_ptr<Expression>*)&fContext->fDefined_Expression;
Ethan Nicholasaf197692017-02-27 13:26:45 -0500393 } else {
John Stiles796cdb72020-10-08 12:06:53 -0400394 *exitDef = nullptr;
Ethan Nicholasaf197692017-02-27 13:26:45 -0500395 }
ethannicholas22f939e2016-10-13 13:25:34 -0700396 }
397 }
John Stiles65b48272020-12-22 17:18:34 -0500398 }
ethannicholas22f939e2016-10-13 13:25:34 -0700399 }
400}
401
Ethan Nicholascb670962017-04-20 19:31:52 -0400402/**
403 * Returns true if assigning to this lvalue has no effect.
404 */
Brian Osman010ce6a2020-10-19 16:34:10 -0400405static bool is_dead(const Expression& lvalue, ProgramUsage* usage) {
Ethan Nicholase6592142020-09-08 10:22:09 -0400406 switch (lvalue.kind()) {
407 case Expression::Kind::kVariableReference:
Brian Osman010ce6a2020-10-19 16:34:10 -0400408 return usage->isDead(*lvalue.as<VariableReference>().variable());
Ethan Nicholase6592142020-09-08 10:22:09 -0400409 case Expression::Kind::kSwizzle:
Brian Osman010ce6a2020-10-19 16:34:10 -0400410 return is_dead(*lvalue.as<Swizzle>().base(), usage);
Ethan Nicholase6592142020-09-08 10:22:09 -0400411 case Expression::Kind::kFieldAccess:
Brian Osman010ce6a2020-10-19 16:34:10 -0400412 return is_dead(*lvalue.as<FieldAccess>().base(), usage);
Ethan Nicholase6592142020-09-08 10:22:09 -0400413 case Expression::Kind::kIndex: {
John Stilesa5a97b42020-08-18 11:19:07 -0400414 const IndexExpression& idx = lvalue.as<IndexExpression>();
Brian Osman010ce6a2020-10-19 16:34:10 -0400415 return is_dead(*idx.base(), usage) &&
Ethan Nicholas2a4952d2020-10-08 15:35:56 -0400416 !idx.index()->hasProperty(Expression::Property::kSideEffects);
Ethan Nicholascb670962017-04-20 19:31:52 -0400417 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400418 case Expression::Kind::kTernary: {
John Stilesa5a97b42020-08-18 11:19:07 -0400419 const TernaryExpression& t = lvalue.as<TernaryExpression>();
Brian Osman010ce6a2020-10-19 16:34:10 -0400420 return !t.test()->hasSideEffects() &&
421 is_dead(*t.ifTrue(), usage) &&
422 is_dead(*t.ifFalse(), usage);
Ethan Nicholasa583b812018-01-18 13:32:11 -0500423 }
Ethan Nicholascb670962017-04-20 19:31:52 -0400424 default:
John Stileseada7bc2021-02-02 16:29:32 -0500425 SkDEBUGFAILF("invalid lvalue: %s\n", lvalue.description().c_str());
Ethan Nicholas2a099da2020-01-02 14:40:54 -0500426 return false;
Ethan Nicholascb670962017-04-20 19:31:52 -0400427 }
428}
ethannicholas22f939e2016-10-13 13:25:34 -0700429
Ethan Nicholascb670962017-04-20 19:31:52 -0400430/**
431 * Returns true if this is an assignment which can be collapsed down to just the right hand side due
432 * to a dead target and lack of side effects on the left hand side.
433 */
Brian Osman010ce6a2020-10-19 16:34:10 -0400434static bool dead_assignment(const BinaryExpression& b, ProgramUsage* usage) {
John Stiles45990502021-02-16 10:55:27 -0500435 if (!b.getOperator().isAssignment()) {
Ethan Nicholascb670962017-04-20 19:31:52 -0400436 return false;
437 }
John Stiles2d4f9592020-10-30 10:29:12 -0400438 return is_dead(*b.left(), usage);
Ethan Nicholascb670962017-04-20 19:31:52 -0400439}
440
John Stiles0ac6c152021-02-10 14:04:24 -0500441/**
442 * Returns true if both expression trees are the same. The left side is expected to be an lvalue.
443 * This only needs to check for trees that can plausibly terminate in a variable, so some basic
444 * candidates like `FloatLiteral` are missing.
445 */
446static bool is_matching_expression_tree(const Expression& left, const Expression& right) {
447 if (left.kind() != right.kind() || left.type() != right.type()) {
448 return false;
449 }
450
451 switch (left.kind()) {
452 case Expression::Kind::kIntLiteral:
453 return left.as<IntLiteral>().value() == right.as<IntLiteral>().value();
454
455 case Expression::Kind::kFieldAccess:
456 return left.as<FieldAccess>().fieldIndex() == right.as<FieldAccess>().fieldIndex() &&
457 is_matching_expression_tree(*left.as<FieldAccess>().base(),
458 *right.as<FieldAccess>().base());
459
460 case Expression::Kind::kIndex:
461 return is_matching_expression_tree(*left.as<IndexExpression>().index(),
462 *right.as<IndexExpression>().index()) &&
463 is_matching_expression_tree(*left.as<IndexExpression>().base(),
464 *right.as<IndexExpression>().base());
465
466 case Expression::Kind::kSwizzle:
467 return left.as<Swizzle>().components() == right.as<Swizzle>().components() &&
468 is_matching_expression_tree(*left.as<Swizzle>().base(),
469 *right.as<Swizzle>().base());
470
471 case Expression::Kind::kVariableReference:
472 return left.as<VariableReference>().variable() ==
473 right.as<VariableReference>().variable();
474
475 default:
476 return false;
477 }
478}
479
480static bool self_assignment(const BinaryExpression& b) {
John Stiles45990502021-02-16 10:55:27 -0500481 return b.getOperator().kind() == Token::Kind::TK_EQ &&
John Stiles0ac6c152021-02-10 14:04:24 -0500482 is_matching_expression_tree(*b.left(), *b.right());
483}
484
Ethan Nicholascb670962017-04-20 19:31:52 -0400485void Compiler::computeDataFlow(CFG* cfg) {
John Stilese8a24922021-02-08 17:54:08 -0500486 cfg->fBlocks[cfg->fStart].fBefore.computeStartState(*cfg);
John Stilese6150002020-10-05 12:03:53 -0400487
488 // We set bits in the "processed" set after a block has been scanned.
489 SkBitSet processedSet(cfg->fBlocks.size());
490 while (SkBitSet::OptionalIndex blockId = processedSet.findFirstUnset()) {
491 processedSet.set(*blockId);
492 this->scanCFG(cfg, *blockId, &processedSet);
ethannicholas22f939e2016-10-13 13:25:34 -0700493 }
Ethan Nicholascb670962017-04-20 19:31:52 -0400494}
495
496/**
497 * Attempts to replace the expression pointed to by iter with a new one (in both the CFG and the
498 * IR). If the expression can be cleanly removed, returns true and updates the iterator to point to
499 * the newly-inserted element. Otherwise updates only the IR and returns false (and the CFG will
500 * need to be regenerated).
501 */
John Stilesafbf8992020-08-18 10:08:21 -0400502static bool try_replace_expression(BasicBlock* b,
503 std::vector<BasicBlock::Node>::iterator* iter,
504 std::unique_ptr<Expression>* newExpression) {
Ethan Nicholascb670962017-04-20 19:31:52 -0400505 std::unique_ptr<Expression>* target = (*iter)->expression();
506 if (!b->tryRemoveExpression(iter)) {
507 *target = std::move(*newExpression);
508 return false;
509 }
510 *target = std::move(*newExpression);
511 return b->tryInsertExpression(iter, target);
512}
513
514/**
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400515 * Returns true if the expression is a constant numeric literal with the specified value, or a
516 * constant vector with all elements equal to the specified value.
Ethan Nicholascb670962017-04-20 19:31:52 -0400517 */
Ethan Nicholasa3f22f12020-10-01 12:13:17 -0400518template <typename T = SKSL_FLOAT>
John Stiles9d944232020-08-19 09:56:49 -0400519static bool is_constant(const Expression& expr, T value) {
Ethan Nicholase6592142020-09-08 10:22:09 -0400520 switch (expr.kind()) {
521 case Expression::Kind::kIntLiteral:
Ethan Nicholase96cdd12020-09-28 16:27:18 -0400522 return expr.as<IntLiteral>().value() == value;
John Stiles9d944232020-08-19 09:56:49 -0400523
Ethan Nicholase6592142020-09-08 10:22:09 -0400524 case Expression::Kind::kFloatLiteral:
Ethan Nicholasa3f22f12020-10-01 12:13:17 -0400525 return expr.as<FloatLiteral>().value() == value;
John Stiles9d944232020-08-19 09:56:49 -0400526
Ethan Nicholase6592142020-09-08 10:22:09 -0400527 case Expression::Kind::kConstructor: {
John Stiles9d944232020-08-19 09:56:49 -0400528 const Constructor& constructor = expr.as<Constructor>();
529 if (constructor.isCompileTimeConstant()) {
Ethan Nicholas30d30222020-09-11 12:27:26 -0400530 const Type& constructorType = constructor.type();
Ethan Nicholas30d30222020-09-11 12:27:26 -0400531 switch (constructorType.typeKind()) {
Ethan Nicholase6592142020-09-08 10:22:09 -0400532 case Type::TypeKind::kVector:
John Stilesbc75ebb2020-11-24 12:04:47 -0500533 if (constructor.componentType().isFloat()) {
534 for (int i = 0; i < constructorType.columns(); ++i) {
John Stiles9d944232020-08-19 09:56:49 -0400535 if (constructor.getFVecComponent(i) != value) {
536 return false;
537 }
John Stilesbc75ebb2020-11-24 12:04:47 -0500538 }
539 return true;
540 } else if (constructor.componentType().isInteger()) {
541 for (int i = 0; i < constructorType.columns(); ++i) {
John Stiles9d944232020-08-19 09:56:49 -0400542 if (constructor.getIVecComponent(i) != value) {
543 return false;
544 }
545 }
John Stilesbc75ebb2020-11-24 12:04:47 -0500546 return true;
Ethan Nicholasd188c182019-06-10 15:55:38 -0400547 }
John Stilesbc75ebb2020-11-24 12:04:47 -0500548 // Other types (e.g. boolean) might occur, but aren't supported here.
549 return false;
John Stiles9d944232020-08-19 09:56:49 -0400550
Ethan Nicholase6592142020-09-08 10:22:09 -0400551 case Type::TypeKind::kScalar:
Ethan Nicholasf70f0442020-09-29 12:41:35 -0400552 SkASSERT(constructor.arguments().size() == 1);
553 return is_constant<T>(*constructor.arguments()[0], value);
John Stiles9d944232020-08-19 09:56:49 -0400554
555 default:
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400556 return false;
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400557 }
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400558 }
559 return false;
560 }
Ethan Nicholascb670962017-04-20 19:31:52 -0400561 default:
562 return false;
563 }
564}
565
566/**
567 * Collapses the binary expression pointed to by iter down to just the right side (in both the IR
568 * and CFG structures).
569 */
John Stilesafbf8992020-08-18 10:08:21 -0400570static void delete_left(BasicBlock* b,
571 std::vector<BasicBlock::Node>::iterator* iter,
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400572 Compiler::OptimizationContext* optimizationContext) {
573 optimizationContext->fUpdated = true;
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400574 std::unique_ptr<Expression>* target = (*iter)->expression();
John Stilesa5a97b42020-08-18 11:19:07 -0400575 BinaryExpression& bin = (*target)->as<BinaryExpression>();
John Stiles2d4f9592020-10-30 10:29:12 -0400576 Expression& left = *bin.left();
577 std::unique_ptr<Expression>& rightPointer = bin.right();
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400578 SkASSERT(!left.hasSideEffects());
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400579 bool result;
John Stiles45990502021-02-16 10:55:27 -0500580 if (bin.getOperator().kind() == Token::Kind::TK_EQ) {
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400581 result = b->tryRemoveLValueBefore(iter, &left);
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400582 } else {
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400583 result = b->tryRemoveExpressionBefore(iter, &left);
Ethan Nicholascb670962017-04-20 19:31:52 -0400584 }
Brian Osman010ce6a2020-10-19 16:34:10 -0400585 // Remove references within LHS.
586 optimizationContext->fUsage->remove(&left);
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400587 *target = std::move(rightPointer);
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400588 if (!result) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400589 optimizationContext->fNeedsRescan = true;
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400590 return;
591 }
592 if (*iter == b->fNodes.begin()) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400593 optimizationContext->fNeedsRescan = true;
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400594 return;
595 }
596 --(*iter);
John Stiles70025e52020-09-28 16:08:58 -0400597 if (!(*iter)->isExpression() || (*iter)->expression() != &rightPointer) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400598 optimizationContext->fNeedsRescan = true;
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400599 return;
600 }
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400601 *iter = b->fNodes.erase(*iter);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400602 SkASSERT((*iter)->expression() == target);
Ethan Nicholascb670962017-04-20 19:31:52 -0400603}
604
605/**
606 * Collapses the binary expression pointed to by iter down to just the left side (in both the IR and
607 * CFG structures).
608 */
John Stilesafbf8992020-08-18 10:08:21 -0400609static void delete_right(BasicBlock* b,
610 std::vector<BasicBlock::Node>::iterator* iter,
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400611 Compiler::OptimizationContext* optimizationContext) {
612 optimizationContext->fUpdated = true;
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400613 std::unique_ptr<Expression>* target = (*iter)->expression();
John Stilesa5a97b42020-08-18 11:19:07 -0400614 BinaryExpression& bin = (*target)->as<BinaryExpression>();
John Stiles2d4f9592020-10-30 10:29:12 -0400615 std::unique_ptr<Expression>& leftPointer = bin.left();
616 Expression& right = *bin.right();
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400617 SkASSERT(!right.hasSideEffects());
Brian Osman010ce6a2020-10-19 16:34:10 -0400618 // Remove references within RHS.
619 optimizationContext->fUsage->remove(&right);
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400620 if (!b->tryRemoveExpressionBefore(iter, &right)) {
621 *target = std::move(leftPointer);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400622 optimizationContext->fNeedsRescan = true;
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400623 return;
Ethan Nicholascb670962017-04-20 19:31:52 -0400624 }
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400625 *target = std::move(leftPointer);
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400626 if (*iter == b->fNodes.begin()) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400627 optimizationContext->fNeedsRescan = true;
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400628 return;
629 }
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400630 --(*iter);
John Stiles70025e52020-09-28 16:08:58 -0400631 if ((!(*iter)->isExpression() || (*iter)->expression() != &leftPointer)) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400632 optimizationContext->fNeedsRescan = true;
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400633 return;
634 }
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400635 *iter = b->fNodes.erase(*iter);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400636 SkASSERT((*iter)->expression() == target);
Ethan Nicholascb670962017-04-20 19:31:52 -0400637}
638
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400639/**
640 * Constructs the specified type using a single argument.
641 */
Ethan Nicholas30d30222020-09-11 12:27:26 -0400642static std::unique_ptr<Expression> construct(const Type* type, std::unique_ptr<Expression> v) {
John Stiles8e3b6be2020-10-13 11:14:08 -0400643 ExpressionArray args;
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400644 args.push_back(std::move(v));
Ethan Nicholase6592142020-09-08 10:22:09 -0400645 std::unique_ptr<Expression> result = std::make_unique<Constructor>(-1, type, std::move(args));
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400646 return result;
647}
648
649/**
650 * Used in the implementations of vectorize_left and vectorize_right. Given a vector type and an
651 * expression x, deletes the expression pointed to by iter and replaces it with <type>(x).
652 */
653static void vectorize(BasicBlock* b,
654 std::vector<BasicBlock::Node>::iterator* iter,
655 const Type& type,
656 std::unique_ptr<Expression>* otherExpression,
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400657 Compiler::OptimizationContext* optimizationContext) {
Ethan Nicholase6592142020-09-08 10:22:09 -0400658 SkASSERT((*(*iter)->expression())->kind() == Expression::Kind::kBinary);
John Stiles9aeed132020-11-24 17:36:06 -0500659 SkASSERT(type.isVector());
660 SkASSERT((*otherExpression)->type().isScalar());
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400661 optimizationContext->fUpdated = true;
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400662 std::unique_ptr<Expression>* target = (*iter)->expression();
663 if (!b->tryRemoveExpression(iter)) {
Ethan Nicholas30d30222020-09-11 12:27:26 -0400664 *target = construct(&type, std::move(*otherExpression));
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400665 optimizationContext->fNeedsRescan = true;
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400666 } else {
Ethan Nicholas30d30222020-09-11 12:27:26 -0400667 *target = construct(&type, std::move(*otherExpression));
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400668 if (!b->tryInsertExpression(iter, target)) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400669 optimizationContext->fNeedsRescan = true;
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400670 }
671 }
672}
673
674/**
675 * Given a binary expression of the form x <op> vec<n>(y), deletes the right side and vectorizes the
676 * left to yield vec<n>(x).
677 */
678static void vectorize_left(BasicBlock* b,
679 std::vector<BasicBlock::Node>::iterator* iter,
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400680 Compiler::OptimizationContext* optimizationContext) {
John Stilesa5a97b42020-08-18 11:19:07 -0400681 BinaryExpression& bin = (*(*iter)->expression())->as<BinaryExpression>();
Brian Osman010ce6a2020-10-19 16:34:10 -0400682 // Remove references within RHS. Vectorization of LHS doesn't change reference counts.
John Stiles2d4f9592020-10-30 10:29:12 -0400683 optimizationContext->fUsage->remove(bin.right().get());
684 vectorize(b, iter, bin.right()->type(), &bin.left(), optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400685}
686
687/**
688 * Given a binary expression of the form vec<n>(x) <op> y, deletes the left side and vectorizes the
689 * right to yield vec<n>(y).
690 */
691static void vectorize_right(BasicBlock* b,
692 std::vector<BasicBlock::Node>::iterator* iter,
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400693 Compiler::OptimizationContext* optimizationContext) {
John Stilesa5a97b42020-08-18 11:19:07 -0400694 BinaryExpression& bin = (*(*iter)->expression())->as<BinaryExpression>();
Brian Osman010ce6a2020-10-19 16:34:10 -0400695 // Remove references within LHS. Vectorization of RHS doesn't change reference counts.
John Stiles2d4f9592020-10-30 10:29:12 -0400696 optimizationContext->fUsage->remove(bin.left().get());
697 vectorize(b, iter, bin.left()->type(), &bin.right(), optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400698}
699
Ethan Nicholascb670962017-04-20 19:31:52 -0400700void Compiler::simplifyExpression(DefinitionMap& definitions,
701 BasicBlock& b,
702 std::vector<BasicBlock::Node>::iterator* iter,
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400703 OptimizationContext* optimizationContext) {
Ethan Nicholascb670962017-04-20 19:31:52 -0400704 Expression* expr = (*iter)->expression()->get();
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400705 SkASSERT(expr);
John Stiles108bbe22020-11-18 11:10:38 -0500706
Ethan Nicholascb670962017-04-20 19:31:52 -0400707 if ((*iter)->fConstantPropagation) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400708 std::unique_ptr<Expression> optimized = expr->constantPropagate(*fIRGenerator,
709 definitions);
Ethan Nicholascb670962017-04-20 19:31:52 -0400710 if (optimized) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400711 optimizationContext->fUpdated = true;
Ethan Nicholas30d30222020-09-11 12:27:26 -0400712 optimized = fIRGenerator->coerce(std::move(optimized), expr->type());
Ethan Nicholas1d881522020-09-11 09:32:54 -0400713 SkASSERT(optimized);
Brian Osman010ce6a2020-10-19 16:34:10 -0400714 // Remove references within 'expr', add references within 'optimized'
715 optimizationContext->fUsage->replace(expr, optimized.get());
Ethan Nicholascb670962017-04-20 19:31:52 -0400716 if (!try_replace_expression(&b, iter, &optimized)) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400717 optimizationContext->fNeedsRescan = true;
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400718 return;
Ethan Nicholascb670962017-04-20 19:31:52 -0400719 }
John Stiles70025e52020-09-28 16:08:58 -0400720 SkASSERT((*iter)->isExpression());
Ethan Nicholascb670962017-04-20 19:31:52 -0400721 expr = (*iter)->expression()->get();
Ethan Nicholascb670962017-04-20 19:31:52 -0400722 }
723 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400724 switch (expr->kind()) {
725 case Expression::Kind::kVariableReference: {
John Stilesa5a97b42020-08-18 11:19:07 -0400726 const VariableReference& ref = expr->as<VariableReference>();
Ethan Nicholas78686922020-10-08 06:46:27 -0400727 const Variable* var = ref.variable();
Ethan Nicholas453f67f2020-10-09 10:43:45 -0400728 if (ref.refKind() != VariableReference::RefKind::kWrite &&
729 ref.refKind() != VariableReference::RefKind::kPointer &&
John Stilese8a24922021-02-08 17:54:08 -0500730 var->storage() == Variable::Storage::kLocal && !definitions.get(var) &&
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400731 optimizationContext->fSilences.find(var) == optimizationContext->fSilences.end()) {
732 optimizationContext->fSilences.insert(var);
Ethan Nicholas82a62d22017-11-07 14:42:10 +0000733 this->error(expr->fOffset,
Ethan Nicholase2c49992020-10-05 11:49:11 -0400734 "'" + var->name() + "' has not been assigned");
Ethan Nicholascb670962017-04-20 19:31:52 -0400735 }
736 break;
737 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400738 case Expression::Kind::kTernary: {
John Stiles403a3632020-08-20 12:11:48 -0400739 TernaryExpression* t = &expr->as<TernaryExpression>();
Ethan Nicholasdd218162020-10-08 05:48:01 -0400740 if (t->test()->is<BoolLiteral>()) {
Ethan Nicholascb670962017-04-20 19:31:52 -0400741 // ternary has a constant test, replace it with either the true or
742 // false branch
Ethan Nicholasdd218162020-10-08 05:48:01 -0400743 if (t->test()->as<BoolLiteral>().value()) {
Brian Osman010ce6a2020-10-19 16:34:10 -0400744 (*iter)->setExpression(std::move(t->ifTrue()), optimizationContext->fUsage);
Ethan Nicholascb670962017-04-20 19:31:52 -0400745 } else {
Brian Osman010ce6a2020-10-19 16:34:10 -0400746 (*iter)->setExpression(std::move(t->ifFalse()), optimizationContext->fUsage);
Ethan Nicholascb670962017-04-20 19:31:52 -0400747 }
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400748 optimizationContext->fUpdated = true;
749 optimizationContext->fNeedsRescan = true;
Ethan Nicholascb670962017-04-20 19:31:52 -0400750 }
751 break;
752 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400753 case Expression::Kind::kBinary: {
John Stiles403a3632020-08-20 12:11:48 -0400754 BinaryExpression* bin = &expr->as<BinaryExpression>();
John Stiles0ac6c152021-02-10 14:04:24 -0500755 if (dead_assignment(*bin, optimizationContext->fUsage) || self_assignment(*bin)) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400756 delete_left(&b, iter, optimizationContext);
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400757 break;
758 }
John Stiles2d4f9592020-10-30 10:29:12 -0400759 Expression& left = *bin->left();
760 Expression& right = *bin->right();
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400761 const Type& leftType = left.type();
762 const Type& rightType = right.type();
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400763 // collapse useless expressions like x * 1 or x + 0
John Stiles9aeed132020-11-24 17:36:06 -0500764 if ((!leftType.isScalar() && !leftType.isVector()) ||
765 (!rightType.isScalar() && !rightType.isVector())) {
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400766 break;
767 }
John Stiles45990502021-02-16 10:55:27 -0500768 switch (bin->getOperator().kind()) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400769 case Token::Kind::TK_STAR:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400770 if (is_constant(left, 1)) {
John Stiles9aeed132020-11-24 17:36:06 -0500771 if (leftType.isVector() && rightType.isScalar()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400772 // float4(1) * x -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400773 vectorize_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400774 } else {
775 // 1 * x -> x
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400776 // 1 * float4(x) -> float4(x)
777 // float4(1) * float4(x) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400778 delete_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400779 }
780 }
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400781 else if (is_constant(left, 0)) {
John Stiles9aeed132020-11-24 17:36:06 -0500782 if (leftType.isScalar() && rightType.isVector() &&
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400783 !right.hasSideEffects()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400784 // 0 * float4(x) -> float4(0)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400785 vectorize_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400786 } else {
787 // 0 * x -> 0
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400788 // float4(0) * x -> float4(0)
789 // float4(0) * float4(x) -> float4(0)
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400790 if (!right.hasSideEffects()) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400791 delete_right(&b, iter, optimizationContext);
Ethan Nicholas51493ee2017-12-11 12:34:33 -0500792 }
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400793 }
Ethan Nicholascb670962017-04-20 19:31:52 -0400794 }
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400795 else if (is_constant(right, 1)) {
John Stiles9aeed132020-11-24 17:36:06 -0500796 if (leftType.isScalar() && rightType.isVector()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400797 // x * float4(1) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400798 vectorize_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400799 } else {
800 // x * 1 -> x
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400801 // float4(x) * 1 -> float4(x)
802 // float4(x) * float4(1) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400803 delete_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400804 }
805 }
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400806 else if (is_constant(right, 0)) {
John Stiles9aeed132020-11-24 17:36:06 -0500807 if (leftType.isVector() && rightType.isScalar() && !left.hasSideEffects()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400808 // float4(x) * 0 -> float4(0)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400809 vectorize_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400810 } else {
811 // x * 0 -> 0
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400812 // x * float4(0) -> float4(0)
813 // float4(x) * float4(0) -> float4(0)
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400814 if (!left.hasSideEffects()) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400815 delete_left(&b, iter, optimizationContext);
Ethan Nicholas51493ee2017-12-11 12:34:33 -0500816 }
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400817 }
Ethan Nicholascb670962017-04-20 19:31:52 -0400818 }
819 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400820 case Token::Kind::TK_PLUS:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400821 if (is_constant(left, 0)) {
John Stiles9aeed132020-11-24 17:36:06 -0500822 if (leftType.isVector() && rightType.isScalar()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400823 // float4(0) + x -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400824 vectorize_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400825 } else {
826 // 0 + x -> x
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400827 // 0 + float4(x) -> float4(x)
828 // float4(0) + float4(x) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400829 delete_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400830 }
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400831 } else if (is_constant(right, 0)) {
John Stiles9aeed132020-11-24 17:36:06 -0500832 if (leftType.isScalar() && rightType.isVector()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400833 // x + float4(0) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400834 vectorize_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400835 } else {
836 // x + 0 -> x
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400837 // float4(x) + 0 -> float4(x)
838 // float4(x) + float4(0) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400839 delete_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400840 }
Ethan Nicholas56e42712017-04-21 10:23:37 -0400841 }
842 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400843 case Token::Kind::TK_MINUS:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400844 if (is_constant(right, 0)) {
John Stiles9aeed132020-11-24 17:36:06 -0500845 if (leftType.isScalar() && rightType.isVector()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400846 // x - float4(0) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400847 vectorize_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400848 } else {
849 // x - 0 -> x
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400850 // float4(x) - 0 -> float4(x)
851 // float4(x) - float4(0) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400852 delete_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400853 }
Ethan Nicholascb670962017-04-20 19:31:52 -0400854 }
855 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400856 case Token::Kind::TK_SLASH:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400857 if (is_constant(right, 1)) {
John Stiles9aeed132020-11-24 17:36:06 -0500858 if (leftType.isScalar() && rightType.isVector()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400859 // x / float4(1) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400860 vectorize_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400861 } else {
862 // x / 1 -> x
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400863 // float4(x) / 1 -> float4(x)
864 // float4(x) / float4(1) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400865 delete_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400866 }
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400867 } else if (is_constant(left, 0)) {
John Stiles9aeed132020-11-24 17:36:06 -0500868 if (leftType.isScalar() && rightType.isVector() &&
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400869 !right.hasSideEffects()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400870 // 0 / float4(x) -> float4(0)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400871 vectorize_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400872 } else {
873 // 0 / x -> 0
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400874 // float4(0) / x -> float4(0)
875 // float4(0) / float4(x) -> float4(0)
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400876 if (!right.hasSideEffects()) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400877 delete_right(&b, iter, optimizationContext);
Ethan Nicholas51493ee2017-12-11 12:34:33 -0500878 }
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400879 }
880 }
881 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400882 case Token::Kind::TK_PLUSEQ:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400883 if (is_constant(right, 0)) {
John Stiles47c0a742021-02-09 09:30:35 -0500884 Analysis::UpdateRefKind(&left, RefKind::kRead);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400885 delete_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400886 }
887 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400888 case Token::Kind::TK_MINUSEQ:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400889 if (is_constant(right, 0)) {
John Stiles47c0a742021-02-09 09:30:35 -0500890 Analysis::UpdateRefKind(&left, RefKind::kRead);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400891 delete_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400892 }
893 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400894 case Token::Kind::TK_STAREQ:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400895 if (is_constant(right, 1)) {
John Stiles47c0a742021-02-09 09:30:35 -0500896 Analysis::UpdateRefKind(&left, RefKind::kRead);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400897 delete_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400898 }
899 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400900 case Token::Kind::TK_SLASHEQ:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400901 if (is_constant(right, 1)) {
John Stiles47c0a742021-02-09 09:30:35 -0500902 Analysis::UpdateRefKind(&left, RefKind::kRead);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400903 delete_right(&b, iter, optimizationContext);
Ethan Nicholascb670962017-04-20 19:31:52 -0400904 }
905 break;
906 default:
907 break;
908 }
Ethan Nicholas409f6f02019-09-17 12:34:39 -0400909 break;
910 }
John Stilesf5c1d042020-11-21 23:26:07 -0500911 case Expression::Kind::kConstructor: {
912 // Find constructors embedded inside constructors and flatten them out where possible.
913 // - float4(float2(1, 2), 3, 4) --> float4(1, 2, 3, 4)
914 // - float4(w, float3(sin(x), cos(y), tan(z))) --> float4(w, sin(x), cos(y), tan(z))
915 // Leave single-argument constructors alone, though. These might be casts or splats.
916 Constructor& c = expr->as<Constructor>();
917 if (c.type().columns() > 1) {
918 // Inspect each constructor argument to see if it's a candidate for flattening.
919 // Remember matched arguments in a bitfield, "argsToOptimize".
920 int argsToOptimize = 0;
921 int currBit = 1;
922 for (const std::unique_ptr<Expression>& arg : c.arguments()) {
923 if (arg->is<Constructor>()) {
924 Constructor& inner = arg->as<Constructor>();
925 if (inner.arguments().size() > 1 &&
926 inner.type().componentType() == c.type().componentType()) {
927 argsToOptimize |= currBit;
928 }
929 }
930 currBit <<= 1;
931 }
932 if (argsToOptimize) {
933 // We found at least one argument that could be flattened out. Re-walk the
934 // constructor args and flatten the candidates we found during our initial pass.
935 ExpressionArray flattened;
936 flattened.reserve_back(c.type().columns());
937 currBit = 1;
938 for (const std::unique_ptr<Expression>& arg : c.arguments()) {
939 if (argsToOptimize & currBit) {
940 Constructor& inner = arg->as<Constructor>();
941 for (const std::unique_ptr<Expression>& innerArg : inner.arguments()) {
942 flattened.push_back(innerArg->clone());
943 }
944 } else {
945 flattened.push_back(arg->clone());
946 }
947 currBit <<= 1;
948 }
John Stiles1b91c0e2021-02-11 11:43:09 -0500949 std::unique_ptr<Expression> replacement(new Constructor(c.fOffset, &c.type(),
950 std::move(flattened)));
951 // We're replacing an expression with a cloned version; we'll need a rescan.
952 // No fUsage change: `float2(float(x), y)` and `float2(x, y)` have equivalent
953 // reference counts.
954 try_replace_expression(&b, iter, &replacement);
John Stilesf5c1d042020-11-21 23:26:07 -0500955 optimizationContext->fUpdated = true;
John Stiles1b91c0e2021-02-11 11:43:09 -0500956 optimizationContext->fNeedsRescan = true;
John Stilesf5c1d042020-11-21 23:26:07 -0500957 break;
958 }
959 }
960 break;
961 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400962 case Expression::Kind::kSwizzle: {
John Stiles403a3632020-08-20 12:11:48 -0400963 Swizzle& s = expr->as<Swizzle>();
John Stiles108bbe22020-11-18 11:10:38 -0500964 // Detect identity swizzles like `foo.rgba`.
Ethan Nicholas6b4d5812020-10-12 16:11:51 -0400965 if ((int) s.components().size() == s.base()->type().columns()) {
Ethan Nicholas409f6f02019-09-17 12:34:39 -0400966 bool identity = true;
Ethan Nicholas6b4d5812020-10-12 16:11:51 -0400967 for (int i = 0; i < (int) s.components().size(); ++i) {
968 if (s.components()[i] != i) {
Ethan Nicholas409f6f02019-09-17 12:34:39 -0400969 identity = false;
970 break;
971 }
972 }
973 if (identity) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400974 optimizationContext->fUpdated = true;
Brian Osman010ce6a2020-10-19 16:34:10 -0400975 // No fUsage change: foo.rgba and foo have equivalent reference counts
Ethan Nicholas6b4d5812020-10-12 16:11:51 -0400976 if (!try_replace_expression(&b, iter, &s.base())) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400977 optimizationContext->fNeedsRescan = true;
Ethan Nicholas409f6f02019-09-17 12:34:39 -0400978 return;
979 }
John Stiles70025e52020-09-28 16:08:58 -0400980 SkASSERT((*iter)->isExpression());
Ethan Nicholas409f6f02019-09-17 12:34:39 -0400981 break;
982 }
983 }
John Stiles108bbe22020-11-18 11:10:38 -0500984 // Detect swizzles of swizzles, e.g. replace `foo.argb.r000` with `foo.a000`.
985 if (s.base()->is<Swizzle>()) {
Ethan Nicholas6b4d5812020-10-12 16:11:51 -0400986 Swizzle& base = s.base()->as<Swizzle>();
John Stiles750109b2020-10-30 13:45:46 -0400987 ComponentArray final;
Ethan Nicholas6b4d5812020-10-12 16:11:51 -0400988 for (int c : s.components()) {
989 final.push_back(base.components()[c]);
Ethan Nicholas409f6f02019-09-17 12:34:39 -0400990 }
Ethan Nicholas6b4d5812020-10-12 16:11:51 -0400991 std::unique_ptr<Expression> replacement(new Swizzle(*fContext, base.base()->clone(),
John Stiles750109b2020-10-30 13:45:46 -0400992 final));
John Stilesd2f51b12021-01-07 18:12:31 -0500993 // We're replacing an expression with a cloned version; we'll need a rescan.
John Stiles108bbe22020-11-18 11:10:38 -0500994 // No fUsage change: `foo.gbr.gbr` and `foo.brg` have equivalent reference counts
John Stilesd2f51b12021-01-07 18:12:31 -0500995 try_replace_expression(&b, iter, &replacement);
996 optimizationContext->fUpdated = true;
997 optimizationContext->fNeedsRescan = true;
John Stiles108bbe22020-11-18 11:10:38 -0500998 break;
999 }
1000 // Optimize swizzles of constructors.
1001 if (s.base()->is<Constructor>()) {
1002 Constructor& base = s.base()->as<Constructor>();
1003 std::unique_ptr<Expression> replacement;
1004 const Type& componentType = base.type().componentType();
1005 int swizzleSize = s.components().size();
1006
1007 // The IR generator has already converted any zero/one swizzle components into
1008 // constructors containing zero/one args. Confirm that this is true by checking that
1009 // our swizzle components are all `xyzw` (values 0 through 3).
1010 SkASSERT(std::all_of(s.components().begin(), s.components().end(),
1011 [](int8_t c) { return c >= 0 && c <= 3; }));
1012
John Stiles9aeed132020-11-24 17:36:06 -05001013 if (base.arguments().size() == 1 && base.arguments().front()->type().isScalar()) {
John Stiles108bbe22020-11-18 11:10:38 -05001014 // `half4(scalar).zyy` can be optimized to `half3(scalar)`. The swizzle
1015 // components don't actually matter since all fields are the same.
John Stilesf0cb7332021-01-08 18:39:00 -05001016 const Expression& argument = *base.arguments().front();
1017 const Type& constructorType = componentType.toCompound(*fContext, swizzleSize,
1018 /*rows=*/1);
1019 replacement = Constructor::SimplifyConversion(constructorType, argument);
1020 if (!replacement) {
1021 ExpressionArray newArgs;
1022 newArgs.push_back(argument.clone());
1023 replacement = std::make_unique<Constructor>(base.fOffset, &constructorType,
1024 std::move(newArgs));
1025 }
John Stiles108bbe22020-11-18 11:10:38 -05001026
John Stilesa60ac0c2020-12-22 08:59:51 -05001027 // We're replacing an expression with a cloned version; we'll need a rescan.
1028 // There's no fUsage change: `half4(foo).xy` and `half2(foo)` have equivalent
1029 // reference counts.
1030 try_replace_expression(&b, iter, &replacement);
John Stiles0777ac42020-11-19 11:06:47 -05001031 optimizationContext->fUpdated = true;
John Stilesa60ac0c2020-12-22 08:59:51 -05001032 optimizationContext->fNeedsRescan = true;
John Stiles108bbe22020-11-18 11:10:38 -05001033 break;
1034 }
1035
John Stiles0777ac42020-11-19 11:06:47 -05001036 // Swizzles can duplicate some elements and discard others, e.g.
1037 // `half4(1, 2, 3, 4).xxz` --> `half3(1, 1, 3)`. However, there are constraints:
1038 // - Expressions with side effects need to occur exactly once, even if they
1039 // would otherwise be swizzle-eliminated
1040 // - Non-trivial expressions should not be repeated, but elimination is OK.
1041 //
1042 // Look up the argument for the constructor at each index. This is typically simple
1043 // but for weird cases like `half4(bar.yz, half2(foo))`, it can be harder than it
1044 // seems. This example would result in:
1045 // argMap[0] = {.fArgIndex = 0, .fComponent = 0} (bar.yz .x)
1046 // argMap[1] = {.fArgIndex = 0, .fComponent = 1} (bar.yz .y)
1047 // argMap[2] = {.fArgIndex = 1, .fComponent = 0} (half2(foo) .x)
1048 // argMap[3] = {.fArgIndex = 1, .fComponent = 1} (half2(foo) .y)
1049 struct ConstructorArgMap {
1050 int8_t fArgIndex;
1051 int8_t fComponent;
1052 };
1053
1054 int numConstructorArgs = base.type().columns();
1055 ConstructorArgMap argMap[4] = {};
1056 int writeIdx = 0;
1057 for (int argIdx = 0; argIdx < (int) base.arguments().size(); ++argIdx) {
1058 const Expression& expr = *base.arguments()[argIdx];
1059 int argWidth = expr.type().columns();
1060 for (int componentIdx = 0; componentIdx < argWidth; ++componentIdx) {
1061 argMap[writeIdx].fArgIndex = argIdx;
1062 argMap[writeIdx].fComponent = componentIdx;
1063 ++writeIdx;
1064 }
1065 }
1066 SkASSERT(writeIdx == numConstructorArgs);
1067
1068 // Count up the number of times each constructor argument is used by the
1069 // swizzle.
1070 // `half4(bar.yz, half2(foo)).xwxy` -> { 3, 1 }
1071 // - bar.yz is referenced 3 times, by `.x_xy`
1072 // - half(foo) is referenced 1 time, by `._w__`
1073 int8_t exprUsed[4] = {};
1074 for (int c : s.components()) {
1075 exprUsed[argMap[c].fArgIndex]++;
1076 }
1077
1078 bool safeToOptimize = true;
1079 for (int index = 0; index < numConstructorArgs; ++index) {
1080 int8_t constructorArgIndex = argMap[index].fArgIndex;
1081 const Expression& baseArg = *base.arguments()[constructorArgIndex];
1082
1083 // Check that non-trivial expressions are not swizzled in more than once.
John Stilesc30fbca2020-11-19 16:25:49 -05001084 if (exprUsed[constructorArgIndex] > 1 &&
1085 !Analysis::IsTrivialExpression(baseArg)) {
John Stiles0777ac42020-11-19 11:06:47 -05001086 safeToOptimize = false;
1087 break;
1088 }
1089 // Check that side-effect-bearing expressions are swizzled in exactly once.
1090 if (exprUsed[constructorArgIndex] != 1 && baseArg.hasSideEffects()) {
1091 safeToOptimize = false;
1092 break;
1093 }
1094 }
1095
1096 if (safeToOptimize) {
John Stilesd9076cb2020-11-19 12:18:36 -05001097 struct ReorderedArgument {
1098 int8_t fArgIndex;
1099 ComponentArray fComponents;
1100 };
1101 SkSTArray<4, ReorderedArgument> reorderedArgs;
John Stiles0777ac42020-11-19 11:06:47 -05001102 for (int c : s.components()) {
1103 const ConstructorArgMap& argument = argMap[c];
1104 const Expression& baseArg = *base.arguments()[argument.fArgIndex];
1105
John Stiles9aeed132020-11-24 17:36:06 -05001106 if (baseArg.type().isScalar()) {
John Stilesd9076cb2020-11-19 12:18:36 -05001107 // This argument is a scalar; add it to the list as-is.
John Stiles0777ac42020-11-19 11:06:47 -05001108 SkASSERT(argument.fComponent == 0);
John Stilesd9076cb2020-11-19 12:18:36 -05001109 reorderedArgs.push_back({argument.fArgIndex,
1110 ComponentArray{}});
John Stiles0777ac42020-11-19 11:06:47 -05001111 } else {
John Stilesd9076cb2020-11-19 12:18:36 -05001112 // This argument is a component from a vector.
John Stiles0777ac42020-11-19 11:06:47 -05001113 SkASSERT(argument.fComponent < baseArg.type().columns());
John Stilesd9076cb2020-11-19 12:18:36 -05001114 if (reorderedArgs.empty() ||
1115 reorderedArgs.back().fArgIndex != argument.fArgIndex) {
1116 // This can't be combined with the previous argument. Add a new one.
1117 reorderedArgs.push_back({argument.fArgIndex,
1118 ComponentArray{argument.fComponent}});
1119 } else {
1120 // Since we know this argument uses components, it should already
1121 // have at least one component set.
1122 SkASSERT(!reorderedArgs.back().fComponents.empty());
1123 // Build up the current argument with one more component.
1124 reorderedArgs.back().fComponents.push_back(argument.fComponent);
1125 }
John Stiles0777ac42020-11-19 11:06:47 -05001126 }
1127 }
John Stilesd9076cb2020-11-19 12:18:36 -05001128
1129 // Convert our reordered argument list to an actual array of expressions, with
1130 // the new order and any new inner swizzles that need to be applied. Note that
1131 // we expect followup passes to clean up the inner swizzles.
1132 ExpressionArray newArgs;
1133 newArgs.reserve_back(swizzleSize);
1134 for (const ReorderedArgument& reorderedArg : reorderedArgs) {
1135 const Expression& baseArg = *base.arguments()[reorderedArg.fArgIndex];
1136 if (reorderedArg.fComponents.empty()) {
1137 newArgs.push_back(baseArg.clone());
1138 } else {
1139 newArgs.push_back(std::make_unique<Swizzle>(*fContext, baseArg.clone(),
1140 reorderedArg.fComponents));
1141 }
1142 }
1143
1144 // Create a new constructor.
John Stiles0777ac42020-11-19 11:06:47 -05001145 replacement = std::make_unique<Constructor>(
1146 base.fOffset,
1147 &componentType.toCompound(*fContext, swizzleSize, /*rows=*/1),
1148 std::move(newArgs));
1149
John Stilesa60ac0c2020-12-22 08:59:51 -05001150 // Remove references within 'expr', add references within 'replacement.'
John Stiles0777ac42020-11-19 11:06:47 -05001151 optimizationContext->fUsage->replace(expr, replacement.get());
John Stilesa60ac0c2020-12-22 08:59:51 -05001152
1153 // We're replacing an expression with a cloned version; we'll need a rescan.
1154 try_replace_expression(&b, iter, &replacement);
1155 optimizationContext->fUpdated = true;
1156 optimizationContext->fNeedsRescan = true;
John Stiles0777ac42020-11-19 11:06:47 -05001157 }
John Stiles108bbe22020-11-18 11:10:38 -05001158 break;
Ethan Nicholas409f6f02019-09-17 12:34:39 -04001159 }
John Stiles30212b72020-06-11 17:55:07 -04001160 break;
Ethan Nicholascb670962017-04-20 19:31:52 -04001161 }
1162 default:
1163 break;
1164 }
1165}
1166
John Stiles92219b42020-06-15 12:32:24 -04001167// Returns true if this statement could potentially execute a break at the current level. We ignore
1168// nested loops and switches, since any breaks inside of them will merely break the loop / switch.
John Stilesb92641c2020-08-31 18:09:01 -04001169static bool contains_conditional_break(Statement& stmt) {
1170 class ContainsConditionalBreak : public ProgramVisitor {
1171 public:
1172 bool visitStatement(const Statement& stmt) override {
Ethan Nicholase6592142020-09-08 10:22:09 -04001173 switch (stmt.kind()) {
1174 case Statement::Kind::kBlock:
John Stilesbb1505f2021-02-12 09:17:53 -05001175 return INHERITED::visitStatement(stmt);
John Stilesb92641c2020-08-31 18:09:01 -04001176
Ethan Nicholase6592142020-09-08 10:22:09 -04001177 case Statement::Kind::kBreak:
John Stilesb92641c2020-08-31 18:09:01 -04001178 return fInConditional > 0;
1179
Ethan Nicholase6592142020-09-08 10:22:09 -04001180 case Statement::Kind::kIf: {
John Stilesb92641c2020-08-31 18:09:01 -04001181 ++fInConditional;
John Stilesbb1505f2021-02-12 09:17:53 -05001182 bool result = INHERITED::visitStatement(stmt);
John Stilesb92641c2020-08-31 18:09:01 -04001183 --fInConditional;
1184 return result;
1185 }
1186
1187 default:
1188 return false;
1189 }
1190 }
1191
1192 int fInConditional = 0;
1193 using INHERITED = ProgramVisitor;
1194 };
1195
1196 return ContainsConditionalBreak{}.visitStatement(stmt);
John Stiles92219b42020-06-15 12:32:24 -04001197}
1198
Ethan Nicholas5005a222018-08-24 13:06:27 -04001199// returns true if this statement definitely executes a break at the current level (we ignore
1200// nested loops and switches, since any breaks inside of them will merely break the loop / switch)
John Stilesb92641c2020-08-31 18:09:01 -04001201static bool contains_unconditional_break(Statement& stmt) {
1202 class ContainsUnconditionalBreak : public ProgramVisitor {
1203 public:
1204 bool visitStatement(const Statement& stmt) override {
Ethan Nicholase6592142020-09-08 10:22:09 -04001205 switch (stmt.kind()) {
1206 case Statement::Kind::kBlock:
John Stilesbb1505f2021-02-12 09:17:53 -05001207 return INHERITED::visitStatement(stmt);
John Stilesb92641c2020-08-31 18:09:01 -04001208
Ethan Nicholase6592142020-09-08 10:22:09 -04001209 case Statement::Kind::kBreak:
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001210 return true;
John Stilesb92641c2020-08-31 18:09:01 -04001211
1212 default:
1213 return false;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001214 }
John Stilesb92641c2020-08-31 18:09:01 -04001215 }
John Stiles92219b42020-06-15 12:32:24 -04001216
John Stilesb92641c2020-08-31 18:09:01 -04001217 using INHERITED = ProgramVisitor;
1218 };
John Stiles92219b42020-06-15 12:32:24 -04001219
John Stilesb92641c2020-08-31 18:09:01 -04001220 return ContainsUnconditionalBreak{}.visitStatement(stmt);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001221}
1222
John Stiles8f2a0cf2020-10-13 12:48:21 -04001223static void move_all_but_break(std::unique_ptr<Statement>& stmt, StatementArray* target) {
Ethan Nicholase6592142020-09-08 10:22:09 -04001224 switch (stmt->kind()) {
1225 case Statement::Kind::kBlock: {
John Stiles92219b42020-06-15 12:32:24 -04001226 // Recurse into the block.
1227 Block& block = static_cast<Block&>(*stmt);
1228
John Stiles8f2a0cf2020-10-13 12:48:21 -04001229 StatementArray blockStmts;
John Stilesf4bda742020-10-14 16:57:41 -04001230 blockStmts.reserve_back(block.children().size());
Ethan Nicholas7bd60432020-09-25 14:31:59 -04001231 for (std::unique_ptr<Statement>& stmt : block.children()) {
1232 move_all_but_break(stmt, &blockStmts);
Ethan Nicholas739e1ca2020-06-11 12:16:14 -04001233 }
John Stiles92219b42020-06-15 12:32:24 -04001234
1235 target->push_back(std::make_unique<Block>(block.fOffset, std::move(blockStmts),
Ethan Nicholas7bd60432020-09-25 14:31:59 -04001236 block.symbolTable(), block.isScope()));
Ethan Nicholas739e1ca2020-06-11 12:16:14 -04001237 break;
John Stiles92219b42020-06-15 12:32:24 -04001238 }
1239
Ethan Nicholase6592142020-09-08 10:22:09 -04001240 case Statement::Kind::kBreak:
John Stiles92219b42020-06-15 12:32:24 -04001241 // Do not append a break to the target.
1242 break;
1243
Ethan Nicholas739e1ca2020-06-11 12:16:14 -04001244 default:
John Stiles92219b42020-06-15 12:32:24 -04001245 // Append normal statements to the target.
1246 target->push_back(std::move(stmt));
1247 break;
Ethan Nicholas739e1ca2020-06-11 12:16:14 -04001248 }
1249}
1250
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001251// Returns a block containing all of the statements that will be run if the given case matches
1252// (which, owing to the statements being owned by unique_ptrs, means the switch itself will be
1253// broken by this call and must then be discarded).
1254// Returns null (and leaves the switch unmodified) if no such simple reduction is possible, such as
1255// when break statements appear inside conditionals.
John Stiles92219b42020-06-15 12:32:24 -04001256static std::unique_ptr<Statement> block_for_case(SwitchStatement* switchStatement,
1257 SwitchCase* caseToCapture) {
1258 // We have to be careful to not move any of the pointers until after we're sure we're going to
1259 // succeed, so before we make any changes at all, we check the switch-cases to decide on a plan
1260 // of action. First, find the switch-case we are interested in.
Ethan Nicholas01b05e52020-10-22 15:53:41 -04001261 auto iter = switchStatement->cases().begin();
1262 for (; iter != switchStatement->cases().end(); ++iter) {
John Stiles2d4f9592020-10-30 10:29:12 -04001263 if (iter->get() == caseToCapture) {
John Stiles92219b42020-06-15 12:32:24 -04001264 break;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001265 }
John Stiles92219b42020-06-15 12:32:24 -04001266 }
1267
1268 // Next, walk forward through the rest of the switch. If we find a conditional break, we're
1269 // stuck and can't simplify at all. If we find an unconditional break, we have a range of
1270 // statements that we can use for simplification.
1271 auto startIter = iter;
1272 Statement* unconditionalBreakStmt = nullptr;
Ethan Nicholas01b05e52020-10-22 15:53:41 -04001273 for (; iter != switchStatement->cases().end(); ++iter) {
John Stiles2d4f9592020-10-30 10:29:12 -04001274 for (std::unique_ptr<Statement>& stmt : (*iter)->statements()) {
John Stiles92219b42020-06-15 12:32:24 -04001275 if (contains_conditional_break(*stmt)) {
1276 // We can't reduce switch-cases to a block when they have conditional breaks.
1277 return nullptr;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001278 }
John Stiles92219b42020-06-15 12:32:24 -04001279
1280 if (contains_unconditional_break(*stmt)) {
1281 // We found an unconditional break. We can use this block, but we need to strip
1282 // out the break statement.
1283 unconditionalBreakStmt = stmt.get();
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001284 break;
1285 }
1286 }
John Stiles92219b42020-06-15 12:32:24 -04001287
1288 if (unconditionalBreakStmt != nullptr) {
1289 break;
1290 }
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001291 }
John Stiles92219b42020-06-15 12:32:24 -04001292
1293 // We fell off the bottom of the switch or encountered a break. We know the range of statements
1294 // that we need to move over, and we know it's safe to do so.
John Stiles8f2a0cf2020-10-13 12:48:21 -04001295 StatementArray caseStmts;
John Stiles92219b42020-06-15 12:32:24 -04001296
1297 // We can move over most of the statements as-is.
1298 while (startIter != iter) {
John Stiles2d4f9592020-10-30 10:29:12 -04001299 for (std::unique_ptr<Statement>& stmt : (*startIter)->statements()) {
John Stiles92219b42020-06-15 12:32:24 -04001300 caseStmts.push_back(std::move(stmt));
1301 }
1302 ++startIter;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001303 }
John Stiles92219b42020-06-15 12:32:24 -04001304
1305 // If we found an unconditional break at the end, we need to move what we can while avoiding
1306 // that break.
1307 if (unconditionalBreakStmt != nullptr) {
John Stiles2d4f9592020-10-30 10:29:12 -04001308 for (std::unique_ptr<Statement>& stmt : (*startIter)->statements()) {
John Stiles92219b42020-06-15 12:32:24 -04001309 if (stmt.get() == unconditionalBreakStmt) {
1310 move_all_but_break(stmt, &caseStmts);
1311 unconditionalBreakStmt = nullptr;
1312 break;
1313 }
1314
1315 caseStmts.push_back(std::move(stmt));
1316 }
1317 }
1318
1319 SkASSERT(unconditionalBreakStmt == nullptr); // Verify that we fixed the unconditional break.
1320
1321 // Return our newly-synthesized block.
Ethan Nicholas01b05e52020-10-22 15:53:41 -04001322 return std::make_unique<Block>(/*offset=*/-1, std::move(caseStmts), switchStatement->symbols());
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001323}
1324
Ethan Nicholascb670962017-04-20 19:31:52 -04001325void Compiler::simplifyStatement(DefinitionMap& definitions,
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001326 BasicBlock& b,
1327 std::vector<BasicBlock::Node>::iterator* iter,
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001328 OptimizationContext* optimizationContext) {
Brian Osman010ce6a2020-10-19 16:34:10 -04001329 ProgramUsage* usage = optimizationContext->fUsage;
Ethan Nicholascb670962017-04-20 19:31:52 -04001330 Statement* stmt = (*iter)->statement()->get();
Ethan Nicholase6592142020-09-08 10:22:09 -04001331 switch (stmt->kind()) {
1332 case Statement::Kind::kVarDeclaration: {
John Stilesa5a97b42020-08-18 11:19:07 -04001333 const auto& varDecl = stmt->as<VarDeclaration>();
Brian Osman010ce6a2020-10-19 16:34:10 -04001334 if (usage->isDead(varDecl.var()) &&
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04001335 (!varDecl.value() ||
1336 !varDecl.value()->hasSideEffects())) {
1337 if (varDecl.value()) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001338 SkASSERT((*iter)->statement()->get() == stmt);
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04001339 if (!b.tryRemoveExpressionBefore(iter, varDecl.value().get())) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001340 optimizationContext->fNeedsRescan = true;
Ethan Nicholascb670962017-04-20 19:31:52 -04001341 }
Ethan Nicholascb670962017-04-20 19:31:52 -04001342 }
Ethan Nicholas5b9b0db2021-01-21 13:12:01 -05001343 // There can still be (soon to be removed) references to the variable at this point.
1344 // Allowing the VarDeclaration to be destroyed here will break those variable's
1345 // initialValue()s, so we hang on to them until optimization is finished.
1346 std::unique_ptr<Statement> old = (*iter)->setStatement(std::make_unique<Nop>(),
1347 usage);
1348 optimizationContext->fOwnedStatements.push_back(std::move(old));
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001349 optimizationContext->fUpdated = true;
Ethan Nicholascb670962017-04-20 19:31:52 -04001350 }
1351 break;
1352 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001353 case Statement::Kind::kIf: {
John Stilesa5a97b42020-08-18 11:19:07 -04001354 IfStatement& i = stmt->as<IfStatement>();
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001355 if (i.test()->kind() == Expression::Kind::kBoolLiteral) {
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001356 // constant if, collapse down to a single branch
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001357 if (i.test()->as<BoolLiteral>().value()) {
1358 SkASSERT(i.ifTrue());
Brian Osman010ce6a2020-10-19 16:34:10 -04001359 (*iter)->setStatement(std::move(i.ifTrue()), usage);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001360 } else {
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001361 if (i.ifFalse()) {
Brian Osman010ce6a2020-10-19 16:34:10 -04001362 (*iter)->setStatement(std::move(i.ifFalse()), usage);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001363 } else {
Brian Osman010ce6a2020-10-19 16:34:10 -04001364 (*iter)->setStatement(std::make_unique<Nop>(), usage);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001365 }
1366 }
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001367 optimizationContext->fUpdated = true;
1368 optimizationContext->fNeedsRescan = true;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001369 break;
1370 }
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001371 if (i.ifFalse() && i.ifFalse()->isEmpty()) {
Ethan Nicholascb670962017-04-20 19:31:52 -04001372 // else block doesn't do anything, remove it
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001373 i.ifFalse().reset();
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001374 optimizationContext->fUpdated = true;
1375 optimizationContext->fNeedsRescan = true;
Ethan Nicholascb670962017-04-20 19:31:52 -04001376 }
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001377 if (!i.ifFalse() && i.ifTrue()->isEmpty()) {
Ethan Nicholascb670962017-04-20 19:31:52 -04001378 // if block doesn't do anything, no else block
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001379 if (i.test()->hasSideEffects()) {
Ethan Nicholascb670962017-04-20 19:31:52 -04001380 // test has side effects, keep it
Brian Osman010ce6a2020-10-19 16:34:10 -04001381 (*iter)->setStatement(
1382 std::make_unique<ExpressionStatement>(std::move(i.test())), usage);
Ethan Nicholascb670962017-04-20 19:31:52 -04001383 } else {
1384 // no if, no else, no test side effects, kill the whole if
1385 // statement
Brian Osman010ce6a2020-10-19 16:34:10 -04001386 (*iter)->setStatement(std::make_unique<Nop>(), usage);
Ethan Nicholascb670962017-04-20 19:31:52 -04001387 }
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001388 optimizationContext->fUpdated = true;
1389 optimizationContext->fNeedsRescan = true;
Ethan Nicholascb670962017-04-20 19:31:52 -04001390 }
1391 break;
1392 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001393 case Statement::Kind::kSwitch: {
John Stilesa5a97b42020-08-18 11:19:07 -04001394 SwitchStatement& s = stmt->as<SwitchStatement>();
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001395 int64_t switchValue;
Ethan Nicholasc0f98152021-02-05 16:21:10 -05001396 if (ConstantFolder::GetConstantInt(*s.value(), &switchValue)) {
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001397 // switch is constant, replace it with the case that matches
1398 bool found = false;
1399 SwitchCase* defaultCase = nullptr;
John Stiles2d4f9592020-10-30 10:29:12 -04001400 for (const std::unique_ptr<SwitchCase>& c : s.cases()) {
1401 if (!c->value()) {
1402 defaultCase = c.get();
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001403 continue;
1404 }
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001405 int64_t caseValue;
Ethan Nicholasc0f98152021-02-05 16:21:10 -05001406 SkAssertResult(ConstantFolder::GetConstantInt(*c->value(), &caseValue));
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001407 if (caseValue == switchValue) {
John Stiles2d4f9592020-10-30 10:29:12 -04001408 std::unique_ptr<Statement> newBlock = block_for_case(&s, c.get());
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001409 if (newBlock) {
Brian Osman010ce6a2020-10-19 16:34:10 -04001410 (*iter)->setStatement(std::move(newBlock), usage);
John Stiles9d944232020-08-19 09:56:49 -04001411 found = true;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001412 break;
1413 } else {
John Stilesd6a5f4492021-02-11 15:46:11 -05001414 if (s.isStatic() &&
1415 !fIRGenerator->fSettings->fPermitInvalidStaticTests) {
1416 auto [iter, didInsert] = optimizationContext->fSilences.insert(&s);
1417 if (didInsert) {
1418 this->error(s.fOffset, "static switch contains non-static "
1419 "conditional break");
1420 }
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001421 }
1422 return; // can't simplify
1423 }
1424 }
1425 }
1426 if (!found) {
1427 // no matching case. use default if it exists, or kill the whole thing
1428 if (defaultCase) {
1429 std::unique_ptr<Statement> newBlock = block_for_case(&s, defaultCase);
1430 if (newBlock) {
Brian Osman010ce6a2020-10-19 16:34:10 -04001431 (*iter)->setStatement(std::move(newBlock), usage);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001432 } else {
John Stilesd6a5f4492021-02-11 15:46:11 -05001433 if (s.isStatic() &&
1434 !fIRGenerator->fSettings->fPermitInvalidStaticTests) {
1435 auto [iter, didInsert] = optimizationContext->fSilences.insert(&s);
1436 if (didInsert) {
1437 this->error(s.fOffset, "static switch contains non-static "
1438 "conditional break");
1439 }
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001440 }
1441 return; // can't simplify
1442 }
1443 } else {
Brian Osman010ce6a2020-10-19 16:34:10 -04001444 (*iter)->setStatement(std::make_unique<Nop>(), usage);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001445 }
1446 }
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001447 optimizationContext->fUpdated = true;
1448 optimizationContext->fNeedsRescan = true;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001449 }
1450 break;
1451 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001452 case Statement::Kind::kExpression: {
John Stilesa5a97b42020-08-18 11:19:07 -04001453 ExpressionStatement& e = stmt->as<ExpressionStatement>();
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001454 SkASSERT((*iter)->statement()->get() == &e);
Ethan Nicholasd503a5a2020-09-30 09:29:55 -04001455 if (!e.expression()->hasSideEffects()) {
Ethan Nicholascb670962017-04-20 19:31:52 -04001456 // Expression statement with no side effects, kill it
Ethan Nicholasd503a5a2020-09-30 09:29:55 -04001457 if (!b.tryRemoveExpressionBefore(iter, e.expression().get())) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001458 optimizationContext->fNeedsRescan = true;
Ethan Nicholascb670962017-04-20 19:31:52 -04001459 }
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001460 SkASSERT((*iter)->statement()->get() == stmt);
Brian Osman010ce6a2020-10-19 16:34:10 -04001461 (*iter)->setStatement(std::make_unique<Nop>(), usage);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001462 optimizationContext->fUpdated = true;
Ethan Nicholascb670962017-04-20 19:31:52 -04001463 }
1464 break;
1465 }
1466 default:
1467 break;
1468 }
1469}
1470
Brian Osman010ce6a2020-10-19 16:34:10 -04001471bool Compiler::scanCFG(FunctionDefinition& f, ProgramUsage* usage) {
John Stiles0cc193a2020-09-09 09:39:34 -04001472 bool madeChanges = false;
1473
Ethan Nicholascb670962017-04-20 19:31:52 -04001474 CFG cfg = CFGGenerator().getCFG(f);
1475 this->computeDataFlow(&cfg);
ethannicholas22f939e2016-10-13 13:25:34 -07001476
1477 // check for unreachable code
1478 for (size_t i = 0; i < cfg.fBlocks.size(); i++) {
John Stiles0cc193a2020-09-09 09:39:34 -04001479 const BasicBlock& block = cfg.fBlocks[i];
John Stiles40525102020-12-16 18:10:44 -05001480 if (!block.fIsReachable && !block.fAllowUnreachable && block.fNodes.size()) {
John Stiles0cc193a2020-09-09 09:39:34 -04001481 const BasicBlock::Node& node = block.fNodes[0];
John Stilesc1129322021-02-03 10:13:42 -05001482 int offset = node.isStatement() ? (*node.statement())->fOffset
1483 : (*node.expression())->fOffset;
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001484 this->error(offset, String("unreachable"));
ethannicholas22f939e2016-10-13 13:25:34 -07001485 }
1486 }
1487 if (fErrorCount) {
John Stiles0cc193a2020-09-09 09:39:34 -04001488 return madeChanges;
ethannicholas22f939e2016-10-13 13:25:34 -07001489 }
1490
Ethan Nicholascb670962017-04-20 19:31:52 -04001491 // check for dead code & undefined variables, perform constant propagation
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001492 OptimizationContext optimizationContext;
Brian Osman010ce6a2020-10-19 16:34:10 -04001493 optimizationContext.fUsage = usage;
John Stiles7d3f0892020-11-03 11:35:01 -05001494 SkBitSet eliminatedBlockIds(cfg.fBlocks.size());
Ethan Nicholascb670962017-04-20 19:31:52 -04001495 do {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001496 if (optimizationContext.fNeedsRescan) {
Ethan Nicholascb670962017-04-20 19:31:52 -04001497 cfg = CFGGenerator().getCFG(f);
1498 this->computeDataFlow(&cfg);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001499 optimizationContext.fNeedsRescan = false;
Ethan Nicholas113628d2017-02-02 16:11:39 -05001500 }
Ethan Nicholascb670962017-04-20 19:31:52 -04001501
John Stiles7d3f0892020-11-03 11:35:01 -05001502 eliminatedBlockIds.reset();
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001503 optimizationContext.fUpdated = false;
John Stiles7d3f0892020-11-03 11:35:01 -05001504
1505 for (BlockId blockId = 0; blockId < cfg.fBlocks.size(); ++blockId) {
1506 if (eliminatedBlockIds.test(blockId)) {
1507 // We reached a block ID that might have been eliminated. Be cautious and rescan.
1508 optimizationContext.fUpdated = true;
1509 optimizationContext.fNeedsRescan = true;
1510 break;
1511 }
1512
1513 BasicBlock& b = cfg.fBlocks[blockId];
1514 if (blockId > 0 && !b.fIsReachable) {
Ethan Nicholas1de14812020-06-19 15:32:49 -04001515 // Block was reachable before optimization, but has since become unreachable. In
1516 // addition to being dead code, it's broken - since control flow can't reach it, no
1517 // prior variable definitions can reach it, and therefore variables might look to
Brian Osmanc0213602020-10-06 14:43:32 -04001518 // have not been properly assigned. Kill it by replacing all statements with Nops.
Ethan Nicholas1de14812020-06-19 15:32:49 -04001519 for (BasicBlock::Node& node : b.fNodes) {
John Stiles70025e52020-09-28 16:08:58 -04001520 if (node.isStatement() && !(*node.statement())->is<Nop>()) {
John Stiles7d3f0892020-11-03 11:35:01 -05001521 // Eliminating a node runs the risk of eliminating that node's exits as
1522 // well. Keep track of this and do a rescan if we are about to access one
1523 // of these.
1524 for (BlockId id : b.fExits) {
1525 eliminatedBlockIds.set(id);
1526 }
Brian Osman010ce6a2020-10-19 16:34:10 -04001527 node.setStatement(std::make_unique<Nop>(), usage);
John Stiles0cc193a2020-09-09 09:39:34 -04001528 madeChanges = true;
Ethan Nicholas1de14812020-06-19 15:32:49 -04001529 }
1530 }
1531 continue;
1532 }
Ethan Nicholascb670962017-04-20 19:31:52 -04001533 DefinitionMap definitions = b.fBefore;
1534
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001535 for (auto iter = b.fNodes.begin(); iter != b.fNodes.end() &&
1536 !optimizationContext.fNeedsRescan; ++iter) {
John Stiles70025e52020-09-28 16:08:58 -04001537 if (iter->isExpression()) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001538 this->simplifyExpression(definitions, b, &iter, &optimizationContext);
Ethan Nicholascb670962017-04-20 19:31:52 -04001539 } else {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001540 this->simplifyStatement(definitions, b, &iter, &optimizationContext);
Ethan Nicholascb670962017-04-20 19:31:52 -04001541 }
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001542 if (optimizationContext.fNeedsRescan) {
Ethan Nicholas4b330df2017-05-17 10:52:55 -04001543 break;
1544 }
John Stilese8a24922021-02-08 17:54:08 -05001545 definitions.addDefinitions(*fContext, *iter);
Ethan Nicholascb670962017-04-20 19:31:52 -04001546 }
Brian Osman01a3eb42020-09-14 11:32:49 -04001547
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001548 if (optimizationContext.fNeedsRescan) {
Brian Osman01a3eb42020-09-14 11:32:49 -04001549 break;
1550 }
Ethan Nicholascb670962017-04-20 19:31:52 -04001551 }
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001552 madeChanges |= optimizationContext.fUpdated;
1553 } while (optimizationContext.fUpdated);
1554 SkASSERT(!optimizationContext.fNeedsRescan);
ethannicholas22f939e2016-10-13 13:25:34 -07001555
1556 // check for missing return
John Stiles54e7c052021-01-11 14:22:36 -05001557 if (f.declaration().returnType() != *fContext->fTypes.fVoid) {
John Stiles61e75e32020-10-01 15:42:37 -04001558 if (cfg.fBlocks[cfg.fExit].fIsReachable) {
Ethan Nicholas0a5d0962020-10-14 13:33:18 -04001559 this->error(f.fOffset, String("function '" + String(f.declaration().name()) +
Ethan Nicholasdb80f692019-11-22 14:06:12 -05001560 "' can exit without returning a value"));
ethannicholas22f939e2016-10-13 13:25:34 -07001561 }
1562 }
John Stiles0cc193a2020-09-09 09:39:34 -04001563
1564 return madeChanges;
ethannicholas22f939e2016-10-13 13:25:34 -07001565}
1566
Brian Osman32d53552020-09-23 13:55:20 -04001567std::unique_ptr<Program> Compiler::convertProgram(
John Stilesdbd4e6f2021-02-16 13:29:15 -05001568 ProgramKind kind,
Brian Osman32d53552020-09-23 13:55:20 -04001569 String text,
1570 const Program::Settings& settings,
Brian Osmanbe0b3b72021-01-06 14:27:35 -05001571 const std::vector<std::unique_ptr<ExternalFunction>>* externalFunctions) {
John Stilesdbd4e6f2021-02-16 13:29:15 -05001572 SkASSERT(!externalFunctions || (kind == ProgramKind::kGeneric));
Ethan Nicholas91164d12019-05-15 15:29:54 -04001573
Brian Osman0006ad02020-11-18 15:38:39 -05001574 // Loading and optimizing our base module might reset the inliner, so do that first,
1575 // *then* configure the inliner with the settings for this program.
1576 const ParsedModule& baseModule = this->moduleForProgramKind(kind);
1577
ethannicholasb3058bd2016-07-01 08:22:01 -07001578 fErrorText = "";
1579 fErrorCount = 0;
Brian Osman0006ad02020-11-18 15:38:39 -05001580 fInliner.reset(fIRGenerator->fModifiers.get(), &settings);
Brian Osman88cda172020-10-09 12:05:16 -04001581
1582 // Not using AutoSource, because caller is likely to call errorText() if we fail to compile
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001583 std::unique_ptr<String> textPtr(new String(std::move(text)));
1584 fSource = textPtr.get();
Brian Osman88cda172020-10-09 12:05:16 -04001585
John Stiles5c7bb322020-10-22 11:09:15 -04001586 // Enable node pooling while converting and optimizing the program for a performance boost.
1587 // The Program will take ownership of the pool.
Brian Osman28f702c2021-02-02 11:52:07 -05001588 std::unique_ptr<Pool> pool;
1589 if (fCaps->useNodePools()) {
1590 pool = Pool::Create();
1591 pool->attachToThread();
1592 }
Brian Osman0006ad02020-11-18 15:38:39 -05001593 IRGenerator::IRBundle ir =
1594 fIRGenerator->convertProgram(kind, &settings, baseModule, /*isBuiltinCode=*/false,
Brian Osmanbe0b3b72021-01-06 14:27:35 -05001595 textPtr->c_str(), textPtr->size(), externalFunctions);
John Stiles5c7bb322020-10-22 11:09:15 -04001596 auto program = std::make_unique<Program>(kind,
1597 std::move(textPtr),
1598 settings,
Brian Osmand7e76592020-11-02 12:26:22 -05001599 fCaps,
John Stiles5c7bb322020-10-22 11:09:15 -04001600 fContext,
1601 std::move(ir.fElements),
Brian Osman133724c2020-10-28 14:14:39 -04001602 std::move(ir.fSharedElements),
John Stiles5c7bb322020-10-22 11:09:15 -04001603 std::move(ir.fModifiers),
1604 std::move(ir.fSymbolTable),
1605 std::move(pool),
1606 ir.fInputs);
1607 bool success = false;
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001608 if (fErrorCount) {
John Stiles5c7bb322020-10-22 11:09:15 -04001609 // Do not return programs that failed to compile.
Brian Osman4f065e22021-02-13 01:06:03 +00001610 } else if (settings.fOptimize && !this->optimize(*program)) {
John Stiles5c7bb322020-10-22 11:09:15 -04001611 // Do not return programs that failed to optimize.
1612 } else {
1613 // We have a successful program!
1614 success = true;
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001615 }
John Stiles5c7bb322020-10-22 11:09:15 -04001616
Brian Osman28f702c2021-02-02 11:52:07 -05001617 if (program->fPool) {
1618 program->fPool->detachFromThread();
1619 }
John Stiles5c7bb322020-10-22 11:09:15 -04001620 return success ? std::move(program) : nullptr;
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001621}
1622
John Stilesbb1505f2021-02-12 09:17:53 -05001623void Compiler::verifyStaticTests(const Program& program) {
1624 class StaticTestVerifier : public ProgramVisitor {
1625 public:
1626 StaticTestVerifier(ErrorReporter* r) : fReporter(r) {}
1627
1628 using ProgramVisitor::visitProgramElement;
1629
1630 bool visitStatement(const Statement& stmt) override {
1631 switch (stmt.kind()) {
1632 case Statement::Kind::kIf:
1633 if (stmt.as<IfStatement>().isStatic()) {
1634 fReporter->error(stmt.fOffset, "static if has non-static test");
1635 }
1636 break;
1637
1638 case Statement::Kind::kSwitch:
1639 if (stmt.as<SwitchStatement>().isStatic()) {
1640 fReporter->error(stmt.fOffset, "static switch has non-static test");
1641 }
1642 break;
1643
1644 default:
1645 break;
1646 }
1647 return INHERITED::visitStatement(stmt);
1648 }
1649
John Stiles59e34562021-02-12 16:56:39 -05001650 bool visitExpression(const Expression&) override {
1651 // We aren't looking for anything inside an Expression, so skip them entirely.
1652 return false;
1653 }
1654
John Stilesbb1505f2021-02-12 09:17:53 -05001655 private:
1656 using INHERITED = ProgramVisitor;
1657 ErrorReporter* fReporter;
1658 };
1659
1660 // If invalid static tests are permitted, we don't need to check anything.
1661 if (fIRGenerator->fSettings->fPermitInvalidStaticTests) {
1662 return;
1663 }
1664
1665 // Check all of the program's owned elements. (Built-in elements are assumed to be valid.)
1666 StaticTestVerifier visitor{this};
1667 for (const std::unique_ptr<ProgramElement>& element : program.ownedElements()) {
1668 if (element->is<FunctionDefinition>()) {
1669 visitor.visitProgramElement(*element);
1670 }
1671 }
1672}
1673
Brian Osman0006ad02020-11-18 15:38:39 -05001674bool Compiler::optimize(LoadedModule& module) {
1675 SkASSERT(!fErrorCount);
1676 Program::Settings settings;
1677 fIRGenerator->fKind = module.fKind;
1678 fIRGenerator->fSettings = &settings;
1679 std::unique_ptr<ProgramUsage> usage = Analysis::GetUsage(module);
1680
1681 fInliner.reset(fModifiers.back().get(), &settings);
1682
1683 while (fErrorCount == 0) {
1684 bool madeChanges = false;
1685
1686 // Scan and optimize based on the control-flow graph for each function.
1687 for (const auto& element : module.fElements) {
1688 if (element->is<FunctionDefinition>()) {
1689 madeChanges |= this->scanCFG(element->as<FunctionDefinition>(), usage.get());
1690 }
1691 }
1692
1693 // Perform inline-candidate analysis and inline any functions deemed suitable.
John Stiles78047582020-12-16 16:17:41 -05001694 madeChanges |= fInliner.analyze(module.fElements, module.fSymbols, usage.get());
Brian Osman0006ad02020-11-18 15:38:39 -05001695
1696 if (!madeChanges) {
1697 break;
1698 }
1699 }
1700 return fErrorCount == 0;
1701}
1702
Ethan Nicholas00543112018-07-31 09:44:36 -04001703bool Compiler::optimize(Program& program) {
1704 SkASSERT(!fErrorCount);
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001705 fIRGenerator->fKind = program.fKind;
1706 fIRGenerator->fSettings = &program.fSettings;
Brian Osman010ce6a2020-10-19 16:34:10 -04001707 ProgramUsage* usage = program.fUsage.get();
John Stiles7954d6c2020-09-01 10:53:02 -04001708
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001709 while (fErrorCount == 0) {
1710 bool madeChanges = false;
John Stiles7954d6c2020-09-01 10:53:02 -04001711
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001712 // Scan and optimize based on the control-flow graph for each function.
Brian Osman133724c2020-10-28 14:14:39 -04001713 for (const auto& element : program.ownedElements()) {
Brian Osman1179fcf2020-10-08 16:04:40 -04001714 if (element->is<FunctionDefinition>()) {
Brian Osman010ce6a2020-10-19 16:34:10 -04001715 madeChanges |= this->scanCFG(element->as<FunctionDefinition>(), usage);
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001716 }
1717 }
1718
1719 // Perform inline-candidate analysis and inline any functions deemed suitable.
John Stiles78047582020-12-16 16:17:41 -05001720 madeChanges |= fInliner.analyze(program.ownedElements(), program.fSymbols, usage);
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001721
1722 // Remove dead functions. We wait until after analysis so that we still report errors,
1723 // even in unused code.
1724 if (program.fSettings.fRemoveDeadFunctions) {
Brian Osman133724c2020-10-28 14:14:39 -04001725 auto isDeadFunction = [&](const ProgramElement* element) {
1726 if (!element->is<FunctionDefinition>()) {
1727 return false;
1728 }
1729 const FunctionDefinition& fn = element->as<FunctionDefinition>();
1730 if (fn.declaration().name() != "main" && usage->get(fn.declaration()) == 0) {
1731 usage->remove(*element);
1732 madeChanges = true;
1733 return true;
1734 }
1735 return false;
1736 };
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001737 program.fElements.erase(
Brian Osman133724c2020-10-28 14:14:39 -04001738 std::remove_if(program.fElements.begin(), program.fElements.end(),
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001739 [&](const std::unique_ptr<ProgramElement>& element) {
Brian Osman133724c2020-10-28 14:14:39 -04001740 return isDeadFunction(element.get());
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001741 }),
1742 program.fElements.end());
Brian Osman133724c2020-10-28 14:14:39 -04001743 program.fSharedElements.erase(
1744 std::remove_if(program.fSharedElements.begin(), program.fSharedElements.end(),
1745 isDeadFunction),
1746 program.fSharedElements.end());
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001747 }
1748
John Stilesdbd4e6f2021-02-16 13:29:15 -05001749 if (program.fKind != ProgramKind::kFragmentProcessor) {
Brian Osmanc0213602020-10-06 14:43:32 -04001750 // Remove declarations of dead global variables
Brian Osman133724c2020-10-28 14:14:39 -04001751 auto isDeadVariable = [&](const ProgramElement* element) {
1752 if (!element->is<GlobalVarDeclaration>()) {
1753 return false;
1754 }
1755 const GlobalVarDeclaration& global = element->as<GlobalVarDeclaration>();
1756 const VarDeclaration& varDecl = global.declaration()->as<VarDeclaration>();
1757 if (usage->isDead(varDecl.var())) {
1758 madeChanges = true;
1759 return true;
1760 }
1761 return false;
1762 };
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001763 program.fElements.erase(
1764 std::remove_if(program.fElements.begin(), program.fElements.end(),
1765 [&](const std::unique_ptr<ProgramElement>& element) {
Brian Osman133724c2020-10-28 14:14:39 -04001766 return isDeadVariable(element.get());
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001767 }),
1768 program.fElements.end());
Brian Osman133724c2020-10-28 14:14:39 -04001769 program.fSharedElements.erase(
1770 std::remove_if(program.fSharedElements.begin(), program.fSharedElements.end(),
1771 isDeadVariable),
1772 program.fSharedElements.end());
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001773 }
John Stiles73a6bff2020-09-09 13:40:37 -04001774
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001775 if (!madeChanges) {
1776 break;
Ethan Nicholas0dc80872019-02-08 15:46:24 -05001777 }
Ethan Nicholas00543112018-07-31 09:44:36 -04001778 }
John Stilesbb1505f2021-02-12 09:17:53 -05001779
1780 if (fErrorCount == 0) {
1781 this->verifyStaticTests(program);
1782 }
1783
Ethan Nicholas00543112018-07-31 09:44:36 -04001784 return fErrorCount == 0;
1785}
1786
Brian Osmanfb32ddf2019-06-18 10:14:20 -04001787#if defined(SKSL_STANDALONE) || SK_SUPPORT_GPU
1788
Ethan Nicholas00543112018-07-31 09:44:36 -04001789bool Compiler::toSPIRV(Program& program, OutputStream& out) {
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001790#ifdef SK_ENABLE_SPIRV_VALIDATION
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001791 StringStream buffer;
Brian Osman88cda172020-10-09 12:05:16 -04001792 AutoSource as(this, program.fSource.get());
Brian Osman8b43dad2020-10-09 13:31:42 -04001793 SPIRVCodeGenerator cg(fContext.get(), &program, this, &buffer);
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001794 bool result = cg.generateCode();
Ethan Nicholasba9a04f2020-11-06 09:28:04 -05001795 if (result && program.fSettings.fValidateSPIRV) {
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001796 spvtools::SpirvTools tools(SPV_ENV_VULKAN_1_0);
Ethan Nicholas762466e2017-06-29 10:03:38 -04001797 const String& data = buffer.str();
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001798 SkASSERT(0 == data.size() % 4);
Brian Osman8d09d4a2020-11-24 15:51:06 -05001799 String errors;
1800 auto dumpmsg = [&errors](spv_message_level_t, const char*, const spv_position_t&,
1801 const char* m) {
1802 errors.appendf("SPIR-V validation error: %s\n", m);
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001803 };
1804 tools.SetMessageConsumer(dumpmsg);
Brian Osman8d09d4a2020-11-24 15:51:06 -05001805
1806 // Verify that the SPIR-V we produced is valid. At runtime, we will abort() with a message
1807 // explaining the error. In standalone mode (skslc), we will send the message, plus the
1808 // entire disassembled SPIR-V (for easier context & debugging) as *our* error message.
1809 result = tools.Validate((const uint32_t*) data.c_str(), data.size() / 4);
1810
1811 if (!result) {
1812#if defined(SKSL_STANDALONE)
1813 // Convert the string-stream to a SPIR-V disassembly.
1814 std::string disassembly;
1815 if (tools.Disassemble((const uint32_t*)data.data(), data.size() / 4, &disassembly)) {
1816 errors.append(disassembly);
1817 }
1818 this->error(-1, errors);
1819#else
1820 SkDEBUGFAILF("%s", errors.c_str());
1821#endif
1822 }
Ethan Nicholas762466e2017-06-29 10:03:38 -04001823 out.write(data.c_str(), data.size());
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001824 }
1825#else
Brian Osman88cda172020-10-09 12:05:16 -04001826 AutoSource as(this, program.fSource.get());
Brian Osman8b43dad2020-10-09 13:31:42 -04001827 SPIRVCodeGenerator cg(fContext.get(), &program, this, &out);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001828 bool result = cg.generateCode();
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001829#endif
Ethan Nicholasce33f102016-12-09 17:22:59 -05001830 return result;
1831}
1832
Ethan Nicholas00543112018-07-31 09:44:36 -04001833bool Compiler::toSPIRV(Program& program, String* out) {
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001834 StringStream buffer;
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001835 bool result = this->toSPIRV(program, buffer);
1836 if (result) {
Ethan Nicholas762466e2017-06-29 10:03:38 -04001837 *out = buffer.str();
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001838 }
1839 return result;
1840}
1841
Ethan Nicholas00543112018-07-31 09:44:36 -04001842bool Compiler::toGLSL(Program& program, OutputStream& out) {
Brian Osman88cda172020-10-09 12:05:16 -04001843 AutoSource as(this, program.fSource.get());
Ethan Nicholas26a9aad2018-03-27 14:10:52 -04001844 GLSLCodeGenerator cg(fContext.get(), &program, this, &out);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001845 bool result = cg.generateCode();
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001846 return result;
1847}
1848
Ethan Nicholas00543112018-07-31 09:44:36 -04001849bool Compiler::toGLSL(Program& program, String* out) {
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001850 StringStream buffer;
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001851 bool result = this->toGLSL(program, buffer);
1852 if (result) {
Ethan Nicholas762466e2017-06-29 10:03:38 -04001853 *out = buffer.str();
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001854 }
1855 return result;
1856}
1857
Brian Osmanc0243912020-02-19 15:35:26 -05001858bool Compiler::toHLSL(Program& program, String* out) {
1859 String spirv;
1860 if (!this->toSPIRV(program, &spirv)) {
1861 return false;
1862 }
1863
1864 return SPIRVtoHLSL(spirv, out);
1865}
1866
Ethan Nicholas00543112018-07-31 09:44:36 -04001867bool Compiler::toMetal(Program& program, OutputStream& out) {
Ethan Nicholas26a9aad2018-03-27 14:10:52 -04001868 MetalCodeGenerator cg(fContext.get(), &program, this, &out);
Ethan Nicholascc305772017-10-13 16:17:45 -04001869 bool result = cg.generateCode();
Ethan Nicholascc305772017-10-13 16:17:45 -04001870 return result;
1871}
1872
Ethan Nicholas00543112018-07-31 09:44:36 -04001873bool Compiler::toMetal(Program& program, String* out) {
Timothy Liangb8eeb802018-07-23 16:46:16 -04001874 StringStream buffer;
1875 bool result = this->toMetal(program, buffer);
1876 if (result) {
1877 *out = buffer.str();
1878 }
1879 return result;
1880}
1881
Greg Daniela28ea672020-09-25 11:12:56 -04001882#if defined(SKSL_STANDALONE) || GR_TEST_UTILS
Ethan Nicholas00543112018-07-31 09:44:36 -04001883bool Compiler::toCPP(Program& program, String name, OutputStream& out) {
Brian Osman88cda172020-10-09 12:05:16 -04001884 AutoSource as(this, program.fSource.get());
Ethan Nicholas26a9aad2018-03-27 14:10:52 -04001885 CPPCodeGenerator cg(fContext.get(), &program, this, name, &out);
Ethan Nicholas762466e2017-06-29 10:03:38 -04001886 bool result = cg.generateCode();
Ethan Nicholas762466e2017-06-29 10:03:38 -04001887 return result;
1888}
1889
Ethan Nicholas00543112018-07-31 09:44:36 -04001890bool Compiler::toH(Program& program, String name, OutputStream& out) {
Brian Osman88cda172020-10-09 12:05:16 -04001891 AutoSource as(this, program.fSource.get());
Ethan Nicholas26a9aad2018-03-27 14:10:52 -04001892 HCodeGenerator cg(fContext.get(), &program, this, name, &out);
Ethan Nicholas762466e2017-06-29 10:03:38 -04001893 bool result = cg.generateCode();
Ethan Nicholas00543112018-07-31 09:44:36 -04001894 return result;
1895}
Greg Daniela28ea672020-09-25 11:12:56 -04001896#endif // defined(SKSL_STANDALONE) || GR_TEST_UTILS
Ethan Nicholas00543112018-07-31 09:44:36 -04001897
Ethan Nicholas2a479a52020-08-18 16:29:45 -04001898#endif // defined(SKSL_STANDALONE) || SK_SUPPORT_GPU
Brian Osman2e29ab52019-09-20 12:19:11 -04001899
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001900Position Compiler::position(int offset) {
Ethan Nicholas3c729892020-12-07 12:47:17 -05001901 if (fSource && offset >= 0) {
1902 int line = 1;
1903 int column = 1;
1904 for (int i = 0; i < offset; i++) {
1905 if ((*fSource)[i] == '\n') {
1906 ++line;
1907 column = 1;
1908 }
1909 else {
1910 ++column;
1911 }
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001912 }
Ethan Nicholas3c729892020-12-07 12:47:17 -05001913 return Position(line, column);
1914 } else {
1915 return Position(-1, -1);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001916 }
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001917}
1918
1919void Compiler::error(int offset, String msg) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001920 fErrorCount++;
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001921 Position pos = this->position(offset);
John Stiles8d3642e2021-01-22 09:50:04 -05001922 fErrorTextLength.push_back(fErrorText.length());
Ethan Nicholas3c729892020-12-07 12:47:17 -05001923 fErrorText += "error: " + (pos.fLine >= 1 ? to_string(pos.fLine) + ": " : "") + msg + "\n";
ethannicholasb3058bd2016-07-01 08:22:01 -07001924}
1925
John Stiles8d3642e2021-01-22 09:50:04 -05001926void Compiler::setErrorCount(int c) {
1927 if (c < fErrorCount) {
1928 fErrorText.resize(fErrorTextLength[c]);
1929 fErrorTextLength.resize(c);
1930 fErrorCount = c;
1931 }
1932}
1933
Ethan Nicholas95046142021-01-07 10:57:27 -05001934String Compiler::errorText(bool showCount) {
1935 if (showCount) {
1936 this->writeErrorCount();
1937 }
Ethan Nicholas00543112018-07-31 09:44:36 -04001938 fErrorCount = 0;
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001939 String result = fErrorText;
Ethan Nicholas95046142021-01-07 10:57:27 -05001940 fErrorText = "";
ethannicholasb3058bd2016-07-01 08:22:01 -07001941 return result;
1942}
1943
1944void Compiler::writeErrorCount() {
1945 if (fErrorCount) {
1946 fErrorText += to_string(fErrorCount) + " error";
1947 if (fErrorCount > 1) {
1948 fErrorText += "s";
1949 }
1950 fErrorText += "\n";
1951 }
1952}
1953
John Stilesa6841be2020-08-06 14:11:56 -04001954} // namespace SkSL