From 958fc5750f315a96f72b69a7dc6747e6c1c52720 Mon Sep 17 00:00:00 2001 From: Nils Hasenbanck Date: Tue, 7 Oct 2025 17:53:57 +0200 Subject: [PATCH 1/3] (Naga) Implement OpSpecConstantOp for the SPIR-V frontend --- CHANGELOG.md | 8 +- naga/src/front/spv/error.rs | 4 + naga/src/front/spv/mod.rs | 291 +++++++++++++++ .../in/spv/spec-constant-op-chained.spvasm | 74 ++++ .../in/spv/spec-constant-op-chained.toml | 8 + naga/tests/in/spv/spec-constant-op.comp | 155 ++++++++ naga/tests/in/spv/spec-constant-op.spvasm | 339 ++++++++++++++++++ naga/tests/in/spv/spec-constant-op.toml | 8 + .../hlsl/spv-spec-constant-op-chained.hlsl | 30 ++ .../out/hlsl/spv-spec-constant-op-chained.ron | 12 + naga/tests/out/hlsl/spv-spec-constant-op.hlsl | 206 +++++++++++ naga/tests/out/hlsl/spv-spec-constant-op.ron | 12 + 12 files changed, 1146 insertions(+), 1 deletion(-) create mode 100644 naga/tests/in/spv/spec-constant-op-chained.spvasm create mode 100644 naga/tests/in/spv/spec-constant-op-chained.toml create mode 100644 naga/tests/in/spv/spec-constant-op.comp create mode 100644 naga/tests/in/spv/spec-constant-op.spvasm create mode 100644 naga/tests/in/spv/spec-constant-op.toml create mode 100644 naga/tests/out/hlsl/spv-spec-constant-op-chained.hlsl create mode 100644 naga/tests/out/hlsl/spv-spec-constant-op-chained.ron create mode 100644 naga/tests/out/hlsl/spv-spec-constant-op.hlsl create mode 100644 naga/tests/out/hlsl/spv-spec-constant-op.ron diff --git a/CHANGELOG.md b/CHANGELOG.md index 6fa8bd6303c..7355eaf07c9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -42,7 +42,7 @@ Bottom level categories: #### 'wgpu::Instance::enumerate_adapters` is now `async` & available on WebGPU -Making `enumerate_adapters` async allows custom backends to use it along with elimnating some native/non-native distinctions +Making `enumerate_adapters` async allows custom backends to use it along with eliminating some native/non-native distinctions This is a breaking change @@ -54,6 +54,12 @@ This is a breaking change By @R-Cramer4 in [#8230](https://github.com/gfx-rs/wgpu/pull/8230) +### Changes + +#### naga + +- The SPIR-V frontend implements OpSpecConstantOp. By @hasenbanck in [8308](https://github.com/gfx-rs/wgpu/pull/8308). + ## v27.0.2 (2025-10-03) ### Bug Fixes diff --git a/naga/src/front/spv/error.rs b/naga/src/front/spv/error.rs index 3e18e4034a9..8bd62341946 100644 --- a/naga/src/front/spv/error.rs +++ b/naga/src/front/spv/error.rs @@ -26,6 +26,10 @@ pub enum Error { UnknownCapability(spirv::Word), #[error("unsupported instruction {1:?} at {0:?}")] UnsupportedInstruction(ModuleState, spirv::Op), + #[error("unsupported opcode in specialization constant operation {0:?}")] + UnsupportedSpecConstantOp(spirv::Op), + #[error("invalid opcode in specialization constant operation {0:?}")] + InvalidSpecConstantOp(spirv::Op), #[error("unsupported capability {0:?}")] UnsupportedCapability(spirv::Capability), #[error("unsupported extension {0}")] diff --git a/naga/src/front/spv/mod.rs b/naga/src/front/spv/mod.rs index 5e1b1146503..6951f11dadc 100644 --- a/naga/src/front/spv/mod.rs +++ b/naga/src/front/spv/mod.rs @@ -4803,6 +4803,7 @@ impl> Frontend { Op::ConstantFalse | Op::SpecConstantFalse => { self.parse_bool_constant(inst, false, &mut module) } + Op::SpecConstantOp => self.parse_spec_constant_op(inst, &mut module), Op::Variable => self.parse_global_variable(inst, &mut module), Op::Function => { self.switch(ModuleState::Function, inst.op)?; @@ -5899,6 +5900,296 @@ impl> Frontend { self.insert_parsed_constant(module, id, type_id, ty, init, span) } + fn parse_spec_constant_op( + &mut self, + inst: Instruction, + module: &mut crate::Module, + ) -> Result<(), Error> { + use spirv::Op; + + let start = self.data_offset; + self.switch(ModuleState::Type, inst.op)?; + inst.expect_at_least(4)?; + + let result_type_id = self.next()?; + let result_id = self.next()?; + let opcode_word = self.next()?; + + let type_lookup = self.lookup_type.lookup(result_type_id)?; + let ty = type_lookup.handle; + let span = self.span_from_with_op(start); + + let opcode = Op::from_u32(opcode_word).ok_or(Error::UnsupportedInstruction( + self.state, + Op::SpecConstantOp, + ))?; + + let mut get_const_expr = + |frontend: &Self, const_id: spirv::Word| -> Result, Error> { + let lookup = frontend.lookup_constant.lookup(const_id)?; + match lookup.inner { + // Wrap regular constants in overrides to avoid creating Expression::Constant + // nodes, which would mark the entire expression tree as Const and fail + // validation for complex operations (Binary, As, Math) in override + // initializers. + // + // The downside is, that unused intermediate constants will get created, which + // I would like to avoid. + Constant::Constant(const_handle) => { + let const_init = module.constants[const_handle].init; + let const_ty = module.constants[const_handle].ty; + let wrapper_override = crate::Override { + name: Some(format!("_spec_const_op_const_{const_id}")), + id: None, + ty: const_ty, + init: Some(const_init), + }; + let override_handle = module.overrides.append(wrapper_override, span); + Ok(module + .global_expressions + .append(crate::Expression::Override(override_handle), span)) + } + Constant::Override(_) => Ok(module + .global_expressions + .append(lookup.inner.to_expr(), span)), + } + }; + + let init = match opcode { + Op::SConvert | Op::UConvert | Op::FConvert => { + let value_id = self.next()?; + let value_expr = get_const_expr(self, value_id)?; + + let scalar = match module.types[ty].inner { + crate::TypeInner::Scalar(scalar) + | crate::TypeInner::Vector { scalar, .. } + | crate::TypeInner::Matrix { scalar, .. } => scalar, + _ => return Err(Error::InvalidAsType(ty)), + }; + + module.global_expressions.append( + crate::Expression::As { + expr: value_expr, + kind: scalar.kind, + convert: Some(scalar.width), + }, + span, + ) + } + + Op::SNegate | Op::Not | Op::LogicalNot => { + let value_id = self.next()?; + let value_expr = get_const_expr(self, value_id)?; + + let op = match opcode { + Op::SNegate => crate::UnaryOperator::Negate, + Op::Not => crate::UnaryOperator::BitwiseNot, + Op::LogicalNot => crate::UnaryOperator::LogicalNot, + _ => unreachable!(), + }; + + module.global_expressions.append( + crate::Expression::Unary { + op, + expr: value_expr, + }, + span, + ) + } + + Op::IAdd + | Op::ISub + | Op::IMul + | Op::UDiv + | Op::SDiv + | Op::SRem + | Op::UMod + | Op::BitwiseOr + | Op::BitwiseXor + | Op::BitwiseAnd + | Op::ShiftLeftLogical + | Op::ShiftRightLogical + | Op::ShiftRightArithmetic + | Op::LogicalOr + | Op::LogicalAnd + | Op::LogicalEqual + | Op::LogicalNotEqual + | Op::IEqual + | Op::INotEqual + | Op::ULessThan + | Op::SLessThan + | Op::UGreaterThan + | Op::SGreaterThan + | Op::ULessThanEqual + | Op::SLessThanEqual + | Op::UGreaterThanEqual + | Op::SGreaterThanEqual => { + let left_id = self.next()?; + let right_id = self.next()?; + let left_expr = get_const_expr(self, left_id)?; + let right_expr = get_const_expr(self, right_id)?; + + let op = match opcode { + Op::IAdd => crate::BinaryOperator::Add, + Op::ISub => crate::BinaryOperator::Subtract, + Op::IMul => crate::BinaryOperator::Multiply, + Op::UDiv | Op::SDiv => crate::BinaryOperator::Divide, + Op::SRem | Op::UMod => crate::BinaryOperator::Modulo, + Op::BitwiseOr => crate::BinaryOperator::InclusiveOr, + Op::BitwiseXor => crate::BinaryOperator::ExclusiveOr, + Op::BitwiseAnd => crate::BinaryOperator::And, + Op::ShiftLeftLogical => crate::BinaryOperator::ShiftLeft, + Op::ShiftRightLogical | Op::ShiftRightArithmetic => { + crate::BinaryOperator::ShiftRight + } + Op::LogicalOr => crate::BinaryOperator::LogicalOr, + Op::LogicalAnd => crate::BinaryOperator::LogicalAnd, + Op::LogicalEqual => crate::BinaryOperator::Equal, + Op::LogicalNotEqual => crate::BinaryOperator::NotEqual, + Op::IEqual => crate::BinaryOperator::Equal, + Op::INotEqual => crate::BinaryOperator::NotEqual, + Op::ULessThan | Op::SLessThan => crate::BinaryOperator::Less, + Op::UGreaterThan | Op::SGreaterThan => crate::BinaryOperator::Greater, + Op::ULessThanEqual | Op::SLessThanEqual => crate::BinaryOperator::LessEqual, + Op::UGreaterThanEqual | Op::SGreaterThanEqual => { + crate::BinaryOperator::GreaterEqual + } + _ => unreachable!(), + }; + + module.global_expressions.append( + crate::Expression::Binary { + op, + left: left_expr, + right: right_expr, + }, + span, + ) + } + + Op::SMod => { + // x - y * int(floor(float(x) / float(y))) + + let left_id = self.next()?; + let right_id = self.next()?; + let left = get_const_expr(self, left_id)?; + let right = get_const_expr(self, right_id)?; + + let scalar = match module.types[ty].inner { + crate::TypeInner::Scalar(scalar) => scalar, + crate::TypeInner::Vector { scalar, .. } => scalar, + _ => return Err(Error::InvalidAsType(ty)), + }; + + let left_cast = module.global_expressions.append( + crate::Expression::As { + expr: left, + kind: crate::ScalarKind::Float, + convert: Some(scalar.width), + }, + span, + ); + let right_cast = module.global_expressions.append( + crate::Expression::As { + expr: right, + kind: crate::ScalarKind::Float, + convert: Some(scalar.width), + }, + span, + ); + let div = module.global_expressions.append( + crate::Expression::Binary { + op: crate::BinaryOperator::Divide, + left: left_cast, + right: right_cast, + }, + span, + ); + let floor = module.global_expressions.append( + crate::Expression::Math { + fun: crate::MathFunction::Floor, + arg: div, + arg1: None, + arg2: None, + arg3: None, + }, + span, + ); + let cast = module.global_expressions.append( + crate::Expression::As { + expr: floor, + kind: scalar.kind, + convert: Some(scalar.width), + }, + span, + ); + let mult = module.global_expressions.append( + crate::Expression::Binary { + op: crate::BinaryOperator::Multiply, + left: cast, + right, + }, + span, + ); + module.global_expressions.append( + crate::Expression::Binary { + op: crate::BinaryOperator::Subtract, + left, + right: mult, + }, + span, + ) + } + + Op::Select => { + let condition_id = self.next()?; + let o1_id = self.next()?; + let o2_id = self.next()?; + + let cond = get_const_expr(self, condition_id)?; + let o1 = get_const_expr(self, o1_id)?; + let o2 = get_const_expr(self, o2_id)?; + + module.global_expressions.append( + crate::Expression::Select { + condition: cond, + accept: o1, + reject: o2, + }, + span, + ) + } + + Op::VectorShuffle | Op::CompositeExtract | Op::CompositeInsert | Op::QuantizeToF16 => { + // Nothing stops us from implementing these cases in general. + // I just couldn't get them to work properly. + return Err(Error::UnsupportedSpecConstantOp(opcode)); + } + + _ => return Err(Error::InvalidSpecConstantOp(opcode)), + }; + + // IMPORTANT: Overrides must have either a name or an id to be processed correctly + // by process_overrides(). OpSpecConstantOp results don't have a SpecId (they're + // not user-overridable), so we assign them a name based on the result_id. + let op_override = crate::Override { + name: Some(format!("_spec_const_op_{result_id}")), + id: None, + ty, + init: Some(init), + }; + + self.lookup_constant.insert( + result_id, + LookupConstant { + inner: Constant::Override(module.overrides.append(op_override, span)), + type_id: result_type_id, + }, + ); + + Ok(()) + } + fn insert_parsed_constant( &mut self, module: &mut crate::Module, diff --git a/naga/tests/in/spv/spec-constant-op-chained.spvasm b/naga/tests/in/spv/spec-constant-op-chained.spvasm new file mode 100644 index 00000000000..aa05b955b32 --- /dev/null +++ b/naga/tests/in/spv/spec-constant-op-chained.spvasm @@ -0,0 +1,74 @@ +; SPIR-V +; Version: 1.4 +; Generator: Manual +; Bound: 50 +; Schema: 0 + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %main "main" %output_buffer + OpExecutionMode %main LocalSize 1 1 1 + +; Decorations for spec constants + OpDecorate %spec_a SpecId 0 + OpDecorate %spec_b SpecId 1 + +; Decorations for storage buffer + OpDecorate %OutputStruct Block + OpMemberDecorate %OutputStruct 0 Offset 0 + OpMemberDecorate %OutputStruct 1 Offset 4 + OpMemberDecorate %OutputStruct 2 Offset 8 + OpDecorate %output_buffer DescriptorSet 0 + OpDecorate %output_buffer Binding 0 + +; Types + %void = OpTypeVoid + %3 = OpTypeFunction %void + %int = OpTypeInt 32 1 + %uint = OpTypeInt 32 0 + +; Storage buffer types +%OutputStruct = OpTypeStruct %uint %uint %uint +%_ptr_StorageBuffer_OutputStruct = OpTypePointer StorageBuffer %OutputStruct +%output_buffer = OpVariable %_ptr_StorageBuffer_OutputStruct StorageBuffer +%_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint + +; Base spec constants +%spec_a = OpSpecConstant %int 0 +%spec_b = OpSpecConstant %int 0 + +; Basic chaining +%add_result = OpSpecConstantOp %int IAdd %spec_a %spec_b ; 10 + 3 = 13 +%mul_result = OpSpecConstantOp %int IMul %add_result %spec_b ; 13 * 3 = 39 +%sub_result = OpSpecConstantOp %int ISub %mul_result %add_result ; 39 - 13 = 26 + +; Deeper chaining +%step1 = OpSpecConstantOp %int IAdd %spec_a %spec_b ; 10 + 3 = 13 +%step2 = OpSpecConstantOp %int IMul %step1 %spec_a ; 13 * 10 = 130 +%const_one = OpConstant %int 1 +%step3 = OpSpecConstantOp %int ISub %step2 %const_one ; 130 - 1 = 129 +%step4 = OpSpecConstantOp %int IMul %step3 %spec_b ; 129 * 3 = 387 + +; Constants for indices + %idx_0 = OpConstant %uint 0 + %idx_1 = OpConstant %uint 1 + %idx_2 = OpConstant %uint 2 + +; Main function + %main = OpFunction %void None %3 + %5 = OpLabel + +; Store results + %mul_uint = OpBitcast %uint %mul_result + %ptr_0 = OpAccessChain %_ptr_StorageBuffer_uint %output_buffer %idx_0 + OpStore %ptr_0 %mul_uint + + %sub_uint = OpBitcast %uint %sub_result + %ptr_1 = OpAccessChain %_ptr_StorageBuffer_uint %output_buffer %idx_1 + OpStore %ptr_1 %sub_uint + + %step4_uint = OpBitcast %uint %step4 + %ptr_2 = OpAccessChain %_ptr_StorageBuffer_uint %output_buffer %idx_2 + OpStore %ptr_2 %step4_uint + + OpReturn + OpFunctionEnd diff --git a/naga/tests/in/spv/spec-constant-op-chained.toml b/naga/tests/in/spv/spec-constant-op-chained.toml new file mode 100644 index 00000000000..c0c904e6328 --- /dev/null +++ b/naga/tests/in/spv/spec-constant-op-chained.toml @@ -0,0 +1,8 @@ +pipeline_constants = { 0 = 10, 1 = 3 } +targets = "HLSL" + +[spv-in] +adjust_coordinate_space = false + +[spv] +separate_entry_points = true diff --git a/naga/tests/in/spv/spec-constant-op.comp b/naga/tests/in/spv/spec-constant-op.comp new file mode 100644 index 00000000000..6a82726c326 --- /dev/null +++ b/naga/tests/in/spv/spec-constant-op.comp @@ -0,0 +1,155 @@ +// Compiled with: +// glslang -V -o naga/tests/in/spv/spec-constant-op.spv naga/tests/in/spv/spec-constant-op.comp +// Disassembled with: +// spirv-dis naga/tests/in/spv/spec-constant-op.spv -o naga/tests/in/spv/spec-constant-op.spvasm +// Based on this test of glslang: https://github.com/KhronosGroup/glslang/blob/main/Test/spv.specConstantOperations.vert +#version 450 + +layout(constant_id = 0) const float sp_float = 3.1415926; +layout(constant_id = 1) const int sp_int = 10; +layout(constant_id = 2) const uint sp_uint = 100; +layout(constant_id = 3) const int sp_sint = -10; + +// +// Scalars +// + +// uint/int <-> bool conversion +const bool bool_from_int = bool(sp_int); // bool(3) = true +const bool bool_from_uint = bool(sp_uint); // bool(20) = true +const int int_from_bool = int(bool_from_int); // int(true) = 1 +const uint uint_from_bool = uint(bool_from_int); // uint(true) = 1 + +// Negate and Not +const int negate_int = -sp_int; // -3 = -3 +const int not_int = ~sp_int; // ~3 = -4 + +// Add and Subtract +const int sp_int_add_two = sp_int + 2; // 3 + 2 = 5 +const int sp_int_add_two_sub_three = sp_int + 2 - 3; // 3 + 2 - 3 = 2 +const int sp_int_add_two_sub_four = sp_int_add_two - 4; // 5 - 4 = 1 + +// Mul, Div +const int sp_sint_mul_two = sp_sint * 2; // 4 * 2 = 8 +const uint sp_uint_mul_two = sp_uint * 2; // 20 * 2 = 40 +const int sp_sint_mul_two_div_five = sp_sint_mul_two / 5; // 8 / 5 = 1 +const uint sp_uint_mul_two_div_five = sp_uint_mul_two / 5; // 40 / 5 = 8 +const int sp_sint_mul_three_div_five = sp_sint * 3 / 5; // 4 * 3 / 5 = 2 + +// Rem +const int sp_sint_rem_four = sp_sint % 4; // 4 % 4 = 0 +const uint sp_uint_rem_four = sp_uint % 4; // 20 % 4 = 0 + +// Shift (the shift value must be an unsigned integer) +const int sp_sint_shift_right_arithmetic = sp_sint >> 10u; // 4 >> 10 = 0 +const uint sp_uint_shift_right_arithmetic = sp_uint >> 20u; // 20 >> 20 = 0 +const int sp_sint_shift_left = sp_sint << 1u; // 4 << 1 = 8 +const uint sp_uint_shift_left = sp_uint << 2u; // 20 << 2 = 80 + +// Bitwise And, Or, Xor +const int sp_sint_and_3 = sp_sint & 3; // 4 & 3 = 0 +const int sp_sint_or_256 = sp_sint | 0x100; // 4 | 256 = 260 +const uint sp_uint_xor_512 = sp_uint ^ 0x200; // 20 ^ 512 = 532 + +// Scalar comparison +const bool sp_int_lt_sp_sint = sp_int < sp_sint; // 3 < 4 = true +const bool sp_int_le_sp_sint = sp_int <= sp_sint; // 3 <= 4 = true +const bool sp_uint_equal_sp_uint = sp_uint == sp_uint; // 20 == 20 = true +const bool sp_uint_not_equal_sp_uint = sp_uint != sp_uint; // 20 != 20 = false +const bool sp_int_gt_sp_sint = sp_int > sp_sint; // 3 > 4 = false +const bool sp_int_ge_sp_sint = sp_int >= sp_sint; // 3 >= 4 = false + +// Logical operations +const bool logical_and = bool_from_int && bool_from_uint; // true && true = true +const bool logical_or = bool_from_int || bool_from_uint; // true || true = true +const bool logical_equal = bool_from_int == bool_from_uint; // true == true = true +const bool logical_not_equal = bool_from_int != bool_from_uint; // true != true = false + +// ternary +layout(constant_id = 4) const int a = 4; +layout(constant_id = 5) const int b = 6; +layout(constant_id = 6) const bool c = true; +const int t1 = c ? 13 : 17; // true ? 13 : 17 = 13 +const int t2 = c ? a : 17; // true ? 1 : 17 = 1 +const int t3 = true ? a : 17; // true ? 1 : 17 = 1 +const int t4 = a > b ? 13 + a : 17 * b; // 1 > 0 ? 13+1 : 17*0 = 14 + +layout(set = 0, binding = 0) buffer OutputBuffer { + uint bool_from_int_val; + uint bool_from_uint_val; + int int_from_bool_val; + uint uint_from_bool_val; + int negate_int_val; + int not_int_val; + int sp_int_add_two_val; + int sp_int_add_two_sub_three_val; + int sp_int_add_two_sub_four_val; + int sp_sint_mul_two_val; + uint sp_uint_mul_two_val; + int sp_sint_mul_two_div_five_val; + uint sp_uint_mul_two_div_five_val; + int sp_sint_mul_three_div_five_val; + int sp_sint_rem_four_val; + uint sp_uint_rem_four_val; + int sp_sint_shift_right_arithmetic_val; + uint sp_uint_shift_right_arithmetic_val; + int sp_sint_shift_left_val; + uint sp_uint_shift_left_val; + int sp_sint_and_3_val; + int sp_sint_or_256_val; + uint sp_uint_xor_512_val; + uint sp_int_lt_sp_sint_val; + uint sp_int_le_sp_sint_val; + uint sp_uint_equal_sp_uint_val; + uint sp_uint_not_equal_sp_uint_val; + uint sp_int_gt_sp_sint_val; + uint sp_int_ge_sp_sint_val; + uint logical_and_val; + uint logical_or_val; + uint logical_equal_val; + uint logical_not_equal_val; + int t1_val; + int t2_val; + int t3_val; + int t4_val; +} output_buffer; + +void main() { + output_buffer.bool_from_int_val = uint(bool_from_int); + output_buffer.bool_from_uint_val = uint(bool_from_uint); + output_buffer.int_from_bool_val = int_from_bool; + output_buffer.uint_from_bool_val = uint_from_bool; + output_buffer.negate_int_val = negate_int; + output_buffer.not_int_val = not_int; + output_buffer.sp_int_add_two_val = sp_int_add_two; + output_buffer.sp_int_add_two_sub_three_val = sp_int_add_two_sub_three; + output_buffer.sp_int_add_two_sub_four_val = sp_int_add_two_sub_four; + output_buffer.sp_sint_mul_two_val = sp_sint_mul_two; + output_buffer.sp_uint_mul_two_val = sp_uint_mul_two; + output_buffer.sp_sint_mul_two_div_five_val = sp_sint_mul_two_div_five; + output_buffer.sp_uint_mul_two_div_five_val = sp_uint_mul_two_div_five; + output_buffer.sp_sint_mul_three_div_five_val = sp_sint_mul_three_div_five; + output_buffer.sp_sint_rem_four_val = sp_sint_rem_four; + output_buffer.sp_uint_rem_four_val = sp_uint_rem_four; + output_buffer.sp_sint_shift_right_arithmetic_val = sp_sint_shift_right_arithmetic; + output_buffer.sp_uint_shift_right_arithmetic_val = sp_uint_shift_right_arithmetic; + output_buffer.sp_sint_shift_left_val = sp_sint_shift_left; + output_buffer.sp_uint_shift_left_val = sp_uint_shift_left; + output_buffer.sp_sint_and_3_val = sp_sint_and_3; + output_buffer.sp_sint_or_256_val = sp_sint_or_256; + output_buffer.sp_uint_xor_512_val = sp_uint_xor_512; + output_buffer.sp_int_lt_sp_sint_val = uint(sp_int_lt_sp_sint); + output_buffer.sp_int_le_sp_sint_val = uint(sp_int_le_sp_sint); + output_buffer.sp_uint_equal_sp_uint_val = uint(sp_uint_equal_sp_uint); + output_buffer.sp_uint_not_equal_sp_uint_val = uint(sp_uint_not_equal_sp_uint); + output_buffer.sp_int_gt_sp_sint_val = uint(sp_int_gt_sp_sint); + output_buffer.sp_int_ge_sp_sint_val = uint(sp_int_ge_sp_sint); + output_buffer.logical_and_val = uint(logical_and); + output_buffer.logical_or_val = uint(logical_or); + output_buffer.logical_equal_val = uint(logical_equal); + output_buffer.logical_not_equal_val = uint(logical_not_equal); + output_buffer.t1_val = t1; + output_buffer.t2_val = t2; + output_buffer.t3_val = t3; + output_buffer.t4_val = t4; +} diff --git a/naga/tests/in/spv/spec-constant-op.spvasm b/naga/tests/in/spv/spec-constant-op.spvasm new file mode 100644 index 00000000000..c6f19e5f6b0 --- /dev/null +++ b/naga/tests/in/spv/spec-constant-op.spvasm @@ -0,0 +1,339 @@ +; SPIR-V +; Version: 1.0 +; Generator: Khronos Glslang Reference Front End; 11 +; Bound: 160 +; Schema: 0 + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %main "main" + OpExecutionMode %main LocalSize 1 1 1 + OpSource GLSL 450 + OpName %main "main" + OpName %OutputBuffer "OutputBuffer" + OpMemberName %OutputBuffer 0 "bool_from_int_val" + OpMemberName %OutputBuffer 1 "bool_from_uint_val" + OpMemberName %OutputBuffer 2 "int_from_bool_val" + OpMemberName %OutputBuffer 3 "uint_from_bool_val" + OpMemberName %OutputBuffer 4 "negate_int_val" + OpMemberName %OutputBuffer 5 "not_int_val" + OpMemberName %OutputBuffer 6 "sp_int_add_two_val" + OpMemberName %OutputBuffer 7 "sp_int_add_two_sub_three_val" + OpMemberName %OutputBuffer 8 "sp_int_add_two_sub_four_val" + OpMemberName %OutputBuffer 9 "sp_sint_mul_two_val" + OpMemberName %OutputBuffer 10 "sp_uint_mul_two_val" + OpMemberName %OutputBuffer 11 "sp_sint_mul_two_div_five_val" + OpMemberName %OutputBuffer 12 "sp_uint_mul_two_div_five_val" + OpMemberName %OutputBuffer 13 "sp_sint_mul_three_div_five_val" + OpMemberName %OutputBuffer 14 "sp_sint_rem_four_val" + OpMemberName %OutputBuffer 15 "sp_uint_rem_four_val" + OpMemberName %OutputBuffer 16 "sp_sint_shift_right_arithmetic_val" + OpMemberName %OutputBuffer 17 "sp_uint_shift_right_arithmetic_val" + OpMemberName %OutputBuffer 18 "sp_sint_shift_left_val" + OpMemberName %OutputBuffer 19 "sp_uint_shift_left_val" + OpMemberName %OutputBuffer 20 "sp_sint_and_3_val" + OpMemberName %OutputBuffer 21 "sp_sint_or_256_val" + OpMemberName %OutputBuffer 22 "sp_uint_xor_512_val" + OpMemberName %OutputBuffer 23 "sp_int_lt_sp_sint_val" + OpMemberName %OutputBuffer 24 "sp_int_le_sp_sint_val" + OpMemberName %OutputBuffer 25 "sp_uint_equal_sp_uint_val" + OpMemberName %OutputBuffer 26 "sp_uint_not_equal_sp_uint_val" + OpMemberName %OutputBuffer 27 "sp_int_gt_sp_sint_val" + OpMemberName %OutputBuffer 28 "sp_int_ge_sp_sint_val" + OpMemberName %OutputBuffer 29 "logical_and_val" + OpMemberName %OutputBuffer 30 "logical_or_val" + OpMemberName %OutputBuffer 31 "logical_equal_val" + OpMemberName %OutputBuffer 32 "logical_not_equal_val" + OpMemberName %OutputBuffer 33 "t1_val" + OpMemberName %OutputBuffer 34 "t2_val" + OpMemberName %OutputBuffer 35 "t3_val" + OpMemberName %OutputBuffer 36 "t4_val" + OpName %output_buffer "output_buffer" + OpName %sp_int "sp_int" + OpName %bool_from_int "bool_from_int" + OpName %sp_uint "sp_uint" + OpName %bool_from_uint "bool_from_uint" + OpName %int_from_bool "int_from_bool" + OpName %uint_from_bool "uint_from_bool" + OpName %negate_int "negate_int" + OpName %not_int "not_int" + OpName %sp_int_add_two "sp_int_add_two" + OpName %sp_int_add_two_sub_three "sp_int_add_two_sub_three" + OpName %sp_int_add_two_sub_four "sp_int_add_two_sub_four" + OpName %sp_sint "sp_sint" + OpName %sp_sint_mul_two "sp_sint_mul_two" + OpName %sp_uint_mul_two "sp_uint_mul_two" + OpName %sp_sint_mul_two_div_five "sp_sint_mul_two_div_five" + OpName %sp_uint_mul_two_div_five "sp_uint_mul_two_div_five" + OpName %sp_sint_mul_three_div_five "sp_sint_mul_three_div_five" + OpName %sp_sint_rem_four "sp_sint_rem_four" + OpName %sp_uint_rem_four "sp_uint_rem_four" + OpName %sp_sint_shift_right_arithmetic "sp_sint_shift_right_arithmetic" + OpName %sp_uint_shift_right_arithmetic "sp_uint_shift_right_arithmetic" + OpName %sp_sint_shift_left "sp_sint_shift_left" + OpName %sp_uint_shift_left "sp_uint_shift_left" + OpName %sp_sint_and_3 "sp_sint_and_3" + OpName %sp_sint_or_256 "sp_sint_or_256" + OpName %sp_uint_xor_512 "sp_uint_xor_512" + OpName %sp_int_lt_sp_sint "sp_int_lt_sp_sint" + OpName %sp_int_le_sp_sint "sp_int_le_sp_sint" + OpName %sp_uint_equal_sp_uint "sp_uint_equal_sp_uint" + OpName %sp_uint_not_equal_sp_uint "sp_uint_not_equal_sp_uint" + OpName %sp_int_gt_sp_sint "sp_int_gt_sp_sint" + OpName %sp_int_ge_sp_sint "sp_int_ge_sp_sint" + OpName %logical_and "logical_and" + OpName %logical_or "logical_or" + OpName %logical_equal "logical_equal" + OpName %logical_not_equal "logical_not_equal" + OpName %c "c" + OpName %t1 "t1" + OpName %a "a" + OpName %t2 "t2" + OpName %t3 "t3" + OpName %b "b" + OpName %t4 "t4" + OpName %sp_float "sp_float" + OpDecorate %OutputBuffer BufferBlock + OpMemberDecorate %OutputBuffer 0 Offset 0 + OpMemberDecorate %OutputBuffer 1 Offset 4 + OpMemberDecorate %OutputBuffer 2 Offset 8 + OpMemberDecorate %OutputBuffer 3 Offset 12 + OpMemberDecorate %OutputBuffer 4 Offset 16 + OpMemberDecorate %OutputBuffer 5 Offset 20 + OpMemberDecorate %OutputBuffer 6 Offset 24 + OpMemberDecorate %OutputBuffer 7 Offset 28 + OpMemberDecorate %OutputBuffer 8 Offset 32 + OpMemberDecorate %OutputBuffer 9 Offset 36 + OpMemberDecorate %OutputBuffer 10 Offset 40 + OpMemberDecorate %OutputBuffer 11 Offset 44 + OpMemberDecorate %OutputBuffer 12 Offset 48 + OpMemberDecorate %OutputBuffer 13 Offset 52 + OpMemberDecorate %OutputBuffer 14 Offset 56 + OpMemberDecorate %OutputBuffer 15 Offset 60 + OpMemberDecorate %OutputBuffer 16 Offset 64 + OpMemberDecorate %OutputBuffer 17 Offset 68 + OpMemberDecorate %OutputBuffer 18 Offset 72 + OpMemberDecorate %OutputBuffer 19 Offset 76 + OpMemberDecorate %OutputBuffer 20 Offset 80 + OpMemberDecorate %OutputBuffer 21 Offset 84 + OpMemberDecorate %OutputBuffer 22 Offset 88 + OpMemberDecorate %OutputBuffer 23 Offset 92 + OpMemberDecorate %OutputBuffer 24 Offset 96 + OpMemberDecorate %OutputBuffer 25 Offset 100 + OpMemberDecorate %OutputBuffer 26 Offset 104 + OpMemberDecorate %OutputBuffer 27 Offset 108 + OpMemberDecorate %OutputBuffer 28 Offset 112 + OpMemberDecorate %OutputBuffer 29 Offset 116 + OpMemberDecorate %OutputBuffer 30 Offset 120 + OpMemberDecorate %OutputBuffer 31 Offset 124 + OpMemberDecorate %OutputBuffer 32 Offset 128 + OpMemberDecorate %OutputBuffer 33 Offset 132 + OpMemberDecorate %OutputBuffer 34 Offset 136 + OpMemberDecorate %OutputBuffer 35 Offset 140 + OpMemberDecorate %OutputBuffer 36 Offset 144 + OpDecorate %output_buffer Binding 0 + OpDecorate %output_buffer DescriptorSet 0 + OpDecorate %sp_int SpecId 1 + OpDecorate %sp_uint SpecId 2 + OpDecorate %sp_sint SpecId 3 + OpDecorate %c SpecId 6 + OpDecorate %a SpecId 4 + OpDecorate %b SpecId 5 + OpDecorate %sp_float SpecId 0 + %void = OpTypeVoid + %3 = OpTypeFunction %void + %uint = OpTypeInt 32 0 + %int = OpTypeInt 32 1 +%OutputBuffer = OpTypeStruct %uint %uint %int %uint %int %int %int %int %int %int %uint %int %uint %int %int %uint %int %uint %int %uint %int %int %uint %uint %uint %uint %uint %uint %uint %uint %uint %uint %uint %int %int %int %int +%_ptr_Uniform_OutputBuffer = OpTypePointer Uniform %OutputBuffer +%output_buffer = OpVariable %_ptr_Uniform_OutputBuffer Uniform + %int_0 = OpConstant %int 0 + %sp_int = OpSpecConstant %int 10 + %bool = OpTypeBool + %uint_0 = OpConstant %uint 0 +%bool_from_int = OpSpecConstantOp %bool INotEqual %sp_int %uint_0 + %uint_1 = OpConstant %uint 1 + %17 = OpSpecConstantOp %uint Select %bool_from_int %uint_1 %uint_0 +%_ptr_Uniform_uint = OpTypePointer Uniform %uint + %int_1 = OpConstant %int 1 + %sp_uint = OpSpecConstant %uint 100 +%bool_from_uint = OpSpecConstantOp %bool INotEqual %sp_uint %uint_0 + %23 = OpSpecConstantOp %uint Select %bool_from_uint %uint_1 %uint_0 + %int_2 = OpConstant %int 2 +%int_from_bool = OpSpecConstantOp %int Select %bool_from_int %int_1 %int_0 +%_ptr_Uniform_int = OpTypePointer Uniform %int + %int_3 = OpConstant %int 3 +%uint_from_bool = OpSpecConstantOp %uint Select %bool_from_int %uint_1 %uint_0 + %int_4 = OpConstant %int 4 + %negate_int = OpSpecConstantOp %int SNegate %sp_int + %int_5 = OpConstant %int 5 + %not_int = OpSpecConstantOp %int Not %sp_int + %int_6 = OpConstant %int 6 +%sp_int_add_two = OpSpecConstantOp %int IAdd %sp_int %int_2 + %int_7 = OpConstant %int 7 + %42 = OpSpecConstantOp %int IAdd %sp_int %int_2 +%sp_int_add_two_sub_three = OpSpecConstantOp %int ISub %42 %int_3 + %int_8 = OpConstant %int 8 +%sp_int_add_two_sub_four = OpSpecConstantOp %int ISub %sp_int_add_two %int_4 + %int_9 = OpConstant %int 9 + %sp_sint = OpSpecConstant %int -10 +%sp_sint_mul_two = OpSpecConstantOp %int IMul %sp_sint %int_2 + %int_10 = OpConstant %int 10 + %uint_2 = OpConstant %uint 2 +%sp_uint_mul_two = OpSpecConstantOp %uint IMul %sp_uint %uint_2 + %int_11 = OpConstant %int 11 +%sp_sint_mul_two_div_five = OpSpecConstantOp %int SDiv %sp_sint_mul_two %int_5 + %int_12 = OpConstant %int 12 + %uint_5 = OpConstant %uint 5 +%sp_uint_mul_two_div_five = OpSpecConstantOp %uint UDiv %sp_uint_mul_two %uint_5 + %int_13 = OpConstant %int 13 + %64 = OpSpecConstantOp %int IMul %sp_sint %int_3 +%sp_sint_mul_three_div_five = OpSpecConstantOp %int SDiv %64 %int_5 + %int_14 = OpConstant %int 14 +%sp_sint_rem_four = OpSpecConstantOp %int SMod %sp_sint %int_4 + %int_15 = OpConstant %int 15 + %uint_4 = OpConstant %uint 4 +%sp_uint_rem_four = OpSpecConstantOp %uint UMod %sp_uint %uint_4 + %int_16 = OpConstant %int 16 + %uint_10 = OpConstant %uint 10 +%sp_sint_shift_right_arithmetic = OpSpecConstantOp %int ShiftRightArithmetic %sp_sint %uint_10 + %int_17 = OpConstant %int 17 + %uint_20 = OpConstant %uint 20 +%sp_uint_shift_right_arithmetic = OpSpecConstantOp %uint ShiftRightLogical %sp_uint %uint_20 + %int_18 = OpConstant %int 18 +%sp_sint_shift_left = OpSpecConstantOp %int ShiftLeftLogical %sp_sint %uint_1 + %int_19 = OpConstant %int 19 +%sp_uint_shift_left = OpSpecConstantOp %uint ShiftLeftLogical %sp_uint %uint_2 + %int_20 = OpConstant %int 20 +%sp_sint_and_3 = OpSpecConstantOp %int BitwiseAnd %sp_sint %int_3 + %int_21 = OpConstant %int 21 + %int_256 = OpConstant %int 256 +%sp_sint_or_256 = OpSpecConstantOp %int BitwiseOr %sp_sint %int_256 + %int_22 = OpConstant %int 22 + %uint_512 = OpConstant %uint 512 +%sp_uint_xor_512 = OpSpecConstantOp %uint BitwiseXor %sp_uint %uint_512 + %int_23 = OpConstant %int 23 +%sp_int_lt_sp_sint = OpSpecConstantOp %bool SLessThan %sp_int %sp_sint + %101 = OpSpecConstantOp %uint Select %sp_int_lt_sp_sint %uint_1 %uint_0 + %int_24 = OpConstant %int 24 +%sp_int_le_sp_sint = OpSpecConstantOp %bool SLessThanEqual %sp_int %sp_sint + %105 = OpSpecConstantOp %uint Select %sp_int_le_sp_sint %uint_1 %uint_0 + %int_25 = OpConstant %int 25 +%sp_uint_equal_sp_uint = OpSpecConstantOp %bool IEqual %sp_uint %sp_uint + %109 = OpSpecConstantOp %uint Select %sp_uint_equal_sp_uint %uint_1 %uint_0 + %int_26 = OpConstant %int 26 +%sp_uint_not_equal_sp_uint = OpSpecConstantOp %bool INotEqual %sp_uint %sp_uint + %113 = OpSpecConstantOp %uint Select %sp_uint_not_equal_sp_uint %uint_1 %uint_0 + %int_27 = OpConstant %int 27 +%sp_int_gt_sp_sint = OpSpecConstantOp %bool SGreaterThan %sp_int %sp_sint + %117 = OpSpecConstantOp %uint Select %sp_int_gt_sp_sint %uint_1 %uint_0 + %int_28 = OpConstant %int 28 +%sp_int_ge_sp_sint = OpSpecConstantOp %bool SGreaterThanEqual %sp_int %sp_sint + %121 = OpSpecConstantOp %uint Select %sp_int_ge_sp_sint %uint_1 %uint_0 + %int_29 = OpConstant %int 29 +%logical_and = OpSpecConstantOp %bool LogicalAnd %bool_from_int %bool_from_uint + %125 = OpSpecConstantOp %uint Select %logical_and %uint_1 %uint_0 + %int_30 = OpConstant %int 30 + %logical_or = OpSpecConstantOp %bool LogicalOr %bool_from_int %bool_from_uint + %129 = OpSpecConstantOp %uint Select %logical_or %uint_1 %uint_0 + %int_31 = OpConstant %int 31 +%logical_equal = OpSpecConstantOp %bool LogicalEqual %bool_from_int %bool_from_uint + %133 = OpSpecConstantOp %uint Select %logical_equal %uint_1 %uint_0 + %int_32 = OpConstant %int 32 +%logical_not_equal = OpSpecConstantOp %bool LogicalNotEqual %bool_from_int %bool_from_uint + %137 = OpSpecConstantOp %uint Select %logical_not_equal %uint_1 %uint_0 + %int_33 = OpConstant %int 33 + %c = OpSpecConstantTrue %bool + %t1 = OpSpecConstantOp %int Select %c %int_13 %int_17 + %int_34 = OpConstant %int 34 + %a = OpSpecConstant %int 4 + %t2 = OpSpecConstantOp %int Select %c %a %int_17 + %int_35 = OpConstant %int 35 + %true = OpConstantTrue %bool + %t3 = OpSpecConstantOp %int Select %true %a %int_17 + %int_36 = OpConstant %int 36 + %b = OpSpecConstant %int 6 + %153 = OpSpecConstantOp %bool SGreaterThan %a %b + %154 = OpSpecConstantOp %int IAdd %int_13 %a + %155 = OpSpecConstantOp %int IMul %int_17 %b + %t4 = OpSpecConstantOp %int Select %153 %154 %155 + %float = OpTypeFloat 32 + %sp_float = OpSpecConstant %float 3.1415925 + %main = OpFunction %void None %3 + %5 = OpLabel + %19 = OpAccessChain %_ptr_Uniform_uint %output_buffer %int_0 + OpStore %19 %17 + %24 = OpAccessChain %_ptr_Uniform_uint %output_buffer %int_1 + OpStore %24 %23 + %28 = OpAccessChain %_ptr_Uniform_int %output_buffer %int_2 + OpStore %28 %int_from_bool + %31 = OpAccessChain %_ptr_Uniform_uint %output_buffer %int_3 + OpStore %31 %uint_from_bool + %34 = OpAccessChain %_ptr_Uniform_int %output_buffer %int_4 + OpStore %34 %negate_int + %37 = OpAccessChain %_ptr_Uniform_int %output_buffer %int_5 + OpStore %37 %not_int + %40 = OpAccessChain %_ptr_Uniform_int %output_buffer %int_6 + OpStore %40 %sp_int_add_two + %44 = OpAccessChain %_ptr_Uniform_int %output_buffer %int_7 + OpStore %44 %sp_int_add_two_sub_three + %47 = OpAccessChain %_ptr_Uniform_int %output_buffer %int_8 + OpStore %47 %sp_int_add_two_sub_four + %51 = OpAccessChain %_ptr_Uniform_int %output_buffer %int_9 + OpStore %51 %sp_sint_mul_two + %55 = OpAccessChain %_ptr_Uniform_uint %output_buffer %int_10 + OpStore %55 %sp_uint_mul_two + %58 = OpAccessChain %_ptr_Uniform_int %output_buffer %int_11 + OpStore %58 %sp_sint_mul_two_div_five + %62 = OpAccessChain %_ptr_Uniform_uint %output_buffer %int_12 + OpStore %62 %sp_uint_mul_two_div_five + %66 = OpAccessChain %_ptr_Uniform_int %output_buffer %int_13 + OpStore %66 %sp_sint_mul_three_div_five + %69 = OpAccessChain %_ptr_Uniform_int %output_buffer %int_14 + OpStore %69 %sp_sint_rem_four + %73 = OpAccessChain %_ptr_Uniform_uint %output_buffer %int_15 + OpStore %73 %sp_uint_rem_four + %77 = OpAccessChain %_ptr_Uniform_int %output_buffer %int_16 + OpStore %77 %sp_sint_shift_right_arithmetic + %81 = OpAccessChain %_ptr_Uniform_uint %output_buffer %int_17 + OpStore %81 %sp_uint_shift_right_arithmetic + %84 = OpAccessChain %_ptr_Uniform_int %output_buffer %int_18 + OpStore %84 %sp_sint_shift_left + %87 = OpAccessChain %_ptr_Uniform_uint %output_buffer %int_19 + OpStore %87 %sp_uint_shift_left + %90 = OpAccessChain %_ptr_Uniform_int %output_buffer %int_20 + OpStore %90 %sp_sint_and_3 + %94 = OpAccessChain %_ptr_Uniform_int %output_buffer %int_21 + OpStore %94 %sp_sint_or_256 + %98 = OpAccessChain %_ptr_Uniform_uint %output_buffer %int_22 + OpStore %98 %sp_uint_xor_512 + %102 = OpAccessChain %_ptr_Uniform_uint %output_buffer %int_23 + OpStore %102 %101 + %106 = OpAccessChain %_ptr_Uniform_uint %output_buffer %int_24 + OpStore %106 %105 + %110 = OpAccessChain %_ptr_Uniform_uint %output_buffer %int_25 + OpStore %110 %109 + %114 = OpAccessChain %_ptr_Uniform_uint %output_buffer %int_26 + OpStore %114 %113 + %118 = OpAccessChain %_ptr_Uniform_uint %output_buffer %int_27 + OpStore %118 %117 + %122 = OpAccessChain %_ptr_Uniform_uint %output_buffer %int_28 + OpStore %122 %121 + %126 = OpAccessChain %_ptr_Uniform_uint %output_buffer %int_29 + OpStore %126 %125 + %130 = OpAccessChain %_ptr_Uniform_uint %output_buffer %int_30 + OpStore %130 %129 + %134 = OpAccessChain %_ptr_Uniform_uint %output_buffer %int_31 + OpStore %134 %133 + %138 = OpAccessChain %_ptr_Uniform_uint %output_buffer %int_32 + OpStore %138 %137 + %142 = OpAccessChain %_ptr_Uniform_int %output_buffer %int_33 + OpStore %142 %t1 + %146 = OpAccessChain %_ptr_Uniform_int %output_buffer %int_34 + OpStore %146 %t2 + %150 = OpAccessChain %_ptr_Uniform_int %output_buffer %int_35 + OpStore %150 %t3 + %157 = OpAccessChain %_ptr_Uniform_int %output_buffer %int_36 + OpStore %157 %t4 + OpReturn + OpFunctionEnd diff --git a/naga/tests/in/spv/spec-constant-op.toml b/naga/tests/in/spv/spec-constant-op.toml new file mode 100644 index 00000000000..d5430502843 --- /dev/null +++ b/naga/tests/in/spv/spec-constant-op.toml @@ -0,0 +1,8 @@ +pipeline_constants = { 0 = 10, 1 = 3, 2 = 20, 3 = 4, 4 = 1.0, 5 = 0.0, 6 = 10.5 } +targets = "HLSL" + +[spv-in] +adjust_coordinate_space = false + +[spv] +separate_entry_points = true diff --git a/naga/tests/out/hlsl/spv-spec-constant-op-chained.hlsl b/naga/tests/out/hlsl/spv-spec-constant-op-chained.hlsl new file mode 100644 index 00000000000..f78b43088d1 --- /dev/null +++ b/naga/tests/out/hlsl/spv-spec-constant-op-chained.hlsl @@ -0,0 +1,30 @@ +struct type_2 { + uint member; + uint member_1; + uint member_2; +}; + +static const int _spec_const_op_12_ = int(13); +static const int _spec_const_op_13_ = int(39); +static const int _spec_const_op_14_ = int(26); +static const int _spec_const_op_15_ = int(13); +static const int _spec_const_op_16_ = int(130); +static const int _spec_const_op_const_17_ = int(1); +static const int _spec_const_op_18_ = int(129); +static const int _spec_const_op_19_ = int(387); + +RWByteAddressBuffer global : register(u0); + +void function() +{ + global.Store(0, asuint(asuint(_spec_const_op_13_))); + global.Store(4, asuint(asuint(_spec_const_op_14_))); + global.Store(8, asuint(asuint(_spec_const_op_19_))); + return; +} + +[numthreads(1, 1, 1)] +void main() +{ + function(); +} diff --git a/naga/tests/out/hlsl/spv-spec-constant-op-chained.ron b/naga/tests/out/hlsl/spv-spec-constant-op-chained.ron new file mode 100644 index 00000000000..a07b03300b1 --- /dev/null +++ b/naga/tests/out/hlsl/spv-spec-constant-op-chained.ron @@ -0,0 +1,12 @@ +( + vertex:[ + ], + fragment:[ + ], + compute:[ + ( + entry_point:"main", + target_profile:"cs_5_1", + ), + ], +) diff --git a/naga/tests/out/hlsl/spv-spec-constant-op.hlsl b/naga/tests/out/hlsl/spv-spec-constant-op.hlsl new file mode 100644 index 00000000000..4955da755b9 --- /dev/null +++ b/naga/tests/out/hlsl/spv-spec-constant-op.hlsl @@ -0,0 +1,206 @@ +struct OutputBuffer { + uint bool_from_int_val; + uint bool_from_uint_val; + int int_from_bool_val; + uint uint_from_bool_val; + int negate_int_val; + int not_int_val; + int sp_int_add_two_val; + int sp_int_add_two_sub_three_val; + int sp_int_add_two_sub_four_val; + int sp_sint_mul_two_val; + uint sp_uint_mul_two_val; + int sp_sint_mul_two_div_five_val; + uint sp_uint_mul_two_div_five_val; + int sp_sint_mul_three_div_five_val; + int sp_sint_rem_four_val; + uint sp_uint_rem_four_val; + int sp_sint_shift_right_arithmetic_val; + uint sp_uint_shift_right_arithmetic_val; + int sp_sint_shift_left_val; + uint sp_uint_shift_left_val; + int sp_sint_and_3_val; + int sp_sint_or_256_val; + uint sp_uint_xor_512_val; + uint sp_int_lt_sp_sint_val; + uint sp_int_le_sp_sint_val; + uint sp_uint_equal_sp_uint_val; + uint sp_uint_not_equal_sp_uint_val; + uint sp_int_gt_sp_sint_val; + uint sp_int_ge_sp_sint_val; + uint logical_and_val; + uint logical_or_val; + uint logical_equal_val; + uint logical_not_equal_val; + int t1_val; + int t2_val; + int t3_val; + int t4_val; +}; + +static const int sp_int = int(3); +static const uint _spec_const_op_const_56_ = 0u; +static const bool _spec_const_op_6_ = true; +static const uint _spec_const_op_const_57_ = 1u; +static const uint _spec_const_op_const_56_1 = 0u; +static const uint _spec_const_op_58_ = 1u; +static const uint sp_uint = 20u; +static const uint _spec_const_op_const_56_2 = 0u; +static const bool _spec_const_op_8_ = true; +static const uint _spec_const_op_const_57_1 = 1u; +static const uint _spec_const_op_const_56_3 = 0u; +static const uint _spec_const_op_61_ = 1u; +static const int _spec_const_op_const_60_ = int(1); +static const int _spec_const_op_const_54_ = int(0); +static const int _spec_const_op_9_ = int(1); +static const uint _spec_const_op_const_57_2 = 1u; +static const uint _spec_const_op_const_56_4 = 0u; +static const uint _spec_const_op_10_ = 1u; +static const int _spec_const_op_11_ = int(-3); +static const int _spec_const_op_12_ = int(-4); +static const int _spec_const_op_const_62_ = int(2); +static const int _spec_const_op_13_ = int(5); +static const int _spec_const_op_const_62_1 = int(2); +static const int _spec_const_op_69_ = int(5); +static const int _spec_const_op_const_64_ = int(3); +static const int _spec_const_op_14_ = int(2); +static const int _spec_const_op_const_65_ = int(4); +static const int _spec_const_op_15_ = int(1); +static const int sp_sint = int(4); +static const int _spec_const_op_const_62_2 = int(2); +static const int _spec_const_op_17_ = int(8); +static const uint _spec_const_op_const_73_ = 2u; +static const uint _spec_const_op_18_ = 40u; +static const int _spec_const_op_const_66_ = int(5); +static const int _spec_const_op_19_ = int(1); +static const uint _spec_const_op_const_76_ = 5u; +static const uint _spec_const_op_20_ = 8u; +static const int _spec_const_op_const_64_1 = int(3); +static const int _spec_const_op_78_ = int(12); +static const int _spec_const_op_const_66_1 = int(5); +static const int _spec_const_op_21_ = int(2); +static const int _spec_const_op_const_65_1 = int(4); +static const int _spec_const_op_22_ = int(0); +static const uint _spec_const_op_const_81_ = 4u; +static const uint _spec_const_op_23_ = 0u; +static const uint _spec_const_op_const_83_ = 10u; +static const int _spec_const_op_24_ = int(0); +static const uint _spec_const_op_const_85_ = 20u; +static const uint _spec_const_op_25_ = 0u; +static const uint _spec_const_op_const_57_3 = 1u; +static const int _spec_const_op_26_ = int(8); +static const uint _spec_const_op_const_73_1 = 2u; +static const uint _spec_const_op_27_ = 80u; +static const int _spec_const_op_const_64_2 = int(3); +static const int _spec_const_op_28_ = int(0); +static const int _spec_const_op_const_90_ = int(256); +static const int _spec_const_op_29_ = int(260); +static const uint _spec_const_op_const_92_ = 512u; +static const uint _spec_const_op_30_ = 532u; +static const bool _spec_const_op_31_ = true; +static const uint _spec_const_op_const_57_4 = 1u; +static const uint _spec_const_op_const_56_5 = 0u; +static const uint _spec_const_op_94_ = 1u; +static const bool _spec_const_op_32_ = true; +static const uint _spec_const_op_const_57_5 = 1u; +static const uint _spec_const_op_const_56_6 = 0u; +static const uint _spec_const_op_96_ = 1u; +static const bool _spec_const_op_33_ = true; +static const uint _spec_const_op_const_57_6 = 1u; +static const uint _spec_const_op_const_56_7 = 0u; +static const uint _spec_const_op_98_ = 1u; +static const bool _spec_const_op_34_ = false; +static const uint _spec_const_op_const_57_7 = 1u; +static const uint _spec_const_op_const_56_8 = 0u; +static const uint _spec_const_op_100_ = 0u; +static const bool _spec_const_op_35_ = false; +static const uint _spec_const_op_const_57_8 = 1u; +static const uint _spec_const_op_const_56_9 = 0u; +static const uint _spec_const_op_102_ = 0u; +static const bool _spec_const_op_36_ = false; +static const uint _spec_const_op_const_57_9 = 1u; +static const uint _spec_const_op_const_56_10 = 0u; +static const uint _spec_const_op_104_ = 0u; +static const bool _spec_const_op_37_ = true; +static const uint _spec_const_op_const_57_10 = 1u; +static const uint _spec_const_op_const_56_11 = 0u; +static const uint _spec_const_op_106_ = 1u; +static const bool _spec_const_op_38_ = true; +static const uint _spec_const_op_const_57_11 = 1u; +static const uint _spec_const_op_const_56_12 = 0u; +static const uint _spec_const_op_108_ = 1u; +static const bool _spec_const_op_39_ = true; +static const uint _spec_const_op_const_57_12 = 1u; +static const uint _spec_const_op_const_56_13 = 0u; +static const uint _spec_const_op_110_ = 1u; +static const bool _spec_const_op_40_ = false; +static const uint _spec_const_op_const_57_13 = 1u; +static const uint _spec_const_op_const_56_14 = 0u; +static const uint _spec_const_op_112_ = 0u; +static const bool c = true; +static const int _spec_const_op_const_77_ = int(13); +static const int _spec_const_op_const_84_ = int(17); +static const int _spec_const_op_42_ = int(13); +static const int a = int(1); +static const int _spec_const_op_const_84_1 = int(17); +static const int _spec_const_op_44_ = int(1); +static const bool _spec_const_op_const_116_ = true; +static const int _spec_const_op_const_84_2 = int(17); +static const int _spec_const_op_45_ = int(1); +static const int b = int(0); +static const bool _spec_const_op_118_ = true; +static const int _spec_const_op_const_77_1 = int(13); +static const int _spec_const_op_119_ = int(14); +static const int _spec_const_op_const_84_3 = int(17); +static const int _spec_const_op_120_ = int(0); +static const int _spec_const_op_47_ = int(14); + +RWByteAddressBuffer output_buffer : register(u0); + +void main_1() +{ + output_buffer.Store(0, asuint(_spec_const_op_58_)); + output_buffer.Store(4, asuint(_spec_const_op_61_)); + output_buffer.Store(8, asuint(_spec_const_op_9_)); + output_buffer.Store(12, asuint(_spec_const_op_10_)); + output_buffer.Store(16, asuint(_spec_const_op_11_)); + output_buffer.Store(20, asuint(_spec_const_op_12_)); + output_buffer.Store(24, asuint(_spec_const_op_13_)); + output_buffer.Store(28, asuint(_spec_const_op_14_)); + output_buffer.Store(32, asuint(_spec_const_op_15_)); + output_buffer.Store(36, asuint(_spec_const_op_17_)); + output_buffer.Store(40, asuint(_spec_const_op_18_)); + output_buffer.Store(44, asuint(_spec_const_op_19_)); + output_buffer.Store(48, asuint(_spec_const_op_20_)); + output_buffer.Store(52, asuint(_spec_const_op_21_)); + output_buffer.Store(56, asuint(_spec_const_op_22_)); + output_buffer.Store(60, asuint(_spec_const_op_23_)); + output_buffer.Store(64, asuint(_spec_const_op_24_)); + output_buffer.Store(68, asuint(_spec_const_op_25_)); + output_buffer.Store(72, asuint(_spec_const_op_26_)); + output_buffer.Store(76, asuint(_spec_const_op_27_)); + output_buffer.Store(80, asuint(_spec_const_op_28_)); + output_buffer.Store(84, asuint(_spec_const_op_29_)); + output_buffer.Store(88, asuint(_spec_const_op_30_)); + output_buffer.Store(92, asuint(_spec_const_op_94_)); + output_buffer.Store(96, asuint(_spec_const_op_96_)); + output_buffer.Store(100, asuint(_spec_const_op_98_)); + output_buffer.Store(104, asuint(_spec_const_op_100_)); + output_buffer.Store(108, asuint(_spec_const_op_102_)); + output_buffer.Store(112, asuint(_spec_const_op_104_)); + output_buffer.Store(116, asuint(_spec_const_op_106_)); + output_buffer.Store(120, asuint(_spec_const_op_108_)); + output_buffer.Store(124, asuint(_spec_const_op_110_)); + output_buffer.Store(128, asuint(_spec_const_op_112_)); + output_buffer.Store(132, asuint(_spec_const_op_42_)); + output_buffer.Store(136, asuint(_spec_const_op_44_)); + output_buffer.Store(140, asuint(_spec_const_op_45_)); + output_buffer.Store(144, asuint(_spec_const_op_47_)); + return; +} + +[numthreads(1, 1, 1)] +void main() +{ + main_1(); +} diff --git a/naga/tests/out/hlsl/spv-spec-constant-op.ron b/naga/tests/out/hlsl/spv-spec-constant-op.ron new file mode 100644 index 00000000000..a07b03300b1 --- /dev/null +++ b/naga/tests/out/hlsl/spv-spec-constant-op.ron @@ -0,0 +1,12 @@ +( + vertex:[ + ], + fragment:[ + ], + compute:[ + ( + entry_point:"main", + target_profile:"cs_5_1", + ), + ], +) From 0bacbdf43209172fd8993be75935abcfd908a426 Mon Sep 17 00:00:00 2001 From: Nils Hasenbanck Date: Tue, 7 Oct 2025 18:16:10 +0200 Subject: [PATCH 2/3] (Naga) Remove override workaround and properly track expression kind in the SPIR-V frontend --- naga/src/front/spv/error.rs | 13 +- naga/src/front/spv/mod.rs | 403 +++++++++++++----- naga/src/front/spv/null.rs | 31 +- .../hlsl/spv-spec-constant-op-chained.hlsl | 1 - naga/tests/out/hlsl/spv-spec-constant-op.hlsl | 56 --- 5 files changed, 331 insertions(+), 173 deletions(-) diff --git a/naga/src/front/spv/error.rs b/naga/src/front/spv/error.rs index 8bd62341946..e0194fbd15f 100644 --- a/naga/src/front/spv/error.rs +++ b/naga/src/front/spv/error.rs @@ -1,8 +1,8 @@ +use alloc::borrow::Cow; use alloc::{ format, string::{String, ToString}, }; - use codespan_reporting::diagnostic::Diagnostic; use codespan_reporting::files::SimpleFile; use codespan_reporting::term; @@ -14,6 +14,8 @@ use crate::{ front::atomic_upgrade, }; +use crate::proc::ConstantEvaluatorError; + #[derive(Clone, Debug, thiserror::Error)] pub enum Error { #[error("invalid header")] @@ -30,6 +32,8 @@ pub enum Error { UnsupportedSpecConstantOp(spirv::Op), #[error("invalid opcode in specialization constant operation {0:?}")] InvalidSpecConstantOp(spirv::Op), + #[error("{0}")] + SemanticError(Cow<'static, str>), #[error("unsupported capability {0:?}")] UnsupportedCapability(spirv::Capability), #[error("unsupported extension {0}")] @@ -155,11 +159,16 @@ pub enum Error { NonBindingArrayOfImageOrSamplers, #[error("naga only supports specialization constant IDs up to 65535 but was given {0}")] SpecIdTooHigh(u32), - #[error("atomic upgrade error: {0}")] AtomicUpgradeError(atomic_upgrade::Error), } +impl From for Error { + fn from(err: ConstantEvaluatorError) -> Self { + Error::SemanticError(err.to_string().into()) + } +} + impl Error { pub fn emit_to_writer(&self, writer: &mut impl ErrorWrite, source: &str) { self.emit_to_writer_with_path(writer, source, "glsl"); diff --git a/naga/src/front/spv/mod.rs b/naga/src/front/spv/mod.rs index 6951f11dadc..bff6d4baf02 100644 --- a/naga/src/front/spv/mod.rs +++ b/naga/src/front/spv/mod.rs @@ -310,6 +310,13 @@ impl Constant { Self::Override(o) => crate::Expression::Override(o), } } + + const fn to_expr_kind(&self) -> crate::proc::ExpressionKind { + match *self { + Self::Constant(_) => crate::proc::ExpressionKind::Const, + Self::Override(_) => crate::proc::ExpressionKind::Override, + } + } } #[derive(Debug)] @@ -4753,6 +4760,8 @@ impl> Frontend { self.lookup_function.clear(); self.function_call_graph.clear(); + let mut global_expression_kind_tracker = crate::proc::ExpressionKindTracker::new(); + loop { use spirv::Op; @@ -4792,19 +4801,74 @@ impl> Frontend { Op::TypeImage => self.parse_type_image(inst, &mut module), Op::TypeSampledImage => self.parse_type_sampled_image(inst), Op::TypeSampler => self.parse_type_sampler(inst, &mut module), - Op::Constant | Op::SpecConstant => self.parse_constant(inst, &mut module), - Op::ConstantComposite | Op::SpecConstantComposite => { - self.parse_composite_constant(inst, &mut module) - } - Op::ConstantNull | Op::Undef => self.parse_null_constant(inst, &mut module), - Op::ConstantTrue | Op::SpecConstantTrue => { - self.parse_bool_constant(inst, true, &mut module) - } - Op::ConstantFalse | Op::SpecConstantFalse => { - self.parse_bool_constant(inst, false, &mut module) - } - Op::SpecConstantOp => self.parse_spec_constant_op(inst, &mut module), - Op::Variable => self.parse_global_variable(inst, &mut module), + Op::Constant => self.parse_constant( + inst, + &mut module, + &mut global_expression_kind_tracker, + crate::proc::ExpressionKind::Const, + ), + Op::SpecConstant => self.parse_constant( + inst, + &mut module, + &mut global_expression_kind_tracker, + crate::proc::ExpressionKind::Override, + ), + Op::ConstantComposite => self.parse_composite_constant( + inst, + &mut module, + &mut global_expression_kind_tracker, + crate::proc::ExpressionKind::Const, + ), + Op::SpecConstantComposite => self.parse_composite_constant( + inst, + &mut module, + &mut global_expression_kind_tracker, + crate::proc::ExpressionKind::Override, + ), + Op::ConstantNull | Op::Undef => self.parse_null_constant( + inst, + &mut module, + &mut global_expression_kind_tracker, + crate::proc::ExpressionKind::Const, + ), + Op::ConstantTrue => self.parse_bool_constant( + inst, + true, + &mut module, + &mut global_expression_kind_tracker, + crate::proc::ExpressionKind::Const, + ), + Op::SpecConstantTrue => self.parse_bool_constant( + inst, + true, + &mut module, + &mut global_expression_kind_tracker, + crate::proc::ExpressionKind::Override, + ), + Op::ConstantFalse => self.parse_bool_constant( + inst, + false, + &mut module, + &mut global_expression_kind_tracker, + crate::proc::ExpressionKind::Const, + ), + Op::SpecConstantFalse => self.parse_bool_constant( + inst, + false, + &mut module, + &mut global_expression_kind_tracker, + crate::proc::ExpressionKind::Override, + ), + Op::SpecConstantOp => self.parse_spec_constant_op( + inst, + &mut module, + &mut global_expression_kind_tracker, + ), + Op::Variable => self.parse_global_variable( + inst, + &mut module, + &mut global_expression_kind_tracker, + ), Op::Function => { self.switch(ModuleState::Function, inst.op)?; inst.expect(5)?; @@ -5747,6 +5811,8 @@ impl> Frontend { &mut self, inst: Instruction, module: &mut crate::Module, + global_expression_kind_tracker: &mut crate::proc::ExpressionKindTracker, + expr_kind: crate::proc::ExpressionKind, ) -> Result<(), Error> { let start = self.data_offset; self.switch(ModuleState::Type, inst.op)?; @@ -5812,9 +5878,13 @@ impl> Frontend { let span = self.span_from_with_op(start); - let init = module - .global_expressions - .append(crate::Expression::Literal(literal), span); + let init = append_global_expression( + module, + global_expression_kind_tracker, + crate::Expression::Literal(literal), + expr_kind, + span, + ); self.insert_parsed_constant(module, id, type_id, ty, init, span) } @@ -5823,6 +5893,8 @@ impl> Frontend { &mut self, inst: Instruction, module: &mut crate::Module, + global_expression_kind_tracker: &mut crate::proc::ExpressionKindTracker, + expr_kind: crate::proc::ExpressionKind, ) -> Result<(), Error> { let start = self.data_offset; self.switch(ModuleState::Type, inst.op)?; @@ -5839,17 +5911,25 @@ impl> Frontend { let component_id = self.next()?; let span = self.span_from_with_op(start); let constant = self.lookup_constant.lookup(component_id)?; - let expr = module - .global_expressions - .append(constant.inner.to_expr(), span); + let expr = append_global_expression( + module, + global_expression_kind_tracker, + constant.inner.to_expr(), + constant.inner.to_expr_kind(), + span, + ); components.push(expr); } let span = self.span_from_with_op(start); - let init = module - .global_expressions - .append(crate::Expression::Compose { ty, components }, span); + let init = append_global_expression( + module, + global_expression_kind_tracker, + crate::Expression::Compose { ty, components }, + expr_kind, + span, + ); self.insert_parsed_constant(module, id, type_id, ty, init, span) } @@ -5858,6 +5938,8 @@ impl> Frontend { &mut self, inst: Instruction, module: &mut crate::Module, + global_expression_kind_tracker: &mut crate::proc::ExpressionKindTracker, + expr_kind: crate::proc::ExpressionKind, ) -> Result<(), Error> { let start = self.data_offset; self.switch(ModuleState::Type, inst.op)?; @@ -5869,9 +5951,13 @@ impl> Frontend { let type_lookup = self.lookup_type.lookup(type_id)?; let ty = type_lookup.handle; - let init = module - .global_expressions - .append(crate::Expression::ZeroValue(ty), span); + let init = append_global_expression( + module, + global_expression_kind_tracker, + crate::Expression::ZeroValue(ty), + expr_kind, + span, + ); self.insert_parsed_constant(module, id, type_id, ty, init, span) } @@ -5881,6 +5967,8 @@ impl> Frontend { inst: Instruction, value: bool, module: &mut crate::Module, + global_expression_kind_tracker: &mut crate::proc::ExpressionKindTracker, + expr_kind: crate::proc::ExpressionKind, ) -> Result<(), Error> { let start = self.data_offset; self.switch(ModuleState::Type, inst.op)?; @@ -5892,18 +5980,40 @@ impl> Frontend { let type_lookup = self.lookup_type.lookup(type_id)?; let ty = type_lookup.handle; - let init = module.global_expressions.append( + let init = append_global_expression( + module, + global_expression_kind_tracker, crate::Expression::Literal(crate::Literal::Bool(value)), + expr_kind, span, ); self.insert_parsed_constant(module, id, type_id, ty, init, span) } + fn eval_and_append_expression( + &mut self, + module: &mut crate::Module, + global_expression_kind_tracker: &mut crate::proc::ExpressionKindTracker, + expr: crate::Expression, + span: crate::Span, + ) -> Result, Error> { + let mut evaluator = crate::proc::ConstantEvaluator::for_wgsl_module( + module, + global_expression_kind_tracker, + &mut self.layouter, + true, + ); + evaluator + .try_eval_and_append(expr, span) + .map_err(|error| error.into()) + } + fn parse_spec_constant_op( &mut self, inst: Instruction, module: &mut crate::Module, + global_expression_kind_tracker: &mut crate::proc::ExpressionKindTracker, ) -> Result<(), Error> { use spirv::Op; @@ -5924,41 +6034,9 @@ impl> Frontend { Op::SpecConstantOp, ))?; - let mut get_const_expr = - |frontend: &Self, const_id: spirv::Word| -> Result, Error> { - let lookup = frontend.lookup_constant.lookup(const_id)?; - match lookup.inner { - // Wrap regular constants in overrides to avoid creating Expression::Constant - // nodes, which would mark the entire expression tree as Const and fail - // validation for complex operations (Binary, As, Math) in override - // initializers. - // - // The downside is, that unused intermediate constants will get created, which - // I would like to avoid. - Constant::Constant(const_handle) => { - let const_init = module.constants[const_handle].init; - let const_ty = module.constants[const_handle].ty; - let wrapper_override = crate::Override { - name: Some(format!("_spec_const_op_const_{const_id}")), - id: None, - ty: const_ty, - init: Some(const_init), - }; - let override_handle = module.overrides.append(wrapper_override, span); - Ok(module - .global_expressions - .append(crate::Expression::Override(override_handle), span)) - } - Constant::Override(_) => Ok(module - .global_expressions - .append(lookup.inner.to_expr(), span)), - } - }; - let init = match opcode { Op::SConvert | Op::UConvert | Op::FConvert => { let value_id = self.next()?; - let value_expr = get_const_expr(self, value_id)?; let scalar = match module.types[ty].inner { crate::TypeInner::Scalar(scalar) @@ -5967,19 +6045,28 @@ impl> Frontend { _ => return Err(Error::InvalidAsType(ty)), }; - module.global_expressions.append( + let value_expr_inner = self.lookup_constant.lookup(value_id)?.inner.to_expr(); + let value_expr = self.eval_and_append_expression( + module, + global_expression_kind_tracker, + value_expr_inner, + span, + )?; + + self.eval_and_append_expression( + module, + global_expression_kind_tracker, crate::Expression::As { expr: value_expr, kind: scalar.kind, convert: Some(scalar.width), }, span, - ) + )? } Op::SNegate | Op::Not | Op::LogicalNot => { let value_id = self.next()?; - let value_expr = get_const_expr(self, value_id)?; let op = match opcode { Op::SNegate => crate::UnaryOperator::Negate, @@ -5988,13 +6075,23 @@ impl> Frontend { _ => unreachable!(), }; - module.global_expressions.append( + let value_expr_inner = self.lookup_constant.lookup(value_id)?.inner.to_expr(); + let value_expr = self.eval_and_append_expression( + module, + global_expression_kind_tracker, + value_expr_inner, + span, + )?; + + self.eval_and_append_expression( + module, + global_expression_kind_tracker, crate::Expression::Unary { op, expr: value_expr, }, span, - ) + )? } Op::IAdd @@ -6026,8 +6123,6 @@ impl> Frontend { | Op::SGreaterThanEqual => { let left_id = self.next()?; let right_id = self.next()?; - let left_expr = get_const_expr(self, left_id)?; - let right_expr = get_const_expr(self, right_id)?; let op = match opcode { Op::IAdd => crate::BinaryOperator::Add, @@ -6057,14 +6152,31 @@ impl> Frontend { _ => unreachable!(), }; - module.global_expressions.append( + let left_expr_inner = self.lookup_constant.lookup(left_id)?.inner.to_expr(); + let right_expr_inner = self.lookup_constant.lookup(right_id)?.inner.to_expr(); + let left_expr = self.eval_and_append_expression( + module, + global_expression_kind_tracker, + left_expr_inner, + span, + )?; + let right_expr = self.eval_and_append_expression( + module, + global_expression_kind_tracker, + right_expr_inner, + span, + )?; + + self.eval_and_append_expression( + module, + global_expression_kind_tracker, crate::Expression::Binary { op, left: left_expr, right: right_expr, }, span, - ) + )? } Op::SMod => { @@ -6072,40 +6184,62 @@ impl> Frontend { let left_id = self.next()?; let right_id = self.next()?; - let left = get_const_expr(self, left_id)?; - let right = get_const_expr(self, right_id)?; let scalar = match module.types[ty].inner { - crate::TypeInner::Scalar(scalar) => scalar, - crate::TypeInner::Vector { scalar, .. } => scalar, + crate::TypeInner::Scalar(scalar) | crate::TypeInner::Vector { scalar, .. } => { + scalar + } _ => return Err(Error::InvalidAsType(ty)), }; - let left_cast = module.global_expressions.append( + let left_inner = self.lookup_constant.lookup(left_id)?.inner.to_expr(); + let right_inner = self.lookup_constant.lookup(right_id)?.inner.to_expr(); + let left = self.eval_and_append_expression( + module, + global_expression_kind_tracker, + left_inner, + span, + )?; + let right = self.eval_and_append_expression( + module, + global_expression_kind_tracker, + right_inner, + span, + )?; + + let left_cast = self.eval_and_append_expression( + module, + global_expression_kind_tracker, crate::Expression::As { expr: left, kind: crate::ScalarKind::Float, convert: Some(scalar.width), }, span, - ); - let right_cast = module.global_expressions.append( + )?; + let right_cast = self.eval_and_append_expression( + module, + global_expression_kind_tracker, crate::Expression::As { expr: right, kind: crate::ScalarKind::Float, convert: Some(scalar.width), }, span, - ); - let div = module.global_expressions.append( + )?; + let div = self.eval_and_append_expression( + module, + global_expression_kind_tracker, crate::Expression::Binary { op: crate::BinaryOperator::Divide, left: left_cast, right: right_cast, }, span, - ); - let floor = module.global_expressions.append( + )?; + let floor = self.eval_and_append_expression( + module, + global_expression_kind_tracker, crate::Expression::Math { fun: crate::MathFunction::Floor, arg: div, @@ -6114,31 +6248,37 @@ impl> Frontend { arg3: None, }, span, - ); - let cast = module.global_expressions.append( + )?; + let cast = self.eval_and_append_expression( + module, + global_expression_kind_tracker, crate::Expression::As { expr: floor, kind: scalar.kind, convert: Some(scalar.width), }, span, - ); - let mult = module.global_expressions.append( + )?; + let mult = self.eval_and_append_expression( + module, + global_expression_kind_tracker, crate::Expression::Binary { op: crate::BinaryOperator::Multiply, left: cast, right, }, span, - ); - module.global_expressions.append( + )?; + self.eval_and_append_expression( + module, + global_expression_kind_tracker, crate::Expression::Binary { op: crate::BinaryOperator::Subtract, left, right: mult, }, span, - ) + )? } Op::Select => { @@ -6146,18 +6286,38 @@ impl> Frontend { let o1_id = self.next()?; let o2_id = self.next()?; - let cond = get_const_expr(self, condition_id)?; - let o1 = get_const_expr(self, o1_id)?; - let o2 = get_const_expr(self, o2_id)?; + let cond_expr = self.lookup_constant.lookup(condition_id)?.inner.to_expr(); + let o1_expr = self.lookup_constant.lookup(o1_id)?.inner.to_expr(); + let o2_expr = self.lookup_constant.lookup(o2_id)?.inner.to_expr(); + let cond = self.eval_and_append_expression( + module, + global_expression_kind_tracker, + cond_expr, + span, + )?; + let o1 = self.eval_and_append_expression( + module, + global_expression_kind_tracker, + o1_expr, + span, + )?; + let o2 = self.eval_and_append_expression( + module, + global_expression_kind_tracker, + o2_expr, + span, + )?; - module.global_expressions.append( + self.eval_and_append_expression( + module, + global_expression_kind_tracker, crate::Expression::Select { condition: cond, accept: o1, reject: o2, }, span, - ) + )? } Op::VectorShuffle | Op::CompositeExtract | Op::CompositeInsert | Op::QuantizeToF16 => { @@ -6227,6 +6387,7 @@ impl> Frontend { &mut self, inst: Instruction, module: &mut crate::Module, + global_expression_kind_tracker: &mut crate::proc::ExpressionKindTracker, ) -> Result<(), Error> { let start = self.data_offset; self.switch(ModuleState::Type, inst.op)?; @@ -6240,9 +6401,13 @@ impl> Frontend { let init_id = self.next()?; let span = self.span_from_with_op(start); let lconst = self.lookup_constant.lookup(init_id)?; - let expr = module - .global_expressions - .append(lconst.inner.to_expr(), span); + let expr = append_global_expression( + module, + global_expression_kind_tracker, + lconst.inner.to_expr(), + lconst.inner.to_expr_kind(), + span, + ); Some(expr) } else { None @@ -6361,9 +6526,10 @@ impl> Frontend { let init = match binding { Some(crate::Binding::BuiltIn(built_in)) => { match null::generate_default_built_in( + module, + global_expression_kind_tracker, Some(built_in), ty, - &mut module.global_expressions, span, ) { Ok(handle) => Some(handle), @@ -6376,25 +6542,36 @@ impl> Frontend { Some(crate::Binding::Location { .. }) => None, None => match module.types[ty].inner { crate::TypeInner::Struct { ref members, .. } => { - let mut components = Vec::with_capacity(members.len()); - for member in members.iter() { - let built_in = match member.binding { - Some(crate::Binding::BuiltIn(built_in)) => Some(built_in), - _ => None, - }; + // Collect member information first to avoid borrow conflicts + let member_info: Vec<_> = members + .iter() + .map(|member| { + let built_in = match member.binding { + Some(crate::Binding::BuiltIn(built_in)) => Some(built_in), + _ => None, + }; + (built_in, member.ty) + }) + .collect(); + + let mut components = Vec::with_capacity(member_info.len()); + for (built_in, member_ty) in member_info { let handle = null::generate_default_built_in( + module, + global_expression_kind_tracker, built_in, - member.ty, - &mut module.global_expressions, + member_ty, span, )?; components.push(handle); } - Some( - module - .global_expressions - .append(crate::Expression::Compose { ty, components }, span), - ) + Some(append_global_expression( + module, + global_expression_kind_tracker, + crate::Expression::Compose { ty, components }, + crate::proc::ExpressionKind::Const, + span, + )) } _ => None, }, @@ -6486,6 +6663,18 @@ impl> Frontend { } } +fn append_global_expression( + module: &mut crate::Module, + global_expression_kind_tracker: &mut crate::proc::ExpressionKindTracker, + expr: crate::Expression, + expr_kind: crate::proc::ExpressionKind, + span: crate::Span, +) -> Handle { + let handle = module.global_expressions.append(expr, span); + global_expression_kind_tracker.insert(handle, expr_kind); + handle +} + fn make_index_literal( ctx: &mut BlockContext, index: u32, diff --git a/naga/src/front/spv/null.rs b/naga/src/front/spv/null.rs index 8cd33f142f2..ff81f660089 100644 --- a/naga/src/front/spv/null.rs +++ b/naga/src/front/spv/null.rs @@ -1,21 +1,32 @@ use alloc::vec; use super::Error; -use crate::arena::{Arena, Handle}; +use crate::arena::Handle; /// Create a default value for an output built-in. pub fn generate_default_built_in( + module: &mut crate::Module, + global_expression_kind_tracker: &mut crate::proc::ExpressionKindTracker, built_in: Option, ty: Handle, - global_expressions: &mut Arena, span: crate::Span, ) -> Result, Error> { let expr = match built_in { Some(crate::BuiltIn::Position { .. }) => { - let zero = global_expressions - .append(crate::Expression::Literal(crate::Literal::F32(0.0)), span); - let one = global_expressions - .append(crate::Expression::Literal(crate::Literal::F32(1.0)), span); + let zero = super::append_global_expression( + module, + global_expression_kind_tracker, + crate::Expression::Literal(crate::Literal::F32(0.0)), + crate::proc::ExpressionKind::Const, + span, + ); + let one = super::append_global_expression( + module, + global_expression_kind_tracker, + crate::Expression::Literal(crate::Literal::F32(1.0)), + crate::proc::ExpressionKind::Const, + span, + ); crate::Expression::Compose { ty, components: vec![zero, zero, zero, one], @@ -29,5 +40,11 @@ pub fn generate_default_built_in( // Note: `crate::BuiltIn::ClipDistance` is intentionally left for the default path _ => crate::Expression::ZeroValue(ty), }; - Ok(global_expressions.append(expr, span)) + Ok(super::append_global_expression( + module, + global_expression_kind_tracker, + expr, + crate::proc::ExpressionKind::Const, + span, + )) } diff --git a/naga/tests/out/hlsl/spv-spec-constant-op-chained.hlsl b/naga/tests/out/hlsl/spv-spec-constant-op-chained.hlsl index f78b43088d1..c5f4dd5bf37 100644 --- a/naga/tests/out/hlsl/spv-spec-constant-op-chained.hlsl +++ b/naga/tests/out/hlsl/spv-spec-constant-op-chained.hlsl @@ -9,7 +9,6 @@ static const int _spec_const_op_13_ = int(39); static const int _spec_const_op_14_ = int(26); static const int _spec_const_op_15_ = int(13); static const int _spec_const_op_16_ = int(130); -static const int _spec_const_op_const_17_ = int(1); static const int _spec_const_op_18_ = int(129); static const int _spec_const_op_19_ = int(387); diff --git a/naga/tests/out/hlsl/spv-spec-constant-op.hlsl b/naga/tests/out/hlsl/spv-spec-constant-op.hlsl index 4955da755b9..989baadaceb 100644 --- a/naga/tests/out/hlsl/spv-spec-constant-op.hlsl +++ b/naga/tests/out/hlsl/spv-spec-constant-op.hlsl @@ -39,119 +39,63 @@ struct OutputBuffer { }; static const int sp_int = int(3); -static const uint _spec_const_op_const_56_ = 0u; static const bool _spec_const_op_6_ = true; -static const uint _spec_const_op_const_57_ = 1u; -static const uint _spec_const_op_const_56_1 = 0u; static const uint _spec_const_op_58_ = 1u; static const uint sp_uint = 20u; -static const uint _spec_const_op_const_56_2 = 0u; static const bool _spec_const_op_8_ = true; -static const uint _spec_const_op_const_57_1 = 1u; -static const uint _spec_const_op_const_56_3 = 0u; static const uint _spec_const_op_61_ = 1u; -static const int _spec_const_op_const_60_ = int(1); -static const int _spec_const_op_const_54_ = int(0); static const int _spec_const_op_9_ = int(1); -static const uint _spec_const_op_const_57_2 = 1u; -static const uint _spec_const_op_const_56_4 = 0u; static const uint _spec_const_op_10_ = 1u; static const int _spec_const_op_11_ = int(-3); static const int _spec_const_op_12_ = int(-4); -static const int _spec_const_op_const_62_ = int(2); static const int _spec_const_op_13_ = int(5); -static const int _spec_const_op_const_62_1 = int(2); static const int _spec_const_op_69_ = int(5); -static const int _spec_const_op_const_64_ = int(3); static const int _spec_const_op_14_ = int(2); -static const int _spec_const_op_const_65_ = int(4); static const int _spec_const_op_15_ = int(1); static const int sp_sint = int(4); -static const int _spec_const_op_const_62_2 = int(2); static const int _spec_const_op_17_ = int(8); -static const uint _spec_const_op_const_73_ = 2u; static const uint _spec_const_op_18_ = 40u; -static const int _spec_const_op_const_66_ = int(5); static const int _spec_const_op_19_ = int(1); -static const uint _spec_const_op_const_76_ = 5u; static const uint _spec_const_op_20_ = 8u; -static const int _spec_const_op_const_64_1 = int(3); static const int _spec_const_op_78_ = int(12); -static const int _spec_const_op_const_66_1 = int(5); static const int _spec_const_op_21_ = int(2); -static const int _spec_const_op_const_65_1 = int(4); static const int _spec_const_op_22_ = int(0); -static const uint _spec_const_op_const_81_ = 4u; static const uint _spec_const_op_23_ = 0u; -static const uint _spec_const_op_const_83_ = 10u; static const int _spec_const_op_24_ = int(0); -static const uint _spec_const_op_const_85_ = 20u; static const uint _spec_const_op_25_ = 0u; -static const uint _spec_const_op_const_57_3 = 1u; static const int _spec_const_op_26_ = int(8); -static const uint _spec_const_op_const_73_1 = 2u; static const uint _spec_const_op_27_ = 80u; -static const int _spec_const_op_const_64_2 = int(3); static const int _spec_const_op_28_ = int(0); -static const int _spec_const_op_const_90_ = int(256); static const int _spec_const_op_29_ = int(260); -static const uint _spec_const_op_const_92_ = 512u; static const uint _spec_const_op_30_ = 532u; static const bool _spec_const_op_31_ = true; -static const uint _spec_const_op_const_57_4 = 1u; -static const uint _spec_const_op_const_56_5 = 0u; static const uint _spec_const_op_94_ = 1u; static const bool _spec_const_op_32_ = true; -static const uint _spec_const_op_const_57_5 = 1u; -static const uint _spec_const_op_const_56_6 = 0u; static const uint _spec_const_op_96_ = 1u; static const bool _spec_const_op_33_ = true; -static const uint _spec_const_op_const_57_6 = 1u; -static const uint _spec_const_op_const_56_7 = 0u; static const uint _spec_const_op_98_ = 1u; static const bool _spec_const_op_34_ = false; -static const uint _spec_const_op_const_57_7 = 1u; -static const uint _spec_const_op_const_56_8 = 0u; static const uint _spec_const_op_100_ = 0u; static const bool _spec_const_op_35_ = false; -static const uint _spec_const_op_const_57_8 = 1u; -static const uint _spec_const_op_const_56_9 = 0u; static const uint _spec_const_op_102_ = 0u; static const bool _spec_const_op_36_ = false; -static const uint _spec_const_op_const_57_9 = 1u; -static const uint _spec_const_op_const_56_10 = 0u; static const uint _spec_const_op_104_ = 0u; static const bool _spec_const_op_37_ = true; -static const uint _spec_const_op_const_57_10 = 1u; -static const uint _spec_const_op_const_56_11 = 0u; static const uint _spec_const_op_106_ = 1u; static const bool _spec_const_op_38_ = true; -static const uint _spec_const_op_const_57_11 = 1u; -static const uint _spec_const_op_const_56_12 = 0u; static const uint _spec_const_op_108_ = 1u; static const bool _spec_const_op_39_ = true; -static const uint _spec_const_op_const_57_12 = 1u; -static const uint _spec_const_op_const_56_13 = 0u; static const uint _spec_const_op_110_ = 1u; static const bool _spec_const_op_40_ = false; -static const uint _spec_const_op_const_57_13 = 1u; -static const uint _spec_const_op_const_56_14 = 0u; static const uint _spec_const_op_112_ = 0u; static const bool c = true; -static const int _spec_const_op_const_77_ = int(13); -static const int _spec_const_op_const_84_ = int(17); static const int _spec_const_op_42_ = int(13); static const int a = int(1); -static const int _spec_const_op_const_84_1 = int(17); static const int _spec_const_op_44_ = int(1); -static const bool _spec_const_op_const_116_ = true; -static const int _spec_const_op_const_84_2 = int(17); static const int _spec_const_op_45_ = int(1); static const int b = int(0); static const bool _spec_const_op_118_ = true; -static const int _spec_const_op_const_77_1 = int(13); static const int _spec_const_op_119_ = int(14); -static const int _spec_const_op_const_84_3 = int(17); static const int _spec_const_op_120_ = int(0); static const int _spec_const_op_47_ = int(14); From f1c1b507a4596447cd6584c0ef7a6be73596c385 Mon Sep 17 00:00:00 2001 From: Nils Hasenbanck Date: Wed, 8 Oct 2025 17:06:26 +0200 Subject: [PATCH 3/3] (Naga) Handle implicit casting of operators in SPIR-V frontend We also now also try to select the best name for the override We also handle optimization of common conversion pattern to `As` instructions and with a proper, derived name. This makes the constants of the final shader of a GLSL compiled SPIR-V highly readable. --- naga/src/front/spv/mod.rs | 579 +++++++++++++++--- naga/tests/in/spv/spec-constant-op.comp | 84 ++- naga/tests/in/spv/spec-constant-op.spvasm | 457 +++++++++----- naga/tests/out/hlsl/spv-spec-constant-op.hlsl | 251 +++++--- 4 files changed, 1033 insertions(+), 338 deletions(-) diff --git a/naga/src/front/spv/mod.rs b/naga/src/front/spv/mod.rs index bff6d4baf02..bd2be6f5cf1 100644 --- a/naga/src/front/spv/mod.rs +++ b/naga/src/front/spv/mod.rs @@ -484,6 +484,8 @@ enum MergeBlockInformation { SwitchMerge, } +type OptimizationResult = Result, Option)>, Error>; + /// Fragments of Naga IR, to be assembled into `Statements` once data flow is /// resolved. /// @@ -6009,6 +6011,367 @@ impl> Frontend { .map_err(|error| error.into()) } + fn get_expr_scalar( + &self, + module: &crate::Module, + expr_handle: Handle, + ) -> Option { + match module.global_expressions[expr_handle] { + crate::Expression::Literal(ref literal) => Some(literal.scalar()), + crate::Expression::Constant(const_handle) => { + let ty = module.constants[const_handle].ty; + match module.types[ty].inner { + crate::TypeInner::Scalar(scalar) | crate::TypeInner::Vector { scalar, .. } => { + Some(scalar) + } + _ => None, + } + } + crate::Expression::Override(override_handle) => { + let ty = module.overrides[override_handle].ty; + match module.types[ty].inner { + crate::TypeInner::Scalar(scalar) | crate::TypeInner::Vector { scalar, .. } => { + Some(scalar) + } + _ => None, + } + } + crate::Expression::As { kind, convert, .. } => { + convert.map(|width| crate::Scalar { kind, width }) + } + // We don't have enough information to determine the scalar type. + _ => None, + } + } + + fn convert_expr_to_target_scalar( + &mut self, + module: &mut crate::Module, + global_expression_kind_tracker: &mut crate::proc::ExpressionKindTracker, + expr: &mut Handle, + target_scalar: crate::Scalar, + span: crate::Span, + ) -> Result<(), Error> { + *expr = self.eval_and_append_expression( + module, + global_expression_kind_tracker, + crate::Expression::As { + expr: *expr, + kind: target_scalar.kind, + convert: Some(target_scalar.width), + }, + span, + )?; + Ok(()) + } + + /// Apply implicit type conversions for binary operations to ensure SPIR-V -> WGSL compatibility. + #[allow(clippy::too_many_arguments)] + fn implicit_cast_operators( + &mut self, + module: &mut crate::Module, + global_expression_kind_tracker: &mut crate::proc::ExpressionKindTracker, + op: crate::BinaryOperator, + ty: Handle, + left_expr: &mut Handle, + right_expr: &mut Handle, + span: crate::Span, + ) -> Result<(), Error> { + match op { + crate::BinaryOperator::ShiftLeft | crate::BinaryOperator::ShiftRight => { + // Shift operations: convert right operand (shift amount) to u32. + if let Some(current_scalar) = self.get_expr_scalar(module, *right_expr) { + if current_scalar != crate::Scalar::U32 { + self.convert_expr_to_target_scalar( + module, + global_expression_kind_tracker, + right_expr, + crate::Scalar::U32, + span, + )?; + } + } + } + // Comparison operators: convert operands to the same type. + crate::BinaryOperator::Equal + | crate::BinaryOperator::NotEqual + | crate::BinaryOperator::Less + | crate::BinaryOperator::LessEqual + | crate::BinaryOperator::Greater + | crate::BinaryOperator::GreaterEqual => { + let left_scalar = self.get_expr_scalar(module, *left_expr); + let right_scalar = self.get_expr_scalar(module, *right_expr); + + if let (Some(left), Some(right)) = (left_scalar, right_scalar) { + if left != right { + let target_scalar = if left.kind != right.kind { + // Different signedness: use unsigned. + crate::Scalar { + kind: crate::ScalarKind::Uint, + width: left.width.max(right.width), + } + } else { + // Same signedness: use the wider type. + if left.width > right.width { + left + } else { + right + } + }; + + if left != target_scalar { + self.convert_expr_to_target_scalar( + module, + global_expression_kind_tracker, + left_expr, + target_scalar, + span, + )?; + } + + if right != target_scalar { + self.convert_expr_to_target_scalar( + module, + global_expression_kind_tracker, + right_expr, + target_scalar, + span, + )?; + } + } + } + } + // Logical operators: no change needed. + crate::BinaryOperator::LogicalAnd | crate::BinaryOperator::LogicalOr => {} + // All other operators: convert operands to match the result type. + _ => { + if let crate::TypeInner::Scalar(target_scalar) + | crate::TypeInner::Vector { + scalar: target_scalar, + .. + } = module.types[ty].inner + { + if let Some(left_scalar) = self.get_expr_scalar(module, *left_expr) { + if left_scalar != target_scalar { + self.convert_expr_to_target_scalar( + module, + global_expression_kind_tracker, + left_expr, + target_scalar, + span, + )?; + } + } + + if let Some(right_scalar) = self.get_expr_scalar(module, *right_expr) { + if right_scalar != target_scalar { + self.convert_expr_to_target_scalar( + module, + global_expression_kind_tracker, + right_expr, + target_scalar, + span, + )?; + } + } + } + } + } + + Ok(()) + } + + fn is_constant_zero( + &self, + module: &crate::Module, + const_id: spirv::Word, + ) -> Result { + let lookup = self.lookup_constant.lookup(const_id)?; + match lookup.inner { + Constant::Constant(const_handle) => { + let init = module.constants[const_handle].init; + match module.global_expressions[init] { + crate::Expression::Literal(literal) => Ok(match literal { + crate::Literal::I32(v) => v == 0, + crate::Literal::U32(v) => v == 0, + crate::Literal::I64(v) => v == 0, + crate::Literal::U64(v) => v == 0, + _ => false, + }), + _ => Ok(false), + } + } + Constant::Override(_) => Ok(false), + } + } + + fn is_constant_one( + &self, + module: &crate::Module, + const_id: spirv::Word, + ) -> Result { + let lookup = self.lookup_constant.lookup(const_id)?; + match lookup.inner { + Constant::Constant(const_handle) => { + let init = module.constants[const_handle].init; + match module.global_expressions[init] { + crate::Expression::Literal(literal) => Ok(match literal { + crate::Literal::I32(v) => v == 1, + crate::Literal::U32(v) => v == 1, + crate::Literal::I64(v) => v == 1, + crate::Literal::U64(v) => v == 1, + _ => false, + }), + _ => Ok(false), + } + } + Constant::Override(_) => Ok(false), + } + } + + fn get_constant_name(&self, module: &crate::Module, const_id: spirv::Word) -> Option { + let lookup = self.lookup_constant.lookup(const_id).ok()?; + match lookup.inner { + Constant::Override(override_handle) => module.overrides[override_handle].name.clone(), + Constant::Constant(_) => None, + } + } + + fn format_target_type(&self, module: &crate::Module, ty: Handle) -> String { + match module.types[ty].inner { + crate::TypeInner::Scalar(scalar) | crate::TypeInner::Vector { scalar, .. } => { + match scalar.kind { + crate::ScalarKind::Sint => String::from("int"), + crate::ScalarKind::Uint => String::from("uint"), + crate::ScalarKind::Float => String::from("float"), + crate::ScalarKind::Bool => String::from("bool"), + crate::ScalarKind::AbstractInt => String::from("abstract_int"), + crate::ScalarKind::AbstractFloat => String::from("abstract_float"), + } + } + _ => String::from("unknown"), + } + } + + /// Try to optimize common SPIR-V type conversion patterns to simpler `As` expressions. + /// + /// Example: IAdd %a_value %zero + #[allow(clippy::too_many_arguments)] + fn try_optimize_type_conversion_pattern( + &mut self, + module: &mut crate::Module, + global_expression_kind_tracker: &mut crate::proc::ExpressionKindTracker, + opcode: spirv::Op, + ty: Handle, + left_id: spirv::Word, + right_id: spirv::Word, + span: crate::Span, + ) -> OptimizationResult { + if matches!(opcode, spirv::Op::IAdd | spirv::Op::BitwiseOr) { + let left_is_zero = self.is_constant_zero(module, left_id)?; + let right_is_zero = self.is_constant_zero(module, right_id)?; + + let (value_id, source_name) = if left_is_zero && !right_is_zero { + (right_id, self.get_constant_name(module, right_id)) + } else if right_is_zero && !left_is_zero { + (left_id, self.get_constant_name(module, left_id)) + } else { + return Ok(None); + }; + + let scalar = match module.types[ty].inner { + crate::TypeInner::Scalar(scalar) + | crate::TypeInner::Vector { scalar, .. } + | crate::TypeInner::Matrix { scalar, .. } => scalar, + _ => return Ok(None), + }; + + let value_expr_inner = self.lookup_constant.lookup(value_id)?.inner.to_expr(); + let value_expr = self.eval_and_append_expression( + module, + global_expression_kind_tracker, + value_expr_inner, + span, + )?; + + let as_expr = self.eval_and_append_expression( + module, + global_expression_kind_tracker, + crate::Expression::As { + expr: value_expr, + kind: scalar.kind, + convert: Some(scalar.width), + }, + span, + )?; + + let derived_name = source_name.map(|name| { + let target_type = self.format_target_type(module, ty); + format!("{name}_as_{target_type}") + }); + + return Ok(Some((as_expr, derived_name))); + } + + Ok(None) + } + + /// Try to optimize `select` pattern used for bool to int/uint conversion to simpler `As` expressions. + /// + /// Example: Select %bool_value %one %zero + #[allow(clippy::too_many_arguments)] + fn try_optimize_select_conversion( + &mut self, + module: &mut crate::Module, + global_expression_kind_tracker: &mut crate::proc::ExpressionKindTracker, + ty: Handle, + condition_id: spirv::Word, + o1_id: spirv::Word, + o2_id: spirv::Word, + span: crate::Span, + ) -> OptimizationResult { + let o1_is_one = self.is_constant_one(module, o1_id)?; + let o2_is_zero = self.is_constant_zero(module, o2_id)?; + + if !o1_is_one || !o2_is_zero { + return Ok(None); + } + + let scalar = match module.types[ty].inner { + crate::TypeInner::Scalar(scalar) + | crate::TypeInner::Vector { scalar, .. } + | crate::TypeInner::Matrix { scalar, .. } => scalar, + _ => return Ok(None), + }; + + let condition_expr_inner = self.lookup_constant.lookup(condition_id)?.inner.to_expr(); + let condition_expr = self.eval_and_append_expression( + module, + global_expression_kind_tracker, + condition_expr_inner, + span, + )?; + + let as_expr = self.eval_and_append_expression( + module, + global_expression_kind_tracker, + crate::Expression::As { + expr: condition_expr, + kind: scalar.kind, + convert: Some(scalar.width), + }, + span, + )?; + + let source_name = self.get_constant_name(module, condition_id); + let derived_name = source_name.map(|name| { + let target_type = self.format_target_type(module, ty); + format!("{name}_as_{target_type}") + }); + + Ok(Some((as_expr, derived_name))) + } + fn parse_spec_constant_op( &mut self, inst: Instruction, @@ -6034,10 +6397,17 @@ impl> Frontend { Op::SpecConstantOp, ))?; + let mut derived_name: Option = None; + let init = match opcode { Op::SConvert | Op::UConvert | Op::FConvert => { let value_id = self.next()?; + if let Some(source_name) = self.get_constant_name(module, value_id) { + let target_type = self.format_target_type(module, ty); + derived_name = Some(format!("{source_name}_as_{target_type}")); + } + let scalar = match module.types[ty].inner { crate::TypeInner::Scalar(scalar) | crate::TypeInner::Vector { scalar, .. } @@ -6124,59 +6494,88 @@ impl> Frontend { let left_id = self.next()?; let right_id = self.next()?; - let op = match opcode { - Op::IAdd => crate::BinaryOperator::Add, - Op::ISub => crate::BinaryOperator::Subtract, - Op::IMul => crate::BinaryOperator::Multiply, - Op::UDiv | Op::SDiv => crate::BinaryOperator::Divide, - Op::SRem | Op::UMod => crate::BinaryOperator::Modulo, - Op::BitwiseOr => crate::BinaryOperator::InclusiveOr, - Op::BitwiseXor => crate::BinaryOperator::ExclusiveOr, - Op::BitwiseAnd => crate::BinaryOperator::And, - Op::ShiftLeftLogical => crate::BinaryOperator::ShiftLeft, - Op::ShiftRightLogical | Op::ShiftRightArithmetic => { - crate::BinaryOperator::ShiftRight - } - Op::LogicalOr => crate::BinaryOperator::LogicalOr, - Op::LogicalAnd => crate::BinaryOperator::LogicalAnd, - Op::LogicalEqual => crate::BinaryOperator::Equal, - Op::LogicalNotEqual => crate::BinaryOperator::NotEqual, - Op::IEqual => crate::BinaryOperator::Equal, - Op::INotEqual => crate::BinaryOperator::NotEqual, - Op::ULessThan | Op::SLessThan => crate::BinaryOperator::Less, - Op::UGreaterThan | Op::SGreaterThan => crate::BinaryOperator::Greater, - Op::ULessThanEqual | Op::SLessThanEqual => crate::BinaryOperator::LessEqual, - Op::UGreaterThanEqual | Op::SGreaterThanEqual => { - crate::BinaryOperator::GreaterEqual - } - _ => unreachable!(), - }; - - let left_expr_inner = self.lookup_constant.lookup(left_id)?.inner.to_expr(); - let right_expr_inner = self.lookup_constant.lookup(right_id)?.inner.to_expr(); - let left_expr = self.eval_and_append_expression( - module, - global_expression_kind_tracker, - left_expr_inner, - span, - )?; - let right_expr = self.eval_and_append_expression( + match self.try_optimize_type_conversion_pattern( module, global_expression_kind_tracker, - right_expr_inner, + opcode, + ty, + left_id, + right_id, span, - )?; + )? { + Some((optimized_expr, name)) => { + derived_name = name; + optimized_expr + } + None => { + let op = match opcode { + Op::IAdd => crate::BinaryOperator::Add, + Op::ISub => crate::BinaryOperator::Subtract, + Op::IMul => crate::BinaryOperator::Multiply, + Op::UDiv | Op::SDiv => crate::BinaryOperator::Divide, + Op::SRem | Op::UMod => crate::BinaryOperator::Modulo, + Op::BitwiseOr => crate::BinaryOperator::InclusiveOr, + Op::BitwiseXor => crate::BinaryOperator::ExclusiveOr, + Op::BitwiseAnd => crate::BinaryOperator::And, + Op::ShiftLeftLogical => crate::BinaryOperator::ShiftLeft, + Op::ShiftRightLogical | Op::ShiftRightArithmetic => { + crate::BinaryOperator::ShiftRight + } + Op::LogicalOr => crate::BinaryOperator::LogicalOr, + Op::LogicalAnd => crate::BinaryOperator::LogicalAnd, + Op::LogicalEqual => crate::BinaryOperator::Equal, + Op::LogicalNotEqual => crate::BinaryOperator::NotEqual, + Op::IEqual => crate::BinaryOperator::Equal, + Op::INotEqual => crate::BinaryOperator::NotEqual, + Op::ULessThan | Op::SLessThan => crate::BinaryOperator::Less, + Op::UGreaterThan | Op::SGreaterThan => crate::BinaryOperator::Greater, + Op::ULessThanEqual | Op::SLessThanEqual => { + crate::BinaryOperator::LessEqual + } + Op::UGreaterThanEqual | Op::SGreaterThanEqual => { + crate::BinaryOperator::GreaterEqual + } + _ => unreachable!(), + }; - self.eval_and_append_expression( - module, - global_expression_kind_tracker, - crate::Expression::Binary { - op, - left: left_expr, - right: right_expr, - }, - span, - )? + let left_expr_inner = self.lookup_constant.lookup(left_id)?.inner.to_expr(); + let right_expr_inner = + self.lookup_constant.lookup(right_id)?.inner.to_expr(); + let mut left_expr = self.eval_and_append_expression( + module, + global_expression_kind_tracker, + left_expr_inner, + span, + )?; + let mut right_expr = self.eval_and_append_expression( + module, + global_expression_kind_tracker, + right_expr_inner, + span, + )?; + + self.implicit_cast_operators( + module, + global_expression_kind_tracker, + op, + ty, + &mut left_expr, + &mut right_expr, + span, + )?; + + self.eval_and_append_expression( + module, + global_expression_kind_tracker, + crate::Expression::Binary { + op, + left: left_expr, + right: right_expr, + }, + span, + )? + } + } } Op::SMod => { @@ -6286,38 +6685,54 @@ impl> Frontend { let o1_id = self.next()?; let o2_id = self.next()?; - let cond_expr = self.lookup_constant.lookup(condition_id)?.inner.to_expr(); - let o1_expr = self.lookup_constant.lookup(o1_id)?.inner.to_expr(); - let o2_expr = self.lookup_constant.lookup(o2_id)?.inner.to_expr(); - let cond = self.eval_and_append_expression( - module, - global_expression_kind_tracker, - cond_expr, - span, - )?; - let o1 = self.eval_and_append_expression( - module, - global_expression_kind_tracker, - o1_expr, - span, - )?; - let o2 = self.eval_and_append_expression( + match self.try_optimize_select_conversion( module, global_expression_kind_tracker, - o2_expr, + ty, + condition_id, + o1_id, + o2_id, span, - )?; + )? { + Some((optimized_expr, name)) => { + derived_name = name; + optimized_expr + } + None => { + let cond_expr = self.lookup_constant.lookup(condition_id)?.inner.to_expr(); + let o1_expr = self.lookup_constant.lookup(o1_id)?.inner.to_expr(); + let o2_expr = self.lookup_constant.lookup(o2_id)?.inner.to_expr(); + let cond = self.eval_and_append_expression( + module, + global_expression_kind_tracker, + cond_expr, + span, + )?; + let o1 = self.eval_and_append_expression( + module, + global_expression_kind_tracker, + o1_expr, + span, + )?; + let o2 = self.eval_and_append_expression( + module, + global_expression_kind_tracker, + o2_expr, + span, + )?; - self.eval_and_append_expression( - module, - global_expression_kind_tracker, - crate::Expression::Select { - condition: cond, - accept: o1, - reject: o2, - }, - span, - )? + self.eval_and_append_expression( + module, + global_expression_kind_tracker, + crate::Expression::Select { + condition: cond, + accept: o1, + reject: o2, + }, + span, + )? + } + } } Op::VectorShuffle | Op::CompositeExtract | Op::CompositeInsert | Op::QuantizeToF16 => { @@ -6329,11 +6744,13 @@ impl> Frontend { _ => return Err(Error::InvalidSpecConstantOp(opcode)), }; - // IMPORTANT: Overrides must have either a name or an id to be processed correctly - // by process_overrides(). OpSpecConstantOp results don't have a SpecId (they're - // not user-overridable), so we assign them a name based on the result_id. + let decor = self.future_decor.remove(&result_id).unwrap_or_default(); + let name = decor + .name + .or(derived_name) + .or_else(|| Some(format!("_spec_const_op_{result_id}"))); let op_override = crate::Override { - name: Some(format!("_spec_const_op_{result_id}")), + name, id: None, ty, init: Some(init), diff --git a/naga/tests/in/spv/spec-constant-op.comp b/naga/tests/in/spv/spec-constant-op.comp index 6a82726c326..463a0b07248 100644 --- a/naga/tests/in/spv/spec-constant-op.comp +++ b/naga/tests/in/spv/spec-constant-op.comp @@ -5,10 +5,10 @@ // Based on this test of glslang: https://github.com/KhronosGroup/glslang/blob/main/Test/spv.specConstantOperations.vert #version 450 -layout(constant_id = 0) const float sp_float = 3.1415926; -layout(constant_id = 1) const int sp_int = 10; -layout(constant_id = 2) const uint sp_uint = 100; -layout(constant_id = 3) const int sp_sint = -10; +layout(constant_id = 0) const float sp_float = 0.0; +layout(constant_id = 1) const int sp_int = 0; +layout(constant_id = 2) const uint sp_uint = 0; +layout(constant_id = 3) const int sp_sint = 0; // // Scalars @@ -20,6 +20,10 @@ const bool bool_from_uint = bool(sp_uint); // bool(20) = true const int int_from_bool = int(bool_from_int); // int(true) = 1 const uint uint_from_bool = uint(bool_from_int); // uint(true) = 1 +// uint <-> int conversion +const uint sp_uint_from_sint = uint(sp_sint); // uint(4) = 4 +const int sp_sint_from_uint = int(sp_uint); // int(20) = 20 + // Negate and Not const int negate_int = -sp_int; // -3 = -3 const int not_int = ~sp_int; // ~3 = -4 @@ -29,6 +33,12 @@ const int sp_int_add_two = sp_int + 2; // 3 + 2 = 5 const int sp_int_add_two_sub_three = sp_int + 2 - 3; // 3 + 2 - 3 = 2 const int sp_int_add_two_sub_four = sp_int_add_two - 4; // 5 - 4 = 1 +// Mixed-type arithmetic operations +const uint mixed_sint_add_uint = sp_sint + sp_uint; // 4 + 20 = 24 +const uint mixed_uint_sub_sint = sp_uint - sp_sint; // 20 - 4 = 16 +const uint mixed_spec_sint_add_const_uint = sp_sint + 10u; // 4 + 10 = 14 +const uint mixed_const_sint_mul_spec_uint = 3 * sp_uint; // 3 * 20 = 60 + // Mul, Div const int sp_sint_mul_two = sp_sint * 2; // 4 * 2 = 8 const uint sp_uint_mul_two = sp_uint * 2; // 20 * 2 = 40 @@ -40,17 +50,30 @@ const int sp_sint_mul_three_div_five = sp_sint * 3 / 5; // 4 * 3 / 5 = 2 const int sp_sint_rem_four = sp_sint % 4; // 4 % 4 = 0 const uint sp_uint_rem_four = sp_uint % 4; // 20 % 4 = 0 -// Shift (the shift value must be an unsigned integer) -const int sp_sint_shift_right_arithmetic = sp_sint >> 10u; // 4 >> 10 = 0 +// Mixed-type modulo operations +const uint mixed_sint_mod_uint = sp_sint % sp_uint; // 4 % 20 = 4 +const uint mixed_uint_mod_sint = sp_uint % sp_sint; // 20 % 4 = 0 +const int mixed_sint_smod_const_int = sp_sint % 3; // 4 % 3 = 1 +const uint mixed_uint_mod_const_uint = sp_uint % 7u; // 20 % 7 = 6 + +// Shift +const int sp_sint_shift_right_arithmetic = sp_sint >> 10; // 4 >> 10 = 0 const uint sp_uint_shift_right_arithmetic = sp_uint >> 20u; // 20 >> 20 = 0 const int sp_sint_shift_left = sp_sint << 1u; // 4 << 1 = 8 -const uint sp_uint_shift_left = sp_uint << 2u; // 20 << 2 = 80 +const uint sp_uint_shift_left = sp_uint << 2; // 20 << 2 = 80 // Bitwise And, Or, Xor const int sp_sint_and_3 = sp_sint & 3; // 4 & 3 = 0 const int sp_sint_or_256 = sp_sint | 0x100; // 4 | 256 = 260 const uint sp_uint_xor_512 = sp_uint ^ 0x200; // 20 ^ 512 = 532 +// Mixed-type bitwise operations +const uint mixed_sint_and_uint = sp_sint & sp_uint; // 4 & 20 = 4 +const uint mixed_uint_or_sint = sp_uint | sp_sint; // 20 | 4 = 20 +const uint mixed_sint_xor_uint = sp_sint ^ sp_uint; // 4 ^ 20 = 16 +const uint mixed_spec_uint_and_const_sint = sp_uint & 15; // 20 & 15 = 4 +const uint mixed_const_uint_or_spec_sint = 0x80u | sp_sint; // 128 | 4 = 132 + // Scalar comparison const bool sp_int_lt_sp_sint = sp_int < sp_sint; // 3 < 4 = true const bool sp_int_le_sp_sint = sp_int <= sp_sint; // 3 <= 4 = true @@ -59,6 +82,11 @@ const bool sp_uint_not_equal_sp_uint = sp_uint != sp_uint; // 20 != 20 = fa const bool sp_int_gt_sp_sint = sp_int > sp_sint; // 3 > 4 = false const bool sp_int_ge_sp_sint = sp_int >= sp_sint; // 3 >= 4 = false +// Mixed-type comparisons +const bool mixed_sint_lt_uint = sp_sint < sp_uint; // 4 < 20 = true +const bool mixed_uint_ge_sint = sp_uint >= sp_sint; // 20 >= 4 = true +const bool mixed_sint_eq_uint = sp_sint == sp_uint; // 4 == 20 = false + // Logical operations const bool logical_and = bool_from_int && bool_from_uint; // true && true = true const bool logical_or = bool_from_int || bool_from_uint; // true || true = true @@ -66,9 +94,9 @@ const bool logical_equal = bool_from_int == bool_from_uint; // true == true const bool logical_not_equal = bool_from_int != bool_from_uint; // true != true = false // ternary -layout(constant_id = 4) const int a = 4; -layout(constant_id = 5) const int b = 6; -layout(constant_id = 6) const bool c = true; +layout(constant_id = 4) const int a = 0; +layout(constant_id = 5) const int b = 0; +layout(constant_id = 6) const bool c = false; const int t1 = c ? 13 : 17; // true ? 13 : 17 = 13 const int t2 = c ? a : 17; // true ? 1 : 17 = 1 const int t3 = true ? a : 17; // true ? 1 : 17 = 1 @@ -79,11 +107,17 @@ layout(set = 0, binding = 0) buffer OutputBuffer { uint bool_from_uint_val; int int_from_bool_val; uint uint_from_bool_val; + uint sp_uint_from_sint_val; + int sp_sint_from_uint_val; int negate_int_val; int not_int_val; int sp_int_add_two_val; int sp_int_add_two_sub_three_val; int sp_int_add_two_sub_four_val; + uint mixed_sint_add_uint_val; + uint mixed_uint_sub_sint_val; + uint mixed_spec_sint_add_const_uint_val; + uint mixed_const_sint_mul_spec_uint_val; int sp_sint_mul_two_val; uint sp_uint_mul_two_val; int sp_sint_mul_two_div_five_val; @@ -91,6 +125,10 @@ layout(set = 0, binding = 0) buffer OutputBuffer { int sp_sint_mul_three_div_five_val; int sp_sint_rem_four_val; uint sp_uint_rem_four_val; + uint mixed_sint_mod_uint_val; + uint mixed_uint_mod_sint_val; + int mixed_sint_smod_const_int_val; + uint mixed_uint_mod_const_uint_val; int sp_sint_shift_right_arithmetic_val; uint sp_uint_shift_right_arithmetic_val; int sp_sint_shift_left_val; @@ -98,12 +136,20 @@ layout(set = 0, binding = 0) buffer OutputBuffer { int sp_sint_and_3_val; int sp_sint_or_256_val; uint sp_uint_xor_512_val; + uint mixed_sint_and_uint_val; + uint mixed_uint_or_sint_val; + uint mixed_sint_xor_uint_val; + uint mixed_spec_uint_and_const_sint_val; + uint mixed_const_uint_or_spec_sint_val; uint sp_int_lt_sp_sint_val; uint sp_int_le_sp_sint_val; uint sp_uint_equal_sp_uint_val; uint sp_uint_not_equal_sp_uint_val; uint sp_int_gt_sp_sint_val; uint sp_int_ge_sp_sint_val; + uint mixed_sint_lt_uint_val; + uint mixed_uint_ge_sint_val; + uint mixed_sint_eq_uint_val; uint logical_and_val; uint logical_or_val; uint logical_equal_val; @@ -119,11 +165,17 @@ void main() { output_buffer.bool_from_uint_val = uint(bool_from_uint); output_buffer.int_from_bool_val = int_from_bool; output_buffer.uint_from_bool_val = uint_from_bool; + output_buffer.sp_uint_from_sint_val = sp_uint_from_sint; + output_buffer.sp_sint_from_uint_val = sp_sint_from_uint; output_buffer.negate_int_val = negate_int; output_buffer.not_int_val = not_int; output_buffer.sp_int_add_two_val = sp_int_add_two; output_buffer.sp_int_add_two_sub_three_val = sp_int_add_two_sub_three; output_buffer.sp_int_add_two_sub_four_val = sp_int_add_two_sub_four; + output_buffer.mixed_sint_add_uint_val = mixed_sint_add_uint; + output_buffer.mixed_uint_sub_sint_val = mixed_uint_sub_sint; + output_buffer.mixed_spec_sint_add_const_uint_val = mixed_spec_sint_add_const_uint; + output_buffer.mixed_const_sint_mul_spec_uint_val = mixed_const_sint_mul_spec_uint; output_buffer.sp_sint_mul_two_val = sp_sint_mul_two; output_buffer.sp_uint_mul_two_val = sp_uint_mul_two; output_buffer.sp_sint_mul_two_div_five_val = sp_sint_mul_two_div_five; @@ -131,6 +183,10 @@ void main() { output_buffer.sp_sint_mul_three_div_five_val = sp_sint_mul_three_div_five; output_buffer.sp_sint_rem_four_val = sp_sint_rem_four; output_buffer.sp_uint_rem_four_val = sp_uint_rem_four; + output_buffer.mixed_sint_mod_uint_val = mixed_sint_mod_uint; + output_buffer.mixed_uint_mod_sint_val = mixed_uint_mod_sint; + output_buffer.mixed_sint_smod_const_int_val = mixed_sint_smod_const_int; + output_buffer.mixed_uint_mod_const_uint_val = mixed_uint_mod_const_uint; output_buffer.sp_sint_shift_right_arithmetic_val = sp_sint_shift_right_arithmetic; output_buffer.sp_uint_shift_right_arithmetic_val = sp_uint_shift_right_arithmetic; output_buffer.sp_sint_shift_left_val = sp_sint_shift_left; @@ -138,12 +194,20 @@ void main() { output_buffer.sp_sint_and_3_val = sp_sint_and_3; output_buffer.sp_sint_or_256_val = sp_sint_or_256; output_buffer.sp_uint_xor_512_val = sp_uint_xor_512; + output_buffer.mixed_sint_and_uint_val = mixed_sint_and_uint; + output_buffer.mixed_uint_or_sint_val = mixed_uint_or_sint; + output_buffer.mixed_sint_xor_uint_val = mixed_sint_xor_uint; + output_buffer.mixed_spec_uint_and_const_sint_val = mixed_spec_uint_and_const_sint; + output_buffer.mixed_const_uint_or_spec_sint_val = mixed_const_uint_or_spec_sint; output_buffer.sp_int_lt_sp_sint_val = uint(sp_int_lt_sp_sint); output_buffer.sp_int_le_sp_sint_val = uint(sp_int_le_sp_sint); output_buffer.sp_uint_equal_sp_uint_val = uint(sp_uint_equal_sp_uint); output_buffer.sp_uint_not_equal_sp_uint_val = uint(sp_uint_not_equal_sp_uint); output_buffer.sp_int_gt_sp_sint_val = uint(sp_int_gt_sp_sint); output_buffer.sp_int_ge_sp_sint_val = uint(sp_int_ge_sp_sint); + output_buffer.mixed_sint_lt_uint_val = uint(mixed_sint_lt_uint); + output_buffer.mixed_uint_ge_sint_val = uint(mixed_uint_ge_sint); + output_buffer.mixed_sint_eq_uint_val = uint(mixed_sint_eq_uint); output_buffer.logical_and_val = uint(logical_and); output_buffer.logical_or_val = uint(logical_or); output_buffer.logical_equal_val = uint(logical_equal); diff --git a/naga/tests/in/spv/spec-constant-op.spvasm b/naga/tests/in/spv/spec-constant-op.spvasm index c6f19e5f6b0..f0b8020b321 100644 --- a/naga/tests/in/spv/spec-constant-op.spvasm +++ b/naga/tests/in/spv/spec-constant-op.spvasm @@ -1,7 +1,7 @@ ; SPIR-V ; Version: 1.0 ; Generator: Khronos Glslang Reference Front End; 11 -; Bound: 160 +; Bound: 233 ; Schema: 0 OpCapability Shader %1 = OpExtInstImport "GLSL.std.450" @@ -15,39 +15,57 @@ OpMemberName %OutputBuffer 1 "bool_from_uint_val" OpMemberName %OutputBuffer 2 "int_from_bool_val" OpMemberName %OutputBuffer 3 "uint_from_bool_val" - OpMemberName %OutputBuffer 4 "negate_int_val" - OpMemberName %OutputBuffer 5 "not_int_val" - OpMemberName %OutputBuffer 6 "sp_int_add_two_val" - OpMemberName %OutputBuffer 7 "sp_int_add_two_sub_three_val" - OpMemberName %OutputBuffer 8 "sp_int_add_two_sub_four_val" - OpMemberName %OutputBuffer 9 "sp_sint_mul_two_val" - OpMemberName %OutputBuffer 10 "sp_uint_mul_two_val" - OpMemberName %OutputBuffer 11 "sp_sint_mul_two_div_five_val" - OpMemberName %OutputBuffer 12 "sp_uint_mul_two_div_five_val" - OpMemberName %OutputBuffer 13 "sp_sint_mul_three_div_five_val" - OpMemberName %OutputBuffer 14 "sp_sint_rem_four_val" - OpMemberName %OutputBuffer 15 "sp_uint_rem_four_val" - OpMemberName %OutputBuffer 16 "sp_sint_shift_right_arithmetic_val" - OpMemberName %OutputBuffer 17 "sp_uint_shift_right_arithmetic_val" - OpMemberName %OutputBuffer 18 "sp_sint_shift_left_val" - OpMemberName %OutputBuffer 19 "sp_uint_shift_left_val" - OpMemberName %OutputBuffer 20 "sp_sint_and_3_val" - OpMemberName %OutputBuffer 21 "sp_sint_or_256_val" - OpMemberName %OutputBuffer 22 "sp_uint_xor_512_val" - OpMemberName %OutputBuffer 23 "sp_int_lt_sp_sint_val" - OpMemberName %OutputBuffer 24 "sp_int_le_sp_sint_val" - OpMemberName %OutputBuffer 25 "sp_uint_equal_sp_uint_val" - OpMemberName %OutputBuffer 26 "sp_uint_not_equal_sp_uint_val" - OpMemberName %OutputBuffer 27 "sp_int_gt_sp_sint_val" - OpMemberName %OutputBuffer 28 "sp_int_ge_sp_sint_val" - OpMemberName %OutputBuffer 29 "logical_and_val" - OpMemberName %OutputBuffer 30 "logical_or_val" - OpMemberName %OutputBuffer 31 "logical_equal_val" - OpMemberName %OutputBuffer 32 "logical_not_equal_val" - OpMemberName %OutputBuffer 33 "t1_val" - OpMemberName %OutputBuffer 34 "t2_val" - OpMemberName %OutputBuffer 35 "t3_val" - OpMemberName %OutputBuffer 36 "t4_val" + OpMemberName %OutputBuffer 4 "sp_uint_from_sint_val" + OpMemberName %OutputBuffer 5 "sp_sint_from_uint_val" + OpMemberName %OutputBuffer 6 "negate_int_val" + OpMemberName %OutputBuffer 7 "not_int_val" + OpMemberName %OutputBuffer 8 "sp_int_add_two_val" + OpMemberName %OutputBuffer 9 "sp_int_add_two_sub_three_val" + OpMemberName %OutputBuffer 10 "sp_int_add_two_sub_four_val" + OpMemberName %OutputBuffer 11 "mixed_sint_add_uint_val" + OpMemberName %OutputBuffer 12 "mixed_uint_sub_sint_val" + OpMemberName %OutputBuffer 13 "mixed_spec_sint_add_const_uint_val" + OpMemberName %OutputBuffer 14 "mixed_const_sint_mul_spec_uint_val" + OpMemberName %OutputBuffer 15 "sp_sint_mul_two_val" + OpMemberName %OutputBuffer 16 "sp_uint_mul_two_val" + OpMemberName %OutputBuffer 17 "sp_sint_mul_two_div_five_val" + OpMemberName %OutputBuffer 18 "sp_uint_mul_two_div_five_val" + OpMemberName %OutputBuffer 19 "sp_sint_mul_three_div_five_val" + OpMemberName %OutputBuffer 20 "sp_sint_rem_four_val" + OpMemberName %OutputBuffer 21 "sp_uint_rem_four_val" + OpMemberName %OutputBuffer 22 "mixed_sint_mod_uint_val" + OpMemberName %OutputBuffer 23 "mixed_uint_mod_sint_val" + OpMemberName %OutputBuffer 24 "mixed_sint_smod_const_int_val" + OpMemberName %OutputBuffer 25 "mixed_uint_mod_const_uint_val" + OpMemberName %OutputBuffer 26 "sp_sint_shift_right_arithmetic_val" + OpMemberName %OutputBuffer 27 "sp_uint_shift_right_arithmetic_val" + OpMemberName %OutputBuffer 28 "sp_sint_shift_left_val" + OpMemberName %OutputBuffer 29 "sp_uint_shift_left_val" + OpMemberName %OutputBuffer 30 "sp_sint_and_3_val" + OpMemberName %OutputBuffer 31 "sp_sint_or_256_val" + OpMemberName %OutputBuffer 32 "sp_uint_xor_512_val" + OpMemberName %OutputBuffer 33 "mixed_sint_and_uint_val" + OpMemberName %OutputBuffer 34 "mixed_uint_or_sint_val" + OpMemberName %OutputBuffer 35 "mixed_sint_xor_uint_val" + OpMemberName %OutputBuffer 36 "mixed_spec_uint_and_const_sint_val" + OpMemberName %OutputBuffer 37 "mixed_const_uint_or_spec_sint_val" + OpMemberName %OutputBuffer 38 "sp_int_lt_sp_sint_val" + OpMemberName %OutputBuffer 39 "sp_int_le_sp_sint_val" + OpMemberName %OutputBuffer 40 "sp_uint_equal_sp_uint_val" + OpMemberName %OutputBuffer 41 "sp_uint_not_equal_sp_uint_val" + OpMemberName %OutputBuffer 42 "sp_int_gt_sp_sint_val" + OpMemberName %OutputBuffer 43 "sp_int_ge_sp_sint_val" + OpMemberName %OutputBuffer 44 "mixed_sint_lt_uint_val" + OpMemberName %OutputBuffer 45 "mixed_uint_ge_sint_val" + OpMemberName %OutputBuffer 46 "mixed_sint_eq_uint_val" + OpMemberName %OutputBuffer 47 "logical_and_val" + OpMemberName %OutputBuffer 48 "logical_or_val" + OpMemberName %OutputBuffer 49 "logical_equal_val" + OpMemberName %OutputBuffer 50 "logical_not_equal_val" + OpMemberName %OutputBuffer 51 "t1_val" + OpMemberName %OutputBuffer 52 "t2_val" + OpMemberName %OutputBuffer 53 "t3_val" + OpMemberName %OutputBuffer 54 "t4_val" OpName %output_buffer "output_buffer" OpName %sp_int "sp_int" OpName %bool_from_int "bool_from_int" @@ -55,12 +73,18 @@ OpName %bool_from_uint "bool_from_uint" OpName %int_from_bool "int_from_bool" OpName %uint_from_bool "uint_from_bool" + OpName %sp_sint "sp_sint" + OpName %sp_uint_from_sint "sp_uint_from_sint" + OpName %sp_sint_from_uint "sp_sint_from_uint" OpName %negate_int "negate_int" OpName %not_int "not_int" OpName %sp_int_add_two "sp_int_add_two" OpName %sp_int_add_two_sub_three "sp_int_add_two_sub_three" OpName %sp_int_add_two_sub_four "sp_int_add_two_sub_four" - OpName %sp_sint "sp_sint" + OpName %mixed_sint_add_uint "mixed_sint_add_uint" + OpName %mixed_uint_sub_sint "mixed_uint_sub_sint" + OpName %mixed_spec_sint_add_const_uint "mixed_spec_sint_add_const_uint" + OpName %mixed_const_sint_mul_spec_uint "mixed_const_sint_mul_spec_uint" OpName %sp_sint_mul_two "sp_sint_mul_two" OpName %sp_uint_mul_two "sp_uint_mul_two" OpName %sp_sint_mul_two_div_five "sp_sint_mul_two_div_five" @@ -68,6 +92,10 @@ OpName %sp_sint_mul_three_div_five "sp_sint_mul_three_div_five" OpName %sp_sint_rem_four "sp_sint_rem_four" OpName %sp_uint_rem_four "sp_uint_rem_four" + OpName %mixed_sint_mod_uint "mixed_sint_mod_uint" + OpName %mixed_uint_mod_sint "mixed_uint_mod_sint" + OpName %mixed_sint_smod_const_int "mixed_sint_smod_const_int" + OpName %mixed_uint_mod_const_uint "mixed_uint_mod_const_uint" OpName %sp_sint_shift_right_arithmetic "sp_sint_shift_right_arithmetic" OpName %sp_uint_shift_right_arithmetic "sp_uint_shift_right_arithmetic" OpName %sp_sint_shift_left "sp_sint_shift_left" @@ -75,12 +103,20 @@ OpName %sp_sint_and_3 "sp_sint_and_3" OpName %sp_sint_or_256 "sp_sint_or_256" OpName %sp_uint_xor_512 "sp_uint_xor_512" + OpName %mixed_sint_and_uint "mixed_sint_and_uint" + OpName %mixed_uint_or_sint "mixed_uint_or_sint" + OpName %mixed_sint_xor_uint "mixed_sint_xor_uint" + OpName %mixed_spec_uint_and_const_sint "mixed_spec_uint_and_const_sint" + OpName %mixed_const_uint_or_spec_sint "mixed_const_uint_or_spec_sint" OpName %sp_int_lt_sp_sint "sp_int_lt_sp_sint" OpName %sp_int_le_sp_sint "sp_int_le_sp_sint" OpName %sp_uint_equal_sp_uint "sp_uint_equal_sp_uint" OpName %sp_uint_not_equal_sp_uint "sp_uint_not_equal_sp_uint" OpName %sp_int_gt_sp_sint "sp_int_gt_sp_sint" OpName %sp_int_ge_sp_sint "sp_int_ge_sp_sint" + OpName %mixed_sint_lt_uint "mixed_sint_lt_uint" + OpName %mixed_uint_ge_sint "mixed_uint_ge_sint" + OpName %mixed_sint_eq_uint "mixed_sint_eq_uint" OpName %logical_and "logical_and" OpName %logical_or "logical_or" OpName %logical_equal "logical_equal" @@ -131,6 +167,24 @@ OpMemberDecorate %OutputBuffer 34 Offset 136 OpMemberDecorate %OutputBuffer 35 Offset 140 OpMemberDecorate %OutputBuffer 36 Offset 144 + OpMemberDecorate %OutputBuffer 37 Offset 148 + OpMemberDecorate %OutputBuffer 38 Offset 152 + OpMemberDecorate %OutputBuffer 39 Offset 156 + OpMemberDecorate %OutputBuffer 40 Offset 160 + OpMemberDecorate %OutputBuffer 41 Offset 164 + OpMemberDecorate %OutputBuffer 42 Offset 168 + OpMemberDecorate %OutputBuffer 43 Offset 172 + OpMemberDecorate %OutputBuffer 44 Offset 176 + OpMemberDecorate %OutputBuffer 45 Offset 180 + OpMemberDecorate %OutputBuffer 46 Offset 184 + OpMemberDecorate %OutputBuffer 47 Offset 188 + OpMemberDecorate %OutputBuffer 48 Offset 192 + OpMemberDecorate %OutputBuffer 49 Offset 196 + OpMemberDecorate %OutputBuffer 50 Offset 200 + OpMemberDecorate %OutputBuffer 51 Offset 204 + OpMemberDecorate %OutputBuffer 52 Offset 208 + OpMemberDecorate %OutputBuffer 53 Offset 212 + OpMemberDecorate %OutputBuffer 54 Offset 216 OpDecorate %output_buffer Binding 0 OpDecorate %output_buffer DescriptorSet 0 OpDecorate %sp_int SpecId 1 @@ -144,11 +198,11 @@ %3 = OpTypeFunction %void %uint = OpTypeInt 32 0 %int = OpTypeInt 32 1 -%OutputBuffer = OpTypeStruct %uint %uint %int %uint %int %int %int %int %int %int %uint %int %uint %int %int %uint %int %uint %int %uint %int %int %uint %uint %uint %uint %uint %uint %uint %uint %uint %uint %uint %int %int %int %int +%OutputBuffer = OpTypeStruct %uint %uint %int %uint %uint %int %int %int %int %int %int %uint %uint %uint %uint %int %uint %int %uint %int %int %uint %uint %uint %int %uint %int %uint %int %uint %int %int %uint %uint %uint %uint %uint %uint %uint %uint %uint %uint %uint %uint %uint %uint %uint %uint %uint %uint %uint %int %int %int %int %_ptr_Uniform_OutputBuffer = OpTypePointer Uniform %OutputBuffer %output_buffer = OpVariable %_ptr_Uniform_OutputBuffer Uniform %int_0 = OpConstant %int 0 - %sp_int = OpSpecConstant %int 10 + %sp_int = OpSpecConstant %int 0 %bool = OpTypeBool %uint_0 = OpConstant %uint 0 %bool_from_int = OpSpecConstantOp %bool INotEqual %sp_int %uint_0 @@ -156,7 +210,7 @@ %17 = OpSpecConstantOp %uint Select %bool_from_int %uint_1 %uint_0 %_ptr_Uniform_uint = OpTypePointer Uniform %uint %int_1 = OpConstant %int 1 - %sp_uint = OpSpecConstant %uint 100 + %sp_uint = OpSpecConstant %uint 0 %bool_from_uint = OpSpecConstantOp %bool INotEqual %sp_uint %uint_0 %23 = OpSpecConstantOp %uint Select %bool_from_uint %uint_1 %uint_0 %int_2 = OpConstant %int 2 @@ -165,100 +219,155 @@ %int_3 = OpConstant %int 3 %uint_from_bool = OpSpecConstantOp %uint Select %bool_from_int %uint_1 %uint_0 %int_4 = OpConstant %int 4 - %negate_int = OpSpecConstantOp %int SNegate %sp_int + %sp_sint = OpSpecConstant %int 0 +%sp_uint_from_sint = OpSpecConstantOp %uint IAdd %sp_sint %uint_0 %int_5 = OpConstant %int 5 - %not_int = OpSpecConstantOp %int Not %sp_int +%sp_sint_from_uint = OpSpecConstantOp %int IAdd %sp_uint %uint_0 %int_6 = OpConstant %int 6 -%sp_int_add_two = OpSpecConstantOp %int IAdd %sp_int %int_2 + %negate_int = OpSpecConstantOp %int SNegate %sp_int %int_7 = OpConstant %int 7 - %42 = OpSpecConstantOp %int IAdd %sp_int %int_2 -%sp_int_add_two_sub_three = OpSpecConstantOp %int ISub %42 %int_3 + %not_int = OpSpecConstantOp %int Not %sp_int %int_8 = OpConstant %int 8 -%sp_int_add_two_sub_four = OpSpecConstantOp %int ISub %sp_int_add_two %int_4 +%sp_int_add_two = OpSpecConstantOp %int IAdd %sp_int %int_2 %int_9 = OpConstant %int 9 - %sp_sint = OpSpecConstant %int -10 -%sp_sint_mul_two = OpSpecConstantOp %int IMul %sp_sint %int_2 + %49 = OpSpecConstantOp %int IAdd %sp_int %int_2 +%sp_int_add_two_sub_three = OpSpecConstantOp %int ISub %49 %int_3 %int_10 = OpConstant %int 10 +%sp_int_add_two_sub_four = OpSpecConstantOp %int ISub %sp_int_add_two %int_4 + %int_11 = OpConstant %int 11 + %56 = OpSpecConstantOp %uint IAdd %sp_sint %uint_0 +%mixed_sint_add_uint = OpSpecConstantOp %uint IAdd %56 %sp_uint + %int_12 = OpConstant %int 12 + %60 = OpSpecConstantOp %uint IAdd %sp_sint %uint_0 +%mixed_uint_sub_sint = OpSpecConstantOp %uint ISub %sp_uint %60 + %int_13 = OpConstant %int 13 + %64 = OpSpecConstantOp %uint IAdd %sp_sint %uint_0 + %uint_10 = OpConstant %uint 10 +%mixed_spec_sint_add_const_uint = OpSpecConstantOp %uint IAdd %64 %uint_10 + %int_14 = OpConstant %int 14 + %uint_3 = OpConstant %uint 3 +%mixed_const_sint_mul_spec_uint = OpSpecConstantOp %uint IMul %uint_3 %sp_uint + %int_15 = OpConstant %int 15 +%sp_sint_mul_two = OpSpecConstantOp %int IMul %sp_sint %int_2 + %int_16 = OpConstant %int 16 %uint_2 = OpConstant %uint 2 %sp_uint_mul_two = OpSpecConstantOp %uint IMul %sp_uint %uint_2 - %int_11 = OpConstant %int 11 + %int_17 = OpConstant %int 17 %sp_sint_mul_two_div_five = OpSpecConstantOp %int SDiv %sp_sint_mul_two %int_5 - %int_12 = OpConstant %int 12 + %int_18 = OpConstant %int 18 %uint_5 = OpConstant %uint 5 %sp_uint_mul_two_div_five = OpSpecConstantOp %uint UDiv %sp_uint_mul_two %uint_5 - %int_13 = OpConstant %int 13 - %64 = OpSpecConstantOp %int IMul %sp_sint %int_3 -%sp_sint_mul_three_div_five = OpSpecConstantOp %int SDiv %64 %int_5 - %int_14 = OpConstant %int 14 + %int_19 = OpConstant %int 19 + %87 = OpSpecConstantOp %int IMul %sp_sint %int_3 +%sp_sint_mul_three_div_five = OpSpecConstantOp %int SDiv %87 %int_5 + %int_20 = OpConstant %int 20 %sp_sint_rem_four = OpSpecConstantOp %int SMod %sp_sint %int_4 - %int_15 = OpConstant %int 15 + %int_21 = OpConstant %int 21 %uint_4 = OpConstant %uint 4 %sp_uint_rem_four = OpSpecConstantOp %uint UMod %sp_uint %uint_4 - %int_16 = OpConstant %int 16 - %uint_10 = OpConstant %uint 10 -%sp_sint_shift_right_arithmetic = OpSpecConstantOp %int ShiftRightArithmetic %sp_sint %uint_10 - %int_17 = OpConstant %int 17 + %int_22 = OpConstant %int 22 + %98 = OpSpecConstantOp %uint IAdd %sp_sint %uint_0 +%mixed_sint_mod_uint = OpSpecConstantOp %uint UMod %98 %sp_uint + %int_23 = OpConstant %int 23 + %102 = OpSpecConstantOp %uint IAdd %sp_sint %uint_0 +%mixed_uint_mod_sint = OpSpecConstantOp %uint UMod %sp_uint %102 + %int_24 = OpConstant %int 24 +%mixed_sint_smod_const_int = OpSpecConstantOp %int SMod %sp_sint %int_3 + %int_25 = OpConstant %int 25 + %uint_7 = OpConstant %uint 7 +%mixed_uint_mod_const_uint = OpSpecConstantOp %uint UMod %sp_uint %uint_7 + %int_26 = OpConstant %int 26 +%sp_sint_shift_right_arithmetic = OpSpecConstantOp %int ShiftRightArithmetic %sp_sint %int_10 + %int_27 = OpConstant %int 27 %uint_20 = OpConstant %uint 20 %sp_uint_shift_right_arithmetic = OpSpecConstantOp %uint ShiftRightLogical %sp_uint %uint_20 - %int_18 = OpConstant %int 18 + %int_28 = OpConstant %int 28 %sp_sint_shift_left = OpSpecConstantOp %int ShiftLeftLogical %sp_sint %uint_1 - %int_19 = OpConstant %int 19 -%sp_uint_shift_left = OpSpecConstantOp %uint ShiftLeftLogical %sp_uint %uint_2 - %int_20 = OpConstant %int 20 + %int_29 = OpConstant %int 29 +%sp_uint_shift_left = OpSpecConstantOp %uint ShiftLeftLogical %sp_uint %int_2 + %int_30 = OpConstant %int 30 %sp_sint_and_3 = OpSpecConstantOp %int BitwiseAnd %sp_sint %int_3 - %int_21 = OpConstant %int 21 + %int_31 = OpConstant %int 31 %int_256 = OpConstant %int 256 %sp_sint_or_256 = OpSpecConstantOp %int BitwiseOr %sp_sint %int_256 - %int_22 = OpConstant %int 22 + %int_32 = OpConstant %int 32 %uint_512 = OpConstant %uint 512 %sp_uint_xor_512 = OpSpecConstantOp %uint BitwiseXor %sp_uint %uint_512 - %int_23 = OpConstant %int 23 + %int_33 = OpConstant %int 33 + %137 = OpSpecConstantOp %uint IAdd %sp_sint %uint_0 +%mixed_sint_and_uint = OpSpecConstantOp %uint BitwiseAnd %137 %sp_uint + %int_34 = OpConstant %int 34 + %141 = OpSpecConstantOp %uint IAdd %sp_sint %uint_0 +%mixed_uint_or_sint = OpSpecConstantOp %uint BitwiseOr %sp_uint %141 + %int_35 = OpConstant %int 35 + %145 = OpSpecConstantOp %uint IAdd %sp_sint %uint_0 +%mixed_sint_xor_uint = OpSpecConstantOp %uint BitwiseXor %145 %sp_uint + %int_36 = OpConstant %int 36 + %uint_15 = OpConstant %uint 15 +%mixed_spec_uint_and_const_sint = OpSpecConstantOp %uint BitwiseAnd %sp_uint %uint_15 + %int_37 = OpConstant %int 37 + %uint_128 = OpConstant %uint 128 + %154 = OpSpecConstantOp %uint IAdd %sp_sint %uint_0 +%mixed_const_uint_or_spec_sint = OpSpecConstantOp %uint BitwiseOr %uint_128 %154 + %int_38 = OpConstant %int 38 %sp_int_lt_sp_sint = OpSpecConstantOp %bool SLessThan %sp_int %sp_sint - %101 = OpSpecConstantOp %uint Select %sp_int_lt_sp_sint %uint_1 %uint_0 - %int_24 = OpConstant %int 24 + %159 = OpSpecConstantOp %uint Select %sp_int_lt_sp_sint %uint_1 %uint_0 + %int_39 = OpConstant %int 39 %sp_int_le_sp_sint = OpSpecConstantOp %bool SLessThanEqual %sp_int %sp_sint - %105 = OpSpecConstantOp %uint Select %sp_int_le_sp_sint %uint_1 %uint_0 - %int_25 = OpConstant %int 25 + %163 = OpSpecConstantOp %uint Select %sp_int_le_sp_sint %uint_1 %uint_0 + %int_40 = OpConstant %int 40 %sp_uint_equal_sp_uint = OpSpecConstantOp %bool IEqual %sp_uint %sp_uint - %109 = OpSpecConstantOp %uint Select %sp_uint_equal_sp_uint %uint_1 %uint_0 - %int_26 = OpConstant %int 26 + %167 = OpSpecConstantOp %uint Select %sp_uint_equal_sp_uint %uint_1 %uint_0 + %int_41 = OpConstant %int 41 %sp_uint_not_equal_sp_uint = OpSpecConstantOp %bool INotEqual %sp_uint %sp_uint - %113 = OpSpecConstantOp %uint Select %sp_uint_not_equal_sp_uint %uint_1 %uint_0 - %int_27 = OpConstant %int 27 + %171 = OpSpecConstantOp %uint Select %sp_uint_not_equal_sp_uint %uint_1 %uint_0 + %int_42 = OpConstant %int 42 %sp_int_gt_sp_sint = OpSpecConstantOp %bool SGreaterThan %sp_int %sp_sint - %117 = OpSpecConstantOp %uint Select %sp_int_gt_sp_sint %uint_1 %uint_0 - %int_28 = OpConstant %int 28 + %175 = OpSpecConstantOp %uint Select %sp_int_gt_sp_sint %uint_1 %uint_0 + %int_43 = OpConstant %int 43 %sp_int_ge_sp_sint = OpSpecConstantOp %bool SGreaterThanEqual %sp_int %sp_sint - %121 = OpSpecConstantOp %uint Select %sp_int_ge_sp_sint %uint_1 %uint_0 - %int_29 = OpConstant %int 29 + %179 = OpSpecConstantOp %uint Select %sp_int_ge_sp_sint %uint_1 %uint_0 + %int_44 = OpConstant %int 44 + %182 = OpSpecConstantOp %uint IAdd %sp_sint %uint_0 +%mixed_sint_lt_uint = OpSpecConstantOp %bool ULessThan %182 %sp_uint + %184 = OpSpecConstantOp %uint Select %mixed_sint_lt_uint %uint_1 %uint_0 + %int_45 = OpConstant %int 45 + %187 = OpSpecConstantOp %uint IAdd %sp_sint %uint_0 +%mixed_uint_ge_sint = OpSpecConstantOp %bool UGreaterThanEqual %sp_uint %187 + %189 = OpSpecConstantOp %uint Select %mixed_uint_ge_sint %uint_1 %uint_0 + %int_46 = OpConstant %int 46 + %192 = OpSpecConstantOp %uint IAdd %sp_sint %uint_0 +%mixed_sint_eq_uint = OpSpecConstantOp %bool IEqual %192 %sp_uint + %194 = OpSpecConstantOp %uint Select %mixed_sint_eq_uint %uint_1 %uint_0 + %int_47 = OpConstant %int 47 %logical_and = OpSpecConstantOp %bool LogicalAnd %bool_from_int %bool_from_uint - %125 = OpSpecConstantOp %uint Select %logical_and %uint_1 %uint_0 - %int_30 = OpConstant %int 30 + %198 = OpSpecConstantOp %uint Select %logical_and %uint_1 %uint_0 + %int_48 = OpConstant %int 48 %logical_or = OpSpecConstantOp %bool LogicalOr %bool_from_int %bool_from_uint - %129 = OpSpecConstantOp %uint Select %logical_or %uint_1 %uint_0 - %int_31 = OpConstant %int 31 + %202 = OpSpecConstantOp %uint Select %logical_or %uint_1 %uint_0 + %int_49 = OpConstant %int 49 %logical_equal = OpSpecConstantOp %bool LogicalEqual %bool_from_int %bool_from_uint - %133 = OpSpecConstantOp %uint Select %logical_equal %uint_1 %uint_0 - %int_32 = OpConstant %int 32 + %206 = OpSpecConstantOp %uint Select %logical_equal %uint_1 %uint_0 + %int_50 = OpConstant %int 50 %logical_not_equal = OpSpecConstantOp %bool LogicalNotEqual %bool_from_int %bool_from_uint - %137 = OpSpecConstantOp %uint Select %logical_not_equal %uint_1 %uint_0 - %int_33 = OpConstant %int 33 - %c = OpSpecConstantTrue %bool + %210 = OpSpecConstantOp %uint Select %logical_not_equal %uint_1 %uint_0 + %int_51 = OpConstant %int 51 + %c = OpSpecConstantFalse %bool %t1 = OpSpecConstantOp %int Select %c %int_13 %int_17 - %int_34 = OpConstant %int 34 - %a = OpSpecConstant %int 4 + %int_52 = OpConstant %int 52 + %a = OpSpecConstant %int 0 %t2 = OpSpecConstantOp %int Select %c %a %int_17 - %int_35 = OpConstant %int 35 + %int_53 = OpConstant %int 53 %true = OpConstantTrue %bool %t3 = OpSpecConstantOp %int Select %true %a %int_17 - %int_36 = OpConstant %int 36 - %b = OpSpecConstant %int 6 - %153 = OpSpecConstantOp %bool SGreaterThan %a %b - %154 = OpSpecConstantOp %int IAdd %int_13 %a - %155 = OpSpecConstantOp %int IMul %int_17 %b - %t4 = OpSpecConstantOp %int Select %153 %154 %155 + %int_54 = OpConstant %int 54 + %b = OpSpecConstant %int 0 + %226 = OpSpecConstantOp %bool SGreaterThan %a %b + %227 = OpSpecConstantOp %int IAdd %int_13 %a + %228 = OpSpecConstantOp %int IMul %int_17 %b + %t4 = OpSpecConstantOp %int Select %226 %227 %228 %float = OpTypeFloat 32 - %sp_float = OpSpecConstant %float 3.1415925 + %sp_float = OpSpecConstant %float 0 %main = OpFunction %void None %3 %5 = OpLabel %19 = OpAccessChain %_ptr_Uniform_uint %output_buffer %int_0 @@ -269,71 +378,107 @@ OpStore %28 %int_from_bool %31 = OpAccessChain %_ptr_Uniform_uint %output_buffer %int_3 OpStore %31 %uint_from_bool - %34 = OpAccessChain %_ptr_Uniform_int %output_buffer %int_4 - OpStore %34 %negate_int - %37 = OpAccessChain %_ptr_Uniform_int %output_buffer %int_5 - OpStore %37 %not_int - %40 = OpAccessChain %_ptr_Uniform_int %output_buffer %int_6 - OpStore %40 %sp_int_add_two + %35 = OpAccessChain %_ptr_Uniform_uint %output_buffer %int_4 + OpStore %35 %sp_uint_from_sint + %38 = OpAccessChain %_ptr_Uniform_int %output_buffer %int_5 + OpStore %38 %sp_sint_from_uint + %41 = OpAccessChain %_ptr_Uniform_int %output_buffer %int_6 + OpStore %41 %negate_int %44 = OpAccessChain %_ptr_Uniform_int %output_buffer %int_7 - OpStore %44 %sp_int_add_two_sub_three + OpStore %44 %not_int %47 = OpAccessChain %_ptr_Uniform_int %output_buffer %int_8 - OpStore %47 %sp_int_add_two_sub_four + OpStore %47 %sp_int_add_two %51 = OpAccessChain %_ptr_Uniform_int %output_buffer %int_9 - OpStore %51 %sp_sint_mul_two - %55 = OpAccessChain %_ptr_Uniform_uint %output_buffer %int_10 - OpStore %55 %sp_uint_mul_two - %58 = OpAccessChain %_ptr_Uniform_int %output_buffer %int_11 - OpStore %58 %sp_sint_mul_two_div_five + OpStore %51 %sp_int_add_two_sub_three + %54 = OpAccessChain %_ptr_Uniform_int %output_buffer %int_10 + OpStore %54 %sp_int_add_two_sub_four + %58 = OpAccessChain %_ptr_Uniform_uint %output_buffer %int_11 + OpStore %58 %mixed_sint_add_uint %62 = OpAccessChain %_ptr_Uniform_uint %output_buffer %int_12 - OpStore %62 %sp_uint_mul_two_div_five - %66 = OpAccessChain %_ptr_Uniform_int %output_buffer %int_13 - OpStore %66 %sp_sint_mul_three_div_five - %69 = OpAccessChain %_ptr_Uniform_int %output_buffer %int_14 - OpStore %69 %sp_sint_rem_four - %73 = OpAccessChain %_ptr_Uniform_uint %output_buffer %int_15 - OpStore %73 %sp_uint_rem_four - %77 = OpAccessChain %_ptr_Uniform_int %output_buffer %int_16 - OpStore %77 %sp_sint_shift_right_arithmetic - %81 = OpAccessChain %_ptr_Uniform_uint %output_buffer %int_17 - OpStore %81 %sp_uint_shift_right_arithmetic - %84 = OpAccessChain %_ptr_Uniform_int %output_buffer %int_18 - OpStore %84 %sp_sint_shift_left - %87 = OpAccessChain %_ptr_Uniform_uint %output_buffer %int_19 - OpStore %87 %sp_uint_shift_left - %90 = OpAccessChain %_ptr_Uniform_int %output_buffer %int_20 - OpStore %90 %sp_sint_and_3 - %94 = OpAccessChain %_ptr_Uniform_int %output_buffer %int_21 - OpStore %94 %sp_sint_or_256 - %98 = OpAccessChain %_ptr_Uniform_uint %output_buffer %int_22 - OpStore %98 %sp_uint_xor_512 - %102 = OpAccessChain %_ptr_Uniform_uint %output_buffer %int_23 - OpStore %102 %101 - %106 = OpAccessChain %_ptr_Uniform_uint %output_buffer %int_24 - OpStore %106 %105 - %110 = OpAccessChain %_ptr_Uniform_uint %output_buffer %int_25 - OpStore %110 %109 - %114 = OpAccessChain %_ptr_Uniform_uint %output_buffer %int_26 - OpStore %114 %113 + OpStore %62 %mixed_uint_sub_sint + %67 = OpAccessChain %_ptr_Uniform_uint %output_buffer %int_13 + OpStore %67 %mixed_spec_sint_add_const_uint + %71 = OpAccessChain %_ptr_Uniform_uint %output_buffer %int_14 + OpStore %71 %mixed_const_sint_mul_spec_uint + %74 = OpAccessChain %_ptr_Uniform_int %output_buffer %int_15 + OpStore %74 %sp_sint_mul_two + %78 = OpAccessChain %_ptr_Uniform_uint %output_buffer %int_16 + OpStore %78 %sp_uint_mul_two + %81 = OpAccessChain %_ptr_Uniform_int %output_buffer %int_17 + OpStore %81 %sp_sint_mul_two_div_five + %85 = OpAccessChain %_ptr_Uniform_uint %output_buffer %int_18 + OpStore %85 %sp_uint_mul_two_div_five + %89 = OpAccessChain %_ptr_Uniform_int %output_buffer %int_19 + OpStore %89 %sp_sint_mul_three_div_five + %92 = OpAccessChain %_ptr_Uniform_int %output_buffer %int_20 + OpStore %92 %sp_sint_rem_four + %96 = OpAccessChain %_ptr_Uniform_uint %output_buffer %int_21 + OpStore %96 %sp_uint_rem_four + %100 = OpAccessChain %_ptr_Uniform_uint %output_buffer %int_22 + OpStore %100 %mixed_sint_mod_uint + %104 = OpAccessChain %_ptr_Uniform_uint %output_buffer %int_23 + OpStore %104 %mixed_uint_mod_sint + %107 = OpAccessChain %_ptr_Uniform_int %output_buffer %int_24 + OpStore %107 %mixed_sint_smod_const_int + %111 = OpAccessChain %_ptr_Uniform_uint %output_buffer %int_25 + OpStore %111 %mixed_uint_mod_const_uint + %114 = OpAccessChain %_ptr_Uniform_int %output_buffer %int_26 + OpStore %114 %sp_sint_shift_right_arithmetic %118 = OpAccessChain %_ptr_Uniform_uint %output_buffer %int_27 - OpStore %118 %117 - %122 = OpAccessChain %_ptr_Uniform_uint %output_buffer %int_28 - OpStore %122 %121 - %126 = OpAccessChain %_ptr_Uniform_uint %output_buffer %int_29 - OpStore %126 %125 - %130 = OpAccessChain %_ptr_Uniform_uint %output_buffer %int_30 - OpStore %130 %129 - %134 = OpAccessChain %_ptr_Uniform_uint %output_buffer %int_31 - OpStore %134 %133 - %138 = OpAccessChain %_ptr_Uniform_uint %output_buffer %int_32 - OpStore %138 %137 - %142 = OpAccessChain %_ptr_Uniform_int %output_buffer %int_33 - OpStore %142 %t1 - %146 = OpAccessChain %_ptr_Uniform_int %output_buffer %int_34 - OpStore %146 %t2 - %150 = OpAccessChain %_ptr_Uniform_int %output_buffer %int_35 - OpStore %150 %t3 - %157 = OpAccessChain %_ptr_Uniform_int %output_buffer %int_36 - OpStore %157 %t4 + OpStore %118 %sp_uint_shift_right_arithmetic + %121 = OpAccessChain %_ptr_Uniform_int %output_buffer %int_28 + OpStore %121 %sp_sint_shift_left + %124 = OpAccessChain %_ptr_Uniform_uint %output_buffer %int_29 + OpStore %124 %sp_uint_shift_left + %127 = OpAccessChain %_ptr_Uniform_int %output_buffer %int_30 + OpStore %127 %sp_sint_and_3 + %131 = OpAccessChain %_ptr_Uniform_int %output_buffer %int_31 + OpStore %131 %sp_sint_or_256 + %135 = OpAccessChain %_ptr_Uniform_uint %output_buffer %int_32 + OpStore %135 %sp_uint_xor_512 + %139 = OpAccessChain %_ptr_Uniform_uint %output_buffer %int_33 + OpStore %139 %mixed_sint_and_uint + %143 = OpAccessChain %_ptr_Uniform_uint %output_buffer %int_34 + OpStore %143 %mixed_uint_or_sint + %147 = OpAccessChain %_ptr_Uniform_uint %output_buffer %int_35 + OpStore %147 %mixed_sint_xor_uint + %151 = OpAccessChain %_ptr_Uniform_uint %output_buffer %int_36 + OpStore %151 %mixed_spec_uint_and_const_sint + %156 = OpAccessChain %_ptr_Uniform_uint %output_buffer %int_37 + OpStore %156 %mixed_const_uint_or_spec_sint + %160 = OpAccessChain %_ptr_Uniform_uint %output_buffer %int_38 + OpStore %160 %159 + %164 = OpAccessChain %_ptr_Uniform_uint %output_buffer %int_39 + OpStore %164 %163 + %168 = OpAccessChain %_ptr_Uniform_uint %output_buffer %int_40 + OpStore %168 %167 + %172 = OpAccessChain %_ptr_Uniform_uint %output_buffer %int_41 + OpStore %172 %171 + %176 = OpAccessChain %_ptr_Uniform_uint %output_buffer %int_42 + OpStore %176 %175 + %180 = OpAccessChain %_ptr_Uniform_uint %output_buffer %int_43 + OpStore %180 %179 + %185 = OpAccessChain %_ptr_Uniform_uint %output_buffer %int_44 + OpStore %185 %184 + %190 = OpAccessChain %_ptr_Uniform_uint %output_buffer %int_45 + OpStore %190 %189 + %195 = OpAccessChain %_ptr_Uniform_uint %output_buffer %int_46 + OpStore %195 %194 + %199 = OpAccessChain %_ptr_Uniform_uint %output_buffer %int_47 + OpStore %199 %198 + %203 = OpAccessChain %_ptr_Uniform_uint %output_buffer %int_48 + OpStore %203 %202 + %207 = OpAccessChain %_ptr_Uniform_uint %output_buffer %int_49 + OpStore %207 %206 + %211 = OpAccessChain %_ptr_Uniform_uint %output_buffer %int_50 + OpStore %211 %210 + %215 = OpAccessChain %_ptr_Uniform_int %output_buffer %int_51 + OpStore %215 %t1 + %219 = OpAccessChain %_ptr_Uniform_int %output_buffer %int_52 + OpStore %219 %t2 + %223 = OpAccessChain %_ptr_Uniform_int %output_buffer %int_53 + OpStore %223 %t3 + %230 = OpAccessChain %_ptr_Uniform_int %output_buffer %int_54 + OpStore %230 %t4 OpReturn OpFunctionEnd diff --git a/naga/tests/out/hlsl/spv-spec-constant-op.hlsl b/naga/tests/out/hlsl/spv-spec-constant-op.hlsl index 989baadaceb..abee6dc4d09 100644 --- a/naga/tests/out/hlsl/spv-spec-constant-op.hlsl +++ b/naga/tests/out/hlsl/spv-spec-constant-op.hlsl @@ -3,11 +3,17 @@ struct OutputBuffer { uint bool_from_uint_val; int int_from_bool_val; uint uint_from_bool_val; + uint sp_uint_from_sint_val; + int sp_sint_from_uint_val; int negate_int_val; int not_int_val; int sp_int_add_two_val; int sp_int_add_two_sub_three_val; int sp_int_add_two_sub_four_val; + uint mixed_sint_add_uint_val; + uint mixed_uint_sub_sint_val; + uint mixed_spec_sint_add_const_uint_val; + uint mixed_const_sint_mul_spec_uint_val; int sp_sint_mul_two_val; uint sp_uint_mul_two_val; int sp_sint_mul_two_div_five_val; @@ -15,6 +21,10 @@ struct OutputBuffer { int sp_sint_mul_three_div_five_val; int sp_sint_rem_four_val; uint sp_uint_rem_four_val; + uint mixed_sint_mod_uint_val; + uint mixed_uint_mod_sint_val; + int mixed_sint_smod_const_int_val; + uint mixed_uint_mod_const_uint_val; int sp_sint_shift_right_arithmetic_val; uint sp_uint_shift_right_arithmetic_val; int sp_sint_shift_left_val; @@ -22,12 +32,20 @@ struct OutputBuffer { int sp_sint_and_3_val; int sp_sint_or_256_val; uint sp_uint_xor_512_val; + uint mixed_sint_and_uint_val; + uint mixed_uint_or_sint_val; + uint mixed_sint_xor_uint_val; + uint mixed_spec_uint_and_const_sint_val; + uint mixed_const_uint_or_spec_sint_val; uint sp_int_lt_sp_sint_val; uint sp_int_le_sp_sint_val; uint sp_uint_equal_sp_uint_val; uint sp_uint_not_equal_sp_uint_val; uint sp_int_gt_sp_sint_val; uint sp_int_ge_sp_sint_val; + uint mixed_sint_lt_uint_val; + uint mixed_uint_ge_sint_val; + uint mixed_sint_eq_uint_val; uint logical_and_val; uint logical_or_val; uint logical_equal_val; @@ -39,107 +57,158 @@ struct OutputBuffer { }; static const int sp_int = int(3); -static const bool _spec_const_op_6_ = true; -static const uint _spec_const_op_58_ = 1u; +static const bool bool_from_int = true; +static const uint bool_from_int_as_uint = 1u; static const uint sp_uint = 20u; -static const bool _spec_const_op_8_ = true; -static const uint _spec_const_op_61_ = 1u; -static const int _spec_const_op_9_ = int(1); -static const uint _spec_const_op_10_ = 1u; -static const int _spec_const_op_11_ = int(-3); -static const int _spec_const_op_12_ = int(-4); -static const int _spec_const_op_13_ = int(5); -static const int _spec_const_op_69_ = int(5); -static const int _spec_const_op_14_ = int(2); -static const int _spec_const_op_15_ = int(1); +static const bool bool_from_uint = true; +static const uint bool_from_uint_as_uint = 1u; +static const int int_from_bool = int(1); +static const uint uint_from_bool = 1u; static const int sp_sint = int(4); -static const int _spec_const_op_17_ = int(8); -static const uint _spec_const_op_18_ = 40u; -static const int _spec_const_op_19_ = int(1); -static const uint _spec_const_op_20_ = 8u; -static const int _spec_const_op_78_ = int(12); -static const int _spec_const_op_21_ = int(2); -static const int _spec_const_op_22_ = int(0); -static const uint _spec_const_op_23_ = 0u; -static const int _spec_const_op_24_ = int(0); -static const uint _spec_const_op_25_ = 0u; -static const int _spec_const_op_26_ = int(8); -static const uint _spec_const_op_27_ = 80u; -static const int _spec_const_op_28_ = int(0); -static const int _spec_const_op_29_ = int(260); -static const uint _spec_const_op_30_ = 532u; -static const bool _spec_const_op_31_ = true; -static const uint _spec_const_op_94_ = 1u; -static const bool _spec_const_op_32_ = true; -static const uint _spec_const_op_96_ = 1u; -static const bool _spec_const_op_33_ = true; -static const uint _spec_const_op_98_ = 1u; -static const bool _spec_const_op_34_ = false; -static const uint _spec_const_op_100_ = 0u; -static const bool _spec_const_op_35_ = false; -static const uint _spec_const_op_102_ = 0u; -static const bool _spec_const_op_36_ = false; -static const uint _spec_const_op_104_ = 0u; -static const bool _spec_const_op_37_ = true; -static const uint _spec_const_op_106_ = 1u; -static const bool _spec_const_op_38_ = true; -static const uint _spec_const_op_108_ = 1u; -static const bool _spec_const_op_39_ = true; -static const uint _spec_const_op_110_ = 1u; -static const bool _spec_const_op_40_ = false; -static const uint _spec_const_op_112_ = 0u; +static const uint sp_uint_from_sint = 4u; +static const int sp_sint_from_uint = int(20); +static const int negate_int = int(-3); +static const int not_int = int(-4); +static const int sp_int_add_two = int(5); +static const int _spec_const_op_89_ = int(5); +static const int sp_int_add_two_sub_three = int(2); +static const int sp_int_add_two_sub_four = int(1); +static const uint sp_sint_as_uint = 4u; +static const uint mixed_sint_add_uint = 24u; +static const uint sp_sint_as_uint_1 = 4u; +static const uint mixed_uint_sub_sint = 16u; +static const uint sp_sint_as_uint_2 = 4u; +static const uint mixed_spec_sint_add_const_uint = 14u; +static const uint mixed_const_sint_mul_spec_uint = 60u; +static const int sp_sint_mul_two = int(8); +static const uint sp_uint_mul_two = 40u; +static const int sp_sint_mul_two_div_five = int(1); +static const uint sp_uint_mul_two_div_five = 8u; +static const int _spec_const_op_107_ = int(12); +static const int sp_sint_mul_three_div_five = int(2); +static const int sp_sint_rem_four = int(0); +static const uint sp_uint_rem_four = 0u; +static const uint sp_sint_as_uint_3 = 4u; +static const uint mixed_sint_mod_uint = 4u; +static const uint sp_sint_as_uint_4 = 4u; +static const uint mixed_uint_mod_sint = 0u; +static const int mixed_sint_smod_const_int = int(1); +static const uint mixed_uint_mod_const_uint = 6u; +static const int sp_sint_shift_right_arithmetic = int(0); +static const uint sp_uint_shift_right_arithmetic = 0u; +static const int sp_sint_shift_left = int(8); +static const uint sp_uint_shift_left = 80u; +static const int sp_sint_and_3_ = int(0); +static const int sp_sint_or_256_ = int(260); +static const uint sp_uint_xor_512_ = 532u; +static const uint sp_sint_as_uint_5 = 4u; +static const uint mixed_sint_and_uint = 4u; +static const uint sp_sint_as_uint_6 = 4u; +static const uint mixed_uint_or_sint = 20u; +static const uint sp_sint_as_uint_7 = 4u; +static const uint mixed_sint_xor_uint = 16u; +static const uint mixed_spec_uint_and_const_sint = 4u; +static const uint sp_sint_as_uint_8 = 4u; +static const uint mixed_const_uint_or_spec_sint = 132u; +static const bool sp_int_lt_sp_sint = true; +static const uint sp_int_lt_sp_sint_as_uint = 1u; +static const bool sp_int_le_sp_sint = true; +static const uint sp_int_le_sp_sint_as_uint = 1u; +static const bool sp_uint_equal_sp_uint = true; +static const uint sp_uint_equal_sp_uint_as_uint = 1u; +static const bool sp_uint_not_equal_sp_uint = false; +static const uint sp_uint_not_equal_sp_uint_as_uint = 0u; +static const bool sp_int_gt_sp_sint = false; +static const uint sp_int_gt_sp_sint_as_uint = 0u; +static const bool sp_int_ge_sp_sint = false; +static const uint sp_int_ge_sp_sint_as_uint = 0u; +static const uint sp_sint_as_uint_9 = 4u; +static const bool mixed_sint_lt_uint = true; +static const uint mixed_sint_lt_uint_as_uint = 1u; +static const uint sp_sint_as_uint_10 = 4u; +static const bool mixed_uint_ge_sint = true; +static const uint mixed_uint_ge_sint_as_uint = 1u; +static const uint sp_sint_as_uint_11 = 4u; +static const bool mixed_sint_eq_uint = false; +static const uint mixed_sint_eq_uint_as_uint = 0u; +static const bool logical_and = true; +static const uint logical_and_as_uint = 1u; +static const bool logical_or = true; +static const uint logical_or_as_uint = 1u; +static const bool logical_equal = true; +static const uint logical_equal_as_uint = 1u; +static const bool logical_not_equal = false; +static const uint logical_not_equal_as_uint = 0u; static const bool c = true; -static const int _spec_const_op_42_ = int(13); +static const int t1_ = int(13); static const int a = int(1); -static const int _spec_const_op_44_ = int(1); -static const int _spec_const_op_45_ = int(1); +static const int t2_ = int(1); +static const int t3_ = int(1); static const int b = int(0); -static const bool _spec_const_op_118_ = true; -static const int _spec_const_op_119_ = int(14); -static const int _spec_const_op_120_ = int(0); -static const int _spec_const_op_47_ = int(14); +static const bool _spec_const_op_173_ = true; +static const int _spec_const_op_174_ = int(14); +static const int _spec_const_op_175_ = int(0); +static const int t4_ = int(14); RWByteAddressBuffer output_buffer : register(u0); void main_1() { - output_buffer.Store(0, asuint(_spec_const_op_58_)); - output_buffer.Store(4, asuint(_spec_const_op_61_)); - output_buffer.Store(8, asuint(_spec_const_op_9_)); - output_buffer.Store(12, asuint(_spec_const_op_10_)); - output_buffer.Store(16, asuint(_spec_const_op_11_)); - output_buffer.Store(20, asuint(_spec_const_op_12_)); - output_buffer.Store(24, asuint(_spec_const_op_13_)); - output_buffer.Store(28, asuint(_spec_const_op_14_)); - output_buffer.Store(32, asuint(_spec_const_op_15_)); - output_buffer.Store(36, asuint(_spec_const_op_17_)); - output_buffer.Store(40, asuint(_spec_const_op_18_)); - output_buffer.Store(44, asuint(_spec_const_op_19_)); - output_buffer.Store(48, asuint(_spec_const_op_20_)); - output_buffer.Store(52, asuint(_spec_const_op_21_)); - output_buffer.Store(56, asuint(_spec_const_op_22_)); - output_buffer.Store(60, asuint(_spec_const_op_23_)); - output_buffer.Store(64, asuint(_spec_const_op_24_)); - output_buffer.Store(68, asuint(_spec_const_op_25_)); - output_buffer.Store(72, asuint(_spec_const_op_26_)); - output_buffer.Store(76, asuint(_spec_const_op_27_)); - output_buffer.Store(80, asuint(_spec_const_op_28_)); - output_buffer.Store(84, asuint(_spec_const_op_29_)); - output_buffer.Store(88, asuint(_spec_const_op_30_)); - output_buffer.Store(92, asuint(_spec_const_op_94_)); - output_buffer.Store(96, asuint(_spec_const_op_96_)); - output_buffer.Store(100, asuint(_spec_const_op_98_)); - output_buffer.Store(104, asuint(_spec_const_op_100_)); - output_buffer.Store(108, asuint(_spec_const_op_102_)); - output_buffer.Store(112, asuint(_spec_const_op_104_)); - output_buffer.Store(116, asuint(_spec_const_op_106_)); - output_buffer.Store(120, asuint(_spec_const_op_108_)); - output_buffer.Store(124, asuint(_spec_const_op_110_)); - output_buffer.Store(128, asuint(_spec_const_op_112_)); - output_buffer.Store(132, asuint(_spec_const_op_42_)); - output_buffer.Store(136, asuint(_spec_const_op_44_)); - output_buffer.Store(140, asuint(_spec_const_op_45_)); - output_buffer.Store(144, asuint(_spec_const_op_47_)); + output_buffer.Store(0, asuint(bool_from_int_as_uint)); + output_buffer.Store(4, asuint(bool_from_uint_as_uint)); + output_buffer.Store(8, asuint(int_from_bool)); + output_buffer.Store(12, asuint(uint_from_bool)); + output_buffer.Store(16, asuint(sp_uint_from_sint)); + output_buffer.Store(20, asuint(sp_sint_from_uint)); + output_buffer.Store(24, asuint(negate_int)); + output_buffer.Store(28, asuint(not_int)); + output_buffer.Store(32, asuint(sp_int_add_two)); + output_buffer.Store(36, asuint(sp_int_add_two_sub_three)); + output_buffer.Store(40, asuint(sp_int_add_two_sub_four)); + output_buffer.Store(44, asuint(mixed_sint_add_uint)); + output_buffer.Store(48, asuint(mixed_uint_sub_sint)); + output_buffer.Store(52, asuint(mixed_spec_sint_add_const_uint)); + output_buffer.Store(56, asuint(mixed_const_sint_mul_spec_uint)); + output_buffer.Store(60, asuint(sp_sint_mul_two)); + output_buffer.Store(64, asuint(sp_uint_mul_two)); + output_buffer.Store(68, asuint(sp_sint_mul_two_div_five)); + output_buffer.Store(72, asuint(sp_uint_mul_two_div_five)); + output_buffer.Store(76, asuint(sp_sint_mul_three_div_five)); + output_buffer.Store(80, asuint(sp_sint_rem_four)); + output_buffer.Store(84, asuint(sp_uint_rem_four)); + output_buffer.Store(88, asuint(mixed_sint_mod_uint)); + output_buffer.Store(92, asuint(mixed_uint_mod_sint)); + output_buffer.Store(96, asuint(mixed_sint_smod_const_int)); + output_buffer.Store(100, asuint(mixed_uint_mod_const_uint)); + output_buffer.Store(104, asuint(sp_sint_shift_right_arithmetic)); + output_buffer.Store(108, asuint(sp_uint_shift_right_arithmetic)); + output_buffer.Store(112, asuint(sp_sint_shift_left)); + output_buffer.Store(116, asuint(sp_uint_shift_left)); + output_buffer.Store(120, asuint(sp_sint_and_3_)); + output_buffer.Store(124, asuint(sp_sint_or_256_)); + output_buffer.Store(128, asuint(sp_uint_xor_512_)); + output_buffer.Store(132, asuint(mixed_sint_and_uint)); + output_buffer.Store(136, asuint(mixed_uint_or_sint)); + output_buffer.Store(140, asuint(mixed_sint_xor_uint)); + output_buffer.Store(144, asuint(mixed_spec_uint_and_const_sint)); + output_buffer.Store(148, asuint(mixed_const_uint_or_spec_sint)); + output_buffer.Store(152, asuint(sp_int_lt_sp_sint_as_uint)); + output_buffer.Store(156, asuint(sp_int_le_sp_sint_as_uint)); + output_buffer.Store(160, asuint(sp_uint_equal_sp_uint_as_uint)); + output_buffer.Store(164, asuint(sp_uint_not_equal_sp_uint_as_uint)); + output_buffer.Store(168, asuint(sp_int_gt_sp_sint_as_uint)); + output_buffer.Store(172, asuint(sp_int_ge_sp_sint_as_uint)); + output_buffer.Store(176, asuint(mixed_sint_lt_uint_as_uint)); + output_buffer.Store(180, asuint(mixed_uint_ge_sint_as_uint)); + output_buffer.Store(184, asuint(mixed_sint_eq_uint_as_uint)); + output_buffer.Store(188, asuint(logical_and_as_uint)); + output_buffer.Store(192, asuint(logical_or_as_uint)); + output_buffer.Store(196, asuint(logical_equal_as_uint)); + output_buffer.Store(200, asuint(logical_not_equal_as_uint)); + output_buffer.Store(204, asuint(t1_)); + output_buffer.Store(208, asuint(t2_)); + output_buffer.Store(212, asuint(t3_)); + output_buffer.Store(216, asuint(t4_)); return; }