Hash :
f51fdd2e
Author :
Date :
2016-10-03T10:03:40
Ensure that all functions have a body node in the AST Some traversers that insert code to main() assume that the main() function has a non-null body node in place. This assumption was previously wrong, since functions could be missing the body node in case the function body was empty. Fix possible invalid dereferencing of missing function body nodes by always adding an empty sequence node to represent the body of functions that have an empty body in the ESSL source. This also enables simplifying some tree traversers that used to take the possibility of missing function body nodes into account. Also fix AddDefaultReturnStatements to check the last statement inside the function body for a return statement, instead of checking the first statement. BUG=angleproject:1539 TEST=angle_unittests, angle_end2end_tests Change-Id: I2fbd18c78653fa2f1a96dbd9a619accc4874030d Reviewed-on: https://chromium-review.googlesource.com/392046 Reviewed-by: Corentin Wallez <cwallez@chromium.org> Reviewed-by: Jamie Madill <jmadill@chromium.org> Commit-Queue: Olli Etuaho <oetuaho@nvidia.com>
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120
//
// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
#include "compiler/translator/InitializeVariables.h"
#include "angle_gl.h"
#include "common/debug.h"
#include "compiler/translator/IntermNode.h"
#include "compiler/translator/util.h"
namespace
{
class VariableInitializer : public TIntermTraverser
{
public:
VariableInitializer(const InitVariableList &vars)
: TIntermTraverser(true, false, false), mVariables(vars), mCodeInserted(false)
{
}
protected:
bool visitBinary(Visit, TIntermBinary *node) override { return false; }
bool visitUnary(Visit, TIntermUnary *node) override { return false; }
bool visitIfElse(Visit, TIntermIfElse *node) override { return false; }
bool visitLoop(Visit, TIntermLoop *node) override { return false; }
bool visitBranch(Visit, TIntermBranch *node) override { return false; }
bool visitAggregate(Visit visit, TIntermAggregate *node) override;
private:
void insertInitCode(TIntermSequence *sequence);
const InitVariableList &mVariables;
bool mCodeInserted;
};
// VariableInitializer implementation.
bool VariableInitializer::visitAggregate(Visit visit, TIntermAggregate *node)
{
bool visitChildren = !mCodeInserted;
switch (node->getOp())
{
case EOpSequence:
break;
case EOpFunction:
{
// Function definition.
ASSERT(visit == PreVisit);
if (node->getName() == "main(")
{
TIntermSequence *sequence = node->getSequence();
ASSERT(sequence->size() == 2);
TIntermAggregate *body = (*sequence)[1]->getAsAggregate();
ASSERT(body);
insertInitCode(body->getSequence());
mCodeInserted = true;
}
break;
}
default:
visitChildren = false;
break;
}
return visitChildren;
}
void VariableInitializer::insertInitCode(TIntermSequence *sequence)
{
for (const auto &var : mVariables)
{
TString name = TString(var.name.c_str());
TType type = sh::GetShaderVariableType(var);
// Assign the array elements one by one to keep the AST compatible with ESSL 1.00 which
// doesn't have array assignment.
if (var.isArray())
{
size_t pos = name.find_last_of('[');
if (pos != TString::npos)
{
name = name.substr(0, pos);
}
TType elementType = type;
elementType.clearArrayness();
for (unsigned int i = 0; i < var.arraySize; ++i)
{
TIntermSymbol *arraySymbol = new TIntermSymbol(0, name, type);
TIntermBinary *element = new TIntermBinary(EOpIndexDirect, arraySymbol,
TIntermTyped::CreateIndexNode(i));
TIntermTyped *zero = TIntermTyped::CreateZero(elementType);
TIntermBinary *assignment = new TIntermBinary(EOpAssign, element, zero);
sequence->insert(sequence->begin(), assignment);
}
}
else
{
TIntermSymbol *symbol = new TIntermSymbol(0, name, type);
TIntermTyped *zero = TIntermTyped::CreateZero(type);
TIntermBinary *assign = new TIntermBinary(EOpAssign, symbol, zero);
sequence->insert(sequence->begin(), assign);
}
}
}
} // namespace anonymous
void InitializeVariables(TIntermNode *root, const InitVariableList &vars)
{
VariableInitializer initializer(vars);
root->traverse(&initializer);
}