[LTO] Account for overriding lib calls via the alias attribute

Given a library call that is represented as an llvm intrinsic call, but
later transformed to an actual call, if an overriding definition of that
library routine is provided indirectly via an alias, prevent LTO from
eliminating the definition.

This is a fix for PR38547.

Differential Revision: https://reviews.llvm.org/D52836

llvm-svn: 344198
This commit is contained in:
Warren Ristow 2018-10-10 22:54:31 +00:00
parent a22145584e
commit c0dcf88967
2 changed files with 80 additions and 5 deletions

View File

@ -95,12 +95,18 @@ private:
if (GV.hasPrivateLinkage())
return;
// Conservatively append user-supplied runtime library functions to
// llvm.compiler.used. These could be internalized and deleted by
// optimizations like -globalopt, causing problems when later optimizations
// add new library calls (e.g., llvm.memset => memset and printf => puts).
// Conservatively append user-supplied runtime library functions (supplied
// either directly, or via a function alias) to llvm.compiler.used. These
// could be internalized and deleted by optimizations like -globalopt,
// causing problems when later optimizations add new library calls (e.g.,
// llvm.memset => memset and printf => puts).
// Leave it to the linker to remove any dead code (e.g. with -dead_strip).
if (isa<Function>(GV) && Libcalls.count(GV.getName())) {
GlobalValue *FuncAliasee = nullptr;
if (isa<GlobalAlias>(GV)) {
auto *A = cast<GlobalAlias>(&GV);
FuncAliasee = dyn_cast<Function>(A->getAliasee());
}
if ((isa<Function>(GV) || FuncAliasee) && Libcalls.count(GV.getName())) {
LLVMUsed.push_back(&GV);
return;
}

View File

@ -0,0 +1,69 @@
; Given a library call that is represented as an llvm intrinsic call, but
; later transformed to an actual call, if an overriding definition of that
; library routine is provided indirectly via an alias, verify that LTO
; does not eliminate the definition. This is a test for PR38547.
;
; RUN: llvm-as -o %t1 %s
; RUN: llvm-lto -exported-symbol=main -save-merged-module -filetype=asm -o %t2 %t1
; RUN: llvm-dis -o - %t2.merged.bc | FileCheck --check-prefix=CHECK_IR %s
;
; Check that the call is represented as an llvm intrinsic in the IR after LTO:
; CHECK_IR-LABEL: main
; CHECK_IR: call float @llvm.log.f32
;
; Check that the IR contains the overriding definition of the library routine
; in the IR after LTO:
; CHECK_IR: define internal float @logf(float [[X:%.*]])
; CHECK_IR-NEXT: [[TMP:%.*]] = fadd float [[X]], [[X]]
; CHECK_IR-NEXT: ret float [[TMP]]
;
; Check that the assembly code from LTO contains the call to the expected
; library routine, and that the overriding definition of the library routine
; is present:
; RUN: FileCheck --check-prefix=CHECK_ASM %s < %t2
; CHECK_ASM-LABEL: main:
; CHECK_ASM: callq logf
; CHECK_ASM-LABEL: logf:
; CHECK_ASM-NEXT: add
; CHECK_ASM-NEXT: ret
; Produced from the following source-code:
;
;extern float logf(float);
;// 'src' and 'dst' are 'volatile' to prohibit optimization.
;volatile float src = 3.14f;
;volatile float dst;
;
;int main() {
; dst = logf(src);
; return 0;
;}
;
;extern float fname(float x);
;float fname(float x) {
; return x + x;
;}
;
;float logf(float x) __attribute__((alias("fname")));
;
target triple = "x86_64-unknown-linux-gnu"
@src = global float 0x40091EB860000000, align 4
@dst = common global float 0.000000e+00, align 4
@logf = alias float (float), float (float)* @fname
define i32 @main() local_unnamed_addr {
entry:
%0 = load volatile float, float* @src, align 4
%1 = tail call float @llvm.log.f32(float %0)
store volatile float %1, float* @dst, align 4
ret i32 0
}
declare float @llvm.log.f32(float)
define float @fname(float %x) {
%add = fadd float %x, %x
ret float %add
}