1 /*
2 * Copyright (c) 2021-2024 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 ark::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
VisitStoreObjectPair(GraphVisitor * v,Inst * inst)160 void OptimizeMemoryBarriers::VisitStoreObjectPair(GraphVisitor *v, Inst *inst)
161 {
162 static_cast<OptimizeMemoryBarriers *>(v)->CheckTwoInputs(inst->GetInput(0).GetInst(), inst->GetInput(1).GetInst());
163 }
164
VisitStoreObjectDynamic(GraphVisitor * v,Inst * inst)165 void OptimizeMemoryBarriers::VisitStoreObjectDynamic(GraphVisitor *v, Inst *inst)
166 {
167 static_cast<OptimizeMemoryBarriers *>(v)->CheckInput(inst->GetInput(inst->GetInputsCount() - 1).GetInst());
168 }
169
VisitStoreArray(GraphVisitor * v,Inst * inst)170 void OptimizeMemoryBarriers::VisitStoreArray(GraphVisitor *v, Inst *inst)
171 {
172 static_cast<OptimizeMemoryBarriers *>(v)->CheckInput(inst->GetInput(inst->GetInputsCount() - 1).GetInst());
173 }
174
VisitStoreArrayI(GraphVisitor * v,Inst * inst)175 void OptimizeMemoryBarriers::VisitStoreArrayI(GraphVisitor *v, Inst *inst)
176 {
177 static_cast<OptimizeMemoryBarriers *>(v)->CheckInput(inst->GetInput(inst->GetInputsCount() - 1).GetInst());
178 }
179
VisitStoreStatic(GraphVisitor * v,Inst * inst)180 void OptimizeMemoryBarriers::VisitStoreStatic(GraphVisitor *v, Inst *inst)
181 {
182 static_cast<OptimizeMemoryBarriers *>(v)->CheckInput(inst->GetInput(inst->GetInputsCount() - 1).GetInst());
183 }
184
VisitStore(GraphVisitor * v,Inst * inst)185 void OptimizeMemoryBarriers::VisitStore(GraphVisitor *v, Inst *inst)
186 {
187 static_cast<OptimizeMemoryBarriers *>(v)->CheckInput(inst->GetInput(inst->GetInputsCount() - 1).GetInst());
188 }
189
VisitStoreI(GraphVisitor * v,Inst * inst)190 void OptimizeMemoryBarriers::VisitStoreI(GraphVisitor *v, Inst *inst)
191 {
192 static_cast<OptimizeMemoryBarriers *>(v)->CheckInput(inst->GetInput(inst->GetInputsCount() - 1).GetInst());
193 }
194
VisitStoreResolvedObjectField(GraphVisitor * v,Inst * inst)195 void OptimizeMemoryBarriers::VisitStoreResolvedObjectField(GraphVisitor *v, Inst *inst)
196 {
197 static_cast<OptimizeMemoryBarriers *>(v)->CheckInput(inst->GetInput(1).GetInst());
198 }
199
VisitStoreResolvedObjectFieldStatic(GraphVisitor * v,Inst * inst)200 void OptimizeMemoryBarriers::VisitStoreResolvedObjectFieldStatic(GraphVisitor *v, Inst *inst)
201 {
202 static_cast<OptimizeMemoryBarriers *>(v)->CheckInput(inst->GetInput(1).GetInst());
203 }
204
VisitUnresolvedStoreStatic(GraphVisitor * v,Inst * inst)205 void OptimizeMemoryBarriers::VisitUnresolvedStoreStatic(GraphVisitor *v, Inst *inst)
206 {
207 static_cast<OptimizeMemoryBarriers *>(v)->CheckInput(inst->GetInput(0).GetInst());
208 }
209
VisitStoreArrayPair(GraphVisitor * v,Inst * inst)210 void OptimizeMemoryBarriers::VisitStoreArrayPair(GraphVisitor *v, Inst *inst)
211 {
212 auto val = inst->GetInputsCount() - 1;
213 static_cast<OptimizeMemoryBarriers *>(v)->CheckTwoInputs(inst->GetInput(val).GetInst(),
214 inst->GetInput(val - 1).GetInst());
215 }
216
VisitStoreArrayPairI(GraphVisitor * v,Inst * inst)217 void OptimizeMemoryBarriers::VisitStoreArrayPairI(GraphVisitor *v, Inst *inst)
218 {
219 auto val = inst->GetInputsCount() - 1;
220 static_cast<OptimizeMemoryBarriers *>(v)->CheckTwoInputs(inst->GetInput(val).GetInst(),
221 inst->GetInput(val - 1).GetInst());
222 }
223
GetMemInstForImplicitNullCheck(Inst * inst)224 static Inst *GetMemInstForImplicitNullCheck(Inst *inst)
225 {
226 if (!inst->HasUsers()) {
227 return nullptr;
228 }
229 auto nextInst = inst->GetNext();
230 while (nextInst != nullptr) {
231 if (IsSuitableForImplicitNullCheck(nextInst)) {
232 if (nextInst->GetInput(0) != inst) {
233 return nullptr;
234 }
235 return nextInst;
236 }
237 if (!nextInst->IsSafeInst()) {
238 return nullptr;
239 }
240 nextInst = nextInst->GetNext();
241 }
242
243 return nullptr;
244 }
245
VisitNullCheck(GraphVisitor * v,Inst * inst)246 void OptimizeMemoryBarriers::VisitNullCheck(GraphVisitor *v, Inst *inst)
247 {
248 // NullCheck was hoisted and can't be implicit
249 if (inst->CanDeoptimize()) {
250 return;
251 }
252 static_cast<OptimizeMemoryBarriers *>(v)->CheckInput(inst->GetInput(0).GetInst());
253 auto nc = static_cast<NullCheckInst *>(inst);
254 auto graph = nc->GetBasicBlock()->GetGraph();
255 // NOTE (pishin) support for arm32
256 if (graph->GetArch() == Arch::AARCH32) {
257 return;
258 }
259 if (!g_options.IsCompilerImplicitNullCheck() || graph->IsOsrMode() || graph->IsBytecodeOptimizer()) {
260 return;
261 }
262
263 auto memInst = GetMemInstForImplicitNullCheck(inst);
264 if (memInst == nullptr) {
265 return;
266 }
267 memInst->SetFlag(compiler::inst_flags::CAN_THROW);
268 nc->SetImplicit(true);
269 }
270
VisitBoundCheck(GraphVisitor * v,Inst * inst)271 void OptimizeMemoryBarriers::VisitBoundCheck(GraphVisitor *v, Inst *inst)
272 {
273 static_cast<OptimizeMemoryBarriers *>(v)->CheckTwoInputs(inst->GetInput(0).GetInst(), inst->GetInput(1).GetInst());
274 }
275
ApplyGraph()276 void OptimizeMemoryBarriers::ApplyGraph()
277 {
278 barriersInsts_.clear();
279 for (auto bb : GetGraph()->GetBlocksRPO()) {
280 for (auto inst : bb->Insts()) {
281 if (inst->GetFlag(inst_flags::MEM_BARRIER)) {
282 barriersInsts_.push_back(inst);
283 }
284 this->VisitInstruction(inst);
285 }
286 this->MergeBarriers();
287 }
288 }
289
RunImpl()290 bool OptimizeMemoryBarriers::RunImpl()
291 {
292 ApplyGraph();
293 return IsApplied();
294 }
295
296 } // namespace ark::compiler
297