shithub: riscv

Download patch

ref: 9e3ef5c777971707ab4ba426bb55d3bb2553ddf9
parent: d2af6b40af268fafdbd04c0222e785167b9ae021
author: cinap_lenrek <cinap_lenrek@felloff.net>
date: Sun Oct 4 15:50:24 EDT 2015

ape: add machine specific code for spim

--- /dev/null
+++ b/sys/src/ape/lib/ap/spim/memchr.s
@@ -1,0 +1,39 @@
+TEXT	memchr(SB), $0
+	MOVW	R1, 0(FP)
+
+	MOVW	n+8(FP), R1
+	MOVW	s1+0(FP), R2
+	MOVBU	c+4(FP), R3
+	ADDU	R1, R2, R6
+
+	AND	$(~1), R1, R5
+	ADDU	R2, R5
+	BEQ	R2, R5, lt2
+
+l1:
+	MOVBU	0(R2), R4
+	MOVBU	1(R2), R7
+	BEQ	R3, R4, eq0
+	ADDU	$2, R2
+	BEQ	R3, R7, eq
+	BNE	R2, R5, l1
+
+lt2:
+	BEQ	R2, R6, zret
+
+l2:
+	MOVBU	(R2), R4
+	ADDU	$1, R2
+	BEQ	R3, R4, eq
+	BNE	R2, R6, l2
+zret:
+	MOVW	R0, R1
+	RET
+
+eq0:
+	MOVW	R2, R1
+	RET
+
+eq:
+	SUBU	$1,R2, R1
+	RET
--- /dev/null
+++ b/sys/src/ape/lib/ap/spim/memcmp.s
@@ -1,0 +1,117 @@
+TEXT	memcmp(SB), $0
+	MOVW R1, 0(FP)
+
+/*
+ * performance:
+ *	alligned about 1.0us/call and 17.4mb/sec
+ *	unalligned is about 3.1mb/sec
+ */
+
+	MOVW	n+8(FP), R3		/* R3 is count */
+	MOVW	s1+0(FP), R4		/* R4 is pointer1 */
+	MOVW	s2+4(FP), R5		/* R5 is pointer2 */
+	ADDU	R3,R4, R6		/* R6 is end pointer1 */
+
+	/* TODO(mischief): fix multibyte copy */
+	JMP	out
+
+/*
+ * if not at least 4 chars,
+ * dont even mess around.
+ * 3 chars to guarantee any
+ * rounding up to a word
+ * boundary and 4 characters
+ * to get at least maybe one
+ * full word cmp.
+ */
+	SGT	$4,R3, R1
+	BNE	R1, out
+
+/*
+ * test if both pointers
+ * are similarly word alligned
+ */
+	XOR	R4,R5, R1
+	AND	$3, R1
+	BNE	R1, out
+
+/*
+ * byte at a time to word allign
+ */
+l1:
+	AND	$3,R4, R1
+	BEQ	R1, l2
+	MOVBU	0(R4), R8
+	MOVBU	0(R5), R9
+	ADDU	$1, R4
+	BNE	R8,R9, ne
+	ADDU	$1, R5
+	JMP	l1
+
+/*
+ * turn R3 into end pointer1-15
+ * cmp 16 at a time while theres room
+ */
+l2:
+	ADDU	$-15,R6, R3
+l3:
+	SGTU	R3,R4, R1
+	BEQ	R1, l4
+	MOVW	0(R4), R8
+	MOVW	0(R5), R9
+	MOVW	4(R4), R10
+	BNE	R8,R9, ne
+	MOVW	4(R5), R11
+	MOVW	8(R4), R8
+	BNE	R10,R11, ne1
+	MOVW	8(R5), R9
+	MOVW	12(R4), R10
+	BNE	R8,R9, ne
+	MOVW	12(R5), R11
+	ADDU	$16, R4
+	BNE	R10,R11, ne1
+	BNE	R8,R9, ne
+	ADDU	$16, R5
+	JMP	l3
+
+/*
+ * turn R3 into end pointer1-3
+ * cmp 4 at a time while theres room
+ */
+l4:
+	ADDU	$-3,R6, R3
+l5:
+	SGTU	R3,R4, R1
+	BEQ	R1, out
+	MOVW	0(R4), R8
+	MOVW	0(R5), R9
+	ADDU	$4, R4
+	BNE	R8,R9, ne	/* only works because big endian */
+	ADDU	$4, R5
+	JMP	l5
+
+/*
+ * last loop, cmp byte at a time
+ */
+out:
+	SGTU	R6,R4, R1
+	BEQ	R1, ret
+	MOVBU	0(R4), R8
+	MOVBU	0(R5), R9
+	ADDU	$1, R4
+	BNE	R8,R9, ne
+	ADDU	$1, R5
+	JMP	out
+
+ne1:
+	SGTU	R10,R11, R1
+	BNE	R1, ret
+	MOVW	$-1,R1
+	RET
+ne:
+	SGTU	R8,R9, R1
+	BNE	R1, ret
+	MOVW	$-1,R1
+ret:
+	RET
+	END
--- a/sys/src/ape/lib/ap/spim/mkfile
+++ b/sys/src/ape/lib/ap/spim/mkfile
@@ -1,30 +1,45 @@
 APE=/sys/src/ape
 <$APE/config
 LIB=/$objtype/lib/ape/libap.a
+
+MIPSSFILES=\
+	getfcr.s\
+	main9.s\
+	main9p.s\
+	memmove.s\
+	memset.s\
+	setjmp.s\
+	strcmp.s\
+	strcpy.s\
+	tas.s\
+
+MIPSCFILES=\
+	cycles.c\
+	lock.c\
+	notetramp.c\
+
+SFILES=\
+	memchr.s\
+	memcmp.s\
+	strchr.s\
+	vlop.s\
+
+CFILES=\
+	vlrt.c\
+
 OFILES=\
-	cycles.$O\
-	getfcr.$O\
-	lock.$O\
-	main9.$O\
-	main9p.$O\
-	memchr.$O\
-	memcmp.$O\
-	memmove.$O\
-	memset.$O\
-	notetramp.$O\
-	setjmp.$O\
-	strchr.$O\
-	strcmp.$O\
-	strcpy.$O\
-	tas.$O\
-	vlop.$O\
-	vlrt.$O\
+	${MIPSSFILES:%.s=%.$O}\
+	${SFILES:%.s=%.$O}\
+	${MIPSCFILES:%.c=%.$O}\
+	${CFILES:%.c=%.$O}\
 
-%.$O:	../mips/%.c
-	$CC -I../mips $CFLAGS ../mips/$stem.c
+MIPSS=`{echo $MIPSSFILES | sed 's/\.s//g; s/ /|/g'}
+^($MIPSS)\.$O:R:	'../mips/\1.s'
+	$AS $AFLAGS ../mips/$stem1.s
 
-%.$O:	../mips/%.s
-	$AS -I../mips $AFLAGS ../mips/$stem.s
+MIPSC=`{echo $MIPSCFILES | sed 's/\.c//g; s/ /|/g'}
+^($MIPSC)\.$O:R:	'../mips/\1.c'
+	$CC $CFLAGS ../mips/$stem1.c
 
 </sys/src/cmd/mksyslib
 
--- /dev/null
+++ b/sys/src/ape/lib/ap/spim/strchr.s
@@ -1,0 +1,63 @@
+TEXT	strchr(SB), $0
+	MOVW R1, 0(FP)
+	MOVB	c+4(FP), R4
+	MOVW	s+0(FP), R3
+
+	BEQ	R4, l2
+
+/*
+ * char is not null
+ */
+l1:
+	MOVB	(R3), R1
+	ADDU	$1, R3
+	BEQ	R1, ret
+	BNE	R1,R4, l1
+	JMP	rm1
+
+/*
+ * char is null
+ * align to word
+ */
+l2:
+	AND	$3,R3, R1
+	BEQ	R1, l3
+	MOVB	(R3), R1
+	ADDU	$1, R3
+	BNE	R1, l2
+	JMP	rm1
+
+l3:
+	MOVW	$0xff000000, R6
+	MOVW	$0x00ff0000, R7
+
+l4:
+	MOVW	(R3), R5
+	ADDU	$4, R3
+	AND	R6,R5, R1
+	AND	R7,R5, R2
+	BEQ	R1, b0
+	AND	$0xff00,R5, R1
+	BEQ	R2, b1
+	AND	$0xff,R5, R2
+	BEQ	R1, b2
+	BNE	R2, l4
+
+rm1:
+	ADDU	$-1,R3, R1
+	JMP	ret
+
+b2:
+	ADDU	$-2,R3, R1
+	JMP	ret
+
+b1:
+	ADDU	$-3,R3, R1
+	JMP	ret
+
+b0:
+	ADDU	$-4,R3, R1
+	JMP	ret
+
+ret:
+	RET
--- /dev/null
+++ b/sys/src/ape/lib/ap/spim/vlop.s
@@ -1,0 +1,20 @@
+/*
+ * from https://bitbucket.org/cherry9/plan9-loongson
+ */
+TEXT	_mulv(SB), $0
+	MOVW	8(FP), R2	/* hi1 */
+	MOVW	4(FP), R3	/* lo1 */
+	MOVW	16(FP), R4	/* hi2 */
+	MOVW	12(FP), R5	/* lo2 */
+	MULU	R5, R3	/* lo1*lo2 -> hi:lo*/
+	MOVW	LO, R6
+	MOVW	HI, R7
+	MULU	R3, R4	/* lo1*hi2 -> _:hi */
+	MOVW	LO, R8
+	ADDU	R8, R7
+	MULU	R2, R5	/* hi1*lo2 -> _:hi */
+	MOVW	LO, R8
+	ADDU	R8, R7
+	MOVW	R6, 0(R1)	/* lo */
+	MOVW	R7, 4(R1)	/* hi */
+	RET
--- /dev/null
+++ b/sys/src/ape/lib/ap/spim/vlrt.c
@@ -1,0 +1,759 @@
+typedef	unsigned long	ulong;
+typedef	unsigned int	uint;
+typedef	unsigned short	ushort;
+typedef	unsigned char	uchar;
+typedef	signed char	schar;
+
+#define	SIGN(n)	(1UL<<(n-1))
+
+typedef	struct	Vlong	Vlong;
+struct	Vlong
+{
+	union
+	{
+		struct
+		{
+			ulong	lo;
+			ulong	hi;
+		};
+		struct
+		{
+			ushort	loms;
+			ushort	lols;
+			ushort	hims;
+			ushort	hils;
+		};
+	};
+};
+
+void	abort(void);
+
+/* needed by profiler; can't be profiled. */
+#pragma profile off
+void
+_addv(Vlong *r, Vlong a, Vlong b)
+{
+	ulong lo, hi;
+
+	lo = a.lo + b.lo;
+	hi = a.hi + b.hi;
+	if(lo < a.lo)
+		hi++;
+	r->lo = lo;
+	r->hi = hi;
+}
+
+void
+_subv(Vlong *r, Vlong a, Vlong b)
+{
+	ulong lo, hi;
+
+	lo = a.lo - b.lo;
+	hi = a.hi - b.hi;
+	if(lo > a.lo)
+		hi--;
+	r->lo = lo;
+	r->hi = hi;
+}
+
+#pragma profile on
+
+void
+_d2v(Vlong *y, double d)
+{
+	union { double d; struct Vlong; } x;
+	ulong xhi, xlo, ylo, yhi;
+	int sh;
+
+	x.d = d;
+
+	xhi = (x.hi & 0xfffff) | 0x100000;
+	xlo = x.lo;
+	sh = 1075 - ((x.hi >> 20) & 0x7ff);
+
+	ylo = 0;
+	yhi = 0;
+	if(sh >= 0) {
+		/* v = (hi||lo) >> sh */
+		if(sh < 32) {
+			if(sh == 0) {
+				ylo = xlo;
+				yhi = xhi;
+			} else {
+				ylo = (xlo >> sh) | (xhi << (32-sh));
+				yhi = xhi >> sh;
+			}
+		} else {
+			if(sh == 32) {
+				ylo = xhi;
+			} else
+			if(sh < 64) {
+				ylo = xhi >> (sh-32);
+			}
+		}
+	} else {
+		/* v = (hi||lo) << -sh */
+		sh = -sh;
+		if(sh <= 10) {
+			ylo = xlo << sh;
+			yhi = (xhi << sh) | (xlo >> (32-sh));
+		} else {
+			/* overflow */
+			yhi = d;	/* causes something awful */
+		}
+	}
+	if(x.hi & SIGN(32)) {
+		if(ylo != 0) {
+			ylo = -ylo;
+			yhi = ~yhi;
+		} else
+			yhi = -yhi;
+	}
+
+	y->hi = yhi;
+	y->lo = ylo;
+}
+
+void
+_f2v(Vlong *y, float f)
+{
+	_d2v(y, f);
+}
+
+double
+_v2d(Vlong x)
+{
+	if(x.hi & SIGN(32)) {
+		if(x.lo) {
+			x.lo = -x.lo;
+			x.hi = ~x.hi;
+		} else
+			x.hi = -x.hi;
+		return -((long)x.hi*4294967296. + x.lo);
+	}
+	return (long)x.hi*4294967296. + x.lo;
+}
+
+float
+_v2f(Vlong x)
+{
+	return _v2d(x);
+}
+
+double
+_uv2d(Vlong x)
+{
+	return x.hi*4294967296. + x.lo;
+}
+
+float
+_uv2f(Vlong x)
+{
+	return _uv2d(x);
+}
+
+void
+_vasaddd(Vlong *ret, Vlong *lv, double v2d(Vlong), double rv)
+{
+	_d2v(lv, v2d(*lv)+rv);
+	*ret = *lv;
+}
+void
+_vassubd(Vlong *ret, Vlong *lv, double v2d(Vlong), double rv)
+{
+	_d2v(lv, v2d(*lv)-rv);
+	*ret = *lv;
+}
+void
+_vasmuld(Vlong *ret, Vlong *lv, double v2d(Vlong), double rv)
+{
+	_d2v(lv, v2d(*lv)*rv);
+	*ret = *lv;
+}
+void
+_vasdivd(Vlong *ret, Vlong *lv, double v2d(Vlong), double rv)
+{
+	_d2v(lv, v2d(*lv)/rv);
+	*ret = *lv;
+}
+
+static void
+dodiv(Vlong num, Vlong den, Vlong *qp, Vlong *rp)
+{
+	ulong numlo, numhi, denhi, denlo, quohi, quolo, t;
+	int i;
+
+	numhi = num.hi;
+	numlo = num.lo;
+	denhi = den.hi;
+	denlo = den.lo;
+
+	/*
+	 * get a divide by zero
+	 */
+	if(denlo==0 && denhi==0) {
+		numlo = numlo / denlo;
+	}
+
+	/*
+	 * set up the divisor and find the number of iterations needed
+	 */
+	if(numhi >= SIGN(32)) {
+		quohi = SIGN(32);
+		quolo = 0;
+	} else {
+		quohi = numhi;
+		quolo = numlo;
+	}
+	i = 0;
+	while(denhi < quohi || (denhi == quohi && denlo < quolo)) {
+		denhi = (denhi<<1) | (denlo>>31);
+		denlo <<= 1;
+		i++;
+	}
+
+	quohi = 0;
+	quolo = 0;
+	for(; i >= 0; i--) {
+		quohi = (quohi<<1) | (quolo>>31);
+		quolo <<= 1;
+		if(numhi > denhi || (numhi == denhi && numlo >= denlo)) {
+			t = numlo;
+			numlo -= denlo;
+			if(numlo > t)
+				numhi--;
+			numhi -= denhi;
+			quolo |= 1;
+		}
+		denlo = (denlo>>1) | (denhi<<31);
+		denhi >>= 1;
+	}
+
+	if(qp) {
+		qp->lo = quolo;
+		qp->hi = quohi;
+	}
+	if(rp) {
+		rp->lo = numlo;
+		rp->hi = numhi;
+	}
+}
+
+void
+_divvu(Vlong *q, Vlong n, Vlong d)
+{
+
+	if(n.hi == 0 && d.hi == 0) {
+		q->hi = 0;
+		q->lo = n.lo / d.lo;
+		return;
+	}
+	dodiv(n, d, q, 0);
+}
+
+void
+_modvu(Vlong *r, Vlong n, Vlong d)
+{
+
+	if(n.hi == 0 && d.hi == 0) {
+		r->hi = 0;
+		r->lo = n.lo % d.lo;
+		return;
+	}
+	dodiv(n, d, 0, r);
+}
+
+static void
+vneg(Vlong *v)
+{
+
+	if(v->lo == 0) {
+		v->hi = -v->hi;
+		return;
+	}
+	v->lo = -v->lo;
+	v->hi = ~v->hi;
+}
+
+void
+_divv(Vlong *q, Vlong n, Vlong d)
+{
+	long nneg, dneg;
+
+	if(n.hi == (((long)n.lo)>>31) && d.hi == (((long)d.lo)>>31)) {
+		q->lo = (long)n.lo / (long)d.lo;
+		q->hi = ((long)q->lo) >> 31;
+		return;
+	}
+	nneg = n.hi >> 31;
+	if(nneg)
+		vneg(&n);
+	dneg = d.hi >> 31;
+	if(dneg)
+		vneg(&d);
+	dodiv(n, d, q, 0);
+	if(nneg != dneg)
+		vneg(q);
+}
+
+void
+_modv(Vlong *r, Vlong n, Vlong d)
+{
+	long nneg, dneg;
+
+	if(n.hi == (((long)n.lo)>>31) && d.hi == (((long)d.lo)>>31)) {
+		r->lo = (long)n.lo % (long)d.lo;
+		r->hi = ((long)r->lo) >> 31;
+		return;
+	}
+	nneg = n.hi >> 31;
+	if(nneg)
+		vneg(&n);
+	dneg = d.hi >> 31;
+	if(dneg)
+		vneg(&d);
+	dodiv(n, d, 0, r);
+	if(nneg)
+		vneg(r);
+}
+
+void
+_rshav(Vlong *r, Vlong a, int b)
+{
+	long t;
+
+	t = a.hi;
+	if(b >= 32) {
+		r->hi = t>>31;
+		if(b >= 64) {
+			/* this is illegal re C standard */
+			r->lo = t>>31;
+			return;
+		}
+		r->lo = t >> (b-32);
+		return;
+	}
+	if(b <= 0) {
+		r->hi = t;
+		r->lo = a.lo;
+		return;
+	}
+	r->hi = t >> b;
+	r->lo = (t << (32-b)) | (a.lo >> b);
+}
+
+void
+_rshlv(Vlong *r, Vlong a, int b)
+{
+	ulong t;
+
+	t = a.hi;
+	if(b >= 32) {
+		r->hi = 0;
+		if(b >= 64) {
+			/* this is illegal re C standard */
+			r->lo = 0;
+			return;
+		}
+		r->lo = t >> (b-32);
+		return;
+	}
+	if(b <= 0) {
+		r->hi = t;
+		r->lo = a.lo;
+		return;
+	}
+	r->hi = t >> b;
+	r->lo = (t << (32-b)) | (a.lo >> b);
+}
+
+void
+_lshv(Vlong *r, Vlong a, int b)
+{
+	ulong t;
+
+	t = a.lo;
+	if(b >= 32) {
+		r->lo = 0;
+		if(b >= 64) {
+			/* this is illegal re C standard */
+			r->hi = 0;
+			return;
+		}
+		r->hi = t << (b-32);
+		return;
+	}
+	if(b <= 0) {
+		r->lo = t;
+		r->hi = a.hi;
+		return;
+	}
+	r->lo = t << b;
+	r->hi = (t >> (32-b)) | (a.hi << b);
+}
+
+void
+_andv(Vlong *r, Vlong a, Vlong b)
+{
+	r->hi = a.hi & b.hi;
+	r->lo = a.lo & b.lo;
+}
+
+void
+_orv(Vlong *r, Vlong a, Vlong b)
+{
+	r->hi = a.hi | b.hi;
+	r->lo = a.lo | b.lo;
+}
+
+void
+_xorv(Vlong *r, Vlong a, Vlong b)
+{
+	r->hi = a.hi ^ b.hi;
+	r->lo = a.lo ^ b.lo;
+}
+
+void
+_vpp(Vlong *l, Vlong *r)
+{
+
+	l->hi = r->hi;
+	l->lo = r->lo;
+	r->lo++;
+	if(r->lo == 0)
+		r->hi++;
+}
+
+void
+_vmm(Vlong *l, Vlong *r)
+{
+
+	l->hi = r->hi;
+	l->lo = r->lo;
+	if(r->lo == 0)
+		r->hi--;
+	r->lo--;
+}
+
+void
+_ppv(Vlong *l, Vlong *r)
+{
+
+	r->lo++;
+	if(r->lo == 0)
+		r->hi++;
+	l->hi = r->hi;
+	l->lo = r->lo;
+}
+
+void
+_mmv(Vlong *l, Vlong *r)
+{
+
+	if(r->lo == 0)
+		r->hi--;
+	r->lo--;
+	l->hi = r->hi;
+	l->lo = r->lo;
+}
+
+void
+_vasop(Vlong *ret, void *lv, void fn(Vlong*, Vlong, Vlong), int type, Vlong rv)
+{
+	Vlong t, u;
+
+	u.lo = 0;
+	u.hi = 0;
+	switch(type) {
+	default:
+		abort();
+		break;
+
+	case 1:	/* schar */
+		t.lo = *(schar*)lv;
+		t.hi = t.lo >> 31;
+		fn(&u, t, rv);
+		*(schar*)lv = u.lo;
+		break;
+
+	case 2:	/* uchar */
+		t.lo = *(uchar*)lv;
+		t.hi = 0;
+		fn(&u, t, rv);
+		*(uchar*)lv = u.lo;
+		break;
+
+	case 3:	/* short */
+		t.lo = *(short*)lv;
+		t.hi = t.lo >> 31;
+		fn(&u, t, rv);
+		*(short*)lv = u.lo;
+		break;
+
+	case 4:	/* ushort */
+		t.lo = *(ushort*)lv;
+		t.hi = 0;
+		fn(&u, t, rv);
+		*(ushort*)lv = u.lo;
+		break;
+
+	case 9:	/* int */
+		t.lo = *(int*)lv;
+		t.hi = t.lo >> 31;
+		fn(&u, t, rv);
+		*(int*)lv = u.lo;
+		break;
+
+	case 10:	/* uint */
+		t.lo = *(uint*)lv;
+		t.hi = 0;
+		fn(&u, t, rv);
+		*(uint*)lv = u.lo;
+		break;
+
+	case 5:	/* long */
+		t.lo = *(long*)lv;
+		t.hi = t.lo >> 31;
+		fn(&u, t, rv);
+		*(long*)lv = u.lo;
+		break;
+
+	case 6:	/* ulong */
+		t.lo = *(ulong*)lv;
+		t.hi = 0;
+		fn(&u, t, rv);
+		*(ulong*)lv = u.lo;
+		break;
+
+	case 7:	/* vlong */
+	case 8:	/* uvlong */
+		fn(&u, *(Vlong*)lv, rv);
+		*(Vlong*)lv = u;
+		break;
+	}
+	*ret = u;
+}
+
+void
+_p2v(Vlong *ret, void *p)
+{
+	long t;
+
+	t = (ulong)p;
+	ret->lo = t;
+	ret->hi = 0;
+}
+
+void
+_sl2v(Vlong *ret, long sl)
+{
+	long t;
+
+	t = sl;
+	ret->lo = t;
+	ret->hi = t >> 31;
+}
+
+void
+_ul2v(Vlong *ret, ulong ul)
+{
+	long t;
+
+	t = ul;
+	ret->lo = t;
+	ret->hi = 0;
+}
+
+void
+_si2v(Vlong *ret, int si)
+{
+	long t;
+
+	t = si;
+	ret->lo = t;
+	ret->hi = t >> 31;
+}
+
+void
+_ui2v(Vlong *ret, uint ui)
+{
+	long t;
+
+	t = ui;
+	ret->lo = t;
+	ret->hi = 0;
+}
+
+void
+_sh2v(Vlong *ret, long sh)
+{
+	long t;
+
+	t = (sh << 16) >> 16;
+	ret->lo = t;
+	ret->hi = t >> 31;
+}
+
+void
+_uh2v(Vlong *ret, ulong ul)
+{
+	long t;
+
+	t = ul & 0xffff;
+	ret->lo = t;
+	ret->hi = 0;
+}
+
+void
+_sc2v(Vlong *ret, long uc)
+{
+	long t;
+
+	t = (uc << 24) >> 24;
+	ret->lo = t;
+	ret->hi = t >> 31;
+}
+
+void
+_uc2v(Vlong *ret, ulong ul)
+{
+	long t;
+
+	t = ul & 0xff;
+	ret->lo = t;
+	ret->hi = 0;
+}
+
+long
+_v2sc(Vlong rv)
+{
+	long t;
+
+	t = rv.lo & 0xff;
+	return (t << 24) >> 24;
+}
+
+long
+_v2uc(Vlong rv)
+{
+
+	return rv.lo & 0xff;
+}
+
+long
+_v2sh(Vlong rv)
+{
+	long t;
+
+	t = rv.lo & 0xffff;
+	return (t << 16) >> 16;
+}
+
+long
+_v2uh(Vlong rv)
+{
+
+	return rv.lo & 0xffff;
+}
+
+long
+_v2sl(Vlong rv)
+{
+
+	return rv.lo;
+}
+
+long
+_v2ul(Vlong rv)
+{
+
+	return rv.lo;
+}
+
+long
+_v2si(Vlong rv)
+{
+
+	return rv.lo;
+}
+
+long
+_v2ui(Vlong rv)
+{
+
+	return rv.lo;
+}
+
+int
+_testv(Vlong rv)
+{
+	return rv.lo || rv.hi;
+}
+
+int
+_eqv(Vlong lv, Vlong rv)
+{
+	return lv.lo == rv.lo && lv.hi == rv.hi;
+}
+
+int
+_nev(Vlong lv, Vlong rv)
+{
+	return lv.lo != rv.lo || lv.hi != rv.hi;
+}
+
+int
+_ltv(Vlong lv, Vlong rv)
+{
+	return (long)lv.hi < (long)rv.hi || 
+		(lv.hi == rv.hi && lv.lo < rv.lo);
+}
+
+int
+_lev(Vlong lv, Vlong rv)
+{
+	return (long)lv.hi < (long)rv.hi || 
+		(lv.hi == rv.hi && lv.lo <= rv.lo);
+}
+
+int
+_gtv(Vlong lv, Vlong rv)
+{
+	return (long)lv.hi > (long)rv.hi || 
+		(lv.hi == rv.hi && lv.lo > rv.lo);
+}
+
+int
+_gev(Vlong lv, Vlong rv)
+{
+	return (long)lv.hi > (long)rv.hi || 
+		(lv.hi == rv.hi && lv.lo >= rv.lo);
+}
+
+int
+_lov(Vlong lv, Vlong rv)
+{
+	return lv.hi < rv.hi || 
+		(lv.hi == rv.hi && lv.lo < rv.lo);
+}
+
+int
+_lsv(Vlong lv, Vlong rv)
+{
+	return lv.hi < rv.hi || 
+		(lv.hi == rv.hi && lv.lo <= rv.lo);
+}
+
+int
+_hiv(Vlong lv, Vlong rv)
+{
+	return lv.hi > rv.hi || 
+		(lv.hi == rv.hi && lv.lo > rv.lo);
+}
+
+int
+_hsv(Vlong lv, Vlong rv)
+{
+	return lv.hi > rv.hi || 
+		(lv.hi == rv.hi && lv.lo >= rv.lo);
+}