Home | History | Annotate | Download | only in SPIRV
      1 //
      2 // Copyright (C) 2014-2015 LunarG, Inc.
      3 // Copyright (C) 2015-2018 Google, Inc.
      4 //
      5 // All rights reserved.
      6 //
      7 // Redistribution and use in source and binary forms, with or without
      8 // modification, are permitted provided that the following conditions
      9 // are met:
     10 //
     11 //    Redistributions of source code must retain the above copyright
     12 //    notice, this list of conditions and the following disclaimer.
     13 //
     14 //    Redistributions in binary form must reproduce the above
     15 //    copyright notice, this list of conditions and the following
     16 //    disclaimer in the documentation and/or other materials provided
     17 //    with the distribution.
     18 //
     19 //    Neither the name of 3Dlabs Inc. Ltd. nor the names of its
     20 //    contributors may be used to endorse or promote products derived
     21 //    from this software without specific prior written permission.
     22 //
     23 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     24 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     25 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
     26 // FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
     27 // COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
     28 // INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
     29 // BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
     30 // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
     31 // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     32 // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
     33 // ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     34 // POSSIBILITY OF SUCH DAMAGE.
     35 
     36 //
     37 // Helper for making SPIR-V IR.  Generally, this is documented in the header
     38 // SpvBuilder.h.
     39 //
     40 
     41 #include <cassert>
     42 #include <cstdlib>
     43 
     44 #include <unordered_set>
     45 #include <algorithm>
     46 
     47 #include "SpvBuilder.h"
     48 
     49 #include "hex_float.h"
     50 
     51 #ifndef _WIN32
     52     #include <cstdio>
     53 #endif
     54 
     55 namespace spv {
     56 
     57 Builder::Builder(unsigned int spvVersion, unsigned int magicNumber, SpvBuildLogger* buildLogger) :
     58     spvVersion(spvVersion),
     59     source(SourceLanguageUnknown),
     60     sourceVersion(0),
     61     sourceFileStringId(NoResult),
     62     currentLine(0),
     63     currentFile(nullptr),
     64     emitOpLines(false),
     65     addressModel(AddressingModelLogical),
     66     memoryModel(MemoryModelGLSL450),
     67     builderNumber(magicNumber),
     68     buildPoint(0),
     69     uniqueId(0),
     70     entryPointFunction(0),
     71     generatingOpCodeForSpecConst(false),
     72     logger(buildLogger)
     73 {
     74     clearAccessChain();
     75 }
     76 
     77 Builder::~Builder()
     78 {
     79 }
     80 
     81 Id Builder::import(const char* name)
     82 {
     83     Instruction* import = new Instruction(getUniqueId(), NoType, OpExtInstImport);
     84     import->addStringOperand(name);
     85     module.mapInstruction(import);
     86 
     87     imports.push_back(std::unique_ptr<Instruction>(import));
     88     return import->getResultId();
     89 }
     90 
     91 // Emit instruction for non-filename-based #line directives (ie. no filename
     92 // seen yet): emit an OpLine if we've been asked to emit OpLines and the line
     93 // number has changed since the last time, and is a valid line number.
     94 void Builder::setLine(int lineNum)
     95 {
     96     if (lineNum != 0 && lineNum != currentLine) {
     97         currentLine = lineNum;
     98         if (emitOpLines)
     99             addLine(sourceFileStringId, currentLine, 0);
    100     }
    101 }
    102 
    103 // If no filename, do non-filename-based #line emit. Else do filename-based emit.
    104 // Emit OpLine if we've been asked to emit OpLines and the line number or filename
    105 // has changed since the last time, and line number is valid.
    106 void Builder::setLine(int lineNum, const char* filename)
    107 {
    108     if (filename == nullptr) {
    109         setLine(lineNum);
    110         return;
    111     }
    112     if ((lineNum != 0 && lineNum != currentLine) || currentFile == nullptr ||
    113             strncmp(filename, currentFile, strlen(currentFile) + 1) != 0) {
    114         currentLine = lineNum;
    115         currentFile = filename;
    116         if (emitOpLines) {
    117             spv::Id strId = getStringId(filename);
    118             addLine(strId, currentLine, 0);
    119         }
    120     }
    121 }
    122 
    123 void Builder::addLine(Id fileName, int lineNum, int column)
    124 {
    125     Instruction* line = new Instruction(OpLine);
    126     line->addIdOperand(fileName);
    127     line->addImmediateOperand(lineNum);
    128     line->addImmediateOperand(column);
    129     buildPoint->addInstruction(std::unique_ptr<Instruction>(line));
    130 }
    131 
    132 // For creating new groupedTypes (will return old type if the requested one was already made).
    133 Id Builder::makeVoidType()
    134 {
    135     Instruction* type;
    136     if (groupedTypes[OpTypeVoid].size() == 0) {
    137         type = new Instruction(getUniqueId(), NoType, OpTypeVoid);
    138         groupedTypes[OpTypeVoid].push_back(type);
    139         constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
    140         module.mapInstruction(type);
    141     } else
    142         type = groupedTypes[OpTypeVoid].back();
    143 
    144     return type->getResultId();
    145 }
    146 
    147 Id Builder::makeBoolType()
    148 {
    149     Instruction* type;
    150     if (groupedTypes[OpTypeBool].size() == 0) {
    151         type = new Instruction(getUniqueId(), NoType, OpTypeBool);
    152         groupedTypes[OpTypeBool].push_back(type);
    153         constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
    154         module.mapInstruction(type);
    155     } else
    156         type = groupedTypes[OpTypeBool].back();
    157 
    158     return type->getResultId();
    159 }
    160 
    161 Id Builder::makeSamplerType()
    162 {
    163     Instruction* type;
    164     if (groupedTypes[OpTypeSampler].size() == 0) {
    165         type = new Instruction(getUniqueId(), NoType, OpTypeSampler);
    166         groupedTypes[OpTypeSampler].push_back(type);
    167         constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
    168         module.mapInstruction(type);
    169     } else
    170         type = groupedTypes[OpTypeSampler].back();
    171 
    172     return type->getResultId();
    173 }
    174 
    175 Id Builder::makePointer(StorageClass storageClass, Id pointee)
    176 {
    177     // try to find it
    178     Instruction* type;
    179     for (int t = 0; t < (int)groupedTypes[OpTypePointer].size(); ++t) {
    180         type = groupedTypes[OpTypePointer][t];
    181         if (type->getImmediateOperand(0) == (unsigned)storageClass &&
    182             type->getIdOperand(1) == pointee)
    183             return type->getResultId();
    184     }
    185 
    186     // not found, make it
    187     type = new Instruction(getUniqueId(), NoType, OpTypePointer);
    188     type->addImmediateOperand(storageClass);
    189     type->addIdOperand(pointee);
    190     groupedTypes[OpTypePointer].push_back(type);
    191     constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
    192     module.mapInstruction(type);
    193 
    194     return type->getResultId();
    195 }
    196 
    197 Id Builder::makeForwardPointer(StorageClass storageClass)
    198 {
    199     // Caching/uniquifying doesn't work here, because we don't know the
    200     // pointee type and there can be multiple forward pointers of the same
    201     // storage type. Somebody higher up in the stack must keep track.
    202     Instruction* type = new Instruction(getUniqueId(), NoType, OpTypeForwardPointer);
    203     type->addImmediateOperand(storageClass);
    204     constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
    205     module.mapInstruction(type);
    206 
    207     return type->getResultId();
    208 }
    209 
    210 Id Builder::makePointerFromForwardPointer(StorageClass storageClass, Id forwardPointerType, Id pointee)
    211 {
    212     // try to find it
    213     Instruction* type;
    214     for (int t = 0; t < (int)groupedTypes[OpTypePointer].size(); ++t) {
    215         type = groupedTypes[OpTypePointer][t];
    216         if (type->getImmediateOperand(0) == (unsigned)storageClass &&
    217             type->getIdOperand(1) == pointee)
    218             return type->getResultId();
    219     }
    220 
    221     type = new Instruction(forwardPointerType, NoType, OpTypePointer);
    222     type->addImmediateOperand(storageClass);
    223     type->addIdOperand(pointee);
    224     groupedTypes[OpTypePointer].push_back(type);
    225     constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
    226     module.mapInstruction(type);
    227 
    228     return type->getResultId();
    229 }
    230 
    231 Id Builder::makeIntegerType(int width, bool hasSign)
    232 {
    233     // try to find it
    234     Instruction* type;
    235     for (int t = 0; t < (int)groupedTypes[OpTypeInt].size(); ++t) {
    236         type = groupedTypes[OpTypeInt][t];
    237         if (type->getImmediateOperand(0) == (unsigned)width &&
    238             type->getImmediateOperand(1) == (hasSign ? 1u : 0u))
    239             return type->getResultId();
    240     }
    241 
    242     // not found, make it
    243     type = new Instruction(getUniqueId(), NoType, OpTypeInt);
    244     type->addImmediateOperand(width);
    245     type->addImmediateOperand(hasSign ? 1 : 0);
    246     groupedTypes[OpTypeInt].push_back(type);
    247     constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
    248     module.mapInstruction(type);
    249 
    250     // deal with capabilities
    251     switch (width) {
    252     case 8:
    253     case 16:
    254         // these are currently handled by storage-type declarations and post processing
    255         break;
    256     case 64:
    257         addCapability(CapabilityInt64);
    258         break;
    259     default:
    260         break;
    261     }
    262 
    263     return type->getResultId();
    264 }
    265 
    266 Id Builder::makeFloatType(int width)
    267 {
    268     // try to find it
    269     Instruction* type;
    270     for (int t = 0; t < (int)groupedTypes[OpTypeFloat].size(); ++t) {
    271         type = groupedTypes[OpTypeFloat][t];
    272         if (type->getImmediateOperand(0) == (unsigned)width)
    273             return type->getResultId();
    274     }
    275 
    276     // not found, make it
    277     type = new Instruction(getUniqueId(), NoType, OpTypeFloat);
    278     type->addImmediateOperand(width);
    279     groupedTypes[OpTypeFloat].push_back(type);
    280     constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
    281     module.mapInstruction(type);
    282 
    283     // deal with capabilities
    284     switch (width) {
    285     case 16:
    286         // currently handled by storage-type declarations and post processing
    287         break;
    288     case 64:
    289         addCapability(CapabilityFloat64);
    290         break;
    291     default:
    292         break;
    293     }
    294 
    295     return type->getResultId();
    296 }
    297 
    298 // Make a struct without checking for duplication.
    299 // See makeStructResultType() for non-decorated structs
    300 // needed as the result of some instructions, which does
    301 // check for duplicates.
    302 Id Builder::makeStructType(const std::vector<Id>& members, const char* name)
    303 {
    304     // Don't look for previous one, because in the general case,
    305     // structs can be duplicated except for decorations.
    306 
    307     // not found, make it
    308     Instruction* type = new Instruction(getUniqueId(), NoType, OpTypeStruct);
    309     for (int op = 0; op < (int)members.size(); ++op)
    310         type->addIdOperand(members[op]);
    311     groupedTypes[OpTypeStruct].push_back(type);
    312     constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
    313     module.mapInstruction(type);
    314     addName(type->getResultId(), name);
    315 
    316     return type->getResultId();
    317 }
    318 
    319 // Make a struct for the simple results of several instructions,
    320 // checking for duplication.
    321 Id Builder::makeStructResultType(Id type0, Id type1)
    322 {
    323     // try to find it
    324     Instruction* type;
    325     for (int t = 0; t < (int)groupedTypes[OpTypeStruct].size(); ++t) {
    326         type = groupedTypes[OpTypeStruct][t];
    327         if (type->getNumOperands() != 2)
    328             continue;
    329         if (type->getIdOperand(0) != type0 ||
    330             type->getIdOperand(1) != type1)
    331             continue;
    332         return type->getResultId();
    333     }
    334 
    335     // not found, make it
    336     std::vector<spv::Id> members;
    337     members.push_back(type0);
    338     members.push_back(type1);
    339 
    340     return makeStructType(members, "ResType");
    341 }
    342 
    343 Id Builder::makeVectorType(Id component, int size)
    344 {
    345     // try to find it
    346     Instruction* type;
    347     for (int t = 0; t < (int)groupedTypes[OpTypeVector].size(); ++t) {
    348         type = groupedTypes[OpTypeVector][t];
    349         if (type->getIdOperand(0) == component &&
    350             type->getImmediateOperand(1) == (unsigned)size)
    351             return type->getResultId();
    352     }
    353 
    354     // not found, make it
    355     type = new Instruction(getUniqueId(), NoType, OpTypeVector);
    356     type->addIdOperand(component);
    357     type->addImmediateOperand(size);
    358     groupedTypes[OpTypeVector].push_back(type);
    359     constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
    360     module.mapInstruction(type);
    361 
    362     return type->getResultId();
    363 }
    364 
    365 Id Builder::makeMatrixType(Id component, int cols, int rows)
    366 {
    367     assert(cols <= maxMatrixSize && rows <= maxMatrixSize);
    368 
    369     Id column = makeVectorType(component, rows);
    370 
    371     // try to find it
    372     Instruction* type;
    373     for (int t = 0; t < (int)groupedTypes[OpTypeMatrix].size(); ++t) {
    374         type = groupedTypes[OpTypeMatrix][t];
    375         if (type->getIdOperand(0) == column &&
    376             type->getImmediateOperand(1) == (unsigned)cols)
    377             return type->getResultId();
    378     }
    379 
    380     // not found, make it
    381     type = new Instruction(getUniqueId(), NoType, OpTypeMatrix);
    382     type->addIdOperand(column);
    383     type->addImmediateOperand(cols);
    384     groupedTypes[OpTypeMatrix].push_back(type);
    385     constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
    386     module.mapInstruction(type);
    387 
    388     return type->getResultId();
    389 }
    390 
    391 // TODO: performance: track arrays per stride
    392 // If a stride is supplied (non-zero) make an array.
    393 // If no stride (0), reuse previous array types.
    394 // 'size' is an Id of a constant or specialization constant of the array size
    395 Id Builder::makeArrayType(Id element, Id sizeId, int stride)
    396 {
    397     Instruction* type;
    398     if (stride == 0) {
    399         // try to find existing type
    400         for (int t = 0; t < (int)groupedTypes[OpTypeArray].size(); ++t) {
    401             type = groupedTypes[OpTypeArray][t];
    402             if (type->getIdOperand(0) == element &&
    403                 type->getIdOperand(1) == sizeId)
    404                 return type->getResultId();
    405         }
    406     }
    407 
    408     // not found, make it
    409     type = new Instruction(getUniqueId(), NoType, OpTypeArray);
    410     type->addIdOperand(element);
    411     type->addIdOperand(sizeId);
    412     groupedTypes[OpTypeArray].push_back(type);
    413     constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
    414     module.mapInstruction(type);
    415 
    416     return type->getResultId();
    417 }
    418 
    419 Id Builder::makeRuntimeArray(Id element)
    420 {
    421     Instruction* type = new Instruction(getUniqueId(), NoType, OpTypeRuntimeArray);
    422     type->addIdOperand(element);
    423     constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
    424     module.mapInstruction(type);
    425 
    426     return type->getResultId();
    427 }
    428 
    429 Id Builder::makeFunctionType(Id returnType, const std::vector<Id>& paramTypes)
    430 {
    431     // try to find it
    432     Instruction* type;
    433     for (int t = 0; t < (int)groupedTypes[OpTypeFunction].size(); ++t) {
    434         type = groupedTypes[OpTypeFunction][t];
    435         if (type->getIdOperand(0) != returnType || (int)paramTypes.size() != type->getNumOperands() - 1)
    436             continue;
    437         bool mismatch = false;
    438         for (int p = 0; p < (int)paramTypes.size(); ++p) {
    439             if (paramTypes[p] != type->getIdOperand(p + 1)) {
    440                 mismatch = true;
    441                 break;
    442             }
    443         }
    444         if (! mismatch)
    445             return type->getResultId();
    446     }
    447 
    448     // not found, make it
    449     type = new Instruction(getUniqueId(), NoType, OpTypeFunction);
    450     type->addIdOperand(returnType);
    451     for (int p = 0; p < (int)paramTypes.size(); ++p)
    452         type->addIdOperand(paramTypes[p]);
    453     groupedTypes[OpTypeFunction].push_back(type);
    454     constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
    455     module.mapInstruction(type);
    456 
    457     return type->getResultId();
    458 }
    459 
    460 Id Builder::makeImageType(Id sampledType, Dim dim, bool depth, bool arrayed, bool ms, unsigned sampled, ImageFormat format)
    461 {
    462     assert(sampled == 1 || sampled == 2);
    463 
    464     // try to find it
    465     Instruction* type;
    466     for (int t = 0; t < (int)groupedTypes[OpTypeImage].size(); ++t) {
    467         type = groupedTypes[OpTypeImage][t];
    468         if (type->getIdOperand(0) == sampledType &&
    469             type->getImmediateOperand(1) == (unsigned int)dim &&
    470             type->getImmediateOperand(2) == (  depth ? 1u : 0u) &&
    471             type->getImmediateOperand(3) == (arrayed ? 1u : 0u) &&
    472             type->getImmediateOperand(4) == (     ms ? 1u : 0u) &&
    473             type->getImmediateOperand(5) == sampled &&
    474             type->getImmediateOperand(6) == (unsigned int)format)
    475             return type->getResultId();
    476     }
    477 
    478     // not found, make it
    479     type = new Instruction(getUniqueId(), NoType, OpTypeImage);
    480     type->addIdOperand(sampledType);
    481     type->addImmediateOperand(   dim);
    482     type->addImmediateOperand(  depth ? 1 : 0);
    483     type->addImmediateOperand(arrayed ? 1 : 0);
    484     type->addImmediateOperand(     ms ? 1 : 0);
    485     type->addImmediateOperand(sampled);
    486     type->addImmediateOperand((unsigned int)format);
    487 
    488     groupedTypes[OpTypeImage].push_back(type);
    489     constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
    490     module.mapInstruction(type);
    491 
    492     // deal with capabilities
    493     switch (dim) {
    494     case DimBuffer:
    495         if (sampled == 1)
    496             addCapability(CapabilitySampledBuffer);
    497         else
    498             addCapability(CapabilityImageBuffer);
    499         break;
    500     case Dim1D:
    501         if (sampled == 1)
    502             addCapability(CapabilitySampled1D);
    503         else
    504             addCapability(CapabilityImage1D);
    505         break;
    506     case DimCube:
    507         if (arrayed) {
    508             if (sampled == 1)
    509                 addCapability(CapabilitySampledCubeArray);
    510             else
    511                 addCapability(CapabilityImageCubeArray);
    512         }
    513         break;
    514     case DimRect:
    515         if (sampled == 1)
    516             addCapability(CapabilitySampledRect);
    517         else
    518             addCapability(CapabilityImageRect);
    519         break;
    520     case DimSubpassData:
    521         addCapability(CapabilityInputAttachment);
    522         break;
    523     default:
    524         break;
    525     }
    526 
    527     if (ms) {
    528         if (sampled == 2) {
    529             // Images used with subpass data are not storage
    530             // images, so don't require the capability for them.
    531             if (dim != Dim::DimSubpassData)
    532                 addCapability(CapabilityStorageImageMultisample);
    533             if (arrayed)
    534                 addCapability(CapabilityImageMSArray);
    535         }
    536     }
    537 
    538     return type->getResultId();
    539 }
    540 
    541 Id Builder::makeSampledImageType(Id imageType)
    542 {
    543     // try to find it
    544     Instruction* type;
    545     for (int t = 0; t < (int)groupedTypes[OpTypeSampledImage].size(); ++t) {
    546         type = groupedTypes[OpTypeSampledImage][t];
    547         if (type->getIdOperand(0) == imageType)
    548             return type->getResultId();
    549     }
    550 
    551     // not found, make it
    552     type = new Instruction(getUniqueId(), NoType, OpTypeSampledImage);
    553     type->addIdOperand(imageType);
    554 
    555     groupedTypes[OpTypeSampledImage].push_back(type);
    556     constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
    557     module.mapInstruction(type);
    558 
    559     return type->getResultId();
    560 }
    561 
    562 #ifdef NV_EXTENSIONS
    563 Id Builder::makeAccelerationStructureNVType()
    564 {
    565     Instruction *type;
    566     if (groupedTypes[OpTypeAccelerationStructureNV].size() == 0) {
    567         type = new Instruction(getUniqueId(), NoType, OpTypeAccelerationStructureNV);
    568         groupedTypes[OpTypeAccelerationStructureNV].push_back(type);
    569         constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
    570         module.mapInstruction(type);
    571     } else {
    572         type = groupedTypes[OpTypeAccelerationStructureNV].back();
    573     }
    574 
    575     return type->getResultId();
    576 }
    577 #endif
    578 Id Builder::getDerefTypeId(Id resultId) const
    579 {
    580     Id typeId = getTypeId(resultId);
    581     assert(isPointerType(typeId));
    582 
    583     return module.getInstruction(typeId)->getIdOperand(1);
    584 }
    585 
    586 Op Builder::getMostBasicTypeClass(Id typeId) const
    587 {
    588     Instruction* instr = module.getInstruction(typeId);
    589 
    590     Op typeClass = instr->getOpCode();
    591     switch (typeClass)
    592     {
    593     case OpTypeVector:
    594     case OpTypeMatrix:
    595     case OpTypeArray:
    596     case OpTypeRuntimeArray:
    597         return getMostBasicTypeClass(instr->getIdOperand(0));
    598     case OpTypePointer:
    599         return getMostBasicTypeClass(instr->getIdOperand(1));
    600     default:
    601         return typeClass;
    602     }
    603 }
    604 
    605 int Builder::getNumTypeConstituents(Id typeId) const
    606 {
    607     Instruction* instr = module.getInstruction(typeId);
    608 
    609     switch (instr->getOpCode())
    610     {
    611     case OpTypeBool:
    612     case OpTypeInt:
    613     case OpTypeFloat:
    614     case OpTypePointer:
    615         return 1;
    616     case OpTypeVector:
    617     case OpTypeMatrix:
    618         return instr->getImmediateOperand(1);
    619     case OpTypeArray:
    620     {
    621         Id lengthId = instr->getIdOperand(1);
    622         return module.getInstruction(lengthId)->getImmediateOperand(0);
    623     }
    624     case OpTypeStruct:
    625         return instr->getNumOperands();
    626     default:
    627         assert(0);
    628         return 1;
    629     }
    630 }
    631 
    632 // Return the lowest-level type of scalar that an homogeneous composite is made out of.
    633 // Typically, this is just to find out if something is made out of ints or floats.
    634 // However, it includes returning a structure, if say, it is an array of structure.
    635 Id Builder::getScalarTypeId(Id typeId) const
    636 {
    637     Instruction* instr = module.getInstruction(typeId);
    638 
    639     Op typeClass = instr->getOpCode();
    640     switch (typeClass)
    641     {
    642     case OpTypeVoid:
    643     case OpTypeBool:
    644     case OpTypeInt:
    645     case OpTypeFloat:
    646     case OpTypeStruct:
    647         return instr->getResultId();
    648     case OpTypeVector:
    649     case OpTypeMatrix:
    650     case OpTypeArray:
    651     case OpTypeRuntimeArray:
    652     case OpTypePointer:
    653         return getScalarTypeId(getContainedTypeId(typeId));
    654     default:
    655         assert(0);
    656         return NoResult;
    657     }
    658 }
    659 
    660 // Return the type of 'member' of a composite.
    661 Id Builder::getContainedTypeId(Id typeId, int member) const
    662 {
    663     Instruction* instr = module.getInstruction(typeId);
    664 
    665     Op typeClass = instr->getOpCode();
    666     switch (typeClass)
    667     {
    668     case OpTypeVector:
    669     case OpTypeMatrix:
    670     case OpTypeArray:
    671     case OpTypeRuntimeArray:
    672         return instr->getIdOperand(0);
    673     case OpTypePointer:
    674         return instr->getIdOperand(1);
    675     case OpTypeStruct:
    676         return instr->getIdOperand(member);
    677     default:
    678         assert(0);
    679         return NoResult;
    680     }
    681 }
    682 
    683 // Return the immediately contained type of a given composite type.
    684 Id Builder::getContainedTypeId(Id typeId) const
    685 {
    686     return getContainedTypeId(typeId, 0);
    687 }
    688 
    689 // Returns true if 'typeId' is or contains a scalar type declared with 'typeOp'
    690 // of width 'width'. The 'width' is only consumed for int and float types.
    691 // Returns false otherwise.
    692 bool Builder::containsType(Id typeId, spv::Op typeOp, unsigned int width) const
    693 {
    694     const Instruction& instr = *module.getInstruction(typeId);
    695 
    696     Op typeClass = instr.getOpCode();
    697     switch (typeClass)
    698     {
    699     case OpTypeInt:
    700     case OpTypeFloat:
    701         return typeClass == typeOp && instr.getImmediateOperand(0) == width;
    702     case OpTypeStruct:
    703         for (int m = 0; m < instr.getNumOperands(); ++m) {
    704             if (containsType(instr.getIdOperand(m), typeOp, width))
    705                 return true;
    706         }
    707         return false;
    708     case OpTypePointer:
    709         return false;
    710     case OpTypeVector:
    711     case OpTypeMatrix:
    712     case OpTypeArray:
    713     case OpTypeRuntimeArray:
    714         return containsType(getContainedTypeId(typeId), typeOp, width);
    715     default:
    716         return typeClass == typeOp;
    717     }
    718 }
    719 
    720 // return true if the type is a pointer to PhysicalStorageBufferEXT or an
    721 // array of such pointers. These require restrict/aliased decorations.
    722 bool Builder::containsPhysicalStorageBufferOrArray(Id typeId) const
    723 {
    724     const Instruction& instr = *module.getInstruction(typeId);
    725 
    726     Op typeClass = instr.getOpCode();
    727     switch (typeClass)
    728     {
    729     case OpTypePointer:
    730         return getTypeStorageClass(typeId) == StorageClassPhysicalStorageBufferEXT;
    731     case OpTypeArray:
    732         return containsPhysicalStorageBufferOrArray(getContainedTypeId(typeId));
    733     default:
    734         return false;
    735     }
    736 }
    737 
    738 // See if a scalar constant of this type has already been created, so it
    739 // can be reused rather than duplicated.  (Required by the specification).
    740 Id Builder::findScalarConstant(Op typeClass, Op opcode, Id typeId, unsigned value)
    741 {
    742     Instruction* constant;
    743     for (int i = 0; i < (int)groupedConstants[typeClass].size(); ++i) {
    744         constant = groupedConstants[typeClass][i];
    745         if (constant->getOpCode() == opcode &&
    746             constant->getTypeId() == typeId &&
    747             constant->getImmediateOperand(0) == value)
    748             return constant->getResultId();
    749     }
    750 
    751     return 0;
    752 }
    753 
    754 // Version of findScalarConstant (see above) for scalars that take two operands (e.g. a 'double' or 'int64').
    755 Id Builder::findScalarConstant(Op typeClass, Op opcode, Id typeId, unsigned v1, unsigned v2)
    756 {
    757     Instruction* constant;
    758     for (int i = 0; i < (int)groupedConstants[typeClass].size(); ++i) {
    759         constant = groupedConstants[typeClass][i];
    760         if (constant->getOpCode() == opcode &&
    761             constant->getTypeId() == typeId &&
    762             constant->getImmediateOperand(0) == v1 &&
    763             constant->getImmediateOperand(1) == v2)
    764             return constant->getResultId();
    765     }
    766 
    767     return 0;
    768 }
    769 
    770 // Return true if consuming 'opcode' means consuming a constant.
    771 // "constant" here means after final transform to executable code,
    772 // the value consumed will be a constant, so includes specialization.
    773 bool Builder::isConstantOpCode(Op opcode) const
    774 {
    775     switch (opcode) {
    776     case OpUndef:
    777     case OpConstantTrue:
    778     case OpConstantFalse:
    779     case OpConstant:
    780     case OpConstantComposite:
    781     case OpConstantSampler:
    782     case OpConstantNull:
    783     case OpSpecConstantTrue:
    784     case OpSpecConstantFalse:
    785     case OpSpecConstant:
    786     case OpSpecConstantComposite:
    787     case OpSpecConstantOp:
    788         return true;
    789     default:
    790         return false;
    791     }
    792 }
    793 
    794 // Return true if consuming 'opcode' means consuming a specialization constant.
    795 bool Builder::isSpecConstantOpCode(Op opcode) const
    796 {
    797     switch (opcode) {
    798     case OpSpecConstantTrue:
    799     case OpSpecConstantFalse:
    800     case OpSpecConstant:
    801     case OpSpecConstantComposite:
    802     case OpSpecConstantOp:
    803         return true;
    804     default:
    805         return false;
    806     }
    807 }
    808 
    809 Id Builder::makeBoolConstant(bool b, bool specConstant)
    810 {
    811     Id typeId = makeBoolType();
    812     Instruction* constant;
    813     Op opcode = specConstant ? (b ? OpSpecConstantTrue : OpSpecConstantFalse) : (b ? OpConstantTrue : OpConstantFalse);
    814 
    815     // See if we already made it. Applies only to regular constants, because specialization constants
    816     // must remain distinct for the purpose of applying a SpecId decoration.
    817     if (! specConstant) {
    818         Id existing = 0;
    819         for (int i = 0; i < (int)groupedConstants[OpTypeBool].size(); ++i) {
    820             constant = groupedConstants[OpTypeBool][i];
    821             if (constant->getTypeId() == typeId && constant->getOpCode() == opcode)
    822                 existing = constant->getResultId();
    823         }
    824 
    825         if (existing)
    826             return existing;
    827     }
    828 
    829     // Make it
    830     Instruction* c = new Instruction(getUniqueId(), typeId, opcode);
    831     constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(c));
    832     groupedConstants[OpTypeBool].push_back(c);
    833     module.mapInstruction(c);
    834 
    835     return c->getResultId();
    836 }
    837 
    838 Id Builder::makeIntConstant(Id typeId, unsigned value, bool specConstant)
    839 {
    840     Op opcode = specConstant ? OpSpecConstant : OpConstant;
    841 
    842     // See if we already made it. Applies only to regular constants, because specialization constants
    843     // must remain distinct for the purpose of applying a SpecId decoration.
    844     if (! specConstant) {
    845         Id existing = findScalarConstant(OpTypeInt, opcode, typeId, value);
    846         if (existing)
    847             return existing;
    848     }
    849 
    850     Instruction* c = new Instruction(getUniqueId(), typeId, opcode);
    851     c->addImmediateOperand(value);
    852     constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(c));
    853     groupedConstants[OpTypeInt].push_back(c);
    854     module.mapInstruction(c);
    855 
    856     return c->getResultId();
    857 }
    858 
    859 Id Builder::makeInt64Constant(Id typeId, unsigned long long value, bool specConstant)
    860 {
    861     Op opcode = specConstant ? OpSpecConstant : OpConstant;
    862 
    863     unsigned op1 = value & 0xFFFFFFFF;
    864     unsigned op2 = value >> 32;
    865 
    866     // See if we already made it. Applies only to regular constants, because specialization constants
    867     // must remain distinct for the purpose of applying a SpecId decoration.
    868     if (! specConstant) {
    869         Id existing = findScalarConstant(OpTypeInt, opcode, typeId, op1, op2);
    870         if (existing)
    871             return existing;
    872     }
    873 
    874     Instruction* c = new Instruction(getUniqueId(), typeId, opcode);
    875     c->addImmediateOperand(op1);
    876     c->addImmediateOperand(op2);
    877     constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(c));
    878     groupedConstants[OpTypeInt].push_back(c);
    879     module.mapInstruction(c);
    880 
    881     return c->getResultId();
    882 }
    883 
    884 Id Builder::makeFloatConstant(float f, bool specConstant)
    885 {
    886     Op opcode = specConstant ? OpSpecConstant : OpConstant;
    887     Id typeId = makeFloatType(32);
    888     union { float fl; unsigned int ui; } u;
    889     u.fl = f;
    890     unsigned value = u.ui;
    891 
    892     // See if we already made it. Applies only to regular constants, because specialization constants
    893     // must remain distinct for the purpose of applying a SpecId decoration.
    894     if (! specConstant) {
    895         Id existing = findScalarConstant(OpTypeFloat, opcode, typeId, value);
    896         if (existing)
    897             return existing;
    898     }
    899 
    900     Instruction* c = new Instruction(getUniqueId(), typeId, opcode);
    901     c->addImmediateOperand(value);
    902     constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(c));
    903     groupedConstants[OpTypeFloat].push_back(c);
    904     module.mapInstruction(c);
    905 
    906     return c->getResultId();
    907 }
    908 
    909 Id Builder::makeDoubleConstant(double d, bool specConstant)
    910 {
    911     Op opcode = specConstant ? OpSpecConstant : OpConstant;
    912     Id typeId = makeFloatType(64);
    913     union { double db; unsigned long long ull; } u;
    914     u.db = d;
    915     unsigned long long value = u.ull;
    916     unsigned op1 = value & 0xFFFFFFFF;
    917     unsigned op2 = value >> 32;
    918 
    919     // See if we already made it. Applies only to regular constants, because specialization constants
    920     // must remain distinct for the purpose of applying a SpecId decoration.
    921     if (! specConstant) {
    922         Id existing = findScalarConstant(OpTypeFloat, opcode, typeId, op1, op2);
    923         if (existing)
    924             return existing;
    925     }
    926 
    927     Instruction* c = new Instruction(getUniqueId(), typeId, opcode);
    928     c->addImmediateOperand(op1);
    929     c->addImmediateOperand(op2);
    930     constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(c));
    931     groupedConstants[OpTypeFloat].push_back(c);
    932     module.mapInstruction(c);
    933 
    934     return c->getResultId();
    935 }
    936 
    937 Id Builder::makeFloat16Constant(float f16, bool specConstant)
    938 {
    939     Op opcode = specConstant ? OpSpecConstant : OpConstant;
    940     Id typeId = makeFloatType(16);
    941 
    942     spvutils::HexFloat<spvutils::FloatProxy<float>> fVal(f16);
    943     spvutils::HexFloat<spvutils::FloatProxy<spvutils::Float16>> f16Val(0);
    944     fVal.castTo(f16Val, spvutils::kRoundToZero);
    945 
    946     unsigned value = f16Val.value().getAsFloat().get_value();
    947 
    948     // See if we already made it. Applies only to regular constants, because specialization constants
    949     // must remain distinct for the purpose of applying a SpecId decoration.
    950     if (!specConstant) {
    951         Id existing = findScalarConstant(OpTypeFloat, opcode, typeId, value);
    952         if (existing)
    953             return existing;
    954     }
    955 
    956     Instruction* c = new Instruction(getUniqueId(), typeId, opcode);
    957     c->addImmediateOperand(value);
    958     constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(c));
    959     groupedConstants[OpTypeFloat].push_back(c);
    960     module.mapInstruction(c);
    961 
    962     return c->getResultId();
    963 }
    964 
    965 Id Builder::makeFpConstant(Id type, double d, bool specConstant)
    966 {
    967         assert(isFloatType(type));
    968 
    969         switch (getScalarTypeWidth(type)) {
    970         case 16:
    971                 return makeFloat16Constant((float)d, specConstant);
    972         case 32:
    973                 return makeFloatConstant((float)d, specConstant);
    974         case 64:
    975                 return makeDoubleConstant(d, specConstant);
    976         default:
    977                 break;
    978         }
    979 
    980         assert(false);
    981         return NoResult;
    982 }
    983 
    984 Id Builder::findCompositeConstant(Op typeClass, const std::vector<Id>& comps)
    985 {
    986     Instruction* constant = 0;
    987     bool found = false;
    988     for (int i = 0; i < (int)groupedConstants[typeClass].size(); ++i) {
    989         constant = groupedConstants[typeClass][i];
    990 
    991         // same shape?
    992         if (constant->getNumOperands() != (int)comps.size())
    993             continue;
    994 
    995         // same contents?
    996         bool mismatch = false;
    997         for (int op = 0; op < constant->getNumOperands(); ++op) {
    998             if (constant->getIdOperand(op) != comps[op]) {
    999                 mismatch = true;
   1000                 break;
   1001             }
   1002         }
   1003         if (! mismatch) {
   1004             found = true;
   1005             break;
   1006         }
   1007     }
   1008 
   1009     return found ? constant->getResultId() : NoResult;
   1010 }
   1011 
   1012 Id Builder::findStructConstant(Id typeId, const std::vector<Id>& comps)
   1013 {
   1014     Instruction* constant = 0;
   1015     bool found = false;
   1016     for (int i = 0; i < (int)groupedStructConstants[typeId].size(); ++i) {
   1017         constant = groupedStructConstants[typeId][i];
   1018 
   1019         // same contents?
   1020         bool mismatch = false;
   1021         for (int op = 0; op < constant->getNumOperands(); ++op) {
   1022             if (constant->getIdOperand(op) != comps[op]) {
   1023                 mismatch = true;
   1024                 break;
   1025             }
   1026         }
   1027         if (! mismatch) {
   1028             found = true;
   1029             break;
   1030         }
   1031     }
   1032 
   1033     return found ? constant->getResultId() : NoResult;
   1034 }
   1035 
   1036 // Comments in header
   1037 Id Builder::makeCompositeConstant(Id typeId, const std::vector<Id>& members, bool specConstant)
   1038 {
   1039     Op opcode = specConstant ? OpSpecConstantComposite : OpConstantComposite;
   1040     assert(typeId);
   1041     Op typeClass = getTypeClass(typeId);
   1042 
   1043     switch (typeClass) {
   1044     case OpTypeVector:
   1045     case OpTypeArray:
   1046     case OpTypeMatrix:
   1047         if (! specConstant) {
   1048             Id existing = findCompositeConstant(typeClass, members);
   1049             if (existing)
   1050                 return existing;
   1051         }
   1052         break;
   1053     case OpTypeStruct:
   1054         if (! specConstant) {
   1055             Id existing = findStructConstant(typeId, members);
   1056             if (existing)
   1057                 return existing;
   1058         }
   1059         break;
   1060     default:
   1061         assert(0);
   1062         return makeFloatConstant(0.0);
   1063     }
   1064 
   1065     Instruction* c = new Instruction(getUniqueId(), typeId, opcode);
   1066     for (int op = 0; op < (int)members.size(); ++op)
   1067         c->addIdOperand(members[op]);
   1068     constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(c));
   1069     if (typeClass == OpTypeStruct)
   1070         groupedStructConstants[typeId].push_back(c);
   1071     else
   1072         groupedConstants[typeClass].push_back(c);
   1073     module.mapInstruction(c);
   1074 
   1075     return c->getResultId();
   1076 }
   1077 
   1078 Instruction* Builder::addEntryPoint(ExecutionModel model, Function* function, const char* name)
   1079 {
   1080     Instruction* entryPoint = new Instruction(OpEntryPoint);
   1081     entryPoint->addImmediateOperand(model);
   1082     entryPoint->addIdOperand(function->getId());
   1083     entryPoint->addStringOperand(name);
   1084 
   1085     entryPoints.push_back(std::unique_ptr<Instruction>(entryPoint));
   1086 
   1087     return entryPoint;
   1088 }
   1089 
   1090 // Currently relying on the fact that all 'value' of interest are small non-negative values.
   1091 void Builder::addExecutionMode(Function* entryPoint, ExecutionMode mode, int value1, int value2, int value3)
   1092 {
   1093     Instruction* instr = new Instruction(OpExecutionMode);
   1094     instr->addIdOperand(entryPoint->getId());
   1095     instr->addImmediateOperand(mode);
   1096     if (value1 >= 0)
   1097         instr->addImmediateOperand(value1);
   1098     if (value2 >= 0)
   1099         instr->addImmediateOperand(value2);
   1100     if (value3 >= 0)
   1101         instr->addImmediateOperand(value3);
   1102 
   1103     executionModes.push_back(std::unique_ptr<Instruction>(instr));
   1104 }
   1105 
   1106 void Builder::addName(Id id, const char* string)
   1107 {
   1108     Instruction* name = new Instruction(OpName);
   1109     name->addIdOperand(id);
   1110     name->addStringOperand(string);
   1111 
   1112     names.push_back(std::unique_ptr<Instruction>(name));
   1113 }
   1114 
   1115 void Builder::addMemberName(Id id, int memberNumber, const char* string)
   1116 {
   1117     Instruction* name = new Instruction(OpMemberName);
   1118     name->addIdOperand(id);
   1119     name->addImmediateOperand(memberNumber);
   1120     name->addStringOperand(string);
   1121 
   1122     names.push_back(std::unique_ptr<Instruction>(name));
   1123 }
   1124 
   1125 void Builder::addDecoration(Id id, Decoration decoration, int num)
   1126 {
   1127     if (decoration == spv::DecorationMax)
   1128         return;
   1129 
   1130     Instruction* dec = new Instruction(OpDecorate);
   1131     dec->addIdOperand(id);
   1132     dec->addImmediateOperand(decoration);
   1133     if (num >= 0)
   1134         dec->addImmediateOperand(num);
   1135 
   1136     decorations.push_back(std::unique_ptr<Instruction>(dec));
   1137 }
   1138 
   1139 void Builder::addDecoration(Id id, Decoration decoration, const char* s)
   1140 {
   1141     if (decoration == spv::DecorationMax)
   1142         return;
   1143 
   1144     Instruction* dec = new Instruction(OpDecorateStringGOOGLE);
   1145     dec->addIdOperand(id);
   1146     dec->addImmediateOperand(decoration);
   1147     dec->addStringOperand(s);
   1148 
   1149     decorations.push_back(std::unique_ptr<Instruction>(dec));
   1150 }
   1151 
   1152 void Builder::addDecorationId(Id id, Decoration decoration, Id idDecoration)
   1153 {
   1154     if (decoration == spv::DecorationMax)
   1155         return;
   1156 
   1157     Instruction* dec = new Instruction(OpDecorateId);
   1158     dec->addIdOperand(id);
   1159     dec->addImmediateOperand(decoration);
   1160     dec->addIdOperand(idDecoration);
   1161 
   1162     decorations.push_back(std::unique_ptr<Instruction>(dec));
   1163 }
   1164 
   1165 void Builder::addMemberDecoration(Id id, unsigned int member, Decoration decoration, int num)
   1166 {
   1167     if (decoration == spv::DecorationMax)
   1168         return;
   1169 
   1170     Instruction* dec = new Instruction(OpMemberDecorate);
   1171     dec->addIdOperand(id);
   1172     dec->addImmediateOperand(member);
   1173     dec->addImmediateOperand(decoration);
   1174     if (num >= 0)
   1175         dec->addImmediateOperand(num);
   1176 
   1177     decorations.push_back(std::unique_ptr<Instruction>(dec));
   1178 }
   1179 
   1180 void Builder::addMemberDecoration(Id id, unsigned int member, Decoration decoration, const char *s)
   1181 {
   1182     if (decoration == spv::DecorationMax)
   1183         return;
   1184 
   1185     Instruction* dec = new Instruction(OpMemberDecorateStringGOOGLE);
   1186     dec->addIdOperand(id);
   1187     dec->addImmediateOperand(member);
   1188     dec->addImmediateOperand(decoration);
   1189     dec->addStringOperand(s);
   1190 
   1191     decorations.push_back(std::unique_ptr<Instruction>(dec));
   1192 }
   1193 
   1194 // Comments in header
   1195 Function* Builder::makeEntryPoint(const char* entryPoint)
   1196 {
   1197     assert(! entryPointFunction);
   1198 
   1199     Block* entry;
   1200     std::vector<Id> params;
   1201     std::vector<std::vector<Decoration>> decorations;
   1202 
   1203     entryPointFunction = makeFunctionEntry(NoPrecision, makeVoidType(), entryPoint, params, decorations, &entry);
   1204 
   1205     return entryPointFunction;
   1206 }
   1207 
   1208 // Comments in header
   1209 Function* Builder::makeFunctionEntry(Decoration precision, Id returnType, const char* name,
   1210                                      const std::vector<Id>& paramTypes, const std::vector<std::vector<Decoration>>& decorations, Block **entry)
   1211 {
   1212     // Make the function and initial instructions in it
   1213     Id typeId = makeFunctionType(returnType, paramTypes);
   1214     Id firstParamId = paramTypes.size() == 0 ? 0 : getUniqueIds((int)paramTypes.size());
   1215     Function* function = new Function(getUniqueId(), returnType, typeId, firstParamId, module);
   1216 
   1217     // Set up the precisions
   1218     setPrecision(function->getId(), precision);
   1219     for (unsigned p = 0; p < (unsigned)decorations.size(); ++p) {
   1220         for (int d = 0; d < (int)decorations[p].size(); ++d)
   1221             addDecoration(firstParamId + p, decorations[p][d]);
   1222     }
   1223 
   1224     // CFG
   1225     if (entry) {
   1226         *entry = new Block(getUniqueId(), *function);
   1227         function->addBlock(*entry);
   1228         setBuildPoint(*entry);
   1229     }
   1230 
   1231     if (name)
   1232         addName(function->getId(), name);
   1233 
   1234     functions.push_back(std::unique_ptr<Function>(function));
   1235 
   1236     return function;
   1237 }
   1238 
   1239 // Comments in header
   1240 void Builder::makeReturn(bool implicit, Id retVal)
   1241 {
   1242     if (retVal) {
   1243         Instruction* inst = new Instruction(NoResult, NoType, OpReturnValue);
   1244         inst->addIdOperand(retVal);
   1245         buildPoint->addInstruction(std::unique_ptr<Instruction>(inst));
   1246     } else
   1247         buildPoint->addInstruction(std::unique_ptr<Instruction>(new Instruction(NoResult, NoType, OpReturn)));
   1248 
   1249     if (! implicit)
   1250         createAndSetNoPredecessorBlock("post-return");
   1251 }
   1252 
   1253 // Comments in header
   1254 void Builder::leaveFunction()
   1255 {
   1256     Block* block = buildPoint;
   1257     Function& function = buildPoint->getParent();
   1258     assert(block);
   1259 
   1260     // If our function did not contain a return, add a return void now.
   1261     if (! block->isTerminated()) {
   1262         if (function.getReturnType() == makeVoidType())
   1263             makeReturn(true);
   1264         else {
   1265             makeReturn(true, createUndefined(function.getReturnType()));
   1266         }
   1267     }
   1268 }
   1269 
   1270 // Comments in header
   1271 void Builder::makeDiscard()
   1272 {
   1273     buildPoint->addInstruction(std::unique_ptr<Instruction>(new Instruction(OpKill)));
   1274     createAndSetNoPredecessorBlock("post-discard");
   1275 }
   1276 
   1277 // Comments in header
   1278 Id Builder::createVariable(StorageClass storageClass, Id type, const char* name)
   1279 {
   1280     Id pointerType = makePointer(storageClass, type);
   1281     Instruction* inst = new Instruction(getUniqueId(), pointerType, OpVariable);
   1282     inst->addImmediateOperand(storageClass);
   1283 
   1284     switch (storageClass) {
   1285     case StorageClassFunction:
   1286         // Validation rules require the declaration in the entry block
   1287         buildPoint->getParent().addLocalVariable(std::unique_ptr<Instruction>(inst));
   1288         break;
   1289 
   1290     default:
   1291         constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(inst));
   1292         module.mapInstruction(inst);
   1293         break;
   1294     }
   1295 
   1296     if (name)
   1297         addName(inst->getResultId(), name);
   1298 
   1299     return inst->getResultId();
   1300 }
   1301 
   1302 // Comments in header
   1303 Id Builder::createUndefined(Id type)
   1304 {
   1305   Instruction* inst = new Instruction(getUniqueId(), type, OpUndef);
   1306   buildPoint->addInstruction(std::unique_ptr<Instruction>(inst));
   1307   return inst->getResultId();
   1308 }
   1309 
   1310 // av/vis/nonprivate are unnecessary and illegal for some storage classes.
   1311 spv::MemoryAccessMask Builder::sanitizeMemoryAccessForStorageClass(spv::MemoryAccessMask memoryAccess, StorageClass sc) const
   1312 {
   1313     switch (sc) {
   1314     case spv::StorageClassUniform:
   1315     case spv::StorageClassWorkgroup:
   1316     case spv::StorageClassStorageBuffer:
   1317     case spv::StorageClassPhysicalStorageBufferEXT:
   1318         break;
   1319     default:
   1320         memoryAccess = spv::MemoryAccessMask(memoryAccess &
   1321                         ~(spv::MemoryAccessMakePointerAvailableKHRMask |
   1322                           spv::MemoryAccessMakePointerVisibleKHRMask |
   1323                           spv::MemoryAccessNonPrivatePointerKHRMask));
   1324         break;
   1325     }
   1326     return memoryAccess;
   1327 }
   1328 
   1329 // Comments in header
   1330 void Builder::createStore(Id rValue, Id lValue, spv::MemoryAccessMask memoryAccess, spv::Scope scope, unsigned int alignment)
   1331 {
   1332     Instruction* store = new Instruction(OpStore);
   1333     store->addIdOperand(lValue);
   1334     store->addIdOperand(rValue);
   1335 
   1336     memoryAccess = sanitizeMemoryAccessForStorageClass(memoryAccess, getStorageClass(lValue));
   1337 
   1338     if (memoryAccess != MemoryAccessMaskNone) {
   1339         store->addImmediateOperand(memoryAccess);
   1340         if (memoryAccess & spv::MemoryAccessAlignedMask) {
   1341             store->addImmediateOperand(alignment);
   1342         }
   1343         if (memoryAccess & spv::MemoryAccessMakePointerAvailableKHRMask) {
   1344             store->addIdOperand(makeUintConstant(scope));
   1345         }
   1346     }
   1347 
   1348     buildPoint->addInstruction(std::unique_ptr<Instruction>(store));
   1349 }
   1350 
   1351 // Comments in header
   1352 Id Builder::createLoad(Id lValue, spv::MemoryAccessMask memoryAccess, spv::Scope scope, unsigned int alignment)
   1353 {
   1354     Instruction* load = new Instruction(getUniqueId(), getDerefTypeId(lValue), OpLoad);
   1355     load->addIdOperand(lValue);
   1356 
   1357     memoryAccess = sanitizeMemoryAccessForStorageClass(memoryAccess, getStorageClass(lValue));
   1358 
   1359     if (memoryAccess != MemoryAccessMaskNone) {
   1360         load->addImmediateOperand(memoryAccess);
   1361         if (memoryAccess & spv::MemoryAccessAlignedMask) {
   1362             load->addImmediateOperand(alignment);
   1363         }
   1364         if (memoryAccess & spv::MemoryAccessMakePointerVisibleKHRMask) {
   1365             load->addIdOperand(makeUintConstant(scope));
   1366         }
   1367     }
   1368 
   1369     buildPoint->addInstruction(std::unique_ptr<Instruction>(load));
   1370 
   1371     return load->getResultId();
   1372 }
   1373 
   1374 // Comments in header
   1375 Id Builder::createAccessChain(StorageClass storageClass, Id base, const std::vector<Id>& offsets)
   1376 {
   1377     // Figure out the final resulting type.
   1378     spv::Id typeId = getTypeId(base);
   1379     assert(isPointerType(typeId) && offsets.size() > 0);
   1380     typeId = getContainedTypeId(typeId);
   1381     for (int i = 0; i < (int)offsets.size(); ++i) {
   1382         if (isStructType(typeId)) {
   1383             assert(isConstantScalar(offsets[i]));
   1384             typeId = getContainedTypeId(typeId, getConstantScalar(offsets[i]));
   1385         } else
   1386             typeId = getContainedTypeId(typeId, offsets[i]);
   1387     }
   1388     typeId = makePointer(storageClass, typeId);
   1389 
   1390     // Make the instruction
   1391     Instruction* chain = new Instruction(getUniqueId(), typeId, OpAccessChain);
   1392     chain->addIdOperand(base);
   1393     for (int i = 0; i < (int)offsets.size(); ++i)
   1394         chain->addIdOperand(offsets[i]);
   1395     buildPoint->addInstruction(std::unique_ptr<Instruction>(chain));
   1396 
   1397     return chain->getResultId();
   1398 }
   1399 
   1400 Id Builder::createArrayLength(Id base, unsigned int member)
   1401 {
   1402     spv::Id intType = makeUintType(32);
   1403     Instruction* length = new Instruction(getUniqueId(), intType, OpArrayLength);
   1404     length->addIdOperand(base);
   1405     length->addImmediateOperand(member);
   1406     buildPoint->addInstruction(std::unique_ptr<Instruction>(length));
   1407 
   1408     return length->getResultId();
   1409 }
   1410 
   1411 Id Builder::createCompositeExtract(Id composite, Id typeId, unsigned index)
   1412 {
   1413     // Generate code for spec constants if in spec constant operation
   1414     // generation mode.
   1415     if (generatingOpCodeForSpecConst) {
   1416         return createSpecConstantOp(OpCompositeExtract, typeId, std::vector<Id>(1, composite), std::vector<Id>(1, index));
   1417     }
   1418     Instruction* extract = new Instruction(getUniqueId(), typeId, OpCompositeExtract);
   1419     extract->addIdOperand(composite);
   1420     extract->addImmediateOperand(index);
   1421     buildPoint->addInstruction(std::unique_ptr<Instruction>(extract));
   1422 
   1423     return extract->getResultId();
   1424 }
   1425 
   1426 Id Builder::createCompositeExtract(Id composite, Id typeId, const std::vector<unsigned>& indexes)
   1427 {
   1428     // Generate code for spec constants if in spec constant operation
   1429     // generation mode.
   1430     if (generatingOpCodeForSpecConst) {
   1431         return createSpecConstantOp(OpCompositeExtract, typeId, std::vector<Id>(1, composite), indexes);
   1432     }
   1433     Instruction* extract = new Instruction(getUniqueId(), typeId, OpCompositeExtract);
   1434     extract->addIdOperand(composite);
   1435     for (int i = 0; i < (int)indexes.size(); ++i)
   1436         extract->addImmediateOperand(indexes[i]);
   1437     buildPoint->addInstruction(std::unique_ptr<Instruction>(extract));
   1438 
   1439     return extract->getResultId();
   1440 }
   1441 
   1442 Id Builder::createCompositeInsert(Id object, Id composite, Id typeId, unsigned index)
   1443 {
   1444     Instruction* insert = new Instruction(getUniqueId(), typeId, OpCompositeInsert);
   1445     insert->addIdOperand(object);
   1446     insert->addIdOperand(composite);
   1447     insert->addImmediateOperand(index);
   1448     buildPoint->addInstruction(std::unique_ptr<Instruction>(insert));
   1449 
   1450     return insert->getResultId();
   1451 }
   1452 
   1453 Id Builder::createCompositeInsert(Id object, Id composite, Id typeId, const std::vector<unsigned>& indexes)
   1454 {
   1455     Instruction* insert = new Instruction(getUniqueId(), typeId, OpCompositeInsert);
   1456     insert->addIdOperand(object);
   1457     insert->addIdOperand(composite);
   1458     for (int i = 0; i < (int)indexes.size(); ++i)
   1459         insert->addImmediateOperand(indexes[i]);
   1460     buildPoint->addInstruction(std::unique_ptr<Instruction>(insert));
   1461 
   1462     return insert->getResultId();
   1463 }
   1464 
   1465 Id Builder::createVectorExtractDynamic(Id vector, Id typeId, Id componentIndex)
   1466 {
   1467     Instruction* extract = new Instruction(getUniqueId(), typeId, OpVectorExtractDynamic);
   1468     extract->addIdOperand(vector);
   1469     extract->addIdOperand(componentIndex);
   1470     buildPoint->addInstruction(std::unique_ptr<Instruction>(extract));
   1471 
   1472     return extract->getResultId();
   1473 }
   1474 
   1475 Id Builder::createVectorInsertDynamic(Id vector, Id typeId, Id component, Id componentIndex)
   1476 {
   1477     Instruction* insert = new Instruction(getUniqueId(), typeId, OpVectorInsertDynamic);
   1478     insert->addIdOperand(vector);
   1479     insert->addIdOperand(component);
   1480     insert->addIdOperand(componentIndex);
   1481     buildPoint->addInstruction(std::unique_ptr<Instruction>(insert));
   1482 
   1483     return insert->getResultId();
   1484 }
   1485 
   1486 // An opcode that has no operands, no result id, and no type
   1487 void Builder::createNoResultOp(Op opCode)
   1488 {
   1489     Instruction* op = new Instruction(opCode);
   1490     buildPoint->addInstruction(std::unique_ptr<Instruction>(op));
   1491 }
   1492 
   1493 // An opcode that has one id operand, no result id, and no type
   1494 void Builder::createNoResultOp(Op opCode, Id operand)
   1495 {
   1496     Instruction* op = new Instruction(opCode);
   1497     op->addIdOperand(operand);
   1498     buildPoint->addInstruction(std::unique_ptr<Instruction>(op));
   1499 }
   1500 
   1501 // An opcode that has one or more operands, no result id, and no type
   1502 void Builder::createNoResultOp(Op opCode, const std::vector<Id>& operands)
   1503 {
   1504     Instruction* op = new Instruction(opCode);
   1505     for (auto it = operands.cbegin(); it != operands.cend(); ++it) {
   1506         op->addIdOperand(*it);
   1507     }
   1508     buildPoint->addInstruction(std::unique_ptr<Instruction>(op));
   1509 }
   1510 
   1511 // An opcode that has multiple operands, no result id, and no type
   1512 void Builder::createNoResultOp(Op opCode, const std::vector<IdImmediate>& operands)
   1513 {
   1514     Instruction* op = new Instruction(opCode);
   1515     for (auto it = operands.cbegin(); it != operands.cend(); ++it) {
   1516         if (it->isId)
   1517             op->addIdOperand(it->word);
   1518         else
   1519             op->addImmediateOperand(it->word);
   1520     }
   1521     buildPoint->addInstruction(std::unique_ptr<Instruction>(op));
   1522 }
   1523 
   1524 void Builder::createControlBarrier(Scope execution, Scope memory, MemorySemanticsMask semantics)
   1525 {
   1526     Instruction* op = new Instruction(OpControlBarrier);
   1527     op->addIdOperand(makeUintConstant(execution));
   1528     op->addIdOperand(makeUintConstant(memory));
   1529     op->addIdOperand(makeUintConstant(semantics));
   1530     buildPoint->addInstruction(std::unique_ptr<Instruction>(op));
   1531 }
   1532 
   1533 void Builder::createMemoryBarrier(unsigned executionScope, unsigned memorySemantics)
   1534 {
   1535     Instruction* op = new Instruction(OpMemoryBarrier);
   1536     op->addIdOperand(makeUintConstant(executionScope));
   1537     op->addIdOperand(makeUintConstant(memorySemantics));
   1538     buildPoint->addInstruction(std::unique_ptr<Instruction>(op));
   1539 }
   1540 
   1541 // An opcode that has one operands, a result id, and a type
   1542 Id Builder::createUnaryOp(Op opCode, Id typeId, Id operand)
   1543 {
   1544     // Generate code for spec constants if in spec constant operation
   1545     // generation mode.
   1546     if (generatingOpCodeForSpecConst) {
   1547         return createSpecConstantOp(opCode, typeId, std::vector<Id>(1, operand), std::vector<Id>());
   1548     }
   1549     Instruction* op = new Instruction(getUniqueId(), typeId, opCode);
   1550     op->addIdOperand(operand);
   1551     buildPoint->addInstruction(std::unique_ptr<Instruction>(op));
   1552 
   1553     return op->getResultId();
   1554 }
   1555 
   1556 Id Builder::createBinOp(Op opCode, Id typeId, Id left, Id right)
   1557 {
   1558     // Generate code for spec constants if in spec constant operation
   1559     // generation mode.
   1560     if (generatingOpCodeForSpecConst) {
   1561         std::vector<Id> operands(2);
   1562         operands[0] = left; operands[1] = right;
   1563         return createSpecConstantOp(opCode, typeId, operands, std::vector<Id>());
   1564     }
   1565     Instruction* op = new Instruction(getUniqueId(), typeId, opCode);
   1566     op->addIdOperand(left);
   1567     op->addIdOperand(right);
   1568     buildPoint->addInstruction(std::unique_ptr<Instruction>(op));
   1569 
   1570     return op->getResultId();
   1571 }
   1572 
   1573 Id Builder::createTriOp(Op opCode, Id typeId, Id op1, Id op2, Id op3)
   1574 {
   1575     // Generate code for spec constants if in spec constant operation
   1576     // generation mode.
   1577     if (generatingOpCodeForSpecConst) {
   1578         std::vector<Id> operands(3);
   1579         operands[0] = op1;
   1580         operands[1] = op2;
   1581         operands[2] = op3;
   1582         return createSpecConstantOp(
   1583             opCode, typeId, operands, std::vector<Id>());
   1584     }
   1585     Instruction* op = new Instruction(getUniqueId(), typeId, opCode);
   1586     op->addIdOperand(op1);
   1587     op->addIdOperand(op2);
   1588     op->addIdOperand(op3);
   1589     buildPoint->addInstruction(std::unique_ptr<Instruction>(op));
   1590 
   1591     return op->getResultId();
   1592 }
   1593 
   1594 Id Builder::createOp(Op opCode, Id typeId, const std::vector<Id>& operands)
   1595 {
   1596     Instruction* op = new Instruction(getUniqueId(), typeId, opCode);
   1597     for (auto it = operands.cbegin(); it != operands.cend(); ++it)
   1598         op->addIdOperand(*it);
   1599     buildPoint->addInstruction(std::unique_ptr<Instruction>(op));
   1600 
   1601     return op->getResultId();
   1602 }
   1603 
   1604 Id Builder::createOp(Op opCode, Id typeId, const std::vector<IdImmediate>& operands)
   1605 {
   1606     Instruction* op = new Instruction(getUniqueId(), typeId, opCode);
   1607     for (auto it = operands.cbegin(); it != operands.cend(); ++it) {
   1608         if (it->isId)
   1609             op->addIdOperand(it->word);
   1610         else
   1611             op->addImmediateOperand(it->word);
   1612     }
   1613     buildPoint->addInstruction(std::unique_ptr<Instruction>(op));
   1614 
   1615     return op->getResultId();
   1616 }
   1617 
   1618 Id Builder::createSpecConstantOp(Op opCode, Id typeId, const std::vector<Id>& operands, const std::vector<unsigned>& literals)
   1619 {
   1620     Instruction* op = new Instruction(getUniqueId(), typeId, OpSpecConstantOp);
   1621     op->addImmediateOperand((unsigned) opCode);
   1622     for (auto it = operands.cbegin(); it != operands.cend(); ++it)
   1623         op->addIdOperand(*it);
   1624     for (auto it = literals.cbegin(); it != literals.cend(); ++it)
   1625         op->addImmediateOperand(*it);
   1626     module.mapInstruction(op);
   1627     constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(op));
   1628 
   1629     return op->getResultId();
   1630 }
   1631 
   1632 Id Builder::createFunctionCall(spv::Function* function, const std::vector<spv::Id>& args)
   1633 {
   1634     Instruction* op = new Instruction(getUniqueId(), function->getReturnType(), OpFunctionCall);
   1635     op->addIdOperand(function->getId());
   1636     for (int a = 0; a < (int)args.size(); ++a)
   1637         op->addIdOperand(args[a]);
   1638     buildPoint->addInstruction(std::unique_ptr<Instruction>(op));
   1639 
   1640     return op->getResultId();
   1641 }
   1642 
   1643 // Comments in header
   1644 Id Builder::createRvalueSwizzle(Decoration precision, Id typeId, Id source, const std::vector<unsigned>& channels)
   1645 {
   1646     if (channels.size() == 1)
   1647         return setPrecision(createCompositeExtract(source, typeId, channels.front()), precision);
   1648 
   1649     if (generatingOpCodeForSpecConst) {
   1650         std::vector<Id> operands(2);
   1651         operands[0] = operands[1] = source;
   1652         return setPrecision(createSpecConstantOp(OpVectorShuffle, typeId, operands, channels), precision);
   1653     }
   1654     Instruction* swizzle = new Instruction(getUniqueId(), typeId, OpVectorShuffle);
   1655     assert(isVector(source));
   1656     swizzle->addIdOperand(source);
   1657     swizzle->addIdOperand(source);
   1658     for (int i = 0; i < (int)channels.size(); ++i)
   1659         swizzle->addImmediateOperand(channels[i]);
   1660     buildPoint->addInstruction(std::unique_ptr<Instruction>(swizzle));
   1661 
   1662     return setPrecision(swizzle->getResultId(), precision);
   1663 }
   1664 
   1665 // Comments in header
   1666 Id Builder::createLvalueSwizzle(Id typeId, Id target, Id source, const std::vector<unsigned>& channels)
   1667 {
   1668     if (channels.size() == 1 && getNumComponents(source) == 1)
   1669         return createCompositeInsert(source, target, typeId, channels.front());
   1670 
   1671     Instruction* swizzle = new Instruction(getUniqueId(), typeId, OpVectorShuffle);
   1672 
   1673     assert(isVector(target));
   1674     swizzle->addIdOperand(target);
   1675 
   1676     assert(getNumComponents(source) == (int)channels.size());
   1677     assert(isVector(source));
   1678     swizzle->addIdOperand(source);
   1679 
   1680     // Set up an identity shuffle from the base value to the result value
   1681     unsigned int components[4];
   1682     int numTargetComponents = getNumComponents(target);
   1683     for (int i = 0; i < numTargetComponents; ++i)
   1684         components[i] = i;
   1685 
   1686     // Punch in the l-value swizzle
   1687     for (int i = 0; i < (int)channels.size(); ++i)
   1688         components[channels[i]] = numTargetComponents + i;
   1689 
   1690     // finish the instruction with these components selectors
   1691     for (int i = 0; i < numTargetComponents; ++i)
   1692         swizzle->addImmediateOperand(components[i]);
   1693     buildPoint->addInstruction(std::unique_ptr<Instruction>(swizzle));
   1694 
   1695     return swizzle->getResultId();
   1696 }
   1697 
   1698 // Comments in header
   1699 void Builder::promoteScalar(Decoration precision, Id& left, Id& right)
   1700 {
   1701     int direction = getNumComponents(right) - getNumComponents(left);
   1702 
   1703     if (direction > 0)
   1704         left = smearScalar(precision, left, makeVectorType(getTypeId(left), getNumComponents(right)));
   1705     else if (direction < 0)
   1706         right = smearScalar(precision, right, makeVectorType(getTypeId(right), getNumComponents(left)));
   1707 
   1708     return;
   1709 }
   1710 
   1711 // Comments in header
   1712 Id Builder::smearScalar(Decoration precision, Id scalar, Id vectorType)
   1713 {
   1714     assert(getNumComponents(scalar) == 1);
   1715     assert(getTypeId(scalar) == getScalarTypeId(vectorType));
   1716 
   1717     int numComponents = getNumTypeComponents(vectorType);
   1718     if (numComponents == 1)
   1719         return scalar;
   1720 
   1721     Instruction* smear = nullptr;
   1722     if (generatingOpCodeForSpecConst) {
   1723         auto members = std::vector<spv::Id>(numComponents, scalar);
   1724         // Sometime even in spec-constant-op mode, the temporary vector created by
   1725         // promoting a scalar might not be a spec constant. This should depend on
   1726         // the scalar.
   1727         // e.g.:
   1728         //  const vec2 spec_const_result = a_spec_const_vec2 + a_front_end_const_scalar;
   1729         // In such cases, the temporary vector created from a_front_end_const_scalar
   1730         // is not a spec constant vector, even though the binary operation node is marked
   1731         // as 'specConstant' and we are in spec-constant-op mode.
   1732         auto result_id = makeCompositeConstant(vectorType, members, isSpecConstant(scalar));
   1733         smear = module.getInstruction(result_id);
   1734     } else {
   1735         smear = new Instruction(getUniqueId(), vectorType, OpCompositeConstruct);
   1736         for (int c = 0; c < numComponents; ++c)
   1737             smear->addIdOperand(scalar);
   1738         buildPoint->addInstruction(std::unique_ptr<Instruction>(smear));
   1739     }
   1740 
   1741     return setPrecision(smear->getResultId(), precision);
   1742 }
   1743 
   1744 // Comments in header
   1745 Id Builder::createBuiltinCall(Id resultType, Id builtins, int entryPoint, const std::vector<Id>& args)
   1746 {
   1747     Instruction* inst = new Instruction(getUniqueId(), resultType, OpExtInst);
   1748     inst->addIdOperand(builtins);
   1749     inst->addImmediateOperand(entryPoint);
   1750     for (int arg = 0; arg < (int)args.size(); ++arg)
   1751         inst->addIdOperand(args[arg]);
   1752 
   1753     buildPoint->addInstruction(std::unique_ptr<Instruction>(inst));
   1754 
   1755     return inst->getResultId();
   1756 }
   1757 
   1758 // Accept all parameters needed to create a texture instruction.
   1759 // Create the correct instruction based on the inputs, and make the call.
   1760 Id Builder::createTextureCall(Decoration precision, Id resultType, bool sparse, bool fetch, bool proj, bool gather,
   1761     bool noImplicitLod, const TextureParameters& parameters)
   1762 {
   1763     static const int maxTextureArgs = 10;
   1764     Id texArgs[maxTextureArgs] = {};
   1765 
   1766     //
   1767     // Set up the fixed arguments
   1768     //
   1769     int numArgs = 0;
   1770     bool explicitLod = false;
   1771     texArgs[numArgs++] = parameters.sampler;
   1772     texArgs[numArgs++] = parameters.coords;
   1773     if (parameters.Dref != NoResult)
   1774         texArgs[numArgs++] = parameters.Dref;
   1775     if (parameters.component != NoResult)
   1776         texArgs[numArgs++] = parameters.component;
   1777 
   1778 #ifdef NV_EXTENSIONS
   1779     if (parameters.granularity != NoResult)
   1780         texArgs[numArgs++] = parameters.granularity;
   1781     if (parameters.coarse != NoResult)
   1782         texArgs[numArgs++] = parameters.coarse;
   1783 #endif
   1784 
   1785     //
   1786     // Set up the optional arguments
   1787     //
   1788     int optArgNum = numArgs;                        // track which operand, if it exists, is the mask of optional arguments
   1789     ++numArgs;                                      // speculatively make room for the mask operand
   1790     ImageOperandsMask mask = ImageOperandsMaskNone; // the mask operand
   1791     if (parameters.bias) {
   1792         mask = (ImageOperandsMask)(mask | ImageOperandsBiasMask);
   1793         texArgs[numArgs++] = parameters.bias;
   1794     }
   1795     if (parameters.lod) {
   1796         mask = (ImageOperandsMask)(mask | ImageOperandsLodMask);
   1797         texArgs[numArgs++] = parameters.lod;
   1798         explicitLod = true;
   1799     } else if (parameters.gradX) {
   1800         mask = (ImageOperandsMask)(mask | ImageOperandsGradMask);
   1801         texArgs[numArgs++] = parameters.gradX;
   1802         texArgs[numArgs++] = parameters.gradY;
   1803         explicitLod = true;
   1804     } else if (noImplicitLod && ! fetch && ! gather) {
   1805         // have to explicitly use lod of 0 if not allowed to have them be implicit, and
   1806         // we would otherwise be about to issue an implicit instruction
   1807         mask = (ImageOperandsMask)(mask | ImageOperandsLodMask);
   1808         texArgs[numArgs++] = makeFloatConstant(0.0);
   1809         explicitLod = true;
   1810     }
   1811     if (parameters.offset) {
   1812         if (isConstant(parameters.offset))
   1813             mask = (ImageOperandsMask)(mask | ImageOperandsConstOffsetMask);
   1814         else {
   1815             addCapability(CapabilityImageGatherExtended);
   1816             mask = (ImageOperandsMask)(mask | ImageOperandsOffsetMask);
   1817         }
   1818         texArgs[numArgs++] = parameters.offset;
   1819     }
   1820     if (parameters.offsets) {
   1821         addCapability(CapabilityImageGatherExtended);
   1822         mask = (ImageOperandsMask)(mask | ImageOperandsConstOffsetsMask);
   1823         texArgs[numArgs++] = parameters.offsets;
   1824     }
   1825     if (parameters.sample) {
   1826         mask = (ImageOperandsMask)(mask | ImageOperandsSampleMask);
   1827         texArgs[numArgs++] = parameters.sample;
   1828     }
   1829     if (parameters.lodClamp) {
   1830         // capability if this bit is used
   1831         addCapability(CapabilityMinLod);
   1832 
   1833         mask = (ImageOperandsMask)(mask | ImageOperandsMinLodMask);
   1834         texArgs[numArgs++] = parameters.lodClamp;
   1835     }
   1836     if (parameters.nonprivate) {
   1837         mask = mask | ImageOperandsNonPrivateTexelKHRMask;
   1838     }
   1839     if (parameters.volatil) {
   1840         mask = mask | ImageOperandsVolatileTexelKHRMask;
   1841     }
   1842     if (mask == ImageOperandsMaskNone)
   1843         --numArgs;  // undo speculative reservation for the mask argument
   1844     else
   1845         texArgs[optArgNum] = mask;
   1846 
   1847     //
   1848     // Set up the instruction
   1849     //
   1850     Op opCode = OpNop;  // All paths below need to set this
   1851     if (fetch) {
   1852         if (sparse)
   1853             opCode = OpImageSparseFetch;
   1854         else
   1855             opCode = OpImageFetch;
   1856 #ifdef NV_EXTENSIONS
   1857     } else if (parameters.granularity && parameters.coarse) {
   1858         opCode = OpImageSampleFootprintNV;
   1859 #endif
   1860     } else if (gather) {
   1861         if (parameters.Dref)
   1862             if (sparse)
   1863                 opCode = OpImageSparseDrefGather;
   1864             else
   1865                 opCode = OpImageDrefGather;
   1866         else
   1867             if (sparse)
   1868                 opCode = OpImageSparseGather;
   1869             else
   1870                 opCode = OpImageGather;
   1871     } else if (explicitLod) {
   1872         if (parameters.Dref) {
   1873             if (proj)
   1874                 if (sparse)
   1875                     opCode = OpImageSparseSampleProjDrefExplicitLod;
   1876                 else
   1877                     opCode = OpImageSampleProjDrefExplicitLod;
   1878             else
   1879                 if (sparse)
   1880                     opCode = OpImageSparseSampleDrefExplicitLod;
   1881                 else
   1882                     opCode = OpImageSampleDrefExplicitLod;
   1883         } else {
   1884             if (proj)
   1885                 if (sparse)
   1886                     opCode = OpImageSparseSampleProjExplicitLod;
   1887                 else
   1888                     opCode = OpImageSampleProjExplicitLod;
   1889             else
   1890                 if (sparse)
   1891                     opCode = OpImageSparseSampleExplicitLod;
   1892                 else
   1893                     opCode = OpImageSampleExplicitLod;
   1894         }
   1895     } else {
   1896         if (parameters.Dref) {
   1897             if (proj)
   1898                 if (sparse)
   1899                     opCode = OpImageSparseSampleProjDrefImplicitLod;
   1900                 else
   1901                     opCode = OpImageSampleProjDrefImplicitLod;
   1902             else
   1903                 if (sparse)
   1904                     opCode = OpImageSparseSampleDrefImplicitLod;
   1905                 else
   1906                     opCode = OpImageSampleDrefImplicitLod;
   1907         } else {
   1908             if (proj)
   1909                 if (sparse)
   1910                     opCode = OpImageSparseSampleProjImplicitLod;
   1911                 else
   1912                     opCode = OpImageSampleProjImplicitLod;
   1913             else
   1914                 if (sparse)
   1915                     opCode = OpImageSparseSampleImplicitLod;
   1916                 else
   1917                     opCode = OpImageSampleImplicitLod;
   1918         }
   1919     }
   1920 
   1921     // See if the result type is expecting a smeared result.
   1922     // This happens when a legacy shadow*() call is made, which
   1923     // gets a vec4 back instead of a float.
   1924     Id smearedType = resultType;
   1925     if (! isScalarType(resultType)) {
   1926         switch (opCode) {
   1927         case OpImageSampleDrefImplicitLod:
   1928         case OpImageSampleDrefExplicitLod:
   1929         case OpImageSampleProjDrefImplicitLod:
   1930         case OpImageSampleProjDrefExplicitLod:
   1931             resultType = getScalarTypeId(resultType);
   1932             break;
   1933         default:
   1934             break;
   1935         }
   1936     }
   1937 
   1938     Id typeId0 = 0;
   1939     Id typeId1 = 0;
   1940 
   1941     if (sparse) {
   1942         typeId0 = resultType;
   1943         typeId1 = getDerefTypeId(parameters.texelOut);
   1944         resultType = makeStructResultType(typeId0, typeId1);
   1945     }
   1946 
   1947     // Build the SPIR-V instruction
   1948     Instruction* textureInst = new Instruction(getUniqueId(), resultType, opCode);
   1949     for (int op = 0; op < optArgNum; ++op)
   1950         textureInst->addIdOperand(texArgs[op]);
   1951     if (optArgNum < numArgs)
   1952         textureInst->addImmediateOperand(texArgs[optArgNum]);
   1953     for (int op = optArgNum + 1; op < numArgs; ++op)
   1954         textureInst->addIdOperand(texArgs[op]);
   1955     setPrecision(textureInst->getResultId(), precision);
   1956     buildPoint->addInstruction(std::unique_ptr<Instruction>(textureInst));
   1957 
   1958     Id resultId = textureInst->getResultId();
   1959 
   1960     if (sparse) {
   1961         // set capability
   1962         addCapability(CapabilitySparseResidency);
   1963 
   1964         // Decode the return type that was a special structure
   1965         createStore(createCompositeExtract(resultId, typeId1, 1), parameters.texelOut);
   1966         resultId = createCompositeExtract(resultId, typeId0, 0);
   1967         setPrecision(resultId, precision);
   1968     } else {
   1969         // When a smear is needed, do it, as per what was computed
   1970         // above when resultType was changed to a scalar type.
   1971         if (resultType != smearedType)
   1972             resultId = smearScalar(precision, resultId, smearedType);
   1973     }
   1974 
   1975     return resultId;
   1976 }
   1977 
   1978 // Comments in header
   1979 Id Builder::createTextureQueryCall(Op opCode, const TextureParameters& parameters, bool isUnsignedResult)
   1980 {
   1981     // Figure out the result type
   1982     Id resultType = 0;
   1983     switch (opCode) {
   1984     case OpImageQuerySize:
   1985     case OpImageQuerySizeLod:
   1986     {
   1987         int numComponents = 0;
   1988         switch (getTypeDimensionality(getImageType(parameters.sampler))) {
   1989         case Dim1D:
   1990         case DimBuffer:
   1991             numComponents = 1;
   1992             break;
   1993         case Dim2D:
   1994         case DimCube:
   1995         case DimRect:
   1996         case DimSubpassData:
   1997             numComponents = 2;
   1998             break;
   1999         case Dim3D:
   2000             numComponents = 3;
   2001             break;
   2002 
   2003         default:
   2004             assert(0);
   2005             break;
   2006         }
   2007         if (isArrayedImageType(getImageType(parameters.sampler)))
   2008             ++numComponents;
   2009 
   2010         Id intType = isUnsignedResult ? makeUintType(32) : makeIntType(32);
   2011         if (numComponents == 1)
   2012             resultType = intType;
   2013         else
   2014             resultType = makeVectorType(intType, numComponents);
   2015 
   2016         break;
   2017     }
   2018     case OpImageQueryLod:
   2019 #ifdef AMD_EXTENSIONS
   2020         resultType = makeVectorType(getScalarTypeId(getTypeId(parameters.coords)), 2);
   2021 #else
   2022         resultType = makeVectorType(makeFloatType(32), 2);
   2023 #endif
   2024         break;
   2025     case OpImageQueryLevels:
   2026     case OpImageQuerySamples:
   2027         resultType = isUnsignedResult ? makeUintType(32) : makeIntType(32);
   2028         break;
   2029     default:
   2030         assert(0);
   2031         break;
   2032     }
   2033 
   2034     Instruction* query = new Instruction(getUniqueId(), resultType, opCode);
   2035     query->addIdOperand(parameters.sampler);
   2036     if (parameters.coords)
   2037         query->addIdOperand(parameters.coords);
   2038     if (parameters.lod)
   2039         query->addIdOperand(parameters.lod);
   2040     buildPoint->addInstruction(std::unique_ptr<Instruction>(query));
   2041 
   2042     return query->getResultId();
   2043 }
   2044 
   2045 // External comments in header.
   2046 // Operates recursively to visit the composite's hierarchy.
   2047 Id Builder::createCompositeCompare(Decoration precision, Id value1, Id value2, bool equal)
   2048 {
   2049     Id boolType = makeBoolType();
   2050     Id valueType = getTypeId(value1);
   2051 
   2052     Id resultId = NoResult;
   2053 
   2054     int numConstituents = getNumTypeConstituents(valueType);
   2055 
   2056     // Scalars and Vectors
   2057 
   2058     if (isScalarType(valueType) || isVectorType(valueType)) {
   2059         assert(valueType == getTypeId(value2));
   2060         // These just need a single comparison, just have
   2061         // to figure out what it is.
   2062         Op op;
   2063         switch (getMostBasicTypeClass(valueType)) {
   2064         case OpTypeFloat:
   2065             op = equal ? OpFOrdEqual : OpFOrdNotEqual;
   2066             break;
   2067         case OpTypeInt:
   2068         default:
   2069             op = equal ? OpIEqual : OpINotEqual;
   2070             break;
   2071         case OpTypeBool:
   2072             op = equal ? OpLogicalEqual : OpLogicalNotEqual;
   2073             precision = NoPrecision;
   2074             break;
   2075         }
   2076 
   2077         if (isScalarType(valueType)) {
   2078             // scalar
   2079             resultId = createBinOp(op, boolType, value1, value2);
   2080         } else {
   2081             // vector
   2082             resultId = createBinOp(op, makeVectorType(boolType, numConstituents), value1, value2);
   2083             setPrecision(resultId, precision);
   2084             // reduce vector compares...
   2085             resultId = createUnaryOp(equal ? OpAll : OpAny, boolType, resultId);
   2086         }
   2087 
   2088         return setPrecision(resultId, precision);
   2089     }
   2090 
   2091     // Only structs, arrays, and matrices should be left.
   2092     // They share in common the reduction operation across their constituents.
   2093     assert(isAggregateType(valueType) || isMatrixType(valueType));
   2094 
   2095     // Compare each pair of constituents
   2096     for (int constituent = 0; constituent < numConstituents; ++constituent) {
   2097         std::vector<unsigned> indexes(1, constituent);
   2098         Id constituentType1 = getContainedTypeId(getTypeId(value1), constituent);
   2099         Id constituentType2 = getContainedTypeId(getTypeId(value2), constituent);
   2100         Id constituent1 = createCompositeExtract(value1, constituentType1, indexes);
   2101         Id constituent2 = createCompositeExtract(value2, constituentType2, indexes);
   2102 
   2103         Id subResultId = createCompositeCompare(precision, constituent1, constituent2, equal);
   2104 
   2105         if (constituent == 0)
   2106             resultId = subResultId;
   2107         else
   2108             resultId = setPrecision(createBinOp(equal ? OpLogicalAnd : OpLogicalOr, boolType, resultId, subResultId), precision);
   2109     }
   2110 
   2111     return resultId;
   2112 }
   2113 
   2114 // OpCompositeConstruct
   2115 Id Builder::createCompositeConstruct(Id typeId, const std::vector<Id>& constituents)
   2116 {
   2117     assert(isAggregateType(typeId) || (getNumTypeConstituents(typeId) > 1 && getNumTypeConstituents(typeId) == (int)constituents.size()));
   2118 
   2119     if (generatingOpCodeForSpecConst) {
   2120         // Sometime, even in spec-constant-op mode, the constant composite to be
   2121         // constructed may not be a specialization constant.
   2122         // e.g.:
   2123         //  const mat2 m2 = mat2(a_spec_const, a_front_end_const, another_front_end_const, third_front_end_const);
   2124         // The first column vector should be a spec constant one, as a_spec_const is a spec constant.
   2125         // The second column vector should NOT be spec constant, as it does not contain any spec constants.
   2126         // To handle such cases, we check the constituents of the constant vector to determine whether this
   2127         // vector should be created as a spec constant.
   2128         return makeCompositeConstant(typeId, constituents,
   2129                                      std::any_of(constituents.begin(), constituents.end(),
   2130                                                  [&](spv::Id id) { return isSpecConstant(id); }));
   2131     }
   2132 
   2133     Instruction* op = new Instruction(getUniqueId(), typeId, OpCompositeConstruct);
   2134     for (int c = 0; c < (int)constituents.size(); ++c)
   2135         op->addIdOperand(constituents[c]);
   2136     buildPoint->addInstruction(std::unique_ptr<Instruction>(op));
   2137 
   2138     return op->getResultId();
   2139 }
   2140 
   2141 // Vector or scalar constructor
   2142 Id Builder::createConstructor(Decoration precision, const std::vector<Id>& sources, Id resultTypeId)
   2143 {
   2144     Id result = NoResult;
   2145     unsigned int numTargetComponents = getNumTypeComponents(resultTypeId);
   2146     unsigned int targetComponent = 0;
   2147 
   2148     // Special case: when calling a vector constructor with a single scalar
   2149     // argument, smear the scalar
   2150     if (sources.size() == 1 && isScalar(sources[0]) && numTargetComponents > 1)
   2151         return smearScalar(precision, sources[0], resultTypeId);
   2152 
   2153     // accumulate the arguments for OpCompositeConstruct
   2154     std::vector<Id> constituents;
   2155     Id scalarTypeId = getScalarTypeId(resultTypeId);
   2156 
   2157     // lambda to store the result of visiting an argument component
   2158     const auto latchResult = [&](Id comp) {
   2159         if (numTargetComponents > 1)
   2160             constituents.push_back(comp);
   2161         else
   2162             result = comp;
   2163         ++targetComponent;
   2164     };
   2165 
   2166     // lambda to visit a vector argument's components
   2167     const auto accumulateVectorConstituents = [&](Id sourceArg) {
   2168         unsigned int sourceSize = getNumComponents(sourceArg);
   2169         unsigned int sourcesToUse = sourceSize;
   2170         if (sourcesToUse + targetComponent > numTargetComponents)
   2171             sourcesToUse = numTargetComponents - targetComponent;
   2172 
   2173         for (unsigned int s = 0; s < sourcesToUse; ++s) {
   2174             std::vector<unsigned> swiz;
   2175             swiz.push_back(s);
   2176             latchResult(createRvalueSwizzle(precision, scalarTypeId, sourceArg, swiz));
   2177         }
   2178     };
   2179 
   2180     // lambda to visit a matrix argument's components
   2181     const auto accumulateMatrixConstituents = [&](Id sourceArg) {
   2182         unsigned int sourceSize = getNumColumns(sourceArg) * getNumRows(sourceArg);
   2183         unsigned int sourcesToUse = sourceSize;
   2184         if (sourcesToUse + targetComponent > numTargetComponents)
   2185             sourcesToUse = numTargetComponents - targetComponent;
   2186 
   2187         int col = 0;
   2188         int row = 0;
   2189         for (unsigned int s = 0; s < sourcesToUse; ++s) {
   2190             if (row >= getNumRows(sourceArg)) {
   2191                 row = 0;
   2192                 col++;
   2193             }
   2194             std::vector<Id> indexes;
   2195             indexes.push_back(col);
   2196             indexes.push_back(row);
   2197             latchResult(createCompositeExtract(sourceArg, scalarTypeId, indexes));
   2198             row++;
   2199         }
   2200     };
   2201 
   2202     // Go through the source arguments, each one could have either
   2203     // a single or multiple components to contribute.
   2204     for (unsigned int i = 0; i < sources.size(); ++i) {
   2205 
   2206         if (isScalar(sources[i]) || isPointer(sources[i]))
   2207             latchResult(sources[i]);
   2208         else if (isVector(sources[i]))
   2209             accumulateVectorConstituents(sources[i]);
   2210         else if (isMatrix(sources[i]))
   2211             accumulateMatrixConstituents(sources[i]);
   2212         else
   2213             assert(0);
   2214 
   2215         if (targetComponent >= numTargetComponents)
   2216             break;
   2217     }
   2218 
   2219     // If the result is a vector, make it from the gathered constituents.
   2220     if (constituents.size() > 0)
   2221         result = createCompositeConstruct(resultTypeId, constituents);
   2222 
   2223     return setPrecision(result, precision);
   2224 }
   2225 
   2226 // Comments in header
   2227 Id Builder::createMatrixConstructor(Decoration precision, const std::vector<Id>& sources, Id resultTypeId)
   2228 {
   2229     Id componentTypeId = getScalarTypeId(resultTypeId);
   2230     int numCols = getTypeNumColumns(resultTypeId);
   2231     int numRows = getTypeNumRows(resultTypeId);
   2232 
   2233     Instruction* instr = module.getInstruction(componentTypeId);
   2234     unsigned bitCount = instr->getImmediateOperand(0);
   2235 
   2236     // Optimize matrix constructed from a bigger matrix
   2237     if (isMatrix(sources[0]) && getNumColumns(sources[0]) >= numCols && getNumRows(sources[0]) >= numRows) {
   2238         // To truncate the matrix to a smaller number of rows/columns, we need to:
   2239         // 1. For each column, extract the column and truncate it to the required size using shuffle
   2240         // 2. Assemble the resulting matrix from all columns
   2241         Id matrix = sources[0];
   2242         Id columnTypeId = getContainedTypeId(resultTypeId);
   2243         Id sourceColumnTypeId = getContainedTypeId(getTypeId(matrix));
   2244 
   2245         std::vector<unsigned> channels;
   2246         for (int row = 0; row < numRows; ++row)
   2247             channels.push_back(row);
   2248 
   2249         std::vector<Id> matrixColumns;
   2250         for (int col = 0; col < numCols; ++col) {
   2251             std::vector<unsigned> indexes;
   2252             indexes.push_back(col);
   2253             Id colv = createCompositeExtract(matrix, sourceColumnTypeId, indexes);
   2254             setPrecision(colv, precision);
   2255 
   2256             if (numRows != getNumRows(matrix)) {
   2257                 matrixColumns.push_back(createRvalueSwizzle(precision, columnTypeId, colv, channels));
   2258             } else {
   2259                 matrixColumns.push_back(colv);
   2260             }
   2261         }
   2262 
   2263         return setPrecision(createCompositeConstruct(resultTypeId, matrixColumns), precision);
   2264     }
   2265 
   2266     // Otherwise, will use a two step process
   2267     // 1. make a compile-time 2D array of values
   2268     // 2. construct a matrix from that array
   2269 
   2270     // Step 1.
   2271 
   2272     // initialize the array to the identity matrix
   2273     Id ids[maxMatrixSize][maxMatrixSize];
   2274     Id  one = (bitCount == 64 ? makeDoubleConstant(1.0) : makeFloatConstant(1.0));
   2275     Id zero = (bitCount == 64 ? makeDoubleConstant(0.0) : makeFloatConstant(0.0));
   2276     for (int col = 0; col < 4; ++col) {
   2277         for (int row = 0; row < 4; ++row) {
   2278             if (col == row)
   2279                 ids[col][row] = one;
   2280             else
   2281                 ids[col][row] = zero;
   2282         }
   2283     }
   2284 
   2285     // modify components as dictated by the arguments
   2286     if (sources.size() == 1 && isScalar(sources[0])) {
   2287         // a single scalar; resets the diagonals
   2288         for (int col = 0; col < 4; ++col)
   2289             ids[col][col] = sources[0];
   2290     } else if (isMatrix(sources[0])) {
   2291         // constructing from another matrix; copy over the parts that exist in both the argument and constructee
   2292         Id matrix = sources[0];
   2293         int minCols = std::min(numCols, getNumColumns(matrix));
   2294         int minRows = std::min(numRows, getNumRows(matrix));
   2295         for (int col = 0; col < minCols; ++col) {
   2296             std::vector<unsigned> indexes;
   2297             indexes.push_back(col);
   2298             for (int row = 0; row < minRows; ++row) {
   2299                 indexes.push_back(row);
   2300                 ids[col][row] = createCompositeExtract(matrix, componentTypeId, indexes);
   2301                 indexes.pop_back();
   2302                 setPrecision(ids[col][row], precision);
   2303             }
   2304         }
   2305     } else {
   2306         // fill in the matrix in column-major order with whatever argument components are available
   2307         int row = 0;
   2308         int col = 0;
   2309 
   2310         for (int arg = 0; arg < (int)sources.size(); ++arg) {
   2311             Id argComp = sources[arg];
   2312             for (int comp = 0; comp < getNumComponents(sources[arg]); ++comp) {
   2313                 if (getNumComponents(sources[arg]) > 1) {
   2314                     argComp = createCompositeExtract(sources[arg], componentTypeId, comp);
   2315                     setPrecision(argComp, precision);
   2316                 }
   2317                 ids[col][row++] = argComp;
   2318                 if (row == numRows) {
   2319                     row = 0;
   2320                     col++;
   2321                 }
   2322             }
   2323         }
   2324     }
   2325 
   2326     // Step 2:  Construct a matrix from that array.
   2327     // First make the column vectors, then make the matrix.
   2328 
   2329     // make the column vectors
   2330     Id columnTypeId = getContainedTypeId(resultTypeId);
   2331     std::vector<Id> matrixColumns;
   2332     for (int col = 0; col < numCols; ++col) {
   2333         std::vector<Id> vectorComponents;
   2334         for (int row = 0; row < numRows; ++row)
   2335             vectorComponents.push_back(ids[col][row]);
   2336         Id column = createCompositeConstruct(columnTypeId, vectorComponents);
   2337         setPrecision(column, precision);
   2338         matrixColumns.push_back(column);
   2339     }
   2340 
   2341     // make the matrix
   2342     return setPrecision(createCompositeConstruct(resultTypeId, matrixColumns), precision);
   2343 }
   2344 
   2345 // Comments in header
   2346 Builder::If::If(Id cond, unsigned int ctrl, Builder& gb) :
   2347     builder(gb),
   2348     condition(cond),
   2349     control(ctrl),
   2350     elseBlock(0)
   2351 {
   2352     function = &builder.getBuildPoint()->getParent();
   2353 
   2354     // make the blocks, but only put the then-block into the function,
   2355     // the else-block and merge-block will be added later, in order, after
   2356     // earlier code is emitted
   2357     thenBlock = new Block(builder.getUniqueId(), *function);
   2358     mergeBlock = new Block(builder.getUniqueId(), *function);
   2359 
   2360     // Save the current block, so that we can add in the flow control split when
   2361     // makeEndIf is called.
   2362     headerBlock = builder.getBuildPoint();
   2363 
   2364     function->addBlock(thenBlock);
   2365     builder.setBuildPoint(thenBlock);
   2366 }
   2367 
   2368 // Comments in header
   2369 void Builder::If::makeBeginElse()
   2370 {
   2371     // Close out the "then" by having it jump to the mergeBlock
   2372     builder.createBranch(mergeBlock);
   2373 
   2374     // Make the first else block and add it to the function
   2375     elseBlock = new Block(builder.getUniqueId(), *function);
   2376     function->addBlock(elseBlock);
   2377 
   2378     // Start building the else block
   2379     builder.setBuildPoint(elseBlock);
   2380 }
   2381 
   2382 // Comments in header
   2383 void Builder::If::makeEndIf()
   2384 {
   2385     // jump to the merge block
   2386     builder.createBranch(mergeBlock);
   2387 
   2388     // Go back to the headerBlock and make the flow control split
   2389     builder.setBuildPoint(headerBlock);
   2390     builder.createSelectionMerge(mergeBlock, control);
   2391     if (elseBlock)
   2392         builder.createConditionalBranch(condition, thenBlock, elseBlock);
   2393     else
   2394         builder.createConditionalBranch(condition, thenBlock, mergeBlock);
   2395 
   2396     // add the merge block to the function
   2397     function->addBlock(mergeBlock);
   2398     builder.setBuildPoint(mergeBlock);
   2399 }
   2400 
   2401 // Comments in header
   2402 void Builder::makeSwitch(Id selector, unsigned int control, int numSegments, const std::vector<int>& caseValues,
   2403                          const std::vector<int>& valueIndexToSegment, int defaultSegment,
   2404                          std::vector<Block*>& segmentBlocks)
   2405 {
   2406     Function& function = buildPoint->getParent();
   2407 
   2408     // make all the blocks
   2409     for (int s = 0; s < numSegments; ++s)
   2410         segmentBlocks.push_back(new Block(getUniqueId(), function));
   2411 
   2412     Block* mergeBlock = new Block(getUniqueId(), function);
   2413 
   2414     // make and insert the switch's selection-merge instruction
   2415     createSelectionMerge(mergeBlock, control);
   2416 
   2417     // make the switch instruction
   2418     Instruction* switchInst = new Instruction(NoResult, NoType, OpSwitch);
   2419     switchInst->addIdOperand(selector);
   2420     auto defaultOrMerge = (defaultSegment >= 0) ? segmentBlocks[defaultSegment] : mergeBlock;
   2421     switchInst->addIdOperand(defaultOrMerge->getId());
   2422     defaultOrMerge->addPredecessor(buildPoint);
   2423     for (int i = 0; i < (int)caseValues.size(); ++i) {
   2424         switchInst->addImmediateOperand(caseValues[i]);
   2425         switchInst->addIdOperand(segmentBlocks[valueIndexToSegment[i]]->getId());
   2426         segmentBlocks[valueIndexToSegment[i]]->addPredecessor(buildPoint);
   2427     }
   2428     buildPoint->addInstruction(std::unique_ptr<Instruction>(switchInst));
   2429 
   2430     // push the merge block
   2431     switchMerges.push(mergeBlock);
   2432 }
   2433 
   2434 // Comments in header
   2435 void Builder::addSwitchBreak()
   2436 {
   2437     // branch to the top of the merge block stack
   2438     createBranch(switchMerges.top());
   2439     createAndSetNoPredecessorBlock("post-switch-break");
   2440 }
   2441 
   2442 // Comments in header
   2443 void Builder::nextSwitchSegment(std::vector<Block*>& segmentBlock, int nextSegment)
   2444 {
   2445     int lastSegment = nextSegment - 1;
   2446     if (lastSegment >= 0) {
   2447         // Close out previous segment by jumping, if necessary, to next segment
   2448         if (! buildPoint->isTerminated())
   2449             createBranch(segmentBlock[nextSegment]);
   2450     }
   2451     Block* block = segmentBlock[nextSegment];
   2452     block->getParent().addBlock(block);
   2453     setBuildPoint(block);
   2454 }
   2455 
   2456 // Comments in header
   2457 void Builder::endSwitch(std::vector<Block*>& /*segmentBlock*/)
   2458 {
   2459     // Close out previous segment by jumping, if necessary, to next segment
   2460     if (! buildPoint->isTerminated())
   2461         addSwitchBreak();
   2462 
   2463     switchMerges.top()->getParent().addBlock(switchMerges.top());
   2464     setBuildPoint(switchMerges.top());
   2465 
   2466     switchMerges.pop();
   2467 }
   2468 
   2469 Block& Builder::makeNewBlock()
   2470 {
   2471     Function& function = buildPoint->getParent();
   2472     auto block = new Block(getUniqueId(), function);
   2473     function.addBlock(block);
   2474     return *block;
   2475 }
   2476 
   2477 Builder::LoopBlocks& Builder::makeNewLoop()
   2478 {
   2479     // This verbosity is needed to simultaneously get the same behavior
   2480     // everywhere (id's in the same order), have a syntax that works
   2481     // across lots of versions of C++, have no warnings from pedantic
   2482     // compilation modes, and leave the rest of the code alone.
   2483     Block& head            = makeNewBlock();
   2484     Block& body            = makeNewBlock();
   2485     Block& merge           = makeNewBlock();
   2486     Block& continue_target = makeNewBlock();
   2487     LoopBlocks blocks(head, body, merge, continue_target);
   2488     loops.push(blocks);
   2489     return loops.top();
   2490 }
   2491 
   2492 void Builder::createLoopContinue()
   2493 {
   2494     createBranch(&loops.top().continue_target);
   2495     // Set up a block for dead code.
   2496     createAndSetNoPredecessorBlock("post-loop-continue");
   2497 }
   2498 
   2499 void Builder::createLoopExit()
   2500 {
   2501     createBranch(&loops.top().merge);
   2502     // Set up a block for dead code.
   2503     createAndSetNoPredecessorBlock("post-loop-break");
   2504 }
   2505 
   2506 void Builder::closeLoop()
   2507 {
   2508     loops.pop();
   2509 }
   2510 
   2511 void Builder::clearAccessChain()
   2512 {
   2513     accessChain.base = NoResult;
   2514     accessChain.indexChain.clear();
   2515     accessChain.instr = NoResult;
   2516     accessChain.swizzle.clear();
   2517     accessChain.component = NoResult;
   2518     accessChain.preSwizzleBaseType = NoType;
   2519     accessChain.isRValue = false;
   2520     accessChain.coherentFlags.clear();
   2521     accessChain.alignment = 0;
   2522 }
   2523 
   2524 // Comments in header
   2525 void Builder::accessChainPushSwizzle(std::vector<unsigned>& swizzle, Id preSwizzleBaseType, AccessChain::CoherentFlags coherentFlags, unsigned int alignment)
   2526 {
   2527     accessChain.coherentFlags |= coherentFlags;
   2528     accessChain.alignment |= alignment;
   2529 
   2530     // swizzles can be stacked in GLSL, but simplified to a single
   2531     // one here; the base type doesn't change
   2532     if (accessChain.preSwizzleBaseType == NoType)
   2533         accessChain.preSwizzleBaseType = preSwizzleBaseType;
   2534 
   2535     // if needed, propagate the swizzle for the current access chain
   2536     if (accessChain.swizzle.size() > 0) {
   2537         std::vector<unsigned> oldSwizzle = accessChain.swizzle;
   2538         accessChain.swizzle.resize(0);
   2539         for (unsigned int i = 0; i < swizzle.size(); ++i) {
   2540             assert(swizzle[i] < oldSwizzle.size());
   2541             accessChain.swizzle.push_back(oldSwizzle[swizzle[i]]);
   2542         }
   2543     } else
   2544         accessChain.swizzle = swizzle;
   2545 
   2546     // determine if we need to track this swizzle anymore
   2547     simplifyAccessChainSwizzle();
   2548 }
   2549 
   2550 // Comments in header
   2551 void Builder::accessChainStore(Id rvalue, spv::MemoryAccessMask memoryAccess, spv::Scope scope, unsigned int alignment)
   2552 {
   2553     assert(accessChain.isRValue == false);
   2554 
   2555     transferAccessChainSwizzle(true);
   2556     Id base = collapseAccessChain();
   2557     Id source = rvalue;
   2558 
   2559     // dynamic component should be gone
   2560     assert(accessChain.component == NoResult);
   2561 
   2562     // If swizzle still exists, it is out-of-order or not full, we must load the target vector,
   2563     // extract and insert elements to perform writeMask and/or swizzle.
   2564     if (accessChain.swizzle.size() > 0) {
   2565         Id tempBaseId = createLoad(base);
   2566         source = createLvalueSwizzle(getTypeId(tempBaseId), tempBaseId, source, accessChain.swizzle);
   2567     }
   2568 
   2569     // take LSB of alignment
   2570     alignment = alignment & ~(alignment & (alignment-1));
   2571     if (getStorageClass(base) == StorageClassPhysicalStorageBufferEXT) {
   2572         memoryAccess = (spv::MemoryAccessMask)(memoryAccess | spv::MemoryAccessAlignedMask);
   2573     }
   2574 
   2575     createStore(source, base, memoryAccess, scope, alignment);
   2576 }
   2577 
   2578 // Comments in header
   2579 Id Builder::accessChainLoad(Decoration precision, Decoration nonUniform, Id resultType, spv::MemoryAccessMask memoryAccess, spv::Scope scope, unsigned int alignment)
   2580 {
   2581     Id id;
   2582 
   2583     if (accessChain.isRValue) {
   2584         // transfer access chain, but try to stay in registers
   2585         transferAccessChainSwizzle(false);
   2586         if (accessChain.indexChain.size() > 0) {
   2587             Id swizzleBase = accessChain.preSwizzleBaseType != NoType ? accessChain.preSwizzleBaseType : resultType;
   2588 
   2589             // if all the accesses are constants, we can use OpCompositeExtract
   2590             std::vector<unsigned> indexes;
   2591             bool constant = true;
   2592             for (int i = 0; i < (int)accessChain.indexChain.size(); ++i) {
   2593                 if (isConstantScalar(accessChain.indexChain[i]))
   2594                     indexes.push_back(getConstantScalar(accessChain.indexChain[i]));
   2595                 else {
   2596                     constant = false;
   2597                     break;
   2598                 }
   2599             }
   2600 
   2601             if (constant)
   2602                 id = createCompositeExtract(accessChain.base, swizzleBase, indexes);
   2603             else {
   2604                 // make a new function variable for this r-value
   2605                 Id lValue = createVariable(StorageClassFunction, getTypeId(accessChain.base), "indexable");
   2606 
   2607                 // store into it
   2608                 createStore(accessChain.base, lValue);
   2609 
   2610                 // move base to the new variable
   2611                 accessChain.base = lValue;
   2612                 accessChain.isRValue = false;
   2613 
   2614                 // load through the access chain
   2615                 id = createLoad(collapseAccessChain());
   2616             }
   2617             setPrecision(id, precision);
   2618         } else
   2619             id = accessChain.base;  // no precision, it was set when this was defined
   2620     } else {
   2621         transferAccessChainSwizzle(true);
   2622 
   2623         // take LSB of alignment
   2624         alignment = alignment & ~(alignment & (alignment-1));
   2625         if (getStorageClass(accessChain.base) == StorageClassPhysicalStorageBufferEXT) {
   2626             memoryAccess = (spv::MemoryAccessMask)(memoryAccess | spv::MemoryAccessAlignedMask);
   2627         }
   2628 
   2629         // load through the access chain
   2630         id = createLoad(collapseAccessChain(), memoryAccess, scope, alignment);
   2631         setPrecision(id, precision);
   2632         addDecoration(id, nonUniform);
   2633     }
   2634 
   2635     // Done, unless there are swizzles to do
   2636     if (accessChain.swizzle.size() == 0 && accessChain.component == NoResult)
   2637         return id;
   2638 
   2639     // Do remaining swizzling
   2640 
   2641     // Do the basic swizzle
   2642     if (accessChain.swizzle.size() > 0) {
   2643         Id swizzledType = getScalarTypeId(getTypeId(id));
   2644         if (accessChain.swizzle.size() > 1)
   2645             swizzledType = makeVectorType(swizzledType, (int)accessChain.swizzle.size());
   2646         id = createRvalueSwizzle(precision, swizzledType, id, accessChain.swizzle);
   2647     }
   2648 
   2649     // Do the dynamic component
   2650     if (accessChain.component != NoResult)
   2651         id = setPrecision(createVectorExtractDynamic(id, resultType, accessChain.component), precision);
   2652 
   2653     addDecoration(id, nonUniform);
   2654     return id;
   2655 }
   2656 
   2657 Id Builder::accessChainGetLValue()
   2658 {
   2659     assert(accessChain.isRValue == false);
   2660 
   2661     transferAccessChainSwizzle(true);
   2662     Id lvalue = collapseAccessChain();
   2663 
   2664     // If swizzle exists, it is out-of-order or not full, we must load the target vector,
   2665     // extract and insert elements to perform writeMask and/or swizzle.  This does not
   2666     // go with getting a direct l-value pointer.
   2667     assert(accessChain.swizzle.size() == 0);
   2668     assert(accessChain.component == NoResult);
   2669 
   2670     return lvalue;
   2671 }
   2672 
   2673 // comment in header
   2674 Id Builder::accessChainGetInferredType()
   2675 {
   2676     // anything to operate on?
   2677     if (accessChain.base == NoResult)
   2678         return NoType;
   2679     Id type = getTypeId(accessChain.base);
   2680 
   2681     // do initial dereference
   2682     if (! accessChain.isRValue)
   2683         type = getContainedTypeId(type);
   2684 
   2685     // dereference each index
   2686     for (auto it = accessChain.indexChain.cbegin(); it != accessChain.indexChain.cend(); ++it) {
   2687         if (isStructType(type))
   2688             type = getContainedTypeId(type, getConstantScalar(*it));
   2689         else
   2690             type = getContainedTypeId(type);
   2691     }
   2692 
   2693     // dereference swizzle
   2694     if (accessChain.swizzle.size() == 1)
   2695         type = getContainedTypeId(type);
   2696     else if (accessChain.swizzle.size() > 1)
   2697         type = makeVectorType(getContainedTypeId(type), (int)accessChain.swizzle.size());
   2698 
   2699     // dereference component selection
   2700     if (accessChain.component)
   2701         type = getContainedTypeId(type);
   2702 
   2703     return type;
   2704 }
   2705 
   2706 void Builder::dump(std::vector<unsigned int>& out) const
   2707 {
   2708     // Header, before first instructions:
   2709     out.push_back(MagicNumber);
   2710     out.push_back(spvVersion);
   2711     out.push_back(builderNumber);
   2712     out.push_back(uniqueId + 1);
   2713     out.push_back(0);
   2714 
   2715     // Capabilities
   2716     for (auto it = capabilities.cbegin(); it != capabilities.cend(); ++it) {
   2717         Instruction capInst(0, 0, OpCapability);
   2718         capInst.addImmediateOperand(*it);
   2719         capInst.dump(out);
   2720     }
   2721 
   2722     for (auto it = extensions.cbegin(); it != extensions.cend(); ++it) {
   2723         Instruction extInst(0, 0, OpExtension);
   2724         extInst.addStringOperand(it->c_str());
   2725         extInst.dump(out);
   2726     }
   2727 
   2728     dumpInstructions(out, imports);
   2729     Instruction memInst(0, 0, OpMemoryModel);
   2730     memInst.addImmediateOperand(addressModel);
   2731     memInst.addImmediateOperand(memoryModel);
   2732     memInst.dump(out);
   2733 
   2734     // Instructions saved up while building:
   2735     dumpInstructions(out, entryPoints);
   2736     dumpInstructions(out, executionModes);
   2737 
   2738     // Debug instructions
   2739     dumpInstructions(out, strings);
   2740     dumpSourceInstructions(out);
   2741     for (int e = 0; e < (int)sourceExtensions.size(); ++e) {
   2742         Instruction sourceExtInst(0, 0, OpSourceExtension);
   2743         sourceExtInst.addStringOperand(sourceExtensions[e]);
   2744         sourceExtInst.dump(out);
   2745     }
   2746     dumpInstructions(out, names);
   2747     dumpModuleProcesses(out);
   2748 
   2749     // Annotation instructions
   2750     dumpInstructions(out, decorations);
   2751 
   2752     dumpInstructions(out, constantsTypesGlobals);
   2753     dumpInstructions(out, externals);
   2754 
   2755     // The functions
   2756     module.dump(out);
   2757 }
   2758 
   2759 //
   2760 // Protected methods.
   2761 //
   2762 
   2763 // Turn the described access chain in 'accessChain' into an instruction(s)
   2764 // computing its address.  This *cannot* include complex swizzles, which must
   2765 // be handled after this is called.
   2766 //
   2767 // Can generate code.
   2768 Id Builder::collapseAccessChain()
   2769 {
   2770     assert(accessChain.isRValue == false);
   2771 
   2772     // did we already emit an access chain for this?
   2773     if (accessChain.instr != NoResult)
   2774         return accessChain.instr;
   2775 
   2776     // If we have a dynamic component, we can still transfer
   2777     // that into a final operand to the access chain.  We need to remap the
   2778     // dynamic component through the swizzle to get a new dynamic component to
   2779     // update.
   2780     //
   2781     // This was not done in transferAccessChainSwizzle() because it might
   2782     // generate code.
   2783     remapDynamicSwizzle();
   2784     if (accessChain.component != NoResult) {
   2785         // transfer the dynamic component to the access chain
   2786         accessChain.indexChain.push_back(accessChain.component);
   2787         accessChain.component = NoResult;
   2788     }
   2789 
   2790     // note that non-trivial swizzling is left pending
   2791 
   2792     // do we have an access chain?
   2793     if (accessChain.indexChain.size() == 0)
   2794         return accessChain.base;
   2795 
   2796     // emit the access chain
   2797     StorageClass storageClass = (StorageClass)module.getStorageClass(getTypeId(accessChain.base));
   2798     accessChain.instr = createAccessChain(storageClass, accessChain.base, accessChain.indexChain);
   2799 
   2800     return accessChain.instr;
   2801 }
   2802 
   2803 // For a dynamic component selection of a swizzle.
   2804 //
   2805 // Turn the swizzle and dynamic component into just a dynamic component.
   2806 //
   2807 // Generates code.
   2808 void Builder::remapDynamicSwizzle()
   2809 {
   2810     // do we have a swizzle to remap a dynamic component through?
   2811     if (accessChain.component != NoResult && accessChain.swizzle.size() > 1) {
   2812         // build a vector of the swizzle for the component to map into
   2813         std::vector<Id> components;
   2814         for (int c = 0; c < (int)accessChain.swizzle.size(); ++c)
   2815             components.push_back(makeUintConstant(accessChain.swizzle[c]));
   2816         Id mapType = makeVectorType(makeUintType(32), (int)accessChain.swizzle.size());
   2817         Id map = makeCompositeConstant(mapType, components);
   2818 
   2819         // use it
   2820         accessChain.component = createVectorExtractDynamic(map, makeUintType(32), accessChain.component);
   2821         accessChain.swizzle.clear();
   2822     }
   2823 }
   2824 
   2825 // clear out swizzle if it is redundant, that is reselecting the same components
   2826 // that would be present without the swizzle.
   2827 void Builder::simplifyAccessChainSwizzle()
   2828 {
   2829     // If the swizzle has fewer components than the vector, it is subsetting, and must stay
   2830     // to preserve that fact.
   2831     if (getNumTypeComponents(accessChain.preSwizzleBaseType) > (int)accessChain.swizzle.size())
   2832         return;
   2833 
   2834     // if components are out of order, it is a swizzle
   2835     for (unsigned int i = 0; i < accessChain.swizzle.size(); ++i) {
   2836         if (i != accessChain.swizzle[i])
   2837             return;
   2838     }
   2839 
   2840     // otherwise, there is no need to track this swizzle
   2841     accessChain.swizzle.clear();
   2842     if (accessChain.component == NoResult)
   2843         accessChain.preSwizzleBaseType = NoType;
   2844 }
   2845 
   2846 // To the extent any swizzling can become part of the chain
   2847 // of accesses instead of a post operation, make it so.
   2848 // If 'dynamic' is true, include transferring the dynamic component,
   2849 // otherwise, leave it pending.
   2850 //
   2851 // Does not generate code. just updates the access chain.
   2852 void Builder::transferAccessChainSwizzle(bool dynamic)
   2853 {
   2854     // non existent?
   2855     if (accessChain.swizzle.size() == 0 && accessChain.component == NoResult)
   2856         return;
   2857 
   2858     // too complex?
   2859     // (this requires either a swizzle, or generating code for a dynamic component)
   2860     if (accessChain.swizzle.size() > 1)
   2861         return;
   2862 
   2863     // single component, either in the swizzle and/or dynamic component
   2864     if (accessChain.swizzle.size() == 1) {
   2865         assert(accessChain.component == NoResult);
   2866         // handle static component selection
   2867         accessChain.indexChain.push_back(makeUintConstant(accessChain.swizzle.front()));
   2868         accessChain.swizzle.clear();
   2869         accessChain.preSwizzleBaseType = NoType;
   2870     } else if (dynamic && accessChain.component != NoResult) {
   2871         assert(accessChain.swizzle.size() == 0);
   2872         // handle dynamic component
   2873         accessChain.indexChain.push_back(accessChain.component);
   2874         accessChain.preSwizzleBaseType = NoType;
   2875         accessChain.component = NoResult;
   2876     }
   2877 }
   2878 
   2879 // Utility method for creating a new block and setting the insert point to
   2880 // be in it. This is useful for flow-control operations that need a "dummy"
   2881 // block proceeding them (e.g. instructions after a discard, etc).
   2882 void Builder::createAndSetNoPredecessorBlock(const char* /*name*/)
   2883 {
   2884     Block* block = new Block(getUniqueId(), buildPoint->getParent());
   2885     block->setUnreachable();
   2886     buildPoint->getParent().addBlock(block);
   2887     setBuildPoint(block);
   2888 
   2889     // if (name)
   2890     //    addName(block->getId(), name);
   2891 }
   2892 
   2893 // Comments in header
   2894 void Builder::createBranch(Block* block)
   2895 {
   2896     Instruction* branch = new Instruction(OpBranch);
   2897     branch->addIdOperand(block->getId());
   2898     buildPoint->addInstruction(std::unique_ptr<Instruction>(branch));
   2899     block->addPredecessor(buildPoint);
   2900 }
   2901 
   2902 void Builder::createSelectionMerge(Block* mergeBlock, unsigned int control)
   2903 {
   2904     Instruction* merge = new Instruction(OpSelectionMerge);
   2905     merge->addIdOperand(mergeBlock->getId());
   2906     merge->addImmediateOperand(control);
   2907     buildPoint->addInstruction(std::unique_ptr<Instruction>(merge));
   2908 }
   2909 
   2910 void Builder::createLoopMerge(Block* mergeBlock, Block* continueBlock, unsigned int control,
   2911                               unsigned int dependencyLength)
   2912 {
   2913     Instruction* merge = new Instruction(OpLoopMerge);
   2914     merge->addIdOperand(mergeBlock->getId());
   2915     merge->addIdOperand(continueBlock->getId());
   2916     merge->addImmediateOperand(control);
   2917     if ((control & LoopControlDependencyLengthMask) != 0)
   2918         merge->addImmediateOperand(dependencyLength);
   2919     buildPoint->addInstruction(std::unique_ptr<Instruction>(merge));
   2920 }
   2921 
   2922 void Builder::createConditionalBranch(Id condition, Block* thenBlock, Block* elseBlock)
   2923 {
   2924     Instruction* branch = new Instruction(OpBranchConditional);
   2925     branch->addIdOperand(condition);
   2926     branch->addIdOperand(thenBlock->getId());
   2927     branch->addIdOperand(elseBlock->getId());
   2928     buildPoint->addInstruction(std::unique_ptr<Instruction>(branch));
   2929     thenBlock->addPredecessor(buildPoint);
   2930     elseBlock->addPredecessor(buildPoint);
   2931 }
   2932 
   2933 // OpSource
   2934 // [OpSourceContinued]
   2935 // ...
   2936 void Builder::dumpSourceInstructions(const spv::Id fileId, const std::string& text,
   2937                                      std::vector<unsigned int>& out) const
   2938 {
   2939     const int maxWordCount = 0xFFFF;
   2940     const int opSourceWordCount = 4;
   2941     const int nonNullBytesPerInstruction = 4 * (maxWordCount - opSourceWordCount) - 1;
   2942 
   2943     if (source != SourceLanguageUnknown) {
   2944         // OpSource Language Version File Source
   2945         Instruction sourceInst(NoResult, NoType, OpSource);
   2946         sourceInst.addImmediateOperand(source);
   2947         sourceInst.addImmediateOperand(sourceVersion);
   2948         // File operand
   2949         if (fileId != NoResult) {
   2950             sourceInst.addIdOperand(fileId);
   2951             // Source operand
   2952             if (text.size() > 0) {
   2953                 int nextByte = 0;
   2954                 std::string subString;
   2955                 while ((int)text.size() - nextByte > 0) {
   2956                     subString = text.substr(nextByte, nonNullBytesPerInstruction);
   2957                     if (nextByte == 0) {
   2958                         // OpSource
   2959                         sourceInst.addStringOperand(subString.c_str());
   2960                         sourceInst.dump(out);
   2961                     } else {
   2962                         // OpSourcContinued
   2963                         Instruction sourceContinuedInst(OpSourceContinued);
   2964                         sourceContinuedInst.addStringOperand(subString.c_str());
   2965                         sourceContinuedInst.dump(out);
   2966                     }
   2967                     nextByte += nonNullBytesPerInstruction;
   2968                 }
   2969             } else
   2970                 sourceInst.dump(out);
   2971         } else
   2972             sourceInst.dump(out);
   2973     }
   2974 }
   2975 
   2976 // Dump an OpSource[Continued] sequence for the source and every include file
   2977 void Builder::dumpSourceInstructions(std::vector<unsigned int>& out) const
   2978 {
   2979     dumpSourceInstructions(sourceFileStringId, sourceText, out);
   2980     for (auto iItr = includeFiles.begin(); iItr != includeFiles.end(); ++iItr)
   2981         dumpSourceInstructions(iItr->first, *iItr->second, out);
   2982 }
   2983 
   2984 void Builder::dumpInstructions(std::vector<unsigned int>& out, const std::vector<std::unique_ptr<Instruction> >& instructions) const
   2985 {
   2986     for (int i = 0; i < (int)instructions.size(); ++i) {
   2987         instructions[i]->dump(out);
   2988     }
   2989 }
   2990 
   2991 void Builder::dumpModuleProcesses(std::vector<unsigned int>& out) const
   2992 {
   2993     for (int i = 0; i < (int)moduleProcesses.size(); ++i) {
   2994         Instruction moduleProcessed(OpModuleProcessed);
   2995         moduleProcessed.addStringOperand(moduleProcesses[i]);
   2996         moduleProcessed.dump(out);
   2997     }
   2998 }
   2999 
   3000 }; // end spv namespace
   3001