aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/llvm/CodeGen/MachineInstr.h4
-rw-r--r--include/llvm/CodeGen/MachineOperand.h17
-rw-r--r--lib/CodeGen/MachineInstr.cpp121
3 files changed, 100 insertions, 42 deletions
diff --git a/include/llvm/CodeGen/MachineInstr.h b/include/llvm/CodeGen/MachineInstr.h
index 67ae3f9..e6ed56b 100644
--- a/include/llvm/CodeGen/MachineInstr.h
+++ b/include/llvm/CodeGen/MachineInstr.h
@@ -952,8 +952,8 @@ private:
void untieRegOperand(unsigned OpIdx) {
MachineOperand &MO = getOperand(OpIdx);
if (MO.isReg() && MO.isTied()) {
- getOperand(findTiedOperandIdx(OpIdx)).IsTied = false;
- MO.IsTied = false;
+ getOperand(findTiedOperandIdx(OpIdx)).TiedTo = false;
+ MO.TiedTo = false;
}
}
diff --git a/include/llvm/CodeGen/MachineOperand.h b/include/llvm/CodeGen/MachineOperand.h
index baec882..5c6662e 100644
--- a/include/llvm/CodeGen/MachineOperand.h
+++ b/include/llvm/CodeGen/MachineOperand.h
@@ -70,6 +70,11 @@ private:
unsigned char TargetFlags;
};
+ /// TiedTo - Non-zero when this register operand is tied to another register
+ /// operand. The encoding of this field is described in the block comment
+ /// before MachineInstr::tieOperands().
+ unsigned char TiedTo : 4;
+
/// IsDef/IsImp/IsKill/IsDead flags - These are only valid for MO_Register
/// operands.
@@ -124,14 +129,6 @@ private:
/// model the GCC inline asm '&' constraint modifier.
bool IsEarlyClobber : 1;
- /// IsTied - True if this MO_Register operand is tied to another operand on
- /// the instruction. Tied operands form def-use pairs that must be assigned
- /// the same physical register by the register allocator, but they will have
- /// different virtual registers while the code is in SSA form.
- ///
- /// See MachineInstr::isRegTiedToUseOperand() and isRegTiedToDefOperand().
- bool IsTied : 1;
-
/// IsDebug - True if this MO_Register 'use' operand is in a debug pseudo,
/// not a real instruction. Such uses should be ignored during codegen.
bool IsDebug : 1;
@@ -309,7 +306,7 @@ public:
bool isTied() const {
assert(isReg() && "Wrong MachineOperand accessor");
- return IsTied;
+ return TiedTo;
}
bool isDebug() const {
@@ -572,7 +569,7 @@ public:
Op.IsUndef = isUndef;
Op.IsInternalRead = isInternalRead;
Op.IsEarlyClobber = isEarlyClobber;
- Op.IsTied = false;
+ Op.TiedTo = 0;
Op.IsDebug = isDebug;
Op.SmallContents.RegNo = Reg;
Op.Contents.Reg.Prev = 0;
diff --git a/lib/CodeGen/MachineInstr.cpp b/lib/CodeGen/MachineInstr.cpp
index 5a395fd..941847f 100644
--- a/lib/CodeGen/MachineInstr.cpp
+++ b/lib/CodeGen/MachineInstr.cpp
@@ -155,9 +155,9 @@ void MachineOperand::ChangeToRegister(unsigned Reg, bool isDef, bool isImp,
IsDebug = isDebug;
// Ensure isOnRegUseList() returns false.
Contents.Reg.Prev = 0;
- // Preserve the tie bit when the operand was already a register.
+ // Preserve the tie when the operand was already a register.
if (!WasReg)
- IsTied = false;
+ TiedTo = 0;
// If this operand is embedded in a function, add the operand to the
// register's use/def list.
@@ -310,6 +310,8 @@ void MachineOperand::print(raw_ostream &OS, const TargetMachine *TM) const {
if (isTied()) {
if (NeedComma) OS << ',';
OS << "tied";
+ if (TiedTo != 15)
+ OS << unsigned(TiedTo - 1);
NeedComma = true;
}
OS << '>';
@@ -681,6 +683,7 @@ void MachineInstr::addOperand(const MachineOperand &Op) {
if (!isImpReg && !isInlineAsm()) {
while (OpNo && Operands[OpNo-1].isReg() && Operands[OpNo-1].isImplicit()) {
--OpNo;
+ assert(!Operands[OpNo].isTied() && "Cannot move tied operands");
if (RegInfo)
RegInfo->removeRegOperandFromUseList(&Operands[OpNo]);
}
@@ -716,8 +719,8 @@ void MachineInstr::addOperand(const MachineOperand &Op) {
if (Operands[OpNo].isReg()) {
// Ensure isOnRegUseList() returns false, regardless of Op's status.
Operands[OpNo].Contents.Reg.Prev = 0;
- // Ignore existing IsTied bit. This is not a property that can be copied.
- Operands[OpNo].IsTied = false;
+ // Ignore existing ties. This is not a property that can be copied.
+ Operands[OpNo].TiedTo = 0;
// Add the new operand to RegInfo.
if (RegInfo)
RegInfo->addRegOperandToUseList(&Operands[OpNo]);
@@ -725,7 +728,7 @@ void MachineInstr::addOperand(const MachineOperand &Op) {
// explicit operands. The implicit operands are added first, then the
// explicits are inserted before them.
if (!isImpReg) {
- // Set the IsTied bit if MC indicates this use is tied to a def.
+ // Tie uses to defs as indicated in MCInstrDesc.
if (Operands[OpNo].isUse()) {
int DefIdx = MCID->getOperandConstraint(OpNo, MCOI::TIED_TO);
if (DefIdx != -1)
@@ -774,6 +777,13 @@ void MachineInstr::RemoveOperand(unsigned OpNo) {
}
}
+#ifndef NDEBUG
+ // Moving tied operands would break the ties.
+ for (unsigned i = OpNo + 1, e = Operands.size(); i != e; ++i)
+ if (Operands[i].isReg())
+ assert(!Operands[i].isTied() && "Cannot move tied operands");
+#endif
+
Operands.erase(Operands.begin()+OpNo);
if (RegInfo) {
@@ -1136,9 +1146,22 @@ int MachineInstr::findFirstPredOperandIdx() const {
return -1;
}
-/// Mark operands at DefIdx and UseIdx as tied to each other.
+// MachineOperand::TiedTo is 4 bits wide.
+const unsigned TiedMax = 15;
+
+/// tieOperands - Mark operands at DefIdx and UseIdx as tied to each other.
+///
+/// Use and def operands can be tied together, indicated by a non-zero TiedTo
+/// field. TiedTo can have these values:
+///
+/// 0: Operand is not tied to anything.
+/// 1 to TiedMax-1: Tied to getOperand(TiedTo-1).
+/// TiedMax: Tied to an operand >= TiedMax-1.
+///
+/// The tied def must be one of the first TiedMax operands on a normal
+/// instruction. INLINEASM instructions allow more tied defs.
+///
void MachineInstr::tieOperands(unsigned DefIdx, unsigned UseIdx) {
- assert(DefIdx < UseIdx && "Tied defs must precede the use");
MachineOperand &DefMO = getOperand(DefIdx);
MachineOperand &UseMO = getOperand(UseIdx);
assert(DefMO.isDef() && "DefIdx must be a def operand");
@@ -1146,38 +1169,76 @@ void MachineInstr::tieOperands(unsigned DefIdx, unsigned UseIdx) {
assert(!DefMO.isTied() && "Def is already tied to another use");
assert(!UseMO.isTied() && "Use is already tied to another def");
- DefMO.IsTied = true;
- UseMO.IsTied = true;
+ if (DefIdx < TiedMax)
+ UseMO.TiedTo = DefIdx + 1;
+ else {
+ // Inline asm can use the group descriptors to find tied operands, but on
+ // normal instruction, the tied def must be within the first TiedMax
+ // operands.
+ assert(isInlineAsm() && "DefIdx out of range");
+ UseMO.TiedTo = TiedMax;
+ }
+
+ // UseIdx can be out of range, we'll search for it in findTiedOperandIdx().
+ DefMO.TiedTo = std::min(UseIdx + 1, TiedMax);
}
/// Given the index of a tied register operand, find the operand it is tied to.
/// Defs are tied to uses and vice versa. Returns the index of the tied operand
/// which must exist.
unsigned MachineInstr::findTiedOperandIdx(unsigned OpIdx) const {
- // It doesn't usually happen, but an instruction can have multiple pairs of
- // tied operands.
- SmallVector<unsigned, 4> Uses, Defs;
- unsigned PairNo = ~0u;
- for (unsigned i = 0, e = getNumOperands(); i != e; ++i) {
- const MachineOperand &MO = getOperand(i);
- if (!MO.isReg() || !MO.isTied())
- continue;
- if (MO.isUse()) {
- if (i == OpIdx)
- PairNo = Uses.size();
- Uses.push_back(i);
- } else {
- if (i == OpIdx)
- PairNo = Defs.size();
- Defs.push_back(i);
+ const MachineOperand &MO = getOperand(OpIdx);
+ assert(MO.isTied() && "Operand isn't tied");
+
+ // Normally TiedTo is in range.
+ if (MO.TiedTo < TiedMax)
+ return MO.TiedTo - 1;
+
+ // Uses on normal instructions can be out of range.
+ if (!isInlineAsm()) {
+ // Normal tied defs must be in the 0..TiedMax-1 range.
+ if (MO.isUse())
+ return TiedMax - 1;
+ // MO is a def. Search for the tied use.
+ for (unsigned i = TiedMax - 1, e = getNumOperands(); i != e; ++i) {
+ const MachineOperand &UseMO = getOperand(i);
+ if (UseMO.isReg() && UseMO.isUse() && UseMO.TiedTo == OpIdx + 1)
+ return i;
}
+ llvm_unreachable("Can't find tied use");
}
- // For each tied use there must be a tied def and vice versa.
- assert(Uses.size() == Defs.size() && "Tied uses and defs don't match");
- assert(PairNo < Uses.size() && "OpIdx must be a tied register operand");
- // Find the matching operand.
- return (getOperand(OpIdx).isDef() ? Uses : Defs)[PairNo];
+ // Now deal with inline asm by parsing the operand group descriptor flags.
+ // Find the beginning of each operand group.
+ SmallVector<unsigned, 8> GroupIdx;
+ unsigned OpIdxGroup = ~0u;
+ unsigned NumOps;
+ for (unsigned i = InlineAsm::MIOp_FirstOperand, e = getNumOperands(); i < e;
+ i += NumOps) {
+ const MachineOperand &FlagMO = getOperand(i);
+ assert(FlagMO.isImm() && "Invalid tied operand on inline asm");
+ unsigned CurGroup = GroupIdx.size();
+ GroupIdx.push_back(i);
+ NumOps = 1 + InlineAsm::getNumOperandRegisters(FlagMO.getImm());
+ // OpIdx belongs to this operand group.
+ if (OpIdx > i && OpIdx < i + NumOps)
+ OpIdxGroup = CurGroup;
+ unsigned TiedGroup;
+ if (!InlineAsm::isUseOperandTiedToDef(FlagMO.getImm(), TiedGroup))
+ continue;
+ // Operands in this group are tied to operands in TiedGroup which must be
+ // earlier. Find the number of operands between the two groups.
+ unsigned Delta = i - GroupIdx[TiedGroup];
+
+ // OpIdx is a use tied to TiedGroup.
+ if (OpIdxGroup == CurGroup)
+ return OpIdx - Delta;
+
+ // OpIdx is a def tied to this use group.
+ if (OpIdxGroup == TiedGroup)
+ return OpIdx + Delta;
+ }
+ llvm_unreachable("Invalid tied operand on inline asm");
}
/// isRegTiedToUseOperand - Given the index of a register def operand,