Skip to content

Commit

Permalink
MIR Serialization: Serialize instruction's register ties.
Browse files Browse the repository at this point in the history
This commit serializes the machine instruction's register operand ties.
The ties are printed out only when the instructon has register ties that are
different from the ties that are specified in the instruction's description.


git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@245482 91177308-0d34-0410-b5e6-96231b3b80d8
  • Loading branch information
hyp committed Aug 19, 2015
1 parent b326c12 commit dab6ae0
Show file tree
Hide file tree
Showing 10 changed files with 269 additions and 19 deletions.
1 change: 1 addition & 0 deletions lib/CodeGen/MIRParser/MILexer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,7 @@ static MIToken::TokenKind getIdentifierKind(StringRef Identifier) {
.Case("internal", MIToken::kw_internal)
.Case("early-clobber", MIToken::kw_early_clobber)
.Case("debug-use", MIToken::kw_debug_use)
.Case("tied-def", MIToken::kw_tied_def)
.Case("frame-setup", MIToken::kw_frame_setup)
.Case("debug-location", MIToken::kw_debug_location)
.Case(".cfi_same_value", MIToken::kw_cfi_same_value)
Expand Down
1 change: 1 addition & 0 deletions lib/CodeGen/MIRParser/MILexer.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ struct MIToken {
kw_internal,
kw_early_clobber,
kw_debug_use,
kw_tied_def,
kw_frame_setup,
kw_debug_location,
kw_cfi_same_value,
Expand Down
107 changes: 93 additions & 14 deletions lib/CodeGen/MIRParser/MIParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,10 +43,16 @@ struct MachineOperandWithLocation {
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 {
Expand Down Expand Up @@ -111,7 +117,9 @@ 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);
Expand All @@ -136,8 +144,10 @@ class MIParser {
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);
Expand Down Expand Up @@ -174,6 +184,9 @@ class MIParser {

bool parseInstruction(unsigned &OpCode, unsigned &Flags);

bool assignRegisterTies(MachineInstr &MI,
ArrayRef<MachineOperandWithLocation> Operands);

bool verifyImplicitOperands(ArrayRef<MachineOperandWithLocation> Operands,
const MCInstrDesc &MCID);

Expand Down Expand Up @@ -552,9 +565,11 @@ bool MIParser::parse(MachineInstr *&MI) {
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();
Expand All @@ -570,9 +585,11 @@ bool MIParser::parse(MachineInstr *&MI) {
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;
Expand Down Expand Up @@ -621,6 +638,8 @@ bool MIParser::parse(MachineInstr *&MI) {
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 =
Expand Down Expand Up @@ -861,7 +880,59 @@ bool MIParser::parseSubRegisterIndex(unsigned &SubReg) {
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()) {
Expand All @@ -878,6 +949,12 @@ bool MIParser::parseRegisterOperand(MachineOperand &Dest, bool IsDef) {
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,
Expand Down Expand Up @@ -1296,7 +1373,8 @@ bool MIParser::parseLiveoutRegisterMaskOperand(MachineOperand &Dest) {
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:
Expand All @@ -1310,7 +1388,7 @@ bool MIParser::parseMachineOperand(MachineOperand &Dest) {
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:
Expand Down Expand Up @@ -1367,7 +1445,8 @@ bool MIParser::parseMachineOperand(MachineOperand &Dest) {
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)) {
Expand Down Expand Up @@ -1399,7 +1478,7 @@ bool MIParser::parseMachineOperandAndTargetFlags(MachineOperand &Dest) {
return true;
}
auto Loc = Token.location();
if (parseMachineOperand(Dest))
if (parseMachineOperand(Dest, TiedDefIdx))
return true;
if (!HasTargetFlags)
return false;
Expand Down
29 changes: 24 additions & 5 deletions lib/CodeGen/MIRPrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ class MIPrinter {
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);
Expand Down Expand Up @@ -502,6 +502,23 @@ void MIPrinter::print(const MachineBasicBlock &MBB) {
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();
Expand All @@ -511,13 +528,14 @@ void MIPrinter::print(const MachineInstr &MI) {
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)
Expand All @@ -532,7 +550,7 @@ void MIPrinter::print(const MachineInstr &MI) {
for (; I < E; ++I) {
if (NeedComma)
OS << ", ";
print(MI.getOperand(I), TRI);
print(MI.getOperand(I), TRI, I, ShouldPrintRegisterTies);
NeedComma = true;
}

Expand Down Expand Up @@ -690,11 +708,10 @@ static const char *getTargetIndexName(const MachineFunction &MF, int Index) {
}

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())
Expand All @@ -716,6 +733,8 @@ void MIPrinter::print(const MachineOperand &Op, const TargetRegisterInfo *TRI,
// 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();
Expand Down
25 changes: 25 additions & 0 deletions test/CodeGen/MIR/X86/def-register-already-tied-error.mir
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# RUN: not llc -march=x86-64 -start-after branch-folder -stop-after branch-folder -o /dev/null %s 2>&1 | FileCheck %s
--- |
define i64 @test(i64 %x) #0 {
entry:
%asm = tail call i64 asm sideeffect "$foo", "=r,0"(i64 %x) nounwind
ret i64 %asm
}

attributes #0 = { nounwind }
...
---
name: test
hasInlineAsm: true
tracksRegLiveness: true
liveins:
- { reg: '%rdi' }
body: |
bb.0.entry:
liveins: %rdi
; CHECK: [[@LINE+1]]:83: the tied-def operand #3 is already tied with another register operand
INLINEASM $"$foo", 1, 2818058, def %rdi, 2147483657, killed %rdi(tied-def 3), killed %rdi(tied-def 3)
%rax = COPY killed %rdi
RETQ killed %rax
...
25 changes: 25 additions & 0 deletions test/CodeGen/MIR/X86/expected-integer-after-tied-def.mir
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# RUN: not llc -march=x86-64 -start-after branch-folder -stop-after branch-folder -o /dev/null %s 2>&1 | FileCheck %s
--- |
define i64 @test(i64 %x) #0 {
entry:
%asm = tail call i64 asm sideeffect "$foo", "=r,0"(i64 %x) nounwind
ret i64 %asm
}

attributes #0 = { nounwind }
...
---
name: test
hasInlineAsm: true
tracksRegLiveness: true
liveins:
- { reg: '%rdi' }
body: |
bb.0.entry:
liveins: %rdi
; CHECK: [[@LINE+1]]:78: expected an integer literal after 'tied-def'
INLINEASM $"$foo", 1, 2818058, def %rdi, 2147483657, killed %rdi(tied-def)
%rax = COPY killed %rdi
RETQ killed %rax
...
25 changes: 25 additions & 0 deletions test/CodeGen/MIR/X86/expected-tied-def-after-lparen.mir
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# RUN: not llc -march=x86-64 -start-after branch-folder -stop-after branch-folder -o /dev/null %s 2>&1 | FileCheck %s
--- |
define i64 @test(i64 %x) #0 {
entry:
%asm = tail call i64 asm sideeffect "$foo", "=r,0"(i64 %x) nounwind
ret i64 %asm
}

attributes #0 = { nounwind }
...
---
name: test
hasInlineAsm: true
tracksRegLiveness: true
liveins:
- { reg: '%rdi' }
body: |
bb.0.entry:
liveins: %rdi
; CHECK: [[@LINE+1]]:70: expected 'tied-def' after '('
INLINEASM $"$foo", 1, 2818058, def %rdi, 2147483657, killed %rdi(3)
%rax = COPY killed %rdi
RETQ killed %rax
...
Loading

0 comments on commit dab6ae0

Please sign in to comment.