diff options
Diffstat (limited to 'src/pkg/runtime/arm')
-rw-r--r-- | src/pkg/runtime/arm/asm.s | 112 | ||||
-rw-r--r-- | src/pkg/runtime/arm/cas5.s | 8 | ||||
-rw-r--r-- | src/pkg/runtime/arm/cas6.s | 2 | ||||
-rw-r--r-- | src/pkg/runtime/arm/closure.c | 14 | ||||
-rw-r--r-- | src/pkg/runtime/arm/memmove.s | 2 | ||||
-rw-r--r-- | src/pkg/runtime/arm/memset.s | 2 | ||||
-rw-r--r-- | src/pkg/runtime/arm/softfloat.c | 784 | ||||
-rw-r--r-- | src/pkg/runtime/arm/traceback.c | 32 | ||||
-rw-r--r-- | src/pkg/runtime/arm/vlop.s | 22 | ||||
-rw-r--r-- | src/pkg/runtime/arm/vlrt.c | 854 |
10 files changed, 970 insertions, 862 deletions
diff --git a/src/pkg/runtime/arm/asm.s b/src/pkg/runtime/arm/asm.s index 1144ff2a1..44c47bad1 100644 --- a/src/pkg/runtime/arm/asm.s +++ b/src/pkg/runtime/arm/asm.s @@ -6,7 +6,7 @@ // using frame size $-4 means do not save LR on stack. TEXT _rt0_arm(SB),7,$-4 - MOVW $setR12(SB), R12 + MOVW $0xcafebabe, R12 // copy arguments forward on an even stack // use R13 instead of SP to avoid linker rewriting the offsets @@ -19,8 +19,8 @@ TEXT _rt0_arm(SB),7,$-4 // set up m and g registers // g is R10, m is R9 - MOVW $g0(SB), g - MOVW $m0(SB), m + MOVW $runtime·g0(SB), g + MOVW $runtime·m0(SB), m // save m->g0 = g0 MOVW g, m_g0(m) @@ -29,45 +29,47 @@ TEXT _rt0_arm(SB),7,$-4 MOVW $(-8192+104)(R13), R0 MOVW R0, g_stackguard(g) // (w 104b guard) MOVW R13, g_stackbase(g) - BL emptyfunc(SB) // fault if stack check is wrong + BL runtime·emptyfunc(SB) // fault if stack check is wrong - BL check(SB) + BL runtime·check(SB) // saved argc, argv MOVW 120(R13), R0 MOVW R0, 4(R13) MOVW 124(R13), R1 MOVW R1, 8(R13) - BL args(SB) - BL osinit(SB) - BL schedinit(SB) + BL runtime·args(SB) + BL runtime·osinit(SB) + BL runtime·schedinit(SB) // create a new goroutine to start program - MOVW $mainstart(SB), R0 + MOVW $runtime·mainstart(SB), R0 MOVW.W R0, -4(R13) MOVW $8, R0 MOVW.W R0, -4(R13) MOVW $0, R0 MOVW.W R0, -4(R13) // push $0 as guard - BL ·newproc(SB) + BL runtime·newproc(SB) MOVW $12(R13), R13 // pop args and LR // start this M - BL mstart(SB) + BL runtime·mstart(SB) MOVW $1234, R0 MOVW $1000, R1 MOVW R0, (R1) // fail hard - B _dep_dummy(SB) // Never reached + B runtime·_dep_dummy(SB) // Never reached -TEXT mainstart(SB),7,$4 +TEXT runtime·mainstart(SB),7,$4 BL main·init(SB) - BL initdone(SB) + BL runtime·initdone(SB) + EOR R0, R0 + MOVW R0, 0(R13) BL main·main(SB) MOVW $0, R0 MOVW R0, 4(SP) - BL exit(SB) + BL runtime·exit(SB) MOVW $1234, R0 MOVW $1001, R1 MOVW R0, (R1) // fail hard @@ -75,7 +77,7 @@ TEXT mainstart(SB),7,$4 // TODO(kaib): remove these once i actually understand how the linker removes symbols // pull in dummy dependencies -TEXT _dep_dummy(SB),7,$0 +TEXT runtime·_dep_dummy(SB),7,$0 BL _div(SB) BL _divu(SB) BL _mod(SB) @@ -83,8 +85,8 @@ TEXT _dep_dummy(SB),7,$0 BL _modu(SB) BL _sfloat(SB) -TEXT breakpoint(SB),7,$0 - BL abort(SB) +TEXT runtime·breakpoint(SB),7,$0 + // no breakpoint yet; let program exit RET /* @@ -93,8 +95,8 @@ TEXT breakpoint(SB),7,$0 // uintptr gosave(Gobuf*) // save state in Gobuf; setjmp -TEXT gosave(SB), 7, $-4 - MOVW 0(FP), R0 +TEXT runtime·gosave(SB), 7, $-4 + MOVW 0(FP), R0 // gobuf MOVW SP, gobuf_sp(R0) MOVW LR, gobuf_pc(R0) MOVW g, gobuf_g(R0) @@ -103,8 +105,8 @@ TEXT gosave(SB), 7, $-4 // void gogo(Gobuf*, uintptr) // restore state from Gobuf; longjmp -TEXT gogo(SB), 7, $-4 - MOVW 0(FP), R1 // gobuf +TEXT runtime·gogo(SB), 7, $-4 + MOVW 0(FP), R1 // gobuf MOVW 4(FP), R0 // return 2nd arg MOVW gobuf_g(R1), g MOVW 0(g), R2 // make sure g != nil @@ -115,11 +117,12 @@ TEXT gogo(SB), 7, $-4 // restore state from Gobuf but then call fn. // (call fn, returning to state in Gobuf) // using frame size $-4 means do not save LR on stack. -TEXT gogocall(SB), 7, $-4 - MOVW 0(FP), R0 +TEXT runtime·gogocall(SB), 7, $-4 + MOVW 0(FP), R0 // gobuf MOVW 4(FP), R1 // fn + MOVW 8(FP), R2 // fp offset MOVW gobuf_g(R0), g - MOVW 0(g), R2 // make sure g != nil + MOVW 0(g), R3 // make sure g != nil MOVW gobuf_sp(R0), SP // restore SP MOVW gobuf_pc(R0), LR MOVW R1, PC @@ -135,12 +138,11 @@ TEXT gogocall(SB), 7, $-4 // NB. we do not save R0 because we've forced 5c to pass all arguments // on the stack. // using frame size $-4 means do not save LR on stack. -TEXT ·morestack(SB),7,$-4 +TEXT runtime·morestack(SB),7,$-4 // Cannot grow scheduler stack (m->g0). MOVW m_g0(m), R4 CMP g, R4 - BNE 2(PC) - BL abort(SB) + BL.EQ runtime·abort(SB) // Save in m. MOVW R1, m_moreframe(m) @@ -148,9 +150,9 @@ TEXT ·morestack(SB),7,$-4 // Called from f. // Set m->morebuf to f's caller. - MOVW R3, (m_morebuf+gobuf_pc)(m) // f's caller's PC - MOVW SP, (m_morebuf+gobuf_sp)(m) // f's caller's SP - MOVW SP, m_morefp(m) // f's caller's SP + MOVW R3, (m_morebuf+gobuf_pc)(m) // f's caller's PC + MOVW SP, (m_morebuf+gobuf_sp)(m) // f's caller's SP + MOVW SP, m_morefp(m) // f's caller's SP MOVW g, (m_morebuf+gobuf_g)(m) // Set m->morepc to f's PC. @@ -159,7 +161,7 @@ TEXT ·morestack(SB),7,$-4 // Call newstack on m's scheduling stack. MOVW m_g0(m), g MOVW (m_sched+gobuf_sp)(m), SP - B newstack(SB) + B runtime·newstack(SB) // Called from reflection library. Mimics morestack, // reuses stack growth code to create a frame @@ -179,45 +181,48 @@ TEXT reflect·call(SB), 7, $-4 // If it turns out that f needs a larger frame than // the default stack, f's usual stack growth prolog will // allocate a new segment (and recopy the arguments). - MOVW 4(SP), R0 // fn - MOVW 8(SP), R1 // arg frame - MOVW 12(SP), R2 // arg size + MOVW 4(SP), R0 // fn + MOVW 8(SP), R1 // arg frame + MOVW 12(SP), R2 // arg size - MOVW R0, m_morepc(m) // f's PC - MOVW R1, m_morefp(m) // argument frame pointer - MOVW R2, m_moreargs(m) // f's argument size + SUB $4,R1 // add the saved LR to the frame + ADD $4,R2 + + MOVW R0, m_morepc(m) // f's PC + MOVW R1, m_morefp(m) // argument frame pointer + MOVW R2, m_moreargs(m) // f's argument size MOVW $1, R3 - MOVW R3, m_moreframe(m) // f's frame size + MOVW R3, m_moreframe(m) // f's frame size // Call newstack on m's scheduling stack. MOVW m_g0(m), g MOVW (m_sched+gobuf_sp)(m), SP - B newstack(SB) + B runtime·newstack(SB) // Return point when leaving stack. // using frame size $-4 means do not save LR on stack. -TEXT ·lessstack(SB), 7, $-4 +TEXT runtime·lessstack(SB), 7, $-4 // Save return value in m->cret MOVW R0, m_cret(m) // Call oldstack on m's scheduling stack. MOVW m_g0(m), g MOVW (m_sched+gobuf_sp)(m), SP - B oldstack(SB) + B runtime·oldstack(SB) // void jmpdefer(fn, sp); // called from deferreturn. // 1. grab stored LR for caller // 2. sub 4 bytes to get back to BL deferreturn // 3. B to fn -TEXT jmpdefer(SB), 7, $0 +TEXT runtime·jmpdefer(SB), 7, $0 MOVW 0(SP), LR MOVW $-4(LR), LR // BL deferreturn MOVW 4(SP), R0 // fn MOVW 8(SP), SP B (R0) -TEXT ·memclr(SB),7,$20 +TEXT runtime·memclr(SB),7,$20 MOVW 0(FP), R0 MOVW $0, R1 // c = 0 MOVW R1, -16(SP) @@ -225,21 +230,21 @@ TEXT ·memclr(SB),7,$20 MOVW R1, -12(SP) MOVW m, -8(SP) // Save m and g MOVW g, -4(SP) - BL memset(SB) + BL runtime·memset(SB) MOVW -8(SP), m // Restore m and g, memset clobbers them MOVW -4(SP), g RET -TEXT ·getcallerpc+0(SB),7,$-4 +TEXT runtime·getcallerpc(SB),7,$-4 MOVW 0(SP), R0 RET -TEXT ·setcallerpc+0(SB),7,$-4 +TEXT runtime·setcallerpc(SB),7,$-4 MOVW x+4(FP), R0 MOVW R0, 0(SP) RET -TEXT getcallersp(SB),7,$-4 +TEXT runtime·getcallersp(SB),7,$-4 MOVW 0(FP), R0 MOVW $-4(R0), R0 RET @@ -248,8 +253,8 @@ TEXT getcallersp(SB),7,$-4 // Just call fn(arg), but first align the stack // appropriately for the gcc ABI. // TODO(kaib): figure out the arm-gcc ABI -TEXT runcgo(SB),7,$16 - BL abort(SB) +TEXT runtime·runcgo(SB),7,$16 + BL runtime·abort(SB) // MOVL fn+0(FP), AX // MOVL arg+4(FP), BX // MOVL SP, CX @@ -260,10 +265,13 @@ TEXT runcgo(SB),7,$16 // MOVL 4(SP), SP // RET -TEXT emptyfunc(SB),0,$0 +TEXT runtime·emptyfunc(SB),0,$0 RET -TEXT abort(SB),7,$-4 +TEXT runtime·abort(SB),7,$-4 MOVW $0, R0 MOVW (R0), R1 +TEXT runtime·runcgocallback(SB),7,$0 + MOVW $0, R0 + MOVW (R0), R1 diff --git a/src/pkg/runtime/arm/cas5.s b/src/pkg/runtime/arm/cas5.s index 8a4c8be12..20bd3c3e2 100644 --- a/src/pkg/runtime/arm/cas5.s +++ b/src/pkg/runtime/arm/cas5.s @@ -14,12 +14,12 @@ // }else // return 0; -TEXT cas(SB),7,$0 +TEXT runtime·cas(SB),7,$0 MOVW 0(FP), R0 // *val MOVW 4(FP), R1 // old MOVW 8(FP), R2 // new MOVW $1, R3 - MOVW $cas_mutex(SB), R4 + MOVW $runtime·cas_mutex(SB), R4 l: SWPW (R4), R3 // acquire mutex CMP $0, R3 @@ -39,5 +39,5 @@ fail0: MOVW $0, R0 RET -DATA cas_mutex(SB)/4, $0 -GLOBL cas_mutex(SB), $4 +DATA runtime·cas_mutex(SB)/4, $0 +GLOBL runtime·cas_mutex(SB), $4 diff --git a/src/pkg/runtime/arm/cas6.s b/src/pkg/runtime/arm/cas6.s index 63df1396d..43788b28a 100644 --- a/src/pkg/runtime/arm/cas6.s +++ b/src/pkg/runtime/arm/cas6.s @@ -10,7 +10,7 @@ // }else // return 0; -TEXT cas(SB),7,$0 +TEXT runtime·cas(SB),7,$0 MOVW 0(FP), R1 // *val MOVW 4(FP), R2 // old MOVW 8(FP), R3 // new diff --git a/src/pkg/runtime/arm/closure.c b/src/pkg/runtime/arm/closure.c index 11a7719c9..3aca3a42d 100644 --- a/src/pkg/runtime/arm/closure.c +++ b/src/pkg/runtime/arm/closure.c @@ -47,20 +47,20 @@ extern void cacheflush(byte* start, byte* end); #pragma textflag 7 void -·closure(int32 siz, byte *fn, byte *arg0) +runtime·closure(int32 siz, byte *fn, byte *arg0) { byte *p, *q, **ret; uint32 *pc; int32 n; if(siz < 0 || siz%4 != 0) - throw("bad closure size"); + runtime·throw("bad closure size"); ret = (byte**)((byte*)&arg0 + siz); if(siz > 100) { // TODO(kaib): implement stack growth preamble? - throw("closure too big"); + runtime·throw("closure too big"); } // size of new fn. @@ -73,7 +73,7 @@ void // store args aligned after code, so gc can find them. n += siz; - p = mal(n); + p = runtime·mal(n); *ret = p; q = p + n - siz; @@ -83,7 +83,7 @@ void *pc++ = 0xe52de000 | (siz + 4); if(siz > 0) { - mcpy(q, (byte*)&arg0, siz); + runtime·mcpy(q, (byte*)&arg0, siz); // MOVW $vars(PC), R0 *pc = 0xe28f0000 | (int32)(q - (byte*)pc - 8); @@ -122,8 +122,8 @@ void p = (byte*)pc; if(p > q) - throw("bad math in sys.closure"); + runtime·throw("bad math in sys.closure"); - cacheflush(*ret, q+siz); + runtime·cacheflush(*ret, q+siz); } diff --git a/src/pkg/runtime/arm/memmove.s b/src/pkg/runtime/arm/memmove.s index 9f7dc1dd2..5c0e57404 100644 --- a/src/pkg/runtime/arm/memmove.s +++ b/src/pkg/runtime/arm/memmove.s @@ -31,7 +31,7 @@ TMP = 3 /* N and TMP don't overlap */ TMP1 = 4 // TODO(kaib): This can be done with the existing registers of LR is re-used. Same for memset. -TEXT memmove(SB), 7, $8 +TEXT runtime·memmove(SB), 7, $8 // save g and m MOVW R9, 4(R13) MOVW R10, 8(R13) diff --git a/src/pkg/runtime/arm/memset.s b/src/pkg/runtime/arm/memset.s index cce94534c..974b8da7a 100644 --- a/src/pkg/runtime/arm/memset.s +++ b/src/pkg/runtime/arm/memset.s @@ -31,7 +31,7 @@ TMP = 3 /* N and TMP don't overlap */ // TODO(kaib): memset clobbers R9 and R10 (m and g). This makes the // registers unpredictable if (when) memset SIGSEGV's. Fix it by // moving the R4-R11 register bank. -TEXT memset(SB), $0 +TEXT runtime·memset(SB), $0 MOVW R0, R(TO) MOVW data+4(FP), R(4) MOVW n+8(FP), R(N) diff --git a/src/pkg/runtime/arm/softfloat.c b/src/pkg/runtime/arm/softfloat.c index 46ab07c82..f60fab14f 100644 --- a/src/pkg/runtime/arm/softfloat.c +++ b/src/pkg/runtime/arm/softfloat.c @@ -2,428 +2,498 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +// Software floating point interpretaton of ARM 7500 FP instructions. +// The interpretation is not bit compatible with the 7500. +// It uses true little-endian doubles, while the 7500 used mixed-endian. + #include "runtime.h" -void abort(void); +#define CPSR 14 +#define FLAGS_N (1 << 31) +#define FLAGS_Z (1 << 30) +#define FLAGS_C (1 << 29) +#define FLAGS_V (1 << 28) + +void runtime·abort(void); + +static uint32 trace = 0; static void fabort(void) { if (1) { - printf("Unsupported floating point instruction\n"); - abort(); + runtime·printf("Unsupported floating point instruction\n"); + runtime·abort(); } } -static uint32 doabort = 0; -static uint32 trace = 0; - -#define DOUBLE_EXPBIAS 1023 -#define SINGLE_EXPBIAS 127 - -static const int8* opnames[] = { - // binary - "adf", - "muf", - "suf", - "rsf", - "dvf", - "rdf", - "pow", - "rpw", - "rmf", - "fml", - "fdv", - "frd", - "pol", - "UNDEFINED", - "UNDEFINED", - "UNDEFINED", - - // unary - "mvf", - "mnf", - "abs", - "rnd", - "sqt", - "log", - "lgn", - "exp", - "sin", - "cos", - "tan", - "asn", - "acs", - "atn", - "urd", - "nrm" -}; - -static const int8* fpconst[] = { - "0.0", "1.0", "2.0", "3.0", "4.0", "5.0", "0.5", "10.0", -}; - -static const uint64 fpdconst[] = { - 0x0000000000000000ll, - 0x3ff0000000000000ll, - 0x4000000000000000ll, - 0x4008000000000000ll, - 0x4010000000000000ll, - 0x4014000000000000ll, - 0x3fe0000000000000ll, - 0x4024000000000000ll -}; - -static const int8* fpprec[] = { - "s", "d", "e", "?" -}; - -static uint32 -precision(uint32 i) -{ - switch (i&0x00080080) { - case 0: - return 0; - case 0x80: - return 1; - default: - fabort(); - } - return 0; -} - -static uint64 -frhs(uint32 rhs) -{ - if (rhs & 0x8) { - return fpdconst[rhs&0x7]; - } else { - return m->freg[rhs&0x7]; - } -} - -static int32 -fexp(uint64 f) +static void +putf(uint32 reg, uint32 val) { - return (int32)((uint32)(f >> 52) & 0x7ff) - DOUBLE_EXPBIAS; + m->freglo[reg] = val; } -static uint32 -fsign(uint64 f) +static void +putd(uint32 reg, uint64 val) { - return (uint32)(f >> 63) & 0x1; + m->freglo[reg] = (uint32)val; + m->freghi[reg] = (uint32)(val>>32); } static uint64 -fmantissa(uint64 f) +getd(uint32 reg) { - return f &0x000fffffffffffffll; + return (uint64)m->freglo[reg] | ((uint64)m->freghi[reg]<<32); } static void -fprint() +fprint(void) { uint32 i; - for (i = 0; i < 8; i++) { - printf("\tf%d:\t%X\n", i, m->freg[i]); + for (i = 0; i < 16; i++) { + runtime·printf("\tf%d:\t%X %X\n", i, m->freghi[i], m->freglo[i]); } } static uint32 -d2s(uint64 d) +d2f(uint64 d) { - return (d>>32 & 0x80000000) | //sign - ((uint32)(fexp(d) + SINGLE_EXPBIAS) & 0xff) << 23 | // exponent - (d >> 29 & 0x7fffff); // mantissa + uint32 x; + + runtime·f64to32c(d, &x); + return x; } static uint64 -s2d(uint32 s) +f2d(uint32 f) { - return (uint64)(s & 0x80000000) << 63 | // sign - (uint64)((s >> 23 &0xff) + (DOUBLE_EXPBIAS - SINGLE_EXPBIAS)) << 52 | // exponent - (uint64)(s & 0x7fffff) << 29; // mantissa + uint64 x; + + runtime·f32to64c(f, &x); + return x; } -// cdp, data processing instructions -static void -dataprocess(uint32* pc) +static uint32 +fstatus(bool nan, int32 cmp) { - uint32 i, opcode, unary, dest, lhs, rhs, prec; - uint32 high; - uint64 fraw0, fraw1, exp, sign; - uint64 fd, f0, f1; - - i = *pc; - - // data processing - opcode = i>>20 & 15; - unary = i>>15 & 1; - - dest = i>>12 & 7; - lhs = i>>16 & 7; - rhs = i & 15; - - prec = precision(i); - if (unary) { - switch (opcode) { - case 0: // mvf - m->freg[dest] = frhs(rhs); - goto ret; - default: - goto undef; - } - } else { - switch (opcode) { - case 1: // muf - fraw0 = m->freg[lhs]; - fraw1 = frhs(rhs); - f0 = fraw0>>21 & 0xffffffff | 0x80000000; - f1 = fraw1>>21 & 0xffffffff | 0x80000000; - fd = f0*f1; - high = fd >> 63; - if (high) - fd = fd >> 11 & 0x000fffffffffffffll; - else - fd = fd >> 10 & 0x000fffffffffffffll; - exp = (uint64)(fexp(fraw0) + fexp(fraw1) + !!high + DOUBLE_EXPBIAS) & 0x7ff; - sign = fraw0 >> 63 ^ fraw1 >> 63; - fd = sign << 63 | exp <<52 | fd; - m->freg[dest] = fd; - goto ret; - default: - goto undef; - } - } - -undef: - doabort = 1; - -ret: - if (trace || doabort) { - printf(" %p %x\t%s%s\tf%d, ", pc, *pc, opnames[opcode | unary<<4], - fpprec[prec], dest); - if (!unary) - printf("f%d, ", lhs); - if (rhs & 0x8) - printf("#%s\n", fpconst[rhs&0x7]); - else - printf("f%d\n", rhs&0x7); - } - if (doabort) - fabort(); + if(nan) + return FLAGS_C | FLAGS_V; + if(cmp == 0) + return FLAGS_Z | FLAGS_C; + if(cmp < 0) + return FLAGS_N; + return FLAGS_C; } -#define CPSR 14 -#define FLAGS_N (1 << 31) -#define FLAGS_Z (1 << 30) -#define FLAGS_C (1 << 29) - -// cmf, compare floating point -static void -compare(uint32 *pc, uint32 *regs) { - uint32 i, flags, lhs, rhs, sign0, sign1; - uint32 f0, f1, mant0, mant1; - int32 exp0, exp1; +// returns number of words that the fp instruction +// is occupying, 0 if next instruction isn't float. +static uint32 +stepflt(uint32 *pc, uint32 *regs) +{ + uint32 i, regd, regm, regn; + uint32 *addr; + uint64 uval; + int64 sval; + bool nan, ok; + int32 cmp; i = *pc; - flags = 0; - lhs = i>>16 & 0x7; - rhs = i & 0xf; - - f0 = m->freg[lhs]; - f1 = frhs(rhs); - if (f0 == f1) { - flags = FLAGS_Z | FLAGS_C; - goto ret; - } - sign0 = fsign(f0); - sign1 = fsign(f1); - if (sign0 == 1 && sign1 == 0) { - flags = FLAGS_N; - goto ret; + if(trace) + runtime·printf("stepflt %p %x\n", pc, i); + + // special cases + if((i&0xfffff000) == 0xe59fb000) { + // load r11 from pc-relative address. + // might be part of a floating point move + // (or might not, but no harm in simulating + // one instruction too many). + addr = (uint32*)((uint8*)pc + (i&0xfff) + 8); + regs[11] = addr[0]; + + if(trace) + runtime·printf("*** cpu R[%d] = *(%p) %x\n", + 11, addr, regs[11]); + return 1; } - if (sign0 == 0 && sign1 == 1) { - flags = FLAGS_C; - goto ret; + if(i == 0xe08bb00d) { + // add sp to 11. + // might be part of a large stack offset address + // (or might not, but again no harm done). + regs[11] += regs[13]; + + if(trace) + runtime·printf("*** cpu R[%d] += R[%d] %x\n", + 11, 13, regs[11]); + return 1; } + if(i == 0xeef1fa10) { + regs[CPSR] = (regs[CPSR]&0x0fffffff) | m->fflag; - if (sign0 == 0) { - exp0 = fexp(f0); - exp1 = fexp(f1); - mant0 = fmantissa(f0); - mant1 = fmantissa(f1); - } else { - exp0 = fexp(f1); - exp1 = fexp(f0); - mant0 = fmantissa(f1); - mant1 = fmantissa(f0); + if(trace) + runtime·printf("*** fpsr R[CPSR] = F[CPSR] %x\n", regs[CPSR]); + return 1; } + goto stage1; - if (exp0 > exp1) { - flags = FLAGS_C; - } else if (exp0 < exp1) { - flags = FLAGS_N; - } else { - if (mant0 > mant1) - flags = FLAGS_C; - else - flags = FLAGS_N; - } +stage1: // load/store regn is cpureg, regm is 8bit offset + regd = i>>12 & 0xf; + regn = i>>16 & 0xf; + regm = (i & 0xff) << 2; // PLUS or MINUS ?? -ret: - if (trace) { - printf(" %p %x\tcmf\tf%d, ", pc, *pc, lhs); - if (rhs & 0x8) - printf("#%s\n", fpconst[rhs&0x7]); - else - printf("f%d\n", rhs&0x7); + switch(i & 0xfff00f00) { + default: + goto stage2; + + case 0xed900a00: // single load + addr = (uint32*)(regs[regn] + regm); + m->freglo[regd] = addr[0]; + + if(trace) + runtime·printf("*** load F[%d] = %x\n", + regd, m->freglo[regd]); + break; + + case 0xed900b00: // double load + addr = (uint32*)(regs[regn] + regm); + m->freglo[regd] = addr[0]; + m->freghi[regd] = addr[1]; + + if(trace) + runtime·printf("*** load D[%d] = %x-%x\n", + regd, m->freghi[regd], m->freglo[regd]); + break; + + case 0xed800a00: // single store + addr = (uint32*)(regs[regn] + regm); + addr[0] = m->freglo[regd]; + + if(trace) + runtime·printf("*** *(%p) = %x\n", + addr, addr[0]); + break; + + case 0xed800b00: // double store + addr = (uint32*)(regs[regn] + regm); + addr[0] = m->freglo[regd]; + addr[1] = m->freghi[regd]; + + if(trace) + runtime·printf("*** *(%p) = %x-%x\n", + addr, addr[1], addr[0]); + break; } - regs[CPSR] = regs[CPSR] & 0x0fffffff | flags; -} + return 1; -// ldf/stf, load/store floating -static void -loadstore(uint32 *pc, uint32 *regs) -{ - uint32 i, isload, coproc, ud, wb, tlen, p, reg, freg, offset; - uint32 addr; - - i = *pc; - coproc = i>>8&0xf; - isload = i>>20&1; - p = i>>24&1; - ud = i>>23&1; - tlen = i>>(22 - 1)&1 | i>>15&1; - wb = i>>21&1; - reg = i>>16 &0xf; - freg = i>>12 &0x7; - offset = (i&0xff) << 2; - - if (coproc != 1 || p != 1 || wb != 0 || tlen > 1) - goto undef; - if (reg > 13) - goto undef; - - if (ud) - addr = regs[reg] + offset; - else - addr = regs[reg] - offset; - - if (isload) - if (tlen) - m->freg[freg] = *((uint64*)addr); - else - m->freg[freg] = s2d(*((uint32*)addr)); - else - if (tlen) - *((uint64*)addr) = m->freg[freg]; - else - *((uint32*)addr) = d2s(m->freg[freg]); - goto ret; - -undef: - doabort = 1; - -ret: - if (trace || doabort) { - if (isload) - printf(" %p %x\tldf", pc, *pc); - else - printf(" %p %x\tstf", pc, *pc); - printf("%s\t\tf%d, %s%d(r%d)", fpprec[tlen], freg, ud ? "" : "-", offset, reg); - printf("\t\t// %p", regs[reg] + (ud ? offset : -offset)); - if (coproc != 1 || p != 1 || wb != 0) - printf(" coproc: %d pre: %d wb %d", coproc, p, wb); - printf("\n"); - fprint(); +stage2: // regd, regm, regn are 4bit variables + regm = i>>0 & 0xf; + switch(i & 0xfff00ff0) { + default: + goto stage3; + + case 0xf3000110: // veor + m->freglo[regd] = m->freglo[regm]^m->freglo[regn]; + m->freghi[regd] = m->freghi[regm]^m->freghi[regn]; + + if(trace) + runtime·printf("*** veor D[%d] = %x-%x\n", + regd, m->freghi[regd], m->freglo[regd]); + break; + + case 0xeeb00b00: // D[regd] = const(regn,regm) + regn = (regn<<4) | regm; + regm = 0x40000000UL; + if(regn & 0x80) + regm |= 0x80000000UL; + if(regn & 0x40) + regm ^= 0x7fc00000UL; + regm |= (regn & 0x3f) << 16; + m->freglo[regd] = 0; + m->freghi[regd] = regm; + + if(trace) + runtime·printf("*** immed D[%d] = %x-%x\n", + regd, m->freghi[regd], m->freglo[regd]); + break; + + case 0xeeb00a00: // F[regd] = const(regn,regm) + regn = (regn<<4) | regm; + regm = 0x40000000UL; + if(regn & 0x80) + regm |= 0x80000000UL; + if(regn & 0x40) + regm ^= 0x7e000000UL; + regm |= (regn & 0x3f) << 19; + m->freglo[regd] = regm; + + if(trace) + runtime·printf("*** immed D[%d] = %x\n", + regd, m->freglo[regd]); + break; + + case 0xee300b00: // D[regd] = D[regn]+D[regm] + runtime·fadd64c(getd(regn), getd(regm), &uval); + putd(regd, uval); + + if(trace) + runtime·printf("*** add D[%d] = D[%d]+D[%d] %x-%x\n", + regd, regn, regm, m->freghi[regd], m->freglo[regd]); + break; + + case 0xee300a00: // F[regd] = F[regn]+F[regm] + runtime·fadd64c(f2d(m->freglo[regn]), f2d(m->freglo[regm]), &uval); + m->freglo[regd] = d2f(uval); + + if(trace) + runtime·printf("*** add F[%d] = F[%d]+F[%d] %x\n", + regd, regn, regm, m->freglo[regd]); + break; + + case 0xee300b40: // D[regd] = D[regn]-D[regm] + runtime·fsub64c(getd(regn), getd(regm), &uval); + putd(regd, uval); + + if(trace) + runtime·printf("*** sub D[%d] = D[%d]-D[%d] %x-%x\n", + regd, regn, regm, m->freghi[regd], m->freglo[regd]); + break; + + case 0xee300a40: // F[regd] = F[regn]-F[regm] + runtime·fsub64c(f2d(m->freglo[regn]), f2d(m->freglo[regm]), &uval); + m->freglo[regd] = d2f(uval); + + if(trace) + runtime·printf("*** sub F[%d] = F[%d]-F[%d] %x\n", + regd, regn, regm, m->freglo[regd]); + break; + + case 0xee200b00: // D[regd] = D[regn]*D[regm] + runtime·fmul64c(getd(regn), getd(regm), &uval); + putd(regd, uval); + + if(trace) + runtime·printf("*** mul D[%d] = D[%d]*D[%d] %x-%x\n", + regd, regn, regm, m->freghi[regd], m->freglo[regd]); + break; + + case 0xee200a00: // F[regd] = F[regn]*F[regm] + runtime·fmul64c(f2d(m->freglo[regn]), f2d(m->freglo[regm]), &uval); + m->freglo[regd] = d2f(uval); + + if(trace) + runtime·printf("*** mul F[%d] = F[%d]*F[%d] %x\n", + regd, regn, regm, m->freglo[regd]); + break; + + case 0xee800b00: // D[regd] = D[regn]/D[regm] + runtime·fdiv64c(getd(regn), getd(regm), &uval); + putd(regd, uval); + + if(trace) + runtime·printf("*** div D[%d] = D[%d]/D[%d] %x-%x\n", + regd, regn, regm, m->freghi[regd], m->freglo[regd]); + break; + + case 0xee800a00: // F[regd] = F[regn]/F[regm] + runtime·fdiv64c(f2d(m->freglo[regn]), f2d(m->freglo[regm]), &uval); + m->freglo[regd] = d2f(uval); + + if(trace) + runtime·printf("*** div F[%d] = F[%d]/F[%d] %x\n", + regd, regn, regm, m->freglo[regd]); + break; + + case 0xee000b10: // S[regn] = R[regd] (MOVW) (regm ignored) + m->freglo[regn] = regs[regd]; + + if(trace) + runtime·printf("*** cpy S[%d] = R[%d] %x\n", + regn, regd, m->freglo[regn]); + break; + + case 0xee100b10: // R[regd] = S[regn] (MOVW) (regm ignored) + regs[regd] = m->freglo[regn]; + + if(trace) + runtime·printf("*** cpy R[%d] = S[%d] %x\n", + regd, regn, regs[regd]); + break; } - if (doabort) - fabort(); -} - -static void -loadconst(uint32 *pc, uint32 *regs) -{ - uint32 offset; - uint32 *addr; - - if (*pc & 0xfffff000 != 0xe59fb838 || - *(pc+1) != 0xe08bb00c || - *(pc+2) & 0xffff8fff != 0xed9b0100) - goto undef; - - offset = *pc & 0xfff; - addr = (uint32*)((uint8*)pc + offset + 8); -//printf("DEBUG: addr %p *addr %x final %p\n", addr, *addr, *addr + regs[12]); - regs[11] = *addr + regs[12]; - loadstore(pc + 2, regs); - goto ret; + return 1; -undef: - doabort = 1; - -ret: - if (trace || doabort) { - printf(" %p coproc const %x %x %x\n", pc, *pc, *(pc+1), *(pc+2)); - } - if (doabort) - fabort(); -} +stage3: // regd, regm are 4bit variables + switch(i & 0xffff0ff0) { + default: + goto done; + + case 0xeeb00a40: // F[regd] = F[regm] (MOVF) + m->freglo[regd] = m->freglo[regm]; + + if(trace) + runtime·printf("*** F[%d] = F[%d] %x\n", + regd, regm, m->freglo[regd]); + break; + + case 0xeeb00b40: // D[regd] = D[regm] (MOVD) + m->freglo[regd] = m->freglo[regm]; + m->freghi[regd] = m->freghi[regm]; + + if(trace) + runtime·printf("*** D[%d] = D[%d] %x-%x\n", + regd, regm, m->freghi[regd], m->freglo[regd]); + break; + + case 0xeeb40bc0: // D[regd] :: D[regm] (CMPD) + runtime·fcmp64c(getd(regd), getd(regm), &cmp, &nan); + m->fflag = fstatus(nan, cmp); + + if(trace) + runtime·printf("*** cmp D[%d]::D[%d] %x\n", + regd, regm, m->fflag); + break; + + case 0xeeb40ac0: // F[regd] :: F[regm] (CMPF) + runtime·fcmp64c(f2d(m->freglo[regd]), f2d(m->freglo[regm]), &cmp, &nan); + m->fflag = fstatus(nan, cmp); + + if(trace) + runtime·printf("*** cmp F[%d]::F[%d] %x\n", + regd, regm, m->fflag); + break; + + case 0xeeb70ac0: // D[regd] = F[regm] (MOVFD) + putd(regd, f2d(m->freglo[regm])); + + if(trace) + runtime·printf("*** f2d D[%d]=F[%d] %x-%x\n", + regd, regm, m->freghi[regd], m->freglo[regd]); + break; + + case 0xeeb70bc0: // F[regd] = D[regm] (MOVDF) + m->freglo[regd] = d2f(getd(regm)); + + if(trace) + runtime·printf("*** d2f F[%d]=D[%d] %x-%x\n", + regd, regm, m->freghi[regd], m->freglo[regd]); + break; + + case 0xeebd0ac0: // S[regd] = F[regm] (MOVFW) + runtime·f64tointc(f2d(m->freglo[regm]), &sval, &ok); + if(!ok || (int32)sval != sval) + sval = 0; + m->freglo[regd] = sval; + + if(trace) + runtime·printf("*** fix S[%d]=F[%d] %x\n", + regd, regm, m->freglo[regd]); + break; + + case 0xeebc0ac0: // S[regd] = F[regm] (MOVFW.U) + runtime·f64tointc(f2d(m->freglo[regm]), &sval, &ok); + if(!ok || (uint32)sval != sval) + sval = 0; + m->freglo[regd] = sval; + + if(trace) + runtime·printf("*** fix unsigned S[%d]=F[%d] %x\n", + regd, regm, m->freglo[regd]); + break; + + case 0xeebd0bc0: // S[regd] = D[regm] (MOVDW) + runtime·f64tointc(getd(regm), &sval, &ok); + if(!ok || (int32)sval != sval) + sval = 0; + m->freglo[regd] = sval; + + if(trace) + runtime·printf("*** fix S[%d]=D[%d] %x\n", + regd, regm, m->freglo[regd]); + break; + + case 0xeebc0bc0: // S[regd] = D[regm] (MOVDW.U) + runtime·f64tointc(getd(regm), &sval, &ok); + if(!ok || (uint32)sval != sval) + sval = 0; + m->freglo[regd] = sval; + + if(trace) + runtime·printf("*** fix unsigned S[%d]=D[%d] %x\n", + regd, regm, m->freglo[regd]); + break; + + case 0xeeb80ac0: // D[regd] = S[regm] (MOVWF) + cmp = m->freglo[regm]; + if(cmp < 0) { + runtime·fintto64c(-cmp, &uval); + putf(regd, d2f(uval)); + m->freglo[regd] ^= 0x80000000; + } else { + runtime·fintto64c(cmp, &uval); + putf(regd, d2f(uval)); + } + if(trace) + runtime·printf("*** float D[%d]=S[%d] %x-%x\n", + regd, regm, m->freghi[regd], m->freglo[regd]); + break; + + case 0xeeb80a40: // D[regd] = S[regm] (MOVWF.U) + runtime·fintto64c(m->freglo[regm], &uval); + putf(regd, d2f(uval)); + + if(trace) + runtime·printf("*** float unsigned D[%d]=S[%d] %x-%x\n", + regd, regm, m->freghi[regd], m->freglo[regd]); + break; + + case 0xeeb80bc0: // D[regd] = S[regm] (MOVWD) + cmp = m->freglo[regm]; + if(cmp < 0) { + runtime·fintto64c(-cmp, &uval); + putd(regd, uval); + m->freghi[regd] ^= 0x80000000; + } else { + runtime·fintto64c(cmp, &uval); + putd(regd, uval); + } -// returns number of words that the fp instruction is occupying, 0 if next instruction isn't float. -// TODO(kaib): insert sanity checks for coproc 1 -static uint32 -stepflt(uint32 *pc, uint32 *regs) -{ - uint32 i, c; + if(trace) + runtime·printf("*** float D[%d]=S[%d] %x-%x\n", + regd, regm, m->freghi[regd], m->freglo[regd]); + break; - i = *pc; - c = i >> 25 & 7; + case 0xeeb80b40: // D[regd] = S[regm] (MOVWD.U) + runtime·fintto64c(m->freglo[regm], &uval); + putd(regd, uval); - switch(c) { - case 6: // 110 - loadstore(pc, regs); - return 1; - case 7: // 111 - if (i>>24 & 1) return 0; // ignore swi - - if (i>>4 & 1) { //data transfer - if ((i&0x00f0ff00) != 0x0090f100) { - printf(" %p %x\n", pc, i); - fabort(); - } - compare(pc, regs); - } else { - dataprocess(pc); - } - return 1; + if(trace) + runtime·printf("*** float unsigned D[%d]=S[%d] %x-%x\n", + regd, regm, m->freghi[regd], m->freglo[regd]); + break; } + return 1; - // lookahead for virtual instructions that span multiple arm instructions - c = ((*pc & 0x0f000000) >> 16) | - ((*(pc + 1) & 0x0f000000) >> 20) | - ((*(pc + 2) & 0x0f000000) >> 24); - if(c == 0x50d) { // 0101 0000 1101 - loadconst(pc, regs); - return 3; +done: + if((i&0xff000000) == 0xee000000 || + (i&0xff000000) == 0xed000000) { + runtime·printf("stepflt %p %x\n", pc, i); + fabort(); } - return 0; } #pragma textflag 7 uint32* -_sfloat2(uint32 *lr, uint32 r0) +runtime·_sfloat2(uint32 *lr, uint32 r0) { uint32 skip; - uint32 cpsr; - while(skip = stepflt(lr, &r0)) { + skip = stepflt(lr, &r0); + if(skip == 0) + fabort(); // not ok to fail first instruction + + lr += skip; + while(skip = stepflt(lr, &r0)) lr += skip; - } return lr; } - diff --git a/src/pkg/runtime/arm/traceback.c b/src/pkg/runtime/arm/traceback.c index 0131f21d6..8289fdb28 100644 --- a/src/pkg/runtime/arm/traceback.c +++ b/src/pkg/runtime/arm/traceback.c @@ -16,9 +16,9 @@ gentraceback(byte *pc0, byte *sp, byte *lr0, G *g, int32 skip, uintptr *pcbuf, i lr = (uintptr)lr0; // If the PC is goexit, it hasn't started yet. - if(pc == (uintptr)goexit) { + if(pc == (uintptr)runtime·goexit) { pc = (uintptr)g->entry; - lr = (uintptr)goexit; + lr = (uintptr)runtime·goexit; } // If the PC is zero, it's likely a nil function call. @@ -31,7 +31,7 @@ gentraceback(byte *pc0, byte *sp, byte *lr0, G *g, int32 skip, uintptr *pcbuf, i n = 0; stk = (Stktop*)g->stackbase; for(iter = 0; iter < 100 && n < m; iter++) { // iter avoids looping forever - if(pc == (uintptr)·lessstack) { + if(pc == (uintptr)runtime·lessstack) { // Hit top of stack segment. Unwind to next segment. pc = (uintptr)stk->gobuf.pc; sp = stk->gobuf.sp; @@ -39,7 +39,7 @@ gentraceback(byte *pc0, byte *sp, byte *lr0, G *g, int32 skip, uintptr *pcbuf, i stk = (Stktop*)stk->stackbase; continue; } - if(pc <= 0x1000 || (f = findfunc(pc-4)) == nil) { + if(pc <= 0x1000 || (f = runtime·findfunc(pc-4)) == nil) { // TODO: Check for closure. break; } @@ -53,24 +53,24 @@ gentraceback(byte *pc0, byte *sp, byte *lr0, G *g, int32 skip, uintptr *pcbuf, i // Print during crash. // main+0xf /home/rsc/go/src/runtime/x.go:23 // main(0x1, 0x2, 0x3) - printf("%S", f->name); + runtime·printf("%S", f->name); if(pc > f->entry) - printf("+%p", (uintptr)(pc - f->entry)); + runtime·printf("+%p", (uintptr)(pc - f->entry)); tracepc = pc; // back up to CALL instruction for funcline. if(n > 0 && pc > f->entry) tracepc -= sizeof(uintptr); - printf(" %S:%d\n", f->src, funcline(f, tracepc)); - printf("\t%S(", f->name); + runtime·printf(" %S:%d\n", f->src, runtime·funcline(f, tracepc)); + runtime·printf("\t%S(", f->name); for(i = 0; i < f->args; i++) { if(i != 0) - prints(", "); - ·printhex(((uintptr*)sp)[1+i]); + runtime·prints(", "); + runtime·printhex(((uintptr*)sp)[1+i]); if(i >= 4) { - prints(", ..."); + runtime·prints(", ..."); break; } } - prints(")\n"); + runtime·prints(")\n"); n++; } @@ -85,19 +85,19 @@ gentraceback(byte *pc0, byte *sp, byte *lr0, G *g, int32 skip, uintptr *pcbuf, i } void -traceback(byte *pc0, byte *sp, byte *lr, G *g) +runtime·traceback(byte *pc0, byte *sp, byte *lr, G *g) { gentraceback(pc0, sp, lr, g, 0, nil, 100); } // func caller(n int) (pc uintptr, file string, line int, ok bool) int32 -callers(int32 skip, uintptr *pcbuf, int32 m) +runtime·callers(int32 skip, uintptr *pcbuf, int32 m) { byte *pc, *sp; - sp = getcallersp(&skip); - pc = ·getcallerpc(&skip); + sp = runtime·getcallersp(&skip); + pc = runtime·getcallerpc(&skip); return gentraceback(pc, sp, 0, g, skip, pcbuf, m); } diff --git a/src/pkg/runtime/arm/vlop.s b/src/pkg/runtime/arm/vlop.s index c9e7090fc..2c5d7ebe1 100644 --- a/src/pkg/runtime/arm/vlop.s +++ b/src/pkg/runtime/arm/vlop.s @@ -30,7 +30,7 @@ arg=0 /* replaced use of R10 by R11 because the former can be the data segment base register */ -TEXT _mulv(SB), $0 +TEXT _mulv(SB), $0 MOVW 0(FP), R0 MOVW 4(FP), R2 /* l0 */ MOVW 8(FP), R11 /* h0 */ @@ -52,7 +52,7 @@ D = 2 CC = 3 TMP = 11 -TEXT save<>(SB), 7, $0 +TEXT save<>(SB), 7, $0 MOVW R(Q), 0(FP) MOVW R(N), 4(FP) MOVW R(D), 8(FP) @@ -62,11 +62,11 @@ TEXT save<>(SB), 7, $0 MOVW 20(FP), R(D) /* denominator */ CMP $0, R(D) BNE s1 - SWI 0 + BL runtime·panicdivide(SB) /* MOVW -1(R(D)), R(TMP) /* divide by zero fault */ s1: RET -TEXT rest<>(SB), 7, $0 +TEXT rest<>(SB), 7, $0 MOVW 0(FP), R(Q) MOVW 4(FP), R(N) MOVW 8(FP), R(D) @@ -79,7 +79,7 @@ TEXT rest<>(SB), 7, $0 ADD $20, R13 B (R14) -TEXT div<>(SB), 7, $0 +TEXT div<>(SB), 7, $0 MOVW $32, R(CC) /* * skip zeros 8-at-a-time @@ -114,7 +114,7 @@ loop: BNE loop RET -TEXT _div(SB), 7, $16 +TEXT _div(SB), 7, $16 BL save<>(SB) CMP $0, R(Q) BGE d1 @@ -135,7 +135,7 @@ d2: RSB $0, R(Q), R(TMP) B out -TEXT _mod(SB), 7, $16 +TEXT _mod(SB), 7, $16 BL save<>(SB) CMP $0, R(D) RSB.LT $0, R(D), R(D) @@ -150,13 +150,13 @@ m1: MOVW R(N), R(TMP) B out -TEXT _divu(SB), 7, $16 +TEXT _divu(SB), 7, $16 BL save<>(SB) BL div<>(SB) MOVW R(Q), R(TMP) B out -TEXT _modu(SB), 7, $16 +TEXT _modu(SB), 7, $16 BL save<>(SB) BL div<>(SB) MOVW R(N), R(TMP) @@ -169,7 +169,7 @@ out: // trampoline for _sfloat2. passes LR as arg0 and // saves registers R0-R13 and CPSR on the stack. R0-R12 and CPSR flags can // be changed by _sfloat2. -TEXT _sfloat(SB), 7, $64 // 4 arg + 14*4 saved regs + cpsr +TEXT _sfloat(SB), 7, $64 // 4 arg + 14*4 saved regs + cpsr MOVW R14, 4(R13) MOVW R0, 8(R13) MOVW $12(R13), R0 @@ -178,7 +178,7 @@ TEXT _sfloat(SB), 7, $64 // 4 arg + 14*4 saved regs + cpsr MOVW R1, 60(R13) WORD $0xe10f1000 // mrs r1, cpsr MOVW R1, 64(R13) - BL _sfloat2(SB) + BL runtime·_sfloat2(SB) MOVW R0, 0(R13) MOVW 64(R13), R1 WORD $0xe128f001 // msr cpsr_f, r1 diff --git a/src/pkg/runtime/arm/vlrt.c b/src/pkg/runtime/arm/vlrt.c index 76b777a35..50f33710b 100644 --- a/src/pkg/runtime/arm/vlrt.c +++ b/src/pkg/runtime/arm/vlrt.c @@ -23,6 +23,9 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. +// declared here to avoid include of runtime.h +void runtime·panicstring(char*); + typedef unsigned long ulong; typedef unsigned int uint; typedef unsigned short ushort; @@ -31,6 +34,12 @@ typedef signed char schar; #define SIGN(n) (1UL<<(n-1)) +void +runtime·panicdivide(void) +{ + runtime·panicstring("integer divide by zero"); +} + typedef struct Vlong Vlong; struct Vlong { @@ -47,210 +56,231 @@ struct Vlong ushort loms; ushort hils; ushort hims; - }; - }; + }; + }; }; -void abort(void); +void runtime·abort(void); void _addv(Vlong *r, Vlong a, Vlong b) { - ulong lo, hi; + ulong lo, hi; - lo = a.lo + b.lo; - hi = a.hi + b.hi; - if(lo < a.lo) - hi++; - r->lo = lo; - r->hi = 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; + ulong lo, hi; - lo = a.lo - b.lo; - hi = a.hi - b.hi; - if(lo > a.lo) - hi--; - r->lo = lo; - r->hi = hi; + lo = a.lo - b.lo; + hi = a.hi - b.hi; + if(lo > a.lo) + hi--; + r->lo = lo; + r->hi = hi; } - 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; + 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 <= 11) { + 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); + _d2v(y, f); +} + +void +runtime·float64toint64(double d, Vlong y) +{ + _d2v(&y, d); } void -·float64toint64(double d, Vlong y) +runtime·float64touint64(double d, Vlong y) { _d2v(&y, d); } double +_ul2d(ulong u) +{ + // compensate for bug in c + if(u & SIGN(32)) { + u ^= SIGN(32); + return 2147483648. + u; + } + return u; +} + +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; + if(x.hi & SIGN(32)) { + if(x.lo) { + x.lo = -x.lo; + x.hi = ~x.hi; + } else + x.hi = -x.hi; + return -(_ul2d(x.hi)*4294967296. + _ul2d(x.lo)); + } + return x.hi*4294967296. + _ul2d(x.lo); } float _v2f(Vlong x) { - return _v2d(x); + return _v2d(x); } void -·int64tofloat64(Vlong y, double d) +runtime·int64tofloat64(Vlong y, double d) { d = _v2d(y); } +void +runtime·uint64tofloat64(Vlong y, double d) +{ + d = _ul2d(y.hi)*4294967296. + _ul2d(y.lo); +} static void dodiv(Vlong num, Vlong den, Vlong *q, Vlong *r) { - 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(q) { - q->lo = quolo; - q->hi = quohi; - } - if(r) { - r->lo = numlo; - r->hi = numhi; - } + 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) { + runtime·panicdivide(); + } + + /* + * 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(q) { + q->lo = quolo; + q->hi = quohi; + } + if(r) { + r->lo = numlo; + r->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); + if(n.hi == 0 && d.hi == 0) { + q->hi = 0; + q->lo = n.lo / d.lo; + return; + } + dodiv(n, d, q, 0); } void -·uint64div(Vlong n, Vlong d, Vlong q) +runtime·uint64div(Vlong n, Vlong d, Vlong q) { _divvu(&q, n, d); } @@ -259,16 +289,16 @@ 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); + if(n.hi == 0 && d.hi == 0) { + r->hi = 0; + r->lo = n.lo % d.lo; + return; + } + dodiv(n, d, 0, r); } void -·uint64mod(Vlong n, Vlong d, Vlong q) +runtime·uint64mod(Vlong n, Vlong d, Vlong q) { _modvu(&q, n, d); } @@ -277,20 +307,20 @@ static void vneg(Vlong *v) { - if(v->lo == 0) { - v->hi = -v->hi; - return; - } - v->lo = -v->lo; - v->hi = ~v->hi; + 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; + long nneg, dneg; - if(n.hi == (((long)n.lo)>>31) && d.hi == (((long)d.lo)>>31)) { + if(n.hi == (((long)n.lo)>>31) && d.hi == (((long)d.lo)>>31)) { if((long)n.lo == -0x80000000 && (long)d.lo == -1) { // special case: 32-bit -0x80000000 / -1 causes wrong sign q->lo = 0x80000000; @@ -300,20 +330,20 @@ _divv(Vlong *q, Vlong n, Vlong d) 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); + } + 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 -·int64div(Vlong n, Vlong d, Vlong q) +runtime·int64div(Vlong n, Vlong d, Vlong q) { _divv(&q, n, d); } @@ -321,26 +351,26 @@ void void _modv(Vlong *r, Vlong n, Vlong d) { - long nneg, dneg; + 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); + 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 -·int64mod(Vlong n, Vlong d, Vlong q) +runtime·int64mod(Vlong n, Vlong d, Vlong q) { _modv(&q, n, d); } @@ -348,439 +378,439 @@ void 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); + 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); + 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); + 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; + 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; + 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; + 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++; + 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--; + 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; + 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; + 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 = *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; + Vlong t, u; + + u = *ret; + switch(type) { + default: + runtime·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; + long t; - t = (ulong)p; - ret->lo = t; - ret->hi = 0; + t = (ulong)p; + ret->lo = t; + ret->hi = 0; } void _sl2v(Vlong *ret, long sl) { - long t; + long t; - t = sl; - ret->lo = t; - ret->hi = t >> 31; + t = sl; + ret->lo = t; + ret->hi = t >> 31; } void _ul2v(Vlong *ret, ulong ul) { - long t; + long t; - t = ul; - ret->lo = t; - ret->hi = 0; + t = ul; + ret->lo = t; + ret->hi = 0; } void _si2v(Vlong *ret, int si) { - long t; + long t; - t = si; - ret->lo = t; - ret->hi = t >> 31; + t = si; + ret->lo = t; + ret->hi = t >> 31; } void _ui2v(Vlong *ret, uint ui) { - long t; + long t; - t = ui; - ret->lo = t; - ret->hi = 0; + t = ui; + ret->lo = t; + ret->hi = 0; } void _sh2v(Vlong *ret, long sh) { - long t; + long t; - t = (sh << 16) >> 16; - ret->lo = t; - ret->hi = t >> 31; + t = (sh << 16) >> 16; + ret->lo = t; + ret->hi = t >> 31; } void _uh2v(Vlong *ret, ulong ul) { - long t; + long t; - t = ul & 0xffff; - ret->lo = t; - ret->hi = 0; + t = ul & 0xffff; + ret->lo = t; + ret->hi = 0; } void _sc2v(Vlong *ret, long uc) { - long t; + long t; - t = (uc << 24) >> 24; - ret->lo = t; - ret->hi = t >> 31; + t = (uc << 24) >> 24; + ret->lo = t; + ret->hi = t >> 31; } void _uc2v(Vlong *ret, ulong ul) { - long t; + long t; - t = ul & 0xff; - ret->lo = t; - ret->hi = 0; + t = ul & 0xff; + ret->lo = t; + ret->hi = 0; } long _v2sc(Vlong rv) { - long t; + long t; - t = rv.lo & 0xff; - return (t << 24) >> 24; + t = rv.lo & 0xff; + return (t << 24) >> 24; } long _v2uc(Vlong rv) { - return rv.lo & 0xff; + return rv.lo & 0xff; } long _v2sh(Vlong rv) { - long t; + long t; - t = rv.lo & 0xffff; - return (t << 16) >> 16; + t = rv.lo & 0xffff; + return (t << 16) >> 16; } long _v2uh(Vlong rv) { - return rv.lo & 0xffff; + return rv.lo & 0xffff; } long _v2sl(Vlong rv) { - return rv.lo; + return rv.lo; } long _v2ul(Vlong rv) { - return rv.lo; + return rv.lo; } long _v2si(Vlong rv) { - return rv.lo; + return rv.lo; } long _v2ui(Vlong rv) { - return rv.lo; + return rv.lo; } int _testv(Vlong rv) { - return rv.lo || rv.hi; + return rv.lo || rv.hi; } int _eqv(Vlong lv, Vlong rv) { - return lv.lo == rv.lo && lv.hi == rv.hi; + return lv.lo == rv.lo && lv.hi == rv.hi; } int _nev(Vlong lv, Vlong rv) { - return lv.lo != rv.lo || lv.hi != rv.hi; + 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); + 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); + 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); + 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); + 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); + 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); + 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); + 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); + return lv.hi > rv.hi || + (lv.hi == rv.hi && lv.lo >= rv.lo); } |