xref: /llvm-project/llvm/unittests/CodeGen/GlobalISel/LegalizerTest.cpp (revision 387bee91f095c197270b4d0a9e19cc86b2edea73)
1 //===- LegalizerTest.cpp --------------------------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "llvm/CodeGen/GlobalISel/Legalizer.h"
10 #include "GISelMITest.h"
11 #include "llvm/CodeGen/GlobalISel/GISelKnownBits.h"
12 #include "llvm/CodeGen/GlobalISel/LostDebugLocObserver.h"
13 
14 #define DEBUG_TYPE "legalizer-test"
15 
16 using namespace LegalizeActions;
17 using namespace LegalizeMutations;
18 using namespace LegalityPredicates;
19 
20 namespace {
21 
22 ::testing::AssertionResult isNullMIPtr(const MachineInstr *MI) {
23   if (MI == nullptr)
24     return ::testing::AssertionSuccess();
25   std::string MIBuffer;
26   raw_string_ostream MISStream(MIBuffer);
27   MI->print(MISStream, /*IsStandalone=*/true, /*SkipOpers=*/false,
28             /*SkipDebugLoc=*/false, /*AddNewLine=*/false);
29   return ::testing::AssertionFailure()
30          << "unable to legalize instruction: " << MIBuffer;
31 }
32 
33 DefineLegalizerInfo(ALegalizer, {
34   auto p0 = LLT::pointer(0, 64);
35   auto s8 = LLT::scalar(8);
36   auto v2s8 = LLT::fixed_vector(2, 8);
37   auto v2s16 = LLT::fixed_vector(2, 16);
38   getActionDefinitionsBuilder(G_LOAD)
39       .legalForTypesWithMemDesc({{s16, p0, s8, 8}})
40       .scalarize(0)
41       .clampScalar(0, s16, s16);
42   getActionDefinitionsBuilder(G_PTR_ADD).legalFor({{p0, s64}});
43   getActionDefinitionsBuilder(G_CONSTANT).legalFor({s32, s64});
44   getActionDefinitionsBuilder(G_BUILD_VECTOR)
45       .legalFor({{v2s16, s16}})
46       .clampScalar(1, s16, s16);
47   getActionDefinitionsBuilder(G_BUILD_VECTOR_TRUNC).legalFor({{v2s8, s16}});
48   getActionDefinitionsBuilder(G_ANYEXT).legalFor({{s32, s16}});
49   getActionDefinitionsBuilder(G_ZEXT).legalFor({{s32, s16}});
50   getActionDefinitionsBuilder(G_SEXT).legalFor({{s32, s16}});
51   getActionDefinitionsBuilder(G_AND).legalFor({s32});
52   getActionDefinitionsBuilder(G_SEXT_INREG).lower();
53   getActionDefinitionsBuilder(G_ASHR).legalFor({{s32, s32}});
54   getActionDefinitionsBuilder(G_SHL).legalFor({{s32, s32}});
55 })
56 
57 TEST_F(AArch64GISelMITest, BasicLegalizerTest) {
58   StringRef MIRString = R"(
59     %vptr:_(p0) = COPY $x4
60     %v:_(<2 x s8>) = G_LOAD %vptr:_(p0) :: (load (<2 x s8>), align 1)
61     $h4 = COPY %v:_(<2 x s8>)
62   )";
63   setUp(MIRString.rtrim(' '));
64   if (!TM)
65     GTEST_SKIP();
66 
67   ALegalizerInfo LI(MF->getSubtarget());
68   LostDebugLocObserver LocObserver(DEBUG_TYPE);
69   GISelKnownBits KB(*MF);
70 
71   Legalizer::MFResult Result = Legalizer::legalizeMachineFunction(
72       *MF, LI, {&LocObserver}, LocObserver, B, &KB);
73 
74   EXPECT_TRUE(isNullMIPtr(Result.FailedOn));
75   EXPECT_TRUE(Result.Changed);
76 
77   StringRef CheckString = R"(
78     CHECK:      %vptr:_(p0) = COPY $x4
79     CHECK-NEXT: [[LOAD_0:%[0-9]+]]:_(s16) = G_LOAD %vptr:_(p0) :: (load (s8))
80     CHECK-NEXT: [[OFFSET_1:%[0-9]+]]:_(s64) = G_CONSTANT i64 1
81     CHECK-NEXT: [[VPTR_1:%[0-9]+]]:_(p0) = G_PTR_ADD %vptr:_, [[OFFSET_1]]:_(s64)
82     CHECK-NEXT: [[LOAD_1:%[0-9]+]]:_(s16) = G_LOAD [[VPTR_1]]:_(p0) :: (load (s8) from unknown-address + 1)
83     CHECK-NEXT: %v:_(<2 x s8>) = G_BUILD_VECTOR_TRUNC [[LOAD_0]]:_(s16), [[LOAD_1]]:_(s16)
84     CHECK-NEXT: $h4 = COPY %v:_(<2 x s8>)
85   )";
86 
87   EXPECT_TRUE(CheckMachineFunction(*MF, CheckString)) << *MF;
88 }
89 
90 // Making sure the legalization finishes successfully w/o failure to combine
91 // away all the legalization artifacts regardless of the order of their
92 // creation.
93 TEST_F(AArch64GISelMITest, UnorderedArtifactCombiningTest) {
94   StringRef MIRString = R"(
95     %vptr:_(p0) = COPY $x4
96     %v:_(<2 x s8>) = G_LOAD %vptr:_(p0) :: (load (<2 x s8>), align 1)
97     %v0:_(s8), %v1:_(s8) = G_UNMERGE_VALUES %v:_(<2 x s8>)
98     %v0_ext:_(s16) = G_ANYEXT %v0:_(s8)
99     $h4 = COPY %v0_ext:_(s16)
100   )";
101   setUp(MIRString.rtrim(' '));
102   if (!TM)
103     GTEST_SKIP();
104 
105   ALegalizerInfo LI(MF->getSubtarget());
106   LostDebugLocObserver LocObserver(DEBUG_TYPE);
107   GISelKnownBits KB(*MF);
108 
109   // The events here unfold as follows:
110   // 1. First, the function is scanned pre-forming the worklist of artifacts:
111   //
112   //      UNMERGE  (1): pushed into the worklist first, will be processed last.
113   //         |
114   //       ANYEXT  (2)
115   //
116   // 2. Second, the load is scalarized, and then its destination is widened,
117   //    forming the following chain of legalization artifacts:
118   //
119   //        TRUNC  (4): created last, will be processed first.
120   //         |
121   // BUILD_VECTOR  (3)
122   //         |
123   //      UNMERGE  (1): pushed into the worklist first, will be processed last.
124   //         |
125   //       ANYEXT  (2)
126   //
127   // 3. Third, the artifacts are attempted to be combined in pairs, looking
128   //    through the def-use chain from the roots towards the leafs, visiting the
129   //    roots in order they happen to be in the worklist:
130   //      (4) - (trunc):                  can not be combined;
131   //      (3) - (build_vector (trunc)):   can not be combined;
132   //      (2) - (anyext (unmerge)):       can not be combined;
133   //      (1) - (unmerge (build_vector)): combined and eliminated;
134   //
135   //    leaving the function in the following state:
136   //
137   //        TRUNC  (1): moved to non-artifact instructions worklist first.
138   //         |
139   //       ANYEXT  (2): also moved to non-artifact instructions worklist.
140   //
141   //    Every other instruction is successfully legalized in full.
142   //    If combining (unmerge (build_vector)) does not re-insert every artifact
143   //    that had its def-use chain modified (shortened) into the artifact
144   //    worklist (here it's just ANYEXT), the process moves on onto the next
145   //    outer loop iteration of the top-level legalization algorithm here, w/o
146   //    performing all the artifact combines possible. Let's consider this
147   //    scenario first:
148   //  4.A. Neither TRUNC, nor ANYEXT can be legalized in isolation, both of them
149   //       get moved to the retry worklist, but no additional artifacts were
150   //       created in the process, thus algorithm concludes no progress could be
151   //       made, and fails.
152   //  4.B. If, however, combining (unmerge (build_vector)) had re-inserted
153   //       ANYEXT into the worklist (as ANYEXT's source changes, not by value,
154   //       but by implementation), (anyext (trunc)) combine happens next, which
155   //       fully eliminates all the artifacts and legalization succeeds.
156   //
157   //  We're looking into making sure that (4.B) happens here, not (4.A). Note
158   //  that in that case the first scan through the artifacts worklist, while not
159   //  being done in any guaranteed order, only needs to find the innermost
160   //  pair(s) of artifacts that could be immediately combined out. After that
161   //  the process follows def-use chains, making them shorter at each step, thus
162   //  combining everything that can be combined in O(n) time.
163   Legalizer::MFResult Result = Legalizer::legalizeMachineFunction(
164       *MF, LI, {&LocObserver}, LocObserver, B, &KB);
165 
166   EXPECT_TRUE(isNullMIPtr(Result.FailedOn));
167   EXPECT_TRUE(Result.Changed);
168 
169   StringRef CheckString = R"(
170     CHECK:      %vptr:_(p0) = COPY $x4
171     CHECK-NEXT: [[LOAD_0:%[0-9]+]]:_(s16) = G_LOAD %vptr:_(p0) :: (load (s8))
172     CHECK:      $h4 = COPY [[LOAD_0]]:_(s16)
173   )";
174 
175   EXPECT_TRUE(CheckMachineFunction(*MF, CheckString)) << *MF;
176 }
177 
178 TEST_F(AArch64GISelMITest, UnorderedArtifactCombiningManyCopiesTest) {
179   StringRef MIRString = R"(
180     %vptr:_(p0) = COPY $x4
181     %v:_(<2 x s8>) = G_LOAD %vptr:_(p0) :: (load (<2 x s8>), align 1)
182     %vc0:_(<2 x s8>) = COPY %v:_(<2 x s8>)
183     %vc1:_(<2 x s8>) = COPY %v:_(<2 x s8>)
184     %vc00:_(s8), %vc01:_(s8) = G_UNMERGE_VALUES %vc0:_(<2 x s8>)
185     %vc10:_(s8), %vc11:_(s8) = G_UNMERGE_VALUES %vc1:_(<2 x s8>)
186     %v0t:_(s8) = COPY %vc00:_(s8)
187     %v0:_(s8) = COPY %v0t:_(s8)
188     %v1t:_(s8) = COPY %vc11:_(s8)
189     %v1:_(s8) = COPY %v1t:_(s8)
190     %v0_zext:_(s32) = G_ZEXT %v0:_(s8)
191     %v1_sext:_(s32) = G_SEXT %v1:_(s8)
192     $w4 = COPY %v0_zext:_(s32)
193     $w5 = COPY %v1_sext:_(s32)
194   )";
195   setUp(MIRString.rtrim(' '));
196   if (!TM)
197     GTEST_SKIP();
198 
199   ALegalizerInfo LI(MF->getSubtarget());
200   LostDebugLocObserver LocObserver(DEBUG_TYPE);
201   GISelKnownBits KB(*MF);
202 
203   Legalizer::MFResult Result = Legalizer::legalizeMachineFunction(
204       *MF, LI, {&LocObserver}, LocObserver, B, &KB);
205 
206   EXPECT_TRUE(isNullMIPtr(Result.FailedOn));
207   EXPECT_TRUE(Result.Changed);
208 
209   StringRef CheckString = R"(
210     CHECK:      %vptr:_(p0) = COPY $x4
211     CHECK-NEXT: [[LOAD_0:%[0-9]+]]:_(s16) = G_LOAD %vptr:_(p0) :: (load (s8))
212     CHECK-NEXT: [[OFFSET_1:%[0-9]+]]:_(s64) = G_CONSTANT i64 1
213     CHECK-NEXT: [[VPTR_1:%[0-9]+]]:_(p0) = G_PTR_ADD %vptr:_, [[OFFSET_1]]:_(s64)
214     CHECK-NEXT: [[LOAD_1:%[0-9]+]]:_(s16) = G_LOAD [[VPTR_1]]:_(p0) :: (load (s8) from unknown-address + 1)
215     CHECK-NEXT: [[V0_EXT:%[0-9]+]]:_(s32) = G_ANYEXT [[LOAD_0]]:_(s16)
216     CHECK-NEXT: [[FF_MASK:%[0-9]+]]:_(s32) = G_CONSTANT i32 255
217     CHECK-NEXT: %v0_zext:_(s32) = G_AND [[V0_EXT]]:_, [[FF_MASK]]:_
218     CHECK-NEXT: [[V1_EXT:%[0-9]+]]:_(s32) = G_ANYEXT [[LOAD_1]]:_(s16)
219     CHECK-NEXT: [[SHAMNT:%[0-9]+]]:_(s32) = G_CONSTANT i32 24
220     CHECK-NEXT: [[V1_SHL:%[0-9]+]]:_(s32) = G_SHL [[V1_EXT]]:_, [[SHAMNT]]:_(s32)
221     CHECK-NEXT: %v1_sext:_(s32) = G_ASHR [[V1_SHL]]:_, [[SHAMNT]]:_(s32)
222     CHECK-NEXT: $w4 = COPY %v0_zext:_(s32)
223     CHECK-NEXT: $w5 = COPY %v1_sext:_(s32)
224   )";
225 
226   EXPECT_TRUE(CheckMachineFunction(*MF, CheckString)) << *MF;
227 }
228 
229 } // namespace
230