diff --git a/llvm/include/llvm/SandboxIR/BasicBlock.h b/llvm/include/llvm/SandboxIR/BasicBlock.h new file mode 100644 index 00000000000000..93e79e2a421f96 --- /dev/null +++ b/llvm/include/llvm/SandboxIR/BasicBlock.h @@ -0,0 +1,112 @@ +//===- BasicBlock.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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SANDBOXIR_BASICBLOCK_H +#define LLVM_SANDBOXIR_BASICBLOCK_H + +#include "llvm/IR/BasicBlock.h" +#include "llvm/SandboxIR/Value.h" + +namespace llvm::sandboxir { + +class BasicBlock; +class Function; +class Instruction; + +/// Iterator for `Instruction`s in a `BasicBlock. +/// \Returns an sandboxir::Instruction & when derereferenced. +class BBIterator { +public: + using difference_type = std::ptrdiff_t; + using value_type = Instruction; + using pointer = value_type *; + using reference = value_type &; + using iterator_category = std::bidirectional_iterator_tag; + +private: + llvm::BasicBlock *BB; + llvm::BasicBlock::iterator It; + Context *Ctx; + pointer getInstr(llvm::BasicBlock::iterator It) const; + +public: + BBIterator() : BB(nullptr), Ctx(nullptr) {} + BBIterator(llvm::BasicBlock *BB, llvm::BasicBlock::iterator It, Context *Ctx) + : BB(BB), It(It), Ctx(Ctx) {} + reference operator*() const { return *getInstr(It); } + BBIterator &operator++(); + BBIterator operator++(int) { + auto Copy = *this; + ++*this; + return Copy; + } + BBIterator &operator--(); + BBIterator operator--(int) { + auto Copy = *this; + --*this; + return Copy; + } + bool operator==(const BBIterator &Other) const { + assert(Ctx == Other.Ctx && "BBIterators in different context!"); + return It == Other.It; + } + bool operator!=(const BBIterator &Other) const { return !(*this == Other); } + /// \Returns the SBInstruction that corresponds to this iterator, or null if + /// the instruction is not found in the IR-to-SandboxIR tables. + pointer get() const { return getInstr(It); } + /// \Returns the parent BB. + BasicBlock *getNodeParent() const; +}; + +/// Contains a list of sandboxir::Instruction's. +class BasicBlock : public Value { + /// Builds a graph that contains all values in \p BB in their original form + /// i.e., no vectorization is taking place here. + void buildBasicBlockFromLLVMIR(llvm::BasicBlock *LLVMBB); + friend class Context; // For `buildBasicBlockFromIR` + friend class Instruction; // For LLVM Val. + + BasicBlock(llvm::BasicBlock *BB, Context &SBCtx) + : Value(ClassID::Block, BB, SBCtx) { + buildBasicBlockFromLLVMIR(BB); + } + +public: + ~BasicBlock() = default; + /// For isa/dyn_cast. + static bool classof(const Value *From) { + return From->getSubclassID() == Value::ClassID::Block; + } + Function *getParent() const; + using iterator = BBIterator; + iterator begin() const; + iterator end() const { + auto *BB = cast(Val); + return iterator(BB, BB->end(), &Ctx); + } + std::reverse_iterator rbegin() const { + return std::make_reverse_iterator(end()); + } + std::reverse_iterator rend() const { + return std::make_reverse_iterator(begin()); + } + Context &getContext() const { return Ctx; } + Instruction *getTerminator() const; + bool empty() const { return begin() == end(); } + Instruction &front() const; + Instruction &back() const; + +#ifndef NDEBUG + void verify() const final; + void dumpOS(raw_ostream &OS) const final; +#endif +}; + +} // namespace llvm::sandboxir + +#endif // LLVM_SANDBOXIR_BASICBLOCK_H diff --git a/llvm/include/llvm/SandboxIR/SandboxIR.h b/llvm/include/llvm/SandboxIR/SandboxIR.h index 02246c303ab614..2376450d190115 100644 --- a/llvm/include/llvm/SandboxIR/SandboxIR.h +++ b/llvm/include/llvm/SandboxIR/SandboxIR.h @@ -110,6 +110,7 @@ #include "llvm/IR/User.h" #include "llvm/IR/Value.h" #include "llvm/SandboxIR/Argument.h" +#include "llvm/SandboxIR/BasicBlock.h" #include "llvm/SandboxIR/Constant.h" #include "llvm/SandboxIR/Context.h" #include "llvm/SandboxIR/Module.h" @@ -191,95 +192,6 @@ class CmpInst; class ICmpInst; class FCmpInst; -/// Iterator for `Instruction`s in a `BasicBlock. -/// \Returns an sandboxir::Instruction & when derereferenced. -class BBIterator { -public: - using difference_type = std::ptrdiff_t; - using value_type = Instruction; - using pointer = value_type *; - using reference = value_type &; - using iterator_category = std::bidirectional_iterator_tag; - -private: - llvm::BasicBlock *BB; - llvm::BasicBlock::iterator It; - Context *Ctx; - pointer getInstr(llvm::BasicBlock::iterator It) const; - -public: - BBIterator() : BB(nullptr), Ctx(nullptr) {} - BBIterator(llvm::BasicBlock *BB, llvm::BasicBlock::iterator It, Context *Ctx) - : BB(BB), It(It), Ctx(Ctx) {} - reference operator*() const { return *getInstr(It); } - BBIterator &operator++(); - BBIterator operator++(int) { - auto Copy = *this; - ++*this; - return Copy; - } - BBIterator &operator--(); - BBIterator operator--(int) { - auto Copy = *this; - --*this; - return Copy; - } - bool operator==(const BBIterator &Other) const { - assert(Ctx == Other.Ctx && "BBIterators in different context!"); - return It == Other.It; - } - bool operator!=(const BBIterator &Other) const { return !(*this == Other); } - /// \Returns the SBInstruction that corresponds to this iterator, or null if - /// the instruction is not found in the IR-to-SandboxIR tables. - pointer get() const { return getInstr(It); } - /// \Returns the parent BB. - BasicBlock *getNodeParent() const; -}; - -/// Contains a list of sandboxir::Instruction's. -class BasicBlock : public Value { - /// Builds a graph that contains all values in \p BB in their original form - /// i.e., no vectorization is taking place here. - void buildBasicBlockFromLLVMIR(llvm::BasicBlock *LLVMBB); - friend class Context; // For `buildBasicBlockFromIR` - friend class Instruction; // For LLVM Val. - - BasicBlock(llvm::BasicBlock *BB, Context &SBCtx) - : Value(ClassID::Block, BB, SBCtx) { - buildBasicBlockFromLLVMIR(BB); - } - -public: - ~BasicBlock() = default; - /// For isa/dyn_cast. - static bool classof(const Value *From) { - return From->getSubclassID() == Value::ClassID::Block; - } - Function *getParent() const; - using iterator = BBIterator; - iterator begin() const; - iterator end() const { - auto *BB = cast(Val); - return iterator(BB, BB->end(), &Ctx); - } - std::reverse_iterator rbegin() const { - return std::make_reverse_iterator(end()); - } - std::reverse_iterator rend() const { - return std::make_reverse_iterator(begin()); - } - Context &getContext() const { return Ctx; } - Instruction *getTerminator() const; - bool empty() const { return begin() == end(); } - Instruction &front() const; - Instruction &back() const; - -#ifndef NDEBUG - void verify() const final; - void dumpOS(raw_ostream &OS) const final; -#endif -}; - /// A sandboxir::User with operands, opcode and linked with previous/next /// instructions in an instruction list. class Instruction : public sandboxir::User { diff --git a/llvm/lib/SandboxIR/BasicBlock.cpp b/llvm/lib/SandboxIR/BasicBlock.cpp new file mode 100644 index 00000000000000..7eba53ffb5ec4a --- /dev/null +++ b/llvm/lib/SandboxIR/BasicBlock.cpp @@ -0,0 +1,163 @@ +//===- BasicBlock.cpp - The BasicBlock class of Sandbox IR ----------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#include "llvm/SandboxIR/BasicBlock.h" +#include "llvm/SandboxIR/Context.h" +#include "llvm/SandboxIR/SandboxIR.h" // TODO: remove this + +namespace llvm::sandboxir { + +BBIterator &BBIterator::operator++() { + auto ItE = BB->end(); + assert(It != ItE && "Already at end!"); + ++It; + if (It == ItE) + return *this; + Instruction &NextI = *cast(Ctx->getValue(&*It)); + unsigned Num = NextI.getNumOfIRInstrs(); + assert(Num > 0 && "Bad getNumOfIRInstrs()"); + It = std::next(It, Num - 1); + return *this; +} + +BBIterator &BBIterator::operator--() { + assert(It != BB->begin() && "Already at begin!"); + if (It == BB->end()) { + --It; + return *this; + } + Instruction &CurrI = **this; + unsigned Num = CurrI.getNumOfIRInstrs(); + assert(Num > 0 && "Bad getNumOfIRInstrs()"); + assert(std::prev(It, Num - 1) != BB->begin() && "Already at begin!"); + It = std::prev(It, Num); + return *this; +} + +BasicBlock *BBIterator::getNodeParent() const { + llvm::BasicBlock *Parent = const_cast(this)->It.getNodeParent(); + return cast(Ctx->getValue(Parent)); +} + +BasicBlock::iterator::pointer +BasicBlock::iterator::getInstr(llvm::BasicBlock::iterator It) const { + return cast_or_null(Ctx->getValue(&*It)); +} + +Function *BasicBlock::getParent() const { + auto *BB = cast(Val); + auto *F = BB->getParent(); + if (F == nullptr) + // Detached + return nullptr; + return cast_or_null(Ctx.getValue(F)); +} + +void BasicBlock::buildBasicBlockFromLLVMIR(llvm::BasicBlock *LLVMBB) { + for (llvm::Instruction &IRef : reverse(*LLVMBB)) { + llvm::Instruction *I = &IRef; + Ctx.getOrCreateValue(I); + for (auto [OpIdx, Op] : enumerate(I->operands())) { + // Skip instruction's label operands + if (isa(Op)) + continue; + // Skip metadata + if (isa(Op)) + continue; + // Skip asm + if (isa(Op)) + continue; + Ctx.getOrCreateValue(Op); + } + } +#if !defined(NDEBUG) + verify(); +#endif +} + +BasicBlock::iterator BasicBlock::begin() const { + llvm::BasicBlock *BB = cast(Val); + llvm::BasicBlock::iterator It = BB->begin(); + if (!BB->empty()) { + auto *V = Ctx.getValue(&*BB->begin()); + assert(V != nullptr && "No SandboxIR for BB->begin()!"); + auto *I = cast(V); + unsigned Num = I->getNumOfIRInstrs(); + assert(Num >= 1u && "Bad getNumOfIRInstrs()"); + It = std::next(It, Num - 1); + } + return iterator(BB, It, &Ctx); +} + +Instruction *BasicBlock::getTerminator() const { + auto *TerminatorV = + Ctx.getValue(cast(Val)->getTerminator()); + return cast_or_null(TerminatorV); +} + +Instruction &BasicBlock::front() const { + auto *BB = cast(Val); + assert(!BB->empty() && "Empty block!"); + auto *SBI = cast(getContext().getValue(&*BB->begin())); + assert(SBI != nullptr && "Expected Instr!"); + return *SBI; +} + +Instruction &BasicBlock::back() const { + auto *BB = cast(Val); + assert(!BB->empty() && "Empty block!"); + auto *SBI = cast(getContext().getValue(&*BB->rbegin())); + assert(SBI != nullptr && "Expected Instr!"); + return *SBI; +} + +#ifndef NDEBUG +void BasicBlock::dumpOS(raw_ostream &OS) const { + llvm::BasicBlock *BB = cast(Val); + const auto &Name = BB->getName(); + OS << Name; + if (!Name.empty()) + OS << ":\n"; + // If there are Instructions in the BB that are not mapped to SandboxIR, then + // use a crash-proof dump. + if (any_of(*BB, [this](llvm::Instruction &I) { + return Ctx.getValue(&I) == nullptr; + })) { + OS << "\n"; + DenseSet Visited; + for (llvm::Instruction &IRef : *BB) { + Value *SBV = Ctx.getValue(&IRef); + if (SBV == nullptr) + OS << IRef << " *** No SandboxIR ***\n"; + else { + auto *SBI = dyn_cast(SBV); + if (SBI == nullptr) { + OS << IRef << " *** Not a SBInstruction!!! ***\n"; + } else { + if (Visited.insert(SBI).second) + OS << *SBI << "\n"; + } + } + } + } else { + for (auto &SBI : *this) { + SBI.dumpOS(OS); + OS << "\n"; + } + } +} + +void BasicBlock::verify() const { + assert(isa(Val) && "Expected BasicBlock!"); + for (const auto &I : *this) { + I.verify(); + } +} +#endif // NDEBUG + +} // namespace llvm::sandboxir diff --git a/llvm/lib/SandboxIR/CMakeLists.txt b/llvm/lib/SandboxIR/CMakeLists.txt index 50374de59761e2..deea86d442d395 100644 --- a/llvm/lib/SandboxIR/CMakeLists.txt +++ b/llvm/lib/SandboxIR/CMakeLists.txt @@ -1,5 +1,6 @@ add_llvm_component_library(LLVMSandboxIR Argument.cpp + BasicBlock.cpp Constant.cpp Context.cpp Module.cpp diff --git a/llvm/lib/SandboxIR/Constant.cpp b/llvm/lib/SandboxIR/Constant.cpp index 83b33f72f19d40..6f1eb1e74347d9 100644 --- a/llvm/lib/SandboxIR/Constant.cpp +++ b/llvm/lib/SandboxIR/Constant.cpp @@ -7,8 +7,9 @@ //===----------------------------------------------------------------------===// #include "llvm/SandboxIR/Constant.h" +#include "llvm/SandboxIR/Argument.h" +#include "llvm/SandboxIR/BasicBlock.h" #include "llvm/SandboxIR/Context.h" -#include "llvm/SandboxIR/SandboxIR.h" // TODO: Try to remove this namespace llvm::sandboxir { diff --git a/llvm/lib/SandboxIR/SandboxIR.cpp b/llvm/lib/SandboxIR/SandboxIR.cpp index 42df9df8119733..5baeffef32e5e5 100644 --- a/llvm/lib/SandboxIR/SandboxIR.cpp +++ b/llvm/lib/SandboxIR/SandboxIR.cpp @@ -11,6 +11,7 @@ #include "llvm/ADT/SmallVector.h" #include "llvm/IR/Constants.h" #include "llvm/SandboxIR/Argument.h" +#include "llvm/SandboxIR/BasicBlock.h" #include "llvm/Support/Debug.h" #include @@ -106,38 +107,6 @@ int OperandUseIterator::operator-(const OperandUseIterator &Other) const { return ThisOpNo - OtherOpNo; } -BBIterator &BBIterator::operator++() { - auto ItE = BB->end(); - assert(It != ItE && "Already at end!"); - ++It; - if (It == ItE) - return *this; - Instruction &NextI = *cast(Ctx->getValue(&*It)); - unsigned Num = NextI.getNumOfIRInstrs(); - assert(Num > 0 && "Bad getNumOfIRInstrs()"); - It = std::next(It, Num - 1); - return *this; -} - -BBIterator &BBIterator::operator--() { - assert(It != BB->begin() && "Already at begin!"); - if (It == BB->end()) { - --It; - return *this; - } - Instruction &CurrI = **this; - unsigned Num = CurrI.getNumOfIRInstrs(); - assert(Num > 0 && "Bad getNumOfIRInstrs()"); - assert(std::prev(It, Num - 1) != BB->begin() && "Already at begin!"); - It = std::prev(It, Num); - return *this; -} - -BasicBlock *BBIterator::getNodeParent() const { - llvm::BasicBlock *Parent = const_cast(this)->It.getNodeParent(); - return cast(Ctx->getValue(Parent)); -} - const char *Instruction::getOpcodeName(Opcode Opc) { switch (Opc) { #define OP(OPC) \ @@ -2089,120 +2058,3 @@ ConstantTokenNone *ConstantTokenNone::get(Context &Ctx) { auto *LLVMC = llvm::ConstantTokenNone::get(Ctx.LLVMCtx); return cast(Ctx.getOrCreateConstant(LLVMC)); } - -BasicBlock::iterator::pointer -BasicBlock::iterator::getInstr(llvm::BasicBlock::iterator It) const { - return cast_or_null(Ctx->getValue(&*It)); -} - -Function *BasicBlock::getParent() const { - auto *BB = cast(Val); - auto *F = BB->getParent(); - if (F == nullptr) - // Detached - return nullptr; - return cast_or_null(Ctx.getValue(F)); -} - -void BasicBlock::buildBasicBlockFromLLVMIR(llvm::BasicBlock *LLVMBB) { - for (llvm::Instruction &IRef : reverse(*LLVMBB)) { - llvm::Instruction *I = &IRef; - Ctx.getOrCreateValue(I); - for (auto [OpIdx, Op] : enumerate(I->operands())) { - // Skip instruction's label operands - if (isa(Op)) - continue; - // Skip metadata - if (isa(Op)) - continue; - // Skip asm - if (isa(Op)) - continue; - Ctx.getOrCreateValue(Op); - } - } -#if !defined(NDEBUG) - verify(); -#endif -} - -BasicBlock::iterator BasicBlock::begin() const { - llvm::BasicBlock *BB = cast(Val); - llvm::BasicBlock::iterator It = BB->begin(); - if (!BB->empty()) { - auto *V = Ctx.getValue(&*BB->begin()); - assert(V != nullptr && "No SandboxIR for BB->begin()!"); - auto *I = cast(V); - unsigned Num = I->getNumOfIRInstrs(); - assert(Num >= 1u && "Bad getNumOfIRInstrs()"); - It = std::next(It, Num - 1); - } - return iterator(BB, It, &Ctx); -} - -Instruction *BasicBlock::getTerminator() const { - auto *TerminatorV = - Ctx.getValue(cast(Val)->getTerminator()); - return cast_or_null(TerminatorV); -} - -Instruction &BasicBlock::front() const { - auto *BB = cast(Val); - assert(!BB->empty() && "Empty block!"); - auto *SBI = cast(getContext().getValue(&*BB->begin())); - assert(SBI != nullptr && "Expected Instr!"); - return *SBI; -} - -Instruction &BasicBlock::back() const { - auto *BB = cast(Val); - assert(!BB->empty() && "Empty block!"); - auto *SBI = cast(getContext().getValue(&*BB->rbegin())); - assert(SBI != nullptr && "Expected Instr!"); - return *SBI; -} - -#ifndef NDEBUG -void BasicBlock::dumpOS(raw_ostream &OS) const { - llvm::BasicBlock *BB = cast(Val); - const auto &Name = BB->getName(); - OS << Name; - if (!Name.empty()) - OS << ":\n"; - // If there are Instructions in the BB that are not mapped to SandboxIR, then - // use a crash-proof dump. - if (any_of(*BB, [this](llvm::Instruction &I) { - return Ctx.getValue(&I) == nullptr; - })) { - OS << "\n"; - DenseSet Visited; - for (llvm::Instruction &IRef : *BB) { - Value *SBV = Ctx.getValue(&IRef); - if (SBV == nullptr) - OS << IRef << " *** No SandboxIR ***\n"; - else { - auto *SBI = dyn_cast(SBV); - if (SBI == nullptr) { - OS << IRef << " *** Not a SBInstruction!!! ***\n"; - } else { - if (Visited.insert(SBI).second) - OS << *SBI << "\n"; - } - } - } - } else { - for (auto &SBI : *this) { - SBI.dumpOS(OS); - OS << "\n"; - } - } -} - -void BasicBlock::verify() const { - assert(isa(Val) && "Expected BasicBlock!"); - for (const auto &I : *this) { - I.verify(); - } -} - -#endif // NDEBUG