make valgrind accept /𝕩 and 𝕨/𝕩 impls

This commit is contained in:
dzaima 2022-07-10 01:51:15 +03:00
parent 0684fe5fcb
commit 041a87ff98
7 changed files with 174 additions and 3 deletions

View File

@ -326,6 +326,96 @@ B pick_c2(B t, B w, B x) {
#ifdef __BMI2__
#include <immintrin.h>
#if USE_VALGRIND
#define DBG_VG_SLASH 0
u64 loadMask(u64* p, u64 unk, u64 exp, u64 i, u64 pos) {
// #if DBG_VG_SLASH
// if (pos==0) printf("index %2ld, got %016lx\n", i, p[i]);
// #endif
if (pos==0) return ~(p[i]^exp);
u64 res = loadMask(p, unk, exp, i, pos<<1);
if (unk&pos) res&= loadMask(p, unk, exp, i|pos, pos<<1);
return res;
}
NOINLINE u64 vg_load64(u64* p, u64 i) {
u64 unk = ~vg_getDefined_u64(i);
u64 res = p[vg_withDefined_u64(i, ~0ULL)]; // result value will always be the proper indexing operation
i32 undefCount = POPC(unk);
if (undefCount>0) {
if (undefCount>8) err("too many unknown bits in index of vg_load64");
res = vg_withDefined_u64(res, loadMask(p, unk, res, i & ~unk, 1));
}
#if DBG_VG_SLASH
vg_printDefined_u64("idx", i);
vg_printDefined_u64("res", res);
#endif
return res;
}
NOINLINE u64 vg_pext_u64(u64 src, u64 mask) {
u64 maskD = vg_getDefined_u64(mask);
u64 r = vg_undef_u64(0);
i32 ri = 0;
u64 undefMask = 0;
for (i32 i = 0; i < 64; i++) {
u64 c = 1ull<<i;
if (!(maskD&c) && undefMask==0) undefMask = (~0ULL)<<ri;
if (vg_def_u64(mask&c)) r = vg_withBit_u64(r, ri++, (c&src)!=0);
}
while (ri<64) r = vg_withBit_u64(r, ri++, 0);
r = vg_withDefined_u64(r, vg_getDefined_u64(r) & ~undefMask);
#if DBG_VG_SLASH
printf("pext:\n");
vg_printDefined_u64("src", src);
vg_printDefined_u64("msk", mask);
vg_printDefined_u64("res", r);
vg_printDefined_u64("exp", _pext_u64(src, mask));
#endif
return r;
}
NOINLINE u64 vg_pdep_u64(u64 src, u64 mask) {
if (0 != ~vg_getDefined_u64(mask)) err("pdep impl assumes mask is defined everywhere");
u64 c = src;
u64 r = 0;
for (i32 i = 0; i < 64; i++) {
if ((mask>>i)&1) {
r|= (c&1) << i;
c>>= 1;
}
}
#if DBG_VG_SLASH
printf("pdep:\n");
vg_printDefined_u64("src", src);
vg_printDefined_u64("msk", mask);
vg_printDefined_u64("res", r);
vg_printDefined_u64("exp", _pdep_u64(src, mask));
#endif
return r;
}
u64 vgRand64(u64 range);
NOINLINE u64 rand_popc64(u64 x) {
u64 def = vg_getDefined_u64(x);
if (def==~0ULL) return POPC(x);
i32 min = POPC(x & def);
i32 diff = POPC(~def);
i32 res = min + vgRand64(diff);
#if DBG_VG_SLASH
printf("popc:\n");
vg_printDefined_u64("x", x);
printf("popc in %d-%d; res: %d\n", min, min+diff, res);
#endif
return res;
}
#define _pext_u32 vg_pext_u64
#define _pext_u64 vg_pext_u64
#define _pdep_u32 vg_pdep_u64
#define _pdep_u64 vg_pdep_u64
#else
#define vg_load64(p, i) p[i]
#define rand_popc64(X) POPC(X)
#endif
void storeu_u64(u64* p, u64 v) { memcpy(p, &v, 8); }
u64 loadu_u64(u64* p) { u64 v; memcpy(&v, p, 8); return v; }
#if SINGELI
@ -433,7 +523,7 @@ B slash_c2(B t, B w, B x) {
for (usz i=0; i<BIT_N(wia); i++) {
u64 wv = wp[i];
u64 v = _pext_u64(xp[i], wv);
u64 c = POPC(wv);
u64 c = rand_popc64(wv);
cw|= v<<ro;
u64 ro2 = ro+c;
if (ro2>=64) {

View File

@ -494,7 +494,17 @@ B rand_subset_c2(B t, B w, B x) {
return r;
}
#if USE_VALGRIND
u64 vgRandSeed;
u64 vgRand64(u64 range) {
return wy2u0k(wyrand(&vgRandSeed), range);
}
#endif
static NOINLINE void rand_init() {
#if USE_VALGRIND
vgRandSeed = nsTime();
#endif
rand_ns = m_nnsDesc("seed1", "seed2", "range", "deal", "subset");
NSDesc* d = rand_ns->nsDesc;
d->expGIDs[0] = d->expGIDs[1] = -1;

View File

@ -697,6 +697,40 @@ NOINLINE void print_allocStats() {
#endif
}
#if USE_VALGRIND
static void printBitDef(u8 val, u8 def) {
printf("%s", def&1? val&1?"1":"0" : val&1?"¹":"");
}
void vg_printDump_p(char* name, void* data, u64 len) {
u8 vbits[len];
int r = VALGRIND_GET_VBITS(data, vbits, len);
printf("%s:\n", name);
if (r!=1) printf("(failed to get vbits)\n");
for (u64 i = 0; i < len; i++) {
if (i!=0) printf(i&7? " " : "\n");
u8 cv = ~vbits[i];
u8 cd = ((u8*)data)[i];
VALGRIND_SET_VBITS(&cd, &(u8[]){0}, 1);
for (i32 j = 7; j >= 0; j--) {
printBitDef(cd>>j, cv>>j);
}
}
putchar('\n');
}
void vg_printDefined_u64(char* name, u64 x) {
printf("%s: ", name);
u64 d = vg_getDefined_u64(x);
u64 xv = x;
VALGRIND_MAKE_MEM_DEFINED(&xv, 8);
for (i32 i = 63; i >= 0; i--) printBitDef(xv>>i, d>>i);
printf("\n");
}
#endif
// for gdb
B info_c2(B, B, B);
Value* g_v(B x) { return v(x); }

View File

@ -1,3 +1,7 @@
#ifdef USE_VALGRIND
#include "../utils/valgrind.h"
#endif
#define buckets BN(buckets)
static void BN(free)(Value* x) {
onFree(x);

View File

@ -4,3 +4,6 @@ def pext{x:u64, m:u64} = emit{u64, '_pext_u64', x, m}
def pext{x:u32, m:u32} = emit{u32, '_pext_u32', x, m}
def popc{x:T & isint{T} & width{T}==64} = emit{u8, '__builtin_popcountll', x}
def popc{x:T & isint{T} & width{T}<=32} = emit{u8, '__builtin_popcount', x}
def popcRand{x:T & isint{T} & width{T}==64} = emit{u8, 'rand_popc64', x} # under valgrind, return a random result in the range of possible ones
def popcRand{x:T & isint{T} & width{T}<=32} = emit{u8, 'rand_popc64', x}

View File

@ -20,11 +20,13 @@ def tab{n,l} = {
def tab{n==0,l} = tup{0}
c16lut:*u64 = tab{4,16}
def vgLoad{p:T, i & T == *u64} = emit{eltype{T}, 'vg_load64', p, i}
def comp16{w:*u64, X, r:*i16, l:u64} = {
@for(w in *u8~~w over i to cdiv{l,8}) {
def step{w} = {
pc:= popc{w}
storeu{*u64~~r, 0, pext{promote{u64,X{}}, load{c16lut, w}}}
pc:= popcRand{w}
storeu{*u64~~r, 0, pext{promote{u64,X{}}, vgLoad{c16lut, w}}}
r+= pc
}
step{w&15}

28
src/utils/valgrind.h Normal file
View File

@ -0,0 +1,28 @@
#pragma once
#include <valgrind/memcheck.h>
static u64 vg_getDefined_u64(u64 x) { // for each bit, returns whether it is defined
u64 r;
i32 v = VALGRIND_GET_VBITS(&x, &r, 8);
if(v==0) return ~0ULL; // don't do weird stuff if not on valgrind
if (v!=1) err("unexpected VALGRIND_GET_VBITS result");
return ~r;
}
static u64 vg_withDefined_u64(u64 x, u64 where) {
where = ~where;
i32 v = VALGRIND_SET_VBITS(&x, &where, 8);
if (v>1) err("unexpected VALGRIND_SET_VBITS result");
return x;
}
static u64 vg_undef_u64(u64 x) {
return vg_withDefined_u64(x, 0);
}
static u64 vg_def_u64(u64 x) {
return vg_withDefined_u64(x, ~0ULL);
}
static u64 vg_withBit_u64(u64 r, i32 i, bool val) {
return (r & ~(1ULL<<i)) | ((u64)val)<<i;
}
void vg_printDefined_u64(char* name, u64 x);
void vg_printDump_p(char* name, void* data, u64 len);
#define vg_printDump_v(X) ({ AUTO x_ = (X); vg_printDump_p(#X, &x_, sizeof(x_)); })