blob: 801639fb0a0c2037ad670c4e1fafd99eb12ab6ec [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 Stilesb92641c2020-08-31 18:09:01 -040013#include "src/sksl/SkSLAnalysis.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050014#include "src/sksl/SkSLByteCodeGenerator.h"
15#include "src/sksl/SkSLCFGGenerator.h"
16#include "src/sksl/SkSLCPPCodeGenerator.h"
17#include "src/sksl/SkSLGLSLCodeGenerator.h"
18#include "src/sksl/SkSLHCodeGenerator.h"
19#include "src/sksl/SkSLIRGenerator.h"
20#include "src/sksl/SkSLMetalCodeGenerator.h"
21#include "src/sksl/SkSLPipelineStageCodeGenerator.h"
Ethan Nicholasc18bb512020-07-28 14:46:53 -040022#include "src/sksl/SkSLRehydrator.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050023#include "src/sksl/SkSLSPIRVCodeGenerator.h"
Brian Osmanc0243912020-02-19 15:35:26 -050024#include "src/sksl/SkSLSPIRVtoHLSL.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050025#include "src/sksl/ir/SkSLEnum.h"
26#include "src/sksl/ir/SkSLExpression.h"
27#include "src/sksl/ir/SkSLExpressionStatement.h"
28#include "src/sksl/ir/SkSLFunctionCall.h"
29#include "src/sksl/ir/SkSLIntLiteral.h"
30#include "src/sksl/ir/SkSLModifiersDeclaration.h"
31#include "src/sksl/ir/SkSLNop.h"
32#include "src/sksl/ir/SkSLSymbolTable.h"
33#include "src/sksl/ir/SkSLTernaryExpression.h"
34#include "src/sksl/ir/SkSLUnresolvedFunction.h"
35#include "src/sksl/ir/SkSLVarDeclarations.h"
John Stilese6150002020-10-05 12:03:53 -040036#include "src/utils/SkBitSet.h"
ethannicholasb3058bd2016-07-01 08:22:01 -070037
Ethan Nicholasb33fa3f2020-08-06 13:00:19 -040038#include <fstream>
39
Ethan Nicholasa11035b2019-11-26 16:27:47 -050040#if !defined(SKSL_STANDALONE) & SK_SUPPORT_GPU
41#include "include/gpu/GrContextOptions.h"
42#include "src/gpu/GrShaderCaps.h"
43#endif
44
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -040045#ifdef SK_ENABLE_SPIRV_VALIDATION
46#include "spirv-tools/libspirv.hpp"
47#endif
48
Brian Osman3d87e9f2020-10-08 11:50:22 -040049#if defined(SKSL_STANDALONE)
Ethan Nicholasc18bb512020-07-28 14:46:53 -040050
Brian Osman3d87e9f2020-10-08 11:50:22 -040051// In standalone mode, we load the textual sksl source files. GN generates or copies these files
52// to the skslc executable directory. The "data" in this mode is just the filename.
53#define MODULE_DATA(name) MakeModulePath("sksl_" #name ".sksl")
54
55#else
56
57// At runtime, we load the dehydrated sksl data files. The data is a (pointer, size) pair.
Ethan Nicholasc18bb512020-07-28 14:46:53 -040058#include "src/sksl/generated/sksl_fp.dehydrated.sksl"
59#include "src/sksl/generated/sksl_frag.dehydrated.sksl"
60#include "src/sksl/generated/sksl_geom.dehydrated.sksl"
61#include "src/sksl/generated/sksl_gpu.dehydrated.sksl"
62#include "src/sksl/generated/sksl_interp.dehydrated.sksl"
63#include "src/sksl/generated/sksl_pipeline.dehydrated.sksl"
Brian Osmanb06301e2020-11-06 11:45:36 -050064#include "src/sksl/generated/sksl_public.dehydrated.sksl"
Ethan Nicholasc18bb512020-07-28 14:46:53 -040065#include "src/sksl/generated/sksl_vert.dehydrated.sksl"
66
Brian Osman3d87e9f2020-10-08 11:50:22 -040067#define MODULE_DATA(name) MakeModuleData(SKSL_INCLUDE_sksl_##name,\
68 SKSL_INCLUDE_sksl_##name##_LENGTH)
Ethan Nicholasc18bb512020-07-28 14:46:53 -040069
70#endif
Ethan Nicholas0d997662019-04-08 09:46:01 -040071
ethannicholasb3058bd2016-07-01 08:22:01 -070072namespace SkSL {
73
Brian Osman88cda172020-10-09 12:05:16 -040074class AutoSource {
75public:
76 AutoSource(Compiler* compiler, const String* source)
77 : fCompiler(compiler), fOldSource(fCompiler->fSource) {
78 fCompiler->fSource = source;
79 }
80
81 ~AutoSource() { fCompiler->fSource = fOldSource; }
82
83 Compiler* fCompiler;
84 const String* fOldSource;
85};
86
Brian Osmand7e76592020-11-02 12:26:22 -050087Compiler::Compiler(const ShaderCapsClass* caps, Flags flags)
Brian Osman0006ad02020-11-18 15:38:39 -050088 : fContext(std::make_shared<Context>())
89 , fCaps(caps)
90 , fInliner(fContext.get(), fCaps)
91 , fFlags(flags)
92 , fErrorCount(0) {
93 SkASSERT(fCaps);
John Stiles7c3515b2020-10-16 18:38:39 -040094 fRootSymbolTable = std::make_shared<SymbolTable>(this, /*builtin=*/true);
Brian Osmanb06301e2020-11-06 11:45:36 -050095 fPrivateSymbolTable = std::make_shared<SymbolTable>(fRootSymbolTable, /*builtin=*/true);
John Stiles0f464502020-11-20 12:52:22 -050096 fIRGenerator = std::make_unique<IRGenerator>(fContext.get(), fCaps, *this);
ethannicholasb3058bd2016-07-01 08:22:01 -070097
Brian Osmanb06301e2020-11-06 11:45:36 -050098#define TYPE(t) fContext->f##t##_Type.get()
ethannicholasb3058bd2016-07-01 08:22:01 -070099
Brian Osmanb06301e2020-11-06 11:45:36 -0500100 const SkSL::Symbol* rootTypes[] = {
101 TYPE(Void),
Brian Salomonbf7b6202016-11-11 16:08:03 -0500102
Brian Osmanb06301e2020-11-06 11:45:36 -0500103 TYPE( Float), TYPE( Float2), TYPE( Float3), TYPE( Float4),
104 TYPE( Half), TYPE( Half2), TYPE( Half3), TYPE( Half4),
105 TYPE( Int), TYPE( Int2), TYPE( Int3), TYPE( Int4),
106 TYPE( UInt), TYPE( UInt2), TYPE( UInt3), TYPE( UInt4),
107 TYPE( Short), TYPE( Short2), TYPE( Short3), TYPE( Short4),
108 TYPE(UShort), TYPE(UShort2), TYPE(UShort3), TYPE(UShort4),
109 TYPE( Byte), TYPE( Byte2), TYPE( Byte3), TYPE( Byte4),
110 TYPE( UByte), TYPE( UByte2), TYPE( UByte3), TYPE( UByte4),
111 TYPE( Bool), TYPE( Bool2), TYPE( Bool3), TYPE( Bool4),
Brian Salomon2a51de82016-11-16 12:06:01 -0500112
Brian Osmanb06301e2020-11-06 11:45:36 -0500113 TYPE(Float2x2), TYPE(Float2x3), TYPE(Float2x4),
114 TYPE(Float3x2), TYPE(Float3x3), TYPE(Float3x4),
115 TYPE(Float4x2), TYPE(Float4x3), TYPE(Float4x4),
Greg Daniel64773e62016-11-22 09:44:03 -0500116
Brian Osmanb06301e2020-11-06 11:45:36 -0500117 TYPE(Half2x2), TYPE(Half2x3), TYPE(Half2x4),
118 TYPE(Half3x2), TYPE(Half3x3), TYPE(Half3x4),
119 TYPE(Half4x2), TYPE(Half4x3), TYPE(Half4x4),
ethannicholasb3058bd2016-07-01 08:22:01 -0700120
Brian Osmanb06301e2020-11-06 11:45:36 -0500121 TYPE(GenType), TYPE(GenHType), TYPE(GenIType), TYPE(GenUType), TYPE(GenBType),
122 TYPE(Mat), TYPE(Vec),
123 TYPE(GVec), TYPE(GVec2), TYPE(GVec3), TYPE(GVec4),
124 TYPE(HVec), TYPE(IVec), TYPE(UVec), TYPE(SVec), TYPE(USVec),
125 TYPE(ByteVec), TYPE(UByteVec), TYPE(BVec),
126
127 TYPE(FragmentProcessor),
128 };
129
130 const SkSL::Symbol* privateTypes[] = {
131 TYPE(Sampler1D), TYPE(Sampler2D), TYPE(Sampler3D),
132 TYPE(SamplerExternalOES),
133 TYPE(SamplerCube),
134 TYPE(Sampler2DRect),
135 TYPE(Sampler1DArray), TYPE(Sampler2DArray), TYPE(SamplerCubeArray),
136 TYPE(SamplerBuffer),
137 TYPE(Sampler2DMS), TYPE(Sampler2DMSArray),
138
139 TYPE(ISampler2D),
140 TYPE(Image2D), TYPE(IImage2D),
141 TYPE(SubpassInput), TYPE(SubpassInputMS),
142
143 TYPE(GSampler1D), TYPE(GSampler2D), TYPE(GSampler3D),
144 TYPE(GSamplerCube),
145 TYPE(GSampler2DRect),
146 TYPE(GSampler1DArray), TYPE(GSampler2DArray), TYPE(GSamplerCubeArray),
147 TYPE(GSamplerBuffer),
148 TYPE(GSampler2DMS), TYPE(GSampler2DMSArray),
149
150 TYPE(Sampler1DShadow), TYPE(Sampler2DShadow), TYPE(SamplerCubeShadow),
151 TYPE(Sampler2DRectShadow),
152 TYPE(Sampler1DArrayShadow), TYPE(Sampler2DArrayShadow), TYPE(SamplerCubeArrayShadow),
153
154 TYPE(GSampler2DArrayShadow), TYPE(GSamplerCubeArrayShadow),
155 TYPE(Sampler),
156 TYPE(Texture2D),
157 };
158
159 for (const SkSL::Symbol* type : rootTypes) {
160 fRootSymbolTable->addWithoutOwnership(type);
161 }
162 for (const SkSL::Symbol* type : privateTypes) {
163 fPrivateSymbolTable->addWithoutOwnership(type);
164 }
165
166#undef TYPE
ethannicholasb3058bd2016-07-01 08:22:01 -0700167
Brian Osman3887a012020-09-30 13:22:27 -0400168 // sk_Caps is "builtin", but all references to it are resolved to Settings, so we don't need to
169 // treat it as builtin (ie, no need to clone it into the Program).
Brian Osmanb06301e2020-11-06 11:45:36 -0500170 fPrivateSymbolTable->add(
171 std::make_unique<Variable>(/*offset=*/-1,
John Stiles586df952020-11-12 18:27:13 -0500172 fIRGenerator->fModifiers->addToPool(Modifiers()),
Brian Osmanb06301e2020-11-06 11:45:36 -0500173 "sk_Caps",
174 fContext->fSkCaps_Type.get(),
175 /*builtin=*/false,
176 Variable::Storage::kGlobal));
Ethan Nicholas3605ace2016-11-21 15:59:48 -0500177
Brian Osman3d87e9f2020-10-08 11:50:22 -0400178 fRootModule = {fRootSymbolTable, /*fIntrinsics=*/nullptr};
Brian Osmanb06301e2020-11-06 11:45:36 -0500179 fPrivateModule = {fPrivateSymbolTable, /*fIntrinsics=*/nullptr};
John Stilesbc0c29e2020-09-28 13:13:40 -0400180
Brian Osmanb06301e2020-11-06 11:45:36 -0500181 fGPUModule = this->parseModule(Program::kFragment_Kind, MODULE_DATA(gpu), fPrivateModule);
Brian Osman3d87e9f2020-10-08 11:50:22 -0400182 fVertexModule = this->parseModule(Program::kVertex_Kind, MODULE_DATA(vert), fGPUModule);
183 fFragmentModule = this->parseModule(Program::kFragment_Kind, MODULE_DATA(frag), fGPUModule);
ethannicholasb3058bd2016-07-01 08:22:01 -0700184}
185
John Stilesdd13dba2020-10-29 10:45:34 -0400186Compiler::~Compiler() {}
ethannicholasb3058bd2016-07-01 08:22:01 -0700187
Brian Osman88cda172020-10-09 12:05:16 -0400188const ParsedModule& Compiler::loadGeometryModule() {
Brian Osman3d87e9f2020-10-08 11:50:22 -0400189 if (!fGeometryModule.fSymbols) {
190 fGeometryModule = this->parseModule(Program::kGeometry_Kind, MODULE_DATA(geom), fGPUModule);
Ethan Nicholasc18bb512020-07-28 14:46:53 -0400191 }
Brian Osman88cda172020-10-09 12:05:16 -0400192 return fGeometryModule;
Ethan Nicholasc18bb512020-07-28 14:46:53 -0400193}
194
Brian Osman88cda172020-10-09 12:05:16 -0400195const ParsedModule& Compiler::loadFPModule() {
Brian Osman3d87e9f2020-10-08 11:50:22 -0400196 if (!fFPModule.fSymbols) {
197 fFPModule =
198 this->parseModule(Program::kFragmentProcessor_Kind, MODULE_DATA(fp), fGPUModule);
Brian Osman8e2ef022020-09-30 13:26:43 -0400199 }
Brian Osman88cda172020-10-09 12:05:16 -0400200 return fFPModule;
Brian Osman8e2ef022020-09-30 13:26:43 -0400201}
202
Brian Osmanb06301e2020-11-06 11:45:36 -0500203const ParsedModule& Compiler::loadPublicModule() {
204 if (!fPublicModule.fSymbols) {
205 fPublicModule = this->parseModule(Program::kGeneric_Kind, MODULE_DATA(public), fRootModule);
206 }
207 return fPublicModule;
208}
209
Brian Osman88cda172020-10-09 12:05:16 -0400210const ParsedModule& Compiler::loadPipelineModule() {
Brian Osman3d87e9f2020-10-08 11:50:22 -0400211 if (!fPipelineModule.fSymbols) {
Brian Osmanb06301e2020-11-06 11:45:36 -0500212 fPipelineModule = this->parseModule(Program::kPipelineStage_Kind, MODULE_DATA(pipeline),
213 this->loadPublicModule());
Brian Osmanf1319c32020-10-13 09:34:23 -0400214
215 // Add some aliases to the pipeline module so that it's friendlier, and more like GLSL
216 fPipelineModule.fSymbols->addAlias("shader", fContext->fFragmentProcessor_Type.get());
217
218 fPipelineModule.fSymbols->addAlias("vec2", fContext->fFloat2_Type.get());
219 fPipelineModule.fSymbols->addAlias("vec3", fContext->fFloat3_Type.get());
220 fPipelineModule.fSymbols->addAlias("vec4", fContext->fFloat4_Type.get());
221
222 fPipelineModule.fSymbols->addAlias("bvec2", fContext->fBool2_Type.get());
223 fPipelineModule.fSymbols->addAlias("bvec3", fContext->fBool3_Type.get());
224 fPipelineModule.fSymbols->addAlias("bvec4", fContext->fBool4_Type.get());
225
226 fPipelineModule.fSymbols->addAlias("mat2", fContext->fFloat2x2_Type.get());
227 fPipelineModule.fSymbols->addAlias("mat3", fContext->fFloat3x3_Type.get());
228 fPipelineModule.fSymbols->addAlias("mat4", fContext->fFloat4x4_Type.get());
229
230 fPipelineModule.fSymbols->addAlias("mat2x2", fContext->fFloat2x2_Type.get());
231 fPipelineModule.fSymbols->addAlias("mat2x3", fContext->fFloat2x3_Type.get());
232 fPipelineModule.fSymbols->addAlias("mat2x4", fContext->fFloat2x4_Type.get());
233
234 fPipelineModule.fSymbols->addAlias("mat3x2", fContext->fFloat3x2_Type.get());
235 fPipelineModule.fSymbols->addAlias("mat3x3", fContext->fFloat3x3_Type.get());
236 fPipelineModule.fSymbols->addAlias("mat3x4", fContext->fFloat3x4_Type.get());
237
238 fPipelineModule.fSymbols->addAlias("mat4x2", fContext->fFloat4x2_Type.get());
239 fPipelineModule.fSymbols->addAlias("mat4x3", fContext->fFloat4x3_Type.get());
240 fPipelineModule.fSymbols->addAlias("mat4x4", fContext->fFloat4x4_Type.get());
Ethan Nicholasc18bb512020-07-28 14:46:53 -0400241 }
Brian Osman88cda172020-10-09 12:05:16 -0400242 return fPipelineModule;
Ethan Nicholasc18bb512020-07-28 14:46:53 -0400243}
244
Brian Osman88cda172020-10-09 12:05:16 -0400245const ParsedModule& Compiler::loadInterpreterModule() {
Brian Osman3d87e9f2020-10-08 11:50:22 -0400246 if (!fInterpreterModule.fSymbols) {
Brian Osmanb06301e2020-11-06 11:45:36 -0500247 fInterpreterModule = this->parseModule(Program::kGeneric_Kind, MODULE_DATA(interp),
248 this->loadPublicModule());
Ethan Nicholasc18bb512020-07-28 14:46:53 -0400249 }
Brian Osman88cda172020-10-09 12:05:16 -0400250 return fInterpreterModule;
251}
252
253const ParsedModule& Compiler::moduleForProgramKind(Program::Kind kind) {
254 switch (kind) {
255 case Program::kVertex_Kind: return fVertexModule; break;
256 case Program::kFragment_Kind: return fFragmentModule; break;
257 case Program::kGeometry_Kind: return this->loadGeometryModule(); break;
258 case Program::kFragmentProcessor_Kind: return this->loadFPModule(); break;
259 case Program::kPipelineStage_Kind: return this->loadPipelineModule(); break;
260 case Program::kGeneric_Kind: return this->loadInterpreterModule(); break;
261 }
262 SkUNREACHABLE;
Ethan Nicholasc18bb512020-07-28 14:46:53 -0400263}
264
Brian Osman3d87e9f2020-10-08 11:50:22 -0400265LoadedModule Compiler::loadModule(Program::Kind kind,
266 ModuleData data,
267 std::shared_ptr<SymbolTable> base) {
Brian Osman3d87e9f2020-10-08 11:50:22 -0400268 if (!base) {
Brian Osmanb06301e2020-11-06 11:45:36 -0500269 // NOTE: This is a workaround. The only time 'base' is null is when dehydrating includes.
270 // In that case, skslc doesn't know which module it's preparing, nor what the correct base
271 // module is. We can't use 'Root', because many GPU intrinsics reference private types,
272 // like samplers or textures. Today, 'Private' does contain the union of all known types,
273 // so this is safe. If we ever have types that only exist in 'Public' (for example), this
274 // logic needs to be smarter (by choosing the correct base for the module we're compiling).
275 base = fPrivateSymbolTable;
Brian Osman3d87e9f2020-10-08 11:50:22 -0400276 }
277
278#if defined(SKSL_STANDALONE)
279 SkASSERT(data.fPath);
280 std::ifstream in(data.fPath);
Brian Osmane498b3c2020-09-23 14:42:11 -0400281 std::unique_ptr<String> text = std::make_unique<String>(std::istreambuf_iterator<char>(in),
282 std::istreambuf_iterator<char>());
Ethan Nicholasb33fa3f2020-08-06 13:00:19 -0400283 if (in.rdstate()) {
Brian Osman3d87e9f2020-10-08 11:50:22 -0400284 printf("error reading %s\n", data.fPath);
Ethan Nicholasb33fa3f2020-08-06 13:00:19 -0400285 abort();
286 }
Brian Osmane498b3c2020-09-23 14:42:11 -0400287 const String* source = fRootSymbolTable->takeOwnershipOfString(std::move(text));
Brian Osman88cda172020-10-09 12:05:16 -0400288 AutoSource as(this, source);
Ethan Nicholas8da1e652019-05-24 11:01:59 -0400289 Program::Settings settings;
John Stiles881a10c2020-09-19 10:13:24 -0400290 SkASSERT(fIRGenerator->fCanInline);
291 fIRGenerator->fCanInline = false;
Brian Osman88cda172020-10-09 12:05:16 -0400292 ParsedModule baseModule = {base, /*fIntrinsics=*/nullptr};
Brian Osmand7e76592020-11-02 12:26:22 -0500293 IRGenerator::IRBundle ir =
Brian Osman0006ad02020-11-18 15:38:39 -0500294 fIRGenerator->convertProgram(kind, &settings, baseModule,
Brian Osmand7e76592020-11-02 12:26:22 -0500295 /*isBuiltinCode=*/true, source->c_str(), source->length(),
296 /*externalValues=*/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
316ParsedModule Compiler::parseModule(Program::Kind 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
ethannicholas22f939e2016-10-13 13:25:34 -0700371// add the definition created by assigning to the lvalue to the definition set
Ethan Nicholas86a43402017-01-19 13:32:00 -0500372void Compiler::addDefinition(const Expression* lvalue, std::unique_ptr<Expression>* expr,
373 DefinitionMap* definitions) {
Ethan Nicholase6592142020-09-08 10:22:09 -0400374 switch (lvalue->kind()) {
375 case Expression::Kind::kVariableReference: {
Ethan Nicholas78686922020-10-08 06:46:27 -0400376 const Variable& var = *lvalue->as<VariableReference>().variable();
Ethan Nicholas453f67f2020-10-09 10:43:45 -0400377 if (var.storage() == Variable::Storage::kLocal) {
John Stiles796cdb72020-10-08 12:06:53 -0400378 definitions->set(&var, expr);
ethannicholas22f939e2016-10-13 13:25:34 -0700379 }
380 break;
381 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400382 case Expression::Kind::kSwizzle:
ethannicholas22f939e2016-10-13 13:25:34 -0700383 // We consider the variable written to as long as at least some of its components have
384 // been written to. This will lead to some false negatives (we won't catch it if you
385 // write to foo.x and then read foo.y), but being stricter could lead to false positives
Mike Klein6ad99092016-10-26 10:35:22 -0400386 // (we write to foo.x, and then pass foo to a function which happens to only read foo.x,
387 // but since we pass foo as a whole it is flagged as an error) unless we perform a much
ethannicholas22f939e2016-10-13 13:25:34 -0700388 // more complicated whole-program analysis. This is probably good enough.
Ethan Nicholas6b4d5812020-10-12 16:11:51 -0400389 this->addDefinition(lvalue->as<Swizzle>().base().get(),
Ethan Nicholas26a9aad2018-03-27 14:10:52 -0400390 (std::unique_ptr<Expression>*) &fContext->fDefined_Expression,
ethannicholas22f939e2016-10-13 13:25:34 -0700391 definitions);
392 break;
Ethan Nicholase6592142020-09-08 10:22:09 -0400393 case Expression::Kind::kIndex:
ethannicholas22f939e2016-10-13 13:25:34 -0700394 // see comments in Swizzle
Ethan Nicholas2a4952d2020-10-08 15:35:56 -0400395 this->addDefinition(lvalue->as<IndexExpression>().base().get(),
Ethan Nicholas26a9aad2018-03-27 14:10:52 -0400396 (std::unique_ptr<Expression>*) &fContext->fDefined_Expression,
ethannicholas22f939e2016-10-13 13:25:34 -0700397 definitions);
398 break;
Ethan Nicholase6592142020-09-08 10:22:09 -0400399 case Expression::Kind::kFieldAccess:
ethannicholas22f939e2016-10-13 13:25:34 -0700400 // see comments in Swizzle
Ethan Nicholas7a95b202020-10-09 11:55:40 -0400401 this->addDefinition(lvalue->as<FieldAccess>().base().get(),
Ethan Nicholas26a9aad2018-03-27 14:10:52 -0400402 (std::unique_ptr<Expression>*) &fContext->fDefined_Expression,
ethannicholas22f939e2016-10-13 13:25:34 -0700403 definitions);
404 break;
Ethan Nicholase6592142020-09-08 10:22:09 -0400405 case Expression::Kind::kTernary:
Ethan Nicholasa583b812018-01-18 13:32:11 -0500406 // To simplify analysis, we just pretend that we write to both sides of the ternary.
407 // This allows for false positives (meaning we fail to detect that a variable might not
408 // have been assigned), but is preferable to false negatives.
Ethan Nicholasdd218162020-10-08 05:48:01 -0400409 this->addDefinition(lvalue->as<TernaryExpression>().ifTrue().get(),
Ethan Nicholas26a9aad2018-03-27 14:10:52 -0400410 (std::unique_ptr<Expression>*) &fContext->fDefined_Expression,
Ethan Nicholasa583b812018-01-18 13:32:11 -0500411 definitions);
Ethan Nicholasdd218162020-10-08 05:48:01 -0400412 this->addDefinition(lvalue->as<TernaryExpression>().ifFalse().get(),
Ethan Nicholas26a9aad2018-03-27 14:10:52 -0400413 (std::unique_ptr<Expression>*) &fContext->fDefined_Expression,
Ethan Nicholasa583b812018-01-18 13:32:11 -0500414 definitions);
415 break;
Ethan Nicholase6592142020-09-08 10:22:09 -0400416 case Expression::Kind::kExternalValue:
Ethan Nicholas91164d12019-05-15 15:29:54 -0400417 break;
ethannicholas22f939e2016-10-13 13:25:34 -0700418 default:
419 // not an lvalue, can't happen
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400420 SkASSERT(false);
ethannicholas22f939e2016-10-13 13:25:34 -0700421 }
422}
423
424// add local variables defined by this node to the set
John Stiles796cdb72020-10-08 12:06:53 -0400425void Compiler::addDefinitions(const BasicBlock::Node& node, DefinitionMap* definitions) {
John Stiles70025e52020-09-28 16:08:58 -0400426 if (node.isExpression()) {
427 Expression* expr = node.expression()->get();
428 switch (expr->kind()) {
429 case Expression::Kind::kBinary: {
430 BinaryExpression* b = &expr->as<BinaryExpression>();
431 if (b->getOperator() == Token::Kind::TK_EQ) {
John Stiles2d4f9592020-10-30 10:29:12 -0400432 this->addDefinition(b->left().get(), &b->right(), definitions);
John Stiles70025e52020-09-28 16:08:58 -0400433 } else if (Compiler::IsAssignment(b->getOperator())) {
434 this->addDefinition(
John Stiles2d4f9592020-10-30 10:29:12 -0400435 b->left().get(),
John Stiles70025e52020-09-28 16:08:58 -0400436 (std::unique_ptr<Expression>*) &fContext->fDefined_Expression,
437 definitions);
Ethan Nicholas86a43402017-01-19 13:32:00 -0500438
ethannicholas22f939e2016-10-13 13:25:34 -0700439 }
John Stiles70025e52020-09-28 16:08:58 -0400440 break;
ethannicholas22f939e2016-10-13 13:25:34 -0700441 }
John Stiles70025e52020-09-28 16:08:58 -0400442 case Expression::Kind::kFunctionCall: {
443 const FunctionCall& c = expr->as<FunctionCall>();
Brian Osman5bf3e202020-10-13 10:34:18 -0400444 const std::vector<const Variable*>& parameters = c.function().parameters();
Ethan Nicholased84b732020-10-08 11:45:44 -0400445 for (size_t i = 0; i < parameters.size(); ++i) {
446 if (parameters[i]->modifiers().fFlags & Modifiers::kOut_Flag) {
John Stiles70025e52020-09-28 16:08:58 -0400447 this->addDefinition(
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400448 c.arguments()[i].get(),
John Stiles70025e52020-09-28 16:08:58 -0400449 (std::unique_ptr<Expression>*) &fContext->fDefined_Expression,
450 definitions);
451 }
452 }
453 break;
454 }
455 case Expression::Kind::kPrefix: {
456 const PrefixExpression* p = &expr->as<PrefixExpression>();
Ethan Nicholas444ccc62020-10-09 10:16:22 -0400457 if (p->getOperator() == Token::Kind::TK_MINUSMINUS ||
458 p->getOperator() == Token::Kind::TK_PLUSPLUS) {
John Stiles70025e52020-09-28 16:08:58 -0400459 this->addDefinition(
Ethan Nicholas444ccc62020-10-09 10:16:22 -0400460 p->operand().get(),
John Stiles70025e52020-09-28 16:08:58 -0400461 (std::unique_ptr<Expression>*) &fContext->fDefined_Expression,
462 definitions);
463 }
464 break;
465 }
466 case Expression::Kind::kPostfix: {
467 const PostfixExpression* p = &expr->as<PostfixExpression>();
Ethan Nicholas444ccc62020-10-09 10:16:22 -0400468 if (p->getOperator() == Token::Kind::TK_MINUSMINUS ||
469 p->getOperator() == Token::Kind::TK_PLUSPLUS) {
John Stiles70025e52020-09-28 16:08:58 -0400470 this->addDefinition(
Ethan Nicholas444ccc62020-10-09 10:16:22 -0400471 p->operand().get(),
John Stiles70025e52020-09-28 16:08:58 -0400472 (std::unique_ptr<Expression>*) &fContext->fDefined_Expression,
473 definitions);
474 }
475 break;
476 }
477 case Expression::Kind::kVariableReference: {
478 const VariableReference* v = &expr->as<VariableReference>();
Ethan Nicholas453f67f2020-10-09 10:43:45 -0400479 if (v->refKind() != VariableReference::RefKind::kRead) {
John Stiles70025e52020-09-28 16:08:58 -0400480 this->addDefinition(
481 v,
482 (std::unique_ptr<Expression>*) &fContext->fDefined_Expression,
483 definitions);
484 }
485 break;
486 }
487 default:
488 break;
ethannicholas22f939e2016-10-13 13:25:34 -0700489 }
John Stiles70025e52020-09-28 16:08:58 -0400490 } else if (node.isStatement()) {
491 Statement* stmt = node.statement()->get();
492 if (stmt->is<VarDeclaration>()) {
493 VarDeclaration& vd = stmt->as<VarDeclaration>();
Ethan Nicholasc51f33e2020-10-13 13:49:44 -0400494 if (vd.value()) {
495 definitions->set(&vd.var(), &vd.value());
ethannicholas22f939e2016-10-13 13:25:34 -0700496 }
ethannicholas22f939e2016-10-13 13:25:34 -0700497 }
498 }
499}
500
John Stilese6150002020-10-05 12:03:53 -0400501void Compiler::scanCFG(CFG* cfg, BlockId blockId, SkBitSet* processedSet) {
ethannicholas22f939e2016-10-13 13:25:34 -0700502 BasicBlock& block = cfg->fBlocks[blockId];
503
504 // compute definitions after this block
Ethan Nicholas86a43402017-01-19 13:32:00 -0500505 DefinitionMap after = block.fBefore;
ethannicholas22f939e2016-10-13 13:25:34 -0700506 for (const BasicBlock::Node& n : block.fNodes) {
507 this->addDefinitions(n, &after);
508 }
509
510 // propagate definitions to exits
511 for (BlockId exitId : block.fExits) {
Ethan Nicholas26a9aad2018-03-27 14:10:52 -0400512 if (exitId == blockId) {
513 continue;
514 }
ethannicholas22f939e2016-10-13 13:25:34 -0700515 BasicBlock& exit = cfg->fBlocks[exitId];
John Stiles796cdb72020-10-08 12:06:53 -0400516 after.foreach([&](const Variable* var, std::unique_ptr<Expression>** e1Ptr) {
517 std::unique_ptr<Expression>* e1 = *e1Ptr;
518 std::unique_ptr<Expression>** exitDef = exit.fBefore.find(var);
519 if (!exitDef) {
John Stilese6150002020-10-05 12:03:53 -0400520 // exit has no definition for it, just copy it and reprocess exit block
521 processedSet->reset(exitId);
John Stiles796cdb72020-10-08 12:06:53 -0400522 exit.fBefore[var] = e1;
ethannicholas22f939e2016-10-13 13:25:34 -0700523 } else {
Ethan Nicholas86a43402017-01-19 13:32:00 -0500524 // exit has a (possibly different) value already defined
John Stiles796cdb72020-10-08 12:06:53 -0400525 std::unique_ptr<Expression>* e2 = *exitDef;
ethannicholas22f939e2016-10-13 13:25:34 -0700526 if (e1 != e2) {
John Stilese6150002020-10-05 12:03:53 -0400527 // definition has changed, merge and reprocess the exit block
528 processedSet->reset(exitId);
Ethan Nicholasaf197692017-02-27 13:26:45 -0500529 if (e1 && e2) {
John Stiles796cdb72020-10-08 12:06:53 -0400530 *exitDef = (std::unique_ptr<Expression>*)&fContext->fDefined_Expression;
Ethan Nicholasaf197692017-02-27 13:26:45 -0500531 } else {
John Stiles796cdb72020-10-08 12:06:53 -0400532 *exitDef = nullptr;
Ethan Nicholasaf197692017-02-27 13:26:45 -0500533 }
ethannicholas22f939e2016-10-13 13:25:34 -0700534 }
535 }
John Stiles796cdb72020-10-08 12:06:53 -0400536 });
ethannicholas22f939e2016-10-13 13:25:34 -0700537 }
538}
539
540// returns a map which maps all local variables in the function to null, indicating that their value
541// is initially unknown
Ethan Nicholas86a43402017-01-19 13:32:00 -0500542static DefinitionMap compute_start_state(const CFG& cfg) {
543 DefinitionMap result;
Mike Klein6ad99092016-10-26 10:35:22 -0400544 for (const auto& block : cfg.fBlocks) {
545 for (const auto& node : block.fNodes) {
John Stiles70025e52020-09-28 16:08:58 -0400546 if (node.isStatement()) {
Ethan Nicholascb670962017-04-20 19:31:52 -0400547 const Statement* s = node.statement()->get();
Brian Osmanc0213602020-10-06 14:43:32 -0400548 if (s->is<VarDeclaration>()) {
Ethan Nicholasc51f33e2020-10-13 13:49:44 -0400549 result[&s->as<VarDeclaration>().var()] = nullptr;
ethannicholas22f939e2016-10-13 13:25:34 -0700550 }
551 }
552 }
553 }
554 return result;
555}
556
Ethan Nicholascb670962017-04-20 19:31:52 -0400557/**
558 * Returns true if assigning to this lvalue has no effect.
559 */
Brian Osman010ce6a2020-10-19 16:34:10 -0400560static bool is_dead(const Expression& lvalue, ProgramUsage* usage) {
Ethan Nicholase6592142020-09-08 10:22:09 -0400561 switch (lvalue.kind()) {
562 case Expression::Kind::kVariableReference:
Brian Osman010ce6a2020-10-19 16:34:10 -0400563 return usage->isDead(*lvalue.as<VariableReference>().variable());
Ethan Nicholase6592142020-09-08 10:22:09 -0400564 case Expression::Kind::kSwizzle:
Brian Osman010ce6a2020-10-19 16:34:10 -0400565 return is_dead(*lvalue.as<Swizzle>().base(), usage);
Ethan Nicholase6592142020-09-08 10:22:09 -0400566 case Expression::Kind::kFieldAccess:
Brian Osman010ce6a2020-10-19 16:34:10 -0400567 return is_dead(*lvalue.as<FieldAccess>().base(), usage);
Ethan Nicholase6592142020-09-08 10:22:09 -0400568 case Expression::Kind::kIndex: {
John Stilesa5a97b42020-08-18 11:19:07 -0400569 const IndexExpression& idx = lvalue.as<IndexExpression>();
Brian Osman010ce6a2020-10-19 16:34:10 -0400570 return is_dead(*idx.base(), usage) &&
Ethan Nicholas2a4952d2020-10-08 15:35:56 -0400571 !idx.index()->hasProperty(Expression::Property::kSideEffects);
Ethan Nicholascb670962017-04-20 19:31:52 -0400572 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400573 case Expression::Kind::kTernary: {
John Stilesa5a97b42020-08-18 11:19:07 -0400574 const TernaryExpression& t = lvalue.as<TernaryExpression>();
Brian Osman010ce6a2020-10-19 16:34:10 -0400575 return !t.test()->hasSideEffects() &&
576 is_dead(*t.ifTrue(), usage) &&
577 is_dead(*t.ifFalse(), usage);
Ethan Nicholasa583b812018-01-18 13:32:11 -0500578 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400579 case Expression::Kind::kExternalValue:
Ethan Nicholas91164d12019-05-15 15:29:54 -0400580 return false;
Ethan Nicholascb670962017-04-20 19:31:52 -0400581 default:
Ethan Nicholas2a099da2020-01-02 14:40:54 -0500582#ifdef SK_DEBUG
Ethan Nicholascb670962017-04-20 19:31:52 -0400583 ABORT("invalid lvalue: %s\n", lvalue.description().c_str());
Ethan Nicholas2a099da2020-01-02 14:40:54 -0500584#endif
585 return false;
Ethan Nicholascb670962017-04-20 19:31:52 -0400586 }
587}
ethannicholas22f939e2016-10-13 13:25:34 -0700588
Ethan Nicholascb670962017-04-20 19:31:52 -0400589/**
590 * Returns true if this is an assignment which can be collapsed down to just the right hand side due
591 * to a dead target and lack of side effects on the left hand side.
592 */
Brian Osman010ce6a2020-10-19 16:34:10 -0400593static bool dead_assignment(const BinaryExpression& b, ProgramUsage* usage) {
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400594 if (!Compiler::IsAssignment(b.getOperator())) {
Ethan Nicholascb670962017-04-20 19:31:52 -0400595 return false;
596 }
John Stiles2d4f9592020-10-30 10:29:12 -0400597 return is_dead(*b.left(), usage);
Ethan Nicholascb670962017-04-20 19:31:52 -0400598}
599
600void Compiler::computeDataFlow(CFG* cfg) {
601 cfg->fBlocks[cfg->fStart].fBefore = compute_start_state(*cfg);
John Stilese6150002020-10-05 12:03:53 -0400602
603 // We set bits in the "processed" set after a block has been scanned.
604 SkBitSet processedSet(cfg->fBlocks.size());
605 while (SkBitSet::OptionalIndex blockId = processedSet.findFirstUnset()) {
606 processedSet.set(*blockId);
607 this->scanCFG(cfg, *blockId, &processedSet);
ethannicholas22f939e2016-10-13 13:25:34 -0700608 }
Ethan Nicholascb670962017-04-20 19:31:52 -0400609}
610
611/**
612 * Attempts to replace the expression pointed to by iter with a new one (in both the CFG and the
613 * IR). If the expression can be cleanly removed, returns true and updates the iterator to point to
614 * the newly-inserted element. Otherwise updates only the IR and returns false (and the CFG will
615 * need to be regenerated).
616 */
John Stilesafbf8992020-08-18 10:08:21 -0400617static bool try_replace_expression(BasicBlock* b,
618 std::vector<BasicBlock::Node>::iterator* iter,
619 std::unique_ptr<Expression>* newExpression) {
Ethan Nicholascb670962017-04-20 19:31:52 -0400620 std::unique_ptr<Expression>* target = (*iter)->expression();
621 if (!b->tryRemoveExpression(iter)) {
622 *target = std::move(*newExpression);
623 return false;
624 }
625 *target = std::move(*newExpression);
626 return b->tryInsertExpression(iter, target);
627}
628
629/**
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400630 * Returns true if the expression is a constant numeric literal with the specified value, or a
631 * constant vector with all elements equal to the specified value.
Ethan Nicholascb670962017-04-20 19:31:52 -0400632 */
Ethan Nicholasa3f22f12020-10-01 12:13:17 -0400633template <typename T = SKSL_FLOAT>
John Stiles9d944232020-08-19 09:56:49 -0400634static bool is_constant(const Expression& expr, T value) {
Ethan Nicholase6592142020-09-08 10:22:09 -0400635 switch (expr.kind()) {
636 case Expression::Kind::kIntLiteral:
Ethan Nicholase96cdd12020-09-28 16:27:18 -0400637 return expr.as<IntLiteral>().value() == value;
John Stiles9d944232020-08-19 09:56:49 -0400638
Ethan Nicholase6592142020-09-08 10:22:09 -0400639 case Expression::Kind::kFloatLiteral:
Ethan Nicholasa3f22f12020-10-01 12:13:17 -0400640 return expr.as<FloatLiteral>().value() == value;
John Stiles9d944232020-08-19 09:56:49 -0400641
Ethan Nicholase6592142020-09-08 10:22:09 -0400642 case Expression::Kind::kConstructor: {
John Stiles9d944232020-08-19 09:56:49 -0400643 const Constructor& constructor = expr.as<Constructor>();
644 if (constructor.isCompileTimeConstant()) {
Ethan Nicholas30d30222020-09-11 12:27:26 -0400645 const Type& constructorType = constructor.type();
646 bool isFloat = constructorType.columns() > 1
647 ? constructorType.componentType().isFloat()
648 : constructorType.isFloat();
649 switch (constructorType.typeKind()) {
Ethan Nicholase6592142020-09-08 10:22:09 -0400650 case Type::TypeKind::kVector:
Ethan Nicholas30d30222020-09-11 12:27:26 -0400651 for (int i = 0; i < constructorType.columns(); ++i) {
John Stiles9d944232020-08-19 09:56:49 -0400652 if (isFloat) {
653 if (constructor.getFVecComponent(i) != value) {
654 return false;
655 }
656 } else {
657 if (constructor.getIVecComponent(i) != value) {
658 return false;
659 }
660 }
Ethan Nicholasd188c182019-06-10 15:55:38 -0400661 }
John Stiles9d944232020-08-19 09:56:49 -0400662 return true;
663
Ethan Nicholase6592142020-09-08 10:22:09 -0400664 case Type::TypeKind::kScalar:
Ethan Nicholasf70f0442020-09-29 12:41:35 -0400665 SkASSERT(constructor.arguments().size() == 1);
666 return is_constant<T>(*constructor.arguments()[0], value);
John Stiles9d944232020-08-19 09:56:49 -0400667
668 default:
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400669 return false;
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400670 }
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400671 }
672 return false;
673 }
Ethan Nicholascb670962017-04-20 19:31:52 -0400674 default:
675 return false;
676 }
677}
678
679/**
680 * Collapses the binary expression pointed to by iter down to just the right side (in both the IR
681 * and CFG structures).
682 */
John Stilesafbf8992020-08-18 10:08:21 -0400683static void delete_left(BasicBlock* b,
684 std::vector<BasicBlock::Node>::iterator* iter,
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400685 Compiler::OptimizationContext* optimizationContext) {
686 optimizationContext->fUpdated = true;
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400687 std::unique_ptr<Expression>* target = (*iter)->expression();
John Stilesa5a97b42020-08-18 11:19:07 -0400688 BinaryExpression& bin = (*target)->as<BinaryExpression>();
John Stiles2d4f9592020-10-30 10:29:12 -0400689 Expression& left = *bin.left();
690 std::unique_ptr<Expression>& rightPointer = bin.right();
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400691 SkASSERT(!left.hasSideEffects());
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400692 bool result;
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400693 if (bin.getOperator() == Token::Kind::TK_EQ) {
694 result = b->tryRemoveLValueBefore(iter, &left);
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400695 } else {
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400696 result = b->tryRemoveExpressionBefore(iter, &left);
Ethan Nicholascb670962017-04-20 19:31:52 -0400697 }
Brian Osman010ce6a2020-10-19 16:34:10 -0400698 // Remove references within LHS.
699 optimizationContext->fUsage->remove(&left);
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400700 *target = std::move(rightPointer);
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400701 if (!result) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400702 optimizationContext->fNeedsRescan = true;
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400703 return;
704 }
705 if (*iter == b->fNodes.begin()) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400706 optimizationContext->fNeedsRescan = true;
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400707 return;
708 }
709 --(*iter);
John Stiles70025e52020-09-28 16:08:58 -0400710 if (!(*iter)->isExpression() || (*iter)->expression() != &rightPointer) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400711 optimizationContext->fNeedsRescan = true;
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400712 return;
713 }
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400714 *iter = b->fNodes.erase(*iter);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400715 SkASSERT((*iter)->expression() == target);
Ethan Nicholascb670962017-04-20 19:31:52 -0400716}
717
718/**
719 * Collapses the binary expression pointed to by iter down to just the left side (in both the IR and
720 * CFG structures).
721 */
John Stilesafbf8992020-08-18 10:08:21 -0400722static void delete_right(BasicBlock* b,
723 std::vector<BasicBlock::Node>::iterator* iter,
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400724 Compiler::OptimizationContext* optimizationContext) {
725 optimizationContext->fUpdated = true;
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400726 std::unique_ptr<Expression>* target = (*iter)->expression();
John Stilesa5a97b42020-08-18 11:19:07 -0400727 BinaryExpression& bin = (*target)->as<BinaryExpression>();
John Stiles2d4f9592020-10-30 10:29:12 -0400728 std::unique_ptr<Expression>& leftPointer = bin.left();
729 Expression& right = *bin.right();
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400730 SkASSERT(!right.hasSideEffects());
Brian Osman010ce6a2020-10-19 16:34:10 -0400731 // Remove references within RHS.
732 optimizationContext->fUsage->remove(&right);
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400733 if (!b->tryRemoveExpressionBefore(iter, &right)) {
734 *target = std::move(leftPointer);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400735 optimizationContext->fNeedsRescan = true;
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400736 return;
Ethan Nicholascb670962017-04-20 19:31:52 -0400737 }
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400738 *target = std::move(leftPointer);
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400739 if (*iter == b->fNodes.begin()) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400740 optimizationContext->fNeedsRescan = true;
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400741 return;
742 }
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400743 --(*iter);
John Stiles70025e52020-09-28 16:08:58 -0400744 if ((!(*iter)->isExpression() || (*iter)->expression() != &leftPointer)) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400745 optimizationContext->fNeedsRescan = true;
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400746 return;
747 }
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400748 *iter = b->fNodes.erase(*iter);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400749 SkASSERT((*iter)->expression() == target);
Ethan Nicholascb670962017-04-20 19:31:52 -0400750}
751
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400752/**
753 * Constructs the specified type using a single argument.
754 */
Ethan Nicholas30d30222020-09-11 12:27:26 -0400755static std::unique_ptr<Expression> construct(const Type* type, std::unique_ptr<Expression> v) {
John Stiles8e3b6be2020-10-13 11:14:08 -0400756 ExpressionArray args;
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400757 args.push_back(std::move(v));
Ethan Nicholase6592142020-09-08 10:22:09 -0400758 std::unique_ptr<Expression> result = std::make_unique<Constructor>(-1, type, std::move(args));
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400759 return result;
760}
761
762/**
763 * Used in the implementations of vectorize_left and vectorize_right. Given a vector type and an
764 * expression x, deletes the expression pointed to by iter and replaces it with <type>(x).
765 */
766static void vectorize(BasicBlock* b,
767 std::vector<BasicBlock::Node>::iterator* iter,
768 const Type& type,
769 std::unique_ptr<Expression>* otherExpression,
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400770 Compiler::OptimizationContext* optimizationContext) {
Ethan Nicholase6592142020-09-08 10:22:09 -0400771 SkASSERT((*(*iter)->expression())->kind() == Expression::Kind::kBinary);
772 SkASSERT(type.typeKind() == Type::TypeKind::kVector);
Ethan Nicholas30d30222020-09-11 12:27:26 -0400773 SkASSERT((*otherExpression)->type().typeKind() == Type::TypeKind::kScalar);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400774 optimizationContext->fUpdated = true;
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400775 std::unique_ptr<Expression>* target = (*iter)->expression();
776 if (!b->tryRemoveExpression(iter)) {
Ethan Nicholas30d30222020-09-11 12:27:26 -0400777 *target = construct(&type, std::move(*otherExpression));
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400778 optimizationContext->fNeedsRescan = true;
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400779 } else {
Ethan Nicholas30d30222020-09-11 12:27:26 -0400780 *target = construct(&type, std::move(*otherExpression));
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400781 if (!b->tryInsertExpression(iter, target)) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400782 optimizationContext->fNeedsRescan = true;
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400783 }
784 }
785}
786
787/**
788 * Given a binary expression of the form x <op> vec<n>(y), deletes the right side and vectorizes the
789 * left to yield vec<n>(x).
790 */
791static void vectorize_left(BasicBlock* b,
792 std::vector<BasicBlock::Node>::iterator* iter,
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400793 Compiler::OptimizationContext* optimizationContext) {
John Stilesa5a97b42020-08-18 11:19:07 -0400794 BinaryExpression& bin = (*(*iter)->expression())->as<BinaryExpression>();
Brian Osman010ce6a2020-10-19 16:34:10 -0400795 // Remove references within RHS. Vectorization of LHS doesn't change reference counts.
John Stiles2d4f9592020-10-30 10:29:12 -0400796 optimizationContext->fUsage->remove(bin.right().get());
797 vectorize(b, iter, bin.right()->type(), &bin.left(), optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400798}
799
800/**
801 * Given a binary expression of the form vec<n>(x) <op> y, deletes the left side and vectorizes the
802 * right to yield vec<n>(y).
803 */
804static void vectorize_right(BasicBlock* b,
805 std::vector<BasicBlock::Node>::iterator* iter,
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400806 Compiler::OptimizationContext* optimizationContext) {
John Stilesa5a97b42020-08-18 11:19:07 -0400807 BinaryExpression& bin = (*(*iter)->expression())->as<BinaryExpression>();
Brian Osman010ce6a2020-10-19 16:34:10 -0400808 // Remove references within LHS. Vectorization of RHS doesn't change reference counts.
John Stiles2d4f9592020-10-30 10:29:12 -0400809 optimizationContext->fUsage->remove(bin.left().get());
810 vectorize(b, iter, bin.left()->type(), &bin.right(), optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400811}
812
813// Mark that an expression which we were writing to is no longer being written to
John Stilesa5a97b42020-08-18 11:19:07 -0400814static void clear_write(Expression& expr) {
Ethan Nicholase6592142020-09-08 10:22:09 -0400815 switch (expr.kind()) {
816 case Expression::Kind::kVariableReference: {
Ethan Nicholas453f67f2020-10-09 10:43:45 -0400817 expr.as<VariableReference>().setRefKind(VariableReference::RefKind::kRead);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400818 break;
819 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400820 case Expression::Kind::kFieldAccess:
Ethan Nicholas7a95b202020-10-09 11:55:40 -0400821 clear_write(*expr.as<FieldAccess>().base());
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400822 break;
Ethan Nicholase6592142020-09-08 10:22:09 -0400823 case Expression::Kind::kSwizzle:
Ethan Nicholas6b4d5812020-10-12 16:11:51 -0400824 clear_write(*expr.as<Swizzle>().base());
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400825 break;
Ethan Nicholase6592142020-09-08 10:22:09 -0400826 case Expression::Kind::kIndex:
Ethan Nicholas2a4952d2020-10-08 15:35:56 -0400827 clear_write(*expr.as<IndexExpression>().base());
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400828 break;
829 default:
830 ABORT("shouldn't be writing to this kind of expression\n");
831 break;
832 }
833}
834
Ethan Nicholascb670962017-04-20 19:31:52 -0400835void Compiler::simplifyExpression(DefinitionMap& definitions,
836 BasicBlock& b,
837 std::vector<BasicBlock::Node>::iterator* iter,
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400838 OptimizationContext* optimizationContext) {
Ethan Nicholascb670962017-04-20 19:31:52 -0400839 Expression* expr = (*iter)->expression()->get();
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400840 SkASSERT(expr);
John Stiles108bbe22020-11-18 11:10:38 -0500841
Ethan Nicholascb670962017-04-20 19:31:52 -0400842 if ((*iter)->fConstantPropagation) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400843 std::unique_ptr<Expression> optimized = expr->constantPropagate(*fIRGenerator,
844 definitions);
Ethan Nicholascb670962017-04-20 19:31:52 -0400845 if (optimized) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400846 optimizationContext->fUpdated = true;
Ethan Nicholas30d30222020-09-11 12:27:26 -0400847 optimized = fIRGenerator->coerce(std::move(optimized), expr->type());
Ethan Nicholas1d881522020-09-11 09:32:54 -0400848 SkASSERT(optimized);
Brian Osman010ce6a2020-10-19 16:34:10 -0400849 // Remove references within 'expr', add references within 'optimized'
850 optimizationContext->fUsage->replace(expr, optimized.get());
Ethan Nicholascb670962017-04-20 19:31:52 -0400851 if (!try_replace_expression(&b, iter, &optimized)) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400852 optimizationContext->fNeedsRescan = true;
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400853 return;
Ethan Nicholascb670962017-04-20 19:31:52 -0400854 }
John Stiles70025e52020-09-28 16:08:58 -0400855 SkASSERT((*iter)->isExpression());
Ethan Nicholascb670962017-04-20 19:31:52 -0400856 expr = (*iter)->expression()->get();
Ethan Nicholascb670962017-04-20 19:31:52 -0400857 }
858 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400859 switch (expr->kind()) {
860 case Expression::Kind::kVariableReference: {
John Stilesa5a97b42020-08-18 11:19:07 -0400861 const VariableReference& ref = expr->as<VariableReference>();
Ethan Nicholas78686922020-10-08 06:46:27 -0400862 const Variable* var = ref.variable();
Ethan Nicholas453f67f2020-10-09 10:43:45 -0400863 if (ref.refKind() != VariableReference::RefKind::kWrite &&
864 ref.refKind() != VariableReference::RefKind::kPointer &&
865 var->storage() == Variable::Storage::kLocal && !definitions[var] &&
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400866 optimizationContext->fSilences.find(var) == optimizationContext->fSilences.end()) {
867 optimizationContext->fSilences.insert(var);
Ethan Nicholas82a62d22017-11-07 14:42:10 +0000868 this->error(expr->fOffset,
Ethan Nicholase2c49992020-10-05 11:49:11 -0400869 "'" + var->name() + "' has not been assigned");
Ethan Nicholascb670962017-04-20 19:31:52 -0400870 }
871 break;
872 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400873 case Expression::Kind::kTernary: {
John Stiles403a3632020-08-20 12:11:48 -0400874 TernaryExpression* t = &expr->as<TernaryExpression>();
Ethan Nicholasdd218162020-10-08 05:48:01 -0400875 if (t->test()->is<BoolLiteral>()) {
Ethan Nicholascb670962017-04-20 19:31:52 -0400876 // ternary has a constant test, replace it with either the true or
877 // false branch
Ethan Nicholasdd218162020-10-08 05:48:01 -0400878 if (t->test()->as<BoolLiteral>().value()) {
Brian Osman010ce6a2020-10-19 16:34:10 -0400879 (*iter)->setExpression(std::move(t->ifTrue()), optimizationContext->fUsage);
Ethan Nicholascb670962017-04-20 19:31:52 -0400880 } else {
Brian Osman010ce6a2020-10-19 16:34:10 -0400881 (*iter)->setExpression(std::move(t->ifFalse()), optimizationContext->fUsage);
Ethan Nicholascb670962017-04-20 19:31:52 -0400882 }
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400883 optimizationContext->fUpdated = true;
884 optimizationContext->fNeedsRescan = true;
Ethan Nicholascb670962017-04-20 19:31:52 -0400885 }
886 break;
887 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400888 case Expression::Kind::kBinary: {
John Stiles403a3632020-08-20 12:11:48 -0400889 BinaryExpression* bin = &expr->as<BinaryExpression>();
Brian Osman010ce6a2020-10-19 16:34:10 -0400890 if (dead_assignment(*bin, optimizationContext->fUsage)) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400891 delete_left(&b, iter, optimizationContext);
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400892 break;
893 }
John Stiles2d4f9592020-10-30 10:29:12 -0400894 Expression& left = *bin->left();
895 Expression& right = *bin->right();
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400896 const Type& leftType = left.type();
897 const Type& rightType = right.type();
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400898 // collapse useless expressions like x * 1 or x + 0
Ethan Nicholas30d30222020-09-11 12:27:26 -0400899 if (((leftType.typeKind() != Type::TypeKind::kScalar) &&
900 (leftType.typeKind() != Type::TypeKind::kVector)) ||
901 ((rightType.typeKind() != Type::TypeKind::kScalar) &&
902 (rightType.typeKind() != Type::TypeKind::kVector))) {
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400903 break;
904 }
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400905 switch (bin->getOperator()) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400906 case Token::Kind::TK_STAR:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400907 if (is_constant(left, 1)) {
Ethan Nicholas30d30222020-09-11 12:27:26 -0400908 if (leftType.typeKind() == Type::TypeKind::kVector &&
909 rightType.typeKind() == Type::TypeKind::kScalar) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400910 // float4(1) * x -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400911 vectorize_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400912 } else {
913 // 1 * x -> x
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400914 // 1 * float4(x) -> float4(x)
915 // float4(1) * float4(x) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400916 delete_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400917 }
918 }
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400919 else if (is_constant(left, 0)) {
Ethan Nicholas30d30222020-09-11 12:27:26 -0400920 if (leftType.typeKind() == Type::TypeKind::kScalar &&
921 rightType.typeKind() == Type::TypeKind::kVector &&
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400922 !right.hasSideEffects()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400923 // 0 * float4(x) -> float4(0)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400924 vectorize_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400925 } else {
926 // 0 * x -> 0
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400927 // float4(0) * x -> float4(0)
928 // float4(0) * float4(x) -> float4(0)
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400929 if (!right.hasSideEffects()) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400930 delete_right(&b, iter, optimizationContext);
Ethan Nicholas51493ee2017-12-11 12:34:33 -0500931 }
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400932 }
Ethan Nicholascb670962017-04-20 19:31:52 -0400933 }
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400934 else if (is_constant(right, 1)) {
Ethan Nicholas30d30222020-09-11 12:27:26 -0400935 if (leftType.typeKind() == Type::TypeKind::kScalar &&
936 rightType.typeKind() == Type::TypeKind::kVector) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400937 // x * float4(1) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400938 vectorize_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400939 } else {
940 // x * 1 -> x
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400941 // float4(x) * 1 -> float4(x)
942 // float4(x) * float4(1) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400943 delete_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400944 }
945 }
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400946 else if (is_constant(right, 0)) {
Ethan Nicholas30d30222020-09-11 12:27:26 -0400947 if (leftType.typeKind() == Type::TypeKind::kVector &&
948 rightType.typeKind() == Type::TypeKind::kScalar &&
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400949 !left.hasSideEffects()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400950 // float4(x) * 0 -> float4(0)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400951 vectorize_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400952 } else {
953 // x * 0 -> 0
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400954 // x * float4(0) -> float4(0)
955 // float4(x) * float4(0) -> float4(0)
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400956 if (!left.hasSideEffects()) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400957 delete_left(&b, iter, optimizationContext);
Ethan Nicholas51493ee2017-12-11 12:34:33 -0500958 }
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400959 }
Ethan Nicholascb670962017-04-20 19:31:52 -0400960 }
961 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400962 case Token::Kind::TK_PLUS:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400963 if (is_constant(left, 0)) {
Ethan Nicholas30d30222020-09-11 12:27:26 -0400964 if (leftType.typeKind() == Type::TypeKind::kVector &&
965 rightType.typeKind() == Type::TypeKind::kScalar) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400966 // float4(0) + x -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400967 vectorize_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400968 } else {
969 // 0 + x -> x
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400970 // 0 + float4(x) -> float4(x)
971 // float4(0) + float4(x) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400972 delete_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400973 }
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400974 } else if (is_constant(right, 0)) {
Ethan Nicholas30d30222020-09-11 12:27:26 -0400975 if (leftType.typeKind() == Type::TypeKind::kScalar &&
976 rightType.typeKind() == Type::TypeKind::kVector) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400977 // x + float4(0) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400978 vectorize_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400979 } else {
980 // x + 0 -> x
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400981 // float4(x) + 0 -> float4(x)
982 // float4(x) + float4(0) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400983 delete_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400984 }
Ethan Nicholas56e42712017-04-21 10:23:37 -0400985 }
986 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400987 case Token::Kind::TK_MINUS:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400988 if (is_constant(right, 0)) {
Ethan Nicholas30d30222020-09-11 12:27:26 -0400989 if (leftType.typeKind() == Type::TypeKind::kScalar &&
990 rightType.typeKind() == Type::TypeKind::kVector) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400991 // x - float4(0) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400992 vectorize_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400993 } else {
994 // x - 0 -> x
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400995 // float4(x) - 0 -> float4(x)
996 // float4(x) - float4(0) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400997 delete_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400998 }
Ethan Nicholascb670962017-04-20 19:31:52 -0400999 }
1000 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001001 case Token::Kind::TK_SLASH:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -04001002 if (is_constant(right, 1)) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001003 if (leftType.typeKind() == Type::TypeKind::kScalar &&
1004 rightType.typeKind() == Type::TypeKind::kVector) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -04001005 // x / float4(1) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001006 vectorize_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -04001007 } else {
1008 // x / 1 -> x
Ethan Nicholas5af9ea32017-07-28 15:19:46 -04001009 // float4(x) / 1 -> float4(x)
1010 // float4(x) / float4(1) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001011 delete_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -04001012 }
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -04001013 } else if (is_constant(left, 0)) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001014 if (leftType.typeKind() == Type::TypeKind::kScalar &&
1015 rightType.typeKind() == Type::TypeKind::kVector &&
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -04001016 !right.hasSideEffects()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -04001017 // 0 / float4(x) -> float4(0)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001018 vectorize_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -04001019 } else {
1020 // 0 / x -> 0
Ethan Nicholas5af9ea32017-07-28 15:19:46 -04001021 // float4(0) / x -> float4(0)
1022 // float4(0) / float4(x) -> float4(0)
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -04001023 if (!right.hasSideEffects()) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001024 delete_right(&b, iter, optimizationContext);
Ethan Nicholas51493ee2017-12-11 12:34:33 -05001025 }
Ethan Nicholasfe53e582017-04-27 16:24:51 -04001026 }
1027 }
1028 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001029 case Token::Kind::TK_PLUSEQ:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -04001030 if (is_constant(right, 0)) {
1031 clear_write(left);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001032 delete_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -04001033 }
1034 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001035 case Token::Kind::TK_MINUSEQ:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -04001036 if (is_constant(right, 0)) {
1037 clear_write(left);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001038 delete_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -04001039 }
1040 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001041 case Token::Kind::TK_STAREQ:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -04001042 if (is_constant(right, 1)) {
1043 clear_write(left);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001044 delete_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -04001045 }
1046 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001047 case Token::Kind::TK_SLASHEQ:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -04001048 if (is_constant(right, 1)) {
1049 clear_write(left);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001050 delete_right(&b, iter, optimizationContext);
Ethan Nicholascb670962017-04-20 19:31:52 -04001051 }
1052 break;
1053 default:
1054 break;
1055 }
Ethan Nicholas409f6f02019-09-17 12:34:39 -04001056 break;
1057 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001058 case Expression::Kind::kSwizzle: {
John Stiles403a3632020-08-20 12:11:48 -04001059 Swizzle& s = expr->as<Swizzle>();
John Stiles108bbe22020-11-18 11:10:38 -05001060 // Detect identity swizzles like `foo.rgba`.
Ethan Nicholas6b4d5812020-10-12 16:11:51 -04001061 if ((int) s.components().size() == s.base()->type().columns()) {
Ethan Nicholas409f6f02019-09-17 12:34:39 -04001062 bool identity = true;
Ethan Nicholas6b4d5812020-10-12 16:11:51 -04001063 for (int i = 0; i < (int) s.components().size(); ++i) {
1064 if (s.components()[i] != i) {
Ethan Nicholas409f6f02019-09-17 12:34:39 -04001065 identity = false;
1066 break;
1067 }
1068 }
1069 if (identity) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001070 optimizationContext->fUpdated = true;
Brian Osman010ce6a2020-10-19 16:34:10 -04001071 // No fUsage change: foo.rgba and foo have equivalent reference counts
Ethan Nicholas6b4d5812020-10-12 16:11:51 -04001072 if (!try_replace_expression(&b, iter, &s.base())) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001073 optimizationContext->fNeedsRescan = true;
Ethan Nicholas409f6f02019-09-17 12:34:39 -04001074 return;
1075 }
John Stiles70025e52020-09-28 16:08:58 -04001076 SkASSERT((*iter)->isExpression());
Ethan Nicholas409f6f02019-09-17 12:34:39 -04001077 break;
1078 }
1079 }
John Stiles108bbe22020-11-18 11:10:38 -05001080 // Detect swizzles of swizzles, e.g. replace `foo.argb.r000` with `foo.a000`.
1081 if (s.base()->is<Swizzle>()) {
Ethan Nicholas6b4d5812020-10-12 16:11:51 -04001082 Swizzle& base = s.base()->as<Swizzle>();
John Stiles750109b2020-10-30 13:45:46 -04001083 ComponentArray final;
Ethan Nicholas6b4d5812020-10-12 16:11:51 -04001084 for (int c : s.components()) {
1085 final.push_back(base.components()[c]);
Ethan Nicholas409f6f02019-09-17 12:34:39 -04001086 }
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001087 optimizationContext->fUpdated = true;
Ethan Nicholas6b4d5812020-10-12 16:11:51 -04001088 std::unique_ptr<Expression> replacement(new Swizzle(*fContext, base.base()->clone(),
John Stiles750109b2020-10-30 13:45:46 -04001089 final));
John Stiles108bbe22020-11-18 11:10:38 -05001090 // No fUsage change: `foo.gbr.gbr` and `foo.brg` have equivalent reference counts
Ethan Nicholas409f6f02019-09-17 12:34:39 -04001091 if (!try_replace_expression(&b, iter, &replacement)) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001092 optimizationContext->fNeedsRescan = true;
Ethan Nicholas409f6f02019-09-17 12:34:39 -04001093 return;
1094 }
John Stiles70025e52020-09-28 16:08:58 -04001095 SkASSERT((*iter)->isExpression());
John Stiles108bbe22020-11-18 11:10:38 -05001096 break;
1097 }
1098 // Optimize swizzles of constructors.
1099 if (s.base()->is<Constructor>()) {
1100 Constructor& base = s.base()->as<Constructor>();
1101 std::unique_ptr<Expression> replacement;
1102 const Type& componentType = base.type().componentType();
1103 int swizzleSize = s.components().size();
1104
1105 // The IR generator has already converted any zero/one swizzle components into
1106 // constructors containing zero/one args. Confirm that this is true by checking that
1107 // our swizzle components are all `xyzw` (values 0 through 3).
1108 SkASSERT(std::all_of(s.components().begin(), s.components().end(),
1109 [](int8_t c) { return c >= 0 && c <= 3; }));
1110
1111 if (base.arguments().size() == 1 &&
1112 base.arguments().front()->type().typeKind() == Type::TypeKind::kScalar) {
1113 // `half4(scalar).zyy` can be optimized to `half3(scalar)`. The swizzle
1114 // components don't actually matter since all fields are the same.
1115 ExpressionArray newArgs;
1116 newArgs.push_back(base.arguments().front()->clone());
1117 replacement = std::make_unique<Constructor>(
1118 base.fOffset,
1119 &componentType.toCompound(*fContext, swizzleSize, /*rows=*/1),
1120 std::move(newArgs));
1121
1122 // No fUsage change: `half4(foo).xy` and `half2(foo)` have equivalent reference
1123 // counts.
John Stiles0777ac42020-11-19 11:06:47 -05001124 optimizationContext->fUpdated = true;
John Stiles108bbe22020-11-18 11:10:38 -05001125 if (!try_replace_expression(&b, iter, &replacement)) {
1126 optimizationContext->fNeedsRescan = true;
1127 return;
1128 }
1129 SkASSERT((*iter)->isExpression());
1130 break;
1131 }
1132
John Stiles0777ac42020-11-19 11:06:47 -05001133 // Swizzles can duplicate some elements and discard others, e.g.
1134 // `half4(1, 2, 3, 4).xxz` --> `half3(1, 1, 3)`. However, there are constraints:
1135 // - Expressions with side effects need to occur exactly once, even if they
1136 // would otherwise be swizzle-eliminated
1137 // - Non-trivial expressions should not be repeated, but elimination is OK.
1138 //
1139 // Look up the argument for the constructor at each index. This is typically simple
1140 // but for weird cases like `half4(bar.yz, half2(foo))`, it can be harder than it
1141 // seems. This example would result in:
1142 // argMap[0] = {.fArgIndex = 0, .fComponent = 0} (bar.yz .x)
1143 // argMap[1] = {.fArgIndex = 0, .fComponent = 1} (bar.yz .y)
1144 // argMap[2] = {.fArgIndex = 1, .fComponent = 0} (half2(foo) .x)
1145 // argMap[3] = {.fArgIndex = 1, .fComponent = 1} (half2(foo) .y)
1146 struct ConstructorArgMap {
1147 int8_t fArgIndex;
1148 int8_t fComponent;
1149 };
1150
1151 int numConstructorArgs = base.type().columns();
1152 ConstructorArgMap argMap[4] = {};
1153 int writeIdx = 0;
1154 for (int argIdx = 0; argIdx < (int) base.arguments().size(); ++argIdx) {
1155 const Expression& expr = *base.arguments()[argIdx];
1156 int argWidth = expr.type().columns();
1157 for (int componentIdx = 0; componentIdx < argWidth; ++componentIdx) {
1158 argMap[writeIdx].fArgIndex = argIdx;
1159 argMap[writeIdx].fComponent = componentIdx;
1160 ++writeIdx;
1161 }
1162 }
1163 SkASSERT(writeIdx == numConstructorArgs);
1164
1165 // Count up the number of times each constructor argument is used by the
1166 // swizzle.
1167 // `half4(bar.yz, half2(foo)).xwxy` -> { 3, 1 }
1168 // - bar.yz is referenced 3 times, by `.x_xy`
1169 // - half(foo) is referenced 1 time, by `._w__`
1170 int8_t exprUsed[4] = {};
1171 for (int c : s.components()) {
1172 exprUsed[argMap[c].fArgIndex]++;
1173 }
1174
1175 bool safeToOptimize = true;
1176 for (int index = 0; index < numConstructorArgs; ++index) {
1177 int8_t constructorArgIndex = argMap[index].fArgIndex;
1178 const Expression& baseArg = *base.arguments()[constructorArgIndex];
1179
1180 // Check that non-trivial expressions are not swizzled in more than once.
John Stilesc30fbca2020-11-19 16:25:49 -05001181 if (exprUsed[constructorArgIndex] > 1 &&
1182 !Analysis::IsTrivialExpression(baseArg)) {
John Stiles0777ac42020-11-19 11:06:47 -05001183 safeToOptimize = false;
1184 break;
1185 }
1186 // Check that side-effect-bearing expressions are swizzled in exactly once.
1187 if (exprUsed[constructorArgIndex] != 1 && baseArg.hasSideEffects()) {
1188 safeToOptimize = false;
1189 break;
1190 }
1191 }
1192
1193 if (safeToOptimize) {
John Stilesd9076cb2020-11-19 12:18:36 -05001194 struct ReorderedArgument {
1195 int8_t fArgIndex;
1196 ComponentArray fComponents;
1197 };
1198 SkSTArray<4, ReorderedArgument> reorderedArgs;
John Stiles0777ac42020-11-19 11:06:47 -05001199 for (int c : s.components()) {
1200 const ConstructorArgMap& argument = argMap[c];
1201 const Expression& baseArg = *base.arguments()[argument.fArgIndex];
1202
1203 if (baseArg.type().typeKind() == Type::TypeKind::kScalar) {
John Stilesd9076cb2020-11-19 12:18:36 -05001204 // This argument is a scalar; add it to the list as-is.
John Stiles0777ac42020-11-19 11:06:47 -05001205 SkASSERT(argument.fComponent == 0);
John Stilesd9076cb2020-11-19 12:18:36 -05001206 reorderedArgs.push_back({argument.fArgIndex,
1207 ComponentArray{}});
John Stiles0777ac42020-11-19 11:06:47 -05001208 } else {
John Stilesd9076cb2020-11-19 12:18:36 -05001209 // This argument is a component from a vector.
John Stiles0777ac42020-11-19 11:06:47 -05001210 SkASSERT(argument.fComponent < baseArg.type().columns());
John Stilesd9076cb2020-11-19 12:18:36 -05001211 if (reorderedArgs.empty() ||
1212 reorderedArgs.back().fArgIndex != argument.fArgIndex) {
1213 // This can't be combined with the previous argument. Add a new one.
1214 reorderedArgs.push_back({argument.fArgIndex,
1215 ComponentArray{argument.fComponent}});
1216 } else {
1217 // Since we know this argument uses components, it should already
1218 // have at least one component set.
1219 SkASSERT(!reorderedArgs.back().fComponents.empty());
1220 // Build up the current argument with one more component.
1221 reorderedArgs.back().fComponents.push_back(argument.fComponent);
1222 }
John Stiles0777ac42020-11-19 11:06:47 -05001223 }
1224 }
John Stilesd9076cb2020-11-19 12:18:36 -05001225
1226 // Convert our reordered argument list to an actual array of expressions, with
1227 // the new order and any new inner swizzles that need to be applied. Note that
1228 // we expect followup passes to clean up the inner swizzles.
1229 ExpressionArray newArgs;
1230 newArgs.reserve_back(swizzleSize);
1231 for (const ReorderedArgument& reorderedArg : reorderedArgs) {
1232 const Expression& baseArg = *base.arguments()[reorderedArg.fArgIndex];
1233 if (reorderedArg.fComponents.empty()) {
1234 newArgs.push_back(baseArg.clone());
1235 } else {
1236 newArgs.push_back(std::make_unique<Swizzle>(*fContext, baseArg.clone(),
1237 reorderedArg.fComponents));
1238 }
1239 }
1240
1241 // Create a new constructor.
John Stiles0777ac42020-11-19 11:06:47 -05001242 replacement = std::make_unique<Constructor>(
1243 base.fOffset,
1244 &componentType.toCompound(*fContext, swizzleSize, /*rows=*/1),
1245 std::move(newArgs));
1246
1247 // Remove references within 'expr', add references within 'optimized'
1248 optimizationContext->fUpdated = true;
1249 optimizationContext->fUsage->replace(expr, replacement.get());
1250 if (!try_replace_expression(&b, iter, &replacement)) {
1251 optimizationContext->fNeedsRescan = true;
1252 return;
1253 }
1254 SkASSERT((*iter)->isExpression());
1255 }
John Stiles108bbe22020-11-18 11:10:38 -05001256 break;
Ethan Nicholas409f6f02019-09-17 12:34:39 -04001257 }
John Stiles30212b72020-06-11 17:55:07 -04001258 break;
Ethan Nicholascb670962017-04-20 19:31:52 -04001259 }
1260 default:
1261 break;
1262 }
1263}
1264
John Stiles92219b42020-06-15 12:32:24 -04001265// Returns true if this statement could potentially execute a break at the current level. We ignore
1266// nested loops and switches, since any breaks inside of them will merely break the loop / switch.
John Stilesb92641c2020-08-31 18:09:01 -04001267static bool contains_conditional_break(Statement& stmt) {
1268 class ContainsConditionalBreak : public ProgramVisitor {
1269 public:
1270 bool visitStatement(const Statement& stmt) override {
Ethan Nicholase6592142020-09-08 10:22:09 -04001271 switch (stmt.kind()) {
1272 case Statement::Kind::kBlock:
John Stilesb92641c2020-08-31 18:09:01 -04001273 return this->INHERITED::visitStatement(stmt);
1274
Ethan Nicholase6592142020-09-08 10:22:09 -04001275 case Statement::Kind::kBreak:
John Stilesb92641c2020-08-31 18:09:01 -04001276 return fInConditional > 0;
1277
Ethan Nicholase6592142020-09-08 10:22:09 -04001278 case Statement::Kind::kIf: {
John Stilesb92641c2020-08-31 18:09:01 -04001279 ++fInConditional;
1280 bool result = this->INHERITED::visitStatement(stmt);
1281 --fInConditional;
1282 return result;
1283 }
1284
1285 default:
1286 return false;
1287 }
1288 }
1289
1290 int fInConditional = 0;
1291 using INHERITED = ProgramVisitor;
1292 };
1293
1294 return ContainsConditionalBreak{}.visitStatement(stmt);
John Stiles92219b42020-06-15 12:32:24 -04001295}
1296
Ethan Nicholas5005a222018-08-24 13:06:27 -04001297// returns true if this statement definitely executes a break at the current level (we ignore
1298// nested loops and switches, since any breaks inside of them will merely break the loop / switch)
John Stilesb92641c2020-08-31 18:09:01 -04001299static bool contains_unconditional_break(Statement& stmt) {
1300 class ContainsUnconditionalBreak : public ProgramVisitor {
1301 public:
1302 bool visitStatement(const Statement& stmt) override {
Ethan Nicholase6592142020-09-08 10:22:09 -04001303 switch (stmt.kind()) {
1304 case Statement::Kind::kBlock:
John Stilesb92641c2020-08-31 18:09:01 -04001305 return this->INHERITED::visitStatement(stmt);
1306
Ethan Nicholase6592142020-09-08 10:22:09 -04001307 case Statement::Kind::kBreak:
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001308 return true;
John Stilesb92641c2020-08-31 18:09:01 -04001309
1310 default:
1311 return false;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001312 }
John Stilesb92641c2020-08-31 18:09:01 -04001313 }
John Stiles92219b42020-06-15 12:32:24 -04001314
John Stilesb92641c2020-08-31 18:09:01 -04001315 using INHERITED = ProgramVisitor;
1316 };
John Stiles92219b42020-06-15 12:32:24 -04001317
John Stilesb92641c2020-08-31 18:09:01 -04001318 return ContainsUnconditionalBreak{}.visitStatement(stmt);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001319}
1320
John Stiles8f2a0cf2020-10-13 12:48:21 -04001321static void move_all_but_break(std::unique_ptr<Statement>& stmt, StatementArray* target) {
Ethan Nicholase6592142020-09-08 10:22:09 -04001322 switch (stmt->kind()) {
1323 case Statement::Kind::kBlock: {
John Stiles92219b42020-06-15 12:32:24 -04001324 // Recurse into the block.
1325 Block& block = static_cast<Block&>(*stmt);
1326
John Stiles8f2a0cf2020-10-13 12:48:21 -04001327 StatementArray blockStmts;
John Stilesf4bda742020-10-14 16:57:41 -04001328 blockStmts.reserve_back(block.children().size());
Ethan Nicholas7bd60432020-09-25 14:31:59 -04001329 for (std::unique_ptr<Statement>& stmt : block.children()) {
1330 move_all_but_break(stmt, &blockStmts);
Ethan Nicholas739e1ca2020-06-11 12:16:14 -04001331 }
John Stiles92219b42020-06-15 12:32:24 -04001332
1333 target->push_back(std::make_unique<Block>(block.fOffset, std::move(blockStmts),
Ethan Nicholas7bd60432020-09-25 14:31:59 -04001334 block.symbolTable(), block.isScope()));
Ethan Nicholas739e1ca2020-06-11 12:16:14 -04001335 break;
John Stiles92219b42020-06-15 12:32:24 -04001336 }
1337
Ethan Nicholase6592142020-09-08 10:22:09 -04001338 case Statement::Kind::kBreak:
John Stiles92219b42020-06-15 12:32:24 -04001339 // Do not append a break to the target.
1340 break;
1341
Ethan Nicholas739e1ca2020-06-11 12:16:14 -04001342 default:
John Stiles92219b42020-06-15 12:32:24 -04001343 // Append normal statements to the target.
1344 target->push_back(std::move(stmt));
1345 break;
Ethan Nicholas739e1ca2020-06-11 12:16:14 -04001346 }
1347}
1348
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001349// Returns a block containing all of the statements that will be run if the given case matches
1350// (which, owing to the statements being owned by unique_ptrs, means the switch itself will be
1351// broken by this call and must then be discarded).
1352// Returns null (and leaves the switch unmodified) if no such simple reduction is possible, such as
1353// when break statements appear inside conditionals.
John Stiles92219b42020-06-15 12:32:24 -04001354static std::unique_ptr<Statement> block_for_case(SwitchStatement* switchStatement,
1355 SwitchCase* caseToCapture) {
1356 // We have to be careful to not move any of the pointers until after we're sure we're going to
1357 // succeed, so before we make any changes at all, we check the switch-cases to decide on a plan
1358 // of action. First, find the switch-case we are interested in.
Ethan Nicholas01b05e52020-10-22 15:53:41 -04001359 auto iter = switchStatement->cases().begin();
1360 for (; iter != switchStatement->cases().end(); ++iter) {
John Stiles2d4f9592020-10-30 10:29:12 -04001361 if (iter->get() == caseToCapture) {
John Stiles92219b42020-06-15 12:32:24 -04001362 break;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001363 }
John Stiles92219b42020-06-15 12:32:24 -04001364 }
1365
1366 // Next, walk forward through the rest of the switch. If we find a conditional break, we're
1367 // stuck and can't simplify at all. If we find an unconditional break, we have a range of
1368 // statements that we can use for simplification.
1369 auto startIter = iter;
1370 Statement* unconditionalBreakStmt = nullptr;
Ethan Nicholas01b05e52020-10-22 15:53:41 -04001371 for (; iter != switchStatement->cases().end(); ++iter) {
John Stiles2d4f9592020-10-30 10:29:12 -04001372 for (std::unique_ptr<Statement>& stmt : (*iter)->statements()) {
John Stiles92219b42020-06-15 12:32:24 -04001373 if (contains_conditional_break(*stmt)) {
1374 // We can't reduce switch-cases to a block when they have conditional breaks.
1375 return nullptr;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001376 }
John Stiles92219b42020-06-15 12:32:24 -04001377
1378 if (contains_unconditional_break(*stmt)) {
1379 // We found an unconditional break. We can use this block, but we need to strip
1380 // out the break statement.
1381 unconditionalBreakStmt = stmt.get();
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001382 break;
1383 }
1384 }
John Stiles92219b42020-06-15 12:32:24 -04001385
1386 if (unconditionalBreakStmt != nullptr) {
1387 break;
1388 }
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001389 }
John Stiles92219b42020-06-15 12:32:24 -04001390
1391 // We fell off the bottom of the switch or encountered a break. We know the range of statements
1392 // that we need to move over, and we know it's safe to do so.
John Stiles8f2a0cf2020-10-13 12:48:21 -04001393 StatementArray caseStmts;
John Stiles92219b42020-06-15 12:32:24 -04001394
1395 // We can move over most of the statements as-is.
1396 while (startIter != iter) {
John Stiles2d4f9592020-10-30 10:29:12 -04001397 for (std::unique_ptr<Statement>& stmt : (*startIter)->statements()) {
John Stiles92219b42020-06-15 12:32:24 -04001398 caseStmts.push_back(std::move(stmt));
1399 }
1400 ++startIter;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001401 }
John Stiles92219b42020-06-15 12:32:24 -04001402
1403 // If we found an unconditional break at the end, we need to move what we can while avoiding
1404 // that break.
1405 if (unconditionalBreakStmt != nullptr) {
John Stiles2d4f9592020-10-30 10:29:12 -04001406 for (std::unique_ptr<Statement>& stmt : (*startIter)->statements()) {
John Stiles92219b42020-06-15 12:32:24 -04001407 if (stmt.get() == unconditionalBreakStmt) {
1408 move_all_but_break(stmt, &caseStmts);
1409 unconditionalBreakStmt = nullptr;
1410 break;
1411 }
1412
1413 caseStmts.push_back(std::move(stmt));
1414 }
1415 }
1416
1417 SkASSERT(unconditionalBreakStmt == nullptr); // Verify that we fixed the unconditional break.
1418
1419 // Return our newly-synthesized block.
Ethan Nicholas01b05e52020-10-22 15:53:41 -04001420 return std::make_unique<Block>(/*offset=*/-1, std::move(caseStmts), switchStatement->symbols());
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001421}
1422
Ethan Nicholascb670962017-04-20 19:31:52 -04001423void Compiler::simplifyStatement(DefinitionMap& definitions,
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001424 BasicBlock& b,
1425 std::vector<BasicBlock::Node>::iterator* iter,
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001426 OptimizationContext* optimizationContext) {
Brian Osman010ce6a2020-10-19 16:34:10 -04001427 ProgramUsage* usage = optimizationContext->fUsage;
Ethan Nicholascb670962017-04-20 19:31:52 -04001428 Statement* stmt = (*iter)->statement()->get();
Ethan Nicholase6592142020-09-08 10:22:09 -04001429 switch (stmt->kind()) {
1430 case Statement::Kind::kVarDeclaration: {
John Stilesa5a97b42020-08-18 11:19:07 -04001431 const auto& varDecl = stmt->as<VarDeclaration>();
Brian Osman010ce6a2020-10-19 16:34:10 -04001432 if (usage->isDead(varDecl.var()) &&
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04001433 (!varDecl.value() ||
1434 !varDecl.value()->hasSideEffects())) {
1435 if (varDecl.value()) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001436 SkASSERT((*iter)->statement()->get() == stmt);
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04001437 if (!b.tryRemoveExpressionBefore(iter, varDecl.value().get())) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001438 optimizationContext->fNeedsRescan = true;
Ethan Nicholascb670962017-04-20 19:31:52 -04001439 }
Ethan Nicholascb670962017-04-20 19:31:52 -04001440 }
Brian Osman010ce6a2020-10-19 16:34:10 -04001441 (*iter)->setStatement(std::make_unique<Nop>(), usage);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001442 optimizationContext->fUpdated = true;
Ethan Nicholascb670962017-04-20 19:31:52 -04001443 }
1444 break;
1445 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001446 case Statement::Kind::kIf: {
John Stilesa5a97b42020-08-18 11:19:07 -04001447 IfStatement& i = stmt->as<IfStatement>();
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001448 if (i.test()->kind() == Expression::Kind::kBoolLiteral) {
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001449 // constant if, collapse down to a single branch
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001450 if (i.test()->as<BoolLiteral>().value()) {
1451 SkASSERT(i.ifTrue());
Brian Osman010ce6a2020-10-19 16:34:10 -04001452 (*iter)->setStatement(std::move(i.ifTrue()), usage);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001453 } else {
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001454 if (i.ifFalse()) {
Brian Osman010ce6a2020-10-19 16:34:10 -04001455 (*iter)->setStatement(std::move(i.ifFalse()), usage);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001456 } else {
Brian Osman010ce6a2020-10-19 16:34:10 -04001457 (*iter)->setStatement(std::make_unique<Nop>(), usage);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001458 }
1459 }
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001460 optimizationContext->fUpdated = true;
1461 optimizationContext->fNeedsRescan = true;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001462 break;
1463 }
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001464 if (i.ifFalse() && i.ifFalse()->isEmpty()) {
Ethan Nicholascb670962017-04-20 19:31:52 -04001465 // else block doesn't do anything, remove it
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001466 i.ifFalse().reset();
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001467 optimizationContext->fUpdated = true;
1468 optimizationContext->fNeedsRescan = true;
Ethan Nicholascb670962017-04-20 19:31:52 -04001469 }
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001470 if (!i.ifFalse() && i.ifTrue()->isEmpty()) {
Ethan Nicholascb670962017-04-20 19:31:52 -04001471 // if block doesn't do anything, no else block
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001472 if (i.test()->hasSideEffects()) {
Ethan Nicholascb670962017-04-20 19:31:52 -04001473 // test has side effects, keep it
Brian Osman010ce6a2020-10-19 16:34:10 -04001474 (*iter)->setStatement(
1475 std::make_unique<ExpressionStatement>(std::move(i.test())), usage);
Ethan Nicholascb670962017-04-20 19:31:52 -04001476 } else {
1477 // no if, no else, no test side effects, kill the whole if
1478 // statement
Brian Osman010ce6a2020-10-19 16:34:10 -04001479 (*iter)->setStatement(std::make_unique<Nop>(), usage);
Ethan Nicholascb670962017-04-20 19:31:52 -04001480 }
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001481 optimizationContext->fUpdated = true;
1482 optimizationContext->fNeedsRescan = true;
Ethan Nicholascb670962017-04-20 19:31:52 -04001483 }
1484 break;
1485 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001486 case Statement::Kind::kSwitch: {
John Stilesa5a97b42020-08-18 11:19:07 -04001487 SwitchStatement& s = stmt->as<SwitchStatement>();
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001488 int64_t switchValue;
Ethan Nicholas01b05e52020-10-22 15:53:41 -04001489 if (fIRGenerator->getConstantInt(*s.value(), &switchValue)) {
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001490 // switch is constant, replace it with the case that matches
1491 bool found = false;
1492 SwitchCase* defaultCase = nullptr;
John Stiles2d4f9592020-10-30 10:29:12 -04001493 for (const std::unique_ptr<SwitchCase>& c : s.cases()) {
1494 if (!c->value()) {
1495 defaultCase = c.get();
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001496 continue;
1497 }
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001498 int64_t caseValue;
John Stiles2d4f9592020-10-30 10:29:12 -04001499 SkAssertResult(fIRGenerator->getConstantInt(*c->value(), &caseValue));
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001500 if (caseValue == switchValue) {
John Stiles2d4f9592020-10-30 10:29:12 -04001501 std::unique_ptr<Statement> newBlock = block_for_case(&s, c.get());
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001502 if (newBlock) {
Brian Osman010ce6a2020-10-19 16:34:10 -04001503 (*iter)->setStatement(std::move(newBlock), usage);
John Stiles9d944232020-08-19 09:56:49 -04001504 found = true;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001505 break;
1506 } else {
Ethan Nicholas01b05e52020-10-22 15:53:41 -04001507 if (s.isStatic() && !(fFlags & kPermitInvalidStaticTests_Flag) &&
1508 optimizationContext->fSilences.find(&s) ==
1509 optimizationContext->fSilences.end()) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001510 this->error(s.fOffset,
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001511 "static switch contains non-static conditional break");
Ethan Nicholas01b05e52020-10-22 15:53:41 -04001512 optimizationContext->fSilences.insert(&s);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001513 }
1514 return; // can't simplify
1515 }
1516 }
1517 }
1518 if (!found) {
1519 // no matching case. use default if it exists, or kill the whole thing
1520 if (defaultCase) {
1521 std::unique_ptr<Statement> newBlock = block_for_case(&s, defaultCase);
1522 if (newBlock) {
Brian Osman010ce6a2020-10-19 16:34:10 -04001523 (*iter)->setStatement(std::move(newBlock), usage);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001524 } else {
Ethan Nicholas01b05e52020-10-22 15:53:41 -04001525 if (s.isStatic() && !(fFlags & kPermitInvalidStaticTests_Flag) &&
1526 optimizationContext->fSilences.find(&s) ==
1527 optimizationContext->fSilences.end()) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001528 this->error(s.fOffset,
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001529 "static switch contains non-static conditional break");
Ethan Nicholas01b05e52020-10-22 15:53:41 -04001530 optimizationContext->fSilences.insert(&s);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001531 }
1532 return; // can't simplify
1533 }
1534 } else {
Brian Osman010ce6a2020-10-19 16:34:10 -04001535 (*iter)->setStatement(std::make_unique<Nop>(), usage);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001536 }
1537 }
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001538 optimizationContext->fUpdated = true;
1539 optimizationContext->fNeedsRescan = true;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001540 }
1541 break;
1542 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001543 case Statement::Kind::kExpression: {
John Stilesa5a97b42020-08-18 11:19:07 -04001544 ExpressionStatement& e = stmt->as<ExpressionStatement>();
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001545 SkASSERT((*iter)->statement()->get() == &e);
Ethan Nicholasd503a5a2020-09-30 09:29:55 -04001546 if (!e.expression()->hasSideEffects()) {
Ethan Nicholascb670962017-04-20 19:31:52 -04001547 // Expression statement with no side effects, kill it
Ethan Nicholasd503a5a2020-09-30 09:29:55 -04001548 if (!b.tryRemoveExpressionBefore(iter, e.expression().get())) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001549 optimizationContext->fNeedsRescan = true;
Ethan Nicholascb670962017-04-20 19:31:52 -04001550 }
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001551 SkASSERT((*iter)->statement()->get() == stmt);
Brian Osman010ce6a2020-10-19 16:34:10 -04001552 (*iter)->setStatement(std::make_unique<Nop>(), usage);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001553 optimizationContext->fUpdated = true;
Ethan Nicholascb670962017-04-20 19:31:52 -04001554 }
1555 break;
1556 }
1557 default:
1558 break;
1559 }
1560}
1561
Brian Osman010ce6a2020-10-19 16:34:10 -04001562bool Compiler::scanCFG(FunctionDefinition& f, ProgramUsage* usage) {
John Stiles0cc193a2020-09-09 09:39:34 -04001563 bool madeChanges = false;
1564
Ethan Nicholascb670962017-04-20 19:31:52 -04001565 CFG cfg = CFGGenerator().getCFG(f);
1566 this->computeDataFlow(&cfg);
ethannicholas22f939e2016-10-13 13:25:34 -07001567
1568 // check for unreachable code
1569 for (size_t i = 0; i < cfg.fBlocks.size(); i++) {
John Stiles0cc193a2020-09-09 09:39:34 -04001570 const BasicBlock& block = cfg.fBlocks[i];
John Stiles61e75e32020-10-01 15:42:37 -04001571 if (i != cfg.fStart && !block.fIsReachable && block.fNodes.size()) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001572 int offset;
John Stiles0cc193a2020-09-09 09:39:34 -04001573 const BasicBlock::Node& node = block.fNodes[0];
John Stiles70025e52020-09-28 16:08:58 -04001574 if (node.isStatement()) {
1575 offset = (*node.statement())->fOffset;
1576 } else {
1577 offset = (*node.expression())->fOffset;
1578 if ((*node.expression())->is<BoolLiteral>()) {
1579 // Function inlining can generate do { ... } while(false) loops which always
1580 // break, so the boolean condition is considered unreachable. Since not being
1581 // able to reach a literal is a non-issue in the first place, we don't report an
1582 // error in this case.
1583 continue;
1584 }
Ethan Nicholas86a43402017-01-19 13:32:00 -05001585 }
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001586 this->error(offset, String("unreachable"));
ethannicholas22f939e2016-10-13 13:25:34 -07001587 }
1588 }
1589 if (fErrorCount) {
John Stiles0cc193a2020-09-09 09:39:34 -04001590 return madeChanges;
ethannicholas22f939e2016-10-13 13:25:34 -07001591 }
1592
Ethan Nicholascb670962017-04-20 19:31:52 -04001593 // check for dead code & undefined variables, perform constant propagation
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001594 OptimizationContext optimizationContext;
Brian Osman010ce6a2020-10-19 16:34:10 -04001595 optimizationContext.fUsage = usage;
John Stiles7d3f0892020-11-03 11:35:01 -05001596 SkBitSet eliminatedBlockIds(cfg.fBlocks.size());
Ethan Nicholascb670962017-04-20 19:31:52 -04001597 do {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001598 if (optimizationContext.fNeedsRescan) {
Ethan Nicholascb670962017-04-20 19:31:52 -04001599 cfg = CFGGenerator().getCFG(f);
1600 this->computeDataFlow(&cfg);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001601 optimizationContext.fNeedsRescan = false;
Ethan Nicholas113628d2017-02-02 16:11:39 -05001602 }
Ethan Nicholascb670962017-04-20 19:31:52 -04001603
John Stiles7d3f0892020-11-03 11:35:01 -05001604 eliminatedBlockIds.reset();
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001605 optimizationContext.fUpdated = false;
John Stiles7d3f0892020-11-03 11:35:01 -05001606
1607 for (BlockId blockId = 0; blockId < cfg.fBlocks.size(); ++blockId) {
1608 if (eliminatedBlockIds.test(blockId)) {
1609 // We reached a block ID that might have been eliminated. Be cautious and rescan.
1610 optimizationContext.fUpdated = true;
1611 optimizationContext.fNeedsRescan = true;
1612 break;
1613 }
1614
1615 BasicBlock& b = cfg.fBlocks[blockId];
1616 if (blockId > 0 && !b.fIsReachable) {
Ethan Nicholas1de14812020-06-19 15:32:49 -04001617 // Block was reachable before optimization, but has since become unreachable. In
1618 // addition to being dead code, it's broken - since control flow can't reach it, no
1619 // prior variable definitions can reach it, and therefore variables might look to
Brian Osmanc0213602020-10-06 14:43:32 -04001620 // have not been properly assigned. Kill it by replacing all statements with Nops.
Ethan Nicholas1de14812020-06-19 15:32:49 -04001621 for (BasicBlock::Node& node : b.fNodes) {
John Stiles70025e52020-09-28 16:08:58 -04001622 if (node.isStatement() && !(*node.statement())->is<Nop>()) {
John Stiles7d3f0892020-11-03 11:35:01 -05001623 // Eliminating a node runs the risk of eliminating that node's exits as
1624 // well. Keep track of this and do a rescan if we are about to access one
1625 // of these.
1626 for (BlockId id : b.fExits) {
1627 eliminatedBlockIds.set(id);
1628 }
Brian Osman010ce6a2020-10-19 16:34:10 -04001629 node.setStatement(std::make_unique<Nop>(), usage);
John Stiles0cc193a2020-09-09 09:39:34 -04001630 madeChanges = true;
Ethan Nicholas1de14812020-06-19 15:32:49 -04001631 }
1632 }
1633 continue;
1634 }
Ethan Nicholascb670962017-04-20 19:31:52 -04001635 DefinitionMap definitions = b.fBefore;
1636
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001637 for (auto iter = b.fNodes.begin(); iter != b.fNodes.end() &&
1638 !optimizationContext.fNeedsRescan; ++iter) {
John Stiles70025e52020-09-28 16:08:58 -04001639 if (iter->isExpression()) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001640 this->simplifyExpression(definitions, b, &iter, &optimizationContext);
Ethan Nicholascb670962017-04-20 19:31:52 -04001641 } else {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001642 this->simplifyStatement(definitions, b, &iter, &optimizationContext);
Ethan Nicholascb670962017-04-20 19:31:52 -04001643 }
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001644 if (optimizationContext.fNeedsRescan) {
Ethan Nicholas4b330df2017-05-17 10:52:55 -04001645 break;
1646 }
Ethan Nicholascb670962017-04-20 19:31:52 -04001647 this->addDefinitions(*iter, &definitions);
1648 }
Brian Osman01a3eb42020-09-14 11:32:49 -04001649
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001650 if (optimizationContext.fNeedsRescan) {
Brian Osman01a3eb42020-09-14 11:32:49 -04001651 break;
1652 }
Ethan Nicholascb670962017-04-20 19:31:52 -04001653 }
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001654 madeChanges |= optimizationContext.fUpdated;
1655 } while (optimizationContext.fUpdated);
1656 SkASSERT(!optimizationContext.fNeedsRescan);
ethannicholas22f939e2016-10-13 13:25:34 -07001657
Ethan Nicholas91a10532017-06-22 11:24:38 -04001658 // verify static ifs & switches, clean up dead variable decls
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001659 for (BasicBlock& b : cfg.fBlocks) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001660 for (auto iter = b.fNodes.begin(); iter != b.fNodes.end() &&
1661 !optimizationContext.fNeedsRescan;) {
John Stiles70025e52020-09-28 16:08:58 -04001662 if (iter->isStatement()) {
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001663 const Statement& s = **iter->statement();
Ethan Nicholase6592142020-09-08 10:22:09 -04001664 switch (s.kind()) {
1665 case Statement::Kind::kIf:
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001666 if (s.as<IfStatement>().isStatic() &&
Ethan Nicholas6e1cbc02017-07-14 10:12:15 -04001667 !(fFlags & kPermitInvalidStaticTests_Flag)) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001668 this->error(s.fOffset, "static if has non-static test");
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001669 }
Ethan Nicholas91a10532017-06-22 11:24:38 -04001670 ++iter;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001671 break;
Ethan Nicholase6592142020-09-08 10:22:09 -04001672 case Statement::Kind::kSwitch:
Ethan Nicholas01b05e52020-10-22 15:53:41 -04001673 if (s.as<SwitchStatement>().isStatic() &&
1674 !(fFlags & kPermitInvalidStaticTests_Flag) &&
1675 optimizationContext.fSilences.find(&s) ==
1676 optimizationContext.fSilences.end()) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001677 this->error(s.fOffset, "static switch has non-static test");
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001678 }
Ethan Nicholas91a10532017-06-22 11:24:38 -04001679 ++iter;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001680 break;
1681 default:
Ethan Nicholas91a10532017-06-22 11:24:38 -04001682 ++iter;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001683 break;
1684 }
Ethan Nicholas91a10532017-06-22 11:24:38 -04001685 } else {
1686 ++iter;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001687 }
1688 }
1689 }
1690
ethannicholas22f939e2016-10-13 13:25:34 -07001691 // check for missing return
Ethan Nicholas0a5d0962020-10-14 13:33:18 -04001692 if (f.declaration().returnType() != *fContext->fVoid_Type) {
John Stiles61e75e32020-10-01 15:42:37 -04001693 if (cfg.fBlocks[cfg.fExit].fIsReachable) {
Ethan Nicholas0a5d0962020-10-14 13:33:18 -04001694 this->error(f.fOffset, String("function '" + String(f.declaration().name()) +
Ethan Nicholasdb80f692019-11-22 14:06:12 -05001695 "' can exit without returning a value"));
ethannicholas22f939e2016-10-13 13:25:34 -07001696 }
1697 }
John Stiles0cc193a2020-09-09 09:39:34 -04001698
1699 return madeChanges;
ethannicholas22f939e2016-10-13 13:25:34 -07001700}
1701
Brian Osman32d53552020-09-23 13:55:20 -04001702std::unique_ptr<Program> Compiler::convertProgram(
1703 Program::Kind kind,
1704 String text,
1705 const Program::Settings& settings,
1706 const std::vector<std::unique_ptr<ExternalValue>>* externalValues) {
1707 SkASSERT(!externalValues || (kind == Program::kGeneric_Kind));
Ethan Nicholas91164d12019-05-15 15:29:54 -04001708
Brian Osman0006ad02020-11-18 15:38:39 -05001709 // Loading and optimizing our base module might reset the inliner, so do that first,
1710 // *then* configure the inliner with the settings for this program.
1711 const ParsedModule& baseModule = this->moduleForProgramKind(kind);
1712
ethannicholasb3058bd2016-07-01 08:22:01 -07001713 fErrorText = "";
1714 fErrorCount = 0;
Brian Osman0006ad02020-11-18 15:38:39 -05001715 fInliner.reset(fIRGenerator->fModifiers.get(), &settings);
Brian Osman88cda172020-10-09 12:05:16 -04001716
1717 // Not using AutoSource, because caller is likely to call errorText() if we fail to compile
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001718 std::unique_ptr<String> textPtr(new String(std::move(text)));
1719 fSource = textPtr.get();
Brian Osman88cda172020-10-09 12:05:16 -04001720
John Stiles5c7bb322020-10-22 11:09:15 -04001721 // Enable node pooling while converting and optimizing the program for a performance boost.
1722 // The Program will take ownership of the pool.
John Stiles2d68ea32020-10-22 15:42:27 -04001723 std::unique_ptr<Pool> pool = Pool::Create();
1724 pool->attachToThread();
Brian Osman0006ad02020-11-18 15:38:39 -05001725 IRGenerator::IRBundle ir =
1726 fIRGenerator->convertProgram(kind, &settings, baseModule, /*isBuiltinCode=*/false,
1727 textPtr->c_str(), textPtr->size(), externalValues);
John Stiles5c7bb322020-10-22 11:09:15 -04001728 auto program = std::make_unique<Program>(kind,
1729 std::move(textPtr),
1730 settings,
Brian Osmand7e76592020-11-02 12:26:22 -05001731 fCaps,
John Stiles5c7bb322020-10-22 11:09:15 -04001732 fContext,
1733 std::move(ir.fElements),
Brian Osman133724c2020-10-28 14:14:39 -04001734 std::move(ir.fSharedElements),
John Stiles5c7bb322020-10-22 11:09:15 -04001735 std::move(ir.fModifiers),
1736 std::move(ir.fSymbolTable),
1737 std::move(pool),
1738 ir.fInputs);
1739 bool success = false;
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001740 if (fErrorCount) {
John Stiles5c7bb322020-10-22 11:09:15 -04001741 // Do not return programs that failed to compile.
1742 } else if (settings.fOptimize && !this->optimize(*program)) {
1743 // Do not return programs that failed to optimize.
1744 } else {
1745 // We have a successful program!
1746 success = true;
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001747 }
John Stiles5c7bb322020-10-22 11:09:15 -04001748
1749 program->fPool->detachFromThread();
1750 return success ? std::move(program) : nullptr;
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001751}
1752
Brian Osman0006ad02020-11-18 15:38:39 -05001753bool Compiler::optimize(LoadedModule& module) {
1754 SkASSERT(!fErrorCount);
1755 Program::Settings settings;
1756 fIRGenerator->fKind = module.fKind;
1757 fIRGenerator->fSettings = &settings;
1758 std::unique_ptr<ProgramUsage> usage = Analysis::GetUsage(module);
1759
1760 fInliner.reset(fModifiers.back().get(), &settings);
1761
1762 while (fErrorCount == 0) {
1763 bool madeChanges = false;
1764
1765 // Scan and optimize based on the control-flow graph for each function.
1766 for (const auto& element : module.fElements) {
1767 if (element->is<FunctionDefinition>()) {
1768 madeChanges |= this->scanCFG(element->as<FunctionDefinition>(), usage.get());
1769 }
1770 }
1771
1772 // Perform inline-candidate analysis and inline any functions deemed suitable.
1773 madeChanges |= fInliner.analyze(module.fElements, module.fSymbols.get(), usage.get());
1774
1775 if (!madeChanges) {
1776 break;
1777 }
1778 }
1779 return fErrorCount == 0;
1780}
1781
Ethan Nicholas00543112018-07-31 09:44:36 -04001782bool Compiler::optimize(Program& program) {
1783 SkASSERT(!fErrorCount);
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001784 fIRGenerator->fKind = program.fKind;
1785 fIRGenerator->fSettings = &program.fSettings;
Brian Osman010ce6a2020-10-19 16:34:10 -04001786 ProgramUsage* usage = program.fUsage.get();
John Stiles7954d6c2020-09-01 10:53:02 -04001787
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001788 while (fErrorCount == 0) {
1789 bool madeChanges = false;
John Stiles7954d6c2020-09-01 10:53:02 -04001790
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001791 // Scan and optimize based on the control-flow graph for each function.
Brian Osman133724c2020-10-28 14:14:39 -04001792 for (const auto& element : program.ownedElements()) {
Brian Osman1179fcf2020-10-08 16:04:40 -04001793 if (element->is<FunctionDefinition>()) {
Brian Osman010ce6a2020-10-19 16:34:10 -04001794 madeChanges |= this->scanCFG(element->as<FunctionDefinition>(), usage);
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001795 }
1796 }
1797
1798 // Perform inline-candidate analysis and inline any functions deemed suitable.
Brian Osman0006ad02020-11-18 15:38:39 -05001799 madeChanges |= fInliner.analyze(program.ownedElements(), program.fSymbols.get(), usage);
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001800
1801 // Remove dead functions. We wait until after analysis so that we still report errors,
1802 // even in unused code.
1803 if (program.fSettings.fRemoveDeadFunctions) {
Brian Osman133724c2020-10-28 14:14:39 -04001804 auto isDeadFunction = [&](const ProgramElement* element) {
1805 if (!element->is<FunctionDefinition>()) {
1806 return false;
1807 }
1808 const FunctionDefinition& fn = element->as<FunctionDefinition>();
1809 if (fn.declaration().name() != "main" && usage->get(fn.declaration()) == 0) {
1810 usage->remove(*element);
1811 madeChanges = true;
1812 return true;
1813 }
1814 return false;
1815 };
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001816 program.fElements.erase(
Brian Osman133724c2020-10-28 14:14:39 -04001817 std::remove_if(program.fElements.begin(), program.fElements.end(),
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001818 [&](const std::unique_ptr<ProgramElement>& element) {
Brian Osman133724c2020-10-28 14:14:39 -04001819 return isDeadFunction(element.get());
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001820 }),
1821 program.fElements.end());
Brian Osman133724c2020-10-28 14:14:39 -04001822 program.fSharedElements.erase(
1823 std::remove_if(program.fSharedElements.begin(), program.fSharedElements.end(),
1824 isDeadFunction),
1825 program.fSharedElements.end());
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001826 }
1827
1828 if (program.fKind != Program::kFragmentProcessor_Kind) {
Brian Osmanc0213602020-10-06 14:43:32 -04001829 // Remove declarations of dead global variables
Brian Osman133724c2020-10-28 14:14:39 -04001830 auto isDeadVariable = [&](const ProgramElement* element) {
1831 if (!element->is<GlobalVarDeclaration>()) {
1832 return false;
1833 }
1834 const GlobalVarDeclaration& global = element->as<GlobalVarDeclaration>();
1835 const VarDeclaration& varDecl = global.declaration()->as<VarDeclaration>();
1836 if (usage->isDead(varDecl.var())) {
1837 madeChanges = true;
1838 return true;
1839 }
1840 return false;
1841 };
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001842 program.fElements.erase(
1843 std::remove_if(program.fElements.begin(), program.fElements.end(),
1844 [&](const std::unique_ptr<ProgramElement>& element) {
Brian Osman133724c2020-10-28 14:14:39 -04001845 return isDeadVariable(element.get());
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001846 }),
1847 program.fElements.end());
Brian Osman133724c2020-10-28 14:14:39 -04001848 program.fSharedElements.erase(
1849 std::remove_if(program.fSharedElements.begin(), program.fSharedElements.end(),
1850 isDeadVariable),
1851 program.fSharedElements.end());
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001852 }
John Stiles73a6bff2020-09-09 13:40:37 -04001853
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001854 if (!madeChanges) {
1855 break;
Ethan Nicholas0dc80872019-02-08 15:46:24 -05001856 }
Ethan Nicholas00543112018-07-31 09:44:36 -04001857 }
1858 return fErrorCount == 0;
1859}
1860
Brian Osmanfb32ddf2019-06-18 10:14:20 -04001861#if defined(SKSL_STANDALONE) || SK_SUPPORT_GPU
1862
Ethan Nicholas00543112018-07-31 09:44:36 -04001863bool Compiler::toSPIRV(Program& program, OutputStream& out) {
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001864#ifdef SK_ENABLE_SPIRV_VALIDATION
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001865 StringStream buffer;
Brian Osman88cda172020-10-09 12:05:16 -04001866 AutoSource as(this, program.fSource.get());
Brian Osman8b43dad2020-10-09 13:31:42 -04001867 SPIRVCodeGenerator cg(fContext.get(), &program, this, &buffer);
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001868 bool result = cg.generateCode();
Ethan Nicholasba9a04f2020-11-06 09:28:04 -05001869 if (result && program.fSettings.fValidateSPIRV) {
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001870 spvtools::SpirvTools tools(SPV_ENV_VULKAN_1_0);
Ethan Nicholas762466e2017-06-29 10:03:38 -04001871 const String& data = buffer.str();
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001872 SkASSERT(0 == data.size() % 4);
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001873 auto dumpmsg = [](spv_message_level_t, const char*, const spv_position_t&, const char* m) {
1874 SkDebugf("SPIR-V validation error: %s\n", m);
1875 };
1876 tools.SetMessageConsumer(dumpmsg);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001877 // Verify that the SPIR-V we produced is valid. If this SkASSERT fails, check the logs prior
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001878 // to the failure to see the validation errors.
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001879 SkAssertResult(tools.Validate((const uint32_t*) data.c_str(), data.size() / 4));
Ethan Nicholas762466e2017-06-29 10:03:38 -04001880 out.write(data.c_str(), data.size());
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001881 }
1882#else
Brian Osman88cda172020-10-09 12:05:16 -04001883 AutoSource as(this, program.fSource.get());
Brian Osman8b43dad2020-10-09 13:31:42 -04001884 SPIRVCodeGenerator cg(fContext.get(), &program, this, &out);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001885 bool result = cg.generateCode();
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001886#endif
Ethan Nicholasce33f102016-12-09 17:22:59 -05001887 return result;
1888}
1889
Ethan Nicholas00543112018-07-31 09:44:36 -04001890bool Compiler::toSPIRV(Program& program, String* out) {
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001891 StringStream buffer;
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001892 bool result = this->toSPIRV(program, buffer);
1893 if (result) {
Ethan Nicholas762466e2017-06-29 10:03:38 -04001894 *out = buffer.str();
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001895 }
1896 return result;
1897}
1898
Ethan Nicholas00543112018-07-31 09:44:36 -04001899bool Compiler::toGLSL(Program& program, OutputStream& out) {
Brian Osman88cda172020-10-09 12:05:16 -04001900 AutoSource as(this, program.fSource.get());
Ethan Nicholas26a9aad2018-03-27 14:10:52 -04001901 GLSLCodeGenerator cg(fContext.get(), &program, this, &out);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001902 bool result = cg.generateCode();
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001903 return result;
1904}
1905
Ethan Nicholas00543112018-07-31 09:44:36 -04001906bool Compiler::toGLSL(Program& program, String* out) {
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001907 StringStream buffer;
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001908 bool result = this->toGLSL(program, buffer);
1909 if (result) {
Ethan Nicholas762466e2017-06-29 10:03:38 -04001910 *out = buffer.str();
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001911 }
1912 return result;
1913}
1914
Brian Osmanc0243912020-02-19 15:35:26 -05001915bool Compiler::toHLSL(Program& program, String* out) {
1916 String spirv;
1917 if (!this->toSPIRV(program, &spirv)) {
1918 return false;
1919 }
1920
1921 return SPIRVtoHLSL(spirv, out);
1922}
1923
Ethan Nicholas00543112018-07-31 09:44:36 -04001924bool Compiler::toMetal(Program& program, OutputStream& out) {
Ethan Nicholas26a9aad2018-03-27 14:10:52 -04001925 MetalCodeGenerator cg(fContext.get(), &program, this, &out);
Ethan Nicholascc305772017-10-13 16:17:45 -04001926 bool result = cg.generateCode();
Ethan Nicholascc305772017-10-13 16:17:45 -04001927 return result;
1928}
1929
Ethan Nicholas00543112018-07-31 09:44:36 -04001930bool Compiler::toMetal(Program& program, String* out) {
Timothy Liangb8eeb802018-07-23 16:46:16 -04001931 StringStream buffer;
1932 bool result = this->toMetal(program, buffer);
1933 if (result) {
1934 *out = buffer.str();
1935 }
1936 return result;
1937}
1938
Greg Daniela28ea672020-09-25 11:12:56 -04001939#if defined(SKSL_STANDALONE) || GR_TEST_UTILS
Ethan Nicholas00543112018-07-31 09:44:36 -04001940bool Compiler::toCPP(Program& program, String name, OutputStream& out) {
Brian Osman88cda172020-10-09 12:05:16 -04001941 AutoSource as(this, program.fSource.get());
Ethan Nicholas26a9aad2018-03-27 14:10:52 -04001942 CPPCodeGenerator cg(fContext.get(), &program, this, name, &out);
Ethan Nicholas762466e2017-06-29 10:03:38 -04001943 bool result = cg.generateCode();
Ethan Nicholas762466e2017-06-29 10:03:38 -04001944 return result;
1945}
1946
Ethan Nicholas00543112018-07-31 09:44:36 -04001947bool Compiler::toH(Program& program, String name, OutputStream& out) {
Brian Osman88cda172020-10-09 12:05:16 -04001948 AutoSource as(this, program.fSource.get());
Ethan Nicholas26a9aad2018-03-27 14:10:52 -04001949 HCodeGenerator cg(fContext.get(), &program, this, name, &out);
Ethan Nicholas762466e2017-06-29 10:03:38 -04001950 bool result = cg.generateCode();
Ethan Nicholas00543112018-07-31 09:44:36 -04001951 return result;
1952}
Greg Daniela28ea672020-09-25 11:12:56 -04001953#endif // defined(SKSL_STANDALONE) || GR_TEST_UTILS
Ethan Nicholas00543112018-07-31 09:44:36 -04001954
Ethan Nicholas2a479a52020-08-18 16:29:45 -04001955#endif // defined(SKSL_STANDALONE) || SK_SUPPORT_GPU
Brian Osman2e29ab52019-09-20 12:19:11 -04001956
1957#if !defined(SKSL_STANDALONE) && SK_SUPPORT_GPU
Brian Osmana4b91692020-08-10 14:26:16 -04001958bool Compiler::toPipelineStage(Program& program, PipelineStageArgs* outArgs) {
Brian Osman88cda172020-10-09 12:05:16 -04001959 AutoSource as(this, program.fSource.get());
Ethan Nicholas00543112018-07-31 09:44:36 -04001960 StringStream buffer;
Brian Osman300fe1d2020-01-23 15:42:43 -05001961 PipelineStageCodeGenerator cg(fContext.get(), &program, this, &buffer, outArgs);
Ethan Nicholas00543112018-07-31 09:44:36 -04001962 bool result = cg.generateCode();
Ethan Nicholas00543112018-07-31 09:44:36 -04001963 if (result) {
Brian Osman107c6662019-12-30 15:02:30 -05001964 outArgs->fCode = buffer.str();
Ethan Nicholas00543112018-07-31 09:44:36 -04001965 }
Ethan Nicholas762466e2017-06-29 10:03:38 -04001966 return result;
1967}
Brian Osmanfb32ddf2019-06-18 10:14:20 -04001968#endif
1969
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001970std::unique_ptr<ByteCode> Compiler::toByteCode(Program& program) {
Brian Osman88cda172020-10-09 12:05:16 -04001971 AutoSource as(this, program.fSource.get());
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001972 std::unique_ptr<ByteCode> result(new ByteCode());
Brian Osmanb08cc022020-04-02 11:38:40 -04001973 ByteCodeGenerator cg(fContext.get(), &program, this, result.get());
1974 bool success = cg.generateCode();
Brian Osmanb08cc022020-04-02 11:38:40 -04001975 if (success) {
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001976 return result;
1977 }
1978 return nullptr;
1979}
1980
Brian Osman401a0092020-09-10 14:47:24 -04001981const char* Compiler::OperatorName(Token::Kind op) {
1982 switch (op) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001983 case Token::Kind::TK_PLUS: return "+";
1984 case Token::Kind::TK_MINUS: return "-";
1985 case Token::Kind::TK_STAR: return "*";
1986 case Token::Kind::TK_SLASH: return "/";
1987 case Token::Kind::TK_PERCENT: return "%";
1988 case Token::Kind::TK_SHL: return "<<";
1989 case Token::Kind::TK_SHR: return ">>";
1990 case Token::Kind::TK_LOGICALNOT: return "!";
1991 case Token::Kind::TK_LOGICALAND: return "&&";
1992 case Token::Kind::TK_LOGICALOR: return "||";
1993 case Token::Kind::TK_LOGICALXOR: return "^^";
1994 case Token::Kind::TK_BITWISENOT: return "~";
1995 case Token::Kind::TK_BITWISEAND: return "&";
1996 case Token::Kind::TK_BITWISEOR: return "|";
1997 case Token::Kind::TK_BITWISEXOR: return "^";
1998 case Token::Kind::TK_EQ: return "=";
1999 case Token::Kind::TK_EQEQ: return "==";
2000 case Token::Kind::TK_NEQ: return "!=";
2001 case Token::Kind::TK_LT: return "<";
2002 case Token::Kind::TK_GT: return ">";
2003 case Token::Kind::TK_LTEQ: return "<=";
2004 case Token::Kind::TK_GTEQ: return ">=";
2005 case Token::Kind::TK_PLUSEQ: return "+=";
2006 case Token::Kind::TK_MINUSEQ: return "-=";
2007 case Token::Kind::TK_STAREQ: return "*=";
2008 case Token::Kind::TK_SLASHEQ: return "/=";
2009 case Token::Kind::TK_PERCENTEQ: return "%=";
2010 case Token::Kind::TK_SHLEQ: return "<<=";
2011 case Token::Kind::TK_SHREQ: return ">>=";
2012 case Token::Kind::TK_LOGICALANDEQ: return "&&=";
2013 case Token::Kind::TK_LOGICALOREQ: return "||=";
2014 case Token::Kind::TK_LOGICALXOREQ: return "^^=";
2015 case Token::Kind::TK_BITWISEANDEQ: return "&=";
2016 case Token::Kind::TK_BITWISEOREQ: return "|=";
2017 case Token::Kind::TK_BITWISEXOREQ: return "^=";
2018 case Token::Kind::TK_PLUSPLUS: return "++";
2019 case Token::Kind::TK_MINUSMINUS: return "--";
2020 case Token::Kind::TK_COMMA: return ",";
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002021 default:
Brian Osman401a0092020-09-10 14:47:24 -04002022 ABORT("unsupported operator: %d\n", (int) op);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002023 }
2024}
2025
2026
2027bool Compiler::IsAssignment(Token::Kind op) {
2028 switch (op) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002029 case Token::Kind::TK_EQ: // fall through
2030 case Token::Kind::TK_PLUSEQ: // fall through
2031 case Token::Kind::TK_MINUSEQ: // fall through
2032 case Token::Kind::TK_STAREQ: // fall through
2033 case Token::Kind::TK_SLASHEQ: // fall through
2034 case Token::Kind::TK_PERCENTEQ: // fall through
2035 case Token::Kind::TK_SHLEQ: // fall through
2036 case Token::Kind::TK_SHREQ: // fall through
2037 case Token::Kind::TK_BITWISEOREQ: // fall through
2038 case Token::Kind::TK_BITWISEXOREQ: // fall through
2039 case Token::Kind::TK_BITWISEANDEQ: // fall through
2040 case Token::Kind::TK_LOGICALOREQ: // fall through
2041 case Token::Kind::TK_LOGICALXOREQ: // fall through
2042 case Token::Kind::TK_LOGICALANDEQ:
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002043 return true;
2044 default:
2045 return false;
2046 }
2047}
2048
Brian Osman401a0092020-09-10 14:47:24 -04002049Token::Kind Compiler::RemoveAssignment(Token::Kind op) {
2050 switch (op) {
2051 case Token::Kind::TK_PLUSEQ: return Token::Kind::TK_PLUS;
2052 case Token::Kind::TK_MINUSEQ: return Token::Kind::TK_MINUS;
2053 case Token::Kind::TK_STAREQ: return Token::Kind::TK_STAR;
2054 case Token::Kind::TK_SLASHEQ: return Token::Kind::TK_SLASH;
2055 case Token::Kind::TK_PERCENTEQ: return Token::Kind::TK_PERCENT;
2056 case Token::Kind::TK_SHLEQ: return Token::Kind::TK_SHL;
2057 case Token::Kind::TK_SHREQ: return Token::Kind::TK_SHR;
2058 case Token::Kind::TK_BITWISEOREQ: return Token::Kind::TK_BITWISEOR;
2059 case Token::Kind::TK_BITWISEXOREQ: return Token::Kind::TK_BITWISEXOR;
2060 case Token::Kind::TK_BITWISEANDEQ: return Token::Kind::TK_BITWISEAND;
2061 case Token::Kind::TK_LOGICALOREQ: return Token::Kind::TK_LOGICALOR;
2062 case Token::Kind::TK_LOGICALXOREQ: return Token::Kind::TK_LOGICALXOR;
2063 case Token::Kind::TK_LOGICALANDEQ: return Token::Kind::TK_LOGICALAND;
2064 default: return op;
2065 }
2066}
2067
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002068Position Compiler::position(int offset) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002069 SkASSERT(fSource);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002070 int line = 1;
2071 int column = 1;
2072 for (int i = 0; i < offset; i++) {
2073 if ((*fSource)[i] == '\n') {
2074 ++line;
2075 column = 1;
2076 }
2077 else {
2078 ++column;
2079 }
2080 }
2081 return Position(line, column);
2082}
2083
2084void Compiler::error(int offset, String msg) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002085 fErrorCount++;
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002086 Position pos = this->position(offset);
2087 fErrorText += "error: " + to_string(pos.fLine) + ": " + msg.c_str() + "\n";
ethannicholasb3058bd2016-07-01 08:22:01 -07002088}
2089
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002090String Compiler::errorText() {
Ethan Nicholas00543112018-07-31 09:44:36 -04002091 this->writeErrorCount();
2092 fErrorCount = 0;
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002093 String result = fErrorText;
ethannicholasb3058bd2016-07-01 08:22:01 -07002094 return result;
2095}
2096
2097void Compiler::writeErrorCount() {
2098 if (fErrorCount) {
2099 fErrorText += to_string(fErrorCount) + " error";
2100 if (fErrorCount > 1) {
2101 fErrorText += "s";
2102 }
2103 fErrorText += "\n";
2104 }
2105}
2106
John Stilesa6841be2020-08-06 14:11:56 -04002107} // namespace SkSL