diff --git a/AK/StdLibExtras.cpp b/AK/StdLibExtras.cpp index 95652e368b..31b3b9221c 100644 --- a/AK/StdLibExtras.cpp +++ b/AK/StdLibExtras.cpp @@ -3,6 +3,8 @@ #include #include +extern "C" { + void* mmx_memcpy(void* dest, const void* src, size_t len) { ASSERT(len >= 1024); @@ -49,3 +51,76 @@ void* mmx_memcpy(void* dest, const void* src, size_t len) memcpy(dest_ptr, src_ptr, len); return dest; } + +static inline uint32_t divq(uint64_t n, uint32_t d) +{ + uint32_t n1 = n >> 32; + uint32_t n0 = n; + uint32_t q; + uint32_t r; + asm volatile("divl %4" : "=d"(r), "=a"(q) : "0"(n1), "1"(n0), "rm"(d)); + return q; +} + +static uint64_t unsigned_divide64(uint64_t n, uint64_t d) +{ + if ((d >> 32) == 0) { + uint64_t b = 1ULL << 32; + uint32_t n1 = n >> 32; + uint32_t n0 = n; + uint32_t d0 = d; + return divq(b * (n1 % d0) + n0, d0) + b * (n1 / d0); + } + if (n < d) + return 0; + uint32_t d1 = d >> 32u; + int s = __builtin_clz(d1); + uint64_t q = divq(n >> 1, (d << s) >> 32) >> (31 - s); + return n - (q - 1) * d < d ? q - 1 : q; +} + +static uint32_t unsigned_modulo64(uint64_t n, uint64_t d) +{ + return n - d * unsigned_divide64(n, d); +} + +static int64_t signed_divide64(int64_t n, int64_t d) +{ + uint64_t n_abs = n >= 0 ? (uint64_t)n : -(uint64_t)n; + uint64_t d_abs = d >= 0 ? (uint64_t)d : -(uint64_t)d; + uint64_t q_abs = unsigned_divide64(n_abs, d_abs); + return (n < 0) == (d < 0) ? (int64_t)q_abs : -(int64_t)q_abs; +} + +static int32_t signed_modulo64(int64_t n, int64_t d) +{ + return n - d * signed_divide64(n, d); +} + +int64_t __divdi3(int64_t n, int64_t d) +{ + return signed_divide64 (n, d); +} + +int64_t __moddi3(int64_t n, int64_t d) +{ + return signed_modulo64(n, d); +} + +uint64_t __udivdi3(uint64_t n, uint64_t d) +{ + return unsigned_divide64(n, d); +} + +uint64_t __umoddi3(uint64_t n, uint64_t d) +{ + return unsigned_modulo64(n, d); +} + +uint64_t __udivmoddi4(uint64_t n, uint64_t d, uint64_t* r) +{ + *r = unsigned_modulo64(n, d); + return unsigned_divide64(n, d); +} + +} diff --git a/AK/StdLibExtras.h b/AK/StdLibExtras.h index db4228d8ba..97e6ad57d1 100644 --- a/AK/StdLibExtras.h +++ b/AK/StdLibExtras.h @@ -9,7 +9,7 @@ #include -void* mmx_memcpy(void* to, const void* from, size_t); +extern "C" void* mmx_memcpy(void* to, const void* from, size_t); [[gnu::always_inline]] inline void fast_dword_copy(dword* dest, const dword* src, size_t count) { diff --git a/AK/printf.cpp b/AK/printf.cpp index 8948734512..41c9c3dbb6 100644 --- a/AK/printf.cpp +++ b/AK/printf.cpp @@ -1,6 +1,7 @@ typedef unsigned char byte; typedef unsigned short word; typedef unsigned int dword; +typedef long long unsigned int qword; [[gnu::always_inline]] inline size_t strlen(const char* str) { @@ -12,8 +13,8 @@ typedef unsigned int dword; static constexpr const char* h = "0123456789abcdef"; -template -[[gnu::always_inline]] inline int print_hex(PutChFunc putch, char*& bufptr, dword number, byte fields) +template +[[gnu::always_inline]] inline int print_hex(PutChFunc putch, char*& bufptr, T number, byte fields) { int ret = 0; byte shr_count = fields * 4; @@ -66,6 +67,47 @@ template return fieldWidth; } +template +[[gnu::always_inline]] inline int print_qword(PutChFunc putch, char*& bufptr, qword number, bool leftPad, bool zeroPad, dword fieldWidth) +{ + qword divisor = 10000000000000000000LLU; + char ch; + char padding = 1; + char buf[16]; + char* p = buf; + + for (;;) { + ch = '0' + (number / divisor); + number %= divisor; + if (ch != '0') + padding = 0; + if (!padding || divisor == 1) + *(p++) = ch; + if (divisor == 1) + break; + divisor /= 10; + } + + size_t numlen = p - buf; + if (!fieldWidth || fieldWidth < numlen) + fieldWidth = numlen; + if (!leftPad) { + for (unsigned i = 0; i < fieldWidth - numlen; ++i) { + putch(bufptr, zeroPad ? '0' : ' '); + } + } + for (unsigned i = 0; i < numlen; ++i) { + putch(bufptr, buf[i]); + } + if (leftPad) { + for (unsigned i = 0; i < fieldWidth - numlen; ++i) { + putch(bufptr, ' '); + } + } + + return fieldWidth; +} + template [[gnu::always_inline]] inline int print_octal_number(PutChFunc putch, char*& bufptr, dword number, bool leftPad, bool zeroPad, dword fieldWidth) { @@ -191,6 +233,14 @@ one_more: ret += print_number(putch, bufptr, va_arg(ap, dword), leftPad, zeroPad, fieldWidth); break; + case 'Q': + ret += print_qword(putch, bufptr, va_arg(ap, qword), leftPad, zeroPad, fieldWidth); + break; + + case 'q': + ret += print_hex(putch, bufptr, va_arg(ap, qword), 16); + break; + case 'f': // FIXME: Print as float! ret += print_number(putch, bufptr, (int)va_arg(ap, double), leftPad, zeroPad, fieldWidth); diff --git a/Kernel/i386.h b/Kernel/i386.h index 4dc56620d4..9b2b3447d4 100644 --- a/Kernel/i386.h +++ b/Kernel/i386.h @@ -269,27 +269,29 @@ inline void read_tsc(dword& lsw, dword& msw) } struct Stopwatch { + union SplitQword { + struct { + uint32_t lsw; + uint32_t msw; + }; + uint64_t qw { 0 }; + }; public: Stopwatch(const char* name) : m_name(name) { - read_tsc(m_start_lsw, m_start_msw); + read_tsc(m_start.lsw, m_start.msw); } ~Stopwatch() { - dword end_lsw; - dword end_msw; - read_tsc(end_lsw, end_msw); - if (m_start_msw != end_msw) { - dbgprintf("stopwatch: differing msw, no result for %s\n", m_name); - } - dword diff = end_lsw - m_start_lsw; - dbgprintf("Stopwatch(%s): %u ticks\n", m_name, diff); + SplitQword end; + read_tsc(end.lsw, end.msw); + uint64_t diff = end.qw - m_start.qw; + dbgprintf("Stopwatch(%s): %q ticks\n", m_name, diff); } private: const char* m_name { nullptr }; - dword m_start_lsw { 0 }; - dword m_start_msw { 0 }; + SplitQword m_start; }; diff --git a/LibC/serenity.h b/LibC/serenity.h index 0854941942..ce9efff53c 100644 --- a/LibC/serenity.h +++ b/LibC/serenity.h @@ -5,30 +5,33 @@ #ifdef __cplusplus + struct Stopwatch { + union SplitQword { + struct { + uint32_t lsw; + uint32_t msw; + }; + uint64_t qw { 0 }; + }; public: Stopwatch(const char* name) : m_name(name) { - read_tsc(&m_start_lsw, &m_start_msw); + read_tsc(&m_start.lsw, &m_start.msw); } ~Stopwatch() { - unsigned end_lsw; - unsigned end_msw; - read_tsc(&end_lsw, &end_msw); - if (m_start_msw != end_msw) { - dbgprintf("Stopwatch: differing msw, no result for %s\n", m_name); - } - unsigned diff = end_lsw - m_start_lsw; - dbgprintf("Stopwatch(%s): %u ticks\n", m_name, diff); + SplitQword end; + read_tsc(&end.lsw, &end.msw); + uint64_t diff = end.qw - m_start.qw; + dbgprintf("Stopwatch(%s): %q ticks\n", m_name, diff); } private: const char* m_name { nullptr }; - unsigned m_start_lsw { 0 }; - unsigned m_start_msw { 0 }; + SplitQword m_start; }; #endif // __cplusplus