1617a3babSopenharmony_ci//
2617a3babSopenharmony_ci// Copyright (C) 2014-2015 LunarG, Inc.
3617a3babSopenharmony_ci// Copyright (C) 2015-2018 Google, Inc.
4617a3babSopenharmony_ci// Modifications Copyright (C) 2020 Advanced Micro Devices, Inc. All rights reserved.
5617a3babSopenharmony_ci//
6617a3babSopenharmony_ci// All rights reserved.
7617a3babSopenharmony_ci//
8617a3babSopenharmony_ci// Redistribution and use in source and binary forms, with or without
9617a3babSopenharmony_ci// modification, are permitted provided that the following conditions
10617a3babSopenharmony_ci// are met:
11617a3babSopenharmony_ci//
12617a3babSopenharmony_ci//    Redistributions of source code must retain the above copyright
13617a3babSopenharmony_ci//    notice, this list of conditions and the following disclaimer.
14617a3babSopenharmony_ci//
15617a3babSopenharmony_ci//    Redistributions in binary form must reproduce the above
16617a3babSopenharmony_ci//    copyright notice, this list of conditions and the following
17617a3babSopenharmony_ci//    disclaimer in the documentation and/or other materials provided
18617a3babSopenharmony_ci//    with the distribution.
19617a3babSopenharmony_ci//
20617a3babSopenharmony_ci//    Neither the name of 3Dlabs Inc. Ltd. nor the names of its
21617a3babSopenharmony_ci//    contributors may be used to endorse or promote products derived
22617a3babSopenharmony_ci//    from this software without specific prior written permission.
23617a3babSopenharmony_ci//
24617a3babSopenharmony_ci// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
25617a3babSopenharmony_ci// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
26617a3babSopenharmony_ci// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
27617a3babSopenharmony_ci// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
28617a3babSopenharmony_ci// COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
29617a3babSopenharmony_ci// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
30617a3babSopenharmony_ci// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
31617a3babSopenharmony_ci// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
32617a3babSopenharmony_ci// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33617a3babSopenharmony_ci// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
34617a3babSopenharmony_ci// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
35617a3babSopenharmony_ci// POSSIBILITY OF SUCH DAMAGE.
36617a3babSopenharmony_ci
37617a3babSopenharmony_ci//
38617a3babSopenharmony_ci// Helper for making SPIR-V IR.  Generally, this is documented in the header
39617a3babSopenharmony_ci// SpvBuilder.h.
40617a3babSopenharmony_ci//
41617a3babSopenharmony_ci
42617a3babSopenharmony_ci#include <cassert>
43617a3babSopenharmony_ci#include <cstdlib>
44617a3babSopenharmony_ci
45617a3babSopenharmony_ci#include <unordered_set>
46617a3babSopenharmony_ci#include <algorithm>
47617a3babSopenharmony_ci
48617a3babSopenharmony_ci#include "SpvBuilder.h"
49617a3babSopenharmony_ci#include "hex_float.h"
50617a3babSopenharmony_ci
51617a3babSopenharmony_ci#ifndef _WIN32
52617a3babSopenharmony_ci    #include <cstdio>
53617a3babSopenharmony_ci#endif
54617a3babSopenharmony_ci
55617a3babSopenharmony_cinamespace spv {
56617a3babSopenharmony_ci
57617a3babSopenharmony_ciBuilder::Builder(unsigned int spvVersion, unsigned int magicNumber, SpvBuildLogger* buildLogger) :
58617a3babSopenharmony_ci    spvVersion(spvVersion),
59617a3babSopenharmony_ci    sourceLang(SourceLanguageUnknown),
60617a3babSopenharmony_ci    sourceVersion(0),
61617a3babSopenharmony_ci    sourceFileStringId(NoResult),
62617a3babSopenharmony_ci    currentLine(0),
63617a3babSopenharmony_ci    currentFile(nullptr),
64617a3babSopenharmony_ci    currentFileId(NoResult),
65617a3babSopenharmony_ci    lastDebugScopeId(NoResult),
66617a3babSopenharmony_ci    emitOpLines(false),
67617a3babSopenharmony_ci    emitNonSemanticShaderDebugInfo(false),
68617a3babSopenharmony_ci    addressModel(AddressingModelLogical),
69617a3babSopenharmony_ci    memoryModel(MemoryModelGLSL450),
70617a3babSopenharmony_ci    builderNumber(magicNumber),
71617a3babSopenharmony_ci    buildPoint(nullptr),
72617a3babSopenharmony_ci    uniqueId(0),
73617a3babSopenharmony_ci    entryPointFunction(nullptr),
74617a3babSopenharmony_ci    generatingOpCodeForSpecConst(false),
75617a3babSopenharmony_ci    logger(buildLogger)
76617a3babSopenharmony_ci{
77617a3babSopenharmony_ci    clearAccessChain();
78617a3babSopenharmony_ci}
79617a3babSopenharmony_ci
80617a3babSopenharmony_ciBuilder::~Builder()
81617a3babSopenharmony_ci{
82617a3babSopenharmony_ci}
83617a3babSopenharmony_ci
84617a3babSopenharmony_ciId Builder::import(const char* name)
85617a3babSopenharmony_ci{
86617a3babSopenharmony_ci    Instruction* import = new Instruction(getUniqueId(), NoType, OpExtInstImport);
87617a3babSopenharmony_ci    import->addStringOperand(name);
88617a3babSopenharmony_ci    module.mapInstruction(import);
89617a3babSopenharmony_ci
90617a3babSopenharmony_ci    imports.push_back(std::unique_ptr<Instruction>(import));
91617a3babSopenharmony_ci    return import->getResultId();
92617a3babSopenharmony_ci}
93617a3babSopenharmony_ci
94617a3babSopenharmony_ci// Emit instruction for non-filename-based #line directives (ie. no filename
95617a3babSopenharmony_ci// seen yet): emit an OpLine if we've been asked to emit OpLines and the line
96617a3babSopenharmony_ci// number has changed since the last time, and is a valid line number.
97617a3babSopenharmony_civoid Builder::setLine(int lineNum)
98617a3babSopenharmony_ci{
99617a3babSopenharmony_ci    if (lineNum != 0 && lineNum != currentLine) {
100617a3babSopenharmony_ci        currentLine = lineNum;
101617a3babSopenharmony_ci        if (emitOpLines) {
102617a3babSopenharmony_ci          if (emitNonSemanticShaderDebugInfo)
103617a3babSopenharmony_ci              addDebugScopeAndLine(currentFileId, currentLine, 0);
104617a3babSopenharmony_ci          else
105617a3babSopenharmony_ci              addLine(sourceFileStringId, currentLine, 0);
106617a3babSopenharmony_ci        }
107617a3babSopenharmony_ci    }
108617a3babSopenharmony_ci}
109617a3babSopenharmony_ci
110617a3babSopenharmony_ci// If no filename, do non-filename-based #line emit. Else do filename-based emit.
111617a3babSopenharmony_ci// Emit OpLine if we've been asked to emit OpLines and the line number or filename
112617a3babSopenharmony_ci// has changed since the last time, and line number is valid.
113617a3babSopenharmony_civoid Builder::setLine(int lineNum, const char* filename)
114617a3babSopenharmony_ci{
115617a3babSopenharmony_ci    if (filename == nullptr) {
116617a3babSopenharmony_ci        setLine(lineNum);
117617a3babSopenharmony_ci        return;
118617a3babSopenharmony_ci    }
119617a3babSopenharmony_ci    if ((lineNum != 0 && lineNum != currentLine) || currentFile == nullptr ||
120617a3babSopenharmony_ci            strncmp(filename, currentFile, strlen(currentFile) + 1) != 0) {
121617a3babSopenharmony_ci        currentLine = lineNum;
122617a3babSopenharmony_ci        currentFile = filename;
123617a3babSopenharmony_ci        if (emitOpLines) {
124617a3babSopenharmony_ci            spv::Id strId = getStringId(filename);
125617a3babSopenharmony_ci            if (emitNonSemanticShaderDebugInfo)
126617a3babSopenharmony_ci                addDebugScopeAndLine(strId, currentLine, 0);
127617a3babSopenharmony_ci            else
128617a3babSopenharmony_ci                addLine(strId, currentLine, 0);
129617a3babSopenharmony_ci        }
130617a3babSopenharmony_ci    }
131617a3babSopenharmony_ci}
132617a3babSopenharmony_ci
133617a3babSopenharmony_civoid Builder::addLine(Id fileName, int lineNum, int column)
134617a3babSopenharmony_ci{
135617a3babSopenharmony_ci    Instruction* line = new Instruction(OpLine);
136617a3babSopenharmony_ci    line->addIdOperand(fileName);
137617a3babSopenharmony_ci    line->addImmediateOperand(lineNum);
138617a3babSopenharmony_ci    line->addImmediateOperand(column);
139617a3babSopenharmony_ci    buildPoint->addInstruction(std::unique_ptr<Instruction>(line));
140617a3babSopenharmony_ci}
141617a3babSopenharmony_ci
142617a3babSopenharmony_civoid Builder::addDebugScopeAndLine(Id fileName, int lineNum, int column)
143617a3babSopenharmony_ci{
144617a3babSopenharmony_ci    assert(!currentDebugScopeId.empty());
145617a3babSopenharmony_ci    if (currentDebugScopeId.top() != lastDebugScopeId) {
146617a3babSopenharmony_ci        spv::Id resultId = getUniqueId();
147617a3babSopenharmony_ci        Instruction* scopeInst = new Instruction(resultId, makeVoidType(), OpExtInst);
148617a3babSopenharmony_ci        scopeInst->addIdOperand(nonSemanticShaderDebugInfo);
149617a3babSopenharmony_ci        scopeInst->addImmediateOperand(NonSemanticShaderDebugInfo100DebugScope);
150617a3babSopenharmony_ci        scopeInst->addIdOperand(currentDebugScopeId.top());
151617a3babSopenharmony_ci        buildPoint->addInstruction(std::unique_ptr<Instruction>(scopeInst));
152617a3babSopenharmony_ci        lastDebugScopeId = currentDebugScopeId.top();
153617a3babSopenharmony_ci    }
154617a3babSopenharmony_ci    spv::Id resultId = getUniqueId();
155617a3babSopenharmony_ci    Instruction* lineInst = new Instruction(resultId, makeVoidType(), OpExtInst);
156617a3babSopenharmony_ci    lineInst->addIdOperand(nonSemanticShaderDebugInfo);
157617a3babSopenharmony_ci    lineInst->addImmediateOperand(NonSemanticShaderDebugInfo100DebugLine);
158617a3babSopenharmony_ci    lineInst->addIdOperand(makeDebugSource(fileName));
159617a3babSopenharmony_ci    lineInst->addIdOperand(makeUintConstant(lineNum));
160617a3babSopenharmony_ci    lineInst->addIdOperand(makeUintConstant(lineNum));
161617a3babSopenharmony_ci    lineInst->addIdOperand(makeUintConstant(column));
162617a3babSopenharmony_ci    lineInst->addIdOperand(makeUintConstant(column));
163617a3babSopenharmony_ci    buildPoint->addInstruction(std::unique_ptr<Instruction>(lineInst));
164617a3babSopenharmony_ci}
165617a3babSopenharmony_ci
166617a3babSopenharmony_ci// For creating new groupedTypes (will return old type if the requested one was already made).
167617a3babSopenharmony_ciId Builder::makeVoidType()
168617a3babSopenharmony_ci{
169617a3babSopenharmony_ci    Instruction* type;
170617a3babSopenharmony_ci    if (groupedTypes[OpTypeVoid].size() == 0) {
171617a3babSopenharmony_ci        Id typeId = getUniqueId();
172617a3babSopenharmony_ci        type = new Instruction(typeId, NoType, OpTypeVoid);
173617a3babSopenharmony_ci        groupedTypes[OpTypeVoid].push_back(type);
174617a3babSopenharmony_ci        constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
175617a3babSopenharmony_ci        module.mapInstruction(type);
176617a3babSopenharmony_ci        // Core OpTypeVoid used for debug void type
177617a3babSopenharmony_ci        if (emitNonSemanticShaderDebugInfo)
178617a3babSopenharmony_ci            debugId[typeId] = typeId;
179617a3babSopenharmony_ci    } else
180617a3babSopenharmony_ci        type = groupedTypes[OpTypeVoid].back();
181617a3babSopenharmony_ci
182617a3babSopenharmony_ci    return type->getResultId();
183617a3babSopenharmony_ci}
184617a3babSopenharmony_ci
185617a3babSopenharmony_ciId Builder::makeBoolType()
186617a3babSopenharmony_ci{
187617a3babSopenharmony_ci    Instruction* type;
188617a3babSopenharmony_ci    if (groupedTypes[OpTypeBool].size() == 0) {
189617a3babSopenharmony_ci        type = new Instruction(getUniqueId(), NoType, OpTypeBool);
190617a3babSopenharmony_ci        groupedTypes[OpTypeBool].push_back(type);
191617a3babSopenharmony_ci        constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
192617a3babSopenharmony_ci        module.mapInstruction(type);
193617a3babSopenharmony_ci
194617a3babSopenharmony_ci        if (emitNonSemanticShaderDebugInfo) {
195617a3babSopenharmony_ci            auto const debugResultId = makeBoolDebugType(32);
196617a3babSopenharmony_ci            debugId[type->getResultId()] = debugResultId;
197617a3babSopenharmony_ci        }
198617a3babSopenharmony_ci
199617a3babSopenharmony_ci    } else
200617a3babSopenharmony_ci        type = groupedTypes[OpTypeBool].back();
201617a3babSopenharmony_ci
202617a3babSopenharmony_ci
203617a3babSopenharmony_ci    return type->getResultId();
204617a3babSopenharmony_ci}
205617a3babSopenharmony_ci
206617a3babSopenharmony_ciId Builder::makeSamplerType()
207617a3babSopenharmony_ci{
208617a3babSopenharmony_ci    Instruction* type;
209617a3babSopenharmony_ci    if (groupedTypes[OpTypeSampler].size() == 0) {
210617a3babSopenharmony_ci        type = new Instruction(getUniqueId(), NoType, OpTypeSampler);
211617a3babSopenharmony_ci        groupedTypes[OpTypeSampler].push_back(type);
212617a3babSopenharmony_ci        constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
213617a3babSopenharmony_ci        module.mapInstruction(type);
214617a3babSopenharmony_ci    } else
215617a3babSopenharmony_ci        type = groupedTypes[OpTypeSampler].back();
216617a3babSopenharmony_ci
217617a3babSopenharmony_ci    if (emitNonSemanticShaderDebugInfo)
218617a3babSopenharmony_ci    {
219617a3babSopenharmony_ci        auto const debugResultId = makeCompositeDebugType({}, "type.sampler", NonSemanticShaderDebugInfo100Structure, true);
220617a3babSopenharmony_ci        debugId[type->getResultId()] = debugResultId;
221617a3babSopenharmony_ci    }
222617a3babSopenharmony_ci
223617a3babSopenharmony_ci    return type->getResultId();
224617a3babSopenharmony_ci}
225617a3babSopenharmony_ci
226617a3babSopenharmony_ciId Builder::makePointer(StorageClass storageClass, Id pointee)
227617a3babSopenharmony_ci{
228617a3babSopenharmony_ci    // try to find it
229617a3babSopenharmony_ci    Instruction* type;
230617a3babSopenharmony_ci    for (int t = 0; t < (int)groupedTypes[OpTypePointer].size(); ++t) {
231617a3babSopenharmony_ci        type = groupedTypes[OpTypePointer][t];
232617a3babSopenharmony_ci        if (type->getImmediateOperand(0) == (unsigned)storageClass &&
233617a3babSopenharmony_ci            type->getIdOperand(1) == pointee)
234617a3babSopenharmony_ci            return type->getResultId();
235617a3babSopenharmony_ci    }
236617a3babSopenharmony_ci
237617a3babSopenharmony_ci    // not found, make it
238617a3babSopenharmony_ci    type = new Instruction(getUniqueId(), NoType, OpTypePointer);
239617a3babSopenharmony_ci    type->addImmediateOperand(storageClass);
240617a3babSopenharmony_ci    type->addIdOperand(pointee);
241617a3babSopenharmony_ci    groupedTypes[OpTypePointer].push_back(type);
242617a3babSopenharmony_ci    constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
243617a3babSopenharmony_ci    module.mapInstruction(type);
244617a3babSopenharmony_ci
245617a3babSopenharmony_ci    return type->getResultId();
246617a3babSopenharmony_ci}
247617a3babSopenharmony_ci
248617a3babSopenharmony_ciId Builder::makeForwardPointer(StorageClass storageClass)
249617a3babSopenharmony_ci{
250617a3babSopenharmony_ci    // Caching/uniquifying doesn't work here, because we don't know the
251617a3babSopenharmony_ci    // pointee type and there can be multiple forward pointers of the same
252617a3babSopenharmony_ci    // storage type. Somebody higher up in the stack must keep track.
253617a3babSopenharmony_ci    Instruction* type = new Instruction(getUniqueId(), NoType, OpTypeForwardPointer);
254617a3babSopenharmony_ci    type->addImmediateOperand(storageClass);
255617a3babSopenharmony_ci    constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
256617a3babSopenharmony_ci    module.mapInstruction(type);
257617a3babSopenharmony_ci
258617a3babSopenharmony_ci    return type->getResultId();
259617a3babSopenharmony_ci}
260617a3babSopenharmony_ci
261617a3babSopenharmony_ciId Builder::makePointerFromForwardPointer(StorageClass storageClass, Id forwardPointerType, Id pointee)
262617a3babSopenharmony_ci{
263617a3babSopenharmony_ci    // try to find it
264617a3babSopenharmony_ci    Instruction* type;
265617a3babSopenharmony_ci    for (int t = 0; t < (int)groupedTypes[OpTypePointer].size(); ++t) {
266617a3babSopenharmony_ci        type = groupedTypes[OpTypePointer][t];
267617a3babSopenharmony_ci        if (type->getImmediateOperand(0) == (unsigned)storageClass &&
268617a3babSopenharmony_ci            type->getIdOperand(1) == pointee)
269617a3babSopenharmony_ci            return type->getResultId();
270617a3babSopenharmony_ci    }
271617a3babSopenharmony_ci
272617a3babSopenharmony_ci    type = new Instruction(forwardPointerType, NoType, OpTypePointer);
273617a3babSopenharmony_ci    type->addImmediateOperand(storageClass);
274617a3babSopenharmony_ci    type->addIdOperand(pointee);
275617a3babSopenharmony_ci    groupedTypes[OpTypePointer].push_back(type);
276617a3babSopenharmony_ci    constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
277617a3babSopenharmony_ci    module.mapInstruction(type);
278617a3babSopenharmony_ci
279617a3babSopenharmony_ci    return type->getResultId();
280617a3babSopenharmony_ci}
281617a3babSopenharmony_ci
282617a3babSopenharmony_ciId Builder::makeIntegerType(int width, bool hasSign)
283617a3babSopenharmony_ci{
284617a3babSopenharmony_ci    // try to find it
285617a3babSopenharmony_ci    Instruction* type;
286617a3babSopenharmony_ci    for (int t = 0; t < (int)groupedTypes[OpTypeInt].size(); ++t) {
287617a3babSopenharmony_ci        type = groupedTypes[OpTypeInt][t];
288617a3babSopenharmony_ci        if (type->getImmediateOperand(0) == (unsigned)width &&
289617a3babSopenharmony_ci            type->getImmediateOperand(1) == (hasSign ? 1u : 0u))
290617a3babSopenharmony_ci            return type->getResultId();
291617a3babSopenharmony_ci    }
292617a3babSopenharmony_ci
293617a3babSopenharmony_ci    // not found, make it
294617a3babSopenharmony_ci    type = new Instruction(getUniqueId(), NoType, OpTypeInt);
295617a3babSopenharmony_ci    type->addImmediateOperand(width);
296617a3babSopenharmony_ci    type->addImmediateOperand(hasSign ? 1 : 0);
297617a3babSopenharmony_ci    groupedTypes[OpTypeInt].push_back(type);
298617a3babSopenharmony_ci    constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
299617a3babSopenharmony_ci    module.mapInstruction(type);
300617a3babSopenharmony_ci
301617a3babSopenharmony_ci    // deal with capabilities
302617a3babSopenharmony_ci    switch (width) {
303617a3babSopenharmony_ci    case 8:
304617a3babSopenharmony_ci    case 16:
305617a3babSopenharmony_ci        // these are currently handled by storage-type declarations and post processing
306617a3babSopenharmony_ci        break;
307617a3babSopenharmony_ci    case 64:
308617a3babSopenharmony_ci        addCapability(CapabilityInt64);
309617a3babSopenharmony_ci        break;
310617a3babSopenharmony_ci    default:
311617a3babSopenharmony_ci        break;
312617a3babSopenharmony_ci    }
313617a3babSopenharmony_ci
314617a3babSopenharmony_ci    if (emitNonSemanticShaderDebugInfo)
315617a3babSopenharmony_ci    {
316617a3babSopenharmony_ci        auto const debugResultId = makeIntegerDebugType(width, hasSign);
317617a3babSopenharmony_ci        debugId[type->getResultId()] = debugResultId;
318617a3babSopenharmony_ci    }
319617a3babSopenharmony_ci
320617a3babSopenharmony_ci    return type->getResultId();
321617a3babSopenharmony_ci}
322617a3babSopenharmony_ci
323617a3babSopenharmony_ciId Builder::makeFloatType(int width)
324617a3babSopenharmony_ci{
325617a3babSopenharmony_ci    // try to find it
326617a3babSopenharmony_ci    Instruction* type;
327617a3babSopenharmony_ci    for (int t = 0; t < (int)groupedTypes[OpTypeFloat].size(); ++t) {
328617a3babSopenharmony_ci        type = groupedTypes[OpTypeFloat][t];
329617a3babSopenharmony_ci        if (type->getImmediateOperand(0) == (unsigned)width)
330617a3babSopenharmony_ci            return type->getResultId();
331617a3babSopenharmony_ci    }
332617a3babSopenharmony_ci
333617a3babSopenharmony_ci    // not found, make it
334617a3babSopenharmony_ci    type = new Instruction(getUniqueId(), NoType, OpTypeFloat);
335617a3babSopenharmony_ci    type->addImmediateOperand(width);
336617a3babSopenharmony_ci    groupedTypes[OpTypeFloat].push_back(type);
337617a3babSopenharmony_ci    constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
338617a3babSopenharmony_ci    module.mapInstruction(type);
339617a3babSopenharmony_ci
340617a3babSopenharmony_ci    // deal with capabilities
341617a3babSopenharmony_ci    switch (width) {
342617a3babSopenharmony_ci    case 16:
343617a3babSopenharmony_ci        // currently handled by storage-type declarations and post processing
344617a3babSopenharmony_ci        break;
345617a3babSopenharmony_ci    case 64:
346617a3babSopenharmony_ci        addCapability(CapabilityFloat64);
347617a3babSopenharmony_ci        break;
348617a3babSopenharmony_ci    default:
349617a3babSopenharmony_ci        break;
350617a3babSopenharmony_ci    }
351617a3babSopenharmony_ci
352617a3babSopenharmony_ci    if (emitNonSemanticShaderDebugInfo)
353617a3babSopenharmony_ci    {
354617a3babSopenharmony_ci        auto const debugResultId = makeFloatDebugType(width);
355617a3babSopenharmony_ci        debugId[type->getResultId()] = debugResultId;
356617a3babSopenharmony_ci    }
357617a3babSopenharmony_ci
358617a3babSopenharmony_ci    return type->getResultId();
359617a3babSopenharmony_ci}
360617a3babSopenharmony_ci
361617a3babSopenharmony_ci// Make a struct without checking for duplication.
362617a3babSopenharmony_ci// See makeStructResultType() for non-decorated structs
363617a3babSopenharmony_ci// needed as the result of some instructions, which does
364617a3babSopenharmony_ci// check for duplicates.
365617a3babSopenharmony_ciId Builder::makeStructType(const std::vector<Id>& members, const char* name, bool const compilerGenerated)
366617a3babSopenharmony_ci{
367617a3babSopenharmony_ci    // Don't look for previous one, because in the general case,
368617a3babSopenharmony_ci    // structs can be duplicated except for decorations.
369617a3babSopenharmony_ci
370617a3babSopenharmony_ci    // not found, make it
371617a3babSopenharmony_ci    Instruction* type = new Instruction(getUniqueId(), NoType, OpTypeStruct);
372617a3babSopenharmony_ci    for (int op = 0; op < (int)members.size(); ++op)
373617a3babSopenharmony_ci        type->addIdOperand(members[op]);
374617a3babSopenharmony_ci    groupedTypes[OpTypeStruct].push_back(type);
375617a3babSopenharmony_ci    constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
376617a3babSopenharmony_ci    module.mapInstruction(type);
377617a3babSopenharmony_ci    addName(type->getResultId(), name);
378617a3babSopenharmony_ci
379617a3babSopenharmony_ci    if (emitNonSemanticShaderDebugInfo && !compilerGenerated)
380617a3babSopenharmony_ci    {
381617a3babSopenharmony_ci        auto const debugResultId = makeCompositeDebugType(members, name, NonSemanticShaderDebugInfo100Structure);
382617a3babSopenharmony_ci        debugId[type->getResultId()] = debugResultId;
383617a3babSopenharmony_ci    }
384617a3babSopenharmony_ci
385617a3babSopenharmony_ci    return type->getResultId();
386617a3babSopenharmony_ci}
387617a3babSopenharmony_ci
388617a3babSopenharmony_ci// Make a struct for the simple results of several instructions,
389617a3babSopenharmony_ci// checking for duplication.
390617a3babSopenharmony_ciId Builder::makeStructResultType(Id type0, Id type1)
391617a3babSopenharmony_ci{
392617a3babSopenharmony_ci    // try to find it
393617a3babSopenharmony_ci    Instruction* type;
394617a3babSopenharmony_ci    for (int t = 0; t < (int)groupedTypes[OpTypeStruct].size(); ++t) {
395617a3babSopenharmony_ci        type = groupedTypes[OpTypeStruct][t];
396617a3babSopenharmony_ci        if (type->getNumOperands() != 2)
397617a3babSopenharmony_ci            continue;
398617a3babSopenharmony_ci        if (type->getIdOperand(0) != type0 ||
399617a3babSopenharmony_ci            type->getIdOperand(1) != type1)
400617a3babSopenharmony_ci            continue;
401617a3babSopenharmony_ci        return type->getResultId();
402617a3babSopenharmony_ci    }
403617a3babSopenharmony_ci
404617a3babSopenharmony_ci    // not found, make it
405617a3babSopenharmony_ci    std::vector<spv::Id> members;
406617a3babSopenharmony_ci    members.push_back(type0);
407617a3babSopenharmony_ci    members.push_back(type1);
408617a3babSopenharmony_ci
409617a3babSopenharmony_ci    return makeStructType(members, "ResType");
410617a3babSopenharmony_ci}
411617a3babSopenharmony_ci
412617a3babSopenharmony_ciId Builder::makeVectorType(Id component, int size)
413617a3babSopenharmony_ci{
414617a3babSopenharmony_ci    // try to find it
415617a3babSopenharmony_ci    Instruction* type;
416617a3babSopenharmony_ci    for (int t = 0; t < (int)groupedTypes[OpTypeVector].size(); ++t) {
417617a3babSopenharmony_ci        type = groupedTypes[OpTypeVector][t];
418617a3babSopenharmony_ci        if (type->getIdOperand(0) == component &&
419617a3babSopenharmony_ci            type->getImmediateOperand(1) == (unsigned)size)
420617a3babSopenharmony_ci            return type->getResultId();
421617a3babSopenharmony_ci    }
422617a3babSopenharmony_ci
423617a3babSopenharmony_ci    // not found, make it
424617a3babSopenharmony_ci    type = new Instruction(getUniqueId(), NoType, OpTypeVector);
425617a3babSopenharmony_ci    type->addIdOperand(component);
426617a3babSopenharmony_ci    type->addImmediateOperand(size);
427617a3babSopenharmony_ci    groupedTypes[OpTypeVector].push_back(type);
428617a3babSopenharmony_ci    constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
429617a3babSopenharmony_ci    module.mapInstruction(type);
430617a3babSopenharmony_ci
431617a3babSopenharmony_ci    if (emitNonSemanticShaderDebugInfo)
432617a3babSopenharmony_ci    {
433617a3babSopenharmony_ci        auto const debugResultId = makeVectorDebugType(component, size);
434617a3babSopenharmony_ci        debugId[type->getResultId()] = debugResultId;
435617a3babSopenharmony_ci    }
436617a3babSopenharmony_ci
437617a3babSopenharmony_ci    return type->getResultId();
438617a3babSopenharmony_ci}
439617a3babSopenharmony_ci
440617a3babSopenharmony_ciId Builder::makeMatrixType(Id component, int cols, int rows)
441617a3babSopenharmony_ci{
442617a3babSopenharmony_ci    assert(cols <= maxMatrixSize && rows <= maxMatrixSize);
443617a3babSopenharmony_ci
444617a3babSopenharmony_ci    Id column = makeVectorType(component, rows);
445617a3babSopenharmony_ci
446617a3babSopenharmony_ci    // try to find it
447617a3babSopenharmony_ci    Instruction* type;
448617a3babSopenharmony_ci    for (int t = 0; t < (int)groupedTypes[OpTypeMatrix].size(); ++t) {
449617a3babSopenharmony_ci        type = groupedTypes[OpTypeMatrix][t];
450617a3babSopenharmony_ci        if (type->getIdOperand(0) == column &&
451617a3babSopenharmony_ci            type->getImmediateOperand(1) == (unsigned)cols)
452617a3babSopenharmony_ci            return type->getResultId();
453617a3babSopenharmony_ci    }
454617a3babSopenharmony_ci
455617a3babSopenharmony_ci    // not found, make it
456617a3babSopenharmony_ci    type = new Instruction(getUniqueId(), NoType, OpTypeMatrix);
457617a3babSopenharmony_ci    type->addIdOperand(column);
458617a3babSopenharmony_ci    type->addImmediateOperand(cols);
459617a3babSopenharmony_ci    groupedTypes[OpTypeMatrix].push_back(type);
460617a3babSopenharmony_ci    constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
461617a3babSopenharmony_ci    module.mapInstruction(type);
462617a3babSopenharmony_ci
463617a3babSopenharmony_ci    if (emitNonSemanticShaderDebugInfo)
464617a3babSopenharmony_ci    {
465617a3babSopenharmony_ci        auto const debugResultId = makeMatrixDebugType(column, cols);
466617a3babSopenharmony_ci        debugId[type->getResultId()] = debugResultId;
467617a3babSopenharmony_ci    }
468617a3babSopenharmony_ci
469617a3babSopenharmony_ci    return type->getResultId();
470617a3babSopenharmony_ci}
471617a3babSopenharmony_ci
472617a3babSopenharmony_ciId Builder::makeCooperativeMatrixTypeKHR(Id component, Id scope, Id rows, Id cols, Id use)
473617a3babSopenharmony_ci{
474617a3babSopenharmony_ci    // try to find it
475617a3babSopenharmony_ci    Instruction* type;
476617a3babSopenharmony_ci    for (int t = 0; t < (int)groupedTypes[OpTypeCooperativeMatrixKHR].size(); ++t) {
477617a3babSopenharmony_ci        type = groupedTypes[OpTypeCooperativeMatrixKHR][t];
478617a3babSopenharmony_ci        if (type->getIdOperand(0) == component &&
479617a3babSopenharmony_ci            type->getIdOperand(1) == scope &&
480617a3babSopenharmony_ci            type->getIdOperand(2) == rows &&
481617a3babSopenharmony_ci            type->getIdOperand(3) == cols &&
482617a3babSopenharmony_ci            type->getIdOperand(4) == use)
483617a3babSopenharmony_ci            return type->getResultId();
484617a3babSopenharmony_ci    }
485617a3babSopenharmony_ci
486617a3babSopenharmony_ci    // not found, make it
487617a3babSopenharmony_ci    type = new Instruction(getUniqueId(), NoType, OpTypeCooperativeMatrixKHR);
488617a3babSopenharmony_ci    type->addIdOperand(component);
489617a3babSopenharmony_ci    type->addIdOperand(scope);
490617a3babSopenharmony_ci    type->addIdOperand(rows);
491617a3babSopenharmony_ci    type->addIdOperand(cols);
492617a3babSopenharmony_ci    type->addIdOperand(use);
493617a3babSopenharmony_ci    groupedTypes[OpTypeCooperativeMatrixKHR].push_back(type);
494617a3babSopenharmony_ci    constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
495617a3babSopenharmony_ci    module.mapInstruction(type);
496617a3babSopenharmony_ci
497617a3babSopenharmony_ci    return type->getResultId();
498617a3babSopenharmony_ci}
499617a3babSopenharmony_ci
500617a3babSopenharmony_ciId Builder::makeCooperativeMatrixTypeNV(Id component, Id scope, Id rows, Id cols)
501617a3babSopenharmony_ci{
502617a3babSopenharmony_ci    // try to find it
503617a3babSopenharmony_ci    Instruction* type;
504617a3babSopenharmony_ci    for (int t = 0; t < (int)groupedTypes[OpTypeCooperativeMatrixNV].size(); ++t) {
505617a3babSopenharmony_ci        type = groupedTypes[OpTypeCooperativeMatrixNV][t];
506617a3babSopenharmony_ci        if (type->getIdOperand(0) == component && type->getIdOperand(1) == scope && type->getIdOperand(2) == rows &&
507617a3babSopenharmony_ci            type->getIdOperand(3) == cols)
508617a3babSopenharmony_ci            return type->getResultId();
509617a3babSopenharmony_ci    }
510617a3babSopenharmony_ci
511617a3babSopenharmony_ci    // not found, make it
512617a3babSopenharmony_ci    type = new Instruction(getUniqueId(), NoType, OpTypeCooperativeMatrixNV);
513617a3babSopenharmony_ci    type->addIdOperand(component);
514617a3babSopenharmony_ci    type->addIdOperand(scope);
515617a3babSopenharmony_ci    type->addIdOperand(rows);
516617a3babSopenharmony_ci    type->addIdOperand(cols);
517617a3babSopenharmony_ci    groupedTypes[OpTypeCooperativeMatrixNV].push_back(type);
518617a3babSopenharmony_ci    constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
519617a3babSopenharmony_ci    module.mapInstruction(type);
520617a3babSopenharmony_ci
521617a3babSopenharmony_ci    return type->getResultId();
522617a3babSopenharmony_ci}
523617a3babSopenharmony_ci
524617a3babSopenharmony_ciId Builder::makeCooperativeMatrixTypeWithSameShape(Id component, Id otherType)
525617a3babSopenharmony_ci{
526617a3babSopenharmony_ci    Instruction* instr = module.getInstruction(otherType);
527617a3babSopenharmony_ci    if (instr->getOpCode() == OpTypeCooperativeMatrixNV) {
528617a3babSopenharmony_ci        return makeCooperativeMatrixTypeNV(component, instr->getIdOperand(1), instr->getIdOperand(2), instr->getIdOperand(3));
529617a3babSopenharmony_ci    } else {
530617a3babSopenharmony_ci        assert(instr->getOpCode() == OpTypeCooperativeMatrixKHR);
531617a3babSopenharmony_ci        return makeCooperativeMatrixTypeKHR(component, instr->getIdOperand(1), instr->getIdOperand(2), instr->getIdOperand(3), instr->getIdOperand(4));
532617a3babSopenharmony_ci    }
533617a3babSopenharmony_ci}
534617a3babSopenharmony_ci
535617a3babSopenharmony_ciId Builder::makeGenericType(spv::Op opcode, std::vector<spv::IdImmediate>& operands)
536617a3babSopenharmony_ci{
537617a3babSopenharmony_ci    // try to find it
538617a3babSopenharmony_ci    Instruction* type;
539617a3babSopenharmony_ci    for (int t = 0; t < (int)groupedTypes[opcode].size(); ++t) {
540617a3babSopenharmony_ci        type = groupedTypes[opcode][t];
541617a3babSopenharmony_ci        if (static_cast<size_t>(type->getNumOperands()) != operands.size())
542617a3babSopenharmony_ci            continue; // Number mismatch, find next
543617a3babSopenharmony_ci
544617a3babSopenharmony_ci        bool match = true;
545617a3babSopenharmony_ci        for (int op = 0; match && op < (int)operands.size(); ++op) {
546617a3babSopenharmony_ci            match = (operands[op].isId ? type->getIdOperand(op) : type->getImmediateOperand(op)) == operands[op].word;
547617a3babSopenharmony_ci        }
548617a3babSopenharmony_ci        if (match)
549617a3babSopenharmony_ci            return type->getResultId();
550617a3babSopenharmony_ci    }
551617a3babSopenharmony_ci
552617a3babSopenharmony_ci    // not found, make it
553617a3babSopenharmony_ci    type = new Instruction(getUniqueId(), NoType, opcode);
554617a3babSopenharmony_ci    for (size_t op = 0; op < operands.size(); ++op) {
555617a3babSopenharmony_ci        if (operands[op].isId)
556617a3babSopenharmony_ci            type->addIdOperand(operands[op].word);
557617a3babSopenharmony_ci        else
558617a3babSopenharmony_ci            type->addImmediateOperand(operands[op].word);
559617a3babSopenharmony_ci    }
560617a3babSopenharmony_ci    groupedTypes[opcode].push_back(type);
561617a3babSopenharmony_ci    constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
562617a3babSopenharmony_ci    module.mapInstruction(type);
563617a3babSopenharmony_ci
564617a3babSopenharmony_ci    return type->getResultId();
565617a3babSopenharmony_ci}
566617a3babSopenharmony_ci
567617a3babSopenharmony_ci// TODO: performance: track arrays per stride
568617a3babSopenharmony_ci// If a stride is supplied (non-zero) make an array.
569617a3babSopenharmony_ci// If no stride (0), reuse previous array types.
570617a3babSopenharmony_ci// 'size' is an Id of a constant or specialization constant of the array size
571617a3babSopenharmony_ciId Builder::makeArrayType(Id element, Id sizeId, int stride)
572617a3babSopenharmony_ci{
573617a3babSopenharmony_ci    Instruction* type;
574617a3babSopenharmony_ci    if (stride == 0) {
575617a3babSopenharmony_ci        // try to find existing type
576617a3babSopenharmony_ci        for (int t = 0; t < (int)groupedTypes[OpTypeArray].size(); ++t) {
577617a3babSopenharmony_ci            type = groupedTypes[OpTypeArray][t];
578617a3babSopenharmony_ci            if (type->getIdOperand(0) == element &&
579617a3babSopenharmony_ci                type->getIdOperand(1) == sizeId)
580617a3babSopenharmony_ci                return type->getResultId();
581617a3babSopenharmony_ci        }
582617a3babSopenharmony_ci    }
583617a3babSopenharmony_ci
584617a3babSopenharmony_ci    // not found, make it
585617a3babSopenharmony_ci    type = new Instruction(getUniqueId(), NoType, OpTypeArray);
586617a3babSopenharmony_ci    type->addIdOperand(element);
587617a3babSopenharmony_ci    type->addIdOperand(sizeId);
588617a3babSopenharmony_ci    groupedTypes[OpTypeArray].push_back(type);
589617a3babSopenharmony_ci    constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
590617a3babSopenharmony_ci    module.mapInstruction(type);
591617a3babSopenharmony_ci
592617a3babSopenharmony_ci    if (emitNonSemanticShaderDebugInfo)
593617a3babSopenharmony_ci    {
594617a3babSopenharmony_ci        auto const debugResultId = makeArrayDebugType(element, sizeId);
595617a3babSopenharmony_ci        debugId[type->getResultId()] = debugResultId;
596617a3babSopenharmony_ci    }
597617a3babSopenharmony_ci
598617a3babSopenharmony_ci    return type->getResultId();
599617a3babSopenharmony_ci}
600617a3babSopenharmony_ci
601617a3babSopenharmony_ciId Builder::makeRuntimeArray(Id element)
602617a3babSopenharmony_ci{
603617a3babSopenharmony_ci    Instruction* type = new Instruction(getUniqueId(), NoType, OpTypeRuntimeArray);
604617a3babSopenharmony_ci    type->addIdOperand(element);
605617a3babSopenharmony_ci    constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
606617a3babSopenharmony_ci    module.mapInstruction(type);
607617a3babSopenharmony_ci
608617a3babSopenharmony_ci    if (emitNonSemanticShaderDebugInfo)
609617a3babSopenharmony_ci    {
610617a3babSopenharmony_ci        auto const debugResultId = makeArrayDebugType(element, makeUintConstant(0));
611617a3babSopenharmony_ci        debugId[type->getResultId()] = debugResultId;
612617a3babSopenharmony_ci    }
613617a3babSopenharmony_ci
614617a3babSopenharmony_ci    return type->getResultId();
615617a3babSopenharmony_ci}
616617a3babSopenharmony_ci
617617a3babSopenharmony_ciId Builder::makeFunctionType(Id returnType, const std::vector<Id>& paramTypes)
618617a3babSopenharmony_ci{
619617a3babSopenharmony_ci    // try to find it
620617a3babSopenharmony_ci    Instruction* type;
621617a3babSopenharmony_ci    for (int t = 0; t < (int)groupedTypes[OpTypeFunction].size(); ++t) {
622617a3babSopenharmony_ci        type = groupedTypes[OpTypeFunction][t];
623617a3babSopenharmony_ci        if (type->getIdOperand(0) != returnType || (int)paramTypes.size() != type->getNumOperands() - 1)
624617a3babSopenharmony_ci            continue;
625617a3babSopenharmony_ci        bool mismatch = false;
626617a3babSopenharmony_ci        for (int p = 0; p < (int)paramTypes.size(); ++p) {
627617a3babSopenharmony_ci            if (paramTypes[p] != type->getIdOperand(p + 1)) {
628617a3babSopenharmony_ci                mismatch = true;
629617a3babSopenharmony_ci                break;
630617a3babSopenharmony_ci            }
631617a3babSopenharmony_ci        }
632617a3babSopenharmony_ci        if (! mismatch)
633617a3babSopenharmony_ci        {
634617a3babSopenharmony_ci            // If compiling HLSL, glslang will create a wrapper function around the entrypoint. Accordingly, a void(void)
635617a3babSopenharmony_ci            // function type is created for the wrapper function. However, nonsemantic shader debug information is disabled
636617a3babSopenharmony_ci            // while creating the HLSL wrapper. Consequently, if we encounter another void(void) function, we need to create
637617a3babSopenharmony_ci            // the associated debug function type if it hasn't been created yet.
638617a3babSopenharmony_ci            if(emitNonSemanticShaderDebugInfo && debugId[type->getResultId()] == 0) {
639617a3babSopenharmony_ci                assert(sourceLang == spv::SourceLanguageHLSL);
640617a3babSopenharmony_ci                assert(getTypeClass(returnType) == OpTypeVoid && paramTypes.size() == 0);
641617a3babSopenharmony_ci
642617a3babSopenharmony_ci                Id debugTypeId = makeDebugFunctionType(returnType, {});
643617a3babSopenharmony_ci                debugId[type->getResultId()] = debugTypeId;
644617a3babSopenharmony_ci            }
645617a3babSopenharmony_ci            return type->getResultId();
646617a3babSopenharmony_ci        }
647617a3babSopenharmony_ci    }
648617a3babSopenharmony_ci
649617a3babSopenharmony_ci    // not found, make it
650617a3babSopenharmony_ci    Id typeId = getUniqueId();
651617a3babSopenharmony_ci    type = new Instruction(typeId, NoType, OpTypeFunction);
652617a3babSopenharmony_ci    type->addIdOperand(returnType);
653617a3babSopenharmony_ci    for (int p = 0; p < (int)paramTypes.size(); ++p)
654617a3babSopenharmony_ci        type->addIdOperand(paramTypes[p]);
655617a3babSopenharmony_ci    groupedTypes[OpTypeFunction].push_back(type);
656617a3babSopenharmony_ci    constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
657617a3babSopenharmony_ci    module.mapInstruction(type);
658617a3babSopenharmony_ci
659617a3babSopenharmony_ci    // make debug type and map it
660617a3babSopenharmony_ci    if (emitNonSemanticShaderDebugInfo) {
661617a3babSopenharmony_ci        Id debugTypeId = makeDebugFunctionType(returnType, paramTypes);
662617a3babSopenharmony_ci        debugId[typeId] = debugTypeId;
663617a3babSopenharmony_ci    }
664617a3babSopenharmony_ci
665617a3babSopenharmony_ci    return type->getResultId();
666617a3babSopenharmony_ci}
667617a3babSopenharmony_ci
668617a3babSopenharmony_ciId Builder::makeDebugFunctionType(Id returnType, const std::vector<Id>& paramTypes)
669617a3babSopenharmony_ci{
670617a3babSopenharmony_ci    assert(debugId[returnType] != 0);
671617a3babSopenharmony_ci
672617a3babSopenharmony_ci    Id typeId = getUniqueId();
673617a3babSopenharmony_ci    auto type = new Instruction(typeId, makeVoidType(), OpExtInst);
674617a3babSopenharmony_ci    type->addIdOperand(nonSemanticShaderDebugInfo);
675617a3babSopenharmony_ci    type->addImmediateOperand(NonSemanticShaderDebugInfo100DebugTypeFunction);
676617a3babSopenharmony_ci    type->addIdOperand(makeUintConstant(NonSemanticShaderDebugInfo100FlagIsPublic));
677617a3babSopenharmony_ci    type->addIdOperand(debugId[returnType]);
678617a3babSopenharmony_ci    for (auto const paramType : paramTypes) {
679617a3babSopenharmony_ci        if (isPointerType(paramType) || isArrayType(paramType)) {
680617a3babSopenharmony_ci            type->addIdOperand(debugId[getContainedTypeId(paramType)]);
681617a3babSopenharmony_ci        }
682617a3babSopenharmony_ci        else {
683617a3babSopenharmony_ci            type->addIdOperand(debugId[paramType]);
684617a3babSopenharmony_ci        }
685617a3babSopenharmony_ci    }
686617a3babSopenharmony_ci    constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
687617a3babSopenharmony_ci    module.mapInstruction(type);
688617a3babSopenharmony_ci    return typeId;
689617a3babSopenharmony_ci}
690617a3babSopenharmony_ci
691617a3babSopenharmony_ciId Builder::makeImageType(Id sampledType, Dim dim, bool depth, bool arrayed, bool ms, unsigned sampled,
692617a3babSopenharmony_ci    ImageFormat format)
693617a3babSopenharmony_ci{
694617a3babSopenharmony_ci    assert(sampled == 1 || sampled == 2);
695617a3babSopenharmony_ci
696617a3babSopenharmony_ci    // try to find it
697617a3babSopenharmony_ci    Instruction* type;
698617a3babSopenharmony_ci    for (int t = 0; t < (int)groupedTypes[OpTypeImage].size(); ++t) {
699617a3babSopenharmony_ci        type = groupedTypes[OpTypeImage][t];
700617a3babSopenharmony_ci        if (type->getIdOperand(0) == sampledType &&
701617a3babSopenharmony_ci            type->getImmediateOperand(1) == (unsigned int)dim &&
702617a3babSopenharmony_ci            type->getImmediateOperand(2) == (  depth ? 1u : 0u) &&
703617a3babSopenharmony_ci            type->getImmediateOperand(3) == (arrayed ? 1u : 0u) &&
704617a3babSopenharmony_ci            type->getImmediateOperand(4) == (     ms ? 1u : 0u) &&
705617a3babSopenharmony_ci            type->getImmediateOperand(5) == sampled &&
706617a3babSopenharmony_ci            type->getImmediateOperand(6) == (unsigned int)format)
707617a3babSopenharmony_ci            return type->getResultId();
708617a3babSopenharmony_ci    }
709617a3babSopenharmony_ci
710617a3babSopenharmony_ci    // not found, make it
711617a3babSopenharmony_ci    type = new Instruction(getUniqueId(), NoType, OpTypeImage);
712617a3babSopenharmony_ci    type->addIdOperand(sampledType);
713617a3babSopenharmony_ci    type->addImmediateOperand(   dim);
714617a3babSopenharmony_ci    type->addImmediateOperand(  depth ? 1 : 0);
715617a3babSopenharmony_ci    type->addImmediateOperand(arrayed ? 1 : 0);
716617a3babSopenharmony_ci    type->addImmediateOperand(     ms ? 1 : 0);
717617a3babSopenharmony_ci    type->addImmediateOperand(sampled);
718617a3babSopenharmony_ci    type->addImmediateOperand((unsigned int)format);
719617a3babSopenharmony_ci
720617a3babSopenharmony_ci    groupedTypes[OpTypeImage].push_back(type);
721617a3babSopenharmony_ci    constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
722617a3babSopenharmony_ci    module.mapInstruction(type);
723617a3babSopenharmony_ci
724617a3babSopenharmony_ci    // deal with capabilities
725617a3babSopenharmony_ci    switch (dim) {
726617a3babSopenharmony_ci    case DimBuffer:
727617a3babSopenharmony_ci        if (sampled == 1)
728617a3babSopenharmony_ci            addCapability(CapabilitySampledBuffer);
729617a3babSopenharmony_ci        else
730617a3babSopenharmony_ci            addCapability(CapabilityImageBuffer);
731617a3babSopenharmony_ci        break;
732617a3babSopenharmony_ci    case Dim1D:
733617a3babSopenharmony_ci        if (sampled == 1)
734617a3babSopenharmony_ci            addCapability(CapabilitySampled1D);
735617a3babSopenharmony_ci        else
736617a3babSopenharmony_ci            addCapability(CapabilityImage1D);
737617a3babSopenharmony_ci        break;
738617a3babSopenharmony_ci    case DimCube:
739617a3babSopenharmony_ci        if (arrayed) {
740617a3babSopenharmony_ci            if (sampled == 1)
741617a3babSopenharmony_ci                addCapability(CapabilitySampledCubeArray);
742617a3babSopenharmony_ci            else
743617a3babSopenharmony_ci                addCapability(CapabilityImageCubeArray);
744617a3babSopenharmony_ci        }
745617a3babSopenharmony_ci        break;
746617a3babSopenharmony_ci    case DimRect:
747617a3babSopenharmony_ci        if (sampled == 1)
748617a3babSopenharmony_ci            addCapability(CapabilitySampledRect);
749617a3babSopenharmony_ci        else
750617a3babSopenharmony_ci            addCapability(CapabilityImageRect);
751617a3babSopenharmony_ci        break;
752617a3babSopenharmony_ci    case DimSubpassData:
753617a3babSopenharmony_ci        addCapability(CapabilityInputAttachment);
754617a3babSopenharmony_ci        break;
755617a3babSopenharmony_ci    default:
756617a3babSopenharmony_ci        break;
757617a3babSopenharmony_ci    }
758617a3babSopenharmony_ci
759617a3babSopenharmony_ci    if (ms) {
760617a3babSopenharmony_ci        if (sampled == 2) {
761617a3babSopenharmony_ci            // Images used with subpass data are not storage
762617a3babSopenharmony_ci            // images, so don't require the capability for them.
763617a3babSopenharmony_ci            if (dim != Dim::DimSubpassData)
764617a3babSopenharmony_ci                addCapability(CapabilityStorageImageMultisample);
765617a3babSopenharmony_ci            if (arrayed)
766617a3babSopenharmony_ci                addCapability(CapabilityImageMSArray);
767617a3babSopenharmony_ci        }
768617a3babSopenharmony_ci    }
769617a3babSopenharmony_ci
770617a3babSopenharmony_ci    if (emitNonSemanticShaderDebugInfo)
771617a3babSopenharmony_ci    {
772617a3babSopenharmony_ci        auto TypeName = [&dim]() -> char const* {
773617a3babSopenharmony_ci            switch (dim) {
774617a3babSopenharmony_ci                case Dim1D: return "type.1d.image";
775617a3babSopenharmony_ci                case Dim2D: return "type.2d.image";
776617a3babSopenharmony_ci                case Dim3D: return "type.3d.image";
777617a3babSopenharmony_ci                case DimCube: return "type.cube.image";
778617a3babSopenharmony_ci                default: return "type.image";
779617a3babSopenharmony_ci            }
780617a3babSopenharmony_ci        };
781617a3babSopenharmony_ci
782617a3babSopenharmony_ci        auto const debugResultId = makeCompositeDebugType({}, TypeName(), NonSemanticShaderDebugInfo100Class, true);
783617a3babSopenharmony_ci        debugId[type->getResultId()] = debugResultId;
784617a3babSopenharmony_ci    }
785617a3babSopenharmony_ci
786617a3babSopenharmony_ci    return type->getResultId();
787617a3babSopenharmony_ci}
788617a3babSopenharmony_ci
789617a3babSopenharmony_ciId Builder::makeSampledImageType(Id imageType)
790617a3babSopenharmony_ci{
791617a3babSopenharmony_ci    // try to find it
792617a3babSopenharmony_ci    Instruction* type;
793617a3babSopenharmony_ci    for (int t = 0; t < (int)groupedTypes[OpTypeSampledImage].size(); ++t) {
794617a3babSopenharmony_ci        type = groupedTypes[OpTypeSampledImage][t];
795617a3babSopenharmony_ci        if (type->getIdOperand(0) == imageType)
796617a3babSopenharmony_ci            return type->getResultId();
797617a3babSopenharmony_ci    }
798617a3babSopenharmony_ci
799617a3babSopenharmony_ci    // not found, make it
800617a3babSopenharmony_ci    type = new Instruction(getUniqueId(), NoType, OpTypeSampledImage);
801617a3babSopenharmony_ci    type->addIdOperand(imageType);
802617a3babSopenharmony_ci
803617a3babSopenharmony_ci    groupedTypes[OpTypeSampledImage].push_back(type);
804617a3babSopenharmony_ci    constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
805617a3babSopenharmony_ci    module.mapInstruction(type);
806617a3babSopenharmony_ci
807617a3babSopenharmony_ci    if (emitNonSemanticShaderDebugInfo)
808617a3babSopenharmony_ci    {
809617a3babSopenharmony_ci        auto const debugResultId = makeCompositeDebugType({}, "type.sampled.image", NonSemanticShaderDebugInfo100Class, true);
810617a3babSopenharmony_ci        debugId[type->getResultId()] = debugResultId;
811617a3babSopenharmony_ci    }
812617a3babSopenharmony_ci
813617a3babSopenharmony_ci    return type->getResultId();
814617a3babSopenharmony_ci}
815617a3babSopenharmony_ci
816617a3babSopenharmony_ciId Builder::makeDebugInfoNone()
817617a3babSopenharmony_ci{
818617a3babSopenharmony_ci    if (debugInfoNone != 0)
819617a3babSopenharmony_ci        return debugInfoNone;
820617a3babSopenharmony_ci
821617a3babSopenharmony_ci    Instruction* inst = new Instruction(getUniqueId(), makeVoidType(), OpExtInst);
822617a3babSopenharmony_ci    inst->addIdOperand(nonSemanticShaderDebugInfo);
823617a3babSopenharmony_ci    inst->addImmediateOperand(NonSemanticShaderDebugInfo100DebugInfoNone);
824617a3babSopenharmony_ci
825617a3babSopenharmony_ci    constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(inst));
826617a3babSopenharmony_ci    module.mapInstruction(inst);
827617a3babSopenharmony_ci
828617a3babSopenharmony_ci    debugInfoNone = inst->getResultId();
829617a3babSopenharmony_ci
830617a3babSopenharmony_ci    return debugInfoNone;
831617a3babSopenharmony_ci}
832617a3babSopenharmony_ci
833617a3babSopenharmony_ciId Builder::makeBoolDebugType(int const size)
834617a3babSopenharmony_ci{
835617a3babSopenharmony_ci    // try to find it
836617a3babSopenharmony_ci    Instruction* type;
837617a3babSopenharmony_ci    for (int t = 0; t < (int)groupedDebugTypes[NonSemanticShaderDebugInfo100DebugTypeBasic].size(); ++t) {
838617a3babSopenharmony_ci        type = groupedDebugTypes[NonSemanticShaderDebugInfo100DebugTypeBasic][t];
839617a3babSopenharmony_ci        if (type->getIdOperand(0) == getStringId("bool") &&
840617a3babSopenharmony_ci            type->getIdOperand(1) == static_cast<unsigned int>(size) &&
841617a3babSopenharmony_ci            type->getIdOperand(2) == NonSemanticShaderDebugInfo100Boolean)
842617a3babSopenharmony_ci            return type->getResultId();
843617a3babSopenharmony_ci    }
844617a3babSopenharmony_ci
845617a3babSopenharmony_ci    type = new Instruction(getUniqueId(), makeVoidType(), OpExtInst);
846617a3babSopenharmony_ci    type->addIdOperand(nonSemanticShaderDebugInfo);
847617a3babSopenharmony_ci    type->addImmediateOperand(NonSemanticShaderDebugInfo100DebugTypeBasic);
848617a3babSopenharmony_ci
849617a3babSopenharmony_ci    type->addIdOperand(getStringId("bool")); // name id
850617a3babSopenharmony_ci    type->addIdOperand(makeUintConstant(size)); // size id
851617a3babSopenharmony_ci    type->addIdOperand(makeUintConstant(NonSemanticShaderDebugInfo100Boolean)); // encoding id
852617a3babSopenharmony_ci    type->addIdOperand(makeUintConstant(NonSemanticShaderDebugInfo100None)); // flags id
853617a3babSopenharmony_ci
854617a3babSopenharmony_ci    groupedDebugTypes[NonSemanticShaderDebugInfo100DebugTypeBasic].push_back(type);
855617a3babSopenharmony_ci    constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
856617a3babSopenharmony_ci    module.mapInstruction(type);
857617a3babSopenharmony_ci
858617a3babSopenharmony_ci    return type->getResultId();
859617a3babSopenharmony_ci}
860617a3babSopenharmony_ci
861617a3babSopenharmony_ciId Builder::makeIntegerDebugType(int const width, bool const hasSign)
862617a3babSopenharmony_ci{
863617a3babSopenharmony_ci    const char* typeName = nullptr;
864617a3babSopenharmony_ci    switch (width) {
865617a3babSopenharmony_ci        case 8:  typeName = hasSign ? "int8_t" : "uint8_t"; break;
866617a3babSopenharmony_ci        case 16: typeName = hasSign ? "int16_t" : "uint16_t"; break;
867617a3babSopenharmony_ci        case 64: typeName = hasSign ? "int64_t" : "uint64_t"; break;
868617a3babSopenharmony_ci        default: typeName = hasSign ? "int" : "uint";
869617a3babSopenharmony_ci    }
870617a3babSopenharmony_ci    auto nameId = getStringId(typeName);
871617a3babSopenharmony_ci    // try to find it
872617a3babSopenharmony_ci    Instruction* type;
873617a3babSopenharmony_ci    for (int t = 0; t < (int)groupedDebugTypes[NonSemanticShaderDebugInfo100DebugTypeBasic].size(); ++t) {
874617a3babSopenharmony_ci        type = groupedDebugTypes[NonSemanticShaderDebugInfo100DebugTypeBasic][t];
875617a3babSopenharmony_ci        if (type->getIdOperand(0) == nameId &&
876617a3babSopenharmony_ci            type->getIdOperand(1) == static_cast<unsigned int>(width) &&
877617a3babSopenharmony_ci            type->getIdOperand(2) == (hasSign ? NonSemanticShaderDebugInfo100Signed : NonSemanticShaderDebugInfo100Unsigned))
878617a3babSopenharmony_ci            return type->getResultId();
879617a3babSopenharmony_ci    }
880617a3babSopenharmony_ci
881617a3babSopenharmony_ci    // not found, make it
882617a3babSopenharmony_ci    type = new Instruction(getUniqueId(), makeVoidType(), OpExtInst);
883617a3babSopenharmony_ci    type->addIdOperand(nonSemanticShaderDebugInfo);
884617a3babSopenharmony_ci    type->addImmediateOperand(NonSemanticShaderDebugInfo100DebugTypeBasic);
885617a3babSopenharmony_ci    type->addIdOperand(nameId); // name id
886617a3babSopenharmony_ci    type->addIdOperand(makeUintConstant(width)); // size id
887617a3babSopenharmony_ci    if(hasSign == true) {
888617a3babSopenharmony_ci        type->addIdOperand(makeUintConstant(NonSemanticShaderDebugInfo100Signed)); // encoding id
889617a3babSopenharmony_ci    } else {
890617a3babSopenharmony_ci        type->addIdOperand(makeUintConstant(NonSemanticShaderDebugInfo100Unsigned)); // encoding id
891617a3babSopenharmony_ci    }
892617a3babSopenharmony_ci    type->addIdOperand(makeUintConstant(NonSemanticShaderDebugInfo100None)); // flags id
893617a3babSopenharmony_ci
894617a3babSopenharmony_ci    groupedDebugTypes[NonSemanticShaderDebugInfo100DebugTypeBasic].push_back(type);
895617a3babSopenharmony_ci    constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
896617a3babSopenharmony_ci    module.mapInstruction(type);
897617a3babSopenharmony_ci
898617a3babSopenharmony_ci    return type->getResultId();
899617a3babSopenharmony_ci}
900617a3babSopenharmony_ci
901617a3babSopenharmony_ciId Builder::makeFloatDebugType(int const width)
902617a3babSopenharmony_ci{
903617a3babSopenharmony_ci    const char* typeName = nullptr;
904617a3babSopenharmony_ci    switch (width) {
905617a3babSopenharmony_ci        case 16: typeName = "float16_t"; break;
906617a3babSopenharmony_ci        case 64: typeName = "double"; break;
907617a3babSopenharmony_ci        default: typeName = "float"; break;
908617a3babSopenharmony_ci    }
909617a3babSopenharmony_ci    auto nameId = getStringId(typeName);
910617a3babSopenharmony_ci    // try to find it
911617a3babSopenharmony_ci    Instruction* type;
912617a3babSopenharmony_ci    for (int t = 0; t < (int)groupedDebugTypes[NonSemanticShaderDebugInfo100DebugTypeBasic].size(); ++t) {
913617a3babSopenharmony_ci        type = groupedDebugTypes[NonSemanticShaderDebugInfo100DebugTypeBasic][t];
914617a3babSopenharmony_ci        if (type->getIdOperand(0) == nameId &&
915617a3babSopenharmony_ci            type->getIdOperand(1) == static_cast<unsigned int>(width) &&
916617a3babSopenharmony_ci            type->getIdOperand(2) == NonSemanticShaderDebugInfo100Float)
917617a3babSopenharmony_ci            return type->getResultId();
918617a3babSopenharmony_ci    }
919617a3babSopenharmony_ci
920617a3babSopenharmony_ci    // not found, make it
921617a3babSopenharmony_ci    type = new Instruction(getUniqueId(), makeVoidType(), OpExtInst);
922617a3babSopenharmony_ci    type->addIdOperand(nonSemanticShaderDebugInfo);
923617a3babSopenharmony_ci    type->addImmediateOperand(NonSemanticShaderDebugInfo100DebugTypeBasic);
924617a3babSopenharmony_ci    type->addIdOperand(nameId); // name id
925617a3babSopenharmony_ci    type->addIdOperand(makeUintConstant(width)); // size id
926617a3babSopenharmony_ci    type->addIdOperand(makeUintConstant(NonSemanticShaderDebugInfo100Float)); // encoding id
927617a3babSopenharmony_ci    type->addIdOperand(makeUintConstant(NonSemanticShaderDebugInfo100None)); // flags id
928617a3babSopenharmony_ci
929617a3babSopenharmony_ci    groupedDebugTypes[NonSemanticShaderDebugInfo100DebugTypeBasic].push_back(type);
930617a3babSopenharmony_ci    constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
931617a3babSopenharmony_ci    module.mapInstruction(type);
932617a3babSopenharmony_ci
933617a3babSopenharmony_ci    return type->getResultId();
934617a3babSopenharmony_ci}
935617a3babSopenharmony_ci
936617a3babSopenharmony_ciId Builder::makeSequentialDebugType(Id const baseType, Id const componentCount, NonSemanticShaderDebugInfo100Instructions const sequenceType)
937617a3babSopenharmony_ci{
938617a3babSopenharmony_ci    assert(sequenceType == NonSemanticShaderDebugInfo100DebugTypeArray ||
939617a3babSopenharmony_ci        sequenceType == NonSemanticShaderDebugInfo100DebugTypeVector);
940617a3babSopenharmony_ci
941617a3babSopenharmony_ci    // try to find it
942617a3babSopenharmony_ci    Instruction* type;
943617a3babSopenharmony_ci    for (int t = 0; t < (int)groupedDebugTypes[sequenceType].size(); ++t) {
944617a3babSopenharmony_ci        type = groupedDebugTypes[sequenceType][t];
945617a3babSopenharmony_ci        if (type->getIdOperand(0) == baseType &&
946617a3babSopenharmony_ci            type->getIdOperand(1) == makeUintConstant(componentCount))
947617a3babSopenharmony_ci            return type->getResultId();
948617a3babSopenharmony_ci    }
949617a3babSopenharmony_ci
950617a3babSopenharmony_ci    // not found, make it
951617a3babSopenharmony_ci    type = new Instruction(getUniqueId(), makeVoidType(), OpExtInst);
952617a3babSopenharmony_ci    type->addIdOperand(nonSemanticShaderDebugInfo);
953617a3babSopenharmony_ci    type->addImmediateOperand(sequenceType);
954617a3babSopenharmony_ci    type->addIdOperand(debugId[baseType]); // base type
955617a3babSopenharmony_ci    type->addIdOperand(componentCount); // component count
956617a3babSopenharmony_ci
957617a3babSopenharmony_ci    groupedDebugTypes[sequenceType].push_back(type);
958617a3babSopenharmony_ci    constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
959617a3babSopenharmony_ci    module.mapInstruction(type);
960617a3babSopenharmony_ci
961617a3babSopenharmony_ci    return type->getResultId();
962617a3babSopenharmony_ci}
963617a3babSopenharmony_ci
964617a3babSopenharmony_ciId Builder::makeArrayDebugType(Id const baseType, Id const componentCount)
965617a3babSopenharmony_ci{
966617a3babSopenharmony_ci    return makeSequentialDebugType(baseType, componentCount, NonSemanticShaderDebugInfo100DebugTypeArray);
967617a3babSopenharmony_ci}
968617a3babSopenharmony_ci
969617a3babSopenharmony_ciId Builder::makeVectorDebugType(Id const baseType, int const componentCount)
970617a3babSopenharmony_ci{
971617a3babSopenharmony_ci    return makeSequentialDebugType(baseType, makeUintConstant(componentCount), NonSemanticShaderDebugInfo100DebugTypeVector);
972617a3babSopenharmony_ci}
973617a3babSopenharmony_ci
974617a3babSopenharmony_ciId Builder::makeMatrixDebugType(Id const vectorType, int const vectorCount, bool columnMajor)
975617a3babSopenharmony_ci{
976617a3babSopenharmony_ci    // try to find it
977617a3babSopenharmony_ci    Instruction* type;
978617a3babSopenharmony_ci    for (int t = 0; t < (int)groupedDebugTypes[NonSemanticShaderDebugInfo100DebugTypeMatrix].size(); ++t) {
979617a3babSopenharmony_ci        type = groupedDebugTypes[NonSemanticShaderDebugInfo100DebugTypeMatrix][t];
980617a3babSopenharmony_ci        if (type->getIdOperand(0) == vectorType &&
981617a3babSopenharmony_ci            type->getIdOperand(1) == makeUintConstant(vectorCount))
982617a3babSopenharmony_ci            return type->getResultId();
983617a3babSopenharmony_ci    }
984617a3babSopenharmony_ci
985617a3babSopenharmony_ci    // not found, make it
986617a3babSopenharmony_ci    type = new Instruction(getUniqueId(), makeVoidType(), OpExtInst);
987617a3babSopenharmony_ci    type->addIdOperand(nonSemanticShaderDebugInfo);
988617a3babSopenharmony_ci    type->addImmediateOperand(NonSemanticShaderDebugInfo100DebugTypeMatrix);
989617a3babSopenharmony_ci    type->addIdOperand(debugId[vectorType]); // vector type id
990617a3babSopenharmony_ci    type->addIdOperand(makeUintConstant(vectorCount)); // component count id
991617a3babSopenharmony_ci    type->addIdOperand(makeBoolConstant(columnMajor)); // column-major id
992617a3babSopenharmony_ci
993617a3babSopenharmony_ci    groupedDebugTypes[NonSemanticShaderDebugInfo100DebugTypeMatrix].push_back(type);
994617a3babSopenharmony_ci    constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
995617a3babSopenharmony_ci    module.mapInstruction(type);
996617a3babSopenharmony_ci
997617a3babSopenharmony_ci    return type->getResultId();
998617a3babSopenharmony_ci}
999617a3babSopenharmony_ci
1000617a3babSopenharmony_ciId Builder::makeMemberDebugType(Id const memberType, DebugTypeLoc const& debugTypeLoc)
1001617a3babSopenharmony_ci{
1002617a3babSopenharmony_ci    assert(debugId[memberType] != 0);
1003617a3babSopenharmony_ci
1004617a3babSopenharmony_ci    Instruction* type = new Instruction(getUniqueId(), makeVoidType(), OpExtInst);
1005617a3babSopenharmony_ci    type->addIdOperand(nonSemanticShaderDebugInfo);
1006617a3babSopenharmony_ci    type->addImmediateOperand(NonSemanticShaderDebugInfo100DebugTypeMember);
1007617a3babSopenharmony_ci    type->addIdOperand(getStringId(debugTypeLoc.name)); // name id
1008617a3babSopenharmony_ci    type->addIdOperand(debugId[memberType]); // type id
1009617a3babSopenharmony_ci    type->addIdOperand(makeDebugSource(sourceFileStringId)); // source id TODO: verify this works across include directives
1010617a3babSopenharmony_ci    type->addIdOperand(makeUintConstant(debugTypeLoc.line)); // line id TODO: currentLine is always zero
1011617a3babSopenharmony_ci    type->addIdOperand(makeUintConstant(debugTypeLoc.column)); // TODO: column id
1012617a3babSopenharmony_ci    type->addIdOperand(makeUintConstant(0)); // TODO: offset id
1013617a3babSopenharmony_ci    type->addIdOperand(makeUintConstant(0)); // TODO: size id
1014617a3babSopenharmony_ci    type->addIdOperand(makeUintConstant(NonSemanticShaderDebugInfo100FlagIsPublic)); // flags id
1015617a3babSopenharmony_ci
1016617a3babSopenharmony_ci    groupedDebugTypes[NonSemanticShaderDebugInfo100DebugTypeMember].push_back(type);
1017617a3babSopenharmony_ci    constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
1018617a3babSopenharmony_ci    module.mapInstruction(type);
1019617a3babSopenharmony_ci
1020617a3babSopenharmony_ci    return type->getResultId();
1021617a3babSopenharmony_ci}
1022617a3babSopenharmony_ci
1023617a3babSopenharmony_ci// Note: To represent a source language opaque type, this instruction must have no Members operands, Size operand must be
1024617a3babSopenharmony_ci// DebugInfoNone, and Name must start with @ to avoid clashes with user defined names.
1025617a3babSopenharmony_ciId Builder::makeCompositeDebugType(std::vector<Id> const& memberTypes, char const*const name,
1026617a3babSopenharmony_ci    NonSemanticShaderDebugInfo100DebugCompositeType const tag, bool const isOpaqueType)
1027617a3babSopenharmony_ci{
1028617a3babSopenharmony_ci    // Create the debug member types.
1029617a3babSopenharmony_ci    std::vector<Id> memberDebugTypes;
1030617a3babSopenharmony_ci    for(auto const memberType : memberTypes) {
1031617a3babSopenharmony_ci        assert(debugTypeLocs.find(memberType) != debugTypeLocs.end());
1032617a3babSopenharmony_ci
1033617a3babSopenharmony_ci        // There _should_ be debug types for all the member types but currently buffer references
1034617a3babSopenharmony_ci        // do not have member debug info generated.
1035617a3babSopenharmony_ci        if (debugId[memberType])
1036617a3babSopenharmony_ci            memberDebugTypes.emplace_back(makeMemberDebugType(memberType, debugTypeLocs[memberType]));
1037617a3babSopenharmony_ci
1038617a3babSopenharmony_ci        // TODO: Need to rethink this method of passing location information.
1039617a3babSopenharmony_ci        // debugTypeLocs.erase(memberType);
1040617a3babSopenharmony_ci    }
1041617a3babSopenharmony_ci
1042617a3babSopenharmony_ci    // Create The structure debug type.
1043617a3babSopenharmony_ci    Instruction* type = new Instruction(getUniqueId(), makeVoidType(), OpExtInst);
1044617a3babSopenharmony_ci    type->addIdOperand(nonSemanticShaderDebugInfo);
1045617a3babSopenharmony_ci    type->addImmediateOperand(NonSemanticShaderDebugInfo100DebugTypeComposite);
1046617a3babSopenharmony_ci    type->addIdOperand(getStringId(name)); // name id
1047617a3babSopenharmony_ci    type->addIdOperand(makeUintConstant(tag)); // tag id
1048617a3babSopenharmony_ci    type->addIdOperand(makeDebugSource(sourceFileStringId)); // source id TODO: verify this works across include directives
1049617a3babSopenharmony_ci    type->addIdOperand(makeUintConstant(currentLine)); // line id TODO: currentLine always zero?
1050617a3babSopenharmony_ci    type->addIdOperand(makeUintConstant(0)); // TODO: column id
1051617a3babSopenharmony_ci    type->addIdOperand(makeDebugCompilationUnit()); // scope id
1052617a3babSopenharmony_ci    if(isOpaqueType == true) {
1053617a3babSopenharmony_ci        // Prepend '@' to opaque types.
1054617a3babSopenharmony_ci        type->addIdOperand(getStringId('@' + std::string(name))); // linkage name id
1055617a3babSopenharmony_ci        type->addIdOperand(makeDebugInfoNone()); // size id
1056617a3babSopenharmony_ci    } else {
1057617a3babSopenharmony_ci        type->addIdOperand(getStringId(name)); // linkage name id
1058617a3babSopenharmony_ci        type->addIdOperand(makeUintConstant(0)); // TODO: size id
1059617a3babSopenharmony_ci    }
1060617a3babSopenharmony_ci    type->addIdOperand(makeUintConstant(NonSemanticShaderDebugInfo100FlagIsPublic)); // flags id
1061617a3babSopenharmony_ci    assert(isOpaqueType == false || (isOpaqueType == true && memberDebugTypes.empty()));
1062617a3babSopenharmony_ci    for(auto const memberDebugType : memberDebugTypes) {
1063617a3babSopenharmony_ci        type->addIdOperand(memberDebugType);
1064617a3babSopenharmony_ci    }
1065617a3babSopenharmony_ci
1066617a3babSopenharmony_ci    groupedDebugTypes[NonSemanticShaderDebugInfo100DebugTypeComposite].push_back(type);
1067617a3babSopenharmony_ci    constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
1068617a3babSopenharmony_ci    module.mapInstruction(type);
1069617a3babSopenharmony_ci
1070617a3babSopenharmony_ci    return type->getResultId();
1071617a3babSopenharmony_ci}
1072617a3babSopenharmony_ci
1073617a3babSopenharmony_ciId Builder::makeDebugSource(const Id fileName) {
1074617a3babSopenharmony_ci    if (debugSourceId.find(fileName) != debugSourceId.end())
1075617a3babSopenharmony_ci        return debugSourceId[fileName];
1076617a3babSopenharmony_ci    spv::Id resultId = getUniqueId();
1077617a3babSopenharmony_ci    Instruction* sourceInst = new Instruction(resultId, makeVoidType(), OpExtInst);
1078617a3babSopenharmony_ci    sourceInst->addIdOperand(nonSemanticShaderDebugInfo);
1079617a3babSopenharmony_ci    sourceInst->addImmediateOperand(NonSemanticShaderDebugInfo100DebugSource);
1080617a3babSopenharmony_ci    sourceInst->addIdOperand(fileName);
1081617a3babSopenharmony_ci    if (emitNonSemanticShaderDebugSource) {
1082617a3babSopenharmony_ci        spv::Id sourceId = 0;
1083617a3babSopenharmony_ci        if (fileName == sourceFileStringId) {
1084617a3babSopenharmony_ci            sourceId = getStringId(sourceText);
1085617a3babSopenharmony_ci        } else {
1086617a3babSopenharmony_ci            auto incItr = includeFiles.find(fileName);
1087617a3babSopenharmony_ci            assert(incItr != includeFiles.end());
1088617a3babSopenharmony_ci            sourceId = getStringId(*incItr->second);
1089617a3babSopenharmony_ci        }
1090617a3babSopenharmony_ci        sourceInst->addIdOperand(sourceId);
1091617a3babSopenharmony_ci    }
1092617a3babSopenharmony_ci    constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(sourceInst));
1093617a3babSopenharmony_ci    module.mapInstruction(sourceInst);
1094617a3babSopenharmony_ci    debugSourceId[fileName] = resultId;
1095617a3babSopenharmony_ci    return resultId;
1096617a3babSopenharmony_ci}
1097617a3babSopenharmony_ci
1098617a3babSopenharmony_ciId Builder::makeDebugCompilationUnit() {
1099617a3babSopenharmony_ci    if (nonSemanticShaderCompilationUnitId != 0)
1100617a3babSopenharmony_ci        return nonSemanticShaderCompilationUnitId;
1101617a3babSopenharmony_ci    spv::Id resultId = getUniqueId();
1102617a3babSopenharmony_ci    Instruction* sourceInst = new Instruction(resultId, makeVoidType(), OpExtInst);
1103617a3babSopenharmony_ci    sourceInst->addIdOperand(nonSemanticShaderDebugInfo);
1104617a3babSopenharmony_ci    sourceInst->addImmediateOperand(NonSemanticShaderDebugInfo100DebugCompilationUnit);
1105617a3babSopenharmony_ci    sourceInst->addIdOperand(makeUintConstant(1)); // TODO(greg-lunarg): Get rid of magic number
1106617a3babSopenharmony_ci    sourceInst->addIdOperand(makeUintConstant(4)); // TODO(greg-lunarg): Get rid of magic number
1107617a3babSopenharmony_ci    sourceInst->addIdOperand(makeDebugSource(sourceFileStringId));
1108617a3babSopenharmony_ci    sourceInst->addIdOperand(makeUintConstant(sourceLang));
1109617a3babSopenharmony_ci    constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(sourceInst));
1110617a3babSopenharmony_ci    module.mapInstruction(sourceInst);
1111617a3babSopenharmony_ci    nonSemanticShaderCompilationUnitId = resultId;
1112617a3babSopenharmony_ci
1113617a3babSopenharmony_ci    // We can reasonably assume that makeDebugCompilationUnit will be called before any of
1114617a3babSopenharmony_ci    // debug-scope stack. Function scopes and lexical scopes will occur afterward.
1115617a3babSopenharmony_ci    assert(currentDebugScopeId.empty());
1116617a3babSopenharmony_ci    currentDebugScopeId.push(nonSemanticShaderCompilationUnitId);
1117617a3babSopenharmony_ci
1118617a3babSopenharmony_ci    return resultId;
1119617a3babSopenharmony_ci}
1120617a3babSopenharmony_ci
1121617a3babSopenharmony_ciId Builder::createDebugGlobalVariable(Id const type, char const*const name, Id const variable)
1122617a3babSopenharmony_ci{
1123617a3babSopenharmony_ci    assert(type != 0);
1124617a3babSopenharmony_ci
1125617a3babSopenharmony_ci    Instruction* inst = new Instruction(getUniqueId(), makeVoidType(), OpExtInst);
1126617a3babSopenharmony_ci    inst->addIdOperand(nonSemanticShaderDebugInfo);
1127617a3babSopenharmony_ci    inst->addImmediateOperand(NonSemanticShaderDebugInfo100DebugGlobalVariable);
1128617a3babSopenharmony_ci    inst->addIdOperand(getStringId(name)); // name id
1129617a3babSopenharmony_ci    inst->addIdOperand(type); // type id
1130617a3babSopenharmony_ci    inst->addIdOperand(makeDebugSource(sourceFileStringId)); // source id
1131617a3babSopenharmony_ci    inst->addIdOperand(makeUintConstant(currentLine)); // line id TODO: currentLine always zero?
1132617a3babSopenharmony_ci    inst->addIdOperand(makeUintConstant(0)); // TODO: column id
1133617a3babSopenharmony_ci    inst->addIdOperand(makeDebugCompilationUnit()); // scope id
1134617a3babSopenharmony_ci    inst->addIdOperand(getStringId(name)); // linkage name id
1135617a3babSopenharmony_ci    inst->addIdOperand(variable); // variable id
1136617a3babSopenharmony_ci    inst->addIdOperand(makeUintConstant(NonSemanticShaderDebugInfo100FlagIsDefinition)); // flags id
1137617a3babSopenharmony_ci
1138617a3babSopenharmony_ci    constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(inst));
1139617a3babSopenharmony_ci    module.mapInstruction(inst);
1140617a3babSopenharmony_ci
1141617a3babSopenharmony_ci    return inst->getResultId();
1142617a3babSopenharmony_ci}
1143617a3babSopenharmony_ci
1144617a3babSopenharmony_ciId Builder::createDebugLocalVariable(Id type, char const*const name, size_t const argNumber)
1145617a3babSopenharmony_ci{
1146617a3babSopenharmony_ci    assert(name != nullptr);
1147617a3babSopenharmony_ci    assert(!currentDebugScopeId.empty());
1148617a3babSopenharmony_ci
1149617a3babSopenharmony_ci    Instruction* inst = new Instruction(getUniqueId(), makeVoidType(), OpExtInst);
1150617a3babSopenharmony_ci    inst->addIdOperand(nonSemanticShaderDebugInfo);
1151617a3babSopenharmony_ci    inst->addImmediateOperand(NonSemanticShaderDebugInfo100DebugLocalVariable);
1152617a3babSopenharmony_ci    inst->addIdOperand(getStringId(name)); // name id
1153617a3babSopenharmony_ci    inst->addIdOperand(type); // type id
1154617a3babSopenharmony_ci    inst->addIdOperand(makeDebugSource(sourceFileStringId)); // source id
1155617a3babSopenharmony_ci    inst->addIdOperand(makeUintConstant(currentLine)); // line id
1156617a3babSopenharmony_ci    inst->addIdOperand(makeUintConstant(0)); // TODO: column id
1157617a3babSopenharmony_ci    inst->addIdOperand(currentDebugScopeId.top()); // scope id
1158617a3babSopenharmony_ci    inst->addIdOperand(makeUintConstant(NonSemanticShaderDebugInfo100FlagIsLocal)); // flags id
1159617a3babSopenharmony_ci    if(argNumber != 0) {
1160617a3babSopenharmony_ci        inst->addIdOperand(makeUintConstant(argNumber));
1161617a3babSopenharmony_ci    }
1162617a3babSopenharmony_ci
1163617a3babSopenharmony_ci    constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(inst));
1164617a3babSopenharmony_ci    module.mapInstruction(inst);
1165617a3babSopenharmony_ci
1166617a3babSopenharmony_ci    return inst->getResultId();
1167617a3babSopenharmony_ci}
1168617a3babSopenharmony_ci
1169617a3babSopenharmony_ciId Builder::makeDebugExpression()
1170617a3babSopenharmony_ci{
1171617a3babSopenharmony_ci    if (debugExpression != 0)
1172617a3babSopenharmony_ci        return debugExpression;
1173617a3babSopenharmony_ci
1174617a3babSopenharmony_ci    Instruction* inst = new Instruction(getUniqueId(), makeVoidType(), OpExtInst);
1175617a3babSopenharmony_ci    inst->addIdOperand(nonSemanticShaderDebugInfo);
1176617a3babSopenharmony_ci    inst->addImmediateOperand(NonSemanticShaderDebugInfo100DebugExpression);
1177617a3babSopenharmony_ci
1178617a3babSopenharmony_ci    constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(inst));
1179617a3babSopenharmony_ci    module.mapInstruction(inst);
1180617a3babSopenharmony_ci
1181617a3babSopenharmony_ci    debugExpression = inst->getResultId();
1182617a3babSopenharmony_ci
1183617a3babSopenharmony_ci    return debugExpression;
1184617a3babSopenharmony_ci}
1185617a3babSopenharmony_ci
1186617a3babSopenharmony_ciId Builder::makeDebugDeclare(Id const debugLocalVariable, Id const pointer)
1187617a3babSopenharmony_ci{
1188617a3babSopenharmony_ci    Instruction* inst = new Instruction(getUniqueId(), makeVoidType(), OpExtInst);
1189617a3babSopenharmony_ci    inst->addIdOperand(nonSemanticShaderDebugInfo);
1190617a3babSopenharmony_ci    inst->addImmediateOperand(NonSemanticShaderDebugInfo100DebugDeclare);
1191617a3babSopenharmony_ci    inst->addIdOperand(debugLocalVariable); // debug local variable id
1192617a3babSopenharmony_ci    inst->addIdOperand(pointer); // pointer to local variable id
1193617a3babSopenharmony_ci    inst->addIdOperand(makeDebugExpression()); // expression id
1194617a3babSopenharmony_ci    buildPoint->addInstruction(std::unique_ptr<Instruction>(inst));
1195617a3babSopenharmony_ci
1196617a3babSopenharmony_ci    return inst->getResultId();
1197617a3babSopenharmony_ci}
1198617a3babSopenharmony_ci
1199617a3babSopenharmony_ciId Builder::makeDebugValue(Id const debugLocalVariable, Id const value)
1200617a3babSopenharmony_ci{
1201617a3babSopenharmony_ci    Instruction* inst = new Instruction(getUniqueId(), makeVoidType(), OpExtInst);
1202617a3babSopenharmony_ci    inst->addIdOperand(nonSemanticShaderDebugInfo);
1203617a3babSopenharmony_ci    inst->addImmediateOperand(NonSemanticShaderDebugInfo100DebugValue);
1204617a3babSopenharmony_ci    inst->addIdOperand(debugLocalVariable); // debug local variable id
1205617a3babSopenharmony_ci    inst->addIdOperand(value); // value of local variable id
1206617a3babSopenharmony_ci    inst->addIdOperand(makeDebugExpression()); // expression id
1207617a3babSopenharmony_ci    buildPoint->addInstruction(std::unique_ptr<Instruction>(inst));
1208617a3babSopenharmony_ci
1209617a3babSopenharmony_ci    return inst->getResultId();
1210617a3babSopenharmony_ci}
1211617a3babSopenharmony_ci
1212617a3babSopenharmony_ciId Builder::makeAccelerationStructureType()
1213617a3babSopenharmony_ci{
1214617a3babSopenharmony_ci    Instruction *type;
1215617a3babSopenharmony_ci    if (groupedTypes[OpTypeAccelerationStructureKHR].size() == 0) {
1216617a3babSopenharmony_ci        type = new Instruction(getUniqueId(), NoType, OpTypeAccelerationStructureKHR);
1217617a3babSopenharmony_ci        groupedTypes[OpTypeAccelerationStructureKHR].push_back(type);
1218617a3babSopenharmony_ci        constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
1219617a3babSopenharmony_ci        module.mapInstruction(type);
1220617a3babSopenharmony_ci    } else {
1221617a3babSopenharmony_ci        type = groupedTypes[OpTypeAccelerationStructureKHR].back();
1222617a3babSopenharmony_ci    }
1223617a3babSopenharmony_ci
1224617a3babSopenharmony_ci    return type->getResultId();
1225617a3babSopenharmony_ci}
1226617a3babSopenharmony_ci
1227617a3babSopenharmony_ciId Builder::makeRayQueryType()
1228617a3babSopenharmony_ci{
1229617a3babSopenharmony_ci    Instruction *type;
1230617a3babSopenharmony_ci    if (groupedTypes[OpTypeRayQueryKHR].size() == 0) {
1231617a3babSopenharmony_ci        type = new Instruction(getUniqueId(), NoType, OpTypeRayQueryKHR);
1232617a3babSopenharmony_ci        groupedTypes[OpTypeRayQueryKHR].push_back(type);
1233617a3babSopenharmony_ci        constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
1234617a3babSopenharmony_ci        module.mapInstruction(type);
1235617a3babSopenharmony_ci    } else {
1236617a3babSopenharmony_ci        type = groupedTypes[OpTypeRayQueryKHR].back();
1237617a3babSopenharmony_ci    }
1238617a3babSopenharmony_ci
1239617a3babSopenharmony_ci    return type->getResultId();
1240617a3babSopenharmony_ci}
1241617a3babSopenharmony_ci
1242617a3babSopenharmony_ciId Builder::makeHitObjectNVType()
1243617a3babSopenharmony_ci{
1244617a3babSopenharmony_ci    Instruction *type;
1245617a3babSopenharmony_ci    if (groupedTypes[OpTypeHitObjectNV].size() == 0) {
1246617a3babSopenharmony_ci        type = new Instruction(getUniqueId(), NoType, OpTypeHitObjectNV);
1247617a3babSopenharmony_ci        groupedTypes[OpTypeHitObjectNV].push_back(type);
1248617a3babSopenharmony_ci        constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
1249617a3babSopenharmony_ci        module.mapInstruction(type);
1250617a3babSopenharmony_ci    } else {
1251617a3babSopenharmony_ci        type = groupedTypes[OpTypeHitObjectNV].back();
1252617a3babSopenharmony_ci    }
1253617a3babSopenharmony_ci
1254617a3babSopenharmony_ci    return type->getResultId();
1255617a3babSopenharmony_ci}
1256617a3babSopenharmony_ci
1257617a3babSopenharmony_ciId Builder::getDerefTypeId(Id resultId) const
1258617a3babSopenharmony_ci{
1259617a3babSopenharmony_ci    Id typeId = getTypeId(resultId);
1260617a3babSopenharmony_ci    assert(isPointerType(typeId));
1261617a3babSopenharmony_ci
1262617a3babSopenharmony_ci    return module.getInstruction(typeId)->getIdOperand(1);
1263617a3babSopenharmony_ci}
1264617a3babSopenharmony_ci
1265617a3babSopenharmony_ciOp Builder::getMostBasicTypeClass(Id typeId) const
1266617a3babSopenharmony_ci{
1267617a3babSopenharmony_ci    Instruction* instr = module.getInstruction(typeId);
1268617a3babSopenharmony_ci
1269617a3babSopenharmony_ci    Op typeClass = instr->getOpCode();
1270617a3babSopenharmony_ci    switch (typeClass)
1271617a3babSopenharmony_ci    {
1272617a3babSopenharmony_ci    case OpTypeVector:
1273617a3babSopenharmony_ci    case OpTypeMatrix:
1274617a3babSopenharmony_ci    case OpTypeArray:
1275617a3babSopenharmony_ci    case OpTypeRuntimeArray:
1276617a3babSopenharmony_ci        return getMostBasicTypeClass(instr->getIdOperand(0));
1277617a3babSopenharmony_ci    case OpTypePointer:
1278617a3babSopenharmony_ci        return getMostBasicTypeClass(instr->getIdOperand(1));
1279617a3babSopenharmony_ci    default:
1280617a3babSopenharmony_ci        return typeClass;
1281617a3babSopenharmony_ci    }
1282617a3babSopenharmony_ci}
1283617a3babSopenharmony_ci
1284617a3babSopenharmony_ciint Builder::getNumTypeConstituents(Id typeId) const
1285617a3babSopenharmony_ci{
1286617a3babSopenharmony_ci    Instruction* instr = module.getInstruction(typeId);
1287617a3babSopenharmony_ci
1288617a3babSopenharmony_ci    switch (instr->getOpCode())
1289617a3babSopenharmony_ci    {
1290617a3babSopenharmony_ci    case OpTypeBool:
1291617a3babSopenharmony_ci    case OpTypeInt:
1292617a3babSopenharmony_ci    case OpTypeFloat:
1293617a3babSopenharmony_ci    case OpTypePointer:
1294617a3babSopenharmony_ci        return 1;
1295617a3babSopenharmony_ci    case OpTypeVector:
1296617a3babSopenharmony_ci    case OpTypeMatrix:
1297617a3babSopenharmony_ci        return instr->getImmediateOperand(1);
1298617a3babSopenharmony_ci    case OpTypeArray:
1299617a3babSopenharmony_ci    {
1300617a3babSopenharmony_ci        Id lengthId = instr->getIdOperand(1);
1301617a3babSopenharmony_ci        return module.getInstruction(lengthId)->getImmediateOperand(0);
1302617a3babSopenharmony_ci    }
1303617a3babSopenharmony_ci    case OpTypeStruct:
1304617a3babSopenharmony_ci        return instr->getNumOperands();
1305617a3babSopenharmony_ci    case OpTypeCooperativeMatrixKHR:
1306617a3babSopenharmony_ci    case OpTypeCooperativeMatrixNV:
1307617a3babSopenharmony_ci        // has only one constituent when used with OpCompositeConstruct.
1308617a3babSopenharmony_ci        return 1;
1309617a3babSopenharmony_ci    default:
1310617a3babSopenharmony_ci        assert(0);
1311617a3babSopenharmony_ci        return 1;
1312617a3babSopenharmony_ci    }
1313617a3babSopenharmony_ci}
1314617a3babSopenharmony_ci
1315617a3babSopenharmony_ci// Return the lowest-level type of scalar that an homogeneous composite is made out of.
1316617a3babSopenharmony_ci// Typically, this is just to find out if something is made out of ints or floats.
1317617a3babSopenharmony_ci// However, it includes returning a structure, if say, it is an array of structure.
1318617a3babSopenharmony_ciId Builder::getScalarTypeId(Id typeId) const
1319617a3babSopenharmony_ci{
1320617a3babSopenharmony_ci    Instruction* instr = module.getInstruction(typeId);
1321617a3babSopenharmony_ci
1322617a3babSopenharmony_ci    Op typeClass = instr->getOpCode();
1323617a3babSopenharmony_ci    switch (typeClass)
1324617a3babSopenharmony_ci    {
1325617a3babSopenharmony_ci    case OpTypeVoid:
1326617a3babSopenharmony_ci    case OpTypeBool:
1327617a3babSopenharmony_ci    case OpTypeInt:
1328617a3babSopenharmony_ci    case OpTypeFloat:
1329617a3babSopenharmony_ci    case OpTypeStruct:
1330617a3babSopenharmony_ci        return instr->getResultId();
1331617a3babSopenharmony_ci    case OpTypeVector:
1332617a3babSopenharmony_ci    case OpTypeMatrix:
1333617a3babSopenharmony_ci    case OpTypeArray:
1334617a3babSopenharmony_ci    case OpTypeRuntimeArray:
1335617a3babSopenharmony_ci    case OpTypePointer:
1336617a3babSopenharmony_ci        return getScalarTypeId(getContainedTypeId(typeId));
1337617a3babSopenharmony_ci    default:
1338617a3babSopenharmony_ci        assert(0);
1339617a3babSopenharmony_ci        return NoResult;
1340617a3babSopenharmony_ci    }
1341617a3babSopenharmony_ci}
1342617a3babSopenharmony_ci
1343617a3babSopenharmony_ci// Return the type of 'member' of a composite.
1344617a3babSopenharmony_ciId Builder::getContainedTypeId(Id typeId, int member) const
1345617a3babSopenharmony_ci{
1346617a3babSopenharmony_ci    Instruction* instr = module.getInstruction(typeId);
1347617a3babSopenharmony_ci
1348617a3babSopenharmony_ci    Op typeClass = instr->getOpCode();
1349617a3babSopenharmony_ci    switch (typeClass)
1350617a3babSopenharmony_ci    {
1351617a3babSopenharmony_ci    case OpTypeVector:
1352617a3babSopenharmony_ci    case OpTypeMatrix:
1353617a3babSopenharmony_ci    case OpTypeArray:
1354617a3babSopenharmony_ci    case OpTypeRuntimeArray:
1355617a3babSopenharmony_ci    case OpTypeCooperativeMatrixKHR:
1356617a3babSopenharmony_ci    case OpTypeCooperativeMatrixNV:
1357617a3babSopenharmony_ci        return instr->getIdOperand(0);
1358617a3babSopenharmony_ci    case OpTypePointer:
1359617a3babSopenharmony_ci        return instr->getIdOperand(1);
1360617a3babSopenharmony_ci    case OpTypeStruct:
1361617a3babSopenharmony_ci        return instr->getIdOperand(member);
1362617a3babSopenharmony_ci    default:
1363617a3babSopenharmony_ci        assert(0);
1364617a3babSopenharmony_ci        return NoResult;
1365617a3babSopenharmony_ci    }
1366617a3babSopenharmony_ci}
1367617a3babSopenharmony_ci
1368617a3babSopenharmony_ci// Figure out the final resulting type of the access chain.
1369617a3babSopenharmony_ciId Builder::getResultingAccessChainType() const
1370617a3babSopenharmony_ci{
1371617a3babSopenharmony_ci    assert(accessChain.base != NoResult);
1372617a3babSopenharmony_ci    Id typeId = getTypeId(accessChain.base);
1373617a3babSopenharmony_ci
1374617a3babSopenharmony_ci    assert(isPointerType(typeId));
1375617a3babSopenharmony_ci    typeId = getContainedTypeId(typeId);
1376617a3babSopenharmony_ci
1377617a3babSopenharmony_ci    for (int i = 0; i < (int)accessChain.indexChain.size(); ++i) {
1378617a3babSopenharmony_ci        if (isStructType(typeId)) {
1379617a3babSopenharmony_ci            assert(isConstantScalar(accessChain.indexChain[i]));
1380617a3babSopenharmony_ci            typeId = getContainedTypeId(typeId, getConstantScalar(accessChain.indexChain[i]));
1381617a3babSopenharmony_ci        } else
1382617a3babSopenharmony_ci            typeId = getContainedTypeId(typeId, accessChain.indexChain[i]);
1383617a3babSopenharmony_ci    }
1384617a3babSopenharmony_ci
1385617a3babSopenharmony_ci    return typeId;
1386617a3babSopenharmony_ci}
1387617a3babSopenharmony_ci
1388617a3babSopenharmony_ci// Return the immediately contained type of a given composite type.
1389617a3babSopenharmony_ciId Builder::getContainedTypeId(Id typeId) const
1390617a3babSopenharmony_ci{
1391617a3babSopenharmony_ci    return getContainedTypeId(typeId, 0);
1392617a3babSopenharmony_ci}
1393617a3babSopenharmony_ci
1394617a3babSopenharmony_ci// Returns true if 'typeId' is or contains a scalar type declared with 'typeOp'
1395617a3babSopenharmony_ci// of width 'width'. The 'width' is only consumed for int and float types.
1396617a3babSopenharmony_ci// Returns false otherwise.
1397617a3babSopenharmony_cibool Builder::containsType(Id typeId, spv::Op typeOp, unsigned int width) const
1398617a3babSopenharmony_ci{
1399617a3babSopenharmony_ci    const Instruction& instr = *module.getInstruction(typeId);
1400617a3babSopenharmony_ci
1401617a3babSopenharmony_ci    Op typeClass = instr.getOpCode();
1402617a3babSopenharmony_ci    switch (typeClass)
1403617a3babSopenharmony_ci    {
1404617a3babSopenharmony_ci    case OpTypeInt:
1405617a3babSopenharmony_ci    case OpTypeFloat:
1406617a3babSopenharmony_ci        return typeClass == typeOp && instr.getImmediateOperand(0) == width;
1407617a3babSopenharmony_ci    case OpTypeStruct:
1408617a3babSopenharmony_ci        for (int m = 0; m < instr.getNumOperands(); ++m) {
1409617a3babSopenharmony_ci            if (containsType(instr.getIdOperand(m), typeOp, width))
1410617a3babSopenharmony_ci                return true;
1411617a3babSopenharmony_ci        }
1412617a3babSopenharmony_ci        return false;
1413617a3babSopenharmony_ci    case OpTypePointer:
1414617a3babSopenharmony_ci        return false;
1415617a3babSopenharmony_ci    case OpTypeVector:
1416617a3babSopenharmony_ci    case OpTypeMatrix:
1417617a3babSopenharmony_ci    case OpTypeArray:
1418617a3babSopenharmony_ci    case OpTypeRuntimeArray:
1419617a3babSopenharmony_ci        return containsType(getContainedTypeId(typeId), typeOp, width);
1420617a3babSopenharmony_ci    default:
1421617a3babSopenharmony_ci        return typeClass == typeOp;
1422617a3babSopenharmony_ci    }
1423617a3babSopenharmony_ci}
1424617a3babSopenharmony_ci
1425617a3babSopenharmony_ci// return true if the type is a pointer to PhysicalStorageBufferEXT or an
1426617a3babSopenharmony_ci// contains such a pointer. These require restrict/aliased decorations.
1427617a3babSopenharmony_cibool Builder::containsPhysicalStorageBufferOrArray(Id typeId) const
1428617a3babSopenharmony_ci{
1429617a3babSopenharmony_ci    const Instruction& instr = *module.getInstruction(typeId);
1430617a3babSopenharmony_ci
1431617a3babSopenharmony_ci    Op typeClass = instr.getOpCode();
1432617a3babSopenharmony_ci    switch (typeClass)
1433617a3babSopenharmony_ci    {
1434617a3babSopenharmony_ci    case OpTypePointer:
1435617a3babSopenharmony_ci        return getTypeStorageClass(typeId) == StorageClassPhysicalStorageBufferEXT;
1436617a3babSopenharmony_ci    case OpTypeArray:
1437617a3babSopenharmony_ci        return containsPhysicalStorageBufferOrArray(getContainedTypeId(typeId));
1438617a3babSopenharmony_ci    case OpTypeStruct:
1439617a3babSopenharmony_ci        for (int m = 0; m < instr.getNumOperands(); ++m) {
1440617a3babSopenharmony_ci            if (containsPhysicalStorageBufferOrArray(instr.getIdOperand(m)))
1441617a3babSopenharmony_ci                return true;
1442617a3babSopenharmony_ci        }
1443617a3babSopenharmony_ci        return false;
1444617a3babSopenharmony_ci    default:
1445617a3babSopenharmony_ci        return false;
1446617a3babSopenharmony_ci    }
1447617a3babSopenharmony_ci}
1448617a3babSopenharmony_ci
1449617a3babSopenharmony_ci// See if a scalar constant of this type has already been created, so it
1450617a3babSopenharmony_ci// can be reused rather than duplicated.  (Required by the specification).
1451617a3babSopenharmony_ciId Builder::findScalarConstant(Op typeClass, Op opcode, Id typeId, unsigned value)
1452617a3babSopenharmony_ci{
1453617a3babSopenharmony_ci    Instruction* constant;
1454617a3babSopenharmony_ci    for (int i = 0; i < (int)groupedConstants[typeClass].size(); ++i) {
1455617a3babSopenharmony_ci        constant = groupedConstants[typeClass][i];
1456617a3babSopenharmony_ci        if (constant->getOpCode() == opcode &&
1457617a3babSopenharmony_ci            constant->getTypeId() == typeId &&
1458617a3babSopenharmony_ci            constant->getImmediateOperand(0) == value)
1459617a3babSopenharmony_ci            return constant->getResultId();
1460617a3babSopenharmony_ci    }
1461617a3babSopenharmony_ci
1462617a3babSopenharmony_ci    return 0;
1463617a3babSopenharmony_ci}
1464617a3babSopenharmony_ci
1465617a3babSopenharmony_ci// Version of findScalarConstant (see above) for scalars that take two operands (e.g. a 'double' or 'int64').
1466617a3babSopenharmony_ciId Builder::findScalarConstant(Op typeClass, Op opcode, Id typeId, unsigned v1, unsigned v2)
1467617a3babSopenharmony_ci{
1468617a3babSopenharmony_ci    Instruction* constant;
1469617a3babSopenharmony_ci    for (int i = 0; i < (int)groupedConstants[typeClass].size(); ++i) {
1470617a3babSopenharmony_ci        constant = groupedConstants[typeClass][i];
1471617a3babSopenharmony_ci        if (constant->getOpCode() == opcode &&
1472617a3babSopenharmony_ci            constant->getTypeId() == typeId &&
1473617a3babSopenharmony_ci            constant->getImmediateOperand(0) == v1 &&
1474617a3babSopenharmony_ci            constant->getImmediateOperand(1) == v2)
1475617a3babSopenharmony_ci            return constant->getResultId();
1476617a3babSopenharmony_ci    }
1477617a3babSopenharmony_ci
1478617a3babSopenharmony_ci    return 0;
1479617a3babSopenharmony_ci}
1480617a3babSopenharmony_ci
1481617a3babSopenharmony_ci// Return true if consuming 'opcode' means consuming a constant.
1482617a3babSopenharmony_ci// "constant" here means after final transform to executable code,
1483617a3babSopenharmony_ci// the value consumed will be a constant, so includes specialization.
1484617a3babSopenharmony_cibool Builder::isConstantOpCode(Op opcode) const
1485617a3babSopenharmony_ci{
1486617a3babSopenharmony_ci    switch (opcode) {
1487617a3babSopenharmony_ci    case OpUndef:
1488617a3babSopenharmony_ci    case OpConstantTrue:
1489617a3babSopenharmony_ci    case OpConstantFalse:
1490617a3babSopenharmony_ci    case OpConstant:
1491617a3babSopenharmony_ci    case OpConstantComposite:
1492617a3babSopenharmony_ci    case OpConstantSampler:
1493617a3babSopenharmony_ci    case OpConstantNull:
1494617a3babSopenharmony_ci    case OpSpecConstantTrue:
1495617a3babSopenharmony_ci    case OpSpecConstantFalse:
1496617a3babSopenharmony_ci    case OpSpecConstant:
1497617a3babSopenharmony_ci    case OpSpecConstantComposite:
1498617a3babSopenharmony_ci    case OpSpecConstantOp:
1499617a3babSopenharmony_ci        return true;
1500617a3babSopenharmony_ci    default:
1501617a3babSopenharmony_ci        return false;
1502617a3babSopenharmony_ci    }
1503617a3babSopenharmony_ci}
1504617a3babSopenharmony_ci
1505617a3babSopenharmony_ci// Return true if consuming 'opcode' means consuming a specialization constant.
1506617a3babSopenharmony_cibool Builder::isSpecConstantOpCode(Op opcode) const
1507617a3babSopenharmony_ci{
1508617a3babSopenharmony_ci    switch (opcode) {
1509617a3babSopenharmony_ci    case OpSpecConstantTrue:
1510617a3babSopenharmony_ci    case OpSpecConstantFalse:
1511617a3babSopenharmony_ci    case OpSpecConstant:
1512617a3babSopenharmony_ci    case OpSpecConstantComposite:
1513617a3babSopenharmony_ci    case OpSpecConstantOp:
1514617a3babSopenharmony_ci        return true;
1515617a3babSopenharmony_ci    default:
1516617a3babSopenharmony_ci        return false;
1517617a3babSopenharmony_ci    }
1518617a3babSopenharmony_ci}
1519617a3babSopenharmony_ci
1520617a3babSopenharmony_cibool Builder::isRayTracingOpCode(Op opcode) const
1521617a3babSopenharmony_ci{
1522617a3babSopenharmony_ci    switch (opcode) {
1523617a3babSopenharmony_ci    case OpTypeAccelerationStructureKHR:
1524617a3babSopenharmony_ci    case OpTypeRayQueryKHR:
1525617a3babSopenharmony_ci        return true;
1526617a3babSopenharmony_ci    default:
1527617a3babSopenharmony_ci        return false;
1528617a3babSopenharmony_ci    }
1529617a3babSopenharmony_ci}
1530617a3babSopenharmony_ci
1531617a3babSopenharmony_ciId Builder::makeNullConstant(Id typeId)
1532617a3babSopenharmony_ci{
1533617a3babSopenharmony_ci    Instruction* constant;
1534617a3babSopenharmony_ci
1535617a3babSopenharmony_ci    // See if we already made it.
1536617a3babSopenharmony_ci    Id existing = NoResult;
1537617a3babSopenharmony_ci    for (int i = 0; i < (int)nullConstants.size(); ++i) {
1538617a3babSopenharmony_ci        constant = nullConstants[i];
1539617a3babSopenharmony_ci        if (constant->getTypeId() == typeId)
1540617a3babSopenharmony_ci            existing = constant->getResultId();
1541617a3babSopenharmony_ci    }
1542617a3babSopenharmony_ci
1543617a3babSopenharmony_ci    if (existing != NoResult)
1544617a3babSopenharmony_ci        return existing;
1545617a3babSopenharmony_ci
1546617a3babSopenharmony_ci    // Make it
1547617a3babSopenharmony_ci    Instruction* c = new Instruction(getUniqueId(), typeId, OpConstantNull);
1548617a3babSopenharmony_ci    constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(c));
1549617a3babSopenharmony_ci    nullConstants.push_back(c);
1550617a3babSopenharmony_ci    module.mapInstruction(c);
1551617a3babSopenharmony_ci
1552617a3babSopenharmony_ci    return c->getResultId();
1553617a3babSopenharmony_ci}
1554617a3babSopenharmony_ci
1555617a3babSopenharmony_ciId Builder::makeBoolConstant(bool b, bool specConstant)
1556617a3babSopenharmony_ci{
1557617a3babSopenharmony_ci    Id typeId = makeBoolType();
1558617a3babSopenharmony_ci    Instruction* constant;
1559617a3babSopenharmony_ci    Op opcode = specConstant ? (b ? OpSpecConstantTrue : OpSpecConstantFalse) : (b ? OpConstantTrue : OpConstantFalse);
1560617a3babSopenharmony_ci
1561617a3babSopenharmony_ci    // See if we already made it. Applies only to regular constants, because specialization constants
1562617a3babSopenharmony_ci    // must remain distinct for the purpose of applying a SpecId decoration.
1563617a3babSopenharmony_ci    if (! specConstant) {
1564617a3babSopenharmony_ci        Id existing = 0;
1565617a3babSopenharmony_ci        for (int i = 0; i < (int)groupedConstants[OpTypeBool].size(); ++i) {
1566617a3babSopenharmony_ci            constant = groupedConstants[OpTypeBool][i];
1567617a3babSopenharmony_ci            if (constant->getTypeId() == typeId && constant->getOpCode() == opcode)
1568617a3babSopenharmony_ci                existing = constant->getResultId();
1569617a3babSopenharmony_ci        }
1570617a3babSopenharmony_ci
1571617a3babSopenharmony_ci        if (existing)
1572617a3babSopenharmony_ci            return existing;
1573617a3babSopenharmony_ci    }
1574617a3babSopenharmony_ci
1575617a3babSopenharmony_ci    // Make it
1576617a3babSopenharmony_ci    Instruction* c = new Instruction(getUniqueId(), typeId, opcode);
1577617a3babSopenharmony_ci    constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(c));
1578617a3babSopenharmony_ci    groupedConstants[OpTypeBool].push_back(c);
1579617a3babSopenharmony_ci    module.mapInstruction(c);
1580617a3babSopenharmony_ci
1581617a3babSopenharmony_ci    return c->getResultId();
1582617a3babSopenharmony_ci}
1583617a3babSopenharmony_ci
1584617a3babSopenharmony_ciId Builder::makeIntConstant(Id typeId, unsigned value, bool specConstant)
1585617a3babSopenharmony_ci{
1586617a3babSopenharmony_ci    Op opcode = specConstant ? OpSpecConstant : OpConstant;
1587617a3babSopenharmony_ci
1588617a3babSopenharmony_ci    // See if we already made it. Applies only to regular constants, because specialization constants
1589617a3babSopenharmony_ci    // must remain distinct for the purpose of applying a SpecId decoration.
1590617a3babSopenharmony_ci    if (! specConstant) {
1591617a3babSopenharmony_ci        Id existing = findScalarConstant(OpTypeInt, opcode, typeId, value);
1592617a3babSopenharmony_ci        if (existing)
1593617a3babSopenharmony_ci            return existing;
1594617a3babSopenharmony_ci    }
1595617a3babSopenharmony_ci
1596617a3babSopenharmony_ci    Instruction* c = new Instruction(getUniqueId(), typeId, opcode);
1597617a3babSopenharmony_ci    c->addImmediateOperand(value);
1598617a3babSopenharmony_ci    constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(c));
1599617a3babSopenharmony_ci    groupedConstants[OpTypeInt].push_back(c);
1600617a3babSopenharmony_ci    module.mapInstruction(c);
1601617a3babSopenharmony_ci
1602617a3babSopenharmony_ci    return c->getResultId();
1603617a3babSopenharmony_ci}
1604617a3babSopenharmony_ci
1605617a3babSopenharmony_ciId Builder::makeInt64Constant(Id typeId, unsigned long long value, bool specConstant)
1606617a3babSopenharmony_ci{
1607617a3babSopenharmony_ci    Op opcode = specConstant ? OpSpecConstant : OpConstant;
1608617a3babSopenharmony_ci
1609617a3babSopenharmony_ci    unsigned op1 = value & 0xFFFFFFFF;
1610617a3babSopenharmony_ci    unsigned op2 = value >> 32;
1611617a3babSopenharmony_ci
1612617a3babSopenharmony_ci    // See if we already made it. Applies only to regular constants, because specialization constants
1613617a3babSopenharmony_ci    // must remain distinct for the purpose of applying a SpecId decoration.
1614617a3babSopenharmony_ci    if (! specConstant) {
1615617a3babSopenharmony_ci        Id existing = findScalarConstant(OpTypeInt, opcode, typeId, op1, op2);
1616617a3babSopenharmony_ci        if (existing)
1617617a3babSopenharmony_ci            return existing;
1618617a3babSopenharmony_ci    }
1619617a3babSopenharmony_ci
1620617a3babSopenharmony_ci    Instruction* c = new Instruction(getUniqueId(), typeId, opcode);
1621617a3babSopenharmony_ci    c->addImmediateOperand(op1);
1622617a3babSopenharmony_ci    c->addImmediateOperand(op2);
1623617a3babSopenharmony_ci    constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(c));
1624617a3babSopenharmony_ci    groupedConstants[OpTypeInt].push_back(c);
1625617a3babSopenharmony_ci    module.mapInstruction(c);
1626617a3babSopenharmony_ci
1627617a3babSopenharmony_ci    return c->getResultId();
1628617a3babSopenharmony_ci}
1629617a3babSopenharmony_ci
1630617a3babSopenharmony_ciId Builder::makeFloatConstant(float f, bool specConstant)
1631617a3babSopenharmony_ci{
1632617a3babSopenharmony_ci    Op opcode = specConstant ? OpSpecConstant : OpConstant;
1633617a3babSopenharmony_ci    Id typeId = makeFloatType(32);
1634617a3babSopenharmony_ci    union { float fl; unsigned int ui; } u;
1635617a3babSopenharmony_ci    u.fl = f;
1636617a3babSopenharmony_ci    unsigned value = u.ui;
1637617a3babSopenharmony_ci
1638617a3babSopenharmony_ci    // See if we already made it. Applies only to regular constants, because specialization constants
1639617a3babSopenharmony_ci    // must remain distinct for the purpose of applying a SpecId decoration.
1640617a3babSopenharmony_ci    if (! specConstant) {
1641617a3babSopenharmony_ci        Id existing = findScalarConstant(OpTypeFloat, opcode, typeId, value);
1642617a3babSopenharmony_ci        if (existing)
1643617a3babSopenharmony_ci            return existing;
1644617a3babSopenharmony_ci    }
1645617a3babSopenharmony_ci
1646617a3babSopenharmony_ci    Instruction* c = new Instruction(getUniqueId(), typeId, opcode);
1647617a3babSopenharmony_ci    c->addImmediateOperand(value);
1648617a3babSopenharmony_ci    constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(c));
1649617a3babSopenharmony_ci    groupedConstants[OpTypeFloat].push_back(c);
1650617a3babSopenharmony_ci    module.mapInstruction(c);
1651617a3babSopenharmony_ci
1652617a3babSopenharmony_ci    return c->getResultId();
1653617a3babSopenharmony_ci}
1654617a3babSopenharmony_ci
1655617a3babSopenharmony_ciId Builder::makeDoubleConstant(double d, bool specConstant)
1656617a3babSopenharmony_ci{
1657617a3babSopenharmony_ci    Op opcode = specConstant ? OpSpecConstant : OpConstant;
1658617a3babSopenharmony_ci    Id typeId = makeFloatType(64);
1659617a3babSopenharmony_ci    union { double db; unsigned long long ull; } u;
1660617a3babSopenharmony_ci    u.db = d;
1661617a3babSopenharmony_ci    unsigned long long value = u.ull;
1662617a3babSopenharmony_ci    unsigned op1 = value & 0xFFFFFFFF;
1663617a3babSopenharmony_ci    unsigned op2 = value >> 32;
1664617a3babSopenharmony_ci
1665617a3babSopenharmony_ci    // See if we already made it. Applies only to regular constants, because specialization constants
1666617a3babSopenharmony_ci    // must remain distinct for the purpose of applying a SpecId decoration.
1667617a3babSopenharmony_ci    if (! specConstant) {
1668617a3babSopenharmony_ci        Id existing = findScalarConstant(OpTypeFloat, opcode, typeId, op1, op2);
1669617a3babSopenharmony_ci        if (existing)
1670617a3babSopenharmony_ci            return existing;
1671617a3babSopenharmony_ci    }
1672617a3babSopenharmony_ci
1673617a3babSopenharmony_ci    Instruction* c = new Instruction(getUniqueId(), typeId, opcode);
1674617a3babSopenharmony_ci    c->addImmediateOperand(op1);
1675617a3babSopenharmony_ci    c->addImmediateOperand(op2);
1676617a3babSopenharmony_ci    constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(c));
1677617a3babSopenharmony_ci    groupedConstants[OpTypeFloat].push_back(c);
1678617a3babSopenharmony_ci    module.mapInstruction(c);
1679617a3babSopenharmony_ci
1680617a3babSopenharmony_ci    return c->getResultId();
1681617a3babSopenharmony_ci}
1682617a3babSopenharmony_ci
1683617a3babSopenharmony_ciId Builder::makeFloat16Constant(float f16, bool specConstant)
1684617a3babSopenharmony_ci{
1685617a3babSopenharmony_ci    Op opcode = specConstant ? OpSpecConstant : OpConstant;
1686617a3babSopenharmony_ci    Id typeId = makeFloatType(16);
1687617a3babSopenharmony_ci
1688617a3babSopenharmony_ci    spvutils::HexFloat<spvutils::FloatProxy<float>> fVal(f16);
1689617a3babSopenharmony_ci    spvutils::HexFloat<spvutils::FloatProxy<spvutils::Float16>> f16Val(0);
1690617a3babSopenharmony_ci    fVal.castTo(f16Val, spvutils::kRoundToZero);
1691617a3babSopenharmony_ci
1692617a3babSopenharmony_ci    unsigned value = f16Val.value().getAsFloat().get_value();
1693617a3babSopenharmony_ci
1694617a3babSopenharmony_ci    // See if we already made it. Applies only to regular constants, because specialization constants
1695617a3babSopenharmony_ci    // must remain distinct for the purpose of applying a SpecId decoration.
1696617a3babSopenharmony_ci    if (!specConstant) {
1697617a3babSopenharmony_ci        Id existing = findScalarConstant(OpTypeFloat, opcode, typeId, value);
1698617a3babSopenharmony_ci        if (existing)
1699617a3babSopenharmony_ci            return existing;
1700617a3babSopenharmony_ci    }
1701617a3babSopenharmony_ci
1702617a3babSopenharmony_ci    Instruction* c = new Instruction(getUniqueId(), typeId, opcode);
1703617a3babSopenharmony_ci    c->addImmediateOperand(value);
1704617a3babSopenharmony_ci    constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(c));
1705617a3babSopenharmony_ci    groupedConstants[OpTypeFloat].push_back(c);
1706617a3babSopenharmony_ci    module.mapInstruction(c);
1707617a3babSopenharmony_ci
1708617a3babSopenharmony_ci    return c->getResultId();
1709617a3babSopenharmony_ci}
1710617a3babSopenharmony_ci
1711617a3babSopenharmony_ciId Builder::makeFpConstant(Id type, double d, bool specConstant)
1712617a3babSopenharmony_ci{
1713617a3babSopenharmony_ci    const int width = getScalarTypeWidth(type);
1714617a3babSopenharmony_ci
1715617a3babSopenharmony_ci    assert(isFloatType(type));
1716617a3babSopenharmony_ci
1717617a3babSopenharmony_ci    switch (width) {
1718617a3babSopenharmony_ci    case 16:
1719617a3babSopenharmony_ci            return makeFloat16Constant((float)d, specConstant);
1720617a3babSopenharmony_ci    case 32:
1721617a3babSopenharmony_ci            return makeFloatConstant((float)d, specConstant);
1722617a3babSopenharmony_ci    case 64:
1723617a3babSopenharmony_ci            return makeDoubleConstant(d, specConstant);
1724617a3babSopenharmony_ci    default:
1725617a3babSopenharmony_ci            break;
1726617a3babSopenharmony_ci    }
1727617a3babSopenharmony_ci
1728617a3babSopenharmony_ci    assert(false);
1729617a3babSopenharmony_ci    return NoResult;
1730617a3babSopenharmony_ci}
1731617a3babSopenharmony_ci
1732617a3babSopenharmony_ciId Builder::importNonSemanticShaderDebugInfoInstructions()
1733617a3babSopenharmony_ci{
1734617a3babSopenharmony_ci    assert(emitNonSemanticShaderDebugInfo == true);
1735617a3babSopenharmony_ci
1736617a3babSopenharmony_ci    if(nonSemanticShaderDebugInfo == 0)
1737617a3babSopenharmony_ci    {
1738617a3babSopenharmony_ci        this->addExtension(spv::E_SPV_KHR_non_semantic_info);
1739617a3babSopenharmony_ci        nonSemanticShaderDebugInfo = this->import("NonSemantic.Shader.DebugInfo.100");
1740617a3babSopenharmony_ci    }
1741617a3babSopenharmony_ci
1742617a3babSopenharmony_ci    return nonSemanticShaderDebugInfo;
1743617a3babSopenharmony_ci}
1744617a3babSopenharmony_ci
1745617a3babSopenharmony_ciId Builder::findCompositeConstant(Op typeClass, Id typeId, const std::vector<Id>& comps)
1746617a3babSopenharmony_ci{
1747617a3babSopenharmony_ci    Instruction* constant = nullptr;
1748617a3babSopenharmony_ci    bool found = false;
1749617a3babSopenharmony_ci    for (int i = 0; i < (int)groupedConstants[typeClass].size(); ++i) {
1750617a3babSopenharmony_ci        constant = groupedConstants[typeClass][i];
1751617a3babSopenharmony_ci
1752617a3babSopenharmony_ci        if (constant->getTypeId() != typeId)
1753617a3babSopenharmony_ci            continue;
1754617a3babSopenharmony_ci
1755617a3babSopenharmony_ci        // same contents?
1756617a3babSopenharmony_ci        bool mismatch = false;
1757617a3babSopenharmony_ci        for (int op = 0; op < constant->getNumOperands(); ++op) {
1758617a3babSopenharmony_ci            if (constant->getIdOperand(op) != comps[op]) {
1759617a3babSopenharmony_ci                mismatch = true;
1760617a3babSopenharmony_ci                break;
1761617a3babSopenharmony_ci            }
1762617a3babSopenharmony_ci        }
1763617a3babSopenharmony_ci        if (! mismatch) {
1764617a3babSopenharmony_ci            found = true;
1765617a3babSopenharmony_ci            break;
1766617a3babSopenharmony_ci        }
1767617a3babSopenharmony_ci    }
1768617a3babSopenharmony_ci
1769617a3babSopenharmony_ci    return found ? constant->getResultId() : NoResult;
1770617a3babSopenharmony_ci}
1771617a3babSopenharmony_ci
1772617a3babSopenharmony_ciId Builder::findStructConstant(Id typeId, const std::vector<Id>& comps)
1773617a3babSopenharmony_ci{
1774617a3babSopenharmony_ci    Instruction* constant = nullptr;
1775617a3babSopenharmony_ci    bool found = false;
1776617a3babSopenharmony_ci    for (int i = 0; i < (int)groupedStructConstants[typeId].size(); ++i) {
1777617a3babSopenharmony_ci        constant = groupedStructConstants[typeId][i];
1778617a3babSopenharmony_ci
1779617a3babSopenharmony_ci        // same contents?
1780617a3babSopenharmony_ci        bool mismatch = false;
1781617a3babSopenharmony_ci        for (int op = 0; op < constant->getNumOperands(); ++op) {
1782617a3babSopenharmony_ci            if (constant->getIdOperand(op) != comps[op]) {
1783617a3babSopenharmony_ci                mismatch = true;
1784617a3babSopenharmony_ci                break;
1785617a3babSopenharmony_ci            }
1786617a3babSopenharmony_ci        }
1787617a3babSopenharmony_ci        if (! mismatch) {
1788617a3babSopenharmony_ci            found = true;
1789617a3babSopenharmony_ci            break;
1790617a3babSopenharmony_ci        }
1791617a3babSopenharmony_ci    }
1792617a3babSopenharmony_ci
1793617a3babSopenharmony_ci    return found ? constant->getResultId() : NoResult;
1794617a3babSopenharmony_ci}
1795617a3babSopenharmony_ci
1796617a3babSopenharmony_ci// Comments in header
1797617a3babSopenharmony_ciId Builder::makeCompositeConstant(Id typeId, const std::vector<Id>& members, bool specConstant)
1798617a3babSopenharmony_ci{
1799617a3babSopenharmony_ci    Op opcode = specConstant ? OpSpecConstantComposite : OpConstantComposite;
1800617a3babSopenharmony_ci    assert(typeId);
1801617a3babSopenharmony_ci    Op typeClass = getTypeClass(typeId);
1802617a3babSopenharmony_ci
1803617a3babSopenharmony_ci    switch (typeClass) {
1804617a3babSopenharmony_ci    case OpTypeVector:
1805617a3babSopenharmony_ci    case OpTypeArray:
1806617a3babSopenharmony_ci    case OpTypeMatrix:
1807617a3babSopenharmony_ci    case OpTypeCooperativeMatrixKHR:
1808617a3babSopenharmony_ci    case OpTypeCooperativeMatrixNV:
1809617a3babSopenharmony_ci        if (! specConstant) {
1810617a3babSopenharmony_ci            Id existing = findCompositeConstant(typeClass, typeId, members);
1811617a3babSopenharmony_ci            if (existing)
1812617a3babSopenharmony_ci                return existing;
1813617a3babSopenharmony_ci        }
1814617a3babSopenharmony_ci        break;
1815617a3babSopenharmony_ci    case OpTypeStruct:
1816617a3babSopenharmony_ci        if (! specConstant) {
1817617a3babSopenharmony_ci            Id existing = findStructConstant(typeId, members);
1818617a3babSopenharmony_ci            if (existing)
1819617a3babSopenharmony_ci                return existing;
1820617a3babSopenharmony_ci        }
1821617a3babSopenharmony_ci        break;
1822617a3babSopenharmony_ci    default:
1823617a3babSopenharmony_ci        assert(0);
1824617a3babSopenharmony_ci        return makeFloatConstant(0.0);
1825617a3babSopenharmony_ci    }
1826617a3babSopenharmony_ci
1827617a3babSopenharmony_ci    Instruction* c = new Instruction(getUniqueId(), typeId, opcode);
1828617a3babSopenharmony_ci    for (int op = 0; op < (int)members.size(); ++op)
1829617a3babSopenharmony_ci        c->addIdOperand(members[op]);
1830617a3babSopenharmony_ci    constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(c));
1831617a3babSopenharmony_ci    if (typeClass == OpTypeStruct)
1832617a3babSopenharmony_ci        groupedStructConstants[typeId].push_back(c);
1833617a3babSopenharmony_ci    else
1834617a3babSopenharmony_ci        groupedConstants[typeClass].push_back(c);
1835617a3babSopenharmony_ci    module.mapInstruction(c);
1836617a3babSopenharmony_ci
1837617a3babSopenharmony_ci    return c->getResultId();
1838617a3babSopenharmony_ci}
1839617a3babSopenharmony_ci
1840617a3babSopenharmony_ciInstruction* Builder::addEntryPoint(ExecutionModel model, Function* function, const char* name)
1841617a3babSopenharmony_ci{
1842617a3babSopenharmony_ci    Instruction* entryPoint = new Instruction(OpEntryPoint);
1843617a3babSopenharmony_ci    entryPoint->addImmediateOperand(model);
1844617a3babSopenharmony_ci    entryPoint->addIdOperand(function->getId());
1845617a3babSopenharmony_ci    entryPoint->addStringOperand(name);
1846617a3babSopenharmony_ci
1847617a3babSopenharmony_ci    entryPoints.push_back(std::unique_ptr<Instruction>(entryPoint));
1848617a3babSopenharmony_ci
1849617a3babSopenharmony_ci    return entryPoint;
1850617a3babSopenharmony_ci}
1851617a3babSopenharmony_ci
1852617a3babSopenharmony_ci// Currently relying on the fact that all 'value' of interest are small non-negative values.
1853617a3babSopenharmony_civoid Builder::addExecutionMode(Function* entryPoint, ExecutionMode mode, int value1, int value2, int value3)
1854617a3babSopenharmony_ci{
1855617a3babSopenharmony_ci    // entryPoint can be null if we are in compile-only mode
1856617a3babSopenharmony_ci    if (!entryPoint)
1857617a3babSopenharmony_ci        return;
1858617a3babSopenharmony_ci
1859617a3babSopenharmony_ci    Instruction* instr = new Instruction(OpExecutionMode);
1860617a3babSopenharmony_ci    instr->addIdOperand(entryPoint->getId());
1861617a3babSopenharmony_ci    instr->addImmediateOperand(mode);
1862617a3babSopenharmony_ci    if (value1 >= 0)
1863617a3babSopenharmony_ci        instr->addImmediateOperand(value1);
1864617a3babSopenharmony_ci    if (value2 >= 0)
1865617a3babSopenharmony_ci        instr->addImmediateOperand(value2);
1866617a3babSopenharmony_ci    if (value3 >= 0)
1867617a3babSopenharmony_ci        instr->addImmediateOperand(value3);
1868617a3babSopenharmony_ci
1869617a3babSopenharmony_ci    executionModes.push_back(std::unique_ptr<Instruction>(instr));
1870617a3babSopenharmony_ci}
1871617a3babSopenharmony_ci
1872617a3babSopenharmony_civoid Builder::addExecutionMode(Function* entryPoint, ExecutionMode mode, const std::vector<unsigned>& literals)
1873617a3babSopenharmony_ci{
1874617a3babSopenharmony_ci    // entryPoint can be null if we are in compile-only mode
1875617a3babSopenharmony_ci    if (!entryPoint)
1876617a3babSopenharmony_ci        return;
1877617a3babSopenharmony_ci
1878617a3babSopenharmony_ci    Instruction* instr = new Instruction(OpExecutionMode);
1879617a3babSopenharmony_ci    instr->addIdOperand(entryPoint->getId());
1880617a3babSopenharmony_ci    instr->addImmediateOperand(mode);
1881617a3babSopenharmony_ci    for (auto literal : literals)
1882617a3babSopenharmony_ci        instr->addImmediateOperand(literal);
1883617a3babSopenharmony_ci
1884617a3babSopenharmony_ci    executionModes.push_back(std::unique_ptr<Instruction>(instr));
1885617a3babSopenharmony_ci}
1886617a3babSopenharmony_ci
1887617a3babSopenharmony_civoid Builder::addExecutionModeId(Function* entryPoint, ExecutionMode mode, const std::vector<Id>& operandIds)
1888617a3babSopenharmony_ci{
1889617a3babSopenharmony_ci    // entryPoint can be null if we are in compile-only mode
1890617a3babSopenharmony_ci    if (!entryPoint)
1891617a3babSopenharmony_ci        return;
1892617a3babSopenharmony_ci
1893617a3babSopenharmony_ci    Instruction* instr = new Instruction(OpExecutionModeId);
1894617a3babSopenharmony_ci    instr->addIdOperand(entryPoint->getId());
1895617a3babSopenharmony_ci    instr->addImmediateOperand(mode);
1896617a3babSopenharmony_ci    for (auto operandId : operandIds)
1897617a3babSopenharmony_ci        instr->addIdOperand(operandId);
1898617a3babSopenharmony_ci
1899617a3babSopenharmony_ci    executionModes.push_back(std::unique_ptr<Instruction>(instr));
1900617a3babSopenharmony_ci}
1901617a3babSopenharmony_ci
1902617a3babSopenharmony_civoid Builder::addName(Id id, const char* string)
1903617a3babSopenharmony_ci{
1904617a3babSopenharmony_ci    Instruction* name = new Instruction(OpName);
1905617a3babSopenharmony_ci    name->addIdOperand(id);
1906617a3babSopenharmony_ci    name->addStringOperand(string);
1907617a3babSopenharmony_ci
1908617a3babSopenharmony_ci    names.push_back(std::unique_ptr<Instruction>(name));
1909617a3babSopenharmony_ci}
1910617a3babSopenharmony_ci
1911617a3babSopenharmony_civoid Builder::addMemberName(Id id, int memberNumber, const char* string)
1912617a3babSopenharmony_ci{
1913617a3babSopenharmony_ci    Instruction* name = new Instruction(OpMemberName);
1914617a3babSopenharmony_ci    name->addIdOperand(id);
1915617a3babSopenharmony_ci    name->addImmediateOperand(memberNumber);
1916617a3babSopenharmony_ci    name->addStringOperand(string);
1917617a3babSopenharmony_ci
1918617a3babSopenharmony_ci    names.push_back(std::unique_ptr<Instruction>(name));
1919617a3babSopenharmony_ci}
1920617a3babSopenharmony_ci
1921617a3babSopenharmony_civoid Builder::addDecoration(Id id, Decoration decoration, int num)
1922617a3babSopenharmony_ci{
1923617a3babSopenharmony_ci    if (decoration == spv::DecorationMax)
1924617a3babSopenharmony_ci        return;
1925617a3babSopenharmony_ci
1926617a3babSopenharmony_ci    Instruction* dec = new Instruction(OpDecorate);
1927617a3babSopenharmony_ci    dec->addIdOperand(id);
1928617a3babSopenharmony_ci    dec->addImmediateOperand(decoration);
1929617a3babSopenharmony_ci    if (num >= 0)
1930617a3babSopenharmony_ci        dec->addImmediateOperand(num);
1931617a3babSopenharmony_ci
1932617a3babSopenharmony_ci    decorations.push_back(std::unique_ptr<Instruction>(dec));
1933617a3babSopenharmony_ci}
1934617a3babSopenharmony_ci
1935617a3babSopenharmony_civoid Builder::addDecoration(Id id, Decoration decoration, const char* s)
1936617a3babSopenharmony_ci{
1937617a3babSopenharmony_ci    if (decoration == spv::DecorationMax)
1938617a3babSopenharmony_ci        return;
1939617a3babSopenharmony_ci
1940617a3babSopenharmony_ci    Instruction* dec = new Instruction(OpDecorateString);
1941617a3babSopenharmony_ci    dec->addIdOperand(id);
1942617a3babSopenharmony_ci    dec->addImmediateOperand(decoration);
1943617a3babSopenharmony_ci    dec->addStringOperand(s);
1944617a3babSopenharmony_ci
1945617a3babSopenharmony_ci    decorations.push_back(std::unique_ptr<Instruction>(dec));
1946617a3babSopenharmony_ci}
1947617a3babSopenharmony_ci
1948617a3babSopenharmony_civoid Builder::addDecoration(Id id, Decoration decoration, const std::vector<unsigned>& literals)
1949617a3babSopenharmony_ci{
1950617a3babSopenharmony_ci    if (decoration == spv::DecorationMax)
1951617a3babSopenharmony_ci        return;
1952617a3babSopenharmony_ci
1953617a3babSopenharmony_ci    Instruction* dec = new Instruction(OpDecorate);
1954617a3babSopenharmony_ci    dec->addIdOperand(id);
1955617a3babSopenharmony_ci    dec->addImmediateOperand(decoration);
1956617a3babSopenharmony_ci    for (auto literal : literals)
1957617a3babSopenharmony_ci        dec->addImmediateOperand(literal);
1958617a3babSopenharmony_ci
1959617a3babSopenharmony_ci    decorations.push_back(std::unique_ptr<Instruction>(dec));
1960617a3babSopenharmony_ci}
1961617a3babSopenharmony_ci
1962617a3babSopenharmony_civoid Builder::addDecoration(Id id, Decoration decoration, const std::vector<const char*>& strings)
1963617a3babSopenharmony_ci{
1964617a3babSopenharmony_ci    if (decoration == spv::DecorationMax)
1965617a3babSopenharmony_ci        return;
1966617a3babSopenharmony_ci
1967617a3babSopenharmony_ci    Instruction* dec = new Instruction(OpDecorateString);
1968617a3babSopenharmony_ci    dec->addIdOperand(id);
1969617a3babSopenharmony_ci    dec->addImmediateOperand(decoration);
1970617a3babSopenharmony_ci    for (auto string : strings)
1971617a3babSopenharmony_ci        dec->addStringOperand(string);
1972617a3babSopenharmony_ci
1973617a3babSopenharmony_ci    decorations.push_back(std::unique_ptr<Instruction>(dec));
1974617a3babSopenharmony_ci}
1975617a3babSopenharmony_ci
1976617a3babSopenharmony_civoid Builder::addLinkageDecoration(Id id, const char* name, spv::LinkageType linkType) {
1977617a3babSopenharmony_ci    Instruction* dec = new Instruction(OpDecorate);
1978617a3babSopenharmony_ci    dec->addIdOperand(id);
1979617a3babSopenharmony_ci    dec->addImmediateOperand(spv::DecorationLinkageAttributes);
1980617a3babSopenharmony_ci    dec->addStringOperand(name);
1981617a3babSopenharmony_ci    dec->addImmediateOperand(linkType);
1982617a3babSopenharmony_ci
1983617a3babSopenharmony_ci    decorations.push_back(std::unique_ptr<Instruction>(dec));
1984617a3babSopenharmony_ci}
1985617a3babSopenharmony_ci
1986617a3babSopenharmony_civoid Builder::addDecorationId(Id id, Decoration decoration, Id idDecoration)
1987617a3babSopenharmony_ci{
1988617a3babSopenharmony_ci    if (decoration == spv::DecorationMax)
1989617a3babSopenharmony_ci        return;
1990617a3babSopenharmony_ci
1991617a3babSopenharmony_ci    Instruction* dec = new Instruction(OpDecorateId);
1992617a3babSopenharmony_ci    dec->addIdOperand(id);
1993617a3babSopenharmony_ci    dec->addImmediateOperand(decoration);
1994617a3babSopenharmony_ci    dec->addIdOperand(idDecoration);
1995617a3babSopenharmony_ci
1996617a3babSopenharmony_ci    decorations.push_back(std::unique_ptr<Instruction>(dec));
1997617a3babSopenharmony_ci}
1998617a3babSopenharmony_ci
1999617a3babSopenharmony_civoid Builder::addDecorationId(Id id, Decoration decoration, const std::vector<Id>& operandIds)
2000617a3babSopenharmony_ci{
2001617a3babSopenharmony_ci    if(decoration == spv::DecorationMax)
2002617a3babSopenharmony_ci        return;
2003617a3babSopenharmony_ci
2004617a3babSopenharmony_ci    Instruction* dec = new Instruction(OpDecorateId);
2005617a3babSopenharmony_ci    dec->addIdOperand(id);
2006617a3babSopenharmony_ci    dec->addImmediateOperand(decoration);
2007617a3babSopenharmony_ci
2008617a3babSopenharmony_ci    for (auto operandId : operandIds)
2009617a3babSopenharmony_ci        dec->addIdOperand(operandId);
2010617a3babSopenharmony_ci
2011617a3babSopenharmony_ci    decorations.push_back(std::unique_ptr<Instruction>(dec));
2012617a3babSopenharmony_ci}
2013617a3babSopenharmony_ci
2014617a3babSopenharmony_civoid Builder::addMemberDecoration(Id id, unsigned int member, Decoration decoration, int num)
2015617a3babSopenharmony_ci{
2016617a3babSopenharmony_ci    if (decoration == spv::DecorationMax)
2017617a3babSopenharmony_ci        return;
2018617a3babSopenharmony_ci
2019617a3babSopenharmony_ci    Instruction* dec = new Instruction(OpMemberDecorate);
2020617a3babSopenharmony_ci    dec->addIdOperand(id);
2021617a3babSopenharmony_ci    dec->addImmediateOperand(member);
2022617a3babSopenharmony_ci    dec->addImmediateOperand(decoration);
2023617a3babSopenharmony_ci    if (num >= 0)
2024617a3babSopenharmony_ci        dec->addImmediateOperand(num);
2025617a3babSopenharmony_ci
2026617a3babSopenharmony_ci    decorations.push_back(std::unique_ptr<Instruction>(dec));
2027617a3babSopenharmony_ci}
2028617a3babSopenharmony_ci
2029617a3babSopenharmony_civoid Builder::addMemberDecoration(Id id, unsigned int member, Decoration decoration, const char *s)
2030617a3babSopenharmony_ci{
2031617a3babSopenharmony_ci    if (decoration == spv::DecorationMax)
2032617a3babSopenharmony_ci        return;
2033617a3babSopenharmony_ci
2034617a3babSopenharmony_ci    Instruction* dec = new Instruction(OpMemberDecorateStringGOOGLE);
2035617a3babSopenharmony_ci    dec->addIdOperand(id);
2036617a3babSopenharmony_ci    dec->addImmediateOperand(member);
2037617a3babSopenharmony_ci    dec->addImmediateOperand(decoration);
2038617a3babSopenharmony_ci    dec->addStringOperand(s);
2039617a3babSopenharmony_ci
2040617a3babSopenharmony_ci    decorations.push_back(std::unique_ptr<Instruction>(dec));
2041617a3babSopenharmony_ci}
2042617a3babSopenharmony_ci
2043617a3babSopenharmony_civoid Builder::addMemberDecoration(Id id, unsigned int member, Decoration decoration, const std::vector<unsigned>& literals)
2044617a3babSopenharmony_ci{
2045617a3babSopenharmony_ci    if (decoration == spv::DecorationMax)
2046617a3babSopenharmony_ci        return;
2047617a3babSopenharmony_ci
2048617a3babSopenharmony_ci    Instruction* dec = new Instruction(OpMemberDecorate);
2049617a3babSopenharmony_ci    dec->addIdOperand(id);
2050617a3babSopenharmony_ci    dec->addImmediateOperand(member);
2051617a3babSopenharmony_ci    dec->addImmediateOperand(decoration);
2052617a3babSopenharmony_ci    for (auto literal : literals)
2053617a3babSopenharmony_ci        dec->addImmediateOperand(literal);
2054617a3babSopenharmony_ci
2055617a3babSopenharmony_ci    decorations.push_back(std::unique_ptr<Instruction>(dec));
2056617a3babSopenharmony_ci}
2057617a3babSopenharmony_ci
2058617a3babSopenharmony_civoid Builder::addMemberDecoration(Id id, unsigned int member, Decoration decoration, const std::vector<const char*>& strings)
2059617a3babSopenharmony_ci{
2060617a3babSopenharmony_ci    if (decoration == spv::DecorationMax)
2061617a3babSopenharmony_ci        return;
2062617a3babSopenharmony_ci
2063617a3babSopenharmony_ci    Instruction* dec = new Instruction(OpMemberDecorateString);
2064617a3babSopenharmony_ci    dec->addIdOperand(id);
2065617a3babSopenharmony_ci    dec->addImmediateOperand(member);
2066617a3babSopenharmony_ci    dec->addImmediateOperand(decoration);
2067617a3babSopenharmony_ci    for (auto string : strings)
2068617a3babSopenharmony_ci        dec->addStringOperand(string);
2069617a3babSopenharmony_ci
2070617a3babSopenharmony_ci    decorations.push_back(std::unique_ptr<Instruction>(dec));
2071617a3babSopenharmony_ci}
2072617a3babSopenharmony_ci
2073617a3babSopenharmony_ci// Comments in header
2074617a3babSopenharmony_ciFunction* Builder::makeEntryPoint(const char* entryPoint)
2075617a3babSopenharmony_ci{
2076617a3babSopenharmony_ci    assert(! entryPointFunction);
2077617a3babSopenharmony_ci
2078617a3babSopenharmony_ci    auto const returnType = makeVoidType();
2079617a3babSopenharmony_ci
2080617a3babSopenharmony_ci    restoreNonSemanticShaderDebugInfo = emitNonSemanticShaderDebugInfo;
2081617a3babSopenharmony_ci    if(sourceLang == spv::SourceLanguageHLSL) {
2082617a3babSopenharmony_ci        emitNonSemanticShaderDebugInfo = false;
2083617a3babSopenharmony_ci    }
2084617a3babSopenharmony_ci
2085617a3babSopenharmony_ci    Block* entry = nullptr;
2086617a3babSopenharmony_ci    entryPointFunction = makeFunctionEntry(NoPrecision, returnType, entryPoint, LinkageTypeMax, {}, {}, &entry);
2087617a3babSopenharmony_ci
2088617a3babSopenharmony_ci    emitNonSemanticShaderDebugInfo = restoreNonSemanticShaderDebugInfo;
2089617a3babSopenharmony_ci
2090617a3babSopenharmony_ci    return entryPointFunction;
2091617a3babSopenharmony_ci}
2092617a3babSopenharmony_ci
2093617a3babSopenharmony_ci// Comments in header
2094617a3babSopenharmony_ciFunction* Builder::makeFunctionEntry(Decoration precision, Id returnType, const char* name, LinkageType linkType,
2095617a3babSopenharmony_ci                                     const std::vector<Id>& paramTypes,
2096617a3babSopenharmony_ci                                     const std::vector<std::vector<Decoration>>& decorations, Block** entry)
2097617a3babSopenharmony_ci{
2098617a3babSopenharmony_ci    // Make the function and initial instructions in it
2099617a3babSopenharmony_ci    Id typeId = makeFunctionType(returnType, paramTypes);
2100617a3babSopenharmony_ci    Id firstParamId = paramTypes.size() == 0 ? 0 : getUniqueIds((int)paramTypes.size());
2101617a3babSopenharmony_ci    Id funcId = getUniqueId();
2102617a3babSopenharmony_ci    Function* function = new Function(funcId, returnType, typeId, firstParamId, linkType, name, module);
2103617a3babSopenharmony_ci
2104617a3babSopenharmony_ci    // Set up the precisions
2105617a3babSopenharmony_ci    setPrecision(function->getId(), precision);
2106617a3babSopenharmony_ci    function->setReturnPrecision(precision);
2107617a3babSopenharmony_ci    for (unsigned p = 0; p < (unsigned)decorations.size(); ++p) {
2108617a3babSopenharmony_ci        for (int d = 0; d < (int)decorations[p].size(); ++d) {
2109617a3babSopenharmony_ci            addDecoration(firstParamId + p, decorations[p][d]);
2110617a3babSopenharmony_ci            function->addParamPrecision(p, decorations[p][d]);
2111617a3babSopenharmony_ci        }
2112617a3babSopenharmony_ci    }
2113617a3babSopenharmony_ci
2114617a3babSopenharmony_ci    // reset last debug scope
2115617a3babSopenharmony_ci    if (emitNonSemanticShaderDebugInfo) {
2116617a3babSopenharmony_ci        lastDebugScopeId = NoResult;
2117617a3babSopenharmony_ci    }
2118617a3babSopenharmony_ci
2119617a3babSopenharmony_ci    // CFG
2120617a3babSopenharmony_ci    assert(entry != nullptr);
2121617a3babSopenharmony_ci    *entry = new Block(getUniqueId(), *function);
2122617a3babSopenharmony_ci    function->addBlock(*entry);
2123617a3babSopenharmony_ci    setBuildPoint(*entry);
2124617a3babSopenharmony_ci
2125617a3babSopenharmony_ci    if (name)
2126617a3babSopenharmony_ci        addName(function->getId(), name);
2127617a3babSopenharmony_ci
2128617a3babSopenharmony_ci    functions.push_back(std::unique_ptr<Function>(function));
2129617a3babSopenharmony_ci
2130617a3babSopenharmony_ci    return function;
2131617a3babSopenharmony_ci}
2132617a3babSopenharmony_ci
2133617a3babSopenharmony_civoid Builder::setupDebugFunctionEntry(Function* function, const char* name, int line, const std::vector<Id>& paramTypes,
2134617a3babSopenharmony_ci                                      const std::vector<char const*>& paramNames)
2135617a3babSopenharmony_ci{
2136617a3babSopenharmony_ci
2137617a3babSopenharmony_ci    if (!emitNonSemanticShaderDebugInfo)
2138617a3babSopenharmony_ci        return;
2139617a3babSopenharmony_ci
2140617a3babSopenharmony_ci    currentLine = line;
2141617a3babSopenharmony_ci    Id nameId = getStringId(unmangleFunctionName(name));
2142617a3babSopenharmony_ci    Id funcTypeId = function->getFuncTypeId();
2143617a3babSopenharmony_ci    assert(debugId[funcTypeId] != 0);
2144617a3babSopenharmony_ci    Id funcId = function->getId();
2145617a3babSopenharmony_ci
2146617a3babSopenharmony_ci    assert(funcId != 0);
2147617a3babSopenharmony_ci
2148617a3babSopenharmony_ci    // Make the debug function instruction
2149617a3babSopenharmony_ci    Id debugFuncId = makeDebugFunction(function, nameId, funcTypeId);
2150617a3babSopenharmony_ci    debugId[funcId] = debugFuncId;
2151617a3babSopenharmony_ci    currentDebugScopeId.push(debugFuncId);
2152617a3babSopenharmony_ci
2153617a3babSopenharmony_ci    // DebugScope and DebugLine for parameter DebugDeclares
2154617a3babSopenharmony_ci    assert(paramTypes.size() == paramNames.size());
2155617a3babSopenharmony_ci    if ((int)paramTypes.size() > 0) {
2156617a3babSopenharmony_ci        addDebugScopeAndLine(currentFileId, currentLine, 0);
2157617a3babSopenharmony_ci
2158617a3babSopenharmony_ci        Id firstParamId = function->getParamId(0);
2159617a3babSopenharmony_ci
2160617a3babSopenharmony_ci        for (size_t p = 0; p < paramTypes.size(); ++p) {
2161617a3babSopenharmony_ci            bool passByRef = false;
2162617a3babSopenharmony_ci            Id paramTypeId = paramTypes[p];
2163617a3babSopenharmony_ci
2164617a3babSopenharmony_ci            // For pointer-typed parameters, they are actually passed by reference and we need unwrap the pointer to get the actual parameter type.
2165617a3babSopenharmony_ci            if (isPointerType(paramTypeId) || isArrayType(paramTypeId)) {
2166617a3babSopenharmony_ci                passByRef = true;
2167617a3babSopenharmony_ci                paramTypeId = getContainedTypeId(paramTypeId);
2168617a3babSopenharmony_ci            }
2169617a3babSopenharmony_ci
2170617a3babSopenharmony_ci            auto const& paramName = paramNames[p];
2171617a3babSopenharmony_ci            auto const debugLocalVariableId = createDebugLocalVariable(debugId[paramTypeId], paramName, p + 1);
2172617a3babSopenharmony_ci            auto const paramId = static_cast<Id>(firstParamId + p);
2173617a3babSopenharmony_ci            debugId[paramId] = debugLocalVariableId;
2174617a3babSopenharmony_ci
2175617a3babSopenharmony_ci            if (passByRef) {
2176617a3babSopenharmony_ci                makeDebugDeclare(debugLocalVariableId, paramId);
2177617a3babSopenharmony_ci            } else {
2178617a3babSopenharmony_ci                makeDebugValue(debugLocalVariableId, paramId);
2179617a3babSopenharmony_ci            }
2180617a3babSopenharmony_ci        }
2181617a3babSopenharmony_ci    }
2182617a3babSopenharmony_ci
2183617a3babSopenharmony_ci    // Clear debug scope stack
2184617a3babSopenharmony_ci    if (emitNonSemanticShaderDebugInfo)
2185617a3babSopenharmony_ci        currentDebugScopeId.pop();
2186617a3babSopenharmony_ci}
2187617a3babSopenharmony_ci
2188617a3babSopenharmony_ciId Builder::makeDebugFunction([[maybe_unused]] Function* function, Id nameId, Id funcTypeId)
2189617a3babSopenharmony_ci{
2190617a3babSopenharmony_ci    assert(function != nullptr);
2191617a3babSopenharmony_ci    assert(nameId != 0);
2192617a3babSopenharmony_ci    assert(funcTypeId != 0);
2193617a3babSopenharmony_ci    assert(debugId[funcTypeId] != 0);
2194617a3babSopenharmony_ci
2195617a3babSopenharmony_ci    Id funcId = getUniqueId();
2196617a3babSopenharmony_ci    auto type = new Instruction(funcId, makeVoidType(), OpExtInst);
2197617a3babSopenharmony_ci    type->addIdOperand(nonSemanticShaderDebugInfo);
2198617a3babSopenharmony_ci    type->addImmediateOperand(NonSemanticShaderDebugInfo100DebugFunction);
2199617a3babSopenharmony_ci    type->addIdOperand(nameId);
2200617a3babSopenharmony_ci    type->addIdOperand(debugId[funcTypeId]);
2201617a3babSopenharmony_ci    type->addIdOperand(makeDebugSource(currentFileId)); // TODO: This points to file of definition instead of declaration
2202617a3babSopenharmony_ci    type->addIdOperand(makeUintConstant(currentLine)); // TODO: This points to line of definition instead of declaration
2203617a3babSopenharmony_ci    type->addIdOperand(makeUintConstant(0)); // column
2204617a3babSopenharmony_ci    type->addIdOperand(makeDebugCompilationUnit()); // scope
2205617a3babSopenharmony_ci    type->addIdOperand(nameId); // linkage name
2206617a3babSopenharmony_ci    type->addIdOperand(makeUintConstant(NonSemanticShaderDebugInfo100FlagIsPublic));
2207617a3babSopenharmony_ci    type->addIdOperand(makeUintConstant(currentLine));
2208617a3babSopenharmony_ci    constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
2209617a3babSopenharmony_ci    module.mapInstruction(type);
2210617a3babSopenharmony_ci    return funcId;
2211617a3babSopenharmony_ci}
2212617a3babSopenharmony_ci
2213617a3babSopenharmony_ciId Builder::makeDebugLexicalBlock(uint32_t line) {
2214617a3babSopenharmony_ci    assert(!currentDebugScopeId.empty());
2215617a3babSopenharmony_ci
2216617a3babSopenharmony_ci    Id lexId = getUniqueId();
2217617a3babSopenharmony_ci    auto lex = new Instruction(lexId, makeVoidType(), OpExtInst);
2218617a3babSopenharmony_ci    lex->addIdOperand(nonSemanticShaderDebugInfo);
2219617a3babSopenharmony_ci    lex->addImmediateOperand(NonSemanticShaderDebugInfo100DebugLexicalBlock);
2220617a3babSopenharmony_ci    lex->addIdOperand(makeDebugSource(currentFileId));
2221617a3babSopenharmony_ci    lex->addIdOperand(makeUintConstant(line));
2222617a3babSopenharmony_ci    lex->addIdOperand(makeUintConstant(0)); // column
2223617a3babSopenharmony_ci    lex->addIdOperand(currentDebugScopeId.top()); // scope
2224617a3babSopenharmony_ci    constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(lex));
2225617a3babSopenharmony_ci    module.mapInstruction(lex);
2226617a3babSopenharmony_ci    return lexId;
2227617a3babSopenharmony_ci}
2228617a3babSopenharmony_ci
2229617a3babSopenharmony_cistd::string Builder::unmangleFunctionName(std::string const& name) const
2230617a3babSopenharmony_ci{
2231617a3babSopenharmony_ci    assert(name.length() > 0);
2232617a3babSopenharmony_ci
2233617a3babSopenharmony_ci    if(name.rfind('(') != std::string::npos) {
2234617a3babSopenharmony_ci        return name.substr(0, name.rfind('('));
2235617a3babSopenharmony_ci    } else {
2236617a3babSopenharmony_ci        return name;
2237617a3babSopenharmony_ci    }
2238617a3babSopenharmony_ci}
2239617a3babSopenharmony_ci
2240617a3babSopenharmony_ci// Comments in header
2241617a3babSopenharmony_civoid Builder::makeReturn(bool implicit, Id retVal)
2242617a3babSopenharmony_ci{
2243617a3babSopenharmony_ci    if (retVal) {
2244617a3babSopenharmony_ci        Instruction* inst = new Instruction(NoResult, NoType, OpReturnValue);
2245617a3babSopenharmony_ci        inst->addIdOperand(retVal);
2246617a3babSopenharmony_ci        buildPoint->addInstruction(std::unique_ptr<Instruction>(inst));
2247617a3babSopenharmony_ci    } else
2248617a3babSopenharmony_ci        buildPoint->addInstruction(std::unique_ptr<Instruction>(new Instruction(NoResult, NoType, OpReturn)));
2249617a3babSopenharmony_ci
2250617a3babSopenharmony_ci    if (! implicit)
2251617a3babSopenharmony_ci        createAndSetNoPredecessorBlock("post-return");
2252617a3babSopenharmony_ci}
2253617a3babSopenharmony_ci
2254617a3babSopenharmony_ci// Comments in header
2255617a3babSopenharmony_civoid Builder::enterScope(uint32_t line)
2256617a3babSopenharmony_ci{
2257617a3babSopenharmony_ci    // Generate new lexical scope debug instruction
2258617a3babSopenharmony_ci    Id lexId = makeDebugLexicalBlock(line);
2259617a3babSopenharmony_ci    currentDebugScopeId.push(lexId);
2260617a3babSopenharmony_ci    lastDebugScopeId = NoResult;
2261617a3babSopenharmony_ci}
2262617a3babSopenharmony_ci
2263617a3babSopenharmony_ci// Comments in header
2264617a3babSopenharmony_civoid Builder::leaveScope()
2265617a3babSopenharmony_ci{
2266617a3babSopenharmony_ci    // Pop current scope from stack and clear current scope
2267617a3babSopenharmony_ci    currentDebugScopeId.pop();
2268617a3babSopenharmony_ci    lastDebugScopeId = NoResult;
2269617a3babSopenharmony_ci}
2270617a3babSopenharmony_ci
2271617a3babSopenharmony_ci// Comments in header
2272617a3babSopenharmony_civoid Builder::enterFunction(Function const* function)
2273617a3babSopenharmony_ci{
2274617a3babSopenharmony_ci    // Save and disable debugInfo for HLSL entry point function. It is a wrapper
2275617a3babSopenharmony_ci    // function with no user code in it.
2276617a3babSopenharmony_ci    restoreNonSemanticShaderDebugInfo = emitNonSemanticShaderDebugInfo;
2277617a3babSopenharmony_ci    if (sourceLang == spv::SourceLanguageHLSL && function == entryPointFunction) {
2278617a3babSopenharmony_ci        emitNonSemanticShaderDebugInfo = false;
2279617a3babSopenharmony_ci    }
2280617a3babSopenharmony_ci
2281617a3babSopenharmony_ci    if (emitNonSemanticShaderDebugInfo) {
2282617a3babSopenharmony_ci        // Initialize scope state
2283617a3babSopenharmony_ci        Id funcId = function->getFuncId();
2284617a3babSopenharmony_ci        currentDebugScopeId.push(debugId[funcId]);
2285617a3babSopenharmony_ci        // Create DebugFunctionDefinition
2286617a3babSopenharmony_ci        spv::Id resultId = getUniqueId();
2287617a3babSopenharmony_ci        Instruction* defInst = new Instruction(resultId, makeVoidType(), OpExtInst);
2288617a3babSopenharmony_ci        defInst->addIdOperand(nonSemanticShaderDebugInfo);
2289617a3babSopenharmony_ci        defInst->addImmediateOperand(NonSemanticShaderDebugInfo100DebugFunctionDefinition);
2290617a3babSopenharmony_ci        defInst->addIdOperand(debugId[funcId]);
2291617a3babSopenharmony_ci        defInst->addIdOperand(funcId);
2292617a3babSopenharmony_ci        buildPoint->addInstruction(std::unique_ptr<Instruction>(defInst));
2293617a3babSopenharmony_ci    }
2294617a3babSopenharmony_ci
2295617a3babSopenharmony_ci    if (auto linkType = function->getLinkType(); linkType != LinkageTypeMax) {
2296617a3babSopenharmony_ci        Id funcId = function->getFuncId();
2297617a3babSopenharmony_ci        addCapability(CapabilityLinkage);
2298617a3babSopenharmony_ci        addLinkageDecoration(funcId, function->getExportName(), linkType);
2299617a3babSopenharmony_ci    }
2300617a3babSopenharmony_ci}
2301617a3babSopenharmony_ci
2302617a3babSopenharmony_ci// Comments in header
2303617a3babSopenharmony_civoid Builder::leaveFunction()
2304617a3babSopenharmony_ci{
2305617a3babSopenharmony_ci    Block* block = buildPoint;
2306617a3babSopenharmony_ci    Function& function = buildPoint->getParent();
2307617a3babSopenharmony_ci    assert(block);
2308617a3babSopenharmony_ci
2309617a3babSopenharmony_ci    // If our function did not contain a return, add a return void now.
2310617a3babSopenharmony_ci    if (! block->isTerminated()) {
2311617a3babSopenharmony_ci        if (function.getReturnType() == makeVoidType())
2312617a3babSopenharmony_ci            makeReturn(true);
2313617a3babSopenharmony_ci        else {
2314617a3babSopenharmony_ci            makeReturn(true, createUndefined(function.getReturnType()));
2315617a3babSopenharmony_ci        }
2316617a3babSopenharmony_ci    }
2317617a3babSopenharmony_ci
2318617a3babSopenharmony_ci    // Clear function scope from debug scope stack
2319617a3babSopenharmony_ci    if (emitNonSemanticShaderDebugInfo)
2320617a3babSopenharmony_ci        currentDebugScopeId.pop();
2321617a3babSopenharmony_ci
2322617a3babSopenharmony_ci    emitNonSemanticShaderDebugInfo = restoreNonSemanticShaderDebugInfo;
2323617a3babSopenharmony_ci}
2324617a3babSopenharmony_ci
2325617a3babSopenharmony_ci// Comments in header
2326617a3babSopenharmony_civoid Builder::makeStatementTerminator(spv::Op opcode, const char *name)
2327617a3babSopenharmony_ci{
2328617a3babSopenharmony_ci    buildPoint->addInstruction(std::unique_ptr<Instruction>(new Instruction(opcode)));
2329617a3babSopenharmony_ci    createAndSetNoPredecessorBlock(name);
2330617a3babSopenharmony_ci}
2331617a3babSopenharmony_ci
2332617a3babSopenharmony_ci// Comments in header
2333617a3babSopenharmony_civoid Builder::makeStatementTerminator(spv::Op opcode, const std::vector<Id>& operands, const char* name)
2334617a3babSopenharmony_ci{
2335617a3babSopenharmony_ci    // It's assumed that the terminator instruction is always of void return type
2336617a3babSopenharmony_ci    // However in future if there is a need for non void return type, new helper
2337617a3babSopenharmony_ci    // methods can be created.
2338617a3babSopenharmony_ci    createNoResultOp(opcode, operands);
2339617a3babSopenharmony_ci    createAndSetNoPredecessorBlock(name);
2340617a3babSopenharmony_ci}
2341617a3babSopenharmony_ci
2342617a3babSopenharmony_ci// Comments in header
2343617a3babSopenharmony_ciId Builder::createVariable(Decoration precision, StorageClass storageClass, Id type, const char* name, Id initializer,
2344617a3babSopenharmony_ci    bool const compilerGenerated)
2345617a3babSopenharmony_ci{
2346617a3babSopenharmony_ci    Id pointerType = makePointer(storageClass, type);
2347617a3babSopenharmony_ci    Instruction* inst = new Instruction(getUniqueId(), pointerType, OpVariable);
2348617a3babSopenharmony_ci    inst->addImmediateOperand(storageClass);
2349617a3babSopenharmony_ci    if (initializer != NoResult)
2350617a3babSopenharmony_ci        inst->addIdOperand(initializer);
2351617a3babSopenharmony_ci
2352617a3babSopenharmony_ci    switch (storageClass) {
2353617a3babSopenharmony_ci    case StorageClassFunction:
2354617a3babSopenharmony_ci        // Validation rules require the declaration in the entry block
2355617a3babSopenharmony_ci        buildPoint->getParent().addLocalVariable(std::unique_ptr<Instruction>(inst));
2356617a3babSopenharmony_ci
2357617a3babSopenharmony_ci        if (emitNonSemanticShaderDebugInfo && !compilerGenerated)
2358617a3babSopenharmony_ci        {
2359617a3babSopenharmony_ci            auto const debugLocalVariableId = createDebugLocalVariable(debugId[type], name);
2360617a3babSopenharmony_ci            debugId[inst->getResultId()] = debugLocalVariableId;
2361617a3babSopenharmony_ci
2362617a3babSopenharmony_ci            makeDebugDeclare(debugLocalVariableId, inst->getResultId());
2363617a3babSopenharmony_ci        }
2364617a3babSopenharmony_ci
2365617a3babSopenharmony_ci        break;
2366617a3babSopenharmony_ci
2367617a3babSopenharmony_ci    default:
2368617a3babSopenharmony_ci        constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(inst));
2369617a3babSopenharmony_ci        module.mapInstruction(inst);
2370617a3babSopenharmony_ci
2371617a3babSopenharmony_ci        if (emitNonSemanticShaderDebugInfo && !isRayTracingOpCode(getOpCode(type)))
2372617a3babSopenharmony_ci        {
2373617a3babSopenharmony_ci            auto const debugResultId = createDebugGlobalVariable(debugId[type], name, inst->getResultId());
2374617a3babSopenharmony_ci            debugId[inst->getResultId()] = debugResultId;
2375617a3babSopenharmony_ci        }
2376617a3babSopenharmony_ci        break;
2377617a3babSopenharmony_ci    }
2378617a3babSopenharmony_ci
2379617a3babSopenharmony_ci    if (name)
2380617a3babSopenharmony_ci        addName(inst->getResultId(), name);
2381617a3babSopenharmony_ci    setPrecision(inst->getResultId(), precision);
2382617a3babSopenharmony_ci
2383617a3babSopenharmony_ci    return inst->getResultId();
2384617a3babSopenharmony_ci}
2385617a3babSopenharmony_ci
2386617a3babSopenharmony_ci// Comments in header
2387617a3babSopenharmony_ciId Builder::createUndefined(Id type)
2388617a3babSopenharmony_ci{
2389617a3babSopenharmony_ci  Instruction* inst = new Instruction(getUniqueId(), type, OpUndef);
2390617a3babSopenharmony_ci  buildPoint->addInstruction(std::unique_ptr<Instruction>(inst));
2391617a3babSopenharmony_ci  return inst->getResultId();
2392617a3babSopenharmony_ci}
2393617a3babSopenharmony_ci
2394617a3babSopenharmony_ci// av/vis/nonprivate are unnecessary and illegal for some storage classes.
2395617a3babSopenharmony_cispv::MemoryAccessMask Builder::sanitizeMemoryAccessForStorageClass(spv::MemoryAccessMask memoryAccess, StorageClass sc)
2396617a3babSopenharmony_ci    const
2397617a3babSopenharmony_ci{
2398617a3babSopenharmony_ci    switch (sc) {
2399617a3babSopenharmony_ci    case spv::StorageClassUniform:
2400617a3babSopenharmony_ci    case spv::StorageClassWorkgroup:
2401617a3babSopenharmony_ci    case spv::StorageClassStorageBuffer:
2402617a3babSopenharmony_ci    case spv::StorageClassPhysicalStorageBufferEXT:
2403617a3babSopenharmony_ci        break;
2404617a3babSopenharmony_ci    default:
2405617a3babSopenharmony_ci        memoryAccess = spv::MemoryAccessMask(memoryAccess &
2406617a3babSopenharmony_ci                        ~(spv::MemoryAccessMakePointerAvailableKHRMask |
2407617a3babSopenharmony_ci                          spv::MemoryAccessMakePointerVisibleKHRMask |
2408617a3babSopenharmony_ci                          spv::MemoryAccessNonPrivatePointerKHRMask));
2409617a3babSopenharmony_ci        break;
2410617a3babSopenharmony_ci    }
2411617a3babSopenharmony_ci    return memoryAccess;
2412617a3babSopenharmony_ci}
2413617a3babSopenharmony_ci
2414617a3babSopenharmony_ci// Comments in header
2415617a3babSopenharmony_civoid Builder::createStore(Id rValue, Id lValue, spv::MemoryAccessMask memoryAccess, spv::Scope scope,
2416617a3babSopenharmony_ci    unsigned int alignment)
2417617a3babSopenharmony_ci{
2418617a3babSopenharmony_ci    Instruction* store = new Instruction(OpStore);
2419617a3babSopenharmony_ci    store->addIdOperand(lValue);
2420617a3babSopenharmony_ci    store->addIdOperand(rValue);
2421617a3babSopenharmony_ci
2422617a3babSopenharmony_ci    memoryAccess = sanitizeMemoryAccessForStorageClass(memoryAccess, getStorageClass(lValue));
2423617a3babSopenharmony_ci
2424617a3babSopenharmony_ci    if (memoryAccess != MemoryAccessMaskNone) {
2425617a3babSopenharmony_ci        store->addImmediateOperand(memoryAccess);
2426617a3babSopenharmony_ci        if (memoryAccess & spv::MemoryAccessAlignedMask) {
2427617a3babSopenharmony_ci            store->addImmediateOperand(alignment);
2428617a3babSopenharmony_ci        }
2429617a3babSopenharmony_ci        if (memoryAccess & spv::MemoryAccessMakePointerAvailableKHRMask) {
2430617a3babSopenharmony_ci            store->addIdOperand(makeUintConstant(scope));
2431617a3babSopenharmony_ci        }
2432617a3babSopenharmony_ci    }
2433617a3babSopenharmony_ci
2434617a3babSopenharmony_ci    buildPoint->addInstruction(std::unique_ptr<Instruction>(store));
2435617a3babSopenharmony_ci}
2436617a3babSopenharmony_ci
2437617a3babSopenharmony_ci// Comments in header
2438617a3babSopenharmony_ciId Builder::createLoad(Id lValue, spv::Decoration precision, spv::MemoryAccessMask memoryAccess,
2439617a3babSopenharmony_ci    spv::Scope scope, unsigned int alignment)
2440617a3babSopenharmony_ci{
2441617a3babSopenharmony_ci    Instruction* load = new Instruction(getUniqueId(), getDerefTypeId(lValue), OpLoad);
2442617a3babSopenharmony_ci    load->addIdOperand(lValue);
2443617a3babSopenharmony_ci
2444617a3babSopenharmony_ci    memoryAccess = sanitizeMemoryAccessForStorageClass(memoryAccess, getStorageClass(lValue));
2445617a3babSopenharmony_ci
2446617a3babSopenharmony_ci    if (memoryAccess != MemoryAccessMaskNone) {
2447617a3babSopenharmony_ci        load->addImmediateOperand(memoryAccess);
2448617a3babSopenharmony_ci        if (memoryAccess & spv::MemoryAccessAlignedMask) {
2449617a3babSopenharmony_ci            load->addImmediateOperand(alignment);
2450617a3babSopenharmony_ci        }
2451617a3babSopenharmony_ci        if (memoryAccess & spv::MemoryAccessMakePointerVisibleKHRMask) {
2452617a3babSopenharmony_ci            load->addIdOperand(makeUintConstant(scope));
2453617a3babSopenharmony_ci        }
2454617a3babSopenharmony_ci    }
2455617a3babSopenharmony_ci
2456617a3babSopenharmony_ci    buildPoint->addInstruction(std::unique_ptr<Instruction>(load));
2457617a3babSopenharmony_ci    setPrecision(load->getResultId(), precision);
2458617a3babSopenharmony_ci
2459617a3babSopenharmony_ci    return load->getResultId();
2460617a3babSopenharmony_ci}
2461617a3babSopenharmony_ci
2462617a3babSopenharmony_ci// Comments in header
2463617a3babSopenharmony_ciId Builder::createAccessChain(StorageClass storageClass, Id base, const std::vector<Id>& offsets)
2464617a3babSopenharmony_ci{
2465617a3babSopenharmony_ci    // Figure out the final resulting type.
2466617a3babSopenharmony_ci    Id typeId = getResultingAccessChainType();
2467617a3babSopenharmony_ci    typeId = makePointer(storageClass, typeId);
2468617a3babSopenharmony_ci
2469617a3babSopenharmony_ci    // Make the instruction
2470617a3babSopenharmony_ci    Instruction* chain = new Instruction(getUniqueId(), typeId, OpAccessChain);
2471617a3babSopenharmony_ci    chain->addIdOperand(base);
2472617a3babSopenharmony_ci    for (int i = 0; i < (int)offsets.size(); ++i)
2473617a3babSopenharmony_ci        chain->addIdOperand(offsets[i]);
2474617a3babSopenharmony_ci    buildPoint->addInstruction(std::unique_ptr<Instruction>(chain));
2475617a3babSopenharmony_ci
2476617a3babSopenharmony_ci    return chain->getResultId();
2477617a3babSopenharmony_ci}
2478617a3babSopenharmony_ci
2479617a3babSopenharmony_ciId Builder::createArrayLength(Id base, unsigned int member)
2480617a3babSopenharmony_ci{
2481617a3babSopenharmony_ci    spv::Id intType = makeUintType(32);
2482617a3babSopenharmony_ci    Instruction* length = new Instruction(getUniqueId(), intType, OpArrayLength);
2483617a3babSopenharmony_ci    length->addIdOperand(base);
2484617a3babSopenharmony_ci    length->addImmediateOperand(member);
2485617a3babSopenharmony_ci    buildPoint->addInstruction(std::unique_ptr<Instruction>(length));
2486617a3babSopenharmony_ci
2487617a3babSopenharmony_ci    return length->getResultId();
2488617a3babSopenharmony_ci}
2489617a3babSopenharmony_ci
2490617a3babSopenharmony_ciId Builder::createCooperativeMatrixLengthKHR(Id type)
2491617a3babSopenharmony_ci{
2492617a3babSopenharmony_ci    spv::Id intType = makeUintType(32);
2493617a3babSopenharmony_ci
2494617a3babSopenharmony_ci    // Generate code for spec constants if in spec constant operation
2495617a3babSopenharmony_ci    // generation mode.
2496617a3babSopenharmony_ci    if (generatingOpCodeForSpecConst) {
2497617a3babSopenharmony_ci        return createSpecConstantOp(OpCooperativeMatrixLengthKHR, intType, std::vector<Id>(1, type), std::vector<Id>());
2498617a3babSopenharmony_ci    }
2499617a3babSopenharmony_ci
2500617a3babSopenharmony_ci    Instruction* length = new Instruction(getUniqueId(), intType, OpCooperativeMatrixLengthKHR);
2501617a3babSopenharmony_ci    length->addIdOperand(type);
2502617a3babSopenharmony_ci    buildPoint->addInstruction(std::unique_ptr<Instruction>(length));
2503617a3babSopenharmony_ci
2504617a3babSopenharmony_ci    return length->getResultId();
2505617a3babSopenharmony_ci}
2506617a3babSopenharmony_ci
2507617a3babSopenharmony_ciId Builder::createCooperativeMatrixLengthNV(Id type)
2508617a3babSopenharmony_ci{
2509617a3babSopenharmony_ci    spv::Id intType = makeUintType(32);
2510617a3babSopenharmony_ci
2511617a3babSopenharmony_ci    // Generate code for spec constants if in spec constant operation
2512617a3babSopenharmony_ci    // generation mode.
2513617a3babSopenharmony_ci    if (generatingOpCodeForSpecConst) {
2514617a3babSopenharmony_ci        return createSpecConstantOp(OpCooperativeMatrixLengthNV, intType, std::vector<Id>(1, type), std::vector<Id>());
2515617a3babSopenharmony_ci    }
2516617a3babSopenharmony_ci
2517617a3babSopenharmony_ci    Instruction* length = new Instruction(getUniqueId(), intType, OpCooperativeMatrixLengthNV);
2518617a3babSopenharmony_ci    length->addIdOperand(type);
2519617a3babSopenharmony_ci    buildPoint->addInstruction(std::unique_ptr<Instruction>(length));
2520617a3babSopenharmony_ci
2521617a3babSopenharmony_ci    return length->getResultId();
2522617a3babSopenharmony_ci}
2523617a3babSopenharmony_ci
2524617a3babSopenharmony_ciId Builder::createCompositeExtract(Id composite, Id typeId, unsigned index)
2525617a3babSopenharmony_ci{
2526617a3babSopenharmony_ci    // Generate code for spec constants if in spec constant operation
2527617a3babSopenharmony_ci    // generation mode.
2528617a3babSopenharmony_ci    if (generatingOpCodeForSpecConst) {
2529617a3babSopenharmony_ci        return createSpecConstantOp(OpCompositeExtract, typeId, std::vector<Id>(1, composite),
2530617a3babSopenharmony_ci            std::vector<Id>(1, index));
2531617a3babSopenharmony_ci    }
2532617a3babSopenharmony_ci    Instruction* extract = new Instruction(getUniqueId(), typeId, OpCompositeExtract);
2533617a3babSopenharmony_ci    extract->addIdOperand(composite);
2534617a3babSopenharmony_ci    extract->addImmediateOperand(index);
2535617a3babSopenharmony_ci    buildPoint->addInstruction(std::unique_ptr<Instruction>(extract));
2536617a3babSopenharmony_ci
2537617a3babSopenharmony_ci    return extract->getResultId();
2538617a3babSopenharmony_ci}
2539617a3babSopenharmony_ci
2540617a3babSopenharmony_ciId Builder::createCompositeExtract(Id composite, Id typeId, const std::vector<unsigned>& indexes)
2541617a3babSopenharmony_ci{
2542617a3babSopenharmony_ci    // Generate code for spec constants if in spec constant operation
2543617a3babSopenharmony_ci    // generation mode.
2544617a3babSopenharmony_ci    if (generatingOpCodeForSpecConst) {
2545617a3babSopenharmony_ci        return createSpecConstantOp(OpCompositeExtract, typeId, std::vector<Id>(1, composite), indexes);
2546617a3babSopenharmony_ci    }
2547617a3babSopenharmony_ci    Instruction* extract = new Instruction(getUniqueId(), typeId, OpCompositeExtract);
2548617a3babSopenharmony_ci    extract->addIdOperand(composite);
2549617a3babSopenharmony_ci    for (int i = 0; i < (int)indexes.size(); ++i)
2550617a3babSopenharmony_ci        extract->addImmediateOperand(indexes[i]);
2551617a3babSopenharmony_ci    buildPoint->addInstruction(std::unique_ptr<Instruction>(extract));
2552617a3babSopenharmony_ci
2553617a3babSopenharmony_ci    return extract->getResultId();
2554617a3babSopenharmony_ci}
2555617a3babSopenharmony_ci
2556617a3babSopenharmony_ciId Builder::createCompositeInsert(Id object, Id composite, Id typeId, unsigned index)
2557617a3babSopenharmony_ci{
2558617a3babSopenharmony_ci    Instruction* insert = new Instruction(getUniqueId(), typeId, OpCompositeInsert);
2559617a3babSopenharmony_ci    insert->addIdOperand(object);
2560617a3babSopenharmony_ci    insert->addIdOperand(composite);
2561617a3babSopenharmony_ci    insert->addImmediateOperand(index);
2562617a3babSopenharmony_ci    buildPoint->addInstruction(std::unique_ptr<Instruction>(insert));
2563617a3babSopenharmony_ci
2564617a3babSopenharmony_ci    return insert->getResultId();
2565617a3babSopenharmony_ci}
2566617a3babSopenharmony_ci
2567617a3babSopenharmony_ciId Builder::createCompositeInsert(Id object, Id composite, Id typeId, const std::vector<unsigned>& indexes)
2568617a3babSopenharmony_ci{
2569617a3babSopenharmony_ci    Instruction* insert = new Instruction(getUniqueId(), typeId, OpCompositeInsert);
2570617a3babSopenharmony_ci    insert->addIdOperand(object);
2571617a3babSopenharmony_ci    insert->addIdOperand(composite);
2572617a3babSopenharmony_ci    for (int i = 0; i < (int)indexes.size(); ++i)
2573617a3babSopenharmony_ci        insert->addImmediateOperand(indexes[i]);
2574617a3babSopenharmony_ci    buildPoint->addInstruction(std::unique_ptr<Instruction>(insert));
2575617a3babSopenharmony_ci
2576617a3babSopenharmony_ci    return insert->getResultId();
2577617a3babSopenharmony_ci}
2578617a3babSopenharmony_ci
2579617a3babSopenharmony_ciId Builder::createVectorExtractDynamic(Id vector, Id typeId, Id componentIndex)
2580617a3babSopenharmony_ci{
2581617a3babSopenharmony_ci    Instruction* extract = new Instruction(getUniqueId(), typeId, OpVectorExtractDynamic);
2582617a3babSopenharmony_ci    extract->addIdOperand(vector);
2583617a3babSopenharmony_ci    extract->addIdOperand(componentIndex);
2584617a3babSopenharmony_ci    buildPoint->addInstruction(std::unique_ptr<Instruction>(extract));
2585617a3babSopenharmony_ci
2586617a3babSopenharmony_ci    return extract->getResultId();
2587617a3babSopenharmony_ci}
2588617a3babSopenharmony_ci
2589617a3babSopenharmony_ciId Builder::createVectorInsertDynamic(Id vector, Id typeId, Id component, Id componentIndex)
2590617a3babSopenharmony_ci{
2591617a3babSopenharmony_ci    Instruction* insert = new Instruction(getUniqueId(), typeId, OpVectorInsertDynamic);
2592617a3babSopenharmony_ci    insert->addIdOperand(vector);
2593617a3babSopenharmony_ci    insert->addIdOperand(component);
2594617a3babSopenharmony_ci    insert->addIdOperand(componentIndex);
2595617a3babSopenharmony_ci    buildPoint->addInstruction(std::unique_ptr<Instruction>(insert));
2596617a3babSopenharmony_ci
2597617a3babSopenharmony_ci    return insert->getResultId();
2598617a3babSopenharmony_ci}
2599617a3babSopenharmony_ci
2600617a3babSopenharmony_ci// An opcode that has no operands, no result id, and no type
2601617a3babSopenharmony_civoid Builder::createNoResultOp(Op opCode)
2602617a3babSopenharmony_ci{
2603617a3babSopenharmony_ci    Instruction* op = new Instruction(opCode);
2604617a3babSopenharmony_ci    buildPoint->addInstruction(std::unique_ptr<Instruction>(op));
2605617a3babSopenharmony_ci}
2606617a3babSopenharmony_ci
2607617a3babSopenharmony_ci// An opcode that has one id operand, no result id, and no type
2608617a3babSopenharmony_civoid Builder::createNoResultOp(Op opCode, Id operand)
2609617a3babSopenharmony_ci{
2610617a3babSopenharmony_ci    Instruction* op = new Instruction(opCode);
2611617a3babSopenharmony_ci    op->addIdOperand(operand);
2612617a3babSopenharmony_ci    buildPoint->addInstruction(std::unique_ptr<Instruction>(op));
2613617a3babSopenharmony_ci}
2614617a3babSopenharmony_ci
2615617a3babSopenharmony_ci// An opcode that has one or more operands, no result id, and no type
2616617a3babSopenharmony_civoid Builder::createNoResultOp(Op opCode, const std::vector<Id>& operands)
2617617a3babSopenharmony_ci{
2618617a3babSopenharmony_ci    Instruction* op = new Instruction(opCode);
2619617a3babSopenharmony_ci    for (auto it = operands.cbegin(); it != operands.cend(); ++it) {
2620617a3babSopenharmony_ci        op->addIdOperand(*it);
2621617a3babSopenharmony_ci    }
2622617a3babSopenharmony_ci    buildPoint->addInstruction(std::unique_ptr<Instruction>(op));
2623617a3babSopenharmony_ci}
2624617a3babSopenharmony_ci
2625617a3babSopenharmony_ci// An opcode that has multiple operands, no result id, and no type
2626617a3babSopenharmony_civoid Builder::createNoResultOp(Op opCode, const std::vector<IdImmediate>& operands)
2627617a3babSopenharmony_ci{
2628617a3babSopenharmony_ci    Instruction* op = new Instruction(opCode);
2629617a3babSopenharmony_ci    for (auto it = operands.cbegin(); it != operands.cend(); ++it) {
2630617a3babSopenharmony_ci        if (it->isId)
2631617a3babSopenharmony_ci            op->addIdOperand(it->word);
2632617a3babSopenharmony_ci        else
2633617a3babSopenharmony_ci            op->addImmediateOperand(it->word);
2634617a3babSopenharmony_ci    }
2635617a3babSopenharmony_ci    buildPoint->addInstruction(std::unique_ptr<Instruction>(op));
2636617a3babSopenharmony_ci}
2637617a3babSopenharmony_ci
2638617a3babSopenharmony_civoid Builder::createControlBarrier(Scope execution, Scope memory, MemorySemanticsMask semantics)
2639617a3babSopenharmony_ci{
2640617a3babSopenharmony_ci    Instruction* op = new Instruction(OpControlBarrier);
2641617a3babSopenharmony_ci    op->addIdOperand(makeUintConstant(execution));
2642617a3babSopenharmony_ci    op->addIdOperand(makeUintConstant(memory));
2643617a3babSopenharmony_ci    op->addIdOperand(makeUintConstant(semantics));
2644617a3babSopenharmony_ci    buildPoint->addInstruction(std::unique_ptr<Instruction>(op));
2645617a3babSopenharmony_ci}
2646617a3babSopenharmony_ci
2647617a3babSopenharmony_civoid Builder::createMemoryBarrier(unsigned executionScope, unsigned memorySemantics)
2648617a3babSopenharmony_ci{
2649617a3babSopenharmony_ci    Instruction* op = new Instruction(OpMemoryBarrier);
2650617a3babSopenharmony_ci    op->addIdOperand(makeUintConstant(executionScope));
2651617a3babSopenharmony_ci    op->addIdOperand(makeUintConstant(memorySemantics));
2652617a3babSopenharmony_ci    buildPoint->addInstruction(std::unique_ptr<Instruction>(op));
2653617a3babSopenharmony_ci}
2654617a3babSopenharmony_ci
2655617a3babSopenharmony_ci// An opcode that has one operands, a result id, and a type
2656617a3babSopenharmony_ciId Builder::createUnaryOp(Op opCode, Id typeId, Id operand)
2657617a3babSopenharmony_ci{
2658617a3babSopenharmony_ci    // Generate code for spec constants if in spec constant operation
2659617a3babSopenharmony_ci    // generation mode.
2660617a3babSopenharmony_ci    if (generatingOpCodeForSpecConst) {
2661617a3babSopenharmony_ci        return createSpecConstantOp(opCode, typeId, std::vector<Id>(1, operand), std::vector<Id>());
2662617a3babSopenharmony_ci    }
2663617a3babSopenharmony_ci    Instruction* op = new Instruction(getUniqueId(), typeId, opCode);
2664617a3babSopenharmony_ci    op->addIdOperand(operand);
2665617a3babSopenharmony_ci    buildPoint->addInstruction(std::unique_ptr<Instruction>(op));
2666617a3babSopenharmony_ci
2667617a3babSopenharmony_ci    return op->getResultId();
2668617a3babSopenharmony_ci}
2669617a3babSopenharmony_ci
2670617a3babSopenharmony_ciId Builder::createBinOp(Op opCode, Id typeId, Id left, Id right)
2671617a3babSopenharmony_ci{
2672617a3babSopenharmony_ci    // Generate code for spec constants if in spec constant operation
2673617a3babSopenharmony_ci    // generation mode.
2674617a3babSopenharmony_ci    if (generatingOpCodeForSpecConst) {
2675617a3babSopenharmony_ci        std::vector<Id> operands(2);
2676617a3babSopenharmony_ci        operands[0] = left; operands[1] = right;
2677617a3babSopenharmony_ci        return createSpecConstantOp(opCode, typeId, operands, std::vector<Id>());
2678617a3babSopenharmony_ci    }
2679617a3babSopenharmony_ci    Instruction* op = new Instruction(getUniqueId(), typeId, opCode);
2680617a3babSopenharmony_ci    op->addIdOperand(left);
2681617a3babSopenharmony_ci    op->addIdOperand(right);
2682617a3babSopenharmony_ci    buildPoint->addInstruction(std::unique_ptr<Instruction>(op));
2683617a3babSopenharmony_ci
2684617a3babSopenharmony_ci    return op->getResultId();
2685617a3babSopenharmony_ci}
2686617a3babSopenharmony_ci
2687617a3babSopenharmony_ciId Builder::createTriOp(Op opCode, Id typeId, Id op1, Id op2, Id op3)
2688617a3babSopenharmony_ci{
2689617a3babSopenharmony_ci    // Generate code for spec constants if in spec constant operation
2690617a3babSopenharmony_ci    // generation mode.
2691617a3babSopenharmony_ci    if (generatingOpCodeForSpecConst) {
2692617a3babSopenharmony_ci        std::vector<Id> operands(3);
2693617a3babSopenharmony_ci        operands[0] = op1;
2694617a3babSopenharmony_ci        operands[1] = op2;
2695617a3babSopenharmony_ci        operands[2] = op3;
2696617a3babSopenharmony_ci        return createSpecConstantOp(
2697617a3babSopenharmony_ci            opCode, typeId, operands, std::vector<Id>());
2698617a3babSopenharmony_ci    }
2699617a3babSopenharmony_ci    Instruction* op = new Instruction(getUniqueId(), typeId, opCode);
2700617a3babSopenharmony_ci    op->addIdOperand(op1);
2701617a3babSopenharmony_ci    op->addIdOperand(op2);
2702617a3babSopenharmony_ci    op->addIdOperand(op3);
2703617a3babSopenharmony_ci    buildPoint->addInstruction(std::unique_ptr<Instruction>(op));
2704617a3babSopenharmony_ci
2705617a3babSopenharmony_ci    return op->getResultId();
2706617a3babSopenharmony_ci}
2707617a3babSopenharmony_ci
2708617a3babSopenharmony_ciId Builder::createOp(Op opCode, Id typeId, const std::vector<Id>& operands)
2709617a3babSopenharmony_ci{
2710617a3babSopenharmony_ci    Instruction* op = new Instruction(getUniqueId(), typeId, opCode);
2711617a3babSopenharmony_ci    for (auto it = operands.cbegin(); it != operands.cend(); ++it)
2712617a3babSopenharmony_ci        op->addIdOperand(*it);
2713617a3babSopenharmony_ci    buildPoint->addInstruction(std::unique_ptr<Instruction>(op));
2714617a3babSopenharmony_ci
2715617a3babSopenharmony_ci    return op->getResultId();
2716617a3babSopenharmony_ci}
2717617a3babSopenharmony_ci
2718617a3babSopenharmony_ciId Builder::createOp(Op opCode, Id typeId, const std::vector<IdImmediate>& operands)
2719617a3babSopenharmony_ci{
2720617a3babSopenharmony_ci    Instruction* op = new Instruction(getUniqueId(), typeId, opCode);
2721617a3babSopenharmony_ci    for (auto it = operands.cbegin(); it != operands.cend(); ++it) {
2722617a3babSopenharmony_ci        if (it->isId)
2723617a3babSopenharmony_ci            op->addIdOperand(it->word);
2724617a3babSopenharmony_ci        else
2725617a3babSopenharmony_ci            op->addImmediateOperand(it->word);
2726617a3babSopenharmony_ci    }
2727617a3babSopenharmony_ci    buildPoint->addInstruction(std::unique_ptr<Instruction>(op));
2728617a3babSopenharmony_ci
2729617a3babSopenharmony_ci    return op->getResultId();
2730617a3babSopenharmony_ci}
2731617a3babSopenharmony_ci
2732617a3babSopenharmony_ciId Builder::createSpecConstantOp(Op opCode, Id typeId, const std::vector<Id>& operands,
2733617a3babSopenharmony_ci    const std::vector<unsigned>& literals)
2734617a3babSopenharmony_ci{
2735617a3babSopenharmony_ci    Instruction* op = new Instruction(getUniqueId(), typeId, OpSpecConstantOp);
2736617a3babSopenharmony_ci    op->addImmediateOperand((unsigned) opCode);
2737617a3babSopenharmony_ci    for (auto it = operands.cbegin(); it != operands.cend(); ++it)
2738617a3babSopenharmony_ci        op->addIdOperand(*it);
2739617a3babSopenharmony_ci    for (auto it = literals.cbegin(); it != literals.cend(); ++it)
2740617a3babSopenharmony_ci        op->addImmediateOperand(*it);
2741617a3babSopenharmony_ci    module.mapInstruction(op);
2742617a3babSopenharmony_ci    constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(op));
2743617a3babSopenharmony_ci
2744617a3babSopenharmony_ci    // OpSpecConstantOp's using 8 or 16 bit types require the associated capability
2745617a3babSopenharmony_ci    if (containsType(typeId, OpTypeInt, 8))
2746617a3babSopenharmony_ci        addCapability(CapabilityInt8);
2747617a3babSopenharmony_ci    if (containsType(typeId, OpTypeInt, 16))
2748617a3babSopenharmony_ci        addCapability(CapabilityInt16);
2749617a3babSopenharmony_ci    if (containsType(typeId, OpTypeFloat, 16))
2750617a3babSopenharmony_ci        addCapability(CapabilityFloat16);
2751617a3babSopenharmony_ci
2752617a3babSopenharmony_ci    return op->getResultId();
2753617a3babSopenharmony_ci}
2754617a3babSopenharmony_ci
2755617a3babSopenharmony_ciId Builder::createFunctionCall(spv::Function* function, const std::vector<spv::Id>& args)
2756617a3babSopenharmony_ci{
2757617a3babSopenharmony_ci    Instruction* op = new Instruction(getUniqueId(), function->getReturnType(), OpFunctionCall);
2758617a3babSopenharmony_ci    op->addIdOperand(function->getId());
2759617a3babSopenharmony_ci    for (int a = 0; a < (int)args.size(); ++a)
2760617a3babSopenharmony_ci        op->addIdOperand(args[a]);
2761617a3babSopenharmony_ci    buildPoint->addInstruction(std::unique_ptr<Instruction>(op));
2762617a3babSopenharmony_ci
2763617a3babSopenharmony_ci    return op->getResultId();
2764617a3babSopenharmony_ci}
2765617a3babSopenharmony_ci
2766617a3babSopenharmony_ci// Comments in header
2767617a3babSopenharmony_ciId Builder::createRvalueSwizzle(Decoration precision, Id typeId, Id source, const std::vector<unsigned>& channels)
2768617a3babSopenharmony_ci{
2769617a3babSopenharmony_ci    if (channels.size() == 1)
2770617a3babSopenharmony_ci        return setPrecision(createCompositeExtract(source, typeId, channels.front()), precision);
2771617a3babSopenharmony_ci
2772617a3babSopenharmony_ci    if (generatingOpCodeForSpecConst) {
2773617a3babSopenharmony_ci        std::vector<Id> operands(2);
2774617a3babSopenharmony_ci        operands[0] = operands[1] = source;
2775617a3babSopenharmony_ci        return setPrecision(createSpecConstantOp(OpVectorShuffle, typeId, operands, channels), precision);
2776617a3babSopenharmony_ci    }
2777617a3babSopenharmony_ci    Instruction* swizzle = new Instruction(getUniqueId(), typeId, OpVectorShuffle);
2778617a3babSopenharmony_ci    assert(isVector(source));
2779617a3babSopenharmony_ci    swizzle->addIdOperand(source);
2780617a3babSopenharmony_ci    swizzle->addIdOperand(source);
2781617a3babSopenharmony_ci    for (int i = 0; i < (int)channels.size(); ++i)
2782617a3babSopenharmony_ci        swizzle->addImmediateOperand(channels[i]);
2783617a3babSopenharmony_ci    buildPoint->addInstruction(std::unique_ptr<Instruction>(swizzle));
2784617a3babSopenharmony_ci
2785617a3babSopenharmony_ci    return setPrecision(swizzle->getResultId(), precision);
2786617a3babSopenharmony_ci}
2787617a3babSopenharmony_ci
2788617a3babSopenharmony_ci// Comments in header
2789617a3babSopenharmony_ciId Builder::createLvalueSwizzle(Id typeId, Id target, Id source, const std::vector<unsigned>& channels)
2790617a3babSopenharmony_ci{
2791617a3babSopenharmony_ci    if (channels.size() == 1 && getNumComponents(source) == 1)
2792617a3babSopenharmony_ci        return createCompositeInsert(source, target, typeId, channels.front());
2793617a3babSopenharmony_ci
2794617a3babSopenharmony_ci    Instruction* swizzle = new Instruction(getUniqueId(), typeId, OpVectorShuffle);
2795617a3babSopenharmony_ci
2796617a3babSopenharmony_ci    assert(isVector(target));
2797617a3babSopenharmony_ci    swizzle->addIdOperand(target);
2798617a3babSopenharmony_ci
2799617a3babSopenharmony_ci    assert(getNumComponents(source) == (int)channels.size());
2800617a3babSopenharmony_ci    assert(isVector(source));
2801617a3babSopenharmony_ci    swizzle->addIdOperand(source);
2802617a3babSopenharmony_ci
2803617a3babSopenharmony_ci    // Set up an identity shuffle from the base value to the result value
2804617a3babSopenharmony_ci    unsigned int components[4];
2805617a3babSopenharmony_ci    int numTargetComponents = getNumComponents(target);
2806617a3babSopenharmony_ci    for (int i = 0; i < numTargetComponents; ++i)
2807617a3babSopenharmony_ci        components[i] = i;
2808617a3babSopenharmony_ci
2809617a3babSopenharmony_ci    // Punch in the l-value swizzle
2810617a3babSopenharmony_ci    for (int i = 0; i < (int)channels.size(); ++i)
2811617a3babSopenharmony_ci        components[channels[i]] = numTargetComponents + i;
2812617a3babSopenharmony_ci
2813617a3babSopenharmony_ci    // finish the instruction with these components selectors
2814617a3babSopenharmony_ci    for (int i = 0; i < numTargetComponents; ++i)
2815617a3babSopenharmony_ci        swizzle->addImmediateOperand(components[i]);
2816617a3babSopenharmony_ci    buildPoint->addInstruction(std::unique_ptr<Instruction>(swizzle));
2817617a3babSopenharmony_ci
2818617a3babSopenharmony_ci    return swizzle->getResultId();
2819617a3babSopenharmony_ci}
2820617a3babSopenharmony_ci
2821617a3babSopenharmony_ci// Comments in header
2822617a3babSopenharmony_civoid Builder::promoteScalar(Decoration precision, Id& left, Id& right)
2823617a3babSopenharmony_ci{
2824617a3babSopenharmony_ci    int direction = getNumComponents(right) - getNumComponents(left);
2825617a3babSopenharmony_ci
2826617a3babSopenharmony_ci    if (direction > 0)
2827617a3babSopenharmony_ci        left = smearScalar(precision, left, makeVectorType(getTypeId(left), getNumComponents(right)));
2828617a3babSopenharmony_ci    else if (direction < 0)
2829617a3babSopenharmony_ci        right = smearScalar(precision, right, makeVectorType(getTypeId(right), getNumComponents(left)));
2830617a3babSopenharmony_ci
2831617a3babSopenharmony_ci    return;
2832617a3babSopenharmony_ci}
2833617a3babSopenharmony_ci
2834617a3babSopenharmony_ci// Comments in header
2835617a3babSopenharmony_ciId Builder::smearScalar(Decoration precision, Id scalar, Id vectorType)
2836617a3babSopenharmony_ci{
2837617a3babSopenharmony_ci    assert(getNumComponents(scalar) == 1);
2838617a3babSopenharmony_ci    assert(getTypeId(scalar) == getScalarTypeId(vectorType));
2839617a3babSopenharmony_ci
2840617a3babSopenharmony_ci    int numComponents = getNumTypeComponents(vectorType);
2841617a3babSopenharmony_ci    if (numComponents == 1)
2842617a3babSopenharmony_ci        return scalar;
2843617a3babSopenharmony_ci
2844617a3babSopenharmony_ci    Instruction* smear = nullptr;
2845617a3babSopenharmony_ci    if (generatingOpCodeForSpecConst) {
2846617a3babSopenharmony_ci        auto members = std::vector<spv::Id>(numComponents, scalar);
2847617a3babSopenharmony_ci        // Sometime even in spec-constant-op mode, the temporary vector created by
2848617a3babSopenharmony_ci        // promoting a scalar might not be a spec constant. This should depend on
2849617a3babSopenharmony_ci        // the scalar.
2850617a3babSopenharmony_ci        // e.g.:
2851617a3babSopenharmony_ci        //  const vec2 spec_const_result = a_spec_const_vec2 + a_front_end_const_scalar;
2852617a3babSopenharmony_ci        // In such cases, the temporary vector created from a_front_end_const_scalar
2853617a3babSopenharmony_ci        // is not a spec constant vector, even though the binary operation node is marked
2854617a3babSopenharmony_ci        // as 'specConstant' and we are in spec-constant-op mode.
2855617a3babSopenharmony_ci        auto result_id = makeCompositeConstant(vectorType, members, isSpecConstant(scalar));
2856617a3babSopenharmony_ci        smear = module.getInstruction(result_id);
2857617a3babSopenharmony_ci    } else {
2858617a3babSopenharmony_ci        smear = new Instruction(getUniqueId(), vectorType, OpCompositeConstruct);
2859617a3babSopenharmony_ci        for (int c = 0; c < numComponents; ++c)
2860617a3babSopenharmony_ci            smear->addIdOperand(scalar);
2861617a3babSopenharmony_ci        buildPoint->addInstruction(std::unique_ptr<Instruction>(smear));
2862617a3babSopenharmony_ci    }
2863617a3babSopenharmony_ci
2864617a3babSopenharmony_ci    return setPrecision(smear->getResultId(), precision);
2865617a3babSopenharmony_ci}
2866617a3babSopenharmony_ci
2867617a3babSopenharmony_ci// Comments in header
2868617a3babSopenharmony_ciId Builder::createBuiltinCall(Id resultType, Id builtins, int entryPoint, const std::vector<Id>& args)
2869617a3babSopenharmony_ci{
2870617a3babSopenharmony_ci    Instruction* inst = new Instruction(getUniqueId(), resultType, OpExtInst);
2871617a3babSopenharmony_ci    inst->addIdOperand(builtins);
2872617a3babSopenharmony_ci    inst->addImmediateOperand(entryPoint);
2873617a3babSopenharmony_ci    for (int arg = 0; arg < (int)args.size(); ++arg)
2874617a3babSopenharmony_ci        inst->addIdOperand(args[arg]);
2875617a3babSopenharmony_ci
2876617a3babSopenharmony_ci    buildPoint->addInstruction(std::unique_ptr<Instruction>(inst));
2877617a3babSopenharmony_ci
2878617a3babSopenharmony_ci    return inst->getResultId();
2879617a3babSopenharmony_ci}
2880617a3babSopenharmony_ci
2881617a3babSopenharmony_ci// Accept all parameters needed to create a texture instruction.
2882617a3babSopenharmony_ci// Create the correct instruction based on the inputs, and make the call.
2883617a3babSopenharmony_ciId Builder::createTextureCall(Decoration precision, Id resultType, bool sparse, bool fetch, bool proj, bool gather,
2884617a3babSopenharmony_ci    bool noImplicitLod, const TextureParameters& parameters, ImageOperandsMask signExtensionMask)
2885617a3babSopenharmony_ci{
2886617a3babSopenharmony_ci    std::vector<Id> texArgs;
2887617a3babSopenharmony_ci
2888617a3babSopenharmony_ci    //
2889617a3babSopenharmony_ci    // Set up the fixed arguments
2890617a3babSopenharmony_ci    //
2891617a3babSopenharmony_ci    bool explicitLod = false;
2892617a3babSopenharmony_ci    texArgs.push_back(parameters.sampler);
2893617a3babSopenharmony_ci    texArgs.push_back(parameters.coords);
2894617a3babSopenharmony_ci    if (parameters.Dref != NoResult)
2895617a3babSopenharmony_ci        texArgs.push_back(parameters.Dref);
2896617a3babSopenharmony_ci    if (parameters.component != NoResult)
2897617a3babSopenharmony_ci        texArgs.push_back(parameters.component);
2898617a3babSopenharmony_ci
2899617a3babSopenharmony_ci    if (parameters.granularity != NoResult)
2900617a3babSopenharmony_ci        texArgs.push_back(parameters.granularity);
2901617a3babSopenharmony_ci    if (parameters.coarse != NoResult)
2902617a3babSopenharmony_ci        texArgs.push_back(parameters.coarse);
2903617a3babSopenharmony_ci
2904617a3babSopenharmony_ci    //
2905617a3babSopenharmony_ci    // Set up the optional arguments
2906617a3babSopenharmony_ci    //
2907617a3babSopenharmony_ci    size_t optArgNum = texArgs.size(); // the position of the mask for the optional arguments, if any.
2908617a3babSopenharmony_ci    ImageOperandsMask mask = ImageOperandsMaskNone; // the mask operand
2909617a3babSopenharmony_ci    if (parameters.bias) {
2910617a3babSopenharmony_ci        mask = (ImageOperandsMask)(mask | ImageOperandsBiasMask);
2911617a3babSopenharmony_ci        texArgs.push_back(parameters.bias);
2912617a3babSopenharmony_ci    }
2913617a3babSopenharmony_ci    if (parameters.lod) {
2914617a3babSopenharmony_ci        mask = (ImageOperandsMask)(mask | ImageOperandsLodMask);
2915617a3babSopenharmony_ci        texArgs.push_back(parameters.lod);
2916617a3babSopenharmony_ci        explicitLod = true;
2917617a3babSopenharmony_ci    } else if (parameters.gradX) {
2918617a3babSopenharmony_ci        mask = (ImageOperandsMask)(mask | ImageOperandsGradMask);
2919617a3babSopenharmony_ci        texArgs.push_back(parameters.gradX);
2920617a3babSopenharmony_ci        texArgs.push_back(parameters.gradY);
2921617a3babSopenharmony_ci        explicitLod = true;
2922617a3babSopenharmony_ci    } else if (noImplicitLod && ! fetch && ! gather) {
2923617a3babSopenharmony_ci        // have to explicitly use lod of 0 if not allowed to have them be implicit, and
2924617a3babSopenharmony_ci        // we would otherwise be about to issue an implicit instruction
2925617a3babSopenharmony_ci        mask = (ImageOperandsMask)(mask | ImageOperandsLodMask);
2926617a3babSopenharmony_ci        texArgs.push_back(makeFloatConstant(0.0));
2927617a3babSopenharmony_ci        explicitLod = true;
2928617a3babSopenharmony_ci    }
2929617a3babSopenharmony_ci    if (parameters.offset) {
2930617a3babSopenharmony_ci        if (isConstant(parameters.offset))
2931617a3babSopenharmony_ci            mask = (ImageOperandsMask)(mask | ImageOperandsConstOffsetMask);
2932617a3babSopenharmony_ci        else {
2933617a3babSopenharmony_ci            addCapability(CapabilityImageGatherExtended);
2934617a3babSopenharmony_ci            mask = (ImageOperandsMask)(mask | ImageOperandsOffsetMask);
2935617a3babSopenharmony_ci        }
2936617a3babSopenharmony_ci        texArgs.push_back(parameters.offset);
2937617a3babSopenharmony_ci    }
2938617a3babSopenharmony_ci    if (parameters.offsets) {
2939617a3babSopenharmony_ci        addCapability(CapabilityImageGatherExtended);
2940617a3babSopenharmony_ci        mask = (ImageOperandsMask)(mask | ImageOperandsConstOffsetsMask);
2941617a3babSopenharmony_ci        texArgs.push_back(parameters.offsets);
2942617a3babSopenharmony_ci    }
2943617a3babSopenharmony_ci    if (parameters.sample) {
2944617a3babSopenharmony_ci        mask = (ImageOperandsMask)(mask | ImageOperandsSampleMask);
2945617a3babSopenharmony_ci        texArgs.push_back(parameters.sample);
2946617a3babSopenharmony_ci    }
2947617a3babSopenharmony_ci    if (parameters.lodClamp) {
2948617a3babSopenharmony_ci        // capability if this bit is used
2949617a3babSopenharmony_ci        addCapability(CapabilityMinLod);
2950617a3babSopenharmony_ci
2951617a3babSopenharmony_ci        mask = (ImageOperandsMask)(mask | ImageOperandsMinLodMask);
2952617a3babSopenharmony_ci        texArgs.push_back(parameters.lodClamp);
2953617a3babSopenharmony_ci    }
2954617a3babSopenharmony_ci    if (parameters.nonprivate) {
2955617a3babSopenharmony_ci        mask = mask | ImageOperandsNonPrivateTexelKHRMask;
2956617a3babSopenharmony_ci    }
2957617a3babSopenharmony_ci    if (parameters.volatil) {
2958617a3babSopenharmony_ci        mask = mask | ImageOperandsVolatileTexelKHRMask;
2959617a3babSopenharmony_ci    }
2960617a3babSopenharmony_ci    mask = mask | signExtensionMask;
2961617a3babSopenharmony_ci    // insert the operand for the mask, if any bits were set.
2962617a3babSopenharmony_ci    if (mask != ImageOperandsMaskNone)
2963617a3babSopenharmony_ci        texArgs.insert(texArgs.begin() + optArgNum, mask);
2964617a3babSopenharmony_ci
2965617a3babSopenharmony_ci    //
2966617a3babSopenharmony_ci    // Set up the instruction
2967617a3babSopenharmony_ci    //
2968617a3babSopenharmony_ci    Op opCode = OpNop;  // All paths below need to set this
2969617a3babSopenharmony_ci    if (fetch) {
2970617a3babSopenharmony_ci        if (sparse)
2971617a3babSopenharmony_ci            opCode = OpImageSparseFetch;
2972617a3babSopenharmony_ci        else
2973617a3babSopenharmony_ci            opCode = OpImageFetch;
2974617a3babSopenharmony_ci    } else if (parameters.granularity && parameters.coarse) {
2975617a3babSopenharmony_ci        opCode = OpImageSampleFootprintNV;
2976617a3babSopenharmony_ci    } else if (gather) {
2977617a3babSopenharmony_ci        if (parameters.Dref)
2978617a3babSopenharmony_ci            if (sparse)
2979617a3babSopenharmony_ci                opCode = OpImageSparseDrefGather;
2980617a3babSopenharmony_ci            else
2981617a3babSopenharmony_ci                opCode = OpImageDrefGather;
2982617a3babSopenharmony_ci        else
2983617a3babSopenharmony_ci            if (sparse)
2984617a3babSopenharmony_ci                opCode = OpImageSparseGather;
2985617a3babSopenharmony_ci            else
2986617a3babSopenharmony_ci                opCode = OpImageGather;
2987617a3babSopenharmony_ci    } else if (explicitLod) {
2988617a3babSopenharmony_ci        if (parameters.Dref) {
2989617a3babSopenharmony_ci            if (proj)
2990617a3babSopenharmony_ci                if (sparse)
2991617a3babSopenharmony_ci                    opCode = OpImageSparseSampleProjDrefExplicitLod;
2992617a3babSopenharmony_ci                else
2993617a3babSopenharmony_ci                    opCode = OpImageSampleProjDrefExplicitLod;
2994617a3babSopenharmony_ci            else
2995617a3babSopenharmony_ci                if (sparse)
2996617a3babSopenharmony_ci                    opCode = OpImageSparseSampleDrefExplicitLod;
2997617a3babSopenharmony_ci                else
2998617a3babSopenharmony_ci                    opCode = OpImageSampleDrefExplicitLod;
2999617a3babSopenharmony_ci        } else {
3000617a3babSopenharmony_ci            if (proj)
3001617a3babSopenharmony_ci                if (sparse)
3002617a3babSopenharmony_ci                    opCode = OpImageSparseSampleProjExplicitLod;
3003617a3babSopenharmony_ci                else
3004617a3babSopenharmony_ci                    opCode = OpImageSampleProjExplicitLod;
3005617a3babSopenharmony_ci            else
3006617a3babSopenharmony_ci                if (sparse)
3007617a3babSopenharmony_ci                    opCode = OpImageSparseSampleExplicitLod;
3008617a3babSopenharmony_ci                else
3009617a3babSopenharmony_ci                    opCode = OpImageSampleExplicitLod;
3010617a3babSopenharmony_ci        }
3011617a3babSopenharmony_ci    } else {
3012617a3babSopenharmony_ci        if (parameters.Dref) {
3013617a3babSopenharmony_ci            if (proj)
3014617a3babSopenharmony_ci                if (sparse)
3015617a3babSopenharmony_ci                    opCode = OpImageSparseSampleProjDrefImplicitLod;
3016617a3babSopenharmony_ci                else
3017617a3babSopenharmony_ci                    opCode = OpImageSampleProjDrefImplicitLod;
3018617a3babSopenharmony_ci            else
3019617a3babSopenharmony_ci                if (sparse)
3020617a3babSopenharmony_ci                    opCode = OpImageSparseSampleDrefImplicitLod;
3021617a3babSopenharmony_ci                else
3022617a3babSopenharmony_ci                    opCode = OpImageSampleDrefImplicitLod;
3023617a3babSopenharmony_ci        } else {
3024617a3babSopenharmony_ci            if (proj)
3025617a3babSopenharmony_ci                if (sparse)
3026617a3babSopenharmony_ci                    opCode = OpImageSparseSampleProjImplicitLod;
3027617a3babSopenharmony_ci                else
3028617a3babSopenharmony_ci                    opCode = OpImageSampleProjImplicitLod;
3029617a3babSopenharmony_ci            else
3030617a3babSopenharmony_ci                if (sparse)
3031617a3babSopenharmony_ci                    opCode = OpImageSparseSampleImplicitLod;
3032617a3babSopenharmony_ci                else
3033617a3babSopenharmony_ci                    opCode = OpImageSampleImplicitLod;
3034617a3babSopenharmony_ci        }
3035617a3babSopenharmony_ci    }
3036617a3babSopenharmony_ci
3037617a3babSopenharmony_ci    // See if the result type is expecting a smeared result.
3038617a3babSopenharmony_ci    // This happens when a legacy shadow*() call is made, which
3039617a3babSopenharmony_ci    // gets a vec4 back instead of a float.
3040617a3babSopenharmony_ci    Id smearedType = resultType;
3041617a3babSopenharmony_ci    if (! isScalarType(resultType)) {
3042617a3babSopenharmony_ci        switch (opCode) {
3043617a3babSopenharmony_ci        case OpImageSampleDrefImplicitLod:
3044617a3babSopenharmony_ci        case OpImageSampleDrefExplicitLod:
3045617a3babSopenharmony_ci        case OpImageSampleProjDrefImplicitLod:
3046617a3babSopenharmony_ci        case OpImageSampleProjDrefExplicitLod:
3047617a3babSopenharmony_ci            resultType = getScalarTypeId(resultType);
3048617a3babSopenharmony_ci            break;
3049617a3babSopenharmony_ci        default:
3050617a3babSopenharmony_ci            break;
3051617a3babSopenharmony_ci        }
3052617a3babSopenharmony_ci    }
3053617a3babSopenharmony_ci
3054617a3babSopenharmony_ci    Id typeId0 = 0;
3055617a3babSopenharmony_ci    Id typeId1 = 0;
3056617a3babSopenharmony_ci
3057617a3babSopenharmony_ci    if (sparse) {
3058617a3babSopenharmony_ci        typeId0 = resultType;
3059617a3babSopenharmony_ci        typeId1 = getDerefTypeId(parameters.texelOut);
3060617a3babSopenharmony_ci        resultType = makeStructResultType(typeId0, typeId1);
3061617a3babSopenharmony_ci    }
3062617a3babSopenharmony_ci
3063617a3babSopenharmony_ci    // Build the SPIR-V instruction
3064617a3babSopenharmony_ci    Instruction* textureInst = new Instruction(getUniqueId(), resultType, opCode);
3065617a3babSopenharmony_ci    for (size_t op = 0; op < optArgNum; ++op)
3066617a3babSopenharmony_ci        textureInst->addIdOperand(texArgs[op]);
3067617a3babSopenharmony_ci    if (optArgNum < texArgs.size())
3068617a3babSopenharmony_ci        textureInst->addImmediateOperand(texArgs[optArgNum]);
3069617a3babSopenharmony_ci    for (size_t op = optArgNum + 1; op < texArgs.size(); ++op)
3070617a3babSopenharmony_ci        textureInst->addIdOperand(texArgs[op]);
3071617a3babSopenharmony_ci    setPrecision(textureInst->getResultId(), precision);
3072617a3babSopenharmony_ci    buildPoint->addInstruction(std::unique_ptr<Instruction>(textureInst));
3073617a3babSopenharmony_ci
3074617a3babSopenharmony_ci    Id resultId = textureInst->getResultId();
3075617a3babSopenharmony_ci
3076617a3babSopenharmony_ci    if (sparse) {
3077617a3babSopenharmony_ci        // set capability
3078617a3babSopenharmony_ci        addCapability(CapabilitySparseResidency);
3079617a3babSopenharmony_ci
3080617a3babSopenharmony_ci        // Decode the return type that was a special structure
3081617a3babSopenharmony_ci        createStore(createCompositeExtract(resultId, typeId1, 1), parameters.texelOut);
3082617a3babSopenharmony_ci        resultId = createCompositeExtract(resultId, typeId0, 0);
3083617a3babSopenharmony_ci        setPrecision(resultId, precision);
3084617a3babSopenharmony_ci    } else {
3085617a3babSopenharmony_ci        // When a smear is needed, do it, as per what was computed
3086617a3babSopenharmony_ci        // above when resultType was changed to a scalar type.
3087617a3babSopenharmony_ci        if (resultType != smearedType)
3088617a3babSopenharmony_ci            resultId = smearScalar(precision, resultId, smearedType);
3089617a3babSopenharmony_ci    }
3090617a3babSopenharmony_ci
3091617a3babSopenharmony_ci    return resultId;
3092617a3babSopenharmony_ci}
3093617a3babSopenharmony_ci
3094617a3babSopenharmony_ci// Comments in header
3095617a3babSopenharmony_ciId Builder::createTextureQueryCall(Op opCode, const TextureParameters& parameters, bool isUnsignedResult)
3096617a3babSopenharmony_ci{
3097617a3babSopenharmony_ci    // Figure out the result type
3098617a3babSopenharmony_ci    Id resultType = 0;
3099617a3babSopenharmony_ci    switch (opCode) {
3100617a3babSopenharmony_ci    case OpImageQuerySize:
3101617a3babSopenharmony_ci    case OpImageQuerySizeLod:
3102617a3babSopenharmony_ci    {
3103617a3babSopenharmony_ci        int numComponents = 0;
3104617a3babSopenharmony_ci        switch (getTypeDimensionality(getImageType(parameters.sampler))) {
3105617a3babSopenharmony_ci        case Dim1D:
3106617a3babSopenharmony_ci        case DimBuffer:
3107617a3babSopenharmony_ci            numComponents = 1;
3108617a3babSopenharmony_ci            break;
3109617a3babSopenharmony_ci        case Dim2D:
3110617a3babSopenharmony_ci        case DimCube:
3111617a3babSopenharmony_ci        case DimRect:
3112617a3babSopenharmony_ci        case DimSubpassData:
3113617a3babSopenharmony_ci            numComponents = 2;
3114617a3babSopenharmony_ci            break;
3115617a3babSopenharmony_ci        case Dim3D:
3116617a3babSopenharmony_ci            numComponents = 3;
3117617a3babSopenharmony_ci            break;
3118617a3babSopenharmony_ci
3119617a3babSopenharmony_ci        default:
3120617a3babSopenharmony_ci            assert(0);
3121617a3babSopenharmony_ci            break;
3122617a3babSopenharmony_ci        }
3123617a3babSopenharmony_ci        if (isArrayedImageType(getImageType(parameters.sampler)))
3124617a3babSopenharmony_ci            ++numComponents;
3125617a3babSopenharmony_ci
3126617a3babSopenharmony_ci        Id intType = isUnsignedResult ? makeUintType(32) : makeIntType(32);
3127617a3babSopenharmony_ci        if (numComponents == 1)
3128617a3babSopenharmony_ci            resultType = intType;
3129617a3babSopenharmony_ci        else
3130617a3babSopenharmony_ci            resultType = makeVectorType(intType, numComponents);
3131617a3babSopenharmony_ci
3132617a3babSopenharmony_ci        break;
3133617a3babSopenharmony_ci    }
3134617a3babSopenharmony_ci    case OpImageQueryLod:
3135617a3babSopenharmony_ci        resultType = makeVectorType(getScalarTypeId(getTypeId(parameters.coords)), 2);
3136617a3babSopenharmony_ci        break;
3137617a3babSopenharmony_ci    case OpImageQueryLevels:
3138617a3babSopenharmony_ci    case OpImageQuerySamples:
3139617a3babSopenharmony_ci        resultType = isUnsignedResult ? makeUintType(32) : makeIntType(32);
3140617a3babSopenharmony_ci        break;
3141617a3babSopenharmony_ci    default:
3142617a3babSopenharmony_ci        assert(0);
3143617a3babSopenharmony_ci        break;
3144617a3babSopenharmony_ci    }
3145617a3babSopenharmony_ci
3146617a3babSopenharmony_ci    Instruction* query = new Instruction(getUniqueId(), resultType, opCode);
3147617a3babSopenharmony_ci    query->addIdOperand(parameters.sampler);
3148617a3babSopenharmony_ci    if (parameters.coords)
3149617a3babSopenharmony_ci        query->addIdOperand(parameters.coords);
3150617a3babSopenharmony_ci    if (parameters.lod)
3151617a3babSopenharmony_ci        query->addIdOperand(parameters.lod);
3152617a3babSopenharmony_ci    buildPoint->addInstruction(std::unique_ptr<Instruction>(query));
3153617a3babSopenharmony_ci    addCapability(CapabilityImageQuery);
3154617a3babSopenharmony_ci
3155617a3babSopenharmony_ci    return query->getResultId();
3156617a3babSopenharmony_ci}
3157617a3babSopenharmony_ci
3158617a3babSopenharmony_ci// External comments in header.
3159617a3babSopenharmony_ci// Operates recursively to visit the composite's hierarchy.
3160617a3babSopenharmony_ciId Builder::createCompositeCompare(Decoration precision, Id value1, Id value2, bool equal)
3161617a3babSopenharmony_ci{
3162617a3babSopenharmony_ci    Id boolType = makeBoolType();
3163617a3babSopenharmony_ci    Id valueType = getTypeId(value1);
3164617a3babSopenharmony_ci
3165617a3babSopenharmony_ci    Id resultId = NoResult;
3166617a3babSopenharmony_ci
3167617a3babSopenharmony_ci    int numConstituents = getNumTypeConstituents(valueType);
3168617a3babSopenharmony_ci
3169617a3babSopenharmony_ci    // Scalars and Vectors
3170617a3babSopenharmony_ci
3171617a3babSopenharmony_ci    if (isScalarType(valueType) || isVectorType(valueType)) {
3172617a3babSopenharmony_ci        assert(valueType == getTypeId(value2));
3173617a3babSopenharmony_ci        // These just need a single comparison, just have
3174617a3babSopenharmony_ci        // to figure out what it is.
3175617a3babSopenharmony_ci        Op op;
3176617a3babSopenharmony_ci        switch (getMostBasicTypeClass(valueType)) {
3177617a3babSopenharmony_ci        case OpTypeFloat:
3178617a3babSopenharmony_ci            op = equal ? OpFOrdEqual : OpFUnordNotEqual;
3179617a3babSopenharmony_ci            break;
3180617a3babSopenharmony_ci        case OpTypeInt:
3181617a3babSopenharmony_ci        default:
3182617a3babSopenharmony_ci            op = equal ? OpIEqual : OpINotEqual;
3183617a3babSopenharmony_ci            break;
3184617a3babSopenharmony_ci        case OpTypeBool:
3185617a3babSopenharmony_ci            op = equal ? OpLogicalEqual : OpLogicalNotEqual;
3186617a3babSopenharmony_ci            precision = NoPrecision;
3187617a3babSopenharmony_ci            break;
3188617a3babSopenharmony_ci        }
3189617a3babSopenharmony_ci
3190617a3babSopenharmony_ci        if (isScalarType(valueType)) {
3191617a3babSopenharmony_ci            // scalar
3192617a3babSopenharmony_ci            resultId = createBinOp(op, boolType, value1, value2);
3193617a3babSopenharmony_ci        } else {
3194617a3babSopenharmony_ci            // vector
3195617a3babSopenharmony_ci            resultId = createBinOp(op, makeVectorType(boolType, numConstituents), value1, value2);
3196617a3babSopenharmony_ci            setPrecision(resultId, precision);
3197617a3babSopenharmony_ci            // reduce vector compares...
3198617a3babSopenharmony_ci            resultId = createUnaryOp(equal ? OpAll : OpAny, boolType, resultId);
3199617a3babSopenharmony_ci        }
3200617a3babSopenharmony_ci
3201617a3babSopenharmony_ci        return setPrecision(resultId, precision);
3202617a3babSopenharmony_ci    }
3203617a3babSopenharmony_ci
3204617a3babSopenharmony_ci    // Only structs, arrays, and matrices should be left.
3205617a3babSopenharmony_ci    // They share in common the reduction operation across their constituents.
3206617a3babSopenharmony_ci    assert(isAggregateType(valueType) || isMatrixType(valueType));
3207617a3babSopenharmony_ci
3208617a3babSopenharmony_ci    // Compare each pair of constituents
3209617a3babSopenharmony_ci    for (int constituent = 0; constituent < numConstituents; ++constituent) {
3210617a3babSopenharmony_ci        std::vector<unsigned> indexes(1, constituent);
3211617a3babSopenharmony_ci        Id constituentType1 = getContainedTypeId(getTypeId(value1), constituent);
3212617a3babSopenharmony_ci        Id constituentType2 = getContainedTypeId(getTypeId(value2), constituent);
3213617a3babSopenharmony_ci        Id constituent1 = createCompositeExtract(value1, constituentType1, indexes);
3214617a3babSopenharmony_ci        Id constituent2 = createCompositeExtract(value2, constituentType2, indexes);
3215617a3babSopenharmony_ci
3216617a3babSopenharmony_ci        Id subResultId = createCompositeCompare(precision, constituent1, constituent2, equal);
3217617a3babSopenharmony_ci
3218617a3babSopenharmony_ci        if (constituent == 0)
3219617a3babSopenharmony_ci            resultId = subResultId;
3220617a3babSopenharmony_ci        else
3221617a3babSopenharmony_ci            resultId = setPrecision(createBinOp(equal ? OpLogicalAnd : OpLogicalOr, boolType, resultId, subResultId),
3222617a3babSopenharmony_ci                                    precision);
3223617a3babSopenharmony_ci    }
3224617a3babSopenharmony_ci
3225617a3babSopenharmony_ci    return resultId;
3226617a3babSopenharmony_ci}
3227617a3babSopenharmony_ci
3228617a3babSopenharmony_ci// OpCompositeConstruct
3229617a3babSopenharmony_ciId Builder::createCompositeConstruct(Id typeId, const std::vector<Id>& constituents)
3230617a3babSopenharmony_ci{
3231617a3babSopenharmony_ci    assert(isAggregateType(typeId) || (getNumTypeConstituents(typeId) > 1 &&
3232617a3babSopenharmony_ci           getNumTypeConstituents(typeId) == (int)constituents.size()));
3233617a3babSopenharmony_ci
3234617a3babSopenharmony_ci    if (generatingOpCodeForSpecConst) {
3235617a3babSopenharmony_ci        // Sometime, even in spec-constant-op mode, the constant composite to be
3236617a3babSopenharmony_ci        // constructed may not be a specialization constant.
3237617a3babSopenharmony_ci        // e.g.:
3238617a3babSopenharmony_ci        //  const mat2 m2 = mat2(a_spec_const, a_front_end_const, another_front_end_const, third_front_end_const);
3239617a3babSopenharmony_ci        // The first column vector should be a spec constant one, as a_spec_const is a spec constant.
3240617a3babSopenharmony_ci        // The second column vector should NOT be spec constant, as it does not contain any spec constants.
3241617a3babSopenharmony_ci        // To handle such cases, we check the constituents of the constant vector to determine whether this
3242617a3babSopenharmony_ci        // vector should be created as a spec constant.
3243617a3babSopenharmony_ci        return makeCompositeConstant(typeId, constituents,
3244617a3babSopenharmony_ci                                     std::any_of(constituents.begin(), constituents.end(),
3245617a3babSopenharmony_ci                                                 [&](spv::Id id) { return isSpecConstant(id); }));
3246617a3babSopenharmony_ci    }
3247617a3babSopenharmony_ci
3248617a3babSopenharmony_ci    Instruction* op = new Instruction(getUniqueId(), typeId, OpCompositeConstruct);
3249617a3babSopenharmony_ci    for (int c = 0; c < (int)constituents.size(); ++c)
3250617a3babSopenharmony_ci        op->addIdOperand(constituents[c]);
3251617a3babSopenharmony_ci    buildPoint->addInstruction(std::unique_ptr<Instruction>(op));
3252617a3babSopenharmony_ci
3253617a3babSopenharmony_ci    return op->getResultId();
3254617a3babSopenharmony_ci}
3255617a3babSopenharmony_ci
3256617a3babSopenharmony_ci// Vector or scalar constructor
3257617a3babSopenharmony_ciId Builder::createConstructor(Decoration precision, const std::vector<Id>& sources, Id resultTypeId)
3258617a3babSopenharmony_ci{
3259617a3babSopenharmony_ci    Id result = NoResult;
3260617a3babSopenharmony_ci    unsigned int numTargetComponents = getNumTypeComponents(resultTypeId);
3261617a3babSopenharmony_ci    unsigned int targetComponent = 0;
3262617a3babSopenharmony_ci
3263617a3babSopenharmony_ci    // Special case: when calling a vector constructor with a single scalar
3264617a3babSopenharmony_ci    // argument, smear the scalar
3265617a3babSopenharmony_ci    if (sources.size() == 1 && isScalar(sources[0]) && numTargetComponents > 1)
3266617a3babSopenharmony_ci        return smearScalar(precision, sources[0], resultTypeId);
3267617a3babSopenharmony_ci
3268617a3babSopenharmony_ci    // accumulate the arguments for OpCompositeConstruct
3269617a3babSopenharmony_ci    std::vector<Id> constituents;
3270617a3babSopenharmony_ci    Id scalarTypeId = getScalarTypeId(resultTypeId);
3271617a3babSopenharmony_ci
3272617a3babSopenharmony_ci    // lambda to store the result of visiting an argument component
3273617a3babSopenharmony_ci    const auto latchResult = [&](Id comp) {
3274617a3babSopenharmony_ci        if (numTargetComponents > 1)
3275617a3babSopenharmony_ci            constituents.push_back(comp);
3276617a3babSopenharmony_ci        else
3277617a3babSopenharmony_ci            result = comp;
3278617a3babSopenharmony_ci        ++targetComponent;
3279617a3babSopenharmony_ci    };
3280617a3babSopenharmony_ci
3281617a3babSopenharmony_ci    // lambda to visit a vector argument's components
3282617a3babSopenharmony_ci    const auto accumulateVectorConstituents = [&](Id sourceArg) {
3283617a3babSopenharmony_ci        unsigned int sourceSize = getNumComponents(sourceArg);
3284617a3babSopenharmony_ci        unsigned int sourcesToUse = sourceSize;
3285617a3babSopenharmony_ci        if (sourcesToUse + targetComponent > numTargetComponents)
3286617a3babSopenharmony_ci            sourcesToUse = numTargetComponents - targetComponent;
3287617a3babSopenharmony_ci
3288617a3babSopenharmony_ci        for (unsigned int s = 0; s < sourcesToUse; ++s) {
3289617a3babSopenharmony_ci            std::vector<unsigned> swiz;
3290617a3babSopenharmony_ci            swiz.push_back(s);
3291617a3babSopenharmony_ci            latchResult(createRvalueSwizzle(precision, scalarTypeId, sourceArg, swiz));
3292617a3babSopenharmony_ci        }
3293617a3babSopenharmony_ci    };
3294617a3babSopenharmony_ci
3295617a3babSopenharmony_ci    // lambda to visit a matrix argument's components
3296617a3babSopenharmony_ci    const auto accumulateMatrixConstituents = [&](Id sourceArg) {
3297617a3babSopenharmony_ci        unsigned int sourceSize = getNumColumns(sourceArg) * getNumRows(sourceArg);
3298617a3babSopenharmony_ci        unsigned int sourcesToUse = sourceSize;
3299617a3babSopenharmony_ci        if (sourcesToUse + targetComponent > numTargetComponents)
3300617a3babSopenharmony_ci            sourcesToUse = numTargetComponents - targetComponent;
3301617a3babSopenharmony_ci
3302617a3babSopenharmony_ci        int col = 0;
3303617a3babSopenharmony_ci        int row = 0;
3304617a3babSopenharmony_ci        for (unsigned int s = 0; s < sourcesToUse; ++s) {
3305617a3babSopenharmony_ci            if (row >= getNumRows(sourceArg)) {
3306617a3babSopenharmony_ci                row = 0;
3307617a3babSopenharmony_ci                col++;
3308617a3babSopenharmony_ci            }
3309617a3babSopenharmony_ci            std::vector<Id> indexes;
3310617a3babSopenharmony_ci            indexes.push_back(col);
3311617a3babSopenharmony_ci            indexes.push_back(row);
3312617a3babSopenharmony_ci            latchResult(createCompositeExtract(sourceArg, scalarTypeId, indexes));
3313617a3babSopenharmony_ci            row++;
3314617a3babSopenharmony_ci        }
3315617a3babSopenharmony_ci    };
3316617a3babSopenharmony_ci
3317617a3babSopenharmony_ci    // Go through the source arguments, each one could have either
3318617a3babSopenharmony_ci    // a single or multiple components to contribute.
3319617a3babSopenharmony_ci    for (unsigned int i = 0; i < sources.size(); ++i) {
3320617a3babSopenharmony_ci
3321617a3babSopenharmony_ci        if (isScalar(sources[i]) || isPointer(sources[i]))
3322617a3babSopenharmony_ci            latchResult(sources[i]);
3323617a3babSopenharmony_ci        else if (isVector(sources[i]))
3324617a3babSopenharmony_ci            accumulateVectorConstituents(sources[i]);
3325617a3babSopenharmony_ci        else if (isMatrix(sources[i]))
3326617a3babSopenharmony_ci            accumulateMatrixConstituents(sources[i]);
3327617a3babSopenharmony_ci        else
3328617a3babSopenharmony_ci            assert(0);
3329617a3babSopenharmony_ci
3330617a3babSopenharmony_ci        if (targetComponent >= numTargetComponents)
3331617a3babSopenharmony_ci            break;
3332617a3babSopenharmony_ci    }
3333617a3babSopenharmony_ci
3334617a3babSopenharmony_ci    // If the result is a vector, make it from the gathered constituents.
3335617a3babSopenharmony_ci    if (constituents.size() > 0)
3336617a3babSopenharmony_ci        result = createCompositeConstruct(resultTypeId, constituents);
3337617a3babSopenharmony_ci
3338617a3babSopenharmony_ci    return setPrecision(result, precision);
3339617a3babSopenharmony_ci}
3340617a3babSopenharmony_ci
3341617a3babSopenharmony_ci// Comments in header
3342617a3babSopenharmony_ciId Builder::createMatrixConstructor(Decoration precision, const std::vector<Id>& sources, Id resultTypeId)
3343617a3babSopenharmony_ci{
3344617a3babSopenharmony_ci    Id componentTypeId = getScalarTypeId(resultTypeId);
3345617a3babSopenharmony_ci    int numCols = getTypeNumColumns(resultTypeId);
3346617a3babSopenharmony_ci    int numRows = getTypeNumRows(resultTypeId);
3347617a3babSopenharmony_ci
3348617a3babSopenharmony_ci    Instruction* instr = module.getInstruction(componentTypeId);
3349617a3babSopenharmony_ci    const unsigned bitCount = instr->getImmediateOperand(0);
3350617a3babSopenharmony_ci
3351617a3babSopenharmony_ci    // Optimize matrix constructed from a bigger matrix
3352617a3babSopenharmony_ci    if (isMatrix(sources[0]) && getNumColumns(sources[0]) >= numCols && getNumRows(sources[0]) >= numRows) {
3353617a3babSopenharmony_ci        // To truncate the matrix to a smaller number of rows/columns, we need to:
3354617a3babSopenharmony_ci        // 1. For each column, extract the column and truncate it to the required size using shuffle
3355617a3babSopenharmony_ci        // 2. Assemble the resulting matrix from all columns
3356617a3babSopenharmony_ci        Id matrix = sources[0];
3357617a3babSopenharmony_ci        Id columnTypeId = getContainedTypeId(resultTypeId);
3358617a3babSopenharmony_ci        Id sourceColumnTypeId = getContainedTypeId(getTypeId(matrix));
3359617a3babSopenharmony_ci
3360617a3babSopenharmony_ci        std::vector<unsigned> channels;
3361617a3babSopenharmony_ci        for (int row = 0; row < numRows; ++row)
3362617a3babSopenharmony_ci            channels.push_back(row);
3363617a3babSopenharmony_ci
3364617a3babSopenharmony_ci        std::vector<Id> matrixColumns;
3365617a3babSopenharmony_ci        for (int col = 0; col < numCols; ++col) {
3366617a3babSopenharmony_ci            std::vector<unsigned> indexes;
3367617a3babSopenharmony_ci            indexes.push_back(col);
3368617a3babSopenharmony_ci            Id colv = createCompositeExtract(matrix, sourceColumnTypeId, indexes);
3369617a3babSopenharmony_ci            setPrecision(colv, precision);
3370617a3babSopenharmony_ci
3371617a3babSopenharmony_ci            if (numRows != getNumRows(matrix)) {
3372617a3babSopenharmony_ci                matrixColumns.push_back(createRvalueSwizzle(precision, columnTypeId, colv, channels));
3373617a3babSopenharmony_ci            } else {
3374617a3babSopenharmony_ci                matrixColumns.push_back(colv);
3375617a3babSopenharmony_ci            }
3376617a3babSopenharmony_ci        }
3377617a3babSopenharmony_ci
3378617a3babSopenharmony_ci        return setPrecision(createCompositeConstruct(resultTypeId, matrixColumns), precision);
3379617a3babSopenharmony_ci    }
3380617a3babSopenharmony_ci
3381617a3babSopenharmony_ci    // Otherwise, will use a two step process
3382617a3babSopenharmony_ci    // 1. make a compile-time 2D array of values
3383617a3babSopenharmony_ci    // 2. construct a matrix from that array
3384617a3babSopenharmony_ci
3385617a3babSopenharmony_ci    // Step 1.
3386617a3babSopenharmony_ci
3387617a3babSopenharmony_ci    // initialize the array to the identity matrix
3388617a3babSopenharmony_ci    Id ids[maxMatrixSize][maxMatrixSize];
3389617a3babSopenharmony_ci    Id  one = (bitCount == 64 ? makeDoubleConstant(1.0) : makeFloatConstant(1.0));
3390617a3babSopenharmony_ci    Id zero = (bitCount == 64 ? makeDoubleConstant(0.0) : makeFloatConstant(0.0));
3391617a3babSopenharmony_ci    for (int col = 0; col < 4; ++col) {
3392617a3babSopenharmony_ci        for (int row = 0; row < 4; ++row) {
3393617a3babSopenharmony_ci            if (col == row)
3394617a3babSopenharmony_ci                ids[col][row] = one;
3395617a3babSopenharmony_ci            else
3396617a3babSopenharmony_ci                ids[col][row] = zero;
3397617a3babSopenharmony_ci        }
3398617a3babSopenharmony_ci    }
3399617a3babSopenharmony_ci
3400617a3babSopenharmony_ci    // modify components as dictated by the arguments
3401617a3babSopenharmony_ci    if (sources.size() == 1 && isScalar(sources[0])) {
3402617a3babSopenharmony_ci        // a single scalar; resets the diagonals
3403617a3babSopenharmony_ci        for (int col = 0; col < 4; ++col)
3404617a3babSopenharmony_ci            ids[col][col] = sources[0];
3405617a3babSopenharmony_ci    } else if (isMatrix(sources[0])) {
3406617a3babSopenharmony_ci        // constructing from another matrix; copy over the parts that exist in both the argument and constructee
3407617a3babSopenharmony_ci        Id matrix = sources[0];
3408617a3babSopenharmony_ci        int minCols = std::min(numCols, getNumColumns(matrix));
3409617a3babSopenharmony_ci        int minRows = std::min(numRows, getNumRows(matrix));
3410617a3babSopenharmony_ci        for (int col = 0; col < minCols; ++col) {
3411617a3babSopenharmony_ci            std::vector<unsigned> indexes;
3412617a3babSopenharmony_ci            indexes.push_back(col);
3413617a3babSopenharmony_ci            for (int row = 0; row < minRows; ++row) {
3414617a3babSopenharmony_ci                indexes.push_back(row);
3415617a3babSopenharmony_ci                ids[col][row] = createCompositeExtract(matrix, componentTypeId, indexes);
3416617a3babSopenharmony_ci                indexes.pop_back();
3417617a3babSopenharmony_ci                setPrecision(ids[col][row], precision);
3418617a3babSopenharmony_ci            }
3419617a3babSopenharmony_ci        }
3420617a3babSopenharmony_ci    } else {
3421617a3babSopenharmony_ci        // fill in the matrix in column-major order with whatever argument components are available
3422617a3babSopenharmony_ci        int row = 0;
3423617a3babSopenharmony_ci        int col = 0;
3424617a3babSopenharmony_ci
3425617a3babSopenharmony_ci        for (int arg = 0; arg < (int)sources.size() && col < numCols; ++arg) {
3426617a3babSopenharmony_ci            Id argComp = sources[arg];
3427617a3babSopenharmony_ci            for (int comp = 0; comp < getNumComponents(sources[arg]); ++comp) {
3428617a3babSopenharmony_ci                if (getNumComponents(sources[arg]) > 1) {
3429617a3babSopenharmony_ci                    argComp = createCompositeExtract(sources[arg], componentTypeId, comp);
3430617a3babSopenharmony_ci                    setPrecision(argComp, precision);
3431617a3babSopenharmony_ci                }
3432617a3babSopenharmony_ci                ids[col][row++] = argComp;
3433617a3babSopenharmony_ci                if (row == numRows) {
3434617a3babSopenharmony_ci                    row = 0;
3435617a3babSopenharmony_ci                    col++;
3436617a3babSopenharmony_ci                }
3437617a3babSopenharmony_ci                if (col == numCols) {
3438617a3babSopenharmony_ci                    // If more components are provided than fit the matrix, discard the rest.
3439617a3babSopenharmony_ci                    break;
3440617a3babSopenharmony_ci                }
3441617a3babSopenharmony_ci            }
3442617a3babSopenharmony_ci        }
3443617a3babSopenharmony_ci    }
3444617a3babSopenharmony_ci
3445617a3babSopenharmony_ci    // Step 2:  Construct a matrix from that array.
3446617a3babSopenharmony_ci    // First make the column vectors, then make the matrix.
3447617a3babSopenharmony_ci
3448617a3babSopenharmony_ci    // make the column vectors
3449617a3babSopenharmony_ci    Id columnTypeId = getContainedTypeId(resultTypeId);
3450617a3babSopenharmony_ci    std::vector<Id> matrixColumns;
3451617a3babSopenharmony_ci    for (int col = 0; col < numCols; ++col) {
3452617a3babSopenharmony_ci        std::vector<Id> vectorComponents;
3453617a3babSopenharmony_ci        for (int row = 0; row < numRows; ++row)
3454617a3babSopenharmony_ci            vectorComponents.push_back(ids[col][row]);
3455617a3babSopenharmony_ci        Id column = createCompositeConstruct(columnTypeId, vectorComponents);
3456617a3babSopenharmony_ci        setPrecision(column, precision);
3457617a3babSopenharmony_ci        matrixColumns.push_back(column);
3458617a3babSopenharmony_ci    }
3459617a3babSopenharmony_ci
3460617a3babSopenharmony_ci    // make the matrix
3461617a3babSopenharmony_ci    return setPrecision(createCompositeConstruct(resultTypeId, matrixColumns), precision);
3462617a3babSopenharmony_ci}
3463617a3babSopenharmony_ci
3464617a3babSopenharmony_ci// Comments in header
3465617a3babSopenharmony_ciBuilder::If::If(Id cond, unsigned int ctrl, Builder& gb) :
3466617a3babSopenharmony_ci    builder(gb),
3467617a3babSopenharmony_ci    condition(cond),
3468617a3babSopenharmony_ci    control(ctrl),
3469617a3babSopenharmony_ci    elseBlock(nullptr)
3470617a3babSopenharmony_ci{
3471617a3babSopenharmony_ci    function = &builder.getBuildPoint()->getParent();
3472617a3babSopenharmony_ci
3473617a3babSopenharmony_ci    // make the blocks, but only put the then-block into the function,
3474617a3babSopenharmony_ci    // the else-block and merge-block will be added later, in order, after
3475617a3babSopenharmony_ci    // earlier code is emitted
3476617a3babSopenharmony_ci    thenBlock = new Block(builder.getUniqueId(), *function);
3477617a3babSopenharmony_ci    mergeBlock = new Block(builder.getUniqueId(), *function);
3478617a3babSopenharmony_ci
3479617a3babSopenharmony_ci    // Save the current block, so that we can add in the flow control split when
3480617a3babSopenharmony_ci    // makeEndIf is called.
3481617a3babSopenharmony_ci    headerBlock = builder.getBuildPoint();
3482617a3babSopenharmony_ci
3483617a3babSopenharmony_ci    function->addBlock(thenBlock);
3484617a3babSopenharmony_ci    builder.setBuildPoint(thenBlock);
3485617a3babSopenharmony_ci}
3486617a3babSopenharmony_ci
3487617a3babSopenharmony_ci// Comments in header
3488617a3babSopenharmony_civoid Builder::If::makeBeginElse()
3489617a3babSopenharmony_ci{
3490617a3babSopenharmony_ci    // Close out the "then" by having it jump to the mergeBlock
3491617a3babSopenharmony_ci    builder.createBranch(mergeBlock);
3492617a3babSopenharmony_ci
3493617a3babSopenharmony_ci    // Make the first else block and add it to the function
3494617a3babSopenharmony_ci    elseBlock = new Block(builder.getUniqueId(), *function);
3495617a3babSopenharmony_ci    function->addBlock(elseBlock);
3496617a3babSopenharmony_ci
3497617a3babSopenharmony_ci    // Start building the else block
3498617a3babSopenharmony_ci    builder.setBuildPoint(elseBlock);
3499617a3babSopenharmony_ci}
3500617a3babSopenharmony_ci
3501617a3babSopenharmony_ci// Comments in header
3502617a3babSopenharmony_civoid Builder::If::makeEndIf()
3503617a3babSopenharmony_ci{
3504617a3babSopenharmony_ci    // jump to the merge block
3505617a3babSopenharmony_ci    builder.createBranch(mergeBlock);
3506617a3babSopenharmony_ci
3507617a3babSopenharmony_ci    // Go back to the headerBlock and make the flow control split
3508617a3babSopenharmony_ci    builder.setBuildPoint(headerBlock);
3509617a3babSopenharmony_ci    builder.createSelectionMerge(mergeBlock, control);
3510617a3babSopenharmony_ci    if (elseBlock)
3511617a3babSopenharmony_ci        builder.createConditionalBranch(condition, thenBlock, elseBlock);
3512617a3babSopenharmony_ci    else
3513617a3babSopenharmony_ci        builder.createConditionalBranch(condition, thenBlock, mergeBlock);
3514617a3babSopenharmony_ci
3515617a3babSopenharmony_ci    // add the merge block to the function
3516617a3babSopenharmony_ci    function->addBlock(mergeBlock);
3517617a3babSopenharmony_ci    builder.setBuildPoint(mergeBlock);
3518617a3babSopenharmony_ci}
3519617a3babSopenharmony_ci
3520617a3babSopenharmony_ci// Comments in header
3521617a3babSopenharmony_civoid Builder::makeSwitch(Id selector, unsigned int control, int numSegments, const std::vector<int>& caseValues,
3522617a3babSopenharmony_ci                         const std::vector<int>& valueIndexToSegment, int defaultSegment,
3523617a3babSopenharmony_ci                         std::vector<Block*>& segmentBlocks)
3524617a3babSopenharmony_ci{
3525617a3babSopenharmony_ci    Function& function = buildPoint->getParent();
3526617a3babSopenharmony_ci
3527617a3babSopenharmony_ci    // make all the blocks
3528617a3babSopenharmony_ci    for (int s = 0; s < numSegments; ++s)
3529617a3babSopenharmony_ci        segmentBlocks.push_back(new Block(getUniqueId(), function));
3530617a3babSopenharmony_ci
3531617a3babSopenharmony_ci    Block* mergeBlock = new Block(getUniqueId(), function);
3532617a3babSopenharmony_ci
3533617a3babSopenharmony_ci    // make and insert the switch's selection-merge instruction
3534617a3babSopenharmony_ci    createSelectionMerge(mergeBlock, control);
3535617a3babSopenharmony_ci
3536617a3babSopenharmony_ci    // make the switch instruction
3537617a3babSopenharmony_ci    Instruction* switchInst = new Instruction(NoResult, NoType, OpSwitch);
3538617a3babSopenharmony_ci    switchInst->addIdOperand(selector);
3539617a3babSopenharmony_ci    auto defaultOrMerge = (defaultSegment >= 0) ? segmentBlocks[defaultSegment] : mergeBlock;
3540617a3babSopenharmony_ci    switchInst->addIdOperand(defaultOrMerge->getId());
3541617a3babSopenharmony_ci    defaultOrMerge->addPredecessor(buildPoint);
3542617a3babSopenharmony_ci    for (int i = 0; i < (int)caseValues.size(); ++i) {
3543617a3babSopenharmony_ci        switchInst->addImmediateOperand(caseValues[i]);
3544617a3babSopenharmony_ci        switchInst->addIdOperand(segmentBlocks[valueIndexToSegment[i]]->getId());
3545617a3babSopenharmony_ci        segmentBlocks[valueIndexToSegment[i]]->addPredecessor(buildPoint);
3546617a3babSopenharmony_ci    }
3547617a3babSopenharmony_ci    buildPoint->addInstruction(std::unique_ptr<Instruction>(switchInst));
3548617a3babSopenharmony_ci
3549617a3babSopenharmony_ci    // push the merge block
3550617a3babSopenharmony_ci    switchMerges.push(mergeBlock);
3551617a3babSopenharmony_ci}
3552617a3babSopenharmony_ci
3553617a3babSopenharmony_ci// Comments in header
3554617a3babSopenharmony_civoid Builder::addSwitchBreak()
3555617a3babSopenharmony_ci{
3556617a3babSopenharmony_ci    // branch to the top of the merge block stack
3557617a3babSopenharmony_ci    createBranch(switchMerges.top());
3558617a3babSopenharmony_ci    createAndSetNoPredecessorBlock("post-switch-break");
3559617a3babSopenharmony_ci}
3560617a3babSopenharmony_ci
3561617a3babSopenharmony_ci// Comments in header
3562617a3babSopenharmony_civoid Builder::nextSwitchSegment(std::vector<Block*>& segmentBlock, int nextSegment)
3563617a3babSopenharmony_ci{
3564617a3babSopenharmony_ci    int lastSegment = nextSegment - 1;
3565617a3babSopenharmony_ci    if (lastSegment >= 0) {
3566617a3babSopenharmony_ci        // Close out previous segment by jumping, if necessary, to next segment
3567617a3babSopenharmony_ci        if (! buildPoint->isTerminated())
3568617a3babSopenharmony_ci            createBranch(segmentBlock[nextSegment]);
3569617a3babSopenharmony_ci    }
3570617a3babSopenharmony_ci    Block* block = segmentBlock[nextSegment];
3571617a3babSopenharmony_ci    block->getParent().addBlock(block);
3572617a3babSopenharmony_ci    setBuildPoint(block);
3573617a3babSopenharmony_ci}
3574617a3babSopenharmony_ci
3575617a3babSopenharmony_ci// Comments in header
3576617a3babSopenharmony_civoid Builder::endSwitch(std::vector<Block*>& /*segmentBlock*/)
3577617a3babSopenharmony_ci{
3578617a3babSopenharmony_ci    // Close out previous segment by jumping, if necessary, to next segment
3579617a3babSopenharmony_ci    if (! buildPoint->isTerminated())
3580617a3babSopenharmony_ci        addSwitchBreak();
3581617a3babSopenharmony_ci
3582617a3babSopenharmony_ci    switchMerges.top()->getParent().addBlock(switchMerges.top());
3583617a3babSopenharmony_ci    setBuildPoint(switchMerges.top());
3584617a3babSopenharmony_ci
3585617a3babSopenharmony_ci    switchMerges.pop();
3586617a3babSopenharmony_ci}
3587617a3babSopenharmony_ci
3588617a3babSopenharmony_ciBlock& Builder::makeNewBlock()
3589617a3babSopenharmony_ci{
3590617a3babSopenharmony_ci    Function& function = buildPoint->getParent();
3591617a3babSopenharmony_ci    auto block = new Block(getUniqueId(), function);
3592617a3babSopenharmony_ci    function.addBlock(block);
3593617a3babSopenharmony_ci    return *block;
3594617a3babSopenharmony_ci}
3595617a3babSopenharmony_ci
3596617a3babSopenharmony_ciBuilder::LoopBlocks& Builder::makeNewLoop()
3597617a3babSopenharmony_ci{
3598617a3babSopenharmony_ci    // This verbosity is needed to simultaneously get the same behavior
3599617a3babSopenharmony_ci    // everywhere (id's in the same order), have a syntax that works
3600617a3babSopenharmony_ci    // across lots of versions of C++, have no warnings from pedantic
3601617a3babSopenharmony_ci    // compilation modes, and leave the rest of the code alone.
3602617a3babSopenharmony_ci    Block& head            = makeNewBlock();
3603617a3babSopenharmony_ci    Block& body            = makeNewBlock();
3604617a3babSopenharmony_ci    Block& merge           = makeNewBlock();
3605617a3babSopenharmony_ci    Block& continue_target = makeNewBlock();
3606617a3babSopenharmony_ci    LoopBlocks blocks(head, body, merge, continue_target);
3607617a3babSopenharmony_ci    loops.push(blocks);
3608617a3babSopenharmony_ci    return loops.top();
3609617a3babSopenharmony_ci}
3610617a3babSopenharmony_ci
3611617a3babSopenharmony_civoid Builder::createLoopContinue()
3612617a3babSopenharmony_ci{
3613617a3babSopenharmony_ci    createBranch(&loops.top().continue_target);
3614617a3babSopenharmony_ci    // Set up a block for dead code.
3615617a3babSopenharmony_ci    createAndSetNoPredecessorBlock("post-loop-continue");
3616617a3babSopenharmony_ci}
3617617a3babSopenharmony_ci
3618617a3babSopenharmony_civoid Builder::createLoopExit()
3619617a3babSopenharmony_ci{
3620617a3babSopenharmony_ci    createBranch(&loops.top().merge);
3621617a3babSopenharmony_ci    // Set up a block for dead code.
3622617a3babSopenharmony_ci    createAndSetNoPredecessorBlock("post-loop-break");
3623617a3babSopenharmony_ci}
3624617a3babSopenharmony_ci
3625617a3babSopenharmony_civoid Builder::closeLoop()
3626617a3babSopenharmony_ci{
3627617a3babSopenharmony_ci    loops.pop();
3628617a3babSopenharmony_ci}
3629617a3babSopenharmony_ci
3630617a3babSopenharmony_civoid Builder::clearAccessChain()
3631617a3babSopenharmony_ci{
3632617a3babSopenharmony_ci    accessChain.base = NoResult;
3633617a3babSopenharmony_ci    accessChain.indexChain.clear();
3634617a3babSopenharmony_ci    accessChain.instr = NoResult;
3635617a3babSopenharmony_ci    accessChain.swizzle.clear();
3636617a3babSopenharmony_ci    accessChain.component = NoResult;
3637617a3babSopenharmony_ci    accessChain.preSwizzleBaseType = NoType;
3638617a3babSopenharmony_ci    accessChain.isRValue = false;
3639617a3babSopenharmony_ci    accessChain.coherentFlags.clear();
3640617a3babSopenharmony_ci    accessChain.alignment = 0;
3641617a3babSopenharmony_ci}
3642617a3babSopenharmony_ci
3643617a3babSopenharmony_ci// Comments in header
3644617a3babSopenharmony_civoid Builder::accessChainPushSwizzle(std::vector<unsigned>& swizzle, Id preSwizzleBaseType,
3645617a3babSopenharmony_ci    AccessChain::CoherentFlags coherentFlags, unsigned int alignment)
3646617a3babSopenharmony_ci{
3647617a3babSopenharmony_ci    accessChain.coherentFlags |= coherentFlags;
3648617a3babSopenharmony_ci    accessChain.alignment |= alignment;
3649617a3babSopenharmony_ci
3650617a3babSopenharmony_ci    // swizzles can be stacked in GLSL, but simplified to a single
3651617a3babSopenharmony_ci    // one here; the base type doesn't change
3652617a3babSopenharmony_ci    if (accessChain.preSwizzleBaseType == NoType)
3653617a3babSopenharmony_ci        accessChain.preSwizzleBaseType = preSwizzleBaseType;
3654617a3babSopenharmony_ci
3655617a3babSopenharmony_ci    // if needed, propagate the swizzle for the current access chain
3656617a3babSopenharmony_ci    if (accessChain.swizzle.size() > 0) {
3657617a3babSopenharmony_ci        std::vector<unsigned> oldSwizzle = accessChain.swizzle;
3658617a3babSopenharmony_ci        accessChain.swizzle.resize(0);
3659617a3babSopenharmony_ci        for (unsigned int i = 0; i < swizzle.size(); ++i) {
3660617a3babSopenharmony_ci            assert(swizzle[i] < oldSwizzle.size());
3661617a3babSopenharmony_ci            accessChain.swizzle.push_back(oldSwizzle[swizzle[i]]);
3662617a3babSopenharmony_ci        }
3663617a3babSopenharmony_ci    } else
3664617a3babSopenharmony_ci        accessChain.swizzle = swizzle;
3665617a3babSopenharmony_ci
3666617a3babSopenharmony_ci    // determine if we need to track this swizzle anymore
3667617a3babSopenharmony_ci    simplifyAccessChainSwizzle();
3668617a3babSopenharmony_ci}
3669617a3babSopenharmony_ci
3670617a3babSopenharmony_ci// Comments in header
3671617a3babSopenharmony_civoid Builder::accessChainStore(Id rvalue, Decoration nonUniform, spv::MemoryAccessMask memoryAccess, spv::Scope scope, unsigned int alignment)
3672617a3babSopenharmony_ci{
3673617a3babSopenharmony_ci    assert(accessChain.isRValue == false);
3674617a3babSopenharmony_ci
3675617a3babSopenharmony_ci    transferAccessChainSwizzle(true);
3676617a3babSopenharmony_ci
3677617a3babSopenharmony_ci    // If a swizzle exists and is not full and is not dynamic, then the swizzle will be broken into individual stores.
3678617a3babSopenharmony_ci    if (accessChain.swizzle.size() > 0 &&
3679617a3babSopenharmony_ci        getNumTypeComponents(getResultingAccessChainType()) != (int)accessChain.swizzle.size() &&
3680617a3babSopenharmony_ci        accessChain.component == NoResult) {
3681617a3babSopenharmony_ci        for (unsigned int i = 0; i < accessChain.swizzle.size(); ++i) {
3682617a3babSopenharmony_ci            accessChain.indexChain.push_back(makeUintConstant(accessChain.swizzle[i]));
3683617a3babSopenharmony_ci            accessChain.instr = NoResult;
3684617a3babSopenharmony_ci
3685617a3babSopenharmony_ci            Id base = collapseAccessChain();
3686617a3babSopenharmony_ci            addDecoration(base, nonUniform);
3687617a3babSopenharmony_ci
3688617a3babSopenharmony_ci            accessChain.indexChain.pop_back();
3689617a3babSopenharmony_ci            accessChain.instr = NoResult;
3690617a3babSopenharmony_ci
3691617a3babSopenharmony_ci            // dynamic component should be gone
3692617a3babSopenharmony_ci            assert(accessChain.component == NoResult);
3693617a3babSopenharmony_ci
3694617a3babSopenharmony_ci            Id source = createCompositeExtract(rvalue, getContainedTypeId(getTypeId(rvalue)), i);
3695617a3babSopenharmony_ci
3696617a3babSopenharmony_ci            // take LSB of alignment
3697617a3babSopenharmony_ci            alignment = alignment & ~(alignment & (alignment-1));
3698617a3babSopenharmony_ci            if (getStorageClass(base) == StorageClassPhysicalStorageBufferEXT) {
3699617a3babSopenharmony_ci                memoryAccess = (spv::MemoryAccessMask)(memoryAccess | spv::MemoryAccessAlignedMask);
3700617a3babSopenharmony_ci            }
3701617a3babSopenharmony_ci
3702617a3babSopenharmony_ci            createStore(source, base, memoryAccess, scope, alignment);
3703617a3babSopenharmony_ci        }
3704617a3babSopenharmony_ci    }
3705617a3babSopenharmony_ci    else {
3706617a3babSopenharmony_ci        Id base = collapseAccessChain();
3707617a3babSopenharmony_ci        addDecoration(base, nonUniform);
3708617a3babSopenharmony_ci
3709617a3babSopenharmony_ci        Id source = rvalue;
3710617a3babSopenharmony_ci
3711617a3babSopenharmony_ci        // dynamic component should be gone
3712617a3babSopenharmony_ci        assert(accessChain.component == NoResult);
3713617a3babSopenharmony_ci
3714617a3babSopenharmony_ci        // If swizzle still exists, it may be out-of-order, we must load the target vector,
3715617a3babSopenharmony_ci        // extract and insert elements to perform writeMask and/or swizzle.
3716617a3babSopenharmony_ci        if (accessChain.swizzle.size() > 0) {
3717617a3babSopenharmony_ci            Id tempBaseId = createLoad(base, spv::NoPrecision);
3718617a3babSopenharmony_ci            source = createLvalueSwizzle(getTypeId(tempBaseId), tempBaseId, source, accessChain.swizzle);
3719617a3babSopenharmony_ci        }
3720617a3babSopenharmony_ci
3721617a3babSopenharmony_ci        // take LSB of alignment
3722617a3babSopenharmony_ci        alignment = alignment & ~(alignment & (alignment-1));
3723617a3babSopenharmony_ci        if (getStorageClass(base) == StorageClassPhysicalStorageBufferEXT) {
3724617a3babSopenharmony_ci            memoryAccess = (spv::MemoryAccessMask)(memoryAccess | spv::MemoryAccessAlignedMask);
3725617a3babSopenharmony_ci        }
3726617a3babSopenharmony_ci
3727617a3babSopenharmony_ci        createStore(source, base, memoryAccess, scope, alignment);
3728617a3babSopenharmony_ci    }
3729617a3babSopenharmony_ci}
3730617a3babSopenharmony_ci
3731617a3babSopenharmony_ci// Comments in header
3732617a3babSopenharmony_ciId Builder::accessChainLoad(Decoration precision, Decoration l_nonUniform,
3733617a3babSopenharmony_ci    Decoration r_nonUniform, Id resultType, spv::MemoryAccessMask memoryAccess,
3734617a3babSopenharmony_ci    spv::Scope scope, unsigned int alignment)
3735617a3babSopenharmony_ci{
3736617a3babSopenharmony_ci    Id id;
3737617a3babSopenharmony_ci
3738617a3babSopenharmony_ci    if (accessChain.isRValue) {
3739617a3babSopenharmony_ci        // transfer access chain, but try to stay in registers
3740617a3babSopenharmony_ci        transferAccessChainSwizzle(false);
3741617a3babSopenharmony_ci        if (accessChain.indexChain.size() > 0) {
3742617a3babSopenharmony_ci            Id swizzleBase = accessChain.preSwizzleBaseType != NoType ? accessChain.preSwizzleBaseType : resultType;
3743617a3babSopenharmony_ci
3744617a3babSopenharmony_ci            // if all the accesses are constants, we can use OpCompositeExtract
3745617a3babSopenharmony_ci            std::vector<unsigned> indexes;
3746617a3babSopenharmony_ci            bool constant = true;
3747617a3babSopenharmony_ci            for (int i = 0; i < (int)accessChain.indexChain.size(); ++i) {
3748617a3babSopenharmony_ci                if (isConstantScalar(accessChain.indexChain[i]))
3749617a3babSopenharmony_ci                    indexes.push_back(getConstantScalar(accessChain.indexChain[i]));
3750617a3babSopenharmony_ci                else {
3751617a3babSopenharmony_ci                    constant = false;
3752617a3babSopenharmony_ci                    break;
3753617a3babSopenharmony_ci                }
3754617a3babSopenharmony_ci            }
3755617a3babSopenharmony_ci
3756617a3babSopenharmony_ci            if (constant) {
3757617a3babSopenharmony_ci                id = createCompositeExtract(accessChain.base, swizzleBase, indexes);
3758617a3babSopenharmony_ci                setPrecision(id, precision);
3759617a3babSopenharmony_ci            } else {
3760617a3babSopenharmony_ci                Id lValue = NoResult;
3761617a3babSopenharmony_ci                if (spvVersion >= Spv_1_4 && isValidInitializer(accessChain.base)) {
3762617a3babSopenharmony_ci                    // make a new function variable for this r-value, using an initializer,
3763617a3babSopenharmony_ci                    // and mark it as NonWritable so that downstream it can be detected as a lookup
3764617a3babSopenharmony_ci                    // table
3765617a3babSopenharmony_ci                    lValue = createVariable(NoPrecision, StorageClassFunction, getTypeId(accessChain.base),
3766617a3babSopenharmony_ci                        "indexable", accessChain.base);
3767617a3babSopenharmony_ci                    addDecoration(lValue, DecorationNonWritable);
3768617a3babSopenharmony_ci                } else {
3769617a3babSopenharmony_ci                    lValue = createVariable(NoPrecision, StorageClassFunction, getTypeId(accessChain.base),
3770617a3babSopenharmony_ci                        "indexable");
3771617a3babSopenharmony_ci                    // store into it
3772617a3babSopenharmony_ci                    createStore(accessChain.base, lValue);
3773617a3babSopenharmony_ci                }
3774617a3babSopenharmony_ci                // move base to the new variable
3775617a3babSopenharmony_ci                accessChain.base = lValue;
3776617a3babSopenharmony_ci                accessChain.isRValue = false;
3777617a3babSopenharmony_ci
3778617a3babSopenharmony_ci                // load through the access chain
3779617a3babSopenharmony_ci                id = createLoad(collapseAccessChain(), precision);
3780617a3babSopenharmony_ci            }
3781617a3babSopenharmony_ci        } else
3782617a3babSopenharmony_ci            id = accessChain.base;  // no precision, it was set when this was defined
3783617a3babSopenharmony_ci    } else {
3784617a3babSopenharmony_ci        transferAccessChainSwizzle(true);
3785617a3babSopenharmony_ci
3786617a3babSopenharmony_ci        // take LSB of alignment
3787617a3babSopenharmony_ci        alignment = alignment & ~(alignment & (alignment-1));
3788617a3babSopenharmony_ci        if (getStorageClass(accessChain.base) == StorageClassPhysicalStorageBufferEXT) {
3789617a3babSopenharmony_ci            memoryAccess = (spv::MemoryAccessMask)(memoryAccess | spv::MemoryAccessAlignedMask);
3790617a3babSopenharmony_ci        }
3791617a3babSopenharmony_ci
3792617a3babSopenharmony_ci        // load through the access chain
3793617a3babSopenharmony_ci        id = collapseAccessChain();
3794617a3babSopenharmony_ci        // Apply nonuniform both to the access chain and the loaded value.
3795617a3babSopenharmony_ci        // Buffer accesses need the access chain decorated, and this is where
3796617a3babSopenharmony_ci        // loaded image types get decorated. TODO: This should maybe move to
3797617a3babSopenharmony_ci        // createImageTextureFunctionCall.
3798617a3babSopenharmony_ci        addDecoration(id, l_nonUniform);
3799617a3babSopenharmony_ci        id = createLoad(id, precision, memoryAccess, scope, alignment);
3800617a3babSopenharmony_ci        addDecoration(id, r_nonUniform);
3801617a3babSopenharmony_ci    }
3802617a3babSopenharmony_ci
3803617a3babSopenharmony_ci    // Done, unless there are swizzles to do
3804617a3babSopenharmony_ci    if (accessChain.swizzle.size() == 0 && accessChain.component == NoResult)
3805617a3babSopenharmony_ci        return id;
3806617a3babSopenharmony_ci
3807617a3babSopenharmony_ci    // Do remaining swizzling
3808617a3babSopenharmony_ci
3809617a3babSopenharmony_ci    // Do the basic swizzle
3810617a3babSopenharmony_ci    if (accessChain.swizzle.size() > 0) {
3811617a3babSopenharmony_ci        Id swizzledType = getScalarTypeId(getTypeId(id));
3812617a3babSopenharmony_ci        if (accessChain.swizzle.size() > 1)
3813617a3babSopenharmony_ci            swizzledType = makeVectorType(swizzledType, (int)accessChain.swizzle.size());
3814617a3babSopenharmony_ci        id = createRvalueSwizzle(precision, swizzledType, id, accessChain.swizzle);
3815617a3babSopenharmony_ci    }
3816617a3babSopenharmony_ci
3817617a3babSopenharmony_ci    // Do the dynamic component
3818617a3babSopenharmony_ci    if (accessChain.component != NoResult)
3819617a3babSopenharmony_ci        id = setPrecision(createVectorExtractDynamic(id, resultType, accessChain.component), precision);
3820617a3babSopenharmony_ci
3821617a3babSopenharmony_ci    addDecoration(id, r_nonUniform);
3822617a3babSopenharmony_ci    return id;
3823617a3babSopenharmony_ci}
3824617a3babSopenharmony_ci
3825617a3babSopenharmony_ciId Builder::accessChainGetLValue()
3826617a3babSopenharmony_ci{
3827617a3babSopenharmony_ci    assert(accessChain.isRValue == false);
3828617a3babSopenharmony_ci
3829617a3babSopenharmony_ci    transferAccessChainSwizzle(true);
3830617a3babSopenharmony_ci    Id lvalue = collapseAccessChain();
3831617a3babSopenharmony_ci
3832617a3babSopenharmony_ci    // If swizzle exists, it is out-of-order or not full, we must load the target vector,
3833617a3babSopenharmony_ci    // extract and insert elements to perform writeMask and/or swizzle.  This does not
3834617a3babSopenharmony_ci    // go with getting a direct l-value pointer.
3835617a3babSopenharmony_ci    assert(accessChain.swizzle.size() == 0);
3836617a3babSopenharmony_ci    assert(accessChain.component == NoResult);
3837617a3babSopenharmony_ci
3838617a3babSopenharmony_ci    return lvalue;
3839617a3babSopenharmony_ci}
3840617a3babSopenharmony_ci
3841617a3babSopenharmony_ci// comment in header
3842617a3babSopenharmony_ciId Builder::accessChainGetInferredType()
3843617a3babSopenharmony_ci{
3844617a3babSopenharmony_ci    // anything to operate on?
3845617a3babSopenharmony_ci    if (accessChain.base == NoResult)
3846617a3babSopenharmony_ci        return NoType;
3847617a3babSopenharmony_ci    Id type = getTypeId(accessChain.base);
3848617a3babSopenharmony_ci
3849617a3babSopenharmony_ci    // do initial dereference
3850617a3babSopenharmony_ci    if (! accessChain.isRValue)
3851617a3babSopenharmony_ci        type = getContainedTypeId(type);
3852617a3babSopenharmony_ci
3853617a3babSopenharmony_ci    // dereference each index
3854617a3babSopenharmony_ci    for (auto it = accessChain.indexChain.cbegin(); it != accessChain.indexChain.cend(); ++it) {
3855617a3babSopenharmony_ci        if (isStructType(type))
3856617a3babSopenharmony_ci            type = getContainedTypeId(type, getConstantScalar(*it));
3857617a3babSopenharmony_ci        else
3858617a3babSopenharmony_ci            type = getContainedTypeId(type);
3859617a3babSopenharmony_ci    }
3860617a3babSopenharmony_ci
3861617a3babSopenharmony_ci    // dereference swizzle
3862617a3babSopenharmony_ci    if (accessChain.swizzle.size() == 1)
3863617a3babSopenharmony_ci        type = getContainedTypeId(type);
3864617a3babSopenharmony_ci    else if (accessChain.swizzle.size() > 1)
3865617a3babSopenharmony_ci        type = makeVectorType(getContainedTypeId(type), (int)accessChain.swizzle.size());
3866617a3babSopenharmony_ci
3867617a3babSopenharmony_ci    // dereference component selection
3868617a3babSopenharmony_ci    if (accessChain.component)
3869617a3babSopenharmony_ci        type = getContainedTypeId(type);
3870617a3babSopenharmony_ci
3871617a3babSopenharmony_ci    return type;
3872617a3babSopenharmony_ci}
3873617a3babSopenharmony_ci
3874617a3babSopenharmony_civoid Builder::dump(std::vector<unsigned int>& out) const
3875617a3babSopenharmony_ci{
3876617a3babSopenharmony_ci    // Header, before first instructions:
3877617a3babSopenharmony_ci    out.push_back(MagicNumber);
3878617a3babSopenharmony_ci    out.push_back(spvVersion);
3879617a3babSopenharmony_ci    out.push_back(builderNumber);
3880617a3babSopenharmony_ci    out.push_back(uniqueId + 1);
3881617a3babSopenharmony_ci    out.push_back(0);
3882617a3babSopenharmony_ci
3883617a3babSopenharmony_ci    // Capabilities
3884617a3babSopenharmony_ci    for (auto it = capabilities.cbegin(); it != capabilities.cend(); ++it) {
3885617a3babSopenharmony_ci        Instruction capInst(0, 0, OpCapability);
3886617a3babSopenharmony_ci        capInst.addImmediateOperand(*it);
3887617a3babSopenharmony_ci        capInst.dump(out);
3888617a3babSopenharmony_ci    }
3889617a3babSopenharmony_ci
3890617a3babSopenharmony_ci    for (auto it = extensions.cbegin(); it != extensions.cend(); ++it) {
3891617a3babSopenharmony_ci        Instruction extInst(0, 0, OpExtension);
3892617a3babSopenharmony_ci        extInst.addStringOperand(it->c_str());
3893617a3babSopenharmony_ci        extInst.dump(out);
3894617a3babSopenharmony_ci    }
3895617a3babSopenharmony_ci
3896617a3babSopenharmony_ci    dumpInstructions(out, imports);
3897617a3babSopenharmony_ci    Instruction memInst(0, 0, OpMemoryModel);
3898617a3babSopenharmony_ci    memInst.addImmediateOperand(addressModel);
3899617a3babSopenharmony_ci    memInst.addImmediateOperand(memoryModel);
3900617a3babSopenharmony_ci    memInst.dump(out);
3901617a3babSopenharmony_ci
3902617a3babSopenharmony_ci    // Instructions saved up while building:
3903617a3babSopenharmony_ci    dumpInstructions(out, entryPoints);
3904617a3babSopenharmony_ci    dumpInstructions(out, executionModes);
3905617a3babSopenharmony_ci
3906617a3babSopenharmony_ci    // Debug instructions
3907617a3babSopenharmony_ci    dumpInstructions(out, strings);
3908617a3babSopenharmony_ci    dumpSourceInstructions(out);
3909617a3babSopenharmony_ci    for (int e = 0; e < (int)sourceExtensions.size(); ++e) {
3910617a3babSopenharmony_ci        Instruction sourceExtInst(0, 0, OpSourceExtension);
3911617a3babSopenharmony_ci        sourceExtInst.addStringOperand(sourceExtensions[e]);
3912617a3babSopenharmony_ci        sourceExtInst.dump(out);
3913617a3babSopenharmony_ci    }
3914617a3babSopenharmony_ci    dumpInstructions(out, names);
3915617a3babSopenharmony_ci    dumpModuleProcesses(out);
3916617a3babSopenharmony_ci
3917617a3babSopenharmony_ci    // Annotation instructions
3918617a3babSopenharmony_ci    dumpInstructions(out, decorations);
3919617a3babSopenharmony_ci
3920617a3babSopenharmony_ci    dumpInstructions(out, constantsTypesGlobals);
3921617a3babSopenharmony_ci    dumpInstructions(out, externals);
3922617a3babSopenharmony_ci
3923617a3babSopenharmony_ci    // The functions
3924617a3babSopenharmony_ci    module.dump(out);
3925617a3babSopenharmony_ci}
3926617a3babSopenharmony_ci
3927617a3babSopenharmony_ci//
3928617a3babSopenharmony_ci// Protected methods.
3929617a3babSopenharmony_ci//
3930617a3babSopenharmony_ci
3931617a3babSopenharmony_ci// Turn the described access chain in 'accessChain' into an instruction(s)
3932617a3babSopenharmony_ci// computing its address.  This *cannot* include complex swizzles, which must
3933617a3babSopenharmony_ci// be handled after this is called.
3934617a3babSopenharmony_ci//
3935617a3babSopenharmony_ci// Can generate code.
3936617a3babSopenharmony_ciId Builder::collapseAccessChain()
3937617a3babSopenharmony_ci{
3938617a3babSopenharmony_ci    assert(accessChain.isRValue == false);
3939617a3babSopenharmony_ci
3940617a3babSopenharmony_ci    // did we already emit an access chain for this?
3941617a3babSopenharmony_ci    if (accessChain.instr != NoResult)
3942617a3babSopenharmony_ci        return accessChain.instr;
3943617a3babSopenharmony_ci
3944617a3babSopenharmony_ci    // If we have a dynamic component, we can still transfer
3945617a3babSopenharmony_ci    // that into a final operand to the access chain.  We need to remap the
3946617a3babSopenharmony_ci    // dynamic component through the swizzle to get a new dynamic component to
3947617a3babSopenharmony_ci    // update.
3948617a3babSopenharmony_ci    //
3949617a3babSopenharmony_ci    // This was not done in transferAccessChainSwizzle() because it might
3950617a3babSopenharmony_ci    // generate code.
3951617a3babSopenharmony_ci    remapDynamicSwizzle();
3952617a3babSopenharmony_ci    if (accessChain.component != NoResult) {
3953617a3babSopenharmony_ci        // transfer the dynamic component to the access chain
3954617a3babSopenharmony_ci        accessChain.indexChain.push_back(accessChain.component);
3955617a3babSopenharmony_ci        accessChain.component = NoResult;
3956617a3babSopenharmony_ci    }
3957617a3babSopenharmony_ci
3958617a3babSopenharmony_ci    // note that non-trivial swizzling is left pending
3959617a3babSopenharmony_ci
3960617a3babSopenharmony_ci    // do we have an access chain?
3961617a3babSopenharmony_ci    if (accessChain.indexChain.size() == 0)
3962617a3babSopenharmony_ci        return accessChain.base;
3963617a3babSopenharmony_ci
3964617a3babSopenharmony_ci    // emit the access chain
3965617a3babSopenharmony_ci    StorageClass storageClass = (StorageClass)module.getStorageClass(getTypeId(accessChain.base));
3966617a3babSopenharmony_ci    accessChain.instr = createAccessChain(storageClass, accessChain.base, accessChain.indexChain);
3967617a3babSopenharmony_ci
3968617a3babSopenharmony_ci    return accessChain.instr;
3969617a3babSopenharmony_ci}
3970617a3babSopenharmony_ci
3971617a3babSopenharmony_ci// For a dynamic component selection of a swizzle.
3972617a3babSopenharmony_ci//
3973617a3babSopenharmony_ci// Turn the swizzle and dynamic component into just a dynamic component.
3974617a3babSopenharmony_ci//
3975617a3babSopenharmony_ci// Generates code.
3976617a3babSopenharmony_civoid Builder::remapDynamicSwizzle()
3977617a3babSopenharmony_ci{
3978617a3babSopenharmony_ci    // do we have a swizzle to remap a dynamic component through?
3979617a3babSopenharmony_ci    if (accessChain.component != NoResult && accessChain.swizzle.size() > 1) {
3980617a3babSopenharmony_ci        // build a vector of the swizzle for the component to map into
3981617a3babSopenharmony_ci        std::vector<Id> components;
3982617a3babSopenharmony_ci        for (int c = 0; c < (int)accessChain.swizzle.size(); ++c)
3983617a3babSopenharmony_ci            components.push_back(makeUintConstant(accessChain.swizzle[c]));
3984617a3babSopenharmony_ci        Id mapType = makeVectorType(makeUintType(32), (int)accessChain.swizzle.size());
3985617a3babSopenharmony_ci        Id map = makeCompositeConstant(mapType, components);
3986617a3babSopenharmony_ci
3987617a3babSopenharmony_ci        // use it
3988617a3babSopenharmony_ci        accessChain.component = createVectorExtractDynamic(map, makeUintType(32), accessChain.component);
3989617a3babSopenharmony_ci        accessChain.swizzle.clear();
3990617a3babSopenharmony_ci    }
3991617a3babSopenharmony_ci}
3992617a3babSopenharmony_ci
3993617a3babSopenharmony_ci// clear out swizzle if it is redundant, that is reselecting the same components
3994617a3babSopenharmony_ci// that would be present without the swizzle.
3995617a3babSopenharmony_civoid Builder::simplifyAccessChainSwizzle()
3996617a3babSopenharmony_ci{
3997617a3babSopenharmony_ci    // If the swizzle has fewer components than the vector, it is subsetting, and must stay
3998617a3babSopenharmony_ci    // to preserve that fact.
3999617a3babSopenharmony_ci    if (getNumTypeComponents(accessChain.preSwizzleBaseType) > (int)accessChain.swizzle.size())
4000617a3babSopenharmony_ci        return;
4001617a3babSopenharmony_ci
4002617a3babSopenharmony_ci    // if components are out of order, it is a swizzle
4003617a3babSopenharmony_ci    for (unsigned int i = 0; i < accessChain.swizzle.size(); ++i) {
4004617a3babSopenharmony_ci        if (i != accessChain.swizzle[i])
4005617a3babSopenharmony_ci            return;
4006617a3babSopenharmony_ci    }
4007617a3babSopenharmony_ci
4008617a3babSopenharmony_ci    // otherwise, there is no need to track this swizzle
4009617a3babSopenharmony_ci    accessChain.swizzle.clear();
4010617a3babSopenharmony_ci    if (accessChain.component == NoResult)
4011617a3babSopenharmony_ci        accessChain.preSwizzleBaseType = NoType;
4012617a3babSopenharmony_ci}
4013617a3babSopenharmony_ci
4014617a3babSopenharmony_ci// To the extent any swizzling can become part of the chain
4015617a3babSopenharmony_ci// of accesses instead of a post operation, make it so.
4016617a3babSopenharmony_ci// If 'dynamic' is true, include transferring the dynamic component,
4017617a3babSopenharmony_ci// otherwise, leave it pending.
4018617a3babSopenharmony_ci//
4019617a3babSopenharmony_ci// Does not generate code. just updates the access chain.
4020617a3babSopenharmony_civoid Builder::transferAccessChainSwizzle(bool dynamic)
4021617a3babSopenharmony_ci{
4022617a3babSopenharmony_ci    // non existent?
4023617a3babSopenharmony_ci    if (accessChain.swizzle.size() == 0 && accessChain.component == NoResult)
4024617a3babSopenharmony_ci        return;
4025617a3babSopenharmony_ci
4026617a3babSopenharmony_ci    // too complex?
4027617a3babSopenharmony_ci    // (this requires either a swizzle, or generating code for a dynamic component)
4028617a3babSopenharmony_ci    if (accessChain.swizzle.size() > 1)
4029617a3babSopenharmony_ci        return;
4030617a3babSopenharmony_ci
4031617a3babSopenharmony_ci    // single component, either in the swizzle and/or dynamic component
4032617a3babSopenharmony_ci    if (accessChain.swizzle.size() == 1) {
4033617a3babSopenharmony_ci        assert(accessChain.component == NoResult);
4034617a3babSopenharmony_ci        // handle static component selection
4035617a3babSopenharmony_ci        accessChain.indexChain.push_back(makeUintConstant(accessChain.swizzle.front()));
4036617a3babSopenharmony_ci        accessChain.swizzle.clear();
4037617a3babSopenharmony_ci        accessChain.preSwizzleBaseType = NoType;
4038617a3babSopenharmony_ci    } else if (dynamic && accessChain.component != NoResult) {
4039617a3babSopenharmony_ci        assert(accessChain.swizzle.size() == 0);
4040617a3babSopenharmony_ci        // handle dynamic component
4041617a3babSopenharmony_ci        accessChain.indexChain.push_back(accessChain.component);
4042617a3babSopenharmony_ci        accessChain.preSwizzleBaseType = NoType;
4043617a3babSopenharmony_ci        accessChain.component = NoResult;
4044617a3babSopenharmony_ci    }
4045617a3babSopenharmony_ci}
4046617a3babSopenharmony_ci
4047617a3babSopenharmony_ci// Utility method for creating a new block and setting the insert point to
4048617a3babSopenharmony_ci// be in it. This is useful for flow-control operations that need a "dummy"
4049617a3babSopenharmony_ci// block proceeding them (e.g. instructions after a discard, etc).
4050617a3babSopenharmony_civoid Builder::createAndSetNoPredecessorBlock(const char* /*name*/)
4051617a3babSopenharmony_ci{
4052617a3babSopenharmony_ci    Block* block = new Block(getUniqueId(), buildPoint->getParent());
4053617a3babSopenharmony_ci    block->setUnreachable();
4054617a3babSopenharmony_ci    buildPoint->getParent().addBlock(block);
4055617a3babSopenharmony_ci    setBuildPoint(block);
4056617a3babSopenharmony_ci
4057617a3babSopenharmony_ci    // if (name)
4058617a3babSopenharmony_ci    //    addName(block->getId(), name);
4059617a3babSopenharmony_ci}
4060617a3babSopenharmony_ci
4061617a3babSopenharmony_ci// Comments in header
4062617a3babSopenharmony_civoid Builder::createBranch(Block* block)
4063617a3babSopenharmony_ci{
4064617a3babSopenharmony_ci    Instruction* branch = new Instruction(OpBranch);
4065617a3babSopenharmony_ci    branch->addIdOperand(block->getId());
4066617a3babSopenharmony_ci    buildPoint->addInstruction(std::unique_ptr<Instruction>(branch));
4067617a3babSopenharmony_ci    block->addPredecessor(buildPoint);
4068617a3babSopenharmony_ci}
4069617a3babSopenharmony_ci
4070617a3babSopenharmony_civoid Builder::createSelectionMerge(Block* mergeBlock, unsigned int control)
4071617a3babSopenharmony_ci{
4072617a3babSopenharmony_ci    Instruction* merge = new Instruction(OpSelectionMerge);
4073617a3babSopenharmony_ci    merge->addIdOperand(mergeBlock->getId());
4074617a3babSopenharmony_ci    merge->addImmediateOperand(control);
4075617a3babSopenharmony_ci    buildPoint->addInstruction(std::unique_ptr<Instruction>(merge));
4076617a3babSopenharmony_ci}
4077617a3babSopenharmony_ci
4078617a3babSopenharmony_civoid Builder::createLoopMerge(Block* mergeBlock, Block* continueBlock, unsigned int control,
4079617a3babSopenharmony_ci                              const std::vector<unsigned int>& operands)
4080617a3babSopenharmony_ci{
4081617a3babSopenharmony_ci    Instruction* merge = new Instruction(OpLoopMerge);
4082617a3babSopenharmony_ci    merge->addIdOperand(mergeBlock->getId());
4083617a3babSopenharmony_ci    merge->addIdOperand(continueBlock->getId());
4084617a3babSopenharmony_ci    merge->addImmediateOperand(control);
4085617a3babSopenharmony_ci    for (int op = 0; op < (int)operands.size(); ++op)
4086617a3babSopenharmony_ci        merge->addImmediateOperand(operands[op]);
4087617a3babSopenharmony_ci    buildPoint->addInstruction(std::unique_ptr<Instruction>(merge));
4088617a3babSopenharmony_ci}
4089617a3babSopenharmony_ci
4090617a3babSopenharmony_civoid Builder::createConditionalBranch(Id condition, Block* thenBlock, Block* elseBlock)
4091617a3babSopenharmony_ci{
4092617a3babSopenharmony_ci    Instruction* branch = new Instruction(OpBranchConditional);
4093617a3babSopenharmony_ci    branch->addIdOperand(condition);
4094617a3babSopenharmony_ci    branch->addIdOperand(thenBlock->getId());
4095617a3babSopenharmony_ci    branch->addIdOperand(elseBlock->getId());
4096617a3babSopenharmony_ci    buildPoint->addInstruction(std::unique_ptr<Instruction>(branch));
4097617a3babSopenharmony_ci    thenBlock->addPredecessor(buildPoint);
4098617a3babSopenharmony_ci    elseBlock->addPredecessor(buildPoint);
4099617a3babSopenharmony_ci}
4100617a3babSopenharmony_ci
4101617a3babSopenharmony_ci// OpSource
4102617a3babSopenharmony_ci// [OpSourceContinued]
4103617a3babSopenharmony_ci// ...
4104617a3babSopenharmony_civoid Builder::dumpSourceInstructions(const spv::Id fileId, const std::string& text,
4105617a3babSopenharmony_ci                                     std::vector<unsigned int>& out) const
4106617a3babSopenharmony_ci{
4107617a3babSopenharmony_ci    const int maxWordCount = 0xFFFF;
4108617a3babSopenharmony_ci    const int opSourceWordCount = 4;
4109617a3babSopenharmony_ci    const int nonNullBytesPerInstruction = 4 * (maxWordCount - opSourceWordCount) - 1;
4110617a3babSopenharmony_ci
4111617a3babSopenharmony_ci    if (sourceLang != SourceLanguageUnknown) {
4112617a3babSopenharmony_ci        // OpSource Language Version File Source
4113617a3babSopenharmony_ci        Instruction sourceInst(NoResult, NoType, OpSource);
4114617a3babSopenharmony_ci        sourceInst.addImmediateOperand(sourceLang);
4115617a3babSopenharmony_ci        sourceInst.addImmediateOperand(sourceVersion);
4116617a3babSopenharmony_ci        // File operand
4117617a3babSopenharmony_ci        if (fileId != NoResult) {
4118617a3babSopenharmony_ci            sourceInst.addIdOperand(fileId);
4119617a3babSopenharmony_ci            // Source operand
4120617a3babSopenharmony_ci            if (text.size() > 0) {
4121617a3babSopenharmony_ci                int nextByte = 0;
4122617a3babSopenharmony_ci                std::string subString;
4123617a3babSopenharmony_ci                while ((int)text.size() - nextByte > 0) {
4124617a3babSopenharmony_ci                    subString = text.substr(nextByte, nonNullBytesPerInstruction);
4125617a3babSopenharmony_ci                    if (nextByte == 0) {
4126617a3babSopenharmony_ci                        // OpSource
4127617a3babSopenharmony_ci                        sourceInst.addStringOperand(subString.c_str());
4128617a3babSopenharmony_ci                        sourceInst.dump(out);
4129617a3babSopenharmony_ci                    } else {
4130617a3babSopenharmony_ci                        // OpSourcContinued
4131617a3babSopenharmony_ci                        Instruction sourceContinuedInst(OpSourceContinued);
4132617a3babSopenharmony_ci                        sourceContinuedInst.addStringOperand(subString.c_str());
4133617a3babSopenharmony_ci                        sourceContinuedInst.dump(out);
4134617a3babSopenharmony_ci                    }
4135617a3babSopenharmony_ci                    nextByte += nonNullBytesPerInstruction;
4136617a3babSopenharmony_ci                }
4137617a3babSopenharmony_ci            } else
4138617a3babSopenharmony_ci                sourceInst.dump(out);
4139617a3babSopenharmony_ci        } else
4140617a3babSopenharmony_ci            sourceInst.dump(out);
4141617a3babSopenharmony_ci    }
4142617a3babSopenharmony_ci}
4143617a3babSopenharmony_ci
4144617a3babSopenharmony_ci// Dump an OpSource[Continued] sequence for the source and every include file
4145617a3babSopenharmony_civoid Builder::dumpSourceInstructions(std::vector<unsigned int>& out) const
4146617a3babSopenharmony_ci{
4147617a3babSopenharmony_ci    if (emitNonSemanticShaderDebugInfo) return;
4148617a3babSopenharmony_ci    dumpSourceInstructions(sourceFileStringId, sourceText, out);
4149617a3babSopenharmony_ci    for (auto iItr = includeFiles.begin(); iItr != includeFiles.end(); ++iItr)
4150617a3babSopenharmony_ci        dumpSourceInstructions(iItr->first, *iItr->second, out);
4151617a3babSopenharmony_ci}
4152617a3babSopenharmony_ci
4153617a3babSopenharmony_civoid Builder::dumpInstructions(std::vector<unsigned int>& out,
4154617a3babSopenharmony_ci    const std::vector<std::unique_ptr<Instruction> >& instructions) const
4155617a3babSopenharmony_ci{
4156617a3babSopenharmony_ci    for (int i = 0; i < (int)instructions.size(); ++i) {
4157617a3babSopenharmony_ci        instructions[i]->dump(out);
4158617a3babSopenharmony_ci    }
4159617a3babSopenharmony_ci}
4160617a3babSopenharmony_ci
4161617a3babSopenharmony_civoid Builder::dumpModuleProcesses(std::vector<unsigned int>& out) const
4162617a3babSopenharmony_ci{
4163617a3babSopenharmony_ci    for (int i = 0; i < (int)moduleProcesses.size(); ++i) {
4164617a3babSopenharmony_ci        Instruction moduleProcessed(OpModuleProcessed);
4165617a3babSopenharmony_ci        moduleProcessed.addStringOperand(moduleProcesses[i]);
4166617a3babSopenharmony_ci        moduleProcessed.dump(out);
4167617a3babSopenharmony_ci    }
4168617a3babSopenharmony_ci}
4169617a3babSopenharmony_ci
4170617a3babSopenharmony_ci} // end spv namespace
4171