Index: llvm/include/llvm/AsmParser/LLParser.h =================================================================== --- llvm/include/llvm/AsmParser/LLParser.h +++ llvm/include/llvm/AsmParser/LLParser.h @@ -301,6 +301,9 @@ bool parseOrdering(AtomicOrdering &Ordering); bool parseOptionalStackAlignment(unsigned &Alignment); bool parseOptionalCommaAlign(MaybeAlign &Alignment, bool &AteExtraComma); + bool parseOptionalCommaPtrProvenance(Value *&V, LocTy &Loc, + PerFunctionState &PFS, + bool &AteExtraComma); bool parseOptionalCommaAddrSpace(unsigned &AddrSpace, LocTy &Loc, bool &AteExtraComma); bool parseAllocSizeArguments(unsigned &BaseSizeArg, Index: llvm/include/llvm/AsmParser/LLToken.h =================================================================== --- llvm/include/llvm/AsmParser/LLToken.h +++ llvm/include/llvm/AsmParser/LLToken.h @@ -90,6 +90,7 @@ kw_unwind, kw_datalayout, kw_volatile, + kw_ptr_provenance, kw_unknown_provenance, kw_atomic, kw_unordered, Index: llvm/lib/AsmParser/LLLexer.cpp =================================================================== --- llvm/lib/AsmParser/LLLexer.cpp +++ llvm/lib/AsmParser/LLLexer.cpp @@ -545,6 +545,7 @@ KEYWORD(unwind); KEYWORD(datalayout); KEYWORD(volatile); + KEYWORD(ptr_provenance); KEYWORD(unknown_provenance); KEYWORD(atomic); KEYWORD(unordered); Index: llvm/lib/AsmParser/LLParser.cpp =================================================================== --- llvm/lib/AsmParser/LLParser.cpp +++ llvm/lib/AsmParser/LLParser.cpp @@ -2348,16 +2348,20 @@ /// end. bool LLParser::parseOptionalCommaAlign(MaybeAlign &Alignment, bool &AteExtraComma) { - AteExtraComma = false; - while (EatIfPresent(lltok::comma)) { + while (AteExtraComma || EatIfPresent(lltok::comma)) { + AteExtraComma = false; // Metadata at the end is an early exit. if (Lex.getKind() == lltok::MetadataVar) { AteExtraComma = true; return false; } - if (Lex.getKind() != lltok::kw_align) + // if we get here, ptr_provenance must not be possible any more + if (Lex.getKind() == lltok::kw_ptr_provenance) return error(Lex.getLoc(), "expected metadata or 'align'"); + if (Lex.getKind() != lltok::kw_align) + return error(Lex.getLoc(), + "expected metadata or 'align' or 'ptr_provenance'"); if (parseOptionalAlignment(Alignment)) return true; @@ -2366,6 +2370,27 @@ return false; } +/// parseOptionalCommandPtrProvenance +/// ::= +/// ::= ',' ptr_provenance int* %3 +/// +/// This returns with AteExtraComma set to true if it ate an excess comma at the +/// end. +bool LLParser::parseOptionalCommaPtrProvenance(Value *&V, LLParser::LocTy &Loc, + LLParser::PerFunctionState &PFS, + bool &AteExtraComma) { + assert(AteExtraComma == false); + if (EatIfPresent(lltok::comma)) { + if (Lex.getKind() == lltok::kw_ptr_provenance) { + Lex.Lex(); + return parseTypeAndValue(V, Loc, PFS); + } + + AteExtraComma = true; + } + return false; +} + /// parseOptionalCommaAddrSpace /// ::= /// ::= ',' addrspace(1) @@ -7557,6 +7582,8 @@ /// 'singlethread'? AtomicOrdering (',' 'align' i32)? int LLParser::parseLoad(Instruction *&Inst, PerFunctionState &PFS) { Value *Val; LocTy Loc; + Value *PtrProvenance = nullptr; + LocTy PtrProvenanceLoc; MaybeAlign Alignment; bool AteExtraComma = false; bool isAtomic = false; @@ -7580,6 +7607,8 @@ parseToken(lltok::comma, "expected comma after load's type") || parseTypeAndValue(Val, Loc, PFS) || parseScopeAndOrdering(isAtomic, SSID, Ordering) || + parseOptionalCommaPtrProvenance(PtrProvenance, PtrProvenanceLoc, PFS, + AteExtraComma) || parseOptionalCommaAlign(Alignment, AteExtraComma)) return true; @@ -7603,7 +7632,10 @@ return error(ExplicitTypeLoc, "loading unsized types is not allowed"); if (!Alignment) Alignment = M->getDataLayout().getABITypeAlign(Ty); - Inst = new LoadInst(Ty, Val, "", isVolatile, *Alignment, Ordering, SSID); + auto *LI = new LoadInst(Ty, Val, "", isVolatile, *Alignment, Ordering, SSID); + if (PtrProvenance) + LI->setPtrProvenanceOperand(PtrProvenance); + Inst = LI; return AteExtraComma ? InstExtraComma : InstNormal; } @@ -7614,6 +7646,8 @@ /// 'singlethread'? AtomicOrdering (',' 'align' i32)? int LLParser::parseStore(Instruction *&Inst, PerFunctionState &PFS) { Value *Val, *Ptr; LocTy Loc, PtrLoc; + Value *PtrProvenance = nullptr; + LocTy PtrProvenanceLoc; MaybeAlign Alignment; bool AteExtraComma = false; bool isAtomic = false; @@ -7635,6 +7669,8 @@ parseToken(lltok::comma, "expected ',' after store operand") || parseTypeAndValue(Ptr, PtrLoc, PFS) || parseScopeAndOrdering(isAtomic, SSID, Ordering) || + parseOptionalCommaPtrProvenance(PtrProvenance, PtrProvenanceLoc, PFS, + AteExtraComma) || parseOptionalCommaAlign(Alignment, AteExtraComma)) return true; @@ -7656,7 +7692,11 @@ if (!Alignment) Alignment = M->getDataLayout().getABITypeAlign(Val->getType()); - Inst = new StoreInst(Val, Ptr, isVolatile, *Alignment, Ordering, SSID); + auto *SI = new StoreInst(Val, Ptr, isVolatile, *Alignment, Ordering, SSID); + if (PtrProvenance) + SI->setPtrProvenanceOperand(PtrProvenance); + Inst = SI; + return AteExtraComma ? InstExtraComma : InstNormal; } Index: llvm/test/Bitcode/loadstore_ptr_provenance.ll =================================================================== --- /dev/null +++ llvm/test/Bitcode/loadstore_ptr_provenance.ll @@ -0,0 +1,52 @@ +; RUN: opt -passes=verify -S < %s | FileCheck %s +; Activate when bitcode support is added: +; R U N: llvm-as < %s | llvm-dis | llvm-as | llvm-dis | FileCheck %s +; R U N: verify-uselistorder < %s + +define i32 @f(ptr %p, ptr %q, ptr %word, ptr %base) { + ; CHECK: define i32 @f(ptr %p, ptr %q, ptr %word, ptr %base) { + store i32 42, ptr %p, ptr_provenance ptr %p + ; CHECK-NEXT: store i32 42, ptr %p, ptr_provenance ptr %p + store i32 43, ptr %q, ptr_provenance ptr %q + ; CHECK-NEXT: store i32 43, ptr %q, ptr_provenance ptr %q + %r = load i32, ptr %p, ptr_provenance ptr %p + ; CHECK-NEXT: %r = load i32, ptr %p, ptr_provenance ptr %p + + store i32 42, ptr %p, ptr_provenance ptr unknown_provenance + ; CHECK-NEXT: store i32 42, ptr %p, ptr_provenance ptr unknown_provenance + store i32 43, ptr %q, ptr_provenance ptr unknown_provenance + ; CHECK-NEXT: store i32 43, ptr %q, ptr_provenance ptr unknown_provenance + %r2 = load i32, ptr %p, ptr_provenance ptr unknown_provenance + ; CHECK-NEXT: %r2 = load i32, ptr %p, ptr_provenance ptr unknown_provenance + + %ld.1p = load atomic i32, ptr %word monotonic, ptr_provenance ptr %word, align 4 + ; CHECK: %ld.1p = load atomic i32, ptr %word monotonic, ptr_provenance ptr %word, align 4 + %ld.2p = load atomic volatile i32, ptr %word acquire, ptr_provenance ptr %word, align 8 + ; CHECK: %ld.2p = load atomic volatile i32, ptr %word acquire, ptr_provenance ptr %word, align 8 + %ld.3p = load atomic volatile i32, ptr %word syncscope("singlethread") seq_cst, ptr_provenance ptr %word, align 16 + ; CHECK: %ld.3p = load atomic volatile i32, ptr %word syncscope("singlethread") seq_cst, ptr_provenance ptr %word, align 16 + + store atomic i32 23, ptr %word monotonic, align 4 + ; CHECK: store atomic i32 23, ptr %word monotonic, align 4 + store atomic volatile i32 24, ptr %word monotonic, align 4 + ; CHECK: store atomic volatile i32 24, ptr %word monotonic, align 4 + store atomic volatile i32 25, ptr %word syncscope("singlethread") monotonic, align 4 + ; CHECK: store atomic volatile i32 25, ptr %word syncscope("singlethread") monotonic, align 4 + + load ptr, ptr %base, ptr_provenance ptr %base, align 8, !invariant.load !0, !nontemporal !1, !nonnull !1, !dereferenceable !2, !dereferenceable_or_null !2 + ; CHECK: load ptr, ptr %base, ptr_provenance ptr %base, align 8, !invariant.load !0, !nontemporal !1, !nonnull !1, !dereferenceable !2, !dereferenceable_or_null !2 + load volatile ptr, ptr %base, ptr_provenance ptr %base, align 8, !invariant.load !0, !nontemporal !1, !nonnull !1, !dereferenceable !2, !dereferenceable_or_null !2 + ; CHECK: load volatile ptr, ptr %base, ptr_provenance ptr %base, align 8, !invariant.load !0, !nontemporal !1, !nonnull !1, !dereferenceable !2, !dereferenceable_or_null !2 + + store ptr null, ptr %base, ptr_provenance ptr %base, align 4, !nontemporal !1 + ; CHECK: store ptr null, ptr %base, ptr_provenance ptr %base, align 4, !nontemporal !1 + store volatile ptr null, ptr %base, ptr_provenance ptr %base, align 4, !nontemporal !1 + ; CHECK: store volatile ptr null, ptr %base, ptr_provenance ptr %base, align 4, !nontemporal !1 + + ret i32 %r + ; CHECK-NEXT: ret i32 %r +} + +!0 = !{i32 1} +!1 = !{} +!2 = !{i64 4}