LLVM 20.0.0git
PPCTOCRegDeps.cpp
Go to the documentation of this file.
1//===-- PPCTOCRegDeps.cpp - Add Extra TOC Register Dependencies -----------===//
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// When resolving an address using the ELF ABI TOC pointer, two relocations are
10// generally required: one for the high part and one for the low part. Only
11// the high part generally explicitly depends on r2 (the TOC pointer). And, so,
12// we might produce code like this:
13//
14// .Ltmp526:
15// addis 3, 2, .LC12@toc@ha
16// .Ltmp1628:
17// std 2, 40(1)
18// ld 5, 0(27)
19// ld 2, 8(27)
20// ld 11, 16(27)
21// ld 3, .LC12@toc@l(3)
22// rldicl 4, 4, 0, 32
23// mtctr 5
24// bctrl
25// ld 2, 40(1)
26//
27// And there is nothing wrong with this code, as such, but there is a linker bug
28// in binutils (https://sourceware.org/bugzilla/show_bug.cgi?id=18414) that will
29// misoptimize this code sequence to this:
30// nop
31// std r2,40(r1)
32// ld r5,0(r27)
33// ld r2,8(r27)
34// ld r11,16(r27)
35// ld r3,-32472(r2)
36// clrldi r4,r4,32
37// mtctr r5
38// bctrl
39// ld r2,40(r1)
40// because the linker does not know (and does not check) that the value in r2
41// changed in between the instruction using the .LC12@toc@ha (TOC-relative)
42// relocation and the instruction using the .LC12@toc@l(3) relocation.
43// Because it finds these instructions using the relocations (and not by
44// scanning the instructions), it has been asserted that there is no good way
45// to detect the change of r2 in between. As a result, this bug may never be
46// fixed (i.e. it may become part of the definition of the ABI). GCC was
47// updated to add extra dependencies on r2 to instructions using the @toc@l
48// relocations to avoid this problem, and we'll do the same here.
49//
50// This is done as a separate pass because:
51// 1. These extra r2 dependencies are not really properties of the
52// instructions, but rather due to a linker bug, and maybe one day we'll be
53// able to get rid of them when targeting linkers without this bug (and,
54// thus, keeping the logic centralized here will make that
55// straightforward).
56// 2. There are ISel-level peephole optimizations that propagate the @toc@l
57// relocations to some user instructions, and so the exta dependencies do
58// not apply only to a fixed set of instructions (without undesirable
59// definition replication).
60//
61//===----------------------------------------------------------------------===//
62
64#include "PPC.h"
65#include "PPCInstrBuilder.h"
66#include "PPCInstrInfo.h"
68#include "PPCTargetMachine.h"
69#include "llvm/ADT/STLExtras.h"
70#include "llvm/ADT/Statistic.h"
75#include "llvm/MC/MCAsmInfo.h"
77#include "llvm/Support/Debug.h"
80
81using namespace llvm;
82
83#define DEBUG_TYPE "ppc-toc-reg-deps"
84
85namespace {
86 // PPCTOCRegDeps pass - For simple functions without epilogue code, move
87 // returns up, and create conditional returns, to avoid unnecessary
88 // branch-to-blr sequences.
89 struct PPCTOCRegDeps : public MachineFunctionPass {
90 static char ID;
91 PPCTOCRegDeps() : MachineFunctionPass(ID) {
93 }
94
95protected:
96 bool hasTOCLoReloc(const MachineInstr &MI) {
97 if (MI.getOpcode() == PPC::LDtocL || MI.getOpcode() == PPC::ADDItocL8 ||
98 MI.getOpcode() == PPC::LWZtocL)
99 return true;
100
101 for (const MachineOperand &MO : MI.operands()) {
102 if (MO.getTargetFlags() == PPCII::MO_TOC_LO)
103 return true;
104 }
105
106 return false;
107 }
108
109 bool processBlock(MachineBasicBlock &MBB) {
110 bool Changed = false;
111
112 const bool isPPC64 =
113 MBB.getParent()->getSubtarget<PPCSubtarget>().isPPC64();
114 const unsigned TOCReg = isPPC64 ? PPC::X2 : PPC::R2;
115
116 for (auto &MI : MBB) {
117 if (!hasTOCLoReloc(MI))
118 continue;
119
120 MI.addOperand(MachineOperand::CreateReg(TOCReg,
121 false /*IsDef*/,
122 true /*IsImp*/));
123 Changed = true;
124 }
125
126 return Changed;
127 }
128
129public:
130 bool runOnMachineFunction(MachineFunction &MF) override {
131 bool Changed = false;
132
134 if (processBlock(B))
135 Changed = true;
136
137 return Changed;
138 }
139
140 void getAnalysisUsage(AnalysisUsage &AU) const override {
142 }
143 };
144}
145
146INITIALIZE_PASS(PPCTOCRegDeps, DEBUG_TYPE,
147 "PowerPC TOC Register Dependencies", false, false)
148
149char PPCTOCRegDeps::ID = 0;
151llvm::createPPCTOCRegDepsPass() { return new PPCTOCRegDeps(); }
152
MachineBasicBlock & MBB
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
IRTranslator LLVM IR MI
#define DEBUG_TYPE
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
Definition: PassSupport.h:38
This file contains some templates that are useful if you are working with the STL at all.
This file defines the 'Statistic' class, which is designed to be an easy way to expose various metric...
Represent the analysis usage information of a pass.
FunctionPass class - This class is used to implement most global optimizations.
Definition: Pass.h:310
const MachineFunction * getParent() const
Return the MachineFunction containing this basic block.
MachineFunctionPass - This class adapts the FunctionPass interface to allow convenient creation of pa...
void getAnalysisUsage(AnalysisUsage &AU) const override
getAnalysisUsage - Subclasses that override getAnalysisUsage must call this.
virtual bool runOnMachineFunction(MachineFunction &MF)=0
runOnMachineFunction - This method must be overloaded to perform the desired machine code transformat...
const TargetSubtargetInfo & getSubtarget() const
getSubtarget - Return the subtarget for which this machine code is being compiled.
Representation of each machine instruction.
Definition: MachineInstr.h:69
MachineOperand class - Representation of each machine instruction operand.
static MachineOperand CreateReg(Register Reg, bool isDef, bool isImp=false, bool isKill=false, bool isDead=false, bool isUndef=false, bool isEarlyClobber=false, unsigned SubReg=0, bool isDebug=false, bool isInternalRead=false, bool isRenamable=false)
static PassRegistry * getPassRegistry()
getPassRegistry - Access the global registry object, which is automatically initialized at applicatio...
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
Definition: CallingConv.h:24
@ MO_TOC_LO
Definition: PPC.h:185
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:18
iterator_range< early_inc_iterator_impl< detail::IterOfRange< RangeT > > > make_early_inc_range(RangeT &&Range)
Make a range that does early increment to allow mutation of the underlying range without disrupting i...
Definition: STLExtras.h:656
void initializePPCTOCRegDepsPass(PassRegistry &)
FunctionPass * createPPCTOCRegDepsPass()