[SPIR-V] Operand loading
This commit is contained in:
parent
de059f3d57
commit
4dba2d8d89
|
@ -29,6 +29,10 @@ void SpirvShaderTranslator::Reset() {
|
||||||
|
|
||||||
builder_.reset();
|
builder_.reset();
|
||||||
|
|
||||||
|
uniform_float_constants_ = spv::NoResult;
|
||||||
|
|
||||||
|
var_main_registers_ = spv::NoResult;
|
||||||
|
|
||||||
main_switch_op_.reset();
|
main_switch_op_.reset();
|
||||||
main_switch_next_pc_phi_operands_.clear();
|
main_switch_next_pc_phi_operands_.clear();
|
||||||
|
|
||||||
|
@ -85,15 +89,42 @@ void SpirvShaderTranslator::StartTranslation() {
|
||||||
const_float4_0_ =
|
const_float4_0_ =
|
||||||
builder_->makeCompositeConstant(type_float4_, id_vector_temp_);
|
builder_->makeCompositeConstant(type_float4_, id_vector_temp_);
|
||||||
|
|
||||||
|
// Common uniform buffer - float constants.
|
||||||
|
uint32_t float_constant_count = constant_register_map().float_count;
|
||||||
|
if (float_constant_count) {
|
||||||
|
id_vector_temp_.clear();
|
||||||
|
id_vector_temp_.reserve(1);
|
||||||
|
id_vector_temp_.push_back(builder_->makeArrayType(
|
||||||
|
type_float4_, builder_->makeUintConstant(float_constant_count),
|
||||||
|
sizeof(float) * 4));
|
||||||
|
// Currently (as of October 24, 2020) makeArrayType only uses the stride to
|
||||||
|
// check if deduplication can be done - the array stride decoration needs to
|
||||||
|
// be applied explicitly.
|
||||||
|
builder_->addDecoration(id_vector_temp_.back(), spv::DecorationArrayStride,
|
||||||
|
sizeof(float) * 4);
|
||||||
|
spv::Id type_float_constants =
|
||||||
|
builder_->makeStructType(id_vector_temp_, "XeFloatConstants");
|
||||||
|
builder_->addMemberName(type_float_constants, 0, "float_constants");
|
||||||
|
builder_->addMemberDecoration(type_float_constants, 0,
|
||||||
|
spv::DecorationOffset, 0);
|
||||||
|
builder_->addDecoration(type_float_constants, spv::DecorationBlock);
|
||||||
|
uniform_float_constants_ = builder_->createVariable(
|
||||||
|
spv::NoPrecision, spv::StorageClassUniform, type_float_constants,
|
||||||
|
"xe_uniform_float_constants");
|
||||||
|
builder_->addDecoration(
|
||||||
|
uniform_float_constants_, spv::DecorationDescriptorSet,
|
||||||
|
int(IsSpirvFragmentShader() ? kDescriptorSetFloatConstantsPixel
|
||||||
|
: kDescriptorSetFloatConstantsVertex));
|
||||||
|
builder_->addDecoration(uniform_float_constants_, spv::DecorationBinding,
|
||||||
|
0);
|
||||||
|
}
|
||||||
|
|
||||||
// Common uniform buffer - bool and loop constants.
|
// Common uniform buffer - bool and loop constants.
|
||||||
id_vector_temp_.clear();
|
id_vector_temp_.clear();
|
||||||
id_vector_temp_.reserve(2);
|
id_vector_temp_.reserve(2);
|
||||||
// 256 bool constants.
|
// 256 bool constants.
|
||||||
id_vector_temp_.push_back(builder_->makeArrayType(
|
id_vector_temp_.push_back(builder_->makeArrayType(
|
||||||
type_uint4_, builder_->makeUintConstant(2), sizeof(uint32_t) * 4));
|
type_uint4_, builder_->makeUintConstant(2), sizeof(uint32_t) * 4));
|
||||||
// Currently (as of October 24, 2020) makeArrayType only uses the stride to
|
|
||||||
// check if deduplication can be done - the array stride decoration needs to
|
|
||||||
// be applied explicitly.
|
|
||||||
builder_->addDecoration(id_vector_temp_.back(), spv::DecorationArrayStride,
|
builder_->addDecoration(id_vector_temp_.back(), spv::DecorationArrayStride,
|
||||||
sizeof(uint32_t) * 4);
|
sizeof(uint32_t) * 4);
|
||||||
// 32 loop constants.
|
// 32 loop constants.
|
||||||
|
@ -188,7 +219,7 @@ void SpirvShaderTranslator::StartTranslation() {
|
||||||
// Main loop header - based on whether it's the first iteration (entered from
|
// Main loop header - based on whether it's the first iteration (entered from
|
||||||
// the function or from the continuation), choose the program counter.
|
// the function or from the continuation), choose the program counter.
|
||||||
builder_->setBuildPoint(main_loop_header_);
|
builder_->setBuildPoint(main_loop_header_);
|
||||||
spv::Id main_loop_pc_current = 0;
|
spv::Id main_loop_pc_current = spv::NoResult;
|
||||||
if (has_main_switch) {
|
if (has_main_switch) {
|
||||||
// OpPhi must be the first in the block.
|
// OpPhi must be the first in the block.
|
||||||
id_vector_temp_.clear();
|
id_vector_temp_.clear();
|
||||||
|
@ -704,15 +735,24 @@ void SpirvShaderTranslator::StartVertexOrTessEvalShaderBeforeMain() {
|
||||||
builder_->makeArrayType(type_float_, builder_->makeUintConstant(1), 0));
|
builder_->makeArrayType(type_float_, builder_->makeUintConstant(1), 0));
|
||||||
spv::Id type_struct_per_vertex =
|
spv::Id type_struct_per_vertex =
|
||||||
builder_->makeStructType(struct_per_vertex_members, "gl_PerVertex");
|
builder_->makeStructType(struct_per_vertex_members, "gl_PerVertex");
|
||||||
|
builder_->addMemberDecoration(type_struct_per_vertex,
|
||||||
|
kOutputPerVertexMemberPosition,
|
||||||
|
spv::DecorationInvariant);
|
||||||
builder_->addMemberDecoration(type_struct_per_vertex,
|
builder_->addMemberDecoration(type_struct_per_vertex,
|
||||||
kOutputPerVertexMemberPosition,
|
kOutputPerVertexMemberPosition,
|
||||||
spv::DecorationBuiltIn, spv::BuiltInPosition);
|
spv::DecorationBuiltIn, spv::BuiltInPosition);
|
||||||
builder_->addMemberDecoration(type_struct_per_vertex,
|
builder_->addMemberDecoration(type_struct_per_vertex,
|
||||||
kOutputPerVertexMemberPointSize,
|
kOutputPerVertexMemberPointSize,
|
||||||
spv::DecorationBuiltIn, spv::BuiltInPointSize);
|
spv::DecorationBuiltIn, spv::BuiltInPointSize);
|
||||||
|
builder_->addMemberDecoration(type_struct_per_vertex,
|
||||||
|
kOutputPerVertexMemberClipDistance,
|
||||||
|
spv::DecorationInvariant);
|
||||||
builder_->addMemberDecoration(
|
builder_->addMemberDecoration(
|
||||||
type_struct_per_vertex, kOutputPerVertexMemberClipDistance,
|
type_struct_per_vertex, kOutputPerVertexMemberClipDistance,
|
||||||
spv::DecorationBuiltIn, spv::BuiltInClipDistance);
|
spv::DecorationBuiltIn, spv::BuiltInClipDistance);
|
||||||
|
builder_->addMemberDecoration(type_struct_per_vertex,
|
||||||
|
kOutputPerVertexMemberCullDistance,
|
||||||
|
spv::DecorationInvariant);
|
||||||
builder_->addMemberDecoration(
|
builder_->addMemberDecoration(
|
||||||
type_struct_per_vertex, kOutputPerVertexMemberCullDistance,
|
type_struct_per_vertex, kOutputPerVertexMemberCullDistance,
|
||||||
spv::DecorationBuiltIn, spv::BuiltInCullDistance);
|
spv::DecorationBuiltIn, spv::BuiltInCullDistance);
|
||||||
|
@ -902,5 +942,132 @@ void SpirvShaderTranslator::CloseExecConditionals() {
|
||||||
cf_exec_predicate_written_ = false;
|
cf_exec_predicate_written_ = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
spv::Id SpirvShaderTranslator::GetStorageAddressingIndex(
|
||||||
|
InstructionStorageAddressingMode addressing_mode, uint32_t storage_index) {
|
||||||
|
EnsureBuildPointAvailable();
|
||||||
|
spv::Id base_pointer = spv::NoResult;
|
||||||
|
switch (addressing_mode) {
|
||||||
|
case InstructionStorageAddressingMode::kStatic:
|
||||||
|
return builder_->makeIntConstant(int(storage_index));
|
||||||
|
case InstructionStorageAddressingMode::kAddressAbsolute:
|
||||||
|
base_pointer = var_main_address_absolute_;
|
||||||
|
break;
|
||||||
|
case InstructionStorageAddressingMode::kAddressRelative:
|
||||||
|
// Load X component.
|
||||||
|
id_vector_temp_util_.clear();
|
||||||
|
id_vector_temp_util_.reserve(1);
|
||||||
|
id_vector_temp_util_.push_back(const_int_0_);
|
||||||
|
base_pointer = builder_->createAccessChain(spv::StorageClassFunction,
|
||||||
|
var_main_address_relative_,
|
||||||
|
id_vector_temp_util_);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
assert_not_zero(base_pointer);
|
||||||
|
spv::Id index = builder_->createLoad(base_pointer, spv::NoPrecision);
|
||||||
|
if (storage_index) {
|
||||||
|
index =
|
||||||
|
builder_->createBinOp(spv::OpIAdd, type_int_, index,
|
||||||
|
builder_->makeIntConstant(int(storage_index)));
|
||||||
|
}
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
|
||||||
|
spv::Id SpirvShaderTranslator::LoadOperandStorage(
|
||||||
|
const InstructionOperand& operand) {
|
||||||
|
spv::Id index = GetStorageAddressingIndex(operand.storage_addressing_mode,
|
||||||
|
operand.storage_index);
|
||||||
|
EnsureBuildPointAvailable();
|
||||||
|
spv::Id vec4_pointer = spv::NoResult;
|
||||||
|
switch (operand.storage_source) {
|
||||||
|
case InstructionStorageSource::kRegister:
|
||||||
|
assert_not_zero(var_main_registers_);
|
||||||
|
id_vector_temp_util_.clear();
|
||||||
|
id_vector_temp_util_.reserve(1);
|
||||||
|
// Array element.
|
||||||
|
id_vector_temp_util_.push_back(index);
|
||||||
|
vec4_pointer = builder_->createAccessChain(
|
||||||
|
spv::StorageClassFunction, var_main_registers_, id_vector_temp_util_);
|
||||||
|
break;
|
||||||
|
case InstructionStorageSource::kConstantFloat:
|
||||||
|
assert_not_zero(uniform_float_constants_);
|
||||||
|
id_vector_temp_util_.clear();
|
||||||
|
id_vector_temp_util_.reserve(2);
|
||||||
|
// The first and the only structure member.
|
||||||
|
id_vector_temp_util_.push_back(const_int_0_);
|
||||||
|
// Array element.
|
||||||
|
id_vector_temp_util_.push_back(index);
|
||||||
|
vec4_pointer = builder_->createAccessChain(spv::StorageClassUniform,
|
||||||
|
uniform_float_constants_,
|
||||||
|
id_vector_temp_util_);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
assert_unhandled_case(operand.storage_source);
|
||||||
|
}
|
||||||
|
assert_not_zero(vec4_pointer);
|
||||||
|
return builder_->createLoad(vec4_pointer, spv::NoPrecision);
|
||||||
|
}
|
||||||
|
|
||||||
|
spv::Id SpirvShaderTranslator::ApplyOperandModifiers(
|
||||||
|
spv::Id operand_value, const InstructionOperand& original_operand,
|
||||||
|
bool invert_negate, bool force_absolute) {
|
||||||
|
spv::Id type = builder_->getTypeId(operand_value);
|
||||||
|
assert_true(type != spv::NoType);
|
||||||
|
if (type == spv::NoType) {
|
||||||
|
return operand_value;
|
||||||
|
}
|
||||||
|
if (original_operand.is_absolute_value || force_absolute) {
|
||||||
|
EnsureBuildPointAvailable();
|
||||||
|
id_vector_temp_util_.clear();
|
||||||
|
id_vector_temp_util_.reserve(1);
|
||||||
|
id_vector_temp_util_.push_back(operand_value);
|
||||||
|
operand_value = builder_->createBuiltinCall(
|
||||||
|
type, ext_inst_glsl_std_450_, GLSLstd450FAbs, id_vector_temp_util_);
|
||||||
|
}
|
||||||
|
if (original_operand.is_negated != invert_negate) {
|
||||||
|
EnsureBuildPointAvailable();
|
||||||
|
operand_value =
|
||||||
|
builder_->createUnaryOp(spv::OpFNegate, type, operand_value);
|
||||||
|
builder_->addDecoration(operand_value, spv::DecorationNoContraction);
|
||||||
|
}
|
||||||
|
return operand_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
spv::Id SpirvShaderTranslator::GetUnmodifiedOperandComponents(
|
||||||
|
spv::Id operand_storage, const InstructionOperand& original_operand,
|
||||||
|
uint32_t components) {
|
||||||
|
assert_not_zero(components);
|
||||||
|
if (!components) {
|
||||||
|
return spv::NoResult;
|
||||||
|
}
|
||||||
|
assert_true(components <= 0b1111);
|
||||||
|
if (components == 0b1111 && original_operand.IsStandardSwizzle()) {
|
||||||
|
return operand_storage;
|
||||||
|
}
|
||||||
|
EnsureBuildPointAvailable();
|
||||||
|
uint32_t component_count = xe::bit_count(components);
|
||||||
|
if (component_count == 1) {
|
||||||
|
uint32_t scalar_index;
|
||||||
|
xe::bit_scan_forward(components, &scalar_index);
|
||||||
|
return builder_->createCompositeExtract(
|
||||||
|
operand_storage, type_float_,
|
||||||
|
static_cast<unsigned int>(original_operand.GetComponent(scalar_index)) -
|
||||||
|
static_cast<unsigned int>(SwizzleSource::kX));
|
||||||
|
}
|
||||||
|
id_vector_temp_util_.clear();
|
||||||
|
id_vector_temp_util_.reserve(component_count);
|
||||||
|
uint32_t components_remaining = components;
|
||||||
|
uint32_t component_index;
|
||||||
|
while (xe::bit_scan_forward(components_remaining, &component_index)) {
|
||||||
|
components_remaining &= ~(uint32_t(1) << component_index);
|
||||||
|
id_vector_temp_util_.push_back(
|
||||||
|
static_cast<unsigned int>(
|
||||||
|
original_operand.GetComponent(component_index)) -
|
||||||
|
static_cast<unsigned int>(SwizzleSource::kX));
|
||||||
|
}
|
||||||
|
return builder_->createRvalueSwizzle(spv::NoPrecision,
|
||||||
|
type_float_vectors_[component_count - 1],
|
||||||
|
operand_storage, id_vector_temp_util_);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace gpu
|
} // namespace gpu
|
||||||
} // namespace xe
|
} // namespace xe
|
||||||
|
|
|
@ -81,9 +81,10 @@ class SpirvShaderTranslator : public ShaderTranslator {
|
||||||
}
|
}
|
||||||
bool IsSpirvFragmentShader() const { return is_pixel_shader(); }
|
bool IsSpirvFragmentShader() const { return is_pixel_shader(); }
|
||||||
|
|
||||||
// Must be called before emitting any non-control-flow SPIR-V operations in
|
// Must be called before emitting any SPIR-V operations that must be in a
|
||||||
// translator callback to ensure that if the last instruction added was
|
// block in translator callbacks to ensure that if the last instruction added
|
||||||
// something like OpBranch - in this case, an unreachable block is created.
|
// was something like OpBranch - in this case, an unreachable block is
|
||||||
|
// created.
|
||||||
void EnsureBuildPointAvailable();
|
void EnsureBuildPointAvailable();
|
||||||
|
|
||||||
void StartVertexOrTessEvalShaderBeforeMain();
|
void StartVertexOrTessEvalShaderBeforeMain();
|
||||||
|
@ -109,12 +110,47 @@ class SpirvShaderTranslator : public ShaderTranslator {
|
||||||
// labels) and updates the state accordingly.
|
// labels) and updates the state accordingly.
|
||||||
void CloseExecConditionals();
|
void CloseExecConditionals();
|
||||||
|
|
||||||
|
spv::Id GetStorageAddressingIndex(
|
||||||
|
InstructionStorageAddressingMode addressing_mode, uint32_t storage_index);
|
||||||
|
// Loads unswizzled operand without sign modifiers as float4.
|
||||||
|
spv::Id LoadOperandStorage(const InstructionOperand& operand);
|
||||||
|
spv::Id ApplyOperandModifiers(spv::Id operand_value,
|
||||||
|
const InstructionOperand& original_operand,
|
||||||
|
bool invert_negate = false,
|
||||||
|
bool force_absolute = false);
|
||||||
|
// Returns the requested components, with the operand's swizzle applied, in a
|
||||||
|
// condensed form, but without negation / absolute value modifiers. The
|
||||||
|
// storage is float4, no matter what the component count of original_operand
|
||||||
|
// is (the storage will be either r# or c#, but the instruction may be
|
||||||
|
// scalar).
|
||||||
|
spv::Id GetUnmodifiedOperandComponents(
|
||||||
|
spv::Id operand_storage, const InstructionOperand& original_operand,
|
||||||
|
uint32_t components);
|
||||||
|
spv::Id GetOperandComponents(spv::Id operand_storage,
|
||||||
|
const InstructionOperand& original_operand,
|
||||||
|
uint32_t components, bool invert_negate = false,
|
||||||
|
bool force_absolute = false) {
|
||||||
|
return ApplyOperandModifiers(
|
||||||
|
GetUnmodifiedOperandComponents(operand_storage, original_operand,
|
||||||
|
components),
|
||||||
|
original_operand, invert_negate, force_absolute);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return type is a float vector of xe::bit_count(result.GetUsedWriteMask())
|
||||||
|
// or a single float, depending on whether it's a reduction instruction (check
|
||||||
|
// getTypeId of the result), or returns spv::NoResult if nothing to store.
|
||||||
|
spv::Id ProcessVectorAluOperation(const ParsedAluInstruction& instr,
|
||||||
|
bool& predicate_written);
|
||||||
|
|
||||||
bool supports_clip_distance_;
|
bool supports_clip_distance_;
|
||||||
bool supports_cull_distance_;
|
bool supports_cull_distance_;
|
||||||
|
|
||||||
std::unique_ptr<spv::Builder> builder_;
|
std::unique_ptr<spv::Builder> builder_;
|
||||||
|
|
||||||
std::vector<spv::Id> id_vector_temp_;
|
std::vector<spv::Id> id_vector_temp_;
|
||||||
|
// For helper functions like operand loading, so they don't conflict with
|
||||||
|
// id_vector_temp_ usage in bigger callbacks.
|
||||||
|
std::vector<spv::Id> id_vector_temp_util_;
|
||||||
std::vector<unsigned int> uint_vector_temp_;
|
std::vector<unsigned int> uint_vector_temp_;
|
||||||
|
|
||||||
spv::Id ext_inst_glsl_std_450_;
|
spv::Id ext_inst_glsl_std_450_;
|
||||||
|
@ -126,10 +162,16 @@ class SpirvShaderTranslator : public ShaderTranslator {
|
||||||
spv::Id type_uint_;
|
spv::Id type_uint_;
|
||||||
spv::Id type_uint3_;
|
spv::Id type_uint3_;
|
||||||
spv::Id type_uint4_;
|
spv::Id type_uint4_;
|
||||||
|
union {
|
||||||
|
struct {
|
||||||
spv::Id type_float_;
|
spv::Id type_float_;
|
||||||
spv::Id type_float2_;
|
spv::Id type_float2_;
|
||||||
spv::Id type_float3_;
|
spv::Id type_float3_;
|
||||||
spv::Id type_float4_;
|
spv::Id type_float4_;
|
||||||
|
};
|
||||||
|
// Index = component count - 1.
|
||||||
|
spv::Id type_float_vectors_[4];
|
||||||
|
};
|
||||||
|
|
||||||
spv::Id const_int_0_;
|
spv::Id const_int_0_;
|
||||||
spv::Id const_int4_0_;
|
spv::Id const_int4_0_;
|
||||||
|
@ -138,6 +180,7 @@ class SpirvShaderTranslator : public ShaderTranslator {
|
||||||
spv::Id const_float_0_;
|
spv::Id const_float_0_;
|
||||||
spv::Id const_float4_0_;
|
spv::Id const_float4_0_;
|
||||||
|
|
||||||
|
spv::Id uniform_float_constants_;
|
||||||
spv::Id uniform_bool_loop_constants_;
|
spv::Id uniform_bool_loop_constants_;
|
||||||
|
|
||||||
// VS as VS only - int.
|
// VS as VS only - int.
|
||||||
|
|
|
@ -9,6 +9,8 @@
|
||||||
|
|
||||||
#include "xenia/gpu/spirv_shader_translator.h"
|
#include "xenia/gpu/spirv_shader_translator.h"
|
||||||
|
|
||||||
|
#include "xenia/base/math.h"
|
||||||
|
|
||||||
namespace xe {
|
namespace xe {
|
||||||
namespace gpu {
|
namespace gpu {
|
||||||
|
|
||||||
|
@ -21,7 +23,77 @@ void SpirvShaderTranslator::ProcessAluInstruction(
|
||||||
|
|
||||||
UpdateInstructionPredication(instr.is_predicated, instr.predicate_condition);
|
UpdateInstructionPredication(instr.is_predicated, instr.predicate_condition);
|
||||||
|
|
||||||
// TODO(Triang3l): Translate the ALU instruction.
|
// Floating-point arithmetic operations (addition, subtraction, negation,
|
||||||
|
// multiplication, dot product, division, modulo - see isArithmeticOperation
|
||||||
|
// in propagateNoContraction of glslang) must have the NoContraction
|
||||||
|
// decoration to prevent reordering to make sure floating-point calculations
|
||||||
|
// are optimized predictably and exactly the same in different shaders to
|
||||||
|
// allow for multipass rendering (in addition to the Invariant decoration on
|
||||||
|
// outputs).
|
||||||
|
|
||||||
|
// Whether the instruction has changed the predicate, and it needs to be
|
||||||
|
// checked again later.
|
||||||
|
bool predicate_written_vector = false;
|
||||||
|
ProcessVectorAluOperation(instr, predicate_written_vector);
|
||||||
|
// TODO(Triang3l): Process the ALU scalar operation.
|
||||||
|
|
||||||
|
if (predicate_written_vector) {
|
||||||
|
cf_exec_predicate_written_ = true;
|
||||||
|
CloseInstructionPredication();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
spv::Id SpirvShaderTranslator::ProcessVectorAluOperation(
|
||||||
|
const ParsedAluInstruction& instr, bool& predicate_written) {
|
||||||
|
predicate_written = false;
|
||||||
|
|
||||||
|
uint32_t used_result_components =
|
||||||
|
instr.vector_and_constant_result.GetUsedResultComponents();
|
||||||
|
if (!used_result_components &&
|
||||||
|
!AluVectorOpHasSideEffects(instr.vector_opcode)) {
|
||||||
|
return spv::NoResult;
|
||||||
|
}
|
||||||
|
uint32_t used_result_component_count = xe::bit_count(used_result_components);
|
||||||
|
|
||||||
|
// Load operand storage without swizzle and sign modifiers.
|
||||||
|
// A small shortcut, operands of cube are the same, but swizzled.
|
||||||
|
uint32_t operand_count;
|
||||||
|
if (instr.vector_opcode == ucode::AluVectorOpcode::kCube) {
|
||||||
|
operand_count = 1;
|
||||||
|
} else {
|
||||||
|
operand_count = instr.vector_operand_count;
|
||||||
|
}
|
||||||
|
spv::Id operand_storage[3] = {};
|
||||||
|
for (uint32_t i = 0; i < operand_count; ++i) {
|
||||||
|
operand_storage[i] = LoadOperandStorage(instr.vector_operands[i]);
|
||||||
|
}
|
||||||
|
spv::Id result_vector_type =
|
||||||
|
used_result_component_count
|
||||||
|
? type_float_vectors_[used_result_component_count - 1]
|
||||||
|
: spv::NoType;
|
||||||
|
|
||||||
|
// In case the paired scalar instruction (if processed first) terminates the
|
||||||
|
// block (like via OpKill).
|
||||||
|
EnsureBuildPointAvailable();
|
||||||
|
|
||||||
|
switch (instr.vector_opcode) {
|
||||||
|
case ucode::AluVectorOpcode::kAdd: {
|
||||||
|
spv::Id result = builder_->createBinOp(
|
||||||
|
spv::OpFAdd, result_vector_type,
|
||||||
|
GetOperandComponents(operand_storage[0], instr.vector_operands[0],
|
||||||
|
used_result_components),
|
||||||
|
GetOperandComponents(operand_storage[1], instr.vector_operands[1],
|
||||||
|
used_result_components));
|
||||||
|
builder_->addDecoration(result, spv::DecorationNoContraction);
|
||||||
|
return result;
|
||||||
|
} break;
|
||||||
|
// TODO(Triang3l): Handle all instructions.
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Invalid instruction.
|
||||||
|
return spv::NoResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace gpu
|
} // namespace gpu
|
||||||
|
|
Loading…
Reference in New Issue