Skip to content

Commit 2cdf8f7

Browse files
Amanieunikic
authored andcommitted
[MergeFunctions] Preserve symbols used llvm.used/llvm.compiler.used
llvm.used and llvm.compiler.used are often used with inline assembly that refers to a specific symbol so that the symbol is kept through to the linker even though there are no references to it from LLVM IR. This fixes the MergeFunctions pass to preserve references to these symbols in llvm.used/llvm.compiler.used so they are not deleted from the IR. This doesn't prevent these functions from being merged, but guarantees that an alias or thunk with the expected symbol name is kept in the IR. Differential Revision: https://reviews.llvm.org/D127751 (cherry picked from commit caa2a82)
1 parent 42ac158 commit 2cdf8f7

File tree

2 files changed

+49
-1
lines changed

2 files changed

+49
-1
lines changed

llvm/lib/Transforms/IPO/MergeFunctions.cpp

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,7 @@
123123
#include "llvm/Transforms/IPO.h"
124124
#include "llvm/Transforms/IPO/MergeFunctions.h"
125125
#include "llvm/Transforms/Utils/FunctionComparator.h"
126+
#include "llvm/Transforms/Utils/ModuleUtils.h"
126127
#include <algorithm>
127128
#include <cassert>
128129
#include <iterator>
@@ -228,6 +229,9 @@ class MergeFunctions {
228229
/// analyzed again.
229230
std::vector<WeakTrackingVH> Deferred;
230231

232+
/// Set of values marked as used in llvm.used and llvm.compiler.used.
233+
SmallPtrSet<GlobalValue *, 4> Used;
234+
231235
#ifndef NDEBUG
232236
/// Checks the rules of order relation introduced among functions set.
233237
/// Returns true, if sanity check has been passed, and false if failed.
@@ -410,6 +414,11 @@ static bool isEligibleForMerging(Function &F) {
410414
bool MergeFunctions::runOnModule(Module &M) {
411415
bool Changed = false;
412416

417+
SmallVector<GlobalValue *, 4> UsedV;
418+
collectUsedGlobalVariables(M, UsedV, /*CompilerUsed=*/false);
419+
collectUsedGlobalVariables(M, UsedV, /*CompilerUsed=*/true);
420+
Used.insert(UsedV.begin(), UsedV.end());
421+
413422
// All functions in the module, ordered by hash. Functions with a unique
414423
// hash value are easily eliminated.
415424
std::vector<std::pair<FunctionComparator::FunctionHash, Function *>>
@@ -456,6 +465,7 @@ bool MergeFunctions::runOnModule(Module &M) {
456465
FnTree.clear();
457466
FNodesInTree.clear();
458467
GlobalNumbers.clear();
468+
Used.clear();
459469

460470
return Changed;
461471
}
@@ -828,7 +838,10 @@ void MergeFunctions::mergeTwoFunctions(Function *F, Function *G) {
828838
// For better debugability, under MergeFunctionsPDI, we do not modify G's
829839
// call sites to point to F even when within the same translation unit.
830840
if (!G->isInterposable() && !MergeFunctionsPDI) {
831-
if (G->hasGlobalUnnamedAddr()) {
841+
// Functions referred to by llvm.used/llvm.compiler.used are special:
842+
// there are uses of the symbol name that are not visible to LLVM,
843+
// usually from inline asm.
844+
if (G->hasGlobalUnnamedAddr() && !Used.contains(G)) {
832845
// G might have been a key in our GlobalNumberState, and it's illegal
833846
// to replace a key in ValueMap<GlobalValue *> with a non-global.
834847
GlobalNumbers.erase(G);
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
; RUN: opt -S -mergefunc < %s | FileCheck %s
2+
3+
@llvm.compiler.used = appending global [1 x i8*] [i8* bitcast (i32 (i32)* @a to i8*)], section "llvm.metadata"
4+
5+
define internal i32 @a(i32 %a) unnamed_addr {
6+
%b = xor i32 %a, 0
7+
%c = xor i32 %b, 0
8+
ret i32 %c
9+
}
10+
11+
define i32 @b(i32 %a) unnamed_addr {
12+
%b = xor i32 %a, 0
13+
%c = xor i32 %b, 0
14+
ret i32 %c
15+
}
16+
17+
define i32 @c(i32 %a) unnamed_addr {
18+
%b = tail call i32 @a(i32 %a)
19+
ret i32 %b
20+
}
21+
22+
; CHECK-LABEL: @llvm.compiler.used = appending global [1 x i8*] [i8* bitcast (i32 (i32)* @a to i8*)], section "llvm.metadata"
23+
24+
; CHECK-LABEL: define i32 @b(i32 %a) unnamed_addr
25+
; CHECK-NEXT: xor
26+
; CHECK-NEXT: xor
27+
; CHECK-NEXT: ret
28+
29+
; CHECK-LABEL: define i32 @c(i32 %a) unnamed_addr
30+
; CHECK-NEXT: tail call i32 @b(i32 %a)
31+
; CHECK-NEXT: ret
32+
33+
; CHECK-LABEL: define internal i32 @a(i32 %0) unnamed_addr
34+
; CHECK-NEXT: tail call i32 @b(i32 %0)
35+
; CHECK-NEXT: ret

0 commit comments

Comments
 (0)