[llvm] [ThinLTO] Don't mark calloc function dead (PR #72673)
via llvm-commits
llvm-commits at lists.llvm.org
Mon Nov 20 01:22:14 PST 2023
https://github.com/eleviant updated https://github.com/llvm/llvm-project/pull/72673
>From 75d63776b1e1409fb2305becea7448bff55b623f Mon Sep 17 00:00:00 2001
From: Evgeny Leviant <eleviant at accesssoftek.com>
Date: Fri, 17 Nov 2023 15:32:24 +0300
Subject: [PATCH] [ThinLTO] Don't mark calloc function dead
Dead store elimination pass may fold malloc + memset calls into a
single call to calloc. If calloc is not preserved and is not being
called directly it can be marked dead during thin link and result
in link error.
---
llvm/lib/LTO/LTO.cpp | 8 ++++-
llvm/test/ThinLTO/X86/Inputs/calloc.ll | 25 ++++++++++++++++
llvm/test/ThinLTO/X86/Inputs/operator-new.ll | 11 +++++++
llvm/test/ThinLTO/X86/call-calloc.ll | 31 ++++++++++++++++++++
4 files changed, 74 insertions(+), 1 deletion(-)
create mode 100644 llvm/test/ThinLTO/X86/Inputs/calloc.ll
create mode 100644 llvm/test/ThinLTO/X86/Inputs/operator-new.ll
create mode 100644 llvm/test/ThinLTO/X86/call-calloc.ll
diff --git a/llvm/lib/LTO/LTO.cpp b/llvm/lib/LTO/LTO.cpp
index e111e09681178e2..8614f1c9bbcd680 100644
--- a/llvm/lib/LTO/LTO.cpp
+++ b/llvm/lib/LTO/LTO.cpp
@@ -606,6 +606,8 @@ void LTO::addModuleToGlobalRes(ArrayRef<InputFile::Symbol> Syms,
auto *ResE = Res.end();
(void)ResE;
const Triple TT(RegularLTO.CombinedModule->getTargetTriple());
+ TargetLibraryInfoImpl TLII(TT);
+ StringRef CallocName = TargetLibraryInfo(TLII).getName(LibFunc_calloc);
for (const InputFile::Symbol &Sym : Syms) {
assert(ResI != ResE);
SymbolResolution Res = *ResI++;
@@ -644,7 +646,11 @@ void LTO::addModuleToGlobalRes(ArrayRef<InputFile::Symbol> Syms,
// FIXME: instead of this check, it would be desirable to compute GUIDs
// based on mangled name, but this requires an access to the Target Triple
// and would be relatively invasive on the codebase.
- if (GlobalRes.IRName != Sym.getIRName()) {
+ if ((GlobalRes.IRName != Sym.getIRName()) ||
+ // The dead store elimination pass can fold malloc + memset calls into
+ // a single call to calloc. Prevent thin LTO from marking calloc a dead
+ // function otherwise we may face link errors.
+ (!CallocName.empty() && GlobalRes.IRName == CallocName)) {
GlobalRes.Partition = GlobalResolution::External;
GlobalRes.VisibleOutsideSummary = true;
}
diff --git a/llvm/test/ThinLTO/X86/Inputs/calloc.ll b/llvm/test/ThinLTO/X86/Inputs/calloc.ll
new file mode 100644
index 000000000000000..8a9d5015875176f
--- /dev/null
+++ b/llvm/test/ThinLTO/X86/Inputs/calloc.ll
@@ -0,0 +1,25 @@
+target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+ at _ZZ6mallocE3buf = internal global [2000 x i8] zeroinitializer, align 1
+
+define hidden ptr @malloc(i64 %a) {
+entry:
+ ret ptr @_ZZ6mallocE3buf
+}
+
+define hidden void @free(ptr %p) {
+entry:
+ ret void
+}
+
+define hidden ptr @calloc(i64 noundef %num, i64 noundef %size) {
+entry:
+ %mul = mul i64 %size, %num
+ %call = tail call noalias ptr @malloc(i64 poison)
+ tail call void @llvm.memset.p0.i64(ptr nonnull align 1 @_ZZ6mallocE3buf, i8 0, i64 %mul, i1 false)
+ ret ptr @_ZZ6mallocE3buf
+}
+
+declare void @llvm.memset.p0.i64(ptr nocapture writeonly, i8, i64, i1 immarg)
+
diff --git a/llvm/test/ThinLTO/X86/Inputs/operator-new.ll b/llvm/test/ThinLTO/X86/Inputs/operator-new.ll
new file mode 100644
index 000000000000000..b3e54d70ad3fee8
--- /dev/null
+++ b/llvm/test/ThinLTO/X86/Inputs/operator-new.ll
@@ -0,0 +1,11 @@
+target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+declare ptr @malloc(i64)
+
+define ptr @_ZnwmRKSt9nothrow_t(i64 %size, ptr %0) {
+entry:
+ %call = tail call noalias ptr @malloc(i64 %size)
+ ret ptr %call
+}
+
diff --git a/llvm/test/ThinLTO/X86/call-calloc.ll b/llvm/test/ThinLTO/X86/call-calloc.ll
new file mode 100644
index 000000000000000..7f42004ab4694d2
--- /dev/null
+++ b/llvm/test/ThinLTO/X86/call-calloc.ll
@@ -0,0 +1,31 @@
+; RUN: opt -module-summary %s -o %t1.bc
+; RUN: opt -module-summary %p/Inputs/calloc.ll -o %t2.bc
+; RUN: opt -module-summary %p/Inputs/operator-new.ll -o %t3.bc
+; RUN: llvm-lto2 run -save-temps -o %t.out \
+; RUN: %t1.bc -r=%t1.bc,_Z7DoStuffv,px -r=%t1.bc,_ZnwmRKSt9nothrow_t,l \
+; RUN: -r=%t1.bc,_ZSt7nothrow \
+; RUN: %t2.bc -r=%t2.bc,malloc,pl -r=%t2.bc,free,pl -r=%t2.bc,calloc,pl \
+; RUN: %t3.bc -r=%t3.bc,_ZnwmRKSt9nothrow_t,px -r=%t3.bc,malloc,l
+; RUN: llvm-dis %t.out.2.5.precodegen.bc -o - | FileCheck %s
+
+; CHECK: define {{.*}} @calloc
+
+target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+%"struct.std::nothrow_t" = type { i8 }
+
+ at _ZSt7nothrow = external global %"struct.std::nothrow_t", align 1
+
+declare ptr @_ZnwmRKSt9nothrow_t(i64, ptr)
+
+define void @_Z7DoStuffv() {
+entry:
+ %call = tail call ptr @_ZnwmRKSt9nothrow_t(i64 400, ptr @_ZSt7nothrow)
+ %new.isnull = icmp ne ptr %call, null
+ tail call void @llvm.memset.p0.i64(ptr %call, i8 0, i64 400, i1 false)
+ ret void
+}
+
+declare void @llvm.memset.p0.i64(ptr nocapture writeonly, i8, i64, i1 immarg)
+
More information about the llvm-commits
mailing list