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