[clang] [CIR] Fix spurious MemRead on pure pointer-arithmetic ops (PR #185154)
Henrich Lauko via cfe-commits
cfe-commits at lists.llvm.org
Fri Mar 6 22:55:45 PST 2026
https://github.com/xlauko created https://github.com/llvm/llvm-project/pull/185154
Remove incorrect [MemRead] annotations from ops that only perform
pointer arithmetic without loading memory. Add Pure trait to ops
that were missing it.
Affected ops:
- VTableGetVPtrOp, VTableGetVirtualFnAddrOp, VTableGetTypeInfoOp:
remove [MemRead] (already had Pure)
- GetMemberOp, GetRuntimeMemberOp, BaseClassAddrOp, DerivedClassAddrOp:
remove [MemRead] and add Pure
>From 08f3edad0554c236bbdc977eaa574ca4dca344ee Mon Sep 17 00:00:00 2001
From: xlauko <xlauko at mail.muni.cz>
Date: Sat, 7 Mar 2026 07:53:25 +0100
Subject: [PATCH] [CIR] Fix spurious MemRead on pure pointer-arithmetic ops
Remove incorrect [MemRead] annotations from ops that only perform
pointer arithmetic without loading memory. Add Pure trait to ops
that were missing it.
Affected ops:
- VTableGetVPtrOp, VTableGetVirtualFnAddrOp, VTableGetTypeInfoOp:
remove [MemRead] (already had Pure)
- GetMemberOp, GetRuntimeMemberOp, BaseClassAddrOp, DerivedClassAddrOp:
remove [MemRead] and add Pure
---
clang/include/clang/CIR/Dialect/IR/CIROps.td | 25 ++++---
.../CIR/Transforms/pure-ptr-arithmetic.cir | 65 +++++++++++++++++++
2 files changed, 77 insertions(+), 13 deletions(-)
create mode 100644 clang/test/CIR/Transforms/pure-ptr-arithmetic.cir
diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td
index 79eef71229192..e5268a69b15e0 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIROps.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td
@@ -204,7 +204,6 @@ def CIR_CastKind : CIR_I32EnumAttr<"CastKind", "cast kind", [
def CIR_CastOp : CIR_Op<"cast", [
Pure, DeclareOpInterfaceMethods<PromotableOpInterface>
]> {
- // FIXME: not all conversions are free of side effects.
let summary = "Conversion between values of different types";
let description = [{
Apply the usual C/C++ conversion rules between values. This operation models
@@ -2804,7 +2803,7 @@ def CIR_VTableGetVPtrOp : CIR_Op<"vtable.get_vptr", [Pure]> {
}];
let arguments = (ins
- Arg<CIR_PointerType, "the vptr address", [MemRead]>:$src
+ CIR_PointerType:$src
);
let results = (outs CIR_PtrToVPtr:$result);
@@ -2851,7 +2850,7 @@ def CIR_VTableGetVirtualFnAddrOp : CIR_Op<"vtable.get_virtual_fn_addr", [
}];
let arguments = (ins
- Arg<CIR_VPtrType, "vptr", [MemRead]>:$vptr,
+ CIR_VPtrType:$vptr,
I64Attr:$index);
let results = (outs CIR_PointerType:$result);
@@ -2890,7 +2889,7 @@ def CIR_VTableGetTypeInfoOp : CIR_Op<"vtable.get_type_info", [
```
}];
- let arguments = (ins Arg<CIR_VPtrType, "vptr", [MemRead]>:$vptr);
+ let arguments = (ins CIR_VPtrType:$vptr);
let results = (outs CIR_PointerType:$result);
let assemblyFormat = [{
@@ -3149,7 +3148,7 @@ def CIR_GetBitfieldOp : CIR_Op<"get_bitfield"> {
// GetMemberOp
//===----------------------------------------------------------------------===//
-def CIR_GetMemberOp : CIR_Op<"get_member"> {
+def CIR_GetMemberOp : CIR_Op<"get_member", [Pure]> {
let summary = "Get the address of a member of a record";
let description = [{
The `cir.get_member` operation gets the address of a particular named
@@ -3171,7 +3170,7 @@ def CIR_GetMemberOp : CIR_Op<"get_member"> {
}];
let arguments = (ins
- Arg<CIR_PointerType, "the address to load from", [MemRead]>:$addr,
+ CIR_PointerType:$addr,
StrAttr:$name,
IndexAttr:$index_attr);
@@ -4317,7 +4316,7 @@ def CIR_ArrayDtor : CIR_ArrayInitDestroy<"array.dtor"> {
// GetRuntimeMemberOp
//===----------------------------------------------------------------------===//
-def CIR_GetRuntimeMemberOp : CIR_Op<"get_runtime_member"> {
+def CIR_GetRuntimeMemberOp : CIR_Op<"get_runtime_member", [Pure]> {
let summary = "Get the address of a member of a record";
let description = [{
The `cir.get_runtime_member` operation gets the address of a member from
@@ -4357,8 +4356,8 @@ def CIR_GetRuntimeMemberOp : CIR_Op<"get_runtime_member"> {
}];
let arguments = (ins
- Arg<CIR_PtrToRecordType, "address of the record object", [MemRead]>:$addr,
- Arg<CIR_DataMemberType, "pointer to the target member">:$member);
+ CIR_PtrToRecordType:$addr,
+ CIR_DataMemberType:$member);
let results = (outs Res<CIR_PointerType, "">:$result);
@@ -4714,7 +4713,7 @@ def CIR_VecSplatOp : CIR_Op<"vec.splat", [
// BaseClassAddrOp
//===----------------------------------------------------------------------===//
-def CIR_BaseClassAddrOp : CIR_Op<"base_class_addr"> {
+def CIR_BaseClassAddrOp : CIR_Op<"base_class_addr", [Pure]> {
let summary = "Get the base class address for a class/struct";
let description = [{
The `cir.base_class_addr` operaration gets the address of a particular
@@ -4743,7 +4742,7 @@ def CIR_BaseClassAddrOp : CIR_Op<"base_class_addr"> {
}];
let arguments = (ins
- Arg<CIR_PointerType, "derived class pointer", [MemRead]>:$derived_addr,
+ CIR_PointerType:$derived_addr,
IndexAttr:$offset, UnitAttr:$assume_not_null);
let results = (outs Res<CIR_PointerType, "">:$base_addr);
@@ -4759,7 +4758,7 @@ def CIR_BaseClassAddrOp : CIR_Op<"base_class_addr"> {
// DerivedClassAddrOp
//===----------------------------------------------------------------------===//
-def CIR_DerivedClassAddrOp : CIR_Op<"derived_class_addr"> {
+def CIR_DerivedClassAddrOp : CIR_Op<"derived_class_addr", [Pure]> {
let summary = "Get the derived class address for a class/struct";
let description = [{
The `cir.derived_class_addr` operaration gets the address of a particular
@@ -4793,7 +4792,7 @@ def CIR_DerivedClassAddrOp : CIR_Op<"derived_class_addr"> {
}];
let arguments = (ins
- Arg<CIR_PointerType, "base class pointer", [MemRead]>:$base_addr,
+ CIR_PointerType:$base_addr,
IndexAttr:$offset, UnitAttr:$assume_not_null);
let results = (outs Res<CIR_PointerType, "">:$derived_addr);
diff --git a/clang/test/CIR/Transforms/pure-ptr-arithmetic.cir b/clang/test/CIR/Transforms/pure-ptr-arithmetic.cir
new file mode 100644
index 0000000000000..4c7e79923d0db
--- /dev/null
+++ b/clang/test/CIR/Transforms/pure-ptr-arithmetic.cir
@@ -0,0 +1,65 @@
+// RUN: cir-opt %s -canonicalize -o - | FileCheck %s
+
+// Verify that pointer-arithmetic ops marked Pure are eliminated when their
+// results are unused (trivially dead).
+
+!s32i = !cir.int<s, 32>
+!u8i = !cir.int<u, 8>
+!void = !cir.void
+
+!rec_S = !cir.record<struct "S" {!s32i, !s32i}>
+!rec_Base = !cir.record<struct "Base" {!u8i}>
+!rec_Derived = !cir.record<struct "Derived" {!rec_Base, !s32i}>
+
+module {
+
+// CHECK-LABEL: @dead_get_member
+// CHECK-NOT: cir.get_member
+cir.func @dead_get_member(%arg0: !cir.ptr<!rec_S>) {
+ %0 = cir.get_member %arg0[1] {name = "y"} : !cir.ptr<!rec_S> -> !cir.ptr<!s32i>
+ cir.return
+}
+
+// CHECK-LABEL: @dead_base_class_addr
+// CHECK-NOT: cir.base_class_addr
+cir.func @dead_base_class_addr(%arg0: !cir.ptr<!rec_Derived>) {
+ %0 = cir.base_class_addr %arg0 : !cir.ptr<!rec_Derived> nonnull [0] -> !cir.ptr<!rec_Base>
+ cir.return
+}
+
+// CHECK-LABEL: @dead_derived_class_addr
+// CHECK-NOT: cir.derived_class_addr
+cir.func @dead_derived_class_addr(%arg0: !cir.ptr<!rec_Base>) {
+ %0 = cir.derived_class_addr %arg0 : !cir.ptr<!rec_Base> nonnull [0] -> !cir.ptr<!rec_Derived>
+ cir.return
+}
+
+// CHECK-LABEL: @dead_vtable_get_vptr
+// CHECK-NOT: cir.vtable.get_vptr
+cir.func @dead_vtable_get_vptr(%arg0: !cir.ptr<!rec_Derived>) {
+ %0 = cir.vtable.get_vptr %arg0 : !cir.ptr<!rec_Derived> -> !cir.ptr<!cir.vptr>
+ cir.return
+}
+
+// CHECK-LABEL: @dead_vtable_get_virtual_fn_addr
+// CHECK-NOT: cir.vtable.get_virtual_fn_addr
+cir.func @dead_vtable_get_virtual_fn_addr(%arg0: !cir.vptr) {
+ %0 = cir.vtable.get_virtual_fn_addr %arg0[0] : !cir.vptr -> !cir.ptr<!cir.ptr<!cir.func<(!cir.ptr<!rec_Base>)>>>
+ cir.return
+}
+
+// CHECK-LABEL: @dead_vtable_get_type_info
+// CHECK-NOT: cir.vtable.get_type_info
+cir.func @dead_vtable_get_type_info(%arg0: !cir.vptr) {
+ %0 = cir.vtable.get_type_info %arg0 : !cir.vptr -> !cir.ptr<!cir.ptr<!rec_S>>
+ cir.return
+}
+
+// CHECK-LABEL: @dead_get_runtime_member
+// CHECK-NOT: cir.get_runtime_member
+cir.func @dead_get_runtime_member(%arg0: !cir.ptr<!rec_S>, %arg1: !cir.data_member<!s32i in !rec_S>) {
+ %0 = cir.get_runtime_member %arg0[%arg1 : !cir.data_member<!s32i in !rec_S>] : !cir.ptr<!rec_S> -> !cir.ptr<!s32i>
+ cir.return
+}
+
+}
More information about the cfe-commits
mailing list