Skip to content

Commit 7b6ff5f

Browse files
authored
[naga wgsl-out] Represent min value i64 literals as -9223372036854775807li - 1li (gfx-rs#7424)
ie the second-most negative value minus 1. The most negative value of an integer type is not directly expressible in WGSL, as it relies on applying the unary negation operator to a value which is one larger than the largest value representable by the type. To avoid this issue for i32, we negate the required value as an AbstractInt before converting to i32. AbstractInt, being 64 bits, is capable of representing the maximum i32 value + 1. However, for i64 this is not the case. Instead this patch makes us express the mimimum i64 value as the second most negative i64 value, minus 1, ie `-9223372036854775807li - 1li`, thereby avoiding the issue.
1 parent 94dd3a7 commit 7b6ff5f

File tree

6 files changed

+383
-370
lines changed

6 files changed

+383
-370
lines changed

naga/src/back/wgsl/writer.rs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1147,11 +1147,12 @@ impl<W: Write> Writer<W> {
11471147
crate::Literal::Bool(value) => write!(self.out, "{value}")?,
11481148
crate::Literal::F64(value) => write!(self.out, "{value:?}lf")?,
11491149
crate::Literal::I64(value) => {
1150-
// `-9223372036854775808li` is not valid WGSL. The most negative `i64`
1151-
// value can only be expressed in WGSL using AbstractInt and
1152-
// a unary negation operator.
1150+
// `-9223372036854775808li` is not valid WGSL. Nor can we use the AbstractInt
1151+
// trick above, as AbstractInt also cannot represent `9223372036854775808`.
1152+
// The most negative `i64` value can only be expressed in WGSL using
1153+
// subtracting 1 from the second most negative value.
11531154
if value == i64::MIN {
1154-
write!(self.out, "i64({value})")?;
1155+
write!(self.out, "{}li - 1li", value + 1)?;
11551156
} else {
11561157
write!(self.out, "{value}li")?;
11571158
}

naga/tests/in/wgsl/int64.wgsl

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,8 @@ fn int64_function(x: i64) -> i64 {
5555
val += bitcast<vec2<i64>>(input_uniform.val_u64_2).y;
5656
val += bitcast<vec3<i64>>(input_uniform.val_u64_3).z;
5757
val += bitcast<vec4<i64>>(input_uniform.val_u64_4).w;
58+
// Most negative i64
59+
val += -9223372036854775807li - 1li;
5860

5961
// Reading/writing to a uniform/storage buffer
6062
output.val_i64 = input_uniform.val_i64 + input_storage.val_i64;

naga/tests/out/hlsl/int64.hlsl

Lines changed: 32 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -95,49 +95,51 @@ int64_t int64_function(int64_t x)
9595
uint64_t4 _e71 = input_uniform.val_u64_4_;
9696
int64_t _e74 = val;
9797
val = (_e74 + _e71.w);
98-
int64_t _e80 = input_uniform.val_i64_;
99-
int64_t _e83 = input_storage.Load<int64_t>(128);
100-
output.Store(128, (_e80 + _e83));
101-
int64_t2 _e89 = input_uniform.val_i64_2_;
102-
int64_t2 _e92 = input_storage.Load<int64_t2>(144);
103-
output.Store(144, (_e89 + _e92));
104-
int64_t3 _e98 = input_uniform.val_i64_3_;
105-
int64_t3 _e101 = input_storage.Load<int64_t3>(160);
106-
output.Store(160, (_e98 + _e101));
107-
int64_t4 _e107 = input_uniform.val_i64_4_;
108-
int64_t4 _e110 = input_storage.Load<int64_t4>(192);
109-
output.Store(192, (_e107 + _e110));
110-
int64_t _e116[2] = Constructarray2_int64_t_(input_arrays.Load<int64_t>(16+0), input_arrays.Load<int64_t>(16+8));
98+
int64_t _e79 = val;
99+
val = (_e79 + (-9223372036854775807L - 1L));
100+
int64_t _e85 = input_uniform.val_i64_;
101+
int64_t _e88 = input_storage.Load<int64_t>(128);
102+
output.Store(128, (_e85 + _e88));
103+
int64_t2 _e94 = input_uniform.val_i64_2_;
104+
int64_t2 _e97 = input_storage.Load<int64_t2>(144);
105+
output.Store(144, (_e94 + _e97));
106+
int64_t3 _e103 = input_uniform.val_i64_3_;
107+
int64_t3 _e106 = input_storage.Load<int64_t3>(160);
108+
output.Store(160, (_e103 + _e106));
109+
int64_t4 _e112 = input_uniform.val_i64_4_;
110+
int64_t4 _e115 = input_storage.Load<int64_t4>(192);
111+
output.Store(192, (_e112 + _e115));
112+
int64_t _e121[2] = Constructarray2_int64_t_(input_arrays.Load<int64_t>(16+0), input_arrays.Load<int64_t>(16+8));
111113
{
112-
int64_t _value2[2] = _e116;
114+
int64_t _value2[2] = _e121;
113115
output_arrays.Store(16+0, _value2[0]);
114116
output_arrays.Store(16+8, _value2[1]);
115117
}
116-
int64_t _e117 = val;
117-
int64_t _e119 = val;
118-
val = (_e119 + abs(_e117));
119-
int64_t _e121 = val;
120118
int64_t _e122 = val;
121-
int64_t _e123 = val;
122-
int64_t _e125 = val;
123-
val = (_e125 + clamp(_e121, _e122, _e123));
119+
int64_t _e124 = val;
120+
val = (_e124 + abs(_e122));
121+
int64_t _e126 = val;
124122
int64_t _e127 = val;
125-
int64_t _e129 = val;
123+
int64_t _e128 = val;
124+
int64_t _e130 = val;
125+
val = (_e130 + clamp(_e126, _e127, _e128));
126126
int64_t _e132 = val;
127-
val = (_e132 + dot((_e127).xx, (_e129).xx));
128127
int64_t _e134 = val;
129-
int64_t _e135 = val;
130128
int64_t _e137 = val;
131-
val = (_e137 + max(_e134, _e135));
129+
val = (_e137 + dot((_e132).xx, (_e134).xx));
132130
int64_t _e139 = val;
133131
int64_t _e140 = val;
134132
int64_t _e142 = val;
135-
val = (_e142 + min(_e139, _e140));
133+
val = (_e142 + max(_e139, _e140));
136134
int64_t _e144 = val;
137-
int64_t _e146 = val;
138-
val = (_e146 + sign(_e144));
139-
int64_t _e148 = val;
140-
return _e148;
135+
int64_t _e145 = val;
136+
int64_t _e147 = val;
137+
val = (_e147 + min(_e144, _e145));
138+
int64_t _e149 = val;
139+
int64_t _e151 = val;
140+
val = (_e151 + sign(_e149));
141+
int64_t _e153 = val;
142+
return _e153;
141143
}
142144

143145
typedef uint64_t ret_Constructarray2_uint64_t_[2];

naga/tests/out/msl/int64.msl

Lines changed: 34 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -79,47 +79,49 @@ long int64_function(
7979
metal::ulong4 _e71 = input_uniform.val_u64_4_;
8080
long _e74 = val;
8181
val = as_type<long>(as_type<ulong>(_e74) + as_type<ulong>(as_type<metal::long4>(_e71).w));
82-
long _e80 = input_uniform.val_i64_;
83-
long _e83 = input_storage.val_i64_;
84-
output.val_i64_ = as_type<long>(as_type<ulong>(_e80) + as_type<ulong>(_e83));
85-
metal::long2 _e89 = input_uniform.val_i64_2_;
86-
metal::long2 _e92 = input_storage.val_i64_2_;
87-
output.val_i64_2_ = as_type<metal::long2>(as_type<metal::ulong2>(_e89) + as_type<metal::ulong2>(_e92));
88-
metal::long3 _e98 = input_uniform.val_i64_3_;
89-
metal::long3 _e101 = input_storage.val_i64_3_;
90-
output.val_i64_3_ = as_type<metal::long3>(as_type<metal::ulong3>(_e98) + as_type<metal::ulong3>(_e101));
91-
metal::long4 _e107 = input_uniform.val_i64_4_;
92-
metal::long4 _e110 = input_storage.val_i64_4_;
93-
output.val_i64_4_ = as_type<metal::long4>(as_type<metal::ulong4>(_e107) + as_type<metal::ulong4>(_e110));
94-
type_12 _e116 = input_arrays.val_i64_array_2_;
95-
output_arrays.val_i64_array_2_ = _e116;
96-
long _e117 = val;
97-
long _e119 = val;
98-
val = as_type<long>(as_type<ulong>(_e119) + as_type<ulong>(naga_abs(_e117)));
99-
long _e121 = val;
82+
long _e79 = val;
83+
val = as_type<long>(as_type<ulong>(_e79) + as_type<ulong>(as_type<long>(as_type<ulong>(-9223372036854775807L) - as_type<ulong>(1L))));
84+
long _e85 = input_uniform.val_i64_;
85+
long _e88 = input_storage.val_i64_;
86+
output.val_i64_ = as_type<long>(as_type<ulong>(_e85) + as_type<ulong>(_e88));
87+
metal::long2 _e94 = input_uniform.val_i64_2_;
88+
metal::long2 _e97 = input_storage.val_i64_2_;
89+
output.val_i64_2_ = as_type<metal::long2>(as_type<metal::ulong2>(_e94) + as_type<metal::ulong2>(_e97));
90+
metal::long3 _e103 = input_uniform.val_i64_3_;
91+
metal::long3 _e106 = input_storage.val_i64_3_;
92+
output.val_i64_3_ = as_type<metal::long3>(as_type<metal::ulong3>(_e103) + as_type<metal::ulong3>(_e106));
93+
metal::long4 _e112 = input_uniform.val_i64_4_;
94+
metal::long4 _e115 = input_storage.val_i64_4_;
95+
output.val_i64_4_ = as_type<metal::long4>(as_type<metal::ulong4>(_e112) + as_type<metal::ulong4>(_e115));
96+
type_12 _e121 = input_arrays.val_i64_array_2_;
97+
output_arrays.val_i64_array_2_ = _e121;
10098
long _e122 = val;
101-
long _e123 = val;
102-
long _e125 = val;
103-
val = as_type<long>(as_type<ulong>(_e125) + as_type<ulong>(metal::clamp(_e121, _e122, _e123)));
99+
long _e124 = val;
100+
val = as_type<long>(as_type<ulong>(_e124) + as_type<ulong>(naga_abs(_e122)));
101+
long _e126 = val;
104102
long _e127 = val;
105-
metal::long2 _e128 = metal::long2(_e127);
106-
long _e129 = val;
107-
metal::long2 _e130 = metal::long2(_e129);
103+
long _e128 = val;
104+
long _e130 = val;
105+
val = as_type<long>(as_type<ulong>(_e130) + as_type<ulong>(metal::clamp(_e126, _e127, _e128)));
108106
long _e132 = val;
109-
val = as_type<long>(as_type<ulong>(_e132) + as_type<ulong>(( + _e128.x * _e130.x + _e128.y * _e130.y)));
107+
metal::long2 _e133 = metal::long2(_e132);
110108
long _e134 = val;
111-
long _e135 = val;
109+
metal::long2 _e135 = metal::long2(_e134);
112110
long _e137 = val;
113-
val = as_type<long>(as_type<ulong>(_e137) + as_type<ulong>(metal::max(_e134, _e135)));
111+
val = as_type<long>(as_type<ulong>(_e137) + as_type<ulong>(( + _e133.x * _e135.x + _e133.y * _e135.y)));
114112
long _e139 = val;
115113
long _e140 = val;
116114
long _e142 = val;
117-
val = as_type<long>(as_type<ulong>(_e142) + as_type<ulong>(metal::min(_e139, _e140)));
115+
val = as_type<long>(as_type<ulong>(_e142) + as_type<ulong>(metal::max(_e139, _e140)));
118116
long _e144 = val;
119-
long _e146 = val;
120-
val = as_type<long>(as_type<ulong>(_e146) + as_type<ulong>(metal::select(metal::select(long(-1), long(1), (_e144 > 0)), long(0), (_e144 == 0))));
121-
long _e148 = val;
122-
return _e148;
117+
long _e145 = val;
118+
long _e147 = val;
119+
val = as_type<long>(as_type<ulong>(_e147) + as_type<ulong>(metal::min(_e144, _e145)));
120+
long _e149 = val;
121+
long _e151 = val;
122+
val = as_type<long>(as_type<ulong>(_e151) + as_type<ulong>(metal::select(metal::select(long(-1), long(1), (_e149 > 0)), long(0), (_e149 == 0))));
123+
long _e153 = val;
124+
return _e153;
123125
}
124126

125127
ulong uint64_function(

0 commit comments

Comments
 (0)