cl::desc("Make small offsets be this amount for testing purposes"),
cl::Hidden);
-/// UnknownPadding - Return the worst case padding that could result from
-/// unknown offset bits. This does not include alignment padding caused by
-/// known offset bits.
-///
-/// @param LogAlign log2(alignment)
-/// @param KnownBits Number of known low offset bits.
-static inline unsigned UnknownPadding(unsigned LogAlign, unsigned KnownBits) {
- if (KnownBits < LogAlign)
- return (1u << LogAlign) - (1u << KnownBits);
- return 0;
-}
+//
+// For testing purposes we tell it to not use relaxed load forms so that it
+// will split blocks.
+//
+static cl::opt<bool> NoLoadRelaxation(
+ "mips-constant-islands-no-load-relaxation",
+ cl::init(false),
+ cl::desc("Don't relax loads to long loads - for testing purposes"),
+ cl::Hidden);
+
namespace {
/// beginning of the block, or from an aligned jump table at the end.
unsigned Size;
- /// KnownBits - The number of low bits in Offset that are known to be
- /// exact. The remaining bits of Offset are an upper bound.
- uint8_t KnownBits;
-
- /// Unalign - When non-zero, the block contains instructions (inline asm)
- /// of unknown size. The real size may be smaller than Size bytes by a
- /// multiple of 1 << Unalign.
- uint8_t Unalign;
-
- /// PostAlign - When non-zero, the block terminator contains a .align
- /// directive, so the end of the block is aligned to 1 << PostAlign
- /// bytes.
- uint8_t PostAlign;
-
- BasicBlockInfo() : Offset(0), Size(0), KnownBits(0), Unalign(0),
- PostAlign(0) {}
-
- /// Compute the number of known offset bits internally to this block.
- /// This number should be used to predict worst case padding when
- /// splitting the block.
- unsigned internalKnownBits() const {
- unsigned Bits = Unalign ? Unalign : KnownBits;
- // If the block size isn't a multiple of the known bits, assume the
- // worst case padding.
- if (Size & ((1u << Bits) - 1))
- Bits = countTrailingZeros(Size);
- return Bits;
- }
-
- /// Compute the offset immediately following this block. If LogAlign is
- /// specified, return the offset the successor block will get if it has
- /// this alignment.
+ // FIXME: ignore LogAlign for this patch
+ //
unsigned postOffset(unsigned LogAlign = 0) const {
unsigned PO = Offset + Size;
return PO;
}
- /// Compute the number of known low bits of postOffset. If this block
- /// contains inline asm, the number of known bits drops to the
- /// instruction alignment. An aligned terminator may increase the number
- /// of know bits.
- /// If LogAlign is given, also consider the alignment of the next block.
- unsigned postKnownBits(unsigned LogAlign = 0) const {
- return std::max(std::max(unsigned(PostAlign), LogAlign),
- internalKnownBits());
- }
+ BasicBlockInfo() : Offset(0), Size(0) {}
+
};
std::vector<BasicBlockInfo> BBInfo;
unsigned LongFormOpcode;
public:
bool NegOk;
- bool IsSoImm;
- bool KnownAlignment;
CPUser(MachineInstr *mi, MachineInstr *cpemi, unsigned maxdisp,
- bool neg, bool soimm,
+ bool neg,
unsigned longformmaxdisp, unsigned longformopcode)
: MI(mi), CPEMI(cpemi), MaxDisp(maxdisp),
LongFormMaxDisp(longformmaxdisp), LongFormOpcode(longformopcode),
- NegOk(neg), IsSoImm(soimm), KnownAlignment(false) {
+ NegOk(neg){
HighWaterMark = CPEMI->getParent();
}
/// getMaxDisp - Returns the maximum displacement supported by MI.
- /// Correct for unknown alignment.
- /// Conservatively subtract 2 bytes to handle weird alignment effects.
unsigned getMaxDisp() const {
unsigned xMaxDisp = ConstantIslandsSmallOffset?
ConstantIslandsSmallOffset: MaxDisp;
- return (KnownAlignment ? xMaxDisp : xMaxDisp - 2) - 2;
+ return xMaxDisp;
+ }
+ void setMaxDisp(unsigned val) {
+ MaxDisp = val;
}
unsigned getLongFormMaxDisp() const {
- return (KnownAlignment ? LongFormMaxDisp : LongFormMaxDisp - 2) - 2;
+ return LongFormMaxDisp;
}
unsigned getLongFormOpcode() const {
return LongFormOpcode;
void verify();
bool isOffsetInRange(unsigned UserOffset, unsigned TrialOffset,
- unsigned Disp, bool NegativeOK, bool IsSoImm = false);
+ unsigned Disp, bool NegativeOK);
bool isOffsetInRange(unsigned UserOffset, unsigned TrialOffset,
const CPUser &U);
(unsigned UserOffset, unsigned TrialOffset,
const CPUser &U) {
return isOffsetInRange(UserOffset, TrialOffset,
- U.getLongFormMaxDisp(), U.NegOk, U.IsSoImm);
+ U.getLongFormMaxDisp(), U.NegOk);
}
bool MipsConstantIslands::isOffsetInRange
(unsigned UserOffset, unsigned TrialOffset,
const CPUser &U) {
return isOffsetInRange(UserOffset, TrialOffset,
- U.getMaxDisp(), U.NegOk, U.IsSoImm);
+ U.getMaxDisp(), U.NegOk);
}
/// print block size and offset information - debugging
void MipsConstantIslands::dumpBBs() {
for (unsigned J = 0, E = BBInfo.size(); J !=E; ++J) {
const BasicBlockInfo &BBI = BBInfo[J];
dbgs() << format("%08x BB#%u\t", BBI.Offset, J)
- << " kb=" << unsigned(BBI.KnownBits)
- << " ua=" << unsigned(BBI.Unalign)
- << " pa=" << unsigned(BBI.PostAlign)
<< format(" size=%#x\n", BBInfo[J].Size);
}
});
for (MachineFunction::iterator I = MF->begin(), E = MF->end(); I != E; ++I)
computeBlockSize(I);
- // The known bits of the entry block offset are determined by the function
- // alignment.
- BBInfo.front().KnownBits = MF->getAlignment();
// Compute block offsets.
adjustBBOffsetsAfter(MF->begin());
continue;
int Opc = I->getOpcode();
+#ifdef IN_PROGRESS
if (I->isBranch()) {
bool isCond = false;
unsigned Bits = 0;
unsigned Scale = 1;
int UOpc = Opc;
-
switch (Opc) {
default:
continue; // Ignore other JT branches
// Record this immediate branch.
unsigned MaxOffs = ((1 << (Bits-1))-1) * Scale;
ImmBranches.push_back(ImmBranch(I, MaxOffs, isCond, UOpc));
-
}
-
+#endif
if (Opc == Mips::CONSTPOOL_ENTRY)
continue;
unsigned Bits = 0;
unsigned Scale = 1;
bool NegOk = false;
- bool IsSoImm = false;
unsigned LongFormBits = 0;
unsigned LongFormScale = 0;
unsigned LongFormOpcode = 0;
llvm_unreachable("Unknown addressing mode for CP reference!");
case Mips::LwRxPcTcp16:
Bits = 8;
- Scale = 2;
+ Scale = 4;
LongFormOpcode = Mips::LwRxPcTcpX16;
+ LongFormBits = 16;
+ LongFormScale = 1;
break;
case Mips::LwRxPcTcpX16:
Bits = 16;
- Scale = 2;
+ Scale = 1;
+ NegOk = true;
break;
}
// Remember that this is a user of a CP entry.
unsigned MaxOffs = ((1 << Bits)-1) * Scale;
unsigned LongFormMaxOffs = ((1 << LongFormBits)-1) * LongFormScale;
CPUsers.push_back(CPUser(I, CPEMI, MaxOffs, NegOk,
- IsSoImm, LongFormMaxOffs,
- LongFormOpcode));
+ LongFormMaxOffs, LongFormOpcode));
// Increment corresponding CPEntry reference count.
CPEntry *CPE = findConstPoolEntry(CPI, CPEMI);
void MipsConstantIslands::computeBlockSize(MachineBasicBlock *MBB) {
BasicBlockInfo &BBI = BBInfo[MBB->getNumber()];
BBI.Size = 0;
- BBI.Unalign = 0;
- BBI.PostAlign = 0;
for (MachineBasicBlock::iterator I = MBB->begin(), E = MBB->end(); I != E;
++I)
WaterList.insert(IP, NewBB);
}
-/// getUserOffset - Compute the offset of U.MI as seen by the hardware
-/// displacement computation. Update U.KnownAlignment to match its current
-/// basic block location.
unsigned MipsConstantIslands::getUserOffset(CPUser &U) const {
- unsigned UserOffset = getOffsetOf(U.MI);
- const BasicBlockInfo &BBI = BBInfo[U.MI->getParent()->getNumber()];
- unsigned KnownBits = BBI.internalKnownBits();
-
- // The value read from PC is offset from the actual instruction address.
-
-
- // Because of inline assembly, we may not know the alignment (mod 4) of U.MI.
- // Make sure U.getMaxDisp() returns a constrained range.
- U.KnownAlignment = (KnownBits >= 2);
-
-
- return UserOffset;
+ return getOffsetOf(U.MI);
}
/// Split the basic block containing MI into two blocks, which are joined by
// Note the new unconditional branch is not being recorded.
// There doesn't seem to be meaningful DebugInfo available; this doesn't
// correspond to anything in the source.
- BuildMI(OrigBB, DebugLoc(), TII->get(Mips::BimmX16)).addMBB(NewBB);
+ BuildMI(OrigBB, DebugLoc(), TII->get(Mips::Bimm16)).addMBB(NewBB);
++NumSplit;
// Update the CFG. All succs of OrigBB are now succs of NewBB.
/// isOffsetInRange - Checks whether UserOffset (the location of a constant pool
/// reference) is within MaxDisp of TrialOffset (a proposed location of a
/// constant pool entry).
-/// UserOffset is computed by getUserOffset above to include PC adjustments. If
-/// the mod 4 alignment of UserOffset is not known, the uncertainty must be
-/// subtracted from MaxDisp instead. CPUser::getMaxDisp() does that.
bool MipsConstantIslands::isOffsetInRange(unsigned UserOffset,
unsigned TrialOffset, unsigned MaxDisp,
- bool NegativeOK, bool IsSoImm) {
+ bool NegativeOK) {
if (UserOffset <= TrialOffset) {
// User before the Trial.
if (TrialOffset - UserOffset <= MaxDisp)
return true;
- // FIXME: Make use full range of soimm values.
} else if (NegativeOK) {
if (UserOffset - TrialOffset <= MaxDisp)
return true;
- // FIXME: Make use full range of soimm values.
}
return false;
}
// the offset of the instruction. Also account for unknown alignment padding
// in blocks between CPE and the user.
if (CPEOffset < UserOffset)
- UserOffset += Growth + UnknownPadding(MF->getAlignment(), CPELogAlign);
+ UserOffset += Growth;
} else
// CPE fits in existing padding.
Growth = 0;
MachineBasicBlock *Succ = *MBB->succ_begin();
MachineBasicBlock *Pred = *MBB->pred_begin();
MachineInstr *PredMI = &Pred->back();
- if (PredMI->getOpcode() == Mips::BimmX16)
+ if (PredMI->getOpcode() == Mips::Bimm16)
return PredMI->getOperand(0).getMBB() == Succ;
return false;
}
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.
- unsigned Offset = BBInfo[i - 1].postOffset();
+ unsigned Offset = BBInfo[i - 1].Offset + BBInfo[i - 1].Size;
BBInfo[i].Offset = Offset;
}
}
true)) {
DEBUG(dbgs() << "In range\n");
UserMI->setDesc(TII->get(U.getLongFormOpcode()));
+ U.setMaxDisp(U.getLongFormMaxDisp());
return 2; // instruction is longer length now
}
/// the specific unconditional branch instruction.
static inline unsigned getUnconditionalBrDisp(int Opc) {
switch (Opc) {
+ case Mips::Bimm16:
+ return ((1<<10)-1)*2;
case Mips::BimmX16:
return ((1<<16)-1)*2;
default:
// but if the preceding conditional branch is out of range, the targets
// will be exchanged, and the altered branch may be out of range, so the
// machinery has to know about it.
- int UncondBr = Mips::BimmX16;
+ int UncondBr = Mips::Bimm16;
BuildMI(UserMBB, DebugLoc(), TII->get(UncondBr)).addMBB(NewMBB);
unsigned MaxDisp = getUnconditionalBrDisp(UncondBr);
ImmBranches.push_back(ImmBranch(&UserMBB->back(),
// LogAlign which is the largest possible alignment in the function.
unsigned LogAlign = MF->getAlignment();
assert(LogAlign >= CPELogAlign && "Over-aligned constant pool entry");
- unsigned KnownBits = UserBBI.internalKnownBits();
- unsigned UPad = UnknownPadding(LogAlign, KnownBits);
- unsigned BaseInsertOffset = UserOffset + U.getMaxDisp() - UPad;
+ unsigned BaseInsertOffset = UserOffset + U.getMaxDisp();
DEBUG(dbgs() << format("Split in middle of big block before %#x",
BaseInsertOffset));
BaseInsertOffset -= 4;
DEBUG(dbgs() << format(", adjusted to %#x", BaseInsertOffset)
- << " la=" << LogAlign
- << " kb=" << KnownBits
- << " up=" << UPad << '\n');
+ << " la=" << LogAlign << '\n');
// This could point off the end of the block if we've already got constant
// pool entries following this block; only the last one is in the water list.
// Back past any possible branches (allow for a conditional and a maximally
// long unconditional).
if (BaseInsertOffset + 8 >= UserBBI.postOffset()) {
- BaseInsertOffset = UserBBI.postOffset() - UPad - 8;
+ BaseInsertOffset = UserBBI.postOffset() - 8;
DEBUG(dbgs() << format("Move inside block: %#x\n", BaseInsertOffset));
}
- unsigned EndInsertOffset = BaseInsertOffset + 4 + UPad +
+ unsigned EndInsertOffset = BaseInsertOffset + 4 +
CPEMI->getOperand(2).getImm();
MachineBasicBlock::iterator MI = UserMI;
++MI;
// No water found.
// we first see if a longer form of the instrucion could have reached
// the constant. in that case we won't bother to split
-#ifdef IN_PROGRESS
- result = findLongFormInRangeCPEntry(U, UserOffset);
-#endif
+ if (!NoLoadRelaxation) {
+ result = findLongFormInRangeCPEntry(U, UserOffset);
+ if (result != 0) return true;
+ }
DEBUG(dbgs() << "No water found\n");
createNewWater(CPUserIndex, UserOffset, NewMBB);