diff --git a/src/dynarmic/ir/microinstruction.cpp b/src/dynarmic/ir/microinstruction.cpp index 81bfbbaa..cde0ab99 100644 --- a/src/dynarmic/ir/microinstruction.cpp +++ b/src/dynarmic/ir/microinstruction.cpp @@ -583,40 +583,19 @@ bool Inst::AreAllArgsImmediates() const { } bool Inst::HasAssociatedPseudoOperation() const { - return carry_inst - || overflow_inst - || ge_inst - || nzcv_inst - || upper_inst - || lower_inst; + return next_pseudoop && !IsAPseudoOperation(); } Inst* Inst::GetAssociatedPseudoOperation(Opcode opcode) { - // This is faster than doing a search through the block. - switch (opcode) { - case Opcode::GetCarryFromOp: - ASSERT(!carry_inst || carry_inst->GetOpcode() == Opcode::GetCarryFromOp); - return carry_inst; - case Opcode::GetOverflowFromOp: - ASSERT(!overflow_inst || overflow_inst->GetOpcode() == Opcode::GetOverflowFromOp); - return overflow_inst; - case Opcode::GetGEFromOp: - ASSERT(!ge_inst || ge_inst->GetOpcode() == Opcode::GetGEFromOp); - return ge_inst; - case Opcode::GetNZCVFromOp: - ASSERT(!nzcv_inst || nzcv_inst->GetOpcode() == Opcode::GetNZCVFromOp); - return nzcv_inst; - case Opcode::GetUpperFromOp: - ASSERT(!upper_inst || upper_inst->GetOpcode() == Opcode::GetUpperFromOp); - return upper_inst; - case Opcode::GetLowerFromOp: - ASSERT(!lower_inst || lower_inst->GetOpcode() == Opcode::GetLowerFromOp); - return lower_inst; - default: - break; + Inst* pseudoop = next_pseudoop; + while (pseudoop) { + if (pseudoop->GetOpcode() == opcode) { + ASSERT(pseudoop->GetArg(0).GetInst() == this); + return pseudoop; + } + pseudoop = pseudoop->next_pseudoop; } - - ASSERT_FALSE("Not a valid pseudo-operation"); + return nullptr; } Type Inst::GetType() const { @@ -679,67 +658,31 @@ void Inst::ReplaceUsesWith(Value replacement) { void Inst::Use(const Value& value) { value.GetInst()->use_count++; - switch (op) { - case Opcode::GetCarryFromOp: - ASSERT_MSG(!value.GetInst()->carry_inst, "Only one of each type of pseudo-op allowed"); - value.GetInst()->carry_inst = this; - break; - case Opcode::GetOverflowFromOp: - ASSERT_MSG(!value.GetInst()->overflow_inst, "Only one of each type of pseudo-op allowed"); - value.GetInst()->overflow_inst = this; - break; - case Opcode::GetGEFromOp: - ASSERT_MSG(!value.GetInst()->ge_inst, "Only one of each type of pseudo-op allowed"); - value.GetInst()->ge_inst = this; - break; - case Opcode::GetNZCVFromOp: - ASSERT_MSG(!value.GetInst()->nzcv_inst, "Only one of each type of pseudo-op allowed"); - ASSERT_MSG(value.GetInst()->MayGetNZCVFromOp(), "This value doesn't support the GetNZCVFromOp pseduo-op"); - value.GetInst()->nzcv_inst = this; - break; - case Opcode::GetUpperFromOp: - ASSERT_MSG(!value.GetInst()->upper_inst, "Only one of each type of pseudo-op allowed"); - value.GetInst()->upper_inst = this; - break; - case Opcode::GetLowerFromOp: - ASSERT_MSG(!value.GetInst()->lower_inst, "Only one of each type of pseudo-op allowed"); - value.GetInst()->lower_inst = this; - break; - default: - break; + if (IsAPseudoOperation()) { + if (op == Opcode::GetNZCVFromOp) { + ASSERT_MSG(value.GetInst()->MayGetNZCVFromOp(), "This value doesn't support the GetNZCVFromOp pseduo-op"); + } + + Inst* insert_point = value.GetInst(); + while (insert_point->next_pseudoop) { + insert_point = insert_point->next_pseudoop; + DEBUG_ASSERT(insert_point->GetArg(0).GetInst() == this); + } + insert_point->next_pseudoop = this; } } void Inst::UndoUse(const Value& value) { value.GetInst()->use_count--; - switch (op) { - case Opcode::GetCarryFromOp: - ASSERT(value.GetInst()->carry_inst->GetOpcode() == Opcode::GetCarryFromOp); - value.GetInst()->carry_inst = nullptr; - break; - case Opcode::GetOverflowFromOp: - ASSERT(value.GetInst()->overflow_inst->GetOpcode() == Opcode::GetOverflowFromOp); - value.GetInst()->overflow_inst = nullptr; - break; - case Opcode::GetGEFromOp: - ASSERT(value.GetInst()->ge_inst->GetOpcode() == Opcode::GetGEFromOp); - value.GetInst()->ge_inst = nullptr; - break; - case Opcode::GetNZCVFromOp: - ASSERT(value.GetInst()->nzcv_inst->GetOpcode() == Opcode::GetNZCVFromOp); - value.GetInst()->nzcv_inst = nullptr; - break; - case Opcode::GetUpperFromOp: - ASSERT(value.GetInst()->upper_inst->GetOpcode() == Opcode::GetUpperFromOp); - value.GetInst()->upper_inst = nullptr; - break; - case Opcode::GetLowerFromOp: - ASSERT(value.GetInst()->lower_inst->GetOpcode() == Opcode::GetLowerFromOp); - value.GetInst()->lower_inst = nullptr; - break; - default: - break; + if (IsAPseudoOperation()) { + Inst* insert_point = value.GetInst(); + while (insert_point->next_pseudoop != this) { + insert_point = insert_point->next_pseudoop; + DEBUG_ASSERT(insert_point->GetArg(0).GetInst() == this); + } + insert_point->next_pseudoop = next_pseudoop; + next_pseudoop = nullptr; } } diff --git a/src/dynarmic/ir/microinstruction.h b/src/dynarmic/ir/microinstruction.h index a5011b20..7c2d9dc7 100644 --- a/src/dynarmic/ir/microinstruction.h +++ b/src/dynarmic/ir/microinstruction.h @@ -149,18 +149,8 @@ private: size_t use_count = 0; std::array args; - // Pointers to related pseudooperations: - // Since not all combinations are possible, we use a union to save space - union { - Inst* carry_inst = nullptr; - Inst* ge_inst; - Inst* upper_inst; - }; - Inst* overflow_inst = nullptr; - union { - Inst* nzcv_inst = nullptr; - Inst* lower_inst; - }; + // Linked list of pseudooperations associated with this instruction. + Inst* next_pseudoop = nullptr; }; } // namespace Dynarmic::IR