[clang] [CIR] Fix reference alignment to use pointee type (PR #186667)
Henrich Lauko via cfe-commits
cfe-commits at lists.llvm.org
Sun Mar 15 22:59:21 PDT 2026
https://github.com/xlauko updated https://github.com/llvm/llvm-project/pull/186667
>From 62f57541b4367881e75fbe440a3905a6d9b514ae Mon Sep 17 00:00:00 2001
From: xlauko <xlauko at mail.muni.cz>
Date: Sun, 15 Mar 2026 13:54:42 +0100
Subject: [PATCH] [CIR] Fix reference alignment to use pointee type
getNaturalTypeAlignment on a reference type returned pointer alignment
instead of pointee alignment. Pass the pointee type with
forPointeeType=true to match traditional codegen's
getNaturalPointeeTypeAlignment behavior. Fix applies to both argument
and return type attribute construction paths.
---
clang/lib/CIR/CodeGen/CIRGenCall.cpp | 13 +++++++----
clang/lib/CIR/CodeGen/CIRGenExpr.cpp | 5 +---
clang/lib/CIR/CodeGen/CIRGenModule.cpp | 7 ++++++
clang/lib/CIR/CodeGen/CIRGenModule.h | 3 +++
clang/test/CIR/CodeGen/arg-attrs.cpp | 31 +++++++++++++++++++++----
clang/test/CIR/CodeGen/invoke-attrs.cpp | 6 ++---
6 files changed, 49 insertions(+), 16 deletions(-)
diff --git a/clang/lib/CIR/CodeGen/CIRGenCall.cpp b/clang/lib/CIR/CodeGen/CIRGenCall.cpp
index 1d7f15c569798..aba3ccde28065 100644
--- a/clang/lib/CIR/CodeGen/CIRGenCall.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenCall.cpp
@@ -620,7 +620,7 @@ void CIRGenModule::constructFunctionReturnAttributes(
if (pointeeTy->isObjectType())
retAttrs.set(mlir::LLVM::LLVMDialect::getAlignAttrName(),
builder.getI64IntegerAttr(
- getNaturalTypeAlignment(pointeeTy).getQuantity()));
+ getNaturalPointeeTypeAlignment(retTy).getQuantity()));
}
}
}
@@ -659,7 +659,9 @@ void CIRGenModule::constructFunctionArgumentAttributes(
argAttrs[0].set(mlir::LLVM::LLVMDialect::getAlignAttrName(),
builder.getI64IntegerAttr(
- getNaturalTypeAlignment(thisTy).getQuantity()));
+ getNaturalTypeAlignment(thisTy, /*baseInfo=*/nullptr,
+ /*forPointeeType=*/true)
+ .getQuantity()));
// TODO(cir): the classic codegen has a recently-added bunch of logic for
// 'dead_on_return' as an attribute. This both doesn't exist in the LLVM
@@ -702,9 +704,10 @@ void CIRGenModule::constructFunctionArgumentAttributes(
argAttrList.set(mlir::LLVM::LLVMDialect::getNonNullAttrName(),
mlir::UnitAttr::get(&getMLIRContext()));
if (pointeeTy->isObjectType())
- argAttrList.set(mlir::LLVM::LLVMDialect::getAlignAttrName(),
- builder.getI64IntegerAttr(
- getNaturalTypeAlignment(argType).getQuantity()));
+ argAttrList.set(
+ mlir::LLVM::LLVMDialect::getAlignAttrName(),
+ builder.getI64IntegerAttr(
+ getNaturalPointeeTypeAlignment(argType).getQuantity()));
}
}
}
diff --git a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp
index 5328bb0a812a5..8c51ac46cea79 100644
--- a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp
@@ -903,10 +903,7 @@ LValue CIRGenFunction::emitDeclRefLValue(const DeclRefExpr *e) {
}
} else {
// Should we be using the alignment of the constant pointer we emitted?
- CharUnits alignment =
- cgm.getNaturalTypeAlignment(e->getType(),
- /*BaseInfo=*/nullptr,
- /*forPointeeType=*/true);
+ CharUnits alignment = cgm.getNaturalPointeeTypeAlignment(e->getType());
// Classic codegen passes TBAA as null-ptr to the above function, so it
// probably needs to deal with that.
assert(!cir::MissingFeatures::opTBAA());
diff --git a/clang/lib/CIR/CodeGen/CIRGenModule.cpp b/clang/lib/CIR/CodeGen/CIRGenModule.cpp
index cb931f969a41d..43f4c48d00828 100644
--- a/clang/lib/CIR/CodeGen/CIRGenModule.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenModule.cpp
@@ -237,6 +237,13 @@ CharUnits CIRGenModule::getNaturalTypeAlignment(QualType t,
return alignment;
}
+CharUnits
+CIRGenModule::getNaturalPointeeTypeAlignment(QualType t,
+ LValueBaseInfo *baseInfo) {
+ return getNaturalTypeAlignment(t->getPointeeType(), baseInfo,
+ /*forPointeeType=*/true);
+}
+
const TargetCIRGenInfo &CIRGenModule::getTargetCIRGenInfo() {
if (theTargetCIRGenInfo)
return *theTargetCIRGenInfo;
diff --git a/clang/lib/CIR/CodeGen/CIRGenModule.h b/clang/lib/CIR/CodeGen/CIRGenModule.h
index bef154955b9b6..9d402ffb3bf79 100644
--- a/clang/lib/CIR/CodeGen/CIRGenModule.h
+++ b/clang/lib/CIR/CodeGen/CIRGenModule.h
@@ -398,6 +398,9 @@ class CIRGenModule : public CIRGenTypeCache {
clang::CharUnits getNaturalTypeAlignment(clang::QualType t,
LValueBaseInfo *baseInfo = nullptr,
bool forPointeeType = false);
+ clang::CharUnits
+ getNaturalPointeeTypeAlignment(clang::QualType t,
+ LValueBaseInfo *baseInfo = nullptr);
/// Returns the minimum object size for an object of the given class type
/// (or a class derived from it).
diff --git a/clang/test/CIR/CodeGen/arg-attrs.cpp b/clang/test/CIR/CodeGen/arg-attrs.cpp
index a66cf661dc66c..800b86e602cd0 100644
--- a/clang/test/CIR/CodeGen/arg-attrs.cpp
+++ b/clang/test/CIR/CodeGen/arg-attrs.cpp
@@ -18,18 +18,41 @@ void Struct::this_func(){}
// CIR: cir.func {{.*}}@_ZN6Struct9this_funcEv(%{{.*}}: !cir.ptr<!rec_Struct> {llvm.align = 4 : i64, llvm.dereferenceable = 20 : i64, llvm.nonnull, llvm.noundef} {{.*}}) {
// BOTH: define {{.*}}void @_ZN6Struct9this_funcEv(ptr noundef nonnull align 4 dereferenceable(20) %{{.*}})
void Struct::arg_attr(Struct s, int &i, Incomplete &j){}
- // CIR: cir.func {{.*}}@_ZN6Struct8arg_attrES_RiR10Incomplete(%{{.*}}: !cir.ptr<!rec_Struct> {llvm.align = 4 : i64, llvm.dereferenceable = 20 : i64, llvm.nonnull, llvm.noundef} {{.*}}, %{{.*}}: !rec_Struct {{.*}}, %{{.*}}: !cir.ptr<!s32i> {llvm.align = 8 : i64, llvm.dereferenceable = 4 : i64, llvm.nonnull, llvm.noundef} {{.*}}, %arg3: !cir.ptr<!rec_Incomplete> {llvm.align = 8 : i64, llvm.nonnull, llvm.noundef} {{.*}}) {
- // LLVM: define {{.*}}void @_ZN6Struct8arg_attrES_RiR10Incomplete(ptr noundef nonnull align 4 dereferenceable(20) %{{.*}}, %struct.Struct %{{.*}}, ptr noundef nonnull align 8 dereferenceable(4) %{{.*}}, ptr noundef nonnull align 8 %{{.*}})
+ // CIR: cir.func {{.*}}@_ZN6Struct8arg_attrES_RiR10Incomplete(%{{.*}}: !cir.ptr<!rec_Struct> {llvm.align = 4 : i64, llvm.dereferenceable = 20 : i64, llvm.nonnull, llvm.noundef} {{.*}}, %{{.*}}: !rec_Struct {{.*}}, %{{.*}}: !cir.ptr<!s32i> {llvm.align = 4 : i64, llvm.dereferenceable = 4 : i64, llvm.nonnull, llvm.noundef} {{.*}}, %arg3: !cir.ptr<!rec_Incomplete> {llvm.align = 1 : i64, llvm.nonnull, llvm.noundef} {{.*}}) {
+ // LLVM: define {{.*}}void @_ZN6Struct8arg_attrES_RiR10Incomplete(ptr noundef nonnull align 4 dereferenceable(20) %{{.*}}, %struct.Struct %{{.*}}, ptr noundef nonnull align 4 dereferenceable(4) %{{.*}}, ptr noundef nonnull align 1 %{{.*}})
// OGCG: define {{.*}}void @_ZN6Struct8arg_attrES_RiR10Incomplete(ptr noundef nonnull align 4 dereferenceable(20) %{{.*}}, ptr noundef byval(%struct.Struct) align 8 %{{.*}}, ptr noundef nonnull align 4 dereferenceable(4) %{{.*}}, ptr noundef nonnull align 1 %{{.*}})
+struct __attribute__((aligned(32))) Aligned32 {
+ int x;
+ void method();
+};
+
+void Aligned32::method() {}
+ // CIR: cir.func {{.*}}@_ZN9Aligned326methodEv(%{{.*}}: !cir.ptr<!rec_Aligned32> {llvm.align = 32 : i64, llvm.dereferenceable = 32 : i64, llvm.nonnull, llvm.noundef} {{.*}}) {
+ // BOTH: define {{.*}}void @_ZN9Aligned326methodEv(ptr noundef nonnull align 32 dereferenceable(32) %{{.*}})
+
+void aligned_ref(Aligned32 &a) {}
+ // CIR: cir.func {{.*}}@_Z11aligned_refR9Aligned32(%{{.*}}: !cir.ptr<!rec_Aligned32> {llvm.align = 32 : i64, llvm.dereferenceable = 32 : i64, llvm.nonnull, llvm.noundef} {{.*}}) {
+ // BOTH: define {{.*}}void @_Z11aligned_refR9Aligned32(ptr noundef nonnull align 32 dereferenceable(32) %{{.*}})
+
+int g;
+int &return_int_ref() { return g; }
+ // CIR: cir.func {{.*}}@_Z14return_int_refv() -> (!cir.ptr<!s32i> {llvm.align = 4 : i64, llvm.dereferenceable = 4 : i64, llvm.nonnull, llvm.noundef}) {
+ // BOTH: define {{.*}}noundef nonnull align 4 dereferenceable(4) ptr @_Z14return_int_refv()
+
+Aligned32 ga;
+Aligned32 &return_aligned_ref() { return ga; }
+ // CIR: cir.func {{.*}}@_Z18return_aligned_refv() -> (!cir.ptr<!rec_Aligned32> {llvm.align = 32 : i64, llvm.dereferenceable = 32 : i64, llvm.nonnull, llvm.noundef}) {
+ // BOTH: define {{.*}}noundef nonnull align 32 dereferenceable(32) ptr @_Z18return_aligned_refv()
+
void caller(Struct s, int i, Incomplete &inc) {
s.this_func();
// CIR: cir.call @_ZN6Struct9this_funcEv(%{{.*}}) : (!cir.ptr<!rec_Struct> {llvm.align = 4 : i64, llvm.dereferenceable = 20 : i64, llvm.nonnull, llvm.noundef})
// BOTH: call void @_ZN6Struct9this_funcEv(ptr noundef nonnull align 4 dereferenceable(20) %{{.*}})
s.arg_attr(s, i, inc);
- // CIR: cir.call @_ZN6Struct8arg_attrES_RiR10Incomplete(%{{.*}}, %{{.*}}, %{{.*}}, %{{.*}}) : (!cir.ptr<!rec_Struct> {llvm.align = 4 : i64, llvm.dereferenceable = 20 : i64, llvm.nonnull, llvm.noundef}, !rec_Struct, !cir.ptr<!s32i> {llvm.align = 8 : i64, llvm.dereferenceable = 4 : i64, llvm.nonnull, llvm.noundef}, !cir.ptr<!rec_Incomplete> {llvm.align = 8 : i64, llvm.nonnull, llvm.noundef})
- // LLVM: call void @_ZN6Struct8arg_attrES_RiR10Incomplete(ptr noundef nonnull align 4 dereferenceable(20) %{{.*}}, %struct.Struct %{{.*}}, ptr noundef nonnull align 8 dereferenceable(4) %{{.*}}, ptr noundef nonnull align 8 %{{.*}})
+ // CIR: cir.call @_ZN6Struct8arg_attrES_RiR10Incomplete(%{{.*}}, %{{.*}}, %{{.*}}, %{{.*}}) : (!cir.ptr<!rec_Struct> {llvm.align = 4 : i64, llvm.dereferenceable = 20 : i64, llvm.nonnull, llvm.noundef}, !rec_Struct, !cir.ptr<!s32i> {llvm.align = 4 : i64, llvm.dereferenceable = 4 : i64, llvm.nonnull, llvm.noundef}, !cir.ptr<!rec_Incomplete> {llvm.align = 1 : i64, llvm.nonnull, llvm.noundef})
+ // LLVM: call void @_ZN6Struct8arg_attrES_RiR10Incomplete(ptr noundef nonnull align 4 dereferenceable(20) %{{.*}}, %struct.Struct %{{.*}}, ptr noundef nonnull align 4 dereferenceable(4) %{{.*}}, ptr noundef nonnull align 1 %{{.*}})
// OGCG: call void @_ZN6Struct8arg_attrES_RiR10Incomplete(ptr noundef nonnull align 4 dereferenceable(20) %{{.*}}, ptr noundef byval(%struct.Struct) align 8 %{{.*}}, ptr noundef nonnull align 4 dereferenceable(4) %{{.*}}, ptr noundef nonnull align 1 %{{.*}})
}
diff --git a/clang/test/CIR/CodeGen/invoke-attrs.cpp b/clang/test/CIR/CodeGen/invoke-attrs.cpp
index bc58d2193c267..aeb2d0cfbc386 100644
--- a/clang/test/CIR/CodeGen/invoke-attrs.cpp
+++ b/clang/test/CIR/CodeGen/invoke-attrs.cpp
@@ -44,13 +44,13 @@ void test_ref_param_attrs(S &s, int &i) {
}
// CIR-LABEL: cir.func {{.*}}@_Z20test_ref_param_attrsR1SRi
-// CIR: cir.call @_ZN1S9ref_paramERi({{%.*}}, {{%.*}}) : (!cir.ptr<!rec_S> {llvm.align = 4 : i64, llvm.dereferenceable = 20 : i64, llvm.nonnull, llvm.noundef}, !cir.ptr<!s32i> {llvm.align = 8 : i64, llvm.dereferenceable = 4 : i64, llvm.nonnull, llvm.noundef}) -> ()
+// CIR: cir.call @_ZN1S9ref_paramERi({{%.*}}, {{%.*}}) : (!cir.ptr<!rec_S> {llvm.align = 4 : i64, llvm.dereferenceable = 20 : i64, llvm.nonnull, llvm.noundef}, !cir.ptr<!s32i> {llvm.align = 4 : i64, llvm.dereferenceable = 4 : i64, llvm.nonnull, llvm.noundef}) -> ()
// CIR-FLAT-LABEL: cir.func {{.*}}@_Z20test_ref_param_attrsR1SRi
-// CIR-FLAT: cir.try_call @_ZN1S9ref_paramERi({{%.*}}, {{%.*}}) ^{{bb[0-9]+}}, ^{{bb[0-9]+}} : (!cir.ptr<!rec_S> {llvm.align = 4 : i64, llvm.dereferenceable = 20 : i64, llvm.nonnull, llvm.noundef}, !cir.ptr<!s32i> {llvm.align = 8 : i64, llvm.dereferenceable = 4 : i64, llvm.nonnull, llvm.noundef}) -> ()
+// CIR-FLAT: cir.try_call @_ZN1S9ref_paramERi({{%.*}}, {{%.*}}) ^{{bb[0-9]+}}, ^{{bb[0-9]+}} : (!cir.ptr<!rec_S> {llvm.align = 4 : i64, llvm.dereferenceable = 20 : i64, llvm.nonnull, llvm.noundef}, !cir.ptr<!s32i> {llvm.align = 4 : i64, llvm.dereferenceable = 4 : i64, llvm.nonnull, llvm.noundef}) -> ()
// LLVM-LABEL: define {{.*}} void @_Z20test_ref_param_attrsR1SRi
-// LLVM: invoke void @_ZN1S9ref_paramERi(ptr noundef nonnull align 4 dereferenceable(20) {{%.*}}, ptr noundef nonnull align 8 dereferenceable(4) {{%.*}})
+// LLVM: invoke void @_ZN1S9ref_paramERi(ptr noundef nonnull align 4 dereferenceable(20) {{%.*}}, ptr noundef nonnull align 4 dereferenceable(4) {{%.*}})
// OGCG-LABEL: define {{.*}} void @_Z20test_ref_param_attrsR1SRi
// OGCG: invoke void @_ZN1S9ref_paramERi(ptr noundef nonnull align 4 dereferenceable(20) {{%.*}}, ptr noundef nonnull align 4 dereferenceable(4) {{%.*}})
More information about the cfe-commits
mailing list