Path: blob/main/contrib/llvm-project/llvm/lib/Target/Hexagon/HexagonBranchRelaxation.cpp
35268 views
//===--- HexagonBranchRelaxation.cpp - Identify and relax long jumps ------===//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//===----------------------------------------------------------------------===//78#include "Hexagon.h"9#include "HexagonInstrInfo.h"10#include "HexagonSubtarget.h"11#include "llvm/ADT/DenseMap.h"12#include "llvm/ADT/SmallVector.h"13#include "llvm/ADT/StringRef.h"14#include "llvm/CodeGen/MachineBasicBlock.h"15#include "llvm/CodeGen/MachineFunction.h"16#include "llvm/CodeGen/MachineFunctionPass.h"17#include "llvm/CodeGen/MachineInstr.h"18#include "llvm/CodeGen/MachineOperand.h"19#include "llvm/CodeGen/Passes.h"20#include "llvm/Pass.h"21#include "llvm/Support/CommandLine.h"22#include "llvm/Support/Debug.h"23#include "llvm/Support/raw_ostream.h"24#include <cassert>25#include <cstdint>26#include <cstdlib>27#include <iterator>2829#define DEBUG_TYPE "hexagon-brelax"3031using namespace llvm;3233// Since we have no exact knowledge of code layout, allow some safety buffer34// for jump target. This is measured in bytes.35static cl::opt<uint32_t>36BranchRelaxSafetyBuffer("branch-relax-safety-buffer", cl::init(200),37cl::Hidden, cl::desc("safety buffer size"));3839namespace llvm {4041FunctionPass *createHexagonBranchRelaxation();42void initializeHexagonBranchRelaxationPass(PassRegistry&);4344} // end namespace llvm4546namespace {4748struct HexagonBranchRelaxation : public MachineFunctionPass {49public:50static char ID;5152HexagonBranchRelaxation() : MachineFunctionPass(ID) {53initializeHexagonBranchRelaxationPass(*PassRegistry::getPassRegistry());54}5556bool runOnMachineFunction(MachineFunction &MF) override;5758StringRef getPassName() const override {59return "Hexagon Branch Relaxation";60}6162void getAnalysisUsage(AnalysisUsage &AU) const override {63AU.setPreservesCFG();64MachineFunctionPass::getAnalysisUsage(AU);65}6667private:68const HexagonInstrInfo *HII;69const HexagonRegisterInfo *HRI;7071bool relaxBranches(MachineFunction &MF);72void computeOffset(MachineFunction &MF,73DenseMap<MachineBasicBlock*, unsigned> &BlockToInstOffset);74bool reGenerateBranch(MachineFunction &MF,75DenseMap<MachineBasicBlock*, unsigned> &BlockToInstOffset);76bool isJumpOutOfRange(MachineInstr &MI,77DenseMap<MachineBasicBlock*, unsigned> &BlockToInstOffset);78};7980char HexagonBranchRelaxation::ID = 0;8182} // end anonymous namespace8384INITIALIZE_PASS(HexagonBranchRelaxation, "hexagon-brelax",85"Hexagon Branch Relaxation", false, false)8687FunctionPass *llvm::createHexagonBranchRelaxation() {88return new HexagonBranchRelaxation();89}9091bool HexagonBranchRelaxation::runOnMachineFunction(MachineFunction &MF) {92LLVM_DEBUG(dbgs() << "****** Hexagon Branch Relaxation ******\n");9394auto &HST = MF.getSubtarget<HexagonSubtarget>();95HII = HST.getInstrInfo();96HRI = HST.getRegisterInfo();9798bool Changed = false;99Changed = relaxBranches(MF);100return Changed;101}102103void HexagonBranchRelaxation::computeOffset(MachineFunction &MF,104DenseMap<MachineBasicBlock*, unsigned> &OffsetMap) {105// offset of the current instruction from the start.106unsigned InstOffset = 0;107for (auto &B : MF) {108if (B.getAlignment() != Align(1)) {109// Although we don't know the exact layout of the final code, we need110// to account for alignment padding somehow. This heuristic pads each111// aligned basic block according to the alignment value.112InstOffset = alignTo(InstOffset, B.getAlignment());113}114OffsetMap[&B] = InstOffset;115for (auto &MI : B.instrs()) {116InstOffset += HII->getSize(MI);117// Assume that all extendable branches will be extended.118if (MI.isBranch() && HII->isExtendable(MI))119InstOffset += HEXAGON_INSTR_SIZE;120}121}122}123124/// relaxBranches - For Hexagon, if the jump target/loop label is too far from125/// the jump/loop instruction then, we need to make sure that we have constant126/// extenders set for jumps and loops.127128/// There are six iterations in this phase. It's self explanatory below.129bool HexagonBranchRelaxation::relaxBranches(MachineFunction &MF) {130// Compute the offset of each basic block131// offset of the current instruction from the start.132// map for each instruction to the beginning of the function133DenseMap<MachineBasicBlock*, unsigned> BlockToInstOffset;134computeOffset(MF, BlockToInstOffset);135136return reGenerateBranch(MF, BlockToInstOffset);137}138139/// Check if a given instruction is:140/// - a jump to a distant target141/// - that exceeds its immediate range142/// If both conditions are true, it requires constant extension.143bool HexagonBranchRelaxation::isJumpOutOfRange(MachineInstr &MI,144DenseMap<MachineBasicBlock*, unsigned> &BlockToInstOffset) {145MachineBasicBlock &B = *MI.getParent();146auto FirstTerm = B.getFirstInstrTerminator();147if (FirstTerm == B.instr_end())148return false;149150if (HII->isExtended(MI))151return false;152153unsigned InstOffset = BlockToInstOffset[&B];154unsigned Distance = 0;155156// To save time, estimate exact position of a branch instruction157// as one at the end of the MBB.158// Number of instructions times typical instruction size.159InstOffset += HII->nonDbgBBSize(&B) * HEXAGON_INSTR_SIZE;160161MachineBasicBlock *TBB = nullptr, *FBB = nullptr;162SmallVector<MachineOperand, 4> Cond;163164// Try to analyze this branch.165if (HII->analyzeBranch(B, TBB, FBB, Cond, false)) {166// Could not analyze it. See if this is something we can recognize.167// If it is a NVJ, it should always have its target in168// a fixed location.169if (HII->isNewValueJump(*FirstTerm))170TBB = FirstTerm->getOperand(HII->getCExtOpNum(*FirstTerm)).getMBB();171}172if (TBB && &MI == &*FirstTerm) {173Distance = std::abs((long long)InstOffset - BlockToInstOffset[TBB])174+ BranchRelaxSafetyBuffer;175return !HII->isJumpWithinBranchRange(*FirstTerm, Distance);176}177if (FBB) {178// Look for second terminator.179auto SecondTerm = std::next(FirstTerm);180assert(SecondTerm != B.instr_end() &&181(SecondTerm->isBranch() || SecondTerm->isCall()) &&182"Bad second terminator");183if (&MI != &*SecondTerm)184return false;185// Analyze the second branch in the BB.186Distance = std::abs((long long)InstOffset - BlockToInstOffset[FBB])187+ BranchRelaxSafetyBuffer;188return !HII->isJumpWithinBranchRange(*SecondTerm, Distance);189}190return false;191}192193bool HexagonBranchRelaxation::reGenerateBranch(MachineFunction &MF,194DenseMap<MachineBasicBlock*, unsigned> &BlockToInstOffset) {195bool Changed = false;196197for (auto &B : MF) {198for (auto &MI : B) {199if (!MI.isBranch() || !isJumpOutOfRange(MI, BlockToInstOffset))200continue;201LLVM_DEBUG(dbgs() << "Long distance jump. isExtendable("202<< HII->isExtendable(MI) << ") isConstExtended("203<< HII->isConstExtended(MI) << ") " << MI);204205// Since we have not merged HW loops relaxation into206// this code (yet), soften our approach for the moment.207if (!HII->isExtendable(MI) && !HII->isExtended(MI)) {208LLVM_DEBUG(dbgs() << "\tUnderimplemented relax branch instruction.\n");209} else {210// Find which operand is expandable.211int ExtOpNum = HII->getCExtOpNum(MI);212MachineOperand &MO = MI.getOperand(ExtOpNum);213// This need to be something we understand. So far we assume all214// branches have only MBB address as expandable field.215// If it changes, this will need to be expanded.216assert(MO.isMBB() && "Branch with unknown expandable field type");217// Mark given operand as extended.218MO.addTargetFlag(HexagonII::HMOTF_ConstExtended);219Changed = true;220}221}222}223return Changed;224}225226227