MachineOperand Operand;
StringRef::iterator Begin;
StringRef::iterator End;
+ Optional<unsigned> TiedDefIdx;
MachineOperandWithLocation(const MachineOperand &Operand,
- StringRef::iterator Begin, StringRef::iterator End)
- : Operand(Operand), Begin(Begin), End(End) {}
+ StringRef::iterator Begin, StringRef::iterator End,
+ Optional<unsigned> &TiedDefIdx)
+ : Operand(Operand), Begin(Begin), End(End), TiedDefIdx(TiedDefIdx) {
+ if (TiedDefIdx)
+ assert(Operand.isReg() && Operand.isUse() &&
+ "Only used register operands can be tied");
+ }
};
class MIParser {
bool parseRegister(unsigned &Reg);
bool parseRegisterFlag(unsigned &Flags);
bool parseSubRegisterIndex(unsigned &SubReg);
- bool parseRegisterOperand(MachineOperand &Dest, bool IsDef = false);
+ bool parseRegisterTiedDefIndex(unsigned &TiedDefIdx);
+ bool parseRegisterOperand(MachineOperand &Dest,
+ Optional<unsigned> &TiedDefIdx, bool IsDef = false);
bool parseImmediateOperand(MachineOperand &Dest);
bool parseIRConstant(StringRef::iterator Loc, const Constant *&C);
bool parseTypedImmediateOperand(MachineOperand &Dest);
bool parseBlockAddressOperand(MachineOperand &Dest);
bool parseTargetIndexOperand(MachineOperand &Dest);
bool parseLiveoutRegisterMaskOperand(MachineOperand &Dest);
- bool parseMachineOperand(MachineOperand &Dest);
- bool parseMachineOperandAndTargetFlags(MachineOperand &Dest);
+ bool parseMachineOperand(MachineOperand &Dest,
+ Optional<unsigned> &TiedDefIdx);
+ bool parseMachineOperandAndTargetFlags(MachineOperand &Dest,
+ Optional<unsigned> &TiedDefIdx);
bool parseOffset(int64_t &Offset);
bool parseAlignment(unsigned &Alignment);
bool parseOperandsOffset(MachineOperand &Op);
bool parseInstruction(unsigned &OpCode, unsigned &Flags);
+ bool assignRegisterTies(MachineInstr &MI,
+ ArrayRef<MachineOperandWithLocation> Operands);
+
bool verifyImplicitOperands(ArrayRef<MachineOperandWithLocation> Operands,
const MCInstrDesc &MCID);
SmallVector<MachineOperandWithLocation, 8> Operands;
while (Token.isRegister() || Token.isRegisterFlag()) {
auto Loc = Token.location();
- if (parseRegisterOperand(MO, /*IsDef=*/true))
+ Optional<unsigned> TiedDefIdx;
+ if (parseRegisterOperand(MO, TiedDefIdx, /*IsDef=*/true))
return true;
- Operands.push_back(MachineOperandWithLocation(MO, Loc, Token.location()));
+ Operands.push_back(
+ MachineOperandWithLocation(MO, Loc, Token.location(), TiedDefIdx));
if (Token.isNot(MIToken::comma))
break;
lex();
while (!Token.isNewlineOrEOF() && Token.isNot(MIToken::kw_debug_location) &&
Token.isNot(MIToken::coloncolon) && Token.isNot(MIToken::lbrace)) {
auto Loc = Token.location();
- if (parseMachineOperandAndTargetFlags(MO))
+ Optional<unsigned> TiedDefIdx;
+ if (parseMachineOperandAndTargetFlags(MO, TiedDefIdx))
return true;
- Operands.push_back(MachineOperandWithLocation(MO, Loc, Token.location()));
+ Operands.push_back(
+ MachineOperandWithLocation(MO, Loc, Token.location(), TiedDefIdx));
if (Token.isNewlineOrEOF() || Token.is(MIToken::coloncolon) ||
Token.is(MIToken::lbrace))
break;
MI->setFlags(Flags);
for (const auto &Operand : Operands)
MI->addOperand(MF, Operand.Operand);
+ if (assignRegisterTies(*MI, Operands))
+ return true;
if (MemOperands.empty())
return false;
MachineInstr::mmo_iterator MemRefs =
return false;
}
-bool MIParser::parseRegisterOperand(MachineOperand &Dest, bool IsDef) {
+bool MIParser::parseRegisterTiedDefIndex(unsigned &TiedDefIdx) {
+ if (!consumeIfPresent(MIToken::kw_tied_def))
+ return error("expected 'tied-def' after '('");
+ if (Token.isNot(MIToken::IntegerLiteral))
+ return error("expected an integer literal after 'tied-def'");
+ if (getUnsigned(TiedDefIdx))
+ return true;
+ lex();
+ if (expectAndConsume(MIToken::rparen))
+ return true;
+ return false;
+}
+
+bool MIParser::assignRegisterTies(
+ MachineInstr &MI, ArrayRef<MachineOperandWithLocation> Operands) {
+ SmallVector<std::pair<unsigned, unsigned>, 4> TiedRegisterPairs;
+ for (unsigned I = 0, E = Operands.size(); I != E; ++I) {
+ if (!Operands[I].TiedDefIdx)
+ continue;
+ // The parser ensures that this operand is a register use, so we just have
+ // to check the tied-def operand.
+ unsigned DefIdx = Operands[I].TiedDefIdx.getValue();
+ if (DefIdx >= E)
+ return error(Operands[I].Begin,
+ Twine("use of invalid tied-def operand index '" +
+ Twine(DefIdx) + "'; instruction has only ") +
+ Twine(E) + " operands");
+ const auto &DefOperand = Operands[DefIdx].Operand;
+ if (!DefOperand.isReg() || !DefOperand.isDef())
+ // FIXME: add note with the def operand.
+ return error(Operands[I].Begin,
+ Twine("use of invalid tied-def operand index '") +
+ Twine(DefIdx) + "'; the operand #" + Twine(DefIdx) +
+ " isn't a defined register");
+ // Check that the tied-def operand wasn't tied elsewhere.
+ for (const auto &TiedPair : TiedRegisterPairs) {
+ if (TiedPair.first == DefIdx)
+ return error(Operands[I].Begin,
+ Twine("the tied-def operand #") + Twine(DefIdx) +
+ " is already tied with another register operand");
+ }
+ TiedRegisterPairs.push_back(std::make_pair(DefIdx, I));
+ }
+ // FIXME: Verify that for non INLINEASM instructions, the def and use tied
+ // indices must be less than tied max.
+ for (const auto &TiedPair : TiedRegisterPairs)
+ MI.tieOperands(TiedPair.first, TiedPair.second);
+ return false;
+}
+
+bool MIParser::parseRegisterOperand(MachineOperand &Dest,
+ Optional<unsigned> &TiedDefIdx,
+ bool IsDef) {
unsigned Reg;
unsigned Flags = IsDef ? RegState::Define : 0;
while (Token.isRegisterFlag()) {
if (parseSubRegisterIndex(SubReg))
return true;
}
+ if ((Flags & RegState::Define) == 0 && consumeIfPresent(MIToken::lparen)) {
+ unsigned Idx;
+ if (parseRegisterTiedDefIndex(Idx))
+ return true;
+ TiedDefIdx = Idx;
+ }
Dest = MachineOperand::CreateReg(
Reg, Flags & RegState::Define, Flags & RegState::Implicit,
Flags & RegState::Kill, Flags & RegState::Dead, Flags & RegState::Undef,
return false;
}
-bool MIParser::parseMachineOperand(MachineOperand &Dest) {
+bool MIParser::parseMachineOperand(MachineOperand &Dest,
+ Optional<unsigned> &TiedDefIdx) {
switch (Token.kind()) {
case MIToken::kw_implicit:
case MIToken::kw_implicit_define:
case MIToken::underscore:
case MIToken::NamedRegister:
case MIToken::VirtualRegister:
- return parseRegisterOperand(Dest);
+ return parseRegisterOperand(Dest, TiedDefIdx);
case MIToken::IntegerLiteral:
return parseImmediateOperand(Dest);
case MIToken::IntegerType:
return false;
}
-bool MIParser::parseMachineOperandAndTargetFlags(MachineOperand &Dest) {
+bool MIParser::parseMachineOperandAndTargetFlags(
+ MachineOperand &Dest, Optional<unsigned> &TiedDefIdx) {
unsigned TF = 0;
bool HasTargetFlags = false;
if (Token.is(MIToken::kw_target_flags)) {
return true;
}
auto Loc = Token.location();
- if (parseMachineOperand(Dest))
+ if (parseMachineOperand(Dest, TiedDefIdx))
return true;
if (!HasTargetFlags)
return false;
void printOffset(int64_t Offset);
void printTargetFlags(const MachineOperand &Op);
void print(const MachineOperand &Op, const TargetRegisterInfo *TRI,
- bool IsDef = false);
+ unsigned I, bool ShouldPrintRegisterTies, bool IsDef = false);
void print(const MachineMemOperand &Op);
void print(const MCCFIInstruction &CFI, const TargetRegisterInfo *TRI);
OS.indent(2) << "}\n";
}
+/// Return true when an instruction has tied register that can't be determined
+/// by the instruction's descriptor.
+static bool hasComplexRegisterTies(const MachineInstr &MI) {
+ const MCInstrDesc &MCID = MI.getDesc();
+ for (unsigned I = 0, E = MI.getNumOperands(); I < E; ++I) {
+ const auto &Operand = MI.getOperand(I);
+ if (!Operand.isReg() || Operand.isDef())
+ // Ignore the defined registers as MCID marks only the uses as tied.
+ continue;
+ int ExpectedTiedIdx = MCID.getOperandConstraint(I, MCOI::TIED_TO);
+ int TiedIdx = Operand.isTied() ? int(MI.findTiedOperandIdx(I)) : -1;
+ if (ExpectedTiedIdx != TiedIdx)
+ return true;
+ }
+ return false;
+}
+
void MIPrinter::print(const MachineInstr &MI) {
const auto &SubTarget = MI.getParent()->getParent()->getSubtarget();
const auto *TRI = SubTarget.getRegisterInfo();
if (MI.isCFIInstruction())
assert(MI.getNumOperands() == 1 && "Expected 1 operand in CFI instruction");
+ bool ShouldPrintRegisterTies = hasComplexRegisterTies(MI);
unsigned I = 0, E = MI.getNumOperands();
for (; I < E && MI.getOperand(I).isReg() && MI.getOperand(I).isDef() &&
!MI.getOperand(I).isImplicit();
++I) {
if (I)
OS << ", ";
- print(MI.getOperand(I), TRI, /*IsDef=*/true);
+ print(MI.getOperand(I), TRI, I, ShouldPrintRegisterTies, /*IsDef=*/true);
}
if (I)
for (; I < E; ++I) {
if (NeedComma)
OS << ", ";
- print(MI.getOperand(I), TRI);
+ print(MI.getOperand(I), TRI, I, ShouldPrintRegisterTies);
NeedComma = true;
}
}
void MIPrinter::print(const MachineOperand &Op, const TargetRegisterInfo *TRI,
- bool IsDef) {
+ unsigned I, bool ShouldPrintRegisterTies, bool IsDef) {
printTargetFlags(Op);
switch (Op.getType()) {
case MachineOperand::MO_Register:
- // FIXME: Serialize the tied register.
if (Op.isImplicit())
OS << (Op.isDef() ? "implicit-def " : "implicit ");
else if (!IsDef && Op.isDef())
// Print the sub register.
if (Op.getSubReg() != 0)
OS << ':' << TRI->getSubRegIndexName(Op.getSubReg());
+ if (ShouldPrintRegisterTies && Op.isTied() && !Op.isDef())
+ OS << "(tied-def " << Op.getParent()->findTiedOperandIdx(I) << ")";
break;
case MachineOperand::MO_Immediate:
OS << Op.getImm();