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