xref: /llvm-project/bolt/lib/Core/MCPlusBuilder.cpp (revision b6f07d3ae8ddd749b33591f34b9519ed7b021970)
1 //===- bolt/Core/MCPlusBuilder.cpp - Interface for MCPlus -----------------===//
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 // This file implements the MCPlusBuilder class.
10 //
11 //===----------------------------------------------------------------------===//
12 
13 #include "bolt/Core/MCPlusBuilder.h"
14 #include "bolt/Core/MCPlus.h"
15 #include "llvm/MC/MCInst.h"
16 #include "llvm/MC/MCInstrAnalysis.h"
17 #include "llvm/MC/MCInstrDesc.h"
18 #include "llvm/MC/MCInstrInfo.h"
19 #include "llvm/MC/MCRegisterInfo.h"
20 #include "llvm/Support/Debug.h"
21 #include <cstdint>
22 #include <queue>
23 
24 #define DEBUG_TYPE "mcplus"
25 
26 using namespace llvm;
27 using namespace bolt;
28 using namespace MCPlus;
29 
30 bool MCPlusBuilder::equals(const MCInst &A, const MCInst &B,
31                            CompFuncTy Comp) const {
32   if (A.getOpcode() != B.getOpcode())
33     return false;
34 
35   unsigned NumOperands = MCPlus::getNumPrimeOperands(A);
36   if (NumOperands != MCPlus::getNumPrimeOperands(B))
37     return false;
38 
39   for (unsigned Index = 0; Index < NumOperands; ++Index)
40     if (!equals(A.getOperand(Index), B.getOperand(Index), Comp))
41       return false;
42 
43   return true;
44 }
45 
46 bool MCPlusBuilder::equals(const MCOperand &A, const MCOperand &B,
47                            CompFuncTy Comp) const {
48   if (A.isReg()) {
49     if (!B.isReg())
50       return false;
51     return A.getReg() == B.getReg();
52   } else if (A.isImm()) {
53     if (!B.isImm())
54       return false;
55     return A.getImm() == B.getImm();
56   } else if (A.isSFPImm()) {
57     if (!B.isSFPImm())
58       return false;
59     return A.getSFPImm() == B.getSFPImm();
60   } else if (A.isDFPImm()) {
61     if (!B.isDFPImm())
62       return false;
63     return A.getDFPImm() == B.getDFPImm();
64   } else if (A.isExpr()) {
65     if (!B.isExpr())
66       return false;
67     return equals(*A.getExpr(), *B.getExpr(), Comp);
68   } else {
69     llvm_unreachable("unexpected operand kind");
70     return false;
71   }
72 }
73 
74 bool MCPlusBuilder::equals(const MCExpr &A, const MCExpr &B,
75                            CompFuncTy Comp) const {
76   if (A.getKind() != B.getKind())
77     return false;
78 
79   switch (A.getKind()) {
80   case MCExpr::Constant: {
81     const auto &ConstA = cast<MCConstantExpr>(A);
82     const auto &ConstB = cast<MCConstantExpr>(B);
83     return ConstA.getValue() == ConstB.getValue();
84   }
85 
86   case MCExpr::SymbolRef: {
87     const MCSymbolRefExpr &SymbolA = cast<MCSymbolRefExpr>(A);
88     const MCSymbolRefExpr &SymbolB = cast<MCSymbolRefExpr>(B);
89     return SymbolA.getKind() == SymbolB.getKind() &&
90            Comp(&SymbolA.getSymbol(), &SymbolB.getSymbol());
91   }
92 
93   case MCExpr::Unary: {
94     const auto &UnaryA = cast<MCUnaryExpr>(A);
95     const auto &UnaryB = cast<MCUnaryExpr>(B);
96     return UnaryA.getOpcode() == UnaryB.getOpcode() &&
97            equals(*UnaryA.getSubExpr(), *UnaryB.getSubExpr(), Comp);
98   }
99 
100   case MCExpr::Binary: {
101     const auto &BinaryA = cast<MCBinaryExpr>(A);
102     const auto &BinaryB = cast<MCBinaryExpr>(B);
103     return BinaryA.getOpcode() == BinaryB.getOpcode() &&
104            equals(*BinaryA.getLHS(), *BinaryB.getLHS(), Comp) &&
105            equals(*BinaryA.getRHS(), *BinaryB.getRHS(), Comp);
106   }
107 
108   case MCExpr::Target: {
109     const auto &TargetExprA = cast<MCTargetExpr>(A);
110     const auto &TargetExprB = cast<MCTargetExpr>(B);
111     return equals(TargetExprA, TargetExprB, Comp);
112   }
113   }
114 
115   llvm_unreachable("Invalid expression kind!");
116 }
117 
118 bool MCPlusBuilder::equals(const MCTargetExpr &A, const MCTargetExpr &B,
119                            CompFuncTy Comp) const {
120   llvm_unreachable("target-specific expressions are unsupported");
121 }
122 
123 void MCPlusBuilder::setTailCall(MCInst &Inst) {
124   assert(!hasAnnotation(Inst, MCAnnotation::kTailCall));
125   setAnnotationOpValue(Inst, MCAnnotation::kTailCall, true);
126 }
127 
128 bool MCPlusBuilder::isTailCall(const MCInst &Inst) const {
129   if (hasAnnotation(Inst, MCAnnotation::kTailCall))
130     return true;
131   if (getConditionalTailCall(Inst))
132     return true;
133   return false;
134 }
135 
136 std::optional<MCLandingPad> MCPlusBuilder::getEHInfo(const MCInst &Inst) const {
137   if (!isCall(Inst))
138     return std::nullopt;
139   std::optional<int64_t> LPSym =
140       getAnnotationOpValue(Inst, MCAnnotation::kEHLandingPad);
141   if (!LPSym)
142     return std::nullopt;
143   std::optional<int64_t> Action =
144       getAnnotationOpValue(Inst, MCAnnotation::kEHAction);
145   if (!Action)
146     return std::nullopt;
147 
148   return std::make_pair(reinterpret_cast<const MCSymbol *>(*LPSym),
149                         static_cast<uint64_t>(*Action));
150 }
151 
152 void MCPlusBuilder::addEHInfo(MCInst &Inst, const MCLandingPad &LP) {
153   if (isCall(Inst)) {
154     assert(!getEHInfo(Inst));
155     setAnnotationOpValue(Inst, MCAnnotation::kEHLandingPad,
156                          reinterpret_cast<int64_t>(LP.first));
157     setAnnotationOpValue(Inst, MCAnnotation::kEHAction,
158                          static_cast<int64_t>(LP.second));
159   }
160 }
161 
162 bool MCPlusBuilder::updateEHInfo(MCInst &Inst, const MCLandingPad &LP) {
163   if (!isInvoke(Inst))
164     return false;
165 
166   setAnnotationOpValue(Inst, MCAnnotation::kEHLandingPad,
167                        reinterpret_cast<int64_t>(LP.first));
168   setAnnotationOpValue(Inst, MCAnnotation::kEHAction,
169                        static_cast<int64_t>(LP.second));
170   return true;
171 }
172 
173 int64_t MCPlusBuilder::getGnuArgsSize(const MCInst &Inst) const {
174   std::optional<int64_t> Value =
175       getAnnotationOpValue(Inst, MCAnnotation::kGnuArgsSize);
176   if (!Value)
177     return -1LL;
178   return *Value;
179 }
180 
181 void MCPlusBuilder::addGnuArgsSize(MCInst &Inst, int64_t GnuArgsSize,
182                                    AllocatorIdTy AllocId) {
183   assert(GnuArgsSize >= 0 && "cannot set GNU_args_size to negative value");
184   assert(getGnuArgsSize(Inst) == -1LL && "GNU_args_size already set");
185   assert(isInvoke(Inst) && "GNU_args_size can only be set for invoke");
186 
187   setAnnotationOpValue(Inst, MCAnnotation::kGnuArgsSize, GnuArgsSize, AllocId);
188 }
189 
190 uint64_t MCPlusBuilder::getJumpTable(const MCInst &Inst) const {
191   std::optional<int64_t> Value =
192       getAnnotationOpValue(Inst, MCAnnotation::kJumpTable);
193   if (!Value)
194     return 0;
195   return *Value;
196 }
197 
198 uint16_t MCPlusBuilder::getJumpTableIndexReg(const MCInst &Inst) const {
199   return getAnnotationAs<uint16_t>(Inst, "JTIndexReg");
200 }
201 
202 bool MCPlusBuilder::setJumpTable(MCInst &Inst, uint64_t Value,
203                                  uint16_t IndexReg, AllocatorIdTy AllocId) {
204   if (!isIndirectBranch(Inst))
205     return false;
206   setAnnotationOpValue(Inst, MCAnnotation::kJumpTable, Value, AllocId);
207   getOrCreateAnnotationAs<uint16_t>(Inst, "JTIndexReg", AllocId) = IndexReg;
208   return true;
209 }
210 
211 bool MCPlusBuilder::unsetJumpTable(MCInst &Inst) {
212   if (!getJumpTable(Inst))
213     return false;
214   removeAnnotation(Inst, MCAnnotation::kJumpTable);
215   removeAnnotation(Inst, "JTIndexReg");
216   return true;
217 }
218 
219 std::optional<uint64_t>
220 MCPlusBuilder::getConditionalTailCall(const MCInst &Inst) const {
221   std::optional<int64_t> Value =
222       getAnnotationOpValue(Inst, MCAnnotation::kConditionalTailCall);
223   if (!Value)
224     return std::nullopt;
225   return static_cast<uint64_t>(*Value);
226 }
227 
228 bool MCPlusBuilder::setConditionalTailCall(MCInst &Inst, uint64_t Dest) {
229   if (!isConditionalBranch(Inst))
230     return false;
231 
232   setAnnotationOpValue(Inst, MCAnnotation::kConditionalTailCall, Dest);
233   return true;
234 }
235 
236 bool MCPlusBuilder::unsetConditionalTailCall(MCInst &Inst) {
237   if (!getConditionalTailCall(Inst))
238     return false;
239   removeAnnotation(Inst, MCAnnotation::kConditionalTailCall);
240   return true;
241 }
242 
243 std::optional<uint32_t> MCPlusBuilder::getOffset(const MCInst &Inst) const {
244   std::optional<int64_t> Value =
245       getAnnotationOpValue(Inst, MCAnnotation::kOffset);
246   if (!Value)
247     return std::nullopt;
248   return static_cast<uint32_t>(*Value);
249 }
250 
251 uint32_t MCPlusBuilder::getOffsetWithDefault(const MCInst &Inst,
252                                              uint32_t Default) const {
253   if (std::optional<uint32_t> Offset = getOffset(Inst))
254     return *Offset;
255   return Default;
256 }
257 
258 bool MCPlusBuilder::setOffset(MCInst &Inst, uint32_t Offset,
259                               AllocatorIdTy AllocatorId) {
260   setAnnotationOpValue(Inst, MCAnnotation::kOffset, Offset, AllocatorId);
261   return true;
262 }
263 
264 bool MCPlusBuilder::clearOffset(MCInst &Inst) {
265   if (!hasAnnotation(Inst, MCAnnotation::kOffset))
266     return false;
267   removeAnnotation(Inst, MCAnnotation::kOffset);
268   return true;
269 }
270 
271 bool MCPlusBuilder::hasAnnotation(const MCInst &Inst, unsigned Index) const {
272   const MCInst *AnnotationInst = getAnnotationInst(Inst);
273   if (!AnnotationInst)
274     return false;
275 
276   return (bool)getAnnotationOpValue(Inst, Index);
277 }
278 
279 bool MCPlusBuilder::removeAnnotation(MCInst &Inst, unsigned Index) {
280   MCInst *AnnotationInst = getAnnotationInst(Inst);
281   if (!AnnotationInst)
282     return false;
283 
284   for (int I = AnnotationInst->getNumOperands() - 1; I >= 0; --I) {
285     int64_t ImmValue = AnnotationInst->getOperand(I).getImm();
286     if (extractAnnotationIndex(ImmValue) == Index) {
287       AnnotationInst->erase(AnnotationInst->begin() + I);
288       return true;
289     }
290   }
291   return false;
292 }
293 
294 void MCPlusBuilder::stripAnnotations(MCInst &Inst, bool KeepTC) {
295   MCInst *AnnotationInst = getAnnotationInst(Inst);
296   if (!AnnotationInst)
297     return;
298   // Preserve TailCall annotation.
299   auto IsTC = hasAnnotation(Inst, MCAnnotation::kTailCall);
300 
301   removeAnnotationInst(Inst);
302 
303   if (KeepTC && IsTC)
304     setTailCall(Inst);
305 }
306 
307 void MCPlusBuilder::printAnnotations(const MCInst &Inst,
308                                      raw_ostream &OS) const {
309   const MCInst *AnnotationInst = getAnnotationInst(Inst);
310   if (!AnnotationInst)
311     return;
312 
313   for (unsigned I = 0; I < AnnotationInst->getNumOperands(); ++I) {
314     const int64_t Imm = AnnotationInst->getOperand(I).getImm();
315     const unsigned Index = extractAnnotationIndex(Imm);
316     const int64_t Value = extractAnnotationValue(Imm);
317     const auto *Annotation = reinterpret_cast<const MCAnnotation *>(Value);
318     if (Index >= MCAnnotation::kGeneric) {
319       OS << " # " << AnnotationNames[Index - MCAnnotation::kGeneric] << ": ";
320       Annotation->print(OS);
321     }
322   }
323 }
324 
325 void MCPlusBuilder::getClobberedRegs(const MCInst &Inst,
326                                      BitVector &Regs) const {
327   if (isPrefix(Inst) || isCFI(Inst))
328     return;
329 
330   const MCInstrDesc &InstInfo = Info->get(Inst.getOpcode());
331 
332   for (MCPhysReg ImplicitDef : InstInfo.implicit_defs())
333     Regs |= getAliases(ImplicitDef, /*OnlySmaller=*/false);
334 
335   for (const MCOperand &Operand : defOperands(Inst)) {
336     assert(Operand.isReg());
337     Regs |= getAliases(Operand.getReg(), /*OnlySmaller=*/false);
338   }
339 }
340 
341 void MCPlusBuilder::getTouchedRegs(const MCInst &Inst, BitVector &Regs) const {
342   if (isPrefix(Inst) || isCFI(Inst))
343     return;
344 
345   const MCInstrDesc &InstInfo = Info->get(Inst.getOpcode());
346 
347   for (MCPhysReg ImplicitDef : InstInfo.implicit_defs())
348     Regs |= getAliases(ImplicitDef, /*OnlySmaller=*/false);
349   for (MCPhysReg ImplicitUse : InstInfo.implicit_uses())
350     Regs |= getAliases(ImplicitUse, /*OnlySmaller=*/false);
351 
352   for (unsigned I = 0, E = Inst.getNumOperands(); I != E; ++I) {
353     if (!Inst.getOperand(I).isReg())
354       continue;
355     Regs |= getAliases(Inst.getOperand(I).getReg(), /*OnlySmaller=*/false);
356   }
357 }
358 
359 void MCPlusBuilder::getWrittenRegs(const MCInst &Inst, BitVector &Regs) const {
360   if (isPrefix(Inst) || isCFI(Inst))
361     return;
362 
363   const MCInstrDesc &InstInfo = Info->get(Inst.getOpcode());
364 
365   for (MCPhysReg ImplicitDef : InstInfo.implicit_defs())
366     Regs |= getAliases(ImplicitDef, /*OnlySmaller=*/true);
367 
368   for (const MCOperand &Operand : defOperands(Inst)) {
369     assert(Operand.isReg());
370     Regs |= getAliases(Operand.getReg(), /*OnlySmaller=*/true);
371   }
372 }
373 
374 void MCPlusBuilder::getUsedRegs(const MCInst &Inst, BitVector &Regs) const {
375   if (isPrefix(Inst) || isCFI(Inst))
376     return;
377 
378   const MCInstrDesc &InstInfo = Info->get(Inst.getOpcode());
379 
380   for (MCPhysReg ImplicitUse : InstInfo.implicit_uses())
381     Regs |= getAliases(ImplicitUse, /*OnlySmaller=*/true);
382 
383   for (unsigned I = 0, E = Inst.getNumOperands(); I != E; ++I) {
384     if (!Inst.getOperand(I).isReg())
385       continue;
386     Regs |= getAliases(Inst.getOperand(I).getReg(), /*OnlySmaller=*/true);
387   }
388 }
389 
390 void MCPlusBuilder::getSrcRegs(const MCInst &Inst, BitVector &Regs) const {
391   if (isPrefix(Inst) || isCFI(Inst))
392     return;
393 
394   if (isCall(Inst)) {
395     BitVector CallRegs = BitVector(Regs.size(), false);
396     getCalleeSavedRegs(CallRegs);
397     CallRegs.flip();
398     Regs |= CallRegs;
399     return;
400   }
401 
402   if (isReturn(Inst)) {
403     getDefaultLiveOut(Regs);
404     return;
405   }
406 
407   if (isRep(Inst))
408     getRepRegs(Regs);
409 
410   const MCInstrDesc &InstInfo = Info->get(Inst.getOpcode());
411 
412   for (MCPhysReg ImplicitUse : InstInfo.implicit_uses())
413     Regs |= getAliases(ImplicitUse, /*OnlySmaller=*/true);
414 
415   for (const MCOperand &Operand : useOperands(Inst))
416     if (Operand.isReg())
417       Regs |= getAliases(Operand.getReg(), /*OnlySmaller=*/true);
418 }
419 
420 bool MCPlusBuilder::hasDefOfPhysReg(const MCInst &MI, unsigned Reg) const {
421   const MCInstrDesc &InstInfo = Info->get(MI.getOpcode());
422   return InstInfo.hasDefOfPhysReg(MI, Reg, *RegInfo);
423 }
424 
425 bool MCPlusBuilder::hasUseOfPhysReg(const MCInst &MI, unsigned Reg) const {
426   const MCInstrDesc &InstInfo = Info->get(MI.getOpcode());
427   for (int I = InstInfo.NumDefs; I < InstInfo.NumOperands; ++I)
428     if (MI.getOperand(I).isReg() &&
429         RegInfo->isSubRegisterEq(Reg, MI.getOperand(I).getReg()))
430       return true;
431   for (MCPhysReg ImplicitUse : InstInfo.implicit_uses()) {
432     if (ImplicitUse == Reg || RegInfo->isSubRegister(Reg, ImplicitUse))
433       return true;
434   }
435   return false;
436 }
437 
438 const BitVector &MCPlusBuilder::getAliases(MCPhysReg Reg,
439                                            bool OnlySmaller) const {
440   if (OnlySmaller)
441     return SmallerAliasMap[Reg];
442   return AliasMap[Reg];
443 }
444 
445 void MCPlusBuilder::initAliases() {
446   assert(AliasMap.size() == 0 && SmallerAliasMap.size() == 0);
447   // Build alias map
448   for (MCPhysReg I = 0, E = RegInfo->getNumRegs(); I != E; ++I) {
449     BitVector BV(RegInfo->getNumRegs(), false);
450     BV.set(I);
451     AliasMap.emplace_back(BV);
452     SmallerAliasMap.emplace_back(BV);
453   }
454 
455   // Cache all aliases for each register
456   for (MCPhysReg I = 1, E = RegInfo->getNumRegs(); I != E; ++I) {
457     for (MCRegAliasIterator AI(I, RegInfo, true); AI.isValid(); ++AI)
458       AliasMap[I].set(*AI);
459   }
460 
461   // Propagate smaller alias info upwards. Skip reg 0 (mapped to NoRegister)
462   for (MCPhysReg I = 1, E = RegInfo->getNumRegs(); I < E; ++I)
463     for (MCSubRegIterator SI(I, RegInfo); SI.isValid(); ++SI)
464       SmallerAliasMap[I] |= SmallerAliasMap[*SI];
465 
466   LLVM_DEBUG({
467     dbgs() << "Dumping reg alias table:\n";
468     for (MCPhysReg I = 0, E = RegInfo->getNumRegs(); I != E; ++I) {
469       dbgs() << "Reg " << I << ": ";
470       const BitVector &BV = AliasMap[I];
471       int Idx = BV.find_first();
472       while (Idx != -1) {
473         dbgs() << Idx << " ";
474         Idx = BV.find_next(Idx);
475       }
476       dbgs() << "\n";
477     }
478   });
479 }
480 
481 void MCPlusBuilder::initSizeMap() {
482   SizeMap.resize(RegInfo->getNumRegs());
483   // Build size map
484   for (auto RC : RegInfo->regclasses())
485     for (MCPhysReg Reg : RC)
486       SizeMap[Reg] = RC.getSizeInBits() / 8;
487 }
488 
489 bool MCPlusBuilder::setOperandToSymbolRef(MCInst &Inst, int OpNum,
490                                           const MCSymbol *Symbol,
491                                           int64_t Addend, MCContext *Ctx,
492                                           uint64_t RelType) const {
493   MCOperand Operand;
494   if (!Addend) {
495     Operand = MCOperand::createExpr(getTargetExprFor(
496         Inst, MCSymbolRefExpr::create(Symbol, *Ctx), *Ctx, RelType));
497   } else {
498     Operand = MCOperand::createExpr(getTargetExprFor(
499         Inst,
500         MCBinaryExpr::createAdd(MCSymbolRefExpr::create(Symbol, *Ctx),
501                                 MCConstantExpr::create(Addend, *Ctx), *Ctx),
502         *Ctx, RelType));
503   }
504   Inst.getOperand(OpNum) = Operand;
505   return true;
506 }
507