cosmopolitan/tool/plinko/lib/gc.c
Justine Tunney 8bfd56b59e
Rename _bsr/_bsf to bsr/bsf
Now that these functions are behind _COSMO_SOURCE there's no reason for
having the ugly underscore anymore. To use these functions, you need to
pass -mcosmo to cosmocc.
2024-03-04 17:33:26 -08:00

157 lines
4.6 KiB
C

/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
│ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │
╞══════════════════════════════════════════════════════════════════════════════╡
│ Copyright 2022 Justine Alexandra Roberts Tunney │
│ │
│ Permission to use, copy, modify, and/or distribute this software for │
│ any purpose with or without fee is hereby granted, provided that the │
│ above copyright notice and this permission notice appear in all copies. │
│ │
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
│ 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. │
╚─────────────────────────────────────────────────────────────────────────────*/
#include "tool/plinko/lib/gc.h"
#include "libc/assert.h"
#include "libc/intrin/bsf.h"
#include "libc/intrin/popcnt.h"
#include "libc/limits.h"
#include "libc/log/check.h"
#include "libc/log/countbranch.h"
#include "libc/log/log.h"
#include "libc/macros.internal.h"
#include "libc/mem/mem.h"
#include "libc/str/str.h"
#include "tool/plinko/lib/cons.h"
#include "tool/plinko/lib/histo.h"
#include "tool/plinko/lib/plinko.h"
#include "tool/plinko/lib/print.h"
#include "tool/plinko/lib/printf.h"
#include "tool/plinko/lib/stack.h"
forceinline void SetBit(dword M[], unsigned i) {
M[i / DWBITS] |= (dword)1 << (i % DWBITS);
}
forceinline nosideeffect bool HasBit(const dword M[], unsigned i) {
return (M[i / DWBITS] >> (i % DWBITS)) & 1;
}
struct Gc *NewGc(int A) {
int B = cx;
unsigned n;
struct Gc *G;
DCHECK_LE(B, A);
DCHECK_LE(A, 0);
if (B < cHeap) cHeap = B;
n = ROUNDUP(A - B, DWBITS) / DWBITS;
G = Addr(BANE);
bzero(G->M, n * sizeof(G->M[0]));
G->n = n;
G->A = A;
G->B = B;
G->P = (unsigned *)(G->M + n);
*G->P++ = 0;
return G;
}
void Marker(const dword M[], int A, int x) {
int i;
dword t;
do {
i = ~(x - A);
if (HasBit(M, i)) return;
SetBit((void *)M, i);
if (HI(GetShadow(x)) < A) {
Marker(M, A, HI(GetShadow(x)));
}
t = Get(x);
if (LO(t) < A) {
Marker(M, A, LO(t));
}
} while ((x = HI(t)) < A);
}
int Census(struct Gc *G) {
int n, t, l;
unsigned i, j;
i = G->A - G->B;
n = i / DWBITS;
for (j = t = 0; j < n; ++j) {
G->P[j] = t += popcnt(G->M[j]);
}
if (i % DWBITS) {
t += popcnt(G->M[j]);
}
G->noop = t == i;
for (l = j = 0; j < G->n; ++j) {
if (!~G->M[j]) {
l += DWBITS;
} else {
l += bsfl(~G->M[j]);
break;
}
}
G->C = G->A - l;
#if HISTO_GARBAGE
HISTO(g_gc_marks_histogram, t);
HISTO(g_gc_discards_histogram, i - t);
HISTO(g_gc_lop_histogram, l);
#endif
return t;
}
int Relocater(const dword M[], const unsigned P[], int A, int x) {
long n;
unsigned i, r;
i = ~(x - A);
n = i / DWBITS;
r = i % DWBITS;
return A + ~(P[n - 1] + popcnt(M[n] & (((dword)1 << r) - 1)));
}
void Sweep(struct Gc *G) {
dword m;
int a, b, d, i, j;
if (G->noop) return;
i = 0;
b = d = G->A;
for (; i < G->n; ++i) {
m = G->M[i];
if (~m) {
j = bsfl(~m);
m >>= j;
m <<= j;
d -= j;
break;
} else {
b -= DWBITS;
d -= DWBITS;
}
}
for (; i < G->n; b -= DWBITS, m = G->M[++i]) {
for (; m; m &= ~((dword)1 << j)) {
a = b + ~(j = bsfl(m));
Set(--d, MAKE(Relocate(G, LO(Get(a))), Relocate(G, HI(Get(a)))));
SetShadow(d, MAKE(LO(GetShadow(a)), Relocate(G, HI(GetShadow(a)))));
}
}
cx = d;
}
int MarkSweep(int A, int x) {
struct Gc *G;
if (x >= A) return cx = A, x;
G = NewGc(A);
Mark(G, x);
Census(G);
x = Relocate(G, x);
Sweep(G);
return x;
}