//===-- SystemZLongBranch.cpp - Branch lengthening for SystemZ ------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // // This pass makes sure that all branches are in range. There are several ways // in which this could be done. One aggressive approach is to assume that all // branches are in range and successively replace those that turn out not // to be in range with a longer form (branch relaxation). A simple // implementation is to continually walk through the function relaxing // branches until no more changes are needed and a fixed point is reached. // However, in the pathological worst case, this implementation is // quadratic in the number of blocks; relaxing branch N can make branch N-1 // go out of range, which in turn can make branch N-2 go out of range, // and so on. // // An alternative approach is to assume that all branches must be // converted to their long forms, then reinstate the short forms of // branches that, even under this pessimistic assumption, turn out to be // in range (branch shortening). This too can be implemented as a function // walk that is repeated until a fixed point is reached. In general, // the result of shortening is not as good as that of relaxation, and // shortening is also quadratic in the worst case; shortening branch N // can bring branch N-1 in range of the short form, which in turn can do // the same for branch N-2, and so on. The main advantage of shortening // is that each walk through the function produces valid code, so it is // possible to stop at any point after the first walk. The quadraticness // could therefore be handled with a maximum pass count, although the // question then becomes: what maximum count should be used? // // On SystemZ, long branches are only needed for functions bigger than 64k, // which are relatively rare to begin with, and the long branch sequences // are actually relatively cheap. It therefore doesn't seem worth spending // much compilation time on the problem. Instead, the approach we take is: // // (1) Work out the address that each block would have if no branches // need relaxing. Exit the pass early if all branches are in range // according to this assumption. // // (2) Work out the address that each block would have if all branches // need relaxing. // // (3) Walk through the block calculating the final address of each instruction // and relaxing those that need to be relaxed. For backward branches, // this check uses the final address of the target block, as calculated // earlier in the walk. For forward branches, this check uses the // address of the target block that was calculated in (2). Both checks // give a conservatively-correct range. // //===----------------------------------------------------------------------===// #include "SystemZ.h" #include "SystemZInstrInfo.h" #include "SystemZTargetMachine.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/Statistic.h" #include "llvm/ADT/StringRef.h" #include "llvm/CodeGen/MachineBasicBlock.h" #include "llvm/CodeGen/MachineFunction.h" #include "llvm/CodeGen/MachineFunctionPass.h" #include "llvm/CodeGen/MachineInstr.h" #include "llvm/CodeGen/MachineInstrBuilder.h" #include "llvm/IR/DebugLoc.h" #include "llvm/Support/ErrorHandling.h" #include <cassert> #include <cstdint> usingnamespacellvm; #define DEBUG_TYPE … STATISTIC(LongBranches, "Number of long branches."); namespace { // Represents positional information about a basic block. struct MBBInfo { … }; // Represents the state of a block terminator. struct TerminatorInfo { … }; // Used to keep track of the current position while iterating over the blocks. struct BlockPosition { … }; class SystemZLongBranch : public MachineFunctionPass { … }; char SystemZLongBranch::ID = …; const uint64_t MaxBackwardRange = …; const uint64_t MaxForwardRange = …; } // end anonymous namespace INITIALIZE_PASS(…) // Position describes the state immediately before Block. Update Block // accordingly and move Position to the end of the block's non-terminator // instructions. void SystemZLongBranch::skipNonTerminators(BlockPosition &Position, MBBInfo &Block) { … } // Position describes the state immediately before Terminator. // Update Terminator accordingly and move Position past it. // Assume that Terminator will be relaxed if AssumeRelaxed. void SystemZLongBranch::skipTerminator(BlockPosition &Position, TerminatorInfo &Terminator, bool AssumeRelaxed) { … } static unsigned getInstSizeInBytes(const MachineInstr &MI, const SystemZInstrInfo *TII) { … } // Return a description of terminator instruction MI. TerminatorInfo SystemZLongBranch::describeTerminator(MachineInstr &MI) { … } // Fill MBBs and Terminators, setting the addresses on the assumption // that no branches need relaxation. Return the size of the function under // this assumption. uint64_t SystemZLongBranch::initMBBInfo() { … } // Return true if, under current assumptions, Terminator would need to be // relaxed if it were placed at address Address. bool SystemZLongBranch::mustRelaxBranch(const TerminatorInfo &Terminator, uint64_t Address) { … } // Return true if, under current assumptions, any terminator needs // to be relaxed. bool SystemZLongBranch::mustRelaxABranch() { … } // Set the address of each block on the assumption that all branches // must be long. void SystemZLongBranch::setWorstCaseAddresses() { … } // Split BRANCH ON COUNT MI into the addition given by AddOpcode followed // by a BRCL on the result. void SystemZLongBranch::splitBranchOnCount(MachineInstr *MI, unsigned AddOpcode) { … } // Split MI into the comparison given by CompareOpcode followed // a BRCL on the result. void SystemZLongBranch::splitCompareBranch(MachineInstr *MI, unsigned CompareOpcode) { … } // Relax the branch described by Terminator. void SystemZLongBranch::relaxBranch(TerminatorInfo &Terminator) { … } // Run a shortening pass and relax any branches that need to be relaxed. void SystemZLongBranch::relaxBranches() { … } bool SystemZLongBranch::runOnMachineFunction(MachineFunction &F) { … } FunctionPass *llvm::createSystemZLongBranchPass(SystemZTargetMachine &TM) { … }