Since we store pointers and have an interface for iterators
set up, the count is just the distance from the beginning
to the end of the list.
Nice thing is that because of this, basic blocks also get
the ability to have a size count without needing to do anything
directly.
Small helpers for inserting nodes before and after an existing one.
insert() is the same as insert_before(), so insert() is just made
to be an alias of this.
Whenever more rigorous optimizations are attempted (or even basic ones),
it's usually helpful to know what overall kind of instruction is being
dealt with, in the event certain classes of instructions may be eligible
for optimization.
Moves functions out of the main CMakeLists file into module files that
can just be included whenever necessary. This also uses the CMake
provided variables for enforcing compiler requirements.
In the case when RD === RN, RD was updated before AddOverflow was called
to check for an overflow, resulting in an incorrect state of the Q flag.
This is reapplying a patch from f12578b9ab
that was lost during the 20e253ece2 update
Currently basic block kind of acts like a 'dumb struct' which makes things
a little more verbose to write (as opposed to keeping it all in one place,
I guess). It's also a little wonky conceptually, considering a block is
composed of instructions (i.e. 'contains' them).
So providing accessors that make it act more like a container can make working
with algorithms a little nicer. It also makes the API a little more
defined.
Ideally, the list would be only available through a function, but
currently, the pool allocator is exposed, which seems somewhat odd,
considering the block itself should manage its overall allocations
(with placement new, and regular new), rather than putting that
sanitizing directly on the IR emitter (it should just care about emission,
not block state). However, recontaining that can be followed up with,
as it's very trivial to do.
Makes the name match the standard library equivalents.
C++17 introduces non-member empty() which allows for nicer handling
in generic contexts. May as well make the data structure compatible with
it.
This necessated handling literal versions of the instructions separately
as they had different requirements. The rationale for detecting
unpredictable instructions is because:
a. they are unlikely to be outputted by a well-behaved compiler
b. their behaviour may change between different processors
I would rather unpredictable instructions fail loudly than silently do
approximately the right thing.
The only valid objects to add to the list are those that inherit from
IntrusiveListNode. Therefore anything being added to the list that isn't
inheriting from it will cause compilation to fail.
This generalizes the regular iterator to be compatible with both use
cases. Passing in the list instance directly isn't needed, because the
only way you'd ever get a valid instantiation of an iterator is from a
list instance itself.