[clang] [llvm] [clang][CodeGen][AA] Add `!llvm.errno.tbaa` gathering int-compatible TBAA nodes (PR #125258)
Antonio Frighetto via cfe-commits
cfe-commits at lists.llvm.org
Fri Feb 21 06:01:38 PST 2025
https://github.com/antoniofrighetto updated https://github.com/llvm/llvm-project/pull/125258
>From 25e79b19581d47924c4b1a56d954031a09600b8f Mon Sep 17 00:00:00 2001
From: Antonio Frighetto <me at antoniofrighetto.com>
Date: Tue, 18 Feb 2025 16:36:12 +0100
Subject: [PATCH 1/3] [GVN] Introduce test for PR125258 (NFC)
---
.../test/Transforms/GVN/does-clobber-errno.ll | 27 +++++++++++++++++++
1 file changed, 27 insertions(+)
create mode 100644 llvm/test/Transforms/GVN/does-clobber-errno.ll
diff --git a/llvm/test/Transforms/GVN/does-clobber-errno.ll b/llvm/test/Transforms/GVN/does-clobber-errno.ll
new file mode 100644
index 0000000000000..4c68789a09dcd
--- /dev/null
+++ b/llvm/test/Transforms/GVN/does-clobber-errno.ll
@@ -0,0 +1,27 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5
+; RUN: opt -passes=gvn -S < %s | FileCheck %s
+
+; FIXME: This is a miscompilation.
+define noundef i32 @test_malloc_clobbering_errno() {
+; CHECK-LABEL: define noundef i32 @test_malloc_clobbering_errno() {
+; CHECK-NEXT: [[TMP1:%.*]] = alloca ptr, align 8
+; CHECK-NEXT: [[TMP2:%.*]] = call ptr @__errno_location()
+; CHECK-NEXT: store i32 0, ptr [[TMP2]], align 4
+; CHECK-NEXT: [[TMP3:%.*]] = call noalias ptr @malloc(i64 1844674407370955161)
+; CHECK-NEXT: store volatile ptr [[TMP3]], ptr [[TMP1]], align 8
+; CHECK-NEXT: ret i32 0
+;
+ %1 = alloca ptr, align 8
+ %2 = call ptr @__errno_location()
+ store i32 0, ptr %2, align 4
+ %3 = call noalias ptr @malloc(i64 1844674407370955161)
+ store volatile ptr %3, ptr %1, align 8
+ %4 = load i32, ptr %2, align 4
+ ret i32 %4
+}
+
+declare ptr @__errno_location() #1
+declare noalias ptr @malloc(i64) #2
+
+attributes #1 = { mustprogress nofree nosync nounwind willreturn memory(none) }
+attributes #2 = { mustprogress nofree nounwind willreturn memory(inaccessiblemem: readwrite) }
>From b88ac9fb739ac495c31f09a57afcf240be84bab5 Mon Sep 17 00:00:00 2001
From: Antonio Frighetto <me at antoniofrighetto.com>
Date: Tue, 18 Feb 2025 15:32:09 +0100
Subject: [PATCH 2/3] [clang][CodeGen][AA] Add `!llvm.errno.tbaa` listing
int-compatible TBAA nodes
Model integer accesses through an ad-hoc TBAA module-level metadata, so as to
disambiguate integer accesses from non-integer ones, at TBAA level. This is
purposefully as part of handling `errno` accesses, which are guaranteed to be
integer-compatible.
---
clang/lib/CodeGen/CodeGenModule.cpp | 7 +++
.../test/Transforms/GVN/does-clobber-errno.ll | 6 +--
.../Transforms/InstCombine/may-alias-errno.ll | 49 +++++++++++++++++++
3 files changed, 59 insertions(+), 3 deletions(-)
create mode 100644 llvm/test/Transforms/InstCombine/may-alias-errno.ll
diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp
index 7924c32fcf633..3e8917a7b587d 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()) {
@@ -1457,6 +1458,12 @@ void CodeGenModule::Release() {
}
}
}
+
+ if (TBAA) {
+ auto *ErrnoTBAAMD = TheModule.getOrInsertNamedMetadata(ErrnoTBAAMDName);
+ llvm::MDNode *IntegerNode = TBAA->getTypeInfo(Context.IntTy);
+ ErrnoTBAAMD->addOperand(IntegerNode);
+ }
}
void CodeGenModule::EmitOpenCLMetadata() {
diff --git a/llvm/test/Transforms/GVN/does-clobber-errno.ll b/llvm/test/Transforms/GVN/does-clobber-errno.ll
index 4c68789a09dcd..7c625b10eac7b 100644
--- a/llvm/test/Transforms/GVN/does-clobber-errno.ll
+++ b/llvm/test/Transforms/GVN/does-clobber-errno.ll
@@ -1,7 +1,6 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5
; RUN: opt -passes=gvn -S < %s | FileCheck %s
-; FIXME: This is a miscompilation.
define noundef i32 @test_malloc_clobbering_errno() {
; CHECK-LABEL: define noundef i32 @test_malloc_clobbering_errno() {
; CHECK-NEXT: [[TMP1:%.*]] = alloca ptr, align 8
@@ -9,7 +8,8 @@ define noundef i32 @test_malloc_clobbering_errno() {
; CHECK-NEXT: store i32 0, ptr [[TMP2]], align 4
; CHECK-NEXT: [[TMP3:%.*]] = call noalias ptr @malloc(i64 1844674407370955161)
; CHECK-NEXT: store volatile ptr [[TMP3]], ptr [[TMP1]], align 8
-; CHECK-NEXT: ret i32 0
+; CHECK-NEXT: [[TMP4:%.*]] = load i32, ptr [[TMP2]], align 4
+; CHECK-NEXT: ret i32 [[TMP4]]
;
%1 = alloca ptr, align 8
%2 = call ptr @__errno_location()
@@ -24,4 +24,4 @@ declare ptr @__errno_location() #1
declare noalias ptr @malloc(i64) #2
attributes #1 = { mustprogress nofree nosync nounwind willreturn memory(none) }
-attributes #2 = { mustprogress nofree nounwind willreturn memory(inaccessiblemem: readwrite) }
+attributes #2 = { mustprogress nofree nounwind willreturn memory(inaccessiblemem: readwrite, errnomem: readwrite) }
diff --git a/llvm/test/Transforms/InstCombine/may-alias-errno.ll b/llvm/test/Transforms/InstCombine/may-alias-errno.ll
new file mode 100644
index 0000000000000..cd4a39815a904
--- /dev/null
+++ b/llvm/test/Transforms/InstCombine/may-alias-errno.ll
@@ -0,0 +1,49 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5
+; RUN: opt -S -passes=instcombine < %s | FileCheck %s
+
+; 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) {
+; CHECK-LABEL: define float @does_not_alias_errno(
+; CHECK-SAME: ptr noundef [[P:%.*]], float noundef [[F:%.*]]) {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: store float 0.000000e+00, ptr [[P]], align 4, !tbaa [[TBAA3:![0-9]+]]
+; CHECK-NEXT: [[CALL:%.*]] = call float @sinf(float noundef [[F]]), !tbaa [[TBAA5:![0-9]+]]
+; CHECK-NEXT: ret float 0.000000e+00
+;
+entry:
+ store float 0.000000e+00, ptr %p, align 4, !tbaa !3
+ %call = call float @sinf(float noundef %f), !tbaa !10
+ %0 = load float, ptr %p, align 4, !tbaa !3
+ ret float %0
+}
+
+; sinf clobbering errno, unknown TBAA info, %p may alias errno
+define float @may_alias_errno(ptr noundef %p, float noundef %f) {
+; CHECK-LABEL: define float @may_alias_errno(
+; CHECK-SAME: ptr noundef [[P:%.*]], float noundef [[F:%.*]]) {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: store float 0.000000e+00, ptr [[P]], align 4
+; CHECK-NEXT: [[CALL:%.*]] = call float @sinf(float noundef [[F]])
+; CHECK-NEXT: [[TMP0:%.*]] = load float, ptr [[P]], align 4
+; CHECK-NEXT: ret float [[TMP0]]
+;
+entry:
+ store float 0.000000e+00, ptr %p, align 4
+ %call = call float @sinf(float noundef %f)
+ %0 = load float, ptr %p, align 4
+ ret float %0
+}
+
+declare float @sinf(float noundef) #1
+
+attributes #1 = { mustprogress nofree nounwind willreturn memory(errnomem: write) }
+
+!llvm.errno.tbaa = !{!0}
+
+!0 = !{!"int", !1, i64 0}
+!1 = !{!"omnipotent char", !2, i64 0}
+!2 = !{!"Simple C/C++ TBAA"}
+!3 = !{!4, !4, i64 0}
+!4 = !{!"float", !1, i64 0}
+!10 = !{!0, !0, i64 0}
>From 860a842b07fa2d3384b19bc182a617098b387cac Mon Sep 17 00:00:00 2001
From: Antonio Frighetto <me at antoniofrighetto.com>
Date: Fri, 21 Feb 2025 14:51:35 +0100
Subject: [PATCH 3/3] tmp
---
llvm/include/llvm/Analysis/AliasAnalysis.h | 14 +++++++++++++
.../llvm/Analysis/TypeBasedAliasAnalysis.h | 1 +
llvm/lib/Analysis/AliasAnalysis.cpp | 20 +++++++++++++++++++
llvm/lib/Analysis/TypeBasedAliasAnalysis.cpp | 15 ++++++++++++++
4 files changed, 50 insertions(+)
diff --git a/llvm/include/llvm/Analysis/AliasAnalysis.h b/llvm/include/llvm/Analysis/AliasAnalysis.h
index b192a9f5e65e7..4ef461bc44f4c 100644
--- a/llvm/include/llvm/Analysis/AliasAnalysis.h
+++ b/llvm/include/llvm/Analysis/AliasAnalysis.h
@@ -572,6 +572,7 @@ class AAResults {
// relationship holds through the entire function.
AliasResult alias(const MemoryLocation &LocA, const MemoryLocation &LocB,
AAQueryInfo &AAQI, const Instruction *CtxI = nullptr);
+ AliasResult aliasErrno(const MemoryLocation &Loc, const Module *M);
ModRefInfo getModRefInfoMask(const MemoryLocation &Loc, AAQueryInfo &AAQI,
bool IgnoreLocals = false);
@@ -718,6 +719,11 @@ class AAResults::Concept {
const MemoryLocation &LocB, AAQueryInfo &AAQI,
const Instruction *CtxI) = 0;
+ /// Returns an AliasResult indicating whether a specific memory location
+ /// aliases errno.
+ virtual AliasResult aliasErrno(const MemoryLocation &Loc,
+ const Module *M) = 0;
+
/// @}
//===--------------------------------------------------------------------===//
/// \name Simple mod/ref information
@@ -779,6 +785,10 @@ template <typename AAResultT> class AAResults::Model final : public Concept {
return Result.alias(LocA, LocB, AAQI, CtxI);
}
+ AliasResult aliasErrno(const MemoryLocation &Loc, const Module *M) override {
+ return Result.aliasErrno(Loc, M);
+ }
+
ModRefInfo getModRefInfoMask(const MemoryLocation &Loc, AAQueryInfo &AAQI,
bool IgnoreLocals) override {
return Result.getModRefInfoMask(Loc, AAQI, IgnoreLocals);
@@ -834,6 +844,10 @@ class AAResultBase {
return AliasResult::MayAlias;
}
+ AliasResult aliasErrno(const MemoryLocation &Loc, const Module *M) {
+ return AliasResult::MayAlias;
+ }
+
ModRefInfo getModRefInfoMask(const MemoryLocation &Loc, AAQueryInfo &AAQI,
bool IgnoreLocals) {
return ModRefInfo::ModRef;
diff --git a/llvm/include/llvm/Analysis/TypeBasedAliasAnalysis.h b/llvm/include/llvm/Analysis/TypeBasedAliasAnalysis.h
index e70f35174e4ca..81ee271b245f8 100644
--- a/llvm/include/llvm/Analysis/TypeBasedAliasAnalysis.h
+++ b/llvm/include/llvm/Analysis/TypeBasedAliasAnalysis.h
@@ -48,6 +48,7 @@ class TypeBasedAAResult : public AAResultBase {
AliasResult alias(const MemoryLocation &LocA, const MemoryLocation &LocB,
AAQueryInfo &AAQI, const Instruction *CtxI);
+ AliasResult aliasErrno(const MemoryLocation &Loc, const Module *M);
ModRefInfo getModRefInfoMask(const MemoryLocation &Loc, AAQueryInfo &AAQI,
bool IgnoreLocals);
diff --git a/llvm/lib/Analysis/AliasAnalysis.cpp b/llvm/lib/Analysis/AliasAnalysis.cpp
index 1a9136e464d25..651b9e0d06757 100644
--- a/llvm/lib/Analysis/AliasAnalysis.cpp
+++ b/llvm/lib/Analysis/AliasAnalysis.cpp
@@ -146,6 +146,18 @@ AliasResult AAResults::alias(const MemoryLocation &LocA,
return Result;
}
+AliasResult AAResults::aliasErrno(const MemoryLocation &Loc, const Module *M) {
+ AliasResult Result = AliasResult::MayAlias;
+
+ for (const auto &AA : AAs) {
+ Result = AA->aliasErrno(Loc, M);
+ if (Result != AliasResult::MayAlias)
+ break;
+ }
+
+ return Result;
+}
+
ModRefInfo AAResults::getModRefInfoMask(const MemoryLocation &Loc,
bool IgnoreLocals) {
SimpleAAQueryInfo AAQIP(*this);
@@ -253,6 +265,14 @@ ModRefInfo AAResults::getModRefInfo(const CallBase *Call,
Result &= ArgMR | OtherMR;
+#if 0
+ // AA can mask out ErrnoMem, despite the call-site clobbering errno, if we can
+ // prove the location does not alias errno. Done only via TBAA, for now.
+ if (ME.getModRef(IRMemLocation::ErrnoMem) != ModRefInfo::NoModRef)
+ if (aliasErrno(Loc, Call->getModule()) == AliasResult::NoAlias)
+ Result &= ME.getWithoutLoc(IRMemLocation::ErrnoMem).getModRef();
+#endif
+
// Apply the ModRef mask. This ensures that if Loc is a constant memory
// location, we take into account the fact that the call definitely could not
// modify the memory location.
diff --git a/llvm/lib/Analysis/TypeBasedAliasAnalysis.cpp b/llvm/lib/Analysis/TypeBasedAliasAnalysis.cpp
index 3f44f746eb173..704a6ef81def3 100644
--- a/llvm/lib/Analysis/TypeBasedAliasAnalysis.cpp
+++ b/llvm/lib/Analysis/TypeBasedAliasAnalysis.cpp
@@ -115,6 +115,7 @@
#include "llvm/IR/InstrTypes.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Metadata.h"
+#include "llvm/IR/Module.h"
#include "llvm/InitializePasses.h"
#include "llvm/Pass.h"
#include "llvm/Support/Casting.h"
@@ -385,6 +386,20 @@ AliasResult TypeBasedAAResult::alias(const MemoryLocation &LocA,
return AliasResult::NoAlias;
}
+AliasResult TypeBasedAAResult::aliasErrno(const MemoryLocation &Loc,
+ const Module *M) {
+ if (!shouldUseTBAA())
+ return AliasResult::MayAlias;
+
+ const auto *ErrnoTBAAMD = M->getNamedMetadata("llvm.errno.tbaa");
+ const auto *N = Loc.AATags.TBAA;
+ if (!ErrnoTBAAMD || !N ||
+ llvm::any_of(ErrnoTBAAMD->operands(),
+ [&](const auto *Node) { return Aliases(N, Node); }))
+ return AliasResult::MayAlias;
+ return AliasResult::NoAlias;
+}
+
ModRefInfo TypeBasedAAResult::getModRefInfoMask(const MemoryLocation &Loc,
AAQueryInfo &AAQI,
bool IgnoreLocals) {
More information about the cfe-commits
mailing list