Skip to content

[Clang][CodeGen] Add metadata for load from reference #98746

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
May 26, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,8 @@ C++ Specific Potentially Breaking Changes
- A workaround for libstdc++4.7 has been removed. Note that 4.8.3 remains the oldest
supported libstdc++ version.

- Added ``!nonnull/!align`` metadata to load of references for better codegen.

ABI Changes in This Version
---------------------------

Expand Down
28 changes: 25 additions & 3 deletions clang/lib/CodeGen/CGExpr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2938,9 +2938,31 @@ CodeGenFunction::EmitLoadOfReference(LValue RefLVal,
llvm::LoadInst *Load =
Builder.CreateLoad(RefLVal.getAddress(), RefLVal.isVolatile());
CGM.DecorateInstructionWithTBAA(Load, RefLVal.getTBAAInfo());
return makeNaturalAddressForPointer(Load, RefLVal.getType()->getPointeeType(),
CharUnits(), /*ForPointeeType=*/true,
PointeeBaseInfo, PointeeTBAAInfo);
QualType PTy = RefLVal.getType()->getPointeeType();
CharUnits Align = CGM.getNaturalTypeAlignment(
PTy, PointeeBaseInfo, PointeeTBAAInfo, /*ForPointeeType=*/true);
if (!PTy->isIncompleteType()) {
llvm::LLVMContext &Ctx = getLLVMContext();
llvm::MDBuilder MDB(Ctx);
// Emit !nonnull metadata
if (CGM.getTypes().getTargetAddressSpace(PTy) == 0 &&
!CGM.getCodeGenOpts().NullPointerIsValid)
Load->setMetadata(llvm::LLVMContext::MD_nonnull,
llvm::MDNode::get(Ctx, {}));
// Emit !align metadata
if (PTy->isObjectType()) {
auto AlignVal = Align.getQuantity();
if (AlignVal > 1) {
Load->setMetadata(
llvm::LLVMContext::MD_align,
llvm::MDNode::get(Ctx, MDB.createConstant(llvm::ConstantInt::get(
Builder.getInt64Ty(), AlignVal))));
}
}
}
return makeNaturalAddressForPointer(Load, PTy, Align,
/*ForPointeeType=*/true, PointeeBaseInfo,
PointeeTBAAInfo);
}

LValue CodeGenFunction::EmitLoadOfReferenceLValue(LValue RefLVal) {
Expand Down
98 changes: 98 additions & 0 deletions clang/test/CodeGenCXX/load-reference-metadata.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --version 5
// RUN: %clang_cc1 -triple x86_64-linux-gnu -emit-llvm -std=c++11 -O1 -disable-llvm-passes %s -o - | FileCheck %s

struct alignas(32) F { int x; };

struct S {
char &a;
int &b;
F &c;
};

// CHECK-LABEL: define dso_local void @_Z4testR1S(
// CHECK-SAME: ptr noundef nonnull align 8 dereferenceable(24) [[S:%.*]]) #[[ATTR0:[0-9]+]] {
// CHECK-NEXT: [[ENTRY:.*:]]
// CHECK-NEXT: [[S_ADDR:%.*]] = alloca ptr, align 8
// CHECK-NEXT: store ptr [[S]], ptr [[S_ADDR]], align 8, !tbaa [[TBAA2:![0-9]+]]
// CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[S_ADDR]], align 8, !tbaa [[TBAA2]], !nonnull [[META7:![0-9]+]], !align [[META8:![0-9]+]]
// CHECK-NEXT: [[A:%.*]] = getelementptr inbounds nuw [[STRUCT_S:%.*]], ptr [[TMP0]], i32 0, i32 0
// CHECK-NEXT: [[TMP1:%.*]] = load ptr, ptr [[A]], align 8, !tbaa [[TBAA9:![0-9]+]], !nonnull [[META7]]
// CHECK-NEXT: store i8 0, ptr [[TMP1]], align 1, !tbaa [[TBAA14:![0-9]+]]
// CHECK-NEXT: [[TMP2:%.*]] = load ptr, ptr [[S_ADDR]], align 8, !tbaa [[TBAA2]], !nonnull [[META7]], !align [[META8]]
// CHECK-NEXT: [[B:%.*]] = getelementptr inbounds nuw [[STRUCT_S]], ptr [[TMP2]], i32 0, i32 1
// CHECK-NEXT: [[TMP3:%.*]] = load ptr, ptr [[B]], align 8, !tbaa [[TBAA15:![0-9]+]], !nonnull [[META7]], !align [[META16:![0-9]+]]
// CHECK-NEXT: store i32 0, ptr [[TMP3]], align 4, !tbaa [[TBAA17:![0-9]+]]
// CHECK-NEXT: [[TMP4:%.*]] = load ptr, ptr [[S_ADDR]], align 8, !tbaa [[TBAA2]], !nonnull [[META7]], !align [[META8]]
// CHECK-NEXT: [[C:%.*]] = getelementptr inbounds nuw [[STRUCT_S]], ptr [[TMP4]], i32 0, i32 2
// CHECK-NEXT: [[TMP5:%.*]] = load ptr, ptr [[C]], align 8, !tbaa [[TBAA19:![0-9]+]], !nonnull [[META7]], !align [[META20:![0-9]+]]
// CHECK-NEXT: [[X:%.*]] = getelementptr inbounds nuw [[STRUCT_F:%.*]], ptr [[TMP5]], i32 0, i32 0
// CHECK-NEXT: store i32 0, ptr [[X]], align 32, !tbaa [[TBAA21:![0-9]+]]
// CHECK-NEXT: ret void
//
void test(S &s) {
s.a = 0;
s.b = 0;
s.c.x = 0;
}

struct A { alignas(32) char x[32]; };
struct B : virtual A { long long b; char c; };
extern B& b;
extern B (&bb)[2];
// CHECK-LABEL: define dso_local void @_Z13test_externalv(
// CHECK-SAME: ) #[[ATTR0]] {
// CHECK-NEXT: [[ENTRY:.*:]]
// CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr @b, align 8, !tbaa [[TBAA23:![0-9]+]], !nonnull [[META7]], !align [[META8]]
// CHECK-NEXT: [[C:%.*]] = getelementptr inbounds nuw [[STRUCT_B:%.*]], ptr [[TMP0]], i32 0, i32 2
// CHECK-NEXT: store i8 0, ptr [[C]], align 8, !tbaa [[TBAA25:![0-9]+]]
// CHECK-NEXT: [[TMP1:%.*]] = load ptr, ptr @bb, align 8, !tbaa [[TBAA23]], !nonnull [[META7]], !align [[META20]]
// CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [2 x %struct.B], ptr [[TMP1]], i64 0, i64 0
// CHECK-NEXT: [[C1:%.*]] = getelementptr inbounds nuw [[STRUCT_B]], ptr [[ARRAYIDX]], i32 0, i32 2
// CHECK-NEXT: store i8 0, ptr [[C1]], align 16, !tbaa [[TBAA25]]
// CHECK-NEXT: ret void
//
void test_external() {
b.c = 0; // align 8
bb[0].c = 0; // align 32
}

// CHECK-LABEL: define dso_local noundef ptr @_Z15test_deref_onlyR1B(
// CHECK-SAME: ptr noundef nonnull align 8 dereferenceable(17) [[S:%.*]]) #[[ATTR0]] {
// CHECK-NEXT: [[ENTRY:.*:]]
// CHECK-NEXT: [[S_ADDR:%.*]] = alloca ptr, align 8
// CHECK-NEXT: store ptr [[S]], ptr [[S_ADDR]], align 8, !tbaa [[TBAA23]]
// CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[S_ADDR]], align 8, !tbaa [[TBAA23]], !nonnull [[META7]], !align [[META8]]
// CHECK-NEXT: [[C:%.*]] = getelementptr inbounds nuw [[STRUCT_B:%.*]], ptr [[TMP0]], i32 0, i32 2
// CHECK-NEXT: ret ptr [[C]]
//
char* test_deref_only(B &s) {
return &s.c;
}
//.
// CHECK: [[TBAA2]] = !{[[META3:![0-9]+]], [[META3]], i64 0}
// CHECK: [[META3]] = !{!"p1 _ZTS1S", [[META4:![0-9]+]], i64 0}
// CHECK: [[META4]] = !{!"any pointer", [[META5:![0-9]+]], i64 0}
// CHECK: [[META5]] = !{!"omnipotent char", [[META6:![0-9]+]], i64 0}
// CHECK: [[META6]] = !{!"Simple C++ TBAA"}
// CHECK: [[META7]] = !{}
// CHECK: [[META8]] = !{i64 8}
// CHECK: [[TBAA9]] = !{[[META10:![0-9]+]], [[META11:![0-9]+]], i64 0}
// CHECK: [[META10]] = !{!"_ZTS1S", [[META11]], i64 0, [[META12:![0-9]+]], i64 8, [[META13:![0-9]+]], i64 16}
// CHECK: [[META11]] = !{!"p1 omnipotent char", [[META4]], i64 0}
// CHECK: [[META12]] = !{!"p1 int", [[META4]], i64 0}
// CHECK: [[META13]] = !{!"p1 _ZTS1F", [[META4]], i64 0}
// CHECK: [[TBAA14]] = !{[[META5]], [[META5]], i64 0}
// CHECK: [[TBAA15]] = !{[[META10]], [[META12]], i64 8}
// CHECK: [[META16]] = !{i64 4}
// CHECK: [[TBAA17]] = !{[[META18:![0-9]+]], [[META18]], i64 0}
// CHECK: [[META18]] = !{!"int", [[META5]], i64 0}
// CHECK: [[TBAA19]] = !{[[META10]], [[META13]], i64 16}
// CHECK: [[META20]] = !{i64 32}
// CHECK: [[TBAA21]] = !{[[META22:![0-9]+]], [[META18]], i64 0}
// CHECK: [[META22]] = !{!"_ZTS1F", [[META18]], i64 0}
// CHECK: [[TBAA23]] = !{[[META24:![0-9]+]], [[META24]], i64 0}
// CHECK: [[META24]] = !{!"p1 _ZTS1B", [[META4]], i64 0}
// CHECK: [[TBAA25]] = !{[[META26:![0-9]+]], [[META5]], i64 16}
// CHECK: [[META26]] = !{!"_ZTS1B", [[META27:![0-9]+]], i64 8, [[META5]], i64 16}
// CHECK: [[META27]] = !{!"long long", [[META5]], i64 0}
//.
20 changes: 10 additions & 10 deletions clang/test/CodeGenCXX/matrix-type-operators.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -215,11 +215,11 @@ void insert(MyMatrix<EltTy, Rows, Columns> &Mat, EltTy e, unsigned i, unsigned j

void test_insert_template1(MyMatrix<unsigned, 2, 2> &Mat, unsigned e, unsigned i, unsigned j) {
// CHECK-LABEL: @_Z21test_insert_template1R8MyMatrixIjLj2ELj2EEjjj(
// NOOPT: [[MAT_ADDR:%.*]] = load ptr, ptr %Mat.addr, align 8{{$}}
// NOOPT: [[MAT_ADDR:%.*]] = load ptr, ptr %Mat.addr, align 8,
// NOOPT-NEXT: [[E:%.*]] = load i32, ptr %e.addr, align 4{{$}}
// NOOPT-NEXT: [[I:%.*]] = load i32, ptr %i.addr, align 4{{$}}
// NOOPT-NEXT: [[J:%.*]] = load i32, ptr %j.addr, align 4{{$}}
// OPT: [[MAT_ADDR:%.*]] = load ptr, ptr %Mat.addr, align 8, !tbaa !{{[0-9]+}}{{$}}
// OPT: [[MAT_ADDR:%.*]] = load ptr, ptr %Mat.addr, align 8, !tbaa !{{[0-9]+}},
// OPT-NEXT: [[E:%.*]] = load i32, ptr %e.addr, align 4, !tbaa !{{[0-9]+}}{{$}}
// OPT-NEXT: [[I:%.*]] = load i32, ptr %i.addr, align 4, !tbaa !{{[0-9]+}}{{$}}
// OPT-NEXT: [[J:%.*]] = load i32, ptr %j.addr, align 4, !tbaa !{{[0-9]+}}{{$}}
Expand Down Expand Up @@ -249,9 +249,9 @@ void test_insert_template1(MyMatrix<unsigned, 2, 2> &Mat, unsigned e, unsigned i

void test_insert_template2(MyMatrix<float, 3, 8> &Mat, float e) {
// CHECK-LABEL: @_Z21test_insert_template2R8MyMatrixIfLj3ELj8EEf(
// NOOPT: [[MAT_ADDR:%.*]] = load ptr, ptr %Mat.addr, align 8{{$}}
// NOOPT: [[MAT_ADDR:%.*]] = load ptr, ptr %Mat.addr, align 8,
// NOOPT-NEXT: [[E:%.*]] = load float, ptr %e.addr, align 4{{$}}
// OPT: [[MAT_ADDR:%.*]] = load ptr, ptr %Mat.addr, align 8, !tbaa !{{[0-9]+}}{{$}}
// OPT: [[MAT_ADDR:%.*]] = load ptr, ptr %Mat.addr, align 8, !tbaa !{{[0-9]+}},
// OPT-NEXT: [[E:%.*]] = load float, ptr %e.addr, align 4, !tbaa !{{[0-9]+}}{{$}}
// CHECK-NEXT: call void @_Z6insertIfLj3ELj8EEvR8MyMatrixIT_XT0_EXT1_EES1_jj(ptr noundef nonnull align 4 dereferenceable(96) [[MAT_ADDR]], float noundef [[E]], i32 noundef 2, i32 noundef 5)
// CHECK-NEXT: ret void
Expand Down Expand Up @@ -350,11 +350,11 @@ double extract_IntWrapper_idx(double4x4 &m, IntWrapper i, UnsignedWrapper j) {
// CHECK-NEXT: [[J_SUB_EXT:%.*]] = zext i32 [[J_SUB]] to i64
// CHECK-NEXT: [[IDX1:%.*]] = mul i64 [[J_SUB_EXT]], 4
// CHECK-NEXT: [[IDX2:%.*]] = add i64 [[IDX1]], [[I_ADD_EXT]]
// NOOPT-NEXT: [[MAT_ADDR:%.*]] = load ptr, ptr %m.addr, align 8{{$}}
// NOOPT-NEXT: [[MAT_ADDR:%.*]] = load ptr, ptr %m.addr, align 8,
// NOOPT-NEXT: [[MAT:%.*]] = load <16 x double>, ptr [[MAT_ADDR]], align 8{{$}}
// OPT-NEXT: [[CMP:%.*]] = icmp ult i64 [[IDX2]], 16
// OPT-NEXT: call void @llvm.assume(i1 [[CMP]])
// OPT-NEXT: [[MAT_ADDR:%.*]] = load ptr, ptr %m.addr, align 8, !tbaa !{{[0-9]+}}{{$}}
// OPT-NEXT: [[MAT_ADDR:%.*]] = load ptr, ptr %m.addr, align 8, !tbaa !{{[0-9]+}},
// OPT-NEXT: [[MAT:%.*]] = load <16 x double>, ptr [[MAT_ADDR]], align 8, !tbaa !{{[0-9]+}}{{$}}
// CHECK-NEXT: [[MATEXT:%.*]] = extractelement <16 x double> [[MAT]], i64 [[IDX2]]
// CHECK-NEXT: ret double [[MATEXT]]
Expand All @@ -381,8 +381,8 @@ void test_constexpr1(matrix_type<float, 4, 4> &m) {
// OPT: [[MAT:%.*]] = load <16 x float>, ptr {{.*}}, align 4, !tbaa !{{[0-9]+}}{{$}}
// CHECK-NEXT: [[IM:%.*]] = call noundef <16 x float> @_ZNK13identmatrix_tcvu11matrix_typeIXT0_EXT0_ET_EIfLj4EEEv(ptr {{[^,]*}} @_ZL11identmatrix)
// CHECK-NEXT: [[ADD:%.*]] = fadd <16 x float> [[MAT]], [[IM]]
// NOOPT-NEXT: [[MAT_ADDR:%.*]] = load ptr, ptr %m.addr, align 8{{$}}
// OPT-NEXT: [[MAT_ADDR:%.*]] = load ptr, ptr %m.addr, align 8, !tbaa !{{[0-9]+}}{{$}}
// NOOPT-NEXT: [[MAT_ADDR:%.*]] = load ptr, ptr %m.addr, align 8,
// OPT-NEXT: [[MAT_ADDR:%.*]] = load ptr, ptr %m.addr, align 8, !tbaa !{{[0-9]+}},
// CHECK-NEXT: store <16 x float> [[ADD]], ptr [[MAT_ADDR]], align 4
// CHECK-NEXT: ret voi

Expand Down Expand Up @@ -412,8 +412,8 @@ void test_constexpr2(matrix_type<int, 5, 5> &m) {
// OPT: [[MAT:%.*]] = load <25 x i32>, ptr {{.*}}, align 4, !tbaa !{{[0-9]+}}{{$}}
// CHECK-NEXT: [[SUB:%.*]] = sub <25 x i32> [[IM]], [[MAT]]
// CHECK-NEXT: [[SUB2:%.*]] = add <25 x i32> [[SUB]], splat (i32 1)
// NOOPT-NEXT: [[MAT_ADDR:%.*]] = load ptr, ptr %m.addr, align 8{{$}}
// OPT-NEXT: [[MAT_ADDR:%.*]] = load ptr, ptr %m.addr, align 8, !tbaa !{{[0-9]+}}{{$}}
// NOOPT-NEXT: [[MAT_ADDR:%.*]] = load ptr, ptr %m.addr, align 8,
// OPT-NEXT: [[MAT_ADDR:%.*]] = load ptr, ptr %m.addr, align 8, !tbaa !{{[0-9]+}},
// CHECK-NEXT: store <25 x i32> [[SUB2]], ptr [[MAT_ADDR]], align 4
// CHECK-NEXT: ret void
//
Expand Down
8 changes: 0 additions & 8 deletions clang/test/CodeGenCXX/reference-field.cpp

This file was deleted.

Loading