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 | |
14 | namespace llvm::sandboxir { |
15 | |
16 | BBIterator &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 | |
29 | BBIterator &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 | |
43 | BasicBlock *BBIterator::getNodeParent() const { |
44 | llvm::BasicBlock *Parent = const_cast<BBIterator *>(this)->It.getNodeParent(); |
45 | return cast<BasicBlock>(Val: Ctx->getValue(V: Parent)); |
46 | } |
47 | |
48 | BasicBlock::iterator::pointer |
49 | BasicBlock::iterator::getInstr(llvm::BasicBlock::iterator It) const { |
50 | return cast_or_null<Instruction>(Val: Ctx->getValue(V: &*It)); |
51 | } |
52 | |
53 | Function *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 | |
62 | void 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 | |
78 | BasicBlock::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 | |
92 | Instruction *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 | |
98 | Instruction &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 | |
106 | Instruction &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 |
115 | void 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 | |
150 | void 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 | |