• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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