abainbridge
My code gen is definitely worse than TCC! But I think modern CPUs see all my redundant register-register moves and just treat them as a no-ops. Probably performance isn't much worse than TCC. But currently I can hardly compile a program complex enough for a meaningful comparison to be made.
Ooo, no. I already have an AST. When writing the code gen for a node type in the AST, I normally start by typing a few lines of C into godbolt that exercises the same kind of thing represented by the node type. I try a few different compilers and optimization settings and look at what gets generated. I pick an approach that looks simple and good enough. Then I ask an AI to assemble the instructions I see the compilers using. I like to ask an AI to do this because it will explain what all the bits do in the instruction encoding and it is less error prone at reading the ISA docs than I am. The description from the AI might prompt me to ask things like, "what if the jump target doesn't fit in the 32-bit immediate" etc.
All I was claiming was that this is easier than generating code for a byte code of my invention, partly because I don't have to invent a byte code and partly because I can use existing tools to help, eg disassemblers/debuggers to check my output or compilers to give me ideas on how to convert C-like statements into machine code.
I don't have any IR at the moment. I'll have a think about what benefits that might bring.
The reason I posted my project under this top level thread is because I'm interested in Small Programs and Languages. My experiment is in what I can remove from a language implementation to make it simpler. Adding a dependency on LLVM is the opposite of what I had in mind :-)
There are many reasons I'm writing it in C but mainly because I like C.
I feel like the way we write about compiler design could be reduced in complexity too. I read the blog posts by Nora Sandler and they did a great job compared to "the Dragon book" (confusing now because her book has a dragon on the front too). But we still ought to replace phrases like "lexical analysis" with "character grouping" (credit to Sam H Smith for forcing that one into my brain).
This is an area I want to explore. It seems to me that it is less true than it used to be. Nowadays all desktop or server class CPUs support 8, 16, 32 and 64-bit integers. And they all have at least 10 general purpose registers. As a result, the same code generator works for them all. As it stands, my code generator calls functions like emit_indexed_load, emit_conditional_jump etc. There are currently 26 of those functions.
So far I have only implemented them for x86_64 machine code output. But writing versions that output ARM64 or risvc doesn't seem hard. I expect I'll find small problems which will cause me to have to tweak the set of CPU features my code gen depends on.
As for generating bytecode being easier than x86_64 machine code, I disagree. There are lots of tools for validating x86_64 machine code (ie disassemblers). There aren't any for a bytecode I might invent. And I can ask an AI how to generate x86_64 machine code to do an indexed load. I immediately get the answer. I don't have to think about how to make an efficient bytecode encoding.
And the original TCC code is not easy to understand. It is a lot cleverer than I can cope with!
1: Design a bytecode. 2: Write a compiler. 3: Write an interpreter.
It seems like it would be simpler to not bother with 1 and 3 and instead use machine code as the bytecode. A side benefit is that programs will run faster.
I think it is easy to generate machine code for x86_64, ARM64 and risvc64, as long as you don't mind it being 3x larger and slower than an optimizing compiler would generate. It ought to be easy because it is possible to only target the common subset of features these architectures support.
I made a start, https://github.com/abainbridge/mortar, but haven't got much past being able to compile and run a Fibonacci sequence generator. I have no experience with language design or compiler implementation. I was somewhat gobsmacked when the fib generator ran 380x faster than an almost identical looking Python program.
Any comments or suggestions, including, "that's a bad idea, you will fail because of XYZ", or, "save yourself the effort, here's one I wrote earlier..."?
Has 7 sizes ranging from 6x10 pixels to 16x30. The larger ones are a bit rubbish. Only covers Latin-1.
I know I'm a bit weird, but the internet is full of weird people. It seems strange to me that nobody is interested in bitmap fonts these days.
What I really want is a hand anti-aliased bitmap font which prioritizes sharpness.
I mention this because in the 1990s, while at uni in St Andrews, Scotland, I remember a trip to the astronomy observatory one evening. There was a peculiar cloud overhead - whitish purple, tube shaped and shimmering. I asked the astro professor what it was. He said, "Its a cloud" and showed no further interest. I took a photo. When I got the film developed and photos printed, you could see bright colours either side of the tube. I've always wondered a) what it was and b) why that astronomy professor was an astronomy professor when he had no interest in what the universe had to reveal to him.
I now believe it to have been a STEVE. I've still got no insight into the mind of the astro professor.
Nowadays, I expect optimizations that minimize energy consumption are an important target for LLM hosts.
I think that era of CPUs used a single circuit capable of doing add, sub, xor etc. They'd have 8 of them and the signals propagate through them in a row. I think this page explains the situation on the 6502: https://c74project.com/card-b-alu-cu/
And this one for the ARM 1: https://daveshacks.blogspot.com/2015/12/inside-alu-of-armv1-...
But I'm a software engineer speculating about how hardware works. You might want to ask a hardware engineer instead.
OK, this is the main thing. Going from C to assembly is not deterministic in a sense because different compilers can produce different output. But the behaviour of the generated assembly is always the same. This isn't true of a spec.
This perfectly explains the feeling I had when, 20 years into my career, I had to start writing specs. I could never quite put my finger on why it was harder than coding. My greater familiarity with coding didn't seem a sufficient explanation.
When writing a line of spec, I had to consider how it might be interpreted in the context of different implementations of other lines of spec - combinatorial nightmare.
But code is just a spec as far as, say, a C compiler is concerned. The compiler is free to implement the assembly however it likes. Writing that spec is definitely easier than writing the assembly (Fred Brookes said this, so it must be true).
So why the difference?
I tried asking Gemini and ChatGPT, "What opcode has the value 0x3c on the Intel 8048?"
They were both wrong. The datasheet with the correct encodings is easily found online. And there are several correct open source emulators, eg MAME.
Does this mean that if generation was free, and there were no green policy costs, our electric would still be expensive?
edit: "Network and Distribution" appears to contribute about 23% of the retail price. I guess green energy increased that cost because wind/solar are more spread out and sometimes off-shore.
Or have I missed something?
FTA: "So to summarize the state of the art in oral peptide delivery: there are exactly two FDA-approved products that use permeation enhancers to get peptides into your bloodstream through your GI tract. Both achieve sub-1% bioavailability. Both required over a decade of development, thousands of clinical trial participants, and hundreds of millions of dollars."