I know you can create a structure/typedef in QBE quite easily, where
```elle
struct Foo {
int a;
string b;
double c;
};
```
maps almost exactly to
```qbe
type :Foo = { w, l, d }
```
My questions are as follows:
- Is there an easy way to get the size of the structure without needing
to keep track of it in the language frontend?
- Is there a GEP (getelementptr) equivalent, or is that in the missing
30%? (I couldn't find anything similar to GEP in the documentation so I
would assume no)
- Is the copy instruction restricted to return first-class IL citizens only?
(For example:
```qbe
export function w $main() {
@start
%foo.addr =:Foo call $getFoo()
%foo.copy =:Foo copy %foo.addr
%foo.a =w loadw %foo.copy
call $printf(l $test, ..., w %foo.a)
ret 0
}
```
would exit with "invalid type for first operand %foo.copy in loadsw",
however
```qbe
export function w $main() {
@start
%foo.addr =:Foo call $getFoo()
%foo.copy =l copy %foo.addr
%foo.a =w loadw %foo.copy
call $printf(l $test, ..., w %foo.a)
ret 0
}
```
works fine)
Thanks!
Nevermind, this snippet:
```qbe
export function w $main() {
@start
%foo.addr =:Foo call $getFoo()
%foo.copy =:Foo copy %foo.addr
%foo.a =w loadw %foo.copy
call $printf(l $test, ..., w %foo.a)
ret 0
}
```
actually exits with "size class must be w, l, s, or d". It wasn't in my
original message because I modified the QBE source to skip that check.
This leads me to believe that yes, the copy instruction is restricted to
first-class IL citizens only. However that doesn't really make sense
because %foo.addr isn't really :Foo its only a pointer to the start of
:Foo, so the size class should just be `long`, surely.
Quoth Rosie <acquitefx@gmail.com>:
> Nevermind, this snippet:> ```qbe> export function w $main() {> @start> %foo.addr =:Foo call $getFoo()> %foo.copy =:Foo copy %foo.addr> > %foo.a =w loadw %foo.copy> > call $printf(l $test, ..., w %foo.a)> ret 0> }> ```> actually exits with "size class must be w, l, s, or d". It wasn't in my > original message because I modified the QBE source to skip that check.> > This leads me to believe that yes, the copy instruction is restricted to > first-class IL citizens only. However that doesn't really make sense > because %foo.addr isn't really :Foo its only a pointer to the start of > :Foo, so the size class should just be `long`, surely.>
Struct definitions are almost exclusively there for ABI purposes.
You're meant to compute offsets and generate loads and stores.
For example:
struct foo {
int a;
int b;
};
int f(struct foo *a) { return a->b; }
might compile to:
export function w $f(l %.1) {
%.2 =l add %.1, 4
%.3 =w loadw %.2
ret %.3
}
That makes sense I suppose, considering GEP essentially just does load
and store instructions internally, thank you!
One thing I'm still confused about though, is why this:
```qbe
%foo.addr =:Foo call $getFoo()
%foo.copy =:Foo copy %foo.addr
```
throws an exception, but this:
```qbe
%foo.addr =:Foo call $getFoo()
%foo.copy =l copy %foo.addr
```
doesn't, and continues execution normally.
On Thu, Aug 1, 2024, at 17:45, Rosie wrote:
> One thing I'm still confused about though, is why this:>> ```qbe> %foo.addr =:Foo call $getFoo()> %foo.copy =:Foo copy %foo.addr> ```>> throws an exception, but this:>> ```qbe> %foo.addr =:Foo call $getFoo()> %foo.copy =l copy %foo.addr> ```
Calls are the only instructions that may have an
aggregate type for their output. As per the doc,
it is to be understood as a pointer (l) and not
a struct value (which do not exist in qbe IL).
For ABI purposes, calls need to know what is the
precise aggregate type that the called function
returns, this is why you must provide structural
information on the result. All other instructions
must just deal with scalars and pointers.