• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "locations_builder.h"
17 #include "compiler/optimizer/code_generator/callconv.h"
18 #include "compiler/optimizer/ir/graph.h"
19 #include "compiler/optimizer/ir/locations.h"
20 
21 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
22 #define LOCATIONS_BUILDER(type) \
23     template <Arch arch>        \
24     type LocationsBuilder<arch>
25 
26 namespace ark::compiler {
RunLocationsBuilder(Graph * graph)27 bool RunLocationsBuilder(Graph *graph)
28 {
29     if (graph->GetCallingConvention() == nullptr) {
30         return true;
31     }
32     auto pinfo = graph->GetCallingConvention()->GetParameterInfo(0);
33     switch (graph->GetArch()) {
34         case Arch::X86_64: {
35             return graph->RunPass<LocationsBuilder<Arch::X86_64>>(pinfo);
36         }
37         case Arch::AARCH64: {
38             return graph->RunPass<LocationsBuilder<Arch::AARCH64>>(pinfo);
39         }
40         case Arch::AARCH32: {
41             return graph->RunPass<LocationsBuilder<Arch::AARCH32>>(pinfo);
42         }
43         default:
44             break;
45     }
46     LOG(ERROR, COMPILER) << "Unknown target architecture";
47     return false;
48 }
49 
LOCATIONS_BUILDER()50 LOCATIONS_BUILDER()::LocationsBuilder(Graph *graph, ParameterInfo *pinfo) : Optimization(graph), paramsInfo_(pinfo)
51 {
52     if (graph->SupportManagedCode()) {
53         /* We skip first parameter location in managed mode, because calling convention for Panda methods requires
54            pointer to the called method as a first parameter. So we reserve one native parameter for it. */
55         GetParameterInfo()->GetNextLocation(DataType::POINTER);
56     }
57 }
58 
LOCATIONS_BUILDER(const ArenaVector<BasicBlock * > &)59 LOCATIONS_BUILDER(const ArenaVector<BasicBlock *> &)::GetBlocksToVisit() const
60 {
61     return GetGraph()->GetBlocksRPO();
62 }
63 
LOCATIONS_BUILDER(bool)64 LOCATIONS_BUILDER(bool)::RunImpl()
65 {
66     VisitGraph();
67     return true;
68 }
69 
LOCATIONS_BUILDER(void)70 LOCATIONS_BUILDER(void)::ProcessManagedCall(Inst *inst, ParameterInfo *pinfo)
71 {
72     ArenaAllocator *allocator = GetGraph()->GetAllocator();
73     LocationsInfo *locations = allocator->New<LocationsInfo>(allocator, inst);
74 
75     if (pinfo == nullptr) {
76         pinfo = GetResetParameterInfo();
77         if (inst->GetOpcode() != Opcode::CallResolvedVirtual && inst->GetOpcode() != Opcode::CallResolvedStatic) {
78             pinfo->GetNextLocation(GetWordType());
79         }
80     }
81 
82     size_t inputsCount = inst->GetInputsCount() - (inst->RequireState() ? 1 : 0);
83     size_t stackArgs = 0;
84     for (size_t i = 0; i < inputsCount; i++) {
85         ASSERT(inst->GetInputType(i) != DataType::NO_TYPE);
86         auto param = pinfo->GetNextLocation(inst->GetInputType(i));
87         if (i == 0 && inst->IsIntrinsic() && inst->CastToIntrinsic()->HasIdInput()) {
88             param = Location::MakeRegister(GetTarget().GetParamRegId(0));  // place id input before imms
89         }
90         locations->SetLocation(i, param);
91         if (param.IsStackArgument()) {
92             stackArgs++;
93         }
94     }
95     if (inst->IsIntrinsic() && stackArgs > 0) {
96         inst->CastToIntrinsic()->SetArgumentsOnStack();
97     }
98     if (!inst->NoDest()) {
99         locations->SetDstLocation(GetLocationForReturn(inst));
100     }
101     GetGraph()->UpdateStackSlotsCount(stackArgs);
102 }
103 
LOCATIONS_BUILDER(void)104 LOCATIONS_BUILDER(void)::ProcessManagedCallStackRange(Inst *inst, size_t rangeStart, ParameterInfo *pinfo)
105 {
106     ArenaAllocator *allocator = GetGraph()->GetAllocator();
107     LocationsInfo *locations = allocator->New<LocationsInfo>(allocator, inst);
108 
109     /* Reserve first parameter for the callee method. It will be set by codegen. */
110     if (pinfo == nullptr) {
111         pinfo = GetResetParameterInfo();
112         pinfo->GetNextLocation(GetWordType());
113     }
114 
115     size_t inputsCount = inst->GetInputsCount() - (inst->RequireState() ? 1 : 0);
116     size_t stackArgs = 0;
117     ASSERT(inputsCount >= rangeStart);
118     for (size_t i = 0; i < rangeStart; i++) {
119         ASSERT(inst->GetInputType(i) != DataType::NO_TYPE);
120         auto param = pinfo->GetNextLocation(inst->GetInputType(i));
121         locations->SetLocation(i, param);
122         if (param.IsStackArgument()) {
123             stackArgs++;
124         }
125     }
126     if (inst->IsIntrinsic() && stackArgs > 0) {
127         inst->CastToIntrinsic()->SetArgumentsOnStack();
128     }
129     for (size_t i = rangeStart; i < inputsCount; i++) {
130         locations->SetLocation(i, Location::MakeStackArgument(stackArgs++));
131     }
132     locations->SetDstLocation(GetLocationForReturn(inst));
133     GetGraph()->UpdateStackSlotsCount(stackArgs);
134 }
135 
LOCATIONS_BUILDER(void)136 LOCATIONS_BUILDER(void)::VisitResolveStatic([[maybe_unused]] GraphVisitor *visitor, Inst *inst)
137 {
138     inst->CastToResolveStatic()->SetDstLocation(GetLocationForReturn(inst));
139 }
140 
LOCATIONS_BUILDER(void)141 LOCATIONS_BUILDER(void)::VisitCallResolvedStatic(GraphVisitor *visitor, Inst *inst)
142 {
143     if (inst->CastToCallResolvedStatic()->IsInlined()) {
144         return;
145     }
146     static_cast<LocationsBuilder *>(visitor)->ProcessManagedCall(inst);
147 }
148 
LOCATIONS_BUILDER(void)149 LOCATIONS_BUILDER(void)::VisitResolveVirtual([[maybe_unused]] GraphVisitor *visitor, Inst *inst)
150 {
151     inst->CastToResolveVirtual()->SetDstLocation(GetLocationForReturn(inst));
152 }
153 
LOCATIONS_BUILDER(void)154 LOCATIONS_BUILDER(void)::VisitCallResolvedVirtual(GraphVisitor *visitor, Inst *inst)
155 {
156     if (inst->CastToCallResolvedVirtual()->IsInlined()) {
157         return;
158     }
159     static_cast<LocationsBuilder *>(visitor)->ProcessManagedCall(inst);
160 }
161 
LOCATIONS_BUILDER(void)162 LOCATIONS_BUILDER(void)::VisitCallStatic(GraphVisitor *visitor, Inst *inst)
163 {
164     if (inst->CastToCallStatic()->IsInlined()) {
165         return;
166     }
167     static_cast<LocationsBuilder *>(visitor)->ProcessManagedCall(inst);
168 }
169 
LOCATIONS_BUILDER(void)170 LOCATIONS_BUILDER(void)::VisitCallVirtual(GraphVisitor *visitor, Inst *inst)
171 {
172     if (inst->CastToCallVirtual()->IsInlined()) {
173         return;
174     }
175     static_cast<LocationsBuilder *>(visitor)->ProcessManagedCall(inst);
176 }
177 
LOCATIONS_BUILDER(void)178 LOCATIONS_BUILDER(void)::VisitCallDynamic(GraphVisitor *visitor, Inst *inst)
179 {
180     ArenaAllocator *allocator = static_cast<LocationsBuilder *>(visitor)->GetGraph()->GetAllocator();
181     LocationsInfo *locations = allocator->New<LocationsInfo>(allocator, inst);
182 
183     if (inst->CastToCallDynamic()->IsInlined()) {
184         ASSERT(inst->GetInputType(CallConvDynInfo::REG_METHOD) == DataType::ANY);
185         auto param = Location::MakeRegister(GetTarget().GetParamRegId(CallConvDynInfo::REG_METHOD));
186         locations->SetLocation(CallConvDynInfo::REG_METHOD, param);
187         return;
188     }
189 
190     auto pinfo = static_cast<LocationsBuilder *>(visitor)->GetResetParameterInfo();
191     for (uint8_t i = 0; i < CallConvDynInfo::REG_COUNT; i++) {
192         [[maybe_unused]] Location loc = pinfo->GetNextLocation(GetWordType());
193         ASSERT(loc.IsRegister());
194     }
195     size_t inputsCount = inst->GetInputsCount() - (inst->RequireState() ? 1 : 0);
196 
197     for (size_t i = 0; i < inputsCount; ++i) {
198         ASSERT(inst->GetInputType(i) == DataType::ANY);
199         auto param = Location::MakeStackArgument(i + CallConvDynInfo::FIXED_SLOT_COUNT);
200         locations->SetLocation(i, param);
201     }
202     locations->SetDstLocation(GetLocationForReturn(inst));
203     static_cast<LocationsBuilder *>(visitor)->GetGraph()->UpdateStackSlotsCount(inputsCount);
204 }
205 
LOCATIONS_BUILDER(void)206 LOCATIONS_BUILDER(void)::VisitCallIndirect(GraphVisitor *visitor, Inst *inst)
207 {
208     ArenaAllocator *allocator = static_cast<LocationsBuilder *>(visitor)->GetGraph()->GetAllocator();
209     LocationsInfo *locations = allocator->New<LocationsInfo>(allocator, inst);
210     auto params = static_cast<LocationsBuilder *>(visitor)->GetResetParameterInfo();
211 
212     /* First input is an address of the memory to call. So it hasn't exact location and maybe be any register */
213     locations->SetLocation(0, Location::RequireRegister());
214 
215     /* Inputs, starting from 1, are the native call arguments */
216     for (size_t i = 1; i < inst->GetInputsCount(); i++) {
217         auto param = params->GetNextLocation(inst->GetInputType(i));
218         locations->SetLocation(i, param);
219     }
220     if (!inst->NoDest()) {
221         locations->SetDstLocation(GetLocationForReturn(inst));
222     }
223 }
224 
LOCATIONS_BUILDER(void)225 LOCATIONS_BUILDER(void)::VisitCall(GraphVisitor *visitor, Inst *inst)
226 {
227     ArenaAllocator *allocator = static_cast<LocationsBuilder *>(visitor)->GetGraph()->GetAllocator();
228     LocationsInfo *locations = allocator->New<LocationsInfo>(allocator, inst);
229     auto params = static_cast<LocationsBuilder *>(visitor)->GetResetParameterInfo();
230 
231     for (size_t i = 0; i < inst->GetInputsCount(); i++) {
232         auto param = params->GetNextLocation(inst->GetInputType(i));
233         locations->SetLocation(i, param);
234     }
235     if (!inst->NoDest()) {
236         locations->SetDstLocation(GetLocationForReturn(inst));
237     }
238 }
239 
LOCATIONS_BUILDER(void)240 LOCATIONS_BUILDER(void)::VisitIntrinsic(GraphVisitor *visitor, Inst *inst)
241 {
242     auto graph = static_cast<LocationsBuilder *>(visitor)->GetGraph();
243     auto intrinsic = inst->CastToIntrinsic();
244     auto id = intrinsic->GetIntrinsicId();
245     if (intrinsic->IsNativeCall() || IntrinsicNeedsParamLocations(id)) {
246         auto pinfo = static_cast<LocationsBuilder *>(visitor)->GetResetParameterInfo();
247         if (intrinsic->IsMethodFirstInput()) {
248             pinfo->GetNextLocation(GetWordType());
249         }
250         if (intrinsic->HasImms() && graph->SupportManagedCode()) {
251             for ([[maybe_unused]] auto imm : intrinsic->GetImms()) {
252                 pinfo->GetNextLocation(DataType::INT32);
253             }
254         }
255         size_t explicitArgs;
256         if (IsStackRangeIntrinsic(id, &explicitArgs)) {
257             static_cast<LocationsBuilder *>(visitor)->ProcessManagedCallStackRange(inst, explicitArgs, pinfo);
258         } else {
259             static_cast<LocationsBuilder *>(visitor)->ProcessManagedCall(inst, pinfo);
260         }
261         return;
262     }
263     ArenaAllocator *allocator = static_cast<LocationsBuilder *>(visitor)->GetGraph()->GetAllocator();
264     LocationsInfo *locations = allocator->New<LocationsInfo>(allocator, inst);
265     auto inputsCount = inst->GetInputsCount() - (inst->RequireState() ? 1 : 0);
266     for (size_t i = 0; i < inputsCount; i++) {
267         locations->SetLocation(i, Location::RequireRegister());
268     }
269 }
270 
LOCATIONS_BUILDER(void)271 LOCATIONS_BUILDER(void)::VisitNewArray([[maybe_unused]] GraphVisitor *visitor, Inst *inst)
272 {
273     inst->CastToNewArray()->SetLocation(0, Location::MakeRegister(GetTarget().GetParamRegId(0)));
274     inst->CastToNewArray()->SetLocation(1, Location::MakeRegister(GetTarget().GetParamRegId(1)));
275     inst->CastToNewArray()->SetDstLocation(GetLocationForReturn(inst));
276 }
277 
LOCATIONS_BUILDER(void)278 LOCATIONS_BUILDER(void)::VisitNewObject([[maybe_unused]] GraphVisitor *visitor, Inst *inst)
279 {
280     inst->CastToNewObject()->SetLocation(0, Location::MakeRegister(GetTarget().GetParamRegId(0)));
281     inst->CastToNewObject()->SetDstLocation(GetLocationForReturn(inst));
282 }
283 
LOCATIONS_BUILDER(void)284 LOCATIONS_BUILDER(void)::VisitParameter([[maybe_unused]] GraphVisitor *visitor, [[maybe_unused]] Inst *inst)
285 {
286     /* Currently we can't process parameters in the Locations Builder, because Parameter instructions may be removed
287      * during optimizations pipeline. Thus, locations is set by IR builder before optimizations.
288      * NOTE(compiler): we need to move Parameters' locations here, thereby we get rid of arch structures in the Graph,
289      * such as ParameterInfo, CallingConvention, etc.
290      */
291 }
292 
LOCATIONS_BUILDER(void)293 LOCATIONS_BUILDER(void)::VisitReturn([[maybe_unused]] GraphVisitor *visitor, Inst *inst)
294 {
295     auto returnReg =
296         DataType::IsFloatType(inst->GetType()) ? GetTarget().GetReturnRegId() : GetTarget().GetReturnFpRegId();
297     inst->CastToReturn()->SetLocation(0, Location::MakeRegister(returnReg));
298 }
299 
LOCATIONS_BUILDER(void)300 LOCATIONS_BUILDER(void)::VisitThrow([[maybe_unused]] GraphVisitor *visitor, Inst *inst)
301 {
302     inst->CastToThrow()->SetLocation(0, Location::MakeRegister(GetTarget().GetParamRegId(0)));
303 }
304 
LOCATIONS_BUILDER(void)305 LOCATIONS_BUILDER(void)::VisitLiveOut([[maybe_unused]] GraphVisitor *visitor, Inst *inst)
306 {
307     inst->CastToLiveOut()->SetLocation(0, Location::MakeRegister(inst->GetDstReg()));
308 }
309 
LOCATIONS_BUILDER(void)310 LOCATIONS_BUILDER(void)::VisitMultiArray(GraphVisitor *visitor, Inst *inst)
311 {
312     auto graph = static_cast<LocationsBuilder *>(visitor)->GetGraph();
313     ArenaAllocator *allocator = graph->GetAllocator();
314     LocationsInfo *locations = allocator->New<LocationsInfo>(allocator, inst);
315     locations->SetLocation(0, Location::RequireRegister());
316 
317     for (size_t i = 1; i < inst->GetInputsCount() - 1; i++) {
318         locations->SetLocation(i, Location::MakeStackArgument(i - 1));
319     }
320     auto stackArgs = inst->GetInputsCount() - 2U;
321     graph->UpdateStackSlotsCount(RoundUp(stackArgs, 2U));
322     locations->SetDstLocation(GetLocationForReturn(inst));
323 }
324 
LOCATIONS_BUILDER(void)325 LOCATIONS_BUILDER(void)::VisitCallLaunchStatic(GraphVisitor *visitor, Inst *inst)
326 {
327     auto graph = static_cast<LocationsBuilder *>(visitor)->GetGraph();
328     ArenaAllocator *allocator = graph->GetAllocator();
329     LocationsInfo *locations = allocator->New<LocationsInfo>(allocator, inst);
330     // First input is second parameter(first is pointer to a method)
331     locations->SetLocation(0, Location::MakeRegister(GetTarget().GetParamRegId(1)));
332 
333     for (size_t i = 1; i < inst->GetInputsCount() - 1; i++) {
334         locations->SetLocation(i, Location::MakeStackArgument(i - 1));
335     }
336     auto stackArgs = inst->GetInputsCount() - 2U;
337     graph->UpdateStackSlotsCount(RoundUp(stackArgs, 2U));
338     locations->SetDstLocation(GetLocationForReturn(inst));
339 }
340 
LOCATIONS_BUILDER(void)341 LOCATIONS_BUILDER(void)::VisitCallLaunchVirtual(GraphVisitor *visitor, Inst *inst)
342 {
343     auto graph = static_cast<LocationsBuilder *>(visitor)->GetGraph();
344     ArenaAllocator *allocator = graph->GetAllocator();
345     LocationsInfo *locations = allocator->New<LocationsInfo>(allocator, inst);
346     // First input is second parameter(first is pointer to a method)
347     locations->SetLocation(0, Location::MakeRegister(GetTarget().GetParamRegId(1)));
348     // This object
349     locations->SetLocation(1, Location::MakeRegister(GetTarget().GetParamRegId(3U)));
350 
351     for (size_t i = 2U; i < inst->GetInputsCount() - 1; i++) {
352         locations->SetLocation(i, Location::MakeStackArgument(i - 2U));
353     }
354     auto stackArgs = inst->GetInputsCount() - 3U;
355     graph->UpdateStackSlotsCount(RoundUp(stackArgs, 2U));
356     locations->SetDstLocation(GetLocationForReturn(inst));
357 }
358 
LOCATIONS_BUILDER(void)359 LOCATIONS_BUILDER(void)::VisitCallResolvedLaunchStatic(GraphVisitor *visitor, Inst *inst)
360 {
361     auto graph = static_cast<LocationsBuilder *>(visitor)->GetGraph();
362     ArenaAllocator *allocator = graph->GetAllocator();
363     LocationsInfo *locations = allocator->New<LocationsInfo>(allocator, inst);
364     // Pointer to the method
365     locations->SetLocation(0, Location::MakeRegister(GetTarget().GetParamRegId(0)));
366     // Launch object
367     locations->SetLocation(1, Location::MakeRegister(GetTarget().GetParamRegId(1)));
368 
369     for (size_t i = 2U; i < inst->GetInputsCount() - 1; i++) {
370         locations->SetLocation(i, Location::MakeStackArgument(i - 2U));
371     }
372     auto stackArgs = inst->GetInputsCount() - 3U;
373     graph->UpdateStackSlotsCount(RoundUp(stackArgs, 2U));
374     locations->SetDstLocation(GetLocationForReturn(inst));
375 }
376 
LOCATIONS_BUILDER(void)377 LOCATIONS_BUILDER(void)::VisitCallResolvedLaunchVirtual(GraphVisitor *visitor, Inst *inst)
378 {
379     auto graph = static_cast<LocationsBuilder *>(visitor)->GetGraph();
380     ArenaAllocator *allocator = graph->GetAllocator();
381     LocationsInfo *locations = allocator->New<LocationsInfo>(allocator, inst);
382     // Pointer to the method
383     locations->SetLocation(0, Location::MakeRegister(GetTarget().GetParamRegId(0)));
384     // Launch object
385     locations->SetLocation(1, Location::MakeRegister(GetTarget().GetParamRegId(1)));
386     // This object
387     locations->SetLocation(2U, Location::MakeRegister(GetTarget().GetParamRegId(3U)));
388 
389     for (size_t i = 3U; i < inst->GetInputsCount() - 1; i++) {
390         locations->SetLocation(i, Location::MakeStackArgument(i - 3U));
391     }
392     auto stackArgs = inst->GetInputsCount() - 4U;
393     graph->UpdateStackSlotsCount(RoundUp(stackArgs, 2U));
394     locations->SetDstLocation(GetLocationForReturn(inst));
395 }
396 
LOCATIONS_BUILDER(void)397 LOCATIONS_BUILDER(void)::VisitStoreStatic([[maybe_unused]] GraphVisitor *visitor, Inst *inst)
398 {
399     if (inst->CastToStoreStatic()->GetNeedBarrier()) {
400         inst->SetFlag(inst_flags::REQUIRE_TMP);
401     }
402 }
403 
404 template <Arch ARCH>
GetLocationForReturn(Inst * inst)405 Location LocationsBuilder<ARCH>::GetLocationForReturn(Inst *inst)
406 {
407     auto returnReg =
408         DataType::IsFloatType(inst->GetType()) ? GetTarget().GetReturnFpRegId() : GetTarget().GetReturnRegId();
409     return Location::MakeRegister(returnReg, inst->GetType());
410 }
411 
412 template <Arch ARCH>
GetResetParameterInfo()413 ParameterInfo *LocationsBuilder<ARCH>::GetResetParameterInfo()
414 {
415     paramsInfo_->Reset();
416     return paramsInfo_;
417 }
418 }  // namespace ark::compiler
419