[llvm] ValueTracking: llvm.amdgcn.fract cannot introduce overflow (PR #189002)

Matt Arsenault via llvm-commits llvm-commits at lists.llvm.org
Fri Mar 27 06:55:29 PDT 2026


https://github.com/arsenm created https://github.com/llvm/llvm-project/pull/189002

This returns a value with an absolute value less than 1.

>From d8dec594b88134ce6c3dfece7c0be198587fe464 Mon Sep 17 00:00:00 2001
From: Matt Arsenault <Matthew.Arsenault at amd.com>
Date: Fri, 27 Mar 2026 14:42:06 +0100
Subject: [PATCH] ValueTracking: llvm.amdgcn.fract cannot introduce overflow

This returns a value with an absolute value less than 1.
---
 llvm/lib/Analysis/ValueTracking.cpp           |  3 ++-
 .../AMDGPU/nofpclass-amdgcn-fract.ll          | 26 +++++++++++++++++++
 2 files changed, 28 insertions(+), 1 deletion(-)

diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp
index 23b0e1de29931..eca4b98b21226 100644
--- a/llvm/lib/Analysis/ValueTracking.cpp
+++ b/llvm/lib/Analysis/ValueTracking.cpp
@@ -4978,7 +4978,8 @@ static constexpr KnownFPClass::MinMaxKind getMinMaxKind(Intrinsic::ID IID) {
 /// magnitude smaller than 1. i.e., fabs(X) <= 1.0
 static bool isAbsoluteValueLessEqualOne(const Value *V) {
   // TODO: Handle frexp and x - floor(x)?
-  return match(V, m_Intrinsic<Intrinsic::amdgcn_trig_preop>(m_Value()));
+  return match(V, m_Intrinsic<Intrinsic::amdgcn_trig_preop>(m_Value())) ||
+         match(V, m_Intrinsic<Intrinsic::amdgcn_fract>(m_Value()));
 }
 
 void computeKnownFPClass(const Value *V, const APInt &DemandedElts,
diff --git a/llvm/test/Transforms/Attributor/AMDGPU/nofpclass-amdgcn-fract.ll b/llvm/test/Transforms/Attributor/AMDGPU/nofpclass-amdgcn-fract.ll
index fc27e4144545f..92e841a39fd93 100644
--- a/llvm/test/Transforms/Attributor/AMDGPU/nofpclass-amdgcn-fract.ll
+++ b/llvm/test/Transforms/Attributor/AMDGPU/nofpclass-amdgcn-fract.ll
@@ -63,4 +63,30 @@ define double @ret_fract_no_nan_no_inf(double nofpclass(inf nan) %x) {
   ret double %fract
 }
 
+; Fract must be <= 1, so this cannot introduce overfloww
+define float @ret_not_inf__fmul__fract(float nofpclass(inf) %not.inf, float %x) {
+; CHECK-LABEL: define nofpclass(inf) float @ret_not_inf__fmul__fract(
+; CHECK-SAME: float nofpclass(inf) [[NOT_INF:%.*]], float [[X:%.*]]) #[[ATTR1]] {
+; CHECK-NEXT:    [[FRACT:%.*]] = call float @llvm.amdgcn.fract.f32(float [[X]]) #[[ATTR2]]
+; CHECK-NEXT:    [[MUL:%.*]] = fmul float [[NOT_INF]], [[FRACT]]
+; CHECK-NEXT:    ret float [[MUL]]
+;
+  %fract = call float @llvm.amdgcn.fract.f32(float %x)
+  %mul = fmul float %not.inf, %fract
+  ret float %mul
+}
+
+; Commuted
+define float @ret_fract__fmul__not_inf(float nofpclass(inf) %not.inf, float %x) {
+; CHECK-LABEL: define nofpclass(inf) float @ret_fract__fmul__not_inf(
+; CHECK-SAME: float nofpclass(inf) [[NOT_INF:%.*]], float [[X:%.*]]) #[[ATTR1]] {
+; CHECK-NEXT:    [[FRACT:%.*]] = call float @llvm.amdgcn.fract.f32(float [[X]]) #[[ATTR2]]
+; CHECK-NEXT:    [[MUL:%.*]] = fmul float [[FRACT]], [[NOT_INF]]
+; CHECK-NEXT:    ret float [[MUL]]
+;
+  %fract = call float @llvm.amdgcn.fract.f32(float %x)
+  %mul = fmul float %fract, %not.inf
+  ret float %mul
+}
+
 attributes #0 = { nocallback nofree nosync nounwind speculatable willreturn memory(none) }



More information about the llvm-commits mailing list