We can move the op into the implementing function and get rid of
an unnecessary function.
We can also add an assert to ensure the predicates are valid as well.
insert() will only ever perform an insertion if the relevant element
doesn't exist within the set, so we were doing an unnecessary lookup
in two spots.
We don't use emplace() here because it will need to construct the
key for the element inside the allocated node (since the key may
be non-copyable/non-movable), causing an allocation even if an insert
doesn't actually occur.
Conversely, insert() will not need to allocate and construct a node
ahead of time if an element already exists in the set.
Inspired from: https://github.com/dotnet/runtime/issues/8072
Currently FEX is /very/ heavy handed with our backpatching where we wrap
every backpatched loadstore with `dmb ish`.
This can be relaxed slightly according to the linked issue.
For TSO load instructions the instruction sequence changes to:
ldr <args>;
dmb ld; <-- Slightly less strict dmb
For TSO store instructions the instruction sequence changes to:
dmb ish; <-- Still the all encompassing dmb
str <args>;
For backpatching loadstores this does the same thing where only one side
needs the nop and it uses the same instruction sequence when
backpatched.
The minor change is that on load backpatching, we are no longer backing
up a single instruction, instead just re-executing the instruction we
patched directly.
Took a long time to come back to this (Last looked in August 2020).
Previously when I was implementing this idea it didn't work, but that
was because our CompareExchange operation was broken back then. With the
CAS now, it should just work.
We expect that PF is written more often than it's read, so we want to
get the expensive popcount out of the hot path. (Thank you to Dougall
for suggesting that.)
There are two cases:
1. PF is written by an integer instruction. In this case, we calculate
with the formula `popcount(x ^ 1) & 1`.
2. PF is written by a float instruction, copying a host flag.
What we really want is to defer the relatively expensive popcount. So,
to unify these cases, we have integer instructions write `x ^ 1` and
(unchanged) float instructions write the host flag. Then, when reading
PF, we do `popcount(value) & 1` on the byte read in.
If PF is written but not read, this saves the expensive popcount and
leaves only the cheap xor.
If PF is written by an integer op and read, this maybe shuffles some
code but does not materially change anything.
If PF is written by a float op and read, this is worse because now we're
doing an extra pointless popcount. This is a tradeoff... However, this
is only relevant to unordered float comparisons, which I expect to be
obscure for games. So this should be worth it over all (for games, if
not weird numerical computing workloads).
How does this connect to my register zeroing quest? The constant folding
code doesn't currently deal with FPRs and I'm not in a mood to change
this. So before, a block ending with `xor eax, eax` would still do a
popcount for PF. Now it just writes a constant 1 since the xor constant
folds and the popcount never happens at all.
Signed-off-by: Alyssa Rosenzweig <alyssa@rosenzweig.io>
Lets us deduplicate the asserts and put them in one spot. We can also
improve the assert message to also indicate the valid range.
While we're in the area, we can collapse a few case paths
as a result of this assert movement.
For #2804 so it can compare if GPRs match more easily.
Only adding to GPR and Literal types, since its ambiguous what this
would mean for the memory accessing types. Going to leave those other
ones alone for now.
Now that we have the helper for encoding immediate shifts,
we can trivially implement the remaining missing instruction
in the bitwise logical unpredicated group.
Prevents the code invalidation mutex from being locked as shared recursively,
since it is locked before entering ThreadExitFunctionLink and would end up
being locked again by ThreadAddBlockLink.
This fixes a deadlock on Windows.