diff --git a/src/cmd/dc/dc.c b/src/cmd/dc/dc.c index 37aceab..d3bb890 100644 --- a/src/cmd/dc/dc.c +++ b/src/cmd/dc/dc.c @@ -2,8 +2,39 @@ #include #include #include +#include #include "dc.h" +void init(int argc, char *argv[]); +void commnds(void); +int readc(void); +void unreadc(char c); +void pushp(struct blk *p); +void sdump(char *s1, struct blk *hptr); +void chsign(struct blk *p); +void more(struct blk *hptr); +int subt(void); +int eqk(void); +void binop(char c); +int dscale(void); +void release(struct blk *p); +int log2v(long n); +void print(struct blk *hptr); +void load(void); +void seekc(struct blk *hptr, int n); +void salterwd(struct wblk *hptr, struct blk *n); +void putwd(struct blk *p, struct blk *c); +int command(void); +int cond(char c); +void oneot(struct blk *p, int sc, char ch); +void tenot(struct blk *p, int sc); +void hexot(struct blk *p, int flg); +void bigot(struct blk *p, int flg); +void garbage(char *s); +void ospace(char *s); +void redef(struct blk *p); + +int main(argc,argv) int argc; char *argv[]; @@ -12,6 +43,7 @@ char *argv[]; commnds(); } +void commnds() { register int c; @@ -491,7 +523,7 @@ sempty: if (q!=NULL) release(q); s = pop(); EMPTY; - salterwd(p,s); + salterwd((struct wblk *) p, s); sptr->val = p; continue; case ';': @@ -703,6 +735,7 @@ ddone: return(p); } +int dscale() { register struct blk *dd,*dr; @@ -873,7 +906,8 @@ edone: return(r); } -void onintr(sig) +void +onintr(sig) { signal(SIGINT,onintr); while(readptr != &readstk[0]){ @@ -884,6 +918,7 @@ void onintr(sig) commnds(); } +void init(argc,argv) int argc; char *argv[]; @@ -943,6 +978,7 @@ char *argv[]; return; } +void pushp(p) struct blk *p; { @@ -1098,6 +1134,7 @@ struct blk *p,*q; return(mr); } +void chsign(p) struct blk *p; { @@ -1133,6 +1170,7 @@ struct blk *p; return; } +int readc() { loop: @@ -1157,8 +1195,8 @@ loop: exit(0); } -unreadc(c) -char c; +void +unreadc(char c) { if((readptr != &readstk[0]) && (*readptr != 0)){ @@ -1168,8 +1206,8 @@ char c; return; } -binop(c) -char c; +void +binop(char c) { register struct blk *r; @@ -1191,6 +1229,7 @@ char c; return; } +void print(hptr) struct blk *hptr; { @@ -1304,6 +1343,7 @@ struct blk *p; return(q); } +void tenot(p,sc) struct blk *p; { @@ -1354,9 +1394,8 @@ struct blk *p; return; } -oneot(p,sc,ch) -struct blk *p; -char ch; +void +oneot(struct blk *p, int sc, char ch) { register struct blk *q; @@ -1374,6 +1413,7 @@ char ch; return; } +void hexot(p,flg) struct blk *p; { @@ -1394,6 +1434,7 @@ struct blk *p; return; } +void bigot(p,flg) struct blk *p; { @@ -1494,6 +1535,7 @@ struct blk *a1,*a2; return(p); } +int eqk() { register struct blk *p,*q; @@ -1577,6 +1619,7 @@ struct blk *p; return(q); } +int subt() { arg1=pop(); @@ -1590,6 +1633,7 @@ subt() return(0); } +int command() { int c; @@ -1622,8 +1666,8 @@ command() } } -cond(c) -char c; +int +cond(char c) { register struct blk *p; register char cc; @@ -1664,6 +1708,7 @@ char c; return(1); } +void load() { register int c; @@ -1699,6 +1744,7 @@ load() return; } +int log2v(n) long n; { @@ -1793,17 +1839,20 @@ int size; return(hdr); } +void sdump(s1,hptr) char *s1; struct blk *hptr; { char *p; - printf("%s %o rd %o wt %o beg %o last %o\n",s1,hptr,hptr->rd,hptr->wt,hptr->beg,hptr->last); + printf("%s %p rd %p wt %p beg %p last %p\n", + s1, hptr, hptr->rd, hptr->wt, hptr->beg, hptr->last); p = hptr->beg; while(p < hptr->wt)printf("%d ",*p++); printf("\n"); } +void seekc(hptr,n) struct blk *hptr; { @@ -1828,16 +1877,19 @@ struct blk *hptr; return; } +void salterwd(hptr,n) struct wblk *hptr; struct blk *n; { - if(hptr->rdw == hptr->lastw)more(hptr); + if (hptr->rdw == hptr->lastw) + more((struct blk *) hptr); *hptr->rdw++ = n; - if(hptr->rdw > hptr->wtw)hptr->wtw = hptr->rdw; - return; + if (hptr->rdw > hptr->wtw) + hptr->wtw = hptr->rdw; } +void more(hptr) struct blk *hptr; { @@ -1860,6 +1912,7 @@ struct blk *hptr; return; } +void ospace(s) char *s; { @@ -1870,6 +1923,7 @@ char *s; abort(); } +void garbage(s) char *s; { @@ -1904,7 +1958,7 @@ char *s; if(q != 0){ if(((int)q->beg & 01) != 0){ printf("array %o elt %d odd\n",i-ARRAYST,ct); -printf("tmps %o p %o\n",tmps,p); + printf("tmps %p p %p\n", tmps, p); sdump("elt",q); } redef(q); @@ -1917,14 +1971,15 @@ printf("tmps %o p %o\n",tmps,p); } } +void redef(p) struct blk *p; { - register offset; + register int offset; register char *newp; if ((int)p->beg&01) { - printf("odd ptr %o hdr %o\n",p->beg,p); + printf("odd ptr %p hdr %p\n",p->beg,p); ospace("redef-bad"); } newp = realloc(p->beg, (unsigned)(p->last-p->beg)); @@ -1936,6 +1991,7 @@ struct blk *p; p->last += offset; } +void release(p) register struct blk *p; { @@ -1958,6 +2014,7 @@ struct blk *p; return(*wp->rdw++); } +void putwd(p, c) struct blk *p, *c; { diff --git a/src/cmd/dc/dc.h b/src/cmd/dc/dc.h index fb8c534..6d32349 100644 --- a/src/cmd/dc/dc.h +++ b/src/cmd/dc/dc.h @@ -103,8 +103,7 @@ long all; long headmor; long obase; int fw,fw1,ll; -int (*outdit)(); -int bigot(),hexot(); +void (*outdit)(struct blk *p, int flg); int logo; int log10v; int count; diff --git a/src/libc/runtime/Makefile b/src/libc/runtime/Makefile index 96eb6c0..3cb38a9 100644 --- a/src/libc/runtime/Makefile +++ b/src/libc/runtime/Makefile @@ -21,10 +21,11 @@ CFLAGS += ${DEFS} OBJS = adddf3.o \ addsf3.o \ - divdf3.o \ - divsf3.o \ comparedf2.o \ comparesf2.o \ + divdf3.o \ + divdi3.o \ + divsf3.o \ extendsfdf2.o \ fixdfsi.o \ fixsfsi.o \ @@ -32,11 +33,15 @@ OBJS = adddf3.o \ floatsisf.o \ floatunsisf.o \ fp_mode.o \ + moddi3.o \ muldf3.o \ mulsf3.o \ subdf3.o \ subsf3.o \ - truncdfsf2.o + truncdfsf2.o \ + udivdi3.o \ + udivmoddi4.o \ + umoddi3.o runtime.a: ${OBJS} @echo "buiding runtime.a" diff --git a/src/libc/runtime/divdi3.c b/src/libc/runtime/divdi3.c new file mode 100644 index 0000000..d71e138 --- /dev/null +++ b/src/libc/runtime/divdi3.c @@ -0,0 +1,22 @@ +//===-- divdi3.c - Implement __divdi3 -------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file implements __divdi3 for the compiler_rt library. +// +//===----------------------------------------------------------------------===// + +#include "int_lib.h" + +// Returns: a / b + +#define fixint_t di_int +#define fixuint_t du_int +#define COMPUTE_UDIV(a, b) __udivmoddi4((a), (b), (du_int *)0) +#include "int_div_impl.inc" + +COMPILER_RT_ABI di_int __divdi3(di_int a, di_int b) { return __divXi3(a, b); } diff --git a/src/libc/runtime/int_div_impl.inc b/src/libc/runtime/int_div_impl.inc new file mode 100644 index 0000000..dc1f97c --- /dev/null +++ b/src/libc/runtime/int_div_impl.inc @@ -0,0 +1,95 @@ +//===-- int_div_impl.inc - Integer division ---------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Helpers used by __udivsi3, __umodsi3, __udivdi3, and __umodsi3. +// +//===----------------------------------------------------------------------===// + +#define clz(a) (sizeof(a) == sizeof(unsigned long long) ? __builtin_clzll(a) : clzsi(a)) + +// Adapted from Figure 3-40 of The PowerPC Compiler Writer's Guide +static __inline fixuint_t __udivXi3(fixuint_t n, fixuint_t d) { + const unsigned N = sizeof(fixuint_t) * CHAR_BIT; + // d == 0 cases are unspecified. + unsigned sr = (d ? clz(d) : N) - (n ? clz(n) : N); + // 0 <= sr <= N - 1 or sr is very large. + if (sr > N - 1) // n < d + return 0; + if (sr == N - 1) // d == 1 + return n; + ++sr; + // 1 <= sr <= N - 1. Shifts do not trigger UB. + fixuint_t r = n >> sr; + n <<= N - sr; + fixuint_t carry = 0; + for (; sr > 0; --sr) { + r = (r << 1) | (n >> (N - 1)); + n = (n << 1) | carry; + // Branch-less version of: + // carry = 0; + // if (r >= d) r -= d, carry = 1; + const fixint_t s = (fixint_t)(d - r - 1) >> (N - 1); + carry = s & 1; + r -= d & s; + } + n = (n << 1) | carry; + return n; +} + +// Mostly identical to __udivXi3 but the return values are different. +static __inline fixuint_t __umodXi3(fixuint_t n, fixuint_t d) { + const unsigned N = sizeof(fixuint_t) * CHAR_BIT; + // d == 0 cases are unspecified. + unsigned sr = (d ? clz(d) : N) - (n ? clz(n) : N); + // 0 <= sr <= N - 1 or sr is very large. + if (sr > N - 1) // n < d + return n; + if (sr == N - 1) // d == 1 + return 0; + ++sr; + // 1 <= sr <= N - 1. Shifts do not trigger UB. + fixuint_t r = n >> sr; + n <<= N - sr; + fixuint_t carry = 0; + for (; sr > 0; --sr) { + r = (r << 1) | (n >> (N - 1)); + n = (n << 1) | carry; + // Branch-less version of: + // carry = 0; + // if (r >= d) r -= d, carry = 1; + const fixint_t s = (fixint_t)(d - r - 1) >> (N - 1); + carry = s & 1; + r -= d & s; + } + return r; +} + +#ifdef COMPUTE_UDIV +static __inline fixint_t __divXi3(fixint_t a, fixint_t b) { + const int N = (int)(sizeof(fixint_t) * CHAR_BIT) - 1; + fixint_t s_a = a >> N; // s_a = a < 0 ? -1 : 0 + fixint_t s_b = b >> N; // s_b = b < 0 ? -1 : 0 + fixuint_t a_u = (fixuint_t)(a ^ s_a) + (-s_a); // negate if s_a == -1 + fixuint_t b_u = (fixuint_t)(b ^ s_b) + (-s_b); // negate if s_b == -1 + s_a ^= s_b; // sign of quotient + return (COMPUTE_UDIV(a_u, b_u) ^ s_a) + (-s_a); // negate if s_a == -1 +} +#endif // COMPUTE_UDIV + +#ifdef ASSIGN_UMOD +static __inline fixint_t __modXi3(fixint_t a, fixint_t b) { + const int N = (int)(sizeof(fixint_t) * CHAR_BIT) - 1; + fixint_t s = b >> N; // s = b < 0 ? -1 : 0 + fixuint_t b_u = (fixuint_t)(b ^ s) + (-s); // negate if s == -1 + s = a >> N; // s = a < 0 ? -1 : 0 + fixuint_t a_u = (fixuint_t)(a ^ s) + (-s); // negate if s == -1 + fixuint_t res; + ASSIGN_UMOD(res, a_u, b_u); + return (res ^ s) + (-s); // negate if s == -1 +} +#endif // ASSIGN_UMOD diff --git a/src/libc/runtime/moddi3.c b/src/libc/runtime/moddi3.c new file mode 100644 index 0000000..15cf80b --- /dev/null +++ b/src/libc/runtime/moddi3.c @@ -0,0 +1,22 @@ +//===-- moddi3.c - Implement __moddi3 -------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file implements __moddi3 for the compiler_rt library. +// +//===----------------------------------------------------------------------===// + +#include "int_lib.h" + +// Returns: a % b + +#define fixint_t di_int +#define fixuint_t du_int +#define ASSIGN_UMOD(res, a, b) __udivmoddi4((a), (b), &(res)) +#include "int_div_impl.inc" + +COMPILER_RT_ABI di_int __moddi3(di_int a, di_int b) { return __modXi3(a, b); } diff --git a/src/libc/runtime/udivdi3.c b/src/libc/runtime/udivdi3.c new file mode 100644 index 0000000..74319cb --- /dev/null +++ b/src/libc/runtime/udivdi3.c @@ -0,0 +1,23 @@ +//===-- udivdi3.c - Implement __udivdi3 -----------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file implements __udivdi3 for the compiler_rt library. +// +//===----------------------------------------------------------------------===// + +#include "int_lib.h" + +typedef du_int fixuint_t; +typedef di_int fixint_t; +#include "int_div_impl.inc" + +// Returns: a / b + +COMPILER_RT_ABI du_int __udivdi3(du_int a, du_int b) { + return __udivXi3(a, b); +} diff --git a/src/libc/runtime/udivmoddi4.c b/src/libc/runtime/udivmoddi4.c new file mode 100644 index 0000000..10b41df --- /dev/null +++ b/src/libc/runtime/udivmoddi4.c @@ -0,0 +1,200 @@ +//===-- udivmoddi4.c - Implement __udivmoddi4 -----------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file implements __udivmoddi4 for the compiler_rt library. +// +//===----------------------------------------------------------------------===// + +#include "int_lib.h" + +// Effects: if rem != 0, *rem = a % b +// Returns: a / b + +// Translated from Figure 3-40 of The PowerPC Compiler Writer's Guide + +#if defined(_MSC_VER) && !defined(__clang__) +// MSVC throws a warning about mod 0 here, disable it for builds that +// warn-as-error +#pragma warning(push) +#pragma warning(disable : 4724) +#endif + +COMPILER_RT_ABI du_int __udivmoddi4(du_int a, du_int b, du_int *rem) { + const unsigned n_uword_bits = sizeof(su_int) * CHAR_BIT; + const unsigned n_udword_bits = sizeof(du_int) * CHAR_BIT; + udwords n; + n.all = a; + udwords d; + d.all = b; + udwords q; + udwords r; + unsigned sr; + // special cases, X is unknown, K != 0 + if (n.s.high == 0) { + if (d.s.high == 0) { + // 0 X + // --- + // 0 X + if (rem) + *rem = n.s.low % d.s.low; + return n.s.low / d.s.low; + } + // 0 X + // --- + // K X + if (rem) + *rem = n.s.low; + return 0; + } + // n.s.high != 0 + if (d.s.low == 0) { + if (d.s.high == 0) { + // K X + // --- + // 0 0 + if (rem) + *rem = n.s.high % d.s.low; + return n.s.high / d.s.low; + } + // d.s.high != 0 + if (n.s.low == 0) { + // K 0 + // --- + // K 0 + if (rem) { + r.s.high = n.s.high % d.s.high; + r.s.low = 0; + *rem = r.all; + } + return n.s.high / d.s.high; + } + // K K + // --- + // K 0 + if ((d.s.high & (d.s.high - 1)) == 0) /* if d is a power of 2 */ { + if (rem) { + r.s.low = n.s.low; + r.s.high = n.s.high & (d.s.high - 1); + *rem = r.all; + } + return n.s.high >> __builtin_ctz(d.s.high); + } + // K K + // --- + // K 0 + sr = clzsi(d.s.high) - clzsi(n.s.high); + // 0 <= sr <= n_uword_bits - 2 or sr large + if (sr > n_uword_bits - 2) { + if (rem) + *rem = n.all; + return 0; + } + ++sr; + // 1 <= sr <= n_uword_bits - 1 + // q.all = n.all << (n_udword_bits - sr); + q.s.low = 0; + q.s.high = n.s.low << (n_uword_bits - sr); + // r.all = n.all >> sr; + r.s.high = n.s.high >> sr; + r.s.low = (n.s.high << (n_uword_bits - sr)) | (n.s.low >> sr); + } else /* d.s.low != 0 */ { + if (d.s.high == 0) { + // K X + // --- + // 0 K + if ((d.s.low & (d.s.low - 1)) == 0) /* if d is a power of 2 */ { + if (rem) + *rem = n.s.low & (d.s.low - 1); + if (d.s.low == 1) + return n.all; + sr = __builtin_ctz(d.s.low); + q.s.high = n.s.high >> sr; + q.s.low = (n.s.high << (n_uword_bits - sr)) | (n.s.low >> sr); + return q.all; + } + // K X + // --- + // 0 K + sr = 1 + n_uword_bits + clzsi(d.s.low) - clzsi(n.s.high); + // 2 <= sr <= n_udword_bits - 1 + // q.all = n.all << (n_udword_bits - sr); + // r.all = n.all >> sr; + if (sr == n_uword_bits) { + q.s.low = 0; + q.s.high = n.s.low; + r.s.high = 0; + r.s.low = n.s.high; + } else if (sr < n_uword_bits) /* 2 <= sr <= n_uword_bits - 1 */ { + q.s.low = 0; + q.s.high = n.s.low << (n_uword_bits - sr); + r.s.high = n.s.high >> sr; + r.s.low = (n.s.high << (n_uword_bits - sr)) | (n.s.low >> sr); + } else /* n_uword_bits + 1 <= sr <= n_udword_bits - 1 */ { + q.s.low = n.s.low << (n_udword_bits - sr); + q.s.high = (n.s.high << (n_udword_bits - sr)) | + (n.s.low >> (sr - n_uword_bits)); + r.s.high = 0; + r.s.low = n.s.high >> (sr - n_uword_bits); + } + } else { + // K X + // --- + // K K + sr = clzsi(d.s.high) - clzsi(n.s.high); + // 0 <= sr <= n_uword_bits - 1 or sr large + if (sr > n_uword_bits - 1) { + if (rem) + *rem = n.all; + return 0; + } + ++sr; + // 1 <= sr <= n_uword_bits + // q.all = n.all << (n_udword_bits - sr); + q.s.low = 0; + if (sr == n_uword_bits) { + q.s.high = n.s.low; + r.s.high = 0; + r.s.low = n.s.high; + } else { + q.s.high = n.s.low << (n_uword_bits - sr); + r.s.high = n.s.high >> sr; + r.s.low = (n.s.high << (n_uword_bits - sr)) | (n.s.low >> sr); + } + } + } + // Not a special case + // q and r are initialized with: + // q.all = n.all << (n_udword_bits - sr); + // r.all = n.all >> sr; + // 1 <= sr <= n_udword_bits - 1 + su_int carry = 0; + for (; sr > 0; --sr) { + // r:q = ((r:q) << 1) | carry + r.s.high = (r.s.high << 1) | (r.s.low >> (n_uword_bits - 1)); + r.s.low = (r.s.low << 1) | (q.s.high >> (n_uword_bits - 1)); + q.s.high = (q.s.high << 1) | (q.s.low >> (n_uword_bits - 1)); + q.s.low = (q.s.low << 1) | carry; + // carry = 0; + // if (r.all >= d.all) + // { + // r.all -= d.all; + // carry = 1; + // } + const di_int s = (di_int)(d.all - r.all - 1) >> (n_udword_bits - 1); + carry = s & 1; + r.all -= d.all & s; + } + q.all = (q.all << 1) | carry; + if (rem) + *rem = r.all; + return q.all; +} + +#if defined(_MSC_VER) && !defined(__clang__) +#pragma warning(pop) +#endif diff --git a/src/libc/runtime/umoddi3.c b/src/libc/runtime/umoddi3.c new file mode 100644 index 0000000..e672da9 --- /dev/null +++ b/src/libc/runtime/umoddi3.c @@ -0,0 +1,23 @@ +//===-- umoddi3.c - Implement __umoddi3 -----------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file implements __umoddi3 for the compiler_rt library. +// +//===----------------------------------------------------------------------===// + +#include "int_lib.h" + +typedef du_int fixuint_t; +typedef di_int fixint_t; +#include "int_div_impl.inc" + +// Returns: a % b + +COMPILER_RT_ABI du_int __umoddi3(du_int a, du_int b) { + return __umodXi3(a, b); +}