aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPjotr Prins2025-02-11 02:27:38 -0600
committerPjotr Prins2025-02-11 02:27:38 -0600
commitd2150e69343861d7a83b820fc6e74f7572857651 (patch)
tree122202d5b814c2c6507096c9e8f948ec169c90fb
parentfd714598394a36d94846a5c2cfa1dc6a7e4bcced (diff)
downloadpresentations-d2150e69343861d7a83b820fc6e74f7572857651.tar.gz
Add slides
-rw-r--r--prescheme-nim-local/prescheme-nim-transpilers-FOSDEM-2025-talk.org238
1 files changed, 238 insertions, 0 deletions
diff --git a/prescheme-nim-local/prescheme-nim-transpilers-FOSDEM-2025-talk.org b/prescheme-nim-local/prescheme-nim-transpilers-FOSDEM-2025-talk.org
new file mode 100644
index 0000000..5b77991
--- /dev/null
+++ b/prescheme-nim-local/prescheme-nim-transpilers-FOSDEM-2025-talk.org
@@ -0,0 +1,238 @@
+#+TITLE: Small Headed Programming
+
+#+AUTHOR: Pjotr Prins
+
+# 15-20 min
+# Images: C-c C-x C-v
+# org-tree-slide-mode C-< and C->
+
+* Reality
+
+> Small headed programming: languages that fit in the brain
+
+Does not have to be a *small* language per se.
+
+Fits are:
+
+- Many LISPs
+- Zig
+- C
+
+No fits are:
+
+- Python
+- Rust
+- C++
+
+* What do I really want out of any language?
+
+- I want to express myself quickly and get results fast
+- I want decent error messages
+- I want to be able to drop in a REPL and debug
+- I want my code to be recognizable and readable after two years
+- I want the experience to be really fast at compile time
+- I would like compile type checking *when* I want it
+- I want few dependencies (wait?)
+
+* Thoughts on garbage collectors (GC)
+
+- Faster development, less mistakes
+- GC is a great invention - what is not to like?
+
+- Start/stop the world issues - threading and RT - e.g. games
+- Hurts when crossing language boundaries, i.e. bindings
+- Some languages suffer more than others, but it is never trivial
+
+* Rust does not have GC
+
+- That means you always have to deal with memory.
+
+* Two Years Ago
+
+- Everyone needs two languages: one for quick coding and one for performance
+- My 1st choice is to program in Guile and Zig (instead of Python and C)
+
+I went looking for convenience + a performance option
+
+Guile+Zig exploration:
+
+https://gitlab.com/pjotrp/guile-zig/-/blob/main/README.md
+
+* Zig
+
+- Zig is a minimalistic new language
+- unapologetically focused on performance
+- blazingly fast compiler
+- it may even replace C++ in places
+- Zig uses the C-ABI, has NO GC, so it is ideal for binding against other languages
+- Suffers from the semi-colon
+* Zig bootstrap
+
+- Compilers need to be bootstrapped (from C)
+- At some point they become self-hosting
+- Zig created a bootstrap in WASM - cool
+- But a binary blob does not sit well with the likes of Debian
+- Been an issue for years now and prevents deploying our toolstacks
+
+* Zig in Guix
+
+- Zig recently got bootstrapped from C source in Guix - it builds the WASM blob!
+- GNU Guix now Supports the latest stable verion!
+- Debian could copy that.
+
+When languages get popular enough, someone will create a bootstrap
+path. Even when it is hard.
+
+* Why not Zig now?
+
+- We target HPC - need to create deployments
+- Getting permission to run compiler tool stacks etc. can be painful
+- Similarly for low-end (RISC-V) systems
+- But C compilers are *always* there!!
+
+* Enter C-transpiling
+
+- C-transpilers w.o. GC, e.g. Nim, prescheme and Chicken (ref counter)
+- We want no GC because of linking against guile, python, etc.
+- Will compile C on any target system (ideally optimized!)
+- Can distribute both original code and transpiled code (if it looks nice enough)
+- Actually, nice output is important
+
+* Prescheme example
+
+Call C function to convert float to string:
+
+#+BEGIN_SRC C
+void gcvt(float value, int ndigits, char *buf);
+#+END_SRC
+
+#+BEGIN_SRC scheme
+ (define (gcvt v ndigits buf)
+ ((external "gcvt" (=> (float integer (^ char)) unit ) )
+ v ndigits buf))
+
+ (let ((target (make-string 20))
+ (f 1.2))
+ (gcvt f 4 target))
+#+END_SRC
+
+Translates to
+
+#+BEGIN_SRC C
+ char *target_2X = (char *)calloc( 1, 1 + 20);
+ gcvt(1.2, 4, target_2X);
+ ps_write_string(target_2X, out_0X);
+#+END_SRC
+
+* SIMDE
+
+SIMDe is a free software header-only library which provides fast, portable implementations of SIMD intrinsics for platforms which aren’t natively supported by the API in question.
+
+For example, with SIMDe you can use SSE, SSE2, SSE3, SSE4.1 and 4.2, AVX, AVX2, and many AVX-512 intrinsics on ARM, POWER, WebAssembly, or almost any platform with a C compiler. That includes, of course, x86 CPUs which don’t support the ISA extension in question (e.g., calling AVX-512F functions on a CPU which doesn’t natively support them).
+
+
+* Prescheme simde (Lisp)
+
+#+BEGIN_SRC scheme
+ (define (simde-loadu ds)
+ ((external "simde_mm256_loadu_pd" (=> ((^ float)) m256d))
+ ds ))
+
+ (let ((a (make-vector 4 1.1))
+ (b (make-vector 4 1.1))
+ (c (make-vector 4 1.1)))
+ (vector-set! a 0 2.2)
+ (vector-set! a 1 2.2)
+ (vector-set! a 2 4.2)
+ (vector-set! a 3 5.2)
+ (vector-set! b 0 1.1)
+ (vector-set! b 1 2.1)
+ (vector-set! b 2 3.1)
+ (vector-set! b 3 4.1)
+
+ (let* ((evens (simde-loadu a))
+ (odds (simde-loadu b))
+ (result (simde-storeu a (simde-sub-pd evens odds))))
+ (vector-for-each (lambda (i val)
+ (gcvt val 4 target)
+ (write-string target out)
+ (newline out)
+ )
+ result 4)
+#+END_SRC
+
+* Prescheme simde (C)
+
+#+BEGIN_SRC C
+ #include <simde/x86/avx512.h>
+
+ simde__m256d avx_7X;
+ simde__m256d odds_6X;
+ simde__m256d evens_5X;
+ // malloc and initialize a_3X and b_4X as array of floats
+
+ evens_5X = simde_mm256_loadu_pd(a_3X);
+ odds_6X = simde_mm256_loadu_pd(b_4X);
+ avx_7X = simde_mm256_sub_pd(evens_5X, odds_6X);
+ simde_mm256_storeu_pd(a_3X, avx_7X);
+#+END_SRC
+
+* Prescheme
+
+- Writes C beautifully from readable Lisp
+- Prescheme writes C files
+- Even C macros are written without loss
+- Strings and vectors use malloc/free
+- We can use Lisp macros to free on scope exit
+- Currently needs a hack to allow for opaque pointers
+
+* Nim example
+
+#+BEGIN_SRC python
+ var evens = [1.0, 2.1, 3.2, 4.3]
+ var odds = [0.0, 1.1, 2.1, 3.3]
+
+ var regs1 = mm256_loadu_pd(evens[0].addr)
+ var regs2 = mm256_loadu_pd(odds[0].addr)
+ var result = mm256_sub_pd(regs1,regs2)
+ echo cast[array[4, float64]](result)
+#+END_SRC
+
+* Nim transpiled to C
+
+#+BEGIN_SRC C
+ regs1__simd_124 = _mm256_loadu_pd(((void*) ((&l1__simd_122[(((NI) 0))- 0]))));
+ regs2__simd_125 = _mm256_loadu_pd(((void*) ((&l2__simd_123[(((NI) 0))- 0]))));
+ result__simd_126 = _mm256_sub_pd(regs1__simd_124, regs2__simd_125);
+ nimZeroMem((void*)T3_, sizeof(tyArray__nHXaesL0DJZHyVS07ARPRA));
+ LOC4.source = result__simd_126;
+ T3_[0] = dollar___simd_192(LOC4.dest);
+ echoBinSafe(T3_, 1);
+#+END_SRC
+
+* Nim
+
+- Writes C from readable Nim
+- C macros are written without loss
+- Strings and vectors use reference counting
+
+- C files are written to a user cache in $HOME
+- Generated C code has boiler plate, is verbose, and is not really meant for humans
+
+
+* Chicken Scheme transpiler to C
+
+- GC free C transpiler was inspired by recent re-aliving prescheme!
+* TODO Zig transpiler
+
+- Zig can actually generate C
+- `zig build-obj -ofmt=c -lc main.zig`
+- So with bootstrap this is worth looking into
+
+* Conclusion
+
+- prescheme is light, hackable and just generates light-weight C output
+- Amazing mapping to low level
+- Nim is cool too - but more involved and transpiled C is less easy to digest by humans
+- Nim and Chicken have reference counting - prescheme is mapped - and macros can simplify management
+- Think you Andrew Whatson and NLNet!