[llvm] [CGP] Undo constant propagation of pointers across calls (PR #102926)

Antonio Frighetto via llvm-commits llvm-commits at lists.llvm.org
Mon Aug 12 09:14:06 PDT 2024


https://github.com/antoniofrighetto created https://github.com/llvm/llvm-project/pull/102926

It may be profitable to undo SCCP propagation of C++ static values, if such constants are pointers, in order to avoid redundant pointer computation, since the method returning the constant is non-removable.

>From 3c6051e09ad3bbd7b6e7e82754d034ae2fed18d5 Mon Sep 17 00:00:00 2001
From: Antonio Frighetto <me at antoniofrighetto.com>
Date: Mon, 12 Aug 2024 16:57:03 +0200
Subject: [PATCH] [CGP] Undo constant propagation of pointers across calls

It may be profitable to undo SCCP propagation of C++ static values,
if such constants are pointers, in order to avoid redundant pointer
computation, since the method returning the constant is non-removable.
---
 llvm/lib/CodeGen/CodeGenPrepare.cpp           | 31 +++++++++++
 .../remove-constant-on-calls.ll               | 54 +++++++++++++++++++
 2 files changed, 85 insertions(+)
 create mode 100644 llvm/test/Transforms/CodeGenPrepare/remove-constant-on-calls.ll

diff --git a/llvm/lib/CodeGen/CodeGenPrepare.cpp b/llvm/lib/CodeGen/CodeGenPrepare.cpp
index 1fb37fb8406ef4..741aa45a84f8ed 100644
--- a/llvm/lib/CodeGen/CodeGenPrepare.cpp
+++ b/llvm/lib/CodeGen/CodeGenPrepare.cpp
@@ -2555,6 +2555,37 @@ bool CodeGenPrepare::optimizeCallInst(CallInst *CI, ModifyDT &ModifiedDT) {
     return true;
   }
 
+  // SCCP may have propagated C++ static variables across calls. If this happens
+  // to be the case, we may want to undo it in order to avoid redundant pointer
+  // computation of the constant, as the function method returning the constant
+  // needs to be executed anyways.
+  auto MaybeFunctionReturnConstantPtr = [](const Function *F,
+                                           GlobalVariable *GV) {
+    SmallVector<const ReturnInst *, 4> Returns;
+    for (auto &BB : llvm::reverse(*F))
+      if (auto *Ret = dyn_cast<ReturnInst>(BB.getTerminator()))
+        Returns.emplace_back(Ret);
+
+    return !Returns.empty() && all_of(Returns, [&](auto *RI) {
+      return RI->getReturnValue() == GV;
+    });
+  };
+
+  auto *PrevCI = dyn_cast_or_null<CallInst>(CI->getPrevNonDebugInstruction());
+  if (PrevCI && !isa<IntrinsicInst>(PrevCI) && PrevCI->use_empty() &&
+      PrevCI->getType()->isPointerTy()) {
+    for (auto &Arg : CI->args()) {
+      if (auto *GV = dyn_cast<GlobalVariable>(Arg);
+          GV && GV->getType()->isPointerTy()) {
+        const auto *Callee = PrevCI->getCalledFunction();
+        if (Callee && MaybeFunctionReturnConstantPtr(Callee, GV)) {
+          CI->setArgOperand(CI->getArgOperandNo(&Arg), PrevCI);
+          return true;
+        }
+      }
+    }
+  }
+
   return false;
 }
 
diff --git a/llvm/test/Transforms/CodeGenPrepare/remove-constant-on-calls.ll b/llvm/test/Transforms/CodeGenPrepare/remove-constant-on-calls.ll
new file mode 100644
index 00000000000000..e38a22a30df056
--- /dev/null
+++ b/llvm/test/Transforms/CodeGenPrepare/remove-constant-on-calls.ll
@@ -0,0 +1,54 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt -S -passes='require<profile-summary>,function(codegenprepare)' -mtriple=aarch64-none-linux-gnu < %s | FileCheck %s
+
+%struct.S = type { i8 }
+
+ at g_getS = internal global %struct.S zeroinitializer, align 1
+ at guard = internal global i64 0, align 8
+
+define nonnull align 1 dereferenceable(1) ptr @getS() personality ptr @__gxx_personality_v0 {
+entry:
+  %guard = load atomic i8, ptr @guard acquire, align 8
+  %mask = and i8 %guard, 1
+  %cond = icmp eq i8 %mask, 0
+  br i1 %cond, label %to_be_init, label %return
+
+to_be_init:                                       ; preds = %entry
+  %is_init = call i32 @__cxa_guard_acquire(ptr @guard)
+  %cond.2 = icmp ne i32 %is_init, 0
+  br i1 %cond.2, label %ctor, label %return
+
+ctor:                                             ; preds = %to_be_init
+  invoke void @S_ctor(ptr nonnull align 1 dereferenceable(1) @g_getS)
+  to label %continue unwind label %landing_pad
+
+continue:                                         ; preds = %ctor
+  call void @__cxa_guard_release(ptr @guard)
+  br label %return
+
+return:                                           ; preds = %continue, %to_be_init, %entry
+  ret ptr @g_getS
+
+landing_pad:                                      ; preds = %ctor
+  %lp = landingpad { ptr, i32 } cleanup
+  call void @__cxa_guard_abort(ptr @guard)
+  resume { ptr, i32 } %lp
+}
+
+define i32 @getI() {
+; CHECK-LABEL: @getI(
+; CHECK-NEXT:    [[GETS_PTR:%.*]] = call nonnull align 1 dereferenceable(1) ptr @getS()
+; CHECK-NEXT:    [[GETI:%.*]] = call i32 @S_getI(ptr nonnull align 1 dereferenceable(1) [[GETS_PTR]])
+; CHECK-NEXT:    ret i32 [[GETI]]
+;
+  %getS_ptr = call nonnull align 1 dereferenceable(1) ptr @getS()
+  %getI = call i32 @S_getI(ptr nonnull align 1 dereferenceable(1) @g_getS)
+  ret i32 %getI
+}
+
+declare i32 @__cxa_guard_acquire(ptr)
+declare void @S_ctor(ptr nonnull align 1 dereferenceable(1))
+declare i32 @S_getI(ptr nonnull align 1 dereferenceable(1))
+declare void @__cxa_guard_abort(ptr)
+declare void @__cxa_guard_release(ptr)
+declare i32 @__gxx_personality_v0(...)



More information about the llvm-commits mailing list