1 //===- llvm/unittest/CodeGen/GlobalISel/LegalizerInfoTest.cpp -------------===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 10 #include "llvm/CodeGen/GlobalISel/LegalizerInfo.h" 11 #include "llvm/CodeGen/TargetOpcodes.h" 12 #include "gtest/gtest.h" 13 14 using namespace llvm; 15 16 // Define a couple of pretty printers to help debugging when things go wrong. 17 namespace llvm { 18 std::ostream & 19 operator<<(std::ostream &OS, const llvm::LegalizerInfo::LegalizeAction Act) { 20 switch (Act) { 21 case LegalizerInfo::Lower: OS << "Lower"; break; 22 case LegalizerInfo::Legal: OS << "Legal"; break; 23 case LegalizerInfo::NarrowScalar: OS << "NarrowScalar"; break; 24 case LegalizerInfo::WidenScalar: OS << "WidenScalar"; break; 25 case LegalizerInfo::FewerElements: OS << "FewerElements"; break; 26 case LegalizerInfo::MoreElements: OS << "MoreElements"; break; 27 case LegalizerInfo::Libcall: OS << "Libcall"; break; 28 case LegalizerInfo::Custom: OS << "Custom"; break; 29 case LegalizerInfo::Unsupported: OS << "Unsupported"; break; 30 case LegalizerInfo::NotFound: OS << "NotFound"; 31 } 32 return OS; 33 } 34 35 std::ostream & 36 operator<<(std::ostream &OS, const llvm::LLT Ty) { 37 std::string Repr; 38 raw_string_ostream SS{Repr}; 39 Ty.print(SS); 40 OS << SS.str(); 41 return OS; 42 } 43 } 44 45 namespace { 46 47 48 TEST(LegalizerInfoTest, ScalarRISC) { 49 using namespace TargetOpcode; 50 LegalizerInfo L; 51 // Typical RISCy set of operations based on AArch64. 52 for (unsigned Op : {G_ADD, G_SUB}) { 53 for (unsigned Size : {32, 64}) 54 L.setAction({Op, 0, LLT::scalar(Size)}, LegalizerInfo::Legal); 55 L.setLegalizeScalarToDifferentSizeStrategy( 56 Op, 0, LegalizerInfo::widenToLargerTypesAndNarrowToLargest); 57 } 58 59 L.computeTables(); 60 61 for (unsigned opcode : {G_ADD, G_SUB}) { 62 // Check we infer the correct types and actually do what we're told. 63 ASSERT_EQ(L.getAction({opcode, LLT::scalar(8)}), 64 std::make_pair(LegalizerInfo::WidenScalar, LLT::scalar(32))); 65 ASSERT_EQ(L.getAction({opcode, LLT::scalar(16)}), 66 std::make_pair(LegalizerInfo::WidenScalar, LLT::scalar(32))); 67 ASSERT_EQ(L.getAction({opcode, LLT::scalar(32)}), 68 std::make_pair(LegalizerInfo::Legal, LLT::scalar(32))); 69 ASSERT_EQ(L.getAction({opcode, LLT::scalar(64)}), 70 std::make_pair(LegalizerInfo::Legal, LLT::scalar(64))); 71 72 // Make sure the default for over-sized types applies. 73 ASSERT_EQ(L.getAction({opcode, LLT::scalar(128)}), 74 std::make_pair(LegalizerInfo::NarrowScalar, LLT::scalar(64))); 75 // Make sure we also handle unusual sizes 76 ASSERT_EQ(L.getAction({opcode, LLT::scalar(1)}), 77 std::make_pair(LegalizerInfo::WidenScalar, LLT::scalar(32))); 78 ASSERT_EQ(L.getAction({opcode, LLT::scalar(31)}), 79 std::make_pair(LegalizerInfo::WidenScalar, LLT::scalar(32))); 80 ASSERT_EQ(L.getAction({opcode, LLT::scalar(33)}), 81 std::make_pair(LegalizerInfo::WidenScalar, LLT::scalar(64))); 82 ASSERT_EQ(L.getAction({opcode, LLT::scalar(63)}), 83 std::make_pair(LegalizerInfo::WidenScalar, LLT::scalar(64))); 84 ASSERT_EQ(L.getAction({opcode, LLT::scalar(65)}), 85 std::make_pair(LegalizerInfo::NarrowScalar, LLT::scalar(64))); 86 } 87 } 88 89 TEST(LegalizerInfoTest, VectorRISC) { 90 using namespace TargetOpcode; 91 LegalizerInfo L; 92 // Typical RISCy set of operations based on ARM. 93 L.setAction({G_ADD, LLT::vector(8, 8)}, LegalizerInfo::Legal); 94 L.setAction({G_ADD, LLT::vector(16, 8)}, LegalizerInfo::Legal); 95 L.setAction({G_ADD, LLT::vector(4, 16)}, LegalizerInfo::Legal); 96 L.setAction({G_ADD, LLT::vector(8, 16)}, LegalizerInfo::Legal); 97 L.setAction({G_ADD, LLT::vector(2, 32)}, LegalizerInfo::Legal); 98 L.setAction({G_ADD, LLT::vector(4, 32)}, LegalizerInfo::Legal); 99 100 L.setLegalizeVectorElementToDifferentSizeStrategy( 101 G_ADD, 0, LegalizerInfo::widenToLargerTypesUnsupportedOtherwise); 102 103 L.setAction({G_ADD, 0, LLT::scalar(32)}, LegalizerInfo::Legal); 104 105 L.computeTables(); 106 107 // Check we infer the correct types and actually do what we're told for some 108 // simple cases. 109 ASSERT_EQ(L.getAction({G_ADD, LLT::vector(8, 8)}), 110 std::make_pair(LegalizerInfo::Legal, LLT::vector(8, 8))); 111 ASSERT_EQ(L.getAction({G_ADD, LLT::vector(8, 7)}), 112 std::make_pair(LegalizerInfo::WidenScalar, LLT::vector(8, 8))); 113 ASSERT_EQ(L.getAction({G_ADD, LLT::vector(2, 8)}), 114 std::make_pair(LegalizerInfo::MoreElements, LLT::vector(8, 8))); 115 ASSERT_EQ(L.getAction({G_ADD, LLT::vector(8, 32)}), 116 std::make_pair(LegalizerInfo::FewerElements, LLT::vector(4, 32))); 117 // Check a few non-power-of-2 sizes: 118 ASSERT_EQ(L.getAction({G_ADD, LLT::vector(3, 3)}), 119 std::make_pair(LegalizerInfo::WidenScalar, LLT::vector(3, 8))); 120 ASSERT_EQ(L.getAction({G_ADD, LLT::vector(3, 8)}), 121 std::make_pair(LegalizerInfo::MoreElements, LLT::vector(8, 8))); 122 } 123 124 TEST(LegalizerInfoTest, MultipleTypes) { 125 using namespace TargetOpcode; 126 LegalizerInfo L; 127 LLT p0 = LLT::pointer(0, 64); 128 LLT s64 = LLT::scalar(64); 129 130 // Typical RISCy set of operations based on AArch64. 131 L.setAction({G_PTRTOINT, 0, s64}, LegalizerInfo::Legal); 132 L.setAction({G_PTRTOINT, 1, p0}, LegalizerInfo::Legal); 133 134 L.setLegalizeScalarToDifferentSizeStrategy( 135 G_PTRTOINT, 0, LegalizerInfo::widenToLargerTypesAndNarrowToLargest); 136 137 L.computeTables(); 138 139 // Check we infer the correct types and actually do what we're told. 140 ASSERT_EQ(L.getAction({G_PTRTOINT, 0, s64}), 141 std::make_pair(LegalizerInfo::Legal, s64)); 142 ASSERT_EQ(L.getAction({G_PTRTOINT, 1, p0}), 143 std::make_pair(LegalizerInfo::Legal, p0)); 144 // Make sure we also handle unusual sizes 145 ASSERT_EQ(L.getAction({G_PTRTOINT, 0, LLT::scalar(65)}), 146 std::make_pair(LegalizerInfo::NarrowScalar, s64)); 147 ASSERT_EQ(L.getAction({G_PTRTOINT, 1, LLT::pointer(0, 32)}), 148 std::make_pair(LegalizerInfo::Unsupported, LLT::pointer(0, 32))); 149 } 150 151 TEST(LegalizerInfoTest, MultipleSteps) { 152 using namespace TargetOpcode; 153 LegalizerInfo L; 154 LLT s32 = LLT::scalar(32); 155 LLT s64 = LLT::scalar(64); 156 157 L.setLegalizeScalarToDifferentSizeStrategy( 158 G_UREM, 0, LegalizerInfo::widenToLargerTypesUnsupportedOtherwise); 159 L.setAction({G_UREM, 0, s32}, LegalizerInfo::Lower); 160 L.setAction({G_UREM, 0, s64}, LegalizerInfo::Lower); 161 162 L.computeTables(); 163 164 ASSERT_EQ(L.getAction({G_UREM, LLT::scalar(16)}), 165 std::make_pair(LegalizerInfo::WidenScalar, LLT::scalar(32))); 166 ASSERT_EQ(L.getAction({G_UREM, LLT::scalar(32)}), 167 std::make_pair(LegalizerInfo::Lower, LLT::scalar(32))); 168 } 169 170 TEST(LegalizerInfoTest, SizeChangeStrategy) { 171 using namespace TargetOpcode; 172 LegalizerInfo L; 173 for (unsigned Size : {1, 8, 16, 32}) 174 L.setAction({G_UREM, 0, LLT::scalar(Size)}, LegalizerInfo::Legal); 175 176 L.setLegalizeScalarToDifferentSizeStrategy( 177 G_UREM, 0, LegalizerInfo::widenToLargerTypesUnsupportedOtherwise); 178 L.computeTables(); 179 180 // Check we infer the correct types and actually do what we're told. 181 for (unsigned Size : {1, 8, 16, 32}) { 182 ASSERT_EQ(L.getAction({G_UREM, LLT::scalar(Size)}), 183 std::make_pair(LegalizerInfo::Legal, LLT::scalar(Size))); 184 } 185 ASSERT_EQ(L.getAction({G_UREM, LLT::scalar(2)}), 186 std::make_pair(LegalizerInfo::WidenScalar, LLT::scalar(8))); 187 ASSERT_EQ(L.getAction({G_UREM, LLT::scalar(7)}), 188 std::make_pair(LegalizerInfo::WidenScalar, LLT::scalar(8))); 189 ASSERT_EQ(L.getAction({G_UREM, LLT::scalar(9)}), 190 std::make_pair(LegalizerInfo::WidenScalar, LLT::scalar(16))); 191 ASSERT_EQ(L.getAction({G_UREM, LLT::scalar(17)}), 192 std::make_pair(LegalizerInfo::WidenScalar, LLT::scalar(32))); 193 ASSERT_EQ(L.getAction({G_UREM, LLT::scalar(31)}), 194 std::make_pair(LegalizerInfo::WidenScalar, LLT::scalar(32))); 195 ASSERT_EQ(L.getAction({G_UREM, LLT::scalar(33)}), 196 std::make_pair(LegalizerInfo::Unsupported, LLT::scalar(33))); 197 } 198 } 199