blob: a6d6cacada0742b889ad9bcea02daabda5c00e93 [file] [log] [blame]
ethannicholasb3058bd2016-07-01 08:22:01 -07001/*
2 * Copyright 2016 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
Mike Klein6ad99092016-10-26 10:35:22 -04007
Mike Kleinc0bd9f92019-04-23 12:05:21 -05008#include "src/sksl/SkSLCompiler.h"
ethannicholasb3058bd2016-07-01 08:22:01 -07009
John Stilesfbd050b2020-08-03 13:21:46 -040010#include <memory>
John Stilesb8e010c2020-08-11 18:05:39 -040011#include <unordered_set>
John Stilesfbd050b2020-08-03 13:21:46 -040012
John Stiles270cec22021-02-17 12:59:36 -050013#include "src/core/SkScopeExit.h"
Leon Scrogginsb66214e2021-02-11 17:14:18 -050014#include "src/core/SkTraceEvent.h"
John Stilesb92641c2020-08-31 18:09:01 -040015#include "src/sksl/SkSLAnalysis.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050016#include "src/sksl/SkSLCFGGenerator.h"
17#include "src/sksl/SkSLCPPCodeGenerator.h"
18#include "src/sksl/SkSLGLSLCodeGenerator.h"
19#include "src/sksl/SkSLHCodeGenerator.h"
20#include "src/sksl/SkSLIRGenerator.h"
21#include "src/sksl/SkSLMetalCodeGenerator.h"
Brian Osman00185012021-02-04 16:07:11 -050022#include "src/sksl/SkSLOperators.h"
John Stiles270cec22021-02-17 12:59:36 -050023#include "src/sksl/SkSLProgramSettings.h"
Ethan Nicholasc18bb512020-07-28 14:46:53 -040024#include "src/sksl/SkSLRehydrator.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050025#include "src/sksl/SkSLSPIRVCodeGenerator.h"
Brian Osmanc0243912020-02-19 15:35:26 -050026#include "src/sksl/SkSLSPIRVtoHLSL.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050027#include "src/sksl/ir/SkSLEnum.h"
28#include "src/sksl/ir/SkSLExpression.h"
29#include "src/sksl/ir/SkSLExpressionStatement.h"
30#include "src/sksl/ir/SkSLFunctionCall.h"
31#include "src/sksl/ir/SkSLIntLiteral.h"
32#include "src/sksl/ir/SkSLModifiersDeclaration.h"
33#include "src/sksl/ir/SkSLNop.h"
34#include "src/sksl/ir/SkSLSymbolTable.h"
35#include "src/sksl/ir/SkSLTernaryExpression.h"
36#include "src/sksl/ir/SkSLUnresolvedFunction.h"
37#include "src/sksl/ir/SkSLVarDeclarations.h"
John Stilese6150002020-10-05 12:03:53 -040038#include "src/utils/SkBitSet.h"
ethannicholasb3058bd2016-07-01 08:22:01 -070039
Ethan Nicholasb33fa3f2020-08-06 13:00:19 -040040#include <fstream>
41
Ethan Nicholasa11035b2019-11-26 16:27:47 -050042#if !defined(SKSL_STANDALONE) & SK_SUPPORT_GPU
43#include "include/gpu/GrContextOptions.h"
44#include "src/gpu/GrShaderCaps.h"
45#endif
46
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -040047#ifdef SK_ENABLE_SPIRV_VALIDATION
48#include "spirv-tools/libspirv.hpp"
49#endif
50
Brian Osman3d87e9f2020-10-08 11:50:22 -040051#if defined(SKSL_STANDALONE)
Ethan Nicholasc18bb512020-07-28 14:46:53 -040052
Brian Osman3d87e9f2020-10-08 11:50:22 -040053// In standalone mode, we load the textual sksl source files. GN generates or copies these files
54// to the skslc executable directory. The "data" in this mode is just the filename.
55#define MODULE_DATA(name) MakeModulePath("sksl_" #name ".sksl")
56
57#else
58
59// At runtime, we load the dehydrated sksl data files. The data is a (pointer, size) pair.
Ethan Nicholasc18bb512020-07-28 14:46:53 -040060#include "src/sksl/generated/sksl_fp.dehydrated.sksl"
61#include "src/sksl/generated/sksl_frag.dehydrated.sksl"
62#include "src/sksl/generated/sksl_geom.dehydrated.sksl"
63#include "src/sksl/generated/sksl_gpu.dehydrated.sksl"
Brian Osmanb06301e2020-11-06 11:45:36 -050064#include "src/sksl/generated/sksl_public.dehydrated.sksl"
Brian Osman91946752020-12-21 13:20:40 -050065#include "src/sksl/generated/sksl_runtime.dehydrated.sksl"
Ethan Nicholasc18bb512020-07-28 14:46:53 -040066#include "src/sksl/generated/sksl_vert.dehydrated.sksl"
67
Brian Osman3d87e9f2020-10-08 11:50:22 -040068#define MODULE_DATA(name) MakeModuleData(SKSL_INCLUDE_sksl_##name,\
69 SKSL_INCLUDE_sksl_##name##_LENGTH)
Ethan Nicholasc18bb512020-07-28 14:46:53 -040070
71#endif
Ethan Nicholas0d997662019-04-08 09:46:01 -040072
ethannicholasb3058bd2016-07-01 08:22:01 -070073namespace SkSL {
74
John Stiles47c0a742021-02-09 09:30:35 -050075using RefKind = VariableReference::RefKind;
76
Brian Osman88cda172020-10-09 12:05:16 -040077class AutoSource {
78public:
79 AutoSource(Compiler* compiler, const String* source)
80 : fCompiler(compiler), fOldSource(fCompiler->fSource) {
81 fCompiler->fSource = source;
82 }
83
84 ~AutoSource() { fCompiler->fSource = fOldSource; }
85
86 Compiler* fCompiler;
87 const String* fOldSource;
88};
89
John Stilesd6a5f4492021-02-11 15:46:11 -050090Compiler::Compiler(const ShaderCapsClass* caps)
John Stilesc1a98b82021-02-24 13:35:02 -050091 : fContext(std::make_shared<Context>(/*errors=*/*this, *caps))
John Stiles7b920442020-12-17 10:43:41 -050092 , fInliner(fContext.get())
Brian Osman0006ad02020-11-18 15:38:39 -050093 , fErrorCount(0) {
John Stilesc1a98b82021-02-24 13:35:02 -050094 SkASSERT(caps);
John Stiles7c3515b2020-10-16 18:38:39 -040095 fRootSymbolTable = std::make_shared<SymbolTable>(this, /*builtin=*/true);
Brian Osmanb06301e2020-11-06 11:45:36 -050096 fPrivateSymbolTable = std::make_shared<SymbolTable>(fRootSymbolTable, /*builtin=*/true);
John Stilesc1a98b82021-02-24 13:35:02 -050097 fIRGenerator = std::make_unique<IRGenerator>(fContext.get());
ethannicholasb3058bd2016-07-01 08:22:01 -070098
John Stiles54e7c052021-01-11 14:22:36 -050099#define TYPE(t) fContext->fTypes.f ## t .get()
ethannicholasb3058bd2016-07-01 08:22:01 -0700100
Brian Osmanb06301e2020-11-06 11:45:36 -0500101 const SkSL::Symbol* rootTypes[] = {
102 TYPE(Void),
Brian Salomonbf7b6202016-11-11 16:08:03 -0500103
Brian Osmanb06301e2020-11-06 11:45:36 -0500104 TYPE( Float), TYPE( Float2), TYPE( Float3), TYPE( Float4),
105 TYPE( Half), TYPE( Half2), TYPE( Half3), TYPE( Half4),
106 TYPE( Int), TYPE( Int2), TYPE( Int3), TYPE( Int4),
Brian Osmanb06301e2020-11-06 11:45:36 -0500107 TYPE( Bool), TYPE( Bool2), TYPE( Bool3), TYPE( Bool4),
Brian Salomon2a51de82016-11-16 12:06:01 -0500108
Brian Osmanc0f2b642020-12-22 13:35:55 -0500109 TYPE(Float2x2), TYPE(Float3x3), TYPE(Float4x4),
Brian Osmanc63f4312020-12-23 11:44:14 -0500110 TYPE( Half2x2), TYPE( Half3x3), TYPE(Half4x4),
Greg Daniel64773e62016-11-22 09:44:03 -0500111
Brian Osmanc63f4312020-12-23 11:44:14 -0500112 TYPE(SquareMat), TYPE(SquareHMat),
ethannicholasb3058bd2016-07-01 08:22:01 -0700113
Brian Osman20fad322020-12-23 12:42:33 -0500114 TYPE(GenType), TYPE(GenHType), TYPE(GenIType), TYPE(GenBType),
115 TYPE(Vec), TYPE(HVec), TYPE(IVec), TYPE(BVec),
Brian Osmanb06301e2020-11-06 11:45:36 -0500116
117 TYPE(FragmentProcessor),
118 };
119
120 const SkSL::Symbol* privateTypes[] = {
Brian Osman20fad322020-12-23 12:42:33 -0500121 TYPE( UInt), TYPE( UInt2), TYPE( UInt3), TYPE( UInt4),
122 TYPE( Short), TYPE( Short2), TYPE( Short3), TYPE( Short4),
123 TYPE(UShort), TYPE(UShort2), TYPE(UShort3), TYPE(UShort4),
124 TYPE( Byte), TYPE( Byte2), TYPE( Byte3), TYPE( Byte4),
125 TYPE( UByte), TYPE( UByte2), TYPE( UByte3), TYPE( UByte4),
126
127 TYPE(GenUType), TYPE(UVec),
128 TYPE(SVec), TYPE(USVec), TYPE(ByteVec), TYPE(UByteVec),
129
Brian Osmanc0f2b642020-12-22 13:35:55 -0500130 TYPE(Float2x3), TYPE(Float2x4),
131 TYPE(Float3x2), TYPE(Float3x4),
132 TYPE(Float4x2), TYPE(Float4x3),
133
Brian Osmanc63f4312020-12-23 11:44:14 -0500134 TYPE(Half2x3), TYPE(Half2x4),
135 TYPE(Half3x2), TYPE(Half3x4),
136 TYPE(Half4x2), TYPE(Half4x3),
137
Brian Osmanc0f2b642020-12-22 13:35:55 -0500138 TYPE(Mat), TYPE(HMat),
139
Brian Osmanb06301e2020-11-06 11:45:36 -0500140 TYPE(Sampler1D), TYPE(Sampler2D), TYPE(Sampler3D),
141 TYPE(SamplerExternalOES),
Brian Osmanb06301e2020-11-06 11:45:36 -0500142 TYPE(Sampler2DRect),
Brian Osmanb06301e2020-11-06 11:45:36 -0500143
144 TYPE(ISampler2D),
Brian Osmanb06301e2020-11-06 11:45:36 -0500145 TYPE(SubpassInput), TYPE(SubpassInputMS),
146
Brian Osmanb06301e2020-11-06 11:45:36 -0500147 TYPE(Sampler),
148 TYPE(Texture2D),
149 };
150
151 for (const SkSL::Symbol* type : rootTypes) {
152 fRootSymbolTable->addWithoutOwnership(type);
153 }
154 for (const SkSL::Symbol* type : privateTypes) {
155 fPrivateSymbolTable->addWithoutOwnership(type);
156 }
157
158#undef TYPE
ethannicholasb3058bd2016-07-01 08:22:01 -0700159
Brian Osman3887a012020-09-30 13:22:27 -0400160 // sk_Caps is "builtin", but all references to it are resolved to Settings, so we don't need to
161 // treat it as builtin (ie, no need to clone it into the Program).
Brian Osmanb06301e2020-11-06 11:45:36 -0500162 fPrivateSymbolTable->add(
163 std::make_unique<Variable>(/*offset=*/-1,
John Stiles586df952020-11-12 18:27:13 -0500164 fIRGenerator->fModifiers->addToPool(Modifiers()),
Brian Osmanb06301e2020-11-06 11:45:36 -0500165 "sk_Caps",
John Stiles54e7c052021-01-11 14:22:36 -0500166 fContext->fTypes.fSkCaps.get(),
Brian Osmanb06301e2020-11-06 11:45:36 -0500167 /*builtin=*/false,
168 Variable::Storage::kGlobal));
Ethan Nicholas3605ace2016-11-21 15:59:48 -0500169
Brian Osman3d87e9f2020-10-08 11:50:22 -0400170 fRootModule = {fRootSymbolTable, /*fIntrinsics=*/nullptr};
Brian Osmanb06301e2020-11-06 11:45:36 -0500171 fPrivateModule = {fPrivateSymbolTable, /*fIntrinsics=*/nullptr};
ethannicholasb3058bd2016-07-01 08:22:01 -0700172}
173
John Stilesdd13dba2020-10-29 10:45:34 -0400174Compiler::~Compiler() {}
ethannicholasb3058bd2016-07-01 08:22:01 -0700175
Brian Osman56269982020-11-20 12:38:07 -0500176const ParsedModule& Compiler::loadGPUModule() {
177 if (!fGPUModule.fSymbols) {
John Stilesdbd4e6f2021-02-16 13:29:15 -0500178 fGPUModule = this->parseModule(ProgramKind::kFragment, MODULE_DATA(gpu), fPrivateModule);
Brian Osman56269982020-11-20 12:38:07 -0500179 }
180 return fGPUModule;
181}
182
183const ParsedModule& Compiler::loadFragmentModule() {
184 if (!fFragmentModule.fSymbols) {
John Stilesdbd4e6f2021-02-16 13:29:15 -0500185 fFragmentModule = this->parseModule(ProgramKind::kFragment, MODULE_DATA(frag),
Brian Osman56269982020-11-20 12:38:07 -0500186 this->loadGPUModule());
187 }
188 return fFragmentModule;
189}
190
191const ParsedModule& Compiler::loadVertexModule() {
192 if (!fVertexModule.fSymbols) {
John Stilesdbd4e6f2021-02-16 13:29:15 -0500193 fVertexModule = this->parseModule(ProgramKind::kVertex, MODULE_DATA(vert),
Brian Osman56269982020-11-20 12:38:07 -0500194 this->loadGPUModule());
195 }
196 return fVertexModule;
197}
198
Brian Osman88cda172020-10-09 12:05:16 -0400199const ParsedModule& Compiler::loadGeometryModule() {
Brian Osman3d87e9f2020-10-08 11:50:22 -0400200 if (!fGeometryModule.fSymbols) {
John Stilesdbd4e6f2021-02-16 13:29:15 -0500201 fGeometryModule = this->parseModule(ProgramKind::kGeometry, MODULE_DATA(geom),
Brian Osman56269982020-11-20 12:38:07 -0500202 this->loadGPUModule());
Ethan Nicholasc18bb512020-07-28 14:46:53 -0400203 }
Brian Osman88cda172020-10-09 12:05:16 -0400204 return fGeometryModule;
Ethan Nicholasc18bb512020-07-28 14:46:53 -0400205}
206
Brian Osman88cda172020-10-09 12:05:16 -0400207const ParsedModule& Compiler::loadFPModule() {
Brian Osman3d87e9f2020-10-08 11:50:22 -0400208 if (!fFPModule.fSymbols) {
John Stilesdbd4e6f2021-02-16 13:29:15 -0500209 fFPModule = this->parseModule(ProgramKind::kFragmentProcessor, MODULE_DATA(fp),
Brian Osman56269982020-11-20 12:38:07 -0500210 this->loadGPUModule());
Brian Osman8e2ef022020-09-30 13:26:43 -0400211 }
Brian Osman88cda172020-10-09 12:05:16 -0400212 return fFPModule;
Brian Osman8e2ef022020-09-30 13:26:43 -0400213}
214
Brian Osmanb06301e2020-11-06 11:45:36 -0500215const ParsedModule& Compiler::loadPublicModule() {
216 if (!fPublicModule.fSymbols) {
John Stilesdbd4e6f2021-02-16 13:29:15 -0500217 fPublicModule = this->parseModule(ProgramKind::kGeneric, MODULE_DATA(public), fRootModule);
Brian Osmanb06301e2020-11-06 11:45:36 -0500218 }
219 return fPublicModule;
220}
221
Brian Osman91946752020-12-21 13:20:40 -0500222const ParsedModule& Compiler::loadRuntimeEffectModule() {
223 if (!fRuntimeEffectModule.fSymbols) {
John Stilesdbd4e6f2021-02-16 13:29:15 -0500224 fRuntimeEffectModule = this->parseModule(ProgramKind::kRuntimeEffect, MODULE_DATA(runtime),
Brian Osman91946752020-12-21 13:20:40 -0500225 this->loadPublicModule());
Brian Osmanf1319c32020-10-13 09:34:23 -0400226
Brian Osman91946752020-12-21 13:20:40 -0500227 // Add some aliases to the runtime effect module so that it's friendlier, and more like GLSL
John Stiles54e7c052021-01-11 14:22:36 -0500228 fRuntimeEffectModule.fSymbols->addAlias("shader", fContext->fTypes.fFragmentProcessor.get());
Brian Osmanf1319c32020-10-13 09:34:23 -0400229
John Stiles54e7c052021-01-11 14:22:36 -0500230 fRuntimeEffectModule.fSymbols->addAlias("vec2", fContext->fTypes.fFloat2.get());
231 fRuntimeEffectModule.fSymbols->addAlias("vec3", fContext->fTypes.fFloat3.get());
232 fRuntimeEffectModule.fSymbols->addAlias("vec4", fContext->fTypes.fFloat4.get());
Brian Osmanf1319c32020-10-13 09:34:23 -0400233
John Stiles54e7c052021-01-11 14:22:36 -0500234 fRuntimeEffectModule.fSymbols->addAlias("bvec2", fContext->fTypes.fBool2.get());
235 fRuntimeEffectModule.fSymbols->addAlias("bvec3", fContext->fTypes.fBool3.get());
236 fRuntimeEffectModule.fSymbols->addAlias("bvec4", fContext->fTypes.fBool4.get());
Brian Osmanf1319c32020-10-13 09:34:23 -0400237
John Stiles54e7c052021-01-11 14:22:36 -0500238 fRuntimeEffectModule.fSymbols->addAlias("mat2", fContext->fTypes.fFloat2x2.get());
239 fRuntimeEffectModule.fSymbols->addAlias("mat3", fContext->fTypes.fFloat3x3.get());
240 fRuntimeEffectModule.fSymbols->addAlias("mat4", fContext->fTypes.fFloat4x4.get());
Ethan Nicholasc18bb512020-07-28 14:46:53 -0400241 }
Brian Osman91946752020-12-21 13:20:40 -0500242 return fRuntimeEffectModule;
Ethan Nicholasc18bb512020-07-28 14:46:53 -0400243}
244
John Stilesdbd4e6f2021-02-16 13:29:15 -0500245const ParsedModule& Compiler::moduleForProgramKind(ProgramKind kind) {
Brian Osman88cda172020-10-09 12:05:16 -0400246 switch (kind) {
John Stilesdbd4e6f2021-02-16 13:29:15 -0500247 case ProgramKind::kVertex: return this->loadVertexModule(); break;
248 case ProgramKind::kFragment: return this->loadFragmentModule(); break;
249 case ProgramKind::kGeometry: return this->loadGeometryModule(); break;
250 case ProgramKind::kFragmentProcessor: return this->loadFPModule(); break;
251 case ProgramKind::kRuntimeEffect: return this->loadRuntimeEffectModule(); break;
252 case ProgramKind::kGeneric: return this->loadPublicModule(); break;
Brian Osman88cda172020-10-09 12:05:16 -0400253 }
254 SkUNREACHABLE;
Ethan Nicholasc18bb512020-07-28 14:46:53 -0400255}
256
John Stilesdbd4e6f2021-02-16 13:29:15 -0500257LoadedModule Compiler::loadModule(ProgramKind kind,
Brian Osman3d87e9f2020-10-08 11:50:22 -0400258 ModuleData data,
259 std::shared_ptr<SymbolTable> base) {
Brian Osman3d87e9f2020-10-08 11:50:22 -0400260 if (!base) {
Brian Osmanb06301e2020-11-06 11:45:36 -0500261 // NOTE: This is a workaround. The only time 'base' is null is when dehydrating includes.
262 // In that case, skslc doesn't know which module it's preparing, nor what the correct base
263 // module is. We can't use 'Root', because many GPU intrinsics reference private types,
264 // like samplers or textures. Today, 'Private' does contain the union of all known types,
265 // so this is safe. If we ever have types that only exist in 'Public' (for example), this
266 // logic needs to be smarter (by choosing the correct base for the module we're compiling).
267 base = fPrivateSymbolTable;
Brian Osman3d87e9f2020-10-08 11:50:22 -0400268 }
269
270#if defined(SKSL_STANDALONE)
271 SkASSERT(data.fPath);
272 std::ifstream in(data.fPath);
Brian Osmane498b3c2020-09-23 14:42:11 -0400273 std::unique_ptr<String> text = std::make_unique<String>(std::istreambuf_iterator<char>(in),
274 std::istreambuf_iterator<char>());
Ethan Nicholasb33fa3f2020-08-06 13:00:19 -0400275 if (in.rdstate()) {
Brian Osman3d87e9f2020-10-08 11:50:22 -0400276 printf("error reading %s\n", data.fPath);
Ethan Nicholasb33fa3f2020-08-06 13:00:19 -0400277 abort();
278 }
Brian Osmane498b3c2020-09-23 14:42:11 -0400279 const String* source = fRootSymbolTable->takeOwnershipOfString(std::move(text));
Brian Osman88cda172020-10-09 12:05:16 -0400280 AutoSource as(this, source);
John Stilesd1204642021-02-17 16:30:02 -0500281
John Stiles881a10c2020-09-19 10:13:24 -0400282 SkASSERT(fIRGenerator->fCanInline);
283 fIRGenerator->fCanInline = false;
John Stilesd1204642021-02-17 16:30:02 -0500284
285 ProgramConfig config;
286 config.fKind = kind;
287 config.fSettings.fReplaceSettings = false;
288
289 fContext->fConfig = &config;
290 SK_AT_SCOPE_EXIT(fContext->fConfig = nullptr);
John Stilesdbd4e6f2021-02-16 13:29:15 -0500291
Brian Osman88cda172020-10-09 12:05:16 -0400292 ParsedModule baseModule = {base, /*fIntrinsics=*/nullptr};
John Stilesd1204642021-02-17 16:30:02 -0500293 IRGenerator::IRBundle ir = fIRGenerator->convertProgram(baseModule, /*isBuiltinCode=*/true,
294 source->c_str(), source->length(),
295 /*externalFunctions=*/nullptr);
Brian Osman133724c2020-10-28 14:14:39 -0400296 SkASSERT(ir.fSharedElements.empty());
Brian Osman0006ad02020-11-18 15:38:39 -0500297 LoadedModule module = { kind, std::move(ir.fSymbolTable), std::move(ir.fElements) };
John Stiles881a10c2020-09-19 10:13:24 -0400298 fIRGenerator->fCanInline = true;
Ethan Nicholas8da1e652019-05-24 11:01:59 -0400299 if (this->fErrorCount) {
300 printf("Unexpected errors: %s\n", this->fErrorText.c_str());
Brian Osman3d87e9f2020-10-08 11:50:22 -0400301 SkDEBUGFAILF("%s %s\n", data.fPath, this->fErrorText.c_str());
Ethan Nicholas8da1e652019-05-24 11:01:59 -0400302 }
Brian Osman88cda172020-10-09 12:05:16 -0400303 fModifiers.push_back(std::move(ir.fModifiers));
Brian Osman3d87e9f2020-10-08 11:50:22 -0400304#else
305 SkASSERT(data.fData && (data.fSize != 0));
306 Rehydrator rehydrator(fContext.get(), fIRGenerator->fModifiers.get(), base, this,
307 data.fData, data.fSize);
Brian Osman0006ad02020-11-18 15:38:39 -0500308 LoadedModule module = { kind, rehydrator.symbolTable(), rehydrator.elements() };
Brian Osman3d87e9f2020-10-08 11:50:22 -0400309 fModifiers.push_back(fIRGenerator->releaseModifiers());
310#endif
311
312 return module;
313}
314
John Stilesdbd4e6f2021-02-16 13:29:15 -0500315ParsedModule Compiler::parseModule(ProgramKind kind, ModuleData data, const ParsedModule& base) {
Brian Osman0006ad02020-11-18 15:38:39 -0500316 LoadedModule module = this->loadModule(kind, data, base.fSymbols);
317 this->optimize(module);
Brian Osman3d87e9f2020-10-08 11:50:22 -0400318
319 // For modules that just declare (but don't define) intrinsic functions, there will be no new
320 // program elements. In that case, we can share our parent's intrinsic map:
Brian Osman0006ad02020-11-18 15:38:39 -0500321 if (module.fElements.empty()) {
322 return {module.fSymbols, base.fIntrinsics};
Brian Osman3d87e9f2020-10-08 11:50:22 -0400323 }
324
325 auto intrinsics = std::make_shared<IRIntrinsicMap>(base.fIntrinsics.get());
326
327 // Now, transfer all of the program elements to an intrinsic map. This maps certain types of
328 // global objects to the declaring ProgramElement.
Brian Osman0006ad02020-11-18 15:38:39 -0500329 for (std::unique_ptr<ProgramElement>& element : module.fElements) {
Brian Osman3d87e9f2020-10-08 11:50:22 -0400330 switch (element->kind()) {
331 case ProgramElement::Kind::kFunction: {
332 const FunctionDefinition& f = element->as<FunctionDefinition>();
Ethan Nicholas0a5d0962020-10-14 13:33:18 -0400333 SkASSERT(f.declaration().isBuiltin());
334 intrinsics->insertOrDie(f.declaration().description(), std::move(element));
Brian Osman3d87e9f2020-10-08 11:50:22 -0400335 break;
336 }
John Stiles569249b2020-11-03 12:18:22 -0500337 case ProgramElement::Kind::kFunctionPrototype: {
338 // These are already in the symbol table.
339 break;
340 }
Brian Osman3d87e9f2020-10-08 11:50:22 -0400341 case ProgramElement::Kind::kEnum: {
342 const Enum& e = element->as<Enum>();
343 SkASSERT(e.isBuiltin());
344 intrinsics->insertOrDie(e.typeName(), std::move(element));
345 break;
346 }
347 case ProgramElement::Kind::kGlobalVar: {
Ethan Nicholasc51f33e2020-10-13 13:49:44 -0400348 const GlobalVarDeclaration& global = element->as<GlobalVarDeclaration>();
349 const Variable& var = global.declaration()->as<VarDeclaration>().var();
350 SkASSERT(var.isBuiltin());
351 intrinsics->insertOrDie(var.name(), std::move(element));
Brian Osman3d87e9f2020-10-08 11:50:22 -0400352 break;
353 }
354 case ProgramElement::Kind::kInterfaceBlock: {
Ethan Nicholaseaf47882020-10-15 10:10:08 -0400355 const Variable& var = element->as<InterfaceBlock>().variable();
356 SkASSERT(var.isBuiltin());
357 intrinsics->insertOrDie(var.name(), std::move(element));
Brian Osman3d87e9f2020-10-08 11:50:22 -0400358 break;
359 }
360 default:
361 printf("Unsupported element: %s\n", element->description().c_str());
362 SkASSERT(false);
363 break;
364 }
365 }
366
Brian Osman0006ad02020-11-18 15:38:39 -0500367 return {module.fSymbols, std::move(intrinsics)};
Ethan Nicholas8da1e652019-05-24 11:01:59 -0400368}
369
John Stilese6150002020-10-05 12:03:53 -0400370void Compiler::scanCFG(CFG* cfg, BlockId blockId, SkBitSet* processedSet) {
ethannicholas22f939e2016-10-13 13:25:34 -0700371 BasicBlock& block = cfg->fBlocks[blockId];
372
373 // compute definitions after this block
Ethan Nicholas86a43402017-01-19 13:32:00 -0500374 DefinitionMap after = block.fBefore;
ethannicholas22f939e2016-10-13 13:25:34 -0700375 for (const BasicBlock::Node& n : block.fNodes) {
John Stilese8a24922021-02-08 17:54:08 -0500376 after.addDefinitions(*fContext, n);
ethannicholas22f939e2016-10-13 13:25:34 -0700377 }
378
379 // propagate definitions to exits
380 for (BlockId exitId : block.fExits) {
Ethan Nicholas26a9aad2018-03-27 14:10:52 -0400381 if (exitId == blockId) {
382 continue;
383 }
ethannicholas22f939e2016-10-13 13:25:34 -0700384 BasicBlock& exit = cfg->fBlocks[exitId];
John Stiles65b48272020-12-22 17:18:34 -0500385 for (const auto& [var, e1] : after) {
John Stiles796cdb72020-10-08 12:06:53 -0400386 std::unique_ptr<Expression>** exitDef = exit.fBefore.find(var);
387 if (!exitDef) {
John Stilese6150002020-10-05 12:03:53 -0400388 // exit has no definition for it, just copy it and reprocess exit block
389 processedSet->reset(exitId);
John Stilese8a24922021-02-08 17:54:08 -0500390 exit.fBefore.set(var, e1);
ethannicholas22f939e2016-10-13 13:25:34 -0700391 } else {
Ethan Nicholas86a43402017-01-19 13:32:00 -0500392 // exit has a (possibly different) value already defined
John Stiles796cdb72020-10-08 12:06:53 -0400393 std::unique_ptr<Expression>* e2 = *exitDef;
ethannicholas22f939e2016-10-13 13:25:34 -0700394 if (e1 != e2) {
John Stilese6150002020-10-05 12:03:53 -0400395 // definition has changed, merge and reprocess the exit block
396 processedSet->reset(exitId);
Ethan Nicholasaf197692017-02-27 13:26:45 -0500397 if (e1 && e2) {
John Stiles796cdb72020-10-08 12:06:53 -0400398 *exitDef = (std::unique_ptr<Expression>*)&fContext->fDefined_Expression;
Ethan Nicholasaf197692017-02-27 13:26:45 -0500399 } else {
John Stiles796cdb72020-10-08 12:06:53 -0400400 *exitDef = nullptr;
Ethan Nicholasaf197692017-02-27 13:26:45 -0500401 }
ethannicholas22f939e2016-10-13 13:25:34 -0700402 }
403 }
John Stiles65b48272020-12-22 17:18:34 -0500404 }
ethannicholas22f939e2016-10-13 13:25:34 -0700405 }
406}
407
Ethan Nicholascb670962017-04-20 19:31:52 -0400408/**
409 * Returns true if assigning to this lvalue has no effect.
410 */
Brian Osman010ce6a2020-10-19 16:34:10 -0400411static bool is_dead(const Expression& lvalue, ProgramUsage* usage) {
Ethan Nicholase6592142020-09-08 10:22:09 -0400412 switch (lvalue.kind()) {
413 case Expression::Kind::kVariableReference:
Brian Osman010ce6a2020-10-19 16:34:10 -0400414 return usage->isDead(*lvalue.as<VariableReference>().variable());
Ethan Nicholase6592142020-09-08 10:22:09 -0400415 case Expression::Kind::kSwizzle:
Brian Osman010ce6a2020-10-19 16:34:10 -0400416 return is_dead(*lvalue.as<Swizzle>().base(), usage);
Ethan Nicholase6592142020-09-08 10:22:09 -0400417 case Expression::Kind::kFieldAccess:
Brian Osman010ce6a2020-10-19 16:34:10 -0400418 return is_dead(*lvalue.as<FieldAccess>().base(), usage);
Ethan Nicholase6592142020-09-08 10:22:09 -0400419 case Expression::Kind::kIndex: {
John Stilesa5a97b42020-08-18 11:19:07 -0400420 const IndexExpression& idx = lvalue.as<IndexExpression>();
Brian Osman010ce6a2020-10-19 16:34:10 -0400421 return is_dead(*idx.base(), usage) &&
Ethan Nicholas2a4952d2020-10-08 15:35:56 -0400422 !idx.index()->hasProperty(Expression::Property::kSideEffects);
Ethan Nicholascb670962017-04-20 19:31:52 -0400423 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400424 case Expression::Kind::kTernary: {
John Stilesa5a97b42020-08-18 11:19:07 -0400425 const TernaryExpression& t = lvalue.as<TernaryExpression>();
Brian Osman010ce6a2020-10-19 16:34:10 -0400426 return !t.test()->hasSideEffects() &&
427 is_dead(*t.ifTrue(), usage) &&
428 is_dead(*t.ifFalse(), usage);
Ethan Nicholasa583b812018-01-18 13:32:11 -0500429 }
Ethan Nicholascb670962017-04-20 19:31:52 -0400430 default:
John Stileseada7bc2021-02-02 16:29:32 -0500431 SkDEBUGFAILF("invalid lvalue: %s\n", lvalue.description().c_str());
Ethan Nicholas2a099da2020-01-02 14:40:54 -0500432 return false;
Ethan Nicholascb670962017-04-20 19:31:52 -0400433 }
434}
ethannicholas22f939e2016-10-13 13:25:34 -0700435
Ethan Nicholascb670962017-04-20 19:31:52 -0400436/**
437 * Returns true if this is an assignment which can be collapsed down to just the right hand side due
438 * to a dead target and lack of side effects on the left hand side.
439 */
Brian Osman010ce6a2020-10-19 16:34:10 -0400440static bool dead_assignment(const BinaryExpression& b, ProgramUsage* usage) {
John Stiles45990502021-02-16 10:55:27 -0500441 if (!b.getOperator().isAssignment()) {
Ethan Nicholascb670962017-04-20 19:31:52 -0400442 return false;
443 }
John Stiles2d4f9592020-10-30 10:29:12 -0400444 return is_dead(*b.left(), usage);
Ethan Nicholascb670962017-04-20 19:31:52 -0400445}
446
John Stiles0ac6c152021-02-10 14:04:24 -0500447/**
448 * Returns true if both expression trees are the same. The left side is expected to be an lvalue.
449 * This only needs to check for trees that can plausibly terminate in a variable, so some basic
450 * candidates like `FloatLiteral` are missing.
451 */
452static bool is_matching_expression_tree(const Expression& left, const Expression& right) {
453 if (left.kind() != right.kind() || left.type() != right.type()) {
454 return false;
455 }
456
457 switch (left.kind()) {
458 case Expression::Kind::kIntLiteral:
459 return left.as<IntLiteral>().value() == right.as<IntLiteral>().value();
460
461 case Expression::Kind::kFieldAccess:
462 return left.as<FieldAccess>().fieldIndex() == right.as<FieldAccess>().fieldIndex() &&
463 is_matching_expression_tree(*left.as<FieldAccess>().base(),
464 *right.as<FieldAccess>().base());
465
466 case Expression::Kind::kIndex:
467 return is_matching_expression_tree(*left.as<IndexExpression>().index(),
468 *right.as<IndexExpression>().index()) &&
469 is_matching_expression_tree(*left.as<IndexExpression>().base(),
470 *right.as<IndexExpression>().base());
471
472 case Expression::Kind::kSwizzle:
473 return left.as<Swizzle>().components() == right.as<Swizzle>().components() &&
474 is_matching_expression_tree(*left.as<Swizzle>().base(),
475 *right.as<Swizzle>().base());
476
477 case Expression::Kind::kVariableReference:
478 return left.as<VariableReference>().variable() ==
479 right.as<VariableReference>().variable();
480
481 default:
482 return false;
483 }
484}
485
486static bool self_assignment(const BinaryExpression& b) {
John Stiles45990502021-02-16 10:55:27 -0500487 return b.getOperator().kind() == Token::Kind::TK_EQ &&
John Stiles0ac6c152021-02-10 14:04:24 -0500488 is_matching_expression_tree(*b.left(), *b.right());
489}
490
Ethan Nicholascb670962017-04-20 19:31:52 -0400491void Compiler::computeDataFlow(CFG* cfg) {
John Stilese8a24922021-02-08 17:54:08 -0500492 cfg->fBlocks[cfg->fStart].fBefore.computeStartState(*cfg);
John Stilese6150002020-10-05 12:03:53 -0400493
494 // We set bits in the "processed" set after a block has been scanned.
495 SkBitSet processedSet(cfg->fBlocks.size());
496 while (SkBitSet::OptionalIndex blockId = processedSet.findFirstUnset()) {
497 processedSet.set(*blockId);
498 this->scanCFG(cfg, *blockId, &processedSet);
ethannicholas22f939e2016-10-13 13:25:34 -0700499 }
Ethan Nicholascb670962017-04-20 19:31:52 -0400500}
501
502/**
503 * Attempts to replace the expression pointed to by iter with a new one (in both the CFG and the
504 * IR). If the expression can be cleanly removed, returns true and updates the iterator to point to
505 * the newly-inserted element. Otherwise updates only the IR and returns false (and the CFG will
506 * need to be regenerated).
507 */
John Stilesafbf8992020-08-18 10:08:21 -0400508static bool try_replace_expression(BasicBlock* b,
509 std::vector<BasicBlock::Node>::iterator* iter,
510 std::unique_ptr<Expression>* newExpression) {
Ethan Nicholascb670962017-04-20 19:31:52 -0400511 std::unique_ptr<Expression>* target = (*iter)->expression();
512 if (!b->tryRemoveExpression(iter)) {
513 *target = std::move(*newExpression);
514 return false;
515 }
516 *target = std::move(*newExpression);
517 return b->tryInsertExpression(iter, target);
518}
519
520/**
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400521 * Returns true if the expression is a constant numeric literal with the specified value, or a
522 * constant vector with all elements equal to the specified value.
Ethan Nicholascb670962017-04-20 19:31:52 -0400523 */
Ethan Nicholasa3f22f12020-10-01 12:13:17 -0400524template <typename T = SKSL_FLOAT>
John Stiles9d944232020-08-19 09:56:49 -0400525static bool is_constant(const Expression& expr, T value) {
Ethan Nicholase6592142020-09-08 10:22:09 -0400526 switch (expr.kind()) {
527 case Expression::Kind::kIntLiteral:
Ethan Nicholase96cdd12020-09-28 16:27:18 -0400528 return expr.as<IntLiteral>().value() == value;
John Stiles9d944232020-08-19 09:56:49 -0400529
Ethan Nicholase6592142020-09-08 10:22:09 -0400530 case Expression::Kind::kFloatLiteral:
Ethan Nicholasa3f22f12020-10-01 12:13:17 -0400531 return expr.as<FloatLiteral>().value() == value;
John Stiles9d944232020-08-19 09:56:49 -0400532
Ethan Nicholase6592142020-09-08 10:22:09 -0400533 case Expression::Kind::kConstructor: {
John Stiles9d944232020-08-19 09:56:49 -0400534 const Constructor& constructor = expr.as<Constructor>();
535 if (constructor.isCompileTimeConstant()) {
Ethan Nicholas30d30222020-09-11 12:27:26 -0400536 const Type& constructorType = constructor.type();
Ethan Nicholas30d30222020-09-11 12:27:26 -0400537 switch (constructorType.typeKind()) {
Ethan Nicholase6592142020-09-08 10:22:09 -0400538 case Type::TypeKind::kVector:
John Stilesbc75ebb2020-11-24 12:04:47 -0500539 if (constructor.componentType().isFloat()) {
540 for (int i = 0; i < constructorType.columns(); ++i) {
John Stiles9d944232020-08-19 09:56:49 -0400541 if (constructor.getFVecComponent(i) != value) {
542 return false;
543 }
John Stilesbc75ebb2020-11-24 12:04:47 -0500544 }
545 return true;
546 } else if (constructor.componentType().isInteger()) {
547 for (int i = 0; i < constructorType.columns(); ++i) {
John Stiles9d944232020-08-19 09:56:49 -0400548 if (constructor.getIVecComponent(i) != value) {
549 return false;
550 }
551 }
John Stilesbc75ebb2020-11-24 12:04:47 -0500552 return true;
Ethan Nicholasd188c182019-06-10 15:55:38 -0400553 }
John Stilesbc75ebb2020-11-24 12:04:47 -0500554 // Other types (e.g. boolean) might occur, but aren't supported here.
555 return false;
John Stiles9d944232020-08-19 09:56:49 -0400556
Ethan Nicholase6592142020-09-08 10:22:09 -0400557 case Type::TypeKind::kScalar:
Ethan Nicholasf70f0442020-09-29 12:41:35 -0400558 SkASSERT(constructor.arguments().size() == 1);
559 return is_constant<T>(*constructor.arguments()[0], value);
John Stiles9d944232020-08-19 09:56:49 -0400560
561 default:
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400562 return false;
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400563 }
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400564 }
565 return false;
566 }
Ethan Nicholascb670962017-04-20 19:31:52 -0400567 default:
568 return false;
569 }
570}
571
572/**
573 * Collapses the binary expression pointed to by iter down to just the right side (in both the IR
574 * and CFG structures).
575 */
John Stilesafbf8992020-08-18 10:08:21 -0400576static void delete_left(BasicBlock* b,
577 std::vector<BasicBlock::Node>::iterator* iter,
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400578 Compiler::OptimizationContext* optimizationContext) {
579 optimizationContext->fUpdated = true;
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400580 std::unique_ptr<Expression>* target = (*iter)->expression();
John Stilesa5a97b42020-08-18 11:19:07 -0400581 BinaryExpression& bin = (*target)->as<BinaryExpression>();
John Stiles2d4f9592020-10-30 10:29:12 -0400582 Expression& left = *bin.left();
583 std::unique_ptr<Expression>& rightPointer = bin.right();
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400584 SkASSERT(!left.hasSideEffects());
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400585 bool result;
John Stiles45990502021-02-16 10:55:27 -0500586 if (bin.getOperator().kind() == Token::Kind::TK_EQ) {
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400587 result = b->tryRemoveLValueBefore(iter, &left);
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400588 } else {
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400589 result = b->tryRemoveExpressionBefore(iter, &left);
Ethan Nicholascb670962017-04-20 19:31:52 -0400590 }
Brian Osman010ce6a2020-10-19 16:34:10 -0400591 // Remove references within LHS.
592 optimizationContext->fUsage->remove(&left);
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400593 *target = std::move(rightPointer);
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400594 if (!result) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400595 optimizationContext->fNeedsRescan = true;
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400596 return;
597 }
598 if (*iter == b->fNodes.begin()) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400599 optimizationContext->fNeedsRescan = true;
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400600 return;
601 }
602 --(*iter);
John Stiles70025e52020-09-28 16:08:58 -0400603 if (!(*iter)->isExpression() || (*iter)->expression() != &rightPointer) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400604 optimizationContext->fNeedsRescan = true;
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400605 return;
606 }
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400607 *iter = b->fNodes.erase(*iter);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400608 SkASSERT((*iter)->expression() == target);
Ethan Nicholascb670962017-04-20 19:31:52 -0400609}
610
611/**
612 * Collapses the binary expression pointed to by iter down to just the left side (in both the IR and
613 * CFG structures).
614 */
John Stilesafbf8992020-08-18 10:08:21 -0400615static void delete_right(BasicBlock* b,
616 std::vector<BasicBlock::Node>::iterator* iter,
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400617 Compiler::OptimizationContext* optimizationContext) {
618 optimizationContext->fUpdated = true;
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400619 std::unique_ptr<Expression>* target = (*iter)->expression();
John Stilesa5a97b42020-08-18 11:19:07 -0400620 BinaryExpression& bin = (*target)->as<BinaryExpression>();
John Stiles2d4f9592020-10-30 10:29:12 -0400621 std::unique_ptr<Expression>& leftPointer = bin.left();
622 Expression& right = *bin.right();
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400623 SkASSERT(!right.hasSideEffects());
Brian Osman010ce6a2020-10-19 16:34:10 -0400624 // Remove references within RHS.
625 optimizationContext->fUsage->remove(&right);
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400626 if (!b->tryRemoveExpressionBefore(iter, &right)) {
627 *target = std::move(leftPointer);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400628 optimizationContext->fNeedsRescan = true;
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400629 return;
Ethan Nicholascb670962017-04-20 19:31:52 -0400630 }
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400631 *target = std::move(leftPointer);
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400632 if (*iter == b->fNodes.begin()) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400633 optimizationContext->fNeedsRescan = true;
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400634 return;
635 }
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400636 --(*iter);
John Stiles70025e52020-09-28 16:08:58 -0400637 if ((!(*iter)->isExpression() || (*iter)->expression() != &leftPointer)) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400638 optimizationContext->fNeedsRescan = true;
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400639 return;
640 }
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400641 *iter = b->fNodes.erase(*iter);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400642 SkASSERT((*iter)->expression() == target);
Ethan Nicholascb670962017-04-20 19:31:52 -0400643}
644
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400645/**
646 * Constructs the specified type using a single argument.
647 */
Ethan Nicholas30d30222020-09-11 12:27:26 -0400648static std::unique_ptr<Expression> construct(const Type* type, std::unique_ptr<Expression> v) {
John Stiles8e3b6be2020-10-13 11:14:08 -0400649 ExpressionArray args;
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400650 args.push_back(std::move(v));
John Stiles54f00492021-02-19 11:46:10 -0500651 return std::make_unique<Constructor>(/*offset=*/-1, *type, std::move(args));
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400652}
653
654/**
655 * Used in the implementations of vectorize_left and vectorize_right. Given a vector type and an
656 * expression x, deletes the expression pointed to by iter and replaces it with <type>(x).
657 */
658static void vectorize(BasicBlock* b,
659 std::vector<BasicBlock::Node>::iterator* iter,
660 const Type& type,
661 std::unique_ptr<Expression>* otherExpression,
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400662 Compiler::OptimizationContext* optimizationContext) {
Ethan Nicholase6592142020-09-08 10:22:09 -0400663 SkASSERT((*(*iter)->expression())->kind() == Expression::Kind::kBinary);
John Stiles9aeed132020-11-24 17:36:06 -0500664 SkASSERT(type.isVector());
665 SkASSERT((*otherExpression)->type().isScalar());
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400666 optimizationContext->fUpdated = true;
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400667 std::unique_ptr<Expression>* target = (*iter)->expression();
668 if (!b->tryRemoveExpression(iter)) {
Ethan Nicholas30d30222020-09-11 12:27:26 -0400669 *target = construct(&type, std::move(*otherExpression));
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400670 optimizationContext->fNeedsRescan = true;
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400671 } else {
Ethan Nicholas30d30222020-09-11 12:27:26 -0400672 *target = construct(&type, std::move(*otherExpression));
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400673 if (!b->tryInsertExpression(iter, target)) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400674 optimizationContext->fNeedsRescan = true;
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400675 }
676 }
677}
678
679/**
680 * Given a binary expression of the form x <op> vec<n>(y), deletes the right side and vectorizes the
681 * left to yield vec<n>(x).
682 */
683static void vectorize_left(BasicBlock* b,
684 std::vector<BasicBlock::Node>::iterator* iter,
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400685 Compiler::OptimizationContext* optimizationContext) {
John Stilesa5a97b42020-08-18 11:19:07 -0400686 BinaryExpression& bin = (*(*iter)->expression())->as<BinaryExpression>();
Brian Osman010ce6a2020-10-19 16:34:10 -0400687 // Remove references within RHS. Vectorization of LHS doesn't change reference counts.
John Stiles2d4f9592020-10-30 10:29:12 -0400688 optimizationContext->fUsage->remove(bin.right().get());
689 vectorize(b, iter, bin.right()->type(), &bin.left(), optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400690}
691
692/**
693 * Given a binary expression of the form vec<n>(x) <op> y, deletes the left side and vectorizes the
694 * right to yield vec<n>(y).
695 */
696static void vectorize_right(BasicBlock* b,
697 std::vector<BasicBlock::Node>::iterator* iter,
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400698 Compiler::OptimizationContext* optimizationContext) {
John Stilesa5a97b42020-08-18 11:19:07 -0400699 BinaryExpression& bin = (*(*iter)->expression())->as<BinaryExpression>();
Brian Osman010ce6a2020-10-19 16:34:10 -0400700 // Remove references within LHS. Vectorization of RHS doesn't change reference counts.
John Stiles2d4f9592020-10-30 10:29:12 -0400701 optimizationContext->fUsage->remove(bin.left().get());
702 vectorize(b, iter, bin.left()->type(), &bin.right(), optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400703}
704
Ethan Nicholascb670962017-04-20 19:31:52 -0400705void Compiler::simplifyExpression(DefinitionMap& definitions,
706 BasicBlock& b,
707 std::vector<BasicBlock::Node>::iterator* iter,
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400708 OptimizationContext* optimizationContext) {
Ethan Nicholascb670962017-04-20 19:31:52 -0400709 Expression* expr = (*iter)->expression()->get();
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400710 SkASSERT(expr);
John Stiles108bbe22020-11-18 11:10:38 -0500711
Ethan Nicholascb670962017-04-20 19:31:52 -0400712 if ((*iter)->fConstantPropagation) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400713 std::unique_ptr<Expression> optimized = expr->constantPropagate(*fIRGenerator,
714 definitions);
Ethan Nicholascb670962017-04-20 19:31:52 -0400715 if (optimized) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400716 optimizationContext->fUpdated = true;
Ethan Nicholas30d30222020-09-11 12:27:26 -0400717 optimized = fIRGenerator->coerce(std::move(optimized), expr->type());
Ethan Nicholas1d881522020-09-11 09:32:54 -0400718 SkASSERT(optimized);
Brian Osman010ce6a2020-10-19 16:34:10 -0400719 // Remove references within 'expr', add references within 'optimized'
720 optimizationContext->fUsage->replace(expr, optimized.get());
Ethan Nicholascb670962017-04-20 19:31:52 -0400721 if (!try_replace_expression(&b, iter, &optimized)) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400722 optimizationContext->fNeedsRescan = true;
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400723 return;
Ethan Nicholascb670962017-04-20 19:31:52 -0400724 }
John Stiles70025e52020-09-28 16:08:58 -0400725 SkASSERT((*iter)->isExpression());
Ethan Nicholascb670962017-04-20 19:31:52 -0400726 expr = (*iter)->expression()->get();
Ethan Nicholascb670962017-04-20 19:31:52 -0400727 }
728 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400729 switch (expr->kind()) {
730 case Expression::Kind::kVariableReference: {
John Stilesa5a97b42020-08-18 11:19:07 -0400731 const VariableReference& ref = expr->as<VariableReference>();
Ethan Nicholas78686922020-10-08 06:46:27 -0400732 const Variable* var = ref.variable();
John Stiles66c53b92021-02-20 08:00:43 -0500733 if (fContext->fConfig->fSettings.fDeadCodeElimination &&
734 ref.refKind() != VariableReference::RefKind::kWrite &&
Ethan Nicholas453f67f2020-10-09 10:43:45 -0400735 ref.refKind() != VariableReference::RefKind::kPointer &&
John Stilese8a24922021-02-08 17:54:08 -0500736 var->storage() == Variable::Storage::kLocal && !definitions.get(var) &&
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400737 optimizationContext->fSilences.find(var) == optimizationContext->fSilences.end()) {
738 optimizationContext->fSilences.insert(var);
Ethan Nicholas82a62d22017-11-07 14:42:10 +0000739 this->error(expr->fOffset,
Ethan Nicholase2c49992020-10-05 11:49:11 -0400740 "'" + var->name() + "' has not been assigned");
Ethan Nicholascb670962017-04-20 19:31:52 -0400741 }
742 break;
743 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400744 case Expression::Kind::kTernary: {
John Stiles403a3632020-08-20 12:11:48 -0400745 TernaryExpression* t = &expr->as<TernaryExpression>();
Ethan Nicholasdd218162020-10-08 05:48:01 -0400746 if (t->test()->is<BoolLiteral>()) {
Ethan Nicholascb670962017-04-20 19:31:52 -0400747 // ternary has a constant test, replace it with either the true or
748 // false branch
Ethan Nicholasdd218162020-10-08 05:48:01 -0400749 if (t->test()->as<BoolLiteral>().value()) {
Brian Osman010ce6a2020-10-19 16:34:10 -0400750 (*iter)->setExpression(std::move(t->ifTrue()), optimizationContext->fUsage);
Ethan Nicholascb670962017-04-20 19:31:52 -0400751 } else {
Brian Osman010ce6a2020-10-19 16:34:10 -0400752 (*iter)->setExpression(std::move(t->ifFalse()), optimizationContext->fUsage);
Ethan Nicholascb670962017-04-20 19:31:52 -0400753 }
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400754 optimizationContext->fUpdated = true;
755 optimizationContext->fNeedsRescan = true;
Ethan Nicholascb670962017-04-20 19:31:52 -0400756 }
757 break;
758 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400759 case Expression::Kind::kBinary: {
John Stiles403a3632020-08-20 12:11:48 -0400760 BinaryExpression* bin = &expr->as<BinaryExpression>();
John Stiles0ac6c152021-02-10 14:04:24 -0500761 if (dead_assignment(*bin, optimizationContext->fUsage) || self_assignment(*bin)) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400762 delete_left(&b, iter, optimizationContext);
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400763 break;
764 }
John Stiles2d4f9592020-10-30 10:29:12 -0400765 Expression& left = *bin->left();
766 Expression& right = *bin->right();
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400767 const Type& leftType = left.type();
768 const Type& rightType = right.type();
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400769 // collapse useless expressions like x * 1 or x + 0
John Stiles9aeed132020-11-24 17:36:06 -0500770 if ((!leftType.isScalar() && !leftType.isVector()) ||
771 (!rightType.isScalar() && !rightType.isVector())) {
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400772 break;
773 }
John Stiles45990502021-02-16 10:55:27 -0500774 switch (bin->getOperator().kind()) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400775 case Token::Kind::TK_STAR:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400776 if (is_constant(left, 1)) {
John Stiles9aeed132020-11-24 17:36:06 -0500777 if (leftType.isVector() && rightType.isScalar()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400778 // float4(1) * x -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400779 vectorize_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400780 } else {
781 // 1 * x -> x
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400782 // 1 * float4(x) -> float4(x)
783 // float4(1) * float4(x) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400784 delete_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400785 }
786 }
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400787 else if (is_constant(left, 0)) {
John Stiles9aeed132020-11-24 17:36:06 -0500788 if (leftType.isScalar() && rightType.isVector() &&
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400789 !right.hasSideEffects()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400790 // 0 * float4(x) -> float4(0)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400791 vectorize_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400792 } else {
793 // 0 * x -> 0
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400794 // float4(0) * x -> float4(0)
795 // float4(0) * float4(x) -> float4(0)
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400796 if (!right.hasSideEffects()) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400797 delete_right(&b, iter, optimizationContext);
Ethan Nicholas51493ee2017-12-11 12:34:33 -0500798 }
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400799 }
Ethan Nicholascb670962017-04-20 19:31:52 -0400800 }
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400801 else if (is_constant(right, 1)) {
John Stiles9aeed132020-11-24 17:36:06 -0500802 if (leftType.isScalar() && rightType.isVector()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400803 // x * float4(1) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400804 vectorize_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400805 } else {
806 // x * 1 -> x
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400807 // float4(x) * 1 -> float4(x)
808 // float4(x) * float4(1) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400809 delete_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400810 }
811 }
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400812 else if (is_constant(right, 0)) {
John Stiles9aeed132020-11-24 17:36:06 -0500813 if (leftType.isVector() && rightType.isScalar() && !left.hasSideEffects()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400814 // float4(x) * 0 -> float4(0)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400815 vectorize_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400816 } else {
817 // x * 0 -> 0
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400818 // x * float4(0) -> float4(0)
819 // float4(x) * float4(0) -> float4(0)
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400820 if (!left.hasSideEffects()) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400821 delete_left(&b, iter, optimizationContext);
Ethan Nicholas51493ee2017-12-11 12:34:33 -0500822 }
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400823 }
Ethan Nicholascb670962017-04-20 19:31:52 -0400824 }
825 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400826 case Token::Kind::TK_PLUS:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400827 if (is_constant(left, 0)) {
John Stiles9aeed132020-11-24 17:36:06 -0500828 if (leftType.isVector() && rightType.isScalar()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400829 // float4(0) + x -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400830 vectorize_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400831 } else {
832 // 0 + x -> x
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400833 // 0 + float4(x) -> float4(x)
834 // float4(0) + float4(x) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400835 delete_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400836 }
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400837 } else if (is_constant(right, 0)) {
John Stiles9aeed132020-11-24 17:36:06 -0500838 if (leftType.isScalar() && rightType.isVector()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400839 // x + float4(0) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400840 vectorize_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400841 } else {
842 // x + 0 -> x
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400843 // float4(x) + 0 -> float4(x)
844 // float4(x) + float4(0) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400845 delete_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400846 }
Ethan Nicholas56e42712017-04-21 10:23:37 -0400847 }
848 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400849 case Token::Kind::TK_MINUS:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400850 if (is_constant(right, 0)) {
John Stiles9aeed132020-11-24 17:36:06 -0500851 if (leftType.isScalar() && rightType.isVector()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400852 // x - float4(0) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400853 vectorize_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400854 } else {
855 // x - 0 -> x
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400856 // float4(x) - 0 -> float4(x)
857 // float4(x) - float4(0) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400858 delete_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400859 }
Ethan Nicholascb670962017-04-20 19:31:52 -0400860 }
861 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400862 case Token::Kind::TK_SLASH:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400863 if (is_constant(right, 1)) {
John Stiles9aeed132020-11-24 17:36:06 -0500864 if (leftType.isScalar() && rightType.isVector()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400865 // x / float4(1) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400866 vectorize_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400867 } else {
868 // x / 1 -> x
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400869 // float4(x) / 1 -> float4(x)
870 // float4(x) / float4(1) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400871 delete_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400872 }
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400873 } else if (is_constant(left, 0)) {
John Stiles9aeed132020-11-24 17:36:06 -0500874 if (leftType.isScalar() && rightType.isVector() &&
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400875 !right.hasSideEffects()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400876 // 0 / float4(x) -> float4(0)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400877 vectorize_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400878 } else {
879 // 0 / x -> 0
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400880 // float4(0) / x -> float4(0)
881 // float4(0) / float4(x) -> float4(0)
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400882 if (!right.hasSideEffects()) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400883 delete_right(&b, iter, optimizationContext);
Ethan Nicholas51493ee2017-12-11 12:34:33 -0500884 }
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400885 }
886 }
887 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400888 case Token::Kind::TK_PLUSEQ:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400889 if (is_constant(right, 0)) {
John Stiles47c0a742021-02-09 09:30:35 -0500890 Analysis::UpdateRefKind(&left, RefKind::kRead);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400891 delete_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400892 }
893 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400894 case Token::Kind::TK_MINUSEQ:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400895 if (is_constant(right, 0)) {
John Stiles47c0a742021-02-09 09:30:35 -0500896 Analysis::UpdateRefKind(&left, RefKind::kRead);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400897 delete_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400898 }
899 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400900 case Token::Kind::TK_STAREQ:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400901 if (is_constant(right, 1)) {
John Stiles47c0a742021-02-09 09:30:35 -0500902 Analysis::UpdateRefKind(&left, RefKind::kRead);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400903 delete_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400904 }
905 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400906 case Token::Kind::TK_SLASHEQ:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400907 if (is_constant(right, 1)) {
John Stiles47c0a742021-02-09 09:30:35 -0500908 Analysis::UpdateRefKind(&left, RefKind::kRead);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400909 delete_right(&b, iter, optimizationContext);
Ethan Nicholascb670962017-04-20 19:31:52 -0400910 }
911 break;
912 default:
913 break;
914 }
Ethan Nicholas409f6f02019-09-17 12:34:39 -0400915 break;
916 }
John Stilesf5c1d042020-11-21 23:26:07 -0500917 case Expression::Kind::kConstructor: {
918 // Find constructors embedded inside constructors and flatten them out where possible.
919 // - float4(float2(1, 2), 3, 4) --> float4(1, 2, 3, 4)
920 // - float4(w, float3(sin(x), cos(y), tan(z))) --> float4(w, sin(x), cos(y), tan(z))
921 // Leave single-argument constructors alone, though. These might be casts or splats.
922 Constructor& c = expr->as<Constructor>();
923 if (c.type().columns() > 1) {
924 // Inspect each constructor argument to see if it's a candidate for flattening.
925 // Remember matched arguments in a bitfield, "argsToOptimize".
926 int argsToOptimize = 0;
927 int currBit = 1;
928 for (const std::unique_ptr<Expression>& arg : c.arguments()) {
929 if (arg->is<Constructor>()) {
930 Constructor& inner = arg->as<Constructor>();
931 if (inner.arguments().size() > 1 &&
932 inner.type().componentType() == c.type().componentType()) {
933 argsToOptimize |= currBit;
934 }
935 }
936 currBit <<= 1;
937 }
938 if (argsToOptimize) {
939 // We found at least one argument that could be flattened out. Re-walk the
940 // constructor args and flatten the candidates we found during our initial pass.
941 ExpressionArray flattened;
942 flattened.reserve_back(c.type().columns());
943 currBit = 1;
944 for (const std::unique_ptr<Expression>& arg : c.arguments()) {
945 if (argsToOptimize & currBit) {
946 Constructor& inner = arg->as<Constructor>();
947 for (const std::unique_ptr<Expression>& innerArg : inner.arguments()) {
948 flattened.push_back(innerArg->clone());
949 }
950 } else {
951 flattened.push_back(arg->clone());
952 }
953 currBit <<= 1;
954 }
John Stiles54f00492021-02-19 11:46:10 -0500955 std::unique_ptr<Expression> replacement = std::make_unique<Constructor>(
956 c.fOffset, c.type(), std::move(flattened));
John Stiles1b91c0e2021-02-11 11:43:09 -0500957 // We're replacing an expression with a cloned version; we'll need a rescan.
958 // No fUsage change: `float2(float(x), y)` and `float2(x, y)` have equivalent
959 // reference counts.
960 try_replace_expression(&b, iter, &replacement);
John Stilesf5c1d042020-11-21 23:26:07 -0500961 optimizationContext->fUpdated = true;
John Stiles1b91c0e2021-02-11 11:43:09 -0500962 optimizationContext->fNeedsRescan = true;
John Stilesf5c1d042020-11-21 23:26:07 -0500963 break;
964 }
965 }
966 break;
967 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400968 case Expression::Kind::kSwizzle: {
John Stiles403a3632020-08-20 12:11:48 -0400969 Swizzle& s = expr->as<Swizzle>();
John Stiles108bbe22020-11-18 11:10:38 -0500970 // Detect identity swizzles like `foo.rgba`.
Ethan Nicholas6b4d5812020-10-12 16:11:51 -0400971 if ((int) s.components().size() == s.base()->type().columns()) {
Ethan Nicholas409f6f02019-09-17 12:34:39 -0400972 bool identity = true;
Ethan Nicholas6b4d5812020-10-12 16:11:51 -0400973 for (int i = 0; i < (int) s.components().size(); ++i) {
974 if (s.components()[i] != i) {
Ethan Nicholas409f6f02019-09-17 12:34:39 -0400975 identity = false;
976 break;
977 }
978 }
979 if (identity) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400980 optimizationContext->fUpdated = true;
Brian Osman010ce6a2020-10-19 16:34:10 -0400981 // No fUsage change: foo.rgba and foo have equivalent reference counts
Ethan Nicholas6b4d5812020-10-12 16:11:51 -0400982 if (!try_replace_expression(&b, iter, &s.base())) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400983 optimizationContext->fNeedsRescan = true;
Ethan Nicholas409f6f02019-09-17 12:34:39 -0400984 return;
985 }
John Stiles70025e52020-09-28 16:08:58 -0400986 SkASSERT((*iter)->isExpression());
Ethan Nicholas409f6f02019-09-17 12:34:39 -0400987 break;
988 }
989 }
John Stiles108bbe22020-11-18 11:10:38 -0500990 // Detect swizzles of swizzles, e.g. replace `foo.argb.r000` with `foo.a000`.
991 if (s.base()->is<Swizzle>()) {
Ethan Nicholas6b4d5812020-10-12 16:11:51 -0400992 Swizzle& base = s.base()->as<Swizzle>();
John Stiles750109b2020-10-30 13:45:46 -0400993 ComponentArray final;
Ethan Nicholas6b4d5812020-10-12 16:11:51 -0400994 for (int c : s.components()) {
995 final.push_back(base.components()[c]);
Ethan Nicholas409f6f02019-09-17 12:34:39 -0400996 }
Ethan Nicholas6b4d5812020-10-12 16:11:51 -0400997 std::unique_ptr<Expression> replacement(new Swizzle(*fContext, base.base()->clone(),
John Stiles750109b2020-10-30 13:45:46 -0400998 final));
John Stilesd2f51b12021-01-07 18:12:31 -0500999 // We're replacing an expression with a cloned version; we'll need a rescan.
John Stiles108bbe22020-11-18 11:10:38 -05001000 // No fUsage change: `foo.gbr.gbr` and `foo.brg` have equivalent reference counts
John Stilesd2f51b12021-01-07 18:12:31 -05001001 try_replace_expression(&b, iter, &replacement);
1002 optimizationContext->fUpdated = true;
1003 optimizationContext->fNeedsRescan = true;
John Stiles108bbe22020-11-18 11:10:38 -05001004 break;
1005 }
1006 // Optimize swizzles of constructors.
1007 if (s.base()->is<Constructor>()) {
1008 Constructor& base = s.base()->as<Constructor>();
1009 std::unique_ptr<Expression> replacement;
1010 const Type& componentType = base.type().componentType();
1011 int swizzleSize = s.components().size();
1012
1013 // The IR generator has already converted any zero/one swizzle components into
1014 // constructors containing zero/one args. Confirm that this is true by checking that
1015 // our swizzle components are all `xyzw` (values 0 through 3).
1016 SkASSERT(std::all_of(s.components().begin(), s.components().end(),
1017 [](int8_t c) { return c >= 0 && c <= 3; }));
1018
John Stiles9aeed132020-11-24 17:36:06 -05001019 if (base.arguments().size() == 1 && base.arguments().front()->type().isScalar()) {
John Stiles108bbe22020-11-18 11:10:38 -05001020 // `half4(scalar).zyy` can be optimized to `half3(scalar)`. The swizzle
1021 // components don't actually matter since all fields are the same.
John Stilesf0cb7332021-01-08 18:39:00 -05001022 const Expression& argument = *base.arguments().front();
1023 const Type& constructorType = componentType.toCompound(*fContext, swizzleSize,
1024 /*rows=*/1);
1025 replacement = Constructor::SimplifyConversion(constructorType, argument);
1026 if (!replacement) {
1027 ExpressionArray newArgs;
1028 newArgs.push_back(argument.clone());
John Stiles54f00492021-02-19 11:46:10 -05001029 replacement = std::make_unique<Constructor>(base.fOffset, constructorType,
John Stilesf0cb7332021-01-08 18:39:00 -05001030 std::move(newArgs));
1031 }
John Stiles108bbe22020-11-18 11:10:38 -05001032
John Stilesa60ac0c2020-12-22 08:59:51 -05001033 // We're replacing an expression with a cloned version; we'll need a rescan.
1034 // There's no fUsage change: `half4(foo).xy` and `half2(foo)` have equivalent
1035 // reference counts.
1036 try_replace_expression(&b, iter, &replacement);
John Stiles0777ac42020-11-19 11:06:47 -05001037 optimizationContext->fUpdated = true;
John Stilesa60ac0c2020-12-22 08:59:51 -05001038 optimizationContext->fNeedsRescan = true;
John Stiles108bbe22020-11-18 11:10:38 -05001039 break;
1040 }
1041
John Stiles0777ac42020-11-19 11:06:47 -05001042 // Swizzles can duplicate some elements and discard others, e.g.
1043 // `half4(1, 2, 3, 4).xxz` --> `half3(1, 1, 3)`. However, there are constraints:
1044 // - Expressions with side effects need to occur exactly once, even if they
1045 // would otherwise be swizzle-eliminated
1046 // - Non-trivial expressions should not be repeated, but elimination is OK.
1047 //
1048 // Look up the argument for the constructor at each index. This is typically simple
1049 // but for weird cases like `half4(bar.yz, half2(foo))`, it can be harder than it
1050 // seems. This example would result in:
1051 // argMap[0] = {.fArgIndex = 0, .fComponent = 0} (bar.yz .x)
1052 // argMap[1] = {.fArgIndex = 0, .fComponent = 1} (bar.yz .y)
1053 // argMap[2] = {.fArgIndex = 1, .fComponent = 0} (half2(foo) .x)
1054 // argMap[3] = {.fArgIndex = 1, .fComponent = 1} (half2(foo) .y)
1055 struct ConstructorArgMap {
1056 int8_t fArgIndex;
1057 int8_t fComponent;
1058 };
1059
1060 int numConstructorArgs = base.type().columns();
1061 ConstructorArgMap argMap[4] = {};
1062 int writeIdx = 0;
1063 for (int argIdx = 0; argIdx < (int) base.arguments().size(); ++argIdx) {
1064 const Expression& expr = *base.arguments()[argIdx];
1065 int argWidth = expr.type().columns();
1066 for (int componentIdx = 0; componentIdx < argWidth; ++componentIdx) {
1067 argMap[writeIdx].fArgIndex = argIdx;
1068 argMap[writeIdx].fComponent = componentIdx;
1069 ++writeIdx;
1070 }
1071 }
1072 SkASSERT(writeIdx == numConstructorArgs);
1073
1074 // Count up the number of times each constructor argument is used by the
1075 // swizzle.
1076 // `half4(bar.yz, half2(foo)).xwxy` -> { 3, 1 }
1077 // - bar.yz is referenced 3 times, by `.x_xy`
1078 // - half(foo) is referenced 1 time, by `._w__`
1079 int8_t exprUsed[4] = {};
1080 for (int c : s.components()) {
1081 exprUsed[argMap[c].fArgIndex]++;
1082 }
1083
1084 bool safeToOptimize = true;
1085 for (int index = 0; index < numConstructorArgs; ++index) {
1086 int8_t constructorArgIndex = argMap[index].fArgIndex;
1087 const Expression& baseArg = *base.arguments()[constructorArgIndex];
1088
1089 // Check that non-trivial expressions are not swizzled in more than once.
John Stilesc30fbca2020-11-19 16:25:49 -05001090 if (exprUsed[constructorArgIndex] > 1 &&
1091 !Analysis::IsTrivialExpression(baseArg)) {
John Stiles0777ac42020-11-19 11:06:47 -05001092 safeToOptimize = false;
1093 break;
1094 }
1095 // Check that side-effect-bearing expressions are swizzled in exactly once.
1096 if (exprUsed[constructorArgIndex] != 1 && baseArg.hasSideEffects()) {
1097 safeToOptimize = false;
1098 break;
1099 }
1100 }
1101
1102 if (safeToOptimize) {
John Stilesd9076cb2020-11-19 12:18:36 -05001103 struct ReorderedArgument {
1104 int8_t fArgIndex;
1105 ComponentArray fComponents;
1106 };
1107 SkSTArray<4, ReorderedArgument> reorderedArgs;
John Stiles0777ac42020-11-19 11:06:47 -05001108 for (int c : s.components()) {
1109 const ConstructorArgMap& argument = argMap[c];
1110 const Expression& baseArg = *base.arguments()[argument.fArgIndex];
1111
John Stiles9aeed132020-11-24 17:36:06 -05001112 if (baseArg.type().isScalar()) {
John Stilesd9076cb2020-11-19 12:18:36 -05001113 // This argument is a scalar; add it to the list as-is.
John Stiles0777ac42020-11-19 11:06:47 -05001114 SkASSERT(argument.fComponent == 0);
John Stilesd9076cb2020-11-19 12:18:36 -05001115 reorderedArgs.push_back({argument.fArgIndex,
1116 ComponentArray{}});
John Stiles0777ac42020-11-19 11:06:47 -05001117 } else {
John Stilesd9076cb2020-11-19 12:18:36 -05001118 // This argument is a component from a vector.
John Stiles0777ac42020-11-19 11:06:47 -05001119 SkASSERT(argument.fComponent < baseArg.type().columns());
John Stilesd9076cb2020-11-19 12:18:36 -05001120 if (reorderedArgs.empty() ||
1121 reorderedArgs.back().fArgIndex != argument.fArgIndex) {
1122 // This can't be combined with the previous argument. Add a new one.
1123 reorderedArgs.push_back({argument.fArgIndex,
1124 ComponentArray{argument.fComponent}});
1125 } else {
1126 // Since we know this argument uses components, it should already
1127 // have at least one component set.
1128 SkASSERT(!reorderedArgs.back().fComponents.empty());
1129 // Build up the current argument with one more component.
1130 reorderedArgs.back().fComponents.push_back(argument.fComponent);
1131 }
John Stiles0777ac42020-11-19 11:06:47 -05001132 }
1133 }
John Stilesd9076cb2020-11-19 12:18:36 -05001134
1135 // Convert our reordered argument list to an actual array of expressions, with
1136 // the new order and any new inner swizzles that need to be applied. Note that
1137 // we expect followup passes to clean up the inner swizzles.
1138 ExpressionArray newArgs;
1139 newArgs.reserve_back(swizzleSize);
1140 for (const ReorderedArgument& reorderedArg : reorderedArgs) {
1141 const Expression& baseArg = *base.arguments()[reorderedArg.fArgIndex];
1142 if (reorderedArg.fComponents.empty()) {
1143 newArgs.push_back(baseArg.clone());
1144 } else {
1145 newArgs.push_back(std::make_unique<Swizzle>(*fContext, baseArg.clone(),
1146 reorderedArg.fComponents));
1147 }
1148 }
1149
1150 // Create a new constructor.
John Stiles0777ac42020-11-19 11:06:47 -05001151 replacement = std::make_unique<Constructor>(
1152 base.fOffset,
John Stiles54f00492021-02-19 11:46:10 -05001153 componentType.toCompound(*fContext, swizzleSize, /*rows=*/1),
John Stiles0777ac42020-11-19 11:06:47 -05001154 std::move(newArgs));
1155
John Stilesa60ac0c2020-12-22 08:59:51 -05001156 // Remove references within 'expr', add references within 'replacement.'
John Stiles0777ac42020-11-19 11:06:47 -05001157 optimizationContext->fUsage->replace(expr, replacement.get());
John Stilesa60ac0c2020-12-22 08:59:51 -05001158
1159 // We're replacing an expression with a cloned version; we'll need a rescan.
1160 try_replace_expression(&b, iter, &replacement);
1161 optimizationContext->fUpdated = true;
1162 optimizationContext->fNeedsRescan = true;
John Stiles0777ac42020-11-19 11:06:47 -05001163 }
John Stiles108bbe22020-11-18 11:10:38 -05001164 break;
Ethan Nicholas409f6f02019-09-17 12:34:39 -04001165 }
John Stiles30212b72020-06-11 17:55:07 -04001166 break;
Ethan Nicholascb670962017-04-20 19:31:52 -04001167 }
1168 default:
1169 break;
1170 }
1171}
1172
1173void Compiler::simplifyStatement(DefinitionMap& definitions,
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001174 BasicBlock& b,
1175 std::vector<BasicBlock::Node>::iterator* iter,
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001176 OptimizationContext* optimizationContext) {
Brian Osman010ce6a2020-10-19 16:34:10 -04001177 ProgramUsage* usage = optimizationContext->fUsage;
Ethan Nicholascb670962017-04-20 19:31:52 -04001178 Statement* stmt = (*iter)->statement()->get();
Ethan Nicholase6592142020-09-08 10:22:09 -04001179 switch (stmt->kind()) {
1180 case Statement::Kind::kVarDeclaration: {
John Stilesa5a97b42020-08-18 11:19:07 -04001181 const auto& varDecl = stmt->as<VarDeclaration>();
Brian Osman010ce6a2020-10-19 16:34:10 -04001182 if (usage->isDead(varDecl.var()) &&
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04001183 (!varDecl.value() ||
1184 !varDecl.value()->hasSideEffects())) {
1185 if (varDecl.value()) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001186 SkASSERT((*iter)->statement()->get() == stmt);
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04001187 if (!b.tryRemoveExpressionBefore(iter, varDecl.value().get())) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001188 optimizationContext->fNeedsRescan = true;
Ethan Nicholascb670962017-04-20 19:31:52 -04001189 }
Ethan Nicholascb670962017-04-20 19:31:52 -04001190 }
Ethan Nicholas5b9b0db2021-01-21 13:12:01 -05001191 // There can still be (soon to be removed) references to the variable at this point.
1192 // Allowing the VarDeclaration to be destroyed here will break those variable's
1193 // initialValue()s, so we hang on to them until optimization is finished.
1194 std::unique_ptr<Statement> old = (*iter)->setStatement(std::make_unique<Nop>(),
1195 usage);
1196 optimizationContext->fOwnedStatements.push_back(std::move(old));
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001197 optimizationContext->fUpdated = true;
Ethan Nicholascb670962017-04-20 19:31:52 -04001198 }
1199 break;
1200 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001201 case Statement::Kind::kIf: {
John Stilesa5a97b42020-08-18 11:19:07 -04001202 IfStatement& i = stmt->as<IfStatement>();
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001203 if (i.test()->kind() == Expression::Kind::kBoolLiteral) {
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001204 // constant if, collapse down to a single branch
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001205 if (i.test()->as<BoolLiteral>().value()) {
1206 SkASSERT(i.ifTrue());
Brian Osman010ce6a2020-10-19 16:34:10 -04001207 (*iter)->setStatement(std::move(i.ifTrue()), usage);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001208 } else {
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001209 if (i.ifFalse()) {
Brian Osman010ce6a2020-10-19 16:34:10 -04001210 (*iter)->setStatement(std::move(i.ifFalse()), usage);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001211 } else {
Brian Osman010ce6a2020-10-19 16:34:10 -04001212 (*iter)->setStatement(std::make_unique<Nop>(), usage);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001213 }
1214 }
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001215 optimizationContext->fUpdated = true;
1216 optimizationContext->fNeedsRescan = true;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001217 break;
1218 }
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001219 if (i.ifFalse() && i.ifFalse()->isEmpty()) {
Ethan Nicholascb670962017-04-20 19:31:52 -04001220 // else block doesn't do anything, remove it
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001221 i.ifFalse().reset();
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001222 optimizationContext->fUpdated = true;
1223 optimizationContext->fNeedsRescan = true;
Ethan Nicholascb670962017-04-20 19:31:52 -04001224 }
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001225 if (!i.ifFalse() && i.ifTrue()->isEmpty()) {
Ethan Nicholascb670962017-04-20 19:31:52 -04001226 // if block doesn't do anything, no else block
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001227 if (i.test()->hasSideEffects()) {
Ethan Nicholascb670962017-04-20 19:31:52 -04001228 // test has side effects, keep it
Brian Osman010ce6a2020-10-19 16:34:10 -04001229 (*iter)->setStatement(
1230 std::make_unique<ExpressionStatement>(std::move(i.test())), usage);
Ethan Nicholascb670962017-04-20 19:31:52 -04001231 } else {
1232 // no if, no else, no test side effects, kill the whole if
1233 // statement
Brian Osman010ce6a2020-10-19 16:34:10 -04001234 (*iter)->setStatement(std::make_unique<Nop>(), usage);
Ethan Nicholascb670962017-04-20 19:31:52 -04001235 }
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001236 optimizationContext->fUpdated = true;
1237 optimizationContext->fNeedsRescan = true;
Ethan Nicholascb670962017-04-20 19:31:52 -04001238 }
1239 break;
1240 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001241 case Statement::Kind::kSwitch: {
John Stiles642cde22021-02-23 14:57:01 -05001242 // TODO(skia:11319): this optimization logic is redundant with the static-switch
1243 // optimization code found in SwitchStatement.cpp.
John Stilesa5a97b42020-08-18 11:19:07 -04001244 SwitchStatement& s = stmt->as<SwitchStatement>();
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001245 int64_t switchValue;
Ethan Nicholasc0f98152021-02-05 16:21:10 -05001246 if (ConstantFolder::GetConstantInt(*s.value(), &switchValue)) {
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001247 // switch is constant, replace it with the case that matches
1248 bool found = false;
1249 SwitchCase* defaultCase = nullptr;
John Stiles2d4f9592020-10-30 10:29:12 -04001250 for (const std::unique_ptr<SwitchCase>& c : s.cases()) {
1251 if (!c->value()) {
1252 defaultCase = c.get();
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001253 continue;
1254 }
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001255 int64_t caseValue;
Ethan Nicholasc0f98152021-02-05 16:21:10 -05001256 SkAssertResult(ConstantFolder::GetConstantInt(*c->value(), &caseValue));
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001257 if (caseValue == switchValue) {
John Stiles642cde22021-02-23 14:57:01 -05001258 std::unique_ptr<Statement> newBlock =
1259 SwitchStatement::BlockForCase(&s.cases(), c.get(), s.symbols());
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001260 if (newBlock) {
Brian Osman010ce6a2020-10-19 16:34:10 -04001261 (*iter)->setStatement(std::move(newBlock), usage);
John Stiles9d944232020-08-19 09:56:49 -04001262 found = true;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001263 break;
1264 } else {
John Stilesd6a5f4492021-02-11 15:46:11 -05001265 if (s.isStatic() &&
John Stilesd1204642021-02-17 16:30:02 -05001266 !fContext->fConfig->fSettings.fPermitInvalidStaticTests) {
John Stilesd6a5f4492021-02-11 15:46:11 -05001267 auto [iter, didInsert] = optimizationContext->fSilences.insert(&s);
1268 if (didInsert) {
1269 this->error(s.fOffset, "static switch contains non-static "
John Stiles04ca41a2021-02-23 09:58:04 -05001270 "conditional exit");
John Stilesd6a5f4492021-02-11 15:46:11 -05001271 }
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001272 }
1273 return; // can't simplify
1274 }
1275 }
1276 }
1277 if (!found) {
1278 // no matching case. use default if it exists, or kill the whole thing
1279 if (defaultCase) {
John Stiles642cde22021-02-23 14:57:01 -05001280 std::unique_ptr<Statement> newBlock =
1281 SwitchStatement::BlockForCase(&s.cases(), defaultCase, s.symbols());
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001282 if (newBlock) {
Brian Osman010ce6a2020-10-19 16:34:10 -04001283 (*iter)->setStatement(std::move(newBlock), usage);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001284 } else {
John Stilesd6a5f4492021-02-11 15:46:11 -05001285 if (s.isStatic() &&
John Stilesd1204642021-02-17 16:30:02 -05001286 !fContext->fConfig->fSettings.fPermitInvalidStaticTests) {
John Stilesd6a5f4492021-02-11 15:46:11 -05001287 auto [iter, didInsert] = optimizationContext->fSilences.insert(&s);
1288 if (didInsert) {
1289 this->error(s.fOffset, "static switch contains non-static "
John Stiles04ca41a2021-02-23 09:58:04 -05001290 "conditional exit");
John Stilesd6a5f4492021-02-11 15:46:11 -05001291 }
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001292 }
1293 return; // can't simplify
1294 }
1295 } else {
Brian Osman010ce6a2020-10-19 16:34:10 -04001296 (*iter)->setStatement(std::make_unique<Nop>(), usage);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001297 }
1298 }
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001299 optimizationContext->fUpdated = true;
1300 optimizationContext->fNeedsRescan = true;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001301 }
1302 break;
1303 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001304 case Statement::Kind::kExpression: {
John Stilesa5a97b42020-08-18 11:19:07 -04001305 ExpressionStatement& e = stmt->as<ExpressionStatement>();
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001306 SkASSERT((*iter)->statement()->get() == &e);
Ethan Nicholasd503a5a2020-09-30 09:29:55 -04001307 if (!e.expression()->hasSideEffects()) {
Ethan Nicholascb670962017-04-20 19:31:52 -04001308 // Expression statement with no side effects, kill it
Ethan Nicholasd503a5a2020-09-30 09:29:55 -04001309 if (!b.tryRemoveExpressionBefore(iter, e.expression().get())) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001310 optimizationContext->fNeedsRescan = true;
Ethan Nicholascb670962017-04-20 19:31:52 -04001311 }
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001312 SkASSERT((*iter)->statement()->get() == stmt);
Brian Osman010ce6a2020-10-19 16:34:10 -04001313 (*iter)->setStatement(std::make_unique<Nop>(), usage);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001314 optimizationContext->fUpdated = true;
Ethan Nicholascb670962017-04-20 19:31:52 -04001315 }
1316 break;
1317 }
1318 default:
1319 break;
1320 }
1321}
1322
Brian Osman010ce6a2020-10-19 16:34:10 -04001323bool Compiler::scanCFG(FunctionDefinition& f, ProgramUsage* usage) {
John Stiles0cc193a2020-09-09 09:39:34 -04001324 bool madeChanges = false;
1325
Ethan Nicholascb670962017-04-20 19:31:52 -04001326 CFG cfg = CFGGenerator().getCFG(f);
1327 this->computeDataFlow(&cfg);
ethannicholas22f939e2016-10-13 13:25:34 -07001328
John Stiles66c53b92021-02-20 08:00:43 -05001329 if (fContext->fConfig->fSettings.fDeadCodeElimination) {
1330 // Check for unreachable code.
1331 for (size_t i = 0; i < cfg.fBlocks.size(); i++) {
1332 const BasicBlock& block = cfg.fBlocks[i];
1333 if (!block.fIsReachable && !block.fAllowUnreachable && block.fNodes.size()) {
1334 const BasicBlock::Node& node = block.fNodes[0];
1335 int offset = node.isStatement() ? (*node.statement())->fOffset
1336 : (*node.expression())->fOffset;
1337 this->error(offset, String("unreachable"));
1338 }
ethannicholas22f939e2016-10-13 13:25:34 -07001339 }
1340 }
1341 if (fErrorCount) {
John Stiles0cc193a2020-09-09 09:39:34 -04001342 return madeChanges;
ethannicholas22f939e2016-10-13 13:25:34 -07001343 }
1344
Ethan Nicholascb670962017-04-20 19:31:52 -04001345 // check for dead code & undefined variables, perform constant propagation
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001346 OptimizationContext optimizationContext;
Brian Osman010ce6a2020-10-19 16:34:10 -04001347 optimizationContext.fUsage = usage;
John Stiles7d3f0892020-11-03 11:35:01 -05001348 SkBitSet eliminatedBlockIds(cfg.fBlocks.size());
Ethan Nicholascb670962017-04-20 19:31:52 -04001349 do {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001350 if (optimizationContext.fNeedsRescan) {
Ethan Nicholascb670962017-04-20 19:31:52 -04001351 cfg = CFGGenerator().getCFG(f);
1352 this->computeDataFlow(&cfg);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001353 optimizationContext.fNeedsRescan = false;
Ethan Nicholas113628d2017-02-02 16:11:39 -05001354 }
Ethan Nicholascb670962017-04-20 19:31:52 -04001355
John Stiles7d3f0892020-11-03 11:35:01 -05001356 eliminatedBlockIds.reset();
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001357 optimizationContext.fUpdated = false;
John Stiles7d3f0892020-11-03 11:35:01 -05001358
1359 for (BlockId blockId = 0; blockId < cfg.fBlocks.size(); ++blockId) {
1360 if (eliminatedBlockIds.test(blockId)) {
1361 // We reached a block ID that might have been eliminated. Be cautious and rescan.
1362 optimizationContext.fUpdated = true;
1363 optimizationContext.fNeedsRescan = true;
1364 break;
1365 }
1366
1367 BasicBlock& b = cfg.fBlocks[blockId];
John Stiles66c53b92021-02-20 08:00:43 -05001368 if (fContext->fConfig->fSettings.fDeadCodeElimination) {
1369 if (blockId > 0 && !b.fIsReachable) {
1370 // Block was reachable before optimization, but has since become unreachable. In
1371 // addition to being dead code, it's broken - since control flow can't reach it,
1372 // no prior variable definitions can reach it, and therefore variables might
1373 // look to have not been properly assigned. Kill it by replacing all statements
1374 // with Nops.
1375 for (BasicBlock::Node& node : b.fNodes) {
1376 if (node.isStatement() && !(*node.statement())->is<Nop>()) {
1377 // Eliminating a node runs the risk of eliminating that node's exits as
1378 // well. Keep track of this and do a rescan if we are about to access
1379 // one of these.
1380 for (BlockId id : b.fExits) {
1381 eliminatedBlockIds.set(id);
1382 }
1383 node.setStatement(std::make_unique<Nop>(), usage);
1384 madeChanges = true;
John Stiles7d3f0892020-11-03 11:35:01 -05001385 }
Ethan Nicholas1de14812020-06-19 15:32:49 -04001386 }
John Stiles66c53b92021-02-20 08:00:43 -05001387 continue;
Ethan Nicholas1de14812020-06-19 15:32:49 -04001388 }
Ethan Nicholas1de14812020-06-19 15:32:49 -04001389 }
Ethan Nicholascb670962017-04-20 19:31:52 -04001390 DefinitionMap definitions = b.fBefore;
1391
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001392 for (auto iter = b.fNodes.begin(); iter != b.fNodes.end() &&
1393 !optimizationContext.fNeedsRescan; ++iter) {
John Stiles70025e52020-09-28 16:08:58 -04001394 if (iter->isExpression()) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001395 this->simplifyExpression(definitions, b, &iter, &optimizationContext);
Ethan Nicholascb670962017-04-20 19:31:52 -04001396 } else {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001397 this->simplifyStatement(definitions, b, &iter, &optimizationContext);
Ethan Nicholascb670962017-04-20 19:31:52 -04001398 }
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001399 if (optimizationContext.fNeedsRescan) {
Ethan Nicholas4b330df2017-05-17 10:52:55 -04001400 break;
1401 }
John Stilese8a24922021-02-08 17:54:08 -05001402 definitions.addDefinitions(*fContext, *iter);
Ethan Nicholascb670962017-04-20 19:31:52 -04001403 }
Brian Osman01a3eb42020-09-14 11:32:49 -04001404
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001405 if (optimizationContext.fNeedsRescan) {
Brian Osman01a3eb42020-09-14 11:32:49 -04001406 break;
1407 }
Ethan Nicholascb670962017-04-20 19:31:52 -04001408 }
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001409 madeChanges |= optimizationContext.fUpdated;
1410 } while (optimizationContext.fUpdated);
1411 SkASSERT(!optimizationContext.fNeedsRescan);
ethannicholas22f939e2016-10-13 13:25:34 -07001412
1413 // check for missing return
John Stiles54e7c052021-01-11 14:22:36 -05001414 if (f.declaration().returnType() != *fContext->fTypes.fVoid) {
John Stiles61e75e32020-10-01 15:42:37 -04001415 if (cfg.fBlocks[cfg.fExit].fIsReachable) {
Ethan Nicholas0a5d0962020-10-14 13:33:18 -04001416 this->error(f.fOffset, String("function '" + String(f.declaration().name()) +
Ethan Nicholasdb80f692019-11-22 14:06:12 -05001417 "' can exit without returning a value"));
ethannicholas22f939e2016-10-13 13:25:34 -07001418 }
1419 }
John Stiles0cc193a2020-09-09 09:39:34 -04001420
1421 return madeChanges;
ethannicholas22f939e2016-10-13 13:25:34 -07001422}
1423
Brian Osman32d53552020-09-23 13:55:20 -04001424std::unique_ptr<Program> Compiler::convertProgram(
John Stilesdbd4e6f2021-02-16 13:29:15 -05001425 ProgramKind kind,
Brian Osman32d53552020-09-23 13:55:20 -04001426 String text,
1427 const Program::Settings& settings,
Brian Osmanbe0b3b72021-01-06 14:27:35 -05001428 const std::vector<std::unique_ptr<ExternalFunction>>* externalFunctions) {
Leon Scrogginsb66214e2021-02-11 17:14:18 -05001429 ATRACE_ANDROID_FRAMEWORK("SkSL::Compiler::convertProgram");
1430
John Stilesdbd4e6f2021-02-16 13:29:15 -05001431 SkASSERT(!externalFunctions || (kind == ProgramKind::kGeneric));
Ethan Nicholas91164d12019-05-15 15:29:54 -04001432
Brian Osman0006ad02020-11-18 15:38:39 -05001433 // Loading and optimizing our base module might reset the inliner, so do that first,
1434 // *then* configure the inliner with the settings for this program.
1435 const ParsedModule& baseModule = this->moduleForProgramKind(kind);
1436
John Stiles270cec22021-02-17 12:59:36 -05001437 // Update our context to point to the program configuration for the duration of compilation.
1438 auto config = std::make_unique<ProgramConfig>(ProgramConfig{kind, settings});
1439
1440 SkASSERT(!fContext->fConfig);
1441 fContext->fConfig = config.get();
1442 SK_AT_SCOPE_EXIT(fContext->fConfig = nullptr);
1443
ethannicholasb3058bd2016-07-01 08:22:01 -07001444 fErrorText = "";
1445 fErrorCount = 0;
John Stilesd1204642021-02-17 16:30:02 -05001446 fInliner.reset(fIRGenerator->fModifiers.get());
Brian Osman88cda172020-10-09 12:05:16 -04001447
1448 // Not using AutoSource, because caller is likely to call errorText() if we fail to compile
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001449 std::unique_ptr<String> textPtr(new String(std::move(text)));
1450 fSource = textPtr.get();
Brian Osman88cda172020-10-09 12:05:16 -04001451
John Stiles5c7bb322020-10-22 11:09:15 -04001452 // Enable node pooling while converting and optimizing the program for a performance boost.
1453 // The Program will take ownership of the pool.
Brian Osman28f702c2021-02-02 11:52:07 -05001454 std::unique_ptr<Pool> pool;
John Stilesc1a98b82021-02-24 13:35:02 -05001455 if (fContext->fCaps.useNodePools()) {
Brian Osman28f702c2021-02-02 11:52:07 -05001456 pool = Pool::Create();
1457 pool->attachToThread();
1458 }
John Stilesd1204642021-02-17 16:30:02 -05001459 IRGenerator::IRBundle ir = fIRGenerator->convertProgram(baseModule, /*isBuiltinCode=*/false,
1460 textPtr->c_str(), textPtr->size(),
1461 externalFunctions);
John Stiles270cec22021-02-17 12:59:36 -05001462 auto program = std::make_unique<Program>(std::move(textPtr),
1463 std::move(config),
John Stiles5c7bb322020-10-22 11:09:15 -04001464 fContext,
1465 std::move(ir.fElements),
Brian Osman133724c2020-10-28 14:14:39 -04001466 std::move(ir.fSharedElements),
John Stiles5c7bb322020-10-22 11:09:15 -04001467 std::move(ir.fModifiers),
1468 std::move(ir.fSymbolTable),
1469 std::move(pool),
1470 ir.fInputs);
1471 bool success = false;
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001472 if (fErrorCount) {
John Stiles5c7bb322020-10-22 11:09:15 -04001473 // Do not return programs that failed to compile.
John Stilescbd65752021-02-24 14:14:14 +00001474 } else if (settings.fOptimize && !this->optimize(*program)) {
John Stiles5c7bb322020-10-22 11:09:15 -04001475 // Do not return programs that failed to optimize.
1476 } else {
1477 // We have a successful program!
1478 success = true;
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001479 }
John Stiles5c7bb322020-10-22 11:09:15 -04001480
Brian Osman28f702c2021-02-02 11:52:07 -05001481 if (program->fPool) {
1482 program->fPool->detachFromThread();
1483 }
John Stiles5c7bb322020-10-22 11:09:15 -04001484 return success ? std::move(program) : nullptr;
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001485}
1486
John Stilesbb1505f2021-02-12 09:17:53 -05001487void Compiler::verifyStaticTests(const Program& program) {
1488 class StaticTestVerifier : public ProgramVisitor {
1489 public:
1490 StaticTestVerifier(ErrorReporter* r) : fReporter(r) {}
1491
1492 using ProgramVisitor::visitProgramElement;
1493
1494 bool visitStatement(const Statement& stmt) override {
1495 switch (stmt.kind()) {
1496 case Statement::Kind::kIf:
1497 if (stmt.as<IfStatement>().isStatic()) {
1498 fReporter->error(stmt.fOffset, "static if has non-static test");
1499 }
1500 break;
1501
1502 case Statement::Kind::kSwitch:
1503 if (stmt.as<SwitchStatement>().isStatic()) {
1504 fReporter->error(stmt.fOffset, "static switch has non-static test");
1505 }
1506 break;
1507
1508 default:
1509 break;
1510 }
1511 return INHERITED::visitStatement(stmt);
1512 }
1513
John Stiles59e34562021-02-12 16:56:39 -05001514 bool visitExpression(const Expression&) override {
1515 // We aren't looking for anything inside an Expression, so skip them entirely.
1516 return false;
1517 }
1518
John Stilesbb1505f2021-02-12 09:17:53 -05001519 private:
1520 using INHERITED = ProgramVisitor;
1521 ErrorReporter* fReporter;
1522 };
1523
1524 // If invalid static tests are permitted, we don't need to check anything.
John Stilesd1204642021-02-17 16:30:02 -05001525 if (fContext->fConfig->fSettings.fPermitInvalidStaticTests) {
John Stilesbb1505f2021-02-12 09:17:53 -05001526 return;
1527 }
1528
1529 // Check all of the program's owned elements. (Built-in elements are assumed to be valid.)
1530 StaticTestVerifier visitor{this};
1531 for (const std::unique_ptr<ProgramElement>& element : program.ownedElements()) {
1532 if (element->is<FunctionDefinition>()) {
1533 visitor.visitProgramElement(*element);
1534 }
1535 }
1536}
1537
Brian Osman0006ad02020-11-18 15:38:39 -05001538bool Compiler::optimize(LoadedModule& module) {
1539 SkASSERT(!fErrorCount);
Brian Osman0006ad02020-11-18 15:38:39 -05001540
John Stiles270cec22021-02-17 12:59:36 -05001541 // Create a temporary program configuration with default settings.
1542 ProgramConfig config;
1543 config.fKind = module.fKind;
1544
1545 // Update our context to point to this configuration for the duration of compilation.
1546 SkASSERT(!fContext->fConfig);
1547 fContext->fConfig = &config;
1548 SK_AT_SCOPE_EXIT(fContext->fConfig = nullptr);
1549
John Stilesd1204642021-02-17 16:30:02 -05001550 // Reset the Inliner.
1551 fInliner.reset(fModifiers.back().get());
John Stiles270cec22021-02-17 12:59:36 -05001552
1553 std::unique_ptr<ProgramUsage> usage = Analysis::GetUsage(module);
Brian Osman0006ad02020-11-18 15:38:39 -05001554
1555 while (fErrorCount == 0) {
1556 bool madeChanges = false;
1557
1558 // Scan and optimize based on the control-flow graph for each function.
John Stiles0c7312a2021-02-24 11:31:32 -05001559 // TODO(skia:11365): we always perform CFG-based optimization here to reduce Settings into
1560 // their final form. We should do this optimization in our Make functions instead.
Brian Osman0006ad02020-11-18 15:38:39 -05001561 for (const auto& element : module.fElements) {
1562 if (element->is<FunctionDefinition>()) {
1563 madeChanges |= this->scanCFG(element->as<FunctionDefinition>(), usage.get());
1564 }
1565 }
1566
1567 // Perform inline-candidate analysis and inline any functions deemed suitable.
John Stiles78047582020-12-16 16:17:41 -05001568 madeChanges |= fInliner.analyze(module.fElements, module.fSymbols, usage.get());
Brian Osman0006ad02020-11-18 15:38:39 -05001569
1570 if (!madeChanges) {
1571 break;
1572 }
1573 }
1574 return fErrorCount == 0;
1575}
1576
Ethan Nicholas00543112018-07-31 09:44:36 -04001577bool Compiler::optimize(Program& program) {
1578 SkASSERT(!fErrorCount);
Brian Osman010ce6a2020-10-19 16:34:10 -04001579 ProgramUsage* usage = program.fUsage.get();
John Stiles7954d6c2020-09-01 10:53:02 -04001580
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001581 while (fErrorCount == 0) {
1582 bool madeChanges = false;
John Stiles7954d6c2020-09-01 10:53:02 -04001583
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001584 // Scan and optimize based on the control-flow graph for each function.
John Stiles0c7312a2021-02-24 11:31:32 -05001585 if (program.fConfig->fSettings.fControlFlowAnalysis) {
1586 for (const auto& element : program.ownedElements()) {
1587 if (element->is<FunctionDefinition>()) {
1588 madeChanges |= this->scanCFG(element->as<FunctionDefinition>(), usage);
1589 }
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001590 }
1591 }
1592
1593 // Perform inline-candidate analysis and inline any functions deemed suitable.
John Stiles78047582020-12-16 16:17:41 -05001594 madeChanges |= fInliner.analyze(program.ownedElements(), program.fSymbols, usage);
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001595
1596 // Remove dead functions. We wait until after analysis so that we still report errors,
1597 // even in unused code.
John Stiles270cec22021-02-17 12:59:36 -05001598 if (program.fConfig->fSettings.fRemoveDeadFunctions) {
Brian Osman133724c2020-10-28 14:14:39 -04001599 auto isDeadFunction = [&](const ProgramElement* element) {
1600 if (!element->is<FunctionDefinition>()) {
1601 return false;
1602 }
1603 const FunctionDefinition& fn = element->as<FunctionDefinition>();
1604 if (fn.declaration().name() != "main" && usage->get(fn.declaration()) == 0) {
1605 usage->remove(*element);
1606 madeChanges = true;
1607 return true;
1608 }
1609 return false;
1610 };
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001611 program.fElements.erase(
Brian Osman133724c2020-10-28 14:14:39 -04001612 std::remove_if(program.fElements.begin(), program.fElements.end(),
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001613 [&](const std::unique_ptr<ProgramElement>& element) {
Brian Osman133724c2020-10-28 14:14:39 -04001614 return isDeadFunction(element.get());
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001615 }),
1616 program.fElements.end());
Brian Osman133724c2020-10-28 14:14:39 -04001617 program.fSharedElements.erase(
1618 std::remove_if(program.fSharedElements.begin(), program.fSharedElements.end(),
1619 isDeadFunction),
1620 program.fSharedElements.end());
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001621 }
1622
John Stiles270cec22021-02-17 12:59:36 -05001623 if (program.fConfig->fKind != ProgramKind::kFragmentProcessor) {
Brian Osmanc0213602020-10-06 14:43:32 -04001624 // Remove declarations of dead global variables
Brian Osman133724c2020-10-28 14:14:39 -04001625 auto isDeadVariable = [&](const ProgramElement* element) {
1626 if (!element->is<GlobalVarDeclaration>()) {
1627 return false;
1628 }
1629 const GlobalVarDeclaration& global = element->as<GlobalVarDeclaration>();
1630 const VarDeclaration& varDecl = global.declaration()->as<VarDeclaration>();
1631 if (usage->isDead(varDecl.var())) {
1632 madeChanges = true;
1633 return true;
1634 }
1635 return false;
1636 };
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001637 program.fElements.erase(
1638 std::remove_if(program.fElements.begin(), program.fElements.end(),
1639 [&](const std::unique_ptr<ProgramElement>& element) {
Brian Osman133724c2020-10-28 14:14:39 -04001640 return isDeadVariable(element.get());
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001641 }),
1642 program.fElements.end());
Brian Osman133724c2020-10-28 14:14:39 -04001643 program.fSharedElements.erase(
1644 std::remove_if(program.fSharedElements.begin(), program.fSharedElements.end(),
1645 isDeadVariable),
1646 program.fSharedElements.end());
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001647 }
John Stiles73a6bff2020-09-09 13:40:37 -04001648
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001649 if (!madeChanges) {
1650 break;
Ethan Nicholas0dc80872019-02-08 15:46:24 -05001651 }
Ethan Nicholas00543112018-07-31 09:44:36 -04001652 }
John Stilesbb1505f2021-02-12 09:17:53 -05001653
1654 if (fErrorCount == 0) {
1655 this->verifyStaticTests(program);
1656 }
1657
Ethan Nicholas00543112018-07-31 09:44:36 -04001658 return fErrorCount == 0;
1659}
1660
Brian Osmanfb32ddf2019-06-18 10:14:20 -04001661#if defined(SKSL_STANDALONE) || SK_SUPPORT_GPU
1662
Ethan Nicholas00543112018-07-31 09:44:36 -04001663bool Compiler::toSPIRV(Program& program, OutputStream& out) {
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001664#ifdef SK_ENABLE_SPIRV_VALIDATION
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001665 StringStream buffer;
Brian Osman88cda172020-10-09 12:05:16 -04001666 AutoSource as(this, program.fSource.get());
Brian Osman8b43dad2020-10-09 13:31:42 -04001667 SPIRVCodeGenerator cg(fContext.get(), &program, this, &buffer);
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001668 bool result = cg.generateCode();
John Stiles270cec22021-02-17 12:59:36 -05001669 if (result && program.fConfig->fSettings.fValidateSPIRV) {
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001670 spvtools::SpirvTools tools(SPV_ENV_VULKAN_1_0);
Ethan Nicholas762466e2017-06-29 10:03:38 -04001671 const String& data = buffer.str();
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001672 SkASSERT(0 == data.size() % 4);
Brian Osman8d09d4a2020-11-24 15:51:06 -05001673 String errors;
1674 auto dumpmsg = [&errors](spv_message_level_t, const char*, const spv_position_t&,
1675 const char* m) {
1676 errors.appendf("SPIR-V validation error: %s\n", m);
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001677 };
1678 tools.SetMessageConsumer(dumpmsg);
Brian Osman8d09d4a2020-11-24 15:51:06 -05001679
1680 // Verify that the SPIR-V we produced is valid. At runtime, we will abort() with a message
1681 // explaining the error. In standalone mode (skslc), we will send the message, plus the
1682 // entire disassembled SPIR-V (for easier context & debugging) as *our* error message.
1683 result = tools.Validate((const uint32_t*) data.c_str(), data.size() / 4);
1684
1685 if (!result) {
1686#if defined(SKSL_STANDALONE)
1687 // Convert the string-stream to a SPIR-V disassembly.
1688 std::string disassembly;
1689 if (tools.Disassemble((const uint32_t*)data.data(), data.size() / 4, &disassembly)) {
1690 errors.append(disassembly);
1691 }
1692 this->error(-1, errors);
1693#else
1694 SkDEBUGFAILF("%s", errors.c_str());
1695#endif
1696 }
Ethan Nicholas762466e2017-06-29 10:03:38 -04001697 out.write(data.c_str(), data.size());
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001698 }
1699#else
Brian Osman88cda172020-10-09 12:05:16 -04001700 AutoSource as(this, program.fSource.get());
Brian Osman8b43dad2020-10-09 13:31:42 -04001701 SPIRVCodeGenerator cg(fContext.get(), &program, this, &out);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001702 bool result = cg.generateCode();
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001703#endif
Ethan Nicholasce33f102016-12-09 17:22:59 -05001704 return result;
1705}
1706
Ethan Nicholas00543112018-07-31 09:44:36 -04001707bool Compiler::toSPIRV(Program& program, String* out) {
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001708 StringStream buffer;
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001709 bool result = this->toSPIRV(program, buffer);
1710 if (result) {
Ethan Nicholas762466e2017-06-29 10:03:38 -04001711 *out = buffer.str();
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001712 }
1713 return result;
1714}
1715
Ethan Nicholas00543112018-07-31 09:44:36 -04001716bool Compiler::toGLSL(Program& program, OutputStream& out) {
Leon Scrogginsb66214e2021-02-11 17:14:18 -05001717 ATRACE_ANDROID_FRAMEWORK("SkSL::Compiler::toGLSL");
Brian Osman88cda172020-10-09 12:05:16 -04001718 AutoSource as(this, program.fSource.get());
Ethan Nicholas26a9aad2018-03-27 14:10:52 -04001719 GLSLCodeGenerator cg(fContext.get(), &program, this, &out);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001720 bool result = cg.generateCode();
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001721 return result;
1722}
1723
Ethan Nicholas00543112018-07-31 09:44:36 -04001724bool Compiler::toGLSL(Program& program, String* out) {
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001725 StringStream buffer;
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001726 bool result = this->toGLSL(program, buffer);
1727 if (result) {
Ethan Nicholas762466e2017-06-29 10:03:38 -04001728 *out = buffer.str();
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001729 }
1730 return result;
1731}
1732
Brian Osmanc0243912020-02-19 15:35:26 -05001733bool Compiler::toHLSL(Program& program, String* out) {
1734 String spirv;
1735 if (!this->toSPIRV(program, &spirv)) {
1736 return false;
1737 }
1738
1739 return SPIRVtoHLSL(spirv, out);
1740}
1741
Ethan Nicholas00543112018-07-31 09:44:36 -04001742bool Compiler::toMetal(Program& program, OutputStream& out) {
Ethan Nicholas26a9aad2018-03-27 14:10:52 -04001743 MetalCodeGenerator cg(fContext.get(), &program, this, &out);
Ethan Nicholascc305772017-10-13 16:17:45 -04001744 bool result = cg.generateCode();
Ethan Nicholascc305772017-10-13 16:17:45 -04001745 return result;
1746}
1747
Ethan Nicholas00543112018-07-31 09:44:36 -04001748bool Compiler::toMetal(Program& program, String* out) {
Timothy Liangb8eeb802018-07-23 16:46:16 -04001749 StringStream buffer;
1750 bool result = this->toMetal(program, buffer);
1751 if (result) {
1752 *out = buffer.str();
1753 }
1754 return result;
1755}
1756
Greg Daniela28ea672020-09-25 11:12:56 -04001757#if defined(SKSL_STANDALONE) || GR_TEST_UTILS
Ethan Nicholas00543112018-07-31 09:44:36 -04001758bool Compiler::toCPP(Program& program, String name, OutputStream& out) {
Brian Osman88cda172020-10-09 12:05:16 -04001759 AutoSource as(this, program.fSource.get());
Ethan Nicholas26a9aad2018-03-27 14:10:52 -04001760 CPPCodeGenerator cg(fContext.get(), &program, this, name, &out);
Ethan Nicholas762466e2017-06-29 10:03:38 -04001761 bool result = cg.generateCode();
Ethan Nicholas762466e2017-06-29 10:03:38 -04001762 return result;
1763}
1764
Ethan Nicholas00543112018-07-31 09:44:36 -04001765bool Compiler::toH(Program& program, String name, OutputStream& out) {
Brian Osman88cda172020-10-09 12:05:16 -04001766 AutoSource as(this, program.fSource.get());
Ethan Nicholas26a9aad2018-03-27 14:10:52 -04001767 HCodeGenerator cg(fContext.get(), &program, this, name, &out);
Ethan Nicholas762466e2017-06-29 10:03:38 -04001768 bool result = cg.generateCode();
Ethan Nicholas00543112018-07-31 09:44:36 -04001769 return result;
1770}
Greg Daniela28ea672020-09-25 11:12:56 -04001771#endif // defined(SKSL_STANDALONE) || GR_TEST_UTILS
Ethan Nicholas00543112018-07-31 09:44:36 -04001772
Ethan Nicholas2a479a52020-08-18 16:29:45 -04001773#endif // defined(SKSL_STANDALONE) || SK_SUPPORT_GPU
Brian Osman2e29ab52019-09-20 12:19:11 -04001774
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001775Position Compiler::position(int offset) {
Ethan Nicholas3c729892020-12-07 12:47:17 -05001776 if (fSource && offset >= 0) {
1777 int line = 1;
1778 int column = 1;
1779 for (int i = 0; i < offset; i++) {
1780 if ((*fSource)[i] == '\n') {
1781 ++line;
1782 column = 1;
1783 }
1784 else {
1785 ++column;
1786 }
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001787 }
Ethan Nicholas3c729892020-12-07 12:47:17 -05001788 return Position(line, column);
1789 } else {
1790 return Position(-1, -1);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001791 }
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001792}
1793
1794void Compiler::error(int offset, String msg) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001795 fErrorCount++;
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001796 Position pos = this->position(offset);
John Stiles8d3642e2021-01-22 09:50:04 -05001797 fErrorTextLength.push_back(fErrorText.length());
Ethan Nicholas3c729892020-12-07 12:47:17 -05001798 fErrorText += "error: " + (pos.fLine >= 1 ? to_string(pos.fLine) + ": " : "") + msg + "\n";
ethannicholasb3058bd2016-07-01 08:22:01 -07001799}
1800
John Stiles8d3642e2021-01-22 09:50:04 -05001801void Compiler::setErrorCount(int c) {
1802 if (c < fErrorCount) {
1803 fErrorText.resize(fErrorTextLength[c]);
1804 fErrorTextLength.resize(c);
1805 fErrorCount = c;
1806 }
1807}
1808
Ethan Nicholas95046142021-01-07 10:57:27 -05001809String Compiler::errorText(bool showCount) {
1810 if (showCount) {
1811 this->writeErrorCount();
1812 }
Ethan Nicholas00543112018-07-31 09:44:36 -04001813 fErrorCount = 0;
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001814 String result = fErrorText;
Ethan Nicholas95046142021-01-07 10:57:27 -05001815 fErrorText = "";
ethannicholasb3058bd2016-07-01 08:22:01 -07001816 return result;
1817}
1818
1819void Compiler::writeErrorCount() {
1820 if (fErrorCount) {
1821 fErrorText += to_string(fErrorCount) + " error";
1822 if (fErrorCount > 1) {
1823 fErrorText += "s";
1824 }
1825 fErrorText += "\n";
1826 }
1827}
1828
John Stilesa6841be2020-08-06 14:11:56 -04001829} // namespace SkSL