|
@@ -195,14 +195,23 @@ namespace {
|
|
MachineInstr *MI;
|
|
MachineInstr *MI;
|
|
MachineInstr *CPEMI;
|
|
MachineInstr *CPEMI;
|
|
MachineBasicBlock *HighWaterMark;
|
|
MachineBasicBlock *HighWaterMark;
|
|
|
|
+ private:
|
|
unsigned MaxDisp;
|
|
unsigned MaxDisp;
|
|
|
|
+ public:
|
|
bool NegOk;
|
|
bool NegOk;
|
|
bool IsSoImm;
|
|
bool IsSoImm;
|
|
|
|
+ bool KnownAlignment;
|
|
CPUser(MachineInstr *mi, MachineInstr *cpemi, unsigned maxdisp,
|
|
CPUser(MachineInstr *mi, MachineInstr *cpemi, unsigned maxdisp,
|
|
bool neg, bool soimm)
|
|
bool neg, bool soimm)
|
|
- : MI(mi), CPEMI(cpemi), MaxDisp(maxdisp), NegOk(neg), IsSoImm(soimm) {
|
|
|
|
|
|
+ : MI(mi), CPEMI(cpemi), MaxDisp(maxdisp), NegOk(neg), IsSoImm(soimm),
|
|
|
|
+ KnownAlignment(false) {
|
|
HighWaterMark = CPEMI->getParent();
|
|
HighWaterMark = CPEMI->getParent();
|
|
}
|
|
}
|
|
|
|
+ /// getMaxDisp - Returns the maximum displacement supported by MI.
|
|
|
|
+ /// Correct for unknown alignment.
|
|
|
|
+ unsigned getMaxDisp() const {
|
|
|
|
+ return KnownAlignment ? MaxDisp : MaxDisp - 2;
|
|
|
|
+ }
|
|
};
|
|
};
|
|
|
|
|
|
/// CPUsers - Keep track of all of the machine instructions that use various
|
|
/// CPUsers - Keep track of all of the machine instructions that use various
|
|
@@ -309,6 +318,7 @@ namespace {
|
|
|
|
|
|
void ComputeBlockSize(MachineBasicBlock *MBB);
|
|
void ComputeBlockSize(MachineBasicBlock *MBB);
|
|
unsigned GetOffsetOf(MachineInstr *MI) const;
|
|
unsigned GetOffsetOf(MachineInstr *MI) const;
|
|
|
|
+ unsigned GetUserOffset(CPUser&) const;
|
|
void dumpBBs();
|
|
void dumpBBs();
|
|
void verify();
|
|
void verify();
|
|
|
|
|
|
@@ -317,7 +327,7 @@ namespace {
|
|
bool OffsetIsInRange(unsigned UserOffset, unsigned TrialOffset,
|
|
bool OffsetIsInRange(unsigned UserOffset, unsigned TrialOffset,
|
|
const CPUser &U) {
|
|
const CPUser &U) {
|
|
return OffsetIsInRange(UserOffset, TrialOffset,
|
|
return OffsetIsInRange(UserOffset, TrialOffset,
|
|
- U.MaxDisp, U.NegOk, U.IsSoImm);
|
|
|
|
|
|
+ U.getMaxDisp(), U.NegOk, U.IsSoImm);
|
|
}
|
|
}
|
|
};
|
|
};
|
|
char ARMConstantIslands::ID = 0;
|
|
char ARMConstantIslands::ID = 0;
|
|
@@ -336,11 +346,11 @@ void ARMConstantIslands::verify() {
|
|
}
|
|
}
|
|
for (unsigned i = 0, e = CPUsers.size(); i != e; ++i) {
|
|
for (unsigned i = 0, e = CPUsers.size(); i != e; ++i) {
|
|
CPUser &U = CPUsers[i];
|
|
CPUser &U = CPUsers[i];
|
|
- unsigned UserOffset = GetOffsetOf(U.MI) + (isThumb ? 4 : 8);
|
|
|
|
|
|
+ unsigned UserOffset = GetUserOffset(U);
|
|
unsigned CPEOffset = GetOffsetOf(U.CPEMI);
|
|
unsigned CPEOffset = GetOffsetOf(U.CPEMI);
|
|
unsigned Disp = UserOffset < CPEOffset ? CPEOffset - UserOffset :
|
|
unsigned Disp = UserOffset < CPEOffset ? CPEOffset - UserOffset :
|
|
UserOffset - CPEOffset;
|
|
UserOffset - CPEOffset;
|
|
- assert(Disp <= U.MaxDisp || "Constant pool entry out of range!");
|
|
|
|
|
|
+ assert(Disp <= U.getMaxDisp() || "Constant pool entry out of range!");
|
|
}
|
|
}
|
|
#endif
|
|
#endif
|
|
}
|
|
}
|
|
@@ -546,7 +556,8 @@ ARMConstantIslands::DoInitialPlacement(std::vector<MachineInstr*> &CPEMIs) {
|
|
CPEs.push_back(CPEntry(CPEMI, i));
|
|
CPEs.push_back(CPEntry(CPEMI, i));
|
|
CPEntries.push_back(CPEs);
|
|
CPEntries.push_back(CPEs);
|
|
++NumCPEs;
|
|
++NumCPEs;
|
|
- DEBUG(dbgs() << "Moved CPI#" << i << " to end of function\n");
|
|
|
|
|
|
+ DEBUG(dbgs() << "Moved CPI#" << i << " to end of function, size = "
|
|
|
|
+ << Size << ", align = " << Align <<'\n');
|
|
}
|
|
}
|
|
DEBUG(BB->dump());
|
|
DEBUG(BB->dump());
|
|
}
|
|
}
|
|
@@ -924,19 +935,39 @@ MachineBasicBlock *ARMConstantIslands::SplitBlockBeforeInstr(MachineInstr *MI) {
|
|
return NewBB;
|
|
return 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 ARMConstantIslands::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.
|
|
|
|
+ UserOffset += (isThumb ? 4 : 8);
|
|
|
|
+
|
|
|
|
+ // 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);
|
|
|
|
+
|
|
|
|
+ // On Thumb, offsets==2 mod 4 are rounded down by the hardware for
|
|
|
|
+ // purposes of the displacement computation; compensate for that here.
|
|
|
|
+ // For unknown alignments, getMaxDisp() constrains the range instead.
|
|
|
|
+ if (isThumb && U.KnownAlignment)
|
|
|
|
+ UserOffset &= ~3u;
|
|
|
|
+
|
|
|
|
+ return UserOffset;
|
|
|
|
+}
|
|
|
|
+
|
|
/// OffsetIsInRange - Checks whether UserOffset (the location of a constant pool
|
|
/// OffsetIsInRange - Checks whether UserOffset (the location of a constant pool
|
|
/// reference) is within MaxDisp of TrialOffset (a proposed location of a
|
|
/// reference) is within MaxDisp of TrialOffset (a proposed location of a
|
|
/// constant pool entry).
|
|
/// 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 ARMConstantIslands::OffsetIsInRange(unsigned UserOffset,
|
|
bool ARMConstantIslands::OffsetIsInRange(unsigned UserOffset,
|
|
unsigned TrialOffset, unsigned MaxDisp,
|
|
unsigned TrialOffset, unsigned MaxDisp,
|
|
bool NegativeOK, bool IsSoImm) {
|
|
bool NegativeOK, bool IsSoImm) {
|
|
- // On Thumb offsets==2 mod 4 are rounded down by the hardware for
|
|
|
|
- // purposes of the displacement computation; compensate for that here.
|
|
|
|
- // Effectively, the valid range of displacements is 2 bytes smaller for such
|
|
|
|
- // references.
|
|
|
|
- if (isThumb && UserOffset%4 !=0)
|
|
|
|
- UserOffset -= 2;
|
|
|
|
-
|
|
|
|
if (UserOffset <= TrialOffset) {
|
|
if (UserOffset <= TrialOffset) {
|
|
// User before the Trial.
|
|
// User before the Trial.
|
|
if (TrialOffset - UserOffset <= MaxDisp)
|
|
if (TrialOffset - UserOffset <= MaxDisp)
|
|
@@ -1086,7 +1117,7 @@ int ARMConstantIslands::LookForExistingCPEntry(CPUser& U, unsigned UserOffset)
|
|
MachineInstr *CPEMI = U.CPEMI;
|
|
MachineInstr *CPEMI = U.CPEMI;
|
|
|
|
|
|
// Check to see if the CPE is already in-range.
|
|
// Check to see if the CPE is already in-range.
|
|
- if (CPEIsInRange(UserMI, UserOffset, CPEMI, U.MaxDisp, U.NegOk, true)) {
|
|
|
|
|
|
+ if (CPEIsInRange(UserMI, UserOffset, CPEMI, U.getMaxDisp(), U.NegOk, true)) {
|
|
DEBUG(dbgs() << "In range\n");
|
|
DEBUG(dbgs() << "In range\n");
|
|
return 1;
|
|
return 1;
|
|
}
|
|
}
|
|
@@ -1101,7 +1132,8 @@ int ARMConstantIslands::LookForExistingCPEntry(CPUser& U, unsigned UserOffset)
|
|
// Removing CPEs can leave empty entries, skip
|
|
// Removing CPEs can leave empty entries, skip
|
|
if (CPEs[i].CPEMI == NULL)
|
|
if (CPEs[i].CPEMI == NULL)
|
|
continue;
|
|
continue;
|
|
- if (CPEIsInRange(UserMI, UserOffset, CPEs[i].CPEMI, U.MaxDisp, U.NegOk)) {
|
|
|
|
|
|
+ if (CPEIsInRange(UserMI, UserOffset, CPEs[i].CPEMI, U.getMaxDisp(),
|
|
|
|
+ U.NegOk)) {
|
|
DEBUG(dbgs() << "Replacing CPE#" << CPI << " with CPE#"
|
|
DEBUG(dbgs() << "Replacing CPE#" << CPI << " with CPE#"
|
|
<< CPEs[i].CPI << "\n");
|
|
<< CPEs[i].CPI << "\n");
|
|
// Point the CPUser node to the replacement
|
|
// Point the CPUser node to the replacement
|
|
@@ -1202,8 +1234,7 @@ void ARMConstantIslands::CreateNewWater(unsigned CPUserIndex,
|
|
// If the block does not end in an unconditional branch already, and if the
|
|
// If the block does not end in an unconditional branch already, and if the
|
|
// end of the block is within range, make new water there. (The addition
|
|
// end of the block is within range, make new water there. (The addition
|
|
// below is for the unconditional branch we will be adding: 4 bytes on ARM +
|
|
// below is for the unconditional branch we will be adding: 4 bytes on ARM +
|
|
- // Thumb2, 2 on Thumb1. Possible Thumb1 alignment padding is allowed for
|
|
|
|
- // inside OffsetIsInRange.
|
|
|
|
|
|
+ // Thumb2, 2 on Thumb1.
|
|
if (BBHasFallthrough(UserMBB)) {
|
|
if (BBHasFallthrough(UserMBB)) {
|
|
// Size of branch to insert.
|
|
// Size of branch to insert.
|
|
unsigned Delta = isThumb1 ? 2 : 4;
|
|
unsigned Delta = isThumb1 ? 2 : 4;
|
|
@@ -1256,7 +1287,7 @@ void ARMConstantIslands::CreateNewWater(unsigned CPUserIndex,
|
|
assert(LogAlign >= CPELogAlign && "Over-aligned constant pool entry");
|
|
assert(LogAlign >= CPELogAlign && "Over-aligned constant pool entry");
|
|
unsigned KnownBits = UserBBI.internalKnownBits();
|
|
unsigned KnownBits = UserBBI.internalKnownBits();
|
|
unsigned UPad = UnknownPadding(LogAlign, KnownBits);
|
|
unsigned UPad = UnknownPadding(LogAlign, KnownBits);
|
|
- unsigned BaseInsertOffset = UserOffset + U.MaxDisp;
|
|
|
|
|
|
+ unsigned BaseInsertOffset = UserOffset + U.getMaxDisp();
|
|
DEBUG(dbgs() << format("Split in middle of big block before %#x",
|
|
DEBUG(dbgs() << format("Split in middle of big block before %#x",
|
|
BaseInsertOffset));
|
|
BaseInsertOffset));
|
|
|
|
|
|
@@ -1337,9 +1368,8 @@ bool ARMConstantIslands::HandleConstantPoolUser(unsigned CPUserIndex) {
|
|
MachineInstr *CPEMI = U.CPEMI;
|
|
MachineInstr *CPEMI = U.CPEMI;
|
|
unsigned CPI = CPEMI->getOperand(1).getIndex();
|
|
unsigned CPI = CPEMI->getOperand(1).getIndex();
|
|
unsigned Size = CPEMI->getOperand(2).getImm();
|
|
unsigned Size = CPEMI->getOperand(2).getImm();
|
|
- // Compute this only once, it's expensive. The 4 or 8 is the value the
|
|
|
|
- // hardware keeps in the PC.
|
|
|
|
- unsigned UserOffset = GetOffsetOf(UserMI) + (isThumb ? 4 : 8);
|
|
|
|
|
|
+ // Compute this only once, it's expensive.
|
|
|
|
+ unsigned UserOffset = GetUserOffset(U);
|
|
|
|
|
|
// See if the current entry is within range, or there is a clone of it
|
|
// See if the current entry is within range, or there is a clone of it
|
|
// in range.
|
|
// in range.
|
|
@@ -1677,8 +1707,13 @@ bool ARMConstantIslands::OptimizeThumb2Instructions() {
|
|
if (!NewOpc)
|
|
if (!NewOpc)
|
|
continue;
|
|
continue;
|
|
|
|
|
|
- unsigned UserOffset = GetOffsetOf(U.MI) + 4;
|
|
|
|
|
|
+ unsigned UserOffset = GetUserOffset(U);
|
|
unsigned MaxOffs = ((1 << Bits) - 1) * Scale;
|
|
unsigned MaxOffs = ((1 << Bits) - 1) * Scale;
|
|
|
|
+
|
|
|
|
+ // Be conservative with inline asm.
|
|
|
|
+ if (!U.KnownAlignment)
|
|
|
|
+ MaxOffs -= 2;
|
|
|
|
+
|
|
// FIXME: Check if offset is multiple of scale if scale is not 4.
|
|
// FIXME: Check if offset is multiple of scale if scale is not 4.
|
|
if (CPEIsInRange(U.MI, UserOffset, U.CPEMI, MaxOffs, false, true)) {
|
|
if (CPEIsInRange(U.MI, UserOffset, U.CPEMI, MaxOffs, false, true)) {
|
|
U.MI->setDesc(TII->get(NewOpc));
|
|
U.MI->setDesc(TII->get(NewOpc));
|