Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/llvm/lib/Transforms/IPO/SCCP.cpp
35269 views
1
//===-- SCCP.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
// This file implements Interprocedural Sparse Conditional Constant Propagation.
10
//
11
//===----------------------------------------------------------------------===//
12
13
#include "llvm/Transforms/IPO/SCCP.h"
14
#include "llvm/ADT/SetVector.h"
15
#include "llvm/Analysis/AssumptionCache.h"
16
#include "llvm/Analysis/BlockFrequencyInfo.h"
17
#include "llvm/Analysis/PostDominators.h"
18
#include "llvm/Analysis/TargetLibraryInfo.h"
19
#include "llvm/Analysis/TargetTransformInfo.h"
20
#include "llvm/Analysis/ValueLattice.h"
21
#include "llvm/Analysis/ValueLatticeUtils.h"
22
#include "llvm/Analysis/ValueTracking.h"
23
#include "llvm/IR/AttributeMask.h"
24
#include "llvm/IR/Constants.h"
25
#include "llvm/IR/DIBuilder.h"
26
#include "llvm/IR/IntrinsicInst.h"
27
#include "llvm/Support/CommandLine.h"
28
#include "llvm/Support/ModRef.h"
29
#include "llvm/Transforms/IPO.h"
30
#include "llvm/Transforms/IPO/FunctionSpecialization.h"
31
#include "llvm/Transforms/Scalar/SCCP.h"
32
#include "llvm/Transforms/Utils/Local.h"
33
#include "llvm/Transforms/Utils/SCCPSolver.h"
34
35
using namespace llvm;
36
37
#define DEBUG_TYPE "sccp"
38
39
STATISTIC(NumInstRemoved, "Number of instructions removed");
40
STATISTIC(NumArgsElimed ,"Number of arguments constant propagated");
41
STATISTIC(NumGlobalConst, "Number of globals found to be constant");
42
STATISTIC(NumDeadBlocks , "Number of basic blocks unreachable");
43
STATISTIC(NumInstReplaced,
44
"Number of instructions replaced with (simpler) instruction");
45
46
static cl::opt<unsigned> FuncSpecMaxIters(
47
"funcspec-max-iters", cl::init(10), cl::Hidden, cl::desc(
48
"The maximum number of iterations function specialization is run"));
49
50
static void findReturnsToZap(Function &F,
51
SmallVector<ReturnInst *, 8> &ReturnsToZap,
52
SCCPSolver &Solver) {
53
// We can only do this if we know that nothing else can call the function.
54
if (!Solver.isArgumentTrackedFunction(&F))
55
return;
56
57
if (Solver.mustPreserveReturn(&F)) {
58
LLVM_DEBUG(
59
dbgs()
60
<< "Can't zap returns of the function : " << F.getName()
61
<< " due to present musttail or \"clang.arc.attachedcall\" call of "
62
"it\n");
63
return;
64
}
65
66
assert(
67
all_of(F.users(),
68
[&Solver](User *U) {
69
if (isa<Instruction>(U) &&
70
!Solver.isBlockExecutable(cast<Instruction>(U)->getParent()))
71
return true;
72
// Non-callsite uses are not impacted by zapping. Also, constant
73
// uses (like blockaddresses) could stuck around, without being
74
// used in the underlying IR, meaning we do not have lattice
75
// values for them.
76
if (!isa<CallBase>(U))
77
return true;
78
if (U->getType()->isStructTy()) {
79
return all_of(Solver.getStructLatticeValueFor(U),
80
[](const ValueLatticeElement &LV) {
81
return !SCCPSolver::isOverdefined(LV);
82
});
83
}
84
85
// We don't consider assume-like intrinsics to be actual address
86
// captures.
87
if (auto *II = dyn_cast<IntrinsicInst>(U)) {
88
if (II->isAssumeLikeIntrinsic())
89
return true;
90
}
91
92
return !SCCPSolver::isOverdefined(Solver.getLatticeValueFor(U));
93
}) &&
94
"We can only zap functions where all live users have a concrete value");
95
96
for (BasicBlock &BB : F) {
97
if (CallInst *CI = BB.getTerminatingMustTailCall()) {
98
LLVM_DEBUG(dbgs() << "Can't zap return of the block due to present "
99
<< "musttail call : " << *CI << "\n");
100
(void)CI;
101
return;
102
}
103
104
if (auto *RI = dyn_cast<ReturnInst>(BB.getTerminator()))
105
if (!isa<UndefValue>(RI->getOperand(0)))
106
ReturnsToZap.push_back(RI);
107
}
108
}
109
110
static bool runIPSCCP(
111
Module &M, const DataLayout &DL, FunctionAnalysisManager *FAM,
112
std::function<const TargetLibraryInfo &(Function &)> GetTLI,
113
std::function<TargetTransformInfo &(Function &)> GetTTI,
114
std::function<AssumptionCache &(Function &)> GetAC,
115
std::function<DominatorTree &(Function &)> GetDT,
116
std::function<BlockFrequencyInfo &(Function &)> GetBFI,
117
bool IsFuncSpecEnabled) {
118
SCCPSolver Solver(DL, GetTLI, M.getContext());
119
FunctionSpecializer Specializer(Solver, M, FAM, GetBFI, GetTLI, GetTTI,
120
GetAC);
121
122
// Loop over all functions, marking arguments to those with their addresses
123
// taken or that are external as overdefined.
124
for (Function &F : M) {
125
if (F.isDeclaration())
126
continue;
127
128
DominatorTree &DT = GetDT(F);
129
AssumptionCache &AC = GetAC(F);
130
Solver.addPredicateInfo(F, DT, AC);
131
132
// Determine if we can track the function's return values. If so, add the
133
// function to the solver's set of return-tracked functions.
134
if (canTrackReturnsInterprocedurally(&F))
135
Solver.addTrackedFunction(&F);
136
137
// Determine if we can track the function's arguments. If so, add the
138
// function to the solver's set of argument-tracked functions.
139
if (canTrackArgumentsInterprocedurally(&F)) {
140
Solver.addArgumentTrackedFunction(&F);
141
continue;
142
}
143
144
// Assume the function is called.
145
Solver.markBlockExecutable(&F.front());
146
147
for (Argument &AI : F.args())
148
Solver.trackValueOfArgument(&AI);
149
}
150
151
// Determine if we can track any of the module's global variables. If so, add
152
// the global variables we can track to the solver's set of tracked global
153
// variables.
154
for (GlobalVariable &G : M.globals()) {
155
G.removeDeadConstantUsers();
156
if (canTrackGlobalVariableInterprocedurally(&G))
157
Solver.trackValueOfGlobalVariable(&G);
158
}
159
160
// Solve for constants.
161
Solver.solveWhileResolvedUndefsIn(M);
162
163
if (IsFuncSpecEnabled) {
164
unsigned Iters = 0;
165
while (Iters++ < FuncSpecMaxIters && Specializer.run());
166
}
167
168
// Iterate over all of the instructions in the module, replacing them with
169
// constants if we have found them to be of constant values.
170
bool MadeChanges = false;
171
for (Function &F : M) {
172
if (F.isDeclaration())
173
continue;
174
175
SmallVector<BasicBlock *, 512> BlocksToErase;
176
177
if (Solver.isBlockExecutable(&F.front())) {
178
bool ReplacedPointerArg = false;
179
for (Argument &Arg : F.args()) {
180
if (!Arg.use_empty() && Solver.tryToReplaceWithConstant(&Arg)) {
181
ReplacedPointerArg |= Arg.getType()->isPointerTy();
182
++NumArgsElimed;
183
}
184
}
185
186
// If we replaced an argument, we may now also access a global (currently
187
// classified as "other" memory). Update memory attribute to reflect this.
188
if (ReplacedPointerArg) {
189
auto UpdateAttrs = [&](AttributeList AL) {
190
MemoryEffects ME = AL.getMemoryEffects();
191
if (ME == MemoryEffects::unknown())
192
return AL;
193
194
ME |= MemoryEffects(IRMemLocation::Other,
195
ME.getModRef(IRMemLocation::ArgMem));
196
return AL.addFnAttribute(
197
F.getContext(),
198
Attribute::getWithMemoryEffects(F.getContext(), ME));
199
};
200
201
F.setAttributes(UpdateAttrs(F.getAttributes()));
202
for (User *U : F.users()) {
203
auto *CB = dyn_cast<CallBase>(U);
204
if (!CB || CB->getCalledFunction() != &F)
205
continue;
206
207
CB->setAttributes(UpdateAttrs(CB->getAttributes()));
208
}
209
}
210
MadeChanges |= ReplacedPointerArg;
211
}
212
213
SmallPtrSet<Value *, 32> InsertedValues;
214
for (BasicBlock &BB : F) {
215
if (!Solver.isBlockExecutable(&BB)) {
216
LLVM_DEBUG(dbgs() << " BasicBlock Dead:" << BB);
217
++NumDeadBlocks;
218
219
MadeChanges = true;
220
221
if (&BB != &F.front())
222
BlocksToErase.push_back(&BB);
223
continue;
224
}
225
226
MadeChanges |= Solver.simplifyInstsInBlock(
227
BB, InsertedValues, NumInstRemoved, NumInstReplaced);
228
}
229
230
DominatorTree *DT = FAM->getCachedResult<DominatorTreeAnalysis>(F);
231
PostDominatorTree *PDT = FAM->getCachedResult<PostDominatorTreeAnalysis>(F);
232
DomTreeUpdater DTU(DT, PDT, DomTreeUpdater::UpdateStrategy::Lazy);
233
// Change dead blocks to unreachable. We do it after replacing constants
234
// in all executable blocks, because changeToUnreachable may remove PHI
235
// nodes in executable blocks we found values for. The function's entry
236
// block is not part of BlocksToErase, so we have to handle it separately.
237
for (BasicBlock *BB : BlocksToErase) {
238
NumInstRemoved += changeToUnreachable(BB->getFirstNonPHIOrDbg(),
239
/*PreserveLCSSA=*/false, &DTU);
240
}
241
if (!Solver.isBlockExecutable(&F.front()))
242
NumInstRemoved += changeToUnreachable(F.front().getFirstNonPHIOrDbg(),
243
/*PreserveLCSSA=*/false, &DTU);
244
245
BasicBlock *NewUnreachableBB = nullptr;
246
for (BasicBlock &BB : F)
247
MadeChanges |= Solver.removeNonFeasibleEdges(&BB, DTU, NewUnreachableBB);
248
249
for (BasicBlock *DeadBB : BlocksToErase)
250
if (!DeadBB->hasAddressTaken())
251
DTU.deleteBB(DeadBB);
252
253
for (BasicBlock &BB : F) {
254
for (Instruction &Inst : llvm::make_early_inc_range(BB)) {
255
if (Solver.getPredicateInfoFor(&Inst)) {
256
if (auto *II = dyn_cast<IntrinsicInst>(&Inst)) {
257
if (II->getIntrinsicID() == Intrinsic::ssa_copy) {
258
Value *Op = II->getOperand(0);
259
Inst.replaceAllUsesWith(Op);
260
Inst.eraseFromParent();
261
}
262
}
263
}
264
}
265
}
266
}
267
268
// If we inferred constant or undef return values for a function, we replaced
269
// all call uses with the inferred value. This means we don't need to bother
270
// actually returning anything from the function. Replace all return
271
// instructions with return undef.
272
//
273
// Do this in two stages: first identify the functions we should process, then
274
// actually zap their returns. This is important because we can only do this
275
// if the address of the function isn't taken. In cases where a return is the
276
// last use of a function, the order of processing functions would affect
277
// whether other functions are optimizable.
278
SmallVector<ReturnInst*, 8> ReturnsToZap;
279
280
for (const auto &I : Solver.getTrackedRetVals()) {
281
Function *F = I.first;
282
const ValueLatticeElement &ReturnValue = I.second;
283
284
// If there is a known constant range for the return value, add range
285
// attribute to the return value.
286
if (ReturnValue.isConstantRange() &&
287
!ReturnValue.getConstantRange().isSingleElement()) {
288
// Do not add range metadata if the return value may include undef.
289
if (ReturnValue.isConstantRangeIncludingUndef())
290
continue;
291
292
// Do not touch existing attribute for now.
293
// TODO: We should be able to take the intersection of the existing
294
// attribute and the inferred range.
295
if (F->hasRetAttribute(Attribute::Range))
296
continue;
297
auto &CR = ReturnValue.getConstantRange();
298
F->addRangeRetAttr(CR);
299
continue;
300
}
301
if (F->getReturnType()->isVoidTy())
302
continue;
303
if (SCCPSolver::isConstant(ReturnValue) || ReturnValue.isUnknownOrUndef())
304
findReturnsToZap(*F, ReturnsToZap, Solver);
305
}
306
307
for (auto *F : Solver.getMRVFunctionsTracked()) {
308
assert(F->getReturnType()->isStructTy() &&
309
"The return type should be a struct");
310
StructType *STy = cast<StructType>(F->getReturnType());
311
if (Solver.isStructLatticeConstant(F, STy))
312
findReturnsToZap(*F, ReturnsToZap, Solver);
313
}
314
315
// Zap all returns which we've identified as zap to change.
316
SmallSetVector<Function *, 8> FuncZappedReturn;
317
for (ReturnInst *RI : ReturnsToZap) {
318
Function *F = RI->getParent()->getParent();
319
RI->setOperand(0, PoisonValue::get(F->getReturnType()));
320
// Record all functions that are zapped.
321
FuncZappedReturn.insert(F);
322
}
323
324
// Remove the returned attribute for zapped functions and the
325
// corresponding call sites.
326
// Also remove any attributes that convert an undef return value into
327
// immediate undefined behavior
328
AttributeMask UBImplyingAttributes =
329
AttributeFuncs::getUBImplyingAttributes();
330
for (Function *F : FuncZappedReturn) {
331
for (Argument &A : F->args())
332
F->removeParamAttr(A.getArgNo(), Attribute::Returned);
333
F->removeRetAttrs(UBImplyingAttributes);
334
for (Use &U : F->uses()) {
335
CallBase *CB = dyn_cast<CallBase>(U.getUser());
336
if (!CB) {
337
assert(isa<BlockAddress>(U.getUser()) ||
338
(isa<Constant>(U.getUser()) &&
339
all_of(U.getUser()->users(), [](const User *UserUser) {
340
return cast<IntrinsicInst>(UserUser)->isAssumeLikeIntrinsic();
341
})));
342
continue;
343
}
344
345
for (Use &Arg : CB->args())
346
CB->removeParamAttr(CB->getArgOperandNo(&Arg), Attribute::Returned);
347
CB->removeRetAttrs(UBImplyingAttributes);
348
}
349
}
350
351
// If we inferred constant or undef values for globals variables, we can
352
// delete the global and any stores that remain to it.
353
for (const auto &I : make_early_inc_range(Solver.getTrackedGlobals())) {
354
GlobalVariable *GV = I.first;
355
if (SCCPSolver::isOverdefined(I.second))
356
continue;
357
LLVM_DEBUG(dbgs() << "Found that GV '" << GV->getName()
358
<< "' is constant!\n");
359
while (!GV->use_empty()) {
360
StoreInst *SI = cast<StoreInst>(GV->user_back());
361
SI->eraseFromParent();
362
}
363
364
// Try to create a debug constant expression for the global variable
365
// initializer value.
366
SmallVector<DIGlobalVariableExpression *, 1> GVEs;
367
GV->getDebugInfo(GVEs);
368
if (GVEs.size() == 1) {
369
DIBuilder DIB(M);
370
if (DIExpression *InitExpr = getExpressionForConstant(
371
DIB, *GV->getInitializer(), *GV->getValueType()))
372
GVEs[0]->replaceOperandWith(1, InitExpr);
373
}
374
375
MadeChanges = true;
376
M.eraseGlobalVariable(GV);
377
++NumGlobalConst;
378
}
379
380
return MadeChanges;
381
}
382
383
PreservedAnalyses IPSCCPPass::run(Module &M, ModuleAnalysisManager &AM) {
384
const DataLayout &DL = M.getDataLayout();
385
auto &FAM = AM.getResult<FunctionAnalysisManagerModuleProxy>(M).getManager();
386
auto GetTLI = [&FAM](Function &F) -> const TargetLibraryInfo & {
387
return FAM.getResult<TargetLibraryAnalysis>(F);
388
};
389
auto GetTTI = [&FAM](Function &F) -> TargetTransformInfo & {
390
return FAM.getResult<TargetIRAnalysis>(F);
391
};
392
auto GetAC = [&FAM](Function &F) -> AssumptionCache & {
393
return FAM.getResult<AssumptionAnalysis>(F);
394
};
395
auto GetDT = [&FAM](Function &F) -> DominatorTree & {
396
return FAM.getResult<DominatorTreeAnalysis>(F);
397
};
398
auto GetBFI = [&FAM](Function &F) -> BlockFrequencyInfo & {
399
return FAM.getResult<BlockFrequencyAnalysis>(F);
400
};
401
402
403
if (!runIPSCCP(M, DL, &FAM, GetTLI, GetTTI, GetAC, GetDT, GetBFI,
404
isFuncSpecEnabled()))
405
return PreservedAnalyses::all();
406
407
PreservedAnalyses PA;
408
PA.preserve<DominatorTreeAnalysis>();
409
PA.preserve<PostDominatorTreeAnalysis>();
410
PA.preserve<FunctionAnalysisManagerModuleProxy>();
411
return PA;
412
}
413
414