1 /*
2 * Copyright (c) 2024 Shenzhen Kaihong Digital Industry Development 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 * Copyright (c) 2024 Huawei Device Co., Ltd.
16 * Licensed under the Apache License, Version 2.0 (the "License");
17 * you may not use this file except in compliance with the License.
18 * You may obtain a copy of the License at
19
20 * http://www.apache.org/licenses/LICENSE-2.0
21 *
22 * Unless required by applicable law or agreed to in writing, software
23 * distributed under the License is distributed on an "AS IS" BASIS,
24 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
25 * See the License for the specific language governing permissions and
26 * limitations under the License.
27 */
28
29 #include <gtest/gtest.h>
30 #include <utility>
31 #include <vector>
32
33 #include "graph_test.h"
34 #include "optimizer/analysis/liveness_analyzer.h"
35 #include "optimizer/ir/constants.h"
36 #include "optimizer/ir/graph.h"
37 #include "optimizer/ir/inst.h"
38 #include "optimizer/ir/locations.h"
39 #include "optimizer/optimizations/regalloc/reg_alloc_resolver.h"
40 #include "reg_acc_alloc.h"
41 #include "utils/arena_containers.h"
42
43 using namespace testing::ext;
44
45 namespace panda::compiler {
46 class RegAllocResolverTest : public testing::Test {
47 public:
SetUpTestCase(void)48 static void SetUpTestCase(void) {};
TearDownTestCase(void)49 static void TearDownTestCase(void) {};
SetUp()50 void SetUp() {};
TearDown()51 void TearDown() {};
52
53 GraphTest graph_test_;
54
55 template<typename Callback>
ForEachInst(Graph *graph, Callback cb)56 static void ForEachInst(Graph *graph, Callback cb)
57 {
58 ASSERT(graph != nullptr);
59 for (auto bb : graph->GetBlocksRPO()) {
60 for (auto inst : bb->AllInsts()) {
61 cb(inst);
62 }
63 }
64 }
65
IsIntrinsic(Inst *inst, IntrinsicInst::IntrinsicId id)66 static bool IsIntrinsic(Inst *inst, IntrinsicInst::IntrinsicId id)
67 {
68 return inst->IsIntrinsic() && inst->CastToIntrinsic()->GetIntrinsicId() == id;
69 }
70
InitUsedRegs(Graph *graph, size_t count)71 static void InitUsedRegs(Graph *graph, size_t count)
72 {
73 ASSERT(graph != nullptr);
74 ArenaVector<bool> used_regs(count, false, graph->GetAllocator()->Adapter());
75 graph->InitUsedRegs<DataType::INT64>(&used_regs);
76 }
77 };
78
79 /**
80 * @tc.name: reg_alloc_resolver_test_001
81 * @tc.desc: Verify the AddMoveToFixedLocation function.
82 * @tc.type: FUNC
83 * @tc.require:
84 */
HWTEST_F(RegAllocResolverTest, reg_alloc_resolver_test_001, TestSize.Level1)85 HWTEST_F(RegAllocResolverTest, reg_alloc_resolver_test_001, TestSize.Level1)
86 {
87 std::string pfile = GRAPH_TEST_ABC_DIR "regallocTest.abc";
88 const char *test_method_name = "func4";
89 bool status = false;
90 graph_test_.TestBuildGraphFromFile(pfile, [&test_method_name, &status](Graph* graph, std::string &method_name) {
91 if (test_method_name != method_name) {
92 return;
93 }
94
95 graph->RunPass<LivenessAnalyzer>();
96 auto intervals = graph->GetAnalysis<LivenessAnalyzer>().GetLifeIntervals();
97
98 graph->RunPass<bytecodeopt::RegAccAlloc>();
99
100 // Allocate registers
101 Register preassign_count = 0;
102 for (auto interval : intervals) {
103 interval->SetPreassignedReg(preassign_count++);
104 }
105
106 // Make some insts require a fixed input register, then spillfill insts are expected to be created.
107 Register fixed_input_reg = preassign_count;
108 std::vector<std::pair<Inst*, Register>> pairs;
109 ForEachInst(graph, [&pairs, &fixed_input_reg](Inst *inst) {
110 if (IsIntrinsic(inst, IntrinsicInst::IntrinsicId::ADD2_IMM8_V8) ||
111 IsIntrinsic(inst, IntrinsicInst::IntrinsicId::SUB2_IMM8_V8)) {
112 EXPECT_GE(inst->GetInputsCount(), 2);
113
114 inst->SetLocation(0, Location::MakeRegister(fixed_input_reg));
115 inst->SetLocation(1, Location::MakeRegister(fixed_input_reg + 1));
116 pairs.emplace_back(inst, fixed_input_reg);
117 fixed_input_reg += 2;
118 }
119 });
120 EXPECT_FALSE(pairs.empty());
121
122 // Run resolver
123 InitUsedRegs(graph, 256);
124 RegAllocResolver(graph).Resolve();
125
126 for (auto [inst, input_reg] : pairs) {
127 EXPECT_EQ(inst->GetSrcReg(0), input_reg);
128 EXPECT_EQ(inst->GetSrcReg(1), input_reg + 1);
129
130 auto sf_inst = inst->GetPrev();
131 EXPECT_TRUE(sf_inst != nullptr);
132 EXPECT_TRUE(sf_inst->IsSpillFill());
133 EXPECT_EQ(sf_inst->CastToSpillFill()->GetSpillFillType(), SpillFillType::INPUT_FILL);
134
135 auto sf_data1 = sf_inst->CastToSpillFill()->GetSpillFill(0);
136 EXPECT_EQ(sf_data1.GetSrc(), inst->GetInput(0).GetInst()->GetDstLocation());
137 EXPECT_EQ(sf_data1.GetDst(), inst->GetLocation(0));
138
139 auto sf_data2 = sf_inst->CastToSpillFill()->GetSpillFill(1);
140 EXPECT_EQ(sf_data2.GetSrc(), inst->GetInput(1).GetInst()->GetDstLocation());
141 EXPECT_EQ(sf_data2.GetDst(), inst->GetLocation(1));
142 }
143
144 status = true;
145 });
146 EXPECT_TRUE(status);
147 }
148 } // namespace panda::compiler
149