1 /**
2 * Copyright (c) 2021-2022 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 "optimizer/ir/basicblock.h"
18 #include "memory_barriers.h"
19
20 namespace panda::compiler {
21
MergeBarriers()22 void OptimizeMemoryBarriers::MergeBarriers()
23 {
24 if (barriers_insts_.size() <= 1) {
25 barriers_insts_.clear();
26 return;
27 }
28 is_applied_ = true;
29 auto last_barrier_inst = barriers_insts_.back();
30 for (auto inst : barriers_insts_) {
31 inst->ClearFlag(inst_flags::MEM_BARRIER);
32 }
33 last_barrier_inst->SetFlag(inst_flags::MEM_BARRIER);
34 barriers_insts_.clear();
35 }
36
CheckInst(Inst * inst)37 bool OptimizeMemoryBarriers::CheckInst(Inst *inst)
38 {
39 return (std::find(barriers_insts_.begin(), barriers_insts_.end(), inst) != barriers_insts_.end());
40 }
41
CheckAllInputs(Inst * inst)42 void OptimizeMemoryBarriers::CheckAllInputs(Inst *inst)
43 {
44 for (auto input : inst->GetInputs()) {
45 if (CheckInst(input.GetInst())) {
46 MergeBarriers();
47 return;
48 }
49 }
50 }
51
CheckInput(Inst * input)52 void OptimizeMemoryBarriers::CheckInput(Inst *input)
53 {
54 if (CheckInst(input)) {
55 MergeBarriers();
56 }
57 }
58
CheckTwoInputs(Inst * input1,Inst * input2)59 void OptimizeMemoryBarriers::CheckTwoInputs(Inst *input1, Inst *input2)
60 {
61 if (CheckInst(input1) || CheckInst(input2)) {
62 MergeBarriers();
63 }
64 }
65
VisitCallStatic(GraphVisitor * v,Inst * inst)66 void OptimizeMemoryBarriers::VisitCallStatic(GraphVisitor *v, Inst *inst)
67 {
68 if (inst->CastToCallStatic()->IsInlined()) {
69 return;
70 }
71 static_cast<OptimizeMemoryBarriers *>(v)->CheckAllInputs(inst);
72 }
73
VisitCallIndirect(GraphVisitor * v,Inst * inst)74 void OptimizeMemoryBarriers::VisitCallIndirect(GraphVisitor *v, Inst *inst)
75 {
76 static_cast<OptimizeMemoryBarriers *>(v)->CheckAllInputs(inst);
77 }
78
VisitCall(GraphVisitor * v,Inst * inst)79 void OptimizeMemoryBarriers::VisitCall(GraphVisitor *v, Inst *inst)
80 {
81 static_cast<OptimizeMemoryBarriers *>(v)->CheckAllInputs(inst);
82 }
83
VisitUnresolvedCallStatic(GraphVisitor * v,Inst * inst)84 void OptimizeMemoryBarriers::VisitUnresolvedCallStatic(GraphVisitor *v, Inst *inst)
85 {
86 static_cast<OptimizeMemoryBarriers *>(v)->CheckAllInputs(inst);
87 }
88
VisitCallVirtual(GraphVisitor * v,Inst * inst)89 void OptimizeMemoryBarriers::VisitCallVirtual(GraphVisitor *v, Inst *inst)
90 {
91 if (inst->CastToCallVirtual()->IsInlined()) {
92 return;
93 }
94 static_cast<OptimizeMemoryBarriers *>(v)->CheckAllInputs(inst);
95 }
96
VisitUnresolvedCallVirtual(GraphVisitor * v,Inst * inst)97 void OptimizeMemoryBarriers::VisitUnresolvedCallVirtual(GraphVisitor *v, Inst *inst)
98 {
99 static_cast<OptimizeMemoryBarriers *>(v)->CheckAllInputs(inst);
100 }
101
VisitCallDynamic(GraphVisitor * v,Inst * inst)102 void OptimizeMemoryBarriers::VisitCallDynamic(GraphVisitor *v, Inst *inst)
103 {
104 static_cast<OptimizeMemoryBarriers *>(v)->CheckAllInputs(inst);
105 }
106
VisitSelect(GraphVisitor * v,Inst * inst)107 void OptimizeMemoryBarriers::VisitSelect(GraphVisitor *v, Inst *inst)
108 {
109 static_cast<OptimizeMemoryBarriers *>(v)->CheckTwoInputs(inst->GetInput(0).GetInst(), inst->GetInput(1).GetInst());
110 }
111
VisitSelectImm(GraphVisitor * v,Inst * inst)112 void OptimizeMemoryBarriers::VisitSelectImm(GraphVisitor *v, Inst *inst)
113 {
114 static_cast<OptimizeMemoryBarriers *>(v)->CheckTwoInputs(inst->GetInput(0).GetInst(), inst->GetInput(1).GetInst());
115 }
116
VisitStoreObject(GraphVisitor * v,Inst * inst)117 void OptimizeMemoryBarriers::VisitStoreObject(GraphVisitor *v, Inst *inst)
118 {
119 static_cast<OptimizeMemoryBarriers *>(v)->CheckInput(inst->GetInput(inst->GetInputsCount() - 1).GetInst());
120 }
121
VisitStoreArray(GraphVisitor * v,Inst * inst)122 void OptimizeMemoryBarriers::VisitStoreArray(GraphVisitor *v, Inst *inst)
123 {
124 static_cast<OptimizeMemoryBarriers *>(v)->CheckInput(inst->GetInput(inst->GetInputsCount() - 1).GetInst());
125 }
126
VisitStoreArrayI(GraphVisitor * v,Inst * inst)127 void OptimizeMemoryBarriers::VisitStoreArrayI(GraphVisitor *v, Inst *inst)
128 {
129 static_cast<OptimizeMemoryBarriers *>(v)->CheckInput(inst->GetInput(inst->GetInputsCount() - 1).GetInst());
130 }
131
VisitStoreStatic(GraphVisitor * v,Inst * inst)132 void OptimizeMemoryBarriers::VisitStoreStatic(GraphVisitor *v, Inst *inst)
133 {
134 static_cast<OptimizeMemoryBarriers *>(v)->CheckInput(inst->GetInput(inst->GetInputsCount() - 1).GetInst());
135 }
136
VisitStore(GraphVisitor * v,Inst * inst)137 void OptimizeMemoryBarriers::VisitStore(GraphVisitor *v, Inst *inst)
138 {
139 static_cast<OptimizeMemoryBarriers *>(v)->CheckInput(inst->GetInput(inst->GetInputsCount() - 1).GetInst());
140 }
141
VisitStoreI(GraphVisitor * v,Inst * inst)142 void OptimizeMemoryBarriers::VisitStoreI(GraphVisitor *v, Inst *inst)
143 {
144 static_cast<OptimizeMemoryBarriers *>(v)->CheckInput(inst->GetInput(inst->GetInputsCount() - 1).GetInst());
145 }
146
VisitUnresolvedStoreObject(GraphVisitor * v,Inst * inst)147 void OptimizeMemoryBarriers::VisitUnresolvedStoreObject(GraphVisitor *v, Inst *inst)
148 {
149 static_cast<OptimizeMemoryBarriers *>(v)->CheckInput(inst->GetInput(1).GetInst());
150 }
151
VisitUnresolvedStoreStatic(GraphVisitor * v,Inst * inst)152 void OptimizeMemoryBarriers::VisitUnresolvedStoreStatic(GraphVisitor *v, Inst *inst)
153 {
154 static_cast<OptimizeMemoryBarriers *>(v)->CheckInput(inst->GetInput(0).GetInst());
155 }
156
VisitStoreArrayPair(GraphVisitor * v,Inst * inst)157 void OptimizeMemoryBarriers::VisitStoreArrayPair(GraphVisitor *v, Inst *inst)
158 {
159 auto val = inst->GetInputsCount() - 1;
160 static_cast<OptimizeMemoryBarriers *>(v)->CheckTwoInputs(inst->GetInput(val).GetInst(),
161 inst->GetInput(val - 1).GetInst());
162 }
163
VisitStoreArrayPairI(GraphVisitor * v,Inst * inst)164 void OptimizeMemoryBarriers::VisitStoreArrayPairI(GraphVisitor *v, Inst *inst)
165 {
166 auto val = inst->GetInputsCount() - 1;
167 static_cast<OptimizeMemoryBarriers *>(v)->CheckTwoInputs(inst->GetInput(val).GetInst(),
168 inst->GetInput(val - 1).GetInst());
169 }
170
GetMemInstForImplicitNullCheck(Inst * inst)171 static Inst *GetMemInstForImplicitNullCheck(Inst *inst)
172 {
173 if (!inst->HasUsers()) {
174 return nullptr;
175 }
176 auto nextInst = inst->GetNext();
177 while (nextInst != nullptr) {
178 if (IsSuitableForImplicitNullCheck(nextInst)) {
179 if (nextInst->GetInput(0).GetInst() != inst) {
180 return nullptr;
181 }
182 return nextInst;
183 }
184 if (!nextInst->IsSafeInst()) {
185 return nullptr;
186 }
187 nextInst = nextInst->GetNext();
188 }
189
190 return nullptr;
191 }
192
VisitNullCheck(GraphVisitor * v,Inst * inst)193 void OptimizeMemoryBarriers::VisitNullCheck(GraphVisitor *v, Inst *inst)
194 {
195 static_cast<OptimizeMemoryBarriers *>(v)->CheckInput(inst->GetInput(0).GetInst());
196 auto nc = static_cast<NullCheckInst *>(inst);
197 auto graph = nc->GetBasicBlock()->GetGraph();
198 // TODO (pishin) support for arm32
199 if (graph->GetArch() == Arch::AARCH32) {
200 return;
201 }
202 if (!options.IsCompilerImplicitNullCheck() || graph->IsOsrMode() || graph->IsBytecodeOptimizer()) {
203 return;
204 }
205
206 auto memInst = GetMemInstForImplicitNullCheck(inst);
207 if (memInst == nullptr) {
208 return;
209 }
210 memInst->SetFlag(compiler::inst_flags::CAN_THROW);
211 nc->SetImplicit(true);
212 }
213
VisitBoundCheck(GraphVisitor * v,Inst * inst)214 void OptimizeMemoryBarriers::VisitBoundCheck(GraphVisitor *v, Inst *inst)
215 {
216 static_cast<OptimizeMemoryBarriers *>(v)->CheckTwoInputs(inst->GetInput(0).GetInst(), inst->GetInput(1).GetInst());
217 }
218
ApplyGraph()219 void OptimizeMemoryBarriers::ApplyGraph()
220 {
221 barriers_insts_.clear();
222 for (auto bb : GetGraph()->GetBlocksRPO()) {
223 for (auto inst : bb->Insts()) {
224 if (inst->GetFlag(inst_flags::MEM_BARRIER)) {
225 barriers_insts_.push_back(inst);
226 }
227 this->VisitInstruction(inst);
228 }
229 this->MergeBarriers();
230 }
231 }
232
RunImpl()233 bool OptimizeMemoryBarriers::RunImpl()
234 {
235 ApplyGraph();
236 return IsApplied();
237 }
238
239 } // namespace panda::compiler
240