In a syscall microbench this improves performance by ~19% on my
Snapdragon 888.
Going from ~9.6 million syscalls per second to ~11.5 million.
Macbook Pro is less effective here due to high syscall overhead due to
VM. Going form 7.2M/s to 7.6M/s, ~6% improvement
We can also inline some 32-bit syscalls but that will need some more
work which isn't done yet. Even though the op in the JIT supports it.
There's zero need for these to have an independent size field and it was
just confusing.
For stores it was always set to zero and for loads it was just
duplicated.
In addition this allows introspection of the store op without casting
the op, which can be useful in edge cases
This is a pretty straightforward operation that can be nicely modeled
by the BIC instruction on ARMv8, which is nice since we can get rid of
the need to manually perform the And and Not operations.
Previously the offset mismatch error was expecting two arguments, but
only one was provided.
While we're in the area we can convert the logging type over to the
fmt-capable one which can catch these.
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.