Author: Bruno Cardoso Lopes
Date: 2026-10-16T20:31:32-07:00
New Revision: 08b8038d3475001d01d438c836af1c8140c97acd

URL: 
https://github.com/llvm/llvm-project/commit/08b8038d3475001d01d438c836af1c8140c97acd
DIFF: 
https://github.com/llvm/llvm-project/commit/08b8038d3475001d01d438c836af1c8140c97acd.diff

LOG: [CIR] Skip record rebuilds for unchanging types in CXXABI lowering 
(#232880)

CIRABITypeConverter only rewrites data-member and method types, but it
did not override typeMayChange, so every named record converted to a
renamed copy and every op touching one was illegal, forcing the generic
pattern to rebuild them all. Override it to report only those two types
as possibly changing, letting records that reach neither convert to
themselves and stay legal.

Small gains across the more expensive selfhosting TUs (no CIR output
changes):
- Registry 36.7->35.8,
- ASTImporterTest 64.4->63.7,
- SLPVectorizer 93.6->91.9,
- OpenMPDecomp 39.5->38.1, 
- SemaExpr 59.3->57.5.

Added: 
    clang/test/CIR/Transforms/cxx-abi-lowering-member-record.cir
    clang/test/CIR/Transforms/cxx-abi-lowering-same-type-cast-fold.cir

Modified: 
    clang/lib/CIR/Dialect/Transforms/CXXABILowering.cpp

Removed: 
    


################################################################################
diff  --git a/clang/lib/CIR/Dialect/Transforms/CXXABILowering.cpp 
b/clang/lib/CIR/Dialect/Transforms/CXXABILowering.cpp
index 86c74ce14842b..2bf8bf1677912 100644
--- a/clang/lib/CIR/Dialect/Transforms/CXXABILowering.cpp
+++ b/clang/lib/CIR/Dialect/Transforms/CXXABILowering.cpp
@@ -846,6 +846,13 @@ class CIRABITypeConverter : public 
cir::RecordRewritingTypeConverter {
       return convertType(abiType);
     });
   }
+
+protected:
+  // Only member pointer types are rewritten. Records that reach none of them
+  // are left alone.
+  bool typeMayChange(mlir::Type type) const override {
+    return mlir::isa<cir::DataMemberType, cir::MethodType>(type);
+  }
 };
 } // namespace
 
@@ -885,6 +892,27 @@ populateCXXABIConversionTarget(mlir::ConversionTarget 
&target,
                            });
       });
 
+  // TargetLowering leaves same-type casts behind. Keep them illegal so the
+  // conversion driver folds them away.
+  target.addDynamicallyLegalOp<cir::CastOp>([&typeConverter](cir::CastOp op) {
+    if (op.getSrc().getType() == op.getType()) {
+      switch (op.getKind()) {
+      case cir::CastKind::bitcast:
+      case cir::CastKind::address_space:
+      case cir::CastKind::float_complex:
+      case cir::CastKind::int_complex:
+        return false;
+      default:
+        break;
+      }
+    }
+    if (!typeConverter.isLegal(op.getOperation()))
+      return false;
+    // CastOp has no regions, so operand/result types and inherent
+    // attributes are the whole legality check.
+    return areCXXABIInherentAttrsLegal(op, typeConverter);
+  });
+
   // Some CIR ops needs special checking for legality
   target.addDynamicallyLegalOp<cir::FuncOp>([&typeConverter](cir::FuncOp op) {
     bool attrs = areCXXABIInherentAttrsLegal(op, typeConverter);

diff  --git a/clang/test/CIR/Transforms/cxx-abi-lowering-member-record.cir 
b/clang/test/CIR/Transforms/cxx-abi-lowering-member-record.cir
new file mode 100644
index 0000000000000..ee5a0ede7b0bf
--- /dev/null
+++ b/clang/test/CIR/Transforms/cxx-abi-lowering-member-record.cir
@@ -0,0 +1,26 @@
+// RUN: cir-opt %s -cir-cxxabi-lowering -o %t.cir
+// RUN: FileCheck --input-file=%t.cir %s
+
+!s32i = !cir.int<s, 32>
+!rec_Foo = !cir.struct<"Foo" {data !s32i}>
+!method = !cir.method<!cir.func<(!cir.ptr<!rec_Foo>, !s32i)> in !rec_Foo>
+!rec_HasMethod = !cir.struct<"HasMethod" {data !method}>
+!rec_Plain = !cir.struct<"Plain" {data !s32i}>
+
+// A record reaching a method type is rebuilt with the Itanium lowered form,
+// a {ptr
diff _t, ptr
diff _t} pair. Dropping MethodType from typeMayChange
+// leaves the member unlowered and this check fails.
+// CHECK-DAG: !rec_HasMethod = !cir.struct<"HasMethod" {data !rec_anon_struct}>
+// CHECK-DAG: !rec_anon_struct = !cir.struct<{data !s64i, data !s64i}>
+
+// A record reaching no member pointer type converts to itself and passes
+// through with its name and members untouched.
+// CHECK-DAG: !rec_Plain = !cir.struct<"Plain" {data !s32i}>
+
+module attributes {cir.triple = "x86_64-unknown-linux-gnu"} {
+  cir.func @method_record() {
+    %m = cir.const #cir.zero : !rec_HasMethod
+    %p = cir.const #cir.zero : !rec_Plain
+    cir.return
+  }
+}

diff  --git 
a/clang/test/CIR/Transforms/cxx-abi-lowering-same-type-cast-fold.cir 
b/clang/test/CIR/Transforms/cxx-abi-lowering-same-type-cast-fold.cir
new file mode 100644
index 0000000000000..c0ee9a9b611a4
--- /dev/null
+++ b/clang/test/CIR/Transforms/cxx-abi-lowering-same-type-cast-fold.cir
@@ -0,0 +1,45 @@
+// RUN: cir-opt %s -cir-cxxabi-lowering -o %t.cir
+// RUN: FileCheck --input-file=%t.cir %s
+
+!u8i = !cir.int<u, 8>
+!s32i = !cir.int<s, 32>
+!rec_S = !cir.struct<"S" {data !s32i}>
+!rec_Other = !cir.struct<"Other" {pad !u8i}>
+!rec_Dmp = !cir.struct<"Dmp" {data !cir.data_member<!s32i in !rec_Other>}>
+// CHECK: !rec_Dmp = !cir.struct<"Dmp" {data !s64i}>
+
+module attributes {cir.triple = "x86_64-unknown-linux-gnu"} {
+  // Same-type no-op casts stay illegal so the driver folds them away,
+  // on plain ...
+  cir.func @cast_plain(%p: !cir.ptr<!s32i>) -> !cir.ptr<!s32i> {
+    %c = cir.cast bitcast %p : !cir.ptr<!s32i> -> !cir.ptr<!s32i>
+    cir.return %c : !cir.ptr<!s32i>
+  }
+  // CHECK-LABEL: cir.func @cast_plain
+  // CHECK-NEXT: cir.return %{{.*}} : !cir.ptr<!s32i>
+
+  // ... and record pointers.
+  cir.func @cast_record(%p: !cir.ptr<!rec_S>) -> !cir.ptr<!rec_S> {
+    %c = cir.cast bitcast %p : !cir.ptr<!rec_S> -> !cir.ptr<!rec_S>
+    cir.return %c : !cir.ptr<!rec_S>
+  }
+  // CHECK-LABEL: cir.func @cast_record
+  // CHECK-NEXT: cir.return %{{.*}} : !cir.ptr<!rec_S>
+
+  // Same for the address_space casts TargetLowering leaves behind.
+  cir.func @cast_addrspace(%p: !cir.ptr<!s32i>) -> !cir.ptr<!s32i> {
+    %c = cir.cast address_space %p : !cir.ptr<!s32i> -> !cir.ptr<!s32i>
+    cir.return %c : !cir.ptr<!s32i>
+  }
+  // CHECK-LABEL: cir.func @cast_addrspace
+  // CHECK-NEXT: cir.return %{{.*}} : !cir.ptr<!s32i>
+
+  // Records that reach member pointers are still rewritten.
+  cir.func @dmp_rewritten() {
+    %r = cir.const #cir.zero : !rec_Dmp
+    cir.return
+  }
+  // CHECK-LABEL: cir.func @dmp_rewritten
+  // CHECK-NEXT: %{{.*}} = cir.const #cir.zero : !rec_Dmp
+  // CHECK-NEXT: cir.return
+}


        
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to