1 //
2 // Copyright 2022 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6
7 #include "compiler/translator/tree_ops/hlsl/AggregateAssignArraysInSSBOs.h"
8
9 #include "compiler/translator/StaticType.h"
10 #include "compiler/translator/Symbol.h"
11 #include "compiler/translator/tree_util/IntermNode_util.h"
12 #include "compiler/translator/tree_util/IntermTraverse.h"
13 #include "compiler/translator/util.h"
14
15 namespace sh
16 {
17
18 namespace
19 {
20
21 class AggregateAssignArraysInSSBOsTraverser : public TIntermTraverser
22 {
23 public:
AggregateAssignArraysInSSBOsTraverser(TSymbolTable * symbolTable)24 AggregateAssignArraysInSSBOsTraverser(TSymbolTable *symbolTable)
25 : TIntermTraverser(true, false, false, symbolTable)
26 {}
27
28 protected:
visitBinary(Visit visit,TIntermBinary * node)29 bool visitBinary(Visit visit, TIntermBinary *node) override
30 {
31 // Replace all aggregate assignments to arrays in SSBOs with element-by-element assignments.
32 // TODO(anglebug.com/42265833): this implementation only works for the simple case
33 // (assignment statement), not more complex cases such as assignment-as-expression or
34 // functions with side effects in the RHS.
35
36 if (node->getOp() != EOpAssign)
37 {
38 return true;
39 }
40 else if (!node->getLeft()->getType().isArray())
41 {
42 return true;
43 }
44 else if (!IsInShaderStorageBlock(node->getLeft()))
45 {
46 return true;
47 }
48 const TType *mediumpIndexType = StaticType::Get<EbtInt, EbpMedium, EvqTemporary, 1, 1>();
49 auto *indexVariable = CreateTempVariable(mSymbolTable, mediumpIndexType);
50 auto *indexInit =
51 CreateTempInitDeclarationNode(indexVariable, CreateZeroNode(indexVariable->getType()));
52 auto *arraySizeNode = CreateIndexNode(node->getOutermostArraySize());
53 auto *indexSymbolNode = CreateTempSymbolNode(indexVariable);
54 auto *cond = new TIntermBinary(EOpLessThan, indexSymbolNode->deepCopy(), arraySizeNode);
55 auto *indexIncrement =
56 new TIntermUnary(EOpPreIncrement, indexSymbolNode->deepCopy(), nullptr);
57 auto *forLoopBody = new TIntermBlock();
58 auto *indexedLeft =
59 new TIntermBinary(EOpIndexDirect, node->getLeft(), indexSymbolNode->deepCopy());
60 auto *indexedRight =
61 new TIntermBinary(EOpIndexDirect, node->getRight(), indexSymbolNode->deepCopy());
62 auto *assign = new TIntermBinary(TOperator::EOpAssign, indexedLeft, indexedRight);
63 forLoopBody->appendStatement(assign);
64 auto *forLoop = new TIntermLoop(ELoopFor, indexInit, cond, indexIncrement, forLoopBody);
65 queueReplacement(forLoop, OriginalNode::IS_DROPPED);
66 return false;
67 }
68 };
69
70 } // namespace
71
AggregateAssignArraysInSSBOs(TCompiler * compiler,TIntermBlock * root,TSymbolTable * symbolTable)72 bool AggregateAssignArraysInSSBOs(TCompiler *compiler,
73 TIntermBlock *root,
74 TSymbolTable *symbolTable)
75 {
76 AggregateAssignArraysInSSBOsTraverser traverser(symbolTable);
77 root->traverse(&traverser);
78 return traverser.updateTree(compiler, root);
79 }
80
81 } // namespace sh
82