brintos

brintos / llvm-project-archived public Read only

0
0
Text · 28.2 KiB · 7c4a878 Raw
872 lines · cpp
1//===- bolt/Target/RISCV/RISCVMCPlusBuilder.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-exception6//7//===----------------------------------------------------------------------===//8//9// This file provides RISCV-specific MCPlus builder.10//11//===----------------------------------------------------------------------===//12 13#include "MCTargetDesc/RISCVMCAsmInfo.h"14#include "MCTargetDesc/RISCVMCTargetDesc.h"15#include "bolt/Core/MCPlusBuilder.h"16#include "llvm/BinaryFormat/ELF.h"17#include "llvm/MC/MCContext.h"18#include "llvm/MC/MCInst.h"19#include "llvm/MC/MCInstBuilder.h"20#include "llvm/MC/MCSubtargetInfo.h"21#include "llvm/Support/ErrorHandling.h"22 23#define DEBUG_TYPE "mcplus"24 25using namespace llvm;26using namespace bolt;27 28namespace {29 30class RISCVMCPlusBuilder : public MCPlusBuilder {31public:32  using MCPlusBuilder::MCPlusBuilder;33 34  bool equals(const MCSpecifierExpr &A, const MCSpecifierExpr &B,35              CompFuncTy Comp) const override {36    const auto &RISCVExprA = cast<MCSpecifierExpr>(A);37    const auto &RISCVExprB = cast<MCSpecifierExpr>(B);38    if (RISCVExprA.getSpecifier() != RISCVExprB.getSpecifier())39      return false;40 41    return MCPlusBuilder::equals(*RISCVExprA.getSubExpr(),42                                 *RISCVExprB.getSubExpr(), Comp);43  }44 45  void getCalleeSavedRegs(BitVector &Regs) const override {46    Regs |= getAliases(RISCV::X2);47    Regs |= getAliases(RISCV::X8);48    Regs |= getAliases(RISCV::X9);49    Regs |= getAliases(RISCV::X18);50    Regs |= getAliases(RISCV::X19);51    Regs |= getAliases(RISCV::X20);52    Regs |= getAliases(RISCV::X21);53    Regs |= getAliases(RISCV::X22);54    Regs |= getAliases(RISCV::X23);55    Regs |= getAliases(RISCV::X24);56    Regs |= getAliases(RISCV::X25);57    Regs |= getAliases(RISCV::X26);58    Regs |= getAliases(RISCV::X27);59  }60 61  bool shouldRecordCodeRelocation(uint32_t RelType) const override {62    switch (RelType) {63    case ELF::R_RISCV_JAL:64    case ELF::R_RISCV_CALL:65    case ELF::R_RISCV_CALL_PLT:66    case ELF::R_RISCV_BRANCH:67    case ELF::R_RISCV_RVC_BRANCH:68    case ELF::R_RISCV_RVC_JUMP:69    case ELF::R_RISCV_GOT_HI20:70    case ELF::R_RISCV_PCREL_HI20:71    case ELF::R_RISCV_PCREL_LO12_I:72    case ELF::R_RISCV_PCREL_LO12_S:73    case ELF::R_RISCV_HI20:74    case ELF::R_RISCV_LO12_I:75    case ELF::R_RISCV_LO12_S:76    case ELF::R_RISCV_TLS_GOT_HI20:77    case ELF::R_RISCV_TLS_GD_HI20:78      return true;79    default:80      llvm_unreachable("Unexpected RISCV relocation type in code");81    }82  }83 84  bool isNop(const MCInst &Inst) const {85    return Inst.getOpcode() == RISCV::ADDI &&86           Inst.getOperand(0).getReg() == RISCV::X0 &&87           Inst.getOperand(1).getReg() == RISCV::X0 &&88           Inst.getOperand(2).getImm() == 0;89  }90 91  bool isCNop(const MCInst &Inst) const {92    return Inst.getOpcode() == RISCV::C_NOP;93  }94 95  bool isNoop(const MCInst &Inst) const override {96    return isNop(Inst) || isCNop(Inst);97  }98 99  bool isPseudo(const MCInst &Inst) const override {100    switch (Inst.getOpcode()) {101    default:102      return MCPlusBuilder::isPseudo(Inst);103    case RISCV::PseudoCALL:104    case RISCV::PseudoTAIL:105      return false;106    }107  }108 109  bool isIndirectCall(const MCInst &Inst) const override {110    if (!isCall(Inst))111      return false;112 113    switch (Inst.getOpcode()) {114    default:115      return false;116    case RISCV::JALR:117    case RISCV::C_JALR:118    case RISCV::C_JR:119      return true;120    }121  }122 123  bool hasPCRelOperand(const MCInst &Inst) const override {124    switch (Inst.getOpcode()) {125    default:126      return false;127    case RISCV::JAL:128    case RISCV::AUIPC:129      return true;130    }131  }132 133  unsigned getInvertedBranchOpcode(unsigned Opcode) const {134    switch (Opcode) {135    default:136      llvm_unreachable("Failed to invert branch opcode");137      return Opcode;138    case RISCV::BEQ:139      return RISCV::BNE;140    case RISCV::BNE:141      return RISCV::BEQ;142    case RISCV::BLT:143      return RISCV::BGE;144    case RISCV::BGE:145      return RISCV::BLT;146    case RISCV::BLTU:147      return RISCV::BGEU;148    case RISCV::BGEU:149      return RISCV::BLTU;150    case RISCV::C_BEQZ:151      return RISCV::C_BNEZ;152    case RISCV::C_BNEZ:153      return RISCV::C_BEQZ;154    }155  }156 157  void reverseBranchCondition(MCInst &Inst, const MCSymbol *TBB,158                              MCContext *Ctx) const override {159    auto Opcode = getInvertedBranchOpcode(Inst.getOpcode());160    Inst.setOpcode(Opcode);161    replaceBranchTarget(Inst, TBB, Ctx);162  }163 164  void replaceBranchTarget(MCInst &Inst, const MCSymbol *TBB,165                           MCContext *Ctx) const override {166    assert((isCall(Inst) || isBranch(Inst)) && !isIndirectBranch(Inst) &&167           "Invalid instruction");168 169    unsigned SymOpIndex;170    auto Result = getSymbolRefOperandNum(Inst, SymOpIndex);171    (void)Result;172    assert(Result && "unimplemented branch");173 174    Inst.getOperand(SymOpIndex) =175        MCOperand::createExpr(MCSymbolRefExpr::create(TBB, *Ctx));176  }177 178  IndirectBranchType analyzeIndirectBranch(179      MCInst &Instruction, InstructionIterator Begin, InstructionIterator End,180      const unsigned PtrSize, MCInst *&MemLocInstr, unsigned &BaseRegNum,181      unsigned &IndexRegNum, int64_t &DispValue, const MCExpr *&DispExpr,182      MCInst *&PCRelBaseOut, MCInst *&FixedEntryLoadInst) const override {183    MemLocInstr = nullptr;184    BaseRegNum = 0;185    IndexRegNum = 0;186    DispValue = 0;187    DispExpr = nullptr;188    PCRelBaseOut = nullptr;189    FixedEntryLoadInst = nullptr;190 191    // Check for the following long tail call sequence:192    // 1: auipc xi, %pcrel_hi(sym)193    // jalr zero, %pcrel_lo(1b)(xi)194    if (Instruction.getOpcode() == RISCV::JALR && Begin != End) {195      MCInst &PrevInst = *std::prev(End);196      if (isRISCVCall(PrevInst, Instruction) &&197          Instruction.getOperand(0).getReg() == RISCV::X0)198        return IndirectBranchType::POSSIBLE_TAIL_CALL;199    }200 201    return IndirectBranchType::UNKNOWN;202  }203 204  bool convertJmpToTailCall(MCInst &Inst) override {205    if (isTailCall(Inst))206      return false;207 208    switch (Inst.getOpcode()) {209    default:210      llvm_unreachable("unsupported tail call opcode");211    case RISCV::JAL:212    case RISCV::JALR:213    case RISCV::C_J:214    case RISCV::C_JR:215      break;216    }217 218    setTailCall(Inst);219    return true;220  }221 222  void createReturn(MCInst &Inst) const override {223    // TODO "c.jr ra" when RVC is enabled224    Inst.setOpcode(RISCV::JALR);225    Inst.clear();226    Inst.addOperand(MCOperand::createReg(RISCV::X0));227    Inst.addOperand(MCOperand::createReg(RISCV::X1));228    Inst.addOperand(MCOperand::createImm(0));229  }230 231  void createUncondBranch(MCInst &Inst, const MCSymbol *TBB,232                          MCContext *Ctx) const override {233    Inst.setOpcode(RISCV::JAL);234    Inst.clear();235    Inst.addOperand(MCOperand::createReg(RISCV::X0));236    Inst.addOperand(MCOperand::createExpr(MCSymbolRefExpr::create(TBB, *Ctx)));237  }238 239  StringRef getTrapFillValue() const override {240    return StringRef("\0\0\0\0", 4);241  }242 243  void createCall(unsigned Opcode, MCInst &Inst, const MCSymbol *Target,244                  MCContext *Ctx) {245    Inst.setOpcode(Opcode);246    Inst.clear();247    Inst.addOperand(MCOperand::createExpr(MCSpecifierExpr::create(248        MCSymbolRefExpr::create(Target, *Ctx), ELF::R_RISCV_CALL_PLT, *Ctx)));249  }250 251  void createCall(MCInst &Inst, const MCSymbol *Target,252                  MCContext *Ctx) override {253    return createCall(RISCV::PseudoCALL, Inst, Target, Ctx);254  }255 256  void createLongTailCall(InstructionListType &Seq, const MCSymbol *Target,257                          MCContext *Ctx) override {258    createShortJmp(Seq, Target, Ctx, /*IsTailCall*/ true);259  }260 261  void createTailCall(MCInst &Inst, const MCSymbol *Target,262                      MCContext *Ctx) override {263    return createCall(RISCV::PseudoTAIL, Inst, Target, Ctx);264  }265 266  bool analyzeBranch(InstructionIterator Begin, InstructionIterator End,267                     const MCSymbol *&TBB, const MCSymbol *&FBB,268                     MCInst *&CondBranch,269                     MCInst *&UncondBranch) const override {270    auto I = End;271 272    while (I != Begin) {273      --I;274 275      // Ignore nops and CFIs276      if (isPseudo(*I) || isNoop(*I))277        continue;278 279      // Stop when we find the first non-terminator280      if (!isTerminator(*I) || isTailCall(*I) || !isBranch(*I))281        break;282 283      // Handle unconditional branches.284      if (isUnconditionalBranch(*I)) {285        // If any code was seen after this unconditional branch, we've seen286        // unreachable code. Ignore them.287        CondBranch = nullptr;288        UncondBranch = &*I;289        const MCSymbol *Sym = getTargetSymbol(*I);290        assert(Sym != nullptr &&291               "Couldn't extract BB symbol from jump operand");292        TBB = Sym;293        continue;294      }295 296      // Handle conditional branches and ignore indirect branches297      if (isIndirectBranch(*I))298        return false;299 300      if (CondBranch == nullptr) {301        const MCSymbol *TargetBB = getTargetSymbol(*I);302        if (TargetBB == nullptr) {303          // Unrecognized branch target304          return false;305        }306        FBB = TBB;307        TBB = TargetBB;308        CondBranch = &*I;309        continue;310      }311 312      llvm_unreachable("multiple conditional branches in one BB");313    }314 315    return true;316  }317 318  bool getSymbolRefOperandNum(const MCInst &Inst, unsigned &OpNum) const {319    switch (Inst.getOpcode()) {320    default:321      return false;322    case RISCV::C_J:323      OpNum = 0;324      return true;325    case RISCV::AUIPC:326    case RISCV::JAL:327    case RISCV::C_BEQZ:328    case RISCV::C_BNEZ:329      OpNum = 1;330      return true;331    case RISCV::BEQ:332    case RISCV::BGE:333    case RISCV::BGEU:334    case RISCV::BNE:335    case RISCV::BLT:336    case RISCV::BLTU:337      OpNum = 2;338      return true;339    }340  }341 342  const MCSymbol *getTargetSymbol(const MCExpr *Expr) const override {343    auto *RISCVExpr = dyn_cast<MCSpecifierExpr>(Expr);344    if (RISCVExpr && RISCVExpr->getSubExpr())345      return getTargetSymbol(RISCVExpr->getSubExpr());346 347    return MCPlusBuilder::getTargetSymbol(Expr);348  }349 350  const MCSymbol *getTargetSymbol(const MCInst &Inst,351                                  unsigned OpNum = 0) const override {352    if (!OpNum && !getSymbolRefOperandNum(Inst, OpNum))353      return nullptr;354 355    const MCOperand &Op = Inst.getOperand(OpNum);356    if (!Op.isExpr())357      return nullptr;358 359    return getTargetSymbol(Op.getExpr());360  }361 362  bool lowerTailCall(MCInst &Inst) override {363    removeAnnotation(Inst, MCPlus::MCAnnotation::kTailCall);364    if (getConditionalTailCall(Inst))365      unsetConditionalTailCall(Inst);366    return true;367  }368 369  uint64_t analyzePLTEntry(MCInst &Instruction, InstructionIterator Begin,370                           InstructionIterator End,371                           uint64_t BeginPC) const override {372    auto I = Begin;373 374    assert(I != End);375    auto &AUIPC = *I++;376    assert(AUIPC.getOpcode() == RISCV::AUIPC);377    assert(AUIPC.getOperand(0).getReg() == RISCV::X28);378 379    assert(I != End);380    auto &LD = *I++;381    assert(LD.getOpcode() == RISCV::LD);382    assert(LD.getOperand(0).getReg() == RISCV::X28);383    assert(LD.getOperand(1).getReg() == RISCV::X28);384 385    assert(I != End);386    auto &JALR = *I++;387    (void)JALR;388    assert(JALR.getOpcode() == RISCV::JALR);389    assert(JALR.getOperand(0).getReg() == RISCV::X6);390    assert(JALR.getOperand(1).getReg() == RISCV::X28);391 392    assert(I != End);393    auto &NOP = *I++;394    (void)NOP;395    assert(isNoop(NOP));396 397    assert(I == End);398 399    auto AUIPCOffset = AUIPC.getOperand(1).getImm() << 12;400    auto LDOffset = LD.getOperand(2).getImm();401    return BeginPC + AUIPCOffset + LDOffset;402  }403 404  bool replaceImmWithSymbolRef(MCInst &Inst, const MCSymbol *Symbol,405                               int64_t Addend, MCContext *Ctx, int64_t &Value,406                               uint32_t RelType) const override {407    unsigned ImmOpNo = -1U;408 409    for (unsigned Index = 0; Index < MCPlus::getNumPrimeOperands(Inst);410         ++Index) {411      if (Inst.getOperand(Index).isImm()) {412        ImmOpNo = Index;413        break;414      }415    }416 417    if (ImmOpNo == -1U)418      return false;419 420    Value = Inst.getOperand(ImmOpNo).getImm();421    setOperandToSymbolRef(Inst, ImmOpNo, Symbol, Addend, Ctx, RelType);422    return true;423  }424 425  const MCExpr *getTargetExprFor(MCInst &Inst, const MCExpr *Expr,426                                 MCContext &Ctx,427                                 uint32_t RelType) const override {428    switch (RelType) {429    default:430      return Expr;431    case ELF::R_RISCV_GOT_HI20:432    case ELF::R_RISCV_TLS_GOT_HI20:433    case ELF::R_RISCV_TLS_GD_HI20:434      // The GOT is reused so no need to create GOT relocations435    case ELF::R_RISCV_PCREL_HI20:436      return MCSpecifierExpr::create(Expr, ELF::R_RISCV_PCREL_HI20, Ctx);437    case ELF::R_RISCV_PCREL_LO12_I:438    case ELF::R_RISCV_PCREL_LO12_S:439      return MCSpecifierExpr::create(Expr, RISCV::S_PCREL_LO, Ctx);440    case ELF::R_RISCV_HI20:441      return MCSpecifierExpr::create(Expr, ELF::R_RISCV_HI20, Ctx);442    case ELF::R_RISCV_LO12_I:443    case ELF::R_RISCV_LO12_S:444      return MCSpecifierExpr::create(Expr, RISCV::S_LO, Ctx);445    case ELF::R_RISCV_CALL:446      return MCSpecifierExpr::create(Expr, ELF::R_RISCV_CALL_PLT, Ctx);447    case ELF::R_RISCV_CALL_PLT:448      return MCSpecifierExpr::create(Expr, ELF::R_RISCV_CALL_PLT, Ctx);449    }450  }451 452  bool evaluateMemOperandTarget(const MCInst &Inst, uint64_t &Target,453                                uint64_t Address,454                                uint64_t Size) const override {455    return false;456  }457 458  bool isCallAuipc(const MCInst &Inst) const {459    if (Inst.getOpcode() != RISCV::AUIPC)460      return false;461 462    const auto &ImmOp = Inst.getOperand(1);463    if (!ImmOp.isExpr())464      return false;465 466    const auto *ImmExpr = ImmOp.getExpr();467    if (!isa<MCSpecifierExpr>(ImmExpr))468      return false;469 470    switch (cast<MCSpecifierExpr>(ImmExpr)->getSpecifier()) {471    default:472      return false;473    case ELF::R_RISCV_CALL_PLT:474      return true;475    }476  }477 478  bool isRISCVCall(const MCInst &First, const MCInst &Second) const override {479    if (!isCallAuipc(First))480      return false;481 482    assert(Second.getOpcode() == RISCV::JALR);483    return true;484  }485 486  uint16_t getMinFunctionAlignment() const override {487    if (STI->hasFeature(RISCV::FeatureStdExtC) ||488        STI->hasFeature(RISCV::FeatureStdExtZca))489      return 2;490    return 4;491  }492 493  void createStackPointerIncrement(494      MCInst &Inst, int imm,495      bool NoFlagsClobber = false /*unused for RISCV*/) const override {496    Inst = MCInstBuilder(RISCV::ADDI)497               .addReg(RISCV::X2)498               .addReg(RISCV::X2)499               .addImm(-imm);500  }501 502  void createStackPointerDecrement(503      MCInst &Inst, int imm,504      bool NoFlagsClobber = false /*unused for RISCV*/) const override {505    Inst = MCInstBuilder(RISCV::ADDI)506               .addReg(RISCV::X2)507               .addReg(RISCV::X2)508               .addImm(imm);509  }510 511  void loadReg(MCInst &Inst, MCPhysReg To, MCPhysReg From,512               int64_t offset) const {513    Inst = MCInstBuilder(RISCV::LD).addReg(To).addReg(From).addImm(offset);514  }515 516  void storeReg(MCInst &Inst, MCPhysReg From, MCPhysReg To,517                int64_t offset) const {518    Inst = MCInstBuilder(RISCV::SD).addReg(From).addReg(To).addImm(offset);519  }520 521  void spillRegs(InstructionListType &Insts,522                 const SmallVector<unsigned> &Regs) const {523    Insts.emplace_back();524    createStackPointerIncrement(Insts.back(), Regs.size() * 8);525 526    int64_t Offset = 0;527    for (auto Reg : Regs) {528      Insts.emplace_back();529      storeReg(Insts.back(), Reg, RISCV::X2, Offset);530      Offset += 8;531    }532  }533 534  void reloadRegs(InstructionListType &Insts,535                  const SmallVector<unsigned> &Regs) const {536    int64_t Offset = 0;537    for (auto Reg : Regs) {538      Insts.emplace_back();539      loadReg(Insts.back(), Reg, RISCV::X2, Offset);540      Offset += 8;541    }542 543    Insts.emplace_back();544    createStackPointerDecrement(Insts.back(), Regs.size() * 8);545  }546 547  void atomicAdd(MCInst &Inst, MCPhysReg RegAtomic, MCPhysReg RegTo,548                 MCPhysReg RegCnt) const {549    Inst = MCInstBuilder(RISCV::AMOADD_D)550               .addReg(RegAtomic)551               .addReg(RegTo)552               .addReg(RegCnt);553  }554 555  InstructionListType createRegCmpJE(MCPhysReg RegNo, MCPhysReg RegTmp,556                                     const MCSymbol *Target,557                                     MCContext *Ctx) const {558    InstructionListType Insts;559    Insts.emplace_back(560        MCInstBuilder(RISCV::SUB).addReg(RegTmp).addReg(RegNo).addReg(RegNo));561    Insts.emplace_back(MCInstBuilder(RISCV::BEQ)562                           .addReg(RegNo)563                           .addReg(RegTmp)564                           .addExpr(MCSymbolRefExpr::create(Target, *Ctx)));565    return Insts;566  }567 568  void createTrap(MCInst &Inst) const override {569    Inst.clear();570    Inst.setOpcode(RISCV::EBREAK);571  }572 573  void createShortJmp(InstructionListType &Seq, const MCSymbol *Target,574                      MCContext *Ctx, bool IsTailCall) override {575    // The sequence of instructions we create here is the following:576    //  auipc   a5, hi20(Target)577    //  addi    a5, a5, low12(Target)578    //  jr x5 => jalr x0, x5, 0579    MCPhysReg Reg = RISCV::X5;580    InstructionListType Insts = materializeAddress(Target, Ctx, Reg);581    Insts.emplace_back();582    MCInst &Inst = Insts.back();583    Inst.clear();584    Inst = MCInstBuilder(RISCV::JALR).addReg(RISCV::X0).addReg(Reg).addImm(0);585    if (IsTailCall)586      setTailCall(Inst);587    Seq.swap(Insts);588  }589 590  InstructionListType createGetter(MCContext *Ctx, const char *name) const {591    InstructionListType Insts(4);592    MCSymbol *Locs = Ctx->getOrCreateSymbol(name);593    InstructionListType Addr = materializeAddress(Locs, Ctx, RISCV::X10);594    std::copy(Addr.begin(), Addr.end(), Insts.begin());595    loadReg(Insts[2], RISCV::X10, RISCV::X10, 0);596    createReturn(Insts[3]);597    return Insts;598  }599 600  InstructionListType createIncMemory(MCPhysReg RegTo, MCPhysReg RegCnt,601                                      MCPhysReg RegAtomic) const {602    InstructionListType Insts;603    Insts.emplace_back();604    Insts.back() =605        MCInstBuilder(RISCV::ADDI).addReg(RegCnt).addReg(RegAtomic).addImm(1);606    Insts.emplace_back();607    atomicAdd(Insts.back(), RegAtomic, RegTo, RegCnt);608    return Insts;609  }610 611  InstructionListType materializeAddress(const MCSymbol *Target, MCContext *Ctx,612                                         MCPhysReg RegName,613                                         int64_t Addend = 0) const override {614    // Get the symbol address by auipc + addi615    InstructionListType Insts(2);616    MCSymbol *AuipcLabel = Ctx->createNamedTempSymbol("pcrel_hi");617    Insts[0] = MCInstBuilder(RISCV::AUIPC).addReg(RegName).addImm(0);618    setOperandToSymbolRef(Insts[0], /* OpNum */ 1, Target, Addend, Ctx,619                          ELF::R_RISCV_PCREL_HI20);620    setInstLabel(Insts[0], AuipcLabel);621 622    Insts[1] =623        MCInstBuilder(RISCV::ADDI).addReg(RegName).addReg(RegName).addImm(0);624    setOperandToSymbolRef(Insts[1], /* OpNum */ 2, AuipcLabel, Addend, Ctx,625                          ELF::R_RISCV_PCREL_LO12_I);626    return Insts;627  }628 629  InstructionListType createInstrIncMemory(const MCSymbol *Target,630                                           MCContext *Ctx, bool IsLeaf,631                                           unsigned CodePointerSize) override {632    // We need 2 scratch registers: one for the target address (x10), and one633    // for the increment value (x11).634    // addi sp, sp, -16635    // sd x10, 0(sp)636    // sd x11, 8(sp)637    // la x10, target         # 1: auipc x10, %pcrel_hi(target)638    //                        # addi x10, x10, %pcrel_lo(1b)639    // li x11, 1              # addi x11, zero, 1640    // amoadd.d zero, x10, x11641    // ld x10, 0(sp)642    // ld x11, 8(sp)643    // addi sp, sp, 16644 645    InstructionListType Insts;646    spillRegs(Insts, {RISCV::X10, RISCV::X11});647    InstructionListType Addr = materializeAddress(Target, Ctx, RISCV::X10);648    Insts.insert(Insts.end(), Addr.begin(), Addr.end());649    InstructionListType IncInsts =650        createIncMemory(RISCV::X10, RISCV::X11, RISCV::X0);651    Insts.insert(Insts.end(), IncInsts.begin(), IncInsts.end());652    reloadRegs(Insts, {RISCV::X10, RISCV::X11});653    return Insts;654  }655 656  void createDirectCall(MCInst &Inst, const MCSymbol *Target, MCContext *Ctx,657                        bool IsTailCall) override {658    Inst.setOpcode(RISCV::JAL);659    Inst.clear();660    if (IsTailCall) {661      Inst.addOperand(MCOperand::createReg(RISCV::X0));662      Inst.addOperand(MCOperand::createExpr(getTargetExprFor(663          Inst, MCSymbolRefExpr::create(Target, *Ctx), *Ctx, 0)));664      convertJmpToTailCall(Inst);665    } else {666      Inst.addOperand(MCOperand::createReg(RISCV::X1));667      Inst.addOperand(MCOperand::createExpr(getTargetExprFor(668          Inst, MCSymbolRefExpr::create(Target, *Ctx), *Ctx, 0)));669    }670  }671 672  void createIndirectCallInst(MCInst &Inst, bool IsTailCall, MCPhysReg Reg,673                              int64_t Disp) const {674    Inst.clear();675    Inst.setOpcode(RISCV::JALR);676    Inst.clear();677    if (IsTailCall) {678      Inst.addOperand(MCOperand::createReg(RISCV::X0));679      Inst.addOperand(MCOperand::createReg(Reg));680      Inst.addOperand(MCOperand::createImm(Disp));681    } else {682      Inst.addOperand(MCOperand::createReg(RISCV::X1));683      Inst.addOperand(MCOperand::createReg(Reg));684      Inst.addOperand(MCOperand::createImm(Disp));685    }686  }687 688  InstructionListType689  createInstrumentedIndCallHandlerEntryBB(const MCSymbol *InstrTrampoline,690                                          const MCSymbol *IndCallHandler,691                                          MCContext *Ctx) override {692    // Code sequence used to check whether InstrTampoline was initialized693    // and call it if so, returns via IndCallHandler694    //   sp      -16(sp)695    //   sd      x10, 0(sp)696    //   sd      x11, 0(sp)697    //   la      x10, InstrTrampoline -> auipc + addi698    //   ld      x10, [x10]699    //   beq     x10, x11, IndCallHandler700    //   sp      -16(sp)701    //   sd      x1, 0(sp)702    //   jalr    x1,x10,0703    //   ld      x1, [sp], #16704    //   sp      16(sp)705    //   jal     x0, IndCallHandler706 707    InstructionListType Insts;708    spillRegs(Insts, {RISCV::X10, RISCV::X11});709    InstructionListType Addr =710        materializeAddress(InstrTrampoline, Ctx, RISCV::X10);711    Insts.insert(Insts.end(), Addr.begin(), Addr.end());712    Insts.emplace_back();713    loadReg(Insts.back(), RISCV::X10, RISCV::X10, 0);714    InstructionListType cmpJmp =715        createRegCmpJE(RISCV::X10, RISCV::X11, IndCallHandler, Ctx);716    Insts.insert(Insts.end(), cmpJmp.begin(), cmpJmp.end());717    Insts.emplace_back();718    createStackPointerIncrement(Insts.back(), 16);719    Insts.emplace_back();720    storeReg(Insts.back(), RISCV::X1, RISCV::X2, 0);721    Insts.emplace_back();722    createIndirectCallInst(Insts.back(), /*IsTailCall*/ false, RISCV::X10, 0);723    Insts.emplace_back();724    loadReg(Insts.back(), RISCV::X1, RISCV::X2, 0);725    Insts.emplace_back();726    createStackPointerDecrement(Insts.back(), 16);727    Insts.emplace_back();728    createDirectCall(Insts.back(), IndCallHandler, Ctx, /*IsTailCall*/ true);729    return Insts;730  }731 732  InstructionListType createInstrumentedIndCallHandlerExitBB() const override {733    InstructionListType Insts;734    reloadRegs(Insts, {RISCV::X10, RISCV::X11});735    Insts.emplace_back();736    loadReg(Insts.back(), RISCV::X5, RISCV::X2, 0);737    Insts.emplace_back();738    createStackPointerDecrement(Insts.back(), 16);739    reloadRegs(Insts, {RISCV::X10, RISCV::X11});740    Insts.emplace_back();741    createIndirectCallInst(Insts.back(), /*IsTailCall*/ true, RISCV::X5, 0);742    return Insts;743  }744 745  InstructionListType746  createInstrumentedIndTailCallHandlerExitBB() const override {747    return createInstrumentedIndCallHandlerExitBB();748  }749 750  std::vector<MCInst> createSymbolTrampoline(const MCSymbol *TgtSym,751                                             MCContext *Ctx) override {752    std::vector<MCInst> Insts;753    createShortJmp(Insts, TgtSym, Ctx, /*IsTailCall*/ true);754    return Insts;755  }756 757  InstructionListType createNumCountersGetter(MCContext *Ctx) const override {758    return createGetter(Ctx, "__bolt_num_counters");759  }760 761  InstructionListType762  createInstrLocationsGetter(MCContext *Ctx) const override {763    return createGetter(Ctx, "__bolt_instr_locations");764  }765 766  InstructionListType createInstrTablesGetter(MCContext *Ctx) const override {767    return createGetter(Ctx, "__bolt_instr_tables");768  }769 770  InstructionListType createInstrNumFuncsGetter(MCContext *Ctx) const override {771    return createGetter(Ctx, "__bolt_instr_num_funcs");772  }773 774  void convertIndirectCallToLoad(MCInst &Inst, MCPhysReg Reg) override {775    bool IsTailCall = isTailCall(Inst);776    if (IsTailCall)777      removeAnnotation(Inst, MCPlus::MCAnnotation::kTailCall);778    Inst.setOpcode(RISCV::ADD);779    Inst.insert(Inst.begin(), MCOperand::createReg(Reg));780    Inst.insert(Inst.begin() + 1, MCOperand::createReg(RISCV::X0));781  }782 783  InstructionListType createLoadImmediate(const MCPhysReg Dest,784                                          uint64_t Imm) const override {785    InstructionListType Insts;786    // get IMM higher 32bit787    Insts.emplace_back(788        MCInstBuilder(RISCV::LUI).addReg(Dest).addImm((Imm >> 44) & 0xFFFFF));789    Insts.emplace_back(MCInstBuilder(RISCV::LUI)790                           .addReg(RISCV::X5)791                           .addImm((Imm >> 32) & 0xFFF));792    Insts.emplace_back(MCInstBuilder(RISCV::SRLI)793                           .addReg(RISCV::X5)794                           .addReg(RISCV::X5)795                           .addImm(12));796    Insts.emplace_back(797        MCInstBuilder(RISCV::OR).addReg(Dest).addReg(Dest).addReg(RISCV::X5));798    Insts.emplace_back(799        MCInstBuilder(RISCV::SLLI).addReg(Dest).addReg(Dest).addImm(32));800 801    // get IMM lower 32bit802    Insts.emplace_back(MCInstBuilder(RISCV::LUI)803                           .addReg(RISCV::X5)804                           .addImm((Imm >> 12) & 0xFFFFF));805    Insts.emplace_back(806        MCInstBuilder(RISCV::LUI).addReg(RISCV::X6).addImm((Imm)&0xFFF));807    Insts.emplace_back(MCInstBuilder(RISCV::SRLI)808                           .addReg(RISCV::X6)809                           .addReg(RISCV::X6)810                           .addImm(12));811    Insts.emplace_back(812        MCInstBuilder(RISCV::OR).addReg(RISCV::X5).addReg(RISCV::X5).addReg(813            RISCV::X6));814 815    // get 64bit IMM816    Insts.emplace_back(817        MCInstBuilder(RISCV::OR).addReg(Dest).addReg(Dest).addReg(RISCV::X5));818    return Insts;819  }820 821  InstructionListType createInstrumentedIndirectCall(MCInst &&CallInst,822                                                     MCSymbol *HandlerFuncAddr,823                                                     int CallSiteID,824                                                     MCContext *Ctx) override {825    // Code sequence used to enter indirect call instrumentation helper:826    //   addi  sp, sp, -0x10827    //   sd  a0, 0x0(sp)828    //   sd  a1, 0x8(sp)829    //   mov target x0  convertIndirectCallToLoad -> add a0, zero, target830    //   mov x1 CallSiteID createLoadImmediate831    //   addi  sp, sp, -0x10832    //   sd  a0, 0x0(sp)833    //   sd  a1, 0x8(sp)834    //   la x0 *HandlerFuncAddr -> auipc + addi835    //   jalr x0836 837    InstructionListType Insts;838    spillRegs(Insts, {RISCV::X10, RISCV::X11});839    Insts.emplace_back(CallInst);840    convertIndirectCallToLoad(Insts.back(), RISCV::X10);841    InstructionListType LoadImm = createLoadImmediate(RISCV::X11, CallSiteID);842    Insts.insert(Insts.end(), LoadImm.begin(), LoadImm.end());843    spillRegs(Insts, {RISCV::X10, RISCV::X11});844    InstructionListType Addr =845        materializeAddress(HandlerFuncAddr, Ctx, RISCV::X5);846    Insts.insert(Insts.end(), Addr.begin(), Addr.end());847    Insts.emplace_back();848    createIndirectCallInst(Insts.back(), isTailCall(CallInst), RISCV::X5, 0);849 850    // // Carry over metadata including tail call marker if present.851    stripAnnotations(Insts.back());852    moveAnnotations(std::move(CallInst), Insts.back());853 854    return Insts;855  }856};857 858} // end anonymous namespace859 860namespace llvm {861namespace bolt {862 863MCPlusBuilder *createRISCVMCPlusBuilder(const MCInstrAnalysis *Analysis,864                                        const MCInstrInfo *Info,865                                        const MCRegisterInfo *RegInfo,866                                        const MCSubtargetInfo *STI) {867  return new RISCVMCPlusBuilder(Analysis, Info, RegInfo, STI);868}869 870} // namespace bolt871} // namespace llvm872