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-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This file provides RISCV-specific MCPlus builder.
10//
11//===----------------------------------------------------------------------===//
12
13#include "MCTargetDesc/RISCVMCExpr.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<RISCVMCExpr>(Val: A);
37 const auto &RISCVExprB = cast<RISCVMCExpr>(Val: B);
38 if (RISCVExprA.getSpecifier() != RISCVExprB.getSpecifier())
39 return false;
40
41 return MCPlusBuilder::equals(A: *RISCVExprA.getSubExpr(),
42 B: *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(Opcode: 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, OpNum&: SymOpIndex);
171 (void)Result;
172 assert(Result && "unimplemented branch");
173
174 Inst.getOperand(i: SymOpIndex) = MCOperand::createExpr(
175 Val: MCSymbolRefExpr::create(Symbol: TBB, Kind: MCSymbolRefExpr::VK_None, Ctx&: *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(x: 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 enabled
224 Inst.setOpcode(RISCV::JALR);
225 Inst.clear();
226 Inst.addOperand(MCOperand::createReg(RISCV::X0));
227 Inst.addOperand(MCOperand::createReg(RISCV::X1));
228 Inst.addOperand(Op: MCOperand::createImm(Val: 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(Op: MCOperand::createExpr(
237 Val: MCSymbolRefExpr::create(Symbol: TBB, Kind: MCSymbolRefExpr::VK_None, Ctx&: *Ctx)));
238 }
239
240 StringRef getTrapFillValue() const override {
241 return StringRef("\0\0\0\0", 4);
242 }
243
244 void createCall(unsigned Opcode, MCInst &Inst, const MCSymbol *Target,
245 MCContext *Ctx) {
246 Inst.setOpcode(Opcode);
247 Inst.clear();
248 Inst.addOperand(Op: MCOperand::createExpr(Val: RISCVMCExpr::create(
249 Expr: MCSymbolRefExpr::create(Symbol: Target, Kind: MCSymbolRefExpr::VK_None, Ctx&: *Ctx),
250 S: ELF::R_RISCV_CALL_PLT, Ctx&: *Ctx)));
251 }
252
253 void createCall(MCInst &Inst, const MCSymbol *Target,
254 MCContext *Ctx) override {
255 return createCall(RISCV::PseudoCALL, Inst, Target, Ctx);
256 }
257
258 void createLongTailCall(InstructionListType &Seq, const MCSymbol *Target,
259 MCContext *Ctx) override {
260 createShortJmp(Seq, Target, Ctx, /*IsTailCall*/ true);
261 }
262
263 void createTailCall(MCInst &Inst, const MCSymbol *Target,
264 MCContext *Ctx) override {
265 return createCall(RISCV::PseudoTAIL, Inst, Target, Ctx);
266 }
267
268 bool analyzeBranch(InstructionIterator Begin, InstructionIterator End,
269 const MCSymbol *&TBB, const MCSymbol *&FBB,
270 MCInst *&CondBranch,
271 MCInst *&UncondBranch) const override {
272 auto I = End;
273
274 while (I != Begin) {
275 --I;
276
277 // Ignore nops and CFIs
278 if (isPseudo(Inst: *I) || isNoop(Inst: *I))
279 continue;
280
281 // Stop when we find the first non-terminator
282 if (!isTerminator(Inst: *I) || isTailCall(Inst: *I) || !isBranch(Inst: *I))
283 break;
284
285 // Handle unconditional branches.
286 if (isUnconditionalBranch(Inst: *I)) {
287 // If any code was seen after this unconditional branch, we've seen
288 // unreachable code. Ignore them.
289 CondBranch = nullptr;
290 UncondBranch = &*I;
291 const MCSymbol *Sym = getTargetSymbol(Inst: *I);
292 assert(Sym != nullptr &&
293 "Couldn't extract BB symbol from jump operand");
294 TBB = Sym;
295 continue;
296 }
297
298 // Handle conditional branches and ignore indirect branches
299 if (isIndirectBranch(Inst: *I))
300 return false;
301
302 if (CondBranch == nullptr) {
303 const MCSymbol *TargetBB = getTargetSymbol(Inst: *I);
304 if (TargetBB == nullptr) {
305 // Unrecognized branch target
306 return false;
307 }
308 FBB = TBB;
309 TBB = TargetBB;
310 CondBranch = &*I;
311 continue;
312 }
313
314 llvm_unreachable("multiple conditional branches in one BB");
315 }
316
317 return true;
318 }
319
320 bool getSymbolRefOperandNum(const MCInst &Inst, unsigned &OpNum) const {
321 switch (Inst.getOpcode()) {
322 default:
323 return false;
324 case RISCV::C_J:
325 OpNum = 0;
326 return true;
327 case RISCV::AUIPC:
328 case RISCV::JAL:
329 case RISCV::C_BEQZ:
330 case RISCV::C_BNEZ:
331 OpNum = 1;
332 return true;
333 case RISCV::BEQ:
334 case RISCV::BGE:
335 case RISCV::BGEU:
336 case RISCV::BNE:
337 case RISCV::BLT:
338 case RISCV::BLTU:
339 OpNum = 2;
340 return true;
341 }
342 }
343
344 const MCSymbol *getTargetSymbol(const MCExpr *Expr) const override {
345 auto *RISCVExpr = dyn_cast<RISCVMCExpr>(Val: Expr);
346 if (RISCVExpr && RISCVExpr->getSubExpr())
347 return getTargetSymbol(Expr: RISCVExpr->getSubExpr());
348
349 return MCPlusBuilder::getTargetSymbol(Expr);
350 }
351
352 const MCSymbol *getTargetSymbol(const MCInst &Inst,
353 unsigned OpNum = 0) const override {
354 if (!OpNum && !getSymbolRefOperandNum(Inst, OpNum))
355 return nullptr;
356
357 const MCOperand &Op = Inst.getOperand(i: OpNum);
358 if (!Op.isExpr())
359 return nullptr;
360
361 return getTargetSymbol(Expr: Op.getExpr());
362 }
363
364 bool lowerTailCall(MCInst &Inst) override {
365 removeAnnotation(Inst, Index: MCPlus::MCAnnotation::kTailCall);
366 if (getConditionalTailCall(Inst))
367 unsetConditionalTailCall(Inst);
368 return true;
369 }
370
371 uint64_t analyzePLTEntry(MCInst &Instruction, InstructionIterator Begin,
372 InstructionIterator End,
373 uint64_t BeginPC) const override {
374 auto I = Begin;
375
376 assert(I != End);
377 auto &AUIPC = *I++;
378 assert(AUIPC.getOpcode() == RISCV::AUIPC);
379 assert(AUIPC.getOperand(0).getReg() == RISCV::X28);
380
381 assert(I != End);
382 auto &LD = *I++;
383 assert(LD.getOpcode() == RISCV::LD);
384 assert(LD.getOperand(0).getReg() == RISCV::X28);
385 assert(LD.getOperand(1).getReg() == RISCV::X28);
386
387 assert(I != End);
388 auto &JALR = *I++;
389 (void)JALR;
390 assert(JALR.getOpcode() == RISCV::JALR);
391 assert(JALR.getOperand(0).getReg() == RISCV::X6);
392 assert(JALR.getOperand(1).getReg() == RISCV::X28);
393
394 assert(I != End);
395 auto &NOP = *I++;
396 (void)NOP;
397 assert(isNoop(NOP));
398
399 assert(I == End);
400
401 auto AUIPCOffset = AUIPC.getOperand(i: 1).getImm() << 12;
402 auto LDOffset = LD.getOperand(i: 2).getImm();
403 return BeginPC + AUIPCOffset + LDOffset;
404 }
405
406 bool replaceImmWithSymbolRef(MCInst &Inst, const MCSymbol *Symbol,
407 int64_t Addend, MCContext *Ctx, int64_t &Value,
408 uint32_t RelType) const override {
409 unsigned ImmOpNo = -1U;
410
411 for (unsigned Index = 0; Index < MCPlus::getNumPrimeOperands(Inst);
412 ++Index) {
413 if (Inst.getOperand(i: Index).isImm()) {
414 ImmOpNo = Index;
415 break;
416 }
417 }
418
419 if (ImmOpNo == -1U)
420 return false;
421
422 Value = Inst.getOperand(i: ImmOpNo).getImm();
423 setOperandToSymbolRef(Inst, OpNum: ImmOpNo, Symbol, Addend, Ctx, RelType);
424 return true;
425 }
426
427 const MCExpr *getTargetExprFor(MCInst &Inst, const MCExpr *Expr,
428 MCContext &Ctx,
429 uint32_t RelType) const override {
430 switch (RelType) {
431 default:
432 return Expr;
433 case ELF::R_RISCV_GOT_HI20:
434 case ELF::R_RISCV_TLS_GOT_HI20:
435 case ELF::R_RISCV_TLS_GD_HI20:
436 // The GOT is reused so no need to create GOT relocations
437 case ELF::R_RISCV_PCREL_HI20:
438 return RISCVMCExpr::create(Expr, S: ELF::R_RISCV_PCREL_HI20, Ctx);
439 case ELF::R_RISCV_PCREL_LO12_I:
440 case ELF::R_RISCV_PCREL_LO12_S:
441 return RISCVMCExpr::create(Expr, S: RISCVMCExpr::VK_PCREL_LO, Ctx);
442 case ELF::R_RISCV_HI20:
443 return RISCVMCExpr::create(Expr, S: ELF::R_RISCV_HI20, Ctx);
444 case ELF::R_RISCV_LO12_I:
445 case ELF::R_RISCV_LO12_S:
446 return RISCVMCExpr::create(Expr, S: RISCVMCExpr::VK_LO, Ctx);
447 case ELF::R_RISCV_CALL:
448 return RISCVMCExpr::create(Expr, S: ELF::R_RISCV_CALL_PLT, Ctx);
449 case ELF::R_RISCV_CALL_PLT:
450 return RISCVMCExpr::create(Expr, S: ELF::R_RISCV_CALL_PLT, Ctx);
451 }
452 }
453
454 bool evaluateMemOperandTarget(const MCInst &Inst, uint64_t &Target,
455 uint64_t Address,
456 uint64_t Size) const override {
457 return false;
458 }
459
460 bool isCallAuipc(const MCInst &Inst) const {
461 if (Inst.getOpcode() != RISCV::AUIPC)
462 return false;
463
464 const auto &ImmOp = Inst.getOperand(i: 1);
465 if (!ImmOp.isExpr())
466 return false;
467
468 const auto *ImmExpr = ImmOp.getExpr();
469 if (!isa<RISCVMCExpr>(Val: ImmExpr))
470 return false;
471
472 switch (cast<RISCVMCExpr>(Val: ImmExpr)->getSpecifier()) {
473 default:
474 return false;
475 case ELF::R_RISCV_CALL_PLT:
476 return true;
477 }
478 }
479
480 bool isRISCVCall(const MCInst &First, const MCInst &Second) const override {
481 if (!isCallAuipc(Inst: First))
482 return false;
483
484 assert(Second.getOpcode() == RISCV::JALR);
485 return true;
486 }
487
488 uint16_t getMinFunctionAlignment() const override {
489 if (STI->hasFeature(RISCV::FeatureStdExtC) ||
490 STI->hasFeature(RISCV::FeatureStdExtZca))
491 return 2;
492 return 4;
493 }
494
495 void createStackPointerIncrement(
496 MCInst &Inst, int imm,
497 bool NoFlagsClobber = false /*unused for RISCV*/) const override {
498 Inst = MCInstBuilder(RISCV::ADDI)
499 .addReg(RISCV::X2)
500 .addReg(RISCV::X2)
501 .addImm(-imm);
502 }
503
504 void createStackPointerDecrement(
505 MCInst &Inst, int imm,
506 bool NoFlagsClobber = false /*unused for RISCV*/) const override {
507 Inst = MCInstBuilder(RISCV::ADDI)
508 .addReg(RISCV::X2)
509 .addReg(RISCV::X2)
510 .addImm(imm);
511 }
512
513 void loadReg(MCInst &Inst, MCPhysReg To, MCPhysReg From,
514 int64_t offset) const {
515 Inst = MCInstBuilder(RISCV::LD).addReg(To).addReg(From).addImm(offset);
516 }
517
518 void storeReg(MCInst &Inst, MCPhysReg From, MCPhysReg To,
519 int64_t offset) const {
520 Inst = MCInstBuilder(RISCV::SD).addReg(From).addReg(To).addImm(offset);
521 }
522
523 void spillRegs(InstructionListType &Insts,
524 const SmallVector<unsigned> &Regs) const {
525 Insts.emplace_back();
526 createStackPointerIncrement(Inst&: Insts.back(), imm: Regs.size() * 8);
527
528 int64_t Offset = 0;
529 for (auto Reg : Regs) {
530 Insts.emplace_back();
531 storeReg(Insts.back(), Reg, RISCV::X2, Offset);
532 Offset += 8;
533 }
534 }
535
536 void reloadRegs(InstructionListType &Insts,
537 const SmallVector<unsigned> &Regs) const {
538 int64_t Offset = 0;
539 for (auto Reg : Regs) {
540 Insts.emplace_back();
541 loadReg(Insts.back(), Reg, RISCV::X2, Offset);
542 Offset += 8;
543 }
544
545 Insts.emplace_back();
546 createStackPointerDecrement(Inst&: Insts.back(), imm: Regs.size() * 8);
547 }
548
549 void atomicAdd(MCInst &Inst, MCPhysReg RegAtomic, MCPhysReg RegTo,
550 MCPhysReg RegCnt) const {
551 Inst = MCInstBuilder(RISCV::AMOADD_D)
552 .addReg(RegAtomic)
553 .addReg(RegTo)
554 .addReg(RegCnt);
555 }
556
557 InstructionListType createRegCmpJE(MCPhysReg RegNo, MCPhysReg RegTmp,
558 const MCSymbol *Target,
559 MCContext *Ctx) const {
560 InstructionListType Insts;
561 Insts.emplace_back(
562 MCInstBuilder(RISCV::SUB).addReg(RegTmp).addReg(RegNo).addReg(RegNo));
563 Insts.emplace_back(MCInstBuilder(RISCV::BEQ)
564 .addReg(RegNo)
565 .addReg(RegTmp)
566 .addExpr(MCSymbolRefExpr::create(
567 Target, MCSymbolRefExpr::VK_None, *Ctx)));
568 return Insts;
569 }
570
571 void createTrap(MCInst &Inst) const override {
572 Inst.clear();
573 Inst.setOpcode(RISCV::EBREAK);
574 }
575
576 void createShortJmp(InstructionListType &Seq, const MCSymbol *Target,
577 MCContext *Ctx, bool IsTailCall) override {
578 // The sequence of instructions we create here is the following:
579 // auipc a5, hi20(Target)
580 // addi a5, a5, low12(Target)
581 // jr x5 => jalr x0, x5, 0
582 MCPhysReg Reg = RISCV::X5;
583 InstructionListType Insts = materializeAddress(Target, Ctx, RegName: Reg);
584 Insts.emplace_back();
585 MCInst &Inst = Insts.back();
586 Inst.clear();
587 Inst = MCInstBuilder(RISCV::JALR).addReg(RISCV::X0).addReg(Reg).addImm(0);
588 if (IsTailCall)
589 setTailCall(Inst);
590 Seq.swap(x&: Insts);
591 }
592
593 InstructionListType createGetter(MCContext *Ctx, const char *name) const {
594 InstructionListType Insts(4);
595 MCSymbol *Locs = Ctx->getOrCreateSymbol(Name: name);
596 InstructionListType Addr = materializeAddress(Locs, Ctx, RISCV::X10);
597 std::copy(first: Addr.begin(), last: Addr.end(), result: Insts.begin());
598 loadReg(Insts[2], RISCV::X10, RISCV::X10, 0);
599 createReturn(Inst&: Insts[3]);
600 return Insts;
601 }
602
603 InstructionListType createIncMemory(MCPhysReg RegTo, MCPhysReg RegCnt,
604 MCPhysReg RegAtomic) const {
605 InstructionListType Insts;
606 Insts.emplace_back();
607 Insts.back() =
608 MCInstBuilder(RISCV::ADDI).addReg(RegCnt).addReg(RegAtomic).addImm(1);
609 Insts.emplace_back();
610 atomicAdd(Inst&: Insts.back(), RegAtomic, RegTo, RegCnt);
611 return Insts;
612 }
613
614 InstructionListType materializeAddress(const MCSymbol *Target, MCContext *Ctx,
615 MCPhysReg RegName,
616 int64_t Addend = 0) const override {
617 // Get the symbol address by auipc + addi
618 InstructionListType Insts(2);
619 MCSymbol *AuipcLabel = Ctx->createNamedTempSymbol(Name: "pcrel_hi");
620 Insts[0] = MCInstBuilder(RISCV::AUIPC).addReg(RegName).addImm(0);
621 setOperandToSymbolRef(Inst&: Insts[0], /* OpNum */ 1, Symbol: Target, Addend, Ctx,
622 RelType: ELF::R_RISCV_PCREL_HI20);
623 setInstLabel(Inst&: Insts[0], Label: AuipcLabel);
624
625 Insts[1] =
626 MCInstBuilder(RISCV::ADDI).addReg(RegName).addReg(RegName).addImm(0);
627 setOperandToSymbolRef(Inst&: Insts[1], /* OpNum */ 2, Symbol: AuipcLabel, Addend, Ctx,
628 RelType: ELF::R_RISCV_PCREL_LO12_I);
629 return Insts;
630 }
631
632 InstructionListType
633 createInstrIncMemory(const MCSymbol *Target, MCContext *Ctx, bool IsLeaf,
634 unsigned CodePointerSize) const override {
635 // We need 2 scratch registers: one for the target address (x10), and one
636 // for the increment value (x11).
637 // addi sp, sp, -16
638 // sd x10, 0(sp)
639 // sd x11, 8(sp)
640 // la x10, target # 1: auipc x10, %pcrel_hi(target)
641 // # addi x10, x10, %pcrel_lo(1b)
642 // li x11, 1 # addi x11, zero, 1
643 // amoadd.d zero, x10, x11
644 // ld x10, 0(sp)
645 // ld x11, 8(sp)
646 // addi sp, sp, 16
647
648 InstructionListType Insts;
649 spillRegs(Insts, {RISCV::X10, RISCV::X11});
650 InstructionListType Addr = materializeAddress(Target, Ctx, RISCV::X10);
651 Insts.insert(position: Insts.end(), first: Addr.begin(), last: Addr.end());
652 InstructionListType IncInsts =
653 createIncMemory(RISCV::X10, RISCV::X11, RISCV::X0);
654 Insts.insert(position: Insts.end(), first: IncInsts.begin(), last: IncInsts.end());
655 reloadRegs(Insts, {RISCV::X10, RISCV::X11});
656 return Insts;
657 }
658
659 void createDirectCall(MCInst &Inst, const MCSymbol *Target, MCContext *Ctx,
660 bool IsTailCall) override {
661 Inst.setOpcode(RISCV::JAL);
662 Inst.clear();
663 if (IsTailCall) {
664 Inst.addOperand(MCOperand::createReg(RISCV::X0));
665 Inst.addOperand(Op: MCOperand::createExpr(Val: getTargetExprFor(
666 Inst, Expr: MCSymbolRefExpr::create(Symbol: Target, Kind: MCSymbolRefExpr::VK_None, Ctx&: *Ctx),
667 Ctx&: *Ctx, RelType: 0)));
668 convertJmpToTailCall(Inst);
669 } else {
670 Inst.addOperand(MCOperand::createReg(RISCV::X1));
671 Inst.addOperand(Op: MCOperand::createExpr(Val: getTargetExprFor(
672 Inst, Expr: MCSymbolRefExpr::create(Symbol: Target, Kind: MCSymbolRefExpr::VK_None, Ctx&: *Ctx),
673 Ctx&: *Ctx, RelType: 0)));
674 }
675 }
676
677 void createIndirectCallInst(MCInst &Inst, bool IsTailCall, MCPhysReg Reg,
678 int64_t Disp) const {
679 Inst.clear();
680 Inst.setOpcode(RISCV::JALR);
681 Inst.clear();
682 if (IsTailCall) {
683 Inst.addOperand(MCOperand::createReg(RISCV::X0));
684 Inst.addOperand(Op: MCOperand::createReg(Reg));
685 Inst.addOperand(Op: MCOperand::createImm(Val: Disp));
686 } else {
687 Inst.addOperand(MCOperand::createReg(RISCV::X1));
688 Inst.addOperand(Op: MCOperand::createReg(Reg));
689 Inst.addOperand(Op: MCOperand::createImm(Val: Disp));
690 }
691 }
692
693 InstructionListType
694 createInstrumentedIndCallHandlerEntryBB(const MCSymbol *InstrTrampoline,
695 const MCSymbol *IndCallHandler,
696 MCContext *Ctx) override {
697 // Code sequence used to check whether InstrTampoline was initialized
698 // and call it if so, returns via IndCallHandler
699 // sp -16(sp)
700 // sd x10, 0(sp)
701 // sd x11, 0(sp)
702 // la x10, InstrTrampoline -> auipc + addi
703 // ld x10, [x10]
704 // beq x10, x11, IndCallHandler
705 // sp -16(sp)
706 // sd x1, 0(sp)
707 // jalr x1,x10,0
708 // ld x1, [sp], #16
709 // sp 16(sp)
710 // jal x0, IndCallHandler
711
712 InstructionListType Insts;
713 spillRegs(Insts, {RISCV::X10, RISCV::X11});
714 InstructionListType Addr =
715 materializeAddress(InstrTrampoline, Ctx, RISCV::X10);
716 Insts.insert(position: Insts.end(), first: Addr.begin(), last: Addr.end());
717 Insts.emplace_back();
718 loadReg(Insts.back(), RISCV::X10, RISCV::X10, 0);
719 InstructionListType cmpJmp =
720 createRegCmpJE(RISCV::X10, RISCV::X11, IndCallHandler, Ctx);
721 Insts.insert(position: Insts.end(), first: cmpJmp.begin(), last: cmpJmp.end());
722 Insts.emplace_back();
723 createStackPointerIncrement(Inst&: Insts.back(), imm: 16);
724 Insts.emplace_back();
725 storeReg(Insts.back(), RISCV::X1, RISCV::X2, 0);
726 Insts.emplace_back();
727 createIndirectCallInst(Insts.back(), /*IsTailCall*/ false, RISCV::X10, 0);
728 Insts.emplace_back();
729 loadReg(Insts.back(), RISCV::X1, RISCV::X2, 0);
730 Insts.emplace_back();
731 createStackPointerDecrement(Inst&: Insts.back(), imm: 16);
732 Insts.emplace_back();
733 createDirectCall(Inst&: Insts.back(), Target: IndCallHandler, Ctx, /*IsTailCall*/ true);
734 return Insts;
735 }
736
737 InstructionListType createInstrumentedIndCallHandlerExitBB() const override {
738 InstructionListType Insts;
739 reloadRegs(Insts, {RISCV::X10, RISCV::X11});
740 Insts.emplace_back();
741 loadReg(Insts.back(), RISCV::X5, RISCV::X2, 0);
742 Insts.emplace_back();
743 createStackPointerDecrement(Inst&: Insts.back(), imm: 16);
744 reloadRegs(Insts, {RISCV::X10, RISCV::X11});
745 Insts.emplace_back();
746 createIndirectCallInst(Insts.back(), /*IsTailCall*/ true, RISCV::X5, 0);
747 return Insts;
748 }
749
750 InstructionListType
751 createInstrumentedIndTailCallHandlerExitBB() const override {
752 return createInstrumentedIndCallHandlerExitBB();
753 }
754
755 std::vector<MCInst> createSymbolTrampoline(const MCSymbol *TgtSym,
756 MCContext *Ctx) override {
757 std::vector<MCInst> Insts;
758 createShortJmp(Seq&: Insts, Target: TgtSym, Ctx, /*IsTailCall*/ true);
759 return Insts;
760 }
761
762 InstructionListType createNumCountersGetter(MCContext *Ctx) const override {
763 return createGetter(Ctx, name: "__bolt_num_counters");
764 }
765
766 InstructionListType
767 createInstrLocationsGetter(MCContext *Ctx) const override {
768 return createGetter(Ctx, name: "__bolt_instr_locations");
769 }
770
771 InstructionListType createInstrTablesGetter(MCContext *Ctx) const override {
772 return createGetter(Ctx, name: "__bolt_instr_tables");
773 }
774
775 InstructionListType createInstrNumFuncsGetter(MCContext *Ctx) const override {
776 return createGetter(Ctx, name: "__bolt_instr_num_funcs");
777 }
778
779 void convertIndirectCallToLoad(MCInst &Inst, MCPhysReg Reg) override {
780 bool IsTailCall = isTailCall(Inst);
781 if (IsTailCall)
782 removeAnnotation(Inst, Index: MCPlus::MCAnnotation::kTailCall);
783 Inst.setOpcode(RISCV::ADD);
784 Inst.insert(I: Inst.begin(), Op: MCOperand::createReg(Reg));
785 Inst.insert(Inst.begin() + 1, MCOperand::createReg(RISCV::X0));
786 }
787
788 InstructionListType createLoadImmediate(const MCPhysReg Dest,
789 uint64_t Imm) const override {
790 InstructionListType Insts;
791 // get IMM higher 32bit
792 Insts.emplace_back(
793 MCInstBuilder(RISCV::LUI).addReg(Dest).addImm((Imm >> 44) & 0xFFFFF));
794 Insts.emplace_back(MCInstBuilder(RISCV::LUI)
795 .addReg(RISCV::X5)
796 .addImm((Imm >> 32) & 0xFFF));
797 Insts.emplace_back(MCInstBuilder(RISCV::SRLI)
798 .addReg(RISCV::X5)
799 .addReg(RISCV::X5)
800 .addImm(12));
801 Insts.emplace_back(
802 MCInstBuilder(RISCV::OR).addReg(Dest).addReg(Dest).addReg(RISCV::X5));
803 Insts.emplace_back(
804 MCInstBuilder(RISCV::SLLI).addReg(Dest).addReg(Dest).addImm(32));
805
806 // get IMM lower 32bit
807 Insts.emplace_back(MCInstBuilder(RISCV::LUI)
808 .addReg(RISCV::X5)
809 .addImm((Imm >> 12) & 0xFFFFF));
810 Insts.emplace_back(
811 MCInstBuilder(RISCV::LUI).addReg(RISCV::X6).addImm((Imm)&0xFFF));
812 Insts.emplace_back(MCInstBuilder(RISCV::SRLI)
813 .addReg(RISCV::X6)
814 .addReg(RISCV::X6)
815 .addImm(12));
816 Insts.emplace_back(
817 MCInstBuilder(RISCV::OR).addReg(RISCV::X5).addReg(RISCV::X5).addReg(
818 RISCV::X6));
819
820 // get 64bit IMM
821 Insts.emplace_back(
822 MCInstBuilder(RISCV::OR).addReg(Dest).addReg(Dest).addReg(RISCV::X5));
823 return Insts;
824 }
825
826 InstructionListType createInstrumentedIndirectCall(MCInst &&CallInst,
827 MCSymbol *HandlerFuncAddr,
828 int CallSiteID,
829 MCContext *Ctx) override {
830 // Code sequence used to enter indirect call instrumentation helper:
831 // addi sp, sp, -0x10
832 // sd a0, 0x0(sp)
833 // sd a1, 0x8(sp)
834 // mov target x0 convertIndirectCallToLoad -> add a0, zero, target
835 // mov x1 CallSiteID createLoadImmediate
836 // addi sp, sp, -0x10
837 // sd a0, 0x0(sp)
838 // sd a1, 0x8(sp)
839 // la x0 *HandlerFuncAddr -> auipc + addi
840 // jalr x0
841
842 InstructionListType Insts;
843 spillRegs(Insts, {RISCV::X10, RISCV::X11});
844 Insts.emplace_back(args&: CallInst);
845 convertIndirectCallToLoad(Insts.back(), RISCV::X10);
846 InstructionListType LoadImm = createLoadImmediate(RISCV::X11, CallSiteID);
847 Insts.insert(position: Insts.end(), first: LoadImm.begin(), last: LoadImm.end());
848 spillRegs(Insts, {RISCV::X10, RISCV::X11});
849 InstructionListType Addr =
850 materializeAddress(HandlerFuncAddr, Ctx, RISCV::X5);
851 Insts.insert(position: Insts.end(), first: Addr.begin(), last: Addr.end());
852 Insts.emplace_back();
853 createIndirectCallInst(Insts.back(), isTailCall(CallInst), RISCV::X5, 0);
854
855 // // Carry over metadata including tail call marker if present.
856 stripAnnotations(Inst&: Insts.back());
857 moveAnnotations(SrcInst: std::move(CallInst), DstInst&: Insts.back());
858
859 return Insts;
860 }
861};
862
863} // end anonymous namespace
864
865namespace llvm {
866namespace bolt {
867
868MCPlusBuilder *createRISCVMCPlusBuilder(const MCInstrAnalysis *Analysis,
869 const MCInstrInfo *Info,
870 const MCRegisterInfo *RegInfo,
871 const MCSubtargetInfo *STI) {
872 return new RISCVMCPlusBuilder(Analysis, Info, RegInfo, STI);
873}
874
875} // namespace bolt
876} // namespace llvm
877

source code of bolt/lib/Target/RISCV/RISCVMCPlusBuilder.cpp