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