diff --git a/llvm/lib/Linker/LinkModules.cpp b/llvm/lib/Linker/LinkModules.cpp --- a/llvm/lib/Linker/LinkModules.cpp +++ b/llvm/lib/Linker/LinkModules.cpp @@ -379,8 +379,20 @@ GV.hasAvailableExternallyLinkage())) return false; - if (GV.isDeclaration()) + // Drop memory (inaccessiblemem) and nocallback attributes while linking + // because they are only valid on the module level. + // - memory (inaccessiblemem) function attributes are generated internally per + // module semantics. + // - nocallback function attribute is treated as a hint on the module level. + if (GV.isDeclaration()) { + if (auto *F = dyn_cast(&GV)) { + if (!F->doesNotAccessMemory() && F->onlyAccessesInaccessibleMemory()) + F->removeFnAttr(llvm::Attribute::Memory); + if (F->hasFnAttribute(llvm::Attribute::NoCallback)) + F->removeFnAttr(llvm::Attribute::NoCallback); + } return false; + } LinkFrom ComdatFrom = LinkFrom::Dst; if (const Comdat *SC = GV.getComdat()) { diff --git a/llvm/test/Linker/Inputs/drop-attribute.ll b/llvm/test/Linker/Inputs/drop-attribute.ll new file mode 100644 --- /dev/null +++ b/llvm/test/Linker/Inputs/drop-attribute.ll @@ -0,0 +1,4 @@ +define void @test_nocallback_declaration_definition_linked_in() { +entry: + ret void +} diff --git a/llvm/test/Linker/drop-attribute.ll b/llvm/test/Linker/drop-attribute.ll new file mode 100644 --- /dev/null +++ b/llvm/test/Linker/drop-attribute.ll @@ -0,0 +1,37 @@ +; RUN: llvm-link %s %p/Inputs/drop-attribute.ll -S -o - | FileCheck %s + +; Test case that checks that memory(inaccessiblemem) and nocallback attributes are dropped during linking. + +; CHECK: define i32 @main() +define i32 @main() { +entry: + call void @test_inaccessiblemem_read() + call void @test_inaccessiblemem_write() + call void @test_inaccessiblemem_readwrite() + call float @llvm.sqrt.f32(float undef) + call void @test_nocallback_declaration_definition_not_linked_in() + call void @test_nocallback_declaration_definition_linked_in() + ret i32 0 +} + +; CHECK: declare void @test_inaccessiblemem_read(){{$}} +declare void @test_inaccessiblemem_read() memory(inaccessiblemem: read) + +; CHECK: declare void @test_inaccessiblemem_write(){{$}} +declare void @test_inaccessiblemem_write() memory(inaccessiblemem: write) + +; CHECK: declare void @test_inaccessiblemem_readwrite(){{$}} +declare void @test_inaccessiblemem_readwrite() memory(inaccessiblemem: readwrite) + +; CHECK: ; Function Attrs: nofree nosync nounwind speculatable willreturn +; CHECK-NEXT: declare float @llvm.sqrt.f32(float) #0 +declare float @llvm.sqrt.f32(float) nocallback + +; CHECK: declare void @test_nocallback_declaration_definition_not_linked_in(){{$}} +declare void @test_nocallback_declaration_definition_not_linked_in() nocallback + +declare void @test_nocallback_declaration_definition_linked_in() nocallback + +; CHECK: define void @test_nocallback_declaration_definition_linked_in() +; CHECK: entry: +; CHECK-NEXT: ret void