diff --git a/reference/shaders-msl-no-opt/asm/comp/arithmetic-conversion-signs.asm.comp b/reference/shaders-msl-no-opt/asm/comp/arithmetic-conversion-signs.asm.comp new file mode 100644 index 00000000..c3f9f5e1 --- /dev/null +++ b/reference/shaders-msl-no-opt/asm/comp/arithmetic-conversion-signs.asm.comp @@ -0,0 +1,42 @@ +#include +#include + +using namespace metal; + +struct SSBO +{ + int s32; + uint u32; + short s16; + ushort u16; + float f32; +}; + +kernel void main0(device SSBO& _4 [[buffer(0)]]) +{ + int _29 = _4.s32; + uint _30 = _4.u32; + short _31 = _4.s16; + ushort _32 = _4.u16; + float _33 = _4.f32; + _4.s32 = int(_31); + _4.u32 = uint(_31); + _4.s32 = int(short(_32)); + _4.u32 = uint(short(_32)); + _4.u32 = uint(ushort(_31)); + _4.u32 = uint(_32); + _4.s16 = short(_29); + _4.u16 = ushort(_29); + _4.s16 = short(_30); + _4.u16 = ushort(_30); + _4.u16 = ushort(_29); + _4.u16 = ushort(_30); + _4.f32 = float(_31); + _4.f32 = float(short(_32)); + _4.f32 = float(ushort(_31)); + _4.f32 = float(_32); + _4.s16 = short(_33); + _4.u16 = ushort(short(_33)); + _4.u16 = ushort(_33); +} + diff --git a/reference/shaders-no-opt/asm/comp/arithmetic-conversion-signs.asm.nocompat.vk.comp.vk b/reference/shaders-no-opt/asm/comp/arithmetic-conversion-signs.asm.nocompat.vk.comp.vk new file mode 100644 index 00000000..c2fb3990 --- /dev/null +++ b/reference/shaders-no-opt/asm/comp/arithmetic-conversion-signs.asm.nocompat.vk.comp.vk @@ -0,0 +1,42 @@ +#version 450 +#extension GL_EXT_shader_explicit_arithmetic_types_int16 : require +#extension GL_EXT_shader_16bit_storage : require +layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in; + +layout(set = 0, binding = 0, std430) buffer SSBO +{ + int s32; + uint u32; + int16_t s16; + uint16_t u16; + float f32; +} _4; + +void main() +{ + int _29 = _4.s32; + uint _30 = _4.u32; + int16_t _31 = _4.s16; + uint16_t _32 = _4.u16; + float _33 = _4.f32; + _4.s32 = int(_31); + _4.u32 = uint(_31); + _4.s32 = int(int16_t(_32)); + _4.u32 = uint(int16_t(_32)); + _4.u32 = uint(uint16_t(_31)); + _4.u32 = uint(_32); + _4.s16 = int16_t(_29); + _4.u16 = uint16_t(_29); + _4.s16 = int16_t(_30); + _4.u16 = uint16_t(_30); + _4.u16 = uint16_t(_29); + _4.u16 = uint16_t(_30); + _4.f32 = float(_31); + _4.f32 = float(int16_t(_32)); + _4.f32 = float(uint16_t(_31)); + _4.f32 = float(_32); + _4.s16 = int16_t(_33); + _4.u16 = uint16_t(int16_t(_33)); + _4.u16 = uint16_t(_33); +} + diff --git a/reference/shaders-no-opt/asm/comp/spec-constant-op-convert-sign.asm.comp b/reference/shaders-no-opt/asm/comp/spec-constant-op-convert-sign.asm.comp new file mode 100644 index 00000000..c6aa711f --- /dev/null +++ b/reference/shaders-no-opt/asm/comp/spec-constant-op-convert-sign.asm.comp @@ -0,0 +1,33 @@ +#version 450 +#extension GL_ARB_gpu_shader_int64 : require +layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in; + +#ifndef SPIRV_CROSS_CONSTANT_ID_0 +#define SPIRV_CROSS_CONSTANT_ID_0 1 +#endif +const int ConstantInt = SPIRV_CROSS_CONSTANT_ID_0; +#ifndef SPIRV_CROSS_CONSTANT_ID_1 +#define SPIRV_CROSS_CONSTANT_ID_1 2u +#endif +const uint ConstantUint = SPIRV_CROSS_CONSTANT_ID_1; +const int64_t ConstantInt64_1 = int64_t(ConstantInt); +const int64_t ConstantInt64_2 = int64_t(int(ConstantUint)); +const uint64_t ConstantUint64_1 = uint64_t(ConstantInt); +const uint64_t ConstantUint64_2 = uint64_t(int(ConstantUint)); +const int64_t _20 = (ConstantInt64_1 + ConstantInt64_2); +const uint64_t _21 = (ConstantUint64_1 + ConstantUint64_2); +const int _22 = int(_20); +const uint _23 = uint(_21); + +layout(binding = 0, std430) buffer SSBO +{ + int s64; + uint u64; +} _4; + +void main() +{ + _4.s64 = _22; + _4.u64 = _23; +} + diff --git a/shaders-msl-no-opt/asm/comp/arithmetic-conversion-signs.asm.comp b/shaders-msl-no-opt/asm/comp/arithmetic-conversion-signs.asm.comp new file mode 100644 index 00000000..0e1ce235 --- /dev/null +++ b/shaders-msl-no-opt/asm/comp/arithmetic-conversion-signs.asm.comp @@ -0,0 +1,131 @@ +; SPIR-V +; Version: 1.0 +; Generator: Khronos Glslang Reference Front End; 7 +; Bound: 76 +; Schema: 0 + OpCapability Shader + OpCapability Int16 + OpCapability StorageBuffer16BitAccess + OpExtension "SPV_KHR_16bit_storage" + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %main "main" + OpExecutionMode %main LocalSize 1 1 1 + OpSource GLSL 450 + OpSourceExtension "GL_EXT_shader_explicit_arithmetic_types_int16" + OpName %main "main" + OpName %SSBO "SSBO" + OpMemberName %SSBO 0 "s32" + OpMemberName %SSBO 1 "u32" + OpMemberName %SSBO 2 "s16" + OpMemberName %SSBO 3 "u16" + OpMemberName %SSBO 4 "f32" + OpName %_ "" + OpMemberDecorate %SSBO 0 Offset 0 + OpMemberDecorate %SSBO 1 Offset 4 + OpMemberDecorate %SSBO 2 Offset 8 + OpMemberDecorate %SSBO 3 Offset 10 + OpMemberDecorate %SSBO 4 Offset 12 + OpDecorate %SSBO BufferBlock + OpDecorate %_ DescriptorSet 0 + OpDecorate %_ Binding 0 + %void = OpTypeVoid + %3 = OpTypeFunction %void + %int = OpTypeInt 32 1 + %uint = OpTypeInt 32 0 + %short = OpTypeInt 16 1 + %ushort = OpTypeInt 16 0 + %float = OpTypeFloat 32 + %SSBO = OpTypeStruct %int %uint %short %ushort %float +%_ptr_Uniform_SSBO = OpTypePointer Uniform %SSBO + %_ = OpVariable %_ptr_Uniform_SSBO Uniform + %int_2 = OpConstant %int 2 + %int_0 = OpConstant %int 0 +%_ptr_Uniform_int = OpTypePointer Uniform %int +%_ptr_Uniform_short = OpTypePointer Uniform %short + %int_1 = OpConstant %int 1 +%_ptr_Uniform_uint = OpTypePointer Uniform %uint + %int_3 = OpConstant %int 3 +%_ptr_Uniform_ushort = OpTypePointer Uniform %ushort + %int_4 = OpConstant %int 4 +%_ptr_Uniform_float = OpTypePointer Uniform %float + %main = OpFunction %void None %3 + %5 = OpLabel + %ptr_s32 = OpAccessChain %_ptr_Uniform_int %_ %int_0 + %ptr_u32 = OpAccessChain %_ptr_Uniform_uint %_ %int_1 + %ptr_s16 = OpAccessChain %_ptr_Uniform_short %_ %int_2 + %ptr_u16 = OpAccessChain %_ptr_Uniform_ushort %_ %int_3 + %ptr_f32 = OpAccessChain %_ptr_Uniform_float %_ %int_4 + %s32 = OpLoad %int %ptr_s32 + %u32 = OpLoad %uint %ptr_u32 + %s16 = OpLoad %short %ptr_s16 + %u16 = OpLoad %ushort %ptr_u16 + %f32 = OpLoad %float %ptr_f32 + + ; Sign-extend + %s16_to_s32_signed = OpSConvert %int %s16 + OpStore %ptr_s32 %s16_to_s32_signed + %s16_to_u32_signed = OpSConvert %uint %s16 + OpStore %ptr_u32 %s16_to_u32_signed + + %u16_to_s32_signed = OpSConvert %int %u16 + OpStore %ptr_s32 %u16_to_s32_signed + %u16_to_u32_signed = OpSConvert %uint %u16 + OpStore %ptr_u32 %u16_to_u32_signed + + ; Zero-extend + ; Result must be unsigned for OpUConvert. + ;%s16_to_s32_unsigned = OpUConvert %int %s16 + ;OpStore %ptr_s32 %s16_to_s32_unsigned + %s16_to_u32_unsigned = OpUConvert %uint %s16 + OpStore %ptr_u32 %s16_to_u32_unsigned + + ;%u16_to_s32_unsigned = OpUConvert %int %u16 + ;OpStore %ptr_s32 %u16_to_s32_unsigned + %u16_to_u32_unsigned = OpUConvert %uint %u16 + OpStore %ptr_u32 %u16_to_u32_unsigned + + ; Truncate (SConvert == UConvert) + %s32_to_s16_signed = OpSConvert %short %s32 + OpStore %ptr_s16 %s32_to_s16_signed + %s32_to_u16_signed = OpSConvert %ushort %s32 + OpStore %ptr_u16 %s32_to_u16_signed + + %u32_to_s16_signed = OpSConvert %short %u32 + OpStore %ptr_s16 %u32_to_s16_signed + %u32_to_u16_signed = OpSConvert %ushort %u32 + OpStore %ptr_u16 %u32_to_u16_signed + + ;%s32_to_s16_unsigned = OpUConvert %short %s32 + ;OpStore %ptr_s16 %s32_to_s16_unsigned + %s32_to_u16_unsigned = OpUConvert %ushort %s32 + OpStore %ptr_u16 %s32_to_u16_unsigned + + ;%u32_to_s16_unsigned = OpUConvert %short %u32 + ;OpStore %ptr_s16 %u32_to_s16_unsigned + %u32_to_u16_unsigned = OpUConvert %ushort %u32 + OpStore %ptr_u16 %u32_to_u16_unsigned + + ; SToF + %s16_to_f32_signed = OpConvertSToF %float %s16 + OpStore %ptr_f32 %s16_to_f32_signed + %u16_to_f32_signed = OpConvertSToF %float %u16 + OpStore %ptr_f32 %u16_to_f32_signed + %s16_to_f32_unsigned = OpConvertUToF %float %s16 + OpStore %ptr_f32 %s16_to_f32_unsigned + %u16_to_f32_unsigned = OpConvertUToF %float %u16 + OpStore %ptr_f32 %u16_to_f32_unsigned + + ; FToS + %f32_to_s16_signed = OpConvertFToS %short %f32 + OpStore %ptr_s16 %f32_to_s16_signed + %f32_to_u16_signed = OpConvertFToS %ushort %f32 + OpStore %ptr_u16 %f32_to_u16_signed + + ; FToU + %f32_to_u16_unsigned = OpConvertFToU %ushort %f32 + OpStore %ptr_u16 %f32_to_u16_unsigned + ; Result must be unsigned for FToU, so don't bother testing that. + + OpReturn + OpFunctionEnd diff --git a/shaders-no-opt/asm/comp/arithmetic-conversion-signs.asm.nocompat.vk.comp b/shaders-no-opt/asm/comp/arithmetic-conversion-signs.asm.nocompat.vk.comp new file mode 100644 index 00000000..0e1ce235 --- /dev/null +++ b/shaders-no-opt/asm/comp/arithmetic-conversion-signs.asm.nocompat.vk.comp @@ -0,0 +1,131 @@ +; SPIR-V +; Version: 1.0 +; Generator: Khronos Glslang Reference Front End; 7 +; Bound: 76 +; Schema: 0 + OpCapability Shader + OpCapability Int16 + OpCapability StorageBuffer16BitAccess + OpExtension "SPV_KHR_16bit_storage" + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %main "main" + OpExecutionMode %main LocalSize 1 1 1 + OpSource GLSL 450 + OpSourceExtension "GL_EXT_shader_explicit_arithmetic_types_int16" + OpName %main "main" + OpName %SSBO "SSBO" + OpMemberName %SSBO 0 "s32" + OpMemberName %SSBO 1 "u32" + OpMemberName %SSBO 2 "s16" + OpMemberName %SSBO 3 "u16" + OpMemberName %SSBO 4 "f32" + OpName %_ "" + OpMemberDecorate %SSBO 0 Offset 0 + OpMemberDecorate %SSBO 1 Offset 4 + OpMemberDecorate %SSBO 2 Offset 8 + OpMemberDecorate %SSBO 3 Offset 10 + OpMemberDecorate %SSBO 4 Offset 12 + OpDecorate %SSBO BufferBlock + OpDecorate %_ DescriptorSet 0 + OpDecorate %_ Binding 0 + %void = OpTypeVoid + %3 = OpTypeFunction %void + %int = OpTypeInt 32 1 + %uint = OpTypeInt 32 0 + %short = OpTypeInt 16 1 + %ushort = OpTypeInt 16 0 + %float = OpTypeFloat 32 + %SSBO = OpTypeStruct %int %uint %short %ushort %float +%_ptr_Uniform_SSBO = OpTypePointer Uniform %SSBO + %_ = OpVariable %_ptr_Uniform_SSBO Uniform + %int_2 = OpConstant %int 2 + %int_0 = OpConstant %int 0 +%_ptr_Uniform_int = OpTypePointer Uniform %int +%_ptr_Uniform_short = OpTypePointer Uniform %short + %int_1 = OpConstant %int 1 +%_ptr_Uniform_uint = OpTypePointer Uniform %uint + %int_3 = OpConstant %int 3 +%_ptr_Uniform_ushort = OpTypePointer Uniform %ushort + %int_4 = OpConstant %int 4 +%_ptr_Uniform_float = OpTypePointer Uniform %float + %main = OpFunction %void None %3 + %5 = OpLabel + %ptr_s32 = OpAccessChain %_ptr_Uniform_int %_ %int_0 + %ptr_u32 = OpAccessChain %_ptr_Uniform_uint %_ %int_1 + %ptr_s16 = OpAccessChain %_ptr_Uniform_short %_ %int_2 + %ptr_u16 = OpAccessChain %_ptr_Uniform_ushort %_ %int_3 + %ptr_f32 = OpAccessChain %_ptr_Uniform_float %_ %int_4 + %s32 = OpLoad %int %ptr_s32 + %u32 = OpLoad %uint %ptr_u32 + %s16 = OpLoad %short %ptr_s16 + %u16 = OpLoad %ushort %ptr_u16 + %f32 = OpLoad %float %ptr_f32 + + ; Sign-extend + %s16_to_s32_signed = OpSConvert %int %s16 + OpStore %ptr_s32 %s16_to_s32_signed + %s16_to_u32_signed = OpSConvert %uint %s16 + OpStore %ptr_u32 %s16_to_u32_signed + + %u16_to_s32_signed = OpSConvert %int %u16 + OpStore %ptr_s32 %u16_to_s32_signed + %u16_to_u32_signed = OpSConvert %uint %u16 + OpStore %ptr_u32 %u16_to_u32_signed + + ; Zero-extend + ; Result must be unsigned for OpUConvert. + ;%s16_to_s32_unsigned = OpUConvert %int %s16 + ;OpStore %ptr_s32 %s16_to_s32_unsigned + %s16_to_u32_unsigned = OpUConvert %uint %s16 + OpStore %ptr_u32 %s16_to_u32_unsigned + + ;%u16_to_s32_unsigned = OpUConvert %int %u16 + ;OpStore %ptr_s32 %u16_to_s32_unsigned + %u16_to_u32_unsigned = OpUConvert %uint %u16 + OpStore %ptr_u32 %u16_to_u32_unsigned + + ; Truncate (SConvert == UConvert) + %s32_to_s16_signed = OpSConvert %short %s32 + OpStore %ptr_s16 %s32_to_s16_signed + %s32_to_u16_signed = OpSConvert %ushort %s32 + OpStore %ptr_u16 %s32_to_u16_signed + + %u32_to_s16_signed = OpSConvert %short %u32 + OpStore %ptr_s16 %u32_to_s16_signed + %u32_to_u16_signed = OpSConvert %ushort %u32 + OpStore %ptr_u16 %u32_to_u16_signed + + ;%s32_to_s16_unsigned = OpUConvert %short %s32 + ;OpStore %ptr_s16 %s32_to_s16_unsigned + %s32_to_u16_unsigned = OpUConvert %ushort %s32 + OpStore %ptr_u16 %s32_to_u16_unsigned + + ;%u32_to_s16_unsigned = OpUConvert %short %u32 + ;OpStore %ptr_s16 %u32_to_s16_unsigned + %u32_to_u16_unsigned = OpUConvert %ushort %u32 + OpStore %ptr_u16 %u32_to_u16_unsigned + + ; SToF + %s16_to_f32_signed = OpConvertSToF %float %s16 + OpStore %ptr_f32 %s16_to_f32_signed + %u16_to_f32_signed = OpConvertSToF %float %u16 + OpStore %ptr_f32 %u16_to_f32_signed + %s16_to_f32_unsigned = OpConvertUToF %float %s16 + OpStore %ptr_f32 %s16_to_f32_unsigned + %u16_to_f32_unsigned = OpConvertUToF %float %u16 + OpStore %ptr_f32 %u16_to_f32_unsigned + + ; FToS + %f32_to_s16_signed = OpConvertFToS %short %f32 + OpStore %ptr_s16 %f32_to_s16_signed + %f32_to_u16_signed = OpConvertFToS %ushort %f32 + OpStore %ptr_u16 %f32_to_u16_signed + + ; FToU + %f32_to_u16_unsigned = OpConvertFToU %ushort %f32 + OpStore %ptr_u16 %f32_to_u16_unsigned + ; Result must be unsigned for FToU, so don't bother testing that. + + OpReturn + OpFunctionEnd diff --git a/shaders-no-opt/asm/comp/spec-constant-op-convert-sign.asm.comp b/shaders-no-opt/asm/comp/spec-constant-op-convert-sign.asm.comp new file mode 100644 index 00000000..b7ca1143 --- /dev/null +++ b/shaders-no-opt/asm/comp/spec-constant-op-convert-sign.asm.comp @@ -0,0 +1,63 @@ +; SPIR-V +; Version: 1.0 +; Generator: Khronos Glslang Reference Front End; 7 +; Bound: 30 +; Schema: 0 + OpCapability Shader + OpCapability Int64 + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %main "main" + OpExecutionMode %main LocalSize 1 1 1 + OpSource GLSL 450 + OpSourceExtension "GL_ARB_gpu_shader_int64" + OpName %main "main" + OpName %SSBO "SSBO" + OpMemberName %SSBO 0 "s64" + OpMemberName %SSBO 1 "u64" + OpName %_ "" + OpName %ConstantInt "ConstantInt" + OpName %ConstantInt64_1 "ConstantInt64_1" + OpName %ConstantUint "ConstantUint" + OpName %ConstantInt64_2 "ConstantInt64_2" + OpName %ConstantUint64_1 "ConstantUint64_1" + OpName %ConstantUint64_2 "ConstantUint64_2" + OpMemberDecorate %SSBO 0 Offset 0 + OpMemberDecorate %SSBO 1 Offset 4 + OpDecorate %SSBO BufferBlock + OpDecorate %_ DescriptorSet 0 + OpDecorate %_ Binding 0 + OpDecorate %ConstantInt SpecId 0 + OpDecorate %ConstantUint SpecId 1 + %void = OpTypeVoid + %3 = OpTypeFunction %void + %int = OpTypeInt 32 1 + %uint = OpTypeInt 32 0 + %long = OpTypeInt 64 1 + %ulong = OpTypeInt 64 0 + %SSBO = OpTypeStruct %int %uint +%_ptr_Uniform_SSBO = OpTypePointer Uniform %SSBO + %_ = OpVariable %_ptr_Uniform_SSBO Uniform + %int_0 = OpConstant %int 0 + %ulong_0 = OpConstant %ulong 0 +%ConstantInt = OpSpecConstant %int 1 +%ConstantUint = OpSpecConstant %uint 2 +%ConstantInt64_1 = OpSpecConstantOp %long SConvert %ConstantInt +%ConstantInt64_2 = OpSpecConstantOp %long SConvert %ConstantUint +%ConstantUint64_1 = OpSpecConstantOp %ulong SConvert %ConstantInt +%ConstantUint64_2 = OpSpecConstantOp %ulong SConvert %ConstantUint + %added_long = OpSpecConstantOp %long IAdd %ConstantInt64_1 %ConstantInt64_2 + %added_ulong = OpSpecConstantOp %ulong IAdd %ConstantUint64_1 %ConstantUint64_2 + %trunc_long = OpSpecConstantOp %int SConvert %added_long + %trunc_ulong = OpSpecConstantOp %uint SConvert %added_ulong +%_ptr_Uniform_int = OpTypePointer Uniform %int + %int_1 = OpConstant %int 1 +%_ptr_Uniform_uint = OpTypePointer Uniform %uint + %main = OpFunction %void None %3 + %5 = OpLabel + %22 = OpAccessChain %_ptr_Uniform_int %_ %int_0 + OpStore %22 %trunc_long + %29 = OpAccessChain %_ptr_Uniform_uint %_ %int_1 + OpStore %29 %trunc_ulong + OpReturn + OpFunctionEnd diff --git a/spirv_glsl.cpp b/spirv_glsl.cpp index f15afde6..218396e9 100644 --- a/spirv_glsl.cpp +++ b/spirv_glsl.cpp @@ -2868,7 +2868,7 @@ string CompilerGLSL::constant_op_expression(const SPIRConstantOp &cop) } uint32_t bit_width = 0; - if (unary || binary) + if (unary || binary || cop.opcode == OpSConvert || cop.opcode == OpUConvert) bit_width = expression_type(cop.arguments[0]).width; SPIRType::BaseType input_type; @@ -2888,6 +2888,8 @@ string CompilerGLSL::constant_op_expression(const SPIRConstantOp &cop) case OpSMod: case OpSDiv: case OpShiftRightArithmetic: + case OpSConvert: + case OpSNegate: input_type = to_signed_basetype(bit_width); break; @@ -2898,6 +2900,7 @@ string CompilerGLSL::constant_op_expression(const SPIRConstantOp &cop) case OpUMod: case OpUDiv: case OpShiftRightLogical: + case OpUConvert: input_type = to_unsigned_basetype(bit_width); break; @@ -2939,6 +2942,21 @@ string CompilerGLSL::constant_op_expression(const SPIRConstantOp &cop) // Works around various casting scenarios in glslang as there is no OpBitcast for specialization constants. return join("(", op, bitcast_glsl(type, cop.arguments[0]), ")"); } + else if (cop.opcode == OpSConvert || cop.opcode == OpUConvert) + { + if (cop.arguments.size() < 1) + SPIRV_CROSS_THROW("Not enough arguments to OpSpecConstantOp."); + + auto &arg_type = expression_type(cop.arguments[0]); + if (arg_type.width < type.width && input_type != arg_type.basetype) + { + auto expected = arg_type; + expected.basetype = input_type; + return join(op, "(", bitcast_glsl(expected, cop.arguments[0]), ")"); + } + else + return join(op, "(", to_expression(cop.arguments[0]), ")"); + } else { if (cop.arguments.size() < 1) @@ -3822,15 +3840,19 @@ void CompilerGLSL::emit_unary_func_op_cast(uint32_t result_type, uint32_t result SPIRType::BaseType input_type, SPIRType::BaseType expected_result_type) { auto &out_type = get(result_type); + auto &expr_type = expression_type(op0); auto expected_type = out_type; + + // Bit-widths might be different in unary cases because we use it for SConvert/UConvert and friends. expected_type.basetype = input_type; - string cast_op = - expression_type(op0).basetype != input_type ? bitcast_glsl(expected_type, op0) : to_expression(op0); + expected_type.width = expr_type.width; + string cast_op = expr_type.basetype != input_type ? bitcast_glsl(expected_type, op0) : to_unpacked_expression(op0); string expr; if (out_type.basetype != expected_result_type) { expected_type.basetype = expected_result_type; + expected_type.width = out_type.width; expr = bitcast_glsl_op(out_type, expected_type); expr += '('; expr += join(op, "(", cast_op, ")"); @@ -3852,11 +3874,11 @@ void CompilerGLSL::emit_trinary_func_op_cast(uint32_t result_type, uint32_t resu auto expected_type = out_type; expected_type.basetype = input_type; string cast_op0 = - expression_type(op0).basetype != input_type ? bitcast_glsl(expected_type, op0) : to_expression(op0); + expression_type(op0).basetype != input_type ? bitcast_glsl(expected_type, op0) : to_unpacked_expression(op0); string cast_op1 = - expression_type(op1).basetype != input_type ? bitcast_glsl(expected_type, op1) : to_expression(op1); + expression_type(op1).basetype != input_type ? bitcast_glsl(expected_type, op1) : to_unpacked_expression(op1); string cast_op2 = - expression_type(op2).basetype != input_type ? bitcast_glsl(expected_type, op2) : to_expression(op2); + expression_type(op2).basetype != input_type ? bitcast_glsl(expected_type, op2) : to_unpacked_expression(op2); string expr; if (out_type.basetype != input_type) @@ -5622,9 +5644,9 @@ string CompilerGLSL::bitcast_glsl(const SPIRType &result_type, uint32_t argument { auto op = bitcast_glsl_op(result_type, expression_type(argument)); if (op.empty()) - return to_enclosed_expression(argument); + return to_enclosed_unpacked_expression(argument); else - return join(op, "(", to_expression(argument), ")"); + return join(op, "(", to_unpacked_expression(argument), ")"); } std::string CompilerGLSL::bitcast_expression(SPIRType::BaseType target_type, uint32_t arg) @@ -7077,6 +7099,10 @@ uint32_t CompilerGLSL::get_integer_width_for_instruction(const Instruction &inst switch (instr.op) { + case OpSConvert: + case OpConvertSToF: + case OpUConvert: + case OpConvertUToF: case OpIEqual: case OpINotEqual: case OpSLessThan: @@ -8150,12 +8176,45 @@ void CompilerGLSL::emit_instruction(const Instruction &instruction) } // Conversion + case OpSConvert: + case OpConvertSToF: + case OpUConvert: + case OpConvertUToF: + { + auto input_type = opcode == OpSConvert || opcode == OpConvertSToF ? int_type : uint_type; + uint32_t result_type = ops[0]; + uint32_t id = ops[1]; + + auto &type = get(result_type); + auto &arg_type = expression_type(ops[2]); + auto func = type_to_glsl_constructor(type); + + // If we're sign-extending or zero-extending, we need to make sure we cast from the correct type. + // For truncation, it does not matter, so don't emit useless casts. + if (arg_type.width < type.width) + emit_unary_func_op_cast(result_type, id, ops[2], func.c_str(), input_type, type.basetype); + else + emit_unary_func_op(result_type, id, ops[2], func.c_str()); + break; + } + case OpConvertFToU: case OpConvertFToS: - case OpConvertSToF: - case OpConvertUToF: - case OpUConvert: - case OpSConvert: + { + // Cast to expected arithmetic type, then potentially bitcast away to desired signedness. + uint32_t result_type = ops[0]; + uint32_t id = ops[1]; + auto &type = get(result_type); + auto expected_type = type; + auto &float_type = expression_type(ops[2]); + expected_type.basetype = + opcode == OpConvertFToS ? to_signed_basetype(type.width) : to_unsigned_basetype(type.width); + + auto func = type_to_glsl_constructor(expected_type); + emit_unary_func_op_cast(result_type, id, ops[2], func.c_str(), float_type.basetype, expected_type.basetype); + break; + } + case OpFConvert: { uint32_t result_type = ops[0]; diff --git a/test_shaders.py b/test_shaders.py index cf17bcdf..69dde98e 100755 --- a/test_shaders.py +++ b/test_shaders.py @@ -404,7 +404,7 @@ def regression_check_reflect(shader, json_file, args): with open(reference) as f: expected = json.load(f) if (json_compare(actual, expected) != True): - if update: + if args.update: print('Generated reflection json has changed for {}!'.format(reference)) # If we expect changes, update the reference file. if os.path.exists(reference): @@ -440,7 +440,7 @@ def regression_check(shader, glsl, args): if os.path.exists(reference): if md5_for_file(glsl) != md5_for_file(reference): - if update: + if args.update: print('Generated source code has changed for {}!'.format(reference)) # If we expect changes, update the reference file. if os.path.exists(reference):