[llvm] [EarlyCSE] merge consecutive bitfield accesses in case of pointers (PR #76053)

via llvm-commits llvm-commits at lists.llvm.org
Wed Dec 20 06:32:54 PST 2023


https://github.com/adamszilagyi updated https://github.com/llvm/llvm-project/pull/76053

>From b64499c6ef73881378b7e767b31c0fa06e3fe7b4 Mon Sep 17 00:00:00 2001
From: Adam Szilagyi <adam.szilagyi97 at gmail.com>
Date: Wed, 20 Dec 2023 14:12:36 +0100
Subject: [PATCH] [EarlyCSE] merge consecutive bitfield accesses in case of
 pointers

---
 llvm/lib/Transforms/Scalar/EarlyCSE.cpp  | 27 ++++++++++++
 llvm/test/Transforms/EarlyCSE/ptrload.ll | 55 ++++++++++++++++++++++++
 2 files changed, 82 insertions(+)
 create mode 100644 llvm/test/Transforms/EarlyCSE/ptrload.ll

diff --git a/llvm/lib/Transforms/Scalar/EarlyCSE.cpp b/llvm/lib/Transforms/Scalar/EarlyCSE.cpp
index f736d429cb6381..5b426089498568 100644
--- a/llvm/lib/Transforms/Scalar/EarlyCSE.cpp
+++ b/llvm/lib/Transforms/Scalar/EarlyCSE.cpp
@@ -1744,6 +1744,33 @@ bool EarlyCSE::processNode(DomTreeNode *Node) {
           // fallthrough - we can exploit information about this store
         }
 
+        // For loading from pointers we use two load instructions, one for
+        // loading the address and then another one to load the value from the
+        // address.
+        //   0 = load p
+        //   x = load 0
+        //   ...
+        //   store x, 0
+        // In order to be able to remove redundant load/store of this pattern,
+        // before we update the previously stored value load instruction in the
+        // hash table we should update the generation of the pointer load as
+        // well.
+        LoadValue PrevLoad = AvailableLoads.lookup(MemInst.getPointerOperand());
+        if (PrevLoad.DefInst != nullptr) {
+          LoadInst *PtrLoad = dyn_cast<LoadInst>(MemInst.getPointerOperand());
+          if (PtrLoad != nullptr) {
+            ParseMemoryInst PtrMemInst(PtrLoad, TTI);
+            LoadValue PtrLoadVal =
+                AvailableLoads.lookup(PtrMemInst.getPointerOperand());
+            if (PtrLoadVal.DefInst != nullptr)
+              AvailableLoads.insert(PtrMemInst.getPointerOperand(),
+                                    LoadValue(PtrLoad, CurrentGeneration,
+                                              PtrMemInst.getMatchingId(),
+                                              PtrMemInst.isAtomic(),
+                                              PtrMemInst.isLoad()));
+          }
+        }
+
         // Okay, we just invalidated anything we knew about loaded values.  Try
         // to salvage *something* by remembering that the stored value is a live
         // version of the pointer.  It is safe to forward from volatile stores
diff --git a/llvm/test/Transforms/EarlyCSE/ptrload.ll b/llvm/test/Transforms/EarlyCSE/ptrload.ll
new file mode 100644
index 00000000000000..7441903a6d87af
--- /dev/null
+++ b/llvm/test/Transforms/EarlyCSE/ptrload.ll
@@ -0,0 +1,55 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt -S -passes=early-cse < %s | FileCheck %s
+
+%struct.bits = type { i8, [3 x i8] }
+
+ at b = dso_local global %struct.bits zeroinitializer, align 4
+
+; Function Attrs: nounwind
+define dso_local arm_aapcscc void @clear_bits() #0 {
+; CHECK-LABEL: @clear_bits(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[TMP0:%.*]] = load ptr, ptr @b, align 4
+; CHECK-NEXT:    [[BF_LOAD:%.*]] = load i8, ptr [[TMP0]], align 4
+; CHECK-NEXT:    [[BF_CLEAR:%.*]] = and i8 [[BF_LOAD]], -33
+; CHECK-NEXT:    [[BF_CLEAR2:%.*]] = and i8 [[BF_CLEAR]], -17
+; CHECK-NEXT:    [[BF_CLEAR5:%.*]] = and i8 [[BF_CLEAR2]], -9
+; CHECK-NEXT:    [[BF_CLEAR8:%.*]] = and i8 [[BF_CLEAR5]], -5
+; CHECK-NEXT:    [[BF_CLEAR11:%.*]] = and i8 [[BF_CLEAR8]], -3
+; CHECK-NEXT:    [[BF_CLEAR14:%.*]] = and i8 [[BF_CLEAR11]], -2
+; CHECK-NEXT:    store i8 [[BF_CLEAR14]], ptr [[TMP0]], align 4
+; CHECK-NEXT:    ret void
+;
+entry:
+  %0 = load ptr, ptr @b, align 4
+  %bf.load = load i8, ptr %0, align 4
+  %bf.clear = and i8 %bf.load, -33
+  %bf.set = or i8 %bf.clear, 0
+  store i8 %bf.set, ptr %0, align 4
+  %1 = load ptr, ptr @b, align 4
+  %bf.load1 = load i8, ptr %1, align 4
+  %bf.clear2 = and i8 %bf.load1, -17
+  %bf.set3 = or i8 %bf.clear2, 0
+  store i8 %bf.set3, ptr %1, align 4
+  %2 = load ptr, ptr @b, align 4
+  %bf.load4 = load i8, ptr %2, align 4
+  %bf.clear5 = and i8 %bf.load4, -9
+  %bf.set6 = or i8 %bf.clear5, 0
+  store i8 %bf.set6, ptr %2, align 4
+  %3 = load ptr, ptr @b, align 4
+  %bf.load7 = load i8, ptr %3, align 4
+  %bf.clear8 = and i8 %bf.load7, -5
+  %bf.set9 = or i8 %bf.clear8, 0
+  store i8 %bf.set9, ptr %3, align 4
+  %4 = load ptr, ptr @b, align 4
+  %bf.load10 = load i8, ptr %4, align 4
+  %bf.clear11 = and i8 %bf.load10, -3
+  %bf.set12 = or i8 %bf.clear11, 0
+  store i8 %bf.set12, ptr %4, align 4
+  %5 = load ptr, ptr @b, align 4
+  %bf.load13 = load i8, ptr %5, align 4
+  %bf.clear14 = and i8 %bf.load13, -2
+  %bf.set15 = or i8 %bf.clear14, 0
+  store i8 %bf.set15, ptr %5, align 4
+  ret void
+}



More information about the llvm-commits mailing list