1 /*
2 * Copyright (c) 2024-2025 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "compiler_logger.h"
17 #include "savestate_optimization.h"
18 #include "optimizer/analysis/alias_analysis.h"
19 #include "optimizer/analysis/dominators_tree.h"
20 #include "optimizer/ir/analysis.h"
21
22 namespace ark::compiler {
23
RunImpl()24 bool SaveStateOptimization::RunImpl()
25 {
26 if (g_options.IsCompilerEnforceSafepointPlacement()) {
27 return false;
28 }
29 uint64_t instsNumber = VisitGraphAndCount();
30 if (!HaveCalls() && instsNumber <= g_options.GetCompilerSafepointEliminationLimit()) {
31 RemoveSafePoints();
32 }
33 return IsApplied();
34 }
35
RemoveSafePoints()36 void SaveStateOptimization::RemoveSafePoints()
37 {
38 auto block = GetGraph()->GetStartBlock();
39 ASSERT(block != nullptr && block->IsStartBlock());
40 for (auto sp : block->Insts()) {
41 if (sp->GetOpcode() == Opcode::SafePoint) {
42 sp->ClearFlag(inst_flags::NO_DCE);
43 SetApplied();
44 COMPILER_LOG(DEBUG, SAVESTATE_OPT) << "SafePoint " << sp->GetId() << " is deleted from start block";
45 block->GetGraph()->GetEventWriter().EventSaveStateOptimization(GetOpcodeString(sp->GetOpcode()),
46 sp->GetId(), sp->GetPc());
47 }
48 }
49 }
50
RequireRegMap(Inst * inst)51 bool SaveStateOptimization::RequireRegMap(Inst *inst)
52 {
53 for (auto &user : inst->GetUsers()) {
54 auto userInst = user.GetInst();
55 if (userInst->RequireRegMap()) {
56 return true;
57 }
58 auto opcode = userInst->GetOpcode();
59 if (opcode == Opcode::CallStatic || opcode == Opcode::CallVirtual || opcode == Opcode::CallResolvedVirtual ||
60 opcode == Opcode::CallDynamic || opcode == Opcode::CallResolvedStatic) {
61 // Inlined method can contain Deoptimize or DeoptimizeIf
62 if (static_cast<CallInst *>(userInst)->IsInlined()) {
63 return true;
64 }
65 }
66 }
67 return false;
68 }
69
VisitDefault(Inst * inst)70 void SaveStateOptimization::VisitDefault(Inst *inst)
71 {
72 if (inst->GetType() != DataType::REFERENCE) {
73 return;
74 }
75 for (auto &user : inst->GetUsers()) {
76 auto userInst = user.GetInst();
77 if (!userInst->IsSaveState()) {
78 return;
79 }
80 if (userInst->GetOpcode() == Opcode::SafePoint) {
81 if (g_options.IsCompilerSafePointsRequireRegMap()) {
82 return;
83 }
84 continue;
85 }
86 if (RequireRegMap(userInst)) {
87 return;
88 }
89 }
90
91 inst->RemoveUsers<true>();
92
93 SetApplied();
94 COMPILER_LOG(DEBUG, SAVESTATE_OPT) << "All users of the instructions " << inst->GetId() << " are SaveStates";
95 inst->GetBasicBlock()->GetGraph()->GetEventWriter().EventSaveStateOptimization(GetOpcodeString(inst->GetOpcode()),
96 inst->GetId(), inst->GetPc());
97 }
98
VisitSaveState(GraphVisitor * v,Inst * inst)99 void SaveStateOptimization::VisitSaveState(GraphVisitor *v, Inst *inst)
100 {
101 auto visitor = static_cast<SaveStateOptimization *>(v);
102 if (visitor->TryToRemoveRedundantSaveState(inst)) {
103 return;
104 }
105
106 if (visitor->RequireRegMap(inst)) {
107 return;
108 }
109
110 auto ss = inst->CastToSaveState();
111 if (ss->RemoveNumericInputs()) {
112 visitor->SetApplied();
113 COMPILER_LOG(DEBUG, SAVESTATE_OPT) << "SaveState " << ss->GetId() << " numeric inputs were deleted";
114 ss->GetBasicBlock()->GetGraph()->GetEventWriter().EventSaveStateOptimization(GetOpcodeString(ss->GetOpcode()),
115 ss->GetId(), ss->GetPc());
116 ss->SetInputsWereDeleted();
117 }
118 }
119
VisitSaveStateDeoptimize(GraphVisitor * v,Inst * inst)120 void SaveStateOptimization::VisitSaveStateDeoptimize(GraphVisitor *v, Inst *inst)
121 {
122 static_cast<SaveStateOptimization *>(v)->TryToRemoveRedundantSaveState(inst);
123 }
124
TryToRemoveRedundantSaveState(Inst * inst)125 bool SaveStateOptimization::TryToRemoveRedundantSaveState(Inst *inst)
126 {
127 if (!inst->HasUsers()) {
128 auto block = inst->GetBasicBlock();
129 block->ReplaceInst(inst, block->GetGraph()->CreateInstNOP());
130 inst->RemoveInputs();
131 SetApplied();
132 COMPILER_LOG(DEBUG, SAVESTATE_OPT) << "SaveState " << inst->GetId() << " without users is deleted";
133 block->GetGraph()->GetEventWriter().EventSaveStateOptimization(GetOpcodeString(inst->GetOpcode()),
134 inst->GetId(), inst->GetPc());
135 return true;
136 }
137 return false;
138 }
139 } // namespace ark::compiler
140