diff options
Diffstat (limited to 'llvm/lib')
-rw-r--r-- | llvm/lib/Target/SystemZ/CMakeLists.txt | 1 | ||||
-rw-r--r-- | llvm/lib/Target/SystemZ/MCTargetDesc/SystemZMCAsmBackend.cpp | 5 | ||||
-rw-r--r-- | llvm/lib/Target/SystemZ/README.txt | 6 | ||||
-rw-r--r-- | llvm/lib/Target/SystemZ/SystemZ.h | 1 | ||||
-rw-r--r-- | llvm/lib/Target/SystemZ/SystemZISelLowering.cpp | 14 | ||||
-rw-r--r-- | llvm/lib/Target/SystemZ/SystemZInstrInfo.cpp | 16 | ||||
-rw-r--r-- | llvm/lib/Target/SystemZ/SystemZInstrInfo.h | 3 | ||||
-rw-r--r-- | llvm/lib/Target/SystemZ/SystemZInstrInfo.td | 13 | ||||
-rw-r--r-- | llvm/lib/Target/SystemZ/SystemZLongBranch.cpp | 357 | ||||
-rw-r--r-- | llvm/lib/Target/SystemZ/SystemZMCInstLower.cpp | 9 | ||||
-rw-r--r-- | llvm/lib/Target/SystemZ/SystemZTargetMachine.cpp | 8 |
11 files changed, 399 insertions, 34 deletions
diff --git a/llvm/lib/Target/SystemZ/CMakeLists.txt b/llvm/lib/Target/SystemZ/CMakeLists.txt index 757d5a88986..edb679dabfd 100644 --- a/llvm/lib/Target/SystemZ/CMakeLists.txt +++ b/llvm/lib/Target/SystemZ/CMakeLists.txt @@ -19,6 +19,7 @@ add_llvm_target(SystemZCodeGen SystemZISelDAGToDAG.cpp SystemZISelLowering.cpp SystemZInstrInfo.cpp + SystemZLongBranch.cpp SystemZMCInstLower.cpp SystemZRegisterInfo.cpp SystemZSubtarget.cpp diff --git a/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZMCAsmBackend.cpp b/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZMCAsmBackend.cpp index e901c6c6919..027db441d60 100644 --- a/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZMCAsmBackend.cpp +++ b/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZMCAsmBackend.cpp @@ -35,11 +35,10 @@ static uint64_t extractBitsForFixup(MCFixupKind Kind, uint64_t Value) { llvm_unreachable("Unknown fixup kind!"); } -// If Opcode can be relaxed, return the relaxed form, otherwise return 0. +// If Opcode is a relaxable interprocedural reference, return the relaxed form, +// otherwise return 0. static unsigned getRelaxedOpcode(unsigned Opcode) { switch (Opcode) { - case SystemZ::BRC: return SystemZ::BRCL; - case SystemZ::J: return SystemZ::JG; case SystemZ::BRAS: return SystemZ::BRASL; } return 0; diff --git a/llvm/lib/Target/SystemZ/README.txt b/llvm/lib/Target/SystemZ/README.txt index 8f5a5476b41..b6cd5de1fe6 100644 --- a/llvm/lib/Target/SystemZ/README.txt +++ b/llvm/lib/Target/SystemZ/README.txt @@ -56,11 +56,7 @@ and conditional returns. -- -We don't use the combined COMPARE AND BRANCH instructions. Using them -would require a change to the way we handle out-of-range branches. -At the moment, we start with 32-bit forms like BRCL and shorten them -to forms like BRC where possible, but COMPARE AND BRANCH does not have -a 32-bit form. +We don't use the combined COMPARE AND BRANCH instructions. -- diff --git a/llvm/lib/Target/SystemZ/SystemZ.h b/llvm/lib/Target/SystemZ/SystemZ.h index b811cbe9f04..24612bbce83 100644 --- a/llvm/lib/Target/SystemZ/SystemZ.h +++ b/llvm/lib/Target/SystemZ/SystemZ.h @@ -73,5 +73,6 @@ namespace llvm { FunctionPass *createSystemZISelDag(SystemZTargetMachine &TM, CodeGenOpt::Level OptLevel); + FunctionPass *createSystemZLongBranchPass(SystemZTargetMachine &TM); } // end namespace llvm; #endif diff --git a/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp b/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp index ea094b39f35..6ac32a3534d 100644 --- a/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp +++ b/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp @@ -1632,7 +1632,7 @@ SystemZTargetLowering::emitSelect(MachineInstr *MI, // jCC JoinMBB // # fallthrough to FalseMBB MBB = StartMBB; - BuildMI(MBB, DL, TII->get(SystemZ::BRCL)).addImm(CCMask).addMBB(JoinMBB); + BuildMI(MBB, DL, TII->get(SystemZ::BRC)).addImm(CCMask).addMBB(JoinMBB); MBB->addSuccessor(JoinMBB); MBB->addSuccessor(FalseMBB); @@ -1769,7 +1769,7 @@ SystemZTargetLowering::emitAtomicLoadBinary(MachineInstr *MI, .addReg(RotatedNewVal).addReg(NegBitShift).addImm(0); BuildMI(MBB, DL, TII->get(CSOpcode), Dest) .addReg(OldVal).addReg(NewVal).addOperand(Base).addImm(Disp); - BuildMI(MBB, DL, TII->get(SystemZ::BRCL)).addImm(MaskNE).addMBB(LoopMBB); + BuildMI(MBB, DL, TII->get(SystemZ::BRC)).addImm(MaskNE).addMBB(LoopMBB); MBB->addSuccessor(LoopMBB); MBB->addSuccessor(DoneMBB); @@ -1846,7 +1846,7 @@ SystemZTargetLowering::emitAtomicLoadMinMax(MachineInstr *MI, // %OldVal = phi [ %OrigVal, StartMBB ], [ %Dest, UpdateMBB ] // %RotatedOldVal = RLL %OldVal, 0(%BitShift) // CompareOpcode %RotatedOldVal, %Src2 - // BRCL KeepOldMask, UpdateMBB + // BRC KeepOldMask, UpdateMBB MBB = LoopMBB; BuildMI(MBB, DL, TII->get(SystemZ::PHI), OldVal) .addReg(OrigVal).addMBB(StartMBB) @@ -1856,7 +1856,7 @@ SystemZTargetLowering::emitAtomicLoadMinMax(MachineInstr *MI, .addReg(OldVal).addReg(BitShift).addImm(0); BuildMI(MBB, DL, TII->get(CompareOpcode)) .addReg(RotatedOldVal).addReg(Src2); - BuildMI(MBB, DL, TII->get(SystemZ::BRCL)) + BuildMI(MBB, DL, TII->get(SystemZ::BRC)) .addImm(KeepOldMask).addMBB(UpdateMBB); MBB->addSuccessor(UpdateMBB); MBB->addSuccessor(UseAltMBB); @@ -1887,7 +1887,7 @@ SystemZTargetLowering::emitAtomicLoadMinMax(MachineInstr *MI, .addReg(RotatedNewVal).addReg(NegBitShift).addImm(0); BuildMI(MBB, DL, TII->get(CSOpcode), Dest) .addReg(OldVal).addReg(NewVal).addOperand(Base).addImm(Disp); - BuildMI(MBB, DL, TII->get(SystemZ::BRCL)).addImm(MaskNE).addMBB(LoopMBB); + BuildMI(MBB, DL, TII->get(SystemZ::BRC)).addImm(MaskNE).addMBB(LoopMBB); MBB->addSuccessor(LoopMBB); MBB->addSuccessor(DoneMBB); @@ -1978,7 +1978,7 @@ SystemZTargetLowering::emitAtomicCmpSwapW(MachineInstr *MI, .addReg(CmpVal).addReg(Dest).addImm(32).addImm(63 - BitSize).addImm(0); BuildMI(MBB, DL, TII->get(SystemZ::CR)) .addReg(Dest).addReg(RetryCmpVal); - BuildMI(MBB, DL, TII->get(SystemZ::BRCL)).addImm(MaskNE).addMBB(DoneMBB); + BuildMI(MBB, DL, TII->get(SystemZ::BRC)).addImm(MaskNE).addMBB(DoneMBB); MBB->addSuccessor(DoneMBB); MBB->addSuccessor(SetMBB); @@ -1998,7 +1998,7 @@ SystemZTargetLowering::emitAtomicCmpSwapW(MachineInstr *MI, .addReg(RetrySwapVal).addReg(NegBitShift).addImm(-BitSize); BuildMI(MBB, DL, TII->get(CSOpcode), RetryOldVal) .addReg(OldVal).addReg(StoreVal).addOperand(Base).addImm(Disp); - BuildMI(MBB, DL, TII->get(SystemZ::BRCL)).addImm(MaskNE).addMBB(LoopMBB); + BuildMI(MBB, DL, TII->get(SystemZ::BRC)).addImm(MaskNE).addMBB(LoopMBB); MBB->addSuccessor(LoopMBB); MBB->addSuccessor(DoneMBB); diff --git a/llvm/lib/Target/SystemZ/SystemZInstrInfo.cpp b/llvm/lib/Target/SystemZ/SystemZInstrInfo.cpp index 0718c83fc72..e13a3d95864 100644 --- a/llvm/lib/Target/SystemZ/SystemZInstrInfo.cpp +++ b/llvm/lib/Target/SystemZ/SystemZInstrInfo.cpp @@ -13,6 +13,7 @@ #include "SystemZInstrInfo.h" #include "SystemZInstrBuilder.h" +#include "llvm/Target/TargetMachine.h" #define GET_INSTRINFO_CTOR #define GET_INSTRMAP_INFO @@ -229,19 +230,19 @@ SystemZInstrInfo::InsertBranch(MachineBasicBlock &MBB, MachineBasicBlock *TBB, if (Cond.empty()) { // Unconditional branch? assert(!FBB && "Unconditional branch with multiple successors!"); - BuildMI(&MBB, DL, get(SystemZ::JG)).addMBB(TBB); + BuildMI(&MBB, DL, get(SystemZ::J)).addMBB(TBB); return 1; } // Conditional branch. unsigned Count = 0; unsigned CC = Cond[0].getImm(); - BuildMI(&MBB, DL, get(SystemZ::BRCL)).addImm(CC).addMBB(TBB); + BuildMI(&MBB, DL, get(SystemZ::BRC)).addImm(CC).addMBB(TBB); ++Count; if (FBB) { // Two-way Conditional branch. Insert the second branch. - BuildMI(&MBB, DL, get(SystemZ::JG)).addMBB(FBB); + BuildMI(&MBB, DL, get(SystemZ::J)).addMBB(FBB); ++Count; } return Count; @@ -348,6 +349,15 @@ ReverseBranchCondition(SmallVectorImpl<MachineOperand> &Cond) const { return false; } +uint64_t SystemZInstrInfo::getInstSizeInBytes(const MachineInstr *MI) const { + if (MI->getOpcode() == TargetOpcode::INLINEASM) { + const MachineFunction *MF = MI->getParent()->getParent(); + const char *AsmStr = MI->getOperand(0).getSymbolName(); + return getInlineAsmLength(AsmStr, *MF->getTarget().getMCAsmInfo()); + } + return MI->getDesc().getSize(); +} + bool SystemZInstrInfo::isBranch(const MachineInstr *MI, unsigned &Cond, const MachineOperand *&Target) const { switch (MI->getOpcode()) { diff --git a/llvm/lib/Target/SystemZ/SystemZInstrInfo.h b/llvm/lib/Target/SystemZ/SystemZInstrInfo.h index 0fc47617f0a..7fcc2c5ce70 100644 --- a/llvm/lib/Target/SystemZ/SystemZInstrInfo.h +++ b/llvm/lib/Target/SystemZ/SystemZInstrInfo.h @@ -93,6 +93,9 @@ public: // Return the SystemZRegisterInfo, which this class owns. const SystemZRegisterInfo &getRegisterInfo() const { return RI; } + // Return the size in bytes of MI. + uint64_t getInstSizeInBytes(const MachineInstr *MI) const; + // Return true if MI is a conditional or unconditional branch. // When returning true, set Cond to the mask of condition-code // values on which the instruction will branch, and set Target diff --git a/llvm/lib/Target/SystemZ/SystemZInstrInfo.td b/llvm/lib/Target/SystemZ/SystemZInstrInfo.td index 903fb740a4e..d07e4a1ff4d 100644 --- a/llvm/lib/Target/SystemZ/SystemZInstrInfo.td +++ b/llvm/lib/Target/SystemZ/SystemZInstrInfo.td @@ -45,16 +45,13 @@ let isBranch = 1, isTerminator = 1, isBarrier = 1, R1 = 15 in { def BR : InstRR<0x07, (outs), (ins ADDR64:$R2), "br\t$R2", [(brind ADDR64:$R2)]>; - // An assembler extended mnemonic for BRC. Use a separate instruction for - // the asm parser, so that we don't relax Js to external symbols into JGs. - let isCodeGenOnly = 1 in - def J : InstRI<0xA74, (outs), (ins brtarget16:$I2), "j\t$I2", []>; - def AsmJ : InstRI<0xA74, (outs), (ins brtarget16:$I2), "j\t$I2", []>; + // An assembler extended mnemonic for BRC. + def J : InstRI<0xA74, (outs), (ins brtarget16:$I2), "j\t$I2", + [(br bb:$I2)]>; // An assembler extended mnemonic for BRCL. (The extension is "G" // rather than "L" because "JL" is "Jump if Less".) - def JG : InstRIL<0xC04, (outs), (ins brtarget32:$I2), - "jg\t$I2", [(br bb:$I2)]>; + def JG : InstRIL<0xC04, (outs), (ins brtarget32:$I2), "jg\t$I2", []>; } // Conditional branches. It's easier for LLVM to handle these branches @@ -71,7 +68,7 @@ let isCodeGenOnly = 1 in defm BRC : CondBranches<cond4, "j$R1\t$I2", "jg$R1\t$I2">; defm AsmBRC : CondBranches<uimm8zx4, "brc\t$R1, $I2", "brcl\t$R1, $I2">; -def : Pat<(z_br_ccmask cond4:$cond, bb:$dst), (BRCL cond4:$cond, bb:$dst)>; +def : Pat<(z_br_ccmask cond4:$cond, bb:$dst), (BRC cond4:$cond, bb:$dst)>; // Define AsmParser mnemonics for each condition code. multiclass CondExtendedMnemonic<bits<4> Cond, string name> { diff --git a/llvm/lib/Target/SystemZ/SystemZLongBranch.cpp b/llvm/lib/Target/SystemZ/SystemZLongBranch.cpp new file mode 100644 index 00000000000..d9d1c7ea699 --- /dev/null +++ b/llvm/lib/Target/SystemZ/SystemZLongBranch.cpp @@ -0,0 +1,357 @@ +//===-- SystemZLongBranch.cpp - Branch lengthening for SystemZ ------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This pass makes sure that all branches are in range. There are several ways +// in which this could be done. One aggressive approach is to assume that all +// branches are in range and successively replace those that turn out not +// to be in range with a longer form (branch relaxation). A simple +// implementation is to continually walk through the function relaxing +// branches until no more changes are needed and a fixed point is reached. +// However, in the pathological worst case, this implementation is +// quadratic in the number of blocks; relaxing branch N can make branch N-1 +// go out of range, which in turn can make branch N-2 go out of range, +// and so on. +// +// An alternative approach is to assume that all branches must be +// converted to their long forms, then reinstate the short forms of +// branches that, even under this pessimistic assumption, turn out to be +// in range (branch shortening). This too can be implemented as a function +// walk that is repeated until a fixed point is reached. In general, +// the result of shortening is not as good as that of relaxation, and +// shortening is also quadratic in the worst case; shortening branch N +// can bring branch N-1 in range of the short form, which in turn can do +// the same for branch N-2, and so on. The main advantage of shortening +// is that each walk through the function produces valid code, so it is +// possible to stop at any point after the first walk. The quadraticness +// could therefore be handled with a maximum pass count, although the +// question then becomes: what maximum count should be used? +// +// On SystemZ, long branches are only needed for functions bigger than 64k, +// which are relatively rare to begin with, and the long branch sequences +// are actually relatively cheap. It therefore doesn't seem worth spending +// much compilation time on the problem. Instead, the approach we take is: +// +// (1) Check whether all branches can be short (the usual case). Exit the +// pass if so. +// (2) If one branch needs to be long, work out the address that each block +// would have if all branches need to be long, as for shortening above. +// (3) Relax any branch that is out of range according to this pessimistic +// assumption. +// +//===----------------------------------------------------------------------===// + +#define DEBUG_TYPE "systemz-long-branch" + +#include "SystemZTargetMachine.h" +#include "llvm/ADT/Statistic.h" +#include "llvm/CodeGen/MachineFunctionPass.h" +#include "llvm/CodeGen/MachineInstrBuilder.h" +#include "llvm/IR/Function.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/MathExtras.h" +#include "llvm/Target/TargetInstrInfo.h" +#include "llvm/Target/TargetMachine.h" +#include "llvm/Target/TargetRegisterInfo.h" + +using namespace llvm; + +STATISTIC(LongBranches, "Number of long branches."); + +namespace { + typedef MachineBasicBlock::iterator Iter; + + // Represents positional information about a basic block. + struct MBBInfo { + // The address that we currently assume the block has, relative to + // the start of the function. This is designed so that taking the + // difference between two addresses gives a conservative upper bound + // on the distance between them. + uint64_t Address; + + // The size of the block in bytes, excluding terminators. + // This value never changes. + uint64_t Size; + + // The minimum alignment of the block, as a log2 value. + // This value never changes. + unsigned Alignment; + + // The number of terminators in this block. This value never changes. + unsigned NumTerminators; + + MBBInfo() + : Address(0), Size(0), Alignment(0), NumTerminators(0) {} + }; + + // Represents the state of a block terminator. + struct TerminatorInfo { + // If this terminator is a relaxable branch, this points to the branch + // instruction, otherwise it is null. + MachineInstr *Branch; + + // The current address of the terminator, in the same form as + // for BlockInfo. + uint64_t Address; + + // The current size of the terminator in bytes. + uint64_t Size; + + // If Branch is nonnull, this is the number of the target block, + // otherwise it is unused. + unsigned TargetBlock; + + // If Branch is nonnull, this is the length of the longest relaxed form, + // otherwise it is zero. + unsigned ExtraRelaxSize; + + TerminatorInfo() : Branch(0), Size(0), TargetBlock(0), ExtraRelaxSize(0) {} + }; + + // Used to keep track of the current position while iterating over the blocks. + struct BlockPosition { + // The offset from the start of the function, in the same form + // as BlockInfo. + uint64_t Address; + + // The number of low bits in Address that are known to be the same + // as the runtime address. + unsigned KnownBits; + + BlockPosition(unsigned InitialAlignment) + : Address(0), KnownBits(InitialAlignment) {} + }; + + class SystemZLongBranch : public MachineFunctionPass { + public: + static char ID; + SystemZLongBranch(const SystemZTargetMachine &tm) + : MachineFunctionPass(ID), + TII(static_cast<const SystemZInstrInfo *>(tm.getInstrInfo())) {} + + virtual const char *getPassName() const { + return "SystemZ Long Branch"; + } + + bool runOnMachineFunction(MachineFunction &F); + + private: + void skipNonTerminators(BlockPosition &Position, MBBInfo &Block); + void skipTerminator(BlockPosition &Position, TerminatorInfo &Terminator, + bool AssumeRelaxed); + TerminatorInfo describeTerminator(MachineInstr *MI); + uint64_t initMBBInfo(); + bool mustRelaxBranch(const TerminatorInfo &Terminator); + bool mustRelaxABranch(); + void setWorstCaseAddresses(); + void relaxBranch(TerminatorInfo &Terminator); + void relaxBranches(); + + const SystemZInstrInfo *TII; + MachineFunction *MF; + SmallVector<MBBInfo, 16> MBBs; + SmallVector<TerminatorInfo, 16> Terminators; + }; + + char SystemZLongBranch::ID = 0; + + const uint64_t MaxBackwardRange = 0x10000; + const uint64_t MaxForwardRange = 0xfffe; +} // end of anonymous namespace + +FunctionPass *llvm::createSystemZLongBranchPass(SystemZTargetMachine &TM) { + return new SystemZLongBranch(TM); +} + +// Position describes the state immediately before Block. Update Block +// accordingly and move Position to the end of the block's non-terminator +// instructions. +void SystemZLongBranch::skipNonTerminators(BlockPosition &Position, + MBBInfo &Block) { + if (Block.Alignment > Position.KnownBits) { + // When calculating the address of Block, we need to conservatively + // assume that Block had the worst possible misalignment. + Position.Address += ((uint64_t(1) << Block.Alignment) - + (uint64_t(1) << Position.KnownBits)); + Position.KnownBits = Block.Alignment; + } + + // Align the addresses. + uint64_t AlignMask = (uint64_t(1) << Block.Alignment) - 1; + Position.Address = (Position.Address + AlignMask) & ~AlignMask; + + // Record the block's position. + Block.Address = Position.Address; + + // Move past the non-terminators in the block. + Position.Address += Block.Size; +} + +// Position describes the state immediately before Terminator. +// Update Terminator accordingly and move Position past it. +// Assume that Terminator will be relaxed if AssumeRelaxed. +void SystemZLongBranch::skipTerminator(BlockPosition &Position, + TerminatorInfo &Terminator, + bool AssumeRelaxed) { + Terminator.Address = Position.Address; + Position.Address += Terminator.Size; + if (AssumeRelaxed) + Position.Address += Terminator.ExtraRelaxSize; +} + +// Return a description of terminator instruction MI. +TerminatorInfo SystemZLongBranch::describeTerminator(MachineInstr *MI) { + TerminatorInfo Terminator; + Terminator.Size = TII->getInstSizeInBytes(MI); + if (MI->isConditionalBranch() || MI->isUnconditionalBranch()) { + Terminator.Branch = MI; + switch (MI->getOpcode()) { + case SystemZ::J: + // Relaxes to JG, which is 2 bytes longer. + Terminator.TargetBlock = MI->getOperand(0).getMBB()->getNumber(); + Terminator.ExtraRelaxSize = 2; + break; + case SystemZ::BRC: + // Relaxes to BRCL, which is 2 bytes longer. Operand 0 is the + // condition code mask. + Terminator.TargetBlock = MI->getOperand(1).getMBB()->getNumber(); + Terminator.ExtraRelaxSize = 2; + break; + default: + llvm_unreachable("Unrecognized branch instruction"); + } + } + return Terminator; +} + +// Fill MBBs and Terminators, setting the addresses on the assumption +// that no branches need relaxation. Return the size of the function under +// this assumption. +uint64_t SystemZLongBranch::initMBBInfo() { + MF->RenumberBlocks(); + unsigned NumBlocks = MF->size(); + + MBBs.clear(); + MBBs.resize(NumBlocks); + + Terminators.clear(); + Terminators.reserve(NumBlocks); + + BlockPosition Position(MF->getAlignment()); + for (unsigned I = 0; I < NumBlocks; ++I) { + MachineBasicBlock *MBB = MF->getBlockNumbered(I); + MBBInfo &Block = MBBs[I]; + + // Record the alignment, for quick access. + Block.Alignment = MBB->getAlignment(); + + // Calculate the size of the fixed part of the block. + MachineBasicBlock::iterator MI = MBB->begin(); + MachineBasicBlock::iterator End = MBB->end(); + while (MI != End && !MI->isTerminator()) { + Block.Size += TII->getInstSizeInBytes(MI); + ++MI; + } + skipNonTerminators(Position, Block); + + // Add the terminators. + while (MI != End) { + if (!MI->isDebugValue()) { + assert(MI->isTerminator() && "Terminator followed by non-terminator"); + Terminators.push_back(describeTerminator(MI)); + skipTerminator(Position, Terminators.back(), false); + ++Block.NumTerminators; + } + ++MI; + } + } + + return Position.Address; +} + +// Return true if, under current assumptions, Terminator needs to be relaxed. +bool SystemZLongBranch::mustRelaxBranch(const TerminatorInfo &Terminator) { + if (!Terminator.Branch) + return false; + + const MBBInfo &Target = MBBs[Terminator.TargetBlock]; + if (Target.Address < Terminator.Address) { + if (Terminator.Address - Target.Address <= MaxBackwardRange) + return false; + } else { + if (Target.Address - Terminator.Address <= MaxForwardRange) + return false; + } + + return true; +} + +// Return true if, under current assumptions, any terminator needs +// to be relaxed. +bool SystemZLongBranch::mustRelaxABranch() { + for (SmallVector<TerminatorInfo, 16>::iterator TI = Terminators.begin(), + TE = Terminators.end(); TI != TE; ++TI) + if (mustRelaxBranch(*TI)) + return true; + return false; +} + +// Set the address of each block on the assumption that all branches +// must be long. +void SystemZLongBranch::setWorstCaseAddresses() { + SmallVector<TerminatorInfo, 16>::iterator TI = Terminators.begin(); + BlockPosition Position(MF->getAlignment()); + for (SmallVector<MBBInfo, 16>::iterator BI = MBBs.begin(), BE = MBBs.end(); + BI != BE; ++BI) { + skipNonTerminators(Position, *BI); + for (unsigned BTI = 0, BTE = BI->NumTerminators; BTI != BTE; ++BTI) { + skipTerminator(Position, *TI, true); + ++TI; + } + } +} + +// Relax the branch described by Terminator. +void SystemZLongBranch::relaxBranch(TerminatorInfo &Terminator) { + MachineInstr *Branch = Terminator.Branch; + switch (Branch->getOpcode()) { + case SystemZ::J: + Branch->setDesc(TII->get(SystemZ::JG)); + break; + case SystemZ::BRC: + Branch->setDesc(TII->get(SystemZ::BRCL)); + break; + default: + llvm_unreachable("Unrecognized branch"); + } + + Terminator.Size += Terminator.ExtraRelaxSize; + Terminator.ExtraRelaxSize = 0; + Terminator.Branch = 0; + + ++LongBranches; +} + +// Relax any branches that need to be relaxed, under current assumptions. +void SystemZLongBranch::relaxBranches() { + for (SmallVector<TerminatorInfo, 16>::iterator TI = Terminators.begin(), + TE = Terminators.end(); TI != TE; ++TI) + if (mustRelaxBranch(*TI)) + relaxBranch(*TI); +} + +bool SystemZLongBranch::runOnMachineFunction(MachineFunction &F) { + MF = &F; + uint64_t Size = initMBBInfo(); + if (Size <= MaxForwardRange || !mustRelaxABranch()) + return false; + + setWorstCaseAddresses(); + relaxBranches(); + return true; +} diff --git a/llvm/lib/Target/SystemZ/SystemZMCInstLower.cpp b/llvm/lib/Target/SystemZ/SystemZMCInstLower.cpp index 5d833213e6f..fd3f867015c 100644 --- a/llvm/lib/Target/SystemZ/SystemZMCInstLower.cpp +++ b/llvm/lib/Target/SystemZ/SystemZMCInstLower.cpp @@ -15,15 +15,10 @@ using namespace llvm; -// Where relaxable pairs of reloc-generating instructions exist, -// we tend to use the longest form by default, since that produces -// correct assembly in cases where no relaxation is performed. -// If Opcode is one such instruction, return the opcode for the -// shortest possible form instead, otherwise return Opcode itself. +// If Opcode is an interprocedural reference that can be shortened, +// return the short form, otherwise return 0. static unsigned getShortenedInstr(unsigned Opcode) { switch (Opcode) { - case SystemZ::BRCL: return SystemZ::BRC; - case SystemZ::JG: return SystemZ::J; case SystemZ::BRASL: return SystemZ::BRAS; } return Opcode; diff --git a/llvm/lib/Target/SystemZ/SystemZTargetMachine.cpp b/llvm/lib/Target/SystemZ/SystemZTargetMachine.cpp index 17450ee53e9..6e7540cec1f 100644 --- a/llvm/lib/Target/SystemZ/SystemZTargetMachine.cpp +++ b/llvm/lib/Target/SystemZ/SystemZTargetMachine.cpp @@ -47,7 +47,8 @@ public: return getTM<SystemZTargetMachine>(); } - virtual bool addInstSelector(); + virtual bool addInstSelector() LLVM_OVERRIDE; + virtual bool addPreEmitPass() LLVM_OVERRIDE; }; } // end anonymous namespace @@ -56,6 +57,11 @@ bool SystemZPassConfig::addInstSelector() { return false; } +bool SystemZPassConfig::addPreEmitPass() { + addPass(createSystemZLongBranchPass(getSystemZTargetMachine())); + return true; +} + TargetPassConfig *SystemZTargetMachine::createPassConfig(PassManagerBase &PM) { return new SystemZPassConfig(this, PM); } |