Expand description
The answer to every object_size the front end left for the IR.
Design: spec/optimizer/20-idioms-and-libcalls.md section 20.2, and spec/13-gnu-compat.md
section 13.5 for the builtin itself.
The checker answers __builtin_object_size where it can see the object by looking at the
expression, and leaves Opcode::ObjectSize behind where it cannot. What is left is an address
read out of a variable, and inside a function that variable is usually one of a handful of
addresses a branch or a loop chose between, as in r = l == 1 ? &a.buf1[5] : &a.buf2[4]. The
IR as the front end writes it has every one of those in front of it: the variable is a block
parameter and each branch to its block passes one address, which is an alloca or a global with
constant offsets on top. This walks that and writes the answer in as a constant.
§When it runs
Before every other pass and at every level, because nothing after the front end is allowed to
see the instruction. The _chk folds in crate::libcall run next and read the answer as the
constant they compare a count against, which is the order gcc’s own object size pass and its
_chk folds run in. At -O0 nothing is walked and every question gets the answer that says
nothing, which is what gcc 16.2.0 gives at that level for an address in a variable.
§What the walk believes
A fixed alloca is its size and a dynamic one of a constant count is that count. A global is
its size where extents::vouched says the definition in the module is the one that
will run. A ptr_add of a constant count takes it off what is left, down to nothing past the
end, and one going backwards is not followed. A block parameter is every argument every branch
to its block passes and a select is both of its arms. Anything else is not known.
The kinds asking for the largest answer take the largest of a choice and the kinds asking for
the smallest take the smallest, and not knowing any part of a choice is not knowing the whole
of it. A loop is the one place that needs thought. A parameter reached again while its own
answer is being worked out is the pointer carried round the loop unchanged or moved forward,
which can only leave less, so for the largest it adds nothing to the choice. Moved backwards it
could leave more, and that is why a backwards ptr_add is never followed. For the smallest the
same holds where the pointer comes round unchanged, and one moved forward each time round may
leave as little as anything, so there the smallest is not known.
The closest member, which is the low bit of the kind, is not something the IR remembers. The whole object is an answer no smaller than the member for the largest, so the first kind’s answer stands for the second. For the smallest it could be too big, so the fourth kind is not known here and only the checker ever answers it.
Functions§
- answer
- Answers every
object_sizein the module and says how many there were.