blob: 68226e2eec79633a6b62ff43407c474d3e3c853e [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);
John Stilesd1204642021-02-17 16:30:02 -0500283
John Stiles881a10c2020-09-19 10:13:24 -0400284 SkASSERT(fIRGenerator->fCanInline);
285 fIRGenerator->fCanInline = false;
John Stilesd1204642021-02-17 16:30:02 -0500286
287 ProgramConfig config;
288 config.fKind = kind;
289 config.fSettings.fReplaceSettings = false;
290
291 fContext->fConfig = &config;
292 SK_AT_SCOPE_EXIT(fContext->fConfig = nullptr);
John Stilesdbd4e6f2021-02-16 13:29:15 -0500293
Brian Osman88cda172020-10-09 12:05:16 -0400294 ParsedModule baseModule = {base, /*fIntrinsics=*/nullptr};
John Stilesd1204642021-02-17 16:30:02 -0500295 IRGenerator::IRBundle ir = fIRGenerator->convertProgram(baseModule, /*isBuiltinCode=*/true,
296 source->c_str(), source->length(),
297 /*externalFunctions=*/nullptr);
Brian Osman133724c2020-10-28 14:14:39 -0400298 SkASSERT(ir.fSharedElements.empty());
Brian Osman0006ad02020-11-18 15:38:39 -0500299 LoadedModule module = { kind, std::move(ir.fSymbolTable), std::move(ir.fElements) };
John Stiles881a10c2020-09-19 10:13:24 -0400300 fIRGenerator->fCanInline = true;
Ethan Nicholas8da1e652019-05-24 11:01:59 -0400301 if (this->fErrorCount) {
302 printf("Unexpected errors: %s\n", this->fErrorText.c_str());
Brian Osman3d87e9f2020-10-08 11:50:22 -0400303 SkDEBUGFAILF("%s %s\n", data.fPath, this->fErrorText.c_str());
Ethan Nicholas8da1e652019-05-24 11:01:59 -0400304 }
Brian Osman88cda172020-10-09 12:05:16 -0400305 fModifiers.push_back(std::move(ir.fModifiers));
Brian Osman3d87e9f2020-10-08 11:50:22 -0400306#else
307 SkASSERT(data.fData && (data.fSize != 0));
308 Rehydrator rehydrator(fContext.get(), fIRGenerator->fModifiers.get(), base, this,
309 data.fData, data.fSize);
Brian Osman0006ad02020-11-18 15:38:39 -0500310 LoadedModule module = { kind, rehydrator.symbolTable(), rehydrator.elements() };
Brian Osman3d87e9f2020-10-08 11:50:22 -0400311 fModifiers.push_back(fIRGenerator->releaseModifiers());
312#endif
313
314 return module;
315}
316
John Stilesdbd4e6f2021-02-16 13:29:15 -0500317ParsedModule Compiler::parseModule(ProgramKind kind, ModuleData data, const ParsedModule& base) {
Brian Osman0006ad02020-11-18 15:38:39 -0500318 LoadedModule module = this->loadModule(kind, data, base.fSymbols);
319 this->optimize(module);
Brian Osman3d87e9f2020-10-08 11:50:22 -0400320
321 // For modules that just declare (but don't define) intrinsic functions, there will be no new
322 // program elements. In that case, we can share our parent's intrinsic map:
Brian Osman0006ad02020-11-18 15:38:39 -0500323 if (module.fElements.empty()) {
324 return {module.fSymbols, base.fIntrinsics};
Brian Osman3d87e9f2020-10-08 11:50:22 -0400325 }
326
327 auto intrinsics = std::make_shared<IRIntrinsicMap>(base.fIntrinsics.get());
328
329 // Now, transfer all of the program elements to an intrinsic map. This maps certain types of
330 // global objects to the declaring ProgramElement.
Brian Osman0006ad02020-11-18 15:38:39 -0500331 for (std::unique_ptr<ProgramElement>& element : module.fElements) {
Brian Osman3d87e9f2020-10-08 11:50:22 -0400332 switch (element->kind()) {
333 case ProgramElement::Kind::kFunction: {
334 const FunctionDefinition& f = element->as<FunctionDefinition>();
Ethan Nicholas0a5d0962020-10-14 13:33:18 -0400335 SkASSERT(f.declaration().isBuiltin());
336 intrinsics->insertOrDie(f.declaration().description(), std::move(element));
Brian Osman3d87e9f2020-10-08 11:50:22 -0400337 break;
338 }
John Stiles569249b2020-11-03 12:18:22 -0500339 case ProgramElement::Kind::kFunctionPrototype: {
340 // These are already in the symbol table.
341 break;
342 }
Brian Osman3d87e9f2020-10-08 11:50:22 -0400343 case ProgramElement::Kind::kEnum: {
344 const Enum& e = element->as<Enum>();
345 SkASSERT(e.isBuiltin());
346 intrinsics->insertOrDie(e.typeName(), std::move(element));
347 break;
348 }
349 case ProgramElement::Kind::kGlobalVar: {
Ethan Nicholasc51f33e2020-10-13 13:49:44 -0400350 const GlobalVarDeclaration& global = element->as<GlobalVarDeclaration>();
351 const Variable& var = global.declaration()->as<VarDeclaration>().var();
352 SkASSERT(var.isBuiltin());
353 intrinsics->insertOrDie(var.name(), std::move(element));
Brian Osman3d87e9f2020-10-08 11:50:22 -0400354 break;
355 }
356 case ProgramElement::Kind::kInterfaceBlock: {
Ethan Nicholaseaf47882020-10-15 10:10:08 -0400357 const Variable& var = element->as<InterfaceBlock>().variable();
358 SkASSERT(var.isBuiltin());
359 intrinsics->insertOrDie(var.name(), std::move(element));
Brian Osman3d87e9f2020-10-08 11:50:22 -0400360 break;
361 }
362 default:
363 printf("Unsupported element: %s\n", element->description().c_str());
364 SkASSERT(false);
365 break;
366 }
367 }
368
Brian Osman0006ad02020-11-18 15:38:39 -0500369 return {module.fSymbols, std::move(intrinsics)};
Ethan Nicholas8da1e652019-05-24 11:01:59 -0400370}
371
John Stilese6150002020-10-05 12:03:53 -0400372void Compiler::scanCFG(CFG* cfg, BlockId blockId, SkBitSet* processedSet) {
ethannicholas22f939e2016-10-13 13:25:34 -0700373 BasicBlock& block = cfg->fBlocks[blockId];
374
375 // compute definitions after this block
Ethan Nicholas86a43402017-01-19 13:32:00 -0500376 DefinitionMap after = block.fBefore;
ethannicholas22f939e2016-10-13 13:25:34 -0700377 for (const BasicBlock::Node& n : block.fNodes) {
John Stilese8a24922021-02-08 17:54:08 -0500378 after.addDefinitions(*fContext, n);
ethannicholas22f939e2016-10-13 13:25:34 -0700379 }
380
381 // propagate definitions to exits
382 for (BlockId exitId : block.fExits) {
Ethan Nicholas26a9aad2018-03-27 14:10:52 -0400383 if (exitId == blockId) {
384 continue;
385 }
ethannicholas22f939e2016-10-13 13:25:34 -0700386 BasicBlock& exit = cfg->fBlocks[exitId];
John Stiles65b48272020-12-22 17:18:34 -0500387 for (const auto& [var, e1] : after) {
John Stiles796cdb72020-10-08 12:06:53 -0400388 std::unique_ptr<Expression>** exitDef = exit.fBefore.find(var);
389 if (!exitDef) {
John Stilese6150002020-10-05 12:03:53 -0400390 // exit has no definition for it, just copy it and reprocess exit block
391 processedSet->reset(exitId);
John Stilese8a24922021-02-08 17:54:08 -0500392 exit.fBefore.set(var, e1);
ethannicholas22f939e2016-10-13 13:25:34 -0700393 } else {
Ethan Nicholas86a43402017-01-19 13:32:00 -0500394 // exit has a (possibly different) value already defined
John Stiles796cdb72020-10-08 12:06:53 -0400395 std::unique_ptr<Expression>* e2 = *exitDef;
ethannicholas22f939e2016-10-13 13:25:34 -0700396 if (e1 != e2) {
John Stilese6150002020-10-05 12:03:53 -0400397 // definition has changed, merge and reprocess the exit block
398 processedSet->reset(exitId);
Ethan Nicholasaf197692017-02-27 13:26:45 -0500399 if (e1 && e2) {
John Stiles796cdb72020-10-08 12:06:53 -0400400 *exitDef = (std::unique_ptr<Expression>*)&fContext->fDefined_Expression;
Ethan Nicholasaf197692017-02-27 13:26:45 -0500401 } else {
John Stiles796cdb72020-10-08 12:06:53 -0400402 *exitDef = nullptr;
Ethan Nicholasaf197692017-02-27 13:26:45 -0500403 }
ethannicholas22f939e2016-10-13 13:25:34 -0700404 }
405 }
John Stiles65b48272020-12-22 17:18:34 -0500406 }
ethannicholas22f939e2016-10-13 13:25:34 -0700407 }
408}
409
Ethan Nicholascb670962017-04-20 19:31:52 -0400410/**
411 * Returns true if assigning to this lvalue has no effect.
412 */
Brian Osman010ce6a2020-10-19 16:34:10 -0400413static bool is_dead(const Expression& lvalue, ProgramUsage* usage) {
Ethan Nicholase6592142020-09-08 10:22:09 -0400414 switch (lvalue.kind()) {
415 case Expression::Kind::kVariableReference:
Brian Osman010ce6a2020-10-19 16:34:10 -0400416 return usage->isDead(*lvalue.as<VariableReference>().variable());
Ethan Nicholase6592142020-09-08 10:22:09 -0400417 case Expression::Kind::kSwizzle:
Brian Osman010ce6a2020-10-19 16:34:10 -0400418 return is_dead(*lvalue.as<Swizzle>().base(), usage);
Ethan Nicholase6592142020-09-08 10:22:09 -0400419 case Expression::Kind::kFieldAccess:
Brian Osman010ce6a2020-10-19 16:34:10 -0400420 return is_dead(*lvalue.as<FieldAccess>().base(), usage);
Ethan Nicholase6592142020-09-08 10:22:09 -0400421 case Expression::Kind::kIndex: {
John Stilesa5a97b42020-08-18 11:19:07 -0400422 const IndexExpression& idx = lvalue.as<IndexExpression>();
Brian Osman010ce6a2020-10-19 16:34:10 -0400423 return is_dead(*idx.base(), usage) &&
Ethan Nicholas2a4952d2020-10-08 15:35:56 -0400424 !idx.index()->hasProperty(Expression::Property::kSideEffects);
Ethan Nicholascb670962017-04-20 19:31:52 -0400425 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400426 case Expression::Kind::kTernary: {
John Stilesa5a97b42020-08-18 11:19:07 -0400427 const TernaryExpression& t = lvalue.as<TernaryExpression>();
Brian Osman010ce6a2020-10-19 16:34:10 -0400428 return !t.test()->hasSideEffects() &&
429 is_dead(*t.ifTrue(), usage) &&
430 is_dead(*t.ifFalse(), usage);
Ethan Nicholasa583b812018-01-18 13:32:11 -0500431 }
Ethan Nicholascb670962017-04-20 19:31:52 -0400432 default:
John Stileseada7bc2021-02-02 16:29:32 -0500433 SkDEBUGFAILF("invalid lvalue: %s\n", lvalue.description().c_str());
Ethan Nicholas2a099da2020-01-02 14:40:54 -0500434 return false;
Ethan Nicholascb670962017-04-20 19:31:52 -0400435 }
436}
ethannicholas22f939e2016-10-13 13:25:34 -0700437
Ethan Nicholascb670962017-04-20 19:31:52 -0400438/**
439 * Returns true if this is an assignment which can be collapsed down to just the right hand side due
440 * to a dead target and lack of side effects on the left hand side.
441 */
Brian Osman010ce6a2020-10-19 16:34:10 -0400442static bool dead_assignment(const BinaryExpression& b, ProgramUsage* usage) {
John Stiles45990502021-02-16 10:55:27 -0500443 if (!b.getOperator().isAssignment()) {
Ethan Nicholascb670962017-04-20 19:31:52 -0400444 return false;
445 }
John Stiles2d4f9592020-10-30 10:29:12 -0400446 return is_dead(*b.left(), usage);
Ethan Nicholascb670962017-04-20 19:31:52 -0400447}
448
John Stiles0ac6c152021-02-10 14:04:24 -0500449/**
450 * Returns true if both expression trees are the same. The left side is expected to be an lvalue.
451 * This only needs to check for trees that can plausibly terminate in a variable, so some basic
452 * candidates like `FloatLiteral` are missing.
453 */
454static bool is_matching_expression_tree(const Expression& left, const Expression& right) {
455 if (left.kind() != right.kind() || left.type() != right.type()) {
456 return false;
457 }
458
459 switch (left.kind()) {
460 case Expression::Kind::kIntLiteral:
461 return left.as<IntLiteral>().value() == right.as<IntLiteral>().value();
462
463 case Expression::Kind::kFieldAccess:
464 return left.as<FieldAccess>().fieldIndex() == right.as<FieldAccess>().fieldIndex() &&
465 is_matching_expression_tree(*left.as<FieldAccess>().base(),
466 *right.as<FieldAccess>().base());
467
468 case Expression::Kind::kIndex:
469 return is_matching_expression_tree(*left.as<IndexExpression>().index(),
470 *right.as<IndexExpression>().index()) &&
471 is_matching_expression_tree(*left.as<IndexExpression>().base(),
472 *right.as<IndexExpression>().base());
473
474 case Expression::Kind::kSwizzle:
475 return left.as<Swizzle>().components() == right.as<Swizzle>().components() &&
476 is_matching_expression_tree(*left.as<Swizzle>().base(),
477 *right.as<Swizzle>().base());
478
479 case Expression::Kind::kVariableReference:
480 return left.as<VariableReference>().variable() ==
481 right.as<VariableReference>().variable();
482
483 default:
484 return false;
485 }
486}
487
488static bool self_assignment(const BinaryExpression& b) {
John Stiles45990502021-02-16 10:55:27 -0500489 return b.getOperator().kind() == Token::Kind::TK_EQ &&
John Stiles0ac6c152021-02-10 14:04:24 -0500490 is_matching_expression_tree(*b.left(), *b.right());
491}
492
Ethan Nicholascb670962017-04-20 19:31:52 -0400493void Compiler::computeDataFlow(CFG* cfg) {
John Stilese8a24922021-02-08 17:54:08 -0500494 cfg->fBlocks[cfg->fStart].fBefore.computeStartState(*cfg);
John Stilese6150002020-10-05 12:03:53 -0400495
496 // We set bits in the "processed" set after a block has been scanned.
497 SkBitSet processedSet(cfg->fBlocks.size());
498 while (SkBitSet::OptionalIndex blockId = processedSet.findFirstUnset()) {
499 processedSet.set(*blockId);
500 this->scanCFG(cfg, *blockId, &processedSet);
ethannicholas22f939e2016-10-13 13:25:34 -0700501 }
Ethan Nicholascb670962017-04-20 19:31:52 -0400502}
503
504/**
505 * Attempts to replace the expression pointed to by iter with a new one (in both the CFG and the
506 * IR). If the expression can be cleanly removed, returns true and updates the iterator to point to
507 * the newly-inserted element. Otherwise updates only the IR and returns false (and the CFG will
508 * need to be regenerated).
509 */
John Stilesafbf8992020-08-18 10:08:21 -0400510static bool try_replace_expression(BasicBlock* b,
511 std::vector<BasicBlock::Node>::iterator* iter,
512 std::unique_ptr<Expression>* newExpression) {
Ethan Nicholascb670962017-04-20 19:31:52 -0400513 std::unique_ptr<Expression>* target = (*iter)->expression();
514 if (!b->tryRemoveExpression(iter)) {
515 *target = std::move(*newExpression);
516 return false;
517 }
518 *target = std::move(*newExpression);
519 return b->tryInsertExpression(iter, target);
520}
521
522/**
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400523 * Returns true if the expression is a constant numeric literal with the specified value, or a
524 * constant vector with all elements equal to the specified value.
Ethan Nicholascb670962017-04-20 19:31:52 -0400525 */
Ethan Nicholasa3f22f12020-10-01 12:13:17 -0400526template <typename T = SKSL_FLOAT>
John Stiles9d944232020-08-19 09:56:49 -0400527static bool is_constant(const Expression& expr, T value) {
Ethan Nicholase6592142020-09-08 10:22:09 -0400528 switch (expr.kind()) {
529 case Expression::Kind::kIntLiteral:
Ethan Nicholase96cdd12020-09-28 16:27:18 -0400530 return expr.as<IntLiteral>().value() == value;
John Stiles9d944232020-08-19 09:56:49 -0400531
Ethan Nicholase6592142020-09-08 10:22:09 -0400532 case Expression::Kind::kFloatLiteral:
Ethan Nicholasa3f22f12020-10-01 12:13:17 -0400533 return expr.as<FloatLiteral>().value() == value;
John Stiles9d944232020-08-19 09:56:49 -0400534
Ethan Nicholase6592142020-09-08 10:22:09 -0400535 case Expression::Kind::kConstructor: {
John Stiles9d944232020-08-19 09:56:49 -0400536 const Constructor& constructor = expr.as<Constructor>();
537 if (constructor.isCompileTimeConstant()) {
Ethan Nicholas30d30222020-09-11 12:27:26 -0400538 const Type& constructorType = constructor.type();
Ethan Nicholas30d30222020-09-11 12:27:26 -0400539 switch (constructorType.typeKind()) {
Ethan Nicholase6592142020-09-08 10:22:09 -0400540 case Type::TypeKind::kVector:
John Stilesbc75ebb2020-11-24 12:04:47 -0500541 if (constructor.componentType().isFloat()) {
542 for (int i = 0; i < constructorType.columns(); ++i) {
John Stiles9d944232020-08-19 09:56:49 -0400543 if (constructor.getFVecComponent(i) != value) {
544 return false;
545 }
John Stilesbc75ebb2020-11-24 12:04:47 -0500546 }
547 return true;
548 } else if (constructor.componentType().isInteger()) {
549 for (int i = 0; i < constructorType.columns(); ++i) {
John Stiles9d944232020-08-19 09:56:49 -0400550 if (constructor.getIVecComponent(i) != value) {
551 return false;
552 }
553 }
John Stilesbc75ebb2020-11-24 12:04:47 -0500554 return true;
Ethan Nicholasd188c182019-06-10 15:55:38 -0400555 }
John Stilesbc75ebb2020-11-24 12:04:47 -0500556 // Other types (e.g. boolean) might occur, but aren't supported here.
557 return false;
John Stiles9d944232020-08-19 09:56:49 -0400558
Ethan Nicholase6592142020-09-08 10:22:09 -0400559 case Type::TypeKind::kScalar:
Ethan Nicholasf70f0442020-09-29 12:41:35 -0400560 SkASSERT(constructor.arguments().size() == 1);
561 return is_constant<T>(*constructor.arguments()[0], value);
John Stiles9d944232020-08-19 09:56:49 -0400562
563 default:
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400564 return false;
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400565 }
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400566 }
567 return false;
568 }
Ethan Nicholascb670962017-04-20 19:31:52 -0400569 default:
570 return false;
571 }
572}
573
574/**
575 * Collapses the binary expression pointed to by iter down to just the right side (in both the IR
576 * and CFG structures).
577 */
John Stilesafbf8992020-08-18 10:08:21 -0400578static void delete_left(BasicBlock* b,
579 std::vector<BasicBlock::Node>::iterator* iter,
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400580 Compiler::OptimizationContext* optimizationContext) {
581 optimizationContext->fUpdated = true;
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400582 std::unique_ptr<Expression>* target = (*iter)->expression();
John Stilesa5a97b42020-08-18 11:19:07 -0400583 BinaryExpression& bin = (*target)->as<BinaryExpression>();
John Stiles2d4f9592020-10-30 10:29:12 -0400584 Expression& left = *bin.left();
585 std::unique_ptr<Expression>& rightPointer = bin.right();
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400586 SkASSERT(!left.hasSideEffects());
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400587 bool result;
John Stiles45990502021-02-16 10:55:27 -0500588 if (bin.getOperator().kind() == Token::Kind::TK_EQ) {
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400589 result = b->tryRemoveLValueBefore(iter, &left);
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400590 } else {
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400591 result = b->tryRemoveExpressionBefore(iter, &left);
Ethan Nicholascb670962017-04-20 19:31:52 -0400592 }
Brian Osman010ce6a2020-10-19 16:34:10 -0400593 // Remove references within LHS.
594 optimizationContext->fUsage->remove(&left);
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400595 *target = std::move(rightPointer);
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400596 if (!result) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400597 optimizationContext->fNeedsRescan = true;
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400598 return;
599 }
600 if (*iter == b->fNodes.begin()) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400601 optimizationContext->fNeedsRescan = true;
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400602 return;
603 }
604 --(*iter);
John Stiles70025e52020-09-28 16:08:58 -0400605 if (!(*iter)->isExpression() || (*iter)->expression() != &rightPointer) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400606 optimizationContext->fNeedsRescan = true;
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400607 return;
608 }
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400609 *iter = b->fNodes.erase(*iter);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400610 SkASSERT((*iter)->expression() == target);
Ethan Nicholascb670962017-04-20 19:31:52 -0400611}
612
613/**
614 * Collapses the binary expression pointed to by iter down to just the left side (in both the IR and
615 * CFG structures).
616 */
John Stilesafbf8992020-08-18 10:08:21 -0400617static void delete_right(BasicBlock* b,
618 std::vector<BasicBlock::Node>::iterator* iter,
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400619 Compiler::OptimizationContext* optimizationContext) {
620 optimizationContext->fUpdated = true;
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400621 std::unique_ptr<Expression>* target = (*iter)->expression();
John Stilesa5a97b42020-08-18 11:19:07 -0400622 BinaryExpression& bin = (*target)->as<BinaryExpression>();
John Stiles2d4f9592020-10-30 10:29:12 -0400623 std::unique_ptr<Expression>& leftPointer = bin.left();
624 Expression& right = *bin.right();
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400625 SkASSERT(!right.hasSideEffects());
Brian Osman010ce6a2020-10-19 16:34:10 -0400626 // Remove references within RHS.
627 optimizationContext->fUsage->remove(&right);
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400628 if (!b->tryRemoveExpressionBefore(iter, &right)) {
629 *target = std::move(leftPointer);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400630 optimizationContext->fNeedsRescan = true;
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400631 return;
Ethan Nicholascb670962017-04-20 19:31:52 -0400632 }
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400633 *target = std::move(leftPointer);
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400634 if (*iter == b->fNodes.begin()) {
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);
John Stiles70025e52020-09-28 16:08:58 -0400639 if ((!(*iter)->isExpression() || (*iter)->expression() != &leftPointer)) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400640 optimizationContext->fNeedsRescan = true;
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400641 return;
642 }
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400643 *iter = b->fNodes.erase(*iter);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400644 SkASSERT((*iter)->expression() == target);
Ethan Nicholascb670962017-04-20 19:31:52 -0400645}
646
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400647/**
648 * Constructs the specified type using a single argument.
649 */
Ethan Nicholas30d30222020-09-11 12:27:26 -0400650static std::unique_ptr<Expression> construct(const Type* type, std::unique_ptr<Expression> v) {
John Stiles8e3b6be2020-10-13 11:14:08 -0400651 ExpressionArray args;
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400652 args.push_back(std::move(v));
John Stiles54f00492021-02-19 11:46:10 -0500653 return std::make_unique<Constructor>(/*offset=*/-1, *type, std::move(args));
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400654}
655
656/**
657 * Used in the implementations of vectorize_left and vectorize_right. Given a vector type and an
658 * expression x, deletes the expression pointed to by iter and replaces it with <type>(x).
659 */
660static void vectorize(BasicBlock* b,
661 std::vector<BasicBlock::Node>::iterator* iter,
662 const Type& type,
663 std::unique_ptr<Expression>* otherExpression,
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400664 Compiler::OptimizationContext* optimizationContext) {
Ethan Nicholase6592142020-09-08 10:22:09 -0400665 SkASSERT((*(*iter)->expression())->kind() == Expression::Kind::kBinary);
John Stiles9aeed132020-11-24 17:36:06 -0500666 SkASSERT(type.isVector());
667 SkASSERT((*otherExpression)->type().isScalar());
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400668 optimizationContext->fUpdated = true;
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400669 std::unique_ptr<Expression>* target = (*iter)->expression();
670 if (!b->tryRemoveExpression(iter)) {
Ethan Nicholas30d30222020-09-11 12:27:26 -0400671 *target = construct(&type, std::move(*otherExpression));
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400672 optimizationContext->fNeedsRescan = true;
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400673 } else {
Ethan Nicholas30d30222020-09-11 12:27:26 -0400674 *target = construct(&type, std::move(*otherExpression));
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400675 if (!b->tryInsertExpression(iter, target)) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400676 optimizationContext->fNeedsRescan = true;
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400677 }
678 }
679}
680
681/**
682 * Given a binary expression of the form x <op> vec<n>(y), deletes the right side and vectorizes the
683 * left to yield vec<n>(x).
684 */
685static void vectorize_left(BasicBlock* b,
686 std::vector<BasicBlock::Node>::iterator* iter,
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400687 Compiler::OptimizationContext* optimizationContext) {
John Stilesa5a97b42020-08-18 11:19:07 -0400688 BinaryExpression& bin = (*(*iter)->expression())->as<BinaryExpression>();
Brian Osman010ce6a2020-10-19 16:34:10 -0400689 // Remove references within RHS. Vectorization of LHS doesn't change reference counts.
John Stiles2d4f9592020-10-30 10:29:12 -0400690 optimizationContext->fUsage->remove(bin.right().get());
691 vectorize(b, iter, bin.right()->type(), &bin.left(), optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400692}
693
694/**
695 * Given a binary expression of the form vec<n>(x) <op> y, deletes the left side and vectorizes the
696 * right to yield vec<n>(y).
697 */
698static void vectorize_right(BasicBlock* b,
699 std::vector<BasicBlock::Node>::iterator* iter,
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400700 Compiler::OptimizationContext* optimizationContext) {
John Stilesa5a97b42020-08-18 11:19:07 -0400701 BinaryExpression& bin = (*(*iter)->expression())->as<BinaryExpression>();
Brian Osman010ce6a2020-10-19 16:34:10 -0400702 // Remove references within LHS. Vectorization of RHS doesn't change reference counts.
John Stiles2d4f9592020-10-30 10:29:12 -0400703 optimizationContext->fUsage->remove(bin.left().get());
704 vectorize(b, iter, bin.left()->type(), &bin.right(), optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400705}
706
Ethan Nicholascb670962017-04-20 19:31:52 -0400707void Compiler::simplifyExpression(DefinitionMap& definitions,
708 BasicBlock& b,
709 std::vector<BasicBlock::Node>::iterator* iter,
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400710 OptimizationContext* optimizationContext) {
Ethan Nicholascb670962017-04-20 19:31:52 -0400711 Expression* expr = (*iter)->expression()->get();
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400712 SkASSERT(expr);
John Stiles108bbe22020-11-18 11:10:38 -0500713
Ethan Nicholascb670962017-04-20 19:31:52 -0400714 if ((*iter)->fConstantPropagation) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400715 std::unique_ptr<Expression> optimized = expr->constantPropagate(*fIRGenerator,
716 definitions);
Ethan Nicholascb670962017-04-20 19:31:52 -0400717 if (optimized) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400718 optimizationContext->fUpdated = true;
Ethan Nicholas30d30222020-09-11 12:27:26 -0400719 optimized = fIRGenerator->coerce(std::move(optimized), expr->type());
Ethan Nicholas1d881522020-09-11 09:32:54 -0400720 SkASSERT(optimized);
Brian Osman010ce6a2020-10-19 16:34:10 -0400721 // Remove references within 'expr', add references within 'optimized'
722 optimizationContext->fUsage->replace(expr, optimized.get());
Ethan Nicholascb670962017-04-20 19:31:52 -0400723 if (!try_replace_expression(&b, iter, &optimized)) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400724 optimizationContext->fNeedsRescan = true;
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400725 return;
Ethan Nicholascb670962017-04-20 19:31:52 -0400726 }
John Stiles70025e52020-09-28 16:08:58 -0400727 SkASSERT((*iter)->isExpression());
Ethan Nicholascb670962017-04-20 19:31:52 -0400728 expr = (*iter)->expression()->get();
Ethan Nicholascb670962017-04-20 19:31:52 -0400729 }
730 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400731 switch (expr->kind()) {
732 case Expression::Kind::kVariableReference: {
John Stilesa5a97b42020-08-18 11:19:07 -0400733 const VariableReference& ref = expr->as<VariableReference>();
Ethan Nicholas78686922020-10-08 06:46:27 -0400734 const Variable* var = ref.variable();
John Stiles66c53b92021-02-20 08:00:43 -0500735 if (fContext->fConfig->fSettings.fDeadCodeElimination &&
736 ref.refKind() != VariableReference::RefKind::kWrite &&
Ethan Nicholas453f67f2020-10-09 10:43:45 -0400737 ref.refKind() != VariableReference::RefKind::kPointer &&
John Stilese8a24922021-02-08 17:54:08 -0500738 var->storage() == Variable::Storage::kLocal && !definitions.get(var) &&
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400739 optimizationContext->fSilences.find(var) == optimizationContext->fSilences.end()) {
740 optimizationContext->fSilences.insert(var);
Ethan Nicholas82a62d22017-11-07 14:42:10 +0000741 this->error(expr->fOffset,
Ethan Nicholase2c49992020-10-05 11:49:11 -0400742 "'" + var->name() + "' has not been assigned");
Ethan Nicholascb670962017-04-20 19:31:52 -0400743 }
744 break;
745 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400746 case Expression::Kind::kTernary: {
John Stiles403a3632020-08-20 12:11:48 -0400747 TernaryExpression* t = &expr->as<TernaryExpression>();
Ethan Nicholasdd218162020-10-08 05:48:01 -0400748 if (t->test()->is<BoolLiteral>()) {
Ethan Nicholascb670962017-04-20 19:31:52 -0400749 // ternary has a constant test, replace it with either the true or
750 // false branch
Ethan Nicholasdd218162020-10-08 05:48:01 -0400751 if (t->test()->as<BoolLiteral>().value()) {
Brian Osman010ce6a2020-10-19 16:34:10 -0400752 (*iter)->setExpression(std::move(t->ifTrue()), optimizationContext->fUsage);
Ethan Nicholascb670962017-04-20 19:31:52 -0400753 } else {
Brian Osman010ce6a2020-10-19 16:34:10 -0400754 (*iter)->setExpression(std::move(t->ifFalse()), optimizationContext->fUsage);
Ethan Nicholascb670962017-04-20 19:31:52 -0400755 }
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400756 optimizationContext->fUpdated = true;
757 optimizationContext->fNeedsRescan = true;
Ethan Nicholascb670962017-04-20 19:31:52 -0400758 }
759 break;
760 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400761 case Expression::Kind::kBinary: {
John Stiles403a3632020-08-20 12:11:48 -0400762 BinaryExpression* bin = &expr->as<BinaryExpression>();
John Stiles0ac6c152021-02-10 14:04:24 -0500763 if (dead_assignment(*bin, optimizationContext->fUsage) || self_assignment(*bin)) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400764 delete_left(&b, iter, optimizationContext);
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400765 break;
766 }
John Stiles2d4f9592020-10-30 10:29:12 -0400767 Expression& left = *bin->left();
768 Expression& right = *bin->right();
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400769 const Type& leftType = left.type();
770 const Type& rightType = right.type();
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400771 // collapse useless expressions like x * 1 or x + 0
John Stiles9aeed132020-11-24 17:36:06 -0500772 if ((!leftType.isScalar() && !leftType.isVector()) ||
773 (!rightType.isScalar() && !rightType.isVector())) {
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400774 break;
775 }
John Stiles45990502021-02-16 10:55:27 -0500776 switch (bin->getOperator().kind()) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400777 case Token::Kind::TK_STAR:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400778 if (is_constant(left, 1)) {
John Stiles9aeed132020-11-24 17:36:06 -0500779 if (leftType.isVector() && rightType.isScalar()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400780 // float4(1) * x -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400781 vectorize_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400782 } else {
783 // 1 * x -> x
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400784 // 1 * float4(x) -> float4(x)
785 // float4(1) * float4(x) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400786 delete_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400787 }
788 }
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400789 else if (is_constant(left, 0)) {
John Stiles9aeed132020-11-24 17:36:06 -0500790 if (leftType.isScalar() && rightType.isVector() &&
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400791 !right.hasSideEffects()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400792 // 0 * float4(x) -> float4(0)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400793 vectorize_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400794 } else {
795 // 0 * x -> 0
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400796 // float4(0) * x -> float4(0)
797 // float4(0) * float4(x) -> float4(0)
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400798 if (!right.hasSideEffects()) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400799 delete_right(&b, iter, optimizationContext);
Ethan Nicholas51493ee2017-12-11 12:34:33 -0500800 }
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400801 }
Ethan Nicholascb670962017-04-20 19:31:52 -0400802 }
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400803 else if (is_constant(right, 1)) {
John Stiles9aeed132020-11-24 17:36:06 -0500804 if (leftType.isScalar() && rightType.isVector()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400805 // x * float4(1) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400806 vectorize_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400807 } else {
808 // x * 1 -> x
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400809 // float4(x) * 1 -> float4(x)
810 // float4(x) * float4(1) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400811 delete_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400812 }
813 }
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400814 else if (is_constant(right, 0)) {
John Stiles9aeed132020-11-24 17:36:06 -0500815 if (leftType.isVector() && rightType.isScalar() && !left.hasSideEffects()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400816 // float4(x) * 0 -> float4(0)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400817 vectorize_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400818 } else {
819 // x * 0 -> 0
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400820 // x * float4(0) -> float4(0)
821 // float4(x) * float4(0) -> float4(0)
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400822 if (!left.hasSideEffects()) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400823 delete_left(&b, iter, optimizationContext);
Ethan Nicholas51493ee2017-12-11 12:34:33 -0500824 }
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400825 }
Ethan Nicholascb670962017-04-20 19:31:52 -0400826 }
827 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400828 case Token::Kind::TK_PLUS:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400829 if (is_constant(left, 0)) {
John Stiles9aeed132020-11-24 17:36:06 -0500830 if (leftType.isVector() && rightType.isScalar()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400831 // float4(0) + x -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400832 vectorize_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400833 } else {
834 // 0 + x -> x
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400835 // 0 + float4(x) -> float4(x)
836 // float4(0) + float4(x) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400837 delete_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400838 }
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400839 } else if (is_constant(right, 0)) {
John Stiles9aeed132020-11-24 17:36:06 -0500840 if (leftType.isScalar() && rightType.isVector()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400841 // x + float4(0) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400842 vectorize_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400843 } else {
844 // x + 0 -> x
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400845 // float4(x) + 0 -> float4(x)
846 // float4(x) + float4(0) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400847 delete_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400848 }
Ethan Nicholas56e42712017-04-21 10:23:37 -0400849 }
850 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400851 case Token::Kind::TK_MINUS:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400852 if (is_constant(right, 0)) {
John Stiles9aeed132020-11-24 17:36:06 -0500853 if (leftType.isScalar() && rightType.isVector()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400854 // x - float4(0) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400855 vectorize_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400856 } else {
857 // x - 0 -> x
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400858 // float4(x) - 0 -> float4(x)
859 // float4(x) - float4(0) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400860 delete_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400861 }
Ethan Nicholascb670962017-04-20 19:31:52 -0400862 }
863 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400864 case Token::Kind::TK_SLASH:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400865 if (is_constant(right, 1)) {
John Stiles9aeed132020-11-24 17:36:06 -0500866 if (leftType.isScalar() && rightType.isVector()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400867 // x / float4(1) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400868 vectorize_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400869 } else {
870 // x / 1 -> x
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400871 // float4(x) / 1 -> float4(x)
872 // float4(x) / float4(1) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400873 delete_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400874 }
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400875 } else if (is_constant(left, 0)) {
John Stiles9aeed132020-11-24 17:36:06 -0500876 if (leftType.isScalar() && rightType.isVector() &&
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400877 !right.hasSideEffects()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400878 // 0 / float4(x) -> float4(0)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400879 vectorize_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400880 } else {
881 // 0 / x -> 0
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400882 // float4(0) / x -> float4(0)
883 // float4(0) / float4(x) -> float4(0)
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400884 if (!right.hasSideEffects()) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400885 delete_right(&b, iter, optimizationContext);
Ethan Nicholas51493ee2017-12-11 12:34:33 -0500886 }
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400887 }
888 }
889 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400890 case Token::Kind::TK_PLUSEQ:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400891 if (is_constant(right, 0)) {
John Stiles47c0a742021-02-09 09:30:35 -0500892 Analysis::UpdateRefKind(&left, RefKind::kRead);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400893 delete_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400894 }
895 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400896 case Token::Kind::TK_MINUSEQ:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400897 if (is_constant(right, 0)) {
John Stiles47c0a742021-02-09 09:30:35 -0500898 Analysis::UpdateRefKind(&left, RefKind::kRead);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400899 delete_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400900 }
901 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400902 case Token::Kind::TK_STAREQ:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400903 if (is_constant(right, 1)) {
John Stiles47c0a742021-02-09 09:30:35 -0500904 Analysis::UpdateRefKind(&left, RefKind::kRead);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400905 delete_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400906 }
907 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400908 case Token::Kind::TK_SLASHEQ:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400909 if (is_constant(right, 1)) {
John Stiles47c0a742021-02-09 09:30:35 -0500910 Analysis::UpdateRefKind(&left, RefKind::kRead);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400911 delete_right(&b, iter, optimizationContext);
Ethan Nicholascb670962017-04-20 19:31:52 -0400912 }
913 break;
914 default:
915 break;
916 }
Ethan Nicholas409f6f02019-09-17 12:34:39 -0400917 break;
918 }
John Stilesf5c1d042020-11-21 23:26:07 -0500919 case Expression::Kind::kConstructor: {
920 // Find constructors embedded inside constructors and flatten them out where possible.
921 // - float4(float2(1, 2), 3, 4) --> float4(1, 2, 3, 4)
922 // - float4(w, float3(sin(x), cos(y), tan(z))) --> float4(w, sin(x), cos(y), tan(z))
923 // Leave single-argument constructors alone, though. These might be casts or splats.
924 Constructor& c = expr->as<Constructor>();
925 if (c.type().columns() > 1) {
926 // Inspect each constructor argument to see if it's a candidate for flattening.
927 // Remember matched arguments in a bitfield, "argsToOptimize".
928 int argsToOptimize = 0;
929 int currBit = 1;
930 for (const std::unique_ptr<Expression>& arg : c.arguments()) {
931 if (arg->is<Constructor>()) {
932 Constructor& inner = arg->as<Constructor>();
933 if (inner.arguments().size() > 1 &&
934 inner.type().componentType() == c.type().componentType()) {
935 argsToOptimize |= currBit;
936 }
937 }
938 currBit <<= 1;
939 }
940 if (argsToOptimize) {
941 // We found at least one argument that could be flattened out. Re-walk the
942 // constructor args and flatten the candidates we found during our initial pass.
943 ExpressionArray flattened;
944 flattened.reserve_back(c.type().columns());
945 currBit = 1;
946 for (const std::unique_ptr<Expression>& arg : c.arguments()) {
947 if (argsToOptimize & currBit) {
948 Constructor& inner = arg->as<Constructor>();
949 for (const std::unique_ptr<Expression>& innerArg : inner.arguments()) {
950 flattened.push_back(innerArg->clone());
951 }
952 } else {
953 flattened.push_back(arg->clone());
954 }
955 currBit <<= 1;
956 }
John Stiles54f00492021-02-19 11:46:10 -0500957 std::unique_ptr<Expression> replacement = std::make_unique<Constructor>(
958 c.fOffset, c.type(), std::move(flattened));
John Stiles1b91c0e2021-02-11 11:43:09 -0500959 // We're replacing an expression with a cloned version; we'll need a rescan.
960 // No fUsage change: `float2(float(x), y)` and `float2(x, y)` have equivalent
961 // reference counts.
962 try_replace_expression(&b, iter, &replacement);
John Stilesf5c1d042020-11-21 23:26:07 -0500963 optimizationContext->fUpdated = true;
John Stiles1b91c0e2021-02-11 11:43:09 -0500964 optimizationContext->fNeedsRescan = true;
John Stilesf5c1d042020-11-21 23:26:07 -0500965 break;
966 }
967 }
968 break;
969 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400970 case Expression::Kind::kSwizzle: {
John Stiles403a3632020-08-20 12:11:48 -0400971 Swizzle& s = expr->as<Swizzle>();
John Stiles108bbe22020-11-18 11:10:38 -0500972 // Detect identity swizzles like `foo.rgba`.
Ethan Nicholas6b4d5812020-10-12 16:11:51 -0400973 if ((int) s.components().size() == s.base()->type().columns()) {
Ethan Nicholas409f6f02019-09-17 12:34:39 -0400974 bool identity = true;
Ethan Nicholas6b4d5812020-10-12 16:11:51 -0400975 for (int i = 0; i < (int) s.components().size(); ++i) {
976 if (s.components()[i] != i) {
Ethan Nicholas409f6f02019-09-17 12:34:39 -0400977 identity = false;
978 break;
979 }
980 }
981 if (identity) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400982 optimizationContext->fUpdated = true;
Brian Osman010ce6a2020-10-19 16:34:10 -0400983 // No fUsage change: foo.rgba and foo have equivalent reference counts
Ethan Nicholas6b4d5812020-10-12 16:11:51 -0400984 if (!try_replace_expression(&b, iter, &s.base())) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400985 optimizationContext->fNeedsRescan = true;
Ethan Nicholas409f6f02019-09-17 12:34:39 -0400986 return;
987 }
John Stiles70025e52020-09-28 16:08:58 -0400988 SkASSERT((*iter)->isExpression());
Ethan Nicholas409f6f02019-09-17 12:34:39 -0400989 break;
990 }
991 }
John Stiles108bbe22020-11-18 11:10:38 -0500992 // Detect swizzles of swizzles, e.g. replace `foo.argb.r000` with `foo.a000`.
993 if (s.base()->is<Swizzle>()) {
Ethan Nicholas6b4d5812020-10-12 16:11:51 -0400994 Swizzle& base = s.base()->as<Swizzle>();
John Stiles750109b2020-10-30 13:45:46 -0400995 ComponentArray final;
Ethan Nicholas6b4d5812020-10-12 16:11:51 -0400996 for (int c : s.components()) {
997 final.push_back(base.components()[c]);
Ethan Nicholas409f6f02019-09-17 12:34:39 -0400998 }
Ethan Nicholas6b4d5812020-10-12 16:11:51 -0400999 std::unique_ptr<Expression> replacement(new Swizzle(*fContext, base.base()->clone(),
John Stiles750109b2020-10-30 13:45:46 -04001000 final));
John Stilesd2f51b12021-01-07 18:12:31 -05001001 // We're replacing an expression with a cloned version; we'll need a rescan.
John Stiles108bbe22020-11-18 11:10:38 -05001002 // No fUsage change: `foo.gbr.gbr` and `foo.brg` have equivalent reference counts
John Stilesd2f51b12021-01-07 18:12:31 -05001003 try_replace_expression(&b, iter, &replacement);
1004 optimizationContext->fUpdated = true;
1005 optimizationContext->fNeedsRescan = true;
John Stiles108bbe22020-11-18 11:10:38 -05001006 break;
1007 }
1008 // Optimize swizzles of constructors.
1009 if (s.base()->is<Constructor>()) {
1010 Constructor& base = s.base()->as<Constructor>();
1011 std::unique_ptr<Expression> replacement;
1012 const Type& componentType = base.type().componentType();
1013 int swizzleSize = s.components().size();
1014
1015 // The IR generator has already converted any zero/one swizzle components into
1016 // constructors containing zero/one args. Confirm that this is true by checking that
1017 // our swizzle components are all `xyzw` (values 0 through 3).
1018 SkASSERT(std::all_of(s.components().begin(), s.components().end(),
1019 [](int8_t c) { return c >= 0 && c <= 3; }));
1020
John Stiles9aeed132020-11-24 17:36:06 -05001021 if (base.arguments().size() == 1 && base.arguments().front()->type().isScalar()) {
John Stiles108bbe22020-11-18 11:10:38 -05001022 // `half4(scalar).zyy` can be optimized to `half3(scalar)`. The swizzle
1023 // components don't actually matter since all fields are the same.
John Stilesf0cb7332021-01-08 18:39:00 -05001024 const Expression& argument = *base.arguments().front();
1025 const Type& constructorType = componentType.toCompound(*fContext, swizzleSize,
1026 /*rows=*/1);
1027 replacement = Constructor::SimplifyConversion(constructorType, argument);
1028 if (!replacement) {
1029 ExpressionArray newArgs;
1030 newArgs.push_back(argument.clone());
John Stiles54f00492021-02-19 11:46:10 -05001031 replacement = std::make_unique<Constructor>(base.fOffset, constructorType,
John Stilesf0cb7332021-01-08 18:39:00 -05001032 std::move(newArgs));
1033 }
John Stiles108bbe22020-11-18 11:10:38 -05001034
John Stilesa60ac0c2020-12-22 08:59:51 -05001035 // We're replacing an expression with a cloned version; we'll need a rescan.
1036 // There's no fUsage change: `half4(foo).xy` and `half2(foo)` have equivalent
1037 // reference counts.
1038 try_replace_expression(&b, iter, &replacement);
John Stiles0777ac42020-11-19 11:06:47 -05001039 optimizationContext->fUpdated = true;
John Stilesa60ac0c2020-12-22 08:59:51 -05001040 optimizationContext->fNeedsRescan = true;
John Stiles108bbe22020-11-18 11:10:38 -05001041 break;
1042 }
1043
John Stiles0777ac42020-11-19 11:06:47 -05001044 // Swizzles can duplicate some elements and discard others, e.g.
1045 // `half4(1, 2, 3, 4).xxz` --> `half3(1, 1, 3)`. However, there are constraints:
1046 // - Expressions with side effects need to occur exactly once, even if they
1047 // would otherwise be swizzle-eliminated
1048 // - Non-trivial expressions should not be repeated, but elimination is OK.
1049 //
1050 // Look up the argument for the constructor at each index. This is typically simple
1051 // but for weird cases like `half4(bar.yz, half2(foo))`, it can be harder than it
1052 // seems. This example would result in:
1053 // argMap[0] = {.fArgIndex = 0, .fComponent = 0} (bar.yz .x)
1054 // argMap[1] = {.fArgIndex = 0, .fComponent = 1} (bar.yz .y)
1055 // argMap[2] = {.fArgIndex = 1, .fComponent = 0} (half2(foo) .x)
1056 // argMap[3] = {.fArgIndex = 1, .fComponent = 1} (half2(foo) .y)
1057 struct ConstructorArgMap {
1058 int8_t fArgIndex;
1059 int8_t fComponent;
1060 };
1061
1062 int numConstructorArgs = base.type().columns();
1063 ConstructorArgMap argMap[4] = {};
1064 int writeIdx = 0;
1065 for (int argIdx = 0; argIdx < (int) base.arguments().size(); ++argIdx) {
1066 const Expression& expr = *base.arguments()[argIdx];
1067 int argWidth = expr.type().columns();
1068 for (int componentIdx = 0; componentIdx < argWidth; ++componentIdx) {
1069 argMap[writeIdx].fArgIndex = argIdx;
1070 argMap[writeIdx].fComponent = componentIdx;
1071 ++writeIdx;
1072 }
1073 }
1074 SkASSERT(writeIdx == numConstructorArgs);
1075
1076 // Count up the number of times each constructor argument is used by the
1077 // swizzle.
1078 // `half4(bar.yz, half2(foo)).xwxy` -> { 3, 1 }
1079 // - bar.yz is referenced 3 times, by `.x_xy`
1080 // - half(foo) is referenced 1 time, by `._w__`
1081 int8_t exprUsed[4] = {};
1082 for (int c : s.components()) {
1083 exprUsed[argMap[c].fArgIndex]++;
1084 }
1085
1086 bool safeToOptimize = true;
1087 for (int index = 0; index < numConstructorArgs; ++index) {
1088 int8_t constructorArgIndex = argMap[index].fArgIndex;
1089 const Expression& baseArg = *base.arguments()[constructorArgIndex];
1090
1091 // Check that non-trivial expressions are not swizzled in more than once.
John Stilesc30fbca2020-11-19 16:25:49 -05001092 if (exprUsed[constructorArgIndex] > 1 &&
1093 !Analysis::IsTrivialExpression(baseArg)) {
John Stiles0777ac42020-11-19 11:06:47 -05001094 safeToOptimize = false;
1095 break;
1096 }
1097 // Check that side-effect-bearing expressions are swizzled in exactly once.
1098 if (exprUsed[constructorArgIndex] != 1 && baseArg.hasSideEffects()) {
1099 safeToOptimize = false;
1100 break;
1101 }
1102 }
1103
1104 if (safeToOptimize) {
John Stilesd9076cb2020-11-19 12:18:36 -05001105 struct ReorderedArgument {
1106 int8_t fArgIndex;
1107 ComponentArray fComponents;
1108 };
1109 SkSTArray<4, ReorderedArgument> reorderedArgs;
John Stiles0777ac42020-11-19 11:06:47 -05001110 for (int c : s.components()) {
1111 const ConstructorArgMap& argument = argMap[c];
1112 const Expression& baseArg = *base.arguments()[argument.fArgIndex];
1113
John Stiles9aeed132020-11-24 17:36:06 -05001114 if (baseArg.type().isScalar()) {
John Stilesd9076cb2020-11-19 12:18:36 -05001115 // This argument is a scalar; add it to the list as-is.
John Stiles0777ac42020-11-19 11:06:47 -05001116 SkASSERT(argument.fComponent == 0);
John Stilesd9076cb2020-11-19 12:18:36 -05001117 reorderedArgs.push_back({argument.fArgIndex,
1118 ComponentArray{}});
John Stiles0777ac42020-11-19 11:06:47 -05001119 } else {
John Stilesd9076cb2020-11-19 12:18:36 -05001120 // This argument is a component from a vector.
John Stiles0777ac42020-11-19 11:06:47 -05001121 SkASSERT(argument.fComponent < baseArg.type().columns());
John Stilesd9076cb2020-11-19 12:18:36 -05001122 if (reorderedArgs.empty() ||
1123 reorderedArgs.back().fArgIndex != argument.fArgIndex) {
1124 // This can't be combined with the previous argument. Add a new one.
1125 reorderedArgs.push_back({argument.fArgIndex,
1126 ComponentArray{argument.fComponent}});
1127 } else {
1128 // Since we know this argument uses components, it should already
1129 // have at least one component set.
1130 SkASSERT(!reorderedArgs.back().fComponents.empty());
1131 // Build up the current argument with one more component.
1132 reorderedArgs.back().fComponents.push_back(argument.fComponent);
1133 }
John Stiles0777ac42020-11-19 11:06:47 -05001134 }
1135 }
John Stilesd9076cb2020-11-19 12:18:36 -05001136
1137 // Convert our reordered argument list to an actual array of expressions, with
1138 // the new order and any new inner swizzles that need to be applied. Note that
1139 // we expect followup passes to clean up the inner swizzles.
1140 ExpressionArray newArgs;
1141 newArgs.reserve_back(swizzleSize);
1142 for (const ReorderedArgument& reorderedArg : reorderedArgs) {
1143 const Expression& baseArg = *base.arguments()[reorderedArg.fArgIndex];
1144 if (reorderedArg.fComponents.empty()) {
1145 newArgs.push_back(baseArg.clone());
1146 } else {
1147 newArgs.push_back(std::make_unique<Swizzle>(*fContext, baseArg.clone(),
1148 reorderedArg.fComponents));
1149 }
1150 }
1151
1152 // Create a new constructor.
John Stiles0777ac42020-11-19 11:06:47 -05001153 replacement = std::make_unique<Constructor>(
1154 base.fOffset,
John Stiles54f00492021-02-19 11:46:10 -05001155 componentType.toCompound(*fContext, swizzleSize, /*rows=*/1),
John Stiles0777ac42020-11-19 11:06:47 -05001156 std::move(newArgs));
1157
John Stilesa60ac0c2020-12-22 08:59:51 -05001158 // Remove references within 'expr', add references within 'replacement.'
John Stiles0777ac42020-11-19 11:06:47 -05001159 optimizationContext->fUsage->replace(expr, replacement.get());
John Stilesa60ac0c2020-12-22 08:59:51 -05001160
1161 // We're replacing an expression with a cloned version; we'll need a rescan.
1162 try_replace_expression(&b, iter, &replacement);
1163 optimizationContext->fUpdated = true;
1164 optimizationContext->fNeedsRescan = true;
John Stiles0777ac42020-11-19 11:06:47 -05001165 }
John Stiles108bbe22020-11-18 11:10:38 -05001166 break;
Ethan Nicholas409f6f02019-09-17 12:34:39 -04001167 }
John Stiles30212b72020-06-11 17:55:07 -04001168 break;
Ethan Nicholascb670962017-04-20 19:31:52 -04001169 }
1170 default:
1171 break;
1172 }
1173}
1174
John Stiles04ca41a2021-02-23 09:58:04 -05001175static bool contains_exit(Statement& stmt, bool conditionalExits) {
1176 class ContainsExit : public ProgramVisitor {
John Stilesb92641c2020-08-31 18:09:01 -04001177 public:
John Stiles04ca41a2021-02-23 09:58:04 -05001178 ContainsExit(bool e) : fConditionalExits(e) {}
1179
John Stilesb92641c2020-08-31 18:09:01 -04001180 bool visitStatement(const Statement& stmt) override {
Ethan Nicholase6592142020-09-08 10:22:09 -04001181 switch (stmt.kind()) {
1182 case Statement::Kind::kBlock:
John Stilesbb1505f2021-02-12 09:17:53 -05001183 return INHERITED::visitStatement(stmt);
John Stilesb92641c2020-08-31 18:09:01 -04001184
John Stiles04ca41a2021-02-23 09:58:04 -05001185 case Statement::Kind::kReturn:
1186 // Returns are an early exit regardless of the surrounding control structures.
1187 return fConditionalExits ? fInConditional : !fInConditional;
1188
1189 case Statement::Kind::kContinue:
1190 // Continues are an early exit from switches, but not loops.
1191 return !fInLoop &&
1192 (fConditionalExits ? fInConditional : !fInConditional);
1193
Ethan Nicholase6592142020-09-08 10:22:09 -04001194 case Statement::Kind::kBreak:
John Stiles04ca41a2021-02-23 09:58:04 -05001195 // Breaks cannot escape from switches or loops.
1196 return !fInLoop && !fInSwitch &&
1197 (fConditionalExits ? fInConditional : !fInConditional);
John Stilesb92641c2020-08-31 18:09:01 -04001198
Ethan Nicholase6592142020-09-08 10:22:09 -04001199 case Statement::Kind::kIf: {
John Stilesb92641c2020-08-31 18:09:01 -04001200 ++fInConditional;
John Stilesbb1505f2021-02-12 09:17:53 -05001201 bool result = INHERITED::visitStatement(stmt);
John Stilesb92641c2020-08-31 18:09:01 -04001202 --fInConditional;
1203 return result;
1204 }
1205
John Stiles04ca41a2021-02-23 09:58:04 -05001206 case Statement::Kind::kFor:
1207 case Statement::Kind::kDo: {
1208 // Loops are treated as conditionals because a loop could potentially execute
1209 // zero times. We don't have a straightforward way to determine that a loop
1210 // definitely executes at least once.
1211 ++fInConditional;
1212 ++fInLoop;
1213 bool result = INHERITED::visitStatement(stmt);
1214 --fInLoop;
1215 --fInConditional;
1216 return result;
1217 }
1218
1219 case Statement::Kind::kSwitch: {
1220 ++fInSwitch;
1221 bool result = INHERITED::visitStatement(stmt);
1222 --fInSwitch;
1223 return result;
1224 }
1225
John Stilesb92641c2020-08-31 18:09:01 -04001226 default:
1227 return false;
1228 }
1229 }
1230
John Stiles04ca41a2021-02-23 09:58:04 -05001231 bool fConditionalExits = false;
John Stilesb92641c2020-08-31 18:09:01 -04001232 int fInConditional = 0;
John Stiles04ca41a2021-02-23 09:58:04 -05001233 int fInLoop = 0;
1234 int fInSwitch = 0;
John Stilesb92641c2020-08-31 18:09:01 -04001235 using INHERITED = ProgramVisitor;
1236 };
1237
John Stiles04ca41a2021-02-23 09:58:04 -05001238 return ContainsExit{conditionalExits}.visitStatement(stmt);
John Stiles92219b42020-06-15 12:32:24 -04001239}
1240
John Stiles04ca41a2021-02-23 09:58:04 -05001241// Finds unconditional exits from a switch-case. Returns true if this statement unconditionally
1242// causes an exit from this switch (via continue, break or return).
1243static bool contains_unconditional_exit(Statement& stmt) {
1244 return contains_exit(stmt, /*conditionalExits=*/false);
1245}
John Stilesb92641c2020-08-31 18:09:01 -04001246
John Stiles04ca41a2021-02-23 09:58:04 -05001247// Finds conditional exits from a switch-case. Returns true if this statement contains a conditional
1248// that wraps a potential exit from the switch (via continue, break or return).
1249static bool contains_conditional_exit(Statement& stmt) {
1250 return contains_exit(stmt, /*conditionalExits=*/true);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001251}
1252
John Stiles8f2a0cf2020-10-13 12:48:21 -04001253static void move_all_but_break(std::unique_ptr<Statement>& stmt, StatementArray* target) {
Ethan Nicholase6592142020-09-08 10:22:09 -04001254 switch (stmt->kind()) {
1255 case Statement::Kind::kBlock: {
John Stiles92219b42020-06-15 12:32:24 -04001256 // Recurse into the block.
1257 Block& block = static_cast<Block&>(*stmt);
1258
John Stiles8f2a0cf2020-10-13 12:48:21 -04001259 StatementArray blockStmts;
John Stilesf4bda742020-10-14 16:57:41 -04001260 blockStmts.reserve_back(block.children().size());
Ethan Nicholas7bd60432020-09-25 14:31:59 -04001261 for (std::unique_ptr<Statement>& stmt : block.children()) {
1262 move_all_but_break(stmt, &blockStmts);
Ethan Nicholas739e1ca2020-06-11 12:16:14 -04001263 }
John Stiles92219b42020-06-15 12:32:24 -04001264
1265 target->push_back(std::make_unique<Block>(block.fOffset, std::move(blockStmts),
Ethan Nicholas7bd60432020-09-25 14:31:59 -04001266 block.symbolTable(), block.isScope()));
Ethan Nicholas739e1ca2020-06-11 12:16:14 -04001267 break;
John Stiles92219b42020-06-15 12:32:24 -04001268 }
1269
Ethan Nicholase6592142020-09-08 10:22:09 -04001270 case Statement::Kind::kBreak:
John Stiles92219b42020-06-15 12:32:24 -04001271 // Do not append a break to the target.
1272 break;
1273
Ethan Nicholas739e1ca2020-06-11 12:16:14 -04001274 default:
John Stiles92219b42020-06-15 12:32:24 -04001275 // Append normal statements to the target.
1276 target->push_back(std::move(stmt));
1277 break;
Ethan Nicholas739e1ca2020-06-11 12:16:14 -04001278 }
1279}
1280
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001281// Returns a block containing all of the statements that will be run if the given case matches
1282// (which, owing to the statements being owned by unique_ptrs, means the switch itself will be
1283// broken by this call and must then be discarded).
1284// Returns null (and leaves the switch unmodified) if no such simple reduction is possible, such as
1285// when break statements appear inside conditionals.
John Stiles92219b42020-06-15 12:32:24 -04001286static std::unique_ptr<Statement> block_for_case(SwitchStatement* switchStatement,
1287 SwitchCase* caseToCapture) {
1288 // We have to be careful to not move any of the pointers until after we're sure we're going to
1289 // succeed, so before we make any changes at all, we check the switch-cases to decide on a plan
1290 // of action. First, find the switch-case we are interested in.
Ethan Nicholas01b05e52020-10-22 15:53:41 -04001291 auto iter = switchStatement->cases().begin();
1292 for (; iter != switchStatement->cases().end(); ++iter) {
John Stiles2d4f9592020-10-30 10:29:12 -04001293 if (iter->get() == caseToCapture) {
John Stiles92219b42020-06-15 12:32:24 -04001294 break;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001295 }
John Stiles92219b42020-06-15 12:32:24 -04001296 }
1297
1298 // Next, walk forward through the rest of the switch. If we find a conditional break, we're
1299 // stuck and can't simplify at all. If we find an unconditional break, we have a range of
1300 // statements that we can use for simplification.
1301 auto startIter = iter;
John Stiles04ca41a2021-02-23 09:58:04 -05001302 Statement* stripBreakStmt = nullptr;
Ethan Nicholas01b05e52020-10-22 15:53:41 -04001303 for (; iter != switchStatement->cases().end(); ++iter) {
John Stiles2d4f9592020-10-30 10:29:12 -04001304 for (std::unique_ptr<Statement>& stmt : (*iter)->statements()) {
John Stiles04ca41a2021-02-23 09:58:04 -05001305 if (contains_conditional_exit(*stmt)) {
1306 // We can't reduce switch-cases to a block when they have conditional exits.
John Stiles92219b42020-06-15 12:32:24 -04001307 return nullptr;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001308 }
John Stiles04ca41a2021-02-23 09:58:04 -05001309 if (contains_unconditional_exit(*stmt)) {
1310 // We found an unconditional exit. We can use this block, but we need to strip
1311 // out a break statement if it has one.
1312 stripBreakStmt = stmt.get();
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001313 break;
1314 }
1315 }
John Stiles92219b42020-06-15 12:32:24 -04001316
John Stiles04ca41a2021-02-23 09:58:04 -05001317 if (stripBreakStmt) {
John Stiles92219b42020-06-15 12:32:24 -04001318 break;
1319 }
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001320 }
John Stiles92219b42020-06-15 12:32:24 -04001321
1322 // We fell off the bottom of the switch or encountered a break. We know the range of statements
1323 // that we need to move over, and we know it's safe to do so.
John Stiles8f2a0cf2020-10-13 12:48:21 -04001324 StatementArray caseStmts;
John Stiles92219b42020-06-15 12:32:24 -04001325
1326 // We can move over most of the statements as-is.
1327 while (startIter != iter) {
John Stiles2d4f9592020-10-30 10:29:12 -04001328 for (std::unique_ptr<Statement>& stmt : (*startIter)->statements()) {
John Stiles92219b42020-06-15 12:32:24 -04001329 caseStmts.push_back(std::move(stmt));
1330 }
1331 ++startIter;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001332 }
John Stiles92219b42020-06-15 12:32:24 -04001333
John Stiles04ca41a2021-02-23 09:58:04 -05001334 // For the last statement, we need to move what we can, stopping at a break if there is one.
1335 if (stripBreakStmt != nullptr) {
John Stiles2d4f9592020-10-30 10:29:12 -04001336 for (std::unique_ptr<Statement>& stmt : (*startIter)->statements()) {
John Stiles04ca41a2021-02-23 09:58:04 -05001337 if (stmt.get() == stripBreakStmt) {
John Stiles92219b42020-06-15 12:32:24 -04001338 move_all_but_break(stmt, &caseStmts);
John Stiles04ca41a2021-02-23 09:58:04 -05001339 stripBreakStmt = nullptr;
John Stiles92219b42020-06-15 12:32:24 -04001340 break;
1341 }
1342
1343 caseStmts.push_back(std::move(stmt));
1344 }
1345 }
1346
John Stiles04ca41a2021-02-23 09:58:04 -05001347 SkASSERT(stripBreakStmt == nullptr); // Verify that we fixed the unconditional break.
John Stiles92219b42020-06-15 12:32:24 -04001348
1349 // Return our newly-synthesized block.
Ethan Nicholas01b05e52020-10-22 15:53:41 -04001350 return std::make_unique<Block>(/*offset=*/-1, std::move(caseStmts), switchStatement->symbols());
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001351}
1352
Ethan Nicholascb670962017-04-20 19:31:52 -04001353void Compiler::simplifyStatement(DefinitionMap& definitions,
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001354 BasicBlock& b,
1355 std::vector<BasicBlock::Node>::iterator* iter,
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001356 OptimizationContext* optimizationContext) {
Brian Osman010ce6a2020-10-19 16:34:10 -04001357 ProgramUsage* usage = optimizationContext->fUsage;
Ethan Nicholascb670962017-04-20 19:31:52 -04001358 Statement* stmt = (*iter)->statement()->get();
Ethan Nicholase6592142020-09-08 10:22:09 -04001359 switch (stmt->kind()) {
1360 case Statement::Kind::kVarDeclaration: {
John Stilesa5a97b42020-08-18 11:19:07 -04001361 const auto& varDecl = stmt->as<VarDeclaration>();
Brian Osman010ce6a2020-10-19 16:34:10 -04001362 if (usage->isDead(varDecl.var()) &&
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04001363 (!varDecl.value() ||
1364 !varDecl.value()->hasSideEffects())) {
1365 if (varDecl.value()) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001366 SkASSERT((*iter)->statement()->get() == stmt);
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04001367 if (!b.tryRemoveExpressionBefore(iter, varDecl.value().get())) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001368 optimizationContext->fNeedsRescan = true;
Ethan Nicholascb670962017-04-20 19:31:52 -04001369 }
Ethan Nicholascb670962017-04-20 19:31:52 -04001370 }
Ethan Nicholas5b9b0db2021-01-21 13:12:01 -05001371 // There can still be (soon to be removed) references to the variable at this point.
1372 // Allowing the VarDeclaration to be destroyed here will break those variable's
1373 // initialValue()s, so we hang on to them until optimization is finished.
1374 std::unique_ptr<Statement> old = (*iter)->setStatement(std::make_unique<Nop>(),
1375 usage);
1376 optimizationContext->fOwnedStatements.push_back(std::move(old));
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001377 optimizationContext->fUpdated = true;
Ethan Nicholascb670962017-04-20 19:31:52 -04001378 }
1379 break;
1380 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001381 case Statement::Kind::kIf: {
John Stilesa5a97b42020-08-18 11:19:07 -04001382 IfStatement& i = stmt->as<IfStatement>();
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001383 if (i.test()->kind() == Expression::Kind::kBoolLiteral) {
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001384 // constant if, collapse down to a single branch
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001385 if (i.test()->as<BoolLiteral>().value()) {
1386 SkASSERT(i.ifTrue());
Brian Osman010ce6a2020-10-19 16:34:10 -04001387 (*iter)->setStatement(std::move(i.ifTrue()), usage);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001388 } else {
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001389 if (i.ifFalse()) {
Brian Osman010ce6a2020-10-19 16:34:10 -04001390 (*iter)->setStatement(std::move(i.ifFalse()), usage);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001391 } else {
Brian Osman010ce6a2020-10-19 16:34:10 -04001392 (*iter)->setStatement(std::make_unique<Nop>(), usage);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001393 }
1394 }
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001395 optimizationContext->fUpdated = true;
1396 optimizationContext->fNeedsRescan = true;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001397 break;
1398 }
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001399 if (i.ifFalse() && i.ifFalse()->isEmpty()) {
Ethan Nicholascb670962017-04-20 19:31:52 -04001400 // else block doesn't do anything, remove it
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001401 i.ifFalse().reset();
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001402 optimizationContext->fUpdated = true;
1403 optimizationContext->fNeedsRescan = true;
Ethan Nicholascb670962017-04-20 19:31:52 -04001404 }
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001405 if (!i.ifFalse() && i.ifTrue()->isEmpty()) {
Ethan Nicholascb670962017-04-20 19:31:52 -04001406 // if block doesn't do anything, no else block
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001407 if (i.test()->hasSideEffects()) {
Ethan Nicholascb670962017-04-20 19:31:52 -04001408 // test has side effects, keep it
Brian Osman010ce6a2020-10-19 16:34:10 -04001409 (*iter)->setStatement(
1410 std::make_unique<ExpressionStatement>(std::move(i.test())), usage);
Ethan Nicholascb670962017-04-20 19:31:52 -04001411 } else {
1412 // no if, no else, no test side effects, kill the whole if
1413 // statement
Brian Osman010ce6a2020-10-19 16:34:10 -04001414 (*iter)->setStatement(std::make_unique<Nop>(), usage);
Ethan Nicholascb670962017-04-20 19:31:52 -04001415 }
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001416 optimizationContext->fUpdated = true;
1417 optimizationContext->fNeedsRescan = true;
Ethan Nicholascb670962017-04-20 19:31:52 -04001418 }
1419 break;
1420 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001421 case Statement::Kind::kSwitch: {
John Stilesa5a97b42020-08-18 11:19:07 -04001422 SwitchStatement& s = stmt->as<SwitchStatement>();
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001423 int64_t switchValue;
Ethan Nicholasc0f98152021-02-05 16:21:10 -05001424 if (ConstantFolder::GetConstantInt(*s.value(), &switchValue)) {
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001425 // switch is constant, replace it with the case that matches
1426 bool found = false;
1427 SwitchCase* defaultCase = nullptr;
John Stiles2d4f9592020-10-30 10:29:12 -04001428 for (const std::unique_ptr<SwitchCase>& c : s.cases()) {
1429 if (!c->value()) {
1430 defaultCase = c.get();
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001431 continue;
1432 }
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001433 int64_t caseValue;
Ethan Nicholasc0f98152021-02-05 16:21:10 -05001434 SkAssertResult(ConstantFolder::GetConstantInt(*c->value(), &caseValue));
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001435 if (caseValue == switchValue) {
John Stiles2d4f9592020-10-30 10:29:12 -04001436 std::unique_ptr<Statement> newBlock = block_for_case(&s, c.get());
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001437 if (newBlock) {
Brian Osman010ce6a2020-10-19 16:34:10 -04001438 (*iter)->setStatement(std::move(newBlock), usage);
John Stiles9d944232020-08-19 09:56:49 -04001439 found = true;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001440 break;
1441 } else {
John Stilesd6a5f4492021-02-11 15:46:11 -05001442 if (s.isStatic() &&
John Stilesd1204642021-02-17 16:30:02 -05001443 !fContext->fConfig->fSettings.fPermitInvalidStaticTests) {
John Stilesd6a5f4492021-02-11 15:46:11 -05001444 auto [iter, didInsert] = optimizationContext->fSilences.insert(&s);
1445 if (didInsert) {
1446 this->error(s.fOffset, "static switch contains non-static "
John Stiles04ca41a2021-02-23 09:58:04 -05001447 "conditional exit");
John Stilesd6a5f4492021-02-11 15:46:11 -05001448 }
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001449 }
1450 return; // can't simplify
1451 }
1452 }
1453 }
1454 if (!found) {
1455 // no matching case. use default if it exists, or kill the whole thing
1456 if (defaultCase) {
1457 std::unique_ptr<Statement> newBlock = block_for_case(&s, defaultCase);
1458 if (newBlock) {
Brian Osman010ce6a2020-10-19 16:34:10 -04001459 (*iter)->setStatement(std::move(newBlock), usage);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001460 } else {
John Stilesd6a5f4492021-02-11 15:46:11 -05001461 if (s.isStatic() &&
John Stilesd1204642021-02-17 16:30:02 -05001462 !fContext->fConfig->fSettings.fPermitInvalidStaticTests) {
John Stilesd6a5f4492021-02-11 15:46:11 -05001463 auto [iter, didInsert] = optimizationContext->fSilences.insert(&s);
1464 if (didInsert) {
1465 this->error(s.fOffset, "static switch contains non-static "
John Stiles04ca41a2021-02-23 09:58:04 -05001466 "conditional exit");
John Stilesd6a5f4492021-02-11 15:46:11 -05001467 }
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001468 }
1469 return; // can't simplify
1470 }
1471 } else {
Brian Osman010ce6a2020-10-19 16:34:10 -04001472 (*iter)->setStatement(std::make_unique<Nop>(), usage);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001473 }
1474 }
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001475 optimizationContext->fUpdated = true;
1476 optimizationContext->fNeedsRescan = true;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001477 }
1478 break;
1479 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001480 case Statement::Kind::kExpression: {
John Stilesa5a97b42020-08-18 11:19:07 -04001481 ExpressionStatement& e = stmt->as<ExpressionStatement>();
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001482 SkASSERT((*iter)->statement()->get() == &e);
Ethan Nicholasd503a5a2020-09-30 09:29:55 -04001483 if (!e.expression()->hasSideEffects()) {
Ethan Nicholascb670962017-04-20 19:31:52 -04001484 // Expression statement with no side effects, kill it
Ethan Nicholasd503a5a2020-09-30 09:29:55 -04001485 if (!b.tryRemoveExpressionBefore(iter, e.expression().get())) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001486 optimizationContext->fNeedsRescan = true;
Ethan Nicholascb670962017-04-20 19:31:52 -04001487 }
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001488 SkASSERT((*iter)->statement()->get() == stmt);
Brian Osman010ce6a2020-10-19 16:34:10 -04001489 (*iter)->setStatement(std::make_unique<Nop>(), usage);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001490 optimizationContext->fUpdated = true;
Ethan Nicholascb670962017-04-20 19:31:52 -04001491 }
1492 break;
1493 }
1494 default:
1495 break;
1496 }
1497}
1498
Brian Osman010ce6a2020-10-19 16:34:10 -04001499bool Compiler::scanCFG(FunctionDefinition& f, ProgramUsage* usage) {
John Stiles0cc193a2020-09-09 09:39:34 -04001500 bool madeChanges = false;
1501
Ethan Nicholascb670962017-04-20 19:31:52 -04001502 CFG cfg = CFGGenerator().getCFG(f);
1503 this->computeDataFlow(&cfg);
ethannicholas22f939e2016-10-13 13:25:34 -07001504
John Stiles66c53b92021-02-20 08:00:43 -05001505 if (fContext->fConfig->fSettings.fDeadCodeElimination) {
1506 // Check for unreachable code.
1507 for (size_t i = 0; i < cfg.fBlocks.size(); i++) {
1508 const BasicBlock& block = cfg.fBlocks[i];
1509 if (!block.fIsReachable && !block.fAllowUnreachable && block.fNodes.size()) {
1510 const BasicBlock::Node& node = block.fNodes[0];
1511 int offset = node.isStatement() ? (*node.statement())->fOffset
1512 : (*node.expression())->fOffset;
1513 this->error(offset, String("unreachable"));
1514 }
ethannicholas22f939e2016-10-13 13:25:34 -07001515 }
1516 }
1517 if (fErrorCount) {
John Stiles0cc193a2020-09-09 09:39:34 -04001518 return madeChanges;
ethannicholas22f939e2016-10-13 13:25:34 -07001519 }
1520
Ethan Nicholascb670962017-04-20 19:31:52 -04001521 // check for dead code & undefined variables, perform constant propagation
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001522 OptimizationContext optimizationContext;
Brian Osman010ce6a2020-10-19 16:34:10 -04001523 optimizationContext.fUsage = usage;
John Stiles7d3f0892020-11-03 11:35:01 -05001524 SkBitSet eliminatedBlockIds(cfg.fBlocks.size());
Ethan Nicholascb670962017-04-20 19:31:52 -04001525 do {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001526 if (optimizationContext.fNeedsRescan) {
Ethan Nicholascb670962017-04-20 19:31:52 -04001527 cfg = CFGGenerator().getCFG(f);
1528 this->computeDataFlow(&cfg);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001529 optimizationContext.fNeedsRescan = false;
Ethan Nicholas113628d2017-02-02 16:11:39 -05001530 }
Ethan Nicholascb670962017-04-20 19:31:52 -04001531
John Stiles7d3f0892020-11-03 11:35:01 -05001532 eliminatedBlockIds.reset();
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001533 optimizationContext.fUpdated = false;
John Stiles7d3f0892020-11-03 11:35:01 -05001534
1535 for (BlockId blockId = 0; blockId < cfg.fBlocks.size(); ++blockId) {
1536 if (eliminatedBlockIds.test(blockId)) {
1537 // We reached a block ID that might have been eliminated. Be cautious and rescan.
1538 optimizationContext.fUpdated = true;
1539 optimizationContext.fNeedsRescan = true;
1540 break;
1541 }
1542
1543 BasicBlock& b = cfg.fBlocks[blockId];
John Stiles66c53b92021-02-20 08:00:43 -05001544 if (fContext->fConfig->fSettings.fDeadCodeElimination) {
1545 if (blockId > 0 && !b.fIsReachable) {
1546 // Block was reachable before optimization, but has since become unreachable. In
1547 // addition to being dead code, it's broken - since control flow can't reach it,
1548 // no prior variable definitions can reach it, and therefore variables might
1549 // look to have not been properly assigned. Kill it by replacing all statements
1550 // with Nops.
1551 for (BasicBlock::Node& node : b.fNodes) {
1552 if (node.isStatement() && !(*node.statement())->is<Nop>()) {
1553 // Eliminating a node runs the risk of eliminating that node's exits as
1554 // well. Keep track of this and do a rescan if we are about to access
1555 // one of these.
1556 for (BlockId id : b.fExits) {
1557 eliminatedBlockIds.set(id);
1558 }
1559 node.setStatement(std::make_unique<Nop>(), usage);
1560 madeChanges = true;
John Stiles7d3f0892020-11-03 11:35:01 -05001561 }
Ethan Nicholas1de14812020-06-19 15:32:49 -04001562 }
John Stiles66c53b92021-02-20 08:00:43 -05001563 continue;
Ethan Nicholas1de14812020-06-19 15:32:49 -04001564 }
Ethan Nicholas1de14812020-06-19 15:32:49 -04001565 }
Ethan Nicholascb670962017-04-20 19:31:52 -04001566 DefinitionMap definitions = b.fBefore;
1567
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001568 for (auto iter = b.fNodes.begin(); iter != b.fNodes.end() &&
1569 !optimizationContext.fNeedsRescan; ++iter) {
John Stiles70025e52020-09-28 16:08:58 -04001570 if (iter->isExpression()) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001571 this->simplifyExpression(definitions, b, &iter, &optimizationContext);
Ethan Nicholascb670962017-04-20 19:31:52 -04001572 } else {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001573 this->simplifyStatement(definitions, b, &iter, &optimizationContext);
Ethan Nicholascb670962017-04-20 19:31:52 -04001574 }
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001575 if (optimizationContext.fNeedsRescan) {
Ethan Nicholas4b330df2017-05-17 10:52:55 -04001576 break;
1577 }
John Stilese8a24922021-02-08 17:54:08 -05001578 definitions.addDefinitions(*fContext, *iter);
Ethan Nicholascb670962017-04-20 19:31:52 -04001579 }
Brian Osman01a3eb42020-09-14 11:32:49 -04001580
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001581 if (optimizationContext.fNeedsRescan) {
Brian Osman01a3eb42020-09-14 11:32:49 -04001582 break;
1583 }
Ethan Nicholascb670962017-04-20 19:31:52 -04001584 }
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001585 madeChanges |= optimizationContext.fUpdated;
1586 } while (optimizationContext.fUpdated);
1587 SkASSERT(!optimizationContext.fNeedsRescan);
ethannicholas22f939e2016-10-13 13:25:34 -07001588
1589 // check for missing return
John Stiles54e7c052021-01-11 14:22:36 -05001590 if (f.declaration().returnType() != *fContext->fTypes.fVoid) {
John Stiles61e75e32020-10-01 15:42:37 -04001591 if (cfg.fBlocks[cfg.fExit].fIsReachable) {
Ethan Nicholas0a5d0962020-10-14 13:33:18 -04001592 this->error(f.fOffset, String("function '" + String(f.declaration().name()) +
Ethan Nicholasdb80f692019-11-22 14:06:12 -05001593 "' can exit without returning a value"));
ethannicholas22f939e2016-10-13 13:25:34 -07001594 }
1595 }
John Stiles0cc193a2020-09-09 09:39:34 -04001596
1597 return madeChanges;
ethannicholas22f939e2016-10-13 13:25:34 -07001598}
1599
Brian Osman32d53552020-09-23 13:55:20 -04001600std::unique_ptr<Program> Compiler::convertProgram(
John Stilesdbd4e6f2021-02-16 13:29:15 -05001601 ProgramKind kind,
Brian Osman32d53552020-09-23 13:55:20 -04001602 String text,
1603 const Program::Settings& settings,
Brian Osmanbe0b3b72021-01-06 14:27:35 -05001604 const std::vector<std::unique_ptr<ExternalFunction>>* externalFunctions) {
Leon Scrogginsb66214e2021-02-11 17:14:18 -05001605 ATRACE_ANDROID_FRAMEWORK("SkSL::Compiler::convertProgram");
1606
John Stilesdbd4e6f2021-02-16 13:29:15 -05001607 SkASSERT(!externalFunctions || (kind == ProgramKind::kGeneric));
Ethan Nicholas91164d12019-05-15 15:29:54 -04001608
Brian Osman0006ad02020-11-18 15:38:39 -05001609 // Loading and optimizing our base module might reset the inliner, so do that first,
1610 // *then* configure the inliner with the settings for this program.
1611 const ParsedModule& baseModule = this->moduleForProgramKind(kind);
1612
John Stiles270cec22021-02-17 12:59:36 -05001613 // Update our context to point to the program configuration for the duration of compilation.
1614 auto config = std::make_unique<ProgramConfig>(ProgramConfig{kind, settings});
1615
1616 SkASSERT(!fContext->fConfig);
1617 fContext->fConfig = config.get();
1618 SK_AT_SCOPE_EXIT(fContext->fConfig = nullptr);
1619
ethannicholasb3058bd2016-07-01 08:22:01 -07001620 fErrorText = "";
1621 fErrorCount = 0;
John Stilesd1204642021-02-17 16:30:02 -05001622 fInliner.reset(fIRGenerator->fModifiers.get());
Brian Osman88cda172020-10-09 12:05:16 -04001623
1624 // Not using AutoSource, because caller is likely to call errorText() if we fail to compile
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001625 std::unique_ptr<String> textPtr(new String(std::move(text)));
1626 fSource = textPtr.get();
Brian Osman88cda172020-10-09 12:05:16 -04001627
John Stiles5c7bb322020-10-22 11:09:15 -04001628 // Enable node pooling while converting and optimizing the program for a performance boost.
1629 // The Program will take ownership of the pool.
Brian Osman28f702c2021-02-02 11:52:07 -05001630 std::unique_ptr<Pool> pool;
1631 if (fCaps->useNodePools()) {
1632 pool = Pool::Create();
1633 pool->attachToThread();
1634 }
John Stilesd1204642021-02-17 16:30:02 -05001635 IRGenerator::IRBundle ir = fIRGenerator->convertProgram(baseModule, /*isBuiltinCode=*/false,
1636 textPtr->c_str(), textPtr->size(),
1637 externalFunctions);
John Stiles270cec22021-02-17 12:59:36 -05001638 auto program = std::make_unique<Program>(std::move(textPtr),
1639 std::move(config),
Brian Osmand7e76592020-11-02 12:26:22 -05001640 fCaps,
John Stiles5c7bb322020-10-22 11:09:15 -04001641 fContext,
1642 std::move(ir.fElements),
Brian Osman133724c2020-10-28 14:14:39 -04001643 std::move(ir.fSharedElements),
John Stiles5c7bb322020-10-22 11:09:15 -04001644 std::move(ir.fModifiers),
1645 std::move(ir.fSymbolTable),
1646 std::move(pool),
1647 ir.fInputs);
1648 bool success = false;
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001649 if (fErrorCount) {
John Stiles5c7bb322020-10-22 11:09:15 -04001650 // Do not return programs that failed to compile.
Brian Osman4f065e22021-02-13 01:06:03 +00001651 } else if (settings.fOptimize && !this->optimize(*program)) {
John Stiles5c7bb322020-10-22 11:09:15 -04001652 // Do not return programs that failed to optimize.
1653 } else {
1654 // We have a successful program!
1655 success = true;
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001656 }
John Stiles5c7bb322020-10-22 11:09:15 -04001657
Brian Osman28f702c2021-02-02 11:52:07 -05001658 if (program->fPool) {
1659 program->fPool->detachFromThread();
1660 }
John Stiles5c7bb322020-10-22 11:09:15 -04001661 return success ? std::move(program) : nullptr;
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001662}
1663
John Stilesbb1505f2021-02-12 09:17:53 -05001664void Compiler::verifyStaticTests(const Program& program) {
1665 class StaticTestVerifier : public ProgramVisitor {
1666 public:
1667 StaticTestVerifier(ErrorReporter* r) : fReporter(r) {}
1668
1669 using ProgramVisitor::visitProgramElement;
1670
1671 bool visitStatement(const Statement& stmt) override {
1672 switch (stmt.kind()) {
1673 case Statement::Kind::kIf:
1674 if (stmt.as<IfStatement>().isStatic()) {
1675 fReporter->error(stmt.fOffset, "static if has non-static test");
1676 }
1677 break;
1678
1679 case Statement::Kind::kSwitch:
1680 if (stmt.as<SwitchStatement>().isStatic()) {
1681 fReporter->error(stmt.fOffset, "static switch has non-static test");
1682 }
1683 break;
1684
1685 default:
1686 break;
1687 }
1688 return INHERITED::visitStatement(stmt);
1689 }
1690
John Stiles59e34562021-02-12 16:56:39 -05001691 bool visitExpression(const Expression&) override {
1692 // We aren't looking for anything inside an Expression, so skip them entirely.
1693 return false;
1694 }
1695
John Stilesbb1505f2021-02-12 09:17:53 -05001696 private:
1697 using INHERITED = ProgramVisitor;
1698 ErrorReporter* fReporter;
1699 };
1700
1701 // If invalid static tests are permitted, we don't need to check anything.
John Stilesd1204642021-02-17 16:30:02 -05001702 if (fContext->fConfig->fSettings.fPermitInvalidStaticTests) {
John Stilesbb1505f2021-02-12 09:17:53 -05001703 return;
1704 }
1705
1706 // Check all of the program's owned elements. (Built-in elements are assumed to be valid.)
1707 StaticTestVerifier visitor{this};
1708 for (const std::unique_ptr<ProgramElement>& element : program.ownedElements()) {
1709 if (element->is<FunctionDefinition>()) {
1710 visitor.visitProgramElement(*element);
1711 }
1712 }
1713}
1714
Brian Osman0006ad02020-11-18 15:38:39 -05001715bool Compiler::optimize(LoadedModule& module) {
1716 SkASSERT(!fErrorCount);
Brian Osman0006ad02020-11-18 15:38:39 -05001717
John Stiles270cec22021-02-17 12:59:36 -05001718 // Create a temporary program configuration with default settings.
1719 ProgramConfig config;
1720 config.fKind = module.fKind;
1721
1722 // Update our context to point to this configuration for the duration of compilation.
1723 SkASSERT(!fContext->fConfig);
1724 fContext->fConfig = &config;
1725 SK_AT_SCOPE_EXIT(fContext->fConfig = nullptr);
1726
John Stilesd1204642021-02-17 16:30:02 -05001727 // Reset the Inliner.
1728 fInliner.reset(fModifiers.back().get());
John Stiles270cec22021-02-17 12:59:36 -05001729
1730 std::unique_ptr<ProgramUsage> usage = Analysis::GetUsage(module);
Brian Osman0006ad02020-11-18 15:38:39 -05001731
1732 while (fErrorCount == 0) {
1733 bool madeChanges = false;
1734
1735 // Scan and optimize based on the control-flow graph for each function.
1736 for (const auto& element : module.fElements) {
1737 if (element->is<FunctionDefinition>()) {
1738 madeChanges |= this->scanCFG(element->as<FunctionDefinition>(), usage.get());
1739 }
1740 }
1741
1742 // Perform inline-candidate analysis and inline any functions deemed suitable.
John Stiles78047582020-12-16 16:17:41 -05001743 madeChanges |= fInliner.analyze(module.fElements, module.fSymbols, usage.get());
Brian Osman0006ad02020-11-18 15:38:39 -05001744
1745 if (!madeChanges) {
1746 break;
1747 }
1748 }
1749 return fErrorCount == 0;
1750}
1751
Ethan Nicholas00543112018-07-31 09:44:36 -04001752bool Compiler::optimize(Program& program) {
1753 SkASSERT(!fErrorCount);
Brian Osman010ce6a2020-10-19 16:34:10 -04001754 ProgramUsage* usage = program.fUsage.get();
John Stiles7954d6c2020-09-01 10:53:02 -04001755
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001756 while (fErrorCount == 0) {
1757 bool madeChanges = false;
John Stiles7954d6c2020-09-01 10:53:02 -04001758
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001759 // Scan and optimize based on the control-flow graph for each function.
Brian Osman133724c2020-10-28 14:14:39 -04001760 for (const auto& element : program.ownedElements()) {
Brian Osman1179fcf2020-10-08 16:04:40 -04001761 if (element->is<FunctionDefinition>()) {
Brian Osman010ce6a2020-10-19 16:34:10 -04001762 madeChanges |= this->scanCFG(element->as<FunctionDefinition>(), usage);
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001763 }
1764 }
1765
1766 // Perform inline-candidate analysis and inline any functions deemed suitable.
John Stiles78047582020-12-16 16:17:41 -05001767 madeChanges |= fInliner.analyze(program.ownedElements(), program.fSymbols, usage);
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001768
1769 // Remove dead functions. We wait until after analysis so that we still report errors,
1770 // even in unused code.
John Stiles270cec22021-02-17 12:59:36 -05001771 if (program.fConfig->fSettings.fRemoveDeadFunctions) {
Brian Osman133724c2020-10-28 14:14:39 -04001772 auto isDeadFunction = [&](const ProgramElement* element) {
1773 if (!element->is<FunctionDefinition>()) {
1774 return false;
1775 }
1776 const FunctionDefinition& fn = element->as<FunctionDefinition>();
1777 if (fn.declaration().name() != "main" && usage->get(fn.declaration()) == 0) {
1778 usage->remove(*element);
1779 madeChanges = true;
1780 return true;
1781 }
1782 return false;
1783 };
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001784 program.fElements.erase(
Brian Osman133724c2020-10-28 14:14:39 -04001785 std::remove_if(program.fElements.begin(), program.fElements.end(),
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001786 [&](const std::unique_ptr<ProgramElement>& element) {
Brian Osman133724c2020-10-28 14:14:39 -04001787 return isDeadFunction(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 isDeadFunction),
1793 program.fSharedElements.end());
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001794 }
1795
John Stiles270cec22021-02-17 12:59:36 -05001796 if (program.fConfig->fKind != ProgramKind::kFragmentProcessor) {
Brian Osmanc0213602020-10-06 14:43:32 -04001797 // Remove declarations of dead global variables
Brian Osman133724c2020-10-28 14:14:39 -04001798 auto isDeadVariable = [&](const ProgramElement* element) {
1799 if (!element->is<GlobalVarDeclaration>()) {
1800 return false;
1801 }
1802 const GlobalVarDeclaration& global = element->as<GlobalVarDeclaration>();
1803 const VarDeclaration& varDecl = global.declaration()->as<VarDeclaration>();
1804 if (usage->isDead(varDecl.var())) {
1805 madeChanges = true;
1806 return true;
1807 }
1808 return false;
1809 };
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001810 program.fElements.erase(
1811 std::remove_if(program.fElements.begin(), program.fElements.end(),
1812 [&](const std::unique_ptr<ProgramElement>& element) {
Brian Osman133724c2020-10-28 14:14:39 -04001813 return isDeadVariable(element.get());
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001814 }),
1815 program.fElements.end());
Brian Osman133724c2020-10-28 14:14:39 -04001816 program.fSharedElements.erase(
1817 std::remove_if(program.fSharedElements.begin(), program.fSharedElements.end(),
1818 isDeadVariable),
1819 program.fSharedElements.end());
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001820 }
John Stiles73a6bff2020-09-09 13:40:37 -04001821
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001822 if (!madeChanges) {
1823 break;
Ethan Nicholas0dc80872019-02-08 15:46:24 -05001824 }
Ethan Nicholas00543112018-07-31 09:44:36 -04001825 }
John Stilesbb1505f2021-02-12 09:17:53 -05001826
1827 if (fErrorCount == 0) {
1828 this->verifyStaticTests(program);
1829 }
1830
Ethan Nicholas00543112018-07-31 09:44:36 -04001831 return fErrorCount == 0;
1832}
1833
Brian Osmanfb32ddf2019-06-18 10:14:20 -04001834#if defined(SKSL_STANDALONE) || SK_SUPPORT_GPU
1835
Ethan Nicholas00543112018-07-31 09:44:36 -04001836bool Compiler::toSPIRV(Program& program, OutputStream& out) {
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001837#ifdef SK_ENABLE_SPIRV_VALIDATION
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001838 StringStream buffer;
Brian Osman88cda172020-10-09 12:05:16 -04001839 AutoSource as(this, program.fSource.get());
Brian Osman8b43dad2020-10-09 13:31:42 -04001840 SPIRVCodeGenerator cg(fContext.get(), &program, this, &buffer);
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001841 bool result = cg.generateCode();
John Stiles270cec22021-02-17 12:59:36 -05001842 if (result && program.fConfig->fSettings.fValidateSPIRV) {
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001843 spvtools::SpirvTools tools(SPV_ENV_VULKAN_1_0);
Ethan Nicholas762466e2017-06-29 10:03:38 -04001844 const String& data = buffer.str();
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001845 SkASSERT(0 == data.size() % 4);
Brian Osman8d09d4a2020-11-24 15:51:06 -05001846 String errors;
1847 auto dumpmsg = [&errors](spv_message_level_t, const char*, const spv_position_t&,
1848 const char* m) {
1849 errors.appendf("SPIR-V validation error: %s\n", m);
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001850 };
1851 tools.SetMessageConsumer(dumpmsg);
Brian Osman8d09d4a2020-11-24 15:51:06 -05001852
1853 // Verify that the SPIR-V we produced is valid. At runtime, we will abort() with a message
1854 // explaining the error. In standalone mode (skslc), we will send the message, plus the
1855 // entire disassembled SPIR-V (for easier context & debugging) as *our* error message.
1856 result = tools.Validate((const uint32_t*) data.c_str(), data.size() / 4);
1857
1858 if (!result) {
1859#if defined(SKSL_STANDALONE)
1860 // Convert the string-stream to a SPIR-V disassembly.
1861 std::string disassembly;
1862 if (tools.Disassemble((const uint32_t*)data.data(), data.size() / 4, &disassembly)) {
1863 errors.append(disassembly);
1864 }
1865 this->error(-1, errors);
1866#else
1867 SkDEBUGFAILF("%s", errors.c_str());
1868#endif
1869 }
Ethan Nicholas762466e2017-06-29 10:03:38 -04001870 out.write(data.c_str(), data.size());
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001871 }
1872#else
Brian Osman88cda172020-10-09 12:05:16 -04001873 AutoSource as(this, program.fSource.get());
Brian Osman8b43dad2020-10-09 13:31:42 -04001874 SPIRVCodeGenerator cg(fContext.get(), &program, this, &out);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001875 bool result = cg.generateCode();
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001876#endif
Ethan Nicholasce33f102016-12-09 17:22:59 -05001877 return result;
1878}
1879
Ethan Nicholas00543112018-07-31 09:44:36 -04001880bool Compiler::toSPIRV(Program& program, String* out) {
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001881 StringStream buffer;
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001882 bool result = this->toSPIRV(program, buffer);
1883 if (result) {
Ethan Nicholas762466e2017-06-29 10:03:38 -04001884 *out = buffer.str();
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001885 }
1886 return result;
1887}
1888
Ethan Nicholas00543112018-07-31 09:44:36 -04001889bool Compiler::toGLSL(Program& program, OutputStream& out) {
Leon Scrogginsb66214e2021-02-11 17:14:18 -05001890 ATRACE_ANDROID_FRAMEWORK("SkSL::Compiler::toGLSL");
Brian Osman88cda172020-10-09 12:05:16 -04001891 AutoSource as(this, program.fSource.get());
Ethan Nicholas26a9aad2018-03-27 14:10:52 -04001892 GLSLCodeGenerator cg(fContext.get(), &program, this, &out);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001893 bool result = cg.generateCode();
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001894 return result;
1895}
1896
Ethan Nicholas00543112018-07-31 09:44:36 -04001897bool Compiler::toGLSL(Program& program, String* out) {
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001898 StringStream buffer;
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001899 bool result = this->toGLSL(program, buffer);
1900 if (result) {
Ethan Nicholas762466e2017-06-29 10:03:38 -04001901 *out = buffer.str();
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001902 }
1903 return result;
1904}
1905
Brian Osmanc0243912020-02-19 15:35:26 -05001906bool Compiler::toHLSL(Program& program, String* out) {
1907 String spirv;
1908 if (!this->toSPIRV(program, &spirv)) {
1909 return false;
1910 }
1911
1912 return SPIRVtoHLSL(spirv, out);
1913}
1914
Ethan Nicholas00543112018-07-31 09:44:36 -04001915bool Compiler::toMetal(Program& program, OutputStream& out) {
Ethan Nicholas26a9aad2018-03-27 14:10:52 -04001916 MetalCodeGenerator cg(fContext.get(), &program, this, &out);
Ethan Nicholascc305772017-10-13 16:17:45 -04001917 bool result = cg.generateCode();
Ethan Nicholascc305772017-10-13 16:17:45 -04001918 return result;
1919}
1920
Ethan Nicholas00543112018-07-31 09:44:36 -04001921bool Compiler::toMetal(Program& program, String* out) {
Timothy Liangb8eeb802018-07-23 16:46:16 -04001922 StringStream buffer;
1923 bool result = this->toMetal(program, buffer);
1924 if (result) {
1925 *out = buffer.str();
1926 }
1927 return result;
1928}
1929
Greg Daniela28ea672020-09-25 11:12:56 -04001930#if defined(SKSL_STANDALONE) || GR_TEST_UTILS
Ethan Nicholas00543112018-07-31 09:44:36 -04001931bool Compiler::toCPP(Program& program, String name, OutputStream& out) {
Brian Osman88cda172020-10-09 12:05:16 -04001932 AutoSource as(this, program.fSource.get());
Ethan Nicholas26a9aad2018-03-27 14:10:52 -04001933 CPPCodeGenerator cg(fContext.get(), &program, this, name, &out);
Ethan Nicholas762466e2017-06-29 10:03:38 -04001934 bool result = cg.generateCode();
Ethan Nicholas762466e2017-06-29 10:03:38 -04001935 return result;
1936}
1937
Ethan Nicholas00543112018-07-31 09:44:36 -04001938bool Compiler::toH(Program& program, String name, OutputStream& out) {
Brian Osman88cda172020-10-09 12:05:16 -04001939 AutoSource as(this, program.fSource.get());
Ethan Nicholas26a9aad2018-03-27 14:10:52 -04001940 HCodeGenerator cg(fContext.get(), &program, this, name, &out);
Ethan Nicholas762466e2017-06-29 10:03:38 -04001941 bool result = cg.generateCode();
Ethan Nicholas00543112018-07-31 09:44:36 -04001942 return result;
1943}
Greg Daniela28ea672020-09-25 11:12:56 -04001944#endif // defined(SKSL_STANDALONE) || GR_TEST_UTILS
Ethan Nicholas00543112018-07-31 09:44:36 -04001945
Ethan Nicholas2a479a52020-08-18 16:29:45 -04001946#endif // defined(SKSL_STANDALONE) || SK_SUPPORT_GPU
Brian Osman2e29ab52019-09-20 12:19:11 -04001947
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001948Position Compiler::position(int offset) {
Ethan Nicholas3c729892020-12-07 12:47:17 -05001949 if (fSource && offset >= 0) {
1950 int line = 1;
1951 int column = 1;
1952 for (int i = 0; i < offset; i++) {
1953 if ((*fSource)[i] == '\n') {
1954 ++line;
1955 column = 1;
1956 }
1957 else {
1958 ++column;
1959 }
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001960 }
Ethan Nicholas3c729892020-12-07 12:47:17 -05001961 return Position(line, column);
1962 } else {
1963 return Position(-1, -1);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001964 }
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001965}
1966
1967void Compiler::error(int offset, String msg) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001968 fErrorCount++;
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001969 Position pos = this->position(offset);
John Stiles8d3642e2021-01-22 09:50:04 -05001970 fErrorTextLength.push_back(fErrorText.length());
Ethan Nicholas3c729892020-12-07 12:47:17 -05001971 fErrorText += "error: " + (pos.fLine >= 1 ? to_string(pos.fLine) + ": " : "") + msg + "\n";
ethannicholasb3058bd2016-07-01 08:22:01 -07001972}
1973
John Stiles8d3642e2021-01-22 09:50:04 -05001974void Compiler::setErrorCount(int c) {
1975 if (c < fErrorCount) {
1976 fErrorText.resize(fErrorTextLength[c]);
1977 fErrorTextLength.resize(c);
1978 fErrorCount = c;
1979 }
1980}
1981
Ethan Nicholas95046142021-01-07 10:57:27 -05001982String Compiler::errorText(bool showCount) {
1983 if (showCount) {
1984 this->writeErrorCount();
1985 }
Ethan Nicholas00543112018-07-31 09:44:36 -04001986 fErrorCount = 0;
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001987 String result = fErrorText;
Ethan Nicholas95046142021-01-07 10:57:27 -05001988 fErrorText = "";
ethannicholasb3058bd2016-07-01 08:22:01 -07001989 return result;
1990}
1991
1992void Compiler::writeErrorCount() {
1993 if (fErrorCount) {
1994 fErrorText += to_string(fErrorCount) + " error";
1995 if (fErrorCount > 1) {
1996 fErrorText += "s";
1997 }
1998 fErrorText += "\n";
1999 }
2000}
2001
John Stilesa6841be2020-08-06 14:11:56 -04002002} // namespace SkSL