xref: /freebsd/contrib/llvm-project/llvm/lib/SandboxIR/Region.cpp (revision 700637cbb5e582861067a11aaca4d053546871d2)
1*700637cbSDimitry Andric //===- Region.cpp ---------------------------------------------------------===//
2*700637cbSDimitry Andric //
3*700637cbSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*700637cbSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*700637cbSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*700637cbSDimitry Andric //
7*700637cbSDimitry Andric //===----------------------------------------------------------------------===//
8*700637cbSDimitry Andric 
9*700637cbSDimitry Andric #include "llvm/SandboxIR/Region.h"
10*700637cbSDimitry Andric #include "llvm/SandboxIR/Function.h"
11*700637cbSDimitry Andric 
12*700637cbSDimitry Andric namespace llvm::sandboxir {
13*700637cbSDimitry Andric 
getCost(Instruction * I) const14*700637cbSDimitry Andric InstructionCost ScoreBoard::getCost(Instruction *I) const {
15*700637cbSDimitry Andric   auto *LLVMI = cast<llvm::Instruction>(I->Val);
16*700637cbSDimitry Andric   SmallVector<const llvm::Value *> Operands(LLVMI->operands());
17*700637cbSDimitry Andric   return TTI.getInstructionCost(LLVMI, Operands, CostKind);
18*700637cbSDimitry Andric }
19*700637cbSDimitry Andric 
remove(Instruction * I)20*700637cbSDimitry Andric void ScoreBoard::remove(Instruction *I) {
21*700637cbSDimitry Andric   auto Cost = getCost(I);
22*700637cbSDimitry Andric   if (Rgn.contains(I))
23*700637cbSDimitry Andric     // If `I` is one the newly added ones, then we should adjust `AfterCost`
24*700637cbSDimitry Andric     AfterCost -= Cost;
25*700637cbSDimitry Andric   else
26*700637cbSDimitry Andric     // If `I` is one of the original instructions (outside the region) then it
27*700637cbSDimitry Andric     // is part of the original code, so adjust `BeforeCost`.
28*700637cbSDimitry Andric     BeforeCost += Cost;
29*700637cbSDimitry Andric }
30*700637cbSDimitry Andric 
31*700637cbSDimitry Andric #ifndef NDEBUG
dump() const32*700637cbSDimitry Andric void ScoreBoard::dump() const { dump(dbgs()); }
33*700637cbSDimitry Andric #endif
34*700637cbSDimitry Andric 
Region(Context & Ctx,TargetTransformInfo & TTI)35*700637cbSDimitry Andric Region::Region(Context &Ctx, TargetTransformInfo &TTI)
36*700637cbSDimitry Andric     : Ctx(Ctx), Scoreboard(*this, TTI) {
37*700637cbSDimitry Andric   LLVMContext &LLVMCtx = Ctx.LLVMCtx;
38*700637cbSDimitry Andric   auto *RegionStrMD = MDString::get(LLVMCtx, RegionStr);
39*700637cbSDimitry Andric   RegionMDN = MDNode::getDistinct(LLVMCtx, {RegionStrMD});
40*700637cbSDimitry Andric 
41*700637cbSDimitry Andric   CreateInstCB = Ctx.registerCreateInstrCallback(
42*700637cbSDimitry Andric       [this](Instruction *NewInst) { add(NewInst); });
43*700637cbSDimitry Andric   EraseInstCB = Ctx.registerEraseInstrCallback([this](Instruction *ErasedInst) {
44*700637cbSDimitry Andric     remove(ErasedInst);
45*700637cbSDimitry Andric     removeFromAux(ErasedInst);
46*700637cbSDimitry Andric   });
47*700637cbSDimitry Andric }
48*700637cbSDimitry Andric 
~Region()49*700637cbSDimitry Andric Region::~Region() {
50*700637cbSDimitry Andric   Ctx.unregisterCreateInstrCallback(CreateInstCB);
51*700637cbSDimitry Andric   Ctx.unregisterEraseInstrCallback(EraseInstCB);
52*700637cbSDimitry Andric }
53*700637cbSDimitry Andric 
addImpl(Instruction * I,bool IgnoreCost)54*700637cbSDimitry Andric void Region::addImpl(Instruction *I, bool IgnoreCost) {
55*700637cbSDimitry Andric   Insts.insert(I);
56*700637cbSDimitry Andric   // TODO: Consider tagging instructions lazily.
57*700637cbSDimitry Andric   cast<llvm::Instruction>(I->Val)->setMetadata(MDKind, RegionMDN);
58*700637cbSDimitry Andric   if (!IgnoreCost)
59*700637cbSDimitry Andric     // Keep track of the instruction cost.
60*700637cbSDimitry Andric     Scoreboard.add(I);
61*700637cbSDimitry Andric }
62*700637cbSDimitry Andric 
setAux(ArrayRef<Instruction * > Aux)63*700637cbSDimitry Andric void Region::setAux(ArrayRef<Instruction *> Aux) {
64*700637cbSDimitry Andric   this->Aux = SmallVector<Instruction *>(Aux);
65*700637cbSDimitry Andric   auto &LLVMCtx = Ctx.LLVMCtx;
66*700637cbSDimitry Andric   for (auto [Idx, I] : enumerate(Aux)) {
67*700637cbSDimitry Andric     llvm::ConstantInt *IdxC =
68*700637cbSDimitry Andric         llvm::ConstantInt::get(llvm::Type::getInt32Ty(LLVMCtx), Idx, false);
69*700637cbSDimitry Andric     assert(cast<llvm::Instruction>(I->Val)->getMetadata(AuxMDKind) == nullptr &&
70*700637cbSDimitry Andric            "Instruction already in Aux!");
71*700637cbSDimitry Andric     cast<llvm::Instruction>(I->Val)->setMetadata(
72*700637cbSDimitry Andric         AuxMDKind, MDNode::get(LLVMCtx, ConstantAsMetadata::get(IdxC)));
73*700637cbSDimitry Andric     // Aux instrs should always be in a region.
74*700637cbSDimitry Andric     addImpl(I, /*DontTrackCost=*/true);
75*700637cbSDimitry Andric   }
76*700637cbSDimitry Andric }
77*700637cbSDimitry Andric 
setAux(unsigned Idx,Instruction * I)78*700637cbSDimitry Andric void Region::setAux(unsigned Idx, Instruction *I) {
79*700637cbSDimitry Andric   assert((Idx >= Aux.size() || Aux[Idx] == nullptr) &&
80*700637cbSDimitry Andric          "There is already an Instruction at Idx in Aux!");
81*700637cbSDimitry Andric   unsigned ExpectedSz = Idx + 1;
82*700637cbSDimitry Andric   if (Aux.size() < ExpectedSz) {
83*700637cbSDimitry Andric     auto SzBefore = Aux.size();
84*700637cbSDimitry Andric     Aux.resize(ExpectedSz);
85*700637cbSDimitry Andric     // Initialize the gap with nullptr.
86*700637cbSDimitry Andric     for (unsigned Idx = SzBefore; Idx + 1 < ExpectedSz; ++Idx)
87*700637cbSDimitry Andric       Aux[Idx] = nullptr;
88*700637cbSDimitry Andric   }
89*700637cbSDimitry Andric   Aux[Idx] = I;
90*700637cbSDimitry Andric   // Aux instrs should always be in a region.
91*700637cbSDimitry Andric   addImpl(I, /*DontTrackCost=*/true);
92*700637cbSDimitry Andric }
93*700637cbSDimitry Andric 
dropAuxMetadata(Instruction * I)94*700637cbSDimitry Andric void Region::dropAuxMetadata(Instruction *I) {
95*700637cbSDimitry Andric   auto *LLVMI = cast<llvm::Instruction>(I->Val);
96*700637cbSDimitry Andric   LLVMI->setMetadata(AuxMDKind, nullptr);
97*700637cbSDimitry Andric }
98*700637cbSDimitry Andric 
removeFromAux(Instruction * I)99*700637cbSDimitry Andric void Region::removeFromAux(Instruction *I) {
100*700637cbSDimitry Andric   auto It = find(Aux, I);
101*700637cbSDimitry Andric   if (It == Aux.end())
102*700637cbSDimitry Andric     return;
103*700637cbSDimitry Andric   dropAuxMetadata(I);
104*700637cbSDimitry Andric   Aux.erase(It);
105*700637cbSDimitry Andric }
106*700637cbSDimitry Andric 
clearAux()107*700637cbSDimitry Andric void Region::clearAux() {
108*700637cbSDimitry Andric   for (unsigned Idx : seq<unsigned>(0, Aux.size()))
109*700637cbSDimitry Andric     dropAuxMetadata(Aux[Idx]);
110*700637cbSDimitry Andric   Aux.clear();
111*700637cbSDimitry Andric }
112*700637cbSDimitry Andric 
remove(Instruction * I)113*700637cbSDimitry Andric void Region::remove(Instruction *I) {
114*700637cbSDimitry Andric   // Keep track of the instruction cost. This need to be done *before* we remove
115*700637cbSDimitry Andric   // `I` from the region.
116*700637cbSDimitry Andric   Scoreboard.remove(I);
117*700637cbSDimitry Andric 
118*700637cbSDimitry Andric   Insts.remove(I);
119*700637cbSDimitry Andric   cast<llvm::Instruction>(I->Val)->setMetadata(MDKind, nullptr);
120*700637cbSDimitry Andric }
121*700637cbSDimitry Andric 
122*700637cbSDimitry Andric #ifndef NDEBUG
operator ==(const Region & Other) const123*700637cbSDimitry Andric bool Region::operator==(const Region &Other) const {
124*700637cbSDimitry Andric   if (Insts.size() != Other.Insts.size())
125*700637cbSDimitry Andric     return false;
126*700637cbSDimitry Andric   if (!std::is_permutation(Insts.begin(), Insts.end(), Other.Insts.begin()))
127*700637cbSDimitry Andric     return false;
128*700637cbSDimitry Andric   return true;
129*700637cbSDimitry Andric }
130*700637cbSDimitry Andric 
dump(raw_ostream & OS) const131*700637cbSDimitry Andric void Region::dump(raw_ostream &OS) const {
132*700637cbSDimitry Andric   for (auto *I : Insts)
133*700637cbSDimitry Andric     OS << *I << "\n";
134*700637cbSDimitry Andric   if (!Aux.empty()) {
135*700637cbSDimitry Andric     OS << "\nAux:\n";
136*700637cbSDimitry Andric     for (auto *I : Aux) {
137*700637cbSDimitry Andric       if (I == nullptr)
138*700637cbSDimitry Andric         OS << "NULL\n";
139*700637cbSDimitry Andric       else
140*700637cbSDimitry Andric         OS << *I << "\n";
141*700637cbSDimitry Andric     }
142*700637cbSDimitry Andric   }
143*700637cbSDimitry Andric }
144*700637cbSDimitry Andric 
dump() const145*700637cbSDimitry Andric void Region::dump() const {
146*700637cbSDimitry Andric   dump(dbgs());
147*700637cbSDimitry Andric   dbgs() << "\n";
148*700637cbSDimitry Andric }
149*700637cbSDimitry Andric #endif // NDEBUG
150*700637cbSDimitry Andric 
151*700637cbSDimitry Andric SmallVector<std::unique_ptr<Region>>
createRegionsFromMD(Function & F,TargetTransformInfo & TTI)152*700637cbSDimitry Andric Region::createRegionsFromMD(Function &F, TargetTransformInfo &TTI) {
153*700637cbSDimitry Andric   SmallVector<std::unique_ptr<Region>> Regions;
154*700637cbSDimitry Andric   DenseMap<MDNode *, Region *> MDNToRegion;
155*700637cbSDimitry Andric   auto &Ctx = F.getContext();
156*700637cbSDimitry Andric   for (BasicBlock &BB : F) {
157*700637cbSDimitry Andric     for (Instruction &Inst : BB) {
158*700637cbSDimitry Andric       auto *LLVMI = cast<llvm::Instruction>(Inst.Val);
159*700637cbSDimitry Andric       Region *R = nullptr;
160*700637cbSDimitry Andric       if (auto *MDN = LLVMI->getMetadata(MDKind)) {
161*700637cbSDimitry Andric         auto [It, Inserted] = MDNToRegion.try_emplace(MDN);
162*700637cbSDimitry Andric         if (Inserted) {
163*700637cbSDimitry Andric           Regions.push_back(std::make_unique<Region>(Ctx, TTI));
164*700637cbSDimitry Andric           R = Regions.back().get();
165*700637cbSDimitry Andric           It->second = R;
166*700637cbSDimitry Andric         } else {
167*700637cbSDimitry Andric           R = It->second;
168*700637cbSDimitry Andric         }
169*700637cbSDimitry Andric         R->addImpl(&Inst, /*IgnoreCost=*/true);
170*700637cbSDimitry Andric       }
171*700637cbSDimitry Andric       if (auto *AuxMDN = LLVMI->getMetadata(AuxMDKind)) {
172*700637cbSDimitry Andric         llvm::Constant *IdxC =
173*700637cbSDimitry Andric             dyn_cast<ConstantAsMetadata>(AuxMDN->getOperand(0))->getValue();
174*700637cbSDimitry Andric         auto Idx = cast<llvm::ConstantInt>(IdxC)->getSExtValue();
175*700637cbSDimitry Andric         if (R == nullptr) {
176*700637cbSDimitry Andric           errs() << "No region specified for Aux: '" << *LLVMI << "'\n";
177*700637cbSDimitry Andric           exit(1);
178*700637cbSDimitry Andric         }
179*700637cbSDimitry Andric         R->setAux(Idx, &Inst);
180*700637cbSDimitry Andric       }
181*700637cbSDimitry Andric     }
182*700637cbSDimitry Andric   }
183*700637cbSDimitry Andric #ifndef NDEBUG
184*700637cbSDimitry Andric   // Check that there are no gaps in the Aux vector.
185*700637cbSDimitry Andric   for (auto &RPtr : Regions)
186*700637cbSDimitry Andric     for (auto *I : RPtr->getAux())
187*700637cbSDimitry Andric       assert(I != nullptr && "Gap in Aux!");
188*700637cbSDimitry Andric #endif
189*700637cbSDimitry Andric   return Regions;
190*700637cbSDimitry Andric }
191*700637cbSDimitry Andric 
192*700637cbSDimitry Andric } // namespace llvm::sandboxir
193