mirror of
				https://github.com/RetroDECK/Duckstation.git
				synced 2025-04-10 19:15:14 +00:00 
			
		
		
		
	
		
			
	
	
		
			3128 lines
		
	
	
		
			105 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
		
		
			
		
	
	
			3128 lines
		
	
	
		
			105 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								// Copyright (C) 2014-2015 LunarG, Inc.
							 | 
						||
| 
								 | 
							
								// Copyright (C) 2015-2018 Google, Inc.
							 | 
						||
| 
								 | 
							
								// Modifications Copyright (C) 2020 Advanced Micro Devices, Inc. All rights reserved.
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								// All rights reserved.
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								// Redistribution and use in source and binary forms, with or without
							 | 
						||
| 
								 | 
							
								// modification, are permitted provided that the following conditions
							 | 
						||
| 
								 | 
							
								// are met:
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								//    Redistributions of source code must retain the above copyright
							 | 
						||
| 
								 | 
							
								//    notice, this list of conditions and the following disclaimer.
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								//    Redistributions in binary form must reproduce the above
							 | 
						||
| 
								 | 
							
								//    copyright notice, this list of conditions and the following
							 | 
						||
| 
								 | 
							
								//    disclaimer in the documentation and/or other materials provided
							 | 
						||
| 
								 | 
							
								//    with the distribution.
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								//    Neither the name of 3Dlabs Inc. Ltd. nor the names of its
							 | 
						||
| 
								 | 
							
								//    contributors may be used to endorse or promote products derived
							 | 
						||
| 
								 | 
							
								//    from this software without specific prior written permission.
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
							 | 
						||
| 
								 | 
							
								// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
							 | 
						||
| 
								 | 
							
								// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
							 | 
						||
| 
								 | 
							
								// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
							 | 
						||
| 
								 | 
							
								// COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
							 | 
						||
| 
								 | 
							
								// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
							 | 
						||
| 
								 | 
							
								// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
							 | 
						||
| 
								 | 
							
								// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
							 | 
						||
| 
								 | 
							
								// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
							 | 
						||
| 
								 | 
							
								// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
							 | 
						||
| 
								 | 
							
								// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
							 | 
						||
| 
								 | 
							
								// POSSIBILITY OF SUCH DAMAGE.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								// Helper for making SPIR-V IR.  Generally, this is documented in the header
							 | 
						||
| 
								 | 
							
								// SpvBuilder.h.
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#include <cassert>
							 | 
						||
| 
								 | 
							
								#include <cstdlib>
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#include <unordered_set>
							 | 
						||
| 
								 | 
							
								#include <algorithm>
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#include "SpvBuilder.h"
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#ifndef GLSLANG_WEB
							 | 
						||
| 
								 | 
							
								#include "hex_float.h"
							 | 
						||
| 
								 | 
							
								#endif
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#ifndef _WIN32
							 | 
						||
| 
								 | 
							
								    #include <cstdio>
							 | 
						||
| 
								 | 
							
								#endif
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								namespace spv {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Builder::Builder(unsigned int spvVersion, unsigned int magicNumber, SpvBuildLogger* buildLogger) :
							 | 
						||
| 
								 | 
							
								    spvVersion(spvVersion),
							 | 
						||
| 
								 | 
							
								    source(SourceLanguageUnknown),
							 | 
						||
| 
								 | 
							
								    sourceVersion(0),
							 | 
						||
| 
								 | 
							
								    sourceFileStringId(NoResult),
							 | 
						||
| 
								 | 
							
								    currentLine(0),
							 | 
						||
| 
								 | 
							
								    currentFile(nullptr),
							 | 
						||
| 
								 | 
							
								    emitOpLines(false),
							 | 
						||
| 
								 | 
							
								    addressModel(AddressingModelLogical),
							 | 
						||
| 
								 | 
							
								    memoryModel(MemoryModelGLSL450),
							 | 
						||
| 
								 | 
							
								    builderNumber(magicNumber),
							 | 
						||
| 
								 | 
							
								    buildPoint(0),
							 | 
						||
| 
								 | 
							
								    uniqueId(0),
							 | 
						||
| 
								 | 
							
								    entryPointFunction(0),
							 | 
						||
| 
								 | 
							
								    generatingOpCodeForSpecConst(false),
							 | 
						||
| 
								 | 
							
								    logger(buildLogger)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    clearAccessChain();
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Builder::~Builder()
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Id Builder::import(const char* name)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    Instruction* import = new Instruction(getUniqueId(), NoType, OpExtInstImport);
							 | 
						||
| 
								 | 
							
								    import->addStringOperand(name);
							 | 
						||
| 
								 | 
							
								    module.mapInstruction(import);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    imports.push_back(std::unique_ptr<Instruction>(import));
							 | 
						||
| 
								 | 
							
								    return import->getResultId();
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// Emit instruction for non-filename-based #line directives (ie. no filename
							 | 
						||
| 
								 | 
							
								// seen yet): emit an OpLine if we've been asked to emit OpLines and the line
							 | 
						||
| 
								 | 
							
								// number has changed since the last time, and is a valid line number.
							 | 
						||
| 
								 | 
							
								void Builder::setLine(int lineNum)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    if (lineNum != 0 && lineNum != currentLine) {
							 | 
						||
| 
								 | 
							
								        currentLine = lineNum;
							 | 
						||
| 
								 | 
							
								        if (emitOpLines)
							 | 
						||
| 
								 | 
							
								            addLine(sourceFileStringId, currentLine, 0);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// If no filename, do non-filename-based #line emit. Else do filename-based emit.
							 | 
						||
| 
								 | 
							
								// Emit OpLine if we've been asked to emit OpLines and the line number or filename
							 | 
						||
| 
								 | 
							
								// has changed since the last time, and line number is valid.
							 | 
						||
| 
								 | 
							
								void Builder::setLine(int lineNum, const char* filename)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    if (filename == nullptr) {
							 | 
						||
| 
								 | 
							
								        setLine(lineNum);
							 | 
						||
| 
								 | 
							
								        return;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    if ((lineNum != 0 && lineNum != currentLine) || currentFile == nullptr ||
							 | 
						||
| 
								 | 
							
								            strncmp(filename, currentFile, strlen(currentFile) + 1) != 0) {
							 | 
						||
| 
								 | 
							
								        currentLine = lineNum;
							 | 
						||
| 
								 | 
							
								        currentFile = filename;
							 | 
						||
| 
								 | 
							
								        if (emitOpLines) {
							 | 
						||
| 
								 | 
							
								            spv::Id strId = getStringId(filename);
							 | 
						||
| 
								 | 
							
								            addLine(strId, currentLine, 0);
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								void Builder::addLine(Id fileName, int lineNum, int column)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    Instruction* line = new Instruction(OpLine);
							 | 
						||
| 
								 | 
							
								    line->addIdOperand(fileName);
							 | 
						||
| 
								 | 
							
								    line->addImmediateOperand(lineNum);
							 | 
						||
| 
								 | 
							
								    line->addImmediateOperand(column);
							 | 
						||
| 
								 | 
							
								    buildPoint->addInstruction(std::unique_ptr<Instruction>(line));
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// For creating new groupedTypes (will return old type if the requested one was already made).
							 | 
						||
| 
								 | 
							
								Id Builder::makeVoidType()
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    Instruction* type;
							 | 
						||
| 
								 | 
							
								    if (groupedTypes[OpTypeVoid].size() == 0) {
							 | 
						||
| 
								 | 
							
								        type = new Instruction(getUniqueId(), NoType, OpTypeVoid);
							 | 
						||
| 
								 | 
							
								        groupedTypes[OpTypeVoid].push_back(type);
							 | 
						||
| 
								 | 
							
								        constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
							 | 
						||
| 
								 | 
							
								        module.mapInstruction(type);
							 | 
						||
| 
								 | 
							
								    } else
							 | 
						||
| 
								 | 
							
								        type = groupedTypes[OpTypeVoid].back();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    return type->getResultId();
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Id Builder::makeBoolType()
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    Instruction* type;
							 | 
						||
| 
								 | 
							
								    if (groupedTypes[OpTypeBool].size() == 0) {
							 | 
						||
| 
								 | 
							
								        type = new Instruction(getUniqueId(), NoType, OpTypeBool);
							 | 
						||
| 
								 | 
							
								        groupedTypes[OpTypeBool].push_back(type);
							 | 
						||
| 
								 | 
							
								        constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
							 | 
						||
| 
								 | 
							
								        module.mapInstruction(type);
							 | 
						||
| 
								 | 
							
								    } else
							 | 
						||
| 
								 | 
							
								        type = groupedTypes[OpTypeBool].back();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    return type->getResultId();
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Id Builder::makeSamplerType()
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    Instruction* type;
							 | 
						||
| 
								 | 
							
								    if (groupedTypes[OpTypeSampler].size() == 0) {
							 | 
						||
| 
								 | 
							
								        type = new Instruction(getUniqueId(), NoType, OpTypeSampler);
							 | 
						||
| 
								 | 
							
								        groupedTypes[OpTypeSampler].push_back(type);
							 | 
						||
| 
								 | 
							
								        constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
							 | 
						||
| 
								 | 
							
								        module.mapInstruction(type);
							 | 
						||
| 
								 | 
							
								    } else
							 | 
						||
| 
								 | 
							
								        type = groupedTypes[OpTypeSampler].back();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    return type->getResultId();
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Id Builder::makePointer(StorageClass storageClass, Id pointee)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    // try to find it
							 | 
						||
| 
								 | 
							
								    Instruction* type;
							 | 
						||
| 
								 | 
							
								    for (int t = 0; t < (int)groupedTypes[OpTypePointer].size(); ++t) {
							 | 
						||
| 
								 | 
							
								        type = groupedTypes[OpTypePointer][t];
							 | 
						||
| 
								 | 
							
								        if (type->getImmediateOperand(0) == (unsigned)storageClass &&
							 | 
						||
| 
								 | 
							
								            type->getIdOperand(1) == pointee)
							 | 
						||
| 
								 | 
							
								            return type->getResultId();
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // not found, make it
							 | 
						||
| 
								 | 
							
								    type = new Instruction(getUniqueId(), NoType, OpTypePointer);
							 | 
						||
| 
								 | 
							
								    type->addImmediateOperand(storageClass);
							 | 
						||
| 
								 | 
							
								    type->addIdOperand(pointee);
							 | 
						||
| 
								 | 
							
								    groupedTypes[OpTypePointer].push_back(type);
							 | 
						||
| 
								 | 
							
								    constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
							 | 
						||
| 
								 | 
							
								    module.mapInstruction(type);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    return type->getResultId();
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Id Builder::makeForwardPointer(StorageClass storageClass)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    // Caching/uniquifying doesn't work here, because we don't know the
							 | 
						||
| 
								 | 
							
								    // pointee type and there can be multiple forward pointers of the same
							 | 
						||
| 
								 | 
							
								    // storage type. Somebody higher up in the stack must keep track.
							 | 
						||
| 
								 | 
							
								    Instruction* type = new Instruction(getUniqueId(), NoType, OpTypeForwardPointer);
							 | 
						||
| 
								 | 
							
								    type->addImmediateOperand(storageClass);
							 | 
						||
| 
								 | 
							
								    constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
							 | 
						||
| 
								 | 
							
								    module.mapInstruction(type);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    return type->getResultId();
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Id Builder::makePointerFromForwardPointer(StorageClass storageClass, Id forwardPointerType, Id pointee)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    // try to find it
							 | 
						||
| 
								 | 
							
								    Instruction* type;
							 | 
						||
| 
								 | 
							
								    for (int t = 0; t < (int)groupedTypes[OpTypePointer].size(); ++t) {
							 | 
						||
| 
								 | 
							
								        type = groupedTypes[OpTypePointer][t];
							 | 
						||
| 
								 | 
							
								        if (type->getImmediateOperand(0) == (unsigned)storageClass &&
							 | 
						||
| 
								 | 
							
								            type->getIdOperand(1) == pointee)
							 | 
						||
| 
								 | 
							
								            return type->getResultId();
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    type = new Instruction(forwardPointerType, NoType, OpTypePointer);
							 | 
						||
| 
								 | 
							
								    type->addImmediateOperand(storageClass);
							 | 
						||
| 
								 | 
							
								    type->addIdOperand(pointee);
							 | 
						||
| 
								 | 
							
								    groupedTypes[OpTypePointer].push_back(type);
							 | 
						||
| 
								 | 
							
								    constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
							 | 
						||
| 
								 | 
							
								    module.mapInstruction(type);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    return type->getResultId();
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Id Builder::makeIntegerType(int width, bool hasSign)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								#ifdef GLSLANG_WEB
							 | 
						||
| 
								 | 
							
								    assert(width == 32);
							 | 
						||
| 
								 | 
							
								    width = 32;
							 | 
						||
| 
								 | 
							
								#endif
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // try to find it
							 | 
						||
| 
								 | 
							
								    Instruction* type;
							 | 
						||
| 
								 | 
							
								    for (int t = 0; t < (int)groupedTypes[OpTypeInt].size(); ++t) {
							 | 
						||
| 
								 | 
							
								        type = groupedTypes[OpTypeInt][t];
							 | 
						||
| 
								 | 
							
								        if (type->getImmediateOperand(0) == (unsigned)width &&
							 | 
						||
| 
								 | 
							
								            type->getImmediateOperand(1) == (hasSign ? 1u : 0u))
							 | 
						||
| 
								 | 
							
								            return type->getResultId();
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // not found, make it
							 | 
						||
| 
								 | 
							
								    type = new Instruction(getUniqueId(), NoType, OpTypeInt);
							 | 
						||
| 
								 | 
							
								    type->addImmediateOperand(width);
							 | 
						||
| 
								 | 
							
								    type->addImmediateOperand(hasSign ? 1 : 0);
							 | 
						||
| 
								 | 
							
								    groupedTypes[OpTypeInt].push_back(type);
							 | 
						||
| 
								 | 
							
								    constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
							 | 
						||
| 
								 | 
							
								    module.mapInstruction(type);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // deal with capabilities
							 | 
						||
| 
								 | 
							
								    switch (width) {
							 | 
						||
| 
								 | 
							
								    case 8:
							 | 
						||
| 
								 | 
							
								    case 16:
							 | 
						||
| 
								 | 
							
								        // these are currently handled by storage-type declarations and post processing
							 | 
						||
| 
								 | 
							
								        break;
							 | 
						||
| 
								 | 
							
								    case 64:
							 | 
						||
| 
								 | 
							
								        addCapability(CapabilityInt64);
							 | 
						||
| 
								 | 
							
								        break;
							 | 
						||
| 
								 | 
							
								    default:
							 | 
						||
| 
								 | 
							
								        break;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    return type->getResultId();
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Id Builder::makeFloatType(int width)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								#ifdef GLSLANG_WEB
							 | 
						||
| 
								 | 
							
								    assert(width == 32);
							 | 
						||
| 
								 | 
							
								    width = 32;
							 | 
						||
| 
								 | 
							
								#endif
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // try to find it
							 | 
						||
| 
								 | 
							
								    Instruction* type;
							 | 
						||
| 
								 | 
							
								    for (int t = 0; t < (int)groupedTypes[OpTypeFloat].size(); ++t) {
							 | 
						||
| 
								 | 
							
								        type = groupedTypes[OpTypeFloat][t];
							 | 
						||
| 
								 | 
							
								        if (type->getImmediateOperand(0) == (unsigned)width)
							 | 
						||
| 
								 | 
							
								            return type->getResultId();
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // not found, make it
							 | 
						||
| 
								 | 
							
								    type = new Instruction(getUniqueId(), NoType, OpTypeFloat);
							 | 
						||
| 
								 | 
							
								    type->addImmediateOperand(width);
							 | 
						||
| 
								 | 
							
								    groupedTypes[OpTypeFloat].push_back(type);
							 | 
						||
| 
								 | 
							
								    constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
							 | 
						||
| 
								 | 
							
								    module.mapInstruction(type);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // deal with capabilities
							 | 
						||
| 
								 | 
							
								    switch (width) {
							 | 
						||
| 
								 | 
							
								    case 16:
							 | 
						||
| 
								 | 
							
								        // currently handled by storage-type declarations and post processing
							 | 
						||
| 
								 | 
							
								        break;
							 | 
						||
| 
								 | 
							
								    case 64:
							 | 
						||
| 
								 | 
							
								        addCapability(CapabilityFloat64);
							 | 
						||
| 
								 | 
							
								        break;
							 | 
						||
| 
								 | 
							
								    default:
							 | 
						||
| 
								 | 
							
								        break;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    return type->getResultId();
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// Make a struct without checking for duplication.
							 | 
						||
| 
								 | 
							
								// See makeStructResultType() for non-decorated structs
							 | 
						||
| 
								 | 
							
								// needed as the result of some instructions, which does
							 | 
						||
| 
								 | 
							
								// check for duplicates.
							 | 
						||
| 
								 | 
							
								Id Builder::makeStructType(const std::vector<Id>& members, const char* name)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    // Don't look for previous one, because in the general case,
							 | 
						||
| 
								 | 
							
								    // structs can be duplicated except for decorations.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // not found, make it
							 | 
						||
| 
								 | 
							
								    Instruction* type = new Instruction(getUniqueId(), NoType, OpTypeStruct);
							 | 
						||
| 
								 | 
							
								    for (int op = 0; op < (int)members.size(); ++op)
							 | 
						||
| 
								 | 
							
								        type->addIdOperand(members[op]);
							 | 
						||
| 
								 | 
							
								    groupedTypes[OpTypeStruct].push_back(type);
							 | 
						||
| 
								 | 
							
								    constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
							 | 
						||
| 
								 | 
							
								    module.mapInstruction(type);
							 | 
						||
| 
								 | 
							
								    addName(type->getResultId(), name);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    return type->getResultId();
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// Make a struct for the simple results of several instructions,
							 | 
						||
| 
								 | 
							
								// checking for duplication.
							 | 
						||
| 
								 | 
							
								Id Builder::makeStructResultType(Id type0, Id type1)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    // try to find it
							 | 
						||
| 
								 | 
							
								    Instruction* type;
							 | 
						||
| 
								 | 
							
								    for (int t = 0; t < (int)groupedTypes[OpTypeStruct].size(); ++t) {
							 | 
						||
| 
								 | 
							
								        type = groupedTypes[OpTypeStruct][t];
							 | 
						||
| 
								 | 
							
								        if (type->getNumOperands() != 2)
							 | 
						||
| 
								 | 
							
								            continue;
							 | 
						||
| 
								 | 
							
								        if (type->getIdOperand(0) != type0 ||
							 | 
						||
| 
								 | 
							
								            type->getIdOperand(1) != type1)
							 | 
						||
| 
								 | 
							
								            continue;
							 | 
						||
| 
								 | 
							
								        return type->getResultId();
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // not found, make it
							 | 
						||
| 
								 | 
							
								    std::vector<spv::Id> members;
							 | 
						||
| 
								 | 
							
								    members.push_back(type0);
							 | 
						||
| 
								 | 
							
								    members.push_back(type1);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    return makeStructType(members, "ResType");
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Id Builder::makeVectorType(Id component, int size)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    // try to find it
							 | 
						||
| 
								 | 
							
								    Instruction* type;
							 | 
						||
| 
								 | 
							
								    for (int t = 0; t < (int)groupedTypes[OpTypeVector].size(); ++t) {
							 | 
						||
| 
								 | 
							
								        type = groupedTypes[OpTypeVector][t];
							 | 
						||
| 
								 | 
							
								        if (type->getIdOperand(0) == component &&
							 | 
						||
| 
								 | 
							
								            type->getImmediateOperand(1) == (unsigned)size)
							 | 
						||
| 
								 | 
							
								            return type->getResultId();
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // not found, make it
							 | 
						||
| 
								 | 
							
								    type = new Instruction(getUniqueId(), NoType, OpTypeVector);
							 | 
						||
| 
								 | 
							
								    type->addIdOperand(component);
							 | 
						||
| 
								 | 
							
								    type->addImmediateOperand(size);
							 | 
						||
| 
								 | 
							
								    groupedTypes[OpTypeVector].push_back(type);
							 | 
						||
| 
								 | 
							
								    constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
							 | 
						||
| 
								 | 
							
								    module.mapInstruction(type);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    return type->getResultId();
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Id Builder::makeMatrixType(Id component, int cols, int rows)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    assert(cols <= maxMatrixSize && rows <= maxMatrixSize);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    Id column = makeVectorType(component, rows);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // try to find it
							 | 
						||
| 
								 | 
							
								    Instruction* type;
							 | 
						||
| 
								 | 
							
								    for (int t = 0; t < (int)groupedTypes[OpTypeMatrix].size(); ++t) {
							 | 
						||
| 
								 | 
							
								        type = groupedTypes[OpTypeMatrix][t];
							 | 
						||
| 
								 | 
							
								        if (type->getIdOperand(0) == column &&
							 | 
						||
| 
								 | 
							
								            type->getImmediateOperand(1) == (unsigned)cols)
							 | 
						||
| 
								 | 
							
								            return type->getResultId();
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // not found, make it
							 | 
						||
| 
								 | 
							
								    type = new Instruction(getUniqueId(), NoType, OpTypeMatrix);
							 | 
						||
| 
								 | 
							
								    type->addIdOperand(column);
							 | 
						||
| 
								 | 
							
								    type->addImmediateOperand(cols);
							 | 
						||
| 
								 | 
							
								    groupedTypes[OpTypeMatrix].push_back(type);
							 | 
						||
| 
								 | 
							
								    constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
							 | 
						||
| 
								 | 
							
								    module.mapInstruction(type);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    return type->getResultId();
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Id Builder::makeCooperativeMatrixType(Id component, Id scope, Id rows, Id cols)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    // try to find it
							 | 
						||
| 
								 | 
							
								    Instruction* type;
							 | 
						||
| 
								 | 
							
								    for (int t = 0; t < (int)groupedTypes[OpTypeCooperativeMatrixNV].size(); ++t) {
							 | 
						||
| 
								 | 
							
								        type = groupedTypes[OpTypeCooperativeMatrixNV][t];
							 | 
						||
| 
								 | 
							
								        if (type->getIdOperand(0) == component &&
							 | 
						||
| 
								 | 
							
								            type->getIdOperand(1) == scope &&
							 | 
						||
| 
								 | 
							
								            type->getIdOperand(2) == rows &&
							 | 
						||
| 
								 | 
							
								            type->getIdOperand(3) == cols)
							 | 
						||
| 
								 | 
							
								            return type->getResultId();
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // not found, make it
							 | 
						||
| 
								 | 
							
								    type = new Instruction(getUniqueId(), NoType, OpTypeCooperativeMatrixNV);
							 | 
						||
| 
								 | 
							
								    type->addIdOperand(component);
							 | 
						||
| 
								 | 
							
								    type->addIdOperand(scope);
							 | 
						||
| 
								 | 
							
								    type->addIdOperand(rows);
							 | 
						||
| 
								 | 
							
								    type->addIdOperand(cols);
							 | 
						||
| 
								 | 
							
								    groupedTypes[OpTypeCooperativeMatrixNV].push_back(type);
							 | 
						||
| 
								 | 
							
								    constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
							 | 
						||
| 
								 | 
							
								    module.mapInstruction(type);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    return type->getResultId();
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// TODO: performance: track arrays per stride
							 | 
						||
| 
								 | 
							
								// If a stride is supplied (non-zero) make an array.
							 | 
						||
| 
								 | 
							
								// If no stride (0), reuse previous array types.
							 | 
						||
| 
								 | 
							
								// 'size' is an Id of a constant or specialization constant of the array size
							 | 
						||
| 
								 | 
							
								Id Builder::makeArrayType(Id element, Id sizeId, int stride)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    Instruction* type;
							 | 
						||
| 
								 | 
							
								    if (stride == 0) {
							 | 
						||
| 
								 | 
							
								        // try to find existing type
							 | 
						||
| 
								 | 
							
								        for (int t = 0; t < (int)groupedTypes[OpTypeArray].size(); ++t) {
							 | 
						||
| 
								 | 
							
								            type = groupedTypes[OpTypeArray][t];
							 | 
						||
| 
								 | 
							
								            if (type->getIdOperand(0) == element &&
							 | 
						||
| 
								 | 
							
								                type->getIdOperand(1) == sizeId)
							 | 
						||
| 
								 | 
							
								                return type->getResultId();
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // not found, make it
							 | 
						||
| 
								 | 
							
								    type = new Instruction(getUniqueId(), NoType, OpTypeArray);
							 | 
						||
| 
								 | 
							
								    type->addIdOperand(element);
							 | 
						||
| 
								 | 
							
								    type->addIdOperand(sizeId);
							 | 
						||
| 
								 | 
							
								    groupedTypes[OpTypeArray].push_back(type);
							 | 
						||
| 
								 | 
							
								    constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
							 | 
						||
| 
								 | 
							
								    module.mapInstruction(type);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    return type->getResultId();
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Id Builder::makeRuntimeArray(Id element)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    Instruction* type = new Instruction(getUniqueId(), NoType, OpTypeRuntimeArray);
							 | 
						||
| 
								 | 
							
								    type->addIdOperand(element);
							 | 
						||
| 
								 | 
							
								    constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
							 | 
						||
| 
								 | 
							
								    module.mapInstruction(type);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    return type->getResultId();
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Id Builder::makeFunctionType(Id returnType, const std::vector<Id>& paramTypes)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    // try to find it
							 | 
						||
| 
								 | 
							
								    Instruction* type;
							 | 
						||
| 
								 | 
							
								    for (int t = 0; t < (int)groupedTypes[OpTypeFunction].size(); ++t) {
							 | 
						||
| 
								 | 
							
								        type = groupedTypes[OpTypeFunction][t];
							 | 
						||
| 
								 | 
							
								        if (type->getIdOperand(0) != returnType || (int)paramTypes.size() != type->getNumOperands() - 1)
							 | 
						||
| 
								 | 
							
								            continue;
							 | 
						||
| 
								 | 
							
								        bool mismatch = false;
							 | 
						||
| 
								 | 
							
								        for (int p = 0; p < (int)paramTypes.size(); ++p) {
							 | 
						||
| 
								 | 
							
								            if (paramTypes[p] != type->getIdOperand(p + 1)) {
							 | 
						||
| 
								 | 
							
								                mismatch = true;
							 | 
						||
| 
								 | 
							
								                break;
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        if (! mismatch)
							 | 
						||
| 
								 | 
							
								            return type->getResultId();
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // not found, make it
							 | 
						||
| 
								 | 
							
								    type = new Instruction(getUniqueId(), NoType, OpTypeFunction);
							 | 
						||
| 
								 | 
							
								    type->addIdOperand(returnType);
							 | 
						||
| 
								 | 
							
								    for (int p = 0; p < (int)paramTypes.size(); ++p)
							 | 
						||
| 
								 | 
							
								        type->addIdOperand(paramTypes[p]);
							 | 
						||
| 
								 | 
							
								    groupedTypes[OpTypeFunction].push_back(type);
							 | 
						||
| 
								 | 
							
								    constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
							 | 
						||
| 
								 | 
							
								    module.mapInstruction(type);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    return type->getResultId();
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Id Builder::makeImageType(Id sampledType, Dim dim, bool depth, bool arrayed, bool ms, unsigned sampled,
							 | 
						||
| 
								 | 
							
								    ImageFormat format)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    assert(sampled == 1 || sampled == 2);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // try to find it
							 | 
						||
| 
								 | 
							
								    Instruction* type;
							 | 
						||
| 
								 | 
							
								    for (int t = 0; t < (int)groupedTypes[OpTypeImage].size(); ++t) {
							 | 
						||
| 
								 | 
							
								        type = groupedTypes[OpTypeImage][t];
							 | 
						||
| 
								 | 
							
								        if (type->getIdOperand(0) == sampledType &&
							 | 
						||
| 
								 | 
							
								            type->getImmediateOperand(1) == (unsigned int)dim &&
							 | 
						||
| 
								 | 
							
								            type->getImmediateOperand(2) == (  depth ? 1u : 0u) &&
							 | 
						||
| 
								 | 
							
								            type->getImmediateOperand(3) == (arrayed ? 1u : 0u) &&
							 | 
						||
| 
								 | 
							
								            type->getImmediateOperand(4) == (     ms ? 1u : 0u) &&
							 | 
						||
| 
								 | 
							
								            type->getImmediateOperand(5) == sampled &&
							 | 
						||
| 
								 | 
							
								            type->getImmediateOperand(6) == (unsigned int)format)
							 | 
						||
| 
								 | 
							
								            return type->getResultId();
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // not found, make it
							 | 
						||
| 
								 | 
							
								    type = new Instruction(getUniqueId(), NoType, OpTypeImage);
							 | 
						||
| 
								 | 
							
								    type->addIdOperand(sampledType);
							 | 
						||
| 
								 | 
							
								    type->addImmediateOperand(   dim);
							 | 
						||
| 
								 | 
							
								    type->addImmediateOperand(  depth ? 1 : 0);
							 | 
						||
| 
								 | 
							
								    type->addImmediateOperand(arrayed ? 1 : 0);
							 | 
						||
| 
								 | 
							
								    type->addImmediateOperand(     ms ? 1 : 0);
							 | 
						||
| 
								 | 
							
								    type->addImmediateOperand(sampled);
							 | 
						||
| 
								 | 
							
								    type->addImmediateOperand((unsigned int)format);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    groupedTypes[OpTypeImage].push_back(type);
							 | 
						||
| 
								 | 
							
								    constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
							 | 
						||
| 
								 | 
							
								    module.mapInstruction(type);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#ifndef GLSLANG_WEB
							 | 
						||
| 
								 | 
							
								    // deal with capabilities
							 | 
						||
| 
								 | 
							
								    switch (dim) {
							 | 
						||
| 
								 | 
							
								    case DimBuffer:
							 | 
						||
| 
								 | 
							
								        if (sampled == 1)
							 | 
						||
| 
								 | 
							
								            addCapability(CapabilitySampledBuffer);
							 | 
						||
| 
								 | 
							
								        else
							 | 
						||
| 
								 | 
							
								            addCapability(CapabilityImageBuffer);
							 | 
						||
| 
								 | 
							
								        break;
							 | 
						||
| 
								 | 
							
								    case Dim1D:
							 | 
						||
| 
								 | 
							
								        if (sampled == 1)
							 | 
						||
| 
								 | 
							
								            addCapability(CapabilitySampled1D);
							 | 
						||
| 
								 | 
							
								        else
							 | 
						||
| 
								 | 
							
								            addCapability(CapabilityImage1D);
							 | 
						||
| 
								 | 
							
								        break;
							 | 
						||
| 
								 | 
							
								    case DimCube:
							 | 
						||
| 
								 | 
							
								        if (arrayed) {
							 | 
						||
| 
								 | 
							
								            if (sampled == 1)
							 | 
						||
| 
								 | 
							
								                addCapability(CapabilitySampledCubeArray);
							 | 
						||
| 
								 | 
							
								            else
							 | 
						||
| 
								 | 
							
								                addCapability(CapabilityImageCubeArray);
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        break;
							 | 
						||
| 
								 | 
							
								    case DimRect:
							 | 
						||
| 
								 | 
							
								        if (sampled == 1)
							 | 
						||
| 
								 | 
							
								            addCapability(CapabilitySampledRect);
							 | 
						||
| 
								 | 
							
								        else
							 | 
						||
| 
								 | 
							
								            addCapability(CapabilityImageRect);
							 | 
						||
| 
								 | 
							
								        break;
							 | 
						||
| 
								 | 
							
								    case DimSubpassData:
							 | 
						||
| 
								 | 
							
								        addCapability(CapabilityInputAttachment);
							 | 
						||
| 
								 | 
							
								        break;
							 | 
						||
| 
								 | 
							
								    default:
							 | 
						||
| 
								 | 
							
								        break;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if (ms) {
							 | 
						||
| 
								 | 
							
								        if (sampled == 2) {
							 | 
						||
| 
								 | 
							
								            // Images used with subpass data are not storage
							 | 
						||
| 
								 | 
							
								            // images, so don't require the capability for them.
							 | 
						||
| 
								 | 
							
								            if (dim != Dim::DimSubpassData)
							 | 
						||
| 
								 | 
							
								                addCapability(CapabilityStorageImageMultisample);
							 | 
						||
| 
								 | 
							
								            if (arrayed)
							 | 
						||
| 
								 | 
							
								                addCapability(CapabilityImageMSArray);
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								#endif
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    return type->getResultId();
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Id Builder::makeSampledImageType(Id imageType)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    // try to find it
							 | 
						||
| 
								 | 
							
								    Instruction* type;
							 | 
						||
| 
								 | 
							
								    for (int t = 0; t < (int)groupedTypes[OpTypeSampledImage].size(); ++t) {
							 | 
						||
| 
								 | 
							
								        type = groupedTypes[OpTypeSampledImage][t];
							 | 
						||
| 
								 | 
							
								        if (type->getIdOperand(0) == imageType)
							 | 
						||
| 
								 | 
							
								            return type->getResultId();
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // not found, make it
							 | 
						||
| 
								 | 
							
								    type = new Instruction(getUniqueId(), NoType, OpTypeSampledImage);
							 | 
						||
| 
								 | 
							
								    type->addIdOperand(imageType);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    groupedTypes[OpTypeSampledImage].push_back(type);
							 | 
						||
| 
								 | 
							
								    constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
							 | 
						||
| 
								 | 
							
								    module.mapInstruction(type);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    return type->getResultId();
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#ifndef GLSLANG_WEB
							 | 
						||
| 
								 | 
							
								Id Builder::makeAccelerationStructureType()
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    Instruction *type;
							 | 
						||
| 
								 | 
							
								    if (groupedTypes[OpTypeAccelerationStructureKHR].size() == 0) {
							 | 
						||
| 
								 | 
							
								        type = new Instruction(getUniqueId(), NoType, OpTypeAccelerationStructureKHR);
							 | 
						||
| 
								 | 
							
								        groupedTypes[OpTypeAccelerationStructureKHR].push_back(type);
							 | 
						||
| 
								 | 
							
								        constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
							 | 
						||
| 
								 | 
							
								        module.mapInstruction(type);
							 | 
						||
| 
								 | 
							
								    } else {
							 | 
						||
| 
								 | 
							
								        type = groupedTypes[OpTypeAccelerationStructureKHR].back();
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    return type->getResultId();
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Id Builder::makeRayQueryType()
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    Instruction *type;
							 | 
						||
| 
								 | 
							
								    if (groupedTypes[OpTypeRayQueryProvisionalKHR].size() == 0) {
							 | 
						||
| 
								 | 
							
								        type = new Instruction(getUniqueId(), NoType, OpTypeRayQueryProvisionalKHR);
							 | 
						||
| 
								 | 
							
								        groupedTypes[OpTypeRayQueryProvisionalKHR].push_back(type);
							 | 
						||
| 
								 | 
							
								        constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
							 | 
						||
| 
								 | 
							
								        module.mapInstruction(type);
							 | 
						||
| 
								 | 
							
								    } else {
							 | 
						||
| 
								 | 
							
								        type = groupedTypes[OpTypeRayQueryProvisionalKHR].back();
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    return type->getResultId();
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								#endif
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Id Builder::getDerefTypeId(Id resultId) const
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    Id typeId = getTypeId(resultId);
							 | 
						||
| 
								 | 
							
								    assert(isPointerType(typeId));
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    return module.getInstruction(typeId)->getIdOperand(1);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Op Builder::getMostBasicTypeClass(Id typeId) const
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    Instruction* instr = module.getInstruction(typeId);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    Op typeClass = instr->getOpCode();
							 | 
						||
| 
								 | 
							
								    switch (typeClass)
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								    case OpTypeVector:
							 | 
						||
| 
								 | 
							
								    case OpTypeMatrix:
							 | 
						||
| 
								 | 
							
								    case OpTypeArray:
							 | 
						||
| 
								 | 
							
								    case OpTypeRuntimeArray:
							 | 
						||
| 
								 | 
							
								        return getMostBasicTypeClass(instr->getIdOperand(0));
							 | 
						||
| 
								 | 
							
								    case OpTypePointer:
							 | 
						||
| 
								 | 
							
								        return getMostBasicTypeClass(instr->getIdOperand(1));
							 | 
						||
| 
								 | 
							
								    default:
							 | 
						||
| 
								 | 
							
								        return typeClass;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								int Builder::getNumTypeConstituents(Id typeId) const
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    Instruction* instr = module.getInstruction(typeId);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    switch (instr->getOpCode())
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								    case OpTypeBool:
							 | 
						||
| 
								 | 
							
								    case OpTypeInt:
							 | 
						||
| 
								 | 
							
								    case OpTypeFloat:
							 | 
						||
| 
								 | 
							
								    case OpTypePointer:
							 | 
						||
| 
								 | 
							
								        return 1;
							 | 
						||
| 
								 | 
							
								    case OpTypeVector:
							 | 
						||
| 
								 | 
							
								    case OpTypeMatrix:
							 | 
						||
| 
								 | 
							
								        return instr->getImmediateOperand(1);
							 | 
						||
| 
								 | 
							
								    case OpTypeArray:
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								        Id lengthId = instr->getIdOperand(1);
							 | 
						||
| 
								 | 
							
								        return module.getInstruction(lengthId)->getImmediateOperand(0);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    case OpTypeStruct:
							 | 
						||
| 
								 | 
							
								        return instr->getNumOperands();
							 | 
						||
| 
								 | 
							
								    case OpTypeCooperativeMatrixNV:
							 | 
						||
| 
								 | 
							
								        // has only one constituent when used with OpCompositeConstruct.
							 | 
						||
| 
								 | 
							
								        return 1;
							 | 
						||
| 
								 | 
							
								    default:
							 | 
						||
| 
								 | 
							
								        assert(0);
							 | 
						||
| 
								 | 
							
								        return 1;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// Return the lowest-level type of scalar that an homogeneous composite is made out of.
							 | 
						||
| 
								 | 
							
								// Typically, this is just to find out if something is made out of ints or floats.
							 | 
						||
| 
								 | 
							
								// However, it includes returning a structure, if say, it is an array of structure.
							 | 
						||
| 
								 | 
							
								Id Builder::getScalarTypeId(Id typeId) const
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    Instruction* instr = module.getInstruction(typeId);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    Op typeClass = instr->getOpCode();
							 | 
						||
| 
								 | 
							
								    switch (typeClass)
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								    case OpTypeVoid:
							 | 
						||
| 
								 | 
							
								    case OpTypeBool:
							 | 
						||
| 
								 | 
							
								    case OpTypeInt:
							 | 
						||
| 
								 | 
							
								    case OpTypeFloat:
							 | 
						||
| 
								 | 
							
								    case OpTypeStruct:
							 | 
						||
| 
								 | 
							
								        return instr->getResultId();
							 | 
						||
| 
								 | 
							
								    case OpTypeVector:
							 | 
						||
| 
								 | 
							
								    case OpTypeMatrix:
							 | 
						||
| 
								 | 
							
								    case OpTypeArray:
							 | 
						||
| 
								 | 
							
								    case OpTypeRuntimeArray:
							 | 
						||
| 
								 | 
							
								    case OpTypePointer:
							 | 
						||
| 
								 | 
							
								        return getScalarTypeId(getContainedTypeId(typeId));
							 | 
						||
| 
								 | 
							
								    default:
							 | 
						||
| 
								 | 
							
								        assert(0);
							 | 
						||
| 
								 | 
							
								        return NoResult;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// Return the type of 'member' of a composite.
							 | 
						||
| 
								 | 
							
								Id Builder::getContainedTypeId(Id typeId, int member) const
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    Instruction* instr = module.getInstruction(typeId);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    Op typeClass = instr->getOpCode();
							 | 
						||
| 
								 | 
							
								    switch (typeClass)
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								    case OpTypeVector:
							 | 
						||
| 
								 | 
							
								    case OpTypeMatrix:
							 | 
						||
| 
								 | 
							
								    case OpTypeArray:
							 | 
						||
| 
								 | 
							
								    case OpTypeRuntimeArray:
							 | 
						||
| 
								 | 
							
								    case OpTypeCooperativeMatrixNV:
							 | 
						||
| 
								 | 
							
								        return instr->getIdOperand(0);
							 | 
						||
| 
								 | 
							
								    case OpTypePointer:
							 | 
						||
| 
								 | 
							
								        return instr->getIdOperand(1);
							 | 
						||
| 
								 | 
							
								    case OpTypeStruct:
							 | 
						||
| 
								 | 
							
								        return instr->getIdOperand(member);
							 | 
						||
| 
								 | 
							
								    default:
							 | 
						||
| 
								 | 
							
								        assert(0);
							 | 
						||
| 
								 | 
							
								        return NoResult;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// Return the immediately contained type of a given composite type.
							 | 
						||
| 
								 | 
							
								Id Builder::getContainedTypeId(Id typeId) const
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    return getContainedTypeId(typeId, 0);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// Returns true if 'typeId' is or contains a scalar type declared with 'typeOp'
							 | 
						||
| 
								 | 
							
								// of width 'width'. The 'width' is only consumed for int and float types.
							 | 
						||
| 
								 | 
							
								// Returns false otherwise.
							 | 
						||
| 
								 | 
							
								bool Builder::containsType(Id typeId, spv::Op typeOp, unsigned int width) const
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    const Instruction& instr = *module.getInstruction(typeId);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    Op typeClass = instr.getOpCode();
							 | 
						||
| 
								 | 
							
								    switch (typeClass)
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								    case OpTypeInt:
							 | 
						||
| 
								 | 
							
								    case OpTypeFloat:
							 | 
						||
| 
								 | 
							
								        return typeClass == typeOp && instr.getImmediateOperand(0) == width;
							 | 
						||
| 
								 | 
							
								    case OpTypeStruct:
							 | 
						||
| 
								 | 
							
								        for (int m = 0; m < instr.getNumOperands(); ++m) {
							 | 
						||
| 
								 | 
							
								            if (containsType(instr.getIdOperand(m), typeOp, width))
							 | 
						||
| 
								 | 
							
								                return true;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        return false;
							 | 
						||
| 
								 | 
							
								    case OpTypePointer:
							 | 
						||
| 
								 | 
							
								        return false;
							 | 
						||
| 
								 | 
							
								    case OpTypeVector:
							 | 
						||
| 
								 | 
							
								    case OpTypeMatrix:
							 | 
						||
| 
								 | 
							
								    case OpTypeArray:
							 | 
						||
| 
								 | 
							
								    case OpTypeRuntimeArray:
							 | 
						||
| 
								 | 
							
								        return containsType(getContainedTypeId(typeId), typeOp, width);
							 | 
						||
| 
								 | 
							
								    default:
							 | 
						||
| 
								 | 
							
								        return typeClass == typeOp;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// return true if the type is a pointer to PhysicalStorageBufferEXT or an
							 | 
						||
| 
								 | 
							
								// array of such pointers. These require restrict/aliased decorations.
							 | 
						||
| 
								 | 
							
								bool Builder::containsPhysicalStorageBufferOrArray(Id typeId) const
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    const Instruction& instr = *module.getInstruction(typeId);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    Op typeClass = instr.getOpCode();
							 | 
						||
| 
								 | 
							
								    switch (typeClass)
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								    case OpTypePointer:
							 | 
						||
| 
								 | 
							
								        return getTypeStorageClass(typeId) == StorageClassPhysicalStorageBufferEXT;
							 | 
						||
| 
								 | 
							
								    case OpTypeArray:
							 | 
						||
| 
								 | 
							
								        return containsPhysicalStorageBufferOrArray(getContainedTypeId(typeId));
							 | 
						||
| 
								 | 
							
								    default:
							 | 
						||
| 
								 | 
							
								        return false;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// See if a scalar constant of this type has already been created, so it
							 | 
						||
| 
								 | 
							
								// can be reused rather than duplicated.  (Required by the specification).
							 | 
						||
| 
								 | 
							
								Id Builder::findScalarConstant(Op typeClass, Op opcode, Id typeId, unsigned value)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    Instruction* constant;
							 | 
						||
| 
								 | 
							
								    for (int i = 0; i < (int)groupedConstants[typeClass].size(); ++i) {
							 | 
						||
| 
								 | 
							
								        constant = groupedConstants[typeClass][i];
							 | 
						||
| 
								 | 
							
								        if (constant->getOpCode() == opcode &&
							 | 
						||
| 
								 | 
							
								            constant->getTypeId() == typeId &&
							 | 
						||
| 
								 | 
							
								            constant->getImmediateOperand(0) == value)
							 | 
						||
| 
								 | 
							
								            return constant->getResultId();
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    return 0;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// Version of findScalarConstant (see above) for scalars that take two operands (e.g. a 'double' or 'int64').
							 | 
						||
| 
								 | 
							
								Id Builder::findScalarConstant(Op typeClass, Op opcode, Id typeId, unsigned v1, unsigned v2)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    Instruction* constant;
							 | 
						||
| 
								 | 
							
								    for (int i = 0; i < (int)groupedConstants[typeClass].size(); ++i) {
							 | 
						||
| 
								 | 
							
								        constant = groupedConstants[typeClass][i];
							 | 
						||
| 
								 | 
							
								        if (constant->getOpCode() == opcode &&
							 | 
						||
| 
								 | 
							
								            constant->getTypeId() == typeId &&
							 | 
						||
| 
								 | 
							
								            constant->getImmediateOperand(0) == v1 &&
							 | 
						||
| 
								 | 
							
								            constant->getImmediateOperand(1) == v2)
							 | 
						||
| 
								 | 
							
								            return constant->getResultId();
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    return 0;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// Return true if consuming 'opcode' means consuming a constant.
							 | 
						||
| 
								 | 
							
								// "constant" here means after final transform to executable code,
							 | 
						||
| 
								 | 
							
								// the value consumed will be a constant, so includes specialization.
							 | 
						||
| 
								 | 
							
								bool Builder::isConstantOpCode(Op opcode) const
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    switch (opcode) {
							 | 
						||
| 
								 | 
							
								    case OpUndef:
							 | 
						||
| 
								 | 
							
								    case OpConstantTrue:
							 | 
						||
| 
								 | 
							
								    case OpConstantFalse:
							 | 
						||
| 
								 | 
							
								    case OpConstant:
							 | 
						||
| 
								 | 
							
								    case OpConstantComposite:
							 | 
						||
| 
								 | 
							
								    case OpConstantSampler:
							 | 
						||
| 
								 | 
							
								    case OpConstantNull:
							 | 
						||
| 
								 | 
							
								    case OpSpecConstantTrue:
							 | 
						||
| 
								 | 
							
								    case OpSpecConstantFalse:
							 | 
						||
| 
								 | 
							
								    case OpSpecConstant:
							 | 
						||
| 
								 | 
							
								    case OpSpecConstantComposite:
							 | 
						||
| 
								 | 
							
								    case OpSpecConstantOp:
							 | 
						||
| 
								 | 
							
								        return true;
							 | 
						||
| 
								 | 
							
								    default:
							 | 
						||
| 
								 | 
							
								        return false;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// Return true if consuming 'opcode' means consuming a specialization constant.
							 | 
						||
| 
								 | 
							
								bool Builder::isSpecConstantOpCode(Op opcode) const
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    switch (opcode) {
							 | 
						||
| 
								 | 
							
								    case OpSpecConstantTrue:
							 | 
						||
| 
								 | 
							
								    case OpSpecConstantFalse:
							 | 
						||
| 
								 | 
							
								    case OpSpecConstant:
							 | 
						||
| 
								 | 
							
								    case OpSpecConstantComposite:
							 | 
						||
| 
								 | 
							
								    case OpSpecConstantOp:
							 | 
						||
| 
								 | 
							
								        return true;
							 | 
						||
| 
								 | 
							
								    default:
							 | 
						||
| 
								 | 
							
								        return false;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Id Builder::makeBoolConstant(bool b, bool specConstant)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    Id typeId = makeBoolType();
							 | 
						||
| 
								 | 
							
								    Instruction* constant;
							 | 
						||
| 
								 | 
							
								    Op opcode = specConstant ? (b ? OpSpecConstantTrue : OpSpecConstantFalse) : (b ? OpConstantTrue : OpConstantFalse);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // See if we already made it. Applies only to regular constants, because specialization constants
							 | 
						||
| 
								 | 
							
								    // must remain distinct for the purpose of applying a SpecId decoration.
							 | 
						||
| 
								 | 
							
								    if (! specConstant) {
							 | 
						||
| 
								 | 
							
								        Id existing = 0;
							 | 
						||
| 
								 | 
							
								        for (int i = 0; i < (int)groupedConstants[OpTypeBool].size(); ++i) {
							 | 
						||
| 
								 | 
							
								            constant = groupedConstants[OpTypeBool][i];
							 | 
						||
| 
								 | 
							
								            if (constant->getTypeId() == typeId && constant->getOpCode() == opcode)
							 | 
						||
| 
								 | 
							
								                existing = constant->getResultId();
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        if (existing)
							 | 
						||
| 
								 | 
							
								            return existing;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // Make it
							 | 
						||
| 
								 | 
							
								    Instruction* c = new Instruction(getUniqueId(), typeId, opcode);
							 | 
						||
| 
								 | 
							
								    constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(c));
							 | 
						||
| 
								 | 
							
								    groupedConstants[OpTypeBool].push_back(c);
							 | 
						||
| 
								 | 
							
								    module.mapInstruction(c);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    return c->getResultId();
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Id Builder::makeIntConstant(Id typeId, unsigned value, bool specConstant)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    Op opcode = specConstant ? OpSpecConstant : OpConstant;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // See if we already made it. Applies only to regular constants, because specialization constants
							 | 
						||
| 
								 | 
							
								    // must remain distinct for the purpose of applying a SpecId decoration.
							 | 
						||
| 
								 | 
							
								    if (! specConstant) {
							 | 
						||
| 
								 | 
							
								        Id existing = findScalarConstant(OpTypeInt, opcode, typeId, value);
							 | 
						||
| 
								 | 
							
								        if (existing)
							 | 
						||
| 
								 | 
							
								            return existing;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    Instruction* c = new Instruction(getUniqueId(), typeId, opcode);
							 | 
						||
| 
								 | 
							
								    c->addImmediateOperand(value);
							 | 
						||
| 
								 | 
							
								    constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(c));
							 | 
						||
| 
								 | 
							
								    groupedConstants[OpTypeInt].push_back(c);
							 | 
						||
| 
								 | 
							
								    module.mapInstruction(c);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    return c->getResultId();
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Id Builder::makeInt64Constant(Id typeId, unsigned long long value, bool specConstant)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    Op opcode = specConstant ? OpSpecConstant : OpConstant;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    unsigned op1 = value & 0xFFFFFFFF;
							 | 
						||
| 
								 | 
							
								    unsigned op2 = value >> 32;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // See if we already made it. Applies only to regular constants, because specialization constants
							 | 
						||
| 
								 | 
							
								    // must remain distinct for the purpose of applying a SpecId decoration.
							 | 
						||
| 
								 | 
							
								    if (! specConstant) {
							 | 
						||
| 
								 | 
							
								        Id existing = findScalarConstant(OpTypeInt, opcode, typeId, op1, op2);
							 | 
						||
| 
								 | 
							
								        if (existing)
							 | 
						||
| 
								 | 
							
								            return existing;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    Instruction* c = new Instruction(getUniqueId(), typeId, opcode);
							 | 
						||
| 
								 | 
							
								    c->addImmediateOperand(op1);
							 | 
						||
| 
								 | 
							
								    c->addImmediateOperand(op2);
							 | 
						||
| 
								 | 
							
								    constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(c));
							 | 
						||
| 
								 | 
							
								    groupedConstants[OpTypeInt].push_back(c);
							 | 
						||
| 
								 | 
							
								    module.mapInstruction(c);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    return c->getResultId();
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Id Builder::makeFloatConstant(float f, bool specConstant)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    Op opcode = specConstant ? OpSpecConstant : OpConstant;
							 | 
						||
| 
								 | 
							
								    Id typeId = makeFloatType(32);
							 | 
						||
| 
								 | 
							
								    union { float fl; unsigned int ui; } u;
							 | 
						||
| 
								 | 
							
								    u.fl = f;
							 | 
						||
| 
								 | 
							
								    unsigned value = u.ui;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // See if we already made it. Applies only to regular constants, because specialization constants
							 | 
						||
| 
								 | 
							
								    // must remain distinct for the purpose of applying a SpecId decoration.
							 | 
						||
| 
								 | 
							
								    if (! specConstant) {
							 | 
						||
| 
								 | 
							
								        Id existing = findScalarConstant(OpTypeFloat, opcode, typeId, value);
							 | 
						||
| 
								 | 
							
								        if (existing)
							 | 
						||
| 
								 | 
							
								            return existing;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    Instruction* c = new Instruction(getUniqueId(), typeId, opcode);
							 | 
						||
| 
								 | 
							
								    c->addImmediateOperand(value);
							 | 
						||
| 
								 | 
							
								    constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(c));
							 | 
						||
| 
								 | 
							
								    groupedConstants[OpTypeFloat].push_back(c);
							 | 
						||
| 
								 | 
							
								    module.mapInstruction(c);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    return c->getResultId();
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Id Builder::makeDoubleConstant(double d, bool specConstant)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								#ifdef GLSLANG_WEB
							 | 
						||
| 
								 | 
							
								    assert(0);
							 | 
						||
| 
								 | 
							
								    return NoResult;
							 | 
						||
| 
								 | 
							
								#else
							 | 
						||
| 
								 | 
							
								    Op opcode = specConstant ? OpSpecConstant : OpConstant;
							 | 
						||
| 
								 | 
							
								    Id typeId = makeFloatType(64);
							 | 
						||
| 
								 | 
							
								    union { double db; unsigned long long ull; } u;
							 | 
						||
| 
								 | 
							
								    u.db = d;
							 | 
						||
| 
								 | 
							
								    unsigned long long value = u.ull;
							 | 
						||
| 
								 | 
							
								    unsigned op1 = value & 0xFFFFFFFF;
							 | 
						||
| 
								 | 
							
								    unsigned op2 = value >> 32;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // See if we already made it. Applies only to regular constants, because specialization constants
							 | 
						||
| 
								 | 
							
								    // must remain distinct for the purpose of applying a SpecId decoration.
							 | 
						||
| 
								 | 
							
								    if (! specConstant) {
							 | 
						||
| 
								 | 
							
								        Id existing = findScalarConstant(OpTypeFloat, opcode, typeId, op1, op2);
							 | 
						||
| 
								 | 
							
								        if (existing)
							 | 
						||
| 
								 | 
							
								            return existing;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    Instruction* c = new Instruction(getUniqueId(), typeId, opcode);
							 | 
						||
| 
								 | 
							
								    c->addImmediateOperand(op1);
							 | 
						||
| 
								 | 
							
								    c->addImmediateOperand(op2);
							 | 
						||
| 
								 | 
							
								    constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(c));
							 | 
						||
| 
								 | 
							
								    groupedConstants[OpTypeFloat].push_back(c);
							 | 
						||
| 
								 | 
							
								    module.mapInstruction(c);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    return c->getResultId();
							 | 
						||
| 
								 | 
							
								#endif
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Id Builder::makeFloat16Constant(float f16, bool specConstant)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								#ifdef GLSLANG_WEB
							 | 
						||
| 
								 | 
							
								    assert(0);
							 | 
						||
| 
								 | 
							
								    return NoResult;
							 | 
						||
| 
								 | 
							
								#else
							 | 
						||
| 
								 | 
							
								    Op opcode = specConstant ? OpSpecConstant : OpConstant;
							 | 
						||
| 
								 | 
							
								    Id typeId = makeFloatType(16);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    spvutils::HexFloat<spvutils::FloatProxy<float>> fVal(f16);
							 | 
						||
| 
								 | 
							
								    spvutils::HexFloat<spvutils::FloatProxy<spvutils::Float16>> f16Val(0);
							 | 
						||
| 
								 | 
							
								    fVal.castTo(f16Val, spvutils::kRoundToZero);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    unsigned value = f16Val.value().getAsFloat().get_value();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // See if we already made it. Applies only to regular constants, because specialization constants
							 | 
						||
| 
								 | 
							
								    // must remain distinct for the purpose of applying a SpecId decoration.
							 | 
						||
| 
								 | 
							
								    if (!specConstant) {
							 | 
						||
| 
								 | 
							
								        Id existing = findScalarConstant(OpTypeFloat, opcode, typeId, value);
							 | 
						||
| 
								 | 
							
								        if (existing)
							 | 
						||
| 
								 | 
							
								            return existing;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    Instruction* c = new Instruction(getUniqueId(), typeId, opcode);
							 | 
						||
| 
								 | 
							
								    c->addImmediateOperand(value);
							 | 
						||
| 
								 | 
							
								    constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(c));
							 | 
						||
| 
								 | 
							
								    groupedConstants[OpTypeFloat].push_back(c);
							 | 
						||
| 
								 | 
							
								    module.mapInstruction(c);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    return c->getResultId();
							 | 
						||
| 
								 | 
							
								#endif
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Id Builder::makeFpConstant(Id type, double d, bool specConstant)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								#ifdef GLSLANG_WEB
							 | 
						||
| 
								 | 
							
								    const int width = 32;
							 | 
						||
| 
								 | 
							
								    assert(width == getScalarTypeWidth(type));
							 | 
						||
| 
								 | 
							
								#else
							 | 
						||
| 
								 | 
							
								    const int width = getScalarTypeWidth(type);
							 | 
						||
| 
								 | 
							
								#endif
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    assert(isFloatType(type));
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    switch (width) {
							 | 
						||
| 
								 | 
							
								    case 16:
							 | 
						||
| 
								 | 
							
								            return makeFloat16Constant((float)d, specConstant);
							 | 
						||
| 
								 | 
							
								    case 32:
							 | 
						||
| 
								 | 
							
								            return makeFloatConstant((float)d, specConstant);
							 | 
						||
| 
								 | 
							
								    case 64:
							 | 
						||
| 
								 | 
							
								            return makeDoubleConstant(d, specConstant);
							 | 
						||
| 
								 | 
							
								    default:
							 | 
						||
| 
								 | 
							
								            break;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    assert(false);
							 | 
						||
| 
								 | 
							
								    return NoResult;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Id Builder::findCompositeConstant(Op typeClass, Id typeId, const std::vector<Id>& comps)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    Instruction* constant = 0;
							 | 
						||
| 
								 | 
							
								    bool found = false;
							 | 
						||
| 
								 | 
							
								    for (int i = 0; i < (int)groupedConstants[typeClass].size(); ++i) {
							 | 
						||
| 
								 | 
							
								        constant = groupedConstants[typeClass][i];
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        if (constant->getTypeId() != typeId)
							 | 
						||
| 
								 | 
							
								            continue;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        // same contents?
							 | 
						||
| 
								 | 
							
								        bool mismatch = false;
							 | 
						||
| 
								 | 
							
								        for (int op = 0; op < constant->getNumOperands(); ++op) {
							 | 
						||
| 
								 | 
							
								            if (constant->getIdOperand(op) != comps[op]) {
							 | 
						||
| 
								 | 
							
								                mismatch = true;
							 | 
						||
| 
								 | 
							
								                break;
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        if (! mismatch) {
							 | 
						||
| 
								 | 
							
								            found = true;
							 | 
						||
| 
								 | 
							
								            break;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    return found ? constant->getResultId() : NoResult;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Id Builder::findStructConstant(Id typeId, const std::vector<Id>& comps)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    Instruction* constant = 0;
							 | 
						||
| 
								 | 
							
								    bool found = false;
							 | 
						||
| 
								 | 
							
								    for (int i = 0; i < (int)groupedStructConstants[typeId].size(); ++i) {
							 | 
						||
| 
								 | 
							
								        constant = groupedStructConstants[typeId][i];
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        // same contents?
							 | 
						||
| 
								 | 
							
								        bool mismatch = false;
							 | 
						||
| 
								 | 
							
								        for (int op = 0; op < constant->getNumOperands(); ++op) {
							 | 
						||
| 
								 | 
							
								            if (constant->getIdOperand(op) != comps[op]) {
							 | 
						||
| 
								 | 
							
								                mismatch = true;
							 | 
						||
| 
								 | 
							
								                break;
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        if (! mismatch) {
							 | 
						||
| 
								 | 
							
								            found = true;
							 | 
						||
| 
								 | 
							
								            break;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    return found ? constant->getResultId() : NoResult;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// Comments in header
							 | 
						||
| 
								 | 
							
								Id Builder::makeCompositeConstant(Id typeId, const std::vector<Id>& members, bool specConstant)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    Op opcode = specConstant ? OpSpecConstantComposite : OpConstantComposite;
							 | 
						||
| 
								 | 
							
								    assert(typeId);
							 | 
						||
| 
								 | 
							
								    Op typeClass = getTypeClass(typeId);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    switch (typeClass) {
							 | 
						||
| 
								 | 
							
								    case OpTypeVector:
							 | 
						||
| 
								 | 
							
								    case OpTypeArray:
							 | 
						||
| 
								 | 
							
								    case OpTypeMatrix:
							 | 
						||
| 
								 | 
							
								    case OpTypeCooperativeMatrixNV:
							 | 
						||
| 
								 | 
							
								        if (! specConstant) {
							 | 
						||
| 
								 | 
							
								            Id existing = findCompositeConstant(typeClass, typeId, members);
							 | 
						||
| 
								 | 
							
								            if (existing)
							 | 
						||
| 
								 | 
							
								                return existing;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        break;
							 | 
						||
| 
								 | 
							
								    case OpTypeStruct:
							 | 
						||
| 
								 | 
							
								        if (! specConstant) {
							 | 
						||
| 
								 | 
							
								            Id existing = findStructConstant(typeId, members);
							 | 
						||
| 
								 | 
							
								            if (existing)
							 | 
						||
| 
								 | 
							
								                return existing;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        break;
							 | 
						||
| 
								 | 
							
								    default:
							 | 
						||
| 
								 | 
							
								        assert(0);
							 | 
						||
| 
								 | 
							
								        return makeFloatConstant(0.0);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    Instruction* c = new Instruction(getUniqueId(), typeId, opcode);
							 | 
						||
| 
								 | 
							
								    for (int op = 0; op < (int)members.size(); ++op)
							 | 
						||
| 
								 | 
							
								        c->addIdOperand(members[op]);
							 | 
						||
| 
								 | 
							
								    constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(c));
							 | 
						||
| 
								 | 
							
								    if (typeClass == OpTypeStruct)
							 | 
						||
| 
								 | 
							
								        groupedStructConstants[typeId].push_back(c);
							 | 
						||
| 
								 | 
							
								    else
							 | 
						||
| 
								 | 
							
								        groupedConstants[typeClass].push_back(c);
							 | 
						||
| 
								 | 
							
								    module.mapInstruction(c);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    return c->getResultId();
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Instruction* Builder::addEntryPoint(ExecutionModel model, Function* function, const char* name)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    Instruction* entryPoint = new Instruction(OpEntryPoint);
							 | 
						||
| 
								 | 
							
								    entryPoint->addImmediateOperand(model);
							 | 
						||
| 
								 | 
							
								    entryPoint->addIdOperand(function->getId());
							 | 
						||
| 
								 | 
							
								    entryPoint->addStringOperand(name);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    entryPoints.push_back(std::unique_ptr<Instruction>(entryPoint));
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    return entryPoint;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// Currently relying on the fact that all 'value' of interest are small non-negative values.
							 | 
						||
| 
								 | 
							
								void Builder::addExecutionMode(Function* entryPoint, ExecutionMode mode, int value1, int value2, int value3)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    Instruction* instr = new Instruction(OpExecutionMode);
							 | 
						||
| 
								 | 
							
								    instr->addIdOperand(entryPoint->getId());
							 | 
						||
| 
								 | 
							
								    instr->addImmediateOperand(mode);
							 | 
						||
| 
								 | 
							
								    if (value1 >= 0)
							 | 
						||
| 
								 | 
							
								        instr->addImmediateOperand(value1);
							 | 
						||
| 
								 | 
							
								    if (value2 >= 0)
							 | 
						||
| 
								 | 
							
								        instr->addImmediateOperand(value2);
							 | 
						||
| 
								 | 
							
								    if (value3 >= 0)
							 | 
						||
| 
								 | 
							
								        instr->addImmediateOperand(value3);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    executionModes.push_back(std::unique_ptr<Instruction>(instr));
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								void Builder::addName(Id id, const char* string)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    Instruction* name = new Instruction(OpName);
							 | 
						||
| 
								 | 
							
								    name->addIdOperand(id);
							 | 
						||
| 
								 | 
							
								    name->addStringOperand(string);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    names.push_back(std::unique_ptr<Instruction>(name));
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								void Builder::addMemberName(Id id, int memberNumber, const char* string)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    Instruction* name = new Instruction(OpMemberName);
							 | 
						||
| 
								 | 
							
								    name->addIdOperand(id);
							 | 
						||
| 
								 | 
							
								    name->addImmediateOperand(memberNumber);
							 | 
						||
| 
								 | 
							
								    name->addStringOperand(string);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    names.push_back(std::unique_ptr<Instruction>(name));
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								void Builder::addDecoration(Id id, Decoration decoration, int num)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    if (decoration == spv::DecorationMax)
							 | 
						||
| 
								 | 
							
								        return;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    Instruction* dec = new Instruction(OpDecorate);
							 | 
						||
| 
								 | 
							
								    dec->addIdOperand(id);
							 | 
						||
| 
								 | 
							
								    dec->addImmediateOperand(decoration);
							 | 
						||
| 
								 | 
							
								    if (num >= 0)
							 | 
						||
| 
								 | 
							
								        dec->addImmediateOperand(num);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    decorations.push_back(std::unique_ptr<Instruction>(dec));
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								void Builder::addDecoration(Id id, Decoration decoration, const char* s)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    if (decoration == spv::DecorationMax)
							 | 
						||
| 
								 | 
							
								        return;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    Instruction* dec = new Instruction(OpDecorateStringGOOGLE);
							 | 
						||
| 
								 | 
							
								    dec->addIdOperand(id);
							 | 
						||
| 
								 | 
							
								    dec->addImmediateOperand(decoration);
							 | 
						||
| 
								 | 
							
								    dec->addStringOperand(s);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    decorations.push_back(std::unique_ptr<Instruction>(dec));
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								void Builder::addDecorationId(Id id, Decoration decoration, Id idDecoration)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    if (decoration == spv::DecorationMax)
							 | 
						||
| 
								 | 
							
								        return;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    Instruction* dec = new Instruction(OpDecorateId);
							 | 
						||
| 
								 | 
							
								    dec->addIdOperand(id);
							 | 
						||
| 
								 | 
							
								    dec->addImmediateOperand(decoration);
							 | 
						||
| 
								 | 
							
								    dec->addIdOperand(idDecoration);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    decorations.push_back(std::unique_ptr<Instruction>(dec));
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								void Builder::addMemberDecoration(Id id, unsigned int member, Decoration decoration, int num)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    if (decoration == spv::DecorationMax)
							 | 
						||
| 
								 | 
							
								        return;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    Instruction* dec = new Instruction(OpMemberDecorate);
							 | 
						||
| 
								 | 
							
								    dec->addIdOperand(id);
							 | 
						||
| 
								 | 
							
								    dec->addImmediateOperand(member);
							 | 
						||
| 
								 | 
							
								    dec->addImmediateOperand(decoration);
							 | 
						||
| 
								 | 
							
								    if (num >= 0)
							 | 
						||
| 
								 | 
							
								        dec->addImmediateOperand(num);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    decorations.push_back(std::unique_ptr<Instruction>(dec));
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								void Builder::addMemberDecoration(Id id, unsigned int member, Decoration decoration, const char *s)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    if (decoration == spv::DecorationMax)
							 | 
						||
| 
								 | 
							
								        return;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    Instruction* dec = new Instruction(OpMemberDecorateStringGOOGLE);
							 | 
						||
| 
								 | 
							
								    dec->addIdOperand(id);
							 | 
						||
| 
								 | 
							
								    dec->addImmediateOperand(member);
							 | 
						||
| 
								 | 
							
								    dec->addImmediateOperand(decoration);
							 | 
						||
| 
								 | 
							
								    dec->addStringOperand(s);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    decorations.push_back(std::unique_ptr<Instruction>(dec));
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// Comments in header
							 | 
						||
| 
								 | 
							
								Function* Builder::makeEntryPoint(const char* entryPoint)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    assert(! entryPointFunction);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    Block* entry;
							 | 
						||
| 
								 | 
							
								    std::vector<Id> params;
							 | 
						||
| 
								 | 
							
								    std::vector<std::vector<Decoration>> decorations;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    entryPointFunction = makeFunctionEntry(NoPrecision, makeVoidType(), entryPoint, params, decorations, &entry);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    return entryPointFunction;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// Comments in header
							 | 
						||
| 
								 | 
							
								Function* Builder::makeFunctionEntry(Decoration precision, Id returnType, const char* name,
							 | 
						||
| 
								 | 
							
								                                     const std::vector<Id>& paramTypes,
							 | 
						||
| 
								 | 
							
								                                     const std::vector<std::vector<Decoration>>& decorations, Block **entry)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    // Make the function and initial instructions in it
							 | 
						||
| 
								 | 
							
								    Id typeId = makeFunctionType(returnType, paramTypes);
							 | 
						||
| 
								 | 
							
								    Id firstParamId = paramTypes.size() == 0 ? 0 : getUniqueIds((int)paramTypes.size());
							 | 
						||
| 
								 | 
							
								    Function* function = new Function(getUniqueId(), returnType, typeId, firstParamId, module);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // Set up the precisions
							 | 
						||
| 
								 | 
							
								    setPrecision(function->getId(), precision);
							 | 
						||
| 
								 | 
							
								    for (unsigned p = 0; p < (unsigned)decorations.size(); ++p) {
							 | 
						||
| 
								 | 
							
								        for (int d = 0; d < (int)decorations[p].size(); ++d)
							 | 
						||
| 
								 | 
							
								            addDecoration(firstParamId + p, decorations[p][d]);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // CFG
							 | 
						||
| 
								 | 
							
								    if (entry) {
							 | 
						||
| 
								 | 
							
								        *entry = new Block(getUniqueId(), *function);
							 | 
						||
| 
								 | 
							
								        function->addBlock(*entry);
							 | 
						||
| 
								 | 
							
								        setBuildPoint(*entry);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if (name)
							 | 
						||
| 
								 | 
							
								        addName(function->getId(), name);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    functions.push_back(std::unique_ptr<Function>(function));
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    return function;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// Comments in header
							 | 
						||
| 
								 | 
							
								void Builder::makeReturn(bool implicit, Id retVal)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    if (retVal) {
							 | 
						||
| 
								 | 
							
								        Instruction* inst = new Instruction(NoResult, NoType, OpReturnValue);
							 | 
						||
| 
								 | 
							
								        inst->addIdOperand(retVal);
							 | 
						||
| 
								 | 
							
								        buildPoint->addInstruction(std::unique_ptr<Instruction>(inst));
							 | 
						||
| 
								 | 
							
								    } else
							 | 
						||
| 
								 | 
							
								        buildPoint->addInstruction(std::unique_ptr<Instruction>(new Instruction(NoResult, NoType, OpReturn)));
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if (! implicit)
							 | 
						||
| 
								 | 
							
								        createAndSetNoPredecessorBlock("post-return");
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// Comments in header
							 | 
						||
| 
								 | 
							
								void Builder::leaveFunction()
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    Block* block = buildPoint;
							 | 
						||
| 
								 | 
							
								    Function& function = buildPoint->getParent();
							 | 
						||
| 
								 | 
							
								    assert(block);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // If our function did not contain a return, add a return void now.
							 | 
						||
| 
								 | 
							
								    if (! block->isTerminated()) {
							 | 
						||
| 
								 | 
							
								        if (function.getReturnType() == makeVoidType())
							 | 
						||
| 
								 | 
							
								            makeReturn(true);
							 | 
						||
| 
								 | 
							
								        else {
							 | 
						||
| 
								 | 
							
								            makeReturn(true, createUndefined(function.getReturnType()));
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// Comments in header
							 | 
						||
| 
								 | 
							
								void Builder::makeDiscard()
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    buildPoint->addInstruction(std::unique_ptr<Instruction>(new Instruction(OpKill)));
							 | 
						||
| 
								 | 
							
								    createAndSetNoPredecessorBlock("post-discard");
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// Comments in header
							 | 
						||
| 
								 | 
							
								Id Builder::createVariable(StorageClass storageClass, Id type, const char* name, Id initializer)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    Id pointerType = makePointer(storageClass, type);
							 | 
						||
| 
								 | 
							
								    Instruction* inst = new Instruction(getUniqueId(), pointerType, OpVariable);
							 | 
						||
| 
								 | 
							
								    inst->addImmediateOperand(storageClass);
							 | 
						||
| 
								 | 
							
								    if (initializer != NoResult)
							 | 
						||
| 
								 | 
							
								        inst->addIdOperand(initializer);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    switch (storageClass) {
							 | 
						||
| 
								 | 
							
								    case StorageClassFunction:
							 | 
						||
| 
								 | 
							
								        // Validation rules require the declaration in the entry block
							 | 
						||
| 
								 | 
							
								        buildPoint->getParent().addLocalVariable(std::unique_ptr<Instruction>(inst));
							 | 
						||
| 
								 | 
							
								        break;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    default:
							 | 
						||
| 
								 | 
							
								        constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(inst));
							 | 
						||
| 
								 | 
							
								        module.mapInstruction(inst);
							 | 
						||
| 
								 | 
							
								        break;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if (name)
							 | 
						||
| 
								 | 
							
								        addName(inst->getResultId(), name);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    return inst->getResultId();
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// Comments in header
							 | 
						||
| 
								 | 
							
								Id Builder::createUndefined(Id type)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								  Instruction* inst = new Instruction(getUniqueId(), type, OpUndef);
							 | 
						||
| 
								 | 
							
								  buildPoint->addInstruction(std::unique_ptr<Instruction>(inst));
							 | 
						||
| 
								 | 
							
								  return inst->getResultId();
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// av/vis/nonprivate are unnecessary and illegal for some storage classes.
							 | 
						||
| 
								 | 
							
								spv::MemoryAccessMask Builder::sanitizeMemoryAccessForStorageClass(spv::MemoryAccessMask memoryAccess, StorageClass sc)
							 | 
						||
| 
								 | 
							
								    const
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    switch (sc) {
							 | 
						||
| 
								 | 
							
								    case spv::StorageClassUniform:
							 | 
						||
| 
								 | 
							
								    case spv::StorageClassWorkgroup:
							 | 
						||
| 
								 | 
							
								    case spv::StorageClassStorageBuffer:
							 | 
						||
| 
								 | 
							
								    case spv::StorageClassPhysicalStorageBufferEXT:
							 | 
						||
| 
								 | 
							
								        break;
							 | 
						||
| 
								 | 
							
								    default:
							 | 
						||
| 
								 | 
							
								        memoryAccess = spv::MemoryAccessMask(memoryAccess & 
							 | 
						||
| 
								 | 
							
								                        ~(spv::MemoryAccessMakePointerAvailableKHRMask |
							 | 
						||
| 
								 | 
							
								                          spv::MemoryAccessMakePointerVisibleKHRMask |
							 | 
						||
| 
								 | 
							
								                          spv::MemoryAccessNonPrivatePointerKHRMask));
							 | 
						||
| 
								 | 
							
								        break;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    return memoryAccess;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// Comments in header
							 | 
						||
| 
								 | 
							
								void Builder::createStore(Id rValue, Id lValue, spv::MemoryAccessMask memoryAccess, spv::Scope scope,
							 | 
						||
| 
								 | 
							
								    unsigned int alignment)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    Instruction* store = new Instruction(OpStore);
							 | 
						||
| 
								 | 
							
								    store->addIdOperand(lValue);
							 | 
						||
| 
								 | 
							
								    store->addIdOperand(rValue);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    memoryAccess = sanitizeMemoryAccessForStorageClass(memoryAccess, getStorageClass(lValue));
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if (memoryAccess != MemoryAccessMaskNone) {
							 | 
						||
| 
								 | 
							
								        store->addImmediateOperand(memoryAccess);
							 | 
						||
| 
								 | 
							
								        if (memoryAccess & spv::MemoryAccessAlignedMask) {
							 | 
						||
| 
								 | 
							
								            store->addImmediateOperand(alignment);
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        if (memoryAccess & spv::MemoryAccessMakePointerAvailableKHRMask) {
							 | 
						||
| 
								 | 
							
								            store->addIdOperand(makeUintConstant(scope));
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    buildPoint->addInstruction(std::unique_ptr<Instruction>(store));
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// Comments in header
							 | 
						||
| 
								 | 
							
								Id Builder::createLoad(Id lValue, spv::MemoryAccessMask memoryAccess, spv::Scope scope, unsigned int alignment)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    Instruction* load = new Instruction(getUniqueId(), getDerefTypeId(lValue), OpLoad);
							 | 
						||
| 
								 | 
							
								    load->addIdOperand(lValue);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    memoryAccess = sanitizeMemoryAccessForStorageClass(memoryAccess, getStorageClass(lValue));
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if (memoryAccess != MemoryAccessMaskNone) {
							 | 
						||
| 
								 | 
							
								        load->addImmediateOperand(memoryAccess);
							 | 
						||
| 
								 | 
							
								        if (memoryAccess & spv::MemoryAccessAlignedMask) {
							 | 
						||
| 
								 | 
							
								            load->addImmediateOperand(alignment);
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        if (memoryAccess & spv::MemoryAccessMakePointerVisibleKHRMask) {
							 | 
						||
| 
								 | 
							
								            load->addIdOperand(makeUintConstant(scope));
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    buildPoint->addInstruction(std::unique_ptr<Instruction>(load));
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    return load->getResultId();
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// Comments in header
							 | 
						||
| 
								 | 
							
								Id Builder::createAccessChain(StorageClass storageClass, Id base, const std::vector<Id>& offsets)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    // Figure out the final resulting type.
							 | 
						||
| 
								 | 
							
								    spv::Id typeId = getTypeId(base);
							 | 
						||
| 
								 | 
							
								    assert(isPointerType(typeId) && offsets.size() > 0);
							 | 
						||
| 
								 | 
							
								    typeId = getContainedTypeId(typeId);
							 | 
						||
| 
								 | 
							
								    for (int i = 0; i < (int)offsets.size(); ++i) {
							 | 
						||
| 
								 | 
							
								        if (isStructType(typeId)) {
							 | 
						||
| 
								 | 
							
								            assert(isConstantScalar(offsets[i]));
							 | 
						||
| 
								 | 
							
								            typeId = getContainedTypeId(typeId, getConstantScalar(offsets[i]));
							 | 
						||
| 
								 | 
							
								        } else
							 | 
						||
| 
								 | 
							
								            typeId = getContainedTypeId(typeId, offsets[i]);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    typeId = makePointer(storageClass, typeId);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // Make the instruction
							 | 
						||
| 
								 | 
							
								    Instruction* chain = new Instruction(getUniqueId(), typeId, OpAccessChain);
							 | 
						||
| 
								 | 
							
								    chain->addIdOperand(base);
							 | 
						||
| 
								 | 
							
								    for (int i = 0; i < (int)offsets.size(); ++i)
							 | 
						||
| 
								 | 
							
								        chain->addIdOperand(offsets[i]);
							 | 
						||
| 
								 | 
							
								    buildPoint->addInstruction(std::unique_ptr<Instruction>(chain));
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    return chain->getResultId();
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Id Builder::createArrayLength(Id base, unsigned int member)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    spv::Id intType = makeUintType(32);
							 | 
						||
| 
								 | 
							
								    Instruction* length = new Instruction(getUniqueId(), intType, OpArrayLength);
							 | 
						||
| 
								 | 
							
								    length->addIdOperand(base);
							 | 
						||
| 
								 | 
							
								    length->addImmediateOperand(member);
							 | 
						||
| 
								 | 
							
								    buildPoint->addInstruction(std::unique_ptr<Instruction>(length));
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    return length->getResultId();
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Id Builder::createCooperativeMatrixLength(Id type)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    spv::Id intType = makeUintType(32);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // Generate code for spec constants if in spec constant operation
							 | 
						||
| 
								 | 
							
								    // generation mode.
							 | 
						||
| 
								 | 
							
								    if (generatingOpCodeForSpecConst) {
							 | 
						||
| 
								 | 
							
								        return createSpecConstantOp(OpCooperativeMatrixLengthNV, intType, std::vector<Id>(1, type), std::vector<Id>());
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    Instruction* length = new Instruction(getUniqueId(), intType, OpCooperativeMatrixLengthNV);
							 | 
						||
| 
								 | 
							
								    length->addIdOperand(type);
							 | 
						||
| 
								 | 
							
								    buildPoint->addInstruction(std::unique_ptr<Instruction>(length));
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    return length->getResultId();
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Id Builder::createCompositeExtract(Id composite, Id typeId, unsigned index)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    // Generate code for spec constants if in spec constant operation
							 | 
						||
| 
								 | 
							
								    // generation mode.
							 | 
						||
| 
								 | 
							
								    if (generatingOpCodeForSpecConst) {
							 | 
						||
| 
								 | 
							
								        return createSpecConstantOp(OpCompositeExtract, typeId, std::vector<Id>(1, composite),
							 | 
						||
| 
								 | 
							
								            std::vector<Id>(1, index));
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    Instruction* extract = new Instruction(getUniqueId(), typeId, OpCompositeExtract);
							 | 
						||
| 
								 | 
							
								    extract->addIdOperand(composite);
							 | 
						||
| 
								 | 
							
								    extract->addImmediateOperand(index);
							 | 
						||
| 
								 | 
							
								    buildPoint->addInstruction(std::unique_ptr<Instruction>(extract));
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    return extract->getResultId();
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Id Builder::createCompositeExtract(Id composite, Id typeId, const std::vector<unsigned>& indexes)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    // Generate code for spec constants if in spec constant operation
							 | 
						||
| 
								 | 
							
								    // generation mode.
							 | 
						||
| 
								 | 
							
								    if (generatingOpCodeForSpecConst) {
							 | 
						||
| 
								 | 
							
								        return createSpecConstantOp(OpCompositeExtract, typeId, std::vector<Id>(1, composite), indexes);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    Instruction* extract = new Instruction(getUniqueId(), typeId, OpCompositeExtract);
							 | 
						||
| 
								 | 
							
								    extract->addIdOperand(composite);
							 | 
						||
| 
								 | 
							
								    for (int i = 0; i < (int)indexes.size(); ++i)
							 | 
						||
| 
								 | 
							
								        extract->addImmediateOperand(indexes[i]);
							 | 
						||
| 
								 | 
							
								    buildPoint->addInstruction(std::unique_ptr<Instruction>(extract));
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    return extract->getResultId();
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Id Builder::createCompositeInsert(Id object, Id composite, Id typeId, unsigned index)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    Instruction* insert = new Instruction(getUniqueId(), typeId, OpCompositeInsert);
							 | 
						||
| 
								 | 
							
								    insert->addIdOperand(object);
							 | 
						||
| 
								 | 
							
								    insert->addIdOperand(composite);
							 | 
						||
| 
								 | 
							
								    insert->addImmediateOperand(index);
							 | 
						||
| 
								 | 
							
								    buildPoint->addInstruction(std::unique_ptr<Instruction>(insert));
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    return insert->getResultId();
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Id Builder::createCompositeInsert(Id object, Id composite, Id typeId, const std::vector<unsigned>& indexes)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    Instruction* insert = new Instruction(getUniqueId(), typeId, OpCompositeInsert);
							 | 
						||
| 
								 | 
							
								    insert->addIdOperand(object);
							 | 
						||
| 
								 | 
							
								    insert->addIdOperand(composite);
							 | 
						||
| 
								 | 
							
								    for (int i = 0; i < (int)indexes.size(); ++i)
							 | 
						||
| 
								 | 
							
								        insert->addImmediateOperand(indexes[i]);
							 | 
						||
| 
								 | 
							
								    buildPoint->addInstruction(std::unique_ptr<Instruction>(insert));
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    return insert->getResultId();
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Id Builder::createVectorExtractDynamic(Id vector, Id typeId, Id componentIndex)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    Instruction* extract = new Instruction(getUniqueId(), typeId, OpVectorExtractDynamic);
							 | 
						||
| 
								 | 
							
								    extract->addIdOperand(vector);
							 | 
						||
| 
								 | 
							
								    extract->addIdOperand(componentIndex);
							 | 
						||
| 
								 | 
							
								    buildPoint->addInstruction(std::unique_ptr<Instruction>(extract));
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    return extract->getResultId();
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Id Builder::createVectorInsertDynamic(Id vector, Id typeId, Id component, Id componentIndex)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    Instruction* insert = new Instruction(getUniqueId(), typeId, OpVectorInsertDynamic);
							 | 
						||
| 
								 | 
							
								    insert->addIdOperand(vector);
							 | 
						||
| 
								 | 
							
								    insert->addIdOperand(component);
							 | 
						||
| 
								 | 
							
								    insert->addIdOperand(componentIndex);
							 | 
						||
| 
								 | 
							
								    buildPoint->addInstruction(std::unique_ptr<Instruction>(insert));
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    return insert->getResultId();
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// An opcode that has no operands, no result id, and no type
							 | 
						||
| 
								 | 
							
								void Builder::createNoResultOp(Op opCode)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    Instruction* op = new Instruction(opCode);
							 | 
						||
| 
								 | 
							
								    buildPoint->addInstruction(std::unique_ptr<Instruction>(op));
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// An opcode that has one id operand, no result id, and no type
							 | 
						||
| 
								 | 
							
								void Builder::createNoResultOp(Op opCode, Id operand)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    Instruction* op = new Instruction(opCode);
							 | 
						||
| 
								 | 
							
								    op->addIdOperand(operand);
							 | 
						||
| 
								 | 
							
								    buildPoint->addInstruction(std::unique_ptr<Instruction>(op));
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// An opcode that has one or more operands, no result id, and no type
							 | 
						||
| 
								 | 
							
								void Builder::createNoResultOp(Op opCode, const std::vector<Id>& operands)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    Instruction* op = new Instruction(opCode);
							 | 
						||
| 
								 | 
							
								    for (auto it = operands.cbegin(); it != operands.cend(); ++it) {
							 | 
						||
| 
								 | 
							
								        op->addIdOperand(*it);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    buildPoint->addInstruction(std::unique_ptr<Instruction>(op));
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// An opcode that has multiple operands, no result id, and no type
							 | 
						||
| 
								 | 
							
								void Builder::createNoResultOp(Op opCode, const std::vector<IdImmediate>& operands)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    Instruction* op = new Instruction(opCode);
							 | 
						||
| 
								 | 
							
								    for (auto it = operands.cbegin(); it != operands.cend(); ++it) {
							 | 
						||
| 
								 | 
							
								        if (it->isId)
							 | 
						||
| 
								 | 
							
								            op->addIdOperand(it->word);
							 | 
						||
| 
								 | 
							
								        else
							 | 
						||
| 
								 | 
							
								            op->addImmediateOperand(it->word);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    buildPoint->addInstruction(std::unique_ptr<Instruction>(op));
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								void Builder::createControlBarrier(Scope execution, Scope memory, MemorySemanticsMask semantics)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    Instruction* op = new Instruction(OpControlBarrier);
							 | 
						||
| 
								 | 
							
								    op->addIdOperand(makeUintConstant(execution));
							 | 
						||
| 
								 | 
							
								    op->addIdOperand(makeUintConstant(memory));
							 | 
						||
| 
								 | 
							
								    op->addIdOperand(makeUintConstant(semantics));
							 | 
						||
| 
								 | 
							
								    buildPoint->addInstruction(std::unique_ptr<Instruction>(op));
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								void Builder::createMemoryBarrier(unsigned executionScope, unsigned memorySemantics)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    Instruction* op = new Instruction(OpMemoryBarrier);
							 | 
						||
| 
								 | 
							
								    op->addIdOperand(makeUintConstant(executionScope));
							 | 
						||
| 
								 | 
							
								    op->addIdOperand(makeUintConstant(memorySemantics));
							 | 
						||
| 
								 | 
							
								    buildPoint->addInstruction(std::unique_ptr<Instruction>(op));
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// An opcode that has one operands, a result id, and a type
							 | 
						||
| 
								 | 
							
								Id Builder::createUnaryOp(Op opCode, Id typeId, Id operand)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    // Generate code for spec constants if in spec constant operation
							 | 
						||
| 
								 | 
							
								    // generation mode.
							 | 
						||
| 
								 | 
							
								    if (generatingOpCodeForSpecConst) {
							 | 
						||
| 
								 | 
							
								        return createSpecConstantOp(opCode, typeId, std::vector<Id>(1, operand), std::vector<Id>());
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    Instruction* op = new Instruction(getUniqueId(), typeId, opCode);
							 | 
						||
| 
								 | 
							
								    op->addIdOperand(operand);
							 | 
						||
| 
								 | 
							
								    buildPoint->addInstruction(std::unique_ptr<Instruction>(op));
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    return op->getResultId();
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Id Builder::createBinOp(Op opCode, Id typeId, Id left, Id right)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    // Generate code for spec constants if in spec constant operation
							 | 
						||
| 
								 | 
							
								    // generation mode.
							 | 
						||
| 
								 | 
							
								    if (generatingOpCodeForSpecConst) {
							 | 
						||
| 
								 | 
							
								        std::vector<Id> operands(2);
							 | 
						||
| 
								 | 
							
								        operands[0] = left; operands[1] = right;
							 | 
						||
| 
								 | 
							
								        return createSpecConstantOp(opCode, typeId, operands, std::vector<Id>());
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    Instruction* op = new Instruction(getUniqueId(), typeId, opCode);
							 | 
						||
| 
								 | 
							
								    op->addIdOperand(left);
							 | 
						||
| 
								 | 
							
								    op->addIdOperand(right);
							 | 
						||
| 
								 | 
							
								    buildPoint->addInstruction(std::unique_ptr<Instruction>(op));
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    return op->getResultId();
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Id Builder::createTriOp(Op opCode, Id typeId, Id op1, Id op2, Id op3)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    // Generate code for spec constants if in spec constant operation
							 | 
						||
| 
								 | 
							
								    // generation mode.
							 | 
						||
| 
								 | 
							
								    if (generatingOpCodeForSpecConst) {
							 | 
						||
| 
								 | 
							
								        std::vector<Id> operands(3);
							 | 
						||
| 
								 | 
							
								        operands[0] = op1;
							 | 
						||
| 
								 | 
							
								        operands[1] = op2;
							 | 
						||
| 
								 | 
							
								        operands[2] = op3;
							 | 
						||
| 
								 | 
							
								        return createSpecConstantOp(
							 | 
						||
| 
								 | 
							
								            opCode, typeId, operands, std::vector<Id>());
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    Instruction* op = new Instruction(getUniqueId(), typeId, opCode);
							 | 
						||
| 
								 | 
							
								    op->addIdOperand(op1);
							 | 
						||
| 
								 | 
							
								    op->addIdOperand(op2);
							 | 
						||
| 
								 | 
							
								    op->addIdOperand(op3);
							 | 
						||
| 
								 | 
							
								    buildPoint->addInstruction(std::unique_ptr<Instruction>(op));
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    return op->getResultId();
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Id Builder::createOp(Op opCode, Id typeId, const std::vector<Id>& operands)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    Instruction* op = new Instruction(getUniqueId(), typeId, opCode);
							 | 
						||
| 
								 | 
							
								    for (auto it = operands.cbegin(); it != operands.cend(); ++it)
							 | 
						||
| 
								 | 
							
								        op->addIdOperand(*it);
							 | 
						||
| 
								 | 
							
								    buildPoint->addInstruction(std::unique_ptr<Instruction>(op));
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    return op->getResultId();
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Id Builder::createOp(Op opCode, Id typeId, const std::vector<IdImmediate>& operands)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    Instruction* op = new Instruction(getUniqueId(), typeId, opCode);
							 | 
						||
| 
								 | 
							
								    for (auto it = operands.cbegin(); it != operands.cend(); ++it) {
							 | 
						||
| 
								 | 
							
								        if (it->isId)
							 | 
						||
| 
								 | 
							
								            op->addIdOperand(it->word);
							 | 
						||
| 
								 | 
							
								        else
							 | 
						||
| 
								 | 
							
								            op->addImmediateOperand(it->word);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    buildPoint->addInstruction(std::unique_ptr<Instruction>(op));
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    return op->getResultId();
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Id Builder::createSpecConstantOp(Op opCode, Id typeId, const std::vector<Id>& operands,
							 | 
						||
| 
								 | 
							
								    const std::vector<unsigned>& literals)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    Instruction* op = new Instruction(getUniqueId(), typeId, OpSpecConstantOp);
							 | 
						||
| 
								 | 
							
								    op->addImmediateOperand((unsigned) opCode);
							 | 
						||
| 
								 | 
							
								    for (auto it = operands.cbegin(); it != operands.cend(); ++it)
							 | 
						||
| 
								 | 
							
								        op->addIdOperand(*it);
							 | 
						||
| 
								 | 
							
								    for (auto it = literals.cbegin(); it != literals.cend(); ++it)
							 | 
						||
| 
								 | 
							
								        op->addImmediateOperand(*it);
							 | 
						||
| 
								 | 
							
								    module.mapInstruction(op);
							 | 
						||
| 
								 | 
							
								    constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(op));
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    return op->getResultId();
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Id Builder::createFunctionCall(spv::Function* function, const std::vector<spv::Id>& args)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    Instruction* op = new Instruction(getUniqueId(), function->getReturnType(), OpFunctionCall);
							 | 
						||
| 
								 | 
							
								    op->addIdOperand(function->getId());
							 | 
						||
| 
								 | 
							
								    for (int a = 0; a < (int)args.size(); ++a)
							 | 
						||
| 
								 | 
							
								        op->addIdOperand(args[a]);
							 | 
						||
| 
								 | 
							
								    buildPoint->addInstruction(std::unique_ptr<Instruction>(op));
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    return op->getResultId();
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// Comments in header
							 | 
						||
| 
								 | 
							
								Id Builder::createRvalueSwizzle(Decoration precision, Id typeId, Id source, const std::vector<unsigned>& channels)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    if (channels.size() == 1)
							 | 
						||
| 
								 | 
							
								        return setPrecision(createCompositeExtract(source, typeId, channels.front()), precision);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if (generatingOpCodeForSpecConst) {
							 | 
						||
| 
								 | 
							
								        std::vector<Id> operands(2);
							 | 
						||
| 
								 | 
							
								        operands[0] = operands[1] = source;
							 | 
						||
| 
								 | 
							
								        return setPrecision(createSpecConstantOp(OpVectorShuffle, typeId, operands, channels), precision);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    Instruction* swizzle = new Instruction(getUniqueId(), typeId, OpVectorShuffle);
							 | 
						||
| 
								 | 
							
								    assert(isVector(source));
							 | 
						||
| 
								 | 
							
								    swizzle->addIdOperand(source);
							 | 
						||
| 
								 | 
							
								    swizzle->addIdOperand(source);
							 | 
						||
| 
								 | 
							
								    for (int i = 0; i < (int)channels.size(); ++i)
							 | 
						||
| 
								 | 
							
								        swizzle->addImmediateOperand(channels[i]);
							 | 
						||
| 
								 | 
							
								    buildPoint->addInstruction(std::unique_ptr<Instruction>(swizzle));
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    return setPrecision(swizzle->getResultId(), precision);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// Comments in header
							 | 
						||
| 
								 | 
							
								Id Builder::createLvalueSwizzle(Id typeId, Id target, Id source, const std::vector<unsigned>& channels)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    if (channels.size() == 1 && getNumComponents(source) == 1)
							 | 
						||
| 
								 | 
							
								        return createCompositeInsert(source, target, typeId, channels.front());
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    Instruction* swizzle = new Instruction(getUniqueId(), typeId, OpVectorShuffle);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    assert(isVector(target));
							 | 
						||
| 
								 | 
							
								    swizzle->addIdOperand(target);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    assert(getNumComponents(source) == (int)channels.size());
							 | 
						||
| 
								 | 
							
								    assert(isVector(source));
							 | 
						||
| 
								 | 
							
								    swizzle->addIdOperand(source);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // Set up an identity shuffle from the base value to the result value
							 | 
						||
| 
								 | 
							
								    unsigned int components[4];
							 | 
						||
| 
								 | 
							
								    int numTargetComponents = getNumComponents(target);
							 | 
						||
| 
								 | 
							
								    for (int i = 0; i < numTargetComponents; ++i)
							 | 
						||
| 
								 | 
							
								        components[i] = i;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // Punch in the l-value swizzle
							 | 
						||
| 
								 | 
							
								    for (int i = 0; i < (int)channels.size(); ++i)
							 | 
						||
| 
								 | 
							
								        components[channels[i]] = numTargetComponents + i;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // finish the instruction with these components selectors
							 | 
						||
| 
								 | 
							
								    for (int i = 0; i < numTargetComponents; ++i)
							 | 
						||
| 
								 | 
							
								        swizzle->addImmediateOperand(components[i]);
							 | 
						||
| 
								 | 
							
								    buildPoint->addInstruction(std::unique_ptr<Instruction>(swizzle));
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    return swizzle->getResultId();
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// Comments in header
							 | 
						||
| 
								 | 
							
								void Builder::promoteScalar(Decoration precision, Id& left, Id& right)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    int direction = getNumComponents(right) - getNumComponents(left);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if (direction > 0)
							 | 
						||
| 
								 | 
							
								        left = smearScalar(precision, left, makeVectorType(getTypeId(left), getNumComponents(right)));
							 | 
						||
| 
								 | 
							
								    else if (direction < 0)
							 | 
						||
| 
								 | 
							
								        right = smearScalar(precision, right, makeVectorType(getTypeId(right), getNumComponents(left)));
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    return;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// Comments in header
							 | 
						||
| 
								 | 
							
								Id Builder::smearScalar(Decoration precision, Id scalar, Id vectorType)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    assert(getNumComponents(scalar) == 1);
							 | 
						||
| 
								 | 
							
								    assert(getTypeId(scalar) == getScalarTypeId(vectorType));
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    int numComponents = getNumTypeComponents(vectorType);
							 | 
						||
| 
								 | 
							
								    if (numComponents == 1)
							 | 
						||
| 
								 | 
							
								        return scalar;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    Instruction* smear = nullptr;
							 | 
						||
| 
								 | 
							
								    if (generatingOpCodeForSpecConst) {
							 | 
						||
| 
								 | 
							
								        auto members = std::vector<spv::Id>(numComponents, scalar);
							 | 
						||
| 
								 | 
							
								        // Sometime even in spec-constant-op mode, the temporary vector created by
							 | 
						||
| 
								 | 
							
								        // promoting a scalar might not be a spec constant. This should depend on
							 | 
						||
| 
								 | 
							
								        // the scalar.
							 | 
						||
| 
								 | 
							
								        // e.g.:
							 | 
						||
| 
								 | 
							
								        //  const vec2 spec_const_result = a_spec_const_vec2 + a_front_end_const_scalar;
							 | 
						||
| 
								 | 
							
								        // In such cases, the temporary vector created from a_front_end_const_scalar
							 | 
						||
| 
								 | 
							
								        // is not a spec constant vector, even though the binary operation node is marked
							 | 
						||
| 
								 | 
							
								        // as 'specConstant' and we are in spec-constant-op mode.
							 | 
						||
| 
								 | 
							
								        auto result_id = makeCompositeConstant(vectorType, members, isSpecConstant(scalar));
							 | 
						||
| 
								 | 
							
								        smear = module.getInstruction(result_id);
							 | 
						||
| 
								 | 
							
								    } else {
							 | 
						||
| 
								 | 
							
								        smear = new Instruction(getUniqueId(), vectorType, OpCompositeConstruct);
							 | 
						||
| 
								 | 
							
								        for (int c = 0; c < numComponents; ++c)
							 | 
						||
| 
								 | 
							
								            smear->addIdOperand(scalar);
							 | 
						||
| 
								 | 
							
								        buildPoint->addInstruction(std::unique_ptr<Instruction>(smear));
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    return setPrecision(smear->getResultId(), precision);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// Comments in header
							 | 
						||
| 
								 | 
							
								Id Builder::createBuiltinCall(Id resultType, Id builtins, int entryPoint, const std::vector<Id>& args)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    Instruction* inst = new Instruction(getUniqueId(), resultType, OpExtInst);
							 | 
						||
| 
								 | 
							
								    inst->addIdOperand(builtins);
							 | 
						||
| 
								 | 
							
								    inst->addImmediateOperand(entryPoint);
							 | 
						||
| 
								 | 
							
								    for (int arg = 0; arg < (int)args.size(); ++arg)
							 | 
						||
| 
								 | 
							
								        inst->addIdOperand(args[arg]);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    buildPoint->addInstruction(std::unique_ptr<Instruction>(inst));
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    return inst->getResultId();
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// Accept all parameters needed to create a texture instruction.
							 | 
						||
| 
								 | 
							
								// Create the correct instruction based on the inputs, and make the call.
							 | 
						||
| 
								 | 
							
								Id Builder::createTextureCall(Decoration precision, Id resultType, bool sparse, bool fetch, bool proj, bool gather,
							 | 
						||
| 
								 | 
							
								    bool noImplicitLod, const TextureParameters& parameters, ImageOperandsMask signExtensionMask)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    static const int maxTextureArgs = 10;
							 | 
						||
| 
								 | 
							
								    Id texArgs[maxTextureArgs] = {};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    //
							 | 
						||
| 
								 | 
							
								    // Set up the fixed arguments
							 | 
						||
| 
								 | 
							
								    //
							 | 
						||
| 
								 | 
							
								    int numArgs = 0;
							 | 
						||
| 
								 | 
							
								    bool explicitLod = false;
							 | 
						||
| 
								 | 
							
								    texArgs[numArgs++] = parameters.sampler;
							 | 
						||
| 
								 | 
							
								    texArgs[numArgs++] = parameters.coords;
							 | 
						||
| 
								 | 
							
								    if (parameters.Dref != NoResult)
							 | 
						||
| 
								 | 
							
								        texArgs[numArgs++] = parameters.Dref;
							 | 
						||
| 
								 | 
							
								    if (parameters.component != NoResult)
							 | 
						||
| 
								 | 
							
								        texArgs[numArgs++] = parameters.component;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#ifndef GLSLANG_WEB
							 | 
						||
| 
								 | 
							
								    if (parameters.granularity != NoResult)
							 | 
						||
| 
								 | 
							
								        texArgs[numArgs++] = parameters.granularity;
							 | 
						||
| 
								 | 
							
								    if (parameters.coarse != NoResult)
							 | 
						||
| 
								 | 
							
								        texArgs[numArgs++] = parameters.coarse;
							 | 
						||
| 
								 | 
							
								#endif 
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    //
							 | 
						||
| 
								 | 
							
								    // Set up the optional arguments
							 | 
						||
| 
								 | 
							
								    //
							 | 
						||
| 
								 | 
							
								    int optArgNum = numArgs;    // track which operand, if it exists, is the mask of optional arguments
							 | 
						||
| 
								 | 
							
								    ++numArgs;                  // speculatively make room for the mask operand
							 | 
						||
| 
								 | 
							
								    ImageOperandsMask mask = ImageOperandsMaskNone; // the mask operand
							 | 
						||
| 
								 | 
							
								    if (parameters.bias) {
							 | 
						||
| 
								 | 
							
								        mask = (ImageOperandsMask)(mask | ImageOperandsBiasMask);
							 | 
						||
| 
								 | 
							
								        texArgs[numArgs++] = parameters.bias;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    if (parameters.lod) {
							 | 
						||
| 
								 | 
							
								        mask = (ImageOperandsMask)(mask | ImageOperandsLodMask);
							 | 
						||
| 
								 | 
							
								        texArgs[numArgs++] = parameters.lod;
							 | 
						||
| 
								 | 
							
								        explicitLod = true;
							 | 
						||
| 
								 | 
							
								    } else if (parameters.gradX) {
							 | 
						||
| 
								 | 
							
								        mask = (ImageOperandsMask)(mask | ImageOperandsGradMask);
							 | 
						||
| 
								 | 
							
								        texArgs[numArgs++] = parameters.gradX;
							 | 
						||
| 
								 | 
							
								        texArgs[numArgs++] = parameters.gradY;
							 | 
						||
| 
								 | 
							
								        explicitLod = true;
							 | 
						||
| 
								 | 
							
								    } else if (noImplicitLod && ! fetch && ! gather) {
							 | 
						||
| 
								 | 
							
								        // have to explicitly use lod of 0 if not allowed to have them be implicit, and
							 | 
						||
| 
								 | 
							
								        // we would otherwise be about to issue an implicit instruction
							 | 
						||
| 
								 | 
							
								        mask = (ImageOperandsMask)(mask | ImageOperandsLodMask);
							 | 
						||
| 
								 | 
							
								        texArgs[numArgs++] = makeFloatConstant(0.0);
							 | 
						||
| 
								 | 
							
								        explicitLod = true;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    if (parameters.offset) {
							 | 
						||
| 
								 | 
							
								        if (isConstant(parameters.offset))
							 | 
						||
| 
								 | 
							
								            mask = (ImageOperandsMask)(mask | ImageOperandsConstOffsetMask);
							 | 
						||
| 
								 | 
							
								        else {
							 | 
						||
| 
								 | 
							
								            addCapability(CapabilityImageGatherExtended);
							 | 
						||
| 
								 | 
							
								            mask = (ImageOperandsMask)(mask | ImageOperandsOffsetMask);
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        texArgs[numArgs++] = parameters.offset;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    if (parameters.offsets) {
							 | 
						||
| 
								 | 
							
								        addCapability(CapabilityImageGatherExtended);
							 | 
						||
| 
								 | 
							
								        mask = (ImageOperandsMask)(mask | ImageOperandsConstOffsetsMask);
							 | 
						||
| 
								 | 
							
								        texArgs[numArgs++] = parameters.offsets;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								#ifndef GLSLANG_WEB
							 | 
						||
| 
								 | 
							
								    if (parameters.sample) {
							 | 
						||
| 
								 | 
							
								        mask = (ImageOperandsMask)(mask | ImageOperandsSampleMask);
							 | 
						||
| 
								 | 
							
								        texArgs[numArgs++] = parameters.sample;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    if (parameters.lodClamp) {
							 | 
						||
| 
								 | 
							
								        // capability if this bit is used
							 | 
						||
| 
								 | 
							
								        addCapability(CapabilityMinLod);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        mask = (ImageOperandsMask)(mask | ImageOperandsMinLodMask);
							 | 
						||
| 
								 | 
							
								        texArgs[numArgs++] = parameters.lodClamp;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    if (parameters.nonprivate) {
							 | 
						||
| 
								 | 
							
								        mask = mask | ImageOperandsNonPrivateTexelKHRMask;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    if (parameters.volatil) {
							 | 
						||
| 
								 | 
							
								        mask = mask | ImageOperandsVolatileTexelKHRMask;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								#endif
							 | 
						||
| 
								 | 
							
								    mask = mask | signExtensionMask;
							 | 
						||
| 
								 | 
							
								    if (mask == ImageOperandsMaskNone)
							 | 
						||
| 
								 | 
							
								        --numArgs;  // undo speculative reservation for the mask argument
							 | 
						||
| 
								 | 
							
								    else
							 | 
						||
| 
								 | 
							
								        texArgs[optArgNum] = mask;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    //
							 | 
						||
| 
								 | 
							
								    // Set up the instruction
							 | 
						||
| 
								 | 
							
								    //
							 | 
						||
| 
								 | 
							
								    Op opCode = OpNop;  // All paths below need to set this
							 | 
						||
| 
								 | 
							
								    if (fetch) {
							 | 
						||
| 
								 | 
							
								        if (sparse)
							 | 
						||
| 
								 | 
							
								            opCode = OpImageSparseFetch;
							 | 
						||
| 
								 | 
							
								        else
							 | 
						||
| 
								 | 
							
								            opCode = OpImageFetch;
							 | 
						||
| 
								 | 
							
								#ifndef GLSLANG_WEB
							 | 
						||
| 
								 | 
							
								    } else if (parameters.granularity && parameters.coarse) {
							 | 
						||
| 
								 | 
							
								        opCode = OpImageSampleFootprintNV;
							 | 
						||
| 
								 | 
							
								    } else if (gather) {
							 | 
						||
| 
								 | 
							
								        if (parameters.Dref)
							 | 
						||
| 
								 | 
							
								            if (sparse)
							 | 
						||
| 
								 | 
							
								                opCode = OpImageSparseDrefGather;
							 | 
						||
| 
								 | 
							
								            else
							 | 
						||
| 
								 | 
							
								                opCode = OpImageDrefGather;
							 | 
						||
| 
								 | 
							
								        else
							 | 
						||
| 
								 | 
							
								            if (sparse)
							 | 
						||
| 
								 | 
							
								                opCode = OpImageSparseGather;
							 | 
						||
| 
								 | 
							
								            else
							 | 
						||
| 
								 | 
							
								                opCode = OpImageGather;
							 | 
						||
| 
								 | 
							
								#endif
							 | 
						||
| 
								 | 
							
								    } else if (explicitLod) {
							 | 
						||
| 
								 | 
							
								        if (parameters.Dref) {
							 | 
						||
| 
								 | 
							
								            if (proj)
							 | 
						||
| 
								 | 
							
								                if (sparse)
							 | 
						||
| 
								 | 
							
								                    opCode = OpImageSparseSampleProjDrefExplicitLod;
							 | 
						||
| 
								 | 
							
								                else
							 | 
						||
| 
								 | 
							
								                    opCode = OpImageSampleProjDrefExplicitLod;
							 | 
						||
| 
								 | 
							
								            else
							 | 
						||
| 
								 | 
							
								                if (sparse)
							 | 
						||
| 
								 | 
							
								                    opCode = OpImageSparseSampleDrefExplicitLod;
							 | 
						||
| 
								 | 
							
								                else
							 | 
						||
| 
								 | 
							
								                    opCode = OpImageSampleDrefExplicitLod;
							 | 
						||
| 
								 | 
							
								        } else {
							 | 
						||
| 
								 | 
							
								            if (proj)
							 | 
						||
| 
								 | 
							
								                if (sparse)
							 | 
						||
| 
								 | 
							
								                    opCode = OpImageSparseSampleProjExplicitLod;
							 | 
						||
| 
								 | 
							
								                else
							 | 
						||
| 
								 | 
							
								                    opCode = OpImageSampleProjExplicitLod;
							 | 
						||
| 
								 | 
							
								            else
							 | 
						||
| 
								 | 
							
								                if (sparse)
							 | 
						||
| 
								 | 
							
								                    opCode = OpImageSparseSampleExplicitLod;
							 | 
						||
| 
								 | 
							
								                else
							 | 
						||
| 
								 | 
							
								                    opCode = OpImageSampleExplicitLod;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								    } else {
							 | 
						||
| 
								 | 
							
								        if (parameters.Dref) {
							 | 
						||
| 
								 | 
							
								            if (proj)
							 | 
						||
| 
								 | 
							
								                if (sparse)
							 | 
						||
| 
								 | 
							
								                    opCode = OpImageSparseSampleProjDrefImplicitLod;
							 | 
						||
| 
								 | 
							
								                else
							 | 
						||
| 
								 | 
							
								                    opCode = OpImageSampleProjDrefImplicitLod;
							 | 
						||
| 
								 | 
							
								            else
							 | 
						||
| 
								 | 
							
								                if (sparse)
							 | 
						||
| 
								 | 
							
								                    opCode = OpImageSparseSampleDrefImplicitLod;
							 | 
						||
| 
								 | 
							
								                else
							 | 
						||
| 
								 | 
							
								                    opCode = OpImageSampleDrefImplicitLod;
							 | 
						||
| 
								 | 
							
								        } else {
							 | 
						||
| 
								 | 
							
								            if (proj)
							 | 
						||
| 
								 | 
							
								                if (sparse)
							 | 
						||
| 
								 | 
							
								                    opCode = OpImageSparseSampleProjImplicitLod;
							 | 
						||
| 
								 | 
							
								                else
							 | 
						||
| 
								 | 
							
								                    opCode = OpImageSampleProjImplicitLod;
							 | 
						||
| 
								 | 
							
								            else
							 | 
						||
| 
								 | 
							
								                if (sparse)
							 | 
						||
| 
								 | 
							
								                    opCode = OpImageSparseSampleImplicitLod;
							 | 
						||
| 
								 | 
							
								                else
							 | 
						||
| 
								 | 
							
								                    opCode = OpImageSampleImplicitLod;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // See if the result type is expecting a smeared result.
							 | 
						||
| 
								 | 
							
								    // This happens when a legacy shadow*() call is made, which
							 | 
						||
| 
								 | 
							
								    // gets a vec4 back instead of a float.
							 | 
						||
| 
								 | 
							
								    Id smearedType = resultType;
							 | 
						||
| 
								 | 
							
								    if (! isScalarType(resultType)) {
							 | 
						||
| 
								 | 
							
								        switch (opCode) {
							 | 
						||
| 
								 | 
							
								        case OpImageSampleDrefImplicitLod:
							 | 
						||
| 
								 | 
							
								        case OpImageSampleDrefExplicitLod:
							 | 
						||
| 
								 | 
							
								        case OpImageSampleProjDrefImplicitLod:
							 | 
						||
| 
								 | 
							
								        case OpImageSampleProjDrefExplicitLod:
							 | 
						||
| 
								 | 
							
								            resultType = getScalarTypeId(resultType);
							 | 
						||
| 
								 | 
							
								            break;
							 | 
						||
| 
								 | 
							
								        default:
							 | 
						||
| 
								 | 
							
								            break;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    Id typeId0 = 0;
							 | 
						||
| 
								 | 
							
								    Id typeId1 = 0;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if (sparse) {
							 | 
						||
| 
								 | 
							
								        typeId0 = resultType;
							 | 
						||
| 
								 | 
							
								        typeId1 = getDerefTypeId(parameters.texelOut);
							 | 
						||
| 
								 | 
							
								        resultType = makeStructResultType(typeId0, typeId1);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // Build the SPIR-V instruction
							 | 
						||
| 
								 | 
							
								    Instruction* textureInst = new Instruction(getUniqueId(), resultType, opCode);
							 | 
						||
| 
								 | 
							
								    for (int op = 0; op < optArgNum; ++op)
							 | 
						||
| 
								 | 
							
								        textureInst->addIdOperand(texArgs[op]);
							 | 
						||
| 
								 | 
							
								    if (optArgNum < numArgs)
							 | 
						||
| 
								 | 
							
								        textureInst->addImmediateOperand(texArgs[optArgNum]);
							 | 
						||
| 
								 | 
							
								    for (int op = optArgNum + 1; op < numArgs; ++op)
							 | 
						||
| 
								 | 
							
								        textureInst->addIdOperand(texArgs[op]);
							 | 
						||
| 
								 | 
							
								    setPrecision(textureInst->getResultId(), precision);
							 | 
						||
| 
								 | 
							
								    buildPoint->addInstruction(std::unique_ptr<Instruction>(textureInst));
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    Id resultId = textureInst->getResultId();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if (sparse) {
							 | 
						||
| 
								 | 
							
								        // set capability
							 | 
						||
| 
								 | 
							
								        addCapability(CapabilitySparseResidency);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        // Decode the return type that was a special structure
							 | 
						||
| 
								 | 
							
								        createStore(createCompositeExtract(resultId, typeId1, 1), parameters.texelOut);
							 | 
						||
| 
								 | 
							
								        resultId = createCompositeExtract(resultId, typeId0, 0);
							 | 
						||
| 
								 | 
							
								        setPrecision(resultId, precision);
							 | 
						||
| 
								 | 
							
								    } else {
							 | 
						||
| 
								 | 
							
								        // When a smear is needed, do it, as per what was computed
							 | 
						||
| 
								 | 
							
								        // above when resultType was changed to a scalar type.
							 | 
						||
| 
								 | 
							
								        if (resultType != smearedType)
							 | 
						||
| 
								 | 
							
								            resultId = smearScalar(precision, resultId, smearedType);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    return resultId;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// Comments in header
							 | 
						||
| 
								 | 
							
								Id Builder::createTextureQueryCall(Op opCode, const TextureParameters& parameters, bool isUnsignedResult)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    // Figure out the result type
							 | 
						||
| 
								 | 
							
								    Id resultType = 0;
							 | 
						||
| 
								 | 
							
								    switch (opCode) {
							 | 
						||
| 
								 | 
							
								    case OpImageQuerySize:
							 | 
						||
| 
								 | 
							
								    case OpImageQuerySizeLod:
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								        int numComponents = 0;
							 | 
						||
| 
								 | 
							
								        switch (getTypeDimensionality(getImageType(parameters.sampler))) {
							 | 
						||
| 
								 | 
							
								        case Dim1D:
							 | 
						||
| 
								 | 
							
								        case DimBuffer:
							 | 
						||
| 
								 | 
							
								            numComponents = 1;
							 | 
						||
| 
								 | 
							
								            break;
							 | 
						||
| 
								 | 
							
								        case Dim2D:
							 | 
						||
| 
								 | 
							
								        case DimCube:
							 | 
						||
| 
								 | 
							
								        case DimRect:
							 | 
						||
| 
								 | 
							
								        case DimSubpassData:
							 | 
						||
| 
								 | 
							
								            numComponents = 2;
							 | 
						||
| 
								 | 
							
								            break;
							 | 
						||
| 
								 | 
							
								        case Dim3D:
							 | 
						||
| 
								 | 
							
								            numComponents = 3;
							 | 
						||
| 
								 | 
							
								            break;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        default:
							 | 
						||
| 
								 | 
							
								            assert(0);
							 | 
						||
| 
								 | 
							
								            break;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        if (isArrayedImageType(getImageType(parameters.sampler)))
							 | 
						||
| 
								 | 
							
								            ++numComponents;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        Id intType = isUnsignedResult ? makeUintType(32) : makeIntType(32);
							 | 
						||
| 
								 | 
							
								        if (numComponents == 1)
							 | 
						||
| 
								 | 
							
								            resultType = intType;
							 | 
						||
| 
								 | 
							
								        else
							 | 
						||
| 
								 | 
							
								            resultType = makeVectorType(intType, numComponents);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        break;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    case OpImageQueryLod:
							 | 
						||
| 
								 | 
							
								        resultType = makeVectorType(getScalarTypeId(getTypeId(parameters.coords)), 2);
							 | 
						||
| 
								 | 
							
								        break;
							 | 
						||
| 
								 | 
							
								    case OpImageQueryLevels:
							 | 
						||
| 
								 | 
							
								    case OpImageQuerySamples:
							 | 
						||
| 
								 | 
							
								        resultType = isUnsignedResult ? makeUintType(32) : makeIntType(32);
							 | 
						||
| 
								 | 
							
								        break;
							 | 
						||
| 
								 | 
							
								    default:
							 | 
						||
| 
								 | 
							
								        assert(0);
							 | 
						||
| 
								 | 
							
								        break;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    Instruction* query = new Instruction(getUniqueId(), resultType, opCode);
							 | 
						||
| 
								 | 
							
								    query->addIdOperand(parameters.sampler);
							 | 
						||
| 
								 | 
							
								    if (parameters.coords)
							 | 
						||
| 
								 | 
							
								        query->addIdOperand(parameters.coords);
							 | 
						||
| 
								 | 
							
								    if (parameters.lod)
							 | 
						||
| 
								 | 
							
								        query->addIdOperand(parameters.lod);
							 | 
						||
| 
								 | 
							
								    buildPoint->addInstruction(std::unique_ptr<Instruction>(query));
							 | 
						||
| 
								 | 
							
								    addCapability(CapabilityImageQuery);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    return query->getResultId();
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// External comments in header.
							 | 
						||
| 
								 | 
							
								// Operates recursively to visit the composite's hierarchy.
							 | 
						||
| 
								 | 
							
								Id Builder::createCompositeCompare(Decoration precision, Id value1, Id value2, bool equal)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    Id boolType = makeBoolType();
							 | 
						||
| 
								 | 
							
								    Id valueType = getTypeId(value1);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    Id resultId = NoResult;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    int numConstituents = getNumTypeConstituents(valueType);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // Scalars and Vectors
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if (isScalarType(valueType) || isVectorType(valueType)) {
							 | 
						||
| 
								 | 
							
								        assert(valueType == getTypeId(value2));
							 | 
						||
| 
								 | 
							
								        // These just need a single comparison, just have
							 | 
						||
| 
								 | 
							
								        // to figure out what it is.
							 | 
						||
| 
								 | 
							
								        Op op;
							 | 
						||
| 
								 | 
							
								        switch (getMostBasicTypeClass(valueType)) {
							 | 
						||
| 
								 | 
							
								        case OpTypeFloat:
							 | 
						||
| 
								 | 
							
								            op = equal ? OpFOrdEqual : OpFOrdNotEqual;
							 | 
						||
| 
								 | 
							
								            break;
							 | 
						||
| 
								 | 
							
								        case OpTypeInt:
							 | 
						||
| 
								 | 
							
								        default:
							 | 
						||
| 
								 | 
							
								            op = equal ? OpIEqual : OpINotEqual;
							 | 
						||
| 
								 | 
							
								            break;
							 | 
						||
| 
								 | 
							
								        case OpTypeBool:
							 | 
						||
| 
								 | 
							
								            op = equal ? OpLogicalEqual : OpLogicalNotEqual;
							 | 
						||
| 
								 | 
							
								            precision = NoPrecision;
							 | 
						||
| 
								 | 
							
								            break;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        if (isScalarType(valueType)) {
							 | 
						||
| 
								 | 
							
								            // scalar
							 | 
						||
| 
								 | 
							
								            resultId = createBinOp(op, boolType, value1, value2);
							 | 
						||
| 
								 | 
							
								        } else {
							 | 
						||
| 
								 | 
							
								            // vector
							 | 
						||
| 
								 | 
							
								            resultId = createBinOp(op, makeVectorType(boolType, numConstituents), value1, value2);
							 | 
						||
| 
								 | 
							
								            setPrecision(resultId, precision);
							 | 
						||
| 
								 | 
							
								            // reduce vector compares...
							 | 
						||
| 
								 | 
							
								            resultId = createUnaryOp(equal ? OpAll : OpAny, boolType, resultId);
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        return setPrecision(resultId, precision);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // Only structs, arrays, and matrices should be left.
							 | 
						||
| 
								 | 
							
								    // They share in common the reduction operation across their constituents.
							 | 
						||
| 
								 | 
							
								    assert(isAggregateType(valueType) || isMatrixType(valueType));
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // Compare each pair of constituents
							 | 
						||
| 
								 | 
							
								    for (int constituent = 0; constituent < numConstituents; ++constituent) {
							 | 
						||
| 
								 | 
							
								        std::vector<unsigned> indexes(1, constituent);
							 | 
						||
| 
								 | 
							
								        Id constituentType1 = getContainedTypeId(getTypeId(value1), constituent);
							 | 
						||
| 
								 | 
							
								        Id constituentType2 = getContainedTypeId(getTypeId(value2), constituent);
							 | 
						||
| 
								 | 
							
								        Id constituent1 = createCompositeExtract(value1, constituentType1, indexes);
							 | 
						||
| 
								 | 
							
								        Id constituent2 = createCompositeExtract(value2, constituentType2, indexes);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        Id subResultId = createCompositeCompare(precision, constituent1, constituent2, equal);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        if (constituent == 0)
							 | 
						||
| 
								 | 
							
								            resultId = subResultId;
							 | 
						||
| 
								 | 
							
								        else
							 | 
						||
| 
								 | 
							
								            resultId = setPrecision(createBinOp(equal ? OpLogicalAnd : OpLogicalOr, boolType, resultId, subResultId),
							 | 
						||
| 
								 | 
							
								                                    precision);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    return resultId;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// OpCompositeConstruct
							 | 
						||
| 
								 | 
							
								Id Builder::createCompositeConstruct(Id typeId, const std::vector<Id>& constituents)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    assert(isAggregateType(typeId) || (getNumTypeConstituents(typeId) > 1 &&
							 | 
						||
| 
								 | 
							
								           getNumTypeConstituents(typeId) == (int)constituents.size()));
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if (generatingOpCodeForSpecConst) {
							 | 
						||
| 
								 | 
							
								        // Sometime, even in spec-constant-op mode, the constant composite to be
							 | 
						||
| 
								 | 
							
								        // constructed may not be a specialization constant.
							 | 
						||
| 
								 | 
							
								        // e.g.:
							 | 
						||
| 
								 | 
							
								        //  const mat2 m2 = mat2(a_spec_const, a_front_end_const, another_front_end_const, third_front_end_const);
							 | 
						||
| 
								 | 
							
								        // The first column vector should be a spec constant one, as a_spec_const is a spec constant.
							 | 
						||
| 
								 | 
							
								        // The second column vector should NOT be spec constant, as it does not contain any spec constants.
							 | 
						||
| 
								 | 
							
								        // To handle such cases, we check the constituents of the constant vector to determine whether this
							 | 
						||
| 
								 | 
							
								        // vector should be created as a spec constant.
							 | 
						||
| 
								 | 
							
								        return makeCompositeConstant(typeId, constituents,
							 | 
						||
| 
								 | 
							
								                                     std::any_of(constituents.begin(), constituents.end(),
							 | 
						||
| 
								 | 
							
								                                                 [&](spv::Id id) { return isSpecConstant(id); }));
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    Instruction* op = new Instruction(getUniqueId(), typeId, OpCompositeConstruct);
							 | 
						||
| 
								 | 
							
								    for (int c = 0; c < (int)constituents.size(); ++c)
							 | 
						||
| 
								 | 
							
								        op->addIdOperand(constituents[c]);
							 | 
						||
| 
								 | 
							
								    buildPoint->addInstruction(std::unique_ptr<Instruction>(op));
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    return op->getResultId();
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// Vector or scalar constructor
							 | 
						||
| 
								 | 
							
								Id Builder::createConstructor(Decoration precision, const std::vector<Id>& sources, Id resultTypeId)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    Id result = NoResult;
							 | 
						||
| 
								 | 
							
								    unsigned int numTargetComponents = getNumTypeComponents(resultTypeId);
							 | 
						||
| 
								 | 
							
								    unsigned int targetComponent = 0;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // Special case: when calling a vector constructor with a single scalar
							 | 
						||
| 
								 | 
							
								    // argument, smear the scalar
							 | 
						||
| 
								 | 
							
								    if (sources.size() == 1 && isScalar(sources[0]) && numTargetComponents > 1)
							 | 
						||
| 
								 | 
							
								        return smearScalar(precision, sources[0], resultTypeId);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // accumulate the arguments for OpCompositeConstruct
							 | 
						||
| 
								 | 
							
								    std::vector<Id> constituents;
							 | 
						||
| 
								 | 
							
								    Id scalarTypeId = getScalarTypeId(resultTypeId);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // lambda to store the result of visiting an argument component
							 | 
						||
| 
								 | 
							
								    const auto latchResult = [&](Id comp) {
							 | 
						||
| 
								 | 
							
								        if (numTargetComponents > 1)
							 | 
						||
| 
								 | 
							
								            constituents.push_back(comp);
							 | 
						||
| 
								 | 
							
								        else
							 | 
						||
| 
								 | 
							
								            result = comp;
							 | 
						||
| 
								 | 
							
								        ++targetComponent;
							 | 
						||
| 
								 | 
							
								    };
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // lambda to visit a vector argument's components
							 | 
						||
| 
								 | 
							
								    const auto accumulateVectorConstituents = [&](Id sourceArg) {
							 | 
						||
| 
								 | 
							
								        unsigned int sourceSize = getNumComponents(sourceArg);
							 | 
						||
| 
								 | 
							
								        unsigned int sourcesToUse = sourceSize;
							 | 
						||
| 
								 | 
							
								        if (sourcesToUse + targetComponent > numTargetComponents)
							 | 
						||
| 
								 | 
							
								            sourcesToUse = numTargetComponents - targetComponent;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        for (unsigned int s = 0; s < sourcesToUse; ++s) {
							 | 
						||
| 
								 | 
							
								            std::vector<unsigned> swiz;
							 | 
						||
| 
								 | 
							
								            swiz.push_back(s);
							 | 
						||
| 
								 | 
							
								            latchResult(createRvalueSwizzle(precision, scalarTypeId, sourceArg, swiz));
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								    };
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // lambda to visit a matrix argument's components
							 | 
						||
| 
								 | 
							
								    const auto accumulateMatrixConstituents = [&](Id sourceArg) {
							 | 
						||
| 
								 | 
							
								        unsigned int sourceSize = getNumColumns(sourceArg) * getNumRows(sourceArg);
							 | 
						||
| 
								 | 
							
								        unsigned int sourcesToUse = sourceSize;
							 | 
						||
| 
								 | 
							
								        if (sourcesToUse + targetComponent > numTargetComponents)
							 | 
						||
| 
								 | 
							
								            sourcesToUse = numTargetComponents - targetComponent;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        int col = 0;
							 | 
						||
| 
								 | 
							
								        int row = 0;
							 | 
						||
| 
								 | 
							
								        for (unsigned int s = 0; s < sourcesToUse; ++s) {
							 | 
						||
| 
								 | 
							
								            if (row >= getNumRows(sourceArg)) {
							 | 
						||
| 
								 | 
							
								                row = 0;
							 | 
						||
| 
								 | 
							
								                col++;
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								            std::vector<Id> indexes;
							 | 
						||
| 
								 | 
							
								            indexes.push_back(col);
							 | 
						||
| 
								 | 
							
								            indexes.push_back(row);
							 | 
						||
| 
								 | 
							
								            latchResult(createCompositeExtract(sourceArg, scalarTypeId, indexes));
							 | 
						||
| 
								 | 
							
								            row++;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								    };
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // Go through the source arguments, each one could have either
							 | 
						||
| 
								 | 
							
								    // a single or multiple components to contribute.
							 | 
						||
| 
								 | 
							
								    for (unsigned int i = 0; i < sources.size(); ++i) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        if (isScalar(sources[i]) || isPointer(sources[i]))
							 | 
						||
| 
								 | 
							
								            latchResult(sources[i]);
							 | 
						||
| 
								 | 
							
								        else if (isVector(sources[i]))
							 | 
						||
| 
								 | 
							
								            accumulateVectorConstituents(sources[i]);
							 | 
						||
| 
								 | 
							
								        else if (isMatrix(sources[i]))
							 | 
						||
| 
								 | 
							
								            accumulateMatrixConstituents(sources[i]);
							 | 
						||
| 
								 | 
							
								        else
							 | 
						||
| 
								 | 
							
								            assert(0);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        if (targetComponent >= numTargetComponents)
							 | 
						||
| 
								 | 
							
								            break;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // If the result is a vector, make it from the gathered constituents.
							 | 
						||
| 
								 | 
							
								    if (constituents.size() > 0)
							 | 
						||
| 
								 | 
							
								        result = createCompositeConstruct(resultTypeId, constituents);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    return setPrecision(result, precision);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// Comments in header
							 | 
						||
| 
								 | 
							
								Id Builder::createMatrixConstructor(Decoration precision, const std::vector<Id>& sources, Id resultTypeId)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    Id componentTypeId = getScalarTypeId(resultTypeId);
							 | 
						||
| 
								 | 
							
								    int numCols = getTypeNumColumns(resultTypeId);
							 | 
						||
| 
								 | 
							
								    int numRows = getTypeNumRows(resultTypeId);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    Instruction* instr = module.getInstruction(componentTypeId);
							 | 
						||
| 
								 | 
							
								#ifdef GLSLANG_WEB
							 | 
						||
| 
								 | 
							
								    const unsigned bitCount = 32;
							 | 
						||
| 
								 | 
							
								    assert(bitCount == instr->getImmediateOperand(0));
							 | 
						||
| 
								 | 
							
								#else
							 | 
						||
| 
								 | 
							
								    const unsigned bitCount = instr->getImmediateOperand(0);
							 | 
						||
| 
								 | 
							
								#endif
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // Optimize matrix constructed from a bigger matrix
							 | 
						||
| 
								 | 
							
								    if (isMatrix(sources[0]) && getNumColumns(sources[0]) >= numCols && getNumRows(sources[0]) >= numRows) {
							 | 
						||
| 
								 | 
							
								        // To truncate the matrix to a smaller number of rows/columns, we need to:
							 | 
						||
| 
								 | 
							
								        // 1. For each column, extract the column and truncate it to the required size using shuffle
							 | 
						||
| 
								 | 
							
								        // 2. Assemble the resulting matrix from all columns
							 | 
						||
| 
								 | 
							
								        Id matrix = sources[0];
							 | 
						||
| 
								 | 
							
								        Id columnTypeId = getContainedTypeId(resultTypeId);
							 | 
						||
| 
								 | 
							
								        Id sourceColumnTypeId = getContainedTypeId(getTypeId(matrix));
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        std::vector<unsigned> channels;
							 | 
						||
| 
								 | 
							
								        for (int row = 0; row < numRows; ++row)
							 | 
						||
| 
								 | 
							
								            channels.push_back(row);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        std::vector<Id> matrixColumns;
							 | 
						||
| 
								 | 
							
								        for (int col = 0; col < numCols; ++col) {
							 | 
						||
| 
								 | 
							
								            std::vector<unsigned> indexes;
							 | 
						||
| 
								 | 
							
								            indexes.push_back(col);
							 | 
						||
| 
								 | 
							
								            Id colv = createCompositeExtract(matrix, sourceColumnTypeId, indexes);
							 | 
						||
| 
								 | 
							
								            setPrecision(colv, precision);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            if (numRows != getNumRows(matrix)) {
							 | 
						||
| 
								 | 
							
								                matrixColumns.push_back(createRvalueSwizzle(precision, columnTypeId, colv, channels));
							 | 
						||
| 
								 | 
							
								            } else {
							 | 
						||
| 
								 | 
							
								                matrixColumns.push_back(colv);
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        return setPrecision(createCompositeConstruct(resultTypeId, matrixColumns), precision);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // Otherwise, will use a two step process
							 | 
						||
| 
								 | 
							
								    // 1. make a compile-time 2D array of values
							 | 
						||
| 
								 | 
							
								    // 2. construct a matrix from that array
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // Step 1.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // initialize the array to the identity matrix
							 | 
						||
| 
								 | 
							
								    Id ids[maxMatrixSize][maxMatrixSize];
							 | 
						||
| 
								 | 
							
								    Id  one = (bitCount == 64 ? makeDoubleConstant(1.0) : makeFloatConstant(1.0));
							 | 
						||
| 
								 | 
							
								    Id zero = (bitCount == 64 ? makeDoubleConstant(0.0) : makeFloatConstant(0.0));
							 | 
						||
| 
								 | 
							
								    for (int col = 0; col < 4; ++col) {
							 | 
						||
| 
								 | 
							
								        for (int row = 0; row < 4; ++row) {
							 | 
						||
| 
								 | 
							
								            if (col == row)
							 | 
						||
| 
								 | 
							
								                ids[col][row] = one;
							 | 
						||
| 
								 | 
							
								            else
							 | 
						||
| 
								 | 
							
								                ids[col][row] = zero;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // modify components as dictated by the arguments
							 | 
						||
| 
								 | 
							
								    if (sources.size() == 1 && isScalar(sources[0])) {
							 | 
						||
| 
								 | 
							
								        // a single scalar; resets the diagonals
							 | 
						||
| 
								 | 
							
								        for (int col = 0; col < 4; ++col)
							 | 
						||
| 
								 | 
							
								            ids[col][col] = sources[0];
							 | 
						||
| 
								 | 
							
								    } else if (isMatrix(sources[0])) {
							 | 
						||
| 
								 | 
							
								        // constructing from another matrix; copy over the parts that exist in both the argument and constructee
							 | 
						||
| 
								 | 
							
								        Id matrix = sources[0];
							 | 
						||
| 
								 | 
							
								        int minCols = std::min(numCols, getNumColumns(matrix));
							 | 
						||
| 
								 | 
							
								        int minRows = std::min(numRows, getNumRows(matrix));
							 | 
						||
| 
								 | 
							
								        for (int col = 0; col < minCols; ++col) {
							 | 
						||
| 
								 | 
							
								            std::vector<unsigned> indexes;
							 | 
						||
| 
								 | 
							
								            indexes.push_back(col);
							 | 
						||
| 
								 | 
							
								            for (int row = 0; row < minRows; ++row) {
							 | 
						||
| 
								 | 
							
								                indexes.push_back(row);
							 | 
						||
| 
								 | 
							
								                ids[col][row] = createCompositeExtract(matrix, componentTypeId, indexes);
							 | 
						||
| 
								 | 
							
								                indexes.pop_back();
							 | 
						||
| 
								 | 
							
								                setPrecision(ids[col][row], precision);
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								    } else {
							 | 
						||
| 
								 | 
							
								        // fill in the matrix in column-major order with whatever argument components are available
							 | 
						||
| 
								 | 
							
								        int row = 0;
							 | 
						||
| 
								 | 
							
								        int col = 0;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        for (int arg = 0; arg < (int)sources.size(); ++arg) {
							 | 
						||
| 
								 | 
							
								            Id argComp = sources[arg];
							 | 
						||
| 
								 | 
							
								            for (int comp = 0; comp < getNumComponents(sources[arg]); ++comp) {
							 | 
						||
| 
								 | 
							
								                if (getNumComponents(sources[arg]) > 1) {
							 | 
						||
| 
								 | 
							
								                    argComp = createCompositeExtract(sources[arg], componentTypeId, comp);
							 | 
						||
| 
								 | 
							
								                    setPrecision(argComp, precision);
							 | 
						||
| 
								 | 
							
								                }
							 | 
						||
| 
								 | 
							
								                ids[col][row++] = argComp;
							 | 
						||
| 
								 | 
							
								                if (row == numRows) {
							 | 
						||
| 
								 | 
							
								                    row = 0;
							 | 
						||
| 
								 | 
							
								                    col++;
							 | 
						||
| 
								 | 
							
								                }
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // Step 2:  Construct a matrix from that array.
							 | 
						||
| 
								 | 
							
								    // First make the column vectors, then make the matrix.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // make the column vectors
							 | 
						||
| 
								 | 
							
								    Id columnTypeId = getContainedTypeId(resultTypeId);
							 | 
						||
| 
								 | 
							
								    std::vector<Id> matrixColumns;
							 | 
						||
| 
								 | 
							
								    for (int col = 0; col < numCols; ++col) {
							 | 
						||
| 
								 | 
							
								        std::vector<Id> vectorComponents;
							 | 
						||
| 
								 | 
							
								        for (int row = 0; row < numRows; ++row)
							 | 
						||
| 
								 | 
							
								            vectorComponents.push_back(ids[col][row]);
							 | 
						||
| 
								 | 
							
								        Id column = createCompositeConstruct(columnTypeId, vectorComponents);
							 | 
						||
| 
								 | 
							
								        setPrecision(column, precision);
							 | 
						||
| 
								 | 
							
								        matrixColumns.push_back(column);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // make the matrix
							 | 
						||
| 
								 | 
							
								    return setPrecision(createCompositeConstruct(resultTypeId, matrixColumns), precision);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// Comments in header
							 | 
						||
| 
								 | 
							
								Builder::If::If(Id cond, unsigned int ctrl, Builder& gb) :
							 | 
						||
| 
								 | 
							
								    builder(gb),
							 | 
						||
| 
								 | 
							
								    condition(cond),
							 | 
						||
| 
								 | 
							
								    control(ctrl),
							 | 
						||
| 
								 | 
							
								    elseBlock(0)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    function = &builder.getBuildPoint()->getParent();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // make the blocks, but only put the then-block into the function,
							 | 
						||
| 
								 | 
							
								    // the else-block and merge-block will be added later, in order, after
							 | 
						||
| 
								 | 
							
								    // earlier code is emitted
							 | 
						||
| 
								 | 
							
								    thenBlock = new Block(builder.getUniqueId(), *function);
							 | 
						||
| 
								 | 
							
								    mergeBlock = new Block(builder.getUniqueId(), *function);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // Save the current block, so that we can add in the flow control split when
							 | 
						||
| 
								 | 
							
								    // makeEndIf is called.
							 | 
						||
| 
								 | 
							
								    headerBlock = builder.getBuildPoint();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    function->addBlock(thenBlock);
							 | 
						||
| 
								 | 
							
								    builder.setBuildPoint(thenBlock);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// Comments in header
							 | 
						||
| 
								 | 
							
								void Builder::If::makeBeginElse()
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    // Close out the "then" by having it jump to the mergeBlock
							 | 
						||
| 
								 | 
							
								    builder.createBranch(mergeBlock);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // Make the first else block and add it to the function
							 | 
						||
| 
								 | 
							
								    elseBlock = new Block(builder.getUniqueId(), *function);
							 | 
						||
| 
								 | 
							
								    function->addBlock(elseBlock);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // Start building the else block
							 | 
						||
| 
								 | 
							
								    builder.setBuildPoint(elseBlock);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// Comments in header
							 | 
						||
| 
								 | 
							
								void Builder::If::makeEndIf()
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    // jump to the merge block
							 | 
						||
| 
								 | 
							
								    builder.createBranch(mergeBlock);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // Go back to the headerBlock and make the flow control split
							 | 
						||
| 
								 | 
							
								    builder.setBuildPoint(headerBlock);
							 | 
						||
| 
								 | 
							
								    builder.createSelectionMerge(mergeBlock, control);
							 | 
						||
| 
								 | 
							
								    if (elseBlock)
							 | 
						||
| 
								 | 
							
								        builder.createConditionalBranch(condition, thenBlock, elseBlock);
							 | 
						||
| 
								 | 
							
								    else
							 | 
						||
| 
								 | 
							
								        builder.createConditionalBranch(condition, thenBlock, mergeBlock);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // add the merge block to the function
							 | 
						||
| 
								 | 
							
								    function->addBlock(mergeBlock);
							 | 
						||
| 
								 | 
							
								    builder.setBuildPoint(mergeBlock);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// Comments in header
							 | 
						||
| 
								 | 
							
								void Builder::makeSwitch(Id selector, unsigned int control, int numSegments, const std::vector<int>& caseValues,
							 | 
						||
| 
								 | 
							
								                         const std::vector<int>& valueIndexToSegment, int defaultSegment,
							 | 
						||
| 
								 | 
							
								                         std::vector<Block*>& segmentBlocks)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    Function& function = buildPoint->getParent();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // make all the blocks
							 | 
						||
| 
								 | 
							
								    for (int s = 0; s < numSegments; ++s)
							 | 
						||
| 
								 | 
							
								        segmentBlocks.push_back(new Block(getUniqueId(), function));
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    Block* mergeBlock = new Block(getUniqueId(), function);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // make and insert the switch's selection-merge instruction
							 | 
						||
| 
								 | 
							
								    createSelectionMerge(mergeBlock, control);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // make the switch instruction
							 | 
						||
| 
								 | 
							
								    Instruction* switchInst = new Instruction(NoResult, NoType, OpSwitch);
							 | 
						||
| 
								 | 
							
								    switchInst->addIdOperand(selector);
							 | 
						||
| 
								 | 
							
								    auto defaultOrMerge = (defaultSegment >= 0) ? segmentBlocks[defaultSegment] : mergeBlock;
							 | 
						||
| 
								 | 
							
								    switchInst->addIdOperand(defaultOrMerge->getId());
							 | 
						||
| 
								 | 
							
								    defaultOrMerge->addPredecessor(buildPoint);
							 | 
						||
| 
								 | 
							
								    for (int i = 0; i < (int)caseValues.size(); ++i) {
							 | 
						||
| 
								 | 
							
								        switchInst->addImmediateOperand(caseValues[i]);
							 | 
						||
| 
								 | 
							
								        switchInst->addIdOperand(segmentBlocks[valueIndexToSegment[i]]->getId());
							 | 
						||
| 
								 | 
							
								        segmentBlocks[valueIndexToSegment[i]]->addPredecessor(buildPoint);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    buildPoint->addInstruction(std::unique_ptr<Instruction>(switchInst));
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // push the merge block
							 | 
						||
| 
								 | 
							
								    switchMerges.push(mergeBlock);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// Comments in header
							 | 
						||
| 
								 | 
							
								void Builder::addSwitchBreak()
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    // branch to the top of the merge block stack
							 | 
						||
| 
								 | 
							
								    createBranch(switchMerges.top());
							 | 
						||
| 
								 | 
							
								    createAndSetNoPredecessorBlock("post-switch-break");
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// Comments in header
							 | 
						||
| 
								 | 
							
								void Builder::nextSwitchSegment(std::vector<Block*>& segmentBlock, int nextSegment)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    int lastSegment = nextSegment - 1;
							 | 
						||
| 
								 | 
							
								    if (lastSegment >= 0) {
							 | 
						||
| 
								 | 
							
								        // Close out previous segment by jumping, if necessary, to next segment
							 | 
						||
| 
								 | 
							
								        if (! buildPoint->isTerminated())
							 | 
						||
| 
								 | 
							
								            createBranch(segmentBlock[nextSegment]);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    Block* block = segmentBlock[nextSegment];
							 | 
						||
| 
								 | 
							
								    block->getParent().addBlock(block);
							 | 
						||
| 
								 | 
							
								    setBuildPoint(block);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// Comments in header
							 | 
						||
| 
								 | 
							
								void Builder::endSwitch(std::vector<Block*>& /*segmentBlock*/)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    // Close out previous segment by jumping, if necessary, to next segment
							 | 
						||
| 
								 | 
							
								    if (! buildPoint->isTerminated())
							 | 
						||
| 
								 | 
							
								        addSwitchBreak();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    switchMerges.top()->getParent().addBlock(switchMerges.top());
							 | 
						||
| 
								 | 
							
								    setBuildPoint(switchMerges.top());
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    switchMerges.pop();
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Block& Builder::makeNewBlock()
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    Function& function = buildPoint->getParent();
							 | 
						||
| 
								 | 
							
								    auto block = new Block(getUniqueId(), function);
							 | 
						||
| 
								 | 
							
								    function.addBlock(block);
							 | 
						||
| 
								 | 
							
								    return *block;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Builder::LoopBlocks& Builder::makeNewLoop()
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    // This verbosity is needed to simultaneously get the same behavior
							 | 
						||
| 
								 | 
							
								    // everywhere (id's in the same order), have a syntax that works
							 | 
						||
| 
								 | 
							
								    // across lots of versions of C++, have no warnings from pedantic
							 | 
						||
| 
								 | 
							
								    // compilation modes, and leave the rest of the code alone.
							 | 
						||
| 
								 | 
							
								    Block& head            = makeNewBlock();
							 | 
						||
| 
								 | 
							
								    Block& body            = makeNewBlock();
							 | 
						||
| 
								 | 
							
								    Block& merge           = makeNewBlock();
							 | 
						||
| 
								 | 
							
								    Block& continue_target = makeNewBlock();
							 | 
						||
| 
								 | 
							
								    LoopBlocks blocks(head, body, merge, continue_target);
							 | 
						||
| 
								 | 
							
								    loops.push(blocks);
							 | 
						||
| 
								 | 
							
								    return loops.top();
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								void Builder::createLoopContinue()
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    createBranch(&loops.top().continue_target);
							 | 
						||
| 
								 | 
							
								    // Set up a block for dead code.
							 | 
						||
| 
								 | 
							
								    createAndSetNoPredecessorBlock("post-loop-continue");
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								void Builder::createLoopExit()
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    createBranch(&loops.top().merge);
							 | 
						||
| 
								 | 
							
								    // Set up a block for dead code.
							 | 
						||
| 
								 | 
							
								    createAndSetNoPredecessorBlock("post-loop-break");
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								void Builder::closeLoop()
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    loops.pop();
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								void Builder::clearAccessChain()
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    accessChain.base = NoResult;
							 | 
						||
| 
								 | 
							
								    accessChain.indexChain.clear();
							 | 
						||
| 
								 | 
							
								    accessChain.instr = NoResult;
							 | 
						||
| 
								 | 
							
								    accessChain.swizzle.clear();
							 | 
						||
| 
								 | 
							
								    accessChain.component = NoResult;
							 | 
						||
| 
								 | 
							
								    accessChain.preSwizzleBaseType = NoType;
							 | 
						||
| 
								 | 
							
								    accessChain.isRValue = false;
							 | 
						||
| 
								 | 
							
								    accessChain.coherentFlags.clear();
							 | 
						||
| 
								 | 
							
								    accessChain.alignment = 0;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// Comments in header
							 | 
						||
| 
								 | 
							
								void Builder::accessChainPushSwizzle(std::vector<unsigned>& swizzle, Id preSwizzleBaseType,
							 | 
						||
| 
								 | 
							
								    AccessChain::CoherentFlags coherentFlags, unsigned int alignment)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    accessChain.coherentFlags |= coherentFlags;
							 | 
						||
| 
								 | 
							
								    accessChain.alignment |= alignment;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // swizzles can be stacked in GLSL, but simplified to a single
							 | 
						||
| 
								 | 
							
								    // one here; the base type doesn't change
							 | 
						||
| 
								 | 
							
								    if (accessChain.preSwizzleBaseType == NoType)
							 | 
						||
| 
								 | 
							
								        accessChain.preSwizzleBaseType = preSwizzleBaseType;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // if needed, propagate the swizzle for the current access chain
							 | 
						||
| 
								 | 
							
								    if (accessChain.swizzle.size() > 0) {
							 | 
						||
| 
								 | 
							
								        std::vector<unsigned> oldSwizzle = accessChain.swizzle;
							 | 
						||
| 
								 | 
							
								        accessChain.swizzle.resize(0);
							 | 
						||
| 
								 | 
							
								        for (unsigned int i = 0; i < swizzle.size(); ++i) {
							 | 
						||
| 
								 | 
							
								            assert(swizzle[i] < oldSwizzle.size());
							 | 
						||
| 
								 | 
							
								            accessChain.swizzle.push_back(oldSwizzle[swizzle[i]]);
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								    } else
							 | 
						||
| 
								 | 
							
								        accessChain.swizzle = swizzle;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // determine if we need to track this swizzle anymore
							 | 
						||
| 
								 | 
							
								    simplifyAccessChainSwizzle();
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// Comments in header
							 | 
						||
| 
								 | 
							
								void Builder::accessChainStore(Id rvalue, spv::MemoryAccessMask memoryAccess, spv::Scope scope, unsigned int alignment)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    assert(accessChain.isRValue == false);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    transferAccessChainSwizzle(true);
							 | 
						||
| 
								 | 
							
								    Id base = collapseAccessChain();
							 | 
						||
| 
								 | 
							
								    Id source = rvalue;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // dynamic component should be gone
							 | 
						||
| 
								 | 
							
								    assert(accessChain.component == NoResult);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // If swizzle still exists, it is out-of-order or not full, we must load the target vector,
							 | 
						||
| 
								 | 
							
								    // extract and insert elements to perform writeMask and/or swizzle.
							 | 
						||
| 
								 | 
							
								    if (accessChain.swizzle.size() > 0) {
							 | 
						||
| 
								 | 
							
								        Id tempBaseId = createLoad(base);
							 | 
						||
| 
								 | 
							
								        source = createLvalueSwizzle(getTypeId(tempBaseId), tempBaseId, source, accessChain.swizzle);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // take LSB of alignment
							 | 
						||
| 
								 | 
							
								    alignment = alignment & ~(alignment & (alignment-1));
							 | 
						||
| 
								 | 
							
								    if (getStorageClass(base) == StorageClassPhysicalStorageBufferEXT) {
							 | 
						||
| 
								 | 
							
								        memoryAccess = (spv::MemoryAccessMask)(memoryAccess | spv::MemoryAccessAlignedMask);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    createStore(source, base, memoryAccess, scope, alignment);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// Comments in header
							 | 
						||
| 
								 | 
							
								Id Builder::accessChainLoad(Decoration precision, Decoration nonUniform, Id resultType,
							 | 
						||
| 
								 | 
							
								    spv::MemoryAccessMask memoryAccess, spv::Scope scope, unsigned int alignment)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    Id id;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if (accessChain.isRValue) {
							 | 
						||
| 
								 | 
							
								        // transfer access chain, but try to stay in registers
							 | 
						||
| 
								 | 
							
								        transferAccessChainSwizzle(false);
							 | 
						||
| 
								 | 
							
								        if (accessChain.indexChain.size() > 0) {
							 | 
						||
| 
								 | 
							
								            Id swizzleBase = accessChain.preSwizzleBaseType != NoType ? accessChain.preSwizzleBaseType : resultType;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            // if all the accesses are constants, we can use OpCompositeExtract
							 | 
						||
| 
								 | 
							
								            std::vector<unsigned> indexes;
							 | 
						||
| 
								 | 
							
								            bool constant = true;
							 | 
						||
| 
								 | 
							
								            for (int i = 0; i < (int)accessChain.indexChain.size(); ++i) {
							 | 
						||
| 
								 | 
							
								                if (isConstantScalar(accessChain.indexChain[i]))
							 | 
						||
| 
								 | 
							
								                    indexes.push_back(getConstantScalar(accessChain.indexChain[i]));
							 | 
						||
| 
								 | 
							
								                else {
							 | 
						||
| 
								 | 
							
								                    constant = false;
							 | 
						||
| 
								 | 
							
								                    break;
							 | 
						||
| 
								 | 
							
								                }
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            if (constant) {
							 | 
						||
| 
								 | 
							
								                id = createCompositeExtract(accessChain.base, swizzleBase, indexes);
							 | 
						||
| 
								 | 
							
								            } else {
							 | 
						||
| 
								 | 
							
								                Id lValue = NoResult;
							 | 
						||
| 
								 | 
							
								                if (spvVersion >= Spv_1_4) {
							 | 
						||
| 
								 | 
							
								                    // make a new function variable for this r-value, using an initializer,
							 | 
						||
| 
								 | 
							
								                    // and mark it as NonWritable so that downstream it can be detected as a lookup
							 | 
						||
| 
								 | 
							
								                    // table
							 | 
						||
| 
								 | 
							
								                    lValue = createVariable(StorageClassFunction, getTypeId(accessChain.base), "indexable",
							 | 
						||
| 
								 | 
							
								                        accessChain.base);
							 | 
						||
| 
								 | 
							
								                    addDecoration(lValue, DecorationNonWritable);
							 | 
						||
| 
								 | 
							
								                } else {
							 | 
						||
| 
								 | 
							
								                    lValue = createVariable(StorageClassFunction, getTypeId(accessChain.base), "indexable");
							 | 
						||
| 
								 | 
							
								                    // store into it
							 | 
						||
| 
								 | 
							
								                    createStore(accessChain.base, lValue);
							 | 
						||
| 
								 | 
							
								                }
							 | 
						||
| 
								 | 
							
								                // move base to the new variable
							 | 
						||
| 
								 | 
							
								                accessChain.base = lValue;
							 | 
						||
| 
								 | 
							
								                accessChain.isRValue = false;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                // load through the access chain
							 | 
						||
| 
								 | 
							
								                id = createLoad(collapseAccessChain());
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								            setPrecision(id, precision);
							 | 
						||
| 
								 | 
							
								        } else
							 | 
						||
| 
								 | 
							
								            id = accessChain.base;  // no precision, it was set when this was defined
							 | 
						||
| 
								 | 
							
								    } else {
							 | 
						||
| 
								 | 
							
								        transferAccessChainSwizzle(true);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        // take LSB of alignment
							 | 
						||
| 
								 | 
							
								        alignment = alignment & ~(alignment & (alignment-1));
							 | 
						||
| 
								 | 
							
								        if (getStorageClass(accessChain.base) == StorageClassPhysicalStorageBufferEXT) {
							 | 
						||
| 
								 | 
							
								            memoryAccess = (spv::MemoryAccessMask)(memoryAccess | spv::MemoryAccessAlignedMask);
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        // load through the access chain
							 | 
						||
| 
								 | 
							
								        id = collapseAccessChain();
							 | 
						||
| 
								 | 
							
								        // Apply nonuniform both to the access chain and the loaded value.
							 | 
						||
| 
								 | 
							
								        // Buffer accesses need the access chain decorated, and this is where
							 | 
						||
| 
								 | 
							
								        // loaded image types get decorated. TODO: This should maybe move to
							 | 
						||
| 
								 | 
							
								        // createImageTextureFunctionCall.
							 | 
						||
| 
								 | 
							
								        addDecoration(id, nonUniform);
							 | 
						||
| 
								 | 
							
								        id = createLoad(id, memoryAccess, scope, alignment);
							 | 
						||
| 
								 | 
							
								        setPrecision(id, precision);
							 | 
						||
| 
								 | 
							
								        addDecoration(id, nonUniform);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // Done, unless there are swizzles to do
							 | 
						||
| 
								 | 
							
								    if (accessChain.swizzle.size() == 0 && accessChain.component == NoResult)
							 | 
						||
| 
								 | 
							
								        return id;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // Do remaining swizzling
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // Do the basic swizzle
							 | 
						||
| 
								 | 
							
								    if (accessChain.swizzle.size() > 0) {
							 | 
						||
| 
								 | 
							
								        Id swizzledType = getScalarTypeId(getTypeId(id));
							 | 
						||
| 
								 | 
							
								        if (accessChain.swizzle.size() > 1)
							 | 
						||
| 
								 | 
							
								            swizzledType = makeVectorType(swizzledType, (int)accessChain.swizzle.size());
							 | 
						||
| 
								 | 
							
								        id = createRvalueSwizzle(precision, swizzledType, id, accessChain.swizzle);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // Do the dynamic component
							 | 
						||
| 
								 | 
							
								    if (accessChain.component != NoResult)
							 | 
						||
| 
								 | 
							
								        id = setPrecision(createVectorExtractDynamic(id, resultType, accessChain.component), precision);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    addDecoration(id, nonUniform);
							 | 
						||
| 
								 | 
							
								    return id;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Id Builder::accessChainGetLValue()
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    assert(accessChain.isRValue == false);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    transferAccessChainSwizzle(true);
							 | 
						||
| 
								 | 
							
								    Id lvalue = collapseAccessChain();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // If swizzle exists, it is out-of-order or not full, we must load the target vector,
							 | 
						||
| 
								 | 
							
								    // extract and insert elements to perform writeMask and/or swizzle.  This does not
							 | 
						||
| 
								 | 
							
								    // go with getting a direct l-value pointer.
							 | 
						||
| 
								 | 
							
								    assert(accessChain.swizzle.size() == 0);
							 | 
						||
| 
								 | 
							
								    assert(accessChain.component == NoResult);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    return lvalue;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// comment in header
							 | 
						||
| 
								 | 
							
								Id Builder::accessChainGetInferredType()
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    // anything to operate on?
							 | 
						||
| 
								 | 
							
								    if (accessChain.base == NoResult)
							 | 
						||
| 
								 | 
							
								        return NoType;
							 | 
						||
| 
								 | 
							
								    Id type = getTypeId(accessChain.base);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // do initial dereference
							 | 
						||
| 
								 | 
							
								    if (! accessChain.isRValue)
							 | 
						||
| 
								 | 
							
								        type = getContainedTypeId(type);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // dereference each index
							 | 
						||
| 
								 | 
							
								    for (auto it = accessChain.indexChain.cbegin(); it != accessChain.indexChain.cend(); ++it) {
							 | 
						||
| 
								 | 
							
								        if (isStructType(type))
							 | 
						||
| 
								 | 
							
								            type = getContainedTypeId(type, getConstantScalar(*it));
							 | 
						||
| 
								 | 
							
								        else
							 | 
						||
| 
								 | 
							
								            type = getContainedTypeId(type);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // dereference swizzle
							 | 
						||
| 
								 | 
							
								    if (accessChain.swizzle.size() == 1)
							 | 
						||
| 
								 | 
							
								        type = getContainedTypeId(type);
							 | 
						||
| 
								 | 
							
								    else if (accessChain.swizzle.size() > 1)
							 | 
						||
| 
								 | 
							
								        type = makeVectorType(getContainedTypeId(type), (int)accessChain.swizzle.size());
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // dereference component selection
							 | 
						||
| 
								 | 
							
								    if (accessChain.component)
							 | 
						||
| 
								 | 
							
								        type = getContainedTypeId(type);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    return type;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								void Builder::dump(std::vector<unsigned int>& out) const
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    // Header, before first instructions:
							 | 
						||
| 
								 | 
							
								    out.push_back(MagicNumber);
							 | 
						||
| 
								 | 
							
								    out.push_back(spvVersion);
							 | 
						||
| 
								 | 
							
								    out.push_back(builderNumber);
							 | 
						||
| 
								 | 
							
								    out.push_back(uniqueId + 1);
							 | 
						||
| 
								 | 
							
								    out.push_back(0);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // Capabilities
							 | 
						||
| 
								 | 
							
								    for (auto it = capabilities.cbegin(); it != capabilities.cend(); ++it) {
							 | 
						||
| 
								 | 
							
								        Instruction capInst(0, 0, OpCapability);
							 | 
						||
| 
								 | 
							
								        capInst.addImmediateOperand(*it);
							 | 
						||
| 
								 | 
							
								        capInst.dump(out);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    for (auto it = extensions.cbegin(); it != extensions.cend(); ++it) {
							 | 
						||
| 
								 | 
							
								        Instruction extInst(0, 0, OpExtension);
							 | 
						||
| 
								 | 
							
								        extInst.addStringOperand(it->c_str());
							 | 
						||
| 
								 | 
							
								        extInst.dump(out);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    dumpInstructions(out, imports);
							 | 
						||
| 
								 | 
							
								    Instruction memInst(0, 0, OpMemoryModel);
							 | 
						||
| 
								 | 
							
								    memInst.addImmediateOperand(addressModel);
							 | 
						||
| 
								 | 
							
								    memInst.addImmediateOperand(memoryModel);
							 | 
						||
| 
								 | 
							
								    memInst.dump(out);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // Instructions saved up while building:
							 | 
						||
| 
								 | 
							
								    dumpInstructions(out, entryPoints);
							 | 
						||
| 
								 | 
							
								    dumpInstructions(out, executionModes);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // Debug instructions
							 | 
						||
| 
								 | 
							
								    dumpInstructions(out, strings);
							 | 
						||
| 
								 | 
							
								    dumpSourceInstructions(out);
							 | 
						||
| 
								 | 
							
								    for (int e = 0; e < (int)sourceExtensions.size(); ++e) {
							 | 
						||
| 
								 | 
							
								        Instruction sourceExtInst(0, 0, OpSourceExtension);
							 | 
						||
| 
								 | 
							
								        sourceExtInst.addStringOperand(sourceExtensions[e]);
							 | 
						||
| 
								 | 
							
								        sourceExtInst.dump(out);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    dumpInstructions(out, names);
							 | 
						||
| 
								 | 
							
								    dumpModuleProcesses(out);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // Annotation instructions
							 | 
						||
| 
								 | 
							
								    dumpInstructions(out, decorations);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    dumpInstructions(out, constantsTypesGlobals);
							 | 
						||
| 
								 | 
							
								    dumpInstructions(out, externals);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // The functions
							 | 
						||
| 
								 | 
							
								    module.dump(out);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								// Protected methods.
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// Turn the described access chain in 'accessChain' into an instruction(s)
							 | 
						||
| 
								 | 
							
								// computing its address.  This *cannot* include complex swizzles, which must
							 | 
						||
| 
								 | 
							
								// be handled after this is called.
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								// Can generate code.
							 | 
						||
| 
								 | 
							
								Id Builder::collapseAccessChain()
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    assert(accessChain.isRValue == false);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // did we already emit an access chain for this?
							 | 
						||
| 
								 | 
							
								    if (accessChain.instr != NoResult)
							 | 
						||
| 
								 | 
							
								        return accessChain.instr;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // If we have a dynamic component, we can still transfer
							 | 
						||
| 
								 | 
							
								    // that into a final operand to the access chain.  We need to remap the
							 | 
						||
| 
								 | 
							
								    // dynamic component through the swizzle to get a new dynamic component to
							 | 
						||
| 
								 | 
							
								    // update.
							 | 
						||
| 
								 | 
							
								    //
							 | 
						||
| 
								 | 
							
								    // This was not done in transferAccessChainSwizzle() because it might
							 | 
						||
| 
								 | 
							
								    // generate code.
							 | 
						||
| 
								 | 
							
								    remapDynamicSwizzle();
							 | 
						||
| 
								 | 
							
								    if (accessChain.component != NoResult) {
							 | 
						||
| 
								 | 
							
								        // transfer the dynamic component to the access chain
							 | 
						||
| 
								 | 
							
								        accessChain.indexChain.push_back(accessChain.component);
							 | 
						||
| 
								 | 
							
								        accessChain.component = NoResult;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // note that non-trivial swizzling is left pending
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // do we have an access chain?
							 | 
						||
| 
								 | 
							
								    if (accessChain.indexChain.size() == 0)
							 | 
						||
| 
								 | 
							
								        return accessChain.base;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // emit the access chain
							 | 
						||
| 
								 | 
							
								    StorageClass storageClass = (StorageClass)module.getStorageClass(getTypeId(accessChain.base));
							 | 
						||
| 
								 | 
							
								    accessChain.instr = createAccessChain(storageClass, accessChain.base, accessChain.indexChain);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    return accessChain.instr;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// For a dynamic component selection of a swizzle.
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								// Turn the swizzle and dynamic component into just a dynamic component.
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								// Generates code.
							 | 
						||
| 
								 | 
							
								void Builder::remapDynamicSwizzle()
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    // do we have a swizzle to remap a dynamic component through?
							 | 
						||
| 
								 | 
							
								    if (accessChain.component != NoResult && accessChain.swizzle.size() > 1) {
							 | 
						||
| 
								 | 
							
								        // build a vector of the swizzle for the component to map into
							 | 
						||
| 
								 | 
							
								        std::vector<Id> components;
							 | 
						||
| 
								 | 
							
								        for (int c = 0; c < (int)accessChain.swizzle.size(); ++c)
							 | 
						||
| 
								 | 
							
								            components.push_back(makeUintConstant(accessChain.swizzle[c]));
							 | 
						||
| 
								 | 
							
								        Id mapType = makeVectorType(makeUintType(32), (int)accessChain.swizzle.size());
							 | 
						||
| 
								 | 
							
								        Id map = makeCompositeConstant(mapType, components);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        // use it
							 | 
						||
| 
								 | 
							
								        accessChain.component = createVectorExtractDynamic(map, makeUintType(32), accessChain.component);
							 | 
						||
| 
								 | 
							
								        accessChain.swizzle.clear();
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// clear out swizzle if it is redundant, that is reselecting the same components
							 | 
						||
| 
								 | 
							
								// that would be present without the swizzle.
							 | 
						||
| 
								 | 
							
								void Builder::simplifyAccessChainSwizzle()
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    // If the swizzle has fewer components than the vector, it is subsetting, and must stay
							 | 
						||
| 
								 | 
							
								    // to preserve that fact.
							 | 
						||
| 
								 | 
							
								    if (getNumTypeComponents(accessChain.preSwizzleBaseType) > (int)accessChain.swizzle.size())
							 | 
						||
| 
								 | 
							
								        return;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // if components are out of order, it is a swizzle
							 | 
						||
| 
								 | 
							
								    for (unsigned int i = 0; i < accessChain.swizzle.size(); ++i) {
							 | 
						||
| 
								 | 
							
								        if (i != accessChain.swizzle[i])
							 | 
						||
| 
								 | 
							
								            return;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // otherwise, there is no need to track this swizzle
							 | 
						||
| 
								 | 
							
								    accessChain.swizzle.clear();
							 | 
						||
| 
								 | 
							
								    if (accessChain.component == NoResult)
							 | 
						||
| 
								 | 
							
								        accessChain.preSwizzleBaseType = NoType;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// To the extent any swizzling can become part of the chain
							 | 
						||
| 
								 | 
							
								// of accesses instead of a post operation, make it so.
							 | 
						||
| 
								 | 
							
								// If 'dynamic' is true, include transferring the dynamic component,
							 | 
						||
| 
								 | 
							
								// otherwise, leave it pending.
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								// Does not generate code. just updates the access chain.
							 | 
						||
| 
								 | 
							
								void Builder::transferAccessChainSwizzle(bool dynamic)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    // non existent?
							 | 
						||
| 
								 | 
							
								    if (accessChain.swizzle.size() == 0 && accessChain.component == NoResult)
							 | 
						||
| 
								 | 
							
								        return;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // too complex?
							 | 
						||
| 
								 | 
							
								    // (this requires either a swizzle, or generating code for a dynamic component)
							 | 
						||
| 
								 | 
							
								    if (accessChain.swizzle.size() > 1)
							 | 
						||
| 
								 | 
							
								        return;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // single component, either in the swizzle and/or dynamic component
							 | 
						||
| 
								 | 
							
								    if (accessChain.swizzle.size() == 1) {
							 | 
						||
| 
								 | 
							
								        assert(accessChain.component == NoResult);
							 | 
						||
| 
								 | 
							
								        // handle static component selection
							 | 
						||
| 
								 | 
							
								        accessChain.indexChain.push_back(makeUintConstant(accessChain.swizzle.front()));
							 | 
						||
| 
								 | 
							
								        accessChain.swizzle.clear();
							 | 
						||
| 
								 | 
							
								        accessChain.preSwizzleBaseType = NoType;
							 | 
						||
| 
								 | 
							
								    } else if (dynamic && accessChain.component != NoResult) {
							 | 
						||
| 
								 | 
							
								        assert(accessChain.swizzle.size() == 0);
							 | 
						||
| 
								 | 
							
								        // handle dynamic component
							 | 
						||
| 
								 | 
							
								        accessChain.indexChain.push_back(accessChain.component);
							 | 
						||
| 
								 | 
							
								        accessChain.preSwizzleBaseType = NoType;
							 | 
						||
| 
								 | 
							
								        accessChain.component = NoResult;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// Utility method for creating a new block and setting the insert point to
							 | 
						||
| 
								 | 
							
								// be in it. This is useful for flow-control operations that need a "dummy"
							 | 
						||
| 
								 | 
							
								// block proceeding them (e.g. instructions after a discard, etc).
							 | 
						||
| 
								 | 
							
								void Builder::createAndSetNoPredecessorBlock(const char* /*name*/)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    Block* block = new Block(getUniqueId(), buildPoint->getParent());
							 | 
						||
| 
								 | 
							
								    block->setUnreachable();
							 | 
						||
| 
								 | 
							
								    buildPoint->getParent().addBlock(block);
							 | 
						||
| 
								 | 
							
								    setBuildPoint(block);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // if (name)
							 | 
						||
| 
								 | 
							
								    //    addName(block->getId(), name);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// Comments in header
							 | 
						||
| 
								 | 
							
								void Builder::createBranch(Block* block)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    Instruction* branch = new Instruction(OpBranch);
							 | 
						||
| 
								 | 
							
								    branch->addIdOperand(block->getId());
							 | 
						||
| 
								 | 
							
								    buildPoint->addInstruction(std::unique_ptr<Instruction>(branch));
							 | 
						||
| 
								 | 
							
								    block->addPredecessor(buildPoint);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								void Builder::createSelectionMerge(Block* mergeBlock, unsigned int control)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    Instruction* merge = new Instruction(OpSelectionMerge);
							 | 
						||
| 
								 | 
							
								    merge->addIdOperand(mergeBlock->getId());
							 | 
						||
| 
								 | 
							
								    merge->addImmediateOperand(control);
							 | 
						||
| 
								 | 
							
								    buildPoint->addInstruction(std::unique_ptr<Instruction>(merge));
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								void Builder::createLoopMerge(Block* mergeBlock, Block* continueBlock, unsigned int control,
							 | 
						||
| 
								 | 
							
								                              const std::vector<unsigned int>& operands)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    Instruction* merge = new Instruction(OpLoopMerge);
							 | 
						||
| 
								 | 
							
								    merge->addIdOperand(mergeBlock->getId());
							 | 
						||
| 
								 | 
							
								    merge->addIdOperand(continueBlock->getId());
							 | 
						||
| 
								 | 
							
								    merge->addImmediateOperand(control);
							 | 
						||
| 
								 | 
							
								    for (int op = 0; op < (int)operands.size(); ++op)
							 | 
						||
| 
								 | 
							
								        merge->addImmediateOperand(operands[op]);
							 | 
						||
| 
								 | 
							
								    buildPoint->addInstruction(std::unique_ptr<Instruction>(merge));
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								void Builder::createConditionalBranch(Id condition, Block* thenBlock, Block* elseBlock)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    Instruction* branch = new Instruction(OpBranchConditional);
							 | 
						||
| 
								 | 
							
								    branch->addIdOperand(condition);
							 | 
						||
| 
								 | 
							
								    branch->addIdOperand(thenBlock->getId());
							 | 
						||
| 
								 | 
							
								    branch->addIdOperand(elseBlock->getId());
							 | 
						||
| 
								 | 
							
								    buildPoint->addInstruction(std::unique_ptr<Instruction>(branch));
							 | 
						||
| 
								 | 
							
								    thenBlock->addPredecessor(buildPoint);
							 | 
						||
| 
								 | 
							
								    elseBlock->addPredecessor(buildPoint);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// OpSource
							 | 
						||
| 
								 | 
							
								// [OpSourceContinued]
							 | 
						||
| 
								 | 
							
								// ...
							 | 
						||
| 
								 | 
							
								void Builder::dumpSourceInstructions(const spv::Id fileId, const std::string& text,
							 | 
						||
| 
								 | 
							
								                                     std::vector<unsigned int>& out) const
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    const int maxWordCount = 0xFFFF;
							 | 
						||
| 
								 | 
							
								    const int opSourceWordCount = 4;
							 | 
						||
| 
								 | 
							
								    const int nonNullBytesPerInstruction = 4 * (maxWordCount - opSourceWordCount) - 1;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if (source != SourceLanguageUnknown) {
							 | 
						||
| 
								 | 
							
								        // OpSource Language Version File Source
							 | 
						||
| 
								 | 
							
								        Instruction sourceInst(NoResult, NoType, OpSource);
							 | 
						||
| 
								 | 
							
								        sourceInst.addImmediateOperand(source);
							 | 
						||
| 
								 | 
							
								        sourceInst.addImmediateOperand(sourceVersion);
							 | 
						||
| 
								 | 
							
								        // File operand
							 | 
						||
| 
								 | 
							
								        if (fileId != NoResult) {
							 | 
						||
| 
								 | 
							
								            sourceInst.addIdOperand(fileId);
							 | 
						||
| 
								 | 
							
								            // Source operand
							 | 
						||
| 
								 | 
							
								            if (text.size() > 0) {
							 | 
						||
| 
								 | 
							
								                int nextByte = 0;
							 | 
						||
| 
								 | 
							
								                std::string subString;
							 | 
						||
| 
								 | 
							
								                while ((int)text.size() - nextByte > 0) {
							 | 
						||
| 
								 | 
							
								                    subString = text.substr(nextByte, nonNullBytesPerInstruction);
							 | 
						||
| 
								 | 
							
								                    if (nextByte == 0) {
							 | 
						||
| 
								 | 
							
								                        // OpSource
							 | 
						||
| 
								 | 
							
								                        sourceInst.addStringOperand(subString.c_str());
							 | 
						||
| 
								 | 
							
								                        sourceInst.dump(out);
							 | 
						||
| 
								 | 
							
								                    } else {
							 | 
						||
| 
								 | 
							
								                        // OpSourcContinued
							 | 
						||
| 
								 | 
							
								                        Instruction sourceContinuedInst(OpSourceContinued);
							 | 
						||
| 
								 | 
							
								                        sourceContinuedInst.addStringOperand(subString.c_str());
							 | 
						||
| 
								 | 
							
								                        sourceContinuedInst.dump(out);
							 | 
						||
| 
								 | 
							
								                    }
							 | 
						||
| 
								 | 
							
								                    nextByte += nonNullBytesPerInstruction;
							 | 
						||
| 
								 | 
							
								                }
							 | 
						||
| 
								 | 
							
								            } else
							 | 
						||
| 
								 | 
							
								                sourceInst.dump(out);
							 | 
						||
| 
								 | 
							
								        } else
							 | 
						||
| 
								 | 
							
								            sourceInst.dump(out);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// Dump an OpSource[Continued] sequence for the source and every include file
							 | 
						||
| 
								 | 
							
								void Builder::dumpSourceInstructions(std::vector<unsigned int>& out) const
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    dumpSourceInstructions(sourceFileStringId, sourceText, out);
							 | 
						||
| 
								 | 
							
								    for (auto iItr = includeFiles.begin(); iItr != includeFiles.end(); ++iItr)
							 | 
						||
| 
								 | 
							
								        dumpSourceInstructions(iItr->first, *iItr->second, out);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								void Builder::dumpInstructions(std::vector<unsigned int>& out,
							 | 
						||
| 
								 | 
							
								    const std::vector<std::unique_ptr<Instruction> >& instructions) const
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    for (int i = 0; i < (int)instructions.size(); ++i) {
							 | 
						||
| 
								 | 
							
								        instructions[i]->dump(out);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								void Builder::dumpModuleProcesses(std::vector<unsigned int>& out) const
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    for (int i = 0; i < (int)moduleProcesses.size(); ++i) {
							 | 
						||
| 
								 | 
							
								        Instruction moduleProcessed(OpModuleProcessed);
							 | 
						||
| 
								 | 
							
								        moduleProcessed.addStringOperand(moduleProcesses[i]);
							 | 
						||
| 
								 | 
							
								        moduleProcessed.dump(out);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								}; // end spv namespace
							 |