Skip to content

Commit

Permalink
[MergeFunctions] Preserve symbols used llvm.used/llvm.compiler.used
Browse files Browse the repository at this point in the history
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
  • Loading branch information
Amanieu committed Jun 16, 2022
1 parent decb600 commit caa2a82
Show file tree
Hide file tree
Showing 2 changed files with 49 additions and 1 deletion.
15 changes: 14 additions & 1 deletion llvm/lib/Transforms/IPO/MergeFunctions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 <algorithm>
#include <cassert>
#include <iterator>
Expand Down Expand Up @@ -225,6 +226,9 @@ class MergeFunctions {
/// analyzed again.
std::vector<WeakTrackingVH> Deferred;

/// Set of values marked as used in llvm.used and llvm.compiler.used.
SmallPtrSet<GlobalValue *, 4> Used;

#ifndef NDEBUG
/// Checks the rules of order relation introduced among functions set.
/// Returns true, if check has been passed, and false if failed.
Expand Down Expand Up @@ -407,6 +411,11 @@ static bool isEligibleForMerging(Function &F) {
bool MergeFunctions::runOnModule(Module &M) {
bool Changed = false;

SmallVector<GlobalValue *, 4> 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<std::pair<FunctionComparator::FunctionHash, Function *>>
Expand Down Expand Up @@ -453,6 +462,7 @@ bool MergeFunctions::runOnModule(Module &M) {
FnTree.clear();
FNodesInTree.clear();
GlobalNumbers.clear();
Used.clear();

return Changed;
}
Expand Down Expand Up @@ -825,7 +835,10 @@ void MergeFunctions::mergeTwoFunctions(Function *F, Function *G) {
// 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<GlobalValue *> with a non-global.
GlobalNumbers.erase(G);
Expand Down
35 changes: 35 additions & 0 deletions llvm/test/Transforms/MergeFunc/merge-used.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
; 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
}

define i32 @c(i32 %a) unnamed_addr {
%b = tail call i32 @a(i32 %a)
ret i32 %b
}

; 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 i32 @c(i32 %a) unnamed_addr
; CHECK-NEXT: tail call i32 @b(i32 %a)
; CHECK-NEXT: ret

; CHECK-LABEL: define internal i32 @a(i32 %0) unnamed_addr
; CHECK-NEXT: tail call i32 @b(i32 %0)
; CHECK-NEXT: ret

0 comments on commit caa2a82

Please sign in to comment.