blob: 539959efc2593a20f90ca6465e26b21cacaea161 [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"
64#include "src/sksl/generated/sksl_vert.dehydrated.sksl"
65
Brian Osman3d87e9f2020-10-08 11:50:22 -040066#define MODULE_DATA(name) MakeModuleData(SKSL_INCLUDE_sksl_##name,\
67 SKSL_INCLUDE_sksl_##name##_LENGTH)
Ethan Nicholasc18bb512020-07-28 14:46:53 -040068
69#endif
Ethan Nicholas0d997662019-04-08 09:46:01 -040070
ethannicholasb3058bd2016-07-01 08:22:01 -070071namespace SkSL {
72
Brian Osman88cda172020-10-09 12:05:16 -040073class AutoSource {
74public:
75 AutoSource(Compiler* compiler, const String* source)
76 : fCompiler(compiler), fOldSource(fCompiler->fSource) {
77 fCompiler->fSource = source;
78 }
79
80 ~AutoSource() { fCompiler->fSource = fOldSource; }
81
82 Compiler* fCompiler;
83 const String* fOldSource;
84};
85
Ethan Nicholas6e1cbc02017-07-14 10:12:15 -040086Compiler::Compiler(Flags flags)
Brian Osman00a8b5b2020-10-02 09:06:04 -040087: fFlags(flags)
John Stiles810c8cf2020-08-26 19:46:27 -040088, fContext(std::make_shared<Context>())
Ethan Nicholas6e1cbc02017-07-14 10:12:15 -040089, fErrorCount(0) {
Brian Osmaneac49832020-09-18 11:49:22 -040090 fRootSymbolTable = std::make_shared<SymbolTable>(this);
Brian Osman88cda172020-10-09 12:05:16 -040091 fIRGenerator = std::make_unique<IRGenerator>(fContext.get(), &fInliner, *this);
92#define ADD_TYPE(t) fRootSymbolTable->addWithoutOwnership(fContext->f##t##_Type.get())
ethannicholasb3058bd2016-07-01 08:22:01 -070093 ADD_TYPE(Void);
94 ADD_TYPE(Float);
Ethan Nicholas5af9ea32017-07-28 15:19:46 -040095 ADD_TYPE(Float2);
96 ADD_TYPE(Float3);
97 ADD_TYPE(Float4);
Ethan Nicholasdcba08e2017-08-02 10:52:54 -040098 ADD_TYPE(Half);
99 ADD_TYPE(Half2);
100 ADD_TYPE(Half3);
101 ADD_TYPE(Half4);
ethannicholasb3058bd2016-07-01 08:22:01 -0700102 ADD_TYPE(Int);
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400103 ADD_TYPE(Int2);
104 ADD_TYPE(Int3);
105 ADD_TYPE(Int4);
ethannicholasb3058bd2016-07-01 08:22:01 -0700106 ADD_TYPE(UInt);
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400107 ADD_TYPE(UInt2);
108 ADD_TYPE(UInt3);
109 ADD_TYPE(UInt4);
Ethan Nicholasdcba08e2017-08-02 10:52:54 -0400110 ADD_TYPE(Short);
111 ADD_TYPE(Short2);
112 ADD_TYPE(Short3);
113 ADD_TYPE(Short4);
114 ADD_TYPE(UShort);
115 ADD_TYPE(UShort2);
116 ADD_TYPE(UShort3);
117 ADD_TYPE(UShort4);
Ruiqi Maob609e6d2018-07-17 10:19:38 -0400118 ADD_TYPE(Byte);
119 ADD_TYPE(Byte2);
120 ADD_TYPE(Byte3);
121 ADD_TYPE(Byte4);
122 ADD_TYPE(UByte);
123 ADD_TYPE(UByte2);
124 ADD_TYPE(UByte3);
125 ADD_TYPE(UByte4);
ethannicholasb3058bd2016-07-01 08:22:01 -0700126 ADD_TYPE(Bool);
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400127 ADD_TYPE(Bool2);
128 ADD_TYPE(Bool3);
129 ADD_TYPE(Bool4);
130 ADD_TYPE(Float2x2);
131 ADD_TYPE(Float2x3);
132 ADD_TYPE(Float2x4);
133 ADD_TYPE(Float3x2);
134 ADD_TYPE(Float3x3);
135 ADD_TYPE(Float3x4);
136 ADD_TYPE(Float4x2);
137 ADD_TYPE(Float4x3);
138 ADD_TYPE(Float4x4);
Ethan Nicholasdcba08e2017-08-02 10:52:54 -0400139 ADD_TYPE(Half2x2);
140 ADD_TYPE(Half2x3);
141 ADD_TYPE(Half2x4);
142 ADD_TYPE(Half3x2);
143 ADD_TYPE(Half3x3);
144 ADD_TYPE(Half3x4);
145 ADD_TYPE(Half4x2);
146 ADD_TYPE(Half4x3);
147 ADD_TYPE(Half4x4);
ethannicholasb3058bd2016-07-01 08:22:01 -0700148 ADD_TYPE(GenType);
Ethan Nicholasdcba08e2017-08-02 10:52:54 -0400149 ADD_TYPE(GenHType);
ethannicholasb3058bd2016-07-01 08:22:01 -0700150 ADD_TYPE(GenIType);
151 ADD_TYPE(GenUType);
152 ADD_TYPE(GenBType);
153 ADD_TYPE(Mat);
154 ADD_TYPE(Vec);
155 ADD_TYPE(GVec);
156 ADD_TYPE(GVec2);
157 ADD_TYPE(GVec3);
158 ADD_TYPE(GVec4);
Ethan Nicholasdcba08e2017-08-02 10:52:54 -0400159 ADD_TYPE(HVec);
ethannicholasb3058bd2016-07-01 08:22:01 -0700160 ADD_TYPE(IVec);
161 ADD_TYPE(UVec);
Ethan Nicholasdcba08e2017-08-02 10:52:54 -0400162 ADD_TYPE(SVec);
163 ADD_TYPE(USVec);
Ruiqi Maob609e6d2018-07-17 10:19:38 -0400164 ADD_TYPE(ByteVec);
165 ADD_TYPE(UByteVec);
ethannicholasb3058bd2016-07-01 08:22:01 -0700166 ADD_TYPE(BVec);
167
168 ADD_TYPE(Sampler1D);
169 ADD_TYPE(Sampler2D);
170 ADD_TYPE(Sampler3D);
ethannicholas5961bc92016-10-12 06:39:56 -0700171 ADD_TYPE(SamplerExternalOES);
ethannicholasb3058bd2016-07-01 08:22:01 -0700172 ADD_TYPE(SamplerCube);
173 ADD_TYPE(Sampler2DRect);
174 ADD_TYPE(Sampler1DArray);
175 ADD_TYPE(Sampler2DArray);
176 ADD_TYPE(SamplerCubeArray);
177 ADD_TYPE(SamplerBuffer);
178 ADD_TYPE(Sampler2DMS);
179 ADD_TYPE(Sampler2DMSArray);
180
Brian Salomonbf7b6202016-11-11 16:08:03 -0500181 ADD_TYPE(ISampler2D);
182
Brian Salomon2a51de82016-11-16 12:06:01 -0500183 ADD_TYPE(Image2D);
184 ADD_TYPE(IImage2D);
185
Greg Daniel64773e62016-11-22 09:44:03 -0500186 ADD_TYPE(SubpassInput);
187 ADD_TYPE(SubpassInputMS);
188
ethannicholasb3058bd2016-07-01 08:22:01 -0700189 ADD_TYPE(GSampler1D);
190 ADD_TYPE(GSampler2D);
191 ADD_TYPE(GSampler3D);
192 ADD_TYPE(GSamplerCube);
193 ADD_TYPE(GSampler2DRect);
194 ADD_TYPE(GSampler1DArray);
195 ADD_TYPE(GSampler2DArray);
196 ADD_TYPE(GSamplerCubeArray);
197 ADD_TYPE(GSamplerBuffer);
198 ADD_TYPE(GSampler2DMS);
199 ADD_TYPE(GSampler2DMSArray);
200
201 ADD_TYPE(Sampler1DShadow);
202 ADD_TYPE(Sampler2DShadow);
203 ADD_TYPE(SamplerCubeShadow);
204 ADD_TYPE(Sampler2DRectShadow);
205 ADD_TYPE(Sampler1DArrayShadow);
206 ADD_TYPE(Sampler2DArrayShadow);
207 ADD_TYPE(SamplerCubeArrayShadow);
208 ADD_TYPE(GSampler2DArrayShadow);
209 ADD_TYPE(GSamplerCubeArrayShadow);
Ethan Nicholasc9472af2017-10-10 16:30:21 -0400210 ADD_TYPE(FragmentProcessor);
Stephen Whiteff5d7a22019-07-26 17:42:06 -0400211 ADD_TYPE(Sampler);
212 ADD_TYPE(Texture2D);
ethannicholasb3058bd2016-07-01 08:22:01 -0700213
Brian Osman28590d52020-03-23 16:59:08 -0400214 StringFragment fpAliasName("shader");
John Stiles49a547f2020-10-06 16:14:37 -0400215 fRootSymbolTable->addAlias(fpAliasName, fContext->fFragmentProcessor_Type.get());
Brian Osman28590d52020-03-23 16:59:08 -0400216
Brian Osman3887a012020-09-30 13:22:27 -0400217 // sk_Caps is "builtin", but all references to it are resolved to Settings, so we don't need to
218 // treat it as builtin (ie, no need to clone it into the Program).
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700219 StringFragment skCapsName("sk_Caps");
John Stilesb8cc6652020-10-08 09:12:07 -0400220 fRootSymbolTable->add(std::make_unique<Variable>(/*offset=*/-1,
Ethan Nicholas041fd0a2020-10-07 16:42:04 -0400221 fIRGenerator->fModifiers->handle(Modifiers()),
Ethan Nicholas453f67f2020-10-09 10:43:45 -0400222 skCapsName,
223 fContext->fSkCaps_Type.get(),
224 /*builtin=*/false,
225 Variable::Storage::kGlobal));
Ethan Nicholas3605ace2016-11-21 15:59:48 -0500226
Brian Osman3d87e9f2020-10-08 11:50:22 -0400227 fRootModule = {fRootSymbolTable, /*fIntrinsics=*/nullptr};
John Stilesbc0c29e2020-09-28 13:13:40 -0400228
Brian Osman3d87e9f2020-10-08 11:50:22 -0400229 fGPUModule = this->parseModule(Program::kFragment_Kind, MODULE_DATA(gpu), fRootModule);
230 fVertexModule = this->parseModule(Program::kVertex_Kind, MODULE_DATA(vert), fGPUModule);
231 fFragmentModule = this->parseModule(Program::kFragment_Kind, MODULE_DATA(frag), fGPUModule);
ethannicholasb3058bd2016-07-01 08:22:01 -0700232}
233
John Stiles656427a2020-08-27 15:26:26 -0400234Compiler::~Compiler() {}
ethannicholasb3058bd2016-07-01 08:22:01 -0700235
Brian Osman88cda172020-10-09 12:05:16 -0400236const ParsedModule& Compiler::loadGeometryModule() {
Brian Osman3d87e9f2020-10-08 11:50:22 -0400237 if (!fGeometryModule.fSymbols) {
238 fGeometryModule = this->parseModule(Program::kGeometry_Kind, MODULE_DATA(geom), fGPUModule);
Ethan Nicholasc18bb512020-07-28 14:46:53 -0400239 }
Brian Osman88cda172020-10-09 12:05:16 -0400240 return fGeometryModule;
Ethan Nicholasc18bb512020-07-28 14:46:53 -0400241}
242
Brian Osman88cda172020-10-09 12:05:16 -0400243const ParsedModule& Compiler::loadFPModule() {
Brian Osman3d87e9f2020-10-08 11:50:22 -0400244 if (!fFPModule.fSymbols) {
245 fFPModule =
246 this->parseModule(Program::kFragmentProcessor_Kind, MODULE_DATA(fp), fGPUModule);
Brian Osman8e2ef022020-09-30 13:26:43 -0400247 }
Brian Osman88cda172020-10-09 12:05:16 -0400248 return fFPModule;
Brian Osman8e2ef022020-09-30 13:26:43 -0400249}
250
Brian Osman88cda172020-10-09 12:05:16 -0400251const ParsedModule& Compiler::loadPipelineModule() {
Brian Osman3d87e9f2020-10-08 11:50:22 -0400252 if (!fPipelineModule.fSymbols) {
253 fPipelineModule =
254 this->parseModule(Program::kPipelineStage_Kind, MODULE_DATA(pipeline), fGPUModule);
Ethan Nicholasc18bb512020-07-28 14:46:53 -0400255 }
Brian Osman88cda172020-10-09 12:05:16 -0400256 return fPipelineModule;
Ethan Nicholasc18bb512020-07-28 14:46:53 -0400257}
258
Brian Osman88cda172020-10-09 12:05:16 -0400259const ParsedModule& Compiler::loadInterpreterModule() {
Brian Osman3d87e9f2020-10-08 11:50:22 -0400260 if (!fInterpreterModule.fSymbols) {
261 fInterpreterModule =
262 this->parseModule(Program::kGeneric_Kind, MODULE_DATA(interp), fRootModule);
Ethan Nicholasc18bb512020-07-28 14:46:53 -0400263 }
Brian Osman88cda172020-10-09 12:05:16 -0400264 return fInterpreterModule;
265}
266
267const ParsedModule& Compiler::moduleForProgramKind(Program::Kind kind) {
268 switch (kind) {
269 case Program::kVertex_Kind: return fVertexModule; break;
270 case Program::kFragment_Kind: return fFragmentModule; break;
271 case Program::kGeometry_Kind: return this->loadGeometryModule(); break;
272 case Program::kFragmentProcessor_Kind: return this->loadFPModule(); break;
273 case Program::kPipelineStage_Kind: return this->loadPipelineModule(); break;
274 case Program::kGeneric_Kind: return this->loadInterpreterModule(); break;
275 }
276 SkUNREACHABLE;
Ethan Nicholasc18bb512020-07-28 14:46:53 -0400277}
278
Brian Osman3d87e9f2020-10-08 11:50:22 -0400279LoadedModule Compiler::loadModule(Program::Kind kind,
280 ModuleData data,
281 std::shared_ptr<SymbolTable> base) {
Brian Osman3d87e9f2020-10-08 11:50:22 -0400282 if (!base) {
283 base = fRootSymbolTable;
284 }
285
286#if defined(SKSL_STANDALONE)
287 SkASSERT(data.fPath);
288 std::ifstream in(data.fPath);
Brian Osmane498b3c2020-09-23 14:42:11 -0400289 std::unique_ptr<String> text = std::make_unique<String>(std::istreambuf_iterator<char>(in),
290 std::istreambuf_iterator<char>());
Ethan Nicholasb33fa3f2020-08-06 13:00:19 -0400291 if (in.rdstate()) {
Brian Osman3d87e9f2020-10-08 11:50:22 -0400292 printf("error reading %s\n", data.fPath);
Ethan Nicholasb33fa3f2020-08-06 13:00:19 -0400293 abort();
294 }
Brian Osmane498b3c2020-09-23 14:42:11 -0400295 const String* source = fRootSymbolTable->takeOwnershipOfString(std::move(text));
Brian Osman88cda172020-10-09 12:05:16 -0400296 AutoSource as(this, source);
Ethan Nicholas8da1e652019-05-24 11:01:59 -0400297 Program::Settings settings;
John Stiles881a10c2020-09-19 10:13:24 -0400298 SkASSERT(fIRGenerator->fCanInline);
299 fIRGenerator->fCanInline = false;
Brian Osman88cda172020-10-09 12:05:16 -0400300 ParsedModule baseModule = {base, /*fIntrinsics=*/nullptr};
301 IRGenerator::IRBundle ir = fIRGenerator->convertProgram(
302 kind, &settings, baseModule, /*isBuiltinCode=*/true, source->c_str(), source->length(),
303 /*externalValues=*/nullptr);
304 LoadedModule module = { std::move(ir.fSymbolTable), std::move(ir.fElements) };
John Stiles881a10c2020-09-19 10:13:24 -0400305 fIRGenerator->fCanInline = true;
Ethan Nicholas8da1e652019-05-24 11:01:59 -0400306 if (this->fErrorCount) {
307 printf("Unexpected errors: %s\n", this->fErrorText.c_str());
Brian Osman3d87e9f2020-10-08 11:50:22 -0400308 SkDEBUGFAILF("%s %s\n", data.fPath, this->fErrorText.c_str());
Ethan Nicholas8da1e652019-05-24 11:01:59 -0400309 }
Brian Osman88cda172020-10-09 12:05:16 -0400310 fModifiers.push_back(std::move(ir.fModifiers));
Brian Osman3d87e9f2020-10-08 11:50:22 -0400311#else
312 SkASSERT(data.fData && (data.fSize != 0));
313 Rehydrator rehydrator(fContext.get(), fIRGenerator->fModifiers.get(), base, this,
314 data.fData, data.fSize);
Brian Osman88cda172020-10-09 12:05:16 -0400315 LoadedModule module = { rehydrator.symbolTable(), rehydrator.elements() };
Brian Osman3d87e9f2020-10-08 11:50:22 -0400316 fModifiers.push_back(fIRGenerator->releaseModifiers());
317#endif
318
319 return module;
320}
321
322ParsedModule Compiler::parseModule(Program::Kind kind, ModuleData data, const ParsedModule& base) {
323 auto [symbols, elements] = this->loadModule(kind, data, base.fSymbols);
324
325 // For modules that just declare (but don't define) intrinsic functions, there will be no new
326 // program elements. In that case, we can share our parent's intrinsic map:
327 if (elements.empty()) {
328 return {symbols, base.fIntrinsics};
329 }
330
331 auto intrinsics = std::make_shared<IRIntrinsicMap>(base.fIntrinsics.get());
332
333 // Now, transfer all of the program elements to an intrinsic map. This maps certain types of
334 // global objects to the declaring ProgramElement.
335 for (std::unique_ptr<ProgramElement>& element : elements) {
336 switch (element->kind()) {
337 case ProgramElement::Kind::kFunction: {
338 const FunctionDefinition& f = element->as<FunctionDefinition>();
339 SkASSERT(f.fDeclaration.isBuiltin());
340 // Call counts are used to track dead-stripping and inlinability within the program
341 // being compiled, and should start at zero for a new program. Zero out any call
342 // counts internal to the include data. (If we actually use calls from inside the
343 // intrinsics, we will clone them into the program with new call counts.)
344 f.fDeclaration.callCount() = 0;
345 intrinsics->insertOrDie(f.fDeclaration.description(), std::move(element));
346 break;
347 }
348 case ProgramElement::Kind::kEnum: {
349 const Enum& e = element->as<Enum>();
350 SkASSERT(e.isBuiltin());
351 intrinsics->insertOrDie(e.typeName(), std::move(element));
352 break;
353 }
354 case ProgramElement::Kind::kGlobalVar: {
355 const Variable* var = element->as<GlobalVarDeclaration>().fDecl->fVar;
356 SkASSERT(var->isBuiltin());
357 intrinsics->insertOrDie(var->name(), std::move(element));
358 break;
359 }
360 case ProgramElement::Kind::kInterfaceBlock: {
361 const Variable* var = element->as<InterfaceBlock>().fVariable;
362 SkASSERT(var->isBuiltin());
363 intrinsics->insertOrDie(var->name(), std::move(element));
364 break;
365 }
366 default:
367 printf("Unsupported element: %s\n", element->description().c_str());
368 SkASSERT(false);
369 break;
370 }
371 }
372
373 return {symbols, std::move(intrinsics)};
Ethan Nicholas8da1e652019-05-24 11:01:59 -0400374}
375
ethannicholas22f939e2016-10-13 13:25:34 -0700376// add the definition created by assigning to the lvalue to the definition set
Ethan Nicholas86a43402017-01-19 13:32:00 -0500377void Compiler::addDefinition(const Expression* lvalue, std::unique_ptr<Expression>* expr,
378 DefinitionMap* definitions) {
Ethan Nicholase6592142020-09-08 10:22:09 -0400379 switch (lvalue->kind()) {
380 case Expression::Kind::kVariableReference: {
Ethan Nicholas78686922020-10-08 06:46:27 -0400381 const Variable& var = *lvalue->as<VariableReference>().variable();
Ethan Nicholas453f67f2020-10-09 10:43:45 -0400382 if (var.storage() == Variable::Storage::kLocal) {
John Stiles796cdb72020-10-08 12:06:53 -0400383 definitions->set(&var, expr);
ethannicholas22f939e2016-10-13 13:25:34 -0700384 }
385 break;
386 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400387 case Expression::Kind::kSwizzle:
ethannicholas22f939e2016-10-13 13:25:34 -0700388 // We consider the variable written to as long as at least some of its components have
389 // been written to. This will lead to some false negatives (we won't catch it if you
390 // write to foo.x and then read foo.y), but being stricter could lead to false positives
Mike Klein6ad99092016-10-26 10:35:22 -0400391 // (we write to foo.x, and then pass foo to a function which happens to only read foo.x,
392 // 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 -0700393 // more complicated whole-program analysis. This is probably good enough.
John Stilesa5a97b42020-08-18 11:19:07 -0400394 this->addDefinition(lvalue->as<Swizzle>().fBase.get(),
Ethan Nicholas26a9aad2018-03-27 14:10:52 -0400395 (std::unique_ptr<Expression>*) &fContext->fDefined_Expression,
ethannicholas22f939e2016-10-13 13:25:34 -0700396 definitions);
397 break;
Ethan Nicholase6592142020-09-08 10:22:09 -0400398 case Expression::Kind::kIndex:
ethannicholas22f939e2016-10-13 13:25:34 -0700399 // see comments in Swizzle
Ethan Nicholas2a4952d2020-10-08 15:35:56 -0400400 this->addDefinition(lvalue->as<IndexExpression>().base().get(),
Ethan Nicholas26a9aad2018-03-27 14:10:52 -0400401 (std::unique_ptr<Expression>*) &fContext->fDefined_Expression,
ethannicholas22f939e2016-10-13 13:25:34 -0700402 definitions);
403 break;
Ethan Nicholase6592142020-09-08 10:22:09 -0400404 case Expression::Kind::kFieldAccess:
ethannicholas22f939e2016-10-13 13:25:34 -0700405 // see comments in Swizzle
Ethan Nicholas7a95b202020-10-09 11:55:40 -0400406 this->addDefinition(lvalue->as<FieldAccess>().base().get(),
Ethan Nicholas26a9aad2018-03-27 14:10:52 -0400407 (std::unique_ptr<Expression>*) &fContext->fDefined_Expression,
ethannicholas22f939e2016-10-13 13:25:34 -0700408 definitions);
409 break;
Ethan Nicholase6592142020-09-08 10:22:09 -0400410 case Expression::Kind::kTernary:
Ethan Nicholasa583b812018-01-18 13:32:11 -0500411 // To simplify analysis, we just pretend that we write to both sides of the ternary.
412 // This allows for false positives (meaning we fail to detect that a variable might not
413 // have been assigned), but is preferable to false negatives.
Ethan Nicholasdd218162020-10-08 05:48:01 -0400414 this->addDefinition(lvalue->as<TernaryExpression>().ifTrue().get(),
Ethan Nicholas26a9aad2018-03-27 14:10:52 -0400415 (std::unique_ptr<Expression>*) &fContext->fDefined_Expression,
Ethan Nicholasa583b812018-01-18 13:32:11 -0500416 definitions);
Ethan Nicholasdd218162020-10-08 05:48:01 -0400417 this->addDefinition(lvalue->as<TernaryExpression>().ifFalse().get(),
Ethan Nicholas26a9aad2018-03-27 14:10:52 -0400418 (std::unique_ptr<Expression>*) &fContext->fDefined_Expression,
Ethan Nicholasa583b812018-01-18 13:32:11 -0500419 definitions);
420 break;
Ethan Nicholase6592142020-09-08 10:22:09 -0400421 case Expression::Kind::kExternalValue:
Ethan Nicholas91164d12019-05-15 15:29:54 -0400422 break;
ethannicholas22f939e2016-10-13 13:25:34 -0700423 default:
424 // not an lvalue, can't happen
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400425 SkASSERT(false);
ethannicholas22f939e2016-10-13 13:25:34 -0700426 }
427}
428
429// add local variables defined by this node to the set
John Stiles796cdb72020-10-08 12:06:53 -0400430void Compiler::addDefinitions(const BasicBlock::Node& node, DefinitionMap* definitions) {
John Stiles70025e52020-09-28 16:08:58 -0400431 if (node.isExpression()) {
432 Expression* expr = node.expression()->get();
433 switch (expr->kind()) {
434 case Expression::Kind::kBinary: {
435 BinaryExpression* b = &expr->as<BinaryExpression>();
436 if (b->getOperator() == Token::Kind::TK_EQ) {
437 this->addDefinition(&b->left(), &b->rightPointer(), definitions);
438 } else if (Compiler::IsAssignment(b->getOperator())) {
439 this->addDefinition(
440 &b->left(),
441 (std::unique_ptr<Expression>*) &fContext->fDefined_Expression,
442 definitions);
Ethan Nicholas86a43402017-01-19 13:32:00 -0500443
ethannicholas22f939e2016-10-13 13:25:34 -0700444 }
John Stiles70025e52020-09-28 16:08:58 -0400445 break;
ethannicholas22f939e2016-10-13 13:25:34 -0700446 }
John Stiles70025e52020-09-28 16:08:58 -0400447 case Expression::Kind::kFunctionCall: {
448 const FunctionCall& c = expr->as<FunctionCall>();
Ethan Nicholased84b732020-10-08 11:45:44 -0400449 const std::vector<Variable*>& parameters = c.function().parameters();
450 for (size_t i = 0; i < parameters.size(); ++i) {
451 if (parameters[i]->modifiers().fFlags & Modifiers::kOut_Flag) {
John Stiles70025e52020-09-28 16:08:58 -0400452 this->addDefinition(
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400453 c.arguments()[i].get(),
John Stiles70025e52020-09-28 16:08:58 -0400454 (std::unique_ptr<Expression>*) &fContext->fDefined_Expression,
455 definitions);
456 }
457 }
458 break;
459 }
460 case Expression::Kind::kPrefix: {
461 const PrefixExpression* p = &expr->as<PrefixExpression>();
Ethan Nicholas444ccc62020-10-09 10:16:22 -0400462 if (p->getOperator() == Token::Kind::TK_MINUSMINUS ||
463 p->getOperator() == Token::Kind::TK_PLUSPLUS) {
John Stiles70025e52020-09-28 16:08:58 -0400464 this->addDefinition(
Ethan Nicholas444ccc62020-10-09 10:16:22 -0400465 p->operand().get(),
John Stiles70025e52020-09-28 16:08:58 -0400466 (std::unique_ptr<Expression>*) &fContext->fDefined_Expression,
467 definitions);
468 }
469 break;
470 }
471 case Expression::Kind::kPostfix: {
472 const PostfixExpression* p = &expr->as<PostfixExpression>();
Ethan Nicholas444ccc62020-10-09 10:16:22 -0400473 if (p->getOperator() == Token::Kind::TK_MINUSMINUS ||
474 p->getOperator() == Token::Kind::TK_PLUSPLUS) {
John Stiles70025e52020-09-28 16:08:58 -0400475 this->addDefinition(
Ethan Nicholas444ccc62020-10-09 10:16:22 -0400476 p->operand().get(),
John Stiles70025e52020-09-28 16:08:58 -0400477 (std::unique_ptr<Expression>*) &fContext->fDefined_Expression,
478 definitions);
479 }
480 break;
481 }
482 case Expression::Kind::kVariableReference: {
483 const VariableReference* v = &expr->as<VariableReference>();
Ethan Nicholas453f67f2020-10-09 10:43:45 -0400484 if (v->refKind() != VariableReference::RefKind::kRead) {
John Stiles70025e52020-09-28 16:08:58 -0400485 this->addDefinition(
486 v,
487 (std::unique_ptr<Expression>*) &fContext->fDefined_Expression,
488 definitions);
489 }
490 break;
491 }
492 default:
493 break;
ethannicholas22f939e2016-10-13 13:25:34 -0700494 }
John Stiles70025e52020-09-28 16:08:58 -0400495 } else if (node.isStatement()) {
496 Statement* stmt = node.statement()->get();
497 if (stmt->is<VarDeclaration>()) {
498 VarDeclaration& vd = stmt->as<VarDeclaration>();
499 if (vd.fValue) {
John Stiles796cdb72020-10-08 12:06:53 -0400500 definitions->set(vd.fVar, &vd.fValue);
ethannicholas22f939e2016-10-13 13:25:34 -0700501 }
ethannicholas22f939e2016-10-13 13:25:34 -0700502 }
503 }
504}
505
John Stilese6150002020-10-05 12:03:53 -0400506void Compiler::scanCFG(CFG* cfg, BlockId blockId, SkBitSet* processedSet) {
ethannicholas22f939e2016-10-13 13:25:34 -0700507 BasicBlock& block = cfg->fBlocks[blockId];
508
509 // compute definitions after this block
Ethan Nicholas86a43402017-01-19 13:32:00 -0500510 DefinitionMap after = block.fBefore;
ethannicholas22f939e2016-10-13 13:25:34 -0700511 for (const BasicBlock::Node& n : block.fNodes) {
512 this->addDefinitions(n, &after);
513 }
514
515 // propagate definitions to exits
516 for (BlockId exitId : block.fExits) {
Ethan Nicholas26a9aad2018-03-27 14:10:52 -0400517 if (exitId == blockId) {
518 continue;
519 }
ethannicholas22f939e2016-10-13 13:25:34 -0700520 BasicBlock& exit = cfg->fBlocks[exitId];
John Stiles796cdb72020-10-08 12:06:53 -0400521 after.foreach([&](const Variable* var, std::unique_ptr<Expression>** e1Ptr) {
522 std::unique_ptr<Expression>* e1 = *e1Ptr;
523 std::unique_ptr<Expression>** exitDef = exit.fBefore.find(var);
524 if (!exitDef) {
John Stilese6150002020-10-05 12:03:53 -0400525 // exit has no definition for it, just copy it and reprocess exit block
526 processedSet->reset(exitId);
John Stiles796cdb72020-10-08 12:06:53 -0400527 exit.fBefore[var] = e1;
ethannicholas22f939e2016-10-13 13:25:34 -0700528 } else {
Ethan Nicholas86a43402017-01-19 13:32:00 -0500529 // exit has a (possibly different) value already defined
John Stiles796cdb72020-10-08 12:06:53 -0400530 std::unique_ptr<Expression>* e2 = *exitDef;
ethannicholas22f939e2016-10-13 13:25:34 -0700531 if (e1 != e2) {
John Stilese6150002020-10-05 12:03:53 -0400532 // definition has changed, merge and reprocess the exit block
533 processedSet->reset(exitId);
Ethan Nicholasaf197692017-02-27 13:26:45 -0500534 if (e1 && e2) {
John Stiles796cdb72020-10-08 12:06:53 -0400535 *exitDef = (std::unique_ptr<Expression>*)&fContext->fDefined_Expression;
Ethan Nicholasaf197692017-02-27 13:26:45 -0500536 } else {
John Stiles796cdb72020-10-08 12:06:53 -0400537 *exitDef = nullptr;
Ethan Nicholasaf197692017-02-27 13:26:45 -0500538 }
ethannicholas22f939e2016-10-13 13:25:34 -0700539 }
540 }
John Stiles796cdb72020-10-08 12:06:53 -0400541 });
ethannicholas22f939e2016-10-13 13:25:34 -0700542 }
543}
544
545// returns a map which maps all local variables in the function to null, indicating that their value
546// is initially unknown
Ethan Nicholas86a43402017-01-19 13:32:00 -0500547static DefinitionMap compute_start_state(const CFG& cfg) {
548 DefinitionMap result;
Mike Klein6ad99092016-10-26 10:35:22 -0400549 for (const auto& block : cfg.fBlocks) {
550 for (const auto& node : block.fNodes) {
John Stiles70025e52020-09-28 16:08:58 -0400551 if (node.isStatement()) {
Ethan Nicholascb670962017-04-20 19:31:52 -0400552 const Statement* s = node.statement()->get();
Brian Osmanc0213602020-10-06 14:43:32 -0400553 if (s->is<VarDeclaration>()) {
554 result[s->as<VarDeclaration>().fVar] = nullptr;
ethannicholas22f939e2016-10-13 13:25:34 -0700555 }
556 }
557 }
558 }
559 return result;
560}
561
Ethan Nicholascb670962017-04-20 19:31:52 -0400562/**
563 * Returns true if assigning to this lvalue has no effect.
564 */
565static bool is_dead(const Expression& lvalue) {
Ethan Nicholase6592142020-09-08 10:22:09 -0400566 switch (lvalue.kind()) {
567 case Expression::Kind::kVariableReference:
Ethan Nicholas78686922020-10-08 06:46:27 -0400568 return lvalue.as<VariableReference>().variable()->dead();
Ethan Nicholase6592142020-09-08 10:22:09 -0400569 case Expression::Kind::kSwizzle:
John Stilesa5a97b42020-08-18 11:19:07 -0400570 return is_dead(*lvalue.as<Swizzle>().fBase);
Ethan Nicholase6592142020-09-08 10:22:09 -0400571 case Expression::Kind::kFieldAccess:
Ethan Nicholas7a95b202020-10-09 11:55:40 -0400572 return is_dead(*lvalue.as<FieldAccess>().base());
Ethan Nicholase6592142020-09-08 10:22:09 -0400573 case Expression::Kind::kIndex: {
John Stilesa5a97b42020-08-18 11:19:07 -0400574 const IndexExpression& idx = lvalue.as<IndexExpression>();
Ethan Nicholas2a4952d2020-10-08 15:35:56 -0400575 return is_dead(*idx.base()) &&
576 !idx.index()->hasProperty(Expression::Property::kSideEffects);
Ethan Nicholascb670962017-04-20 19:31:52 -0400577 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400578 case Expression::Kind::kTernary: {
John Stilesa5a97b42020-08-18 11:19:07 -0400579 const TernaryExpression& t = lvalue.as<TernaryExpression>();
Ethan Nicholasdd218162020-10-08 05:48:01 -0400580 return !t.test()->hasSideEffects() && is_dead(*t.ifTrue()) && is_dead(*t.ifFalse());
Ethan Nicholasa583b812018-01-18 13:32:11 -0500581 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400582 case Expression::Kind::kExternalValue:
Ethan Nicholas91164d12019-05-15 15:29:54 -0400583 return false;
Ethan Nicholascb670962017-04-20 19:31:52 -0400584 default:
Ethan Nicholas2a099da2020-01-02 14:40:54 -0500585#ifdef SK_DEBUG
Ethan Nicholascb670962017-04-20 19:31:52 -0400586 ABORT("invalid lvalue: %s\n", lvalue.description().c_str());
Ethan Nicholas2a099da2020-01-02 14:40:54 -0500587#endif
588 return false;
Ethan Nicholascb670962017-04-20 19:31:52 -0400589 }
590}
ethannicholas22f939e2016-10-13 13:25:34 -0700591
Ethan Nicholascb670962017-04-20 19:31:52 -0400592/**
593 * Returns true if this is an assignment which can be collapsed down to just the right hand side due
594 * to a dead target and lack of side effects on the left hand side.
595 */
596static bool dead_assignment(const BinaryExpression& b) {
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400597 if (!Compiler::IsAssignment(b.getOperator())) {
Ethan Nicholascb670962017-04-20 19:31:52 -0400598 return false;
599 }
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400600 return is_dead(b.left());
Ethan Nicholascb670962017-04-20 19:31:52 -0400601}
602
603void Compiler::computeDataFlow(CFG* cfg) {
604 cfg->fBlocks[cfg->fStart].fBefore = compute_start_state(*cfg);
John Stilese6150002020-10-05 12:03:53 -0400605
606 // We set bits in the "processed" set after a block has been scanned.
607 SkBitSet processedSet(cfg->fBlocks.size());
608 while (SkBitSet::OptionalIndex blockId = processedSet.findFirstUnset()) {
609 processedSet.set(*blockId);
610 this->scanCFG(cfg, *blockId, &processedSet);
ethannicholas22f939e2016-10-13 13:25:34 -0700611 }
Ethan Nicholascb670962017-04-20 19:31:52 -0400612}
613
614/**
615 * Attempts to replace the expression pointed to by iter with a new one (in both the CFG and the
616 * IR). If the expression can be cleanly removed, returns true and updates the iterator to point to
617 * the newly-inserted element. Otherwise updates only the IR and returns false (and the CFG will
618 * need to be regenerated).
619 */
John Stilesafbf8992020-08-18 10:08:21 -0400620static bool try_replace_expression(BasicBlock* b,
621 std::vector<BasicBlock::Node>::iterator* iter,
622 std::unique_ptr<Expression>* newExpression) {
Ethan Nicholascb670962017-04-20 19:31:52 -0400623 std::unique_ptr<Expression>* target = (*iter)->expression();
624 if (!b->tryRemoveExpression(iter)) {
625 *target = std::move(*newExpression);
626 return false;
627 }
628 *target = std::move(*newExpression);
629 return b->tryInsertExpression(iter, target);
630}
631
632/**
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400633 * Returns true if the expression is a constant numeric literal with the specified value, or a
634 * constant vector with all elements equal to the specified value.
Ethan Nicholascb670962017-04-20 19:31:52 -0400635 */
Ethan Nicholasa3f22f12020-10-01 12:13:17 -0400636template <typename T = SKSL_FLOAT>
John Stiles9d944232020-08-19 09:56:49 -0400637static bool is_constant(const Expression& expr, T value) {
Ethan Nicholase6592142020-09-08 10:22:09 -0400638 switch (expr.kind()) {
639 case Expression::Kind::kIntLiteral:
Ethan Nicholase96cdd12020-09-28 16:27:18 -0400640 return expr.as<IntLiteral>().value() == value;
John Stiles9d944232020-08-19 09:56:49 -0400641
Ethan Nicholase6592142020-09-08 10:22:09 -0400642 case Expression::Kind::kFloatLiteral:
Ethan Nicholasa3f22f12020-10-01 12:13:17 -0400643 return expr.as<FloatLiteral>().value() == value;
John Stiles9d944232020-08-19 09:56:49 -0400644
Ethan Nicholase6592142020-09-08 10:22:09 -0400645 case Expression::Kind::kConstructor: {
John Stiles9d944232020-08-19 09:56:49 -0400646 const Constructor& constructor = expr.as<Constructor>();
647 if (constructor.isCompileTimeConstant()) {
Ethan Nicholas30d30222020-09-11 12:27:26 -0400648 const Type& constructorType = constructor.type();
649 bool isFloat = constructorType.columns() > 1
650 ? constructorType.componentType().isFloat()
651 : constructorType.isFloat();
652 switch (constructorType.typeKind()) {
Ethan Nicholase6592142020-09-08 10:22:09 -0400653 case Type::TypeKind::kVector:
Ethan Nicholas30d30222020-09-11 12:27:26 -0400654 for (int i = 0; i < constructorType.columns(); ++i) {
John Stiles9d944232020-08-19 09:56:49 -0400655 if (isFloat) {
656 if (constructor.getFVecComponent(i) != value) {
657 return false;
658 }
659 } else {
660 if (constructor.getIVecComponent(i) != value) {
661 return false;
662 }
663 }
Ethan Nicholasd188c182019-06-10 15:55:38 -0400664 }
John Stiles9d944232020-08-19 09:56:49 -0400665 return true;
666
Ethan Nicholase6592142020-09-08 10:22:09 -0400667 case Type::TypeKind::kScalar:
Ethan Nicholasf70f0442020-09-29 12:41:35 -0400668 SkASSERT(constructor.arguments().size() == 1);
669 return is_constant<T>(*constructor.arguments()[0], value);
John Stiles9d944232020-08-19 09:56:49 -0400670
671 default:
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400672 return false;
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400673 }
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400674 }
675 return false;
676 }
Ethan Nicholascb670962017-04-20 19:31:52 -0400677 default:
678 return false;
679 }
680}
681
682/**
683 * Collapses the binary expression pointed to by iter down to just the right side (in both the IR
684 * and CFG structures).
685 */
John Stilesafbf8992020-08-18 10:08:21 -0400686static void delete_left(BasicBlock* b,
687 std::vector<BasicBlock::Node>::iterator* iter,
688 bool* outUpdated,
689 bool* outNeedsRescan) {
Ethan Nicholascb670962017-04-20 19:31:52 -0400690 *outUpdated = true;
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400691 std::unique_ptr<Expression>* target = (*iter)->expression();
John Stilesa5a97b42020-08-18 11:19:07 -0400692 BinaryExpression& bin = (*target)->as<BinaryExpression>();
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400693 Expression& left = bin.left();
694 std::unique_ptr<Expression>& rightPointer = bin.rightPointer();
695 SkASSERT(!left.hasSideEffects());
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400696 bool result;
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400697 if (bin.getOperator() == Token::Kind::TK_EQ) {
698 result = b->tryRemoveLValueBefore(iter, &left);
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400699 } else {
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400700 result = b->tryRemoveExpressionBefore(iter, &left);
Ethan Nicholascb670962017-04-20 19:31:52 -0400701 }
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400702 *target = std::move(rightPointer);
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400703 if (!result) {
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400704 *outNeedsRescan = true;
705 return;
706 }
707 if (*iter == b->fNodes.begin()) {
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400708 *outNeedsRescan = true;
709 return;
710 }
711 --(*iter);
John Stiles70025e52020-09-28 16:08:58 -0400712 if (!(*iter)->isExpression() || (*iter)->expression() != &rightPointer) {
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400713 *outNeedsRescan = true;
714 return;
715 }
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400716 *iter = b->fNodes.erase(*iter);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400717 SkASSERT((*iter)->expression() == target);
Ethan Nicholascb670962017-04-20 19:31:52 -0400718}
719
720/**
721 * Collapses the binary expression pointed to by iter down to just the left side (in both the IR and
722 * CFG structures).
723 */
John Stilesafbf8992020-08-18 10:08:21 -0400724static void delete_right(BasicBlock* b,
725 std::vector<BasicBlock::Node>::iterator* iter,
726 bool* outUpdated,
727 bool* outNeedsRescan) {
Ethan Nicholascb670962017-04-20 19:31:52 -0400728 *outUpdated = true;
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400729 std::unique_ptr<Expression>* target = (*iter)->expression();
John Stilesa5a97b42020-08-18 11:19:07 -0400730 BinaryExpression& bin = (*target)->as<BinaryExpression>();
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400731 std::unique_ptr<Expression>& leftPointer = bin.leftPointer();
732 Expression& right = bin.right();
733 SkASSERT(!right.hasSideEffects());
734 if (!b->tryRemoveExpressionBefore(iter, &right)) {
735 *target = std::move(leftPointer);
Ethan Nicholascb670962017-04-20 19:31:52 -0400736 *outNeedsRescan = true;
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400737 return;
Ethan Nicholascb670962017-04-20 19:31:52 -0400738 }
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400739 *target = std::move(leftPointer);
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400740 if (*iter == b->fNodes.begin()) {
741 *outNeedsRescan = true;
742 return;
743 }
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400744 --(*iter);
John Stiles70025e52020-09-28 16:08:58 -0400745 if ((!(*iter)->isExpression() || (*iter)->expression() != &leftPointer)) {
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400746 *outNeedsRescan = true;
747 return;
748 }
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400749 *iter = b->fNodes.erase(*iter);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400750 SkASSERT((*iter)->expression() == target);
Ethan Nicholascb670962017-04-20 19:31:52 -0400751}
752
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400753/**
754 * Constructs the specified type using a single argument.
755 */
Ethan Nicholas30d30222020-09-11 12:27:26 -0400756static std::unique_ptr<Expression> construct(const Type* type, std::unique_ptr<Expression> v) {
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400757 std::vector<std::unique_ptr<Expression>> args;
758 args.push_back(std::move(v));
Ethan Nicholase6592142020-09-08 10:22:09 -0400759 std::unique_ptr<Expression> result = std::make_unique<Constructor>(-1, type, std::move(args));
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400760 return result;
761}
762
763/**
764 * Used in the implementations of vectorize_left and vectorize_right. Given a vector type and an
765 * expression x, deletes the expression pointed to by iter and replaces it with <type>(x).
766 */
767static void vectorize(BasicBlock* b,
768 std::vector<BasicBlock::Node>::iterator* iter,
769 const Type& type,
770 std::unique_ptr<Expression>* otherExpression,
771 bool* outUpdated,
772 bool* outNeedsRescan) {
Ethan Nicholase6592142020-09-08 10:22:09 -0400773 SkASSERT((*(*iter)->expression())->kind() == Expression::Kind::kBinary);
774 SkASSERT(type.typeKind() == Type::TypeKind::kVector);
Ethan Nicholas30d30222020-09-11 12:27:26 -0400775 SkASSERT((*otherExpression)->type().typeKind() == Type::TypeKind::kScalar);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400776 *outUpdated = true;
777 std::unique_ptr<Expression>* target = (*iter)->expression();
778 if (!b->tryRemoveExpression(iter)) {
Ethan Nicholas30d30222020-09-11 12:27:26 -0400779 *target = construct(&type, std::move(*otherExpression));
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400780 *outNeedsRescan = true;
781 } else {
Ethan Nicholas30d30222020-09-11 12:27:26 -0400782 *target = construct(&type, std::move(*otherExpression));
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400783 if (!b->tryInsertExpression(iter, target)) {
784 *outNeedsRescan = true;
785 }
786 }
787}
788
789/**
790 * Given a binary expression of the form x <op> vec<n>(y), deletes the right side and vectorizes the
791 * left to yield vec<n>(x).
792 */
793static void vectorize_left(BasicBlock* b,
794 std::vector<BasicBlock::Node>::iterator* iter,
795 bool* outUpdated,
796 bool* outNeedsRescan) {
John Stilesa5a97b42020-08-18 11:19:07 -0400797 BinaryExpression& bin = (*(*iter)->expression())->as<BinaryExpression>();
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400798 vectorize(b, iter, bin.right().type(), &bin.leftPointer(), outUpdated, outNeedsRescan);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400799}
800
801/**
802 * Given a binary expression of the form vec<n>(x) <op> y, deletes the left side and vectorizes the
803 * right to yield vec<n>(y).
804 */
805static void vectorize_right(BasicBlock* b,
806 std::vector<BasicBlock::Node>::iterator* iter,
807 bool* outUpdated,
808 bool* outNeedsRescan) {
John Stilesa5a97b42020-08-18 11:19:07 -0400809 BinaryExpression& bin = (*(*iter)->expression())->as<BinaryExpression>();
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400810 vectorize(b, iter, bin.left().type(), &bin.rightPointer(), outUpdated, outNeedsRescan);
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:
John Stilesa5a97b42020-08-18 11:19:07 -0400824 clear_write(*expr.as<Swizzle>().fBase);
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,
838 std::unordered_set<const Variable*>* undefinedVariables,
839 bool* outUpdated,
840 bool* outNeedsRescan) {
841 Expression* expr = (*iter)->expression()->get();
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400842 SkASSERT(expr);
Ethan Nicholascb670962017-04-20 19:31:52 -0400843 if ((*iter)->fConstantPropagation) {
844 std::unique_ptr<Expression> optimized = expr->constantPropagate(*fIRGenerator, definitions);
845 if (optimized) {
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400846 *outUpdated = 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);
Ethan Nicholascb670962017-04-20 19:31:52 -0400849 if (!try_replace_expression(&b, iter, &optimized)) {
850 *outNeedsRescan = true;
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400851 return;
Ethan Nicholascb670962017-04-20 19:31:52 -0400852 }
John Stiles70025e52020-09-28 16:08:58 -0400853 SkASSERT((*iter)->isExpression());
Ethan Nicholascb670962017-04-20 19:31:52 -0400854 expr = (*iter)->expression()->get();
Ethan Nicholascb670962017-04-20 19:31:52 -0400855 }
856 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400857 switch (expr->kind()) {
858 case Expression::Kind::kVariableReference: {
John Stilesa5a97b42020-08-18 11:19:07 -0400859 const VariableReference& ref = expr->as<VariableReference>();
Ethan Nicholas78686922020-10-08 06:46:27 -0400860 const Variable* var = ref.variable();
Ethan Nicholas453f67f2020-10-09 10:43:45 -0400861 if (ref.refKind() != VariableReference::RefKind::kWrite &&
862 ref.refKind() != VariableReference::RefKind::kPointer &&
863 var->storage() == Variable::Storage::kLocal && !definitions[var] &&
Brian Osman79457ef2020-09-24 15:01:27 -0400864 (*undefinedVariables).find(var) == (*undefinedVariables).end()) {
865 (*undefinedVariables).insert(var);
Ethan Nicholas82a62d22017-11-07 14:42:10 +0000866 this->error(expr->fOffset,
Ethan Nicholase2c49992020-10-05 11:49:11 -0400867 "'" + var->name() + "' has not been assigned");
Ethan Nicholascb670962017-04-20 19:31:52 -0400868 }
869 break;
870 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400871 case Expression::Kind::kTernary: {
John Stiles403a3632020-08-20 12:11:48 -0400872 TernaryExpression* t = &expr->as<TernaryExpression>();
Ethan Nicholasdd218162020-10-08 05:48:01 -0400873 if (t->test()->is<BoolLiteral>()) {
Ethan Nicholascb670962017-04-20 19:31:52 -0400874 // ternary has a constant test, replace it with either the true or
875 // false branch
Ethan Nicholasdd218162020-10-08 05:48:01 -0400876 if (t->test()->as<BoolLiteral>().value()) {
877 (*iter)->setExpression(std::move(t->ifTrue()));
Ethan Nicholascb670962017-04-20 19:31:52 -0400878 } else {
Ethan Nicholasdd218162020-10-08 05:48:01 -0400879 (*iter)->setExpression(std::move(t->ifFalse()));
Ethan Nicholascb670962017-04-20 19:31:52 -0400880 }
881 *outUpdated = true;
882 *outNeedsRescan = true;
883 }
884 break;
885 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400886 case Expression::Kind::kBinary: {
John Stiles403a3632020-08-20 12:11:48 -0400887 BinaryExpression* bin = &expr->as<BinaryExpression>();
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400888 if (dead_assignment(*bin)) {
889 delete_left(&b, iter, outUpdated, outNeedsRescan);
890 break;
891 }
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400892 Expression& left = bin->left();
893 Expression& right = bin->right();
894 const Type& leftType = left.type();
895 const Type& rightType = right.type();
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400896 // collapse useless expressions like x * 1 or x + 0
Ethan Nicholas30d30222020-09-11 12:27:26 -0400897 if (((leftType.typeKind() != Type::TypeKind::kScalar) &&
898 (leftType.typeKind() != Type::TypeKind::kVector)) ||
899 ((rightType.typeKind() != Type::TypeKind::kScalar) &&
900 (rightType.typeKind() != Type::TypeKind::kVector))) {
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400901 break;
902 }
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400903 switch (bin->getOperator()) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400904 case Token::Kind::TK_STAR:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400905 if (is_constant(left, 1)) {
Ethan Nicholas30d30222020-09-11 12:27:26 -0400906 if (leftType.typeKind() == Type::TypeKind::kVector &&
907 rightType.typeKind() == Type::TypeKind::kScalar) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400908 // float4(1) * x -> float4(x)
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400909 vectorize_right(&b, iter, outUpdated, outNeedsRescan);
910 } else {
911 // 1 * x -> x
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400912 // 1 * float4(x) -> float4(x)
913 // float4(1) * float4(x) -> float4(x)
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400914 delete_left(&b, iter, outUpdated, outNeedsRescan);
915 }
916 }
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400917 else if (is_constant(left, 0)) {
Ethan Nicholas30d30222020-09-11 12:27:26 -0400918 if (leftType.typeKind() == Type::TypeKind::kScalar &&
919 rightType.typeKind() == Type::TypeKind::kVector &&
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400920 !right.hasSideEffects()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400921 // 0 * float4(x) -> float4(0)
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400922 vectorize_left(&b, iter, outUpdated, outNeedsRescan);
923 } else {
924 // 0 * x -> 0
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400925 // float4(0) * x -> float4(0)
926 // float4(0) * float4(x) -> float4(0)
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400927 if (!right.hasSideEffects()) {
Ethan Nicholas51493ee2017-12-11 12:34:33 -0500928 delete_right(&b, iter, outUpdated, outNeedsRescan);
929 }
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400930 }
Ethan Nicholascb670962017-04-20 19:31:52 -0400931 }
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400932 else if (is_constant(right, 1)) {
Ethan Nicholas30d30222020-09-11 12:27:26 -0400933 if (leftType.typeKind() == Type::TypeKind::kScalar &&
934 rightType.typeKind() == Type::TypeKind::kVector) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400935 // x * float4(1) -> float4(x)
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400936 vectorize_left(&b, iter, outUpdated, outNeedsRescan);
937 } else {
938 // x * 1 -> x
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400939 // float4(x) * 1 -> float4(x)
940 // float4(x) * float4(1) -> float4(x)
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400941 delete_right(&b, iter, outUpdated, outNeedsRescan);
942 }
943 }
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400944 else if (is_constant(right, 0)) {
Ethan Nicholas30d30222020-09-11 12:27:26 -0400945 if (leftType.typeKind() == Type::TypeKind::kVector &&
946 rightType.typeKind() == Type::TypeKind::kScalar &&
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400947 !left.hasSideEffects()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400948 // float4(x) * 0 -> float4(0)
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400949 vectorize_right(&b, iter, outUpdated, outNeedsRescan);
950 } else {
951 // x * 0 -> 0
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400952 // x * float4(0) -> float4(0)
953 // float4(x) * float4(0) -> float4(0)
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400954 if (!left.hasSideEffects()) {
Ethan Nicholas51493ee2017-12-11 12:34:33 -0500955 delete_left(&b, iter, outUpdated, outNeedsRescan);
956 }
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400957 }
Ethan Nicholascb670962017-04-20 19:31:52 -0400958 }
959 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400960 case Token::Kind::TK_PLUS:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400961 if (is_constant(left, 0)) {
Ethan Nicholas30d30222020-09-11 12:27:26 -0400962 if (leftType.typeKind() == Type::TypeKind::kVector &&
963 rightType.typeKind() == Type::TypeKind::kScalar) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400964 // float4(0) + x -> float4(x)
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400965 vectorize_right(&b, iter, outUpdated, outNeedsRescan);
966 } else {
967 // 0 + x -> x
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400968 // 0 + float4(x) -> float4(x)
969 // float4(0) + float4(x) -> float4(x)
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400970 delete_left(&b, iter, outUpdated, outNeedsRescan);
971 }
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400972 } else if (is_constant(right, 0)) {
Ethan Nicholas30d30222020-09-11 12:27:26 -0400973 if (leftType.typeKind() == Type::TypeKind::kScalar &&
974 rightType.typeKind() == Type::TypeKind::kVector) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400975 // x + float4(0) -> float4(x)
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400976 vectorize_left(&b, iter, outUpdated, outNeedsRescan);
977 } else {
978 // x + 0 -> x
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400979 // float4(x) + 0 -> float4(x)
980 // float4(x) + float4(0) -> float4(x)
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400981 delete_right(&b, iter, outUpdated, outNeedsRescan);
982 }
Ethan Nicholas56e42712017-04-21 10:23:37 -0400983 }
984 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400985 case Token::Kind::TK_MINUS:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400986 if (is_constant(right, 0)) {
Ethan Nicholas30d30222020-09-11 12:27:26 -0400987 if (leftType.typeKind() == Type::TypeKind::kScalar &&
988 rightType.typeKind() == Type::TypeKind::kVector) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400989 // x - float4(0) -> float4(x)
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400990 vectorize_left(&b, iter, outUpdated, outNeedsRescan);
991 } else {
992 // x - 0 -> x
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400993 // float4(x) - 0 -> float4(x)
994 // float4(x) - float4(0) -> float4(x)
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400995 delete_right(&b, iter, outUpdated, outNeedsRescan);
996 }
Ethan Nicholascb670962017-04-20 19:31:52 -0400997 }
998 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400999 case Token::Kind::TK_SLASH:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -04001000 if (is_constant(right, 1)) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001001 if (leftType.typeKind() == Type::TypeKind::kScalar &&
1002 rightType.typeKind() == Type::TypeKind::kVector) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -04001003 // x / float4(1) -> float4(x)
Ethan Nicholasfe53e582017-04-27 16:24:51 -04001004 vectorize_left(&b, iter, outUpdated, outNeedsRescan);
1005 } else {
1006 // x / 1 -> x
Ethan Nicholas5af9ea32017-07-28 15:19:46 -04001007 // float4(x) / 1 -> float4(x)
1008 // float4(x) / float4(1) -> float4(x)
Ethan Nicholasfe53e582017-04-27 16:24:51 -04001009 delete_right(&b, iter, outUpdated, outNeedsRescan);
1010 }
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -04001011 } else if (is_constant(left, 0)) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001012 if (leftType.typeKind() == Type::TypeKind::kScalar &&
1013 rightType.typeKind() == Type::TypeKind::kVector &&
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -04001014 !right.hasSideEffects()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -04001015 // 0 / float4(x) -> float4(0)
Ethan Nicholasfe53e582017-04-27 16:24:51 -04001016 vectorize_left(&b, iter, outUpdated, outNeedsRescan);
1017 } else {
1018 // 0 / x -> 0
Ethan Nicholas5af9ea32017-07-28 15:19:46 -04001019 // float4(0) / x -> float4(0)
1020 // float4(0) / float4(x) -> float4(0)
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -04001021 if (!right.hasSideEffects()) {
Ethan Nicholas51493ee2017-12-11 12:34:33 -05001022 delete_right(&b, iter, outUpdated, outNeedsRescan);
1023 }
Ethan Nicholasfe53e582017-04-27 16:24:51 -04001024 }
1025 }
1026 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001027 case Token::Kind::TK_PLUSEQ:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -04001028 if (is_constant(right, 0)) {
1029 clear_write(left);
Ethan Nicholasfe53e582017-04-27 16:24:51 -04001030 delete_right(&b, iter, outUpdated, outNeedsRescan);
1031 }
1032 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001033 case Token::Kind::TK_MINUSEQ:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -04001034 if (is_constant(right, 0)) {
1035 clear_write(left);
Ethan Nicholasfe53e582017-04-27 16:24:51 -04001036 delete_right(&b, iter, outUpdated, outNeedsRescan);
1037 }
1038 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001039 case Token::Kind::TK_STAREQ:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -04001040 if (is_constant(right, 1)) {
1041 clear_write(left);
Ethan Nicholasfe53e582017-04-27 16:24:51 -04001042 delete_right(&b, iter, outUpdated, outNeedsRescan);
1043 }
1044 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001045 case Token::Kind::TK_SLASHEQ:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -04001046 if (is_constant(right, 1)) {
1047 clear_write(left);
Ethan Nicholascb670962017-04-20 19:31:52 -04001048 delete_right(&b, iter, outUpdated, outNeedsRescan);
1049 }
1050 break;
1051 default:
1052 break;
1053 }
Ethan Nicholas409f6f02019-09-17 12:34:39 -04001054 break;
1055 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001056 case Expression::Kind::kSwizzle: {
John Stiles403a3632020-08-20 12:11:48 -04001057 Swizzle& s = expr->as<Swizzle>();
Ethan Nicholas409f6f02019-09-17 12:34:39 -04001058 // detect identity swizzles like foo.rgba
Ethan Nicholas30d30222020-09-11 12:27:26 -04001059 if ((int) s.fComponents.size() == s.fBase->type().columns()) {
Ethan Nicholas409f6f02019-09-17 12:34:39 -04001060 bool identity = true;
1061 for (int i = 0; i < (int) s.fComponents.size(); ++i) {
1062 if (s.fComponents[i] != i) {
1063 identity = false;
1064 break;
1065 }
1066 }
1067 if (identity) {
1068 *outUpdated = true;
1069 if (!try_replace_expression(&b, iter, &s.fBase)) {
1070 *outNeedsRescan = true;
1071 return;
1072 }
John Stiles70025e52020-09-28 16:08:58 -04001073 SkASSERT((*iter)->isExpression());
Ethan Nicholas409f6f02019-09-17 12:34:39 -04001074 break;
1075 }
1076 }
1077 // detect swizzles of swizzles, e.g. replace foo.argb.r000 with foo.a000
Ethan Nicholase6592142020-09-08 10:22:09 -04001078 if (s.fBase->kind() == Expression::Kind::kSwizzle) {
John Stilesa5a97b42020-08-18 11:19:07 -04001079 Swizzle& base = s.fBase->as<Swizzle>();
Ethan Nicholas409f6f02019-09-17 12:34:39 -04001080 std::vector<int> final;
1081 for (int c : s.fComponents) {
Brian Osman25647672020-09-15 15:16:56 -04001082 final.push_back(base.fComponents[c]);
Ethan Nicholas409f6f02019-09-17 12:34:39 -04001083 }
1084 *outUpdated = true;
1085 std::unique_ptr<Expression> replacement(new Swizzle(*fContext, base.fBase->clone(),
1086 std::move(final)));
1087 if (!try_replace_expression(&b, iter, &replacement)) {
1088 *outNeedsRescan = true;
1089 return;
1090 }
John Stiles70025e52020-09-28 16:08:58 -04001091 SkASSERT((*iter)->isExpression());
Ethan Nicholas409f6f02019-09-17 12:34:39 -04001092 }
John Stiles30212b72020-06-11 17:55:07 -04001093 break;
Ethan Nicholascb670962017-04-20 19:31:52 -04001094 }
1095 default:
1096 break;
1097 }
1098}
1099
John Stiles92219b42020-06-15 12:32:24 -04001100// Returns true if this statement could potentially execute a break at the current level. We ignore
1101// nested loops and switches, since any breaks inside of them will merely break the loop / switch.
John Stilesb92641c2020-08-31 18:09:01 -04001102static bool contains_conditional_break(Statement& stmt) {
1103 class ContainsConditionalBreak : public ProgramVisitor {
1104 public:
1105 bool visitStatement(const Statement& stmt) override {
Ethan Nicholase6592142020-09-08 10:22:09 -04001106 switch (stmt.kind()) {
1107 case Statement::Kind::kBlock:
John Stilesb92641c2020-08-31 18:09:01 -04001108 return this->INHERITED::visitStatement(stmt);
1109
Ethan Nicholase6592142020-09-08 10:22:09 -04001110 case Statement::Kind::kBreak:
John Stilesb92641c2020-08-31 18:09:01 -04001111 return fInConditional > 0;
1112
Ethan Nicholase6592142020-09-08 10:22:09 -04001113 case Statement::Kind::kIf: {
John Stilesb92641c2020-08-31 18:09:01 -04001114 ++fInConditional;
1115 bool result = this->INHERITED::visitStatement(stmt);
1116 --fInConditional;
1117 return result;
1118 }
1119
1120 default:
1121 return false;
1122 }
1123 }
1124
1125 int fInConditional = 0;
1126 using INHERITED = ProgramVisitor;
1127 };
1128
1129 return ContainsConditionalBreak{}.visitStatement(stmt);
John Stiles92219b42020-06-15 12:32:24 -04001130}
1131
Ethan Nicholas5005a222018-08-24 13:06:27 -04001132// returns true if this statement definitely executes a break at the current level (we ignore
1133// nested loops and switches, since any breaks inside of them will merely break the loop / switch)
John Stilesb92641c2020-08-31 18:09:01 -04001134static bool contains_unconditional_break(Statement& stmt) {
1135 class ContainsUnconditionalBreak : public ProgramVisitor {
1136 public:
1137 bool visitStatement(const Statement& stmt) override {
Ethan Nicholase6592142020-09-08 10:22:09 -04001138 switch (stmt.kind()) {
1139 case Statement::Kind::kBlock:
John Stilesb92641c2020-08-31 18:09:01 -04001140 return this->INHERITED::visitStatement(stmt);
1141
Ethan Nicholase6592142020-09-08 10:22:09 -04001142 case Statement::Kind::kBreak:
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001143 return true;
John Stilesb92641c2020-08-31 18:09:01 -04001144
1145 default:
1146 return false;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001147 }
John Stilesb92641c2020-08-31 18:09:01 -04001148 }
John Stiles92219b42020-06-15 12:32:24 -04001149
John Stilesb92641c2020-08-31 18:09:01 -04001150 using INHERITED = ProgramVisitor;
1151 };
John Stiles92219b42020-06-15 12:32:24 -04001152
John Stilesb92641c2020-08-31 18:09:01 -04001153 return ContainsUnconditionalBreak{}.visitStatement(stmt);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001154}
1155
John Stiles92219b42020-06-15 12:32:24 -04001156static void move_all_but_break(std::unique_ptr<Statement>& stmt,
1157 std::vector<std::unique_ptr<Statement>>* target) {
Ethan Nicholase6592142020-09-08 10:22:09 -04001158 switch (stmt->kind()) {
1159 case Statement::Kind::kBlock: {
John Stiles92219b42020-06-15 12:32:24 -04001160 // Recurse into the block.
1161 Block& block = static_cast<Block&>(*stmt);
1162
1163 std::vector<std::unique_ptr<Statement>> blockStmts;
Ethan Nicholas7bd60432020-09-25 14:31:59 -04001164 blockStmts.reserve(block.children().size());
1165 for (std::unique_ptr<Statement>& stmt : block.children()) {
1166 move_all_but_break(stmt, &blockStmts);
Ethan Nicholas739e1ca2020-06-11 12:16:14 -04001167 }
John Stiles92219b42020-06-15 12:32:24 -04001168
1169 target->push_back(std::make_unique<Block>(block.fOffset, std::move(blockStmts),
Ethan Nicholas7bd60432020-09-25 14:31:59 -04001170 block.symbolTable(), block.isScope()));
Ethan Nicholas739e1ca2020-06-11 12:16:14 -04001171 break;
John Stiles92219b42020-06-15 12:32:24 -04001172 }
1173
Ethan Nicholase6592142020-09-08 10:22:09 -04001174 case Statement::Kind::kBreak:
John Stiles92219b42020-06-15 12:32:24 -04001175 // Do not append a break to the target.
1176 break;
1177
Ethan Nicholas739e1ca2020-06-11 12:16:14 -04001178 default:
John Stiles92219b42020-06-15 12:32:24 -04001179 // Append normal statements to the target.
1180 target->push_back(std::move(stmt));
1181 break;
Ethan Nicholas739e1ca2020-06-11 12:16:14 -04001182 }
1183}
1184
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001185// Returns a block containing all of the statements that will be run if the given case matches
1186// (which, owing to the statements being owned by unique_ptrs, means the switch itself will be
1187// broken by this call and must then be discarded).
1188// Returns null (and leaves the switch unmodified) if no such simple reduction is possible, such as
1189// when break statements appear inside conditionals.
John Stiles92219b42020-06-15 12:32:24 -04001190static std::unique_ptr<Statement> block_for_case(SwitchStatement* switchStatement,
1191 SwitchCase* caseToCapture) {
1192 // We have to be careful to not move any of the pointers until after we're sure we're going to
1193 // succeed, so before we make any changes at all, we check the switch-cases to decide on a plan
1194 // of action. First, find the switch-case we are interested in.
1195 auto iter = switchStatement->fCases.begin();
1196 for (; iter != switchStatement->fCases.end(); ++iter) {
1197 if (iter->get() == caseToCapture) {
1198 break;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001199 }
John Stiles92219b42020-06-15 12:32:24 -04001200 }
1201
1202 // Next, walk forward through the rest of the switch. If we find a conditional break, we're
1203 // stuck and can't simplify at all. If we find an unconditional break, we have a range of
1204 // statements that we can use for simplification.
1205 auto startIter = iter;
1206 Statement* unconditionalBreakStmt = nullptr;
1207 for (; iter != switchStatement->fCases.end(); ++iter) {
1208 for (std::unique_ptr<Statement>& stmt : (*iter)->fStatements) {
1209 if (contains_conditional_break(*stmt)) {
1210 // We can't reduce switch-cases to a block when they have conditional breaks.
1211 return nullptr;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001212 }
John Stiles92219b42020-06-15 12:32:24 -04001213
1214 if (contains_unconditional_break(*stmt)) {
1215 // We found an unconditional break. We can use this block, but we need to strip
1216 // out the break statement.
1217 unconditionalBreakStmt = stmt.get();
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001218 break;
1219 }
1220 }
John Stiles92219b42020-06-15 12:32:24 -04001221
1222 if (unconditionalBreakStmt != nullptr) {
1223 break;
1224 }
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001225 }
John Stiles92219b42020-06-15 12:32:24 -04001226
1227 // We fell off the bottom of the switch or encountered a break. We know the range of statements
1228 // that we need to move over, and we know it's safe to do so.
1229 std::vector<std::unique_ptr<Statement>> caseStmts;
1230
1231 // We can move over most of the statements as-is.
1232 while (startIter != iter) {
1233 for (std::unique_ptr<Statement>& stmt : (*startIter)->fStatements) {
1234 caseStmts.push_back(std::move(stmt));
1235 }
1236 ++startIter;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001237 }
John Stiles92219b42020-06-15 12:32:24 -04001238
1239 // If we found an unconditional break at the end, we need to move what we can while avoiding
1240 // that break.
1241 if (unconditionalBreakStmt != nullptr) {
1242 for (std::unique_ptr<Statement>& stmt : (*startIter)->fStatements) {
1243 if (stmt.get() == unconditionalBreakStmt) {
1244 move_all_but_break(stmt, &caseStmts);
1245 unconditionalBreakStmt = nullptr;
1246 break;
1247 }
1248
1249 caseStmts.push_back(std::move(stmt));
1250 }
1251 }
1252
1253 SkASSERT(unconditionalBreakStmt == nullptr); // Verify that we fixed the unconditional break.
1254
1255 // Return our newly-synthesized block.
1256 return std::make_unique<Block>(/*offset=*/-1, std::move(caseStmts), switchStatement->fSymbols);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001257}
1258
Ethan Nicholascb670962017-04-20 19:31:52 -04001259void Compiler::simplifyStatement(DefinitionMap& definitions,
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001260 BasicBlock& b,
1261 std::vector<BasicBlock::Node>::iterator* iter,
1262 std::unordered_set<const Variable*>* undefinedVariables,
1263 bool* outUpdated,
1264 bool* outNeedsRescan) {
Ethan Nicholascb670962017-04-20 19:31:52 -04001265 Statement* stmt = (*iter)->statement()->get();
Ethan Nicholase6592142020-09-08 10:22:09 -04001266 switch (stmt->kind()) {
1267 case Statement::Kind::kVarDeclaration: {
John Stilesa5a97b42020-08-18 11:19:07 -04001268 const auto& varDecl = stmt->as<VarDeclaration>();
Ethan Nicholas82a62d22017-11-07 14:42:10 +00001269 if (varDecl.fVar->dead() &&
1270 (!varDecl.fValue ||
1271 !varDecl.fValue->hasSideEffects())) {
1272 if (varDecl.fValue) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001273 SkASSERT((*iter)->statement()->get() == stmt);
Ethan Nicholas82a62d22017-11-07 14:42:10 +00001274 if (!b.tryRemoveExpressionBefore(iter, varDecl.fValue.get())) {
1275 *outNeedsRescan = true;
Ethan Nicholascb670962017-04-20 19:31:52 -04001276 }
Ethan Nicholascb670962017-04-20 19:31:52 -04001277 }
Ethan Nicholascb670962017-04-20 19:31:52 -04001278 (*iter)->setStatement(std::unique_ptr<Statement>(new Nop()));
Ethan Nicholas82a62d22017-11-07 14:42:10 +00001279 *outUpdated = true;
Ethan Nicholascb670962017-04-20 19:31:52 -04001280 }
1281 break;
1282 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001283 case Statement::Kind::kIf: {
John Stilesa5a97b42020-08-18 11:19:07 -04001284 IfStatement& i = stmt->as<IfStatement>();
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001285 if (i.test()->kind() == Expression::Kind::kBoolLiteral) {
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001286 // constant if, collapse down to a single branch
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001287 if (i.test()->as<BoolLiteral>().value()) {
1288 SkASSERT(i.ifTrue());
1289 (*iter)->setStatement(std::move(i.ifTrue()));
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001290 } else {
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001291 if (i.ifFalse()) {
1292 (*iter)->setStatement(std::move(i.ifFalse()));
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001293 } else {
1294 (*iter)->setStatement(std::unique_ptr<Statement>(new Nop()));
1295 }
1296 }
1297 *outUpdated = true;
1298 *outNeedsRescan = true;
1299 break;
1300 }
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001301 if (i.ifFalse() && i.ifFalse()->isEmpty()) {
Ethan Nicholascb670962017-04-20 19:31:52 -04001302 // else block doesn't do anything, remove it
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001303 i.ifFalse().reset();
Ethan Nicholascb670962017-04-20 19:31:52 -04001304 *outUpdated = true;
1305 *outNeedsRescan = true;
1306 }
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001307 if (!i.ifFalse() && i.ifTrue()->isEmpty()) {
Ethan Nicholascb670962017-04-20 19:31:52 -04001308 // if block doesn't do anything, no else block
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001309 if (i.test()->hasSideEffects()) {
Ethan Nicholascb670962017-04-20 19:31:52 -04001310 // test has side effects, keep it
1311 (*iter)->setStatement(std::unique_ptr<Statement>(
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001312 new ExpressionStatement(std::move(i.test()))));
Ethan Nicholascb670962017-04-20 19:31:52 -04001313 } else {
1314 // no if, no else, no test side effects, kill the whole if
1315 // statement
1316 (*iter)->setStatement(std::unique_ptr<Statement>(new Nop()));
1317 }
1318 *outUpdated = true;
1319 *outNeedsRescan = true;
1320 }
1321 break;
1322 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001323 case Statement::Kind::kSwitch: {
John Stilesa5a97b42020-08-18 11:19:07 -04001324 SwitchStatement& s = stmt->as<SwitchStatement>();
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001325 int64_t switchValue;
1326 if (fIRGenerator->getConstantInt(*s.fValue, &switchValue)) {
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001327 // switch is constant, replace it with the case that matches
1328 bool found = false;
1329 SwitchCase* defaultCase = nullptr;
John Stiles9d944232020-08-19 09:56:49 -04001330 for (const std::unique_ptr<SwitchCase>& c : s.fCases) {
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001331 if (!c->fValue) {
1332 defaultCase = c.get();
1333 continue;
1334 }
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001335 int64_t caseValue;
1336 SkAssertResult(fIRGenerator->getConstantInt(*c->fValue, &caseValue));
1337 if (caseValue == switchValue) {
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001338 std::unique_ptr<Statement> newBlock = block_for_case(&s, c.get());
1339 if (newBlock) {
1340 (*iter)->setStatement(std::move(newBlock));
John Stiles9d944232020-08-19 09:56:49 -04001341 found = true;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001342 break;
1343 } else {
Ethan Nicholas6e1cbc02017-07-14 10:12:15 -04001344 if (s.fIsStatic && !(fFlags & kPermitInvalidStaticTests_Flag)) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001345 this->error(s.fOffset,
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001346 "static switch contains non-static conditional break");
1347 s.fIsStatic = false;
1348 }
1349 return; // can't simplify
1350 }
1351 }
1352 }
1353 if (!found) {
1354 // no matching case. use default if it exists, or kill the whole thing
1355 if (defaultCase) {
1356 std::unique_ptr<Statement> newBlock = block_for_case(&s, defaultCase);
1357 if (newBlock) {
1358 (*iter)->setStatement(std::move(newBlock));
1359 } else {
Ethan Nicholas6e1cbc02017-07-14 10:12:15 -04001360 if (s.fIsStatic && !(fFlags & kPermitInvalidStaticTests_Flag)) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001361 this->error(s.fOffset,
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001362 "static switch contains non-static conditional break");
1363 s.fIsStatic = false;
1364 }
1365 return; // can't simplify
1366 }
1367 } else {
1368 (*iter)->setStatement(std::unique_ptr<Statement>(new Nop()));
1369 }
1370 }
1371 *outUpdated = true;
1372 *outNeedsRescan = true;
1373 }
1374 break;
1375 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001376 case Statement::Kind::kExpression: {
John Stilesa5a97b42020-08-18 11:19:07 -04001377 ExpressionStatement& e = stmt->as<ExpressionStatement>();
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001378 SkASSERT((*iter)->statement()->get() == &e);
Ethan Nicholasd503a5a2020-09-30 09:29:55 -04001379 if (!e.expression()->hasSideEffects()) {
Ethan Nicholascb670962017-04-20 19:31:52 -04001380 // Expression statement with no side effects, kill it
Ethan Nicholasd503a5a2020-09-30 09:29:55 -04001381 if (!b.tryRemoveExpressionBefore(iter, e.expression().get())) {
Ethan Nicholascb670962017-04-20 19:31:52 -04001382 *outNeedsRescan = true;
1383 }
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001384 SkASSERT((*iter)->statement()->get() == stmt);
Ethan Nicholascb670962017-04-20 19:31:52 -04001385 (*iter)->setStatement(std::unique_ptr<Statement>(new Nop()));
1386 *outUpdated = true;
1387 }
1388 break;
1389 }
1390 default:
1391 break;
1392 }
1393}
1394
John Stiles0cc193a2020-09-09 09:39:34 -04001395bool Compiler::scanCFG(FunctionDefinition& f) {
1396 bool madeChanges = false;
1397
Ethan Nicholascb670962017-04-20 19:31:52 -04001398 CFG cfg = CFGGenerator().getCFG(f);
1399 this->computeDataFlow(&cfg);
ethannicholas22f939e2016-10-13 13:25:34 -07001400
1401 // check for unreachable code
1402 for (size_t i = 0; i < cfg.fBlocks.size(); i++) {
John Stiles0cc193a2020-09-09 09:39:34 -04001403 const BasicBlock& block = cfg.fBlocks[i];
John Stiles61e75e32020-10-01 15:42:37 -04001404 if (i != cfg.fStart && !block.fIsReachable && block.fNodes.size()) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001405 int offset;
John Stiles0cc193a2020-09-09 09:39:34 -04001406 const BasicBlock::Node& node = block.fNodes[0];
John Stiles70025e52020-09-28 16:08:58 -04001407 if (node.isStatement()) {
1408 offset = (*node.statement())->fOffset;
1409 } else {
1410 offset = (*node.expression())->fOffset;
1411 if ((*node.expression())->is<BoolLiteral>()) {
1412 // Function inlining can generate do { ... } while(false) loops which always
1413 // break, so the boolean condition is considered unreachable. Since not being
1414 // able to reach a literal is a non-issue in the first place, we don't report an
1415 // error in this case.
1416 continue;
1417 }
Ethan Nicholas86a43402017-01-19 13:32:00 -05001418 }
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001419 this->error(offset, String("unreachable"));
ethannicholas22f939e2016-10-13 13:25:34 -07001420 }
1421 }
1422 if (fErrorCount) {
John Stiles0cc193a2020-09-09 09:39:34 -04001423 return madeChanges;
ethannicholas22f939e2016-10-13 13:25:34 -07001424 }
1425
Ethan Nicholascb670962017-04-20 19:31:52 -04001426 // check for dead code & undefined variables, perform constant propagation
1427 std::unordered_set<const Variable*> undefinedVariables;
1428 bool updated;
1429 bool needsRescan = false;
1430 do {
1431 if (needsRescan) {
1432 cfg = CFGGenerator().getCFG(f);
1433 this->computeDataFlow(&cfg);
1434 needsRescan = false;
Ethan Nicholas113628d2017-02-02 16:11:39 -05001435 }
Ethan Nicholascb670962017-04-20 19:31:52 -04001436
1437 updated = false;
Ethan Nicholas1de14812020-06-19 15:32:49 -04001438 bool first = true;
Ethan Nicholascb670962017-04-20 19:31:52 -04001439 for (BasicBlock& b : cfg.fBlocks) {
John Stiles61e75e32020-10-01 15:42:37 -04001440 if (!first && !b.fIsReachable) {
Ethan Nicholas1de14812020-06-19 15:32:49 -04001441 // Block was reachable before optimization, but has since become unreachable. In
1442 // addition to being dead code, it's broken - since control flow can't reach it, no
1443 // prior variable definitions can reach it, and therefore variables might look to
Brian Osmanc0213602020-10-06 14:43:32 -04001444 // have not been properly assigned. Kill it by replacing all statements with Nops.
Ethan Nicholas1de14812020-06-19 15:32:49 -04001445 for (BasicBlock::Node& node : b.fNodes) {
John Stiles70025e52020-09-28 16:08:58 -04001446 if (node.isStatement() && !(*node.statement())->is<Nop>()) {
John Stiles0cc193a2020-09-09 09:39:34 -04001447 node.setStatement(std::make_unique<Nop>());
1448 madeChanges = true;
Ethan Nicholas1de14812020-06-19 15:32:49 -04001449 }
1450 }
1451 continue;
1452 }
1453 first = false;
Ethan Nicholascb670962017-04-20 19:31:52 -04001454 DefinitionMap definitions = b.fBefore;
1455
1456 for (auto iter = b.fNodes.begin(); iter != b.fNodes.end() && !needsRescan; ++iter) {
John Stiles70025e52020-09-28 16:08:58 -04001457 if (iter->isExpression()) {
Ethan Nicholascb670962017-04-20 19:31:52 -04001458 this->simplifyExpression(definitions, b, &iter, &undefinedVariables, &updated,
1459 &needsRescan);
1460 } else {
1461 this->simplifyStatement(definitions, b, &iter, &undefinedVariables, &updated,
John Stiles0cc193a2020-09-09 09:39:34 -04001462 &needsRescan);
Ethan Nicholascb670962017-04-20 19:31:52 -04001463 }
Ethan Nicholas4b330df2017-05-17 10:52:55 -04001464 if (needsRescan) {
1465 break;
1466 }
Ethan Nicholascb670962017-04-20 19:31:52 -04001467 this->addDefinitions(*iter, &definitions);
1468 }
Brian Osman01a3eb42020-09-14 11:32:49 -04001469
1470 if (needsRescan) {
1471 break;
1472 }
Ethan Nicholascb670962017-04-20 19:31:52 -04001473 }
John Stiles0cc193a2020-09-09 09:39:34 -04001474 madeChanges |= updated;
Ethan Nicholascb670962017-04-20 19:31:52 -04001475 } while (updated);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001476 SkASSERT(!needsRescan);
ethannicholas22f939e2016-10-13 13:25:34 -07001477
Ethan Nicholas91a10532017-06-22 11:24:38 -04001478 // verify static ifs & switches, clean up dead variable decls
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001479 for (BasicBlock& b : cfg.fBlocks) {
Ethan Nicholas91a10532017-06-22 11:24:38 -04001480 for (auto iter = b.fNodes.begin(); iter != b.fNodes.end() && !needsRescan;) {
John Stiles70025e52020-09-28 16:08:58 -04001481 if (iter->isStatement()) {
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001482 const Statement& s = **iter->statement();
Ethan Nicholase6592142020-09-08 10:22:09 -04001483 switch (s.kind()) {
1484 case Statement::Kind::kIf:
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001485 if (s.as<IfStatement>().isStatic() &&
Ethan Nicholas6e1cbc02017-07-14 10:12:15 -04001486 !(fFlags & kPermitInvalidStaticTests_Flag)) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001487 this->error(s.fOffset, "static if has non-static test");
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001488 }
Ethan Nicholas91a10532017-06-22 11:24:38 -04001489 ++iter;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001490 break;
Ethan Nicholase6592142020-09-08 10:22:09 -04001491 case Statement::Kind::kSwitch:
John Stilesa5a97b42020-08-18 11:19:07 -04001492 if (s.as<SwitchStatement>().fIsStatic &&
John Stiles0cc193a2020-09-09 09:39:34 -04001493 !(fFlags & kPermitInvalidStaticTests_Flag)) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001494 this->error(s.fOffset, "static switch has non-static test");
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001495 }
Ethan Nicholas91a10532017-06-22 11:24:38 -04001496 ++iter;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001497 break;
1498 default:
Ethan Nicholas91a10532017-06-22 11:24:38 -04001499 ++iter;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001500 break;
1501 }
Ethan Nicholas91a10532017-06-22 11:24:38 -04001502 } else {
1503 ++iter;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001504 }
1505 }
1506 }
1507
ethannicholas22f939e2016-10-13 13:25:34 -07001508 // check for missing return
Ethan Nicholased84b732020-10-08 11:45:44 -04001509 if (f.fDeclaration.returnType() != *fContext->fVoid_Type) {
John Stiles61e75e32020-10-01 15:42:37 -04001510 if (cfg.fBlocks[cfg.fExit].fIsReachable) {
Ethan Nicholase2c49992020-10-05 11:49:11 -04001511 this->error(f.fOffset, String("function '" + String(f.fDeclaration.name()) +
Ethan Nicholasdb80f692019-11-22 14:06:12 -05001512 "' can exit without returning a value"));
ethannicholas22f939e2016-10-13 13:25:34 -07001513 }
1514 }
John Stiles0cc193a2020-09-09 09:39:34 -04001515
1516 return madeChanges;
ethannicholas22f939e2016-10-13 13:25:34 -07001517}
1518
Brian Osman32d53552020-09-23 13:55:20 -04001519std::unique_ptr<Program> Compiler::convertProgram(
1520 Program::Kind kind,
1521 String text,
1522 const Program::Settings& settings,
1523 const std::vector<std::unique_ptr<ExternalValue>>* externalValues) {
1524 SkASSERT(!externalValues || (kind == Program::kGeneric_Kind));
Ethan Nicholas91164d12019-05-15 15:29:54 -04001525
ethannicholasb3058bd2016-07-01 08:22:01 -07001526 fErrorText = "";
1527 fErrorCount = 0;
Brian Osman3d87e9f2020-10-08 11:50:22 -04001528 fInliner.reset(fContext.get(), fIRGenerator->fModifiers.get(), &settings);
Brian Osman88cda172020-10-09 12:05:16 -04001529
1530 // Not using AutoSource, because caller is likely to call errorText() if we fail to compile
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001531 std::unique_ptr<String> textPtr(new String(std::move(text)));
1532 fSource = textPtr.get();
Brian Osman88cda172020-10-09 12:05:16 -04001533
1534 const ParsedModule& baseModule = this->moduleForProgramKind(kind);
1535
1536 IRGenerator::IRBundle ir =
1537 fIRGenerator->convertProgram(kind, &settings, baseModule, /*isBuiltinCode=*/false,
1538 textPtr->c_str(), textPtr->size(), externalValues);
John Stilesfbd050b2020-08-03 13:21:46 -04001539 auto result = std::make_unique<Program>(kind,
1540 std::move(textPtr),
1541 settings,
1542 fContext,
Brian Osman88cda172020-10-09 12:05:16 -04001543 std::move(ir.fElements),
1544 std::move(ir.fModifiers),
1545 std::move(ir.fSymbolTable),
1546 ir.fInputs);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001547 if (fErrorCount) {
1548 return nullptr;
1549 }
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001550 if (settings.fOptimize && !this->optimize(*result)) {
1551 return nullptr;
1552 }
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001553 return result;
1554}
1555
Ethan Nicholas00543112018-07-31 09:44:36 -04001556bool Compiler::optimize(Program& program) {
1557 SkASSERT(!fErrorCount);
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001558 fIRGenerator->fKind = program.fKind;
1559 fIRGenerator->fSettings = &program.fSettings;
John Stiles7954d6c2020-09-01 10:53:02 -04001560
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001561 while (fErrorCount == 0) {
1562 bool madeChanges = false;
John Stiles7954d6c2020-09-01 10:53:02 -04001563
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001564 // Scan and optimize based on the control-flow graph for each function.
Brian Osman1179fcf2020-10-08 16:04:40 -04001565 for (const auto& element : program.elements()) {
1566 if (element->is<FunctionDefinition>()) {
1567 madeChanges |= this->scanCFG(element->as<FunctionDefinition>());
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001568 }
1569 }
1570
1571 // Perform inline-candidate analysis and inline any functions deemed suitable.
John Stiles881a10c2020-09-19 10:13:24 -04001572 madeChanges |= fInliner.analyze(program);
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001573
1574 // Remove dead functions. We wait until after analysis so that we still report errors,
1575 // even in unused code.
1576 if (program.fSettings.fRemoveDeadFunctions) {
1577 program.fElements.erase(
1578 std::remove_if(program.fElements.begin(),
1579 program.fElements.end(),
1580 [&](const std::unique_ptr<ProgramElement>& element) {
1581 if (!element->is<FunctionDefinition>()) {
1582 return false;
1583 }
1584 const auto& fn = element->as<FunctionDefinition>();
Ethan Nicholased84b732020-10-08 11:45:44 -04001585 bool dead = fn.fDeclaration.callCount() == 0 &&
Ethan Nicholase2c49992020-10-05 11:49:11 -04001586 fn.fDeclaration.name() != "main";
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001587 madeChanges |= dead;
1588 return dead;
1589 }),
1590 program.fElements.end());
1591 }
1592
1593 if (program.fKind != Program::kFragmentProcessor_Kind) {
Brian Osmanc0213602020-10-06 14:43:32 -04001594 // Remove declarations of dead global variables
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001595 program.fElements.erase(
1596 std::remove_if(program.fElements.begin(), program.fElements.end(),
1597 [&](const std::unique_ptr<ProgramElement>& element) {
Brian Osmanc0213602020-10-06 14:43:32 -04001598 if (!element->is<GlobalVarDeclaration>()) {
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001599 return false;
1600 }
Brian Osmanc0213602020-10-06 14:43:32 -04001601 const auto& varDecl = element->as<GlobalVarDeclaration>();
1602 bool dead = varDecl.fDecl->fVar->dead();
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001603 madeChanges |= dead;
1604 return dead;
1605 }),
1606 program.fElements.end());
1607 }
John Stiles73a6bff2020-09-09 13:40:37 -04001608
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001609 if (!madeChanges) {
1610 break;
Ethan Nicholas0dc80872019-02-08 15:46:24 -05001611 }
Ethan Nicholas00543112018-07-31 09:44:36 -04001612 }
1613 return fErrorCount == 0;
1614}
1615
Brian Osmanfb32ddf2019-06-18 10:14:20 -04001616#if defined(SKSL_STANDALONE) || SK_SUPPORT_GPU
1617
Ethan Nicholas00543112018-07-31 09:44:36 -04001618bool Compiler::toSPIRV(Program& program, OutputStream& out) {
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001619#ifdef SK_ENABLE_SPIRV_VALIDATION
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001620 StringStream buffer;
Brian Osman88cda172020-10-09 12:05:16 -04001621 AutoSource as(this, program.fSource.get());
Brian Osman8b43dad2020-10-09 13:31:42 -04001622 SPIRVCodeGenerator cg(fContext.get(), &program, this, &buffer);
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001623 bool result = cg.generateCode();
1624 if (result) {
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001625 spvtools::SpirvTools tools(SPV_ENV_VULKAN_1_0);
Ethan Nicholas762466e2017-06-29 10:03:38 -04001626 const String& data = buffer.str();
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001627 SkASSERT(0 == data.size() % 4);
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001628 auto dumpmsg = [](spv_message_level_t, const char*, const spv_position_t&, const char* m) {
1629 SkDebugf("SPIR-V validation error: %s\n", m);
1630 };
1631 tools.SetMessageConsumer(dumpmsg);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001632 // Verify that the SPIR-V we produced is valid. If this SkASSERT fails, check the logs prior
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001633 // to the failure to see the validation errors.
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001634 SkAssertResult(tools.Validate((const uint32_t*) data.c_str(), data.size() / 4));
Ethan Nicholas762466e2017-06-29 10:03:38 -04001635 out.write(data.c_str(), data.size());
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001636 }
1637#else
Brian Osman88cda172020-10-09 12:05:16 -04001638 AutoSource as(this, program.fSource.get());
Brian Osman8b43dad2020-10-09 13:31:42 -04001639 SPIRVCodeGenerator cg(fContext.get(), &program, this, &out);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001640 bool result = cg.generateCode();
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001641#endif
Ethan Nicholasce33f102016-12-09 17:22:59 -05001642 return result;
1643}
1644
Ethan Nicholas00543112018-07-31 09:44:36 -04001645bool Compiler::toSPIRV(Program& program, String* out) {
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001646 StringStream buffer;
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001647 bool result = this->toSPIRV(program, buffer);
1648 if (result) {
Ethan Nicholas762466e2017-06-29 10:03:38 -04001649 *out = buffer.str();
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001650 }
1651 return result;
1652}
1653
Ethan Nicholas00543112018-07-31 09:44:36 -04001654bool Compiler::toGLSL(Program& program, OutputStream& out) {
Brian Osman88cda172020-10-09 12:05:16 -04001655 AutoSource as(this, program.fSource.get());
Ethan Nicholas26a9aad2018-03-27 14:10:52 -04001656 GLSLCodeGenerator cg(fContext.get(), &program, this, &out);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001657 bool result = cg.generateCode();
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001658 return result;
1659}
1660
Ethan Nicholas00543112018-07-31 09:44:36 -04001661bool Compiler::toGLSL(Program& program, String* out) {
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001662 StringStream buffer;
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001663 bool result = this->toGLSL(program, buffer);
1664 if (result) {
Ethan Nicholas762466e2017-06-29 10:03:38 -04001665 *out = buffer.str();
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001666 }
1667 return result;
1668}
1669
Brian Osmanc0243912020-02-19 15:35:26 -05001670bool Compiler::toHLSL(Program& program, String* out) {
1671 String spirv;
1672 if (!this->toSPIRV(program, &spirv)) {
1673 return false;
1674 }
1675
1676 return SPIRVtoHLSL(spirv, out);
1677}
1678
Ethan Nicholas00543112018-07-31 09:44:36 -04001679bool Compiler::toMetal(Program& program, OutputStream& out) {
Ethan Nicholas26a9aad2018-03-27 14:10:52 -04001680 MetalCodeGenerator cg(fContext.get(), &program, this, &out);
Ethan Nicholascc305772017-10-13 16:17:45 -04001681 bool result = cg.generateCode();
Ethan Nicholascc305772017-10-13 16:17:45 -04001682 return result;
1683}
1684
Ethan Nicholas00543112018-07-31 09:44:36 -04001685bool Compiler::toMetal(Program& program, String* out) {
Timothy Liangb8eeb802018-07-23 16:46:16 -04001686 StringStream buffer;
1687 bool result = this->toMetal(program, buffer);
1688 if (result) {
1689 *out = buffer.str();
1690 }
1691 return result;
1692}
1693
Greg Daniela28ea672020-09-25 11:12:56 -04001694#if defined(SKSL_STANDALONE) || GR_TEST_UTILS
Ethan Nicholas00543112018-07-31 09:44:36 -04001695bool Compiler::toCPP(Program& program, String name, OutputStream& out) {
Brian Osman88cda172020-10-09 12:05:16 -04001696 AutoSource as(this, program.fSource.get());
Ethan Nicholas26a9aad2018-03-27 14:10:52 -04001697 CPPCodeGenerator cg(fContext.get(), &program, this, name, &out);
Ethan Nicholas762466e2017-06-29 10:03:38 -04001698 bool result = cg.generateCode();
Ethan Nicholas762466e2017-06-29 10:03:38 -04001699 return result;
1700}
1701
Ethan Nicholas00543112018-07-31 09:44:36 -04001702bool Compiler::toH(Program& program, String name, OutputStream& out) {
Brian Osman88cda172020-10-09 12:05:16 -04001703 AutoSource as(this, program.fSource.get());
Ethan Nicholas26a9aad2018-03-27 14:10:52 -04001704 HCodeGenerator cg(fContext.get(), &program, this, name, &out);
Ethan Nicholas762466e2017-06-29 10:03:38 -04001705 bool result = cg.generateCode();
Ethan Nicholas00543112018-07-31 09:44:36 -04001706 return result;
1707}
Greg Daniela28ea672020-09-25 11:12:56 -04001708#endif // defined(SKSL_STANDALONE) || GR_TEST_UTILS
Ethan Nicholas00543112018-07-31 09:44:36 -04001709
Ethan Nicholas2a479a52020-08-18 16:29:45 -04001710#endif // defined(SKSL_STANDALONE) || SK_SUPPORT_GPU
Brian Osman2e29ab52019-09-20 12:19:11 -04001711
1712#if !defined(SKSL_STANDALONE) && SK_SUPPORT_GPU
Brian Osmana4b91692020-08-10 14:26:16 -04001713bool Compiler::toPipelineStage(Program& program, PipelineStageArgs* outArgs) {
Brian Osman88cda172020-10-09 12:05:16 -04001714 AutoSource as(this, program.fSource.get());
Ethan Nicholas00543112018-07-31 09:44:36 -04001715 StringStream buffer;
Brian Osman300fe1d2020-01-23 15:42:43 -05001716 PipelineStageCodeGenerator cg(fContext.get(), &program, this, &buffer, outArgs);
Ethan Nicholas00543112018-07-31 09:44:36 -04001717 bool result = cg.generateCode();
Ethan Nicholas00543112018-07-31 09:44:36 -04001718 if (result) {
Brian Osman107c6662019-12-30 15:02:30 -05001719 outArgs->fCode = buffer.str();
Ethan Nicholas00543112018-07-31 09:44:36 -04001720 }
Ethan Nicholas762466e2017-06-29 10:03:38 -04001721 return result;
1722}
Brian Osmanfb32ddf2019-06-18 10:14:20 -04001723#endif
1724
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001725std::unique_ptr<ByteCode> Compiler::toByteCode(Program& program) {
Mike Klein853d4ed2020-08-20 00:41:00 +00001726#if defined(SK_ENABLE_SKSL_INTERPRETER)
Brian Osman88cda172020-10-09 12:05:16 -04001727 AutoSource as(this, program.fSource.get());
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001728 std::unique_ptr<ByteCode> result(new ByteCode());
Brian Osmanb08cc022020-04-02 11:38:40 -04001729 ByteCodeGenerator cg(fContext.get(), &program, this, result.get());
1730 bool success = cg.generateCode();
Brian Osmanb08cc022020-04-02 11:38:40 -04001731 if (success) {
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001732 return result;
1733 }
Mike Klein853d4ed2020-08-20 00:41:00 +00001734#else
1735 ABORT("ByteCode interpreter not enabled");
1736#endif
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001737 return nullptr;
1738}
1739
Brian Osman401a0092020-09-10 14:47:24 -04001740const char* Compiler::OperatorName(Token::Kind op) {
1741 switch (op) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001742 case Token::Kind::TK_PLUS: return "+";
1743 case Token::Kind::TK_MINUS: return "-";
1744 case Token::Kind::TK_STAR: return "*";
1745 case Token::Kind::TK_SLASH: return "/";
1746 case Token::Kind::TK_PERCENT: return "%";
1747 case Token::Kind::TK_SHL: return "<<";
1748 case Token::Kind::TK_SHR: return ">>";
1749 case Token::Kind::TK_LOGICALNOT: return "!";
1750 case Token::Kind::TK_LOGICALAND: return "&&";
1751 case Token::Kind::TK_LOGICALOR: return "||";
1752 case Token::Kind::TK_LOGICALXOR: return "^^";
1753 case Token::Kind::TK_BITWISENOT: return "~";
1754 case Token::Kind::TK_BITWISEAND: return "&";
1755 case Token::Kind::TK_BITWISEOR: return "|";
1756 case Token::Kind::TK_BITWISEXOR: return "^";
1757 case Token::Kind::TK_EQ: return "=";
1758 case Token::Kind::TK_EQEQ: return "==";
1759 case Token::Kind::TK_NEQ: return "!=";
1760 case Token::Kind::TK_LT: return "<";
1761 case Token::Kind::TK_GT: return ">";
1762 case Token::Kind::TK_LTEQ: return "<=";
1763 case Token::Kind::TK_GTEQ: return ">=";
1764 case Token::Kind::TK_PLUSEQ: return "+=";
1765 case Token::Kind::TK_MINUSEQ: return "-=";
1766 case Token::Kind::TK_STAREQ: return "*=";
1767 case Token::Kind::TK_SLASHEQ: return "/=";
1768 case Token::Kind::TK_PERCENTEQ: return "%=";
1769 case Token::Kind::TK_SHLEQ: return "<<=";
1770 case Token::Kind::TK_SHREQ: return ">>=";
1771 case Token::Kind::TK_LOGICALANDEQ: return "&&=";
1772 case Token::Kind::TK_LOGICALOREQ: return "||=";
1773 case Token::Kind::TK_LOGICALXOREQ: return "^^=";
1774 case Token::Kind::TK_BITWISEANDEQ: return "&=";
1775 case Token::Kind::TK_BITWISEOREQ: return "|=";
1776 case Token::Kind::TK_BITWISEXOREQ: return "^=";
1777 case Token::Kind::TK_PLUSPLUS: return "++";
1778 case Token::Kind::TK_MINUSMINUS: return "--";
1779 case Token::Kind::TK_COMMA: return ",";
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001780 default:
Brian Osman401a0092020-09-10 14:47:24 -04001781 ABORT("unsupported operator: %d\n", (int) op);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001782 }
1783}
1784
1785
1786bool Compiler::IsAssignment(Token::Kind op) {
1787 switch (op) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001788 case Token::Kind::TK_EQ: // fall through
1789 case Token::Kind::TK_PLUSEQ: // fall through
1790 case Token::Kind::TK_MINUSEQ: // fall through
1791 case Token::Kind::TK_STAREQ: // fall through
1792 case Token::Kind::TK_SLASHEQ: // fall through
1793 case Token::Kind::TK_PERCENTEQ: // fall through
1794 case Token::Kind::TK_SHLEQ: // fall through
1795 case Token::Kind::TK_SHREQ: // fall through
1796 case Token::Kind::TK_BITWISEOREQ: // fall through
1797 case Token::Kind::TK_BITWISEXOREQ: // fall through
1798 case Token::Kind::TK_BITWISEANDEQ: // fall through
1799 case Token::Kind::TK_LOGICALOREQ: // fall through
1800 case Token::Kind::TK_LOGICALXOREQ: // fall through
1801 case Token::Kind::TK_LOGICALANDEQ:
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001802 return true;
1803 default:
1804 return false;
1805 }
1806}
1807
Brian Osman401a0092020-09-10 14:47:24 -04001808Token::Kind Compiler::RemoveAssignment(Token::Kind op) {
1809 switch (op) {
1810 case Token::Kind::TK_PLUSEQ: return Token::Kind::TK_PLUS;
1811 case Token::Kind::TK_MINUSEQ: return Token::Kind::TK_MINUS;
1812 case Token::Kind::TK_STAREQ: return Token::Kind::TK_STAR;
1813 case Token::Kind::TK_SLASHEQ: return Token::Kind::TK_SLASH;
1814 case Token::Kind::TK_PERCENTEQ: return Token::Kind::TK_PERCENT;
1815 case Token::Kind::TK_SHLEQ: return Token::Kind::TK_SHL;
1816 case Token::Kind::TK_SHREQ: return Token::Kind::TK_SHR;
1817 case Token::Kind::TK_BITWISEOREQ: return Token::Kind::TK_BITWISEOR;
1818 case Token::Kind::TK_BITWISEXOREQ: return Token::Kind::TK_BITWISEXOR;
1819 case Token::Kind::TK_BITWISEANDEQ: return Token::Kind::TK_BITWISEAND;
1820 case Token::Kind::TK_LOGICALOREQ: return Token::Kind::TK_LOGICALOR;
1821 case Token::Kind::TK_LOGICALXOREQ: return Token::Kind::TK_LOGICALXOR;
1822 case Token::Kind::TK_LOGICALANDEQ: return Token::Kind::TK_LOGICALAND;
1823 default: return op;
1824 }
1825}
1826
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001827Position Compiler::position(int offset) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001828 SkASSERT(fSource);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001829 int line = 1;
1830 int column = 1;
1831 for (int i = 0; i < offset; i++) {
1832 if ((*fSource)[i] == '\n') {
1833 ++line;
1834 column = 1;
1835 }
1836 else {
1837 ++column;
1838 }
1839 }
1840 return Position(line, column);
1841}
1842
1843void Compiler::error(int offset, String msg) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001844 fErrorCount++;
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001845 Position pos = this->position(offset);
1846 fErrorText += "error: " + to_string(pos.fLine) + ": " + msg.c_str() + "\n";
ethannicholasb3058bd2016-07-01 08:22:01 -07001847}
1848
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001849String Compiler::errorText() {
Ethan Nicholas00543112018-07-31 09:44:36 -04001850 this->writeErrorCount();
1851 fErrorCount = 0;
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001852 String result = fErrorText;
ethannicholasb3058bd2016-07-01 08:22:01 -07001853 return result;
1854}
1855
1856void Compiler::writeErrorCount() {
1857 if (fErrorCount) {
1858 fErrorText += to_string(fErrorCount) + " error";
1859 if (fErrorCount > 1) {
1860 fErrorText += "s";
1861 }
1862 fErrorText += "\n";
1863 }
1864}
1865
John Stilesa6841be2020-08-06 14:11:56 -04001866} // namespace SkSL