blob: 101d71c5af98e5e5961a6db9d38d6b5f07429b68 [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>
11
Mike Kleinc0bd9f92019-04-23 12:05:21 -050012#include "src/sksl/SkSLByteCodeGenerator.h"
13#include "src/sksl/SkSLCFGGenerator.h"
14#include "src/sksl/SkSLCPPCodeGenerator.h"
15#include "src/sksl/SkSLGLSLCodeGenerator.h"
16#include "src/sksl/SkSLHCodeGenerator.h"
17#include "src/sksl/SkSLIRGenerator.h"
18#include "src/sksl/SkSLMetalCodeGenerator.h"
19#include "src/sksl/SkSLPipelineStageCodeGenerator.h"
Ethan Nicholasc18bb512020-07-28 14:46:53 -040020#include "src/sksl/SkSLRehydrator.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050021#include "src/sksl/SkSLSPIRVCodeGenerator.h"
Brian Osmanc0243912020-02-19 15:35:26 -050022#include "src/sksl/SkSLSPIRVtoHLSL.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050023#include "src/sksl/ir/SkSLEnum.h"
24#include "src/sksl/ir/SkSLExpression.h"
25#include "src/sksl/ir/SkSLExpressionStatement.h"
26#include "src/sksl/ir/SkSLFunctionCall.h"
27#include "src/sksl/ir/SkSLIntLiteral.h"
28#include "src/sksl/ir/SkSLModifiersDeclaration.h"
29#include "src/sksl/ir/SkSLNop.h"
30#include "src/sksl/ir/SkSLSymbolTable.h"
31#include "src/sksl/ir/SkSLTernaryExpression.h"
32#include "src/sksl/ir/SkSLUnresolvedFunction.h"
33#include "src/sksl/ir/SkSLVarDeclarations.h"
ethannicholasb3058bd2016-07-01 08:22:01 -070034
Ethan Nicholasa11035b2019-11-26 16:27:47 -050035#if !defined(SKSL_STANDALONE) & SK_SUPPORT_GPU
36#include "include/gpu/GrContextOptions.h"
37#include "src/gpu/GrShaderCaps.h"
38#endif
39
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -040040#ifdef SK_ENABLE_SPIRV_VALIDATION
41#include "spirv-tools/libspirv.hpp"
42#endif
43
Ethan Nicholasc18bb512020-07-28 14:46:53 -040044// If true, we use a compact binary IR representation of the core include files; otherwise we parse
45// the actual source code for the include files at runtime. The main reason you would need to change
46// this is to make format changes easier: set it to 0, change the encoder and decoder as needed,
47// build Skia to regenerate the encoded files, then set this back to 1 to actually use the
48// newly-generated files.
49#define REHYDRATE 1
ethannicholasb3058bd2016-07-01 08:22:01 -070050
Ethan Nicholasc18bb512020-07-28 14:46:53 -040051#if REHYDRATE
52
53#include "src/sksl/generated/sksl_fp.dehydrated.sksl"
54#include "src/sksl/generated/sksl_frag.dehydrated.sksl"
55#include "src/sksl/generated/sksl_geom.dehydrated.sksl"
56#include "src/sksl/generated/sksl_gpu.dehydrated.sksl"
57#include "src/sksl/generated/sksl_interp.dehydrated.sksl"
58#include "src/sksl/generated/sksl_pipeline.dehydrated.sksl"
59#include "src/sksl/generated/sksl_vert.dehydrated.sksl"
60
61#else
62
63#warning SkSL rehydrator is disabled
Ethan Nicholas79707652017-11-16 11:20:11 -050064
Ethan Nicholas8da1e652019-05-24 11:01:59 -040065static const char* SKSL_GPU_INCLUDE =
Ethan Nicholasc18bb512020-07-28 14:46:53 -040066#include "src/sksl/generated/sksl_gpu.c.inc"
Ethan Nicholas8da1e652019-05-24 11:01:59 -040067static const char* SKSL_INTERP_INCLUDE =
Ethan Nicholasc18bb512020-07-28 14:46:53 -040068#include "src/sksl/generated/sksl_interp.c.inc"
ethannicholas5961bc92016-10-12 06:39:56 -070069static const char* SKSL_VERT_INCLUDE =
Ethan Nicholasc18bb512020-07-28 14:46:53 -040070#include "src/sksl/generated/sksl_vert.c.inc"
ethannicholas5961bc92016-10-12 06:39:56 -070071static const char* SKSL_FRAG_INCLUDE =
Ethan Nicholasc18bb512020-07-28 14:46:53 -040072#include "src/sksl/generated/sksl_frag.c.inc"
Ethan Nicholas52cad152017-02-16 16:37:32 -050073static const char* SKSL_GEOM_INCLUDE =
Ethan Nicholasc18bb512020-07-28 14:46:53 -040074#include "src/sksl/generated/sksl_geom.c.inc"
Ethan Nicholas762466e2017-06-29 10:03:38 -040075static const char* SKSL_FP_INCLUDE =
Ethan Nicholasc18bb512020-07-28 14:46:53 -040076#include "src/sksl/generated/sksl_fp.c.inc"
Ethan Nicholas8da1e652019-05-24 11:01:59 -040077static const char* SKSL_PIPELINE_INCLUDE =
Ethan Nicholasc18bb512020-07-28 14:46:53 -040078#include "src/sksl/generated/sksl_pipeline.c.inc"
79
80#endif
Ethan Nicholas0d997662019-04-08 09:46:01 -040081
ethannicholasb3058bd2016-07-01 08:22:01 -070082namespace SkSL {
83
Ethan Nicholasdb80f692019-11-22 14:06:12 -050084static void grab_intrinsics(std::vector<std::unique_ptr<ProgramElement>>* src,
Brian Osman08f986d2020-05-13 17:06:46 -040085 std::map<String, std::pair<std::unique_ptr<ProgramElement>, bool>>* target) {
86 for (auto iter = src->begin(); iter != src->end(); ) {
87 std::unique_ptr<ProgramElement>& element = *iter;
Ethan Nicholasdb80f692019-11-22 14:06:12 -050088 switch (element->fKind) {
89 case ProgramElement::kFunction_Kind: {
90 FunctionDefinition& f = (FunctionDefinition&) *element;
Brian Osman08f986d2020-05-13 17:06:46 -040091 SkASSERT(f.fDeclaration.fBuiltin);
Ethan Nicholasc18bb512020-07-28 14:46:53 -040092 String key = f.fDeclaration.description();
Brian Osman08f986d2020-05-13 17:06:46 -040093 SkASSERT(target->find(key) == target->end());
94 (*target)[key] = std::make_pair(std::move(element), false);
95 iter = src->erase(iter);
Ethan Nicholasdb80f692019-11-22 14:06:12 -050096 break;
97 }
98 case ProgramElement::kEnum_Kind: {
99 Enum& e = (Enum&) *element;
100 StringFragment name = e.fTypeName;
101 SkASSERT(target->find(name) == target->end());
102 (*target)[name] = std::make_pair(std::move(element), false);
Brian Osman08f986d2020-05-13 17:06:46 -0400103 iter = src->erase(iter);
Ethan Nicholasdb80f692019-11-22 14:06:12 -0500104 break;
105 }
106 default:
107 printf("unsupported include file element\n");
108 SkASSERT(false);
109 }
110 }
111}
112
Ethan Nicholas6e1cbc02017-07-14 10:12:15 -0400113Compiler::Compiler(Flags flags)
114: fFlags(flags)
Ethan Nicholas26a9aad2018-03-27 14:10:52 -0400115, fContext(new Context())
Ethan Nicholas6e1cbc02017-07-14 10:12:15 -0400116, fErrorCount(0) {
Ethan Nicholasc18bb512020-07-28 14:46:53 -0400117 auto symbols = std::shared_ptr<SymbolTable>(new SymbolTable(this));
Ethan Nicholas26a9aad2018-03-27 14:10:52 -0400118 fIRGenerator = new IRGenerator(fContext.get(), symbols, *this);
Ethan Nicholasc18bb512020-07-28 14:46:53 -0400119 #define ADD_TYPE(t) symbols->addWithoutOwnership(fContext->f ## t ## _Type->fName, \
120 fContext->f ## t ## _Type.get())
ethannicholasb3058bd2016-07-01 08:22:01 -0700121 ADD_TYPE(Void);
122 ADD_TYPE(Float);
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400123 ADD_TYPE(Float2);
124 ADD_TYPE(Float3);
125 ADD_TYPE(Float4);
Ethan Nicholasdcba08e2017-08-02 10:52:54 -0400126 ADD_TYPE(Half);
127 ADD_TYPE(Half2);
128 ADD_TYPE(Half3);
129 ADD_TYPE(Half4);
ethannicholasb3058bd2016-07-01 08:22:01 -0700130 ADD_TYPE(Int);
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400131 ADD_TYPE(Int2);
132 ADD_TYPE(Int3);
133 ADD_TYPE(Int4);
ethannicholasb3058bd2016-07-01 08:22:01 -0700134 ADD_TYPE(UInt);
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400135 ADD_TYPE(UInt2);
136 ADD_TYPE(UInt3);
137 ADD_TYPE(UInt4);
Ethan Nicholasdcba08e2017-08-02 10:52:54 -0400138 ADD_TYPE(Short);
139 ADD_TYPE(Short2);
140 ADD_TYPE(Short3);
141 ADD_TYPE(Short4);
142 ADD_TYPE(UShort);
143 ADD_TYPE(UShort2);
144 ADD_TYPE(UShort3);
145 ADD_TYPE(UShort4);
Ruiqi Maob609e6d2018-07-17 10:19:38 -0400146 ADD_TYPE(Byte);
147 ADD_TYPE(Byte2);
148 ADD_TYPE(Byte3);
149 ADD_TYPE(Byte4);
150 ADD_TYPE(UByte);
151 ADD_TYPE(UByte2);
152 ADD_TYPE(UByte3);
153 ADD_TYPE(UByte4);
ethannicholasb3058bd2016-07-01 08:22:01 -0700154 ADD_TYPE(Bool);
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400155 ADD_TYPE(Bool2);
156 ADD_TYPE(Bool3);
157 ADD_TYPE(Bool4);
158 ADD_TYPE(Float2x2);
159 ADD_TYPE(Float2x3);
160 ADD_TYPE(Float2x4);
161 ADD_TYPE(Float3x2);
162 ADD_TYPE(Float3x3);
163 ADD_TYPE(Float3x4);
164 ADD_TYPE(Float4x2);
165 ADD_TYPE(Float4x3);
166 ADD_TYPE(Float4x4);
Ethan Nicholasdcba08e2017-08-02 10:52:54 -0400167 ADD_TYPE(Half2x2);
168 ADD_TYPE(Half2x3);
169 ADD_TYPE(Half2x4);
170 ADD_TYPE(Half3x2);
171 ADD_TYPE(Half3x3);
172 ADD_TYPE(Half3x4);
173 ADD_TYPE(Half4x2);
174 ADD_TYPE(Half4x3);
175 ADD_TYPE(Half4x4);
ethannicholasb3058bd2016-07-01 08:22:01 -0700176 ADD_TYPE(GenType);
Ethan Nicholasdcba08e2017-08-02 10:52:54 -0400177 ADD_TYPE(GenHType);
ethannicholasb3058bd2016-07-01 08:22:01 -0700178 ADD_TYPE(GenIType);
179 ADD_TYPE(GenUType);
180 ADD_TYPE(GenBType);
181 ADD_TYPE(Mat);
182 ADD_TYPE(Vec);
183 ADD_TYPE(GVec);
184 ADD_TYPE(GVec2);
185 ADD_TYPE(GVec3);
186 ADD_TYPE(GVec4);
Ethan Nicholasdcba08e2017-08-02 10:52:54 -0400187 ADD_TYPE(HVec);
ethannicholasb3058bd2016-07-01 08:22:01 -0700188 ADD_TYPE(IVec);
189 ADD_TYPE(UVec);
Ethan Nicholasdcba08e2017-08-02 10:52:54 -0400190 ADD_TYPE(SVec);
191 ADD_TYPE(USVec);
Ruiqi Maob609e6d2018-07-17 10:19:38 -0400192 ADD_TYPE(ByteVec);
193 ADD_TYPE(UByteVec);
ethannicholasb3058bd2016-07-01 08:22:01 -0700194 ADD_TYPE(BVec);
195
196 ADD_TYPE(Sampler1D);
197 ADD_TYPE(Sampler2D);
198 ADD_TYPE(Sampler3D);
ethannicholas5961bc92016-10-12 06:39:56 -0700199 ADD_TYPE(SamplerExternalOES);
ethannicholasb3058bd2016-07-01 08:22:01 -0700200 ADD_TYPE(SamplerCube);
201 ADD_TYPE(Sampler2DRect);
202 ADD_TYPE(Sampler1DArray);
203 ADD_TYPE(Sampler2DArray);
204 ADD_TYPE(SamplerCubeArray);
205 ADD_TYPE(SamplerBuffer);
206 ADD_TYPE(Sampler2DMS);
207 ADD_TYPE(Sampler2DMSArray);
208
Brian Salomonbf7b6202016-11-11 16:08:03 -0500209 ADD_TYPE(ISampler2D);
210
Brian Salomon2a51de82016-11-16 12:06:01 -0500211 ADD_TYPE(Image2D);
212 ADD_TYPE(IImage2D);
213
Greg Daniel64773e62016-11-22 09:44:03 -0500214 ADD_TYPE(SubpassInput);
215 ADD_TYPE(SubpassInputMS);
216
ethannicholasb3058bd2016-07-01 08:22:01 -0700217 ADD_TYPE(GSampler1D);
218 ADD_TYPE(GSampler2D);
219 ADD_TYPE(GSampler3D);
220 ADD_TYPE(GSamplerCube);
221 ADD_TYPE(GSampler2DRect);
222 ADD_TYPE(GSampler1DArray);
223 ADD_TYPE(GSampler2DArray);
224 ADD_TYPE(GSamplerCubeArray);
225 ADD_TYPE(GSamplerBuffer);
226 ADD_TYPE(GSampler2DMS);
227 ADD_TYPE(GSampler2DMSArray);
228
229 ADD_TYPE(Sampler1DShadow);
230 ADD_TYPE(Sampler2DShadow);
231 ADD_TYPE(SamplerCubeShadow);
232 ADD_TYPE(Sampler2DRectShadow);
233 ADD_TYPE(Sampler1DArrayShadow);
234 ADD_TYPE(Sampler2DArrayShadow);
235 ADD_TYPE(SamplerCubeArrayShadow);
236 ADD_TYPE(GSampler2DArrayShadow);
237 ADD_TYPE(GSamplerCubeArrayShadow);
Ethan Nicholasc9472af2017-10-10 16:30:21 -0400238 ADD_TYPE(FragmentProcessor);
Stephen Whiteff5d7a22019-07-26 17:42:06 -0400239 ADD_TYPE(Sampler);
240 ADD_TYPE(Texture2D);
ethannicholasb3058bd2016-07-01 08:22:01 -0700241
Brian Osman28590d52020-03-23 16:59:08 -0400242 StringFragment fpAliasName("shader");
Ethan Nicholasc18bb512020-07-28 14:46:53 -0400243 symbols->addWithoutOwnership(fpAliasName, fContext->fFragmentProcessor_Type.get());
Brian Osman28590d52020-03-23 16:59:08 -0400244
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700245 StringFragment skCapsName("sk_Caps");
246 Variable* skCaps = new Variable(-1, Modifiers(), skCapsName,
Ethan Nicholas26a9aad2018-03-27 14:10:52 -0400247 *fContext->fSkCaps_Type, Variable::kGlobal_Storage);
Ethan Nicholas3605ace2016-11-21 15:59:48 -0500248 fIRGenerator->fSymbolTable->add(skCapsName, std::unique_ptr<Symbol>(skCaps));
249
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700250 StringFragment skArgsName("sk_Args");
251 Variable* skArgs = new Variable(-1, Modifiers(), skArgsName,
Ethan Nicholas26a9aad2018-03-27 14:10:52 -0400252 *fContext->fSkArgs_Type, Variable::kGlobal_Storage);
Ethan Nicholas762466e2017-06-29 10:03:38 -0400253 fIRGenerator->fSymbolTable->add(skArgsName, std::unique_ptr<Symbol>(skArgs));
254
Ethan Nicholasdb80f692019-11-22 14:06:12 -0500255 fIRGenerator->fIntrinsics = &fGPUIntrinsics;
256 std::vector<std::unique_ptr<ProgramElement>> gpuIntrinsics;
Ethan Nicholasc18bb512020-07-28 14:46:53 -0400257 std::vector<std::unique_ptr<ProgramElement>> interpIntrinsics;
258#if !REHYDRATE
Ethan Nicholas8da1e652019-05-24 11:01:59 -0400259 this->processIncludeFile(Program::kFragment_Kind, SKSL_GPU_INCLUDE, strlen(SKSL_GPU_INCLUDE),
Ethan Nicholasdb80f692019-11-22 14:06:12 -0500260 symbols, &gpuIntrinsics, &fGpuSymbolTable);
Ethan Nicholasdb80f692019-11-22 14:06:12 -0500261 // need to hang on to the source so that FunctionDefinition.fSource pointers in this file
262 // remain valid
263 fGpuIncludeSource = std::move(fIRGenerator->fFile);
Ethan Nicholas8da1e652019-05-24 11:01:59 -0400264 this->processIncludeFile(Program::kVertex_Kind, SKSL_VERT_INCLUDE, strlen(SKSL_VERT_INCLUDE),
265 fGpuSymbolTable, &fVertexInclude, &fVertexSymbolTable);
266 this->processIncludeFile(Program::kFragment_Kind, SKSL_FRAG_INCLUDE, strlen(SKSL_FRAG_INCLUDE),
267 fGpuSymbolTable, &fFragmentInclude, &fFragmentSymbolTable);
Ethan Nicholasc18bb512020-07-28 14:46:53 -0400268#else
269 {
270 Rehydrator rehydrator(fContext.get(), symbols, this, SKSL_INCLUDE_sksl_gpu,
271 SKSL_INCLUDE_sksl_gpu_LENGTH);
272 fGpuSymbolTable = rehydrator.symbolTable();
273 gpuIntrinsics = rehydrator.elements();
274 }
275 {
276 Rehydrator rehydrator(fContext.get(), fGpuSymbolTable, this, SKSL_INCLUDE_sksl_vert,
277 SKSL_INCLUDE_sksl_vert_LENGTH);
278 fVertexSymbolTable = rehydrator.symbolTable();
279 fVertexInclude = rehydrator.elements();
280 }
281 {
282 Rehydrator rehydrator(fContext.get(), fGpuSymbolTable, this, SKSL_INCLUDE_sksl_frag,
283 SKSL_INCLUDE_sksl_frag_LENGTH);
284 fFragmentSymbolTable = rehydrator.symbolTable();
285 fFragmentInclude = rehydrator.elements();
286 }
287#endif
288 grab_intrinsics(&gpuIntrinsics, &fGPUIntrinsics);
Brian Osmanb08cc022020-04-02 11:38:40 -0400289 grab_intrinsics(&interpIntrinsics, &fInterpreterIntrinsics);
ethannicholasb3058bd2016-07-01 08:22:01 -0700290}
291
292Compiler::~Compiler() {
293 delete fIRGenerator;
294}
295
Ethan Nicholasc18bb512020-07-28 14:46:53 -0400296void Compiler::loadGeometryIntrinsics() {
297 if (fGeometrySymbolTable) {
298 return;
299 }
300 #if REHYDRATE
301 {
302 Rehydrator rehydrator(fContext.get(), fGpuSymbolTable, this, SKSL_INCLUDE_sksl_geom,
303 SKSL_INCLUDE_sksl_geom_LENGTH);
304 fGeometrySymbolTable = rehydrator.symbolTable();
305 fGeometryInclude = rehydrator.elements();
306 }
307 #else
308 this->processIncludeFile(Program::kGeometry_Kind, SKSL_GEOM_INCLUDE,
309 strlen(SKSL_GEOM_INCLUDE), fGpuSymbolTable, &fGeometryInclude,
310 &fGeometrySymbolTable);
311 #endif
312}
313
314void Compiler::loadPipelineIntrinsics() {
315 if (fPipelineSymbolTable) {
316 return;
317 }
318 #if REHYDRATE
319 {
320 Rehydrator rehydrator(fContext.get(), fGpuSymbolTable, this,
321 SKSL_INCLUDE_sksl_pipeline,
322 SKSL_INCLUDE_sksl_pipeline_LENGTH);
323 fPipelineSymbolTable = rehydrator.symbolTable();
324 fPipelineInclude = rehydrator.elements();
325 }
326 #else
327 this->processIncludeFile(Program::kPipelineStage_Kind, SKSL_PIPELINE_INCLUDE,
328 strlen(SKSL_PIPELINE_INCLUDE), fGpuSymbolTable, &fPipelineInclude,
329 &fPipelineSymbolTable);
330 #endif
331}
332
333void Compiler::loadInterpreterIntrinsics() {
334 if (fInterpreterSymbolTable) {
335 return;
336 }
337 this->loadPipelineIntrinsics();
338 #if REHYDRATE
339 {
340 Rehydrator rehydrator(fContext.get(), fPipelineSymbolTable, this,
341 SKSL_INCLUDE_sksl_interp,
342 SKSL_INCLUDE_sksl_interp_LENGTH);
343 fInterpreterSymbolTable = rehydrator.symbolTable();
344 fInterpreterInclude = rehydrator.elements();
345 }
346 #else
347 this->processIncludeFile(Program::kGeneric_Kind, SKSL_INTERP_INCLUDE,
348 strlen(SKSL_INTERP_INCLUDE), fIRGenerator->fSymbolTable,
349 &fInterpreterInclude, &fInterpreterSymbolTable);
350 #endif
351}
352
Ethan Nicholas8da1e652019-05-24 11:01:59 -0400353void Compiler::processIncludeFile(Program::Kind kind, const char* src, size_t length,
354 std::shared_ptr<SymbolTable> base,
355 std::vector<std::unique_ptr<ProgramElement>>* outElements,
356 std::shared_ptr<SymbolTable>* outSymbolTable) {
Ethan Nicholasa11035b2019-11-26 16:27:47 -0500357#ifdef SK_DEBUG
358 String source(src, length);
359 fSource = &source;
360#endif
Ethan Nicholasc18bb512020-07-28 14:46:53 -0400361 std::shared_ptr<SymbolTable> old = fIRGenerator->fSymbolTable;
362 if (base) {
363 fIRGenerator->fSymbolTable = std::move(base);
364 }
Ethan Nicholas8da1e652019-05-24 11:01:59 -0400365 Program::Settings settings;
Ethan Nicholasa11035b2019-11-26 16:27:47 -0500366#if !defined(SKSL_STANDALONE) & SK_SUPPORT_GPU
367 GrContextOptions opts;
368 GrShaderCaps caps(opts);
369 settings.fCaps = &caps;
370#endif
Ethan Nicholasc18bb512020-07-28 14:46:53 -0400371 SkASSERT(fIRGenerator->fCanInline);
372 fIRGenerator->fCanInline = false;
373 fIRGenerator->start(&settings, nullptr, true);
374 fIRGenerator->convertProgram(kind, src, length, outElements);
375 fIRGenerator->fCanInline = true;
Ethan Nicholas8da1e652019-05-24 11:01:59 -0400376 if (this->fErrorCount) {
377 printf("Unexpected errors: %s\n", this->fErrorText.c_str());
378 }
379 SkASSERT(!fErrorCount);
Ethan Nicholas8da1e652019-05-24 11:01:59 -0400380 *outSymbolTable = fIRGenerator->fSymbolTable;
Ethan Nicholasa11035b2019-11-26 16:27:47 -0500381#ifdef SK_DEBUG
382 fSource = nullptr;
383#endif
Ethan Nicholasc18bb512020-07-28 14:46:53 -0400384 fIRGenerator->fSymbolTable = std::move(old);
Ethan Nicholas8da1e652019-05-24 11:01:59 -0400385}
386
ethannicholas22f939e2016-10-13 13:25:34 -0700387// add the definition created by assigning to the lvalue to the definition set
Ethan Nicholas86a43402017-01-19 13:32:00 -0500388void Compiler::addDefinition(const Expression* lvalue, std::unique_ptr<Expression>* expr,
389 DefinitionMap* definitions) {
ethannicholas22f939e2016-10-13 13:25:34 -0700390 switch (lvalue->fKind) {
391 case Expression::kVariableReference_Kind: {
392 const Variable& var = ((VariableReference*) lvalue)->fVariable;
393 if (var.fStorage == Variable::kLocal_Storage) {
394 (*definitions)[&var] = expr;
395 }
396 break;
397 }
398 case Expression::kSwizzle_Kind:
399 // We consider the variable written to as long as at least some of its components have
400 // been written to. This will lead to some false negatives (we won't catch it if you
401 // write to foo.x and then read foo.y), but being stricter could lead to false positives
Mike Klein6ad99092016-10-26 10:35:22 -0400402 // (we write to foo.x, and then pass foo to a function which happens to only read foo.x,
403 // 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 -0700404 // more complicated whole-program analysis. This is probably good enough.
Mike Klein6ad99092016-10-26 10:35:22 -0400405 this->addDefinition(((Swizzle*) lvalue)->fBase.get(),
Ethan Nicholas26a9aad2018-03-27 14:10:52 -0400406 (std::unique_ptr<Expression>*) &fContext->fDefined_Expression,
ethannicholas22f939e2016-10-13 13:25:34 -0700407 definitions);
408 break;
409 case Expression::kIndex_Kind:
410 // see comments in Swizzle
Mike Klein6ad99092016-10-26 10:35:22 -0400411 this->addDefinition(((IndexExpression*) lvalue)->fBase.get(),
Ethan Nicholas26a9aad2018-03-27 14:10:52 -0400412 (std::unique_ptr<Expression>*) &fContext->fDefined_Expression,
ethannicholas22f939e2016-10-13 13:25:34 -0700413 definitions);
414 break;
415 case Expression::kFieldAccess_Kind:
416 // see comments in Swizzle
Mike Klein6ad99092016-10-26 10:35:22 -0400417 this->addDefinition(((FieldAccess*) lvalue)->fBase.get(),
Ethan Nicholas26a9aad2018-03-27 14:10:52 -0400418 (std::unique_ptr<Expression>*) &fContext->fDefined_Expression,
ethannicholas22f939e2016-10-13 13:25:34 -0700419 definitions);
420 break;
Ethan Nicholasa583b812018-01-18 13:32:11 -0500421 case Expression::kTernary_Kind:
422 // To simplify analysis, we just pretend that we write to both sides of the ternary.
423 // This allows for false positives (meaning we fail to detect that a variable might not
424 // have been assigned), but is preferable to false negatives.
425 this->addDefinition(((TernaryExpression*) lvalue)->fIfTrue.get(),
Ethan Nicholas26a9aad2018-03-27 14:10:52 -0400426 (std::unique_ptr<Expression>*) &fContext->fDefined_Expression,
Ethan Nicholasa583b812018-01-18 13:32:11 -0500427 definitions);
428 this->addDefinition(((TernaryExpression*) lvalue)->fIfFalse.get(),
Ethan Nicholas26a9aad2018-03-27 14:10:52 -0400429 (std::unique_ptr<Expression>*) &fContext->fDefined_Expression,
Ethan Nicholasa583b812018-01-18 13:32:11 -0500430 definitions);
431 break;
Ethan Nicholas91164d12019-05-15 15:29:54 -0400432 case Expression::kExternalValue_Kind:
433 break;
ethannicholas22f939e2016-10-13 13:25:34 -0700434 default:
435 // not an lvalue, can't happen
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400436 SkASSERT(false);
ethannicholas22f939e2016-10-13 13:25:34 -0700437 }
438}
439
440// add local variables defined by this node to the set
Mike Klein6ad99092016-10-26 10:35:22 -0400441void Compiler::addDefinitions(const BasicBlock::Node& node,
Ethan Nicholas86a43402017-01-19 13:32:00 -0500442 DefinitionMap* definitions) {
ethannicholas22f939e2016-10-13 13:25:34 -0700443 switch (node.fKind) {
444 case BasicBlock::Node::kExpression_Kind: {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400445 SkASSERT(node.expression());
Ethan Nicholascb670962017-04-20 19:31:52 -0400446 const Expression* expr = (Expression*) node.expression()->get();
Ethan Nicholas86a43402017-01-19 13:32:00 -0500447 switch (expr->fKind) {
448 case Expression::kBinary_Kind: {
449 BinaryExpression* b = (BinaryExpression*) expr;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400450 if (b->fOperator == Token::Kind::TK_EQ) {
Ethan Nicholas86a43402017-01-19 13:32:00 -0500451 this->addDefinition(b->fLeft.get(), &b->fRight, definitions);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700452 } else if (Compiler::IsAssignment(b->fOperator)) {
Ethan Nicholas86a43402017-01-19 13:32:00 -0500453 this->addDefinition(
Ethan Nicholas26a9aad2018-03-27 14:10:52 -0400454 b->fLeft.get(),
455 (std::unique_ptr<Expression>*) &fContext->fDefined_Expression,
456 definitions);
Ethan Nicholas86a43402017-01-19 13:32:00 -0500457
458 }
459 break;
ethannicholas22f939e2016-10-13 13:25:34 -0700460 }
Ethan Nicholasc6a19f12018-03-29 16:46:56 -0400461 case Expression::kFunctionCall_Kind: {
462 const FunctionCall& c = (const FunctionCall&) *expr;
463 for (size_t i = 0; i < c.fFunction.fParameters.size(); ++i) {
464 if (c.fFunction.fParameters[i]->fModifiers.fFlags & Modifiers::kOut_Flag) {
465 this->addDefinition(
466 c.fArguments[i].get(),
467 (std::unique_ptr<Expression>*) &fContext->fDefined_Expression,
468 definitions);
469 }
470 }
471 break;
472 }
Ethan Nicholas86a43402017-01-19 13:32:00 -0500473 case Expression::kPrefix_Kind: {
474 const PrefixExpression* p = (PrefixExpression*) expr;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400475 if (p->fOperator == Token::Kind::TK_MINUSMINUS ||
476 p->fOperator == Token::Kind::TK_PLUSPLUS) {
Ethan Nicholas86a43402017-01-19 13:32:00 -0500477 this->addDefinition(
Ethan Nicholas26a9aad2018-03-27 14:10:52 -0400478 p->fOperand.get(),
479 (std::unique_ptr<Expression>*) &fContext->fDefined_Expression,
480 definitions);
Ethan Nicholas86a43402017-01-19 13:32:00 -0500481 }
482 break;
483 }
484 case Expression::kPostfix_Kind: {
485 const PostfixExpression* p = (PostfixExpression*) expr;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400486 if (p->fOperator == Token::Kind::TK_MINUSMINUS ||
487 p->fOperator == Token::Kind::TK_PLUSPLUS) {
Ethan Nicholas86a43402017-01-19 13:32:00 -0500488 this->addDefinition(
Ethan Nicholas26a9aad2018-03-27 14:10:52 -0400489 p->fOperand.get(),
490 (std::unique_ptr<Expression>*) &fContext->fDefined_Expression,
491 definitions);
Ethan Nicholas86a43402017-01-19 13:32:00 -0500492 }
493 break;
494 }
Ethan Nicholascb670962017-04-20 19:31:52 -0400495 case Expression::kVariableReference_Kind: {
496 const VariableReference* v = (VariableReference*) expr;
497 if (v->fRefKind != VariableReference::kRead_RefKind) {
498 this->addDefinition(
Ethan Nicholas26a9aad2018-03-27 14:10:52 -0400499 v,
500 (std::unique_ptr<Expression>*) &fContext->fDefined_Expression,
501 definitions);
Ethan Nicholascb670962017-04-20 19:31:52 -0400502 }
John Stiles30212b72020-06-11 17:55:07 -0400503 break;
Ethan Nicholascb670962017-04-20 19:31:52 -0400504 }
Ethan Nicholas86a43402017-01-19 13:32:00 -0500505 default:
506 break;
ethannicholas22f939e2016-10-13 13:25:34 -0700507 }
508 break;
509 }
510 case BasicBlock::Node::kStatement_Kind: {
Ethan Nicholascb670962017-04-20 19:31:52 -0400511 const Statement* stmt = (Statement*) node.statement()->get();
Ethan Nicholas82a62d22017-11-07 14:42:10 +0000512 if (stmt->fKind == Statement::kVarDeclaration_Kind) {
513 VarDeclaration& vd = (VarDeclaration&) *stmt;
514 if (vd.fValue) {
515 (*definitions)[vd.fVar] = &vd.fValue;
ethannicholas22f939e2016-10-13 13:25:34 -0700516 }
517 }
518 break;
519 }
520 }
521}
522
523void Compiler::scanCFG(CFG* cfg, BlockId blockId, std::set<BlockId>* workList) {
524 BasicBlock& block = cfg->fBlocks[blockId];
525
526 // compute definitions after this block
Ethan Nicholas86a43402017-01-19 13:32:00 -0500527 DefinitionMap after = block.fBefore;
ethannicholas22f939e2016-10-13 13:25:34 -0700528 for (const BasicBlock::Node& n : block.fNodes) {
529 this->addDefinitions(n, &after);
530 }
531
532 // propagate definitions to exits
533 for (BlockId exitId : block.fExits) {
Ethan Nicholas26a9aad2018-03-27 14:10:52 -0400534 if (exitId == blockId) {
535 continue;
536 }
ethannicholas22f939e2016-10-13 13:25:34 -0700537 BasicBlock& exit = cfg->fBlocks[exitId];
538 for (const auto& pair : after) {
Ethan Nicholas86a43402017-01-19 13:32:00 -0500539 std::unique_ptr<Expression>* e1 = pair.second;
540 auto found = exit.fBefore.find(pair.first);
541 if (found == exit.fBefore.end()) {
542 // exit has no definition for it, just copy it
543 workList->insert(exitId);
ethannicholas22f939e2016-10-13 13:25:34 -0700544 exit.fBefore[pair.first] = e1;
545 } else {
Ethan Nicholas86a43402017-01-19 13:32:00 -0500546 // exit has a (possibly different) value already defined
547 std::unique_ptr<Expression>* e2 = exit.fBefore[pair.first];
ethannicholas22f939e2016-10-13 13:25:34 -0700548 if (e1 != e2) {
549 // definition has changed, merge and add exit block to worklist
550 workList->insert(exitId);
Ethan Nicholasaf197692017-02-27 13:26:45 -0500551 if (e1 && e2) {
552 exit.fBefore[pair.first] =
Ethan Nicholas26a9aad2018-03-27 14:10:52 -0400553 (std::unique_ptr<Expression>*) &fContext->fDefined_Expression;
Ethan Nicholasaf197692017-02-27 13:26:45 -0500554 } else {
555 exit.fBefore[pair.first] = nullptr;
556 }
ethannicholas22f939e2016-10-13 13:25:34 -0700557 }
558 }
559 }
560 }
561}
562
563// returns a map which maps all local variables in the function to null, indicating that their value
564// is initially unknown
Ethan Nicholas86a43402017-01-19 13:32:00 -0500565static DefinitionMap compute_start_state(const CFG& cfg) {
566 DefinitionMap result;
Mike Klein6ad99092016-10-26 10:35:22 -0400567 for (const auto& block : cfg.fBlocks) {
568 for (const auto& node : block.fNodes) {
ethannicholas22f939e2016-10-13 13:25:34 -0700569 if (node.fKind == BasicBlock::Node::kStatement_Kind) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400570 SkASSERT(node.statement());
Ethan Nicholascb670962017-04-20 19:31:52 -0400571 const Statement* s = node.statement()->get();
ethannicholas22f939e2016-10-13 13:25:34 -0700572 if (s->fKind == Statement::kVarDeclarations_Kind) {
573 const VarDeclarationsStatement* vd = (const VarDeclarationsStatement*) s;
Ethan Nicholas82a62d22017-11-07 14:42:10 +0000574 for (const auto& decl : vd->fDeclaration->fVars) {
575 if (decl->fKind == Statement::kVarDeclaration_Kind) {
576 result[((VarDeclaration&) *decl).fVar] = nullptr;
577 }
Mike Klein6ad99092016-10-26 10:35:22 -0400578 }
ethannicholas22f939e2016-10-13 13:25:34 -0700579 }
580 }
581 }
582 }
583 return result;
584}
585
Ethan Nicholascb670962017-04-20 19:31:52 -0400586/**
587 * Returns true if assigning to this lvalue has no effect.
588 */
589static bool is_dead(const Expression& lvalue) {
590 switch (lvalue.fKind) {
591 case Expression::kVariableReference_Kind:
592 return ((VariableReference&) lvalue).fVariable.dead();
593 case Expression::kSwizzle_Kind:
594 return is_dead(*((Swizzle&) lvalue).fBase);
595 case Expression::kFieldAccess_Kind:
596 return is_dead(*((FieldAccess&) lvalue).fBase);
597 case Expression::kIndex_Kind: {
598 const IndexExpression& idx = (IndexExpression&) lvalue;
Ethan Nicholas2a099da2020-01-02 14:40:54 -0500599 return is_dead(*idx.fBase) &&
600 !idx.fIndex->hasProperty(Expression::Property::kSideEffects);
Ethan Nicholascb670962017-04-20 19:31:52 -0400601 }
Ethan Nicholasa583b812018-01-18 13:32:11 -0500602 case Expression::kTernary_Kind: {
603 const TernaryExpression& t = (TernaryExpression&) lvalue;
604 return !t.fTest->hasSideEffects() && is_dead(*t.fIfTrue) && is_dead(*t.fIfFalse);
605 }
Ethan Nicholas91164d12019-05-15 15:29:54 -0400606 case Expression::kExternalValue_Kind:
607 return false;
Ethan Nicholascb670962017-04-20 19:31:52 -0400608 default:
Ethan Nicholas2a099da2020-01-02 14:40:54 -0500609#ifdef SK_DEBUG
Ethan Nicholascb670962017-04-20 19:31:52 -0400610 ABORT("invalid lvalue: %s\n", lvalue.description().c_str());
Ethan Nicholas2a099da2020-01-02 14:40:54 -0500611#endif
612 return false;
Ethan Nicholascb670962017-04-20 19:31:52 -0400613 }
614}
ethannicholas22f939e2016-10-13 13:25:34 -0700615
Ethan Nicholascb670962017-04-20 19:31:52 -0400616/**
617 * Returns true if this is an assignment which can be collapsed down to just the right hand side due
618 * to a dead target and lack of side effects on the left hand side.
619 */
620static bool dead_assignment(const BinaryExpression& b) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700621 if (!Compiler::IsAssignment(b.fOperator)) {
Ethan Nicholascb670962017-04-20 19:31:52 -0400622 return false;
623 }
624 return is_dead(*b.fLeft);
625}
626
627void Compiler::computeDataFlow(CFG* cfg) {
628 cfg->fBlocks[cfg->fStart].fBefore = compute_start_state(*cfg);
ethannicholas22f939e2016-10-13 13:25:34 -0700629 std::set<BlockId> workList;
Ethan Nicholascb670962017-04-20 19:31:52 -0400630 for (BlockId i = 0; i < cfg->fBlocks.size(); i++) {
ethannicholas22f939e2016-10-13 13:25:34 -0700631 workList.insert(i);
632 }
633 while (workList.size()) {
634 BlockId next = *workList.begin();
635 workList.erase(workList.begin());
Ethan Nicholascb670962017-04-20 19:31:52 -0400636 this->scanCFG(cfg, next, &workList);
ethannicholas22f939e2016-10-13 13:25:34 -0700637 }
Ethan Nicholascb670962017-04-20 19:31:52 -0400638}
639
640/**
641 * Attempts to replace the expression pointed to by iter with a new one (in both the CFG and the
642 * IR). If the expression can be cleanly removed, returns true and updates the iterator to point to
643 * the newly-inserted element. Otherwise updates only the IR and returns false (and the CFG will
644 * need to be regenerated).
645 */
646bool try_replace_expression(BasicBlock* b,
647 std::vector<BasicBlock::Node>::iterator* iter,
648 std::unique_ptr<Expression>* newExpression) {
649 std::unique_ptr<Expression>* target = (*iter)->expression();
650 if (!b->tryRemoveExpression(iter)) {
651 *target = std::move(*newExpression);
652 return false;
653 }
654 *target = std::move(*newExpression);
655 return b->tryInsertExpression(iter, target);
656}
657
658/**
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400659 * Returns true if the expression is a constant numeric literal with the specified value, or a
660 * constant vector with all elements equal to the specified value.
Ethan Nicholascb670962017-04-20 19:31:52 -0400661 */
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400662bool is_constant(const Expression& expr, double value) {
Ethan Nicholascb670962017-04-20 19:31:52 -0400663 switch (expr.fKind) {
664 case Expression::kIntLiteral_Kind:
665 return ((IntLiteral&) expr).fValue == value;
666 case Expression::kFloatLiteral_Kind:
667 return ((FloatLiteral&) expr).fValue == value;
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400668 case Expression::kConstructor_Kind: {
669 Constructor& c = (Constructor&) expr;
Ethan Nicholasd188c182019-06-10 15:55:38 -0400670 bool isFloat = c.fType.columns() > 1 ? c.fType.componentType().isFloat()
671 : c.fType.isFloat();
Brian Osmanb6b95732020-06-30 11:44:27 -0400672 if (c.fType.kind() == Type::kVector_Kind && c.isCompileTimeConstant()) {
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400673 for (int i = 0; i < c.fType.columns(); ++i) {
Ethan Nicholasd188c182019-06-10 15:55:38 -0400674 if (isFloat) {
675 if (c.getFVecComponent(i) != value) {
676 return false;
677 }
678 } else if (c.getIVecComponent(i) != value) {
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400679 return false;
680 }
681 }
682 return true;
683 }
684 return false;
685 }
Ethan Nicholascb670962017-04-20 19:31:52 -0400686 default:
687 return false;
688 }
689}
690
691/**
692 * Collapses the binary expression pointed to by iter down to just the right side (in both the IR
693 * and CFG structures).
694 */
695void delete_left(BasicBlock* b,
696 std::vector<BasicBlock::Node>::iterator* iter,
697 bool* outUpdated,
698 bool* outNeedsRescan) {
699 *outUpdated = true;
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400700 std::unique_ptr<Expression>* target = (*iter)->expression();
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400701 SkASSERT((*target)->fKind == Expression::kBinary_Kind);
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400702 BinaryExpression& bin = (BinaryExpression&) **target;
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400703 SkASSERT(!bin.fLeft->hasSideEffects());
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400704 bool result;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400705 if (bin.fOperator == Token::Kind::TK_EQ) {
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400706 result = b->tryRemoveLValueBefore(iter, bin.fLeft.get());
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400707 } else {
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400708 result = b->tryRemoveExpressionBefore(iter, bin.fLeft.get());
Ethan Nicholascb670962017-04-20 19:31:52 -0400709 }
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400710 *target = std::move(bin.fRight);
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400711 if (!result) {
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400712 *outNeedsRescan = true;
713 return;
714 }
715 if (*iter == b->fNodes.begin()) {
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400716 *outNeedsRescan = true;
717 return;
718 }
719 --(*iter);
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400720 if ((*iter)->fKind != BasicBlock::Node::kExpression_Kind ||
721 (*iter)->expression() != &bin.fRight) {
722 *outNeedsRescan = true;
723 return;
724 }
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400725 *iter = b->fNodes.erase(*iter);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400726 SkASSERT((*iter)->expression() == target);
Ethan Nicholascb670962017-04-20 19:31:52 -0400727}
728
729/**
730 * Collapses the binary expression pointed to by iter down to just the left side (in both the IR and
731 * CFG structures).
732 */
733void delete_right(BasicBlock* b,
734 std::vector<BasicBlock::Node>::iterator* iter,
735 bool* outUpdated,
736 bool* outNeedsRescan) {
737 *outUpdated = true;
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400738 std::unique_ptr<Expression>* target = (*iter)->expression();
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400739 SkASSERT((*target)->fKind == Expression::kBinary_Kind);
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400740 BinaryExpression& bin = (BinaryExpression&) **target;
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400741 SkASSERT(!bin.fRight->hasSideEffects());
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400742 if (!b->tryRemoveExpressionBefore(iter, bin.fRight.get())) {
743 *target = std::move(bin.fLeft);
Ethan Nicholascb670962017-04-20 19:31:52 -0400744 *outNeedsRescan = true;
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400745 return;
Ethan Nicholascb670962017-04-20 19:31:52 -0400746 }
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400747 *target = std::move(bin.fLeft);
748 if (*iter == b->fNodes.begin()) {
749 *outNeedsRescan = true;
750 return;
751 }
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400752 --(*iter);
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400753 if (((*iter)->fKind != BasicBlock::Node::kExpression_Kind ||
754 (*iter)->expression() != &bin.fLeft)) {
755 *outNeedsRescan = true;
756 return;
757 }
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400758 *iter = b->fNodes.erase(*iter);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400759 SkASSERT((*iter)->expression() == target);
Ethan Nicholascb670962017-04-20 19:31:52 -0400760}
761
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400762/**
763 * Constructs the specified type using a single argument.
764 */
765static std::unique_ptr<Expression> construct(const Type& type, std::unique_ptr<Expression> v) {
766 std::vector<std::unique_ptr<Expression>> args;
767 args.push_back(std::move(v));
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700768 auto result = std::unique_ptr<Expression>(new Constructor(-1, type, std::move(args)));
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400769 return result;
770}
771
772/**
773 * Used in the implementations of vectorize_left and vectorize_right. Given a vector type and an
774 * expression x, deletes the expression pointed to by iter and replaces it with <type>(x).
775 */
776static void vectorize(BasicBlock* b,
777 std::vector<BasicBlock::Node>::iterator* iter,
778 const Type& type,
779 std::unique_ptr<Expression>* otherExpression,
780 bool* outUpdated,
781 bool* outNeedsRescan) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400782 SkASSERT((*(*iter)->expression())->fKind == Expression::kBinary_Kind);
783 SkASSERT(type.kind() == Type::kVector_Kind);
784 SkASSERT((*otherExpression)->fType.kind() == Type::kScalar_Kind);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400785 *outUpdated = true;
786 std::unique_ptr<Expression>* target = (*iter)->expression();
787 if (!b->tryRemoveExpression(iter)) {
788 *target = construct(type, std::move(*otherExpression));
789 *outNeedsRescan = true;
790 } else {
791 *target = construct(type, std::move(*otherExpression));
792 if (!b->tryInsertExpression(iter, target)) {
793 *outNeedsRescan = true;
794 }
795 }
796}
797
798/**
799 * Given a binary expression of the form x <op> vec<n>(y), deletes the right side and vectorizes the
800 * left to yield vec<n>(x).
801 */
802static void vectorize_left(BasicBlock* b,
803 std::vector<BasicBlock::Node>::iterator* iter,
804 bool* outUpdated,
805 bool* outNeedsRescan) {
806 BinaryExpression& bin = (BinaryExpression&) **(*iter)->expression();
807 vectorize(b, iter, bin.fRight->fType, &bin.fLeft, outUpdated, outNeedsRescan);
808}
809
810/**
811 * Given a binary expression of the form vec<n>(x) <op> y, deletes the left side and vectorizes the
812 * right to yield vec<n>(y).
813 */
814static void vectorize_right(BasicBlock* b,
815 std::vector<BasicBlock::Node>::iterator* iter,
816 bool* outUpdated,
817 bool* outNeedsRescan) {
818 BinaryExpression& bin = (BinaryExpression&) **(*iter)->expression();
819 vectorize(b, iter, bin.fLeft->fType, &bin.fRight, outUpdated, outNeedsRescan);
820}
821
822// Mark that an expression which we were writing to is no longer being written to
823void clear_write(const Expression& expr) {
824 switch (expr.fKind) {
825 case Expression::kVariableReference_Kind: {
826 ((VariableReference&) expr).setRefKind(VariableReference::kRead_RefKind);
827 break;
828 }
829 case Expression::kFieldAccess_Kind:
830 clear_write(*((FieldAccess&) expr).fBase);
831 break;
832 case Expression::kSwizzle_Kind:
833 clear_write(*((Swizzle&) expr).fBase);
834 break;
835 case Expression::kIndex_Kind:
836 clear_write(*((IndexExpression&) expr).fBase);
837 break;
838 default:
839 ABORT("shouldn't be writing to this kind of expression\n");
840 break;
841 }
842}
843
Ethan Nicholascb670962017-04-20 19:31:52 -0400844void Compiler::simplifyExpression(DefinitionMap& definitions,
845 BasicBlock& b,
846 std::vector<BasicBlock::Node>::iterator* iter,
847 std::unordered_set<const Variable*>* undefinedVariables,
848 bool* outUpdated,
849 bool* outNeedsRescan) {
850 Expression* expr = (*iter)->expression()->get();
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400851 SkASSERT(expr);
Ethan Nicholascb670962017-04-20 19:31:52 -0400852 if ((*iter)->fConstantPropagation) {
853 std::unique_ptr<Expression> optimized = expr->constantPropagate(*fIRGenerator, definitions);
854 if (optimized) {
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400855 *outUpdated = true;
Ethan Nicholascb670962017-04-20 19:31:52 -0400856 if (!try_replace_expression(&b, iter, &optimized)) {
857 *outNeedsRescan = true;
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400858 return;
Ethan Nicholascb670962017-04-20 19:31:52 -0400859 }
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400860 SkASSERT((*iter)->fKind == BasicBlock::Node::kExpression_Kind);
Ethan Nicholascb670962017-04-20 19:31:52 -0400861 expr = (*iter)->expression()->get();
Ethan Nicholascb670962017-04-20 19:31:52 -0400862 }
863 }
864 switch (expr->fKind) {
865 case Expression::kVariableReference_Kind: {
Ethan Nicholas8f7e28f2018-03-26 14:24:27 -0400866 const VariableReference& ref = (VariableReference&) *expr;
867 const Variable& var = ref.fVariable;
868 if (ref.refKind() != VariableReference::kWrite_RefKind &&
869 ref.refKind() != VariableReference::kPointer_RefKind &&
870 var.fStorage == Variable::kLocal_Storage && !definitions[&var] &&
Ethan Nicholascb670962017-04-20 19:31:52 -0400871 (*undefinedVariables).find(&var) == (*undefinedVariables).end()) {
872 (*undefinedVariables).insert(&var);
Ethan Nicholas82a62d22017-11-07 14:42:10 +0000873 this->error(expr->fOffset,
874 "'" + var.fName + "' has not been assigned");
Ethan Nicholascb670962017-04-20 19:31:52 -0400875 }
876 break;
877 }
878 case Expression::kTernary_Kind: {
879 TernaryExpression* t = (TernaryExpression*) expr;
880 if (t->fTest->fKind == Expression::kBoolLiteral_Kind) {
881 // ternary has a constant test, replace it with either the true or
882 // false branch
883 if (((BoolLiteral&) *t->fTest).fValue) {
884 (*iter)->setExpression(std::move(t->fIfTrue));
885 } else {
886 (*iter)->setExpression(std::move(t->fIfFalse));
887 }
888 *outUpdated = true;
889 *outNeedsRescan = true;
890 }
891 break;
892 }
893 case Expression::kBinary_Kind: {
Ethan Nicholascb670962017-04-20 19:31:52 -0400894 BinaryExpression* bin = (BinaryExpression*) expr;
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400895 if (dead_assignment(*bin)) {
896 delete_left(&b, iter, outUpdated, outNeedsRescan);
897 break;
898 }
899 // collapse useless expressions like x * 1 or x + 0
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400900 if (((bin->fLeft->fType.kind() != Type::kScalar_Kind) &&
901 (bin->fLeft->fType.kind() != Type::kVector_Kind)) ||
902 ((bin->fRight->fType.kind() != Type::kScalar_Kind) &&
903 (bin->fRight->fType.kind() != Type::kVector_Kind))) {
904 break;
905 }
Ethan Nicholascb670962017-04-20 19:31:52 -0400906 switch (bin->fOperator) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400907 case Token::Kind::TK_STAR:
Ethan Nicholascb670962017-04-20 19:31:52 -0400908 if (is_constant(*bin->fLeft, 1)) {
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400909 if (bin->fLeft->fType.kind() == Type::kVector_Kind &&
910 bin->fRight->fType.kind() == Type::kScalar_Kind) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400911 // float4(1) * x -> float4(x)
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400912 vectorize_right(&b, iter, outUpdated, outNeedsRescan);
913 } else {
914 // 1 * x -> x
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400915 // 1 * float4(x) -> float4(x)
916 // float4(1) * float4(x) -> float4(x)
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400917 delete_left(&b, iter, outUpdated, outNeedsRescan);
918 }
919 }
920 else if (is_constant(*bin->fLeft, 0)) {
921 if (bin->fLeft->fType.kind() == Type::kScalar_Kind &&
Ethan Nicholas08dae922018-01-23 10:31:56 -0500922 bin->fRight->fType.kind() == Type::kVector_Kind &&
923 !bin->fRight->hasSideEffects()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400924 // 0 * float4(x) -> float4(0)
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400925 vectorize_left(&b, iter, outUpdated, outNeedsRescan);
926 } else {
927 // 0 * x -> 0
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400928 // float4(0) * x -> float4(0)
929 // float4(0) * float4(x) -> float4(0)
Ethan Nicholas51493ee2017-12-11 12:34:33 -0500930 if (!bin->fRight->hasSideEffects()) {
931 delete_right(&b, iter, outUpdated, outNeedsRescan);
932 }
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400933 }
Ethan Nicholascb670962017-04-20 19:31:52 -0400934 }
935 else if (is_constant(*bin->fRight, 1)) {
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400936 if (bin->fLeft->fType.kind() == Type::kScalar_Kind &&
937 bin->fRight->fType.kind() == Type::kVector_Kind) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400938 // x * float4(1) -> float4(x)
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400939 vectorize_left(&b, iter, outUpdated, outNeedsRescan);
940 } else {
941 // x * 1 -> x
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400942 // float4(x) * 1 -> float4(x)
943 // float4(x) * float4(1) -> float4(x)
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400944 delete_right(&b, iter, outUpdated, outNeedsRescan);
945 }
946 }
947 else if (is_constant(*bin->fRight, 0)) {
948 if (bin->fLeft->fType.kind() == Type::kVector_Kind &&
Ethan Nicholas08dae922018-01-23 10:31:56 -0500949 bin->fRight->fType.kind() == Type::kScalar_Kind &&
950 !bin->fLeft->hasSideEffects()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400951 // float4(x) * 0 -> float4(0)
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400952 vectorize_right(&b, iter, outUpdated, outNeedsRescan);
953 } else {
954 // x * 0 -> 0
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400955 // x * float4(0) -> float4(0)
956 // float4(x) * float4(0) -> float4(0)
Ethan Nicholas51493ee2017-12-11 12:34:33 -0500957 if (!bin->fLeft->hasSideEffects()) {
958 delete_left(&b, iter, outUpdated, outNeedsRescan);
959 }
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400960 }
Ethan Nicholascb670962017-04-20 19:31:52 -0400961 }
962 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400963 case Token::Kind::TK_PLUS:
Ethan Nicholascb670962017-04-20 19:31:52 -0400964 if (is_constant(*bin->fLeft, 0)) {
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400965 if (bin->fLeft->fType.kind() == Type::kVector_Kind &&
966 bin->fRight->fType.kind() == Type::kScalar_Kind) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400967 // float4(0) + x -> float4(x)
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400968 vectorize_right(&b, iter, outUpdated, outNeedsRescan);
969 } else {
970 // 0 + x -> x
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400971 // 0 + float4(x) -> float4(x)
972 // float4(0) + float4(x) -> float4(x)
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400973 delete_left(&b, iter, outUpdated, outNeedsRescan);
974 }
975 } else if (is_constant(*bin->fRight, 0)) {
976 if (bin->fLeft->fType.kind() == Type::kScalar_Kind &&
977 bin->fRight->fType.kind() == Type::kVector_Kind) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400978 // x + float4(0) -> float4(x)
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400979 vectorize_left(&b, iter, outUpdated, outNeedsRescan);
980 } else {
981 // x + 0 -> x
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400982 // float4(x) + 0 -> float4(x)
983 // float4(x) + float4(0) -> float4(x)
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400984 delete_right(&b, iter, outUpdated, outNeedsRescan);
985 }
Ethan Nicholas56e42712017-04-21 10:23:37 -0400986 }
987 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400988 case Token::Kind::TK_MINUS:
Ethan Nicholas56e42712017-04-21 10:23:37 -0400989 if (is_constant(*bin->fRight, 0)) {
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400990 if (bin->fLeft->fType.kind() == Type::kScalar_Kind &&
991 bin->fRight->fType.kind() == Type::kVector_Kind) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400992 // x - float4(0) -> float4(x)
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400993 vectorize_left(&b, iter, outUpdated, outNeedsRescan);
994 } else {
995 // x - 0 -> x
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400996 // float4(x) - 0 -> float4(x)
997 // float4(x) - float4(0) -> float4(x)
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400998 delete_right(&b, iter, outUpdated, outNeedsRescan);
999 }
Ethan Nicholascb670962017-04-20 19:31:52 -04001000 }
1001 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001002 case Token::Kind::TK_SLASH:
Ethan Nicholascb670962017-04-20 19:31:52 -04001003 if (is_constant(*bin->fRight, 1)) {
Ethan Nicholasfe53e582017-04-27 16:24:51 -04001004 if (bin->fLeft->fType.kind() == Type::kScalar_Kind &&
1005 bin->fRight->fType.kind() == Type::kVector_Kind) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -04001006 // x / float4(1) -> float4(x)
Ethan Nicholasfe53e582017-04-27 16:24:51 -04001007 vectorize_left(&b, iter, outUpdated, outNeedsRescan);
1008 } else {
1009 // x / 1 -> x
Ethan Nicholas5af9ea32017-07-28 15:19:46 -04001010 // float4(x) / 1 -> float4(x)
1011 // float4(x) / float4(1) -> float4(x)
Ethan Nicholasfe53e582017-04-27 16:24:51 -04001012 delete_right(&b, iter, outUpdated, outNeedsRescan);
1013 }
1014 } else if (is_constant(*bin->fLeft, 0)) {
1015 if (bin->fLeft->fType.kind() == Type::kScalar_Kind &&
Ethan Nicholas08dae922018-01-23 10:31:56 -05001016 bin->fRight->fType.kind() == Type::kVector_Kind &&
1017 !bin->fRight->hasSideEffects()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -04001018 // 0 / float4(x) -> float4(0)
Ethan Nicholasfe53e582017-04-27 16:24:51 -04001019 vectorize_left(&b, iter, outUpdated, outNeedsRescan);
1020 } else {
1021 // 0 / x -> 0
Ethan Nicholas5af9ea32017-07-28 15:19:46 -04001022 // float4(0) / x -> float4(0)
1023 // float4(0) / float4(x) -> float4(0)
Ethan Nicholas51493ee2017-12-11 12:34:33 -05001024 if (!bin->fRight->hasSideEffects()) {
1025 delete_right(&b, iter, outUpdated, outNeedsRescan);
1026 }
Ethan Nicholasfe53e582017-04-27 16:24:51 -04001027 }
1028 }
1029 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001030 case Token::Kind::TK_PLUSEQ:
Ethan Nicholasfe53e582017-04-27 16:24:51 -04001031 if (is_constant(*bin->fRight, 0)) {
1032 clear_write(*bin->fLeft);
1033 delete_right(&b, iter, outUpdated, outNeedsRescan);
1034 }
1035 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001036 case Token::Kind::TK_MINUSEQ:
Ethan Nicholasfe53e582017-04-27 16:24:51 -04001037 if (is_constant(*bin->fRight, 0)) {
1038 clear_write(*bin->fLeft);
1039 delete_right(&b, iter, outUpdated, outNeedsRescan);
1040 }
1041 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001042 case Token::Kind::TK_STAREQ:
Ethan Nicholasfe53e582017-04-27 16:24:51 -04001043 if (is_constant(*bin->fRight, 1)) {
1044 clear_write(*bin->fLeft);
1045 delete_right(&b, iter, outUpdated, outNeedsRescan);
1046 }
1047 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001048 case Token::Kind::TK_SLASHEQ:
Ethan Nicholasfe53e582017-04-27 16:24:51 -04001049 if (is_constant(*bin->fRight, 1)) {
1050 clear_write(*bin->fLeft);
Ethan Nicholascb670962017-04-20 19:31:52 -04001051 delete_right(&b, iter, outUpdated, outNeedsRescan);
1052 }
1053 break;
1054 default:
1055 break;
1056 }
Ethan Nicholas409f6f02019-09-17 12:34:39 -04001057 break;
1058 }
1059 case Expression::kSwizzle_Kind: {
1060 Swizzle& s = (Swizzle&) *expr;
1061 // detect identity swizzles like foo.rgba
1062 if ((int) s.fComponents.size() == s.fBase->fType.columns()) {
1063 bool identity = true;
1064 for (int i = 0; i < (int) s.fComponents.size(); ++i) {
1065 if (s.fComponents[i] != i) {
1066 identity = false;
1067 break;
1068 }
1069 }
1070 if (identity) {
1071 *outUpdated = true;
1072 if (!try_replace_expression(&b, iter, &s.fBase)) {
1073 *outNeedsRescan = true;
1074 return;
1075 }
1076 SkASSERT((*iter)->fKind == BasicBlock::Node::kExpression_Kind);
1077 break;
1078 }
1079 }
1080 // detect swizzles of swizzles, e.g. replace foo.argb.r000 with foo.a000
1081 if (s.fBase->fKind == Expression::kSwizzle_Kind) {
1082 Swizzle& base = (Swizzle&) *s.fBase;
1083 std::vector<int> final;
1084 for (int c : s.fComponents) {
1085 if (c == SKSL_SWIZZLE_0 || c == SKSL_SWIZZLE_1) {
1086 final.push_back(c);
1087 } else {
1088 final.push_back(base.fComponents[c]);
1089 }
1090 }
1091 *outUpdated = true;
1092 std::unique_ptr<Expression> replacement(new Swizzle(*fContext, base.fBase->clone(),
1093 std::move(final)));
1094 if (!try_replace_expression(&b, iter, &replacement)) {
1095 *outNeedsRescan = true;
1096 return;
1097 }
1098 SkASSERT((*iter)->fKind == BasicBlock::Node::kExpression_Kind);
Ethan Nicholas409f6f02019-09-17 12:34:39 -04001099 }
John Stiles30212b72020-06-11 17:55:07 -04001100 break;
Ethan Nicholascb670962017-04-20 19:31:52 -04001101 }
1102 default:
1103 break;
1104 }
1105}
1106
John Stiles92219b42020-06-15 12:32:24 -04001107// Implementation-detail recursive helper function for `contains_conditional_break`.
1108static bool contains_conditional_break_impl(Statement& s, bool inConditional) {
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001109 switch (s.fKind) {
1110 case Statement::kBlock_Kind:
John Stiles92219b42020-06-15 12:32:24 -04001111 for (const std::unique_ptr<Statement>& sub : static_cast<Block&>(s).fStatements) {
1112 if (contains_conditional_break_impl(*sub, inConditional)) {
Ethan Nicholas5005a222018-08-24 13:06:27 -04001113 return true;
1114 }
1115 }
1116 return false;
John Stiles92219b42020-06-15 12:32:24 -04001117
Ethan Nicholas5005a222018-08-24 13:06:27 -04001118 case Statement::kBreak_Kind:
1119 return inConditional;
John Stiles92219b42020-06-15 12:32:24 -04001120
Ethan Nicholas5005a222018-08-24 13:06:27 -04001121 case Statement::kIf_Kind: {
John Stiles92219b42020-06-15 12:32:24 -04001122 const IfStatement& i = static_cast<IfStatement&>(s);
1123 return contains_conditional_break_impl(*i.fIfTrue, /*inConditional=*/true) ||
1124 (i.fIfFalse &&
1125 contains_conditional_break_impl(*i.fIfFalse, /*inConditional=*/true));
Ethan Nicholas5005a222018-08-24 13:06:27 -04001126 }
John Stiles92219b42020-06-15 12:32:24 -04001127
Ethan Nicholas5005a222018-08-24 13:06:27 -04001128 default:
1129 return false;
1130 }
1131}
1132
John Stiles92219b42020-06-15 12:32:24 -04001133// Returns true if this statement could potentially execute a break at the current level. We ignore
1134// nested loops and switches, since any breaks inside of them will merely break the loop / switch.
1135static bool contains_conditional_break(Statement& s) {
1136 return contains_conditional_break_impl(s, /*inConditional=*/false);
1137}
1138
Ethan Nicholas5005a222018-08-24 13:06:27 -04001139// returns true if this statement definitely executes a break at the current level (we ignore
1140// nested loops and switches, since any breaks inside of them will merely break the loop / switch)
1141static bool contains_unconditional_break(Statement& s) {
1142 switch (s.fKind) {
1143 case Statement::kBlock_Kind:
John Stiles92219b42020-06-15 12:32:24 -04001144 for (const std::unique_ptr<Statement>& sub : static_cast<Block&>(s).fStatements) {
Ethan Nicholas5005a222018-08-24 13:06:27 -04001145 if (contains_unconditional_break(*sub)) {
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001146 return true;
1147 }
1148 }
1149 return false;
John Stiles92219b42020-06-15 12:32:24 -04001150
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001151 case Statement::kBreak_Kind:
1152 return true;
John Stiles92219b42020-06-15 12:32:24 -04001153
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001154 default:
1155 return false;
1156 }
1157}
1158
John Stiles92219b42020-06-15 12:32:24 -04001159static void move_all_but_break(std::unique_ptr<Statement>& stmt,
1160 std::vector<std::unique_ptr<Statement>>* target) {
Ethan Nicholas739e1ca2020-06-11 12:16:14 -04001161 switch (stmt->fKind) {
John Stiles92219b42020-06-15 12:32:24 -04001162 case Statement::kBlock_Kind: {
1163 // Recurse into the block.
1164 Block& block = static_cast<Block&>(*stmt);
1165
1166 std::vector<std::unique_ptr<Statement>> blockStmts;
1167 blockStmts.reserve(block.fStatements.size());
1168 for (std::unique_ptr<Statement>& statementInBlock : block.fStatements) {
1169 move_all_but_break(statementInBlock, &blockStmts);
Ethan Nicholas739e1ca2020-06-11 12:16:14 -04001170 }
John Stiles92219b42020-06-15 12:32:24 -04001171
1172 target->push_back(std::make_unique<Block>(block.fOffset, std::move(blockStmts),
1173 block.fSymbols, block.fIsScope));
Ethan Nicholas739e1ca2020-06-11 12:16:14 -04001174 break;
John Stiles92219b42020-06-15 12:32:24 -04001175 }
1176
Ethan Nicholas739e1ca2020-06-11 12:16:14 -04001177 case Statement::kBreak_Kind:
John Stiles92219b42020-06-15 12:32:24 -04001178 // Do not append a break to the target.
1179 break;
1180
Ethan Nicholas739e1ca2020-06-11 12:16:14 -04001181 default:
John Stiles92219b42020-06-15 12:32:24 -04001182 // Append normal statements to the target.
1183 target->push_back(std::move(stmt));
1184 break;
Ethan Nicholas739e1ca2020-06-11 12:16:14 -04001185 }
1186}
1187
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001188// Returns a block containing all of the statements that will be run if the given case matches
1189// (which, owing to the statements being owned by unique_ptrs, means the switch itself will be
1190// broken by this call and must then be discarded).
1191// Returns null (and leaves the switch unmodified) if no such simple reduction is possible, such as
1192// when break statements appear inside conditionals.
John Stiles92219b42020-06-15 12:32:24 -04001193static std::unique_ptr<Statement> block_for_case(SwitchStatement* switchStatement,
1194 SwitchCase* caseToCapture) {
1195 // We have to be careful to not move any of the pointers until after we're sure we're going to
1196 // succeed, so before we make any changes at all, we check the switch-cases to decide on a plan
1197 // of action. First, find the switch-case we are interested in.
1198 auto iter = switchStatement->fCases.begin();
1199 for (; iter != switchStatement->fCases.end(); ++iter) {
1200 if (iter->get() == caseToCapture) {
1201 break;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001202 }
John Stiles92219b42020-06-15 12:32:24 -04001203 }
1204
1205 // Next, walk forward through the rest of the switch. If we find a conditional break, we're
1206 // stuck and can't simplify at all. If we find an unconditional break, we have a range of
1207 // statements that we can use for simplification.
1208 auto startIter = iter;
1209 Statement* unconditionalBreakStmt = nullptr;
1210 for (; iter != switchStatement->fCases.end(); ++iter) {
1211 for (std::unique_ptr<Statement>& stmt : (*iter)->fStatements) {
1212 if (contains_conditional_break(*stmt)) {
1213 // We can't reduce switch-cases to a block when they have conditional breaks.
1214 return nullptr;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001215 }
John Stiles92219b42020-06-15 12:32:24 -04001216
1217 if (contains_unconditional_break(*stmt)) {
1218 // We found an unconditional break. We can use this block, but we need to strip
1219 // out the break statement.
1220 unconditionalBreakStmt = stmt.get();
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001221 break;
1222 }
1223 }
John Stiles92219b42020-06-15 12:32:24 -04001224
1225 if (unconditionalBreakStmt != nullptr) {
1226 break;
1227 }
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001228 }
John Stiles92219b42020-06-15 12:32:24 -04001229
1230 // We fell off the bottom of the switch or encountered a break. We know the range of statements
1231 // that we need to move over, and we know it's safe to do so.
1232 std::vector<std::unique_ptr<Statement>> caseStmts;
1233
1234 // We can move over most of the statements as-is.
1235 while (startIter != iter) {
1236 for (std::unique_ptr<Statement>& stmt : (*startIter)->fStatements) {
1237 caseStmts.push_back(std::move(stmt));
1238 }
1239 ++startIter;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001240 }
John Stiles92219b42020-06-15 12:32:24 -04001241
1242 // If we found an unconditional break at the end, we need to move what we can while avoiding
1243 // that break.
1244 if (unconditionalBreakStmt != nullptr) {
1245 for (std::unique_ptr<Statement>& stmt : (*startIter)->fStatements) {
1246 if (stmt.get() == unconditionalBreakStmt) {
1247 move_all_but_break(stmt, &caseStmts);
1248 unconditionalBreakStmt = nullptr;
1249 break;
1250 }
1251
1252 caseStmts.push_back(std::move(stmt));
1253 }
1254 }
1255
1256 SkASSERT(unconditionalBreakStmt == nullptr); // Verify that we fixed the unconditional break.
1257
1258 // Return our newly-synthesized block.
1259 return std::make_unique<Block>(/*offset=*/-1, std::move(caseStmts), switchStatement->fSymbols);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001260}
1261
Ethan Nicholascb670962017-04-20 19:31:52 -04001262void Compiler::simplifyStatement(DefinitionMap& definitions,
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001263 BasicBlock& b,
1264 std::vector<BasicBlock::Node>::iterator* iter,
1265 std::unordered_set<const Variable*>* undefinedVariables,
1266 bool* outUpdated,
1267 bool* outNeedsRescan) {
Ethan Nicholascb670962017-04-20 19:31:52 -04001268 Statement* stmt = (*iter)->statement()->get();
1269 switch (stmt->fKind) {
Ethan Nicholas82a62d22017-11-07 14:42:10 +00001270 case Statement::kVarDeclaration_Kind: {
1271 const auto& varDecl = (VarDeclaration&) *stmt;
1272 if (varDecl.fVar->dead() &&
1273 (!varDecl.fValue ||
1274 !varDecl.fValue->hasSideEffects())) {
1275 if (varDecl.fValue) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001276 SkASSERT((*iter)->statement()->get() == stmt);
Ethan Nicholas82a62d22017-11-07 14:42:10 +00001277 if (!b.tryRemoveExpressionBefore(iter, varDecl.fValue.get())) {
1278 *outNeedsRescan = true;
Ethan Nicholascb670962017-04-20 19:31:52 -04001279 }
Ethan Nicholascb670962017-04-20 19:31:52 -04001280 }
Ethan Nicholascb670962017-04-20 19:31:52 -04001281 (*iter)->setStatement(std::unique_ptr<Statement>(new Nop()));
Ethan Nicholas82a62d22017-11-07 14:42:10 +00001282 *outUpdated = true;
Ethan Nicholascb670962017-04-20 19:31:52 -04001283 }
1284 break;
1285 }
1286 case Statement::kIf_Kind: {
1287 IfStatement& i = (IfStatement&) *stmt;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001288 if (i.fTest->fKind == Expression::kBoolLiteral_Kind) {
1289 // constant if, collapse down to a single branch
1290 if (((BoolLiteral&) *i.fTest).fValue) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001291 SkASSERT(i.fIfTrue);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001292 (*iter)->setStatement(std::move(i.fIfTrue));
1293 } else {
1294 if (i.fIfFalse) {
1295 (*iter)->setStatement(std::move(i.fIfFalse));
1296 } else {
1297 (*iter)->setStatement(std::unique_ptr<Statement>(new Nop()));
1298 }
1299 }
1300 *outUpdated = true;
1301 *outNeedsRescan = true;
1302 break;
1303 }
Ethan Nicholascb670962017-04-20 19:31:52 -04001304 if (i.fIfFalse && i.fIfFalse->isEmpty()) {
1305 // else block doesn't do anything, remove it
1306 i.fIfFalse.reset();
1307 *outUpdated = true;
1308 *outNeedsRescan = true;
1309 }
1310 if (!i.fIfFalse && i.fIfTrue->isEmpty()) {
1311 // if block doesn't do anything, no else block
1312 if (i.fTest->hasSideEffects()) {
1313 // test has side effects, keep it
1314 (*iter)->setStatement(std::unique_ptr<Statement>(
1315 new ExpressionStatement(std::move(i.fTest))));
1316 } else {
1317 // no if, no else, no test side effects, kill the whole if
1318 // statement
1319 (*iter)->setStatement(std::unique_ptr<Statement>(new Nop()));
1320 }
1321 *outUpdated = true;
1322 *outNeedsRescan = true;
1323 }
1324 break;
1325 }
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001326 case Statement::kSwitch_Kind: {
1327 SwitchStatement& s = (SwitchStatement&) *stmt;
Brian Osmanb6b95732020-06-30 11:44:27 -04001328 if (s.fValue->isCompileTimeConstant()) {
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001329 // switch is constant, replace it with the case that matches
1330 bool found = false;
1331 SwitchCase* defaultCase = nullptr;
1332 for (const auto& c : s.fCases) {
1333 if (!c->fValue) {
1334 defaultCase = c.get();
1335 continue;
1336 }
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001337 SkASSERT(c->fValue->fKind == s.fValue->fKind);
Ethan Nicholas26a9aad2018-03-27 14:10:52 -04001338 found = c->fValue->compareConstant(*fContext, *s.fValue);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001339 if (found) {
1340 std::unique_ptr<Statement> newBlock = block_for_case(&s, c.get());
1341 if (newBlock) {
1342 (*iter)->setStatement(std::move(newBlock));
1343 break;
1344 } else {
Ethan Nicholas6e1cbc02017-07-14 10:12:15 -04001345 if (s.fIsStatic && !(fFlags & kPermitInvalidStaticTests_Flag)) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001346 this->error(s.fOffset,
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001347 "static switch contains non-static conditional break");
1348 s.fIsStatic = false;
1349 }
1350 return; // can't simplify
1351 }
1352 }
1353 }
1354 if (!found) {
1355 // no matching case. use default if it exists, or kill the whole thing
1356 if (defaultCase) {
1357 std::unique_ptr<Statement> newBlock = block_for_case(&s, defaultCase);
1358 if (newBlock) {
1359 (*iter)->setStatement(std::move(newBlock));
1360 } else {
Ethan Nicholas6e1cbc02017-07-14 10:12:15 -04001361 if (s.fIsStatic && !(fFlags & kPermitInvalidStaticTests_Flag)) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001362 this->error(s.fOffset,
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001363 "static switch contains non-static conditional break");
1364 s.fIsStatic = false;
1365 }
1366 return; // can't simplify
1367 }
1368 } else {
1369 (*iter)->setStatement(std::unique_ptr<Statement>(new Nop()));
1370 }
1371 }
1372 *outUpdated = true;
1373 *outNeedsRescan = true;
1374 }
1375 break;
1376 }
Ethan Nicholascb670962017-04-20 19:31:52 -04001377 case Statement::kExpression_Kind: {
1378 ExpressionStatement& e = (ExpressionStatement&) *stmt;
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001379 SkASSERT((*iter)->statement()->get() == &e);
Ethan Nicholascb670962017-04-20 19:31:52 -04001380 if (!e.fExpression->hasSideEffects()) {
1381 // Expression statement with no side effects, kill it
1382 if (!b.tryRemoveExpressionBefore(iter, e.fExpression.get())) {
1383 *outNeedsRescan = true;
1384 }
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001385 SkASSERT((*iter)->statement()->get() == stmt);
Ethan Nicholascb670962017-04-20 19:31:52 -04001386 (*iter)->setStatement(std::unique_ptr<Statement>(new Nop()));
1387 *outUpdated = true;
1388 }
1389 break;
1390 }
1391 default:
1392 break;
1393 }
1394}
1395
1396void Compiler::scanCFG(FunctionDefinition& f) {
1397 CFG cfg = CFGGenerator().getCFG(f);
1398 this->computeDataFlow(&cfg);
ethannicholas22f939e2016-10-13 13:25:34 -07001399
1400 // check for unreachable code
1401 for (size_t i = 0; i < cfg.fBlocks.size(); i++) {
Mike Klein6ad99092016-10-26 10:35:22 -04001402 if (i != cfg.fStart && !cfg.fBlocks[i].fEntrances.size() &&
ethannicholas22f939e2016-10-13 13:25:34 -07001403 cfg.fBlocks[i].fNodes.size()) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001404 int offset;
Ethan Nicholas86a43402017-01-19 13:32:00 -05001405 switch (cfg.fBlocks[i].fNodes[0].fKind) {
1406 case BasicBlock::Node::kStatement_Kind:
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001407 offset = (*cfg.fBlocks[i].fNodes[0].statement())->fOffset;
Ethan Nicholas86a43402017-01-19 13:32:00 -05001408 break;
1409 case BasicBlock::Node::kExpression_Kind:
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001410 offset = (*cfg.fBlocks[i].fNodes[0].expression())->fOffset;
Ethan Nicholas70728ef2020-05-28 07:09:00 -04001411 if ((*cfg.fBlocks[i].fNodes[0].expression())->fKind ==
1412 Expression::kBoolLiteral_Kind) {
1413 // Function inlining can generate do { ... } while(false) loops which always
1414 // break, so the boolean condition is considered unreachable. Since not
1415 // being able to reach a literal is a non-issue in the first place, we
1416 // don't report an error in this case.
1417 continue;
1418 }
Ethan Nicholas86a43402017-01-19 13:32:00 -05001419 break;
1420 }
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001421 this->error(offset, String("unreachable"));
ethannicholas22f939e2016-10-13 13:25:34 -07001422 }
1423 }
1424 if (fErrorCount) {
1425 return;
1426 }
1427
Ethan Nicholascb670962017-04-20 19:31:52 -04001428 // check for dead code & undefined variables, perform constant propagation
1429 std::unordered_set<const Variable*> undefinedVariables;
1430 bool updated;
1431 bool needsRescan = false;
1432 do {
1433 if (needsRescan) {
1434 cfg = CFGGenerator().getCFG(f);
1435 this->computeDataFlow(&cfg);
1436 needsRescan = false;
Ethan Nicholas113628d2017-02-02 16:11:39 -05001437 }
Ethan Nicholascb670962017-04-20 19:31:52 -04001438
1439 updated = false;
Ethan Nicholas1de14812020-06-19 15:32:49 -04001440 bool first = true;
Ethan Nicholascb670962017-04-20 19:31:52 -04001441 for (BasicBlock& b : cfg.fBlocks) {
Ethan Nicholas1de14812020-06-19 15:32:49 -04001442 if (!first && b.fEntrances.empty()) {
1443 // Block was reachable before optimization, but has since become unreachable. In
1444 // addition to being dead code, it's broken - since control flow can't reach it, no
1445 // prior variable definitions can reach it, and therefore variables might look to
1446 // have not been properly assigned. Kill it.
1447 for (BasicBlock::Node& node : b.fNodes) {
1448 if (node.fKind == BasicBlock::Node::kStatement_Kind &&
1449 (*node.statement())->fKind != Statement::kNop_Kind) {
1450 node.setStatement(std::unique_ptr<Statement>(new Nop()));
1451 }
1452 }
1453 continue;
1454 }
1455 first = false;
Ethan Nicholascb670962017-04-20 19:31:52 -04001456 DefinitionMap definitions = b.fBefore;
1457
1458 for (auto iter = b.fNodes.begin(); iter != b.fNodes.end() && !needsRescan; ++iter) {
1459 if (iter->fKind == BasicBlock::Node::kExpression_Kind) {
1460 this->simplifyExpression(definitions, b, &iter, &undefinedVariables, &updated,
1461 &needsRescan);
1462 } else {
1463 this->simplifyStatement(definitions, b, &iter, &undefinedVariables, &updated,
1464 &needsRescan);
1465 }
Ethan Nicholas4b330df2017-05-17 10:52:55 -04001466 if (needsRescan) {
1467 break;
1468 }
Ethan Nicholascb670962017-04-20 19:31:52 -04001469 this->addDefinitions(*iter, &definitions);
1470 }
1471 }
1472 } while (updated);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001473 SkASSERT(!needsRescan);
ethannicholas22f939e2016-10-13 13:25:34 -07001474
Ethan Nicholas91a10532017-06-22 11:24:38 -04001475 // verify static ifs & switches, clean up dead variable decls
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001476 for (BasicBlock& b : cfg.fBlocks) {
1477 DefinitionMap definitions = b.fBefore;
1478
Ethan Nicholas91a10532017-06-22 11:24:38 -04001479 for (auto iter = b.fNodes.begin(); iter != b.fNodes.end() && !needsRescan;) {
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001480 if (iter->fKind == BasicBlock::Node::kStatement_Kind) {
1481 const Statement& s = **iter->statement();
1482 switch (s.fKind) {
1483 case Statement::kIf_Kind:
Ethan Nicholas6e1cbc02017-07-14 10:12:15 -04001484 if (((const IfStatement&) s).fIsStatic &&
1485 !(fFlags & kPermitInvalidStaticTests_Flag)) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001486 this->error(s.fOffset, "static if has non-static test");
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001487 }
Ethan Nicholas91a10532017-06-22 11:24:38 -04001488 ++iter;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001489 break;
1490 case Statement::kSwitch_Kind:
Ethan Nicholas6e1cbc02017-07-14 10:12:15 -04001491 if (((const SwitchStatement&) s).fIsStatic &&
1492 !(fFlags & kPermitInvalidStaticTests_Flag)) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001493 this->error(s.fOffset, "static switch has non-static test");
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001494 }
Ethan Nicholas91a10532017-06-22 11:24:38 -04001495 ++iter;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001496 break;
Ethan Nicholas82a62d22017-11-07 14:42:10 +00001497 case Statement::kVarDeclarations_Kind: {
1498 VarDeclarations& decls = *((VarDeclarationsStatement&) s).fDeclaration;
1499 for (auto varIter = decls.fVars.begin(); varIter != decls.fVars.end();) {
1500 if ((*varIter)->fKind == Statement::kNop_Kind) {
1501 varIter = decls.fVars.erase(varIter);
1502 } else {
1503 ++varIter;
1504 }
1505 }
1506 if (!decls.fVars.size()) {
1507 iter = b.fNodes.erase(iter);
1508 } else {
1509 ++iter;
1510 }
1511 break;
1512 }
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001513 default:
Ethan Nicholas91a10532017-06-22 11:24:38 -04001514 ++iter;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001515 break;
1516 }
Ethan Nicholas91a10532017-06-22 11:24:38 -04001517 } else {
1518 ++iter;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001519 }
1520 }
1521 }
1522
ethannicholas22f939e2016-10-13 13:25:34 -07001523 // check for missing return
Ethan Nicholas26a9aad2018-03-27 14:10:52 -04001524 if (f.fDeclaration.fReturnType != *fContext->fVoid_Type) {
ethannicholas22f939e2016-10-13 13:25:34 -07001525 if (cfg.fBlocks[cfg.fExit].fEntrances.size()) {
Ethan Nicholasdb80f692019-11-22 14:06:12 -05001526 this->error(f.fOffset, String("function '" + String(f.fDeclaration.fName) +
1527 "' can exit without returning a value"));
ethannicholas22f939e2016-10-13 13:25:34 -07001528 }
1529 }
1530}
1531
Ethan Nicholas91164d12019-05-15 15:29:54 -04001532void Compiler::registerExternalValue(ExternalValue* value) {
1533 fIRGenerator->fRootSymbolTable->addWithoutOwnership(value->fName, value);
1534}
1535
Ethan Nicholasc18bb512020-07-28 14:46:53 -04001536const Symbol* Compiler::takeOwnership(std::unique_ptr<const Symbol> symbol) {
Ethan Nicholas91164d12019-05-15 15:29:54 -04001537 return fIRGenerator->fRootSymbolTable->takeOwnership(std::move(symbol));
1538}
1539
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001540std::unique_ptr<Program> Compiler::convertProgram(Program::Kind kind, String text,
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001541 const Program::Settings& settings) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001542 fErrorText = "";
1543 fErrorCount = 0;
Ethan Nicholas3c6ae622018-04-24 13:06:09 -04001544 std::vector<std::unique_ptr<ProgramElement>>* inherited;
ethannicholasd598f792016-07-25 10:08:54 -07001545 std::vector<std::unique_ptr<ProgramElement>> elements;
ethannicholasb3058bd2016-07-01 08:22:01 -07001546 switch (kind) {
1547 case Program::kVertex_Kind:
Ethan Nicholas3c6ae622018-04-24 13:06:09 -04001548 inherited = &fVertexInclude;
1549 fIRGenerator->fSymbolTable = fVertexSymbolTable;
Ethan Nicholasdb80f692019-11-22 14:06:12 -05001550 fIRGenerator->fIntrinsics = &fGPUIntrinsics;
Ethan Nicholas3c6ae622018-04-24 13:06:09 -04001551 fIRGenerator->start(&settings, inherited);
ethannicholasb3058bd2016-07-01 08:22:01 -07001552 break;
1553 case Program::kFragment_Kind:
Ethan Nicholas3c6ae622018-04-24 13:06:09 -04001554 inherited = &fFragmentInclude;
1555 fIRGenerator->fSymbolTable = fFragmentSymbolTable;
Ethan Nicholasdb80f692019-11-22 14:06:12 -05001556 fIRGenerator->fIntrinsics = &fGPUIntrinsics;
Ethan Nicholas3c6ae622018-04-24 13:06:09 -04001557 fIRGenerator->start(&settings, inherited);
ethannicholasb3058bd2016-07-01 08:22:01 -07001558 break;
Ethan Nicholas52cad152017-02-16 16:37:32 -05001559 case Program::kGeometry_Kind:
Ethan Nicholasc18bb512020-07-28 14:46:53 -04001560 this->loadGeometryIntrinsics();
Ethan Nicholas3c6ae622018-04-24 13:06:09 -04001561 inherited = &fGeometryInclude;
1562 fIRGenerator->fSymbolTable = fGeometrySymbolTable;
Ethan Nicholasdb80f692019-11-22 14:06:12 -05001563 fIRGenerator->fIntrinsics = &fGPUIntrinsics;
Ethan Nicholas3c6ae622018-04-24 13:06:09 -04001564 fIRGenerator->start(&settings, inherited);
Ethan Nicholas52cad152017-02-16 16:37:32 -05001565 break;
Ethan Nicholas762466e2017-06-29 10:03:38 -04001566 case Program::kFragmentProcessor_Kind:
Ethan Nicholasc18bb512020-07-28 14:46:53 -04001567#if REHYDRATE
1568 {
1569 Rehydrator rehydrator(fContext.get(), fGpuSymbolTable, this,
1570 SKSL_INCLUDE_sksl_fp,
1571 SKSL_INCLUDE_sksl_fp_LENGTH);
1572 fFPSymbolTable = rehydrator.symbolTable();
1573 fFPInclude = rehydrator.elements();
1574 }
1575 inherited = &fFPInclude;
1576 fIRGenerator->fSymbolTable = fFPSymbolTable;
1577 fIRGenerator->fIntrinsics = &fGPUIntrinsics;
1578 fIRGenerator->start(&settings, inherited);
1579 break;
1580#else
Ethan Nicholas3c6ae622018-04-24 13:06:09 -04001581 inherited = nullptr;
Ethan Nicholas8da1e652019-05-24 11:01:59 -04001582 fIRGenerator->fSymbolTable = fGpuSymbolTable;
Ethan Nicholasc18bb512020-07-28 14:46:53 -04001583 fIRGenerator->start(&settings, nullptr, true);
Ethan Nicholasdb80f692019-11-22 14:06:12 -05001584 fIRGenerator->fIntrinsics = &fGPUIntrinsics;
Ethan Nicholasc18bb512020-07-28 14:46:53 -04001585 fIRGenerator->convertProgram(kind, SKSL_FP_INCLUDE, strlen(SKSL_FP_INCLUDE), &elements);
1586 fIRGenerator->fIsBuiltinCode = false;
Ethan Nicholas762466e2017-06-29 10:03:38 -04001587 break;
Ethan Nicholasc18bb512020-07-28 14:46:53 -04001588#endif
Ethan Nicholas8da1e652019-05-24 11:01:59 -04001589 case Program::kPipelineStage_Kind:
Ethan Nicholasc18bb512020-07-28 14:46:53 -04001590 this->loadPipelineIntrinsics();
Ethan Nicholas8da1e652019-05-24 11:01:59 -04001591 inherited = &fPipelineInclude;
1592 fIRGenerator->fSymbolTable = fPipelineSymbolTable;
Ethan Nicholasdb80f692019-11-22 14:06:12 -05001593 fIRGenerator->fIntrinsics = &fGPUIntrinsics;
Ethan Nicholas8da1e652019-05-24 11:01:59 -04001594 fIRGenerator->start(&settings, inherited);
1595 break;
Ethan Nicholas746035a2019-04-23 13:31:09 -04001596 case Program::kGeneric_Kind:
Ethan Nicholasc18bb512020-07-28 14:46:53 -04001597 this->loadInterpreterIntrinsics();
Ethan Nicholas8da1e652019-05-24 11:01:59 -04001598 inherited = &fInterpreterInclude;
1599 fIRGenerator->fSymbolTable = fInterpreterSymbolTable;
Ethan Nicholasdb80f692019-11-22 14:06:12 -05001600 fIRGenerator->fIntrinsics = &fInterpreterIntrinsics;
Ethan Nicholas8da1e652019-05-24 11:01:59 -04001601 fIRGenerator->start(&settings, inherited);
Ethan Nicholas0d997662019-04-08 09:46:01 -04001602 break;
ethannicholasb3058bd2016-07-01 08:22:01 -07001603 }
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001604 std::unique_ptr<String> textPtr(new String(std::move(text)));
1605 fSource = textPtr.get();
Ethan Nicholasc18bb512020-07-28 14:46:53 -04001606 fIRGenerator->convertProgram(kind, textPtr->c_str(), textPtr->size(), &elements);
John Stilesfbd050b2020-08-03 13:21:46 -04001607 auto result = std::make_unique<Program>(kind,
1608 std::move(textPtr),
1609 settings,
1610 fContext,
1611 inherited,
1612 std::move(elements),
1613 fIRGenerator->fSymbolTable,
1614 fIRGenerator->fInputs);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001615 if (fErrorCount) {
1616 return nullptr;
1617 }
1618 return result;
1619}
1620
Ethan Nicholas00543112018-07-31 09:44:36 -04001621bool Compiler::optimize(Program& program) {
1622 SkASSERT(!fErrorCount);
1623 if (!program.fIsOptimized) {
1624 program.fIsOptimized = true;
1625 fIRGenerator->fKind = program.fKind;
1626 fIRGenerator->fSettings = &program.fSettings;
1627 for (auto& element : program) {
1628 if (element.fKind == ProgramElement::kFunction_Kind) {
1629 this->scanCFG((FunctionDefinition&) element);
1630 }
1631 }
Ethan Nicholase8ad02c2020-06-03 16:58:20 -04001632 // we wait until after analysis to remove dead functions so that we still report errors
1633 // even in unused code
1634 if (program.fSettings.fRemoveDeadFunctions) {
1635 for (auto iter = program.fElements.begin(); iter != program.fElements.end(); ) {
1636 if ((*iter)->fKind == ProgramElement::kFunction_Kind) {
1637 const FunctionDefinition& f = (const FunctionDefinition&) **iter;
1638 if (!f.fDeclaration.fCallCount && f.fDeclaration.fName != "main") {
1639 iter = program.fElements.erase(iter);
1640 continue;
1641 }
1642 }
1643 ++iter;
1644 }
1645 }
Ethan Nicholas0dc80872019-02-08 15:46:24 -05001646 if (program.fKind != Program::kFragmentProcessor_Kind) {
1647 for (auto iter = program.fElements.begin(); iter != program.fElements.end();) {
1648 if ((*iter)->fKind == ProgramElement::kVar_Kind) {
1649 VarDeclarations& vars = (VarDeclarations&) **iter;
1650 for (auto varIter = vars.fVars.begin(); varIter != vars.fVars.end();) {
1651 const Variable& var = *((VarDeclaration&) **varIter).fVar;
1652 if (var.dead()) {
1653 varIter = vars.fVars.erase(varIter);
1654 } else {
1655 ++varIter;
1656 }
1657 }
1658 if (vars.fVars.size() == 0) {
1659 iter = program.fElements.erase(iter);
1660 continue;
1661 }
1662 }
1663 ++iter;
1664 }
1665 }
Ethan Nicholas00543112018-07-31 09:44:36 -04001666 }
1667 return fErrorCount == 0;
1668}
1669
1670std::unique_ptr<Program> Compiler::specialize(
1671 Program& program,
1672 const std::unordered_map<SkSL::String, SkSL::Program::Settings::Value>& inputs) {
1673 std::vector<std::unique_ptr<ProgramElement>> elements;
1674 for (const auto& e : program) {
1675 elements.push_back(e.clone());
1676 }
1677 Program::Settings settings;
1678 settings.fCaps = program.fSettings.fCaps;
1679 for (auto iter = inputs.begin(); iter != inputs.end(); ++iter) {
1680 settings.fArgs.insert(*iter);
1681 }
Brian Osman808f0212020-01-21 15:36:47 -05001682 std::unique_ptr<String> sourceCopy(new String(*program.fSource));
Ethan Nicholas00543112018-07-31 09:44:36 -04001683 std::unique_ptr<Program> result(new Program(program.fKind,
Brian Osman808f0212020-01-21 15:36:47 -05001684 std::move(sourceCopy),
Ethan Nicholas00543112018-07-31 09:44:36 -04001685 settings,
1686 program.fContext,
1687 program.fInheritedElements,
1688 std::move(elements),
1689 program.fSymbols,
1690 program.fInputs));
1691 return result;
1692}
1693
Brian Osmanfb32ddf2019-06-18 10:14:20 -04001694#if defined(SKSL_STANDALONE) || SK_SUPPORT_GPU
1695
Ethan Nicholas00543112018-07-31 09:44:36 -04001696bool Compiler::toSPIRV(Program& program, OutputStream& out) {
1697 if (!this->optimize(program)) {
1698 return false;
1699 }
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001700#ifdef SK_ENABLE_SPIRV_VALIDATION
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001701 StringStream buffer;
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001702 fSource = program.fSource.get();
Ethan Nicholas26a9aad2018-03-27 14:10:52 -04001703 SPIRVCodeGenerator cg(fContext.get(), &program, this, &buffer);
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001704 bool result = cg.generateCode();
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001705 fSource = nullptr;
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001706 if (result) {
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001707 spvtools::SpirvTools tools(SPV_ENV_VULKAN_1_0);
Ethan Nicholas762466e2017-06-29 10:03:38 -04001708 const String& data = buffer.str();
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001709 SkASSERT(0 == data.size() % 4);
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001710 auto dumpmsg = [](spv_message_level_t, const char*, const spv_position_t&, const char* m) {
1711 SkDebugf("SPIR-V validation error: %s\n", m);
1712 };
1713 tools.SetMessageConsumer(dumpmsg);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001714 // Verify that the SPIR-V we produced is valid. If this SkASSERT fails, check the logs prior
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001715 // to the failure to see the validation errors.
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001716 SkAssertResult(tools.Validate((const uint32_t*) data.c_str(), data.size() / 4));
Ethan Nicholas762466e2017-06-29 10:03:38 -04001717 out.write(data.c_str(), data.size());
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001718 }
1719#else
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001720 fSource = program.fSource.get();
Ethan Nicholas26a9aad2018-03-27 14:10:52 -04001721 SPIRVCodeGenerator cg(fContext.get(), &program, this, &out);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001722 bool result = cg.generateCode();
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001723 fSource = nullptr;
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001724#endif
Ethan Nicholasce33f102016-12-09 17:22:59 -05001725 return result;
1726}
1727
Ethan Nicholas00543112018-07-31 09:44:36 -04001728bool Compiler::toSPIRV(Program& program, String* out) {
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001729 StringStream buffer;
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001730 bool result = this->toSPIRV(program, buffer);
1731 if (result) {
Ethan Nicholas762466e2017-06-29 10:03:38 -04001732 *out = buffer.str();
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001733 }
1734 return result;
1735}
1736
Ethan Nicholas00543112018-07-31 09:44:36 -04001737bool Compiler::toGLSL(Program& program, OutputStream& out) {
1738 if (!this->optimize(program)) {
1739 return false;
1740 }
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001741 fSource = program.fSource.get();
Ethan Nicholas26a9aad2018-03-27 14:10:52 -04001742 GLSLCodeGenerator cg(fContext.get(), &program, this, &out);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001743 bool result = cg.generateCode();
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001744 fSource = nullptr;
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001745 return result;
1746}
1747
Ethan Nicholas00543112018-07-31 09:44:36 -04001748bool Compiler::toGLSL(Program& program, String* out) {
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001749 StringStream buffer;
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001750 bool result = this->toGLSL(program, buffer);
1751 if (result) {
Ethan Nicholas762466e2017-06-29 10:03:38 -04001752 *out = buffer.str();
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001753 }
1754 return result;
1755}
1756
Brian Osmanc0243912020-02-19 15:35:26 -05001757bool Compiler::toHLSL(Program& program, String* out) {
1758 String spirv;
1759 if (!this->toSPIRV(program, &spirv)) {
1760 return false;
1761 }
1762
1763 return SPIRVtoHLSL(spirv, out);
1764}
1765
Ethan Nicholas00543112018-07-31 09:44:36 -04001766bool Compiler::toMetal(Program& program, OutputStream& out) {
1767 if (!this->optimize(program)) {
1768 return false;
1769 }
Ethan Nicholas26a9aad2018-03-27 14:10:52 -04001770 MetalCodeGenerator cg(fContext.get(), &program, this, &out);
Ethan Nicholascc305772017-10-13 16:17:45 -04001771 bool result = cg.generateCode();
Ethan Nicholascc305772017-10-13 16:17:45 -04001772 return result;
1773}
1774
Ethan Nicholas00543112018-07-31 09:44:36 -04001775bool Compiler::toMetal(Program& program, String* out) {
1776 if (!this->optimize(program)) {
1777 return false;
1778 }
Timothy Liangb8eeb802018-07-23 16:46:16 -04001779 StringStream buffer;
1780 bool result = this->toMetal(program, buffer);
1781 if (result) {
1782 *out = buffer.str();
1783 }
1784 return result;
1785}
1786
Ethan Nicholas00543112018-07-31 09:44:36 -04001787bool Compiler::toCPP(Program& program, String name, OutputStream& out) {
1788 if (!this->optimize(program)) {
1789 return false;
1790 }
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001791 fSource = program.fSource.get();
Ethan Nicholas26a9aad2018-03-27 14:10:52 -04001792 CPPCodeGenerator cg(fContext.get(), &program, this, name, &out);
Ethan Nicholas762466e2017-06-29 10:03:38 -04001793 bool result = cg.generateCode();
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001794 fSource = nullptr;
Ethan Nicholas762466e2017-06-29 10:03:38 -04001795 return result;
1796}
1797
Ethan Nicholas00543112018-07-31 09:44:36 -04001798bool Compiler::toH(Program& program, String name, OutputStream& out) {
1799 if (!this->optimize(program)) {
1800 return false;
1801 }
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001802 fSource = program.fSource.get();
Ethan Nicholas26a9aad2018-03-27 14:10:52 -04001803 HCodeGenerator cg(fContext.get(), &program, this, name, &out);
Ethan Nicholas762466e2017-06-29 10:03:38 -04001804 bool result = cg.generateCode();
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001805 fSource = nullptr;
Ethan Nicholas00543112018-07-31 09:44:36 -04001806 return result;
1807}
1808
Brian Osman2e29ab52019-09-20 12:19:11 -04001809#endif
1810
1811#if !defined(SKSL_STANDALONE) && SK_SUPPORT_GPU
Brian Osman107c6662019-12-30 15:02:30 -05001812bool Compiler::toPipelineStage(const Program& program, PipelineStageArgs* outArgs) {
Ethan Nicholas00543112018-07-31 09:44:36 -04001813 SkASSERT(program.fIsOptimized);
1814 fSource = program.fSource.get();
1815 StringStream buffer;
Brian Osman300fe1d2020-01-23 15:42:43 -05001816 PipelineStageCodeGenerator cg(fContext.get(), &program, this, &buffer, outArgs);
Ethan Nicholas00543112018-07-31 09:44:36 -04001817 bool result = cg.generateCode();
1818 fSource = nullptr;
1819 if (result) {
Brian Osman107c6662019-12-30 15:02:30 -05001820 outArgs->fCode = buffer.str();
Ethan Nicholas00543112018-07-31 09:44:36 -04001821 }
Ethan Nicholas762466e2017-06-29 10:03:38 -04001822 return result;
1823}
Brian Osmanfb32ddf2019-06-18 10:14:20 -04001824#endif
1825
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001826std::unique_ptr<ByteCode> Compiler::toByteCode(Program& program) {
Brian Osman489cf882019-07-09 10:48:28 -04001827#if defined(SK_ENABLE_SKSL_INTERPRETER)
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001828 if (!this->optimize(program)) {
1829 return nullptr;
1830 }
Brian Osman808f0212020-01-21 15:36:47 -05001831 fSource = program.fSource.get();
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001832 std::unique_ptr<ByteCode> result(new ByteCode());
Brian Osmanb08cc022020-04-02 11:38:40 -04001833 ByteCodeGenerator cg(fContext.get(), &program, this, result.get());
1834 bool success = cg.generateCode();
1835 fSource = nullptr;
1836 if (success) {
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001837 return result;
1838 }
Brian Osman489cf882019-07-09 10:48:28 -04001839#else
1840 ABORT("ByteCode interpreter not enabled");
1841#endif
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001842 return nullptr;
1843}
1844
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001845const char* Compiler::OperatorName(Token::Kind kind) {
1846 switch (kind) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001847 case Token::Kind::TK_PLUS: return "+";
1848 case Token::Kind::TK_MINUS: return "-";
1849 case Token::Kind::TK_STAR: return "*";
1850 case Token::Kind::TK_SLASH: return "/";
1851 case Token::Kind::TK_PERCENT: return "%";
1852 case Token::Kind::TK_SHL: return "<<";
1853 case Token::Kind::TK_SHR: return ">>";
1854 case Token::Kind::TK_LOGICALNOT: return "!";
1855 case Token::Kind::TK_LOGICALAND: return "&&";
1856 case Token::Kind::TK_LOGICALOR: return "||";
1857 case Token::Kind::TK_LOGICALXOR: return "^^";
1858 case Token::Kind::TK_BITWISENOT: return "~";
1859 case Token::Kind::TK_BITWISEAND: return "&";
1860 case Token::Kind::TK_BITWISEOR: return "|";
1861 case Token::Kind::TK_BITWISEXOR: return "^";
1862 case Token::Kind::TK_EQ: return "=";
1863 case Token::Kind::TK_EQEQ: return "==";
1864 case Token::Kind::TK_NEQ: return "!=";
1865 case Token::Kind::TK_LT: return "<";
1866 case Token::Kind::TK_GT: return ">";
1867 case Token::Kind::TK_LTEQ: return "<=";
1868 case Token::Kind::TK_GTEQ: return ">=";
1869 case Token::Kind::TK_PLUSEQ: return "+=";
1870 case Token::Kind::TK_MINUSEQ: return "-=";
1871 case Token::Kind::TK_STAREQ: return "*=";
1872 case Token::Kind::TK_SLASHEQ: return "/=";
1873 case Token::Kind::TK_PERCENTEQ: return "%=";
1874 case Token::Kind::TK_SHLEQ: return "<<=";
1875 case Token::Kind::TK_SHREQ: return ">>=";
1876 case Token::Kind::TK_LOGICALANDEQ: return "&&=";
1877 case Token::Kind::TK_LOGICALOREQ: return "||=";
1878 case Token::Kind::TK_LOGICALXOREQ: return "^^=";
1879 case Token::Kind::TK_BITWISEANDEQ: return "&=";
1880 case Token::Kind::TK_BITWISEOREQ: return "|=";
1881 case Token::Kind::TK_BITWISEXOREQ: return "^=";
1882 case Token::Kind::TK_PLUSPLUS: return "++";
1883 case Token::Kind::TK_MINUSMINUS: return "--";
1884 case Token::Kind::TK_COMMA: return ",";
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001885 default:
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001886 ABORT("unsupported operator: %d\n", (int) kind);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001887 }
1888}
1889
1890
1891bool Compiler::IsAssignment(Token::Kind op) {
1892 switch (op) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001893 case Token::Kind::TK_EQ: // fall through
1894 case Token::Kind::TK_PLUSEQ: // fall through
1895 case Token::Kind::TK_MINUSEQ: // fall through
1896 case Token::Kind::TK_STAREQ: // fall through
1897 case Token::Kind::TK_SLASHEQ: // fall through
1898 case Token::Kind::TK_PERCENTEQ: // fall through
1899 case Token::Kind::TK_SHLEQ: // fall through
1900 case Token::Kind::TK_SHREQ: // fall through
1901 case Token::Kind::TK_BITWISEOREQ: // fall through
1902 case Token::Kind::TK_BITWISEXOREQ: // fall through
1903 case Token::Kind::TK_BITWISEANDEQ: // fall through
1904 case Token::Kind::TK_LOGICALOREQ: // fall through
1905 case Token::Kind::TK_LOGICALXOREQ: // fall through
1906 case Token::Kind::TK_LOGICALANDEQ:
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001907 return true;
1908 default:
1909 return false;
1910 }
1911}
1912
1913Position Compiler::position(int offset) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001914 SkASSERT(fSource);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001915 int line = 1;
1916 int column = 1;
1917 for (int i = 0; i < offset; i++) {
1918 if ((*fSource)[i] == '\n') {
1919 ++line;
1920 column = 1;
1921 }
1922 else {
1923 ++column;
1924 }
1925 }
1926 return Position(line, column);
1927}
1928
1929void Compiler::error(int offset, String msg) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001930 fErrorCount++;
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001931 Position pos = this->position(offset);
1932 fErrorText += "error: " + to_string(pos.fLine) + ": " + msg.c_str() + "\n";
ethannicholasb3058bd2016-07-01 08:22:01 -07001933}
1934
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001935String Compiler::errorText() {
Ethan Nicholas00543112018-07-31 09:44:36 -04001936 this->writeErrorCount();
1937 fErrorCount = 0;
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001938 String result = fErrorText;
ethannicholasb3058bd2016-07-01 08:22:01 -07001939 return result;
1940}
1941
1942void Compiler::writeErrorCount() {
1943 if (fErrorCount) {
1944 fErrorText += to_string(fErrorCount) + " error";
1945 if (fErrorCount > 1) {
1946 fErrorText += "s";
1947 }
1948 fErrorText += "\n";
1949 }
1950}
1951
ethannicholasb3058bd2016-07-01 08:22:01 -07001952} // namespace