diff --git a/build/bootstrap/compile.com b/build/bootstrap/compile.com index 4bf5e30aa..438b1af83 100755 Binary files a/build/bootstrap/compile.com and b/build/bootstrap/compile.com differ diff --git a/build/bootstrap/mkdeps.com b/build/bootstrap/mkdeps.com index 22199ca7c..a8e969f1a 100755 Binary files a/build/bootstrap/mkdeps.com and b/build/bootstrap/mkdeps.com differ diff --git a/libc/fmt/unbing.c b/libc/fmt/unbing.c index 89f894d96..400cb5916 100644 --- a/libc/fmt/unbing.c +++ b/libc/fmt/unbing.c @@ -220,7 +220,7 @@ int unbing(int c) { l = 0; r = ARRAYLEN(kCp437i) - 1; while (l <= r) { - m = (l + r) >> 1; + m = (l & r) + ((l ^ r) >> 1); // floor((a+b)/2) if ((kCp437i[m] >> 8) < c) { l = m + 1; } else if ((kCp437i[m] >> 8) > c) { diff --git a/libc/intrin/asan.c b/libc/intrin/asan.c index 5d19cef03..afcfefe0f 100644 --- a/libc/intrin/asan.c +++ b/libc/intrin/asan.c @@ -743,7 +743,7 @@ static void __asan_report_memory_origin_image(intptr_t a, int z) { r = n = st->count; k = a - st->addr_base; while (l < r) { - m = (l + r) >> 1; + m = (l & r) + ((l ^ r) >> 1); // floor((a+b)/2) if (st->symbols[m].y < k) { l = m + 1; } else { diff --git a/libc/intrin/findmemoryinterval.c b/libc/intrin/findmemoryinterval.c index 9dd466f5c..8891e5814 100644 --- a/libc/intrin/findmemoryinterval.c +++ b/libc/intrin/findmemoryinterval.c @@ -17,7 +17,6 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/assert.h" -#include "libc/intrin/midpoint.h" #include "libc/runtime/memtrack.internal.h" noasan unsigned FindMemoryInterval(const struct MemoryIntervals *mm, int x) { @@ -25,7 +24,7 @@ noasan unsigned FindMemoryInterval(const struct MemoryIntervals *mm, int x) { l = 0; r = mm->i; while (l < r) { - m = _midpoint(l, r); + m = (l & r) + ((l ^ r) >> 1); // floor((a+b)/2) if (mm->p[m].y < x) { l = m + 1; } else { diff --git a/libc/intrin/kprintf.greg.c b/libc/intrin/kprintf.greg.c index 1c0176258..d3598d892 100644 --- a/libc/intrin/kprintf.greg.c +++ b/libc/intrin/kprintf.greg.c @@ -161,7 +161,7 @@ privileged static bool kismapped(int x) { if (kismemtrackhosed()) return false; r = _weaken(_mmi)->i; while (l < r) { - m = (l + r) >> 1; + m = (l & r) + ((l ^ r) >> 1); // floor((a+b)/2) if (_weaken(_mmi)->p[m].y < x) { l = m + 1; } else { diff --git a/libc/intrin/midpoint.h b/libc/intrin/midpoint.h deleted file mode 100644 index ce5e31078..000000000 --- a/libc/intrin/midpoint.h +++ /dev/null @@ -1,32 +0,0 @@ -#ifndef COSMOPOLITAN_LIBC_BITS_MIDPOINT_H_ -#define COSMOPOLITAN_LIBC_BITS_MIDPOINT_H_ -#include "libc/assert.h" -#if !(__ASSEMBLER__ + __LINKER__ + 0) - -#if defined(__GNUC__) && !defined(__STRICT_ANSI__) && defined(__x86__) -/** - * Computes `(a + b) / 2` assuming unsigned. - * - * This implementation is the fastest on AMD Zen architecture. - */ -#define _midpoint(a, b) \ - ({ \ - typeof((a) + (b)) a_ = (a); \ - typeof(a_) b_ = (b); \ - _unassert(a_ >= 0); \ - _unassert(b_ >= 0); \ - asm("add\t%1,%0\n\t" \ - "rcr\t%0" \ - : "+r"(a_) \ - : "r"(b_)); \ - a_; \ - }) -#else -/** - * Computes `(a + b) / 2` assuming unsigned. - */ -#define _midpoint(a, b) (((a) & (b)) + ((a) ^ (b)) / 2) -#endif /* __GNUC__ && !__STRICT_ANSI__ && x86 */ - -#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ -#endif /* COSMOPOLITAN_LIBC_BITS_MIDPOINT_H_ */ diff --git a/libc/mem/sortedints.c b/libc/mem/sortedints.c index 7301d1d15..074e0956a 100644 --- a/libc/mem/sortedints.c +++ b/libc/mem/sortedints.c @@ -18,7 +18,6 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/assert.h" #include "libc/dce.h" -#include "libc/intrin/midpoint.h" #include "libc/mem/mem.h" #include "libc/mem/sortedints.internal.h" #include "libc/str/str.h" @@ -28,7 +27,7 @@ bool ContainsInt(const struct SortedInts *t, int k) { l = 0; r = t->n - 1; while (l <= r) { - m = _midpoint(l, r); + m = (l & r) + ((l ^ r) >> 1); // floor((a+b)/2) if (t->p[m] < k) { l = m + 1; } else if (t->p[m] > k) { @@ -45,7 +44,7 @@ int LeftmostInt(const struct SortedInts *t, int k) { l = 0; r = t->n; while (l < r) { - m = _midpoint(l, r); + m = (l & r) + ((l ^ r) >> 1); // floor((a+b)/2) if (t->p[m] < k) { l = m + 1; } else { diff --git a/libc/runtime/getsymbol.c b/libc/runtime/getsymbol.c index 98e0d8f92..87d3c8a00 100644 --- a/libc/runtime/getsymbol.c +++ b/libc/runtime/getsymbol.c @@ -41,7 +41,7 @@ dontinstrument privileged int __get_symbol(struct SymbolTable *t, intptr_t a) { r = n = t->count; k = a - t->addr_base; while (l < r) { - m = (l + r) >> 1; + m = (l & r) + ((l ^ r) >> 1); // floor((a+b)/2) if (t->symbols[m].y < k) { l = m + 1; } else { diff --git a/libc/sock/closesocket-nt.c b/libc/sock/closesocket-nt.c index e441b7d77..b339b9808 100644 --- a/libc/sock/closesocket-nt.c +++ b/libc/sock/closesocket-nt.c @@ -30,7 +30,8 @@ textwindows int sys_closesocket_nt(struct Fd *fd) { struct SockFd *sockfd; sockfd = (struct SockFd *)fd->extra; free(sockfd); - if (__sys_closesocket_nt(fd->handle) != -1) { + int rc = __sys_closesocket_nt(fd->handle); + if (rc != -1) { return 0; } else { return __winsockerr(); diff --git a/libc/str/crc32c.c b/libc/str/crc32c.c index 69099d1ba..399e7e343 100644 --- a/libc/str/crc32c.c +++ b/libc/str/crc32c.c @@ -39,7 +39,7 @@ uint32_t crc32c(uint32_t init, const void *data, size_t size) { static uint32_t kCrc32cTab[256]; if (!once) { crc32init(kCrc32cTab, 0x82f63b78); - once = 0; + once = 1; } p = data; pe = p + size; diff --git a/libc/str/iswseparator.c b/libc/str/iswseparator.c index 03cc4cfb9..4bae0b80f 100644 --- a/libc/str/iswseparator.c +++ b/libc/str/iswseparator.c @@ -399,7 +399,7 @@ int iswseparator(wint_t c) { l = 0; r = n = sizeof(kCodes) / sizeof(kCodes[0]); while (l < r) { - m = (l + r) >> 1; + m = (l & r) + ((l ^ r) >> 1); // floor((a+b)/2) if (kCodes[m][1] < c) { l = m + 1; } else { @@ -411,7 +411,7 @@ int iswseparator(wint_t c) { l = 0; r = n = sizeof(kAstralCodes) / sizeof(kAstralCodes[0]); while (l < r) { - m = (l + r) >> 1; + m = (l & r) + ((l ^ r) >> 1); // floor((a+b)/2) if (kAstralCodes[m][1] < c) { l = m + 1; } else { diff --git a/libc/str/strncpy.c b/libc/str/strncpy.c index ae317629c..e867280e6 100644 --- a/libc/str/strncpy.c +++ b/libc/str/strncpy.c @@ -24,39 +24,6 @@ * 1. If SRC is too long, it's truncated and *not* NUL-terminated. * 2. If SRC is too short, the remainder is zero-filled. * - * Please note this function isn't designed to prevent untrustworthy - * data from modifying memory without authorization; the memccpy() - * function can be used for that purpose. - * - * Here's an example of the only use case we know of for strncpy: - * - * static const struct People { - * char name[8]; - * int age; - * } kPeople[] = { - * {"alice", 29}, // - * {"bob", 42}, // - * }; - * - * int GetAge(const char *name) { - * char k[8]; - * int m, l, r; - * l = 0; - * r = ARRAYLEN(kPeople) - 1; - * strncpy(k, name, 8); - * while (l <= r) { - * m = (l + r) >> 1; - * if (READ64BE(kPeople[m].name) < READ64BE(k)) { - * l = m + 1; - * } else if (READ64BE(kPeople[m].name) > READ64BE(k)) { - * r = m - 1; - * } else { - * return kPeople[m].age; - * } - * } - * return -1; - * } - * * @return dest * @see stpncpy(), memccpy() * @asyncsignalsafe diff --git a/libc/str/towlower.c b/libc/str/towlower.c index 93cacfd9d..ae5912b7f 100644 --- a/libc/str/towlower.c +++ b/libc/str/towlower.c @@ -201,7 +201,7 @@ wint_t towlower(wint_t c) { l = 0; r = n = sizeof(kLower) / sizeof(kLower[0]); while (l < r) { - m = (l + r) >> 1; + m = (l & r) + ((l ^ r) >> 1); // floor((a+b)/2) if (kLower[m].y < c) { l = m + 1; } else { @@ -218,7 +218,7 @@ wint_t towlower(wint_t c) { l = 0; r = n = sizeof(kAstralLower) / sizeof(kAstralLower[0]); while (l < r) { - m = (l + r) >> 1; + m = (l & r) + ((l ^ r) >> 1); // floor((a+b)/2) if (kAstralLower[m][1] < c) { l = m + 1; } else { diff --git a/libc/str/towupper.c b/libc/str/towupper.c index 791d425b4..b3aaaf90c 100644 --- a/libc/str/towupper.c +++ b/libc/str/towupper.c @@ -164,7 +164,7 @@ wint_t towupper(wint_t c) { l = 0; r = n = sizeof(kUpper) / sizeof(kUpper[0]); while (l < r) { - m = (l + r) >> 1; + m = (l & r) + ((l ^ r) >> 1); // floor((a+b)/2) if (kUpper[m].y < c) { l = m + 1; } else { @@ -181,7 +181,7 @@ wint_t towupper(wint_t c) { l = 0; r = n = sizeof(kAstralUpper) / sizeof(kAstralUpper[0]); while (l < r) { - m = (l + r) >> 1; + m = (l & r) + ((l ^ r) >> 1); // floor((a+b)/2) if (kAstralUpper[m][1] < c) { l = m + 1; } else { diff --git a/net/http/findcontenttype.c b/net/http/findcontenttype.c index 2a531f3b3..dc9462582 100644 --- a/net/http/findcontenttype.c +++ b/net/http/findcontenttype.c @@ -119,7 +119,7 @@ static const char *BisectContentType(uint64_t ext) { l = 0; r = ARRAYLEN(kContentTypeExtension) - 1; while (l <= r) { - m = (l + r) >> 1; + m = (l & r) + ((l ^ r) >> 1); // floor((a+b)/2) c = CompareInts(READ64BE(kContentTypeExtension[m].ext), ext); if (c < 0) { l = m + 1; diff --git a/net/http/gethttpreason.c b/net/http/gethttpreason.c index c05f46f7e..8db15df10 100644 --- a/net/http/gethttpreason.c +++ b/net/http/gethttpreason.c @@ -100,7 +100,7 @@ const char *GetHttpReason(int code) { l = 0; r = ARRAYLEN(kHttpReason) - 1; while (l <= r) { - m = (l + r) >> 1; + m = (l & r) + ((l ^ r) >> 1); // floor((a+b)/2) if (kHttpReason[m].code < code) { l = m + 1; } else if (kHttpReason[m].code > code) { diff --git a/net/http/isnocompressext.c b/net/http/isnocompressext.c index 12d49b19d..941c6ede2 100644 --- a/net/http/isnocompressext.c +++ b/net/http/isnocompressext.c @@ -43,7 +43,7 @@ static bool BisectNoCompressExts(uint64_t ext) { l = 0; r = ARRAYLEN(kNoCompressExts) - 1; while (l <= r) { - m = (l + r) >> 1; + m = (l & r) + ((l ^ r) >> 1); // floor((a+b)/2) if (READ64BE(kNoCompressExts[m]) < ext) { l = m + 1; } else if (READ64BE(kNoCompressExts[m]) > ext) { diff --git a/net/turfwar/blackholed.c b/net/turfwar/blackholed.c index 7ffc211c3..7544ac25c 100644 --- a/net/turfwar/blackholed.c +++ b/net/turfwar/blackholed.c @@ -28,7 +28,6 @@ #include "libc/fmt/itoa.h" #include "libc/intrin/bits.h" #include "libc/intrin/kprintf.h" -#include "libc/intrin/midpoint.h" #include "libc/intrin/safemacros.internal.h" #include "libc/mem/mem.h" #include "libc/mem/sortedints.internal.h" diff --git a/test/libc/calls/sched_setscheduler_test.c b/test/libc/calls/sched_setscheduler_test.c index fc6578668..48c688d5d 100644 --- a/test/libc/calls/sched_setscheduler_test.c +++ b/test/libc/calls/sched_setscheduler_test.c @@ -20,7 +20,6 @@ #include "libc/calls/struct/sched_param.h" #include "libc/dce.h" #include "libc/errno.h" -#include "libc/intrin/midpoint.h" #include "libc/limits.h" #include "libc/runtime/runtime.h" #include "libc/sysv/consts/sched.h" @@ -67,7 +66,8 @@ TEST(sched_setscheduler, test) { TEST(sched_setscheduler, testMidpoint) { if (!CanTuneRealtimeSchedulers()) return; - struct sched_param p = {_midpoint(sched_get_priority_min(SCHED_FIFO), - sched_get_priority_max(SCHED_FIFO))}; + struct sched_param p = {(sched_get_priority_min(SCHED_FIFO) + + sched_get_priority_max(SCHED_FIFO)) / + 2}; EXPECT_SYS(0, DEFAULT_POLICY, sched_setscheduler(0, SCHED_FIFO, &p)); } diff --git a/third_party/chibicc/as.c b/third_party/chibicc/as.c index 32b82b8b9..e5ae7520f 100644 --- a/third_party/chibicc/as.c +++ b/third_party/chibicc/as.c @@ -1894,7 +1894,7 @@ static bool Prefix(struct As *a, const char *p, int n) { l = 0; r = ARRAYLEN(kPrefix) - 1; while (l <= r) { - m = (l + r) >> 1; + m = (l & r) + ((l ^ r) >> 1); // floor((a+b)/2) y = READ64BE(kPrefix[m]); if (x < y) { r = m - 1; @@ -1919,7 +1919,7 @@ static bool FindReg(const char *p, int n, struct Reg *out_reg) { l = 0; r = ARRAYLEN(kRegs) - 1; while (l <= r) { - m = (l + r) >> 1; + m = (l & r) + ((l ^ r) >> 1); // floor((a+b)/2) y = READ64BE(kRegs[m].s); if (x < y) { r = m - 1; @@ -3740,7 +3740,7 @@ static bool OnDirective8(struct As *a, struct Slice s) { l = 0; r = ARRAYLEN(kDirective8) - 1; while (l <= r) { - m = (l + r) >> 1; + m = (l & r) + ((l ^ r) >> 1); // floor((a+b)/2) y = READ64BE(kDirective8[m].s); if (x < y) { r = m - 1; @@ -3763,7 +3763,7 @@ static bool OnDirective16(struct As *a, struct Slice s) { l = 0; r = ARRAYLEN(kDirective16) - 1; while (l <= r) { - m = (l + r) >> 1; + m = (l & r) + ((l ^ r) >> 1); // floor((a+b)/2) y = READ128BE(kDirective16[m].s); if (x < y) { r = m - 1; diff --git a/third_party/linenoise/linenoise.c b/third_party/linenoise/linenoise.c index 6deedd785..472608d5d 100644 --- a/third_party/linenoise/linenoise.c +++ b/third_party/linenoise/linenoise.c @@ -313,7 +313,7 @@ static unsigned GetMirror(const unsigned short A[][2], size_t n, unsigned c) { l = 0; r = n - 1; while (l <= r) { - m = (l + r) >> 1; + m = (l & r) + ((l ^ r) >> 1); // floor((a+b)/2) if (A[m][0] < c) { l = m + 1; } else if (A[m][0] > c) { diff --git a/third_party/maxmind/getmetroname.c b/third_party/maxmind/getmetroname.c index 632807a67..7b89746b6 100644 --- a/third_party/maxmind/getmetroname.c +++ b/third_party/maxmind/getmetroname.c @@ -244,7 +244,7 @@ const char *GetMetroName(int code) { l = 0; r = ARRAYLEN(kMetroNames) - 1; while (l <= r) { - m = (l + r) >> 1; + m = (l & r) + ((l ^ r) >> 1); // floor((a+b)/2) if (kMetroNames[m].code < code) { l = m + 1; } else if (kMetroNames[m].code > code) { diff --git a/third_party/python/Modules/unicodedata_tonumeric.c b/third_party/python/Modules/unicodedata_tonumeric.c index 9d8197d6b..a891bc5a0 100644 --- a/third_party/python/Modules/unicodedata_tonumeric.c +++ b/third_party/python/Modules/unicodedata_tonumeric.c @@ -3901,7 +3901,7 @@ double _PyUnicode_ToNumeric(Py_UCS4 c) l = 0; r = sizeof(kNumericCodes) / sizeof(kNumericCodes[0]) - 1; while (l <= r) { - m = (l + r) >> 1; + m = (l & r) + ((l ^ r) >> 1); // floor((a+b)/2) if (kNumericCodes[m] < c) { l = m + 1; } else if (kNumericCodes[m] > c) { @@ -3914,7 +3914,7 @@ double _PyUnicode_ToNumeric(Py_UCS4 c) l = 0; r = sizeof(kNumericAstralCodes) / sizeof(kNumericAstralCodes[0]) - 1; while (l <= r) { - m = (l + r) >> 1; + m = (l & r) + ((l ^ r) >> 1); // floor((a+b)/2) if (kNumericAstralCodes[m] < c) { l = m + 1; } else if (kNumericAstralCodes[m] > c) { diff --git a/third_party/python/Tools/unicode/makeunicodedata.py b/third_party/python/Tools/unicode/makeunicodedata.py index f2ff36e23..af80aac84 100644 --- a/third_party/python/Tools/unicode/makeunicodedata.py +++ b/third_party/python/Tools/unicode/makeunicodedata.py @@ -456,7 +456,7 @@ double _PyUnicode_ToNumeric(Py_UCS4 c) l = 0; r = sizeof(kNumericCodes) / sizeof(kNumericCodes[0]) - 1; while (l <= r) { - m = (l + r) >> 1; + m = (l & r) + ((l ^ r) >> 1); // floor((a+b)/2) if (kNumericCodes[m] < c) { l = m + 1; } else if (kNumericCodes[m] > c) { @@ -469,7 +469,7 @@ double _PyUnicode_ToNumeric(Py_UCS4 c) l = 0; r = sizeof(kNumericAstralCodes) / sizeof(kNumericAstralCodes[0]) - 1; while (l <= r) { - m = (l + r) >> 1; + m = (l & r) + ((l ^ r) >> 1); // floor((a+b)/2) if (kNumericAstralCodes[m] < c) { l = m + 1; } else if (kNumericAstralCodes[m] > c) { diff --git a/third_party/python/pyobj.c b/third_party/python/pyobj.c index 7172d935b..8f1cb90b1 100644 --- a/third_party/python/pyobj.c +++ b/third_party/python/pyobj.c @@ -414,7 +414,7 @@ IsIgnoredModule(const char *s) l = 0; r = ARRAYLEN(kIgnoredModules) - 1; while (l <= r) { - m = (l + r) >> 1; + m = (l & r) + ((l ^ r) >> 1); // floor((a+b)/2) x = strcmp(s, kIgnoredModules[m]); if (x < 0) { r = m - 1; diff --git a/third_party/stb/stb_truetype.c b/third_party/stb/stb_truetype.c index 5f392e318..7fd85b196 100644 --- a/third_party/stb/stb_truetype.c +++ b/third_party/stb/stb_truetype.c @@ -25,6 +25,7 @@ │ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. │ │ │ ╚─────────────────────────────────────────────────────────────────────────────*/ +#include "third_party/stb/stb_truetype.h" #include "libc/assert.h" #include "libc/intrin/bits.h" #include "libc/intrin/likely.h" @@ -34,7 +35,6 @@ #include "libc/runtime/runtime.h" #include "libc/str/str.h" #include "third_party/stb/stb_rect_pack.h" -#include "third_party/stb/stb_truetype.h" asm(".ident\t\"\\n\\n\ stb_truetype (MIT License)\\n\ @@ -1562,7 +1562,7 @@ static int stbtt__GetGlyphKernInfoAdvance(const stbtt_fontinfo *info, int glyph1 r = ttUSHORT(data+10) - 1; needle = glyph1 << 16 | glyph2; while (l <= r) { - m = (l + r) >> 1; + m = (l & r) + ((l ^ r) >> 1); // floor((a+b)/2) straw = ttULONG(data+18+(m*6)); // note: unaligned read if (needle < straw) r = m - 1; @@ -1586,7 +1586,7 @@ static int32_t stbtt__GetCoverageIndex(uint8_t *coverageTable, int glyph) while (l <= r) { uint8_t *glyphArray = coverageTable + 4; uint16_t glyphID; - m = (l + r) >> 1; + m = (l & r) + ((l ^ r) >> 1); // floor((a+b)/2) glyphID = ttUSHORT(glyphArray + 2 * m); straw = glyphID; if (needle < straw) @@ -1607,7 +1607,7 @@ static int32_t stbtt__GetCoverageIndex(uint8_t *coverageTable, int glyph) int strawStart, strawEnd, needle=glyph; while (l <= r) { uint8_t *rangeRecord; - m = (l + r) >> 1; + m = (l & r) + ((l ^ r) >> 1); // floor((a+b)/2) rangeRecord = rangeArray + 6 * m; strawStart = ttUSHORT(rangeRecord); strawEnd = ttUSHORT(rangeRecord + 2); @@ -1648,7 +1648,7 @@ static int32_t stbtt__GetGlyphClass(uint8_t *classDefTable, int glyph) int strawStart, strawEnd, needle=glyph; while (l <= r) { uint8_t *classRangeRecord; - m = (l + r) >> 1; + m = (l & r) + ((l ^ r) >> 1); // floor((a+b)/2) classRangeRecord = classRangeRecords + 6 * m; strawStart = ttUSHORT(classRangeRecord); strawEnd = ttUSHORT(classRangeRecord + 2); @@ -1719,7 +1719,7 @@ static int32_t stbtt__GetGlyphGPOSInfoAdvance(const stbtt_fontinfo *info, int gl while (l <= r) { uint16_t secondGlyph; uint8_t *pairValue; - m = (l + r) >> 1; + m = (l & r) + ((l ^ r) >> 1); // floor((a+b)/2) pairValue = pairValueArray + (2 + valueRecordPairSizeInBytes) * m; secondGlyph = ttUSHORT(pairValue); straw = secondGlyph; diff --git a/tool/build/compile.c b/tool/build/compile.c index 29eeaf6c1..a032bb073 100644 --- a/tool/build/compile.c +++ b/tool/build/compile.c @@ -228,6 +228,7 @@ const char *const kGccOnlyFlags[] = { "-fdelete-dead-exceptions", "-femit-struct-debug-baseonly", "-ffp-int-builtin-inexact", + "-finline-functions-called-once", "-fipa-pta", "-fivopts", "-flimit-function-alignment", @@ -241,6 +242,7 @@ const char *const kGccOnlyFlags[] = { "-fno-fp-int-builtin-inexact", "-fno-gnu-unique", "-fno-gnu-unique", + "-fno-inline-functions-called-once", "-fno-instrument-functions", "-fno-schedule-insns2", "-fno-whole-program", @@ -371,7 +373,7 @@ bool IsSafeEnv(const char *s) { l = 0; r = ARRAYLEN(kSafeEnv) - 1; while (l <= r) { - m = (l + r) >> 1; + m = (l & r) + ((l ^ r) >> 1); // floor((a+b)/2) x = strncmp(s, kSafeEnv[m], n); if (x < 0) { r = m - 1; @@ -389,7 +391,7 @@ bool IsGccOnlyFlag(const char *s) { l = 0; r = ARRAYLEN(kGccOnlyFlags) - 1; while (l <= r) { - m = (l + r) >> 1; + m = (l & r) + ((l ^ r) >> 1); // floor((a+b)/2) x = strcmp(s, kGccOnlyFlags[m]); if (x < 0) { r = m - 1; @@ -1034,7 +1036,6 @@ int main(int argc, char *argv[]) { #ifdef __x86_64__ } else if (!strcmp(argv[i], "-march=native")) { struct X86ProcessorModel *model; - if (X86_HAVE(ABM)) AddArg("-mabm"); if (X86_HAVE(XOP)) AddArg("-mxop"); if (X86_HAVE(SSE4A)) AddArg("-msse4a"); if (X86_HAVE(SSE3)) AddArg("-msse3"); diff --git a/tool/build/mkdeps.c b/tool/build/mkdeps.c index 323fe2298..7a0bd8091 100644 --- a/tool/build/mkdeps.c +++ b/tool/build/mkdeps.c @@ -13,45 +13,24 @@ │ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ │ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ │ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ -│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ -│ PERFORMANCE OF THIS SOFTWARE. │ +│ TORTIOUS ACTION, ARISING OUTPATH OF OR IN CONNECTION WITH THE USE OR │ │ +PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/assert.h" #include "libc/calls/calls.h" -#include "libc/calls/struct/stat.h" -#include "libc/dce.h" #include "libc/errno.h" -#include "libc/fmt/fmt.h" +#include "libc/fmt/magnumstrs.internal.h" #include "libc/intrin/bits.h" -#include "libc/intrin/kprintf.h" -#include "libc/intrin/safemacros.internal.h" -#include "libc/log/check.h" -#include "libc/log/log.h" #include "libc/macros.internal.h" #include "libc/mem/alg.h" -#include "libc/mem/alloca.h" -#include "libc/mem/arraylist.internal.h" -#include "libc/mem/arraylist2.internal.h" -#include "libc/mem/bisectcarleft.internal.h" -#include "libc/mem/gc.internal.h" #include "libc/mem/mem.h" #include "libc/nexgen32e/crc32.h" #include "libc/runtime/runtime.h" -#include "libc/runtime/stack.h" #include "libc/stdio/append.h" #include "libc/stdio/stdio.h" #include "libc/str/str.h" -#include "libc/sysv/consts/clone.h" -#include "libc/sysv/consts/madv.h" #include "libc/sysv/consts/map.h" #include "libc/sysv/consts/o.h" #include "libc/sysv/consts/prot.h" -#include "libc/thread/spawn.h" -#include "libc/thread/thread.h" -#include "libc/thread/tls.h" -#include "libc/thread/wait0.internal.h" -#include "libc/time/time.h" -#include "libc/x/x.h" #include "third_party/getopt/getopt.internal.h" #include "tool/build/lib/getargs.h" @@ -73,27 +52,15 @@ * */ +#define VERSION \ + "cosmopolitan mkdeps v2.0\n" \ + "copyright 2023 justine tunney\n" \ + "https://github.com/jart/cosmopolitan\n" + #define kIncludePrefix "include \"" -#define THREADS 1 // _getcpucount() -#define LOCK (void) // if (__threaded) pthread_spin_lock -#define UNLOCK (void) // pthread_spin_unlock - const char kSourceExts[][5] = {".s", ".S", ".c", ".cc", ".cpp"}; -const char *const kIgnorePrefixes[] = { -#if 0 - "libc/sysv/consts/", "libc/sysv/calls/", "libc/nt/kernel32/", - "libc/nt/KernelBase/", "libc/nt/advapi32/", "libc/nt/gdi32/", - "libc/nt/ntdll/", "libc/nt/user32/", "libc/nt/shell32/", -#endif -}; - -struct Strings { - size_t i, n; - char *p; -}; - struct Source { unsigned hash; unsigned name; @@ -120,31 +87,71 @@ struct Edges { struct Edge *p; }; -char *out; -char **bouts; -pthread_t *th; -unsigned counter; -struct GetArgs ga; -struct Edges edges; -struct Sauce *sauces; -struct Strings strings; -struct Sources sources; -const char *buildroot; -pthread_spinlock_t galock; -pthread_spinlock_t readlock; -pthread_spinlock_t writelock; -pthread_spinlock_t reportlock; +static char *names; +static unsigned counter; +static const char *prog; +static struct Edges edges; +static struct Sauce *sauces; +static struct Sources sources; +static const char *buildroot; +static const char *outpath; -unsigned Hash(const void *s, size_t l) { - return max(1, crc32c(0, s, l)); +static wontreturn void Die(const char *reason) { + tinyprint(2, prog, ": ", reason, "\n", NULL); + exit(1); } -unsigned FindFirstFromEdge(unsigned id) { +static wontreturn void DieSys(const char *thing) { + perror(thing); + exit(1); +} + +static wontreturn void DieOom(void) { + Die("out of memory"); +} + +static unsigned Hash(const void *s, size_t l) { + unsigned h; + h = crc32c(0, s, l); + if (!h) h = 1; + return h; +} + +static void *Malloc(size_t n) { + void *p; + if (!(p = malloc(n))) DieOom(); + return p; +} + +static void *Calloc(size_t n, size_t z) { + void *p; + if (!(p = calloc(n, z))) DieOom(); + return p; +} + +static void *Realloc(void *p, size_t n) { + if (!(p = realloc(p, n))) DieOom(); + return p; +} + +static void Appendw(char **b, uint64_t w) { + if (appendw(b, w) == -1) DieOom(); +} + +static void Appends(char **b, const char *s) { + if (appends(b, s) == -1) DieOom(); +} + +static void Appendd(char **b, const void *p, size_t n) { + if (appendd(b, p, n) == -1) DieOom(); +} + +static unsigned FindFirstFromEdge(unsigned id) { unsigned m, l, r; l = 0; r = edges.i; while (l < r) { - m = (l + r) >> 1; + m = (l & r) + ((l ^ r) >> 1); // floor((a+b)/2) if (edges.p[m].from < id) { l = m + 1; } else { @@ -154,9 +161,18 @@ unsigned FindFirstFromEdge(unsigned id) { return l; } -void Crunch(void) { +static void AppendEdge(struct Edges *edges, unsigned to, unsigned from) { + if (edges->i + 1 > edges->n) { + edges->n += 1; + edges->n += edges->n >> 1; + edges->p = Realloc(edges->p, edges->n * sizeof(*edges->p)); + } + edges->p[edges->i++] = (struct Edge){to, from}; +} + +static void Crunch(void) { size_t i, j; - sauces = malloc(sizeof(*sauces) * sources.n); + sauces = Malloc(sizeof(*sauces) * sources.n); for (j = i = 0; i < sources.n; ++i) { if (sources.p[i].hash) { sauces[j].name = sources.p[i].name; @@ -167,16 +183,18 @@ void Crunch(void) { free(sources.p); sources.p = 0; sources.i = j; - _longsort((const long *)sauces, sources.i); - _longsort((const long *)edges.p, edges.i); + if (!radix_sort_int64((const long *)sauces, sources.i) || + !radix_sort_int64((const long *)edges.p, edges.i)) { + DieOom(); + } } -void Rehash(void) { +static void Rehash(void) { size_t i, j, step; struct Sources old; memcpy(&old, &sources, sizeof(sources)); sources.n = sources.n ? sources.n << 1 : 16; - sources.p = calloc(sources.n, sizeof(struct Source)); + sources.p = Calloc(sources.n, sizeof(struct Source)); for (i = 0; i < old.n; ++i) { if (!old.p[i].hash) continue; step = 0; @@ -189,9 +207,9 @@ void Rehash(void) { free(old.p); } -unsigned GetSourceId(const char *name, size_t len) { - size_t i, step; +static unsigned GetSourceId(const char *name, size_t len) { unsigned hash; + size_t i, step; i = 0; hash = Hash(name, len); if (sources.n) { @@ -199,7 +217,7 @@ unsigned GetSourceId(const char *name, size_t len) { do { i = (hash + step * (step + 1) / 2) & (sources.n - 1); if (sources.p[i].hash == hash && - !memcmp(name, &strings.p[sources.p[i].name], len)) { + !memcmp(name, names + sources.p[i].name, len)) { return sources.p[i].id; } step++; @@ -214,142 +232,128 @@ unsigned GetSourceId(const char *name, size_t len) { } while (sources.p[i].hash); } sources.p[i].hash = hash; - sources.p[i].name = CONCAT(&strings.p, &strings.i, &strings.n, name, len); - strings.p[strings.i++] = '\0'; + sources.p[i].name = appendz(names).i; + Appendd(&names, name, len); + Appendw(&names, 0); return (sources.p[i].id = counter++); } -bool ShouldSkipSource(const char *src) { - unsigned j; - for (j = 0; j < ARRAYLEN(kIgnorePrefixes); ++j) { - if (_startswith(src, kIgnorePrefixes[j])) { - return true; - } - } - return false; -} - -wontreturn void OnMissingFile(const char *list, const char *src) { - kprintf("%s is missing\n", src); - DCHECK_EQ(ENOENT, errno, "%s", src); - /* - * This code helps GNU Make automatically fix itself when we - * delete a source file. It removes o/.../srcs.txt or - * o/.../hdrs.txt and exits nonzero. Since we use hyphen - * notation on mkdeps related rules, the build will - * automatically restart itself. - */ - if (list) { - kprintf("%s %s...\n", "Refreshing", list); - unlink(list); - } - exit(1); -} - -void *LoadRelationshipsWorker(void *arg) { +static void LoadRelationships(int argc, char *argv[]) { int fd; + char *map; ssize_t rc; - bool skipme; - struct stat st; - struct Edge edge; + struct GetArgs ga; size_t i, n, size, inclen; unsigned srcid, dependency; - char *buf, srcbuf[PATH_MAX]; const char *p, *pe, *src, *path, *pathend; + getargs_init(&ga, argv + optind); inclen = strlen(kIncludePrefix); - for (;;) { - LOCK(&galock); - if ((src = getargs_next(&ga))) strcpy(srcbuf, src); - UNLOCK(&galock); - if (!src) break; - src = srcbuf; - if (ShouldSkipSource(src)) continue; + while ((src = getargs_next(&ga))) { n = strlen(src); - LOCK(&readlock); srcid = GetSourceId(src, n); - UNLOCK(&readlock); if ((fd = open(src, O_RDONLY)) == -1) { - LOCK(&reportlock); - OnMissingFile(ga.path, src); + if (errno == ENOENT && ga.path) { + // This code helps GNU Make automatically fix itself when we + // delete a source file. It removes o/.../srcs.txt or + // o/.../hdrs.txt and exits nonzero. Since we use hyphen + // notation on mkdeps related rules, the build will + // automatically restart itself. + tinyprint(2, prog, ": deleting ", ga.path, " to refresh build...\n", + NULL); + } + DieSys(src); } - CHECK_NE(-1, fstat(fd, &st)); - if ((size = st.st_size)) { - CHECK_NE(MAP_FAILED, (buf = mmap(0, size, PROT_READ, MAP_SHARED, fd, 0))); - for (p = buf + 1, pe = buf + size; p < pe; ++p) { + if ((rc = lseek(fd, 0, SEEK_END)) == -1) { + DieSys(src); + } + if ((size = rc)) { + map = mmap(0, size, PROT_READ, MAP_SHARED, fd, 0); + if (map == MAP_FAILED) { + DieSys(src); + } + for (p = map + 1, pe = map + size; p < pe; ++p) { if (!(p = memmem(p, pe - p, kIncludePrefix, inclen))) break; path = p + inclen; pathend = memchr(path, '"', pe - path); if (pathend && // (p[-1] == '#' || p[-1] == '.') && // - (p - buf == 1 || p[-2] == '\n')) { // - LOCK(&readlock); + (p - map == 1 || p[-2] == '\n')) { // dependency = GetSourceId(path, pathend - path); - UNLOCK(&readlock); - edge.from = srcid; - edge.to = dependency; - LOCK(&writelock); - append(&edges, &edge); - UNLOCK(&writelock); + AppendEdge(&edges, dependency, srcid); p = pathend; } } - munmap(buf, size); - } - close(fd); - } - return 0; -} - -void LoadRelationships(int argc, char *argv[]) { - int i; - getargs_init(&ga, argv + optind); - if (THREADS == 1) { - LoadRelationshipsWorker((void *)(intptr_t)0); - } else { - for (i = 0; i < THREADS; ++i) { - if (pthread_create(th + i, 0, LoadRelationshipsWorker, - (void *)(intptr_t)i)) { - LOCK(&reportlock); - kprintf("error: _spawn(%d) failed %m\n", i); - exit(1); + if (munmap(map, size)) { + DieSys(src); } } - for (i = 0; i < THREADS; ++i) { - pthread_join(th[i], 0); + if (close(fd)) { + DieSys(src); } } getargs_destroy(&ga); } -void GetOpts(int argc, char *argv[]) { +static wontreturn void ShowUsage(int rc, int fd) { + tinyprint(fd, VERSION, + "\n" + "USAGE\n" + "\n", + " ", prog, " -r o// -o OUTPUT INPUT...\n", + "\n" + "FLAGS\n" + "\n" + " -h show usage\n" + " -o OUTPUT set output path\n" + " -r ROOT set build output prefix, e.g. o//\n" + "\n" + "ARGUMENTS\n" + "\n" + " OUTPUT shall be makefile code\n" + " INPUT should be source or @args.txt\n" + "\n", + NULL); + exit(rc); +} + +static void GetOpts(int argc, char *argv[]) { int opt; - while ((opt = getopt(argc, argv, "ho:r:")) != -1) { + while ((opt = getopt(argc, argv, "hno:r:")) != -1) { switch (opt) { case 'o': - out = optarg; + outpath = optarg; break; case 'r': buildroot = optarg; break; + case 'n': + exit(0); + case 'h': + ShowUsage(0, 1); default: - kprintf("%s: %s [-r %s] [-o %s] [%s...]\n", "Usage", argv[0], - "BUILDROOT", "OUTPUT", "PATHSFILE"); - exit(1); + ShowUsage(1, 2); } } - if (isempty(out)) kprintf("need -o FILE"), exit(1); - if (isempty(buildroot)) kprintf("need -r o/$(MODE)"), exit(1); + if (!outpath) { + Die("need output path"); + } + if (!buildroot) { + Die("need build output prefix"); + } + if (optind == argc) { + Die("missing input argument"); + } } -const char *StripExt(char pathbuf[PATH_MAX], const char *s) { +static const char *StripExt(char pathbuf[PATH_MAX + 1], const char *s) { static char *dot; - strcpy(pathbuf, s); + strlcpy(pathbuf, s, PATH_MAX + 1); dot = strrchr(pathbuf, '.'); if (dot) *dot = '\0'; return pathbuf; } -bool IsObjectSource(const char *name) { +static bool IsObjectSource(const char *name) { int i; for (i = 0; i < ARRAYLEN(kSourceExts); ++i) { if (_endswith(name, kSourceExts[i])) return true; @@ -357,7 +361,7 @@ bool IsObjectSource(const char *name) { return false; } -forceinline bool Bts(uint32_t *p, size_t i) { +__funline bool Bts(uint32_t *p, size_t i) { bool r; uint32_t k; k = 1u << (i & 31); @@ -366,95 +370,74 @@ forceinline bool Bts(uint32_t *p, size_t i) { return false; } -size_t GetFileSizeOrZero(const char *path) { - struct stat st; - st.st_size = 0; - stat(path, &st); - return st.st_size; -} - -void Dive(char **bout, uint32_t *visited, unsigned id) { +static void Dive(char **makefile, uint32_t *visited, unsigned id) { int i; for (i = FindFirstFromEdge(id); i < edges.i && edges.p[i].from == id; ++i) { if (Bts(visited, edges.p[i].to)) continue; - appendw(bout, READ32LE(" \\\n\t")); - appends(bout, strings.p + sauces[edges.p[i].to].name); - Dive(bout, visited, edges.p[i].to); + Appendw(makefile, READ32LE(" \\\n\t")); + Appends(makefile, names + sauces[edges.p[i].to].name); + Dive(makefile, visited, edges.p[i].to); } } -void *Diver(void *arg) { - char *bout = 0; +static char *Explore(void) { const char *path; - uint32_t *visited; + unsigned *visited; size_t i, visilen; - char pathbuf[PATH_MAX]; - int x = (intptr_t)arg; + char *makefile = 0; + char buf[PATH_MAX + 1]; visilen = (sources.i + sizeof(*visited) * CHAR_BIT - 1) / (sizeof(*visited) * CHAR_BIT); - visited = malloc(visilen * sizeof(*visited)); - for (i = x; i < sources.i; i += THREADS) { - path = strings.p + sauces[i].name; + visited = Malloc(visilen * sizeof(*visited)); + for (i = 0; i < sources.i; ++i) { + path = names + sauces[i].name; if (!IsObjectSource(path)) continue; - appendw(&bout, '\n'); + Appendw(&makefile, '\n'); if (!_startswith(path, "o/")) { - appends(&bout, buildroot); + Appends(&makefile, buildroot); } - appends(&bout, StripExt(pathbuf, path)); - appendw(&bout, READ64LE(".o: \\\n\t")); - appends(&bout, path); + Appends(&makefile, StripExt(buf, path)); + Appendw(&makefile, READ64LE(".o: \\\n\t")); + Appends(&makefile, path); bzero(visited, visilen * sizeof(*visited)); Bts(visited, i); - Dive(&bout, visited, i); - appendw(&bout, '\n'); + Dive(&makefile, visited, i); + Appendw(&makefile, '\n'); } + Appendw(&makefile, '\n'); free(visited); - appendw(&bout, '\n'); - bouts[x] = bout; - return 0; -} - -void Explore(void) { - int i; - if (THREADS == 1) { - Diver((void *)(intptr_t)0); - } else { - for (i = 0; i < THREADS; ++i) { - if (pthread_create(th + i, 0, Diver, (void *)(intptr_t)i)) { - LOCK(&reportlock); - kprintf("error: _spawn(%d) failed %m\n", i); - exit(1); - } - } - for (i = 0; i < THREADS; ++i) { - pthread_join(th[i], 0); - } - } + return makefile; } int main(int argc, char *argv[]) { - int i, fd; + int fd; + ssize_t rc; + size_t i, n; + char *makefile; +#ifndef NDEBUG ShowCrashReports(); - if (argc == 2 && !strcmp(argv[1], "-n")) exit(0); +#endif + prog = argv[0]; + if (!prog) prog = "mkdeps"; GetOpts(argc, argv); - th = calloc(THREADS, sizeof(*th)); - bouts = calloc(THREADS, sizeof(*bouts)); LoadRelationships(argc, argv); Crunch(); - Explore(); - CHECK_NE(-1, (fd = open(out, O_WRONLY | O_CREAT | O_TRUNC, 0644)), - "open(%#s)", out); - for (i = 0; i < THREADS; ++i) { - CHECK_NE(-1, xwrite(fd, bouts[i], appendz(bouts[i]).i)); + makefile = Explore(); + if ((fd = open(outpath, O_WRONLY | O_CREAT | O_TRUNC, 0644)) == -1) { + DieSys(outpath); } - CHECK_NE(-1, close(fd)); - for (i = 0; i < THREADS; ++i) { - free(bouts[i]); + n = appendz(makefile).i; + for (i = 0; i < n; i += (size_t)rc) { + if ((rc = write(fd, makefile + i, n - i)) == -1) { + DieSys(outpath); + } } - free(strings.p); + if (close(fd)) { + DieSys(outpath); + } + free(makefile); free(edges.p); free(sauces); - free(bouts); - free(th); + free(names); return 0; } diff --git a/tool/build/package.c b/tool/build/package.c index a1a570520..d55bdfd40 100644 --- a/tool/build/package.c +++ b/tool/build/package.c @@ -550,7 +550,7 @@ static struct Symbol *BisectSymbol(struct Package *pkg, const char *name) { l = 0; r = pkg->symbols.i - 1; while (l <= r) { - m = (l + r) >> 1; + m = (l & r) + ((l ^ r) >> 1); // floor((a+b)/2) c = strcmp(pkg->strings.p + pkg->symbols.p[m].name, name); if (c < 0) { l = m + 1; diff --git a/tool/net/redbean.c b/tool/net/redbean.c index 9b044cd78..945b15eee 100644 --- a/tool/net/redbean.c +++ b/tool/net/redbean.c @@ -669,7 +669,7 @@ static long FindRedirect(const char *s, size_t n) { l = 0; r = redirects.n - 1; while (l <= r) { - m = (l + r) >> 1; + m = (l & r) + ((l ^ r) >> 1); // floor((a+b)/2) c = CompareSlices(redirects.p[m].path.s, redirects.p[m].path.n, s, n); if (c < 0) { l = m + 1; @@ -5381,7 +5381,7 @@ static bool ShouldAutocomplete(const char *s) { l = 0; r = ARRAYLEN(kDontAutoComplete) - 1; while (l <= r) { - m = (l + r) >> 1; + m = (l & r) + ((l ^ r) >> 1); // floor((a+b)/2) c = strcmp(kDontAutoComplete[m], s); if (c < 0) { l = m + 1; diff --git a/tool/plinko/lib/iswide.c b/tool/plinko/lib/iswide.c index fa4e297c8..99ef20fa9 100644 --- a/tool/plinko/lib/iswide.c +++ b/tool/plinko/lib/iswide.c @@ -16,7 +16,6 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/intrin/midpoint.h" #include "libc/macros.internal.h" #include "tool/plinko/lib/char.h" @@ -315,7 +314,7 @@ pureconst bool IsWide(int c) { l = 0; r = n = sizeof(kWides) / sizeof(kWides[0]); while (l < r) { - m = _midpoint(l, r); + m = (l & r) + ((l ^ r) >> 1); // floor((a+b)/2) if (kWides[m][1] < c) { l = m + 1; } else { @@ -327,7 +326,7 @@ pureconst bool IsWide(int c) { l = 0; r = n = sizeof(kAstralWides) / sizeof(kAstralWides[0]); while (l < r) { - m = _midpoint(l, r); + m = (l & r) + ((l ^ r) >> 1); // floor((a+b)/2) if (kAstralWides[m][1] < c) { l = m + 1; } else {