56 #define DEBUG_TYPE "systemz-long-branch"
71 STATISTIC(LongBranches,
"Number of long branches.");
88 unsigned NumTerminators;
91 : Address(0), Size(0), Alignment(0), NumTerminators(0) {}
95 struct TerminatorInfo {
108 unsigned TargetBlock;
112 unsigned ExtraRelaxSize;
114 TerminatorInfo() :
Branch(0), Size(0), TargetBlock(0), ExtraRelaxSize(0) {}
118 struct BlockPosition {
126 BlockPosition(
unsigned InitialAlignment)
127 : Address(0), KnownBits(InitialAlignment) {}
136 virtual const char *getPassName()
const {
137 return "SystemZ Long Branch";
143 void skipNonTerminators(BlockPosition &Position, MBBInfo &Block);
144 void skipTerminator(BlockPosition &Position, TerminatorInfo &
Terminator,
147 uint64_t initMBBInfo();
148 bool mustRelaxBranch(
const TerminatorInfo &
Terminator, uint64_t Address);
149 bool mustRelaxABranch();
150 void setWorstCaseAddresses();
152 void splitCompareBranch(
MachineInstr *
MI,
unsigned CompareOpcode);
154 void relaxBranches();
164 const uint64_t MaxBackwardRange = 0x10000;
165 const uint64_t MaxForwardRange = 0xfffe;
169 return new SystemZLongBranch(TM);
175 void SystemZLongBranch::skipNonTerminators(BlockPosition &Position,
177 if (Block.Alignment > Position.KnownBits) {
180 Position.Address += ((uint64_t(1) << Block.Alignment) -
181 (uint64_t(1) << Position.KnownBits));
182 Position.KnownBits = Block.Alignment;
186 uint64_t AlignMask = (uint64_t(1) << Block.Alignment) - 1;
187 Position.Address = (Position.Address + AlignMask) & ~AlignMask;
190 Block.Address = Position.Address;
193 Position.Address += Block.Size;
199 void SystemZLongBranch::skipTerminator(BlockPosition &Position,
201 bool AssumeRelaxed) {
202 Terminator.Address = Position.Address;
203 Position.Address += Terminator.Size;
205 Position.Address += Terminator.ExtraRelaxSize;
209 TerminatorInfo SystemZLongBranch::describeTerminator(
MachineInstr *
MI) {
211 Terminator.Size =
TII->getInstSizeInBytes(MI);
216 Terminator.ExtraRelaxSize = 2;
220 Terminator.ExtraRelaxSize = 2;
225 Terminator.ExtraRelaxSize = 6;
230 Terminator.ExtraRelaxSize = 2;
235 Terminator.ExtraRelaxSize = 4;
240 Terminator.ExtraRelaxSize = 4;
245 Terminator.ExtraRelaxSize = 6;
250 Terminator.Branch =
MI;
251 Terminator.TargetBlock =
252 TII->getBranchInfo(MI).Target->getMBB()->getNumber();
260 uint64_t SystemZLongBranch::initMBBInfo() {
261 MF->RenumberBlocks();
262 unsigned NumBlocks = MF->size();
265 MBBs.resize(NumBlocks);
268 Terminators.reserve(NumBlocks);
270 BlockPosition Position(MF->getAlignment());
271 for (
unsigned I = 0;
I < NumBlocks; ++
I) {
273 MBBInfo &Block = MBBs[
I];
281 while (MI != End && !MI->isTerminator()) {
282 Block.Size +=
TII->getInstSizeInBytes(MI);
285 skipNonTerminators(Position, Block);
289 if (!MI->isDebugValue()) {
290 assert(MI->isTerminator() &&
"Terminator followed by non-terminator");
291 Terminators.push_back(describeTerminator(MI));
292 skipTerminator(Position, Terminators.back(),
false);
293 ++Block.NumTerminators;
299 return Position.Address;
304 bool SystemZLongBranch::mustRelaxBranch(
const TerminatorInfo &Terminator,
306 if (!Terminator.Branch)
309 const MBBInfo &
Target = MBBs[Terminator.TargetBlock];
310 if (Address >= Target.Address) {
311 if (Address - Target.Address <= MaxBackwardRange)
314 if (Target.Address - Address <= MaxForwardRange)
323 bool SystemZLongBranch::mustRelaxABranch() {
325 TE = Terminators.end(); TI != TE; ++TI)
326 if (mustRelaxBranch(*TI, TI->Address))
333 void SystemZLongBranch::setWorstCaseAddresses() {
335 BlockPosition Position(MF->getAlignment());
338 skipNonTerminators(Position, *BI);
339 for (
unsigned BTI = 0, BTE = BI->NumTerminators; BTI != BTE; ++BTI) {
340 skipTerminator(Position, *TI,
true);
348 void SystemZLongBranch::splitBranchOnCount(
MachineInstr *MI,
349 unsigned AddOpcode) {
367 void SystemZLongBranch::splitCompareBranch(
MachineInstr *MI,
368 unsigned CompareOpcode) {
371 BuildMI(*MBB, MI, DL,
TII->get(CompareOpcode))
384 void SystemZLongBranch::relaxBranch(TerminatorInfo &Terminator) {
394 splitBranchOnCount(Branch, SystemZ::AHI);
397 splitBranchOnCount(Branch, SystemZ::AGHI);
400 splitCompareBranch(Branch, SystemZ::CR);
403 splitCompareBranch(Branch, SystemZ::CGR);
406 splitCompareBranch(Branch, SystemZ::CHI);
409 splitCompareBranch(Branch, SystemZ::CGHI);
412 splitCompareBranch(Branch, SystemZ::CLR);
415 splitCompareBranch(Branch, SystemZ::CLGR);
418 splitCompareBranch(Branch, SystemZ::CLFI);
421 splitCompareBranch(Branch, SystemZ::CLGFI);
427 Terminator.Size += Terminator.ExtraRelaxSize;
428 Terminator.ExtraRelaxSize = 0;
429 Terminator.Branch = 0;
435 void SystemZLongBranch::relaxBranches() {
437 BlockPosition Position(MF->getAlignment());
440 skipNonTerminators(Position, *BI);
441 for (
unsigned BTI = 0, BTE = BI->NumTerminators; BTI != BTE; ++BTI) {
442 assert(Position.Address <= TI->Address &&
443 "Addresses shouldn't go forwards");
444 if (mustRelaxBranch(*TI, Position.Address))
446 skipTerminator(Position, *TI,
false);
455 uint64_t Size = initMBBInfo();
456 if (Size <= MaxForwardRange || !mustRelaxABranch())
459 setWorstCaseAddresses();
bool isConditionalBranch(QueryType Type=AnyInBundle) const
const unsigned CCMASK_ICMP
const HexagonInstrInfo * TII
#define llvm_unreachable(msg)
ID
LLVM Calling Convention Representation.
const MachineInstrBuilder & addImm(int64_t Val) const
const MachineBasicBlock * getParent() const
bundle_iterator< MachineInstr, instr_iterator > iterator
const MachineOperand & getOperand(unsigned i) const
MachineInstrBuilder BuildMI(MachineFunction &MF, DebugLoc DL, const MCInstrDesc &MCID)
virtual const TargetInstrInfo * getInstrInfo() const
STATISTIC(LongBranches,"Number of long branches.")
void setDesc(const MCInstrDesc &tid)
const unsigned CCMASK_CMP_NE
FunctionPass * createSystemZLongBranchPass(SystemZTargetMachine &TM)
const TargetMachine & getTarget() const
virtual const HexagonRegisterInfo & getRegisterInfo() const
const MachineInstrBuilder & addOperand(const MachineOperand &MO) const
bool addRegisterKilled(unsigned IncomingReg, const TargetRegisterInfo *RegInfo, bool AddIfNotFound=false)
DebugLoc getDebugLoc() const
bool isUnconditionalBranch(QueryType Type=AnyInBundle) const
unsigned getAlignment() const