| //===--- 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 "ARMBasicBlockInfo.h" |
| #include "ARM.h" |
| #include "ARMBaseInstrInfo.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 "llvm/IR/GlobalVariable.h" |
| #include "llvm/Support/Debug.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 = Align::None(); |
| |
| 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 = Align(4); |
| MBB->getParent()->ensureAlignment(Align(4)); |
| } |
| } |
| |
| /// 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. |
| const Align Align = MF.getBlockNumbered(i)->getAlignment(); |
| const unsigned Offset = BBInfo[i - 1].postOffset(Align); |
| const unsigned KnownBits = BBInfo[i - 1].postKnownBits(Align); |
| |
| // 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 |