ref: 96ccc85d6a58b7ebfcb69d6d470ff209668f6187
author: rodri <[email protected]>
date: Thu Nov 23 06:43:50 EST 2023
initial SIMD trials of some libgeometry functions.
--- /dev/null
+++ b/dppd.s
@@ -1,0 +1,71 @@
+#include "sse.h"
+
+DATA one(SB)/8,$1.0
+GLOBL one(SB), $8
+
+TEXT dppd(SB), 1, $0
+ MOVQ SP, AX
+ MOVLPD(8, rAX, rX0) /* MOVLPD a+0(FP), X0 */
+ MOVHPD(16, rAX, rX0) /* MOVHPD a+8(FP), X0 */
+ MOVLPD(32, rAX, rX1) /* MOVLPD b+0(FP), X1 */
+ MOVHPD(40, rAX, rX1) /* MOVHPD b+8(FP), X1*/
+ DPPD(rX1, rX0) /* DPPD $0x31, X1, X0 */
+ RET
+
+TEXT dppd3(SB), 1, $0
+ MOVQ SP, AX
+ MOVLPD(8, rAX, rX0) /* MOVLPD a+0(FP), X0 */
+ MOVHPD(16, rAX, rX0) /* MOVHPD a+8(FP), X0 */
+ MOVLPD(40, rAX, rX1) /* MOVLPD b+0(FP), X1 */
+ MOVHPD(48, rAX, rX1) /* MOVHPD b+8(FP), X1 */
+ DPPD(rX1, rX0) /* DPPD $0x31, X1, X0 */
+ MOVSD one(SB), X1
+ MOVHPD(24, rAX, rX0) /* MOVHPD a+16(FP), X0 */
+ MOVHPD(56, rAX, rX1) /* MOVHPD b+16(FP), X1 */
+ DPPD(rX1, rX0) /* DPPD $0x31, X1, X0 */
+ RET
+
+TEXT Pt2b(SB), 1, $0
+ MOVQ BP, DI
+ MOVSD x+8(FP), X0
+ MOVSD X0, 0(DI)
+ MOVSD y+16(FP), X0
+ MOVSD X0, 8(DI)
+ MOVSD w+24(FP), X0
+ MOVSD X0, 16(DI)
+ RET
+
+TEXT hsubpd(SB), 1, $0
+ MOVQ SP, AX
+ MOVLPD(8, rAX, rX0)
+ MOVHPD(16, rAX, rX0)
+ HSUBPD(rX0, rX0)
+ RET
+
+TEXT xvec3(SB), 1, $0
+ MOVQ SP, AX
+ ADDQ $8, AX
+ MOVLPD(40, rAX, rX0)
+ MOVHPD(8, rAX, rX0)
+ MOVLPD(16, rAX, rX1)
+ MOVHPD(48, rAX, rX1)
+ MOVLPD(56, rAX, rX2)
+ MOVHPD(24, rAX, rX2)
+ MOVAPD X1, X3
+ MULPD X2, X3
+ HSUBPD(rX3, rX3) /* x */
+ MOVAPD X2, X4
+ SHUFPD $0x1, X4, X4
+ MULPD X0, X4
+ HSUBPD(rX4, rX4) /* y */
+ MOVAPD X0, X5
+ MULPD X1, X5
+ SHUFPD $0x1, X5, X5
+ HSUBPD(rX5, rX5) /* z */
+ MOVQ BP, DI
+ MOVSD X3, 0(DI)
+ MOVSD X4, 8(DI)
+ MOVSD X5, 16(DI)
+ XORPD X0, X0
+ MOVSD X0, 24(DI)
+ RET
--- /dev/null
+++ b/main.c
@@ -1,0 +1,82 @@
+#include <u.h>
+#include <libc.h>
+#include <geometry.h>
+
+uvlong nanosec(void);
+double min(double, double);
+double dppd(Point2, Point2);
+double dppd3(Point3, Point3);
+Point2 Pt2b(double, double, double);
+Point3 xvec3(Point3, Point3);
+double hsubpd(double, double);
+
+double
+fmin(double a, double b)
+{
+ return a<b? a: b;
+}
+
+void
+main(int argc, char *argv[])
+{
+ uvlong t0, t1;
+ double a, b, r;
+ Point2 p0, p1;
+ Point3 p0t, p1t, pr;
+
+ GEOMfmtinstall();
+ ARGBEGIN{default:sysfatal("shit");}ARGEND
+ if(argc != 2)
+ sysfatal("shit");
+ a = strtod(argv[0], nil);
+ b = strtod(argv[1], nil);
+
+ t0 = nanosec();
+ r = fmin(a, b);
+ t1 = nanosec();
+ print("fmin(%g, %g) = %g\ttook %lludns\n", a, b, r, t1-t0);
+ t0 = nanosec();
+ r = min(a, b);
+ t1 = nanosec();
+ print("min(%g, %g) = %g\ttook %lludns\n", a, b, r, t1-t0);
+
+ p0 = Pt2b(a, 1, 1);
+ p1 = Pt2b(b, 3, 1);
+ t0 = nanosec();
+ r = dppd(p0, p1);
+ t1 = nanosec();
+ print("dppd(%v, %v) = %g\ttook %lludns\n", p0, p1, r, t1-t0);
+ t0 = nanosec();
+ r = dotvec2(p0, p1);
+ t1 = nanosec();
+ print("dotvec2(%v, %v) = %g\ttook %lludns\n", p0, p1, r, t1-t0);
+
+ p0t = Pt3(a, 1, 9, 1);
+ p1t = Pt3(b, 3, 4, 1);
+ t0 = nanosec();
+ r = dppd3(p0t, p1t);
+ t1 = nanosec();
+ print("dppd3(%V, %V) = %g\ttook %lludns\n", p0t, p1t, r, t1-t0);
+ t0 = nanosec();
+ r = dotvec3(p0t, p1t);
+ t1 = nanosec();
+ print("dotvec3(%V, %V) = %g\ttook %lludns\n", p0t, p1t, r, t1-t0);
+
+ t0 = nanosec();
+ r = hsubpd(a, b);
+ t1 = nanosec();
+ print("hsubpd(%g, %g) = %g\ttook %lludns\n", a, b, r, t1-t0);
+
+ p0t = Pt3(a, 1, 9, 1);
+ p1t = Pt3(b, 3, 4, 1);
+ t0 = nanosec();
+ pr = xvec3(p0t, p1t);
+ t1 = nanosec();
+ print("xvec3(%V, %V) = %V\ttook %lludns\n", p0t, p1t, pr, t1-t0);
+ t0 = nanosec();
+ pr = crossvec3(p0t, p1t);
+ t1 = nanosec();
+ print("crossvec3(%V, %V) = %V\ttook %lludns\n", p0t, p1t, pr, t1-t0);
+
+ exits(nil);
+}
--- /dev/null
+++ b/min.s
@@ -1,0 +1,4 @@
+TEXT min(SB), 1, $0
+ MOVSD a+0(FP), X0
+ MINSD b+8(FP), X0
+ RET
--- /dev/null
+++ b/mkfile
@@ -1,0 +1,14 @@
+</$objtype/mkfile
+
+BIN=/$objtype/bin
+TARG=stuff
+OFILES=\
+ main.$O\
+ min.$O\
+ dppd.$O\
+ nanosec.$O\
+
+HFILES=\
+ sse.h\
+
+</sys/src/cmd/mkone
--- /dev/null
+++ b/nanosec.c
@@ -1,0 +1,109 @@
+#include <u.h>
+#include <libc.h>
+#include <tos.h>
+
+/*
+ * This code is a mixture of cpuid(1) and the nanosec() found in vmx,
+ * in order to force the use of nsec(2) in case we are running in a
+ * virtualized environment where the clock is mis-bhyve-ing.
+ */
+
+typedef struct Res {
+ ulong ax, bx, cx, dx;
+} Res;
+
+static uchar _cpuid[] = {
+ 0x5E, /* POP SI (PC) */
+ 0x5D, /* POP BP (Res&) */
+ 0x58, /* POP AX */
+ 0x59, /* POP CX */
+
+ 0x51, /* PUSH CX */
+ 0x50, /* PUSH AX */
+ 0x55, /* PUSH BP */
+ 0x56, /* PUSH SI */
+
+ 0x31, 0xDB, /* XOR BX, BX */
+ 0x31, 0xD2, /* XOR DX, DX */
+
+ 0x0F, 0xA2, /* CPUID */
+
+ 0x89, 0x45, 0x00, /* MOV AX, 0(BP) */
+ 0x89, 0x5d, 0x04, /* MOV BX, 4(BP) */
+ 0x89, 0x4d, 0x08, /* MOV CX, 8(BP) */
+ 0x89, 0x55, 0x0C, /* MOV DX, 12(BP) */
+ 0xC3, /* RET */
+};
+
+static Res (*cpuid)(ulong ax, ulong cx) = (Res(*)(ulong, ulong)) _cpuid;
+
+/*
+ * nsec() is wallclock and can be adjusted by timesync
+ * so need to use cycles() instead, but fall back to
+ * nsec() in case we can't
+ */
+uvlong
+nanosec(void)
+{
+ static uvlong fasthz, xstart;
+ char buf[13], path[128];
+ ulong w;
+ uvlong x, div;
+ int fd;
+ Res r;
+
+ if(fasthz == ~0ULL)
+ return nsec() - xstart;
+
+ if(fasthz == 0){
+ /* first long in a.out header */
+ snprint(path, sizeof path, "/proc/%d/text", getpid());
+ fd = open(path, OREAD);
+ if(fd < 0)
+ goto Wallclock;
+ if(read(fd, buf, 4) != 4){
+ close(fd);
+ goto Wallclock;
+ }
+ close(fd);
+
+ w = ((ulong *) buf)[0];
+
+ switch(w){
+ default:
+ goto Wallclock;
+ case 0x978a0000: /* amd64 */
+ /* patch out POP BP -> POP AX */
+ _cpuid[1] = 0x58;
+ case 0xeb010000: /* 386 */
+ break;
+ }
+ segflush(_cpuid, sizeof(_cpuid));
+
+ r = cpuid(0x40000000, 0);
+ ((ulong *) buf)[0] = r.bx;
+ ((ulong *) buf)[1] = r.cx;
+ ((ulong *) buf)[2] = r.dx;
+ buf[12] = 0;
+
+ if(strstr(buf, "bhyve") != nil)
+ goto Wallclock;
+
+ if(_tos->cyclefreq){
+ fasthz = _tos->cyclefreq;
+ cycles(&xstart);
+ } else {
+Wallclock:
+ fasthz = ~0ULL;
+ xstart = nsec();
+ }
+ return 0;
+ }
+ cycles(&x);
+ x -= xstart;
+
+ /* this is ugly */
+ for(div = 1000000000ULL; x < 0x1999999999999999ULL && div > 1 ; div /= 10ULL, x *= 10ULL);
+
+ return x / (fasthz / div);
+}
--- /dev/null
+++ b/sse.h
@@ -1,0 +1,50 @@
+#define rAX 0
+#define rCX 1
+#define rDX 2
+#define rBX 3
+#define rSP 4
+#define rBP 5
+#define rSI 6
+#define rDI 7
+
+#define rX0 0
+#define rX1 1
+#define rX2 2
+#define rX3 3
+#define rX4 4
+#define rX5 5
+#define rX6 6
+
+#define OP(o, m, ro, rm) WORD $0x0F66; /* op + modr/m byte */ \
+ BYTE $(o); \
+ BYTE $(((m)<<6)|((ro)<<3)|(rm))
+#define OPi(o, m, ro, rm, i) OP((o), (m), (ro), (rm)); \
+ BYTE $(i)
+#define OP4(o, m, ro, rm) WORD $0x0F66; \
+ WORD $(o); \
+ BYTE $(((m)<<6)|((ro)<<3)|(rm))
+#define OP4i(o, m, ro, rm, i) OP4((o), (m), (ro), (rm)); \
+ BYTE $(i)
+
+/* MOVLPD */
+//opcode = 660F12
+//modrm = 01 000 000 [AX → X0] / 01 001 000 [AX → X1]
+//disp8 = 8 / 32
+#define MOVLPD(off, s, d) OPi(0x12, 0x1, (d), (s), (off))
+
+/* MOVHPD */
+//opcode = 660F16
+//modrm = 01 000 000 [AX → X0] / 01 001 000 [AX → X1]
+//disp8 = 16 / 40
+#define MOVHPD(off, s, d) OPi(0x16, 0x1, (d), (s), (off))
+
+/* HSUBPD */
+//opcode = 660F7D = 01100110 00001111 01111101
+//modrm = 11 000 000 [X0 → X0]
+#define HSUBPD(s, d) OP(0x7D, 0x3, (d), (s))
+
+/* DPPD */
+//opcode = 660F3A41 = 01100110 00001111 00111010 01000001
+//modrm = 11 000 001 [X1 → X0]
+//imm8 = 0011 0001
+#define DPPD(s, d) OP4i(0x413A, 0x3, (d), (s), 0x31)