Hi qbe'rs,
I'm guessing someone might have already done something similar, but I
didn't find it. So I started on a packaging of QBE into a library,
details here: https://github.com/sgraham/libqbe.
In all honesty, it's more awkward than just using text input, but I
think it will be helpful for my pet project front-end, so maybe
someone else will find it useful.
Scott
Thank you for that!
I was going down the same path (and adding meson as build system to
integrate it in my other projects).
Nice to see half of the problem has been solved already :D.
On Sat, Jan 18, 2025 at 3:25 PM Scott Graham <sgraham@gmail.com> wrote:
> Hi qbe'rs,
Hey Scott
> https://github.com/sgraham/libqbe.
Firstly, nice! I took a very brief look, and as far as I can tell the
QBE IL generation approach is to essentially externalise various
parser.c facilities, which seems clever.
> In all honesty, it's more awkward than just using text input, but I> think it will be helpful for my pet project front-end, so maybe> someone else will find it useful.
I think a QBE library is a frequent ask -
https://lists.sr.ht/~mpu/qbe/%3CYgHOXpjABvAaMvMt@debussy%3E.
FWIW some previous (private) thoughts:
---
Off the top of my head the main thing I would be concerned about is
(re-)initialisation of global state on every library invocation. I
don't have a specific example right now, but my intuition is that
there is code in QBE that assumes things like static variables are
zero-initialised - as they are for a new process. Things like the
memory allocators would be the first place I'd look for possible
SNAFU's, and then of course global static variables in sundry QBE
source files.
Or more concretely, QBE definitely makes use of global static
variables in various places - i.e. the assumption of single-usage and
single-threaded-usage is quite deeply baked into the code.
In terms of the interface, the obvious first place to start is to
simply turn the current cmd-line args into a struct, and expose a
single entry function - which QBE standalone process main() would call
after morphing its cmd-line params into the formal struct form. I
think a more fine-grained API would be much trickier semantically.
---
You seem to have neatly solved the "tricker semantically" part by just
re-using the parser process.
Threading support thoughts, also from previous (private) comms:
---
The "re-usable" and "multi-thread" issues are independent, I think.
Multi-thread support is literally as easy as tagging every
(non-constant) global/static variable with C11+ _Thread_local. [Unless
I'm being a complete idiot?] And I do think there is an expectation of
libraries to support threads since threads are so ubiquitous in even
low-level languages. Let me know if you are planning to play with this
yourself - otherwise I might fiddle a bit myself [I did not].
Then (same-thread) re-usable is really just an auditing task... clean
up all state after an invocation.
Of course this assumes our simple single top-level API pseudo-main
"qbe_run(...)" approach.
---
Happy hacking
R
On Sat, Jan 18, 2025 at 6:01 AM Roland Paterson-Jones
<rolandpj@gmail.com> wrote:
> > https://github.com/sgraham/libqbe.>> Firstly, nice! I took a very brief look, and as far as I can tell the> QBE IL generation approach is to essentially externalise various> parser.c facilities, which seems clever.
Yeah, it seemed like the lowest impact way. Some more thoughts on your
other ideas below.
>> You seem to have neatly solved the "tricker semantically" part by just> re-using the parser process.
This mostly seems to work well, but does tie the usage of the API to a
similar usage pattern as a parsed file. In particular right now, it's
not possible to define two functions at the same time (because that
wouldn't make sense in a text qbe file). I didn't think that was too
big of a limitation though.
A limitation that is a little more annoying is that you also can't
define a global data item at the same time as a function is being
defined. It would be nice to (e.g.) emit a string while compiling the
body of a function, but right now the callbacks into main.c call
`freeall()` which flushes the heap allocations for the current top
level item. This one would would be pretty easy to fix I think, but I
haven't done it yet (https://github.com/sgraham/libqbe/issues/13).
> Multi-thread support is literally as easy as tagging every> (non-constant) global/static variable with C11+ _Thread_local. [Unless> I'm being a complete idiot?] And I do think there is an expectation of> libraries to support threads since threads are so ubiquitous in even> low-level languages. Let me know if you are planning to play with this> yourself - otherwise I might fiddle a bit myself [I did not].
That sounds plausible, there's a bunch of global state of course, but
I don't think there's any reason it couldn't be isolated to TLS. I was
planning to eventually bundle all the state up in a single struct that
could then be memset on re-initialization (or in error conditions, or
as you suggest, to make it thread local), but I also haven't done that
yet. I don't think I'll personally need multi-threaded generation, so
I'm not sure that I'll tackle that part of the idea.
After my initial burst of enthusiasm, I lost some motivation when I
realized that the amd64_win backend needs quite some work.
I had hoped that the winabi branch was close to functional, but it's
mostly just a copy of the sysv code, and doesn't do shadow stack
space, or fp register assignment in calls, and I suspect won't handle
structs by value (though I didn't get that far yet). If anyone is
motivated about that, I started a very basic random test generator
here https://github.com/sgraham/libqbe/blob/trunk/ccfuzz.py . (I think
only single parameter functions of basic types work, but I couldn't
really decipher how various places use `T.argregs()` yet.)
Scott
In light of the discussion here, would there be an interest in patches making QBE
use less global static variables, thus making it more amenable to use as a library?
I could work on some.
On Sat, Jan 25, 2025, at 20:00, Maroš Grego wrote:
> In light of the discussion here, would there be an interest in patches > making QBE> use less global static variables, thus making it more amenable to use > as a library?
Sigh, I'll miss the readability. Maybe using
context objects?
Or... what about thread-local storage?
On Sun, Jan 26, 2025 at 1:07 AM Quentin Carbonneaux <quentin@c9x.me> wrote:
>> On Sat, Jan 25, 2025, at 20:00, Maroš Grego wrote:> > In light of the discussion here, would there be an interest in patches> > making QBE> > use less global static variables, thus making it more amenable to use> > as a library?>> Sigh, I'll miss the readability. Maybe using> context objects?
Lol, your baby is out there now and everyone wants to play with it :P
Yes, as Scott mentioned before, context encapsulation is really what
you want from a lib interface.
> Or... what about thread-local storage?
I don't think any of this should necessarily be awful from a code
aesthetics perspective.
So Maros (sorry don't know how to get the 's' accent on my keyboard),
please take a stab at it.
R
On Sun, Jan 26, 2025 at 7:36 AM Roland Paterson-Jones
<rolandpj@gmail.com> wrote:
>> On Sun, Jan 26, 2025 at 1:07 AM Quentin Carbonneaux <quentin@c9x.me> wrote:> >> > On Sat, Jan 25, 2025, at 20:00, Maroš Grego wrote:> > > In light of the discussion here, would there be an interest in patches> > > making QBE> > > use less global static variables, thus making it more amenable to use> > > as a library?> >> > Sigh, I'll miss the readability. Maybe using> > context objects?>> Lol, your baby is out there now and everyone wants to play with it :P>> Yes, as Scott mentioned before, context encapsulation is really what> you want from a lib interface.
FWIW, I didn't really find the "preprocessing" approach too
bothersome. As long as the code style stays consistent it's relatively
straightforward. So if it makes the code less pleasant to work on, I
don't think it's necessary.
I guess the decision is whether the "library" part should live
"upstream" or "downstream" of the main tool. /shruggie
scott