blob: 79b48ca2a47f890ca0723063d18b6722b0f24efb [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),
Brian Osmanb06301e2020-11-06 11:45:36 -0500146 TYPE(SubpassInput), TYPE(SubpassInputMS),
147
Brian Osmanb06301e2020-11-06 11:45:36 -0500148 TYPE(Sampler),
149 TYPE(Texture2D),
150 };
151
152 for (const SkSL::Symbol* type : rootTypes) {
153 fRootSymbolTable->addWithoutOwnership(type);
154 }
155 for (const SkSL::Symbol* type : privateTypes) {
156 fPrivateSymbolTable->addWithoutOwnership(type);
157 }
158
159#undef TYPE
ethannicholasb3058bd2016-07-01 08:22:01 -0700160
Brian Osman3887a012020-09-30 13:22:27 -0400161 // sk_Caps is "builtin", but all references to it are resolved to Settings, so we don't need to
162 // treat it as builtin (ie, no need to clone it into the Program).
Brian Osmanb06301e2020-11-06 11:45:36 -0500163 fPrivateSymbolTable->add(
164 std::make_unique<Variable>(/*offset=*/-1,
John Stiles586df952020-11-12 18:27:13 -0500165 fIRGenerator->fModifiers->addToPool(Modifiers()),
Brian Osmanb06301e2020-11-06 11:45:36 -0500166 "sk_Caps",
John Stiles54e7c052021-01-11 14:22:36 -0500167 fContext->fTypes.fSkCaps.get(),
Brian Osmanb06301e2020-11-06 11:45:36 -0500168 /*builtin=*/false,
169 Variable::Storage::kGlobal));
Ethan Nicholas3605ace2016-11-21 15:59:48 -0500170
Brian Osman3d87e9f2020-10-08 11:50:22 -0400171 fRootModule = {fRootSymbolTable, /*fIntrinsics=*/nullptr};
Brian Osmanb06301e2020-11-06 11:45:36 -0500172 fPrivateModule = {fPrivateSymbolTable, /*fIntrinsics=*/nullptr};
ethannicholasb3058bd2016-07-01 08:22:01 -0700173}
174
John Stilesdd13dba2020-10-29 10:45:34 -0400175Compiler::~Compiler() {}
ethannicholasb3058bd2016-07-01 08:22:01 -0700176
Brian Osman56269982020-11-20 12:38:07 -0500177const ParsedModule& Compiler::loadGPUModule() {
178 if (!fGPUModule.fSymbols) {
John Stilesdbd4e6f2021-02-16 13:29:15 -0500179 fGPUModule = this->parseModule(ProgramKind::kFragment, MODULE_DATA(gpu), fPrivateModule);
Brian Osman56269982020-11-20 12:38:07 -0500180 }
181 return fGPUModule;
182}
183
184const ParsedModule& Compiler::loadFragmentModule() {
185 if (!fFragmentModule.fSymbols) {
John Stilesdbd4e6f2021-02-16 13:29:15 -0500186 fFragmentModule = this->parseModule(ProgramKind::kFragment, MODULE_DATA(frag),
Brian Osman56269982020-11-20 12:38:07 -0500187 this->loadGPUModule());
188 }
189 return fFragmentModule;
190}
191
192const ParsedModule& Compiler::loadVertexModule() {
193 if (!fVertexModule.fSymbols) {
John Stilesdbd4e6f2021-02-16 13:29:15 -0500194 fVertexModule = this->parseModule(ProgramKind::kVertex, MODULE_DATA(vert),
Brian Osman56269982020-11-20 12:38:07 -0500195 this->loadGPUModule());
196 }
197 return fVertexModule;
198}
199
Brian Osman88cda172020-10-09 12:05:16 -0400200const ParsedModule& Compiler::loadGeometryModule() {
Brian Osman3d87e9f2020-10-08 11:50:22 -0400201 if (!fGeometryModule.fSymbols) {
John Stilesdbd4e6f2021-02-16 13:29:15 -0500202 fGeometryModule = this->parseModule(ProgramKind::kGeometry, MODULE_DATA(geom),
Brian Osman56269982020-11-20 12:38:07 -0500203 this->loadGPUModule());
Ethan Nicholasc18bb512020-07-28 14:46:53 -0400204 }
Brian Osman88cda172020-10-09 12:05:16 -0400205 return fGeometryModule;
Ethan Nicholasc18bb512020-07-28 14:46:53 -0400206}
207
Brian Osman88cda172020-10-09 12:05:16 -0400208const ParsedModule& Compiler::loadFPModule() {
Brian Osman3d87e9f2020-10-08 11:50:22 -0400209 if (!fFPModule.fSymbols) {
John Stilesdbd4e6f2021-02-16 13:29:15 -0500210 fFPModule = this->parseModule(ProgramKind::kFragmentProcessor, MODULE_DATA(fp),
Brian Osman56269982020-11-20 12:38:07 -0500211 this->loadGPUModule());
Brian Osman8e2ef022020-09-30 13:26:43 -0400212 }
Brian Osman88cda172020-10-09 12:05:16 -0400213 return fFPModule;
Brian Osman8e2ef022020-09-30 13:26:43 -0400214}
215
Brian Osmanb06301e2020-11-06 11:45:36 -0500216const ParsedModule& Compiler::loadPublicModule() {
217 if (!fPublicModule.fSymbols) {
John Stilesdbd4e6f2021-02-16 13:29:15 -0500218 fPublicModule = this->parseModule(ProgramKind::kGeneric, MODULE_DATA(public), fRootModule);
Brian Osmanb06301e2020-11-06 11:45:36 -0500219 }
220 return fPublicModule;
221}
222
Brian Osman91946752020-12-21 13:20:40 -0500223const ParsedModule& Compiler::loadRuntimeEffectModule() {
224 if (!fRuntimeEffectModule.fSymbols) {
John Stilesdbd4e6f2021-02-16 13:29:15 -0500225 fRuntimeEffectModule = this->parseModule(ProgramKind::kRuntimeEffect, MODULE_DATA(runtime),
Brian Osman91946752020-12-21 13:20:40 -0500226 this->loadPublicModule());
Brian Osmanf1319c32020-10-13 09:34:23 -0400227
Brian Osman91946752020-12-21 13:20:40 -0500228 // Add some aliases to the runtime effect module so that it's friendlier, and more like GLSL
John Stiles54e7c052021-01-11 14:22:36 -0500229 fRuntimeEffectModule.fSymbols->addAlias("shader", fContext->fTypes.fFragmentProcessor.get());
Brian Osmanf1319c32020-10-13 09:34:23 -0400230
John Stiles54e7c052021-01-11 14:22:36 -0500231 fRuntimeEffectModule.fSymbols->addAlias("vec2", fContext->fTypes.fFloat2.get());
232 fRuntimeEffectModule.fSymbols->addAlias("vec3", fContext->fTypes.fFloat3.get());
233 fRuntimeEffectModule.fSymbols->addAlias("vec4", fContext->fTypes.fFloat4.get());
Brian Osmanf1319c32020-10-13 09:34:23 -0400234
John Stiles54e7c052021-01-11 14:22:36 -0500235 fRuntimeEffectModule.fSymbols->addAlias("bvec2", fContext->fTypes.fBool2.get());
236 fRuntimeEffectModule.fSymbols->addAlias("bvec3", fContext->fTypes.fBool3.get());
237 fRuntimeEffectModule.fSymbols->addAlias("bvec4", fContext->fTypes.fBool4.get());
Brian Osmanf1319c32020-10-13 09:34:23 -0400238
John Stiles54e7c052021-01-11 14:22:36 -0500239 fRuntimeEffectModule.fSymbols->addAlias("mat2", fContext->fTypes.fFloat2x2.get());
240 fRuntimeEffectModule.fSymbols->addAlias("mat3", fContext->fTypes.fFloat3x3.get());
241 fRuntimeEffectModule.fSymbols->addAlias("mat4", fContext->fTypes.fFloat4x4.get());
Ethan Nicholasc18bb512020-07-28 14:46:53 -0400242 }
Brian Osman91946752020-12-21 13:20:40 -0500243 return fRuntimeEffectModule;
Ethan Nicholasc18bb512020-07-28 14:46:53 -0400244}
245
John Stilesdbd4e6f2021-02-16 13:29:15 -0500246const ParsedModule& Compiler::moduleForProgramKind(ProgramKind kind) {
Brian Osman88cda172020-10-09 12:05:16 -0400247 switch (kind) {
John Stilesdbd4e6f2021-02-16 13:29:15 -0500248 case ProgramKind::kVertex: return this->loadVertexModule(); break;
249 case ProgramKind::kFragment: return this->loadFragmentModule(); break;
250 case ProgramKind::kGeometry: return this->loadGeometryModule(); break;
251 case ProgramKind::kFragmentProcessor: return this->loadFPModule(); break;
252 case ProgramKind::kRuntimeEffect: return this->loadRuntimeEffectModule(); break;
253 case ProgramKind::kGeneric: return this->loadPublicModule(); break;
Brian Osman88cda172020-10-09 12:05:16 -0400254 }
255 SkUNREACHABLE;
Ethan Nicholasc18bb512020-07-28 14:46:53 -0400256}
257
John Stilesdbd4e6f2021-02-16 13:29:15 -0500258LoadedModule Compiler::loadModule(ProgramKind kind,
Brian Osman3d87e9f2020-10-08 11:50:22 -0400259 ModuleData data,
260 std::shared_ptr<SymbolTable> base) {
Brian Osman3d87e9f2020-10-08 11:50:22 -0400261 if (!base) {
Brian Osmanb06301e2020-11-06 11:45:36 -0500262 // NOTE: This is a workaround. The only time 'base' is null is when dehydrating includes.
263 // In that case, skslc doesn't know which module it's preparing, nor what the correct base
264 // module is. We can't use 'Root', because many GPU intrinsics reference private types,
265 // like samplers or textures. Today, 'Private' does contain the union of all known types,
266 // so this is safe. If we ever have types that only exist in 'Public' (for example), this
267 // logic needs to be smarter (by choosing the correct base for the module we're compiling).
268 base = fPrivateSymbolTable;
Brian Osman3d87e9f2020-10-08 11:50:22 -0400269 }
270
271#if defined(SKSL_STANDALONE)
272 SkASSERT(data.fPath);
273 std::ifstream in(data.fPath);
Brian Osmane498b3c2020-09-23 14:42:11 -0400274 std::unique_ptr<String> text = std::make_unique<String>(std::istreambuf_iterator<char>(in),
275 std::istreambuf_iterator<char>());
Ethan Nicholasb33fa3f2020-08-06 13:00:19 -0400276 if (in.rdstate()) {
Brian Osman3d87e9f2020-10-08 11:50:22 -0400277 printf("error reading %s\n", data.fPath);
Ethan Nicholasb33fa3f2020-08-06 13:00:19 -0400278 abort();
279 }
Brian Osmane498b3c2020-09-23 14:42:11 -0400280 const String* source = fRootSymbolTable->takeOwnershipOfString(std::move(text));
Brian Osman88cda172020-10-09 12:05:16 -0400281 AutoSource as(this, source);
John Stilesd1204642021-02-17 16:30:02 -0500282
John Stiles881a10c2020-09-19 10:13:24 -0400283 SkASSERT(fIRGenerator->fCanInline);
284 fIRGenerator->fCanInline = false;
John Stilesd1204642021-02-17 16:30:02 -0500285
286 ProgramConfig config;
287 config.fKind = kind;
288 config.fSettings.fReplaceSettings = false;
289
290 fContext->fConfig = &config;
291 SK_AT_SCOPE_EXIT(fContext->fConfig = nullptr);
John Stilesdbd4e6f2021-02-16 13:29:15 -0500292
Brian Osman88cda172020-10-09 12:05:16 -0400293 ParsedModule baseModule = {base, /*fIntrinsics=*/nullptr};
John Stilesd1204642021-02-17 16:30:02 -0500294 IRGenerator::IRBundle ir = fIRGenerator->convertProgram(baseModule, /*isBuiltinCode=*/true,
295 source->c_str(), source->length(),
296 /*externalFunctions=*/nullptr);
Brian Osman133724c2020-10-28 14:14:39 -0400297 SkASSERT(ir.fSharedElements.empty());
Brian Osman0006ad02020-11-18 15:38:39 -0500298 LoadedModule module = { kind, std::move(ir.fSymbolTable), std::move(ir.fElements) };
John Stiles881a10c2020-09-19 10:13:24 -0400299 fIRGenerator->fCanInline = true;
Ethan Nicholas8da1e652019-05-24 11:01:59 -0400300 if (this->fErrorCount) {
301 printf("Unexpected errors: %s\n", this->fErrorText.c_str());
Brian Osman3d87e9f2020-10-08 11:50:22 -0400302 SkDEBUGFAILF("%s %s\n", data.fPath, this->fErrorText.c_str());
Ethan Nicholas8da1e652019-05-24 11:01:59 -0400303 }
Brian Osman88cda172020-10-09 12:05:16 -0400304 fModifiers.push_back(std::move(ir.fModifiers));
Brian Osman3d87e9f2020-10-08 11:50:22 -0400305#else
306 SkASSERT(data.fData && (data.fSize != 0));
307 Rehydrator rehydrator(fContext.get(), fIRGenerator->fModifiers.get(), base, this,
308 data.fData, data.fSize);
Brian Osman0006ad02020-11-18 15:38:39 -0500309 LoadedModule module = { kind, rehydrator.symbolTable(), rehydrator.elements() };
Brian Osman3d87e9f2020-10-08 11:50:22 -0400310 fModifiers.push_back(fIRGenerator->releaseModifiers());
311#endif
312
313 return module;
314}
315
John Stilesdbd4e6f2021-02-16 13:29:15 -0500316ParsedModule Compiler::parseModule(ProgramKind kind, ModuleData data, const ParsedModule& base) {
Brian Osman0006ad02020-11-18 15:38:39 -0500317 LoadedModule module = this->loadModule(kind, data, base.fSymbols);
318 this->optimize(module);
Brian Osman3d87e9f2020-10-08 11:50:22 -0400319
320 // For modules that just declare (but don't define) intrinsic functions, there will be no new
321 // program elements. In that case, we can share our parent's intrinsic map:
Brian Osman0006ad02020-11-18 15:38:39 -0500322 if (module.fElements.empty()) {
323 return {module.fSymbols, base.fIntrinsics};
Brian Osman3d87e9f2020-10-08 11:50:22 -0400324 }
325
326 auto intrinsics = std::make_shared<IRIntrinsicMap>(base.fIntrinsics.get());
327
328 // Now, transfer all of the program elements to an intrinsic map. This maps certain types of
329 // global objects to the declaring ProgramElement.
Brian Osman0006ad02020-11-18 15:38:39 -0500330 for (std::unique_ptr<ProgramElement>& element : module.fElements) {
Brian Osman3d87e9f2020-10-08 11:50:22 -0400331 switch (element->kind()) {
332 case ProgramElement::Kind::kFunction: {
333 const FunctionDefinition& f = element->as<FunctionDefinition>();
Ethan Nicholas0a5d0962020-10-14 13:33:18 -0400334 SkASSERT(f.declaration().isBuiltin());
335 intrinsics->insertOrDie(f.declaration().description(), std::move(element));
Brian Osman3d87e9f2020-10-08 11:50:22 -0400336 break;
337 }
John Stiles569249b2020-11-03 12:18:22 -0500338 case ProgramElement::Kind::kFunctionPrototype: {
339 // These are already in the symbol table.
340 break;
341 }
Brian Osman3d87e9f2020-10-08 11:50:22 -0400342 case ProgramElement::Kind::kEnum: {
343 const Enum& e = element->as<Enum>();
344 SkASSERT(e.isBuiltin());
345 intrinsics->insertOrDie(e.typeName(), std::move(element));
346 break;
347 }
348 case ProgramElement::Kind::kGlobalVar: {
Ethan Nicholasc51f33e2020-10-13 13:49:44 -0400349 const GlobalVarDeclaration& global = element->as<GlobalVarDeclaration>();
350 const Variable& var = global.declaration()->as<VarDeclaration>().var();
351 SkASSERT(var.isBuiltin());
352 intrinsics->insertOrDie(var.name(), std::move(element));
Brian Osman3d87e9f2020-10-08 11:50:22 -0400353 break;
354 }
355 case ProgramElement::Kind::kInterfaceBlock: {
Ethan Nicholaseaf47882020-10-15 10:10:08 -0400356 const Variable& var = element->as<InterfaceBlock>().variable();
357 SkASSERT(var.isBuiltin());
358 intrinsics->insertOrDie(var.name(), std::move(element));
Brian Osman3d87e9f2020-10-08 11:50:22 -0400359 break;
360 }
361 default:
362 printf("Unsupported element: %s\n", element->description().c_str());
363 SkASSERT(false);
364 break;
365 }
366 }
367
Brian Osman0006ad02020-11-18 15:38:39 -0500368 return {module.fSymbols, std::move(intrinsics)};
Ethan Nicholas8da1e652019-05-24 11:01:59 -0400369}
370
John Stilese6150002020-10-05 12:03:53 -0400371void Compiler::scanCFG(CFG* cfg, BlockId blockId, SkBitSet* processedSet) {
ethannicholas22f939e2016-10-13 13:25:34 -0700372 BasicBlock& block = cfg->fBlocks[blockId];
373
374 // compute definitions after this block
Ethan Nicholas86a43402017-01-19 13:32:00 -0500375 DefinitionMap after = block.fBefore;
ethannicholas22f939e2016-10-13 13:25:34 -0700376 for (const BasicBlock::Node& n : block.fNodes) {
John Stilese8a24922021-02-08 17:54:08 -0500377 after.addDefinitions(*fContext, n);
ethannicholas22f939e2016-10-13 13:25:34 -0700378 }
379
380 // propagate definitions to exits
381 for (BlockId exitId : block.fExits) {
Ethan Nicholas26a9aad2018-03-27 14:10:52 -0400382 if (exitId == blockId) {
383 continue;
384 }
ethannicholas22f939e2016-10-13 13:25:34 -0700385 BasicBlock& exit = cfg->fBlocks[exitId];
John Stiles65b48272020-12-22 17:18:34 -0500386 for (const auto& [var, e1] : after) {
John Stiles796cdb72020-10-08 12:06:53 -0400387 std::unique_ptr<Expression>** exitDef = exit.fBefore.find(var);
388 if (!exitDef) {
John Stilese6150002020-10-05 12:03:53 -0400389 // exit has no definition for it, just copy it and reprocess exit block
390 processedSet->reset(exitId);
John Stilese8a24922021-02-08 17:54:08 -0500391 exit.fBefore.set(var, e1);
ethannicholas22f939e2016-10-13 13:25:34 -0700392 } else {
Ethan Nicholas86a43402017-01-19 13:32:00 -0500393 // exit has a (possibly different) value already defined
John Stiles796cdb72020-10-08 12:06:53 -0400394 std::unique_ptr<Expression>* e2 = *exitDef;
ethannicholas22f939e2016-10-13 13:25:34 -0700395 if (e1 != e2) {
John Stilese6150002020-10-05 12:03:53 -0400396 // definition has changed, merge and reprocess the exit block
397 processedSet->reset(exitId);
Ethan Nicholasaf197692017-02-27 13:26:45 -0500398 if (e1 && e2) {
John Stiles796cdb72020-10-08 12:06:53 -0400399 *exitDef = (std::unique_ptr<Expression>*)&fContext->fDefined_Expression;
Ethan Nicholasaf197692017-02-27 13:26:45 -0500400 } else {
John Stiles796cdb72020-10-08 12:06:53 -0400401 *exitDef = nullptr;
Ethan Nicholasaf197692017-02-27 13:26:45 -0500402 }
ethannicholas22f939e2016-10-13 13:25:34 -0700403 }
404 }
John Stiles65b48272020-12-22 17:18:34 -0500405 }
ethannicholas22f939e2016-10-13 13:25:34 -0700406 }
407}
408
Ethan Nicholascb670962017-04-20 19:31:52 -0400409/**
410 * Returns true if assigning to this lvalue has no effect.
411 */
Brian Osman010ce6a2020-10-19 16:34:10 -0400412static bool is_dead(const Expression& lvalue, ProgramUsage* usage) {
Ethan Nicholase6592142020-09-08 10:22:09 -0400413 switch (lvalue.kind()) {
414 case Expression::Kind::kVariableReference:
Brian Osman010ce6a2020-10-19 16:34:10 -0400415 return usage->isDead(*lvalue.as<VariableReference>().variable());
Ethan Nicholase6592142020-09-08 10:22:09 -0400416 case Expression::Kind::kSwizzle:
Brian Osman010ce6a2020-10-19 16:34:10 -0400417 return is_dead(*lvalue.as<Swizzle>().base(), usage);
Ethan Nicholase6592142020-09-08 10:22:09 -0400418 case Expression::Kind::kFieldAccess:
Brian Osman010ce6a2020-10-19 16:34:10 -0400419 return is_dead(*lvalue.as<FieldAccess>().base(), usage);
Ethan Nicholase6592142020-09-08 10:22:09 -0400420 case Expression::Kind::kIndex: {
John Stilesa5a97b42020-08-18 11:19:07 -0400421 const IndexExpression& idx = lvalue.as<IndexExpression>();
Brian Osman010ce6a2020-10-19 16:34:10 -0400422 return is_dead(*idx.base(), usage) &&
Ethan Nicholas2a4952d2020-10-08 15:35:56 -0400423 !idx.index()->hasProperty(Expression::Property::kSideEffects);
Ethan Nicholascb670962017-04-20 19:31:52 -0400424 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400425 case Expression::Kind::kTernary: {
John Stilesa5a97b42020-08-18 11:19:07 -0400426 const TernaryExpression& t = lvalue.as<TernaryExpression>();
Brian Osman010ce6a2020-10-19 16:34:10 -0400427 return !t.test()->hasSideEffects() &&
428 is_dead(*t.ifTrue(), usage) &&
429 is_dead(*t.ifFalse(), usage);
Ethan Nicholasa583b812018-01-18 13:32:11 -0500430 }
Ethan Nicholascb670962017-04-20 19:31:52 -0400431 default:
John Stileseada7bc2021-02-02 16:29:32 -0500432 SkDEBUGFAILF("invalid lvalue: %s\n", lvalue.description().c_str());
Ethan Nicholas2a099da2020-01-02 14:40:54 -0500433 return false;
Ethan Nicholascb670962017-04-20 19:31:52 -0400434 }
435}
ethannicholas22f939e2016-10-13 13:25:34 -0700436
Ethan Nicholascb670962017-04-20 19:31:52 -0400437/**
438 * Returns true if this is an assignment which can be collapsed down to just the right hand side due
439 * to a dead target and lack of side effects on the left hand side.
440 */
Brian Osman010ce6a2020-10-19 16:34:10 -0400441static bool dead_assignment(const BinaryExpression& b, ProgramUsage* usage) {
John Stiles45990502021-02-16 10:55:27 -0500442 if (!b.getOperator().isAssignment()) {
Ethan Nicholascb670962017-04-20 19:31:52 -0400443 return false;
444 }
John Stiles2d4f9592020-10-30 10:29:12 -0400445 return is_dead(*b.left(), usage);
Ethan Nicholascb670962017-04-20 19:31:52 -0400446}
447
John Stiles0ac6c152021-02-10 14:04:24 -0500448/**
449 * Returns true if both expression trees are the same. The left side is expected to be an lvalue.
450 * This only needs to check for trees that can plausibly terminate in a variable, so some basic
451 * candidates like `FloatLiteral` are missing.
452 */
453static bool is_matching_expression_tree(const Expression& left, const Expression& right) {
454 if (left.kind() != right.kind() || left.type() != right.type()) {
455 return false;
456 }
457
458 switch (left.kind()) {
459 case Expression::Kind::kIntLiteral:
460 return left.as<IntLiteral>().value() == right.as<IntLiteral>().value();
461
462 case Expression::Kind::kFieldAccess:
463 return left.as<FieldAccess>().fieldIndex() == right.as<FieldAccess>().fieldIndex() &&
464 is_matching_expression_tree(*left.as<FieldAccess>().base(),
465 *right.as<FieldAccess>().base());
466
467 case Expression::Kind::kIndex:
468 return is_matching_expression_tree(*left.as<IndexExpression>().index(),
469 *right.as<IndexExpression>().index()) &&
470 is_matching_expression_tree(*left.as<IndexExpression>().base(),
471 *right.as<IndexExpression>().base());
472
473 case Expression::Kind::kSwizzle:
474 return left.as<Swizzle>().components() == right.as<Swizzle>().components() &&
475 is_matching_expression_tree(*left.as<Swizzle>().base(),
476 *right.as<Swizzle>().base());
477
478 case Expression::Kind::kVariableReference:
479 return left.as<VariableReference>().variable() ==
480 right.as<VariableReference>().variable();
481
482 default:
483 return false;
484 }
485}
486
487static bool self_assignment(const BinaryExpression& b) {
John Stiles45990502021-02-16 10:55:27 -0500488 return b.getOperator().kind() == Token::Kind::TK_EQ &&
John Stiles0ac6c152021-02-10 14:04:24 -0500489 is_matching_expression_tree(*b.left(), *b.right());
490}
491
Ethan Nicholascb670962017-04-20 19:31:52 -0400492void Compiler::computeDataFlow(CFG* cfg) {
John Stilese8a24922021-02-08 17:54:08 -0500493 cfg->fBlocks[cfg->fStart].fBefore.computeStartState(*cfg);
John Stilese6150002020-10-05 12:03:53 -0400494
495 // We set bits in the "processed" set after a block has been scanned.
496 SkBitSet processedSet(cfg->fBlocks.size());
497 while (SkBitSet::OptionalIndex blockId = processedSet.findFirstUnset()) {
498 processedSet.set(*blockId);
499 this->scanCFG(cfg, *blockId, &processedSet);
ethannicholas22f939e2016-10-13 13:25:34 -0700500 }
Ethan Nicholascb670962017-04-20 19:31:52 -0400501}
502
503/**
504 * Attempts to replace the expression pointed to by iter with a new one (in both the CFG and the
505 * IR). If the expression can be cleanly removed, returns true and updates the iterator to point to
506 * the newly-inserted element. Otherwise updates only the IR and returns false (and the CFG will
507 * need to be regenerated).
508 */
John Stilesafbf8992020-08-18 10:08:21 -0400509static bool try_replace_expression(BasicBlock* b,
510 std::vector<BasicBlock::Node>::iterator* iter,
511 std::unique_ptr<Expression>* newExpression) {
Ethan Nicholascb670962017-04-20 19:31:52 -0400512 std::unique_ptr<Expression>* target = (*iter)->expression();
513 if (!b->tryRemoveExpression(iter)) {
514 *target = std::move(*newExpression);
515 return false;
516 }
517 *target = std::move(*newExpression);
518 return b->tryInsertExpression(iter, target);
519}
520
521/**
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400522 * Returns true if the expression is a constant numeric literal with the specified value, or a
523 * constant vector with all elements equal to the specified value.
Ethan Nicholascb670962017-04-20 19:31:52 -0400524 */
Ethan Nicholasa3f22f12020-10-01 12:13:17 -0400525template <typename T = SKSL_FLOAT>
John Stiles9d944232020-08-19 09:56:49 -0400526static bool is_constant(const Expression& expr, T value) {
Ethan Nicholase6592142020-09-08 10:22:09 -0400527 switch (expr.kind()) {
528 case Expression::Kind::kIntLiteral:
Ethan Nicholase96cdd12020-09-28 16:27:18 -0400529 return expr.as<IntLiteral>().value() == value;
John Stiles9d944232020-08-19 09:56:49 -0400530
Ethan Nicholase6592142020-09-08 10:22:09 -0400531 case Expression::Kind::kFloatLiteral:
Ethan Nicholasa3f22f12020-10-01 12:13:17 -0400532 return expr.as<FloatLiteral>().value() == value;
John Stiles9d944232020-08-19 09:56:49 -0400533
Ethan Nicholase6592142020-09-08 10:22:09 -0400534 case Expression::Kind::kConstructor: {
John Stiles9d944232020-08-19 09:56:49 -0400535 const Constructor& constructor = expr.as<Constructor>();
536 if (constructor.isCompileTimeConstant()) {
Ethan Nicholas30d30222020-09-11 12:27:26 -0400537 const Type& constructorType = constructor.type();
Ethan Nicholas30d30222020-09-11 12:27:26 -0400538 switch (constructorType.typeKind()) {
Ethan Nicholase6592142020-09-08 10:22:09 -0400539 case Type::TypeKind::kVector:
John Stilesbc75ebb2020-11-24 12:04:47 -0500540 if (constructor.componentType().isFloat()) {
541 for (int i = 0; i < constructorType.columns(); ++i) {
John Stiles9d944232020-08-19 09:56:49 -0400542 if (constructor.getFVecComponent(i) != value) {
543 return false;
544 }
John Stilesbc75ebb2020-11-24 12:04:47 -0500545 }
546 return true;
547 } else if (constructor.componentType().isInteger()) {
548 for (int i = 0; i < constructorType.columns(); ++i) {
John Stiles9d944232020-08-19 09:56:49 -0400549 if (constructor.getIVecComponent(i) != value) {
550 return false;
551 }
552 }
John Stilesbc75ebb2020-11-24 12:04:47 -0500553 return true;
Ethan Nicholasd188c182019-06-10 15:55:38 -0400554 }
John Stilesbc75ebb2020-11-24 12:04:47 -0500555 // Other types (e.g. boolean) might occur, but aren't supported here.
556 return false;
John Stiles9d944232020-08-19 09:56:49 -0400557
Ethan Nicholase6592142020-09-08 10:22:09 -0400558 case Type::TypeKind::kScalar:
Ethan Nicholasf70f0442020-09-29 12:41:35 -0400559 SkASSERT(constructor.arguments().size() == 1);
560 return is_constant<T>(*constructor.arguments()[0], value);
John Stiles9d944232020-08-19 09:56:49 -0400561
562 default:
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400563 return false;
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400564 }
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400565 }
566 return false;
567 }
Ethan Nicholascb670962017-04-20 19:31:52 -0400568 default:
569 return false;
570 }
571}
572
573/**
574 * Collapses the binary expression pointed to by iter down to just the right side (in both the IR
575 * and CFG structures).
576 */
John Stilesafbf8992020-08-18 10:08:21 -0400577static void delete_left(BasicBlock* b,
578 std::vector<BasicBlock::Node>::iterator* iter,
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400579 Compiler::OptimizationContext* optimizationContext) {
580 optimizationContext->fUpdated = true;
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400581 std::unique_ptr<Expression>* target = (*iter)->expression();
John Stilesa5a97b42020-08-18 11:19:07 -0400582 BinaryExpression& bin = (*target)->as<BinaryExpression>();
John Stiles2d4f9592020-10-30 10:29:12 -0400583 Expression& left = *bin.left();
584 std::unique_ptr<Expression>& rightPointer = bin.right();
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400585 SkASSERT(!left.hasSideEffects());
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400586 bool result;
John Stiles45990502021-02-16 10:55:27 -0500587 if (bin.getOperator().kind() == Token::Kind::TK_EQ) {
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400588 result = b->tryRemoveLValueBefore(iter, &left);
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400589 } else {
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400590 result = b->tryRemoveExpressionBefore(iter, &left);
Ethan Nicholascb670962017-04-20 19:31:52 -0400591 }
Brian Osman010ce6a2020-10-19 16:34:10 -0400592 // Remove references within LHS.
593 optimizationContext->fUsage->remove(&left);
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400594 *target = std::move(rightPointer);
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400595 if (!result) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400596 optimizationContext->fNeedsRescan = true;
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400597 return;
598 }
599 if (*iter == b->fNodes.begin()) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400600 optimizationContext->fNeedsRescan = true;
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400601 return;
602 }
603 --(*iter);
John Stiles70025e52020-09-28 16:08:58 -0400604 if (!(*iter)->isExpression() || (*iter)->expression() != &rightPointer) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400605 optimizationContext->fNeedsRescan = true;
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400606 return;
607 }
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400608 *iter = b->fNodes.erase(*iter);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400609 SkASSERT((*iter)->expression() == target);
Ethan Nicholascb670962017-04-20 19:31:52 -0400610}
611
612/**
613 * Collapses the binary expression pointed to by iter down to just the left side (in both the IR and
614 * CFG structures).
615 */
John Stilesafbf8992020-08-18 10:08:21 -0400616static void delete_right(BasicBlock* b,
617 std::vector<BasicBlock::Node>::iterator* iter,
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400618 Compiler::OptimizationContext* optimizationContext) {
619 optimizationContext->fUpdated = true;
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400620 std::unique_ptr<Expression>* target = (*iter)->expression();
John Stilesa5a97b42020-08-18 11:19:07 -0400621 BinaryExpression& bin = (*target)->as<BinaryExpression>();
John Stiles2d4f9592020-10-30 10:29:12 -0400622 std::unique_ptr<Expression>& leftPointer = bin.left();
623 Expression& right = *bin.right();
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400624 SkASSERT(!right.hasSideEffects());
Brian Osman010ce6a2020-10-19 16:34:10 -0400625 // Remove references within RHS.
626 optimizationContext->fUsage->remove(&right);
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400627 if (!b->tryRemoveExpressionBefore(iter, &right)) {
628 *target = std::move(leftPointer);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400629 optimizationContext->fNeedsRescan = true;
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400630 return;
Ethan Nicholascb670962017-04-20 19:31:52 -0400631 }
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400632 *target = std::move(leftPointer);
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400633 if (*iter == b->fNodes.begin()) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400634 optimizationContext->fNeedsRescan = true;
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400635 return;
636 }
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400637 --(*iter);
John Stiles70025e52020-09-28 16:08:58 -0400638 if ((!(*iter)->isExpression() || (*iter)->expression() != &leftPointer)) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400639 optimizationContext->fNeedsRescan = true;
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400640 return;
641 }
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400642 *iter = b->fNodes.erase(*iter);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400643 SkASSERT((*iter)->expression() == target);
Ethan Nicholascb670962017-04-20 19:31:52 -0400644}
645
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400646/**
647 * Constructs the specified type using a single argument.
648 */
Ethan Nicholas30d30222020-09-11 12:27:26 -0400649static std::unique_ptr<Expression> construct(const Type* type, std::unique_ptr<Expression> v) {
John Stiles8e3b6be2020-10-13 11:14:08 -0400650 ExpressionArray args;
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400651 args.push_back(std::move(v));
John Stiles54f00492021-02-19 11:46:10 -0500652 return std::make_unique<Constructor>(/*offset=*/-1, *type, std::move(args));
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400653}
654
655/**
656 * Used in the implementations of vectorize_left and vectorize_right. Given a vector type and an
657 * expression x, deletes the expression pointed to by iter and replaces it with <type>(x).
658 */
659static void vectorize(BasicBlock* b,
660 std::vector<BasicBlock::Node>::iterator* iter,
661 const Type& type,
662 std::unique_ptr<Expression>* otherExpression,
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400663 Compiler::OptimizationContext* optimizationContext) {
Ethan Nicholase6592142020-09-08 10:22:09 -0400664 SkASSERT((*(*iter)->expression())->kind() == Expression::Kind::kBinary);
John Stiles9aeed132020-11-24 17:36:06 -0500665 SkASSERT(type.isVector());
666 SkASSERT((*otherExpression)->type().isScalar());
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400667 optimizationContext->fUpdated = true;
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400668 std::unique_ptr<Expression>* target = (*iter)->expression();
669 if (!b->tryRemoveExpression(iter)) {
Ethan Nicholas30d30222020-09-11 12:27:26 -0400670 *target = construct(&type, std::move(*otherExpression));
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400671 optimizationContext->fNeedsRescan = true;
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400672 } else {
Ethan Nicholas30d30222020-09-11 12:27:26 -0400673 *target = construct(&type, std::move(*otherExpression));
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400674 if (!b->tryInsertExpression(iter, target)) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400675 optimizationContext->fNeedsRescan = true;
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400676 }
677 }
678}
679
680/**
681 * Given a binary expression of the form x <op> vec<n>(y), deletes the right side and vectorizes the
682 * left to yield vec<n>(x).
683 */
684static void vectorize_left(BasicBlock* b,
685 std::vector<BasicBlock::Node>::iterator* iter,
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400686 Compiler::OptimizationContext* optimizationContext) {
John Stilesa5a97b42020-08-18 11:19:07 -0400687 BinaryExpression& bin = (*(*iter)->expression())->as<BinaryExpression>();
Brian Osman010ce6a2020-10-19 16:34:10 -0400688 // Remove references within RHS. Vectorization of LHS doesn't change reference counts.
John Stiles2d4f9592020-10-30 10:29:12 -0400689 optimizationContext->fUsage->remove(bin.right().get());
690 vectorize(b, iter, bin.right()->type(), &bin.left(), optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400691}
692
693/**
694 * Given a binary expression of the form vec<n>(x) <op> y, deletes the left side and vectorizes the
695 * right to yield vec<n>(y).
696 */
697static void vectorize_right(BasicBlock* b,
698 std::vector<BasicBlock::Node>::iterator* iter,
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400699 Compiler::OptimizationContext* optimizationContext) {
John Stilesa5a97b42020-08-18 11:19:07 -0400700 BinaryExpression& bin = (*(*iter)->expression())->as<BinaryExpression>();
Brian Osman010ce6a2020-10-19 16:34:10 -0400701 // Remove references within LHS. Vectorization of RHS doesn't change reference counts.
John Stiles2d4f9592020-10-30 10:29:12 -0400702 optimizationContext->fUsage->remove(bin.left().get());
703 vectorize(b, iter, bin.left()->type(), &bin.right(), optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400704}
705
Ethan Nicholascb670962017-04-20 19:31:52 -0400706void Compiler::simplifyExpression(DefinitionMap& definitions,
707 BasicBlock& b,
708 std::vector<BasicBlock::Node>::iterator* iter,
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400709 OptimizationContext* optimizationContext) {
Ethan Nicholascb670962017-04-20 19:31:52 -0400710 Expression* expr = (*iter)->expression()->get();
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400711 SkASSERT(expr);
John Stiles108bbe22020-11-18 11:10:38 -0500712
Ethan Nicholascb670962017-04-20 19:31:52 -0400713 if ((*iter)->fConstantPropagation) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400714 std::unique_ptr<Expression> optimized = expr->constantPropagate(*fIRGenerator,
715 definitions);
Ethan Nicholascb670962017-04-20 19:31:52 -0400716 if (optimized) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400717 optimizationContext->fUpdated = true;
Ethan Nicholas30d30222020-09-11 12:27:26 -0400718 optimized = fIRGenerator->coerce(std::move(optimized), expr->type());
Ethan Nicholas1d881522020-09-11 09:32:54 -0400719 SkASSERT(optimized);
Brian Osman010ce6a2020-10-19 16:34:10 -0400720 // Remove references within 'expr', add references within 'optimized'
721 optimizationContext->fUsage->replace(expr, optimized.get());
Ethan Nicholascb670962017-04-20 19:31:52 -0400722 if (!try_replace_expression(&b, iter, &optimized)) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400723 optimizationContext->fNeedsRescan = true;
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400724 return;
Ethan Nicholascb670962017-04-20 19:31:52 -0400725 }
John Stiles70025e52020-09-28 16:08:58 -0400726 SkASSERT((*iter)->isExpression());
Ethan Nicholascb670962017-04-20 19:31:52 -0400727 expr = (*iter)->expression()->get();
Ethan Nicholascb670962017-04-20 19:31:52 -0400728 }
729 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400730 switch (expr->kind()) {
731 case Expression::Kind::kVariableReference: {
John Stilesa5a97b42020-08-18 11:19:07 -0400732 const VariableReference& ref = expr->as<VariableReference>();
Ethan Nicholas78686922020-10-08 06:46:27 -0400733 const Variable* var = ref.variable();
John Stiles66c53b92021-02-20 08:00:43 -0500734 if (fContext->fConfig->fSettings.fDeadCodeElimination &&
735 ref.refKind() != VariableReference::RefKind::kWrite &&
Ethan Nicholas453f67f2020-10-09 10:43:45 -0400736 ref.refKind() != VariableReference::RefKind::kPointer &&
John Stilese8a24922021-02-08 17:54:08 -0500737 var->storage() == Variable::Storage::kLocal && !definitions.get(var) &&
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400738 optimizationContext->fSilences.find(var) == optimizationContext->fSilences.end()) {
739 optimizationContext->fSilences.insert(var);
Ethan Nicholas82a62d22017-11-07 14:42:10 +0000740 this->error(expr->fOffset,
Ethan Nicholase2c49992020-10-05 11:49:11 -0400741 "'" + var->name() + "' has not been assigned");
Ethan Nicholascb670962017-04-20 19:31:52 -0400742 }
743 break;
744 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400745 case Expression::Kind::kTernary: {
John Stiles403a3632020-08-20 12:11:48 -0400746 TernaryExpression* t = &expr->as<TernaryExpression>();
Ethan Nicholasdd218162020-10-08 05:48:01 -0400747 if (t->test()->is<BoolLiteral>()) {
Ethan Nicholascb670962017-04-20 19:31:52 -0400748 // ternary has a constant test, replace it with either the true or
749 // false branch
Ethan Nicholasdd218162020-10-08 05:48:01 -0400750 if (t->test()->as<BoolLiteral>().value()) {
Brian Osman010ce6a2020-10-19 16:34:10 -0400751 (*iter)->setExpression(std::move(t->ifTrue()), optimizationContext->fUsage);
Ethan Nicholascb670962017-04-20 19:31:52 -0400752 } else {
Brian Osman010ce6a2020-10-19 16:34:10 -0400753 (*iter)->setExpression(std::move(t->ifFalse()), optimizationContext->fUsage);
Ethan Nicholascb670962017-04-20 19:31:52 -0400754 }
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400755 optimizationContext->fUpdated = true;
756 optimizationContext->fNeedsRescan = true;
Ethan Nicholascb670962017-04-20 19:31:52 -0400757 }
758 break;
759 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400760 case Expression::Kind::kBinary: {
John Stiles403a3632020-08-20 12:11:48 -0400761 BinaryExpression* bin = &expr->as<BinaryExpression>();
John Stiles0ac6c152021-02-10 14:04:24 -0500762 if (dead_assignment(*bin, optimizationContext->fUsage) || self_assignment(*bin)) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400763 delete_left(&b, iter, optimizationContext);
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400764 break;
765 }
John Stiles2d4f9592020-10-30 10:29:12 -0400766 Expression& left = *bin->left();
767 Expression& right = *bin->right();
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400768 const Type& leftType = left.type();
769 const Type& rightType = right.type();
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400770 // collapse useless expressions like x * 1 or x + 0
John Stiles9aeed132020-11-24 17:36:06 -0500771 if ((!leftType.isScalar() && !leftType.isVector()) ||
772 (!rightType.isScalar() && !rightType.isVector())) {
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400773 break;
774 }
John Stiles45990502021-02-16 10:55:27 -0500775 switch (bin->getOperator().kind()) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400776 case Token::Kind::TK_STAR:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400777 if (is_constant(left, 1)) {
John Stiles9aeed132020-11-24 17:36:06 -0500778 if (leftType.isVector() && rightType.isScalar()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400779 // float4(1) * x -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400780 vectorize_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400781 } else {
782 // 1 * x -> x
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400783 // 1 * float4(x) -> float4(x)
784 // float4(1) * float4(x) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400785 delete_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400786 }
787 }
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400788 else if (is_constant(left, 0)) {
John Stiles9aeed132020-11-24 17:36:06 -0500789 if (leftType.isScalar() && rightType.isVector() &&
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400790 !right.hasSideEffects()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400791 // 0 * float4(x) -> float4(0)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400792 vectorize_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400793 } else {
794 // 0 * x -> 0
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400795 // float4(0) * x -> float4(0)
796 // float4(0) * float4(x) -> float4(0)
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400797 if (!right.hasSideEffects()) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400798 delete_right(&b, iter, optimizationContext);
Ethan Nicholas51493ee2017-12-11 12:34:33 -0500799 }
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400800 }
Ethan Nicholascb670962017-04-20 19:31:52 -0400801 }
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400802 else if (is_constant(right, 1)) {
John Stiles9aeed132020-11-24 17:36:06 -0500803 if (leftType.isScalar() && rightType.isVector()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400804 // x * float4(1) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400805 vectorize_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400806 } else {
807 // x * 1 -> x
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400808 // float4(x) * 1 -> float4(x)
809 // float4(x) * float4(1) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400810 delete_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400811 }
812 }
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400813 else if (is_constant(right, 0)) {
John Stiles9aeed132020-11-24 17:36:06 -0500814 if (leftType.isVector() && rightType.isScalar() && !left.hasSideEffects()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400815 // float4(x) * 0 -> float4(0)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400816 vectorize_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400817 } else {
818 // x * 0 -> 0
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400819 // x * float4(0) -> float4(0)
820 // float4(x) * float4(0) -> float4(0)
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400821 if (!left.hasSideEffects()) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400822 delete_left(&b, iter, optimizationContext);
Ethan Nicholas51493ee2017-12-11 12:34:33 -0500823 }
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400824 }
Ethan Nicholascb670962017-04-20 19:31:52 -0400825 }
826 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400827 case Token::Kind::TK_PLUS:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400828 if (is_constant(left, 0)) {
John Stiles9aeed132020-11-24 17:36:06 -0500829 if (leftType.isVector() && rightType.isScalar()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400830 // float4(0) + x -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400831 vectorize_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400832 } else {
833 // 0 + x -> x
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400834 // 0 + float4(x) -> float4(x)
835 // float4(0) + float4(x) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400836 delete_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400837 }
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400838 } else if (is_constant(right, 0)) {
John Stiles9aeed132020-11-24 17:36:06 -0500839 if (leftType.isScalar() && rightType.isVector()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400840 // x + float4(0) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400841 vectorize_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400842 } else {
843 // x + 0 -> x
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400844 // float4(x) + 0 -> float4(x)
845 // float4(x) + float4(0) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400846 delete_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400847 }
Ethan Nicholas56e42712017-04-21 10:23:37 -0400848 }
849 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400850 case Token::Kind::TK_MINUS:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400851 if (is_constant(right, 0)) {
John Stiles9aeed132020-11-24 17:36:06 -0500852 if (leftType.isScalar() && rightType.isVector()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400853 // x - float4(0) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400854 vectorize_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400855 } else {
856 // x - 0 -> x
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400857 // float4(x) - 0 -> float4(x)
858 // float4(x) - float4(0) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400859 delete_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400860 }
Ethan Nicholascb670962017-04-20 19:31:52 -0400861 }
862 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400863 case Token::Kind::TK_SLASH:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400864 if (is_constant(right, 1)) {
John Stiles9aeed132020-11-24 17:36:06 -0500865 if (leftType.isScalar() && rightType.isVector()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400866 // x / float4(1) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400867 vectorize_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400868 } else {
869 // x / 1 -> x
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400870 // float4(x) / 1 -> float4(x)
871 // float4(x) / float4(1) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400872 delete_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400873 }
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400874 } else if (is_constant(left, 0)) {
John Stiles9aeed132020-11-24 17:36:06 -0500875 if (leftType.isScalar() && rightType.isVector() &&
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400876 !right.hasSideEffects()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400877 // 0 / float4(x) -> float4(0)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400878 vectorize_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400879 } else {
880 // 0 / x -> 0
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400881 // float4(0) / x -> float4(0)
882 // float4(0) / float4(x) -> float4(0)
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400883 if (!right.hasSideEffects()) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400884 delete_right(&b, iter, optimizationContext);
Ethan Nicholas51493ee2017-12-11 12:34:33 -0500885 }
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400886 }
887 }
888 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400889 case Token::Kind::TK_PLUSEQ:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400890 if (is_constant(right, 0)) {
John Stiles47c0a742021-02-09 09:30:35 -0500891 Analysis::UpdateRefKind(&left, RefKind::kRead);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400892 delete_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400893 }
894 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400895 case Token::Kind::TK_MINUSEQ:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400896 if (is_constant(right, 0)) {
John Stiles47c0a742021-02-09 09:30:35 -0500897 Analysis::UpdateRefKind(&left, RefKind::kRead);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400898 delete_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400899 }
900 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400901 case Token::Kind::TK_STAREQ:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400902 if (is_constant(right, 1)) {
John Stiles47c0a742021-02-09 09:30:35 -0500903 Analysis::UpdateRefKind(&left, RefKind::kRead);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400904 delete_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400905 }
906 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400907 case Token::Kind::TK_SLASHEQ:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400908 if (is_constant(right, 1)) {
John Stiles47c0a742021-02-09 09:30:35 -0500909 Analysis::UpdateRefKind(&left, RefKind::kRead);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400910 delete_right(&b, iter, optimizationContext);
Ethan Nicholascb670962017-04-20 19:31:52 -0400911 }
912 break;
913 default:
914 break;
915 }
Ethan Nicholas409f6f02019-09-17 12:34:39 -0400916 break;
917 }
John Stilesf5c1d042020-11-21 23:26:07 -0500918 case Expression::Kind::kConstructor: {
919 // Find constructors embedded inside constructors and flatten them out where possible.
920 // - float4(float2(1, 2), 3, 4) --> float4(1, 2, 3, 4)
921 // - float4(w, float3(sin(x), cos(y), tan(z))) --> float4(w, sin(x), cos(y), tan(z))
922 // Leave single-argument constructors alone, though. These might be casts or splats.
923 Constructor& c = expr->as<Constructor>();
924 if (c.type().columns() > 1) {
925 // Inspect each constructor argument to see if it's a candidate for flattening.
926 // Remember matched arguments in a bitfield, "argsToOptimize".
927 int argsToOptimize = 0;
928 int currBit = 1;
929 for (const std::unique_ptr<Expression>& arg : c.arguments()) {
930 if (arg->is<Constructor>()) {
931 Constructor& inner = arg->as<Constructor>();
932 if (inner.arguments().size() > 1 &&
933 inner.type().componentType() == c.type().componentType()) {
934 argsToOptimize |= currBit;
935 }
936 }
937 currBit <<= 1;
938 }
939 if (argsToOptimize) {
940 // We found at least one argument that could be flattened out. Re-walk the
941 // constructor args and flatten the candidates we found during our initial pass.
942 ExpressionArray flattened;
943 flattened.reserve_back(c.type().columns());
944 currBit = 1;
945 for (const std::unique_ptr<Expression>& arg : c.arguments()) {
946 if (argsToOptimize & currBit) {
947 Constructor& inner = arg->as<Constructor>();
948 for (const std::unique_ptr<Expression>& innerArg : inner.arguments()) {
949 flattened.push_back(innerArg->clone());
950 }
951 } else {
952 flattened.push_back(arg->clone());
953 }
954 currBit <<= 1;
955 }
John Stiles54f00492021-02-19 11:46:10 -0500956 std::unique_ptr<Expression> replacement = std::make_unique<Constructor>(
957 c.fOffset, c.type(), std::move(flattened));
John Stiles1b91c0e2021-02-11 11:43:09 -0500958 // We're replacing an expression with a cloned version; we'll need a rescan.
959 // No fUsage change: `float2(float(x), y)` and `float2(x, y)` have equivalent
960 // reference counts.
961 try_replace_expression(&b, iter, &replacement);
John Stilesf5c1d042020-11-21 23:26:07 -0500962 optimizationContext->fUpdated = true;
John Stiles1b91c0e2021-02-11 11:43:09 -0500963 optimizationContext->fNeedsRescan = true;
John Stilesf5c1d042020-11-21 23:26:07 -0500964 break;
965 }
966 }
967 break;
968 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400969 case Expression::Kind::kSwizzle: {
John Stiles403a3632020-08-20 12:11:48 -0400970 Swizzle& s = expr->as<Swizzle>();
John Stiles108bbe22020-11-18 11:10:38 -0500971 // Detect identity swizzles like `foo.rgba`.
Ethan Nicholas6b4d5812020-10-12 16:11:51 -0400972 if ((int) s.components().size() == s.base()->type().columns()) {
Ethan Nicholas409f6f02019-09-17 12:34:39 -0400973 bool identity = true;
Ethan Nicholas6b4d5812020-10-12 16:11:51 -0400974 for (int i = 0; i < (int) s.components().size(); ++i) {
975 if (s.components()[i] != i) {
Ethan Nicholas409f6f02019-09-17 12:34:39 -0400976 identity = false;
977 break;
978 }
979 }
980 if (identity) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400981 optimizationContext->fUpdated = true;
Brian Osman010ce6a2020-10-19 16:34:10 -0400982 // No fUsage change: foo.rgba and foo have equivalent reference counts
Ethan Nicholas6b4d5812020-10-12 16:11:51 -0400983 if (!try_replace_expression(&b, iter, &s.base())) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400984 optimizationContext->fNeedsRescan = true;
Ethan Nicholas409f6f02019-09-17 12:34:39 -0400985 return;
986 }
John Stiles70025e52020-09-28 16:08:58 -0400987 SkASSERT((*iter)->isExpression());
Ethan Nicholas409f6f02019-09-17 12:34:39 -0400988 break;
989 }
990 }
John Stiles108bbe22020-11-18 11:10:38 -0500991 // Detect swizzles of swizzles, e.g. replace `foo.argb.r000` with `foo.a000`.
992 if (s.base()->is<Swizzle>()) {
Ethan Nicholas6b4d5812020-10-12 16:11:51 -0400993 Swizzle& base = s.base()->as<Swizzle>();
John Stiles750109b2020-10-30 13:45:46 -0400994 ComponentArray final;
Ethan Nicholas6b4d5812020-10-12 16:11:51 -0400995 for (int c : s.components()) {
996 final.push_back(base.components()[c]);
Ethan Nicholas409f6f02019-09-17 12:34:39 -0400997 }
Ethan Nicholas6b4d5812020-10-12 16:11:51 -0400998 std::unique_ptr<Expression> replacement(new Swizzle(*fContext, base.base()->clone(),
John Stiles750109b2020-10-30 13:45:46 -0400999 final));
John Stilesd2f51b12021-01-07 18:12:31 -05001000 // We're replacing an expression with a cloned version; we'll need a rescan.
John Stiles108bbe22020-11-18 11:10:38 -05001001 // No fUsage change: `foo.gbr.gbr` and `foo.brg` have equivalent reference counts
John Stilesd2f51b12021-01-07 18:12:31 -05001002 try_replace_expression(&b, iter, &replacement);
1003 optimizationContext->fUpdated = true;
1004 optimizationContext->fNeedsRescan = true;
John Stiles108bbe22020-11-18 11:10:38 -05001005 break;
1006 }
1007 // Optimize swizzles of constructors.
1008 if (s.base()->is<Constructor>()) {
1009 Constructor& base = s.base()->as<Constructor>();
1010 std::unique_ptr<Expression> replacement;
1011 const Type& componentType = base.type().componentType();
1012 int swizzleSize = s.components().size();
1013
1014 // The IR generator has already converted any zero/one swizzle components into
1015 // constructors containing zero/one args. Confirm that this is true by checking that
1016 // our swizzle components are all `xyzw` (values 0 through 3).
1017 SkASSERT(std::all_of(s.components().begin(), s.components().end(),
1018 [](int8_t c) { return c >= 0 && c <= 3; }));
1019
John Stiles9aeed132020-11-24 17:36:06 -05001020 if (base.arguments().size() == 1 && base.arguments().front()->type().isScalar()) {
John Stiles108bbe22020-11-18 11:10:38 -05001021 // `half4(scalar).zyy` can be optimized to `half3(scalar)`. The swizzle
1022 // components don't actually matter since all fields are the same.
John Stilesf0cb7332021-01-08 18:39:00 -05001023 const Expression& argument = *base.arguments().front();
1024 const Type& constructorType = componentType.toCompound(*fContext, swizzleSize,
1025 /*rows=*/1);
1026 replacement = Constructor::SimplifyConversion(constructorType, argument);
1027 if (!replacement) {
1028 ExpressionArray newArgs;
1029 newArgs.push_back(argument.clone());
John Stiles54f00492021-02-19 11:46:10 -05001030 replacement = std::make_unique<Constructor>(base.fOffset, constructorType,
John Stilesf0cb7332021-01-08 18:39:00 -05001031 std::move(newArgs));
1032 }
John Stiles108bbe22020-11-18 11:10:38 -05001033
John Stilesa60ac0c2020-12-22 08:59:51 -05001034 // We're replacing an expression with a cloned version; we'll need a rescan.
1035 // There's no fUsage change: `half4(foo).xy` and `half2(foo)` have equivalent
1036 // reference counts.
1037 try_replace_expression(&b, iter, &replacement);
John Stiles0777ac42020-11-19 11:06:47 -05001038 optimizationContext->fUpdated = true;
John Stilesa60ac0c2020-12-22 08:59:51 -05001039 optimizationContext->fNeedsRescan = true;
John Stiles108bbe22020-11-18 11:10:38 -05001040 break;
1041 }
1042
John Stiles0777ac42020-11-19 11:06:47 -05001043 // Swizzles can duplicate some elements and discard others, e.g.
1044 // `half4(1, 2, 3, 4).xxz` --> `half3(1, 1, 3)`. However, there are constraints:
1045 // - Expressions with side effects need to occur exactly once, even if they
1046 // would otherwise be swizzle-eliminated
1047 // - Non-trivial expressions should not be repeated, but elimination is OK.
1048 //
1049 // Look up the argument for the constructor at each index. This is typically simple
1050 // but for weird cases like `half4(bar.yz, half2(foo))`, it can be harder than it
1051 // seems. This example would result in:
1052 // argMap[0] = {.fArgIndex = 0, .fComponent = 0} (bar.yz .x)
1053 // argMap[1] = {.fArgIndex = 0, .fComponent = 1} (bar.yz .y)
1054 // argMap[2] = {.fArgIndex = 1, .fComponent = 0} (half2(foo) .x)
1055 // argMap[3] = {.fArgIndex = 1, .fComponent = 1} (half2(foo) .y)
1056 struct ConstructorArgMap {
1057 int8_t fArgIndex;
1058 int8_t fComponent;
1059 };
1060
1061 int numConstructorArgs = base.type().columns();
1062 ConstructorArgMap argMap[4] = {};
1063 int writeIdx = 0;
1064 for (int argIdx = 0; argIdx < (int) base.arguments().size(); ++argIdx) {
1065 const Expression& expr = *base.arguments()[argIdx];
1066 int argWidth = expr.type().columns();
1067 for (int componentIdx = 0; componentIdx < argWidth; ++componentIdx) {
1068 argMap[writeIdx].fArgIndex = argIdx;
1069 argMap[writeIdx].fComponent = componentIdx;
1070 ++writeIdx;
1071 }
1072 }
1073 SkASSERT(writeIdx == numConstructorArgs);
1074
1075 // Count up the number of times each constructor argument is used by the
1076 // swizzle.
1077 // `half4(bar.yz, half2(foo)).xwxy` -> { 3, 1 }
1078 // - bar.yz is referenced 3 times, by `.x_xy`
1079 // - half(foo) is referenced 1 time, by `._w__`
1080 int8_t exprUsed[4] = {};
1081 for (int c : s.components()) {
1082 exprUsed[argMap[c].fArgIndex]++;
1083 }
1084
1085 bool safeToOptimize = true;
1086 for (int index = 0; index < numConstructorArgs; ++index) {
1087 int8_t constructorArgIndex = argMap[index].fArgIndex;
1088 const Expression& baseArg = *base.arguments()[constructorArgIndex];
1089
1090 // Check that non-trivial expressions are not swizzled in more than once.
John Stilesc30fbca2020-11-19 16:25:49 -05001091 if (exprUsed[constructorArgIndex] > 1 &&
1092 !Analysis::IsTrivialExpression(baseArg)) {
John Stiles0777ac42020-11-19 11:06:47 -05001093 safeToOptimize = false;
1094 break;
1095 }
1096 // Check that side-effect-bearing expressions are swizzled in exactly once.
1097 if (exprUsed[constructorArgIndex] != 1 && baseArg.hasSideEffects()) {
1098 safeToOptimize = false;
1099 break;
1100 }
1101 }
1102
1103 if (safeToOptimize) {
John Stilesd9076cb2020-11-19 12:18:36 -05001104 struct ReorderedArgument {
1105 int8_t fArgIndex;
1106 ComponentArray fComponents;
1107 };
1108 SkSTArray<4, ReorderedArgument> reorderedArgs;
John Stiles0777ac42020-11-19 11:06:47 -05001109 for (int c : s.components()) {
1110 const ConstructorArgMap& argument = argMap[c];
1111 const Expression& baseArg = *base.arguments()[argument.fArgIndex];
1112
John Stiles9aeed132020-11-24 17:36:06 -05001113 if (baseArg.type().isScalar()) {
John Stilesd9076cb2020-11-19 12:18:36 -05001114 // This argument is a scalar; add it to the list as-is.
John Stiles0777ac42020-11-19 11:06:47 -05001115 SkASSERT(argument.fComponent == 0);
John Stilesd9076cb2020-11-19 12:18:36 -05001116 reorderedArgs.push_back({argument.fArgIndex,
1117 ComponentArray{}});
John Stiles0777ac42020-11-19 11:06:47 -05001118 } else {
John Stilesd9076cb2020-11-19 12:18:36 -05001119 // This argument is a component from a vector.
John Stiles0777ac42020-11-19 11:06:47 -05001120 SkASSERT(argument.fComponent < baseArg.type().columns());
John Stilesd9076cb2020-11-19 12:18:36 -05001121 if (reorderedArgs.empty() ||
1122 reorderedArgs.back().fArgIndex != argument.fArgIndex) {
1123 // This can't be combined with the previous argument. Add a new one.
1124 reorderedArgs.push_back({argument.fArgIndex,
1125 ComponentArray{argument.fComponent}});
1126 } else {
1127 // Since we know this argument uses components, it should already
1128 // have at least one component set.
1129 SkASSERT(!reorderedArgs.back().fComponents.empty());
1130 // Build up the current argument with one more component.
1131 reorderedArgs.back().fComponents.push_back(argument.fComponent);
1132 }
John Stiles0777ac42020-11-19 11:06:47 -05001133 }
1134 }
John Stilesd9076cb2020-11-19 12:18:36 -05001135
1136 // Convert our reordered argument list to an actual array of expressions, with
1137 // the new order and any new inner swizzles that need to be applied. Note that
1138 // we expect followup passes to clean up the inner swizzles.
1139 ExpressionArray newArgs;
1140 newArgs.reserve_back(swizzleSize);
1141 for (const ReorderedArgument& reorderedArg : reorderedArgs) {
1142 const Expression& baseArg = *base.arguments()[reorderedArg.fArgIndex];
1143 if (reorderedArg.fComponents.empty()) {
1144 newArgs.push_back(baseArg.clone());
1145 } else {
1146 newArgs.push_back(std::make_unique<Swizzle>(*fContext, baseArg.clone(),
1147 reorderedArg.fComponents));
1148 }
1149 }
1150
1151 // Create a new constructor.
John Stiles0777ac42020-11-19 11:06:47 -05001152 replacement = std::make_unique<Constructor>(
1153 base.fOffset,
John Stiles54f00492021-02-19 11:46:10 -05001154 componentType.toCompound(*fContext, swizzleSize, /*rows=*/1),
John Stiles0777ac42020-11-19 11:06:47 -05001155 std::move(newArgs));
1156
John Stilesa60ac0c2020-12-22 08:59:51 -05001157 // Remove references within 'expr', add references within 'replacement.'
John Stiles0777ac42020-11-19 11:06:47 -05001158 optimizationContext->fUsage->replace(expr, replacement.get());
John Stilesa60ac0c2020-12-22 08:59:51 -05001159
1160 // We're replacing an expression with a cloned version; we'll need a rescan.
1161 try_replace_expression(&b, iter, &replacement);
1162 optimizationContext->fUpdated = true;
1163 optimizationContext->fNeedsRescan = true;
John Stiles0777ac42020-11-19 11:06:47 -05001164 }
John Stiles108bbe22020-11-18 11:10:38 -05001165 break;
Ethan Nicholas409f6f02019-09-17 12:34:39 -04001166 }
John Stiles30212b72020-06-11 17:55:07 -04001167 break;
Ethan Nicholascb670962017-04-20 19:31:52 -04001168 }
1169 default:
1170 break;
1171 }
1172}
1173
1174void Compiler::simplifyStatement(DefinitionMap& definitions,
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001175 BasicBlock& b,
1176 std::vector<BasicBlock::Node>::iterator* iter,
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001177 OptimizationContext* optimizationContext) {
Brian Osman010ce6a2020-10-19 16:34:10 -04001178 ProgramUsage* usage = optimizationContext->fUsage;
Ethan Nicholascb670962017-04-20 19:31:52 -04001179 Statement* stmt = (*iter)->statement()->get();
Ethan Nicholase6592142020-09-08 10:22:09 -04001180 switch (stmt->kind()) {
1181 case Statement::Kind::kVarDeclaration: {
John Stilesa5a97b42020-08-18 11:19:07 -04001182 const auto& varDecl = stmt->as<VarDeclaration>();
Brian Osman010ce6a2020-10-19 16:34:10 -04001183 if (usage->isDead(varDecl.var()) &&
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04001184 (!varDecl.value() ||
1185 !varDecl.value()->hasSideEffects())) {
1186 if (varDecl.value()) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001187 SkASSERT((*iter)->statement()->get() == stmt);
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04001188 if (!b.tryRemoveExpressionBefore(iter, varDecl.value().get())) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001189 optimizationContext->fNeedsRescan = true;
Ethan Nicholascb670962017-04-20 19:31:52 -04001190 }
Ethan Nicholascb670962017-04-20 19:31:52 -04001191 }
Ethan Nicholas5b9b0db2021-01-21 13:12:01 -05001192 // There can still be (soon to be removed) references to the variable at this point.
1193 // Allowing the VarDeclaration to be destroyed here will break those variable's
1194 // initialValue()s, so we hang on to them until optimization is finished.
1195 std::unique_ptr<Statement> old = (*iter)->setStatement(std::make_unique<Nop>(),
1196 usage);
1197 optimizationContext->fOwnedStatements.push_back(std::move(old));
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001198 optimizationContext->fUpdated = true;
Ethan Nicholascb670962017-04-20 19:31:52 -04001199 }
1200 break;
1201 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001202 case Statement::Kind::kIf: {
John Stilesa5a97b42020-08-18 11:19:07 -04001203 IfStatement& i = stmt->as<IfStatement>();
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001204 if (i.test()->kind() == Expression::Kind::kBoolLiteral) {
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001205 // constant if, collapse down to a single branch
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001206 if (i.test()->as<BoolLiteral>().value()) {
1207 SkASSERT(i.ifTrue());
Brian Osman010ce6a2020-10-19 16:34:10 -04001208 (*iter)->setStatement(std::move(i.ifTrue()), usage);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001209 } else {
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001210 if (i.ifFalse()) {
Brian Osman010ce6a2020-10-19 16:34:10 -04001211 (*iter)->setStatement(std::move(i.ifFalse()), usage);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001212 } else {
Brian Osman010ce6a2020-10-19 16:34:10 -04001213 (*iter)->setStatement(std::make_unique<Nop>(), usage);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001214 }
1215 }
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001216 optimizationContext->fUpdated = true;
1217 optimizationContext->fNeedsRescan = true;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001218 break;
1219 }
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001220 if (i.ifFalse() && i.ifFalse()->isEmpty()) {
Ethan Nicholascb670962017-04-20 19:31:52 -04001221 // else block doesn't do anything, remove it
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001222 i.ifFalse().reset();
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001223 optimizationContext->fUpdated = true;
1224 optimizationContext->fNeedsRescan = true;
Ethan Nicholascb670962017-04-20 19:31:52 -04001225 }
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001226 if (!i.ifFalse() && i.ifTrue()->isEmpty()) {
Ethan Nicholascb670962017-04-20 19:31:52 -04001227 // if block doesn't do anything, no else block
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001228 if (i.test()->hasSideEffects()) {
Ethan Nicholascb670962017-04-20 19:31:52 -04001229 // test has side effects, keep it
Brian Osman010ce6a2020-10-19 16:34:10 -04001230 (*iter)->setStatement(
1231 std::make_unique<ExpressionStatement>(std::move(i.test())), usage);
Ethan Nicholascb670962017-04-20 19:31:52 -04001232 } else {
1233 // no if, no else, no test side effects, kill the whole if
1234 // statement
Brian Osman010ce6a2020-10-19 16:34:10 -04001235 (*iter)->setStatement(std::make_unique<Nop>(), usage);
Ethan Nicholascb670962017-04-20 19:31:52 -04001236 }
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001237 optimizationContext->fUpdated = true;
1238 optimizationContext->fNeedsRescan = true;
Ethan Nicholascb670962017-04-20 19:31:52 -04001239 }
1240 break;
1241 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001242 case Statement::Kind::kSwitch: {
John Stiles642cde22021-02-23 14:57:01 -05001243 // TODO(skia:11319): this optimization logic is redundant with the static-switch
1244 // optimization code found in SwitchStatement.cpp.
John Stilesa5a97b42020-08-18 11:19:07 -04001245 SwitchStatement& s = stmt->as<SwitchStatement>();
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001246 int64_t switchValue;
Ethan Nicholasc0f98152021-02-05 16:21:10 -05001247 if (ConstantFolder::GetConstantInt(*s.value(), &switchValue)) {
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001248 // switch is constant, replace it with the case that matches
1249 bool found = false;
1250 SwitchCase* defaultCase = nullptr;
John Stiles2d4f9592020-10-30 10:29:12 -04001251 for (const std::unique_ptr<SwitchCase>& c : s.cases()) {
1252 if (!c->value()) {
1253 defaultCase = c.get();
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001254 continue;
1255 }
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001256 int64_t caseValue;
Ethan Nicholasc0f98152021-02-05 16:21:10 -05001257 SkAssertResult(ConstantFolder::GetConstantInt(*c->value(), &caseValue));
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001258 if (caseValue == switchValue) {
John Stiles642cde22021-02-23 14:57:01 -05001259 std::unique_ptr<Statement> newBlock =
1260 SwitchStatement::BlockForCase(&s.cases(), c.get(), s.symbols());
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001261 if (newBlock) {
Brian Osman010ce6a2020-10-19 16:34:10 -04001262 (*iter)->setStatement(std::move(newBlock), usage);
John Stiles9d944232020-08-19 09:56:49 -04001263 found = true;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001264 break;
1265 } else {
John Stilesd6a5f4492021-02-11 15:46:11 -05001266 if (s.isStatic() &&
John Stilesd1204642021-02-17 16:30:02 -05001267 !fContext->fConfig->fSettings.fPermitInvalidStaticTests) {
John Stilesd6a5f4492021-02-11 15:46:11 -05001268 auto [iter, didInsert] = optimizationContext->fSilences.insert(&s);
1269 if (didInsert) {
1270 this->error(s.fOffset, "static switch contains non-static "
John Stiles04ca41a2021-02-23 09:58:04 -05001271 "conditional exit");
John Stilesd6a5f4492021-02-11 15:46:11 -05001272 }
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001273 }
1274 return; // can't simplify
1275 }
1276 }
1277 }
1278 if (!found) {
1279 // no matching case. use default if it exists, or kill the whole thing
1280 if (defaultCase) {
John Stiles642cde22021-02-23 14:57:01 -05001281 std::unique_ptr<Statement> newBlock =
1282 SwitchStatement::BlockForCase(&s.cases(), defaultCase, s.symbols());
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001283 if (newBlock) {
Brian Osman010ce6a2020-10-19 16:34:10 -04001284 (*iter)->setStatement(std::move(newBlock), usage);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001285 } else {
John Stilesd6a5f4492021-02-11 15:46:11 -05001286 if (s.isStatic() &&
John Stilesd1204642021-02-17 16:30:02 -05001287 !fContext->fConfig->fSettings.fPermitInvalidStaticTests) {
John Stilesd6a5f4492021-02-11 15:46:11 -05001288 auto [iter, didInsert] = optimizationContext->fSilences.insert(&s);
1289 if (didInsert) {
1290 this->error(s.fOffset, "static switch contains non-static "
John Stiles04ca41a2021-02-23 09:58:04 -05001291 "conditional exit");
John Stilesd6a5f4492021-02-11 15:46:11 -05001292 }
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001293 }
1294 return; // can't simplify
1295 }
1296 } else {
Brian Osman010ce6a2020-10-19 16:34:10 -04001297 (*iter)->setStatement(std::make_unique<Nop>(), usage);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001298 }
1299 }
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001300 optimizationContext->fUpdated = true;
1301 optimizationContext->fNeedsRescan = true;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001302 }
1303 break;
1304 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001305 case Statement::Kind::kExpression: {
John Stilesa5a97b42020-08-18 11:19:07 -04001306 ExpressionStatement& e = stmt->as<ExpressionStatement>();
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001307 SkASSERT((*iter)->statement()->get() == &e);
Ethan Nicholasd503a5a2020-09-30 09:29:55 -04001308 if (!e.expression()->hasSideEffects()) {
Ethan Nicholascb670962017-04-20 19:31:52 -04001309 // Expression statement with no side effects, kill it
Ethan Nicholasd503a5a2020-09-30 09:29:55 -04001310 if (!b.tryRemoveExpressionBefore(iter, e.expression().get())) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001311 optimizationContext->fNeedsRescan = true;
Ethan Nicholascb670962017-04-20 19:31:52 -04001312 }
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001313 SkASSERT((*iter)->statement()->get() == stmt);
Brian Osman010ce6a2020-10-19 16:34:10 -04001314 (*iter)->setStatement(std::make_unique<Nop>(), usage);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001315 optimizationContext->fUpdated = true;
Ethan Nicholascb670962017-04-20 19:31:52 -04001316 }
1317 break;
1318 }
1319 default:
1320 break;
1321 }
1322}
1323
Brian Osman010ce6a2020-10-19 16:34:10 -04001324bool Compiler::scanCFG(FunctionDefinition& f, ProgramUsage* usage) {
John Stiles0cc193a2020-09-09 09:39:34 -04001325 bool madeChanges = false;
1326
Ethan Nicholascb670962017-04-20 19:31:52 -04001327 CFG cfg = CFGGenerator().getCFG(f);
1328 this->computeDataFlow(&cfg);
ethannicholas22f939e2016-10-13 13:25:34 -07001329
John Stiles66c53b92021-02-20 08:00:43 -05001330 if (fContext->fConfig->fSettings.fDeadCodeElimination) {
1331 // Check for unreachable code.
1332 for (size_t i = 0; i < cfg.fBlocks.size(); i++) {
1333 const BasicBlock& block = cfg.fBlocks[i];
1334 if (!block.fIsReachable && !block.fAllowUnreachable && block.fNodes.size()) {
1335 const BasicBlock::Node& node = block.fNodes[0];
1336 int offset = node.isStatement() ? (*node.statement())->fOffset
1337 : (*node.expression())->fOffset;
1338 this->error(offset, String("unreachable"));
1339 }
ethannicholas22f939e2016-10-13 13:25:34 -07001340 }
1341 }
1342 if (fErrorCount) {
John Stiles0cc193a2020-09-09 09:39:34 -04001343 return madeChanges;
ethannicholas22f939e2016-10-13 13:25:34 -07001344 }
1345
Ethan Nicholascb670962017-04-20 19:31:52 -04001346 // check for dead code & undefined variables, perform constant propagation
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001347 OptimizationContext optimizationContext;
Brian Osman010ce6a2020-10-19 16:34:10 -04001348 optimizationContext.fUsage = usage;
John Stiles7d3f0892020-11-03 11:35:01 -05001349 SkBitSet eliminatedBlockIds(cfg.fBlocks.size());
Ethan Nicholascb670962017-04-20 19:31:52 -04001350 do {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001351 if (optimizationContext.fNeedsRescan) {
Ethan Nicholascb670962017-04-20 19:31:52 -04001352 cfg = CFGGenerator().getCFG(f);
1353 this->computeDataFlow(&cfg);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001354 optimizationContext.fNeedsRescan = false;
Ethan Nicholas113628d2017-02-02 16:11:39 -05001355 }
Ethan Nicholascb670962017-04-20 19:31:52 -04001356
John Stiles7d3f0892020-11-03 11:35:01 -05001357 eliminatedBlockIds.reset();
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001358 optimizationContext.fUpdated = false;
John Stiles7d3f0892020-11-03 11:35:01 -05001359
1360 for (BlockId blockId = 0; blockId < cfg.fBlocks.size(); ++blockId) {
1361 if (eliminatedBlockIds.test(blockId)) {
1362 // We reached a block ID that might have been eliminated. Be cautious and rescan.
1363 optimizationContext.fUpdated = true;
1364 optimizationContext.fNeedsRescan = true;
1365 break;
1366 }
1367
1368 BasicBlock& b = cfg.fBlocks[blockId];
John Stiles66c53b92021-02-20 08:00:43 -05001369 if (fContext->fConfig->fSettings.fDeadCodeElimination) {
1370 if (blockId > 0 && !b.fIsReachable) {
1371 // Block was reachable before optimization, but has since become unreachable. In
1372 // addition to being dead code, it's broken - since control flow can't reach it,
1373 // no prior variable definitions can reach it, and therefore variables might
1374 // look to have not been properly assigned. Kill it by replacing all statements
1375 // with Nops.
1376 for (BasicBlock::Node& node : b.fNodes) {
1377 if (node.isStatement() && !(*node.statement())->is<Nop>()) {
1378 // Eliminating a node runs the risk of eliminating that node's exits as
1379 // well. Keep track of this and do a rescan if we are about to access
1380 // one of these.
1381 for (BlockId id : b.fExits) {
1382 eliminatedBlockIds.set(id);
1383 }
1384 node.setStatement(std::make_unique<Nop>(), usage);
1385 madeChanges = true;
John Stiles7d3f0892020-11-03 11:35:01 -05001386 }
Ethan Nicholas1de14812020-06-19 15:32:49 -04001387 }
John Stiles66c53b92021-02-20 08:00:43 -05001388 continue;
Ethan Nicholas1de14812020-06-19 15:32:49 -04001389 }
Ethan Nicholas1de14812020-06-19 15:32:49 -04001390 }
Ethan Nicholascb670962017-04-20 19:31:52 -04001391 DefinitionMap definitions = b.fBefore;
1392
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001393 for (auto iter = b.fNodes.begin(); iter != b.fNodes.end() &&
1394 !optimizationContext.fNeedsRescan; ++iter) {
John Stiles70025e52020-09-28 16:08:58 -04001395 if (iter->isExpression()) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001396 this->simplifyExpression(definitions, b, &iter, &optimizationContext);
Ethan Nicholascb670962017-04-20 19:31:52 -04001397 } else {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001398 this->simplifyStatement(definitions, b, &iter, &optimizationContext);
Ethan Nicholascb670962017-04-20 19:31:52 -04001399 }
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001400 if (optimizationContext.fNeedsRescan) {
Ethan Nicholas4b330df2017-05-17 10:52:55 -04001401 break;
1402 }
John Stilese8a24922021-02-08 17:54:08 -05001403 definitions.addDefinitions(*fContext, *iter);
Ethan Nicholascb670962017-04-20 19:31:52 -04001404 }
Brian Osman01a3eb42020-09-14 11:32:49 -04001405
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001406 if (optimizationContext.fNeedsRescan) {
Brian Osman01a3eb42020-09-14 11:32:49 -04001407 break;
1408 }
Ethan Nicholascb670962017-04-20 19:31:52 -04001409 }
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001410 madeChanges |= optimizationContext.fUpdated;
1411 } while (optimizationContext.fUpdated);
1412 SkASSERT(!optimizationContext.fNeedsRescan);
ethannicholas22f939e2016-10-13 13:25:34 -07001413
1414 // check for missing return
John Stiles54e7c052021-01-11 14:22:36 -05001415 if (f.declaration().returnType() != *fContext->fTypes.fVoid) {
John Stiles61e75e32020-10-01 15:42:37 -04001416 if (cfg.fBlocks[cfg.fExit].fIsReachable) {
Ethan Nicholas0a5d0962020-10-14 13:33:18 -04001417 this->error(f.fOffset, String("function '" + String(f.declaration().name()) +
Ethan Nicholasdb80f692019-11-22 14:06:12 -05001418 "' can exit without returning a value"));
ethannicholas22f939e2016-10-13 13:25:34 -07001419 }
1420 }
John Stiles0cc193a2020-09-09 09:39:34 -04001421
1422 return madeChanges;
ethannicholas22f939e2016-10-13 13:25:34 -07001423}
1424
Brian Osman32d53552020-09-23 13:55:20 -04001425std::unique_ptr<Program> Compiler::convertProgram(
John Stilesdbd4e6f2021-02-16 13:29:15 -05001426 ProgramKind kind,
Brian Osman32d53552020-09-23 13:55:20 -04001427 String text,
1428 const Program::Settings& settings,
Brian Osmanbe0b3b72021-01-06 14:27:35 -05001429 const std::vector<std::unique_ptr<ExternalFunction>>* externalFunctions) {
Leon Scrogginsb66214e2021-02-11 17:14:18 -05001430 ATRACE_ANDROID_FRAMEWORK("SkSL::Compiler::convertProgram");
1431
John Stilesdbd4e6f2021-02-16 13:29:15 -05001432 SkASSERT(!externalFunctions || (kind == ProgramKind::kGeneric));
Ethan Nicholas91164d12019-05-15 15:29:54 -04001433
Brian Osman0006ad02020-11-18 15:38:39 -05001434 // Loading and optimizing our base module might reset the inliner, so do that first,
1435 // *then* configure the inliner with the settings for this program.
1436 const ParsedModule& baseModule = this->moduleForProgramKind(kind);
1437
John Stiles270cec22021-02-17 12:59:36 -05001438 // Update our context to point to the program configuration for the duration of compilation.
1439 auto config = std::make_unique<ProgramConfig>(ProgramConfig{kind, settings});
1440
1441 SkASSERT(!fContext->fConfig);
1442 fContext->fConfig = config.get();
1443 SK_AT_SCOPE_EXIT(fContext->fConfig = nullptr);
1444
ethannicholasb3058bd2016-07-01 08:22:01 -07001445 fErrorText = "";
1446 fErrorCount = 0;
John Stilesd1204642021-02-17 16:30:02 -05001447 fInliner.reset(fIRGenerator->fModifiers.get());
Brian Osman88cda172020-10-09 12:05:16 -04001448
1449 // Not using AutoSource, because caller is likely to call errorText() if we fail to compile
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001450 std::unique_ptr<String> textPtr(new String(std::move(text)));
1451 fSource = textPtr.get();
Brian Osman88cda172020-10-09 12:05:16 -04001452
John Stiles5c7bb322020-10-22 11:09:15 -04001453 // Enable node pooling while converting and optimizing the program for a performance boost.
1454 // The Program will take ownership of the pool.
Brian Osman28f702c2021-02-02 11:52:07 -05001455 std::unique_ptr<Pool> pool;
1456 if (fCaps->useNodePools()) {
1457 pool = Pool::Create();
1458 pool->attachToThread();
1459 }
John Stilesd1204642021-02-17 16:30:02 -05001460 IRGenerator::IRBundle ir = fIRGenerator->convertProgram(baseModule, /*isBuiltinCode=*/false,
1461 textPtr->c_str(), textPtr->size(),
1462 externalFunctions);
John Stiles270cec22021-02-17 12:59:36 -05001463 auto program = std::make_unique<Program>(std::move(textPtr),
1464 std::move(config),
Brian Osmand7e76592020-11-02 12:26:22 -05001465 fCaps,
John Stiles5c7bb322020-10-22 11:09:15 -04001466 fContext,
1467 std::move(ir.fElements),
Brian Osman133724c2020-10-28 14:14:39 -04001468 std::move(ir.fSharedElements),
John Stiles5c7bb322020-10-22 11:09:15 -04001469 std::move(ir.fModifiers),
1470 std::move(ir.fSymbolTable),
1471 std::move(pool),
1472 ir.fInputs);
1473 bool success = false;
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001474 if (fErrorCount) {
John Stiles5c7bb322020-10-22 11:09:15 -04001475 // Do not return programs that failed to compile.
John Stilescbd65752021-02-24 14:14:14 +00001476 } else if (settings.fOptimize && !this->optimize(*program)) {
John Stiles5c7bb322020-10-22 11:09:15 -04001477 // Do not return programs that failed to optimize.
1478 } else {
1479 // We have a successful program!
1480 success = true;
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001481 }
John Stiles5c7bb322020-10-22 11:09:15 -04001482
Brian Osman28f702c2021-02-02 11:52:07 -05001483 if (program->fPool) {
1484 program->fPool->detachFromThread();
1485 }
John Stiles5c7bb322020-10-22 11:09:15 -04001486 return success ? std::move(program) : nullptr;
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001487}
1488
John Stilesbb1505f2021-02-12 09:17:53 -05001489void Compiler::verifyStaticTests(const Program& program) {
1490 class StaticTestVerifier : public ProgramVisitor {
1491 public:
1492 StaticTestVerifier(ErrorReporter* r) : fReporter(r) {}
1493
1494 using ProgramVisitor::visitProgramElement;
1495
1496 bool visitStatement(const Statement& stmt) override {
1497 switch (stmt.kind()) {
1498 case Statement::Kind::kIf:
1499 if (stmt.as<IfStatement>().isStatic()) {
1500 fReporter->error(stmt.fOffset, "static if has non-static test");
1501 }
1502 break;
1503
1504 case Statement::Kind::kSwitch:
1505 if (stmt.as<SwitchStatement>().isStatic()) {
1506 fReporter->error(stmt.fOffset, "static switch has non-static test");
1507 }
1508 break;
1509
1510 default:
1511 break;
1512 }
1513 return INHERITED::visitStatement(stmt);
1514 }
1515
John Stiles59e34562021-02-12 16:56:39 -05001516 bool visitExpression(const Expression&) override {
1517 // We aren't looking for anything inside an Expression, so skip them entirely.
1518 return false;
1519 }
1520
John Stilesbb1505f2021-02-12 09:17:53 -05001521 private:
1522 using INHERITED = ProgramVisitor;
1523 ErrorReporter* fReporter;
1524 };
1525
1526 // If invalid static tests are permitted, we don't need to check anything.
John Stilesd1204642021-02-17 16:30:02 -05001527 if (fContext->fConfig->fSettings.fPermitInvalidStaticTests) {
John Stilesbb1505f2021-02-12 09:17:53 -05001528 return;
1529 }
1530
1531 // Check all of the program's owned elements. (Built-in elements are assumed to be valid.)
1532 StaticTestVerifier visitor{this};
1533 for (const std::unique_ptr<ProgramElement>& element : program.ownedElements()) {
1534 if (element->is<FunctionDefinition>()) {
1535 visitor.visitProgramElement(*element);
1536 }
1537 }
1538}
1539
Brian Osman0006ad02020-11-18 15:38:39 -05001540bool Compiler::optimize(LoadedModule& module) {
1541 SkASSERT(!fErrorCount);
Brian Osman0006ad02020-11-18 15:38:39 -05001542
John Stiles270cec22021-02-17 12:59:36 -05001543 // Create a temporary program configuration with default settings.
1544 ProgramConfig config;
1545 config.fKind = module.fKind;
1546
1547 // Update our context to point to this configuration for the duration of compilation.
1548 SkASSERT(!fContext->fConfig);
1549 fContext->fConfig = &config;
1550 SK_AT_SCOPE_EXIT(fContext->fConfig = nullptr);
1551
John Stilesd1204642021-02-17 16:30:02 -05001552 // Reset the Inliner.
1553 fInliner.reset(fModifiers.back().get());
John Stiles270cec22021-02-17 12:59:36 -05001554
1555 std::unique_ptr<ProgramUsage> usage = Analysis::GetUsage(module);
Brian Osman0006ad02020-11-18 15:38:39 -05001556
1557 while (fErrorCount == 0) {
1558 bool madeChanges = false;
1559
1560 // Scan and optimize based on the control-flow graph for each function.
John Stiles0c7312a2021-02-24 11:31:32 -05001561 // TODO(skia:11365): we always perform CFG-based optimization here to reduce Settings into
1562 // their final form. We should do this optimization in our Make functions instead.
Brian Osman0006ad02020-11-18 15:38:39 -05001563 for (const auto& element : module.fElements) {
1564 if (element->is<FunctionDefinition>()) {
1565 madeChanges |= this->scanCFG(element->as<FunctionDefinition>(), usage.get());
1566 }
1567 }
1568
1569 // Perform inline-candidate analysis and inline any functions deemed suitable.
John Stiles78047582020-12-16 16:17:41 -05001570 madeChanges |= fInliner.analyze(module.fElements, module.fSymbols, usage.get());
Brian Osman0006ad02020-11-18 15:38:39 -05001571
1572 if (!madeChanges) {
1573 break;
1574 }
1575 }
1576 return fErrorCount == 0;
1577}
1578
Ethan Nicholas00543112018-07-31 09:44:36 -04001579bool Compiler::optimize(Program& program) {
1580 SkASSERT(!fErrorCount);
Brian Osman010ce6a2020-10-19 16:34:10 -04001581 ProgramUsage* usage = program.fUsage.get();
John Stiles7954d6c2020-09-01 10:53:02 -04001582
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001583 while (fErrorCount == 0) {
1584 bool madeChanges = false;
John Stiles7954d6c2020-09-01 10:53:02 -04001585
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001586 // Scan and optimize based on the control-flow graph for each function.
John Stiles0c7312a2021-02-24 11:31:32 -05001587 if (program.fConfig->fSettings.fControlFlowAnalysis) {
1588 for (const auto& element : program.ownedElements()) {
1589 if (element->is<FunctionDefinition>()) {
1590 madeChanges |= this->scanCFG(element->as<FunctionDefinition>(), usage);
1591 }
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001592 }
1593 }
1594
1595 // Perform inline-candidate analysis and inline any functions deemed suitable.
John Stiles78047582020-12-16 16:17:41 -05001596 madeChanges |= fInliner.analyze(program.ownedElements(), program.fSymbols, usage);
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001597
1598 // Remove dead functions. We wait until after analysis so that we still report errors,
1599 // even in unused code.
John Stiles270cec22021-02-17 12:59:36 -05001600 if (program.fConfig->fSettings.fRemoveDeadFunctions) {
Brian Osman133724c2020-10-28 14:14:39 -04001601 auto isDeadFunction = [&](const ProgramElement* element) {
1602 if (!element->is<FunctionDefinition>()) {
1603 return false;
1604 }
1605 const FunctionDefinition& fn = element->as<FunctionDefinition>();
1606 if (fn.declaration().name() != "main" && usage->get(fn.declaration()) == 0) {
1607 usage->remove(*element);
1608 madeChanges = true;
1609 return true;
1610 }
1611 return false;
1612 };
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001613 program.fElements.erase(
Brian Osman133724c2020-10-28 14:14:39 -04001614 std::remove_if(program.fElements.begin(), program.fElements.end(),
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001615 [&](const std::unique_ptr<ProgramElement>& element) {
Brian Osman133724c2020-10-28 14:14:39 -04001616 return isDeadFunction(element.get());
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001617 }),
1618 program.fElements.end());
Brian Osman133724c2020-10-28 14:14:39 -04001619 program.fSharedElements.erase(
1620 std::remove_if(program.fSharedElements.begin(), program.fSharedElements.end(),
1621 isDeadFunction),
1622 program.fSharedElements.end());
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001623 }
1624
John Stiles270cec22021-02-17 12:59:36 -05001625 if (program.fConfig->fKind != ProgramKind::kFragmentProcessor) {
Brian Osmanc0213602020-10-06 14:43:32 -04001626 // Remove declarations of dead global variables
Brian Osman133724c2020-10-28 14:14:39 -04001627 auto isDeadVariable = [&](const ProgramElement* element) {
1628 if (!element->is<GlobalVarDeclaration>()) {
1629 return false;
1630 }
1631 const GlobalVarDeclaration& global = element->as<GlobalVarDeclaration>();
1632 const VarDeclaration& varDecl = global.declaration()->as<VarDeclaration>();
1633 if (usage->isDead(varDecl.var())) {
1634 madeChanges = true;
1635 return true;
1636 }
1637 return false;
1638 };
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001639 program.fElements.erase(
1640 std::remove_if(program.fElements.begin(), program.fElements.end(),
1641 [&](const std::unique_ptr<ProgramElement>& element) {
Brian Osman133724c2020-10-28 14:14:39 -04001642 return isDeadVariable(element.get());
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001643 }),
1644 program.fElements.end());
Brian Osman133724c2020-10-28 14:14:39 -04001645 program.fSharedElements.erase(
1646 std::remove_if(program.fSharedElements.begin(), program.fSharedElements.end(),
1647 isDeadVariable),
1648 program.fSharedElements.end());
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001649 }
John Stiles73a6bff2020-09-09 13:40:37 -04001650
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001651 if (!madeChanges) {
1652 break;
Ethan Nicholas0dc80872019-02-08 15:46:24 -05001653 }
Ethan Nicholas00543112018-07-31 09:44:36 -04001654 }
John Stilesbb1505f2021-02-12 09:17:53 -05001655
1656 if (fErrorCount == 0) {
1657 this->verifyStaticTests(program);
1658 }
1659
Ethan Nicholas00543112018-07-31 09:44:36 -04001660 return fErrorCount == 0;
1661}
1662
Brian Osmanfb32ddf2019-06-18 10:14:20 -04001663#if defined(SKSL_STANDALONE) || SK_SUPPORT_GPU
1664
Ethan Nicholas00543112018-07-31 09:44:36 -04001665bool Compiler::toSPIRV(Program& program, OutputStream& out) {
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001666#ifdef SK_ENABLE_SPIRV_VALIDATION
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001667 StringStream buffer;
Brian Osman88cda172020-10-09 12:05:16 -04001668 AutoSource as(this, program.fSource.get());
Brian Osman8b43dad2020-10-09 13:31:42 -04001669 SPIRVCodeGenerator cg(fContext.get(), &program, this, &buffer);
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001670 bool result = cg.generateCode();
John Stiles270cec22021-02-17 12:59:36 -05001671 if (result && program.fConfig->fSettings.fValidateSPIRV) {
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001672 spvtools::SpirvTools tools(SPV_ENV_VULKAN_1_0);
Ethan Nicholas762466e2017-06-29 10:03:38 -04001673 const String& data = buffer.str();
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001674 SkASSERT(0 == data.size() % 4);
Brian Osman8d09d4a2020-11-24 15:51:06 -05001675 String errors;
1676 auto dumpmsg = [&errors](spv_message_level_t, const char*, const spv_position_t&,
1677 const char* m) {
1678 errors.appendf("SPIR-V validation error: %s\n", m);
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001679 };
1680 tools.SetMessageConsumer(dumpmsg);
Brian Osman8d09d4a2020-11-24 15:51:06 -05001681
1682 // Verify that the SPIR-V we produced is valid. At runtime, we will abort() with a message
1683 // explaining the error. In standalone mode (skslc), we will send the message, plus the
1684 // entire disassembled SPIR-V (for easier context & debugging) as *our* error message.
1685 result = tools.Validate((const uint32_t*) data.c_str(), data.size() / 4);
1686
1687 if (!result) {
1688#if defined(SKSL_STANDALONE)
1689 // Convert the string-stream to a SPIR-V disassembly.
1690 std::string disassembly;
1691 if (tools.Disassemble((const uint32_t*)data.data(), data.size() / 4, &disassembly)) {
1692 errors.append(disassembly);
1693 }
1694 this->error(-1, errors);
1695#else
1696 SkDEBUGFAILF("%s", errors.c_str());
1697#endif
1698 }
Ethan Nicholas762466e2017-06-29 10:03:38 -04001699 out.write(data.c_str(), data.size());
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001700 }
1701#else
Brian Osman88cda172020-10-09 12:05:16 -04001702 AutoSource as(this, program.fSource.get());
Brian Osman8b43dad2020-10-09 13:31:42 -04001703 SPIRVCodeGenerator cg(fContext.get(), &program, this, &out);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001704 bool result = cg.generateCode();
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001705#endif
Ethan Nicholasce33f102016-12-09 17:22:59 -05001706 return result;
1707}
1708
Ethan Nicholas00543112018-07-31 09:44:36 -04001709bool Compiler::toSPIRV(Program& program, String* out) {
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001710 StringStream buffer;
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001711 bool result = this->toSPIRV(program, buffer);
1712 if (result) {
Ethan Nicholas762466e2017-06-29 10:03:38 -04001713 *out = buffer.str();
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001714 }
1715 return result;
1716}
1717
Ethan Nicholas00543112018-07-31 09:44:36 -04001718bool Compiler::toGLSL(Program& program, OutputStream& out) {
Leon Scrogginsb66214e2021-02-11 17:14:18 -05001719 ATRACE_ANDROID_FRAMEWORK("SkSL::Compiler::toGLSL");
Brian Osman88cda172020-10-09 12:05:16 -04001720 AutoSource as(this, program.fSource.get());
Ethan Nicholas26a9aad2018-03-27 14:10:52 -04001721 GLSLCodeGenerator cg(fContext.get(), &program, this, &out);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001722 bool result = cg.generateCode();
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001723 return result;
1724}
1725
Ethan Nicholas00543112018-07-31 09:44:36 -04001726bool Compiler::toGLSL(Program& program, String* out) {
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001727 StringStream buffer;
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001728 bool result = this->toGLSL(program, buffer);
1729 if (result) {
Ethan Nicholas762466e2017-06-29 10:03:38 -04001730 *out = buffer.str();
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001731 }
1732 return result;
1733}
1734
Brian Osmanc0243912020-02-19 15:35:26 -05001735bool Compiler::toHLSL(Program& program, String* out) {
1736 String spirv;
1737 if (!this->toSPIRV(program, &spirv)) {
1738 return false;
1739 }
1740
1741 return SPIRVtoHLSL(spirv, out);
1742}
1743
Ethan Nicholas00543112018-07-31 09:44:36 -04001744bool Compiler::toMetal(Program& program, OutputStream& out) {
Ethan Nicholas26a9aad2018-03-27 14:10:52 -04001745 MetalCodeGenerator cg(fContext.get(), &program, this, &out);
Ethan Nicholascc305772017-10-13 16:17:45 -04001746 bool result = cg.generateCode();
Ethan Nicholascc305772017-10-13 16:17:45 -04001747 return result;
1748}
1749
Ethan Nicholas00543112018-07-31 09:44:36 -04001750bool Compiler::toMetal(Program& program, String* out) {
Timothy Liangb8eeb802018-07-23 16:46:16 -04001751 StringStream buffer;
1752 bool result = this->toMetal(program, buffer);
1753 if (result) {
1754 *out = buffer.str();
1755 }
1756 return result;
1757}
1758
Greg Daniela28ea672020-09-25 11:12:56 -04001759#if defined(SKSL_STANDALONE) || GR_TEST_UTILS
Ethan Nicholas00543112018-07-31 09:44:36 -04001760bool Compiler::toCPP(Program& program, String name, OutputStream& out) {
Brian Osman88cda172020-10-09 12:05:16 -04001761 AutoSource as(this, program.fSource.get());
Ethan Nicholas26a9aad2018-03-27 14:10:52 -04001762 CPPCodeGenerator cg(fContext.get(), &program, this, name, &out);
Ethan Nicholas762466e2017-06-29 10:03:38 -04001763 bool result = cg.generateCode();
Ethan Nicholas762466e2017-06-29 10:03:38 -04001764 return result;
1765}
1766
Ethan Nicholas00543112018-07-31 09:44:36 -04001767bool Compiler::toH(Program& program, String name, OutputStream& out) {
Brian Osman88cda172020-10-09 12:05:16 -04001768 AutoSource as(this, program.fSource.get());
Ethan Nicholas26a9aad2018-03-27 14:10:52 -04001769 HCodeGenerator cg(fContext.get(), &program, this, name, &out);
Ethan Nicholas762466e2017-06-29 10:03:38 -04001770 bool result = cg.generateCode();
Ethan Nicholas00543112018-07-31 09:44:36 -04001771 return result;
1772}
Greg Daniela28ea672020-09-25 11:12:56 -04001773#endif // defined(SKSL_STANDALONE) || GR_TEST_UTILS
Ethan Nicholas00543112018-07-31 09:44:36 -04001774
Ethan Nicholas2a479a52020-08-18 16:29:45 -04001775#endif // defined(SKSL_STANDALONE) || SK_SUPPORT_GPU
Brian Osman2e29ab52019-09-20 12:19:11 -04001776
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001777Position Compiler::position(int offset) {
Ethan Nicholas3c729892020-12-07 12:47:17 -05001778 if (fSource && offset >= 0) {
1779 int line = 1;
1780 int column = 1;
1781 for (int i = 0; i < offset; i++) {
1782 if ((*fSource)[i] == '\n') {
1783 ++line;
1784 column = 1;
1785 }
1786 else {
1787 ++column;
1788 }
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001789 }
Ethan Nicholas3c729892020-12-07 12:47:17 -05001790 return Position(line, column);
1791 } else {
1792 return Position(-1, -1);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001793 }
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001794}
1795
1796void Compiler::error(int offset, String msg) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001797 fErrorCount++;
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001798 Position pos = this->position(offset);
John Stiles8d3642e2021-01-22 09:50:04 -05001799 fErrorTextLength.push_back(fErrorText.length());
Ethan Nicholas3c729892020-12-07 12:47:17 -05001800 fErrorText += "error: " + (pos.fLine >= 1 ? to_string(pos.fLine) + ": " : "") + msg + "\n";
ethannicholasb3058bd2016-07-01 08:22:01 -07001801}
1802
John Stiles8d3642e2021-01-22 09:50:04 -05001803void Compiler::setErrorCount(int c) {
1804 if (c < fErrorCount) {
1805 fErrorText.resize(fErrorTextLength[c]);
1806 fErrorTextLength.resize(c);
1807 fErrorCount = c;
1808 }
1809}
1810
Ethan Nicholas95046142021-01-07 10:57:27 -05001811String Compiler::errorText(bool showCount) {
1812 if (showCount) {
1813 this->writeErrorCount();
1814 }
Ethan Nicholas00543112018-07-31 09:44:36 -04001815 fErrorCount = 0;
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001816 String result = fErrorText;
Ethan Nicholas95046142021-01-07 10:57:27 -05001817 fErrorText = "";
ethannicholasb3058bd2016-07-01 08:22:01 -07001818 return result;
1819}
1820
1821void Compiler::writeErrorCount() {
1822 if (fErrorCount) {
1823 fErrorText += to_string(fErrorCount) + " error";
1824 if (fErrorCount > 1) {
1825 fErrorText += "s";
1826 }
1827 fErrorText += "\n";
1828 }
1829}
1830
John Stilesa6841be2020-08-06 14:11:56 -04001831} // namespace SkSL