blob: f989decdee41763cd8be3e6c60fa24ced3c2f283 [file] [log] [blame]
ethannicholasf789b382016-08-03 12:43:36 -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 */
7
8#include "SkSLGLSLCodeGenerator.h"
9
10#include "string.h"
11
12#include "GLSL.std.450.h"
13
14#include "ir/SkSLExpressionStatement.h"
15#include "ir/SkSLExtension.h"
16#include "ir/SkSLIndexExpression.h"
17#include "ir/SkSLVariableReference.h"
18
ethannicholas9b0fe3d2016-09-12 08:50:13 -070019#define SK_FRAGCOLOR_BUILTIN 10001
20
ethannicholasf789b382016-08-03 12:43:36 -070021namespace SkSL {
22
23void GLSLCodeGenerator::write(const char* s) {
24 if (s[0] == 0) {
25 return;
26 }
27 if (fAtLineStart) {
28 for (int i = 0; i < fIndentation; i++) {
29 *fOut << " ";
30 }
31 }
32 *fOut << s;
33 fAtLineStart = false;
34}
35
36void GLSLCodeGenerator::writeLine(const char* s) {
37 this->write(s);
38 *fOut << "\n";
39 fAtLineStart = true;
40}
41
42void GLSLCodeGenerator::write(const std::string& s) {
43 this->write(s.c_str());
44}
45
46void GLSLCodeGenerator::writeLine(const std::string& s) {
47 this->writeLine(s.c_str());
48}
49
50void GLSLCodeGenerator::writeLine() {
51 this->writeLine("");
52}
53
54void GLSLCodeGenerator::writeExtension(const Extension& ext) {
55 this->writeLine("#extension " + ext.fName + " : enable");
56}
57
58void GLSLCodeGenerator::writeType(const Type& type) {
59 if (type.kind() == Type::kStruct_Kind) {
60 for (const Type* search : fWrittenStructs) {
61 if (*search == type) {
62 // already written
63 this->write(type.name());
64 return;
65 }
66 }
67 fWrittenStructs.push_back(&type);
68 this->writeLine("struct " + type.name() + " {");
69 fIndentation++;
70 for (const auto& f : type.fields()) {
ethannicholas9b0fe3d2016-09-12 08:50:13 -070071 this->writeModifiers(f.fModifiers, false);
ethannicholasf789b382016-08-03 12:43:36 -070072 // sizes (which must be static in structs) are part of the type name here
ethannicholas0730be72016-09-01 07:59:02 -070073 this->writeType(*f.fType);
ethannicholasf789b382016-08-03 12:43:36 -070074 this->writeLine(" " + f.fName + ";");
75 }
76 fIndentation--;
77 this->writeLine("}");
78 } else {
79 this->write(type.name());
80 }
81}
82
83void GLSLCodeGenerator::writeExpression(const Expression& expr, Precedence parentPrecedence) {
84 switch (expr.fKind) {
85 case Expression::kBinary_Kind:
86 this->writeBinaryExpression((BinaryExpression&) expr, parentPrecedence);
87 break;
88 case Expression::kBoolLiteral_Kind:
89 this->writeBoolLiteral((BoolLiteral&) expr);
90 break;
91 case Expression::kConstructor_Kind:
92 this->writeConstructor((Constructor&) expr);
93 break;
94 case Expression::kIntLiteral_Kind:
95 this->writeIntLiteral((IntLiteral&) expr);
96 break;
97 case Expression::kFieldAccess_Kind:
98 this->writeFieldAccess(((FieldAccess&) expr));
99 break;
100 case Expression::kFloatLiteral_Kind:
101 this->writeFloatLiteral(((FloatLiteral&) expr));
102 break;
103 case Expression::kFunctionCall_Kind:
104 this->writeFunctionCall((FunctionCall&) expr);
105 break;
106 case Expression::kPrefix_Kind:
107 this->writePrefixExpression((PrefixExpression&) expr, parentPrecedence);
108 break;
109 case Expression::kPostfix_Kind:
110 this->writePostfixExpression((PostfixExpression&) expr, parentPrecedence);
111 break;
112 case Expression::kSwizzle_Kind:
113 this->writeSwizzle((Swizzle&) expr);
114 break;
115 case Expression::kVariableReference_Kind:
116 this->writeVariableReference((VariableReference&) expr);
117 break;
118 case Expression::kTernary_Kind:
119 this->writeTernaryExpression((TernaryExpression&) expr, parentPrecedence);
120 break;
121 case Expression::kIndex_Kind:
122 this->writeIndexExpression((IndexExpression&) expr);
123 break;
124 default:
125 ABORT("unsupported expression: %s", expr.description().c_str());
126 }
127}
128
ethannicholas9b0fe3d2016-09-12 08:50:13 -0700129static bool is_abs(Expression& expr) {
130 if (expr.fKind != Expression::kFunctionCall_Kind) {
131 return false;
132 }
133 return ((FunctionCall&) expr).fFunction.fName == "abs";
134}
135
136// turns min(abs(x), y) into (abs(x) > (tmpVar = y) ? tmpVar : abs(x)) to avoid a Tegra3 compiler
137// bug.
138void GLSLCodeGenerator::writeMinAbsHack(Expression& absExpr, Expression& otherExpr) {
139 ASSERT(!fCaps.fCanUseMinAndAbsTogether);
140 std::string varName = "minAbsHackVar" + to_string(fVarCount++);
141 this->fFunctionHeader += " " + otherExpr.fType.name() + " " + varName + ";\n";
142 this->write("(");
143 this->writeExpression(absExpr, kTopLevel_Precedence);
144 this->write(" > (" + varName + " = ");
145 this->writeExpression(otherExpr, kRelational_Precedence);
146 this->write(") ? " + varName + " : ");
147 this->writeExpression(absExpr, kTernary_Precedence);
148 this->write(")");
149}
150
ethannicholasf789b382016-08-03 12:43:36 -0700151void GLSLCodeGenerator::writeFunctionCall(const FunctionCall& c) {
ethannicholas9b0fe3d2016-09-12 08:50:13 -0700152 if (!fCaps.fCanUseMinAndAbsTogether && c.fFunction.fName == "min") {
153 ASSERT(c.fArguments.size() == 2);
154 if (is_abs(*c.fArguments[0])) {
155 this->writeMinAbsHack(*c.fArguments[0], *c.fArguments[1]);
156 return;
157 }
158 if (is_abs(*c.fArguments[1])) {
159 this->writeMinAbsHack(*c.fArguments[1], *c.fArguments[0]);
160 return;
161 }
162 }
ethannicholasf789b382016-08-03 12:43:36 -0700163 this->write(c.fFunction.fName + "(");
164 const char* separator = "";
165 for (const auto& arg : c.fArguments) {
166 this->write(separator);
167 separator = ", ";
168 this->writeExpression(*arg, kSequence_Precedence);
169 }
170 this->write(")");
171}
172
173void GLSLCodeGenerator::writeConstructor(const Constructor& c) {
174 this->write(c.fType.name() + "(");
175 const char* separator = "";
176 for (const auto& arg : c.fArguments) {
177 this->write(separator);
178 separator = ", ";
179 this->writeExpression(*arg, kSequence_Precedence);
180 }
181 this->write(")");
182}
183
184void GLSLCodeGenerator::writeVariableReference(const VariableReference& ref) {
ethannicholas9b0fe3d2016-09-12 08:50:13 -0700185 if (ref.fVariable.fModifiers.fLayout.fBuiltin == SK_FRAGCOLOR_BUILTIN) {
186 if (fCaps.fMustDeclareFragmentShaderOutput) {
187 this->write("sk_FragColor");
188 } else {
189 this->write("gl_FragColor");
190 }
191 } else {
192 this->write(ref.fVariable.fName);
193 }
ethannicholasf789b382016-08-03 12:43:36 -0700194}
195
196void GLSLCodeGenerator::writeIndexExpression(const IndexExpression& expr) {
197 this->writeExpression(*expr.fBase, kPostfix_Precedence);
198 this->write("[");
199 this->writeExpression(*expr.fIndex, kTopLevel_Precedence);
200 this->write("]");
201}
202
203void GLSLCodeGenerator::writeFieldAccess(const FieldAccess& f) {
204 if (f.fOwnerKind == FieldAccess::kDefault_OwnerKind) {
205 this->writeExpression(*f.fBase, kPostfix_Precedence);
206 this->write(".");
207 }
208 this->write(f.fBase->fType.fields()[f.fFieldIndex].fName);
209}
210
211void GLSLCodeGenerator::writeSwizzle(const Swizzle& swizzle) {
212 this->writeExpression(*swizzle.fBase, kPostfix_Precedence);
213 this->write(".");
214 for (int c : swizzle.fComponents) {
215 this->write(&("x\0y\0z\0w\0"[c * 2]));
216 }
217}
218
219static GLSLCodeGenerator::Precedence get_binary_precedence(Token::Kind op) {
220 switch (op) {
221 case Token::STAR: // fall through
222 case Token::SLASH: // fall through
223 case Token::PERCENT: return GLSLCodeGenerator::kMultiplicative_Precedence;
224 case Token::PLUS: // fall through
225 case Token::MINUS: return GLSLCodeGenerator::kAdditive_Precedence;
226 case Token::SHL: // fall through
227 case Token::SHR: return GLSLCodeGenerator::kShift_Precedence;
228 case Token::LT: // fall through
229 case Token::GT: // fall through
230 case Token::LTEQ: // fall through
231 case Token::GTEQ: return GLSLCodeGenerator::kRelational_Precedence;
232 case Token::EQEQ: // fall through
233 case Token::NEQ: return GLSLCodeGenerator::kEquality_Precedence;
234 case Token::BITWISEAND: return GLSLCodeGenerator::kBitwiseAnd_Precedence;
235 case Token::BITWISEXOR: return GLSLCodeGenerator::kBitwiseXor_Precedence;
236 case Token::BITWISEOR: return GLSLCodeGenerator::kBitwiseOr_Precedence;
237 case Token::LOGICALAND: return GLSLCodeGenerator::kLogicalAnd_Precedence;
238 case Token::LOGICALXOR: return GLSLCodeGenerator::kLogicalXor_Precedence;
239 case Token::LOGICALOR: return GLSLCodeGenerator::kLogicalOr_Precedence;
240 case Token::EQ: // fall through
241 case Token::PLUSEQ: // fall through
242 case Token::MINUSEQ: // fall through
243 case Token::STAREQ: // fall through
244 case Token::SLASHEQ: // fall through
245 case Token::PERCENTEQ: // fall through
246 case Token::SHLEQ: // fall through
247 case Token::SHREQ: // fall through
248 case Token::LOGICALANDEQ: // fall through
249 case Token::LOGICALXOREQ: // fall through
250 case Token::LOGICALOREQ: // fall through
251 case Token::BITWISEANDEQ: // fall through
252 case Token::BITWISEXOREQ: // fall through
253 case Token::BITWISEOREQ: return GLSLCodeGenerator::kAssignment_Precedence;
254 default: ABORT("unsupported binary operator");
255 }
256}
257
258void GLSLCodeGenerator::writeBinaryExpression(const BinaryExpression& b,
259 Precedence parentPrecedence) {
260 Precedence precedence = get_binary_precedence(b.fOperator);
261 if (precedence >= parentPrecedence) {
262 this->write("(");
263 }
264 this->writeExpression(*b.fLeft, precedence);
265 this->write(" " + Token::OperatorName(b.fOperator) + " ");
266 this->writeExpression(*b.fRight, precedence);
267 if (precedence >= parentPrecedence) {
268 this->write(")");
269 }
270}
271
272void GLSLCodeGenerator::writeTernaryExpression(const TernaryExpression& t,
273 Precedence parentPrecedence) {
274 if (kTernary_Precedence >= parentPrecedence) {
275 this->write("(");
276 }
277 this->writeExpression(*t.fTest, kTernary_Precedence);
278 this->write(" ? ");
279 this->writeExpression(*t.fIfTrue, kTernary_Precedence);
280 this->write(" : ");
281 this->writeExpression(*t.fIfFalse, kTernary_Precedence);
282 if (kTernary_Precedence >= parentPrecedence) {
283 this->write(")");
284 }
285}
286
287void GLSLCodeGenerator::writePrefixExpression(const PrefixExpression& p,
288 Precedence parentPrecedence) {
289 if (kPrefix_Precedence >= parentPrecedence) {
290 this->write("(");
291 }
292 this->write(Token::OperatorName(p.fOperator));
293 this->writeExpression(*p.fOperand, kPrefix_Precedence);
294 if (kPrefix_Precedence >= parentPrecedence) {
295 this->write(")");
296 }
297}
298
299void GLSLCodeGenerator::writePostfixExpression(const PostfixExpression& p,
300 Precedence parentPrecedence) {
301 if (kPostfix_Precedence >= parentPrecedence) {
302 this->write("(");
303 }
304 this->writeExpression(*p.fOperand, kPostfix_Precedence);
305 this->write(Token::OperatorName(p.fOperator));
306 if (kPostfix_Precedence >= parentPrecedence) {
307 this->write(")");
308 }
309}
310
311void GLSLCodeGenerator::writeBoolLiteral(const BoolLiteral& b) {
312 this->write(b.fValue ? "true" : "false");
313}
314
315void GLSLCodeGenerator::writeIntLiteral(const IntLiteral& i) {
316 this->write(to_string(i.fValue));
317}
318
319void GLSLCodeGenerator::writeFloatLiteral(const FloatLiteral& f) {
320 this->write(to_string(f.fValue));
321}
322
323void GLSLCodeGenerator::writeFunction(const FunctionDefinition& f) {
324 this->writeType(f.fDeclaration.fReturnType);
325 this->write(" " + f.fDeclaration.fName + "(");
326 const char* separator = "";
327 for (const auto& param : f.fDeclaration.fParameters) {
328 this->write(separator);
329 separator = ", ";
ethannicholas9b0fe3d2016-09-12 08:50:13 -0700330 this->writeModifiers(param->fModifiers, false);
ethannicholasf789b382016-08-03 12:43:36 -0700331 this->writeType(param->fType);
332 this->write(" " + param->fName);
333 }
ethannicholas9b0fe3d2016-09-12 08:50:13 -0700334 this->writeLine(") {");
335
336 fFunctionHeader = "";
337 std::ostream* oldOut = fOut;
338 std::stringstream buffer;
339 fOut = &buffer;
340 fIndentation++;
341 for (const auto& s : f.fBody->fStatements) {
342 this->writeStatement(*s);
343 this->writeLine();
344 }
345 fIndentation--;
346 this->writeLine("}");
347
348 fOut = oldOut;
349 this->write(fFunctionHeader);
350 this->write(buffer.str());
ethannicholasf789b382016-08-03 12:43:36 -0700351}
352
ethannicholas9b0fe3d2016-09-12 08:50:13 -0700353void GLSLCodeGenerator::writeModifiers(const Modifiers& modifiers,
354 bool globalContext) {
355 if (modifiers.fFlags & Modifiers::kNoPerspective_Flag) {
356 this->write("noperspective ");
357 }
358 if (modifiers.fFlags & Modifiers::kFlat_Flag) {
359 this->write("flat ");
360 }
361 std::string layout = modifiers.fLayout.description();
362 if (layout.length()) {
363 this->write(layout + " ");
364 }
365 if ((modifiers.fFlags & Modifiers::kIn_Flag) &&
366 (modifiers.fFlags & Modifiers::kOut_Flag)) {
367 this->write("inout ");
368 } else if (modifiers.fFlags & Modifiers::kIn_Flag) {
369 if (globalContext && fCaps.fVersion < 130) {
370 this->write(fProgramKind == Program::kVertex_Kind ? "attribute "
371 : "varying ");
372 } else {
373 this->write("in ");
374 }
375 } else if (modifiers.fFlags & Modifiers::kOut_Flag) {
376 if (globalContext && fCaps.fVersion < 130) {
377 this->write("varying ");
378 } else {
379 this->write("out ");
380 }
381 }
382 if (modifiers.fFlags & Modifiers::kUniform_Flag) {
383 this->write("uniform ");
384 }
385 if (modifiers.fFlags & Modifiers::kConst_Flag) {
386 this->write("const ");
387 }
388 if (fCaps.fUsesPrecisionModifiers) {
389 bool modifier = false;
390 if (modifiers.fFlags & Modifiers::kLowp_Flag) {
391 this->write("lowp ");
392 modifier = true;
393 }
394 if (modifiers.fFlags & Modifiers::kHighp_Flag) {
395 this->write("highp ");
396 modifier = true;
397 }
398 if (!modifier) {
399 this->write("mediump ");
400 }
401 }
ethannicholasf789b382016-08-03 12:43:36 -0700402}
403
404void GLSLCodeGenerator::writeInterfaceBlock(const InterfaceBlock& intf) {
405 if (intf.fVariable.fName == "gl_PerVertex") {
406 return;
407 }
ethannicholas9b0fe3d2016-09-12 08:50:13 -0700408 this->writeModifiers(intf.fVariable.fModifiers, true);
ethannicholasf789b382016-08-03 12:43:36 -0700409 this->writeLine(intf.fVariable.fType.name() + " {");
410 fIndentation++;
411 for (const auto& f : intf.fVariable.fType.fields()) {
ethannicholas9b0fe3d2016-09-12 08:50:13 -0700412 this->writeModifiers(f.fModifiers, false);
ethannicholas0730be72016-09-01 07:59:02 -0700413 this->writeType(*f.fType);
ethannicholasf789b382016-08-03 12:43:36 -0700414 this->writeLine(" " + f.fName + ";");
415 }
416 fIndentation--;
417 this->writeLine("};");
418}
419
ethannicholas9b0fe3d2016-09-12 08:50:13 -0700420void GLSLCodeGenerator::writeVarDeclarations(const VarDeclarations& decl, bool global) {
ethannicholasf789b382016-08-03 12:43:36 -0700421 ASSERT(decl.fVars.size() > 0);
ethannicholas9b0fe3d2016-09-12 08:50:13 -0700422 this->writeModifiers(decl.fVars[0].fVar->fModifiers, global);
ethannicholasf789b382016-08-03 12:43:36 -0700423 this->writeType(decl.fBaseType);
424 std::string separator = " ";
ethannicholas14fe8cc2016-09-07 13:37:16 -0700425 for (const auto& var : decl.fVars) {
426 ASSERT(var.fVar->fModifiers == decl.fVars[0].fVar->fModifiers);
ethannicholasf789b382016-08-03 12:43:36 -0700427 this->write(separator);
428 separator = ", ";
ethannicholas14fe8cc2016-09-07 13:37:16 -0700429 this->write(var.fVar->fName);
430 for (const auto& size : var.fSizes) {
ethannicholasf789b382016-08-03 12:43:36 -0700431 this->write("[");
432 this->writeExpression(*size, kTopLevel_Precedence);
433 this->write("]");
434 }
ethannicholas14fe8cc2016-09-07 13:37:16 -0700435 if (var.fValue) {
ethannicholasf789b382016-08-03 12:43:36 -0700436 this->write(" = ");
ethannicholas14fe8cc2016-09-07 13:37:16 -0700437 this->writeExpression(*var.fValue, kTopLevel_Precedence);
ethannicholasf789b382016-08-03 12:43:36 -0700438 }
439 }
440 this->write(";");
441}
442
443void GLSLCodeGenerator::writeStatement(const Statement& s) {
444 switch (s.fKind) {
445 case Statement::kBlock_Kind:
446 this->writeBlock((Block&) s);
447 break;
448 case Statement::kExpression_Kind:
449 this->writeExpression(*((ExpressionStatement&) s).fExpression, kTopLevel_Precedence);
450 this->write(";");
451 break;
452 case Statement::kReturn_Kind:
453 this->writeReturnStatement((ReturnStatement&) s);
454 break;
ethannicholas14fe8cc2016-09-07 13:37:16 -0700455 case Statement::kVarDeclarations_Kind:
ethannicholas9b0fe3d2016-09-12 08:50:13 -0700456 this->writeVarDeclarations(*((VarDeclarationsStatement&) s).fDeclaration, false);
ethannicholasf789b382016-08-03 12:43:36 -0700457 break;
458 case Statement::kIf_Kind:
459 this->writeIfStatement((IfStatement&) s);
460 break;
461 case Statement::kFor_Kind:
462 this->writeForStatement((ForStatement&) s);
463 break;
464 case Statement::kWhile_Kind:
465 this->writeWhileStatement((WhileStatement&) s);
466 break;
467 case Statement::kDo_Kind:
468 this->writeDoStatement((DoStatement&) s);
469 break;
470 case Statement::kBreak_Kind:
471 this->write("break;");
472 break;
473 case Statement::kContinue_Kind:
474 this->write("continue;");
475 break;
476 case Statement::kDiscard_Kind:
477 this->write("discard;");
478 break;
479 default:
480 ABORT("unsupported statement: %s", s.description().c_str());
481 }
482}
483
484void GLSLCodeGenerator::writeBlock(const Block& b) {
485 this->writeLine("{");
486 fIndentation++;
487 for (const auto& s : b.fStatements) {
488 this->writeStatement(*s);
489 this->writeLine();
490 }
491 fIndentation--;
492 this->write("}");
493}
494
495void GLSLCodeGenerator::writeIfStatement(const IfStatement& stmt) {
496 this->write("if (");
497 this->writeExpression(*stmt.fTest, kTopLevel_Precedence);
498 this->write(") ");
499 this->writeStatement(*stmt.fIfTrue);
500 if (stmt.fIfFalse) {
501 this->write(" else ");
502 this->writeStatement(*stmt.fIfFalse);
503 }
504}
505
506void GLSLCodeGenerator::writeForStatement(const ForStatement& f) {
507 this->write("for (");
508 if (f.fInitializer) {
509 this->writeStatement(*f.fInitializer);
510 } else {
511 this->write("; ");
512 }
513 if (f.fTest) {
514 this->writeExpression(*f.fTest, kTopLevel_Precedence);
515 }
516 this->write("; ");
517 if (f.fNext) {
518 this->writeExpression(*f.fNext, kTopLevel_Precedence);
519 }
520 this->write(") ");
521 this->writeStatement(*f.fStatement);
522}
523
524void GLSLCodeGenerator::writeWhileStatement(const WhileStatement& w) {
525 this->write("while (");
526 this->writeExpression(*w.fTest, kTopLevel_Precedence);
527 this->write(") ");
528 this->writeStatement(*w.fStatement);
529}
530
531void GLSLCodeGenerator::writeDoStatement(const DoStatement& d) {
532 this->write("do ");
533 this->writeStatement(*d.fStatement);
534 this->write(" while (");
535 this->writeExpression(*d.fTest, kTopLevel_Precedence);
536 this->write(");");
537}
538
539void GLSLCodeGenerator::writeReturnStatement(const ReturnStatement& r) {
540 this->write("return");
541 if (r.fExpression) {
542 this->write(" ");
543 this->writeExpression(*r.fExpression, kTopLevel_Precedence);
544 }
545 this->write(";");
546}
547
548void GLSLCodeGenerator::generateCode(const Program& program, std::ostream& out) {
549 ASSERT(fOut == nullptr);
550 fOut = &out;
ethannicholas9b0fe3d2016-09-12 08:50:13 -0700551 fProgramKind = program.fKind;
ethannicholasf789b382016-08-03 12:43:36 -0700552 this->write("#version " + to_string(fCaps.fVersion));
553 if (fCaps.fStandard == GLCaps::kGLES_Standard) {
554 this->write(" es");
ethannicholas9b0fe3d2016-09-12 08:50:13 -0700555 } else if (fCaps.fIsCoreProfile) {
556 this->write(" core");
ethannicholasf789b382016-08-03 12:43:36 -0700557 }
558 this->writeLine();
559 for (const auto& e : program.fElements) {
560 switch (e->fKind) {
561 case ProgramElement::kExtension_Kind:
562 this->writeExtension((Extension&) *e);
563 break;
564 case ProgramElement::kVar_Kind: {
ethannicholas14fe8cc2016-09-07 13:37:16 -0700565 VarDeclarations& decl = (VarDeclarations&) *e;
ethannicholas9b0fe3d2016-09-12 08:50:13 -0700566 if (decl.fVars.size() > 0) {
567 int builtin = decl.fVars[0].fVar->fModifiers.fLayout.fBuiltin;
568 if (builtin == -1) {
569 // normal var
570 this->writeVarDeclarations(decl, true);
571 this->writeLine();
572 } else if (builtin == SK_FRAGCOLOR_BUILTIN &&
573 fCaps.fMustDeclareFragmentShaderOutput) {
574 this->writeLine("out vec4 sk_FragColor;");
575 }
ethannicholasf789b382016-08-03 12:43:36 -0700576 }
577 break;
578 }
579 case ProgramElement::kInterfaceBlock_Kind:
580 this->writeInterfaceBlock((InterfaceBlock&) *e);
581 break;
582 case ProgramElement::kFunction_Kind:
583 this->writeFunction((FunctionDefinition&) *e);
584 break;
585 default:
586 printf("%s\n", e->description().c_str());
587 ABORT("unsupported program element");
588 }
589 }
590 fOut = nullptr;
591}
592
593}