llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT--> @llvm/pr-subscribers-clangir @llvm/pr-subscribers-clang Author: Erich Keane (erichkeane) <details> <summary>Changes</summary> This popped up in a benchmark. Classic codegen ALWAYS sets this as 'excludeCtor'/'excludeDtor', but CIR tried 'harder' to get this right. However, with an incomplete type, we can't actually look into it to see if it has any mutable members, so determining 'constness' isn't possible. We could PROBABLY do better with enums since I would assume they can be constant most of the time, but we fall-back to classic-codegen's behavior here instead: which marks it as non-const. Thanks to 'trying harder' than classic codegen as mentioned above, there IS a slight LLVM-IR difference, but for the better. Also note: Claude helped me with the tests. --- Full diff: https://github.com/llvm/llvm-project/pull/223444.diff 2 Files Affected: - (modified) clang/lib/CIR/CodeGen/CIRGenModule.cpp (+11-2) - (modified) clang/test/CIR/CodeGen/forward-decls.cpp (+58) ``````````diff diff --git a/clang/lib/CIR/CodeGen/CIRGenModule.cpp b/clang/lib/CIR/CodeGen/CIRGenModule.cpp index 6da830289568e..bdc2707723283 100644 --- a/clang/lib/CIR/CodeGen/CIRGenModule.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenModule.cpp @@ -1294,10 +1294,19 @@ CIRGenModule::getOrCreateCIRGlobal(StringRef mangledName, mlir::Type ty, // at creation time, matching the logic used in emitCXXGlobalVarDeclInit. bool isConstant = false; if (d) { + QualType declType = d->getType(); + + // Classic codegen doesn't try to exclude ctor or dtor here, but has a FIXME + // to try to do a better job. So this bit of code does slightly more effort + // to get a more accurate answer. We can try to exclude ctor, but only when + // the type is complete, as otherwise we have to check for + // fields(particularly whether they are mutable). + bool excludeCtor = !declType->isIncompleteType(); bool needsDtor = d->needsDestruction(astContext) == QualType::DK_cxx_destructor; - isConstant = d->getType().isConstantStorage( - astContext, /*ExcludeCtor=*/true, /*ExcludeDtor=*/!needsDtor); + + isConstant = declType.isConstantStorage(astContext, excludeCtor, + /*ExcludeDtor=*/!needsDtor); } mlir::ptr::MemorySpaceAttrInterface declCIRAS = diff --git a/clang/test/CIR/CodeGen/forward-decls.cpp b/clang/test/CIR/CodeGen/forward-decls.cpp index ef5fe16f9566f..3394913803182 100644 --- a/clang/test/CIR/CodeGen/forward-decls.cpp +++ b/clang/test/CIR/CodeGen/forward-decls.cpp @@ -122,3 +122,61 @@ struct A { } b; }; void test(struct A *a){}; + + +//--- incomplete_class_comma_expr +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -x c++ -fclangir -emit-cir %t/incomplete_class_comma_expr -o %t/incomplete_class_comma_expr.cir +// RUN: FileCheck %s --input-file=%t/incomplete_class_comma_expr.cir --check-prefix=CHECK6 +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -x c++ -fclangir -emit-llvm %t/incomplete_class_comma_expr -o %t/incomplete_class_comma_expr-cir.ll +// RUN: FileCheck %s --input-file=%t/incomplete_class_comma_expr-cir.ll --check-prefix=CIR6 +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -x c++ -emit-llvm %t/incomplete_class_comma_expr -o %t/incomplete_class_comma_expr-ogcg.ll +// RUN: FileCheck %s --input-file=%t/incomplete_class_comma_expr-ogcg.ll --check-prefix=OGCG6 + +class Enum extern const writeTypeNames; +int flags = (writeTypeNames, flags); + +// Incomplete type, never constant even though its an enum. +// CHECK6: cir.global "private" external @writeTypeNames : !rec_Enum +// CHECK6-NOT: constant + +// CIR6: @writeTypeNames = external global %class.Enum +// CIR6-NOT: constant + +// OGCG6: @writeTypeNames = external global %class.Enum +// OGCG6-NOT: constant + +//--- extern_const_global_constant +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -x c++ -fclangir -emit-cir %t/extern_const_global_constant -o %t/extern_const_global_constant.cir +// RUN: FileCheck %s --input-file=%t/extern_const_global_constant.cir --check-prefix=CHECK7 +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -x c++ -fclangir -emit-llvm %t/extern_const_global_constant -o %t/extern_const_global_constant-cir.ll +// RUN: FileCheck %s --input-file=%t/extern_const_global_constant-cir.ll --check-prefix=CIR7 +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -x c++ -emit-llvm %t/extern_const_global_constant -o %t/extern_const_global_constant-ogcg.ll +// RUN: FileCheck %s --input-file=%t/extern_const_global_constant-ogcg.ll --check-prefix=OGCG7 + +// Complete class with no mutable fields, can be marked constant. +struct NoMutable { int x; }; +extern const NoMutable no_mutable_val; +// CHECK7: cir.global "private" constant external @no_mutable_val : !rec_NoMutable +// Note: This is a case where CIR is doing a better job than classic, which +// always fails to exclude ctor/dtor. +// CIR7: @no_mutable_val = external constant %struct.NoMutable +// OGCG7: @no_mutable_val = external global %struct.NoMutable + +// Complete class with a mutable field. +struct WithMutable { mutable int x; }; +extern const WithMutable with_mutable_val; +// CHECK7: cir.global "private" external @with_mutable_val : !rec_WithMutable +// CHECK7-NOT: constant +// CIR7: @with_mutable_val = external global %struct.WithMutable +// CIR7-NOT: constant +// OGCG7: @with_mutable_val = external global %struct.WithMutable + +// Incomplete class - cannot be marked constant. +class Incomplete; +extern const Incomplete incomplete_val; +// CHECK7: cir.global "private" external @incomplete_val : !rec_Incomplete +// CIR7: @incomplete_val = external global %class.Incomplete +// OGCG7: @incomplete_val = external global %class.Incomplete + +void use(const NoMutable &, const WithMutable &, const Incomplete *); +void foo() { use(no_mutable_val, with_mutable_val, &incomplete_val); } `````````` </details> https://github.com/llvm/llvm-project/pull/223444 _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
