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