| //===- Tracker.h ------------------------------------------------*- C++ -*-===// |
| // |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| // See https://llvm.org/LICENSE.txt for license information. |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| // |
| //===----------------------------------------------------------------------===// |
| // |
| // This file is the component of SandboxIR that tracks all changes made to its |
| // state, such that we can revert the state when needed. |
| // |
| // Tracking changes |
| // ---------------- |
| // The user needs to call `Tracker::save()` to enable tracking changes |
| // made to SandboxIR. From that point on, any change made to SandboxIR, will |
| // automatically create a change tracking object and register it with the |
| // tracker. IR-change objects are subclasses of `IRChangeBase` and get |
| // registered with the `Tracker::track()` function. The change objects |
| // are saved in the order they are registered with the tracker and are stored in |
| // the `Tracker::Changes` vector. All of this is done transparently to |
| // the user. |
| // |
| // Reverting changes |
| // ----------------- |
| // Calling `Tracker::revert()` will restore the state saved when |
| // `Tracker::save()` was called. Internally this goes through the |
| // change objects in `Tracker::Changes` in reverse order, calling their |
| // `IRChangeBase::revert()` function one by one. |
| // |
| // Accepting changes |
| // ----------------- |
| // The user needs to either revert or accept changes before the tracker object |
| // is destroyed. This is enforced in the tracker's destructor. |
| // This is the job of `Tracker::accept()`. Internally this will go |
| // through the change objects in `Tracker::Changes` in order, calling |
| // `IRChangeBase::accept()`. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #ifndef LLVM_SANDBOXIR_TRACKER_H |
| #define LLVM_SANDBOXIR_TRACKER_H |
| |
| #include "llvm/ADT/SmallVector.h" |
| #include "llvm/IR/IRBuilder.h" |
| #include "llvm/IR/Instruction.h" |
| #include "llvm/IR/Module.h" |
| #include "llvm/SandboxIR/Use.h" |
| #include "llvm/Support/Debug.h" |
| #include <memory> |
| #include <regex> |
| |
| namespace llvm::sandboxir { |
| |
| class BasicBlock; |
| class Tracker; |
| |
| /// The base class for IR Change classes. |
| class IRChangeBase { |
| protected: |
| Tracker &Parent; |
| |
| public: |
| IRChangeBase(Tracker &Parent); |
| /// This runs when changes get reverted. |
| virtual void revert() = 0; |
| /// This runs when changes get accepted. |
| virtual void accept() = 0; |
| virtual ~IRChangeBase() = default; |
| #ifndef NDEBUG |
| /// \Returns the index of this change by iterating over all changes in the |
| /// tracker. This is only used for debugging. |
| unsigned getIdx() const; |
| void dumpCommon(raw_ostream &OS) const { OS << getIdx() << ". "; } |
| virtual void dump(raw_ostream &OS) const = 0; |
| LLVM_DUMP_METHOD virtual void dump() const = 0; |
| friend raw_ostream &operator<<(raw_ostream &OS, const IRChangeBase &C) { |
| C.dump(OS); |
| return OS; |
| } |
| #endif |
| }; |
| |
| /// Tracks the change of the source Value of a sandboxir::Use. |
| class UseSet : public IRChangeBase { |
| Use U; |
| Value *OrigV = nullptr; |
| |
| public: |
| UseSet(const Use &U, Tracker &Tracker) |
| : IRChangeBase(Tracker), U(U), OrigV(U.get()) {} |
| void revert() final { U.set(OrigV); } |
| void accept() final {} |
| #ifndef NDEBUG |
| void dump(raw_ostream &OS) const final { |
| dumpCommon(OS); |
| OS << "UseSet"; |
| } |
| LLVM_DUMP_METHOD void dump() const final; |
| #endif |
| }; |
| |
| /// The tracker collects all the change objects and implements the main API for |
| /// saving / reverting / accepting. |
| class Tracker { |
| public: |
| enum class TrackerState { |
| Disabled, ///> Tracking is disabled |
| Record, ///> Tracking changes |
| }; |
| |
| private: |
| /// The list of changes that are being tracked. |
| SmallVector<std::unique_ptr<IRChangeBase>> Changes; |
| #ifndef NDEBUG |
| friend unsigned IRChangeBase::getIdx() const; // For accessing `Changes`. |
| #endif |
| /// The current state of the tracker. |
| TrackerState State = TrackerState::Disabled; |
| |
| public: |
| #ifndef NDEBUG |
| /// Helps catch bugs where we are creating new change objects while in the |
| /// middle of creating other change objects. |
| bool InMiddleOfCreatingChange = false; |
| #endif // NDEBUG |
| |
| Tracker() = default; |
| ~Tracker(); |
| /// Record \p Change and take ownership. This is the main function used to |
| /// track Sandbox IR changes. |
| void track(std::unique_ptr<IRChangeBase> &&Change); |
| /// \Returns true if the tracker is recording changes. |
| bool isTracking() const { return State == TrackerState::Record; } |
| /// \Returns the current state of the tracker. |
| TrackerState getState() const { return State; } |
| /// Turns on IR tracking. |
| void save(); |
| /// Stops tracking and accept changes. |
| void accept(); |
| /// Stops tracking and reverts to saved state. |
| void revert(); |
| |
| #ifndef NDEBUG |
| void dump(raw_ostream &OS) const; |
| LLVM_DUMP_METHOD void dump() const; |
| friend raw_ostream &operator<<(raw_ostream &OS, const Tracker &Tracker) { |
| Tracker.dump(OS); |
| return OS; |
| } |
| #endif // NDEBUG |
| }; |
| |
| } // namespace llvm::sandboxir |
| |
| #endif // LLVM_SANDBOXIR_TRACKER_H |