<geri>
most options involve tons of overhead by allocating closures
<geri>
or wrapping a lot of stuff in first class functions
<abu[7]>
yeah
<geri>
that's why im not really looking into tco for my interpreter currently, cause its supposed to be a pure interpreter xd
<geri>
i love that in compilers you get to write the language in itself and it can be very efficient
<geri>
llvm-ir is a good middle ground, but its not exactly the same language
<abu[7]>
the same as what?
<abu[7]>
ah
<abu[7]>
itself
<geri>
yes
<geri>
pilsrc vs pil
<abu[7]>
T
<abu[7]>
It needs different semantics
<abu[7]>
operates on different data structures
<geri>
i mean, dont most compilers operate on ast?
<geri>
and lisp is pretty much pure ast
<abu[7]>
Yes Syntax
<abu[7]>
the thing is semantics
<abu[7]>
Lisp can't manipulate the stack for example
<abu[7]>
PilSrc maps to a CPU
<abu[7]>
not syms and cells
<abu[7]>
The syms and cells are the product
<geri>
:(
<geri>
no stack for us
<abu[7]>
On the semantic level, PilSrc is C and not Lisp
<abu[7]>
Only syntax is Lisp
<geri>
do you gain much from going to llvm instead of just writing C?
<abu[7]>
yes
<abu[7]>
stack manipulation
<abu[7]>
and CPU flags
<abu[7]>
(mainly carry flag)
<geri>
okay
<abu[7]>
L)
<geri>
afaik llvm is incredibly complex though
<geri>
probably worth it in some cases, maybe not in other
<abu[7]>
Yes, but I don't use it. Only llvm-ir
<abu[7]>
llvm-ir is a generalized assembler
<abu[7]>
so more powerful than C
<geri>
so you get assembly with at least somewhat familiar interface and its portable
<abu[7]>
yeah
<geri>
are cons cells on the stack only possible cause of llvm?
<geri>
like new cells i guess
<abu[7]>
No, in C you can have them too
<abu[7]>
cell structs
<geri>
hmmmmm
<abu[7]>
But in C you cannot decrement the stack pointer in a loop, or create and jump between stack segments (needed for coroutines)
<geri>
:(
<abu[7]>
llvm~stack can get the current hardware stack pointer, and it can also set it to another value
<geri>
you can probably do it with some inline assembly
<geri>
but again, rip portability
<abu[7]>
Yes, assembly
<abu[7]>
Thats why the first versions of pil were asm, then C, then asm again and then llvm~ir
<abu[7]>
AFAIK only Forth gives you such full control over the stack
<abu[7]>
(RP here)
<geri>
rp?
<geri>
return stack pointer?
<abu[7]>
yep
<geri>
yeah, manual tco :D
<abu[7]>
SP and RP in Forth
<geri>
i doubt you can write an amazingly fast lisp interpreter in forth though
<geri>
😔
<abu[7]>
probably not, frequent stack operations are expensive
<abu[7]>
as opposed to registers
<geri>
yeah..
<abu[7]>
A hardware Forth CPU would be the best
<geri>
think itd be comparable to x86 performance?
<abu[7]>
At least a bit closer, if the stacks are in very fast internal memory (like the registers of a normal CPU)
<abu[7]>
Execution may be slower, but the code be more compact, giving better cache efficiency
<geri>
oh that's fun
<geri>
ik some of the better forths use cache for a few of the top stack items
<geri>
sorry, registers*
<geri>
thats why treating the stack as an array is not recommended
<abu[7]>
But this keepinp TOS and some more entries in register has other overhead
<geri>
can't you just allocate a chunk of memory for the stack and "stack-allocate" in there?
<geri>
cause memory is already allocated it should be fast
<geri>
or stack manipulation is more about what usually happens behind the scenes in C
<abu[7]>
Yes, you can do such tricks (in fact I had coroutines in lifo (in C)), but this always implies assumptions which are not guaranteed because C hat no concept of the stack in the language)
<geri>
do you have examples of those assumptions?
<abu[7]>
We have a model of a large array on the stack, but the compiler may optimize it away
<abu[7]>
model in our mind I mean
<geri>
i bet thats part of the reason the phrase "no compiler to mess with your code, you get what you see" has been said in regards to picolisp :D
<abu[7]>
We allocate a big struct, but *mean* "please decrement the stack"
<abu[7]>
Exactly :)
<geri>
what's faster, (quote X) or a symbol constant, like T?
<geri>
:)
<geri>
to defer
<geri>
deref*
<abu[7]>
A symbol value
<abu[7]>
inline 'eval'
<geri>
aha
<geri>
and if there wouldn't be inline eval?
<abu[7]>
a single machine instruction for a symbol, but a complex function call for 'quote'
<abu[7]>
Also
<geri>
okay fair
<abu[7]>
but one more call
<geri>
one more call for quote?
<abu[7]>
T
<abu[7]>
eval as function and then quote
<geri>
ah yeah
ygrek has joined #picolisp
<abu[7]>
So the inline eval handles num and sym directly
<abu[7]>
test and jump
<geri>
"directly" like removing 1 function call?
<geri>
eval is used a lot so probably more than worth it