[llvm] [GlobalOpt] Check if users are CallBase when changing CC (PR #161399)

Hongyu Chen via llvm-commits llvm-commits at lists.llvm.org
Tue Sep 30 09:42:28 PDT 2025


https://github.com/XChy created https://github.com/llvm/llvm-project/pull/161399

Fixes https://github.com/llvm/llvm-project/issues/156656
`hasChangeableCCImpl` guarantees the address of the function is not taken, but it ignores assume-like calls.
This patch ignores assume-like calls when changing CC.

>From 421dbff4940078037fd3d959a846809486ab4203 Mon Sep 17 00:00:00 2001
From: XChy <xxs_chy at outlook.com>
Date: Wed, 1 Oct 2025 00:33:54 +0800
Subject: [PATCH 1/2] autogenerate tests

---
 llvm/test/Transforms/GlobalOpt/fastcc.ll | 73 ++++++++++++++++++------
 1 file changed, 57 insertions(+), 16 deletions(-)

diff --git a/llvm/test/Transforms/GlobalOpt/fastcc.ll b/llvm/test/Transforms/GlobalOpt/fastcc.ll
index 854357e6fad97..bca70f1c2e86f 100644
--- a/llvm/test/Transforms/GlobalOpt/fastcc.ll
+++ b/llvm/test/Transforms/GlobalOpt/fastcc.ll
@@ -1,16 +1,25 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6
 ; RUN: opt < %s -passes=globalopt -S | FileCheck %s
 
 declare token @llvm.call.preallocated.setup(i32)
 declare ptr @llvm.call.preallocated.arg(token, i32)
 
 define internal i32 @f(ptr %m) {
-; CHECK-LABEL: define internal fastcc i32 @f
+; CHECK-LABEL: define internal fastcc i32 @f(
+; CHECK-SAME: ptr [[M:%.*]]) unnamed_addr {
+; CHECK-NEXT:    [[V:%.*]] = load i32, ptr [[M]], align 4
+; CHECK-NEXT:    ret i32 [[V]]
+;
   %v = load i32, ptr %m
   ret i32 %v
 }
 
 define internal x86_thiscallcc i32 @g(ptr %m) {
-; CHECK-LABEL: define internal fastcc i32 @g
+; CHECK-LABEL: define internal fastcc i32 @g(
+; CHECK-SAME: ptr [[M:%.*]]) unnamed_addr {
+; CHECK-NEXT:    [[V:%.*]] = load i32, ptr [[M]], align 4
+; CHECK-NEXT:    ret i32 [[V]]
+;
   %v = load i32, ptr %m
   ret i32 %v
 }
@@ -18,41 +27,80 @@ define internal x86_thiscallcc i32 @g(ptr %m) {
 ; Leave this one alone, because the user went out of their way to request this
 ; convention.
 define internal coldcc i32 @h(ptr %m) {
-; CHECK-LABEL: define internal coldcc i32 @h
+; CHECK-LABEL: define internal coldcc i32 @h(
+; CHECK-SAME: ptr [[M:%.*]]) unnamed_addr {
+; CHECK-NEXT:    [[V:%.*]] = load i32, ptr [[M]], align 4
+; CHECK-NEXT:    ret i32 [[V]]
+;
   %v = load i32, ptr %m
   ret i32 %v
 }
 
 define internal i32 @j(ptr %m) {
-; CHECK-LABEL: define internal i32 @j
+; CHECK-LABEL: define internal i32 @j(
+; CHECK-SAME: ptr [[M:%.*]]) {
+; CHECK-NEXT:    [[V:%.*]] = load i32, ptr [[M]], align 4
+; CHECK-NEXT:    ret i32 [[V]]
+;
   %v = load i32, ptr %m
   ret i32 %v
 }
 
 define internal i32 @inalloca(ptr inalloca(i32) %p) {
-; CHECK-LABEL: define internal fastcc i32 @inalloca(ptr %p)
+; CHECK-LABEL: define internal fastcc i32 @inalloca(
+; CHECK-SAME: ptr [[P:%.*]]) unnamed_addr {
+; CHECK-NEXT:    [[RV:%.*]] = load i32, ptr [[P]], align 4
+; CHECK-NEXT:    ret i32 [[RV]]
+;
   %rv = load i32, ptr %p
   ret i32 %rv
 }
 
 define i32 @inalloca2_caller(ptr inalloca(i32) %p) {
+; CHECK-LABEL: define i32 @inalloca2_caller(
+; CHECK-SAME: ptr inalloca(i32) [[P:%.*]]) local_unnamed_addr {
+; CHECK-NEXT:    [[RV:%.*]] = musttail call i32 @inalloca2(ptr inalloca(i32) [[P]])
+; CHECK-NEXT:    ret i32 [[RV]]
+;
   %rv = musttail call i32 @inalloca2(ptr inalloca(i32) %p)
   ret i32 %rv
 }
 define internal i32 @inalloca2(ptr inalloca(i32) %p) {
 ; Because of the musttail caller, this inalloca cannot be dropped.
-; CHECK-LABEL: define internal i32 @inalloca2(ptr inalloca(i32) %p)
+; CHECK-LABEL: define internal i32 @inalloca2(
+; CHECK-SAME: ptr inalloca(i32) [[P:%.*]]) unnamed_addr {
+; CHECK-NEXT:    [[RV:%.*]] = load i32, ptr [[P]], align 4
+; CHECK-NEXT:    ret i32 [[RV]]
+;
   %rv = load i32, ptr %p
   ret i32 %rv
 }
 
 define internal i32 @preallocated(ptr preallocated(i32) %p) {
-; CHECK-LABEL: define internal fastcc i32 @preallocated(ptr %p)
+; CHECK-LABEL: define internal fastcc i32 @preallocated(
+; CHECK-SAME: ptr [[P:%.*]]) unnamed_addr {
+; CHECK-NEXT:    [[RV:%.*]] = load i32, ptr [[P]], align 4
+; CHECK-NEXT:    ret i32 [[RV]]
+;
   %rv = load i32, ptr %p
   ret i32 %rv
 }
 
 define void @call_things() {
+; CHECK-LABEL: define void @call_things() local_unnamed_addr {
+; CHECK-NEXT:    [[M:%.*]] = alloca i32, align 4
+; CHECK-NEXT:    [[TMP1:%.*]] = call fastcc i32 @f(ptr [[M]])
+; CHECK-NEXT:    [[TMP2:%.*]] = call fastcc i32 @g(ptr [[M]])
+; CHECK-NEXT:    [[TMP3:%.*]] = call coldcc i32 @h(ptr [[M]])
+; CHECK-NEXT:    [[TMP4:%.*]] = call i32 @j(ptr [[M]])
+; CHECK-NEXT:    [[ARGS:%.*]] = alloca inalloca i32, align 4
+; CHECK-NEXT:    [[TMP5:%.*]] = call fastcc i32 @inalloca(ptr [[ARGS]])
+; CHECK-NEXT:    [[TMP6:%.*]] = call ptr @llvm.stacksave.p0()
+; CHECK-NEXT:    [[PAARG:%.*]] = alloca i32, align 4
+; CHECK-NEXT:    [[TMP7:%.*]] = call fastcc i32 @preallocated(ptr [[PAARG]])
+; CHECK-NEXT:    call void @llvm.stackrestore.p0(ptr [[TMP6]])
+; CHECK-NEXT:    ret void
+;
   %m = alloca i32
   call i32 @f(ptr %m)
   call x86_thiscallcc i32 @g(ptr %m)
@@ -65,15 +113,8 @@ define void @call_things() {
   call i32 @preallocated(ptr preallocated(i32) %N) ["preallocated"(token %c)]
   ret void
 }
-; CHECK-LABEL: define void @call_things()
-; CHECK: call fastcc i32 @f
-; CHECK: call fastcc i32 @g
-; CHECK: call coldcc i32 @h
-; CHECK: call i32 @j
-; CHECK: call fastcc i32 @inalloca(ptr %args)
-; CHECK-NOT: llvm.call.preallocated
-; CHECK: call fastcc i32 @preallocated(ptr %paarg)
 
 @llvm.used = appending global [1 x ptr] [
-   ptr @j
+  ptr @j
 ], section "llvm.metadata"
+

>From 6baf27dc0793945cda872ff7c0bde51bbb3c771a Mon Sep 17 00:00:00 2001
From: XChy <xxs_chy at outlook.com>
Date: Wed, 1 Oct 2025 00:35:39 +0800
Subject: [PATCH 2/2] [GlobalOpt] Check if users are CallBase when changing CC

---
 llvm/lib/Transforms/IPO/GlobalOpt.cpp    | 6 ++++--
 llvm/test/Transforms/GlobalOpt/fastcc.ll | 8 ++++++++
 2 files changed, 12 insertions(+), 2 deletions(-)

diff --git a/llvm/lib/Transforms/IPO/GlobalOpt.cpp b/llvm/lib/Transforms/IPO/GlobalOpt.cpp
index f88d51f443bcf..c5a13c83ab39b 100644
--- a/llvm/lib/Transforms/IPO/GlobalOpt.cpp
+++ b/llvm/lib/Transforms/IPO/GlobalOpt.cpp
@@ -1680,7 +1680,8 @@ processGlobal(GlobalValue &GV,
 /// FastCC.
 static void ChangeCalleesToFastCall(Function *F) {
   for (User *U : F->users())
-    cast<CallBase>(U)->setCallingConv(CallingConv::Fast);
+    if (auto *Call = dyn_cast<CallBase>(U))
+      Call->setCallingConv(CallingConv::Fast);
 }
 
 static AttributeList StripAttr(LLVMContext &C, AttributeList Attrs,
@@ -1779,7 +1780,8 @@ isValidCandidateForColdCC(Function &F,
 
 static void changeCallSitesToColdCC(Function *F) {
   for (User *U : F->users())
-    cast<CallBase>(U)->setCallingConv(CallingConv::Cold);
+    if (auto *Call = dyn_cast<CallBase>(U))
+      Call->setCallingConv(CallingConv::Cold);
 }
 
 // This function iterates over all the call instructions in the input Function
diff --git a/llvm/test/Transforms/GlobalOpt/fastcc.ll b/llvm/test/Transforms/GlobalOpt/fastcc.ll
index bca70f1c2e86f..f63cf64ca2f11 100644
--- a/llvm/test/Transforms/GlobalOpt/fastcc.ll
+++ b/llvm/test/Transforms/GlobalOpt/fastcc.ll
@@ -118,3 +118,11 @@ define void @call_things() {
   ptr @j
 ], section "llvm.metadata"
 
+define internal i32 @constexpr_self_user() addrspace(1) {
+; CHECK-LABEL: define internal fastcc i32 @constexpr_self_user() addrspace(1) {
+; CHECK-NEXT:    [[OBJSIZE:%.*]] = call i32 @llvm.objectsize.i32.p0(ptr addrspacecast (ptr addrspace(1) @constexpr_self_user to ptr), i1 false, i1 false, i1 false)
+; CHECK-NEXT:    ret i32 [[OBJSIZE]]
+;
+  %objsize = call i32 @llvm.objectsize.i32.p0(ptr addrspacecast (ptr addrspace(1) @constexpr_self_user to ptr), i1 false, i1 false, i1 false)
+  ret i32 %objsize
+}



More information about the llvm-commits mailing list