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 | |
25 | using namespace llvm; |
26 | using namespace bolt; |
27 | |
28 | namespace { |
29 | |
30 | class RISCVMCPlusBuilder : public MCPlusBuilder { |
31 | public: |
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 | |
865 | namespace llvm { |
866 | namespace bolt { |
867 | |
868 | MCPlusBuilder *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 | |