diff --git a/src/inst.cpp b/src/inst.cpp index e66a669..0636699 100644 --- a/src/inst.cpp +++ b/src/inst.cpp @@ -40,6 +40,10 @@ void Inst::SetDataInput(id_t index, Inst *inst) { if (HasControlProp()) { index++; } + // For dynamic inputs + if (index != NumAllInputs() && GetRawInput(index) != nullptr) { + GetRawInput(index)->DeleteDataUser(this); + } SetRawInput(index, inst); inst->AddDataUser(this); } @@ -268,9 +272,8 @@ ConstantInst *Inst::CastToConstant() { void Inst::ReplaceDataUsers(Inst *from) { ASSERT(!HasControlProp()); - for (auto it = from->StartIteratorDataUsers(); it != from->GetRawUsers().end(); it++) { + for (auto it = from->StartIteratorDataUsers(); it != from->GetRawUsers().end(); it = from->StartIteratorDataUsers()) { auto user = *it; - AddDataUser(user); for (id_t i = 0; i < user->NumDataInputs(); i++) { if (user->GetDataInput(i) == from) { user->SetDataInput(i, this); diff --git a/src/inst.h b/src/inst.h index 3e7796b..d9ac8d7 100644 --- a/src/inst.h +++ b/src/inst.h @@ -118,6 +118,15 @@ class Inst void AddDataUser(Inst *inst); void DeleteDataUser(Inst *inst); + bool HasSingleDataUser() { + return NumDataUsers() == 1; + } + + Inst *GetSingleDataUser() { + ASSERT(HasSingleDataUser()); + return GetRawUsers().back(); + } + const std::list GetDataUsers(); virtual void DumpInputs([[maybe_unused]] std::ostream &out) {}; @@ -205,11 +214,11 @@ class Inst private: bool inst_placed_ = false; - id_t id_; - LinearNumber linear_number_; - LifeNumber life_number_; - Opcode opc_; - Type type_; + id_t id_ {}; + LinearNumber linear_number_ {}; + LifeNumber life_number_ {}; + Opcode opc_ {}; + Type type_ {}; protected: Inst *prev_ = nullptr; diff --git a/src/optimizations/peepholes.cpp b/src/optimizations/peepholes.cpp index b829c8a..5ad88a6 100644 --- a/src/optimizations/peepholes.cpp +++ b/src/optimizations/peepholes.cpp @@ -35,6 +35,8 @@ void Peepholes::VisitSub(Inst *inst) { if (ConstFoldingBinaryOp(graph_, inst)) { return; } + // Some optimization may be applied, so we don't go out from function + TryOptimizeSubSub(inst); if (TryOptimizeSubZero(inst)) { return; @@ -60,6 +62,13 @@ void Peepholes::VisitOr(Inst *inst) { } } +// 1. Constant 0x0 -> v3 +// 2. ... -> v3 +// 3. Sub v2, v1 -> v4 +// ==========>>========== +// 1. Constant 0x0 +// 2. ... -> v4 +// 3. Sub v2, v1 bool Peepholes::TryOptimizeSubZero(Inst *inst) { auto input0 = inst->GetDataInput(0); auto input1 = inst->GetDataInput(1); @@ -71,6 +80,41 @@ bool Peepholes::TryOptimizeSubZero(Inst *inst) { return false; } +// Optimize sub of sub +// 1. Constant ... -> v3 +// 2. Constant ... -> v3 +// 3. ... -> v4 +// 4. Sub v3, v1 -> v3 +// 5. Sub v4, v2 -> v6 +// ==========>>========== +// 1. Constant ... -> v3 +// 2. Constant ... +// 6. Constant /v1+v2/ -> v5 +// 3. ... -> v4 +// 4. Sub v3, v1 +// 5. Sub v3, v6 -> v6 +bool Peepholes::TryOptimizeSubSub(Inst *inst) { + auto input0 = inst->GetDataInput(0); + auto input1 = inst->GetDataInput(1); + + if (!input1->IsConst() || !inst->HasSingleDataUser()) { + return false; + } + + auto single_user = inst->GetSingleDataUser(); + if (single_user->GetOpcode() != Opcode::Sub || !single_user->GetDataInput(1)->IsConst()) { + return false; + } + + auto const_near = input1->CastToConstant()->GetImm(); + auto const_far = single_user->GetDataInput(1)->CastToConstant()->GetImm(); + // Overflow is ok + auto new_const = graph_->CreateConstantInst(const_near + const_far); + single_user->SetDataInput(1, new_const); + single_user->SetDataInput(0, input0); + return true; +} + bool Peepholes::TryOptimizeShlAfterShr(Inst *inst) { auto input0 = inst->GetDataInput(0); auto input1 = inst->GetDataInput(1); diff --git a/src/optimizations/peepholes.h b/src/optimizations/peepholes.h index e86fe5d..dcc9fef 100644 --- a/src/optimizations/peepholes.h +++ b/src/optimizations/peepholes.h @@ -21,6 +21,7 @@ class Peepholes { // Cases of optimization bool TryOptimizeSubZero(Inst *inst); + bool TryOptimizeSubSub(Inst *inst); bool TryOptimizeShlAfterShr(Inst *inst); bool TryOptimizeOrZero(Inst *inst); diff --git a/tests/peepholes_tests.cpp b/tests/peepholes_tests.cpp index 8228c05..37837e0 100644 --- a/tests/peepholes_tests.cpp +++ b/tests/peepholes_tests.cpp @@ -97,6 +97,44 @@ TEST(PeepholesTest, ShrAfterShr) { GraphComparator(true_graph, graph).Compare(); } +TEST(PeepholesTest, SubSub) { + // Before + auto ic = IrConstructor(); + ic.CreateInst(0); + ic.CreateInst(1); + ic.CreateInst(2); + ic.CreateInst(3).Imm(10); + ic.CreateInst(4).Imm(15); + ic.CreateInst(5).DataInputs(2, 3); + ic.CreateInst(6).DataInputs(5, 4); + ic.CreateInst(7).CtrlInput(0).DataInputs(6); + ic.CreateInst(8).CtrlInput(7).JmpTo(1); + + auto graph = ic.GetFinalGraph(); + auto ph = Peepholes(graph); + ph.Run(); + + // After + auto ic_true = IrConstructor(); + ic_true.CreateInst(0); + ic_true.CreateInst(2); + ic_true.CreateInst(3).Imm(10); + ic_true.CreateInst(4).Imm(15); + ic_true.CreateInst(9).Imm(25); + + ic_true.CreateInst(5).DataInputs(2, 3); + ic_true.CreateInst(6).DataInputs(2, 9); + ic_true.CreateInst(7).CtrlInput(0).DataInputs(6); + ic_true.CreateInst(8).CtrlInput(7).JmpTo(1); + + ic_true.CreateInst(1); + + auto true_graph = ic_true.GetFinalGraph(); + + GraphComparator(true_graph, graph).Compare(); +} + + TEST(ConstFoldingTest, Sub) { // Before