1//===- SandboxVectorizer.cpp - Vectorizer based on Sandbox IR -------------===//
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/Transforms/Vectorize/SandboxVectorizer/SandboxVectorizer.h"
10#include "../VectorizeOptions.h"
11#include "llvm/Analysis/TargetTransformInfo.h"
12#include "llvm/IR/Module.h"
13#include "llvm/SandboxIR/Constant.h"
14#include "llvm/Support/Regex.h"
15#include "llvm/Transforms/Vectorize/SandboxVectorizer/Debug.h"
16#include "llvm/Transforms/Vectorize/SandboxVectorizer/SandboxVectorizerPassBuilder.h"
17
18using namespace llvm;
19
20/// A magic string for the default pass pipeline.
21static const char *DefaultPipelineMagicStr = "*";
22
23static constexpr char AllowFilesDelim = ',';
24
25SandboxVectorizerPass::SandboxVectorizerPass() : FPM("fpm") {}
26
27void SandboxVectorizerPass::buildPipeline() {
28 if (Opts->sbvec_passes == DefaultPipelineMagicStr) {
29 // TODO: Add passes to the default pipeline. It currently contains:
30 // - Seed collection, which creates seed regions and runs the pipeline
31 // - Bundle Vectorizer pass that starts from a seed
32 // - Load-Store Vectorizer pass for load-store chains
33 // - Accept or revert IR state pass
34 FPM.setPassPipeline(
35 Pipeline: "seed-collection<tr-save,bundle-vec(bottom-up),load-store-vec,"
36 "tr-accept-or-revert>",
37 CreatePass: sandboxir::SandboxVectorizerPassBuilder::createFunctionPass);
38 } else {
39 // Create the user-defined pipeline.
40 FPM.setPassPipeline(
41 Pipeline: Opts->sbvec_passes,
42 CreatePass: sandboxir::SandboxVectorizerPassBuilder::createFunctionPass);
43 }
44}
45
46SandboxVectorizerPass::SandboxVectorizerPass(SandboxVectorizerPass &&) =
47 default;
48
49SandboxVectorizerPass::~SandboxVectorizerPass() = default;
50
51PreservedAnalyses SandboxVectorizerPass::run(Function &F,
52 FunctionAnalysisManager &AM) {
53 TTI = &AM.getResult<TargetIRAnalysis>(IR&: F);
54 AA = &AM.getResult<AAManager>(IR&: F);
55 SE = &AM.getResult<ScalarEvolutionAnalysis>(IR&: F);
56
57 bool Changed = runImpl(F);
58 if (!Changed)
59 return PreservedAnalyses::all();
60
61 PreservedAnalyses PA;
62 PA.preserveSet<CFGAnalyses>();
63 return PA;
64}
65
66bool SandboxVectorizerPass::allowFile(const std::string &SrcFilePath) {
67 // Iterate over all files in AllowFiles separated by `AllowFilesDelim`.
68 size_t DelimPos = 0;
69 do {
70 size_t LastPos = DelimPos != 0 ? DelimPos + 1 : DelimPos;
71 DelimPos = Opts->sbvec_allow_files.find(C: AllowFilesDelim, From: LastPos);
72 auto FileNameToMatch =
73 Opts->sbvec_allow_files.substr(Start: LastPos, N: DelimPos - LastPos);
74 if (FileNameToMatch.empty())
75 return false;
76 // Note: This only runs when debugging so its OK not to reuse the regex.
77 Regex FileNameRegex((".*" + FileNameToMatch + "$").str());
78 assert(FileNameRegex.isValid() && "Bad regex!");
79 if (FileNameRegex.match(String: SrcFilePath))
80 return true;
81 } while (DelimPos != std::string::npos);
82 return false;
83}
84
85bool SandboxVectorizerPass::runImpl(Function &LLVMF) {
86 Opts = &LLVMF.getContext().getLibraryOptions().get<VectorizeOptions>();
87 if (Ctx == nullptr) {
88 Ctx = std::make_unique<sandboxir::Context>(args&: LLVMF.getContext());
89 buildPipeline();
90 }
91
92 if (Opts->sbvec_print_pass_pipeline) {
93 FPM.printPipeline(OS&: outs());
94 return false;
95 }
96
97 // This is used for debugging.
98 if (LLVM_UNLIKELY(Opts->sbvec_allow_files != ".*")) {
99 const auto &SrcFilePath = LLVMF.getParent()->getSourceFileName();
100 if (!allowFile(SrcFilePath))
101 return false;
102 }
103
104 // If the target claims to have no vector registers early return.
105 if (!TTI->getNumberOfRegisters(ClassID: TTI->getRegisterClassForType(Vector: true))) {
106 LLVM_DEBUG(dbgs() << DEBUG_PREFIX
107 << "Target has no vector registers, return.\n");
108 return false;
109 }
110 LLVM_DEBUG(dbgs() << DEBUG_PREFIX << "Analyzing " << LLVMF.getName()
111 << ".\n");
112 // Early return if the attribute NoImplicitFloat is used.
113 if (LLVMF.hasFnAttribute(Kind: Attribute::NoImplicitFloat)) {
114 LLVM_DEBUG(dbgs() << DEBUG_PREFIX
115 << "NoImplicitFloat attribute, return.\n");
116 return false;
117 }
118
119 // Create SandboxIR for LLVMF and run BundleVec on it.
120 sandboxir::Function &F = *Ctx->createFunction(F: &LLVMF);
121 sandboxir::Analyses A(*AA, *SE, *TTI);
122 bool Change = FPM.runOnFunction(F, A);
123 // Given that sandboxir::Context `Ctx` is defined at a pass-level scope, the
124 // maps from LLVM IR to Sandbox IR may go stale as later passes remove LLVM IR
125 // objects. To avoid issues caused by this clear the context's state.
126 // NOTE: The alternative would be to define Ctx and FPM within runOnFunction()
127 Ctx->clear();
128 return Change;
129}
130