[OpenACC] Implement 'collapse' for combined constructs.
[llvm-project.git] / bolt / lib / Target / RISCV / RISCVMCPlusBuilder.cpp
blobf8c83b09395f5ee1a23aebf3a57f50f2c44dcf69
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.
11 //===----------------------------------------------------------------------===//
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/MCInst.h"
18 #include "llvm/MC/MCSubtargetInfo.h"
19 #include "llvm/Support/ErrorHandling.h"
21 #define DEBUG_TYPE "mcplus"
23 using namespace llvm;
24 using namespace bolt;
26 namespace {
28 class RISCVMCPlusBuilder : public MCPlusBuilder {
29 public:
30 using MCPlusBuilder::MCPlusBuilder;
32 bool equals(const MCTargetExpr &A, const MCTargetExpr &B,
33 CompFuncTy Comp) const override {
34 const auto &RISCVExprA = cast<RISCVMCExpr>(A);
35 const auto &RISCVExprB = cast<RISCVMCExpr>(B);
36 if (RISCVExprA.getKind() != RISCVExprB.getKind())
37 return false;
39 return MCPlusBuilder::equals(*RISCVExprA.getSubExpr(),
40 *RISCVExprB.getSubExpr(), Comp);
43 void getCalleeSavedRegs(BitVector &Regs) const override {
44 Regs |= getAliases(RISCV::X2);
45 Regs |= getAliases(RISCV::X8);
46 Regs |= getAliases(RISCV::X9);
47 Regs |= getAliases(RISCV::X18);
48 Regs |= getAliases(RISCV::X19);
49 Regs |= getAliases(RISCV::X20);
50 Regs |= getAliases(RISCV::X21);
51 Regs |= getAliases(RISCV::X22);
52 Regs |= getAliases(RISCV::X23);
53 Regs |= getAliases(RISCV::X24);
54 Regs |= getAliases(RISCV::X25);
55 Regs |= getAliases(RISCV::X26);
56 Regs |= getAliases(RISCV::X27);
59 bool shouldRecordCodeRelocation(uint64_t RelType) const override {
60 switch (RelType) {
61 case ELF::R_RISCV_JAL:
62 case ELF::R_RISCV_CALL:
63 case ELF::R_RISCV_CALL_PLT:
64 case ELF::R_RISCV_BRANCH:
65 case ELF::R_RISCV_RVC_BRANCH:
66 case ELF::R_RISCV_RVC_JUMP:
67 case ELF::R_RISCV_GOT_HI20:
68 case ELF::R_RISCV_PCREL_HI20:
69 case ELF::R_RISCV_PCREL_LO12_I:
70 case ELF::R_RISCV_PCREL_LO12_S:
71 case ELF::R_RISCV_HI20:
72 case ELF::R_RISCV_LO12_I:
73 case ELF::R_RISCV_LO12_S:
74 case ELF::R_RISCV_TLS_GOT_HI20:
75 return true;
76 default:
77 llvm_unreachable("Unexpected RISCV relocation type in code");
81 bool isNop(const MCInst &Inst) const {
82 return Inst.getOpcode() == RISCV::ADDI &&
83 Inst.getOperand(0).getReg() == RISCV::X0 &&
84 Inst.getOperand(1).getReg() == RISCV::X0 &&
85 Inst.getOperand(2).getImm() == 0;
88 bool isCNop(const MCInst &Inst) const {
89 return Inst.getOpcode() == RISCV::C_NOP;
92 bool isNoop(const MCInst &Inst) const override {
93 return isNop(Inst) || isCNop(Inst);
96 bool isPseudo(const MCInst &Inst) const override {
97 switch (Inst.getOpcode()) {
98 default:
99 return MCPlusBuilder::isPseudo(Inst);
100 case RISCV::PseudoCALL:
101 case RISCV::PseudoTAIL:
102 return false;
106 bool isIndirectCall(const MCInst &Inst) const override {
107 if (!isCall(Inst))
108 return false;
110 switch (Inst.getOpcode()) {
111 default:
112 return false;
113 case RISCV::JALR:
114 case RISCV::C_JALR:
115 case RISCV::C_JR:
116 return true;
120 bool hasPCRelOperand(const MCInst &Inst) const override {
121 switch (Inst.getOpcode()) {
122 default:
123 return false;
124 case RISCV::JAL:
125 case RISCV::AUIPC:
126 return true;
130 unsigned getInvertedBranchOpcode(unsigned Opcode) const {
131 switch (Opcode) {
132 default:
133 llvm_unreachable("Failed to invert branch opcode");
134 return Opcode;
135 case RISCV::BEQ:
136 return RISCV::BNE;
137 case RISCV::BNE:
138 return RISCV::BEQ;
139 case RISCV::BLT:
140 return RISCV::BGE;
141 case RISCV::BGE:
142 return RISCV::BLT;
143 case RISCV::BLTU:
144 return RISCV::BGEU;
145 case RISCV::BGEU:
146 return RISCV::BLTU;
147 case RISCV::C_BEQZ:
148 return RISCV::C_BNEZ;
149 case RISCV::C_BNEZ:
150 return RISCV::C_BEQZ;
154 void reverseBranchCondition(MCInst &Inst, const MCSymbol *TBB,
155 MCContext *Ctx) const override {
156 auto Opcode = getInvertedBranchOpcode(Inst.getOpcode());
157 Inst.setOpcode(Opcode);
158 replaceBranchTarget(Inst, TBB, Ctx);
161 void replaceBranchTarget(MCInst &Inst, const MCSymbol *TBB,
162 MCContext *Ctx) const override {
163 assert((isCall(Inst) || isBranch(Inst)) && !isIndirectBranch(Inst) &&
164 "Invalid instruction");
166 unsigned SymOpIndex;
167 auto Result = getSymbolRefOperandNum(Inst, SymOpIndex);
168 (void)Result;
169 assert(Result && "unimplemented branch");
171 Inst.getOperand(SymOpIndex) = MCOperand::createExpr(
172 MCSymbolRefExpr::create(TBB, MCSymbolRefExpr::VK_None, *Ctx));
175 IndirectBranchType analyzeIndirectBranch(
176 MCInst &Instruction, InstructionIterator Begin, InstructionIterator End,
177 const unsigned PtrSize, MCInst *&MemLocInstr, unsigned &BaseRegNum,
178 unsigned &IndexRegNum, int64_t &DispValue, const MCExpr *&DispExpr,
179 MCInst *&PCRelBaseOut, MCInst *&FixedEntryLoadInst) const override {
180 MemLocInstr = nullptr;
181 BaseRegNum = 0;
182 IndexRegNum = 0;
183 DispValue = 0;
184 DispExpr = nullptr;
185 PCRelBaseOut = nullptr;
186 FixedEntryLoadInst = nullptr;
188 // Check for the following long tail call sequence:
189 // 1: auipc xi, %pcrel_hi(sym)
190 // jalr zero, %pcrel_lo(1b)(xi)
191 if (Instruction.getOpcode() == RISCV::JALR && Begin != End) {
192 MCInst &PrevInst = *std::prev(End);
193 if (isRISCVCall(PrevInst, Instruction) &&
194 Instruction.getOperand(0).getReg() == RISCV::X0)
195 return IndirectBranchType::POSSIBLE_TAIL_CALL;
198 return IndirectBranchType::UNKNOWN;
201 bool convertJmpToTailCall(MCInst &Inst) override {
202 if (isTailCall(Inst))
203 return false;
205 switch (Inst.getOpcode()) {
206 default:
207 llvm_unreachable("unsupported tail call opcode");
208 case RISCV::JAL:
209 case RISCV::JALR:
210 case RISCV::C_J:
211 case RISCV::C_JR:
212 break;
215 setTailCall(Inst);
216 return true;
219 void createReturn(MCInst &Inst) const override {
220 // TODO "c.jr ra" when RVC is enabled
221 Inst.setOpcode(RISCV::JALR);
222 Inst.clear();
223 Inst.addOperand(MCOperand::createReg(RISCV::X0));
224 Inst.addOperand(MCOperand::createReg(RISCV::X1));
225 Inst.addOperand(MCOperand::createImm(0));
228 void createUncondBranch(MCInst &Inst, const MCSymbol *TBB,
229 MCContext *Ctx) const override {
230 Inst.setOpcode(RISCV::JAL);
231 Inst.clear();
232 Inst.addOperand(MCOperand::createReg(RISCV::X0));
233 Inst.addOperand(MCOperand::createExpr(
234 MCSymbolRefExpr::create(TBB, MCSymbolRefExpr::VK_None, *Ctx)));
237 StringRef getTrapFillValue() const override {
238 return StringRef("\0\0\0\0", 4);
241 void createCall(unsigned Opcode, MCInst &Inst, const MCSymbol *Target,
242 MCContext *Ctx) {
243 Inst.setOpcode(Opcode);
244 Inst.clear();
245 Inst.addOperand(MCOperand::createExpr(RISCVMCExpr::create(
246 MCSymbolRefExpr::create(Target, MCSymbolRefExpr::VK_None, *Ctx),
247 RISCVMCExpr::VK_RISCV_CALL, *Ctx)));
250 void createCall(MCInst &Inst, const MCSymbol *Target,
251 MCContext *Ctx) override {
252 return createCall(RISCV::PseudoCALL, Inst, Target, Ctx);
255 void createTailCall(MCInst &Inst, const MCSymbol *Target,
256 MCContext *Ctx) override {
257 return createCall(RISCV::PseudoTAIL, Inst, Target, Ctx);
260 bool analyzeBranch(InstructionIterator Begin, InstructionIterator End,
261 const MCSymbol *&TBB, const MCSymbol *&FBB,
262 MCInst *&CondBranch,
263 MCInst *&UncondBranch) const override {
264 auto I = End;
266 while (I != Begin) {
267 --I;
269 // Ignore nops and CFIs
270 if (isPseudo(*I) || isNoop(*I))
271 continue;
273 // Stop when we find the first non-terminator
274 if (!isTerminator(*I) || isTailCall(*I) || !isBranch(*I))
275 break;
277 // Handle unconditional branches.
278 if (isUnconditionalBranch(*I)) {
279 // If any code was seen after this unconditional branch, we've seen
280 // unreachable code. Ignore them.
281 CondBranch = nullptr;
282 UncondBranch = &*I;
283 const MCSymbol *Sym = getTargetSymbol(*I);
284 assert(Sym != nullptr &&
285 "Couldn't extract BB symbol from jump operand");
286 TBB = Sym;
287 continue;
290 // Handle conditional branches and ignore indirect branches
291 if (isIndirectBranch(*I))
292 return false;
294 if (CondBranch == nullptr) {
295 const MCSymbol *TargetBB = getTargetSymbol(*I);
296 if (TargetBB == nullptr) {
297 // Unrecognized branch target
298 return false;
300 FBB = TBB;
301 TBB = TargetBB;
302 CondBranch = &*I;
303 continue;
306 llvm_unreachable("multiple conditional branches in one BB");
309 return true;
312 bool getSymbolRefOperandNum(const MCInst &Inst, unsigned &OpNum) const {
313 switch (Inst.getOpcode()) {
314 default:
315 return false;
316 case RISCV::C_J:
317 OpNum = 0;
318 return true;
319 case RISCV::AUIPC:
320 case RISCV::JAL:
321 case RISCV::C_BEQZ:
322 case RISCV::C_BNEZ:
323 OpNum = 1;
324 return true;
325 case RISCV::BEQ:
326 case RISCV::BGE:
327 case RISCV::BGEU:
328 case RISCV::BNE:
329 case RISCV::BLT:
330 case RISCV::BLTU:
331 OpNum = 2;
332 return true;
336 const MCSymbol *getTargetSymbol(const MCExpr *Expr) const override {
337 auto *RISCVExpr = dyn_cast<RISCVMCExpr>(Expr);
338 if (RISCVExpr && RISCVExpr->getSubExpr())
339 return getTargetSymbol(RISCVExpr->getSubExpr());
341 auto *BinExpr = dyn_cast<MCBinaryExpr>(Expr);
342 if (BinExpr)
343 return getTargetSymbol(BinExpr->getLHS());
345 auto *SymExpr = dyn_cast<MCSymbolRefExpr>(Expr);
346 if (SymExpr && SymExpr->getKind() == MCSymbolRefExpr::VK_None)
347 return &SymExpr->getSymbol();
349 return nullptr;
352 const MCSymbol *getTargetSymbol(const MCInst &Inst,
353 unsigned OpNum = 0) const override {
354 if (!OpNum && !getSymbolRefOperandNum(Inst, OpNum))
355 return nullptr;
357 const MCOperand &Op = Inst.getOperand(OpNum);
358 if (!Op.isExpr())
359 return nullptr;
361 return getTargetSymbol(Op.getExpr());
364 bool lowerTailCall(MCInst &Inst) override {
365 removeAnnotation(Inst, MCPlus::MCAnnotation::kTailCall);
366 if (getConditionalTailCall(Inst))
367 unsetConditionalTailCall(Inst);
368 return true;
371 uint64_t analyzePLTEntry(MCInst &Instruction, InstructionIterator Begin,
372 InstructionIterator End,
373 uint64_t BeginPC) const override {
374 auto I = Begin;
376 assert(I != End);
377 auto &AUIPC = *I++;
378 assert(AUIPC.getOpcode() == RISCV::AUIPC);
379 assert(AUIPC.getOperand(0).getReg() == RISCV::X28);
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);
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);
394 assert(I != End);
395 auto &NOP = *I++;
396 (void)NOP;
397 assert(isNoop(NOP));
399 assert(I == End);
401 auto AUIPCOffset = AUIPC.getOperand(1).getImm() << 12;
402 auto LDOffset = LD.getOperand(2).getImm();
403 return BeginPC + AUIPCOffset + LDOffset;
406 bool replaceImmWithSymbolRef(MCInst &Inst, const MCSymbol *Symbol,
407 int64_t Addend, MCContext *Ctx, int64_t &Value,
408 uint64_t RelType) const override {
409 unsigned ImmOpNo = -1U;
411 for (unsigned Index = 0; Index < MCPlus::getNumPrimeOperands(Inst);
412 ++Index) {
413 if (Inst.getOperand(Index).isImm()) {
414 ImmOpNo = Index;
415 break;
419 if (ImmOpNo == -1U)
420 return false;
422 Value = Inst.getOperand(ImmOpNo).getImm();
423 setOperandToSymbolRef(Inst, ImmOpNo, Symbol, Addend, Ctx, RelType);
424 return true;
427 const MCExpr *getTargetExprFor(MCInst &Inst, const MCExpr *Expr,
428 MCContext &Ctx,
429 uint64_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 // The GOT is reused so no need to create GOT relocations
436 case ELF::R_RISCV_PCREL_HI20:
437 return RISCVMCExpr::create(Expr, RISCVMCExpr::VK_RISCV_PCREL_HI, Ctx);
438 case ELF::R_RISCV_PCREL_LO12_I:
439 case ELF::R_RISCV_PCREL_LO12_S:
440 return RISCVMCExpr::create(Expr, RISCVMCExpr::VK_RISCV_PCREL_LO, Ctx);
441 case ELF::R_RISCV_HI20:
442 return RISCVMCExpr::create(Expr, RISCVMCExpr::VK_RISCV_HI, Ctx);
443 case ELF::R_RISCV_LO12_I:
444 case ELF::R_RISCV_LO12_S:
445 return RISCVMCExpr::create(Expr, RISCVMCExpr::VK_RISCV_LO, Ctx);
446 case ELF::R_RISCV_CALL:
447 return RISCVMCExpr::create(Expr, RISCVMCExpr::VK_RISCV_CALL, Ctx);
448 case ELF::R_RISCV_CALL_PLT:
449 return RISCVMCExpr::create(Expr, RISCVMCExpr::VK_RISCV_CALL_PLT, Ctx);
453 bool evaluateMemOperandTarget(const MCInst &Inst, uint64_t &Target,
454 uint64_t Address,
455 uint64_t Size) const override {
456 return false;
459 bool isCallAuipc(const MCInst &Inst) const {
460 if (Inst.getOpcode() != RISCV::AUIPC)
461 return false;
463 const auto &ImmOp = Inst.getOperand(1);
464 if (!ImmOp.isExpr())
465 return false;
467 const auto *ImmExpr = ImmOp.getExpr();
468 if (!isa<RISCVMCExpr>(ImmExpr))
469 return false;
471 switch (cast<RISCVMCExpr>(ImmExpr)->getKind()) {
472 default:
473 return false;
474 case RISCVMCExpr::VK_RISCV_CALL:
475 case RISCVMCExpr::VK_RISCV_CALL_PLT:
476 return true;
480 bool isRISCVCall(const MCInst &First, const MCInst &Second) const override {
481 if (!isCallAuipc(First))
482 return false;
484 assert(Second.getOpcode() == RISCV::JALR);
485 return true;
488 uint16_t getMinFunctionAlignment() const override {
489 if (STI->hasFeature(RISCV::FeatureStdExtC) ||
490 STI->hasFeature(RISCV::FeatureStdExtZca))
491 return 2;
492 return 4;
496 } // end anonymous namespace
498 namespace llvm {
499 namespace bolt {
501 MCPlusBuilder *createRISCVMCPlusBuilder(const MCInstrAnalysis *Analysis,
502 const MCInstrInfo *Info,
503 const MCRegisterInfo *RegInfo,
504 const MCSubtargetInfo *STI) {
505 return new RISCVMCPlusBuilder(Analysis, Info, RegInfo, STI);
508 } // namespace bolt
509 } // namespace llvm