[llvm] [TLI] Add support for inferring attr `cold` on `exit`/`abort` (PR #101003)
via llvm-commits
llvm-commits at lists.llvm.org
Mon Jul 29 05:46:08 PDT 2024
https://github.com/goldsteinn updated https://github.com/llvm/llvm-project/pull/101003
>From f5d2444e9fdfb1543d3977724e049f9894a46df1 Mon Sep 17 00:00:00 2001
From: Noah Goldstein <goldstein.w.n at gmail.com>
Date: Mon, 29 Jul 2024 20:02:54 +0800
Subject: [PATCH 1/3] [InstCombine][InferFunctionAttrs] Add tests for inferring
`cold` on exit/abort; NFC
---
.../Transforms/InferFunctionAttrs/annotate.ll | 2 +
.../Transforms/InstCombine/lib-call-exit.ll | 42 +++++++++++++++++++
2 files changed, 44 insertions(+)
create mode 100644 llvm/test/Transforms/InstCombine/lib-call-exit.ll
diff --git a/llvm/test/Transforms/InferFunctionAttrs/annotate.ll b/llvm/test/Transforms/InferFunctionAttrs/annotate.ll
index 79962b45d253a..9a5b902210009 100644
--- a/llvm/test/Transforms/InferFunctionAttrs/annotate.ll
+++ b/llvm/test/Transforms/InferFunctionAttrs/annotate.ll
@@ -1088,6 +1088,8 @@ declare i32 @vsscanf(ptr, ptr, ptr)
; CHECK: declare noundef i64 @write(i32 noundef, ptr nocapture noundef readonly, i64 noundef) [[NOFREE]]
declare i64 @write(i32, ptr, i64)
+; CHECK: declare void @abort()
+declare void @abort()
; memset_pattern{4,8,16} aren't available everywhere.
; CHECK-DARWIN: declare void @memset_pattern4(ptr nocapture writeonly, ptr nocapture readonly, i64) [[ARGMEMONLY_NOFREE_NOUNWIND_WILLRETURN]]
diff --git a/llvm/test/Transforms/InstCombine/lib-call-exit.ll b/llvm/test/Transforms/InstCombine/lib-call-exit.ll
new file mode 100644
index 0000000000000..7f1f7f4208899
--- /dev/null
+++ b/llvm/test/Transforms/InstCombine/lib-call-exit.ll
@@ -0,0 +1,42 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5
+; RUN: opt < %s -passes=instcombine -S | FileCheck %s
+
+declare void @exit(i32)
+declare void @_Exit(i32)
+
+define void @call_exit_0() {
+; CHECK-LABEL: define void @call_exit_0() {
+; CHECK-NEXT: call void @exit(i32 0)
+; CHECK-NEXT: ret void
+;
+ call void @exit(i32 0)
+ ret void
+}
+
+define void @call_exit_1() {
+; CHECK-LABEL: define void @call_exit_1() {
+; CHECK-NEXT: call void @exit(i32 1)
+; CHECK-NEXT: ret void
+;
+ call void @exit(i32 1)
+ ret void
+}
+
+define void @call__Exit_m1() {
+; CHECK-LABEL: define void @call__Exit_m1() {
+; CHECK-NEXT: call void @_Exit(i32 -1)
+; CHECK-NEXT: ret void
+;
+ call void @_Exit(i32 -1)
+ ret void
+}
+
+define void @call__Exit_N(i32 %N) {
+; CHECK-LABEL: define void @call__Exit_N(
+; CHECK-SAME: i32 [[N:%.*]]) {
+; CHECK-NEXT: call void @_Exit(i32 [[N]])
+; CHECK-NEXT: ret void
+;
+ call void @_Exit(i32 %N)
+ ret void
+}
>From 79b06fb228136ec917d2b5bab40deeee030ff0db Mon Sep 17 00:00:00 2001
From: Noah Goldstein <goldstein.w.n at gmail.com>
Date: Mon, 29 Jul 2024 20:02:28 +0800
Subject: [PATCH 2/3] [TLI] Add support for inferring attr `cold` on
`exit`/`abort`
`abort` can be assumed always cold and assume non-zero `exit` status
as a `cold` path as well.
---
.../llvm/Analysis/TargetLibraryInfo.def | 15 ++++++++++++++
.../llvm/Transforms/Utils/SimplifyLibCalls.h | 3 +++
llvm/lib/Transforms/Utils/BuildLibCalls.cpp | 12 +++++++++++
.../lib/Transforms/Utils/SimplifyLibCalls.cpp | 14 +++++++++++++
.../Transforms/InferFunctionAttrs/annotate.ll | 3 ++-
.../Transforms/InstCombine/lib-call-exit.ll | 4 ++--
.../tools/llvm-tli-checker/ps4-tli-check.yaml | 20 +++++++++++++++----
.../Analysis/TargetLibraryInfoTest.cpp | 6 +++++-
8 files changed, 69 insertions(+), 8 deletions(-)
diff --git a/llvm/include/llvm/Analysis/TargetLibraryInfo.def b/llvm/include/llvm/Analysis/TargetLibraryInfo.def
index 623cdb4b6e0b7..e9f3b7fcd99eb 100644
--- a/llvm/include/llvm/Analysis/TargetLibraryInfo.def
+++ b/llvm/include/llvm/Analysis/TargetLibraryInfo.def
@@ -476,6 +476,21 @@ TLI_DEFINE_ENUM_INTERNAL(atexit)
TLI_DEFINE_STRING_INTERNAL("atexit")
TLI_DEFINE_SIG_INTERNAL(Int, Ptr)
+/// void abort(void)
+TLI_DEFINE_ENUM_INTERNAL(abort)
+TLI_DEFINE_STRING_INTERNAL("abort")
+TLI_DEFINE_SIG_INTERNAL(Void)
+
+/// void exit(int)
+TLI_DEFINE_ENUM_INTERNAL(exit)
+TLI_DEFINE_STRING_INTERNAL("exit")
+TLI_DEFINE_SIG_INTERNAL(Void, Int)
+
+/// void _Exit(int)
+TLI_DEFINE_ENUM_INTERNAL(Exit)
+TLI_DEFINE_STRING_INTERNAL("_Exit")
+TLI_DEFINE_SIG_INTERNAL(Void, Int)
+
/// void __cxa_guard_abort(guard_t *guard);
/// guard_t is int64_t in Itanium ABI or int32_t on ARM eabi.
TLI_DEFINE_ENUM_INTERNAL(cxa_guard_abort)
diff --git a/llvm/include/llvm/Transforms/Utils/SimplifyLibCalls.h b/llvm/include/llvm/Transforms/Utils/SimplifyLibCalls.h
index 770da12e01233..43b5c9250a890 100644
--- a/llvm/include/llvm/Transforms/Utils/SimplifyLibCalls.h
+++ b/llvm/include/llvm/Transforms/Utils/SimplifyLibCalls.h
@@ -245,6 +245,9 @@ class LibCallSimplifier {
Value *optimizeSnPrintFString(CallInst *CI, IRBuilderBase &B);
Value *optimizeFPrintFString(CallInst *CI, IRBuilderBase &B);
+ /// Exit functions
+ Value *optimizeExit(CallInst *CI);
+
/// hasFloatVersion - Checks if there is a float version of the specified
/// function by checking for an existing function with name FuncName + f
bool hasFloatVersion(const Module *M, StringRef FuncName);
diff --git a/llvm/lib/Transforms/Utils/BuildLibCalls.cpp b/llvm/lib/Transforms/Utils/BuildLibCalls.cpp
index 0c45bd886af9d..898e5b0f41812 100644
--- a/llvm/lib/Transforms/Utils/BuildLibCalls.cpp
+++ b/llvm/lib/Transforms/Utils/BuildLibCalls.cpp
@@ -48,6 +48,7 @@ STATISTIC(NumNoAlias, "Number of function returns inferred as noalias");
STATISTIC(NumNoUndef, "Number of function returns inferred as noundef returns");
STATISTIC(NumReturnedArg, "Number of arguments inferred as returned");
STATISTIC(NumWillReturn, "Number of functions inferred as willreturn");
+STATISTIC(NumCold, "Number of functions inferred as cold");
static bool setDoesNotAccessMemory(Function &F) {
if (F.doesNotAccessMemory())
@@ -57,6 +58,14 @@ static bool setDoesNotAccessMemory(Function &F) {
return true;
}
+static bool setIsCold(Function &F) {
+ if (F.hasFnAttribute(Attribute::Cold))
+ return false;
+ F.addFnAttr(Attribute::Cold);
+ ++NumCold;
+ return true;
+}
+
static bool setOnlyAccessesInaccessibleMemory(Function &F) {
if (F.onlyAccessesInaccessibleMemory())
return false;
@@ -1087,6 +1096,9 @@ bool llvm::inferNonMandatoryLibFuncAttrs(Function &F,
Changed |= setOnlyWritesMemory(F, 0);
Changed |= setDoesNotThrow(F);
break;
+ case LibFunc_abort:
+ Changed |= setIsCold(F);
+ break;
// int __nvvm_reflect(const char *)
case LibFunc_nvvm_reflect:
Changed |= setRetAndArgsNoUndef(F);
diff --git a/llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp b/llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp
index 92c44265ce8b6..4100471eaaa1d 100644
--- a/llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp
+++ b/llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp
@@ -3729,6 +3729,17 @@ Value *LibCallSimplifier::optimizePuts(CallInst *CI, IRBuilderBase &B) {
return nullptr;
}
+Value *LibCallSimplifier::optimizeExit(CallInst *CI) {
+
+ // Mark 'exit' as cold if its not exit(0) (success).
+ const APInt *C;
+ if (!CI->hasFnAttr(Attribute::Cold) &&
+ match(CI->getArgOperand(0), m_APInt(C)) && !C->isZero()) {
+ CI->addFnAttr(Attribute::Cold);
+ }
+ return nullptr;
+}
+
Value *LibCallSimplifier::optimizeBCopy(CallInst *CI, IRBuilderBase &B) {
// bcopy(src, dst, n) -> llvm.memmove(dst, src, n)
return copyFlags(*CI, B.CreateMemMove(CI->getArgOperand(1), Align(1),
@@ -4084,6 +4095,9 @@ Value *LibCallSimplifier::optimizeCall(CallInst *CI, IRBuilderBase &Builder) {
case LibFunc_vfprintf:
case LibFunc_fiprintf:
return optimizeErrorReporting(CI, Builder, 0);
+ case LibFunc_exit:
+ case LibFunc_Exit:
+ return optimizeExit(CI);
default:
return nullptr;
}
diff --git a/llvm/test/Transforms/InferFunctionAttrs/annotate.ll b/llvm/test/Transforms/InferFunctionAttrs/annotate.ll
index 9a5b902210009..d54290fd3869c 100644
--- a/llvm/test/Transforms/InferFunctionAttrs/annotate.ll
+++ b/llvm/test/Transforms/InferFunctionAttrs/annotate.ll
@@ -1088,7 +1088,7 @@ declare i32 @vsscanf(ptr, ptr, ptr)
; CHECK: declare noundef i64 @write(i32 noundef, ptr nocapture noundef readonly, i64 noundef) [[NOFREE]]
declare i64 @write(i32, ptr, i64)
-; CHECK: declare void @abort()
+; CHECK: declare void @abort() [[NOFREE_COLD:#[0-9]+]]
declare void @abort()
; memset_pattern{4,8,16} aren't available everywhere.
@@ -1116,6 +1116,7 @@ declare void @memset_pattern16(ptr, ptr, i64)
; CHECK-DAG: attributes [[ARGMEMONLY_NOFREE_NOUNWIND]] = { nofree nounwind memory(argmem: readwrite) }
; CHECK-DAG: attributes [[INACCESSIBLEMEMORARGMEMONLY_NOUNWIND_WILLRETURN_ALLOCKIND_REALLOC_ALLOCSIZE1_FAMILY_MALLOC]] = { mustprogress nounwind willreturn allockind("realloc") allocsize(1) memory(argmem: readwrite, inaccessiblemem: readwrite) "alloc-family"="malloc" }
; CHECK-DAG: attributes [[INACCESSIBLEMEMORARGONLY_NOFREE_NOUNWIND_WILLRETURN_FAMILY_MALLOC]] = { mustprogress nofree nounwind willreturn memory(argmem: readwrite, inaccessiblemem: readwrite) "alloc-family"="malloc" }
+; CHECK-DAG: attributes [[NOFREE_COLD]] = { cold nofree }
; CHECK-NVPTX-DAG: attributes [[NOFREE_NOUNWIND_READNONE]] = { nofree nosync nounwind memory(none) }
diff --git a/llvm/test/Transforms/InstCombine/lib-call-exit.ll b/llvm/test/Transforms/InstCombine/lib-call-exit.ll
index 7f1f7f4208899..d6c5ec8979df4 100644
--- a/llvm/test/Transforms/InstCombine/lib-call-exit.ll
+++ b/llvm/test/Transforms/InstCombine/lib-call-exit.ll
@@ -15,7 +15,7 @@ define void @call_exit_0() {
define void @call_exit_1() {
; CHECK-LABEL: define void @call_exit_1() {
-; CHECK-NEXT: call void @exit(i32 1)
+; CHECK-NEXT: call void @exit(i32 1) #[[ATTR0:[0-9]+]]
; CHECK-NEXT: ret void
;
call void @exit(i32 1)
@@ -24,7 +24,7 @@ define void @call_exit_1() {
define void @call__Exit_m1() {
; CHECK-LABEL: define void @call__Exit_m1() {
-; CHECK-NEXT: call void @_Exit(i32 -1)
+; CHECK-NEXT: call void @_Exit(i32 -1) #[[ATTR0]]
; CHECK-NEXT: ret void
;
call void @_Exit(i32 -1)
diff --git a/llvm/test/tools/llvm-tli-checker/ps4-tli-check.yaml b/llvm/test/tools/llvm-tli-checker/ps4-tli-check.yaml
index 5840e024e9786..19e18e09b76d0 100644
--- a/llvm/test/tools/llvm-tli-checker/ps4-tli-check.yaml
+++ b/llvm/test/tools/llvm-tli-checker/ps4-tli-check.yaml
@@ -34,21 +34,21 @@
#
# CHECK: << Total TLI yes SDK no: 8
# CHECK: >> Total TLI no SDK yes: 0
-# CHECK: == Total TLI yes SDK yes: 242
+# CHECK: == Total TLI yes SDK yes: 245
#
# WRONG_DETAIL: << TLI yes SDK no : '_ZdaPv' aka operator delete[](void*)
# WRONG_DETAIL: >> TLI no SDK yes: '_ZdaPvj' aka operator delete[](void*, unsigned int)
# WRONG_DETAIL-COUNT-8: << TLI yes SDK no : {{.*}}__hot_cold_t
# WRONG_SUMMARY: << Total TLI yes SDK no: 9{{$}}
# WRONG_SUMMARY: >> Total TLI no SDK yes: 1{{$}}
-# WRONG_SUMMARY: == Total TLI yes SDK yes: 241
+# WRONG_SUMMARY: == Total TLI yes SDK yes: 244
#
## The -COUNT suffix doesn't care if there are too many matches, so check
## the exact count first; the two directives should add up to that.
## Yes, this means additions to TLI will fail this test, but the argument
## to -COUNT can't be an expression.
-# AVAIL: TLI knows 483 symbols, 250 available
-# AVAIL-COUNT-250: {{^}} available
+# AVAIL: TLI knows 486 symbols, 253 available
+# AVAIL-COUNT-253: {{^}} available
# AVAIL-NOT: {{^}} available
# UNAVAIL-COUNT-233: not available
# UNAVAIL-NOT: not available
@@ -267,6 +267,18 @@ DynamicSymbols:
Type: STT_FUNC
Section: .text
Binding: STB_GLOBAL
+ - Name: abort
+ Type: STT_FUNC
+ Section: .text
+ Binding: STB_GLOBAL
+ - Name: exit
+ Type: STT_FUNC
+ Section: .text
+ Binding: STB_GLOBAL
+ - Name: _Exit
+ Type: STT_FUNC
+ Section: .text
+ Binding: STB_GLOBAL
- Name: atof
Type: STT_FUNC
Section: .text
diff --git a/llvm/unittests/Analysis/TargetLibraryInfoTest.cpp b/llvm/unittests/Analysis/TargetLibraryInfoTest.cpp
index 1447291844dd2..b8125b099343b 100644
--- a/llvm/unittests/Analysis/TargetLibraryInfoTest.cpp
+++ b/llvm/unittests/Analysis/TargetLibraryInfoTest.cpp
@@ -500,6 +500,10 @@ TEST_F(TargetLibraryInfoTest, ValidProto) {
"declare i32 @atexit(void ()*)\n"
+ "declare void @abort()\n"
+ "declare void @exit(i32)\n"
+ "declare void @_Exit(i32)\n"
+
"declare i32 @__nvvm_reflect(i8*)\n"
"declare i8* @__memcpy_chk(i8*, i8*, i64, i64)\n"
@@ -663,4 +667,4 @@ class TLITestAarch64 : public ::testing::Test {
TEST_F(TLITestAarch64, TestFrem) {
EXPECT_EQ(getScalarName(Instruction::FRem, Type::getDoubleTy(Ctx)), "fmod");
EXPECT_EQ(getScalarName(Instruction::FRem, Type::getFloatTy(Ctx)), "fmodf");
-}
\ No newline at end of file
+}
>From 0158f7eadef431fc3c53ac6f8c6f642f4635df93 Mon Sep 17 00:00:00 2001
From: Noah Goldstein <goldstein.w.n at gmail.com>
Date: Mon, 29 Jul 2024 20:45:42 +0800
Subject: [PATCH 3/3] fixup tests
---
llvm/test/Transforms/InstCombine/lib-call-exit.ll | 2 ++
1 file changed, 2 insertions(+)
diff --git a/llvm/test/Transforms/InstCombine/lib-call-exit.ll b/llvm/test/Transforms/InstCombine/lib-call-exit.ll
index d6c5ec8979df4..786eab09c092a 100644
--- a/llvm/test/Transforms/InstCombine/lib-call-exit.ll
+++ b/llvm/test/Transforms/InstCombine/lib-call-exit.ll
@@ -40,3 +40,5 @@ define void @call__Exit_N(i32 %N) {
call void @_Exit(i32 %N)
ret void
}
+
+; CHECK: attributes #[[ATTR0:[0-9]+]] = { cold }
More information about the llvm-commits
mailing list