blob: c4df1826b7ca2756bd643e2c2340071a1faac6c6 [file] [log] [blame]
ethannicholasb3058bd2016-07-01 08:22:01 -07001/*
2 * Copyright 2016 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
Mike Klein6ad99092016-10-26 10:35:22 -04007
Mike Kleinc0bd9f92019-04-23 12:05:21 -05008#include "src/sksl/SkSLCompiler.h"
ethannicholasb3058bd2016-07-01 08:22:01 -07009
John Stilesfbd050b2020-08-03 13:21:46 -040010#include <memory>
John Stilesb8e010c2020-08-11 18:05:39 -040011#include <unordered_set>
John Stilesfbd050b2020-08-03 13:21:46 -040012
John Stiles270cec22021-02-17 12:59:36 -050013#include "src/core/SkScopeExit.h"
Leon Scrogginsb66214e2021-02-11 17:14:18 -050014#include "src/core/SkTraceEvent.h"
John Stilesb92641c2020-08-31 18:09:01 -040015#include "src/sksl/SkSLAnalysis.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050016#include "src/sksl/SkSLCFGGenerator.h"
17#include "src/sksl/SkSLCPPCodeGenerator.h"
18#include "src/sksl/SkSLGLSLCodeGenerator.h"
19#include "src/sksl/SkSLHCodeGenerator.h"
20#include "src/sksl/SkSLIRGenerator.h"
21#include "src/sksl/SkSLMetalCodeGenerator.h"
Brian Osman00185012021-02-04 16:07:11 -050022#include "src/sksl/SkSLOperators.h"
John Stiles270cec22021-02-17 12:59:36 -050023#include "src/sksl/SkSLProgramSettings.h"
Ethan Nicholasc18bb512020-07-28 14:46:53 -040024#include "src/sksl/SkSLRehydrator.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050025#include "src/sksl/SkSLSPIRVCodeGenerator.h"
Brian Osmanc0243912020-02-19 15:35:26 -050026#include "src/sksl/SkSLSPIRVtoHLSL.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050027#include "src/sksl/ir/SkSLEnum.h"
28#include "src/sksl/ir/SkSLExpression.h"
29#include "src/sksl/ir/SkSLExpressionStatement.h"
30#include "src/sksl/ir/SkSLFunctionCall.h"
31#include "src/sksl/ir/SkSLIntLiteral.h"
32#include "src/sksl/ir/SkSLModifiersDeclaration.h"
33#include "src/sksl/ir/SkSLNop.h"
34#include "src/sksl/ir/SkSLSymbolTable.h"
35#include "src/sksl/ir/SkSLTernaryExpression.h"
36#include "src/sksl/ir/SkSLUnresolvedFunction.h"
37#include "src/sksl/ir/SkSLVarDeclarations.h"
John Stilese6150002020-10-05 12:03:53 -040038#include "src/utils/SkBitSet.h"
ethannicholasb3058bd2016-07-01 08:22:01 -070039
Ethan Nicholasb33fa3f2020-08-06 13:00:19 -040040#include <fstream>
41
Ethan Nicholasa11035b2019-11-26 16:27:47 -050042#if !defined(SKSL_STANDALONE) & SK_SUPPORT_GPU
43#include "include/gpu/GrContextOptions.h"
44#include "src/gpu/GrShaderCaps.h"
45#endif
46
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -040047#ifdef SK_ENABLE_SPIRV_VALIDATION
48#include "spirv-tools/libspirv.hpp"
49#endif
50
Brian Osman3d87e9f2020-10-08 11:50:22 -040051#if defined(SKSL_STANDALONE)
Ethan Nicholasc18bb512020-07-28 14:46:53 -040052
Brian Osman3d87e9f2020-10-08 11:50:22 -040053// In standalone mode, we load the textual sksl source files. GN generates or copies these files
54// to the skslc executable directory. The "data" in this mode is just the filename.
55#define MODULE_DATA(name) MakeModulePath("sksl_" #name ".sksl")
56
57#else
58
59// At runtime, we load the dehydrated sksl data files. The data is a (pointer, size) pair.
Ethan Nicholasc18bb512020-07-28 14:46:53 -040060#include "src/sksl/generated/sksl_fp.dehydrated.sksl"
61#include "src/sksl/generated/sksl_frag.dehydrated.sksl"
62#include "src/sksl/generated/sksl_geom.dehydrated.sksl"
63#include "src/sksl/generated/sksl_gpu.dehydrated.sksl"
Brian Osmanb06301e2020-11-06 11:45:36 -050064#include "src/sksl/generated/sksl_public.dehydrated.sksl"
Brian Osman91946752020-12-21 13:20:40 -050065#include "src/sksl/generated/sksl_runtime.dehydrated.sksl"
Ethan Nicholasc18bb512020-07-28 14:46:53 -040066#include "src/sksl/generated/sksl_vert.dehydrated.sksl"
67
Brian Osman3d87e9f2020-10-08 11:50:22 -040068#define MODULE_DATA(name) MakeModuleData(SKSL_INCLUDE_sksl_##name,\
69 SKSL_INCLUDE_sksl_##name##_LENGTH)
Ethan Nicholasc18bb512020-07-28 14:46:53 -040070
71#endif
Ethan Nicholas0d997662019-04-08 09:46:01 -040072
ethannicholasb3058bd2016-07-01 08:22:01 -070073namespace SkSL {
74
John Stiles47c0a742021-02-09 09:30:35 -050075using RefKind = VariableReference::RefKind;
76
Brian Osman88cda172020-10-09 12:05:16 -040077class AutoSource {
78public:
79 AutoSource(Compiler* compiler, const String* source)
80 : fCompiler(compiler), fOldSource(fCompiler->fSource) {
81 fCompiler->fSource = source;
82 }
83
84 ~AutoSource() { fCompiler->fSource = fOldSource; }
85
86 Compiler* fCompiler;
87 const String* fOldSource;
88};
89
John Stilesd6a5f4492021-02-11 15:46:11 -050090Compiler::Compiler(const ShaderCapsClass* caps)
John Stilesb30151e2021-01-11 16:13:08 -050091 : fContext(std::make_shared<Context>(/*errors=*/*this))
Brian Osman0006ad02020-11-18 15:38:39 -050092 , fCaps(caps)
John Stiles7b920442020-12-17 10:43:41 -050093 , fInliner(fContext.get())
Brian Osman0006ad02020-11-18 15:38:39 -050094 , fErrorCount(0) {
95 SkASSERT(fCaps);
John Stiles7c3515b2020-10-16 18:38:39 -040096 fRootSymbolTable = std::make_shared<SymbolTable>(this, /*builtin=*/true);
Brian Osmanb06301e2020-11-06 11:45:36 -050097 fPrivateSymbolTable = std::make_shared<SymbolTable>(fRootSymbolTable, /*builtin=*/true);
John Stilesb30151e2021-01-11 16:13:08 -050098 fIRGenerator = std::make_unique<IRGenerator>(fContext.get(), fCaps);
ethannicholasb3058bd2016-07-01 08:22:01 -070099
John Stiles54e7c052021-01-11 14:22:36 -0500100#define TYPE(t) fContext->fTypes.f ## t .get()
ethannicholasb3058bd2016-07-01 08:22:01 -0700101
Brian Osmanb06301e2020-11-06 11:45:36 -0500102 const SkSL::Symbol* rootTypes[] = {
103 TYPE(Void),
Brian Salomonbf7b6202016-11-11 16:08:03 -0500104
Brian Osmanb06301e2020-11-06 11:45:36 -0500105 TYPE( Float), TYPE( Float2), TYPE( Float3), TYPE( Float4),
106 TYPE( Half), TYPE( Half2), TYPE( Half3), TYPE( Half4),
107 TYPE( Int), TYPE( Int2), TYPE( Int3), TYPE( Int4),
Brian Osmanb06301e2020-11-06 11:45:36 -0500108 TYPE( Bool), TYPE( Bool2), TYPE( Bool3), TYPE( Bool4),
Brian Salomon2a51de82016-11-16 12:06:01 -0500109
Brian Osmanc0f2b642020-12-22 13:35:55 -0500110 TYPE(Float2x2), TYPE(Float3x3), TYPE(Float4x4),
Brian Osmanc63f4312020-12-23 11:44:14 -0500111 TYPE( Half2x2), TYPE( Half3x3), TYPE(Half4x4),
Greg Daniel64773e62016-11-22 09:44:03 -0500112
Brian Osmanc63f4312020-12-23 11:44:14 -0500113 TYPE(SquareMat), TYPE(SquareHMat),
ethannicholasb3058bd2016-07-01 08:22:01 -0700114
Brian Osman20fad322020-12-23 12:42:33 -0500115 TYPE(GenType), TYPE(GenHType), TYPE(GenIType), TYPE(GenBType),
116 TYPE(Vec), TYPE(HVec), TYPE(IVec), TYPE(BVec),
Brian Osmanb06301e2020-11-06 11:45:36 -0500117
118 TYPE(FragmentProcessor),
119 };
120
121 const SkSL::Symbol* privateTypes[] = {
Brian Osman20fad322020-12-23 12:42:33 -0500122 TYPE( UInt), TYPE( UInt2), TYPE( UInt3), TYPE( UInt4),
123 TYPE( Short), TYPE( Short2), TYPE( Short3), TYPE( Short4),
124 TYPE(UShort), TYPE(UShort2), TYPE(UShort3), TYPE(UShort4),
125 TYPE( Byte), TYPE( Byte2), TYPE( Byte3), TYPE( Byte4),
126 TYPE( UByte), TYPE( UByte2), TYPE( UByte3), TYPE( UByte4),
127
128 TYPE(GenUType), TYPE(UVec),
129 TYPE(SVec), TYPE(USVec), TYPE(ByteVec), TYPE(UByteVec),
130
Brian Osmanc0f2b642020-12-22 13:35:55 -0500131 TYPE(Float2x3), TYPE(Float2x4),
132 TYPE(Float3x2), TYPE(Float3x4),
133 TYPE(Float4x2), TYPE(Float4x3),
134
Brian Osmanc63f4312020-12-23 11:44:14 -0500135 TYPE(Half2x3), TYPE(Half2x4),
136 TYPE(Half3x2), TYPE(Half3x4),
137 TYPE(Half4x2), TYPE(Half4x3),
138
Brian Osmanc0f2b642020-12-22 13:35:55 -0500139 TYPE(Mat), TYPE(HMat),
140
Brian Osmanb06301e2020-11-06 11:45:36 -0500141 TYPE(Sampler1D), TYPE(Sampler2D), TYPE(Sampler3D),
142 TYPE(SamplerExternalOES),
Brian Osmanb06301e2020-11-06 11:45:36 -0500143 TYPE(Sampler2DRect),
Brian Osmanb06301e2020-11-06 11:45:36 -0500144
145 TYPE(ISampler2D),
146 TYPE(Image2D), TYPE(IImage2D),
147 TYPE(SubpassInput), TYPE(SubpassInputMS),
148
Brian Osmanb06301e2020-11-06 11:45:36 -0500149 TYPE(Sampler),
150 TYPE(Texture2D),
151 };
152
153 for (const SkSL::Symbol* type : rootTypes) {
154 fRootSymbolTable->addWithoutOwnership(type);
155 }
156 for (const SkSL::Symbol* type : privateTypes) {
157 fPrivateSymbolTable->addWithoutOwnership(type);
158 }
159
160#undef TYPE
ethannicholasb3058bd2016-07-01 08:22:01 -0700161
Brian Osman3887a012020-09-30 13:22:27 -0400162 // sk_Caps is "builtin", but all references to it are resolved to Settings, so we don't need to
163 // treat it as builtin (ie, no need to clone it into the Program).
Brian Osmanb06301e2020-11-06 11:45:36 -0500164 fPrivateSymbolTable->add(
165 std::make_unique<Variable>(/*offset=*/-1,
John Stiles586df952020-11-12 18:27:13 -0500166 fIRGenerator->fModifiers->addToPool(Modifiers()),
Brian Osmanb06301e2020-11-06 11:45:36 -0500167 "sk_Caps",
John Stiles54e7c052021-01-11 14:22:36 -0500168 fContext->fTypes.fSkCaps.get(),
Brian Osmanb06301e2020-11-06 11:45:36 -0500169 /*builtin=*/false,
170 Variable::Storage::kGlobal));
Ethan Nicholas3605ace2016-11-21 15:59:48 -0500171
Brian Osman3d87e9f2020-10-08 11:50:22 -0400172 fRootModule = {fRootSymbolTable, /*fIntrinsics=*/nullptr};
Brian Osmanb06301e2020-11-06 11:45:36 -0500173 fPrivateModule = {fPrivateSymbolTable, /*fIntrinsics=*/nullptr};
ethannicholasb3058bd2016-07-01 08:22:01 -0700174}
175
John Stilesdd13dba2020-10-29 10:45:34 -0400176Compiler::~Compiler() {}
ethannicholasb3058bd2016-07-01 08:22:01 -0700177
Brian Osman56269982020-11-20 12:38:07 -0500178const ParsedModule& Compiler::loadGPUModule() {
179 if (!fGPUModule.fSymbols) {
John Stilesdbd4e6f2021-02-16 13:29:15 -0500180 fGPUModule = this->parseModule(ProgramKind::kFragment, MODULE_DATA(gpu), fPrivateModule);
Brian Osman56269982020-11-20 12:38:07 -0500181 }
182 return fGPUModule;
183}
184
185const ParsedModule& Compiler::loadFragmentModule() {
186 if (!fFragmentModule.fSymbols) {
John Stilesdbd4e6f2021-02-16 13:29:15 -0500187 fFragmentModule = this->parseModule(ProgramKind::kFragment, MODULE_DATA(frag),
Brian Osman56269982020-11-20 12:38:07 -0500188 this->loadGPUModule());
189 }
190 return fFragmentModule;
191}
192
193const ParsedModule& Compiler::loadVertexModule() {
194 if (!fVertexModule.fSymbols) {
John Stilesdbd4e6f2021-02-16 13:29:15 -0500195 fVertexModule = this->parseModule(ProgramKind::kVertex, MODULE_DATA(vert),
Brian Osman56269982020-11-20 12:38:07 -0500196 this->loadGPUModule());
197 }
198 return fVertexModule;
199}
200
Brian Osman88cda172020-10-09 12:05:16 -0400201const ParsedModule& Compiler::loadGeometryModule() {
Brian Osman3d87e9f2020-10-08 11:50:22 -0400202 if (!fGeometryModule.fSymbols) {
John Stilesdbd4e6f2021-02-16 13:29:15 -0500203 fGeometryModule = this->parseModule(ProgramKind::kGeometry, MODULE_DATA(geom),
Brian Osman56269982020-11-20 12:38:07 -0500204 this->loadGPUModule());
Ethan Nicholasc18bb512020-07-28 14:46:53 -0400205 }
Brian Osman88cda172020-10-09 12:05:16 -0400206 return fGeometryModule;
Ethan Nicholasc18bb512020-07-28 14:46:53 -0400207}
208
Brian Osman88cda172020-10-09 12:05:16 -0400209const ParsedModule& Compiler::loadFPModule() {
Brian Osman3d87e9f2020-10-08 11:50:22 -0400210 if (!fFPModule.fSymbols) {
John Stilesdbd4e6f2021-02-16 13:29:15 -0500211 fFPModule = this->parseModule(ProgramKind::kFragmentProcessor, MODULE_DATA(fp),
Brian Osman56269982020-11-20 12:38:07 -0500212 this->loadGPUModule());
Brian Osman8e2ef022020-09-30 13:26:43 -0400213 }
Brian Osman88cda172020-10-09 12:05:16 -0400214 return fFPModule;
Brian Osman8e2ef022020-09-30 13:26:43 -0400215}
216
Brian Osmanb06301e2020-11-06 11:45:36 -0500217const ParsedModule& Compiler::loadPublicModule() {
218 if (!fPublicModule.fSymbols) {
John Stilesdbd4e6f2021-02-16 13:29:15 -0500219 fPublicModule = this->parseModule(ProgramKind::kGeneric, MODULE_DATA(public), fRootModule);
Brian Osmanb06301e2020-11-06 11:45:36 -0500220 }
221 return fPublicModule;
222}
223
Brian Osman91946752020-12-21 13:20:40 -0500224const ParsedModule& Compiler::loadRuntimeEffectModule() {
225 if (!fRuntimeEffectModule.fSymbols) {
John Stilesdbd4e6f2021-02-16 13:29:15 -0500226 fRuntimeEffectModule = this->parseModule(ProgramKind::kRuntimeEffect, MODULE_DATA(runtime),
Brian Osman91946752020-12-21 13:20:40 -0500227 this->loadPublicModule());
Brian Osmanf1319c32020-10-13 09:34:23 -0400228
Brian Osman91946752020-12-21 13:20:40 -0500229 // Add some aliases to the runtime effect module so that it's friendlier, and more like GLSL
John Stiles54e7c052021-01-11 14:22:36 -0500230 fRuntimeEffectModule.fSymbols->addAlias("shader", fContext->fTypes.fFragmentProcessor.get());
Brian Osmanf1319c32020-10-13 09:34:23 -0400231
John Stiles54e7c052021-01-11 14:22:36 -0500232 fRuntimeEffectModule.fSymbols->addAlias("vec2", fContext->fTypes.fFloat2.get());
233 fRuntimeEffectModule.fSymbols->addAlias("vec3", fContext->fTypes.fFloat3.get());
234 fRuntimeEffectModule.fSymbols->addAlias("vec4", fContext->fTypes.fFloat4.get());
Brian Osmanf1319c32020-10-13 09:34:23 -0400235
John Stiles54e7c052021-01-11 14:22:36 -0500236 fRuntimeEffectModule.fSymbols->addAlias("bvec2", fContext->fTypes.fBool2.get());
237 fRuntimeEffectModule.fSymbols->addAlias("bvec3", fContext->fTypes.fBool3.get());
238 fRuntimeEffectModule.fSymbols->addAlias("bvec4", fContext->fTypes.fBool4.get());
Brian Osmanf1319c32020-10-13 09:34:23 -0400239
John Stiles54e7c052021-01-11 14:22:36 -0500240 fRuntimeEffectModule.fSymbols->addAlias("mat2", fContext->fTypes.fFloat2x2.get());
241 fRuntimeEffectModule.fSymbols->addAlias("mat3", fContext->fTypes.fFloat3x3.get());
242 fRuntimeEffectModule.fSymbols->addAlias("mat4", fContext->fTypes.fFloat4x4.get());
Ethan Nicholasc18bb512020-07-28 14:46:53 -0400243 }
Brian Osman91946752020-12-21 13:20:40 -0500244 return fRuntimeEffectModule;
Ethan Nicholasc18bb512020-07-28 14:46:53 -0400245}
246
John Stilesdbd4e6f2021-02-16 13:29:15 -0500247const ParsedModule& Compiler::moduleForProgramKind(ProgramKind kind) {
Brian Osman88cda172020-10-09 12:05:16 -0400248 switch (kind) {
John Stilesdbd4e6f2021-02-16 13:29:15 -0500249 case ProgramKind::kVertex: return this->loadVertexModule(); break;
250 case ProgramKind::kFragment: return this->loadFragmentModule(); break;
251 case ProgramKind::kGeometry: return this->loadGeometryModule(); break;
252 case ProgramKind::kFragmentProcessor: return this->loadFPModule(); break;
253 case ProgramKind::kRuntimeEffect: return this->loadRuntimeEffectModule(); break;
254 case ProgramKind::kGeneric: return this->loadPublicModule(); break;
Brian Osman88cda172020-10-09 12:05:16 -0400255 }
256 SkUNREACHABLE;
Ethan Nicholasc18bb512020-07-28 14:46:53 -0400257}
258
John Stilesdbd4e6f2021-02-16 13:29:15 -0500259LoadedModule Compiler::loadModule(ProgramKind kind,
Brian Osman3d87e9f2020-10-08 11:50:22 -0400260 ModuleData data,
261 std::shared_ptr<SymbolTable> base) {
Brian Osman3d87e9f2020-10-08 11:50:22 -0400262 if (!base) {
Brian Osmanb06301e2020-11-06 11:45:36 -0500263 // NOTE: This is a workaround. The only time 'base' is null is when dehydrating includes.
264 // In that case, skslc doesn't know which module it's preparing, nor what the correct base
265 // module is. We can't use 'Root', because many GPU intrinsics reference private types,
266 // like samplers or textures. Today, 'Private' does contain the union of all known types,
267 // so this is safe. If we ever have types that only exist in 'Public' (for example), this
268 // logic needs to be smarter (by choosing the correct base for the module we're compiling).
269 base = fPrivateSymbolTable;
Brian Osman3d87e9f2020-10-08 11:50:22 -0400270 }
271
272#if defined(SKSL_STANDALONE)
273 SkASSERT(data.fPath);
274 std::ifstream in(data.fPath);
Brian Osmane498b3c2020-09-23 14:42:11 -0400275 std::unique_ptr<String> text = std::make_unique<String>(std::istreambuf_iterator<char>(in),
276 std::istreambuf_iterator<char>());
Ethan Nicholasb33fa3f2020-08-06 13:00:19 -0400277 if (in.rdstate()) {
Brian Osman3d87e9f2020-10-08 11:50:22 -0400278 printf("error reading %s\n", data.fPath);
Ethan Nicholasb33fa3f2020-08-06 13:00:19 -0400279 abort();
280 }
Brian Osmane498b3c2020-09-23 14:42:11 -0400281 const String* source = fRootSymbolTable->takeOwnershipOfString(std::move(text));
Brian Osman88cda172020-10-09 12:05:16 -0400282 AutoSource as(this, source);
John Stilesd1204642021-02-17 16:30:02 -0500283
John Stiles881a10c2020-09-19 10:13:24 -0400284 SkASSERT(fIRGenerator->fCanInline);
285 fIRGenerator->fCanInline = false;
John Stilesd1204642021-02-17 16:30:02 -0500286
287 ProgramConfig config;
288 config.fKind = kind;
289 config.fSettings.fReplaceSettings = false;
290
291 fContext->fConfig = &config;
292 SK_AT_SCOPE_EXIT(fContext->fConfig = nullptr);
John Stilesdbd4e6f2021-02-16 13:29:15 -0500293
Brian Osman88cda172020-10-09 12:05:16 -0400294 ParsedModule baseModule = {base, /*fIntrinsics=*/nullptr};
John Stilesd1204642021-02-17 16:30:02 -0500295 IRGenerator::IRBundle ir = fIRGenerator->convertProgram(baseModule, /*isBuiltinCode=*/true,
296 source->c_str(), source->length(),
297 /*externalFunctions=*/nullptr);
Brian Osman133724c2020-10-28 14:14:39 -0400298 SkASSERT(ir.fSharedElements.empty());
Brian Osman0006ad02020-11-18 15:38:39 -0500299 LoadedModule module = { kind, std::move(ir.fSymbolTable), std::move(ir.fElements) };
John Stiles881a10c2020-09-19 10:13:24 -0400300 fIRGenerator->fCanInline = true;
Ethan Nicholas8da1e652019-05-24 11:01:59 -0400301 if (this->fErrorCount) {
302 printf("Unexpected errors: %s\n", this->fErrorText.c_str());
Brian Osman3d87e9f2020-10-08 11:50:22 -0400303 SkDEBUGFAILF("%s %s\n", data.fPath, this->fErrorText.c_str());
Ethan Nicholas8da1e652019-05-24 11:01:59 -0400304 }
Brian Osman88cda172020-10-09 12:05:16 -0400305 fModifiers.push_back(std::move(ir.fModifiers));
Brian Osman3d87e9f2020-10-08 11:50:22 -0400306#else
307 SkASSERT(data.fData && (data.fSize != 0));
308 Rehydrator rehydrator(fContext.get(), fIRGenerator->fModifiers.get(), base, this,
309 data.fData, data.fSize);
Brian Osman0006ad02020-11-18 15:38:39 -0500310 LoadedModule module = { kind, rehydrator.symbolTable(), rehydrator.elements() };
Brian Osman3d87e9f2020-10-08 11:50:22 -0400311 fModifiers.push_back(fIRGenerator->releaseModifiers());
312#endif
313
314 return module;
315}
316
John Stilesdbd4e6f2021-02-16 13:29:15 -0500317ParsedModule Compiler::parseModule(ProgramKind kind, ModuleData data, const ParsedModule& base) {
Brian Osman0006ad02020-11-18 15:38:39 -0500318 LoadedModule module = this->loadModule(kind, data, base.fSymbols);
319 this->optimize(module);
Brian Osman3d87e9f2020-10-08 11:50:22 -0400320
321 // For modules that just declare (but don't define) intrinsic functions, there will be no new
322 // program elements. In that case, we can share our parent's intrinsic map:
Brian Osman0006ad02020-11-18 15:38:39 -0500323 if (module.fElements.empty()) {
324 return {module.fSymbols, base.fIntrinsics};
Brian Osman3d87e9f2020-10-08 11:50:22 -0400325 }
326
327 auto intrinsics = std::make_shared<IRIntrinsicMap>(base.fIntrinsics.get());
328
329 // Now, transfer all of the program elements to an intrinsic map. This maps certain types of
330 // global objects to the declaring ProgramElement.
Brian Osman0006ad02020-11-18 15:38:39 -0500331 for (std::unique_ptr<ProgramElement>& element : module.fElements) {
Brian Osman3d87e9f2020-10-08 11:50:22 -0400332 switch (element->kind()) {
333 case ProgramElement::Kind::kFunction: {
334 const FunctionDefinition& f = element->as<FunctionDefinition>();
Ethan Nicholas0a5d0962020-10-14 13:33:18 -0400335 SkASSERT(f.declaration().isBuiltin());
336 intrinsics->insertOrDie(f.declaration().description(), std::move(element));
Brian Osman3d87e9f2020-10-08 11:50:22 -0400337 break;
338 }
John Stiles569249b2020-11-03 12:18:22 -0500339 case ProgramElement::Kind::kFunctionPrototype: {
340 // These are already in the symbol table.
341 break;
342 }
Brian Osman3d87e9f2020-10-08 11:50:22 -0400343 case ProgramElement::Kind::kEnum: {
344 const Enum& e = element->as<Enum>();
345 SkASSERT(e.isBuiltin());
346 intrinsics->insertOrDie(e.typeName(), std::move(element));
347 break;
348 }
349 case ProgramElement::Kind::kGlobalVar: {
Ethan Nicholasc51f33e2020-10-13 13:49:44 -0400350 const GlobalVarDeclaration& global = element->as<GlobalVarDeclaration>();
351 const Variable& var = global.declaration()->as<VarDeclaration>().var();
352 SkASSERT(var.isBuiltin());
353 intrinsics->insertOrDie(var.name(), std::move(element));
Brian Osman3d87e9f2020-10-08 11:50:22 -0400354 break;
355 }
356 case ProgramElement::Kind::kInterfaceBlock: {
Ethan Nicholaseaf47882020-10-15 10:10:08 -0400357 const Variable& var = element->as<InterfaceBlock>().variable();
358 SkASSERT(var.isBuiltin());
359 intrinsics->insertOrDie(var.name(), std::move(element));
Brian Osman3d87e9f2020-10-08 11:50:22 -0400360 break;
361 }
362 default:
363 printf("Unsupported element: %s\n", element->description().c_str());
364 SkASSERT(false);
365 break;
366 }
367 }
368
Brian Osman0006ad02020-11-18 15:38:39 -0500369 return {module.fSymbols, std::move(intrinsics)};
Ethan Nicholas8da1e652019-05-24 11:01:59 -0400370}
371
John Stilese6150002020-10-05 12:03:53 -0400372void Compiler::scanCFG(CFG* cfg, BlockId blockId, SkBitSet* processedSet) {
ethannicholas22f939e2016-10-13 13:25:34 -0700373 BasicBlock& block = cfg->fBlocks[blockId];
374
375 // compute definitions after this block
Ethan Nicholas86a43402017-01-19 13:32:00 -0500376 DefinitionMap after = block.fBefore;
ethannicholas22f939e2016-10-13 13:25:34 -0700377 for (const BasicBlock::Node& n : block.fNodes) {
John Stilese8a24922021-02-08 17:54:08 -0500378 after.addDefinitions(*fContext, n);
ethannicholas22f939e2016-10-13 13:25:34 -0700379 }
380
381 // propagate definitions to exits
382 for (BlockId exitId : block.fExits) {
Ethan Nicholas26a9aad2018-03-27 14:10:52 -0400383 if (exitId == blockId) {
384 continue;
385 }
ethannicholas22f939e2016-10-13 13:25:34 -0700386 BasicBlock& exit = cfg->fBlocks[exitId];
John Stiles65b48272020-12-22 17:18:34 -0500387 for (const auto& [var, e1] : after) {
John Stiles796cdb72020-10-08 12:06:53 -0400388 std::unique_ptr<Expression>** exitDef = exit.fBefore.find(var);
389 if (!exitDef) {
John Stilese6150002020-10-05 12:03:53 -0400390 // exit has no definition for it, just copy it and reprocess exit block
391 processedSet->reset(exitId);
John Stilese8a24922021-02-08 17:54:08 -0500392 exit.fBefore.set(var, e1);
ethannicholas22f939e2016-10-13 13:25:34 -0700393 } else {
Ethan Nicholas86a43402017-01-19 13:32:00 -0500394 // exit has a (possibly different) value already defined
John Stiles796cdb72020-10-08 12:06:53 -0400395 std::unique_ptr<Expression>* e2 = *exitDef;
ethannicholas22f939e2016-10-13 13:25:34 -0700396 if (e1 != e2) {
John Stilese6150002020-10-05 12:03:53 -0400397 // definition has changed, merge and reprocess the exit block
398 processedSet->reset(exitId);
Ethan Nicholasaf197692017-02-27 13:26:45 -0500399 if (e1 && e2) {
John Stiles796cdb72020-10-08 12:06:53 -0400400 *exitDef = (std::unique_ptr<Expression>*)&fContext->fDefined_Expression;
Ethan Nicholasaf197692017-02-27 13:26:45 -0500401 } else {
John Stiles796cdb72020-10-08 12:06:53 -0400402 *exitDef = nullptr;
Ethan Nicholasaf197692017-02-27 13:26:45 -0500403 }
ethannicholas22f939e2016-10-13 13:25:34 -0700404 }
405 }
John Stiles65b48272020-12-22 17:18:34 -0500406 }
ethannicholas22f939e2016-10-13 13:25:34 -0700407 }
408}
409
Ethan Nicholascb670962017-04-20 19:31:52 -0400410/**
411 * Returns true if assigning to this lvalue has no effect.
412 */
Brian Osman010ce6a2020-10-19 16:34:10 -0400413static bool is_dead(const Expression& lvalue, ProgramUsage* usage) {
Ethan Nicholase6592142020-09-08 10:22:09 -0400414 switch (lvalue.kind()) {
415 case Expression::Kind::kVariableReference:
Brian Osman010ce6a2020-10-19 16:34:10 -0400416 return usage->isDead(*lvalue.as<VariableReference>().variable());
Ethan Nicholase6592142020-09-08 10:22:09 -0400417 case Expression::Kind::kSwizzle:
Brian Osman010ce6a2020-10-19 16:34:10 -0400418 return is_dead(*lvalue.as<Swizzle>().base(), usage);
Ethan Nicholase6592142020-09-08 10:22:09 -0400419 case Expression::Kind::kFieldAccess:
Brian Osman010ce6a2020-10-19 16:34:10 -0400420 return is_dead(*lvalue.as<FieldAccess>().base(), usage);
Ethan Nicholase6592142020-09-08 10:22:09 -0400421 case Expression::Kind::kIndex: {
John Stilesa5a97b42020-08-18 11:19:07 -0400422 const IndexExpression& idx = lvalue.as<IndexExpression>();
Brian Osman010ce6a2020-10-19 16:34:10 -0400423 return is_dead(*idx.base(), usage) &&
Ethan Nicholas2a4952d2020-10-08 15:35:56 -0400424 !idx.index()->hasProperty(Expression::Property::kSideEffects);
Ethan Nicholascb670962017-04-20 19:31:52 -0400425 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400426 case Expression::Kind::kTernary: {
John Stilesa5a97b42020-08-18 11:19:07 -0400427 const TernaryExpression& t = lvalue.as<TernaryExpression>();
Brian Osman010ce6a2020-10-19 16:34:10 -0400428 return !t.test()->hasSideEffects() &&
429 is_dead(*t.ifTrue(), usage) &&
430 is_dead(*t.ifFalse(), usage);
Ethan Nicholasa583b812018-01-18 13:32:11 -0500431 }
Ethan Nicholascb670962017-04-20 19:31:52 -0400432 default:
John Stileseada7bc2021-02-02 16:29:32 -0500433 SkDEBUGFAILF("invalid lvalue: %s\n", lvalue.description().c_str());
Ethan Nicholas2a099da2020-01-02 14:40:54 -0500434 return false;
Ethan Nicholascb670962017-04-20 19:31:52 -0400435 }
436}
ethannicholas22f939e2016-10-13 13:25:34 -0700437
Ethan Nicholascb670962017-04-20 19:31:52 -0400438/**
439 * Returns true if this is an assignment which can be collapsed down to just the right hand side due
440 * to a dead target and lack of side effects on the left hand side.
441 */
Brian Osman010ce6a2020-10-19 16:34:10 -0400442static bool dead_assignment(const BinaryExpression& b, ProgramUsage* usage) {
John Stiles45990502021-02-16 10:55:27 -0500443 if (!b.getOperator().isAssignment()) {
Ethan Nicholascb670962017-04-20 19:31:52 -0400444 return false;
445 }
John Stiles2d4f9592020-10-30 10:29:12 -0400446 return is_dead(*b.left(), usage);
Ethan Nicholascb670962017-04-20 19:31:52 -0400447}
448
John Stiles0ac6c152021-02-10 14:04:24 -0500449/**
450 * Returns true if both expression trees are the same. The left side is expected to be an lvalue.
451 * This only needs to check for trees that can plausibly terminate in a variable, so some basic
452 * candidates like `FloatLiteral` are missing.
453 */
454static bool is_matching_expression_tree(const Expression& left, const Expression& right) {
455 if (left.kind() != right.kind() || left.type() != right.type()) {
456 return false;
457 }
458
459 switch (left.kind()) {
460 case Expression::Kind::kIntLiteral:
461 return left.as<IntLiteral>().value() == right.as<IntLiteral>().value();
462
463 case Expression::Kind::kFieldAccess:
464 return left.as<FieldAccess>().fieldIndex() == right.as<FieldAccess>().fieldIndex() &&
465 is_matching_expression_tree(*left.as<FieldAccess>().base(),
466 *right.as<FieldAccess>().base());
467
468 case Expression::Kind::kIndex:
469 return is_matching_expression_tree(*left.as<IndexExpression>().index(),
470 *right.as<IndexExpression>().index()) &&
471 is_matching_expression_tree(*left.as<IndexExpression>().base(),
472 *right.as<IndexExpression>().base());
473
474 case Expression::Kind::kSwizzle:
475 return left.as<Swizzle>().components() == right.as<Swizzle>().components() &&
476 is_matching_expression_tree(*left.as<Swizzle>().base(),
477 *right.as<Swizzle>().base());
478
479 case Expression::Kind::kVariableReference:
480 return left.as<VariableReference>().variable() ==
481 right.as<VariableReference>().variable();
482
483 default:
484 return false;
485 }
486}
487
488static bool self_assignment(const BinaryExpression& b) {
John Stiles45990502021-02-16 10:55:27 -0500489 return b.getOperator().kind() == Token::Kind::TK_EQ &&
John Stiles0ac6c152021-02-10 14:04:24 -0500490 is_matching_expression_tree(*b.left(), *b.right());
491}
492
Ethan Nicholascb670962017-04-20 19:31:52 -0400493void Compiler::computeDataFlow(CFG* cfg) {
John Stilese8a24922021-02-08 17:54:08 -0500494 cfg->fBlocks[cfg->fStart].fBefore.computeStartState(*cfg);
John Stilese6150002020-10-05 12:03:53 -0400495
496 // We set bits in the "processed" set after a block has been scanned.
497 SkBitSet processedSet(cfg->fBlocks.size());
498 while (SkBitSet::OptionalIndex blockId = processedSet.findFirstUnset()) {
499 processedSet.set(*blockId);
500 this->scanCFG(cfg, *blockId, &processedSet);
ethannicholas22f939e2016-10-13 13:25:34 -0700501 }
Ethan Nicholascb670962017-04-20 19:31:52 -0400502}
503
504/**
505 * Attempts to replace the expression pointed to by iter with a new one (in both the CFG and the
506 * IR). If the expression can be cleanly removed, returns true and updates the iterator to point to
507 * the newly-inserted element. Otherwise updates only the IR and returns false (and the CFG will
508 * need to be regenerated).
509 */
John Stilesafbf8992020-08-18 10:08:21 -0400510static bool try_replace_expression(BasicBlock* b,
511 std::vector<BasicBlock::Node>::iterator* iter,
512 std::unique_ptr<Expression>* newExpression) {
Ethan Nicholascb670962017-04-20 19:31:52 -0400513 std::unique_ptr<Expression>* target = (*iter)->expression();
514 if (!b->tryRemoveExpression(iter)) {
515 *target = std::move(*newExpression);
516 return false;
517 }
518 *target = std::move(*newExpression);
519 return b->tryInsertExpression(iter, target);
520}
521
522/**
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400523 * Returns true if the expression is a constant numeric literal with the specified value, or a
524 * constant vector with all elements equal to the specified value.
Ethan Nicholascb670962017-04-20 19:31:52 -0400525 */
Ethan Nicholasa3f22f12020-10-01 12:13:17 -0400526template <typename T = SKSL_FLOAT>
John Stiles9d944232020-08-19 09:56:49 -0400527static bool is_constant(const Expression& expr, T value) {
Ethan Nicholase6592142020-09-08 10:22:09 -0400528 switch (expr.kind()) {
529 case Expression::Kind::kIntLiteral:
Ethan Nicholase96cdd12020-09-28 16:27:18 -0400530 return expr.as<IntLiteral>().value() == value;
John Stiles9d944232020-08-19 09:56:49 -0400531
Ethan Nicholase6592142020-09-08 10:22:09 -0400532 case Expression::Kind::kFloatLiteral:
Ethan Nicholasa3f22f12020-10-01 12:13:17 -0400533 return expr.as<FloatLiteral>().value() == value;
John Stiles9d944232020-08-19 09:56:49 -0400534
Ethan Nicholase6592142020-09-08 10:22:09 -0400535 case Expression::Kind::kConstructor: {
John Stiles9d944232020-08-19 09:56:49 -0400536 const Constructor& constructor = expr.as<Constructor>();
537 if (constructor.isCompileTimeConstant()) {
Ethan Nicholas30d30222020-09-11 12:27:26 -0400538 const Type& constructorType = constructor.type();
Ethan Nicholas30d30222020-09-11 12:27:26 -0400539 switch (constructorType.typeKind()) {
Ethan Nicholase6592142020-09-08 10:22:09 -0400540 case Type::TypeKind::kVector:
John Stilesbc75ebb2020-11-24 12:04:47 -0500541 if (constructor.componentType().isFloat()) {
542 for (int i = 0; i < constructorType.columns(); ++i) {
John Stiles9d944232020-08-19 09:56:49 -0400543 if (constructor.getFVecComponent(i) != value) {
544 return false;
545 }
John Stilesbc75ebb2020-11-24 12:04:47 -0500546 }
547 return true;
548 } else if (constructor.componentType().isInteger()) {
549 for (int i = 0; i < constructorType.columns(); ++i) {
John Stiles9d944232020-08-19 09:56:49 -0400550 if (constructor.getIVecComponent(i) != value) {
551 return false;
552 }
553 }
John Stilesbc75ebb2020-11-24 12:04:47 -0500554 return true;
Ethan Nicholasd188c182019-06-10 15:55:38 -0400555 }
John Stilesbc75ebb2020-11-24 12:04:47 -0500556 // Other types (e.g. boolean) might occur, but aren't supported here.
557 return false;
John Stiles9d944232020-08-19 09:56:49 -0400558
Ethan Nicholase6592142020-09-08 10:22:09 -0400559 case Type::TypeKind::kScalar:
Ethan Nicholasf70f0442020-09-29 12:41:35 -0400560 SkASSERT(constructor.arguments().size() == 1);
561 return is_constant<T>(*constructor.arguments()[0], value);
John Stiles9d944232020-08-19 09:56:49 -0400562
563 default:
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400564 return false;
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400565 }
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400566 }
567 return false;
568 }
Ethan Nicholascb670962017-04-20 19:31:52 -0400569 default:
570 return false;
571 }
572}
573
574/**
575 * Collapses the binary expression pointed to by iter down to just the right side (in both the IR
576 * and CFG structures).
577 */
John Stilesafbf8992020-08-18 10:08:21 -0400578static void delete_left(BasicBlock* b,
579 std::vector<BasicBlock::Node>::iterator* iter,
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400580 Compiler::OptimizationContext* optimizationContext) {
581 optimizationContext->fUpdated = true;
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400582 std::unique_ptr<Expression>* target = (*iter)->expression();
John Stilesa5a97b42020-08-18 11:19:07 -0400583 BinaryExpression& bin = (*target)->as<BinaryExpression>();
John Stiles2d4f9592020-10-30 10:29:12 -0400584 Expression& left = *bin.left();
585 std::unique_ptr<Expression>& rightPointer = bin.right();
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400586 SkASSERT(!left.hasSideEffects());
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400587 bool result;
John Stiles45990502021-02-16 10:55:27 -0500588 if (bin.getOperator().kind() == Token::Kind::TK_EQ) {
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400589 result = b->tryRemoveLValueBefore(iter, &left);
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400590 } else {
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400591 result = b->tryRemoveExpressionBefore(iter, &left);
Ethan Nicholascb670962017-04-20 19:31:52 -0400592 }
Brian Osman010ce6a2020-10-19 16:34:10 -0400593 // Remove references within LHS.
594 optimizationContext->fUsage->remove(&left);
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400595 *target = std::move(rightPointer);
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400596 if (!result) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400597 optimizationContext->fNeedsRescan = true;
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400598 return;
599 }
600 if (*iter == b->fNodes.begin()) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400601 optimizationContext->fNeedsRescan = true;
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400602 return;
603 }
604 --(*iter);
John Stiles70025e52020-09-28 16:08:58 -0400605 if (!(*iter)->isExpression() || (*iter)->expression() != &rightPointer) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400606 optimizationContext->fNeedsRescan = true;
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400607 return;
608 }
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400609 *iter = b->fNodes.erase(*iter);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400610 SkASSERT((*iter)->expression() == target);
Ethan Nicholascb670962017-04-20 19:31:52 -0400611}
612
613/**
614 * Collapses the binary expression pointed to by iter down to just the left side (in both the IR and
615 * CFG structures).
616 */
John Stilesafbf8992020-08-18 10:08:21 -0400617static void delete_right(BasicBlock* b,
618 std::vector<BasicBlock::Node>::iterator* iter,
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400619 Compiler::OptimizationContext* optimizationContext) {
620 optimizationContext->fUpdated = true;
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400621 std::unique_ptr<Expression>* target = (*iter)->expression();
John Stilesa5a97b42020-08-18 11:19:07 -0400622 BinaryExpression& bin = (*target)->as<BinaryExpression>();
John Stiles2d4f9592020-10-30 10:29:12 -0400623 std::unique_ptr<Expression>& leftPointer = bin.left();
624 Expression& right = *bin.right();
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400625 SkASSERT(!right.hasSideEffects());
Brian Osman010ce6a2020-10-19 16:34:10 -0400626 // Remove references within RHS.
627 optimizationContext->fUsage->remove(&right);
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400628 if (!b->tryRemoveExpressionBefore(iter, &right)) {
629 *target = std::move(leftPointer);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400630 optimizationContext->fNeedsRescan = true;
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400631 return;
Ethan Nicholascb670962017-04-20 19:31:52 -0400632 }
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400633 *target = std::move(leftPointer);
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400634 if (*iter == b->fNodes.begin()) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400635 optimizationContext->fNeedsRescan = true;
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400636 return;
637 }
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400638 --(*iter);
John Stiles70025e52020-09-28 16:08:58 -0400639 if ((!(*iter)->isExpression() || (*iter)->expression() != &leftPointer)) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400640 optimizationContext->fNeedsRescan = true;
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400641 return;
642 }
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400643 *iter = b->fNodes.erase(*iter);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400644 SkASSERT((*iter)->expression() == target);
Ethan Nicholascb670962017-04-20 19:31:52 -0400645}
646
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400647/**
648 * Constructs the specified type using a single argument.
649 */
Ethan Nicholas30d30222020-09-11 12:27:26 -0400650static std::unique_ptr<Expression> construct(const Type* type, std::unique_ptr<Expression> v) {
John Stiles8e3b6be2020-10-13 11:14:08 -0400651 ExpressionArray args;
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400652 args.push_back(std::move(v));
John Stiles54f00492021-02-19 11:46:10 -0500653 return std::make_unique<Constructor>(/*offset=*/-1, *type, std::move(args));
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400654}
655
656/**
657 * Used in the implementations of vectorize_left and vectorize_right. Given a vector type and an
658 * expression x, deletes the expression pointed to by iter and replaces it with <type>(x).
659 */
660static void vectorize(BasicBlock* b,
661 std::vector<BasicBlock::Node>::iterator* iter,
662 const Type& type,
663 std::unique_ptr<Expression>* otherExpression,
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400664 Compiler::OptimizationContext* optimizationContext) {
Ethan Nicholase6592142020-09-08 10:22:09 -0400665 SkASSERT((*(*iter)->expression())->kind() == Expression::Kind::kBinary);
John Stiles9aeed132020-11-24 17:36:06 -0500666 SkASSERT(type.isVector());
667 SkASSERT((*otherExpression)->type().isScalar());
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400668 optimizationContext->fUpdated = true;
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400669 std::unique_ptr<Expression>* target = (*iter)->expression();
670 if (!b->tryRemoveExpression(iter)) {
Ethan Nicholas30d30222020-09-11 12:27:26 -0400671 *target = construct(&type, std::move(*otherExpression));
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400672 optimizationContext->fNeedsRescan = true;
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400673 } else {
Ethan Nicholas30d30222020-09-11 12:27:26 -0400674 *target = construct(&type, std::move(*otherExpression));
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400675 if (!b->tryInsertExpression(iter, target)) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400676 optimizationContext->fNeedsRescan = true;
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400677 }
678 }
679}
680
681/**
682 * Given a binary expression of the form x <op> vec<n>(y), deletes the right side and vectorizes the
683 * left to yield vec<n>(x).
684 */
685static void vectorize_left(BasicBlock* b,
686 std::vector<BasicBlock::Node>::iterator* iter,
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400687 Compiler::OptimizationContext* optimizationContext) {
John Stilesa5a97b42020-08-18 11:19:07 -0400688 BinaryExpression& bin = (*(*iter)->expression())->as<BinaryExpression>();
Brian Osman010ce6a2020-10-19 16:34:10 -0400689 // Remove references within RHS. Vectorization of LHS doesn't change reference counts.
John Stiles2d4f9592020-10-30 10:29:12 -0400690 optimizationContext->fUsage->remove(bin.right().get());
691 vectorize(b, iter, bin.right()->type(), &bin.left(), optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400692}
693
694/**
695 * Given a binary expression of the form vec<n>(x) <op> y, deletes the left side and vectorizes the
696 * right to yield vec<n>(y).
697 */
698static void vectorize_right(BasicBlock* b,
699 std::vector<BasicBlock::Node>::iterator* iter,
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400700 Compiler::OptimizationContext* optimizationContext) {
John Stilesa5a97b42020-08-18 11:19:07 -0400701 BinaryExpression& bin = (*(*iter)->expression())->as<BinaryExpression>();
Brian Osman010ce6a2020-10-19 16:34:10 -0400702 // Remove references within LHS. Vectorization of RHS doesn't change reference counts.
John Stiles2d4f9592020-10-30 10:29:12 -0400703 optimizationContext->fUsage->remove(bin.left().get());
704 vectorize(b, iter, bin.left()->type(), &bin.right(), optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400705}
706
Ethan Nicholascb670962017-04-20 19:31:52 -0400707void Compiler::simplifyExpression(DefinitionMap& definitions,
708 BasicBlock& b,
709 std::vector<BasicBlock::Node>::iterator* iter,
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400710 OptimizationContext* optimizationContext) {
Ethan Nicholascb670962017-04-20 19:31:52 -0400711 Expression* expr = (*iter)->expression()->get();
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400712 SkASSERT(expr);
John Stiles108bbe22020-11-18 11:10:38 -0500713
Ethan Nicholascb670962017-04-20 19:31:52 -0400714 if ((*iter)->fConstantPropagation) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400715 std::unique_ptr<Expression> optimized = expr->constantPropagate(*fIRGenerator,
716 definitions);
Ethan Nicholascb670962017-04-20 19:31:52 -0400717 if (optimized) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400718 optimizationContext->fUpdated = true;
Ethan Nicholas30d30222020-09-11 12:27:26 -0400719 optimized = fIRGenerator->coerce(std::move(optimized), expr->type());
Ethan Nicholas1d881522020-09-11 09:32:54 -0400720 SkASSERT(optimized);
Brian Osman010ce6a2020-10-19 16:34:10 -0400721 // Remove references within 'expr', add references within 'optimized'
722 optimizationContext->fUsage->replace(expr, optimized.get());
Ethan Nicholascb670962017-04-20 19:31:52 -0400723 if (!try_replace_expression(&b, iter, &optimized)) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400724 optimizationContext->fNeedsRescan = true;
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400725 return;
Ethan Nicholascb670962017-04-20 19:31:52 -0400726 }
John Stiles70025e52020-09-28 16:08:58 -0400727 SkASSERT((*iter)->isExpression());
Ethan Nicholascb670962017-04-20 19:31:52 -0400728 expr = (*iter)->expression()->get();
Ethan Nicholascb670962017-04-20 19:31:52 -0400729 }
730 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400731 switch (expr->kind()) {
732 case Expression::Kind::kVariableReference: {
John Stilesa5a97b42020-08-18 11:19:07 -0400733 const VariableReference& ref = expr->as<VariableReference>();
Ethan Nicholas78686922020-10-08 06:46:27 -0400734 const Variable* var = ref.variable();
John Stiles66c53b92021-02-20 08:00:43 -0500735 if (fContext->fConfig->fSettings.fDeadCodeElimination &&
736 ref.refKind() != VariableReference::RefKind::kWrite &&
Ethan Nicholas453f67f2020-10-09 10:43:45 -0400737 ref.refKind() != VariableReference::RefKind::kPointer &&
John Stilese8a24922021-02-08 17:54:08 -0500738 var->storage() == Variable::Storage::kLocal && !definitions.get(var) &&
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400739 optimizationContext->fSilences.find(var) == optimizationContext->fSilences.end()) {
740 optimizationContext->fSilences.insert(var);
Ethan Nicholas82a62d22017-11-07 14:42:10 +0000741 this->error(expr->fOffset,
Ethan Nicholase2c49992020-10-05 11:49:11 -0400742 "'" + var->name() + "' has not been assigned");
Ethan Nicholascb670962017-04-20 19:31:52 -0400743 }
744 break;
745 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400746 case Expression::Kind::kTernary: {
John Stiles403a3632020-08-20 12:11:48 -0400747 TernaryExpression* t = &expr->as<TernaryExpression>();
Ethan Nicholasdd218162020-10-08 05:48:01 -0400748 if (t->test()->is<BoolLiteral>()) {
Ethan Nicholascb670962017-04-20 19:31:52 -0400749 // ternary has a constant test, replace it with either the true or
750 // false branch
Ethan Nicholasdd218162020-10-08 05:48:01 -0400751 if (t->test()->as<BoolLiteral>().value()) {
Brian Osman010ce6a2020-10-19 16:34:10 -0400752 (*iter)->setExpression(std::move(t->ifTrue()), optimizationContext->fUsage);
Ethan Nicholascb670962017-04-20 19:31:52 -0400753 } else {
Brian Osman010ce6a2020-10-19 16:34:10 -0400754 (*iter)->setExpression(std::move(t->ifFalse()), optimizationContext->fUsage);
Ethan Nicholascb670962017-04-20 19:31:52 -0400755 }
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400756 optimizationContext->fUpdated = true;
757 optimizationContext->fNeedsRescan = true;
Ethan Nicholascb670962017-04-20 19:31:52 -0400758 }
759 break;
760 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400761 case Expression::Kind::kBinary: {
John Stiles403a3632020-08-20 12:11:48 -0400762 BinaryExpression* bin = &expr->as<BinaryExpression>();
John Stiles0ac6c152021-02-10 14:04:24 -0500763 if (dead_assignment(*bin, optimizationContext->fUsage) || self_assignment(*bin)) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400764 delete_left(&b, iter, optimizationContext);
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400765 break;
766 }
John Stiles2d4f9592020-10-30 10:29:12 -0400767 Expression& left = *bin->left();
768 Expression& right = *bin->right();
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400769 const Type& leftType = left.type();
770 const Type& rightType = right.type();
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400771 // collapse useless expressions like x * 1 or x + 0
John Stiles9aeed132020-11-24 17:36:06 -0500772 if ((!leftType.isScalar() && !leftType.isVector()) ||
773 (!rightType.isScalar() && !rightType.isVector())) {
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400774 break;
775 }
John Stiles45990502021-02-16 10:55:27 -0500776 switch (bin->getOperator().kind()) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400777 case Token::Kind::TK_STAR:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400778 if (is_constant(left, 1)) {
John Stiles9aeed132020-11-24 17:36:06 -0500779 if (leftType.isVector() && rightType.isScalar()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400780 // float4(1) * x -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400781 vectorize_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400782 } else {
783 // 1 * x -> x
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400784 // 1 * float4(x) -> float4(x)
785 // float4(1) * float4(x) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400786 delete_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400787 }
788 }
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400789 else if (is_constant(left, 0)) {
John Stiles9aeed132020-11-24 17:36:06 -0500790 if (leftType.isScalar() && rightType.isVector() &&
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400791 !right.hasSideEffects()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400792 // 0 * float4(x) -> float4(0)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400793 vectorize_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400794 } else {
795 // 0 * x -> 0
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400796 // float4(0) * x -> float4(0)
797 // float4(0) * float4(x) -> float4(0)
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400798 if (!right.hasSideEffects()) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400799 delete_right(&b, iter, optimizationContext);
Ethan Nicholas51493ee2017-12-11 12:34:33 -0500800 }
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400801 }
Ethan Nicholascb670962017-04-20 19:31:52 -0400802 }
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400803 else if (is_constant(right, 1)) {
John Stiles9aeed132020-11-24 17:36:06 -0500804 if (leftType.isScalar() && rightType.isVector()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400805 // x * float4(1) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400806 vectorize_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400807 } else {
808 // x * 1 -> x
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400809 // float4(x) * 1 -> float4(x)
810 // float4(x) * float4(1) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400811 delete_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400812 }
813 }
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400814 else if (is_constant(right, 0)) {
John Stiles9aeed132020-11-24 17:36:06 -0500815 if (leftType.isVector() && rightType.isScalar() && !left.hasSideEffects()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400816 // float4(x) * 0 -> float4(0)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400817 vectorize_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400818 } else {
819 // x * 0 -> 0
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400820 // x * float4(0) -> float4(0)
821 // float4(x) * float4(0) -> float4(0)
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400822 if (!left.hasSideEffects()) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400823 delete_left(&b, iter, optimizationContext);
Ethan Nicholas51493ee2017-12-11 12:34:33 -0500824 }
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400825 }
Ethan Nicholascb670962017-04-20 19:31:52 -0400826 }
827 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400828 case Token::Kind::TK_PLUS:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400829 if (is_constant(left, 0)) {
John Stiles9aeed132020-11-24 17:36:06 -0500830 if (leftType.isVector() && rightType.isScalar()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400831 // float4(0) + x -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400832 vectorize_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400833 } else {
834 // 0 + x -> x
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400835 // 0 + float4(x) -> float4(x)
836 // float4(0) + float4(x) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400837 delete_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400838 }
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400839 } else if (is_constant(right, 0)) {
John Stiles9aeed132020-11-24 17:36:06 -0500840 if (leftType.isScalar() && rightType.isVector()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400841 // x + float4(0) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400842 vectorize_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400843 } else {
844 // x + 0 -> x
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400845 // float4(x) + 0 -> float4(x)
846 // float4(x) + float4(0) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400847 delete_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400848 }
Ethan Nicholas56e42712017-04-21 10:23:37 -0400849 }
850 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400851 case Token::Kind::TK_MINUS:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400852 if (is_constant(right, 0)) {
John Stiles9aeed132020-11-24 17:36:06 -0500853 if (leftType.isScalar() && rightType.isVector()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400854 // x - float4(0) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400855 vectorize_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400856 } else {
857 // x - 0 -> x
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400858 // float4(x) - 0 -> float4(x)
859 // float4(x) - float4(0) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400860 delete_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400861 }
Ethan Nicholascb670962017-04-20 19:31:52 -0400862 }
863 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400864 case Token::Kind::TK_SLASH:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400865 if (is_constant(right, 1)) {
John Stiles9aeed132020-11-24 17:36:06 -0500866 if (leftType.isScalar() && rightType.isVector()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400867 // x / float4(1) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400868 vectorize_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400869 } else {
870 // x / 1 -> x
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400871 // float4(x) / 1 -> float4(x)
872 // float4(x) / float4(1) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400873 delete_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400874 }
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400875 } else if (is_constant(left, 0)) {
John Stiles9aeed132020-11-24 17:36:06 -0500876 if (leftType.isScalar() && rightType.isVector() &&
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400877 !right.hasSideEffects()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400878 // 0 / float4(x) -> float4(0)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400879 vectorize_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400880 } else {
881 // 0 / x -> 0
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400882 // float4(0) / x -> float4(0)
883 // float4(0) / float4(x) -> float4(0)
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400884 if (!right.hasSideEffects()) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400885 delete_right(&b, iter, optimizationContext);
Ethan Nicholas51493ee2017-12-11 12:34:33 -0500886 }
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400887 }
888 }
889 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400890 case Token::Kind::TK_PLUSEQ:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400891 if (is_constant(right, 0)) {
John Stiles47c0a742021-02-09 09:30:35 -0500892 Analysis::UpdateRefKind(&left, RefKind::kRead);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400893 delete_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400894 }
895 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400896 case Token::Kind::TK_MINUSEQ:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400897 if (is_constant(right, 0)) {
John Stiles47c0a742021-02-09 09:30:35 -0500898 Analysis::UpdateRefKind(&left, RefKind::kRead);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400899 delete_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400900 }
901 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400902 case Token::Kind::TK_STAREQ:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400903 if (is_constant(right, 1)) {
John Stiles47c0a742021-02-09 09:30:35 -0500904 Analysis::UpdateRefKind(&left, RefKind::kRead);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400905 delete_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400906 }
907 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400908 case Token::Kind::TK_SLASHEQ:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400909 if (is_constant(right, 1)) {
John Stiles47c0a742021-02-09 09:30:35 -0500910 Analysis::UpdateRefKind(&left, RefKind::kRead);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400911 delete_right(&b, iter, optimizationContext);
Ethan Nicholascb670962017-04-20 19:31:52 -0400912 }
913 break;
914 default:
915 break;
916 }
Ethan Nicholas409f6f02019-09-17 12:34:39 -0400917 break;
918 }
John Stilesf5c1d042020-11-21 23:26:07 -0500919 case Expression::Kind::kConstructor: {
920 // Find constructors embedded inside constructors and flatten them out where possible.
921 // - float4(float2(1, 2), 3, 4) --> float4(1, 2, 3, 4)
922 // - float4(w, float3(sin(x), cos(y), tan(z))) --> float4(w, sin(x), cos(y), tan(z))
923 // Leave single-argument constructors alone, though. These might be casts or splats.
924 Constructor& c = expr->as<Constructor>();
925 if (c.type().columns() > 1) {
926 // Inspect each constructor argument to see if it's a candidate for flattening.
927 // Remember matched arguments in a bitfield, "argsToOptimize".
928 int argsToOptimize = 0;
929 int currBit = 1;
930 for (const std::unique_ptr<Expression>& arg : c.arguments()) {
931 if (arg->is<Constructor>()) {
932 Constructor& inner = arg->as<Constructor>();
933 if (inner.arguments().size() > 1 &&
934 inner.type().componentType() == c.type().componentType()) {
935 argsToOptimize |= currBit;
936 }
937 }
938 currBit <<= 1;
939 }
940 if (argsToOptimize) {
941 // We found at least one argument that could be flattened out. Re-walk the
942 // constructor args and flatten the candidates we found during our initial pass.
943 ExpressionArray flattened;
944 flattened.reserve_back(c.type().columns());
945 currBit = 1;
946 for (const std::unique_ptr<Expression>& arg : c.arguments()) {
947 if (argsToOptimize & currBit) {
948 Constructor& inner = arg->as<Constructor>();
949 for (const std::unique_ptr<Expression>& innerArg : inner.arguments()) {
950 flattened.push_back(innerArg->clone());
951 }
952 } else {
953 flattened.push_back(arg->clone());
954 }
955 currBit <<= 1;
956 }
John Stiles54f00492021-02-19 11:46:10 -0500957 std::unique_ptr<Expression> replacement = std::make_unique<Constructor>(
958 c.fOffset, c.type(), std::move(flattened));
John Stiles1b91c0e2021-02-11 11:43:09 -0500959 // We're replacing an expression with a cloned version; we'll need a rescan.
960 // No fUsage change: `float2(float(x), y)` and `float2(x, y)` have equivalent
961 // reference counts.
962 try_replace_expression(&b, iter, &replacement);
John Stilesf5c1d042020-11-21 23:26:07 -0500963 optimizationContext->fUpdated = true;
John Stiles1b91c0e2021-02-11 11:43:09 -0500964 optimizationContext->fNeedsRescan = true;
John Stilesf5c1d042020-11-21 23:26:07 -0500965 break;
966 }
967 }
968 break;
969 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400970 case Expression::Kind::kSwizzle: {
John Stiles403a3632020-08-20 12:11:48 -0400971 Swizzle& s = expr->as<Swizzle>();
John Stiles108bbe22020-11-18 11:10:38 -0500972 // Detect identity swizzles like `foo.rgba`.
Ethan Nicholas6b4d5812020-10-12 16:11:51 -0400973 if ((int) s.components().size() == s.base()->type().columns()) {
Ethan Nicholas409f6f02019-09-17 12:34:39 -0400974 bool identity = true;
Ethan Nicholas6b4d5812020-10-12 16:11:51 -0400975 for (int i = 0; i < (int) s.components().size(); ++i) {
976 if (s.components()[i] != i) {
Ethan Nicholas409f6f02019-09-17 12:34:39 -0400977 identity = false;
978 break;
979 }
980 }
981 if (identity) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400982 optimizationContext->fUpdated = true;
Brian Osman010ce6a2020-10-19 16:34:10 -0400983 // No fUsage change: foo.rgba and foo have equivalent reference counts
Ethan Nicholas6b4d5812020-10-12 16:11:51 -0400984 if (!try_replace_expression(&b, iter, &s.base())) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400985 optimizationContext->fNeedsRescan = true;
Ethan Nicholas409f6f02019-09-17 12:34:39 -0400986 return;
987 }
John Stiles70025e52020-09-28 16:08:58 -0400988 SkASSERT((*iter)->isExpression());
Ethan Nicholas409f6f02019-09-17 12:34:39 -0400989 break;
990 }
991 }
John Stiles108bbe22020-11-18 11:10:38 -0500992 // Detect swizzles of swizzles, e.g. replace `foo.argb.r000` with `foo.a000`.
993 if (s.base()->is<Swizzle>()) {
Ethan Nicholas6b4d5812020-10-12 16:11:51 -0400994 Swizzle& base = s.base()->as<Swizzle>();
John Stiles750109b2020-10-30 13:45:46 -0400995 ComponentArray final;
Ethan Nicholas6b4d5812020-10-12 16:11:51 -0400996 for (int c : s.components()) {
997 final.push_back(base.components()[c]);
Ethan Nicholas409f6f02019-09-17 12:34:39 -0400998 }
Ethan Nicholas6b4d5812020-10-12 16:11:51 -0400999 std::unique_ptr<Expression> replacement(new Swizzle(*fContext, base.base()->clone(),
John Stiles750109b2020-10-30 13:45:46 -04001000 final));
John Stilesd2f51b12021-01-07 18:12:31 -05001001 // We're replacing an expression with a cloned version; we'll need a rescan.
John Stiles108bbe22020-11-18 11:10:38 -05001002 // No fUsage change: `foo.gbr.gbr` and `foo.brg` have equivalent reference counts
John Stilesd2f51b12021-01-07 18:12:31 -05001003 try_replace_expression(&b, iter, &replacement);
1004 optimizationContext->fUpdated = true;
1005 optimizationContext->fNeedsRescan = true;
John Stiles108bbe22020-11-18 11:10:38 -05001006 break;
1007 }
1008 // Optimize swizzles of constructors.
1009 if (s.base()->is<Constructor>()) {
1010 Constructor& base = s.base()->as<Constructor>();
1011 std::unique_ptr<Expression> replacement;
1012 const Type& componentType = base.type().componentType();
1013 int swizzleSize = s.components().size();
1014
1015 // The IR generator has already converted any zero/one swizzle components into
1016 // constructors containing zero/one args. Confirm that this is true by checking that
1017 // our swizzle components are all `xyzw` (values 0 through 3).
1018 SkASSERT(std::all_of(s.components().begin(), s.components().end(),
1019 [](int8_t c) { return c >= 0 && c <= 3; }));
1020
John Stiles9aeed132020-11-24 17:36:06 -05001021 if (base.arguments().size() == 1 && base.arguments().front()->type().isScalar()) {
John Stiles108bbe22020-11-18 11:10:38 -05001022 // `half4(scalar).zyy` can be optimized to `half3(scalar)`. The swizzle
1023 // components don't actually matter since all fields are the same.
John Stilesf0cb7332021-01-08 18:39:00 -05001024 const Expression& argument = *base.arguments().front();
1025 const Type& constructorType = componentType.toCompound(*fContext, swizzleSize,
1026 /*rows=*/1);
1027 replacement = Constructor::SimplifyConversion(constructorType, argument);
1028 if (!replacement) {
1029 ExpressionArray newArgs;
1030 newArgs.push_back(argument.clone());
John Stiles54f00492021-02-19 11:46:10 -05001031 replacement = std::make_unique<Constructor>(base.fOffset, constructorType,
John Stilesf0cb7332021-01-08 18:39:00 -05001032 std::move(newArgs));
1033 }
John Stiles108bbe22020-11-18 11:10:38 -05001034
John Stilesa60ac0c2020-12-22 08:59:51 -05001035 // We're replacing an expression with a cloned version; we'll need a rescan.
1036 // There's no fUsage change: `half4(foo).xy` and `half2(foo)` have equivalent
1037 // reference counts.
1038 try_replace_expression(&b, iter, &replacement);
John Stiles0777ac42020-11-19 11:06:47 -05001039 optimizationContext->fUpdated = true;
John Stilesa60ac0c2020-12-22 08:59:51 -05001040 optimizationContext->fNeedsRescan = true;
John Stiles108bbe22020-11-18 11:10:38 -05001041 break;
1042 }
1043
John Stiles0777ac42020-11-19 11:06:47 -05001044 // Swizzles can duplicate some elements and discard others, e.g.
1045 // `half4(1, 2, 3, 4).xxz` --> `half3(1, 1, 3)`. However, there are constraints:
1046 // - Expressions with side effects need to occur exactly once, even if they
1047 // would otherwise be swizzle-eliminated
1048 // - Non-trivial expressions should not be repeated, but elimination is OK.
1049 //
1050 // Look up the argument for the constructor at each index. This is typically simple
1051 // but for weird cases like `half4(bar.yz, half2(foo))`, it can be harder than it
1052 // seems. This example would result in:
1053 // argMap[0] = {.fArgIndex = 0, .fComponent = 0} (bar.yz .x)
1054 // argMap[1] = {.fArgIndex = 0, .fComponent = 1} (bar.yz .y)
1055 // argMap[2] = {.fArgIndex = 1, .fComponent = 0} (half2(foo) .x)
1056 // argMap[3] = {.fArgIndex = 1, .fComponent = 1} (half2(foo) .y)
1057 struct ConstructorArgMap {
1058 int8_t fArgIndex;
1059 int8_t fComponent;
1060 };
1061
1062 int numConstructorArgs = base.type().columns();
1063 ConstructorArgMap argMap[4] = {};
1064 int writeIdx = 0;
1065 for (int argIdx = 0; argIdx < (int) base.arguments().size(); ++argIdx) {
1066 const Expression& expr = *base.arguments()[argIdx];
1067 int argWidth = expr.type().columns();
1068 for (int componentIdx = 0; componentIdx < argWidth; ++componentIdx) {
1069 argMap[writeIdx].fArgIndex = argIdx;
1070 argMap[writeIdx].fComponent = componentIdx;
1071 ++writeIdx;
1072 }
1073 }
1074 SkASSERT(writeIdx == numConstructorArgs);
1075
1076 // Count up the number of times each constructor argument is used by the
1077 // swizzle.
1078 // `half4(bar.yz, half2(foo)).xwxy` -> { 3, 1 }
1079 // - bar.yz is referenced 3 times, by `.x_xy`
1080 // - half(foo) is referenced 1 time, by `._w__`
1081 int8_t exprUsed[4] = {};
1082 for (int c : s.components()) {
1083 exprUsed[argMap[c].fArgIndex]++;
1084 }
1085
1086 bool safeToOptimize = true;
1087 for (int index = 0; index < numConstructorArgs; ++index) {
1088 int8_t constructorArgIndex = argMap[index].fArgIndex;
1089 const Expression& baseArg = *base.arguments()[constructorArgIndex];
1090
1091 // Check that non-trivial expressions are not swizzled in more than once.
John Stilesc30fbca2020-11-19 16:25:49 -05001092 if (exprUsed[constructorArgIndex] > 1 &&
1093 !Analysis::IsTrivialExpression(baseArg)) {
John Stiles0777ac42020-11-19 11:06:47 -05001094 safeToOptimize = false;
1095 break;
1096 }
1097 // Check that side-effect-bearing expressions are swizzled in exactly once.
1098 if (exprUsed[constructorArgIndex] != 1 && baseArg.hasSideEffects()) {
1099 safeToOptimize = false;
1100 break;
1101 }
1102 }
1103
1104 if (safeToOptimize) {
John Stilesd9076cb2020-11-19 12:18:36 -05001105 struct ReorderedArgument {
1106 int8_t fArgIndex;
1107 ComponentArray fComponents;
1108 };
1109 SkSTArray<4, ReorderedArgument> reorderedArgs;
John Stiles0777ac42020-11-19 11:06:47 -05001110 for (int c : s.components()) {
1111 const ConstructorArgMap& argument = argMap[c];
1112 const Expression& baseArg = *base.arguments()[argument.fArgIndex];
1113
John Stiles9aeed132020-11-24 17:36:06 -05001114 if (baseArg.type().isScalar()) {
John Stilesd9076cb2020-11-19 12:18:36 -05001115 // This argument is a scalar; add it to the list as-is.
John Stiles0777ac42020-11-19 11:06:47 -05001116 SkASSERT(argument.fComponent == 0);
John Stilesd9076cb2020-11-19 12:18:36 -05001117 reorderedArgs.push_back({argument.fArgIndex,
1118 ComponentArray{}});
John Stiles0777ac42020-11-19 11:06:47 -05001119 } else {
John Stilesd9076cb2020-11-19 12:18:36 -05001120 // This argument is a component from a vector.
John Stiles0777ac42020-11-19 11:06:47 -05001121 SkASSERT(argument.fComponent < baseArg.type().columns());
John Stilesd9076cb2020-11-19 12:18:36 -05001122 if (reorderedArgs.empty() ||
1123 reorderedArgs.back().fArgIndex != argument.fArgIndex) {
1124 // This can't be combined with the previous argument. Add a new one.
1125 reorderedArgs.push_back({argument.fArgIndex,
1126 ComponentArray{argument.fComponent}});
1127 } else {
1128 // Since we know this argument uses components, it should already
1129 // have at least one component set.
1130 SkASSERT(!reorderedArgs.back().fComponents.empty());
1131 // Build up the current argument with one more component.
1132 reorderedArgs.back().fComponents.push_back(argument.fComponent);
1133 }
John Stiles0777ac42020-11-19 11:06:47 -05001134 }
1135 }
John Stilesd9076cb2020-11-19 12:18:36 -05001136
1137 // Convert our reordered argument list to an actual array of expressions, with
1138 // the new order and any new inner swizzles that need to be applied. Note that
1139 // we expect followup passes to clean up the inner swizzles.
1140 ExpressionArray newArgs;
1141 newArgs.reserve_back(swizzleSize);
1142 for (const ReorderedArgument& reorderedArg : reorderedArgs) {
1143 const Expression& baseArg = *base.arguments()[reorderedArg.fArgIndex];
1144 if (reorderedArg.fComponents.empty()) {
1145 newArgs.push_back(baseArg.clone());
1146 } else {
1147 newArgs.push_back(std::make_unique<Swizzle>(*fContext, baseArg.clone(),
1148 reorderedArg.fComponents));
1149 }
1150 }
1151
1152 // Create a new constructor.
John Stiles0777ac42020-11-19 11:06:47 -05001153 replacement = std::make_unique<Constructor>(
1154 base.fOffset,
John Stiles54f00492021-02-19 11:46:10 -05001155 componentType.toCompound(*fContext, swizzleSize, /*rows=*/1),
John Stiles0777ac42020-11-19 11:06:47 -05001156 std::move(newArgs));
1157
John Stilesa60ac0c2020-12-22 08:59:51 -05001158 // Remove references within 'expr', add references within 'replacement.'
John Stiles0777ac42020-11-19 11:06:47 -05001159 optimizationContext->fUsage->replace(expr, replacement.get());
John Stilesa60ac0c2020-12-22 08:59:51 -05001160
1161 // We're replacing an expression with a cloned version; we'll need a rescan.
1162 try_replace_expression(&b, iter, &replacement);
1163 optimizationContext->fUpdated = true;
1164 optimizationContext->fNeedsRescan = true;
John Stiles0777ac42020-11-19 11:06:47 -05001165 }
John Stiles108bbe22020-11-18 11:10:38 -05001166 break;
Ethan Nicholas409f6f02019-09-17 12:34:39 -04001167 }
John Stiles30212b72020-06-11 17:55:07 -04001168 break;
Ethan Nicholascb670962017-04-20 19:31:52 -04001169 }
1170 default:
1171 break;
1172 }
1173}
1174
1175void Compiler::simplifyStatement(DefinitionMap& definitions,
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001176 BasicBlock& b,
1177 std::vector<BasicBlock::Node>::iterator* iter,
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001178 OptimizationContext* optimizationContext) {
Brian Osman010ce6a2020-10-19 16:34:10 -04001179 ProgramUsage* usage = optimizationContext->fUsage;
Ethan Nicholascb670962017-04-20 19:31:52 -04001180 Statement* stmt = (*iter)->statement()->get();
Ethan Nicholase6592142020-09-08 10:22:09 -04001181 switch (stmt->kind()) {
1182 case Statement::Kind::kVarDeclaration: {
John Stilesa5a97b42020-08-18 11:19:07 -04001183 const auto& varDecl = stmt->as<VarDeclaration>();
Brian Osman010ce6a2020-10-19 16:34:10 -04001184 if (usage->isDead(varDecl.var()) &&
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04001185 (!varDecl.value() ||
1186 !varDecl.value()->hasSideEffects())) {
1187 if (varDecl.value()) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001188 SkASSERT((*iter)->statement()->get() == stmt);
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04001189 if (!b.tryRemoveExpressionBefore(iter, varDecl.value().get())) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001190 optimizationContext->fNeedsRescan = true;
Ethan Nicholascb670962017-04-20 19:31:52 -04001191 }
Ethan Nicholascb670962017-04-20 19:31:52 -04001192 }
Ethan Nicholas5b9b0db2021-01-21 13:12:01 -05001193 // There can still be (soon to be removed) references to the variable at this point.
1194 // Allowing the VarDeclaration to be destroyed here will break those variable's
1195 // initialValue()s, so we hang on to them until optimization is finished.
1196 std::unique_ptr<Statement> old = (*iter)->setStatement(std::make_unique<Nop>(),
1197 usage);
1198 optimizationContext->fOwnedStatements.push_back(std::move(old));
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001199 optimizationContext->fUpdated = true;
Ethan Nicholascb670962017-04-20 19:31:52 -04001200 }
1201 break;
1202 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001203 case Statement::Kind::kIf: {
John Stilesa5a97b42020-08-18 11:19:07 -04001204 IfStatement& i = stmt->as<IfStatement>();
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001205 if (i.test()->kind() == Expression::Kind::kBoolLiteral) {
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001206 // constant if, collapse down to a single branch
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001207 if (i.test()->as<BoolLiteral>().value()) {
1208 SkASSERT(i.ifTrue());
Brian Osman010ce6a2020-10-19 16:34:10 -04001209 (*iter)->setStatement(std::move(i.ifTrue()), usage);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001210 } else {
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001211 if (i.ifFalse()) {
Brian Osman010ce6a2020-10-19 16:34:10 -04001212 (*iter)->setStatement(std::move(i.ifFalse()), usage);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001213 } else {
Brian Osman010ce6a2020-10-19 16:34:10 -04001214 (*iter)->setStatement(std::make_unique<Nop>(), usage);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001215 }
1216 }
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001217 optimizationContext->fUpdated = true;
1218 optimizationContext->fNeedsRescan = true;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001219 break;
1220 }
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001221 if (i.ifFalse() && i.ifFalse()->isEmpty()) {
Ethan Nicholascb670962017-04-20 19:31:52 -04001222 // else block doesn't do anything, remove it
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001223 i.ifFalse().reset();
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001224 optimizationContext->fUpdated = true;
1225 optimizationContext->fNeedsRescan = true;
Ethan Nicholascb670962017-04-20 19:31:52 -04001226 }
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001227 if (!i.ifFalse() && i.ifTrue()->isEmpty()) {
Ethan Nicholascb670962017-04-20 19:31:52 -04001228 // if block doesn't do anything, no else block
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001229 if (i.test()->hasSideEffects()) {
Ethan Nicholascb670962017-04-20 19:31:52 -04001230 // test has side effects, keep it
Brian Osman010ce6a2020-10-19 16:34:10 -04001231 (*iter)->setStatement(
1232 std::make_unique<ExpressionStatement>(std::move(i.test())), usage);
Ethan Nicholascb670962017-04-20 19:31:52 -04001233 } else {
1234 // no if, no else, no test side effects, kill the whole if
1235 // statement
Brian Osman010ce6a2020-10-19 16:34:10 -04001236 (*iter)->setStatement(std::make_unique<Nop>(), usage);
Ethan Nicholascb670962017-04-20 19:31:52 -04001237 }
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001238 optimizationContext->fUpdated = true;
1239 optimizationContext->fNeedsRescan = true;
Ethan Nicholascb670962017-04-20 19:31:52 -04001240 }
1241 break;
1242 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001243 case Statement::Kind::kSwitch: {
John Stiles642cde22021-02-23 14:57:01 -05001244 // TODO(skia:11319): this optimization logic is redundant with the static-switch
1245 // optimization code found in SwitchStatement.cpp.
John Stilesa5a97b42020-08-18 11:19:07 -04001246 SwitchStatement& s = stmt->as<SwitchStatement>();
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001247 int64_t switchValue;
Ethan Nicholasc0f98152021-02-05 16:21:10 -05001248 if (ConstantFolder::GetConstantInt(*s.value(), &switchValue)) {
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001249 // switch is constant, replace it with the case that matches
1250 bool found = false;
1251 SwitchCase* defaultCase = nullptr;
John Stiles2d4f9592020-10-30 10:29:12 -04001252 for (const std::unique_ptr<SwitchCase>& c : s.cases()) {
1253 if (!c->value()) {
1254 defaultCase = c.get();
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001255 continue;
1256 }
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001257 int64_t caseValue;
Ethan Nicholasc0f98152021-02-05 16:21:10 -05001258 SkAssertResult(ConstantFolder::GetConstantInt(*c->value(), &caseValue));
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001259 if (caseValue == switchValue) {
John Stiles642cde22021-02-23 14:57:01 -05001260 std::unique_ptr<Statement> newBlock =
1261 SwitchStatement::BlockForCase(&s.cases(), c.get(), s.symbols());
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001262 if (newBlock) {
Brian Osman010ce6a2020-10-19 16:34:10 -04001263 (*iter)->setStatement(std::move(newBlock), usage);
John Stiles9d944232020-08-19 09:56:49 -04001264 found = true;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001265 break;
1266 } else {
John Stilesd6a5f4492021-02-11 15:46:11 -05001267 if (s.isStatic() &&
John Stilesd1204642021-02-17 16:30:02 -05001268 !fContext->fConfig->fSettings.fPermitInvalidStaticTests) {
John Stilesd6a5f4492021-02-11 15:46:11 -05001269 auto [iter, didInsert] = optimizationContext->fSilences.insert(&s);
1270 if (didInsert) {
1271 this->error(s.fOffset, "static switch contains non-static "
John Stiles04ca41a2021-02-23 09:58:04 -05001272 "conditional exit");
John Stilesd6a5f4492021-02-11 15:46:11 -05001273 }
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001274 }
1275 return; // can't simplify
1276 }
1277 }
1278 }
1279 if (!found) {
1280 // no matching case. use default if it exists, or kill the whole thing
1281 if (defaultCase) {
John Stiles642cde22021-02-23 14:57:01 -05001282 std::unique_ptr<Statement> newBlock =
1283 SwitchStatement::BlockForCase(&s.cases(), defaultCase, s.symbols());
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001284 if (newBlock) {
Brian Osman010ce6a2020-10-19 16:34:10 -04001285 (*iter)->setStatement(std::move(newBlock), usage);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001286 } else {
John Stilesd6a5f4492021-02-11 15:46:11 -05001287 if (s.isStatic() &&
John Stilesd1204642021-02-17 16:30:02 -05001288 !fContext->fConfig->fSettings.fPermitInvalidStaticTests) {
John Stilesd6a5f4492021-02-11 15:46:11 -05001289 auto [iter, didInsert] = optimizationContext->fSilences.insert(&s);
1290 if (didInsert) {
1291 this->error(s.fOffset, "static switch contains non-static "
John Stiles04ca41a2021-02-23 09:58:04 -05001292 "conditional exit");
John Stilesd6a5f4492021-02-11 15:46:11 -05001293 }
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001294 }
1295 return; // can't simplify
1296 }
1297 } else {
Brian Osman010ce6a2020-10-19 16:34:10 -04001298 (*iter)->setStatement(std::make_unique<Nop>(), usage);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001299 }
1300 }
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001301 optimizationContext->fUpdated = true;
1302 optimizationContext->fNeedsRescan = true;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001303 }
1304 break;
1305 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001306 case Statement::Kind::kExpression: {
John Stilesa5a97b42020-08-18 11:19:07 -04001307 ExpressionStatement& e = stmt->as<ExpressionStatement>();
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001308 SkASSERT((*iter)->statement()->get() == &e);
Ethan Nicholasd503a5a2020-09-30 09:29:55 -04001309 if (!e.expression()->hasSideEffects()) {
Ethan Nicholascb670962017-04-20 19:31:52 -04001310 // Expression statement with no side effects, kill it
Ethan Nicholasd503a5a2020-09-30 09:29:55 -04001311 if (!b.tryRemoveExpressionBefore(iter, e.expression().get())) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001312 optimizationContext->fNeedsRescan = true;
Ethan Nicholascb670962017-04-20 19:31:52 -04001313 }
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001314 SkASSERT((*iter)->statement()->get() == stmt);
Brian Osman010ce6a2020-10-19 16:34:10 -04001315 (*iter)->setStatement(std::make_unique<Nop>(), usage);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001316 optimizationContext->fUpdated = true;
Ethan Nicholascb670962017-04-20 19:31:52 -04001317 }
1318 break;
1319 }
1320 default:
1321 break;
1322 }
1323}
1324
Brian Osman010ce6a2020-10-19 16:34:10 -04001325bool Compiler::scanCFG(FunctionDefinition& f, ProgramUsage* usage) {
John Stiles0cc193a2020-09-09 09:39:34 -04001326 bool madeChanges = false;
1327
Ethan Nicholascb670962017-04-20 19:31:52 -04001328 CFG cfg = CFGGenerator().getCFG(f);
1329 this->computeDataFlow(&cfg);
ethannicholas22f939e2016-10-13 13:25:34 -07001330
John Stiles66c53b92021-02-20 08:00:43 -05001331 if (fContext->fConfig->fSettings.fDeadCodeElimination) {
1332 // Check for unreachable code.
1333 for (size_t i = 0; i < cfg.fBlocks.size(); i++) {
1334 const BasicBlock& block = cfg.fBlocks[i];
1335 if (!block.fIsReachable && !block.fAllowUnreachable && block.fNodes.size()) {
1336 const BasicBlock::Node& node = block.fNodes[0];
1337 int offset = node.isStatement() ? (*node.statement())->fOffset
1338 : (*node.expression())->fOffset;
1339 this->error(offset, String("unreachable"));
1340 }
ethannicholas22f939e2016-10-13 13:25:34 -07001341 }
1342 }
1343 if (fErrorCount) {
John Stiles0cc193a2020-09-09 09:39:34 -04001344 return madeChanges;
ethannicholas22f939e2016-10-13 13:25:34 -07001345 }
1346
Ethan Nicholascb670962017-04-20 19:31:52 -04001347 // check for dead code & undefined variables, perform constant propagation
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001348 OptimizationContext optimizationContext;
Brian Osman010ce6a2020-10-19 16:34:10 -04001349 optimizationContext.fUsage = usage;
John Stiles7d3f0892020-11-03 11:35:01 -05001350 SkBitSet eliminatedBlockIds(cfg.fBlocks.size());
Ethan Nicholascb670962017-04-20 19:31:52 -04001351 do {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001352 if (optimizationContext.fNeedsRescan) {
Ethan Nicholascb670962017-04-20 19:31:52 -04001353 cfg = CFGGenerator().getCFG(f);
1354 this->computeDataFlow(&cfg);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001355 optimizationContext.fNeedsRescan = false;
Ethan Nicholas113628d2017-02-02 16:11:39 -05001356 }
Ethan Nicholascb670962017-04-20 19:31:52 -04001357
John Stiles7d3f0892020-11-03 11:35:01 -05001358 eliminatedBlockIds.reset();
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001359 optimizationContext.fUpdated = false;
John Stiles7d3f0892020-11-03 11:35:01 -05001360
1361 for (BlockId blockId = 0; blockId < cfg.fBlocks.size(); ++blockId) {
1362 if (eliminatedBlockIds.test(blockId)) {
1363 // We reached a block ID that might have been eliminated. Be cautious and rescan.
1364 optimizationContext.fUpdated = true;
1365 optimizationContext.fNeedsRescan = true;
1366 break;
1367 }
1368
1369 BasicBlock& b = cfg.fBlocks[blockId];
John Stiles66c53b92021-02-20 08:00:43 -05001370 if (fContext->fConfig->fSettings.fDeadCodeElimination) {
1371 if (blockId > 0 && !b.fIsReachable) {
1372 // Block was reachable before optimization, but has since become unreachable. In
1373 // addition to being dead code, it's broken - since control flow can't reach it,
1374 // no prior variable definitions can reach it, and therefore variables might
1375 // look to have not been properly assigned. Kill it by replacing all statements
1376 // with Nops.
1377 for (BasicBlock::Node& node : b.fNodes) {
1378 if (node.isStatement() && !(*node.statement())->is<Nop>()) {
1379 // Eliminating a node runs the risk of eliminating that node's exits as
1380 // well. Keep track of this and do a rescan if we are about to access
1381 // one of these.
1382 for (BlockId id : b.fExits) {
1383 eliminatedBlockIds.set(id);
1384 }
1385 node.setStatement(std::make_unique<Nop>(), usage);
1386 madeChanges = true;
John Stiles7d3f0892020-11-03 11:35:01 -05001387 }
Ethan Nicholas1de14812020-06-19 15:32:49 -04001388 }
John Stiles66c53b92021-02-20 08:00:43 -05001389 continue;
Ethan Nicholas1de14812020-06-19 15:32:49 -04001390 }
Ethan Nicholas1de14812020-06-19 15:32:49 -04001391 }
Ethan Nicholascb670962017-04-20 19:31:52 -04001392 DefinitionMap definitions = b.fBefore;
1393
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001394 for (auto iter = b.fNodes.begin(); iter != b.fNodes.end() &&
1395 !optimizationContext.fNeedsRescan; ++iter) {
John Stiles70025e52020-09-28 16:08:58 -04001396 if (iter->isExpression()) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001397 this->simplifyExpression(definitions, b, &iter, &optimizationContext);
Ethan Nicholascb670962017-04-20 19:31:52 -04001398 } else {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001399 this->simplifyStatement(definitions, b, &iter, &optimizationContext);
Ethan Nicholascb670962017-04-20 19:31:52 -04001400 }
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001401 if (optimizationContext.fNeedsRescan) {
Ethan Nicholas4b330df2017-05-17 10:52:55 -04001402 break;
1403 }
John Stilese8a24922021-02-08 17:54:08 -05001404 definitions.addDefinitions(*fContext, *iter);
Ethan Nicholascb670962017-04-20 19:31:52 -04001405 }
Brian Osman01a3eb42020-09-14 11:32:49 -04001406
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001407 if (optimizationContext.fNeedsRescan) {
Brian Osman01a3eb42020-09-14 11:32:49 -04001408 break;
1409 }
Ethan Nicholascb670962017-04-20 19:31:52 -04001410 }
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001411 madeChanges |= optimizationContext.fUpdated;
1412 } while (optimizationContext.fUpdated);
1413 SkASSERT(!optimizationContext.fNeedsRescan);
ethannicholas22f939e2016-10-13 13:25:34 -07001414
1415 // check for missing return
John Stiles54e7c052021-01-11 14:22:36 -05001416 if (f.declaration().returnType() != *fContext->fTypes.fVoid) {
John Stiles61e75e32020-10-01 15:42:37 -04001417 if (cfg.fBlocks[cfg.fExit].fIsReachable) {
Ethan Nicholas0a5d0962020-10-14 13:33:18 -04001418 this->error(f.fOffset, String("function '" + String(f.declaration().name()) +
Ethan Nicholasdb80f692019-11-22 14:06:12 -05001419 "' can exit without returning a value"));
ethannicholas22f939e2016-10-13 13:25:34 -07001420 }
1421 }
John Stiles0cc193a2020-09-09 09:39:34 -04001422
1423 return madeChanges;
ethannicholas22f939e2016-10-13 13:25:34 -07001424}
1425
Brian Osman32d53552020-09-23 13:55:20 -04001426std::unique_ptr<Program> Compiler::convertProgram(
John Stilesdbd4e6f2021-02-16 13:29:15 -05001427 ProgramKind kind,
Brian Osman32d53552020-09-23 13:55:20 -04001428 String text,
1429 const Program::Settings& settings,
Brian Osmanbe0b3b72021-01-06 14:27:35 -05001430 const std::vector<std::unique_ptr<ExternalFunction>>* externalFunctions) {
Leon Scrogginsb66214e2021-02-11 17:14:18 -05001431 ATRACE_ANDROID_FRAMEWORK("SkSL::Compiler::convertProgram");
1432
John Stilesdbd4e6f2021-02-16 13:29:15 -05001433 SkASSERT(!externalFunctions || (kind == ProgramKind::kGeneric));
Ethan Nicholas91164d12019-05-15 15:29:54 -04001434
Brian Osman0006ad02020-11-18 15:38:39 -05001435 // Loading and optimizing our base module might reset the inliner, so do that first,
1436 // *then* configure the inliner with the settings for this program.
1437 const ParsedModule& baseModule = this->moduleForProgramKind(kind);
1438
John Stiles270cec22021-02-17 12:59:36 -05001439 // Update our context to point to the program configuration for the duration of compilation.
1440 auto config = std::make_unique<ProgramConfig>(ProgramConfig{kind, settings});
1441
1442 SkASSERT(!fContext->fConfig);
1443 fContext->fConfig = config.get();
1444 SK_AT_SCOPE_EXIT(fContext->fConfig = nullptr);
1445
ethannicholasb3058bd2016-07-01 08:22:01 -07001446 fErrorText = "";
1447 fErrorCount = 0;
John Stilesd1204642021-02-17 16:30:02 -05001448 fInliner.reset(fIRGenerator->fModifiers.get());
Brian Osman88cda172020-10-09 12:05:16 -04001449
1450 // Not using AutoSource, because caller is likely to call errorText() if we fail to compile
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001451 std::unique_ptr<String> textPtr(new String(std::move(text)));
1452 fSource = textPtr.get();
Brian Osman88cda172020-10-09 12:05:16 -04001453
John Stiles5c7bb322020-10-22 11:09:15 -04001454 // Enable node pooling while converting and optimizing the program for a performance boost.
1455 // The Program will take ownership of the pool.
Brian Osman28f702c2021-02-02 11:52:07 -05001456 std::unique_ptr<Pool> pool;
1457 if (fCaps->useNodePools()) {
1458 pool = Pool::Create();
1459 pool->attachToThread();
1460 }
John Stilesd1204642021-02-17 16:30:02 -05001461 IRGenerator::IRBundle ir = fIRGenerator->convertProgram(baseModule, /*isBuiltinCode=*/false,
1462 textPtr->c_str(), textPtr->size(),
1463 externalFunctions);
John Stiles270cec22021-02-17 12:59:36 -05001464 auto program = std::make_unique<Program>(std::move(textPtr),
1465 std::move(config),
Brian Osmand7e76592020-11-02 12:26:22 -05001466 fCaps,
John Stiles5c7bb322020-10-22 11:09:15 -04001467 fContext,
1468 std::move(ir.fElements),
Brian Osman133724c2020-10-28 14:14:39 -04001469 std::move(ir.fSharedElements),
John Stiles5c7bb322020-10-22 11:09:15 -04001470 std::move(ir.fModifiers),
1471 std::move(ir.fSymbolTable),
1472 std::move(pool),
1473 ir.fInputs);
1474 bool success = false;
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001475 if (fErrorCount) {
John Stiles5c7bb322020-10-22 11:09:15 -04001476 // Do not return programs that failed to compile.
Brian Osman4f065e22021-02-13 01:06:03 +00001477 } else if (settings.fOptimize && !this->optimize(*program)) {
John Stiles5c7bb322020-10-22 11:09:15 -04001478 // Do not return programs that failed to optimize.
1479 } else {
1480 // We have a successful program!
1481 success = true;
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001482 }
John Stiles5c7bb322020-10-22 11:09:15 -04001483
Brian Osman28f702c2021-02-02 11:52:07 -05001484 if (program->fPool) {
1485 program->fPool->detachFromThread();
1486 }
John Stiles5c7bb322020-10-22 11:09:15 -04001487 return success ? std::move(program) : nullptr;
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001488}
1489
John Stilesbb1505f2021-02-12 09:17:53 -05001490void Compiler::verifyStaticTests(const Program& program) {
1491 class StaticTestVerifier : public ProgramVisitor {
1492 public:
1493 StaticTestVerifier(ErrorReporter* r) : fReporter(r) {}
1494
1495 using ProgramVisitor::visitProgramElement;
1496
1497 bool visitStatement(const Statement& stmt) override {
1498 switch (stmt.kind()) {
1499 case Statement::Kind::kIf:
1500 if (stmt.as<IfStatement>().isStatic()) {
1501 fReporter->error(stmt.fOffset, "static if has non-static test");
1502 }
1503 break;
1504
1505 case Statement::Kind::kSwitch:
1506 if (stmt.as<SwitchStatement>().isStatic()) {
1507 fReporter->error(stmt.fOffset, "static switch has non-static test");
1508 }
1509 break;
1510
1511 default:
1512 break;
1513 }
1514 return INHERITED::visitStatement(stmt);
1515 }
1516
John Stiles59e34562021-02-12 16:56:39 -05001517 bool visitExpression(const Expression&) override {
1518 // We aren't looking for anything inside an Expression, so skip them entirely.
1519 return false;
1520 }
1521
John Stilesbb1505f2021-02-12 09:17:53 -05001522 private:
1523 using INHERITED = ProgramVisitor;
1524 ErrorReporter* fReporter;
1525 };
1526
1527 // If invalid static tests are permitted, we don't need to check anything.
John Stilesd1204642021-02-17 16:30:02 -05001528 if (fContext->fConfig->fSettings.fPermitInvalidStaticTests) {
John Stilesbb1505f2021-02-12 09:17:53 -05001529 return;
1530 }
1531
1532 // Check all of the program's owned elements. (Built-in elements are assumed to be valid.)
1533 StaticTestVerifier visitor{this};
1534 for (const std::unique_ptr<ProgramElement>& element : program.ownedElements()) {
1535 if (element->is<FunctionDefinition>()) {
1536 visitor.visitProgramElement(*element);
1537 }
1538 }
1539}
1540
Brian Osman0006ad02020-11-18 15:38:39 -05001541bool Compiler::optimize(LoadedModule& module) {
1542 SkASSERT(!fErrorCount);
Brian Osman0006ad02020-11-18 15:38:39 -05001543
John Stiles270cec22021-02-17 12:59:36 -05001544 // Create a temporary program configuration with default settings.
1545 ProgramConfig config;
1546 config.fKind = module.fKind;
1547
1548 // Update our context to point to this configuration for the duration of compilation.
1549 SkASSERT(!fContext->fConfig);
1550 fContext->fConfig = &config;
1551 SK_AT_SCOPE_EXIT(fContext->fConfig = nullptr);
1552
John Stilesd1204642021-02-17 16:30:02 -05001553 // Reset the Inliner.
1554 fInliner.reset(fModifiers.back().get());
John Stiles270cec22021-02-17 12:59:36 -05001555
1556 std::unique_ptr<ProgramUsage> usage = Analysis::GetUsage(module);
Brian Osman0006ad02020-11-18 15:38:39 -05001557
1558 while (fErrorCount == 0) {
1559 bool madeChanges = false;
1560
1561 // Scan and optimize based on the control-flow graph for each function.
1562 for (const auto& element : module.fElements) {
1563 if (element->is<FunctionDefinition>()) {
1564 madeChanges |= this->scanCFG(element->as<FunctionDefinition>(), usage.get());
1565 }
1566 }
1567
1568 // Perform inline-candidate analysis and inline any functions deemed suitable.
John Stiles78047582020-12-16 16:17:41 -05001569 madeChanges |= fInliner.analyze(module.fElements, module.fSymbols, usage.get());
Brian Osman0006ad02020-11-18 15:38:39 -05001570
1571 if (!madeChanges) {
1572 break;
1573 }
1574 }
1575 return fErrorCount == 0;
1576}
1577
Ethan Nicholas00543112018-07-31 09:44:36 -04001578bool Compiler::optimize(Program& program) {
1579 SkASSERT(!fErrorCount);
Brian Osman010ce6a2020-10-19 16:34:10 -04001580 ProgramUsage* usage = program.fUsage.get();
John Stiles7954d6c2020-09-01 10:53:02 -04001581
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001582 while (fErrorCount == 0) {
1583 bool madeChanges = false;
John Stiles7954d6c2020-09-01 10:53:02 -04001584
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001585 // Scan and optimize based on the control-flow graph for each function.
Brian Osman133724c2020-10-28 14:14:39 -04001586 for (const auto& element : program.ownedElements()) {
Brian Osman1179fcf2020-10-08 16:04:40 -04001587 if (element->is<FunctionDefinition>()) {
Brian Osman010ce6a2020-10-19 16:34:10 -04001588 madeChanges |= this->scanCFG(element->as<FunctionDefinition>(), usage);
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001589 }
1590 }
1591
1592 // Perform inline-candidate analysis and inline any functions deemed suitable.
John Stiles78047582020-12-16 16:17:41 -05001593 madeChanges |= fInliner.analyze(program.ownedElements(), program.fSymbols, usage);
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001594
1595 // Remove dead functions. We wait until after analysis so that we still report errors,
1596 // even in unused code.
John Stiles270cec22021-02-17 12:59:36 -05001597 if (program.fConfig->fSettings.fRemoveDeadFunctions) {
Brian Osman133724c2020-10-28 14:14:39 -04001598 auto isDeadFunction = [&](const ProgramElement* element) {
1599 if (!element->is<FunctionDefinition>()) {
1600 return false;
1601 }
1602 const FunctionDefinition& fn = element->as<FunctionDefinition>();
1603 if (fn.declaration().name() != "main" && usage->get(fn.declaration()) == 0) {
1604 usage->remove(*element);
1605 madeChanges = true;
1606 return true;
1607 }
1608 return false;
1609 };
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001610 program.fElements.erase(
Brian Osman133724c2020-10-28 14:14:39 -04001611 std::remove_if(program.fElements.begin(), program.fElements.end(),
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001612 [&](const std::unique_ptr<ProgramElement>& element) {
Brian Osman133724c2020-10-28 14:14:39 -04001613 return isDeadFunction(element.get());
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001614 }),
1615 program.fElements.end());
Brian Osman133724c2020-10-28 14:14:39 -04001616 program.fSharedElements.erase(
1617 std::remove_if(program.fSharedElements.begin(), program.fSharedElements.end(),
1618 isDeadFunction),
1619 program.fSharedElements.end());
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001620 }
1621
John Stiles270cec22021-02-17 12:59:36 -05001622 if (program.fConfig->fKind != ProgramKind::kFragmentProcessor) {
Brian Osmanc0213602020-10-06 14:43:32 -04001623 // Remove declarations of dead global variables
Brian Osman133724c2020-10-28 14:14:39 -04001624 auto isDeadVariable = [&](const ProgramElement* element) {
1625 if (!element->is<GlobalVarDeclaration>()) {
1626 return false;
1627 }
1628 const GlobalVarDeclaration& global = element->as<GlobalVarDeclaration>();
1629 const VarDeclaration& varDecl = global.declaration()->as<VarDeclaration>();
1630 if (usage->isDead(varDecl.var())) {
1631 madeChanges = true;
1632 return true;
1633 }
1634 return false;
1635 };
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001636 program.fElements.erase(
1637 std::remove_if(program.fElements.begin(), program.fElements.end(),
1638 [&](const std::unique_ptr<ProgramElement>& element) {
Brian Osman133724c2020-10-28 14:14:39 -04001639 return isDeadVariable(element.get());
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001640 }),
1641 program.fElements.end());
Brian Osman133724c2020-10-28 14:14:39 -04001642 program.fSharedElements.erase(
1643 std::remove_if(program.fSharedElements.begin(), program.fSharedElements.end(),
1644 isDeadVariable),
1645 program.fSharedElements.end());
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001646 }
John Stiles73a6bff2020-09-09 13:40:37 -04001647
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001648 if (!madeChanges) {
1649 break;
Ethan Nicholas0dc80872019-02-08 15:46:24 -05001650 }
Ethan Nicholas00543112018-07-31 09:44:36 -04001651 }
John Stilesbb1505f2021-02-12 09:17:53 -05001652
1653 if (fErrorCount == 0) {
1654 this->verifyStaticTests(program);
1655 }
1656
Ethan Nicholas00543112018-07-31 09:44:36 -04001657 return fErrorCount == 0;
1658}
1659
Brian Osmanfb32ddf2019-06-18 10:14:20 -04001660#if defined(SKSL_STANDALONE) || SK_SUPPORT_GPU
1661
Ethan Nicholas00543112018-07-31 09:44:36 -04001662bool Compiler::toSPIRV(Program& program, OutputStream& out) {
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001663#ifdef SK_ENABLE_SPIRV_VALIDATION
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001664 StringStream buffer;
Brian Osman88cda172020-10-09 12:05:16 -04001665 AutoSource as(this, program.fSource.get());
Brian Osman8b43dad2020-10-09 13:31:42 -04001666 SPIRVCodeGenerator cg(fContext.get(), &program, this, &buffer);
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001667 bool result = cg.generateCode();
John Stiles270cec22021-02-17 12:59:36 -05001668 if (result && program.fConfig->fSettings.fValidateSPIRV) {
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001669 spvtools::SpirvTools tools(SPV_ENV_VULKAN_1_0);
Ethan Nicholas762466e2017-06-29 10:03:38 -04001670 const String& data = buffer.str();
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001671 SkASSERT(0 == data.size() % 4);
Brian Osman8d09d4a2020-11-24 15:51:06 -05001672 String errors;
1673 auto dumpmsg = [&errors](spv_message_level_t, const char*, const spv_position_t&,
1674 const char* m) {
1675 errors.appendf("SPIR-V validation error: %s\n", m);
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001676 };
1677 tools.SetMessageConsumer(dumpmsg);
Brian Osman8d09d4a2020-11-24 15:51:06 -05001678
1679 // Verify that the SPIR-V we produced is valid. At runtime, we will abort() with a message
1680 // explaining the error. In standalone mode (skslc), we will send the message, plus the
1681 // entire disassembled SPIR-V (for easier context & debugging) as *our* error message.
1682 result = tools.Validate((const uint32_t*) data.c_str(), data.size() / 4);
1683
1684 if (!result) {
1685#if defined(SKSL_STANDALONE)
1686 // Convert the string-stream to a SPIR-V disassembly.
1687 std::string disassembly;
1688 if (tools.Disassemble((const uint32_t*)data.data(), data.size() / 4, &disassembly)) {
1689 errors.append(disassembly);
1690 }
1691 this->error(-1, errors);
1692#else
1693 SkDEBUGFAILF("%s", errors.c_str());
1694#endif
1695 }
Ethan Nicholas762466e2017-06-29 10:03:38 -04001696 out.write(data.c_str(), data.size());
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001697 }
1698#else
Brian Osman88cda172020-10-09 12:05:16 -04001699 AutoSource as(this, program.fSource.get());
Brian Osman8b43dad2020-10-09 13:31:42 -04001700 SPIRVCodeGenerator cg(fContext.get(), &program, this, &out);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001701 bool result = cg.generateCode();
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001702#endif
Ethan Nicholasce33f102016-12-09 17:22:59 -05001703 return result;
1704}
1705
Ethan Nicholas00543112018-07-31 09:44:36 -04001706bool Compiler::toSPIRV(Program& program, String* out) {
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001707 StringStream buffer;
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001708 bool result = this->toSPIRV(program, buffer);
1709 if (result) {
Ethan Nicholas762466e2017-06-29 10:03:38 -04001710 *out = buffer.str();
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001711 }
1712 return result;
1713}
1714
Ethan Nicholas00543112018-07-31 09:44:36 -04001715bool Compiler::toGLSL(Program& program, OutputStream& out) {
Leon Scrogginsb66214e2021-02-11 17:14:18 -05001716 ATRACE_ANDROID_FRAMEWORK("SkSL::Compiler::toGLSL");
Brian Osman88cda172020-10-09 12:05:16 -04001717 AutoSource as(this, program.fSource.get());
Ethan Nicholas26a9aad2018-03-27 14:10:52 -04001718 GLSLCodeGenerator cg(fContext.get(), &program, this, &out);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001719 bool result = cg.generateCode();
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001720 return result;
1721}
1722
Ethan Nicholas00543112018-07-31 09:44:36 -04001723bool Compiler::toGLSL(Program& program, String* out) {
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001724 StringStream buffer;
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001725 bool result = this->toGLSL(program, buffer);
1726 if (result) {
Ethan Nicholas762466e2017-06-29 10:03:38 -04001727 *out = buffer.str();
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001728 }
1729 return result;
1730}
1731
Brian Osmanc0243912020-02-19 15:35:26 -05001732bool Compiler::toHLSL(Program& program, String* out) {
1733 String spirv;
1734 if (!this->toSPIRV(program, &spirv)) {
1735 return false;
1736 }
1737
1738 return SPIRVtoHLSL(spirv, out);
1739}
1740
Ethan Nicholas00543112018-07-31 09:44:36 -04001741bool Compiler::toMetal(Program& program, OutputStream& out) {
Ethan Nicholas26a9aad2018-03-27 14:10:52 -04001742 MetalCodeGenerator cg(fContext.get(), &program, this, &out);
Ethan Nicholascc305772017-10-13 16:17:45 -04001743 bool result = cg.generateCode();
Ethan Nicholascc305772017-10-13 16:17:45 -04001744 return result;
1745}
1746
Ethan Nicholas00543112018-07-31 09:44:36 -04001747bool Compiler::toMetal(Program& program, String* out) {
Timothy Liangb8eeb802018-07-23 16:46:16 -04001748 StringStream buffer;
1749 bool result = this->toMetal(program, buffer);
1750 if (result) {
1751 *out = buffer.str();
1752 }
1753 return result;
1754}
1755
Greg Daniela28ea672020-09-25 11:12:56 -04001756#if defined(SKSL_STANDALONE) || GR_TEST_UTILS
Ethan Nicholas00543112018-07-31 09:44:36 -04001757bool Compiler::toCPP(Program& program, String name, OutputStream& out) {
Brian Osman88cda172020-10-09 12:05:16 -04001758 AutoSource as(this, program.fSource.get());
Ethan Nicholas26a9aad2018-03-27 14:10:52 -04001759 CPPCodeGenerator cg(fContext.get(), &program, this, name, &out);
Ethan Nicholas762466e2017-06-29 10:03:38 -04001760 bool result = cg.generateCode();
Ethan Nicholas762466e2017-06-29 10:03:38 -04001761 return result;
1762}
1763
Ethan Nicholas00543112018-07-31 09:44:36 -04001764bool Compiler::toH(Program& program, String name, OutputStream& out) {
Brian Osman88cda172020-10-09 12:05:16 -04001765 AutoSource as(this, program.fSource.get());
Ethan Nicholas26a9aad2018-03-27 14:10:52 -04001766 HCodeGenerator cg(fContext.get(), &program, this, name, &out);
Ethan Nicholas762466e2017-06-29 10:03:38 -04001767 bool result = cg.generateCode();
Ethan Nicholas00543112018-07-31 09:44:36 -04001768 return result;
1769}
Greg Daniela28ea672020-09-25 11:12:56 -04001770#endif // defined(SKSL_STANDALONE) || GR_TEST_UTILS
Ethan Nicholas00543112018-07-31 09:44:36 -04001771
Ethan Nicholas2a479a52020-08-18 16:29:45 -04001772#endif // defined(SKSL_STANDALONE) || SK_SUPPORT_GPU
Brian Osman2e29ab52019-09-20 12:19:11 -04001773
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001774Position Compiler::position(int offset) {
Ethan Nicholas3c729892020-12-07 12:47:17 -05001775 if (fSource && offset >= 0) {
1776 int line = 1;
1777 int column = 1;
1778 for (int i = 0; i < offset; i++) {
1779 if ((*fSource)[i] == '\n') {
1780 ++line;
1781 column = 1;
1782 }
1783 else {
1784 ++column;
1785 }
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001786 }
Ethan Nicholas3c729892020-12-07 12:47:17 -05001787 return Position(line, column);
1788 } else {
1789 return Position(-1, -1);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001790 }
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001791}
1792
1793void Compiler::error(int offset, String msg) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001794 fErrorCount++;
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001795 Position pos = this->position(offset);
John Stiles8d3642e2021-01-22 09:50:04 -05001796 fErrorTextLength.push_back(fErrorText.length());
Ethan Nicholas3c729892020-12-07 12:47:17 -05001797 fErrorText += "error: " + (pos.fLine >= 1 ? to_string(pos.fLine) + ": " : "") + msg + "\n";
ethannicholasb3058bd2016-07-01 08:22:01 -07001798}
1799
John Stiles8d3642e2021-01-22 09:50:04 -05001800void Compiler::setErrorCount(int c) {
1801 if (c < fErrorCount) {
1802 fErrorText.resize(fErrorTextLength[c]);
1803 fErrorTextLength.resize(c);
1804 fErrorCount = c;
1805 }
1806}
1807
Ethan Nicholas95046142021-01-07 10:57:27 -05001808String Compiler::errorText(bool showCount) {
1809 if (showCount) {
1810 this->writeErrorCount();
1811 }
Ethan Nicholas00543112018-07-31 09:44:36 -04001812 fErrorCount = 0;
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001813 String result = fErrorText;
Ethan Nicholas95046142021-01-07 10:57:27 -05001814 fErrorText = "";
ethannicholasb3058bd2016-07-01 08:22:01 -07001815 return result;
1816}
1817
1818void Compiler::writeErrorCount() {
1819 if (fErrorCount) {
1820 fErrorText += to_string(fErrorCount) + " error";
1821 if (fErrorCount > 1) {
1822 fErrorText += "s";
1823 }
1824 fErrorText += "\n";
1825 }
1826}
1827
John Stilesa6841be2020-08-06 14:11:56 -04001828} // namespace SkSL