1 //===- llvm/unittest/CodeGen/AArch64SelectionDAGTest.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/SelectionDAG.h" 10 #include "llvm/Analysis/OptimizationRemarkEmitter.h" 11 #include "llvm/AsmParser/Parser.h" 12 #include "llvm/CodeGen/MachineModuleInfo.h" 13 #include "llvm/CodeGen/TargetLowering.h" 14 #include "llvm/Support/SourceMgr.h" 15 #include "llvm/Support/TargetRegistry.h" 16 #include "llvm/Support/TargetSelect.h" 17 #include "llvm/Target/TargetMachine.h" 18 #include "gtest/gtest.h" 19 20 namespace llvm { 21 22 class AArch64SelectionDAGTest : public testing::Test { 23 protected: 24 static void SetUpTestCase() { 25 InitializeAllTargets(); 26 InitializeAllTargetMCs(); 27 } 28 29 void SetUp() override { 30 StringRef Assembly = "define void @f() { ret void }"; 31 32 Triple TargetTriple("aarch64--"); 33 std::string Error; 34 const Target *T = TargetRegistry::lookupTarget("", TargetTriple, Error); 35 // FIXME: These tests do not depend on AArch64 specifically, but we have to 36 // initialize a target. A skeleton Target for unittests would allow us to 37 // always run these tests. 38 if (!T) 39 return; 40 41 TargetOptions Options; 42 TM = std::unique_ptr<LLVMTargetMachine>(static_cast<LLVMTargetMachine *>( 43 T->createTargetMachine("AArch64", "", "+sve", Options, None, None, 44 CodeGenOpt::Aggressive))); 45 if (!TM) 46 return; 47 48 SMDiagnostic SMError; 49 M = parseAssemblyString(Assembly, SMError, Context); 50 if (!M) 51 report_fatal_error(SMError.getMessage()); 52 M->setDataLayout(TM->createDataLayout()); 53 54 F = M->getFunction("f"); 55 if (!F) 56 report_fatal_error("F?"); 57 58 MachineModuleInfo MMI(TM.get()); 59 60 MF = std::make_unique<MachineFunction>(*F, *TM, *TM->getSubtargetImpl(*F), 0, 61 MMI); 62 63 DAG = std::make_unique<SelectionDAG>(*TM, CodeGenOpt::None); 64 if (!DAG) 65 report_fatal_error("DAG?"); 66 OptimizationRemarkEmitter ORE(F); 67 DAG->init(*MF, ORE, nullptr, nullptr, nullptr, nullptr, nullptr); 68 } 69 70 TargetLoweringBase::LegalizeTypeAction getTypeAction(EVT VT) { 71 return DAG->getTargetLoweringInfo().getTypeAction(Context, VT); 72 } 73 74 EVT getTypeToTransformTo(EVT VT) { 75 return DAG->getTargetLoweringInfo().getTypeToTransformTo(Context, VT); 76 } 77 78 LLVMContext Context; 79 std::unique_ptr<LLVMTargetMachine> TM; 80 std::unique_ptr<Module> M; 81 Function *F; 82 std::unique_ptr<MachineFunction> MF; 83 std::unique_ptr<SelectionDAG> DAG; 84 }; 85 86 TEST_F(AArch64SelectionDAGTest, computeKnownBits_ZERO_EXTEND_VECTOR_INREG) { 87 if (!TM) 88 return; 89 SDLoc Loc; 90 auto Int8VT = EVT::getIntegerVT(Context, 8); 91 auto Int16VT = EVT::getIntegerVT(Context, 16); 92 auto InVecVT = EVT::getVectorVT(Context, Int8VT, 4); 93 auto OutVecVT = EVT::getVectorVT(Context, Int16VT, 2); 94 auto InVec = DAG->getConstant(0, Loc, InVecVT); 95 auto Op = DAG->getNode(ISD::ZERO_EXTEND_VECTOR_INREG, Loc, OutVecVT, InVec); 96 auto DemandedElts = APInt(2, 3); 97 KnownBits Known = DAG->computeKnownBits(Op, DemandedElts); 98 EXPECT_TRUE(Known.isZero()); 99 } 100 101 TEST_F(AArch64SelectionDAGTest, computeKnownBits_EXTRACT_SUBVECTOR) { 102 if (!TM) 103 return; 104 SDLoc Loc; 105 auto IntVT = EVT::getIntegerVT(Context, 8); 106 auto VecVT = EVT::getVectorVT(Context, IntVT, 3); 107 auto IdxVT = EVT::getIntegerVT(Context, 64); 108 auto Vec = DAG->getConstant(0, Loc, VecVT); 109 auto ZeroIdx = DAG->getConstant(0, Loc, IdxVT); 110 auto Op = DAG->getNode(ISD::EXTRACT_SUBVECTOR, Loc, VecVT, Vec, ZeroIdx); 111 auto DemandedElts = APInt(3, 7); 112 KnownBits Known = DAG->computeKnownBits(Op, DemandedElts); 113 EXPECT_TRUE(Known.isZero()); 114 } 115 116 TEST_F(AArch64SelectionDAGTest, ComputeNumSignBits_SIGN_EXTEND_VECTOR_INREG) { 117 if (!TM) 118 return; 119 SDLoc Loc; 120 auto Int8VT = EVT::getIntegerVT(Context, 8); 121 auto Int16VT = EVT::getIntegerVT(Context, 16); 122 auto InVecVT = EVT::getVectorVT(Context, Int8VT, 4); 123 auto OutVecVT = EVT::getVectorVT(Context, Int16VT, 2); 124 auto InVec = DAG->getConstant(1, Loc, InVecVT); 125 auto Op = DAG->getNode(ISD::SIGN_EXTEND_VECTOR_INREG, Loc, OutVecVT, InVec); 126 auto DemandedElts = APInt(2, 3); 127 EXPECT_EQ(DAG->ComputeNumSignBits(Op, DemandedElts), 15u); 128 } 129 130 TEST_F(AArch64SelectionDAGTest, ComputeNumSignBits_EXTRACT_SUBVECTOR) { 131 if (!TM) 132 return; 133 SDLoc Loc; 134 auto IntVT = EVT::getIntegerVT(Context, 8); 135 auto VecVT = EVT::getVectorVT(Context, IntVT, 3); 136 auto IdxVT = EVT::getIntegerVT(Context, 64); 137 auto Vec = DAG->getConstant(1, Loc, VecVT); 138 auto ZeroIdx = DAG->getConstant(0, Loc, IdxVT); 139 auto Op = DAG->getNode(ISD::EXTRACT_SUBVECTOR, Loc, VecVT, Vec, ZeroIdx); 140 auto DemandedElts = APInt(3, 7); 141 EXPECT_EQ(DAG->ComputeNumSignBits(Op, DemandedElts), 7u); 142 } 143 144 TEST_F(AArch64SelectionDAGTest, SimplifyDemandedVectorElts_EXTRACT_SUBVECTOR) { 145 if (!TM) 146 return; 147 148 TargetLowering TL(*TM); 149 150 SDLoc Loc; 151 auto IntVT = EVT::getIntegerVT(Context, 8); 152 auto VecVT = EVT::getVectorVT(Context, IntVT, 3); 153 auto IdxVT = EVT::getIntegerVT(Context, 64); 154 auto Vec = DAG->getConstant(1, Loc, VecVT); 155 auto ZeroIdx = DAG->getConstant(0, Loc, IdxVT); 156 auto Op = DAG->getNode(ISD::EXTRACT_SUBVECTOR, Loc, VecVT, Vec, ZeroIdx); 157 auto DemandedElts = APInt(3, 7); 158 auto KnownUndef = APInt(3, 0); 159 auto KnownZero = APInt(3, 0); 160 TargetLowering::TargetLoweringOpt TLO(*DAG, false, false); 161 EXPECT_EQ(TL.SimplifyDemandedVectorElts(Op, DemandedElts, KnownUndef, 162 KnownZero, TLO), 163 false); 164 } 165 166 // Piggy-backing on the AArch64 tests to verify SelectionDAG::computeKnownBits. 167 TEST_F(AArch64SelectionDAGTest, ComputeKnownBits_ADD) { 168 if (!TM) 169 return; 170 SDLoc Loc; 171 auto IntVT = EVT::getIntegerVT(Context, 8); 172 auto UnknownOp = DAG->getRegister(0, IntVT); 173 auto Mask = DAG->getConstant(0x8A, Loc, IntVT); 174 auto N0 = DAG->getNode(ISD::AND, Loc, IntVT, Mask, UnknownOp); 175 auto N1 = DAG->getConstant(0x55, Loc, IntVT); 176 auto Op = DAG->getNode(ISD::ADD, Loc, IntVT, N0, N1); 177 // N0 = ?000?0?0 178 // N1 = 01010101 179 // => 180 // Known.One = 01010101 (0x55) 181 // Known.Zero = 00100000 (0x20) 182 KnownBits Known = DAG->computeKnownBits(Op); 183 EXPECT_EQ(Known.Zero, APInt(8, 0x20)); 184 EXPECT_EQ(Known.One, APInt(8, 0x55)); 185 } 186 187 // Piggy-backing on the AArch64 tests to verify SelectionDAG::computeKnownBits. 188 TEST_F(AArch64SelectionDAGTest, ComputeKnownBits_SUB) { 189 if (!TM) 190 return; 191 SDLoc Loc; 192 auto IntVT = EVT::getIntegerVT(Context, 8); 193 auto N0 = DAG->getConstant(0x55, Loc, IntVT); 194 auto UnknownOp = DAG->getRegister(0, IntVT); 195 auto Mask = DAG->getConstant(0x2e, Loc, IntVT); 196 auto N1 = DAG->getNode(ISD::AND, Loc, IntVT, Mask, UnknownOp); 197 auto Op = DAG->getNode(ISD::SUB, Loc, IntVT, N0, N1); 198 // N0 = 01010101 199 // N1 = 00?0???0 200 // => 201 // Known.One = 00000001 (0x1) 202 // Known.Zero = 10000000 (0x80) 203 KnownBits Known = DAG->computeKnownBits(Op); 204 EXPECT_EQ(Known.Zero, APInt(8, 0x80)); 205 EXPECT_EQ(Known.One, APInt(8, 0x1)); 206 } 207 208 TEST_F(AArch64SelectionDAGTest, isSplatValue_Fixed_BUILD_VECTOR) { 209 if (!TM) 210 return; 211 212 TargetLowering TL(*TM); 213 214 SDLoc Loc; 215 auto IntVT = EVT::getIntegerVT(Context, 8); 216 auto VecVT = EVT::getVectorVT(Context, IntVT, 16, false); 217 // Create a BUILD_VECTOR 218 SDValue Op = DAG->getConstant(1, Loc, VecVT); 219 EXPECT_EQ(Op->getOpcode(), ISD::BUILD_VECTOR); 220 EXPECT_TRUE(DAG->isSplatValue(Op, /*AllowUndefs=*/false)); 221 222 APInt UndefElts; 223 APInt DemandedElts; 224 EXPECT_FALSE(DAG->isSplatValue(Op, DemandedElts, UndefElts)); 225 226 // Width=16, Mask=3 227 DemandedElts = APInt(16, 3); 228 EXPECT_TRUE(DAG->isSplatValue(Op, DemandedElts, UndefElts)); 229 } 230 231 TEST_F(AArch64SelectionDAGTest, isSplatValue_Fixed_ADD_of_BUILD_VECTOR) { 232 if (!TM) 233 return; 234 235 TargetLowering TL(*TM); 236 237 SDLoc Loc; 238 auto IntVT = EVT::getIntegerVT(Context, 8); 239 auto VecVT = EVT::getVectorVT(Context, IntVT, 16, false); 240 241 // Should create BUILD_VECTORs 242 SDValue Val1 = DAG->getConstant(1, Loc, VecVT); 243 SDValue Val2 = DAG->getConstant(3, Loc, VecVT); 244 EXPECT_EQ(Val1->getOpcode(), ISD::BUILD_VECTOR); 245 SDValue Op = DAG->getNode(ISD::ADD, Loc, VecVT, Val1, Val2); 246 247 EXPECT_TRUE(DAG->isSplatValue(Op, /*AllowUndefs=*/false)); 248 249 APInt UndefElts; 250 APInt DemandedElts; 251 EXPECT_FALSE(DAG->isSplatValue(Op, DemandedElts, UndefElts)); 252 253 // Width=16, Mask=3 254 DemandedElts = APInt(16, 3); 255 EXPECT_TRUE(DAG->isSplatValue(Op, DemandedElts, UndefElts)); 256 } 257 258 TEST_F(AArch64SelectionDAGTest, isSplatValue_Scalable_SPLAT_VECTOR) { 259 if (!TM) 260 return; 261 262 TargetLowering TL(*TM); 263 264 SDLoc Loc; 265 auto IntVT = EVT::getIntegerVT(Context, 8); 266 auto VecVT = EVT::getVectorVT(Context, IntVT, 16, true); 267 // Create a SPLAT_VECTOR 268 SDValue Op = DAG->getConstant(1, Loc, VecVT); 269 EXPECT_EQ(Op->getOpcode(), ISD::SPLAT_VECTOR); 270 EXPECT_TRUE(DAG->isSplatValue(Op, /*AllowUndefs=*/false)); 271 272 APInt UndefElts; 273 APInt DemandedElts; 274 EXPECT_TRUE(DAG->isSplatValue(Op, DemandedElts, UndefElts)); 275 276 // Width=16, Mask=3. These bits should be ignored. 277 DemandedElts = APInt(16, 3); 278 EXPECT_TRUE(DAG->isSplatValue(Op, DemandedElts, UndefElts)); 279 } 280 281 TEST_F(AArch64SelectionDAGTest, isSplatValue_Scalable_ADD_of_SPLAT_VECTOR) { 282 if (!TM) 283 return; 284 285 TargetLowering TL(*TM); 286 287 SDLoc Loc; 288 auto IntVT = EVT::getIntegerVT(Context, 8); 289 auto VecVT = EVT::getVectorVT(Context, IntVT, 16, true); 290 291 // Should create SPLAT_VECTORS 292 SDValue Val1 = DAG->getConstant(1, Loc, VecVT); 293 SDValue Val2 = DAG->getConstant(3, Loc, VecVT); 294 EXPECT_EQ(Val1->getOpcode(), ISD::SPLAT_VECTOR); 295 SDValue Op = DAG->getNode(ISD::ADD, Loc, VecVT, Val1, Val2); 296 297 EXPECT_TRUE(DAG->isSplatValue(Op, /*AllowUndefs=*/false)); 298 299 APInt UndefElts; 300 APInt DemandedElts; 301 EXPECT_TRUE(DAG->isSplatValue(Op, DemandedElts, UndefElts)); 302 303 // Width=16, Mask=3. These bits should be ignored. 304 DemandedElts = APInt(16, 3); 305 EXPECT_TRUE(DAG->isSplatValue(Op, DemandedElts, UndefElts)); 306 } 307 308 TEST_F(AArch64SelectionDAGTest, getSplatSourceVector_Fixed_BUILD_VECTOR) { 309 if (!TM) 310 return; 311 312 TargetLowering TL(*TM); 313 314 SDLoc Loc; 315 auto IntVT = EVT::getIntegerVT(Context, 8); 316 auto VecVT = EVT::getVectorVT(Context, IntVT, 16, false); 317 // Create a BUILD_VECTOR 318 SDValue Op = DAG->getConstant(1, Loc, VecVT); 319 EXPECT_EQ(Op->getOpcode(), ISD::BUILD_VECTOR); 320 321 int SplatIdx = -1; 322 EXPECT_EQ(DAG->getSplatSourceVector(Op, SplatIdx), Op); 323 EXPECT_EQ(SplatIdx, 0); 324 } 325 326 TEST_F(AArch64SelectionDAGTest, getSplatSourceVector_Fixed_ADD_of_BUILD_VECTOR) { 327 if (!TM) 328 return; 329 330 TargetLowering TL(*TM); 331 332 SDLoc Loc; 333 auto IntVT = EVT::getIntegerVT(Context, 8); 334 auto VecVT = EVT::getVectorVT(Context, IntVT, 16, false); 335 336 // Should create BUILD_VECTORs 337 SDValue Val1 = DAG->getConstant(1, Loc, VecVT); 338 SDValue Val2 = DAG->getConstant(3, Loc, VecVT); 339 EXPECT_EQ(Val1->getOpcode(), ISD::BUILD_VECTOR); 340 SDValue Op = DAG->getNode(ISD::ADD, Loc, VecVT, Val1, Val2); 341 342 int SplatIdx = -1; 343 EXPECT_EQ(DAG->getSplatSourceVector(Op, SplatIdx), Op); 344 EXPECT_EQ(SplatIdx, 0); 345 } 346 347 TEST_F(AArch64SelectionDAGTest, getSplatSourceVector_Scalable_SPLAT_VECTOR) { 348 if (!TM) 349 return; 350 351 TargetLowering TL(*TM); 352 353 SDLoc Loc; 354 auto IntVT = EVT::getIntegerVT(Context, 8); 355 auto VecVT = EVT::getVectorVT(Context, IntVT, 16, true); 356 // Create a SPLAT_VECTOR 357 SDValue Op = DAG->getConstant(1, Loc, VecVT); 358 EXPECT_EQ(Op->getOpcode(), ISD::SPLAT_VECTOR); 359 360 int SplatIdx = -1; 361 EXPECT_EQ(DAG->getSplatSourceVector(Op, SplatIdx), Op); 362 EXPECT_EQ(SplatIdx, 0); 363 } 364 365 TEST_F(AArch64SelectionDAGTest, getSplatSourceVector_Scalable_ADD_of_SPLAT_VECTOR) { 366 if (!TM) 367 return; 368 369 TargetLowering TL(*TM); 370 371 SDLoc Loc; 372 auto IntVT = EVT::getIntegerVT(Context, 8); 373 auto VecVT = EVT::getVectorVT(Context, IntVT, 16, true); 374 375 // Should create SPLAT_VECTORS 376 SDValue Val1 = DAG->getConstant(1, Loc, VecVT); 377 SDValue Val2 = DAG->getConstant(3, Loc, VecVT); 378 EXPECT_EQ(Val1->getOpcode(), ISD::SPLAT_VECTOR); 379 SDValue Op = DAG->getNode(ISD::ADD, Loc, VecVT, Val1, Val2); 380 381 int SplatIdx = -1; 382 EXPECT_EQ(DAG->getSplatSourceVector(Op, SplatIdx), Op); 383 EXPECT_EQ(SplatIdx, 0); 384 } 385 386 TEST_F(AArch64SelectionDAGTest, getTypeConversion_SplitScalableMVT) { 387 if (!TM) 388 return; 389 390 MVT VT = MVT::nxv4i64; 391 EXPECT_EQ(getTypeAction(VT), TargetLoweringBase::TypeSplitVector); 392 ASSERT_TRUE(getTypeToTransformTo(VT).isScalableVector()); 393 } 394 395 TEST_F(AArch64SelectionDAGTest, getTypeConversion_PromoteScalableMVT) { 396 if (!TM) 397 return; 398 399 MVT VT = MVT::nxv2i32; 400 EXPECT_EQ(getTypeAction(VT), TargetLoweringBase::TypePromoteInteger); 401 ASSERT_TRUE(getTypeToTransformTo(VT).isScalableVector()); 402 } 403 404 TEST_F(AArch64SelectionDAGTest, getTypeConversion_NoScalarizeMVT_nxv1f32) { 405 if (!TM) 406 return; 407 408 MVT VT = MVT::nxv1f32; 409 EXPECT_NE(getTypeAction(VT), TargetLoweringBase::TypeScalarizeVector); 410 ASSERT_TRUE(getTypeToTransformTo(VT).isScalableVector()); 411 } 412 413 TEST_F(AArch64SelectionDAGTest, getTypeConversion_SplitScalableEVT) { 414 if (!TM) 415 return; 416 417 EVT VT = EVT::getVectorVT(Context, MVT::i64, 256, true); 418 EXPECT_EQ(getTypeAction(VT), TargetLoweringBase::TypeSplitVector); 419 EXPECT_EQ(getTypeToTransformTo(VT), VT.getHalfNumVectorElementsVT(Context)); 420 } 421 422 TEST_F(AArch64SelectionDAGTest, getTypeConversion_WidenScalableEVT) { 423 if (!TM) 424 return; 425 426 EVT FromVT = EVT::getVectorVT(Context, MVT::i64, 6, true); 427 EVT ToVT = EVT::getVectorVT(Context, MVT::i64, 8, true); 428 429 EXPECT_EQ(getTypeAction(FromVT), TargetLoweringBase::TypeWidenVector); 430 EXPECT_EQ(getTypeToTransformTo(FromVT), ToVT); 431 } 432 433 TEST_F(AArch64SelectionDAGTest, getTypeConversion_NoScalarizeEVT_nxv1f128) { 434 if (!TM) 435 return; 436 437 EVT FromVT = EVT::getVectorVT(Context, MVT::f128, 1, true); 438 EXPECT_DEATH(getTypeAction(FromVT), "Cannot legalize this vector"); 439 } 440 441 } // end namespace llvm 442