230 lines · cpp
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-exception6//7//===----------------------------------------------------------------------===//8 9#include "llvm/CodeGen/GlobalISel/Legalizer.h"10#include "GISelMITest.h"11#include "llvm/CodeGen/GlobalISel/GISelValueTracking.h"12#include "llvm/CodeGen/GlobalISel/LostDebugLocObserver.h"13 14#define DEBUG_TYPE "legalizer-test"15 16using namespace LegalizeActions;17using namespace LegalizeMutations;18using namespace LegalityPredicates;19 20namespace {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 33DefineLegalizerInfo(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 57TEST_F(AArch64GISelMITest, BasicLegalizerTest) {58 StringRef MIRString = R"(59 %vptr:_(p0) = COPY $x460 %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 GISelValueTracking VT(*MF);70 71 Legalizer::MFResult Result = Legalizer::legalizeMachineFunction(72 *MF, LI, {&LocObserver}, LocObserver, B, &VT);73 74 EXPECT_TRUE(isNullMIPtr(Result.FailedOn));75 EXPECT_TRUE(Result.Changed);76 77 StringRef CheckString = R"(78 CHECK: %vptr:_(p0) = COPY $x479 CHECK-NEXT: [[LOAD_0:%[0-9]+]]:_(s16) = G_LOAD %vptr:_(p0) :: (load (s8))80 CHECK-NEXT: [[OFFSET_1:%[0-9]+]]:_(s64) = G_CONSTANT i64 181 CHECK-NEXT: [[VPTR_1:%[0-9]+]]:_(p0) = nuw inbounds 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 combine91// away all the legalization artifacts regardless of the order of their92// creation.93TEST_F(AArch64GISelMITest, UnorderedArtifactCombiningTest) {94 StringRef MIRString = R"(95 %vptr:_(p0) = COPY $x496 %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 GISelValueTracking VT(*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, looking128 // through the def-use chain from the roots towards the leafs, visiting the129 // 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 artifact143 // that had its def-use chain modified (shortened) into the artifact144 // worklist (here it's just ANYEXT), the process moves on onto the next145 // outer loop iteration of the top-level legalization algorithm here, w/o146 // performing all the artifact combines possible. Let's consider this147 // scenario first:148 // 4.A. Neither TRUNC, nor ANYEXT can be legalized in isolation, both of them149 // get moved to the retry worklist, but no additional artifacts were150 // created in the process, thus algorithm concludes no progress could be151 // made, and fails.152 // 4.B. If, however, combining (unmerge (build_vector)) had re-inserted153 // ANYEXT into the worklist (as ANYEXT's source changes, not by value,154 // but by implementation), (anyext (trunc)) combine happens next, which155 // fully eliminates all the artifacts and legalization succeeds.156 //157 // We're looking into making sure that (4.B) happens here, not (4.A). Note158 // that in that case the first scan through the artifacts worklist, while not159 // being done in any guaranteed order, only needs to find the innermost160 // pair(s) of artifacts that could be immediately combined out. After that161 // the process follows def-use chains, making them shorter at each step, thus162 // combining everything that can be combined in O(n) time.163 Legalizer::MFResult Result = Legalizer::legalizeMachineFunction(164 *MF, LI, {&LocObserver}, LocObserver, B, &VT);165 166 EXPECT_TRUE(isNullMIPtr(Result.FailedOn));167 EXPECT_TRUE(Result.Changed);168 169 StringRef CheckString = R"(170 CHECK: %vptr:_(p0) = COPY $x4171 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 178TEST_F(AArch64GISelMITest, UnorderedArtifactCombiningManyCopiesTest) {179 StringRef MIRString = R"(180 %vptr:_(p0) = COPY $x4181 %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 GISelValueTracking VT(*MF);202 203 Legalizer::MFResult Result = Legalizer::legalizeMachineFunction(204 *MF, LI, {&LocObserver}, LocObserver, B, &VT);205 206 EXPECT_TRUE(isNullMIPtr(Result.FailedOn));207 EXPECT_TRUE(Result.Changed);208 209 StringRef CheckString = R"(210 CHECK: %vptr:_(p0) = COPY $x4211 CHECK-NEXT: [[LOAD_0:%[0-9]+]]:_(s16) = G_LOAD %vptr:_(p0) :: (load (s8))212 CHECK-NEXT: [[OFFSET_1:%[0-9]+]]:_(s64) = G_CONSTANT i64 1213 CHECK-NEXT: [[VPTR_1:%[0-9]+]]:_(p0) = nuw inbounds 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 255217 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 24220 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} // namespace230