ref: a9f4ddade4bb5658b19097a11d139265d57b9748
dir: /sys/src/libc/power/vlrt.c/
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 { ulong hi; ulong lo; }; void abort(void); void _divu64(Vlong, Vlong, Vlong*, Vlong*); void _d2v(Vlong *y, double d) { union { double d; 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.lo) { return (long)x.hi*4294967296.; } if(x.hi & SIGN(32)) { x.lo = -x.lo; 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; } 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; } _divu64(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; } _divu64(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); _divu64(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); _divu64(n, d, 0, r); if(nneg) vneg(r); } void _vasop(Vlong *ret, void *lv, void fn(Vlong*, Vlong, Vlong), int type, Vlong rv) { Vlong t, u; u = *ret; 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; }