Skip to content

Commit d6de5f1

Browse files
author
Francesco Petrogalli
committed
[SVFS] Inject TLI Mappings in VFABI attribute.
This patch introduces a function pass to inject the scalar-to-vector mappings stored in the TargetLIbraryInfo (TLI) into the Vector Function ABI (VFABI) variants attribute. The test is testing the injection for three vector libraries supported by the TLI (Accelerate, SVML, MASSV). The pass does not change any of the analysis associated to the function. Differential Revision: https://reviews.llvm.org/D70107
1 parent 209e30b commit d6de5f1

File tree

13 files changed

+326
-0
lines changed

13 files changed

+326
-0
lines changed

llvm/include/llvm/Analysis/TargetLibraryInfo.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,10 @@ class TargetLibraryInfoImpl {
197197
/// Returns the size of the wchar_t type in bytes or 0 if the size is unknown.
198198
/// This queries the 'wchar_size' metadata.
199199
unsigned getWCharSize(const Module &M) const;
200+
201+
/// Returns the largest vectorization factor used in the list of
202+
/// vector functions.
203+
unsigned getWidestVF(StringRef ScalarF) const;
200204
};
201205

202206
/// Provides information about what library functions are available for
@@ -337,6 +341,12 @@ class TargetLibraryInfo {
337341
FunctionAnalysisManager::Invalidator &) {
338342
return false;
339343
}
344+
345+
/// Returns the largest vectorization factor used in the list of
346+
/// vector functions.
347+
unsigned getWidestVF(StringRef ScalarF) const {
348+
return Impl->getWidestVF(ScalarF);
349+
}
340350
};
341351

342352
/// Analysis pass providing the \c TargetLibraryInfo.

llvm/include/llvm/InitializePasses.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,7 @@ void initializeIndVarSimplifyLegacyPassPass(PassRegistry&);
180180
void initializeIndirectBrExpandPassPass(PassRegistry&);
181181
void initializeInferAddressSpacesPass(PassRegistry&);
182182
void initializeInferFunctionAttrsLegacyPassPass(PassRegistry&);
183+
void initializeInjectTLIMappingsLegacyPass(PassRegistry &);
183184
void initializeInlineCostAnalysisPass(PassRegistry&);
184185
void initializeInstCountPass(PassRegistry&);
185186
void initializeInstNamerPass(PassRegistry&);

llvm/include/llvm/LinkAllPasses.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,7 @@ namespace {
225225
(void) llvm::createScalarizeMaskedMemIntrinPass();
226226
(void) llvm::createWarnMissedTransformationsPass();
227227
(void) llvm::createHardwareLoopsPass();
228+
(void)llvm::createInjectTLIMappingsLegacyPass();
228229

229230
(void)new llvm::IntervalPartition();
230231
(void)new llvm::ScalarEvolutionWrapperPass();

llvm/include/llvm/Transforms/Utils.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,13 @@ ModulePass *createStripNonLineTableDebugInfoPass();
119119
// number of conditional branches in the hot paths based on profiles.
120120
//
121121
FunctionPass *createControlHeightReductionLegacyPass();
122+
123+
//===----------------------------------------------------------------------===//
124+
//
125+
// InjectTLIMappingsLegacy - populates the VFABI attribute with the
126+
// scalar-to-vector mappings from the TargetLibraryInfo.
127+
//
128+
FunctionPass *createInjectTLIMappingsLegacyPass();
122129
}
123130

124131
#endif
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
//===- InjectTLIMAppings.h - TLI to VFABI attribute injection ------------===//
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+
// Populates the VFABI attribute with the scalar-to-vector mappings
10+
// from the TargetLibraryInfo.
11+
//
12+
//===----------------------------------------------------------------------===//
13+
#ifndef LLVM_TRANSFORMS_UTILS_INJECTTLIMAPPINGS_H
14+
#define LLVM_TRANSFORMS_UTILS_INJECTTLIMAPPINGS_H
15+
16+
#include "llvm/IR/PassManager.h"
17+
#include "llvm/InitializePasses.h"
18+
19+
namespace llvm {
20+
class InjectTLIMappings : public PassInfoMixin<InjectTLIMappings> {
21+
public:
22+
PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM);
23+
};
24+
25+
// Legacy pass
26+
class InjectTLIMappingsLegacy : public FunctionPass {
27+
public:
28+
static char ID;
29+
InjectTLIMappingsLegacy() : FunctionPass(ID) {
30+
initializeInjectTLIMappingsLegacyPass(*PassRegistry::getPassRegistry());
31+
}
32+
void getAnalysisUsage(AnalysisUsage &AU) const override;
33+
bool runOnFunction(Function &F) override;
34+
};
35+
36+
} // End namespace llvm
37+
#endif // LLVM_TRANSFORMS_UTILS_INJECTTLIMAPPINGS_H

llvm/lib/Analysis/TargetLibraryInfo.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1637,3 +1637,19 @@ INITIALIZE_PASS(TargetLibraryInfoWrapperPass, "targetlibinfo",
16371637
char TargetLibraryInfoWrapperPass::ID = 0;
16381638

16391639
void TargetLibraryInfoWrapperPass::anchor() {}
1640+
1641+
unsigned TargetLibraryInfoImpl::getWidestVF(StringRef ScalarF) const {
1642+
ScalarF = sanitizeFunctionName(ScalarF);
1643+
if (ScalarF.empty())
1644+
return 1;
1645+
1646+
unsigned VF = 1;
1647+
std::vector<VecDesc>::const_iterator I =
1648+
llvm::lower_bound(VectorDescs, ScalarF, compareWithScalarFnName);
1649+
while (I != VectorDescs.end() && StringRef(I->ScalarFnName) == ScalarF) {
1650+
if (I->VectorizationFactor > VF)
1651+
VF = I->VectorizationFactor;
1652+
++I;
1653+
}
1654+
return VF;
1655+
}

llvm/lib/Analysis/VectorUtils.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1166,6 +1166,9 @@ void VFABI::getVectorVariantNames(
11661166
const StringRef S =
11671167
CI.getAttribute(AttributeList::FunctionIndex, VFABI::MappingsAttrName)
11681168
.getValueAsString();
1169+
if (S.empty())
1170+
return;
1171+
11691172
SmallVector<StringRef, 8> ListAttr;
11701173
S.split(ListAttr, ",");
11711174

llvm/lib/Passes/PassBuilder.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,7 @@
170170
#include "llvm/Transforms/Utils/BreakCriticalEdges.h"
171171
#include "llvm/Transforms/Utils/CanonicalizeAliases.h"
172172
#include "llvm/Transforms/Utils/EntryExitInstrumenter.h"
173+
#include "llvm/Transforms/Utils/InjectTLIMappings.h"
173174
#include "llvm/Transforms/Utils/LCSSA.h"
174175
#include "llvm/Transforms/Utils/LibCallsShrinkWrap.h"
175176
#include "llvm/Transforms/Utils/LoopSimplify.h"

llvm/lib/Passes/PassRegistry.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,7 @@ FUNCTION_PASS("invalidate<all>", InvalidateAllAnalysesPass())
184184
FUNCTION_PASS("float2int", Float2IntPass())
185185
FUNCTION_PASS("no-op-function", NoOpFunctionPass())
186186
FUNCTION_PASS("libcalls-shrinkwrap", LibCallsShrinkWrapPass())
187+
FUNCTION_PASS("inject-tli-mappings", InjectTLIMappings())
187188
FUNCTION_PASS("loweratomic", LowerAtomicPass())
188189
FUNCTION_PASS("lower-expect", LowerExpectIntrinsicPass())
189190
FUNCTION_PASS("lower-guard-intrinsic", LowerGuardIntrinsicPass())

llvm/lib/Transforms/Utils/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ add_llvm_library(LLVMTransformUtils
2323
GuardUtils.cpp
2424
InlineFunction.cpp
2525
ImportedFunctionsInliningStatistics.cpp
26+
InjectTLIMappings.cpp
2627
InstructionNamer.cpp
2728
IntegerDivision.cpp
2829
LCSSA.cpp
Lines changed: 186 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,186 @@
1+
//===- InjectTLIMAppings.cpp - TLI to VFABI attribute injection ----------===//
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+
// Populates the VFABI attribute with the scalar-to-vector mappings
10+
// from the TargetLibraryInfo.
11+
//
12+
//===----------------------------------------------------------------------===//
13+
14+
#include "llvm/Transforms/Utils/InjectTLIMappings.h"
15+
#include "llvm/ADT/Statistic.h"
16+
#include "llvm/Analysis/VectorUtils.h"
17+
#include "llvm/IR/InstIterator.h"
18+
#include "llvm/Transforms/Utils.h"
19+
#include "llvm/Transforms/Utils/ModuleUtils.h"
20+
21+
using namespace llvm;
22+
23+
#define DEBUG_TYPE "inject-tli-mappings"
24+
25+
STATISTIC(NumCallInjected,
26+
"Number of calls in which the mappings have been injected.");
27+
28+
STATISTIC(NumVFDeclAdded,
29+
"Number of function declarations that have been added.");
30+
STATISTIC(NumCompUsedAdded,
31+
"Number of `@llvm.compiler.used` operands that have been added.");
32+
33+
/// Helper function to map the TLI name to a strings that holds
34+
/// scalar-to-vector mapping.
35+
///
36+
/// _ZGV<isa><mask><vlen><vparams>_<scalarname>(<vectorname>)
37+
///
38+
/// where:
39+
///
40+
/// <isa> = "_LLVM_"
41+
/// <mask> = "N". Note: TLI does not support masked interfaces.
42+
/// <vlen> = Number of concurrent lanes, stored in the `VectorizationFactor`
43+
/// field of the `VecDesc` struct.
44+
/// <vparams> = "v", as many as are the number of parameters of CI.
45+
/// <scalarname> = the name of the scalar function called by CI.
46+
/// <vectorname> = the name of the vector function mapped by the TLI.
47+
static std::string mangleTLIName(StringRef VectorName, const CallInst &CI,
48+
unsigned VF) {
49+
SmallString<256> Buffer;
50+
llvm::raw_svector_ostream Out(Buffer);
51+
Out << "_ZGV" << VFABI::_LLVM_ << "N" << VF;
52+
for (unsigned I = 0; I < CI.getNumArgOperands(); ++I)
53+
Out << "v";
54+
Out << "_" << CI.getCalledFunction()->getName() << "(" << VectorName << ")";
55+
return Out.str();
56+
}
57+
58+
/// A helper function for converting Scalar types to vector types.
59+
/// If the incoming type is void, we return void. If the VF is 1, we return
60+
/// the scalar type.
61+
static Type *ToVectorTy(Type *Scalar, unsigned VF, bool isScalable = false) {
62+
if (Scalar->isVoidTy() || VF == 1)
63+
return Scalar;
64+
return VectorType::get(Scalar, {VF, isScalable});
65+
}
66+
67+
/// A helper function that adds the vector function declaration that
68+
/// vectorizes the CallInst CI with a vectorization factor of VF
69+
/// lanes. The TLI assumes that all parameters and the return type of
70+
/// CI (other than void) need to be widened to a VectorType of VF
71+
/// lanes.
72+
static void addVariantDeclaration(CallInst &CI, const unsigned VF,
73+
const StringRef VFName) {
74+
Module *M = CI.getModule();
75+
76+
// Add function declaration.
77+
Type *RetTy = ToVectorTy(CI.getType(), VF);
78+
SmallVector<Type *, 4> Tys;
79+
for (Value *ArgOperand : CI.arg_operands())
80+
Tys.push_back(ToVectorTy(ArgOperand->getType(), VF));
81+
assert(!CI.getFunctionType()->isVarArg() &&
82+
"VarArg functions are not supported.");
83+
FunctionType *FTy = FunctionType::get(RetTy, Tys, /*isVarArg=*/false);
84+
Function *VectorF =
85+
Function::Create(FTy, Function::ExternalLinkage, VFName, M);
86+
VectorF->copyAttributesFrom(CI.getCalledFunction());
87+
++NumVFDeclAdded;
88+
LLVM_DEBUG(dbgs() << DEBUG_TYPE << ": Added to the module: `" << VFName
89+
<< "` of type " << *(VectorF->getType()) << "\n");
90+
91+
// Make function declaration (without a body) "sticky" in the IR by
92+
// listing it in the @llvm.compiler.used intrinsic.
93+
assert(!VectorF->size() && "VFABI attribute requires `@llvm.compiler.used` "
94+
"only on declarations.");
95+
appendToCompilerUsed(*M, {VectorF});
96+
LLVM_DEBUG(dbgs() << DEBUG_TYPE << ": Adding `" << VFName
97+
<< "` to `@llvm.compiler.used`.\n");
98+
++NumCompUsedAdded;
99+
}
100+
101+
static void addMappingsFromTLI(const TargetLibraryInfo &TLI, CallInst &CI) {
102+
// This is needed to make sure we don't query the TLI for calls to
103+
// bitcast of function pointers, like `%call = call i32 (i32*, ...)
104+
// bitcast (i32 (...)* @goo to i32 (i32*, ...)*)(i32* nonnull %i)`,
105+
// as such calls make the `isFunctionVectorizable` raise an
106+
// exception.
107+
if (CI.isNoBuiltin() || !CI.getCalledFunction())
108+
return;
109+
110+
const std::string ScalarName = CI.getCalledFunction()->getName();
111+
// Nothing to be done if the TLI thinks the function is not
112+
// vectorizable.
113+
if (!TLI.isFunctionVectorizable(ScalarName))
114+
return;
115+
SmallVector<std::string, 8> Mappings;
116+
VFABI::getVectorVariantNames(CI, Mappings);
117+
Module *M = CI.getModule();
118+
const SetVector<StringRef> OriginalSetOfMappings(Mappings.begin(),
119+
Mappings.end());
120+
// All VFs in the TLI are powers of 2.
121+
for (unsigned VF = 2, WidestVF = TLI.getWidestVF(ScalarName); VF <= WidestVF;
122+
VF *= 2) {
123+
const std::string TLIName = TLI.getVectorizedFunction(ScalarName, VF);
124+
if (!TLIName.empty()) {
125+
std::string MangledName = mangleTLIName(TLIName, CI, VF);
126+
if (!OriginalSetOfMappings.count(MangledName)) {
127+
Mappings.push_back(MangledName);
128+
++NumCallInjected;
129+
}
130+
Function *VariantF = M->getFunction(TLIName);
131+
if (!VariantF)
132+
addVariantDeclaration(CI, VF, TLIName);
133+
}
134+
}
135+
136+
VFABI::setVectorVariantNames(&CI, Mappings);
137+
}
138+
139+
static bool runImpl(const TargetLibraryInfo &TLI, Function &F) {
140+
for (auto &I : instructions(F))
141+
if (auto CI = dyn_cast<CallInst>(&I))
142+
addMappingsFromTLI(TLI, *CI);
143+
// Even if the pass adds IR attributes, the analyses are preserved.
144+
return false;
145+
}
146+
147+
////////////////////////////////////////////////////////////////////////////////
148+
// New pass manager implementation.
149+
////////////////////////////////////////////////////////////////////////////////
150+
PreservedAnalyses InjectTLIMappings::run(Function &F,
151+
FunctionAnalysisManager &AM) {
152+
const TargetLibraryInfo &TLI = AM.getResult<TargetLibraryAnalysis>(F);
153+
runImpl(TLI, F);
154+
// Even if the pass adds IR attributes, the analyses are preserved.
155+
return PreservedAnalyses::all();
156+
}
157+
158+
////////////////////////////////////////////////////////////////////////////////
159+
// Legacy PM Implementation.
160+
////////////////////////////////////////////////////////////////////////////////
161+
bool InjectTLIMappingsLegacy::runOnFunction(Function &F) {
162+
const TargetLibraryInfo &TLI =
163+
getAnalysis<TargetLibraryInfoWrapperPass>().getTLI(F);
164+
return runImpl(TLI, F);
165+
}
166+
167+
void InjectTLIMappingsLegacy::getAnalysisUsage(AnalysisUsage &AU) const {
168+
AU.setPreservesCFG();
169+
AU.addRequired<TargetLibraryInfoWrapperPass>();
170+
AU.addPreserved<TargetLibraryInfoWrapperPass>();
171+
}
172+
173+
////////////////////////////////////////////////////////////////////////////////
174+
// Legacy Pass manager initialization
175+
////////////////////////////////////////////////////////////////////////////////
176+
char InjectTLIMappingsLegacy::ID = 0;
177+
178+
INITIALIZE_PASS_BEGIN(InjectTLIMappingsLegacy, DEBUG_TYPE,
179+
"Inject TLI Mappings", false, false)
180+
INITIALIZE_PASS_DEPENDENCY(TargetLibraryInfoWrapperPass)
181+
INITIALIZE_PASS_END(InjectTLIMappingsLegacy, DEBUG_TYPE, "Inject TLI Mappings",
182+
false, false)
183+
184+
FunctionPass *llvm::createInjectTLIMappingsLegacyPass() {
185+
return new InjectTLIMappingsLegacy();
186+
}

llvm/lib/Transforms/Utils/Utils.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ void llvm::initializeTransformUtils(PassRegistry &Registry) {
3939
initializeMetaRenamerPass(Registry);
4040
initializeStripGCRelocatesPass(Registry);
4141
initializePredicateInfoPrinterLegacyPassPass(Registry);
42+
initializeInjectTLIMappingsLegacyPass(Registry);
4243
}
4344

4445
/// LLVMInitializeTransformUtils - C binding for initializeTransformUtilsPasses.

0 commit comments

Comments
 (0)