Index: include/llvm/IR/Verifier.h =================================================================== --- include/llvm/IR/Verifier.h +++ include/llvm/IR/Verifier.h @@ -78,6 +78,9 @@ /// Visit an instruction and return true if it is valid, return false if an /// invalid TBAA is attached. bool visitTBAAMetadata(Instruction &I, const MDNode *MD); + + static bool ShouldHaveTBAAAccessTag(Instruction &I); + static bool CouldHaveTBAAAccessTag(Instruction &I); }; /// \brief Check a function for errors, useful for use when debugging a Index: lib/IR/Verifier.cpp =================================================================== --- lib/IR/Verifier.cpp +++ lib/IR/Verifier.cpp @@ -115,6 +115,23 @@ using namespace llvm; +static cl::opt VerifyTBAAAccessTagsPresense( + "verify-tbaa-tags", + cl::desc("Should the presence of TBAA Access Tags be checked"), cl::Hidden, + cl::init(false)); + +enum class TBAAAccessTagsLevel { Never, Partial, Always }; +static cl::opt VerifyTBAAAccessTagsFatality( + "verify-tbaa-tags-fatal", + cl::desc("If the tag is missing, when is that a fatal error"), + cl::values(clEnumValN(TBAAAccessTagsLevel::Never, "never", + "missing tag is never a fatal error"), + clEnumValN(TBAAAccessTagsLevel::Partial, "partial", + "if only some tags are missing, not all of them"), + clEnumValN(TBAAAccessTagsLevel::Always, "always", + "any missing tag is always a fatal error")), + cl::Hidden, cl::init(TBAAAccessTagsLevel::Partial)); + namespace llvm { struct VerifierSupport { @@ -130,6 +147,8 @@ bool BrokenDebugInfo = false; /// Whether to treat broken debug info as an error. bool TreatBrokenDebugInfoAsError = true; + /// Was any appropriate instruction not tagged with a TBAA Access Tag? + bool MissingTBAAAccessTags = false; explicit VerifierSupport(raw_ostream *OS, const Module &M) : OS(OS), M(M), MST(&M), DL(M.getDataLayout()), Context(M.getContext()) {} @@ -244,6 +263,22 @@ if (OS) WriteTs(V1, Vs...); } + + /// A TBAA Access Tag presense check failed. + void TBAAAccessTagsCheckFailed(const Twine &Message) { + if (OS) + *OS << Message << '\n'; + MissingTBAAAccessTags = true; + } + + /// A TBAA Access Tag presense check failed (with values to print). + template + void TBAAAccessTagsCheckFailed(const Twine &Message, const T1 &V1, + const Ts &... Vs) { + TBAAAccessTagsCheckFailed(Message); + if (OS) + WriteTs(V1, Vs...); + } }; } // namespace llvm @@ -281,6 +316,9 @@ /// Whether the current function has a DISubprogram attached to it. bool HasDebugInfo = false; + /// Whether we have seen any TBAA Access tags on appropriate instructions. + bool SeenTBAAAccessTags = false; + /// Stores the count of how many objects were passed to llvm.localescape for a /// given function and the largest index passed to llvm.localrecover. DenseMap> FrameEscapeInfo; @@ -318,6 +356,17 @@ bool hasBrokenDebugInfo() const { return BrokenDebugInfo; } + bool hasBrokenTBAAInfo() const { + switch (VerifyTBAAAccessTagsFatality) { + case TBAAAccessTagsLevel::Never: + return false; + case TBAAAccessTagsLevel::Partial: + return SeenTBAAAccessTags && MissingTBAAAccessTags; + case TBAAAccessTagsLevel::Always: + return MissingTBAAAccessTags; + }; + } + bool verify(const Function &F) { assert(F.getParent() == &M && "An instance of this class only works with a specific module!"); @@ -348,6 +397,8 @@ // FIXME: We strip const here because the inst visitor strips const. visit(const_cast(F)); verifySiblingFuncletUnwinds(); + Broken |= hasBrokenTBAAInfo(); + InstsInThisBlock.clear(); DebugFnArgs.clear(); LandingPadResultTy = nullptr; @@ -3927,8 +3978,12 @@ if (MDNode *MD = I.getMetadata(LLVMContext::MD_dereferenceable_or_null)) visitDereferenceableMetadata(I, MD); - if (MDNode *TBAA = I.getMetadata(LLVMContext::MD_tbaa)) + if (MDNode *TBAA = I.getMetadata(LLVMContext::MD_tbaa)) { TBAAVerifyHelper.visitTBAAMetadata(I, TBAA); + SeenTBAAAccessTags = true; + } else if (VerifyTBAAAccessTagsPresense && + TBAAVerifier::ShouldHaveTBAAAccessTag(I)) + TBAAAccessTagsCheckFailed("Instruction is missing a TBAA access tag.", &I); if (MDNode *AlignMD = I.getMetadata(LLVMContext::MD_align)) { Assert(I.getType()->isPointerTy(), "align applies only to pointer types", @@ -4978,10 +5033,17 @@ return true; } +bool TBAAVerifier::ShouldHaveTBAAAccessTag(Instruction &I) { + return isa(I) || isa(I) || isa(I) || + isa(I) || isa(I); +} + +bool TBAAVerifier::CouldHaveTBAAAccessTag(Instruction &I) { + return ShouldHaveTBAAAccessTag(I) || isa(I); +} + bool TBAAVerifier::visitTBAAMetadata(Instruction &I, const MDNode *MD) { - AssertTBAA(isa(I) || isa(I) || isa(I) || - isa(I) || isa(I) || - isa(I), + AssertTBAA(CouldHaveTBAAAccessTag(I), "This instruction shall not have a TBAA access tag!", &I); bool IsStructPathTBAA = Index: test/Verifier/tbaa-tag-missing.ll =================================================================== --- /dev/null +++ test/Verifier/tbaa-tag-missing.ll @@ -0,0 +1,44 @@ +; RUN: opt -verify -verify-tbaa-tags < %s 2>&1 | FileCheck %s +; RUN: opt -verify -verify-tbaa-tags -verify-tbaa-tags-fatal=never < %s 2>&1 | FileCheck %s +; RUN: opt -verify -verify-tbaa-tags -verify-tbaa-tags-fatal=partial < %s 2>&1 | FileCheck %s +; RUN: not opt -verify -verify-tbaa-tags -verify-tbaa-tags-fatal=always < %s 2>&1 | FileCheck %s -check-prefixes=CHECK,CHECK-ERROR + +declare void @callee() +declare void @llvm.va_start(i8*) nounwind + +; None of the instructions are marked with a TBAA access tag. + +define void @f_0(i8* %ptr, ...) { +; TMPOFF: Instruction is missing a TBAA access tag. +; TMPOFF-NEXT: call void @llvm.va_start(i8* %args) +; CHECK: Instruction is missing a TBAA access tag. +; CHECK-NEXT: %old = atomicrmw add i8* %ptr, i8 0 seq_cst +; CHECK: Instruction is missing a TBAA access tag. +; CHECK-NEXT: %pair = cmpxchg i8* %ptr, i8 0, i8 1 acquire acquire +; CHECK: Instruction is missing a TBAA access tag. +; CHECK-NEXT: %ld = load i8, i8* %ptr +; CHECK: Instruction is missing a TBAA access tag. +; CHECK-NEXT: store i8 1, i8* %ptr +; TMPOFF: Instruction is missing a TBAA access tag. +; TMPOFF-NEXT: call void @callee() + + %args = alloca i8, align 8 + call void @llvm.va_start(i8* %args) + + %old = atomicrmw add i8* %ptr, i8 0 seq_cst + %pair = cmpxchg i8* %ptr, i8 0, i8 1 acquire acquire + %ld = load i8, i8* %ptr + store i8 1, i8* %ptr + call void @callee() + %argval = va_arg i8* %args, i8 + + ret void +} + +; CHECK-NOT: input module is broken +; CHECK-ERROR: input module is broken + +; We can't actually know whether this metadata is in the module, +;so it does not matter. We only check the tags. +!0 = !{!"root"} +!1 = !{!"scalar-a", !0} Index: test/Verifier/tbaa-tag-partially-missing.ll =================================================================== --- /dev/null +++ test/Verifier/tbaa-tag-partially-missing.ll @@ -0,0 +1,43 @@ +; RUN: not opt -verify -verify-tbaa-tags < %s 2>&1 | FileCheck %s -check-prefixes=CHECK,CHECK-ERROR +; RUN: opt -verify -verify-tbaa-tags -verify-tbaa-tags-fatal=never < %s 2>&1 | FileCheck %s +; RUN: not opt -verify -verify-tbaa-tags -verify-tbaa-tags-fatal=partial < %s 2>&1 | FileCheck %s -check-prefixes=CHECK,CHECK-ERROR +; RUN: not opt -verify -verify-tbaa-tags -verify-tbaa-tags-fatal=always < %s 2>&1 | FileCheck %s -check-prefixes=CHECK,CHECK-ERROR + +declare void @callee() +declare void @llvm.va_start(i8*) nounwind + +define void @f_0(i8* %ptr, ...) { +; TMPOFF: Instruction is missing a TBAA access tag. +; TMPOFF-NEXT: call void @llvm.va_start(i8* %args) +; CHECK: Instruction is missing a TBAA access tag. +; CHECK-NEXT: %old = atomicrmw add i8* %ptr, i8 0 seq_cst +; CHECK: Instruction is missing a TBAA access tag. +; CHECK-NEXT: %pair = cmpxchg i8* %ptr, i8 0, i8 1 acquire acquire +; CHECK: Instruction is missing a TBAA access tag. +; CHECK-NEXT: %ld = load i8, i8* %ptr +; CHECK: Instruction is missing a TBAA access tag. +; CHECK-NEXT: store i8 1, i8* %ptr +; TMPOFF: Instruction is missing a TBAA access tag. +; TMPOFF-NEXT: call void @callee() + + %args = alloca i8, align 8 + call void @llvm.va_start(i8* %args) + + %old = atomicrmw add i8* %ptr, i8 0 seq_cst + %pair = cmpxchg i8* %ptr, i8 0, i8 1 acquire acquire + %ld = load i8, i8* %ptr + store i8 1, i8* %ptr + call void @callee() + %argval = va_arg i8* %args, i8 + + ; One instruction witn TBAA access tag not omitted. + call void @callee(), !tbaa !{!1, !1, i64 0} + + ret void +} + +; CHECK-NOT: input module is broken +; CHECK-ERROR: input module is broken + +!0 = !{!"root"} +!1 = !{!"scalar-a", !0} Index: test/Verifier/tbaa-tag-present.ll =================================================================== --- /dev/null +++ test/Verifier/tbaa-tag-present.ll @@ -0,0 +1,25 @@ +; RUN: opt -verify -verify-tbaa-tags < %s +; RUN: opt -verify -verify-tbaa-tags -verify-tbaa-tags-fatal=never < %s +; RUN: opt -verify -verify-tbaa-tags -verify-tbaa-tags-fatal=partial < %s +; RUN: opt -verify -verify-tbaa-tags -verify-tbaa-tags-fatal=always < %s + +declare void @callee() +declare void @llvm.va_start(i8*) nounwind + +; All the instructions are marked with a TBAA access tag. + +define void @f_0(i8* %ptr, ...) { + %args = alloca i8, align 8 + + call void @llvm.va_start(i8* %args), !tbaa !{!1, !1, i64 0} + %old = atomicrmw add i8* %ptr, i8 0 seq_cst, !tbaa !{!1, !1, i64 0} + %pair = cmpxchg i8* %ptr, i8 0, i8 1 acquire acquire, !tbaa !{!1, !1, i64 0} + %ld = load i8, i8* %ptr, !tbaa !{!1, !1, i64 0} + store i8 1, i8* %ptr, !tbaa !{!1, !1, i64 0} + call void @callee(), !tbaa !{!1, !1, i64 0} + %argval = va_arg i8* %args, i8, !tbaa !{!1, !1, i64 0} + ret void +} + +!0 = !{!"root"} +!1 = !{!"scalar-a", !0}