diff --git a/llvm/lib/Transforms/IPO/MergeFunctions.cpp b/llvm/lib/Transforms/IPO/MergeFunctions.cpp --- a/llvm/lib/Transforms/IPO/MergeFunctions.cpp +++ b/llvm/lib/Transforms/IPO/MergeFunctions.cpp @@ -120,6 +120,7 @@ #include "llvm/Support/raw_ostream.h" #include "llvm/Transforms/IPO.h" #include "llvm/Transforms/Utils/FunctionComparator.h" +#include "llvm/Transforms/Utils/ModuleUtils.h" #include #include #include @@ -225,6 +226,9 @@ /// analyzed again. std::vector Deferred; + /// Set of values marked as used in llvm.used and llvm.compiler.used. + SmallPtrSet Used; + #ifndef NDEBUG /// Checks the rules of order relation introduced among functions set. /// Returns true, if check has been passed, and false if failed. @@ -407,6 +411,11 @@ bool MergeFunctions::runOnModule(Module &M) { bool Changed = false; + SmallVector UsedV; + collectUsedGlobalVariables(M, UsedV, /*CompilerUsed=*/false); + collectUsedGlobalVariables(M, UsedV, /*CompilerUsed=*/true); + Used.insert(UsedV.begin(), UsedV.end()); + // All functions in the module, ordered by hash. Functions with a unique // hash value are easily eliminated. std::vector> @@ -453,6 +462,7 @@ FnTree.clear(); FNodesInTree.clear(); GlobalNumbers.clear(); + Used.clear(); return Changed; } @@ -825,7 +835,10 @@ // For better debugability, under MergeFunctionsPDI, we do not modify G's // call sites to point to F even when within the same translation unit. if (!G->isInterposable() && !MergeFunctionsPDI) { - if (G->hasGlobalUnnamedAddr()) { + // Functions referred to by llvm.used/llvm.compiler.used are special: + // there are uses of the symbol name that are not visible to LLVM, + // usually from inline asm. + if (G->hasGlobalUnnamedAddr() && !Used.contains(G)) { // G might have been a key in our GlobalNumberState, and it's illegal // to replace a key in ValueMap with a non-global. GlobalNumbers.erase(G); diff --git a/llvm/test/Transforms/MergeFunc/merge-used.ll b/llvm/test/Transforms/MergeFunc/merge-used.ll new file mode 100644 --- /dev/null +++ b/llvm/test/Transforms/MergeFunc/merge-used.ll @@ -0,0 +1,25 @@ +; RUN: opt -S -mergefunc < %s | FileCheck %s + +@llvm.compiler.used = appending global [1 x i8*] [i8* bitcast (i32 (i32)* @a to i8*)], section "llvm.metadata" + +define internal i32 @a(i32 %a) unnamed_addr { + %b = xor i32 %a, 0 + %c = xor i32 %b, 0 + ret i32 %c +} +define i32 @b(i32 %a) unnamed_addr { + %b = xor i32 %a, 0 + %c = xor i32 %b, 0 + ret i32 %c +} + +; CHECK-LABEL: @llvm.compiler.used = appending global [1 x i8*] [i8* bitcast (i32 (i32)* @a to i8*)], section "llvm.metadata" + +; CHECK-LABEL: define i32 @b(i32 %a) unnamed_addr +; CHECK-NEXT: xor +; CHECK-NEXT: xor +; CHECK-NEXT: ret + +; CHECK-LABEL: define internal i32 @a(i32 %0) unnamed_addr +; CHECK-NEXT: tail call i32 @b(i32 %0) +; CHECK-NEXT: ret