Coverage Report

Created: 2025-07-18 06:47

/src/glslang/glslang/MachineIndependent/SpirvIntrinsics.cpp
Line
Count
Source (jump to first uncovered line)
1
//
2
// Copyright(C) 2021 Advanced Micro Devices, 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
// GL_EXT_spirv_intrinsics
38
//
39
#include "../Include/intermediate.h"
40
#include "../Include/SpirvIntrinsics.h"
41
#include "../Include/Types.h"
42
#include "ParseHelper.h"
43
44
namespace glslang {
45
46
bool TSpirvTypeParameter::operator==(const TSpirvTypeParameter& rhs) const
47
0
{
48
0
    if (getAsConstant() != nullptr)
49
0
        return getAsConstant()->getConstArray() == rhs.getAsConstant()->getConstArray();
50
51
0
    assert(getAsType() != nullptr);
52
0
    return *getAsType() == *rhs.getAsType();
53
0
}
54
55
//
56
// Handle SPIR-V requirements
57
//
58
TSpirvRequirement* TParseContext::makeSpirvRequirement(const TSourceLoc& loc, const TString& name,
59
                                                       const TIntermAggregate* extensions,
60
                                                       const TIntermAggregate* capabilities)
61
0
{
62
0
    TSpirvRequirement* spirvReq = new TSpirvRequirement;
63
64
0
    if (name == "extensions") {
65
0
        assert(extensions);
66
0
        for (auto extension : extensions->getSequence()) {
67
0
            assert(extension->getAsConstantUnion());
68
0
            spirvReq->extensions.insert(*extension->getAsConstantUnion()->getConstArray()[0].getSConst());
69
0
        }
70
0
    } else if (name == "capabilities") {
71
0
        assert(capabilities);
72
0
        for (auto capability : capabilities->getSequence()) {
73
0
            assert(capability->getAsConstantUnion());
74
0
            spirvReq->capabilities.insert(capability->getAsConstantUnion()->getConstArray()[0].getIConst());
75
0
        }
76
0
    } else
77
0
        error(loc, "unknown SPIR-V requirement", name.c_str(), "");
78
79
0
    return spirvReq;
80
0
}
81
82
TSpirvRequirement* TParseContext::mergeSpirvRequirements(const TSourceLoc& loc, TSpirvRequirement* spirvReq1,
83
                                                         TSpirvRequirement* spirvReq2)
84
0
{
85
    // Merge the second SPIR-V requirement to the first one
86
0
    if (!spirvReq2->extensions.empty()) {
87
0
        if (spirvReq1->extensions.empty())
88
0
            spirvReq1->extensions = spirvReq2->extensions;
89
0
        else
90
0
            error(loc, "too many SPIR-V requirements", "extensions", "");
91
0
    }
92
93
0
    if (!spirvReq2->capabilities.empty()) {
94
0
        if (spirvReq1->capabilities.empty())
95
0
            spirvReq1->capabilities = spirvReq2->capabilities;
96
0
        else
97
0
            error(loc, "too many SPIR-V requirements", "capabilities", "");
98
0
    }
99
100
0
    return spirvReq1;
101
0
}
102
103
void TIntermediate::insertSpirvRequirement(const TSpirvRequirement* spirvReq)
104
0
{
105
0
    if (!spirvRequirement)
106
0
        spirvRequirement = new TSpirvRequirement;
107
108
0
    for (auto extension : spirvReq->extensions)
109
0
        spirvRequirement->extensions.insert(extension);
110
111
0
    for (auto capability : spirvReq->capabilities)
112
0
        spirvRequirement->capabilities.insert(capability);
113
0
}
114
115
//
116
// Handle SPIR-V execution modes
117
//
118
void TIntermediate::insertSpirvExecutionMode(int executionMode, const TIntermAggregate* args)
119
0
{
120
0
    if (!spirvExecutionMode)
121
0
        spirvExecutionMode = new TSpirvExecutionMode;
122
123
0
    TVector<const TIntermConstantUnion*> extraOperands;
124
0
    if (args) {
125
0
        for (auto arg : args->getSequence()) {
126
0
            auto extraOperand = arg->getAsConstantUnion();
127
0
            assert(extraOperand != nullptr);
128
0
            extraOperands.push_back(extraOperand);
129
0
        }
130
0
    }
131
0
    spirvExecutionMode->modes[executionMode] = extraOperands;
132
0
}
133
134
void TIntermediate::insertSpirvExecutionModeId(int executionMode, const TIntermAggregate* args)
135
0
{
136
0
    if (!spirvExecutionMode)
137
0
        spirvExecutionMode = new TSpirvExecutionMode;
138
139
0
    assert(args);
140
0
    TVector<const TIntermTyped*> extraOperands;
141
142
0
    for (auto arg : args->getSequence()) {
143
0
        auto extraOperand = arg->getAsTyped();
144
0
        assert(extraOperand != nullptr && extraOperand->getQualifier().isConstant());
145
0
        extraOperands.push_back(extraOperand);
146
0
    }
147
0
    spirvExecutionMode->modeIds[executionMode] = extraOperands;
148
0
}
149
150
//
151
// Handle SPIR-V decorate qualifiers
152
//
153
void TQualifier::setSpirvDecorate(int decoration, const TIntermAggregate* args)
154
0
{
155
0
    if (!spirvDecorate)
156
0
        spirvDecorate = new TSpirvDecorate;
157
158
0
    TVector<const TIntermConstantUnion*> extraOperands;
159
0
    if (args) {
160
0
        for (auto arg : args->getSequence()) {
161
0
            auto extraOperand = arg->getAsConstantUnion();
162
0
            assert(extraOperand != nullptr);
163
0
            extraOperands.push_back(extraOperand);
164
0
        }
165
0
    }
166
0
    spirvDecorate->decorates[decoration] = extraOperands;
167
0
}
168
169
void TQualifier::setSpirvDecorateId(int decoration, const TIntermAggregate* args)
170
0
{
171
0
    if (!spirvDecorate)
172
0
        spirvDecorate = new TSpirvDecorate;
173
174
0
    assert(args);
175
0
    TVector<const TIntermTyped*> extraOperands;
176
0
    for (auto arg : args->getSequence()) {
177
0
        auto extraOperand = arg->getAsTyped();
178
0
        assert(extraOperand != nullptr);
179
0
        extraOperands.push_back(extraOperand);
180
0
    }
181
0
    spirvDecorate->decorateIds[decoration] = extraOperands;
182
0
}
183
184
void TQualifier::setSpirvDecorateString(int decoration, const TIntermAggregate* args)
185
0
{
186
0
    if (!spirvDecorate)
187
0
        spirvDecorate = new TSpirvDecorate;
188
189
0
    assert(args);
190
0
    TVector<const TIntermConstantUnion*> extraOperands;
191
0
    for (auto arg : args->getSequence()) {
192
0
        auto extraOperand = arg->getAsConstantUnion();
193
0
        assert(extraOperand != nullptr);
194
0
        extraOperands.push_back(extraOperand);
195
0
    }
196
0
    spirvDecorate->decorateStrings[decoration] = extraOperands;
197
0
}
198
199
TString TQualifier::getSpirvDecorateQualifierString() const
200
0
{
201
0
    assert(spirvDecorate);
202
203
0
    TString qualifierString;
204
205
0
    const auto appendFloat = [&](float f) { qualifierString.append(std::to_string(f).c_str()); };
206
0
    const auto appendInt = [&](int i) { qualifierString.append(std::to_string(i).c_str()); };
207
0
    const auto appendUint = [&](unsigned int u) { qualifierString.append(std::to_string(u).c_str()); };
208
0
    const auto appendBool = [&](bool b) { qualifierString.append(std::to_string(b).c_str()); };
209
0
    const auto appendStr = [&](const char* s) { qualifierString.append(s); };
210
211
0
    const auto appendDecorate = [&](const TIntermTyped* constant) {
212
0
        if (constant->getAsConstantUnion()) {
213
0
            auto& constArray = constant->getAsConstantUnion()->getConstArray();
214
0
            if (constant->getBasicType() == EbtFloat) {
215
0
                float value = static_cast<float>(constArray[0].getDConst());
216
0
                appendFloat(value);
217
0
            } else if (constant->getBasicType() == EbtInt) {
218
0
                int value = constArray[0].getIConst();
219
0
                appendInt(value);
220
0
            } else if (constant->getBasicType() == EbtUint) {
221
0
                unsigned value = constArray[0].getUConst();
222
0
                appendUint(value);
223
0
            } else if (constant->getBasicType() == EbtBool) {
224
0
                bool value = constArray[0].getBConst();
225
0
                appendBool(value);
226
0
            } else if (constant->getBasicType() == EbtString) {
227
0
                const TString* value = constArray[0].getSConst();
228
0
                appendStr(value->c_str());
229
0
            } else
230
0
                assert(0);
231
0
        } else {
232
0
            assert(constant->getAsSymbolNode());
233
0
            appendStr(constant->getAsSymbolNode()->getName().c_str());
234
0
        }
235
0
    };
236
237
0
    for (auto& decorate : spirvDecorate->decorates) {
238
0
        appendStr("spirv_decorate(");
239
0
        appendInt(decorate.first);
240
0
        for (auto extraOperand : decorate.second) {
241
0
            appendStr(", ");
242
0
            appendDecorate(extraOperand);
243
0
        }
244
0
        appendStr(") ");
245
0
    }
246
247
0
    for (auto& decorateId : spirvDecorate->decorateIds) {
248
0
        appendStr("spirv_decorate_id(");
249
0
        appendInt(decorateId.first);
250
0
        for (auto extraOperand : decorateId.second) {
251
0
            appendStr(", ");
252
0
            appendDecorate(extraOperand);
253
0
        }
254
0
        appendStr(") ");
255
0
    }
256
257
0
    for (auto& decorateString : spirvDecorate->decorateStrings) {
258
0
        appendStr("spirv_decorate_string(");
259
0
        appendInt(decorateString.first);
260
0
        for (auto extraOperand : decorateString.second) {
261
0
            appendStr(", ");
262
0
            appendDecorate(extraOperand);
263
0
        }
264
0
        appendStr(") ");
265
0
    }
266
267
0
    return qualifierString;
268
0
}
269
270
//
271
// Handle SPIR-V type specifiers
272
//
273
void TPublicType::setSpirvType(const TSpirvInstruction& spirvInst, const TSpirvTypeParameters* typeParams)
274
0
{
275
0
    if (!spirvType)
276
0
        spirvType = new TSpirvType;
277
278
0
    basicType = EbtSpirvType;
279
0
    spirvType->spirvInst = spirvInst;
280
0
    if (typeParams)
281
0
        spirvType->typeParams = *typeParams;
282
0
}
283
284
TSpirvTypeParameters* TParseContext::makeSpirvTypeParameters(const TSourceLoc& loc, const TIntermConstantUnion* constant)
285
0
{
286
0
    TSpirvTypeParameters* spirvTypeParams = new TSpirvTypeParameters;
287
0
    if (constant->getBasicType() != EbtFloat &&
288
0
        constant->getBasicType() != EbtInt &&
289
0
        constant->getBasicType() != EbtUint &&
290
0
        constant->getBasicType() != EbtBool &&
291
0
        constant->getBasicType() != EbtString)
292
0
        error(loc, "this type not allowed", constant->getType().getBasicString(), "");
293
0
    else
294
0
        spirvTypeParams->push_back(TSpirvTypeParameter(constant));
295
296
0
    return spirvTypeParams;
297
0
}
298
299
TSpirvTypeParameters* TParseContext::makeSpirvTypeParameters(const TSourceLoc& /* loc */,
300
                                                             const TPublicType& type)
301
0
{
302
0
    TSpirvTypeParameters* spirvTypeParams = new TSpirvTypeParameters;
303
0
    spirvTypeParams->push_back(TSpirvTypeParameter(new TType(type)));
304
0
    return spirvTypeParams;
305
0
}
306
307
TSpirvTypeParameters* TParseContext::mergeSpirvTypeParameters(TSpirvTypeParameters* spirvTypeParams1, TSpirvTypeParameters* spirvTypeParams2)
308
0
{
309
    // Merge SPIR-V type parameters of the second one to the first one
310
0
    for (const auto& spirvTypeParam : *spirvTypeParams2)
311
0
        spirvTypeParams1->push_back(spirvTypeParam);
312
0
    return spirvTypeParams1;
313
0
}
314
315
//
316
// Handle SPIR-V instruction qualifiers
317
//
318
TSpirvInstruction* TParseContext::makeSpirvInstruction(const TSourceLoc& loc, const TString& name, const TString& value)
319
0
{
320
0
    TSpirvInstruction* spirvInst = new TSpirvInstruction;
321
0
    if (name == "set")
322
0
        spirvInst->set = value;
323
0
    else
324
0
        error(loc, "unknown SPIR-V instruction qualifier", name.c_str(), "");
325
326
0
    return spirvInst;
327
0
}
328
329
TSpirvInstruction* TParseContext::makeSpirvInstruction(const TSourceLoc& loc, const TString& name, int value)
330
0
{
331
0
    TSpirvInstruction* spirvInstuction = new TSpirvInstruction;
332
0
    if (name == "id")
333
0
        spirvInstuction->id = value;
334
0
    else
335
0
        error(loc, "unknown SPIR-V instruction qualifier", name.c_str(), "");
336
337
0
    return spirvInstuction;
338
0
}
339
340
TSpirvInstruction* TParseContext::mergeSpirvInstruction(const TSourceLoc& loc, TSpirvInstruction* spirvInst1, TSpirvInstruction* spirvInst2)
341
0
{
342
    // Merge qualifiers of the second SPIR-V instruction to those of the first one
343
0
    if (!spirvInst2->set.empty()) {
344
0
        if (spirvInst1->set.empty())
345
0
            spirvInst1->set = spirvInst2->set;
346
0
        else
347
0
            error(loc, "too many SPIR-V instruction qualifiers", "spirv_instruction", "(set)");
348
0
    }
349
350
0
    if (spirvInst2->id != -1) {
351
0
        if (spirvInst1->id == -1)
352
0
            spirvInst1->id = spirvInst2->id;
353
0
        else
354
0
            error(loc, "too many SPIR-V instruction qualifiers", "spirv_instruction", "(id)");
355
0
    }
356
357
0
    return spirvInst1;
358
0
}
359
360
} // end namespace glslang