-
Notifications
You must be signed in to change notification settings - Fork 13.6k
[clang][CodeGen][AA] Introduce !llvm.errno.tbaa
for errno alias disambiguation
#125258
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
base: main
Are you sure you want to change the base?
[clang][CodeGen][AA] Introduce !llvm.errno.tbaa
for errno alias disambiguation
#125258
Conversation
@nikic Mind glancing over the draft quickly? !llvm.errno.tbaa is being attached to individual load/store accessing errno, although I just realized that this information is already embedded in TBAA, so IIUC !llvm.errno.tbaa should just be a module-level list of int-compatible TBAA nodes. Is my latest understanding correct? That would make it much simpler than I thought. Sorry if I’m missing something! |
Yes, exactly. It should be a module level MD node, not on individual instructions. |
7edf856
to
860a842
Compare
Thank you, I'm updating this. I've been contemplating this, and thought originally we needed to extend TBAA (like aliasErrno as per tmp commit, provided it is correct), but TBAA seems to take care of this already (as clang propagates int TBAA correctly to the call), so I think this shouldn't be needed. Though, I believe there should be some additional AA handling (along the ifdef lines), is that correct? |
The fact that clang currently places TBAA on FP libcalls is a hack that we want to remove. It doesn't work for libcalls that also access other memory. |
860a842
to
5a3404c
Compare
Right, that makes sense! Removing this from draft, hopefully it's heading in the correct direction. |
@llvm/pr-subscribers-clang-codegen @llvm/pr-subscribers-clang Author: Antonio Frighetto (antoniofrighetto) ChangesPatch is 203.79 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/125258.diff 29 Files Affected:
diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp
index 3caa79bb59096..5daf1a93fc2d9 100644
--- a/clang/lib/CodeGen/CodeGenModule.cpp
+++ b/clang/lib/CodeGen/CodeGenModule.cpp
@@ -83,6 +83,7 @@ static llvm::cl::opt<bool> LimitedCoverage(
llvm::cl::desc("Emit limited coverage mapping information (experimental)"));
static const char AnnotationSection[] = "llvm.metadata";
+static constexpr auto ErrnoTBAAMDName = "llvm.errno.tbaa";
static CGCXXABI *createCXXABI(CodeGenModule &CGM) {
switch (CGM.getContext().getCXXABIKind()) {
@@ -1458,6 +1459,17 @@ void CodeGenModule::Release() {
}
}
}
+
+ // Emit `!llvm.errno.tbaa`, a module-level metadata that specifies the TBAA
+ // for an integer access.
+ if (TBAA) {
+ TBAAAccessInfo TBAAInfo = getTBAAAccessInfo(Context.IntTy);
+ llvm::MDNode *IntegerNode = getTBAAAccessTagInfo(TBAAInfo);
+ if (IntegerNode) {
+ auto *ErrnoTBAAMD = TheModule.getOrInsertNamedMetadata(ErrnoTBAAMDName);
+ ErrnoTBAAMD->addOperand(IntegerNode);
+ }
+ }
}
void CodeGenModule::EmitOpenCLMetadata() {
diff --git a/clang/test/CodeGen/LoongArch/inline-asm-operand-modifiers.c b/clang/test/CodeGen/LoongArch/inline-asm-operand-modifiers.c
index b36fe7a7b69bb..bbb9962dd5dd2 100644
--- a/clang/test/CodeGen/LoongArch/inline-asm-operand-modifiers.c
+++ b/clang/test/CodeGen/LoongArch/inline-asm-operand-modifiers.c
@@ -6,7 +6,7 @@
// CHECK-LABEL: @test_z_zero(
// CHECK-NEXT: entry:
-// CHECK-NEXT: [[TMP0:%.*]] = tail call i32 asm sideeffect "add.w $0, $1, ${2:z}", "=r,r,ri"(i32 [[A:%.*]], i32 0) #[[ATTR1:[0-9]+]], !srcloc !2
+// CHECK-NEXT: [[TMP0:%.*]] = tail call i32 asm sideeffect "add.w $0, $1, ${2:z}", "=r,r,ri"(i32 [[A:%.*]], i32 0) #[[ATTR1:[0-9]+]], !srcloc [[META6:![0-9]+]]
// CHECK-NEXT: ret void
//
void test_z_zero(int a) {
@@ -16,7 +16,7 @@ void test_z_zero(int a) {
// CHECK-LABEL: @test_z_nonzero(
// CHECK-NEXT: entry:
-// CHECK-NEXT: [[TMP0:%.*]] = tail call i32 asm sideeffect "add.w $0, $1, ${2:z}", "=r,r,ri"(i32 [[A:%.*]], i32 1) #[[ATTR1]], !srcloc !3
+// CHECK-NEXT: [[TMP0:%.*]] = tail call i32 asm sideeffect "add.w $0, $1, ${2:z}", "=r,r,ri"(i32 [[A:%.*]], i32 1) #[[ATTR1]], !srcloc [[META7:![0-9]+]]
// CHECK-NEXT: ret void
//
void test_z_nonzero(int a) {
diff --git a/clang/test/CodeGen/LoongArch/lasx/inline-asm-gcc-regs.c b/clang/test/CodeGen/LoongArch/lasx/inline-asm-gcc-regs.c
index ed1a9660a06c9..0dc74ff63d089 100644
--- a/clang/test/CodeGen/LoongArch/lasx/inline-asm-gcc-regs.c
+++ b/clang/test/CodeGen/LoongArch/lasx/inline-asm-gcc-regs.c
@@ -4,7 +4,7 @@
typedef signed char v32i8 __attribute__((vector_size(32), aligned(32)));
// CHECK-LABEL: @test_xr0(
-// CHECK: tail call void asm sideeffect "", "{$xr0}"(<32 x i8> undef) #[[ATTR1:[0-9]+]], !srcloc !2
+// CHECK: tail call void asm sideeffect "", "{$xr0}"(<32 x i8> undef) #[[ATTR1:[0-9]+]], !srcloc [[META6:![0-9]+]]
//
void test_xr0() {
register v32i8 a asm ("$xr0");
@@ -12,7 +12,7 @@ void test_xr0() {
}
// CHECK-LABEL: @test_xr7(
-// CHECK: tail call void asm sideeffect "", "{$xr7}"(<32 x i8> undef) #[[ATTR1]], !srcloc !3
+// CHECK: tail call void asm sideeffect "", "{$xr7}"(<32 x i8> undef) #[[ATTR1]], !srcloc [[META7:![0-9]+]]
//
void test_xr7() {
register v32i8 a asm ("$xr7");
@@ -20,7 +20,7 @@ void test_xr7() {
}
// CHECK-LABEL: @test_xr15(
-// CHECK: tail call void asm sideeffect "", "{$xr15}"(<32 x i8> undef) #[[ATTR1]], !srcloc !4
+// CHECK: tail call void asm sideeffect "", "{$xr15}"(<32 x i8> undef) #[[ATTR1]], !srcloc [[META8:![0-9]+]]
//
void test_xr15() {
register v32i8 a asm ("$xr15");
@@ -28,7 +28,7 @@ void test_xr15() {
}
// CHECK-LABEL: @test_xr31(
-// CHECK: tail call void asm sideeffect "", "{$xr31}"(<32 x i8> undef) #[[ATTR1]], !srcloc !5
+// CHECK: tail call void asm sideeffect "", "{$xr31}"(<32 x i8> undef) #[[ATTR1]], !srcloc [[META9:![0-9]+]]
//
void test_xr31() {
register v32i8 a asm ("$xr31");
diff --git a/clang/test/CodeGen/LoongArch/lasx/inline-asm-operand-modifier.c b/clang/test/CodeGen/LoongArch/lasx/inline-asm-operand-modifier.c
index a5cc8798fd66b..cb5e6891885dc 100644
--- a/clang/test/CodeGen/LoongArch/lasx/inline-asm-operand-modifier.c
+++ b/clang/test/CodeGen/LoongArch/lasx/inline-asm-operand-modifier.c
@@ -6,7 +6,7 @@ typedef long long v4i64 __attribute__ ((vector_size(32), aligned(32)));
// CHECK-LABEL: define dso_local void @test_u
// CHECK-SAME: () local_unnamed_addr #[[ATTR0:[0-9]+]] {
// CHECK-NEXT: entry:
-// CHECK-NEXT: [[TMP0:%.*]] = tail call <4 x i64> asm sideeffect "xvldi ${0:u}, 1", "=f"() #[[ATTR1:[0-9]+]], !srcloc !2
+// CHECK-NEXT: [[TMP0:%.*]] = tail call <4 x i64> asm sideeffect "xvldi ${0:u}, 1", "=f"() #[[ATTR1:[0-9]+]], !srcloc [[META6:![0-9]+]]
// CHECK-NEXT: ret void
//
void test_u() {
diff --git a/clang/test/CodeGen/LoongArch/lsx/inline-asm-gcc-regs.c b/clang/test/CodeGen/LoongArch/lsx/inline-asm-gcc-regs.c
index b05b1c8c15fae..588a3a1249247 100644
--- a/clang/test/CodeGen/LoongArch/lsx/inline-asm-gcc-regs.c
+++ b/clang/test/CodeGen/LoongArch/lsx/inline-asm-gcc-regs.c
@@ -4,7 +4,7 @@
typedef signed char v16i8 __attribute__((vector_size(16), aligned(16)));
// CHECK-LABEL: @test_vr0(
-// CHECK: tail call void asm sideeffect "", "{$vr0}"(<16 x i8> undef) #[[ATTR1:[0-9]+]], !srcloc !2
+// CHECK: tail call void asm sideeffect "", "{$vr0}"(<16 x i8> undef) #[[ATTR1:[0-9]+]], !srcloc [[META6:![0-9]+]]
//
void test_vr0() {
register v16i8 a asm ("$vr0");
@@ -12,7 +12,7 @@ void test_vr0() {
}
// CHECK-LABEL: @test_vr7(
-// CHECK: tail call void asm sideeffect "", "{$vr7}"(<16 x i8> undef) #[[ATTR1]], !srcloc !3
+// CHECK: tail call void asm sideeffect "", "{$vr7}"(<16 x i8> undef) #[[ATTR1]], !srcloc [[META7:![0-9]+]]
//
void test_vr7() {
register v16i8 a asm ("$vr7");
@@ -20,7 +20,7 @@ void test_vr7() {
}
// CHECK-LABEL: @test_vr15(
-// CHECK: tail call void asm sideeffect "", "{$vr15}"(<16 x i8> undef) #[[ATTR1]], !srcloc !4
+// CHECK: tail call void asm sideeffect "", "{$vr15}"(<16 x i8> undef) #[[ATTR1]], !srcloc [[META8:![0-9]+]]
//
void test_vr15() {
register v16i8 a asm ("$vr15");
@@ -28,7 +28,7 @@ void test_vr15() {
}
// CHECK-LABEL: @test_vr31(
-// CHECK: tail call void asm sideeffect "", "{$vr31}"(<16 x i8> undef) #[[ATTR1]], !srcloc !5
+// CHECK: tail call void asm sideeffect "", "{$vr31}"(<16 x i8> undef) #[[ATTR1]], !srcloc [[META9:![0-9]+]]
//
void test_vr31() {
register v16i8 a asm ("$vr31");
diff --git a/clang/test/CodeGen/LoongArch/lsx/inline-asm-operand-modifier.c b/clang/test/CodeGen/LoongArch/lsx/inline-asm-operand-modifier.c
index 5e0fae984134e..f0fb6e31a1a02 100644
--- a/clang/test/CodeGen/LoongArch/lsx/inline-asm-operand-modifier.c
+++ b/clang/test/CodeGen/LoongArch/lsx/inline-asm-operand-modifier.c
@@ -6,7 +6,7 @@ typedef long long v2i64 __attribute__ ((vector_size(16), aligned(16)));
// CHECK-LABEL: define dso_local void @test_w
// CHECK-SAME: () local_unnamed_addr #[[ATTR0:[0-9]+]] {
// CHECK-NEXT: entry:
-// CHECK-NEXT: [[TMP0:%.*]] = tail call <2 x i64> asm sideeffect "vldi ${0:w}, 1", "=f"() #[[ATTR1:[0-9]+]], !srcloc !2
+// CHECK-NEXT: [[TMP0:%.*]] = tail call <2 x i64> asm sideeffect "vldi ${0:w}, 1", "=f"() #[[ATTR1:[0-9]+]], !srcloc [[META6:![0-9]+]]
// CHECK-NEXT: ret void
//
void test_w() {
diff --git a/clang/test/CodeGen/SystemZ/zvector2.c b/clang/test/CodeGen/SystemZ/zvector2.c
index b021ae8534353..11836ee007340 100644
--- a/clang/test/CodeGen/SystemZ/zvector2.c
+++ b/clang/test/CodeGen/SystemZ/zvector2.c
@@ -8,8 +8,8 @@ volatile vector bool int bi;
// CHECK-LABEL: define dso_local void @test_assign(
// CHECK-SAME: ) local_unnamed_addr #[[ATTR0:[0-9]+]] {
// CHECK-NEXT: [[ENTRY:.*:]]
-// CHECK-NEXT: [[TMP0:%.*]] = load volatile <4 x float>, ptr @ff2, align 8, !tbaa [[TBAA3:![0-9]+]]
-// CHECK-NEXT: store volatile <4 x float> [[TMP0]], ptr @ff, align 8, !tbaa [[TBAA3]]
+// CHECK-NEXT: [[TMP0:%.*]] = load volatile <4 x float>, ptr @ff2, align 8, !tbaa [[TBAA7:![0-9]+]]
+// CHECK-NEXT: store volatile <4 x float> [[TMP0]], ptr @ff, align 8, !tbaa [[TBAA7]]
// CHECK-NEXT: ret void
//
void test_assign (void)
@@ -20,8 +20,8 @@ void test_assign (void)
// CHECK-LABEL: define dso_local void @test_pos(
// CHECK-SAME: ) local_unnamed_addr #[[ATTR0]] {
// CHECK-NEXT: [[ENTRY:.*:]]
-// CHECK-NEXT: [[TMP0:%.*]] = load volatile <4 x float>, ptr @ff2, align 8, !tbaa [[TBAA3]]
-// CHECK-NEXT: store volatile <4 x float> [[TMP0]], ptr @ff, align 8, !tbaa [[TBAA3]]
+// CHECK-NEXT: [[TMP0:%.*]] = load volatile <4 x float>, ptr @ff2, align 8, !tbaa [[TBAA7]]
+// CHECK-NEXT: store volatile <4 x float> [[TMP0]], ptr @ff, align 8, !tbaa [[TBAA7]]
// CHECK-NEXT: ret void
//
void test_pos (void)
@@ -32,9 +32,9 @@ void test_pos (void)
// CHECK-LABEL: define dso_local void @test_neg(
// CHECK-SAME: ) local_unnamed_addr #[[ATTR0]] {
// CHECK-NEXT: [[ENTRY:.*:]]
-// CHECK-NEXT: [[TMP0:%.*]] = load volatile <4 x float>, ptr @ff2, align 8, !tbaa [[TBAA3]]
+// CHECK-NEXT: [[TMP0:%.*]] = load volatile <4 x float>, ptr @ff2, align 8, !tbaa [[TBAA7]]
// CHECK-NEXT: [[FNEG:%.*]] = fneg <4 x float> [[TMP0]]
-// CHECK-NEXT: store volatile <4 x float> [[FNEG]], ptr @ff, align 8, !tbaa [[TBAA3]]
+// CHECK-NEXT: store volatile <4 x float> [[FNEG]], ptr @ff, align 8, !tbaa [[TBAA7]]
// CHECK-NEXT: ret void
//
void test_neg (void)
@@ -45,9 +45,9 @@ void test_neg (void)
// CHECK-LABEL: define dso_local void @test_preinc(
// CHECK-SAME: ) local_unnamed_addr #[[ATTR0]] {
// CHECK-NEXT: [[ENTRY:.*:]]
-// CHECK-NEXT: [[TMP0:%.*]] = load volatile <4 x float>, ptr @ff2, align 8, !tbaa [[TBAA3]]
+// CHECK-NEXT: [[TMP0:%.*]] = load volatile <4 x float>, ptr @ff2, align 8, !tbaa [[TBAA7]]
// CHECK-NEXT: [[INC:%.*]] = fadd <4 x float> [[TMP0]], splat (float 1.000000e+00)
-// CHECK-NEXT: store volatile <4 x float> [[INC]], ptr @ff2, align 8, !tbaa [[TBAA3]]
+// CHECK-NEXT: store volatile <4 x float> [[INC]], ptr @ff2, align 8, !tbaa [[TBAA7]]
// CHECK-NEXT: ret void
//
void test_preinc (void)
@@ -58,9 +58,9 @@ void test_preinc (void)
// CHECK-LABEL: define dso_local void @test_postinc(
// CHECK-SAME: ) local_unnamed_addr #[[ATTR0]] {
// CHECK-NEXT: [[ENTRY:.*:]]
-// CHECK-NEXT: [[TMP0:%.*]] = load volatile <4 x float>, ptr @ff2, align 8, !tbaa [[TBAA3]]
+// CHECK-NEXT: [[TMP0:%.*]] = load volatile <4 x float>, ptr @ff2, align 8, !tbaa [[TBAA7]]
// CHECK-NEXT: [[INC:%.*]] = fadd <4 x float> [[TMP0]], splat (float 1.000000e+00)
-// CHECK-NEXT: store volatile <4 x float> [[INC]], ptr @ff2, align 8, !tbaa [[TBAA3]]
+// CHECK-NEXT: store volatile <4 x float> [[INC]], ptr @ff2, align 8, !tbaa [[TBAA7]]
// CHECK-NEXT: ret void
//
void test_postinc (void)
@@ -71,9 +71,9 @@ void test_postinc (void)
// CHECK-LABEL: define dso_local void @test_predec(
// CHECK-SAME: ) local_unnamed_addr #[[ATTR0]] {
// CHECK-NEXT: [[ENTRY:.*:]]
-// CHECK-NEXT: [[TMP0:%.*]] = load volatile <4 x float>, ptr @ff2, align 8, !tbaa [[TBAA3]]
+// CHECK-NEXT: [[TMP0:%.*]] = load volatile <4 x float>, ptr @ff2, align 8, !tbaa [[TBAA7]]
// CHECK-NEXT: [[DEC:%.*]] = fadd <4 x float> [[TMP0]], splat (float -1.000000e+00)
-// CHECK-NEXT: store volatile <4 x float> [[DEC]], ptr @ff2, align 8, !tbaa [[TBAA3]]
+// CHECK-NEXT: store volatile <4 x float> [[DEC]], ptr @ff2, align 8, !tbaa [[TBAA7]]
// CHECK-NEXT: ret void
//
void test_predec (void)
@@ -84,9 +84,9 @@ void test_predec (void)
// CHECK-LABEL: define dso_local void @test_postdec(
// CHECK-SAME: ) local_unnamed_addr #[[ATTR0]] {
// CHECK-NEXT: [[ENTRY:.*:]]
-// CHECK-NEXT: [[TMP0:%.*]] = load volatile <4 x float>, ptr @ff2, align 8, !tbaa [[TBAA3]]
+// CHECK-NEXT: [[TMP0:%.*]] = load volatile <4 x float>, ptr @ff2, align 8, !tbaa [[TBAA7]]
// CHECK-NEXT: [[DEC:%.*]] = fadd <4 x float> [[TMP0]], splat (float -1.000000e+00)
-// CHECK-NEXT: store volatile <4 x float> [[DEC]], ptr @ff2, align 8, !tbaa [[TBAA3]]
+// CHECK-NEXT: store volatile <4 x float> [[DEC]], ptr @ff2, align 8, !tbaa [[TBAA7]]
// CHECK-NEXT: ret void
//
void test_postdec (void)
@@ -97,10 +97,10 @@ void test_postdec (void)
// CHECK-LABEL: define dso_local void @test_add(
// CHECK-SAME: ) local_unnamed_addr #[[ATTR0]] {
// CHECK-NEXT: [[ENTRY:.*:]]
-// CHECK-NEXT: [[TMP0:%.*]] = load volatile <4 x float>, ptr @ff, align 8, !tbaa [[TBAA3]]
-// CHECK-NEXT: [[TMP1:%.*]] = load volatile <4 x float>, ptr @ff2, align 8, !tbaa [[TBAA3]]
+// CHECK-NEXT: [[TMP0:%.*]] = load volatile <4 x float>, ptr @ff, align 8, !tbaa [[TBAA7]]
+// CHECK-NEXT: [[TMP1:%.*]] = load volatile <4 x float>, ptr @ff2, align 8, !tbaa [[TBAA7]]
// CHECK-NEXT: [[ADD:%.*]] = fadd <4 x float> [[TMP0]], [[TMP1]]
-// CHECK-NEXT: store volatile <4 x float> [[ADD]], ptr @ff, align 8, !tbaa [[TBAA3]]
+// CHECK-NEXT: store volatile <4 x float> [[ADD]], ptr @ff, align 8, !tbaa [[TBAA7]]
// CHECK-NEXT: ret void
//
void test_add (void)
@@ -111,10 +111,10 @@ void test_add (void)
// CHECK-LABEL: define dso_local void @test_add_assign(
// CHECK-SAME: ) local_unnamed_addr #[[ATTR0]] {
// CHECK-NEXT: [[ENTRY:.*:]]
-// CHECK-NEXT: [[TMP0:%.*]] = load volatile <4 x float>, ptr @ff2, align 8, !tbaa [[TBAA3]]
-// CHECK-NEXT: [[TMP1:%.*]] = load volatile <4 x float>, ptr @ff, align 8, !tbaa [[TBAA3]]
+// CHECK-NEXT: [[TMP0:%.*]] = load volatile <4 x float>, ptr @ff2, align 8, !tbaa [[TBAA7]]
+// CHECK-NEXT: [[TMP1:%.*]] = load volatile <4 x float>, ptr @ff, align 8, !tbaa [[TBAA7]]
// CHECK-NEXT: [[ADD:%.*]] = fadd <4 x float> [[TMP0]], [[TMP1]]
-// CHECK-NEXT: store volatile <4 x float> [[ADD]], ptr @ff, align 8, !tbaa [[TBAA3]]
+// CHECK-NEXT: store volatile <4 x float> [[ADD]], ptr @ff, align 8, !tbaa [[TBAA7]]
// CHECK-NEXT: ret void
//
void test_add_assign (void)
@@ -125,10 +125,10 @@ void test_add_assign (void)
// CHECK-LABEL: define dso_local void @test_sub(
// CHECK-SAME: ) local_unnamed_addr #[[ATTR0]] {
// CHECK-NEXT: [[ENTRY:.*:]]
-// CHECK-NEXT: [[TMP0:%.*]] = load volatile <4 x float>, ptr @ff, align 8, !tbaa [[TBAA3]]
-// CHECK-NEXT: [[TMP1:%.*]] = load volatile <4 x float>, ptr @ff2, align 8, !tbaa [[TBAA3]]
+// CHECK-NEXT: [[TMP0:%.*]] = load volatile <4 x float>, ptr @ff, align 8, !tbaa [[TBAA7]]
+// CHECK-NEXT: [[TMP1:%.*]] = load volatile <4 x float>, ptr @ff2, align 8, !tbaa [[TBAA7]]
// CHECK-NEXT: [[SUB:%.*]] = fsub <4 x float> [[TMP0]], [[TMP1]]
-// CHECK-NEXT: store volatile <4 x float> [[SUB]], ptr @ff, align 8, !tbaa [[TBAA3]]
+// CHECK-NEXT: store volatile <4 x float> [[SUB]], ptr @ff, align 8, !tbaa [[TBAA7]]
// CHECK-NEXT: ret void
//
void test_sub (void)
@@ -139,10 +139,10 @@ void test_sub (void)
// CHECK-LABEL: define dso_local void @test_sub_assign(
// CHECK-SAME: ) local_unnamed_addr #[[ATTR0]] {
// CHECK-NEXT: [[ENTRY:.*:]]
-// CHECK-NEXT: [[TMP0:%.*]] = load volatile <4 x float>, ptr @ff2, align 8, !tbaa [[TBAA3]]
-// CHECK-NEXT: [[TMP1:%.*]] = load volatile <4 x float>, ptr @ff, align 8, !tbaa [[TBAA3]]
+// CHECK-NEXT: [[TMP0:%.*]] = load volatile <4 x float>, ptr @ff2, align 8, !tbaa [[TBAA7]]
+// CHECK-NEXT: [[TMP1:%.*]] = load volatile <4 x float>, ptr @ff, align 8, !tbaa [[TBAA7]]
// CHECK-NEXT: [[SUB:%.*]] = fsub <4 x float> [[TMP1]], [[TMP0]]
-// CHECK-NEXT: store volatile <4 x float> [[SUB]], ptr @ff, align 8, !tbaa [[TBAA3]]
+// CHECK-NEXT: store volatile <4 x float> [[SUB]], ptr @ff, align 8, !tbaa [[TBAA7]]
// CHECK-NEXT: ret void
//
void test_sub_assign (void)
@@ -153,10 +153,10 @@ void test_sub_assign (void)
// CHECK-LABEL: define dso_local void @test_mul(
// CHECK-SAME: ) local_unnamed_addr #[[ATTR0]] {
// CHECK-NEXT: [[ENTRY:.*:]]
-// CHECK-NEXT: [[TMP0:%.*]] = load volatile <4 x float>, ptr @ff, align 8, !tbaa [[TBAA3]]
-// CHECK-NEXT: [[TMP1:%.*]] = load volatile <4 x float>, ptr @ff2, align 8, !tbaa [[TBAA3]]
+// CHECK-NEXT: [[TMP0:%.*]] = load volatile <4 x float>, ptr @ff, align 8, !tbaa [[TBAA7]]
+// CHECK-NEXT: [[TMP1:%.*]] = load volatile <4 x float>, ptr @ff2, align 8, !tbaa [[TBAA7]]
// CHECK-NEXT: [[MUL:%.*]] = fmul <4 x float> [[TMP0]], [[TMP1]]
-// CHECK-NEXT: store volatile <4 x float> [[MUL]], ptr @ff, align 8, !tbaa [[TBAA3]]
+// CHECK-NEXT: store volatile <4 x float> [[MUL]], ptr @ff, align 8, !tbaa [[TBAA7]]
// CHECK-NEXT: ret void
//
void test_mul (void)
@@ -167,10 +167,10 @@ void test_mul (void)
// CHECK-LABEL: define dso_local void @test_mul_assign(
// CHECK-SAME: ) local_unnamed_addr #[[ATTR0]] {
// CHECK-NEXT: [[ENTRY:.*:]]
-// CHECK-NEXT: [[TMP0:%.*]] = load volatile <4 x float>, ptr @ff2, align 8, !tbaa [[TBAA3]]
-// CHECK-NEXT: [[TMP1:%.*]] = load volatile <4 x float>, ptr @ff, align 8, !tbaa [[TBAA3]]
+// CHECK-NEXT: [[TMP0:%.*]] = load volatile <4 x float>, ptr @ff2, align 8, !tbaa [[TBAA7]]
+// CHECK-NEXT: [[TMP1:%.*]] = load volatile <4 x float>, ptr @ff, align 8, !tbaa [[TBAA7]]
// CHECK-NEXT: [[MUL:%.*]] = fmul <4 x float> [[TMP0]], [[TMP1]]
-// CHECK-NEXT: store volatile <4 x float> [[MUL]], ptr @ff, align 8, !tbaa [[TBAA3]]
+// CHECK-NEXT: store volatile <4 x float> [[MUL]], ptr @ff, align 8, !tbaa [[TBAA7]]
// CHECK-NEXT: ret void
//
void test_mul_assign (void)
@@ -181,10 +181,10 @@ void test_mul_assign (void)
// CHECK-LABEL: define dso_local void @test_div(
// CHECK-SAME: ) local_unnamed_addr #[[ATTR0]] {
// CHECK-NEXT: [[ENTRY:.*:]]
-// CHECK-NEXT: [[TMP0:%.*]] = load volatile <4 x float>, ptr @ff, align 8, !tbaa [[TBAA3]]
-// CHECK-NEXT: [[TMP1:%.*]] = load volatile <4 x float>, ptr @ff2, align 8, !tbaa [[TBAA3]]
+// CHECK-NEXT: [[TMP0:%.*]] = load volatile <4 x float>, ptr @ff, align 8, !tbaa [[TBAA7]]
+// CHECK-NEXT: [[TMP1:%.*]] = load volatile <4 x float>, ptr @ff2, align 8, !tbaa [[TBAA7]]
// CHECK-NEXT: [[DIV:%.*]] = fdiv <4 x float> [[TMP0]], [[TMP1]]
-// CHECK-NEXT: store volatile <4 x float> [[DIV]], ptr @ff, align 8, !tbaa [[TBAA3]]
+// CHECK-NEXT: store volatile <4 x float> [[DIV]], ptr @ff, align 8, !tbaa [[TBAA7]]
// CHECK-NEXT: ret void
//
void test_div (void)
@@ -195,10 +195,10 @@ void test_div (void)
// CHECK-LABEL: define dso_local void @test_div_assign(
// CHECK-SAME: ) local_unnamed_addr #[[ATTR0]] {
// CHECK-NEXT: [[ENTRY:.*:]]
-// CHECK-NEXT: [[TMP0:%.*]] = load volatile <4 x float>, ptr @ff2, align 8, !tbaa [[TBAA3]]
-// CHECK-NEXT: [[TMP1:%.*]] = load volatile <4 x float>, ptr @ff, align 8, !tbaa [[TBAA3]]
+// CHECK-NEXT: [[TMP0:%.*]] = load volatile <4 x float>, ptr @ff2, align 8, !tbaa [[TBAA7]]
+// CHECK-NEXT: [[TMP1:%.*]] = load volatile <4 x float>, ptr @ff, align 8, !tbaa [[TBAA7]]
// CHECK-NEXT: [[DIV:%.*]] = fdiv <4 x float> [[TMP1]], [[TMP0]]
-// CHECK-NEXT: store volatile <4 x float> [[DIV]], ptr @ff, align 8, !tbaa [[TBAA3]]
+// CHECK-NEXT: store volatile <4 x float> [[DIV]], ptr @ff, align 8, !tbaa [[TBAA7]]
// CHECK-NEXT: ret void
//
void test_div_assign (void)
@@ -209,11 +209,11 @@ void test_div_assign (void)
// CHECK-LABEL: define dso_local void @test_cmpeq(
// CHECK-SAME: ) local_unnamed_addr #[[ATTR0]] {
// CHECK-NEXT: [[ENTRY:.*:]]
-// CHECK-NEXT: [[TMP0:%.*]] = load volatile <4 x float>, ptr @ff, align 8, !tbaa [[TBAA3]]
-// CHECK-NEXT: [[TMP1:%.*]] = load volatile <4 x float>, ptr @ff2, align 8, !tbaa [[TBAA3]]
+// CHECK-NEXT: [[TMP0:%.*]] = load volatile <4 x float>, ptr @ff, align 8, !tbaa [[TBAA7]]
+// CHECK-NEXT: [[TMP1:%.*]] = load volatile <4 x float>, ptr @ff2, align 8, !tbaa [[TBAA7]]
// CHECK-NEXT: [[CMP:%.*]] = fcmp oeq <4 x float> [[TMP0]], [[TMP1]]
// CHECK-NEXT: [[SEXT:%.*]] = sext <4 x i1> [[CMP]] to <4 x i32>
-// CHECK-NEXT: store volatile <4 x i32> [[SEXT]], ptr @bi, align 8, !tbaa [[TBAA3]]
+// CHECK-NEXT: store volatile <4 x i32> [[SEXT]], ptr @bi, align 8, !tbaa [[TBAA7]]
// CHECK-NEXT: ret void
//
void test_cmpeq (void)
@@ -224,11 +224,11 @@ void test_cmpeq (void)
// CHECK-LABEL: define dso_local void @test_cmpne(
// CHECK-SAME: ) local_unnamed_addr #[[ATTR0]] {
// CHECK-NEXT: [[ENTRY:.*:]]
-// CHECK-NEXT: [[TMP0:%.*]] = load volatile <4 x float>, ptr @ff, alig...
[truncated]
|
5a3404c
to
38b244c
Compare
38b244c
to
c2cd2ab
Compare
Rebased over 38e8dff. |
Kind ping. |
Gentle ping, would be nice moving this forward. |
Sorry, can you back up and explain the root problem you're trying to solve? You have a platform where we're emitting accesses to |
Oh, sorry for not providing context earlier. The reasoning behind is to allow certain optimizations involving errno-writing libcalls (marked as Original miscompilation issue: #114772, previous discussion at: https://discourse.llvm.org/t/rfc-modelling-errno-memory-effects/82972. |
I see. So the idea here is not that we're changing the TBAA nodes used for any actual accesses. Instead, we're using a named global metadata to specify the TBAA node that all |
…ambiguation Allow optimizations around errno-writing libcalls to take place (store-to-load forwarding amongst others), so long as we can prove the involved memory locations/accesses do not alias errno. This is achieved via a new named module-level metadata that specifies the TBAA node for an integer access, for which, errno accesses are guaranteed to use (per C standard). Ensure alias analysis masks out `errnomem` loc when: 1) TBAA proves there is no alias with errno, 2) the memory access size is larger than `sizeof(int)`, or 3) the underlying object is an (escaped) alloca. Previous discussion: https://discourse.llvm.org/t/rfc-modelling-errno-memory-effects/82972.
3bb97f4
to
32411b6
Compare
!llvm.errno.tbaa
gathering int-compatible TBAA nodes!llvm.errno.tbaa
for errno alias disambiguation
Thanks, commit message and PR title/description updated, hope this aligns better! Also, rebased to main, updated tests. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Functionality LGTM. I have a somewhat annoying request for the tests, but it should make things a lot easier for the next person.
@@ -1467,6 +1468,17 @@ void CodeGenModule::Release() { | |||
} | |||
} | |||
} | |||
|
|||
// Emit `!llvm.errno.tbaa`, a module-level metadata that specifies the TBAA | |||
// for an integer access. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
// for an integer access. | |
// for an int access. This allows LLVM to reason about what memory can | |
// be accessed by certain library calls that only touch errno. |
// C11-O2-NEXT: [[TMP1:%.*]] = load i32, ptr [[TMP0]], align 4, !tbaa [[TBAA7:![0-9]+]] | ||
// C11-O2-NEXT: store ptr [[ARRAYDECAY]], ptr [[P]], align 8, !tbaa [[TBAA6:![0-9]+]] | ||
// C11-O2-NEXT: [[TMP0:%.*]] = load ptr, ptr [[P]], align 8, !tbaa [[TBAA6]] | ||
// C11-O2-NEXT: [[TMP1:%.*]] = load i32, ptr [[TMP0]], align 4, !tbaa [[TBAA2:![0-9]+]] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since you're renaming these anyway, could you rename them to something semantic like INTPTR_TBAA
and INT_TBAA
? The number doesn't really mean anything to test readers, and when there are TBAA changes in the future, we want to just be able to change where INTPTR_TBAA
is matched in the metadata section rather than having to renumber all the variables in the tests every time.
(Same for the other tests)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The check lines here are autogenerated; if we edit anything by hand, we'll need to mark it as a test that can't be automatically regenerated. Which annoying not only right now, but in the future if the test ever needs to be updated.
It might be possible to make update_cc_test_checks.py choose better names for TBAA checks; in theory, it could take the type name from the metadata, and use it to choose the name of the tbaa variable.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Something like that would be great, because while I get why autogeneration is more than just a convenience, we do actually need to be reviewing autogenerated test changes, so spurious differences because autogen did something unstable is not a good use of reviewer time.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- The metadata should be documented in LangRef.
- We should test linking of two modules with the metadata. Both the case where they match and where they don't (e.g. mixing C and C++). IRLinker::linkNamedMDNodes should be the relevant code. (I do wonder whether we should instead be making this a module flag with AppendUnique behavior. I'm not sure clear on what the tradeoff is between a module flag and separate named metadata.)
declare float @sinf(float noundef) memory(errnomem: write) | ||
declare void @escape(ptr %p) | ||
|
||
!llvm.errno.tbaa = !{!0} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should add Verifier checks that this metadata is well-formed.
We should also test that the multi-operand form works correctly.
|
||
; sinf clobbering errno, but %p cannot alias errno per C/C++ strict aliasing rules via TBAA. | ||
; Hence, can do constant store-to-load forwarding. | ||
define float @does_not_alias_errno(ptr noundef %p, float noundef %f) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't need the noundef attributes.
if (!shouldUseTBAA()) | ||
return AliasResult::MayAlias; | ||
|
||
const auto *ErrnoTBAAMD = M->getNamedMetadata("llvm.errno.tbaa"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Avoid lookup if we don't have TBAA in the first place.
// Refine writes to errno memory. We can safely exclude the errno location if | ||
// the given memory location is an alloca, the size of the memory access is | ||
// larger than `sizeof(int)` or if TBAA proves it does not alias errno. | ||
if ((ErrnoMR | OtherMR) != OtherMR) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if ((ErrnoMR | OtherMR) != OtherMR) { | |
if ((ErrnoMR | Result) != Result) { |
Would be more efficient, I think?
// the given memory location is an alloca, the size of the memory access is | ||
// larger than `sizeof(int)` or if TBAA proves it does not alias errno. | ||
if ((ErrnoMR | OtherMR) != OtherMR) { | ||
bool IsLocSizeUnknown = Loc.Size == MemoryLocation::UnknownSize; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should check !Loc.Size.hasValue()
. There are multiple types of unknown sizes.
bool IsLocSizeUnknown = Loc.Size == MemoryLocation::UnknownSize; | ||
if (ErrnoMR == ModRefInfo::Mod && !isa<AllocaInst>(Object) && | ||
(IsLocSizeUnknown || | ||
(!IsLocSizeUnknown && Loc.Size.getValue() <= sizeof(int))) && |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should not use sizeof(int)
here, which is a host property. We should query the int
size from TLI instead.
if (ErrnoMR == ModRefInfo::Mod && !isa<AllocaInst>(Object) && | ||
(IsLocSizeUnknown || | ||
(!IsLocSizeUnknown && Loc.Size.getValue() <= sizeof(int))) && | ||
AAQI.AAR.aliasErrno(Loc, Call->getModule()) != AliasResult::NoAlias) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, possibly these extra checks should be in BasicAA::aliasErrno instead?
; CHECK-NEXT: ret float 0.000000e+00 | ||
; | ||
entry: | ||
store float 0.000000e+00, ptr %p, align 4, !tbaa !4 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Missing negative test that uses !0
instead.
It would probably be best to split up the LLVM and the Clang changes. |
Allow optimizations around errno-writing libcalls to take place (store-to-load forwarding amongst others), so long as we can prove the involved memory locations/accesses do not alias errno. This is achieved via a new named module-level metadata that specifies the TBAA node for an integer access, for which, errno accesses are guaranteed to use (per C standard).
Ensure alias analysis masks out
errnomem
loc when: 1) TBAA proves there is no alias with errno, 2) the memory access size is larger thansizeof(int)
, or 3) the underlying object is an (escaped) alloca.Previous discussion: https://discourse.llvm.org/t/rfc-modelling-errno-memory-effects/82972.