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