//===--- 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(1);
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