1 /*
2 * Copyright (c) 2021-2023 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 (barriersInsts_.size() <= 1) {
25 barriersInsts_.clear();
26 return;
27 }
28 isApplied_ = true;
29 auto lastBarrierInst = barriersInsts_.back();
30 for (auto inst : barriersInsts_) {
31 inst->ClearFlag(inst_flags::MEM_BARRIER);
32 }
33 lastBarrierInst->SetFlag(inst_flags::MEM_BARRIER);
34 barriersInsts_.clear();
35 }
36
CheckInst(Inst * inst)37 bool OptimizeMemoryBarriers::CheckInst(Inst *inst)
38 {
39 return (std::find(barriersInsts_.begin(), barriersInsts_.end(), inst) != barriersInsts_.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
VisitCallResolvedStatic(GraphVisitor * v,Inst * inst)84 void OptimizeMemoryBarriers::VisitCallResolvedStatic(GraphVisitor *v, Inst *inst)
85 {
86 if (inst->CastToCallResolvedStatic()->IsInlined()) {
87 return;
88 }
89 static_cast<OptimizeMemoryBarriers *>(v)->CheckAllInputs(inst);
90 }
91
VisitCallVirtual(GraphVisitor * v,Inst * inst)92 void OptimizeMemoryBarriers::VisitCallVirtual(GraphVisitor *v, Inst *inst)
93 {
94 if (inst->CastToCallVirtual()->IsInlined()) {
95 return;
96 }
97 static_cast<OptimizeMemoryBarriers *>(v)->CheckAllInputs(inst);
98 }
99
VisitCallResolvedVirtual(GraphVisitor * v,Inst * inst)100 void OptimizeMemoryBarriers::VisitCallResolvedVirtual(GraphVisitor *v, Inst *inst)
101 {
102 if (inst->CastToCallResolvedVirtual()->IsInlined()) {
103 return;
104 }
105 static_cast<OptimizeMemoryBarriers *>(v)->CheckAllInputs(inst);
106 }
107
VisitCallLaunchStatic(GraphVisitor * v,Inst * inst)108 void OptimizeMemoryBarriers::VisitCallLaunchStatic(GraphVisitor *v, Inst *inst)
109 {
110 if (inst->CastToCallLaunchStatic()->IsInlined()) {
111 return;
112 }
113 static_cast<OptimizeMemoryBarriers *>(v)->CheckAllInputs(inst);
114 }
115
VisitCallResolvedLaunchStatic(GraphVisitor * v,Inst * inst)116 void OptimizeMemoryBarriers::VisitCallResolvedLaunchStatic(GraphVisitor *v, Inst *inst)
117 {
118 if (inst->CastToCallResolvedLaunchStatic()->IsInlined()) {
119 return;
120 }
121 static_cast<OptimizeMemoryBarriers *>(v)->CheckAllInputs(inst);
122 }
123
VisitCallLaunchVirtual(GraphVisitor * v,Inst * inst)124 void OptimizeMemoryBarriers::VisitCallLaunchVirtual(GraphVisitor *v, Inst *inst)
125 {
126 if (inst->CastToCallLaunchVirtual()->IsInlined()) {
127 return;
128 }
129 static_cast<OptimizeMemoryBarriers *>(v)->CheckAllInputs(inst);
130 }
131
VisitCallResolvedLaunchVirtual(GraphVisitor * v,Inst * inst)132 void OptimizeMemoryBarriers::VisitCallResolvedLaunchVirtual(GraphVisitor *v, Inst *inst)
133 {
134 if (inst->CastToCallResolvedLaunchVirtual()->IsInlined()) {
135 return;
136 }
137 static_cast<OptimizeMemoryBarriers *>(v)->CheckAllInputs(inst);
138 }
139
VisitCallDynamic(GraphVisitor * v,Inst * inst)140 void OptimizeMemoryBarriers::VisitCallDynamic(GraphVisitor *v, Inst *inst)
141 {
142 static_cast<OptimizeMemoryBarriers *>(v)->CheckAllInputs(inst);
143 }
144
VisitSelect(GraphVisitor * v,Inst * inst)145 void OptimizeMemoryBarriers::VisitSelect(GraphVisitor *v, Inst *inst)
146 {
147 static_cast<OptimizeMemoryBarriers *>(v)->CheckTwoInputs(inst->GetInput(0).GetInst(), inst->GetInput(1).GetInst());
148 }
149
VisitSelectImm(GraphVisitor * v,Inst * inst)150 void OptimizeMemoryBarriers::VisitSelectImm(GraphVisitor *v, Inst *inst)
151 {
152 static_cast<OptimizeMemoryBarriers *>(v)->CheckTwoInputs(inst->GetInput(0).GetInst(), inst->GetInput(1).GetInst());
153 }
154
VisitStoreObject(GraphVisitor * v,Inst * inst)155 void OptimizeMemoryBarriers::VisitStoreObject(GraphVisitor *v, Inst *inst)
156 {
157 static_cast<OptimizeMemoryBarriers *>(v)->CheckInput(inst->GetInput(inst->GetInputsCount() - 1).GetInst());
158 }
159
VisitStoreObjectDynamic(GraphVisitor * v,Inst * inst)160 void OptimizeMemoryBarriers::VisitStoreObjectDynamic(GraphVisitor *v, Inst *inst)
161 {
162 static_cast<OptimizeMemoryBarriers *>(v)->CheckInput(inst->GetInput(inst->GetInputsCount() - 1).GetInst());
163 }
164
VisitStoreArray(GraphVisitor * v,Inst * inst)165 void OptimizeMemoryBarriers::VisitStoreArray(GraphVisitor *v, Inst *inst)
166 {
167 static_cast<OptimizeMemoryBarriers *>(v)->CheckInput(inst->GetInput(inst->GetInputsCount() - 1).GetInst());
168 }
169
VisitStoreArrayI(GraphVisitor * v,Inst * inst)170 void OptimizeMemoryBarriers::VisitStoreArrayI(GraphVisitor *v, Inst *inst)
171 {
172 static_cast<OptimizeMemoryBarriers *>(v)->CheckInput(inst->GetInput(inst->GetInputsCount() - 1).GetInst());
173 }
174
VisitStoreStatic(GraphVisitor * v,Inst * inst)175 void OptimizeMemoryBarriers::VisitStoreStatic(GraphVisitor *v, Inst *inst)
176 {
177 static_cast<OptimizeMemoryBarriers *>(v)->CheckInput(inst->GetInput(inst->GetInputsCount() - 1).GetInst());
178 }
179
VisitStore(GraphVisitor * v,Inst * inst)180 void OptimizeMemoryBarriers::VisitStore(GraphVisitor *v, Inst *inst)
181 {
182 static_cast<OptimizeMemoryBarriers *>(v)->CheckInput(inst->GetInput(inst->GetInputsCount() - 1).GetInst());
183 }
184
VisitStoreI(GraphVisitor * v,Inst * inst)185 void OptimizeMemoryBarriers::VisitStoreI(GraphVisitor *v, Inst *inst)
186 {
187 static_cast<OptimizeMemoryBarriers *>(v)->CheckInput(inst->GetInput(inst->GetInputsCount() - 1).GetInst());
188 }
189
VisitStoreResolvedObjectField(GraphVisitor * v,Inst * inst)190 void OptimizeMemoryBarriers::VisitStoreResolvedObjectField(GraphVisitor *v, Inst *inst)
191 {
192 static_cast<OptimizeMemoryBarriers *>(v)->CheckInput(inst->GetInput(1).GetInst());
193 }
194
VisitStoreResolvedObjectFieldStatic(GraphVisitor * v,Inst * inst)195 void OptimizeMemoryBarriers::VisitStoreResolvedObjectFieldStatic(GraphVisitor *v, Inst *inst)
196 {
197 static_cast<OptimizeMemoryBarriers *>(v)->CheckInput(inst->GetInput(1).GetInst());
198 }
199
VisitUnresolvedStoreStatic(GraphVisitor * v,Inst * inst)200 void OptimizeMemoryBarriers::VisitUnresolvedStoreStatic(GraphVisitor *v, Inst *inst)
201 {
202 static_cast<OptimizeMemoryBarriers *>(v)->CheckInput(inst->GetInput(0).GetInst());
203 }
204
VisitStoreArrayPair(GraphVisitor * v,Inst * inst)205 void OptimizeMemoryBarriers::VisitStoreArrayPair(GraphVisitor *v, Inst *inst)
206 {
207 auto val = inst->GetInputsCount() - 1;
208 static_cast<OptimizeMemoryBarriers *>(v)->CheckTwoInputs(inst->GetInput(val).GetInst(),
209 inst->GetInput(val - 1).GetInst());
210 }
211
VisitStoreArrayPairI(GraphVisitor * v,Inst * inst)212 void OptimizeMemoryBarriers::VisitStoreArrayPairI(GraphVisitor *v, Inst *inst)
213 {
214 auto val = inst->GetInputsCount() - 1;
215 static_cast<OptimizeMemoryBarriers *>(v)->CheckTwoInputs(inst->GetInput(val).GetInst(),
216 inst->GetInput(val - 1).GetInst());
217 }
218
GetMemInstForImplicitNullCheck(Inst * inst)219 static Inst *GetMemInstForImplicitNullCheck(Inst *inst)
220 {
221 if (!inst->HasUsers()) {
222 return nullptr;
223 }
224 auto nextInst = inst->GetNext();
225 while (nextInst != nullptr) {
226 if (IsSuitableForImplicitNullCheck(nextInst)) {
227 if (nextInst->GetInput(0) != inst) {
228 return nullptr;
229 }
230 return nextInst;
231 }
232 if (!nextInst->IsSafeInst()) {
233 return nullptr;
234 }
235 nextInst = nextInst->GetNext();
236 }
237
238 return nullptr;
239 }
240
VisitNullCheck(GraphVisitor * v,Inst * inst)241 void OptimizeMemoryBarriers::VisitNullCheck(GraphVisitor *v, Inst *inst)
242 {
243 // NullCheck was hoisted and can't be implicit
244 if (inst->CanDeoptimize()) {
245 return;
246 }
247 static_cast<OptimizeMemoryBarriers *>(v)->CheckInput(inst->GetInput(0).GetInst());
248 auto nc = static_cast<NullCheckInst *>(inst);
249 auto graph = nc->GetBasicBlock()->GetGraph();
250 // NOTE (pishin) support for arm32
251 if (graph->GetArch() == Arch::AARCH32) {
252 return;
253 }
254 if (!g_options.IsCompilerImplicitNullCheck() || graph->IsOsrMode() || graph->IsBytecodeOptimizer()) {
255 return;
256 }
257
258 auto memInst = GetMemInstForImplicitNullCheck(inst);
259 if (memInst == nullptr) {
260 return;
261 }
262 memInst->SetFlag(compiler::inst_flags::CAN_THROW);
263 nc->SetImplicit(true);
264 }
265
VisitBoundCheck(GraphVisitor * v,Inst * inst)266 void OptimizeMemoryBarriers::VisitBoundCheck(GraphVisitor *v, Inst *inst)
267 {
268 static_cast<OptimizeMemoryBarriers *>(v)->CheckTwoInputs(inst->GetInput(0).GetInst(), inst->GetInput(1).GetInst());
269 }
270
ApplyGraph()271 void OptimizeMemoryBarriers::ApplyGraph()
272 {
273 barriersInsts_.clear();
274 for (auto bb : GetGraph()->GetBlocksRPO()) {
275 for (auto inst : bb->Insts()) {
276 if (inst->GetFlag(inst_flags::MEM_BARRIER)) {
277 barriersInsts_.push_back(inst);
278 }
279 this->VisitInstruction(inst);
280 }
281 this->MergeBarriers();
282 }
283 }
284
RunImpl()285 bool OptimizeMemoryBarriers::RunImpl()
286 {
287 ApplyGraph();
288 return IsApplied();
289 }
290
291 } // namespace panda::compiler
292