From 7a412523dd041c152b183bf98f749fc3c9d52457 Mon Sep 17 00:00:00 2001 From: dzaima Date: Wed, 12 Mar 2025 16:08:10 +0200 Subject: [PATCH] better SSE2 float getRange --- src/singeli/src/search.singeli | 27 +++++++++++++++--------- test/cases/build-specific/test_range.bqn | 3 ++- 2 files changed, 19 insertions(+), 11 deletions(-) diff --git a/src/singeli/src/search.singeli b/src/singeli/src/search.singeli index a6c9e8a4..9f85780c 100644 --- a/src/singeli/src/search.singeli +++ b/src/singeli/src/search.singeli @@ -307,27 +307,34 @@ def acc{unr, init:T} = { else a1 = F{a1} } } -def isI64{x:T=[_](f64) if hasarch{'AARCH64'}} = x == cvt{f64, cvt{i64, x}} -def isI64{x:T=[_](f64) if hasarch{'SSE4.1'}} = (x==floor{x}) & (abs{x}<=T**(1<<53)) -def maskBlend{b:T, x:T, M} = x -def maskBlend{b:T, x:T, M if M{0}} = blend_hom{b, x, M{T, 'to homogeneous bits'}} +# following RangeFn's specification in calls.h, whether it's necessary to return 0 or otherwise accumulating & converting to i64 may produce incorrect results +def bad_float_i64{x:T=[_](f64)} = { + a:= abs{x} + s:= T**(1<<53) + min{s,a} != s-(s-a) # (a<=s) & (a == s-(s-a)) +} +def bad_float_i64{x:T=[_](f64) if hasarch{'SSE4.1'}} = (x!=floor{x}) | (abs{x}>T**(1<<53)) +def bad_float_i64{x:T=[_](f64) if hasarch{'AARCH64'}} = x != cvt{f64, cvt{i64, x}} + +def mask_blend{b:T, x:T, M} = x +def mask_blend{b:T, x:T, M if M{0}} = blend_hom{b, x, M{T, 'to homogeneous bits'}} fn getRange{E}(x0:*void, res:*i64, n:u64) : u1 = { assert{n>0} x:= *E~~x0 min1:E = *x max1:E = *x - if (has_simd and (not E==f64 or hasarch{'AARCH64'} or hasarch{'SSE4.1'})) { + if (has_simd) { def bulk = arch_defvw/width{E} def VT = [bulk]E def unr = tern{E==f64 and hasarch{'X86_64'}, 1, 2} - def minA = acc{2, VT**min1} - def maxA = acc{2, VT**min1} + def minA = acc{unr, VT**min1} + def maxA = acc{unr, VT**min1} @for_mu{bulk, unr, {} => { minA{'tr',min}; maxA{'tr',max} }}(cx in tup{VT,x}, M in 'm' over is to n) { - if (E==f64 and any_hom{M, ...each{{c} => ~isI64{c}, cx}}) return{0} - minA{'upd', is, {a} => eachx{maskBlend, a, each{min, a, cx}, M}} # blend - maxA{'upd', is, {a} => eachx{maskBlend, a, each{max, a, cx}, M}} # blend + if (E==f64 and any_hom{M, ...each{bad_float_i64, cx}}) return{0} + minA{'upd', is, {a} => eachx{mask_blend, a, each{min, a, cx}, M}} # blend + maxA{'upd', is, {a} => eachx{mask_blend, a, each{max, a, cx}, M}} # blend } min1 = vfold{min, minA{'get'}} max1 = vfold{max, maxA{'get'}} diff --git a/test/cases/build-specific/test_range.bqn b/test/cases/build-specific/test_range.bqn index 393dbc27..6aec2704 100644 --- a/test/cases/build-specific/test_range.bqn +++ b/test/cases/build-specific/test_range.bqn @@ -6,6 +6,7 @@ ≢(⟨⟨0‿9‿1,↕10⟩ ⋄ ⟨¯5‿¯3‿1 ⋄ ¯5‿¯3‿¯4‿¯4‿¯4‿¯4‿¯4⟩⟩∾{⟨⟨¯2,𝕩-3,1⟩,¯2+↕𝕩⟩}¨1+↕100) {exp‿a𝕊𝕩: exp (⋈!≡) •internal.Temp 𝕩•internal.Variation a}⌜ "Ai8"‿"Ai16"‿"Ai32"‿"Af64" T←⋈ ! ⊣ ≡ ·•internal.Temp "Ab"•internal.Variation⊢ ⋄ ≠{𝕊n: 1‿1‿1 T 𝕩⥊1 ⋄ 0‿0‿1 T 𝕩⥊0 ⋄ 0‿1 {0‿1‿1 T (¬𝕨)⌾(𝕩⊸⊑) n⥊𝕨}¨⍟(n>1) 2•rand.Range n}¨1+↕500 %USE invalid ⋄ Invalid¨ ⟨↕4, -⊸∾ 2⋆↕50, π×↕4, 10⥊2⋆60⟩ %% 0‿0‿1‿1 -%USE invalid ⋄ ⟨2⋆63, 1.5, 0÷0⟩ {𝕩!Invalid 𝕨⌾(𝕩⊸⊑) 20⥊0}⌜ ↕20 +%USE invalid ⋄ ⟨2⋆63, 1.5, 0÷0⟩ {𝕨!Invalid 𝕨⌾(𝕩⊸⊑) 20⥊0}⌜ ↕20 %USE invalid ⋄ p←⟨1+2⋆-52, 1-2⋆-53⟩ ⋄ {𝕩!Invalid 𝕩⌾(10⊸⊑) 20⥊0}¨ ⟨∞, ¯∞, 0.1, ¯0.1⟩ ∾ ((1∾p) ×⌜ -⊸∾ 2⋆54+↕12) ∾○⥊ p ×⌜ 2⋆↕70 ≠{! 0‿0‿1 ≡ •internal.Temp 𝕩↑(𝕩⥊0)∾10⥊0÷0}¨ 1+↕10 +{𝕩!0= 2⊑•internal.Temp (0÷0)¨⌾((⍷𝕩)⊸⊏) 10⥊0}¨ ↕10‿10‿10