1 //===- llvm/unittest/CodeGen/GlobalISel/LegalizerInfoTest.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/LegalizerInfo.h" 10 #include "llvm/CodeGen/TargetOpcodes.h" 11 #include "GISelMITest.h" 12 #include "gtest/gtest.h" 13 14 using namespace llvm; 15 using namespace LegalizeActions; 16 17 // Define a couple of pretty printers to help debugging when things go wrong. 18 namespace llvm { 19 std::ostream & 20 operator<<(std::ostream &OS, const LegalizeAction Act) { 21 switch (Act) { 22 case Lower: OS << "Lower"; break; 23 case Legal: OS << "Legal"; break; 24 case NarrowScalar: OS << "NarrowScalar"; break; 25 case WidenScalar: OS << "WidenScalar"; break; 26 case FewerElements: OS << "FewerElements"; break; 27 case MoreElements: OS << "MoreElements"; break; 28 case Libcall: OS << "Libcall"; break; 29 case Custom: OS << "Custom"; break; 30 case Unsupported: OS << "Unsupported"; break; 31 case NotFound: OS << "NotFound"; break; 32 case UseLegacyRules: OS << "UseLegacyRules"; break; 33 } 34 return OS; 35 } 36 37 std::ostream &operator<<(std::ostream &OS, const llvm::LegalizeActionStep Ty) { 38 OS << "LegalizeActionStep(" << Ty.Action << ", " << Ty.TypeIdx << ", " 39 << Ty.NewType << ')'; 40 return OS; 41 } 42 } 43 44 namespace { 45 46 47 TEST(LegalizerInfoTest, ScalarRISC) { 48 using namespace TargetOpcode; 49 LegalizerInfo L; 50 // Typical RISCy set of operations based on AArch64. 51 for (unsigned Op : {G_ADD, G_SUB}) { 52 for (unsigned Size : {32, 64}) 53 L.setAction({Op, 0, LLT::scalar(Size)}, Legal); 54 L.setLegalizeScalarToDifferentSizeStrategy( 55 Op, 0, LegalizerInfo::widenToLargerTypesAndNarrowToLargest); 56 } 57 58 L.computeTables(); 59 60 for (unsigned opcode : {G_ADD, G_SUB}) { 61 // Check we infer the correct types and actually do what we're told. 62 EXPECT_EQ(L.getAction({opcode, {LLT::scalar(8)}}), 63 LegalizeActionStep(WidenScalar, 0, LLT::scalar(32))); 64 EXPECT_EQ(L.getAction({opcode, {LLT::scalar(16)}}), 65 LegalizeActionStep(WidenScalar, 0, LLT::scalar(32))); 66 EXPECT_EQ(L.getAction({opcode, {LLT::scalar(32)}}), 67 LegalizeActionStep(Legal, 0, LLT{})); 68 EXPECT_EQ(L.getAction({opcode, {LLT::scalar(64)}}), 69 LegalizeActionStep(Legal, 0, LLT{})); 70 71 // Make sure the default for over-sized types applies. 72 EXPECT_EQ(L.getAction({opcode, {LLT::scalar(128)}}), 73 LegalizeActionStep(NarrowScalar, 0, LLT::scalar(64))); 74 // Make sure we also handle unusual sizes 75 EXPECT_EQ(L.getAction({opcode, {LLT::scalar(1)}}), 76 LegalizeActionStep(WidenScalar, 0, LLT::scalar(32))); 77 EXPECT_EQ(L.getAction({opcode, {LLT::scalar(31)}}), 78 LegalizeActionStep(WidenScalar, 0, LLT::scalar(32))); 79 EXPECT_EQ(L.getAction({opcode, {LLT::scalar(33)}}), 80 LegalizeActionStep(WidenScalar, 0, LLT::scalar(64))); 81 EXPECT_EQ(L.getAction({opcode, {LLT::scalar(63)}}), 82 LegalizeActionStep(WidenScalar, 0, LLT::scalar(64))); 83 EXPECT_EQ(L.getAction({opcode, {LLT::scalar(65)}}), 84 LegalizeActionStep(NarrowScalar, 0, LLT::scalar(64))); 85 } 86 } 87 88 TEST(LegalizerInfoTest, VectorRISC) { 89 using namespace TargetOpcode; 90 LegalizerInfo L; 91 // Typical RISCy set of operations based on ARM. 92 L.setAction({G_ADD, LLT::vector(8, 8)}, Legal); 93 L.setAction({G_ADD, LLT::vector(16, 8)}, Legal); 94 L.setAction({G_ADD, LLT::vector(4, 16)}, Legal); 95 L.setAction({G_ADD, LLT::vector(8, 16)}, Legal); 96 L.setAction({G_ADD, LLT::vector(2, 32)}, Legal); 97 L.setAction({G_ADD, LLT::vector(4, 32)}, Legal); 98 99 L.setLegalizeVectorElementToDifferentSizeStrategy( 100 G_ADD, 0, LegalizerInfo::widenToLargerTypesUnsupportedOtherwise); 101 102 L.setAction({G_ADD, 0, LLT::scalar(32)}, Legal); 103 104 L.computeTables(); 105 106 // Check we infer the correct types and actually do what we're told for some 107 // simple cases. 108 EXPECT_EQ(L.getAction({G_ADD, {LLT::vector(8, 8)}}), 109 LegalizeActionStep(Legal, 0, LLT{})); 110 EXPECT_EQ(L.getAction({G_ADD, {LLT::vector(8, 7)}}), 111 LegalizeActionStep(WidenScalar, 0, LLT::vector(8, 8))); 112 EXPECT_EQ(L.getAction({G_ADD, {LLT::vector(2, 8)}}), 113 LegalizeActionStep(MoreElements, 0, LLT::vector(8, 8))); 114 EXPECT_EQ(L.getAction({G_ADD, {LLT::vector(8, 32)}}), 115 LegalizeActionStep(FewerElements, 0, LLT::vector(4, 32))); 116 // Check a few non-power-of-2 sizes: 117 EXPECT_EQ(L.getAction({G_ADD, {LLT::vector(3, 3)}}), 118 LegalizeActionStep(WidenScalar, 0, LLT::vector(3, 8))); 119 EXPECT_EQ(L.getAction({G_ADD, {LLT::vector(3, 8)}}), 120 LegalizeActionStep(MoreElements, 0, LLT::vector(8, 8))); 121 } 122 123 TEST(LegalizerInfoTest, MultipleTypes) { 124 using namespace TargetOpcode; 125 LegalizerInfo L; 126 LLT p0 = LLT::pointer(0, 64); 127 LLT s64 = LLT::scalar(64); 128 129 // Typical RISCy set of operations based on AArch64. 130 L.setAction({G_PTRTOINT, 0, s64}, Legal); 131 L.setAction({G_PTRTOINT, 1, p0}, Legal); 132 133 L.setLegalizeScalarToDifferentSizeStrategy( 134 G_PTRTOINT, 0, LegalizerInfo::widenToLargerTypesAndNarrowToLargest); 135 136 L.computeTables(); 137 138 // Check we infer the correct types and actually do what we're told. 139 EXPECT_EQ(L.getAction({G_PTRTOINT, {s64, p0}}), 140 LegalizeActionStep(Legal, 0, LLT{})); 141 142 // Make sure we also handle unusual sizes 143 EXPECT_EQ( 144 L.getAction({G_PTRTOINT, {LLT::scalar(65), s64}}), 145 LegalizeActionStep(NarrowScalar, 0, s64)); 146 EXPECT_EQ( 147 L.getAction({G_PTRTOINT, {s64, LLT::pointer(0, 32)}}), 148 LegalizeActionStep(Unsupported, 1, 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}, Lower); 160 L.setAction({G_UREM, 0, s64}, Lower); 161 162 L.computeTables(); 163 164 EXPECT_EQ(L.getAction({G_UREM, {LLT::scalar(16)}}), 165 LegalizeActionStep(WidenScalar, 0, LLT::scalar(32))); 166 EXPECT_EQ(L.getAction({G_UREM, {LLT::scalar(32)}}), 167 LegalizeActionStep(Lower, 0, 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)}, 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 EXPECT_EQ(L.getAction({G_UREM, {LLT::scalar(Size)}}), 183 LegalizeActionStep(Legal, 0, LLT{})); 184 } 185 EXPECT_EQ(L.getAction({G_UREM, {LLT::scalar(2)}}), 186 LegalizeActionStep(WidenScalar, 0, LLT::scalar(8))); 187 EXPECT_EQ(L.getAction({G_UREM, {LLT::scalar(7)}}), 188 LegalizeActionStep(WidenScalar, 0, LLT::scalar(8))); 189 EXPECT_EQ(L.getAction({G_UREM, {LLT::scalar(9)}}), 190 LegalizeActionStep(WidenScalar, 0, LLT::scalar(16))); 191 EXPECT_EQ(L.getAction({G_UREM, {LLT::scalar(17)}}), 192 LegalizeActionStep(WidenScalar, 0, LLT::scalar(32))); 193 EXPECT_EQ(L.getAction({G_UREM, {LLT::scalar(31)}}), 194 LegalizeActionStep(WidenScalar, 0, LLT::scalar(32))); 195 EXPECT_EQ(L.getAction({G_UREM, {LLT::scalar(33)}}), 196 LegalizeActionStep(Unsupported, 0, LLT::scalar(33))); 197 } 198 } 199 200 #define EXPECT_ACTION(Action, Index, Type, Query) \ 201 do { \ 202 auto A = LI.getAction(Query); \ 203 EXPECT_EQ(LegalizeActionStep(Action, Index, Type), A) << A; \ 204 } while (0) 205 206 TEST(LegalizerInfoTest, RuleSets) { 207 using namespace TargetOpcode; 208 209 const LLT s5 = LLT::scalar(5); 210 const LLT s8 = LLT::scalar(8); 211 const LLT s16 = LLT::scalar(16); 212 const LLT s32 = LLT::scalar(32); 213 const LLT s33 = LLT::scalar(33); 214 const LLT s64 = LLT::scalar(64); 215 216 const LLT v2s5 = LLT::vector(2, 5); 217 const LLT v2s8 = LLT::vector(2, 8); 218 const LLT v2s16 = LLT::vector(2, 16); 219 const LLT v2s32 = LLT::vector(2, 32); 220 const LLT v3s32 = LLT::vector(3, 32); 221 const LLT v4s32 = LLT::vector(4, 32); 222 const LLT v2s33 = LLT::vector(2, 33); 223 const LLT v2s64 = LLT::vector(2, 64); 224 225 const LLT p0 = LLT::pointer(0, 32); 226 const LLT v3p0 = LLT::vector(3, p0); 227 const LLT v4p0 = LLT::vector(4, p0); 228 229 { 230 LegalizerInfo LI; 231 232 LI.getActionDefinitionsBuilder(G_IMPLICIT_DEF) 233 .legalFor({v4s32, v4p0}) 234 .moreElementsToNextPow2(0); 235 LI.computeTables(); 236 237 EXPECT_ACTION(Unsupported, 0, LLT(), LegalityQuery(G_IMPLICIT_DEF, {s32})); 238 EXPECT_ACTION(Unsupported, 0, LLT(), LegalityQuery(G_IMPLICIT_DEF, {v2s32})); 239 EXPECT_ACTION(MoreElements, 0, v4p0, LegalityQuery(G_IMPLICIT_DEF, {v3p0})); 240 EXPECT_ACTION(MoreElements, 0, v4s32, LegalityQuery(G_IMPLICIT_DEF, {v3s32})); 241 } 242 243 // Test minScalarOrElt 244 { 245 LegalizerInfo LI; 246 LI.getActionDefinitionsBuilder(G_OR) 247 .legalFor({s32}) 248 .minScalarOrElt(0, s32); 249 LI.computeTables(); 250 251 EXPECT_ACTION(WidenScalar, 0, s32, LegalityQuery(G_OR, {s16})); 252 EXPECT_ACTION(WidenScalar, 0, v2s32, LegalityQuery(G_OR, {v2s16})); 253 } 254 255 // Test maxScalarOrELt 256 { 257 LegalizerInfo LI; 258 LI.getActionDefinitionsBuilder(G_AND) 259 .legalFor({s16}) 260 .maxScalarOrElt(0, s16); 261 LI.computeTables(); 262 263 EXPECT_ACTION(NarrowScalar, 0, s16, LegalityQuery(G_AND, {s32})); 264 EXPECT_ACTION(NarrowScalar, 0, v2s16, LegalityQuery(G_AND, {v2s32})); 265 } 266 267 // Test clampScalarOrElt 268 { 269 LegalizerInfo LI; 270 LI.getActionDefinitionsBuilder(G_XOR) 271 .legalFor({s16}) 272 .clampScalarOrElt(0, s16, s32); 273 LI.computeTables(); 274 275 EXPECT_ACTION(NarrowScalar, 0, s32, LegalityQuery(G_XOR, {s64})); 276 EXPECT_ACTION(WidenScalar, 0, s16, LegalityQuery(G_XOR, {s8})); 277 278 // Make sure the number of elements is preserved. 279 EXPECT_ACTION(NarrowScalar, 0, v2s32, LegalityQuery(G_XOR, {v2s64})); 280 EXPECT_ACTION(WidenScalar, 0, v2s16, LegalityQuery(G_XOR, {v2s8})); 281 } 282 283 // Test minScalar 284 { 285 LegalizerInfo LI; 286 LI.getActionDefinitionsBuilder(G_OR) 287 .legalFor({s32}) 288 .minScalar(0, s32); 289 LI.computeTables(); 290 291 // Only handle scalars, ignore vectors. 292 EXPECT_ACTION(WidenScalar, 0, s32, LegalityQuery(G_OR, {s16})); 293 EXPECT_ACTION(Unsupported, 0, LLT(), LegalityQuery(G_OR, {v2s16})); 294 } 295 296 // Test maxScalar 297 { 298 LegalizerInfo LI; 299 LI.getActionDefinitionsBuilder(G_AND) 300 .legalFor({s16}) 301 .maxScalar(0, s16); 302 LI.computeTables(); 303 304 // Only handle scalars, ignore vectors. 305 EXPECT_ACTION(NarrowScalar, 0, s16, LegalityQuery(G_AND, {s32})); 306 EXPECT_ACTION(Unsupported, 0, LLT(), LegalityQuery(G_AND, {v2s32})); 307 } 308 309 // Test clampScalar 310 { 311 LegalizerInfo LI; 312 313 LI.getActionDefinitionsBuilder(G_XOR) 314 .legalFor({s16}) 315 .clampScalar(0, s16, s32); 316 LI.computeTables(); 317 318 EXPECT_ACTION(NarrowScalar, 0, s32, LegalityQuery(G_XOR, {s64})); 319 EXPECT_ACTION(WidenScalar, 0, s16, LegalityQuery(G_XOR, {s8})); 320 321 // Only handle scalars, ignore vectors. 322 EXPECT_ACTION(Unsupported, 0, LLT(), LegalityQuery(G_XOR, {v2s64})); 323 EXPECT_ACTION(Unsupported, 0, LLT(), LegalityQuery(G_XOR, {v2s8})); 324 } 325 326 // Test widenScalarOrEltToNextPow2 327 { 328 LegalizerInfo LI; 329 330 LI.getActionDefinitionsBuilder(G_AND) 331 .legalFor({s32}) 332 .widenScalarOrEltToNextPow2(0, 32); 333 LI.computeTables(); 334 335 // Handle scalars and vectors 336 EXPECT_ACTION(WidenScalar, 0, s32, LegalityQuery(G_AND, {s5})); 337 EXPECT_ACTION(WidenScalar, 0, v2s32, LegalityQuery(G_AND, {v2s5})); 338 EXPECT_ACTION(WidenScalar, 0, s64, LegalityQuery(G_AND, {s33})); 339 EXPECT_ACTION(WidenScalar, 0, v2s64, LegalityQuery(G_AND, {v2s33})); 340 } 341 342 // Test widenScalarToNextPow2 343 { 344 LegalizerInfo LI; 345 346 LI.getActionDefinitionsBuilder(G_AND) 347 .legalFor({s32}) 348 .widenScalarToNextPow2(0, 32); 349 LI.computeTables(); 350 351 EXPECT_ACTION(WidenScalar, 0, s32, LegalityQuery(G_AND, {s5})); 352 EXPECT_ACTION(WidenScalar, 0, s64, LegalityQuery(G_AND, {s33})); 353 354 // Do nothing for vectors. 355 EXPECT_ACTION(Unsupported, 0, LLT(), LegalityQuery(G_AND, {v2s5})); 356 EXPECT_ACTION(Unsupported, 0, LLT(), LegalityQuery(G_AND, {v2s33})); 357 } 358 } 359