Hash :
5a4bfd61
Author :
Date :
2024-01-12T17:15:39
Metal: Separate struct definition from function return
The EmitMetal pass in shader translator does not handle writing the
defintion of a structure that is declared in the return type of a
function, such as:
struct Foo { float val; } foo() {
...
}
This change adds a new pass, SeparateStructFromFunctionDeclarations, to
separate the definition and declaration of struct variables in function
prototypes into two statements, such as:
struct Foo { float val; } foo();
struct Bar { int val; } bar() { ... }
void main() { ... }
Foo foo() { ... }
into:
struct Foo { float val; };
Foo foo();
struct Bar { int val; };
Bar bar() { ... }
void main() { ... }
Foo foo() { ... }
Fixed: angleproject:8302
Change-Id: Id8b6ba256d3c8375dd889facd70e4715261c1ca3
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/5191644
Commit-Queue: Shahbaz Youssefi <syoussefi@chromium.org>
Reviewed-by: 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 133 134
//
// Copyright 2024 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.
//
// SeparateStructFromFunctionDeclarations: Separate struct declarations from function declaration
// return type.
//
#include "compiler/translator/tree_ops/SeparateStructFromFunctionDeclarations.h"
#include "compiler/translator/SymbolTable.h"
#include "compiler/translator/tree_util/IntermTraverse.h"
namespace sh
{
namespace
{
class Traverser : public TIntermTraverser
{
public:
explicit Traverser(TSymbolTable *symbolTable)
: TIntermTraverser(true, false, false, symbolTable)
{}
void visitFunctionPrototype(TIntermFunctionPrototype *node) override
{
const TFunction *function = node->getFunction();
if (mFunctionsToReplace.count(function) > 0)
{
TIntermFunctionPrototype *newFuncProto =
new TIntermFunctionPrototype(mFunctionsToReplace[function]);
queueReplacement(newFuncProto, OriginalNode::IS_DROPPED);
}
else
{
const TType &type = node->getType();
if (type.isStructSpecifier())
{
doReplacement(function, type);
}
}
}
bool visitAggregate(Visit visit, TIntermAggregate *node) override
{
const TFunction *function = node->getFunction();
if (mFunctionsToReplace.count(function) > 0)
{
TIntermAggregate *replacementNode = TIntermAggregate::CreateFunctionCall(
*mFunctionsToReplace[function], node->getSequence());
queueReplacement(replacementNode, OriginalNode::IS_DROPPED);
}
return true;
}
private:
void doReplacement(const TFunction *function, const TType &oldType)
{
const TStructure *structure = oldType.getStruct();
// Name unnamed inline structs
if (structure->symbolType() == SymbolType::Empty)
{
structure = new TStructure(mSymbolTable, kEmptyImmutableString, &structure->fields(),
SymbolType::AngleInternal);
}
TVariable *structVar = new TVariable(mSymbolTable, ImmutableString(""),
new TType(structure, true), SymbolType::Empty);
insertStatementInParentBlock(new TIntermDeclaration({structVar}));
TType *returnType = new TType(structure, false);
if (oldType.isArray())
{
returnType->makeArrays(oldType.getArraySizes());
}
returnType->setQualifier(oldType.getQualifier());
const TFunction *oldFunc = function;
ASSERT(oldFunc->symbolType() == SymbolType::UserDefined);
const TFunction *newFunc =
cloneFunctionAndChangeReturnType(mSymbolTable, oldFunc, returnType);
TIntermFunctionPrototype *newFuncProto = new TIntermFunctionPrototype(newFunc);
queueReplacement(newFuncProto, OriginalNode::IS_DROPPED);
mFunctionsToReplace[oldFunc] = newFunc;
}
const TFunction *cloneFunctionAndChangeReturnType(TSymbolTable *symbolTable,
const TFunction *oldFunc,
const TType *newReturnType)
{
ASSERT(oldFunc->symbolType() == SymbolType::UserDefined);
TFunction *newFunc = new TFunction(symbolTable, oldFunc->name(), oldFunc->symbolType(),
newReturnType, oldFunc->isKnownToNotHaveSideEffects());
if (oldFunc->isDefined())
{
newFunc->setDefined();
}
if (oldFunc->hasPrototypeDeclaration())
{
newFunc->setHasPrototypeDeclaration();
}
const size_t paramCount = oldFunc->getParamCount();
for (size_t i = 0; i < paramCount; ++i)
{
const TVariable *var = oldFunc->getParam(i);
newFunc->addParameter(var);
}
return newFunc;
}
using FunctionReplacement = angle::HashMap<const TFunction *, const TFunction *>;
FunctionReplacement mFunctionsToReplace;
};
} // anonymous namespace
bool SeparateStructFromFunctionDeclarations(TCompiler *compiler,
TIntermBlock *root,
TSymbolTable *symbolTable)
{
Traverser separateStructDecls(symbolTable);
root->traverse(&separateStructDecls);
return separateStructDecls.updateTree(compiler, root);
}
} // namespace sh