[llvm] [GISel] Extend ConstantFoldFPBinOp with fminimumnum, fmaximumnum (PR #190561)
Tim Gymnich via llvm-commits
llvm-commits at lists.llvm.org
Tue Apr 7 05:06:04 PDT 2026
https://github.com/tgymnich updated https://github.com/llvm/llvm-project/pull/190561
>From b44466ce2760f5f1606200f33cbae55f70da2ea9 Mon Sep 17 00:00:00 2001
From: Tim Gymnich <tim at gymni.ch>
Date: Mon, 6 Apr 2026 01:22:32 +0200
Subject: [PATCH 1/2] [GISel] Extend ConstantFoldFPBinOp with fminimumnum and
fmaximumnum
- Add constant folding for G_FMINIMUMNUM and G_FMAXIMUMNUM using the
minimumnum/maximumnum APFloat helpers.
- Extend the constant_fold_fp_binop combiner rule to cover all opcodes
that ConstantFoldFPBinOp actually folds: G_FREM, G_FCOPYSIGN,
G_FMINNUM, G_FMAXNUM, G_FMINIMUM, G_FMAXIMUM, G_FMINIMUMNUM,
G_FMAXIMUMNUM. Previously only G_FADD/FSUB/FMUL/FDIV were wired up.
- Add MIR tests for all newly folded opcodes in
postlegalizer-combiner-constant-fold.mir.
---
.../include/llvm/Target/GlobalISel/Combine.td | 5 +-
llvm/lib/CodeGen/GlobalISel/Utils.cpp | 4 +
.../postlegalizer-combiner-constant-fold.mir | 159 ++++++++++++++++++
3 files changed, 167 insertions(+), 1 deletion(-)
diff --git a/llvm/include/llvm/Target/GlobalISel/Combine.td b/llvm/include/llvm/Target/GlobalISel/Combine.td
index 5e99049c32734..ef8c5385c719c 100644
--- a/llvm/include/llvm/Target/GlobalISel/Combine.td
+++ b/llvm/include/llvm/Target/GlobalISel/Combine.td
@@ -1365,7 +1365,10 @@ def constant_fold_binop : GICombineRule<
def constant_fold_fp_binop : GICombineRule<
(defs root:$d, constantfp_matchinfo:$matchinfo),
- (match (wip_match_opcode G_FADD, G_FSUB, G_FMUL, G_FDIV):$d,
+ (match (wip_match_opcode G_FADD, G_FSUB, G_FMUL, G_FDIV, G_FREM,
+ G_FCOPYSIGN, G_FMINNUM, G_FMAXNUM,
+ G_FMINIMUM, G_FMAXIMUM,
+ G_FMINIMUMNUM, G_FMAXIMUMNUM):$d,
[{ return Helper.matchConstantFoldFPBinOp(*${d}, ${matchinfo}); }]),
(apply [{ Helper.replaceInstWithFConstant(*${d}, ${matchinfo}); }])>;
diff --git a/llvm/lib/CodeGen/GlobalISel/Utils.cpp b/llvm/lib/CodeGen/GlobalISel/Utils.cpp
index d019633369163..dacea8e2bbf57 100644
--- a/llvm/lib/CodeGen/GlobalISel/Utils.cpp
+++ b/llvm/lib/CodeGen/GlobalISel/Utils.cpp
@@ -776,6 +776,10 @@ llvm::ConstantFoldFPBinOp(unsigned Opcode, const Register Op1,
return minimum(C1, C2);
case TargetOpcode::G_FMAXIMUM:
return maximum(C1, C2);
+ case TargetOpcode::G_FMINIMUMNUM:
+ return minimumnum(C1, C2);
+ case TargetOpcode::G_FMAXIMUMNUM:
+ return maximumnum(C1, C2);
case TargetOpcode::G_FMINNUM_IEEE:
case TargetOpcode::G_FMAXNUM_IEEE:
// FIXME: These operations were unfortunately named. fminnum/fmaxnum do not
diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/postlegalizer-combiner-constant-fold.mir b/llvm/test/CodeGen/AArch64/GlobalISel/postlegalizer-combiner-constant-fold.mir
index d600bff8e08a9..0435baaf30f01 100644
--- a/llvm/test/CodeGen/AArch64/GlobalISel/postlegalizer-combiner-constant-fold.mir
+++ b/llvm/test/CodeGen/AArch64/GlobalISel/postlegalizer-combiner-constant-fold.mir
@@ -226,6 +226,165 @@ body: |
$d0 = COPY %res(s64)
RET_ReallyLR implicit $d0
+...
+---
+name: fminimumnum
+legalized: true
+liveins:
+ - { reg: '$d0' }
+body: |
+ bb.1.entry:
+ liveins: $d0
+
+ ; CHECK-LABEL: name: fminimumnum
+ ; CHECK: liveins: $d0
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: %a:_(s64) = G_FCONSTANT double 2.000000e+00
+ ; CHECK-NEXT: $d0 = COPY %a(s64)
+ ; CHECK-NEXT: RET_ReallyLR implicit $d0
+ %a:_(s64) = G_FCONSTANT double 2.0
+ %b:_(s64) = G_FCONSTANT double 5.0
+ %res:_(s64) = G_FMINIMUMNUM %a, %b
+ $d0 = COPY %res(s64)
+ RET_ReallyLR implicit $d0
+
+...
+---
+name: fmaximumnum
+legalized: true
+liveins:
+ - { reg: '$d0' }
+body: |
+ bb.1.entry:
+ liveins: $d0
+
+ ; CHECK-LABEL: name: fmaximumnum
+ ; CHECK: liveins: $d0
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: %b:_(s64) = G_FCONSTANT double 5.000000e+00
+ ; CHECK-NEXT: $d0 = COPY %b(s64)
+ ; CHECK-NEXT: RET_ReallyLR implicit $d0
+ %a:_(s64) = G_FCONSTANT double 2.0
+ %b:_(s64) = G_FCONSTANT double 5.0
+ %res:_(s64) = G_FMAXIMUMNUM %a, %b
+ $d0 = COPY %res(s64)
+ RET_ReallyLR implicit $d0
+
+...
+---
+name: fcopysign
+legalized: true
+liveins:
+ - { reg: '$d0' }
+body: |
+ bb.1.entry:
+ liveins: $d0
+
+ ; fcopysign(3.0, -1.0) = -3.0
+ ; CHECK-LABEL: name: fcopysign
+ ; CHECK: liveins: $d0
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: %res:_(s64) = G_FCONSTANT double -3.000000e+00
+ ; CHECK-NEXT: $d0 = COPY %res(s64)
+ ; CHECK-NEXT: RET_ReallyLR implicit $d0
+ %a:_(s64) = G_FCONSTANT double 3.0
+ %b:_(s64) = G_FCONSTANT double -1.0
+ %res:_(s64) = G_FCOPYSIGN %a, %b
+ $d0 = COPY %res(s64)
+ RET_ReallyLR implicit $d0
+
+...
+---
+name: fminnum
+legalized: true
+liveins:
+ - { reg: '$d0' }
+body: |
+ bb.1.entry:
+ liveins: $d0
+
+ ; fminnum(2.0, 5.0) = 2.0
+ ; CHECK-LABEL: name: fminnum
+ ; CHECK: liveins: $d0
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: %a:_(s64) = G_FCONSTANT double 2.000000e+00
+ ; CHECK-NEXT: $d0 = COPY %a(s64)
+ ; CHECK-NEXT: RET_ReallyLR implicit $d0
+ %a:_(s64) = G_FCONSTANT double 2.0
+ %b:_(s64) = G_FCONSTANT double 5.0
+ %res:_(s64) = G_FMINNUM %a, %b
+ $d0 = COPY %res(s64)
+ RET_ReallyLR implicit $d0
+
+...
+---
+name: fmaxnum
+legalized: true
+liveins:
+ - { reg: '$d0' }
+body: |
+ bb.1.entry:
+ liveins: $d0
+
+ ; fmaxnum(2.0, 5.0) = 5.0
+ ; CHECK-LABEL: name: fmaxnum
+ ; CHECK: liveins: $d0
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: %b:_(s64) = G_FCONSTANT double 5.000000e+00
+ ; CHECK-NEXT: $d0 = COPY %b(s64)
+ ; CHECK-NEXT: RET_ReallyLR implicit $d0
+ %a:_(s64) = G_FCONSTANT double 2.0
+ %b:_(s64) = G_FCONSTANT double 5.0
+ %res:_(s64) = G_FMAXNUM %a, %b
+ $d0 = COPY %res(s64)
+ RET_ReallyLR implicit $d0
+
+...
+---
+name: fminimum
+legalized: true
+liveins:
+ - { reg: '$d0' }
+body: |
+ bb.1.entry:
+ liveins: $d0
+
+ ; fminimum(2.0, 5.0) = 2.0
+ ; CHECK-LABEL: name: fminimum
+ ; CHECK: liveins: $d0
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: %a:_(s64) = G_FCONSTANT double 2.000000e+00
+ ; CHECK-NEXT: $d0 = COPY %a(s64)
+ ; CHECK-NEXT: RET_ReallyLR implicit $d0
+ %a:_(s64) = G_FCONSTANT double 2.0
+ %b:_(s64) = G_FCONSTANT double 5.0
+ %res:_(s64) = G_FMINIMUM %a, %b
+ $d0 = COPY %res(s64)
+ RET_ReallyLR implicit $d0
+
+...
+---
+name: fmaximum
+legalized: true
+liveins:
+ - { reg: '$d0' }
+body: |
+ bb.1.entry:
+ liveins: $d0
+
+ ; fmaximum(2.0, 5.0) = 5.0
+ ; CHECK-LABEL: name: fmaximum
+ ; CHECK: liveins: $d0
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: %b:_(s64) = G_FCONSTANT double 5.000000e+00
+ ; CHECK-NEXT: $d0 = COPY %b(s64)
+ ; CHECK-NEXT: RET_ReallyLR implicit $d0
+ %a:_(s64) = G_FCONSTANT double 2.0
+ %b:_(s64) = G_FCONSTANT double 5.0
+ %res:_(s64) = G_FMAXIMUM %a, %b
+ $d0 = COPY %res(s64)
+ RET_ReallyLR implicit $d0
+
...
---
name: fadd32
>From 311f9d048a3480ee355d42a5ae3e93e620f9d13e Mon Sep 17 00:00:00 2001
From: Tim Gymnich <tim at gymni.ch>
Date: Mon, 6 Apr 2026 18:13:44 -0500
Subject: [PATCH 2/2] [GISel] Replace wip_match_opcode with GICombinePatFrag in
constant_fold_fp_binop
Use a proper GICombinePatFrag (constant_fold_fp_binop_frags) with \!foreach
over all FP binop opcodes instead of wip_match_opcode, following the same
pattern as unary_undef_to_undef.
Co-Authored-By: Claude Sonnet 4.6 <noreply at anthropic.com>
---
llvm/include/llvm/Target/GlobalISel/Combine.td | 17 +++++++++++------
1 file changed, 11 insertions(+), 6 deletions(-)
diff --git a/llvm/include/llvm/Target/GlobalISel/Combine.td b/llvm/include/llvm/Target/GlobalISel/Combine.td
index ef8c5385c719c..df3955909fe85 100644
--- a/llvm/include/llvm/Target/GlobalISel/Combine.td
+++ b/llvm/include/llvm/Target/GlobalISel/Combine.td
@@ -1363,14 +1363,19 @@ def constant_fold_binop : GICombineRule<
[{ return Helper.matchConstantFoldBinOp(*${d}, ${matchinfo}); }]),
(apply [{ Helper.replaceInstWithConstant(*${d}, ${matchinfo}); }])>;
+def constant_fold_fp_binop_frags : GICombinePatFrag<
+ (outs root:$dst), (ins),
+ !foreach(op,
+ [G_FADD, G_FSUB, G_FMUL, G_FDIV, G_FREM, G_FCOPYSIGN,
+ G_FMINNUM, G_FMAXNUM, G_FMINIMUM, G_FMAXIMUM,
+ G_FMINIMUMNUM, G_FMAXIMUMNUM],
+ (pattern (op $dst, $src0, $src1)))>;
+
def constant_fold_fp_binop : GICombineRule<
(defs root:$d, constantfp_matchinfo:$matchinfo),
- (match (wip_match_opcode G_FADD, G_FSUB, G_FMUL, G_FDIV, G_FREM,
- G_FCOPYSIGN, G_FMINNUM, G_FMAXNUM,
- G_FMINIMUM, G_FMAXIMUM,
- G_FMINIMUMNUM, G_FMAXIMUMNUM):$d,
- [{ return Helper.matchConstantFoldFPBinOp(*${d}, ${matchinfo}); }]),
- (apply [{ Helper.replaceInstWithFConstant(*${d}, ${matchinfo}); }])>;
+ (match (constant_fold_fp_binop_frags $d):$mi,
+ [{ return Helper.matchConstantFoldFPBinOp(*${mi}, ${matchinfo}); }]),
+ (apply [{ Helper.replaceInstWithFConstant(*${mi}, ${matchinfo}); }])>;
def constant_fold_fma : GICombineRule<
More information about the llvm-commits
mailing list