Coverage Report

Created: 2026-01-17 07:12

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/shaderc/third_party/glslang/glslang/MachineIndependent/limits.cpp
Line
Count
Source
1
//
2
// Copyright (C) 2013 LunarG, Inc.
3
//
4
// All rights reserved.
5
//
6
// Redistribution and use in source and binary forms, with or without
7
// modification, are permitted provided that the following conditions
8
// are met:
9
//
10
//    Redistributions of source code must retain the above copyright
11
//    notice, this list of conditions and the following disclaimer.
12
//
13
//    Redistributions in binary form must reproduce the above
14
//    copyright notice, this list of conditions and the following
15
//    disclaimer in the documentation and/or other materials provided
16
//    with the distribution.
17
//
18
//    Neither the name of 3Dlabs Inc. Ltd. nor the names of its
19
//    contributors may be used to endorse or promote products derived
20
//    from this software without specific prior written permission.
21
//
22
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
25
// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
26
// COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
27
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
28
// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
29
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
30
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
32
// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33
// POSSIBILITY OF SUCH DAMAGE.
34
//
35
36
//
37
// Do sub tree walks for
38
// 1) inductive loop bodies to see if the inductive variable is modified
39
// 2) array-index expressions to see if they are "constant-index-expression"
40
//
41
// These are per Appendix A of ES 2.0:
42
//
43
// "Within the body of the loop, the loop index is not statically assigned to nor is it used as the
44
// argument to a function out or inout parameter."
45
//
46
// "The following are constant-index-expressions:
47
//  - Constant expressions
48
//  - Loop indices as defined in section 4
49
//  - Expressions composed of both of the above"
50
//
51
// N.B.: assuming the last rule excludes function calls
52
//
53
54
#include "ParseHelper.h"
55
56
namespace glslang {
57
58
//
59
// The inductive loop-body traverser.
60
//
61
// Just look at things that might modify the loop index.
62
//
63
64
class TInductiveTraverser : public TIntermTraverser {
65
public:
66
    TInductiveTraverser(long long id, TSymbolTable& st)
67
0
    : loopId(id), symbolTable(st), bad(false)  { }
68
69
    virtual bool visitBinary(TVisit, TIntermBinary* node);
70
    virtual bool visitUnary(TVisit, TIntermUnary* node);
71
    virtual bool visitAggregate(TVisit, TIntermAggregate* node);
72
73
    long long loopId;           // unique ID of the symbol that's the loop inductive variable
74
    TSymbolTable& symbolTable;
75
    bool bad;
76
    TSourceLoc badLoc;
77
78
protected:
79
    TInductiveTraverser(TInductiveTraverser&);
80
    TInductiveTraverser& operator=(TInductiveTraverser&);
81
};
82
83
// check binary operations for those modifying the loop index
84
bool TInductiveTraverser::visitBinary(TVisit /* visit */, TIntermBinary* node)
85
0
{
86
0
    if (node->modifiesState() && node->getLeft()->getAsSymbolNode() &&
87
0
                                 node->getLeft()->getAsSymbolNode()->getId() == loopId) {
88
0
        bad = true;
89
0
        badLoc = node->getLoc();
90
0
    }
91
92
0
    return true;
93
0
}
94
95
// check unary operations for those modifying the loop index
96
bool TInductiveTraverser::visitUnary(TVisit /* visit */, TIntermUnary* node)
97
0
{
98
0
    if (node->modifiesState() && node->getOperand()->getAsSymbolNode() &&
99
0
                                 node->getOperand()->getAsSymbolNode()->getId() == loopId) {
100
0
        bad = true;
101
0
        badLoc = node->getLoc();
102
0
    }
103
104
0
    return true;
105
0
}
106
107
// check function calls for arguments modifying the loop index
108
bool TInductiveTraverser::visitAggregate(TVisit /* visit */, TIntermAggregate* node)
109
0
{
110
0
    if (node->getOp() == EOpFunctionCall) {
111
        // see if an out or inout argument is the loop index
112
0
        const TIntermSequence& args = node->getSequence();
113
0
        for (int i = 0; i < (int)args.size(); ++i) {
114
0
            if (args[i]->getAsSymbolNode() && args[i]->getAsSymbolNode()->getId() == loopId) {
115
0
                TSymbol* function = symbolTable.find(node->getName());
116
0
                const TType* type = (*function->getAsFunction())[i].type;
117
0
                if (type->getQualifier().storage == EvqOut ||
118
0
                    type->getQualifier().storage == EvqInOut) {
119
0
                    bad = true;
120
0
                    badLoc = node->getLoc();
121
0
                }
122
0
            }
123
0
        }
124
0
    }
125
126
0
    return true;
127
0
}
128
129
//
130
// External function to call for loop check.
131
//
132
void TParseContext::inductiveLoopBodyCheck(TIntermNode* body, long long loopId, TSymbolTable& symbolTable)
133
0
{
134
0
    TInductiveTraverser it(loopId, symbolTable);
135
136
0
    if (body == nullptr)
137
0
        return;
138
139
0
    body->traverse(&it);
140
141
0
    if (it.bad)
142
0
        error(it.badLoc, "inductive loop index modified", "limitations", "");
143
0
}
144
145
//
146
// The "constant-index-expression" tranverser.
147
//
148
// Just look at things that can form an index.
149
//
150
151
class TIndexTraverser : public TIntermTraverser {
152
public:
153
0
    TIndexTraverser(const TIdSetType& ids) : inductiveLoopIds(ids), bad(false) { }
154
    virtual void visitSymbol(TIntermSymbol* symbol);
155
    virtual bool visitAggregate(TVisit, TIntermAggregate* node);
156
    const TIdSetType& inductiveLoopIds;
157
    bool bad;
158
    TSourceLoc badLoc;
159
160
protected:
161
    TIndexTraverser(TIndexTraverser&);
162
    TIndexTraverser& operator=(TIndexTraverser&);
163
};
164
165
// make sure symbols are inductive-loop indexes
166
void TIndexTraverser::visitSymbol(TIntermSymbol* symbol)
167
0
{
168
0
    if (inductiveLoopIds.find(symbol->getId()) == inductiveLoopIds.end()) {
169
0
        bad = true;
170
0
        badLoc = symbol->getLoc();
171
0
    }
172
0
}
173
174
// check for function calls, assuming they are bad; spec. doesn't really say
175
bool TIndexTraverser::visitAggregate(TVisit /* visit */, TIntermAggregate* node)
176
0
{
177
0
    if (node->getOp() == EOpFunctionCall) {
178
0
        bad = true;
179
0
        badLoc = node->getLoc();
180
0
    }
181
182
0
    return true;
183
0
}
184
185
//
186
// External function to call for loop check.
187
//
188
void TParseContext::constantIndexExpressionCheck(TIntermNode* index)
189
0
{
190
0
    TIndexTraverser it(inductiveLoopIds);
191
192
0
    index->traverse(&it);
193
194
0
    if (it.bad)
195
0
        error(it.badLoc, "Non-constant-index-expression", "limitations", "");
196
0
}
197
198
} // end namespace glslang