OpcodeDispatcher: drop remnants of deferred flags

Signed-off-by: Alyssa Rosenzweig <alyssa@rosenzweig.io>
This commit is contained in:
Alyssa Rosenzweig committed 2024-07-05 17:22:41 -04:00
1 parent 395573720d
commit adc709db2f
3 files changed
+4 -124

No files matched your search

@@ -4002,8 +4002,6 @@ void OpDispatchBuilder::BeginFunction(uint64_t RIP, const fextl::vector<FEXCore:
auto Block = GetNewJumpBlock(RIP);
SetCurrentCodeBlock(Block);
IRHeader.first->Blocks = Block->Wrapped(DualListData.ListBegin());
LOGMAN_THROW_A_FMT(IsDeferredFlagsStored(), "Something failed to calculate flags and now we began with invalid state");
}
void OpDispatchBuilder::Finalize() {
@@ -87,10 +87,6 @@ class OpDispatchBuilder final : public IREmitter {
friend class FEXCore::IR::PassManager;
public:
enum class FlagsGenerationType : uint8_t {
TYPE_NONE,
};
Ref GetNewJumpBlock(uint64_t RIP) {
auto it = JumpTargets.find(RIP);
LOGMAN_THROW_A_FMT(it != JumpTargets.end(), "Couldn't find block generated for 0x{:x}", RIP);
@@ -196,10 +192,6 @@ public:
}
}
if (LastOp) {
LOGMAN_THROW_A_FMT(IsDeferredFlagsStored(), "FinishOp: Deferred flags weren't generated at end of block");
}
BlockSetRIP = false;
return false;
@@ -1992,98 +1984,18 @@ private:
Ref SelectCC(uint8_t OP, IR::OpSize ResultSize, Ref TrueValue, Ref FalseValue);
/**
* @name Deferred RFLAG calculation and generation.
*
* Only handles the six flags that ALU ops typically generate.
* Specifically: CF, PF, AF, ZF, SF, OF
* These six flags are heavily generated through basic ALU ops and balloon the IR if not early eliminated.
* This tracking structure only tracks single blocks and requires RFLAGS calculation at block-ending ops.
* Some flags generating ALU ops only touch part of the registers, In these cases it will do calculation up front.
* This means we still need our IR passes to eliminate all redundant flags accesses but this light OpcodeDispatcher optimization
* doesn't take it to that level.
* @{ */
// Deferred flag generation tracking structure.
// This structure is used to track RFlags from ALU ops for invalidation.
//
// Future ideas: Use an invalidation mask to do partial generation of flags.
// Particularly for the instructions that don't do the full set of flags calculations.
// These instructions currently calculate the deferred RFLAGS immediately then overwrite rflags state.
// RCLSE IR pass will catch and remove redundant rflags stores like this currently.
struct DeferredFlagData {
// What type of flags to generate
FlagsGenerationType Type {FlagsGenerationType::TYPE_NONE};
// Source size of the op
uint8_t SrcSize;
// Every flag generation type has a result
Ref Res {};
union {
// UMUL, BEXTR, BLSI, POPCOUNT, ZCNT, RDRAND
struct {
} NoSource;
// MUL, BLSR, BLSMSKB, BZHI
struct {
Ref Src1;
} OneSource;
// Logical
struct {
Ref Src1;
Ref Src2;
} TwoSource;
// LSHLI, LSHRI, ASHRI
struct {
Ref Src1;
uint64_t Imm;
} OneSrcImmediate;
// ADD, SUB
struct {
Ref Src1;
Ref Src2;
bool UpdateCF;
} TwoSrcImmediate;
} Sources {};
};
DeferredFlagData CurrentDeferredFlags {};
/**
* @brief Takes the current deferred flag state and stores the result in to RFLAGS.
*
* Once executed there will no longer be any deferred flag state and RFLAGS will have the correct flags in it.
* Necessary to do when leaving a IR block, or if an instruction is doing a partial overwrite of the flags.
* @brief Flushes NZCV. Mostly vestigial.
*/
void CalculateDeferredFlags(uint32_t FlagsToCalculateMask = ~0U);
void CalculateDeferredFlags();
/**
* @brief Invalidates the current deferred flags structure.
*
* If the emulated instruction is going to overwrite all of the flags but isn't tracked using the deferred flag system
* then use this function to stop tracking the current active deferred flags.
* @brief Invalidates NZCV. Mostly vestigial.
*/
void InvalidateDeferredFlags() {
CurrentDeferredFlags.Type = FlagsGenerationType::TYPE_NONE;
// No NZCV bits will be set, they are all invalid.
PossiblySetNZCVBits = 0;
}
/**
* @brief Checks if there is any deferred flag state active.
*
* @return True if RFLAGs contains the flags. False if deferred flags is tracking the data.
*/
bool IsDeferredFlagsStored() const {
return CurrentDeferredFlags.Type == FlagsGenerationType::TYPE_NONE;
}
void ZeroShiftResult(FEXCore::X86Tables::DecodedOp Op) {
// In the case of zero-rotate, we need to store the destination still to deal with 32-bit semantics.
const uint32_t Size = GetSrcSize(Op);
@@ -2275,14 +2187,3 @@ private:
void InstallOpcodeHandlers(Context::OperatingMode Mode);
} // namespace FEXCore::IR
template<>
struct fmt::formatter<FEXCore::IR::OpDispatchBuilder::FlagsGenerationType> : fmt::formatter<int> {
using Base = fmt::formatter<int>;
// Pass-through the underlying value, so IDs can
// be formatted like any integral value.
template<typename FormatContext>
auto format(const FEXCore::IR::OpDispatchBuilder::FlagsGenerationType& ID, FormatContext& ctx) {
return Base::format(static_cast<int>(ID), ctx);
}
};
@@ -258,26 +258,7 @@ void OpDispatchBuilder::CalculateAF(Ref Src1, Ref Src2) {
SetRFLAG<FEXCore::X86State::RFLAG_AF_RAW_LOC>(XorRes);
}
void OpDispatchBuilder::CalculateDeferredFlags(uint32_t FlagsToCalculateMask) {
if (CurrentDeferredFlags.Type == FlagsGenerationType::TYPE_NONE) {
// Nothing to do
if (NZCVDirty && CachedNZCV) {
_StoreNZCV(CachedNZCV);
}
CachedNZCV = nullptr;
NZCVDirty = false;
return;
}
switch (CurrentDeferredFlags.Type) {
case FlagsGenerationType::TYPE_NONE:
default: ERROR_AND_DIE_FMT("Unhandled flags type {}", CurrentDeferredFlags.Type);
}
// Done calculating
CurrentDeferredFlags.Type = FlagsGenerationType::TYPE_NONE;
void OpDispatchBuilder::CalculateDeferredFlags() {
if (NZCVDirty && CachedNZCV) {
_StoreNZCV(CachedNZCV);
}