This allows the RA Validation pass to verify that a spill slot contains
the correct SSA.
I was originally planning to do a IR equlivent test between the IR
before and after register allocation, mostly to catch this type of error.
But this approach was much faster to implement and gives 90%
of the benefits.
There were two issues:
1. The OrderedNode *After overload created the wrong iterator
2. Despite being named After, they were actually inclusive
Kept ReplaceAllUsesWithRange with the current inclusive behaviour and
adjusted the argument name to match
This can prove that the ssa in the Spill slots are consistant based on
control flow.
It's one major blind spot is that it can't prove the spill slot actually
contains the correct ssa, if it has the same wrong ssa on every cfg
path.
This is a validation pass that attempts to prove the output from the RA pass is valid.
The current design should be able to prove that the RA result is internally
consistent. That no-matter what control flow path you take thought the control
flow graph, the physical registers and spill slots will always contain a single
possible SSA value.
It also checks that the SSA values in the IR actually line up with the SSA value
in the physical register.
This isn't quite a 100% clean sweep of IWYU.
There are some false positives where clang fails.
Additionally there are still a few missed in the frontend side of things
that I didn't get to
ConstProp has an assumption that a VMOV of the same size arguments is a no-op.
This isn't quite 100% true as this could be behaving as a zext and the pass can't see through the op correctly.
Something to be said that the vector ops should be looked over to see which op is leaving dirty bits in the upper bits
of the register. But that's a battle for a different time
There is an assumption in the RCLSE pass that if a StoreContext + LoadContext pair of the same size
with a vector register that it is safe to remove the LoadContext.
This isn't quite safe since it can't entirely see through the IR to determine if the store op
had already zext the upper bits of the register.
This was causing 8byte loadcontext operations to "load" with garbage data in the upper
bits when it was expecting a zext.
Which granted it is likely a bug that not all vector ops zero their upper bits but that's a battle for a different day.
Additionally:
- Removes a couple dead optimizations in the GPR path that was never hit.
- Cleans up how access types are checked
- Uses ReplaceAllUsesWithRange to reinforce that this is purely a per block optimization still
Prior to the introduction of fmt, there wasn't a nice and easy way to
format std::string_view, but now that we have it in place, we can modify
relevant log calls to make use of it and get rid of the need to
construct a string around the view.
While we're in the same area, we can make the rest of the modified file
use fmt where appropriate.
No warnings are ever appended to the warning string stream, and
HadWarning is never set to anything other than false, so we can remove
it to bring it in line with the PhiValidation pass.
1) We needed to switch it to the FEXCore allocator so it didn't live in 32-bit space
2) This generates holes in the VA space due to how the allocations line up.
This makes us almost immediate hit the 65k VMA region.
Switching over to jemalloc allocations means we don't hit that.
Not worth creating an mmap based allocator that can work around that.
This cuts start up time from 8.962ms to 3.949ms and lets us use less physical memory.
We pay a small amortized cost from the faulting to populate pages which will be fairly low
Passing in the string directly through the format string input can
unintentionally cause the output string to be interpreted as a format
string.
We can specify a separate format string to ensure it always prints
without any potential mangling.
<iostream> injects a static constructor in translation units that
include it, even if its facilities aren't used.
We can make use of <sstream> to avoid needing to execute those on
startup.
No specializations modify this, and even if they did, it would be a
little confusing to statefully modify the string this way.
Instead, we can make it read-only.
When floats and doubles were converting to integers we weren't doing the correct transformation.
AArch64 provides direct ops for all four of the op types. So lets use them
- f32 -> int64
- f32 -> int32
- f64 -> int64
- f64 -> int32
Doesn't fully fix the case of overflow for AArch64 since overflow behaviour is different.
x86 returns 0x8000'0000 or 0x8000'0000'0000'0000 while AArch64 saturates to the maximum signed
integers. Can't work around that without checking overflow flags.
This does solve the typical case though.
Fixes audio problems in all FMod games.
e.g. LineDefinitions are moderately beefy, they contain
two strings and a vector of strings among other things,
so we can move instances into their containing vector to avoid some
allocation churn.