• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "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         if (i == 0U && inst->GetOpcode() == Opcode::CallNative) {
87             // NOTE: this is a hack for workarounding regalloc bug (i.e. this input can get some parameter register
88             // location by mistake)!
89             ASSERT(locations != nullptr);
90             locations->SetLocation(0U, Location::MakeRegister(GetFirstCalleeReg(GetGraph()->GetArch(), false)));
91             continue;
92         }
93         auto param = pinfo->GetNextLocation(inst->GetInputType(i));
94         if (i == 0 && inst->IsIntrinsic() && inst->CastToIntrinsic()->HasIdInput()) {
95             param = Location::MakeRegister(GetTarget().GetParamRegId(0));  // place id input before imms
96         }
97         locations->SetLocation(i, param);
98         if (param.IsStackArgument()) {
99             stackArgs++;
100         }
101     }
102     if (inst->IsIntrinsic() && stackArgs > 0) {
103         inst->CastToIntrinsic()->SetArgumentsOnStack();
104     }
105     if (!inst->NoDest()) {
106         locations->SetDstLocation(GetLocationForReturn(inst));
107     }
108 
109     GetGraph()->UpdateStackSlotsCount(stackArgs);
110 }
111 
LOCATIONS_BUILDER(void)112 LOCATIONS_BUILDER(void)::ProcessManagedCallStackRange(Inst *inst, size_t rangeStart, ParameterInfo *pinfo)
113 {
114     ArenaAllocator *allocator = GetGraph()->GetAllocator();
115     LocationsInfo *locations = allocator->New<LocationsInfo>(allocator, inst);
116 
117     /* Reserve first parameter for the callee method. It will be set by codegen. */
118     if (pinfo == nullptr) {
119         pinfo = GetResetParameterInfo();
120         pinfo->GetNextLocation(GetWordType());
121     }
122 
123     size_t inputsCount = inst->GetInputsCount() - (inst->RequireState() ? 1 : 0);
124     size_t stackArgs = 0;
125     ASSERT(inputsCount >= rangeStart);
126     for (size_t i = 0; i < rangeStart; i++) {
127         ASSERT(inst->GetInputType(i) != DataType::NO_TYPE);
128         auto param = pinfo->GetNextLocation(inst->GetInputType(i));
129         ASSERT(locations != nullptr);
130         locations->SetLocation(i, param);
131         if (param.IsStackArgument()) {
132             stackArgs++;
133         }
134     }
135     if (inst->IsIntrinsic() && stackArgs > 0) {
136         inst->CastToIntrinsic()->SetArgumentsOnStack();
137     }
138     for (size_t i = rangeStart; i < inputsCount; i++) {
139         locations->SetLocation(i, Location::MakeStackArgument(stackArgs++));
140     }
141     locations->SetDstLocation(GetLocationForReturn(inst));
142     GetGraph()->UpdateStackSlotsCount(stackArgs);
143 }
144 
LOCATIONS_BUILDER(void)145 LOCATIONS_BUILDER(void)::VisitResolveStatic([[maybe_unused]] GraphVisitor *visitor, Inst *inst)
146 {
147     inst->CastToResolveStatic()->SetDstLocation(GetLocationForReturn(inst));
148 }
149 
LOCATIONS_BUILDER(void)150 LOCATIONS_BUILDER(void)::VisitCallResolvedStatic(GraphVisitor *visitor, Inst *inst)
151 {
152     if (inst->CastToCallResolvedStatic()->IsInlined()) {
153         return;
154     }
155     static_cast<LocationsBuilder *>(visitor)->ProcessManagedCall(inst);
156 }
157 
LOCATIONS_BUILDER(void)158 LOCATIONS_BUILDER(void)::VisitResolveVirtual([[maybe_unused]] GraphVisitor *visitor, Inst *inst)
159 {
160     inst->CastToResolveVirtual()->SetDstLocation(GetLocationForReturn(inst));
161 }
162 
LOCATIONS_BUILDER(void)163 LOCATIONS_BUILDER(void)::VisitCallResolvedVirtual(GraphVisitor *visitor, Inst *inst)
164 {
165     if (inst->CastToCallResolvedVirtual()->IsInlined()) {
166         return;
167     }
168     static_cast<LocationsBuilder *>(visitor)->ProcessManagedCall(inst);
169 }
170 
LOCATIONS_BUILDER(void)171 LOCATIONS_BUILDER(void)::VisitCallStatic(GraphVisitor *visitor, Inst *inst)
172 {
173     if (inst->CastToCallStatic()->IsInlined()) {
174         return;
175     }
176     static_cast<LocationsBuilder *>(visitor)->ProcessManagedCall(inst);
177 }
178 
LOCATIONS_BUILDER(void)179 LOCATIONS_BUILDER(void)::VisitCallVirtual(GraphVisitor *visitor, Inst *inst)
180 {
181     if (inst->CastToCallVirtual()->IsInlined()) {
182         return;
183     }
184     static_cast<LocationsBuilder *>(visitor)->ProcessManagedCall(inst);
185 }
186 
LOCATIONS_BUILDER(void)187 LOCATIONS_BUILDER(void)::VisitCallDynamic(GraphVisitor *visitor, Inst *inst)
188 {
189     ArenaAllocator *allocator = static_cast<LocationsBuilder *>(visitor)->GetGraph()->GetAllocator();
190     LocationsInfo *locations = allocator->New<LocationsInfo>(allocator, inst);
191 
192     if (inst->CastToCallDynamic()->IsInlined()) {
193         ASSERT(inst->GetInputType(CallConvDynInfo::REG_METHOD) == DataType::ANY);
194         auto param = Location::MakeRegister(GetTarget().GetParamRegId(CallConvDynInfo::REG_METHOD));
195         locations->SetLocation(CallConvDynInfo::REG_METHOD, param);
196         return;
197     }
198 
199     auto pinfo = static_cast<LocationsBuilder *>(visitor)->GetResetParameterInfo();
200     for (uint8_t i = 0; i < CallConvDynInfo::REG_COUNT; i++) {
201         [[maybe_unused]] Location loc = pinfo->GetNextLocation(GetWordType());
202         ASSERT(loc.IsRegister());
203     }
204     size_t inputsCount = inst->GetInputsCount() - (inst->RequireState() ? 1 : 0);
205 
206     for (size_t i = 0; i < inputsCount; ++i) {
207         ASSERT(inst->GetInputType(i) == DataType::ANY);
208         auto param = Location::MakeStackArgument(i + CallConvDynInfo::FIXED_SLOT_COUNT);
209         locations->SetLocation(i, param);
210     }
211     locations->SetDstLocation(GetLocationForReturn(inst));
212     static_cast<LocationsBuilder *>(visitor)->GetGraph()->UpdateStackSlotsCount(inputsCount);
213 }
214 
LOCATIONS_BUILDER(void)215 LOCATIONS_BUILDER(void)::VisitCallIndirect(GraphVisitor *visitor, Inst *inst)
216 {
217     ArenaAllocator *allocator = static_cast<LocationsBuilder *>(visitor)->GetGraph()->GetAllocator();
218     LocationsInfo *locations = allocator->New<LocationsInfo>(allocator, inst);
219     auto params = static_cast<LocationsBuilder *>(visitor)->GetResetParameterInfo();
220 
221     /* First input is an address of the memory to call. So it hasn't exact location and maybe be any register */
222     ASSERT(locations != nullptr);
223     locations->SetLocation(0, Location::RequireRegister());
224 
225     /* Inputs, starting from 1, are the native call arguments */
226     for (size_t i = 1; i < inst->GetInputsCount(); i++) {
227         auto param = params->GetNextLocation(inst->GetInputType(i));
228         locations->SetLocation(i, param);
229     }
230     if (!inst->NoDest()) {
231         locations->SetDstLocation(GetLocationForReturn(inst));
232     }
233 }
234 
LOCATIONS_BUILDER(void)235 LOCATIONS_BUILDER(void)::VisitCall(GraphVisitor *visitor, Inst *inst)
236 {
237     ArenaAllocator *allocator = static_cast<LocationsBuilder *>(visitor)->GetGraph()->GetAllocator();
238     LocationsInfo *locations = allocator->New<LocationsInfo>(allocator, inst);
239     auto params = static_cast<LocationsBuilder *>(visitor)->GetResetParameterInfo();
240 
241     for (size_t i = 0; i < inst->GetInputsCount(); i++) {
242         auto param = params->GetNextLocation(inst->GetInputType(i));
243         ASSERT(locations != nullptr);
244         locations->SetLocation(i, param);
245     }
246     if (!inst->NoDest()) {
247         locations->SetDstLocation(GetLocationForReturn(inst));
248     }
249 }
250 
LOCATIONS_BUILDER(void)251 LOCATIONS_BUILDER(void)::VisitIntrinsic(GraphVisitor *visitor, Inst *inst)
252 {
253     auto graph = static_cast<LocationsBuilder *>(visitor)->GetGraph();
254     auto intrinsic = inst->CastToIntrinsic();
255     auto id = intrinsic->GetIntrinsicId();
256     if (intrinsic->IsNativeCall() || IntrinsicNeedsParamLocations(id)) {
257         auto pinfo = static_cast<LocationsBuilder *>(visitor)->GetResetParameterInfo();
258         if (intrinsic->IsMethodFirstInput()) {
259             pinfo->GetNextLocation(GetWordType());
260         }
261         if (intrinsic->HasImms() && graph->SupportManagedCode()) {
262             for ([[maybe_unused]] auto imm : intrinsic->GetImms()) {
263                 pinfo->GetNextLocation(DataType::INT32);
264             }
265         }
266         size_t explicitArgs;
267         if (IsStackRangeIntrinsic(id, &explicitArgs)) {
268             static_cast<LocationsBuilder *>(visitor)->ProcessManagedCallStackRange(inst, explicitArgs, pinfo);
269         } else {
270             static_cast<LocationsBuilder *>(visitor)->ProcessManagedCall(inst, pinfo);
271         }
272         return;
273     }
274     ArenaAllocator *allocator = static_cast<LocationsBuilder *>(visitor)->GetGraph()->GetAllocator();
275     LocationsInfo *locations = allocator->New<LocationsInfo>(allocator, inst);
276     auto inputsCount = inst->GetInputsCount() - (inst->RequireState() ? 1 : 0);
277     for (size_t i = 0; i < inputsCount; i++) {
278         ASSERT(locations != nullptr);
279         locations->SetLocation(i, Location::RequireRegister());
280     }
281 }
282 
LOCATIONS_BUILDER(void)283 LOCATIONS_BUILDER(void)::VisitCallNative(GraphVisitor *visitor, Inst *inst)
284 {
285     auto *pinfo = static_cast<LocationsBuilder *>(visitor)->GetResetParameterInfo();
286     static_cast<LocationsBuilder *>(visitor)->ProcessManagedCall(inst, pinfo);
287 }
288 
LOCATIONS_BUILDER(void)289 LOCATIONS_BUILDER(void)::VisitNewArray([[maybe_unused]] GraphVisitor *visitor, Inst *inst)
290 {
291     inst->CastToNewArray()->SetLocation(0, Location::MakeRegister(GetTarget().GetParamRegId(0)));
292     inst->CastToNewArray()->SetLocation(1, Location::MakeRegister(GetTarget().GetParamRegId(1)));
293     inst->CastToNewArray()->SetDstLocation(GetLocationForReturn(inst));
294 }
295 
LOCATIONS_BUILDER(void)296 LOCATIONS_BUILDER(void)::VisitNewObject([[maybe_unused]] GraphVisitor *visitor, Inst *inst)
297 {
298     inst->CastToNewObject()->SetLocation(0, Location::MakeRegister(GetTarget().GetParamRegId(0)));
299     inst->CastToNewObject()->SetDstLocation(GetLocationForReturn(inst));
300 }
301 
LOCATIONS_BUILDER(void)302 LOCATIONS_BUILDER(void)::VisitParameter([[maybe_unused]] GraphVisitor *visitor, [[maybe_unused]] Inst *inst)
303 {
304     /* Currently we can't process parameters in the Locations Builder, because Parameter instructions may be removed
305      * during optimizations pipeline. Thus, locations is set by IR builder before optimizations.
306      * NOTE(compiler): we need to move Parameters' locations here, thereby we get rid of arch structures in the Graph,
307      * such as ParameterInfo, CallingConvention, etc.
308      */
309 }
310 
LOCATIONS_BUILDER(void)311 LOCATIONS_BUILDER(void)::VisitReturn([[maybe_unused]] GraphVisitor *visitor, Inst *inst)
312 {
313     auto returnReg =
314         DataType::IsFloatType(inst->GetType()) ? GetTarget().GetReturnRegId() : GetTarget().GetReturnFpRegId();
315     inst->CastToReturn()->SetLocation(0, Location::MakeRegister(returnReg));
316 }
317 
LOCATIONS_BUILDER(void)318 LOCATIONS_BUILDER(void)::VisitThrow([[maybe_unused]] GraphVisitor *visitor, Inst *inst)
319 {
320     inst->CastToThrow()->SetLocation(0, Location::MakeRegister(GetTarget().GetParamRegId(0)));
321 }
322 
LOCATIONS_BUILDER(void)323 LOCATIONS_BUILDER(void)::VisitLiveOut([[maybe_unused]] GraphVisitor *visitor, Inst *inst)
324 {
325     inst->CastToLiveOut()->SetLocation(0, Location::MakeRegister(inst->GetDstReg()));
326 }
327 
LOCATIONS_BUILDER(void)328 LOCATIONS_BUILDER(void)::VisitMultiArray(GraphVisitor *visitor, Inst *inst)
329 {
330     auto graph = static_cast<LocationsBuilder *>(visitor)->GetGraph();
331     ArenaAllocator *allocator = graph->GetAllocator();
332     LocationsInfo *locations = allocator->New<LocationsInfo>(allocator, inst);
333     ASSERT(locations != nullptr);
334     locations->SetLocation(0, Location::RequireRegister());
335 
336     for (size_t i = 1; i < inst->GetInputsCount() - 1; i++) {
337         locations->SetLocation(i, Location::MakeStackArgument(i - 1));
338     }
339     auto stackArgs = inst->GetInputsCount() - 2U;
340     graph->UpdateStackSlotsCount(RoundUp(stackArgs, 2U));
341     locations->SetDstLocation(GetLocationForReturn(inst));
342 }
343 
LOCATIONS_BUILDER(void)344 LOCATIONS_BUILDER(void)::VisitStoreStatic([[maybe_unused]] GraphVisitor *visitor, Inst *inst)
345 {
346     if (inst->CastToStoreStatic()->GetNeedBarrier()) {
347         inst->SetFlag(inst_flags::REQUIRE_TMP);
348     }
349 }
350 
LOCATIONS_BUILDER(void)351 LOCATIONS_BUILDER(void)::VisitResolveByName([[maybe_unused]] GraphVisitor *visitor, Inst *inst)
352 {
353     inst->CastToResolveByName()->SetDstLocation(GetLocationForReturn(inst));
354 }
355 
356 template <Arch ARCH>
GetLocationForReturn(Inst * inst)357 Location LocationsBuilder<ARCH>::GetLocationForReturn(Inst *inst)
358 {
359     auto returnReg =
360         DataType::IsFloatType(inst->GetType()) ? GetTarget().GetReturnFpRegId() : GetTarget().GetReturnRegId();
361     return Location::MakeRegister(returnReg, inst->GetType());
362 }
363 
364 template <Arch ARCH>
GetResetParameterInfo()365 ParameterInfo *LocationsBuilder<ARCH>::GetResetParameterInfo()
366 {
367     paramsInfo_->Reset();
368     return paramsInfo_;
369 }
370 }  // namespace ark::compiler
371