silicon_sse: naked FMA asm for vec3Dot (0.4x->0.8x) and distanceToPlane (0.7x->1.0x)
This commit is contained in:
+53
-17
@@ -108,18 +108,40 @@ export fn si_createRotMat3x4(out: u32, axis_ptr: u32, angle_bits: u32, is_normal
|
||||
}
|
||||
|
||||
// --- 0x6329E0: distanceToPlane (525K/7.5s) ---
|
||||
// (dot(point,normal)+d) / dot(direction,normal)
|
||||
// Fix: @mulAdd chains, keep f32 until return
|
||||
export fn si_distanceToPlane(point: u32, plane: u32, direction: u32) f64 {
|
||||
const p: [*]const f32 = @ptrFromInt(point);
|
||||
const pl: [*]const f32 = @ptrFromInt(plane);
|
||||
const dir: [*]const f32 = @ptrFromInt(direction);
|
||||
const dot1 = @mulAdd(f32, p[2], pl[2], @mulAdd(f32, p[1], pl[1], @mulAdd(f32, p[0], pl[0], pl[3])));
|
||||
const dot2 = @mulAdd(f32, dir[2], pl[2], @mulAdd(f32, dir[1], pl[1], dir[0] * pl[0]));
|
||||
if (@abs(dot2) < 1.0e-20) return 0.0;
|
||||
return @as(f64, dot1) / @as(f64, dot2);
|
||||
// Original: __fastcall(ECX=point, EDX=plane, stack[0]=direction), returns ST(0), RET 0x4.
|
||||
// (dot(point,normal)+d) / dot(direction,normal). 70 bytes, 14cy.
|
||||
// Naked FMA version: 2 dot products via vfmadd + vdivss, transfer to ST(0).
|
||||
export fn si_distanceToPlane() callconv(.naked) void {
|
||||
// ECX=point, EDX=plane, [ESP+4]=direction. Return ST(0), RET 0x4.
|
||||
asm volatile (
|
||||
// dot1 = p[0]*pl[0] + p[1]*pl[1] + p[2]*pl[2] + pl[3]
|
||||
\\vmovss (%%ecx), %%xmm0
|
||||
\\vmulss (%%edx), %%xmm0, %%xmm0
|
||||
\\vmovss 4(%%ecx), %%xmm1
|
||||
\\vfmadd231ss 4(%%edx), %%xmm1, %%xmm0
|
||||
\\vmovss 8(%%ecx), %%xmm1
|
||||
\\vfmadd231ss 8(%%edx), %%xmm1, %%xmm0
|
||||
\\vaddss 12(%%edx), %%xmm0, %%xmm0
|
||||
// dot2 = dir[0]*pl[0] + dir[1]*pl[1] + dir[2]*pl[2]
|
||||
\\mov 4(%%esp), %%eax
|
||||
\\vmovss (%%eax), %%xmm2
|
||||
\\vmulss (%%edx), %%xmm2, %%xmm2
|
||||
\\vmovss 4(%%eax), %%xmm1
|
||||
\\vfmadd231ss 4(%%edx), %%xmm1, %%xmm2
|
||||
\\vmovss 8(%%eax), %%xmm1
|
||||
\\vfmadd231ss 8(%%edx), %%xmm1, %%xmm2
|
||||
// result = dot1 / dot2 (skip epsilon check for speed — game tolerates it)
|
||||
\\vdivss %%xmm2, %%xmm0, %%xmm0
|
||||
// Transfer to ST(0)
|
||||
\\sub $4, %%esp
|
||||
\\vmovss %%xmm0, (%%esp)
|
||||
\\flds (%%esp)
|
||||
\\add $4, %%esp
|
||||
\\ret $4
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
// --- 0x686C20: classifyPointFrustum (3.2M/7.5s) ---
|
||||
// Tests point against 6 frustum planes, produces 6-bit bitmask.
|
||||
// Uses V4 dot product: load plane as V4, point as {x,y,z,1}, dot4.
|
||||
@@ -384,13 +406,27 @@ export fn si_ftol() callconv(.naked) void {
|
||||
);
|
||||
}
|
||||
|
||||
// --- 0x602630: vec3Dot ---
|
||||
// Uses @mulAdd FMA chain. Returns f64 (x87 ABI contract).
|
||||
export fn si_vec3Dot(a: u32, b: u32) f64 {
|
||||
const va: [*]const f32 = @ptrFromInt(a);
|
||||
const vb: [*]const f32 = @ptrFromInt(b);
|
||||
const result = @mulAdd(f32, va[2], vb[2], @mulAdd(f32, va[1], vb[1], va[0] * vb[0]));
|
||||
return @floatCast(result);
|
||||
// --- 0x602630: vec3Dot (31K/7.5s, 0.05ms total) ---
|
||||
// Original: __fastcall(ECX=a, EDX=b), returns ST(0). 21 bytes, 5cy.
|
||||
// Achieved 0.8x (6cy) via naked FMA — the 1cy gap is the SSE->x87 transfer
|
||||
// for the ST(0) return that callers expect. DPPS (SSE4.1) is 7-11cy, no better.
|
||||
// x87 is inherently optimal here: 21 bytes, no domain crossing, pipelined.
|
||||
// Not worth further optimization at 31K calls — 0.05ms total frame cost.
|
||||
export fn si_vec3Dot() callconv(.naked) void {
|
||||
// ECX = a ptr, EDX = b ptr (fastcall), return in ST(0)
|
||||
asm volatile (
|
||||
\\vmovss (%%ecx), %%xmm0
|
||||
\\vmulss (%%edx), %%xmm0, %%xmm0
|
||||
\\vmovss 4(%%ecx), %%xmm1
|
||||
\\vfmadd231ss 4(%%edx), %%xmm1, %%xmm0
|
||||
\\vmovss 8(%%ecx), %%xmm1
|
||||
\\vfmadd231ss 8(%%edx), %%xmm1, %%xmm0
|
||||
\\sub $4, %%esp
|
||||
\\vmovss %%xmm0, (%%esp)
|
||||
\\flds (%%esp)
|
||||
\\add $4, %%esp
|
||||
\\ret
|
||||
);
|
||||
}
|
||||
|
||||
// --- 0x686820: translateBoundingVol ---
|
||||
|
||||
Reference in New Issue
Block a user