1312425f3SRichard Sandiford //===-- SystemZLongBranch.cpp - Branch lengthening for SystemZ ------------===//
2312425f3SRichard Sandiford //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6312425f3SRichard Sandiford //
7312425f3SRichard Sandiford //===----------------------------------------------------------------------===//
8312425f3SRichard Sandiford //
9bdbb8af7SRichard Sandiford // This pass makes sure that all branches are in range. There are several ways
10bdbb8af7SRichard Sandiford // in which this could be done. One aggressive approach is to assume that all
11bdbb8af7SRichard Sandiford // branches are in range and successively replace those that turn out not
12bdbb8af7SRichard Sandiford // to be in range with a longer form (branch relaxation). A simple
13bdbb8af7SRichard Sandiford // implementation is to continually walk through the function relaxing
14bdbb8af7SRichard Sandiford // branches until no more changes are needed and a fixed point is reached.
15bdbb8af7SRichard Sandiford // However, in the pathological worst case, this implementation is
16bdbb8af7SRichard Sandiford // quadratic in the number of blocks; relaxing branch N can make branch N-1
17bdbb8af7SRichard Sandiford // go out of range, which in turn can make branch N-2 go out of range,
18bdbb8af7SRichard Sandiford // and so on.
19312425f3SRichard Sandiford //
20312425f3SRichard Sandiford // An alternative approach is to assume that all branches must be
21312425f3SRichard Sandiford // converted to their long forms, then reinstate the short forms of
22312425f3SRichard Sandiford // branches that, even under this pessimistic assumption, turn out to be
23312425f3SRichard Sandiford // in range (branch shortening). This too can be implemented as a function
24312425f3SRichard Sandiford // walk that is repeated until a fixed point is reached. In general,
25312425f3SRichard Sandiford // the result of shortening is not as good as that of relaxation, and
26312425f3SRichard Sandiford // shortening is also quadratic in the worst case; shortening branch N
27312425f3SRichard Sandiford // can bring branch N-1 in range of the short form, which in turn can do
28312425f3SRichard Sandiford // the same for branch N-2, and so on. The main advantage of shortening
29312425f3SRichard Sandiford // is that each walk through the function produces valid code, so it is
30312425f3SRichard Sandiford // possible to stop at any point after the first walk. The quadraticness
31312425f3SRichard Sandiford // could therefore be handled with a maximum pass count, although the
32312425f3SRichard Sandiford // question then becomes: what maximum count should be used?
33312425f3SRichard Sandiford //
34312425f3SRichard Sandiford // On SystemZ, long branches are only needed for functions bigger than 64k,
35312425f3SRichard Sandiford // which are relatively rare to begin with, and the long branch sequences
36312425f3SRichard Sandiford // are actually relatively cheap. It therefore doesn't seem worth spending
37312425f3SRichard Sandiford // much compilation time on the problem. Instead, the approach we take is:
38312425f3SRichard Sandiford //
3903528f34SRichard Sandiford // (1) Work out the address that each block would have if no branches
4003528f34SRichard Sandiford // need relaxing. Exit the pass early if all branches are in range
4103528f34SRichard Sandiford // according to this assumption.
4203528f34SRichard Sandiford //
4303528f34SRichard Sandiford // (2) Work out the address that each block would have if all branches
4403528f34SRichard Sandiford // need relaxing.
4503528f34SRichard Sandiford //
4603528f34SRichard Sandiford // (3) Walk through the block calculating the final address of each instruction
4703528f34SRichard Sandiford // and relaxing those that need to be relaxed. For backward branches,
4803528f34SRichard Sandiford // this check uses the final address of the target block, as calculated
4903528f34SRichard Sandiford // earlier in the walk. For forward branches, this check uses the
5003528f34SRichard Sandiford // address of the target block that was calculated in (2). Both checks
5103528f34SRichard Sandiford // give a conservatively-correct range.
52312425f3SRichard Sandiford //
53312425f3SRichard Sandiford //===----------------------------------------------------------------------===//
54312425f3SRichard Sandiford
553943d2b0SEugene Zelenko #include "SystemZ.h"
563943d2b0SEugene Zelenko #include "SystemZInstrInfo.h"
57312425f3SRichard Sandiford #include "SystemZTargetMachine.h"
583943d2b0SEugene Zelenko #include "llvm/ADT/SmallVector.h"
59312425f3SRichard Sandiford #include "llvm/ADT/Statistic.h"
603943d2b0SEugene Zelenko #include "llvm/ADT/StringRef.h"
613943d2b0SEugene Zelenko #include "llvm/CodeGen/MachineBasicBlock.h"
623943d2b0SEugene Zelenko #include "llvm/CodeGen/MachineFunction.h"
63312425f3SRichard Sandiford #include "llvm/CodeGen/MachineFunctionPass.h"
643943d2b0SEugene Zelenko #include "llvm/CodeGen/MachineInstr.h"
65312425f3SRichard Sandiford #include "llvm/CodeGen/MachineInstrBuilder.h"
663943d2b0SEugene Zelenko #include "llvm/IR/DebugLoc.h"
673943d2b0SEugene Zelenko #include "llvm/Support/ErrorHandling.h"
683943d2b0SEugene Zelenko #include <cassert>
693943d2b0SEugene Zelenko #include <cstdint>
70312425f3SRichard Sandiford
71312425f3SRichard Sandiford using namespace llvm;
72312425f3SRichard Sandiford
7384e68b29SChandler Carruth #define DEBUG_TYPE "systemz-long-branch"
7484e68b29SChandler Carruth
75312425f3SRichard Sandiford STATISTIC(LongBranches, "Number of long branches.");
76312425f3SRichard Sandiford
77312425f3SRichard Sandiford namespace {
783943d2b0SEugene Zelenko
79312425f3SRichard Sandiford // Represents positional information about a basic block.
80312425f3SRichard Sandiford struct MBBInfo {
8103528f34SRichard Sandiford // The address that we currently assume the block has.
823943d2b0SEugene Zelenko uint64_t Address = 0;
83312425f3SRichard Sandiford
84312425f3SRichard Sandiford // The size of the block in bytes, excluding terminators.
85312425f3SRichard Sandiford // This value never changes.
863943d2b0SEugene Zelenko uint64_t Size = 0;
87312425f3SRichard Sandiford
88d4c4671aSGuillaume Chatelet // The minimum alignment of the block.
89312425f3SRichard Sandiford // This value never changes.
9018f805a7SGuillaume Chatelet Align Alignment;
91312425f3SRichard Sandiford
92312425f3SRichard Sandiford // The number of terminators in this block. This value never changes.
933943d2b0SEugene Zelenko unsigned NumTerminators = 0;
94312425f3SRichard Sandiford
953943d2b0SEugene Zelenko MBBInfo() = default;
96312425f3SRichard Sandiford };
97312425f3SRichard Sandiford
98312425f3SRichard Sandiford // Represents the state of a block terminator.
99312425f3SRichard Sandiford struct TerminatorInfo {
100312425f3SRichard Sandiford // If this terminator is a relaxable branch, this points to the branch
101312425f3SRichard Sandiford // instruction, otherwise it is null.
1023943d2b0SEugene Zelenko MachineInstr *Branch = nullptr;
103312425f3SRichard Sandiford
10403528f34SRichard Sandiford // The address that we currently assume the terminator has.
1053943d2b0SEugene Zelenko uint64_t Address = 0;
106312425f3SRichard Sandiford
107312425f3SRichard Sandiford // The current size of the terminator in bytes.
1083943d2b0SEugene Zelenko uint64_t Size = 0;
109312425f3SRichard Sandiford
110312425f3SRichard Sandiford // If Branch is nonnull, this is the number of the target block,
111312425f3SRichard Sandiford // otherwise it is unused.
1123943d2b0SEugene Zelenko unsigned TargetBlock = 0;
113312425f3SRichard Sandiford
114312425f3SRichard Sandiford // If Branch is nonnull, this is the length of the longest relaxed form,
115312425f3SRichard Sandiford // otherwise it is zero.
1163943d2b0SEugene Zelenko unsigned ExtraRelaxSize = 0;
117312425f3SRichard Sandiford
1183943d2b0SEugene Zelenko TerminatorInfo() = default;
119312425f3SRichard Sandiford };
120312425f3SRichard Sandiford
121312425f3SRichard Sandiford // Used to keep track of the current position while iterating over the blocks.
122312425f3SRichard Sandiford struct BlockPosition {
12303528f34SRichard Sandiford // The address that we assume this position has.
1243943d2b0SEugene Zelenko uint64_t Address = 0;
125312425f3SRichard Sandiford
126312425f3SRichard Sandiford // The number of low bits in Address that are known to be the same
127312425f3SRichard Sandiford // as the runtime address.
128312425f3SRichard Sandiford unsigned KnownBits;
129312425f3SRichard Sandiford
BlockPosition__anon9324c0210111::BlockPosition130aff45e4bSGuillaume Chatelet BlockPosition(unsigned InitialLogAlignment)
131aff45e4bSGuillaume Chatelet : KnownBits(InitialLogAlignment) {}
132312425f3SRichard Sandiford };
133312425f3SRichard Sandiford
134312425f3SRichard Sandiford class SystemZLongBranch : public MachineFunctionPass {
135312425f3SRichard Sandiford public:
136312425f3SRichard Sandiford static char ID;
1373943d2b0SEugene Zelenko
SystemZLongBranch()138*d5ae039eSKai Nacke SystemZLongBranch() : MachineFunctionPass(ID) {
139*d5ae039eSKai Nacke initializeSystemZLongBranchPass(*PassRegistry::getPassRegistry());
140*d5ae039eSKai Nacke }
141312425f3SRichard Sandiford
1429d74a5a5SCraig Topper bool runOnMachineFunction(MachineFunction &F) override;
1433943d2b0SEugene Zelenko
getRequiredProperties() const1441dbf7a57SDerek Schuff MachineFunctionProperties getRequiredProperties() const override {
1451dbf7a57SDerek Schuff return MachineFunctionProperties().set(
1461eb47368SMatthias Braun MachineFunctionProperties::Property::NoVRegs);
1471dbf7a57SDerek Schuff }
148312425f3SRichard Sandiford
149312425f3SRichard Sandiford private:
150312425f3SRichard Sandiford void skipNonTerminators(BlockPosition &Position, MBBInfo &Block);
151312425f3SRichard Sandiford void skipTerminator(BlockPosition &Position, TerminatorInfo &Terminator,
152312425f3SRichard Sandiford bool AssumeRelaxed);
1539cfc75c2SDuncan P. N. Exon Smith TerminatorInfo describeTerminator(MachineInstr &MI);
154312425f3SRichard Sandiford uint64_t initMBBInfo();
15503528f34SRichard Sandiford bool mustRelaxBranch(const TerminatorInfo &Terminator, uint64_t Address);
156312425f3SRichard Sandiford bool mustRelaxABranch();
157312425f3SRichard Sandiford void setWorstCaseAddresses();
158c212125dSRichard Sandiford void splitBranchOnCount(MachineInstr *MI, unsigned AddOpcode);
1590fb90ab0SRichard Sandiford void splitCompareBranch(MachineInstr *MI, unsigned CompareOpcode);
160312425f3SRichard Sandiford void relaxBranch(TerminatorInfo &Terminator);
161312425f3SRichard Sandiford void relaxBranches();
162312425f3SRichard Sandiford
1633943d2b0SEugene Zelenko const SystemZInstrInfo *TII = nullptr;
164e1670175SSimon Pilgrim MachineFunction *MF = nullptr;
165312425f3SRichard Sandiford SmallVector<MBBInfo, 16> MBBs;
166312425f3SRichard Sandiford SmallVector<TerminatorInfo, 16> Terminators;
167312425f3SRichard Sandiford };
168312425f3SRichard Sandiford
169312425f3SRichard Sandiford char SystemZLongBranch::ID = 0;
170312425f3SRichard Sandiford
171312425f3SRichard Sandiford const uint64_t MaxBackwardRange = 0x10000;
172312425f3SRichard Sandiford const uint64_t MaxForwardRange = 0xfffe;
173312425f3SRichard Sandiford
1743943d2b0SEugene Zelenko } // end anonymous namespace
175312425f3SRichard Sandiford
176*d5ae039eSKai Nacke INITIALIZE_PASS(SystemZLongBranch, DEBUG_TYPE, "SystemZ Long Branch", false,
177*d5ae039eSKai Nacke false)
178*d5ae039eSKai Nacke
179312425f3SRichard Sandiford // Position describes the state immediately before Block. Update Block
180312425f3SRichard Sandiford // accordingly and move Position to the end of the block's non-terminator
181312425f3SRichard Sandiford // instructions.
skipNonTerminators(BlockPosition & Position,MBBInfo & Block)182312425f3SRichard Sandiford void SystemZLongBranch::skipNonTerminators(BlockPosition &Position,
183312425f3SRichard Sandiford MBBInfo &Block) {
184d4c4671aSGuillaume Chatelet if (Log2(Block.Alignment) > Position.KnownBits) {
185312425f3SRichard Sandiford // When calculating the address of Block, we need to conservatively
186312425f3SRichard Sandiford // assume that Block had the worst possible misalignment.
187d4c4671aSGuillaume Chatelet Position.Address +=
188d4c4671aSGuillaume Chatelet (Block.Alignment.value() - (uint64_t(1) << Position.KnownBits));
189d4c4671aSGuillaume Chatelet Position.KnownBits = Log2(Block.Alignment);
190312425f3SRichard Sandiford }
191312425f3SRichard Sandiford
192312425f3SRichard Sandiford // Align the addresses.
193d4c4671aSGuillaume Chatelet Position.Address = alignTo(Position.Address, Block.Alignment);
194312425f3SRichard Sandiford
195312425f3SRichard Sandiford // Record the block's position.
196312425f3SRichard Sandiford Block.Address = Position.Address;
197312425f3SRichard Sandiford
198312425f3SRichard Sandiford // Move past the non-terminators in the block.
199312425f3SRichard Sandiford Position.Address += Block.Size;
200312425f3SRichard Sandiford }
201312425f3SRichard Sandiford
202312425f3SRichard Sandiford // Position describes the state immediately before Terminator.
203312425f3SRichard Sandiford // Update Terminator accordingly and move Position past it.
204312425f3SRichard Sandiford // Assume that Terminator will be relaxed if AssumeRelaxed.
skipTerminator(BlockPosition & Position,TerminatorInfo & Terminator,bool AssumeRelaxed)205312425f3SRichard Sandiford void SystemZLongBranch::skipTerminator(BlockPosition &Position,
206312425f3SRichard Sandiford TerminatorInfo &Terminator,
207312425f3SRichard Sandiford bool AssumeRelaxed) {
208312425f3SRichard Sandiford Terminator.Address = Position.Address;
209312425f3SRichard Sandiford Position.Address += Terminator.Size;
210312425f3SRichard Sandiford if (AssumeRelaxed)
211312425f3SRichard Sandiford Position.Address += Terminator.ExtraRelaxSize;
212312425f3SRichard Sandiford }
213312425f3SRichard Sandiford
getInstSizeInBytes(const MachineInstr & MI,const SystemZInstrInfo * TII)2149f887277SJonas Paulsson static unsigned getInstSizeInBytes(const MachineInstr &MI,
2159f887277SJonas Paulsson const SystemZInstrInfo *TII) {
2169f887277SJonas Paulsson unsigned Size = TII->getInstSizeInBytes(MI);
2179f887277SJonas Paulsson assert((Size ||
2189f887277SJonas Paulsson // These do not have a size:
2199f887277SJonas Paulsson MI.isDebugOrPseudoInstr() || MI.isPosition() || MI.isKill() ||
2209f887277SJonas Paulsson MI.isImplicitDef() || MI.getOpcode() == SystemZ::MemBarrier ||
2219f887277SJonas Paulsson // These have a size that may be zero:
2229f887277SJonas Paulsson MI.isInlineAsm() || MI.getOpcode() == SystemZ::STACKMAP ||
2239f887277SJonas Paulsson MI.getOpcode() == SystemZ::PATCHPOINT) &&
2249f887277SJonas Paulsson "Missing size value for instruction.");
2259f887277SJonas Paulsson return Size;
2269f887277SJonas Paulsson }
2279f887277SJonas Paulsson
228312425f3SRichard Sandiford // Return a description of terminator instruction MI.
describeTerminator(MachineInstr & MI)2299cfc75c2SDuncan P. N. Exon Smith TerminatorInfo SystemZLongBranch::describeTerminator(MachineInstr &MI) {
230312425f3SRichard Sandiford TerminatorInfo Terminator;
2319f887277SJonas Paulsson Terminator.Size = getInstSizeInBytes(MI, TII);
2329cfc75c2SDuncan P. N. Exon Smith if (MI.isConditionalBranch() || MI.isUnconditionalBranch()) {
2339cfc75c2SDuncan P. N. Exon Smith switch (MI.getOpcode()) {
234312425f3SRichard Sandiford case SystemZ::J:
235312425f3SRichard Sandiford // Relaxes to JG, which is 2 bytes longer.
236312425f3SRichard Sandiford Terminator.ExtraRelaxSize = 2;
237312425f3SRichard Sandiford break;
238312425f3SRichard Sandiford case SystemZ::BRC:
23953c9efd9SRichard Sandiford // Relaxes to BRCL, which is 2 bytes longer.
240312425f3SRichard Sandiford Terminator.ExtraRelaxSize = 2;
241312425f3SRichard Sandiford break;
242c212125dSRichard Sandiford case SystemZ::BRCT:
243c212125dSRichard Sandiford case SystemZ::BRCTG:
244c212125dSRichard Sandiford // Relaxes to A(G)HI and BRCL, which is 6 bytes longer.
245c212125dSRichard Sandiford Terminator.ExtraRelaxSize = 6;
246c212125dSRichard Sandiford break;
24775839913SUlrich Weigand case SystemZ::BRCTH:
24875839913SUlrich Weigand // Never needs to be relaxed.
24975839913SUlrich Weigand Terminator.ExtraRelaxSize = 0;
25075839913SUlrich Weigand break;
2510fb90ab0SRichard Sandiford case SystemZ::CRJ:
25293183ee7SRichard Sandiford case SystemZ::CLRJ:
25393183ee7SRichard Sandiford // Relaxes to a C(L)R/BRCL sequence, which is 2 bytes longer.
2540fb90ab0SRichard Sandiford Terminator.ExtraRelaxSize = 2;
2550fb90ab0SRichard Sandiford break;
2560fb90ab0SRichard Sandiford case SystemZ::CGRJ:
25793183ee7SRichard Sandiford case SystemZ::CLGRJ:
25893183ee7SRichard Sandiford // Relaxes to a C(L)GR/BRCL sequence, which is 4 bytes longer.
2590fb90ab0SRichard Sandiford Terminator.ExtraRelaxSize = 4;
2600fb90ab0SRichard Sandiford break;
261e1d9f00fSRichard Sandiford case SystemZ::CIJ:
262e1d9f00fSRichard Sandiford case SystemZ::CGIJ:
263e1d9f00fSRichard Sandiford // Relaxes to a C(G)HI/BRCL sequence, which is 4 bytes longer.
264e1d9f00fSRichard Sandiford Terminator.ExtraRelaxSize = 4;
265e1d9f00fSRichard Sandiford break;
26693183ee7SRichard Sandiford case SystemZ::CLIJ:
26793183ee7SRichard Sandiford case SystemZ::CLGIJ:
26893183ee7SRichard Sandiford // Relaxes to a CL(G)FI/BRCL sequence, which is 6 bytes longer.
26993183ee7SRichard Sandiford Terminator.ExtraRelaxSize = 6;
27093183ee7SRichard Sandiford break;
271312425f3SRichard Sandiford default:
272312425f3SRichard Sandiford llvm_unreachable("Unrecognized branch instruction");
273312425f3SRichard Sandiford }
2749cfc75c2SDuncan P. N. Exon Smith Terminator.Branch = &MI;
27553c9efd9SRichard Sandiford Terminator.TargetBlock =
27682185878SJonas Paulsson TII->getBranchInfo(MI).getMBBTarget()->getNumber();
277312425f3SRichard Sandiford }
278312425f3SRichard Sandiford return Terminator;
279312425f3SRichard Sandiford }
280312425f3SRichard Sandiford
281312425f3SRichard Sandiford // Fill MBBs and Terminators, setting the addresses on the assumption
282312425f3SRichard Sandiford // that no branches need relaxation. Return the size of the function under
283312425f3SRichard Sandiford // this assumption.
initMBBInfo()284312425f3SRichard Sandiford uint64_t SystemZLongBranch::initMBBInfo() {
285312425f3SRichard Sandiford MF->RenumberBlocks();
286312425f3SRichard Sandiford unsigned NumBlocks = MF->size();
287312425f3SRichard Sandiford
288312425f3SRichard Sandiford MBBs.clear();
289312425f3SRichard Sandiford MBBs.resize(NumBlocks);
290312425f3SRichard Sandiford
291312425f3SRichard Sandiford Terminators.clear();
292312425f3SRichard Sandiford Terminators.reserve(NumBlocks);
293312425f3SRichard Sandiford
29448904e94SGuillaume Chatelet BlockPosition Position(Log2(MF->getAlignment()));
295312425f3SRichard Sandiford for (unsigned I = 0; I < NumBlocks; ++I) {
296312425f3SRichard Sandiford MachineBasicBlock *MBB = MF->getBlockNumbered(I);
297312425f3SRichard Sandiford MBBInfo &Block = MBBs[I];
298312425f3SRichard Sandiford
299312425f3SRichard Sandiford // Record the alignment, for quick access.
300d4c4671aSGuillaume Chatelet Block.Alignment = MBB->getAlignment();
301312425f3SRichard Sandiford
302312425f3SRichard Sandiford // Calculate the size of the fixed part of the block.
303312425f3SRichard Sandiford MachineBasicBlock::iterator MI = MBB->begin();
304312425f3SRichard Sandiford MachineBasicBlock::iterator End = MBB->end();
305312425f3SRichard Sandiford while (MI != End && !MI->isTerminator()) {
3069f887277SJonas Paulsson Block.Size += getInstSizeInBytes(*MI, TII);
307312425f3SRichard Sandiford ++MI;
308312425f3SRichard Sandiford }
309312425f3SRichard Sandiford skipNonTerminators(Position, Block);
310312425f3SRichard Sandiford
311312425f3SRichard Sandiford // Add the terminators.
312312425f3SRichard Sandiford while (MI != End) {
313801bf7ebSShiva Chen if (!MI->isDebugInstr()) {
314312425f3SRichard Sandiford assert(MI->isTerminator() && "Terminator followed by non-terminator");
3159cfc75c2SDuncan P. N. Exon Smith Terminators.push_back(describeTerminator(*MI));
316312425f3SRichard Sandiford skipTerminator(Position, Terminators.back(), false);
317312425f3SRichard Sandiford ++Block.NumTerminators;
318312425f3SRichard Sandiford }
319312425f3SRichard Sandiford ++MI;
320312425f3SRichard Sandiford }
321312425f3SRichard Sandiford }
322312425f3SRichard Sandiford
323312425f3SRichard Sandiford return Position.Address;
324312425f3SRichard Sandiford }
325312425f3SRichard Sandiford
32603528f34SRichard Sandiford // Return true if, under current assumptions, Terminator would need to be
32703528f34SRichard Sandiford // relaxed if it were placed at address Address.
mustRelaxBranch(const TerminatorInfo & Terminator,uint64_t Address)32803528f34SRichard Sandiford bool SystemZLongBranch::mustRelaxBranch(const TerminatorInfo &Terminator,
32903528f34SRichard Sandiford uint64_t Address) {
330ef785694SJonas Paulsson if (!Terminator.Branch || Terminator.ExtraRelaxSize == 0)
331312425f3SRichard Sandiford return false;
332312425f3SRichard Sandiford
333312425f3SRichard Sandiford const MBBInfo &Target = MBBs[Terminator.TargetBlock];
33403528f34SRichard Sandiford if (Address >= Target.Address) {
33503528f34SRichard Sandiford if (Address - Target.Address <= MaxBackwardRange)
336312425f3SRichard Sandiford return false;
337312425f3SRichard Sandiford } else {
33803528f34SRichard Sandiford if (Target.Address - Address <= MaxForwardRange)
339312425f3SRichard Sandiford return false;
340312425f3SRichard Sandiford }
341312425f3SRichard Sandiford
342312425f3SRichard Sandiford return true;
343312425f3SRichard Sandiford }
344312425f3SRichard Sandiford
345312425f3SRichard Sandiford // Return true if, under current assumptions, any terminator needs
346312425f3SRichard Sandiford // to be relaxed.
mustRelaxABranch()347312425f3SRichard Sandiford bool SystemZLongBranch::mustRelaxABranch() {
34828c111ecSRichard Sandiford for (auto &Terminator : Terminators)
34928c111ecSRichard Sandiford if (mustRelaxBranch(Terminator, Terminator.Address))
350312425f3SRichard Sandiford return true;
351312425f3SRichard Sandiford return false;
352312425f3SRichard Sandiford }
353312425f3SRichard Sandiford
354312425f3SRichard Sandiford // Set the address of each block on the assumption that all branches
355312425f3SRichard Sandiford // must be long.
setWorstCaseAddresses()356312425f3SRichard Sandiford void SystemZLongBranch::setWorstCaseAddresses() {
357312425f3SRichard Sandiford SmallVector<TerminatorInfo, 16>::iterator TI = Terminators.begin();
35848904e94SGuillaume Chatelet BlockPosition Position(Log2(MF->getAlignment()));
35928c111ecSRichard Sandiford for (auto &Block : MBBs) {
36028c111ecSRichard Sandiford skipNonTerminators(Position, Block);
36128c111ecSRichard Sandiford for (unsigned BTI = 0, BTE = Block.NumTerminators; BTI != BTE; ++BTI) {
362312425f3SRichard Sandiford skipTerminator(Position, *TI, true);
363312425f3SRichard Sandiford ++TI;
364312425f3SRichard Sandiford }
365312425f3SRichard Sandiford }
366312425f3SRichard Sandiford }
367312425f3SRichard Sandiford
368c212125dSRichard Sandiford // Split BRANCH ON COUNT MI into the addition given by AddOpcode followed
369c212125dSRichard Sandiford // by a BRCL on the result.
splitBranchOnCount(MachineInstr * MI,unsigned AddOpcode)370c212125dSRichard Sandiford void SystemZLongBranch::splitBranchOnCount(MachineInstr *MI,
371c212125dSRichard Sandiford unsigned AddOpcode) {
372c212125dSRichard Sandiford MachineBasicBlock *MBB = MI->getParent();
373c212125dSRichard Sandiford DebugLoc DL = MI->getDebugLoc();
374c212125dSRichard Sandiford BuildMI(*MBB, MI, DL, TII->get(AddOpcode))
375116bbab4SDiana Picus .add(MI->getOperand(0))
376116bbab4SDiana Picus .add(MI->getOperand(1))
377c212125dSRichard Sandiford .addImm(-1);
378c212125dSRichard Sandiford MachineInstr *BRCL = BuildMI(*MBB, MI, DL, TII->get(SystemZ::BRCL))
379c212125dSRichard Sandiford .addImm(SystemZ::CCMASK_ICMP)
380c212125dSRichard Sandiford .addImm(SystemZ::CCMASK_CMP_NE)
381116bbab4SDiana Picus .add(MI->getOperand(2));
382c212125dSRichard Sandiford // The implicit use of CC is a killing use.
383c212125dSRichard Sandiford BRCL->addRegisterKilled(SystemZ::CC, &TII->getRegisterInfo());
384c212125dSRichard Sandiford MI->eraseFromParent();
385c212125dSRichard Sandiford }
386c212125dSRichard Sandiford
3870fb90ab0SRichard Sandiford // Split MI into the comparison given by CompareOpcode followed
3880fb90ab0SRichard Sandiford // a BRCL on the result.
splitCompareBranch(MachineInstr * MI,unsigned CompareOpcode)3890fb90ab0SRichard Sandiford void SystemZLongBranch::splitCompareBranch(MachineInstr *MI,
3900fb90ab0SRichard Sandiford unsigned CompareOpcode) {
3910fb90ab0SRichard Sandiford MachineBasicBlock *MBB = MI->getParent();
3920fb90ab0SRichard Sandiford DebugLoc DL = MI->getDebugLoc();
3930fb90ab0SRichard Sandiford BuildMI(*MBB, MI, DL, TII->get(CompareOpcode))
394116bbab4SDiana Picus .add(MI->getOperand(0))
395116bbab4SDiana Picus .add(MI->getOperand(1));
3960fb90ab0SRichard Sandiford MachineInstr *BRCL = BuildMI(*MBB, MI, DL, TII->get(SystemZ::BRCL))
3973d768e33SRichard Sandiford .addImm(SystemZ::CCMASK_ICMP)
398116bbab4SDiana Picus .add(MI->getOperand(2))
399116bbab4SDiana Picus .add(MI->getOperand(3));
4000fb90ab0SRichard Sandiford // The implicit use of CC is a killing use.
4013d768e33SRichard Sandiford BRCL->addRegisterKilled(SystemZ::CC, &TII->getRegisterInfo());
4020fb90ab0SRichard Sandiford MI->eraseFromParent();
4030fb90ab0SRichard Sandiford }
4040fb90ab0SRichard Sandiford
405312425f3SRichard Sandiford // Relax the branch described by Terminator.
relaxBranch(TerminatorInfo & Terminator)406312425f3SRichard Sandiford void SystemZLongBranch::relaxBranch(TerminatorInfo &Terminator) {
407312425f3SRichard Sandiford MachineInstr *Branch = Terminator.Branch;
408312425f3SRichard Sandiford switch (Branch->getOpcode()) {
409312425f3SRichard Sandiford case SystemZ::J:
410312425f3SRichard Sandiford Branch->setDesc(TII->get(SystemZ::JG));
411312425f3SRichard Sandiford break;
412312425f3SRichard Sandiford case SystemZ::BRC:
413312425f3SRichard Sandiford Branch->setDesc(TII->get(SystemZ::BRCL));
414312425f3SRichard Sandiford break;
415c212125dSRichard Sandiford case SystemZ::BRCT:
416c212125dSRichard Sandiford splitBranchOnCount(Branch, SystemZ::AHI);
417c212125dSRichard Sandiford break;
418c212125dSRichard Sandiford case SystemZ::BRCTG:
419c212125dSRichard Sandiford splitBranchOnCount(Branch, SystemZ::AGHI);
420c212125dSRichard Sandiford break;
4210fb90ab0SRichard Sandiford case SystemZ::CRJ:
4220fb90ab0SRichard Sandiford splitCompareBranch(Branch, SystemZ::CR);
4230fb90ab0SRichard Sandiford break;
4240fb90ab0SRichard Sandiford case SystemZ::CGRJ:
4250fb90ab0SRichard Sandiford splitCompareBranch(Branch, SystemZ::CGR);
4260fb90ab0SRichard Sandiford break;
427e1d9f00fSRichard Sandiford case SystemZ::CIJ:
428e1d9f00fSRichard Sandiford splitCompareBranch(Branch, SystemZ::CHI);
429e1d9f00fSRichard Sandiford break;
430e1d9f00fSRichard Sandiford case SystemZ::CGIJ:
431e1d9f00fSRichard Sandiford splitCompareBranch(Branch, SystemZ::CGHI);
432e1d9f00fSRichard Sandiford break;
43393183ee7SRichard Sandiford case SystemZ::CLRJ:
43493183ee7SRichard Sandiford splitCompareBranch(Branch, SystemZ::CLR);
43593183ee7SRichard Sandiford break;
43693183ee7SRichard Sandiford case SystemZ::CLGRJ:
43793183ee7SRichard Sandiford splitCompareBranch(Branch, SystemZ::CLGR);
43893183ee7SRichard Sandiford break;
43993183ee7SRichard Sandiford case SystemZ::CLIJ:
44093183ee7SRichard Sandiford splitCompareBranch(Branch, SystemZ::CLFI);
44193183ee7SRichard Sandiford break;
44293183ee7SRichard Sandiford case SystemZ::CLGIJ:
44393183ee7SRichard Sandiford splitCompareBranch(Branch, SystemZ::CLGFI);
44493183ee7SRichard Sandiford break;
445312425f3SRichard Sandiford default:
446312425f3SRichard Sandiford llvm_unreachable("Unrecognized branch");
447312425f3SRichard Sandiford }
448312425f3SRichard Sandiford
449312425f3SRichard Sandiford Terminator.Size += Terminator.ExtraRelaxSize;
450312425f3SRichard Sandiford Terminator.ExtraRelaxSize = 0;
451062a2baeSCraig Topper Terminator.Branch = nullptr;
452312425f3SRichard Sandiford
453312425f3SRichard Sandiford ++LongBranches;
454312425f3SRichard Sandiford }
455312425f3SRichard Sandiford
45603528f34SRichard Sandiford // Run a shortening pass and relax any branches that need to be relaxed.
relaxBranches()457312425f3SRichard Sandiford void SystemZLongBranch::relaxBranches() {
45803528f34SRichard Sandiford SmallVector<TerminatorInfo, 16>::iterator TI = Terminators.begin();
45948904e94SGuillaume Chatelet BlockPosition Position(Log2(MF->getAlignment()));
46028c111ecSRichard Sandiford for (auto &Block : MBBs) {
46128c111ecSRichard Sandiford skipNonTerminators(Position, Block);
46228c111ecSRichard Sandiford for (unsigned BTI = 0, BTE = Block.NumTerminators; BTI != BTE; ++BTI) {
46303528f34SRichard Sandiford assert(Position.Address <= TI->Address &&
46403528f34SRichard Sandiford "Addresses shouldn't go forwards");
46503528f34SRichard Sandiford if (mustRelaxBranch(*TI, Position.Address))
466312425f3SRichard Sandiford relaxBranch(*TI);
46703528f34SRichard Sandiford skipTerminator(Position, *TI, false);
46803528f34SRichard Sandiford ++TI;
46903528f34SRichard Sandiford }
47003528f34SRichard Sandiford }
471312425f3SRichard Sandiford }
472312425f3SRichard Sandiford
runOnMachineFunction(MachineFunction & F)473312425f3SRichard Sandiford bool SystemZLongBranch::runOnMachineFunction(MachineFunction &F) {
474fc6de428SEric Christopher TII = static_cast<const SystemZInstrInfo *>(F.getSubtarget().getInstrInfo());
475312425f3SRichard Sandiford MF = &F;
476312425f3SRichard Sandiford uint64_t Size = initMBBInfo();
477312425f3SRichard Sandiford if (Size <= MaxForwardRange || !mustRelaxABranch())
478312425f3SRichard Sandiford return false;
479312425f3SRichard Sandiford
480312425f3SRichard Sandiford setWorstCaseAddresses();
481312425f3SRichard Sandiford relaxBranches();
482312425f3SRichard Sandiford return true;
483312425f3SRichard Sandiford }
4843943d2b0SEugene Zelenko
createSystemZLongBranchPass(SystemZTargetMachine & TM)4853943d2b0SEugene Zelenko FunctionPass *llvm::createSystemZLongBranchPass(SystemZTargetMachine &TM) {
486*d5ae039eSKai Nacke return new SystemZLongBranch();
4873943d2b0SEugene Zelenko }
488