xref: /freebsd/contrib/llvm-project/llvm/lib/ExecutionEngine/JITLink/x86.cpp (revision 700637cbb5e582861067a11aaca4d053546871d2)
1*700637cbSDimitry Andric //===-------- x86.cpp - Generic JITLink x86 edge kinds, utilities ---------===//
2*700637cbSDimitry Andric //
3*700637cbSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*700637cbSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*700637cbSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*700637cbSDimitry Andric //
7*700637cbSDimitry Andric //===----------------------------------------------------------------------===//
8*700637cbSDimitry Andric //
9*700637cbSDimitry Andric // Generic utilities for graphs representing x86 objects.
10*700637cbSDimitry Andric //
11*700637cbSDimitry Andric //===----------------------------------------------------------------------===//
12*700637cbSDimitry Andric 
13*700637cbSDimitry Andric #include "llvm/ExecutionEngine/JITLink/x86.h"
14*700637cbSDimitry Andric 
15*700637cbSDimitry Andric #define DEBUG_TYPE "jitlink"
16*700637cbSDimitry Andric 
17*700637cbSDimitry Andric namespace llvm::jitlink::x86 {
18*700637cbSDimitry Andric 
getEdgeKindName(Edge::Kind K)19*700637cbSDimitry Andric const char *getEdgeKindName(Edge::Kind K) {
20*700637cbSDimitry Andric   switch (K) {
21*700637cbSDimitry Andric   case Pointer32:
22*700637cbSDimitry Andric     return "Pointer32";
23*700637cbSDimitry Andric   case PCRel32:
24*700637cbSDimitry Andric     return "PCRel32";
25*700637cbSDimitry Andric   case Pointer16:
26*700637cbSDimitry Andric     return "Pointer16";
27*700637cbSDimitry Andric   case PCRel16:
28*700637cbSDimitry Andric     return "PCRel16";
29*700637cbSDimitry Andric   case Delta32:
30*700637cbSDimitry Andric     return "Delta32";
31*700637cbSDimitry Andric   case Delta32FromGOT:
32*700637cbSDimitry Andric     return "Delta32FromGOT";
33*700637cbSDimitry Andric   case RequestGOTAndTransformToDelta32FromGOT:
34*700637cbSDimitry Andric     return "RequestGOTAndTransformToDelta32FromGOT";
35*700637cbSDimitry Andric   case BranchPCRel32:
36*700637cbSDimitry Andric     return "BranchPCRel32";
37*700637cbSDimitry Andric   case BranchPCRel32ToPtrJumpStub:
38*700637cbSDimitry Andric     return "BranchPCRel32ToPtrJumpStub";
39*700637cbSDimitry Andric   case BranchPCRel32ToPtrJumpStubBypassable:
40*700637cbSDimitry Andric     return "BranchPCRel32ToPtrJumpStubBypassable";
41*700637cbSDimitry Andric   }
42*700637cbSDimitry Andric 
43*700637cbSDimitry Andric   return getGenericEdgeKindName(K);
44*700637cbSDimitry Andric }
45*700637cbSDimitry Andric 
46*700637cbSDimitry Andric const char NullPointerContent[PointerSize] = {0x00, 0x00, 0x00, 0x00};
47*700637cbSDimitry Andric 
48*700637cbSDimitry Andric const char PointerJumpStubContent[6] = {
49*700637cbSDimitry Andric     static_cast<char>(0xFFu), 0x25, 0x00, 0x00, 0x00, 0x00};
50*700637cbSDimitry Andric 
optimizeGOTAndStubAccesses(LinkGraph & G)51*700637cbSDimitry Andric Error optimizeGOTAndStubAccesses(LinkGraph &G) {
52*700637cbSDimitry Andric   LLVM_DEBUG(dbgs() << "Optimizing GOT entries and stubs:\n");
53*700637cbSDimitry Andric 
54*700637cbSDimitry Andric   for (auto *B : G.blocks())
55*700637cbSDimitry Andric     for (auto &E : B->edges()) {
56*700637cbSDimitry Andric       if (E.getKind() == BranchPCRel32ToPtrJumpStubBypassable) {
57*700637cbSDimitry Andric         auto &StubBlock = E.getTarget().getBlock();
58*700637cbSDimitry Andric         assert(StubBlock.getSize() == sizeof(PointerJumpStubContent) &&
59*700637cbSDimitry Andric                "Stub block should be stub sized");
60*700637cbSDimitry Andric         assert(StubBlock.edges_size() == 1 &&
61*700637cbSDimitry Andric                "Stub block should only have one outgoing edge");
62*700637cbSDimitry Andric 
63*700637cbSDimitry Andric         auto &GOTBlock = StubBlock.edges().begin()->getTarget().getBlock();
64*700637cbSDimitry Andric         assert(GOTBlock.getSize() == G.getPointerSize() &&
65*700637cbSDimitry Andric                "GOT block should be pointer sized");
66*700637cbSDimitry Andric         assert(GOTBlock.edges_size() == 1 &&
67*700637cbSDimitry Andric                "GOT block should only have one outgoing edge");
68*700637cbSDimitry Andric 
69*700637cbSDimitry Andric         auto &GOTTarget = GOTBlock.edges().begin()->getTarget();
70*700637cbSDimitry Andric         orc::ExecutorAddr EdgeAddr = B->getAddress() + E.getOffset();
71*700637cbSDimitry Andric         orc::ExecutorAddr TargetAddr = GOTTarget.getAddress();
72*700637cbSDimitry Andric 
73*700637cbSDimitry Andric         int64_t Displacement = TargetAddr - EdgeAddr + 4;
74*700637cbSDimitry Andric         if (isInt<32>(Displacement)) {
75*700637cbSDimitry Andric           E.setKind(BranchPCRel32);
76*700637cbSDimitry Andric           E.setTarget(GOTTarget);
77*700637cbSDimitry Andric           LLVM_DEBUG({
78*700637cbSDimitry Andric             dbgs() << "  Replaced stub branch with direct branch:\n    ";
79*700637cbSDimitry Andric             printEdge(dbgs(), *B, E, getEdgeKindName(E.getKind()));
80*700637cbSDimitry Andric             dbgs() << "\n";
81*700637cbSDimitry Andric           });
82*700637cbSDimitry Andric         }
83*700637cbSDimitry Andric       }
84*700637cbSDimitry Andric     }
85*700637cbSDimitry Andric 
86*700637cbSDimitry Andric   return Error::success();
87*700637cbSDimitry Andric }
88*700637cbSDimitry Andric 
89*700637cbSDimitry Andric } // namespace llvm::jitlink::x86
90