Path: blob/main/contrib/llvm-project/llvm/lib/Target/SystemZ/SystemZLongBranch.cpp
35294 views
//===-- SystemZLongBranch.cpp - Branch lengthening for SystemZ ------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8// This pass makes sure that all branches are in range. There are several ways9// in which this could be done. One aggressive approach is to assume that all10// branches are in range and successively replace those that turn out not11// to be in range with a longer form (branch relaxation). A simple12// implementation is to continually walk through the function relaxing13// branches until no more changes are needed and a fixed point is reached.14// However, in the pathological worst case, this implementation is15// quadratic in the number of blocks; relaxing branch N can make branch N-116// go out of range, which in turn can make branch N-2 go out of range,17// and so on.18//19// An alternative approach is to assume that all branches must be20// converted to their long forms, then reinstate the short forms of21// branches that, even under this pessimistic assumption, turn out to be22// in range (branch shortening). This too can be implemented as a function23// walk that is repeated until a fixed point is reached. In general,24// the result of shortening is not as good as that of relaxation, and25// shortening is also quadratic in the worst case; shortening branch N26// can bring branch N-1 in range of the short form, which in turn can do27// the same for branch N-2, and so on. The main advantage of shortening28// is that each walk through the function produces valid code, so it is29// possible to stop at any point after the first walk. The quadraticness30// could therefore be handled with a maximum pass count, although the31// question then becomes: what maximum count should be used?32//33// On SystemZ, long branches are only needed for functions bigger than 64k,34// which are relatively rare to begin with, and the long branch sequences35// are actually relatively cheap. It therefore doesn't seem worth spending36// much compilation time on the problem. Instead, the approach we take is:37//38// (1) Work out the address that each block would have if no branches39// need relaxing. Exit the pass early if all branches are in range40// according to this assumption.41//42// (2) Work out the address that each block would have if all branches43// need relaxing.44//45// (3) Walk through the block calculating the final address of each instruction46// and relaxing those that need to be relaxed. For backward branches,47// this check uses the final address of the target block, as calculated48// earlier in the walk. For forward branches, this check uses the49// address of the target block that was calculated in (2). Both checks50// give a conservatively-correct range.51//52//===----------------------------------------------------------------------===//5354#include "SystemZ.h"55#include "SystemZInstrInfo.h"56#include "SystemZTargetMachine.h"57#include "llvm/ADT/SmallVector.h"58#include "llvm/ADT/Statistic.h"59#include "llvm/ADT/StringRef.h"60#include "llvm/CodeGen/MachineBasicBlock.h"61#include "llvm/CodeGen/MachineFunction.h"62#include "llvm/CodeGen/MachineFunctionPass.h"63#include "llvm/CodeGen/MachineInstr.h"64#include "llvm/CodeGen/MachineInstrBuilder.h"65#include "llvm/IR/DebugLoc.h"66#include "llvm/Support/ErrorHandling.h"67#include <cassert>68#include <cstdint>6970using namespace llvm;7172#define DEBUG_TYPE "systemz-long-branch"7374STATISTIC(LongBranches, "Number of long branches.");7576namespace {7778// Represents positional information about a basic block.79struct MBBInfo {80// The address that we currently assume the block has.81uint64_t Address = 0;8283// The size of the block in bytes, excluding terminators.84// This value never changes.85uint64_t Size = 0;8687// The minimum alignment of the block.88// This value never changes.89Align Alignment;9091// The number of terminators in this block. This value never changes.92unsigned NumTerminators = 0;9394MBBInfo() = default;95};9697// Represents the state of a block terminator.98struct TerminatorInfo {99// If this terminator is a relaxable branch, this points to the branch100// instruction, otherwise it is null.101MachineInstr *Branch = nullptr;102103// The address that we currently assume the terminator has.104uint64_t Address = 0;105106// The current size of the terminator in bytes.107uint64_t Size = 0;108109// If Branch is nonnull, this is the number of the target block,110// otherwise it is unused.111unsigned TargetBlock = 0;112113// If Branch is nonnull, this is the length of the longest relaxed form,114// otherwise it is zero.115unsigned ExtraRelaxSize = 0;116117TerminatorInfo() = default;118};119120// Used to keep track of the current position while iterating over the blocks.121struct BlockPosition {122// The address that we assume this position has.123uint64_t Address = 0;124125// The number of low bits in Address that are known to be the same126// as the runtime address.127unsigned KnownBits;128129BlockPosition(unsigned InitialLogAlignment)130: KnownBits(InitialLogAlignment) {}131};132133class SystemZLongBranch : public MachineFunctionPass {134public:135static char ID;136137SystemZLongBranch() : MachineFunctionPass(ID) {138initializeSystemZLongBranchPass(*PassRegistry::getPassRegistry());139}140141bool runOnMachineFunction(MachineFunction &F) override;142143MachineFunctionProperties getRequiredProperties() const override {144return MachineFunctionProperties().set(145MachineFunctionProperties::Property::NoVRegs);146}147148private:149void skipNonTerminators(BlockPosition &Position, MBBInfo &Block);150void skipTerminator(BlockPosition &Position, TerminatorInfo &Terminator,151bool AssumeRelaxed);152TerminatorInfo describeTerminator(MachineInstr &MI);153uint64_t initMBBInfo();154bool mustRelaxBranch(const TerminatorInfo &Terminator, uint64_t Address);155bool mustRelaxABranch();156void setWorstCaseAddresses();157void splitBranchOnCount(MachineInstr *MI, unsigned AddOpcode);158void splitCompareBranch(MachineInstr *MI, unsigned CompareOpcode);159void relaxBranch(TerminatorInfo &Terminator);160void relaxBranches();161162const SystemZInstrInfo *TII = nullptr;163MachineFunction *MF = nullptr;164SmallVector<MBBInfo, 16> MBBs;165SmallVector<TerminatorInfo, 16> Terminators;166};167168char SystemZLongBranch::ID = 0;169170const uint64_t MaxBackwardRange = 0x10000;171const uint64_t MaxForwardRange = 0xfffe;172173} // end anonymous namespace174175INITIALIZE_PASS(SystemZLongBranch, DEBUG_TYPE, "SystemZ Long Branch", false,176false)177178// Position describes the state immediately before Block. Update Block179// accordingly and move Position to the end of the block's non-terminator180// instructions.181void SystemZLongBranch::skipNonTerminators(BlockPosition &Position,182MBBInfo &Block) {183if (Log2(Block.Alignment) > Position.KnownBits) {184// When calculating the address of Block, we need to conservatively185// assume that Block had the worst possible misalignment.186Position.Address +=187(Block.Alignment.value() - (uint64_t(1) << Position.KnownBits));188Position.KnownBits = Log2(Block.Alignment);189}190191// Align the addresses.192Position.Address = alignTo(Position.Address, Block.Alignment);193194// Record the block's position.195Block.Address = Position.Address;196197// Move past the non-terminators in the block.198Position.Address += Block.Size;199}200201// Position describes the state immediately before Terminator.202// Update Terminator accordingly and move Position past it.203// Assume that Terminator will be relaxed if AssumeRelaxed.204void SystemZLongBranch::skipTerminator(BlockPosition &Position,205TerminatorInfo &Terminator,206bool AssumeRelaxed) {207Terminator.Address = Position.Address;208Position.Address += Terminator.Size;209if (AssumeRelaxed)210Position.Address += Terminator.ExtraRelaxSize;211}212213static unsigned getInstSizeInBytes(const MachineInstr &MI,214const SystemZInstrInfo *TII) {215unsigned Size = TII->getInstSizeInBytes(MI);216assert((Size ||217// These do not have a size:218MI.isDebugOrPseudoInstr() || MI.isPosition() || MI.isKill() ||219MI.isImplicitDef() || MI.getOpcode() == TargetOpcode::MEMBARRIER ||220// These have a size that may be zero:221MI.isInlineAsm() || MI.getOpcode() == SystemZ::STACKMAP ||222MI.getOpcode() == SystemZ::PATCHPOINT) &&223"Missing size value for instruction.");224return Size;225}226227// Return a description of terminator instruction MI.228TerminatorInfo SystemZLongBranch::describeTerminator(MachineInstr &MI) {229TerminatorInfo Terminator;230Terminator.Size = getInstSizeInBytes(MI, TII);231if (MI.isConditionalBranch() || MI.isUnconditionalBranch()) {232switch (MI.getOpcode()) {233case SystemZ::J:234// Relaxes to JG, which is 2 bytes longer.235Terminator.ExtraRelaxSize = 2;236break;237case SystemZ::BRC:238// Relaxes to BRCL, which is 2 bytes longer.239Terminator.ExtraRelaxSize = 2;240break;241case SystemZ::BRCT:242case SystemZ::BRCTG:243// Relaxes to A(G)HI and BRCL, which is 6 bytes longer.244Terminator.ExtraRelaxSize = 6;245break;246case SystemZ::BRCTH:247// Never needs to be relaxed.248Terminator.ExtraRelaxSize = 0;249break;250case SystemZ::CRJ:251case SystemZ::CLRJ:252// Relaxes to a C(L)R/BRCL sequence, which is 2 bytes longer.253Terminator.ExtraRelaxSize = 2;254break;255case SystemZ::CGRJ:256case SystemZ::CLGRJ:257// Relaxes to a C(L)GR/BRCL sequence, which is 4 bytes longer.258Terminator.ExtraRelaxSize = 4;259break;260case SystemZ::CIJ:261case SystemZ::CGIJ:262// Relaxes to a C(G)HI/BRCL sequence, which is 4 bytes longer.263Terminator.ExtraRelaxSize = 4;264break;265case SystemZ::CLIJ:266case SystemZ::CLGIJ:267// Relaxes to a CL(G)FI/BRCL sequence, which is 6 bytes longer.268Terminator.ExtraRelaxSize = 6;269break;270default:271llvm_unreachable("Unrecognized branch instruction");272}273Terminator.Branch = &MI;274Terminator.TargetBlock =275TII->getBranchInfo(MI).getMBBTarget()->getNumber();276}277return Terminator;278}279280// Fill MBBs and Terminators, setting the addresses on the assumption281// that no branches need relaxation. Return the size of the function under282// this assumption.283uint64_t SystemZLongBranch::initMBBInfo() {284MF->RenumberBlocks();285unsigned NumBlocks = MF->size();286287MBBs.clear();288MBBs.resize(NumBlocks);289290Terminators.clear();291Terminators.reserve(NumBlocks);292293BlockPosition Position(Log2(MF->getAlignment()));294for (unsigned I = 0; I < NumBlocks; ++I) {295MachineBasicBlock *MBB = MF->getBlockNumbered(I);296MBBInfo &Block = MBBs[I];297298// Record the alignment, for quick access.299Block.Alignment = MBB->getAlignment();300301// Calculate the size of the fixed part of the block.302MachineBasicBlock::iterator MI = MBB->begin();303MachineBasicBlock::iterator End = MBB->end();304while (MI != End && !MI->isTerminator()) {305Block.Size += getInstSizeInBytes(*MI, TII);306++MI;307}308skipNonTerminators(Position, Block);309310// Add the terminators.311while (MI != End) {312if (!MI->isDebugInstr()) {313assert(MI->isTerminator() && "Terminator followed by non-terminator");314Terminators.push_back(describeTerminator(*MI));315skipTerminator(Position, Terminators.back(), false);316++Block.NumTerminators;317}318++MI;319}320}321322return Position.Address;323}324325// Return true if, under current assumptions, Terminator would need to be326// relaxed if it were placed at address Address.327bool SystemZLongBranch::mustRelaxBranch(const TerminatorInfo &Terminator,328uint64_t Address) {329if (!Terminator.Branch || Terminator.ExtraRelaxSize == 0)330return false;331332const MBBInfo &Target = MBBs[Terminator.TargetBlock];333if (Address >= Target.Address) {334if (Address - Target.Address <= MaxBackwardRange)335return false;336} else {337if (Target.Address - Address <= MaxForwardRange)338return false;339}340341return true;342}343344// Return true if, under current assumptions, any terminator needs345// to be relaxed.346bool SystemZLongBranch::mustRelaxABranch() {347for (auto &Terminator : Terminators)348if (mustRelaxBranch(Terminator, Terminator.Address))349return true;350return false;351}352353// Set the address of each block on the assumption that all branches354// must be long.355void SystemZLongBranch::setWorstCaseAddresses() {356SmallVector<TerminatorInfo, 16>::iterator TI = Terminators.begin();357BlockPosition Position(Log2(MF->getAlignment()));358for (auto &Block : MBBs) {359skipNonTerminators(Position, Block);360for (unsigned BTI = 0, BTE = Block.NumTerminators; BTI != BTE; ++BTI) {361skipTerminator(Position, *TI, true);362++TI;363}364}365}366367// Split BRANCH ON COUNT MI into the addition given by AddOpcode followed368// by a BRCL on the result.369void SystemZLongBranch::splitBranchOnCount(MachineInstr *MI,370unsigned AddOpcode) {371MachineBasicBlock *MBB = MI->getParent();372DebugLoc DL = MI->getDebugLoc();373BuildMI(*MBB, MI, DL, TII->get(AddOpcode))374.add(MI->getOperand(0))375.add(MI->getOperand(1))376.addImm(-1);377MachineInstr *BRCL = BuildMI(*MBB, MI, DL, TII->get(SystemZ::BRCL))378.addImm(SystemZ::CCMASK_ICMP)379.addImm(SystemZ::CCMASK_CMP_NE)380.add(MI->getOperand(2));381// The implicit use of CC is a killing use.382BRCL->addRegisterKilled(SystemZ::CC, &TII->getRegisterInfo());383MI->eraseFromParent();384}385386// Split MI into the comparison given by CompareOpcode followed387// a BRCL on the result.388void SystemZLongBranch::splitCompareBranch(MachineInstr *MI,389unsigned CompareOpcode) {390MachineBasicBlock *MBB = MI->getParent();391DebugLoc DL = MI->getDebugLoc();392BuildMI(*MBB, MI, DL, TII->get(CompareOpcode))393.add(MI->getOperand(0))394.add(MI->getOperand(1));395MachineInstr *BRCL = BuildMI(*MBB, MI, DL, TII->get(SystemZ::BRCL))396.addImm(SystemZ::CCMASK_ICMP)397.add(MI->getOperand(2))398.add(MI->getOperand(3));399// The implicit use of CC is a killing use.400BRCL->addRegisterKilled(SystemZ::CC, &TII->getRegisterInfo());401MI->eraseFromParent();402}403404// Relax the branch described by Terminator.405void SystemZLongBranch::relaxBranch(TerminatorInfo &Terminator) {406MachineInstr *Branch = Terminator.Branch;407switch (Branch->getOpcode()) {408case SystemZ::J:409Branch->setDesc(TII->get(SystemZ::JG));410break;411case SystemZ::BRC:412Branch->setDesc(TII->get(SystemZ::BRCL));413break;414case SystemZ::BRCT:415splitBranchOnCount(Branch, SystemZ::AHI);416break;417case SystemZ::BRCTG:418splitBranchOnCount(Branch, SystemZ::AGHI);419break;420case SystemZ::CRJ:421splitCompareBranch(Branch, SystemZ::CR);422break;423case SystemZ::CGRJ:424splitCompareBranch(Branch, SystemZ::CGR);425break;426case SystemZ::CIJ:427splitCompareBranch(Branch, SystemZ::CHI);428break;429case SystemZ::CGIJ:430splitCompareBranch(Branch, SystemZ::CGHI);431break;432case SystemZ::CLRJ:433splitCompareBranch(Branch, SystemZ::CLR);434break;435case SystemZ::CLGRJ:436splitCompareBranch(Branch, SystemZ::CLGR);437break;438case SystemZ::CLIJ:439splitCompareBranch(Branch, SystemZ::CLFI);440break;441case SystemZ::CLGIJ:442splitCompareBranch(Branch, SystemZ::CLGFI);443break;444default:445llvm_unreachable("Unrecognized branch");446}447448Terminator.Size += Terminator.ExtraRelaxSize;449Terminator.ExtraRelaxSize = 0;450Terminator.Branch = nullptr;451452++LongBranches;453}454455// Run a shortening pass and relax any branches that need to be relaxed.456void SystemZLongBranch::relaxBranches() {457SmallVector<TerminatorInfo, 16>::iterator TI = Terminators.begin();458BlockPosition Position(Log2(MF->getAlignment()));459for (auto &Block : MBBs) {460skipNonTerminators(Position, Block);461for (unsigned BTI = 0, BTE = Block.NumTerminators; BTI != BTE; ++BTI) {462assert(Position.Address <= TI->Address &&463"Addresses shouldn't go forwards");464if (mustRelaxBranch(*TI, Position.Address))465relaxBranch(*TI);466skipTerminator(Position, *TI, false);467++TI;468}469}470}471472bool SystemZLongBranch::runOnMachineFunction(MachineFunction &F) {473TII = static_cast<const SystemZInstrInfo *>(F.getSubtarget().getInstrInfo());474MF = &F;475uint64_t Size = initMBBInfo();476if (Size <= MaxForwardRange || !mustRelaxABranch())477return false;478479setWorstCaseAddresses();480relaxBranches();481return true;482}483484FunctionPass *llvm::createSystemZLongBranchPass(SystemZTargetMachine &TM) {485return new SystemZLongBranch();486}487488489