[llvm] ValueTracking: Check if x is undef for fma(x, x, y) analysis (PR #174763)

Matt Arsenault via llvm-commits llvm-commits at lists.llvm.org
Wed Jan 7 09:04:15 PST 2026


https://github.com/arsenm updated https://github.com/llvm/llvm-project/pull/174763

>From 6e4eba11ba012f7b45266ec23204e059f2f5c994 Mon Sep 17 00:00:00 2001
From: Matt Arsenault <Matthew.Arsenault at amd.com>
Date: Wed, 7 Jan 2026 09:11:16 +0100
Subject: [PATCH] ValueTracking: Check if x is undef for fma(x, x, y) analysis

---
 llvm/lib/Analysis/ValueTracking.cpp           |  4 +-
 .../Transforms/Attributor/nofpclass-fma.ll    | 54 ++++++++++++++-----
 llvm/test/Transforms/InstCombine/fabs.ll      |  6 +--
 3 files changed, 48 insertions(+), 16 deletions(-)

diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp
index ce80025f45e3d..53d3ffc6ca437 100644
--- a/llvm/lib/Analysis/ValueTracking.cpp
+++ b/llvm/lib/Analysis/ValueTracking.cpp
@@ -5101,7 +5101,9 @@ void computeKnownFPClass(const Value *V, const APInt &DemandedElts,
       if ((InterestedClasses & fcNegative) == fcNone)
         break;
 
-      if (II->getArgOperand(0) != II->getArgOperand(1))
+      if (II->getArgOperand(0) != II->getArgOperand(1) ||
+          !isGuaranteedNotToBeUndef(II->getArgOperand(0), Q.AC, Q.CxtI, Q.DT,
+                                    Depth + 1))
         break;
 
       // The multiply cannot be -0 and therefore the add can't be -0
diff --git a/llvm/test/Transforms/Attributor/nofpclass-fma.ll b/llvm/test/Transforms/Attributor/nofpclass-fma.ll
index dc189924eeac7..877057c4fadc3 100644
--- a/llvm/test/Transforms/Attributor/nofpclass-fma.ll
+++ b/llvm/test/Transforms/Attributor/nofpclass-fma.ll
@@ -4,40 +4,70 @@
 declare float @llvm.fma.f32(float, float, float)
 declare float @llvm.fmuladd.f32(float, float, float)
 
-define float @ret_fma_same_mul_arg(float %arg0, float %arg1) {
+define float @ret_fma_same_mul_arg(float noundef %arg0, float %arg1) {
 ; CHECK-LABEL: define nofpclass(nzero) float @ret_fma_same_mul_arg
-; CHECK-SAME: (float [[ARG0:%.*]], float [[ARG1:%.*]]) #[[ATTR1:[0-9]+]] {
-; CHECK-NEXT:    [[CALL:%.*]] = call nofpclass(nzero) float @llvm.fma.f32(float [[ARG0]], float [[ARG0]], float [[ARG1]]) #[[ATTR2:[0-9]+]]
+; CHECK-SAME: (float noundef [[ARG0:%.*]], float [[ARG1:%.*]]) #[[ATTR1:[0-9]+]] {
+; CHECK-NEXT:    [[CALL:%.*]] = call nofpclass(nzero) float @llvm.fma.f32(float noundef [[ARG0]], float noundef [[ARG0]], float [[ARG1]]) #[[ATTR2:[0-9]+]]
 ; CHECK-NEXT:    ret float [[CALL]]
 ;
   %call = call float @llvm.fma.f32(float %arg0, float %arg0, float %arg1)
   ret float %call
 }
 
-define float @ret_fma_same_mul_arg_positive_addend(float %arg0, float nofpclass(ninf nsub nnorm) %arg1) {
+define float @ret_fma_same_mul_arg_maybe_undef(float %arg0, float %arg1) {
+; CHECK-LABEL: define float @ret_fma_same_mul_arg_maybe_undef
+; CHECK-SAME: (float [[ARG0:%.*]], float [[ARG1:%.*]]) #[[ATTR1]] {
+; CHECK-NEXT:    [[CALL:%.*]] = call float @llvm.fma.f32(float [[ARG0]], float [[ARG0]], float [[ARG1]]) #[[ATTR2]]
+; CHECK-NEXT:    ret float [[CALL]]
+;
+  %call = call float @llvm.fma.f32(float %arg0, float %arg0, float %arg1)
+  ret float %call
+}
+
+define float @ret_fma_same_mul_arg_positive_addend(float noundef %arg0, float nofpclass(ninf nsub nnorm) %arg1) {
 ; CHECK-LABEL: define nofpclass(ninf nzero nsub nnorm) float @ret_fma_same_mul_arg_positive_addend
-; CHECK-SAME: (float [[ARG0:%.*]], float nofpclass(ninf nsub nnorm) [[ARG1:%.*]]) #[[ATTR1]] {
-; CHECK-NEXT:    [[CALL:%.*]] = call nofpclass(ninf nzero nsub nnorm) float @llvm.fma.f32(float [[ARG0]], float [[ARG0]], float nofpclass(ninf nsub nnorm) [[ARG1]]) #[[ATTR2]]
+; CHECK-SAME: (float noundef [[ARG0:%.*]], float nofpclass(ninf nsub nnorm) [[ARG1:%.*]]) #[[ATTR1]] {
+; CHECK-NEXT:    [[CALL:%.*]] = call nofpclass(ninf nzero nsub nnorm) float @llvm.fma.f32(float noundef [[ARG0]], float noundef [[ARG0]], float nofpclass(ninf nsub nnorm) [[ARG1]]) #[[ATTR2]]
 ; CHECK-NEXT:    ret float [[CALL]]
 ;
   %call = call float @llvm.fma.f32(float %arg0, float %arg0, float %arg1)
   ret float %call
 }
 
-define float @ret_fma_different_mul_arg_positive_addend(float %arg0, float %arg1, float nofpclass(ninf nsub nnorm) %arg2) {
+define float @ret_fma_different_mul_arg_positive_addend(float noundef %arg0, float %arg1, float nofpclass(ninf nsub nnorm) %arg2) {
 ; CHECK-LABEL: define float @ret_fma_different_mul_arg_positive_addend
-; CHECK-SAME: (float [[ARG0:%.*]], float [[ARG1:%.*]], float nofpclass(ninf nsub nnorm) [[ARG2:%.*]]) #[[ATTR1]] {
-; CHECK-NEXT:    [[CALL:%.*]] = call float @llvm.fma.f32(float [[ARG0]], float [[ARG1]], float nofpclass(ninf nsub nnorm) [[ARG2]]) #[[ATTR2]]
+; CHECK-SAME: (float noundef [[ARG0:%.*]], float [[ARG1:%.*]], float nofpclass(ninf nsub nnorm) [[ARG2:%.*]]) #[[ATTR1]] {
+; CHECK-NEXT:    [[CALL:%.*]] = call float @llvm.fma.f32(float noundef [[ARG0]], float [[ARG1]], float nofpclass(ninf nsub nnorm) [[ARG2]]) #[[ATTR2]]
 ; CHECK-NEXT:    ret float [[CALL]]
 ;
   %call = call float @llvm.fma.f32(float %arg0, float %arg1, float %arg2)
   ret float %call
 }
 
-define float @ret_fmuladd_different_same_arg_positive_addend(float %arg0, float nofpclass(ninf nsub nnorm) %arg1) {
+define float @ret_fmuladd_same_mul_arg(float noundef %arg0, float %arg1) {
+; CHECK-LABEL: define nofpclass(nzero) float @ret_fmuladd_same_mul_arg
+; CHECK-SAME: (float noundef [[ARG0:%.*]], float [[ARG1:%.*]]) #[[ATTR1]] {
+; CHECK-NEXT:    [[CALL:%.*]] = call nofpclass(nzero) float @llvm.fmuladd.f32(float noundef [[ARG0]], float noundef [[ARG0]], float [[ARG1]]) #[[ATTR2]]
+; CHECK-NEXT:    ret float [[CALL]]
+;
+  %call = call float @llvm.fmuladd.f32(float %arg0, float %arg0, float %arg1)
+  ret float %call
+}
+
+define float @ret_fmuladd_same_mul_arg_maybe_undef(float %arg0, float %arg1) {
+; CHECK-LABEL: define float @ret_fmuladd_same_mul_arg_maybe_undef
+; CHECK-SAME: (float [[ARG0:%.*]], float [[ARG1:%.*]]) #[[ATTR1]] {
+; CHECK-NEXT:    [[CALL:%.*]] = call float @llvm.fmuladd.f32(float [[ARG0]], float [[ARG0]], float [[ARG1]]) #[[ATTR2]]
+; CHECK-NEXT:    ret float [[CALL]]
+;
+  %call = call float @llvm.fmuladd.f32(float %arg0, float %arg0, float %arg1)
+  ret float %call
+}
+
+define float @ret_fmuladd_different_same_arg_positive_addend(float noundef %arg0, float nofpclass(ninf nsub nnorm) %arg1) {
 ; CHECK-LABEL: define nofpclass(ninf nzero nsub nnorm) float @ret_fmuladd_different_same_arg_positive_addend
-; CHECK-SAME: (float [[ARG0:%.*]], float nofpclass(ninf nsub nnorm) [[ARG1:%.*]]) #[[ATTR1]] {
-; CHECK-NEXT:    [[CALL:%.*]] = call nofpclass(ninf nzero nsub nnorm) float @llvm.fmuladd.f32(float [[ARG0]], float [[ARG0]], float nofpclass(ninf nsub nnorm) [[ARG1]]) #[[ATTR2]]
+; CHECK-SAME: (float noundef [[ARG0:%.*]], float nofpclass(ninf nsub nnorm) [[ARG1:%.*]]) #[[ATTR1]] {
+; CHECK-NEXT:    [[CALL:%.*]] = call nofpclass(ninf nzero nsub nnorm) float @llvm.fmuladd.f32(float noundef [[ARG0]], float noundef [[ARG0]], float nofpclass(ninf nsub nnorm) [[ARG1]]) #[[ATTR2]]
 ; CHECK-NEXT:    ret float [[CALL]]
 ;
   %call = call float @llvm.fmuladd.f32(float %arg0, float %arg0, float %arg1)
diff --git a/llvm/test/Transforms/InstCombine/fabs.ll b/llvm/test/Transforms/InstCombine/fabs.ll
index 0d9374410a1d8..2aa035ff2b83e 100644
--- a/llvm/test/Transforms/InstCombine/fabs.ll
+++ b/llvm/test/Transforms/InstCombine/fabs.ll
@@ -204,7 +204,7 @@ define float @square_fma_fabs_intrinsic_f32(float %x) {
 
 ; The fabs cannot be eliminated because %x may be a NaN
 
-define float @square_nnan_fma_fabs_intrinsic_f32(float %x) {
+define float @square_nnan_fma_fabs_intrinsic_f32(float noundef %x) {
 ; CHECK-LABEL: @square_nnan_fma_fabs_intrinsic_f32(
 ; CHECK-NEXT:    [[FMA:%.*]] = call nnan float @llvm.fma.f32(float [[X:%.*]], float [[X]], float 1.000000e+00)
 ; CHECK-NEXT:    ret float [[FMA]]
@@ -214,7 +214,7 @@ define float @square_nnan_fma_fabs_intrinsic_f32(float %x) {
   ret float %fabsf
 }
 
-define float @square_fmuladd_fabs_intrinsic_f32(float %x) {
+define float @square_fmuladd_fabs_intrinsic_f32(float noundef %x) {
 ; CHECK-LABEL: @square_fmuladd_fabs_intrinsic_f32(
 ; CHECK-NEXT:    [[FMULADD:%.*]] = call float @llvm.fmuladd.f32(float [[X:%.*]], float [[X]], float 1.000000e+00)
 ; CHECK-NEXT:    [[FABSF:%.*]] = call float @llvm.fabs.f32(float [[FMULADD]])
@@ -225,7 +225,7 @@ define float @square_fmuladd_fabs_intrinsic_f32(float %x) {
   ret float %fabsf
 }
 
-define float @square_nnan_fmuladd_fabs_intrinsic_f32(float %x) {
+define float @square_nnan_fmuladd_fabs_intrinsic_f32(float noundef %x) {
 ; CHECK-LABEL: @square_nnan_fmuladd_fabs_intrinsic_f32(
 ; CHECK-NEXT:    [[FMULADD:%.*]] = call nnan float @llvm.fmuladd.f32(float [[X:%.*]], float [[X]], float 1.000000e+00)
 ; CHECK-NEXT:    ret float [[FMULADD]]



More information about the llvm-commits mailing list