brintos

brintos / llvm-project-archived public Read only

0
0
Text · 17.5 KiB · 586f846 Raw
507 lines · cpp
1//===- LegalityTest.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/Transforms/Vectorize/SandboxVectorizer/Legality.h"10#include "llvm/Analysis/AssumptionCache.h"11#include "llvm/Analysis/BasicAliasAnalysis.h"12#include "llvm/Analysis/LoopInfo.h"13#include "llvm/Analysis/ScalarEvolution.h"14#include "llvm/Analysis/TargetLibraryInfo.h"15#include "llvm/AsmParser/Parser.h"16#include "llvm/IR/DataLayout.h"17#include "llvm/IR/Dominators.h"18#include "llvm/SandboxIR/Function.h"19#include "llvm/SandboxIR/Instruction.h"20#include "llvm/Support/SourceMgr.h"21#include "llvm/Transforms/Vectorize/SandboxVectorizer/InstrMaps.h"22#include "gmock/gmock.h"23#include "gtest/gtest.h"24 25using namespace llvm;26 27struct LegalityTest : public testing::Test {28  LLVMContext C;29  std::unique_ptr<Module> M;30  std::unique_ptr<DominatorTree> DT;31  std::unique_ptr<TargetLibraryInfoImpl> TLII;32  std::unique_ptr<TargetLibraryInfo> TLI;33  std::unique_ptr<AssumptionCache> AC;34  std::unique_ptr<LoopInfo> LI;35  std::unique_ptr<ScalarEvolution> SE;36  std::unique_ptr<BasicAAResult> BAA;37  std::unique_ptr<AAResults> AA;38 39  void getAnalyses(llvm::Function &LLVMF) {40    DT = std::make_unique<DominatorTree>(LLVMF);41    AC = std::make_unique<AssumptionCache>(LLVMF);42    LI = std::make_unique<LoopInfo>(*DT);43    SE = std::make_unique<ScalarEvolution>(LLVMF, *TLI, *AC, *DT, *LI);44    BAA = std::make_unique<BasicAAResult>(LLVMF.getParent()->getDataLayout(),45                                          LLVMF, *TLI, *AC, DT.get());46    AA = std::make_unique<AAResults>(*TLI);47    AA->addAAResult(*BAA);48  }49 50  void parseIR(LLVMContext &C, const char *IR) {51    SMDiagnostic Err;52    M = parseAssemblyString(IR, Err, C);53    if (!M) {54      Err.print("LegalityTest", errs());55      return;56    }57 58    TLII = std::make_unique<TargetLibraryInfoImpl>(M->getTargetTriple());59    TLI = std::make_unique<TargetLibraryInfo>(*TLII);60  }61};62 63static sandboxir::BasicBlock *getBasicBlockByName(sandboxir::Function *F,64                                                  StringRef Name) {65  for (sandboxir::BasicBlock &BB : *F)66    if (BB.getName() == Name)67      return &BB;68  llvm_unreachable("Expected to find basic block!");69}70 71TEST_F(LegalityTest, LegalitySkipSchedule) {72  parseIR(C, R"IR(73define void @foo(ptr %ptr, <2 x float> %vec2, <3 x float> %vec3, i8 %arg, float %farg0, float %farg1, i64 %v0, i64 %v1, i32 %v2, i1 %c0, i1 %c1) {74entry:75  %gep0 = getelementptr float, ptr %ptr, i32 076  %gep1 = getelementptr float, ptr %ptr, i32 177  store float %farg0, ptr %gep178  br label %bb79 80bb:81  %gep3 = getelementptr float, ptr %ptr, i32 382  %ld0 = load float, ptr %gep083  %ld0b = load float, ptr %gep084  %ld1 = load float, ptr %gep185  %ld3 = load float, ptr %gep386  store float %ld0, ptr %gep087  store float %ld1, ptr %gep188  store <2 x float> %vec2, ptr %gep189  store <3 x float> %vec3, ptr %gep390  store i8 %arg, ptr %gep191  %fadd0 = fadd float %farg0, %farg092  %fadd1 = fadd fast float %farg1, %farg193  %trunc0 = trunc nuw nsw i64 %v0 to i894  %trunc1 = trunc nsw i64 %v1 to i895  %trunc64to8 = trunc i64 %v0 to i896  %trunc32to8 = trunc i32 %v2 to i897  %cmpSLT = icmp slt i64 %v0, %v198  %cmpSGT = icmp sgt i64 %v0, %v199  %sel0 = select i1 %c0, <2 x float> %vec2, <2 x float> %vec2100  %sel1 = select i1 %c1, <2 x float> %vec2, <2 x float> %vec2101  ret void102}103)IR");104  llvm::Function *LLVMF = &*M->getFunction("foo");105  getAnalyses(*LLVMF);106  const auto &DL = M->getDataLayout();107 108  sandboxir::Context Ctx(C);109  auto *F = Ctx.createFunction(LLVMF);110  auto *EntryBB = getBasicBlockByName(F, "entry");111  auto It = EntryBB->begin();112  [[maybe_unused]] auto *Gep0 = cast<sandboxir::GetElementPtrInst>(&*It++);113  [[maybe_unused]] auto *Gep1 = cast<sandboxir::GetElementPtrInst>(&*It++);114  auto *St1Entry = cast<sandboxir::StoreInst>(&*It++);115 116  auto *BB = getBasicBlockByName(F, "bb");117  It = BB->begin();118  [[maybe_unused]] auto *Gep3 = cast<sandboxir::GetElementPtrInst>(&*It++);119  auto *Ld0 = cast<sandboxir::LoadInst>(&*It++);120  auto *Ld0b = cast<sandboxir::LoadInst>(&*It++);121  auto *Ld1 = cast<sandboxir::LoadInst>(&*It++);122  auto *Ld3 = cast<sandboxir::LoadInst>(&*It++);123  auto *St0 = cast<sandboxir::StoreInst>(&*It++);124  auto *St1 = cast<sandboxir::StoreInst>(&*It++);125  auto *StVec2 = cast<sandboxir::StoreInst>(&*It++);126  auto *StVec3 = cast<sandboxir::StoreInst>(&*It++);127  auto *StI8 = cast<sandboxir::StoreInst>(&*It++);128  auto *FAdd0 = cast<sandboxir::BinaryOperator>(&*It++);129  auto *FAdd1 = cast<sandboxir::BinaryOperator>(&*It++);130  auto *Trunc0 = cast<sandboxir::TruncInst>(&*It++);131  auto *Trunc1 = cast<sandboxir::TruncInst>(&*It++);132  auto *Trunc64to8 = cast<sandboxir::TruncInst>(&*It++);133  auto *Trunc32to8 = cast<sandboxir::TruncInst>(&*It++);134  auto *CmpSLT = cast<sandboxir::CmpInst>(&*It++);135  auto *CmpSGT = cast<sandboxir::CmpInst>(&*It++);136  auto *Sel0 = cast<sandboxir::SelectInst>(&*It++);137  auto *Sel1 = cast<sandboxir::SelectInst>(&*It++);138 139  llvm::sandboxir::InstrMaps IMaps;140  sandboxir::LegalityAnalysis Legality(*AA, *SE, DL, Ctx, IMaps);141  const auto &Result =142      Legality.canVectorize({St0, St1}, /*SkipScheduling=*/true);143  EXPECT_TRUE(isa<sandboxir::Widen>(Result));144 145  {146    // Check NotInstructions147    auto &Result = Legality.canVectorize({F, St0}, /*SkipScheduling=*/true);148    EXPECT_TRUE(isa<sandboxir::Pack>(Result));149    EXPECT_EQ(cast<sandboxir::Pack>(Result).getReason(),150              sandboxir::ResultReason::NotInstructions);151  }152  {153    // Check DiffOpcodes154    const auto &Result =155        Legality.canVectorize({St0, Ld0}, /*SkipScheduling=*/true);156    EXPECT_TRUE(isa<sandboxir::Pack>(Result));157    EXPECT_EQ(cast<sandboxir::Pack>(Result).getReason(),158              sandboxir::ResultReason::DiffOpcodes);159  }160  {161    // Check DiffTypes162    EXPECT_TRUE(isa<sandboxir::Widen>(163        Legality.canVectorize({St0, StVec2}, /*SkipScheduling=*/true)));164    EXPECT_TRUE(isa<sandboxir::Widen>(165        Legality.canVectorize({StVec2, StVec3}, /*SkipScheduling=*/true)));166 167    const auto &Result =168        Legality.canVectorize({St0, StI8}, /*SkipScheduling=*/true);169    EXPECT_TRUE(isa<sandboxir::Pack>(Result));170    EXPECT_EQ(cast<sandboxir::Pack>(Result).getReason(),171              sandboxir::ResultReason::DiffTypes);172  }173  {174    // Check DiffMathFlags175    const auto &Result =176        Legality.canVectorize({FAdd0, FAdd1}, /*SkipScheduling=*/true);177    EXPECT_TRUE(isa<sandboxir::Pack>(Result));178    EXPECT_EQ(cast<sandboxir::Pack>(Result).getReason(),179              sandboxir::ResultReason::DiffMathFlags);180  }181  {182    // Check DiffWrapFlags183    const auto &Result =184        Legality.canVectorize({Trunc0, Trunc1}, /*SkipScheduling=*/true);185    EXPECT_TRUE(isa<sandboxir::Pack>(Result));186    EXPECT_EQ(cast<sandboxir::Pack>(Result).getReason(),187              sandboxir::ResultReason::DiffWrapFlags);188  }189  {190    // Check DiffBBs191    const auto &Result =192        Legality.canVectorize({St0, St1Entry}, /*SkipScheduling=*/true);193    EXPECT_TRUE(isa<sandboxir::Pack>(Result));194    EXPECT_EQ(cast<sandboxir::Pack>(Result).getReason(),195              sandboxir::ResultReason::DiffBBs);196  }197  {198    // Check DiffTypes for unary operands that have a different type.199    const auto &Result = Legality.canVectorize({Trunc64to8, Trunc32to8},200                                               /*SkipScheduling=*/true);201    EXPECT_TRUE(isa<sandboxir::Pack>(Result));202    EXPECT_EQ(cast<sandboxir::Pack>(Result).getReason(),203              sandboxir::ResultReason::DiffTypes);204  }205  {206    // Check DiffOpcodes for CMPs with different predicates.207    const auto &Result =208        Legality.canVectorize({CmpSLT, CmpSGT}, /*SkipScheduling=*/true);209    EXPECT_TRUE(isa<sandboxir::Pack>(Result));210    EXPECT_EQ(cast<sandboxir::Pack>(Result).getReason(),211              sandboxir::ResultReason::DiffOpcodes);212  }213  {214    // Check NotConsecutive Ld0,Ld0b215    const auto &Result =216        Legality.canVectorize({Ld0, Ld0b}, /*SkipScheduling=*/true);217    EXPECT_TRUE(isa<sandboxir::Pack>(Result));218    EXPECT_EQ(cast<sandboxir::Pack>(Result).getReason(),219              sandboxir::ResultReason::NotConsecutive);220  }221  {222    // Check NotConsecutive Ld0,Ld3223    const auto &Result =224        Legality.canVectorize({Ld0, Ld3}, /*SkipScheduling=*/true);225    EXPECT_TRUE(isa<sandboxir::Pack>(Result));226    EXPECT_EQ(cast<sandboxir::Pack>(Result).getReason(),227              sandboxir::ResultReason::NotConsecutive);228  }229  {230    // Check Widen Ld0,Ld1231    const auto &Result =232        Legality.canVectorize({Ld0, Ld1}, /*SkipScheduling=*/true);233    EXPECT_TRUE(isa<sandboxir::Widen>(Result));234  }235  {236    // Check Repeated instructions (splat)237    const auto &Result =238        Legality.canVectorize({Ld0, Ld0}, /*SkipScheduling=*/true);239    EXPECT_TRUE(isa<sandboxir::Pack>(Result));240    EXPECT_EQ(cast<sandboxir::Pack>(Result).getReason(),241              sandboxir::ResultReason::RepeatedInstrs);242  }243  {244    // Check Repeated instructions (not splat)245    const auto &Result =246        Legality.canVectorize({Ld0, Ld1, Ld0}, /*SkipScheduling=*/true);247    EXPECT_TRUE(isa<sandboxir::Pack>(Result));248    EXPECT_EQ(cast<sandboxir::Pack>(Result).getReason(),249              sandboxir::ResultReason::RepeatedInstrs);250  }251  {252    // For now don't vectorize Selects when the number of elements of conditions253    // doesn't match the operands.254    const auto &Result =255        Legality.canVectorize({Sel0, Sel1}, /*SkipScheduling=*/true);256    EXPECT_TRUE(isa<sandboxir::Pack>(Result));257    EXPECT_EQ(cast<sandboxir::Pack>(Result).getReason(),258              sandboxir::ResultReason::Unimplemented);259  }260}261 262TEST_F(LegalityTest, LegalitySchedule) {263  parseIR(C, R"IR(264define void @foo(ptr %ptr) {265  %gep0 = getelementptr float, ptr %ptr, i32 0266  %gep1 = getelementptr float, ptr %ptr, i32 1267  %ld0 = load float, ptr %gep0268  store float %ld0, ptr %gep1269  %ld1 = load float, ptr %gep1270  store float %ld0, ptr %gep0271  store float %ld1, ptr %gep1272  ret void273}274)IR");275  llvm::Function *LLVMF = &*M->getFunction("foo");276  getAnalyses(*LLVMF);277  const auto &DL = M->getDataLayout();278 279  sandboxir::Context Ctx(C);280  auto *F = Ctx.createFunction(LLVMF);281  auto *BB = &*F->begin();282  auto It = BB->begin();283  [[maybe_unused]] auto *Gep0 = cast<sandboxir::GetElementPtrInst>(&*It++);284  [[maybe_unused]] auto *Gep1 = cast<sandboxir::GetElementPtrInst>(&*It++);285  auto *Ld0 = cast<sandboxir::LoadInst>(&*It++);286  [[maybe_unused]] auto *ConflictingSt = cast<sandboxir::StoreInst>(&*It++);287  auto *Ld1 = cast<sandboxir::LoadInst>(&*It++);288  auto *St0 = cast<sandboxir::StoreInst>(&*It++);289  auto *St1 = cast<sandboxir::StoreInst>(&*It++);290 291  llvm::sandboxir::InstrMaps IMaps;292  sandboxir::LegalityAnalysis Legality(*AA, *SE, DL, Ctx, IMaps);293  {294    // Can vectorize St0,St1.295    const auto &Result = Legality.canVectorize({St0, St1});296    EXPECT_TRUE(isa<sandboxir::Widen>(Result));297  }298  {299    // Can't vectorize Ld0,Ld1 because of conflicting store.300    auto &Result = Legality.canVectorize({Ld0, Ld1});301    EXPECT_TRUE(isa<sandboxir::Pack>(Result));302    EXPECT_EQ(cast<sandboxir::Pack>(Result).getReason(),303              sandboxir::ResultReason::CantSchedule);304  }305}306 307#ifndef NDEBUG308TEST_F(LegalityTest, LegalityResultDump) {309  parseIR(C, R"IR(310define void @foo() {311  ret void312}313)IR");314  llvm::Function *LLVMF = &*M->getFunction("foo");315  getAnalyses(*LLVMF);316  const auto &DL = M->getDataLayout();317 318  auto Matches = [](const sandboxir::LegalityResult &Result,319                    const std::string &ExpectedStr) -> bool {320    std::string Buff;321    raw_string_ostream OS(Buff);322    Result.print(OS);323    return Buff == ExpectedStr;324  };325 326  sandboxir::Context Ctx(C);327  llvm::sandboxir::InstrMaps IMaps;328  sandboxir::LegalityAnalysis Legality(*AA, *SE, DL, Ctx, IMaps);329  EXPECT_TRUE(330      Matches(Legality.createLegalityResult<sandboxir::Widen>(), "Widen"));331  EXPECT_TRUE(Matches(Legality.createLegalityResult<sandboxir::Pack>(332                          sandboxir::ResultReason::NotInstructions),333                      "Pack Reason: NotInstructions"));334  EXPECT_TRUE(Matches(Legality.createLegalityResult<sandboxir::Pack>(335                          sandboxir::ResultReason::DiffOpcodes),336                      "Pack Reason: DiffOpcodes"));337  EXPECT_TRUE(Matches(Legality.createLegalityResult<sandboxir::Pack>(338                          sandboxir::ResultReason::DiffTypes),339                      "Pack Reason: DiffTypes"));340  EXPECT_TRUE(Matches(Legality.createLegalityResult<sandboxir::Pack>(341                          sandboxir::ResultReason::DiffMathFlags),342                      "Pack Reason: DiffMathFlags"));343  EXPECT_TRUE(Matches(Legality.createLegalityResult<sandboxir::Pack>(344                          sandboxir::ResultReason::DiffWrapFlags),345                      "Pack Reason: DiffWrapFlags"));346}347#endif // NDEBUG348 349TEST_F(LegalityTest, CollectDescr) {350  parseIR(C, R"IR(351define void @foo(ptr %ptr) {352  %gep0 = getelementptr float, ptr %ptr, i32 0353  %gep1 = getelementptr float, ptr %ptr, i32 1354  %ld0 = load float, ptr %gep0355  %ld1 = load float, ptr %gep1356  %vld = load <4 x float>, ptr %ptr357  ret void358}359)IR");360  llvm::Function *LLVMF = &*M->getFunction("foo");361  getAnalyses(*LLVMF);362  sandboxir::Context Ctx(C);363  auto *F = Ctx.createFunction(LLVMF);364  auto *BB = &*F->begin();365  auto It = BB->begin();366  [[maybe_unused]] auto *Gep0 = cast<sandboxir::GetElementPtrInst>(&*It++);367  [[maybe_unused]] auto *Gep1 = cast<sandboxir::GetElementPtrInst>(&*It++);368  auto *Ld0 = cast<sandboxir::LoadInst>(&*It++);369  [[maybe_unused]] auto *Ld1 = cast<sandboxir::LoadInst>(&*It++);370  auto *VLd = cast<sandboxir::LoadInst>(&*It++);371 372  sandboxir::CollectDescr::DescrVecT Descrs;373  using EEDescr = sandboxir::CollectDescr::ExtractElementDescr;374  SmallVector<sandboxir::Value *> Bndl({VLd});375  SmallVector<sandboxir::Value *> UB;376  sandboxir::Action VLdA(nullptr, Bndl, UB, 0);377  {378    // Check single input, no shuffle.379    Descrs.push_back(EEDescr(&VLdA, 0));380    Descrs.push_back(EEDescr(&VLdA, 1));381    sandboxir::CollectDescr CD(std::move(Descrs));382    EXPECT_TRUE(CD.getSingleInput());383    EXPECT_EQ(CD.getSingleInput()->first, &VLdA);384    EXPECT_THAT(CD.getSingleInput()->second, testing::ElementsAre(0, 1));385    EXPECT_TRUE(CD.hasVectorInputs());386  }387  {388    // Check single input, shuffle.389    Descrs.push_back(EEDescr(&VLdA, 1));390    Descrs.push_back(EEDescr(&VLdA, 0));391    sandboxir::CollectDescr CD(std::move(Descrs));392    EXPECT_TRUE(CD.getSingleInput());393    EXPECT_EQ(CD.getSingleInput()->first, &VLdA);394    EXPECT_THAT(CD.getSingleInput()->second, testing::ElementsAre(1, 0));395    EXPECT_TRUE(CD.hasVectorInputs());396  }397  {398    // Check multiple inputs.399    Descrs.push_back(EEDescr(Ld0));400    Descrs.push_back(EEDescr(&VLdA, 0));401    Descrs.push_back(EEDescr(&VLdA, 1));402    sandboxir::CollectDescr CD(std::move(Descrs));403    EXPECT_FALSE(CD.getSingleInput());404    EXPECT_TRUE(CD.hasVectorInputs());405  }406  {407    // Check multiple inputs only scalars.408    Descrs.push_back(EEDescr(Ld0));409    Descrs.push_back(EEDescr(Ld1));410    sandboxir::CollectDescr CD(std::move(Descrs));411    EXPECT_FALSE(CD.getSingleInput());412    EXPECT_FALSE(CD.hasVectorInputs());413  }414}415 416TEST_F(LegalityTest, ShuffleMask) {417  {418    // Check SmallVector constructor.419    SmallVector<int> Indices({0, 1, 2, 3});420    sandboxir::ShuffleMask Mask(std::move(Indices));421    EXPECT_THAT(Mask, testing::ElementsAre(0, 1, 2, 3));422  }423  {424    // Check initializer_list constructor.425    sandboxir::ShuffleMask Mask({0, 1, 2, 3});426    EXPECT_THAT(Mask, testing::ElementsAre(0, 1, 2, 3));427  }428  {429    // Check ArrayRef constructor.430    sandboxir::ShuffleMask Mask(ArrayRef<int>({0, 1, 2, 3}));431    EXPECT_THAT(Mask, testing::ElementsAre(0, 1, 2, 3));432  }433  {434    // Check operator ArrayRef<int>().435    sandboxir::ShuffleMask Mask({0, 1, 2, 3});436    ArrayRef<int> Array = Mask;437    EXPECT_THAT(Array, testing::ElementsAre(0, 1, 2, 3));438  }439  {440    // Check getIdentity().441    auto IdentityMask = sandboxir::ShuffleMask::getIdentity(4);442    EXPECT_THAT(IdentityMask, testing::ElementsAre(0, 1, 2, 3));443    EXPECT_TRUE(IdentityMask.isIdentity());444  }445  {446    // Check isIdentity().447    sandboxir::ShuffleMask Mask1({0, 1, 2, 3});448    EXPECT_TRUE(Mask1.isIdentity());449    sandboxir::ShuffleMask Mask2({1, 2, 3, 4});450    EXPECT_FALSE(Mask2.isIdentity());451  }452  {453    // Check operator==().454    sandboxir::ShuffleMask Mask1({0, 1, 2, 3});455    sandboxir::ShuffleMask Mask2({0, 1, 2, 3});456    EXPECT_TRUE(Mask1 == Mask2);457    EXPECT_FALSE(Mask1 != Mask2);458  }459  {460    // Check operator!=().461    sandboxir::ShuffleMask Mask1({0, 1, 2, 3});462    sandboxir::ShuffleMask Mask2({0, 1, 2, 4});463    EXPECT_TRUE(Mask1 != Mask2);464    EXPECT_FALSE(Mask1 == Mask2);465  }466  {467    // Check size().468    sandboxir::ShuffleMask Mask({0, 1, 2, 3});469    EXPECT_EQ(Mask.size(), 4u);470  }471  {472    // Check operator[].473    sandboxir::ShuffleMask Mask({0, 1, 2, 3});474    for (auto [Idx, Elm] : enumerate(Mask)) {475      EXPECT_EQ(Elm, Mask[Idx]);476    }477  }478  {479    // Check begin(), end().480    sandboxir::ShuffleMask Mask({0, 1, 2, 3});481    sandboxir::ShuffleMask::const_iterator Begin = Mask.begin();482    sandboxir::ShuffleMask::const_iterator End = Mask.begin();483    int Idx = 0;484    for (auto It = Begin; It != End; ++It) {485      EXPECT_EQ(*It, Mask[Idx++]);486    }487  }488#ifndef NDEBUG489  {490    // Check print(OS).491    sandboxir::ShuffleMask Mask({0, 1, 2, 3});492    std::string Str;493    raw_string_ostream OS(Str);494    Mask.print(OS);495    EXPECT_EQ(Str, "0,1,2,3");496  }497  {498    // Check operator<<().499    sandboxir::ShuffleMask Mask({0, 1, 2, 3});500    std::string Str;501    raw_string_ostream OS(Str);502    OS << Mask;503    EXPECT_EQ(Str, "0,1,2,3");504  }505#endif // NDEBUG506}507