microinstruction: Optimize storage of associated pseudooperation

This commit is contained in:
Merry 2022-07-17 09:03:33 +01:00
parent 91d1f944e3
commit ac19912fe7
2 changed files with 30 additions and 97 deletions

View file

@ -583,40 +583,19 @@ bool Inst::AreAllArgsImmediates() const {
} }
bool Inst::HasAssociatedPseudoOperation() const { bool Inst::HasAssociatedPseudoOperation() const {
return carry_inst return next_pseudoop && !IsAPseudoOperation();
|| overflow_inst
|| ge_inst
|| nzcv_inst
|| upper_inst
|| lower_inst;
} }
Inst* Inst::GetAssociatedPseudoOperation(Opcode opcode) { Inst* Inst::GetAssociatedPseudoOperation(Opcode opcode) {
// This is faster than doing a search through the block. Inst* pseudoop = next_pseudoop;
switch (opcode) { while (pseudoop) {
case Opcode::GetCarryFromOp: if (pseudoop->GetOpcode() == opcode) {
ASSERT(!carry_inst || carry_inst->GetOpcode() == Opcode::GetCarryFromOp); ASSERT(pseudoop->GetArg(0).GetInst() == this);
return carry_inst; return pseudoop;
case Opcode::GetOverflowFromOp: }
ASSERT(!overflow_inst || overflow_inst->GetOpcode() == Opcode::GetOverflowFromOp); pseudoop = pseudoop->next_pseudoop;
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;
} }
return nullptr;
ASSERT_FALSE("Not a valid pseudo-operation");
} }
Type Inst::GetType() const { Type Inst::GetType() const {
@ -679,67 +658,31 @@ void Inst::ReplaceUsesWith(Value replacement) {
void Inst::Use(const Value& value) { void Inst::Use(const Value& value) {
value.GetInst()->use_count++; value.GetInst()->use_count++;
switch (op) { if (IsAPseudoOperation()) {
case Opcode::GetCarryFromOp: if (op == Opcode::GetNZCVFromOp) {
ASSERT_MSG(!value.GetInst()->carry_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()->carry_inst = this; }
break;
case Opcode::GetOverflowFromOp: Inst* insert_point = value.GetInst();
ASSERT_MSG(!value.GetInst()->overflow_inst, "Only one of each type of pseudo-op allowed"); while (insert_point->next_pseudoop) {
value.GetInst()->overflow_inst = this; insert_point = insert_point->next_pseudoop;
break; DEBUG_ASSERT(insert_point->GetArg(0).GetInst() == this);
case Opcode::GetGEFromOp: }
ASSERT_MSG(!value.GetInst()->ge_inst, "Only one of each type of pseudo-op allowed"); insert_point->next_pseudoop = this;
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;
} }
} }
void Inst::UndoUse(const Value& value) { void Inst::UndoUse(const Value& value) {
value.GetInst()->use_count--; value.GetInst()->use_count--;
switch (op) { if (IsAPseudoOperation()) {
case Opcode::GetCarryFromOp: Inst* insert_point = value.GetInst();
ASSERT(value.GetInst()->carry_inst->GetOpcode() == Opcode::GetCarryFromOp); while (insert_point->next_pseudoop != this) {
value.GetInst()->carry_inst = nullptr; insert_point = insert_point->next_pseudoop;
break; DEBUG_ASSERT(insert_point->GetArg(0).GetInst() == this);
case Opcode::GetOverflowFromOp: }
ASSERT(value.GetInst()->overflow_inst->GetOpcode() == Opcode::GetOverflowFromOp); insert_point->next_pseudoop = next_pseudoop;
value.GetInst()->overflow_inst = nullptr; next_pseudoop = 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;
} }
} }

View file

@ -149,18 +149,8 @@ private:
size_t use_count = 0; size_t use_count = 0;
std::array<Value, max_arg_count> args; std::array<Value, max_arg_count> args;
// Pointers to related pseudooperations: // Linked list of pseudooperations associated with this instruction.
// Since not all combinations are possible, we use a union to save space Inst* next_pseudoop = nullptr;
union {
Inst* carry_inst = nullptr;
Inst* ge_inst;
Inst* upper_inst;
};
Inst* overflow_inst = nullptr;
union {
Inst* nzcv_inst = nullptr;
Inst* lower_inst;
};
}; };
} // namespace Dynarmic::IR } // namespace Dynarmic::IR