blob: 0025c955329fab6a5056acb803ec3f319fa8cc76 [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
Brian Osmand7e76592020-11-02 12:26:22 -050086Compiler::Compiler(const ShaderCapsClass* caps, Flags flags)
87: fCaps(caps)
88, fFlags(flags)
John Stiles810c8cf2020-08-26 19:46:27 -040089, fContext(std::make_shared<Context>())
Ethan Nicholas6e1cbc02017-07-14 10:12:15 -040090, fErrorCount(0) {
John Stiles7c3515b2020-10-16 18:38:39 -040091 fRootSymbolTable = std::make_shared<SymbolTable>(this, /*builtin=*/true);
John Stiles4c412bc2020-10-13 11:19:41 -040092 fIRGenerator = std::make_unique<IRGenerator>(fContext.get(), &fInliner, *this);
Brian Osman88cda172020-10-09 12:05:16 -040093#define ADD_TYPE(t) fRootSymbolTable->addWithoutOwnership(fContext->f##t##_Type.get())
ethannicholasb3058bd2016-07-01 08:22:01 -070094 ADD_TYPE(Void);
95 ADD_TYPE(Float);
Ethan Nicholas5af9ea32017-07-28 15:19:46 -040096 ADD_TYPE(Float2);
97 ADD_TYPE(Float3);
98 ADD_TYPE(Float4);
Ethan Nicholasdcba08e2017-08-02 10:52:54 -040099 ADD_TYPE(Half);
100 ADD_TYPE(Half2);
101 ADD_TYPE(Half3);
102 ADD_TYPE(Half4);
ethannicholasb3058bd2016-07-01 08:22:01 -0700103 ADD_TYPE(Int);
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400104 ADD_TYPE(Int2);
105 ADD_TYPE(Int3);
106 ADD_TYPE(Int4);
ethannicholasb3058bd2016-07-01 08:22:01 -0700107 ADD_TYPE(UInt);
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400108 ADD_TYPE(UInt2);
109 ADD_TYPE(UInt3);
110 ADD_TYPE(UInt4);
Ethan Nicholasdcba08e2017-08-02 10:52:54 -0400111 ADD_TYPE(Short);
112 ADD_TYPE(Short2);
113 ADD_TYPE(Short3);
114 ADD_TYPE(Short4);
115 ADD_TYPE(UShort);
116 ADD_TYPE(UShort2);
117 ADD_TYPE(UShort3);
118 ADD_TYPE(UShort4);
Ruiqi Maob609e6d2018-07-17 10:19:38 -0400119 ADD_TYPE(Byte);
120 ADD_TYPE(Byte2);
121 ADD_TYPE(Byte3);
122 ADD_TYPE(Byte4);
123 ADD_TYPE(UByte);
124 ADD_TYPE(UByte2);
125 ADD_TYPE(UByte3);
126 ADD_TYPE(UByte4);
ethannicholasb3058bd2016-07-01 08:22:01 -0700127 ADD_TYPE(Bool);
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400128 ADD_TYPE(Bool2);
129 ADD_TYPE(Bool3);
130 ADD_TYPE(Bool4);
131 ADD_TYPE(Float2x2);
132 ADD_TYPE(Float2x3);
133 ADD_TYPE(Float2x4);
134 ADD_TYPE(Float3x2);
135 ADD_TYPE(Float3x3);
136 ADD_TYPE(Float3x4);
137 ADD_TYPE(Float4x2);
138 ADD_TYPE(Float4x3);
139 ADD_TYPE(Float4x4);
Ethan Nicholasdcba08e2017-08-02 10:52:54 -0400140 ADD_TYPE(Half2x2);
141 ADD_TYPE(Half2x3);
142 ADD_TYPE(Half2x4);
143 ADD_TYPE(Half3x2);
144 ADD_TYPE(Half3x3);
145 ADD_TYPE(Half3x4);
146 ADD_TYPE(Half4x2);
147 ADD_TYPE(Half4x3);
148 ADD_TYPE(Half4x4);
ethannicholasb3058bd2016-07-01 08:22:01 -0700149 ADD_TYPE(GenType);
Ethan Nicholasdcba08e2017-08-02 10:52:54 -0400150 ADD_TYPE(GenHType);
ethannicholasb3058bd2016-07-01 08:22:01 -0700151 ADD_TYPE(GenIType);
152 ADD_TYPE(GenUType);
153 ADD_TYPE(GenBType);
154 ADD_TYPE(Mat);
155 ADD_TYPE(Vec);
156 ADD_TYPE(GVec);
157 ADD_TYPE(GVec2);
158 ADD_TYPE(GVec3);
159 ADD_TYPE(GVec4);
Ethan Nicholasdcba08e2017-08-02 10:52:54 -0400160 ADD_TYPE(HVec);
ethannicholasb3058bd2016-07-01 08:22:01 -0700161 ADD_TYPE(IVec);
162 ADD_TYPE(UVec);
Ethan Nicholasdcba08e2017-08-02 10:52:54 -0400163 ADD_TYPE(SVec);
164 ADD_TYPE(USVec);
Ruiqi Maob609e6d2018-07-17 10:19:38 -0400165 ADD_TYPE(ByteVec);
166 ADD_TYPE(UByteVec);
ethannicholasb3058bd2016-07-01 08:22:01 -0700167 ADD_TYPE(BVec);
168
169 ADD_TYPE(Sampler1D);
170 ADD_TYPE(Sampler2D);
171 ADD_TYPE(Sampler3D);
ethannicholas5961bc92016-10-12 06:39:56 -0700172 ADD_TYPE(SamplerExternalOES);
ethannicholasb3058bd2016-07-01 08:22:01 -0700173 ADD_TYPE(SamplerCube);
174 ADD_TYPE(Sampler2DRect);
175 ADD_TYPE(Sampler1DArray);
176 ADD_TYPE(Sampler2DArray);
177 ADD_TYPE(SamplerCubeArray);
178 ADD_TYPE(SamplerBuffer);
179 ADD_TYPE(Sampler2DMS);
180 ADD_TYPE(Sampler2DMSArray);
181
Brian Salomonbf7b6202016-11-11 16:08:03 -0500182 ADD_TYPE(ISampler2D);
183
Brian Salomon2a51de82016-11-16 12:06:01 -0500184 ADD_TYPE(Image2D);
185 ADD_TYPE(IImage2D);
186
Greg Daniel64773e62016-11-22 09:44:03 -0500187 ADD_TYPE(SubpassInput);
188 ADD_TYPE(SubpassInputMS);
189
ethannicholasb3058bd2016-07-01 08:22:01 -0700190 ADD_TYPE(GSampler1D);
191 ADD_TYPE(GSampler2D);
192 ADD_TYPE(GSampler3D);
193 ADD_TYPE(GSamplerCube);
194 ADD_TYPE(GSampler2DRect);
195 ADD_TYPE(GSampler1DArray);
196 ADD_TYPE(GSampler2DArray);
197 ADD_TYPE(GSamplerCubeArray);
198 ADD_TYPE(GSamplerBuffer);
199 ADD_TYPE(GSampler2DMS);
200 ADD_TYPE(GSampler2DMSArray);
201
202 ADD_TYPE(Sampler1DShadow);
203 ADD_TYPE(Sampler2DShadow);
204 ADD_TYPE(SamplerCubeShadow);
205 ADD_TYPE(Sampler2DRectShadow);
206 ADD_TYPE(Sampler1DArrayShadow);
207 ADD_TYPE(Sampler2DArrayShadow);
208 ADD_TYPE(SamplerCubeArrayShadow);
209 ADD_TYPE(GSampler2DArrayShadow);
210 ADD_TYPE(GSamplerCubeArrayShadow);
Ethan Nicholasc9472af2017-10-10 16:30:21 -0400211 ADD_TYPE(FragmentProcessor);
Stephen Whiteff5d7a22019-07-26 17:42:06 -0400212 ADD_TYPE(Sampler);
213 ADD_TYPE(Texture2D);
ethannicholasb3058bd2016-07-01 08:22:01 -0700214
Brian Osman3887a012020-09-30 13:22:27 -0400215 // sk_Caps is "builtin", but all references to it are resolved to Settings, so we don't need to
216 // treat it as builtin (ie, no need to clone it into the Program).
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700217 StringFragment skCapsName("sk_Caps");
John Stilesb8cc6652020-10-08 09:12:07 -0400218 fRootSymbolTable->add(std::make_unique<Variable>(/*offset=*/-1,
Ethan Nicholas041fd0a2020-10-07 16:42:04 -0400219 fIRGenerator->fModifiers->handle(Modifiers()),
Ethan Nicholas453f67f2020-10-09 10:43:45 -0400220 skCapsName,
221 fContext->fSkCaps_Type.get(),
222 /*builtin=*/false,
223 Variable::Storage::kGlobal));
Ethan Nicholas3605ace2016-11-21 15:59:48 -0500224
Brian Osman3d87e9f2020-10-08 11:50:22 -0400225 fRootModule = {fRootSymbolTable, /*fIntrinsics=*/nullptr};
John Stilesbc0c29e2020-09-28 13:13:40 -0400226
Brian Osman3d87e9f2020-10-08 11:50:22 -0400227 fGPUModule = this->parseModule(Program::kFragment_Kind, MODULE_DATA(gpu), fRootModule);
228 fVertexModule = this->parseModule(Program::kVertex_Kind, MODULE_DATA(vert), fGPUModule);
229 fFragmentModule = this->parseModule(Program::kFragment_Kind, MODULE_DATA(frag), fGPUModule);
ethannicholasb3058bd2016-07-01 08:22:01 -0700230}
231
John Stilesdd13dba2020-10-29 10:45:34 -0400232Compiler::~Compiler() {}
ethannicholasb3058bd2016-07-01 08:22:01 -0700233
Brian Osman88cda172020-10-09 12:05:16 -0400234const ParsedModule& Compiler::loadGeometryModule() {
Brian Osman3d87e9f2020-10-08 11:50:22 -0400235 if (!fGeometryModule.fSymbols) {
236 fGeometryModule = this->parseModule(Program::kGeometry_Kind, MODULE_DATA(geom), fGPUModule);
Ethan Nicholasc18bb512020-07-28 14:46:53 -0400237 }
Brian Osman88cda172020-10-09 12:05:16 -0400238 return fGeometryModule;
Ethan Nicholasc18bb512020-07-28 14:46:53 -0400239}
240
Brian Osman88cda172020-10-09 12:05:16 -0400241const ParsedModule& Compiler::loadFPModule() {
Brian Osman3d87e9f2020-10-08 11:50:22 -0400242 if (!fFPModule.fSymbols) {
243 fFPModule =
244 this->parseModule(Program::kFragmentProcessor_Kind, MODULE_DATA(fp), fGPUModule);
Brian Osman8e2ef022020-09-30 13:26:43 -0400245 }
Brian Osman88cda172020-10-09 12:05:16 -0400246 return fFPModule;
Brian Osman8e2ef022020-09-30 13:26:43 -0400247}
248
Brian Osman88cda172020-10-09 12:05:16 -0400249const ParsedModule& Compiler::loadPipelineModule() {
Brian Osman3d87e9f2020-10-08 11:50:22 -0400250 if (!fPipelineModule.fSymbols) {
251 fPipelineModule =
252 this->parseModule(Program::kPipelineStage_Kind, MODULE_DATA(pipeline), fGPUModule);
Brian Osmanf1319c32020-10-13 09:34:23 -0400253
254 // Add some aliases to the pipeline module so that it's friendlier, and more like GLSL
255 fPipelineModule.fSymbols->addAlias("shader", fContext->fFragmentProcessor_Type.get());
256
257 fPipelineModule.fSymbols->addAlias("vec2", fContext->fFloat2_Type.get());
258 fPipelineModule.fSymbols->addAlias("vec3", fContext->fFloat3_Type.get());
259 fPipelineModule.fSymbols->addAlias("vec4", fContext->fFloat4_Type.get());
260
261 fPipelineModule.fSymbols->addAlias("bvec2", fContext->fBool2_Type.get());
262 fPipelineModule.fSymbols->addAlias("bvec3", fContext->fBool3_Type.get());
263 fPipelineModule.fSymbols->addAlias("bvec4", fContext->fBool4_Type.get());
264
265 fPipelineModule.fSymbols->addAlias("mat2", fContext->fFloat2x2_Type.get());
266 fPipelineModule.fSymbols->addAlias("mat3", fContext->fFloat3x3_Type.get());
267 fPipelineModule.fSymbols->addAlias("mat4", fContext->fFloat4x4_Type.get());
268
269 fPipelineModule.fSymbols->addAlias("mat2x2", fContext->fFloat2x2_Type.get());
270 fPipelineModule.fSymbols->addAlias("mat2x3", fContext->fFloat2x3_Type.get());
271 fPipelineModule.fSymbols->addAlias("mat2x4", fContext->fFloat2x4_Type.get());
272
273 fPipelineModule.fSymbols->addAlias("mat3x2", fContext->fFloat3x2_Type.get());
274 fPipelineModule.fSymbols->addAlias("mat3x3", fContext->fFloat3x3_Type.get());
275 fPipelineModule.fSymbols->addAlias("mat3x4", fContext->fFloat3x4_Type.get());
276
277 fPipelineModule.fSymbols->addAlias("mat4x2", fContext->fFloat4x2_Type.get());
278 fPipelineModule.fSymbols->addAlias("mat4x3", fContext->fFloat4x3_Type.get());
279 fPipelineModule.fSymbols->addAlias("mat4x4", fContext->fFloat4x4_Type.get());
Ethan Nicholasc18bb512020-07-28 14:46:53 -0400280 }
Brian Osman88cda172020-10-09 12:05:16 -0400281 return fPipelineModule;
Ethan Nicholasc18bb512020-07-28 14:46:53 -0400282}
283
Brian Osman88cda172020-10-09 12:05:16 -0400284const ParsedModule& Compiler::loadInterpreterModule() {
Brian Osman3d87e9f2020-10-08 11:50:22 -0400285 if (!fInterpreterModule.fSymbols) {
286 fInterpreterModule =
287 this->parseModule(Program::kGeneric_Kind, MODULE_DATA(interp), fRootModule);
Ethan Nicholasc18bb512020-07-28 14:46:53 -0400288 }
Brian Osman88cda172020-10-09 12:05:16 -0400289 return fInterpreterModule;
290}
291
292const ParsedModule& Compiler::moduleForProgramKind(Program::Kind kind) {
293 switch (kind) {
294 case Program::kVertex_Kind: return fVertexModule; break;
295 case Program::kFragment_Kind: return fFragmentModule; break;
296 case Program::kGeometry_Kind: return this->loadGeometryModule(); break;
297 case Program::kFragmentProcessor_Kind: return this->loadFPModule(); break;
298 case Program::kPipelineStage_Kind: return this->loadPipelineModule(); break;
299 case Program::kGeneric_Kind: return this->loadInterpreterModule(); break;
300 }
301 SkUNREACHABLE;
Ethan Nicholasc18bb512020-07-28 14:46:53 -0400302}
303
Brian Osman3d87e9f2020-10-08 11:50:22 -0400304LoadedModule Compiler::loadModule(Program::Kind kind,
305 ModuleData data,
306 std::shared_ptr<SymbolTable> base) {
Brian Osman3d87e9f2020-10-08 11:50:22 -0400307 if (!base) {
308 base = fRootSymbolTable;
309 }
310
311#if defined(SKSL_STANDALONE)
312 SkASSERT(data.fPath);
313 std::ifstream in(data.fPath);
Brian Osmane498b3c2020-09-23 14:42:11 -0400314 std::unique_ptr<String> text = std::make_unique<String>(std::istreambuf_iterator<char>(in),
315 std::istreambuf_iterator<char>());
Ethan Nicholasb33fa3f2020-08-06 13:00:19 -0400316 if (in.rdstate()) {
Brian Osman3d87e9f2020-10-08 11:50:22 -0400317 printf("error reading %s\n", data.fPath);
Ethan Nicholasb33fa3f2020-08-06 13:00:19 -0400318 abort();
319 }
Brian Osmane498b3c2020-09-23 14:42:11 -0400320 const String* source = fRootSymbolTable->takeOwnershipOfString(std::move(text));
Brian Osman88cda172020-10-09 12:05:16 -0400321 AutoSource as(this, source);
Ethan Nicholas8da1e652019-05-24 11:01:59 -0400322 Program::Settings settings;
John Stiles881a10c2020-09-19 10:13:24 -0400323 SkASSERT(fIRGenerator->fCanInline);
324 fIRGenerator->fCanInline = false;
Brian Osman88cda172020-10-09 12:05:16 -0400325 ParsedModule baseModule = {base, /*fIntrinsics=*/nullptr};
Brian Osmand7e76592020-11-02 12:26:22 -0500326 IRGenerator::IRBundle ir =
327 fIRGenerator->convertProgram(kind, &settings, &standaloneCaps, baseModule,
328 /*isBuiltinCode=*/true, source->c_str(), source->length(),
329 /*externalValues=*/nullptr);
330 LoadedModule module = {std::move(ir.fSymbolTable), std::move(ir.fElements)};
John Stiles881a10c2020-09-19 10:13:24 -0400331 fIRGenerator->fCanInline = true;
Ethan Nicholas8da1e652019-05-24 11:01:59 -0400332 if (this->fErrorCount) {
333 printf("Unexpected errors: %s\n", this->fErrorText.c_str());
Brian Osman3d87e9f2020-10-08 11:50:22 -0400334 SkDEBUGFAILF("%s %s\n", data.fPath, this->fErrorText.c_str());
Ethan Nicholas8da1e652019-05-24 11:01:59 -0400335 }
Brian Osman88cda172020-10-09 12:05:16 -0400336 fModifiers.push_back(std::move(ir.fModifiers));
Brian Osman3d87e9f2020-10-08 11:50:22 -0400337#else
338 SkASSERT(data.fData && (data.fSize != 0));
339 Rehydrator rehydrator(fContext.get(), fIRGenerator->fModifiers.get(), base, this,
340 data.fData, data.fSize);
Brian Osman88cda172020-10-09 12:05:16 -0400341 LoadedModule module = { rehydrator.symbolTable(), rehydrator.elements() };
Brian Osman3d87e9f2020-10-08 11:50:22 -0400342 fModifiers.push_back(fIRGenerator->releaseModifiers());
343#endif
344
345 return module;
346}
347
348ParsedModule Compiler::parseModule(Program::Kind kind, ModuleData data, const ParsedModule& base) {
349 auto [symbols, elements] = this->loadModule(kind, data, base.fSymbols);
350
351 // For modules that just declare (but don't define) intrinsic functions, there will be no new
352 // program elements. In that case, we can share our parent's intrinsic map:
353 if (elements.empty()) {
354 return {symbols, base.fIntrinsics};
355 }
356
357 auto intrinsics = std::make_shared<IRIntrinsicMap>(base.fIntrinsics.get());
358
359 // Now, transfer all of the program elements to an intrinsic map. This maps certain types of
360 // global objects to the declaring ProgramElement.
361 for (std::unique_ptr<ProgramElement>& element : elements) {
362 switch (element->kind()) {
363 case ProgramElement::Kind::kFunction: {
364 const FunctionDefinition& f = element->as<FunctionDefinition>();
Ethan Nicholas0a5d0962020-10-14 13:33:18 -0400365 SkASSERT(f.declaration().isBuiltin());
366 intrinsics->insertOrDie(f.declaration().description(), std::move(element));
Brian Osman3d87e9f2020-10-08 11:50:22 -0400367 break;
368 }
John Stiles569249b2020-11-03 12:18:22 -0500369 case ProgramElement::Kind::kFunctionPrototype: {
370 // These are already in the symbol table.
371 break;
372 }
Brian Osman3d87e9f2020-10-08 11:50:22 -0400373 case ProgramElement::Kind::kEnum: {
374 const Enum& e = element->as<Enum>();
375 SkASSERT(e.isBuiltin());
376 intrinsics->insertOrDie(e.typeName(), std::move(element));
377 break;
378 }
379 case ProgramElement::Kind::kGlobalVar: {
Ethan Nicholasc51f33e2020-10-13 13:49:44 -0400380 const GlobalVarDeclaration& global = element->as<GlobalVarDeclaration>();
381 const Variable& var = global.declaration()->as<VarDeclaration>().var();
382 SkASSERT(var.isBuiltin());
383 intrinsics->insertOrDie(var.name(), std::move(element));
Brian Osman3d87e9f2020-10-08 11:50:22 -0400384 break;
385 }
386 case ProgramElement::Kind::kInterfaceBlock: {
Ethan Nicholaseaf47882020-10-15 10:10:08 -0400387 const Variable& var = element->as<InterfaceBlock>().variable();
388 SkASSERT(var.isBuiltin());
389 intrinsics->insertOrDie(var.name(), std::move(element));
Brian Osman3d87e9f2020-10-08 11:50:22 -0400390 break;
391 }
392 default:
393 printf("Unsupported element: %s\n", element->description().c_str());
394 SkASSERT(false);
395 break;
396 }
397 }
398
399 return {symbols, std::move(intrinsics)};
Ethan Nicholas8da1e652019-05-24 11:01:59 -0400400}
401
ethannicholas22f939e2016-10-13 13:25:34 -0700402// add the definition created by assigning to the lvalue to the definition set
Ethan Nicholas86a43402017-01-19 13:32:00 -0500403void Compiler::addDefinition(const Expression* lvalue, std::unique_ptr<Expression>* expr,
404 DefinitionMap* definitions) {
Ethan Nicholase6592142020-09-08 10:22:09 -0400405 switch (lvalue->kind()) {
406 case Expression::Kind::kVariableReference: {
Ethan Nicholas78686922020-10-08 06:46:27 -0400407 const Variable& var = *lvalue->as<VariableReference>().variable();
Ethan Nicholas453f67f2020-10-09 10:43:45 -0400408 if (var.storage() == Variable::Storage::kLocal) {
John Stiles796cdb72020-10-08 12:06:53 -0400409 definitions->set(&var, expr);
ethannicholas22f939e2016-10-13 13:25:34 -0700410 }
411 break;
412 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400413 case Expression::Kind::kSwizzle:
ethannicholas22f939e2016-10-13 13:25:34 -0700414 // We consider the variable written to as long as at least some of its components have
415 // been written to. This will lead to some false negatives (we won't catch it if you
416 // write to foo.x and then read foo.y), but being stricter could lead to false positives
Mike Klein6ad99092016-10-26 10:35:22 -0400417 // (we write to foo.x, and then pass foo to a function which happens to only read foo.x,
418 // 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 -0700419 // more complicated whole-program analysis. This is probably good enough.
Ethan Nicholas6b4d5812020-10-12 16:11:51 -0400420 this->addDefinition(lvalue->as<Swizzle>().base().get(),
Ethan Nicholas26a9aad2018-03-27 14:10:52 -0400421 (std::unique_ptr<Expression>*) &fContext->fDefined_Expression,
ethannicholas22f939e2016-10-13 13:25:34 -0700422 definitions);
423 break;
Ethan Nicholase6592142020-09-08 10:22:09 -0400424 case Expression::Kind::kIndex:
ethannicholas22f939e2016-10-13 13:25:34 -0700425 // see comments in Swizzle
Ethan Nicholas2a4952d2020-10-08 15:35:56 -0400426 this->addDefinition(lvalue->as<IndexExpression>().base().get(),
Ethan Nicholas26a9aad2018-03-27 14:10:52 -0400427 (std::unique_ptr<Expression>*) &fContext->fDefined_Expression,
ethannicholas22f939e2016-10-13 13:25:34 -0700428 definitions);
429 break;
Ethan Nicholase6592142020-09-08 10:22:09 -0400430 case Expression::Kind::kFieldAccess:
ethannicholas22f939e2016-10-13 13:25:34 -0700431 // see comments in Swizzle
Ethan Nicholas7a95b202020-10-09 11:55:40 -0400432 this->addDefinition(lvalue->as<FieldAccess>().base().get(),
Ethan Nicholas26a9aad2018-03-27 14:10:52 -0400433 (std::unique_ptr<Expression>*) &fContext->fDefined_Expression,
ethannicholas22f939e2016-10-13 13:25:34 -0700434 definitions);
435 break;
Ethan Nicholase6592142020-09-08 10:22:09 -0400436 case Expression::Kind::kTernary:
Ethan Nicholasa583b812018-01-18 13:32:11 -0500437 // To simplify analysis, we just pretend that we write to both sides of the ternary.
438 // This allows for false positives (meaning we fail to detect that a variable might not
439 // have been assigned), but is preferable to false negatives.
Ethan Nicholasdd218162020-10-08 05:48:01 -0400440 this->addDefinition(lvalue->as<TernaryExpression>().ifTrue().get(),
Ethan Nicholas26a9aad2018-03-27 14:10:52 -0400441 (std::unique_ptr<Expression>*) &fContext->fDefined_Expression,
Ethan Nicholasa583b812018-01-18 13:32:11 -0500442 definitions);
Ethan Nicholasdd218162020-10-08 05:48:01 -0400443 this->addDefinition(lvalue->as<TernaryExpression>().ifFalse().get(),
Ethan Nicholas26a9aad2018-03-27 14:10:52 -0400444 (std::unique_ptr<Expression>*) &fContext->fDefined_Expression,
Ethan Nicholasa583b812018-01-18 13:32:11 -0500445 definitions);
446 break;
Ethan Nicholase6592142020-09-08 10:22:09 -0400447 case Expression::Kind::kExternalValue:
Ethan Nicholas91164d12019-05-15 15:29:54 -0400448 break;
ethannicholas22f939e2016-10-13 13:25:34 -0700449 default:
450 // not an lvalue, can't happen
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400451 SkASSERT(false);
ethannicholas22f939e2016-10-13 13:25:34 -0700452 }
453}
454
455// add local variables defined by this node to the set
John Stiles796cdb72020-10-08 12:06:53 -0400456void Compiler::addDefinitions(const BasicBlock::Node& node, DefinitionMap* definitions) {
John Stiles70025e52020-09-28 16:08:58 -0400457 if (node.isExpression()) {
458 Expression* expr = node.expression()->get();
459 switch (expr->kind()) {
460 case Expression::Kind::kBinary: {
461 BinaryExpression* b = &expr->as<BinaryExpression>();
462 if (b->getOperator() == Token::Kind::TK_EQ) {
John Stiles2d4f9592020-10-30 10:29:12 -0400463 this->addDefinition(b->left().get(), &b->right(), definitions);
John Stiles70025e52020-09-28 16:08:58 -0400464 } else if (Compiler::IsAssignment(b->getOperator())) {
465 this->addDefinition(
John Stiles2d4f9592020-10-30 10:29:12 -0400466 b->left().get(),
John Stiles70025e52020-09-28 16:08:58 -0400467 (std::unique_ptr<Expression>*) &fContext->fDefined_Expression,
468 definitions);
Ethan Nicholas86a43402017-01-19 13:32:00 -0500469
ethannicholas22f939e2016-10-13 13:25:34 -0700470 }
John Stiles70025e52020-09-28 16:08:58 -0400471 break;
ethannicholas22f939e2016-10-13 13:25:34 -0700472 }
John Stiles70025e52020-09-28 16:08:58 -0400473 case Expression::Kind::kFunctionCall: {
474 const FunctionCall& c = expr->as<FunctionCall>();
Brian Osman5bf3e202020-10-13 10:34:18 -0400475 const std::vector<const Variable*>& parameters = c.function().parameters();
Ethan Nicholased84b732020-10-08 11:45:44 -0400476 for (size_t i = 0; i < parameters.size(); ++i) {
477 if (parameters[i]->modifiers().fFlags & Modifiers::kOut_Flag) {
John Stiles70025e52020-09-28 16:08:58 -0400478 this->addDefinition(
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400479 c.arguments()[i].get(),
John Stiles70025e52020-09-28 16:08:58 -0400480 (std::unique_ptr<Expression>*) &fContext->fDefined_Expression,
481 definitions);
482 }
483 }
484 break;
485 }
486 case Expression::Kind::kPrefix: {
487 const PrefixExpression* p = &expr->as<PrefixExpression>();
Ethan Nicholas444ccc62020-10-09 10:16:22 -0400488 if (p->getOperator() == Token::Kind::TK_MINUSMINUS ||
489 p->getOperator() == Token::Kind::TK_PLUSPLUS) {
John Stiles70025e52020-09-28 16:08:58 -0400490 this->addDefinition(
Ethan Nicholas444ccc62020-10-09 10:16:22 -0400491 p->operand().get(),
John Stiles70025e52020-09-28 16:08:58 -0400492 (std::unique_ptr<Expression>*) &fContext->fDefined_Expression,
493 definitions);
494 }
495 break;
496 }
497 case Expression::Kind::kPostfix: {
498 const PostfixExpression* p = &expr->as<PostfixExpression>();
Ethan Nicholas444ccc62020-10-09 10:16:22 -0400499 if (p->getOperator() == Token::Kind::TK_MINUSMINUS ||
500 p->getOperator() == Token::Kind::TK_PLUSPLUS) {
John Stiles70025e52020-09-28 16:08:58 -0400501 this->addDefinition(
Ethan Nicholas444ccc62020-10-09 10:16:22 -0400502 p->operand().get(),
John Stiles70025e52020-09-28 16:08:58 -0400503 (std::unique_ptr<Expression>*) &fContext->fDefined_Expression,
504 definitions);
505 }
506 break;
507 }
508 case Expression::Kind::kVariableReference: {
509 const VariableReference* v = &expr->as<VariableReference>();
Ethan Nicholas453f67f2020-10-09 10:43:45 -0400510 if (v->refKind() != VariableReference::RefKind::kRead) {
John Stiles70025e52020-09-28 16:08:58 -0400511 this->addDefinition(
512 v,
513 (std::unique_ptr<Expression>*) &fContext->fDefined_Expression,
514 definitions);
515 }
516 break;
517 }
518 default:
519 break;
ethannicholas22f939e2016-10-13 13:25:34 -0700520 }
John Stiles70025e52020-09-28 16:08:58 -0400521 } else if (node.isStatement()) {
522 Statement* stmt = node.statement()->get();
523 if (stmt->is<VarDeclaration>()) {
524 VarDeclaration& vd = stmt->as<VarDeclaration>();
Ethan Nicholasc51f33e2020-10-13 13:49:44 -0400525 if (vd.value()) {
526 definitions->set(&vd.var(), &vd.value());
ethannicholas22f939e2016-10-13 13:25:34 -0700527 }
ethannicholas22f939e2016-10-13 13:25:34 -0700528 }
529 }
530}
531
John Stilese6150002020-10-05 12:03:53 -0400532void Compiler::scanCFG(CFG* cfg, BlockId blockId, SkBitSet* processedSet) {
ethannicholas22f939e2016-10-13 13:25:34 -0700533 BasicBlock& block = cfg->fBlocks[blockId];
534
535 // compute definitions after this block
Ethan Nicholas86a43402017-01-19 13:32:00 -0500536 DefinitionMap after = block.fBefore;
ethannicholas22f939e2016-10-13 13:25:34 -0700537 for (const BasicBlock::Node& n : block.fNodes) {
538 this->addDefinitions(n, &after);
539 }
540
541 // propagate definitions to exits
542 for (BlockId exitId : block.fExits) {
Ethan Nicholas26a9aad2018-03-27 14:10:52 -0400543 if (exitId == blockId) {
544 continue;
545 }
ethannicholas22f939e2016-10-13 13:25:34 -0700546 BasicBlock& exit = cfg->fBlocks[exitId];
John Stiles796cdb72020-10-08 12:06:53 -0400547 after.foreach([&](const Variable* var, std::unique_ptr<Expression>** e1Ptr) {
548 std::unique_ptr<Expression>* e1 = *e1Ptr;
549 std::unique_ptr<Expression>** exitDef = exit.fBefore.find(var);
550 if (!exitDef) {
John Stilese6150002020-10-05 12:03:53 -0400551 // exit has no definition for it, just copy it and reprocess exit block
552 processedSet->reset(exitId);
John Stiles796cdb72020-10-08 12:06:53 -0400553 exit.fBefore[var] = e1;
ethannicholas22f939e2016-10-13 13:25:34 -0700554 } else {
Ethan Nicholas86a43402017-01-19 13:32:00 -0500555 // exit has a (possibly different) value already defined
John Stiles796cdb72020-10-08 12:06:53 -0400556 std::unique_ptr<Expression>* e2 = *exitDef;
ethannicholas22f939e2016-10-13 13:25:34 -0700557 if (e1 != e2) {
John Stilese6150002020-10-05 12:03:53 -0400558 // definition has changed, merge and reprocess the exit block
559 processedSet->reset(exitId);
Ethan Nicholasaf197692017-02-27 13:26:45 -0500560 if (e1 && e2) {
John Stiles796cdb72020-10-08 12:06:53 -0400561 *exitDef = (std::unique_ptr<Expression>*)&fContext->fDefined_Expression;
Ethan Nicholasaf197692017-02-27 13:26:45 -0500562 } else {
John Stiles796cdb72020-10-08 12:06:53 -0400563 *exitDef = nullptr;
Ethan Nicholasaf197692017-02-27 13:26:45 -0500564 }
ethannicholas22f939e2016-10-13 13:25:34 -0700565 }
566 }
John Stiles796cdb72020-10-08 12:06:53 -0400567 });
ethannicholas22f939e2016-10-13 13:25:34 -0700568 }
569}
570
571// returns a map which maps all local variables in the function to null, indicating that their value
572// is initially unknown
Ethan Nicholas86a43402017-01-19 13:32:00 -0500573static DefinitionMap compute_start_state(const CFG& cfg) {
574 DefinitionMap result;
Mike Klein6ad99092016-10-26 10:35:22 -0400575 for (const auto& block : cfg.fBlocks) {
576 for (const auto& node : block.fNodes) {
John Stiles70025e52020-09-28 16:08:58 -0400577 if (node.isStatement()) {
Ethan Nicholascb670962017-04-20 19:31:52 -0400578 const Statement* s = node.statement()->get();
Brian Osmanc0213602020-10-06 14:43:32 -0400579 if (s->is<VarDeclaration>()) {
Ethan Nicholasc51f33e2020-10-13 13:49:44 -0400580 result[&s->as<VarDeclaration>().var()] = nullptr;
ethannicholas22f939e2016-10-13 13:25:34 -0700581 }
582 }
583 }
584 }
585 return result;
586}
587
Ethan Nicholascb670962017-04-20 19:31:52 -0400588/**
589 * Returns true if assigning to this lvalue has no effect.
590 */
Brian Osman010ce6a2020-10-19 16:34:10 -0400591static bool is_dead(const Expression& lvalue, ProgramUsage* usage) {
Ethan Nicholase6592142020-09-08 10:22:09 -0400592 switch (lvalue.kind()) {
593 case Expression::Kind::kVariableReference:
Brian Osman010ce6a2020-10-19 16:34:10 -0400594 return usage->isDead(*lvalue.as<VariableReference>().variable());
Ethan Nicholase6592142020-09-08 10:22:09 -0400595 case Expression::Kind::kSwizzle:
Brian Osman010ce6a2020-10-19 16:34:10 -0400596 return is_dead(*lvalue.as<Swizzle>().base(), usage);
Ethan Nicholase6592142020-09-08 10:22:09 -0400597 case Expression::Kind::kFieldAccess:
Brian Osman010ce6a2020-10-19 16:34:10 -0400598 return is_dead(*lvalue.as<FieldAccess>().base(), usage);
Ethan Nicholase6592142020-09-08 10:22:09 -0400599 case Expression::Kind::kIndex: {
John Stilesa5a97b42020-08-18 11:19:07 -0400600 const IndexExpression& idx = lvalue.as<IndexExpression>();
Brian Osman010ce6a2020-10-19 16:34:10 -0400601 return is_dead(*idx.base(), usage) &&
Ethan Nicholas2a4952d2020-10-08 15:35:56 -0400602 !idx.index()->hasProperty(Expression::Property::kSideEffects);
Ethan Nicholascb670962017-04-20 19:31:52 -0400603 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400604 case Expression::Kind::kTernary: {
John Stilesa5a97b42020-08-18 11:19:07 -0400605 const TernaryExpression& t = lvalue.as<TernaryExpression>();
Brian Osman010ce6a2020-10-19 16:34:10 -0400606 return !t.test()->hasSideEffects() &&
607 is_dead(*t.ifTrue(), usage) &&
608 is_dead(*t.ifFalse(), usage);
Ethan Nicholasa583b812018-01-18 13:32:11 -0500609 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400610 case Expression::Kind::kExternalValue:
Ethan Nicholas91164d12019-05-15 15:29:54 -0400611 return false;
Ethan Nicholascb670962017-04-20 19:31:52 -0400612 default:
Ethan Nicholas2a099da2020-01-02 14:40:54 -0500613#ifdef SK_DEBUG
Ethan Nicholascb670962017-04-20 19:31:52 -0400614 ABORT("invalid lvalue: %s\n", lvalue.description().c_str());
Ethan Nicholas2a099da2020-01-02 14:40:54 -0500615#endif
616 return false;
Ethan Nicholascb670962017-04-20 19:31:52 -0400617 }
618}
ethannicholas22f939e2016-10-13 13:25:34 -0700619
Ethan Nicholascb670962017-04-20 19:31:52 -0400620/**
621 * Returns true if this is an assignment which can be collapsed down to just the right hand side due
622 * to a dead target and lack of side effects on the left hand side.
623 */
Brian Osman010ce6a2020-10-19 16:34:10 -0400624static bool dead_assignment(const BinaryExpression& b, ProgramUsage* usage) {
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400625 if (!Compiler::IsAssignment(b.getOperator())) {
Ethan Nicholascb670962017-04-20 19:31:52 -0400626 return false;
627 }
John Stiles2d4f9592020-10-30 10:29:12 -0400628 return is_dead(*b.left(), usage);
Ethan Nicholascb670962017-04-20 19:31:52 -0400629}
630
631void Compiler::computeDataFlow(CFG* cfg) {
632 cfg->fBlocks[cfg->fStart].fBefore = compute_start_state(*cfg);
John Stilese6150002020-10-05 12:03:53 -0400633
634 // We set bits in the "processed" set after a block has been scanned.
635 SkBitSet processedSet(cfg->fBlocks.size());
636 while (SkBitSet::OptionalIndex blockId = processedSet.findFirstUnset()) {
637 processedSet.set(*blockId);
638 this->scanCFG(cfg, *blockId, &processedSet);
ethannicholas22f939e2016-10-13 13:25:34 -0700639 }
Ethan Nicholascb670962017-04-20 19:31:52 -0400640}
641
642/**
643 * Attempts to replace the expression pointed to by iter with a new one (in both the CFG and the
644 * IR). If the expression can be cleanly removed, returns true and updates the iterator to point to
645 * the newly-inserted element. Otherwise updates only the IR and returns false (and the CFG will
646 * need to be regenerated).
647 */
John Stilesafbf8992020-08-18 10:08:21 -0400648static bool try_replace_expression(BasicBlock* b,
649 std::vector<BasicBlock::Node>::iterator* iter,
650 std::unique_ptr<Expression>* newExpression) {
Ethan Nicholascb670962017-04-20 19:31:52 -0400651 std::unique_ptr<Expression>* target = (*iter)->expression();
652 if (!b->tryRemoveExpression(iter)) {
653 *target = std::move(*newExpression);
654 return false;
655 }
656 *target = std::move(*newExpression);
657 return b->tryInsertExpression(iter, target);
658}
659
660/**
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400661 * Returns true if the expression is a constant numeric literal with the specified value, or a
662 * constant vector with all elements equal to the specified value.
Ethan Nicholascb670962017-04-20 19:31:52 -0400663 */
Ethan Nicholasa3f22f12020-10-01 12:13:17 -0400664template <typename T = SKSL_FLOAT>
John Stiles9d944232020-08-19 09:56:49 -0400665static bool is_constant(const Expression& expr, T value) {
Ethan Nicholase6592142020-09-08 10:22:09 -0400666 switch (expr.kind()) {
667 case Expression::Kind::kIntLiteral:
Ethan Nicholase96cdd12020-09-28 16:27:18 -0400668 return expr.as<IntLiteral>().value() == value;
John Stiles9d944232020-08-19 09:56:49 -0400669
Ethan Nicholase6592142020-09-08 10:22:09 -0400670 case Expression::Kind::kFloatLiteral:
Ethan Nicholasa3f22f12020-10-01 12:13:17 -0400671 return expr.as<FloatLiteral>().value() == value;
John Stiles9d944232020-08-19 09:56:49 -0400672
Ethan Nicholase6592142020-09-08 10:22:09 -0400673 case Expression::Kind::kConstructor: {
John Stiles9d944232020-08-19 09:56:49 -0400674 const Constructor& constructor = expr.as<Constructor>();
675 if (constructor.isCompileTimeConstant()) {
Ethan Nicholas30d30222020-09-11 12:27:26 -0400676 const Type& constructorType = constructor.type();
677 bool isFloat = constructorType.columns() > 1
678 ? constructorType.componentType().isFloat()
679 : constructorType.isFloat();
680 switch (constructorType.typeKind()) {
Ethan Nicholase6592142020-09-08 10:22:09 -0400681 case Type::TypeKind::kVector:
Ethan Nicholas30d30222020-09-11 12:27:26 -0400682 for (int i = 0; i < constructorType.columns(); ++i) {
John Stiles9d944232020-08-19 09:56:49 -0400683 if (isFloat) {
684 if (constructor.getFVecComponent(i) != value) {
685 return false;
686 }
687 } else {
688 if (constructor.getIVecComponent(i) != value) {
689 return false;
690 }
691 }
Ethan Nicholasd188c182019-06-10 15:55:38 -0400692 }
John Stiles9d944232020-08-19 09:56:49 -0400693 return true;
694
Ethan Nicholase6592142020-09-08 10:22:09 -0400695 case Type::TypeKind::kScalar:
Ethan Nicholasf70f0442020-09-29 12:41:35 -0400696 SkASSERT(constructor.arguments().size() == 1);
697 return is_constant<T>(*constructor.arguments()[0], value);
John Stiles9d944232020-08-19 09:56:49 -0400698
699 default:
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400700 return false;
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400701 }
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400702 }
703 return false;
704 }
Ethan Nicholascb670962017-04-20 19:31:52 -0400705 default:
706 return false;
707 }
708}
709
710/**
711 * Collapses the binary expression pointed to by iter down to just the right side (in both the IR
712 * and CFG structures).
713 */
John Stilesafbf8992020-08-18 10:08:21 -0400714static void delete_left(BasicBlock* b,
715 std::vector<BasicBlock::Node>::iterator* iter,
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400716 Compiler::OptimizationContext* optimizationContext) {
717 optimizationContext->fUpdated = true;
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400718 std::unique_ptr<Expression>* target = (*iter)->expression();
John Stilesa5a97b42020-08-18 11:19:07 -0400719 BinaryExpression& bin = (*target)->as<BinaryExpression>();
John Stiles2d4f9592020-10-30 10:29:12 -0400720 Expression& left = *bin.left();
721 std::unique_ptr<Expression>& rightPointer = bin.right();
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400722 SkASSERT(!left.hasSideEffects());
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400723 bool result;
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400724 if (bin.getOperator() == Token::Kind::TK_EQ) {
725 result = b->tryRemoveLValueBefore(iter, &left);
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400726 } else {
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400727 result = b->tryRemoveExpressionBefore(iter, &left);
Ethan Nicholascb670962017-04-20 19:31:52 -0400728 }
Brian Osman010ce6a2020-10-19 16:34:10 -0400729 // Remove references within LHS.
730 optimizationContext->fUsage->remove(&left);
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400731 *target = std::move(rightPointer);
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400732 if (!result) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400733 optimizationContext->fNeedsRescan = true;
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400734 return;
735 }
736 if (*iter == b->fNodes.begin()) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400737 optimizationContext->fNeedsRescan = true;
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400738 return;
739 }
740 --(*iter);
John Stiles70025e52020-09-28 16:08:58 -0400741 if (!(*iter)->isExpression() || (*iter)->expression() != &rightPointer) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400742 optimizationContext->fNeedsRescan = true;
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400743 return;
744 }
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400745 *iter = b->fNodes.erase(*iter);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400746 SkASSERT((*iter)->expression() == target);
Ethan Nicholascb670962017-04-20 19:31:52 -0400747}
748
749/**
750 * Collapses the binary expression pointed to by iter down to just the left side (in both the IR and
751 * CFG structures).
752 */
John Stilesafbf8992020-08-18 10:08:21 -0400753static void delete_right(BasicBlock* b,
754 std::vector<BasicBlock::Node>::iterator* iter,
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400755 Compiler::OptimizationContext* optimizationContext) {
756 optimizationContext->fUpdated = true;
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400757 std::unique_ptr<Expression>* target = (*iter)->expression();
John Stilesa5a97b42020-08-18 11:19:07 -0400758 BinaryExpression& bin = (*target)->as<BinaryExpression>();
John Stiles2d4f9592020-10-30 10:29:12 -0400759 std::unique_ptr<Expression>& leftPointer = bin.left();
760 Expression& right = *bin.right();
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400761 SkASSERT(!right.hasSideEffects());
Brian Osman010ce6a2020-10-19 16:34:10 -0400762 // Remove references within RHS.
763 optimizationContext->fUsage->remove(&right);
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400764 if (!b->tryRemoveExpressionBefore(iter, &right)) {
765 *target = std::move(leftPointer);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400766 optimizationContext->fNeedsRescan = true;
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400767 return;
Ethan Nicholascb670962017-04-20 19:31:52 -0400768 }
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400769 *target = std::move(leftPointer);
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400770 if (*iter == b->fNodes.begin()) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400771 optimizationContext->fNeedsRescan = true;
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400772 return;
773 }
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400774 --(*iter);
John Stiles70025e52020-09-28 16:08:58 -0400775 if ((!(*iter)->isExpression() || (*iter)->expression() != &leftPointer)) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400776 optimizationContext->fNeedsRescan = true;
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400777 return;
778 }
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400779 *iter = b->fNodes.erase(*iter);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400780 SkASSERT((*iter)->expression() == target);
Ethan Nicholascb670962017-04-20 19:31:52 -0400781}
782
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400783/**
784 * Constructs the specified type using a single argument.
785 */
Ethan Nicholas30d30222020-09-11 12:27:26 -0400786static std::unique_ptr<Expression> construct(const Type* type, std::unique_ptr<Expression> v) {
John Stiles8e3b6be2020-10-13 11:14:08 -0400787 ExpressionArray args;
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400788 args.push_back(std::move(v));
Ethan Nicholase6592142020-09-08 10:22:09 -0400789 std::unique_ptr<Expression> result = std::make_unique<Constructor>(-1, type, std::move(args));
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400790 return result;
791}
792
793/**
794 * Used in the implementations of vectorize_left and vectorize_right. Given a vector type and an
795 * expression x, deletes the expression pointed to by iter and replaces it with <type>(x).
796 */
797static void vectorize(BasicBlock* b,
798 std::vector<BasicBlock::Node>::iterator* iter,
799 const Type& type,
800 std::unique_ptr<Expression>* otherExpression,
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400801 Compiler::OptimizationContext* optimizationContext) {
Ethan Nicholase6592142020-09-08 10:22:09 -0400802 SkASSERT((*(*iter)->expression())->kind() == Expression::Kind::kBinary);
803 SkASSERT(type.typeKind() == Type::TypeKind::kVector);
Ethan Nicholas30d30222020-09-11 12:27:26 -0400804 SkASSERT((*otherExpression)->type().typeKind() == Type::TypeKind::kScalar);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400805 optimizationContext->fUpdated = true;
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400806 std::unique_ptr<Expression>* target = (*iter)->expression();
807 if (!b->tryRemoveExpression(iter)) {
Ethan Nicholas30d30222020-09-11 12:27:26 -0400808 *target = construct(&type, std::move(*otherExpression));
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400809 optimizationContext->fNeedsRescan = true;
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400810 } else {
Ethan Nicholas30d30222020-09-11 12:27:26 -0400811 *target = construct(&type, std::move(*otherExpression));
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400812 if (!b->tryInsertExpression(iter, target)) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400813 optimizationContext->fNeedsRescan = true;
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400814 }
815 }
816}
817
818/**
819 * Given a binary expression of the form x <op> vec<n>(y), deletes the right side and vectorizes the
820 * left to yield vec<n>(x).
821 */
822static void vectorize_left(BasicBlock* b,
823 std::vector<BasicBlock::Node>::iterator* iter,
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400824 Compiler::OptimizationContext* optimizationContext) {
John Stilesa5a97b42020-08-18 11:19:07 -0400825 BinaryExpression& bin = (*(*iter)->expression())->as<BinaryExpression>();
Brian Osman010ce6a2020-10-19 16:34:10 -0400826 // Remove references within RHS. Vectorization of LHS doesn't change reference counts.
John Stiles2d4f9592020-10-30 10:29:12 -0400827 optimizationContext->fUsage->remove(bin.right().get());
828 vectorize(b, iter, bin.right()->type(), &bin.left(), optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400829}
830
831/**
832 * Given a binary expression of the form vec<n>(x) <op> y, deletes the left side and vectorizes the
833 * right to yield vec<n>(y).
834 */
835static void vectorize_right(BasicBlock* b,
836 std::vector<BasicBlock::Node>::iterator* iter,
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400837 Compiler::OptimizationContext* optimizationContext) {
John Stilesa5a97b42020-08-18 11:19:07 -0400838 BinaryExpression& bin = (*(*iter)->expression())->as<BinaryExpression>();
Brian Osman010ce6a2020-10-19 16:34:10 -0400839 // Remove references within LHS. Vectorization of RHS doesn't change reference counts.
John Stiles2d4f9592020-10-30 10:29:12 -0400840 optimizationContext->fUsage->remove(bin.left().get());
841 vectorize(b, iter, bin.left()->type(), &bin.right(), optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400842}
843
844// Mark that an expression which we were writing to is no longer being written to
John Stilesa5a97b42020-08-18 11:19:07 -0400845static void clear_write(Expression& expr) {
Ethan Nicholase6592142020-09-08 10:22:09 -0400846 switch (expr.kind()) {
847 case Expression::Kind::kVariableReference: {
Ethan Nicholas453f67f2020-10-09 10:43:45 -0400848 expr.as<VariableReference>().setRefKind(VariableReference::RefKind::kRead);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400849 break;
850 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400851 case Expression::Kind::kFieldAccess:
Ethan Nicholas7a95b202020-10-09 11:55:40 -0400852 clear_write(*expr.as<FieldAccess>().base());
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400853 break;
Ethan Nicholase6592142020-09-08 10:22:09 -0400854 case Expression::Kind::kSwizzle:
Ethan Nicholas6b4d5812020-10-12 16:11:51 -0400855 clear_write(*expr.as<Swizzle>().base());
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400856 break;
Ethan Nicholase6592142020-09-08 10:22:09 -0400857 case Expression::Kind::kIndex:
Ethan Nicholas2a4952d2020-10-08 15:35:56 -0400858 clear_write(*expr.as<IndexExpression>().base());
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400859 break;
860 default:
861 ABORT("shouldn't be writing to this kind of expression\n");
862 break;
863 }
864}
865
Ethan Nicholascb670962017-04-20 19:31:52 -0400866void Compiler::simplifyExpression(DefinitionMap& definitions,
867 BasicBlock& b,
868 std::vector<BasicBlock::Node>::iterator* iter,
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400869 OptimizationContext* optimizationContext) {
Ethan Nicholascb670962017-04-20 19:31:52 -0400870 Expression* expr = (*iter)->expression()->get();
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400871 SkASSERT(expr);
Ethan Nicholascb670962017-04-20 19:31:52 -0400872 if ((*iter)->fConstantPropagation) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400873 std::unique_ptr<Expression> optimized = expr->constantPropagate(*fIRGenerator,
874 definitions);
Ethan Nicholascb670962017-04-20 19:31:52 -0400875 if (optimized) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400876 optimizationContext->fUpdated = true;
Ethan Nicholas30d30222020-09-11 12:27:26 -0400877 optimized = fIRGenerator->coerce(std::move(optimized), expr->type());
Ethan Nicholas1d881522020-09-11 09:32:54 -0400878 SkASSERT(optimized);
Brian Osman010ce6a2020-10-19 16:34:10 -0400879 // Remove references within 'expr', add references within 'optimized'
880 optimizationContext->fUsage->replace(expr, optimized.get());
Ethan Nicholascb670962017-04-20 19:31:52 -0400881 if (!try_replace_expression(&b, iter, &optimized)) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400882 optimizationContext->fNeedsRescan = true;
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400883 return;
Ethan Nicholascb670962017-04-20 19:31:52 -0400884 }
John Stiles70025e52020-09-28 16:08:58 -0400885 SkASSERT((*iter)->isExpression());
Ethan Nicholascb670962017-04-20 19:31:52 -0400886 expr = (*iter)->expression()->get();
Ethan Nicholascb670962017-04-20 19:31:52 -0400887 }
888 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400889 switch (expr->kind()) {
890 case Expression::Kind::kVariableReference: {
John Stilesa5a97b42020-08-18 11:19:07 -0400891 const VariableReference& ref = expr->as<VariableReference>();
Ethan Nicholas78686922020-10-08 06:46:27 -0400892 const Variable* var = ref.variable();
Ethan Nicholas453f67f2020-10-09 10:43:45 -0400893 if (ref.refKind() != VariableReference::RefKind::kWrite &&
894 ref.refKind() != VariableReference::RefKind::kPointer &&
895 var->storage() == Variable::Storage::kLocal && !definitions[var] &&
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400896 optimizationContext->fSilences.find(var) == optimizationContext->fSilences.end()) {
897 optimizationContext->fSilences.insert(var);
Ethan Nicholas82a62d22017-11-07 14:42:10 +0000898 this->error(expr->fOffset,
Ethan Nicholase2c49992020-10-05 11:49:11 -0400899 "'" + var->name() + "' has not been assigned");
Ethan Nicholascb670962017-04-20 19:31:52 -0400900 }
901 break;
902 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400903 case Expression::Kind::kTernary: {
John Stiles403a3632020-08-20 12:11:48 -0400904 TernaryExpression* t = &expr->as<TernaryExpression>();
Ethan Nicholasdd218162020-10-08 05:48:01 -0400905 if (t->test()->is<BoolLiteral>()) {
Ethan Nicholascb670962017-04-20 19:31:52 -0400906 // ternary has a constant test, replace it with either the true or
907 // false branch
Ethan Nicholasdd218162020-10-08 05:48:01 -0400908 if (t->test()->as<BoolLiteral>().value()) {
Brian Osman010ce6a2020-10-19 16:34:10 -0400909 (*iter)->setExpression(std::move(t->ifTrue()), optimizationContext->fUsage);
Ethan Nicholascb670962017-04-20 19:31:52 -0400910 } else {
Brian Osman010ce6a2020-10-19 16:34:10 -0400911 (*iter)->setExpression(std::move(t->ifFalse()), optimizationContext->fUsage);
Ethan Nicholascb670962017-04-20 19:31:52 -0400912 }
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400913 optimizationContext->fUpdated = true;
914 optimizationContext->fNeedsRescan = true;
Ethan Nicholascb670962017-04-20 19:31:52 -0400915 }
916 break;
917 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400918 case Expression::Kind::kBinary: {
John Stiles403a3632020-08-20 12:11:48 -0400919 BinaryExpression* bin = &expr->as<BinaryExpression>();
Brian Osman010ce6a2020-10-19 16:34:10 -0400920 if (dead_assignment(*bin, optimizationContext->fUsage)) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400921 delete_left(&b, iter, optimizationContext);
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400922 break;
923 }
John Stiles2d4f9592020-10-30 10:29:12 -0400924 Expression& left = *bin->left();
925 Expression& right = *bin->right();
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400926 const Type& leftType = left.type();
927 const Type& rightType = right.type();
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400928 // collapse useless expressions like x * 1 or x + 0
Ethan Nicholas30d30222020-09-11 12:27:26 -0400929 if (((leftType.typeKind() != Type::TypeKind::kScalar) &&
930 (leftType.typeKind() != Type::TypeKind::kVector)) ||
931 ((rightType.typeKind() != Type::TypeKind::kScalar) &&
932 (rightType.typeKind() != Type::TypeKind::kVector))) {
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400933 break;
934 }
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400935 switch (bin->getOperator()) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400936 case Token::Kind::TK_STAR:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400937 if (is_constant(left, 1)) {
Ethan Nicholas30d30222020-09-11 12:27:26 -0400938 if (leftType.typeKind() == Type::TypeKind::kVector &&
939 rightType.typeKind() == Type::TypeKind::kScalar) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400940 // float4(1) * x -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400941 vectorize_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400942 } else {
943 // 1 * x -> x
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400944 // 1 * float4(x) -> float4(x)
945 // float4(1) * float4(x) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400946 delete_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400947 }
948 }
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400949 else if (is_constant(left, 0)) {
Ethan Nicholas30d30222020-09-11 12:27:26 -0400950 if (leftType.typeKind() == Type::TypeKind::kScalar &&
951 rightType.typeKind() == Type::TypeKind::kVector &&
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400952 !right.hasSideEffects()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400953 // 0 * float4(x) -> float4(0)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400954 vectorize_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400955 } else {
956 // 0 * x -> 0
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400957 // float4(0) * x -> float4(0)
958 // float4(0) * float4(x) -> float4(0)
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400959 if (!right.hasSideEffects()) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400960 delete_right(&b, iter, optimizationContext);
Ethan Nicholas51493ee2017-12-11 12:34:33 -0500961 }
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400962 }
Ethan Nicholascb670962017-04-20 19:31:52 -0400963 }
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400964 else if (is_constant(right, 1)) {
Ethan Nicholas30d30222020-09-11 12:27:26 -0400965 if (leftType.typeKind() == Type::TypeKind::kScalar &&
966 rightType.typeKind() == Type::TypeKind::kVector) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400967 // x * float4(1) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400968 vectorize_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400969 } else {
970 // x * 1 -> x
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400971 // float4(x) * 1 -> float4(x)
972 // float4(x) * float4(1) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400973 delete_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400974 }
975 }
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400976 else if (is_constant(right, 0)) {
Ethan Nicholas30d30222020-09-11 12:27:26 -0400977 if (leftType.typeKind() == Type::TypeKind::kVector &&
978 rightType.typeKind() == Type::TypeKind::kScalar &&
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400979 !left.hasSideEffects()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400980 // float4(x) * 0 -> float4(0)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400981 vectorize_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400982 } else {
983 // x * 0 -> 0
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400984 // x * float4(0) -> float4(0)
985 // float4(x) * float4(0) -> float4(0)
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400986 if (!left.hasSideEffects()) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400987 delete_left(&b, iter, optimizationContext);
Ethan Nicholas51493ee2017-12-11 12:34:33 -0500988 }
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400989 }
Ethan Nicholascb670962017-04-20 19:31:52 -0400990 }
991 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400992 case Token::Kind::TK_PLUS:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400993 if (is_constant(left, 0)) {
Ethan Nicholas30d30222020-09-11 12:27:26 -0400994 if (leftType.typeKind() == Type::TypeKind::kVector &&
995 rightType.typeKind() == Type::TypeKind::kScalar) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400996 // float4(0) + x -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400997 vectorize_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400998 } else {
999 // 0 + x -> x
Ethan Nicholas5af9ea32017-07-28 15:19:46 -04001000 // 0 + float4(x) -> float4(x)
1001 // float4(0) + float4(x) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001002 delete_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -04001003 }
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -04001004 } else if (is_constant(right, 0)) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001005 if (leftType.typeKind() == Type::TypeKind::kScalar &&
1006 rightType.typeKind() == Type::TypeKind::kVector) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -04001007 // x + float4(0) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001008 vectorize_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -04001009 } else {
1010 // x + 0 -> x
Ethan Nicholas5af9ea32017-07-28 15:19:46 -04001011 // float4(x) + 0 -> float4(x)
1012 // float4(x) + float4(0) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001013 delete_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -04001014 }
Ethan Nicholas56e42712017-04-21 10:23:37 -04001015 }
1016 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001017 case Token::Kind::TK_MINUS:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -04001018 if (is_constant(right, 0)) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001019 if (leftType.typeKind() == Type::TypeKind::kScalar &&
1020 rightType.typeKind() == Type::TypeKind::kVector) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -04001021 // x - float4(0) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001022 vectorize_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -04001023 } else {
1024 // x - 0 -> x
Ethan Nicholas5af9ea32017-07-28 15:19:46 -04001025 // float4(x) - 0 -> float4(x)
1026 // float4(x) - float4(0) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001027 delete_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -04001028 }
Ethan Nicholascb670962017-04-20 19:31:52 -04001029 }
1030 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001031 case Token::Kind::TK_SLASH:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -04001032 if (is_constant(right, 1)) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001033 if (leftType.typeKind() == Type::TypeKind::kScalar &&
1034 rightType.typeKind() == Type::TypeKind::kVector) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -04001035 // x / float4(1) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001036 vectorize_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -04001037 } else {
1038 // x / 1 -> x
Ethan Nicholas5af9ea32017-07-28 15:19:46 -04001039 // float4(x) / 1 -> float4(x)
1040 // float4(x) / float4(1) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001041 delete_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -04001042 }
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -04001043 } else if (is_constant(left, 0)) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001044 if (leftType.typeKind() == Type::TypeKind::kScalar &&
1045 rightType.typeKind() == Type::TypeKind::kVector &&
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -04001046 !right.hasSideEffects()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -04001047 // 0 / float4(x) -> float4(0)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001048 vectorize_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -04001049 } else {
1050 // 0 / x -> 0
Ethan Nicholas5af9ea32017-07-28 15:19:46 -04001051 // float4(0) / x -> float4(0)
1052 // float4(0) / float4(x) -> float4(0)
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -04001053 if (!right.hasSideEffects()) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001054 delete_right(&b, iter, optimizationContext);
Ethan Nicholas51493ee2017-12-11 12:34:33 -05001055 }
Ethan Nicholasfe53e582017-04-27 16:24:51 -04001056 }
1057 }
1058 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001059 case Token::Kind::TK_PLUSEQ:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -04001060 if (is_constant(right, 0)) {
1061 clear_write(left);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001062 delete_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -04001063 }
1064 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001065 case Token::Kind::TK_MINUSEQ:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -04001066 if (is_constant(right, 0)) {
1067 clear_write(left);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001068 delete_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -04001069 }
1070 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001071 case Token::Kind::TK_STAREQ:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -04001072 if (is_constant(right, 1)) {
1073 clear_write(left);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001074 delete_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -04001075 }
1076 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001077 case Token::Kind::TK_SLASHEQ:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -04001078 if (is_constant(right, 1)) {
1079 clear_write(left);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001080 delete_right(&b, iter, optimizationContext);
Ethan Nicholascb670962017-04-20 19:31:52 -04001081 }
1082 break;
1083 default:
1084 break;
1085 }
Ethan Nicholas409f6f02019-09-17 12:34:39 -04001086 break;
1087 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001088 case Expression::Kind::kSwizzle: {
John Stiles403a3632020-08-20 12:11:48 -04001089 Swizzle& s = expr->as<Swizzle>();
Ethan Nicholas409f6f02019-09-17 12:34:39 -04001090 // detect identity swizzles like foo.rgba
Ethan Nicholas6b4d5812020-10-12 16:11:51 -04001091 if ((int) s.components().size() == s.base()->type().columns()) {
Ethan Nicholas409f6f02019-09-17 12:34:39 -04001092 bool identity = true;
Ethan Nicholas6b4d5812020-10-12 16:11:51 -04001093 for (int i = 0; i < (int) s.components().size(); ++i) {
1094 if (s.components()[i] != i) {
Ethan Nicholas409f6f02019-09-17 12:34:39 -04001095 identity = false;
1096 break;
1097 }
1098 }
1099 if (identity) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001100 optimizationContext->fUpdated = true;
Brian Osman010ce6a2020-10-19 16:34:10 -04001101 // No fUsage change: foo.rgba and foo have equivalent reference counts
Ethan Nicholas6b4d5812020-10-12 16:11:51 -04001102 if (!try_replace_expression(&b, iter, &s.base())) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001103 optimizationContext->fNeedsRescan = true;
Ethan Nicholas409f6f02019-09-17 12:34:39 -04001104 return;
1105 }
John Stiles70025e52020-09-28 16:08:58 -04001106 SkASSERT((*iter)->isExpression());
Ethan Nicholas409f6f02019-09-17 12:34:39 -04001107 break;
1108 }
1109 }
1110 // detect swizzles of swizzles, e.g. replace foo.argb.r000 with foo.a000
Ethan Nicholas6b4d5812020-10-12 16:11:51 -04001111 if (s.base()->kind() == Expression::Kind::kSwizzle) {
1112 Swizzle& base = s.base()->as<Swizzle>();
John Stiles750109b2020-10-30 13:45:46 -04001113 ComponentArray final;
Ethan Nicholas6b4d5812020-10-12 16:11:51 -04001114 for (int c : s.components()) {
1115 final.push_back(base.components()[c]);
Ethan Nicholas409f6f02019-09-17 12:34:39 -04001116 }
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001117 optimizationContext->fUpdated = true;
Ethan Nicholas6b4d5812020-10-12 16:11:51 -04001118 std::unique_ptr<Expression> replacement(new Swizzle(*fContext, base.base()->clone(),
John Stiles750109b2020-10-30 13:45:46 -04001119 final));
Brian Osman010ce6a2020-10-19 16:34:10 -04001120 // No fUsage change: foo.gbr.gbr and foo.brg have equivalent reference counts
Ethan Nicholas409f6f02019-09-17 12:34:39 -04001121 if (!try_replace_expression(&b, iter, &replacement)) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001122 optimizationContext->fNeedsRescan = true;
Ethan Nicholas409f6f02019-09-17 12:34:39 -04001123 return;
1124 }
John Stiles70025e52020-09-28 16:08:58 -04001125 SkASSERT((*iter)->isExpression());
Ethan Nicholas409f6f02019-09-17 12:34:39 -04001126 }
John Stiles30212b72020-06-11 17:55:07 -04001127 break;
Ethan Nicholascb670962017-04-20 19:31:52 -04001128 }
1129 default:
1130 break;
1131 }
1132}
1133
John Stiles92219b42020-06-15 12:32:24 -04001134// Returns true if this statement could potentially execute a break at the current level. We ignore
1135// nested loops and switches, since any breaks inside of them will merely break the loop / switch.
John Stilesb92641c2020-08-31 18:09:01 -04001136static bool contains_conditional_break(Statement& stmt) {
1137 class ContainsConditionalBreak : public ProgramVisitor {
1138 public:
1139 bool visitStatement(const Statement& stmt) override {
Ethan Nicholase6592142020-09-08 10:22:09 -04001140 switch (stmt.kind()) {
1141 case Statement::Kind::kBlock:
John Stilesb92641c2020-08-31 18:09:01 -04001142 return this->INHERITED::visitStatement(stmt);
1143
Ethan Nicholase6592142020-09-08 10:22:09 -04001144 case Statement::Kind::kBreak:
John Stilesb92641c2020-08-31 18:09:01 -04001145 return fInConditional > 0;
1146
Ethan Nicholase6592142020-09-08 10:22:09 -04001147 case Statement::Kind::kIf: {
John Stilesb92641c2020-08-31 18:09:01 -04001148 ++fInConditional;
1149 bool result = this->INHERITED::visitStatement(stmt);
1150 --fInConditional;
1151 return result;
1152 }
1153
1154 default:
1155 return false;
1156 }
1157 }
1158
1159 int fInConditional = 0;
1160 using INHERITED = ProgramVisitor;
1161 };
1162
1163 return ContainsConditionalBreak{}.visitStatement(stmt);
John Stiles92219b42020-06-15 12:32:24 -04001164}
1165
Ethan Nicholas5005a222018-08-24 13:06:27 -04001166// returns true if this statement definitely executes a break at the current level (we ignore
1167// nested loops and switches, since any breaks inside of them will merely break the loop / switch)
John Stilesb92641c2020-08-31 18:09:01 -04001168static bool contains_unconditional_break(Statement& stmt) {
1169 class ContainsUnconditionalBreak : public ProgramVisitor {
1170 public:
1171 bool visitStatement(const Statement& stmt) override {
Ethan Nicholase6592142020-09-08 10:22:09 -04001172 switch (stmt.kind()) {
1173 case Statement::Kind::kBlock:
John Stilesb92641c2020-08-31 18:09:01 -04001174 return this->INHERITED::visitStatement(stmt);
1175
Ethan Nicholase6592142020-09-08 10:22:09 -04001176 case Statement::Kind::kBreak:
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001177 return true;
John Stilesb92641c2020-08-31 18:09:01 -04001178
1179 default:
1180 return false;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001181 }
John Stilesb92641c2020-08-31 18:09:01 -04001182 }
John Stiles92219b42020-06-15 12:32:24 -04001183
John Stilesb92641c2020-08-31 18:09:01 -04001184 using INHERITED = ProgramVisitor;
1185 };
John Stiles92219b42020-06-15 12:32:24 -04001186
John Stilesb92641c2020-08-31 18:09:01 -04001187 return ContainsUnconditionalBreak{}.visitStatement(stmt);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001188}
1189
John Stiles8f2a0cf2020-10-13 12:48:21 -04001190static void move_all_but_break(std::unique_ptr<Statement>& stmt, StatementArray* target) {
Ethan Nicholase6592142020-09-08 10:22:09 -04001191 switch (stmt->kind()) {
1192 case Statement::Kind::kBlock: {
John Stiles92219b42020-06-15 12:32:24 -04001193 // Recurse into the block.
1194 Block& block = static_cast<Block&>(*stmt);
1195
John Stiles8f2a0cf2020-10-13 12:48:21 -04001196 StatementArray blockStmts;
John Stilesf4bda742020-10-14 16:57:41 -04001197 blockStmts.reserve_back(block.children().size());
Ethan Nicholas7bd60432020-09-25 14:31:59 -04001198 for (std::unique_ptr<Statement>& stmt : block.children()) {
1199 move_all_but_break(stmt, &blockStmts);
Ethan Nicholas739e1ca2020-06-11 12:16:14 -04001200 }
John Stiles92219b42020-06-15 12:32:24 -04001201
1202 target->push_back(std::make_unique<Block>(block.fOffset, std::move(blockStmts),
Ethan Nicholas7bd60432020-09-25 14:31:59 -04001203 block.symbolTable(), block.isScope()));
Ethan Nicholas739e1ca2020-06-11 12:16:14 -04001204 break;
John Stiles92219b42020-06-15 12:32:24 -04001205 }
1206
Ethan Nicholase6592142020-09-08 10:22:09 -04001207 case Statement::Kind::kBreak:
John Stiles92219b42020-06-15 12:32:24 -04001208 // Do not append a break to the target.
1209 break;
1210
Ethan Nicholas739e1ca2020-06-11 12:16:14 -04001211 default:
John Stiles92219b42020-06-15 12:32:24 -04001212 // Append normal statements to the target.
1213 target->push_back(std::move(stmt));
1214 break;
Ethan Nicholas739e1ca2020-06-11 12:16:14 -04001215 }
1216}
1217
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001218// Returns a block containing all of the statements that will be run if the given case matches
1219// (which, owing to the statements being owned by unique_ptrs, means the switch itself will be
1220// broken by this call and must then be discarded).
1221// Returns null (and leaves the switch unmodified) if no such simple reduction is possible, such as
1222// when break statements appear inside conditionals.
John Stiles92219b42020-06-15 12:32:24 -04001223static std::unique_ptr<Statement> block_for_case(SwitchStatement* switchStatement,
1224 SwitchCase* caseToCapture) {
1225 // We have to be careful to not move any of the pointers until after we're sure we're going to
1226 // succeed, so before we make any changes at all, we check the switch-cases to decide on a plan
1227 // of action. First, find the switch-case we are interested in.
Ethan Nicholas01b05e52020-10-22 15:53:41 -04001228 auto iter = switchStatement->cases().begin();
1229 for (; iter != switchStatement->cases().end(); ++iter) {
John Stiles2d4f9592020-10-30 10:29:12 -04001230 if (iter->get() == caseToCapture) {
John Stiles92219b42020-06-15 12:32:24 -04001231 break;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001232 }
John Stiles92219b42020-06-15 12:32:24 -04001233 }
1234
1235 // Next, walk forward through the rest of the switch. If we find a conditional break, we're
1236 // stuck and can't simplify at all. If we find an unconditional break, we have a range of
1237 // statements that we can use for simplification.
1238 auto startIter = iter;
1239 Statement* unconditionalBreakStmt = nullptr;
Ethan Nicholas01b05e52020-10-22 15:53:41 -04001240 for (; iter != switchStatement->cases().end(); ++iter) {
John Stiles2d4f9592020-10-30 10:29:12 -04001241 for (std::unique_ptr<Statement>& stmt : (*iter)->statements()) {
John Stiles92219b42020-06-15 12:32:24 -04001242 if (contains_conditional_break(*stmt)) {
1243 // We can't reduce switch-cases to a block when they have conditional breaks.
1244 return nullptr;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001245 }
John Stiles92219b42020-06-15 12:32:24 -04001246
1247 if (contains_unconditional_break(*stmt)) {
1248 // We found an unconditional break. We can use this block, but we need to strip
1249 // out the break statement.
1250 unconditionalBreakStmt = stmt.get();
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001251 break;
1252 }
1253 }
John Stiles92219b42020-06-15 12:32:24 -04001254
1255 if (unconditionalBreakStmt != nullptr) {
1256 break;
1257 }
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001258 }
John Stiles92219b42020-06-15 12:32:24 -04001259
1260 // We fell off the bottom of the switch or encountered a break. We know the range of statements
1261 // that we need to move over, and we know it's safe to do so.
John Stiles8f2a0cf2020-10-13 12:48:21 -04001262 StatementArray caseStmts;
John Stiles92219b42020-06-15 12:32:24 -04001263
1264 // We can move over most of the statements as-is.
1265 while (startIter != iter) {
John Stiles2d4f9592020-10-30 10:29:12 -04001266 for (std::unique_ptr<Statement>& stmt : (*startIter)->statements()) {
John Stiles92219b42020-06-15 12:32:24 -04001267 caseStmts.push_back(std::move(stmt));
1268 }
1269 ++startIter;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001270 }
John Stiles92219b42020-06-15 12:32:24 -04001271
1272 // If we found an unconditional break at the end, we need to move what we can while avoiding
1273 // that break.
1274 if (unconditionalBreakStmt != nullptr) {
John Stiles2d4f9592020-10-30 10:29:12 -04001275 for (std::unique_ptr<Statement>& stmt : (*startIter)->statements()) {
John Stiles92219b42020-06-15 12:32:24 -04001276 if (stmt.get() == unconditionalBreakStmt) {
1277 move_all_but_break(stmt, &caseStmts);
1278 unconditionalBreakStmt = nullptr;
1279 break;
1280 }
1281
1282 caseStmts.push_back(std::move(stmt));
1283 }
1284 }
1285
1286 SkASSERT(unconditionalBreakStmt == nullptr); // Verify that we fixed the unconditional break.
1287
1288 // Return our newly-synthesized block.
Ethan Nicholas01b05e52020-10-22 15:53:41 -04001289 return std::make_unique<Block>(/*offset=*/-1, std::move(caseStmts), switchStatement->symbols());
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001290}
1291
Ethan Nicholascb670962017-04-20 19:31:52 -04001292void Compiler::simplifyStatement(DefinitionMap& definitions,
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001293 BasicBlock& b,
1294 std::vector<BasicBlock::Node>::iterator* iter,
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001295 OptimizationContext* optimizationContext) {
Brian Osman010ce6a2020-10-19 16:34:10 -04001296 ProgramUsage* usage = optimizationContext->fUsage;
Ethan Nicholascb670962017-04-20 19:31:52 -04001297 Statement* stmt = (*iter)->statement()->get();
Ethan Nicholase6592142020-09-08 10:22:09 -04001298 switch (stmt->kind()) {
1299 case Statement::Kind::kVarDeclaration: {
John Stilesa5a97b42020-08-18 11:19:07 -04001300 const auto& varDecl = stmt->as<VarDeclaration>();
Brian Osman010ce6a2020-10-19 16:34:10 -04001301 if (usage->isDead(varDecl.var()) &&
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04001302 (!varDecl.value() ||
1303 !varDecl.value()->hasSideEffects())) {
1304 if (varDecl.value()) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001305 SkASSERT((*iter)->statement()->get() == stmt);
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04001306 if (!b.tryRemoveExpressionBefore(iter, varDecl.value().get())) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001307 optimizationContext->fNeedsRescan = true;
Ethan Nicholascb670962017-04-20 19:31:52 -04001308 }
Ethan Nicholascb670962017-04-20 19:31:52 -04001309 }
Brian Osman010ce6a2020-10-19 16:34:10 -04001310 (*iter)->setStatement(std::make_unique<Nop>(), usage);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001311 optimizationContext->fUpdated = true;
Ethan Nicholascb670962017-04-20 19:31:52 -04001312 }
1313 break;
1314 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001315 case Statement::Kind::kIf: {
John Stilesa5a97b42020-08-18 11:19:07 -04001316 IfStatement& i = stmt->as<IfStatement>();
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001317 if (i.test()->kind() == Expression::Kind::kBoolLiteral) {
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001318 // constant if, collapse down to a single branch
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001319 if (i.test()->as<BoolLiteral>().value()) {
1320 SkASSERT(i.ifTrue());
Brian Osman010ce6a2020-10-19 16:34:10 -04001321 (*iter)->setStatement(std::move(i.ifTrue()), usage);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001322 } else {
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001323 if (i.ifFalse()) {
Brian Osman010ce6a2020-10-19 16:34:10 -04001324 (*iter)->setStatement(std::move(i.ifFalse()), usage);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001325 } else {
Brian Osman010ce6a2020-10-19 16:34:10 -04001326 (*iter)->setStatement(std::make_unique<Nop>(), usage);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001327 }
1328 }
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001329 optimizationContext->fUpdated = true;
1330 optimizationContext->fNeedsRescan = true;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001331 break;
1332 }
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001333 if (i.ifFalse() && i.ifFalse()->isEmpty()) {
Ethan Nicholascb670962017-04-20 19:31:52 -04001334 // else block doesn't do anything, remove it
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001335 i.ifFalse().reset();
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001336 optimizationContext->fUpdated = true;
1337 optimizationContext->fNeedsRescan = true;
Ethan Nicholascb670962017-04-20 19:31:52 -04001338 }
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001339 if (!i.ifFalse() && i.ifTrue()->isEmpty()) {
Ethan Nicholascb670962017-04-20 19:31:52 -04001340 // if block doesn't do anything, no else block
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001341 if (i.test()->hasSideEffects()) {
Ethan Nicholascb670962017-04-20 19:31:52 -04001342 // test has side effects, keep it
Brian Osman010ce6a2020-10-19 16:34:10 -04001343 (*iter)->setStatement(
1344 std::make_unique<ExpressionStatement>(std::move(i.test())), usage);
Ethan Nicholascb670962017-04-20 19:31:52 -04001345 } else {
1346 // no if, no else, no test side effects, kill the whole if
1347 // statement
Brian Osman010ce6a2020-10-19 16:34:10 -04001348 (*iter)->setStatement(std::make_unique<Nop>(), usage);
Ethan Nicholascb670962017-04-20 19:31:52 -04001349 }
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001350 optimizationContext->fUpdated = true;
1351 optimizationContext->fNeedsRescan = true;
Ethan Nicholascb670962017-04-20 19:31:52 -04001352 }
1353 break;
1354 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001355 case Statement::Kind::kSwitch: {
John Stilesa5a97b42020-08-18 11:19:07 -04001356 SwitchStatement& s = stmt->as<SwitchStatement>();
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001357 int64_t switchValue;
Ethan Nicholas01b05e52020-10-22 15:53:41 -04001358 if (fIRGenerator->getConstantInt(*s.value(), &switchValue)) {
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001359 // switch is constant, replace it with the case that matches
1360 bool found = false;
1361 SwitchCase* defaultCase = nullptr;
John Stiles2d4f9592020-10-30 10:29:12 -04001362 for (const std::unique_ptr<SwitchCase>& c : s.cases()) {
1363 if (!c->value()) {
1364 defaultCase = c.get();
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001365 continue;
1366 }
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001367 int64_t caseValue;
John Stiles2d4f9592020-10-30 10:29:12 -04001368 SkAssertResult(fIRGenerator->getConstantInt(*c->value(), &caseValue));
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001369 if (caseValue == switchValue) {
John Stiles2d4f9592020-10-30 10:29:12 -04001370 std::unique_ptr<Statement> newBlock = block_for_case(&s, c.get());
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001371 if (newBlock) {
Brian Osman010ce6a2020-10-19 16:34:10 -04001372 (*iter)->setStatement(std::move(newBlock), usage);
John Stiles9d944232020-08-19 09:56:49 -04001373 found = true;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001374 break;
1375 } else {
Ethan Nicholas01b05e52020-10-22 15:53:41 -04001376 if (s.isStatic() && !(fFlags & kPermitInvalidStaticTests_Flag) &&
1377 optimizationContext->fSilences.find(&s) ==
1378 optimizationContext->fSilences.end()) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001379 this->error(s.fOffset,
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001380 "static switch contains non-static conditional break");
Ethan Nicholas01b05e52020-10-22 15:53:41 -04001381 optimizationContext->fSilences.insert(&s);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001382 }
1383 return; // can't simplify
1384 }
1385 }
1386 }
1387 if (!found) {
1388 // no matching case. use default if it exists, or kill the whole thing
1389 if (defaultCase) {
1390 std::unique_ptr<Statement> newBlock = block_for_case(&s, defaultCase);
1391 if (newBlock) {
Brian Osman010ce6a2020-10-19 16:34:10 -04001392 (*iter)->setStatement(std::move(newBlock), usage);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001393 } else {
Ethan Nicholas01b05e52020-10-22 15:53:41 -04001394 if (s.isStatic() && !(fFlags & kPermitInvalidStaticTests_Flag) &&
1395 optimizationContext->fSilences.find(&s) ==
1396 optimizationContext->fSilences.end()) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001397 this->error(s.fOffset,
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001398 "static switch contains non-static conditional break");
Ethan Nicholas01b05e52020-10-22 15:53:41 -04001399 optimizationContext->fSilences.insert(&s);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001400 }
1401 return; // can't simplify
1402 }
1403 } else {
Brian Osman010ce6a2020-10-19 16:34:10 -04001404 (*iter)->setStatement(std::make_unique<Nop>(), usage);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001405 }
1406 }
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001407 optimizationContext->fUpdated = true;
1408 optimizationContext->fNeedsRescan = true;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001409 }
1410 break;
1411 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001412 case Statement::Kind::kExpression: {
John Stilesa5a97b42020-08-18 11:19:07 -04001413 ExpressionStatement& e = stmt->as<ExpressionStatement>();
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001414 SkASSERT((*iter)->statement()->get() == &e);
Ethan Nicholasd503a5a2020-09-30 09:29:55 -04001415 if (!e.expression()->hasSideEffects()) {
Ethan Nicholascb670962017-04-20 19:31:52 -04001416 // Expression statement with no side effects, kill it
Ethan Nicholasd503a5a2020-09-30 09:29:55 -04001417 if (!b.tryRemoveExpressionBefore(iter, e.expression().get())) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001418 optimizationContext->fNeedsRescan = true;
Ethan Nicholascb670962017-04-20 19:31:52 -04001419 }
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001420 SkASSERT((*iter)->statement()->get() == stmt);
Brian Osman010ce6a2020-10-19 16:34:10 -04001421 (*iter)->setStatement(std::make_unique<Nop>(), usage);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001422 optimizationContext->fUpdated = true;
Ethan Nicholascb670962017-04-20 19:31:52 -04001423 }
1424 break;
1425 }
1426 default:
1427 break;
1428 }
1429}
1430
Brian Osman010ce6a2020-10-19 16:34:10 -04001431bool Compiler::scanCFG(FunctionDefinition& f, ProgramUsage* usage) {
John Stiles0cc193a2020-09-09 09:39:34 -04001432 bool madeChanges = false;
1433
Ethan Nicholascb670962017-04-20 19:31:52 -04001434 CFG cfg = CFGGenerator().getCFG(f);
1435 this->computeDataFlow(&cfg);
ethannicholas22f939e2016-10-13 13:25:34 -07001436
1437 // check for unreachable code
1438 for (size_t i = 0; i < cfg.fBlocks.size(); i++) {
John Stiles0cc193a2020-09-09 09:39:34 -04001439 const BasicBlock& block = cfg.fBlocks[i];
John Stiles61e75e32020-10-01 15:42:37 -04001440 if (i != cfg.fStart && !block.fIsReachable && block.fNodes.size()) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001441 int offset;
John Stiles0cc193a2020-09-09 09:39:34 -04001442 const BasicBlock::Node& node = block.fNodes[0];
John Stiles70025e52020-09-28 16:08:58 -04001443 if (node.isStatement()) {
1444 offset = (*node.statement())->fOffset;
1445 } else {
1446 offset = (*node.expression())->fOffset;
1447 if ((*node.expression())->is<BoolLiteral>()) {
1448 // Function inlining can generate do { ... } while(false) loops which always
1449 // break, so the boolean condition is considered unreachable. Since not being
1450 // able to reach a literal is a non-issue in the first place, we don't report an
1451 // error in this case.
1452 continue;
1453 }
Ethan Nicholas86a43402017-01-19 13:32:00 -05001454 }
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001455 this->error(offset, String("unreachable"));
ethannicholas22f939e2016-10-13 13:25:34 -07001456 }
1457 }
1458 if (fErrorCount) {
John Stiles0cc193a2020-09-09 09:39:34 -04001459 return madeChanges;
ethannicholas22f939e2016-10-13 13:25:34 -07001460 }
1461
Ethan Nicholascb670962017-04-20 19:31:52 -04001462 // check for dead code & undefined variables, perform constant propagation
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001463 OptimizationContext optimizationContext;
Brian Osman010ce6a2020-10-19 16:34:10 -04001464 optimizationContext.fUsage = usage;
John Stiles7d3f0892020-11-03 11:35:01 -05001465 SkBitSet eliminatedBlockIds(cfg.fBlocks.size());
Ethan Nicholascb670962017-04-20 19:31:52 -04001466 do {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001467 if (optimizationContext.fNeedsRescan) {
Ethan Nicholascb670962017-04-20 19:31:52 -04001468 cfg = CFGGenerator().getCFG(f);
1469 this->computeDataFlow(&cfg);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001470 optimizationContext.fNeedsRescan = false;
Ethan Nicholas113628d2017-02-02 16:11:39 -05001471 }
Ethan Nicholascb670962017-04-20 19:31:52 -04001472
John Stiles7d3f0892020-11-03 11:35:01 -05001473 eliminatedBlockIds.reset();
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001474 optimizationContext.fUpdated = false;
John Stiles7d3f0892020-11-03 11:35:01 -05001475
1476 for (BlockId blockId = 0; blockId < cfg.fBlocks.size(); ++blockId) {
1477 if (eliminatedBlockIds.test(blockId)) {
1478 // We reached a block ID that might have been eliminated. Be cautious and rescan.
1479 optimizationContext.fUpdated = true;
1480 optimizationContext.fNeedsRescan = true;
1481 break;
1482 }
1483
1484 BasicBlock& b = cfg.fBlocks[blockId];
1485 if (blockId > 0 && !b.fIsReachable) {
Ethan Nicholas1de14812020-06-19 15:32:49 -04001486 // Block was reachable before optimization, but has since become unreachable. In
1487 // addition to being dead code, it's broken - since control flow can't reach it, no
1488 // prior variable definitions can reach it, and therefore variables might look to
Brian Osmanc0213602020-10-06 14:43:32 -04001489 // have not been properly assigned. Kill it by replacing all statements with Nops.
Ethan Nicholas1de14812020-06-19 15:32:49 -04001490 for (BasicBlock::Node& node : b.fNodes) {
John Stiles70025e52020-09-28 16:08:58 -04001491 if (node.isStatement() && !(*node.statement())->is<Nop>()) {
John Stiles7d3f0892020-11-03 11:35:01 -05001492 // Eliminating a node runs the risk of eliminating that node's exits as
1493 // well. Keep track of this and do a rescan if we are about to access one
1494 // of these.
1495 for (BlockId id : b.fExits) {
1496 eliminatedBlockIds.set(id);
1497 }
Brian Osman010ce6a2020-10-19 16:34:10 -04001498 node.setStatement(std::make_unique<Nop>(), usage);
John Stiles0cc193a2020-09-09 09:39:34 -04001499 madeChanges = true;
Ethan Nicholas1de14812020-06-19 15:32:49 -04001500 }
1501 }
1502 continue;
1503 }
Ethan Nicholascb670962017-04-20 19:31:52 -04001504 DefinitionMap definitions = b.fBefore;
1505
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001506 for (auto iter = b.fNodes.begin(); iter != b.fNodes.end() &&
1507 !optimizationContext.fNeedsRescan; ++iter) {
John Stiles70025e52020-09-28 16:08:58 -04001508 if (iter->isExpression()) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001509 this->simplifyExpression(definitions, b, &iter, &optimizationContext);
Ethan Nicholascb670962017-04-20 19:31:52 -04001510 } else {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001511 this->simplifyStatement(definitions, b, &iter, &optimizationContext);
Ethan Nicholascb670962017-04-20 19:31:52 -04001512 }
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001513 if (optimizationContext.fNeedsRescan) {
Ethan Nicholas4b330df2017-05-17 10:52:55 -04001514 break;
1515 }
Ethan Nicholascb670962017-04-20 19:31:52 -04001516 this->addDefinitions(*iter, &definitions);
1517 }
Brian Osman01a3eb42020-09-14 11:32:49 -04001518
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001519 if (optimizationContext.fNeedsRescan) {
Brian Osman01a3eb42020-09-14 11:32:49 -04001520 break;
1521 }
Ethan Nicholascb670962017-04-20 19:31:52 -04001522 }
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001523 madeChanges |= optimizationContext.fUpdated;
1524 } while (optimizationContext.fUpdated);
1525 SkASSERT(!optimizationContext.fNeedsRescan);
ethannicholas22f939e2016-10-13 13:25:34 -07001526
Ethan Nicholas91a10532017-06-22 11:24:38 -04001527 // verify static ifs & switches, clean up dead variable decls
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001528 for (BasicBlock& b : cfg.fBlocks) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001529 for (auto iter = b.fNodes.begin(); iter != b.fNodes.end() &&
1530 !optimizationContext.fNeedsRescan;) {
John Stiles70025e52020-09-28 16:08:58 -04001531 if (iter->isStatement()) {
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001532 const Statement& s = **iter->statement();
Ethan Nicholase6592142020-09-08 10:22:09 -04001533 switch (s.kind()) {
1534 case Statement::Kind::kIf:
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001535 if (s.as<IfStatement>().isStatic() &&
Ethan Nicholas6e1cbc02017-07-14 10:12:15 -04001536 !(fFlags & kPermitInvalidStaticTests_Flag)) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001537 this->error(s.fOffset, "static if has non-static test");
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001538 }
Ethan Nicholas91a10532017-06-22 11:24:38 -04001539 ++iter;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001540 break;
Ethan Nicholase6592142020-09-08 10:22:09 -04001541 case Statement::Kind::kSwitch:
Ethan Nicholas01b05e52020-10-22 15:53:41 -04001542 if (s.as<SwitchStatement>().isStatic() &&
1543 !(fFlags & kPermitInvalidStaticTests_Flag) &&
1544 optimizationContext.fSilences.find(&s) ==
1545 optimizationContext.fSilences.end()) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001546 this->error(s.fOffset, "static switch has non-static test");
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001547 }
Ethan Nicholas91a10532017-06-22 11:24:38 -04001548 ++iter;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001549 break;
1550 default:
Ethan Nicholas91a10532017-06-22 11:24:38 -04001551 ++iter;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001552 break;
1553 }
Ethan Nicholas91a10532017-06-22 11:24:38 -04001554 } else {
1555 ++iter;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001556 }
1557 }
1558 }
1559
ethannicholas22f939e2016-10-13 13:25:34 -07001560 // check for missing return
Ethan Nicholas0a5d0962020-10-14 13:33:18 -04001561 if (f.declaration().returnType() != *fContext->fVoid_Type) {
John Stiles61e75e32020-10-01 15:42:37 -04001562 if (cfg.fBlocks[cfg.fExit].fIsReachable) {
Ethan Nicholas0a5d0962020-10-14 13:33:18 -04001563 this->error(f.fOffset, String("function '" + String(f.declaration().name()) +
Ethan Nicholasdb80f692019-11-22 14:06:12 -05001564 "' can exit without returning a value"));
ethannicholas22f939e2016-10-13 13:25:34 -07001565 }
1566 }
John Stiles0cc193a2020-09-09 09:39:34 -04001567
1568 return madeChanges;
ethannicholas22f939e2016-10-13 13:25:34 -07001569}
1570
Brian Osman32d53552020-09-23 13:55:20 -04001571std::unique_ptr<Program> Compiler::convertProgram(
1572 Program::Kind kind,
1573 String text,
1574 const Program::Settings& settings,
1575 const std::vector<std::unique_ptr<ExternalValue>>* externalValues) {
1576 SkASSERT(!externalValues || (kind == Program::kGeneric_Kind));
Ethan Nicholas91164d12019-05-15 15:29:54 -04001577
ethannicholasb3058bd2016-07-01 08:22:01 -07001578 fErrorText = "";
1579 fErrorCount = 0;
Brian Osmand7e76592020-11-02 12:26:22 -05001580 fInliner.reset(fContext.get(), fIRGenerator->fModifiers.get(), &settings, fCaps);
Brian Osman88cda172020-10-09 12:05:16 -04001581
1582 // Not using AutoSource, because caller is likely to call errorText() if we fail to compile
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001583 std::unique_ptr<String> textPtr(new String(std::move(text)));
1584 fSource = textPtr.get();
Brian Osman88cda172020-10-09 12:05:16 -04001585
1586 const ParsedModule& baseModule = this->moduleForProgramKind(kind);
1587
John Stiles5c7bb322020-10-22 11:09:15 -04001588 // Enable node pooling while converting and optimizing the program for a performance boost.
1589 // The Program will take ownership of the pool.
John Stiles2d68ea32020-10-22 15:42:27 -04001590 std::unique_ptr<Pool> pool = Pool::Create();
1591 pool->attachToThread();
Brian Osmand7e76592020-11-02 12:26:22 -05001592 IRGenerator::IRBundle ir = fIRGenerator->convertProgram(
1593 kind, &settings, fCaps, baseModule, /*isBuiltinCode=*/false, textPtr->c_str(),
1594 textPtr->size(), externalValues);
John Stiles5c7bb322020-10-22 11:09:15 -04001595 auto program = std::make_unique<Program>(kind,
1596 std::move(textPtr),
1597 settings,
Brian Osmand7e76592020-11-02 12:26:22 -05001598 fCaps,
John Stiles5c7bb322020-10-22 11:09:15 -04001599 fContext,
1600 std::move(ir.fElements),
1601 std::move(ir.fModifiers),
1602 std::move(ir.fSymbolTable),
1603 std::move(pool),
1604 ir.fInputs);
1605 bool success = false;
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001606 if (fErrorCount) {
John Stiles5c7bb322020-10-22 11:09:15 -04001607 // Do not return programs that failed to compile.
1608 } else if (settings.fOptimize && !this->optimize(*program)) {
1609 // Do not return programs that failed to optimize.
1610 } else {
1611 // We have a successful program!
1612 success = true;
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001613 }
John Stiles5c7bb322020-10-22 11:09:15 -04001614
1615 program->fPool->detachFromThread();
1616 return success ? std::move(program) : nullptr;
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001617}
1618
Ethan Nicholas00543112018-07-31 09:44:36 -04001619bool Compiler::optimize(Program& program) {
1620 SkASSERT(!fErrorCount);
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001621 fIRGenerator->fKind = program.fKind;
1622 fIRGenerator->fSettings = &program.fSettings;
Brian Osman010ce6a2020-10-19 16:34:10 -04001623 ProgramUsage* usage = program.fUsage.get();
John Stiles7954d6c2020-09-01 10:53:02 -04001624
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001625 while (fErrorCount == 0) {
1626 bool madeChanges = false;
John Stiles7954d6c2020-09-01 10:53:02 -04001627
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001628 // Scan and optimize based on the control-flow graph for each function.
Brian Osman1179fcf2020-10-08 16:04:40 -04001629 for (const auto& element : program.elements()) {
1630 if (element->is<FunctionDefinition>()) {
Brian Osman010ce6a2020-10-19 16:34:10 -04001631 madeChanges |= this->scanCFG(element->as<FunctionDefinition>(), usage);
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001632 }
1633 }
1634
1635 // Perform inline-candidate analysis and inline any functions deemed suitable.
John Stiles881a10c2020-09-19 10:13:24 -04001636 madeChanges |= fInliner.analyze(program);
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001637
1638 // Remove dead functions. We wait until after analysis so that we still report errors,
1639 // even in unused code.
1640 if (program.fSettings.fRemoveDeadFunctions) {
1641 program.fElements.erase(
1642 std::remove_if(program.fElements.begin(),
1643 program.fElements.end(),
1644 [&](const std::unique_ptr<ProgramElement>& element) {
1645 if (!element->is<FunctionDefinition>()) {
1646 return false;
1647 }
1648 const auto& fn = element->as<FunctionDefinition>();
Brian Osman2e25ff42020-10-15 10:32:04 -04001649 bool dead = fn.declaration().name() != "main" &&
Brian Osman010ce6a2020-10-19 16:34:10 -04001650 usage->get(fn.declaration()) == 0;
1651 if (dead) {
1652 madeChanges = true;
1653 usage->remove(*element);
1654 }
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001655 return dead;
1656 }),
1657 program.fElements.end());
1658 }
1659
1660 if (program.fKind != Program::kFragmentProcessor_Kind) {
Brian Osmanc0213602020-10-06 14:43:32 -04001661 // Remove declarations of dead global variables
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001662 program.fElements.erase(
1663 std::remove_if(program.fElements.begin(), program.fElements.end(),
1664 [&](const std::unique_ptr<ProgramElement>& element) {
Brian Osmanc0213602020-10-06 14:43:32 -04001665 if (!element->is<GlobalVarDeclaration>()) {
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001666 return false;
1667 }
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04001668 const auto& global = element->as<GlobalVarDeclaration>();
1669 const auto& varDecl =
1670 global.declaration()->as<VarDeclaration>();
Brian Osman010ce6a2020-10-19 16:34:10 -04001671 bool dead = usage->isDead(varDecl.var());
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001672 madeChanges |= dead;
1673 return dead;
1674 }),
1675 program.fElements.end());
1676 }
John Stiles73a6bff2020-09-09 13:40:37 -04001677
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001678 if (!madeChanges) {
1679 break;
Ethan Nicholas0dc80872019-02-08 15:46:24 -05001680 }
Ethan Nicholas00543112018-07-31 09:44:36 -04001681 }
1682 return fErrorCount == 0;
1683}
1684
Brian Osmanfb32ddf2019-06-18 10:14:20 -04001685#if defined(SKSL_STANDALONE) || SK_SUPPORT_GPU
1686
Ethan Nicholas00543112018-07-31 09:44:36 -04001687bool Compiler::toSPIRV(Program& program, OutputStream& out) {
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001688#ifdef SK_ENABLE_SPIRV_VALIDATION
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001689 StringStream buffer;
Brian Osman88cda172020-10-09 12:05:16 -04001690 AutoSource as(this, program.fSource.get());
Brian Osman8b43dad2020-10-09 13:31:42 -04001691 SPIRVCodeGenerator cg(fContext.get(), &program, this, &buffer);
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001692 bool result = cg.generateCode();
1693 if (result) {
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001694 spvtools::SpirvTools tools(SPV_ENV_VULKAN_1_0);
Ethan Nicholas762466e2017-06-29 10:03:38 -04001695 const String& data = buffer.str();
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001696 SkASSERT(0 == data.size() % 4);
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001697 auto dumpmsg = [](spv_message_level_t, const char*, const spv_position_t&, const char* m) {
1698 SkDebugf("SPIR-V validation error: %s\n", m);
1699 };
1700 tools.SetMessageConsumer(dumpmsg);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001701 // Verify that the SPIR-V we produced is valid. If this SkASSERT fails, check the logs prior
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001702 // to the failure to see the validation errors.
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001703 SkAssertResult(tools.Validate((const uint32_t*) data.c_str(), data.size() / 4));
Ethan Nicholas762466e2017-06-29 10:03:38 -04001704 out.write(data.c_str(), data.size());
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001705 }
1706#else
Brian Osman88cda172020-10-09 12:05:16 -04001707 AutoSource as(this, program.fSource.get());
Brian Osman8b43dad2020-10-09 13:31:42 -04001708 SPIRVCodeGenerator cg(fContext.get(), &program, this, &out);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001709 bool result = cg.generateCode();
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001710#endif
Ethan Nicholasce33f102016-12-09 17:22:59 -05001711 return result;
1712}
1713
Ethan Nicholas00543112018-07-31 09:44:36 -04001714bool Compiler::toSPIRV(Program& program, String* out) {
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001715 StringStream buffer;
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001716 bool result = this->toSPIRV(program, buffer);
1717 if (result) {
Ethan Nicholas762466e2017-06-29 10:03:38 -04001718 *out = buffer.str();
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001719 }
1720 return result;
1721}
1722
Ethan Nicholas00543112018-07-31 09:44:36 -04001723bool Compiler::toGLSL(Program& program, OutputStream& out) {
Brian Osman88cda172020-10-09 12:05:16 -04001724 AutoSource as(this, program.fSource.get());
Ethan Nicholas26a9aad2018-03-27 14:10:52 -04001725 GLSLCodeGenerator cg(fContext.get(), &program, this, &out);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001726 bool result = cg.generateCode();
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001727 return result;
1728}
1729
Ethan Nicholas00543112018-07-31 09:44:36 -04001730bool Compiler::toGLSL(Program& program, String* out) {
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001731 StringStream buffer;
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001732 bool result = this->toGLSL(program, buffer);
1733 if (result) {
Ethan Nicholas762466e2017-06-29 10:03:38 -04001734 *out = buffer.str();
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001735 }
1736 return result;
1737}
1738
Brian Osmanc0243912020-02-19 15:35:26 -05001739bool Compiler::toHLSL(Program& program, String* out) {
1740 String spirv;
1741 if (!this->toSPIRV(program, &spirv)) {
1742 return false;
1743 }
1744
1745 return SPIRVtoHLSL(spirv, out);
1746}
1747
Ethan Nicholas00543112018-07-31 09:44:36 -04001748bool Compiler::toMetal(Program& program, OutputStream& out) {
Ethan Nicholas26a9aad2018-03-27 14:10:52 -04001749 MetalCodeGenerator cg(fContext.get(), &program, this, &out);
Ethan Nicholascc305772017-10-13 16:17:45 -04001750 bool result = cg.generateCode();
Ethan Nicholascc305772017-10-13 16:17:45 -04001751 return result;
1752}
1753
Ethan Nicholas00543112018-07-31 09:44:36 -04001754bool Compiler::toMetal(Program& program, String* out) {
Timothy Liangb8eeb802018-07-23 16:46:16 -04001755 StringStream buffer;
1756 bool result = this->toMetal(program, buffer);
1757 if (result) {
1758 *out = buffer.str();
1759 }
1760 return result;
1761}
1762
Greg Daniela28ea672020-09-25 11:12:56 -04001763#if defined(SKSL_STANDALONE) || GR_TEST_UTILS
Ethan Nicholas00543112018-07-31 09:44:36 -04001764bool Compiler::toCPP(Program& program, String name, OutputStream& out) {
Brian Osman88cda172020-10-09 12:05:16 -04001765 AutoSource as(this, program.fSource.get());
Ethan Nicholas26a9aad2018-03-27 14:10:52 -04001766 CPPCodeGenerator cg(fContext.get(), &program, this, name, &out);
Ethan Nicholas762466e2017-06-29 10:03:38 -04001767 bool result = cg.generateCode();
Ethan Nicholas762466e2017-06-29 10:03:38 -04001768 return result;
1769}
1770
Ethan Nicholas00543112018-07-31 09:44:36 -04001771bool Compiler::toH(Program& program, String name, OutputStream& out) {
Brian Osman88cda172020-10-09 12:05:16 -04001772 AutoSource as(this, program.fSource.get());
Ethan Nicholas26a9aad2018-03-27 14:10:52 -04001773 HCodeGenerator cg(fContext.get(), &program, this, name, &out);
Ethan Nicholas762466e2017-06-29 10:03:38 -04001774 bool result = cg.generateCode();
Ethan Nicholas00543112018-07-31 09:44:36 -04001775 return result;
1776}
Greg Daniela28ea672020-09-25 11:12:56 -04001777#endif // defined(SKSL_STANDALONE) || GR_TEST_UTILS
Ethan Nicholas00543112018-07-31 09:44:36 -04001778
Ethan Nicholas2a479a52020-08-18 16:29:45 -04001779#endif // defined(SKSL_STANDALONE) || SK_SUPPORT_GPU
Brian Osman2e29ab52019-09-20 12:19:11 -04001780
1781#if !defined(SKSL_STANDALONE) && SK_SUPPORT_GPU
Brian Osmana4b91692020-08-10 14:26:16 -04001782bool Compiler::toPipelineStage(Program& program, PipelineStageArgs* outArgs) {
Brian Osman88cda172020-10-09 12:05:16 -04001783 AutoSource as(this, program.fSource.get());
Ethan Nicholas00543112018-07-31 09:44:36 -04001784 StringStream buffer;
Brian Osman300fe1d2020-01-23 15:42:43 -05001785 PipelineStageCodeGenerator cg(fContext.get(), &program, this, &buffer, outArgs);
Ethan Nicholas00543112018-07-31 09:44:36 -04001786 bool result = cg.generateCode();
Ethan Nicholas00543112018-07-31 09:44:36 -04001787 if (result) {
Brian Osman107c6662019-12-30 15:02:30 -05001788 outArgs->fCode = buffer.str();
Ethan Nicholas00543112018-07-31 09:44:36 -04001789 }
Ethan Nicholas762466e2017-06-29 10:03:38 -04001790 return result;
1791}
Brian Osmanfb32ddf2019-06-18 10:14:20 -04001792#endif
1793
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001794std::unique_ptr<ByteCode> Compiler::toByteCode(Program& program) {
Mike Klein853d4ed2020-08-20 00:41:00 +00001795#if defined(SK_ENABLE_SKSL_INTERPRETER)
Brian Osman88cda172020-10-09 12:05:16 -04001796 AutoSource as(this, program.fSource.get());
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001797 std::unique_ptr<ByteCode> result(new ByteCode());
Brian Osmanb08cc022020-04-02 11:38:40 -04001798 ByteCodeGenerator cg(fContext.get(), &program, this, result.get());
1799 bool success = cg.generateCode();
Brian Osmanb08cc022020-04-02 11:38:40 -04001800 if (success) {
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001801 return result;
1802 }
Mike Klein853d4ed2020-08-20 00:41:00 +00001803#else
1804 ABORT("ByteCode interpreter not enabled");
1805#endif
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001806 return nullptr;
1807}
1808
Brian Osman401a0092020-09-10 14:47:24 -04001809const char* Compiler::OperatorName(Token::Kind op) {
1810 switch (op) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001811 case Token::Kind::TK_PLUS: return "+";
1812 case Token::Kind::TK_MINUS: return "-";
1813 case Token::Kind::TK_STAR: return "*";
1814 case Token::Kind::TK_SLASH: return "/";
1815 case Token::Kind::TK_PERCENT: return "%";
1816 case Token::Kind::TK_SHL: return "<<";
1817 case Token::Kind::TK_SHR: return ">>";
1818 case Token::Kind::TK_LOGICALNOT: return "!";
1819 case Token::Kind::TK_LOGICALAND: return "&&";
1820 case Token::Kind::TK_LOGICALOR: return "||";
1821 case Token::Kind::TK_LOGICALXOR: return "^^";
1822 case Token::Kind::TK_BITWISENOT: return "~";
1823 case Token::Kind::TK_BITWISEAND: return "&";
1824 case Token::Kind::TK_BITWISEOR: return "|";
1825 case Token::Kind::TK_BITWISEXOR: return "^";
1826 case Token::Kind::TK_EQ: return "=";
1827 case Token::Kind::TK_EQEQ: return "==";
1828 case Token::Kind::TK_NEQ: return "!=";
1829 case Token::Kind::TK_LT: return "<";
1830 case Token::Kind::TK_GT: return ">";
1831 case Token::Kind::TK_LTEQ: return "<=";
1832 case Token::Kind::TK_GTEQ: return ">=";
1833 case Token::Kind::TK_PLUSEQ: return "+=";
1834 case Token::Kind::TK_MINUSEQ: return "-=";
1835 case Token::Kind::TK_STAREQ: return "*=";
1836 case Token::Kind::TK_SLASHEQ: return "/=";
1837 case Token::Kind::TK_PERCENTEQ: return "%=";
1838 case Token::Kind::TK_SHLEQ: return "<<=";
1839 case Token::Kind::TK_SHREQ: return ">>=";
1840 case Token::Kind::TK_LOGICALANDEQ: return "&&=";
1841 case Token::Kind::TK_LOGICALOREQ: return "||=";
1842 case Token::Kind::TK_LOGICALXOREQ: return "^^=";
1843 case Token::Kind::TK_BITWISEANDEQ: return "&=";
1844 case Token::Kind::TK_BITWISEOREQ: return "|=";
1845 case Token::Kind::TK_BITWISEXOREQ: return "^=";
1846 case Token::Kind::TK_PLUSPLUS: return "++";
1847 case Token::Kind::TK_MINUSMINUS: return "--";
1848 case Token::Kind::TK_COMMA: return ",";
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001849 default:
Brian Osman401a0092020-09-10 14:47:24 -04001850 ABORT("unsupported operator: %d\n", (int) op);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001851 }
1852}
1853
1854
1855bool Compiler::IsAssignment(Token::Kind op) {
1856 switch (op) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001857 case Token::Kind::TK_EQ: // fall through
1858 case Token::Kind::TK_PLUSEQ: // fall through
1859 case Token::Kind::TK_MINUSEQ: // fall through
1860 case Token::Kind::TK_STAREQ: // fall through
1861 case Token::Kind::TK_SLASHEQ: // fall through
1862 case Token::Kind::TK_PERCENTEQ: // fall through
1863 case Token::Kind::TK_SHLEQ: // fall through
1864 case Token::Kind::TK_SHREQ: // fall through
1865 case Token::Kind::TK_BITWISEOREQ: // fall through
1866 case Token::Kind::TK_BITWISEXOREQ: // fall through
1867 case Token::Kind::TK_BITWISEANDEQ: // fall through
1868 case Token::Kind::TK_LOGICALOREQ: // fall through
1869 case Token::Kind::TK_LOGICALXOREQ: // fall through
1870 case Token::Kind::TK_LOGICALANDEQ:
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001871 return true;
1872 default:
1873 return false;
1874 }
1875}
1876
Brian Osman401a0092020-09-10 14:47:24 -04001877Token::Kind Compiler::RemoveAssignment(Token::Kind op) {
1878 switch (op) {
1879 case Token::Kind::TK_PLUSEQ: return Token::Kind::TK_PLUS;
1880 case Token::Kind::TK_MINUSEQ: return Token::Kind::TK_MINUS;
1881 case Token::Kind::TK_STAREQ: return Token::Kind::TK_STAR;
1882 case Token::Kind::TK_SLASHEQ: return Token::Kind::TK_SLASH;
1883 case Token::Kind::TK_PERCENTEQ: return Token::Kind::TK_PERCENT;
1884 case Token::Kind::TK_SHLEQ: return Token::Kind::TK_SHL;
1885 case Token::Kind::TK_SHREQ: return Token::Kind::TK_SHR;
1886 case Token::Kind::TK_BITWISEOREQ: return Token::Kind::TK_BITWISEOR;
1887 case Token::Kind::TK_BITWISEXOREQ: return Token::Kind::TK_BITWISEXOR;
1888 case Token::Kind::TK_BITWISEANDEQ: return Token::Kind::TK_BITWISEAND;
1889 case Token::Kind::TK_LOGICALOREQ: return Token::Kind::TK_LOGICALOR;
1890 case Token::Kind::TK_LOGICALXOREQ: return Token::Kind::TK_LOGICALXOR;
1891 case Token::Kind::TK_LOGICALANDEQ: return Token::Kind::TK_LOGICALAND;
1892 default: return op;
1893 }
1894}
1895
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001896Position Compiler::position(int offset) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001897 SkASSERT(fSource);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001898 int line = 1;
1899 int column = 1;
1900 for (int i = 0; i < offset; i++) {
1901 if ((*fSource)[i] == '\n') {
1902 ++line;
1903 column = 1;
1904 }
1905 else {
1906 ++column;
1907 }
1908 }
1909 return Position(line, column);
1910}
1911
1912void Compiler::error(int offset, String msg) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001913 fErrorCount++;
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001914 Position pos = this->position(offset);
1915 fErrorText += "error: " + to_string(pos.fLine) + ": " + msg.c_str() + "\n";
ethannicholasb3058bd2016-07-01 08:22:01 -07001916}
1917
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001918String Compiler::errorText() {
Ethan Nicholas00543112018-07-31 09:44:36 -04001919 this->writeErrorCount();
1920 fErrorCount = 0;
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001921 String result = fErrorText;
ethannicholasb3058bd2016-07-01 08:22:01 -07001922 return result;
1923}
1924
1925void Compiler::writeErrorCount() {
1926 if (fErrorCount) {
1927 fErrorText += to_string(fErrorCount) + " error";
1928 if (fErrorCount > 1) {
1929 fErrorText += "s";
1930 }
1931 fErrorText += "\n";
1932 }
1933}
1934
John Stilesa6841be2020-08-06 14:11:56 -04001935} // namespace SkSL