[llvm] r340728 - [NFC] Split logic of ImplicitControlFlowTracking to allow generalization

Max Kazantsev via llvm-commits llvm-commits at lists.llvm.org
Mon Aug 27 02:43:16 PDT 2018


Author: mkazantsev
Date: Mon Aug 27 02:43:16 2018
New Revision: 340728

URL: http://llvm.org/viewvc/llvm-project?rev=340728&view=rev
Log:
[NFC] Split logic of ImplicitControlFlowTracking to allow generalization

We have a class `ImplicitControlFlowTracking` which allows us to keep track of
instructions that can abnormally exit and answer queries like "whether or not
there is side-exiting instruction above this instruction in its block".

We may want to have the similar tracking for other types of "special" instructions,
for example instructions that write memory.

This patch separates ImplicitControlFlowTracking into two classes, isolating all
general logic not related to implicit control flow into its parent class. We can
later make another child of this class to keep track of instructions that write
memory.

The motivation for that is that we want to make these checks efficiently in the
patch https://reviews.llvm.org/D50891.

NOTE: The naming of the parent class is not super cool, but the other options we
have are hardly better. Please feel free to rename it as NFC if you think you've
found a more informative name for it.

Differential Revision: https://reviews.llvm.org/D50954
Reviewed By: fedor.sergeev

Added:
    llvm/trunk/include/llvm/Transforms/Utils/InstructionPrecedenceTracking.h
    llvm/trunk/lib/Transforms/Utils/InstructionPrecedenceTracking.cpp
Removed:
    llvm/trunk/include/llvm/Transforms/Utils/ImplicitControlFlowTracking.h
    llvm/trunk/lib/Transforms/Utils/ImplicitControlFlowTracking.cpp
Modified:
    llvm/trunk/include/llvm/Transforms/Scalar/GVN.h
    llvm/trunk/lib/Transforms/Utils/CMakeLists.txt

Modified: llvm/trunk/include/llvm/Transforms/Scalar/GVN.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Transforms/Scalar/GVN.h?rev=340728&r1=340727&r2=340728&view=diff
==============================================================================
--- llvm/trunk/include/llvm/Transforms/Scalar/GVN.h (original)
+++ llvm/trunk/include/llvm/Transforms/Scalar/GVN.h Mon Aug 27 02:43:16 2018
@@ -28,7 +28,7 @@
 #include "llvm/IR/PassManager.h"
 #include "llvm/Support/Allocator.h"
 #include "llvm/Support/Compiler.h"
-#include "llvm/Transforms/Utils/ImplicitControlFlowTracking.h"
+#include "llvm/Transforms/Utils/InstructionPrecedenceTracking.h"
 #include <cstdint>
 #include <utility>
 #include <vector>

Removed: llvm/trunk/include/llvm/Transforms/Utils/ImplicitControlFlowTracking.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Transforms/Utils/ImplicitControlFlowTracking.h?rev=340727&view=auto
==============================================================================
--- llvm/trunk/include/llvm/Transforms/Utils/ImplicitControlFlowTracking.h (original)
+++ llvm/trunk/include/llvm/Transforms/Utils/ImplicitControlFlowTracking.h (removed)
@@ -1,62 +0,0 @@
-//===-- ImplicitControlFlowTracking.h ---------------------------*- C++ -*-===//
-//
-//                     The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-// This class allows to keep track on instructions with implicit control flow.
-// These are instructions that may not pass execution to their successors. For
-// example, throwing calls and guards do not always do this. If we need to know
-// for sure that some instruction is guaranteed to execute if the given block
-// is reached, then we need to make sure that there is no implicit control flow
-// instruction (ICFI) preceeding it. For example, this check is required if we
-// perform PRE moving non-speculable instruction to other place.
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_TRANSFORMS_UTILS_IMPLICITCONTROLFLOWTRACKING_H
-#define LLVM_TRANSFORMS_UTILS_IMPLICITCONTROLFLOWTRACKING_H
-
-#include "llvm/IR/Dominators.h"
-#include "llvm/Transforms/Utils/OrderedInstructions.h"
-
-namespace llvm {
-
-class ImplicitControlFlowTracking {
-public:
-  ImplicitControlFlowTracking(DominatorTree *DT)
-      : OI(OrderedInstructions(DT)) {}
-
-  // Returns the topmost instruction with implicit control flow from the given
-  // basic block. Returns nullptr if there is no such instructions in the block.
-  const Instruction *getFirstICFI(const BasicBlock *BB);
-
-  // Returns true if at least one instruction from the given basic block has
-  // implicit control flow.
-  bool hasICF(const BasicBlock *BB);
-
-  // Returns true if the first ICFI of Insn's block exists and dominates Insn.
-  bool isDominatedByICFIFromSameBlock(const Instruction *Insn);
-
-  // Clears information about this particular block.
-  void invalidateBlock(const BasicBlock *BB);
-
-  // Invalidates all information from this tracking.
-  void clear();
-
-private:
-  // Fills information about the given block's implicit control flow.
-  void fill(const BasicBlock *BB);
-
-  // Maps a block to the topmost instruction with implicit control flow in it.
-  DenseMap<const BasicBlock *, const Instruction *>
-      FirstImplicitControlFlowInsts;
-  OrderedInstructions OI;
-  // Blocks for which we have the actual information.
-  SmallPtrSet<const BasicBlock *, 8> KnownBlocks;
-};
-
-} // llvm
-
-#endif // LLVM_TRANSFORMS_UTILS_IMPLICITCONTROLFLOWTRACKING_H

Added: llvm/trunk/include/llvm/Transforms/Utils/InstructionPrecedenceTracking.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Transforms/Utils/InstructionPrecedenceTracking.h?rev=340728&view=auto
==============================================================================
--- llvm/trunk/include/llvm/Transforms/Utils/InstructionPrecedenceTracking.h (added)
+++ llvm/trunk/include/llvm/Transforms/Utils/InstructionPrecedenceTracking.h Mon Aug 27 02:43:16 2018
@@ -0,0 +1,106 @@
+//===-- InstructionPrecedenceTracking.h -------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+// Implements a class that is able to define some instructions as "special"
+// (e.g. as having implicit control flow, or writing memory, or having another
+// interesting property) and then efficiently answers queries of the types:
+// 1. Are there any special instructions in the block of interest?
+// 2. Return first of the special instructions in the given block;
+// 3. Check if the given instruction is preceeded by the first special
+//    instruction in the same block.
+// The class provides caching that allows to answer these queries quickly. The
+// user must make sure that the cached data is invalidated properly whenever
+// a content of some tracked block is changed.
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_TRANSFORMS_UTILS_INSTRUCTIONPRECEDENCETRACKING_H
+#define LLVM_TRANSFORMS_UTILS_INSTRUCTIONPRECEDENCETRACKING_H
+
+#include "llvm/IR/Dominators.h"
+#include "llvm/Transforms/Utils/OrderedInstructions.h"
+
+namespace llvm {
+
+class InstructionPrecedenceTracking {
+  // Maps a block to the topmost special instruction in it.
+  DenseMap<const BasicBlock *, const Instruction *>
+      FirstImplicitControlFlowInsts;
+  // Allows to answer queries about precedence of instructions within one block.
+  OrderedInstructions OI;
+  // Blocks for which we have the up-to-date cached information.
+  SmallPtrSet<const BasicBlock *, 8> KnownBlocks;
+
+  // Fills information about the given block's special instructions.
+  void fill(const BasicBlock *BB);
+
+protected:
+  InstructionPrecedenceTracking(DominatorTree *DT)
+      : OI(OrderedInstructions(DT)) {}
+
+  /// Returns the topmost special instruction from the block \p BB. Returns
+  /// nullptr if there is no special instructions in the block.
+  const Instruction *getFirstSpecialInstruction(const BasicBlock *BB);
+
+  /// Returns true iff at least one instruction from the basic block \p BB is
+  /// special.
+  bool hasSpecialInstructions(const BasicBlock *BB);
+
+  /// Returns true iff the first special instruction of \p Insn's block exists
+  /// and dominates \p Insn.
+  bool isPreceededBySpecialInstruction(const Instruction *Insn);
+
+  /// A predicate that defines whether or not the instruction \p Insn is
+  /// considered special and needs to be tracked. Implementing this method in
+  /// children classes allows to implement tracking of implicit control flow,
+  /// memory writing instructions or any other kinds of instructions we might
+  /// be interested in.
+  virtual bool isSpecialInstruction(const Instruction *Insn) const = 0;
+
+public:
+  /// Clears cached information about this particular block.
+  void invalidateBlock(const BasicBlock *BB);
+
+  /// Invalidates all information from this tracking.
+  void clear();
+};
+
+/// This class allows to keep track on instructions with implicit control flow.
+/// These are instructions that may not pass execution to their successors. For
+/// example, throwing calls and guards do not always do this. If we need to know
+/// for sure that some instruction is guaranteed to execute if the given block
+/// is reached, then we need to make sure that there is no implicit control flow
+/// instruction (ICFI) preceeding it. For example, this check is required if we
+/// perform PRE moving non-speculable instruction to other place.
+class ImplicitControlFlowTracking : public InstructionPrecedenceTracking {
+public:
+  ImplicitControlFlowTracking(DominatorTree *DT)
+      : InstructionPrecedenceTracking(DT) {}
+
+  /// Returns the topmost instruction with implicit control flow from the given
+  /// basic block. Returns nullptr if there is no such instructions in the block.
+  const Instruction *getFirstICFI(const BasicBlock *BB) {
+    return getFirstSpecialInstruction(BB);
+  }
+
+  /// Returns true if at least one instruction from the given basic block has
+  /// implicit control flow.
+  bool hasICF(const BasicBlock *BB) {
+    return hasSpecialInstructions(BB);
+  }
+
+  /// Returns true if the first ICFI of Insn's block exists and dominates Insn.
+  bool isDominatedByICFIFromSameBlock(const Instruction *Insn) {
+    return isPreceededBySpecialInstruction(Insn);
+  }
+
+  virtual bool isSpecialInstruction(const Instruction *Insn) const;
+};
+
+} // llvm
+
+#endif // LLVM_TRANSFORMS_UTILS_INSTRUCTIONPRECEDENCETRACKING_H

Modified: llvm/trunk/lib/Transforms/Utils/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/Utils/CMakeLists.txt?rev=340728&r1=340727&r2=340728&view=diff
==============================================================================
--- llvm/trunk/lib/Transforms/Utils/CMakeLists.txt (original)
+++ llvm/trunk/lib/Transforms/Utils/CMakeLists.txt Mon Aug 27 02:43:16 2018
@@ -18,10 +18,10 @@ add_llvm_library(LLVMTransformUtils
   FunctionComparator.cpp
   FunctionImportUtils.cpp
   GlobalStatus.cpp
-  ImplicitControlFlowTracking.cpp
   InlineFunction.cpp
   ImportedFunctionsInliningStatistics.cpp
   InstructionNamer.cpp
+  InstructionPrecedenceTracking.cpp
   IntegerDivision.cpp
   LCSSA.cpp
   LibCallsShrinkWrap.cpp

Removed: llvm/trunk/lib/Transforms/Utils/ImplicitControlFlowTracking.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/Utils/ImplicitControlFlowTracking.cpp?rev=340727&view=auto
==============================================================================
--- llvm/trunk/lib/Transforms/Utils/ImplicitControlFlowTracking.cpp (original)
+++ llvm/trunk/lib/Transforms/Utils/ImplicitControlFlowTracking.cpp (removed)
@@ -1,93 +0,0 @@
-//===-- ImplicitControlFlowTracking.cpp -------------------------*- C++ -*-===//
-//
-//                     The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-// This class allows to keep track on instructions with implicit control flow.
-// These are instructions that may not pass execution to their successors. For
-// example, throwing calls and guards do not always do this. If we need to know
-// for sure that some instruction is guaranteed to execute if the given block
-// is reached, then we need to make sure that there is no implicit control flow
-// instruction (ICFI) preceeding it. For example, this check is required if we
-// perform PRE moving non-speculable instruction to other place.
-//===----------------------------------------------------------------------===//
-
-#include "llvm/Analysis/ValueTracking.h"
-#include "llvm/Transforms/Utils/ImplicitControlFlowTracking.h"
-
-using namespace llvm;
-
-const Instruction *
-ImplicitControlFlowTracking::getFirstICFI(const BasicBlock *BB) {
-  if (!KnownBlocks.count(BB))
-    fill(BB);
-  auto *FirstICF = FirstImplicitControlFlowInsts.lookup(BB);
-  assert((!FirstICF || FirstICF->getParent() == BB) && "Inconsistent cache!");
-  return FirstICF;
-}
-
-bool ImplicitControlFlowTracking::hasICF(const BasicBlock *BB) {
-  return getFirstICFI(BB) != nullptr;
-}
-
-bool ImplicitControlFlowTracking::isDominatedByICFIFromSameBlock(
-    const Instruction *Insn) {
-  const Instruction *MaybeFirstICF = getFirstICFI(Insn->getParent());
-  return MaybeFirstICF && OI.dominates(MaybeFirstICF, Insn);
-}
-
-void ImplicitControlFlowTracking::fill(const BasicBlock *BB) {
-  auto MayNotTransferExecutionToSuccessor = [&](const Instruction *I) {
-    // If a block's instruction doesn't always pass the control to its successor
-    // instruction, mark the block as having implicit control flow. We use them
-    // to avoid wrong assumptions of sort "if A is executed and B post-dominates
-    // A, then B is also executed". This is not true is there is an implicit
-    // control flow instruction (e.g. a guard) between them.
-    //
-    // TODO: Currently, isGuaranteedToTransferExecutionToSuccessor returns false
-    // for volatile stores and loads because they can trap. The discussion on
-    // whether or not it is correct is still ongoing. We might want to get rid
-    // of this logic in the future. Anyways, trapping instructions shouldn't
-    // introduce implicit control flow, so we explicitly allow them here. This
-    // must be removed once isGuaranteedToTransferExecutionToSuccessor is fixed.
-    if (isGuaranteedToTransferExecutionToSuccessor(I))
-      return false;
-    if (isa<LoadInst>(I)) {
-      assert(cast<LoadInst>(I)->isVolatile() &&
-             "Non-volatile load should transfer execution to successor!");
-      return false;
-    }
-    if (isa<StoreInst>(I)) {
-      assert(cast<StoreInst>(I)->isVolatile() &&
-             "Non-volatile store should transfer execution to successor!");
-      return false;
-    }
-    return true;
-  };
-  FirstImplicitControlFlowInsts.erase(BB);
-
-  for (auto &I : *BB)
-    if (MayNotTransferExecutionToSuccessor(&I)) {
-      FirstImplicitControlFlowInsts[BB] = &I;
-      break;
-    }
-
-  // Mark this block as having a known result.
-  KnownBlocks.insert(BB);
-}
-
-void ImplicitControlFlowTracking::invalidateBlock(const BasicBlock *BB) {
-  OI.invalidateBlock(BB);
-  FirstImplicitControlFlowInsts.erase(BB);
-  KnownBlocks.erase(BB);
-}
-
-void ImplicitControlFlowTracking::clear() {
-  for (auto It : FirstImplicitControlFlowInsts)
-    OI.invalidateBlock(It.first);
-  FirstImplicitControlFlowInsts.clear();
-  KnownBlocks.clear();
-}

Added: llvm/trunk/lib/Transforms/Utils/InstructionPrecedenceTracking.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/Utils/InstructionPrecedenceTracking.cpp?rev=340728&view=auto
==============================================================================
--- llvm/trunk/lib/Transforms/Utils/InstructionPrecedenceTracking.cpp (added)
+++ llvm/trunk/lib/Transforms/Utils/InstructionPrecedenceTracking.cpp Mon Aug 27 02:43:16 2018
@@ -0,0 +1,99 @@
+//===-- InstructionPrecedenceTracking.cpp -----------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+// Implements a class that is able to define some instructions as "special"
+// (e.g. as having implicit control flow, or writing memory, or having another
+// interesting property) and then efficiently answers queries of the types:
+// 1. Are there any special instructions in the block of interest?
+// 2. Return first of the special instructions in the given block;
+// 3. Check if the given instruction is preceeded by the first special
+//    instruction in the same block.
+// The class provides caching that allows to answer these queries quickly. The
+// user must make sure that the cached data is invalidated properly whenever
+// a content of some tracked block is changed.
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Analysis/ValueTracking.h"
+#include "llvm/Transforms/Utils/InstructionPrecedenceTracking.h"
+
+using namespace llvm;
+
+const Instruction *InstructionPrecedenceTracking::getFirstSpecialInstruction(
+    const BasicBlock *BB) {
+  if (!KnownBlocks.count(BB))
+    fill(BB);
+  auto *FirstICF = FirstImplicitControlFlowInsts.lookup(BB);
+  assert((!FirstICF || FirstICF->getParent() == BB) && "Inconsistent cache!");
+  return FirstICF;
+}
+
+bool InstructionPrecedenceTracking::hasSpecialInstructions(
+    const BasicBlock *BB) {
+  return getFirstSpecialInstruction(BB) != nullptr;
+}
+
+bool InstructionPrecedenceTracking::isPreceededBySpecialInstruction(
+    const Instruction *Insn) {
+  const Instruction *MaybeFirstICF =
+      getFirstSpecialInstruction(Insn->getParent());
+  return MaybeFirstICF && OI.dominates(MaybeFirstICF, Insn);
+}
+
+void InstructionPrecedenceTracking::fill(const BasicBlock *BB) {
+  FirstImplicitControlFlowInsts.erase(BB);
+  for (auto &I : *BB)
+    if (isSpecialInstruction(&I)) {
+      FirstImplicitControlFlowInsts[BB] = &I;
+      break;
+    }
+
+  // Mark this block as having a known result.
+  KnownBlocks.insert(BB);
+}
+
+void InstructionPrecedenceTracking::invalidateBlock(const BasicBlock *BB) {
+  OI.invalidateBlock(BB);
+  FirstImplicitControlFlowInsts.erase(BB);
+  KnownBlocks.erase(BB);
+}
+
+void InstructionPrecedenceTracking::clear() {
+  for (auto It : FirstImplicitControlFlowInsts)
+    OI.invalidateBlock(It.first);
+  FirstImplicitControlFlowInsts.clear();
+  KnownBlocks.clear();
+}
+
+bool ImplicitControlFlowTracking::isSpecialInstruction(
+    const Instruction *Insn) const {
+  // If a block's instruction doesn't always pass the control to its successor
+  // instruction, mark the block as having implicit control flow. We use them
+  // to avoid wrong assumptions of sort "if A is executed and B post-dominates
+  // A, then B is also executed". This is not true is there is an implicit
+  // control flow instruction (e.g. a guard) between them.
+  //
+  // TODO: Currently, isGuaranteedToTransferExecutionToSuccessor returns false
+  // for volatile stores and loads because they can trap. The discussion on
+  // whether or not it is correct is still ongoing. We might want to get rid
+  // of this logic in the future. Anyways, trapping instructions shouldn't
+  // introduce implicit control flow, so we explicitly allow them here. This
+  // must be removed once isGuaranteedToTransferExecutionToSuccessor is fixed.
+  if (isGuaranteedToTransferExecutionToSuccessor(Insn))
+    return false;
+  if (isa<LoadInst>(Insn)) {
+    assert(cast<LoadInst>(Insn)->isVolatile() &&
+           "Non-volatile load should transfer execution to successor!");
+    return false;
+  }
+  if (isa<StoreInst>(Insn)) {
+    assert(cast<StoreInst>(Insn)->isVolatile() &&
+           "Non-volatile store should transfer execution to successor!");
+    return false;
+  }
+  return true;
+}




More information about the llvm-commits mailing list