xref: /freebsd-src/contrib/llvm-project/llvm/lib/Transforms/Scalar/InferAlignment.cpp (revision 5f757f3ff9144b609b3c433dfd370cc6bdc191ad)
1*5f757f3fSDimitry Andric //===- InferAlignment.cpp -------------------------------------------------===//
2*5f757f3fSDimitry Andric //
3*5f757f3fSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*5f757f3fSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*5f757f3fSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*5f757f3fSDimitry Andric //
7*5f757f3fSDimitry Andric //===----------------------------------------------------------------------===//
8*5f757f3fSDimitry Andric //
9*5f757f3fSDimitry Andric // Infer alignment for load, stores and other memory operations based on
10*5f757f3fSDimitry Andric // trailing zero known bits information.
11*5f757f3fSDimitry Andric //
12*5f757f3fSDimitry Andric //===----------------------------------------------------------------------===//
13*5f757f3fSDimitry Andric 
14*5f757f3fSDimitry Andric #include "llvm/Transforms/Scalar/InferAlignment.h"
15*5f757f3fSDimitry Andric #include "llvm/Analysis/AssumptionCache.h"
16*5f757f3fSDimitry Andric #include "llvm/Analysis/ValueTracking.h"
17*5f757f3fSDimitry Andric #include "llvm/IR/Instructions.h"
18*5f757f3fSDimitry Andric #include "llvm/InitializePasses.h"
19*5f757f3fSDimitry Andric #include "llvm/Support/KnownBits.h"
20*5f757f3fSDimitry Andric #include "llvm/Transforms/Scalar.h"
21*5f757f3fSDimitry Andric #include "llvm/Transforms/Utils/Local.h"
22*5f757f3fSDimitry Andric 
23*5f757f3fSDimitry Andric using namespace llvm;
24*5f757f3fSDimitry Andric 
25*5f757f3fSDimitry Andric static bool tryToImproveAlign(
26*5f757f3fSDimitry Andric     const DataLayout &DL, Instruction *I,
27*5f757f3fSDimitry Andric     function_ref<Align(Value *PtrOp, Align OldAlign, Align PrefAlign)> Fn) {
28*5f757f3fSDimitry Andric   if (auto *LI = dyn_cast<LoadInst>(I)) {
29*5f757f3fSDimitry Andric     Value *PtrOp = LI->getPointerOperand();
30*5f757f3fSDimitry Andric     Align OldAlign = LI->getAlign();
31*5f757f3fSDimitry Andric     Align NewAlign = Fn(PtrOp, OldAlign, DL.getPrefTypeAlign(LI->getType()));
32*5f757f3fSDimitry Andric     if (NewAlign > OldAlign) {
33*5f757f3fSDimitry Andric       LI->setAlignment(NewAlign);
34*5f757f3fSDimitry Andric       return true;
35*5f757f3fSDimitry Andric     }
36*5f757f3fSDimitry Andric   } else if (auto *SI = dyn_cast<StoreInst>(I)) {
37*5f757f3fSDimitry Andric     Value *PtrOp = SI->getPointerOperand();
38*5f757f3fSDimitry Andric     Value *ValOp = SI->getValueOperand();
39*5f757f3fSDimitry Andric     Align OldAlign = SI->getAlign();
40*5f757f3fSDimitry Andric     Align NewAlign = Fn(PtrOp, OldAlign, DL.getPrefTypeAlign(ValOp->getType()));
41*5f757f3fSDimitry Andric     if (NewAlign > OldAlign) {
42*5f757f3fSDimitry Andric       SI->setAlignment(NewAlign);
43*5f757f3fSDimitry Andric       return true;
44*5f757f3fSDimitry Andric     }
45*5f757f3fSDimitry Andric   }
46*5f757f3fSDimitry Andric   // TODO: Also handle memory intrinsics.
47*5f757f3fSDimitry Andric   return false;
48*5f757f3fSDimitry Andric }
49*5f757f3fSDimitry Andric 
50*5f757f3fSDimitry Andric bool inferAlignment(Function &F, AssumptionCache &AC, DominatorTree &DT) {
51*5f757f3fSDimitry Andric   const DataLayout &DL = F.getParent()->getDataLayout();
52*5f757f3fSDimitry Andric   bool Changed = false;
53*5f757f3fSDimitry Andric 
54*5f757f3fSDimitry Andric   // Enforce preferred type alignment if possible. We do this as a separate
55*5f757f3fSDimitry Andric   // pass first, because it may improve the alignments we infer below.
56*5f757f3fSDimitry Andric   for (BasicBlock &BB : F) {
57*5f757f3fSDimitry Andric     for (Instruction &I : BB) {
58*5f757f3fSDimitry Andric       Changed |= tryToImproveAlign(
59*5f757f3fSDimitry Andric           DL, &I, [&](Value *PtrOp, Align OldAlign, Align PrefAlign) {
60*5f757f3fSDimitry Andric             if (PrefAlign > OldAlign)
61*5f757f3fSDimitry Andric               return std::max(OldAlign,
62*5f757f3fSDimitry Andric                               tryEnforceAlignment(PtrOp, PrefAlign, DL));
63*5f757f3fSDimitry Andric             return OldAlign;
64*5f757f3fSDimitry Andric           });
65*5f757f3fSDimitry Andric     }
66*5f757f3fSDimitry Andric   }
67*5f757f3fSDimitry Andric 
68*5f757f3fSDimitry Andric   // Compute alignment from known bits.
69*5f757f3fSDimitry Andric   for (BasicBlock &BB : F) {
70*5f757f3fSDimitry Andric     for (Instruction &I : BB) {
71*5f757f3fSDimitry Andric       Changed |= tryToImproveAlign(
72*5f757f3fSDimitry Andric           DL, &I, [&](Value *PtrOp, Align OldAlign, Align PrefAlign) {
73*5f757f3fSDimitry Andric             KnownBits Known = computeKnownBits(PtrOp, DL, 0, &AC, &I, &DT);
74*5f757f3fSDimitry Andric             unsigned TrailZ = std::min(Known.countMinTrailingZeros(),
75*5f757f3fSDimitry Andric                                        +Value::MaxAlignmentExponent);
76*5f757f3fSDimitry Andric             return Align(1ull << std::min(Known.getBitWidth() - 1, TrailZ));
77*5f757f3fSDimitry Andric           });
78*5f757f3fSDimitry Andric     }
79*5f757f3fSDimitry Andric   }
80*5f757f3fSDimitry Andric 
81*5f757f3fSDimitry Andric   return Changed;
82*5f757f3fSDimitry Andric }
83*5f757f3fSDimitry Andric 
84*5f757f3fSDimitry Andric PreservedAnalyses InferAlignmentPass::run(Function &F,
85*5f757f3fSDimitry Andric                                           FunctionAnalysisManager &AM) {
86*5f757f3fSDimitry Andric   AssumptionCache &AC = AM.getResult<AssumptionAnalysis>(F);
87*5f757f3fSDimitry Andric   DominatorTree &DT = AM.getResult<DominatorTreeAnalysis>(F);
88*5f757f3fSDimitry Andric   inferAlignment(F, AC, DT);
89*5f757f3fSDimitry Andric   // Changes to alignment shouldn't invalidated analyses.
90*5f757f3fSDimitry Andric   return PreservedAnalyses::all();
91*5f757f3fSDimitry Andric }
92