diff --git a/llvm/include/llvm/IR/Attributes.h b/llvm/include/llvm/IR/Attributes.h index 03f2fc123cba4a..7d9c2ef17f1f06 100644 --- a/llvm/include/llvm/IR/Attributes.h +++ b/llvm/include/llvm/IR/Attributes.h @@ -111,6 +111,13 @@ class Attribute { static Attribute getWithByRefType(LLVMContext &Context, Type *Ty); static Attribute getWithPreallocatedType(LLVMContext &Context, Type *Ty); + /// For a typed attribute, return the equivalent attribute with the type + /// changed to \p ReplacementTy. + Attribute getWithNewType(LLVMContext &Context, Type *ReplacementTy) { + assert(isTypeAttribute() && "this requires a typed attribute"); + return get(Context, getKindAsEnum(), ReplacementTy); + } + static Attribute::AttrKind getAttrKindFromName(StringRef AttrName); static StringRef getNameFromAttrKind(Attribute::AttrKind AttrKind); @@ -505,6 +512,17 @@ class AttributeList { return removeAttributes(C, ArgNo + FirstArgIndex); } + /// Replace the type contained by attribute \p AttrKind at index \p ArgNo wih + /// \p ReplacementTy, preserving all other attributes. + LLVM_NODISCARD AttributeList replaceAttributeType(LLVMContext &C, + unsigned ArgNo, + Attribute::AttrKind Kind, + Type *ReplacementTy) const { + Attribute Attr = getAttribute(ArgNo, Kind); + auto Attrs = removeAttribute(C, ArgNo, Kind); + return Attrs.addAttribute(C, ArgNo, Attr.getWithNewType(C, ReplacementTy)); + } + /// \brief Add the dereferenceable attribute to the attribute set at the given /// index. Returns a new list because attribute lists are immutable. LLVM_NODISCARD AttributeList addDereferenceableAttr(LLVMContext &C, diff --git a/llvm/lib/Linker/IRMover.cpp b/llvm/lib/Linker/IRMover.cpp index 147bbb9803309e..5acc671717b35e 100644 --- a/llvm/lib/Linker/IRMover.cpp +++ b/llvm/lib/Linker/IRMover.cpp @@ -640,14 +640,14 @@ GlobalVariable *IRLinker::copyGlobalVariableProto(const GlobalVariable *SGVar) { AttributeList IRLinker::mapAttributeTypes(LLVMContext &C, AttributeList Attrs) { for (unsigned i = 0; i < Attrs.getNumAttrSets(); ++i) { - if (Attrs.hasAttribute(i, Attribute::ByVal)) { - Type *Ty = Attrs.getAttribute(i, Attribute::ByVal).getValueAsType(); - if (!Ty) - continue; - - Attrs = Attrs.removeAttribute(C, i, Attribute::ByVal); - Attrs = Attrs.addAttribute( - C, i, Attribute::getWithByValType(C, TypeMap.get(Ty))); + for (Attribute::AttrKind TypedAttr : + {Attribute::ByVal, Attribute::ByRef}) { + if (Attrs.hasAttribute(i, TypedAttr)) { + if (Type *Ty = Attrs.getAttribute(i, TypedAttr).getValueAsType()) { + Attrs = Attrs.replaceAttributeType(C, i, TypedAttr, TypeMap.get(Ty)); + break; + } + } } } return Attrs; diff --git a/llvm/lib/Transforms/Utils/ValueMapper.cpp b/llvm/lib/Transforms/Utils/ValueMapper.cpp index f1b3fe8e2fa9ae..d75be7549aa664 100644 --- a/llvm/lib/Transforms/Utils/ValueMapper.cpp +++ b/llvm/lib/Transforms/Utils/ValueMapper.cpp @@ -900,14 +900,13 @@ void Mapper::remapInstruction(Instruction *I) { LLVMContext &C = CB->getContext(); AttributeList Attrs = CB->getAttributes(); for (unsigned i = 0; i < Attrs.getNumAttrSets(); ++i) { - if (Attrs.hasAttribute(i, Attribute::ByVal)) { - Type *Ty = Attrs.getAttribute(i, Attribute::ByVal).getValueAsType(); - if (!Ty) - continue; - - Attrs = Attrs.removeAttribute(C, i, Attribute::ByVal); - Attrs = Attrs.addAttribute( - C, i, Attribute::getWithByValType(C, TypeMapper->remapType(Ty))); + for (Attribute::AttrKind TypedAttr : + {Attribute::ByVal, Attribute::ByRef}) { + if (Type *Ty = Attrs.getAttribute(i, TypedAttr).getValueAsType()) { + Attrs = Attrs.replaceAttributeType(C, i, TypedAttr, + TypeMapper->remapType(Ty)); + break; + } } } CB->setAttributes(Attrs); diff --git a/llvm/test/Linker/Inputs/byref-type-input.ll b/llvm/test/Linker/Inputs/byref-type-input.ll new file mode 100644 index 00000000000000..1ca8a897327b58 --- /dev/null +++ b/llvm/test/Linker/Inputs/byref-type-input.ll @@ -0,0 +1,13 @@ +%a = type { i64 } +%struct = type { i32, i8 } + +define void @g(%a* byref(%a)) { + ret void +} + +declare void @baz(%struct* byref(%struct)) + +define void @foo(%struct* byref(%struct) %a) { + call void @baz(%struct* byref(%struct) %a) + ret void +} diff --git a/llvm/test/Linker/byref-types.ll b/llvm/test/Linker/byref-types.ll new file mode 100644 index 00000000000000..b79fb2d9df8e4a --- /dev/null +++ b/llvm/test/Linker/byref-types.ll @@ -0,0 +1,25 @@ +; RUN: llvm-link %s %p/Inputs/byref-type-input.ll -S | FileCheck %s + +%a = type { i64 } +%struct = type { i32, i8 } + +; CHECK-LABEL: define void @f(%a* byref(%a) %0) +define void @f(%a* byref(%a)) { + ret void +} + +; CHECK-LABEL: define void @bar( +; CHECK: call void @foo(%struct* byref(%struct) %ptr) +define void @bar() { + %ptr = alloca %struct + call void @foo(%struct* byref(%struct) %ptr) + ret void +} + +; CHECK-LABEL: define void @g(%a* byref(%a) %0) + +; CHECK-LABEL: define void @foo(%struct* byref(%struct) %a) +; CHECK-NEXT: call void @baz(%struct* byref(%struct) %a) +declare void @foo(%struct* byref(%struct) %a) + +; CHECK: declare void @baz(%struct* byref(%struct)) diff --git a/llvm/test/Transforms/Attributor/readattrs.ll b/llvm/test/Transforms/Attributor/readattrs.ll index df14d42f152b8a..67f7fe98436abb 100644 --- a/llvm/test/Transforms/Attributor/readattrs.ll +++ b/llvm/test/Transforms/Attributor/readattrs.ll @@ -106,12 +106,12 @@ define void @test6_2(i8** %p, i8* %q) { define void @test7_1(i32* inalloca %a) { ; IS__TUNIT____: Function Attrs: nofree nosync nounwind readnone willreturn ; IS__TUNIT____-LABEL: define {{[^@]+}}@test7_1 -; IS__TUNIT____-SAME: (i32* inalloca nocapture nofree nonnull writeonly dereferenceable(4) [[A:%.*]]) [[ATTR1]] { +; IS__TUNIT____-SAME: (i32* inalloca nocapture nofree nonnull writeonly dereferenceable(4) [[A:%.*]]) ; IS__TUNIT____-NEXT: ret void ; ; IS__CGSCC____: Function Attrs: nofree norecurse nosync nounwind readnone willreturn ; IS__CGSCC____-LABEL: define {{[^@]+}}@test7_1 -; IS__CGSCC____-SAME: (i32* inalloca nocapture nofree nonnull writeonly dereferenceable(4) [[A:%.*]]) [[ATTR1]] { +; IS__CGSCC____-SAME: (i32* inalloca nocapture nofree nonnull writeonly dereferenceable(4) [[A:%.*]]) ; IS__CGSCC____-NEXT: ret void ; ret void @@ -163,17 +163,11 @@ declare void @llvm.masked.scatter.v4i32.v4p0i32(<4 x i32>%val, <4 x i32*>, i32, ; CHECK-NOT: readnone ; CHECK-NOT: readonly define void @test9(<4 x i32*> %ptrs, <4 x i32>%val) { -; IS__TUNIT____: Function Attrs: nounwind willreturn writeonly -; IS__TUNIT____-LABEL: define {{[^@]+}}@test9 -; IS__TUNIT____-SAME: (<4 x i32*> [[PTRS:%.*]], <4 x i32> [[VAL:%.*]]) [[ATTR4:#.*]] { -; IS__TUNIT____-NEXT: call void @llvm.masked.scatter.v4i32.v4p0i32(<4 x i32> [[VAL]], <4 x i32*> [[PTRS]], i32 noundef 4, <4 x i1> noundef ) [[ATTR11:#.*]] -; IS__TUNIT____-NEXT: ret void -; -; IS__CGSCC____: Function Attrs: nounwind willreturn writeonly -; IS__CGSCC____-LABEL: define {{[^@]+}}@test9 -; IS__CGSCC____-SAME: (<4 x i32*> [[PTRS:%.*]], <4 x i32> [[VAL:%.*]]) [[ATTR4:#.*]] { -; IS__CGSCC____-NEXT: call void @llvm.masked.scatter.v4i32.v4p0i32(<4 x i32> [[VAL]], <4 x i32*> [[PTRS]], i32 noundef 4, <4 x i1> noundef ) [[ATTR12:#.*]] -; IS__CGSCC____-NEXT: ret void +; CHECK: Function Attrs: nounwind willreturn +; CHECK-LABEL: define {{[^@]+}}@test9 +; CHECK-SAME: (<4 x i32*> [[PTRS:%.*]], <4 x i32> [[VAL:%.*]]) +; CHECK-NEXT: call void @llvm.masked.scatter.v4i32.v4p0i32(<4 x i32> [[VAL]], <4 x i32*> [[PTRS]], i32 4, <4 x i1> ) +; CHECK-NEXT: ret void ; call void @llvm.masked.scatter.v4i32.v4p0i32(<4 x i32>%val, <4 x i32*> %ptrs, i32 4, <4 x i1>) ret void @@ -182,17 +176,11 @@ define void @test9(<4 x i32*> %ptrs, <4 x i32>%val) { ; CHECK: declare <4 x i32> @llvm.masked.gather declare <4 x i32> @llvm.masked.gather.v4i32.v4p0i32(<4 x i32*>, i32, <4 x i1>, <4 x i32>) define <4 x i32> @test10(<4 x i32*> %ptrs) { -; IS__TUNIT____: Function Attrs: nounwind readonly willreturn -; IS__TUNIT____-LABEL: define {{[^@]+}}@test10 -; IS__TUNIT____-SAME: (<4 x i32*> [[PTRS:%.*]]) [[ATTR5:#.*]] { -; IS__TUNIT____-NEXT: [[RES:%.*]] = call <4 x i32> @llvm.masked.gather.v4i32.v4p0i32(<4 x i32*> [[PTRS]], i32 noundef 4, <4 x i1> noundef , <4 x i32> undef) [[ATTR12:#.*]] -; IS__TUNIT____-NEXT: ret <4 x i32> [[RES]] -; -; IS__CGSCC____: Function Attrs: nounwind readonly willreturn -; IS__CGSCC____-LABEL: define {{[^@]+}}@test10 -; IS__CGSCC____-SAME: (<4 x i32*> [[PTRS:%.*]]) [[ATTR5:#.*]] { -; IS__CGSCC____-NEXT: [[RES:%.*]] = call <4 x i32> @llvm.masked.gather.v4i32.v4p0i32(<4 x i32*> [[PTRS]], i32 noundef 4, <4 x i1> noundef , <4 x i32> undef) [[ATTR13:#.*]] -; IS__CGSCC____-NEXT: ret <4 x i32> [[RES]] +; CHECK: Function Attrs: nounwind readonly willreturn +; CHECK-LABEL: define {{[^@]+}}@test10 +; CHECK-SAME: (<4 x i32*> [[PTRS:%.*]]) +; CHECK-NEXT: [[RES:%.*]] = call <4 x i32> @llvm.masked.gather.v4i32.v4p0i32(<4 x i32*> [[PTRS]], i32 4, <4 x i1> , <4 x i32> undef) +; CHECK-NEXT: ret <4 x i32> [[RES]] ; %res = call <4 x i32> @llvm.masked.gather.v4i32.v4p0i32(<4 x i32*> %ptrs, i32 4, <4 x i1>, <4 x i32>undef) ret <4 x i32> %res @@ -214,17 +202,11 @@ define <4 x i32> @test11_2(<4 x i32*> %ptrs) { declare <4 x i32> @test12_1(<4 x i32*>) argmemonly nounwind ; CHECK-NOT: readnone define <4 x i32> @test12_2(<4 x i32*> %ptrs) { -; IS__TUNIT____: Function Attrs: argmemonly nounwind -; IS__TUNIT____-LABEL: define {{[^@]+}}@test12_2 -; IS__TUNIT____-SAME: (<4 x i32*> [[PTRS:%.*]]) [[ATTR7:#.*]] { -; IS__TUNIT____-NEXT: [[RES:%.*]] = call <4 x i32> @test12_1(<4 x i32*> [[PTRS]]) [[ATTR13:#.*]] -; IS__TUNIT____-NEXT: ret <4 x i32> [[RES]] -; -; IS__CGSCC____: Function Attrs: argmemonly nounwind -; IS__CGSCC____-LABEL: define {{[^@]+}}@test12_2 -; IS__CGSCC____-SAME: (<4 x i32*> [[PTRS:%.*]]) [[ATTR7:#.*]] { -; IS__CGSCC____-NEXT: [[RES:%.*]] = call <4 x i32> @test12_1(<4 x i32*> [[PTRS]]) [[ATTR14:#.*]] -; IS__CGSCC____-NEXT: ret <4 x i32> [[RES]] +; CHECK: Function Attrs: argmemonly nounwind +; CHECK-LABEL: define {{[^@]+}}@test12_2 +; CHECK-SAME: (<4 x i32*> [[PTRS:%.*]]) +; CHECK-NEXT: [[RES:%.*]] = call <4 x i32> @test12_1(<4 x i32*> [[PTRS]]) +; CHECK-NEXT: ret <4 x i32> [[RES]] ; %res = call <4 x i32> @test12_1(<4 x i32*> %ptrs) ret <4 x i32> %res diff --git a/llvm/test/Transforms/Attributor/value-simplify.ll b/llvm/test/Transforms/Attributor/value-simplify.ll index fc9cb25d732194..83a1e3a0af4512 100644 --- a/llvm/test/Transforms/Attributor/value-simplify.ll +++ b/llvm/test/Transforms/Attributor/value-simplify.ll @@ -321,29 +321,28 @@ define i32 @ipccp3() { define internal i32* @test_inalloca(i32* inalloca %a) { ; IS__TUNIT____: Function Attrs: nofree nosync nounwind readnone willreturn ; IS__TUNIT____-LABEL: define {{[^@]+}}@test_inalloca -; IS__TUNIT____-SAME: (i32* inalloca noalias nofree nonnull returned writeonly dereferenceable(4) "no-capture-maybe-returned" [[A:%.*]]) [[ATTR1]] { +; IS__TUNIT____-SAME: (i32* inalloca noalias nofree nonnull returned writeonly dereferenceable(4) "no-capture-maybe-returned" [[A:%.*]]) ; IS__TUNIT____-NEXT: ret i32* [[A]] ; ; IS__CGSCC____: Function Attrs: nofree norecurse nosync nounwind readnone willreturn ; IS__CGSCC____-LABEL: define {{[^@]+}}@test_inalloca -; IS__CGSCC____-SAME: (i32* inalloca noalias nofree nonnull returned writeonly dereferenceable(4) "no-capture-maybe-returned" [[A:%.*]]) [[ATTR1]] { +; IS__CGSCC____-SAME: (i32* inalloca nofree nonnull returned writeonly dereferenceable(4) "no-capture-maybe-returned" [[A:%.*]]) ; IS__CGSCC____-NEXT: ret i32* [[A]] ; ret i32* %a } define i32* @complicated_args_inalloca(i32* %arg) { ; IS__TUNIT____: Function Attrs: nofree nosync nounwind readnone willreturn -; IS__TUNIT____-LABEL: define {{[^@]+}}@complicated_args_inalloca() -; IS__TUNIT____-SAME: (i32* nofree readnone returned "no-capture-maybe-returned" [[ARG:%.*]]) [[ATTR1]] { -; IS__TUNIT____-NEXT: [[CALL:%.*]] = call i32* @test_inalloca(i32* noalias nofree writeonly "no-capture-maybe-returned" [[ARG]]) [[ATTR1]] +; IS__TUNIT____-LABEL: define {{[^@]+}}@complicated_args_inalloca +; IS__TUNIT____-SAME: (i32* nofree readnone returned "no-capture-maybe-returned" [[ARG:%.*]]) +; IS__TUNIT____-NEXT: [[CALL:%.*]] = call i32* @test_inalloca(i32* noalias nofree writeonly "no-capture-maybe-returned" [[ARG]]) ; IS__TUNIT____-NEXT: ret i32* [[CALL]] ; ; IS__CGSCC____: Function Attrs: nofree norecurse nosync nounwind readnone willreturn -; IS__CGSCC____-LABEL: define {{[^@]+}}@complicated_args_inalloca() -; IS__CGSCC_OPM-SAME: (i32* nofree nonnull readnone returned dereferenceable(4) "no-capture-maybe-returned" [[ARG:%.*]]) [[ATTR1:#.*]] { -; IS__CGSCC_OPM-NEXT: [[CALL:%.*]] = call i32* @test_inalloca(i32* noalias nofree nonnull writeonly dereferenceable(4) "no-capture-maybe-returned" [[ARG]]) [[ATTR5:#.*]] -; IS__CGSCC_NPM-SAME: (i32* nofree nonnull readnone returned dereferenceable(4) "no-capture-maybe-returned" [[ARG:%.*]]) [[ATTR1:#.*]] { -; IS__CGSCC_NPM-NEXT: [[CALL:%.*]] = call i32* @test_inalloca(i32* noalias nofree nonnull writeonly dereferenceable(4) "no-capture-maybe-returned" [[ARG]]) [[ATTR4:#.*]] +; IS__CGSCC____-LABEL: define {{[^@]+}}@complicated_args_inalloca +; IS__CGSCC____-SAME: (i32* nofree nonnull readnone returned dereferenceable(4) [[ARG:%.*]]) +; IS__CGSCC____-NEXT: [[CALL:%.*]] = call i32* @test_inalloca(i32* noalias nofree nonnull writeonly dereferenceable(4) [[ARG]]) +; IS__CGSCC____-NEXT: ret i32* [[CALL]] ; %call = call i32* @test_inalloca(i32* %arg) ret i32* %call @@ -352,12 +351,12 @@ define i32* @complicated_args_inalloca(i32* %arg) { define internal i32* @test_preallocated(i32* preallocated(i32) %a) { ; IS__TUNIT____: Function Attrs: nofree nosync nounwind readnone willreturn ; IS__TUNIT____-LABEL: define {{[^@]+}}@test_preallocated -; IS__TUNIT____-SAME: (i32* noalias nofree noundef nonnull returned writeonly preallocated(i32) align 536870912 dereferenceable(4) "no-capture-maybe-returned" [[A:%.*]]) [[ATTR1]] { +; IS__TUNIT____-SAME: (i32* noalias nofree nonnull returned writeonly preallocated(i32) align 536870912 dereferenceable(4) "no-capture-maybe-returned" [[A:%.*]]) ; IS__TUNIT____-NEXT: ret i32* [[A]] ; ; IS__CGSCC____: Function Attrs: nofree norecurse nosync nounwind readnone willreturn ; IS__CGSCC____-LABEL: define {{[^@]+}}@test_preallocated -; IS__CGSCC____-SAME: (i32* noalias nofree noundef nonnull returned writeonly preallocated(i32) align 536870912 dereferenceable(4) "no-capture-maybe-returned" [[A:%.*]]) [[ATTR1]] { +; IS__CGSCC____-SAME: (i32* noalias nofree nonnull returned writeonly preallocated(i32) align 536870912 dereferenceable(4) "no-capture-maybe-returned" [[A:%.*]]) ; IS__CGSCC____-NEXT: ret i32* [[A]] ; ret i32* %a