[llvm] [ThinLTO] Don't mark calloc function dead (PR #72673)

via llvm-commits llvm-commits at lists.llvm.org
Tue Nov 28 11:40:07 PST 2023


https://github.com/eleviant updated https://github.com/llvm/llvm-project/pull/72673

>From 08598a66ebee7058306454b0b9033e7dcfc1d6c2 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/include/llvm/IR/RuntimeLibcalls.def |  2 ++
 llvm/test/ThinLTO/X86/Inputs/calloc.ll   | 21 +++++++++++++
 llvm/test/ThinLTO/X86/call-calloc.ll     | 39 ++++++++++++++++++++++++
 3 files changed, 62 insertions(+)
 create mode 100644 llvm/test/ThinLTO/X86/Inputs/calloc.ll
 create mode 100644 llvm/test/ThinLTO/X86/call-calloc.ll

diff --git a/llvm/include/llvm/IR/RuntimeLibcalls.def b/llvm/include/llvm/IR/RuntimeLibcalls.def
index 6ec98e278988428..19dea60bebf9be5 100644
--- a/llvm/include/llvm/IR/RuntimeLibcalls.def
+++ b/llvm/include/llvm/IR/RuntimeLibcalls.def
@@ -438,6 +438,8 @@ HANDLE_LIBCALL(UO_PPCF128, "__gcc_qunord")
 HANDLE_LIBCALL(MEMCPY, "memcpy")
 HANDLE_LIBCALL(MEMMOVE, "memmove")
 HANDLE_LIBCALL(MEMSET, "memset")
+// DSEPass can emit calloc if it finds a pair of malloc/memset
+HANDLE_LIBCALL(CALLOC, "calloc")
 HANDLE_LIBCALL(BZERO, nullptr)
 
 // Element-wise unordered-atomic memory of different sizes
diff --git a/llvm/test/ThinLTO/X86/Inputs/calloc.ll b/llvm/test/ThinLTO/X86/Inputs/calloc.ll
new file mode 100644
index 000000000000000..247f7170f706b52
--- /dev/null
+++ b/llvm/test/ThinLTO/X86/Inputs/calloc.ll
@@ -0,0 +1,21 @@
+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) #0 {
+entry:
+  ret ptr @_ZZ6mallocE3buf
+}
+
+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 %call, i8 0, i64 %mul, i1 false)
+  ret ptr @_ZZ6mallocE3buf
+}
+
+declare void @llvm.memset.p0.i64(ptr nocapture writeonly, i8, i64, i1 immarg)
+
+attributes #0 = { noinline }
diff --git a/llvm/test/ThinLTO/X86/call-calloc.ll b/llvm/test/ThinLTO/X86/call-calloc.ll
new file mode 100644
index 000000000000000..f5145e81d9d468f
--- /dev/null
+++ b/llvm/test/ThinLTO/X86/call-calloc.ll
@@ -0,0 +1,39 @@
+; REQUIRES: x86-registered-target
+; Checks that calloc function is not stripped by LTO DCE, otherwise
+; we may get into trouble during final link in case DSEPass folds
+; subsequent calls to malloc/memset into a single call to calloc.
+; Also see builtin-notstrip.ll which is similar to this test.
+
+; RUN: opt -module-summary %s -o %t1.bc
+; RUN: opt -module-summary %p/Inputs/calloc.ll -o %t2.bc
+; RUN: llvm-lto2 run -save-temps -o %t.out \
+; RUN:   %t1.bc -r=%t1.bc,_Z7DoStuffv,px \
+; RUN:          -r=%t1.bc,malloc,l -r=%t1.bc,__p,px \
+; RUN:   %t2.bc -r=%t2.bc,malloc,pl -r=%t2.bc,calloc,pl
+; RUN: llvm-dis %t.out.2.5.precodegen.bc -o - | FileCheck %s --check-prefix=CALLOC-DEF
+; RUN: llvm-dis %t.out.1.5.precodegen.bc -o - | FileCheck %s --check-prefix=CALLOC-USE
+
+; CALLOC-DEF: define {{.*}} @malloc
+; CALLOC-DEF: define {{.*}} @calloc
+
+; CALLOC-USE:      define void @_Z7DoStuffv()
+; CALLOC-USE-NEXT: entry:
+; CALLOC-USE-NEXT:   tail call {{.*}} ptr @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"
+
+declare ptr @malloc(i64)
+
+ at __p = dso_local local_unnamed_addr global ptr null, align 8
+
+define void @_Z7DoStuffv() {
+entry:
+  %call = tail call noalias ptr @malloc(i64 400)
+  tail call void @llvm.memset.p0.i64(ptr %call, i8 0, i64 400, i1 false)
+  store ptr %call, ptr @__p, align 8
+  ret void
+}
+
+declare void @llvm.memset.p0.i64(ptr nocapture writeonly, i8, i64, i1 immarg)
+



More information about the llvm-commits mailing list