@@ -82,93 +82,120 @@ function _simd_scan_ir(t, pred)
8282 """
8383end
8484
85- const FFE_IR = _simd_scan_ir (" i64" , " eq" )
86-
87- function _findfirstequal (vpivot:: Int64 , ptr:: Ptr{Int64} , len:: Int64 )
88- return Base. llvmcall (
89- (FFE_IR, " entry" ),
90- Int64,
91- Tuple{Int64, Ptr{Int64}, Int64},
92- vpivot,
93- ptr,
94- len
95- )
85+ # Portable scalar implementation of the primitives' contract: the 0-based
86+ # offset of the first element with `pred(v[i], x)`, or -1 if there is none.
87+ # Backs the primitives on non-64-bit platforms, where the SIMD kernels
88+ # (64-bit lengths and pointer lowering) are unavailable.
89+ function _scalar_first (pred:: P , x:: T , ptr:: Ptr{T} , len:: Int64 ) where {P, T}
90+ for i in 1 : len
91+ pred (unsafe_load (ptr, i), x) && return i - 1
92+ end
93+ return Int64 (- 1 )
9694end
9795
98- const _SIMD_GT_I64_IR = _simd_scan_ir (" i64" , " sgt" )
99- const _SIMD_GE_I64_IR = _simd_scan_ir (" i64" , " sge" )
100- const _SIMD_GT_F64_IR = _simd_scan_ir (" double" , " ogt" )
101- const _SIMD_GE_F64_IR = _simd_scan_ir (" double" , " oge" )
102-
103- # Reverse-direction predicates: used by `SIMDLinearScan` under
104- # `Base.Order.Reverse` ordering, where the array is decreasing and we want
105- # to find the first lane where `v[i] < x` (searchsortedlast) or `v[i] <= x`
106- # (searchsortedfirst).
107- const _SIMD_LT_I64_IR = _simd_scan_ir (" i64" , " slt" )
108- const _SIMD_LE_I64_IR = _simd_scan_ir (" i64" , " sle" )
109- const _SIMD_LT_F64_IR = _simd_scan_ir (" double" , " olt" )
110- const _SIMD_LE_F64_IR = _simd_scan_ir (" double" , " ole" )
111-
112- # Backing primitives for SIMDLinearScan. Each returns the 0-based offset of
113- # the first lane satisfying the predicate, or -1 if none. Caveat: NaN inputs
114- # always compare false under the ordered `o*` float predicates, so NaN in `v`
115- # or `x` produces "no match" rather than an exception — consistent with the
116- # undefined-input contract for sorted Float64 vectors containing NaN.
117- function _simd_first_gt (x:: Int64 , ptr:: Ptr{Int64} , len:: Int64 )
118- return Base. llvmcall (
119- (_SIMD_GT_I64_IR, " entry" ),
120- Int64, Tuple{Int64, Ptr{Int64}, Int64},
121- x, ptr, len
122- )
123- end
124- function _simd_first_ge (x:: Int64 , ptr:: Ptr{Int64} , len:: Int64 )
125- return Base. llvmcall (
126- (_SIMD_GE_I64_IR, " entry" ),
127- Int64, Tuple{Int64, Ptr{Int64}, Int64},
128- x, ptr, len
129- )
130- end
131- function _simd_first_gt (x:: Float64 , ptr:: Ptr{Float64} , len:: Int64 )
132- return Base. llvmcall (
133- (_SIMD_GT_F64_IR, " entry" ),
134- Int64, Tuple{Float64, Ptr{Float64}, Int64},
135- x, ptr, len
136- )
137- end
138- function _simd_first_ge (x:: Float64 , ptr:: Ptr{Float64} , len:: Int64 )
139- return Base. llvmcall (
140- (_SIMD_GE_F64_IR, " entry" ),
141- Int64, Tuple{Float64, Ptr{Float64}, Int64},
142- x, ptr, len
143- )
144- end
96+ @static if Sys. WORD_SIZE == 64
97+
98+ const FFE_IR = _simd_scan_ir (" i64" , " eq" )
99+
100+ function _findfirstequal (vpivot:: Int64 , ptr:: Ptr{Int64} , len:: Int64 )
101+ return Base. llvmcall (
102+ (FFE_IR, " entry" ),
103+ Int64,
104+ Tuple{Int64, Ptr{Int64}, Int64},
105+ vpivot,
106+ ptr,
107+ len
108+ )
109+ end
110+
111+ const _SIMD_GT_I64_IR = _simd_scan_ir (" i64" , " sgt" )
112+ const _SIMD_GE_I64_IR = _simd_scan_ir (" i64" , " sge" )
113+ const _SIMD_GT_F64_IR = _simd_scan_ir (" double" , " ogt" )
114+ const _SIMD_GE_F64_IR = _simd_scan_ir (" double" , " oge" )
115+
116+ # Reverse-direction predicates: used by `SIMDLinearScan` under
117+ # `Base.Order.Reverse` ordering, where the array is decreasing and we want
118+ # to find the first lane where `v[i] < x` (searchsortedlast) or `v[i] <= x`
119+ # (searchsortedfirst).
120+ const _SIMD_LT_I64_IR = _simd_scan_ir (" i64" , " slt" )
121+ const _SIMD_LE_I64_IR = _simd_scan_ir (" i64" , " sle" )
122+ const _SIMD_LT_F64_IR = _simd_scan_ir (" double" , " olt" )
123+ const _SIMD_LE_F64_IR = _simd_scan_ir (" double" , " ole" )
124+
125+ # Backing primitives for SIMDLinearScan. Each returns the 0-based offset of
126+ # the first lane satisfying the predicate, or -1 if none. Caveat: NaN inputs
127+ # always compare false under the ordered `o*` float predicates, so NaN in `v`
128+ # or `x` produces "no match" rather than an exception — consistent with the
129+ # undefined-input contract for sorted Float64 vectors containing NaN.
130+ function _simd_first_gt (x:: Int64 , ptr:: Ptr{Int64} , len:: Int64 )
131+ return Base. llvmcall (
132+ (_SIMD_GT_I64_IR, " entry" ),
133+ Int64, Tuple{Int64, Ptr{Int64}, Int64},
134+ x, ptr, len
135+ )
136+ end
137+ function _simd_first_ge (x:: Int64 , ptr:: Ptr{Int64} , len:: Int64 )
138+ return Base. llvmcall (
139+ (_SIMD_GE_I64_IR, " entry" ),
140+ Int64, Tuple{Int64, Ptr{Int64}, Int64},
141+ x, ptr, len
142+ )
143+ end
144+ function _simd_first_gt (x:: Float64 , ptr:: Ptr{Float64} , len:: Int64 )
145+ return Base. llvmcall (
146+ (_SIMD_GT_F64_IR, " entry" ),
147+ Int64, Tuple{Float64, Ptr{Float64}, Int64},
148+ x, ptr, len
149+ )
150+ end
151+ function _simd_first_ge (x:: Float64 , ptr:: Ptr{Float64} , len:: Int64 )
152+ return Base. llvmcall (
153+ (_SIMD_GE_F64_IR, " entry" ),
154+ Int64, Tuple{Float64, Ptr{Float64}, Int64},
155+ x, ptr, len
156+ )
157+ end
158+
159+ # Reverse-direction primitives.
160+ function _simd_first_lt (x:: Int64 , ptr:: Ptr{Int64} , len:: Int64 )
161+ return Base. llvmcall (
162+ (_SIMD_LT_I64_IR, " entry" ),
163+ Int64, Tuple{Int64, Ptr{Int64}, Int64},
164+ x, ptr, len
165+ )
166+ end
167+ function _simd_first_le (x:: Int64 , ptr:: Ptr{Int64} , len:: Int64 )
168+ return Base. llvmcall (
169+ (_SIMD_LE_I64_IR, " entry" ),
170+ Int64, Tuple{Int64, Ptr{Int64}, Int64},
171+ x, ptr, len
172+ )
173+ end
174+ function _simd_first_lt (x:: Float64 , ptr:: Ptr{Float64} , len:: Int64 )
175+ return Base. llvmcall (
176+ (_SIMD_LT_F64_IR, " entry" ),
177+ Int64, Tuple{Float64, Ptr{Float64}, Int64},
178+ x, ptr, len
179+ )
180+ end
181+ function _simd_first_le (x:: Float64 , ptr:: Ptr{Float64} , len:: Int64 )
182+ return Base. llvmcall (
183+ (_SIMD_LE_F64_IR, " entry" ),
184+ Int64, Tuple{Float64, Ptr{Float64}, Int64},
185+ x, ptr, len
186+ )
187+ end
188+
189+ else
190+
191+ _findfirstequal (vpivot:: Int64 , ptr:: Ptr{Int64} , len:: Int64 ) = _scalar_first (== , vpivot, ptr, len)
192+ _simd_first_gt (x:: Int64 , ptr:: Ptr{Int64} , len:: Int64 ) = _scalar_first (> , x, ptr, len)
193+ _simd_first_ge (x:: Int64 , ptr:: Ptr{Int64} , len:: Int64 ) = _scalar_first (>= , x, ptr, len)
194+ _simd_first_lt (x:: Int64 , ptr:: Ptr{Int64} , len:: Int64 ) = _scalar_first (< , x, ptr, len)
195+ _simd_first_le (x:: Int64 , ptr:: Ptr{Int64} , len:: Int64 ) = _scalar_first (<= , x, ptr, len)
196+ _simd_first_gt (x:: Float64 , ptr:: Ptr{Float64} , len:: Int64 ) = _scalar_first (> , x, ptr, len)
197+ _simd_first_ge (x:: Float64 , ptr:: Ptr{Float64} , len:: Int64 ) = _scalar_first (>= , x, ptr, len)
198+ _simd_first_lt (x:: Float64 , ptr:: Ptr{Float64} , len:: Int64 ) = _scalar_first (< , x, ptr, len)
199+ _simd_first_le (x:: Float64 , ptr:: Ptr{Float64} , len:: Int64 ) = _scalar_first (<= , x, ptr, len)
145200
146- # Reverse-direction primitives.
147- function _simd_first_lt (x:: Int64 , ptr:: Ptr{Int64} , len:: Int64 )
148- return Base. llvmcall (
149- (_SIMD_LT_I64_IR, " entry" ),
150- Int64, Tuple{Int64, Ptr{Int64}, Int64},
151- x, ptr, len
152- )
153- end
154- function _simd_first_le (x:: Int64 , ptr:: Ptr{Int64} , len:: Int64 )
155- return Base. llvmcall (
156- (_SIMD_LE_I64_IR, " entry" ),
157- Int64, Tuple{Int64, Ptr{Int64}, Int64},
158- x, ptr, len
159- )
160- end
161- function _simd_first_lt (x:: Float64 , ptr:: Ptr{Float64} , len:: Int64 )
162- return Base. llvmcall (
163- (_SIMD_LT_F64_IR, " entry" ),
164- Int64, Tuple{Float64, Ptr{Float64}, Int64},
165- x, ptr, len
166- )
167- end
168- function _simd_first_le (x:: Float64 , ptr:: Ptr{Float64} , len:: Int64 )
169- return Base. llvmcall (
170- (_SIMD_LE_F64_IR, " entry" ),
171- Int64, Tuple{Float64, Ptr{Float64}, Int64},
172- x, ptr, len
173- )
174201end
0 commit comments