1 /*
2 * Copyright (c) 2021-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 "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
VisitCallDynamic(GraphVisitor * v,Inst * inst)108 void OptimizeMemoryBarriers::VisitCallDynamic(GraphVisitor *v, Inst *inst)
109 {
110 static_cast<OptimizeMemoryBarriers *>(v)->CheckAllInputs(inst);
111 }
112
VisitCallNative(GraphVisitor * v,Inst * inst)113 void OptimizeMemoryBarriers::VisitCallNative(GraphVisitor *v, Inst *inst)
114 {
115 static_cast<OptimizeMemoryBarriers *>(v)->CheckAllInputs(inst);
116 }
117
VisitSelect(GraphVisitor * v,Inst * inst)118 void OptimizeMemoryBarriers::VisitSelect(GraphVisitor *v, Inst *inst)
119 {
120 static_cast<OptimizeMemoryBarriers *>(v)->CheckTwoInputs(inst->GetInput(0).GetInst(), inst->GetInput(1).GetInst());
121 }
122
VisitSelectImm(GraphVisitor * v,Inst * inst)123 void OptimizeMemoryBarriers::VisitSelectImm(GraphVisitor *v, Inst *inst)
124 {
125 static_cast<OptimizeMemoryBarriers *>(v)->CheckTwoInputs(inst->GetInput(0).GetInst(), inst->GetInput(1).GetInst());
126 }
127
VisitStoreObject(GraphVisitor * v,Inst * inst)128 void OptimizeMemoryBarriers::VisitStoreObject(GraphVisitor *v, Inst *inst)
129 {
130 static_cast<OptimizeMemoryBarriers *>(v)->CheckInput(inst->GetInput(inst->GetInputsCount() - 1).GetInst());
131 }
132
VisitStoreObjectPair(GraphVisitor * v,Inst * inst)133 void OptimizeMemoryBarriers::VisitStoreObjectPair(GraphVisitor *v, Inst *inst)
134 {
135 static_cast<OptimizeMemoryBarriers *>(v)->CheckTwoInputs(inst->GetInput(0).GetInst(), inst->GetInput(1).GetInst());
136 }
137
VisitStoreObjectDynamic(GraphVisitor * v,Inst * inst)138 void OptimizeMemoryBarriers::VisitStoreObjectDynamic(GraphVisitor *v, Inst *inst)
139 {
140 static_cast<OptimizeMemoryBarriers *>(v)->CheckInput(inst->GetInput(inst->GetInputsCount() - 1).GetInst());
141 }
142
VisitStoreArray(GraphVisitor * v,Inst * inst)143 void OptimizeMemoryBarriers::VisitStoreArray(GraphVisitor *v, Inst *inst)
144 {
145 static_cast<OptimizeMemoryBarriers *>(v)->CheckInput(inst->GetInput(inst->GetInputsCount() - 1).GetInst());
146 }
147
VisitStoreArrayI(GraphVisitor * v,Inst * inst)148 void OptimizeMemoryBarriers::VisitStoreArrayI(GraphVisitor *v, Inst *inst)
149 {
150 static_cast<OptimizeMemoryBarriers *>(v)->CheckInput(inst->GetInput(inst->GetInputsCount() - 1).GetInst());
151 }
152
VisitStoreStatic(GraphVisitor * v,Inst * inst)153 void OptimizeMemoryBarriers::VisitStoreStatic(GraphVisitor *v, Inst *inst)
154 {
155 static_cast<OptimizeMemoryBarriers *>(v)->CheckInput(inst->GetInput(inst->GetInputsCount() - 1).GetInst());
156 }
157
VisitStore(GraphVisitor * v,Inst * inst)158 void OptimizeMemoryBarriers::VisitStore(GraphVisitor *v, Inst *inst)
159 {
160 static_cast<OptimizeMemoryBarriers *>(v)->CheckInput(inst->GetInput(inst->GetInputsCount() - 1).GetInst());
161 }
162
VisitStoreI(GraphVisitor * v,Inst * inst)163 void OptimizeMemoryBarriers::VisitStoreI(GraphVisitor *v, Inst *inst)
164 {
165 static_cast<OptimizeMemoryBarriers *>(v)->CheckInput(inst->GetInput(inst->GetInputsCount() - 1).GetInst());
166 }
167
VisitStoreResolvedObjectField(GraphVisitor * v,Inst * inst)168 void OptimizeMemoryBarriers::VisitStoreResolvedObjectField(GraphVisitor *v, Inst *inst)
169 {
170 static_cast<OptimizeMemoryBarriers *>(v)->CheckInput(inst->GetInput(1).GetInst());
171 }
172
VisitStoreResolvedObjectFieldStatic(GraphVisitor * v,Inst * inst)173 void OptimizeMemoryBarriers::VisitStoreResolvedObjectFieldStatic(GraphVisitor *v, Inst *inst)
174 {
175 static_cast<OptimizeMemoryBarriers *>(v)->CheckInput(inst->GetInput(1).GetInst());
176 }
177
VisitUnresolvedStoreStatic(GraphVisitor * v,Inst * inst)178 void OptimizeMemoryBarriers::VisitUnresolvedStoreStatic(GraphVisitor *v, Inst *inst)
179 {
180 static_cast<OptimizeMemoryBarriers *>(v)->CheckInput(inst->GetInput(0).GetInst());
181 }
182
VisitStoreArrayPair(GraphVisitor * v,Inst * inst)183 void OptimizeMemoryBarriers::VisitStoreArrayPair(GraphVisitor *v, Inst *inst)
184 {
185 auto val = inst->GetInputsCount() - 1;
186 static_cast<OptimizeMemoryBarriers *>(v)->CheckTwoInputs(inst->GetInput(val).GetInst(),
187 inst->GetInput(val - 1).GetInst());
188 }
189
VisitStoreArrayPairI(GraphVisitor * v,Inst * inst)190 void OptimizeMemoryBarriers::VisitStoreArrayPairI(GraphVisitor *v, Inst *inst)
191 {
192 auto val = inst->GetInputsCount() - 1;
193 static_cast<OptimizeMemoryBarriers *>(v)->CheckTwoInputs(inst->GetInput(val).GetInst(),
194 inst->GetInput(val - 1).GetInst());
195 }
196
GetMemInstForImplicitNullCheck(Inst * inst)197 static Inst *GetMemInstForImplicitNullCheck(Inst *inst)
198 {
199 if (!inst->HasUsers()) {
200 return nullptr;
201 }
202 auto nextInst = inst->GetNext();
203 while (nextInst != nullptr) {
204 if (IsSuitableForImplicitNullCheck(nextInst)) {
205 if (nextInst->GetInput(0) != inst) {
206 return nullptr;
207 }
208 return nextInst;
209 }
210 if (!nextInst->IsSafeInst()) {
211 return nullptr;
212 }
213 nextInst = nextInst->GetNext();
214 }
215
216 return nullptr;
217 }
218
VisitNullCheck(GraphVisitor * v,Inst * inst)219 void OptimizeMemoryBarriers::VisitNullCheck(GraphVisitor *v, Inst *inst)
220 {
221 // NullCheck was hoisted and can't be implicit
222 if (inst->CanDeoptimize()) {
223 return;
224 }
225 static_cast<OptimizeMemoryBarriers *>(v)->CheckInput(inst->GetInput(0).GetInst());
226 auto nc = static_cast<NullCheckInst *>(inst);
227 auto graph = nc->GetBasicBlock()->GetGraph();
228 // NOTE (pishin) support for arm32
229 if (graph->GetArch() == Arch::AARCH32) {
230 return;
231 }
232 if (!g_options.IsCompilerImplicitNullCheck() || graph->IsOsrMode() || graph->IsBytecodeOptimizer()) {
233 return;
234 }
235
236 auto memInst = GetMemInstForImplicitNullCheck(inst);
237 if (memInst == nullptr) {
238 return;
239 }
240 memInst->SetFlag(compiler::inst_flags::CAN_THROW);
241 nc->SetImplicit(true);
242 }
243
VisitBoundCheck(GraphVisitor * v,Inst * inst)244 void OptimizeMemoryBarriers::VisitBoundCheck(GraphVisitor *v, Inst *inst)
245 {
246 static_cast<OptimizeMemoryBarriers *>(v)->CheckTwoInputs(inst->GetInput(0).GetInst(), inst->GetInput(1).GetInst());
247 }
248
ApplyGraph()249 void OptimizeMemoryBarriers::ApplyGraph()
250 {
251 barriersInsts_.clear();
252 for (auto bb : GetGraph()->GetBlocksRPO()) {
253 for (auto inst : bb->Insts()) {
254 if (inst->GetFlag(inst_flags::MEM_BARRIER)) {
255 barriersInsts_.push_back(inst);
256 }
257 this->VisitInstruction(inst);
258 }
259 this->MergeBarriers();
260 }
261 }
262
RunImpl()263 bool OptimizeMemoryBarriers::RunImpl()
264 {
265 ApplyGraph();
266 return IsApplied();
267 }
268
269 } // namespace ark::compiler
270