text: //===--- ARMBasicBlockInfo.cpp - Utilities for block sizes ---------------===//
  //
  // 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
  //
  //===----------------------------------------------------------------------===//
  
  #include "ARM.h"
  #include "ARMBaseInstrInfo.h"
  #include "ARMBasicBlockInfo.h"
  #include "ARMMachineFunctionInfo.h"
  #include "llvm/CodeGen/MachineBasicBlock.h"
  #include "llvm/CodeGen/MachineFunction.h"
  #include "llvm/CodeGen/MachineInstr.h"
  #include "llvm/CodeGen/TargetSubtargetInfo.h"
  #include <vector>
  
  #define DEBUG_TYPE "arm-bb-utils"
  
  using namespace llvm;
  
  namespace llvm {
  
  // mayOptimizeThumb2Instruction - Returns true if optimizeThumb2Instructions
  // below may shrink MI.
  static bool
  mayOptimizeThumb2Instruction(const MachineInstr *MI) {
    switch(MI->getOpcode()) {
      // optimizeThumb2Instructions.
      case ARM::t2LEApcrel:
      case ARM::t2LDRpci:
      // optimizeThumb2Branches.
      case ARM::t2B:
      case ARM::t2Bcc:
      case ARM::tBcc:
      // optimizeThumb2JumpTables.
      case ARM::t2BR_JT:
      case ARM::tBR_JTr:
        return true;
    }
    return false;
  }
  
  void ARMBasicBlockUtils::computeBlockSize(MachineBasicBlock *MBB) {
    LLVM_DEBUG(dbgs() << "computeBlockSize: " << MBB->getName() << "\n");
    BasicBlockInfo &BBI = BBInfo[MBB->getNumber()];
    BBI.Size = 0;
    BBI.Unalign = 0;
    BBI.PostAlign = 0;
  
    for (MachineInstr &I : *MBB) {
      BBI.Size += TII->getInstSizeInBytes(I);
      // For inline asm, getInstSizeInBytes returns a conservative estimate.
      // The actual size may be smaller, but still a multiple of the instr size.
      if (I.isInlineAsm())
        BBI.Unalign = isThumb ? 1 : 2;
      // Also consider instructions that may be shrunk later.
      else if (isThumb && mayOptimizeThumb2Instruction(&I))
        BBI.Unalign = 1;
    }
  
    // tBR_JTr contains a .align 2 directive.
    if (!MBB->empty() && MBB->back().getOpcode() == ARM::tBR_JTr) {
      BBI.PostAlign = 2;
      MBB->getParent()->ensureAlignment(2);
    }
  }
  
  /// getOffsetOf - Return the current offset of the specified machine instruction
  /// from the start of the function.  This offset changes as stuff is moved
  /// around inside the function.
  unsigned ARMBasicBlockUtils::getOffsetOf(MachineInstr *MI) const {
    const MachineBasicBlock *MBB = MI->getParent();
  
    // The offset is composed of two things: the sum of the sizes of all MBB's
    // before this instruction's block, and the offset from the start of the block
    // it is in.
    unsigned Offset = BBInfo[MBB->getNumber()].Offset;
  
    // Sum instructions before MI in MBB.
    for (MachineBasicBlock::const_iterator I = MBB->begin(); &*I != MI; ++I) {
      assert(I != MBB->end() && "Didn't find MI in its own basic block?");
      Offset += TII->getInstSizeInBytes(*I);
    }
    return Offset;
  }
  
  /// isBBInRange - Returns true if the distance between specific MI and
  /// specific BB can fit in MI's displacement field.
  bool ARMBasicBlockUtils::isBBInRange(MachineInstr *MI,
                                       MachineBasicBlock *DestBB,
                                       unsigned MaxDisp) const {
    unsigned PCAdj      = isThumb ? 4 : 8;
    unsigned BrOffset   = getOffsetOf(MI) + PCAdj;
    unsigned DestOffset = BBInfo[DestBB->getNumber()].Offset;
  
    LLVM_DEBUG(dbgs() << "Branch of destination " << printMBBReference(*DestBB)
                      << " from " << printMBBReference(*MI->getParent())
                      << " max delta=" << MaxDisp << " from " << getOffsetOf(MI)
                      << " to " << DestOffset << " offset "
                      << int(DestOffset - BrOffset) << "\t" << *MI);
  
    if (BrOffset <= DestOffset) {
      // Branch before the Dest.
      if (DestOffset-BrOffset <= MaxDisp)
        return true;
    } else {
      if (BrOffset-DestOffset <= MaxDisp)
        return true;
    }
    return false;
  }
  
  void ARMBasicBlockUtils::adjustBBOffsetsAfter(MachineBasicBlock *BB) {
    assert(BB->getParent() == &MF &&
           "Basic block is not a child of the current function.\n");
  
    unsigned BBNum = BB->getNumber();
    LLVM_DEBUG(dbgs() << "Adjust block:\n"
               << " - name: " << BB->getName() << "\n"
               << " - number: " << BB->getNumber() << "\n"
               << " - function: " << MF.getName() << "\n"
               << "   - blocks: " << MF.getNumBlockIDs() << "\n");
  
    for(unsigned i = BBNum + 1, e = MF.getNumBlockIDs(); i < e; ++i) {
      // Get the offset and known bits at the end of the layout predecessor.
      // Include the alignment of the current block.
      unsigned LogAlign = MF.getBlockNumbered(i)->getAlignment();
      unsigned Offset = BBInfo[i - 1].postOffset(LogAlign);
      unsigned KnownBits = BBInfo[i - 1].postKnownBits(LogAlign);
  
      // This is where block i begins.  Stop if the offset is already correct,
      // and we have updated 2 blocks.  This is the maximum number of blocks
      // changed before calling this function.
      if (i > BBNum + 2 &&
          BBInfo[i].Offset == Offset &&
          BBInfo[i].KnownBits == KnownBits)
        break;
  
      BBInfo[i].Offset = Offset;
      BBInfo[i].KnownBits = KnownBits;
    }
  }
  
  } // end namespace llvm
  