This commit is contained in:
dzaima 2021-10-21 22:16:04 +03:00
parent f50b8ab503
commit 71c454235c
10 changed files with 422 additions and 89 deletions

9
.gitignore vendored
View File

@ -1,5 +1,6 @@
BQN
c.bqn
/BQN
perf.*
obj/
asm_*
/obj/
/asm_*
/src/singeli/gen
/Singeli/

3
.gitmodules vendored Normal file
View File

@ -0,0 +1,3 @@
[submodule "SingeliClone"]
path = SingeliClone
url = https://github.com/mlochbaum/Singeli

1
SingeliClone Submodule

@ -0,0 +1 @@
Subproject commit 3c474f3ce8ba38e48f51a33c305168cda79fc74c

18
SingeliMake.bqn Executable file
View File

@ -0,0 +1,18 @@
# •Show •args
# resolve arguments & files
siDirRsrcfileRresfileRbuildDir •args
siDir •file.At siDirR
tmpfile •file.At "obj/singeliDeps"
srcfile •file.At srcfileR
resfile •file.At resfileR
depfile (•file.At buildDir) •file.At ".d"˜ ('/') srcfile
# invoke singeli, which creates the result file
("-d" tmpfile "-o" resfile srcfile) •Import siDir •file.At "singeli"
# output dependency file
deps siDir•file.At¨ •file.Lines tmpfile
lnln @+1010
depfile •file.Chars resfileR ": " srcfile ' '¨deps lnln (":"lnln)¨ deps

136
makefile
View File

@ -2,40 +2,55 @@ SHELL = /usr/bin/env bash
MAKEFLAGS+= --no-print-directory
o3:
@${MAKE} t=o3 b
@${MAKE} singeli=0 t=o3 f="-O3" c
o3g:
@${MAKE} t=o3g b
@${MAKE} singeli=0 t=o3g f="-O3 -g" c
o3n:
@${MAKE} t=o3n b
rtperf:
@${MAKE} t=rtperf b
rtverify:
@${MAKE} t=rtverify b
@${MAKE} singeli=0 t=o3n f="-O3 -march=native" c
debug:
@${MAKE} t=debug b
@${MAKE} singeli=0 t=debug f="-g -DDEBUG" c
debug1:
@${MAKE} t=debug1 b
@${MAKE} singeli=0 t=debug1 f="-g -DDEBUG" c
rtperf:
@${MAKE} singeli=0 t=rtperf f="-O3 -DRT_PERF" c
rtverify:
@${MAKE} singeli=0 t=rtverify f="-DDEBUG -O3 -DRT_VERIFY" c
heapverify:
@${MAKE} t=heapverify b
@${MAKE} singeli=0 t=heapverify f="-DDEBUG -g -DHEAP_VERIFY" c
o3n-singeli:
@${MAKE} singeli=1 t=o3n_si f="-O3 -march=native" c
debugn-singeli:
@${MAKE} singeli=1 t=debugn_si f="-g -DDEBUG -march=native" c
debug-singeli:
@${MAKE} singeli=1 t=debug_si f="-g -DDEBUG" c
bd = obj/${t}
c: # custom
@${MAKE} t=${t} FLAGS.${t}="${f}" b
b: gen
PIE = -no-pie
@mkdir -p ${bd}
@if [ "${singeli}" -eq 1 ]; then \
mkdir -p src/singeli/gen; \
${MAKE} gen-singeli; \
echo "post-singeli build:"; \
fi
@${MAKE} t=${t} FLAGS="${f}" gen
single-o3:
$(CC) -std=gnu11 -Wall -Wno-unused-function -fms-extensions $(CCFLAGS) ${PIE} $(f) -O3 -o BQN src/opt/single.c -lm
$(CC) -std=gnu11 -Wall -Wno-unused-function -fms-extensions $(CCFLAGS) $(PIE) $(f) -O3 -o BQN src/opt/single.c -lm
single-o3g:
$(CC) -std=gnu11 -Wall -Wno-unused-function -fms-extensions $(CCFLAGS) ${PIE} $(f) -O3 -g -o BQN src/opt/single.c -lm
$(CC) -std=gnu11 -Wall -Wno-unused-function -fms-extensions $(CCFLAGS) $(PIE) $(f) -O3 -g -o BQN src/opt/single.c -lm
single-debug:
$(CC) -std=gnu11 -Wall -Wno-unused-function -fms-extensions $(CCFLAGS) ${PIE} $(f) -DDEBUG -g -o BQN src/opt/single.c -lm
$(CC) -std=gnu11 -Wall -Wno-unused-function -fms-extensions $(CCFLAGS) $(PIE) $(f) -DDEBUG -g -o BQN src/opt/single.c -lm
single-c:
$(CC) -std=gnu11 -Wall -Wno-unused-function -fms-extensions $(CCFLAGS) ${PIE} $(f) -o BQN src/opt/single.c -lm
$(CC) -std=gnu11 -Wall -Wno-unused-function -fms-extensions $(CCFLAGS) $(PIE) $(f) -o BQN src/opt/single.c -lm
# compiler setup
CC = clang
PIE = -no-pie
# Detects if we are running GCC instead of Clang
CC_IS_GCC = $(shell $(CC) --version | head -n1 | grep -m 1 -c "gcc")
@ -44,84 +59,105 @@ CCFLAGS = -Wno-parentheses
else
CCFLAGS = -Wno-microsoft-anon-tag
endif
CMD = $(CC) -std=gnu11 -Wall -Wno-unused-function -fms-extensions ${CCFLAGS} $(FLAGS) -fPIE -MMD -MP -MF
ifeq (${singeli}, 1)
SINGELIFLAGS = '-DSINGELI'
else
singeli = 0
endif
CMD = $(CC) -std=gnu11 -Wall -Wno-unused-function -fms-extensions $(CCFLAGS) $(FLAGS) $(SINGELIFLAGS) -fPIE -MMD -MP -MF
# `if` to allow `make clean` alone to clean everything, but `make t=debug clean` to just clean obj/debug
ifeq ($(MAKECMDGOALS),clean)
ifndef t
t = *
else ifeq ($(t),)
t = o3
endif
endif
ifneq (${t},debug1)
# don't make makefile cry about something idk
ifeq (${MAKECMDGOALS},b)
MAKEFLAGS += -j4
ifneq (${J4added},yes)
ifeq (${MAKECMDGOALS},gen)
MAKEFLAGS+= -j4 J4added=yes
endif
ifeq (${MAKECMDGOALS},gen-singeli)
MAKEFLAGS+= -j4 J4added=yes
endif
endif
endif
# per-type flags
FLAGS.o3 := -O3
FLAGS.o3n := -O3 -march=native
FLAGS.o3g := -O3 -g
FLAGS.debug := -g -DDEBUG
FLAGS.debug1 := -g -DDEBUG
FLAGS.rtperf := -O3 -DRT_PERF
FLAGS.heapverify := -DDEBUG -g -DHEAP_VERIFY
FLAGS.rtverify := -DDEBUG -O3 -DRT_VERIFY
FLAGS = ${FLAGS.${t}}
bd = obj/${t}
gen: builtins core base jit utils # build the final binary
@$(CC) ${PIE} -o BQN ${bd}/*.o -lm
@echo
builddir: # create the build directory. makefiles are stupid
@mkdir -p ${bd}
@echo ${postmsg}
# build individual object files
core: builddir ${addprefix ${bd}/, tyarr.o harr.o fillarr.o stuff.o derv.o mm.o heap.o}
core: ${addprefix ${bd}/, tyarr.o harr.o fillarr.o stuff.o derv.o mm.o heap.o}
${bd}/%.o: src/core/%.c
@echo $< | cut -c 5-
@$(CMD) $@.d -o $@ -c $<
base: builddir ${addprefix ${bd}/, load.o main.o rtwrap.o vm.o ns.o nfns.o}
base: ${addprefix ${bd}/, load.o main.o rtwrap.o vm.o ns.o nfns.o}
${bd}/%.o: src/%.c
@echo $< | cut -c 5-
@$(CMD) $@.d -o $@ -c $<
utils: builddir ${addprefix ${bd}/, utf.o hash.o file.o mut.o each.o bits.o}
utils: ${addprefix ${bd}/, utf.o hash.o file.o mut.o each.o bits.o}
${bd}/%.o: src/utils/%.c
@echo $< | cut -c 5-
@$(CMD) $@.d -o $@ -c $<
jit: builddir ${addprefix ${bd}/, nvm.o}
jit: ${addprefix ${bd}/, nvm.o}
${bd}/%.o: src/jit/%.c
@echo $< | cut -c 5-
@$(CMD) $@.d -o $@ -c $<
builtins: builddir ${addprefix ${bd}/, arithm.o arithd.o cmp.o sfns.o sort.o md1.o md2.o fns.o sysfn.o internal.o}
builtins: ${addprefix ${bd}/, arithm.o arithd.o cmp.o sfns.o sort.o md1.o md2.o fns.o sysfn.o internal.o}
${bd}/%.o: src/builtins/%.c
@echo $< | cut -c 5-
@$(CMD) $@.d -o $@ -c $<
src/gen/customRuntime:
@echo "Copying precompiled bytecode from the bytecode branch"
git checkout remotes/origin/bytecode src/gen/{compiler,formatter,runtime0,runtime1,src}
git reset src/gen/{compiler,formatter,runtime0,runtime1,src}
${bd}/load.o: src/gen/customRuntime
# singeli
.INTERMEDIATE: preSingeliBin
preSingeliBin:
@if [ ! -d Singeli ]; then \
echo "Updating Singeli submodule; link custom Singeli to Singeli/ to avoid"; \
git submodule update --init; \
fi
@echo "pre-singeli build:"
@${MAKE} singeli=0 postmsg="singeli sources:" t=presingeli f='' c
@mv BQN obj/presingeli/BQN
gen-singeli: ${addprefix src/singeli/gen/, cmp.c}
@:
src/singeli/gen/%.c: src/singeli/src/%.singeli preSingeliBin
@echo $< | cut -c 17- | sed 's/^/ /'
@obj/presingeli/BQN SingeliMake.bqn "$$(if [ -d Singeli ]; then echo Singeli; else echo SingeliClone; fi)" $< $@ "${bd}"
# dependency files
-include $(bd)/*.d
clean-singeli:
rm -rf src/singeli/gen/
ifeq ($(t), *)
clean: clean-singeli
endif
clean:
rm -f ${bd}/*.o
rm -f ${bd}/*.d

View File

@ -1,35 +1,16 @@
#include "../core.h"
#include "../utils/each.h"
#include <math.h>
#define P2(N) { if (isArr(w)|isArr(x)) { \
SLOWIF((!isArr(w) || TI(w,elType)!=el_B) && (!isArr(x) || TI(x,elType)!=el_B)) SLOW2("cmp " #N, w, x); \
return arith_recd(N##_c2, w, x); \
}}
#define AL(X) u64* rp; B r = m_bitarrc(&rp, X); usz ria=a(r)->ia; usz bia = BIT_N(ria);
static NOINLINE u8 aMakeEq(B* w, B* x, u8 we, u8 xe) { // returns el_MAX if failed
B s = we<xe?*w:*x;
u8 me = we>xe?we:xe;
if (elNum(we) & elNum(xe)) {
switch(me) { default: UD;
case el_i8: s = taga(cpyI8Arr (s)); break;
case el_i16: s = taga(cpyI16Arr(s)); break;
case el_i32: s = taga(cpyI32Arr(s)); break;
case el_f64: s = taga(cpyF64Arr(s)); break;
}
} else if (elChr(we) & elChr(xe)) {
switch(me) { default: UD;
case el_c16: s = taga(cpyC16Arr(s)); break;
case el_c32: s = taga(cpyC32Arr(s)); break;
}
} else return el_MAX;
*(we<xe?w:x) = s;
return me;
}
#define CMP_IMPL(CHR, OP, FC, CF, BX) \
#if SINGELI
#include "../singeli/builtins/cmp.c"
#else
#define CMP_IMPL(CHR, NAME, RNAME, OP, FC, CF, BX) \
if (isF64(w)&isF64(x)) return m_i32(w.f OP x.f); \
if (isC32(w)&isC32(x)) return m_i32(w.u OP x.u); \
if (isF64(w)&isC32(x)) return m_i32(FC); \
@ -84,34 +65,57 @@ static NOINLINE u8 aMakeEq(B* w, B* x, u8 we, u8 xe) { // returns el_MAX if fail
dec(r); \
} \
end:;
#endif
#define CMP(CHR,NAME,OP,FC,CF,BX) \
static NOINLINE u8 aMakeEq(B* w, B* x, u8 we, u8 xe) { // returns el_MAX if failed
B s = we<xe?*w:*x;
u8 me = we>xe?we:xe;
if (elNum(we) & elNum(xe)) {
switch(me) { default: UD;
case el_i8: s = taga(cpyI8Arr (s)); break;
case el_i16: s = taga(cpyI16Arr(s)); break;
case el_i32: s = taga(cpyI32Arr(s)); break;
case el_f64: s = taga(cpyF64Arr(s)); break;
}
} else if (elChr(we) & elChr(xe)) {
switch(me) { default: UD;
case el_c16: s = taga(cpyC16Arr(s)); break;
case el_c32: s = taga(cpyC32Arr(s)); break;
}
} else return el_MAX;
*(we<xe?w:x) = s;
return me;
}
#define CMP(CHR,NAME,RNAME,OP,FC,CF,BX) \
B NAME##_c2(B t, B w, B x) { \
CMP_IMPL(CHR, OP, FC, CF, BX); \
CMP_IMPL(CHR,NAME,RNAME,OP,FC,CF,BX); \
P2(NAME); \
return m_i32(compare(w, x) OP 0); \
}
CMP("", le, <=, 1, 0, ~wv | xv)
CMP("", ge, >=, 0, 1, wv | ~xv)
CMP("<", lt, < , 1, 0, ~wv & xv)
CMP(">", gt, > , 0, 1, wv & ~xv)
CMP("", le, ge, <=, 1, 0, ~wv | xv)
CMP("", ge, le, >=, 0, 1, wv | ~xv)
CMP("<", lt, gt, < , 1, 0, ~wv & xv)
CMP(">", gt, lt, > , 0, 1, wv & ~xv)
#undef CMP
B eq_c2(B t, B w, B x) {
CMP_IMPL("=", ==, 0, 0, ~wv^xv);
CMP_IMPL("=", eq, eq, ==, 0, 0, ~wv^xv);
P2(eq);
B r = m_i32(atomEqual(w, x));
dec(w); dec(x);
return r;
}
B ne_c2(B t, B w, B x) {
CMP_IMPL("", !=, 1, 1, wv^xv);
CMP_IMPL("", ne, ne, !=, 1, 1, wv^xv);
P2(ne);
B r = m_i32(!atomEqual(w, x));
dec(w); dec(x);
return r;
}
extern B rt_merge;
B gt_c1(B t, B x) {
if (isAtm(x)) return x;

View File

@ -0,0 +1,88 @@
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-variable"
#include "../gen/cmp.c"
#pragma GCC diagnostic pop
#define avx2_eqAA_u8( d,w,x,l) avx2_eqAA_i8 (d,(i8 *)(w),(i8 *)(x),l)
#define avx2_eqAA_u16(d,w,x,l) avx2_eqAA_i16(d,(i16*)(w),(i16*)(x),l)
#define avx2_eqAA_u32(d,w,x,l) avx2_eqAA_i32(d,(i32*)(w),(i32*)(x),l)
#define avx2_neAA_u8( d,w,x,l) avx2_neAA_i8 (d,(i8 *)(w),(i8 *)(x),l)
#define avx2_neAA_u16(d,w,x,l) avx2_neAA_i16(d,(i16*)(w),(i16*)(x),l)
#define avx2_neAA_u32(d,w,x,l) avx2_neAA_i32(d,(i32*)(w),(i32*)(x),l)
#define avx2_eqAS_u8( d,w,x,l) avx2_eqAS_i8 (d,(i8 *)(w),x,l)
#define avx2_eqAS_u16(d,w,x,l) avx2_eqAS_i16(d,(i16*)(w),x,l)
#define avx2_eqAS_u32(d,w,x,l) avx2_eqAS_i32(d,(i32*)(w),x,l)
#define avx2_neAS_u8( d,w,x,l) avx2_neAS_i8 (d,(i8 *)(w),x,l)
#define avx2_neAS_u16(d,w,x,l) avx2_neAS_i16(d,(i16*)(w),x,l)
#define avx2_neAS_u32(d,w,x,l) avx2_neAS_i32(d,(i32*)(w),x,l)
#define avx2_ltAA_i8(d,w,x,l) avx2_gtAA_i8(d,x,w,l)
#define avx2_leAA_i8(d,w,x,l) avx2_geAA_i8(d,x,w,l)
#define avx2_ltAA_i16(d,w,x,l) avx2_gtAA_i16(d,x,w,l)
#define avx2_leAA_i16(d,w,x,l) avx2_geAA_i16(d,x,w,l)
#define avx2_ltAA_i32(d,w,x,l) avx2_gtAA_i32(d,x,w,l)
#define avx2_leAA_i32(d,w,x,l) avx2_geAA_i32(d,x,w,l)
#define avx2_leAA_u8( d,w,x,l) avx2_geAA_u8 (d,x,w,l)
#define avx2_leAA_u16(d,w,x,l) avx2_geAA_u16(d,x,w,l)
#define avx2_leAA_u32(d,w,x,l) avx2_geAA_u32(d,x,w,l)
#define avx2_ltAA_u8( d,w,x,l) avx2_gtAA_u8 (d,x,w,l)
#define avx2_ltAA_u16(d,w,x,l) avx2_gtAA_u16(d,x,w,l)
#define avx2_ltAA_u32(d,w,x,l) avx2_gtAA_u32(d,x,w,l)
#define avx2_ltAA_f64(d,w,x,l) avx2_gtAA_f64(d,x,w,l)
#define avx2_leAA_f64(d,w,x,l) avx2_geAA_f64(d,x,w,l)
#define CMP_IMPL(CHR, NAME, RNAME, OP, FC, CF, BX) \
if (isF64(w)&isF64(x)) return m_i32(w.f OP x.f); \
if (isC32(w)&isC32(x)) return m_i32(w.u OP x.u); \
if (isF64(w)&isC32(x)) return m_i32(FC); \
if (isC32(w)&isF64(x)) return m_i32(CF); \
if (isArr(w)) { u8 we = TI(w,elType); \
if (we==el_B) goto end; \
if (isArr(x)) { u8 xe = TI(x,elType); \
if (xe==el_B) goto end; \
if (rnk(w)==rnk(x)) { if (!eqShape(w, x)) thrF(CHR": Expected equal shape prefix (%H ≡ ≢𝕨, %H ≡ ≢𝕩)", w, x); \
if (we!=xe) { B tw=w,tx=x; \
we = aMakeEq(&tw, &tx, we, xe); \
if (we==el_MAX) goto end; \
w=tw; x=tx; \
} \
AL(x) \
switch(we) { default: UD; \
case el_bit: { u64* wp=bitarr_ptr(w); u64* xp=bitarr_ptr(x); for(usz i=0;i<bia;i++) { u64 wv=wp[i]; u64 xv=xp[i]; rp[i]=BX; } break; } \
case el_i8: avx2_##NAME##AA_i8 (rp, i8any_ptr (w), i8any_ptr (x), ria); break; \
case el_i16: avx2_##NAME##AA_i16(rp, i16any_ptr(w), i16any_ptr(x), ria); break; \
case el_i32: avx2_##NAME##AA_i32(rp, i32any_ptr(w), i32any_ptr(x), ria); break; \
case el_f64: avx2_##NAME##AA_f64(rp, f64any_ptr(w), f64any_ptr(x), ria); break; \
case el_c8: avx2_##NAME##AA_u8 (rp, c8any_ptr (w), c8any_ptr (x), ria); break; \
case el_c16: avx2_##NAME##AA_u16(rp, c16any_ptr(w), c16any_ptr(x), ria); break; \
case el_c32: avx2_##NAME##AA_i32(rp, (i32*)c32any_ptr(w), (i32*)c32any_ptr(x), ria); break; \
} \
dec(w);dec(x); return r; \
} \
} else { AL(w) \
switch(we) { default: UD; \
case el_bit: { if (!q_bit(x)) break; u64 xv=bitx(x); u64* wp=bitarr_ptr(w); for(usz i=0;i<bia;i++) { u64 wv=wp[i]; rp[i]=BX; } dec(w); return r; } \
case el_i8: if (!q_i8 (x))break; avx2_##NAME##AS_i8 (rp, i8any_ptr (w), o2iu(x), ria); dec(w); return r; \
case el_i16: if (!q_i16(x))break; avx2_##NAME##AS_i16(rp, i16any_ptr(w), o2iu(x), ria); dec(w); return r; \
case el_i32: if (!q_i32(x))break; avx2_##NAME##AS_i32(rp, i32any_ptr(w), o2iu(x), ria); dec(w); return r; \
case el_f64: if (!q_f64(x))break; avx2_##NAME##AS_f64(rp, f64any_ptr(w), o2fu(x), ria); dec(w); return r; \
case el_c8: if (!q_c8 (x))break; avx2_##NAME##AS_u8 (rp, c8any_ptr (w), o2cu(x), ria); dec(w); return r; \
case el_c16: if (!q_c16(x))break; avx2_##NAME##AS_u16(rp, c16any_ptr(w), o2cu(x), ria); dec(w); return r; \
case el_c32: if (!q_c32(x))break; avx2_##NAME##AS_i32(rp, (i32*)c32any_ptr(w), o2cu(x), ria); dec(w); return r; \
} \
dec(r); \
} \
} else if (isArr(x)) { u8 xe = TI(x,elType); if (xe==el_B) goto end; AL(x) \
switch(xe) { default: UD; \
case el_bit: { if (!q_bit(w)) break; u64 wv=bitx(w); u64* xp=bitarr_ptr(x); for(usz i=0;i<bia;i++) { u64 xv=xp[i]; rp[i]=BX; } dec(x); return r; } \
case el_i8: if (!q_i8 (w))break; avx2_##RNAME##AS_i8 (rp, i8any_ptr (x), o2iu(w), ria); dec(x); return r; \
case el_i16: if (!q_i16(w))break; avx2_##RNAME##AS_i16(rp, i16any_ptr(x), o2iu(w), ria); dec(x); return r; \
case el_i32: if (!q_i32(w))break; avx2_##RNAME##AS_i32(rp, i32any_ptr(x), o2iu(w), ria); dec(x); return r; \
case el_f64: if (!q_f64(w))break; avx2_##RNAME##AS_f64(rp, f64any_ptr(x), o2fu(w), ria); dec(x); return r; \
case el_c8: if (!q_c8 (w))break; avx2_##RNAME##AS_u8 (rp, c8any_ptr (x), o2cu(w), ria); dec(x); return r; \
case el_c16: if (!q_c16(w))break; avx2_##RNAME##AS_u16(rp, c16any_ptr(x), o2cu(w), ria); dec(x); return r; \
case el_c32: if (!q_c32(w))break; avx2_##RNAME##AS_i32(rp, (i32*)c32any_ptr(x), o2cu(w), ria); dec(x); return r; \
} \
dec(r); \
} \
end:;

View File

@ -0,0 +1,77 @@
# ugh the intrinsics have their own broken type system
def r_d2i{R, a:T} = emit{R, '_mm256_castpd_si256', a}
def r_f2i{R, a:T} = emit{R, '_mm256_castps_si256', a}
def r_i2d{a:T} = emit{[4]f64, '_mm256_castsi256_pd', a}
def r_f2d{a:T} = emit{[4]f64, '_mm256_castps_pd', a}
def r_d2f{a:T} = emit{[8]f32, '_mm256_castpd_ps', a}
def r_i2f{a:T} = emit{[8]f32, '_mm256_castsi256_ps', a}
# various utilities
def isunsigned{T} = isint{T} & ~issigned{T}
def isintv{T} = isint{eltype{T}}
def isfloatv{T} = isfloat{eltype{T}}
def issignedv{T} = issigned{eltype{T}}
def isunsignedv{T} = isunsigned{eltype{T}}
def w256{T} = width{T}==256
def isintv{T,w} = isintv{T} & width{eltype{T}}==w
# load
def cast_vp{T, a & w256{T}} = emit{*T, '(void*)', a}
def vload{a:T, n & w256{eltype{T}} & isintv{eltype{T}}} = emit{eltype{T}, '_mm256_loadu_si256', emit{T, 'op +', a, n}}
def vload{a:T, n & w256{eltype{T}} & isfloatv{eltype{T}}} = r_i2d{vload{cast_vp{[4]u64, a}, n}} # TODO use the proper float load
# ops
# broadcast; TODO restrict v
def broadcast{T, v & w256{T} & isintv{T, 8}} = emit{T, '_mm256_set1_epi8', v}
def broadcast{T, v & w256{T} & isintv{T, 16}} = emit{T, '_mm256_set1_epi16', v}
def broadcast{T, v & w256{T} & isintv{T, 32}} = emit{T, '_mm256_set1_epi32', v}
def broadcast{T, v & w256{T} & isintv{T, 64}} = emit{T, '_mm256_set1_epi64x',v}
def broadcast{T, v & w256{T} & eltype{T}==f64} = emit{T, '_mm256_set1_pd', v}
def __xor{a:T, b:T & w256{T} & isunsignedv{T}} = r_f2i{T, emit{[8]f32, '_mm256_xor_ps', r_i2f{a}, r_i2f{b}}}
def __not{a:T & w256{T} & isunsignedv{T}} = a ^ broadcast{T, ~cast{eltype{T},0}}
# min & max
def min{a:T,b:T & T==[32]i8 } = emit{T, '_mm256_min_epi8', a, b}; def min{a:T,b:T & T==[32]u8 } = emit{T, '_mm256_min_epu8', a, b}
def min{a:T,b:T & T==[16]i16} = emit{T, '_mm256_min_epi16', a, b}; def min{a:T,b:T & T==[16]u16} = emit{T, '_mm256_min_epu16', a, b}
def min{a:T,b:T & T==[ 8]i32} = emit{T, '_mm256_min_epi32', a, b}; def min{a:T,b:T & T==[ 8]u32} = emit{T, '_mm256_min_epu32', a, b}
def max{a:T,b:T & T==[32]i8 } = emit{T, '_mm256_max_epi8', a, b}; def max{a:T,b:T & T==[32]u8 } = emit{T, '_mm256_max_epu8', a, b}
def max{a:T,b:T & T==[16]i16} = emit{T, '_mm256_max_epi16', a, b}; def max{a:T,b:T & T==[16]u16} = emit{T, '_mm256_max_epu16', a, b}
def max{a:T,b:T & T==[ 8]i32} = emit{T, '_mm256_max_epi32', a, b}; def max{a:T,b:T & T==[ 8]u32} = emit{T, '_mm256_max_epu32', a, b}
# float comparison
def fcmpAVX{a,b,n} = r_d2i{[4]u64, emit{[4]f64, '_mm256_cmp_pd', a, b, n}}
def __eq{a:T,b:T & T==[4]f64} = fcmpAVX{a,b, 0}
def __ne{a:T,b:T & T==[4]f64} = fcmpAVX{a,b, 4}
def __gt{a:T,b:T & T==[4]f64} = fcmpAVX{a,b,30}
def __ge{a:T,b:T & T==[4]f64} = fcmpAVX{a,b,29}
def __lt{a:T,b:T & T==[4]f64} = fcmpAVX{a,b,17}
def __le{a:T,b:T & T==[4]f64} = fcmpAVX{a,b,18}
# signed comparison
def __eq{a:T,b:T & T==[32]i8 } = emit{[32]u8, '_mm256_cmpeq_epi8', a, b}
def __eq{a:T,b:T & T==[16]i16} = emit{[16]u16, '_mm256_cmpeq_epi16', a, b}
def __eq{a:T,b:T & T==[ 8]i32} = emit{[ 8]u32, '_mm256_cmpeq_epi32', a, b}
def __gt{a:T,b:T & T==[32]i8 } = emit{[32]u8, '_mm256_cmpgt_epi8', a, b}
def __gt{a:T,b:T & T==[16]i16} = emit{[16]u16, '_mm256_cmpgt_epi16', a, b}
def __gt{a:T,b:T & T==[ 8]i32} = emit{[ 8]u32, '_mm256_cmpgt_epi32', a, b}
def __lt{a:T,b:T & w256{T} & issignedv{T}} = b>a
def __ge{a:T,b:T & w256{T} & issignedv{T}} = ~(b>a)
def __le{a:T,b:T & w256{T} & issignedv{T}} = ~(a>b)
# unsigned comparison
def __eq{a:T,b:T & T==[32]u8 } = emit{[32]u8, '_mm256_cmpeq_epi8', a, b}
def __eq{a:T,b:T & T==[16]u16} = emit{[16]u16, '_mm256_cmpeq_epi16', a, b}
def __eq{a:T,b:T & T==[ 8]u32} = emit{[ 8]u32, '_mm256_cmpeq_epi32', a, b}
def __le{a:T,b:T & w256{T} & isunsignedv{T}} = a==min{a,b}
def __ge{a:T,b:T & w256{T} & isunsignedv{T}} = a==max{a,b}
def __lt{a:T,b:T & w256{T} & isunsignedv{T}} = ~(a>=b)
def __gt{a:T,b:T & w256{T} & isunsignedv{T}} = ~(a<=b)
# rest of comparison
def __ne{a:T,b:T & w256{T} & isintv{T}} = ~(b==a)
def getmask{x:[32]u8} = emit{u32, '_mm256_movemask_epi8', x}
def getmask{x:[8]u32} = emit{u8, '_mm256_movemask_ps', r_i2f{x}}
def getmask{x:[4]u64} = emit{u8, '_mm256_movemask_pd', r_i2d{x}}
def getmask{x:[16]u16} = {
msk:u32 = getmask{emit{[32]u8, '_mm256_packs_epi16', x, broadcast{[16]u16, 0}}}
(msk&255) | (msk>>8) # TODO try out permute4x64 for fixing up
}

View File

@ -0,0 +1,45 @@
def ones{T, n} = (cast{T,1}<<cast{T,n}) - 1
def b_get{x:*u64, n:(Size)} = {
((load{x,n>>6}>>(n&63)) & 1) != 0
}
def b_set{x:*u64, n:(Size), v:u1} = {
m:u64 = cast{u64,1}<<(n&63)
p:u64 = load{x,n>>6}
if (v) store{x,n>>6,p | m}
else store{x,n>>6,p & ~m}
}
def b_set{sz, x:*u64, n:(Size), v} = { vc:u64 = cast_i{u64,v}
am:u64 = 64/sz;
w:u64 = load{x,n/am}
sh:u64 = (n&(am-1)) * sz
w = w & ~(ones{u64,sz}<<sh)
w = w | (vc<<sh)
store{x, n/am, w}
}
def b_set{sz, x:*u64, n:(Size), v & sz==4} = {
x8:= cast_p{*u8, x}
#w:u64 = cast_i{u64, load{x8,n/2}}
#sh:u64 = (n&1) * 4
#w = w & ~(15<<sh)
#w = w | (cast_i{u64,v}<<sh)
w:u8 = load{x8,n/2}
if ((n&1)==1) {
w = w & ~(cast {u8,15}<<4)
w = w | (cast_i{u8,v}<<4)
} else {
w = w & ~(cast {u8,15})
w = w | (cast_i{u8,v}<<0)
}
store{x8, n/2, cast_i{u8,w}}
}
def b_set{sz, x:*u64, n:(Size), v & sz== 8} = store{cast_p{*u8, x}, n, cast_i{u8, v}}
def b_set{sz, x:*u64, n:(Size), v & sz==16} = store{cast_p{*u16, x}, n, cast_i{u16,v}}
def b_set{sz, x:*u64, n:(Size), v & sz==32} = store{cast_p{*u32, x}, n, cast_i{u32,v}}
def b_set{sz, x:*u64, n:(Size), v & sz==64} = store{x, n, cast_i{u64,v}}

View File

@ -0,0 +1,60 @@
include 'skin/c'
include 'arch/c'
def Size = u64
include './avx2'
include './bitops'
def unroll{vars,begin,end,block & match{kind{begin},'number'} & match{kind{end},'number'}} = {
def f{i,l & i==l} = 0
def f{i,l & i!=l} = {
exec{i, vars, block}
f{i+1, l}
}
f{begin,end}
}
def cdiv{a,b} = (a+b-1)/b
def any2bit{VT, unr, op, wS, wV, xS, xV, dst:*u64, len:Size} = {
xi:Size = 0
ri:Size = 0
def bam = vcount{VT}*unr
while (ri < cdiv{len,bam}) {
r:u64 = 0
@unroll (j from 0 to unr) r = r | (cast_i{u64, getmask{op{wV{xi+j}, xV{xi+j}}}} << (j*vcount{VT}))
b_set{bam, dst, ri, r}
xi = xi+unr
ri = ri+1
}
}
aa2bit{VT, unr, op}(dst:*u64, w:*eltype{VT}, x:*eltype{VT}, len:Size) : void = {
wv:*VT = cast_vp{VT, w}
xv:*VT = cast_vp{VT, x}
any2bit{VT, unr, op, {i}=>load{w,i}, {i}=>vload{wv,i}, {i}=>load{x,i}, {i}=>vload{xv,i}, dst, len}
}
as2bit{VT, unr, op}(dst:*u64, w:*eltype{VT}, x:eltype{VT}, len:Size) : void = {
wv:*VT = cast_vp{VT, w}
xv: VT = broadcast{VT, x}
any2bit{VT, unr, op, {i}=>load{w,i}, {i}=>vload{wv,i}, {i}=>x, {i}=>xv, dst, len}
}
#'avx2_eqAA_f64'=aa2bit{[4]f64,4,__eq}
'avx2_eqAA_i8'=aa2bit{[32]i8,1,__eq}; 'avx2_eqAA_i16'=aa2bit{[16]i16,1,__eq}; 'avx2_eqAA_i32'=aa2bit{[8]i32,1,__eq}; 'avx2_eqAA_f64'=aa2bit{[4]f64,2,__eq}
'avx2_neAA_i8'=aa2bit{[32]i8,1,__ne}; 'avx2_neAA_i16'=aa2bit{[16]i16,1,__ne}; 'avx2_neAA_i32'=aa2bit{[8]i32,1,__ne}; 'avx2_neAA_f64'=aa2bit{[4]f64,2,__ne}
'avx2_gtAA_i8'=aa2bit{[32]i8,1,__gt}; 'avx2_gtAA_i16'=aa2bit{[16]i16,1,__gt}; 'avx2_gtAA_i32'=aa2bit{[8]i32,1,__gt}; 'avx2_gtAA_f64'=aa2bit{[4]f64,2,__gt}
'avx2_geAA_i8'=aa2bit{[32]i8,1,__ge}; 'avx2_geAA_i16'=aa2bit{[16]i16,1,__ge}; 'avx2_geAA_i32'=aa2bit{[8]i32,1,__ge}; 'avx2_geAA_f64'=aa2bit{[4]f64,2,__ge}
'avx2_gtAA_u8'=aa2bit{[32]u8,1,__gt}; 'avx2_gtAA_u16'=aa2bit{[16]u16,1,__gt}
'avx2_geAA_u8'=aa2bit{[32]u8,1,__ge}; 'avx2_geAA_u16'=aa2bit{[16]u16,1,__ge}
'avx2_eqAS_i8'=as2bit{[32]i8,1,__eq}; 'avx2_eqAS_i16'=as2bit{[16]i16,1,__eq}; 'avx2_eqAS_i32'=as2bit{[8]i32,1,__eq}; 'avx2_eqAS_f64'=as2bit{[4]f64,2,__eq}
'avx2_neAS_i8'=as2bit{[32]i8,1,__ne}; 'avx2_neAS_i16'=as2bit{[16]i16,1,__ne}; 'avx2_neAS_i32'=as2bit{[8]i32,1,__ne}; 'avx2_neAS_f64'=as2bit{[4]f64,2,__ne}
'avx2_gtAS_i8'=as2bit{[32]i8,1,__gt}; 'avx2_gtAS_i16'=as2bit{[16]i16,1,__gt}; 'avx2_gtAS_i32'=as2bit{[8]i32,1,__gt}; 'avx2_gtAS_f64'=as2bit{[4]f64,2,__gt}
'avx2_geAS_i8'=as2bit{[32]i8,1,__ge}; 'avx2_geAS_i16'=as2bit{[16]i16,1,__ge}; 'avx2_geAS_i32'=as2bit{[8]i32,1,__ge}; 'avx2_geAS_f64'=as2bit{[4]f64,2,__ge}
'avx2_ltAS_i8'=as2bit{[32]i8,1,__lt}; 'avx2_ltAS_i16'=as2bit{[16]i16,1,__lt}; 'avx2_ltAS_i32'=as2bit{[8]i32,1,__lt}; 'avx2_ltAS_f64'=as2bit{[4]f64,2,__lt}
'avx2_leAS_i8'=as2bit{[32]i8,1,__le}; 'avx2_leAS_i16'=as2bit{[16]i16,1,__le}; 'avx2_leAS_i32'=as2bit{[8]i32,1,__le}; 'avx2_leAS_f64'=as2bit{[4]f64,2,__le}
'avx2_gtAS_u8'=as2bit{[32]u8,1,__gt}; 'avx2_gtAS_u16'=as2bit{[16]u16,1,__gt}
'avx2_geAS_u8'=as2bit{[32]u8,1,__ge}; 'avx2_geAS_u16'=as2bit{[16]u16,1,__ge}
'avx2_ltAS_u8'=as2bit{[32]u8,1,__lt}; 'avx2_ltAS_u16'=as2bit{[16]u16,1,__lt}
'avx2_leAS_u8'=as2bit{[32]u8,1,__le}; 'avx2_leAS_u16'=as2bit{[16]u16,1,__le}