duckstation

duckstation, but archived from the revision just before upstream changed it to a proprietary software project, this version is the libre one
git clone https://git.neptards.moe/u3shit/duckstation.git
Log | Files | Refs | README | LICENSE

effect_codegen_spirv.cpp (81201B)


      1 /*
      2  * Copyright (C) 2014 Patrick Mours
      3  * SPDX-License-Identifier: BSD-3-Clause
      4  */
      5 
      6 #include "effect_parser.hpp"
      7 #include "effect_codegen.hpp"
      8 #include <cassert>
      9 #include <cstring> // memcmp
     10 #include <algorithm> // std::find_if, std::max
     11 #include <unordered_set>
     12 
     13 // Use the C++ variant of the SPIR-V headers
     14 #include <spirv.hpp>
     15 namespace spv {
     16 #include <GLSL.std.450.h>
     17 }
     18 
     19 using namespace reshadefx;
     20 
     21 /// <summary>
     22 /// A single instruction in a SPIR-V module
     23 /// </summary>
     24 struct spirv_instruction
     25 {
     26 	spv::Op op;
     27 	spv::Id type;
     28 	spv::Id result;
     29 	std::vector<spv::Id> operands;
     30 
     31 	explicit spirv_instruction(spv::Op op = spv::OpNop) : op(op), type(0), result(0) {}
     32 	spirv_instruction(spv::Op op, spv::Id result) : op(op), type(result), result(0) {}
     33 	spirv_instruction(spv::Op op, spv::Id type, spv::Id result) : op(op), type(type), result(result) {}
     34 
     35 	/// <summary>
     36 	/// Add a single operand to the instruction.
     37 	/// </summary>
     38 	spirv_instruction &add(spv::Id operand)
     39 	{
     40 		operands.push_back(operand);
     41 		return *this;
     42 	}
     43 
     44 	/// <summary>
     45 	/// Add a range of operands to the instruction.
     46 	/// </summary>
     47 	template <typename It>
     48 	spirv_instruction &add(It begin, It end)
     49 	{
     50 		operands.insert(operands.end(), begin, end);
     51 		return *this;
     52 	}
     53 
     54 	/// <summary>
     55 	/// Add a null-terminated literal UTF-8 string to the instruction.
     56 	/// </summary>
     57 	spirv_instruction &add_string(const char *string)
     58 	{
     59 		uint32_t word;
     60 		do {
     61 			word = 0;
     62 			for (uint32_t i = 0; i < 4 && *string; ++i)
     63 				reinterpret_cast<uint8_t *>(&word)[i] = *string++;
     64 			add(word);
     65 		} while (*string || (word & 0xFF000000));
     66 		return *this;
     67 	}
     68 
     69 	/// <summary>
     70 	/// Write this instruction to a SPIR-V module.
     71 	/// </summary>
     72 	/// <param name="output">The output stream to append this instruction to.</param>
     73 	void write(std::vector<uint32_t> &output) const
     74 	{
     75 		// See https://www.khronos.org/registry/spir-v/specs/unified1/SPIRV.html
     76 		// 0             | Opcode: The 16 high-order bits are the WordCount of the instruction. The 16 low-order bits are the opcode enumerant.
     77 		// 1             | Optional instruction type <id>
     78 		// .             | Optional instruction Result <id>
     79 		// .             | Operand 1 (if needed)
     80 		// .             | Operand 2 (if needed)
     81 		// ...           | ...
     82 		// WordCount - 1 | Operand N (N is determined by WordCount minus the 1 to 3 words used for the opcode, instruction type <id>, and instruction Result <id>).
     83 
     84 		const uint32_t num_words = 1 + (type != 0) + (result != 0) + static_cast<uint32_t>(operands.size());
     85 		output.push_back((num_words << spv::WordCountShift) | op);
     86 
     87 		// Optional instruction type ID
     88 		if (type != 0)
     89 			output.push_back(type);
     90 
     91 		// Optional instruction result ID
     92 		if (result != 0)
     93 			output.push_back(result);
     94 
     95 		// Write out the operands
     96 		output.insert(output.end(), operands.begin(), operands.end());
     97 	}
     98 };
     99 
    100 /// <summary>
    101 /// A list of instructions forming a basic block in the SPIR-V module
    102 /// </summary>
    103 struct spirv_basic_block
    104 {
    105 	std::vector<spirv_instruction> instructions;
    106 
    107 	/// <summary>
    108 	/// Append another basic block the end of this one.
    109 	/// </summary>
    110 	void append(const spirv_basic_block &block)
    111 	{
    112 		instructions.insert(instructions.end(), block.instructions.begin(), block.instructions.end());
    113 	}
    114 };
    115 
    116 class codegen_spirv final : public codegen
    117 {
    118 public:
    119 	codegen_spirv(bool vulkan_semantics, bool debug_info, bool uniforms_to_spec_constants, bool enable_16bit_types, bool flip_vert_y)
    120 		: _debug_info(debug_info), _vulkan_semantics(vulkan_semantics), _uniforms_to_spec_constants(uniforms_to_spec_constants), _enable_16bit_types(enable_16bit_types), _flip_vert_y(flip_vert_y)
    121 	{
    122 		_glsl_ext = make_id();
    123 	}
    124 
    125 private:
    126 	struct type_lookup
    127 	{
    128 		reshadefx::type type;
    129 		bool is_ptr;
    130 		uint32_t array_stride;
    131 		std::pair<spv::StorageClass, spv::ImageFormat> storage;
    132 
    133 		friend bool operator==(const type_lookup &lhs, const type_lookup &rhs)
    134 		{
    135 			return lhs.type == rhs.type && lhs.is_ptr == rhs.is_ptr && lhs.array_stride == rhs.array_stride && lhs.storage == rhs.storage;
    136 		}
    137 	};
    138 	struct function_blocks
    139 	{
    140 		spirv_basic_block declaration;
    141 		spirv_basic_block variables;
    142 		spirv_basic_block definition;
    143 		type return_type;
    144 		std::vector<type> param_types;
    145 		bool is_entry_point = false;
    146 
    147 		friend bool operator==(const function_blocks &lhs, const function_blocks &rhs)
    148 		{
    149 			if (lhs.param_types.size() != rhs.param_types.size())
    150 				return false;
    151 			for (size_t i = 0; i < lhs.param_types.size(); ++i)
    152 				if (!(lhs.param_types[i] == rhs.param_types[i]))
    153 					return false;
    154 			return lhs.return_type == rhs.return_type;
    155 		}
    156 	};
    157 
    158 	spirv_basic_block _entries;
    159 	spirv_basic_block _execution_modes;
    160 	spirv_basic_block _debug_a;
    161 	spirv_basic_block _debug_b;
    162 	spirv_basic_block _annotations;
    163 	spirv_basic_block _types_and_constants;
    164 	spirv_basic_block _variables;
    165 
    166 	std::unordered_set<spv::Id> _spec_constants;
    167 	std::unordered_set<spv::Capability> _capabilities;
    168 	std::vector<std::pair<type_lookup, spv::Id>> _type_lookup;
    169 	std::vector<std::tuple<type, constant, spv::Id>> _constant_lookup;
    170 	std::vector<std::pair<function_blocks, spv::Id>> _function_type_lookup;
    171 	std::unordered_map<std::string, spv::Id> _string_lookup;
    172 	std::unordered_map<spv::Id, std::pair<spv::StorageClass, spv::ImageFormat>> _storage_lookup;
    173 	std::unordered_map<std::string, uint32_t> _semantic_to_location;
    174 
    175 	std::vector<function_blocks> _functions_blocks;
    176 	std::unordered_map<id, spirv_basic_block> _block_data;
    177 	spirv_basic_block *_current_block_data = nullptr;
    178 
    179 	bool _debug_info = false;
    180 	bool _vulkan_semantics = false;
    181 	bool _uniforms_to_spec_constants = false;
    182 	bool _enable_16bit_types = false;
    183 	bool _flip_vert_y = false;
    184 	id _glsl_ext = 0;
    185 	id _global_ubo_type = 0;
    186 	id _global_ubo_variable = 0;
    187 	std::vector<spv::Id> _global_ubo_types;
    188 	function_blocks *_current_function = nullptr;
    189 
    190 	inline void add_location(const location &loc, spirv_basic_block &block)
    191 	{
    192 		if (loc.source.empty() || !_debug_info)
    193 			return;
    194 
    195 		spv::Id file;
    196 
    197 		if (const auto it = _string_lookup.find(loc.source);
    198 			it != _string_lookup.end())
    199 			file = it->second;
    200 		else {
    201 			add_instruction(spv::OpString, 0, _debug_a, file)
    202 				.add_string(loc.source.c_str());
    203 			_string_lookup.emplace(loc.source, file);
    204 		}
    205 
    206 		// https://www.khronos.org/registry/spir-v/specs/unified1/SPIRV.html#OpLine
    207 		add_instruction_without_result(spv::OpLine, block)
    208 			.add(file)
    209 			.add(loc.line)
    210 			.add(loc.column);
    211 	}
    212 	inline spirv_instruction &add_instruction(spv::Op op, spv::Id type = 0)
    213 	{
    214 		assert(is_in_function() && is_in_block());
    215 		return add_instruction(op, type, *_current_block_data);
    216 	}
    217 	inline spirv_instruction &add_instruction(spv::Op op, spv::Id type, spirv_basic_block &block)
    218 	{
    219 		spirv_instruction &instruction = add_instruction_without_result(op, block);
    220 		instruction.type = type;
    221 		instruction.result = make_id();
    222 		return instruction;
    223 	}
    224 	inline spirv_instruction &add_instruction(spv::Op op, spv::Id type, spirv_basic_block &block, spv::Id &result)
    225 	{
    226 		spirv_instruction &instruction = add_instruction_without_result(op, block);
    227 		instruction.type = type;
    228 		instruction.result = result = make_id();
    229 		return instruction;
    230 	}
    231 	inline spirv_instruction &add_instruction_without_result(spv::Op op)
    232 	{
    233 		assert(is_in_function() && is_in_block());
    234 		return add_instruction_without_result(op, *_current_block_data);
    235 	}
    236 	inline spirv_instruction &add_instruction_without_result(spv::Op op, spirv_basic_block &block)
    237 	{
    238 		return block.instructions.emplace_back(op);
    239 	}
    240 
    241 	void write_result(module &module) override
    242 	{
    243 		// First initialize the UBO type now that all member types are known
    244 		if (_global_ubo_type != 0)
    245 		{
    246 			spirv_instruction &type_inst = add_instruction_without_result(spv::OpTypeStruct, _types_and_constants);
    247 			type_inst.add(_global_ubo_types.begin(), _global_ubo_types.end());
    248 			type_inst.result = _global_ubo_type;
    249 
    250 			spirv_instruction &variable_inst = add_instruction_without_result(spv::OpVariable, _variables);
    251 			variable_inst.add(spv::StorageClassUniform);
    252 			variable_inst.type = convert_type({ type::t_struct, 0, 0, type::q_uniform, 0, _global_ubo_type }, true, spv::StorageClassUniform);
    253 			variable_inst.result = _global_ubo_variable;
    254 
    255 			add_name(variable_inst.result, "$Globals");
    256 		}
    257 
    258 		module = std::move(_module);
    259 
    260 		std::vector<spv::Id> spirv;
    261 
    262 		// Write SPIRV header info
    263 		spirv.push_back(spv::MagicNumber);
    264 		spirv.push_back(0x10300); // Force SPIR-V 1.3
    265 		spirv.push_back(0u); // Generator magic number, see https://www.khronos.org/registry/spir-v/api/spir-v.xml
    266 		spirv.push_back(_next_id); // Maximum ID
    267 		spirv.push_back(0u); // Reserved for instruction schema
    268 
    269 		// All capabilities
    270 		spirv_instruction(spv::OpCapability)
    271 			.add(spv::CapabilityShader) // Implicitly declares the Matrix capability too
    272 			.write(spirv);
    273 
    274 		for (spv::Capability capability : _capabilities)
    275 			spirv_instruction(spv::OpCapability)
    276 				.add(capability)
    277 				.write(spirv);
    278 
    279 		// Optional extension instructions
    280 		spirv_instruction(spv::OpExtInstImport, _glsl_ext)
    281 			.add_string("GLSL.std.450") // Import GLSL extension
    282 			.write(spirv);
    283 
    284 		// Single required memory model instruction
    285 		spirv_instruction(spv::OpMemoryModel)
    286 			.add(spv::AddressingModelLogical)
    287 			.add(spv::MemoryModelGLSL450)
    288 			.write(spirv);
    289 
    290 		// All entry point declarations
    291 		for (const auto &node : _entries.instructions)
    292 			node.write(spirv);
    293 
    294 		// All execution mode declarations
    295 		for (const auto &node : _execution_modes.instructions)
    296 			node.write(spirv);
    297 
    298 		spirv_instruction(spv::OpSource)
    299 			.add(spv::SourceLanguageUnknown) // ReShade FX is not a reserved token at the moment
    300 			.add(0) // Language version, TODO: Maybe fill in ReShade version here?
    301 			.write(spirv);
    302 
    303 		if (_debug_info)
    304 		{
    305 			// All debug instructions
    306 			for (const auto &node : _debug_a.instructions)
    307 				node.write(spirv);
    308 			for (const auto &node : _debug_b.instructions)
    309 				node.write(spirv);
    310 		}
    311 
    312 		// All annotation instructions
    313 		for (const auto &node : _annotations.instructions)
    314 			node.write(spirv);
    315 
    316 		// All type declarations
    317 		for (const auto &node : _types_and_constants.instructions)
    318 			node.write(spirv);
    319 		for (const auto &node : _variables.instructions)
    320 			node.write(spirv);
    321 
    322 		// All function definitions
    323 		for (const auto &function : _functions_blocks)
    324 		{
    325 			if (function.definition.instructions.empty())
    326 				continue;
    327 
    328 			for (const auto &node : function.declaration.instructions)
    329 				node.write(spirv);
    330 
    331 			// Grab first label and move it in front of variable declarations
    332 			function.definition.instructions.front().write(spirv);
    333 			assert(function.definition.instructions.front().op == spv::OpLabel);
    334 
    335 			for (const auto &node : function.variables.instructions)
    336 				node.write(spirv);
    337 			for (auto it = function.definition.instructions.begin() + 1; it != function.definition.instructions.end(); ++it)
    338 				it->write(spirv);
    339 		}
    340 
    341 		module.code.assign(reinterpret_cast<const char *>(spirv.data()), reinterpret_cast<const char *>(spirv.data() + spirv.size()));
    342 	}
    343 
    344 	spv::Id convert_type(type info, bool is_ptr = false, spv::StorageClass storage = spv::StorageClassFunction, spv::ImageFormat format = spv::ImageFormatUnknown, uint32_t array_stride = 0)
    345 	{
    346 		assert(array_stride == 0 || info.is_array());
    347 
    348 		// The storage class is only relevant for pointers, so ignore it for other types during lookup
    349 		if (is_ptr == false)
    350 			storage = spv::StorageClassFunction;
    351 		// There cannot be sampler variables that are local to a function, so always assume uniform storage for them
    352 		if (info.is_object())
    353 			storage = spv::StorageClassUniformConstant;
    354 		else
    355 			assert(format == spv::ImageFormatUnknown);
    356 
    357 		if (info.is_sampler() || info.is_storage())
    358 			info.rows = info.cols = 1;
    359 
    360 		// Fall back to 32-bit types and use relaxed precision decoration instead if 16-bit types are not enabled
    361 		if (!_enable_16bit_types && info.is_numeric() && info.precision() < 32)
    362 			info.base = static_cast<type::datatype>(info.base + 1); // min16int -> int, min16uint -> uint, min16float -> float
    363 
    364 		const type_lookup lookup { info, is_ptr, array_stride, { storage, format } };
    365 
    366 		if (const auto it = std::find_if(_type_lookup.begin(), _type_lookup.end(),
    367 				[&lookup](const auto &lookup_it) { return lookup_it.first == lookup; });
    368 			it != _type_lookup.end())
    369 			return it->second;
    370 
    371 		spv::Id type, elem_type;
    372 		if (is_ptr)
    373 		{
    374 			elem_type = convert_type(info, false, storage, format, array_stride);
    375 
    376 			add_instruction(spv::OpTypePointer, 0, _types_and_constants, type)
    377 				.add(storage)
    378 				.add(elem_type);
    379 		}
    380 		else if (info.is_array())
    381 		{
    382 			auto elem_info = info;
    383 			elem_info.array_length = 0;
    384 
    385 			// Make sure we don't get any dynamic arrays here
    386 			assert(info.array_length > 0);
    387 
    388 			elem_type = convert_type(elem_info, false, storage, format);
    389 			const spv::Id array_length = emit_constant(info.array_length);
    390 
    391 			add_instruction(spv::OpTypeArray, 0, _types_and_constants, type)
    392 				.add(elem_type)
    393 				.add(array_length);
    394 
    395 			if (array_stride != 0)
    396 				add_decoration(type, spv::DecorationArrayStride, { array_stride });
    397 		}
    398 		else if (info.is_matrix())
    399 		{
    400 			// Convert MxN matrix to a SPIR-V matrix with M vectors with N elements
    401 			auto elem_info = info;
    402 			elem_info.rows = info.cols;
    403 			elem_info.cols = 1;
    404 
    405 			elem_type = convert_type(elem_info, false, storage, format);
    406 
    407 			// Matrix types with just one row are interpreted as if they were a vector type
    408 			if (info.rows == 1)
    409 				return elem_type;
    410 
    411 			add_instruction(spv::OpTypeMatrix, 0, _types_and_constants, type)
    412 				.add(elem_type)
    413 				.add(info.rows);
    414 		}
    415 		else if (info.is_vector())
    416 		{
    417 			auto elem_info = info;
    418 			elem_info.rows = 1;
    419 			elem_info.cols = 1;
    420 
    421 			elem_type = convert_type(elem_info, false, storage, format);
    422 
    423 			add_instruction(spv::OpTypeVector, 0, _types_and_constants, type)
    424 				.add(elem_type)
    425 				.add(info.rows);
    426 		}
    427 		else
    428 		{
    429 			switch (info.base)
    430 			{
    431 			case type::t_void:
    432 				assert(info.rows == 0 && info.cols == 0);
    433 				add_instruction(spv::OpTypeVoid, 0, _types_and_constants, type);
    434 				break;
    435 			case type::t_bool:
    436 				assert(info.rows == 1 && info.cols == 1);
    437 				add_instruction(spv::OpTypeBool, 0, _types_and_constants, type);
    438 				break;
    439 			case type::t_min16int:
    440 				assert(_enable_16bit_types && info.rows == 1 && info.cols == 1);
    441 				add_capability(spv::CapabilityInt16);
    442 				if (storage == spv::StorageClassInput || storage == spv::StorageClassOutput)
    443 					add_capability(spv::CapabilityStorageInputOutput16);
    444 				add_instruction(spv::OpTypeInt, 0, _types_and_constants, type)
    445 					.add(16) // Width
    446 					.add(1); // Signedness
    447 				break;
    448 			case type::t_int:
    449 				assert(info.rows == 1 && info.cols == 1);
    450 				add_instruction(spv::OpTypeInt, 0, _types_and_constants, type)
    451 					.add(32) // Width
    452 					.add(1); // Signedness
    453 				break;
    454 			case type::t_min16uint:
    455 				assert(_enable_16bit_types && info.rows == 1 && info.cols == 1);
    456 				add_capability(spv::CapabilityInt16);
    457 				if (storage == spv::StorageClassInput || storage == spv::StorageClassOutput)
    458 					add_capability(spv::CapabilityStorageInputOutput16);
    459 				add_instruction(spv::OpTypeInt, 0, _types_and_constants, type)
    460 					.add(16) // Width
    461 					.add(0); // Signedness
    462 				break;
    463 			case type::t_uint:
    464 				assert(info.rows == 1 && info.cols == 1);
    465 				add_instruction(spv::OpTypeInt, 0, _types_and_constants, type)
    466 					.add(32) // Width
    467 					.add(0); // Signedness
    468 				break;
    469 			case type::t_min16float:
    470 				assert(_enable_16bit_types && info.rows == 1 && info.cols == 1);
    471 				add_capability(spv::CapabilityFloat16);
    472 				if (storage == spv::StorageClassInput || storage == spv::StorageClassOutput)
    473 					add_capability(spv::CapabilityStorageInputOutput16);
    474 				add_instruction(spv::OpTypeFloat, 0, _types_and_constants, type)
    475 					.add(16); // Width
    476 				break;
    477 			case type::t_float:
    478 				assert(info.rows == 1 && info.cols == 1);
    479 				add_instruction(spv::OpTypeFloat, 0, _types_and_constants, type)
    480 					.add(32); // Width
    481 				break;
    482 			case type::t_struct:
    483 				assert(info.rows == 0 && info.cols == 0 && info.definition != 0);
    484 				type = info.definition;
    485 				break;
    486 			case type::t_sampler1d_int:
    487 			case type::t_sampler1d_uint:
    488 			case type::t_sampler1d_float:
    489 				add_capability(spv::CapabilitySampled1D);
    490 				[[fallthrough]];
    491 			case type::t_sampler2d_int:
    492 			case type::t_sampler2d_uint:
    493 			case type::t_sampler2d_float:
    494 			case type::t_sampler3d_int:
    495 			case type::t_sampler3d_uint:
    496 			case type::t_sampler3d_float:
    497 				elem_type = convert_image_type(info, format);
    498 				add_instruction(spv::OpTypeSampledImage, 0, _types_and_constants, type)
    499 					.add(elem_type);
    500 				break;
    501 			case type::t_storage1d_int:
    502 			case type::t_storage1d_uint:
    503 			case type::t_storage1d_float:
    504 				add_capability(spv::CapabilityImage1D);
    505 				[[fallthrough]];
    506 			case type::t_storage2d_int:
    507 			case type::t_storage2d_uint:
    508 			case type::t_storage2d_float:
    509 			case type::t_storage3d_int:
    510 			case type::t_storage3d_uint:
    511 			case type::t_storage3d_float:
    512 				// No format specified for the storage image
    513 				if (format == spv::ImageFormatUnknown)
    514 					add_capability(spv::CapabilityStorageImageWriteWithoutFormat);
    515 				return convert_image_type(info, format);
    516 			default:
    517 				return assert(false), 0;
    518 			}
    519 		}
    520 
    521 		_type_lookup.push_back({ lookup, type });
    522 
    523 		return type;
    524 	}
    525 	spv::Id convert_type(const function_blocks &info)
    526 	{
    527 		if (const auto it = std::find_if(_function_type_lookup.begin(), _function_type_lookup.end(),
    528 				[&lookup = info](const auto &lookup_it) { return lookup_it.first == lookup; });
    529 			it != _function_type_lookup.end())
    530 			return it->second;
    531 
    532 		auto return_type = convert_type(info.return_type);
    533 		assert(return_type != 0);
    534 
    535 		std::vector<spv::Id> param_type_ids;
    536 		param_type_ids.reserve(info.param_types.size());
    537 		for (const type &param_type : info.param_types)
    538 			param_type_ids.push_back(convert_type(param_type, true));
    539 
    540 		spirv_instruction &inst = add_instruction(spv::OpTypeFunction, 0, _types_and_constants);
    541 		inst.add(return_type);
    542 		inst.add(param_type_ids.begin(), param_type_ids.end());
    543 
    544 		_function_type_lookup.push_back({ info, inst.result });;
    545 
    546 		return inst.result;
    547 	}
    548 	spv::Id convert_image_type(type info, spv::ImageFormat format = spv::ImageFormatUnknown)
    549 	{
    550 		type_lookup lookup { info, false, 0u, { spv::StorageClassUniformConstant, format } };
    551 
    552 		auto elem_info = info;
    553 		elem_info.rows = 1;
    554 		elem_info.cols = 1;
    555 
    556 		if (!info.is_numeric())
    557 		{
    558 			if ((info.is_integral() && info.is_signed()) || (format >= spv::ImageFormatRgba32i && format <= spv::ImageFormatR8i))
    559 				elem_info.base = type::t_int;
    560 			else if ((info.is_integral() && info.is_unsigned()) || (format >= spv::ImageFormatRgba32ui && format <= spv::ImageFormatR8ui))
    561 				elem_info.base = type::t_uint;
    562 			else
    563 				elem_info.base = type::t_float;
    564 		}
    565 
    566 		if (!info.is_storage())
    567 		{
    568 			lookup.type = elem_info;
    569 			lookup.type.base = static_cast<type::datatype>(type::t_texture1d + info.texture_dimension() - 1);
    570 			lookup.type.definition = static_cast<uint32_t>(elem_info.base);
    571 		}
    572 
    573 		if (const auto it = std::find_if(_type_lookup.begin(), _type_lookup.end(),
    574 				[&lookup](const auto &lookup_it) { return lookup_it.first == lookup; });
    575 			it != _type_lookup.end())
    576 			return it->second;
    577 
    578 		spv::Id type, elem_type = convert_type(elem_info, false, spv::StorageClassUniformConstant);
    579 
    580 		add_instruction(spv::OpTypeImage, 0, _types_and_constants, type)
    581 			.add(elem_type) // Sampled Type (always a scalar type)
    582 			.add(spv::Dim1D + info.texture_dimension() - 1)
    583 			.add(0) // Not a depth image
    584 			.add(0) // Not an array
    585 			.add(0) // Not multi-sampled
    586 			.add(info.is_storage() ? 2 : 1) // Used with a sampler or as storage
    587 			.add(format);
    588 
    589 		_type_lookup.push_back({ lookup, type });
    590 
    591 		return type;
    592 	}
    593 
    594 	uint32_t semantic_to_location(const std::string &semantic, uint32_t max_array_length = 1)
    595 	{
    596 		if (semantic.compare(0, 5, "COLOR") == 0)
    597 			return std::strtoul(semantic.c_str() + 5, nullptr, 10);
    598 		if (semantic.compare(0, 9, "SV_TARGET") == 0)
    599 			return std::strtoul(semantic.c_str() + 9, nullptr, 10);
    600 
    601 		if (const auto it = _semantic_to_location.find(semantic);
    602 			it != _semantic_to_location.end())
    603 			return it->second;
    604 
    605 		// Extract the semantic index from the semantic name (e.g. 2 for "TEXCOORD2")
    606 		size_t digit_index = semantic.size() - 1;
    607 		while (digit_index != 0 && semantic[digit_index] >= '0' && semantic[digit_index] <= '9')
    608 			digit_index--;
    609 		digit_index++;
    610 
    611 		const uint32_t semantic_digit = std::strtoul(semantic.c_str() + digit_index, nullptr, 10);
    612 		const std::string semantic_base = semantic.substr(0, digit_index);
    613 
    614 		uint32_t location = static_cast<uint32_t>(_semantic_to_location.size());
    615 
    616 		// Now create adjoining location indices for all possible semantic indices belonging to this semantic name
    617 		for (uint32_t a = 0; a < semantic_digit + max_array_length; ++a)
    618 		{
    619 			const auto insert = _semantic_to_location.emplace(semantic_base + std::to_string(a), location + a);
    620 			if (!insert.second)
    621 			{
    622 				assert(a == 0 || (insert.first->second - a) == location);
    623 
    624 				// Semantic was already created with a different location index, so need to remap to that
    625 				location = insert.first->second - a;
    626 			}
    627 		}
    628 
    629 		return location + semantic_digit;
    630 	}
    631 
    632 	const spv::BuiltIn semantic_to_builtin(const std::string &semantic, shader_type stype) const
    633 	{
    634 		if (semantic == "SV_POSITION")
    635 			return stype == shader_type::ps ? spv::BuiltInFragCoord : spv::BuiltInPosition;
    636 		if (semantic == "SV_POINTSIZE")
    637 			return spv::BuiltInPointSize;
    638 		if (semantic == "SV_DEPTH")
    639 			return spv::BuiltInFragDepth;
    640 		if (semantic == "SV_VERTEXID")
    641 			return _vulkan_semantics ? spv::BuiltInVertexIndex : spv::BuiltInVertexId;
    642 		if (semantic == "SV_ISFRONTFACE")
    643 			return spv::BuiltInFrontFacing;
    644 		if (semantic == "SV_GROUPID")
    645 			return spv::BuiltInWorkgroupId;
    646 		if (semantic == "SV_GROUPINDEX")
    647 			return spv::BuiltInLocalInvocationIndex;
    648 		if (semantic == "SV_GROUPTHREADID")
    649 			return spv::BuiltInLocalInvocationId;
    650 		if (semantic == "SV_DISPATCHTHREADID")
    651 			return spv::BuiltInGlobalInvocationId;
    652 		return spv::BuiltInMax;
    653 	}
    654 	const spv::ImageFormat format_to_image_format(texture_format format)
    655 	{
    656 		switch (format)
    657 		{
    658 		default:
    659 			assert(false);
    660 			[[fallthrough]];
    661 		case texture_format::unknown:
    662 			return spv::ImageFormatUnknown;
    663 		case texture_format::r8:
    664 			add_capability(spv::CapabilityStorageImageExtendedFormats);
    665 			return spv::ImageFormatR8;
    666 		case texture_format::r16:
    667 			add_capability(spv::CapabilityStorageImageExtendedFormats);
    668 			return spv::ImageFormatR16;
    669 		case texture_format::r16f:
    670 			add_capability(spv::CapabilityStorageImageExtendedFormats);
    671 			return spv::ImageFormatR16f;
    672 		case texture_format::r32i:
    673 			return spv::ImageFormatR32i;
    674 		case texture_format::r32u:
    675 			return spv::ImageFormatR32ui;
    676 		case texture_format::r32f:
    677 			return spv::ImageFormatR32f;
    678 		case texture_format::rg8:
    679 			add_capability(spv::CapabilityStorageImageExtendedFormats);
    680 			return spv::ImageFormatRg8;
    681 		case texture_format::rg16:
    682 			add_capability(spv::CapabilityStorageImageExtendedFormats);
    683 			return spv::ImageFormatRg16;
    684 		case texture_format::rg16f:
    685 			add_capability(spv::CapabilityStorageImageExtendedFormats);
    686 			return spv::ImageFormatRg16f;
    687 		case texture_format::rg32f:
    688 			add_capability(spv::CapabilityStorageImageExtendedFormats);
    689 			return spv::ImageFormatRg32f;
    690 		case texture_format::rgba8:
    691 			return spv::ImageFormatRgba8;
    692 		case texture_format::rgba16:
    693 			add_capability(spv::CapabilityStorageImageExtendedFormats);
    694 			return spv::ImageFormatRgba16;
    695 		case texture_format::rgba16f:
    696 			return spv::ImageFormatRgba16f;
    697 		case texture_format::rgba32f:
    698 			return spv::ImageFormatRgba32f;
    699 		case texture_format::rgb10a2:
    700 			add_capability(spv::CapabilityStorageImageExtendedFormats);
    701 			return spv::ImageFormatRgb10A2;
    702 		}
    703 	}
    704 
    705 	inline void add_name(id id, const char *name)
    706 	{
    707 		if (!_debug_info)
    708 			return;
    709 
    710 		assert(name != nullptr);
    711 		// https://www.khronos.org/registry/spir-v/specs/unified1/SPIRV.html#OpName
    712 		add_instruction_without_result(spv::OpName, _debug_b)
    713 			.add(id)
    714 			.add_string(name);
    715 	}
    716 	inline void add_builtin(id id, spv::BuiltIn builtin)
    717 	{
    718 		add_instruction_without_result(spv::OpDecorate, _annotations)
    719 			.add(id)
    720 			.add(spv::DecorationBuiltIn)
    721 			.add(builtin);
    722 	}
    723 	inline void add_decoration(id id, spv::Decoration decoration, std::initializer_list<uint32_t> values = {})
    724 	{
    725 		// https://www.khronos.org/registry/spir-v/specs/unified1/SPIRV.html#OpDecorate
    726 		add_instruction_without_result(spv::OpDecorate, _annotations)
    727 			.add(id)
    728 			.add(decoration)
    729 			.add(values.begin(), values.end());
    730 	}
    731 	inline void add_member_name(id id, uint32_t member_index, const char *name)
    732 	{
    733 		if (!_debug_info)
    734 			return;
    735 
    736 		assert(name != nullptr);
    737 		// https://www.khronos.org/registry/spir-v/specs/unified1/SPIRV.html#OpMemberName
    738 		add_instruction_without_result(spv::OpMemberName, _debug_b)
    739 			.add(id)
    740 			.add(member_index)
    741 			.add_string(name);
    742 	}
    743 	inline void add_member_builtin(id id, uint32_t member_index, spv::BuiltIn builtin)
    744 	{
    745 		add_instruction_without_result(spv::OpMemberDecorate, _annotations)
    746 			.add(id)
    747 			.add(member_index)
    748 			.add(spv::DecorationBuiltIn)
    749 			.add(builtin);
    750 	}
    751 	inline void add_member_decoration(id id, uint32_t member_index, spv::Decoration decoration, std::initializer_list<uint32_t> values = {})
    752 	{
    753 		// https://www.khronos.org/registry/spir-v/specs/unified1/SPIRV.html#OpMemberDecorate
    754 		add_instruction_without_result(spv::OpMemberDecorate, _annotations)
    755 			.add(id)
    756 			.add(member_index)
    757 			.add(decoration)
    758 			.add(values.begin(), values.end());
    759 	}
    760 	inline void add_capability(spv::Capability capability)
    761 	{
    762 		_capabilities.insert(capability);
    763 	}
    764 
    765 	id   define_struct(const location &loc, struct_info &info) override
    766 	{
    767 		// First define all member types to make sure they are declared before the struct type references them
    768 		std::vector<spv::Id> member_types;
    769 		member_types.reserve(info.member_list.size());
    770 		for (const struct_member_info &member : info.member_list)
    771 			member_types.push_back(convert_type(member.type));
    772 
    773 		// Afterwards define the actual struct type
    774 		add_location(loc, _types_and_constants);
    775 
    776 		add_instruction(spv::OpTypeStruct, 0, _types_and_constants, info.definition)
    777 			.add(member_types.begin(), member_types.end());
    778 
    779 		if (!info.unique_name.empty())
    780 			add_name(info.definition, info.unique_name.c_str());
    781 
    782 		for (uint32_t index = 0; index < info.member_list.size(); ++index)
    783 		{
    784 			const struct_member_info &member = info.member_list[index];
    785 
    786 			add_member_name(info.definition, index, member.name.c_str());
    787 
    788 			if (!_enable_16bit_types && member.type.is_numeric() && member.type.precision() < 32)
    789 				add_member_decoration(info.definition, index, spv::DecorationRelaxedPrecision);
    790 		}
    791 
    792 		_structs.push_back(info);
    793 
    794 		return info.definition;
    795 	}
    796 	id   define_texture(const location &, texture_info &info) override
    797 	{
    798 		info.id = make_id(); // Need to create an unique ID here too, so that the symbol lookup for textures works
    799 		info.binding = ~0u;
    800 
    801 		_module.textures.push_back(info);
    802 
    803 		return info.id;
    804 	}
    805 	id   define_sampler(const location &loc, const texture_info &, sampler_info &info) override
    806 	{
    807 		info.id = define_variable(loc, info.type, info.unique_name.c_str(), spv::StorageClassUniformConstant);
    808 		info.binding = _module.num_sampler_bindings++;
    809 		info.texture_binding = ~0u;
    810 
    811 		add_decoration(info.id, spv::DecorationBinding, { info.binding });
    812 		add_decoration(info.id, spv::DecorationDescriptorSet, { 1 });
    813 
    814 		_module.samplers.push_back(info);
    815 
    816 		return info.id;
    817 	}
    818 	id   define_storage(const location &loc, const texture_info &tex_info, storage_info &info) override
    819 	{
    820 		info.id = define_variable(loc, info.type, info.unique_name.c_str(), spv::StorageClassUniformConstant, format_to_image_format(tex_info.format));
    821 		info.binding = _module.num_storage_bindings++;
    822 
    823 		add_decoration(info.id, spv::DecorationBinding, { info.binding });
    824 		add_decoration(info.id, spv::DecorationDescriptorSet, { 2 });
    825 
    826 		_module.storages.push_back(info);
    827 
    828 		return info.id;
    829 	}
    830 	id   define_uniform(const location &, uniform_info &info) override
    831 	{
    832 		if (_uniforms_to_spec_constants && info.has_initializer_value)
    833 		{
    834 			const id res = emit_constant(info.type, info.initializer_value, true);
    835 
    836 			add_name(res, info.name.c_str());
    837 
    838 			const auto add_spec_constant = [this](const spirv_instruction &inst, const uniform_info &info, const constant &initializer_value, size_t initializer_offset) {
    839 				assert(inst.op == spv::OpSpecConstant || inst.op == spv::OpSpecConstantTrue || inst.op == spv::OpSpecConstantFalse);
    840 
    841 				const uint32_t spec_id = static_cast<uint32_t>(_module.spec_constants.size());
    842 				add_decoration(inst.result, spv::DecorationSpecId, { spec_id });
    843 
    844 				uniform_info scalar_info = info;
    845 				scalar_info.type.rows = 1;
    846 				scalar_info.type.cols = 1;
    847 				scalar_info.size = 4;
    848 				scalar_info.offset = static_cast<uint32_t>(initializer_offset);
    849 				scalar_info.initializer_value = {};
    850 				scalar_info.initializer_value.as_uint[0] = initializer_value.as_uint[initializer_offset];
    851 
    852 				_module.spec_constants.push_back(scalar_info);
    853 			};
    854 
    855 			const spirv_instruction &base_inst = _types_and_constants.instructions.back();
    856 			assert(base_inst.result == res);
    857 
    858 			// External specialization constants need to be scalars
    859 			if (info.type.is_scalar())
    860 			{
    861 				add_spec_constant(base_inst, info, info.initializer_value, 0);
    862 			}
    863 			else
    864 			{
    865 				assert(base_inst.op == spv::OpSpecConstantComposite);
    866 
    867 				// Add each individual scalar component of the constant as a separate external specialization constant
    868 				for (size_t i = 0; i < (info.type.is_array() ? base_inst.operands.size() : 1); ++i)
    869 				{
    870 					constant initializer_value = info.initializer_value;
    871 					spirv_instruction elem_inst = base_inst;
    872 
    873 					if (info.type.is_array())
    874 					{
    875 						elem_inst = *std::find_if(_types_and_constants.instructions.rbegin(), _types_and_constants.instructions.rend(),
    876 							[elem = base_inst.operands[i]](const auto &it) { return it.result == elem; });
    877 
    878 						assert(initializer_value.array_data.size() == base_inst.operands.size());
    879 						initializer_value = initializer_value.array_data[i];
    880 					}
    881 
    882 					for (size_t row = 0; row < elem_inst.operands.size(); ++row)
    883 					{
    884 						const spirv_instruction &row_inst = *std::find_if(_types_and_constants.instructions.rbegin(), _types_and_constants.instructions.rend(),
    885 							[elem = elem_inst.operands[row]](const auto &it) { return it.result == elem; });
    886 
    887 						if (row_inst.op != spv::OpSpecConstantComposite)
    888 						{
    889 							add_spec_constant(row_inst, info, initializer_value, row);
    890 							continue;
    891 						}
    892 
    893 						for (size_t col = 0; col < row_inst.operands.size(); ++col)
    894 						{
    895 							const spirv_instruction &col_inst = *std::find_if(_types_and_constants.instructions.rbegin(), _types_and_constants.instructions.rend(),
    896 								[elem = row_inst.operands[col]](const auto &it) { return it.result == elem; });
    897 
    898 							add_spec_constant(col_inst, info, initializer_value, row * info.type.cols + col);
    899 						}
    900 					}
    901 				}
    902 			}
    903 
    904 			return res;
    905 		}
    906 		else
    907 		{
    908 			// Create global uniform buffer variable on demand
    909 			if (_global_ubo_type == 0)
    910 			{
    911 				_global_ubo_type = make_id();
    912 
    913 				add_decoration(_global_ubo_type, spv::DecorationBlock);
    914 			}
    915 			if (_global_ubo_variable == 0)
    916 			{
    917 				_global_ubo_variable = make_id();
    918 
    919 				add_decoration(_global_ubo_variable, spv::DecorationDescriptorSet, { 0 });
    920 				add_decoration(_global_ubo_variable, spv::DecorationBinding, { 0 });
    921 			}
    922 
    923 			uint32_t alignment = (info.type.rows == 3 ? 4 : info.type.rows) * 4;
    924 			info.size = info.type.rows * 4;
    925 
    926 			uint32_t array_stride = 16;
    927 			const uint32_t matrix_stride = 16;
    928 
    929 			if (info.type.is_matrix())
    930 			{
    931 				alignment = matrix_stride;
    932 				info.size = info.type.rows * matrix_stride;
    933 			}
    934 			if (info.type.is_array())
    935 			{
    936 				alignment = array_stride;
    937 				array_stride = align_up(info.size, array_stride);
    938 				// Uniform block rules do not permit anything in the padding of an array
    939 				info.size = array_stride * info.type.array_length;
    940 			}
    941 
    942 			info.offset = _module.total_uniform_size;
    943 			info.offset = align_up(info.offset, alignment);
    944 			_module.total_uniform_size = info.offset + info.size;
    945 
    946 			type ubo_type = info.type;
    947 			// Convert boolean uniform variables to integer type so that they have a defined size
    948 			if (info.type.is_boolean())
    949 				ubo_type.base = type::t_uint;
    950 
    951 			const uint32_t member_index = static_cast<uint32_t>(_global_ubo_types.size());
    952 
    953 			// Composite objects in the uniform storage class must be explicitly laid out, which includes array types requiring a stride decoration
    954 			_global_ubo_types.push_back(
    955 				convert_type(ubo_type, false, spv::StorageClassUniform, spv::ImageFormatUnknown, info.type.is_array() ? array_stride : 0u));
    956 
    957 			add_member_name(_global_ubo_type, member_index, info.name.c_str());
    958 
    959 			add_member_decoration(_global_ubo_type, member_index, spv::DecorationOffset, { info.offset });
    960 
    961 			if (info.type.is_matrix())
    962 			{
    963 				// Read matrices in column major layout, even though they are actually row major, to avoid transposing them on every access (since SPIR-V uses column matrices)
    964 				// TODO: This technically only works with square matrices
    965 				add_member_decoration(_global_ubo_type, member_index, spv::DecorationColMajor);
    966 				add_member_decoration(_global_ubo_type, member_index, spv::DecorationMatrixStride, { matrix_stride });
    967 			}
    968 
    969 			_module.uniforms.push_back(info);
    970 
    971 			return 0xF0000000 | member_index;
    972 		}
    973 	}
    974 	id   define_variable(const location &loc, const type &type, std::string name, bool global, id initializer_value) override
    975 	{
    976 		spv::StorageClass storage = spv::StorageClassFunction;
    977 		if (type.has(type::q_groupshared))
    978 			storage = spv::StorageClassWorkgroup;
    979 		else if (global)
    980 			storage = spv::StorageClassPrivate;
    981 
    982 		return define_variable(loc, type, name.c_str(), storage, spv::ImageFormatUnknown, initializer_value);
    983 	}
    984 	id   define_variable(const location &loc, const type &type, const char *name, spv::StorageClass storage, spv::ImageFormat format = spv::ImageFormatUnknown, spv::Id initializer_value = 0)
    985 	{
    986 		assert(storage != spv::StorageClassFunction || _current_function != nullptr);
    987 
    988 		spirv_basic_block &block = (storage != spv::StorageClassFunction) ?
    989 			_variables : _current_function->variables;
    990 
    991 		add_location(loc, block);
    992 
    993 		spv::Id res;
    994 		// https://www.khronos.org/registry/spir-v/specs/unified1/SPIRV.html#OpVariable
    995 		spirv_instruction &inst = add_instruction(spv::OpVariable, convert_type(type, true, storage, format), block, res)
    996 			.add(storage);
    997 
    998 		if (initializer_value != 0)
    999 		{
   1000 			if (storage != spv::StorageClassFunction || _current_function->is_entry_point)
   1001 			{
   1002 				// The initializer for variables must be a constant
   1003 				inst.add(initializer_value);
   1004 			}
   1005 			else
   1006 			{
   1007 				// Only use the variable initializer on global variables, since local variables for e.g. "for" statements need to be assigned in their respective scope and not their declaration
   1008 				expression variable;
   1009 				variable.reset_to_lvalue(loc, res, type);
   1010 				emit_store(variable, initializer_value);
   1011 			}
   1012 		}
   1013 
   1014 		if (name != nullptr && *name != '\0')
   1015 			add_name(res, name);
   1016 
   1017 		if (!_enable_16bit_types && type.is_numeric() && type.precision() < 32)
   1018 			add_decoration(res, spv::DecorationRelaxedPrecision);
   1019 
   1020 		_storage_lookup[res] = { storage, format };
   1021 
   1022 		return res;
   1023 	}
   1024 	id   define_function(const location &loc, function_info &info) override
   1025 	{
   1026 		assert(!is_in_function());
   1027 
   1028 		auto &function = _functions_blocks.emplace_back();
   1029 		function.return_type = info.return_type;
   1030 
   1031 		_current_function = &function;
   1032 
   1033 		for (auto &param : info.parameter_list)
   1034 			function.param_types.push_back(param.type);
   1035 
   1036 		add_location(loc, function.declaration);
   1037 
   1038 		// https://www.khronos.org/registry/spir-v/specs/unified1/SPIRV.html#OpFunction
   1039 		add_instruction(spv::OpFunction, convert_type(info.return_type), function.declaration, info.definition)
   1040 			.add(spv::FunctionControlMaskNone)
   1041 			.add(convert_type(function));
   1042 
   1043 		if (!info.name.empty())
   1044 			add_name(info.definition, info.name.c_str());
   1045 
   1046 		for (auto &param : info.parameter_list)
   1047 		{
   1048 			add_location(param.location, function.declaration);
   1049 
   1050 			param.definition = add_instruction(spv::OpFunctionParameter, convert_type(param.type, true), function.declaration).result;
   1051 
   1052 			add_name(param.definition, param.name.c_str());
   1053 		}
   1054 
   1055 		_functions.push_back(std::make_unique<function_info>(info));
   1056 
   1057 		return info.definition;
   1058 	}
   1059 
   1060 	void define_entry_point(function_info &func, shader_type stype, int num_threads[3]) override
   1061 	{
   1062 		// Modify entry point name so each thread configuration is made separate
   1063 		if (stype == shader_type::cs)
   1064 			func.unique_name = 'E' + func.unique_name +
   1065 				'_' + std::to_string(num_threads[0]) +
   1066 				'_' + std::to_string(num_threads[1]) +
   1067 				'_' + std::to_string(num_threads[2]);
   1068 
   1069 		if (const auto it = std::find_if(_module.entry_points.begin(), _module.entry_points.end(),
   1070 				[&func](const auto &ep) { return ep.name == func.unique_name; });
   1071 			it != _module.entry_points.end())
   1072 			return;
   1073 
   1074 		_module.entry_points.push_back({ func.unique_name, stype });
   1075 
   1076 		spv::Id position_variable = 0, point_size_variable = 0;
   1077 		std::vector<spv::Id> inputs_and_outputs;
   1078 		std::vector<expression> call_params;
   1079 
   1080 		// Generate the glue entry point function
   1081 		function_info entry_point;
   1082 		entry_point.return_type = { type::t_void };
   1083 
   1084 		define_function({}, entry_point);
   1085 		enter_block(create_block());
   1086 
   1087 		_current_function->is_entry_point = true;
   1088 
   1089 		const auto create_varying_param = [this, &call_params](const struct_member_info &param) {
   1090 			// Initialize all output variables with zero
   1091 			const spv::Id variable = define_variable({}, param.type, nullptr, spv::StorageClassFunction, spv::ImageFormatUnknown, emit_constant(param.type, 0u));
   1092 
   1093 			expression &call_param = call_params.emplace_back();
   1094 			call_param.reset_to_lvalue({}, variable, param.type);
   1095 
   1096 			return variable;
   1097 		};
   1098 
   1099 		const auto create_varying_variable = [this, &inputs_and_outputs, &position_variable, &point_size_variable, stype](const type &param_type, const std::string &semantic, spv::StorageClass storage, int a = 0) {
   1100 			const spv::Id variable = define_variable({}, param_type, nullptr, storage);
   1101 
   1102 			if (const spv::BuiltIn builtin = semantic_to_builtin(semantic, stype);
   1103 				builtin != spv::BuiltInMax)
   1104 			{
   1105 				assert(a == 0); // Built-in variables cannot be arrays
   1106 
   1107 				add_builtin(variable, builtin);
   1108 
   1109 				if (builtin == spv::BuiltInPosition && storage == spv::StorageClassOutput)
   1110 					position_variable = variable;
   1111 				if (builtin == spv::BuiltInPointSize && storage == spv::StorageClassOutput)
   1112 					point_size_variable = variable;
   1113 			}
   1114 			else
   1115 			{
   1116 				assert(stype != shader_type::cs); // Compute shaders cannot have custom inputs or outputs
   1117 
   1118 				const uint32_t location = semantic_to_location(semantic, std::max(1, param_type.array_length));
   1119 				add_decoration(variable, spv::DecorationLocation, { location + a });
   1120 			}
   1121 
   1122 			if (param_type.has(type::q_noperspective))
   1123 				add_decoration(variable, spv::DecorationNoPerspective);
   1124 			if (param_type.has(type::q_centroid))
   1125 				add_decoration(variable, spv::DecorationCentroid);
   1126 			if (param_type.has(type::q_nointerpolation))
   1127 				add_decoration(variable, spv::DecorationFlat);
   1128 
   1129 			inputs_and_outputs.push_back(variable);
   1130 			return variable;
   1131 		};
   1132 
   1133 		// Translate function parameters to input/output variables
   1134 		for (const struct_member_info &param : func.parameter_list)
   1135 		{
   1136 			spv::Id param_var = create_varying_param(param);
   1137 
   1138 			// Create separate input/output variables for "inout" parameters
   1139 			if (param.type.has(type::q_in))
   1140 			{
   1141 				spv::Id param_value = 0;
   1142 
   1143 				// Flatten structure parameters
   1144 				if (param.type.is_struct())
   1145 				{
   1146 					const struct_info &definition = get_struct(param.type.definition);
   1147 
   1148 					type struct_type = param.type;
   1149 					const int array_length = std::max(1, param.type.array_length);
   1150 					struct_type.array_length = 0;
   1151 
   1152 					// Struct arrays need to be flattened into individual elements as well
   1153 					std::vector<spv::Id> array_elements;
   1154 					array_elements.reserve(array_length);
   1155 					for (int a = 0; a < array_length; a++)
   1156 					{
   1157 						std::vector<spv::Id> struct_elements;
   1158 						struct_elements.reserve(definition.member_list.size());
   1159 						for (const struct_member_info &member : definition.member_list)
   1160 						{
   1161 							spv::Id input_var = create_varying_variable(member.type, member.semantic, spv::StorageClassInput, a);
   1162 
   1163 							param_value = add_instruction(spv::OpLoad, convert_type(member.type))
   1164 								.add(input_var).result;
   1165 							struct_elements.push_back(param_value);
   1166 						}
   1167 
   1168 						param_value = add_instruction(spv::OpCompositeConstruct, convert_type(struct_type))
   1169 							.add(struct_elements.begin(), struct_elements.end()).result;
   1170 						array_elements.push_back(param_value);
   1171 					}
   1172 
   1173 					if (param.type.is_array())
   1174 					{
   1175 						// Build the array from all constructed struct elements
   1176 						param_value = add_instruction(spv::OpCompositeConstruct, convert_type(param.type))
   1177 							.add(array_elements.begin(), array_elements.end()).result;
   1178 					}
   1179 				}
   1180 				else
   1181 				{
   1182 					spv::Id input_var = create_varying_variable(param.type, param.semantic, spv::StorageClassInput);
   1183 
   1184 					param_value = add_instruction(spv::OpLoad, convert_type(param.type))
   1185 						.add(input_var).result;
   1186 				}
   1187 
   1188 				add_instruction_without_result(spv::OpStore)
   1189 					.add(param_var)
   1190 					.add(param_value);
   1191 			}
   1192 
   1193 			if (param.type.has(type::q_out))
   1194 			{
   1195 				if (param.type.is_struct())
   1196 				{
   1197 					const struct_info &definition = get_struct(param.type.definition);
   1198 
   1199 					for (int a = 0, array_length = std::max(1, param.type.array_length); a < array_length; a++)
   1200 					{
   1201 						for (const struct_member_info &member : definition.member_list)
   1202 						{
   1203 							create_varying_variable(member.type, member.semantic, spv::StorageClassOutput, a);
   1204 						}
   1205 					}
   1206 				}
   1207 				else
   1208 				{
   1209 					create_varying_variable(param.type, param.semantic, spv::StorageClassOutput);
   1210 				}
   1211 			}
   1212 		}
   1213 
   1214 		const auto call_result = emit_call({}, func.definition, func.return_type, call_params);
   1215 
   1216 		for (size_t i = 0, inputs_and_outputs_index = 0; i < func.parameter_list.size(); ++i)
   1217 		{
   1218 			const struct_member_info &param = func.parameter_list[i];
   1219 
   1220 			if (param.type.has(type::q_out))
   1221 			{
   1222 				const spv::Id value = add_instruction(spv::OpLoad, convert_type(param.type))
   1223 					.add(call_params[i].base).result;
   1224 
   1225 				if (param.type.is_struct())
   1226 				{
   1227 					const struct_info &definition = get_struct(param.type.definition);
   1228 
   1229 					type struct_type = param.type;
   1230 					const int array_length = std::max(1, param.type.array_length);
   1231 					struct_type.array_length = 0;
   1232 
   1233 					// Skip input variables if this is an "inout" parameter
   1234 					if (param.type.has(type::q_in))
   1235 						inputs_and_outputs_index += definition.member_list.size() * array_length;
   1236 
   1237 					// Split up struct array into individual struct elements again
   1238 					for (int a = 0; a < array_length; a++)
   1239 					{
   1240 						spv::Id element_value = value;
   1241 						if (param.type.is_array())
   1242 						{
   1243 							element_value = add_instruction(spv::OpCompositeExtract, convert_type(struct_type))
   1244 								.add(value)
   1245 								.add(a).result;
   1246 						}
   1247 
   1248 						// Split out struct fields into separate output variables again
   1249 						for (uint32_t member_index = 0; member_index < definition.member_list.size(); ++member_index)
   1250 						{
   1251 							const struct_member_info &member = definition.member_list[member_index];
   1252 
   1253 							const spv::Id member_value = add_instruction(spv::OpCompositeExtract, convert_type(member.type))
   1254 								.add(element_value)
   1255 								.add(member_index).result;
   1256 
   1257 							add_instruction_without_result(spv::OpStore)
   1258 								.add(inputs_and_outputs[inputs_and_outputs_index++])
   1259 								.add(member_value);
   1260 						}
   1261 					}
   1262 				}
   1263 				else
   1264 				{
   1265 					// Skip input variable if this is an "inout" parameter (see loop above)
   1266 					if (param.type.has(type::q_in))
   1267 						inputs_and_outputs_index += 1;
   1268 
   1269 					add_instruction_without_result(spv::OpStore)
   1270 						.add(inputs_and_outputs[inputs_and_outputs_index++])
   1271 						.add(value);
   1272 				}
   1273 			}
   1274 			else
   1275 			{
   1276 				// Input parameters do not need to store anything, but increase the input/output variable index
   1277 				if (param.type.is_struct())
   1278 				{
   1279 					const struct_info &definition = get_struct(param.type.definition);
   1280 					inputs_and_outputs_index += definition.member_list.size() * std::max(1, param.type.array_length);
   1281 				}
   1282 				else
   1283 				{
   1284 					inputs_and_outputs_index += 1;
   1285 				}
   1286 			}
   1287 		}
   1288 
   1289 		if (func.return_type.is_struct())
   1290 		{
   1291 			const struct_info &definition = get_struct(func.return_type.definition);
   1292 
   1293 			for (uint32_t member_index = 0; member_index < definition.member_list.size(); ++member_index)
   1294 			{
   1295 				const struct_member_info &member = definition.member_list[member_index];
   1296 
   1297 				const spv::Id result = create_varying_variable(member.type, member.semantic, spv::StorageClassOutput);
   1298 				const spv::Id member_result = add_instruction(spv::OpCompositeExtract, convert_type(member.type))
   1299 					.add(call_result)
   1300 					.add(member_index).result;
   1301 
   1302 				add_instruction_without_result(spv::OpStore)
   1303 					.add(result)
   1304 					.add(member_result);
   1305 			}
   1306 		}
   1307 		else if (!func.return_type.is_void())
   1308 		{
   1309 			const spv::Id result = create_varying_variable(func.return_type, func.return_semantic, spv::StorageClassOutput);
   1310 
   1311 			add_instruction_without_result(spv::OpStore)
   1312 				.add(result)
   1313 				.add(call_result);
   1314 		}
   1315 
   1316 		// Add code to flip the output vertically
   1317 		if (_flip_vert_y && position_variable != 0 && stype == shader_type::vs)
   1318 		{
   1319 			expression position;
   1320 			position.reset_to_lvalue({}, position_variable, { type::t_float, 4, 1 });
   1321 			position.add_constant_index_access(1); // Y component
   1322 
   1323 			// gl_Position.y = -gl_Position.y
   1324 			emit_store(position,
   1325 				emit_unary_op({}, tokenid::minus, { type::t_float, 1, 1 },
   1326 					emit_load(position, false)));
   1327 		}
   1328 
   1329 		// Add code that sets the point size to a default value (in case this vertex shader is used with point primitives)
   1330 		if (point_size_variable == 0 && stype == shader_type::vs)
   1331 		{
   1332 			create_varying_variable({ type::t_float, 1, 1 }, "SV_POINTSIZE", spv::StorageClassOutput);
   1333 
   1334 			expression point_size;
   1335 			point_size.reset_to_lvalue({}, point_size_variable, { type::t_float, 1, 1 });
   1336 
   1337 			// gl_PointSize = 1.0
   1338 			emit_store(point_size, emit_constant({ type::t_float, 1, 1 }, 1));
   1339 		}
   1340 
   1341 		leave_block_and_return(0);
   1342 		leave_function();
   1343 
   1344 		spv::ExecutionModel model;
   1345 		switch (stype)
   1346 		{
   1347 		case shader_type::vs:
   1348 			model = spv::ExecutionModelVertex;
   1349 			break;
   1350 		case shader_type::ps:
   1351 			model = spv::ExecutionModelFragment;
   1352 			add_instruction_without_result(spv::OpExecutionMode, _execution_modes)
   1353 				.add(entry_point.definition)
   1354 				.add(_vulkan_semantics ? spv::ExecutionModeOriginUpperLeft : spv::ExecutionModeOriginLowerLeft);
   1355 			break;
   1356 		case shader_type::cs:
   1357 			model = spv::ExecutionModelGLCompute;
   1358 			add_instruction_without_result(spv::OpExecutionMode, _execution_modes)
   1359 				.add(entry_point.definition)
   1360 				.add(spv::ExecutionModeLocalSize)
   1361 				.add(num_threads[0])
   1362 				.add(num_threads[1])
   1363 				.add(num_threads[2]);
   1364 			break;
   1365 		default:
   1366 			assert(false);
   1367 			return;
   1368 		}
   1369 
   1370 		assert(!func.unique_name.empty());
   1371 		add_instruction_without_result(spv::OpEntryPoint, _entries)
   1372 			.add(model)
   1373 			.add(entry_point.definition)
   1374 			.add_string(func.unique_name.c_str())
   1375 			.add(inputs_and_outputs.begin(), inputs_and_outputs.end());
   1376 	}
   1377 
   1378 	id   emit_load(const expression &exp, bool) override
   1379 	{
   1380 		if (exp.is_constant) // Constant expressions do not have a complex access chain
   1381 			return emit_constant(exp.type, exp.constant);
   1382 
   1383 		size_t i = 0;
   1384 		spv::Id result = exp.base;
   1385 		auto base_type = exp.type;
   1386 		bool is_uniform_bool = false;
   1387 
   1388 		if (exp.is_lvalue || !exp.chain.empty())
   1389 			add_location(exp.location, *_current_block_data);
   1390 
   1391 		// If a variable is referenced, load the value first
   1392 		if (exp.is_lvalue && _spec_constants.find(exp.base) == _spec_constants.end())
   1393 		{
   1394 			if (!exp.chain.empty())
   1395 				base_type = exp.chain[0].from;
   1396 
   1397 			std::pair<spv::StorageClass, spv::ImageFormat> storage = { spv::StorageClassFunction, spv::ImageFormatUnknown };
   1398 			if (const auto it = _storage_lookup.find(exp.base);
   1399 				it != _storage_lookup.end())
   1400 				storage = it->second;
   1401 
   1402 			spirv_instruction *access_chain = nullptr;
   1403 
   1404 			// Check if this is a uniform variable (see 'define_uniform' function above) and dereference it
   1405 			if (result & 0xF0000000)
   1406 			{
   1407 				const uint32_t member_index = result ^ 0xF0000000;
   1408 
   1409 				storage.first = spv::StorageClassUniform;
   1410 				is_uniform_bool = base_type.is_boolean();
   1411 
   1412 				if (is_uniform_bool)
   1413 					base_type.base = type::t_uint;
   1414 
   1415 				access_chain = &add_instruction(spv::OpAccessChain)
   1416 					.add(_global_ubo_variable)
   1417 					.add(emit_constant(member_index));
   1418 			}
   1419 
   1420 			// Any indexing expressions can be resolved during load with an 'OpAccessChain' already
   1421 			if (!exp.chain.empty() && (
   1422 				exp.chain[0].op == expression::operation::op_member ||
   1423 				exp.chain[0].op == expression::operation::op_dynamic_index ||
   1424 				exp.chain[0].op == expression::operation::op_constant_index))
   1425 			{
   1426 				// Ensure that 'access_chain' cannot get invalidated by calls to 'emit_constant' or 'convert_type'
   1427 				assert(_current_block_data != &_types_and_constants);
   1428 
   1429 				// Use access chain from uniform if possible, otherwise create new one
   1430 				if (access_chain == nullptr) access_chain =
   1431 					&add_instruction(spv::OpAccessChain).add(result); // Base
   1432 
   1433 				// Ignore first index into 1xN matrices, since they were translated to a vector type in SPIR-V
   1434 				if (exp.chain[0].from.rows == 1 && exp.chain[0].from.cols > 1)
   1435 					i = 1;
   1436 
   1437 				for (; i < exp.chain.size() && (
   1438 					exp.chain[i].op == expression::operation::op_member ||
   1439 					exp.chain[i].op == expression::operation::op_dynamic_index ||
   1440 					exp.chain[i].op == expression::operation::op_constant_index); ++i)
   1441 					access_chain->add(exp.chain[i].op == expression::operation::op_dynamic_index ?
   1442 						exp.chain[i].index :
   1443 						emit_constant(exp.chain[i].index)); // Indexes
   1444 
   1445 				base_type = exp.chain[i - 1].to;
   1446 				access_chain->type = convert_type(base_type, true, storage.first, storage.second); // Last type is the result
   1447 				result = access_chain->result;
   1448 			}
   1449 			else if (access_chain != nullptr)
   1450 			{
   1451 				access_chain->type = convert_type(base_type, true, storage.first, storage.second, base_type.is_array() ? 16u : 0u);
   1452 				result = access_chain->result;
   1453 			}
   1454 
   1455 			result = add_instruction(spv::OpLoad, convert_type(base_type, false, spv::StorageClassFunction, storage.second))
   1456 				.add(result) // Pointer
   1457 				.result;
   1458 		}
   1459 
   1460 		// Need to convert boolean uniforms which are actually integers in SPIR-V
   1461 		if (is_uniform_bool)
   1462 		{
   1463 			base_type.base = type::t_bool;
   1464 
   1465 			result = add_instruction(spv::OpINotEqual, convert_type(base_type))
   1466 				.add(result)
   1467 				.add(emit_constant(0))
   1468 				.result;
   1469 		}
   1470 
   1471 		// Work through all remaining operations in the access chain and apply them to the value
   1472 		for (; i < exp.chain.size(); ++i)
   1473 		{
   1474 			assert(result != 0);
   1475 			const auto &op = exp.chain[i];
   1476 
   1477 			switch (op.op)
   1478 			{
   1479 			case expression::operation::op_cast:
   1480 				if (op.from.is_scalar() && !op.to.is_scalar())
   1481 				{
   1482 					type cast_type = op.to;
   1483 					cast_type.base = op.from.base;
   1484 
   1485 					std::vector<expression> args;
   1486 					for (unsigned int c = 0; c < op.to.components(); ++c)
   1487 						args.emplace_back().reset_to_rvalue(exp.location, result, op.from);
   1488 
   1489 					result = emit_construct(exp.location, cast_type, args);
   1490 				}
   1491 
   1492 				if (op.from.is_boolean())
   1493 				{
   1494 					const spv::Id true_constant = emit_constant(op.to, 1);
   1495 					const spv::Id false_constant = emit_constant(op.to, 0);
   1496 
   1497 					result = add_instruction(spv::OpSelect, convert_type(op.to))
   1498 						.add(result) // Condition
   1499 						.add(true_constant)
   1500 						.add(false_constant)
   1501 						.result;
   1502 				}
   1503 				else
   1504 				{
   1505 					spv::Op spv_op = spv::OpNop;
   1506 					switch (op.to.base)
   1507 					{
   1508 					case type::t_bool:
   1509 						if (op.from.is_floating_point())
   1510 							spv_op = spv::OpFOrdNotEqual;
   1511 						else
   1512 							spv_op = spv::OpINotEqual;
   1513 						// Add instruction to compare value against zero instead of casting
   1514 						result = add_instruction(spv_op, convert_type(op.to))
   1515 							.add(result)
   1516 							.add(emit_constant(op.from, 0))
   1517 							.result;
   1518 						continue;
   1519 					case type::t_min16int:
   1520 					case type::t_int:
   1521 						if (op.from.is_floating_point())
   1522 							spv_op = spv::OpConvertFToS;
   1523 						else if (op.from.precision() == op.to.precision())
   1524 							spv_op = spv::OpBitcast;
   1525 						else if (_enable_16bit_types)
   1526 							spv_op = spv::OpSConvert;
   1527 						else
   1528 							continue; // Do not have to add conversion instruction between min16int/int if 16-bit types are not enabled
   1529 						break;
   1530 					case type::t_min16uint:
   1531 					case type::t_uint:
   1532 						if (op.from.is_floating_point())
   1533 							spv_op = spv::OpConvertFToU;
   1534 						else if (op.from.precision() == op.to.precision())
   1535 							spv_op = spv::OpBitcast;
   1536 						else if (_enable_16bit_types)
   1537 							spv_op = spv::OpUConvert;
   1538 						else
   1539 							continue;
   1540 						break;
   1541 					case type::t_min16float:
   1542 					case type::t_float:
   1543 						if (op.from.is_floating_point() && !_enable_16bit_types)
   1544 							continue; // Do not have to add conversion instruction between min16float/float if 16-bit types are not enabled
   1545 						else if (op.from.is_floating_point())
   1546 							spv_op = spv::OpFConvert;
   1547 						else if (op.from.is_signed())
   1548 							spv_op = spv::OpConvertSToF;
   1549 						else
   1550 							spv_op = spv::OpConvertUToF;
   1551 						break;
   1552 					default:
   1553 						assert(false);
   1554 					}
   1555 
   1556 					result = add_instruction(spv_op, convert_type(op.to))
   1557 						.add(result)
   1558 						.result;
   1559 				}
   1560 				break;
   1561 			case expression::operation::op_dynamic_index:
   1562 				assert(op.from.is_vector() && op.to.is_scalar());
   1563 				result = add_instruction(spv::OpVectorExtractDynamic, convert_type(op.to))
   1564 					.add(result) // Vector
   1565 					.add(op.index) // Index
   1566 					.result;
   1567 				break;
   1568 			case expression::operation::op_member: // In case of struct return values, which are r-values
   1569 			case expression::operation::op_constant_index:
   1570 				assert(op.from.is_vector() || op.from.is_matrix() || op.from.is_struct());
   1571 				result = add_instruction(spv::OpCompositeExtract, convert_type(op.to))
   1572 					.add(result)
   1573 					.add(op.index) // Literal Index
   1574 					.result;
   1575 				break;
   1576 			case expression::operation::op_swizzle:
   1577 				if (op.to.is_vector())
   1578 				{
   1579 					if (op.from.is_matrix())
   1580 					{
   1581 						spv::Id components[4];
   1582 						for (unsigned int c = 0; c < 4 && op.swizzle[c] >= 0; ++c)
   1583 						{
   1584 							const unsigned int row = op.swizzle[c] / 4;
   1585 							const unsigned int column = op.swizzle[c] - row * 4;
   1586 
   1587 							type scalar_type = op.to;
   1588 							scalar_type.rows = 1;
   1589 							scalar_type.cols = 1;
   1590 
   1591 							spirv_instruction &node = add_instruction(spv::OpCompositeExtract, convert_type(scalar_type))
   1592 								.add(result);
   1593 
   1594 							if (op.from.rows > 1) // Matrix types with a single row are actually vectors, so they don't need the extra index
   1595 								node.add(row);
   1596 
   1597 							node.add(column);
   1598 
   1599 							components[c] = node.result;
   1600 						}
   1601 
   1602 						spirv_instruction &node = add_instruction(spv::OpCompositeConstruct, convert_type(op.to));
   1603 						for (unsigned int c = 0; c < 4 && op.swizzle[c] >= 0; ++c)
   1604 							node.add(components[c]);
   1605 						result = node.result;
   1606 						break;
   1607 					}
   1608 					else if (op.from.is_vector())
   1609 					{
   1610 						spirv_instruction &node = add_instruction(spv::OpVectorShuffle, convert_type(op.to))
   1611 							.add(result) // Vector 1
   1612 							.add(result); // Vector 2
   1613 						for (unsigned int c = 0; c < 4 && op.swizzle[c] >= 0; ++c)
   1614 							node.add(op.swizzle[c]);
   1615 						result = node.result;
   1616 						break;
   1617 					}
   1618 					else
   1619 					{
   1620 						spirv_instruction &node = add_instruction(spv::OpCompositeConstruct, convert_type(op.to));
   1621 						for (unsigned int c = 0; c < op.to.rows; ++c)
   1622 							node.add(result);
   1623 						result = node.result;
   1624 						break;
   1625 					}
   1626 				}
   1627 				else if (op.from.is_matrix() && op.to.is_scalar())
   1628 				{
   1629 					assert(op.swizzle[1] < 0);
   1630 
   1631 					spirv_instruction &node = add_instruction(spv::OpCompositeExtract, convert_type(op.to))
   1632 						.add(result); // Composite
   1633 					if (op.from.rows > 1)
   1634 					{
   1635 						const unsigned int row = op.swizzle[0] / 4;
   1636 						const unsigned int column = op.swizzle[0] - row * 4;
   1637 						node.add(row);
   1638 						node.add(column);
   1639 					}
   1640 					else
   1641 					{
   1642 						node.add(op.swizzle[0]);
   1643 					}
   1644 					result = node.result; // Result ID
   1645 					break;
   1646 				}
   1647 				assert(false);
   1648 				break;
   1649 			}
   1650 		}
   1651 
   1652 		return result;
   1653 	}
   1654 	void emit_store(const expression &exp, id value) override
   1655 	{
   1656 		assert(value != 0 && exp.is_lvalue && !exp.is_constant && !exp.type.is_sampler());
   1657 
   1658 		add_location(exp.location, *_current_block_data);
   1659 
   1660 		size_t i = 0;
   1661 		// Any indexing expressions can be resolved with an 'OpAccessChain' already
   1662 		spv::Id target = emit_access_chain(exp, i);
   1663 		auto base_type = exp.chain.empty() ? exp.type : i == 0 ? exp.chain[0].from : exp.chain[i - 1].to;
   1664 
   1665 		// TODO: Complex access chains like float4x4[0].m00m10[0] = 0;
   1666 		// Work through all remaining operations in the access chain and apply them to the value
   1667 		for (; i < exp.chain.size(); ++i)
   1668 		{
   1669 			const auto &op = exp.chain[i];
   1670 			switch (op.op)
   1671 			{
   1672 				case expression::operation::op_cast:
   1673 				case expression::operation::op_member:
   1674 					// These should have been handled above already (and casting does not make sense for a store operation)
   1675 					break;
   1676 				case expression::operation::op_dynamic_index:
   1677 				case expression::operation::op_constant_index:
   1678 					assert(false);
   1679 					break;
   1680 				case expression::operation::op_swizzle:
   1681 				{
   1682 					spv::Id result = add_instruction(spv::OpLoad, convert_type(base_type))
   1683 						.add(target) // Pointer
   1684 						.result; // Result ID
   1685 
   1686 					if (base_type.is_vector())
   1687 					{
   1688 						spirv_instruction &node = add_instruction(spv::OpVectorShuffle, convert_type(base_type))
   1689 							.add(result) // Vector 1
   1690 							.add(value); // Vector 2
   1691 
   1692 						unsigned int shuffle[4] = { 0, 1, 2, 3 };
   1693 						for (unsigned int c = 0; c < base_type.rows; ++c)
   1694 							if (op.swizzle[c] >= 0)
   1695 								shuffle[op.swizzle[c]] = base_type.rows + c;
   1696 						for (unsigned int c = 0; c < base_type.rows; ++c)
   1697 							node.add(shuffle[c]);
   1698 
   1699 						value = node.result;
   1700 					}
   1701 					else if (op.to.is_scalar())
   1702 					{
   1703 						assert(op.swizzle[1] < 0);
   1704 
   1705 						spirv_instruction &node = add_instruction(spv::OpCompositeInsert, convert_type(base_type))
   1706 							.add(value) // Object
   1707 							.add(result); // Composite
   1708 
   1709 						if (op.from.is_matrix() && op.from.rows > 1)
   1710 						{
   1711 							const unsigned int row = op.swizzle[0] / 4;
   1712 							const unsigned int column = op.swizzle[0] - row * 4;
   1713 							node.add(row);
   1714 							node.add(column);
   1715 						}
   1716 						else
   1717 						{
   1718 							node.add(op.swizzle[0]);
   1719 						}
   1720 
   1721 						value = node.result; // Result ID
   1722 					}
   1723 					else
   1724 					{
   1725 						// TODO: Implement matrix to vector swizzles
   1726 						assert(false);
   1727 					}
   1728 					break;
   1729 				}
   1730 			}
   1731 		}
   1732 
   1733 		add_instruction_without_result(spv::OpStore)
   1734 			.add(target)
   1735 			.add(value);
   1736 	}
   1737 	id   emit_access_chain(const expression &exp, size_t &i) override
   1738 	{
   1739 		// This function cannot create access chains for uniform variables
   1740 		assert((exp.base & 0xF0000000) == 0);
   1741 
   1742 		i = 0;
   1743 		if (exp.chain.empty() || (
   1744 			exp.chain[0].op != expression::operation::op_member &&
   1745 			exp.chain[0].op != expression::operation::op_dynamic_index &&
   1746 			exp.chain[0].op != expression::operation::op_constant_index))
   1747 			return exp.base;
   1748 
   1749 		std::pair<spv::StorageClass, spv::ImageFormat> storage = { spv::StorageClassFunction, spv::ImageFormatUnknown };
   1750 		if (const auto it = _storage_lookup.find(exp.base);
   1751 			it != _storage_lookup.end())
   1752 			storage = it->second;
   1753 
   1754 		// Ensure that 'access_chain' cannot get invalidated by calls to 'emit_constant' or 'convert_type'
   1755 		assert(_current_block_data != &_types_and_constants);
   1756 
   1757 		spirv_instruction *access_chain =
   1758 			&add_instruction(spv::OpAccessChain).add(exp.base); // Base
   1759 
   1760 		// Ignore first index into 1xN matrices, since they were translated to a vector type in SPIR-V
   1761 		if (exp.chain[0].from.rows == 1 && exp.chain[0].from.cols > 1)
   1762 			i = 1;
   1763 
   1764 		for (; i < exp.chain.size() && (
   1765 			exp.chain[i].op == expression::operation::op_member ||
   1766 			exp.chain[i].op == expression::operation::op_dynamic_index ||
   1767 			exp.chain[i].op == expression::operation::op_constant_index); ++i)
   1768 			access_chain->add(exp.chain[i].op == expression::operation::op_dynamic_index ?
   1769 				exp.chain[i].index :
   1770 				emit_constant(exp.chain[i].index)); // Indexes
   1771 
   1772 		access_chain->type = convert_type(exp.chain[i - 1].to, true, storage.first, storage.second); // Last type is the result
   1773 		return access_chain->result;
   1774 	}
   1775 
   1776 	id   emit_constant(uint32_t value)
   1777 	{
   1778 		return emit_constant({ type::t_uint, 1, 1 }, value);
   1779 	}
   1780 	id   emit_constant(const type &type, uint32_t value)
   1781 	{
   1782 		// Create a constant value of the specified type
   1783 		constant data = {}; // Initialize to zero, so that components not set below still have a defined value for the lookup via std::memcmp
   1784 		for (unsigned int i = 0; i < type.components(); ++i)
   1785 			if (type.is_integral())
   1786 				data.as_uint[i] = value;
   1787 			else
   1788 				data.as_float[i] = static_cast<float>(value);
   1789 
   1790 		return emit_constant(type, data, false);
   1791 	}
   1792 	id   emit_constant(const type &type, const constant &data) override
   1793 	{
   1794 		return emit_constant(type, data, false);
   1795 	}
   1796 	id   emit_constant(const type &type, const constant &data, bool spec_constant)
   1797 	{
   1798 		if (!spec_constant) // Specialization constants cannot reuse other constants
   1799 		{
   1800 			if (const auto it = std::find_if(_constant_lookup.begin(), _constant_lookup.end(),
   1801 				[&type, &data](auto &x) {
   1802 					if (!(std::get<0>(x) == type && std::memcmp(&std::get<1>(x).as_uint[0], &data.as_uint[0], sizeof(uint32_t) * 16) == 0 && std::get<1>(x).array_data.size() == data.array_data.size()))
   1803 						return false;
   1804 					for (size_t i = 0; i < data.array_data.size(); ++i)
   1805 						if (std::memcmp(&std::get<1>(x).array_data[i].as_uint[0], &data.array_data[i].as_uint[0], sizeof(uint32_t) * 16) != 0)
   1806 							return false;
   1807 					return true;
   1808 				});
   1809 				it != _constant_lookup.end())
   1810 				return std::get<2>(*it); // Re-use existing constant instead of duplicating the definition
   1811 		}
   1812 
   1813 		spv::Id result;
   1814 		if (type.is_array())
   1815 		{
   1816 			assert(type.array_length > 0); // Unsized arrays cannot be constants
   1817 
   1818 			auto elem_type = type;
   1819 			elem_type.array_length = 0;
   1820 
   1821 			std::vector<spv::Id> elements;
   1822 			elements.reserve(type.array_length);
   1823 
   1824 			// Fill up elements with constant array data
   1825 			for (const constant &elem : data.array_data)
   1826 				elements.push_back(emit_constant(elem_type, elem, spec_constant));
   1827 			// Fill up any remaining elements with a default value (when the array data did not specify them)
   1828 			for (size_t i = elements.size(); i < static_cast<size_t>(type.array_length); ++i)
   1829 				elements.push_back(emit_constant(elem_type, {}, spec_constant));
   1830 
   1831 			result = add_instruction(spec_constant ? spv::OpSpecConstantComposite : spv::OpConstantComposite, convert_type(type), _types_and_constants)
   1832 				.add(elements.begin(), elements.end())
   1833 				.result;
   1834 		}
   1835 		else if (type.is_struct())
   1836 		{
   1837 			assert(!spec_constant); // Structures cannot be specialization constants
   1838 
   1839 			result = add_instruction(spv::OpConstantNull, convert_type(type), _types_and_constants)
   1840 				.result;
   1841 		}
   1842 		else if (type.is_vector() || type.is_matrix())
   1843 		{
   1844 			auto elem_type = type;
   1845 			elem_type.rows = type.cols;
   1846 			elem_type.cols = 1;
   1847 
   1848 			spv::Id rows[4] = {};
   1849 
   1850 			// Construct matrix constant out of row vector constants
   1851 			// Construct vector constant out of scalar constants for each element
   1852 			for (unsigned int i = 0; i < type.rows; ++i)
   1853 			{
   1854 				constant row_data = {};
   1855 				for (unsigned int k = 0; k < type.cols; ++k)
   1856 					row_data.as_uint[k] = data.as_uint[i * type.cols + k];
   1857 
   1858 				rows[i] = emit_constant(elem_type, row_data, spec_constant);
   1859 			}
   1860 
   1861 			if (type.rows == 1)
   1862 			{
   1863 				result = rows[0];
   1864 			}
   1865 			else
   1866 			{
   1867 				spirv_instruction &node = add_instruction(spec_constant ? spv::OpSpecConstantComposite : spv::OpConstantComposite, convert_type(type), _types_and_constants);
   1868 				for (unsigned int i = 0; i < type.rows; ++i)
   1869 					node.add(rows[i]);
   1870 
   1871 				result = node.result;
   1872 			}
   1873 		}
   1874 		else if (type.is_boolean())
   1875 		{
   1876 			result = add_instruction(data.as_uint[0] ?
   1877 				(spec_constant ? spv::OpSpecConstantTrue : spv::OpConstantTrue) :
   1878 				(spec_constant ? spv::OpSpecConstantFalse : spv::OpConstantFalse), convert_type(type), _types_and_constants)
   1879 				.result;
   1880 		}
   1881 		else
   1882 		{
   1883 			assert(type.is_scalar());
   1884 
   1885 			result = add_instruction(spec_constant ? spv::OpSpecConstant : spv::OpConstant, convert_type(type), _types_and_constants)
   1886 				.add(data.as_uint[0])
   1887 				.result;
   1888 		}
   1889 
   1890 		if (spec_constant) // Keep track of all specialization constants
   1891 			_spec_constants.insert(result);
   1892 		else
   1893 			_constant_lookup.push_back({ type, data, result });
   1894 
   1895 		return result;
   1896 	}
   1897 
   1898 	id   emit_unary_op(const location &loc, tokenid op, const type &type, id val) override
   1899 	{
   1900 		spv::Op spv_op = spv::OpNop;
   1901 
   1902 		switch (op)
   1903 		{
   1904 		case tokenid::minus:
   1905 			spv_op = type.is_floating_point() ? spv::OpFNegate : spv::OpSNegate;
   1906 			break;
   1907 		case tokenid::tilde:
   1908 			spv_op = spv::OpNot;
   1909 			break;
   1910 		case tokenid::exclaim:
   1911 			spv_op = spv::OpLogicalNot;
   1912 			break;
   1913 		default:
   1914 			return assert(false), 0;
   1915 		}
   1916 
   1917 		add_location(loc, *_current_block_data);
   1918 
   1919 		spirv_instruction &inst = add_instruction(spv_op, convert_type(type));
   1920 		inst.add(val); // Operand
   1921 
   1922 		return inst.result;
   1923 	}
   1924 	id   emit_binary_op(const location &loc, tokenid op, const type &res_type, const type &type, id lhs, id rhs) override
   1925 	{
   1926 		spv::Op spv_op = spv::OpNop;
   1927 
   1928 		switch (op)
   1929 		{
   1930 		case tokenid::plus:
   1931 		case tokenid::plus_plus:
   1932 		case tokenid::plus_equal:
   1933 			spv_op = type.is_floating_point() ? spv::OpFAdd : spv::OpIAdd;
   1934 			break;
   1935 		case tokenid::minus:
   1936 		case tokenid::minus_minus:
   1937 		case tokenid::minus_equal:
   1938 			spv_op = type.is_floating_point() ? spv::OpFSub : spv::OpISub;
   1939 			break;
   1940 		case tokenid::star:
   1941 		case tokenid::star_equal:
   1942 			spv_op = type.is_floating_point() ? spv::OpFMul : spv::OpIMul;
   1943 			break;
   1944 		case tokenid::slash:
   1945 		case tokenid::slash_equal:
   1946 			spv_op = type.is_floating_point() ? spv::OpFDiv : type.is_signed() ? spv::OpSDiv : spv::OpUDiv;
   1947 			break;
   1948 		case tokenid::percent:
   1949 		case tokenid::percent_equal:
   1950 			spv_op = type.is_floating_point() ? spv::OpFRem : type.is_signed() ? spv::OpSRem : spv::OpUMod;
   1951 			break;
   1952 		case tokenid::caret:
   1953 		case tokenid::caret_equal:
   1954 			spv_op = spv::OpBitwiseXor;
   1955 			break;
   1956 		case tokenid::pipe:
   1957 		case tokenid::pipe_equal:
   1958 			spv_op = spv::OpBitwiseOr;
   1959 			break;
   1960 		case tokenid::ampersand:
   1961 		case tokenid::ampersand_equal:
   1962 			spv_op = spv::OpBitwiseAnd;
   1963 			break;
   1964 		case tokenid::less_less:
   1965 		case tokenid::less_less_equal:
   1966 			spv_op = spv::OpShiftLeftLogical;
   1967 			break;
   1968 		case tokenid::greater_greater:
   1969 		case tokenid::greater_greater_equal:
   1970 			spv_op = type.is_signed() ? spv::OpShiftRightArithmetic : spv::OpShiftRightLogical;
   1971 			break;
   1972 		case tokenid::pipe_pipe:
   1973 			spv_op = spv::OpLogicalOr;
   1974 			break;
   1975 		case tokenid::ampersand_ampersand:
   1976 			spv_op = spv::OpLogicalAnd;
   1977 			break;
   1978 		case tokenid::less:
   1979 			spv_op = type.is_floating_point() ? spv::OpFOrdLessThan :
   1980 				type.is_signed() ? spv::OpSLessThan : spv::OpULessThan;
   1981 			break;
   1982 		case tokenid::less_equal:
   1983 			spv_op = type.is_floating_point() ? spv::OpFOrdLessThanEqual :
   1984 				type.is_signed() ? spv::OpSLessThanEqual : spv::OpULessThanEqual;
   1985 			break;
   1986 		case tokenid::greater:
   1987 			spv_op = type.is_floating_point() ? spv::OpFOrdGreaterThan :
   1988 				type.is_signed() ? spv::OpSGreaterThan : spv::OpUGreaterThan;
   1989 			break;
   1990 		case tokenid::greater_equal:
   1991 			spv_op = type.is_floating_point() ? spv::OpFOrdGreaterThanEqual :
   1992 				type.is_signed() ? spv::OpSGreaterThanEqual : spv::OpUGreaterThanEqual;
   1993 			break;
   1994 		case tokenid::equal_equal:
   1995 			spv_op = type.is_floating_point() ? spv::OpFOrdEqual :
   1996 				type.is_boolean() ? spv::OpLogicalEqual : spv::OpIEqual;
   1997 			break;
   1998 		case tokenid::exclaim_equal:
   1999 			spv_op = type.is_floating_point() ? spv::OpFOrdNotEqual :
   2000 				type.is_boolean() ? spv::OpLogicalNotEqual : spv::OpINotEqual;
   2001 			break;
   2002 		default:
   2003 			return assert(false), 0;
   2004 		}
   2005 
   2006 		add_location(loc, *_current_block_data);
   2007 
   2008 		// Binary operators generally only work on scalars and vectors in SPIR-V, so need to apply them to matrices component-wise
   2009 		if (type.is_matrix() && type.rows != 1)
   2010 		{
   2011 			std::vector<spv::Id> ids;
   2012 			ids.reserve(type.cols);
   2013 
   2014 			auto vector_type = type;
   2015 			vector_type.rows = type.cols;
   2016 			vector_type.cols = 1;
   2017 
   2018 			for (unsigned int row = 0; row < type.rows; ++row)
   2019 			{
   2020 				const spv::Id lhs_elem = add_instruction(spv::OpCompositeExtract, convert_type(vector_type))
   2021 					.add(lhs)
   2022 					.add(row)
   2023 					.result;
   2024 				const spv::Id rhs_elem = add_instruction(spv::OpCompositeExtract, convert_type(vector_type))
   2025 					.add(rhs)
   2026 					.add(row)
   2027 					.result;
   2028 
   2029 				spirv_instruction &inst = add_instruction(spv_op, convert_type(vector_type));
   2030 				inst.add(lhs_elem); // Operand 1
   2031 				inst.add(rhs_elem); // Operand 2
   2032 
   2033 				if (res_type.has(type::q_precise))
   2034 					add_decoration(inst.result, spv::DecorationNoContraction);
   2035 				if (!_enable_16bit_types && res_type.precision() < 32)
   2036 					add_decoration(inst.result, spv::DecorationRelaxedPrecision);
   2037 
   2038 				ids.push_back(inst.result);
   2039 			}
   2040 
   2041 			spirv_instruction &inst = add_instruction(spv::OpCompositeConstruct, convert_type(res_type));
   2042 			inst.add(ids.begin(), ids.end());
   2043 
   2044 			return inst.result;
   2045 		}
   2046 		else
   2047 		{
   2048 			spirv_instruction &inst = add_instruction(spv_op, convert_type(res_type));
   2049 			inst.add(lhs); // Operand 1
   2050 			inst.add(rhs); // Operand 2
   2051 
   2052 			if (res_type.has(type::q_precise))
   2053 				add_decoration(inst.result, spv::DecorationNoContraction);
   2054 			if (!_enable_16bit_types && res_type.precision() < 32)
   2055 				add_decoration(inst.result, spv::DecorationRelaxedPrecision);
   2056 
   2057 			return inst.result;
   2058 		}
   2059 	}
   2060 	id   emit_ternary_op(const location &loc, tokenid op, const type &type, id condition, id true_value, id false_value) override
   2061 	{
   2062 		if (op != tokenid::question)
   2063 			return assert(false), 0;
   2064 
   2065 		add_location(loc, *_current_block_data);
   2066 
   2067 		spirv_instruction &inst = add_instruction(spv::OpSelect, convert_type(type));
   2068 		inst.add(condition); // Condition
   2069 		inst.add(true_value); // Object 1
   2070 		inst.add(false_value); // Object 2
   2071 
   2072 		return inst.result;
   2073 	}
   2074 	id   emit_call(const location &loc, id function, const type &res_type, const std::vector<expression> &args) override
   2075 	{
   2076 #ifndef NDEBUG
   2077 		for (const expression &arg : args)
   2078 			assert(arg.chain.empty() && arg.base != 0);
   2079 #endif
   2080 		add_location(loc, *_current_block_data);
   2081 
   2082 		// https://www.khronos.org/registry/spir-v/specs/unified1/SPIRV.html#OpFunctionCall
   2083 		spirv_instruction &inst = add_instruction(spv::OpFunctionCall, convert_type(res_type));
   2084 		inst.add(function); // Function
   2085 		for (const expression &arg : args)
   2086 			inst.add(arg.base); // Arguments
   2087 
   2088 		return inst.result;
   2089 	}
   2090 	id   emit_call_intrinsic(const location &loc, id intrinsic, const type &res_type, const std::vector<expression> &args) override
   2091 	{
   2092 #ifndef NDEBUG
   2093 		for (const expression &arg : args)
   2094 			assert(arg.chain.empty() && arg.base != 0);
   2095 #endif
   2096 		add_location(loc, *_current_block_data);
   2097 
   2098 		enum
   2099 		{
   2100 		#define IMPLEMENT_INTRINSIC_SPIRV(name, i, code) name##i,
   2101 			#include "effect_symbol_table_intrinsics.inl"
   2102 		};
   2103 
   2104 		switch (intrinsic)
   2105 		{
   2106 		#define IMPLEMENT_INTRINSIC_SPIRV(name, i, code) case name##i: code
   2107 			#include "effect_symbol_table_intrinsics.inl"
   2108 		default:
   2109 			return assert(false), 0;
   2110 		}
   2111 	}
   2112 	id   emit_construct(const location &loc, const type &type, const std::vector<expression> &args) override
   2113 	{
   2114 #ifndef NDEBUG
   2115 		for (const expression &arg : args)
   2116 			assert((arg.type.is_scalar() || type.is_array()) && arg.chain.empty() && arg.base != 0);
   2117 #endif
   2118 		add_location(loc, *_current_block_data);
   2119 
   2120 		std::vector<spv::Id> ids;
   2121 		ids.reserve(args.size());
   2122 
   2123 		// There must be exactly one constituent for each top-level component of the result
   2124 		if (type.is_matrix())
   2125 		{
   2126 			auto vector_type = type;
   2127 			vector_type.rows = type.cols;
   2128 			vector_type.cols = 1;
   2129 
   2130 			// Turn the list of scalar arguments into a list of column vectors
   2131 			for (size_t arg = 0; arg < args.size(); arg += vector_type.rows)
   2132 			{
   2133 				spirv_instruction &inst = add_instruction(spv::OpCompositeConstruct, convert_type(vector_type));
   2134 				for (unsigned row = 0; row < vector_type.rows; ++row)
   2135 					inst.add(args[arg + row].base);
   2136 
   2137 				ids.push_back(inst.result);
   2138 			}
   2139 		}
   2140 		else
   2141 		{
   2142 			assert(type.is_vector() || type.is_array());
   2143 
   2144 			// The exception is that for constructing a vector, a contiguous subset of the scalars consumed can be represented by a vector operand instead
   2145 			for (const expression &arg : args)
   2146 				ids.push_back(arg.base);
   2147 		}
   2148 
   2149 		spirv_instruction &inst = add_instruction(spv::OpCompositeConstruct, convert_type(type));
   2150 		inst.add(ids.begin(), ids.end());
   2151 
   2152 		return inst.result;
   2153 	}
   2154 
   2155 	void emit_if(const location &loc, id, id condition_block, id true_statement_block, id false_statement_block, unsigned int selection_control) override
   2156 	{
   2157 		spirv_instruction merge_label = _current_block_data->instructions.back();
   2158 		assert(merge_label.op == spv::OpLabel);
   2159 		_current_block_data->instructions.pop_back();
   2160 
   2161 		// Add previous block containing the condition value first
   2162 		_current_block_data->append(_block_data[condition_block]);
   2163 
   2164 		spirv_instruction branch_inst = _current_block_data->instructions.back();
   2165 		assert(branch_inst.op == spv::OpBranchConditional);
   2166 		_current_block_data->instructions.pop_back();
   2167 
   2168 		// Add structured control flow instruction
   2169 		add_location(loc, *_current_block_data);
   2170 		add_instruction_without_result(spv::OpSelectionMerge)
   2171 			.add(merge_label.result)
   2172 			.add(selection_control & 0x3); // 'SelectionControl' happens to match the flags produced by the parser
   2173 
   2174 		// Append all blocks belonging to the branch
   2175 		_current_block_data->instructions.push_back(branch_inst);
   2176 		_current_block_data->append(_block_data[true_statement_block]);
   2177 		_current_block_data->append(_block_data[false_statement_block]);
   2178 
   2179 		_current_block_data->instructions.push_back(merge_label);
   2180 	}
   2181 	id   emit_phi(const location &loc, id, id condition_block, id true_value, id true_statement_block, id false_value, id false_statement_block, const type &type) override
   2182 	{
   2183 		spirv_instruction merge_label = _current_block_data->instructions.back();
   2184 		assert(merge_label.op == spv::OpLabel);
   2185 		_current_block_data->instructions.pop_back();
   2186 
   2187 		// Add previous block containing the condition value first
   2188 		_current_block_data->append(_block_data[condition_block]);
   2189 
   2190 		if (true_statement_block != condition_block)
   2191 			_current_block_data->append(_block_data[true_statement_block]);
   2192 		if (false_statement_block != condition_block)
   2193 			_current_block_data->append(_block_data[false_statement_block]);
   2194 
   2195 		_current_block_data->instructions.push_back(merge_label);
   2196 
   2197 		add_location(loc, *_current_block_data);
   2198 
   2199 		// https://www.khronos.org/registry/spir-v/specs/unified1/SPIRV.html#OpPhi
   2200 		spirv_instruction &inst = add_instruction(spv::OpPhi, convert_type(type))
   2201 			.add(true_value) // Variable 0
   2202 			.add(true_statement_block) // Parent 0
   2203 			.add(false_value) // Variable 1
   2204 			.add(false_statement_block); // Parent 1
   2205 
   2206 		return inst.result;
   2207 	}
   2208 	void emit_loop(const location &loc, id, id prev_block, id header_block, id condition_block, id loop_block, id continue_block, unsigned int loop_control) override
   2209 	{
   2210 		spirv_instruction merge_label = _current_block_data->instructions.back();
   2211 		assert(merge_label.op == spv::OpLabel);
   2212 		_current_block_data->instructions.pop_back();
   2213 
   2214 		// Add previous block first
   2215 		_current_block_data->append(_block_data[prev_block]);
   2216 
   2217 		// Fill header block
   2218 		assert(_block_data[header_block].instructions.size() == 2);
   2219 		_current_block_data->instructions.push_back(_block_data[header_block].instructions[0]);
   2220 		assert(_current_block_data->instructions.back().op == spv::OpLabel);
   2221 
   2222 		// Add structured control flow instruction
   2223 		add_location(loc, *_current_block_data);
   2224 		add_instruction_without_result(spv::OpLoopMerge)
   2225 			.add(merge_label.result)
   2226 			.add(continue_block)
   2227 			.add(loop_control & 0x3); // 'LoopControl' happens to match the flags produced by the parser
   2228 
   2229 		_current_block_data->instructions.push_back(_block_data[header_block].instructions[1]);
   2230 		assert(_current_block_data->instructions.back().op == spv::OpBranch);
   2231 
   2232 		// Add condition block if it exists
   2233 		if (condition_block != 0)
   2234 			_current_block_data->append(_block_data[condition_block]);
   2235 
   2236 		// Append loop body block before continue block
   2237 		_current_block_data->append(_block_data[loop_block]);
   2238 		_current_block_data->append(_block_data[continue_block]);
   2239 
   2240 		_current_block_data->instructions.push_back(merge_label);
   2241 	}
   2242 	void emit_switch(const location &loc, id, id selector_block, id default_label, id default_block, const std::vector<id> &case_literal_and_labels, const std::vector<id> &case_blocks, unsigned int selection_control) override
   2243 	{
   2244 		assert(case_blocks.size() == case_literal_and_labels.size() / 2);
   2245 
   2246 		spirv_instruction merge_label = _current_block_data->instructions.back();
   2247 		assert(merge_label.op == spv::OpLabel);
   2248 		_current_block_data->instructions.pop_back();
   2249 
   2250 		// Add previous block containing the selector value first
   2251 		_current_block_data->append(_block_data[selector_block]);
   2252 
   2253 		spirv_instruction switch_inst = _current_block_data->instructions.back();
   2254 		assert(switch_inst.op == spv::OpSwitch);
   2255 		_current_block_data->instructions.pop_back();
   2256 
   2257 		// Add structured control flow instruction
   2258 		add_location(loc, *_current_block_data);
   2259 		add_instruction_without_result(spv::OpSelectionMerge)
   2260 			.add(merge_label.result)
   2261 			.add(selection_control & 0x3); // 'SelectionControl' happens to match the flags produced by the parser
   2262 
   2263 		// Update switch instruction to contain all case labels
   2264 		switch_inst.operands[1] = default_label;
   2265 		switch_inst.add(case_literal_and_labels.begin(), case_literal_and_labels.end());
   2266 
   2267 		// Append all blocks belonging to the switch
   2268 		_current_block_data->instructions.push_back(switch_inst);
   2269 
   2270 		std::vector<id> blocks = case_blocks;
   2271 		if (default_label != merge_label.result)
   2272 			blocks.push_back(default_block);
   2273 		// Eliminate duplicates (because of multiple case labels pointing to the same block)
   2274 		std::sort(blocks.begin(), blocks.end());
   2275 		blocks.erase(std::unique(blocks.begin(), blocks.end()), blocks.end());
   2276 		for (const id case_block : blocks)
   2277 			_current_block_data->append(_block_data[case_block]);
   2278 
   2279 		_current_block_data->instructions.push_back(merge_label);
   2280 	}
   2281 
   2282 	bool is_in_function() const override { return _current_function != nullptr; }
   2283 
   2284 	id   set_block(id id) override
   2285 	{
   2286 		_last_block = _current_block;
   2287 		_current_block = id;
   2288 		_current_block_data = &_block_data[id];
   2289 
   2290 		return _last_block;
   2291 	}
   2292 	void enter_block(id id) override
   2293 	{
   2294 		assert(id != 0);
   2295 		// Can only use labels inside functions and should never be in another basic block if creating a new one
   2296 		assert(is_in_function() && !is_in_block());
   2297 
   2298 		set_block(id);
   2299 
   2300 		add_instruction_without_result(spv::OpLabel)
   2301 			.result = id;
   2302 	}
   2303 	id   leave_block_and_kill() override
   2304 	{
   2305 		assert(is_in_function()); // Can only discard inside functions
   2306 
   2307 		if (!is_in_block())
   2308 			return 0;
   2309 
   2310 		add_instruction_without_result(spv::OpKill);
   2311 
   2312 		return set_block(0);
   2313 	}
   2314 	id   leave_block_and_return(id value) override
   2315 	{
   2316 		assert(is_in_function()); // Can only return from inside functions
   2317 
   2318 		if (!is_in_block()) // Might already have left the last block in which case this has to be ignored
   2319 			return 0;
   2320 
   2321 		if (_current_function->return_type.is_void())
   2322 		{
   2323 			add_instruction_without_result(spv::OpReturn);
   2324 		}
   2325 		else
   2326 		{
   2327 			if (0 == value) // The implicit return statement needs this
   2328 				value = add_instruction(spv::OpUndef, convert_type(_current_function->return_type), _types_and_constants).result;
   2329 
   2330 			add_instruction_without_result(spv::OpReturnValue)
   2331 				.add(value);
   2332 		}
   2333 
   2334 		return set_block(0);
   2335 	}
   2336 	id   leave_block_and_switch(id value, id default_target) override
   2337 	{
   2338 		assert(value != 0 && default_target != 0);
   2339 		assert(is_in_function()); // Can only switch inside functions
   2340 
   2341 		if (!is_in_block())
   2342 			return _last_block;
   2343 
   2344 		add_instruction_without_result(spv::OpSwitch)
   2345 			.add(value)
   2346 			.add(default_target);
   2347 
   2348 		return set_block(0);
   2349 	}
   2350 	id   leave_block_and_branch(id target, unsigned int) override
   2351 	{
   2352 		assert(target != 0);
   2353 		assert(is_in_function()); // Can only branch inside functions
   2354 
   2355 		if (!is_in_block())
   2356 			return _last_block;
   2357 
   2358 		add_instruction_without_result(spv::OpBranch)
   2359 			.add(target);
   2360 
   2361 		return set_block(0);
   2362 	}
   2363 	id   leave_block_and_branch_conditional(id condition, id true_target, id false_target) override
   2364 	{
   2365 		assert(condition != 0 && true_target != 0 && false_target != 0);
   2366 		assert(is_in_function()); // Can only branch inside functions
   2367 
   2368 		if (!is_in_block())
   2369 			return _last_block;
   2370 
   2371 		add_instruction_without_result(spv::OpBranchConditional)
   2372 			.add(condition)
   2373 			.add(true_target)
   2374 			.add(false_target);
   2375 
   2376 		return set_block(0);
   2377 	}
   2378 	void leave_function() override
   2379 	{
   2380 		assert(is_in_function()); // Can only leave if there was a function to begin with
   2381 
   2382 		_current_function->definition = _block_data[_last_block];
   2383 
   2384 		// Append function end instruction
   2385 		add_instruction_without_result(spv::OpFunctionEnd, _current_function->definition);
   2386 
   2387 		_current_function = nullptr;
   2388 	}
   2389 };
   2390 
   2391 codegen *reshadefx::create_codegen_spirv(bool vulkan_semantics, bool debug_info, bool uniforms_to_spec_constants, bool enable_16bit_types, bool flip_vert_y)
   2392 {
   2393 	return new codegen_spirv(vulkan_semantics, debug_info, uniforms_to_spec_constants, enable_16bit_types, flip_vert_y);
   2394 }