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