diff --git a/src/xenia/gpu/spirv/spirv_compiler.cc b/src/xenia/gpu/spirv/spirv_compiler.cc index e4a1bde6d..4d0cde2eb 100644 --- a/src/xenia/gpu/spirv/spirv_compiler.cc +++ b/src/xenia/gpu/spirv/spirv_compiler.cc @@ -41,16 +41,16 @@ OpFunctionEnd spv_disasm.Disassemble(asm_result->words(), asm_result->word_count()); SpvEmitter e; - auto glsl_std_450 = e.import("GLSL.std.450"); - auto fn = e.makeMain(); - auto float_1_0 = e.makeFloatConstant(1.0f); - auto acos = e.createBuiltinCall( - spv::Decoration::Invariant, e.makeFloatType(32), glsl_std_450, + auto glsl_std_450 = e.ImportExtendedInstructions("GLSL.std.450"); + auto fn = e.MakeMainEntry(); + auto float_1_0 = e.MakeFloatConstant(1.0f); + auto acos = e.CreateExtendedInstructionCall( + spv::Decoration::Invariant, e.MakeFloatType(32), glsl_std_450, static_cast(spv::GLSLstd450::Acos), {{float_1_0}}); - e.makeReturn(false); + e.MakeReturn(true); std::vector words; - e.dump(words); + e.Serialize(words); auto disasm_result2 = spv_disasm.Disassemble(words.data(), words.size()); diff --git a/src/xenia/gpu/spirv/spv_emitter.cc b/src/xenia/gpu/spirv/spv_emitter.cc index 9a3b0a039..690334551 100644 --- a/src/xenia/gpu/spirv/spv_emitter.cc +++ b/src/xenia/gpu/spirv/spv_emitter.cc @@ -54,29 +54,29 @@ namespace xe { namespace gpu { namespace spirv { -SpvEmitter::SpvEmitter() { clearAccessChain(); } +SpvEmitter::SpvEmitter() { ClearAccessChain(); } SpvEmitter::~SpvEmitter() = default; -Id SpvEmitter::import(const char* name) { - auto import = new Instruction(getUniqueId(), NoType, Op::OpExtInstImport); - import->addStringOperand(name); +Id SpvEmitter::ImportExtendedInstructions(const char* name) { + auto import = + new Instruction(AllocateUniqueId(), NoType, Op::OpExtInstImport); + import->AddStringOperand(name); imports_.push_back(import); return import->result_id(); } // For creating new grouped_types_ (will return old type if the requested one -// was -// already made). -Id SpvEmitter::makeVoidType() { +// was already made). +Id SpvEmitter::MakeVoidType() { Instruction* type; auto& grouped_type = grouped_types_[static_cast(Op::OpTypeVoid)]; if (grouped_type.empty()) { - type = new Instruction(getUniqueId(), NoType, Op::OpTypeVoid); + type = new Instruction(AllocateUniqueId(), NoType, Op::OpTypeVoid); grouped_type.push_back(type); constants_types_globals_.push_back(type); - module_.mapInstruction(type); + module_.MapInstruction(type); } else { type = grouped_type.back(); } @@ -84,14 +84,14 @@ Id SpvEmitter::makeVoidType() { return type->result_id(); } -Id SpvEmitter::makeBoolType() { +Id SpvEmitter::MakeBoolType() { Instruction* type; auto& grouped_type = grouped_types_[static_cast(Op::OpTypeBool)]; if (grouped_type.empty()) { - type = new Instruction(getUniqueId(), NoType, Op::OpTypeBool); + type = new Instruction(AllocateUniqueId(), NoType, Op::OpTypeBool); grouped_type.push_back(type); constants_types_globals_.push_back(type); - module_.mapInstruction(type); + module_.MapInstruction(type); } else { type = grouped_type.back(); } @@ -99,22 +99,21 @@ Id SpvEmitter::makeBoolType() { return type->result_id(); } -Id SpvEmitter::makeSamplerType() { +Id SpvEmitter::MakeSamplerType() { Instruction* type; auto& grouped_type = grouped_types_[static_cast(Op::OpTypeSampler)]; if (grouped_type.empty()) { - type = new Instruction(getUniqueId(), NoType, Op::OpTypeSampler); + type = new Instruction(AllocateUniqueId(), NoType, Op::OpTypeSampler); grouped_type.push_back(type); constants_types_globals_.push_back(type); - module_.mapInstruction(type); + module_.MapInstruction(type); } else { type = grouped_type.back(); } - return type->result_id(); } -Id SpvEmitter::makePointer(spv::StorageClass storage_class, Id pointee) { +Id SpvEmitter::MakePointer(spv::StorageClass storage_class, Id pointee) { // try to find it auto& grouped_type = grouped_types_[static_cast(Op::OpTypePointer)]; for (auto& type : grouped_type) { @@ -125,52 +124,52 @@ Id SpvEmitter::makePointer(spv::StorageClass storage_class, Id pointee) { } // not found, make it - auto type = new Instruction(getUniqueId(), NoType, Op::OpTypePointer); - type->addImmediateOperand(storage_class); - type->addIdOperand(pointee); + auto type = new Instruction(AllocateUniqueId(), NoType, Op::OpTypePointer); + type->AddImmediateOperand(storage_class); + type->AddIdOperand(pointee); grouped_type.push_back(type); constants_types_globals_.push_back(type); - module_.mapInstruction(type); + module_.MapInstruction(type); return type->result_id(); } -Id SpvEmitter::makeIntegerType(int width, bool hasSign) { +Id SpvEmitter::MakeIntegerType(int bit_width, bool is_signed) { // try to find it auto& grouped_type = grouped_types_[static_cast(Op::OpTypeInt)]; for (auto& type : grouped_type) { - if (type->immediate_operand(0) == (unsigned)width && - type->immediate_operand(1) == (hasSign ? 1u : 0u)) { + if (type->immediate_operand(0) == (unsigned)bit_width && + type->immediate_operand(1) == (is_signed ? 1u : 0u)) { return type->result_id(); } } // not found, make it - auto type = new Instruction(getUniqueId(), NoType, Op::OpTypeInt); - type->addImmediateOperand(width); - type->addImmediateOperand(hasSign ? 1 : 0); + auto type = new Instruction(AllocateUniqueId(), NoType, Op::OpTypeInt); + type->AddImmediateOperand(bit_width); + type->AddImmediateOperand(is_signed ? 1 : 0); grouped_type.push_back(type); constants_types_globals_.push_back(type); - module_.mapInstruction(type); + module_.MapInstruction(type); return type->result_id(); } -Id SpvEmitter::makeFloatType(int width) { +Id SpvEmitter::MakeFloatType(int bit_width) { // try to find it auto& grouped_type = grouped_types_[static_cast(Op::OpTypeFloat)]; for (auto& type : grouped_type) { - if (type->immediate_operand(0) == (unsigned)width) { + if (type->immediate_operand(0) == (unsigned)bit_width) { return type->result_id(); } } // not found, make it - auto type = new Instruction(getUniqueId(), NoType, Op::OpTypeFloat); - type->addImmediateOperand(width); + auto type = new Instruction(AllocateUniqueId(), NoType, Op::OpTypeFloat); + type->AddImmediateOperand(bit_width); grouped_type.push_back(type); constants_types_globals_.push_back(type); - module_.mapInstruction(type); + module_.MapInstruction(type); return type->result_id(); } @@ -179,25 +178,27 @@ Id SpvEmitter::makeFloatType(int width) { // See makeStructResultType() for non-decorated structs // needed as the result of some instructions, which does // check for duplicates. -Id SpvEmitter::makeStructType(std::vector& members, const char* name) { +Id SpvEmitter::MakeStructType(std::initializer_list members, + const char* name) { // Don't look for previous one, because in the general case, // structs can be duplicated except for decorations. // not found, make it - Instruction* type = new Instruction(getUniqueId(), NoType, Op::OpTypeStruct); - type->addIdOperands(members); + Instruction* type = + new Instruction(AllocateUniqueId(), NoType, Op::OpTypeStruct); + type->AddIdOperands(members); auto& grouped_type = grouped_types_[static_cast(Op::OpTypeStruct)]; grouped_type.push_back(type); constants_types_globals_.push_back(type); - module_.mapInstruction(type); - addName(type->result_id(), name); + module_.MapInstruction(type); + AddName(type->result_id(), name); return type->result_id(); } // Make a struct for the simple results of several instructions, // checking for duplication. -Id SpvEmitter::makeStructResultType(Id type0, Id type1) { +Id SpvEmitter::MakePairStructType(Id type0, Id type1) { // try to find it auto& grouped_type = grouped_types_[static_cast(Op::OpTypeStruct)]; for (auto& type : grouped_type) { @@ -211,38 +212,34 @@ Id SpvEmitter::makeStructResultType(Id type0, Id type1) { } // not found, make it - std::vector members; - members.push_back(type0); - members.push_back(type1); - - return makeStructType(members, "ResType"); + return MakeStructType({type0, type1}, "ResType"); } -Id SpvEmitter::makeVectorType(Id component, int size) { +Id SpvEmitter::MakeVectorType(Id component_type, int component_count) { // try to find it auto& grouped_type = grouped_types_[static_cast(Op::OpTypeVector)]; for (auto& type : grouped_type) { - if (type->id_operand(0) == component && - type->immediate_operand(1) == (unsigned)size) { + if (type->id_operand(0) == component_type && + type->immediate_operand(1) == (unsigned)component_count) { return type->result_id(); } } // not found, make it - auto type = new Instruction(getUniqueId(), NoType, Op::OpTypeVector); - type->addIdOperand(component); - type->addImmediateOperand(size); + auto type = new Instruction(AllocateUniqueId(), NoType, Op::OpTypeVector); + type->AddIdOperand(component_type); + type->AddImmediateOperand(component_count); grouped_type.push_back(type); constants_types_globals_.push_back(type); - module_.mapInstruction(type); + module_.MapInstruction(type); return type->result_id(); } -Id SpvEmitter::makeMatrixType(Id component, int cols, int rows) { +Id SpvEmitter::MakeMatrix2DType(Id component_type, int cols, int rows) { assert(cols <= kMaxMatrixSize && rows <= kMaxMatrixSize); - Id column = makeVectorType(component, rows); + Id column = MakeVectorType(component_type, rows); // try to find it auto& grouped_type = grouped_types_[static_cast(Op::OpTypeMatrix)]; @@ -254,142 +251,144 @@ Id SpvEmitter::makeMatrixType(Id component, int cols, int rows) { } // not found, make it - auto type = new Instruction(getUniqueId(), NoType, Op::OpTypeMatrix); - type->addIdOperand(column); - type->addImmediateOperand(cols); + auto type = new Instruction(AllocateUniqueId(), NoType, Op::OpTypeMatrix); + type->AddIdOperand(column); + type->AddImmediateOperand(cols); grouped_type.push_back(type); constants_types_globals_.push_back(type); - module_.mapInstruction(type); + module_.MapInstruction(type); return type->result_id(); } -Id SpvEmitter::makeArrayType(Id element, unsigned size) { +Id SpvEmitter::MakeArrayType(Id element_type, int length) { // First, we need a constant instruction for the size - Id sizeId = makeUintConstant(size); + Id length_id = MakeUintConstant(length); // try to find existing type auto& grouped_type = grouped_types_[static_cast(Op::OpTypeArray)]; for (auto& type : grouped_type) { - if (type->id_operand(0) == element && type->id_operand(1) == sizeId) { + if (type->id_operand(0) == element_type && + type->id_operand(1) == length_id) { return type->result_id(); } } // not found, make it - auto type = new Instruction(getUniqueId(), NoType, Op::OpTypeArray); - type->addIdOperand(element); - type->addIdOperand(sizeId); + auto type = new Instruction(AllocateUniqueId(), NoType, Op::OpTypeArray); + type->AddIdOperand(element_type); + type->AddIdOperand(length_id); grouped_type.push_back(type); constants_types_globals_.push_back(type); - module_.mapInstruction(type); + module_.MapInstruction(type); return type->result_id(); } -Id SpvEmitter::makeRuntimeArray(Id element) { - Instruction* type = - new Instruction(getUniqueId(), NoType, Op::OpTypeRuntimeArray); - type->addIdOperand(element); +Id SpvEmitter::MakeRuntimeArray(Id element_type) { + auto type = + new Instruction(AllocateUniqueId(), NoType, Op::OpTypeRuntimeArray); + type->AddIdOperand(element_type); constants_types_globals_.push_back(type); - module_.mapInstruction(type); + module_.MapInstruction(type); return type->result_id(); } -Id SpvEmitter::makeFunctionType(Id return_type, std::vector& param_types) { +Id SpvEmitter::MakeFunctionType(Id return_type, + std::initializer_list param_types) { // try to find it auto& grouped_type = grouped_types_[static_cast(Op::OpTypeFunction)]; for (auto& type : grouped_type) { - if (type->id_operand(0) != return_type || - (int)param_types.size() != type->operand_count() - 1) { - continue; - } - bool mismatch = false; - for (int p = 0; p < (int)param_types.size(); ++p) { - if (param_types[p] != type->id_operand(p + 1)) { - mismatch = true; - break; + if (type->id_operand(0) == return_type && + param_types.size() == type->operand_count() - 1) { + bool mismatch = false; + for (int i = 0; i < param_types.size(); ++i) { + if (type->id_operand(i + 1) != *(param_types.begin() + i)) { + mismatch = true; + break; + } + } + if (!mismatch) { + return type->result_id(); } - } - if (!mismatch) { - return type->result_id(); } } // not found, make it - auto type = new Instruction(getUniqueId(), NoType, Op::OpTypeFunction); - type->addIdOperand(return_type); - type->addIdOperands(param_types); + auto type = new Instruction(AllocateUniqueId(), NoType, Op::OpTypeFunction); + type->AddIdOperand(return_type); + type->AddIdOperands(param_types); grouped_type.push_back(type); constants_types_globals_.push_back(type); - module_.mapInstruction(type); + module_.MapInstruction(type); return type->result_id(); } -Id SpvEmitter::makeImageType(Id sampledType, spv::Dim dim, bool depth, - bool arrayed, bool ms, unsigned sampled, +Id SpvEmitter::MakeImageType(Id sampled_type, spv::Dim dim, bool has_depth, + bool is_arrayed, bool is_multisampled, int sampled, spv::ImageFormat format) { // try to find it auto& grouped_type = grouped_types_[static_cast(Op::OpTypeImage)]; for (auto& type : grouped_type) { - if (type->id_operand(0) == sampledType && + if (type->id_operand(0) == sampled_type && type->immediate_operand(1) == (unsigned int)dim && - type->immediate_operand(2) == (depth ? 1u : 0u) && - type->immediate_operand(3) == (arrayed ? 1u : 0u) && - type->immediate_operand(4) == (ms ? 1u : 0u) && + type->immediate_operand(2) == (has_depth ? 1u : 0u) && + type->immediate_operand(3) == (is_arrayed ? 1u : 0u) && + type->immediate_operand(4) == (is_multisampled ? 1u : 0u) && type->immediate_operand(5) == sampled && - type->immediate_operand(6) == (unsigned int)format) { + type->immediate_operand(6) == static_cast(format)) { return type->result_id(); } } // not found, make it - auto type = new Instruction(getUniqueId(), NoType, Op::OpTypeImage); - type->addIdOperand(sampledType); - type->addImmediateOperand(dim); - type->addImmediateOperand(depth ? 1 : 0); - type->addImmediateOperand(arrayed ? 1 : 0); - type->addImmediateOperand(ms ? 1 : 0); - type->addImmediateOperand(sampled); - type->addImmediateOperand((unsigned int)format); + auto type = new Instruction(AllocateUniqueId(), NoType, Op::OpTypeImage); + type->AddIdOperand(sampled_type); + type->AddImmediateOperand(dim); + type->AddImmediateOperand(has_depth ? 1 : 0); + type->AddImmediateOperand(is_arrayed ? 1 : 0); + type->AddImmediateOperand(is_multisampled ? 1 : 0); + type->AddImmediateOperand(sampled); + type->AddImmediateOperand(format); grouped_type.push_back(type); constants_types_globals_.push_back(type); - module_.mapInstruction(type); + module_.MapInstruction(type); return type->result_id(); } -Id SpvEmitter::makeSampledImageType(Id imageType) { +Id SpvEmitter::MakeSampledImageType(Id image_type) { // try to find it auto& grouped_type = grouped_types_[static_cast(Op::OpTypeSampledImage)]; for (auto& type : grouped_type) { - if (type->id_operand(0) == imageType) { + if (type->id_operand(0) == image_type) { return type->result_id(); } } // not found, make it - auto type = new Instruction(getUniqueId(), NoType, Op::OpTypeSampledImage); - type->addIdOperand(imageType); + auto type = + new Instruction(AllocateUniqueId(), NoType, Op::OpTypeSampledImage); + type->AddIdOperand(image_type); grouped_type.push_back(type); constants_types_globals_.push_back(type); - module_.mapInstruction(type); + module_.MapInstruction(type); return type->result_id(); } -Id SpvEmitter::getDerefTypeId(Id result_id) const { - Id type_id = getTypeId(result_id); - assert(isPointerType(type_id)); - return module_.getInstruction(type_id)->immediate_operand(1); +Id SpvEmitter::GetDerefTypeId(Id result_id) const { + Id type_id = GetTypeId(result_id); + assert(IsPointerType(type_id)); + return module_.instruction(type_id)->immediate_operand(1); } -Op SpvEmitter::getMostBasicTypeClass(Id type_id) const { - auto instr = module_.getInstruction(type_id); +Op SpvEmitter::GetMostBasicTypeClass(Id type_id) const { + auto instr = module_.instruction(type_id); Op type_class = instr->opcode(); switch (type_class) { @@ -403,17 +402,17 @@ Op SpvEmitter::getMostBasicTypeClass(Id type_id) const { case Op::OpTypeMatrix: case Op::OpTypeArray: case Op::OpTypeRuntimeArray: - return getMostBasicTypeClass(instr->id_operand(0)); + return GetMostBasicTypeClass(instr->id_operand(0)); case Op::OpTypePointer: - return getMostBasicTypeClass(instr->id_operand(1)); + return GetMostBasicTypeClass(instr->id_operand(1)); default: assert(0); return Op::OpTypeFloat; } } -int SpvEmitter::getNumTypeComponents(Id type_id) const { - auto instr = module_.getInstruction(type_id); +int SpvEmitter::GetTypeComponentCount(Id type_id) const { + auto instr = module_.instruction(type_id); switch (instr->opcode()) { case Op::OpTypeBool: @@ -435,8 +434,8 @@ int SpvEmitter::getNumTypeComponents(Id type_id) const { // floats. // However, it includes returning a structure, if say, it is an array of // structure. -Id SpvEmitter::getScalarTypeId(Id type_id) const { - auto instr = module_.getInstruction(type_id); +Id SpvEmitter::GetScalarTypeId(Id type_id) const { + auto instr = module_.instruction(type_id); Op type_class = instr->opcode(); switch (type_class) { @@ -451,7 +450,7 @@ Id SpvEmitter::getScalarTypeId(Id type_id) const { case Op::OpTypeArray: case Op::OpTypeRuntimeArray: case Op::OpTypePointer: - return getScalarTypeId(getContainedTypeId(type_id)); + return GetScalarTypeId(GetContainedTypeId(type_id)); default: assert(0); return NoResult; @@ -459,8 +458,8 @@ Id SpvEmitter::getScalarTypeId(Id type_id) const { } // Return the type of 'member' of a composite. -Id SpvEmitter::getContainedTypeId(Id type_id, int member) const { - auto instr = module_.getInstruction(type_id); +Id SpvEmitter::GetContainedTypeId(Id type_id, int member) const { + auto instr = module_.instruction(type_id); Op type_class = instr->opcode(); switch (type_class) { @@ -480,16 +479,16 @@ Id SpvEmitter::getContainedTypeId(Id type_id, int member) const { } // Return the immediately contained type of a given composite type. -Id SpvEmitter::getContainedTypeId(Id type_id) const { - return getContainedTypeId(type_id, 0); +Id SpvEmitter::GetContainedTypeId(Id type_id) const { + return GetContainedTypeId(type_id, 0); } // See if a scalar constant of this type has already been created, so it // can be reused rather than duplicated. (Required by the specification). -Id SpvEmitter::findScalarConstant(Op type_class, Op opcode, Id type_id, - unsigned value) const { +Id SpvEmitter::FindScalarConstant(Op type_class, Op opcode, Id type_id, + uint32_t value) const { auto& grouped_constant = grouped_constants_[static_cast(type_class)]; - for (auto& constant : grouped_constant) { + for (auto constant : grouped_constant) { if (constant->opcode() == opcode && constant->type_id() == type_id && constant->immediate_operand(0) == value) { return constant->result_id(); @@ -500,10 +499,10 @@ Id SpvEmitter::findScalarConstant(Op type_class, Op opcode, Id type_id, // Version of findScalarConstant (see above) for scalars that take two operands // (e.g. a 'double'). -Id SpvEmitter::findScalarConstant(Op type_class, Op opcode, Id type_id, - unsigned v1, unsigned v2) const { +Id SpvEmitter::FindScalarConstant(Op type_class, Op opcode, Id type_id, + uint32_t v1, uint32_t v2) const { auto& grouped_constant = grouped_constants_[static_cast(type_class)]; - for (auto& constant : grouped_constant) { + for (auto constant : grouped_constant) { if (constant->opcode() == opcode && constant->type_id() == type_id && constant->immediate_operand(0) == v1 && constant->immediate_operand(1) == v2) { @@ -516,7 +515,7 @@ Id SpvEmitter::findScalarConstant(Op type_class, Op opcode, Id type_id, // Return true if consuming 'opcode' means consuming a constant. // "constant" here means after final transform to executable code, // the value consumed will be a constant, so includes specialization. -bool SpvEmitter::isConstantOpCode(Op opcode) const { +bool SpvEmitter::IsConstantOpCode(Op opcode) const { switch (opcode) { case Op::OpUndef: case Op::OpConstantTrue: @@ -536,120 +535,116 @@ bool SpvEmitter::isConstantOpCode(Op opcode) const { } } -Id SpvEmitter::makeBoolConstant(bool b, bool is_spec_constant) { - Id type_id = makeBoolType(); +Id SpvEmitter::MakeBoolConstant(bool value, bool is_spec_constant) { + Id type_id = MakeBoolType(); Op opcode = is_spec_constant - ? (b ? Op::OpSpecConstantTrue : Op::OpSpecConstantFalse) - : (b ? Op::OpConstantTrue : Op::OpConstantFalse); + ? (value ? Op::OpSpecConstantTrue : Op::OpSpecConstantFalse) + : (value ? Op::OpConstantTrue : Op::OpConstantFalse); // See if we already made it Id existing = 0; auto& grouped_constant = grouped_constants_[static_cast(Op::OpTypeBool)]; for (auto& constant : grouped_constant) { if (constant->type_id() == type_id && constant->opcode() == opcode) { - existing = constant->result_id(); + return constant->result_id(); } } - if (existing) { - return existing; - } // Make it - auto c = new Instruction(getUniqueId(), type_id, opcode); + auto c = new Instruction(AllocateUniqueId(), type_id, opcode); constants_types_globals_.push_back(c); grouped_constants_[static_cast(Op::OpTypeBool)].push_back(c); - module_.mapInstruction(c); + module_.MapInstruction(c); return c->result_id(); } -Id SpvEmitter::makeIntConstant(Id type_id, unsigned value, - bool is_spec_constant) { +Id SpvEmitter::MakeIntegerConstant(Id type_id, uint32_t value, + bool is_spec_constant) { Op opcode = is_spec_constant ? Op::OpSpecConstant : Op::OpConstant; - Id existing = findScalarConstant(Op::OpTypeInt, opcode, type_id, value); + Id existing = FindScalarConstant(Op::OpTypeInt, opcode, type_id, value); if (existing) { return existing; } - auto c = new Instruction(getUniqueId(), type_id, opcode); - c->addImmediateOperand(value); + auto c = new Instruction(AllocateUniqueId(), type_id, opcode); + c->AddImmediateOperand(value); constants_types_globals_.push_back(c); grouped_constants_[static_cast(Op::OpTypeInt)].push_back(c); - module_.mapInstruction(c); + module_.MapInstruction(c); return c->result_id(); } -Id SpvEmitter::makeFloatConstant(float f, bool is_spec_constant) { +Id SpvEmitter::MakeFloatConstant(float value, bool is_spec_constant) { Op opcode = is_spec_constant ? Op::OpSpecConstant : Op::OpConstant; - Id type_id = makeFloatType(32); - unsigned value = *(unsigned int*)&f; - Id existing = findScalarConstant(Op::OpTypeFloat, opcode, type_id, value); + Id type_id = MakeFloatType(32); + uint32_t uint32_value = *reinterpret_cast(&value); + Id existing = + FindScalarConstant(Op::OpTypeFloat, opcode, type_id, uint32_value); if (existing) { return existing; } - auto c = new Instruction(getUniqueId(), type_id, opcode); - c->addImmediateOperand(value); + auto c = new Instruction(AllocateUniqueId(), type_id, opcode); + c->AddImmediateOperand(uint32_value); constants_types_globals_.push_back(c); grouped_constants_[static_cast(Op::OpTypeFloat)].push_back(c); - module_.mapInstruction(c); + module_.MapInstruction(c); return c->result_id(); } -Id SpvEmitter::makeDoubleConstant(double d, bool is_spec_constant) { +Id SpvEmitter::MakeDoubleConstant(double value, bool is_spec_constant) { Op opcode = is_spec_constant ? Op::OpSpecConstant : Op::OpConstant; - Id type_id = makeFloatType(64); - unsigned long long value = *(unsigned long long*)&d; - unsigned op1 = value & 0xFFFFFFFF; - unsigned op2 = value >> 32; - Id existing = findScalarConstant(Op::OpTypeFloat, opcode, type_id, op1, op2); + Id type_id = MakeFloatType(64); + uint64_t uint64_value = *reinterpret_cast(&value); + uint32_t op1 = static_cast(uint64_value & 0xFFFFFFFF); + uint32_t op2 = static_cast(uint64_value >> 32); + Id existing = FindScalarConstant(Op::OpTypeFloat, opcode, type_id, op1, op2); if (existing) { return existing; } - auto c = new Instruction(getUniqueId(), type_id, opcode); - c->addImmediateOperand(op1); - c->addImmediateOperand(op2); + auto c = new Instruction(AllocateUniqueId(), type_id, opcode); + c->AddImmediateOperand(op1); + c->AddImmediateOperand(op2); constants_types_globals_.push_back(c); grouped_constants_[static_cast(Op::OpTypeFloat)].push_back(c); - module_.mapInstruction(c); + module_.MapInstruction(c); return c->result_id(); } -Id SpvEmitter::findCompositeConstant(Op type_class, - std::vector& comps) const { - Instruction* constant = nullptr; - bool found = false; +Id SpvEmitter::FindCompositeConstant( + Op type_class, std::initializer_list components) const { auto& grouped_constant = grouped_constants_[static_cast(type_class)]; for (auto& constant : grouped_constant) { // same shape? - if (constant->operand_count() != (int)comps.size()) { + if (constant->operand_count() != components.size()) { continue; } // same contents? bool mismatch = false; for (int op = 0; op < constant->operand_count(); ++op) { - if (constant->id_operand(op) != comps[op]) { + if (constant->id_operand(op) != *(components.begin() + op)) { mismatch = true; break; } } if (!mismatch) { - found = true; - break; + return constant->result_id(); } } - return found ? constant->result_id() : NoResult; + return NoResult; } -Id SpvEmitter::makeCompositeConstant(Id type_id, std::vector& members) { +Id SpvEmitter::MakeCompositeConstant(Id type_id, + std::initializer_list components) { assert(type_id); - Op type_class = getTypeClass(type_id); + Op type_class = GetTypeClass(type_id); switch (type_class) { case Op::OpTypeVector: @@ -659,159 +654,160 @@ Id SpvEmitter::makeCompositeConstant(Id type_id, std::vector& members) { break; default: assert(0); - return makeFloatConstant(0.0); + return MakeFloatConstant(0.0); } - Id existing = findCompositeConstant(type_class, members); + Id existing = FindCompositeConstant(type_class, components); if (existing) { return existing; } - auto c = new Instruction(getUniqueId(), type_id, Op::OpConstantComposite); - c->addIdOperands(members); + auto c = + new Instruction(AllocateUniqueId(), type_id, Op::OpConstantComposite); + c->AddIdOperands(components); constants_types_globals_.push_back(c); grouped_constants_[static_cast(type_class)].push_back(c); - module_.mapInstruction(c); + module_.MapInstruction(c); return c->result_id(); } -Instruction* SpvEmitter::addEntryPoint(spv::ExecutionModel model, - Function* function, const char* name) { - auto entry_point = new Instruction(Op::OpEntryPoint); - entry_point->addImmediateOperand(model); - entry_point->addIdOperand(function->id()); - entry_point->addStringOperand(name); +Instruction* SpvEmitter::AddEntryPoint(spv::ExecutionModel execution_model, + Function* entry_point, + const char* name) { + auto instr = new Instruction(Op::OpEntryPoint); + instr->AddImmediateOperand(execution_model); + instr->AddIdOperand(entry_point->id()); + instr->AddStringOperand(name); - entry_points_.push_back(entry_point); + entry_points_.push_back(instr); - return entry_point; + return instr; } // Currently relying on the fact that all 'value' of interest are small // non-negative values. -void SpvEmitter::addExecutionMode(Function* entry_point, - spv::ExecutionMode mode, int value1, +void SpvEmitter::AddExecutionMode(Function* entry_point, + spv::ExecutionMode execution_mode, int value1, int value2, int value3) { auto instr = new Instruction(Op::OpExecutionMode); - instr->addIdOperand(entry_point->id()); - instr->addImmediateOperand(mode); + instr->AddIdOperand(entry_point->id()); + instr->AddImmediateOperand(execution_mode); if (value1 >= 0) { - instr->addImmediateOperand(value1); + instr->AddImmediateOperand(value1); } if (value2 >= 0) { - instr->addImmediateOperand(value2); + instr->AddImmediateOperand(value2); } if (value3 >= 0) { - instr->addImmediateOperand(value3); + instr->AddImmediateOperand(value3); } execution_modes_.push_back(instr); } -void SpvEmitter::addName(Id id, const char* string) { - auto name = new Instruction(Op::OpName); - name->addIdOperand(id); - name->addStringOperand(string); - - names_.push_back(name); -} - -void SpvEmitter::addMemberName(Id id, int memberNumber, const char* string) { - auto name = new Instruction(Op::OpMemberName); - name->addIdOperand(id); - name->addImmediateOperand(memberNumber); - name->addStringOperand(string); - - names_.push_back(name); -} - -void SpvEmitter::addLine(Id target, Id file_name, int lineNum, int column) { - auto line = new Instruction(Op::OpLine); - line->addIdOperand(target); - line->addIdOperand(file_name); - line->addImmediateOperand(lineNum); - line->addImmediateOperand(column); - - lines_.push_back(line); -} - -void SpvEmitter::addDecoration(Id id, spv::Decoration decoration, int num) { - if (decoration == (spv::Decoration)BadValue) { +void SpvEmitter::AddName(Id target_id, const char* value) { + if (!value) { return; } - auto dec = new Instruction(Op::OpDecorate); - dec->addIdOperand(id); - dec->addImmediateOperand(decoration); - if (num >= 0) { - dec->addImmediateOperand(num); - } + auto instr = new Instruction(Op::OpName); + instr->AddIdOperand(target_id); + instr->AddStringOperand(value); - decorations_.push_back(dec); + names_.push_back(instr); } -void SpvEmitter::addMemberDecoration(Id id, unsigned int member, +void SpvEmitter::AddMemberName(Id target_id, int member, const char* value) { + if (!value) { + return; + } + auto instr = new Instruction(Op::OpMemberName); + instr->AddIdOperand(target_id); + instr->AddImmediateOperand(member); + instr->AddStringOperand(value); + + names_.push_back(instr); +} + +void SpvEmitter::AddLine(Id target_id, Id file_name, int line_number, + int column_number) { + auto instr = new Instruction(Op::OpLine); + instr->AddIdOperand(target_id); + instr->AddIdOperand(file_name); + instr->AddImmediateOperand(line_number); + instr->AddImmediateOperand(column_number); + + lines_.push_back(instr); +} + +void SpvEmitter::AddDecoration(Id target_id, spv::Decoration decoration, + int num) { + if (decoration == static_cast(BadValue)) { + return; + } + auto instr = new Instruction(Op::OpDecorate); + instr->AddIdOperand(target_id); + instr->AddImmediateOperand(decoration); + if (num >= 0) { + instr->AddImmediateOperand(num); + } + + decorations_.push_back(instr); +} + +void SpvEmitter::AddMemberDecoration(Id target_id, int member, spv::Decoration decoration, int num) { - auto dec = new Instruction(Op::OpMemberDecorate); - dec->addIdOperand(id); - dec->addImmediateOperand(member); - dec->addImmediateOperand(decoration); + auto instr = new Instruction(Op::OpMemberDecorate); + instr->AddIdOperand(target_id); + instr->AddImmediateOperand(member); + instr->AddImmediateOperand(decoration); if (num >= 0) { - dec->addImmediateOperand(num); + instr->AddImmediateOperand(num); } - decorations_.push_back(dec); + decorations_.push_back(instr); } -Function* SpvEmitter::makeMain() { +Function* SpvEmitter::MakeMainEntry() { assert(!main_function_); - - Block* entry; - std::vector params; - - main_function_ = makeFunctionEntry(makeVoidType(), "main", params, &entry); - + Block* entry = nullptr; + main_function_ = MakeFunctionEntry(MakeVoidType(), "main", {}, &entry); return main_function_; } -Function* SpvEmitter::makeFunctionEntry(Id return_type, const char* name, - std::vector& param_types, +Function* SpvEmitter::MakeFunctionEntry(Id return_type, const char* name, + std::initializer_list param_types, Block** entry) { - Id type_id = makeFunctionType(return_type, param_types); - Id firstParamId = - param_types.empty() ? 0 : getUniqueIds((int)param_types.size()); - auto function = - new Function(getUniqueId(), return_type, type_id, firstParamId, module_); - + Id type_id = MakeFunctionType(return_type, param_types); + Id first_param_id = + param_types.size() ? AllocateUniqueIds((int)param_types.size()) : 0; + auto function = new Function(AllocateUniqueId(), return_type, type_id, + first_param_id, module_); if (entry) { - *entry = new Block(getUniqueId(), *function); + *entry = new Block(AllocateUniqueId(), *function); function->push_block(*entry); set_build_point(*entry); } - - if (name) { - addName(function->id(), name); - } - + AddName(function->id(), name); return function; } -void SpvEmitter::makeReturn(bool implicit, Id retVal) { - if (retVal) { +void SpvEmitter::MakeReturn(bool implicit, Id return_value) { + if (return_value) { auto inst = new Instruction(NoResult, NoType, Op::OpReturnValue); - inst->addIdOperand(retVal); - build_point_->push_instruction(inst); + inst->AddIdOperand(return_value); + build_point_->AddInstruction(inst); } else { - build_point_->push_instruction( + build_point_->AddInstruction( new Instruction(NoResult, NoType, Op::OpReturn)); } if (!implicit) { - createAndSetNoPredecessorBlock("post-return"); + CreateAndSetNoPredecessorBlock("post-return"); } } -void SpvEmitter::leaveFunction() { +void SpvEmitter::LeaveFunction() { Block* block = build_point_; Function& function = build_point_->parent(); assert(block); @@ -820,468 +816,454 @@ void SpvEmitter::leaveFunction() { if (!block->is_terminated()) { // Whether we're in an unreachable (non-entry) block. bool unreachable = - function.entry_block() != block && block->predecessor_count() == 0; + function.entry_block() != block && !block->predecessor_count(); if (unreachable) { // Given that this block is at the end of a function, it must be right - // after an - // explicit return, just remove it. + // after an explicit return, just remove it. function.pop_block(block); } else { // We'll add a return instruction at the end of the current block, // which for a non-void function is really error recovery (?), as the - // source - // being translated should have had an explicit return, which would have - // been - // followed by an unreachable block, which was handled above. - if (function.return_type() == makeVoidType()) { - makeReturn(true); + // source being translated should have had an explicit return, which would + // have been followed by an unreachable block, which was handled above. + if (function.return_type() == MakeVoidType()) { + MakeReturn(true); } else { - makeReturn(true, createUndefined(function.return_type())); + MakeReturn(true, CreateUndefined(function.return_type())); } } } } -void SpvEmitter::makeDiscard() { - build_point_->push_instruction(new Instruction(Op::OpKill)); - createAndSetNoPredecessorBlock("post-discard"); +void SpvEmitter::MakeDiscard() { + build_point_->AddInstruction(new Instruction(Op::OpKill)); + CreateAndSetNoPredecessorBlock("post-discard"); } -Id SpvEmitter::createVariable(spv::StorageClass storage_class, Id type, +Id SpvEmitter::CreateVariable(spv::StorageClass storage_class, Id type, const char* name) { - Id pointerType = makePointer(storage_class, type); - auto inst = new Instruction(getUniqueId(), pointerType, Op::OpVariable); - inst->addImmediateOperand(storage_class); + Id pointer_type = MakePointer(storage_class, type); + auto instr = + new Instruction(AllocateUniqueId(), pointer_type, Op::OpVariable); + instr->AddImmediateOperand(storage_class); switch (storage_class) { case spv::StorageClass::Function: - // Validation rules require the declaration in the entry block - build_point_->parent().push_local_variable(inst); + // Validation rules require the declaration in the entry block. + build_point_->parent().AddLocalVariable(instr); break; - default: - constants_types_globals_.push_back(inst); - module_.mapInstruction(inst); + constants_types_globals_.push_back(instr); + module_.MapInstruction(instr); break; } - if (name) { - addName(inst->result_id(), name); - } + AddName(instr->result_id(), name); - return inst->result_id(); + return instr->result_id(); } -Id SpvEmitter::createUndefined(Id type) { - auto inst = new Instruction(getUniqueId(), type, Op::OpUndef); - build_point_->push_instruction(inst); - return inst->result_id(); +Id SpvEmitter::CreateUndefined(Id type) { + auto instr = new Instruction(AllocateUniqueId(), type, Op::OpUndef); + build_point_->AddInstruction(instr); + return instr->result_id(); } -void SpvEmitter::createStore(Id rvalue, Id lvalue) { - auto store = new Instruction(Op::OpStore); - store->addIdOperand(lvalue); - store->addIdOperand(rvalue); - build_point_->push_instruction(store); +void SpvEmitter::CreateStore(Id pointer_id, Id value_id) { + auto instr = new Instruction(Op::OpStore); + instr->AddIdOperand(pointer_id); + instr->AddIdOperand(value_id); + build_point_->AddInstruction(instr); } -Id SpvEmitter::createLoad(Id lvalue) { - auto load = - new Instruction(getUniqueId(), getDerefTypeId(lvalue), Op::OpLoad); - load->addIdOperand(lvalue); - build_point_->push_instruction(load); +Id SpvEmitter::CreateLoad(Id pointer_id) { + auto instr = new Instruction(AllocateUniqueId(), GetDerefTypeId(pointer_id), + Op::OpLoad); + instr->AddIdOperand(pointer_id); + build_point_->AddInstruction(instr); - return load->result_id(); + return instr->result_id(); } -Id SpvEmitter::createAccessChain(spv::StorageClass storage_class, Id base, - std::vector& offsets) { +Id SpvEmitter::CreateAccessChain(spv::StorageClass storage_class, Id base_id, + std::vector index_ids) { // Figure out the final resulting type. - spv::Id type_id = getTypeId(base); - assert(isPointerType(type_id) && !offsets.empty()); - type_id = getContainedTypeId(type_id); - for (size_t i = 0; i < offsets.size(); ++i) { - if (isStructType(type_id)) { - assert(isConstantScalar(offsets[i])); - type_id = getContainedTypeId(type_id, getConstantScalar(offsets[i])); + auto base_type_id = GetTypeId(base_id); + assert(IsPointerType(base_type_id) && index_ids.size()); + auto type_id = GetContainedTypeId(base_type_id); + for (auto index_id : index_ids) { + if (IsStructType(type_id)) { + assert(IsConstantScalar(index_id)); + type_id = GetContainedTypeId(type_id, GetConstantScalar(index_id)); } else { - type_id = getContainedTypeId(type_id, offsets[i]); + type_id = GetContainedTypeId(type_id, index_id); } } - type_id = makePointer(storage_class, type_id); + auto chain_type_id = MakePointer(storage_class, type_id); // Make the instruction - auto chain = new Instruction(getUniqueId(), type_id, Op::OpAccessChain); - chain->addIdOperand(base); - chain->addIdOperands(offsets); - build_point_->push_instruction(chain); + auto instr = + new Instruction(AllocateUniqueId(), chain_type_id, Op::OpAccessChain); + instr->AddIdOperand(base_id); + instr->AddIdOperands(index_ids); + build_point_->AddInstruction(instr); - return chain->result_id(); + return instr->result_id(); } -Id SpvEmitter::createArrayLength(Id base, unsigned int member) { - auto length = - new Instruction(getUniqueId(), makeIntType(32), Op::OpArrayLength); - length->addIdOperand(base); - length->addImmediateOperand(member); - build_point_->push_instruction(length); +Id SpvEmitter::CreateArrayLength(Id struct_id, int array_member) { + auto instr = + new Instruction(AllocateUniqueId(), MakeIntType(32), Op::OpArrayLength); + instr->AddIdOperand(struct_id); + instr->AddImmediateOperand(array_member); + build_point_->AddInstruction(instr); - return length->result_id(); + return instr->result_id(); } -Id SpvEmitter::createCompositeExtract(Id composite, Id type_id, - unsigned index) { - auto extract = - new Instruction(getUniqueId(), type_id, Op::OpCompositeExtract); - extract->addIdOperand(composite); - extract->addImmediateOperand(index); - build_point_->push_instruction(extract); +Id SpvEmitter::CreateCompositeExtract(Id composite, Id type_id, + uint32_t index) { + auto instr = + new Instruction(AllocateUniqueId(), type_id, Op::OpCompositeExtract); + instr->AddIdOperand(composite); + instr->AddImmediateOperand(index); + build_point_->AddInstruction(instr); - return extract->result_id(); + return instr->result_id(); } -Id SpvEmitter::createCompositeExtract(Id composite, Id type_id, - std::vector& indexes) { - auto extract = - new Instruction(getUniqueId(), type_id, Op::OpCompositeExtract); - extract->addIdOperand(composite); - extract->addImmediateOperands(indexes); - build_point_->push_instruction(extract); +Id SpvEmitter::CreateCompositeExtract(Id composite, Id type_id, + std::vector indices) { + auto instr = + new Instruction(AllocateUniqueId(), type_id, Op::OpCompositeExtract); + instr->AddIdOperand(composite); + instr->AddImmediateOperands(indices); + build_point_->AddInstruction(instr); - return extract->result_id(); + return instr->result_id(); } -Id SpvEmitter::createCompositeInsert(Id object, Id composite, Id type_id, - unsigned index) { - auto insert = new Instruction(getUniqueId(), type_id, Op::OpCompositeInsert); - insert->addIdOperand(object); - insert->addIdOperand(composite); - insert->addImmediateOperand(index); - build_point_->push_instruction(insert); +Id SpvEmitter::CreateCompositeInsert(Id object, Id composite, Id type_id, + uint32_t index) { + auto instr = + new Instruction(AllocateUniqueId(), type_id, Op::OpCompositeInsert); + instr->AddIdOperand(object); + instr->AddIdOperand(composite); + instr->AddImmediateOperand(index); + build_point_->AddInstruction(instr); - return insert->result_id(); + return instr->result_id(); } -Id SpvEmitter::createCompositeInsert(Id object, Id composite, Id type_id, - std::vector& indexes) { - auto insert = new Instruction(getUniqueId(), type_id, Op::OpCompositeInsert); - insert->addIdOperand(object); - insert->addIdOperand(composite); - for (size_t i = 0; i < indexes.size(); ++i) { - insert->addImmediateOperand(indexes[i]); - } - build_point_->push_instruction(insert); +Id SpvEmitter::CreateCompositeInsert(Id object, Id composite, Id type_id, + std::vector indices) { + auto instr = + new Instruction(AllocateUniqueId(), type_id, Op::OpCompositeInsert); + instr->AddIdOperand(object); + instr->AddIdOperand(composite); + instr->AddImmediateOperands(indices); + build_point_->AddInstruction(instr); - return insert->result_id(); + return instr->result_id(); } -Id SpvEmitter::createVectorExtractDynamic(Id vector, Id type_id, +Id SpvEmitter::CreateVectorExtractDynamic(Id vector, Id type_id, Id component_index) { - auto extract = - new Instruction(getUniqueId(), type_id, Op::OpVectorExtractDynamic); - extract->addIdOperand(vector); - extract->addIdOperand(component_index); - build_point_->push_instruction(extract); + auto instr = + new Instruction(AllocateUniqueId(), type_id, Op::OpVectorExtractDynamic); + instr->AddIdOperand(vector); + instr->AddIdOperand(component_index); + build_point_->AddInstruction(instr); - return extract->result_id(); + return instr->result_id(); } -Id SpvEmitter::createVectorInsertDynamic(Id vector, Id type_id, Id component, +Id SpvEmitter::CreateVectorInsertDynamic(Id vector, Id type_id, Id component, Id component_index) { - auto insert = - new Instruction(getUniqueId(), type_id, Op::OpVectorInsertDynamic); - insert->addIdOperand(vector); - insert->addIdOperand(component); - insert->addIdOperand(component_index); - build_point_->push_instruction(insert); + auto instr = + new Instruction(AllocateUniqueId(), type_id, Op::OpVectorInsertDynamic); + instr->AddIdOperand(vector); + instr->AddIdOperand(component); + instr->AddIdOperand(component_index); + build_point_->AddInstruction(instr); - return insert->result_id(); + return instr->result_id(); } -// An opcode that has no operands, no result id, and no type -void SpvEmitter::createNoResultOp(Op opcode) { - auto op = new Instruction(opcode); - build_point_->push_instruction(op); +void SpvEmitter::CreateNop() { + auto instr = new Instruction(spv::Op::OpNop); + build_point_->AddInstruction(instr); } -// An opcode that has one operand, no result id, and no type -void SpvEmitter::createNoResultOp(Op opcode, Id operand) { - auto op = new Instruction(opcode); - op->addIdOperand(operand); - build_point_->push_instruction(op); +void SpvEmitter::CreateControlBarrier( + spv::Scope execution_scope, spv::Scope memory_scope, + spv::MemorySemanticsMask memory_semantics) { + auto instr = new Instruction(Op::OpControlBarrier); + instr->AddImmediateOperand(MakeUintConstant(execution_scope)); + instr->AddImmediateOperand(MakeUintConstant(memory_scope)); + instr->AddImmediateOperand(MakeUintConstant(memory_semantics)); + build_point_->AddInstruction(instr); } -// An opcode that has one operand, no result id, and no type -void SpvEmitter::createNoResultOp(Op opcode, const std::vector& operands) { - auto op = new Instruction(opcode); - op->addIdOperands(operands); - build_point_->push_instruction(op); +void SpvEmitter::CreateMemoryBarrier( + spv::Scope execution_scope, spv::MemorySemanticsMask memory_semantics) { + auto instr = new Instruction(Op::OpMemoryBarrier); + instr->AddImmediateOperand(MakeUintConstant(execution_scope)); + instr->AddImmediateOperand(MakeUintConstant(memory_semantics)); + build_point_->AddInstruction(instr); } -void SpvEmitter::createControlBarrier(spv::Scope execution, spv::Scope memory, - spv::MemorySemanticsMask semantics) { - auto op = new Instruction(Op::OpControlBarrier); - op->addImmediateOperand(makeUintConstant(execution)); - op->addImmediateOperand(makeUintConstant(memory)); - op->addImmediateOperand(makeUintConstant(semantics)); - build_point_->push_instruction(op); +Id SpvEmitter::CreateUnaryOp(Op opcode, Id type_id, Id operand) { + auto instr = new Instruction(AllocateUniqueId(), type_id, opcode); + instr->AddIdOperand(operand); + build_point_->AddInstruction(instr); + + return instr->result_id(); } -void SpvEmitter::createMemoryBarrier(unsigned execution_scope, - unsigned memory_semantics) { - auto op = new Instruction(Op::OpMemoryBarrier); - op->addImmediateOperand(makeUintConstant(execution_scope)); - op->addImmediateOperand(makeUintConstant(memory_semantics)); - build_point_->push_instruction(op); +Id SpvEmitter::CreateBinOp(Op opcode, Id type_id, Id left, Id right) { + auto instr = new Instruction(AllocateUniqueId(), type_id, opcode); + instr->AddIdOperand(left); + instr->AddIdOperand(right); + build_point_->AddInstruction(instr); + + return instr->result_id(); } -// An opcode that has one operands, a result id, and a type -Id SpvEmitter::createUnaryOp(Op opcode, Id type_id, Id operand) { - auto op = new Instruction(getUniqueId(), type_id, opcode); - op->addIdOperand(operand); - build_point_->push_instruction(op); +Id SpvEmitter::CreateTriOp(Op opcode, Id type_id, Id op1, Id op2, Id op3) { + auto instr = new Instruction(AllocateUniqueId(), type_id, opcode); + instr->AddIdOperand(op1); + instr->AddIdOperand(op2); + instr->AddIdOperand(op3); + build_point_->AddInstruction(instr); - return op->result_id(); + return instr->result_id(); } -Id SpvEmitter::createBinOp(Op opcode, Id type_id, Id left, Id right) { - auto op = new Instruction(getUniqueId(), type_id, opcode); - op->addIdOperand(left); - op->addIdOperand(right); - build_point_->push_instruction(op); - - return op->result_id(); -} - -Id SpvEmitter::createTriOp(Op opcode, Id type_id, Id op1, Id op2, Id op3) { - auto op = new Instruction(getUniqueId(), type_id, opcode); - op->addIdOperand(op1); - op->addIdOperand(op2); - op->addIdOperand(op3); - build_point_->push_instruction(op); - - return op->result_id(); -} - -Id SpvEmitter::createOp(Op opcode, Id type_id, +Id SpvEmitter::CreateOp(Op opcode, Id type_id, const std::vector& operands) { - auto op = new Instruction(getUniqueId(), type_id, opcode); - op->addIdOperands(operands); - build_point_->push_instruction(op); + auto instr = new Instruction(AllocateUniqueId(), type_id, opcode); + instr->AddIdOperands(operands); + build_point_->AddInstruction(instr); - return op->result_id(); + return instr->result_id(); } -Id SpvEmitter::createFunctionCall(Function* function, - std::vector& args) { - auto op = new Instruction(getUniqueId(), function->return_type(), - Op::OpFunctionCall); - op->addIdOperand(function->id()); - op->addIdOperands(args); - build_point_->push_instruction(op); +Id SpvEmitter::CreateFunctionCall(Function* function, + std::vector args) { + auto instr = new Instruction(AllocateUniqueId(), function->return_type(), + Op::OpFunctionCall); + instr->AddIdOperand(function->id()); + instr->AddIdOperands(args); + build_point_->AddInstruction(instr); - return op->result_id(); + return instr->result_id(); } -Id SpvEmitter::createRvalueSwizzle(Id type_id, Id source, - std::vector& channels) { - if (channels.size() == 1) - return createCompositeExtract(source, type_id, channels.front()); +Id SpvEmitter::CreateSwizzle(Id type_id, Id source, + std::vector channels) { + if (channels.size() == 1) { + return CreateCompositeExtract(source, type_id, channels.front()); + } + auto instr = + new Instruction(AllocateUniqueId(), type_id, Op::OpVectorShuffle); + assert(IsVector(source)); + instr->AddIdOperand(source); + instr->AddIdOperand(source); + instr->AddImmediateOperands(channels); + build_point_->AddInstruction(instr); - auto swizzle = new Instruction(getUniqueId(), type_id, Op::OpVectorShuffle); - assert(isVector(source)); - swizzle->addIdOperand(source); - swizzle->addIdOperand(source); - swizzle->addImmediateOperands(channels); - build_point_->push_instruction(swizzle); - - return swizzle->result_id(); + return instr->result_id(); } -Id SpvEmitter::createLvalueSwizzle(Id type_id, Id target, Id source, - std::vector& channels) { - assert(getNumComponents(source) == (int)channels.size()); - if (channels.size() == 1 && getNumComponents(source) == 1) { - return createCompositeInsert(source, target, type_id, channels.front()); +Id SpvEmitter::CreateLvalueSwizzle(Id type_id, Id target, Id source, + std::vector channels) { + assert(GetComponentCount(source) == channels.size()); + if (channels.size() == 1 && GetComponentCount(source) == 1) { + return CreateCompositeInsert(source, target, type_id, channels.front()); } - auto swizzle = new Instruction(getUniqueId(), type_id, Op::OpVectorShuffle); - assert(isVector(source)); - assert(isVector(target)); - swizzle->addIdOperand(target); - swizzle->addIdOperand(source); + auto instr = + new Instruction(AllocateUniqueId(), type_id, Op::OpVectorShuffle); + assert(IsVector(source)); + assert(IsVector(target)); + instr->AddIdOperand(target); + instr->AddIdOperand(source); - // Set up an identity shuffle from the base value to the result value - unsigned int components[4]; - int numTargetComponents = getNumComponents(target); - for (int i = 0; i < numTargetComponents; ++i) { - components[i] = i; - } + // Set up an identity shuffle from the base value to the result value. + uint32_t components[4] = {0, 1, 2, 3}; - // Punch in the l-value swizzle + // Punch in the l-value swizzle. + int component_count = GetComponentCount(target); for (int i = 0; i < (int)channels.size(); ++i) { - components[channels[i]] = numTargetComponents + i; + components[channels[i]] = component_count + i; } - // finish the instruction with these components selectors - for (int i = 0; i < numTargetComponents; ++i) { - swizzle->addImmediateOperand(components[i]); + // finish the instruction with these components selectors. + for (int i = 0; i < component_count; ++i) { + instr->AddImmediateOperand(components[i]); } - build_point_->push_instruction(swizzle); + build_point_->AddInstruction(instr); - return swizzle->result_id(); + return instr->result_id(); } -void SpvEmitter::promoteScalar(spv::Decoration precision, Id& left, Id& right) { - int direction = getNumComponents(right) - getNumComponents(left); +void SpvEmitter::PromoteScalar(spv::Decoration precision, Id& left, Id& right) { + int direction = GetComponentCount(right) - GetComponentCount(left); if (direction > 0) { - left = smearScalar(precision, left, getTypeId(right)); + left = SmearScalar(precision, left, GetTypeId(right)); } else if (direction < 0) { - right = smearScalar(precision, right, getTypeId(left)); + right = SmearScalar(precision, right, GetTypeId(left)); } } -Id SpvEmitter::smearScalar(spv::Decoration precision, Id scalar, - Id vectorType) { - assert(getNumComponents(scalar) == 1); - - int numComponents = getNumTypeComponents(vectorType); - if (numComponents == 1) { - return scalar; +Id SpvEmitter::SmearScalar(spv::Decoration precision, Id scalar_value, + Id vector_type_id) { + assert(GetComponentCount(scalar_value) == 1); + int component_count = GetTypeComponentCount(vector_type_id); + if (component_count == 1) { + return scalar_value; } - auto smear = - new Instruction(getUniqueId(), vectorType, Op::OpCompositeConstruct); - for (int c = 0; c < numComponents; ++c) { - smear->addIdOperand(scalar); + auto instr = new Instruction(AllocateUniqueId(), vector_type_id, + Op::OpCompositeConstruct); + for (int i = 0; i < component_count; ++i) { + instr->AddIdOperand(scalar_value); } - build_point_->push_instruction(smear); + build_point_->AddInstruction(instr); - return smear->result_id(); + return instr->result_id(); } -Id SpvEmitter::createBuiltinCall(spv::Decoration precision, Id result_type, - Id builtins, int entry_point, - std::initializer_list args) { - auto inst = new Instruction(getUniqueId(), result_type, Op::OpExtInst); - inst->addIdOperand(builtins); - inst->addImmediateOperand(entry_point); - inst->addIdOperands(args); +Id SpvEmitter::CreateExtendedInstructionCall(spv::Decoration precision, + Id result_type, Id instruction_set, + int instruction_ordinal, + std::initializer_list args) { + auto instr = new Instruction(AllocateUniqueId(), result_type, Op::OpExtInst); + instr->AddIdOperand(instruction_set); + instr->AddImmediateOperand(instruction_ordinal); + instr->AddIdOperands(args); - build_point_->push_instruction(inst); - return inst->result_id(); + build_point_->AddInstruction(instr); + return instr->result_id(); } // Accept all parameters needed to create a texture instruction. // Create the correct instruction based on the inputs, and make the call. -Id SpvEmitter::createTextureCall(spv::Decoration precision, Id result_type, +Id SpvEmitter::CreateTextureCall(spv::Decoration precision, Id result_type, bool fetch, bool proj, bool gather, const TextureParameters& parameters) { - static const int maxTextureArgs = 10; - Id texArgs[maxTextureArgs] = {}; + static const int kMaxTextureArgs = 10; + Id tex_args[kMaxTextureArgs] = {}; - // Set up the fixed arguments - int numArgs = 0; - bool xplicit = false; - texArgs[numArgs++] = parameters.sampler; - texArgs[numArgs++] = parameters.coords; - if (parameters.Dref) { - texArgs[numArgs++] = parameters.Dref; + // Set up the fixed arguments. + int arg_count = 0; + bool is_explicit = false; + tex_args[arg_count++] = parameters.sampler; + tex_args[arg_count++] = parameters.coords; + if (parameters.depth_ref) { + tex_args[arg_count++] = parameters.depth_ref; } if (parameters.comp) { - texArgs[numArgs++] = parameters.comp; + tex_args[arg_count++] = parameters.comp; } - // Set up the optional arguments - int optArgNum = numArgs; // track which operand, if it exists, is the mask of - // optional arguments - ++numArgs; // speculatively make room for the mask operand + // Set up the optional arguments. + int opt_arg_index = arg_count; // track which operand, if it exists, is the + // mask of optional arguments speculatively + // make room for the mask operand. + ++arg_count; auto mask = spv::ImageOperandsMask::MaskNone; // the mask operand if (parameters.bias) { mask = mask | spv::ImageOperandsMask::Bias; - texArgs[numArgs++] = parameters.bias; + tex_args[arg_count++] = parameters.bias; } if (parameters.lod) { mask = mask | spv::ImageOperandsMask::Lod; - texArgs[numArgs++] = parameters.lod; - xplicit = true; + tex_args[arg_count++] = parameters.lod; + is_explicit = true; } - if (parameters.gradX) { + if (parameters.grad_x) { mask = mask | spv::ImageOperandsMask::Grad; - texArgs[numArgs++] = parameters.gradX; - texArgs[numArgs++] = parameters.gradY; - xplicit = true; + tex_args[arg_count++] = parameters.grad_x; + tex_args[arg_count++] = parameters.grad_y; + is_explicit = true; } if (parameters.offset) { - if (isConstant(parameters.offset)) { + if (IsConstant(parameters.offset)) { mask = mask | spv::ImageOperandsMask::ConstOffset; } else { mask = mask | spv::ImageOperandsMask::Offset; } - texArgs[numArgs++] = parameters.offset; + tex_args[arg_count++] = parameters.offset; } if (parameters.offsets) { mask = mask | spv::ImageOperandsMask::ConstOffsets; - texArgs[numArgs++] = parameters.offsets; + tex_args[arg_count++] = parameters.offsets; } if (parameters.sample) { mask = mask | spv::ImageOperandsMask::Sample; - texArgs[numArgs++] = parameters.sample; + tex_args[arg_count++] = parameters.sample; } if (mask == spv::ImageOperandsMask::MaskNone) { - --numArgs; // undo speculative reservation for the mask argument + --arg_count; // undo speculative reservation for the mask argument } else { - texArgs[optArgNum] = static_cast(mask); + tex_args[opt_arg_index] = static_cast(mask); } - // Set up the instruction + // Set up the instruction. Op opcode; opcode = Op::OpImageSampleImplicitLod; if (fetch) { opcode = Op::OpImageFetch; } else if (gather) { - if (parameters.Dref) + if (parameters.depth_ref) { opcode = Op::OpImageDrefGather; - else - opcode = Op::OpImageGather; - } else if (xplicit) { - if (parameters.Dref) { - if (proj) - opcode = Op::OpImageSampleProjDrefExplicitLod; - else - opcode = Op::OpImageSampleDrefExplicitLod; } else { - if (proj) + opcode = Op::OpImageGather; + } + } else if (is_explicit) { + if (parameters.depth_ref) { + if (proj) { + opcode = Op::OpImageSampleProjDrefExplicitLod; + } else { + opcode = Op::OpImageSampleDrefExplicitLod; + } + } else { + if (proj) { opcode = Op::OpImageSampleProjExplicitLod; - else + } else { opcode = Op::OpImageSampleExplicitLod; + } } } else { - if (parameters.Dref) { - if (proj) + if (parameters.depth_ref) { + if (proj) { opcode = Op::OpImageSampleProjDrefImplicitLod; - else + } else { opcode = Op::OpImageSampleDrefImplicitLod; + } } else { - if (proj) + if (proj) { opcode = Op::OpImageSampleProjImplicitLod; - else + } else { opcode = Op::OpImageSampleImplicitLod; + } } } // See if the result type is expecting a smeared result. - // This happens when a legacy shadow*() call is made, which - // gets a vec4 back instead of a float. - Id smearedType = result_type; - if (!isScalarType(result_type)) { + // This happens when a legacy shadow*() call is made, which gets a vec4 back + // instead of a float. + Id smeared_type = result_type; + if (!IsScalarType(result_type)) { switch (opcode) { case Op::OpImageSampleDrefImplicitLod: case Op::OpImageSampleDrefExplicitLod: case Op::OpImageSampleProjDrefImplicitLod: case Op::OpImageSampleProjDrefExplicitLod: - result_type = getScalarTypeId(result_type); + result_type = GetScalarTypeId(result_type); break; default: break; @@ -1289,124 +1271,122 @@ Id SpvEmitter::createTextureCall(spv::Decoration precision, Id result_type, } // Build the SPIR-V instruction - auto textureInst = new Instruction(getUniqueId(), result_type, opcode); - for (int op = 0; op < optArgNum; ++op) { - textureInst->addIdOperand(texArgs[op]); + auto instr = new Instruction(AllocateUniqueId(), result_type, opcode); + for (int op = 0; op < opt_arg_index; ++op) { + instr->AddIdOperand(tex_args[op]); } - if (optArgNum < numArgs) textureInst->addImmediateOperand(texArgs[optArgNum]); - for (int op = optArgNum + 1; op < numArgs; ++op) { - textureInst->addIdOperand(texArgs[op]); + if (opt_arg_index < arg_count) { + instr->AddImmediateOperand(tex_args[opt_arg_index]); } - setPrecision(textureInst->result_id(), precision); - build_point_->push_instruction(textureInst); + for (int op = opt_arg_index + 1; op < arg_count; ++op) { + instr->AddIdOperand(tex_args[op]); + } + SetPrecision(instr->result_id(), precision); + build_point_->AddInstruction(instr); - Id result_id = textureInst->result_id(); + Id result_id = instr->result_id(); - // When a smear is needed, do it, as per what was computed - // above when result_type was changed to a scalar type. - if (result_type != smearedType) { - result_id = smearScalar(precision, result_id, smearedType); + // When a smear is needed, do it, as per what was computed above when + // result_type was changed to a scalar type. + if (result_type != smeared_type) { + result_id = SmearScalar(precision, result_id, smeared_type); } return result_id; } -Id SpvEmitter::createTextureQueryCall(Op opcode, +Id SpvEmitter::CreateTextureQueryCall(Op opcode, const TextureParameters& parameters) { - // Figure out the result type + // Figure out the result type. Id result_type = 0; switch (opcode) { case Op::OpImageQuerySize: case Op::OpImageQuerySizeLod: { - int numComponents; - switch (getTypeDimensionality(getImageType(parameters.sampler))) { + int component_count; + switch (GetTypeDimensionality(GetImageType(parameters.sampler))) { case spv::Dim::Dim1D: case spv::Dim::Buffer: - numComponents = 1; + component_count = 1; break; case spv::Dim::Dim2D: case spv::Dim::Cube: case spv::Dim::Rect: - numComponents = 2; + component_count = 2; break; case spv::Dim::Dim3D: - numComponents = 3; + component_count = 3; break; case spv::Dim::SubpassData: CheckNotImplemented("input-attachment dim"); break; - default: assert(0); break; } - if (isArrayedImageType(getImageType(parameters.sampler))) { - ++numComponents; + if (IsArrayedImageType(GetImageType(parameters.sampler))) { + ++component_count; } - if (numComponents == 1) { - result_type = makeIntType(32); + if (component_count == 1) { + result_type = MakeIntType(32); } else { - result_type = makeVectorType(makeIntType(32), numComponents); + result_type = MakeVectorType(MakeIntType(32), component_count); } break; } case Op::OpImageQueryLod: - result_type = makeVectorType(makeFloatType(32), 2); + result_type = MakeVectorType(MakeFloatType(32), 2); break; case Op::OpImageQueryLevels: case Op::OpImageQuerySamples: - result_type = makeIntType(32); + result_type = MakeIntType(32); break; default: assert(0); break; } - auto query = new Instruction(getUniqueId(), result_type, opcode); - query->addIdOperand(parameters.sampler); + auto instr = new Instruction(AllocateUniqueId(), result_type, opcode); + instr->AddIdOperand(parameters.sampler); if (parameters.coords) { - query->addIdOperand(parameters.coords); + instr->AddIdOperand(parameters.coords); } if (parameters.lod) { - query->addIdOperand(parameters.lod); + instr->AddIdOperand(parameters.lod); } - build_point_->push_instruction(query); + build_point_->AddInstruction(instr); - return query->result_id(); + return instr->result_id(); } -Id SpvEmitter::createCompare(spv::Decoration precision, Id value1, Id value2, - bool equal) { - Id boolType = makeBoolType(); - Id valueType = getTypeId(value1); +Id SpvEmitter::CreateCompare(spv::Decoration precision, Id value1, Id value2, + bool is_equal) { + Id bool_type_id = MakeBoolType(); + Id value_type_id = GetTypeId(value1); - assert(valueType == getTypeId(value2)); - assert(!isScalar(value1)); + assert(value_type_id == GetTypeId(value2)); + assert(!IsScalar(value1)); - // Vectors - - if (isVectorType(valueType)) { + // Vectors. + if (IsVectorType(value_type_id)) { Op op; - if (getMostBasicTypeClass(valueType) == Op::OpTypeFloat) { - op = equal ? Op::OpFOrdEqual : Op::OpFOrdNotEqual; + if (GetMostBasicTypeClass(value_type_id) == Op::OpTypeFloat) { + op = is_equal ? Op::OpFOrdEqual : Op::OpFOrdNotEqual; } else { - op = equal ? Op::OpIEqual : Op::OpINotEqual; + op = is_equal ? Op::OpIEqual : Op::OpINotEqual; } - Id boolVectorType = - makeVectorType(boolType, getNumTypeComponents(valueType)); - Id boolVector = createBinOp(op, boolVectorType, value1, value2); - setPrecision(boolVector, precision); + Id bool_vector_type_id = + MakeVectorType(bool_type_id, GetTypeComponentCount(value_type_id)); + Id bool_vector = CreateBinOp(op, bool_vector_type_id, value1, value2); + SetPrecision(bool_vector, precision); // Reduce vector compares with any() and all(). + op = is_equal ? Op::OpAll : Op::OpAny; - op = equal ? Op::OpAll : Op::OpAny; - - return createUnaryOp(op, boolType, boolVector); + return CreateUnaryOp(op, bool_type_id, bool_vector); } CheckNotImplemented("Composite comparison of non-vectors"); - return NoResult; // Recursively handle aggregates, which include matrices, arrays, and @@ -1460,93 +1440,89 @@ Id SpvEmitter::createCompare(spv::Decoration precision, Id value1, Id value2, } // OpCompositeConstruct -Id SpvEmitter::createCompositeConstruct(Id type_id, - std::vector& constituents) { - assert(isAggregateType(type_id) || - (getNumTypeComponents(type_id) > 1 && - getNumTypeComponents(type_id) == (int)constituents.size())); +Id SpvEmitter::CreateCompositeConstruct(Id type_id, + std::vector constituent_ids) { + assert(IsAggregateType(type_id) || + (GetTypeComponentCount(type_id) > 1 && + GetTypeComponentCount(type_id) == constituent_ids.size())); - auto op = new Instruction(getUniqueId(), type_id, Op::OpCompositeConstruct); - op->addIdOperands(constituents); - build_point_->push_instruction(op); + auto instr = + new Instruction(AllocateUniqueId(), type_id, Op::OpCompositeConstruct); + instr->AddIdOperands(constituent_ids); + build_point_->AddInstruction(instr); - return op->result_id(); + return instr->result_id(); } -// Vector or scalar constructor -Id SpvEmitter::createConstructor(spv::Decoration precision, - const std::vector& sources, +Id SpvEmitter::CreateConstructor(spv::Decoration precision, + std::vector source_ids, Id result_type_id) { Id result = 0; - unsigned int numTargetComponents = getNumTypeComponents(result_type_id); - unsigned int targetComponent = 0; + int target_component_count = GetTypeComponentCount(result_type_id); + int target_component = 0; // Special case: when calling a vector constructor with a single scalar // argument, smear the scalar - if (sources.size() == 1 && isScalar(sources[0]) && numTargetComponents > 1) { - return smearScalar(precision, sources[0], result_type_id); + if (source_ids.size() == 1 && IsScalar(source_ids[0]) && + target_component_count > 1) { + return SmearScalar(precision, source_ids[0], result_type_id); } - Id scalarTypeId = getScalarTypeId(result_type_id); - std::vector - constituents; // accumulate the arguments for OpCompositeConstruct - for (auto source : sources) { - assert(!isAggregate(source)); - unsigned int sourceSize = getNumComponents(source); - unsigned int sourcesToUse = sourceSize; - if (sourcesToUse + targetComponent > numTargetComponents) { - sourcesToUse = numTargetComponents - targetComponent; + // Accumulate the arguments for OpCompositeConstruct. + Id scalar_type_id = GetScalarTypeId(result_type_id); + std::vector constituent_ids; + for (auto source_id : source_ids) { + assert(!IsAggregate(source_id)); + int source_component_count = GetComponentCount(source_id); + int sources_to_use = source_component_count; + if (sources_to_use + target_component > target_component_count) { + sources_to_use = target_component_count - target_component; } - - for (unsigned int s = 0; s < sourcesToUse; ++s) { - Id arg = source; - if (sourceSize > 1) { - std::vector swiz; - swiz.push_back(s); - arg = createRvalueSwizzle(scalarTypeId, arg, swiz); + for (int s = 0; s < sources_to_use; ++s) { + Id arg = source_id; + if (source_component_count > 1) { + arg = CreateSwizzle(scalar_type_id, arg, {static_cast(s)}); } - - if (numTargetComponents > 1) { - constituents.push_back(arg); + if (target_component_count > 1) { + constituent_ids.push_back(arg); } else { result = arg; } - ++targetComponent; + ++target_component; } - - if (targetComponent >= numTargetComponents) { + if (target_component >= target_component_count) { break; } } - if (!constituents.empty()) { - result = createCompositeConstruct(result_type_id, constituents); + if (!constituent_ids.empty()) { + result = CreateCompositeConstruct(result_type_id, constituent_ids); } - setPrecision(result, precision); + SetPrecision(result, precision); return result; } -Id SpvEmitter::createMatrixConstructor(spv::Decoration precision, - const std::vector& sources, +Id SpvEmitter::CreateMatrixConstructor(spv::Decoration precision, + std::vector sources, Id result_type_id) { - Id componentTypeId = getScalarTypeId(result_type_id); - int numCols = getTypeNumColumns(result_type_id); - int numRows = getTypeNumRows(result_type_id); + Id component_type_id = GetScalarTypeId(result_type_id); + int column_count = GetTypeColumnCount(result_type_id); + int row_count = GetTypeRowCount(result_type_id); - // Will use a two step process + // Will use a two step process: // 1. make a compile-time 2D array of values // 2. construct a matrix from that array // Step 1. - // initialize the array to the identity matrix + // Initialize the array to the identity matrix. Id ids[kMaxMatrixSize][kMaxMatrixSize]; - Id one = makeFloatConstant(1.0); - Id zero = makeFloatConstant(0.0); - for (int col = 0; col < 4; ++col) { - for (int row = 0; row < 4; ++row) { + Id one = MakeFloatConstant(1.0); + Id zero = MakeFloatConstant(0.0); + for (int col = 0; col < kMaxMatrixSize; ++col) { + for (int row = 0; row < kMaxMatrixSize; ++row) { if (col == row) { ids[col][row] = one; } else { @@ -1555,68 +1531,67 @@ Id SpvEmitter::createMatrixConstructor(spv::Decoration precision, } } - // modify components as dictated by the arguments - if (sources.size() == 1 && isScalar(sources[0])) { - // a single scalar; resets the diagonals - for (int col = 0; col < 4; ++col) { + // Modify components as dictated by the arguments. + if (sources.size() == 1 && IsScalar(sources[0])) { + // A single scalar; resets the diagonals. + for (int col = 0; col < kMaxMatrixSize; ++col) { ids[col][col] = sources[0]; } - } else if (isMatrix(sources[0])) { - // constructing from another matrix; copy over the parts that exist in both - // the argument and constructee + } else if (IsMatrix(sources[0])) { + // Constructing from another matrix; copy over the parts that exist in both + // the argument and constructee. Id matrix = sources[0]; - int minCols = std::min(numCols, getNumColumns(matrix)); - int minRows = std::min(numRows, getNumRows(matrix)); - for (int col = 0; col < minCols; ++col) { - std::vector indexes; + int min_column_count = std::min(column_count, GetColumnCount(matrix)); + int min_row_count = std::min(row_count, GetRowCount(matrix)); + for (int col = 0; col < min_column_count; ++col) { + std::vector indexes; indexes.push_back(col); - for (int row = 0; row < minRows; ++row) { + for (int row = 0; row < min_row_count; ++row) { indexes.push_back(row); ids[col][row] = - createCompositeExtract(matrix, componentTypeId, indexes); + CreateCompositeExtract(matrix, component_type_id, indexes); indexes.pop_back(); - setPrecision(ids[col][row], precision); + SetPrecision(ids[col][row], precision); } } } else { - // fill in the matrix in column-major order with whatever argument - // components are available + // Fill in the matrix in column-major order with whatever argument + // components are available. int row = 0; int col = 0; - for (auto source : sources) { - Id argComp = source; - for (int comp = 0; comp < getNumComponents(source); ++comp) { - if (getNumComponents(source) > 1) { - argComp = createCompositeExtract(source, componentTypeId, comp); - setPrecision(argComp, precision); + Id arg_component = source; + for (int comp = 0; comp < GetComponentCount(source); ++comp) { + if (GetComponentCount(source) > 1) { + arg_component = + CreateCompositeExtract(source, component_type_id, comp); + SetPrecision(arg_component, precision); } - ids[col][row++] = argComp; - if (row == numRows) { + ids[col][row++] = arg_component; + if (row == row_count) { row = 0; - col++; + ++col; } } } } - // Step 2: Construct a matrix from that array. - // First make the column vectors, then make the matrix. + // Step 2: construct a matrix from that array. - // make the column vectors - Id columnTypeId = getContainedTypeId(result_type_id); - std::vector matrixColumns; - for (int col = 0; col < numCols; ++col) { - std::vector vectorComponents; - for (int row = 0; row < numRows; ++row) { - vectorComponents.push_back(ids[col][row]); + // Make the column vectors. + Id column_type_id = GetContainedTypeId(result_type_id); + std::vector matrix_columns; + for (int col = 0; col < column_count; ++col) { + std::vector vector_components; + for (int row = 0; row < row_count; ++row) { + vector_components.push_back(ids[col][row]); } - matrixColumns.push_back( - createCompositeConstruct(columnTypeId, vectorComponents)); + matrix_columns.push_back( + CreateCompositeConstruct(column_type_id, vector_components)); } - // make the matrix - return createCompositeConstruct(result_type_id, matrixColumns); + // Make the matrix. + return CreateCompositeConstruct(result_type_id, matrix_columns); } SpvEmitter::If::If(SpvEmitter& emitter, Id condition) @@ -1626,8 +1601,8 @@ SpvEmitter::If::If(SpvEmitter& emitter, Id condition) // make the blocks, but only put the then-block into the function, // the else-block and merge-block will be added later, in order, after // earlier code is emitted - then_block_ = new Block(emitter_.getUniqueId(), *function_); - merge_block_ = new Block(emitter_.getUniqueId(), *function_); + then_block_ = new Block(emitter_.AllocateUniqueId(), *function_); + merge_block_ = new Block(emitter_.AllocateUniqueId(), *function_); // Save the current block, so that we can add in the flow control split when // makeEndIf is called. @@ -1637,30 +1612,30 @@ SpvEmitter::If::If(SpvEmitter& emitter, Id condition) emitter_.set_build_point(then_block_); } -void SpvEmitter::If::makeBeginElse() { +void SpvEmitter::If::MakeBeginElse() { // Close out the "then" by having it jump to the merge_block - emitter_.createBranch(merge_block_); + emitter_.CreateBranch(merge_block_); // Make the first else block and add it to the function - else_block_ = new Block(emitter_.getUniqueId(), *function_); + else_block_ = new Block(emitter_.AllocateUniqueId(), *function_); function_->push_block(else_block_); // Start building the else block emitter_.set_build_point(else_block_); } -void SpvEmitter::If::makeEndIf() { +void SpvEmitter::If::MakeEndIf() { // jump to the merge block - emitter_.createBranch(merge_block_); + emitter_.CreateBranch(merge_block_); // Go back to the header_block and make the flow control split emitter_.set_build_point(header_block_); - emitter_.createSelectionMerge(merge_block_, + emitter_.CreateSelectionMerge(merge_block_, spv::SelectionControlMask::MaskNone); if (else_block_) { - emitter_.createConditionalBranch(condition_, then_block_, else_block_); + emitter_.CreateConditionalBranch(condition_, then_block_, else_block_); } else { - emitter_.createConditionalBranch(condition_, then_block_, merge_block_); + emitter_.CreateConditionalBranch(condition_, then_block_, merge_block_); } // add the merge block to the function @@ -1668,63 +1643,63 @@ void SpvEmitter::If::makeEndIf() { emitter_.set_build_point(merge_block_); } -void SpvEmitter::makeSwitch(Id selector, int numSegments, - std::vector& caseValues, - std::vector& valueIndexToSegment, - int defaultSegment, - std::vector& segmentBlocks) { +void SpvEmitter::MakeSwitch(Id selector, int segment_count, + std::vector case_values, + std::vector value_index_to_segment, + int default_segment, + std::vector& segment_blocks) { Function& function = build_point_->parent(); - // make all the blocks - for (int s = 0; s < numSegments; ++s) { - segmentBlocks.push_back(new Block(getUniqueId(), function)); + // Make all the blocks. + for (int s = 0; s < segment_count; ++s) { + segment_blocks.push_back(new Block(AllocateUniqueId(), function)); } - Block* merge_block = new Block(getUniqueId(), function); + Block* merge_block = new Block(AllocateUniqueId(), function); - // make and insert the switch's selection-merge instruction - createSelectionMerge(merge_block, spv::SelectionControlMask::MaskNone); + // Make and insert the switch's selection-merge instruction. + CreateSelectionMerge(merge_block, spv::SelectionControlMask::MaskNone); - // make the switch instruction + // Make the switch instruction. auto switchInst = new Instruction(NoResult, NoType, Op::OpSwitch); - switchInst->addIdOperand(selector); - switchInst->addIdOperand(defaultSegment >= 0 - ? segmentBlocks[defaultSegment]->id() + switchInst->AddIdOperand(selector); + switchInst->AddIdOperand(default_segment >= 0 + ? segment_blocks[default_segment]->id() : merge_block->id()); - for (int i = 0; i < (int)caseValues.size(); ++i) { - switchInst->addImmediateOperand(caseValues[i]); - switchInst->addIdOperand(segmentBlocks[valueIndexToSegment[i]]->id()); + for (size_t i = 0; i < case_values.size(); ++i) { + switchInst->AddImmediateOperand(case_values[i]); + switchInst->AddIdOperand(segment_blocks[value_index_to_segment[i]]->id()); } - build_point_->push_instruction(switchInst); + build_point_->AddInstruction(switchInst); - // push the merge block + // Push the merge block. switch_merges_.push(merge_block); } -void SpvEmitter::addSwitchBreak() { - // branch to the top of the merge block stack - createBranch(switch_merges_.top()); - createAndSetNoPredecessorBlock("post-switch-break"); +void SpvEmitter::AddSwitchBreak() { + // Branch to the top of the merge block stack. + CreateBranch(switch_merges_.top()); + CreateAndSetNoPredecessorBlock("post-switch-break"); } -void SpvEmitter::nextSwitchSegment(std::vector& segmentBlock, - int nextSegment) { - int lastSegment = nextSegment - 1; - if (lastSegment >= 0) { - // Close out previous segment by jumping, if necessary, to next segment +void SpvEmitter::NextSwitchSegment(std::vector& segment_block, + int next_segment) { + int last_segment = next_segment - 1; + if (last_segment >= 0) { + // Close out previous segment by jumping, if necessary, to next segment. if (!build_point_->is_terminated()) { - createBranch(segmentBlock[nextSegment]); + CreateBranch(segment_block[next_segment]); } } - Block* block = segmentBlock[nextSegment]; + Block* block = segment_block[next_segment]; block->parent().push_block(block); set_build_point(block); } -void SpvEmitter::endSwitch(std::vector& /*segmentBlock*/) { - // Close out previous segment by jumping, if necessary, to next segment +void SpvEmitter::EndSwitch(std::vector& segment_block) { + // Close out previous segment by jumping, if necessary, to next segment. if (!build_point_->is_terminated()) { - addSwitchBreak(); + AddSwitchBreak(); } switch_merges_.top()->parent().push_block(switch_merges_.top()); @@ -1733,8 +1708,8 @@ void SpvEmitter::endSwitch(std::vector& /*segmentBlock*/) { switch_merges_.pop(); } -void SpvEmitter::makeNewLoop(bool loopTestFirst) { - loops_.push(Loop(*this, loopTestFirst)); +void SpvEmitter::MakeNewLoop(bool test_first) { + loops_.push(Loop(*this, test_first)); const Loop& loop = loops_.top(); // The loop test is always emitted before the loop body. @@ -1746,43 +1721,43 @@ void SpvEmitter::makeNewLoop(bool loopTestFirst) { Block* preheader = build_point(); // Branch into the loop - createBranch(loop.header); + CreateBranch(loop.header); // Set ourselves inside the loop loop.function->push_block(loop.header); set_build_point(loop.header); - if (!loopTestFirst) { + if (!test_first) { // Generate code to defer the loop test until the second and // subsequent iterations. // It's always the first iteration when coming from the preheader. // All other branches to this loop header will need to indicate "false", // but we don't yet know where they will come from. - loop.is_first_iteration->addIdOperand(makeBoolConstant(true)); - loop.is_first_iteration->addIdOperand(preheader->id()); - build_point()->push_instruction(loop.is_first_iteration); + loop.is_first_iteration->AddIdOperand(MakeBoolConstant(true)); + loop.is_first_iteration->AddIdOperand(preheader->id()); + build_point()->AddInstruction(loop.is_first_iteration); // Mark the end of the structured loop. This must exist in the loop header // block. - createLoopMerge(loop.merge, loop.header, spv::LoopControlMask::MaskNone); + CreateLoopMerge(loop.merge, loop.header, spv::LoopControlMask::MaskNone); // Generate code to see if this is the first iteration of the loop. // It needs to be in its own block, since the loop merge and // the selection merge instructions can't both be in the same // (header) block. - Block* firstIterationCheck = new Block(getUniqueId(), *loop.function); - createBranch(firstIterationCheck); + Block* firstIterationCheck = new Block(AllocateUniqueId(), *loop.function); + CreateBranch(firstIterationCheck); loop.function->push_block(firstIterationCheck); set_build_point(firstIterationCheck); // Control flow after this "if" normally reconverges at the loop body. // However, the loop test has a "break branch" out of this selection // construct because it can transfer control to the loop merge block. - createSelectionMerge(loop.body, spv::SelectionControlMask::MaskNone); + CreateSelectionMerge(loop.body, spv::SelectionControlMask::MaskNone); - Block* loopTest = new Block(getUniqueId(), *loop.function); - createConditionalBranch(loop.is_first_iteration->result_id(), loop.body, + Block* loopTest = new Block(AllocateUniqueId(), *loop.function); + CreateConditionalBranch(loop.is_first_iteration->result_id(), loop.body, loopTest); loop.function->push_block(loopTest); @@ -1790,17 +1765,17 @@ void SpvEmitter::makeNewLoop(bool loopTestFirst) { } } -void SpvEmitter::createLoopTestBranch(Id condition) { +void SpvEmitter::CreateLoopTestBranch(Id condition) { const Loop& loop = loops_.top(); // Generate the merge instruction. If the loop test executes before // the body, then this is a loop merge. Otherwise the loop merge // has already been generated and this is a conditional merge. if (loop.test_first) { - createLoopMerge(loop.merge, loop.header, spv::LoopControlMask::MaskNone); + CreateLoopMerge(loop.merge, loop.header, spv::LoopControlMask::MaskNone); // Branching to the "body" block will keep control inside // the loop. - createConditionalBranch(condition, loop.body, loop.merge); + CreateConditionalBranch(condition, loop.body, loop.merge); loop.function->push_block(loop.body); set_build_point(loop.body); } else { @@ -1809,69 +1784,56 @@ void SpvEmitter::createLoopTestBranch(Id condition) { // continue to loop.body block. Since that is already the target // of a merge instruction, and a block can't be the target of more // than one merge instruction, we need to make an intermediate block. - Block* stayInLoopBlock = new Block(getUniqueId(), *loop.function); - createSelectionMerge(stayInLoopBlock, spv::SelectionControlMask::MaskNone); + Block* stayInLoopBlock = new Block(AllocateUniqueId(), *loop.function); + CreateSelectionMerge(stayInLoopBlock, spv::SelectionControlMask::MaskNone); // This is the loop test. - createConditionalBranch(condition, stayInLoopBlock, loop.merge); + CreateConditionalBranch(condition, stayInLoopBlock, loop.merge); // The dummy block just branches to the real loop body. loop.function->push_block(stayInLoopBlock); set_build_point(stayInLoopBlock); - createBranchToBody(); + CreateBranchToBody(); } } -void SpvEmitter::createBranchToBody() { +void SpvEmitter::CreateBranchToBody() { const Loop& loop = loops_.top(); assert(loop.body); // This is a reconvergence of control flow, so no merge instruction // is required. - createBranch(loop.body); + CreateBranch(loop.body); loop.function->push_block(loop.body); set_build_point(loop.body); } -void SpvEmitter::createLoopContinue() { - createBranchToLoopHeaderFromInside(loops_.top()); +void SpvEmitter::CreateLoopContinue() { + CreateBranchToLoopHeaderFromInside(loops_.top()); // Set up a block for dead code. - createAndSetNoPredecessorBlock("post-loop-continue"); + CreateAndSetNoPredecessorBlock("post-loop-continue"); } -// Add an exit (e.g. "break") for the innermost loop that you're in -void SpvEmitter::createLoopExit() { - createBranch(loops_.top().merge); +void SpvEmitter::CreateLoopExit() { + CreateBranch(loops_.top().merge); // Set up a block for dead code. - createAndSetNoPredecessorBlock("post-loop-break"); + CreateAndSetNoPredecessorBlock("post-loop-break"); } -// Close the innermost loop -void SpvEmitter::closeLoop() { +void SpvEmitter::CloseLoop() { const Loop& loop = loops_.top(); - // Branch back to the top - createBranchToLoopHeaderFromInside(loop); + // Branch back to the top. + CreateBranchToLoopHeaderFromInside(loop); - // Add the merge block and set the build point to it + // Add the merge block and set the build point to it. loop.function->push_block(loop.merge); set_build_point(loop.merge); loops_.pop(); } -// Create a branch to the header of the given loop, from inside -// the loop body. -// Adjusts the phi node for the first-iteration value if needeed. -void SpvEmitter::createBranchToLoopHeaderFromInside(const Loop& loop) { - createBranch(loop.header); - if (loop.is_first_iteration) { - loop.is_first_iteration->addIdOperand(makeBoolConstant(false)); - loop.is_first_iteration->addIdOperand(build_point()->id()); - } -} - -void SpvEmitter::clearAccessChain() { +void SpvEmitter::ClearAccessChain() { access_chain_.base = NoResult; access_chain_.index_chain.clear(); access_chain_.instr = NoResult; @@ -1881,219 +1843,18 @@ void SpvEmitter::clearAccessChain() { access_chain_.is_rvalue = false; } -void SpvEmitter::accessChainPushSwizzle(std::vector& swizzle, - Id pre_swizzle_base_type) { - // swizzles can be stacked in GLSL, but simplified to a single - // one here; the base type doesn't change - if (access_chain_.pre_swizzle_base_type == NoType) { - access_chain_.pre_swizzle_base_type = pre_swizzle_base_type; - } - - // if needed, propagate the swizzle for the current access chain - if (access_chain_.swizzle.size()) { - std::vector oldSwizzle = access_chain_.swizzle; - access_chain_.swizzle.resize(0); - for (unsigned int i = 0; i < swizzle.size(); ++i) { - access_chain_.swizzle.push_back(oldSwizzle[swizzle[i]]); - } - } else { - access_chain_.swizzle = swizzle; - } - - // determine if we need to track this swizzle anymore - simplifyAccessChainSwizzle(); -} - -void SpvEmitter::accessChainStore(Id rvalue) { - assert(access_chain_.is_rvalue == false); - - transferAccessChainSwizzle(true); - Id base = collapseAccessChain(); - - if (access_chain_.swizzle.size() && access_chain_.component != NoResult) { - CheckNotImplemented( - "simultaneous l-value swizzle and dynamic component selection"); - } - - // If swizzle still exists, it is out-of-order or not full, we must load the - // target vector, - // extract and insert elements to perform writeMask and/or swizzle. - Id source = NoResult; - if (access_chain_.swizzle.size()) { - Id tempBaseId = createLoad(base); - source = createLvalueSwizzle(getTypeId(tempBaseId), tempBaseId, rvalue, - access_chain_.swizzle); - } - - // dynamic component selection - if (access_chain_.component != NoResult) { - Id tempBaseId = (source == NoResult) ? createLoad(base) : source; - source = createVectorInsertDynamic(tempBaseId, getTypeId(tempBaseId), - rvalue, access_chain_.component); - } - - if (source == NoResult) { - source = rvalue; - } - - createStore(source, base); -} - -Id SpvEmitter::accessChainLoad(Id result_type) { - Id id; - - if (access_chain_.is_rvalue) { - // transfer access chain, but keep it static, so we can stay in registers - transferAccessChainSwizzle(false); - if (!access_chain_.index_chain.empty()) { - Id swizzleBase = access_chain_.pre_swizzle_base_type != NoType - ? access_chain_.pre_swizzle_base_type - : result_type; - - // if all the accesses are constants, we can use OpCompositeExtract - std::vector indexes; - bool constant = true; - for (auto index : access_chain_.index_chain) { - if (isConstantScalar(index)) { - indexes.push_back(getConstantScalar(index)); - } else { - constant = false; - break; - } - } - - if (constant) { - id = createCompositeExtract(access_chain_.base, swizzleBase, indexes); - } else { - // make a new function variable for this r-value - Id lvalue = createVariable(spv::StorageClass::Function, - getTypeId(access_chain_.base), "indexable"); - - // store into it - createStore(access_chain_.base, lvalue); - - // move base to the new variable - access_chain_.base = lvalue; - access_chain_.is_rvalue = false; - - // load through the access chain - id = createLoad(collapseAccessChain()); - } - } else { - id = access_chain_.base; - } - } else { - transferAccessChainSwizzle(true); - // load through the access chain - id = createLoad(collapseAccessChain()); - } - - // Done, unless there are swizzles to do - if (access_chain_.swizzle.empty() && access_chain_.component == NoResult) { - return id; - } - - // Do remaining swizzling - // First, static swizzling - if (access_chain_.swizzle.size()) { - // static swizzle - Id swizzledType = getScalarTypeId(getTypeId(id)); - if (access_chain_.swizzle.size() > 1) { - swizzledType = - makeVectorType(swizzledType, (int)access_chain_.swizzle.size()); - } - id = createRvalueSwizzle(swizzledType, id, access_chain_.swizzle); - } - - // dynamic single-component selection - if (access_chain_.component != NoResult) { - id = createVectorExtractDynamic(id, result_type, access_chain_.component); - } - - return id; -} - -Id SpvEmitter::accessChainGetLValue() { - assert(access_chain_.is_rvalue == false); - - transferAccessChainSwizzle(true); - Id lvalue = collapseAccessChain(); - - // If swizzle exists, it is out-of-order or not full, we must load the target - // vector, - // extract and insert elements to perform writeMask and/or swizzle. This does - // not - // go with getting a direct l-value pointer. - assert(access_chain_.swizzle.empty()); - assert(access_chain_.component == NoResult); - - return lvalue; -} - -void SpvEmitter::dump(std::vector& out) const { - // Header, before first instructions: - out.push_back(spv::MagicNumber); - out.push_back(spv::Version); - out.push_back(builder_number_); - out.push_back(unique_id_ + 1); - out.push_back(0); - - for (auto capability : capabilities_) { - Instruction capInst(0, 0, Op::OpCapability); - capInst.addImmediateOperand(capability); - capInst.dump(out); - } - - // TBD: OpExtension ... - - dumpInstructions(out, imports_); - Instruction memInst(0, 0, Op::OpMemoryModel); - memInst.addImmediateOperand(addressing_model_); - memInst.addImmediateOperand(memory_model_); - memInst.dump(out); - - // Instructions saved up while building: - dumpInstructions(out, entry_points_); - dumpInstructions(out, execution_modes_); - - // Debug instructions - if (source_language_ != spv::SourceLanguage::Unknown) { - Instruction sourceInst(0, 0, Op::OpSource); - sourceInst.addImmediateOperand(source_language_); - sourceInst.addImmediateOperand(source_version_); - sourceInst.dump(out); - } - for (auto extension : extensions_) { - Instruction extInst(0, 0, Op::OpSourceExtension); - extInst.addStringOperand(extension); - extInst.dump(out); - } - dumpInstructions(out, names_); - dumpInstructions(out, lines_); - - // Annotation instructions - dumpInstructions(out, decorations_); - - dumpInstructions(out, constants_types_globals_); - dumpInstructions(out, externals_); - - // The functions - module_.dump(out); -} - // Turn the described access chain in 'accessChain' into an instruction // computing its address. This *cannot* include complex swizzles, which must // be handled after this is called, but it does include swizzles that select // an individual element, as a single address of a scalar type can be // computed by an OpAccessChain instruction. -Id SpvEmitter::collapseAccessChain() { +Id SpvEmitter::CollapseAccessChain() { assert(access_chain_.is_rvalue == false); if (!access_chain_.index_chain.empty()) { if (!access_chain_.instr) { - auto storage_class = - module_.getStorageClass(getTypeId(access_chain_.base)); - access_chain_.instr = createAccessChain(storage_class, access_chain_.base, + auto storage_class = module_.storage_class(GetTypeId(access_chain_.base)); + access_chain_.instr = CreateAccessChain(storage_class, access_chain_.base, access_chain_.index_chain); } return access_chain_.instr; @@ -2101,28 +1862,27 @@ Id SpvEmitter::collapseAccessChain() { return access_chain_.base; } - // note that non-trivial swizzling is left pending... + // Note that non-trivial swizzling is left pending... } -// clear out swizzle if it is redundant, that is reselecting the same components +// Clear out swizzle if it is redundant, that is reselecting the same components // that would be present without the swizzle. -void SpvEmitter::simplifyAccessChainSwizzle() { +void SpvEmitter::SimplifyAccessChainSwizzle() { // If the swizzle has fewer components than the vector, it is subsetting, and - // must stay - // to preserve that fact. - if (getNumTypeComponents(access_chain_.pre_swizzle_base_type) > - (int)access_chain_.swizzle.size()) { + // must stay to preserve that fact. + if (GetTypeComponentCount(access_chain_.pre_swizzle_base_type) > + access_chain_.swizzle.size()) { return; } - // if components are out of order, it is a swizzle - for (unsigned int i = 0; i < access_chain_.swizzle.size(); ++i) { + // If components are out of order, it is a swizzle. + for (size_t i = 0; i < access_chain_.swizzle.size(); ++i) { if (i != access_chain_.swizzle[i]) { return; } } - // otherwise, there is no need to track this swizzle + // Otherwise, there is no need to track this swizzle. access_chain_.swizzle.clear(); if (access_chain_.component == NoResult) { access_chain_.pre_swizzle_base_type = NoType; @@ -2138,7 +1898,7 @@ void SpvEmitter::simplifyAccessChainSwizzle() { // for external storage, they should only be integer types, // function-local bool vectors could use sub-word indexing, // so keep that as a separate Insert/Extract on a loaded vector. -void SpvEmitter::transferAccessChainSwizzle(bool dynamic) { +void SpvEmitter::TransferAccessChainSwizzle(bool dynamic) { // too complex? if (access_chain_.swizzle.size() > 1) { return; @@ -2152,14 +1912,14 @@ void SpvEmitter::transferAccessChainSwizzle(bool dynamic) { // single component... // skip doing it for Boolean vectors - if (isBoolType(getContainedTypeId(access_chain_.pre_swizzle_base_type))) { + if (IsBoolType(GetContainedTypeId(access_chain_.pre_swizzle_base_type))) { return; } if (access_chain_.swizzle.size() == 1) { // handle static component access_chain_.index_chain.push_back( - makeUintConstant(access_chain_.swizzle.front())); + MakeUintConstant(access_chain_.swizzle.front())); access_chain_.swizzle.clear(); // note, the only valid remaining dynamic access would be to this one // component, so don't bother even looking at access_chain_.component @@ -2173,71 +1933,267 @@ void SpvEmitter::transferAccessChainSwizzle(bool dynamic) { } } +void SpvEmitter::PushAccessChainSwizzle(std::vector swizzle, + Id pre_swizzle_base_type) { + // Swizzles can be stacked in GLSL, but simplified to a single + // one here; the base type doesn't change. + if (access_chain_.pre_swizzle_base_type == NoType) { + access_chain_.pre_swizzle_base_type = pre_swizzle_base_type; + } + + // If needed, propagate the swizzle for the current access chain. + if (access_chain_.swizzle.size()) { + std::vector oldSwizzle = access_chain_.swizzle; + access_chain_.swizzle.resize(0); + for (unsigned int i = 0; i < swizzle.size(); ++i) { + access_chain_.swizzle.push_back(oldSwizzle[swizzle[i]]); + } + } else { + access_chain_.swizzle = swizzle; + } + + // Determine if we need to track this swizzle anymore. + SimplifyAccessChainSwizzle(); +} + +void SpvEmitter::CreateAccessChainStore(Id rvalue) { + assert(access_chain_.is_rvalue == false); + + TransferAccessChainSwizzle(true); + Id base = CollapseAccessChain(); + + if (access_chain_.swizzle.size() && access_chain_.component != NoResult) { + CheckNotImplemented( + "simultaneous l-value swizzle and dynamic component selection"); + return; + } + + // If swizzle still exists, it is out-of-order or not full, we must load the + // target vector, extract and insert elements to perform writeMask and/or + // swizzle. + Id source = NoResult; + if (access_chain_.swizzle.size()) { + Id temp_base_id = CreateLoad(base); + source = CreateLvalueSwizzle(GetTypeId(temp_base_id), temp_base_id, rvalue, + access_chain_.swizzle); + } + + // Dynamic component selection. + if (access_chain_.component != NoResult) { + Id temp_base_id = (source == NoResult) ? CreateLoad(base) : source; + source = CreateVectorInsertDynamic(temp_base_id, GetTypeId(temp_base_id), + rvalue, access_chain_.component); + } + + if (source == NoResult) { + source = rvalue; + } + + CreateStore(source, base); +} + +Id SpvEmitter::CreateAccessChainLoad(Id result_type_id) { + Id id; + + if (access_chain_.is_rvalue) { + // Transfer access chain, but keep it static, so we can stay in registers. + TransferAccessChainSwizzle(false); + if (!access_chain_.index_chain.empty()) { + Id swizzle_base_type_id = access_chain_.pre_swizzle_base_type != NoType + ? access_chain_.pre_swizzle_base_type + : result_type_id; + + // If all the accesses are constants we can use OpCompositeExtract. + std::vector indexes; + bool constant = true; + for (auto index : access_chain_.index_chain) { + if (IsConstantScalar(index)) { + indexes.push_back(GetConstantScalar(index)); + } else { + constant = false; + break; + } + } + + if (constant) { + id = CreateCompositeExtract(access_chain_.base, swizzle_base_type_id, + indexes); + } else { + // Make a new function variable for this r-value. + Id lvalue = CreateVariable(spv::StorageClass::Function, + GetTypeId(access_chain_.base), "indexable"); + + // Store into it. + CreateStore(access_chain_.base, lvalue); + + // Move base to the new variable. + access_chain_.base = lvalue; + access_chain_.is_rvalue = false; + + // Load through the access chain. + id = CreateLoad(CollapseAccessChain()); + } + } else { + id = access_chain_.base; + } + } else { + TransferAccessChainSwizzle(true); + // Load through the access chain. + id = CreateLoad(CollapseAccessChain()); + } + + // Done, unless there are swizzles to do. + if (access_chain_.swizzle.empty() && access_chain_.component == NoResult) { + return id; + } + + // Do remaining swizzling. + // First, static swizzling. + if (access_chain_.swizzle.size()) { + // Static swizzle. + Id swizzledType = GetScalarTypeId(GetTypeId(id)); + if (access_chain_.swizzle.size() > 1) { + swizzledType = + MakeVectorType(swizzledType, (int)access_chain_.swizzle.size()); + } + id = CreateSwizzle(swizzledType, id, access_chain_.swizzle); + } + + // Dynamic single-component selection. + if (access_chain_.component != NoResult) { + id = + CreateVectorExtractDynamic(id, result_type_id, access_chain_.component); + } + + return id; +} + +Id SpvEmitter::CreateAccessChainLValue() { + assert(access_chain_.is_rvalue == false); + + TransferAccessChainSwizzle(true); + Id lvalue = CollapseAccessChain(); + + // If swizzle exists, it is out-of-order or not full, we must load the target + // vector, extract and insert elements to perform writeMask and/or swizzle. + // This does not go with getting a direct l-value pointer. + assert(access_chain_.swizzle.empty()); + assert(access_chain_.component == NoResult); + + return lvalue; +} + +void SpvEmitter::Serialize(std::vector& out) const { + // Header, before first instructions: + out.push_back(spv::MagicNumber); + out.push_back(spv::Version); + out.push_back(builder_number_); + out.push_back(unique_id_ + 1); + out.push_back(0); + + for (auto capability : capabilities_) { + Instruction capInst(0, 0, Op::OpCapability); + capInst.AddImmediateOperand(capability); + capInst.Serialize(out); + } + + // TBD: OpExtension ... + + SerializeInstructions(out, imports_); + Instruction memInst(0, 0, Op::OpMemoryModel); + memInst.AddImmediateOperand(addressing_model_); + memInst.AddImmediateOperand(memory_model_); + memInst.Serialize(out); + + // Instructions saved up while building: + SerializeInstructions(out, entry_points_); + SerializeInstructions(out, execution_modes_); + + // Debug instructions: + if (source_language_ != spv::SourceLanguage::Unknown) { + Instruction sourceInst(0, 0, Op::OpSource); + sourceInst.AddImmediateOperand(source_language_); + sourceInst.AddImmediateOperand(source_version_); + sourceInst.Serialize(out); + } + for (auto extension : source_extensions_) { + Instruction extInst(0, 0, Op::OpSourceExtension); + extInst.AddStringOperand(extension); + extInst.Serialize(out); + } + SerializeInstructions(out, names_); + SerializeInstructions(out, lines_); + + // Annotation instructions: + SerializeInstructions(out, decorations_); + + SerializeInstructions(out, constants_types_globals_); + SerializeInstructions(out, externals_); + + // The functions: + module_.Serialize(out); +} + +void SpvEmitter::SerializeInstructions( + std::vector& out, + const std::vector& instructions) const { + for (auto instruction : instructions) { + instruction->Serialize(out); + } +} + // Utility method for creating a new block and setting the insert point to // be in it. This is useful for flow-control operations that need a "dummy" // block proceeding them (e.g. instructions after a discard, etc). -void SpvEmitter::createAndSetNoPredecessorBlock(const char* name) { - Block* block = new Block(getUniqueId(), build_point_->parent()); +void SpvEmitter::CreateAndSetNoPredecessorBlock(const char* name) { + Block* block = new Block(AllocateUniqueId(), build_point_->parent()); block->set_unreachable(true); build_point_->parent().push_block(block); set_build_point(block); - // if (name) - // addName(block->id(), name); + AddName(block->id(), name); } -void SpvEmitter::createBranch(Block* block) { - auto branch = new Instruction(Op::OpBranch); - branch->addIdOperand(block->id()); - build_point_->push_instruction(branch); - block->push_predecessor(build_point_); +void SpvEmitter::CreateBranch(Block* block) { + auto instr = new Instruction(Op::OpBranch); + instr->AddIdOperand(block->id()); + build_point_->AddInstruction(instr); + block->AddPredecessor(build_point_); } -void SpvEmitter::createSelectionMerge(Block* merge_block, +void SpvEmitter::CreateSelectionMerge(Block* merge_block, spv::SelectionControlMask control) { - auto merge = new Instruction(Op::OpSelectionMerge); - merge->addIdOperand(merge_block->id()); - merge->addImmediateOperand(control); - build_point_->push_instruction(merge); + auto instr = new Instruction(Op::OpSelectionMerge); + instr->AddIdOperand(merge_block->id()); + instr->AddImmediateOperand(control); + build_point_->AddInstruction(instr); } -void SpvEmitter::createLoopMerge(Block* merge_block, Block* continueBlock, +void SpvEmitter::CreateLoopMerge(Block* merge_block, Block* continueBlock, spv::LoopControlMask control) { - auto merge = new Instruction(Op::OpLoopMerge); - merge->addIdOperand(merge_block->id()); - merge->addIdOperand(continueBlock->id()); - merge->addImmediateOperand(control); - build_point_->push_instruction(merge); + auto instr = new Instruction(Op::OpLoopMerge); + instr->AddIdOperand(merge_block->id()); + instr->AddIdOperand(continueBlock->id()); + instr->AddImmediateOperand(control); + build_point_->AddInstruction(instr); } -void SpvEmitter::createConditionalBranch(Id condition, Block* then_block, +void SpvEmitter::CreateConditionalBranch(Id condition, Block* then_block, Block* else_block) { - auto branch = new Instruction(Op::OpBranchConditional); - branch->addIdOperand(condition); - branch->addIdOperand(then_block->id()); - branch->addIdOperand(else_block->id()); - build_point_->push_instruction(branch); - then_block->push_predecessor(build_point_); - else_block->push_predecessor(build_point_); -} - -void SpvEmitter::dumpInstructions( - std::vector& out, - const std::vector& instructions) const { - for (int i = 0; i < (int)instructions.size(); ++i) { - instructions[i]->dump(out); - } -} - -void SpvEmitter::CheckNotImplemented(const char* message) { - xe::FatalError("Missing functionality: %s", message); + auto instr = new Instruction(Op::OpBranchConditional); + instr->AddIdOperand(condition); + instr->AddIdOperand(then_block->id()); + instr->AddIdOperand(else_block->id()); + build_point_->AddInstruction(instr); + then_block->AddPredecessor(build_point_); + else_block->AddPredecessor(build_point_); } SpvEmitter::Loop::Loop(SpvEmitter& emitter, bool testFirstArg) : function(&emitter.build_point()->parent()), - header(new Block(emitter.getUniqueId(), *function)), - merge(new Block(emitter.getUniqueId(), *function)), - body(new Block(emitter.getUniqueId(), *function)), + header(new Block(emitter.AllocateUniqueId(), *function)), + merge(new Block(emitter.AllocateUniqueId(), *function)), + body(new Block(emitter.AllocateUniqueId(), *function)), test_first(testFirstArg), is_first_iteration(nullptr) { if (!test_first) { @@ -2246,12 +2202,27 @@ SpvEmitter::Loop::Loop(SpvEmitter& emitter, bool testFirstArg) // This will cause subtle test failures because builder.getUniqueId(), // and builder.makeBoolType() can then get run in a compiler-specific // order making tests fail for certain configurations. - Id instructionId = emitter.getUniqueId(); + Id instructionId = emitter.AllocateUniqueId(); is_first_iteration = - new Instruction(instructionId, emitter.makeBoolType(), Op::OpPhi); + new Instruction(instructionId, emitter.MakeBoolType(), Op::OpPhi); } } +// Create a branch to the header of the given loop, from inside +// the loop body. +// Adjusts the phi node for the first-iteration value if needeed. +void SpvEmitter::CreateBranchToLoopHeaderFromInside(const Loop& loop) { + CreateBranch(loop.header); + if (loop.is_first_iteration) { + loop.is_first_iteration->AddIdOperand(MakeBoolConstant(false)); + loop.is_first_iteration->AddIdOperand(build_point()->id()); + } +} + +void SpvEmitter::CheckNotImplemented(const char* message) { + xe::FatalError("Missing functionality: %s", message); +} + } // namespace spirv } // namespace gpu } // namespace xe diff --git a/src/xenia/gpu/spirv/spv_emitter.h b/src/xenia/gpu/spirv/spv_emitter.h index 6c13e0732..97cfc32de 100644 --- a/src/xenia/gpu/spirv/spv_emitter.h +++ b/src/xenia/gpu/spirv/spv_emitter.h @@ -64,87 +64,86 @@ class SpvEmitter { SpvEmitter(); ~SpvEmitter(); - void setSource(spv::SourceLanguage language, int version) { + // Document what source language and text this module was translated from. + void SetSourceLanguage(spv::SourceLanguage language, int version) { source_language_ = language; source_version_ = version; } - void addSourceExtension(const char* ext) { extensions_.push_back(ext); } + // Document an extension to the source language. Informational only. + void AddSourceExtension(const char* ext) { + source_extensions_.push_back(ext); + } - Id import(const char* name); - - void setMemoryModel(spv::AddressingModel addressing_model, + // Set addressing model and memory model for the entire module. + void SetMemoryModel(spv::AddressingModel addressing_model, spv::MemoryModel memory_model) { addressing_model_ = addressing_model; memory_model_ = memory_model; } - void addCapability(spv::Capability cap) { capabilities_.push_back(cap); } + // Declare a capability used by this module. + void DeclareCapability(spv::Capability cap) { capabilities_.push_back(cap); } - // To get a new for anything needing a new one. - Id getUniqueId() { return ++unique_id_; } - - // To get a set of new s, e.g., for a set of function parameters - Id getUniqueIds(int numIds) { - Id id = unique_id_ + 1; - unique_id_ += numIds; - return id; - } + // Import an extended set of instructions that can be later referenced by the + // returned id. + Id ImportExtendedInstructions(const char* name); // For creating new types (will return old type if the requested one was // already made). - Id makeVoidType(); - Id makeBoolType(); - Id makePointer(spv::StorageClass, Id type); - Id makeIntegerType(int width, bool hasSign); // generic - Id makeIntType(int width) { return makeIntegerType(width, true); } - Id makeUintType(int width) { return makeIntegerType(width, false); } - Id makeFloatType(int width); - Id makeStructType(std::vector& members, const char*); - Id makeStructResultType(Id type0, Id type1); - Id makeVectorType(Id component, int size); - Id makeMatrixType(Id component, int cols, int rows); - Id makeArrayType(Id element, unsigned size); - Id makeRuntimeArray(Id element); - Id makeFunctionType(Id return_type, std::vector& param_types); - Id makeImageType(Id sampledType, spv::Dim, bool depth, bool arrayed, bool ms, - unsigned sampled, spv::ImageFormat format); - Id makeSamplerType(); - Id makeSampledImageType(Id imageType); + Id MakeVoidType(); + Id MakeBoolType(); + Id MakePointer(spv::StorageClass storage_class, Id pointee); + Id MakeIntegerType(int bit_width, bool is_signed); + Id MakeIntType(int bit_width) { return MakeIntegerType(bit_width, true); } + Id MakeUintType(int bit_width) { return MakeIntegerType(bit_width, false); } + Id MakeFloatType(int bit_width); + Id MakeStructType(std::initializer_list members, const char* name); + Id MakePairStructType(Id type0, Id type1); + Id MakeVectorType(Id component_type, int component_count); + Id MakeMatrix2DType(Id component_type, int cols, int rows); + Id MakeArrayType(Id element_type, int length); + Id MakeRuntimeArray(Id element_type); + Id MakeFunctionType(Id return_type, std::initializer_list param_types); + Id MakeImageType(Id sampled_type, spv::Dim dim, bool has_depth, + bool is_arrayed, bool is_multisampled, int sampled, + spv::ImageFormat format); + Id MakeSamplerType(); + Id MakeSampledImageType(Id image_type); // For querying about types. - Id getTypeId(Id result_id) const { return module_.getTypeId(result_id); } - Id getDerefTypeId(Id result_id) const; - Op getOpCode(Id id) const { return module_.getInstruction(id)->opcode(); } - Op getTypeClass(Id type_id) const { return getOpCode(type_id); } - Op getMostBasicTypeClass(Id type_id) const; - int getNumComponents(Id result_id) const { - return getNumTypeComponents(getTypeId(result_id)); + Id GetTypeId(Id result_id) const { return module_.type_id(result_id); } + Id GetDerefTypeId(Id result_id) const; + Op GetOpcode(Id id) const { return module_.instruction(id)->opcode(); } + Op GetTypeClass(Id type_id) const { return GetOpcode(type_id); } + Op GetMostBasicTypeClass(Id type_id) const; + int GetComponentCount(Id result_id) const { + return GetTypeComponentCount(GetTypeId(result_id)); } - int getNumTypeComponents(Id type_id) const; - Id getScalarTypeId(Id type_id) const; - Id getContainedTypeId(Id type_id) const; - Id getContainedTypeId(Id type_id, int) const; - spv::StorageClass getTypeStorageClass(Id type_id) const { - return module_.getStorageClass(type_id); + int GetTypeComponentCount(Id type_id) const; + Id GetScalarTypeId(Id type_id) const; + Id GetContainedTypeId(Id type_id) const; + Id GetContainedTypeId(Id type_id, int member) const; + spv::StorageClass GetTypeStorageClass(Id type_id) const { + return module_.storage_class(type_id); } - bool isPointer(Id result_id) const { - return isPointerType(getTypeId(result_id)); + bool IsPointer(Id result_id) const { + return IsPointerType(GetTypeId(result_id)); } - bool isScalar(Id result_id) const { - return isScalarType(getTypeId(result_id)); + bool IsScalar(Id result_id) const { + return IsScalarType(GetTypeId(result_id)); } - bool isVector(Id result_id) const { - return isVectorType(getTypeId(result_id)); + bool IsVector(Id result_id) const { + return IsVectorType(GetTypeId(result_id)); } - bool isMatrix(Id result_id) const { - return isMatrixType(getTypeId(result_id)); + bool IsMatrix(Id result_id) const { + return IsMatrixType(GetTypeId(result_id)); } - bool isAggregate(Id result_id) const { - return isAggregateType(getTypeId(result_id)); + bool IsAggregate(Id result_id) const { + return IsAggregateType(GetTypeId(result_id)); } - bool isBoolType(Id type_id) const { + bool IsBoolType(Id type_id) const { return grouped_types_[static_cast(spv::Op::OpTypeBool)].size() > 0 && type_id == grouped_types_[static_cast(spv::Op::OpTypeBool)] @@ -152,222 +151,228 @@ class SpvEmitter { ->result_id(); } - bool isPointerType(Id type_id) const { - return getTypeClass(type_id) == spv::Op::OpTypePointer; + bool IsPointerType(Id type_id) const { + return GetTypeClass(type_id) == spv::Op::OpTypePointer; } - bool isScalarType(Id type_id) const { - return getTypeClass(type_id) == spv::Op::OpTypeFloat || - getTypeClass(type_id) == spv::Op::OpTypeInt || - getTypeClass(type_id) == spv::Op::OpTypeBool; + bool IsScalarType(Id type_id) const { + return GetTypeClass(type_id) == spv::Op::OpTypeFloat || + GetTypeClass(type_id) == spv::Op::OpTypeInt || + GetTypeClass(type_id) == spv::Op::OpTypeBool; } - bool isVectorType(Id type_id) const { - return getTypeClass(type_id) == spv::Op::OpTypeVector; + bool IsVectorType(Id type_id) const { + return GetTypeClass(type_id) == spv::Op::OpTypeVector; } - bool isMatrixType(Id type_id) const { - return getTypeClass(type_id) == spv::Op::OpTypeMatrix; + bool IsMatrixType(Id type_id) const { + return GetTypeClass(type_id) == spv::Op::OpTypeMatrix; } - bool isStructType(Id type_id) const { - return getTypeClass(type_id) == spv::Op::OpTypeStruct; + bool IsStructType(Id type_id) const { + return GetTypeClass(type_id) == spv::Op::OpTypeStruct; } - bool isArrayType(Id type_id) const { - return getTypeClass(type_id) == spv::Op::OpTypeArray; + bool IsArrayType(Id type_id) const { + return GetTypeClass(type_id) == spv::Op::OpTypeArray; } - bool isAggregateType(Id type_id) const { - return isArrayType(type_id) || isStructType(type_id); + bool IsAggregateType(Id type_id) const { + return IsArrayType(type_id) || IsStructType(type_id); } - bool isImageType(Id type_id) const { - return getTypeClass(type_id) == spv::Op::OpTypeImage; + bool IsImageType(Id type_id) const { + return GetTypeClass(type_id) == spv::Op::OpTypeImage; } - bool isSamplerType(Id type_id) const { - return getTypeClass(type_id) == spv::Op::OpTypeSampler; + bool IsSamplerType(Id type_id) const { + return GetTypeClass(type_id) == spv::Op::OpTypeSampler; } - bool isSampledImageType(Id type_id) const { - return getTypeClass(type_id) == spv::Op::OpTypeSampledImage; + bool IsSampledImageType(Id type_id) const { + return GetTypeClass(type_id) == spv::Op::OpTypeSampledImage; } - bool isConstantOpCode(Op opcode) const; - bool isConstant(Id result_id) const { - return isConstantOpCode(getOpCode(result_id)); + bool IsConstantOpCode(Op opcode) const; + bool IsConstant(Id result_id) const { + return IsConstantOpCode(GetOpcode(result_id)); } - bool isConstantScalar(Id result_id) const { - return getOpCode(result_id) == spv::Op::OpConstant; + bool IsConstantScalar(Id result_id) const { + return GetOpcode(result_id) == spv::Op::OpConstant; } - unsigned int getConstantScalar(Id result_id) const { - return module_.getInstruction(result_id)->immediate_operand(0); + uint32_t GetConstantScalar(Id result_id) const { + return module_.instruction(result_id)->immediate_operand(0); } - spv::StorageClass getStorageClass(Id result_id) const { - return getTypeStorageClass(getTypeId(result_id)); + spv::StorageClass GetStorageClass(Id result_id) const { + return GetTypeStorageClass(GetTypeId(result_id)); } - int getTypeNumColumns(Id type_id) const { - assert(isMatrixType(type_id)); - return getNumTypeComponents(type_id); + int GetTypeColumnCount(Id type_id) const { + assert(IsMatrixType(type_id)); + return GetTypeComponentCount(type_id); } - int getNumColumns(Id result_id) const { - return getTypeNumColumns(getTypeId(result_id)); + int GetColumnCount(Id result_id) const { + return GetTypeColumnCount(GetTypeId(result_id)); } - int getTypeNumRows(Id type_id) const { - assert(isMatrixType(type_id)); - return getNumTypeComponents(getContainedTypeId(type_id)); + int GetTypeRowCount(Id type_id) const { + assert(IsMatrixType(type_id)); + return GetTypeComponentCount(GetContainedTypeId(type_id)); } - int getNumRows(Id result_id) const { - return getTypeNumRows(getTypeId(result_id)); + int GetRowCount(Id result_id) const { + return GetTypeRowCount(GetTypeId(result_id)); } - spv::Dim getTypeDimensionality(Id type_id) const { - assert(isImageType(type_id)); + spv::Dim GetTypeDimensionality(Id type_id) const { + assert(IsImageType(type_id)); return static_cast( - module_.getInstruction(type_id)->immediate_operand(1)); + module_.instruction(type_id)->immediate_operand(1)); } - Id getImageType(Id result_id) const { - Id type_id = getTypeId(result_id); - assert(isImageType(type_id) || isSampledImageType(type_id)); - return isSampledImageType(type_id) - ? module_.getInstruction(type_id)->id_operand(0) + Id GetImageType(Id result_id) const { + Id type_id = GetTypeId(result_id); + assert(IsImageType(type_id) || IsSampledImageType(type_id)); + return IsSampledImageType(type_id) + ? module_.instruction(type_id)->id_operand(0) : type_id; } - bool isArrayedImageType(Id type_id) const { - assert(isImageType(type_id)); - return module_.getInstruction(type_id)->immediate_operand(3) != 0; + bool IsArrayedImageType(Id type_id) const { + assert(IsImageType(type_id)); + return module_.instruction(type_id)->immediate_operand(3) != 0; } // For making new constants (will return old constant if the requested one was // already made). - Id makeBoolConstant(bool b, bool is_spec_constant = false); - Id makeIntConstant(int i, bool is_spec_constant = false) { - return makeIntConstant(makeIntType(32), (unsigned)i, is_spec_constant); + Id MakeBoolConstant(bool value, bool is_spec_constant = false); + Id MakeIntConstant(int value, bool is_spec_constant = false) { + return MakeIntegerConstant(MakeIntType(32), static_cast(value), + is_spec_constant); } - Id makeUintConstant(uint32_t u, bool is_spec_constant = false) { - return makeIntConstant(makeUintType(32), u, is_spec_constant); + Id MakeUintConstant(uint32_t value, bool is_spec_constant = false) { + return MakeIntegerConstant(MakeUintType(32), value, is_spec_constant); } template - Id makeUintConstant(T u, bool is_spec_constant = false) { + Id MakeUintConstant(T value, bool is_spec_constant = false) { static_assert(sizeof(T) == sizeof(uint32_t), "Invalid type"); - return makeIntConstant(makeUintType(32), static_cast(u), - is_spec_constant); + return MakeIntegerConstant(MakeUintType(32), static_cast(value), + is_spec_constant); } - Id makeFloatConstant(float f, bool is_spec_constant = false); - Id makeDoubleConstant(double d, bool is_spec_constant = false); + Id MakeFloatConstant(float value, bool is_spec_constant = false); + Id MakeDoubleConstant(double value, bool is_spec_constant = false); - // Turn the array of constants into a proper spv constant of the requested - // type. - Id makeCompositeConstant(Id type, std::vector& comps); + // Turns the array of constants into a proper constant of the requested type. + Id MakeCompositeConstant(Id type, std::initializer_list components); - // Methods for adding information outside the CFG. - Instruction* addEntryPoint(spv::ExecutionModel, Function*, const char* name); - void addExecutionMode(Function*, spv::ExecutionMode mode, int value1 = -1, + // Declares an entry point and its execution model. + Instruction* AddEntryPoint(spv::ExecutionModel execution_model, + Function* entry_point, const char* name); + void AddExecutionMode(Function* entry_point, + spv::ExecutionMode execution_mode, int value1 = -1, int value2 = -1, int value3 = -1); - void addName(Id, const char* name); - void addMemberName(Id, int member, const char* name); - void addLine(Id target, Id file_name, int line, int column); - void addDecoration(Id, spv::Decoration, int num = -1); - void addMemberDecoration(Id, unsigned int member, spv::Decoration, + void AddName(Id target_id, const char* name); + void AddMemberName(Id target_id, int member, const char* name); + void AddLine(Id target_id, Id file_name, int line_number, int column_number); + void AddDecoration(Id target_id, spv::Decoration decoration, int num = -1); + void AddMemberDecoration(Id target_id, int member, spv::Decoration, int num = -1); // At the end of what block do the next create*() instructions go? Block* build_point() const { return build_point_; } void set_build_point(Block* build_point) { build_point_ = build_point; } - // Make the main function. - Function* makeMain(); + // Makes the main function. + Function* MakeMainEntry(); - // Make a shader-style function, and create its entry block if entry is + // Makes a shader-style function, and create its entry block if entry is // non-zero. // Return the function, pass back the entry. - Function* makeFunctionEntry(Id return_type, const char* name, - std::vector& param_types, Block** entry = 0); + Function* MakeFunctionEntry(Id return_type, const char* name, + std::initializer_list param_types, + Block** entry = 0); - // Create a return. An 'implicit' return is one not appearing in the source - // code. In the case of an implicit return, no post-return block is inserted. - void makeReturn(bool implicit, Id retVal = 0); + // Creates a return statement. + // An 'implicit' return is one not appearing in the source code. In the case + // of an implicit return, no post-return block is inserted. + void MakeReturn(bool implicit, Id return_value = 0); - // Generate all the code needed to finish up a function. - void leaveFunction(); + // Generates all the code needed to finish up a function. + void LeaveFunction(); - // Create a discard. - void makeDiscard(); + // Creates a fragment-shader discard (kill). + void MakeDiscard(); - // Create a global or function local or IO variable. - Id createVariable(spv::StorageClass storage_class, Id type, + // Creates a global or function local or IO variable. + Id CreateVariable(spv::StorageClass storage_class, Id type, const char* name = 0); - // Create an imtermediate with an undefined value. - Id createUndefined(Id type); + // Creates an intermediate object whose value is undefined. + Id CreateUndefined(Id type); - // Store into an Id and return the l-value - void createStore(Id rvalue, Id lvalue); + // Stores the given value into the specified pointer. + void CreateStore(Id pointer_id, Id value_id); - // Load from an Id and return it - Id createLoad(Id lvalue); + // Loads the value from the given pointer. + Id CreateLoad(Id pointer_id); - // Create an OpAccessChain instruction - Id createAccessChain(spv::StorageClass storage_class, Id base, - std::vector& offsets); + // Creates a pointer into a composite object that can be used with OpLoad and + // OpStore. + Id CreateAccessChain(spv::StorageClass storage_class, Id base_id, + std::vector index_ids); - // Create an OpArrayLength instruction - Id createArrayLength(Id base, unsigned int member); + // Queries the length of a run-time array. + Id CreateArrayLength(Id struct_id, int array_member); - // Create an OpCompositeExtract instruction - Id createCompositeExtract(Id composite, Id type_id, unsigned index); - Id createCompositeExtract(Id composite, Id type_id, - std::vector& indexes); - Id createCompositeInsert(Id object, Id composite, Id type_id, unsigned index); - Id createCompositeInsert(Id object, Id composite, Id type_id, - std::vector& indexes); + Id CreateCompositeExtract(Id composite, Id type_id, uint32_t index); + Id CreateCompositeExtract(Id composite, Id type_id, + std::vector indexes); + Id CreateCompositeInsert(Id object, Id composite, Id type_id, uint32_t index); + Id CreateCompositeInsert(Id object, Id composite, Id type_id, + std::vector indexes); - Id createVectorExtractDynamic(Id vector, Id type_id, Id component_index); - Id createVectorInsertDynamic(Id vector, Id type_id, Id component, + Id CreateVectorExtractDynamic(Id vector, Id type_id, Id component_index); + Id CreateVectorInsertDynamic(Id vector, Id type_id, Id component, Id component_index); - void createNoResultOp(Op); - void createNoResultOp(Op, Id operand); - void createNoResultOp(Op, const std::vector& operands); - void createControlBarrier(spv::Scope execution, spv::Scope memory, - spv::MemorySemanticsMask); - void createMemoryBarrier(unsigned execution_scope, unsigned memory_semantics); - Id createUnaryOp(Op, Id type_id, Id operand); - Id createBinOp(Op, Id type_id, Id operand1, Id operand2); - Id createTriOp(Op, Id type_id, Id operand1, Id operand2, Id operand3); - Id createOp(Op, Id type_id, const std::vector& operands); - Id createFunctionCall(Function*, std::vector&); + // Does nothing. + void CreateNop(); - // Take an rvalue (source) and a set of channels to extract from it to - // make a new rvalue, which is returned. - Id createRvalueSwizzle(Id type_id, Id source, - std::vector& channels); + // Waits for other invocations of this module to reach the current point of + // execution. + void CreateControlBarrier(spv::Scope execution_scope, spv::Scope memory_scope, + spv::MemorySemanticsMask memory_semantics); + // Controls the order that memory accesses are observed. + void CreateMemoryBarrier(spv::Scope execution_scope, + spv::MemorySemanticsMask memory_semantics); - // Take a copy of an lvalue (target) and a source of components, and set the + Id CreateUnaryOp(Op opcode, Id type_id, Id operand); + Id CreateBinOp(Op opcode, Id type_id, Id operand1, Id operand2); + Id CreateTriOp(Op opcode, Id type_id, Id operand1, Id operand2, Id operand3); + Id CreateOp(Op opcode, Id type_id, const std::vector& operands); + Id CreateFunctionCall(Function* function, std::vector args); + + // Takes an rvalue (source) and a set of channels to extract from it to + // make a new rvalue. + Id CreateSwizzle(Id type_id, Id source, std::vector channels); + + // Takes a copy of an lvalue (target) and a source of components, and sets the // source components into the lvalue where the 'channels' say to put them. - // An updated version of the target is returned. - // (No true lvalue or stores are used.) - Id createLvalueSwizzle(Id type_id, Id target, Id source, - std::vector& channels); + Id CreateLvalueSwizzle(Id type_id, Id target, Id source, + std::vector channels); // If the value passed in is an instruction and the precision is not EMpNone, // it gets tagged with the requested precision. - void setPrecision(Id value, spv::Decoration precision) { + void SetPrecision(Id value, spv::Decoration precision) { CheckNotImplemented("setPrecision"); } - // Can smear a scalar to a vector for the following forms: - // - promoteScalar(scalar, vector) // smear scalar to width of vector - // - promoteScalar(vector, scalar) // smear scalar to width of vector - // - promoteScalar(pointer, scalar) // smear scalar to width of what pointer - // points to - // - promoteScalar(scalar, scalar) // do nothing + // Smears a scalar to a vector for the following forms: + // - PromoteScalar(scalar, vector) // smear scalar to width of vector + // - PromoteScalar(vector, scalar) // smear scalar to width of vector + // - PromoteScalar(pointer, scalar) // smear scalar to width of what pointer + // points to + // - PromoteScalar(scalar, scalar) // do nothing // Other forms are not allowed. // // Note: One of the arguments will change, with the result coming back that - // way rather than - // through the return value. - void promoteScalar(spv::Decoration precision, Id& left, Id& right); + // way rather than through the return value. + void PromoteScalar(spv::Decoration precision, Id& left, Id& right); - // make a value by smearing the scalar to fill the type - Id smearScalar(spv::Decoration precision, Id scalarVal, Id); + // Makes a value by smearing the scalar to fill the type. + Id SmearScalar(spv::Decoration precision, Id scalar_value, Id vector_type_id); - // Create a call to a built-in function. - Id createBuiltinCall(spv::Decoration precision, Id result_type, Id builtins, - int entry_point, std::initializer_list args); + // Executes an instruction in an imported set of extended instructions. + Id CreateExtendedInstructionCall(spv::Decoration precision, Id result_type, + Id instruction_set, int instruction_ordinal, + std::initializer_list args); // List of parameters used to create a texture operation struct TextureParameters { @@ -375,45 +380,45 @@ class SpvEmitter { Id coords; Id bias; Id lod; - Id Dref; + Id depth_ref; Id offset; Id offsets; - Id gradX; - Id gradY; + Id grad_x; + Id grad_y; Id sample; Id comp; }; - // Select the correct texture operation based on all inputs, and emit the - // correct instruction - Id createTextureCall(spv::Decoration precision, Id result_type, bool fetch, - bool proj, bool gather, const TextureParameters&); + // Selects the correct texture operation based on all inputs, and emit the + // correct instruction. + Id CreateTextureCall(spv::Decoration precision, Id result_type, bool fetch, + bool proj, bool gather, + const TextureParameters& parameters); - // Emit the OpTextureQuery* instruction that was passed in. - // Figure out the right return value and type, and return it. - Id createTextureQueryCall(Op, const TextureParameters&); + // Emits the OpTextureQuery* instruction that was passed in and figures out + // the right return value and type. + Id CreateTextureQueryCall(Op opcode, const TextureParameters& parameters); - Id createSamplePositionCall(spv::Decoration precision, Id, Id); - - Id createBitFieldExtractCall(spv::Decoration precision, Id, Id, Id, + Id CreateSamplePositionCall(spv::Decoration precision, Id, Id); + Id CreateBitFieldExtractCall(spv::Decoration precision, Id, Id, Id, bool isSigned); - Id createBitFieldInsertCall(spv::Decoration precision, Id, Id, Id, Id); + Id CreateBitFieldInsertCall(spv::Decoration precision, Id, Id, Id, Id); // Reduction comparision for composites: For equal and not-equal resulting in // a scalar. - Id createCompare(spv::Decoration precision, Id, Id, - bool /* true if for equal, fales if for not-equal */); + Id CreateCompare(spv::Decoration precision, Id value1, Id value2, + bool is_equal); // OpCompositeConstruct - Id createCompositeConstruct(Id type_id, std::vector& constituents); + Id CreateCompositeConstruct(Id type_id, std::vector constituent_ids); // vector or scalar constructor - Id createConstructor(spv::Decoration precision, - const std::vector& sources, Id result_type_id); + Id CreateConstructor(spv::Decoration precision, std::vector source_ids, + Id result_type_id); // matrix constructor - Id createMatrixConstructor(spv::Decoration precision, - const std::vector& sources, Id constructee); + Id CreateMatrixConstructor(spv::Decoration precision, std::vector sources, + Id constructee); // Helper to use for building nested control flow with if-then-else. class If { @@ -421,8 +426,8 @@ class SpvEmitter { If(SpvEmitter& emitter, Id condition); ~If() = default; - void makeBeginElse(); - void makeEndIf(); + void MakeBeginElse(); + void MakeEndIf(); private: If(const If&) = delete; @@ -437,7 +442,7 @@ class SpvEmitter { Block* merge_block_ = nullptr; }; - // Make a switch statement. + // Makes a switch statement. // A switch has 'numSegments' of pieces of code, not containing any // case/default labels, all separated by one or more case/default labels. // Each possible case value v is a jump to the caseValues[v] segment. The @@ -452,46 +457,46 @@ class SpvEmitter { // // Returns the right set of basic blocks to start each code segment with, so // that the caller's recursion stack can hold the memory for it. - void makeSwitch(Id condition, int numSegments, std::vector& caseValues, - std::vector& valueToSegment, int defaultSegment, - std::vector& segmentBB); // return argument + void MakeSwitch(Id condition, int segment_count, std::vector case_values, + std::vector value_index_to_segment, int default_segment, + std::vector& segment_blocks); - // Add a branch to the innermost switch's merge block. - void addSwitchBreak(); + // Adds a branch to the innermost switch's merge block. + void AddSwitchBreak(); - // Move to the next code segment, passing in the return argument in - // makeSwitch() - void nextSwitchSegment(std::vector& segmentBB, int segment); + // Move sto the next code segment, passing in the return argument in + // MakeSwitch(). + void NextSwitchSegment(std::vector& segment_block, int next_segment); - // Finish off the innermost switch. - void endSwitch(std::vector& segmentBB); + // Finishes off the innermost switch. + void EndSwitch(std::vector& segment_block); - // Start the beginning of a new loop, and prepare the builder to + // Starts the beginning of a new loop, and prepare the builder to // generate code for the loop test. - // The loopTestFirst parameter is true when the loop test executes before - // the body. (It is false for do-while loops.) - void makeNewLoop(bool loopTestFirst); + // The test_first parameter is true when the loop test executes before + // the body (it is false for do-while loops). + void MakeNewLoop(bool test_first); - // Add the branch for the loop test, based on the given condition. + // Adds the branch for the loop test, based on the given condition. // The true branch goes to the first block in the loop body, and // the false branch goes to the loop's merge block. The builder insertion // point will be placed at the start of the body. - void createLoopTestBranch(Id condition); + void CreateLoopTestBranch(Id condition); - // Generate an unconditional branch to the loop body. The builder insertion - // point will be placed at the start of the body. Use this when there is - // no loop test. - void createBranchToBody(); + // Generates an unconditional branch to the loop body. + // The builder insertion point will be placed at the start of the body. + // Use this when there is no loop test. + void CreateBranchToBody(); - // Add a branch to the test of the current (innermost) loop. + // Adds a branch to the test of the current (innermost) loop. // The way we generate code, that's also the loop header. - void createLoopContinue(); + void CreateLoopContinue(); - // Add an exit (e.g. "break") for the innermost loop that you're in - void createLoopExit(); + // Adds an exit (e.g. "break") for the innermost loop that you're in. + void CreateLoopExit(); - // Close the innermost loop that you're in - void closeLoop(); + // Close the innermost loop that you're in. + void CloseLoop(); // Access chain design for an R-Value vs. L-Value: // @@ -528,7 +533,7 @@ class SpvEmitter { // base object std::vector index_chain; Id instr; // cache the instruction that generates this access chain - std::vector swizzle; // each std::vector element selects the next + std::vector swizzle; // each std::vector element selects the next // GLSL component number Id component; // a dynamic component index, can coexist with a swizzle, // done after the swizzle, NoResult if not present @@ -549,83 +554,98 @@ class SpvEmitter { AccessChain access_chain() { return access_chain_; } void set_access_chain(AccessChain new_chain) { access_chain_ = new_chain; } - // clear accessChain - void clearAccessChain(); + void ClearAccessChain(); // set new base as an l-value base - void setAccessChainLValue(Id lvalue) { - assert(isPointer(lvalue)); + void set_access_chain_lvalue(Id lvalue) { + assert(IsPointer(lvalue)); access_chain_.base = lvalue; } // set new base value as an r-value - void setAccessChainRValue(Id rvalue) { + void set_access_chain_rvalue(Id rvalue) { access_chain_.is_rvalue = true; access_chain_.base = rvalue; } // push offset onto the end of the chain - void accessChainPush(Id offset) { + void PushAccessChainOffset(Id offset) { access_chain_.index_chain.push_back(offset); } // push new swizzle onto the end of any existing swizzle, merging into a // single swizzle - void accessChainPushSwizzle(std::vector& swizzle, + void PushAccessChainSwizzle(std::vector swizzle, Id pre_swizzle_base_type); // push a variable component selection onto the access chain; supporting only // one, so unsided - void accessChainPushComponent(Id component, Id pre_swizzle_base_type) { + void PushAccessChainComponent(Id component, Id pre_swizzle_base_type) { access_chain_.component = component; - if (access_chain_.pre_swizzle_base_type == NoType) + if (access_chain_.pre_swizzle_base_type == NoType) { access_chain_.pre_swizzle_base_type = pre_swizzle_base_type; + } } // use accessChain and swizzle to store value - void accessChainStore(Id rvalue); + void CreateAccessChainStore(Id rvalue); // use accessChain and swizzle to load an r-value - Id accessChainLoad(Id result_type); + Id CreateAccessChainLoad(Id result_type_id); // get the direct pointer for an l-value - Id accessChainGetLValue(); + Id CreateAccessChainLValue(); - void dump(std::vector&) const; + void Serialize(std::vector& out) const; private: // Maximum dimension for column/row in a matrix. static const int kMaxMatrixSize = 4; - // Asserts on unimplemnted functionality. - void CheckNotImplemented(const char* message); + // Allocates a new . + Id AllocateUniqueId() { return ++unique_id_; } - Id makeIntConstant(Id type_id, unsigned value, bool is_spec_constant); - Id findScalarConstant(Op type_class, Op opcode, Id type_id, - unsigned value) const; - Id findScalarConstant(Op type_class, Op opcode, Id type_id, unsigned v1, - unsigned v2) const; - Id findCompositeConstant(Op type_class, std::vector& comps) const; - Id collapseAccessChain(); - void transferAccessChainSwizzle(bool dynamic); - void simplifyAccessChainSwizzle(); - void createAndSetNoPredecessorBlock(const char*); - void createBranch(Block* block); - void createSelectionMerge(Block* merge_block, + // Allocates a contiguous sequence of s. + Id AllocateUniqueIds(int count) { + Id id = unique_id_ + 1; + unique_id_ += count; + return id; + } + + Id MakeIntegerConstant(Id type_id, uint32_t value, bool is_spec_constant); + Id FindScalarConstant(Op type_class, Op opcode, Id type_id, + uint32_t value) const; + Id FindScalarConstant(Op type_class, Op opcode, Id type_id, uint32_t v1, + uint32_t v2) const; + Id FindCompositeConstant(Op type_class, + std::initializer_list components) const; + + Id CollapseAccessChain(); + void SimplifyAccessChainSwizzle(); + void TransferAccessChainSwizzle(bool dynamic); + + void SerializeInstructions( + std::vector& out, + const std::vector& instructions) const; + + void CreateAndSetNoPredecessorBlock(const char* name); + void CreateBranch(Block* block); + void CreateSelectionMerge(Block* merge_block, spv::SelectionControlMask control); - void createLoopMerge(Block* merge_block, Block* continueBlock, + void CreateLoopMerge(Block* merge_block, Block* continueBlock, spv::LoopControlMask control); - void createConditionalBranch(Id condition, Block* then_block, + void CreateConditionalBranch(Id condition, Block* then_block, Block* else_block); - void dumpInstructions(std::vector&, - const std::vector&) const; struct Loop; // Defined below. - void createBranchToLoopHeaderFromInside(const Loop& loop); + void CreateBranchToLoopHeaderFromInside(const Loop& loop); + + // Asserts on unimplemented functionality. + void CheckNotImplemented(const char* message); spv::SourceLanguage source_language_ = spv::SourceLanguage::Unknown; int source_version_ = 0; - std::vector extensions_; + std::vector source_extensions_; spv::AddressingModel addressing_model_ = spv::AddressingModel::Logical; spv::MemoryModel memory_model_ = spv::MemoryModel::GLSL450; std::vector capabilities_; @@ -647,12 +667,13 @@ class SpvEmitter { std::vector externals_; // not output, internally used for quick & dirty canonical (unique) creation - std::vector grouped_constants_[static_cast( - spv::Op::OpConstant)]; // all types appear before OpConstant + // All types appear before OpConstant. + std::vector + grouped_constants_[static_cast(spv::Op::OpConstant)]; std::vector grouped_types_[static_cast(spv::Op::OpConstant)]; - // stack of switches + // Stack of switches. std::stack switch_merges_; // Data that needs to be kept in order to properly handle loops. diff --git a/src/xenia/gpu/spirv/spv_ir.h b/src/xenia/gpu/spirv/spv_ir.h index 47a17a872..640da4bde 100644 --- a/src/xenia/gpu/spirv/spv_ir.h +++ b/src/xenia/gpu/spirv/spv_ir.h @@ -86,55 +86,66 @@ class Instruction { explicit Instruction(Op opcode) : opcode_(opcode) {} ~Instruction() = default; - void addIdOperand(Id id) { operands_.push_back(id); } + void AddIdOperand(Id id) { operands_.push_back(id); } - void addIdOperands(const std::vector& ids) { + void AddIdOperands(const std::vector& ids) { + for (auto id : ids) { + operands_.push_back(id); + } + } + void AddIdOperands(std::initializer_list ids) { for (auto id : ids) { operands_.push_back(id); } } - void addImmediateOperand(uint32_t immediate) { + void AddImmediateOperand(uint32_t immediate) { operands_.push_back(immediate); } template - void addImmediateOperand(T immediate) { + void AddImmediateOperand(T immediate) { static_assert(sizeof(T) == sizeof(uint32_t), "Invalid operand size"); operands_.push_back(static_cast(immediate)); } - void addImmediateOperands(const std::vector& immediates) { + void AddImmediateOperands(const std::vector& immediates) { for (auto immediate : immediates) { operands_.push_back(immediate); } } - void addStringOperand(const char* str) { + void AddImmediateOperands(std::initializer_list immediates) { + for (auto immediate : immediates) { + operands_.push_back(immediate); + } + } + + void AddStringOperand(const char* str) { original_string_ = str; uint32_t word; - char* wordString = (char*)&word; - char* wordPtr = wordString; - int charCount = 0; + char* word_string = reinterpret_cast(&word); + char* word_ptr = word_string; + int char_count = 0; char c; do { c = *(str++); - *(wordPtr++) = c; - ++charCount; - if (charCount == 4) { - addImmediateOperand(word); - wordPtr = wordString; - charCount = 0; + *(word_ptr++) = c; + ++char_count; + if (char_count == 4) { + AddImmediateOperand(word); + word_ptr = word_string; + char_count = 0; } } while (c != 0); // deal with partial last word - if (charCount > 0) { + if (char_count > 0) { // pad with 0s - for (; charCount < 4; ++charCount) { - *(wordPtr++) = 0; + for (; char_count < 4; ++char_count) { + *(word_ptr++) = 0; } - addImmediateOperand(word); + AddImmediateOperand(word); } } @@ -147,17 +158,17 @@ class Instruction { const char* string_operand() const { return original_string_.c_str(); } // Write out the binary form. - void dump(std::vector& out) const { - uint32_t wordCount = 1; + void Serialize(std::vector& out) const { + uint32_t word_count = 1; if (type_id_) { - ++wordCount; + ++word_count; } if (result_id_) { - ++wordCount; + ++word_count; } - wordCount += static_cast(operands_.size()); + word_count += static_cast(operands_.size()); - out.push_back((wordCount << spv::WordCountShift) | + out.push_back((word_count << spv::WordCountShift) | static_cast(opcode_)); if (type_id_) { out.push_back(type_id_); @@ -185,19 +196,24 @@ class Block { public: Block(Id id, Function& parent); ~Block() { - // TODO: free instructions + for (size_t i = 0; i < instructions_.size(); ++i) { + delete instructions_[i]; + } + for (size_t i = 0; i < local_variables_.size(); ++i) { + delete local_variables_[i]; + } } Id id() { return instructions_.front()->result_id(); } Function& parent() const { return parent_; } - void push_instruction(Instruction* inst); - void push_local_variable(Instruction* inst) { - local_variables_.push_back(inst); + void AddInstruction(Instruction* instr); + void AddLocalVariable(Instruction* instr) { + local_variables_.push_back(instr); } - void push_predecessor(Block* predecessor) { + void AddPredecessor(Block* predecessor) { predecessors_.push_back(predecessor); } @@ -222,7 +238,7 @@ class Block { } } - void dump(std::vector& out) const { + void Serialize(std::vector& out) const { // skip the degenerate unreachable blocks // TODO: code gen: skip all unreachable blocks (transitive closure) // (but, until that's done safer to keep non-degenerate @@ -231,12 +247,12 @@ class Block { return; } - instructions_[0]->dump(out); + instructions_[0]->Serialize(out); for (auto variable : local_variables_) { - variable->dump(out); + variable->Serialize(out); } for (int i = 1; i < instructions_.size(); ++i) { - instructions_[i]->dump(out); + instructions_[i]->Serialize(out); } } @@ -275,32 +291,32 @@ class Function { Id param_id(int p) { return parameter_instructions_[p]->result_id(); } void push_block(Block* block) { blocks_.push_back(block); } - void pop_block(Block*) { blocks_.pop_back(); } + void pop_block(Block* block) { blocks_.pop_back(); } Module& parent() const { return parent_; } Block* entry_block() const { return blocks_.front(); } Block* last_block() const { return blocks_.back(); } - void push_local_variable(Instruction* inst); + void AddLocalVariable(Instruction* instr); Id return_type() const { return function_instruction_.type_id(); } - void dump(std::vector& out) const { + void Serialize(std::vector& out) const { // OpFunction - function_instruction_.dump(out); + function_instruction_.Serialize(out); // OpFunctionParameter for (auto instruction : parameter_instructions_) { - instruction->dump(out); + instruction->Serialize(out); } // Blocks for (auto block : blocks_) { - block->dump(out); + block->Serialize(out); } Instruction end(0, 0, spv::Op::OpFunctionEnd); - end.dump(out); + end.Serialize(out); } private: @@ -317,32 +333,35 @@ class Module { public: Module() = default; ~Module() { - // TODO delete things + for (size_t i = 0; i < functions_.size(); ++i) { + delete functions_[i]; + } } - void push_function(Function* function) { functions_.push_back(function); } + void AddFunction(Function* function) { functions_.push_back(function); } - void mapInstruction(Instruction* instruction) { - spv::Id result_id = instruction->result_id(); - // map the instruction's result id - if (result_id >= id_to_instruction_.size()) + void MapInstruction(Instruction* instr) { + spv::Id result_id = instr->result_id(); + // Map the instruction's result id. + if (result_id >= id_to_instruction_.size()) { id_to_instruction_.resize(result_id + 16); - id_to_instruction_[result_id] = instruction; + } + id_to_instruction_[result_id] = instr; } - Instruction* getInstruction(Id id) const { return id_to_instruction_[id]; } + Instruction* instruction(Id id) const { return id_to_instruction_[id]; } - spv::Id getTypeId(Id result_id) const { + spv::Id type_id(Id result_id) const { return id_to_instruction_[result_id]->type_id(); } - spv::StorageClass getStorageClass(Id type_id) const { + spv::StorageClass storage_class(Id type_id) const { return (spv::StorageClass)id_to_instruction_[type_id]->immediate_operand(0); } - void dump(std::vector& out) const { + void Serialize(std::vector& out) const { for (auto function : functions_) { - function->dump(out); + function->Serialize(out); } } @@ -351,37 +370,36 @@ class Module { std::vector functions_; - // map from result id to instruction having that result id + // Maps from result id to instruction having that result id. std::vector id_to_instruction_; - - // map from a result id to its type id }; -inline Function::Function(Id id, Id resultType, Id functionType, - Id firstParamId, Module& parent) +inline Function::Function(Id id, Id result_type_id, Id function_type_id, + Id first_param_id, Module& parent) : parent_(parent), - function_instruction_(id, resultType, spv::Op::OpFunction) { + function_instruction_(id, result_type_id, spv::Op::OpFunction) { // OpFunction - function_instruction_.addImmediateOperand( + function_instruction_.AddImmediateOperand( static_cast(spv::FunctionControlMask::MaskNone)); - function_instruction_.addIdOperand(functionType); - parent.mapInstruction(&function_instruction_); - parent.push_function(this); + function_instruction_.AddIdOperand(function_type_id); + parent.MapInstruction(&function_instruction_); + parent.AddFunction(this); // OpFunctionParameter - Instruction* typeInst = parent.getInstruction(functionType); - int numParams = typeInst->operand_count() - 1; - for (int p = 0; p < numParams; ++p) { - auto param = new Instruction(firstParamId + p, typeInst->id_operand(p + 1), - spv::Op::OpFunctionParameter); - parent.mapInstruction(param); + Instruction* type_instr = parent.instruction(function_type_id); + int param_count = type_instr->operand_count() - 1; + for (int p = 0; p < param_count; ++p) { + auto param = + new Instruction(first_param_id + p, type_instr->id_operand(p + 1), + spv::Op::OpFunctionParameter); + parent.MapInstruction(param); parameter_instructions_.push_back(param); } } -inline void Function::push_local_variable(Instruction* inst) { - blocks_[0]->push_local_variable(inst); - parent_.mapInstruction(inst); +inline void Function::AddLocalVariable(Instruction* instr) { + blocks_[0]->AddLocalVariable(instr); + parent_.MapInstruction(instr); } inline Block::Block(Id id, Function& parent) @@ -389,10 +407,10 @@ inline Block::Block(Id id, Function& parent) instructions_.push_back(new Instruction(id, NoType, spv::Op::OpLabel)); } -inline void Block::push_instruction(Instruction* inst) { +inline void Block::AddInstruction(Instruction* inst) { instructions_.push_back(inst); if (inst->result_id()) { - parent_.parent().mapInstruction(inst); + parent_.parent().MapInstruction(inst); } }