Hash :
18fa02be
Author :
Date :
2024-03-12T10:23:55
Rewrite exprs using separated decl variables
Rewrite expressions that use the rewritten struct declaration variables.
Declaration that specfies a struct and defines multiple variables will
get its variable declarations separated. The type of the variable
changes when a struct specifier is removed for the second and rest of
the variable declarations. The type of the variable changes also when a
anonymous struct is named.
The expressions that used the separated variables used the old struct as
their types.
Fix by using TIntermRebuild. Upon creating a new symbol node referencing
the new type, the rebuilder will instantiate also all the needed
intermediate nodes, which then get the correct struct type.
For consistency, fix the case of anonymous struct -> named struct
transform naming the variables similar to named struct separation.
Consider base case:
struct S { .. } a, b; -> struct S { .. } a; S b;
Compare against case:
struct { .. } a, b;
Before, inconsistency:
struct s1 { .. }; s1 a; s1 b;
After, fixed:
struct s1 { .. } a; s1 b;
Bug: angleproject:8590
Change-Id: Iffb0ef4441d6021e076b04485b808b26a7fa4dcb
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/5365201
Auto-Submit: Kimmo Kinnunen <kkinnunen@apple.com>
Reviewed-by: Shahbaz Youssefi <syoussefi@chromium.org>
Commit-Queue: Kimmo Kinnunen <kkinnunen@apple.com>
Commit-Queue: Shahbaz Youssefi <syoussefi@chromium.org>
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 121 122 123 124 125 126 127 128 129 130 131 132
//
// Copyright 2002 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/tree_ops/SeparateDeclarations.h"
#include <unordered_map>
#include "compiler/translator/SymbolTable.h"
#include "compiler/translator/IntermRebuild.h"
#include "compiler/translator/util.h"
namespace sh
{
namespace
{
class Separator final : private TIntermRebuild
{
public:
Separator(TCompiler &compiler) : TIntermRebuild(compiler, true, true) {}
using TIntermRebuild::rebuildRoot;
private:
void recordModifiedStructVariables(TIntermDeclaration &node)
{
ASSERT(!mNewStructure); // No nested struct declarations.
TIntermSequence &sequence = *node.getSequence();
if (sequence.size() <= 1)
{
return;
}
TIntermTyped *declarator = sequence.at(0)->getAsTyped();
const TType &declaratorType = declarator->getType();
const TStructure *structure = declaratorType.getStruct();
// Rewrite variable declarations that specify structs AND multiple variables at the same
// time. Only one variable can specify the struct and rest must be rewritten with new
// type.
if (!structure || !declaratorType.isStructSpecifier())
{
return;
}
// Struct specifier changes for all variables except the first one.
uint32_t index = 1;
if (structure->symbolType() == SymbolType::Empty)
{
TStructure *newStructure =
new TStructure(&mSymbolTable, kEmptyImmutableString, &structure->fields(),
SymbolType::AngleInternal);
newStructure->setAtGlobalScope(structure->atGlobalScope());
structure = newStructure;
mNewStructure = newStructure;
// Adding name causes the struct type to change, so all variables need rewriting.
index = 0;
}
for (; index < sequence.size(); ++index)
{
Declaration decl = ViewDeclaration(node, index);
const TVariable &var = decl.symbol.variable();
const TType &varType = var.getType();
const bool newTypeIsSpecifier = index == 0;
TType *newType = new TType(structure, newTypeIsSpecifier);
newType->setQualifier(varType.getQualifier());
newType->makeArrays(varType.getArraySizes());
TVariable *newVar = new TVariable(&mSymbolTable, var.name(), newType, var.symbolType());
mStructVariables.insert(std::make_pair(&var, newVar));
}
}
PreResult visitDeclarationPre(TIntermDeclaration &node) override
{
recordModifiedStructVariables(node);
return node;
}
PostResult visitDeclarationPost(TIntermDeclaration &node) override
{
TIntermSequence &sequence = *node.getSequence();
if (sequence.size() <= 1)
{
return node;
}
std::vector<TIntermNode *> replacements;
uint32_t index = 0;
if (mNewStructure)
{
TType *namedType = new TType(mNewStructure, true);
namedType->setQualifier(EvqGlobal);
TIntermDeclaration *replacement = new TIntermDeclaration;
replacement->appendDeclarator(sequence.at(0)->getAsTyped());
replacement->setLine(node.getLine());
replacements.push_back(replacement);
mNewStructure = nullptr;
index = 1;
}
for (; index < sequence.size(); ++index)
{
TIntermDeclaration *replacement = new TIntermDeclaration;
TIntermTyped *declarator = sequence.at(index)->getAsTyped();
replacement->appendDeclarator(declarator);
replacement->setLine(declarator->getLine());
replacements.push_back(replacement);
}
return PostResult::Multi(std::move(replacements));
}
PreResult visitSymbolPre(TIntermSymbol &symbolNode) override
{
auto it = mStructVariables.find(&symbolNode.variable());
if (it == mStructVariables.end())
{
return symbolNode;
}
return *new TIntermSymbol(it->second);
}
const TStructure *mNewStructure = nullptr;
// Old struct variable to new struct variable mapping.
std::unordered_map<const TVariable *, TVariable *> mStructVariables;
};
} // namespace
bool SeparateDeclarations(TCompiler &compiler, TIntermBlock &root)
{
Separator separator(compiler);
return separator.rebuildRoot(root);
}
} // namespace sh