@@ -27,9 +27,9 @@ use std::arch::x86_64::{
2727#[ cfg( target_arch = "aarch64" ) ]
2828use super :: exp:: fast_exp_sigmoid_neon;
2929#[ cfg( any( target_arch = "x86" , target_arch = "x86_64" ) ) ]
30- use super :: exp:: { fast_exp_avx, fast_exp_bittrick_avx , fast_exp_bittrick_sse , fast_exp_sse} ;
30+ use super :: exp:: { fast_exp_avx, fast_exp_sigmoid_avx , fast_exp_sigmoid_sse , fast_exp_sse} ;
3131#[ cfg( target_arch = "x86_64" ) ]
32- use super :: exp:: { fast_exp_avx512, fast_exp_bittrick_avx512 } ;
32+ use super :: exp:: { fast_exp_avx512, fast_exp_sigmoid_avx512 } ;
3333use super :: { SimdDispatchPath , dispatch_path, x86_memory_simd_forces_avx2} ;
3434
3535// ===========================================================================
@@ -517,7 +517,7 @@ unsafe fn fused_row_epilogue_avx_fma(
517517 // SiLU via fast bit-trick exp.
518518 let one = _mm256_set1_ps ( 1.0 ) ;
519519 let neg_x = _mm256_sub_ps ( zero, v) ;
520- let exp_neg = fast_exp_bittrick_avx ( neg_x) ;
520+ let exp_neg = fast_exp_sigmoid_avx ( neg_x) ;
521521 let denom = _mm256_add_ps ( one, exp_neg) ;
522522 v = _mm256_div_ps ( v, denom) ;
523523 }
@@ -1203,150 +1203,41 @@ unsafe fn relu_to_slice_neon(input: &[f32], output: &mut [f32]) {
12031203#[ cfg( target_arch = "aarch64" ) ]
12041204#[ allow( unsafe_code) ]
12051205unsafe fn sigmoid_slice_neon ( input : & [ f32 ] , output : & mut [ f32 ] ) {
1206+ // Точный fast-exp (minimax deg-4) вместо сырого Schraudolph bit-trick:
1207+ // ~1e-3 ошибка бит-трика систематически смещала логиты уверенности
1208+ // детекционных голов (conf 0.75 против 0.93 на FastSAM-s).
1209+ use std:: arch:: aarch64:: { vaddq_f32, vdivq_f32, vld1q_f32, vnegq_f32, vst1q_f32} ;
12061210 let len = input. len ( ) ;
1207- let mut inp = input. as_ptr ( ) ;
1208- let mut out = output. as_mut_ptr ( ) ;
1209- let mut remaining = len;
1210-
1211- // Load all constants ONCE before the loop, keep in NEON registers
1212- if remaining >= 4 {
1213- unsafe {
1214- // Constants on stack for ld1r broadcast
1215- let c_neg88: f32 = -88.0 ;
1216- let c_pos88: f32 = 88.0 ;
1217- // Schraudolph 1999 constants: exp(x) ~ reinterpret(int(x * C + B))
1218- // C = 2^23 / ln(2) = 12102203.16, B = 127 * 2^23 = 1065353216
1219- // WHY: 2^23/ln(2) maps float mantissa bits to IEEE 754 exponent field; 127*2^23 adds the exponent bias.
1220- let c_schr_c: f32 = 12102203.0 ; // 2^23 / ln(2)
1221- let c_schr_b: i32 = 127 << 23 ; // 1065353216 as integer
1222- let c_sixth: f32 = 1.0 / 6.0 ;
1223- let c_half: f32 = 0.5 ;
1224- let c_one: f32 = 1.0 ;
1225- let c_127: i32 = 127 ;
1226-
1227- // Load constants into NEON registers (stays there for entire loop)
1228- std:: arch:: asm!(
1229- "ld1r {{v16.4s}}, [{p_neg88}]" ,
1230- "ld1r {{v17.4s}}, [{p_pos88}]" ,
1231- "ld1r {{v18.4s}}, [{p_schr_c}]" , // Schraudolph C (float)
1232- "dup v19.4s, {p_schr_b:w}" , // Schraudolph B (integer 127<<23)
1233- "ld1r {{v20.4s}}, [{p_sixth}]" ,
1234- "ld1r {{v21.4s}}, [{p_half}]" ,
1235- "ld1r {{v22.4s}}, [{p_one}]" ,
1236- "dup v23.4s, {p_127:w}" ,
1237- p_neg88 = in( reg) & c_neg88,
1238- p_pos88 = in( reg) & c_pos88,
1239- p_schr_c = in( reg) & c_schr_c,
1240- p_schr_b = in( reg) c_schr_b,
1241- p_sixth = in( reg) & c_sixth,
1242- p_half = in( reg) & c_half,
1243- p_one = in( reg) & c_one,
1244- p_127 = in( reg) c_127,
1245- out( "v16" ) _, out( "v17" ) _, out( "v18" ) _, out( "v19" ) _,
1246- out( "v20" ) _, out( "v21" ) _, out( "v22" ) _, out( "v23" ) _,
1247- ) ;
1248-
1249- // Schraudolph bit-trick: exp(x) ~ reinterpret_f32(int(x * 2^23/ln2) + 127<<23)
1250- // Proper integer arithmetic: fcvtzs to get int, then add bias as int, then reinterpret
1251- // 4x unrolled, 16 elements per iteration
1252- while remaining >= 16 {
1253- std:: arch:: asm!(
1254- "ldp q0, q1, [{inp}]" ,
1255- "ldp q2, q3, [{inp}, #32]" ,
1256- "add {inp}, {inp}, #64" ,
1257- "fneg v0.4s, v0.4s" ,
1258- "fneg v1.4s, v1.4s" ,
1259- "fneg v2.4s, v2.4s" ,
1260- "fneg v3.4s, v3.4s" ,
1261- "fmax v0.4s, v0.4s, v16.4s" ,
1262- "fmax v1.4s, v1.4s, v16.4s" ,
1263- "fmax v2.4s, v2.4s, v16.4s" ,
1264- "fmax v3.4s, v3.4s, v16.4s" ,
1265- "fmin v0.4s, v0.4s, v17.4s" ,
1266- "fmin v1.4s, v1.4s, v17.4s" ,
1267- "fmin v2.4s, v2.4s, v17.4s" ,
1268- "fmin v3.4s, v3.4s, v17.4s" ,
1269- // x * (2^23/ln2) -> convert to int
1270- "fmul v0.4s, v0.4s, v18.4s" ,
1271- "fmul v1.4s, v1.4s, v18.4s" ,
1272- "fmul v2.4s, v2.4s, v18.4s" ,
1273- "fmul v3.4s, v3.4s, v18.4s" ,
1274- "fcvtzs v0.4s, v0.4s" ,
1275- "fcvtzs v1.4s, v1.4s" ,
1276- "fcvtzs v2.4s, v2.4s" ,
1277- "fcvtzs v3.4s, v3.4s" ,
1278- // + 127*2^23 (integer add)
1279- "add v0.4s, v0.4s, v19.4s" ,
1280- "add v1.4s, v1.4s, v19.4s" ,
1281- "add v2.4s, v2.4s, v19.4s" ,
1282- "add v3.4s, v3.4s, v19.4s" ,
1283- // v0-v3 bits ARE exp(-x) when reinterpreted as float
1284- // sigmoid = 1 / (1 + exp)
1285- "fadd v0.4s, v22.4s, v0.4s" ,
1286- "fadd v1.4s, v22.4s, v1.4s" ,
1287- "fadd v2.4s, v22.4s, v2.4s" ,
1288- "fadd v3.4s, v22.4s, v3.4s" ,
1289- "fdiv v0.4s, v22.4s, v0.4s" ,
1290- "fdiv v1.4s, v22.4s, v1.4s" ,
1291- "fdiv v2.4s, v22.4s, v2.4s" ,
1292- "fdiv v3.4s, v22.4s, v3.4s" ,
1293- "stp q0, q1, [{out}]" ,
1294- "stp q2, q3, [{out}, #32]" ,
1295- "add {out}, {out}, #64" ,
1296- inp = inout( reg) inp,
1297- out = inout( reg) out,
1298- out( "v0" ) _, out( "v1" ) _, out( "v2" ) _, out( "v3" ) _,
1299- ) ;
1300- remaining -= 16 ;
1301- }
1302- // 4-element tail -- Schraudolph
1303- while remaining >= 4 {
1304- std:: arch:: asm!(
1305- "ld1 {{v0.4s}}, [{inp}], #16" ,
1306- "fneg v0.4s, v0.4s" ,
1307- "fmax v0.4s, v0.4s, v16.4s" ,
1308- "fmin v0.4s, v0.4s, v17.4s" ,
1309- "fmul v0.4s, v0.4s, v18.4s" ,
1310- "fcvtzs v0.4s, v0.4s" ,
1311- "add v0.4s, v0.4s, v19.4s" ,
1312- "fadd v0.4s, v22.4s, v0.4s" ,
1313- "fdiv v0.4s, v22.4s, v0.4s" ,
1314- "st1 {{v0.4s}}, [{out}], #16" ,
1315- inp = inout( reg) inp,
1316- out = inout( reg) out,
1317- out( "v0" ) _,
1318- ) ;
1319- remaining -= 4 ;
1320- }
1321- // 4-element tail -- Schraudolph
1322- while remaining >= 4 {
1323- std:: arch:: asm!(
1324- "ld1 {{v0.4s}}, [{inp}], #16" ,
1325- "fneg v0.4s, v0.4s" ,
1326- "fmax v0.4s, v0.4s, v16.4s" ,
1327- "fmin v0.4s, v0.4s, v17.4s" ,
1328- "fmul v0.4s, v0.4s, v18.4s" ,
1329- "fcvtzs v0.4s, v0.4s" ,
1330- "add v0.4s, v0.4s, v19.4s" ,
1331- "fadd v0.4s, v22.4s, v0.4s" ,
1332- "fdiv v0.4s, v22.4s, v0.4s" ,
1333- "st1 {{v0.4s}}, [{out}], #16" ,
1334- inp = inout( reg) inp,
1335- out = inout( reg) out,
1336- out( "v0" ) _,
1337- ) ;
1338- remaining -= 4 ;
1339- }
1211+ let in_ptr = input. as_ptr ( ) ;
1212+ let out_ptr = output. as_mut_ptr ( ) ;
1213+ let one = vdupq_n_f32 ( 1.0 ) ;
1214+ let mut i = 0usize ;
1215+ unsafe {
1216+ while i + 16 <= len {
1217+ let x0 = vld1q_f32 ( in_ptr. add ( i) ) ;
1218+ let x1 = vld1q_f32 ( in_ptr. add ( i + 4 ) ) ;
1219+ let x2 = vld1q_f32 ( in_ptr. add ( i + 8 ) ) ;
1220+ let x3 = vld1q_f32 ( in_ptr. add ( i + 12 ) ) ;
1221+ let e0 = fast_exp_sigmoid_neon ( vnegq_f32 ( x0) ) ;
1222+ let e1 = fast_exp_sigmoid_neon ( vnegq_f32 ( x1) ) ;
1223+ let e2 = fast_exp_sigmoid_neon ( vnegq_f32 ( x2) ) ;
1224+ let e3 = fast_exp_sigmoid_neon ( vnegq_f32 ( x3) ) ;
1225+ vst1q_f32 ( out_ptr. add ( i) , vdivq_f32 ( one, vaddq_f32 ( one, e0) ) ) ;
1226+ vst1q_f32 ( out_ptr. add ( i + 4 ) , vdivq_f32 ( one, vaddq_f32 ( one, e1) ) ) ;
1227+ vst1q_f32 ( out_ptr. add ( i + 8 ) , vdivq_f32 ( one, vaddq_f32 ( one, e2) ) ) ;
1228+ vst1q_f32 ( out_ptr. add ( i + 12 ) , vdivq_f32 ( one, vaddq_f32 ( one, e3) ) ) ;
1229+ i += 16 ;
13401230 }
1341- }
1342-
1343- // Scalar tail
1344- for i in 0 ..remaining {
1345- unsafe {
1346- let x = * inp. add ( i) ;
1347- * out. add ( i) = 1.0 / ( 1.0 + ( -x) . exp ( ) ) ;
1231+ while i + 4 <= len {
1232+ let x = vld1q_f32 ( in_ptr. add ( i) ) ;
1233+ let e = fast_exp_sigmoid_neon ( vnegq_f32 ( x) ) ;
1234+ vst1q_f32 ( out_ptr. add ( i) , vdivq_f32 ( one, vaddq_f32 ( one, e) ) ) ;
1235+ i += 4 ;
13481236 }
13491237 }
1238+ for k in i..len {
1239+ output[ k] = 1.0 / ( 1.0 + ( -input[ k] ) . exp ( ) ) ;
1240+ }
13501241}
13511242
13521243// (sigmoid_vdsp and silu_vdsp removed -- benchmarked slower than NEON polynomial)
@@ -1376,10 +1267,10 @@ unsafe fn sigmoid_slice_sse(input: &[f32], output: &mut [f32]) {
13761267 let x3 = _mm_loadu_ps ( in_ptr. add ( index + 12 ) ) ;
13771268
13781269 // Bit-trick exp is sufficient for sigmoid (output clamped 0-1, errors wash out)
1379- let e0 = fast_exp_bittrick_sse ( _mm_sub_ps ( zero, x0) ) ;
1380- let e1 = fast_exp_bittrick_sse ( _mm_sub_ps ( zero, x1) ) ;
1381- let e2 = fast_exp_bittrick_sse ( _mm_sub_ps ( zero, x2) ) ;
1382- let e3 = fast_exp_bittrick_sse ( _mm_sub_ps ( zero, x3) ) ;
1270+ let e0 = fast_exp_sigmoid_sse ( _mm_sub_ps ( zero, x0) ) ;
1271+ let e1 = fast_exp_sigmoid_sse ( _mm_sub_ps ( zero, x1) ) ;
1272+ let e2 = fast_exp_sigmoid_sse ( _mm_sub_ps ( zero, x2) ) ;
1273+ let e3 = fast_exp_sigmoid_sse ( _mm_sub_ps ( zero, x3) ) ;
13831274
13841275 let r0 = _mm_div_ps ( one, _mm_add_ps ( one, e0) ) ;
13851276 let r1 = _mm_div_ps ( one, _mm_add_ps ( one, e1) ) ;
@@ -1398,7 +1289,7 @@ unsafe fn sigmoid_slice_sse(input: &[f32], output: &mut [f32]) {
13981289 while index + 4 <= len {
13991290 let x = _mm_loadu_ps ( in_ptr. add ( index) ) ;
14001291 let neg_x = _mm_sub_ps ( zero, x) ;
1401- let exp_neg_x = fast_exp_bittrick_sse ( neg_x) ;
1292+ let exp_neg_x = fast_exp_sigmoid_sse ( neg_x) ;
14021293 let denom = _mm_add_ps ( one, exp_neg_x) ;
14031294 let result = _mm_div_ps ( one, denom) ;
14041295 _mm_storeu_ps ( out_ptr. add ( index) , result) ;
@@ -1436,10 +1327,10 @@ unsafe fn sigmoid_slice_avx(input: &[f32], output: &mut [f32]) {
14361327 let x3 = _mm256_loadu_ps ( in_ptr. add ( index + 24 ) ) ;
14371328
14381329 // Use Schraudolph bit-trick exp for ~3x speedup over polynomial
1439- let e0 = fast_exp_bittrick_avx ( _mm256_sub_ps ( zero, x0) ) ;
1440- let e1 = fast_exp_bittrick_avx ( _mm256_sub_ps ( zero, x1) ) ;
1441- let e2 = fast_exp_bittrick_avx ( _mm256_sub_ps ( zero, x2) ) ;
1442- let e3 = fast_exp_bittrick_avx ( _mm256_sub_ps ( zero, x3) ) ;
1330+ let e0 = fast_exp_sigmoid_avx ( _mm256_sub_ps ( zero, x0) ) ;
1331+ let e1 = fast_exp_sigmoid_avx ( _mm256_sub_ps ( zero, x1) ) ;
1332+ let e2 = fast_exp_sigmoid_avx ( _mm256_sub_ps ( zero, x2) ) ;
1333+ let e3 = fast_exp_sigmoid_avx ( _mm256_sub_ps ( zero, x3) ) ;
14431334
14441335 let r0 = _mm256_div_ps ( one, _mm256_add_ps ( one, e0) ) ;
14451336 let r1 = _mm256_div_ps ( one, _mm256_add_ps ( one, e1) ) ;
@@ -1458,7 +1349,7 @@ unsafe fn sigmoid_slice_avx(input: &[f32], output: &mut [f32]) {
14581349 while index + 8 <= len {
14591350 let x = _mm256_loadu_ps ( in_ptr. add ( index) ) ;
14601351 let neg_x = _mm256_sub_ps ( zero, x) ;
1461- let exp_neg_x = fast_exp_bittrick_avx ( neg_x) ;
1352+ let exp_neg_x = fast_exp_sigmoid_avx ( neg_x) ;
14621353 let denom = _mm256_add_ps ( one, exp_neg_x) ;
14631354 let result = _mm256_div_ps ( one, denom) ;
14641355 _mm256_storeu_ps ( out_ptr. add ( index) , result) ;
@@ -1487,8 +1378,8 @@ unsafe fn sigmoid_slice_avx512(input: &[f32], output: &mut [f32]) {
14871378 while index + 32 <= len {
14881379 let x0 = _mm512_loadu_ps ( in_ptr. add ( index) ) ;
14891380 let x1 = _mm512_loadu_ps ( in_ptr. add ( index + 16 ) ) ;
1490- let e0 = fast_exp_bittrick_avx512 ( _mm512_sub_ps ( zero, x0) ) ;
1491- let e1 = fast_exp_bittrick_avx512 ( _mm512_sub_ps ( zero, x1) ) ;
1381+ let e0 = fast_exp_sigmoid_avx512 ( _mm512_sub_ps ( zero, x0) ) ;
1382+ let e1 = fast_exp_sigmoid_avx512 ( _mm512_sub_ps ( zero, x1) ) ;
14921383 let r0 = _mm512_div_ps ( one, _mm512_add_ps ( one, e0) ) ;
14931384 let r1 = _mm512_div_ps ( one, _mm512_add_ps ( one, e1) ) ;
14941385 _mm512_storeu_ps ( out_ptr. add ( index) , r0) ;
@@ -1498,7 +1389,7 @@ unsafe fn sigmoid_slice_avx512(input: &[f32], output: &mut [f32]) {
14981389
14991390 while index + 16 <= len {
15001391 let x = _mm512_loadu_ps ( in_ptr. add ( index) ) ;
1501- let exp_neg_x = fast_exp_bittrick_avx512 ( _mm512_sub_ps ( zero, x) ) ;
1392+ let exp_neg_x = fast_exp_sigmoid_avx512 ( _mm512_sub_ps ( zero, x) ) ;
15021393 let result = _mm512_div_ps ( one, _mm512_add_ps ( one, exp_neg_x) ) ;
15031394 _mm512_storeu_ps ( out_ptr. add ( index) , result) ;
15041395 index += 16 ;
0 commit comments