diff --git a/llvm/include/llvm/IR/MDBuilder.h b/llvm/include/llvm/IR/MDBuilder.h index dc7fec7b802b..d5218eadc4ab 100644 --- a/llvm/include/llvm/IR/MDBuilder.h +++ b/llvm/include/llvm/IR/MDBuilder.h @@ -190,6 +190,10 @@ public: uint64_t Offset, uint64_t Size, bool IsImmutable = false); + /// \brief Return mutable version of the given mutable or immutable TBAA + /// access tag. + MDNode *createMutableTBAAAccessTag(MDNode *Tag); + /// \brief Return metadata containing an irreducible loop header weight. MDNode *createIrrLoopHeaderWeight(uint64_t Weight); }; diff --git a/llvm/lib/IR/MDBuilder.cpp b/llvm/lib/IR/MDBuilder.cpp index 9d467fb9f6d5..c32a989ef2c7 100644 --- a/llvm/lib/IR/MDBuilder.cpp +++ b/llvm/lib/IR/MDBuilder.cpp @@ -232,6 +232,33 @@ MDNode *MDBuilder::createTBAAAccessTag(MDNode *BaseType, MDNode *AccessType, return MDNode::get(Context, {BaseType, AccessType, OffsetNode, SizeNode}); } +MDNode *MDBuilder::createMutableTBAAAccessTag(MDNode *Tag) { + MDNode *BaseType = cast(Tag->getOperand(1)); + MDNode *AccessType = cast(Tag->getOperand(1)); + Metadata *OffsetNode = Tag->getOperand(2); + uint64_t Offset = mdconst::extract(OffsetNode)->getZExtValue(); + + bool NewFormat = isa(AccessType->getOperand(0)); + + // See if the tag is already mutable. + unsigned ImmutabilityFlagOp = NewFormat ? 4 : 3; + if (Tag->getNumOperands() <= ImmutabilityFlagOp) + return Tag; + + // If Tag is already mutable then return it. + Metadata *ImmutabilityFlagNode = Tag->getOperand(ImmutabilityFlagOp); + if (!mdconst::extract(ImmutabilityFlagNode)->getValue()) + return Tag; + + // Otherwise, create another node. + if (!NewFormat) + return createTBAAStructTagNode(BaseType, AccessType, Offset); + + Metadata *SizeNode = Tag->getOperand(3); + uint64_t Size = mdconst::extract(SizeNode)->getZExtValue(); + return createTBAAAccessTag(BaseType, AccessType, Offset, Size); +} + MDNode *MDBuilder::createIrrLoopHeaderWeight(uint64_t Weight) { SmallVector Vals(2); Vals[0] = createString("loop_header_weight"); diff --git a/llvm/lib/Transforms/Scalar/RewriteStatepointsForGC.cpp b/llvm/lib/Transforms/Scalar/RewriteStatepointsForGC.cpp index c44edbed8ed9..c7acdef27136 100644 --- a/llvm/lib/Transforms/Scalar/RewriteStatepointsForGC.cpp +++ b/llvm/lib/Transforms/Scalar/RewriteStatepointsForGC.cpp @@ -2461,22 +2461,8 @@ static void stripNonValidDataFromBody(Function &F) { continue; } - if (const MDNode *MD = I.getMetadata(LLVMContext::MD_tbaa)) { - assert(MD->getNumOperands() < 5 && "unrecognized metadata shape!"); - bool IsImmutableTBAA = - MD->getNumOperands() == 4 && - mdconst::extract(MD->getOperand(3))->getValue() == 1; - - if (!IsImmutableTBAA) - continue; // no work to do, MD_tbaa is already marked mutable - - MDNode *Base = cast(MD->getOperand(0)); - MDNode *Access = cast(MD->getOperand(1)); - uint64_t Offset = - mdconst::extract(MD->getOperand(2))->getZExtValue(); - - MDNode *MutableTBAA = - Builder.createTBAAStructTagNode(Base, Access, Offset); + if (MDNode *Tag = I.getMetadata(LLVMContext::MD_tbaa)) { + MDNode *MutableTBAA = Builder.createMutableTBAAAccessTag(Tag); I.setMetadata(LLVMContext::MD_tbaa, MutableTBAA); } diff --git a/llvm/test/Transforms/RewriteStatepointsForGC/deref-pointers.ll b/llvm/test/Transforms/RewriteStatepointsForGC/deref-pointers.ll index d08da73887a3..69dbf6f0af6a 100644 --- a/llvm/test/Transforms/RewriteStatepointsForGC/deref-pointers.ll +++ b/llvm/test/Transforms/RewriteStatepointsForGC/deref-pointers.ll @@ -62,13 +62,23 @@ entry: define i8 @test_md(i8 addrspace(1)* %ptr) gc "statepoint-example" { ; CHECK-LABEL: @test_md( -; CHECK: %tmp = load i8, i8 addrspace(1)* %ptr, !tbaa !0 +; CHECK: %tmp = load i8, i8 addrspace(1)* %ptr, !tbaa [[TAG_old:!.*]] entry: %tmp = load i8, i8 addrspace(1)* %ptr, !tbaa !0 call void @foo() [ "deopt"(i32 0, i32 -1, i32 0, i32 0, i32 0) ] ret i8 %tmp } +; Same as test_md() above, but with new-format TBAA metadata. +define i8 @test_md_new(i8 addrspace(1)* %ptr) gc "statepoint-example" { +; CHECK-LABEL: @test_md_new( +; CHECK: %tmp = load i8, i8 addrspace(1)* %ptr, !tbaa [[TAG_new:!.*]] +entry: + %tmp = load i8, i8 addrspace(1)* %ptr, !tbaa !3 + call void @foo() [ "deopt"(i32 0, i32 -1, i32 0, i32 0, i32 0) ] + ret i8 %tmp +} + define i8 addrspace(1)* @test_decl_only_attribute(i8 addrspace(1)* %ptr) gc "statepoint-example" { ; CHECK-LABEL: @test_decl_only_attribute( ; No change here, but the prototype of some_function_ret_deref should have changed. @@ -92,14 +102,21 @@ entry: define i8 addrspace(1)* @test_callsite_arg_attribute(i8 addrspace(1)* %ptr) gc "statepoint-example" { ; CHECK-LABEL: @test_callsite_arg_attribute( ; CHECK: call void @some_function_consumer(i8 addrspace(1)* %ptr) -; CHECK: !0 = !{!1, !1, i64 0} -; CHECK: !1 = !{!"red", !2} -; CHECK: !2 = !{!"blue"} entry: call void @some_function_consumer(i8 addrspace(1)* dereferenceable(4) noalias %ptr) call void @foo() [ "deopt"(i32 0, i32 -1, i32 0, i32 0, i32 0) ] ret i8 addrspace(1)* %ptr } -!0 = !{!1, !1, i64 0, i64 1} -!1 = !{!"red", !2} -!2 = !{!"blue"} + +!0 = !{!1, !1, i64 0, i64 1} ; TAG_old +!1 = !{!"type_old", !2} +!2 = !{!"root"} + +!3 = !{!4, !4, i64 0, i64 1, i64 1} ; TAG_new +!4 = !{!2, i64 1, !"type_new"} + +; CHECK-DAG: [[ROOT:!.*]] = !{!"root"} +; CHECK-DAG: [[TYPE_old:!.*]] = !{!"type_old", [[ROOT]]} +; CHECK-DAG: [[TAG_old]] = !{[[TYPE_old]], [[TYPE_old]], i64 0} +; CHECK-DAG: [[TYPE_new:!.*]] = !{[[ROOT]], i64 1, !"type_new"} +; CHECK-DAG: [[TAG_new]] = !{[[TYPE_new]], [[TYPE_new]], i64 0, i64 1}