blob: 0e1591f42ad60fcfafd22c49f104d023e2e1dc7c [file] [log] [blame]
Max Kazantsev640cb002018-08-07 01:47:20 +00001//===-- ImplicitControlFlowTracking.cpp -------------------------*- C++ -*-===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9// This class allows to keep track on instructions with implicit control flow.
10// These are instructions that may not pass execution to their successors. For
11// example, throwing calls and guards do not always do this. If we need to know
12// for sure that some instruction is guaranteed to execute if the given block
13// is reached, then we need to make sure that there is no implicit control flow
14// instruction (ICFI) preceeding it. For example, this check is required if we
15// perform PRE moving non-speculable instruction to other place.
16//===----------------------------------------------------------------------===//
17
18#include "llvm/Analysis/ValueTracking.h"
19#include "llvm/Transforms/Utils/ImplicitControlFlowTracking.h"
20
21using namespace llvm;
22
23const Instruction *
24ImplicitControlFlowTracking::getFirstICFI(const BasicBlock *BB) {
25 if (!KnownBlocks.count(BB))
26 fill(BB);
Max Kazantsevdf58dd82018-08-15 05:50:38 +000027 auto *FirstICF = FirstImplicitControlFlowInsts.lookup(BB);
28 assert((!FirstICF || FirstICF->getParent() == BB) && "Inconsistent cache!");
29 return FirstICF;
Max Kazantsev640cb002018-08-07 01:47:20 +000030}
31
32bool ImplicitControlFlowTracking::hasICF(const BasicBlock *BB) {
33 return getFirstICFI(BB) != nullptr;
34}
35
36bool ImplicitControlFlowTracking::isDominatedByICFIFromSameBlock(
37 const Instruction *Insn) {
38 const Instruction *MaybeFirstICF = getFirstICFI(Insn->getParent());
39 return MaybeFirstICF && OI.dominates(MaybeFirstICF, Insn);
40}
41
42void ImplicitControlFlowTracking::fill(const BasicBlock *BB) {
43 auto MayNotTransferExecutionToSuccessor = [&](const Instruction *I) {
44 // If a block's instruction doesn't always pass the control to its successor
45 // instruction, mark the block as having implicit control flow. We use them
46 // to avoid wrong assumptions of sort "if A is executed and B post-dominates
47 // A, then B is also executed". This is not true is there is an implicit
48 // control flow instruction (e.g. a guard) between them.
49 //
50 // TODO: Currently, isGuaranteedToTransferExecutionToSuccessor returns false
51 // for volatile stores and loads because they can trap. The discussion on
52 // whether or not it is correct is still ongoing. We might want to get rid
53 // of this logic in the future. Anyways, trapping instructions shouldn't
54 // introduce implicit control flow, so we explicitly allow them here. This
55 // must be removed once isGuaranteedToTransferExecutionToSuccessor is fixed.
56 if (isGuaranteedToTransferExecutionToSuccessor(I))
57 return false;
58 if (isa<LoadInst>(I)) {
59 assert(cast<LoadInst>(I)->isVolatile() &&
60 "Non-volatile load should transfer execution to successor!");
61 return false;
62 }
63 if (isa<StoreInst>(I)) {
64 assert(cast<StoreInst>(I)->isVolatile() &&
65 "Non-volatile store should transfer execution to successor!");
66 return false;
67 }
68 return true;
69 };
70 FirstImplicitControlFlowInsts.erase(BB);
71
72 for (auto &I : *BB)
73 if (MayNotTransferExecutionToSuccessor(&I)) {
74 FirstImplicitControlFlowInsts[BB] = &I;
75 break;
76 }
77
78 // Mark this block as having a known result.
79 KnownBlocks.insert(BB);
80}
81
82void ImplicitControlFlowTracking::invalidateBlock(const BasicBlock *BB) {
83 OI.invalidateBlock(BB);
84 FirstImplicitControlFlowInsts.erase(BB);
85 KnownBlocks.erase(BB);
86}
87
88void ImplicitControlFlowTracking::clear() {
89 for (auto It : FirstImplicitControlFlowInsts)
90 OI.invalidateBlock(It.first);
91 FirstImplicitControlFlowInsts.clear();
92 KnownBlocks.clear();
93}