Skip to content

Commit

Permalink
Linker: Fix linking of byref types
Browse files Browse the repository at this point in the history
This wasn't properly remapping the type like with the other
attributes, so this would end up hitting a verifier error after
linking different modules using byref.

(cherry picked from commit c5ce603)
Change-Id: Ifcf82db3941a2ada745b2e399e2d8a07834ce4e6
  • Loading branch information
arsenm authored and amd-aakash committed Dec 8, 2020
1 parent 2d3a36f commit dac2bfc
Show file tree
Hide file tree
Showing 7 changed files with 99 additions and 63 deletions.
18 changes: 18 additions & 0 deletions llvm/include/llvm/IR/Attributes.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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,
Expand Down
16 changes: 8 additions & 8 deletions llvm/lib/Linker/IRMover.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
15 changes: 7 additions & 8 deletions llvm/lib/Transforms/Utils/ValueMapper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
13 changes: 13 additions & 0 deletions llvm/test/Linker/Inputs/byref-type-input.ll
Original file line number Diff line number Diff line change
@@ -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
}
25 changes: 25 additions & 0 deletions llvm/test/Linker/byref-types.ll
Original file line number Diff line number Diff line change
@@ -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))
52 changes: 17 additions & 35 deletions llvm/test/Transforms/Attributor/readattrs.ll
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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 <i1 true, i1 false, i1 true, i1 false>) [[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 <i1 true, i1 false, i1 true, i1 false>) [[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> <i1 true, i1 false, i1 true, i1 false>)
; CHECK-NEXT: ret void
;
call void @llvm.masked.scatter.v4i32.v4p0i32(<4 x i32>%val, <4 x i32*> %ptrs, i32 4, <4 x i1><i1 true, i1 false, i1 true, i1 false>)
ret void
Expand All @@ -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 <i1 true, i1 false, i1 true, i1 false>, <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 <i1 true, i1 false, i1 true, i1 false>, <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> <i1 true, i1 false, i1 true, i1 false>, <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><i1 true, i1 false, i1 true, i1 false>, <4 x i32>undef)
ret <4 x i32> %res
Expand All @@ -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
Expand Down
23 changes: 11 additions & 12 deletions llvm/test/Transforms/Attributor/value-simplify.ll
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down

0 comments on commit dac2bfc

Please sign in to comment.