xref: /llvm-project/bolt/lib/Passes/FixRISCVCallsPass.cpp (revision fd38366e4525c5507bbb2a2fc1f7d113a964224e)
1*fd38366eSAmir Ayupov //===- bolt/Passes/FixRISCVCallsPass.cpp ------------------------*- C++ -*-===//
2*fd38366eSAmir Ayupov //
3*fd38366eSAmir Ayupov // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*fd38366eSAmir Ayupov // See https://llvm.org/LICENSE.txt for license information.
5*fd38366eSAmir Ayupov // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*fd38366eSAmir Ayupov //
7*fd38366eSAmir Ayupov //===----------------------------------------------------------------------===//
8*fd38366eSAmir Ayupov 
9f8730293SJob Noorman #include "bolt/Passes/FixRISCVCallsPass.h"
10f8730293SJob Noorman #include "bolt/Core/ParallelUtilities.h"
11f8730293SJob Noorman 
12f8730293SJob Noorman #include <iterator>
13f8730293SJob Noorman 
14f8730293SJob Noorman using namespace llvm;
15f8730293SJob Noorman 
16f8730293SJob Noorman namespace llvm {
17f8730293SJob Noorman namespace bolt {
18f8730293SJob Noorman 
runOnFunction(BinaryFunction & BF)19f8730293SJob Noorman void FixRISCVCallsPass::runOnFunction(BinaryFunction &BF) {
20f8730293SJob Noorman   auto &BC = BF.getBinaryContext();
21c5ba6197SJob Noorman   auto &MIB = BC.MIB;
22c5ba6197SJob Noorman   auto *Ctx = BC.Ctx.get();
23f8730293SJob Noorman 
24f8730293SJob Noorman   for (auto &BB : BF) {
25c5ba6197SJob Noorman     for (auto II = BB.begin(); II != BB.end();) {
26c5ba6197SJob Noorman       if (MIB->isCall(*II) && !MIB->isIndirectCall(*II)) {
27c5ba6197SJob Noorman         auto *Target = MIB->getTargetSymbol(*II);
28c5ba6197SJob Noorman         assert(Target && "Cannot find call target");
29f8730293SJob Noorman 
30dc925be6SJob Noorman         MCInst OldCall = *II;
31f8730293SJob Noorman         auto L = BC.scopeLock();
32f8730293SJob Noorman 
33c5ba6197SJob Noorman         if (MIB->isTailCall(*II))
34c5ba6197SJob Noorman           MIB->createTailCall(*II, Target, Ctx);
35c5ba6197SJob Noorman         else
36c5ba6197SJob Noorman           MIB->createCall(*II, Target, Ctx);
37c5ba6197SJob Noorman 
38dc925be6SJob Noorman         MIB->moveAnnotations(std::move(OldCall), *II);
39c5ba6197SJob Noorman         ++II;
40c5ba6197SJob Noorman         continue;
41c5ba6197SJob Noorman       }
42c5ba6197SJob Noorman 
43c5ba6197SJob Noorman       auto NextII = std::next(II);
44c5ba6197SJob Noorman 
45c5ba6197SJob Noorman       if (NextII == BB.end())
46c5ba6197SJob Noorman         break;
47c5ba6197SJob Noorman 
48c5ba6197SJob Noorman       if (MIB->isRISCVCall(*II, *NextII)) {
49c5ba6197SJob Noorman         auto *Target = MIB->getTargetSymbol(*II);
50c5ba6197SJob Noorman         assert(Target && "Cannot find call target");
51c5ba6197SJob Noorman 
52dc925be6SJob Noorman         MCInst OldCall = *NextII;
53c5ba6197SJob Noorman         auto L = BC.scopeLock();
547fa33773SJob Noorman 
557fa33773SJob Noorman         if (MIB->isTailCall(*NextII))
567fa33773SJob Noorman           MIB->createTailCall(*II, Target, Ctx);
577fa33773SJob Noorman         else
58c5ba6197SJob Noorman           MIB->createCall(*II, Target, Ctx);
597fa33773SJob Noorman 
60dc925be6SJob Noorman         MIB->moveAnnotations(std::move(OldCall), *II);
61dc925be6SJob Noorman 
62dc925be6SJob Noorman         // The original offset was set on the jalr of the auipc+jalr pair. Since
63dc925be6SJob Noorman         // the whole pair is replaced by a call, adjust the offset by -4 (the
64dc925be6SJob Noorman         // size of a auipc).
65dc925be6SJob Noorman         if (std::optional<uint32_t> Offset = MIB->getOffset(*II)) {
66dc925be6SJob Noorman           assert(*Offset >= 4 && "Illegal jalr offset");
67dc925be6SJob Noorman           MIB->setOffset(*II, *Offset - 4);
68dc925be6SJob Noorman         }
69dc925be6SJob Noorman 
70c5ba6197SJob Noorman         II = BB.eraseInstruction(NextII);
71c5ba6197SJob Noorman         continue;
72c5ba6197SJob Noorman       }
73c5ba6197SJob Noorman 
74c5ba6197SJob Noorman       ++II;
75f8730293SJob Noorman     }
76f8730293SJob Noorman   }
77f8730293SJob Noorman }
78f8730293SJob Noorman 
runOnFunctions(BinaryContext & BC)79a5f3d1a8SAmir Ayupov Error FixRISCVCallsPass::runOnFunctions(BinaryContext &BC) {
80f8730293SJob Noorman   if (!BC.isRISCV() || !BC.HasRelocations)
81a5f3d1a8SAmir Ayupov     return Error::success();
82f8730293SJob Noorman 
83f8730293SJob Noorman   ParallelUtilities::WorkFuncTy WorkFun = [&](BinaryFunction &BF) {
84f8730293SJob Noorman     runOnFunction(BF);
85f8730293SJob Noorman   };
86f8730293SJob Noorman 
87f8730293SJob Noorman   ParallelUtilities::runOnEachFunction(
88f8730293SJob Noorman       BC, ParallelUtilities::SchedulingPolicy::SP_INST_LINEAR, WorkFun, nullptr,
89f8730293SJob Noorman       "FixRISCVCalls");
90a5f3d1a8SAmir Ayupov 
91a5f3d1a8SAmir Ayupov   return Error::success();
92f8730293SJob Noorman }
93f8730293SJob Noorman 
94f8730293SJob Noorman } // namespace bolt
95f8730293SJob Noorman } // namespace llvm
96