1//===- Region.cpp ---------------------------------------------------------===//
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/Region.h"
10
11namespace llvm::sandboxir {
12
13Region::Region(Context &Ctx, RegionClassID ID) : Ctx(Ctx), ID(ID) {
14 LLVMContext &LLVMCtx = Ctx.LLVMCtx;
15 auto *RegionStrMD = MDString::get(Context&: LLVMCtx, Str: RegionStr);
16 RegionMDN = MDNode::getDistinct(Context&: LLVMCtx, MDs: {RegionStrMD});
17
18 CreateInstCB = Ctx.registerCreateInstrCallback(
19 CB: [this](Instruction *NewInst) { addRaw(I: NewInst); });
20 EraseInstCB = Ctx.registerEraseInstrCallback(CB: [this](Instruction *ErasedInst) {
21 remove(I: ErasedInst);
22 removeFromAux(I: ErasedInst);
23 });
24}
25
26Region::~Region() {
27 Ctx.unregisterCreateInstrCallback(ID: CreateInstCB);
28 Ctx.unregisterEraseInstrCallback(ID: EraseInstCB);
29}
30
31void Region::setAux(ArrayRef<Instruction *> Aux) {
32 this->Aux = SmallVector<Instruction *>(Aux);
33 auto &LLVMCtx = Ctx.LLVMCtx;
34 for (auto [Idx, I] : enumerate(First&: Aux)) {
35 llvm::ConstantInt *IdxC =
36 llvm::ConstantInt::get(Ty: llvm::Type::getInt32Ty(C&: LLVMCtx), V: Idx, IsSigned: false);
37 assert(cast<llvm::Instruction>(I->Val)->getMetadata(AuxMDKind) == nullptr &&
38 "Instruction already in Aux!");
39 cast<llvm::Instruction>(Val: I->Val)->setMetadata(
40 Kind: AuxMDKind, Node: MDNode::get(Context&: LLVMCtx, MDs: ConstantAsMetadata::get(C: IdxC)));
41 // Aux instrs should always be in a region.
42 addRaw(I);
43 }
44}
45
46void Region::setAux(unsigned Idx, Instruction *I) {
47 assert((Idx >= Aux.size() || Aux[Idx] == nullptr) &&
48 "There is already an Instruction at Idx in Aux!");
49 unsigned ExpectedSz = Idx + 1;
50 if (Aux.size() < ExpectedSz) {
51 auto SzBefore = Aux.size();
52 Aux.resize(N: ExpectedSz);
53 // Initialize the gap with nullptr.
54 for (unsigned Idx = SzBefore; Idx + 1 < ExpectedSz; ++Idx)
55 Aux[Idx] = nullptr;
56 }
57 Aux[Idx] = I;
58 // Aux instrs should always be in a region.
59 addRaw(I);
60}
61
62void Region::dropAuxMetadata(Instruction *I) {
63 auto *LLVMI = cast<llvm::Instruction>(Val: I->Val);
64 LLVMI->setMetadata(Kind: AuxMDKind, Node: nullptr);
65}
66
67void Region::removeFromAux(Instruction *I) {
68 auto It = find(Range&: Aux, Val: I);
69 if (It == Aux.end())
70 return;
71 dropAuxMetadata(I);
72 Aux.erase(CI: It);
73}
74
75void Region::clearAux() {
76 for (unsigned Idx : seq<unsigned>(Begin: 0, End: Aux.size()))
77 dropAuxMetadata(I: Aux[Idx]);
78 Aux.clear();
79}
80
81void Region::remove(Instruction *I) {
82 Insts.remove(X: I);
83 cast<llvm::Instruction>(Val: I->Val)->setMetadata(Kind: MDKind, Node: nullptr);
84}
85
86#ifndef NDEBUG
87bool Region::operator==(const Region &Other) const {
88 if (Insts.size() != Other.Insts.size())
89 return false;
90 if (!std::is_permutation(Insts.begin(), Insts.end(), Other.Insts.begin()))
91 return false;
92 return true;
93}
94
95void Region::dump(raw_ostream &OS) const {
96 for (auto *I : Insts)
97 OS << *I << "\n";
98 if (!Aux.empty()) {
99 OS << "\nAux:\n";
100 for (auto *I : Aux) {
101 if (I == nullptr)
102 OS << "NULL\n";
103 else
104 OS << *I << "\n";
105 }
106 }
107}
108
109void Region::dump() const {
110 dump(dbgs());
111 dbgs() << "\n";
112}
113#endif // NDEBUG
114
115SmallVector<std::unique_ptr<Region>> Region::createRegionsFromMD(Function &F) {
116 return Region::createRegionsFromMD<Region>(
117 F, Factory: [&F]() { return std::make_unique<Region>(args&: F.getContext()); });
118}
119
120} // namespace llvm::sandboxir
121