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 
31 #include "graph_test.h"
32 #include "optimizer/ir/basicblock.h"
33 #include "optimizer/ir/constants.h"
34 #include "optimizer/ir/datatype.h"
35 #include "optimizer/ir/graph.h"
36 #include "optimizer/ir/inst.h"
37 #include "optimizer/ir/spill_fill_data.h"
38 #include "optimizer/optimizations/regalloc/spill_fills_resolver.h"
39 #include "tests/graph_comparator.h"
40 #include "utils/arch.h"
41 #include "utils/arena_containers.h"
42 
43 using namespace testing::ext;
44 
45 namespace panda::compiler {
46 class SpillFillsResolverTest : 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 
CreateGraphWithStart(Arch arch = Arch::NONE)53     static Graph* CreateGraphWithStart(Arch arch = Arch::NONE)
54     {
55         auto allocator = new ArenaAllocator(SpaceType::SPACE_TYPE_COMPILER);
56         auto local_allocator = new ArenaAllocator(SpaceType::SPACE_TYPE_COMPILER);
57         auto graph = allocator->New<Graph>(allocator, local_allocator, arch);
58         graph->CreateStartBlock();
59         return graph;
60     }
61 
InitUsedRegs(Graph *graph, size_t count)62     static void InitUsedRegs(Graph *graph, size_t count)
63     {
64         ASSERT(graph != nullptr);
65         ArenaVector<bool> used_regs(count, false, graph->GetAllocator()->Adapter());
66         graph->InitUsedRegs<DataType::INT64>(&used_regs);
67     }
68 };
69 
70 /**
71  * @tc.name: spill_fills_resolver_test_001
72  * @tc.desc: Verify resolve move overwrite.
73  * @tc.type: FUNC
74  * @tc.require:
75  */
HWTEST_F(SpillFillsResolverTest, spill_fills_resolver_test_001, TestSize.Level1)76 HWTEST_F(SpillFillsResolverTest, spill_fills_resolver_test_001, TestSize.Level1)
77 {
78     auto graph = CreateGraphWithStart();
79     auto sf_inst = graph->CreateInstSpillFill();
80     sf_inst->AddMove(0, 1, DataType::INT32);
81     sf_inst->AddMove(1, 2, DataType::INT32);
82 
83     auto expect_sf_inst = graph->CreateInstSpillFill();
84     expect_sf_inst->AddMove(1, 2, DataType::INT32);
85     expect_sf_inst->AddMove(0, 1, DataType::INT32);
86 
87     SpillFillsResolver resolver(graph);
88     resolver.VisitInstruction(sf_inst);
89 
90     EXPECT_TRUE(GraphComparator().Compare(sf_inst, expect_sf_inst));
91 }
92 
93 /**
94  * @tc.name: spill_fills_resolver_test_002
95  * @tc.desc: Verify resolve stack overwrite.
96  * @tc.type: FUNC
97  * @tc.require:
98  */
HWTEST_F(SpillFillsResolverTest, spill_fills_resolver_test_002, TestSize.Level1)99 HWTEST_F(SpillFillsResolverTest, spill_fills_resolver_test_002, TestSize.Level1)
100 {
101     auto graph = CreateGraphWithStart();
102     graph->SetStackSlotsCount(3);
103     auto sf_inst = graph->CreateInstSpillFill();
104     sf_inst->AddMemCopy(0, 1, DataType::FLOAT64);
105     sf_inst->AddMemCopy(1, 2, DataType::FLOAT64);
106 
107     auto expect_sf_inst = graph->CreateInstSpillFill();
108     expect_sf_inst->AddMemCopy(1, 2, DataType::FLOAT64);
109     expect_sf_inst->AddMemCopy(0, 1, DataType::FLOAT64);
110 
111     SpillFillsResolver resolver(graph, INVALID_REG, 0, 3);
112     resolver.ResolveIfRequired(sf_inst);
113 
114     EXPECT_TRUE(GraphComparator().Compare(sf_inst, expect_sf_inst));
115 }
116 
117 /**
118  * @tc.name: spill_fills_resolver_test_003
119  * @tc.desc: Verify resolve cyclic move overwrite.
120  * @tc.type: FUNC
121  * @tc.require:
122  */
HWTEST_F(SpillFillsResolverTest, spill_fills_resolver_test_003, TestSize.Level1)123 HWTEST_F(SpillFillsResolverTest, spill_fills_resolver_test_003, TestSize.Level1)
124 {
125     auto graph = CreateGraphWithStart();
126     auto sf_inst = graph->CreateInstSpillFill();
127     sf_inst->AddMove(3, 1, DataType::FLOAT64);
128     sf_inst->AddMove(2, 3, DataType::FLOAT64);
129     sf_inst->AddMove(1, 2, DataType::FLOAT64);
130 
131     auto expect_sf_inst = graph->CreateInstSpillFill();
132     expect_sf_inst->AddMove(1, 0, DataType::FLOAT64);
133     expect_sf_inst->AddMove(3, 1, DataType::FLOAT64);
134     expect_sf_inst->AddMove(2, 3, DataType::FLOAT64);
135     expect_sf_inst->AddMove(0, 2, DataType::FLOAT64);
136 
137     SpillFillsResolver resolver(graph, INVALID_REG, 0, 5);
138     resolver.VisitInstruction(sf_inst);
139 
140     EXPECT_TRUE(GraphComparator().Compare(sf_inst, expect_sf_inst));
141 }
142 
143 /**
144  * @tc.name: spill_fills_resolver_test_004
145  * @tc.desc: Verify resolve cyclic move overwrite with preassigned resolver register.
146  * @tc.type: FUNC
147  * @tc.require:
148  */
HWTEST_F(SpillFillsResolverTest, spill_fills_resolver_test_004, TestSize.Level1)149 HWTEST_F(SpillFillsResolverTest, spill_fills_resolver_test_004, TestSize.Level1)
150 {
151     auto graph = CreateGraphWithStart();
152     InitUsedRegs(graph, 6);
153     auto sf_inst = graph->CreateInstSpillFill();
154     sf_inst->AddMove(3, 1, DataType::INT32);
155     sf_inst->AddMove(2, 3, DataType::INT32);
156     sf_inst->AddMove(1, 2, DataType::INT32);
157 
158     auto expect_sf_inst = graph->CreateInstSpillFill();
159     expect_sf_inst->AddMove(1, 5, DataType::INT32);
160     expect_sf_inst->AddMove(3, 1, DataType::INT32);
161     expect_sf_inst->AddMove(2, 3, DataType::INT32);
162     expect_sf_inst->AddMove(5, 2, DataType::INT32);
163 
164     SpillFillsResolver resolver(graph, 5, 6, 0);
165     resolver.VisitInstruction(sf_inst);
166 
167     EXPECT_TRUE(GraphComparator().Compare(sf_inst, expect_sf_inst));
168 }
169 
170 /**
171  * @tc.name: spill_fills_resolver_test_005
172  * @tc.desc: Verify resolve cyclic move overwrite on AARCH32.
173  * @tc.type: FUNC
174  * @tc.require:
175  */
HWTEST_F(SpillFillsResolverTest, spill_fills_resolver_test_005, TestSize.Level1)176 HWTEST_F(SpillFillsResolverTest, spill_fills_resolver_test_005, TestSize.Level1)
177 {
178     auto graph = CreateGraphWithStart(Arch::AARCH32);
179     graph->SetStackSlotsCount(1);
180     auto sf_inst = graph->CreateInstSpillFill();
181     sf_inst->AddMove(3, 1, DataType::FLOAT64);
182     sf_inst->AddMove(2, 3, DataType::FLOAT64);
183     sf_inst->AddMove(1, 2, DataType::FLOAT64);
184 
185     auto expect_sf_inst = graph->CreateInstSpillFill();
186     expect_sf_inst->AddSpill(1, 0, DataType::FLOAT64);
187     expect_sf_inst->AddMove(3, 1, DataType::FLOAT64);
188     expect_sf_inst->AddMove(2, 3, DataType::FLOAT64);
189     expect_sf_inst->AddFill(0, 2, DataType::FLOAT64);
190 
191     SpillFillsResolver resolver(graph, INVALID_REG, 0, 5);
192     resolver.VisitInstruction(sf_inst);
193 
194     EXPECT_TRUE(GraphComparator().Compare(sf_inst, expect_sf_inst));
195 }
196 }  // namespace panda::compiler
197