1//===- BasicBlock.cpp - The BasicBlock class of Sandbox IR ----------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "llvm/SandboxIR/BasicBlock.h"
10#include "llvm/SandboxIR/Context.h"
11#include "llvm/SandboxIR/Function.h"
12#include "llvm/SandboxIR/Instruction.h"
13
14namespace llvm::sandboxir {
15
16BBIterator &BBIterator::operator++() {
17 auto ItE = BB->end();
18 assert(It != ItE && "Already at end!");
19 ++It;
20 if (It == ItE)
21 return *this;
22 Instruction &NextI = *cast<sandboxir::Instruction>(Val: Ctx->getValue(V: &*It));
23 unsigned Num = NextI.getNumOfIRInstrs();
24 assert(Num > 0 && "Bad getNumOfIRInstrs()");
25 It = std::next(x: It, n: Num - 1);
26 return *this;
27}
28
29BBIterator &BBIterator::operator--() {
30 assert(It != BB->begin() && "Already at begin!");
31 if (It == BB->end()) {
32 --It;
33 return *this;
34 }
35 Instruction &CurrI = **this;
36 unsigned Num = CurrI.getNumOfIRInstrs();
37 assert(Num > 0 && "Bad getNumOfIRInstrs()");
38 assert(std::prev(It, Num - 1) != BB->begin() && "Already at begin!");
39 It = std::prev(x: It, n: Num);
40 return *this;
41}
42
43BasicBlock *BBIterator::getNodeParent() const {
44 llvm::BasicBlock *Parent = const_cast<BBIterator *>(this)->It.getNodeParent();
45 return cast<BasicBlock>(Val: Ctx->getValue(V: Parent));
46}
47
48BasicBlock::iterator::pointer
49BasicBlock::iterator::getInstr(llvm::BasicBlock::iterator It) const {
50 return cast_or_null<Instruction>(Val: Ctx->getValue(V: &*It));
51}
52
53Function *BasicBlock::getParent() const {
54 auto *BB = cast<llvm::BasicBlock>(Val);
55 auto *F = BB->getParent();
56 if (F == nullptr)
57 // Detached
58 return nullptr;
59 return cast_or_null<Function>(Val: Ctx.getValue(V: F));
60}
61
62void BasicBlock::buildBasicBlockFromLLVMIR(llvm::BasicBlock *LLVMBB) {
63 for (llvm::Instruction &IRef : reverse(C&: *LLVMBB)) {
64 llvm::Instruction *I = &IRef;
65 Ctx.getOrCreateValue(LLVMV: I);
66 for (auto [OpIdx, Op] : enumerate(First: I->operands())) {
67 // Skip instruction's label operands
68 if (isa<llvm::BasicBlock>(Val: Op))
69 continue;
70 Ctx.getOrCreateValue(LLVMV: Op);
71 }
72 }
73#if !defined(NDEBUG)
74 verify();
75#endif
76}
77
78BasicBlock::iterator BasicBlock::begin() const {
79 llvm::BasicBlock *BB = cast<llvm::BasicBlock>(Val);
80 llvm::BasicBlock::iterator It = BB->begin();
81 if (!BB->empty()) {
82 auto *V = Ctx.getValue(V: &*BB->begin());
83 assert(V != nullptr && "No SandboxIR for BB->begin()!");
84 auto *I = cast<Instruction>(Val: V);
85 unsigned Num = I->getNumOfIRInstrs();
86 assert(Num >= 1u && "Bad getNumOfIRInstrs()");
87 It = std::next(x: It, n: Num - 1);
88 }
89 return iterator(BB, It, &Ctx);
90}
91
92Instruction *BasicBlock::getTerminator() const {
93 auto *TerminatorV =
94 Ctx.getValue(V: cast<llvm::BasicBlock>(Val)->getTerminator());
95 return cast_or_null<Instruction>(Val: TerminatorV);
96}
97
98Instruction &BasicBlock::front() const {
99 auto *BB = cast<llvm::BasicBlock>(Val);
100 assert(!BB->empty() && "Empty block!");
101 auto *SBI = cast<Instruction>(Val: getContext().getValue(V: &*BB->begin()));
102 assert(SBI != nullptr && "Expected Instr!");
103 return *SBI;
104}
105
106Instruction &BasicBlock::back() const {
107 auto *BB = cast<llvm::BasicBlock>(Val);
108 assert(!BB->empty() && "Empty block!");
109 auto *SBI = cast<Instruction>(Val: getContext().getValue(V: &*BB->rbegin()));
110 assert(SBI != nullptr && "Expected Instr!");
111 return *SBI;
112}
113
114#ifndef NDEBUG
115void BasicBlock::dumpOS(raw_ostream &OS) const {
116 llvm::BasicBlock *BB = cast<llvm::BasicBlock>(Val);
117 const auto &Name = BB->getName();
118 OS << Name;
119 if (!Name.empty())
120 OS << ":\n";
121 // If there are Instructions in the BB that are not mapped to SandboxIR, then
122 // use a crash-proof dump.
123 if (any_of(*BB, [this](llvm::Instruction &I) {
124 return Ctx.getValue(&I) == nullptr;
125 })) {
126 OS << "<Crash-proof mode!>\n";
127 DenseSet<Instruction *> Visited;
128 for (llvm::Instruction &IRef : *BB) {
129 Value *SBV = Ctx.getValue(&IRef);
130 if (SBV == nullptr)
131 OS << IRef << " *** No SandboxIR ***\n";
132 else {
133 auto *SBI = dyn_cast<Instruction>(SBV);
134 if (SBI == nullptr) {
135 OS << IRef << " *** Not a SBInstruction!!! ***\n";
136 } else {
137 if (Visited.insert(SBI).second)
138 OS << *SBI << "\n";
139 }
140 }
141 }
142 } else {
143 for (auto &SBI : *this) {
144 SBI.dumpOS(OS);
145 OS << "\n";
146 }
147 }
148}
149
150void BasicBlock::verify() const {
151 assert(isa<llvm::BasicBlock>(Val) && "Expected BasicBlock!");
152 for (const auto &I : *this) {
153 I.verify();
154 }
155}
156#endif // NDEBUG
157
158} // namespace llvm::sandboxir
159