llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT--> @llvm/pr-subscribers-clang Author: Henrich Lauko (xlauko) <details> <summary>Changes</summary> Remove incorrect [MemRead] annotations from seven CIR ops that only perform pointer arithmetic, and add the Pure trait where missing. - VTableGetVPtrOp computes the address of the vptr slot within an object. Since the vptr is always at offset zero, this is a bitcast — confirmed by the lowering which does replaceOp(op, srcVal). No memory access. - VTableGetVirtualFnAddrOp takes an already-loaded !cir.vptr value and an index, computes the address of the nth vtable entry. Lowers to a GEPOp. No memory access. - VTableGetTypeInfoOp takes an already-loaded !cir.vptr value, computes the address of the type_info entry at a known ABI offset. Pointer arithmetic only. No memory access. - GetMemberOp computes the address of a struct/class member given a base pointer and a constant index. Lowers to GEPOp (struct/class) or BitcastOp (union). No memory access. - GetRuntimeMemberOp computes a member address using a runtime pointer-to-data-member value. Lowers to CastOp + PtrStrideOp (byte-level pointer arithmetic). No memory access. - BaseClassAddrOp computes the base class address from a derived class pointer using a byte offset. Lowers to GEPOp/BitcastOp with a null check when needed. No memory access. - DerivedClassAddrOp computes the derived class address from a base class pointer using a negative byte offset. Lowers to GEPOp with a null check when needed. No memory access. In all cases, the actual memory reads are performed by separate cir.load ops that follow these address computations. --- Full diff: https://github.com/llvm/llvm-project/pull/185154.diff 2 Files Affected: - (modified) clang/include/clang/CIR/Dialect/IR/CIROps.td (+12-13) - (added) clang/test/CIR/Transforms/pure-ptr-arithmetic.cir (+65) ``````````diff 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 +} + +} `````````` </details> https://github.com/llvm/llvm-project/pull/185154 _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
