Skip to content

Commit bd6f2ec

Browse files
feat(const_eval): impl. firstTrailingBit
1 parent cbeac7d commit bd6f2ec

File tree

6 files changed

+148
-80
lines changed

6 files changed

+148
-80
lines changed

naga/src/proc/constant_evaluator.rs

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1233,6 +1233,9 @@ impl<'a> ConstantEvaluator<'a> {
12331233
crate::MathFunction::ReverseBits => {
12341234
component_wise_concrete_int!(self, span, [arg], |e| { Ok([e.reverse_bits()]) })
12351235
}
1236+
crate::MathFunction::FirstTrailingBit => {
1237+
component_wise_concrete_int(self, span, [arg], |ci| Ok(first_trailing_bit(ci)))
1238+
}
12361239
crate::MathFunction::FirstLeadingBit => {
12371240
component_wise_concrete_int(self, span, [arg], |ci| Ok(first_leading_bit(ci)))
12381241
}
@@ -2101,6 +2104,86 @@ impl<'a> ConstantEvaluator<'a> {
21012104
}
21022105
}
21032106

2107+
fn first_trailing_bit(concrete_int: ConcreteInt<1>) -> ConcreteInt<1> {
2108+
// NOTE: Bit indices for this built-in start at 0 at the "right" (or LSB). For example, a value
2109+
// of 1 means the least significant bit is set. Therefore, an input of `0x[80 00…]` would
2110+
// return a right-to-left bit index of 0.
2111+
let trailing_zeros_to_bit_idx = |e: u32| -> u32 {
2112+
match e {
2113+
idx @ 0..=31 => idx,
2114+
32 => u32::MAX,
2115+
_ => panic!("invalid `trailing_zeros` values"),
2116+
}
2117+
};
2118+
match concrete_int {
2119+
ConcreteInt::U32([e]) => ConcreteInt::U32([trailing_zeros_to_bit_idx(e.trailing_zeros())]),
2120+
ConcreteInt::I32([e]) => {
2121+
ConcreteInt::I32([trailing_zeros_to_bit_idx(e.trailing_zeros()) as i32])
2122+
}
2123+
}
2124+
}
2125+
2126+
#[test]
2127+
fn first_trailing_bit_smoke() {
2128+
assert_eq!(
2129+
first_trailing_bit(ConcreteInt::I32([0])),
2130+
ConcreteInt::I32([-1])
2131+
);
2132+
assert_eq!(
2133+
first_trailing_bit(ConcreteInt::I32([1])),
2134+
ConcreteInt::I32([0])
2135+
);
2136+
assert_eq!(
2137+
first_trailing_bit(ConcreteInt::I32([2])),
2138+
ConcreteInt::I32([1])
2139+
);
2140+
assert_eq!(
2141+
first_trailing_bit(ConcreteInt::I32([-1])),
2142+
ConcreteInt::I32([0]),
2143+
);
2144+
assert_eq!(
2145+
first_trailing_bit(ConcreteInt::I32([i32::MIN])),
2146+
ConcreteInt::I32([31]),
2147+
);
2148+
assert_eq!(
2149+
first_trailing_bit(ConcreteInt::I32([i32::MAX])),
2150+
ConcreteInt::I32([0]),
2151+
);
2152+
for idx in 0..32 {
2153+
assert_eq!(
2154+
first_trailing_bit(ConcreteInt::I32([1 << idx])),
2155+
ConcreteInt::I32([idx])
2156+
)
2157+
}
2158+
2159+
assert_eq!(
2160+
first_trailing_bit(ConcreteInt::U32([0])),
2161+
ConcreteInt::U32([u32::MAX])
2162+
);
2163+
assert_eq!(
2164+
first_trailing_bit(ConcreteInt::U32([1])),
2165+
ConcreteInt::U32([0])
2166+
);
2167+
assert_eq!(
2168+
first_trailing_bit(ConcreteInt::U32([2])),
2169+
ConcreteInt::U32([1])
2170+
);
2171+
assert_eq!(
2172+
first_trailing_bit(ConcreteInt::U32([1 << 31])),
2173+
ConcreteInt::U32([31]),
2174+
);
2175+
assert_eq!(
2176+
first_trailing_bit(ConcreteInt::U32([u32::MAX])),
2177+
ConcreteInt::U32([0]),
2178+
);
2179+
for idx in 0..32 {
2180+
assert_eq!(
2181+
first_trailing_bit(ConcreteInt::U32([1 << idx])),
2182+
ConcreteInt::U32([idx])
2183+
)
2184+
}
2185+
}
2186+
21042187
fn first_leading_bit(concrete_int: ConcreteInt<1>) -> ConcreteInt<1> {
21052188
// NOTE: Bit indices for this built-in start at 0 at the "right" (or LSB). For example, 1 means
21062189
// the least significant bit is set. Therefore, an input of 1 would return a right-to-left bit

naga/tests/out/glsl/math-functions.main.Fragment.glsl

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -67,10 +67,8 @@ void main() {
6767
int const_dot = ( + ivec2(0).x * ivec2(0).x + ivec2(0).y * ivec2(0).y);
6868
ivec2 flb_b = ivec2(-1, -1);
6969
uvec2 flb_c = uvec2(0u, 0u);
70-
int ftb_a = findLSB(-1);
71-
uint ftb_b = uint(findLSB(1u));
72-
ivec2 ftb_c = findLSB(ivec2(-1));
73-
uvec2 ftb_d = uvec2(findLSB(uvec2(1u)));
70+
ivec2 ftb_c = ivec2(0, 0);
71+
uvec2 ftb_d = uvec2(0u, 0u);
7472
uvec2 ctz_e = uvec2(32u, 32u);
7573
ivec2 ctz_f = ivec2(32, 32);
7674
uvec2 ctz_g = uvec2(0u, 0u);

naga/tests/out/hlsl/math-functions.hlsl

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -81,10 +81,8 @@ void main()
8181
int const_dot = dot(ZeroValueint2(), ZeroValueint2());
8282
int2 flb_b = int2(-1, -1);
8383
uint2 flb_c = uint2(0u, 0u);
84-
int ftb_a = asint(firstbitlow(-1));
85-
uint ftb_b = firstbitlow(1u);
86-
int2 ftb_c = asint(firstbitlow((-1).xx));
87-
uint2 ftb_d = firstbitlow((1u).xx);
84+
int2 ftb_c = int2(0, 0);
85+
uint2 ftb_d = uint2(0u, 0u);
8886
uint2 ctz_e = uint2(32u, 32u);
8987
int2 ctz_f = int2(32, 32);
9088
uint2 ctz_g = uint2(0u, 0u);

naga/tests/out/msl/math-functions.msl

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -69,10 +69,8 @@ fragment void main_(
6969
int const_dot = ( + metal::int2 {}.x * metal::int2 {}.x + metal::int2 {}.y * metal::int2 {}.y);
7070
metal::int2 flb_b = metal::int2(-1, -1);
7171
metal::uint2 flb_c = metal::uint2(0u, 0u);
72-
int ftb_a = (((metal::ctz(-1) + 1) % 33) - 1);
73-
uint ftb_b = (((metal::ctz(1u) + 1) % 33) - 1);
74-
metal::int2 ftb_c = (((metal::ctz(metal::int2(-1)) + 1) % 33) - 1);
75-
metal::uint2 ftb_d = (((metal::ctz(metal::uint2(1u)) + 1) % 33) - 1);
72+
metal::int2 ftb_c = metal::int2(0, 0);
73+
metal::uint2 ftb_d = metal::uint2(0u, 0u);
7674
metal::uint2 ctz_e = metal::uint2(32u, 32u);
7775
metal::int2 ctz_f = metal::int2(32, 32);
7876
metal::uint2 ctz_g = metal::uint2(0u, 0u);
Lines changed: 57 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
; SPIR-V
22
; Version: 1.1
33
; Generator: rspirv
4-
; Bound: 94
4+
; Bound: 87
55
OpCapability Shader
66
%1 = OpExtInstImport "GLSL.std.450"
77
OpMemoryModel Logical GLSL450
@@ -44,71 +44,64 @@ OpMemberDecorate %15 1 Offset 16
4444
%28 = OpConstantComposite %7 %22 %22
4545
%29 = OpConstant %9 0
4646
%30 = OpConstantComposite %8 %29 %29
47-
%31 = OpConstant %9 1
48-
%32 = OpConstantComposite %7 %22 %22
49-
%33 = OpConstantComposite %8 %31 %31
50-
%34 = OpConstant %9 32
51-
%35 = OpConstant %6 32
52-
%36 = OpConstant %6 0
53-
%37 = OpConstantComposite %8 %34 %34
54-
%38 = OpConstantComposite %7 %35 %35
55-
%39 = OpConstantComposite %7 %36 %36
56-
%40 = OpConstant %9 31
57-
%41 = OpConstantComposite %8 %40 %40
58-
%42 = OpConstant %6 2
59-
%43 = OpConstant %4 2.0
60-
%44 = OpConstantComposite %10 %19 %43
61-
%45 = OpConstant %6 3
62-
%46 = OpConstant %6 4
63-
%47 = OpConstantComposite %7 %45 %46
64-
%48 = OpConstant %4 1.5
65-
%49 = OpConstantComposite %10 %48 %48
66-
%50 = OpConstantComposite %3 %48 %48 %48 %48
67-
%57 = OpConstantComposite %3 %19 %19 %19 %19
68-
%60 = OpConstantNull %6
47+
%31 = OpConstant %6 0
48+
%32 = OpConstantComposite %7 %31 %31
49+
%33 = OpConstant %9 32
50+
%34 = OpConstant %6 32
51+
%35 = OpConstantComposite %8 %33 %33
52+
%36 = OpConstantComposite %7 %34 %34
53+
%37 = OpConstant %9 31
54+
%38 = OpConstantComposite %8 %37 %37
55+
%39 = OpConstant %6 2
56+
%40 = OpConstant %4 2.0
57+
%41 = OpConstantComposite %10 %19 %40
58+
%42 = OpConstant %6 3
59+
%43 = OpConstant %6 4
60+
%44 = OpConstantComposite %7 %42 %43
61+
%45 = OpConstant %4 1.5
62+
%46 = OpConstantComposite %10 %45 %45
63+
%47 = OpConstantComposite %3 %45 %45 %45 %45
64+
%54 = OpConstantComposite %3 %19 %19 %19 %19
65+
%57 = OpConstantNull %6
6966
%17 = OpFunction %2 None %18
7067
%16 = OpLabel
71-
OpBranch %51
72-
%51 = OpLabel
73-
%52 = OpExtInst %4 %1 Degrees %19
74-
%53 = OpExtInst %4 %1 Radians %19
75-
%54 = OpExtInst %3 %1 Degrees %21
76-
%55 = OpExtInst %3 %1 Radians %21
77-
%56 = OpExtInst %3 %1 FClamp %21 %21 %57
78-
%58 = OpExtInst %3 %1 Refract %21 %21 %19
79-
%61 = OpCompositeExtract %6 %26 0
80-
%62 = OpCompositeExtract %6 %26 0
81-
%63 = OpIMul %6 %61 %62
82-
%64 = OpIAdd %6 %60 %63
83-
%65 = OpCompositeExtract %6 %26 1
84-
%66 = OpCompositeExtract %6 %26 1
85-
%67 = OpIMul %6 %65 %66
86-
%59 = OpIAdd %6 %64 %67
87-
%68 = OpExtInst %6 %1 FindILsb %22
88-
%69 = OpExtInst %9 %1 FindILsb %31
89-
%70 = OpExtInst %7 %1 FindILsb %32
90-
%71 = OpExtInst %8 %1 FindILsb %33
91-
%72 = OpExtInst %4 %1 Ldexp %19 %42
92-
%73 = OpExtInst %10 %1 Ldexp %44 %47
93-
%74 = OpExtInst %11 %1 ModfStruct %48
94-
%75 = OpExtInst %11 %1 ModfStruct %48
95-
%76 = OpCompositeExtract %4 %75 0
96-
%77 = OpExtInst %11 %1 ModfStruct %48
68+
OpBranch %48
69+
%48 = OpLabel
70+
%49 = OpExtInst %4 %1 Degrees %19
71+
%50 = OpExtInst %4 %1 Radians %19
72+
%51 = OpExtInst %3 %1 Degrees %21
73+
%52 = OpExtInst %3 %1 Radians %21
74+
%53 = OpExtInst %3 %1 FClamp %21 %21 %54
75+
%55 = OpExtInst %3 %1 Refract %21 %21 %19
76+
%58 = OpCompositeExtract %6 %26 0
77+
%59 = OpCompositeExtract %6 %26 0
78+
%60 = OpIMul %6 %58 %59
79+
%61 = OpIAdd %6 %57 %60
80+
%62 = OpCompositeExtract %6 %26 1
81+
%63 = OpCompositeExtract %6 %26 1
82+
%64 = OpIMul %6 %62 %63
83+
%56 = OpIAdd %6 %61 %64
84+
%65 = OpExtInst %4 %1 Ldexp %19 %39
85+
%66 = OpExtInst %10 %1 Ldexp %41 %44
86+
%67 = OpExtInst %11 %1 ModfStruct %45
87+
%68 = OpExtInst %11 %1 ModfStruct %45
88+
%69 = OpCompositeExtract %4 %68 0
89+
%70 = OpExtInst %11 %1 ModfStruct %45
90+
%71 = OpCompositeExtract %4 %70 1
91+
%72 = OpExtInst %12 %1 ModfStruct %46
92+
%73 = OpExtInst %13 %1 ModfStruct %47
93+
%74 = OpCompositeExtract %3 %73 1
94+
%75 = OpCompositeExtract %4 %74 0
95+
%76 = OpExtInst %12 %1 ModfStruct %46
96+
%77 = OpCompositeExtract %10 %76 0
9797
%78 = OpCompositeExtract %4 %77 1
98-
%79 = OpExtInst %12 %1 ModfStruct %49
99-
%80 = OpExtInst %13 %1 ModfStruct %50
100-
%81 = OpCompositeExtract %3 %80 1
101-
%82 = OpCompositeExtract %4 %81 0
102-
%83 = OpExtInst %12 %1 ModfStruct %49
103-
%84 = OpCompositeExtract %10 %83 0
104-
%85 = OpCompositeExtract %4 %84 1
105-
%86 = OpExtInst %14 %1 FrexpStruct %48
106-
%87 = OpExtInst %14 %1 FrexpStruct %48
107-
%88 = OpCompositeExtract %4 %87 0
108-
%89 = OpExtInst %14 %1 FrexpStruct %48
109-
%90 = OpCompositeExtract %6 %89 1
110-
%91 = OpExtInst %15 %1 FrexpStruct %50
111-
%92 = OpCompositeExtract %5 %91 1
112-
%93 = OpCompositeExtract %6 %92 0
98+
%79 = OpExtInst %14 %1 FrexpStruct %45
99+
%80 = OpExtInst %14 %1 FrexpStruct %45
100+
%81 = OpCompositeExtract %4 %80 0
101+
%82 = OpExtInst %14 %1 FrexpStruct %45
102+
%83 = OpCompositeExtract %6 %82 1
103+
%84 = OpExtInst %15 %1 FrexpStruct %47
104+
%85 = OpCompositeExtract %5 %84 1
105+
%86 = OpCompositeExtract %6 %85 0
113106
OpReturn
114107
OpFunctionEnd

naga/tests/out/wgsl/math-functions.wgsl

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,8 @@ fn main() {
1212
let const_dot = dot(vec2<i32>(), vec2<i32>());
1313
let flb_b = vec2<i32>(-1i, -1i);
1414
let flb_c = vec2<u32>(0u, 0u);
15-
let ftb_a = firstTrailingBit(-1i);
16-
let ftb_b = firstTrailingBit(1u);
17-
let ftb_c = firstTrailingBit(vec2(-1i));
18-
let ftb_d = firstTrailingBit(vec2(1u));
15+
let ftb_c = vec2<i32>(0i, 0i);
16+
let ftb_d = vec2<u32>(0u, 0u);
1917
let ctz_e = vec2<u32>(32u, 32u);
2018
let ctz_f = vec2<i32>(32i, 32i);
2119
let ctz_g = vec2<u32>(0u, 0u);

0 commit comments

Comments
 (0)