blob: bbd84942adc2356bc96117d3c2770c75b4cce2d1 [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 -0500463static bool self_assignment(const BinaryExpression& b) {
John Stiles45990502021-02-16 10:55:27 -0500464 return b.getOperator().kind() == Token::Kind::TK_EQ &&
John Stiles95d0bad2021-03-01 17:02:28 -0500465 Analysis::IsSelfAssignment(*b.left(), *b.right());
John Stiles0ac6c152021-02-10 14:04:24 -0500466}
467
Ethan Nicholascb670962017-04-20 19:31:52 -0400468void Compiler::computeDataFlow(CFG* cfg) {
John Stilese8a24922021-02-08 17:54:08 -0500469 cfg->fBlocks[cfg->fStart].fBefore.computeStartState(*cfg);
John Stilese6150002020-10-05 12:03:53 -0400470
471 // We set bits in the "processed" set after a block has been scanned.
472 SkBitSet processedSet(cfg->fBlocks.size());
473 while (SkBitSet::OptionalIndex blockId = processedSet.findFirstUnset()) {
474 processedSet.set(*blockId);
475 this->scanCFG(cfg, *blockId, &processedSet);
ethannicholas22f939e2016-10-13 13:25:34 -0700476 }
Ethan Nicholascb670962017-04-20 19:31:52 -0400477}
478
479/**
480 * Attempts to replace the expression pointed to by iter with a new one (in both the CFG and the
481 * IR). If the expression can be cleanly removed, returns true and updates the iterator to point to
482 * the newly-inserted element. Otherwise updates only the IR and returns false (and the CFG will
483 * need to be regenerated).
484 */
John Stilesafbf8992020-08-18 10:08:21 -0400485static bool try_replace_expression(BasicBlock* b,
486 std::vector<BasicBlock::Node>::iterator* iter,
487 std::unique_ptr<Expression>* newExpression) {
Ethan Nicholascb670962017-04-20 19:31:52 -0400488 std::unique_ptr<Expression>* target = (*iter)->expression();
489 if (!b->tryRemoveExpression(iter)) {
490 *target = std::move(*newExpression);
491 return false;
492 }
493 *target = std::move(*newExpression);
494 return b->tryInsertExpression(iter, target);
495}
496
497/**
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400498 * Returns true if the expression is a constant numeric literal with the specified value, or a
499 * constant vector with all elements equal to the specified value.
Ethan Nicholascb670962017-04-20 19:31:52 -0400500 */
Ethan Nicholasa3f22f12020-10-01 12:13:17 -0400501template <typename T = SKSL_FLOAT>
John Stiles9d944232020-08-19 09:56:49 -0400502static bool is_constant(const Expression& expr, T value) {
Ethan Nicholase6592142020-09-08 10:22:09 -0400503 switch (expr.kind()) {
504 case Expression::Kind::kIntLiteral:
Ethan Nicholase96cdd12020-09-28 16:27:18 -0400505 return expr.as<IntLiteral>().value() == value;
John Stiles9d944232020-08-19 09:56:49 -0400506
Ethan Nicholase6592142020-09-08 10:22:09 -0400507 case Expression::Kind::kFloatLiteral:
Ethan Nicholasa3f22f12020-10-01 12:13:17 -0400508 return expr.as<FloatLiteral>().value() == value;
John Stiles9d944232020-08-19 09:56:49 -0400509
Ethan Nicholase6592142020-09-08 10:22:09 -0400510 case Expression::Kind::kConstructor: {
John Stiles9d944232020-08-19 09:56:49 -0400511 const Constructor& constructor = expr.as<Constructor>();
512 if (constructor.isCompileTimeConstant()) {
Ethan Nicholas30d30222020-09-11 12:27:26 -0400513 const Type& constructorType = constructor.type();
Ethan Nicholas30d30222020-09-11 12:27:26 -0400514 switch (constructorType.typeKind()) {
Ethan Nicholase6592142020-09-08 10:22:09 -0400515 case Type::TypeKind::kVector:
John Stilesbc75ebb2020-11-24 12:04:47 -0500516 if (constructor.componentType().isFloat()) {
517 for (int i = 0; i < constructorType.columns(); ++i) {
John Stiles9d944232020-08-19 09:56:49 -0400518 if (constructor.getFVecComponent(i) != value) {
519 return false;
520 }
John Stilesbc75ebb2020-11-24 12:04:47 -0500521 }
522 return true;
523 } else if (constructor.componentType().isInteger()) {
524 for (int i = 0; i < constructorType.columns(); ++i) {
John Stiles9d944232020-08-19 09:56:49 -0400525 if (constructor.getIVecComponent(i) != value) {
526 return false;
527 }
528 }
John Stilesbc75ebb2020-11-24 12:04:47 -0500529 return true;
Ethan Nicholasd188c182019-06-10 15:55:38 -0400530 }
John Stilesbc75ebb2020-11-24 12:04:47 -0500531 // Other types (e.g. boolean) might occur, but aren't supported here.
532 return false;
John Stiles9d944232020-08-19 09:56:49 -0400533
Ethan Nicholase6592142020-09-08 10:22:09 -0400534 case Type::TypeKind::kScalar:
Ethan Nicholasf70f0442020-09-29 12:41:35 -0400535 SkASSERT(constructor.arguments().size() == 1);
536 return is_constant<T>(*constructor.arguments()[0], value);
John Stiles9d944232020-08-19 09:56:49 -0400537
538 default:
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400539 return false;
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400540 }
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400541 }
542 return false;
543 }
Ethan Nicholascb670962017-04-20 19:31:52 -0400544 default:
545 return false;
546 }
547}
548
549/**
550 * Collapses the binary expression pointed to by iter down to just the right side (in both the IR
551 * and CFG structures).
552 */
John Stilesafbf8992020-08-18 10:08:21 -0400553static void delete_left(BasicBlock* b,
554 std::vector<BasicBlock::Node>::iterator* iter,
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400555 Compiler::OptimizationContext* optimizationContext) {
556 optimizationContext->fUpdated = true;
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400557 std::unique_ptr<Expression>* target = (*iter)->expression();
John Stilesa5a97b42020-08-18 11:19:07 -0400558 BinaryExpression& bin = (*target)->as<BinaryExpression>();
John Stiles2d4f9592020-10-30 10:29:12 -0400559 Expression& left = *bin.left();
560 std::unique_ptr<Expression>& rightPointer = bin.right();
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400561 SkASSERT(!left.hasSideEffects());
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400562 bool result;
John Stiles45990502021-02-16 10:55:27 -0500563 if (bin.getOperator().kind() == Token::Kind::TK_EQ) {
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400564 result = b->tryRemoveLValueBefore(iter, &left);
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400565 } else {
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400566 result = b->tryRemoveExpressionBefore(iter, &left);
Ethan Nicholascb670962017-04-20 19:31:52 -0400567 }
Brian Osman010ce6a2020-10-19 16:34:10 -0400568 // Remove references within LHS.
569 optimizationContext->fUsage->remove(&left);
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400570 *target = std::move(rightPointer);
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400571 if (!result) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400572 optimizationContext->fNeedsRescan = true;
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400573 return;
574 }
575 if (*iter == b->fNodes.begin()) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400576 optimizationContext->fNeedsRescan = true;
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400577 return;
578 }
579 --(*iter);
John Stiles70025e52020-09-28 16:08:58 -0400580 if (!(*iter)->isExpression() || (*iter)->expression() != &rightPointer) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400581 optimizationContext->fNeedsRescan = true;
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400582 return;
583 }
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400584 *iter = b->fNodes.erase(*iter);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400585 SkASSERT((*iter)->expression() == target);
Ethan Nicholascb670962017-04-20 19:31:52 -0400586}
587
588/**
589 * Collapses the binary expression pointed to by iter down to just the left side (in both the IR and
590 * CFG structures).
591 */
John Stilesafbf8992020-08-18 10:08:21 -0400592static void delete_right(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 std::unique_ptr<Expression>& leftPointer = bin.left();
599 Expression& right = *bin.right();
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400600 SkASSERT(!right.hasSideEffects());
Brian Osman010ce6a2020-10-19 16:34:10 -0400601 // Remove references within RHS.
602 optimizationContext->fUsage->remove(&right);
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400603 if (!b->tryRemoveExpressionBefore(iter, &right)) {
604 *target = std::move(leftPointer);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400605 optimizationContext->fNeedsRescan = true;
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400606 return;
Ethan Nicholascb670962017-04-20 19:31:52 -0400607 }
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400608 *target = std::move(leftPointer);
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400609 if (*iter == b->fNodes.begin()) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400610 optimizationContext->fNeedsRescan = true;
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400611 return;
612 }
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400613 --(*iter);
John Stiles70025e52020-09-28 16:08:58 -0400614 if ((!(*iter)->isExpression() || (*iter)->expression() != &leftPointer)) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400615 optimizationContext->fNeedsRescan = true;
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400616 return;
617 }
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400618 *iter = b->fNodes.erase(*iter);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400619 SkASSERT((*iter)->expression() == target);
Ethan Nicholascb670962017-04-20 19:31:52 -0400620}
621
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400622/**
623 * Constructs the specified type using a single argument.
624 */
Ethan Nicholas30d30222020-09-11 12:27:26 -0400625static std::unique_ptr<Expression> construct(const Type* type, std::unique_ptr<Expression> v) {
John Stiles8e3b6be2020-10-13 11:14:08 -0400626 ExpressionArray args;
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400627 args.push_back(std::move(v));
John Stiles54f00492021-02-19 11:46:10 -0500628 return std::make_unique<Constructor>(/*offset=*/-1, *type, std::move(args));
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400629}
630
631/**
632 * Used in the implementations of vectorize_left and vectorize_right. Given a vector type and an
633 * expression x, deletes the expression pointed to by iter and replaces it with <type>(x).
634 */
635static void vectorize(BasicBlock* b,
636 std::vector<BasicBlock::Node>::iterator* iter,
637 const Type& type,
638 std::unique_ptr<Expression>* otherExpression,
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400639 Compiler::OptimizationContext* optimizationContext) {
Ethan Nicholase6592142020-09-08 10:22:09 -0400640 SkASSERT((*(*iter)->expression())->kind() == Expression::Kind::kBinary);
John Stiles9aeed132020-11-24 17:36:06 -0500641 SkASSERT(type.isVector());
642 SkASSERT((*otherExpression)->type().isScalar());
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400643 optimizationContext->fUpdated = true;
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400644 std::unique_ptr<Expression>* target = (*iter)->expression();
645 if (!b->tryRemoveExpression(iter)) {
Ethan Nicholas30d30222020-09-11 12:27:26 -0400646 *target = construct(&type, std::move(*otherExpression));
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400647 optimizationContext->fNeedsRescan = true;
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400648 } else {
Ethan Nicholas30d30222020-09-11 12:27:26 -0400649 *target = construct(&type, std::move(*otherExpression));
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400650 if (!b->tryInsertExpression(iter, target)) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400651 optimizationContext->fNeedsRescan = true;
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400652 }
653 }
654}
655
656/**
657 * Given a binary expression of the form x <op> vec<n>(y), deletes the right side and vectorizes the
658 * left to yield vec<n>(x).
659 */
660static void vectorize_left(BasicBlock* b,
661 std::vector<BasicBlock::Node>::iterator* iter,
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400662 Compiler::OptimizationContext* optimizationContext) {
John Stilesa5a97b42020-08-18 11:19:07 -0400663 BinaryExpression& bin = (*(*iter)->expression())->as<BinaryExpression>();
Brian Osman010ce6a2020-10-19 16:34:10 -0400664 // Remove references within RHS. Vectorization of LHS doesn't change reference counts.
John Stiles2d4f9592020-10-30 10:29:12 -0400665 optimizationContext->fUsage->remove(bin.right().get());
666 vectorize(b, iter, bin.right()->type(), &bin.left(), optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400667}
668
669/**
670 * Given a binary expression of the form vec<n>(x) <op> y, deletes the left side and vectorizes the
671 * right to yield vec<n>(y).
672 */
673static void vectorize_right(BasicBlock* b,
674 std::vector<BasicBlock::Node>::iterator* iter,
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400675 Compiler::OptimizationContext* optimizationContext) {
John Stilesa5a97b42020-08-18 11:19:07 -0400676 BinaryExpression& bin = (*(*iter)->expression())->as<BinaryExpression>();
Brian Osman010ce6a2020-10-19 16:34:10 -0400677 // Remove references within LHS. Vectorization of RHS doesn't change reference counts.
John Stiles2d4f9592020-10-30 10:29:12 -0400678 optimizationContext->fUsage->remove(bin.left().get());
679 vectorize(b, iter, bin.left()->type(), &bin.right(), optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400680}
681
Ethan Nicholascb670962017-04-20 19:31:52 -0400682void Compiler::simplifyExpression(DefinitionMap& definitions,
683 BasicBlock& b,
684 std::vector<BasicBlock::Node>::iterator* iter,
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400685 OptimizationContext* optimizationContext) {
Ethan Nicholascb670962017-04-20 19:31:52 -0400686 Expression* expr = (*iter)->expression()->get();
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400687 SkASSERT(expr);
John Stiles108bbe22020-11-18 11:10:38 -0500688
Ethan Nicholascb670962017-04-20 19:31:52 -0400689 if ((*iter)->fConstantPropagation) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400690 std::unique_ptr<Expression> optimized = expr->constantPropagate(*fIRGenerator,
691 definitions);
Ethan Nicholascb670962017-04-20 19:31:52 -0400692 if (optimized) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400693 optimizationContext->fUpdated = true;
Ethan Nicholas30d30222020-09-11 12:27:26 -0400694 optimized = fIRGenerator->coerce(std::move(optimized), expr->type());
Ethan Nicholas1d881522020-09-11 09:32:54 -0400695 SkASSERT(optimized);
Brian Osman010ce6a2020-10-19 16:34:10 -0400696 // Remove references within 'expr', add references within 'optimized'
697 optimizationContext->fUsage->replace(expr, optimized.get());
Ethan Nicholascb670962017-04-20 19:31:52 -0400698 if (!try_replace_expression(&b, iter, &optimized)) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400699 optimizationContext->fNeedsRescan = true;
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400700 return;
Ethan Nicholascb670962017-04-20 19:31:52 -0400701 }
John Stiles70025e52020-09-28 16:08:58 -0400702 SkASSERT((*iter)->isExpression());
Ethan Nicholascb670962017-04-20 19:31:52 -0400703 expr = (*iter)->expression()->get();
Ethan Nicholascb670962017-04-20 19:31:52 -0400704 }
705 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400706 switch (expr->kind()) {
707 case Expression::Kind::kVariableReference: {
John Stilesa5a97b42020-08-18 11:19:07 -0400708 const VariableReference& ref = expr->as<VariableReference>();
Ethan Nicholas78686922020-10-08 06:46:27 -0400709 const Variable* var = ref.variable();
John Stiles66c53b92021-02-20 08:00:43 -0500710 if (fContext->fConfig->fSettings.fDeadCodeElimination &&
711 ref.refKind() != VariableReference::RefKind::kWrite &&
Ethan Nicholas453f67f2020-10-09 10:43:45 -0400712 ref.refKind() != VariableReference::RefKind::kPointer &&
John Stilese8a24922021-02-08 17:54:08 -0500713 var->storage() == Variable::Storage::kLocal && !definitions.get(var) &&
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400714 optimizationContext->fSilences.find(var) == optimizationContext->fSilences.end()) {
715 optimizationContext->fSilences.insert(var);
Ethan Nicholas82a62d22017-11-07 14:42:10 +0000716 this->error(expr->fOffset,
Ethan Nicholase2c49992020-10-05 11:49:11 -0400717 "'" + var->name() + "' has not been assigned");
Ethan Nicholascb670962017-04-20 19:31:52 -0400718 }
719 break;
720 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400721 case Expression::Kind::kTernary: {
John Stiles403a3632020-08-20 12:11:48 -0400722 TernaryExpression* t = &expr->as<TernaryExpression>();
Ethan Nicholasdd218162020-10-08 05:48:01 -0400723 if (t->test()->is<BoolLiteral>()) {
Ethan Nicholascb670962017-04-20 19:31:52 -0400724 // ternary has a constant test, replace it with either the true or
725 // false branch
Ethan Nicholasdd218162020-10-08 05:48:01 -0400726 if (t->test()->as<BoolLiteral>().value()) {
Brian Osman010ce6a2020-10-19 16:34:10 -0400727 (*iter)->setExpression(std::move(t->ifTrue()), optimizationContext->fUsage);
Ethan Nicholascb670962017-04-20 19:31:52 -0400728 } else {
Brian Osman010ce6a2020-10-19 16:34:10 -0400729 (*iter)->setExpression(std::move(t->ifFalse()), optimizationContext->fUsage);
Ethan Nicholascb670962017-04-20 19:31:52 -0400730 }
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400731 optimizationContext->fUpdated = true;
732 optimizationContext->fNeedsRescan = true;
Ethan Nicholascb670962017-04-20 19:31:52 -0400733 }
734 break;
735 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400736 case Expression::Kind::kBinary: {
John Stiles403a3632020-08-20 12:11:48 -0400737 BinaryExpression* bin = &expr->as<BinaryExpression>();
John Stiles0ac6c152021-02-10 14:04:24 -0500738 if (dead_assignment(*bin, optimizationContext->fUsage) || self_assignment(*bin)) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400739 delete_left(&b, iter, optimizationContext);
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400740 break;
741 }
John Stiles2d4f9592020-10-30 10:29:12 -0400742 Expression& left = *bin->left();
743 Expression& right = *bin->right();
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400744 const Type& leftType = left.type();
745 const Type& rightType = right.type();
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400746 // collapse useless expressions like x * 1 or x + 0
John Stiles9aeed132020-11-24 17:36:06 -0500747 if ((!leftType.isScalar() && !leftType.isVector()) ||
748 (!rightType.isScalar() && !rightType.isVector())) {
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400749 break;
750 }
John Stiles45990502021-02-16 10:55:27 -0500751 switch (bin->getOperator().kind()) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400752 case Token::Kind::TK_STAR:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400753 if (is_constant(left, 1)) {
John Stiles9aeed132020-11-24 17:36:06 -0500754 if (leftType.isVector() && rightType.isScalar()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400755 // float4(1) * x -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400756 vectorize_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400757 } else {
758 // 1 * x -> x
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400759 // 1 * float4(x) -> float4(x)
760 // float4(1) * float4(x) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400761 delete_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400762 }
763 }
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400764 else if (is_constant(left, 0)) {
John Stiles9aeed132020-11-24 17:36:06 -0500765 if (leftType.isScalar() && rightType.isVector() &&
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400766 !right.hasSideEffects()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400767 // 0 * float4(x) -> float4(0)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400768 vectorize_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400769 } else {
770 // 0 * x -> 0
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400771 // float4(0) * x -> float4(0)
772 // float4(0) * float4(x) -> float4(0)
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400773 if (!right.hasSideEffects()) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400774 delete_right(&b, iter, optimizationContext);
Ethan Nicholas51493ee2017-12-11 12:34:33 -0500775 }
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400776 }
Ethan Nicholascb670962017-04-20 19:31:52 -0400777 }
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400778 else if (is_constant(right, 1)) {
John Stiles9aeed132020-11-24 17:36:06 -0500779 if (leftType.isScalar() && rightType.isVector()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400780 // x * float4(1) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400781 vectorize_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400782 } else {
783 // x * 1 -> x
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400784 // float4(x) * 1 -> float4(x)
785 // float4(x) * float4(1) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400786 delete_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400787 }
788 }
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400789 else if (is_constant(right, 0)) {
John Stiles9aeed132020-11-24 17:36:06 -0500790 if (leftType.isVector() && rightType.isScalar() && !left.hasSideEffects()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400791 // float4(x) * 0 -> float4(0)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400792 vectorize_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400793 } else {
794 // x * 0 -> 0
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400795 // x * float4(0) -> float4(0)
796 // float4(x) * float4(0) -> float4(0)
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400797 if (!left.hasSideEffects()) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400798 delete_left(&b, iter, optimizationContext);
Ethan Nicholas51493ee2017-12-11 12:34:33 -0500799 }
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400800 }
Ethan Nicholascb670962017-04-20 19:31:52 -0400801 }
802 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400803 case Token::Kind::TK_PLUS:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400804 if (is_constant(left, 0)) {
John Stiles9aeed132020-11-24 17:36:06 -0500805 if (leftType.isVector() && rightType.isScalar()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400806 // float4(0) + x -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400807 vectorize_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400808 } else {
809 // 0 + x -> x
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400810 // 0 + float4(x) -> float4(x)
811 // float4(0) + float4(x) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400812 delete_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400813 }
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400814 } else if (is_constant(right, 0)) {
John Stiles9aeed132020-11-24 17:36:06 -0500815 if (leftType.isScalar() && rightType.isVector()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400816 // x + float4(0) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400817 vectorize_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400818 } else {
819 // x + 0 -> x
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400820 // float4(x) + 0 -> float4(x)
821 // float4(x) + float4(0) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400822 delete_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400823 }
Ethan Nicholas56e42712017-04-21 10:23:37 -0400824 }
825 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400826 case Token::Kind::TK_MINUS:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400827 if (is_constant(right, 0)) {
John Stiles9aeed132020-11-24 17:36:06 -0500828 if (leftType.isScalar() && rightType.isVector()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400829 // x - float4(0) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400830 vectorize_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400831 } else {
832 // x - 0 -> x
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400833 // float4(x) - 0 -> float4(x)
834 // float4(x) - float4(0) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400835 delete_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400836 }
Ethan Nicholascb670962017-04-20 19:31:52 -0400837 }
838 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400839 case Token::Kind::TK_SLASH:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400840 if (is_constant(right, 1)) {
John Stiles9aeed132020-11-24 17:36:06 -0500841 if (leftType.isScalar() && rightType.isVector()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400842 // x / float4(1) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400843 vectorize_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400844 } else {
845 // x / 1 -> x
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400846 // float4(x) / 1 -> float4(x)
847 // float4(x) / float4(1) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400848 delete_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400849 }
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400850 } else if (is_constant(left, 0)) {
John Stiles9aeed132020-11-24 17:36:06 -0500851 if (leftType.isScalar() && rightType.isVector() &&
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400852 !right.hasSideEffects()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400853 // 0 / float4(x) -> float4(0)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400854 vectorize_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400855 } else {
856 // 0 / x -> 0
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400857 // float4(0) / x -> float4(0)
858 // float4(0) / float4(x) -> float4(0)
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400859 if (!right.hasSideEffects()) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400860 delete_right(&b, iter, optimizationContext);
Ethan Nicholas51493ee2017-12-11 12:34:33 -0500861 }
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400862 }
863 }
864 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400865 case Token::Kind::TK_PLUSEQ:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400866 if (is_constant(right, 0)) {
John Stiles47c0a742021-02-09 09:30:35 -0500867 Analysis::UpdateRefKind(&left, RefKind::kRead);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400868 delete_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400869 }
870 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400871 case Token::Kind::TK_MINUSEQ:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400872 if (is_constant(right, 0)) {
John Stiles47c0a742021-02-09 09:30:35 -0500873 Analysis::UpdateRefKind(&left, RefKind::kRead);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400874 delete_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400875 }
876 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400877 case Token::Kind::TK_STAREQ:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400878 if (is_constant(right, 1)) {
John Stiles47c0a742021-02-09 09:30:35 -0500879 Analysis::UpdateRefKind(&left, RefKind::kRead);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400880 delete_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400881 }
882 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400883 case Token::Kind::TK_SLASHEQ:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400884 if (is_constant(right, 1)) {
John Stiles47c0a742021-02-09 09:30:35 -0500885 Analysis::UpdateRefKind(&left, RefKind::kRead);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400886 delete_right(&b, iter, optimizationContext);
Ethan Nicholascb670962017-04-20 19:31:52 -0400887 }
888 break;
889 default:
890 break;
891 }
Ethan Nicholas409f6f02019-09-17 12:34:39 -0400892 break;
893 }
John Stilesf5c1d042020-11-21 23:26:07 -0500894 case Expression::Kind::kConstructor: {
John Stilesb9e4f642021-03-05 09:11:38 -0500895 // TODO(skia:11319): this optimization logic is redundant with the optimization code
896 // found in SkSLConstructor.cpp.
897
John Stilesf5c1d042020-11-21 23:26:07 -0500898 // Find constructors embedded inside constructors and flatten them out where possible.
899 // - float4(float2(1, 2), 3, 4) --> float4(1, 2, 3, 4)
900 // - float4(w, float3(sin(x), cos(y), tan(z))) --> float4(w, sin(x), cos(y), tan(z))
901 // Leave single-argument constructors alone, though. These might be casts or splats.
902 Constructor& c = expr->as<Constructor>();
903 if (c.type().columns() > 1) {
904 // Inspect each constructor argument to see if it's a candidate for flattening.
905 // Remember matched arguments in a bitfield, "argsToOptimize".
906 int argsToOptimize = 0;
907 int currBit = 1;
908 for (const std::unique_ptr<Expression>& arg : c.arguments()) {
909 if (arg->is<Constructor>()) {
910 Constructor& inner = arg->as<Constructor>();
911 if (inner.arguments().size() > 1 &&
912 inner.type().componentType() == c.type().componentType()) {
913 argsToOptimize |= currBit;
914 }
915 }
916 currBit <<= 1;
917 }
918 if (argsToOptimize) {
919 // We found at least one argument that could be flattened out. Re-walk the
920 // constructor args and flatten the candidates we found during our initial pass.
921 ExpressionArray flattened;
922 flattened.reserve_back(c.type().columns());
923 currBit = 1;
924 for (const std::unique_ptr<Expression>& arg : c.arguments()) {
925 if (argsToOptimize & currBit) {
926 Constructor& inner = arg->as<Constructor>();
927 for (const std::unique_ptr<Expression>& innerArg : inner.arguments()) {
928 flattened.push_back(innerArg->clone());
929 }
930 } else {
931 flattened.push_back(arg->clone());
932 }
933 currBit <<= 1;
934 }
John Stiles54f00492021-02-19 11:46:10 -0500935 std::unique_ptr<Expression> replacement = std::make_unique<Constructor>(
936 c.fOffset, c.type(), std::move(flattened));
John Stiles1b91c0e2021-02-11 11:43:09 -0500937 // We're replacing an expression with a cloned version; we'll need a rescan.
938 // No fUsage change: `float2(float(x), y)` and `float2(x, y)` have equivalent
939 // reference counts.
940 try_replace_expression(&b, iter, &replacement);
John Stilesf5c1d042020-11-21 23:26:07 -0500941 optimizationContext->fUpdated = true;
John Stiles1b91c0e2021-02-11 11:43:09 -0500942 optimizationContext->fNeedsRescan = true;
John Stilesf5c1d042020-11-21 23:26:07 -0500943 break;
944 }
945 }
946 break;
947 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400948 case Expression::Kind::kSwizzle: {
John Stiles403a3632020-08-20 12:11:48 -0400949 Swizzle& s = expr->as<Swizzle>();
John Stiles108bbe22020-11-18 11:10:38 -0500950 // Detect identity swizzles like `foo.rgba`.
Ethan Nicholas6b4d5812020-10-12 16:11:51 -0400951 if ((int) s.components().size() == s.base()->type().columns()) {
Ethan Nicholas409f6f02019-09-17 12:34:39 -0400952 bool identity = true;
Ethan Nicholas6b4d5812020-10-12 16:11:51 -0400953 for (int i = 0; i < (int) s.components().size(); ++i) {
954 if (s.components()[i] != i) {
Ethan Nicholas409f6f02019-09-17 12:34:39 -0400955 identity = false;
956 break;
957 }
958 }
959 if (identity) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400960 optimizationContext->fUpdated = true;
Brian Osman010ce6a2020-10-19 16:34:10 -0400961 // No fUsage change: foo.rgba and foo have equivalent reference counts
Ethan Nicholas6b4d5812020-10-12 16:11:51 -0400962 if (!try_replace_expression(&b, iter, &s.base())) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400963 optimizationContext->fNeedsRescan = true;
Ethan Nicholas409f6f02019-09-17 12:34:39 -0400964 return;
965 }
John Stiles70025e52020-09-28 16:08:58 -0400966 SkASSERT((*iter)->isExpression());
Ethan Nicholas409f6f02019-09-17 12:34:39 -0400967 break;
968 }
969 }
John Stiles108bbe22020-11-18 11:10:38 -0500970 // Detect swizzles of swizzles, e.g. replace `foo.argb.r000` with `foo.a000`.
971 if (s.base()->is<Swizzle>()) {
Ethan Nicholas6b4d5812020-10-12 16:11:51 -0400972 Swizzle& base = s.base()->as<Swizzle>();
John Stiles750109b2020-10-30 13:45:46 -0400973 ComponentArray final;
Ethan Nicholas6b4d5812020-10-12 16:11:51 -0400974 for (int c : s.components()) {
975 final.push_back(base.components()[c]);
Ethan Nicholas409f6f02019-09-17 12:34:39 -0400976 }
Ethan Nicholas6b4d5812020-10-12 16:11:51 -0400977 std::unique_ptr<Expression> replacement(new Swizzle(*fContext, base.base()->clone(),
John Stiles750109b2020-10-30 13:45:46 -0400978 final));
John Stilesd2f51b12021-01-07 18:12:31 -0500979 // We're replacing an expression with a cloned version; we'll need a rescan.
John Stiles108bbe22020-11-18 11:10:38 -0500980 // No fUsage change: `foo.gbr.gbr` and `foo.brg` have equivalent reference counts
John Stilesd2f51b12021-01-07 18:12:31 -0500981 try_replace_expression(&b, iter, &replacement);
982 optimizationContext->fUpdated = true;
983 optimizationContext->fNeedsRescan = true;
John Stiles108bbe22020-11-18 11:10:38 -0500984 break;
985 }
986 // Optimize swizzles of constructors.
987 if (s.base()->is<Constructor>()) {
988 Constructor& base = s.base()->as<Constructor>();
989 std::unique_ptr<Expression> replacement;
990 const Type& componentType = base.type().componentType();
991 int swizzleSize = s.components().size();
992
993 // The IR generator has already converted any zero/one swizzle components into
994 // constructors containing zero/one args. Confirm that this is true by checking that
995 // our swizzle components are all `xyzw` (values 0 through 3).
996 SkASSERT(std::all_of(s.components().begin(), s.components().end(),
997 [](int8_t c) { return c >= 0 && c <= 3; }));
998
John Stiles9aeed132020-11-24 17:36:06 -0500999 if (base.arguments().size() == 1 && base.arguments().front()->type().isScalar()) {
John Stiles108bbe22020-11-18 11:10:38 -05001000 // `half4(scalar).zyy` can be optimized to `half3(scalar)`. The swizzle
1001 // components don't actually matter since all fields are the same.
John Stilesf0cb7332021-01-08 18:39:00 -05001002 const Expression& argument = *base.arguments().front();
1003 const Type& constructorType = componentType.toCompound(*fContext, swizzleSize,
1004 /*rows=*/1);
1005 replacement = Constructor::SimplifyConversion(constructorType, argument);
1006 if (!replacement) {
1007 ExpressionArray newArgs;
1008 newArgs.push_back(argument.clone());
John Stiles54f00492021-02-19 11:46:10 -05001009 replacement = std::make_unique<Constructor>(base.fOffset, constructorType,
John Stilesf0cb7332021-01-08 18:39:00 -05001010 std::move(newArgs));
1011 }
John Stiles108bbe22020-11-18 11:10:38 -05001012
John Stilesa60ac0c2020-12-22 08:59:51 -05001013 // We're replacing an expression with a cloned version; we'll need a rescan.
1014 // There's no fUsage change: `half4(foo).xy` and `half2(foo)` have equivalent
1015 // reference counts.
1016 try_replace_expression(&b, iter, &replacement);
John Stiles0777ac42020-11-19 11:06:47 -05001017 optimizationContext->fUpdated = true;
John Stilesa60ac0c2020-12-22 08:59:51 -05001018 optimizationContext->fNeedsRescan = true;
John Stiles108bbe22020-11-18 11:10:38 -05001019 break;
1020 }
1021
John Stiles0777ac42020-11-19 11:06:47 -05001022 // Swizzles can duplicate some elements and discard others, e.g.
1023 // `half4(1, 2, 3, 4).xxz` --> `half3(1, 1, 3)`. However, there are constraints:
1024 // - Expressions with side effects need to occur exactly once, even if they
1025 // would otherwise be swizzle-eliminated
1026 // - Non-trivial expressions should not be repeated, but elimination is OK.
1027 //
1028 // Look up the argument for the constructor at each index. This is typically simple
1029 // but for weird cases like `half4(bar.yz, half2(foo))`, it can be harder than it
1030 // seems. This example would result in:
1031 // argMap[0] = {.fArgIndex = 0, .fComponent = 0} (bar.yz .x)
1032 // argMap[1] = {.fArgIndex = 0, .fComponent = 1} (bar.yz .y)
1033 // argMap[2] = {.fArgIndex = 1, .fComponent = 0} (half2(foo) .x)
1034 // argMap[3] = {.fArgIndex = 1, .fComponent = 1} (half2(foo) .y)
1035 struct ConstructorArgMap {
1036 int8_t fArgIndex;
1037 int8_t fComponent;
1038 };
1039
1040 int numConstructorArgs = base.type().columns();
1041 ConstructorArgMap argMap[4] = {};
1042 int writeIdx = 0;
1043 for (int argIdx = 0; argIdx < (int) base.arguments().size(); ++argIdx) {
1044 const Expression& expr = *base.arguments()[argIdx];
1045 int argWidth = expr.type().columns();
1046 for (int componentIdx = 0; componentIdx < argWidth; ++componentIdx) {
1047 argMap[writeIdx].fArgIndex = argIdx;
1048 argMap[writeIdx].fComponent = componentIdx;
1049 ++writeIdx;
1050 }
1051 }
1052 SkASSERT(writeIdx == numConstructorArgs);
1053
1054 // Count up the number of times each constructor argument is used by the
1055 // swizzle.
1056 // `half4(bar.yz, half2(foo)).xwxy` -> { 3, 1 }
1057 // - bar.yz is referenced 3 times, by `.x_xy`
1058 // - half(foo) is referenced 1 time, by `._w__`
1059 int8_t exprUsed[4] = {};
1060 for (int c : s.components()) {
1061 exprUsed[argMap[c].fArgIndex]++;
1062 }
1063
1064 bool safeToOptimize = true;
1065 for (int index = 0; index < numConstructorArgs; ++index) {
1066 int8_t constructorArgIndex = argMap[index].fArgIndex;
1067 const Expression& baseArg = *base.arguments()[constructorArgIndex];
1068
1069 // Check that non-trivial expressions are not swizzled in more than once.
John Stilesc30fbca2020-11-19 16:25:49 -05001070 if (exprUsed[constructorArgIndex] > 1 &&
1071 !Analysis::IsTrivialExpression(baseArg)) {
John Stiles0777ac42020-11-19 11:06:47 -05001072 safeToOptimize = false;
1073 break;
1074 }
1075 // Check that side-effect-bearing expressions are swizzled in exactly once.
1076 if (exprUsed[constructorArgIndex] != 1 && baseArg.hasSideEffects()) {
1077 safeToOptimize = false;
1078 break;
1079 }
1080 }
1081
1082 if (safeToOptimize) {
John Stilesd9076cb2020-11-19 12:18:36 -05001083 struct ReorderedArgument {
1084 int8_t fArgIndex;
1085 ComponentArray fComponents;
1086 };
1087 SkSTArray<4, ReorderedArgument> reorderedArgs;
John Stiles0777ac42020-11-19 11:06:47 -05001088 for (int c : s.components()) {
1089 const ConstructorArgMap& argument = argMap[c];
1090 const Expression& baseArg = *base.arguments()[argument.fArgIndex];
1091
John Stiles9aeed132020-11-24 17:36:06 -05001092 if (baseArg.type().isScalar()) {
John Stilesd9076cb2020-11-19 12:18:36 -05001093 // This argument is a scalar; add it to the list as-is.
John Stiles0777ac42020-11-19 11:06:47 -05001094 SkASSERT(argument.fComponent == 0);
John Stilesd9076cb2020-11-19 12:18:36 -05001095 reorderedArgs.push_back({argument.fArgIndex,
1096 ComponentArray{}});
John Stiles0777ac42020-11-19 11:06:47 -05001097 } else {
John Stilesd9076cb2020-11-19 12:18:36 -05001098 // This argument is a component from a vector.
John Stiles0777ac42020-11-19 11:06:47 -05001099 SkASSERT(argument.fComponent < baseArg.type().columns());
John Stilesd9076cb2020-11-19 12:18:36 -05001100 if (reorderedArgs.empty() ||
1101 reorderedArgs.back().fArgIndex != argument.fArgIndex) {
1102 // This can't be combined with the previous argument. Add a new one.
1103 reorderedArgs.push_back({argument.fArgIndex,
1104 ComponentArray{argument.fComponent}});
1105 } else {
1106 // Since we know this argument uses components, it should already
1107 // have at least one component set.
1108 SkASSERT(!reorderedArgs.back().fComponents.empty());
1109 // Build up the current argument with one more component.
1110 reorderedArgs.back().fComponents.push_back(argument.fComponent);
1111 }
John Stiles0777ac42020-11-19 11:06:47 -05001112 }
1113 }
John Stilesd9076cb2020-11-19 12:18:36 -05001114
1115 // Convert our reordered argument list to an actual array of expressions, with
1116 // the new order and any new inner swizzles that need to be applied. Note that
1117 // we expect followup passes to clean up the inner swizzles.
1118 ExpressionArray newArgs;
1119 newArgs.reserve_back(swizzleSize);
1120 for (const ReorderedArgument& reorderedArg : reorderedArgs) {
1121 const Expression& baseArg = *base.arguments()[reorderedArg.fArgIndex];
1122 if (reorderedArg.fComponents.empty()) {
1123 newArgs.push_back(baseArg.clone());
1124 } else {
1125 newArgs.push_back(std::make_unique<Swizzle>(*fContext, baseArg.clone(),
1126 reorderedArg.fComponents));
1127 }
1128 }
1129
1130 // Create a new constructor.
John Stiles0777ac42020-11-19 11:06:47 -05001131 replacement = std::make_unique<Constructor>(
1132 base.fOffset,
John Stiles54f00492021-02-19 11:46:10 -05001133 componentType.toCompound(*fContext, swizzleSize, /*rows=*/1),
John Stiles0777ac42020-11-19 11:06:47 -05001134 std::move(newArgs));
1135
John Stilesa60ac0c2020-12-22 08:59:51 -05001136 // Remove references within 'expr', add references within 'replacement.'
John Stiles0777ac42020-11-19 11:06:47 -05001137 optimizationContext->fUsage->replace(expr, replacement.get());
John Stilesa60ac0c2020-12-22 08:59:51 -05001138
1139 // We're replacing an expression with a cloned version; we'll need a rescan.
1140 try_replace_expression(&b, iter, &replacement);
1141 optimizationContext->fUpdated = true;
1142 optimizationContext->fNeedsRescan = true;
John Stiles0777ac42020-11-19 11:06:47 -05001143 }
John Stiles108bbe22020-11-18 11:10:38 -05001144 break;
Ethan Nicholas409f6f02019-09-17 12:34:39 -04001145 }
John Stiles30212b72020-06-11 17:55:07 -04001146 break;
Ethan Nicholascb670962017-04-20 19:31:52 -04001147 }
1148 default:
1149 break;
1150 }
1151}
1152
1153void Compiler::simplifyStatement(DefinitionMap& definitions,
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001154 BasicBlock& b,
1155 std::vector<BasicBlock::Node>::iterator* iter,
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001156 OptimizationContext* optimizationContext) {
Brian Osman010ce6a2020-10-19 16:34:10 -04001157 ProgramUsage* usage = optimizationContext->fUsage;
Ethan Nicholascb670962017-04-20 19:31:52 -04001158 Statement* stmt = (*iter)->statement()->get();
Ethan Nicholase6592142020-09-08 10:22:09 -04001159 switch (stmt->kind()) {
1160 case Statement::Kind::kVarDeclaration: {
John Stilesa5a97b42020-08-18 11:19:07 -04001161 const auto& varDecl = stmt->as<VarDeclaration>();
Brian Osman010ce6a2020-10-19 16:34:10 -04001162 if (usage->isDead(varDecl.var()) &&
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04001163 (!varDecl.value() ||
1164 !varDecl.value()->hasSideEffects())) {
1165 if (varDecl.value()) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001166 SkASSERT((*iter)->statement()->get() == stmt);
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04001167 if (!b.tryRemoveExpressionBefore(iter, varDecl.value().get())) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001168 optimizationContext->fNeedsRescan = true;
Ethan Nicholascb670962017-04-20 19:31:52 -04001169 }
Ethan Nicholascb670962017-04-20 19:31:52 -04001170 }
Ethan Nicholas5b9b0db2021-01-21 13:12:01 -05001171 // There can still be (soon to be removed) references to the variable at this point.
1172 // Allowing the VarDeclaration to be destroyed here will break those variable's
1173 // initialValue()s, so we hang on to them until optimization is finished.
1174 std::unique_ptr<Statement> old = (*iter)->setStatement(std::make_unique<Nop>(),
1175 usage);
1176 optimizationContext->fOwnedStatements.push_back(std::move(old));
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001177 optimizationContext->fUpdated = true;
Ethan Nicholascb670962017-04-20 19:31:52 -04001178 }
1179 break;
1180 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001181 case Statement::Kind::kIf: {
John Stiles4633c912021-03-03 16:13:45 -05001182 // TODO(skia:11319): this optimization logic is redundant with the optimization code
1183 // found in IfStatement.cpp.
John Stilesa5a97b42020-08-18 11:19:07 -04001184 IfStatement& i = stmt->as<IfStatement>();
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001185 if (i.test()->kind() == Expression::Kind::kBoolLiteral) {
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001186 // constant if, collapse down to a single branch
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001187 if (i.test()->as<BoolLiteral>().value()) {
1188 SkASSERT(i.ifTrue());
Brian Osman010ce6a2020-10-19 16:34:10 -04001189 (*iter)->setStatement(std::move(i.ifTrue()), usage);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001190 } else {
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001191 if (i.ifFalse()) {
Brian Osman010ce6a2020-10-19 16:34:10 -04001192 (*iter)->setStatement(std::move(i.ifFalse()), usage);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001193 } else {
Brian Osman010ce6a2020-10-19 16:34:10 -04001194 (*iter)->setStatement(std::make_unique<Nop>(), usage);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001195 }
1196 }
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001197 optimizationContext->fUpdated = true;
1198 optimizationContext->fNeedsRescan = true;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001199 break;
1200 }
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001201 if (i.ifFalse() && i.ifFalse()->isEmpty()) {
Ethan Nicholascb670962017-04-20 19:31:52 -04001202 // else block doesn't do anything, remove it
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001203 i.ifFalse().reset();
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001204 optimizationContext->fUpdated = true;
1205 optimizationContext->fNeedsRescan = true;
Ethan Nicholascb670962017-04-20 19:31:52 -04001206 }
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001207 if (!i.ifFalse() && i.ifTrue()->isEmpty()) {
Ethan Nicholascb670962017-04-20 19:31:52 -04001208 // if block doesn't do anything, no else block
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001209 if (i.test()->hasSideEffects()) {
Ethan Nicholascb670962017-04-20 19:31:52 -04001210 // test has side effects, keep it
Brian Osman010ce6a2020-10-19 16:34:10 -04001211 (*iter)->setStatement(
1212 std::make_unique<ExpressionStatement>(std::move(i.test())), usage);
Ethan Nicholascb670962017-04-20 19:31:52 -04001213 } else {
1214 // no if, no else, no test side effects, kill the whole if
1215 // statement
Brian Osman010ce6a2020-10-19 16:34:10 -04001216 (*iter)->setStatement(std::make_unique<Nop>(), usage);
Ethan Nicholascb670962017-04-20 19:31:52 -04001217 }
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001218 optimizationContext->fUpdated = true;
1219 optimizationContext->fNeedsRescan = true;
Ethan Nicholascb670962017-04-20 19:31:52 -04001220 }
1221 break;
1222 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001223 case Statement::Kind::kSwitch: {
John Stiles642cde22021-02-23 14:57:01 -05001224 // TODO(skia:11319): this optimization logic is redundant with the static-switch
1225 // optimization code found in SwitchStatement.cpp.
John Stilesa5a97b42020-08-18 11:19:07 -04001226 SwitchStatement& s = stmt->as<SwitchStatement>();
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001227 int64_t switchValue;
Ethan Nicholasc0f98152021-02-05 16:21:10 -05001228 if (ConstantFolder::GetConstantInt(*s.value(), &switchValue)) {
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001229 // switch is constant, replace it with the case that matches
1230 bool found = false;
1231 SwitchCase* defaultCase = nullptr;
John Stiles2d4f9592020-10-30 10:29:12 -04001232 for (const std::unique_ptr<SwitchCase>& c : s.cases()) {
1233 if (!c->value()) {
1234 defaultCase = c.get();
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001235 continue;
1236 }
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001237 int64_t caseValue;
Ethan Nicholasc0f98152021-02-05 16:21:10 -05001238 SkAssertResult(ConstantFolder::GetConstantInt(*c->value(), &caseValue));
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001239 if (caseValue == switchValue) {
John Stiles642cde22021-02-23 14:57:01 -05001240 std::unique_ptr<Statement> newBlock =
1241 SwitchStatement::BlockForCase(&s.cases(), c.get(), s.symbols());
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001242 if (newBlock) {
Brian Osman010ce6a2020-10-19 16:34:10 -04001243 (*iter)->setStatement(std::move(newBlock), usage);
John Stiles9d944232020-08-19 09:56:49 -04001244 found = true;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001245 break;
1246 } else {
John Stilesd6a5f4492021-02-11 15:46:11 -05001247 if (s.isStatic() &&
John Stilesd1204642021-02-17 16:30:02 -05001248 !fContext->fConfig->fSettings.fPermitInvalidStaticTests) {
John Stilesd6a5f4492021-02-11 15:46:11 -05001249 auto [iter, didInsert] = optimizationContext->fSilences.insert(&s);
1250 if (didInsert) {
1251 this->error(s.fOffset, "static switch contains non-static "
John Stiles04ca41a2021-02-23 09:58:04 -05001252 "conditional exit");
John Stilesd6a5f4492021-02-11 15:46:11 -05001253 }
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001254 }
1255 return; // can't simplify
1256 }
1257 }
1258 }
1259 if (!found) {
1260 // no matching case. use default if it exists, or kill the whole thing
1261 if (defaultCase) {
John Stiles642cde22021-02-23 14:57:01 -05001262 std::unique_ptr<Statement> newBlock =
1263 SwitchStatement::BlockForCase(&s.cases(), defaultCase, s.symbols());
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001264 if (newBlock) {
Brian Osman010ce6a2020-10-19 16:34:10 -04001265 (*iter)->setStatement(std::move(newBlock), usage);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001266 } else {
John Stilesd6a5f4492021-02-11 15:46:11 -05001267 if (s.isStatic() &&
John Stilesd1204642021-02-17 16:30:02 -05001268 !fContext->fConfig->fSettings.fPermitInvalidStaticTests) {
John Stilesd6a5f4492021-02-11 15:46:11 -05001269 auto [iter, didInsert] = optimizationContext->fSilences.insert(&s);
1270 if (didInsert) {
1271 this->error(s.fOffset, "static switch contains non-static "
John Stiles04ca41a2021-02-23 09:58:04 -05001272 "conditional exit");
John Stilesd6a5f4492021-02-11 15:46:11 -05001273 }
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001274 }
1275 return; // can't simplify
1276 }
1277 } else {
Brian Osman010ce6a2020-10-19 16:34:10 -04001278 (*iter)->setStatement(std::make_unique<Nop>(), usage);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001279 }
1280 }
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001281 optimizationContext->fUpdated = true;
1282 optimizationContext->fNeedsRescan = true;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001283 }
1284 break;
1285 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001286 case Statement::Kind::kExpression: {
John Stilesa5a97b42020-08-18 11:19:07 -04001287 ExpressionStatement& e = stmt->as<ExpressionStatement>();
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001288 SkASSERT((*iter)->statement()->get() == &e);
Ethan Nicholasd503a5a2020-09-30 09:29:55 -04001289 if (!e.expression()->hasSideEffects()) {
Ethan Nicholascb670962017-04-20 19:31:52 -04001290 // Expression statement with no side effects, kill it
Ethan Nicholasd503a5a2020-09-30 09:29:55 -04001291 if (!b.tryRemoveExpressionBefore(iter, e.expression().get())) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001292 optimizationContext->fNeedsRescan = true;
Ethan Nicholascb670962017-04-20 19:31:52 -04001293 }
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001294 SkASSERT((*iter)->statement()->get() == stmt);
Brian Osman010ce6a2020-10-19 16:34:10 -04001295 (*iter)->setStatement(std::make_unique<Nop>(), usage);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001296 optimizationContext->fUpdated = true;
Ethan Nicholascb670962017-04-20 19:31:52 -04001297 }
1298 break;
1299 }
1300 default:
1301 break;
1302 }
1303}
1304
Brian Osman010ce6a2020-10-19 16:34:10 -04001305bool Compiler::scanCFG(FunctionDefinition& f, ProgramUsage* usage) {
John Stiles0cc193a2020-09-09 09:39:34 -04001306 bool madeChanges = false;
1307
Ethan Nicholascb670962017-04-20 19:31:52 -04001308 CFG cfg = CFGGenerator().getCFG(f);
1309 this->computeDataFlow(&cfg);
ethannicholas22f939e2016-10-13 13:25:34 -07001310
John Stiles66c53b92021-02-20 08:00:43 -05001311 if (fContext->fConfig->fSettings.fDeadCodeElimination) {
1312 // Check for unreachable code.
1313 for (size_t i = 0; i < cfg.fBlocks.size(); i++) {
1314 const BasicBlock& block = cfg.fBlocks[i];
1315 if (!block.fIsReachable && !block.fAllowUnreachable && block.fNodes.size()) {
1316 const BasicBlock::Node& node = block.fNodes[0];
1317 int offset = node.isStatement() ? (*node.statement())->fOffset
1318 : (*node.expression())->fOffset;
1319 this->error(offset, String("unreachable"));
1320 }
ethannicholas22f939e2016-10-13 13:25:34 -07001321 }
1322 }
1323 if (fErrorCount) {
John Stiles0cc193a2020-09-09 09:39:34 -04001324 return madeChanges;
ethannicholas22f939e2016-10-13 13:25:34 -07001325 }
1326
Ethan Nicholascb670962017-04-20 19:31:52 -04001327 // check for dead code & undefined variables, perform constant propagation
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001328 OptimizationContext optimizationContext;
Brian Osman010ce6a2020-10-19 16:34:10 -04001329 optimizationContext.fUsage = usage;
John Stiles7d3f0892020-11-03 11:35:01 -05001330 SkBitSet eliminatedBlockIds(cfg.fBlocks.size());
Ethan Nicholascb670962017-04-20 19:31:52 -04001331 do {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001332 if (optimizationContext.fNeedsRescan) {
Ethan Nicholascb670962017-04-20 19:31:52 -04001333 cfg = CFGGenerator().getCFG(f);
1334 this->computeDataFlow(&cfg);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001335 optimizationContext.fNeedsRescan = false;
Ethan Nicholas113628d2017-02-02 16:11:39 -05001336 }
Ethan Nicholascb670962017-04-20 19:31:52 -04001337
John Stiles7d3f0892020-11-03 11:35:01 -05001338 eliminatedBlockIds.reset();
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001339 optimizationContext.fUpdated = false;
John Stiles7d3f0892020-11-03 11:35:01 -05001340
1341 for (BlockId blockId = 0; blockId < cfg.fBlocks.size(); ++blockId) {
1342 if (eliminatedBlockIds.test(blockId)) {
1343 // We reached a block ID that might have been eliminated. Be cautious and rescan.
1344 optimizationContext.fUpdated = true;
1345 optimizationContext.fNeedsRescan = true;
1346 break;
1347 }
1348
1349 BasicBlock& b = cfg.fBlocks[blockId];
John Stiles66c53b92021-02-20 08:00:43 -05001350 if (fContext->fConfig->fSettings.fDeadCodeElimination) {
1351 if (blockId > 0 && !b.fIsReachable) {
1352 // Block was reachable before optimization, but has since become unreachable. In
1353 // addition to being dead code, it's broken - since control flow can't reach it,
1354 // no prior variable definitions can reach it, and therefore variables might
1355 // look to have not been properly assigned. Kill it by replacing all statements
1356 // with Nops.
1357 for (BasicBlock::Node& node : b.fNodes) {
1358 if (node.isStatement() && !(*node.statement())->is<Nop>()) {
1359 // Eliminating a node runs the risk of eliminating that node's exits as
1360 // well. Keep track of this and do a rescan if we are about to access
1361 // one of these.
1362 for (BlockId id : b.fExits) {
1363 eliminatedBlockIds.set(id);
1364 }
1365 node.setStatement(std::make_unique<Nop>(), usage);
1366 madeChanges = true;
John Stiles7d3f0892020-11-03 11:35:01 -05001367 }
Ethan Nicholas1de14812020-06-19 15:32:49 -04001368 }
John Stiles66c53b92021-02-20 08:00:43 -05001369 continue;
Ethan Nicholas1de14812020-06-19 15:32:49 -04001370 }
Ethan Nicholas1de14812020-06-19 15:32:49 -04001371 }
Ethan Nicholascb670962017-04-20 19:31:52 -04001372 DefinitionMap definitions = b.fBefore;
1373
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001374 for (auto iter = b.fNodes.begin(); iter != b.fNodes.end() &&
1375 !optimizationContext.fNeedsRescan; ++iter) {
John Stiles70025e52020-09-28 16:08:58 -04001376 if (iter->isExpression()) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001377 this->simplifyExpression(definitions, b, &iter, &optimizationContext);
Ethan Nicholascb670962017-04-20 19:31:52 -04001378 } else {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001379 this->simplifyStatement(definitions, b, &iter, &optimizationContext);
Ethan Nicholascb670962017-04-20 19:31:52 -04001380 }
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001381 if (optimizationContext.fNeedsRescan) {
Ethan Nicholas4b330df2017-05-17 10:52:55 -04001382 break;
1383 }
John Stilese8a24922021-02-08 17:54:08 -05001384 definitions.addDefinitions(*fContext, *iter);
Ethan Nicholascb670962017-04-20 19:31:52 -04001385 }
Brian Osman01a3eb42020-09-14 11:32:49 -04001386
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001387 if (optimizationContext.fNeedsRescan) {
Brian Osman01a3eb42020-09-14 11:32:49 -04001388 break;
1389 }
Ethan Nicholascb670962017-04-20 19:31:52 -04001390 }
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001391 madeChanges |= optimizationContext.fUpdated;
1392 } while (optimizationContext.fUpdated);
1393 SkASSERT(!optimizationContext.fNeedsRescan);
ethannicholas22f939e2016-10-13 13:25:34 -07001394
John Stiles0cc193a2020-09-09 09:39:34 -04001395 return madeChanges;
ethannicholas22f939e2016-10-13 13:25:34 -07001396}
1397
Brian Osman32d53552020-09-23 13:55:20 -04001398std::unique_ptr<Program> Compiler::convertProgram(
John Stilesdbd4e6f2021-02-16 13:29:15 -05001399 ProgramKind kind,
Brian Osman32d53552020-09-23 13:55:20 -04001400 String text,
1401 const Program::Settings& settings,
Brian Osmanbe0b3b72021-01-06 14:27:35 -05001402 const std::vector<std::unique_ptr<ExternalFunction>>* externalFunctions) {
Brian Osmand010f652021-02-24 13:59:39 -05001403 TRACE_EVENT0("skia.gpu", "SkSL::Compiler::convertProgram");
Leon Scrogginsb66214e2021-02-11 17:14:18 -05001404
John Stilesdbd4e6f2021-02-16 13:29:15 -05001405 SkASSERT(!externalFunctions || (kind == ProgramKind::kGeneric));
Ethan Nicholas91164d12019-05-15 15:29:54 -04001406
Brian Osman0006ad02020-11-18 15:38:39 -05001407 // Loading and optimizing our base module might reset the inliner, so do that first,
1408 // *then* configure the inliner with the settings for this program.
1409 const ParsedModule& baseModule = this->moduleForProgramKind(kind);
1410
John Stiles270cec22021-02-17 12:59:36 -05001411 // Update our context to point to the program configuration for the duration of compilation.
1412 auto config = std::make_unique<ProgramConfig>(ProgramConfig{kind, settings});
John Stilesa935c3f2021-02-25 10:35:49 -05001413 AutoProgramConfig autoConfig(fContext, config.get());
John Stiles270cec22021-02-17 12:59:36 -05001414
ethannicholasb3058bd2016-07-01 08:22:01 -07001415 fErrorText = "";
1416 fErrorCount = 0;
John Stilesd1204642021-02-17 16:30:02 -05001417 fInliner.reset(fIRGenerator->fModifiers.get());
Brian Osman88cda172020-10-09 12:05:16 -04001418
1419 // Not using AutoSource, because caller is likely to call errorText() if we fail to compile
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001420 std::unique_ptr<String> textPtr(new String(std::move(text)));
1421 fSource = textPtr.get();
Brian Osman88cda172020-10-09 12:05:16 -04001422
John Stiles5c7bb322020-10-22 11:09:15 -04001423 // Enable node pooling while converting and optimizing the program for a performance boost.
1424 // The Program will take ownership of the pool.
Brian Osman28f702c2021-02-02 11:52:07 -05001425 std::unique_ptr<Pool> pool;
John Stilesc1a98b82021-02-24 13:35:02 -05001426 if (fContext->fCaps.useNodePools()) {
Brian Osman28f702c2021-02-02 11:52:07 -05001427 pool = Pool::Create();
1428 pool->attachToThread();
1429 }
John Stilesd1204642021-02-17 16:30:02 -05001430 IRGenerator::IRBundle ir = fIRGenerator->convertProgram(baseModule, /*isBuiltinCode=*/false,
1431 textPtr->c_str(), textPtr->size(),
1432 externalFunctions);
John Stiles270cec22021-02-17 12:59:36 -05001433 auto program = std::make_unique<Program>(std::move(textPtr),
1434 std::move(config),
John Stiles5c7bb322020-10-22 11:09:15 -04001435 fContext,
1436 std::move(ir.fElements),
Brian Osman133724c2020-10-28 14:14:39 -04001437 std::move(ir.fSharedElements),
John Stiles5c7bb322020-10-22 11:09:15 -04001438 std::move(ir.fModifiers),
1439 std::move(ir.fSymbolTable),
1440 std::move(pool),
1441 ir.fInputs);
1442 bool success = false;
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001443 if (fErrorCount) {
John Stiles5c7bb322020-10-22 11:09:15 -04001444 // Do not return programs that failed to compile.
John Stilescbd65752021-02-24 14:14:14 +00001445 } else if (settings.fOptimize && !this->optimize(*program)) {
John Stiles5c7bb322020-10-22 11:09:15 -04001446 // Do not return programs that failed to optimize.
1447 } else {
1448 // We have a successful program!
1449 success = true;
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001450 }
John Stiles5c7bb322020-10-22 11:09:15 -04001451
Brian Osman28f702c2021-02-02 11:52:07 -05001452 if (program->fPool) {
1453 program->fPool->detachFromThread();
1454 }
John Stiles5c7bb322020-10-22 11:09:15 -04001455 return success ? std::move(program) : nullptr;
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001456}
1457
John Stilesbb1505f2021-02-12 09:17:53 -05001458void Compiler::verifyStaticTests(const Program& program) {
1459 class StaticTestVerifier : public ProgramVisitor {
1460 public:
1461 StaticTestVerifier(ErrorReporter* r) : fReporter(r) {}
1462
1463 using ProgramVisitor::visitProgramElement;
1464
1465 bool visitStatement(const Statement& stmt) override {
1466 switch (stmt.kind()) {
1467 case Statement::Kind::kIf:
1468 if (stmt.as<IfStatement>().isStatic()) {
1469 fReporter->error(stmt.fOffset, "static if has non-static test");
1470 }
1471 break;
1472
1473 case Statement::Kind::kSwitch:
1474 if (stmt.as<SwitchStatement>().isStatic()) {
1475 fReporter->error(stmt.fOffset, "static switch has non-static test");
1476 }
1477 break;
1478
1479 default:
1480 break;
1481 }
1482 return INHERITED::visitStatement(stmt);
1483 }
1484
John Stiles59e34562021-02-12 16:56:39 -05001485 bool visitExpression(const Expression&) override {
1486 // We aren't looking for anything inside an Expression, so skip them entirely.
1487 return false;
1488 }
1489
John Stilesbb1505f2021-02-12 09:17:53 -05001490 private:
1491 using INHERITED = ProgramVisitor;
1492 ErrorReporter* fReporter;
1493 };
1494
1495 // If invalid static tests are permitted, we don't need to check anything.
John Stilesd1204642021-02-17 16:30:02 -05001496 if (fContext->fConfig->fSettings.fPermitInvalidStaticTests) {
John Stilesbb1505f2021-02-12 09:17:53 -05001497 return;
1498 }
1499
1500 // Check all of the program's owned elements. (Built-in elements are assumed to be valid.)
1501 StaticTestVerifier visitor{this};
1502 for (const std::unique_ptr<ProgramElement>& element : program.ownedElements()) {
1503 if (element->is<FunctionDefinition>()) {
1504 visitor.visitProgramElement(*element);
1505 }
1506 }
1507}
1508
Brian Osman0006ad02020-11-18 15:38:39 -05001509bool Compiler::optimize(LoadedModule& module) {
1510 SkASSERT(!fErrorCount);
Brian Osman0006ad02020-11-18 15:38:39 -05001511
John Stiles270cec22021-02-17 12:59:36 -05001512 // Create a temporary program configuration with default settings.
1513 ProgramConfig config;
1514 config.fKind = module.fKind;
John Stilesa935c3f2021-02-25 10:35:49 -05001515 AutoProgramConfig autoConfig(fContext, &config);
John Stiles270cec22021-02-17 12:59:36 -05001516
John Stilesd1204642021-02-17 16:30:02 -05001517 // Reset the Inliner.
1518 fInliner.reset(fModifiers.back().get());
John Stiles270cec22021-02-17 12:59:36 -05001519
1520 std::unique_ptr<ProgramUsage> usage = Analysis::GetUsage(module);
Brian Osman0006ad02020-11-18 15:38:39 -05001521
1522 while (fErrorCount == 0) {
1523 bool madeChanges = false;
1524
1525 // Scan and optimize based on the control-flow graph for each function.
John Stilesa935c3f2021-02-25 10:35:49 -05001526 if (config.fSettings.fControlFlowAnalysis) {
1527 for (const auto& element : module.fElements) {
1528 if (element->is<FunctionDefinition>()) {
1529 madeChanges |= this->scanCFG(element->as<FunctionDefinition>(), usage.get());
1530 }
Brian Osman0006ad02020-11-18 15:38:39 -05001531 }
1532 }
1533
1534 // Perform inline-candidate analysis and inline any functions deemed suitable.
John Stiles78047582020-12-16 16:17:41 -05001535 madeChanges |= fInliner.analyze(module.fElements, module.fSymbols, usage.get());
Brian Osman0006ad02020-11-18 15:38:39 -05001536
1537 if (!madeChanges) {
1538 break;
1539 }
1540 }
1541 return fErrorCount == 0;
1542}
1543
Ethan Nicholas00543112018-07-31 09:44:36 -04001544bool Compiler::optimize(Program& program) {
1545 SkASSERT(!fErrorCount);
Brian Osman010ce6a2020-10-19 16:34:10 -04001546 ProgramUsage* usage = program.fUsage.get();
John Stiles7954d6c2020-09-01 10:53:02 -04001547
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001548 while (fErrorCount == 0) {
1549 bool madeChanges = false;
John Stiles7954d6c2020-09-01 10:53:02 -04001550
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001551 // Scan and optimize based on the control-flow graph for each function.
John Stiles0c7312a2021-02-24 11:31:32 -05001552 if (program.fConfig->fSettings.fControlFlowAnalysis) {
1553 for (const auto& element : program.ownedElements()) {
1554 if (element->is<FunctionDefinition>()) {
1555 madeChanges |= this->scanCFG(element->as<FunctionDefinition>(), usage);
1556 }
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001557 }
1558 }
1559
1560 // Perform inline-candidate analysis and inline any functions deemed suitable.
John Stiles78047582020-12-16 16:17:41 -05001561 madeChanges |= fInliner.analyze(program.ownedElements(), program.fSymbols, usage);
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001562
1563 // Remove dead functions. We wait until after analysis so that we still report errors,
1564 // even in unused code.
John Stiles270cec22021-02-17 12:59:36 -05001565 if (program.fConfig->fSettings.fRemoveDeadFunctions) {
Brian Osman133724c2020-10-28 14:14:39 -04001566 auto isDeadFunction = [&](const ProgramElement* element) {
1567 if (!element->is<FunctionDefinition>()) {
1568 return false;
1569 }
1570 const FunctionDefinition& fn = element->as<FunctionDefinition>();
1571 if (fn.declaration().name() != "main" && usage->get(fn.declaration()) == 0) {
1572 usage->remove(*element);
1573 madeChanges = true;
1574 return true;
1575 }
1576 return false;
1577 };
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001578 program.fElements.erase(
Brian Osman133724c2020-10-28 14:14:39 -04001579 std::remove_if(program.fElements.begin(), program.fElements.end(),
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001580 [&](const std::unique_ptr<ProgramElement>& element) {
Brian Osman133724c2020-10-28 14:14:39 -04001581 return isDeadFunction(element.get());
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001582 }),
1583 program.fElements.end());
Brian Osman133724c2020-10-28 14:14:39 -04001584 program.fSharedElements.erase(
1585 std::remove_if(program.fSharedElements.begin(), program.fSharedElements.end(),
1586 isDeadFunction),
1587 program.fSharedElements.end());
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001588 }
1589
John Stiles270cec22021-02-17 12:59:36 -05001590 if (program.fConfig->fKind != ProgramKind::kFragmentProcessor) {
Brian Osmanc0213602020-10-06 14:43:32 -04001591 // Remove declarations of dead global variables
Brian Osman133724c2020-10-28 14:14:39 -04001592 auto isDeadVariable = [&](const ProgramElement* element) {
1593 if (!element->is<GlobalVarDeclaration>()) {
1594 return false;
1595 }
1596 const GlobalVarDeclaration& global = element->as<GlobalVarDeclaration>();
1597 const VarDeclaration& varDecl = global.declaration()->as<VarDeclaration>();
1598 if (usage->isDead(varDecl.var())) {
1599 madeChanges = true;
1600 return true;
1601 }
1602 return false;
1603 };
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001604 program.fElements.erase(
1605 std::remove_if(program.fElements.begin(), program.fElements.end(),
1606 [&](const std::unique_ptr<ProgramElement>& element) {
Brian Osman133724c2020-10-28 14:14:39 -04001607 return isDeadVariable(element.get());
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001608 }),
1609 program.fElements.end());
Brian Osman133724c2020-10-28 14:14:39 -04001610 program.fSharedElements.erase(
1611 std::remove_if(program.fSharedElements.begin(), program.fSharedElements.end(),
1612 isDeadVariable),
1613 program.fSharedElements.end());
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001614 }
John Stiles73a6bff2020-09-09 13:40:37 -04001615
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001616 if (!madeChanges) {
1617 break;
Ethan Nicholas0dc80872019-02-08 15:46:24 -05001618 }
Ethan Nicholas00543112018-07-31 09:44:36 -04001619 }
John Stilesbb1505f2021-02-12 09:17:53 -05001620
1621 if (fErrorCount == 0) {
1622 this->verifyStaticTests(program);
1623 }
1624
Ethan Nicholas00543112018-07-31 09:44:36 -04001625 return fErrorCount == 0;
1626}
1627
Brian Osmanfb32ddf2019-06-18 10:14:20 -04001628#if defined(SKSL_STANDALONE) || SK_SUPPORT_GPU
1629
Ethan Nicholas00543112018-07-31 09:44:36 -04001630bool Compiler::toSPIRV(Program& program, OutputStream& out) {
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001631#ifdef SK_ENABLE_SPIRV_VALIDATION
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001632 StringStream buffer;
Brian Osman88cda172020-10-09 12:05:16 -04001633 AutoSource as(this, program.fSource.get());
Brian Osman8b43dad2020-10-09 13:31:42 -04001634 SPIRVCodeGenerator cg(fContext.get(), &program, this, &buffer);
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001635 bool result = cg.generateCode();
John Stiles270cec22021-02-17 12:59:36 -05001636 if (result && program.fConfig->fSettings.fValidateSPIRV) {
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001637 spvtools::SpirvTools tools(SPV_ENV_VULKAN_1_0);
Ethan Nicholas762466e2017-06-29 10:03:38 -04001638 const String& data = buffer.str();
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001639 SkASSERT(0 == data.size() % 4);
Brian Osman8d09d4a2020-11-24 15:51:06 -05001640 String errors;
1641 auto dumpmsg = [&errors](spv_message_level_t, const char*, const spv_position_t&,
1642 const char* m) {
1643 errors.appendf("SPIR-V validation error: %s\n", m);
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001644 };
1645 tools.SetMessageConsumer(dumpmsg);
Brian Osman8d09d4a2020-11-24 15:51:06 -05001646
1647 // Verify that the SPIR-V we produced is valid. At runtime, we will abort() with a message
1648 // explaining the error. In standalone mode (skslc), we will send the message, plus the
1649 // entire disassembled SPIR-V (for easier context & debugging) as *our* error message.
1650 result = tools.Validate((const uint32_t*) data.c_str(), data.size() / 4);
1651
1652 if (!result) {
1653#if defined(SKSL_STANDALONE)
1654 // Convert the string-stream to a SPIR-V disassembly.
1655 std::string disassembly;
1656 if (tools.Disassemble((const uint32_t*)data.data(), data.size() / 4, &disassembly)) {
1657 errors.append(disassembly);
1658 }
1659 this->error(-1, errors);
1660#else
1661 SkDEBUGFAILF("%s", errors.c_str());
1662#endif
1663 }
Ethan Nicholas762466e2017-06-29 10:03:38 -04001664 out.write(data.c_str(), data.size());
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001665 }
1666#else
Brian Osman88cda172020-10-09 12:05:16 -04001667 AutoSource as(this, program.fSource.get());
Brian Osman8b43dad2020-10-09 13:31:42 -04001668 SPIRVCodeGenerator cg(fContext.get(), &program, this, &out);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001669 bool result = cg.generateCode();
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001670#endif
Ethan Nicholasce33f102016-12-09 17:22:59 -05001671 return result;
1672}
1673
Ethan Nicholas00543112018-07-31 09:44:36 -04001674bool Compiler::toSPIRV(Program& program, String* out) {
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001675 StringStream buffer;
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001676 bool result = this->toSPIRV(program, buffer);
1677 if (result) {
Ethan Nicholas762466e2017-06-29 10:03:38 -04001678 *out = buffer.str();
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001679 }
1680 return result;
1681}
1682
Ethan Nicholas00543112018-07-31 09:44:36 -04001683bool Compiler::toGLSL(Program& program, OutputStream& out) {
Brian Osmand010f652021-02-24 13:59:39 -05001684 TRACE_EVENT0("skia.gpu", "SkSL::Compiler::toGLSL");
Brian Osman88cda172020-10-09 12:05:16 -04001685 AutoSource as(this, program.fSource.get());
Ethan Nicholas26a9aad2018-03-27 14:10:52 -04001686 GLSLCodeGenerator cg(fContext.get(), &program, this, &out);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001687 bool result = cg.generateCode();
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001688 return result;
1689}
1690
Ethan Nicholas00543112018-07-31 09:44:36 -04001691bool Compiler::toGLSL(Program& program, String* out) {
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001692 StringStream buffer;
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001693 bool result = this->toGLSL(program, buffer);
1694 if (result) {
Ethan Nicholas762466e2017-06-29 10:03:38 -04001695 *out = buffer.str();
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001696 }
1697 return result;
1698}
1699
Brian Osmanc0243912020-02-19 15:35:26 -05001700bool Compiler::toHLSL(Program& program, String* out) {
1701 String spirv;
1702 if (!this->toSPIRV(program, &spirv)) {
1703 return false;
1704 }
1705
1706 return SPIRVtoHLSL(spirv, out);
1707}
1708
Ethan Nicholas00543112018-07-31 09:44:36 -04001709bool Compiler::toMetal(Program& program, OutputStream& out) {
Ethan Nicholas26a9aad2018-03-27 14:10:52 -04001710 MetalCodeGenerator cg(fContext.get(), &program, this, &out);
Ethan Nicholascc305772017-10-13 16:17:45 -04001711 bool result = cg.generateCode();
Ethan Nicholascc305772017-10-13 16:17:45 -04001712 return result;
1713}
1714
Ethan Nicholas00543112018-07-31 09:44:36 -04001715bool Compiler::toMetal(Program& program, String* out) {
Timothy Liangb8eeb802018-07-23 16:46:16 -04001716 StringStream buffer;
1717 bool result = this->toMetal(program, buffer);
1718 if (result) {
1719 *out = buffer.str();
1720 }
1721 return result;
1722}
1723
Greg Daniela28ea672020-09-25 11:12:56 -04001724#if defined(SKSL_STANDALONE) || GR_TEST_UTILS
Ethan Nicholas00543112018-07-31 09:44:36 -04001725bool Compiler::toCPP(Program& program, String name, OutputStream& out) {
Brian Osman88cda172020-10-09 12:05:16 -04001726 AutoSource as(this, program.fSource.get());
Ethan Nicholas26a9aad2018-03-27 14:10:52 -04001727 CPPCodeGenerator cg(fContext.get(), &program, this, name, &out);
Ethan Nicholas762466e2017-06-29 10:03:38 -04001728 bool result = cg.generateCode();
Ethan Nicholas762466e2017-06-29 10:03:38 -04001729 return result;
1730}
1731
Ethan Nicholas00543112018-07-31 09:44:36 -04001732bool Compiler::toH(Program& program, String name, OutputStream& out) {
Brian Osman88cda172020-10-09 12:05:16 -04001733 AutoSource as(this, program.fSource.get());
Ethan Nicholas26a9aad2018-03-27 14:10:52 -04001734 HCodeGenerator cg(fContext.get(), &program, this, name, &out);
Ethan Nicholas762466e2017-06-29 10:03:38 -04001735 bool result = cg.generateCode();
Ethan Nicholas00543112018-07-31 09:44:36 -04001736 return result;
1737}
Greg Daniela28ea672020-09-25 11:12:56 -04001738#endif // defined(SKSL_STANDALONE) || GR_TEST_UTILS
Ethan Nicholas00543112018-07-31 09:44:36 -04001739
Ethan Nicholas2a479a52020-08-18 16:29:45 -04001740#endif // defined(SKSL_STANDALONE) || SK_SUPPORT_GPU
Brian Osman2e29ab52019-09-20 12:19:11 -04001741
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001742Position Compiler::position(int offset) {
Ethan Nicholas3c729892020-12-07 12:47:17 -05001743 if (fSource && offset >= 0) {
1744 int line = 1;
1745 int column = 1;
1746 for (int i = 0; i < offset; i++) {
1747 if ((*fSource)[i] == '\n') {
1748 ++line;
1749 column = 1;
1750 }
1751 else {
1752 ++column;
1753 }
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001754 }
Ethan Nicholas3c729892020-12-07 12:47:17 -05001755 return Position(line, column);
1756 } else {
1757 return Position(-1, -1);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001758 }
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001759}
1760
1761void Compiler::error(int offset, String msg) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001762 fErrorCount++;
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001763 Position pos = this->position(offset);
John Stiles8d3642e2021-01-22 09:50:04 -05001764 fErrorTextLength.push_back(fErrorText.length());
Ethan Nicholas3c729892020-12-07 12:47:17 -05001765 fErrorText += "error: " + (pos.fLine >= 1 ? to_string(pos.fLine) + ": " : "") + msg + "\n";
ethannicholasb3058bd2016-07-01 08:22:01 -07001766}
1767
John Stiles8d3642e2021-01-22 09:50:04 -05001768void Compiler::setErrorCount(int c) {
1769 if (c < fErrorCount) {
1770 fErrorText.resize(fErrorTextLength[c]);
1771 fErrorTextLength.resize(c);
1772 fErrorCount = c;
1773 }
1774}
1775
Ethan Nicholas95046142021-01-07 10:57:27 -05001776String Compiler::errorText(bool showCount) {
1777 if (showCount) {
1778 this->writeErrorCount();
1779 }
Ethan Nicholas00543112018-07-31 09:44:36 -04001780 fErrorCount = 0;
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001781 String result = fErrorText;
Ethan Nicholas95046142021-01-07 10:57:27 -05001782 fErrorText = "";
ethannicholasb3058bd2016-07-01 08:22:01 -07001783 return result;
1784}
1785
1786void Compiler::writeErrorCount() {
1787 if (fErrorCount) {
1788 fErrorText += to_string(fErrorCount) + " error";
1789 if (fErrorCount > 1) {
1790 fErrorText += "s";
1791 }
1792 fErrorText += "\n";
1793 }
1794}
1795
John Stilesa6841be2020-08-06 14:11:56 -04001796} // namespace SkSL