xref: /llvm-project/llvm/unittests/CodeGen/GlobalISel/LegalizerTest.cpp (revision 387bee91f095c197270b4d0a9e19cc86b2edea73)
118bf9670SRoman Tereshin //===- LegalizerTest.cpp --------------------------------------------------===//
218bf9670SRoman Tereshin //
318bf9670SRoman Tereshin // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
418bf9670SRoman Tereshin // See https://llvm.org/LICENSE.txt for license information.
518bf9670SRoman Tereshin // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
618bf9670SRoman Tereshin //
718bf9670SRoman Tereshin //===----------------------------------------------------------------------===//
818bf9670SRoman Tereshin 
918bf9670SRoman Tereshin #include "llvm/CodeGen/GlobalISel/Legalizer.h"
10d9085f65SDaniel Sanders #include "GISelMITest.h"
11fc672b6aSJessica Del #include "llvm/CodeGen/GlobalISel/GISelKnownBits.h"
12d9085f65SDaniel Sanders #include "llvm/CodeGen/GlobalISel/LostDebugLocObserver.h"
13d9085f65SDaniel Sanders 
14d9085f65SDaniel Sanders #define DEBUG_TYPE "legalizer-test"
1518bf9670SRoman Tereshin 
1618bf9670SRoman Tereshin using namespace LegalizeActions;
1718bf9670SRoman Tereshin using namespace LegalizeMutations;
1818bf9670SRoman Tereshin using namespace LegalityPredicates;
1918bf9670SRoman Tereshin 
2018bf9670SRoman Tereshin namespace {
2118bf9670SRoman Tereshin 
2218bf9670SRoman Tereshin ::testing::AssertionResult isNullMIPtr(const MachineInstr *MI) {
2318bf9670SRoman Tereshin   if (MI == nullptr)
2418bf9670SRoman Tereshin     return ::testing::AssertionSuccess();
2518bf9670SRoman Tereshin   std::string MIBuffer;
2618bf9670SRoman Tereshin   raw_string_ostream MISStream(MIBuffer);
2718bf9670SRoman Tereshin   MI->print(MISStream, /*IsStandalone=*/true, /*SkipOpers=*/false,
2818bf9670SRoman Tereshin             /*SkipDebugLoc=*/false, /*AddNewLine=*/false);
2918bf9670SRoman Tereshin   return ::testing::AssertionFailure()
30*387bee91SJOE1994          << "unable to legalize instruction: " << MIBuffer;
3118bf9670SRoman Tereshin }
3218bf9670SRoman Tereshin 
3318bf9670SRoman Tereshin DefineLegalizerInfo(ALegalizer, {
3418bf9670SRoman Tereshin   auto p0 = LLT::pointer(0, 64);
3528f2f662SMatt Arsenault   auto s8 = LLT::scalar(8);
36d5e14ba8SSander de Smalen   auto v2s8 = LLT::fixed_vector(2, 8);
37d5e14ba8SSander de Smalen   auto v2s16 = LLT::fixed_vector(2, 16);
3818bf9670SRoman Tereshin   getActionDefinitionsBuilder(G_LOAD)
3928f2f662SMatt Arsenault       .legalForTypesWithMemDesc({{s16, p0, s8, 8}})
4018bf9670SRoman Tereshin       .scalarize(0)
4118bf9670SRoman Tereshin       .clampScalar(0, s16, s16);
4218bf9670SRoman Tereshin   getActionDefinitionsBuilder(G_PTR_ADD).legalFor({{p0, s64}});
438731799fSRoman Tereshin   getActionDefinitionsBuilder(G_CONSTANT).legalFor({s32, s64});
4418bf9670SRoman Tereshin   getActionDefinitionsBuilder(G_BUILD_VECTOR)
4518bf9670SRoman Tereshin       .legalFor({{v2s16, s16}})
4618bf9670SRoman Tereshin       .clampScalar(1, s16, s16);
4718bf9670SRoman Tereshin   getActionDefinitionsBuilder(G_BUILD_VECTOR_TRUNC).legalFor({{v2s8, s16}});
4818bf9670SRoman Tereshin   getActionDefinitionsBuilder(G_ANYEXT).legalFor({{s32, s16}});
498731799fSRoman Tereshin   getActionDefinitionsBuilder(G_ZEXT).legalFor({{s32, s16}});
508731799fSRoman Tereshin   getActionDefinitionsBuilder(G_SEXT).legalFor({{s32, s16}});
518731799fSRoman Tereshin   getActionDefinitionsBuilder(G_AND).legalFor({s32});
528731799fSRoman Tereshin   getActionDefinitionsBuilder(G_SEXT_INREG).lower();
538731799fSRoman Tereshin   getActionDefinitionsBuilder(G_ASHR).legalFor({{s32, s32}});
548731799fSRoman Tereshin   getActionDefinitionsBuilder(G_SHL).legalFor({{s32, s32}});
55d76202d3SSimon Pilgrim })
5618bf9670SRoman Tereshin 
5758f843a5SMatt Arsenault TEST_F(AArch64GISelMITest, BasicLegalizerTest) {
588731799fSRoman Tereshin   StringRef MIRString = R"(
598731799fSRoman Tereshin     %vptr:_(p0) = COPY $x4
60fae05692SMatt Arsenault     %v:_(<2 x s8>) = G_LOAD %vptr:_(p0) :: (load (<2 x s8>), align 1)
618731799fSRoman Tereshin     $h4 = COPY %v:_(<2 x s8>)
628731799fSRoman Tereshin   )";
6342a84d22SDaniel Sanders   setUp(MIRString.rtrim(' '));
648731799fSRoman Tereshin   if (!TM)
657fc87159SPaul Robinson     GTEST_SKIP();
668731799fSRoman Tereshin 
6718bf9670SRoman Tereshin   ALegalizerInfo LI(MF->getSubtarget());
68d9085f65SDaniel Sanders   LostDebugLocObserver LocObserver(DEBUG_TYPE);
69fc672b6aSJessica Del   GISelKnownBits KB(*MF);
7018bf9670SRoman Tereshin 
71d9085f65SDaniel Sanders   Legalizer::MFResult Result = Legalizer::legalizeMachineFunction(
72fc672b6aSJessica Del       *MF, LI, {&LocObserver}, LocObserver, B, &KB);
7318bf9670SRoman Tereshin 
7418bf9670SRoman Tereshin   EXPECT_TRUE(isNullMIPtr(Result.FailedOn));
7518bf9670SRoman Tereshin   EXPECT_TRUE(Result.Changed);
7618bf9670SRoman Tereshin 
7718bf9670SRoman Tereshin   StringRef CheckString = R"(
7818bf9670SRoman Tereshin     CHECK:      %vptr:_(p0) = COPY $x4
79fae05692SMatt Arsenault     CHECK-NEXT: [[LOAD_0:%[0-9]+]]:_(s16) = G_LOAD %vptr:_(p0) :: (load (s8))
8018bf9670SRoman Tereshin     CHECK-NEXT: [[OFFSET_1:%[0-9]+]]:_(s64) = G_CONSTANT i64 1
8118bf9670SRoman Tereshin     CHECK-NEXT: [[VPTR_1:%[0-9]+]]:_(p0) = G_PTR_ADD %vptr:_, [[OFFSET_1]]:_(s64)
82fae05692SMatt Arsenault     CHECK-NEXT: [[LOAD_1:%[0-9]+]]:_(s16) = G_LOAD [[VPTR_1]]:_(p0) :: (load (s8) from unknown-address + 1)
832bf4eeeeSPetar Avramovic     CHECK-NEXT: %v:_(<2 x s8>) = G_BUILD_VECTOR_TRUNC [[LOAD_0]]:_(s16), [[LOAD_1]]:_(s16)
8418bf9670SRoman Tereshin     CHECK-NEXT: $h4 = COPY %v:_(<2 x s8>)
8518bf9670SRoman Tereshin   )";
8618bf9670SRoman Tereshin 
8718bf9670SRoman Tereshin   EXPECT_TRUE(CheckMachineFunction(*MF, CheckString)) << *MF;
8818bf9670SRoman Tereshin }
8918bf9670SRoman Tereshin 
908731799fSRoman Tereshin // Making sure the legalization finishes successfully w/o failure to combine
918731799fSRoman Tereshin // away all the legalization artifacts regardless of the order of their
928731799fSRoman Tereshin // creation.
9358f843a5SMatt Arsenault TEST_F(AArch64GISelMITest, UnorderedArtifactCombiningTest) {
948731799fSRoman Tereshin   StringRef MIRString = R"(
958731799fSRoman Tereshin     %vptr:_(p0) = COPY $x4
96fae05692SMatt Arsenault     %v:_(<2 x s8>) = G_LOAD %vptr:_(p0) :: (load (<2 x s8>), align 1)
978731799fSRoman Tereshin     %v0:_(s8), %v1:_(s8) = G_UNMERGE_VALUES %v:_(<2 x s8>)
988731799fSRoman Tereshin     %v0_ext:_(s16) = G_ANYEXT %v0:_(s8)
998731799fSRoman Tereshin     $h4 = COPY %v0_ext:_(s16)
1008731799fSRoman Tereshin   )";
10142a84d22SDaniel Sanders   setUp(MIRString.rtrim(' '));
1028731799fSRoman Tereshin   if (!TM)
1037fc87159SPaul Robinson     GTEST_SKIP();
1048731799fSRoman Tereshin 
1058731799fSRoman Tereshin   ALegalizerInfo LI(MF->getSubtarget());
106d9085f65SDaniel Sanders   LostDebugLocObserver LocObserver(DEBUG_TYPE);
107fc672b6aSJessica Del   GISelKnownBits KB(*MF);
1088731799fSRoman Tereshin 
1098731799fSRoman Tereshin   // The events here unfold as follows:
1108731799fSRoman Tereshin   // 1. First, the function is scanned pre-forming the worklist of artifacts:
1118731799fSRoman Tereshin   //
1128731799fSRoman Tereshin   //      UNMERGE  (1): pushed into the worklist first, will be processed last.
1138731799fSRoman Tereshin   //         |
1148731799fSRoman Tereshin   //       ANYEXT  (2)
1158731799fSRoman Tereshin   //
1168731799fSRoman Tereshin   // 2. Second, the load is scalarized, and then its destination is widened,
1178731799fSRoman Tereshin   //    forming the following chain of legalization artifacts:
1188731799fSRoman Tereshin   //
1198731799fSRoman Tereshin   //        TRUNC  (4): created last, will be processed first.
1208731799fSRoman Tereshin   //         |
1218731799fSRoman Tereshin   // BUILD_VECTOR  (3)
1228731799fSRoman Tereshin   //         |
1238731799fSRoman Tereshin   //      UNMERGE  (1): pushed into the worklist first, will be processed last.
1248731799fSRoman Tereshin   //         |
1258731799fSRoman Tereshin   //       ANYEXT  (2)
1268731799fSRoman Tereshin   //
1278731799fSRoman Tereshin   // 3. Third, the artifacts are attempted to be combined in pairs, looking
1288731799fSRoman Tereshin   //    through the def-use chain from the roots towards the leafs, visiting the
1298731799fSRoman Tereshin   //    roots in order they happen to be in the worklist:
1308731799fSRoman Tereshin   //      (4) - (trunc):                  can not be combined;
1318731799fSRoman Tereshin   //      (3) - (build_vector (trunc)):   can not be combined;
1328731799fSRoman Tereshin   //      (2) - (anyext (unmerge)):       can not be combined;
1338731799fSRoman Tereshin   //      (1) - (unmerge (build_vector)): combined and eliminated;
1348731799fSRoman Tereshin   //
1358731799fSRoman Tereshin   //    leaving the function in the following state:
1368731799fSRoman Tereshin   //
1378731799fSRoman Tereshin   //        TRUNC  (1): moved to non-artifact instructions worklist first.
1388731799fSRoman Tereshin   //         |
1398731799fSRoman Tereshin   //       ANYEXT  (2): also moved to non-artifact instructions worklist.
1408731799fSRoman Tereshin   //
1418731799fSRoman Tereshin   //    Every other instruction is successfully legalized in full.
1428731799fSRoman Tereshin   //    If combining (unmerge (build_vector)) does not re-insert every artifact
1438731799fSRoman Tereshin   //    that had its def-use chain modified (shortened) into the artifact
1448731799fSRoman Tereshin   //    worklist (here it's just ANYEXT), the process moves on onto the next
1458731799fSRoman Tereshin   //    outer loop iteration of the top-level legalization algorithm here, w/o
1468731799fSRoman Tereshin   //    performing all the artifact combines possible. Let's consider this
1478731799fSRoman Tereshin   //    scenario first:
1488731799fSRoman Tereshin   //  4.A. Neither TRUNC, nor ANYEXT can be legalized in isolation, both of them
1498731799fSRoman Tereshin   //       get moved to the retry worklist, but no additional artifacts were
1508731799fSRoman Tereshin   //       created in the process, thus algorithm concludes no progress could be
1518731799fSRoman Tereshin   //       made, and fails.
1528731799fSRoman Tereshin   //  4.B. If, however, combining (unmerge (build_vector)) had re-inserted
1538731799fSRoman Tereshin   //       ANYEXT into the worklist (as ANYEXT's source changes, not by value,
1548731799fSRoman Tereshin   //       but by implementation), (anyext (trunc)) combine happens next, which
1558731799fSRoman Tereshin   //       fully eliminates all the artifacts and legalization succeeds.
1568731799fSRoman Tereshin   //
1578731799fSRoman Tereshin   //  We're looking into making sure that (4.B) happens here, not (4.A). Note
1588731799fSRoman Tereshin   //  that in that case the first scan through the artifacts worklist, while not
1598731799fSRoman Tereshin   //  being done in any guaranteed order, only needs to find the innermost
1608731799fSRoman Tereshin   //  pair(s) of artifacts that could be immediately combined out. After that
1618731799fSRoman Tereshin   //  the process follows def-use chains, making them shorter at each step, thus
1628731799fSRoman Tereshin   //  combining everything that can be combined in O(n) time.
163d9085f65SDaniel Sanders   Legalizer::MFResult Result = Legalizer::legalizeMachineFunction(
164fc672b6aSJessica Del       *MF, LI, {&LocObserver}, LocObserver, B, &KB);
1658731799fSRoman Tereshin 
1668731799fSRoman Tereshin   EXPECT_TRUE(isNullMIPtr(Result.FailedOn));
1678731799fSRoman Tereshin   EXPECT_TRUE(Result.Changed);
1688731799fSRoman Tereshin 
1698731799fSRoman Tereshin   StringRef CheckString = R"(
1708731799fSRoman Tereshin     CHECK:      %vptr:_(p0) = COPY $x4
171fae05692SMatt Arsenault     CHECK-NEXT: [[LOAD_0:%[0-9]+]]:_(s16) = G_LOAD %vptr:_(p0) :: (load (s8))
1722bf4eeeeSPetar Avramovic     CHECK:      $h4 = COPY [[LOAD_0]]:_(s16)
1738731799fSRoman Tereshin   )";
1748731799fSRoman Tereshin 
1758731799fSRoman Tereshin   EXPECT_TRUE(CheckMachineFunction(*MF, CheckString)) << *MF;
1768731799fSRoman Tereshin }
1778731799fSRoman Tereshin 
17858f843a5SMatt Arsenault TEST_F(AArch64GISelMITest, UnorderedArtifactCombiningManyCopiesTest) {
1798731799fSRoman Tereshin   StringRef MIRString = R"(
1808731799fSRoman Tereshin     %vptr:_(p0) = COPY $x4
181fae05692SMatt Arsenault     %v:_(<2 x s8>) = G_LOAD %vptr:_(p0) :: (load (<2 x s8>), align 1)
1828731799fSRoman Tereshin     %vc0:_(<2 x s8>) = COPY %v:_(<2 x s8>)
1838731799fSRoman Tereshin     %vc1:_(<2 x s8>) = COPY %v:_(<2 x s8>)
1848731799fSRoman Tereshin     %vc00:_(s8), %vc01:_(s8) = G_UNMERGE_VALUES %vc0:_(<2 x s8>)
1858731799fSRoman Tereshin     %vc10:_(s8), %vc11:_(s8) = G_UNMERGE_VALUES %vc1:_(<2 x s8>)
1868731799fSRoman Tereshin     %v0t:_(s8) = COPY %vc00:_(s8)
1878731799fSRoman Tereshin     %v0:_(s8) = COPY %v0t:_(s8)
1888731799fSRoman Tereshin     %v1t:_(s8) = COPY %vc11:_(s8)
1898731799fSRoman Tereshin     %v1:_(s8) = COPY %v1t:_(s8)
1908731799fSRoman Tereshin     %v0_zext:_(s32) = G_ZEXT %v0:_(s8)
1918731799fSRoman Tereshin     %v1_sext:_(s32) = G_SEXT %v1:_(s8)
1928731799fSRoman Tereshin     $w4 = COPY %v0_zext:_(s32)
1938731799fSRoman Tereshin     $w5 = COPY %v1_sext:_(s32)
1948731799fSRoman Tereshin   )";
19542a84d22SDaniel Sanders   setUp(MIRString.rtrim(' '));
1968731799fSRoman Tereshin   if (!TM)
1977fc87159SPaul Robinson     GTEST_SKIP();
1988731799fSRoman Tereshin 
1998731799fSRoman Tereshin   ALegalizerInfo LI(MF->getSubtarget());
200d9085f65SDaniel Sanders   LostDebugLocObserver LocObserver(DEBUG_TYPE);
201fc672b6aSJessica Del   GISelKnownBits KB(*MF);
2028731799fSRoman Tereshin 
203d9085f65SDaniel Sanders   Legalizer::MFResult Result = Legalizer::legalizeMachineFunction(
204fc672b6aSJessica Del       *MF, LI, {&LocObserver}, LocObserver, B, &KB);
2058731799fSRoman Tereshin 
2068731799fSRoman Tereshin   EXPECT_TRUE(isNullMIPtr(Result.FailedOn));
2078731799fSRoman Tereshin   EXPECT_TRUE(Result.Changed);
2088731799fSRoman Tereshin 
2098731799fSRoman Tereshin   StringRef CheckString = R"(
2108731799fSRoman Tereshin     CHECK:      %vptr:_(p0) = COPY $x4
211fae05692SMatt Arsenault     CHECK-NEXT: [[LOAD_0:%[0-9]+]]:_(s16) = G_LOAD %vptr:_(p0) :: (load (s8))
2128731799fSRoman Tereshin     CHECK-NEXT: [[OFFSET_1:%[0-9]+]]:_(s64) = G_CONSTANT i64 1
2138731799fSRoman Tereshin     CHECK-NEXT: [[VPTR_1:%[0-9]+]]:_(p0) = G_PTR_ADD %vptr:_, [[OFFSET_1]]:_(s64)
214fae05692SMatt Arsenault     CHECK-NEXT: [[LOAD_1:%[0-9]+]]:_(s16) = G_LOAD [[VPTR_1]]:_(p0) :: (load (s8) from unknown-address + 1)
215305fbc1bSTobias Stadler     CHECK-NEXT: [[V0_EXT:%[0-9]+]]:_(s32) = G_ANYEXT [[LOAD_0]]:_(s16)
216373c343aSTobias Stadler     CHECK-NEXT: [[FF_MASK:%[0-9]+]]:_(s32) = G_CONSTANT i32 255
2178731799fSRoman Tereshin     CHECK-NEXT: %v0_zext:_(s32) = G_AND [[V0_EXT]]:_, [[FF_MASK]]:_
2188731799fSRoman Tereshin     CHECK-NEXT: [[V1_EXT:%[0-9]+]]:_(s32) = G_ANYEXT [[LOAD_1]]:_(s16)
2198731799fSRoman Tereshin     CHECK-NEXT: [[SHAMNT:%[0-9]+]]:_(s32) = G_CONSTANT i32 24
2208731799fSRoman Tereshin     CHECK-NEXT: [[V1_SHL:%[0-9]+]]:_(s32) = G_SHL [[V1_EXT]]:_, [[SHAMNT]]:_(s32)
2218731799fSRoman Tereshin     CHECK-NEXT: %v1_sext:_(s32) = G_ASHR [[V1_SHL]]:_, [[SHAMNT]]:_(s32)
2228731799fSRoman Tereshin     CHECK-NEXT: $w4 = COPY %v0_zext:_(s32)
2238731799fSRoman Tereshin     CHECK-NEXT: $w5 = COPY %v1_sext:_(s32)
2248731799fSRoman Tereshin   )";
2258731799fSRoman Tereshin 
2268731799fSRoman Tereshin   EXPECT_TRUE(CheckMachineFunction(*MF, CheckString)) << *MF;
2278731799fSRoman Tereshin }
2288731799fSRoman Tereshin 
22918bf9670SRoman Tereshin } // namespace
230