blob: 59afc0d6f533f379691075d09bf47a6f21157b41 [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 Stiles270cec22021-02-17 12:59:36 -050013#include "src/core/SkScopeExit.h"
Leon Scrogginsb66214e2021-02-11 17:14:18 -050014#include "src/core/SkTraceEvent.h"
John Stilesb92641c2020-08-31 18:09:01 -040015#include "src/sksl/SkSLAnalysis.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050016#include "src/sksl/SkSLCFGGenerator.h"
17#include "src/sksl/SkSLCPPCodeGenerator.h"
18#include "src/sksl/SkSLGLSLCodeGenerator.h"
19#include "src/sksl/SkSLHCodeGenerator.h"
20#include "src/sksl/SkSLIRGenerator.h"
21#include "src/sksl/SkSLMetalCodeGenerator.h"
Brian Osman00185012021-02-04 16:07:11 -050022#include "src/sksl/SkSLOperators.h"
John Stiles270cec22021-02-17 12:59:36 -050023#include "src/sksl/SkSLProgramSettings.h"
Ethan Nicholasc18bb512020-07-28 14:46:53 -040024#include "src/sksl/SkSLRehydrator.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050025#include "src/sksl/SkSLSPIRVCodeGenerator.h"
Brian Osmanc0243912020-02-19 15:35:26 -050026#include "src/sksl/SkSLSPIRVtoHLSL.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050027#include "src/sksl/ir/SkSLEnum.h"
28#include "src/sksl/ir/SkSLExpression.h"
29#include "src/sksl/ir/SkSLExpressionStatement.h"
30#include "src/sksl/ir/SkSLFunctionCall.h"
31#include "src/sksl/ir/SkSLIntLiteral.h"
32#include "src/sksl/ir/SkSLModifiersDeclaration.h"
33#include "src/sksl/ir/SkSLNop.h"
34#include "src/sksl/ir/SkSLSymbolTable.h"
35#include "src/sksl/ir/SkSLTernaryExpression.h"
36#include "src/sksl/ir/SkSLUnresolvedFunction.h"
37#include "src/sksl/ir/SkSLVarDeclarations.h"
John Stilese6150002020-10-05 12:03:53 -040038#include "src/utils/SkBitSet.h"
ethannicholasb3058bd2016-07-01 08:22:01 -070039
Ethan Nicholasb33fa3f2020-08-06 13:00:19 -040040#include <fstream>
41
Ethan Nicholasa11035b2019-11-26 16:27:47 -050042#if !defined(SKSL_STANDALONE) & SK_SUPPORT_GPU
43#include "include/gpu/GrContextOptions.h"
44#include "src/gpu/GrShaderCaps.h"
45#endif
46
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -040047#ifdef SK_ENABLE_SPIRV_VALIDATION
48#include "spirv-tools/libspirv.hpp"
49#endif
50
Brian Osman3d87e9f2020-10-08 11:50:22 -040051#if defined(SKSL_STANDALONE)
Ethan Nicholasc18bb512020-07-28 14:46:53 -040052
Brian Osman3d87e9f2020-10-08 11:50:22 -040053// In standalone mode, we load the textual sksl source files. GN generates or copies these files
54// to the skslc executable directory. The "data" in this mode is just the filename.
55#define MODULE_DATA(name) MakeModulePath("sksl_" #name ".sksl")
56
57#else
58
59// At runtime, we load the dehydrated sksl data files. The data is a (pointer, size) pair.
Ethan Nicholasc18bb512020-07-28 14:46:53 -040060#include "src/sksl/generated/sksl_fp.dehydrated.sksl"
61#include "src/sksl/generated/sksl_frag.dehydrated.sksl"
62#include "src/sksl/generated/sksl_geom.dehydrated.sksl"
63#include "src/sksl/generated/sksl_gpu.dehydrated.sksl"
Brian Osmanb06301e2020-11-06 11:45:36 -050064#include "src/sksl/generated/sksl_public.dehydrated.sksl"
Brian Osman91946752020-12-21 13:20:40 -050065#include "src/sksl/generated/sksl_runtime.dehydrated.sksl"
Ethan Nicholasc18bb512020-07-28 14:46:53 -040066#include "src/sksl/generated/sksl_vert.dehydrated.sksl"
67
Brian Osman3d87e9f2020-10-08 11:50:22 -040068#define MODULE_DATA(name) MakeModuleData(SKSL_INCLUDE_sksl_##name,\
69 SKSL_INCLUDE_sksl_##name##_LENGTH)
Ethan Nicholasc18bb512020-07-28 14:46:53 -040070
71#endif
Ethan Nicholas0d997662019-04-08 09:46:01 -040072
ethannicholasb3058bd2016-07-01 08:22:01 -070073namespace SkSL {
74
John Stiles47c0a742021-02-09 09:30:35 -050075using RefKind = VariableReference::RefKind;
76
Brian Osman88cda172020-10-09 12:05:16 -040077class AutoSource {
78public:
79 AutoSource(Compiler* compiler, const String* source)
80 : fCompiler(compiler), fOldSource(fCompiler->fSource) {
81 fCompiler->fSource = source;
82 }
83
84 ~AutoSource() { fCompiler->fSource = fOldSource; }
85
86 Compiler* fCompiler;
87 const String* fOldSource;
88};
89
John Stilesd6a5f4492021-02-11 15:46:11 -050090Compiler::Compiler(const ShaderCapsClass* caps)
John Stilesb30151e2021-01-11 16:13:08 -050091 : fContext(std::make_shared<Context>(/*errors=*/*this))
Brian Osman0006ad02020-11-18 15:38:39 -050092 , fCaps(caps)
John Stiles7b920442020-12-17 10:43:41 -050093 , fInliner(fContext.get())
Brian Osman0006ad02020-11-18 15:38:39 -050094 , fErrorCount(0) {
95 SkASSERT(fCaps);
John Stiles7c3515b2020-10-16 18:38:39 -040096 fRootSymbolTable = std::make_shared<SymbolTable>(this, /*builtin=*/true);
Brian Osmanb06301e2020-11-06 11:45:36 -050097 fPrivateSymbolTable = std::make_shared<SymbolTable>(fRootSymbolTable, /*builtin=*/true);
John Stilesb30151e2021-01-11 16:13:08 -050098 fIRGenerator = std::make_unique<IRGenerator>(fContext.get(), fCaps);
ethannicholasb3058bd2016-07-01 08:22:01 -070099
John Stiles54e7c052021-01-11 14:22:36 -0500100#define TYPE(t) fContext->fTypes.f ## t .get()
ethannicholasb3058bd2016-07-01 08:22:01 -0700101
Brian Osmanb06301e2020-11-06 11:45:36 -0500102 const SkSL::Symbol* rootTypes[] = {
103 TYPE(Void),
Brian Salomonbf7b6202016-11-11 16:08:03 -0500104
Brian Osmanb06301e2020-11-06 11:45:36 -0500105 TYPE( Float), TYPE( Float2), TYPE( Float3), TYPE( Float4),
106 TYPE( Half), TYPE( Half2), TYPE( Half3), TYPE( Half4),
107 TYPE( Int), TYPE( Int2), TYPE( Int3), TYPE( Int4),
Brian Osmanb06301e2020-11-06 11:45:36 -0500108 TYPE( Bool), TYPE( Bool2), TYPE( Bool3), TYPE( Bool4),
Brian Salomon2a51de82016-11-16 12:06:01 -0500109
Brian Osmanc0f2b642020-12-22 13:35:55 -0500110 TYPE(Float2x2), TYPE(Float3x3), TYPE(Float4x4),
Brian Osmanc63f4312020-12-23 11:44:14 -0500111 TYPE( Half2x2), TYPE( Half3x3), TYPE(Half4x4),
Greg Daniel64773e62016-11-22 09:44:03 -0500112
Brian Osmanc63f4312020-12-23 11:44:14 -0500113 TYPE(SquareMat), TYPE(SquareHMat),
ethannicholasb3058bd2016-07-01 08:22:01 -0700114
Brian Osman20fad322020-12-23 12:42:33 -0500115 TYPE(GenType), TYPE(GenHType), TYPE(GenIType), TYPE(GenBType),
116 TYPE(Vec), TYPE(HVec), TYPE(IVec), TYPE(BVec),
Brian Osmanb06301e2020-11-06 11:45:36 -0500117
118 TYPE(FragmentProcessor),
119 };
120
121 const SkSL::Symbol* privateTypes[] = {
Brian Osman20fad322020-12-23 12:42:33 -0500122 TYPE( UInt), TYPE( UInt2), TYPE( UInt3), TYPE( UInt4),
123 TYPE( Short), TYPE( Short2), TYPE( Short3), TYPE( Short4),
124 TYPE(UShort), TYPE(UShort2), TYPE(UShort3), TYPE(UShort4),
125 TYPE( Byte), TYPE( Byte2), TYPE( Byte3), TYPE( Byte4),
126 TYPE( UByte), TYPE( UByte2), TYPE( UByte3), TYPE( UByte4),
127
128 TYPE(GenUType), TYPE(UVec),
129 TYPE(SVec), TYPE(USVec), TYPE(ByteVec), TYPE(UByteVec),
130
Brian Osmanc0f2b642020-12-22 13:35:55 -0500131 TYPE(Float2x3), TYPE(Float2x4),
132 TYPE(Float3x2), TYPE(Float3x4),
133 TYPE(Float4x2), TYPE(Float4x3),
134
Brian Osmanc63f4312020-12-23 11:44:14 -0500135 TYPE(Half2x3), TYPE(Half2x4),
136 TYPE(Half3x2), TYPE(Half3x4),
137 TYPE(Half4x2), TYPE(Half4x3),
138
Brian Osmanc0f2b642020-12-22 13:35:55 -0500139 TYPE(Mat), TYPE(HMat),
140
Brian Osmanb06301e2020-11-06 11:45:36 -0500141 TYPE(Sampler1D), TYPE(Sampler2D), TYPE(Sampler3D),
142 TYPE(SamplerExternalOES),
Brian Osmanb06301e2020-11-06 11:45:36 -0500143 TYPE(Sampler2DRect),
Brian Osmanb06301e2020-11-06 11:45:36 -0500144
145 TYPE(ISampler2D),
146 TYPE(Image2D), TYPE(IImage2D),
147 TYPE(SubpassInput), TYPE(SubpassInputMS),
148
Brian Osmanb06301e2020-11-06 11:45:36 -0500149 TYPE(Sampler),
150 TYPE(Texture2D),
151 };
152
153 for (const SkSL::Symbol* type : rootTypes) {
154 fRootSymbolTable->addWithoutOwnership(type);
155 }
156 for (const SkSL::Symbol* type : privateTypes) {
157 fPrivateSymbolTable->addWithoutOwnership(type);
158 }
159
160#undef TYPE
ethannicholasb3058bd2016-07-01 08:22:01 -0700161
Brian Osman3887a012020-09-30 13:22:27 -0400162 // sk_Caps is "builtin", but all references to it are resolved to Settings, so we don't need to
163 // treat it as builtin (ie, no need to clone it into the Program).
Brian Osmanb06301e2020-11-06 11:45:36 -0500164 fPrivateSymbolTable->add(
165 std::make_unique<Variable>(/*offset=*/-1,
John Stiles586df952020-11-12 18:27:13 -0500166 fIRGenerator->fModifiers->addToPool(Modifiers()),
Brian Osmanb06301e2020-11-06 11:45:36 -0500167 "sk_Caps",
John Stiles54e7c052021-01-11 14:22:36 -0500168 fContext->fTypes.fSkCaps.get(),
Brian Osmanb06301e2020-11-06 11:45:36 -0500169 /*builtin=*/false,
170 Variable::Storage::kGlobal));
Ethan Nicholas3605ace2016-11-21 15:59:48 -0500171
Brian Osman3d87e9f2020-10-08 11:50:22 -0400172 fRootModule = {fRootSymbolTable, /*fIntrinsics=*/nullptr};
Brian Osmanb06301e2020-11-06 11:45:36 -0500173 fPrivateModule = {fPrivateSymbolTable, /*fIntrinsics=*/nullptr};
ethannicholasb3058bd2016-07-01 08:22:01 -0700174}
175
John Stilesdd13dba2020-10-29 10:45:34 -0400176Compiler::~Compiler() {}
ethannicholasb3058bd2016-07-01 08:22:01 -0700177
Brian Osman56269982020-11-20 12:38:07 -0500178const ParsedModule& Compiler::loadGPUModule() {
179 if (!fGPUModule.fSymbols) {
John Stilesdbd4e6f2021-02-16 13:29:15 -0500180 fGPUModule = this->parseModule(ProgramKind::kFragment, MODULE_DATA(gpu), fPrivateModule);
Brian Osman56269982020-11-20 12:38:07 -0500181 }
182 return fGPUModule;
183}
184
185const ParsedModule& Compiler::loadFragmentModule() {
186 if (!fFragmentModule.fSymbols) {
John Stilesdbd4e6f2021-02-16 13:29:15 -0500187 fFragmentModule = this->parseModule(ProgramKind::kFragment, MODULE_DATA(frag),
Brian Osman56269982020-11-20 12:38:07 -0500188 this->loadGPUModule());
189 }
190 return fFragmentModule;
191}
192
193const ParsedModule& Compiler::loadVertexModule() {
194 if (!fVertexModule.fSymbols) {
John Stilesdbd4e6f2021-02-16 13:29:15 -0500195 fVertexModule = this->parseModule(ProgramKind::kVertex, MODULE_DATA(vert),
Brian Osman56269982020-11-20 12:38:07 -0500196 this->loadGPUModule());
197 }
198 return fVertexModule;
199}
200
Brian Osman88cda172020-10-09 12:05:16 -0400201const ParsedModule& Compiler::loadGeometryModule() {
Brian Osman3d87e9f2020-10-08 11:50:22 -0400202 if (!fGeometryModule.fSymbols) {
John Stilesdbd4e6f2021-02-16 13:29:15 -0500203 fGeometryModule = this->parseModule(ProgramKind::kGeometry, MODULE_DATA(geom),
Brian Osman56269982020-11-20 12:38:07 -0500204 this->loadGPUModule());
Ethan Nicholasc18bb512020-07-28 14:46:53 -0400205 }
Brian Osman88cda172020-10-09 12:05:16 -0400206 return fGeometryModule;
Ethan Nicholasc18bb512020-07-28 14:46:53 -0400207}
208
Brian Osman88cda172020-10-09 12:05:16 -0400209const ParsedModule& Compiler::loadFPModule() {
Brian Osman3d87e9f2020-10-08 11:50:22 -0400210 if (!fFPModule.fSymbols) {
John Stilesdbd4e6f2021-02-16 13:29:15 -0500211 fFPModule = this->parseModule(ProgramKind::kFragmentProcessor, MODULE_DATA(fp),
Brian Osman56269982020-11-20 12:38:07 -0500212 this->loadGPUModule());
Brian Osman8e2ef022020-09-30 13:26:43 -0400213 }
Brian Osman88cda172020-10-09 12:05:16 -0400214 return fFPModule;
Brian Osman8e2ef022020-09-30 13:26:43 -0400215}
216
Brian Osmanb06301e2020-11-06 11:45:36 -0500217const ParsedModule& Compiler::loadPublicModule() {
218 if (!fPublicModule.fSymbols) {
John Stilesdbd4e6f2021-02-16 13:29:15 -0500219 fPublicModule = this->parseModule(ProgramKind::kGeneric, MODULE_DATA(public), fRootModule);
Brian Osmanb06301e2020-11-06 11:45:36 -0500220 }
221 return fPublicModule;
222}
223
Brian Osman91946752020-12-21 13:20:40 -0500224const ParsedModule& Compiler::loadRuntimeEffectModule() {
225 if (!fRuntimeEffectModule.fSymbols) {
John Stilesdbd4e6f2021-02-16 13:29:15 -0500226 fRuntimeEffectModule = this->parseModule(ProgramKind::kRuntimeEffect, MODULE_DATA(runtime),
Brian Osman91946752020-12-21 13:20:40 -0500227 this->loadPublicModule());
Brian Osmanf1319c32020-10-13 09:34:23 -0400228
Brian Osman91946752020-12-21 13:20:40 -0500229 // Add some aliases to the runtime effect module so that it's friendlier, and more like GLSL
John Stiles54e7c052021-01-11 14:22:36 -0500230 fRuntimeEffectModule.fSymbols->addAlias("shader", fContext->fTypes.fFragmentProcessor.get());
Brian Osmanf1319c32020-10-13 09:34:23 -0400231
John Stiles54e7c052021-01-11 14:22:36 -0500232 fRuntimeEffectModule.fSymbols->addAlias("vec2", fContext->fTypes.fFloat2.get());
233 fRuntimeEffectModule.fSymbols->addAlias("vec3", fContext->fTypes.fFloat3.get());
234 fRuntimeEffectModule.fSymbols->addAlias("vec4", fContext->fTypes.fFloat4.get());
Brian Osmanf1319c32020-10-13 09:34:23 -0400235
John Stiles54e7c052021-01-11 14:22:36 -0500236 fRuntimeEffectModule.fSymbols->addAlias("bvec2", fContext->fTypes.fBool2.get());
237 fRuntimeEffectModule.fSymbols->addAlias("bvec3", fContext->fTypes.fBool3.get());
238 fRuntimeEffectModule.fSymbols->addAlias("bvec4", fContext->fTypes.fBool4.get());
Brian Osmanf1319c32020-10-13 09:34:23 -0400239
John Stiles54e7c052021-01-11 14:22:36 -0500240 fRuntimeEffectModule.fSymbols->addAlias("mat2", fContext->fTypes.fFloat2x2.get());
241 fRuntimeEffectModule.fSymbols->addAlias("mat3", fContext->fTypes.fFloat3x3.get());
242 fRuntimeEffectModule.fSymbols->addAlias("mat4", fContext->fTypes.fFloat4x4.get());
Ethan Nicholasc18bb512020-07-28 14:46:53 -0400243 }
Brian Osman91946752020-12-21 13:20:40 -0500244 return fRuntimeEffectModule;
Ethan Nicholasc18bb512020-07-28 14:46:53 -0400245}
246
John Stilesdbd4e6f2021-02-16 13:29:15 -0500247const ParsedModule& Compiler::moduleForProgramKind(ProgramKind kind) {
Brian Osman88cda172020-10-09 12:05:16 -0400248 switch (kind) {
John Stilesdbd4e6f2021-02-16 13:29:15 -0500249 case ProgramKind::kVertex: return this->loadVertexModule(); break;
250 case ProgramKind::kFragment: return this->loadFragmentModule(); break;
251 case ProgramKind::kGeometry: return this->loadGeometryModule(); break;
252 case ProgramKind::kFragmentProcessor: return this->loadFPModule(); break;
253 case ProgramKind::kRuntimeEffect: return this->loadRuntimeEffectModule(); break;
254 case ProgramKind::kGeneric: return this->loadPublicModule(); break;
Brian Osman88cda172020-10-09 12:05:16 -0400255 }
256 SkUNREACHABLE;
Ethan Nicholasc18bb512020-07-28 14:46:53 -0400257}
258
John Stilesdbd4e6f2021-02-16 13:29:15 -0500259LoadedModule Compiler::loadModule(ProgramKind kind,
Brian Osman3d87e9f2020-10-08 11:50:22 -0400260 ModuleData data,
261 std::shared_ptr<SymbolTable> base) {
Brian Osman3d87e9f2020-10-08 11:50:22 -0400262 if (!base) {
Brian Osmanb06301e2020-11-06 11:45:36 -0500263 // NOTE: This is a workaround. The only time 'base' is null is when dehydrating includes.
264 // In that case, skslc doesn't know which module it's preparing, nor what the correct base
265 // module is. We can't use 'Root', because many GPU intrinsics reference private types,
266 // like samplers or textures. Today, 'Private' does contain the union of all known types,
267 // so this is safe. If we ever have types that only exist in 'Public' (for example), this
268 // logic needs to be smarter (by choosing the correct base for the module we're compiling).
269 base = fPrivateSymbolTable;
Brian Osman3d87e9f2020-10-08 11:50:22 -0400270 }
271
272#if defined(SKSL_STANDALONE)
273 SkASSERT(data.fPath);
274 std::ifstream in(data.fPath);
Brian Osmane498b3c2020-09-23 14:42:11 -0400275 std::unique_ptr<String> text = std::make_unique<String>(std::istreambuf_iterator<char>(in),
276 std::istreambuf_iterator<char>());
Ethan Nicholasb33fa3f2020-08-06 13:00:19 -0400277 if (in.rdstate()) {
Brian Osman3d87e9f2020-10-08 11:50:22 -0400278 printf("error reading %s\n", data.fPath);
Ethan Nicholasb33fa3f2020-08-06 13:00:19 -0400279 abort();
280 }
Brian Osmane498b3c2020-09-23 14:42:11 -0400281 const String* source = fRootSymbolTable->takeOwnershipOfString(std::move(text));
Brian Osman88cda172020-10-09 12:05:16 -0400282 AutoSource as(this, source);
Ethan Nicholas8da1e652019-05-24 11:01:59 -0400283 Program::Settings settings;
John Stiles881a10c2020-09-19 10:13:24 -0400284 SkASSERT(fIRGenerator->fCanInline);
285 fIRGenerator->fCanInline = false;
Brian Osmanf4738962021-02-11 11:17:36 -0500286 settings.fReplaceSettings = false;
John Stilesdbd4e6f2021-02-16 13:29:15 -0500287
Brian Osman88cda172020-10-09 12:05:16 -0400288 ParsedModule baseModule = {base, /*fIntrinsics=*/nullptr};
Brian Osmand7e76592020-11-02 12:26:22 -0500289 IRGenerator::IRBundle ir =
Brian Osman0006ad02020-11-18 15:38:39 -0500290 fIRGenerator->convertProgram(kind, &settings, baseModule,
Brian Osmand7e76592020-11-02 12:26:22 -0500291 /*isBuiltinCode=*/true, source->c_str(), source->length(),
Brian Osmanbe0b3b72021-01-06 14:27:35 -0500292 /*externalFunctions=*/nullptr);
Brian Osman133724c2020-10-28 14:14:39 -0400293 SkASSERT(ir.fSharedElements.empty());
Brian Osman0006ad02020-11-18 15:38:39 -0500294 LoadedModule module = { kind, std::move(ir.fSymbolTable), std::move(ir.fElements) };
John Stiles881a10c2020-09-19 10:13:24 -0400295 fIRGenerator->fCanInline = true;
Ethan Nicholas8da1e652019-05-24 11:01:59 -0400296 if (this->fErrorCount) {
297 printf("Unexpected errors: %s\n", this->fErrorText.c_str());
Brian Osman3d87e9f2020-10-08 11:50:22 -0400298 SkDEBUGFAILF("%s %s\n", data.fPath, this->fErrorText.c_str());
Ethan Nicholas8da1e652019-05-24 11:01:59 -0400299 }
Brian Osman88cda172020-10-09 12:05:16 -0400300 fModifiers.push_back(std::move(ir.fModifiers));
Brian Osman3d87e9f2020-10-08 11:50:22 -0400301#else
302 SkASSERT(data.fData && (data.fSize != 0));
303 Rehydrator rehydrator(fContext.get(), fIRGenerator->fModifiers.get(), base, this,
304 data.fData, data.fSize);
Brian Osman0006ad02020-11-18 15:38:39 -0500305 LoadedModule module = { kind, rehydrator.symbolTable(), rehydrator.elements() };
Brian Osman3d87e9f2020-10-08 11:50:22 -0400306 fModifiers.push_back(fIRGenerator->releaseModifiers());
307#endif
308
309 return module;
310}
311
John Stilesdbd4e6f2021-02-16 13:29:15 -0500312ParsedModule Compiler::parseModule(ProgramKind kind, ModuleData data, const ParsedModule& base) {
Brian Osman0006ad02020-11-18 15:38:39 -0500313 LoadedModule module = this->loadModule(kind, data, base.fSymbols);
314 this->optimize(module);
Brian Osman3d87e9f2020-10-08 11:50:22 -0400315
316 // For modules that just declare (but don't define) intrinsic functions, there will be no new
317 // program elements. In that case, we can share our parent's intrinsic map:
Brian Osman0006ad02020-11-18 15:38:39 -0500318 if (module.fElements.empty()) {
319 return {module.fSymbols, base.fIntrinsics};
Brian Osman3d87e9f2020-10-08 11:50:22 -0400320 }
321
322 auto intrinsics = std::make_shared<IRIntrinsicMap>(base.fIntrinsics.get());
323
324 // Now, transfer all of the program elements to an intrinsic map. This maps certain types of
325 // global objects to the declaring ProgramElement.
Brian Osman0006ad02020-11-18 15:38:39 -0500326 for (std::unique_ptr<ProgramElement>& element : module.fElements) {
Brian Osman3d87e9f2020-10-08 11:50:22 -0400327 switch (element->kind()) {
328 case ProgramElement::Kind::kFunction: {
329 const FunctionDefinition& f = element->as<FunctionDefinition>();
Ethan Nicholas0a5d0962020-10-14 13:33:18 -0400330 SkASSERT(f.declaration().isBuiltin());
331 intrinsics->insertOrDie(f.declaration().description(), std::move(element));
Brian Osman3d87e9f2020-10-08 11:50:22 -0400332 break;
333 }
John Stiles569249b2020-11-03 12:18:22 -0500334 case ProgramElement::Kind::kFunctionPrototype: {
335 // These are already in the symbol table.
336 break;
337 }
Brian Osman3d87e9f2020-10-08 11:50:22 -0400338 case ProgramElement::Kind::kEnum: {
339 const Enum& e = element->as<Enum>();
340 SkASSERT(e.isBuiltin());
341 intrinsics->insertOrDie(e.typeName(), std::move(element));
342 break;
343 }
344 case ProgramElement::Kind::kGlobalVar: {
Ethan Nicholasc51f33e2020-10-13 13:49:44 -0400345 const GlobalVarDeclaration& global = element->as<GlobalVarDeclaration>();
346 const Variable& var = global.declaration()->as<VarDeclaration>().var();
347 SkASSERT(var.isBuiltin());
348 intrinsics->insertOrDie(var.name(), std::move(element));
Brian Osman3d87e9f2020-10-08 11:50:22 -0400349 break;
350 }
351 case ProgramElement::Kind::kInterfaceBlock: {
Ethan Nicholaseaf47882020-10-15 10:10:08 -0400352 const Variable& var = element->as<InterfaceBlock>().variable();
353 SkASSERT(var.isBuiltin());
354 intrinsics->insertOrDie(var.name(), std::move(element));
Brian Osman3d87e9f2020-10-08 11:50:22 -0400355 break;
356 }
357 default:
358 printf("Unsupported element: %s\n", element->description().c_str());
359 SkASSERT(false);
360 break;
361 }
362 }
363
Brian Osman0006ad02020-11-18 15:38:39 -0500364 return {module.fSymbols, std::move(intrinsics)};
Ethan Nicholas8da1e652019-05-24 11:01:59 -0400365}
366
John Stilese6150002020-10-05 12:03:53 -0400367void Compiler::scanCFG(CFG* cfg, BlockId blockId, SkBitSet* processedSet) {
ethannicholas22f939e2016-10-13 13:25:34 -0700368 BasicBlock& block = cfg->fBlocks[blockId];
369
370 // compute definitions after this block
Ethan Nicholas86a43402017-01-19 13:32:00 -0500371 DefinitionMap after = block.fBefore;
ethannicholas22f939e2016-10-13 13:25:34 -0700372 for (const BasicBlock::Node& n : block.fNodes) {
John Stilese8a24922021-02-08 17:54:08 -0500373 after.addDefinitions(*fContext, n);
ethannicholas22f939e2016-10-13 13:25:34 -0700374 }
375
376 // propagate definitions to exits
377 for (BlockId exitId : block.fExits) {
Ethan Nicholas26a9aad2018-03-27 14:10:52 -0400378 if (exitId == blockId) {
379 continue;
380 }
ethannicholas22f939e2016-10-13 13:25:34 -0700381 BasicBlock& exit = cfg->fBlocks[exitId];
John Stiles65b48272020-12-22 17:18:34 -0500382 for (const auto& [var, e1] : after) {
John Stiles796cdb72020-10-08 12:06:53 -0400383 std::unique_ptr<Expression>** exitDef = exit.fBefore.find(var);
384 if (!exitDef) {
John Stilese6150002020-10-05 12:03:53 -0400385 // exit has no definition for it, just copy it and reprocess exit block
386 processedSet->reset(exitId);
John Stilese8a24922021-02-08 17:54:08 -0500387 exit.fBefore.set(var, e1);
ethannicholas22f939e2016-10-13 13:25:34 -0700388 } else {
Ethan Nicholas86a43402017-01-19 13:32:00 -0500389 // exit has a (possibly different) value already defined
John Stiles796cdb72020-10-08 12:06:53 -0400390 std::unique_ptr<Expression>* e2 = *exitDef;
ethannicholas22f939e2016-10-13 13:25:34 -0700391 if (e1 != e2) {
John Stilese6150002020-10-05 12:03:53 -0400392 // definition has changed, merge and reprocess the exit block
393 processedSet->reset(exitId);
Ethan Nicholasaf197692017-02-27 13:26:45 -0500394 if (e1 && e2) {
John Stiles796cdb72020-10-08 12:06:53 -0400395 *exitDef = (std::unique_ptr<Expression>*)&fContext->fDefined_Expression;
Ethan Nicholasaf197692017-02-27 13:26:45 -0500396 } else {
John Stiles796cdb72020-10-08 12:06:53 -0400397 *exitDef = nullptr;
Ethan Nicholasaf197692017-02-27 13:26:45 -0500398 }
ethannicholas22f939e2016-10-13 13:25:34 -0700399 }
400 }
John Stiles65b48272020-12-22 17:18:34 -0500401 }
ethannicholas22f939e2016-10-13 13:25:34 -0700402 }
403}
404
Ethan Nicholascb670962017-04-20 19:31:52 -0400405/**
406 * Returns true if assigning to this lvalue has no effect.
407 */
Brian Osman010ce6a2020-10-19 16:34:10 -0400408static bool is_dead(const Expression& lvalue, ProgramUsage* usage) {
Ethan Nicholase6592142020-09-08 10:22:09 -0400409 switch (lvalue.kind()) {
410 case Expression::Kind::kVariableReference:
Brian Osman010ce6a2020-10-19 16:34:10 -0400411 return usage->isDead(*lvalue.as<VariableReference>().variable());
Ethan Nicholase6592142020-09-08 10:22:09 -0400412 case Expression::Kind::kSwizzle:
Brian Osman010ce6a2020-10-19 16:34:10 -0400413 return is_dead(*lvalue.as<Swizzle>().base(), usage);
Ethan Nicholase6592142020-09-08 10:22:09 -0400414 case Expression::Kind::kFieldAccess:
Brian Osman010ce6a2020-10-19 16:34:10 -0400415 return is_dead(*lvalue.as<FieldAccess>().base(), usage);
Ethan Nicholase6592142020-09-08 10:22:09 -0400416 case Expression::Kind::kIndex: {
John Stilesa5a97b42020-08-18 11:19:07 -0400417 const IndexExpression& idx = lvalue.as<IndexExpression>();
Brian Osman010ce6a2020-10-19 16:34:10 -0400418 return is_dead(*idx.base(), usage) &&
Ethan Nicholas2a4952d2020-10-08 15:35:56 -0400419 !idx.index()->hasProperty(Expression::Property::kSideEffects);
Ethan Nicholascb670962017-04-20 19:31:52 -0400420 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400421 case Expression::Kind::kTernary: {
John Stilesa5a97b42020-08-18 11:19:07 -0400422 const TernaryExpression& t = lvalue.as<TernaryExpression>();
Brian Osman010ce6a2020-10-19 16:34:10 -0400423 return !t.test()->hasSideEffects() &&
424 is_dead(*t.ifTrue(), usage) &&
425 is_dead(*t.ifFalse(), usage);
Ethan Nicholasa583b812018-01-18 13:32:11 -0500426 }
Ethan Nicholascb670962017-04-20 19:31:52 -0400427 default:
John Stileseada7bc2021-02-02 16:29:32 -0500428 SkDEBUGFAILF("invalid lvalue: %s\n", lvalue.description().c_str());
Ethan Nicholas2a099da2020-01-02 14:40:54 -0500429 return false;
Ethan Nicholascb670962017-04-20 19:31:52 -0400430 }
431}
ethannicholas22f939e2016-10-13 13:25:34 -0700432
Ethan Nicholascb670962017-04-20 19:31:52 -0400433/**
434 * Returns true if this is an assignment which can be collapsed down to just the right hand side due
435 * to a dead target and lack of side effects on the left hand side.
436 */
Brian Osman010ce6a2020-10-19 16:34:10 -0400437static bool dead_assignment(const BinaryExpression& b, ProgramUsage* usage) {
John Stiles45990502021-02-16 10:55:27 -0500438 if (!b.getOperator().isAssignment()) {
Ethan Nicholascb670962017-04-20 19:31:52 -0400439 return false;
440 }
John Stiles2d4f9592020-10-30 10:29:12 -0400441 return is_dead(*b.left(), usage);
Ethan Nicholascb670962017-04-20 19:31:52 -0400442}
443
John Stiles0ac6c152021-02-10 14:04:24 -0500444/**
445 * Returns true if both expression trees are the same. The left side is expected to be an lvalue.
446 * This only needs to check for trees that can plausibly terminate in a variable, so some basic
447 * candidates like `FloatLiteral` are missing.
448 */
449static bool is_matching_expression_tree(const Expression& left, const Expression& right) {
450 if (left.kind() != right.kind() || left.type() != right.type()) {
451 return false;
452 }
453
454 switch (left.kind()) {
455 case Expression::Kind::kIntLiteral:
456 return left.as<IntLiteral>().value() == right.as<IntLiteral>().value();
457
458 case Expression::Kind::kFieldAccess:
459 return left.as<FieldAccess>().fieldIndex() == right.as<FieldAccess>().fieldIndex() &&
460 is_matching_expression_tree(*left.as<FieldAccess>().base(),
461 *right.as<FieldAccess>().base());
462
463 case Expression::Kind::kIndex:
464 return is_matching_expression_tree(*left.as<IndexExpression>().index(),
465 *right.as<IndexExpression>().index()) &&
466 is_matching_expression_tree(*left.as<IndexExpression>().base(),
467 *right.as<IndexExpression>().base());
468
469 case Expression::Kind::kSwizzle:
470 return left.as<Swizzle>().components() == right.as<Swizzle>().components() &&
471 is_matching_expression_tree(*left.as<Swizzle>().base(),
472 *right.as<Swizzle>().base());
473
474 case Expression::Kind::kVariableReference:
475 return left.as<VariableReference>().variable() ==
476 right.as<VariableReference>().variable();
477
478 default:
479 return false;
480 }
481}
482
483static bool self_assignment(const BinaryExpression& b) {
John Stiles45990502021-02-16 10:55:27 -0500484 return b.getOperator().kind() == Token::Kind::TK_EQ &&
John Stiles0ac6c152021-02-10 14:04:24 -0500485 is_matching_expression_tree(*b.left(), *b.right());
486}
487
Ethan Nicholascb670962017-04-20 19:31:52 -0400488void Compiler::computeDataFlow(CFG* cfg) {
John Stilese8a24922021-02-08 17:54:08 -0500489 cfg->fBlocks[cfg->fStart].fBefore.computeStartState(*cfg);
John Stilese6150002020-10-05 12:03:53 -0400490
491 // We set bits in the "processed" set after a block has been scanned.
492 SkBitSet processedSet(cfg->fBlocks.size());
493 while (SkBitSet::OptionalIndex blockId = processedSet.findFirstUnset()) {
494 processedSet.set(*blockId);
495 this->scanCFG(cfg, *blockId, &processedSet);
ethannicholas22f939e2016-10-13 13:25:34 -0700496 }
Ethan Nicholascb670962017-04-20 19:31:52 -0400497}
498
499/**
500 * Attempts to replace the expression pointed to by iter with a new one (in both the CFG and the
501 * IR). If the expression can be cleanly removed, returns true and updates the iterator to point to
502 * the newly-inserted element. Otherwise updates only the IR and returns false (and the CFG will
503 * need to be regenerated).
504 */
John Stilesafbf8992020-08-18 10:08:21 -0400505static bool try_replace_expression(BasicBlock* b,
506 std::vector<BasicBlock::Node>::iterator* iter,
507 std::unique_ptr<Expression>* newExpression) {
Ethan Nicholascb670962017-04-20 19:31:52 -0400508 std::unique_ptr<Expression>* target = (*iter)->expression();
509 if (!b->tryRemoveExpression(iter)) {
510 *target = std::move(*newExpression);
511 return false;
512 }
513 *target = std::move(*newExpression);
514 return b->tryInsertExpression(iter, target);
515}
516
517/**
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400518 * Returns true if the expression is a constant numeric literal with the specified value, or a
519 * constant vector with all elements equal to the specified value.
Ethan Nicholascb670962017-04-20 19:31:52 -0400520 */
Ethan Nicholasa3f22f12020-10-01 12:13:17 -0400521template <typename T = SKSL_FLOAT>
John Stiles9d944232020-08-19 09:56:49 -0400522static bool is_constant(const Expression& expr, T value) {
Ethan Nicholase6592142020-09-08 10:22:09 -0400523 switch (expr.kind()) {
524 case Expression::Kind::kIntLiteral:
Ethan Nicholase96cdd12020-09-28 16:27:18 -0400525 return expr.as<IntLiteral>().value() == value;
John Stiles9d944232020-08-19 09:56:49 -0400526
Ethan Nicholase6592142020-09-08 10:22:09 -0400527 case Expression::Kind::kFloatLiteral:
Ethan Nicholasa3f22f12020-10-01 12:13:17 -0400528 return expr.as<FloatLiteral>().value() == value;
John Stiles9d944232020-08-19 09:56:49 -0400529
Ethan Nicholase6592142020-09-08 10:22:09 -0400530 case Expression::Kind::kConstructor: {
John Stiles9d944232020-08-19 09:56:49 -0400531 const Constructor& constructor = expr.as<Constructor>();
532 if (constructor.isCompileTimeConstant()) {
Ethan Nicholas30d30222020-09-11 12:27:26 -0400533 const Type& constructorType = constructor.type();
Ethan Nicholas30d30222020-09-11 12:27:26 -0400534 switch (constructorType.typeKind()) {
Ethan Nicholase6592142020-09-08 10:22:09 -0400535 case Type::TypeKind::kVector:
John Stilesbc75ebb2020-11-24 12:04:47 -0500536 if (constructor.componentType().isFloat()) {
537 for (int i = 0; i < constructorType.columns(); ++i) {
John Stiles9d944232020-08-19 09:56:49 -0400538 if (constructor.getFVecComponent(i) != value) {
539 return false;
540 }
John Stilesbc75ebb2020-11-24 12:04:47 -0500541 }
542 return true;
543 } else if (constructor.componentType().isInteger()) {
544 for (int i = 0; i < constructorType.columns(); ++i) {
John Stiles9d944232020-08-19 09:56:49 -0400545 if (constructor.getIVecComponent(i) != value) {
546 return false;
547 }
548 }
John Stilesbc75ebb2020-11-24 12:04:47 -0500549 return true;
Ethan Nicholasd188c182019-06-10 15:55:38 -0400550 }
John Stilesbc75ebb2020-11-24 12:04:47 -0500551 // Other types (e.g. boolean) might occur, but aren't supported here.
552 return false;
John Stiles9d944232020-08-19 09:56:49 -0400553
Ethan Nicholase6592142020-09-08 10:22:09 -0400554 case Type::TypeKind::kScalar:
Ethan Nicholasf70f0442020-09-29 12:41:35 -0400555 SkASSERT(constructor.arguments().size() == 1);
556 return is_constant<T>(*constructor.arguments()[0], value);
John Stiles9d944232020-08-19 09:56:49 -0400557
558 default:
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400559 return false;
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400560 }
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400561 }
562 return false;
563 }
Ethan Nicholascb670962017-04-20 19:31:52 -0400564 default:
565 return false;
566 }
567}
568
569/**
570 * Collapses the binary expression pointed to by iter down to just the right side (in both the IR
571 * and CFG structures).
572 */
John Stilesafbf8992020-08-18 10:08:21 -0400573static void delete_left(BasicBlock* b,
574 std::vector<BasicBlock::Node>::iterator* iter,
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400575 Compiler::OptimizationContext* optimizationContext) {
576 optimizationContext->fUpdated = true;
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400577 std::unique_ptr<Expression>* target = (*iter)->expression();
John Stilesa5a97b42020-08-18 11:19:07 -0400578 BinaryExpression& bin = (*target)->as<BinaryExpression>();
John Stiles2d4f9592020-10-30 10:29:12 -0400579 Expression& left = *bin.left();
580 std::unique_ptr<Expression>& rightPointer = bin.right();
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400581 SkASSERT(!left.hasSideEffects());
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400582 bool result;
John Stiles45990502021-02-16 10:55:27 -0500583 if (bin.getOperator().kind() == Token::Kind::TK_EQ) {
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400584 result = b->tryRemoveLValueBefore(iter, &left);
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400585 } else {
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400586 result = b->tryRemoveExpressionBefore(iter, &left);
Ethan Nicholascb670962017-04-20 19:31:52 -0400587 }
Brian Osman010ce6a2020-10-19 16:34:10 -0400588 // Remove references within LHS.
589 optimizationContext->fUsage->remove(&left);
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400590 *target = std::move(rightPointer);
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400591 if (!result) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400592 optimizationContext->fNeedsRescan = true;
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400593 return;
594 }
595 if (*iter == b->fNodes.begin()) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400596 optimizationContext->fNeedsRescan = true;
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400597 return;
598 }
599 --(*iter);
John Stiles70025e52020-09-28 16:08:58 -0400600 if (!(*iter)->isExpression() || (*iter)->expression() != &rightPointer) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400601 optimizationContext->fNeedsRescan = true;
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400602 return;
603 }
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400604 *iter = b->fNodes.erase(*iter);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400605 SkASSERT((*iter)->expression() == target);
Ethan Nicholascb670962017-04-20 19:31:52 -0400606}
607
608/**
609 * Collapses the binary expression pointed to by iter down to just the left side (in both the IR and
610 * CFG structures).
611 */
John Stilesafbf8992020-08-18 10:08:21 -0400612static void delete_right(BasicBlock* b,
613 std::vector<BasicBlock::Node>::iterator* iter,
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400614 Compiler::OptimizationContext* optimizationContext) {
615 optimizationContext->fUpdated = true;
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400616 std::unique_ptr<Expression>* target = (*iter)->expression();
John Stilesa5a97b42020-08-18 11:19:07 -0400617 BinaryExpression& bin = (*target)->as<BinaryExpression>();
John Stiles2d4f9592020-10-30 10:29:12 -0400618 std::unique_ptr<Expression>& leftPointer = bin.left();
619 Expression& right = *bin.right();
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400620 SkASSERT(!right.hasSideEffects());
Brian Osman010ce6a2020-10-19 16:34:10 -0400621 // Remove references within RHS.
622 optimizationContext->fUsage->remove(&right);
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400623 if (!b->tryRemoveExpressionBefore(iter, &right)) {
624 *target = std::move(leftPointer);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400625 optimizationContext->fNeedsRescan = true;
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400626 return;
Ethan Nicholascb670962017-04-20 19:31:52 -0400627 }
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400628 *target = std::move(leftPointer);
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400629 if (*iter == b->fNodes.begin()) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400630 optimizationContext->fNeedsRescan = true;
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400631 return;
632 }
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400633 --(*iter);
John Stiles70025e52020-09-28 16:08:58 -0400634 if ((!(*iter)->isExpression() || (*iter)->expression() != &leftPointer)) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400635 optimizationContext->fNeedsRescan = true;
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400636 return;
637 }
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400638 *iter = b->fNodes.erase(*iter);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400639 SkASSERT((*iter)->expression() == target);
Ethan Nicholascb670962017-04-20 19:31:52 -0400640}
641
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400642/**
643 * Constructs the specified type using a single argument.
644 */
Ethan Nicholas30d30222020-09-11 12:27:26 -0400645static std::unique_ptr<Expression> construct(const Type* type, std::unique_ptr<Expression> v) {
John Stiles8e3b6be2020-10-13 11:14:08 -0400646 ExpressionArray args;
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400647 args.push_back(std::move(v));
Ethan Nicholase6592142020-09-08 10:22:09 -0400648 std::unique_ptr<Expression> result = std::make_unique<Constructor>(-1, type, std::move(args));
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400649 return result;
650}
651
652/**
653 * Used in the implementations of vectorize_left and vectorize_right. Given a vector type and an
654 * expression x, deletes the expression pointed to by iter and replaces it with <type>(x).
655 */
656static void vectorize(BasicBlock* b,
657 std::vector<BasicBlock::Node>::iterator* iter,
658 const Type& type,
659 std::unique_ptr<Expression>* otherExpression,
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400660 Compiler::OptimizationContext* optimizationContext) {
Ethan Nicholase6592142020-09-08 10:22:09 -0400661 SkASSERT((*(*iter)->expression())->kind() == Expression::Kind::kBinary);
John Stiles9aeed132020-11-24 17:36:06 -0500662 SkASSERT(type.isVector());
663 SkASSERT((*otherExpression)->type().isScalar());
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400664 optimizationContext->fUpdated = true;
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400665 std::unique_ptr<Expression>* target = (*iter)->expression();
666 if (!b->tryRemoveExpression(iter)) {
Ethan Nicholas30d30222020-09-11 12:27:26 -0400667 *target = construct(&type, std::move(*otherExpression));
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400668 optimizationContext->fNeedsRescan = true;
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400669 } else {
Ethan Nicholas30d30222020-09-11 12:27:26 -0400670 *target = construct(&type, std::move(*otherExpression));
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400671 if (!b->tryInsertExpression(iter, target)) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400672 optimizationContext->fNeedsRescan = true;
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400673 }
674 }
675}
676
677/**
678 * Given a binary expression of the form x <op> vec<n>(y), deletes the right side and vectorizes the
679 * left to yield vec<n>(x).
680 */
681static void vectorize_left(BasicBlock* b,
682 std::vector<BasicBlock::Node>::iterator* iter,
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400683 Compiler::OptimizationContext* optimizationContext) {
John Stilesa5a97b42020-08-18 11:19:07 -0400684 BinaryExpression& bin = (*(*iter)->expression())->as<BinaryExpression>();
Brian Osman010ce6a2020-10-19 16:34:10 -0400685 // Remove references within RHS. Vectorization of LHS doesn't change reference counts.
John Stiles2d4f9592020-10-30 10:29:12 -0400686 optimizationContext->fUsage->remove(bin.right().get());
687 vectorize(b, iter, bin.right()->type(), &bin.left(), optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400688}
689
690/**
691 * Given a binary expression of the form vec<n>(x) <op> y, deletes the left side and vectorizes the
692 * right to yield vec<n>(y).
693 */
694static void vectorize_right(BasicBlock* b,
695 std::vector<BasicBlock::Node>::iterator* iter,
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400696 Compiler::OptimizationContext* optimizationContext) {
John Stilesa5a97b42020-08-18 11:19:07 -0400697 BinaryExpression& bin = (*(*iter)->expression())->as<BinaryExpression>();
Brian Osman010ce6a2020-10-19 16:34:10 -0400698 // Remove references within LHS. Vectorization of RHS doesn't change reference counts.
John Stiles2d4f9592020-10-30 10:29:12 -0400699 optimizationContext->fUsage->remove(bin.left().get());
700 vectorize(b, iter, bin.left()->type(), &bin.right(), optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400701}
702
Ethan Nicholascb670962017-04-20 19:31:52 -0400703void Compiler::simplifyExpression(DefinitionMap& definitions,
704 BasicBlock& b,
705 std::vector<BasicBlock::Node>::iterator* iter,
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400706 OptimizationContext* optimizationContext) {
Ethan Nicholascb670962017-04-20 19:31:52 -0400707 Expression* expr = (*iter)->expression()->get();
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400708 SkASSERT(expr);
John Stiles108bbe22020-11-18 11:10:38 -0500709
Ethan Nicholascb670962017-04-20 19:31:52 -0400710 if ((*iter)->fConstantPropagation) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400711 std::unique_ptr<Expression> optimized = expr->constantPropagate(*fIRGenerator,
712 definitions);
Ethan Nicholascb670962017-04-20 19:31:52 -0400713 if (optimized) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400714 optimizationContext->fUpdated = true;
Ethan Nicholas30d30222020-09-11 12:27:26 -0400715 optimized = fIRGenerator->coerce(std::move(optimized), expr->type());
Ethan Nicholas1d881522020-09-11 09:32:54 -0400716 SkASSERT(optimized);
Brian Osman010ce6a2020-10-19 16:34:10 -0400717 // Remove references within 'expr', add references within 'optimized'
718 optimizationContext->fUsage->replace(expr, optimized.get());
Ethan Nicholascb670962017-04-20 19:31:52 -0400719 if (!try_replace_expression(&b, iter, &optimized)) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400720 optimizationContext->fNeedsRescan = true;
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400721 return;
Ethan Nicholascb670962017-04-20 19:31:52 -0400722 }
John Stiles70025e52020-09-28 16:08:58 -0400723 SkASSERT((*iter)->isExpression());
Ethan Nicholascb670962017-04-20 19:31:52 -0400724 expr = (*iter)->expression()->get();
Ethan Nicholascb670962017-04-20 19:31:52 -0400725 }
726 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400727 switch (expr->kind()) {
728 case Expression::Kind::kVariableReference: {
John Stilesa5a97b42020-08-18 11:19:07 -0400729 const VariableReference& ref = expr->as<VariableReference>();
Ethan Nicholas78686922020-10-08 06:46:27 -0400730 const Variable* var = ref.variable();
Ethan Nicholas453f67f2020-10-09 10:43:45 -0400731 if (ref.refKind() != VariableReference::RefKind::kWrite &&
732 ref.refKind() != VariableReference::RefKind::kPointer &&
John Stilese8a24922021-02-08 17:54:08 -0500733 var->storage() == Variable::Storage::kLocal && !definitions.get(var) &&
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400734 optimizationContext->fSilences.find(var) == optimizationContext->fSilences.end()) {
735 optimizationContext->fSilences.insert(var);
Ethan Nicholas82a62d22017-11-07 14:42:10 +0000736 this->error(expr->fOffset,
Ethan Nicholase2c49992020-10-05 11:49:11 -0400737 "'" + var->name() + "' has not been assigned");
Ethan Nicholascb670962017-04-20 19:31:52 -0400738 }
739 break;
740 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400741 case Expression::Kind::kTernary: {
John Stiles403a3632020-08-20 12:11:48 -0400742 TernaryExpression* t = &expr->as<TernaryExpression>();
Ethan Nicholasdd218162020-10-08 05:48:01 -0400743 if (t->test()->is<BoolLiteral>()) {
Ethan Nicholascb670962017-04-20 19:31:52 -0400744 // ternary has a constant test, replace it with either the true or
745 // false branch
Ethan Nicholasdd218162020-10-08 05:48:01 -0400746 if (t->test()->as<BoolLiteral>().value()) {
Brian Osman010ce6a2020-10-19 16:34:10 -0400747 (*iter)->setExpression(std::move(t->ifTrue()), optimizationContext->fUsage);
Ethan Nicholascb670962017-04-20 19:31:52 -0400748 } else {
Brian Osman010ce6a2020-10-19 16:34:10 -0400749 (*iter)->setExpression(std::move(t->ifFalse()), optimizationContext->fUsage);
Ethan Nicholascb670962017-04-20 19:31:52 -0400750 }
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400751 optimizationContext->fUpdated = true;
752 optimizationContext->fNeedsRescan = true;
Ethan Nicholascb670962017-04-20 19:31:52 -0400753 }
754 break;
755 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400756 case Expression::Kind::kBinary: {
John Stiles403a3632020-08-20 12:11:48 -0400757 BinaryExpression* bin = &expr->as<BinaryExpression>();
John Stiles0ac6c152021-02-10 14:04:24 -0500758 if (dead_assignment(*bin, optimizationContext->fUsage) || self_assignment(*bin)) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400759 delete_left(&b, iter, optimizationContext);
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400760 break;
761 }
John Stiles2d4f9592020-10-30 10:29:12 -0400762 Expression& left = *bin->left();
763 Expression& right = *bin->right();
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400764 const Type& leftType = left.type();
765 const Type& rightType = right.type();
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400766 // collapse useless expressions like x * 1 or x + 0
John Stiles9aeed132020-11-24 17:36:06 -0500767 if ((!leftType.isScalar() && !leftType.isVector()) ||
768 (!rightType.isScalar() && !rightType.isVector())) {
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400769 break;
770 }
John Stiles45990502021-02-16 10:55:27 -0500771 switch (bin->getOperator().kind()) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400772 case Token::Kind::TK_STAR:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400773 if (is_constant(left, 1)) {
John Stiles9aeed132020-11-24 17:36:06 -0500774 if (leftType.isVector() && rightType.isScalar()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400775 // float4(1) * x -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400776 vectorize_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400777 } else {
778 // 1 * x -> x
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400779 // 1 * float4(x) -> float4(x)
780 // float4(1) * float4(x) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400781 delete_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400782 }
783 }
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400784 else if (is_constant(left, 0)) {
John Stiles9aeed132020-11-24 17:36:06 -0500785 if (leftType.isScalar() && rightType.isVector() &&
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400786 !right.hasSideEffects()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400787 // 0 * float4(x) -> float4(0)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400788 vectorize_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400789 } else {
790 // 0 * x -> 0
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400791 // float4(0) * x -> float4(0)
792 // float4(0) * float4(x) -> float4(0)
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400793 if (!right.hasSideEffects()) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400794 delete_right(&b, iter, optimizationContext);
Ethan Nicholas51493ee2017-12-11 12:34:33 -0500795 }
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400796 }
Ethan Nicholascb670962017-04-20 19:31:52 -0400797 }
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400798 else if (is_constant(right, 1)) {
John Stiles9aeed132020-11-24 17:36:06 -0500799 if (leftType.isScalar() && rightType.isVector()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400800 // x * float4(1) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400801 vectorize_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400802 } else {
803 // x * 1 -> x
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400804 // float4(x) * 1 -> float4(x)
805 // float4(x) * float4(1) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400806 delete_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400807 }
808 }
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400809 else if (is_constant(right, 0)) {
John Stiles9aeed132020-11-24 17:36:06 -0500810 if (leftType.isVector() && rightType.isScalar() && !left.hasSideEffects()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400811 // float4(x) * 0 -> float4(0)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400812 vectorize_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400813 } else {
814 // x * 0 -> 0
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400815 // x * float4(0) -> float4(0)
816 // float4(x) * float4(0) -> float4(0)
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400817 if (!left.hasSideEffects()) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400818 delete_left(&b, iter, optimizationContext);
Ethan Nicholas51493ee2017-12-11 12:34:33 -0500819 }
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400820 }
Ethan Nicholascb670962017-04-20 19:31:52 -0400821 }
822 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400823 case Token::Kind::TK_PLUS:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400824 if (is_constant(left, 0)) {
John Stiles9aeed132020-11-24 17:36:06 -0500825 if (leftType.isVector() && rightType.isScalar()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400826 // float4(0) + x -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400827 vectorize_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400828 } else {
829 // 0 + x -> x
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400830 // 0 + float4(x) -> float4(x)
831 // float4(0) + float4(x) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400832 delete_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400833 }
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400834 } else if (is_constant(right, 0)) {
John Stiles9aeed132020-11-24 17:36:06 -0500835 if (leftType.isScalar() && rightType.isVector()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400836 // x + float4(0) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400837 vectorize_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400838 } else {
839 // x + 0 -> x
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400840 // float4(x) + 0 -> float4(x)
841 // float4(x) + float4(0) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400842 delete_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400843 }
Ethan Nicholas56e42712017-04-21 10:23:37 -0400844 }
845 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400846 case Token::Kind::TK_MINUS:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400847 if (is_constant(right, 0)) {
John Stiles9aeed132020-11-24 17:36:06 -0500848 if (leftType.isScalar() && rightType.isVector()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400849 // x - float4(0) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400850 vectorize_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400851 } else {
852 // x - 0 -> x
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400853 // float4(x) - 0 -> float4(x)
854 // float4(x) - float4(0) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400855 delete_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400856 }
Ethan Nicholascb670962017-04-20 19:31:52 -0400857 }
858 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400859 case Token::Kind::TK_SLASH:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400860 if (is_constant(right, 1)) {
John Stiles9aeed132020-11-24 17:36:06 -0500861 if (leftType.isScalar() && rightType.isVector()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400862 // x / float4(1) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400863 vectorize_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400864 } else {
865 // x / 1 -> x
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400866 // float4(x) / 1 -> float4(x)
867 // float4(x) / float4(1) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400868 delete_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400869 }
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400870 } else if (is_constant(left, 0)) {
John Stiles9aeed132020-11-24 17:36:06 -0500871 if (leftType.isScalar() && rightType.isVector() &&
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400872 !right.hasSideEffects()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400873 // 0 / float4(x) -> float4(0)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400874 vectorize_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400875 } else {
876 // 0 / x -> 0
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400877 // float4(0) / x -> float4(0)
878 // float4(0) / float4(x) -> float4(0)
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400879 if (!right.hasSideEffects()) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400880 delete_right(&b, iter, optimizationContext);
Ethan Nicholas51493ee2017-12-11 12:34:33 -0500881 }
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400882 }
883 }
884 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400885 case Token::Kind::TK_PLUSEQ:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400886 if (is_constant(right, 0)) {
John Stiles47c0a742021-02-09 09:30:35 -0500887 Analysis::UpdateRefKind(&left, RefKind::kRead);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400888 delete_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400889 }
890 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400891 case Token::Kind::TK_MINUSEQ:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400892 if (is_constant(right, 0)) {
John Stiles47c0a742021-02-09 09:30:35 -0500893 Analysis::UpdateRefKind(&left, RefKind::kRead);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400894 delete_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400895 }
896 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400897 case Token::Kind::TK_STAREQ:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400898 if (is_constant(right, 1)) {
John Stiles47c0a742021-02-09 09:30:35 -0500899 Analysis::UpdateRefKind(&left, RefKind::kRead);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400900 delete_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400901 }
902 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400903 case Token::Kind::TK_SLASHEQ:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400904 if (is_constant(right, 1)) {
John Stiles47c0a742021-02-09 09:30:35 -0500905 Analysis::UpdateRefKind(&left, RefKind::kRead);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400906 delete_right(&b, iter, optimizationContext);
Ethan Nicholascb670962017-04-20 19:31:52 -0400907 }
908 break;
909 default:
910 break;
911 }
Ethan Nicholas409f6f02019-09-17 12:34:39 -0400912 break;
913 }
John Stilesf5c1d042020-11-21 23:26:07 -0500914 case Expression::Kind::kConstructor: {
915 // Find constructors embedded inside constructors and flatten them out where possible.
916 // - float4(float2(1, 2), 3, 4) --> float4(1, 2, 3, 4)
917 // - float4(w, float3(sin(x), cos(y), tan(z))) --> float4(w, sin(x), cos(y), tan(z))
918 // Leave single-argument constructors alone, though. These might be casts or splats.
919 Constructor& c = expr->as<Constructor>();
920 if (c.type().columns() > 1) {
921 // Inspect each constructor argument to see if it's a candidate for flattening.
922 // Remember matched arguments in a bitfield, "argsToOptimize".
923 int argsToOptimize = 0;
924 int currBit = 1;
925 for (const std::unique_ptr<Expression>& arg : c.arguments()) {
926 if (arg->is<Constructor>()) {
927 Constructor& inner = arg->as<Constructor>();
928 if (inner.arguments().size() > 1 &&
929 inner.type().componentType() == c.type().componentType()) {
930 argsToOptimize |= currBit;
931 }
932 }
933 currBit <<= 1;
934 }
935 if (argsToOptimize) {
936 // We found at least one argument that could be flattened out. Re-walk the
937 // constructor args and flatten the candidates we found during our initial pass.
938 ExpressionArray flattened;
939 flattened.reserve_back(c.type().columns());
940 currBit = 1;
941 for (const std::unique_ptr<Expression>& arg : c.arguments()) {
942 if (argsToOptimize & currBit) {
943 Constructor& inner = arg->as<Constructor>();
944 for (const std::unique_ptr<Expression>& innerArg : inner.arguments()) {
945 flattened.push_back(innerArg->clone());
946 }
947 } else {
948 flattened.push_back(arg->clone());
949 }
950 currBit <<= 1;
951 }
John Stiles1b91c0e2021-02-11 11:43:09 -0500952 std::unique_ptr<Expression> replacement(new Constructor(c.fOffset, &c.type(),
953 std::move(flattened)));
954 // We're replacing an expression with a cloned version; we'll need a rescan.
955 // No fUsage change: `float2(float(x), y)` and `float2(x, y)` have equivalent
956 // reference counts.
957 try_replace_expression(&b, iter, &replacement);
John Stilesf5c1d042020-11-21 23:26:07 -0500958 optimizationContext->fUpdated = true;
John Stiles1b91c0e2021-02-11 11:43:09 -0500959 optimizationContext->fNeedsRescan = true;
John Stilesf5c1d042020-11-21 23:26:07 -0500960 break;
961 }
962 }
963 break;
964 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400965 case Expression::Kind::kSwizzle: {
John Stiles403a3632020-08-20 12:11:48 -0400966 Swizzle& s = expr->as<Swizzle>();
John Stiles108bbe22020-11-18 11:10:38 -0500967 // Detect identity swizzles like `foo.rgba`.
Ethan Nicholas6b4d5812020-10-12 16:11:51 -0400968 if ((int) s.components().size() == s.base()->type().columns()) {
Ethan Nicholas409f6f02019-09-17 12:34:39 -0400969 bool identity = true;
Ethan Nicholas6b4d5812020-10-12 16:11:51 -0400970 for (int i = 0; i < (int) s.components().size(); ++i) {
971 if (s.components()[i] != i) {
Ethan Nicholas409f6f02019-09-17 12:34:39 -0400972 identity = false;
973 break;
974 }
975 }
976 if (identity) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400977 optimizationContext->fUpdated = true;
Brian Osman010ce6a2020-10-19 16:34:10 -0400978 // No fUsage change: foo.rgba and foo have equivalent reference counts
Ethan Nicholas6b4d5812020-10-12 16:11:51 -0400979 if (!try_replace_expression(&b, iter, &s.base())) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400980 optimizationContext->fNeedsRescan = true;
Ethan Nicholas409f6f02019-09-17 12:34:39 -0400981 return;
982 }
John Stiles70025e52020-09-28 16:08:58 -0400983 SkASSERT((*iter)->isExpression());
Ethan Nicholas409f6f02019-09-17 12:34:39 -0400984 break;
985 }
986 }
John Stiles108bbe22020-11-18 11:10:38 -0500987 // Detect swizzles of swizzles, e.g. replace `foo.argb.r000` with `foo.a000`.
988 if (s.base()->is<Swizzle>()) {
Ethan Nicholas6b4d5812020-10-12 16:11:51 -0400989 Swizzle& base = s.base()->as<Swizzle>();
John Stiles750109b2020-10-30 13:45:46 -0400990 ComponentArray final;
Ethan Nicholas6b4d5812020-10-12 16:11:51 -0400991 for (int c : s.components()) {
992 final.push_back(base.components()[c]);
Ethan Nicholas409f6f02019-09-17 12:34:39 -0400993 }
Ethan Nicholas6b4d5812020-10-12 16:11:51 -0400994 std::unique_ptr<Expression> replacement(new Swizzle(*fContext, base.base()->clone(),
John Stiles750109b2020-10-30 13:45:46 -0400995 final));
John Stilesd2f51b12021-01-07 18:12:31 -0500996 // We're replacing an expression with a cloned version; we'll need a rescan.
John Stiles108bbe22020-11-18 11:10:38 -0500997 // No fUsage change: `foo.gbr.gbr` and `foo.brg` have equivalent reference counts
John Stilesd2f51b12021-01-07 18:12:31 -0500998 try_replace_expression(&b, iter, &replacement);
999 optimizationContext->fUpdated = true;
1000 optimizationContext->fNeedsRescan = true;
John Stiles108bbe22020-11-18 11:10:38 -05001001 break;
1002 }
1003 // Optimize swizzles of constructors.
1004 if (s.base()->is<Constructor>()) {
1005 Constructor& base = s.base()->as<Constructor>();
1006 std::unique_ptr<Expression> replacement;
1007 const Type& componentType = base.type().componentType();
1008 int swizzleSize = s.components().size();
1009
1010 // The IR generator has already converted any zero/one swizzle components into
1011 // constructors containing zero/one args. Confirm that this is true by checking that
1012 // our swizzle components are all `xyzw` (values 0 through 3).
1013 SkASSERT(std::all_of(s.components().begin(), s.components().end(),
1014 [](int8_t c) { return c >= 0 && c <= 3; }));
1015
John Stiles9aeed132020-11-24 17:36:06 -05001016 if (base.arguments().size() == 1 && base.arguments().front()->type().isScalar()) {
John Stiles108bbe22020-11-18 11:10:38 -05001017 // `half4(scalar).zyy` can be optimized to `half3(scalar)`. The swizzle
1018 // components don't actually matter since all fields are the same.
John Stilesf0cb7332021-01-08 18:39:00 -05001019 const Expression& argument = *base.arguments().front();
1020 const Type& constructorType = componentType.toCompound(*fContext, swizzleSize,
1021 /*rows=*/1);
1022 replacement = Constructor::SimplifyConversion(constructorType, argument);
1023 if (!replacement) {
1024 ExpressionArray newArgs;
1025 newArgs.push_back(argument.clone());
1026 replacement = std::make_unique<Constructor>(base.fOffset, &constructorType,
1027 std::move(newArgs));
1028 }
John Stiles108bbe22020-11-18 11:10:38 -05001029
John Stilesa60ac0c2020-12-22 08:59:51 -05001030 // We're replacing an expression with a cloned version; we'll need a rescan.
1031 // There's no fUsage change: `half4(foo).xy` and `half2(foo)` have equivalent
1032 // reference counts.
1033 try_replace_expression(&b, iter, &replacement);
John Stiles0777ac42020-11-19 11:06:47 -05001034 optimizationContext->fUpdated = true;
John Stilesa60ac0c2020-12-22 08:59:51 -05001035 optimizationContext->fNeedsRescan = true;
John Stiles108bbe22020-11-18 11:10:38 -05001036 break;
1037 }
1038
John Stiles0777ac42020-11-19 11:06:47 -05001039 // Swizzles can duplicate some elements and discard others, e.g.
1040 // `half4(1, 2, 3, 4).xxz` --> `half3(1, 1, 3)`. However, there are constraints:
1041 // - Expressions with side effects need to occur exactly once, even if they
1042 // would otherwise be swizzle-eliminated
1043 // - Non-trivial expressions should not be repeated, but elimination is OK.
1044 //
1045 // Look up the argument for the constructor at each index. This is typically simple
1046 // but for weird cases like `half4(bar.yz, half2(foo))`, it can be harder than it
1047 // seems. This example would result in:
1048 // argMap[0] = {.fArgIndex = 0, .fComponent = 0} (bar.yz .x)
1049 // argMap[1] = {.fArgIndex = 0, .fComponent = 1} (bar.yz .y)
1050 // argMap[2] = {.fArgIndex = 1, .fComponent = 0} (half2(foo) .x)
1051 // argMap[3] = {.fArgIndex = 1, .fComponent = 1} (half2(foo) .y)
1052 struct ConstructorArgMap {
1053 int8_t fArgIndex;
1054 int8_t fComponent;
1055 };
1056
1057 int numConstructorArgs = base.type().columns();
1058 ConstructorArgMap argMap[4] = {};
1059 int writeIdx = 0;
1060 for (int argIdx = 0; argIdx < (int) base.arguments().size(); ++argIdx) {
1061 const Expression& expr = *base.arguments()[argIdx];
1062 int argWidth = expr.type().columns();
1063 for (int componentIdx = 0; componentIdx < argWidth; ++componentIdx) {
1064 argMap[writeIdx].fArgIndex = argIdx;
1065 argMap[writeIdx].fComponent = componentIdx;
1066 ++writeIdx;
1067 }
1068 }
1069 SkASSERT(writeIdx == numConstructorArgs);
1070
1071 // Count up the number of times each constructor argument is used by the
1072 // swizzle.
1073 // `half4(bar.yz, half2(foo)).xwxy` -> { 3, 1 }
1074 // - bar.yz is referenced 3 times, by `.x_xy`
1075 // - half(foo) is referenced 1 time, by `._w__`
1076 int8_t exprUsed[4] = {};
1077 for (int c : s.components()) {
1078 exprUsed[argMap[c].fArgIndex]++;
1079 }
1080
1081 bool safeToOptimize = true;
1082 for (int index = 0; index < numConstructorArgs; ++index) {
1083 int8_t constructorArgIndex = argMap[index].fArgIndex;
1084 const Expression& baseArg = *base.arguments()[constructorArgIndex];
1085
1086 // Check that non-trivial expressions are not swizzled in more than once.
John Stilesc30fbca2020-11-19 16:25:49 -05001087 if (exprUsed[constructorArgIndex] > 1 &&
1088 !Analysis::IsTrivialExpression(baseArg)) {
John Stiles0777ac42020-11-19 11:06:47 -05001089 safeToOptimize = false;
1090 break;
1091 }
1092 // Check that side-effect-bearing expressions are swizzled in exactly once.
1093 if (exprUsed[constructorArgIndex] != 1 && baseArg.hasSideEffects()) {
1094 safeToOptimize = false;
1095 break;
1096 }
1097 }
1098
1099 if (safeToOptimize) {
John Stilesd9076cb2020-11-19 12:18:36 -05001100 struct ReorderedArgument {
1101 int8_t fArgIndex;
1102 ComponentArray fComponents;
1103 };
1104 SkSTArray<4, ReorderedArgument> reorderedArgs;
John Stiles0777ac42020-11-19 11:06:47 -05001105 for (int c : s.components()) {
1106 const ConstructorArgMap& argument = argMap[c];
1107 const Expression& baseArg = *base.arguments()[argument.fArgIndex];
1108
John Stiles9aeed132020-11-24 17:36:06 -05001109 if (baseArg.type().isScalar()) {
John Stilesd9076cb2020-11-19 12:18:36 -05001110 // This argument is a scalar; add it to the list as-is.
John Stiles0777ac42020-11-19 11:06:47 -05001111 SkASSERT(argument.fComponent == 0);
John Stilesd9076cb2020-11-19 12:18:36 -05001112 reorderedArgs.push_back({argument.fArgIndex,
1113 ComponentArray{}});
John Stiles0777ac42020-11-19 11:06:47 -05001114 } else {
John Stilesd9076cb2020-11-19 12:18:36 -05001115 // This argument is a component from a vector.
John Stiles0777ac42020-11-19 11:06:47 -05001116 SkASSERT(argument.fComponent < baseArg.type().columns());
John Stilesd9076cb2020-11-19 12:18:36 -05001117 if (reorderedArgs.empty() ||
1118 reorderedArgs.back().fArgIndex != argument.fArgIndex) {
1119 // This can't be combined with the previous argument. Add a new one.
1120 reorderedArgs.push_back({argument.fArgIndex,
1121 ComponentArray{argument.fComponent}});
1122 } else {
1123 // Since we know this argument uses components, it should already
1124 // have at least one component set.
1125 SkASSERT(!reorderedArgs.back().fComponents.empty());
1126 // Build up the current argument with one more component.
1127 reorderedArgs.back().fComponents.push_back(argument.fComponent);
1128 }
John Stiles0777ac42020-11-19 11:06:47 -05001129 }
1130 }
John Stilesd9076cb2020-11-19 12:18:36 -05001131
1132 // Convert our reordered argument list to an actual array of expressions, with
1133 // the new order and any new inner swizzles that need to be applied. Note that
1134 // we expect followup passes to clean up the inner swizzles.
1135 ExpressionArray newArgs;
1136 newArgs.reserve_back(swizzleSize);
1137 for (const ReorderedArgument& reorderedArg : reorderedArgs) {
1138 const Expression& baseArg = *base.arguments()[reorderedArg.fArgIndex];
1139 if (reorderedArg.fComponents.empty()) {
1140 newArgs.push_back(baseArg.clone());
1141 } else {
1142 newArgs.push_back(std::make_unique<Swizzle>(*fContext, baseArg.clone(),
1143 reorderedArg.fComponents));
1144 }
1145 }
1146
1147 // Create a new constructor.
John Stiles0777ac42020-11-19 11:06:47 -05001148 replacement = std::make_unique<Constructor>(
1149 base.fOffset,
1150 &componentType.toCompound(*fContext, swizzleSize, /*rows=*/1),
1151 std::move(newArgs));
1152
John Stilesa60ac0c2020-12-22 08:59:51 -05001153 // Remove references within 'expr', add references within 'replacement.'
John Stiles0777ac42020-11-19 11:06:47 -05001154 optimizationContext->fUsage->replace(expr, replacement.get());
John Stilesa60ac0c2020-12-22 08:59:51 -05001155
1156 // We're replacing an expression with a cloned version; we'll need a rescan.
1157 try_replace_expression(&b, iter, &replacement);
1158 optimizationContext->fUpdated = true;
1159 optimizationContext->fNeedsRescan = true;
John Stiles0777ac42020-11-19 11:06:47 -05001160 }
John Stiles108bbe22020-11-18 11:10:38 -05001161 break;
Ethan Nicholas409f6f02019-09-17 12:34:39 -04001162 }
John Stiles30212b72020-06-11 17:55:07 -04001163 break;
Ethan Nicholascb670962017-04-20 19:31:52 -04001164 }
1165 default:
1166 break;
1167 }
1168}
1169
John Stiles92219b42020-06-15 12:32:24 -04001170// Returns true if this statement could potentially execute a break at the current level. We ignore
1171// nested loops and switches, since any breaks inside of them will merely break the loop / switch.
John Stilesb92641c2020-08-31 18:09:01 -04001172static bool contains_conditional_break(Statement& stmt) {
1173 class ContainsConditionalBreak : public ProgramVisitor {
1174 public:
1175 bool visitStatement(const Statement& stmt) override {
Ethan Nicholase6592142020-09-08 10:22:09 -04001176 switch (stmt.kind()) {
1177 case Statement::Kind::kBlock:
John Stilesbb1505f2021-02-12 09:17:53 -05001178 return INHERITED::visitStatement(stmt);
John Stilesb92641c2020-08-31 18:09:01 -04001179
Ethan Nicholase6592142020-09-08 10:22:09 -04001180 case Statement::Kind::kBreak:
John Stilesb92641c2020-08-31 18:09:01 -04001181 return fInConditional > 0;
1182
Ethan Nicholase6592142020-09-08 10:22:09 -04001183 case Statement::Kind::kIf: {
John Stilesb92641c2020-08-31 18:09:01 -04001184 ++fInConditional;
John Stilesbb1505f2021-02-12 09:17:53 -05001185 bool result = INHERITED::visitStatement(stmt);
John Stilesb92641c2020-08-31 18:09:01 -04001186 --fInConditional;
1187 return result;
1188 }
1189
1190 default:
1191 return false;
1192 }
1193 }
1194
1195 int fInConditional = 0;
1196 using INHERITED = ProgramVisitor;
1197 };
1198
1199 return ContainsConditionalBreak{}.visitStatement(stmt);
John Stiles92219b42020-06-15 12:32:24 -04001200}
1201
Ethan Nicholas5005a222018-08-24 13:06:27 -04001202// returns true if this statement definitely executes a break at the current level (we ignore
1203// nested loops and switches, since any breaks inside of them will merely break the loop / switch)
John Stilesb92641c2020-08-31 18:09:01 -04001204static bool contains_unconditional_break(Statement& stmt) {
1205 class ContainsUnconditionalBreak : public ProgramVisitor {
1206 public:
1207 bool visitStatement(const Statement& stmt) override {
Ethan Nicholase6592142020-09-08 10:22:09 -04001208 switch (stmt.kind()) {
1209 case Statement::Kind::kBlock:
John Stilesbb1505f2021-02-12 09:17:53 -05001210 return INHERITED::visitStatement(stmt);
John Stilesb92641c2020-08-31 18:09:01 -04001211
Ethan Nicholase6592142020-09-08 10:22:09 -04001212 case Statement::Kind::kBreak:
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001213 return true;
John Stilesb92641c2020-08-31 18:09:01 -04001214
1215 default:
1216 return false;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001217 }
John Stilesb92641c2020-08-31 18:09:01 -04001218 }
John Stiles92219b42020-06-15 12:32:24 -04001219
John Stilesb92641c2020-08-31 18:09:01 -04001220 using INHERITED = ProgramVisitor;
1221 };
John Stiles92219b42020-06-15 12:32:24 -04001222
John Stilesb92641c2020-08-31 18:09:01 -04001223 return ContainsUnconditionalBreak{}.visitStatement(stmt);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001224}
1225
John Stiles8f2a0cf2020-10-13 12:48:21 -04001226static void move_all_but_break(std::unique_ptr<Statement>& stmt, StatementArray* target) {
Ethan Nicholase6592142020-09-08 10:22:09 -04001227 switch (stmt->kind()) {
1228 case Statement::Kind::kBlock: {
John Stiles92219b42020-06-15 12:32:24 -04001229 // Recurse into the block.
1230 Block& block = static_cast<Block&>(*stmt);
1231
John Stiles8f2a0cf2020-10-13 12:48:21 -04001232 StatementArray blockStmts;
John Stilesf4bda742020-10-14 16:57:41 -04001233 blockStmts.reserve_back(block.children().size());
Ethan Nicholas7bd60432020-09-25 14:31:59 -04001234 for (std::unique_ptr<Statement>& stmt : block.children()) {
1235 move_all_but_break(stmt, &blockStmts);
Ethan Nicholas739e1ca2020-06-11 12:16:14 -04001236 }
John Stiles92219b42020-06-15 12:32:24 -04001237
1238 target->push_back(std::make_unique<Block>(block.fOffset, std::move(blockStmts),
Ethan Nicholas7bd60432020-09-25 14:31:59 -04001239 block.symbolTable(), block.isScope()));
Ethan Nicholas739e1ca2020-06-11 12:16:14 -04001240 break;
John Stiles92219b42020-06-15 12:32:24 -04001241 }
1242
Ethan Nicholase6592142020-09-08 10:22:09 -04001243 case Statement::Kind::kBreak:
John Stiles92219b42020-06-15 12:32:24 -04001244 // Do not append a break to the target.
1245 break;
1246
Ethan Nicholas739e1ca2020-06-11 12:16:14 -04001247 default:
John Stiles92219b42020-06-15 12:32:24 -04001248 // Append normal statements to the target.
1249 target->push_back(std::move(stmt));
1250 break;
Ethan Nicholas739e1ca2020-06-11 12:16:14 -04001251 }
1252}
1253
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001254// Returns a block containing all of the statements that will be run if the given case matches
1255// (which, owing to the statements being owned by unique_ptrs, means the switch itself will be
1256// broken by this call and must then be discarded).
1257// Returns null (and leaves the switch unmodified) if no such simple reduction is possible, such as
1258// when break statements appear inside conditionals.
John Stiles92219b42020-06-15 12:32:24 -04001259static std::unique_ptr<Statement> block_for_case(SwitchStatement* switchStatement,
1260 SwitchCase* caseToCapture) {
1261 // We have to be careful to not move any of the pointers until after we're sure we're going to
1262 // succeed, so before we make any changes at all, we check the switch-cases to decide on a plan
1263 // of action. First, find the switch-case we are interested in.
Ethan Nicholas01b05e52020-10-22 15:53:41 -04001264 auto iter = switchStatement->cases().begin();
1265 for (; iter != switchStatement->cases().end(); ++iter) {
John Stiles2d4f9592020-10-30 10:29:12 -04001266 if (iter->get() == caseToCapture) {
John Stiles92219b42020-06-15 12:32:24 -04001267 break;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001268 }
John Stiles92219b42020-06-15 12:32:24 -04001269 }
1270
1271 // Next, walk forward through the rest of the switch. If we find a conditional break, we're
1272 // stuck and can't simplify at all. If we find an unconditional break, we have a range of
1273 // statements that we can use for simplification.
1274 auto startIter = iter;
1275 Statement* unconditionalBreakStmt = nullptr;
Ethan Nicholas01b05e52020-10-22 15:53:41 -04001276 for (; iter != switchStatement->cases().end(); ++iter) {
John Stiles2d4f9592020-10-30 10:29:12 -04001277 for (std::unique_ptr<Statement>& stmt : (*iter)->statements()) {
John Stiles92219b42020-06-15 12:32:24 -04001278 if (contains_conditional_break(*stmt)) {
1279 // We can't reduce switch-cases to a block when they have conditional breaks.
1280 return nullptr;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001281 }
John Stiles92219b42020-06-15 12:32:24 -04001282
1283 if (contains_unconditional_break(*stmt)) {
1284 // We found an unconditional break. We can use this block, but we need to strip
1285 // out the break statement.
1286 unconditionalBreakStmt = stmt.get();
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001287 break;
1288 }
1289 }
John Stiles92219b42020-06-15 12:32:24 -04001290
1291 if (unconditionalBreakStmt != nullptr) {
1292 break;
1293 }
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001294 }
John Stiles92219b42020-06-15 12:32:24 -04001295
1296 // We fell off the bottom of the switch or encountered a break. We know the range of statements
1297 // that we need to move over, and we know it's safe to do so.
John Stiles8f2a0cf2020-10-13 12:48:21 -04001298 StatementArray caseStmts;
John Stiles92219b42020-06-15 12:32:24 -04001299
1300 // We can move over most of the statements as-is.
1301 while (startIter != iter) {
John Stiles2d4f9592020-10-30 10:29:12 -04001302 for (std::unique_ptr<Statement>& stmt : (*startIter)->statements()) {
John Stiles92219b42020-06-15 12:32:24 -04001303 caseStmts.push_back(std::move(stmt));
1304 }
1305 ++startIter;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001306 }
John Stiles92219b42020-06-15 12:32:24 -04001307
1308 // If we found an unconditional break at the end, we need to move what we can while avoiding
1309 // that break.
1310 if (unconditionalBreakStmt != nullptr) {
John Stiles2d4f9592020-10-30 10:29:12 -04001311 for (std::unique_ptr<Statement>& stmt : (*startIter)->statements()) {
John Stiles92219b42020-06-15 12:32:24 -04001312 if (stmt.get() == unconditionalBreakStmt) {
1313 move_all_but_break(stmt, &caseStmts);
1314 unconditionalBreakStmt = nullptr;
1315 break;
1316 }
1317
1318 caseStmts.push_back(std::move(stmt));
1319 }
1320 }
1321
1322 SkASSERT(unconditionalBreakStmt == nullptr); // Verify that we fixed the unconditional break.
1323
1324 // Return our newly-synthesized block.
Ethan Nicholas01b05e52020-10-22 15:53:41 -04001325 return std::make_unique<Block>(/*offset=*/-1, std::move(caseStmts), switchStatement->symbols());
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001326}
1327
Ethan Nicholascb670962017-04-20 19:31:52 -04001328void Compiler::simplifyStatement(DefinitionMap& definitions,
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001329 BasicBlock& b,
1330 std::vector<BasicBlock::Node>::iterator* iter,
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001331 OptimizationContext* optimizationContext) {
Brian Osman010ce6a2020-10-19 16:34:10 -04001332 ProgramUsage* usage = optimizationContext->fUsage;
Ethan Nicholascb670962017-04-20 19:31:52 -04001333 Statement* stmt = (*iter)->statement()->get();
Ethan Nicholase6592142020-09-08 10:22:09 -04001334 switch (stmt->kind()) {
1335 case Statement::Kind::kVarDeclaration: {
John Stilesa5a97b42020-08-18 11:19:07 -04001336 const auto& varDecl = stmt->as<VarDeclaration>();
Brian Osman010ce6a2020-10-19 16:34:10 -04001337 if (usage->isDead(varDecl.var()) &&
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04001338 (!varDecl.value() ||
1339 !varDecl.value()->hasSideEffects())) {
1340 if (varDecl.value()) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001341 SkASSERT((*iter)->statement()->get() == stmt);
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04001342 if (!b.tryRemoveExpressionBefore(iter, varDecl.value().get())) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001343 optimizationContext->fNeedsRescan = true;
Ethan Nicholascb670962017-04-20 19:31:52 -04001344 }
Ethan Nicholascb670962017-04-20 19:31:52 -04001345 }
Ethan Nicholas5b9b0db2021-01-21 13:12:01 -05001346 // There can still be (soon to be removed) references to the variable at this point.
1347 // Allowing the VarDeclaration to be destroyed here will break those variable's
1348 // initialValue()s, so we hang on to them until optimization is finished.
1349 std::unique_ptr<Statement> old = (*iter)->setStatement(std::make_unique<Nop>(),
1350 usage);
1351 optimizationContext->fOwnedStatements.push_back(std::move(old));
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001352 optimizationContext->fUpdated = true;
Ethan Nicholascb670962017-04-20 19:31:52 -04001353 }
1354 break;
1355 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001356 case Statement::Kind::kIf: {
John Stilesa5a97b42020-08-18 11:19:07 -04001357 IfStatement& i = stmt->as<IfStatement>();
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001358 if (i.test()->kind() == Expression::Kind::kBoolLiteral) {
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001359 // constant if, collapse down to a single branch
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001360 if (i.test()->as<BoolLiteral>().value()) {
1361 SkASSERT(i.ifTrue());
Brian Osman010ce6a2020-10-19 16:34:10 -04001362 (*iter)->setStatement(std::move(i.ifTrue()), usage);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001363 } else {
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001364 if (i.ifFalse()) {
Brian Osman010ce6a2020-10-19 16:34:10 -04001365 (*iter)->setStatement(std::move(i.ifFalse()), usage);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001366 } else {
Brian Osman010ce6a2020-10-19 16:34:10 -04001367 (*iter)->setStatement(std::make_unique<Nop>(), usage);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001368 }
1369 }
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001370 optimizationContext->fUpdated = true;
1371 optimizationContext->fNeedsRescan = true;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001372 break;
1373 }
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001374 if (i.ifFalse() && i.ifFalse()->isEmpty()) {
Ethan Nicholascb670962017-04-20 19:31:52 -04001375 // else block doesn't do anything, remove it
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001376 i.ifFalse().reset();
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001377 optimizationContext->fUpdated = true;
1378 optimizationContext->fNeedsRescan = true;
Ethan Nicholascb670962017-04-20 19:31:52 -04001379 }
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001380 if (!i.ifFalse() && i.ifTrue()->isEmpty()) {
Ethan Nicholascb670962017-04-20 19:31:52 -04001381 // if block doesn't do anything, no else block
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001382 if (i.test()->hasSideEffects()) {
Ethan Nicholascb670962017-04-20 19:31:52 -04001383 // test has side effects, keep it
Brian Osman010ce6a2020-10-19 16:34:10 -04001384 (*iter)->setStatement(
1385 std::make_unique<ExpressionStatement>(std::move(i.test())), usage);
Ethan Nicholascb670962017-04-20 19:31:52 -04001386 } else {
1387 // no if, no else, no test side effects, kill the whole if
1388 // statement
Brian Osman010ce6a2020-10-19 16:34:10 -04001389 (*iter)->setStatement(std::make_unique<Nop>(), usage);
Ethan Nicholascb670962017-04-20 19:31:52 -04001390 }
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001391 optimizationContext->fUpdated = true;
1392 optimizationContext->fNeedsRescan = true;
Ethan Nicholascb670962017-04-20 19:31:52 -04001393 }
1394 break;
1395 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001396 case Statement::Kind::kSwitch: {
John Stilesa5a97b42020-08-18 11:19:07 -04001397 SwitchStatement& s = stmt->as<SwitchStatement>();
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001398 int64_t switchValue;
Ethan Nicholasc0f98152021-02-05 16:21:10 -05001399 if (ConstantFolder::GetConstantInt(*s.value(), &switchValue)) {
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001400 // switch is constant, replace it with the case that matches
1401 bool found = false;
1402 SwitchCase* defaultCase = nullptr;
John Stiles2d4f9592020-10-30 10:29:12 -04001403 for (const std::unique_ptr<SwitchCase>& c : s.cases()) {
1404 if (!c->value()) {
1405 defaultCase = c.get();
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001406 continue;
1407 }
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001408 int64_t caseValue;
Ethan Nicholasc0f98152021-02-05 16:21:10 -05001409 SkAssertResult(ConstantFolder::GetConstantInt(*c->value(), &caseValue));
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001410 if (caseValue == switchValue) {
John Stiles2d4f9592020-10-30 10:29:12 -04001411 std::unique_ptr<Statement> newBlock = block_for_case(&s, c.get());
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001412 if (newBlock) {
Brian Osman010ce6a2020-10-19 16:34:10 -04001413 (*iter)->setStatement(std::move(newBlock), usage);
John Stiles9d944232020-08-19 09:56:49 -04001414 found = true;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001415 break;
1416 } else {
John Stilesd6a5f4492021-02-11 15:46:11 -05001417 if (s.isStatic() &&
1418 !fIRGenerator->fSettings->fPermitInvalidStaticTests) {
1419 auto [iter, didInsert] = optimizationContext->fSilences.insert(&s);
1420 if (didInsert) {
1421 this->error(s.fOffset, "static switch contains non-static "
1422 "conditional break");
1423 }
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001424 }
1425 return; // can't simplify
1426 }
1427 }
1428 }
1429 if (!found) {
1430 // no matching case. use default if it exists, or kill the whole thing
1431 if (defaultCase) {
1432 std::unique_ptr<Statement> newBlock = block_for_case(&s, defaultCase);
1433 if (newBlock) {
Brian Osman010ce6a2020-10-19 16:34:10 -04001434 (*iter)->setStatement(std::move(newBlock), usage);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001435 } else {
John Stilesd6a5f4492021-02-11 15:46:11 -05001436 if (s.isStatic() &&
1437 !fIRGenerator->fSettings->fPermitInvalidStaticTests) {
1438 auto [iter, didInsert] = optimizationContext->fSilences.insert(&s);
1439 if (didInsert) {
1440 this->error(s.fOffset, "static switch contains non-static "
1441 "conditional break");
1442 }
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001443 }
1444 return; // can't simplify
1445 }
1446 } else {
Brian Osman010ce6a2020-10-19 16:34:10 -04001447 (*iter)->setStatement(std::make_unique<Nop>(), usage);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001448 }
1449 }
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001450 optimizationContext->fUpdated = true;
1451 optimizationContext->fNeedsRescan = true;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001452 }
1453 break;
1454 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001455 case Statement::Kind::kExpression: {
John Stilesa5a97b42020-08-18 11:19:07 -04001456 ExpressionStatement& e = stmt->as<ExpressionStatement>();
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001457 SkASSERT((*iter)->statement()->get() == &e);
Ethan Nicholasd503a5a2020-09-30 09:29:55 -04001458 if (!e.expression()->hasSideEffects()) {
Ethan Nicholascb670962017-04-20 19:31:52 -04001459 // Expression statement with no side effects, kill it
Ethan Nicholasd503a5a2020-09-30 09:29:55 -04001460 if (!b.tryRemoveExpressionBefore(iter, e.expression().get())) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001461 optimizationContext->fNeedsRescan = true;
Ethan Nicholascb670962017-04-20 19:31:52 -04001462 }
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001463 SkASSERT((*iter)->statement()->get() == stmt);
Brian Osman010ce6a2020-10-19 16:34:10 -04001464 (*iter)->setStatement(std::make_unique<Nop>(), usage);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001465 optimizationContext->fUpdated = true;
Ethan Nicholascb670962017-04-20 19:31:52 -04001466 }
1467 break;
1468 }
1469 default:
1470 break;
1471 }
1472}
1473
Brian Osman010ce6a2020-10-19 16:34:10 -04001474bool Compiler::scanCFG(FunctionDefinition& f, ProgramUsage* usage) {
John Stiles0cc193a2020-09-09 09:39:34 -04001475 bool madeChanges = false;
1476
Ethan Nicholascb670962017-04-20 19:31:52 -04001477 CFG cfg = CFGGenerator().getCFG(f);
1478 this->computeDataFlow(&cfg);
ethannicholas22f939e2016-10-13 13:25:34 -07001479
1480 // check for unreachable code
1481 for (size_t i = 0; i < cfg.fBlocks.size(); i++) {
John Stiles0cc193a2020-09-09 09:39:34 -04001482 const BasicBlock& block = cfg.fBlocks[i];
John Stiles40525102020-12-16 18:10:44 -05001483 if (!block.fIsReachable && !block.fAllowUnreachable && block.fNodes.size()) {
John Stiles0cc193a2020-09-09 09:39:34 -04001484 const BasicBlock::Node& node = block.fNodes[0];
John Stilesc1129322021-02-03 10:13:42 -05001485 int offset = node.isStatement() ? (*node.statement())->fOffset
1486 : (*node.expression())->fOffset;
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001487 this->error(offset, String("unreachable"));
ethannicholas22f939e2016-10-13 13:25:34 -07001488 }
1489 }
1490 if (fErrorCount) {
John Stiles0cc193a2020-09-09 09:39:34 -04001491 return madeChanges;
ethannicholas22f939e2016-10-13 13:25:34 -07001492 }
1493
Ethan Nicholascb670962017-04-20 19:31:52 -04001494 // check for dead code & undefined variables, perform constant propagation
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001495 OptimizationContext optimizationContext;
Brian Osman010ce6a2020-10-19 16:34:10 -04001496 optimizationContext.fUsage = usage;
John Stiles7d3f0892020-11-03 11:35:01 -05001497 SkBitSet eliminatedBlockIds(cfg.fBlocks.size());
Ethan Nicholascb670962017-04-20 19:31:52 -04001498 do {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001499 if (optimizationContext.fNeedsRescan) {
Ethan Nicholascb670962017-04-20 19:31:52 -04001500 cfg = CFGGenerator().getCFG(f);
1501 this->computeDataFlow(&cfg);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001502 optimizationContext.fNeedsRescan = false;
Ethan Nicholas113628d2017-02-02 16:11:39 -05001503 }
Ethan Nicholascb670962017-04-20 19:31:52 -04001504
John Stiles7d3f0892020-11-03 11:35:01 -05001505 eliminatedBlockIds.reset();
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001506 optimizationContext.fUpdated = false;
John Stiles7d3f0892020-11-03 11:35:01 -05001507
1508 for (BlockId blockId = 0; blockId < cfg.fBlocks.size(); ++blockId) {
1509 if (eliminatedBlockIds.test(blockId)) {
1510 // We reached a block ID that might have been eliminated. Be cautious and rescan.
1511 optimizationContext.fUpdated = true;
1512 optimizationContext.fNeedsRescan = true;
1513 break;
1514 }
1515
1516 BasicBlock& b = cfg.fBlocks[blockId];
1517 if (blockId > 0 && !b.fIsReachable) {
Ethan Nicholas1de14812020-06-19 15:32:49 -04001518 // Block was reachable before optimization, but has since become unreachable. In
1519 // addition to being dead code, it's broken - since control flow can't reach it, no
1520 // prior variable definitions can reach it, and therefore variables might look to
Brian Osmanc0213602020-10-06 14:43:32 -04001521 // have not been properly assigned. Kill it by replacing all statements with Nops.
Ethan Nicholas1de14812020-06-19 15:32:49 -04001522 for (BasicBlock::Node& node : b.fNodes) {
John Stiles70025e52020-09-28 16:08:58 -04001523 if (node.isStatement() && !(*node.statement())->is<Nop>()) {
John Stiles7d3f0892020-11-03 11:35:01 -05001524 // Eliminating a node runs the risk of eliminating that node's exits as
1525 // well. Keep track of this and do a rescan if we are about to access one
1526 // of these.
1527 for (BlockId id : b.fExits) {
1528 eliminatedBlockIds.set(id);
1529 }
Brian Osman010ce6a2020-10-19 16:34:10 -04001530 node.setStatement(std::make_unique<Nop>(), usage);
John Stiles0cc193a2020-09-09 09:39:34 -04001531 madeChanges = true;
Ethan Nicholas1de14812020-06-19 15:32:49 -04001532 }
1533 }
1534 continue;
1535 }
Ethan Nicholascb670962017-04-20 19:31:52 -04001536 DefinitionMap definitions = b.fBefore;
1537
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001538 for (auto iter = b.fNodes.begin(); iter != b.fNodes.end() &&
1539 !optimizationContext.fNeedsRescan; ++iter) {
John Stiles70025e52020-09-28 16:08:58 -04001540 if (iter->isExpression()) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001541 this->simplifyExpression(definitions, b, &iter, &optimizationContext);
Ethan Nicholascb670962017-04-20 19:31:52 -04001542 } else {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001543 this->simplifyStatement(definitions, b, &iter, &optimizationContext);
Ethan Nicholascb670962017-04-20 19:31:52 -04001544 }
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001545 if (optimizationContext.fNeedsRescan) {
Ethan Nicholas4b330df2017-05-17 10:52:55 -04001546 break;
1547 }
John Stilese8a24922021-02-08 17:54:08 -05001548 definitions.addDefinitions(*fContext, *iter);
Ethan Nicholascb670962017-04-20 19:31:52 -04001549 }
Brian Osman01a3eb42020-09-14 11:32:49 -04001550
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001551 if (optimizationContext.fNeedsRescan) {
Brian Osman01a3eb42020-09-14 11:32:49 -04001552 break;
1553 }
Ethan Nicholascb670962017-04-20 19:31:52 -04001554 }
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001555 madeChanges |= optimizationContext.fUpdated;
1556 } while (optimizationContext.fUpdated);
1557 SkASSERT(!optimizationContext.fNeedsRescan);
ethannicholas22f939e2016-10-13 13:25:34 -07001558
1559 // check for missing return
John Stiles54e7c052021-01-11 14:22:36 -05001560 if (f.declaration().returnType() != *fContext->fTypes.fVoid) {
John Stiles61e75e32020-10-01 15:42:37 -04001561 if (cfg.fBlocks[cfg.fExit].fIsReachable) {
Ethan Nicholas0a5d0962020-10-14 13:33:18 -04001562 this->error(f.fOffset, String("function '" + String(f.declaration().name()) +
Ethan Nicholasdb80f692019-11-22 14:06:12 -05001563 "' can exit without returning a value"));
ethannicholas22f939e2016-10-13 13:25:34 -07001564 }
1565 }
John Stiles0cc193a2020-09-09 09:39:34 -04001566
1567 return madeChanges;
ethannicholas22f939e2016-10-13 13:25:34 -07001568}
1569
Brian Osman32d53552020-09-23 13:55:20 -04001570std::unique_ptr<Program> Compiler::convertProgram(
John Stilesdbd4e6f2021-02-16 13:29:15 -05001571 ProgramKind kind,
Brian Osman32d53552020-09-23 13:55:20 -04001572 String text,
1573 const Program::Settings& settings,
Brian Osmanbe0b3b72021-01-06 14:27:35 -05001574 const std::vector<std::unique_ptr<ExternalFunction>>* externalFunctions) {
Leon Scrogginsb66214e2021-02-11 17:14:18 -05001575 ATRACE_ANDROID_FRAMEWORK("SkSL::Compiler::convertProgram");
1576
John Stilesdbd4e6f2021-02-16 13:29:15 -05001577 SkASSERT(!externalFunctions || (kind == ProgramKind::kGeneric));
Ethan Nicholas91164d12019-05-15 15:29:54 -04001578
Brian Osman0006ad02020-11-18 15:38:39 -05001579 // Loading and optimizing our base module might reset the inliner, so do that first,
1580 // *then* configure the inliner with the settings for this program.
1581 const ParsedModule& baseModule = this->moduleForProgramKind(kind);
1582
John Stiles270cec22021-02-17 12:59:36 -05001583 // Update our context to point to the program configuration for the duration of compilation.
1584 auto config = std::make_unique<ProgramConfig>(ProgramConfig{kind, settings});
1585
1586 SkASSERT(!fContext->fConfig);
1587 fContext->fConfig = config.get();
1588 SK_AT_SCOPE_EXIT(fContext->fConfig = nullptr);
1589
ethannicholasb3058bd2016-07-01 08:22:01 -07001590 fErrorText = "";
1591 fErrorCount = 0;
John Stiles270cec22021-02-17 12:59:36 -05001592 fInliner.reset(fIRGenerator->fModifiers.get(), &config->fSettings);
Brian Osman88cda172020-10-09 12:05:16 -04001593
1594 // Not using AutoSource, because caller is likely to call errorText() if we fail to compile
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001595 std::unique_ptr<String> textPtr(new String(std::move(text)));
1596 fSource = textPtr.get();
Brian Osman88cda172020-10-09 12:05:16 -04001597
John Stiles5c7bb322020-10-22 11:09:15 -04001598 // Enable node pooling while converting and optimizing the program for a performance boost.
1599 // The Program will take ownership of the pool.
Brian Osman28f702c2021-02-02 11:52:07 -05001600 std::unique_ptr<Pool> pool;
1601 if (fCaps->useNodePools()) {
1602 pool = Pool::Create();
1603 pool->attachToThread();
1604 }
Brian Osman0006ad02020-11-18 15:38:39 -05001605 IRGenerator::IRBundle ir =
1606 fIRGenerator->convertProgram(kind, &settings, baseModule, /*isBuiltinCode=*/false,
Brian Osmanbe0b3b72021-01-06 14:27:35 -05001607 textPtr->c_str(), textPtr->size(), externalFunctions);
John Stiles270cec22021-02-17 12:59:36 -05001608 auto program = std::make_unique<Program>(std::move(textPtr),
1609 std::move(config),
Brian Osmand7e76592020-11-02 12:26:22 -05001610 fCaps,
John Stiles5c7bb322020-10-22 11:09:15 -04001611 fContext,
1612 std::move(ir.fElements),
Brian Osman133724c2020-10-28 14:14:39 -04001613 std::move(ir.fSharedElements),
John Stiles5c7bb322020-10-22 11:09:15 -04001614 std::move(ir.fModifiers),
1615 std::move(ir.fSymbolTable),
1616 std::move(pool),
1617 ir.fInputs);
1618 bool success = false;
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001619 if (fErrorCount) {
John Stiles5c7bb322020-10-22 11:09:15 -04001620 // Do not return programs that failed to compile.
Brian Osman4f065e22021-02-13 01:06:03 +00001621 } else if (settings.fOptimize && !this->optimize(*program)) {
John Stiles5c7bb322020-10-22 11:09:15 -04001622 // Do not return programs that failed to optimize.
1623 } else {
1624 // We have a successful program!
1625 success = true;
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001626 }
John Stiles5c7bb322020-10-22 11:09:15 -04001627
Brian Osman28f702c2021-02-02 11:52:07 -05001628 if (program->fPool) {
1629 program->fPool->detachFromThread();
1630 }
John Stiles5c7bb322020-10-22 11:09:15 -04001631 return success ? std::move(program) : nullptr;
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001632}
1633
John Stilesbb1505f2021-02-12 09:17:53 -05001634void Compiler::verifyStaticTests(const Program& program) {
1635 class StaticTestVerifier : public ProgramVisitor {
1636 public:
1637 StaticTestVerifier(ErrorReporter* r) : fReporter(r) {}
1638
1639 using ProgramVisitor::visitProgramElement;
1640
1641 bool visitStatement(const Statement& stmt) override {
1642 switch (stmt.kind()) {
1643 case Statement::Kind::kIf:
1644 if (stmt.as<IfStatement>().isStatic()) {
1645 fReporter->error(stmt.fOffset, "static if has non-static test");
1646 }
1647 break;
1648
1649 case Statement::Kind::kSwitch:
1650 if (stmt.as<SwitchStatement>().isStatic()) {
1651 fReporter->error(stmt.fOffset, "static switch has non-static test");
1652 }
1653 break;
1654
1655 default:
1656 break;
1657 }
1658 return INHERITED::visitStatement(stmt);
1659 }
1660
John Stiles59e34562021-02-12 16:56:39 -05001661 bool visitExpression(const Expression&) override {
1662 // We aren't looking for anything inside an Expression, so skip them entirely.
1663 return false;
1664 }
1665
John Stilesbb1505f2021-02-12 09:17:53 -05001666 private:
1667 using INHERITED = ProgramVisitor;
1668 ErrorReporter* fReporter;
1669 };
1670
1671 // If invalid static tests are permitted, we don't need to check anything.
1672 if (fIRGenerator->fSettings->fPermitInvalidStaticTests) {
1673 return;
1674 }
1675
1676 // Check all of the program's owned elements. (Built-in elements are assumed to be valid.)
1677 StaticTestVerifier visitor{this};
1678 for (const std::unique_ptr<ProgramElement>& element : program.ownedElements()) {
1679 if (element->is<FunctionDefinition>()) {
1680 visitor.visitProgramElement(*element);
1681 }
1682 }
1683}
1684
Brian Osman0006ad02020-11-18 15:38:39 -05001685bool Compiler::optimize(LoadedModule& module) {
1686 SkASSERT(!fErrorCount);
Brian Osman0006ad02020-11-18 15:38:39 -05001687
John Stiles270cec22021-02-17 12:59:36 -05001688 // Create a temporary program configuration with default settings.
1689 ProgramConfig config;
1690 config.fKind = module.fKind;
1691
1692 // Update our context to point to this configuration for the duration of compilation.
1693 SkASSERT(!fContext->fConfig);
1694 fContext->fConfig = &config;
1695 SK_AT_SCOPE_EXIT(fContext->fConfig = nullptr);
1696
1697 // Set this configuration in the IR Generator and Inliner.
1698 fIRGenerator->fKind = config.fKind;
1699 fIRGenerator->fSettings = &config.fSettings;
1700 fInliner.reset(fModifiers.back().get(), &config.fSettings);
1701
1702 std::unique_ptr<ProgramUsage> usage = Analysis::GetUsage(module);
Brian Osman0006ad02020-11-18 15:38:39 -05001703
1704 while (fErrorCount == 0) {
1705 bool madeChanges = false;
1706
1707 // Scan and optimize based on the control-flow graph for each function.
1708 for (const auto& element : module.fElements) {
1709 if (element->is<FunctionDefinition>()) {
1710 madeChanges |= this->scanCFG(element->as<FunctionDefinition>(), usage.get());
1711 }
1712 }
1713
1714 // Perform inline-candidate analysis and inline any functions deemed suitable.
John Stiles78047582020-12-16 16:17:41 -05001715 madeChanges |= fInliner.analyze(module.fElements, module.fSymbols, usage.get());
Brian Osman0006ad02020-11-18 15:38:39 -05001716
1717 if (!madeChanges) {
1718 break;
1719 }
1720 }
1721 return fErrorCount == 0;
1722}
1723
Ethan Nicholas00543112018-07-31 09:44:36 -04001724bool Compiler::optimize(Program& program) {
1725 SkASSERT(!fErrorCount);
John Stiles270cec22021-02-17 12:59:36 -05001726 fIRGenerator->fKind = program.fConfig->fKind;
1727 fIRGenerator->fSettings = &program.fConfig->fSettings;
Brian Osman010ce6a2020-10-19 16:34:10 -04001728 ProgramUsage* usage = program.fUsage.get();
John Stiles7954d6c2020-09-01 10:53:02 -04001729
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001730 while (fErrorCount == 0) {
1731 bool madeChanges = false;
John Stiles7954d6c2020-09-01 10:53:02 -04001732
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001733 // Scan and optimize based on the control-flow graph for each function.
Brian Osman133724c2020-10-28 14:14:39 -04001734 for (const auto& element : program.ownedElements()) {
Brian Osman1179fcf2020-10-08 16:04:40 -04001735 if (element->is<FunctionDefinition>()) {
Brian Osman010ce6a2020-10-19 16:34:10 -04001736 madeChanges |= this->scanCFG(element->as<FunctionDefinition>(), usage);
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001737 }
1738 }
1739
1740 // Perform inline-candidate analysis and inline any functions deemed suitable.
John Stiles78047582020-12-16 16:17:41 -05001741 madeChanges |= fInliner.analyze(program.ownedElements(), program.fSymbols, usage);
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001742
1743 // Remove dead functions. We wait until after analysis so that we still report errors,
1744 // even in unused code.
John Stiles270cec22021-02-17 12:59:36 -05001745 if (program.fConfig->fSettings.fRemoveDeadFunctions) {
Brian Osman133724c2020-10-28 14:14:39 -04001746 auto isDeadFunction = [&](const ProgramElement* element) {
1747 if (!element->is<FunctionDefinition>()) {
1748 return false;
1749 }
1750 const FunctionDefinition& fn = element->as<FunctionDefinition>();
1751 if (fn.declaration().name() != "main" && usage->get(fn.declaration()) == 0) {
1752 usage->remove(*element);
1753 madeChanges = true;
1754 return true;
1755 }
1756 return false;
1757 };
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001758 program.fElements.erase(
Brian Osman133724c2020-10-28 14:14:39 -04001759 std::remove_if(program.fElements.begin(), program.fElements.end(),
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001760 [&](const std::unique_ptr<ProgramElement>& element) {
Brian Osman133724c2020-10-28 14:14:39 -04001761 return isDeadFunction(element.get());
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001762 }),
1763 program.fElements.end());
Brian Osman133724c2020-10-28 14:14:39 -04001764 program.fSharedElements.erase(
1765 std::remove_if(program.fSharedElements.begin(), program.fSharedElements.end(),
1766 isDeadFunction),
1767 program.fSharedElements.end());
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001768 }
1769
John Stiles270cec22021-02-17 12:59:36 -05001770 if (program.fConfig->fKind != ProgramKind::kFragmentProcessor) {
Brian Osmanc0213602020-10-06 14:43:32 -04001771 // Remove declarations of dead global variables
Brian Osman133724c2020-10-28 14:14:39 -04001772 auto isDeadVariable = [&](const ProgramElement* element) {
1773 if (!element->is<GlobalVarDeclaration>()) {
1774 return false;
1775 }
1776 const GlobalVarDeclaration& global = element->as<GlobalVarDeclaration>();
1777 const VarDeclaration& varDecl = global.declaration()->as<VarDeclaration>();
1778 if (usage->isDead(varDecl.var())) {
1779 madeChanges = true;
1780 return true;
1781 }
1782 return false;
1783 };
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001784 program.fElements.erase(
1785 std::remove_if(program.fElements.begin(), program.fElements.end(),
1786 [&](const std::unique_ptr<ProgramElement>& element) {
Brian Osman133724c2020-10-28 14:14:39 -04001787 return isDeadVariable(element.get());
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001788 }),
1789 program.fElements.end());
Brian Osman133724c2020-10-28 14:14:39 -04001790 program.fSharedElements.erase(
1791 std::remove_if(program.fSharedElements.begin(), program.fSharedElements.end(),
1792 isDeadVariable),
1793 program.fSharedElements.end());
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001794 }
John Stiles73a6bff2020-09-09 13:40:37 -04001795
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001796 if (!madeChanges) {
1797 break;
Ethan Nicholas0dc80872019-02-08 15:46:24 -05001798 }
Ethan Nicholas00543112018-07-31 09:44:36 -04001799 }
John Stilesbb1505f2021-02-12 09:17:53 -05001800
1801 if (fErrorCount == 0) {
1802 this->verifyStaticTests(program);
1803 }
1804
Ethan Nicholas00543112018-07-31 09:44:36 -04001805 return fErrorCount == 0;
1806}
1807
Brian Osmanfb32ddf2019-06-18 10:14:20 -04001808#if defined(SKSL_STANDALONE) || SK_SUPPORT_GPU
1809
Ethan Nicholas00543112018-07-31 09:44:36 -04001810bool Compiler::toSPIRV(Program& program, OutputStream& out) {
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001811#ifdef SK_ENABLE_SPIRV_VALIDATION
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001812 StringStream buffer;
Brian Osman88cda172020-10-09 12:05:16 -04001813 AutoSource as(this, program.fSource.get());
Brian Osman8b43dad2020-10-09 13:31:42 -04001814 SPIRVCodeGenerator cg(fContext.get(), &program, this, &buffer);
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001815 bool result = cg.generateCode();
John Stiles270cec22021-02-17 12:59:36 -05001816 if (result && program.fConfig->fSettings.fValidateSPIRV) {
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001817 spvtools::SpirvTools tools(SPV_ENV_VULKAN_1_0);
Ethan Nicholas762466e2017-06-29 10:03:38 -04001818 const String& data = buffer.str();
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001819 SkASSERT(0 == data.size() % 4);
Brian Osman8d09d4a2020-11-24 15:51:06 -05001820 String errors;
1821 auto dumpmsg = [&errors](spv_message_level_t, const char*, const spv_position_t&,
1822 const char* m) {
1823 errors.appendf("SPIR-V validation error: %s\n", m);
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001824 };
1825 tools.SetMessageConsumer(dumpmsg);
Brian Osman8d09d4a2020-11-24 15:51:06 -05001826
1827 // Verify that the SPIR-V we produced is valid. At runtime, we will abort() with a message
1828 // explaining the error. In standalone mode (skslc), we will send the message, plus the
1829 // entire disassembled SPIR-V (for easier context & debugging) as *our* error message.
1830 result = tools.Validate((const uint32_t*) data.c_str(), data.size() / 4);
1831
1832 if (!result) {
1833#if defined(SKSL_STANDALONE)
1834 // Convert the string-stream to a SPIR-V disassembly.
1835 std::string disassembly;
1836 if (tools.Disassemble((const uint32_t*)data.data(), data.size() / 4, &disassembly)) {
1837 errors.append(disassembly);
1838 }
1839 this->error(-1, errors);
1840#else
1841 SkDEBUGFAILF("%s", errors.c_str());
1842#endif
1843 }
Ethan Nicholas762466e2017-06-29 10:03:38 -04001844 out.write(data.c_str(), data.size());
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001845 }
1846#else
Brian Osman88cda172020-10-09 12:05:16 -04001847 AutoSource as(this, program.fSource.get());
Brian Osman8b43dad2020-10-09 13:31:42 -04001848 SPIRVCodeGenerator cg(fContext.get(), &program, this, &out);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001849 bool result = cg.generateCode();
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001850#endif
Ethan Nicholasce33f102016-12-09 17:22:59 -05001851 return result;
1852}
1853
Ethan Nicholas00543112018-07-31 09:44:36 -04001854bool Compiler::toSPIRV(Program& program, String* out) {
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001855 StringStream buffer;
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001856 bool result = this->toSPIRV(program, buffer);
1857 if (result) {
Ethan Nicholas762466e2017-06-29 10:03:38 -04001858 *out = buffer.str();
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001859 }
1860 return result;
1861}
1862
Ethan Nicholas00543112018-07-31 09:44:36 -04001863bool Compiler::toGLSL(Program& program, OutputStream& out) {
Leon Scrogginsb66214e2021-02-11 17:14:18 -05001864 ATRACE_ANDROID_FRAMEWORK("SkSL::Compiler::toGLSL");
Brian Osman88cda172020-10-09 12:05:16 -04001865 AutoSource as(this, program.fSource.get());
Ethan Nicholas26a9aad2018-03-27 14:10:52 -04001866 GLSLCodeGenerator cg(fContext.get(), &program, this, &out);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001867 bool result = cg.generateCode();
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001868 return result;
1869}
1870
Ethan Nicholas00543112018-07-31 09:44:36 -04001871bool Compiler::toGLSL(Program& program, String* out) {
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001872 StringStream buffer;
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001873 bool result = this->toGLSL(program, buffer);
1874 if (result) {
Ethan Nicholas762466e2017-06-29 10:03:38 -04001875 *out = buffer.str();
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001876 }
1877 return result;
1878}
1879
Brian Osmanc0243912020-02-19 15:35:26 -05001880bool Compiler::toHLSL(Program& program, String* out) {
1881 String spirv;
1882 if (!this->toSPIRV(program, &spirv)) {
1883 return false;
1884 }
1885
1886 return SPIRVtoHLSL(spirv, out);
1887}
1888
Ethan Nicholas00543112018-07-31 09:44:36 -04001889bool Compiler::toMetal(Program& program, OutputStream& out) {
Ethan Nicholas26a9aad2018-03-27 14:10:52 -04001890 MetalCodeGenerator cg(fContext.get(), &program, this, &out);
Ethan Nicholascc305772017-10-13 16:17:45 -04001891 bool result = cg.generateCode();
Ethan Nicholascc305772017-10-13 16:17:45 -04001892 return result;
1893}
1894
Ethan Nicholas00543112018-07-31 09:44:36 -04001895bool Compiler::toMetal(Program& program, String* out) {
Timothy Liangb8eeb802018-07-23 16:46:16 -04001896 StringStream buffer;
1897 bool result = this->toMetal(program, buffer);
1898 if (result) {
1899 *out = buffer.str();
1900 }
1901 return result;
1902}
1903
Greg Daniela28ea672020-09-25 11:12:56 -04001904#if defined(SKSL_STANDALONE) || GR_TEST_UTILS
Ethan Nicholas00543112018-07-31 09:44:36 -04001905bool Compiler::toCPP(Program& program, String name, OutputStream& out) {
Brian Osman88cda172020-10-09 12:05:16 -04001906 AutoSource as(this, program.fSource.get());
Ethan Nicholas26a9aad2018-03-27 14:10:52 -04001907 CPPCodeGenerator cg(fContext.get(), &program, this, name, &out);
Ethan Nicholas762466e2017-06-29 10:03:38 -04001908 bool result = cg.generateCode();
Ethan Nicholas762466e2017-06-29 10:03:38 -04001909 return result;
1910}
1911
Ethan Nicholas00543112018-07-31 09:44:36 -04001912bool Compiler::toH(Program& program, String name, OutputStream& out) {
Brian Osman88cda172020-10-09 12:05:16 -04001913 AutoSource as(this, program.fSource.get());
Ethan Nicholas26a9aad2018-03-27 14:10:52 -04001914 HCodeGenerator cg(fContext.get(), &program, this, name, &out);
Ethan Nicholas762466e2017-06-29 10:03:38 -04001915 bool result = cg.generateCode();
Ethan Nicholas00543112018-07-31 09:44:36 -04001916 return result;
1917}
Greg Daniela28ea672020-09-25 11:12:56 -04001918#endif // defined(SKSL_STANDALONE) || GR_TEST_UTILS
Ethan Nicholas00543112018-07-31 09:44:36 -04001919
Ethan Nicholas2a479a52020-08-18 16:29:45 -04001920#endif // defined(SKSL_STANDALONE) || SK_SUPPORT_GPU
Brian Osman2e29ab52019-09-20 12:19:11 -04001921
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001922Position Compiler::position(int offset) {
Ethan Nicholas3c729892020-12-07 12:47:17 -05001923 if (fSource && offset >= 0) {
1924 int line = 1;
1925 int column = 1;
1926 for (int i = 0; i < offset; i++) {
1927 if ((*fSource)[i] == '\n') {
1928 ++line;
1929 column = 1;
1930 }
1931 else {
1932 ++column;
1933 }
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001934 }
Ethan Nicholas3c729892020-12-07 12:47:17 -05001935 return Position(line, column);
1936 } else {
1937 return Position(-1, -1);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001938 }
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001939}
1940
1941void Compiler::error(int offset, String msg) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001942 fErrorCount++;
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001943 Position pos = this->position(offset);
John Stiles8d3642e2021-01-22 09:50:04 -05001944 fErrorTextLength.push_back(fErrorText.length());
Ethan Nicholas3c729892020-12-07 12:47:17 -05001945 fErrorText += "error: " + (pos.fLine >= 1 ? to_string(pos.fLine) + ": " : "") + msg + "\n";
ethannicholasb3058bd2016-07-01 08:22:01 -07001946}
1947
John Stiles8d3642e2021-01-22 09:50:04 -05001948void Compiler::setErrorCount(int c) {
1949 if (c < fErrorCount) {
1950 fErrorText.resize(fErrorTextLength[c]);
1951 fErrorTextLength.resize(c);
1952 fErrorCount = c;
1953 }
1954}
1955
Ethan Nicholas95046142021-01-07 10:57:27 -05001956String Compiler::errorText(bool showCount) {
1957 if (showCount) {
1958 this->writeErrorCount();
1959 }
Ethan Nicholas00543112018-07-31 09:44:36 -04001960 fErrorCount = 0;
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001961 String result = fErrorText;
Ethan Nicholas95046142021-01-07 10:57:27 -05001962 fErrorText = "";
ethannicholasb3058bd2016-07-01 08:22:01 -07001963 return result;
1964}
1965
1966void Compiler::writeErrorCount() {
1967 if (fErrorCount) {
1968 fErrorText += to_string(fErrorCount) + " error";
1969 if (fErrorCount > 1) {
1970 fErrorText += "s";
1971 }
1972 fErrorText += "\n";
1973 }
1974}
1975
John Stilesa6841be2020-08-06 14:11:56 -04001976} // namespace SkSL