Index: include/llvm/Target/TargetLowering.h =================================================================== --- include/llvm/Target/TargetLowering.h +++ include/llvm/Target/TargetLowering.h @@ -3067,6 +3067,13 @@ return Chain; } + /// This callback is used to inspect load/store instructions and add + /// target-specific MachineMemOperand flags to them. The default + /// implementation does nothing. + virtual MachineMemOperand::Flags getMMOFlags(const Instruction &I) const { + return MachineMemOperand::MONone; + } + /// This callback is invoked by the type legalizer to legalize nodes with an /// illegal operand type but legal result types. It replaces the /// LowerOperation callback in the type Legalizer. The reason we can not do Index: lib/CodeGen/MIRParser/MILexer.h =================================================================== --- lib/CodeGen/MIRParser/MILexer.h +++ lib/CodeGen/MIRParser/MILexer.h @@ -81,6 +81,9 @@ kw_volatile, kw_non_temporal, kw_invariant, + kw_flag1, + kw_flag2, + kw_flag3, kw_align, kw_stack, kw_got, @@ -168,7 +171,8 @@ bool isMemoryOperandFlag() const { return Kind == kw_volatile || Kind == kw_non_temporal || - Kind == kw_dereferenceable || Kind == kw_invariant; + Kind == kw_dereferenceable || Kind == kw_invariant || + Kind == kw_flag1 || Kind == kw_flag2 || Kind == kw_flag3; } bool is(TokenKind K) const { return Kind == K; } Index: lib/CodeGen/MIRParser/MILexer.cpp =================================================================== --- lib/CodeGen/MIRParser/MILexer.cpp +++ lib/CodeGen/MIRParser/MILexer.cpp @@ -224,6 +224,9 @@ .Case("non-temporal", MIToken::kw_non_temporal) .Case("dereferenceable", MIToken::kw_dereferenceable) .Case("invariant", MIToken::kw_invariant) + .Case("flag1", MIToken::kw_flag1) + .Case("flag2", MIToken::kw_flag2) + .Case("flag3", MIToken::kw_flag3) .Case("align", MIToken::kw_align) .Case("stack", MIToken::kw_stack) .Case("got", MIToken::kw_got) Index: lib/CodeGen/MIRParser/MIParser.cpp =================================================================== --- lib/CodeGen/MIRParser/MIParser.cpp +++ lib/CodeGen/MIRParser/MIParser.cpp @@ -2034,7 +2034,15 @@ case MIToken::kw_invariant: Flags |= MachineMemOperand::MOInvariant; break; - // TODO: parse the target specific memory operand flags. + case MIToken::kw_flag1: + Flags |= MachineMemOperand::MOTargetFlag1; + break; + case MIToken::kw_flag2: + Flags |= MachineMemOperand::MOTargetFlag2; + break; + case MIToken::kw_flag3: + Flags |= MachineMemOperand::MOTargetFlag3; + break; default: llvm_unreachable("The current token should be a memory operand flag"); } Index: lib/CodeGen/MIRPrinter.cpp =================================================================== --- lib/CodeGen/MIRPrinter.cpp +++ lib/CodeGen/MIRPrinter.cpp @@ -1033,7 +1033,6 @@ void MIPrinter::print(const MachineMemOperand &Op) { OS << '('; - // TODO: Print operand's target specific flags. if (Op.isVolatile()) OS << "volatile "; if (Op.isNonTemporal()) @@ -1042,6 +1041,13 @@ OS << "dereferenceable "; if (Op.isInvariant()) OS << "invariant "; + if (Op.getFlags() & MachineMemOperand::MOTargetFlag1) + OS << "flag1 "; + if (Op.getFlags() & MachineMemOperand::MOTargetFlag2) + OS << "flag2 "; + if (Op.getFlags() & MachineMemOperand::MOTargetFlag3) + OS << "flag3 "; + if (Op.isLoad()) OS << "load "; else { Index: lib/CodeGen/MachineInstr.cpp =================================================================== --- lib/CodeGen/MachineInstr.cpp +++ lib/CodeGen/MachineInstr.cpp @@ -744,6 +744,12 @@ OS << "(dereferenceable)"; if (isInvariant()) OS << "(invariant)"; + if (getFlags() & MOTargetFlag1) + OS << "(flag1)"; + if (getFlags() & MOTargetFlag2) + OS << "(flag2)"; + if (getFlags() & MOTargetFlag3) + OS << "(flag3)"; } //===----------------------------------------------------------------------===// Index: lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp =================================================================== --- lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp +++ lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp @@ -3559,6 +3559,7 @@ MMOFlags |= MachineMemOperand::MOInvariant; if (isDereferenceable) MMOFlags |= MachineMemOperand::MODereferenceable; + MMOFlags |= TLI.getMMOFlags(I); SDValue L = DAG.getLoad(ValueVTs[i], dl, Root, A, MachinePointerInfo(SV, Offsets[i]), Alignment, @@ -3688,6 +3689,7 @@ MMOFlags |= MachineMemOperand::MOVolatile; if (I.getMetadata(LLVMContext::MD_nontemporal) != nullptr) MMOFlags |= MachineMemOperand::MONonTemporal; + MMOFlags |= TLI.getMMOFlags(I); // An aggregate load cannot wrap around the address space, so offsets to its // parts don't wrap either. Index: test/CodeGen/MIR/AArch64/target-memoperands.mir =================================================================== --- /dev/null +++ test/CodeGen/MIR/AArch64/target-memoperands.mir @@ -0,0 +1,30 @@ +# 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) :: (flag1 load 8) +# CHECK: %2(s32) = G_LOAD %0(p0) :: (flag2 load 4) +# CHECK: %3(s16) = G_LOAD %0(p0) :: (flag3 load 2) +# CHECK: G_STORE %3(s16), %0(p0) :: (flag1 store 2) +# CHECK: G_STORE %2(s32), %0(p0) :: (flag2 store 4) +# CHECK: G_STORE %1(s64), %0(p0) :: (flag3 store 8) +name: target_memoperands +body: | + bb.0: + + %0:_(p0) = COPY %x0 + %1:_(s64) = G_LOAD %0(p0) :: (flag1 load 8) + %2:_(s32) = G_LOAD %0(p0) :: (flag2 load 4) + %3:_(s16) = G_LOAD %0(p0) :: (flag3 load 2) + G_STORE %3(s16), %0(p0) :: (flag1 store 2) + G_STORE %2(s32), %0(p0) :: (flag2 store 4) + G_STORE %1(s64), %0(p0) :: (flag3 store 8) + RET_ReallyLR +...