Index: llvm/include/llvm/CodeGen/MachineMemOperand.h =================================================================== --- llvm/include/llvm/CodeGen/MachineMemOperand.h +++ llvm/include/llvm/CodeGen/MachineMemOperand.h @@ -40,6 +40,12 @@ /// This is the IR pointer value for the access, or it is null if unknown. PointerUnion V; + /// The provenance of the pointer. When UnknownProvenance, the provenance can + /// be any object. + /// FIXME: nullptr here means : use V as provenance. This will change in + /// future. + const Value *PtrProvenance = nullptr; + /// Offset - This is an offset from the base Value*. int64_t Offset; @@ -48,8 +54,9 @@ uint8_t StackID; explicit MachinePointerInfo(const Value *v, int64_t offset = 0, - uint8_t ID = 0) - : V(v), Offset(offset), StackID(ID) { + uint8_t ID = 0, + const Value *ptrProvenance = nullptr) + : V(v), PtrProvenance(ptrProvenance), Offset(offset), StackID(ID) { AddrSpace = v ? v->getType()->getPointerAddressSpace() : 0; } @@ -59,15 +66,15 @@ AddrSpace = v ? v->getAddressSpace() : 0; } - explicit MachinePointerInfo(unsigned AddressSpace = 0, int64_t offset = 0) - : V((const Value *)nullptr), Offset(offset), AddrSpace(AddressSpace), - StackID(0) {} + explicit MachinePointerInfo(unsigned AddressSpace = 0, int64_t offset = 0, + const Value *ptrProvenance = nullptr) + : V((const Value *)nullptr), PtrProvenance(ptrProvenance), Offset(offset), + AddrSpace(AddressSpace), StackID(0) {} explicit MachinePointerInfo( - PointerUnion v, - int64_t offset = 0, - uint8_t ID = 0) - : V(v), Offset(offset), StackID(ID) { + PointerUnion v, + int64_t offset = 0, uint8_t ID = 0, const Value *ptrProvenance = nullptr) + : V(v), PtrProvenance(ptrProvenance), Offset(offset), StackID(ID) { if (V) { if (const auto *ValPtr = V.dyn_cast()) AddrSpace = ValPtr->getType()->getPointerAddressSpace(); @@ -215,6 +222,8 @@ const void *getOpaqueValue() const { return PtrInfo.V.getOpaqueValue(); } + const Value *getPtrProvenance() const { return PtrInfo.PtrProvenance; } + /// Return the raw flags of the source value, \see Flags. Flags getFlags() const { return FlagVals; } Index: llvm/lib/CodeGen/MIRParser/MILexer.h =================================================================== --- llvm/lib/CodeGen/MIRParser/MILexer.h +++ llvm/lib/CodeGen/MIRParser/MILexer.h @@ -108,6 +108,7 @@ kw_align, kw_basealign, kw_addrspace, + kw_ptr_provenance, kw_stack, kw_got, kw_jump_table, Index: llvm/lib/CodeGen/MIRParser/MILexer.cpp =================================================================== --- llvm/lib/CodeGen/MIRParser/MILexer.cpp +++ llvm/lib/CodeGen/MIRParser/MILexer.cpp @@ -251,6 +251,7 @@ .Case("align", MIToken::kw_align) .Case("basealign", MIToken::kw_basealign) .Case("addrspace", MIToken::kw_addrspace) + .Case("ptr_provenance", MIToken::kw_ptr_provenance) .Case("stack", MIToken::kw_stack) .Case("got", MIToken::kw_got) .Case("jump-table", MIToken::kw_jump_table) Index: llvm/lib/CodeGen/MIRParser/MIParser.cpp =================================================================== --- llvm/lib/CodeGen/MIRParser/MIParser.cpp +++ llvm/lib/CodeGen/MIRParser/MIParser.cpp @@ -503,6 +503,7 @@ bool parseBBID(std::optional &BBID); bool parseOperandsOffset(MachineOperand &Op); bool parseIRValue(const Value *&V); + bool parseIRValueAsPointer(const Value *&V); bool parseMemoryOperandFlag(MachineMemOperand::Flags &Flags); bool parseMemoryPseudoSourceValue(const PseudoSourceValue *&PSV); bool parseMachinePointerInfo(MachinePointerInfo &Dest); @@ -3104,6 +3105,23 @@ }); } +bool MIParser::parseIRValueAsPointer(const Value *&V) { + if (Token.isNot(MIToken::NamedIRValue) && Token.isNot(MIToken::IRValue) && + Token.isNot(MIToken::GlobalValue) && + Token.isNot(MIToken::NamedGlobalValue) && + Token.isNot(MIToken::QuotedIRValue) && + Token.isNot(MIToken::kw_unknown_address)) { + return error("expected an IR value reference"); + } + V = nullptr; + if (parseIRValue(V)) + return true; + if (V && !V->getType()->isPointerTy()) + return error("expected a pointer IR value"); + lex(); + return false; +} + bool MIParser::getUint64(uint64_t &Result) { if (Token.hasIntegerValue()) { if (Token.integerValue().getActiveBits() > 64) @@ -3246,18 +3264,9 @@ Dest = MachinePointerInfo(PSV, Offset); return false; } - if (Token.isNot(MIToken::NamedIRValue) && Token.isNot(MIToken::IRValue) && - Token.isNot(MIToken::GlobalValue) && - Token.isNot(MIToken::NamedGlobalValue) && - Token.isNot(MIToken::QuotedIRValue) && - Token.isNot(MIToken::kw_unknown_address)) - return error("expected an IR value reference"); const Value *V = nullptr; - if (parseIRValue(V)) + if (parseIRValueAsPointer(V)) return true; - if (V && !V->getType()->isPointerTy()) - return error("expected a pointer IR value"); - lex(); int64_t Offset = 0; if (parseOffset(Offset)) return true; @@ -3373,6 +3382,7 @@ } MachinePointerInfo Ptr = MachinePointerInfo(); + const Value *PtrProvenancePtr = nullptr; if (Token.is(MIToken::Identifier)) { const char *Word = ((Flags & MachineMemOperand::MOLoad) && @@ -3416,6 +3426,15 @@ if (parseAddrspace(Ptr.AddrSpace)) return true; break; + case MIToken::kw_ptr_provenance: { + if (PtrProvenancePtr) + return error("ptr_provenance must occur at most once"); + lex(); + if (parseIRValueAsPointer(PtrProvenancePtr)) + return true; + Ptr.PtrProvenance = PtrProvenancePtr; + break; + } case MIToken::md_tbaa: lex(); if (parseMDNode(AAInfo.TBAA)) Index: llvm/lib/CodeGen/MachineOperand.cpp =================================================================== --- llvm/lib/CodeGen/MachineOperand.cpp +++ llvm/lib/CodeGen/MachineOperand.cpp @@ -1237,6 +1237,10 @@ << "unknown-address"; } MachineOperand::printOperandOffset(OS, getOffset()); + if (getPtrProvenance()) { + OS << ", ptr_provenance "; + MIRFormatter::printIRValue(OS, *getPtrProvenance(), MST); + } if (getSize() > 0 && getAlign() != getSize()) OS << ", align " << getAlign().value(); if (getAlign() != getBaseAlign()) Index: llvm/test/CodeGen/X86/ptr_provenance_memoperand.ll =================================================================== --- /dev/null +++ llvm/test/CodeGen/X86/ptr_provenance_memoperand.ll @@ -0,0 +1,47 @@ +; NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py +; RUN: llc < %s -mtriple=x86_64-unknown-unknown -stop-after=finalize-isel 2>&1 | FileCheck %s + +; NOTE: change 'RUN' to 'R U N' in following lines before regenerating the results; afterwards, put it back. +; RUN: llc < %s -mtriple=x86_64-unknown-unknown -stop-before=finalize-isel -o %t.mir +; RUN: llc %t.mir -mtriple=x86_64-unknown-unknown -run-pass=finalize-isel -o - 2>&1 | FileCheck %s + +; This test validates that the ptr_provenance is added to the MachineMemOperand. +; It also validates that the MIR parser can read it back in. + +; Function Attrs: nounwind +define i32 @test01(ptr %pa, ptr %pb) #0 { + ; CHECK-LABEL: name: test01 + ; CHECK: bb.0 (%ir-block.0): + ; CHECK-NEXT: liveins: $rdi, $rsi + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: [[COPY:%[0-9]+]]:gr64 = COPY $rsi + ; CHECK-NEXT: [[COPY1:%[0-9]+]]:gr64 = COPY $rdi + ; CHECK-NEXT: MOV32mi [[COPY]], 1, $noreg, 0, $noreg, 43 :: (store (s32) into %ir.pb, ptr_provenance `ptr unknown_provenance`) + ; CHECK-NEXT: MOV32mi [[COPY1]], 1, $noreg, 0, $noreg, 42 :: (store (s32) into %ir.pa, ptr_provenance %ir.pb) + ; CHECK-NEXT: [[MOV32rm:%[0-9]+]]:gr32 = MOV32rm [[COPY]], 1, $noreg, 0, $noreg :: (load (s32) from %ir.pb, ptr_provenance %ir.pa) + ; CHECK-NEXT: $eax = COPY [[MOV32rm]] + ; CHECK-NEXT: RET 0, $eax + store i32 43, ptr %pb, ptr_provenance ptr unknown_provenance + store i32 42, ptr %pa, ptr_provenance ptr %pb + %retval = load i32, ptr %pb, ptr_provenance ptr %pa + ret i32 %retval +} + +; Function Attrs: nounwind +define i32 @test02(ptr %pa, ptr %pb) #0 { + ; CHECK-LABEL: name: test02 + ; CHECK: bb.0 (%ir-block.0): + ; CHECK-NEXT: liveins: $rdi, $rsi + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: [[COPY:%[0-9]+]]:gr64 = COPY $rsi + ; CHECK-NEXT: [[COPY1:%[0-9]+]]:gr64 = COPY $rdi + ; CHECK-NEXT: MOV32mi [[COPY1]], 1, $noreg, 0, $noreg, 43 :: (store (s32) into %ir.pa) + ; CHECK-NEXT: [[MOV32rm:%[0-9]+]]:gr32 = MOV32rm [[COPY]], 1, $noreg, 0, $noreg :: (load (s32) from %ir.pb) + ; CHECK-NEXT: $eax = COPY [[MOV32rm]] + ; CHECK-NEXT: RET 0, $eax + store i32 43, ptr %pa + %retval = load i32, ptr %pb + ret i32 %retval +} + +attributes #0 = { nounwind }