blob: d10eb1814964fc3854a5cde3656a0eefe50bd519 [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 Stilesa935c3f2021-02-25 10:35:49 -050090class AutoProgramConfig {
91public:
92 AutoProgramConfig(std::shared_ptr<Context>& context, ProgramConfig* config)
93 : fContext(context.get()) {
94 SkASSERT(!fContext->fConfig);
95 fContext->fConfig = config;
96 }
97
98 ~AutoProgramConfig() {
99 fContext->fConfig = nullptr;
100 }
101
102 Context* fContext;
103};
104
John Stilesd6a5f4492021-02-11 15:46:11 -0500105Compiler::Compiler(const ShaderCapsClass* caps)
John Stilesc1a98b82021-02-24 13:35:02 -0500106 : fContext(std::make_shared<Context>(/*errors=*/*this, *caps))
John Stiles7b920442020-12-17 10:43:41 -0500107 , fInliner(fContext.get())
Brian Osman0006ad02020-11-18 15:38:39 -0500108 , fErrorCount(0) {
John Stilesc1a98b82021-02-24 13:35:02 -0500109 SkASSERT(caps);
John Stiles7c3515b2020-10-16 18:38:39 -0400110 fRootSymbolTable = std::make_shared<SymbolTable>(this, /*builtin=*/true);
Brian Osmanb06301e2020-11-06 11:45:36 -0500111 fPrivateSymbolTable = std::make_shared<SymbolTable>(fRootSymbolTable, /*builtin=*/true);
John Stilesc1a98b82021-02-24 13:35:02 -0500112 fIRGenerator = std::make_unique<IRGenerator>(fContext.get());
ethannicholasb3058bd2016-07-01 08:22:01 -0700113
John Stiles54e7c052021-01-11 14:22:36 -0500114#define TYPE(t) fContext->fTypes.f ## t .get()
ethannicholasb3058bd2016-07-01 08:22:01 -0700115
Brian Osmanb06301e2020-11-06 11:45:36 -0500116 const SkSL::Symbol* rootTypes[] = {
117 TYPE(Void),
Brian Salomonbf7b6202016-11-11 16:08:03 -0500118
Brian Osmanb06301e2020-11-06 11:45:36 -0500119 TYPE( Float), TYPE( Float2), TYPE( Float3), TYPE( Float4),
120 TYPE( Half), TYPE( Half2), TYPE( Half3), TYPE( Half4),
121 TYPE( Int), TYPE( Int2), TYPE( Int3), TYPE( Int4),
Brian Osmanb06301e2020-11-06 11:45:36 -0500122 TYPE( Bool), TYPE( Bool2), TYPE( Bool3), TYPE( Bool4),
Brian Salomon2a51de82016-11-16 12:06:01 -0500123
Brian Osmanc0f2b642020-12-22 13:35:55 -0500124 TYPE(Float2x2), TYPE(Float3x3), TYPE(Float4x4),
Brian Osmanc63f4312020-12-23 11:44:14 -0500125 TYPE( Half2x2), TYPE( Half3x3), TYPE(Half4x4),
Greg Daniel64773e62016-11-22 09:44:03 -0500126
Brian Osmanc63f4312020-12-23 11:44:14 -0500127 TYPE(SquareMat), TYPE(SquareHMat),
ethannicholasb3058bd2016-07-01 08:22:01 -0700128
Brian Osman20fad322020-12-23 12:42:33 -0500129 TYPE(GenType), TYPE(GenHType), TYPE(GenIType), TYPE(GenBType),
130 TYPE(Vec), TYPE(HVec), TYPE(IVec), TYPE(BVec),
Brian Osmanb06301e2020-11-06 11:45:36 -0500131
132 TYPE(FragmentProcessor),
133 };
134
135 const SkSL::Symbol* privateTypes[] = {
Brian Osman20fad322020-12-23 12:42:33 -0500136 TYPE( UInt), TYPE( UInt2), TYPE( UInt3), TYPE( UInt4),
137 TYPE( Short), TYPE( Short2), TYPE( Short3), TYPE( Short4),
138 TYPE(UShort), TYPE(UShort2), TYPE(UShort3), TYPE(UShort4),
139 TYPE( Byte), TYPE( Byte2), TYPE( Byte3), TYPE( Byte4),
140 TYPE( UByte), TYPE( UByte2), TYPE( UByte3), TYPE( UByte4),
141
142 TYPE(GenUType), TYPE(UVec),
143 TYPE(SVec), TYPE(USVec), TYPE(ByteVec), TYPE(UByteVec),
144
Brian Osmanc0f2b642020-12-22 13:35:55 -0500145 TYPE(Float2x3), TYPE(Float2x4),
146 TYPE(Float3x2), TYPE(Float3x4),
147 TYPE(Float4x2), TYPE(Float4x3),
148
Brian Osmanc63f4312020-12-23 11:44:14 -0500149 TYPE(Half2x3), TYPE(Half2x4),
150 TYPE(Half3x2), TYPE(Half3x4),
151 TYPE(Half4x2), TYPE(Half4x3),
152
Brian Osmanc0f2b642020-12-22 13:35:55 -0500153 TYPE(Mat), TYPE(HMat),
154
Brian Osmanb06301e2020-11-06 11:45:36 -0500155 TYPE(Sampler1D), TYPE(Sampler2D), TYPE(Sampler3D),
156 TYPE(SamplerExternalOES),
Brian Osmanb06301e2020-11-06 11:45:36 -0500157 TYPE(Sampler2DRect),
Brian Osmanb06301e2020-11-06 11:45:36 -0500158
159 TYPE(ISampler2D),
Brian Osmanb06301e2020-11-06 11:45:36 -0500160 TYPE(SubpassInput), TYPE(SubpassInputMS),
161
Brian Osmanb06301e2020-11-06 11:45:36 -0500162 TYPE(Sampler),
163 TYPE(Texture2D),
164 };
165
166 for (const SkSL::Symbol* type : rootTypes) {
167 fRootSymbolTable->addWithoutOwnership(type);
168 }
169 for (const SkSL::Symbol* type : privateTypes) {
170 fPrivateSymbolTable->addWithoutOwnership(type);
171 }
172
173#undef TYPE
ethannicholasb3058bd2016-07-01 08:22:01 -0700174
Brian Osman3887a012020-09-30 13:22:27 -0400175 // sk_Caps is "builtin", but all references to it are resolved to Settings, so we don't need to
176 // treat it as builtin (ie, no need to clone it into the Program).
Brian Osmanb06301e2020-11-06 11:45:36 -0500177 fPrivateSymbolTable->add(
178 std::make_unique<Variable>(/*offset=*/-1,
John Stiles586df952020-11-12 18:27:13 -0500179 fIRGenerator->fModifiers->addToPool(Modifiers()),
Brian Osmanb06301e2020-11-06 11:45:36 -0500180 "sk_Caps",
John Stiles54e7c052021-01-11 14:22:36 -0500181 fContext->fTypes.fSkCaps.get(),
Brian Osmanb06301e2020-11-06 11:45:36 -0500182 /*builtin=*/false,
183 Variable::Storage::kGlobal));
Ethan Nicholas3605ace2016-11-21 15:59:48 -0500184
Brian Osman3d87e9f2020-10-08 11:50:22 -0400185 fRootModule = {fRootSymbolTable, /*fIntrinsics=*/nullptr};
Brian Osmanb06301e2020-11-06 11:45:36 -0500186 fPrivateModule = {fPrivateSymbolTable, /*fIntrinsics=*/nullptr};
ethannicholasb3058bd2016-07-01 08:22:01 -0700187}
188
John Stilesdd13dba2020-10-29 10:45:34 -0400189Compiler::~Compiler() {}
ethannicholasb3058bd2016-07-01 08:22:01 -0700190
Brian Osman56269982020-11-20 12:38:07 -0500191const ParsedModule& Compiler::loadGPUModule() {
192 if (!fGPUModule.fSymbols) {
John Stilesdbd4e6f2021-02-16 13:29:15 -0500193 fGPUModule = this->parseModule(ProgramKind::kFragment, MODULE_DATA(gpu), fPrivateModule);
Brian Osman56269982020-11-20 12:38:07 -0500194 }
195 return fGPUModule;
196}
197
198const ParsedModule& Compiler::loadFragmentModule() {
199 if (!fFragmentModule.fSymbols) {
John Stilesdbd4e6f2021-02-16 13:29:15 -0500200 fFragmentModule = this->parseModule(ProgramKind::kFragment, MODULE_DATA(frag),
Brian Osman56269982020-11-20 12:38:07 -0500201 this->loadGPUModule());
202 }
203 return fFragmentModule;
204}
205
206const ParsedModule& Compiler::loadVertexModule() {
207 if (!fVertexModule.fSymbols) {
John Stilesdbd4e6f2021-02-16 13:29:15 -0500208 fVertexModule = this->parseModule(ProgramKind::kVertex, MODULE_DATA(vert),
Brian Osman56269982020-11-20 12:38:07 -0500209 this->loadGPUModule());
210 }
211 return fVertexModule;
212}
213
Brian Osman88cda172020-10-09 12:05:16 -0400214const ParsedModule& Compiler::loadGeometryModule() {
Brian Osman3d87e9f2020-10-08 11:50:22 -0400215 if (!fGeometryModule.fSymbols) {
John Stilesdbd4e6f2021-02-16 13:29:15 -0500216 fGeometryModule = this->parseModule(ProgramKind::kGeometry, MODULE_DATA(geom),
Brian Osman56269982020-11-20 12:38:07 -0500217 this->loadGPUModule());
Ethan Nicholasc18bb512020-07-28 14:46:53 -0400218 }
Brian Osman88cda172020-10-09 12:05:16 -0400219 return fGeometryModule;
Ethan Nicholasc18bb512020-07-28 14:46:53 -0400220}
221
Brian Osman88cda172020-10-09 12:05:16 -0400222const ParsedModule& Compiler::loadFPModule() {
Brian Osman3d87e9f2020-10-08 11:50:22 -0400223 if (!fFPModule.fSymbols) {
John Stilesdbd4e6f2021-02-16 13:29:15 -0500224 fFPModule = this->parseModule(ProgramKind::kFragmentProcessor, MODULE_DATA(fp),
Brian Osman56269982020-11-20 12:38:07 -0500225 this->loadGPUModule());
Brian Osman8e2ef022020-09-30 13:26:43 -0400226 }
Brian Osman88cda172020-10-09 12:05:16 -0400227 return fFPModule;
Brian Osman8e2ef022020-09-30 13:26:43 -0400228}
229
Brian Osmanb06301e2020-11-06 11:45:36 -0500230const ParsedModule& Compiler::loadPublicModule() {
231 if (!fPublicModule.fSymbols) {
John Stilesdbd4e6f2021-02-16 13:29:15 -0500232 fPublicModule = this->parseModule(ProgramKind::kGeneric, MODULE_DATA(public), fRootModule);
Brian Osmanb06301e2020-11-06 11:45:36 -0500233 }
234 return fPublicModule;
235}
236
Brian Osman91946752020-12-21 13:20:40 -0500237const ParsedModule& Compiler::loadRuntimeEffectModule() {
238 if (!fRuntimeEffectModule.fSymbols) {
John Stilesdbd4e6f2021-02-16 13:29:15 -0500239 fRuntimeEffectModule = this->parseModule(ProgramKind::kRuntimeEffect, MODULE_DATA(runtime),
Brian Osman91946752020-12-21 13:20:40 -0500240 this->loadPublicModule());
Brian Osmanf1319c32020-10-13 09:34:23 -0400241
Brian Osman91946752020-12-21 13:20:40 -0500242 // Add some aliases to the runtime effect module so that it's friendlier, and more like GLSL
John Stiles54e7c052021-01-11 14:22:36 -0500243 fRuntimeEffectModule.fSymbols->addAlias("shader", fContext->fTypes.fFragmentProcessor.get());
Brian Osmanf1319c32020-10-13 09:34:23 -0400244
John Stiles54e7c052021-01-11 14:22:36 -0500245 fRuntimeEffectModule.fSymbols->addAlias("vec2", fContext->fTypes.fFloat2.get());
246 fRuntimeEffectModule.fSymbols->addAlias("vec3", fContext->fTypes.fFloat3.get());
247 fRuntimeEffectModule.fSymbols->addAlias("vec4", fContext->fTypes.fFloat4.get());
Brian Osmanf1319c32020-10-13 09:34:23 -0400248
John Stiles54e7c052021-01-11 14:22:36 -0500249 fRuntimeEffectModule.fSymbols->addAlias("bvec2", fContext->fTypes.fBool2.get());
250 fRuntimeEffectModule.fSymbols->addAlias("bvec3", fContext->fTypes.fBool3.get());
251 fRuntimeEffectModule.fSymbols->addAlias("bvec4", fContext->fTypes.fBool4.get());
Brian Osmanf1319c32020-10-13 09:34:23 -0400252
John Stiles54e7c052021-01-11 14:22:36 -0500253 fRuntimeEffectModule.fSymbols->addAlias("mat2", fContext->fTypes.fFloat2x2.get());
254 fRuntimeEffectModule.fSymbols->addAlias("mat3", fContext->fTypes.fFloat3x3.get());
255 fRuntimeEffectModule.fSymbols->addAlias("mat4", fContext->fTypes.fFloat4x4.get());
Ethan Nicholasc18bb512020-07-28 14:46:53 -0400256 }
Brian Osman91946752020-12-21 13:20:40 -0500257 return fRuntimeEffectModule;
Ethan Nicholasc18bb512020-07-28 14:46:53 -0400258}
259
John Stilesdbd4e6f2021-02-16 13:29:15 -0500260const ParsedModule& Compiler::moduleForProgramKind(ProgramKind kind) {
Brian Osman88cda172020-10-09 12:05:16 -0400261 switch (kind) {
John Stilesdbd4e6f2021-02-16 13:29:15 -0500262 case ProgramKind::kVertex: return this->loadVertexModule(); break;
263 case ProgramKind::kFragment: return this->loadFragmentModule(); break;
264 case ProgramKind::kGeometry: return this->loadGeometryModule(); break;
265 case ProgramKind::kFragmentProcessor: return this->loadFPModule(); break;
266 case ProgramKind::kRuntimeEffect: return this->loadRuntimeEffectModule(); break;
267 case ProgramKind::kGeneric: return this->loadPublicModule(); break;
Brian Osman88cda172020-10-09 12:05:16 -0400268 }
269 SkUNREACHABLE;
Ethan Nicholasc18bb512020-07-28 14:46:53 -0400270}
271
John Stilesdbd4e6f2021-02-16 13:29:15 -0500272LoadedModule Compiler::loadModule(ProgramKind kind,
Brian Osman3d87e9f2020-10-08 11:50:22 -0400273 ModuleData data,
John Stilesa935c3f2021-02-25 10:35:49 -0500274 std::shared_ptr<SymbolTable> base,
275 bool dehydrate) {
276 if (dehydrate) {
277 // NOTE: This is a workaround. When dehydrating includes, skslc doesn't know which module
278 // it's preparing, nor what the correct base module is. We can't use 'Root', because many
279 // GPU intrinsics reference private types, like samplers or textures. Today, 'Private' does
280 // contain the union of all known types, so this is safe. If we ever have types that only
281 // exist in 'Public' (for example), this logic needs to be smarter (by choosing the correct
282 // base for the module we're compiling).
Brian Osmanb06301e2020-11-06 11:45:36 -0500283 base = fPrivateSymbolTable;
Brian Osman3d87e9f2020-10-08 11:50:22 -0400284 }
John Stilesa935c3f2021-02-25 10:35:49 -0500285 SkASSERT(base);
286
287 // Built-in modules always use default program settings.
288 ProgramConfig config;
289 config.fKind = kind;
290 config.fSettings.fReplaceSettings = !dehydrate;
291 AutoProgramConfig autoConfig(fContext, &config);
Brian Osman3d87e9f2020-10-08 11:50:22 -0400292
293#if defined(SKSL_STANDALONE)
294 SkASSERT(data.fPath);
295 std::ifstream in(data.fPath);
Brian Osmane498b3c2020-09-23 14:42:11 -0400296 std::unique_ptr<String> text = std::make_unique<String>(std::istreambuf_iterator<char>(in),
297 std::istreambuf_iterator<char>());
Ethan Nicholasb33fa3f2020-08-06 13:00:19 -0400298 if (in.rdstate()) {
Brian Osman3d87e9f2020-10-08 11:50:22 -0400299 printf("error reading %s\n", data.fPath);
Ethan Nicholasb33fa3f2020-08-06 13:00:19 -0400300 abort();
301 }
Brian Osmane498b3c2020-09-23 14:42:11 -0400302 const String* source = fRootSymbolTable->takeOwnershipOfString(std::move(text));
Brian Osman88cda172020-10-09 12:05:16 -0400303 AutoSource as(this, source);
John Stilesd1204642021-02-17 16:30:02 -0500304
John Stiles881a10c2020-09-19 10:13:24 -0400305 SkASSERT(fIRGenerator->fCanInline);
306 fIRGenerator->fCanInline = false;
John Stilesd1204642021-02-17 16:30:02 -0500307
Brian Osman88cda172020-10-09 12:05:16 -0400308 ParsedModule baseModule = {base, /*fIntrinsics=*/nullptr};
John Stilesd1204642021-02-17 16:30:02 -0500309 IRGenerator::IRBundle ir = fIRGenerator->convertProgram(baseModule, /*isBuiltinCode=*/true,
310 source->c_str(), source->length(),
311 /*externalFunctions=*/nullptr);
Brian Osman133724c2020-10-28 14:14:39 -0400312 SkASSERT(ir.fSharedElements.empty());
Brian Osman0006ad02020-11-18 15:38:39 -0500313 LoadedModule module = { kind, std::move(ir.fSymbolTable), std::move(ir.fElements) };
John Stiles881a10c2020-09-19 10:13:24 -0400314 fIRGenerator->fCanInline = true;
Ethan Nicholas8da1e652019-05-24 11:01:59 -0400315 if (this->fErrorCount) {
316 printf("Unexpected errors: %s\n", this->fErrorText.c_str());
Brian Osman3d87e9f2020-10-08 11:50:22 -0400317 SkDEBUGFAILF("%s %s\n", data.fPath, this->fErrorText.c_str());
Ethan Nicholas8da1e652019-05-24 11:01:59 -0400318 }
Brian Osman88cda172020-10-09 12:05:16 -0400319 fModifiers.push_back(std::move(ir.fModifiers));
Brian Osman3d87e9f2020-10-08 11:50:22 -0400320#else
321 SkASSERT(data.fData && (data.fSize != 0));
322 Rehydrator rehydrator(fContext.get(), fIRGenerator->fModifiers.get(), base, this,
323 data.fData, data.fSize);
Brian Osman0006ad02020-11-18 15:38:39 -0500324 LoadedModule module = { kind, rehydrator.symbolTable(), rehydrator.elements() };
Brian Osman3d87e9f2020-10-08 11:50:22 -0400325 fModifiers.push_back(fIRGenerator->releaseModifiers());
326#endif
327
328 return module;
329}
330
John Stilesdbd4e6f2021-02-16 13:29:15 -0500331ParsedModule Compiler::parseModule(ProgramKind kind, ModuleData data, const ParsedModule& base) {
John Stilesa935c3f2021-02-25 10:35:49 -0500332 LoadedModule module = this->loadModule(kind, data, base.fSymbols, /*dehydrate=*/false);
Brian Osman0006ad02020-11-18 15:38:39 -0500333 this->optimize(module);
Brian Osman3d87e9f2020-10-08 11:50:22 -0400334
335 // For modules that just declare (but don't define) intrinsic functions, there will be no new
336 // program elements. In that case, we can share our parent's intrinsic map:
Brian Osman0006ad02020-11-18 15:38:39 -0500337 if (module.fElements.empty()) {
338 return {module.fSymbols, base.fIntrinsics};
Brian Osman3d87e9f2020-10-08 11:50:22 -0400339 }
340
341 auto intrinsics = std::make_shared<IRIntrinsicMap>(base.fIntrinsics.get());
342
343 // Now, transfer all of the program elements to an intrinsic map. This maps certain types of
344 // global objects to the declaring ProgramElement.
Brian Osman0006ad02020-11-18 15:38:39 -0500345 for (std::unique_ptr<ProgramElement>& element : module.fElements) {
Brian Osman3d87e9f2020-10-08 11:50:22 -0400346 switch (element->kind()) {
347 case ProgramElement::Kind::kFunction: {
348 const FunctionDefinition& f = element->as<FunctionDefinition>();
Ethan Nicholas0a5d0962020-10-14 13:33:18 -0400349 SkASSERT(f.declaration().isBuiltin());
350 intrinsics->insertOrDie(f.declaration().description(), std::move(element));
Brian Osman3d87e9f2020-10-08 11:50:22 -0400351 break;
352 }
John Stiles569249b2020-11-03 12:18:22 -0500353 case ProgramElement::Kind::kFunctionPrototype: {
354 // These are already in the symbol table.
355 break;
356 }
Brian Osman3d87e9f2020-10-08 11:50:22 -0400357 case ProgramElement::Kind::kEnum: {
358 const Enum& e = element->as<Enum>();
359 SkASSERT(e.isBuiltin());
360 intrinsics->insertOrDie(e.typeName(), std::move(element));
361 break;
362 }
363 case ProgramElement::Kind::kGlobalVar: {
Ethan Nicholasc51f33e2020-10-13 13:49:44 -0400364 const GlobalVarDeclaration& global = element->as<GlobalVarDeclaration>();
365 const Variable& var = global.declaration()->as<VarDeclaration>().var();
366 SkASSERT(var.isBuiltin());
367 intrinsics->insertOrDie(var.name(), std::move(element));
Brian Osman3d87e9f2020-10-08 11:50:22 -0400368 break;
369 }
370 case ProgramElement::Kind::kInterfaceBlock: {
Ethan Nicholaseaf47882020-10-15 10:10:08 -0400371 const Variable& var = element->as<InterfaceBlock>().variable();
372 SkASSERT(var.isBuiltin());
373 intrinsics->insertOrDie(var.name(), std::move(element));
Brian Osman3d87e9f2020-10-08 11:50:22 -0400374 break;
375 }
376 default:
377 printf("Unsupported element: %s\n", element->description().c_str());
378 SkASSERT(false);
379 break;
380 }
381 }
382
Brian Osman0006ad02020-11-18 15:38:39 -0500383 return {module.fSymbols, std::move(intrinsics)};
Ethan Nicholas8da1e652019-05-24 11:01:59 -0400384}
385
John Stilese6150002020-10-05 12:03:53 -0400386void Compiler::scanCFG(CFG* cfg, BlockId blockId, SkBitSet* processedSet) {
ethannicholas22f939e2016-10-13 13:25:34 -0700387 BasicBlock& block = cfg->fBlocks[blockId];
388
389 // compute definitions after this block
Ethan Nicholas86a43402017-01-19 13:32:00 -0500390 DefinitionMap after = block.fBefore;
ethannicholas22f939e2016-10-13 13:25:34 -0700391 for (const BasicBlock::Node& n : block.fNodes) {
John Stilese8a24922021-02-08 17:54:08 -0500392 after.addDefinitions(*fContext, n);
ethannicholas22f939e2016-10-13 13:25:34 -0700393 }
394
395 // propagate definitions to exits
396 for (BlockId exitId : block.fExits) {
Ethan Nicholas26a9aad2018-03-27 14:10:52 -0400397 if (exitId == blockId) {
398 continue;
399 }
ethannicholas22f939e2016-10-13 13:25:34 -0700400 BasicBlock& exit = cfg->fBlocks[exitId];
John Stiles65b48272020-12-22 17:18:34 -0500401 for (const auto& [var, e1] : after) {
John Stiles796cdb72020-10-08 12:06:53 -0400402 std::unique_ptr<Expression>** exitDef = exit.fBefore.find(var);
403 if (!exitDef) {
John Stilese6150002020-10-05 12:03:53 -0400404 // exit has no definition for it, just copy it and reprocess exit block
405 processedSet->reset(exitId);
John Stilese8a24922021-02-08 17:54:08 -0500406 exit.fBefore.set(var, e1);
ethannicholas22f939e2016-10-13 13:25:34 -0700407 } else {
Ethan Nicholas86a43402017-01-19 13:32:00 -0500408 // exit has a (possibly different) value already defined
John Stiles796cdb72020-10-08 12:06:53 -0400409 std::unique_ptr<Expression>* e2 = *exitDef;
ethannicholas22f939e2016-10-13 13:25:34 -0700410 if (e1 != e2) {
John Stilese6150002020-10-05 12:03:53 -0400411 // definition has changed, merge and reprocess the exit block
412 processedSet->reset(exitId);
Ethan Nicholasaf197692017-02-27 13:26:45 -0500413 if (e1 && e2) {
John Stiles796cdb72020-10-08 12:06:53 -0400414 *exitDef = (std::unique_ptr<Expression>*)&fContext->fDefined_Expression;
Ethan Nicholasaf197692017-02-27 13:26:45 -0500415 } else {
John Stiles796cdb72020-10-08 12:06:53 -0400416 *exitDef = nullptr;
Ethan Nicholasaf197692017-02-27 13:26:45 -0500417 }
ethannicholas22f939e2016-10-13 13:25:34 -0700418 }
419 }
John Stiles65b48272020-12-22 17:18:34 -0500420 }
ethannicholas22f939e2016-10-13 13:25:34 -0700421 }
422}
423
Ethan Nicholascb670962017-04-20 19:31:52 -0400424/**
425 * Returns true if assigning to this lvalue has no effect.
426 */
Brian Osman010ce6a2020-10-19 16:34:10 -0400427static bool is_dead(const Expression& lvalue, ProgramUsage* usage) {
Ethan Nicholase6592142020-09-08 10:22:09 -0400428 switch (lvalue.kind()) {
429 case Expression::Kind::kVariableReference:
Brian Osman010ce6a2020-10-19 16:34:10 -0400430 return usage->isDead(*lvalue.as<VariableReference>().variable());
Ethan Nicholase6592142020-09-08 10:22:09 -0400431 case Expression::Kind::kSwizzle:
Brian Osman010ce6a2020-10-19 16:34:10 -0400432 return is_dead(*lvalue.as<Swizzle>().base(), usage);
Ethan Nicholase6592142020-09-08 10:22:09 -0400433 case Expression::Kind::kFieldAccess:
Brian Osman010ce6a2020-10-19 16:34:10 -0400434 return is_dead(*lvalue.as<FieldAccess>().base(), usage);
Ethan Nicholase6592142020-09-08 10:22:09 -0400435 case Expression::Kind::kIndex: {
John Stilesa5a97b42020-08-18 11:19:07 -0400436 const IndexExpression& idx = lvalue.as<IndexExpression>();
Brian Osman010ce6a2020-10-19 16:34:10 -0400437 return is_dead(*idx.base(), usage) &&
Ethan Nicholas2a4952d2020-10-08 15:35:56 -0400438 !idx.index()->hasProperty(Expression::Property::kSideEffects);
Ethan Nicholascb670962017-04-20 19:31:52 -0400439 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400440 case Expression::Kind::kTernary: {
John Stilesa5a97b42020-08-18 11:19:07 -0400441 const TernaryExpression& t = lvalue.as<TernaryExpression>();
Brian Osman010ce6a2020-10-19 16:34:10 -0400442 return !t.test()->hasSideEffects() &&
443 is_dead(*t.ifTrue(), usage) &&
444 is_dead(*t.ifFalse(), usage);
Ethan Nicholasa583b812018-01-18 13:32:11 -0500445 }
Ethan Nicholascb670962017-04-20 19:31:52 -0400446 default:
John Stileseada7bc2021-02-02 16:29:32 -0500447 SkDEBUGFAILF("invalid lvalue: %s\n", lvalue.description().c_str());
Ethan Nicholas2a099da2020-01-02 14:40:54 -0500448 return false;
Ethan Nicholascb670962017-04-20 19:31:52 -0400449 }
450}
ethannicholas22f939e2016-10-13 13:25:34 -0700451
Ethan Nicholascb670962017-04-20 19:31:52 -0400452/**
453 * Returns true if this is an assignment which can be collapsed down to just the right hand side due
454 * to a dead target and lack of side effects on the left hand side.
455 */
Brian Osman010ce6a2020-10-19 16:34:10 -0400456static bool dead_assignment(const BinaryExpression& b, ProgramUsage* usage) {
John Stiles45990502021-02-16 10:55:27 -0500457 if (!b.getOperator().isAssignment()) {
Ethan Nicholascb670962017-04-20 19:31:52 -0400458 return false;
459 }
John Stiles2d4f9592020-10-30 10:29:12 -0400460 return is_dead(*b.left(), usage);
Ethan Nicholascb670962017-04-20 19:31:52 -0400461}
462
John Stiles0ac6c152021-02-10 14:04:24 -0500463/**
464 * Returns true if both expression trees are the same. The left side is expected to be an lvalue.
465 * This only needs to check for trees that can plausibly terminate in a variable, so some basic
466 * candidates like `FloatLiteral` are missing.
467 */
468static bool is_matching_expression_tree(const Expression& left, const Expression& right) {
469 if (left.kind() != right.kind() || left.type() != right.type()) {
470 return false;
471 }
472
473 switch (left.kind()) {
474 case Expression::Kind::kIntLiteral:
475 return left.as<IntLiteral>().value() == right.as<IntLiteral>().value();
476
477 case Expression::Kind::kFieldAccess:
478 return left.as<FieldAccess>().fieldIndex() == right.as<FieldAccess>().fieldIndex() &&
479 is_matching_expression_tree(*left.as<FieldAccess>().base(),
480 *right.as<FieldAccess>().base());
481
482 case Expression::Kind::kIndex:
483 return is_matching_expression_tree(*left.as<IndexExpression>().index(),
484 *right.as<IndexExpression>().index()) &&
485 is_matching_expression_tree(*left.as<IndexExpression>().base(),
486 *right.as<IndexExpression>().base());
487
488 case Expression::Kind::kSwizzle:
489 return left.as<Swizzle>().components() == right.as<Swizzle>().components() &&
490 is_matching_expression_tree(*left.as<Swizzle>().base(),
491 *right.as<Swizzle>().base());
492
493 case Expression::Kind::kVariableReference:
494 return left.as<VariableReference>().variable() ==
495 right.as<VariableReference>().variable();
496
497 default:
498 return false;
499 }
500}
501
502static bool self_assignment(const BinaryExpression& b) {
John Stiles45990502021-02-16 10:55:27 -0500503 return b.getOperator().kind() == Token::Kind::TK_EQ &&
John Stiles0ac6c152021-02-10 14:04:24 -0500504 is_matching_expression_tree(*b.left(), *b.right());
505}
506
Ethan Nicholascb670962017-04-20 19:31:52 -0400507void Compiler::computeDataFlow(CFG* cfg) {
John Stilese8a24922021-02-08 17:54:08 -0500508 cfg->fBlocks[cfg->fStart].fBefore.computeStartState(*cfg);
John Stilese6150002020-10-05 12:03:53 -0400509
510 // We set bits in the "processed" set after a block has been scanned.
511 SkBitSet processedSet(cfg->fBlocks.size());
512 while (SkBitSet::OptionalIndex blockId = processedSet.findFirstUnset()) {
513 processedSet.set(*blockId);
514 this->scanCFG(cfg, *blockId, &processedSet);
ethannicholas22f939e2016-10-13 13:25:34 -0700515 }
Ethan Nicholascb670962017-04-20 19:31:52 -0400516}
517
518/**
519 * Attempts to replace the expression pointed to by iter with a new one (in both the CFG and the
520 * IR). If the expression can be cleanly removed, returns true and updates the iterator to point to
521 * the newly-inserted element. Otherwise updates only the IR and returns false (and the CFG will
522 * need to be regenerated).
523 */
John Stilesafbf8992020-08-18 10:08:21 -0400524static bool try_replace_expression(BasicBlock* b,
525 std::vector<BasicBlock::Node>::iterator* iter,
526 std::unique_ptr<Expression>* newExpression) {
Ethan Nicholascb670962017-04-20 19:31:52 -0400527 std::unique_ptr<Expression>* target = (*iter)->expression();
528 if (!b->tryRemoveExpression(iter)) {
529 *target = std::move(*newExpression);
530 return false;
531 }
532 *target = std::move(*newExpression);
533 return b->tryInsertExpression(iter, target);
534}
535
536/**
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400537 * Returns true if the expression is a constant numeric literal with the specified value, or a
538 * constant vector with all elements equal to the specified value.
Ethan Nicholascb670962017-04-20 19:31:52 -0400539 */
Ethan Nicholasa3f22f12020-10-01 12:13:17 -0400540template <typename T = SKSL_FLOAT>
John Stiles9d944232020-08-19 09:56:49 -0400541static bool is_constant(const Expression& expr, T value) {
Ethan Nicholase6592142020-09-08 10:22:09 -0400542 switch (expr.kind()) {
543 case Expression::Kind::kIntLiteral:
Ethan Nicholase96cdd12020-09-28 16:27:18 -0400544 return expr.as<IntLiteral>().value() == value;
John Stiles9d944232020-08-19 09:56:49 -0400545
Ethan Nicholase6592142020-09-08 10:22:09 -0400546 case Expression::Kind::kFloatLiteral:
Ethan Nicholasa3f22f12020-10-01 12:13:17 -0400547 return expr.as<FloatLiteral>().value() == value;
John Stiles9d944232020-08-19 09:56:49 -0400548
Ethan Nicholase6592142020-09-08 10:22:09 -0400549 case Expression::Kind::kConstructor: {
John Stiles9d944232020-08-19 09:56:49 -0400550 const Constructor& constructor = expr.as<Constructor>();
551 if (constructor.isCompileTimeConstant()) {
Ethan Nicholas30d30222020-09-11 12:27:26 -0400552 const Type& constructorType = constructor.type();
Ethan Nicholas30d30222020-09-11 12:27:26 -0400553 switch (constructorType.typeKind()) {
Ethan Nicholase6592142020-09-08 10:22:09 -0400554 case Type::TypeKind::kVector:
John Stilesbc75ebb2020-11-24 12:04:47 -0500555 if (constructor.componentType().isFloat()) {
556 for (int i = 0; i < constructorType.columns(); ++i) {
John Stiles9d944232020-08-19 09:56:49 -0400557 if (constructor.getFVecComponent(i) != value) {
558 return false;
559 }
John Stilesbc75ebb2020-11-24 12:04:47 -0500560 }
561 return true;
562 } else if (constructor.componentType().isInteger()) {
563 for (int i = 0; i < constructorType.columns(); ++i) {
John Stiles9d944232020-08-19 09:56:49 -0400564 if (constructor.getIVecComponent(i) != value) {
565 return false;
566 }
567 }
John Stilesbc75ebb2020-11-24 12:04:47 -0500568 return true;
Ethan Nicholasd188c182019-06-10 15:55:38 -0400569 }
John Stilesbc75ebb2020-11-24 12:04:47 -0500570 // Other types (e.g. boolean) might occur, but aren't supported here.
571 return false;
John Stiles9d944232020-08-19 09:56:49 -0400572
Ethan Nicholase6592142020-09-08 10:22:09 -0400573 case Type::TypeKind::kScalar:
Ethan Nicholasf70f0442020-09-29 12:41:35 -0400574 SkASSERT(constructor.arguments().size() == 1);
575 return is_constant<T>(*constructor.arguments()[0], value);
John Stiles9d944232020-08-19 09:56:49 -0400576
577 default:
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400578 return false;
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400579 }
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400580 }
581 return false;
582 }
Ethan Nicholascb670962017-04-20 19:31:52 -0400583 default:
584 return false;
585 }
586}
587
588/**
589 * Collapses the binary expression pointed to by iter down to just the right side (in both the IR
590 * and CFG structures).
591 */
John Stilesafbf8992020-08-18 10:08:21 -0400592static void delete_left(BasicBlock* b,
593 std::vector<BasicBlock::Node>::iterator* iter,
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400594 Compiler::OptimizationContext* optimizationContext) {
595 optimizationContext->fUpdated = true;
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400596 std::unique_ptr<Expression>* target = (*iter)->expression();
John Stilesa5a97b42020-08-18 11:19:07 -0400597 BinaryExpression& bin = (*target)->as<BinaryExpression>();
John Stiles2d4f9592020-10-30 10:29:12 -0400598 Expression& left = *bin.left();
599 std::unique_ptr<Expression>& rightPointer = bin.right();
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400600 SkASSERT(!left.hasSideEffects());
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400601 bool result;
John Stiles45990502021-02-16 10:55:27 -0500602 if (bin.getOperator().kind() == Token::Kind::TK_EQ) {
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400603 result = b->tryRemoveLValueBefore(iter, &left);
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400604 } else {
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400605 result = b->tryRemoveExpressionBefore(iter, &left);
Ethan Nicholascb670962017-04-20 19:31:52 -0400606 }
Brian Osman010ce6a2020-10-19 16:34:10 -0400607 // Remove references within LHS.
608 optimizationContext->fUsage->remove(&left);
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400609 *target = std::move(rightPointer);
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400610 if (!result) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400611 optimizationContext->fNeedsRescan = true;
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400612 return;
613 }
614 if (*iter == b->fNodes.begin()) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400615 optimizationContext->fNeedsRescan = true;
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400616 return;
617 }
618 --(*iter);
John Stiles70025e52020-09-28 16:08:58 -0400619 if (!(*iter)->isExpression() || (*iter)->expression() != &rightPointer) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400620 optimizationContext->fNeedsRescan = true;
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400621 return;
622 }
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400623 *iter = b->fNodes.erase(*iter);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400624 SkASSERT((*iter)->expression() == target);
Ethan Nicholascb670962017-04-20 19:31:52 -0400625}
626
627/**
628 * Collapses the binary expression pointed to by iter down to just the left side (in both the IR and
629 * CFG structures).
630 */
John Stilesafbf8992020-08-18 10:08:21 -0400631static void delete_right(BasicBlock* b,
632 std::vector<BasicBlock::Node>::iterator* iter,
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400633 Compiler::OptimizationContext* optimizationContext) {
634 optimizationContext->fUpdated = true;
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400635 std::unique_ptr<Expression>* target = (*iter)->expression();
John Stilesa5a97b42020-08-18 11:19:07 -0400636 BinaryExpression& bin = (*target)->as<BinaryExpression>();
John Stiles2d4f9592020-10-30 10:29:12 -0400637 std::unique_ptr<Expression>& leftPointer = bin.left();
638 Expression& right = *bin.right();
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400639 SkASSERT(!right.hasSideEffects());
Brian Osman010ce6a2020-10-19 16:34:10 -0400640 // Remove references within RHS.
641 optimizationContext->fUsage->remove(&right);
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400642 if (!b->tryRemoveExpressionBefore(iter, &right)) {
643 *target = std::move(leftPointer);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400644 optimizationContext->fNeedsRescan = true;
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400645 return;
Ethan Nicholascb670962017-04-20 19:31:52 -0400646 }
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400647 *target = std::move(leftPointer);
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400648 if (*iter == b->fNodes.begin()) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400649 optimizationContext->fNeedsRescan = true;
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400650 return;
651 }
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400652 --(*iter);
John Stiles70025e52020-09-28 16:08:58 -0400653 if ((!(*iter)->isExpression() || (*iter)->expression() != &leftPointer)) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400654 optimizationContext->fNeedsRescan = true;
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400655 return;
656 }
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400657 *iter = b->fNodes.erase(*iter);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400658 SkASSERT((*iter)->expression() == target);
Ethan Nicholascb670962017-04-20 19:31:52 -0400659}
660
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400661/**
662 * Constructs the specified type using a single argument.
663 */
Ethan Nicholas30d30222020-09-11 12:27:26 -0400664static std::unique_ptr<Expression> construct(const Type* type, std::unique_ptr<Expression> v) {
John Stiles8e3b6be2020-10-13 11:14:08 -0400665 ExpressionArray args;
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400666 args.push_back(std::move(v));
John Stiles54f00492021-02-19 11:46:10 -0500667 return std::make_unique<Constructor>(/*offset=*/-1, *type, std::move(args));
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400668}
669
670/**
671 * Used in the implementations of vectorize_left and vectorize_right. Given a vector type and an
672 * expression x, deletes the expression pointed to by iter and replaces it with <type>(x).
673 */
674static void vectorize(BasicBlock* b,
675 std::vector<BasicBlock::Node>::iterator* iter,
676 const Type& type,
677 std::unique_ptr<Expression>* otherExpression,
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400678 Compiler::OptimizationContext* optimizationContext) {
Ethan Nicholase6592142020-09-08 10:22:09 -0400679 SkASSERT((*(*iter)->expression())->kind() == Expression::Kind::kBinary);
John Stiles9aeed132020-11-24 17:36:06 -0500680 SkASSERT(type.isVector());
681 SkASSERT((*otherExpression)->type().isScalar());
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400682 optimizationContext->fUpdated = true;
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400683 std::unique_ptr<Expression>* target = (*iter)->expression();
684 if (!b->tryRemoveExpression(iter)) {
Ethan Nicholas30d30222020-09-11 12:27:26 -0400685 *target = construct(&type, std::move(*otherExpression));
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400686 optimizationContext->fNeedsRescan = true;
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400687 } else {
Ethan Nicholas30d30222020-09-11 12:27:26 -0400688 *target = construct(&type, std::move(*otherExpression));
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400689 if (!b->tryInsertExpression(iter, target)) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400690 optimizationContext->fNeedsRescan = true;
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400691 }
692 }
693}
694
695/**
696 * Given a binary expression of the form x <op> vec<n>(y), deletes the right side and vectorizes the
697 * left to yield vec<n>(x).
698 */
699static void vectorize_left(BasicBlock* b,
700 std::vector<BasicBlock::Node>::iterator* iter,
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400701 Compiler::OptimizationContext* optimizationContext) {
John Stilesa5a97b42020-08-18 11:19:07 -0400702 BinaryExpression& bin = (*(*iter)->expression())->as<BinaryExpression>();
Brian Osman010ce6a2020-10-19 16:34:10 -0400703 // Remove references within RHS. Vectorization of LHS doesn't change reference counts.
John Stiles2d4f9592020-10-30 10:29:12 -0400704 optimizationContext->fUsage->remove(bin.right().get());
705 vectorize(b, iter, bin.right()->type(), &bin.left(), optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400706}
707
708/**
709 * Given a binary expression of the form vec<n>(x) <op> y, deletes the left side and vectorizes the
710 * right to yield vec<n>(y).
711 */
712static void vectorize_right(BasicBlock* b,
713 std::vector<BasicBlock::Node>::iterator* iter,
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400714 Compiler::OptimizationContext* optimizationContext) {
John Stilesa5a97b42020-08-18 11:19:07 -0400715 BinaryExpression& bin = (*(*iter)->expression())->as<BinaryExpression>();
Brian Osman010ce6a2020-10-19 16:34:10 -0400716 // Remove references within LHS. Vectorization of RHS doesn't change reference counts.
John Stiles2d4f9592020-10-30 10:29:12 -0400717 optimizationContext->fUsage->remove(bin.left().get());
718 vectorize(b, iter, bin.left()->type(), &bin.right(), optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400719}
720
Ethan Nicholascb670962017-04-20 19:31:52 -0400721void Compiler::simplifyExpression(DefinitionMap& definitions,
722 BasicBlock& b,
723 std::vector<BasicBlock::Node>::iterator* iter,
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400724 OptimizationContext* optimizationContext) {
Ethan Nicholascb670962017-04-20 19:31:52 -0400725 Expression* expr = (*iter)->expression()->get();
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400726 SkASSERT(expr);
John Stiles108bbe22020-11-18 11:10:38 -0500727
Ethan Nicholascb670962017-04-20 19:31:52 -0400728 if ((*iter)->fConstantPropagation) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400729 std::unique_ptr<Expression> optimized = expr->constantPropagate(*fIRGenerator,
730 definitions);
Ethan Nicholascb670962017-04-20 19:31:52 -0400731 if (optimized) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400732 optimizationContext->fUpdated = true;
Ethan Nicholas30d30222020-09-11 12:27:26 -0400733 optimized = fIRGenerator->coerce(std::move(optimized), expr->type());
Ethan Nicholas1d881522020-09-11 09:32:54 -0400734 SkASSERT(optimized);
Brian Osman010ce6a2020-10-19 16:34:10 -0400735 // Remove references within 'expr', add references within 'optimized'
736 optimizationContext->fUsage->replace(expr, optimized.get());
Ethan Nicholascb670962017-04-20 19:31:52 -0400737 if (!try_replace_expression(&b, iter, &optimized)) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400738 optimizationContext->fNeedsRescan = true;
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400739 return;
Ethan Nicholascb670962017-04-20 19:31:52 -0400740 }
John Stiles70025e52020-09-28 16:08:58 -0400741 SkASSERT((*iter)->isExpression());
Ethan Nicholascb670962017-04-20 19:31:52 -0400742 expr = (*iter)->expression()->get();
Ethan Nicholascb670962017-04-20 19:31:52 -0400743 }
744 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400745 switch (expr->kind()) {
746 case Expression::Kind::kVariableReference: {
John Stilesa5a97b42020-08-18 11:19:07 -0400747 const VariableReference& ref = expr->as<VariableReference>();
Ethan Nicholas78686922020-10-08 06:46:27 -0400748 const Variable* var = ref.variable();
John Stiles66c53b92021-02-20 08:00:43 -0500749 if (fContext->fConfig->fSettings.fDeadCodeElimination &&
750 ref.refKind() != VariableReference::RefKind::kWrite &&
Ethan Nicholas453f67f2020-10-09 10:43:45 -0400751 ref.refKind() != VariableReference::RefKind::kPointer &&
John Stilese8a24922021-02-08 17:54:08 -0500752 var->storage() == Variable::Storage::kLocal && !definitions.get(var) &&
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400753 optimizationContext->fSilences.find(var) == optimizationContext->fSilences.end()) {
754 optimizationContext->fSilences.insert(var);
Ethan Nicholas82a62d22017-11-07 14:42:10 +0000755 this->error(expr->fOffset,
Ethan Nicholase2c49992020-10-05 11:49:11 -0400756 "'" + var->name() + "' has not been assigned");
Ethan Nicholascb670962017-04-20 19:31:52 -0400757 }
758 break;
759 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400760 case Expression::Kind::kTernary: {
John Stiles403a3632020-08-20 12:11:48 -0400761 TernaryExpression* t = &expr->as<TernaryExpression>();
Ethan Nicholasdd218162020-10-08 05:48:01 -0400762 if (t->test()->is<BoolLiteral>()) {
Ethan Nicholascb670962017-04-20 19:31:52 -0400763 // ternary has a constant test, replace it with either the true or
764 // false branch
Ethan Nicholasdd218162020-10-08 05:48:01 -0400765 if (t->test()->as<BoolLiteral>().value()) {
Brian Osman010ce6a2020-10-19 16:34:10 -0400766 (*iter)->setExpression(std::move(t->ifTrue()), optimizationContext->fUsage);
Ethan Nicholascb670962017-04-20 19:31:52 -0400767 } else {
Brian Osman010ce6a2020-10-19 16:34:10 -0400768 (*iter)->setExpression(std::move(t->ifFalse()), optimizationContext->fUsage);
Ethan Nicholascb670962017-04-20 19:31:52 -0400769 }
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400770 optimizationContext->fUpdated = true;
771 optimizationContext->fNeedsRescan = true;
Ethan Nicholascb670962017-04-20 19:31:52 -0400772 }
773 break;
774 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400775 case Expression::Kind::kBinary: {
John Stiles403a3632020-08-20 12:11:48 -0400776 BinaryExpression* bin = &expr->as<BinaryExpression>();
John Stiles0ac6c152021-02-10 14:04:24 -0500777 if (dead_assignment(*bin, optimizationContext->fUsage) || self_assignment(*bin)) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400778 delete_left(&b, iter, optimizationContext);
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400779 break;
780 }
John Stiles2d4f9592020-10-30 10:29:12 -0400781 Expression& left = *bin->left();
782 Expression& right = *bin->right();
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400783 const Type& leftType = left.type();
784 const Type& rightType = right.type();
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400785 // collapse useless expressions like x * 1 or x + 0
John Stiles9aeed132020-11-24 17:36:06 -0500786 if ((!leftType.isScalar() && !leftType.isVector()) ||
787 (!rightType.isScalar() && !rightType.isVector())) {
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400788 break;
789 }
John Stiles45990502021-02-16 10:55:27 -0500790 switch (bin->getOperator().kind()) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400791 case Token::Kind::TK_STAR:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400792 if (is_constant(left, 1)) {
John Stiles9aeed132020-11-24 17:36:06 -0500793 if (leftType.isVector() && rightType.isScalar()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400794 // float4(1) * x -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400795 vectorize_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400796 } else {
797 // 1 * x -> x
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400798 // 1 * float4(x) -> float4(x)
799 // float4(1) * float4(x) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400800 delete_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400801 }
802 }
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400803 else if (is_constant(left, 0)) {
John Stiles9aeed132020-11-24 17:36:06 -0500804 if (leftType.isScalar() && rightType.isVector() &&
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400805 !right.hasSideEffects()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400806 // 0 * float4(x) -> float4(0)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400807 vectorize_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400808 } else {
809 // 0 * x -> 0
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400810 // float4(0) * x -> float4(0)
811 // float4(0) * float4(x) -> float4(0)
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400812 if (!right.hasSideEffects()) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400813 delete_right(&b, iter, optimizationContext);
Ethan Nicholas51493ee2017-12-11 12:34:33 -0500814 }
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400815 }
Ethan Nicholascb670962017-04-20 19:31:52 -0400816 }
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400817 else if (is_constant(right, 1)) {
John Stiles9aeed132020-11-24 17:36:06 -0500818 if (leftType.isScalar() && rightType.isVector()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400819 // x * float4(1) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400820 vectorize_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400821 } else {
822 // x * 1 -> x
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400823 // float4(x) * 1 -> float4(x)
824 // float4(x) * float4(1) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400825 delete_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400826 }
827 }
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400828 else if (is_constant(right, 0)) {
John Stiles9aeed132020-11-24 17:36:06 -0500829 if (leftType.isVector() && rightType.isScalar() && !left.hasSideEffects()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400830 // float4(x) * 0 -> float4(0)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400831 vectorize_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400832 } else {
833 // x * 0 -> 0
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400834 // x * float4(0) -> float4(0)
835 // float4(x) * float4(0) -> float4(0)
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400836 if (!left.hasSideEffects()) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400837 delete_left(&b, iter, optimizationContext);
Ethan Nicholas51493ee2017-12-11 12:34:33 -0500838 }
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400839 }
Ethan Nicholascb670962017-04-20 19:31:52 -0400840 }
841 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400842 case Token::Kind::TK_PLUS:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400843 if (is_constant(left, 0)) {
John Stiles9aeed132020-11-24 17:36:06 -0500844 if (leftType.isVector() && rightType.isScalar()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400845 // float4(0) + x -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400846 vectorize_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400847 } else {
848 // 0 + x -> x
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400849 // 0 + float4(x) -> float4(x)
850 // float4(0) + float4(x) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400851 delete_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400852 }
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400853 } else if (is_constant(right, 0)) {
John Stiles9aeed132020-11-24 17:36:06 -0500854 if (leftType.isScalar() && rightType.isVector()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400855 // x + float4(0) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400856 vectorize_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400857 } else {
858 // x + 0 -> x
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400859 // float4(x) + 0 -> float4(x)
860 // float4(x) + float4(0) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400861 delete_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400862 }
Ethan Nicholas56e42712017-04-21 10:23:37 -0400863 }
864 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400865 case Token::Kind::TK_MINUS:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400866 if (is_constant(right, 0)) {
John Stiles9aeed132020-11-24 17:36:06 -0500867 if (leftType.isScalar() && rightType.isVector()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400868 // x - float4(0) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400869 vectorize_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400870 } else {
871 // x - 0 -> x
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400872 // float4(x) - 0 -> float4(x)
873 // float4(x) - float4(0) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400874 delete_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400875 }
Ethan Nicholascb670962017-04-20 19:31:52 -0400876 }
877 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400878 case Token::Kind::TK_SLASH:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400879 if (is_constant(right, 1)) {
John Stiles9aeed132020-11-24 17:36:06 -0500880 if (leftType.isScalar() && rightType.isVector()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400881 // x / float4(1) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400882 vectorize_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400883 } else {
884 // x / 1 -> x
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400885 // float4(x) / 1 -> float4(x)
886 // float4(x) / float4(1) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400887 delete_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400888 }
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400889 } else if (is_constant(left, 0)) {
John Stiles9aeed132020-11-24 17:36:06 -0500890 if (leftType.isScalar() && rightType.isVector() &&
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400891 !right.hasSideEffects()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400892 // 0 / float4(x) -> float4(0)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400893 vectorize_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400894 } else {
895 // 0 / x -> 0
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400896 // float4(0) / x -> float4(0)
897 // float4(0) / float4(x) -> float4(0)
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400898 if (!right.hasSideEffects()) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400899 delete_right(&b, iter, optimizationContext);
Ethan Nicholas51493ee2017-12-11 12:34:33 -0500900 }
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400901 }
902 }
903 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400904 case Token::Kind::TK_PLUSEQ:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400905 if (is_constant(right, 0)) {
John Stiles47c0a742021-02-09 09:30:35 -0500906 Analysis::UpdateRefKind(&left, RefKind::kRead);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400907 delete_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400908 }
909 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400910 case Token::Kind::TK_MINUSEQ:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400911 if (is_constant(right, 0)) {
John Stiles47c0a742021-02-09 09:30:35 -0500912 Analysis::UpdateRefKind(&left, RefKind::kRead);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400913 delete_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400914 }
915 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400916 case Token::Kind::TK_STAREQ:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400917 if (is_constant(right, 1)) {
John Stiles47c0a742021-02-09 09:30:35 -0500918 Analysis::UpdateRefKind(&left, RefKind::kRead);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400919 delete_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400920 }
921 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400922 case Token::Kind::TK_SLASHEQ:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400923 if (is_constant(right, 1)) {
John Stiles47c0a742021-02-09 09:30:35 -0500924 Analysis::UpdateRefKind(&left, RefKind::kRead);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400925 delete_right(&b, iter, optimizationContext);
Ethan Nicholascb670962017-04-20 19:31:52 -0400926 }
927 break;
928 default:
929 break;
930 }
Ethan Nicholas409f6f02019-09-17 12:34:39 -0400931 break;
932 }
John Stilesf5c1d042020-11-21 23:26:07 -0500933 case Expression::Kind::kConstructor: {
934 // Find constructors embedded inside constructors and flatten them out where possible.
935 // - float4(float2(1, 2), 3, 4) --> float4(1, 2, 3, 4)
936 // - float4(w, float3(sin(x), cos(y), tan(z))) --> float4(w, sin(x), cos(y), tan(z))
937 // Leave single-argument constructors alone, though. These might be casts or splats.
938 Constructor& c = expr->as<Constructor>();
939 if (c.type().columns() > 1) {
940 // Inspect each constructor argument to see if it's a candidate for flattening.
941 // Remember matched arguments in a bitfield, "argsToOptimize".
942 int argsToOptimize = 0;
943 int currBit = 1;
944 for (const std::unique_ptr<Expression>& arg : c.arguments()) {
945 if (arg->is<Constructor>()) {
946 Constructor& inner = arg->as<Constructor>();
947 if (inner.arguments().size() > 1 &&
948 inner.type().componentType() == c.type().componentType()) {
949 argsToOptimize |= currBit;
950 }
951 }
952 currBit <<= 1;
953 }
954 if (argsToOptimize) {
955 // We found at least one argument that could be flattened out. Re-walk the
956 // constructor args and flatten the candidates we found during our initial pass.
957 ExpressionArray flattened;
958 flattened.reserve_back(c.type().columns());
959 currBit = 1;
960 for (const std::unique_ptr<Expression>& arg : c.arguments()) {
961 if (argsToOptimize & currBit) {
962 Constructor& inner = arg->as<Constructor>();
963 for (const std::unique_ptr<Expression>& innerArg : inner.arguments()) {
964 flattened.push_back(innerArg->clone());
965 }
966 } else {
967 flattened.push_back(arg->clone());
968 }
969 currBit <<= 1;
970 }
John Stiles54f00492021-02-19 11:46:10 -0500971 std::unique_ptr<Expression> replacement = std::make_unique<Constructor>(
972 c.fOffset, c.type(), std::move(flattened));
John Stiles1b91c0e2021-02-11 11:43:09 -0500973 // We're replacing an expression with a cloned version; we'll need a rescan.
974 // No fUsage change: `float2(float(x), y)` and `float2(x, y)` have equivalent
975 // reference counts.
976 try_replace_expression(&b, iter, &replacement);
John Stilesf5c1d042020-11-21 23:26:07 -0500977 optimizationContext->fUpdated = true;
John Stiles1b91c0e2021-02-11 11:43:09 -0500978 optimizationContext->fNeedsRescan = true;
John Stilesf5c1d042020-11-21 23:26:07 -0500979 break;
980 }
981 }
982 break;
983 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400984 case Expression::Kind::kSwizzle: {
John Stiles403a3632020-08-20 12:11:48 -0400985 Swizzle& s = expr->as<Swizzle>();
John Stiles108bbe22020-11-18 11:10:38 -0500986 // Detect identity swizzles like `foo.rgba`.
Ethan Nicholas6b4d5812020-10-12 16:11:51 -0400987 if ((int) s.components().size() == s.base()->type().columns()) {
Ethan Nicholas409f6f02019-09-17 12:34:39 -0400988 bool identity = true;
Ethan Nicholas6b4d5812020-10-12 16:11:51 -0400989 for (int i = 0; i < (int) s.components().size(); ++i) {
990 if (s.components()[i] != i) {
Ethan Nicholas409f6f02019-09-17 12:34:39 -0400991 identity = false;
992 break;
993 }
994 }
995 if (identity) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400996 optimizationContext->fUpdated = true;
Brian Osman010ce6a2020-10-19 16:34:10 -0400997 // No fUsage change: foo.rgba and foo have equivalent reference counts
Ethan Nicholas6b4d5812020-10-12 16:11:51 -0400998 if (!try_replace_expression(&b, iter, &s.base())) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400999 optimizationContext->fNeedsRescan = true;
Ethan Nicholas409f6f02019-09-17 12:34:39 -04001000 return;
1001 }
John Stiles70025e52020-09-28 16:08:58 -04001002 SkASSERT((*iter)->isExpression());
Ethan Nicholas409f6f02019-09-17 12:34:39 -04001003 break;
1004 }
1005 }
John Stiles108bbe22020-11-18 11:10:38 -05001006 // Detect swizzles of swizzles, e.g. replace `foo.argb.r000` with `foo.a000`.
1007 if (s.base()->is<Swizzle>()) {
Ethan Nicholas6b4d5812020-10-12 16:11:51 -04001008 Swizzle& base = s.base()->as<Swizzle>();
John Stiles750109b2020-10-30 13:45:46 -04001009 ComponentArray final;
Ethan Nicholas6b4d5812020-10-12 16:11:51 -04001010 for (int c : s.components()) {
1011 final.push_back(base.components()[c]);
Ethan Nicholas409f6f02019-09-17 12:34:39 -04001012 }
Ethan Nicholas6b4d5812020-10-12 16:11:51 -04001013 std::unique_ptr<Expression> replacement(new Swizzle(*fContext, base.base()->clone(),
John Stiles750109b2020-10-30 13:45:46 -04001014 final));
John Stilesd2f51b12021-01-07 18:12:31 -05001015 // We're replacing an expression with a cloned version; we'll need a rescan.
John Stiles108bbe22020-11-18 11:10:38 -05001016 // No fUsage change: `foo.gbr.gbr` and `foo.brg` have equivalent reference counts
John Stilesd2f51b12021-01-07 18:12:31 -05001017 try_replace_expression(&b, iter, &replacement);
1018 optimizationContext->fUpdated = true;
1019 optimizationContext->fNeedsRescan = true;
John Stiles108bbe22020-11-18 11:10:38 -05001020 break;
1021 }
1022 // Optimize swizzles of constructors.
1023 if (s.base()->is<Constructor>()) {
1024 Constructor& base = s.base()->as<Constructor>();
1025 std::unique_ptr<Expression> replacement;
1026 const Type& componentType = base.type().componentType();
1027 int swizzleSize = s.components().size();
1028
1029 // The IR generator has already converted any zero/one swizzle components into
1030 // constructors containing zero/one args. Confirm that this is true by checking that
1031 // our swizzle components are all `xyzw` (values 0 through 3).
1032 SkASSERT(std::all_of(s.components().begin(), s.components().end(),
1033 [](int8_t c) { return c >= 0 && c <= 3; }));
1034
John Stiles9aeed132020-11-24 17:36:06 -05001035 if (base.arguments().size() == 1 && base.arguments().front()->type().isScalar()) {
John Stiles108bbe22020-11-18 11:10:38 -05001036 // `half4(scalar).zyy` can be optimized to `half3(scalar)`. The swizzle
1037 // components don't actually matter since all fields are the same.
John Stilesf0cb7332021-01-08 18:39:00 -05001038 const Expression& argument = *base.arguments().front();
1039 const Type& constructorType = componentType.toCompound(*fContext, swizzleSize,
1040 /*rows=*/1);
1041 replacement = Constructor::SimplifyConversion(constructorType, argument);
1042 if (!replacement) {
1043 ExpressionArray newArgs;
1044 newArgs.push_back(argument.clone());
John Stiles54f00492021-02-19 11:46:10 -05001045 replacement = std::make_unique<Constructor>(base.fOffset, constructorType,
John Stilesf0cb7332021-01-08 18:39:00 -05001046 std::move(newArgs));
1047 }
John Stiles108bbe22020-11-18 11:10:38 -05001048
John Stilesa60ac0c2020-12-22 08:59:51 -05001049 // We're replacing an expression with a cloned version; we'll need a rescan.
1050 // There's no fUsage change: `half4(foo).xy` and `half2(foo)` have equivalent
1051 // reference counts.
1052 try_replace_expression(&b, iter, &replacement);
John Stiles0777ac42020-11-19 11:06:47 -05001053 optimizationContext->fUpdated = true;
John Stilesa60ac0c2020-12-22 08:59:51 -05001054 optimizationContext->fNeedsRescan = true;
John Stiles108bbe22020-11-18 11:10:38 -05001055 break;
1056 }
1057
John Stiles0777ac42020-11-19 11:06:47 -05001058 // Swizzles can duplicate some elements and discard others, e.g.
1059 // `half4(1, 2, 3, 4).xxz` --> `half3(1, 1, 3)`. However, there are constraints:
1060 // - Expressions with side effects need to occur exactly once, even if they
1061 // would otherwise be swizzle-eliminated
1062 // - Non-trivial expressions should not be repeated, but elimination is OK.
1063 //
1064 // Look up the argument for the constructor at each index. This is typically simple
1065 // but for weird cases like `half4(bar.yz, half2(foo))`, it can be harder than it
1066 // seems. This example would result in:
1067 // argMap[0] = {.fArgIndex = 0, .fComponent = 0} (bar.yz .x)
1068 // argMap[1] = {.fArgIndex = 0, .fComponent = 1} (bar.yz .y)
1069 // argMap[2] = {.fArgIndex = 1, .fComponent = 0} (half2(foo) .x)
1070 // argMap[3] = {.fArgIndex = 1, .fComponent = 1} (half2(foo) .y)
1071 struct ConstructorArgMap {
1072 int8_t fArgIndex;
1073 int8_t fComponent;
1074 };
1075
1076 int numConstructorArgs = base.type().columns();
1077 ConstructorArgMap argMap[4] = {};
1078 int writeIdx = 0;
1079 for (int argIdx = 0; argIdx < (int) base.arguments().size(); ++argIdx) {
1080 const Expression& expr = *base.arguments()[argIdx];
1081 int argWidth = expr.type().columns();
1082 for (int componentIdx = 0; componentIdx < argWidth; ++componentIdx) {
1083 argMap[writeIdx].fArgIndex = argIdx;
1084 argMap[writeIdx].fComponent = componentIdx;
1085 ++writeIdx;
1086 }
1087 }
1088 SkASSERT(writeIdx == numConstructorArgs);
1089
1090 // Count up the number of times each constructor argument is used by the
1091 // swizzle.
1092 // `half4(bar.yz, half2(foo)).xwxy` -> { 3, 1 }
1093 // - bar.yz is referenced 3 times, by `.x_xy`
1094 // - half(foo) is referenced 1 time, by `._w__`
1095 int8_t exprUsed[4] = {};
1096 for (int c : s.components()) {
1097 exprUsed[argMap[c].fArgIndex]++;
1098 }
1099
1100 bool safeToOptimize = true;
1101 for (int index = 0; index < numConstructorArgs; ++index) {
1102 int8_t constructorArgIndex = argMap[index].fArgIndex;
1103 const Expression& baseArg = *base.arguments()[constructorArgIndex];
1104
1105 // Check that non-trivial expressions are not swizzled in more than once.
John Stilesc30fbca2020-11-19 16:25:49 -05001106 if (exprUsed[constructorArgIndex] > 1 &&
1107 !Analysis::IsTrivialExpression(baseArg)) {
John Stiles0777ac42020-11-19 11:06:47 -05001108 safeToOptimize = false;
1109 break;
1110 }
1111 // Check that side-effect-bearing expressions are swizzled in exactly once.
1112 if (exprUsed[constructorArgIndex] != 1 && baseArg.hasSideEffects()) {
1113 safeToOptimize = false;
1114 break;
1115 }
1116 }
1117
1118 if (safeToOptimize) {
John Stilesd9076cb2020-11-19 12:18:36 -05001119 struct ReorderedArgument {
1120 int8_t fArgIndex;
1121 ComponentArray fComponents;
1122 };
1123 SkSTArray<4, ReorderedArgument> reorderedArgs;
John Stiles0777ac42020-11-19 11:06:47 -05001124 for (int c : s.components()) {
1125 const ConstructorArgMap& argument = argMap[c];
1126 const Expression& baseArg = *base.arguments()[argument.fArgIndex];
1127
John Stiles9aeed132020-11-24 17:36:06 -05001128 if (baseArg.type().isScalar()) {
John Stilesd9076cb2020-11-19 12:18:36 -05001129 // This argument is a scalar; add it to the list as-is.
John Stiles0777ac42020-11-19 11:06:47 -05001130 SkASSERT(argument.fComponent == 0);
John Stilesd9076cb2020-11-19 12:18:36 -05001131 reorderedArgs.push_back({argument.fArgIndex,
1132 ComponentArray{}});
John Stiles0777ac42020-11-19 11:06:47 -05001133 } else {
John Stilesd9076cb2020-11-19 12:18:36 -05001134 // This argument is a component from a vector.
John Stiles0777ac42020-11-19 11:06:47 -05001135 SkASSERT(argument.fComponent < baseArg.type().columns());
John Stilesd9076cb2020-11-19 12:18:36 -05001136 if (reorderedArgs.empty() ||
1137 reorderedArgs.back().fArgIndex != argument.fArgIndex) {
1138 // This can't be combined with the previous argument. Add a new one.
1139 reorderedArgs.push_back({argument.fArgIndex,
1140 ComponentArray{argument.fComponent}});
1141 } else {
1142 // Since we know this argument uses components, it should already
1143 // have at least one component set.
1144 SkASSERT(!reorderedArgs.back().fComponents.empty());
1145 // Build up the current argument with one more component.
1146 reorderedArgs.back().fComponents.push_back(argument.fComponent);
1147 }
John Stiles0777ac42020-11-19 11:06:47 -05001148 }
1149 }
John Stilesd9076cb2020-11-19 12:18:36 -05001150
1151 // Convert our reordered argument list to an actual array of expressions, with
1152 // the new order and any new inner swizzles that need to be applied. Note that
1153 // we expect followup passes to clean up the inner swizzles.
1154 ExpressionArray newArgs;
1155 newArgs.reserve_back(swizzleSize);
1156 for (const ReorderedArgument& reorderedArg : reorderedArgs) {
1157 const Expression& baseArg = *base.arguments()[reorderedArg.fArgIndex];
1158 if (reorderedArg.fComponents.empty()) {
1159 newArgs.push_back(baseArg.clone());
1160 } else {
1161 newArgs.push_back(std::make_unique<Swizzle>(*fContext, baseArg.clone(),
1162 reorderedArg.fComponents));
1163 }
1164 }
1165
1166 // Create a new constructor.
John Stiles0777ac42020-11-19 11:06:47 -05001167 replacement = std::make_unique<Constructor>(
1168 base.fOffset,
John Stiles54f00492021-02-19 11:46:10 -05001169 componentType.toCompound(*fContext, swizzleSize, /*rows=*/1),
John Stiles0777ac42020-11-19 11:06:47 -05001170 std::move(newArgs));
1171
John Stilesa60ac0c2020-12-22 08:59:51 -05001172 // Remove references within 'expr', add references within 'replacement.'
John Stiles0777ac42020-11-19 11:06:47 -05001173 optimizationContext->fUsage->replace(expr, replacement.get());
John Stilesa60ac0c2020-12-22 08:59:51 -05001174
1175 // We're replacing an expression with a cloned version; we'll need a rescan.
1176 try_replace_expression(&b, iter, &replacement);
1177 optimizationContext->fUpdated = true;
1178 optimizationContext->fNeedsRescan = true;
John Stiles0777ac42020-11-19 11:06:47 -05001179 }
John Stiles108bbe22020-11-18 11:10:38 -05001180 break;
Ethan Nicholas409f6f02019-09-17 12:34:39 -04001181 }
John Stiles30212b72020-06-11 17:55:07 -04001182 break;
Ethan Nicholascb670962017-04-20 19:31:52 -04001183 }
1184 default:
1185 break;
1186 }
1187}
1188
1189void Compiler::simplifyStatement(DefinitionMap& definitions,
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001190 BasicBlock& b,
1191 std::vector<BasicBlock::Node>::iterator* iter,
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001192 OptimizationContext* optimizationContext) {
Brian Osman010ce6a2020-10-19 16:34:10 -04001193 ProgramUsage* usage = optimizationContext->fUsage;
Ethan Nicholascb670962017-04-20 19:31:52 -04001194 Statement* stmt = (*iter)->statement()->get();
Ethan Nicholase6592142020-09-08 10:22:09 -04001195 switch (stmt->kind()) {
1196 case Statement::Kind::kVarDeclaration: {
John Stilesa5a97b42020-08-18 11:19:07 -04001197 const auto& varDecl = stmt->as<VarDeclaration>();
Brian Osman010ce6a2020-10-19 16:34:10 -04001198 if (usage->isDead(varDecl.var()) &&
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04001199 (!varDecl.value() ||
1200 !varDecl.value()->hasSideEffects())) {
1201 if (varDecl.value()) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001202 SkASSERT((*iter)->statement()->get() == stmt);
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04001203 if (!b.tryRemoveExpressionBefore(iter, varDecl.value().get())) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001204 optimizationContext->fNeedsRescan = true;
Ethan Nicholascb670962017-04-20 19:31:52 -04001205 }
Ethan Nicholascb670962017-04-20 19:31:52 -04001206 }
Ethan Nicholas5b9b0db2021-01-21 13:12:01 -05001207 // There can still be (soon to be removed) references to the variable at this point.
1208 // Allowing the VarDeclaration to be destroyed here will break those variable's
1209 // initialValue()s, so we hang on to them until optimization is finished.
1210 std::unique_ptr<Statement> old = (*iter)->setStatement(std::make_unique<Nop>(),
1211 usage);
1212 optimizationContext->fOwnedStatements.push_back(std::move(old));
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001213 optimizationContext->fUpdated = true;
Ethan Nicholascb670962017-04-20 19:31:52 -04001214 }
1215 break;
1216 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001217 case Statement::Kind::kIf: {
John Stilesa5a97b42020-08-18 11:19:07 -04001218 IfStatement& i = stmt->as<IfStatement>();
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001219 if (i.test()->kind() == Expression::Kind::kBoolLiteral) {
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001220 // constant if, collapse down to a single branch
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001221 if (i.test()->as<BoolLiteral>().value()) {
1222 SkASSERT(i.ifTrue());
Brian Osman010ce6a2020-10-19 16:34:10 -04001223 (*iter)->setStatement(std::move(i.ifTrue()), usage);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001224 } else {
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001225 if (i.ifFalse()) {
Brian Osman010ce6a2020-10-19 16:34:10 -04001226 (*iter)->setStatement(std::move(i.ifFalse()), usage);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001227 } else {
Brian Osman010ce6a2020-10-19 16:34:10 -04001228 (*iter)->setStatement(std::make_unique<Nop>(), usage);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001229 }
1230 }
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001231 optimizationContext->fUpdated = true;
1232 optimizationContext->fNeedsRescan = true;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001233 break;
1234 }
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001235 if (i.ifFalse() && i.ifFalse()->isEmpty()) {
Ethan Nicholascb670962017-04-20 19:31:52 -04001236 // else block doesn't do anything, remove it
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001237 i.ifFalse().reset();
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001238 optimizationContext->fUpdated = true;
1239 optimizationContext->fNeedsRescan = true;
Ethan Nicholascb670962017-04-20 19:31:52 -04001240 }
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001241 if (!i.ifFalse() && i.ifTrue()->isEmpty()) {
Ethan Nicholascb670962017-04-20 19:31:52 -04001242 // if block doesn't do anything, no else block
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001243 if (i.test()->hasSideEffects()) {
Ethan Nicholascb670962017-04-20 19:31:52 -04001244 // test has side effects, keep it
Brian Osman010ce6a2020-10-19 16:34:10 -04001245 (*iter)->setStatement(
1246 std::make_unique<ExpressionStatement>(std::move(i.test())), usage);
Ethan Nicholascb670962017-04-20 19:31:52 -04001247 } else {
1248 // no if, no else, no test side effects, kill the whole if
1249 // statement
Brian Osman010ce6a2020-10-19 16:34:10 -04001250 (*iter)->setStatement(std::make_unique<Nop>(), usage);
Ethan Nicholascb670962017-04-20 19:31:52 -04001251 }
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001252 optimizationContext->fUpdated = true;
1253 optimizationContext->fNeedsRescan = true;
Ethan Nicholascb670962017-04-20 19:31:52 -04001254 }
1255 break;
1256 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001257 case Statement::Kind::kSwitch: {
John Stiles642cde22021-02-23 14:57:01 -05001258 // TODO(skia:11319): this optimization logic is redundant with the static-switch
1259 // optimization code found in SwitchStatement.cpp.
John Stilesa5a97b42020-08-18 11:19:07 -04001260 SwitchStatement& s = stmt->as<SwitchStatement>();
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001261 int64_t switchValue;
Ethan Nicholasc0f98152021-02-05 16:21:10 -05001262 if (ConstantFolder::GetConstantInt(*s.value(), &switchValue)) {
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001263 // switch is constant, replace it with the case that matches
1264 bool found = false;
1265 SwitchCase* defaultCase = nullptr;
John Stiles2d4f9592020-10-30 10:29:12 -04001266 for (const std::unique_ptr<SwitchCase>& c : s.cases()) {
1267 if (!c->value()) {
1268 defaultCase = c.get();
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001269 continue;
1270 }
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001271 int64_t caseValue;
Ethan Nicholasc0f98152021-02-05 16:21:10 -05001272 SkAssertResult(ConstantFolder::GetConstantInt(*c->value(), &caseValue));
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001273 if (caseValue == switchValue) {
John Stiles642cde22021-02-23 14:57:01 -05001274 std::unique_ptr<Statement> newBlock =
1275 SwitchStatement::BlockForCase(&s.cases(), c.get(), s.symbols());
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001276 if (newBlock) {
Brian Osman010ce6a2020-10-19 16:34:10 -04001277 (*iter)->setStatement(std::move(newBlock), usage);
John Stiles9d944232020-08-19 09:56:49 -04001278 found = true;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001279 break;
1280 } else {
John Stilesd6a5f4492021-02-11 15:46:11 -05001281 if (s.isStatic() &&
John Stilesd1204642021-02-17 16:30:02 -05001282 !fContext->fConfig->fSettings.fPermitInvalidStaticTests) {
John Stilesd6a5f4492021-02-11 15:46:11 -05001283 auto [iter, didInsert] = optimizationContext->fSilences.insert(&s);
1284 if (didInsert) {
1285 this->error(s.fOffset, "static switch contains non-static "
John Stiles04ca41a2021-02-23 09:58:04 -05001286 "conditional exit");
John Stilesd6a5f4492021-02-11 15:46:11 -05001287 }
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001288 }
1289 return; // can't simplify
1290 }
1291 }
1292 }
1293 if (!found) {
1294 // no matching case. use default if it exists, or kill the whole thing
1295 if (defaultCase) {
John Stiles642cde22021-02-23 14:57:01 -05001296 std::unique_ptr<Statement> newBlock =
1297 SwitchStatement::BlockForCase(&s.cases(), defaultCase, s.symbols());
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001298 if (newBlock) {
Brian Osman010ce6a2020-10-19 16:34:10 -04001299 (*iter)->setStatement(std::move(newBlock), usage);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001300 } else {
John Stilesd6a5f4492021-02-11 15:46:11 -05001301 if (s.isStatic() &&
John Stilesd1204642021-02-17 16:30:02 -05001302 !fContext->fConfig->fSettings.fPermitInvalidStaticTests) {
John Stilesd6a5f4492021-02-11 15:46:11 -05001303 auto [iter, didInsert] = optimizationContext->fSilences.insert(&s);
1304 if (didInsert) {
1305 this->error(s.fOffset, "static switch contains non-static "
John Stiles04ca41a2021-02-23 09:58:04 -05001306 "conditional exit");
John Stilesd6a5f4492021-02-11 15:46:11 -05001307 }
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001308 }
1309 return; // can't simplify
1310 }
1311 } else {
Brian Osman010ce6a2020-10-19 16:34:10 -04001312 (*iter)->setStatement(std::make_unique<Nop>(), usage);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001313 }
1314 }
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001315 optimizationContext->fUpdated = true;
1316 optimizationContext->fNeedsRescan = true;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001317 }
1318 break;
1319 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001320 case Statement::Kind::kExpression: {
John Stilesa5a97b42020-08-18 11:19:07 -04001321 ExpressionStatement& e = stmt->as<ExpressionStatement>();
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001322 SkASSERT((*iter)->statement()->get() == &e);
Ethan Nicholasd503a5a2020-09-30 09:29:55 -04001323 if (!e.expression()->hasSideEffects()) {
Ethan Nicholascb670962017-04-20 19:31:52 -04001324 // Expression statement with no side effects, kill it
Ethan Nicholasd503a5a2020-09-30 09:29:55 -04001325 if (!b.tryRemoveExpressionBefore(iter, e.expression().get())) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001326 optimizationContext->fNeedsRescan = true;
Ethan Nicholascb670962017-04-20 19:31:52 -04001327 }
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001328 SkASSERT((*iter)->statement()->get() == stmt);
Brian Osman010ce6a2020-10-19 16:34:10 -04001329 (*iter)->setStatement(std::make_unique<Nop>(), usage);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001330 optimizationContext->fUpdated = true;
Ethan Nicholascb670962017-04-20 19:31:52 -04001331 }
1332 break;
1333 }
1334 default:
1335 break;
1336 }
1337}
1338
Brian Osman010ce6a2020-10-19 16:34:10 -04001339bool Compiler::scanCFG(FunctionDefinition& f, ProgramUsage* usage) {
John Stiles0cc193a2020-09-09 09:39:34 -04001340 bool madeChanges = false;
1341
Ethan Nicholascb670962017-04-20 19:31:52 -04001342 CFG cfg = CFGGenerator().getCFG(f);
1343 this->computeDataFlow(&cfg);
ethannicholas22f939e2016-10-13 13:25:34 -07001344
John Stiles66c53b92021-02-20 08:00:43 -05001345 if (fContext->fConfig->fSettings.fDeadCodeElimination) {
1346 // Check for unreachable code.
1347 for (size_t i = 0; i < cfg.fBlocks.size(); i++) {
1348 const BasicBlock& block = cfg.fBlocks[i];
1349 if (!block.fIsReachable && !block.fAllowUnreachable && block.fNodes.size()) {
1350 const BasicBlock::Node& node = block.fNodes[0];
1351 int offset = node.isStatement() ? (*node.statement())->fOffset
1352 : (*node.expression())->fOffset;
1353 this->error(offset, String("unreachable"));
1354 }
ethannicholas22f939e2016-10-13 13:25:34 -07001355 }
1356 }
1357 if (fErrorCount) {
John Stiles0cc193a2020-09-09 09:39:34 -04001358 return madeChanges;
ethannicholas22f939e2016-10-13 13:25:34 -07001359 }
1360
Ethan Nicholascb670962017-04-20 19:31:52 -04001361 // check for dead code & undefined variables, perform constant propagation
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001362 OptimizationContext optimizationContext;
Brian Osman010ce6a2020-10-19 16:34:10 -04001363 optimizationContext.fUsage = usage;
John Stiles7d3f0892020-11-03 11:35:01 -05001364 SkBitSet eliminatedBlockIds(cfg.fBlocks.size());
Ethan Nicholascb670962017-04-20 19:31:52 -04001365 do {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001366 if (optimizationContext.fNeedsRescan) {
Ethan Nicholascb670962017-04-20 19:31:52 -04001367 cfg = CFGGenerator().getCFG(f);
1368 this->computeDataFlow(&cfg);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001369 optimizationContext.fNeedsRescan = false;
Ethan Nicholas113628d2017-02-02 16:11:39 -05001370 }
Ethan Nicholascb670962017-04-20 19:31:52 -04001371
John Stiles7d3f0892020-11-03 11:35:01 -05001372 eliminatedBlockIds.reset();
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001373 optimizationContext.fUpdated = false;
John Stiles7d3f0892020-11-03 11:35:01 -05001374
1375 for (BlockId blockId = 0; blockId < cfg.fBlocks.size(); ++blockId) {
1376 if (eliminatedBlockIds.test(blockId)) {
1377 // We reached a block ID that might have been eliminated. Be cautious and rescan.
1378 optimizationContext.fUpdated = true;
1379 optimizationContext.fNeedsRescan = true;
1380 break;
1381 }
1382
1383 BasicBlock& b = cfg.fBlocks[blockId];
John Stiles66c53b92021-02-20 08:00:43 -05001384 if (fContext->fConfig->fSettings.fDeadCodeElimination) {
1385 if (blockId > 0 && !b.fIsReachable) {
1386 // Block was reachable before optimization, but has since become unreachable. In
1387 // addition to being dead code, it's broken - since control flow can't reach it,
1388 // no prior variable definitions can reach it, and therefore variables might
1389 // look to have not been properly assigned. Kill it by replacing all statements
1390 // with Nops.
1391 for (BasicBlock::Node& node : b.fNodes) {
1392 if (node.isStatement() && !(*node.statement())->is<Nop>()) {
1393 // Eliminating a node runs the risk of eliminating that node's exits as
1394 // well. Keep track of this and do a rescan if we are about to access
1395 // one of these.
1396 for (BlockId id : b.fExits) {
1397 eliminatedBlockIds.set(id);
1398 }
1399 node.setStatement(std::make_unique<Nop>(), usage);
1400 madeChanges = true;
John Stiles7d3f0892020-11-03 11:35:01 -05001401 }
Ethan Nicholas1de14812020-06-19 15:32:49 -04001402 }
John Stiles66c53b92021-02-20 08:00:43 -05001403 continue;
Ethan Nicholas1de14812020-06-19 15:32:49 -04001404 }
Ethan Nicholas1de14812020-06-19 15:32:49 -04001405 }
Ethan Nicholascb670962017-04-20 19:31:52 -04001406 DefinitionMap definitions = b.fBefore;
1407
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001408 for (auto iter = b.fNodes.begin(); iter != b.fNodes.end() &&
1409 !optimizationContext.fNeedsRescan; ++iter) {
John Stiles70025e52020-09-28 16:08:58 -04001410 if (iter->isExpression()) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001411 this->simplifyExpression(definitions, b, &iter, &optimizationContext);
Ethan Nicholascb670962017-04-20 19:31:52 -04001412 } else {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001413 this->simplifyStatement(definitions, b, &iter, &optimizationContext);
Ethan Nicholascb670962017-04-20 19:31:52 -04001414 }
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001415 if (optimizationContext.fNeedsRescan) {
Ethan Nicholas4b330df2017-05-17 10:52:55 -04001416 break;
1417 }
John Stilese8a24922021-02-08 17:54:08 -05001418 definitions.addDefinitions(*fContext, *iter);
Ethan Nicholascb670962017-04-20 19:31:52 -04001419 }
Brian Osman01a3eb42020-09-14 11:32:49 -04001420
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001421 if (optimizationContext.fNeedsRescan) {
Brian Osman01a3eb42020-09-14 11:32:49 -04001422 break;
1423 }
Ethan Nicholascb670962017-04-20 19:31:52 -04001424 }
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001425 madeChanges |= optimizationContext.fUpdated;
1426 } while (optimizationContext.fUpdated);
1427 SkASSERT(!optimizationContext.fNeedsRescan);
ethannicholas22f939e2016-10-13 13:25:34 -07001428
1429 // check for missing return
John Stiles54e7c052021-01-11 14:22:36 -05001430 if (f.declaration().returnType() != *fContext->fTypes.fVoid) {
John Stiles61e75e32020-10-01 15:42:37 -04001431 if (cfg.fBlocks[cfg.fExit].fIsReachable) {
Ethan Nicholas0a5d0962020-10-14 13:33:18 -04001432 this->error(f.fOffset, String("function '" + String(f.declaration().name()) +
Ethan Nicholasdb80f692019-11-22 14:06:12 -05001433 "' can exit without returning a value"));
ethannicholas22f939e2016-10-13 13:25:34 -07001434 }
1435 }
John Stiles0cc193a2020-09-09 09:39:34 -04001436
1437 return madeChanges;
ethannicholas22f939e2016-10-13 13:25:34 -07001438}
1439
Brian Osman32d53552020-09-23 13:55:20 -04001440std::unique_ptr<Program> Compiler::convertProgram(
John Stilesdbd4e6f2021-02-16 13:29:15 -05001441 ProgramKind kind,
Brian Osman32d53552020-09-23 13:55:20 -04001442 String text,
1443 const Program::Settings& settings,
Brian Osmanbe0b3b72021-01-06 14:27:35 -05001444 const std::vector<std::unique_ptr<ExternalFunction>>* externalFunctions) {
Brian Osmand010f652021-02-24 13:59:39 -05001445 TRACE_EVENT0("skia.gpu", "SkSL::Compiler::convertProgram");
Leon Scrogginsb66214e2021-02-11 17:14:18 -05001446
John Stilesdbd4e6f2021-02-16 13:29:15 -05001447 SkASSERT(!externalFunctions || (kind == ProgramKind::kGeneric));
Ethan Nicholas91164d12019-05-15 15:29:54 -04001448
Brian Osman0006ad02020-11-18 15:38:39 -05001449 // Loading and optimizing our base module might reset the inliner, so do that first,
1450 // *then* configure the inliner with the settings for this program.
1451 const ParsedModule& baseModule = this->moduleForProgramKind(kind);
1452
John Stiles270cec22021-02-17 12:59:36 -05001453 // Update our context to point to the program configuration for the duration of compilation.
1454 auto config = std::make_unique<ProgramConfig>(ProgramConfig{kind, settings});
John Stilesa935c3f2021-02-25 10:35:49 -05001455 AutoProgramConfig autoConfig(fContext, config.get());
John Stiles270cec22021-02-17 12:59:36 -05001456
ethannicholasb3058bd2016-07-01 08:22:01 -07001457 fErrorText = "";
1458 fErrorCount = 0;
John Stilesd1204642021-02-17 16:30:02 -05001459 fInliner.reset(fIRGenerator->fModifiers.get());
Brian Osman88cda172020-10-09 12:05:16 -04001460
1461 // Not using AutoSource, because caller is likely to call errorText() if we fail to compile
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001462 std::unique_ptr<String> textPtr(new String(std::move(text)));
1463 fSource = textPtr.get();
Brian Osman88cda172020-10-09 12:05:16 -04001464
John Stiles5c7bb322020-10-22 11:09:15 -04001465 // Enable node pooling while converting and optimizing the program for a performance boost.
1466 // The Program will take ownership of the pool.
Brian Osman28f702c2021-02-02 11:52:07 -05001467 std::unique_ptr<Pool> pool;
John Stilesc1a98b82021-02-24 13:35:02 -05001468 if (fContext->fCaps.useNodePools()) {
Brian Osman28f702c2021-02-02 11:52:07 -05001469 pool = Pool::Create();
1470 pool->attachToThread();
1471 }
John Stilesd1204642021-02-17 16:30:02 -05001472 IRGenerator::IRBundle ir = fIRGenerator->convertProgram(baseModule, /*isBuiltinCode=*/false,
1473 textPtr->c_str(), textPtr->size(),
1474 externalFunctions);
John Stiles270cec22021-02-17 12:59:36 -05001475 auto program = std::make_unique<Program>(std::move(textPtr),
1476 std::move(config),
John Stiles5c7bb322020-10-22 11:09:15 -04001477 fContext,
1478 std::move(ir.fElements),
Brian Osman133724c2020-10-28 14:14:39 -04001479 std::move(ir.fSharedElements),
John Stiles5c7bb322020-10-22 11:09:15 -04001480 std::move(ir.fModifiers),
1481 std::move(ir.fSymbolTable),
1482 std::move(pool),
1483 ir.fInputs);
1484 bool success = false;
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001485 if (fErrorCount) {
John Stiles5c7bb322020-10-22 11:09:15 -04001486 // Do not return programs that failed to compile.
John Stilescbd65752021-02-24 14:14:14 +00001487 } else if (settings.fOptimize && !this->optimize(*program)) {
John Stiles5c7bb322020-10-22 11:09:15 -04001488 // Do not return programs that failed to optimize.
1489 } else {
1490 // We have a successful program!
1491 success = true;
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001492 }
John Stiles5c7bb322020-10-22 11:09:15 -04001493
Brian Osman28f702c2021-02-02 11:52:07 -05001494 if (program->fPool) {
1495 program->fPool->detachFromThread();
1496 }
John Stiles5c7bb322020-10-22 11:09:15 -04001497 return success ? std::move(program) : nullptr;
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001498}
1499
John Stilesbb1505f2021-02-12 09:17:53 -05001500void Compiler::verifyStaticTests(const Program& program) {
1501 class StaticTestVerifier : public ProgramVisitor {
1502 public:
1503 StaticTestVerifier(ErrorReporter* r) : fReporter(r) {}
1504
1505 using ProgramVisitor::visitProgramElement;
1506
1507 bool visitStatement(const Statement& stmt) override {
1508 switch (stmt.kind()) {
1509 case Statement::Kind::kIf:
1510 if (stmt.as<IfStatement>().isStatic()) {
1511 fReporter->error(stmt.fOffset, "static if has non-static test");
1512 }
1513 break;
1514
1515 case Statement::Kind::kSwitch:
1516 if (stmt.as<SwitchStatement>().isStatic()) {
1517 fReporter->error(stmt.fOffset, "static switch has non-static test");
1518 }
1519 break;
1520
1521 default:
1522 break;
1523 }
1524 return INHERITED::visitStatement(stmt);
1525 }
1526
John Stiles59e34562021-02-12 16:56:39 -05001527 bool visitExpression(const Expression&) override {
1528 // We aren't looking for anything inside an Expression, so skip them entirely.
1529 return false;
1530 }
1531
John Stilesbb1505f2021-02-12 09:17:53 -05001532 private:
1533 using INHERITED = ProgramVisitor;
1534 ErrorReporter* fReporter;
1535 };
1536
1537 // If invalid static tests are permitted, we don't need to check anything.
John Stilesd1204642021-02-17 16:30:02 -05001538 if (fContext->fConfig->fSettings.fPermitInvalidStaticTests) {
John Stilesbb1505f2021-02-12 09:17:53 -05001539 return;
1540 }
1541
1542 // Check all of the program's owned elements. (Built-in elements are assumed to be valid.)
1543 StaticTestVerifier visitor{this};
1544 for (const std::unique_ptr<ProgramElement>& element : program.ownedElements()) {
1545 if (element->is<FunctionDefinition>()) {
1546 visitor.visitProgramElement(*element);
1547 }
1548 }
1549}
1550
Brian Osman0006ad02020-11-18 15:38:39 -05001551bool Compiler::optimize(LoadedModule& module) {
1552 SkASSERT(!fErrorCount);
Brian Osman0006ad02020-11-18 15:38:39 -05001553
John Stiles270cec22021-02-17 12:59:36 -05001554 // Create a temporary program configuration with default settings.
1555 ProgramConfig config;
1556 config.fKind = module.fKind;
John Stilesa935c3f2021-02-25 10:35:49 -05001557 AutoProgramConfig autoConfig(fContext, &config);
John Stiles270cec22021-02-17 12:59:36 -05001558
John Stilesd1204642021-02-17 16:30:02 -05001559 // Reset the Inliner.
1560 fInliner.reset(fModifiers.back().get());
John Stiles270cec22021-02-17 12:59:36 -05001561
1562 std::unique_ptr<ProgramUsage> usage = Analysis::GetUsage(module);
Brian Osman0006ad02020-11-18 15:38:39 -05001563
1564 while (fErrorCount == 0) {
1565 bool madeChanges = false;
1566
1567 // Scan and optimize based on the control-flow graph for each function.
John Stilesa935c3f2021-02-25 10:35:49 -05001568 if (config.fSettings.fControlFlowAnalysis) {
1569 for (const auto& element : module.fElements) {
1570 if (element->is<FunctionDefinition>()) {
1571 madeChanges |= this->scanCFG(element->as<FunctionDefinition>(), usage.get());
1572 }
Brian Osman0006ad02020-11-18 15:38:39 -05001573 }
1574 }
1575
1576 // Perform inline-candidate analysis and inline any functions deemed suitable.
John Stiles78047582020-12-16 16:17:41 -05001577 madeChanges |= fInliner.analyze(module.fElements, module.fSymbols, usage.get());
Brian Osman0006ad02020-11-18 15:38:39 -05001578
1579 if (!madeChanges) {
1580 break;
1581 }
1582 }
1583 return fErrorCount == 0;
1584}
1585
Ethan Nicholas00543112018-07-31 09:44:36 -04001586bool Compiler::optimize(Program& program) {
1587 SkASSERT(!fErrorCount);
Brian Osman010ce6a2020-10-19 16:34:10 -04001588 ProgramUsage* usage = program.fUsage.get();
John Stiles7954d6c2020-09-01 10:53:02 -04001589
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001590 while (fErrorCount == 0) {
1591 bool madeChanges = false;
John Stiles7954d6c2020-09-01 10:53:02 -04001592
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001593 // Scan and optimize based on the control-flow graph for each function.
John Stiles0c7312a2021-02-24 11:31:32 -05001594 if (program.fConfig->fSettings.fControlFlowAnalysis) {
1595 for (const auto& element : program.ownedElements()) {
1596 if (element->is<FunctionDefinition>()) {
1597 madeChanges |= this->scanCFG(element->as<FunctionDefinition>(), usage);
1598 }
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001599 }
1600 }
1601
1602 // Perform inline-candidate analysis and inline any functions deemed suitable.
John Stiles78047582020-12-16 16:17:41 -05001603 madeChanges |= fInliner.analyze(program.ownedElements(), program.fSymbols, usage);
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001604
1605 // Remove dead functions. We wait until after analysis so that we still report errors,
1606 // even in unused code.
John Stiles270cec22021-02-17 12:59:36 -05001607 if (program.fConfig->fSettings.fRemoveDeadFunctions) {
Brian Osman133724c2020-10-28 14:14:39 -04001608 auto isDeadFunction = [&](const ProgramElement* element) {
1609 if (!element->is<FunctionDefinition>()) {
1610 return false;
1611 }
1612 const FunctionDefinition& fn = element->as<FunctionDefinition>();
1613 if (fn.declaration().name() != "main" && usage->get(fn.declaration()) == 0) {
1614 usage->remove(*element);
1615 madeChanges = true;
1616 return true;
1617 }
1618 return false;
1619 };
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001620 program.fElements.erase(
Brian Osman133724c2020-10-28 14:14:39 -04001621 std::remove_if(program.fElements.begin(), program.fElements.end(),
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001622 [&](const std::unique_ptr<ProgramElement>& element) {
Brian Osman133724c2020-10-28 14:14:39 -04001623 return isDeadFunction(element.get());
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001624 }),
1625 program.fElements.end());
Brian Osman133724c2020-10-28 14:14:39 -04001626 program.fSharedElements.erase(
1627 std::remove_if(program.fSharedElements.begin(), program.fSharedElements.end(),
1628 isDeadFunction),
1629 program.fSharedElements.end());
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001630 }
1631
John Stiles270cec22021-02-17 12:59:36 -05001632 if (program.fConfig->fKind != ProgramKind::kFragmentProcessor) {
Brian Osmanc0213602020-10-06 14:43:32 -04001633 // Remove declarations of dead global variables
Brian Osman133724c2020-10-28 14:14:39 -04001634 auto isDeadVariable = [&](const ProgramElement* element) {
1635 if (!element->is<GlobalVarDeclaration>()) {
1636 return false;
1637 }
1638 const GlobalVarDeclaration& global = element->as<GlobalVarDeclaration>();
1639 const VarDeclaration& varDecl = global.declaration()->as<VarDeclaration>();
1640 if (usage->isDead(varDecl.var())) {
1641 madeChanges = true;
1642 return true;
1643 }
1644 return false;
1645 };
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001646 program.fElements.erase(
1647 std::remove_if(program.fElements.begin(), program.fElements.end(),
1648 [&](const std::unique_ptr<ProgramElement>& element) {
Brian Osman133724c2020-10-28 14:14:39 -04001649 return isDeadVariable(element.get());
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001650 }),
1651 program.fElements.end());
Brian Osman133724c2020-10-28 14:14:39 -04001652 program.fSharedElements.erase(
1653 std::remove_if(program.fSharedElements.begin(), program.fSharedElements.end(),
1654 isDeadVariable),
1655 program.fSharedElements.end());
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001656 }
John Stiles73a6bff2020-09-09 13:40:37 -04001657
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001658 if (!madeChanges) {
1659 break;
Ethan Nicholas0dc80872019-02-08 15:46:24 -05001660 }
Ethan Nicholas00543112018-07-31 09:44:36 -04001661 }
John Stilesbb1505f2021-02-12 09:17:53 -05001662
1663 if (fErrorCount == 0) {
1664 this->verifyStaticTests(program);
1665 }
1666
Ethan Nicholas00543112018-07-31 09:44:36 -04001667 return fErrorCount == 0;
1668}
1669
Brian Osmanfb32ddf2019-06-18 10:14:20 -04001670#if defined(SKSL_STANDALONE) || SK_SUPPORT_GPU
1671
Ethan Nicholas00543112018-07-31 09:44:36 -04001672bool Compiler::toSPIRV(Program& program, OutputStream& out) {
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001673#ifdef SK_ENABLE_SPIRV_VALIDATION
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001674 StringStream buffer;
Brian Osman88cda172020-10-09 12:05:16 -04001675 AutoSource as(this, program.fSource.get());
Brian Osman8b43dad2020-10-09 13:31:42 -04001676 SPIRVCodeGenerator cg(fContext.get(), &program, this, &buffer);
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001677 bool result = cg.generateCode();
John Stiles270cec22021-02-17 12:59:36 -05001678 if (result && program.fConfig->fSettings.fValidateSPIRV) {
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001679 spvtools::SpirvTools tools(SPV_ENV_VULKAN_1_0);
Ethan Nicholas762466e2017-06-29 10:03:38 -04001680 const String& data = buffer.str();
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001681 SkASSERT(0 == data.size() % 4);
Brian Osman8d09d4a2020-11-24 15:51:06 -05001682 String errors;
1683 auto dumpmsg = [&errors](spv_message_level_t, const char*, const spv_position_t&,
1684 const char* m) {
1685 errors.appendf("SPIR-V validation error: %s\n", m);
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001686 };
1687 tools.SetMessageConsumer(dumpmsg);
Brian Osman8d09d4a2020-11-24 15:51:06 -05001688
1689 // Verify that the SPIR-V we produced is valid. At runtime, we will abort() with a message
1690 // explaining the error. In standalone mode (skslc), we will send the message, plus the
1691 // entire disassembled SPIR-V (for easier context & debugging) as *our* error message.
1692 result = tools.Validate((const uint32_t*) data.c_str(), data.size() / 4);
1693
1694 if (!result) {
1695#if defined(SKSL_STANDALONE)
1696 // Convert the string-stream to a SPIR-V disassembly.
1697 std::string disassembly;
1698 if (tools.Disassemble((const uint32_t*)data.data(), data.size() / 4, &disassembly)) {
1699 errors.append(disassembly);
1700 }
1701 this->error(-1, errors);
1702#else
1703 SkDEBUGFAILF("%s", errors.c_str());
1704#endif
1705 }
Ethan Nicholas762466e2017-06-29 10:03:38 -04001706 out.write(data.c_str(), data.size());
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001707 }
1708#else
Brian Osman88cda172020-10-09 12:05:16 -04001709 AutoSource as(this, program.fSource.get());
Brian Osman8b43dad2020-10-09 13:31:42 -04001710 SPIRVCodeGenerator cg(fContext.get(), &program, this, &out);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001711 bool result = cg.generateCode();
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001712#endif
Ethan Nicholasce33f102016-12-09 17:22:59 -05001713 return result;
1714}
1715
Ethan Nicholas00543112018-07-31 09:44:36 -04001716bool Compiler::toSPIRV(Program& program, String* out) {
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001717 StringStream buffer;
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001718 bool result = this->toSPIRV(program, buffer);
1719 if (result) {
Ethan Nicholas762466e2017-06-29 10:03:38 -04001720 *out = buffer.str();
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001721 }
1722 return result;
1723}
1724
Ethan Nicholas00543112018-07-31 09:44:36 -04001725bool Compiler::toGLSL(Program& program, OutputStream& out) {
Brian Osmand010f652021-02-24 13:59:39 -05001726 TRACE_EVENT0("skia.gpu", "SkSL::Compiler::toGLSL");
Brian Osman88cda172020-10-09 12:05:16 -04001727 AutoSource as(this, program.fSource.get());
Ethan Nicholas26a9aad2018-03-27 14:10:52 -04001728 GLSLCodeGenerator cg(fContext.get(), &program, this, &out);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001729 bool result = cg.generateCode();
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001730 return result;
1731}
1732
Ethan Nicholas00543112018-07-31 09:44:36 -04001733bool Compiler::toGLSL(Program& program, String* out) {
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001734 StringStream buffer;
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001735 bool result = this->toGLSL(program, buffer);
1736 if (result) {
Ethan Nicholas762466e2017-06-29 10:03:38 -04001737 *out = buffer.str();
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001738 }
1739 return result;
1740}
1741
Brian Osmanc0243912020-02-19 15:35:26 -05001742bool Compiler::toHLSL(Program& program, String* out) {
1743 String spirv;
1744 if (!this->toSPIRV(program, &spirv)) {
1745 return false;
1746 }
1747
1748 return SPIRVtoHLSL(spirv, out);
1749}
1750
Ethan Nicholas00543112018-07-31 09:44:36 -04001751bool Compiler::toMetal(Program& program, OutputStream& out) {
Ethan Nicholas26a9aad2018-03-27 14:10:52 -04001752 MetalCodeGenerator cg(fContext.get(), &program, this, &out);
Ethan Nicholascc305772017-10-13 16:17:45 -04001753 bool result = cg.generateCode();
Ethan Nicholascc305772017-10-13 16:17:45 -04001754 return result;
1755}
1756
Ethan Nicholas00543112018-07-31 09:44:36 -04001757bool Compiler::toMetal(Program& program, String* out) {
Timothy Liangb8eeb802018-07-23 16:46:16 -04001758 StringStream buffer;
1759 bool result = this->toMetal(program, buffer);
1760 if (result) {
1761 *out = buffer.str();
1762 }
1763 return result;
1764}
1765
Greg Daniela28ea672020-09-25 11:12:56 -04001766#if defined(SKSL_STANDALONE) || GR_TEST_UTILS
Ethan Nicholas00543112018-07-31 09:44:36 -04001767bool Compiler::toCPP(Program& program, String name, OutputStream& out) {
Brian Osman88cda172020-10-09 12:05:16 -04001768 AutoSource as(this, program.fSource.get());
Ethan Nicholas26a9aad2018-03-27 14:10:52 -04001769 CPPCodeGenerator cg(fContext.get(), &program, this, name, &out);
Ethan Nicholas762466e2017-06-29 10:03:38 -04001770 bool result = cg.generateCode();
Ethan Nicholas762466e2017-06-29 10:03:38 -04001771 return result;
1772}
1773
Ethan Nicholas00543112018-07-31 09:44:36 -04001774bool Compiler::toH(Program& program, String name, OutputStream& out) {
Brian Osman88cda172020-10-09 12:05:16 -04001775 AutoSource as(this, program.fSource.get());
Ethan Nicholas26a9aad2018-03-27 14:10:52 -04001776 HCodeGenerator cg(fContext.get(), &program, this, name, &out);
Ethan Nicholas762466e2017-06-29 10:03:38 -04001777 bool result = cg.generateCode();
Ethan Nicholas00543112018-07-31 09:44:36 -04001778 return result;
1779}
Greg Daniela28ea672020-09-25 11:12:56 -04001780#endif // defined(SKSL_STANDALONE) || GR_TEST_UTILS
Ethan Nicholas00543112018-07-31 09:44:36 -04001781
Ethan Nicholas2a479a52020-08-18 16:29:45 -04001782#endif // defined(SKSL_STANDALONE) || SK_SUPPORT_GPU
Brian Osman2e29ab52019-09-20 12:19:11 -04001783
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001784Position Compiler::position(int offset) {
Ethan Nicholas3c729892020-12-07 12:47:17 -05001785 if (fSource && offset >= 0) {
1786 int line = 1;
1787 int column = 1;
1788 for (int i = 0; i < offset; i++) {
1789 if ((*fSource)[i] == '\n') {
1790 ++line;
1791 column = 1;
1792 }
1793 else {
1794 ++column;
1795 }
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001796 }
Ethan Nicholas3c729892020-12-07 12:47:17 -05001797 return Position(line, column);
1798 } else {
1799 return Position(-1, -1);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001800 }
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001801}
1802
1803void Compiler::error(int offset, String msg) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001804 fErrorCount++;
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001805 Position pos = this->position(offset);
John Stiles8d3642e2021-01-22 09:50:04 -05001806 fErrorTextLength.push_back(fErrorText.length());
Ethan Nicholas3c729892020-12-07 12:47:17 -05001807 fErrorText += "error: " + (pos.fLine >= 1 ? to_string(pos.fLine) + ": " : "") + msg + "\n";
ethannicholasb3058bd2016-07-01 08:22:01 -07001808}
1809
John Stiles8d3642e2021-01-22 09:50:04 -05001810void Compiler::setErrorCount(int c) {
1811 if (c < fErrorCount) {
1812 fErrorText.resize(fErrorTextLength[c]);
1813 fErrorTextLength.resize(c);
1814 fErrorCount = c;
1815 }
1816}
1817
Ethan Nicholas95046142021-01-07 10:57:27 -05001818String Compiler::errorText(bool showCount) {
1819 if (showCount) {
1820 this->writeErrorCount();
1821 }
Ethan Nicholas00543112018-07-31 09:44:36 -04001822 fErrorCount = 0;
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001823 String result = fErrorText;
Ethan Nicholas95046142021-01-07 10:57:27 -05001824 fErrorText = "";
ethannicholasb3058bd2016-07-01 08:22:01 -07001825 return result;
1826}
1827
1828void Compiler::writeErrorCount() {
1829 if (fErrorCount) {
1830 fErrorText += to_string(fErrorCount) + " error";
1831 if (fErrorCount > 1) {
1832 fErrorText += "s";
1833 }
1834 fErrorText += "\n";
1835 }
1836}
1837
John Stilesa6841be2020-08-06 14:11:56 -04001838} // namespace SkSL