blob: b7788a8f49a3e2292113a2dcd4034d88866e7781 [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 Stilesf04e09c2021-03-05 13:13:14 -0500949 // TODO(skia:11319): this optimization logic is redundant with the optimization code
950 // found in SkSLSwizzle.cpp.
951
John Stiles403a3632020-08-20 12:11:48 -0400952 Swizzle& s = expr->as<Swizzle>();
John Stiles108bbe22020-11-18 11:10:38 -0500953 // Detect identity swizzles like `foo.rgba`.
Ethan Nicholas6b4d5812020-10-12 16:11:51 -0400954 if ((int) s.components().size() == s.base()->type().columns()) {
Ethan Nicholas409f6f02019-09-17 12:34:39 -0400955 bool identity = true;
Ethan Nicholas6b4d5812020-10-12 16:11:51 -0400956 for (int i = 0; i < (int) s.components().size(); ++i) {
957 if (s.components()[i] != i) {
Ethan Nicholas409f6f02019-09-17 12:34:39 -0400958 identity = false;
959 break;
960 }
961 }
962 if (identity) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400963 optimizationContext->fUpdated = true;
Brian Osman010ce6a2020-10-19 16:34:10 -0400964 // No fUsage change: foo.rgba and foo have equivalent reference counts
Ethan Nicholas6b4d5812020-10-12 16:11:51 -0400965 if (!try_replace_expression(&b, iter, &s.base())) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400966 optimizationContext->fNeedsRescan = true;
Ethan Nicholas409f6f02019-09-17 12:34:39 -0400967 return;
968 }
John Stiles70025e52020-09-28 16:08:58 -0400969 SkASSERT((*iter)->isExpression());
Ethan Nicholas409f6f02019-09-17 12:34:39 -0400970 break;
971 }
972 }
John Stiles108bbe22020-11-18 11:10:38 -0500973 // Detect swizzles of swizzles, e.g. replace `foo.argb.r000` with `foo.a000`.
974 if (s.base()->is<Swizzle>()) {
Ethan Nicholas6b4d5812020-10-12 16:11:51 -0400975 Swizzle& base = s.base()->as<Swizzle>();
John Stiles750109b2020-10-30 13:45:46 -0400976 ComponentArray final;
Ethan Nicholas6b4d5812020-10-12 16:11:51 -0400977 for (int c : s.components()) {
978 final.push_back(base.components()[c]);
Ethan Nicholas409f6f02019-09-17 12:34:39 -0400979 }
Ethan Nicholas6b4d5812020-10-12 16:11:51 -0400980 std::unique_ptr<Expression> replacement(new Swizzle(*fContext, base.base()->clone(),
John Stiles750109b2020-10-30 13:45:46 -0400981 final));
John Stilesd2f51b12021-01-07 18:12:31 -0500982 // We're replacing an expression with a cloned version; we'll need a rescan.
John Stiles108bbe22020-11-18 11:10:38 -0500983 // No fUsage change: `foo.gbr.gbr` and `foo.brg` have equivalent reference counts
John Stilesd2f51b12021-01-07 18:12:31 -0500984 try_replace_expression(&b, iter, &replacement);
985 optimizationContext->fUpdated = true;
986 optimizationContext->fNeedsRescan = true;
John Stiles108bbe22020-11-18 11:10:38 -0500987 break;
988 }
989 // Optimize swizzles of constructors.
990 if (s.base()->is<Constructor>()) {
991 Constructor& base = s.base()->as<Constructor>();
992 std::unique_ptr<Expression> replacement;
993 const Type& componentType = base.type().componentType();
994 int swizzleSize = s.components().size();
995
996 // The IR generator has already converted any zero/one swizzle components into
997 // constructors containing zero/one args. Confirm that this is true by checking that
998 // our swizzle components are all `xyzw` (values 0 through 3).
999 SkASSERT(std::all_of(s.components().begin(), s.components().end(),
1000 [](int8_t c) { return c >= 0 && c <= 3; }));
1001
John Stiles9aeed132020-11-24 17:36:06 -05001002 if (base.arguments().size() == 1 && base.arguments().front()->type().isScalar()) {
John Stiles108bbe22020-11-18 11:10:38 -05001003 // `half4(scalar).zyy` can be optimized to `half3(scalar)`. The swizzle
1004 // components don't actually matter since all fields are the same.
John Stilesf0cb7332021-01-08 18:39:00 -05001005 const Expression& argument = *base.arguments().front();
1006 const Type& constructorType = componentType.toCompound(*fContext, swizzleSize,
1007 /*rows=*/1);
1008 replacement = Constructor::SimplifyConversion(constructorType, argument);
1009 if (!replacement) {
1010 ExpressionArray newArgs;
1011 newArgs.push_back(argument.clone());
John Stiles54f00492021-02-19 11:46:10 -05001012 replacement = std::make_unique<Constructor>(base.fOffset, constructorType,
John Stilesf0cb7332021-01-08 18:39:00 -05001013 std::move(newArgs));
1014 }
John Stiles108bbe22020-11-18 11:10:38 -05001015
John Stilesa60ac0c2020-12-22 08:59:51 -05001016 // We're replacing an expression with a cloned version; we'll need a rescan.
1017 // There's no fUsage change: `half4(foo).xy` and `half2(foo)` have equivalent
1018 // reference counts.
1019 try_replace_expression(&b, iter, &replacement);
John Stiles0777ac42020-11-19 11:06:47 -05001020 optimizationContext->fUpdated = true;
John Stilesa60ac0c2020-12-22 08:59:51 -05001021 optimizationContext->fNeedsRescan = true;
John Stiles108bbe22020-11-18 11:10:38 -05001022 break;
1023 }
1024
John Stiles0777ac42020-11-19 11:06:47 -05001025 // Swizzles can duplicate some elements and discard others, e.g.
1026 // `half4(1, 2, 3, 4).xxz` --> `half3(1, 1, 3)`. However, there are constraints:
1027 // - Expressions with side effects need to occur exactly once, even if they
1028 // would otherwise be swizzle-eliminated
1029 // - Non-trivial expressions should not be repeated, but elimination is OK.
1030 //
1031 // Look up the argument for the constructor at each index. This is typically simple
1032 // but for weird cases like `half4(bar.yz, half2(foo))`, it can be harder than it
1033 // seems. This example would result in:
1034 // argMap[0] = {.fArgIndex = 0, .fComponent = 0} (bar.yz .x)
1035 // argMap[1] = {.fArgIndex = 0, .fComponent = 1} (bar.yz .y)
1036 // argMap[2] = {.fArgIndex = 1, .fComponent = 0} (half2(foo) .x)
1037 // argMap[3] = {.fArgIndex = 1, .fComponent = 1} (half2(foo) .y)
1038 struct ConstructorArgMap {
1039 int8_t fArgIndex;
1040 int8_t fComponent;
1041 };
1042
1043 int numConstructorArgs = base.type().columns();
1044 ConstructorArgMap argMap[4] = {};
1045 int writeIdx = 0;
1046 for (int argIdx = 0; argIdx < (int) base.arguments().size(); ++argIdx) {
1047 const Expression& expr = *base.arguments()[argIdx];
1048 int argWidth = expr.type().columns();
1049 for (int componentIdx = 0; componentIdx < argWidth; ++componentIdx) {
1050 argMap[writeIdx].fArgIndex = argIdx;
1051 argMap[writeIdx].fComponent = componentIdx;
1052 ++writeIdx;
1053 }
1054 }
1055 SkASSERT(writeIdx == numConstructorArgs);
1056
1057 // Count up the number of times each constructor argument is used by the
1058 // swizzle.
1059 // `half4(bar.yz, half2(foo)).xwxy` -> { 3, 1 }
1060 // - bar.yz is referenced 3 times, by `.x_xy`
1061 // - half(foo) is referenced 1 time, by `._w__`
1062 int8_t exprUsed[4] = {};
1063 for (int c : s.components()) {
1064 exprUsed[argMap[c].fArgIndex]++;
1065 }
1066
1067 bool safeToOptimize = true;
1068 for (int index = 0; index < numConstructorArgs; ++index) {
1069 int8_t constructorArgIndex = argMap[index].fArgIndex;
1070 const Expression& baseArg = *base.arguments()[constructorArgIndex];
1071
1072 // Check that non-trivial expressions are not swizzled in more than once.
John Stilesc30fbca2020-11-19 16:25:49 -05001073 if (exprUsed[constructorArgIndex] > 1 &&
1074 !Analysis::IsTrivialExpression(baseArg)) {
John Stiles0777ac42020-11-19 11:06:47 -05001075 safeToOptimize = false;
1076 break;
1077 }
1078 // Check that side-effect-bearing expressions are swizzled in exactly once.
1079 if (exprUsed[constructorArgIndex] != 1 && baseArg.hasSideEffects()) {
1080 safeToOptimize = false;
1081 break;
1082 }
1083 }
1084
1085 if (safeToOptimize) {
John Stilesd9076cb2020-11-19 12:18:36 -05001086 struct ReorderedArgument {
1087 int8_t fArgIndex;
1088 ComponentArray fComponents;
1089 };
1090 SkSTArray<4, ReorderedArgument> reorderedArgs;
John Stiles0777ac42020-11-19 11:06:47 -05001091 for (int c : s.components()) {
1092 const ConstructorArgMap& argument = argMap[c];
1093 const Expression& baseArg = *base.arguments()[argument.fArgIndex];
1094
John Stiles9aeed132020-11-24 17:36:06 -05001095 if (baseArg.type().isScalar()) {
John Stilesd9076cb2020-11-19 12:18:36 -05001096 // This argument is a scalar; add it to the list as-is.
John Stiles0777ac42020-11-19 11:06:47 -05001097 SkASSERT(argument.fComponent == 0);
John Stilesd9076cb2020-11-19 12:18:36 -05001098 reorderedArgs.push_back({argument.fArgIndex,
1099 ComponentArray{}});
John Stiles0777ac42020-11-19 11:06:47 -05001100 } else {
John Stilesd9076cb2020-11-19 12:18:36 -05001101 // This argument is a component from a vector.
John Stiles0777ac42020-11-19 11:06:47 -05001102 SkASSERT(argument.fComponent < baseArg.type().columns());
John Stilesd9076cb2020-11-19 12:18:36 -05001103 if (reorderedArgs.empty() ||
1104 reorderedArgs.back().fArgIndex != argument.fArgIndex) {
1105 // This can't be combined with the previous argument. Add a new one.
1106 reorderedArgs.push_back({argument.fArgIndex,
1107 ComponentArray{argument.fComponent}});
1108 } else {
1109 // Since we know this argument uses components, it should already
1110 // have at least one component set.
1111 SkASSERT(!reorderedArgs.back().fComponents.empty());
1112 // Build up the current argument with one more component.
1113 reorderedArgs.back().fComponents.push_back(argument.fComponent);
1114 }
John Stiles0777ac42020-11-19 11:06:47 -05001115 }
1116 }
John Stilesd9076cb2020-11-19 12:18:36 -05001117
1118 // Convert our reordered argument list to an actual array of expressions, with
1119 // the new order and any new inner swizzles that need to be applied. Note that
1120 // we expect followup passes to clean up the inner swizzles.
1121 ExpressionArray newArgs;
1122 newArgs.reserve_back(swizzleSize);
1123 for (const ReorderedArgument& reorderedArg : reorderedArgs) {
1124 const Expression& baseArg = *base.arguments()[reorderedArg.fArgIndex];
1125 if (reorderedArg.fComponents.empty()) {
1126 newArgs.push_back(baseArg.clone());
1127 } else {
1128 newArgs.push_back(std::make_unique<Swizzle>(*fContext, baseArg.clone(),
1129 reorderedArg.fComponents));
1130 }
1131 }
1132
1133 // Create a new constructor.
John Stiles0777ac42020-11-19 11:06:47 -05001134 replacement = std::make_unique<Constructor>(
1135 base.fOffset,
John Stiles54f00492021-02-19 11:46:10 -05001136 componentType.toCompound(*fContext, swizzleSize, /*rows=*/1),
John Stiles0777ac42020-11-19 11:06:47 -05001137 std::move(newArgs));
1138
John Stilesa60ac0c2020-12-22 08:59:51 -05001139 // Remove references within 'expr', add references within 'replacement.'
John Stiles0777ac42020-11-19 11:06:47 -05001140 optimizationContext->fUsage->replace(expr, replacement.get());
John Stilesa60ac0c2020-12-22 08:59:51 -05001141
1142 // We're replacing an expression with a cloned version; we'll need a rescan.
1143 try_replace_expression(&b, iter, &replacement);
1144 optimizationContext->fUpdated = true;
1145 optimizationContext->fNeedsRescan = true;
John Stiles0777ac42020-11-19 11:06:47 -05001146 }
John Stiles108bbe22020-11-18 11:10:38 -05001147 break;
Ethan Nicholas409f6f02019-09-17 12:34:39 -04001148 }
John Stiles30212b72020-06-11 17:55:07 -04001149 break;
Ethan Nicholascb670962017-04-20 19:31:52 -04001150 }
1151 default:
1152 break;
1153 }
1154}
1155
1156void Compiler::simplifyStatement(DefinitionMap& definitions,
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001157 BasicBlock& b,
1158 std::vector<BasicBlock::Node>::iterator* iter,
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001159 OptimizationContext* optimizationContext) {
Brian Osman010ce6a2020-10-19 16:34:10 -04001160 ProgramUsage* usage = optimizationContext->fUsage;
Ethan Nicholascb670962017-04-20 19:31:52 -04001161 Statement* stmt = (*iter)->statement()->get();
Ethan Nicholase6592142020-09-08 10:22:09 -04001162 switch (stmt->kind()) {
1163 case Statement::Kind::kVarDeclaration: {
John Stilesa5a97b42020-08-18 11:19:07 -04001164 const auto& varDecl = stmt->as<VarDeclaration>();
Brian Osman010ce6a2020-10-19 16:34:10 -04001165 if (usage->isDead(varDecl.var()) &&
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04001166 (!varDecl.value() ||
1167 !varDecl.value()->hasSideEffects())) {
1168 if (varDecl.value()) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001169 SkASSERT((*iter)->statement()->get() == stmt);
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04001170 if (!b.tryRemoveExpressionBefore(iter, varDecl.value().get())) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001171 optimizationContext->fNeedsRescan = true;
Ethan Nicholascb670962017-04-20 19:31:52 -04001172 }
Ethan Nicholascb670962017-04-20 19:31:52 -04001173 }
Ethan Nicholas5b9b0db2021-01-21 13:12:01 -05001174 // There can still be (soon to be removed) references to the variable at this point.
1175 // Allowing the VarDeclaration to be destroyed here will break those variable's
1176 // initialValue()s, so we hang on to them until optimization is finished.
1177 std::unique_ptr<Statement> old = (*iter)->setStatement(std::make_unique<Nop>(),
1178 usage);
1179 optimizationContext->fOwnedStatements.push_back(std::move(old));
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001180 optimizationContext->fUpdated = true;
Ethan Nicholascb670962017-04-20 19:31:52 -04001181 }
1182 break;
1183 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001184 case Statement::Kind::kIf: {
John Stiles4633c912021-03-03 16:13:45 -05001185 // TODO(skia:11319): this optimization logic is redundant with the optimization code
1186 // found in IfStatement.cpp.
John Stilesa5a97b42020-08-18 11:19:07 -04001187 IfStatement& i = stmt->as<IfStatement>();
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001188 if (i.test()->kind() == Expression::Kind::kBoolLiteral) {
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001189 // constant if, collapse down to a single branch
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001190 if (i.test()->as<BoolLiteral>().value()) {
1191 SkASSERT(i.ifTrue());
Brian Osman010ce6a2020-10-19 16:34:10 -04001192 (*iter)->setStatement(std::move(i.ifTrue()), usage);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001193 } else {
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001194 if (i.ifFalse()) {
Brian Osman010ce6a2020-10-19 16:34:10 -04001195 (*iter)->setStatement(std::move(i.ifFalse()), usage);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001196 } else {
Brian Osman010ce6a2020-10-19 16:34:10 -04001197 (*iter)->setStatement(std::make_unique<Nop>(), usage);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001198 }
1199 }
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001200 optimizationContext->fUpdated = true;
1201 optimizationContext->fNeedsRescan = true;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001202 break;
1203 }
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001204 if (i.ifFalse() && i.ifFalse()->isEmpty()) {
Ethan Nicholascb670962017-04-20 19:31:52 -04001205 // else block doesn't do anything, remove it
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001206 i.ifFalse().reset();
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001207 optimizationContext->fUpdated = true;
1208 optimizationContext->fNeedsRescan = true;
Ethan Nicholascb670962017-04-20 19:31:52 -04001209 }
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001210 if (!i.ifFalse() && i.ifTrue()->isEmpty()) {
Ethan Nicholascb670962017-04-20 19:31:52 -04001211 // if block doesn't do anything, no else block
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001212 if (i.test()->hasSideEffects()) {
Ethan Nicholascb670962017-04-20 19:31:52 -04001213 // test has side effects, keep it
Brian Osman010ce6a2020-10-19 16:34:10 -04001214 (*iter)->setStatement(
1215 std::make_unique<ExpressionStatement>(std::move(i.test())), usage);
Ethan Nicholascb670962017-04-20 19:31:52 -04001216 } else {
1217 // no if, no else, no test side effects, kill the whole if
1218 // statement
Brian Osman010ce6a2020-10-19 16:34:10 -04001219 (*iter)->setStatement(std::make_unique<Nop>(), usage);
Ethan Nicholascb670962017-04-20 19:31:52 -04001220 }
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001221 optimizationContext->fUpdated = true;
1222 optimizationContext->fNeedsRescan = true;
Ethan Nicholascb670962017-04-20 19:31:52 -04001223 }
1224 break;
1225 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001226 case Statement::Kind::kSwitch: {
John Stiles642cde22021-02-23 14:57:01 -05001227 // TODO(skia:11319): this optimization logic is redundant with the static-switch
1228 // optimization code found in SwitchStatement.cpp.
John Stilesa5a97b42020-08-18 11:19:07 -04001229 SwitchStatement& s = stmt->as<SwitchStatement>();
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001230 int64_t switchValue;
Ethan Nicholasc0f98152021-02-05 16:21:10 -05001231 if (ConstantFolder::GetConstantInt(*s.value(), &switchValue)) {
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001232 // switch is constant, replace it with the case that matches
1233 bool found = false;
1234 SwitchCase* defaultCase = nullptr;
John Stiles2d4f9592020-10-30 10:29:12 -04001235 for (const std::unique_ptr<SwitchCase>& c : s.cases()) {
1236 if (!c->value()) {
1237 defaultCase = c.get();
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001238 continue;
1239 }
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001240 int64_t caseValue;
Ethan Nicholasc0f98152021-02-05 16:21:10 -05001241 SkAssertResult(ConstantFolder::GetConstantInt(*c->value(), &caseValue));
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001242 if (caseValue == switchValue) {
John Stiles642cde22021-02-23 14:57:01 -05001243 std::unique_ptr<Statement> newBlock =
1244 SwitchStatement::BlockForCase(&s.cases(), c.get(), s.symbols());
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001245 if (newBlock) {
Brian Osman010ce6a2020-10-19 16:34:10 -04001246 (*iter)->setStatement(std::move(newBlock), usage);
John Stiles9d944232020-08-19 09:56:49 -04001247 found = true;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001248 break;
1249 } else {
John Stilesd6a5f4492021-02-11 15:46:11 -05001250 if (s.isStatic() &&
John Stilesd1204642021-02-17 16:30:02 -05001251 !fContext->fConfig->fSettings.fPermitInvalidStaticTests) {
John Stilesd6a5f4492021-02-11 15:46:11 -05001252 auto [iter, didInsert] = optimizationContext->fSilences.insert(&s);
1253 if (didInsert) {
1254 this->error(s.fOffset, "static switch contains non-static "
John Stiles04ca41a2021-02-23 09:58:04 -05001255 "conditional exit");
John Stilesd6a5f4492021-02-11 15:46:11 -05001256 }
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001257 }
1258 return; // can't simplify
1259 }
1260 }
1261 }
1262 if (!found) {
1263 // no matching case. use default if it exists, or kill the whole thing
1264 if (defaultCase) {
John Stiles642cde22021-02-23 14:57:01 -05001265 std::unique_ptr<Statement> newBlock =
1266 SwitchStatement::BlockForCase(&s.cases(), defaultCase, s.symbols());
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001267 if (newBlock) {
Brian Osman010ce6a2020-10-19 16:34:10 -04001268 (*iter)->setStatement(std::move(newBlock), usage);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001269 } else {
John Stilesd6a5f4492021-02-11 15:46:11 -05001270 if (s.isStatic() &&
John Stilesd1204642021-02-17 16:30:02 -05001271 !fContext->fConfig->fSettings.fPermitInvalidStaticTests) {
John Stilesd6a5f4492021-02-11 15:46:11 -05001272 auto [iter, didInsert] = optimizationContext->fSilences.insert(&s);
1273 if (didInsert) {
1274 this->error(s.fOffset, "static switch contains non-static "
John Stiles04ca41a2021-02-23 09:58:04 -05001275 "conditional exit");
John Stilesd6a5f4492021-02-11 15:46:11 -05001276 }
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001277 }
1278 return; // can't simplify
1279 }
1280 } else {
Brian Osman010ce6a2020-10-19 16:34:10 -04001281 (*iter)->setStatement(std::make_unique<Nop>(), usage);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001282 }
1283 }
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001284 optimizationContext->fUpdated = true;
1285 optimizationContext->fNeedsRescan = true;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001286 }
1287 break;
1288 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001289 case Statement::Kind::kExpression: {
John Stilesa5a97b42020-08-18 11:19:07 -04001290 ExpressionStatement& e = stmt->as<ExpressionStatement>();
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001291 SkASSERT((*iter)->statement()->get() == &e);
Ethan Nicholasd503a5a2020-09-30 09:29:55 -04001292 if (!e.expression()->hasSideEffects()) {
Ethan Nicholascb670962017-04-20 19:31:52 -04001293 // Expression statement with no side effects, kill it
Ethan Nicholasd503a5a2020-09-30 09:29:55 -04001294 if (!b.tryRemoveExpressionBefore(iter, e.expression().get())) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001295 optimizationContext->fNeedsRescan = true;
Ethan Nicholascb670962017-04-20 19:31:52 -04001296 }
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001297 SkASSERT((*iter)->statement()->get() == stmt);
Brian Osman010ce6a2020-10-19 16:34:10 -04001298 (*iter)->setStatement(std::make_unique<Nop>(), usage);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001299 optimizationContext->fUpdated = true;
Ethan Nicholascb670962017-04-20 19:31:52 -04001300 }
1301 break;
1302 }
1303 default:
1304 break;
1305 }
1306}
1307
Brian Osman010ce6a2020-10-19 16:34:10 -04001308bool Compiler::scanCFG(FunctionDefinition& f, ProgramUsage* usage) {
John Stiles0cc193a2020-09-09 09:39:34 -04001309 bool madeChanges = false;
1310
Ethan Nicholascb670962017-04-20 19:31:52 -04001311 CFG cfg = CFGGenerator().getCFG(f);
1312 this->computeDataFlow(&cfg);
ethannicholas22f939e2016-10-13 13:25:34 -07001313
John Stiles66c53b92021-02-20 08:00:43 -05001314 if (fContext->fConfig->fSettings.fDeadCodeElimination) {
1315 // Check for unreachable code.
1316 for (size_t i = 0; i < cfg.fBlocks.size(); i++) {
1317 const BasicBlock& block = cfg.fBlocks[i];
1318 if (!block.fIsReachable && !block.fAllowUnreachable && block.fNodes.size()) {
1319 const BasicBlock::Node& node = block.fNodes[0];
1320 int offset = node.isStatement() ? (*node.statement())->fOffset
1321 : (*node.expression())->fOffset;
1322 this->error(offset, String("unreachable"));
1323 }
ethannicholas22f939e2016-10-13 13:25:34 -07001324 }
1325 }
1326 if (fErrorCount) {
John Stiles0cc193a2020-09-09 09:39:34 -04001327 return madeChanges;
ethannicholas22f939e2016-10-13 13:25:34 -07001328 }
1329
Ethan Nicholascb670962017-04-20 19:31:52 -04001330 // check for dead code & undefined variables, perform constant propagation
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001331 OptimizationContext optimizationContext;
Brian Osman010ce6a2020-10-19 16:34:10 -04001332 optimizationContext.fUsage = usage;
John Stiles7d3f0892020-11-03 11:35:01 -05001333 SkBitSet eliminatedBlockIds(cfg.fBlocks.size());
Ethan Nicholascb670962017-04-20 19:31:52 -04001334 do {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001335 if (optimizationContext.fNeedsRescan) {
Ethan Nicholascb670962017-04-20 19:31:52 -04001336 cfg = CFGGenerator().getCFG(f);
1337 this->computeDataFlow(&cfg);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001338 optimizationContext.fNeedsRescan = false;
Ethan Nicholas113628d2017-02-02 16:11:39 -05001339 }
Ethan Nicholascb670962017-04-20 19:31:52 -04001340
John Stiles7d3f0892020-11-03 11:35:01 -05001341 eliminatedBlockIds.reset();
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001342 optimizationContext.fUpdated = false;
John Stiles7d3f0892020-11-03 11:35:01 -05001343
1344 for (BlockId blockId = 0; blockId < cfg.fBlocks.size(); ++blockId) {
1345 if (eliminatedBlockIds.test(blockId)) {
1346 // We reached a block ID that might have been eliminated. Be cautious and rescan.
1347 optimizationContext.fUpdated = true;
1348 optimizationContext.fNeedsRescan = true;
1349 break;
1350 }
1351
1352 BasicBlock& b = cfg.fBlocks[blockId];
John Stiles66c53b92021-02-20 08:00:43 -05001353 if (fContext->fConfig->fSettings.fDeadCodeElimination) {
1354 if (blockId > 0 && !b.fIsReachable) {
1355 // Block was reachable before optimization, but has since become unreachable. In
1356 // addition to being dead code, it's broken - since control flow can't reach it,
1357 // no prior variable definitions can reach it, and therefore variables might
1358 // look to have not been properly assigned. Kill it by replacing all statements
1359 // with Nops.
1360 for (BasicBlock::Node& node : b.fNodes) {
1361 if (node.isStatement() && !(*node.statement())->is<Nop>()) {
1362 // Eliminating a node runs the risk of eliminating that node's exits as
1363 // well. Keep track of this and do a rescan if we are about to access
1364 // one of these.
1365 for (BlockId id : b.fExits) {
1366 eliminatedBlockIds.set(id);
1367 }
1368 node.setStatement(std::make_unique<Nop>(), usage);
1369 madeChanges = true;
John Stiles7d3f0892020-11-03 11:35:01 -05001370 }
Ethan Nicholas1de14812020-06-19 15:32:49 -04001371 }
John Stiles66c53b92021-02-20 08:00:43 -05001372 continue;
Ethan Nicholas1de14812020-06-19 15:32:49 -04001373 }
Ethan Nicholas1de14812020-06-19 15:32:49 -04001374 }
Ethan Nicholascb670962017-04-20 19:31:52 -04001375 DefinitionMap definitions = b.fBefore;
1376
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001377 for (auto iter = b.fNodes.begin(); iter != b.fNodes.end() &&
1378 !optimizationContext.fNeedsRescan; ++iter) {
John Stiles70025e52020-09-28 16:08:58 -04001379 if (iter->isExpression()) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001380 this->simplifyExpression(definitions, b, &iter, &optimizationContext);
Ethan Nicholascb670962017-04-20 19:31:52 -04001381 } else {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001382 this->simplifyStatement(definitions, b, &iter, &optimizationContext);
Ethan Nicholascb670962017-04-20 19:31:52 -04001383 }
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001384 if (optimizationContext.fNeedsRescan) {
Ethan Nicholas4b330df2017-05-17 10:52:55 -04001385 break;
1386 }
John Stilese8a24922021-02-08 17:54:08 -05001387 definitions.addDefinitions(*fContext, *iter);
Ethan Nicholascb670962017-04-20 19:31:52 -04001388 }
Brian Osman01a3eb42020-09-14 11:32:49 -04001389
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001390 if (optimizationContext.fNeedsRescan) {
Brian Osman01a3eb42020-09-14 11:32:49 -04001391 break;
1392 }
Ethan Nicholascb670962017-04-20 19:31:52 -04001393 }
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001394 madeChanges |= optimizationContext.fUpdated;
1395 } while (optimizationContext.fUpdated);
1396 SkASSERT(!optimizationContext.fNeedsRescan);
ethannicholas22f939e2016-10-13 13:25:34 -07001397
John Stiles0cc193a2020-09-09 09:39:34 -04001398 return madeChanges;
ethannicholas22f939e2016-10-13 13:25:34 -07001399}
1400
Brian Osman32d53552020-09-23 13:55:20 -04001401std::unique_ptr<Program> Compiler::convertProgram(
John Stilesdbd4e6f2021-02-16 13:29:15 -05001402 ProgramKind kind,
Brian Osman32d53552020-09-23 13:55:20 -04001403 String text,
1404 const Program::Settings& settings,
Brian Osmanbe0b3b72021-01-06 14:27:35 -05001405 const std::vector<std::unique_ptr<ExternalFunction>>* externalFunctions) {
Brian Osmand010f652021-02-24 13:59:39 -05001406 TRACE_EVENT0("skia.gpu", "SkSL::Compiler::convertProgram");
Leon Scrogginsb66214e2021-02-11 17:14:18 -05001407
John Stilesdbd4e6f2021-02-16 13:29:15 -05001408 SkASSERT(!externalFunctions || (kind == ProgramKind::kGeneric));
Ethan Nicholas91164d12019-05-15 15:29:54 -04001409
Brian Osman0006ad02020-11-18 15:38:39 -05001410 // Loading and optimizing our base module might reset the inliner, so do that first,
1411 // *then* configure the inliner with the settings for this program.
1412 const ParsedModule& baseModule = this->moduleForProgramKind(kind);
1413
John Stiles270cec22021-02-17 12:59:36 -05001414 // Update our context to point to the program configuration for the duration of compilation.
1415 auto config = std::make_unique<ProgramConfig>(ProgramConfig{kind, settings});
John Stilesa935c3f2021-02-25 10:35:49 -05001416 AutoProgramConfig autoConfig(fContext, config.get());
John Stiles270cec22021-02-17 12:59:36 -05001417
ethannicholasb3058bd2016-07-01 08:22:01 -07001418 fErrorText = "";
1419 fErrorCount = 0;
John Stilesd1204642021-02-17 16:30:02 -05001420 fInliner.reset(fIRGenerator->fModifiers.get());
Brian Osman88cda172020-10-09 12:05:16 -04001421
1422 // Not using AutoSource, because caller is likely to call errorText() if we fail to compile
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001423 std::unique_ptr<String> textPtr(new String(std::move(text)));
1424 fSource = textPtr.get();
Brian Osman88cda172020-10-09 12:05:16 -04001425
John Stiles5c7bb322020-10-22 11:09:15 -04001426 // Enable node pooling while converting and optimizing the program for a performance boost.
1427 // The Program will take ownership of the pool.
Brian Osman28f702c2021-02-02 11:52:07 -05001428 std::unique_ptr<Pool> pool;
John Stilesc1a98b82021-02-24 13:35:02 -05001429 if (fContext->fCaps.useNodePools()) {
Brian Osman28f702c2021-02-02 11:52:07 -05001430 pool = Pool::Create();
1431 pool->attachToThread();
1432 }
John Stilesd1204642021-02-17 16:30:02 -05001433 IRGenerator::IRBundle ir = fIRGenerator->convertProgram(baseModule, /*isBuiltinCode=*/false,
1434 textPtr->c_str(), textPtr->size(),
1435 externalFunctions);
John Stiles270cec22021-02-17 12:59:36 -05001436 auto program = std::make_unique<Program>(std::move(textPtr),
1437 std::move(config),
John Stiles5c7bb322020-10-22 11:09:15 -04001438 fContext,
1439 std::move(ir.fElements),
Brian Osman133724c2020-10-28 14:14:39 -04001440 std::move(ir.fSharedElements),
John Stiles5c7bb322020-10-22 11:09:15 -04001441 std::move(ir.fModifiers),
1442 std::move(ir.fSymbolTable),
1443 std::move(pool),
1444 ir.fInputs);
1445 bool success = false;
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001446 if (fErrorCount) {
John Stiles5c7bb322020-10-22 11:09:15 -04001447 // Do not return programs that failed to compile.
John Stilescbd65752021-02-24 14:14:14 +00001448 } else if (settings.fOptimize && !this->optimize(*program)) {
John Stiles5c7bb322020-10-22 11:09:15 -04001449 // Do not return programs that failed to optimize.
1450 } else {
1451 // We have a successful program!
1452 success = true;
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001453 }
John Stiles5c7bb322020-10-22 11:09:15 -04001454
Brian Osman28f702c2021-02-02 11:52:07 -05001455 if (program->fPool) {
1456 program->fPool->detachFromThread();
1457 }
John Stiles5c7bb322020-10-22 11:09:15 -04001458 return success ? std::move(program) : nullptr;
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001459}
1460
John Stilesbb1505f2021-02-12 09:17:53 -05001461void Compiler::verifyStaticTests(const Program& program) {
1462 class StaticTestVerifier : public ProgramVisitor {
1463 public:
1464 StaticTestVerifier(ErrorReporter* r) : fReporter(r) {}
1465
1466 using ProgramVisitor::visitProgramElement;
1467
1468 bool visitStatement(const Statement& stmt) override {
1469 switch (stmt.kind()) {
1470 case Statement::Kind::kIf:
1471 if (stmt.as<IfStatement>().isStatic()) {
1472 fReporter->error(stmt.fOffset, "static if has non-static test");
1473 }
1474 break;
1475
1476 case Statement::Kind::kSwitch:
1477 if (stmt.as<SwitchStatement>().isStatic()) {
1478 fReporter->error(stmt.fOffset, "static switch has non-static test");
1479 }
1480 break;
1481
1482 default:
1483 break;
1484 }
1485 return INHERITED::visitStatement(stmt);
1486 }
1487
John Stiles59e34562021-02-12 16:56:39 -05001488 bool visitExpression(const Expression&) override {
1489 // We aren't looking for anything inside an Expression, so skip them entirely.
1490 return false;
1491 }
1492
John Stilesbb1505f2021-02-12 09:17:53 -05001493 private:
1494 using INHERITED = ProgramVisitor;
1495 ErrorReporter* fReporter;
1496 };
1497
1498 // If invalid static tests are permitted, we don't need to check anything.
John Stilesd1204642021-02-17 16:30:02 -05001499 if (fContext->fConfig->fSettings.fPermitInvalidStaticTests) {
John Stilesbb1505f2021-02-12 09:17:53 -05001500 return;
1501 }
1502
1503 // Check all of the program's owned elements. (Built-in elements are assumed to be valid.)
1504 StaticTestVerifier visitor{this};
1505 for (const std::unique_ptr<ProgramElement>& element : program.ownedElements()) {
1506 if (element->is<FunctionDefinition>()) {
1507 visitor.visitProgramElement(*element);
1508 }
1509 }
1510}
1511
Brian Osman0006ad02020-11-18 15:38:39 -05001512bool Compiler::optimize(LoadedModule& module) {
1513 SkASSERT(!fErrorCount);
Brian Osman0006ad02020-11-18 15:38:39 -05001514
John Stiles270cec22021-02-17 12:59:36 -05001515 // Create a temporary program configuration with default settings.
1516 ProgramConfig config;
1517 config.fKind = module.fKind;
John Stilesa935c3f2021-02-25 10:35:49 -05001518 AutoProgramConfig autoConfig(fContext, &config);
John Stiles270cec22021-02-17 12:59:36 -05001519
John Stilesd1204642021-02-17 16:30:02 -05001520 // Reset the Inliner.
1521 fInliner.reset(fModifiers.back().get());
John Stiles270cec22021-02-17 12:59:36 -05001522
1523 std::unique_ptr<ProgramUsage> usage = Analysis::GetUsage(module);
Brian Osman0006ad02020-11-18 15:38:39 -05001524
1525 while (fErrorCount == 0) {
1526 bool madeChanges = false;
1527
1528 // Scan and optimize based on the control-flow graph for each function.
John Stilesa935c3f2021-02-25 10:35:49 -05001529 if (config.fSettings.fControlFlowAnalysis) {
1530 for (const auto& element : module.fElements) {
1531 if (element->is<FunctionDefinition>()) {
1532 madeChanges |= this->scanCFG(element->as<FunctionDefinition>(), usage.get());
1533 }
Brian Osman0006ad02020-11-18 15:38:39 -05001534 }
1535 }
1536
1537 // Perform inline-candidate analysis and inline any functions deemed suitable.
John Stiles78047582020-12-16 16:17:41 -05001538 madeChanges |= fInliner.analyze(module.fElements, module.fSymbols, usage.get());
Brian Osman0006ad02020-11-18 15:38:39 -05001539
1540 if (!madeChanges) {
1541 break;
1542 }
1543 }
1544 return fErrorCount == 0;
1545}
1546
Ethan Nicholas00543112018-07-31 09:44:36 -04001547bool Compiler::optimize(Program& program) {
1548 SkASSERT(!fErrorCount);
Brian Osman010ce6a2020-10-19 16:34:10 -04001549 ProgramUsage* usage = program.fUsage.get();
John Stiles7954d6c2020-09-01 10:53:02 -04001550
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001551 while (fErrorCount == 0) {
1552 bool madeChanges = false;
John Stiles7954d6c2020-09-01 10:53:02 -04001553
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001554 // Scan and optimize based on the control-flow graph for each function.
John Stiles0c7312a2021-02-24 11:31:32 -05001555 if (program.fConfig->fSettings.fControlFlowAnalysis) {
1556 for (const auto& element : program.ownedElements()) {
1557 if (element->is<FunctionDefinition>()) {
1558 madeChanges |= this->scanCFG(element->as<FunctionDefinition>(), usage);
1559 }
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001560 }
1561 }
1562
1563 // Perform inline-candidate analysis and inline any functions deemed suitable.
John Stiles78047582020-12-16 16:17:41 -05001564 madeChanges |= fInliner.analyze(program.ownedElements(), program.fSymbols, usage);
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001565
1566 // Remove dead functions. We wait until after analysis so that we still report errors,
1567 // even in unused code.
John Stiles270cec22021-02-17 12:59:36 -05001568 if (program.fConfig->fSettings.fRemoveDeadFunctions) {
Brian Osman133724c2020-10-28 14:14:39 -04001569 auto isDeadFunction = [&](const ProgramElement* element) {
1570 if (!element->is<FunctionDefinition>()) {
1571 return false;
1572 }
1573 const FunctionDefinition& fn = element->as<FunctionDefinition>();
1574 if (fn.declaration().name() != "main" && usage->get(fn.declaration()) == 0) {
1575 usage->remove(*element);
1576 madeChanges = true;
1577 return true;
1578 }
1579 return false;
1580 };
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001581 program.fElements.erase(
Brian Osman133724c2020-10-28 14:14:39 -04001582 std::remove_if(program.fElements.begin(), program.fElements.end(),
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001583 [&](const std::unique_ptr<ProgramElement>& element) {
Brian Osman133724c2020-10-28 14:14:39 -04001584 return isDeadFunction(element.get());
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001585 }),
1586 program.fElements.end());
Brian Osman133724c2020-10-28 14:14:39 -04001587 program.fSharedElements.erase(
1588 std::remove_if(program.fSharedElements.begin(), program.fSharedElements.end(),
1589 isDeadFunction),
1590 program.fSharedElements.end());
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001591 }
1592
John Stiles270cec22021-02-17 12:59:36 -05001593 if (program.fConfig->fKind != ProgramKind::kFragmentProcessor) {
Brian Osmanc0213602020-10-06 14:43:32 -04001594 // Remove declarations of dead global variables
Brian Osman133724c2020-10-28 14:14:39 -04001595 auto isDeadVariable = [&](const ProgramElement* element) {
1596 if (!element->is<GlobalVarDeclaration>()) {
1597 return false;
1598 }
1599 const GlobalVarDeclaration& global = element->as<GlobalVarDeclaration>();
1600 const VarDeclaration& varDecl = global.declaration()->as<VarDeclaration>();
1601 if (usage->isDead(varDecl.var())) {
1602 madeChanges = true;
1603 return true;
1604 }
1605 return false;
1606 };
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001607 program.fElements.erase(
1608 std::remove_if(program.fElements.begin(), program.fElements.end(),
1609 [&](const std::unique_ptr<ProgramElement>& element) {
Brian Osman133724c2020-10-28 14:14:39 -04001610 return isDeadVariable(element.get());
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001611 }),
1612 program.fElements.end());
Brian Osman133724c2020-10-28 14:14:39 -04001613 program.fSharedElements.erase(
1614 std::remove_if(program.fSharedElements.begin(), program.fSharedElements.end(),
1615 isDeadVariable),
1616 program.fSharedElements.end());
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001617 }
John Stiles73a6bff2020-09-09 13:40:37 -04001618
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001619 if (!madeChanges) {
1620 break;
Ethan Nicholas0dc80872019-02-08 15:46:24 -05001621 }
Ethan Nicholas00543112018-07-31 09:44:36 -04001622 }
John Stilesbb1505f2021-02-12 09:17:53 -05001623
1624 if (fErrorCount == 0) {
1625 this->verifyStaticTests(program);
1626 }
1627
Ethan Nicholas00543112018-07-31 09:44:36 -04001628 return fErrorCount == 0;
1629}
1630
Brian Osmanfb32ddf2019-06-18 10:14:20 -04001631#if defined(SKSL_STANDALONE) || SK_SUPPORT_GPU
1632
Ethan Nicholas00543112018-07-31 09:44:36 -04001633bool Compiler::toSPIRV(Program& program, OutputStream& out) {
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001634#ifdef SK_ENABLE_SPIRV_VALIDATION
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001635 StringStream buffer;
Brian Osman88cda172020-10-09 12:05:16 -04001636 AutoSource as(this, program.fSource.get());
Brian Osman8b43dad2020-10-09 13:31:42 -04001637 SPIRVCodeGenerator cg(fContext.get(), &program, this, &buffer);
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001638 bool result = cg.generateCode();
John Stiles270cec22021-02-17 12:59:36 -05001639 if (result && program.fConfig->fSettings.fValidateSPIRV) {
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001640 spvtools::SpirvTools tools(SPV_ENV_VULKAN_1_0);
Ethan Nicholas762466e2017-06-29 10:03:38 -04001641 const String& data = buffer.str();
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001642 SkASSERT(0 == data.size() % 4);
Brian Osman8d09d4a2020-11-24 15:51:06 -05001643 String errors;
1644 auto dumpmsg = [&errors](spv_message_level_t, const char*, const spv_position_t&,
1645 const char* m) {
1646 errors.appendf("SPIR-V validation error: %s\n", m);
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001647 };
1648 tools.SetMessageConsumer(dumpmsg);
Brian Osman8d09d4a2020-11-24 15:51:06 -05001649
1650 // Verify that the SPIR-V we produced is valid. At runtime, we will abort() with a message
1651 // explaining the error. In standalone mode (skslc), we will send the message, plus the
1652 // entire disassembled SPIR-V (for easier context & debugging) as *our* error message.
1653 result = tools.Validate((const uint32_t*) data.c_str(), data.size() / 4);
1654
1655 if (!result) {
1656#if defined(SKSL_STANDALONE)
1657 // Convert the string-stream to a SPIR-V disassembly.
1658 std::string disassembly;
1659 if (tools.Disassemble((const uint32_t*)data.data(), data.size() / 4, &disassembly)) {
1660 errors.append(disassembly);
1661 }
1662 this->error(-1, errors);
1663#else
1664 SkDEBUGFAILF("%s", errors.c_str());
1665#endif
1666 }
Ethan Nicholas762466e2017-06-29 10:03:38 -04001667 out.write(data.c_str(), data.size());
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001668 }
1669#else
Brian Osman88cda172020-10-09 12:05:16 -04001670 AutoSource as(this, program.fSource.get());
Brian Osman8b43dad2020-10-09 13:31:42 -04001671 SPIRVCodeGenerator cg(fContext.get(), &program, this, &out);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001672 bool result = cg.generateCode();
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001673#endif
Ethan Nicholasce33f102016-12-09 17:22:59 -05001674 return result;
1675}
1676
Ethan Nicholas00543112018-07-31 09:44:36 -04001677bool Compiler::toSPIRV(Program& program, String* out) {
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001678 StringStream buffer;
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001679 bool result = this->toSPIRV(program, buffer);
1680 if (result) {
Ethan Nicholas762466e2017-06-29 10:03:38 -04001681 *out = buffer.str();
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001682 }
1683 return result;
1684}
1685
Ethan Nicholas00543112018-07-31 09:44:36 -04001686bool Compiler::toGLSL(Program& program, OutputStream& out) {
Brian Osmand010f652021-02-24 13:59:39 -05001687 TRACE_EVENT0("skia.gpu", "SkSL::Compiler::toGLSL");
Brian Osman88cda172020-10-09 12:05:16 -04001688 AutoSource as(this, program.fSource.get());
Ethan Nicholas26a9aad2018-03-27 14:10:52 -04001689 GLSLCodeGenerator cg(fContext.get(), &program, this, &out);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001690 bool result = cg.generateCode();
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001691 return result;
1692}
1693
Ethan Nicholas00543112018-07-31 09:44:36 -04001694bool Compiler::toGLSL(Program& program, String* out) {
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001695 StringStream buffer;
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001696 bool result = this->toGLSL(program, buffer);
1697 if (result) {
Ethan Nicholas762466e2017-06-29 10:03:38 -04001698 *out = buffer.str();
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001699 }
1700 return result;
1701}
1702
Brian Osmanc0243912020-02-19 15:35:26 -05001703bool Compiler::toHLSL(Program& program, String* out) {
1704 String spirv;
1705 if (!this->toSPIRV(program, &spirv)) {
1706 return false;
1707 }
1708
1709 return SPIRVtoHLSL(spirv, out);
1710}
1711
Ethan Nicholas00543112018-07-31 09:44:36 -04001712bool Compiler::toMetal(Program& program, OutputStream& out) {
Ethan Nicholas26a9aad2018-03-27 14:10:52 -04001713 MetalCodeGenerator cg(fContext.get(), &program, this, &out);
Ethan Nicholascc305772017-10-13 16:17:45 -04001714 bool result = cg.generateCode();
Ethan Nicholascc305772017-10-13 16:17:45 -04001715 return result;
1716}
1717
Ethan Nicholas00543112018-07-31 09:44:36 -04001718bool Compiler::toMetal(Program& program, String* out) {
Timothy Liangb8eeb802018-07-23 16:46:16 -04001719 StringStream buffer;
1720 bool result = this->toMetal(program, buffer);
1721 if (result) {
1722 *out = buffer.str();
1723 }
1724 return result;
1725}
1726
Greg Daniela28ea672020-09-25 11:12:56 -04001727#if defined(SKSL_STANDALONE) || GR_TEST_UTILS
Ethan Nicholas00543112018-07-31 09:44:36 -04001728bool Compiler::toCPP(Program& program, String name, OutputStream& out) {
Brian Osman88cda172020-10-09 12:05:16 -04001729 AutoSource as(this, program.fSource.get());
Ethan Nicholas26a9aad2018-03-27 14:10:52 -04001730 CPPCodeGenerator cg(fContext.get(), &program, this, name, &out);
Ethan Nicholas762466e2017-06-29 10:03:38 -04001731 bool result = cg.generateCode();
Ethan Nicholas762466e2017-06-29 10:03:38 -04001732 return result;
1733}
1734
Ethan Nicholas00543112018-07-31 09:44:36 -04001735bool Compiler::toH(Program& program, String name, OutputStream& out) {
Brian Osman88cda172020-10-09 12:05:16 -04001736 AutoSource as(this, program.fSource.get());
Ethan Nicholas26a9aad2018-03-27 14:10:52 -04001737 HCodeGenerator cg(fContext.get(), &program, this, name, &out);
Ethan Nicholas762466e2017-06-29 10:03:38 -04001738 bool result = cg.generateCode();
Ethan Nicholas00543112018-07-31 09:44:36 -04001739 return result;
1740}
Greg Daniela28ea672020-09-25 11:12:56 -04001741#endif // defined(SKSL_STANDALONE) || GR_TEST_UTILS
Ethan Nicholas00543112018-07-31 09:44:36 -04001742
Ethan Nicholas2a479a52020-08-18 16:29:45 -04001743#endif // defined(SKSL_STANDALONE) || SK_SUPPORT_GPU
Brian Osman2e29ab52019-09-20 12:19:11 -04001744
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001745Position Compiler::position(int offset) {
Ethan Nicholas3c729892020-12-07 12:47:17 -05001746 if (fSource && offset >= 0) {
1747 int line = 1;
1748 int column = 1;
1749 for (int i = 0; i < offset; i++) {
1750 if ((*fSource)[i] == '\n') {
1751 ++line;
1752 column = 1;
1753 }
1754 else {
1755 ++column;
1756 }
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001757 }
Ethan Nicholas3c729892020-12-07 12:47:17 -05001758 return Position(line, column);
1759 } else {
1760 return Position(-1, -1);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001761 }
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001762}
1763
1764void Compiler::error(int offset, String msg) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001765 fErrorCount++;
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001766 Position pos = this->position(offset);
John Stiles8d3642e2021-01-22 09:50:04 -05001767 fErrorTextLength.push_back(fErrorText.length());
Ethan Nicholas3c729892020-12-07 12:47:17 -05001768 fErrorText += "error: " + (pos.fLine >= 1 ? to_string(pos.fLine) + ": " : "") + msg + "\n";
ethannicholasb3058bd2016-07-01 08:22:01 -07001769}
1770
John Stiles8d3642e2021-01-22 09:50:04 -05001771void Compiler::setErrorCount(int c) {
1772 if (c < fErrorCount) {
1773 fErrorText.resize(fErrorTextLength[c]);
1774 fErrorTextLength.resize(c);
1775 fErrorCount = c;
1776 }
1777}
1778
Ethan Nicholas95046142021-01-07 10:57:27 -05001779String Compiler::errorText(bool showCount) {
1780 if (showCount) {
1781 this->writeErrorCount();
1782 }
Ethan Nicholas00543112018-07-31 09:44:36 -04001783 fErrorCount = 0;
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001784 String result = fErrorText;
Ethan Nicholas95046142021-01-07 10:57:27 -05001785 fErrorText = "";
ethannicholasb3058bd2016-07-01 08:22:01 -07001786 return result;
1787}
1788
1789void Compiler::writeErrorCount() {
1790 if (fErrorCount) {
1791 fErrorText += to_string(fErrorCount) + " error";
1792 if (fErrorCount > 1) {
1793 fErrorText += "s";
1794 }
1795 fErrorText += "\n";
1796 }
1797}
1798
John Stilesa6841be2020-08-06 14:11:56 -04001799} // namespace SkSL