//===- bolt/Core/MCPlusBuilder.cpp - Interface for MCPlus -----------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // // This file implements the MCPlusBuilder class. // //===----------------------------------------------------------------------===// #include "bolt/Core/MCPlusBuilder.h" #include "bolt/Core/MCPlus.h" #include "llvm/MC/MCInst.h" #include "llvm/MC/MCInstrAnalysis.h" #include "llvm/MC/MCInstrDesc.h" #include "llvm/MC/MCInstrInfo.h" #include "llvm/Support/Debug.h" #include #include #define DEBUG_TYPE "mcplus" using namespace llvm; using namespace bolt; using namespace MCPlus; bool MCPlusBuilder::equals(const MCInst &A, const MCInst &B, CompFuncTy Comp) const { if (A.getOpcode() != B.getOpcode()) return false; unsigned NumOperands = MCPlus::getNumPrimeOperands(A); if (NumOperands != MCPlus::getNumPrimeOperands(B)) return false; for (unsigned Index = 0; Index < NumOperands; ++Index) if (!equals(A.getOperand(Index), B.getOperand(Index), Comp)) return false; return true; } bool MCPlusBuilder::equals(const MCOperand &A, const MCOperand &B, CompFuncTy Comp) const { if (A.isReg()) { if (!B.isReg()) return false; return A.getReg() == B.getReg(); } else if (A.isImm()) { if (!B.isImm()) return false; return A.getImm() == B.getImm(); } else if (A.isSFPImm()) { if (!B.isSFPImm()) return false; return A.getSFPImm() == B.getSFPImm(); } else if (A.isDFPImm()) { if (!B.isDFPImm()) return false; return A.getDFPImm() == B.getDFPImm(); } else if (A.isExpr()) { if (!B.isExpr()) return false; return equals(*A.getExpr(), *B.getExpr(), Comp); } else { llvm_unreachable("unexpected operand kind"); return false; } } bool MCPlusBuilder::equals(const MCExpr &A, const MCExpr &B, CompFuncTy Comp) const { if (A.getKind() != B.getKind()) return false; switch (A.getKind()) { case MCExpr::Constant: { const auto &ConstA = cast(A); const auto &ConstB = cast(B); return ConstA.getValue() == ConstB.getValue(); } case MCExpr::SymbolRef: { const MCSymbolRefExpr &SymbolA = cast(A); const MCSymbolRefExpr &SymbolB = cast(B); return SymbolA.getKind() == SymbolB.getKind() && Comp(&SymbolA.getSymbol(), &SymbolB.getSymbol()); } case MCExpr::Unary: { const auto &UnaryA = cast(A); const auto &UnaryB = cast(B); return UnaryA.getOpcode() == UnaryB.getOpcode() && equals(*UnaryA.getSubExpr(), *UnaryB.getSubExpr(), Comp); } case MCExpr::Binary: { const auto &BinaryA = cast(A); const auto &BinaryB = cast(B); return BinaryA.getOpcode() == BinaryB.getOpcode() && equals(*BinaryA.getLHS(), *BinaryB.getLHS(), Comp) && equals(*BinaryA.getRHS(), *BinaryB.getRHS(), Comp); } case MCExpr::Target: { const auto &TargetExprA = cast(A); const auto &TargetExprB = cast(B); return equals(TargetExprA, TargetExprB, Comp); } } llvm_unreachable("Invalid expression kind!"); } bool MCPlusBuilder::equals(const MCTargetExpr &A, const MCTargetExpr &B, CompFuncTy Comp) const { llvm_unreachable("target-specific expressions are unsupported"); } void MCPlusBuilder::setTailCall(MCInst &Inst) { assert(!hasAnnotation(Inst, MCAnnotation::kTailCall)); setAnnotationOpValue(Inst, MCAnnotation::kTailCall, true); } bool MCPlusBuilder::isTailCall(const MCInst &Inst) const { if (hasAnnotation(Inst, MCAnnotation::kTailCall)) return true; if (getConditionalTailCall(Inst)) return true; return false; } Optional MCPlusBuilder::getEHInfo(const MCInst &Inst) const { if (!isCall(Inst)) return NoneType(); Optional LPSym = getAnnotationOpValue(Inst, MCAnnotation::kEHLandingPad); if (!LPSym) return NoneType(); Optional Action = getAnnotationOpValue(Inst, MCAnnotation::kEHAction); if (!Action) return NoneType(); return std::make_pair(reinterpret_cast(*LPSym), static_cast(*Action)); } void MCPlusBuilder::addEHInfo(MCInst &Inst, const MCLandingPad &LP) { if (isCall(Inst)) { assert(!getEHInfo(Inst)); setAnnotationOpValue(Inst, MCAnnotation::kEHLandingPad, reinterpret_cast(LP.first)); setAnnotationOpValue(Inst, MCAnnotation::kEHAction, static_cast(LP.second)); } } int64_t MCPlusBuilder::getGnuArgsSize(const MCInst &Inst) const { Optional Value = getAnnotationOpValue(Inst, MCAnnotation::kGnuArgsSize); if (!Value) return -1LL; return *Value; } void MCPlusBuilder::addGnuArgsSize(MCInst &Inst, int64_t GnuArgsSize, AllocatorIdTy AllocId) { assert(GnuArgsSize >= 0 && "cannot set GNU_args_size to negative value"); assert(getGnuArgsSize(Inst) == -1LL && "GNU_args_size already set"); assert(isInvoke(Inst) && "GNU_args_size can only be set for invoke"); setAnnotationOpValue(Inst, MCAnnotation::kGnuArgsSize, GnuArgsSize, AllocId); } uint64_t MCPlusBuilder::getJumpTable(const MCInst &Inst) const { Optional Value = getAnnotationOpValue(Inst, MCAnnotation::kJumpTable); if (!Value) return 0; return *Value; } uint16_t MCPlusBuilder::getJumpTableIndexReg(const MCInst &Inst) const { return getAnnotationAs(Inst, "JTIndexReg"); } bool MCPlusBuilder::setJumpTable(MCInst &Inst, uint64_t Value, uint16_t IndexReg, AllocatorIdTy AllocId) { if (!isIndirectBranch(Inst)) return false; setAnnotationOpValue(Inst, MCAnnotation::kJumpTable, Value, AllocId); getOrCreateAnnotationAs(Inst, "JTIndexReg", AllocId) = IndexReg; return true; } bool MCPlusBuilder::unsetJumpTable(MCInst &Inst) { if (!getJumpTable(Inst)) return false; removeAnnotation(Inst, MCAnnotation::kJumpTable); removeAnnotation(Inst, "JTIndexReg"); return true; } Optional MCPlusBuilder::getConditionalTailCall(const MCInst &Inst) const { Optional Value = getAnnotationOpValue(Inst, MCAnnotation::kConditionalTailCall); if (!Value) return NoneType(); return static_cast(*Value); } bool MCPlusBuilder::setConditionalTailCall(MCInst &Inst, uint64_t Dest) { if (!isConditionalBranch(Inst)) return false; setAnnotationOpValue(Inst, MCAnnotation::kConditionalTailCall, Dest); return true; } bool MCPlusBuilder::unsetConditionalTailCall(MCInst &Inst) { if (!getConditionalTailCall(Inst)) return false; removeAnnotation(Inst, MCAnnotation::kConditionalTailCall); return true; } Optional MCPlusBuilder::getOffset(const MCInst &Inst) const { Optional Value = getAnnotationOpValue(Inst, MCAnnotation::kOffset); if (!Value) return NoneType(); return static_cast(*Value); } uint32_t MCPlusBuilder::getOffsetWithDefault(const MCInst &Inst, uint32_t Default) const { if (Optional Offset = getOffset(Inst)) return *Offset; return Default; } bool MCPlusBuilder::setOffset(MCInst &Inst, uint32_t Offset, AllocatorIdTy AllocatorId) { setAnnotationOpValue(Inst, MCAnnotation::kOffset, Offset, AllocatorId); return true; } bool MCPlusBuilder::clearOffset(MCInst &Inst) { if (!hasAnnotation(Inst, MCAnnotation::kOffset)) return false; removeAnnotation(Inst, MCAnnotation::kOffset); return true; } bool MCPlusBuilder::hasAnnotation(const MCInst &Inst, unsigned Index) const { const MCInst *AnnotationInst = getAnnotationInst(Inst); if (!AnnotationInst) return false; return (bool)getAnnotationOpValue(Inst, Index); } bool MCPlusBuilder::removeAnnotation(MCInst &Inst, unsigned Index) { MCInst *AnnotationInst = getAnnotationInst(Inst); if (!AnnotationInst) return false; for (int I = AnnotationInst->getNumOperands() - 1; I >= 0; --I) { int64_t ImmValue = AnnotationInst->getOperand(I).getImm(); if (extractAnnotationIndex(ImmValue) == Index) { AnnotationInst->erase(AnnotationInst->begin() + I); return true; } } return false; } void MCPlusBuilder::stripAnnotations(MCInst &Inst, bool KeepTC) { MCInst *AnnotationInst = getAnnotationInst(Inst); if (!AnnotationInst) return; // Preserve TailCall annotation. auto IsTC = hasAnnotation(Inst, MCAnnotation::kTailCall); Inst.erase(std::prev(Inst.end())); if (KeepTC && IsTC) setTailCall(Inst); } void MCPlusBuilder::printAnnotations(const MCInst &Inst, raw_ostream &OS) const { const MCInst *AnnotationInst = getAnnotationInst(Inst); if (!AnnotationInst) return; for (unsigned I = 0; I < AnnotationInst->getNumOperands(); ++I) { const int64_t Imm = AnnotationInst->getOperand(I).getImm(); const unsigned Index = extractAnnotationIndex(Imm); const int64_t Value = extractAnnotationValue(Imm); const auto *Annotation = reinterpret_cast(Value); if (Index >= MCAnnotation::kGeneric) { OS << " # " << AnnotationNames[Index - MCAnnotation::kGeneric] << ": "; Annotation->print(OS); } } } bool MCPlusBuilder::evaluateBranch(const MCInst &Inst, uint64_t Addr, uint64_t Size, uint64_t &Target) const { return Analysis->evaluateBranch(Inst, Addr, Size, Target); } void MCPlusBuilder::getClobberedRegs(const MCInst &Inst, BitVector &Regs) const { if (isPrefix(Inst) || isCFI(Inst)) return; const MCInstrDesc &InstInfo = Info->get(Inst.getOpcode()); const MCPhysReg *ImplicitDefs = InstInfo.getImplicitDefs(); for (unsigned I = 0, E = InstInfo.getNumImplicitDefs(); I != E; ++I) Regs |= getAliases(ImplicitDefs[I], /*OnlySmaller=*/false); for (unsigned I = 0, E = InstInfo.getNumDefs(); I != E; ++I) { const MCOperand &Operand = Inst.getOperand(I); assert(Operand.isReg()); Regs |= getAliases(Operand.getReg(), /*OnlySmaller=*/false); } } void MCPlusBuilder::getTouchedRegs(const MCInst &Inst, BitVector &Regs) const { if (isPrefix(Inst) || isCFI(Inst)) return; const MCInstrDesc &InstInfo = Info->get(Inst.getOpcode()); const MCPhysReg *ImplicitDefs = InstInfo.getImplicitDefs(); for (unsigned I = 0, E = InstInfo.getNumImplicitDefs(); I != E; ++I) Regs |= getAliases(ImplicitDefs[I], /*OnlySmaller=*/false); const MCPhysReg *ImplicitUses = InstInfo.getImplicitUses(); for (unsigned I = 0, E = InstInfo.getNumImplicitUses(); I != E; ++I) Regs |= getAliases(ImplicitUses[I], /*OnlySmaller=*/false); for (unsigned I = 0, E = Inst.getNumOperands(); I != E; ++I) { if (!Inst.getOperand(I).isReg()) continue; Regs |= getAliases(Inst.getOperand(I).getReg(), /*OnlySmaller=*/false); } } void MCPlusBuilder::getWrittenRegs(const MCInst &Inst, BitVector &Regs) const { if (isPrefix(Inst) || isCFI(Inst)) return; const MCInstrDesc &InstInfo = Info->get(Inst.getOpcode()); const MCPhysReg *ImplicitDefs = InstInfo.getImplicitDefs(); for (unsigned I = 0, E = InstInfo.getNumImplicitDefs(); I != E; ++I) Regs |= getAliases(ImplicitDefs[I], /*OnlySmaller=*/true); for (unsigned I = 0, E = InstInfo.getNumDefs(); I != E; ++I) { const MCOperand &Operand = Inst.getOperand(I); assert(Operand.isReg()); Regs |= getAliases(Operand.getReg(), /*OnlySmaller=*/true); } } void MCPlusBuilder::getUsedRegs(const MCInst &Inst, BitVector &Regs) const { if (isPrefix(Inst) || isCFI(Inst)) return; const MCInstrDesc &InstInfo = Info->get(Inst.getOpcode()); const MCPhysReg *ImplicitUses = InstInfo.getImplicitUses(); for (unsigned I = 0, E = InstInfo.getNumImplicitUses(); I != E; ++I) Regs |= getAliases(ImplicitUses[I], /*OnlySmaller=*/true); for (unsigned I = 0, E = Inst.getNumOperands(); I != E; ++I) { if (!Inst.getOperand(I).isReg()) continue; Regs |= getAliases(Inst.getOperand(I).getReg(), /*OnlySmaller=*/true); } } void MCPlusBuilder::getSrcRegs(const MCInst &Inst, BitVector &Regs) const { if (isPrefix(Inst) || isCFI(Inst)) return; if (isCall(Inst)) { BitVector CallRegs = BitVector(Regs.size(), false); getCalleeSavedRegs(CallRegs); CallRegs.flip(); Regs |= CallRegs; return; } if (isReturn(Inst)) { getDefaultLiveOut(Regs); return; } if (isRep(Inst)) getRepRegs(Regs); const MCInstrDesc &InstInfo = Info->get(Inst.getOpcode()); const MCPhysReg *ImplicitUses = InstInfo.getImplicitUses(); for (unsigned I = 0, E = InstInfo.getNumImplicitUses(); I != E; ++I) Regs |= getAliases(ImplicitUses[I], /*OnlySmaller=*/true); for (unsigned I = InstInfo.getNumDefs(), E = InstInfo.getNumOperands(); I != E; ++I) { if (!Inst.getOperand(I).isReg()) continue; Regs |= getAliases(Inst.getOperand(I).getReg(), /*OnlySmaller=*/true); } } bool MCPlusBuilder::hasDefOfPhysReg(const MCInst &MI, unsigned Reg) const { const MCInstrDesc &InstInfo = Info->get(MI.getOpcode()); return InstInfo.hasDefOfPhysReg(MI, Reg, *RegInfo); } bool MCPlusBuilder::hasUseOfPhysReg(const MCInst &MI, unsigned Reg) const { const MCInstrDesc &InstInfo = Info->get(MI.getOpcode()); for (int I = InstInfo.NumDefs; I < InstInfo.NumOperands; ++I) if (MI.getOperand(I).isReg() && RegInfo->isSubRegisterEq(Reg, MI.getOperand(I).getReg())) return true; if (const uint16_t *ImpUses = InstInfo.ImplicitUses) { for (; *ImpUses; ++ImpUses) if (*ImpUses == Reg || RegInfo->isSubRegister(Reg, *ImpUses)) return true; } return false; } const BitVector &MCPlusBuilder::getAliases(MCPhysReg Reg, bool OnlySmaller) const { // AliasMap caches a mapping of registers to the set of registers that // alias (are sub or superregs of itself, including itself). static std::vector AliasMap; static std::vector SuperReg; if (AliasMap.size() > 0) { if (OnlySmaller) return AliasMap[Reg]; return AliasMap[SuperReg[Reg]]; } // Build alias map for (MCPhysReg I = 0, E = RegInfo->getNumRegs(); I != E; ++I) { BitVector BV(RegInfo->getNumRegs(), false); BV.set(I); AliasMap.emplace_back(std::move(BV)); SuperReg.emplace_back(I); } std::queue Worklist; // Propagate alias info upwards. Skip reg 0 (mapped to NoRegister) for (MCPhysReg I = 1, E = RegInfo->getNumRegs(); I < E; ++I) Worklist.push(I); while (!Worklist.empty()) { MCPhysReg I = Worklist.front(); Worklist.pop(); for (MCSubRegIterator SI(I, RegInfo); SI.isValid(); ++SI) AliasMap[I] |= AliasMap[*SI]; for (MCSuperRegIterator SI(I, RegInfo); SI.isValid(); ++SI) Worklist.push(*SI); } // Propagate parent reg downwards for (MCPhysReg I = 1, E = RegInfo->getNumRegs(); I < E; ++I) Worklist.push(I); while (!Worklist.empty()) { MCPhysReg I = Worklist.front(); Worklist.pop(); for (MCSubRegIterator SI(I, RegInfo); SI.isValid(); ++SI) { SuperReg[*SI] = SuperReg[I]; Worklist.push(*SI); } } LLVM_DEBUG({ dbgs() << "Dumping reg alias table:\n"; for (MCPhysReg I = 0, E = RegInfo->getNumRegs(); I != E; ++I) { dbgs() << "Reg " << I << ": "; const BitVector &BV = AliasMap[SuperReg[I]]; int Idx = BV.find_first(); while (Idx != -1) { dbgs() << Idx << " "; Idx = BV.find_next(Idx); } dbgs() << "\n"; } }); if (OnlySmaller) return AliasMap[Reg]; return AliasMap[SuperReg[Reg]]; } uint8_t MCPlusBuilder::getRegSize(MCPhysReg Reg) const { // SizeMap caches a mapping of registers to their sizes static std::vector SizeMap; if (SizeMap.size() > 0) { return SizeMap[Reg]; } SizeMap = std::vector(RegInfo->getNumRegs()); // Build size map for (auto I = RegInfo->regclass_begin(), E = RegInfo->regclass_end(); I != E; ++I) { for (MCPhysReg Reg : *I) SizeMap[Reg] = I->getSizeInBits() / 8; } return SizeMap[Reg]; } bool MCPlusBuilder::setOperandToSymbolRef(MCInst &Inst, int OpNum, const MCSymbol *Symbol, int64_t Addend, MCContext *Ctx, uint64_t RelType) const { MCOperand Operand; if (!Addend) { Operand = MCOperand::createExpr(getTargetExprFor( Inst, MCSymbolRefExpr::create(Symbol, *Ctx), *Ctx, RelType)); } else { Operand = MCOperand::createExpr(getTargetExprFor( Inst, MCBinaryExpr::createAdd(MCSymbolRefExpr::create(Symbol, *Ctx), MCConstantExpr::create(Addend, *Ctx), *Ctx), *Ctx, RelType)); } Inst.getOperand(OpNum) = Operand; return true; }