mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-12-02 16:36:40 +00:00
[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:
parent
a22145584e
commit
c0dcf88967
@ -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;
|
||||
}
|
||||
|
69
test/LTO/X86/libcall-overridden-via-alias.ll
Executable file
69
test/LTO/X86/libcall-overridden-via-alias.ll
Executable 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
|
||||
}
|
Loading…
Reference in New Issue
Block a user