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