[llvm] [msan] Handle fpto[us]i_sat (PR #196429)
Thurston Dang via llvm-commits
llvm-commits at lists.llvm.org
Thu May 7 14:53:15 PDT 2026
https://github.com/thurstond updated https://github.com/llvm/llvm-project/pull/196429
>From 5c5ce3050ed20482ff120dd25002c01ce4ea0c0b Mon Sep 17 00:00:00 2001
From: Thurston Dang <thurston at google.com>
Date: Thu, 7 May 2026 21:42:26 +0000
Subject: [PATCH 1/2] [msan] Handle fpto[us]i_sat
This adds explicit handling for fpto[us]i_sat, similar to how the
non-saturating versions are handled.
N.B. PR #191365 lowered NEON fcvtz[us] intrinsics into fpto[us]i.sat.
There is a slight inconsistency in MSan insofar as the former were
handled by handleNEONVectorConvertIntrinsic(), which takes an
all-or-nothing propagation approach to the shadows (i.e., even a single
uninitialized bit will result in the corresponding integer being fully
uninitialized). For now, we choose to follow the laxer behavior of
fpto[usi. Future work may consider changing the behavior of fpto[us]i
and fpto[us]i_sat to use the all-or-nothing approach.
---
.../Instrumentation/MemorySanitizer.cpp | 9 +++++++
.../Instrumentation/MemorySanitizer/ftrunc.ll | 26 +++++--------------
2 files changed, 16 insertions(+), 19 deletions(-)
diff --git a/llvm/lib/Transforms/Instrumentation/MemorySanitizer.cpp b/llvm/lib/Transforms/Instrumentation/MemorySanitizer.cpp
index 933865f9cb7be..a69177b54ae95 100644
--- a/llvm/lib/Transforms/Instrumentation/MemorySanitizer.cpp
+++ b/llvm/lib/Transforms/Instrumentation/MemorySanitizer.cpp
@@ -5864,6 +5864,15 @@ struct MemorySanitizerVisitor : public InstVisitor<MemorySanitizerVisitor> {
setOrigin(&I, getCleanOrigin());
break;
+ // The non-saturating versions are handled by visitFPTo[US]IInst().
+ //
+ // N.B. some platform-specific intrinsics, such as Aarch64 fcvtz[us], are
+ // lowered to these cross-platform intrinsics.
+ case Intrinsic::fptosi_sat:
+ case Intrinsic::fptoui_sat:
+ handleShadowOr(I);
+ break;
+
default:
return false;
}
diff --git a/llvm/test/Instrumentation/MemorySanitizer/ftrunc.ll b/llvm/test/Instrumentation/MemorySanitizer/ftrunc.ll
index e061a1048a6ef..878bdd24eed73 100644
--- a/llvm/test/Instrumentation/MemorySanitizer/ftrunc.ll
+++ b/llvm/test/Instrumentation/MemorySanitizer/ftrunc.ll
@@ -3,8 +3,9 @@
;
; Forked from llvm/test/Instrumentation/MemorySanitizer/ftrunc.ll
;
-; Handled strictly:
-; - llvm.fptoui.sat, llvm.fptosi.sat
+; Handled strictly: (none)
+;
+; Handled heuristically: (none)
;
; REQUIRES: x86-registered-target
@@ -235,15 +236,10 @@ define float @trunc_unsigned_f32_disable_via_intrinsic(float %x) #0 {
; CHECK-SAME: float [[X:%.*]]) #[[ATTR1]] {
; CHECK-NEXT: [[TMP1:%.*]] = load i32, ptr @__msan_param_tls, align 8
; CHECK-NEXT: call void @llvm.donothing()
-; CHECK-NEXT: [[_MSCMP:%.*]] = icmp ne i32 [[TMP1]], 0
-; CHECK-NEXT: br i1 [[_MSCMP]], label %[[BB2:.*]], label %[[BB3:.*]], !prof [[PROF1:![0-9]+]]
-; CHECK: [[BB2]]:
-; CHECK-NEXT: call void @__msan_warning_noreturn() #[[ATTR4:[0-9]+]]
-; CHECK-NEXT: unreachable
-; CHECK: [[BB3]]:
+; CHECK-NEXT: [[_MSPROP:%.*]] = or i32 [[TMP1]], 0
; CHECK-NEXT: [[I:%.*]] = call i32 @llvm.fptoui.sat.i32.f32(float [[X]])
; CHECK-NEXT: [[R:%.*]] = uitofp i32 [[I]] to float
-; CHECK-NEXT: store i32 0, ptr @__msan_retval_tls, align 8
+; CHECK-NEXT: store i32 [[_MSPROP]], ptr @__msan_retval_tls, align 8
; CHECK-NEXT: ret float [[R]]
;
%i = call i32 @llvm.fptoui.sat.i32.f32(float %x)
@@ -256,15 +252,10 @@ define double @trunc_signed_f64_disable_via_intrinsic(double %x) #0 {
; CHECK-SAME: double [[X:%.*]]) #[[ATTR1]] {
; CHECK-NEXT: [[TMP1:%.*]] = load i64, ptr @__msan_param_tls, align 8
; CHECK-NEXT: call void @llvm.donothing()
-; CHECK-NEXT: [[_MSCMP:%.*]] = icmp ne i64 [[TMP1]], 0
-; CHECK-NEXT: br i1 [[_MSCMP]], label %[[BB2:.*]], label %[[BB3:.*]], !prof [[PROF1]]
-; CHECK: [[BB2]]:
-; CHECK-NEXT: call void @__msan_warning_noreturn() #[[ATTR4]]
-; CHECK-NEXT: unreachable
-; CHECK: [[BB3]]:
+; CHECK-NEXT: [[_MSPROP:%.*]] = or i64 [[TMP1]], 0
; CHECK-NEXT: [[I:%.*]] = call i64 @llvm.fptosi.sat.i64.f64(double [[X]])
; CHECK-NEXT: [[R:%.*]] = sitofp i64 [[I]] to double
-; CHECK-NEXT: store i64 0, ptr @__msan_retval_tls, align 8
+; CHECK-NEXT: store i64 [[_MSPROP]], ptr @__msan_retval_tls, align 8
; CHECK-NEXT: ret double [[R]]
;
%i = call i64 @llvm.fptosi.sat.i64.f64(double %x)
@@ -273,6 +264,3 @@ define double @trunc_signed_f64_disable_via_intrinsic(double %x) #0 {
}
attributes #0 = { sanitize_memory }
-;.
-; CHECK: [[PROF1]] = !{!"branch_weights", i32 1, i32 1048575}
-;.
>From c1ba44e7934882bc7bd7758331142b12b9d24459 Mon Sep 17 00:00:00 2001
From: Thurston Dang <thurston at google.com>
Date: Thu, 7 May 2026 21:52:57 +0000
Subject: [PATCH 2/2] clang-format
---
.../Transforms/Instrumentation/MemorySanitizer.cpp | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/llvm/lib/Transforms/Instrumentation/MemorySanitizer.cpp b/llvm/lib/Transforms/Instrumentation/MemorySanitizer.cpp
index a69177b54ae95..980edc14ff57c 100644
--- a/llvm/lib/Transforms/Instrumentation/MemorySanitizer.cpp
+++ b/llvm/lib/Transforms/Instrumentation/MemorySanitizer.cpp
@@ -5864,12 +5864,12 @@ struct MemorySanitizerVisitor : public InstVisitor<MemorySanitizerVisitor> {
setOrigin(&I, getCleanOrigin());
break;
- // The non-saturating versions are handled by visitFPTo[US]IInst().
- //
- // N.B. some platform-specific intrinsics, such as Aarch64 fcvtz[us], are
- // lowered to these cross-platform intrinsics.
- case Intrinsic::fptosi_sat:
- case Intrinsic::fptoui_sat:
+ // The non-saturating versions are handled by visitFPTo[US]IInst().
+ //
+ // N.B. some platform-specific intrinsics, such as Aarch64 fcvtz[us], are
+ // lowered to these cross-platform intrinsics.
+ case Intrinsic::fptosi_sat:
+ case Intrinsic::fptoui_sat:
handleShadowOr(I);
break;
More information about the llvm-commits
mailing list