[MIR] Add support for printing and parsing target MMO flags

Summary: Add target hooks for printing and parsing target MMO flags.
Targets may override getSerializableMachineMemOperandTargetFlags() to
return a mapping from string to flag value for target MMO values that
should be serialized/parsed in MIR output.

Add implementation of this hook for AArch64 SuppressPair MMO flag.

Reviewers: bogner, hfinkel, qcolombet, MatzeB

Subscribers: mcrosier, javed.absar, llvm-commits

Differential Revision: https://reviews.llvm.org/D34962

llvm-svn: 307877
This commit is contained in:
Geoff Berry 2017-07-13 02:28:54 +00:00
parent 02d34adfd8
commit 6748abe24d
10 changed files with 135 additions and 6 deletions

View File

@ -114,6 +114,9 @@ public:
MOInvariant = 1u << 5,
// Reserved for use by target-specific passes.
// Targets may override getSerializableMachineMemOperandTargetFlags() to
// enable MIR serialization/parsing of these flags. If more of these flags
// are added, the MIR printing/parsing code will need to be updated as well.
MOTargetFlag1 = 1u << 6,
MOTargetFlag2 = 1u << 7,
MOTargetFlag3 = 1u << 8,

View File

@ -1545,6 +1545,16 @@ public:
return None;
}
/// Return an array that contains the MMO target flag values and their
/// names.
///
/// MIR Serialization is able to serialize only the MMO target flags that are
/// defined by this method.
virtual ArrayRef<std::pair<MachineMemOperand::Flags, const char *>>
getSerializableMachineMemOperandTargetFlags() const {
return None;
}
/// Determines whether \p Inst is a tail call instruction. Override this
/// method on targets that do not properly set MCID::Return and MCID::Call on
/// tail call instructions."

View File

@ -169,7 +169,8 @@ public:
bool isMemoryOperandFlag() const {
return Kind == kw_volatile || Kind == kw_non_temporal ||
Kind == kw_dereferenceable || Kind == kw_invariant;
Kind == kw_dereferenceable || Kind == kw_invariant ||
Kind == StringConstant;
}
bool is(TokenKind K) const { return Kind == K; }

View File

@ -141,6 +141,8 @@ class MIParser {
StringMap<unsigned> Names2DirectTargetFlags;
/// Maps from direct target flag names to the bitmask target flag values.
StringMap<unsigned> Names2BitmaskTargetFlags;
/// Maps from MMO target flag names to MMO target flag values.
StringMap<MachineMemOperand::Flags> Names2MMOTargetFlags;
public:
MIParser(PerFunctionMIParsingState &PFS, SMDiagnostic &Error,
@ -320,6 +322,14 @@ private:
/// Return true if the name isn't a name of a bitmask target flag.
bool getBitmaskTargetFlag(StringRef Name, unsigned &Flag);
void initNames2MMOTargetFlags();
/// Try to convert a name of a MachineMemOperand target flag to the
/// corresponding target flag.
///
/// Return true if the name isn't a name of a target MMO flag.
bool getMMOTargetFlag(StringRef Name, MachineMemOperand::Flags &Flag);
/// parseStringConstant
/// ::= StringConstant
bool parseStringConstant(std::string &Result);
@ -2039,7 +2049,14 @@ bool MIParser::parseMemoryOperandFlag(MachineMemOperand::Flags &Flags) {
case MIToken::kw_invariant:
Flags |= MachineMemOperand::MOInvariant;
break;
// TODO: parse the target specific memory operand flags.
case MIToken::StringConstant: {
MachineMemOperand::Flags TF;
if (getMMOTargetFlag(Token.stringValue(), TF))
return error("use of undefined target MMO flag '" + Token.stringValue() +
"'");
Flags |= TF;
break;
}
default:
llvm_unreachable("The current token should be a memory operand flag");
}
@ -2480,6 +2497,27 @@ bool MIParser::getBitmaskTargetFlag(StringRef Name, unsigned &Flag) {
return false;
}
void MIParser::initNames2MMOTargetFlags() {
if (!Names2MMOTargetFlags.empty())
return;
const auto *TII = MF.getSubtarget().getInstrInfo();
assert(TII && "Expected target instruction info");
auto Flags = TII->getSerializableMachineMemOperandTargetFlags();
for (const auto &I : Flags)
Names2MMOTargetFlags.insert(
std::make_pair(StringRef(I.second), I.first));
}
bool MIParser::getMMOTargetFlag(StringRef Name,
MachineMemOperand::Flags &Flag) {
initNames2MMOTargetFlags();
auto FlagInfo = Names2MMOTargetFlags.find(Name);
if (FlagInfo == Names2MMOTargetFlags.end())
return true;
Flag = FlagInfo->second;
return false;
}
bool MIParser::parseStringConstant(std::string &Result) {
if (Token.isNot(MIToken::StringConstant))
return error("expected string constant");

View File

@ -165,7 +165,8 @@ public:
void print(const MachineOperand &Op, const TargetRegisterInfo *TRI,
unsigned I, bool ShouldPrintRegisterTies,
LLT TypeToPrint, bool IsDef = false);
void print(const LLVMContext &Context, const MachineMemOperand &Op);
void print(const LLVMContext &Context, const TargetInstrInfo &TII,
const MachineMemOperand &Op);
void printSyncScope(const LLVMContext &Context, SyncScope::ID SSID);
void print(const MCCFIInstruction &CFI, const TargetRegisterInfo *TRI);
@ -740,7 +741,7 @@ void MIPrinter::print(const MachineInstr &MI) {
for (const auto *Op : MI.memoperands()) {
if (NeedComma)
OS << ", ";
print(Context, *Op);
print(Context, *TII, *Op);
NeedComma = true;
}
}
@ -1036,9 +1037,20 @@ void MIPrinter::print(const MachineOperand &Op, const TargetRegisterInfo *TRI,
}
}
void MIPrinter::print(const LLVMContext &Context, const MachineMemOperand &Op) {
static const char *getTargetMMOFlagName(const TargetInstrInfo &TII,
unsigned TMMOFlag) {
auto Flags = TII.getSerializableMachineMemOperandTargetFlags();
for (const auto &I : Flags) {
if (I.first == TMMOFlag) {
return I.second;
}
}
return nullptr;
}
void MIPrinter::print(const LLVMContext &Context, const TargetInstrInfo &TII,
const MachineMemOperand &Op) {
OS << '(';
// TODO: Print operand's target specific flags.
if (Op.isVolatile())
OS << "volatile ";
if (Op.isNonTemporal())
@ -1047,6 +1059,15 @@ void MIPrinter::print(const LLVMContext &Context, const MachineMemOperand &Op) {
OS << "dereferenceable ";
if (Op.isInvariant())
OS << "invariant ";
if (Op.getFlags() & MachineMemOperand::MOTargetFlag1)
OS << '"' << getTargetMMOFlagName(TII, MachineMemOperand::MOTargetFlag1)
<< "\" ";
if (Op.getFlags() & MachineMemOperand::MOTargetFlag2)
OS << '"' << getTargetMMOFlagName(TII, MachineMemOperand::MOTargetFlag2)
<< "\" ";
if (Op.getFlags() & MachineMemOperand::MOTargetFlag3)
OS << '"' << getTargetMMOFlagName(TII, MachineMemOperand::MOTargetFlag3)
<< "\" ";
if (Op.isLoad())
OS << "load ";
else {

View File

@ -752,6 +752,12 @@ void MachineMemOperand::print(raw_ostream &OS, ModuleSlotTracker &MST) const {
OS << "(dereferenceable)";
if (isInvariant())
OS << "(invariant)";
if (getFlags() & MOTargetFlag1)
OS << "(flag1)";
if (getFlags() & MOTargetFlag2)
OS << "(flag2)";
if (getFlags() & MOTargetFlag3)
OS << "(flag3)";
}
//===----------------------------------------------------------------------===//

View File

@ -4430,6 +4430,13 @@ AArch64InstrInfo::getSerializableBitmaskMachineOperandTargetFlags() const {
return makeArrayRef(TargetFlags);
}
ArrayRef<std::pair<MachineMemOperand::Flags, const char *>>
AArch64InstrInfo::getSerializableMachineMemOperandTargetFlags() const {
static const std::pair<MachineMemOperand::Flags, const char *> TargetFlags[] =
{{MOSuppressPair, "aarch64-suppress-pair"}};
return makeArrayRef(TargetFlags);
}
unsigned AArch64InstrInfo::getOutliningBenefit(size_t SequenceSize,
size_t Occurrences,
bool CanBeTailCall) const {

View File

@ -289,6 +289,8 @@ public:
getSerializableDirectMachineOperandTargetFlags() const override;
ArrayRef<std::pair<unsigned, const char *>>
getSerializableBitmaskMachineOperandTargetFlags() const override;
ArrayRef<std::pair<MachineMemOperand::Flags, const char *>>
getSerializableMachineMemOperandTargetFlags() const override;
bool isFunctionSafeToOutlineFrom(MachineFunction &MF) const override;
unsigned getOutliningBenefit(size_t SequenceSize, size_t Occurrences,

View File

@ -0,0 +1,19 @@
# RUN: not llc -mtriple=aarch64-none-linux-gnu -run-pass none -o /dev/null %s 2>&1 | FileCheck %s
--- |
define void @target_memoperands_error() {
ret void
}
...
---
name: target_memoperands_error
body: |
bb.0:
%0:_(p0) = COPY %x0
; CHECK: [[@LINE+1]]:35: use of undefined target MMO flag 'aarch64-invalid'
%1:_(s64) = G_LOAD %0(p0) :: ("aarch64-invalid" load 8)
RET_ReallyLR
...

View File

@ -0,0 +1,22 @@
# RUN: llc -mtriple=aarch64-none-linux-gnu -run-pass none -o - %s | FileCheck %s
--- |
define void @target_memoperands() {
ret void
}
...
---
# CHECK-LABEL: name: target_memoperands
# CHECK: %1(s64) = G_LOAD %0(p0) :: ("aarch64-suppress-pair" load 8)
# CHECK: G_STORE %1(s64), %0(p0) :: ("aarch64-suppress-pair" store 8)
name: target_memoperands
body: |
bb.0:
%0:_(p0) = COPY %x0
%1:_(s64) = G_LOAD %0(p0) :: ("aarch64-suppress-pair" load 8)
G_STORE %1(s64), %0(p0) :: ("aarch64-suppress-pair" store 8)
RET_ReallyLR
...