xref: /freebsd/contrib/llvm-project/llvm/lib/Target/ARM/ARMBasicBlockInfo.cpp (revision 5f757f3ff9144b609b3c433dfd370cc6bdc191ad)
10b57cec5SDimitry Andric //===--- ARMBasicBlockInfo.cpp - Utilities for block sizes ---------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric 
98bcb0991SDimitry Andric #include "ARMBasicBlockInfo.h"
100b57cec5SDimitry Andric #include "ARM.h"
110b57cec5SDimitry Andric #include "ARMBaseInstrInfo.h"
120b57cec5SDimitry Andric #include "ARMMachineFunctionInfo.h"
130b57cec5SDimitry Andric #include "llvm/CodeGen/MachineBasicBlock.h"
140b57cec5SDimitry Andric #include "llvm/CodeGen/MachineFunction.h"
150b57cec5SDimitry Andric #include "llvm/CodeGen/MachineInstr.h"
160b57cec5SDimitry Andric #include "llvm/CodeGen/TargetSubtargetInfo.h"
178bcb0991SDimitry Andric #include "llvm/IR/GlobalVariable.h"
188bcb0991SDimitry Andric #include "llvm/Support/Debug.h"
190b57cec5SDimitry Andric 
200b57cec5SDimitry Andric #define DEBUG_TYPE "arm-bb-utils"
210b57cec5SDimitry Andric 
220b57cec5SDimitry Andric using namespace llvm;
230b57cec5SDimitry Andric 
240b57cec5SDimitry Andric namespace llvm {
250b57cec5SDimitry Andric 
260b57cec5SDimitry Andric // mayOptimizeThumb2Instruction - Returns true if optimizeThumb2Instructions
270b57cec5SDimitry Andric // below may shrink MI.
280b57cec5SDimitry Andric static bool
290b57cec5SDimitry Andric mayOptimizeThumb2Instruction(const MachineInstr *MI) {
300b57cec5SDimitry Andric   switch(MI->getOpcode()) {
310b57cec5SDimitry Andric     // optimizeThumb2Instructions.
320b57cec5SDimitry Andric     case ARM::t2LEApcrel:
330b57cec5SDimitry Andric     case ARM::t2LDRpci:
340b57cec5SDimitry Andric     // optimizeThumb2Branches.
350b57cec5SDimitry Andric     case ARM::t2B:
360b57cec5SDimitry Andric     case ARM::t2Bcc:
370b57cec5SDimitry Andric     case ARM::tBcc:
380b57cec5SDimitry Andric     // optimizeThumb2JumpTables.
390b57cec5SDimitry Andric     case ARM::t2BR_JT:
400b57cec5SDimitry Andric     case ARM::tBR_JTr:
410b57cec5SDimitry Andric       return true;
420b57cec5SDimitry Andric   }
430b57cec5SDimitry Andric   return false;
440b57cec5SDimitry Andric }
450b57cec5SDimitry Andric 
460b57cec5SDimitry Andric void ARMBasicBlockUtils::computeBlockSize(MachineBasicBlock *MBB) {
470b57cec5SDimitry Andric   LLVM_DEBUG(dbgs() << "computeBlockSize: " << MBB->getName() << "\n");
480b57cec5SDimitry Andric   BasicBlockInfo &BBI = BBInfo[MBB->getNumber()];
490b57cec5SDimitry Andric   BBI.Size = 0;
500b57cec5SDimitry Andric   BBI.Unalign = 0;
51*5ffd83dbSDimitry Andric   BBI.PostAlign = Align(1);
520b57cec5SDimitry Andric 
530b57cec5SDimitry Andric   for (MachineInstr &I : *MBB) {
540b57cec5SDimitry Andric     BBI.Size += TII->getInstSizeInBytes(I);
550b57cec5SDimitry Andric     // For inline asm, getInstSizeInBytes returns a conservative estimate.
560b57cec5SDimitry Andric     // The actual size may be smaller, but still a multiple of the instr size.
570b57cec5SDimitry Andric     if (I.isInlineAsm())
580b57cec5SDimitry Andric       BBI.Unalign = isThumb ? 1 : 2;
590b57cec5SDimitry Andric     // Also consider instructions that may be shrunk later.
600b57cec5SDimitry Andric     else if (isThumb && mayOptimizeThumb2Instruction(&I))
610b57cec5SDimitry Andric       BBI.Unalign = 1;
620b57cec5SDimitry Andric   }
630b57cec5SDimitry Andric 
640b57cec5SDimitry Andric   // tBR_JTr contains a .align 2 directive.
650b57cec5SDimitry Andric   if (!MBB->empty() && MBB->back().getOpcode() == ARM::tBR_JTr) {
668bcb0991SDimitry Andric     BBI.PostAlign = Align(4);
678bcb0991SDimitry Andric     MBB->getParent()->ensureAlignment(Align(4));
680b57cec5SDimitry Andric   }
690b57cec5SDimitry Andric }
700b57cec5SDimitry Andric 
710b57cec5SDimitry Andric /// getOffsetOf - Return the current offset of the specified machine instruction
720b57cec5SDimitry Andric /// from the start of the function.  This offset changes as stuff is moved
730b57cec5SDimitry Andric /// around inside the function.
740b57cec5SDimitry Andric unsigned ARMBasicBlockUtils::getOffsetOf(MachineInstr *MI) const {
750b57cec5SDimitry Andric   const MachineBasicBlock *MBB = MI->getParent();
760b57cec5SDimitry Andric 
770b57cec5SDimitry Andric   // The offset is composed of two things: the sum of the sizes of all MBB's
780b57cec5SDimitry Andric   // before this instruction's block, and the offset from the start of the block
790b57cec5SDimitry Andric   // it is in.
800b57cec5SDimitry Andric   unsigned Offset = BBInfo[MBB->getNumber()].Offset;
810b57cec5SDimitry Andric 
820b57cec5SDimitry Andric   // Sum instructions before MI in MBB.
830b57cec5SDimitry Andric   for (MachineBasicBlock::const_iterator I = MBB->begin(); &*I != MI; ++I) {
840b57cec5SDimitry Andric     assert(I != MBB->end() && "Didn't find MI in its own basic block?");
850b57cec5SDimitry Andric     Offset += TII->getInstSizeInBytes(*I);
860b57cec5SDimitry Andric   }
870b57cec5SDimitry Andric   return Offset;
880b57cec5SDimitry Andric }
890b57cec5SDimitry Andric 
900b57cec5SDimitry Andric /// isBBInRange - Returns true if the distance between specific MI and
910b57cec5SDimitry Andric /// specific BB can fit in MI's displacement field.
920b57cec5SDimitry Andric bool ARMBasicBlockUtils::isBBInRange(MachineInstr *MI,
930b57cec5SDimitry Andric                                      MachineBasicBlock *DestBB,
940b57cec5SDimitry Andric                                      unsigned MaxDisp) const {
950b57cec5SDimitry Andric   unsigned PCAdj      = isThumb ? 4 : 8;
960b57cec5SDimitry Andric   unsigned BrOffset   = getOffsetOf(MI) + PCAdj;
970b57cec5SDimitry Andric   unsigned DestOffset = BBInfo[DestBB->getNumber()].Offset;
980b57cec5SDimitry Andric 
990b57cec5SDimitry Andric   LLVM_DEBUG(dbgs() << "Branch of destination " << printMBBReference(*DestBB)
1000b57cec5SDimitry Andric                     << " from " << printMBBReference(*MI->getParent())
1010b57cec5SDimitry Andric                     << " max delta=" << MaxDisp << " from " << getOffsetOf(MI)
1020b57cec5SDimitry Andric                     << " to " << DestOffset << " offset "
1030b57cec5SDimitry Andric                     << int(DestOffset - BrOffset) << "\t" << *MI);
1040b57cec5SDimitry Andric 
1050b57cec5SDimitry Andric   if (BrOffset <= DestOffset) {
1060b57cec5SDimitry Andric     // Branch before the Dest.
1070b57cec5SDimitry Andric     if (DestOffset-BrOffset <= MaxDisp)
1080b57cec5SDimitry Andric       return true;
1090b57cec5SDimitry Andric   } else {
1100b57cec5SDimitry Andric     if (BrOffset-DestOffset <= MaxDisp)
1110b57cec5SDimitry Andric       return true;
1120b57cec5SDimitry Andric   }
1130b57cec5SDimitry Andric   return false;
1140b57cec5SDimitry Andric }
1150b57cec5SDimitry Andric 
1160b57cec5SDimitry Andric void ARMBasicBlockUtils::adjustBBOffsetsAfter(MachineBasicBlock *BB) {
1170b57cec5SDimitry Andric   assert(BB->getParent() == &MF &&
1180b57cec5SDimitry Andric          "Basic block is not a child of the current function.\n");
1190b57cec5SDimitry Andric 
1200b57cec5SDimitry Andric   unsigned BBNum = BB->getNumber();
1210b57cec5SDimitry Andric   LLVM_DEBUG(dbgs() << "Adjust block:\n"
1220b57cec5SDimitry Andric              << " - name: " << BB->getName() << "\n"
1230b57cec5SDimitry Andric              << " - number: " << BB->getNumber() << "\n"
1240b57cec5SDimitry Andric              << " - function: " << MF.getName() << "\n"
1250b57cec5SDimitry Andric              << "   - blocks: " << MF.getNumBlockIDs() << "\n");
1260b57cec5SDimitry Andric 
1270b57cec5SDimitry Andric   for(unsigned i = BBNum + 1, e = MF.getNumBlockIDs(); i < e; ++i) {
1280b57cec5SDimitry Andric     // Get the offset and known bits at the end of the layout predecessor.
1290b57cec5SDimitry Andric     // Include the alignment of the current block.
1308bcb0991SDimitry Andric     const Align Align = MF.getBlockNumbered(i)->getAlignment();
1318bcb0991SDimitry Andric     const unsigned Offset = BBInfo[i - 1].postOffset(Align);
1328bcb0991SDimitry Andric     const unsigned KnownBits = BBInfo[i - 1].postKnownBits(Align);
1330b57cec5SDimitry Andric 
1340b57cec5SDimitry Andric     // This is where block i begins.  Stop if the offset is already correct,
1350b57cec5SDimitry Andric     // and we have updated 2 blocks.  This is the maximum number of blocks
1360b57cec5SDimitry Andric     // changed before calling this function.
1370b57cec5SDimitry Andric     if (i > BBNum + 2 &&
1380b57cec5SDimitry Andric         BBInfo[i].Offset == Offset &&
1390b57cec5SDimitry Andric         BBInfo[i].KnownBits == KnownBits)
1400b57cec5SDimitry Andric       break;
1410b57cec5SDimitry Andric 
1420b57cec5SDimitry Andric     BBInfo[i].Offset = Offset;
1430b57cec5SDimitry Andric     BBInfo[i].KnownBits = KnownBits;
1440b57cec5SDimitry Andric   }
1450b57cec5SDimitry Andric }
1460b57cec5SDimitry Andric 
1470b57cec5SDimitry Andric } // end namespace llvm
148