[llvm] [GIsel] Add combiner for constant-folding G_BITCAST (PR #193060)
Alex MacLean via llvm-commits
llvm-commits at lists.llvm.org
Wed Apr 22 19:13:00 PDT 2026
https://github.com/AlexMaclean updated https://github.com/llvm/llvm-project/pull/193060
>From 0d59ced20ec1c0941876128d5ba8dcf10f0b7f59 Mon Sep 17 00:00:00 2001
From: Alex Maclean <amaclean at nvidia.com>
Date: Mon, 20 Apr 2026 12:07:14 -0700
Subject: [PATCH 1/4] pre-commit tests
---
.../combine-constant-fold-bitcast.mir | 100 ++++++++++++++++++
1 file changed, 100 insertions(+)
create mode 100644 llvm/test/CodeGen/AArch64/GlobalISel/combine-constant-fold-bitcast.mir
diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/combine-constant-fold-bitcast.mir b/llvm/test/CodeGen/AArch64/GlobalISel/combine-constant-fold-bitcast.mir
new file mode 100644
index 0000000000000..39ae8b056a7b8
--- /dev/null
+++ b/llvm/test/CodeGen/AArch64/GlobalISel/combine-constant-fold-bitcast.mir
@@ -0,0 +1,100 @@
+# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py
+# RUN: llc -mtriple aarch64 -run-pass=aarch64-prelegalizer-combiner -verify-machineinstrs %s -o - | FileCheck %s
+
+# 0x3F800000 = 1065353216 = IEEE 754 float 1.0
+---
+name: int_constant_to_float
+body: |
+ bb.0:
+ ; CHECK-LABEL: name: int_constant_to_float
+ ; CHECK: %src:_(i32) = G_CONSTANT i32 1065353216
+ ; CHECK-NEXT: %dst:_(f32) = G_BITCAST %src(i32)
+ ; CHECK-NEXT: $w0 = COPY %dst(f32)
+ ; CHECK-NEXT: RET_ReallyLR implicit $w0
+ %src:_(i32) = G_CONSTANT i32 1065353216
+ %dst:_(f32) = G_BITCAST %src(i32)
+ $w0 = COPY %dst(f32)
+ RET_ReallyLR implicit $w0
+...
+
+---
+name: float_constant_to_int
+body: |
+ bb.0:
+ ; CHECK-LABEL: name: float_constant_to_int
+ ; CHECK: %src:_(f32) = G_FCONSTANT float 1.000000e+00
+ ; CHECK-NEXT: %dst:_(i32) = G_BITCAST %src(f32)
+ ; CHECK-NEXT: $w0 = COPY %dst(i32)
+ ; CHECK-NEXT: RET_ReallyLR implicit $w0
+ %src:_(f32) = G_FCONSTANT float 1.000000e+00
+ %dst:_(i32) = G_BITCAST %src(f32)
+ $w0 = COPY %dst(i32)
+ RET_ReallyLR implicit $w0
+...
+
+# 0x3FF0000000000000 = 4607182418800017408 = IEEE 754 double 1.0
+---
+name: int64_constant_to_double
+body: |
+ bb.0:
+ ; CHECK-LABEL: name: int64_constant_to_double
+ ; CHECK: %src:_(i64) = G_CONSTANT i64 4607182418800017408
+ ; CHECK-NEXT: %dst:_(f64) = G_BITCAST %src(i64)
+ ; CHECK-NEXT: $x0 = COPY %dst(f64)
+ ; CHECK-NEXT: RET_ReallyLR implicit $x0
+ %src:_(i64) = G_CONSTANT i64 4607182418800017408
+ %dst:_(f64) = G_BITCAST %src(i64)
+ $x0 = COPY %dst(f64)
+ RET_ReallyLR implicit $x0
+...
+
+---
+name: double_constant_to_int64
+body: |
+ bb.0:
+ ; CHECK-LABEL: name: double_constant_to_int64
+ ; CHECK: %src:_(f64) = G_FCONSTANT double 1.000000e+00
+ ; CHECK-NEXT: %dst:_(i64) = G_BITCAST %src(f64)
+ ; CHECK-NEXT: $x0 = COPY %dst(i64)
+ ; CHECK-NEXT: RET_ReallyLR implicit $x0
+ %src:_(f64) = G_FCONSTANT double 1.000000e+00
+ %dst:_(i64) = G_BITCAST %src(f64)
+ $x0 = COPY %dst(i64)
+ RET_ReallyLR implicit $x0
+...
+
+# Non-constant source should not be folded.
+---
+name: non_constant_no_fold
+tracksRegLiveness: true
+body: |
+ bb.0:
+ liveins: $w0
+ ; CHECK-LABEL: name: non_constant_no_fold
+ ; CHECK: liveins: $w0
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: %src:_(i32) = COPY $w0
+ ; CHECK-NEXT: %dst:_(f32) = G_BITCAST %src(i32)
+ ; CHECK-NEXT: $s0 = COPY %dst(f32)
+ ; CHECK-NEXT: RET_ReallyLR implicit $s0
+ %src:_(i32) = COPY $w0
+ %dst:_(f32) = G_BITCAST %src(i32)
+ $s0 = COPY %dst(f32)
+ RET_ReallyLR implicit $s0
+...
+
+# Vector destination should not be folded.
+---
+name: vector_dst_no_fold
+body: |
+ bb.0:
+ ; CHECK-LABEL: name: vector_dst_no_fold
+ ; CHECK: %src:_(i64) = G_CONSTANT i64 4607182418800017408
+ ; CHECK-NEXT: %dst:_(<2 x i32>) = G_BITCAST %src(i64)
+ ; CHECK-NEXT: $x0 = COPY %dst(<2 x i32>)
+ ; CHECK-NEXT: RET_ReallyLR implicit $x0
+ %src:_(i64) = G_CONSTANT i64 4607182418800017408
+ %dst:_(<2 x i32>) = G_BITCAST %src(i64)
+ $x0 = COPY %dst(<2 x i32>)
+ RET_ReallyLR implicit $x0
+...
>From 39a901fb1ad2dd27e9f5384b6122e41789996e96 Mon Sep 17 00:00:00 2001
From: Alex Maclean <amaclean at nvidia.com>
Date: Mon, 20 Apr 2026 12:08:16 -0700
Subject: [PATCH 2/4] [GIsel] Add combiner for constant-folding G_BITCAST
Made-with: Cursor
---
.../llvm/CodeGen/GlobalISel/CombinerHelper.h | 3 ++
.../include/llvm/Target/GlobalISel/Combine.td | 19 +++++++-
.../GlobalISel/CombinerHelperCasts.cpp | 43 ++++++++++++++++++-
.../combine-constant-fold-bitcast.mir | 12 ++----
4 files changed, 66 insertions(+), 11 deletions(-)
diff --git a/llvm/include/llvm/CodeGen/GlobalISel/CombinerHelper.h b/llvm/include/llvm/CodeGen/GlobalISel/CombinerHelper.h
index 365bbaacfe055..546f9be19353d 100644
--- a/llvm/include/llvm/CodeGen/GlobalISel/CombinerHelper.h
+++ b/llvm/include/llvm/CodeGen/GlobalISel/CombinerHelper.h
@@ -708,6 +708,9 @@ class CombinerHelper {
/// Do constant folding when opportunities are exposed after MIR building.
bool matchConstantFoldCastOp(MachineInstr &MI, APInt &MatchInfo) const;
+ /// Do constant folding when opportunities are exposed after MIR building.
+ bool matchConstantFoldBitcast(MachineInstr &MI, BuildFnTy &MatchInfo) const;
+
/// Do constant folding when opportunities are exposed after MIR building.
bool matchConstantFoldBinOp(MachineInstr &MI, APInt &MatchInfo) const;
diff --git a/llvm/include/llvm/Target/GlobalISel/Combine.td b/llvm/include/llvm/Target/GlobalISel/Combine.td
index df3955909fe85..84064fb6550d2 100644
--- a/llvm/include/llvm/Target/GlobalISel/Combine.td
+++ b/llvm/include/llvm/Target/GlobalISel/Combine.td
@@ -1390,6 +1390,23 @@ def constant_fold_cast_op : GICombineRule<
[{ return Helper.matchConstantFoldCastOp(*${d}, ${matchinfo}); }]),
(apply [{ Helper.replaceInstWithConstant(*${d}, ${matchinfo}); }])>;
+def constant_fold_bitcast_of_const : GICombineRule<
+ (defs root:$d, build_fn_matchinfo:$matchinfo),
+ (match (G_CONSTANT $src, $imm),
+ (G_BITCAST $d, $src):$mi,
+ [{ return Helper.matchConstantFoldBitcast(*${mi}, ${matchinfo}); }]),
+ (apply [{ Helper.applyBuildFn(*${mi}, ${matchinfo}); }])>;
+
+def constant_fold_bitcast_of_fconst : GICombineRule<
+ (defs root:$d, build_fn_matchinfo:$matchinfo),
+ (match (G_FCONSTANT $src, $imm),
+ (G_BITCAST $d, $src):$mi,
+ [{ return Helper.matchConstantFoldBitcast(*${mi}, ${matchinfo}); }]),
+ (apply [{ Helper.applyBuildFn(*${mi}, ${matchinfo}); }])>;
+
+def constant_fold_bitcast : GICombineGroup<[constant_fold_bitcast_of_const,
+ constant_fold_bitcast_of_fconst]>;
+
def mulo_by_2: GICombineRule<
(defs root:$root, build_fn_matchinfo:$matchinfo),
(match (wip_match_opcode G_UMULO, G_SMULO):$root,
@@ -2366,7 +2383,7 @@ def all_combines : GICombineGroup<[integer_reassoc_combines, trivial_combines,
shift_immed_chain, shift_of_shifted_logic_chain, load_or_combine,
div_rem_to_divrem, funnel_shift_combines, bitreverse_shift, commute_shift,
form_bitfield_extract, constant_fold_binops, constant_fold_fma,
- constant_fold_cast_op, fabs_fneg_fold,
+ constant_fold_cast_op, constant_fold_bitcast, fabs_fneg_fold,
mulh_combines, redundant_neg_operands,
and_or_disjoint_mask, fma_combines, fold_binop_into_select,
intrem_combines, intdiv_combines, fdiv_repeated_divison,
diff --git a/llvm/lib/CodeGen/GlobalISel/CombinerHelperCasts.cpp b/llvm/lib/CodeGen/GlobalISel/CombinerHelperCasts.cpp
index fc7e3ae5b7942..c5d36f9cbd770 100644
--- a/llvm/lib/CodeGen/GlobalISel/CombinerHelperCasts.cpp
+++ b/llvm/lib/CodeGen/GlobalISel/CombinerHelperCasts.cpp
@@ -6,8 +6,8 @@
//
//===----------------------------------------------------------------------===//
//
-// This file implements CombinerHelper for G_ANYEXT, G_SEXT, G_TRUNC, and
-// G_ZEXT
+// This file implements CombinerHelper for G_ANYEXT, G_SEXT, G_TRUNC,
+// G_ZEXT, and G_BITCAST
//
//===----------------------------------------------------------------------===//
#include "llvm/CodeGen/GlobalISel/CombinerHelper.h"
@@ -413,3 +413,42 @@ bool CombinerHelper::matchRedundantSextInReg(MachineInstr &Root,
return true;
}
+
+bool CombinerHelper::matchConstantFoldBitcast(MachineInstr &MI,
+ BuildFnTy &MatchInfo) const {
+ assert(MI.getOpcode() == TargetOpcode::G_BITCAST);
+
+ Register DstReg = MI.getOperand(0).getReg();
+ Register SrcReg = MI.getOperand(1).getReg();
+ LLT DstTy = MRI.getType(DstReg);
+
+ if (!DstTy.isScalar())
+ return false;
+
+ if (const auto Cst = getIConstantVRegVal(SrcReg, MRI)) {
+ if (DstTy.isFloat()) {
+ const fltSemantics &Sem =
+ APFloat::EnumToSemantics(DstTy.getFpSemantics());
+ APFloat FPVal(Sem, *Cst);
+ MatchInfo = [=](MachineIRBuilder &B) { B.buildFConstant(DstReg, FPVal); };
+ } else {
+ MatchInfo = [=](MachineIRBuilder &B) { B.buildConstant(DstReg, *Cst); };
+ }
+ return true;
+ }
+
+ if (const ConstantFP *CFP = getConstantFPVRegVal(SrcReg, MRI)) {
+ APInt Bits = CFP->getValueAPF().bitcastToAPInt();
+ if (DstTy.isFloat()) {
+ const fltSemantics &Sem =
+ APFloat::EnumToSemantics(DstTy.getFpSemantics());
+ APFloat FPVal(Sem, Bits);
+ MatchInfo = [=](MachineIRBuilder &B) { B.buildFConstant(DstReg, FPVal); };
+ } else {
+ MatchInfo = [=](MachineIRBuilder &B) { B.buildConstant(DstReg, Bits); };
+ }
+ return true;
+ }
+
+ return false;
+}
diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/combine-constant-fold-bitcast.mir b/llvm/test/CodeGen/AArch64/GlobalISel/combine-constant-fold-bitcast.mir
index 39ae8b056a7b8..b0a7b407534ac 100644
--- a/llvm/test/CodeGen/AArch64/GlobalISel/combine-constant-fold-bitcast.mir
+++ b/llvm/test/CodeGen/AArch64/GlobalISel/combine-constant-fold-bitcast.mir
@@ -7,8 +7,7 @@ name: int_constant_to_float
body: |
bb.0:
; CHECK-LABEL: name: int_constant_to_float
- ; CHECK: %src:_(i32) = G_CONSTANT i32 1065353216
- ; CHECK-NEXT: %dst:_(f32) = G_BITCAST %src(i32)
+ ; CHECK: %dst:_(f32) = G_FCONSTANT float 1.000000e+00
; CHECK-NEXT: $w0 = COPY %dst(f32)
; CHECK-NEXT: RET_ReallyLR implicit $w0
%src:_(i32) = G_CONSTANT i32 1065353216
@@ -22,8 +21,7 @@ name: float_constant_to_int
body: |
bb.0:
; CHECK-LABEL: name: float_constant_to_int
- ; CHECK: %src:_(f32) = G_FCONSTANT float 1.000000e+00
- ; CHECK-NEXT: %dst:_(i32) = G_BITCAST %src(f32)
+ ; CHECK: %dst:_(i32) = G_CONSTANT i32 1065353216
; CHECK-NEXT: $w0 = COPY %dst(i32)
; CHECK-NEXT: RET_ReallyLR implicit $w0
%src:_(f32) = G_FCONSTANT float 1.000000e+00
@@ -38,8 +36,7 @@ name: int64_constant_to_double
body: |
bb.0:
; CHECK-LABEL: name: int64_constant_to_double
- ; CHECK: %src:_(i64) = G_CONSTANT i64 4607182418800017408
- ; CHECK-NEXT: %dst:_(f64) = G_BITCAST %src(i64)
+ ; CHECK: %dst:_(f64) = G_FCONSTANT double 1.000000e+00
; CHECK-NEXT: $x0 = COPY %dst(f64)
; CHECK-NEXT: RET_ReallyLR implicit $x0
%src:_(i64) = G_CONSTANT i64 4607182418800017408
@@ -53,8 +50,7 @@ name: double_constant_to_int64
body: |
bb.0:
; CHECK-LABEL: name: double_constant_to_int64
- ; CHECK: %src:_(f64) = G_FCONSTANT double 1.000000e+00
- ; CHECK-NEXT: %dst:_(i64) = G_BITCAST %src(f64)
+ ; CHECK: %dst:_(i64) = G_CONSTANT i64 4607182418800017408
; CHECK-NEXT: $x0 = COPY %dst(i64)
; CHECK-NEXT: RET_ReallyLR implicit $x0
%src:_(f64) = G_FCONSTANT double 1.000000e+00
>From d9207f23c9a67e5948b9742949018b6fc16c52e3 Mon Sep 17 00:00:00 2001
From: Alex Maclean <amaclean at nvidia.com>
Date: Wed, 22 Apr 2026 13:39:52 -0700
Subject: [PATCH 3/4] address comments
---
.../llvm/CodeGen/GlobalISel/CombinerHelper.h | 3 +-
.../include/llvm/Target/GlobalISel/Combine.td | 24 ++++++-----
.../GlobalISel/CombinerHelperCasts.cpp | 40 +++++--------------
3 files changed, 26 insertions(+), 41 deletions(-)
diff --git a/llvm/include/llvm/CodeGen/GlobalISel/CombinerHelper.h b/llvm/include/llvm/CodeGen/GlobalISel/CombinerHelper.h
index 546f9be19353d..9495880af622d 100644
--- a/llvm/include/llvm/CodeGen/GlobalISel/CombinerHelper.h
+++ b/llvm/include/llvm/CodeGen/GlobalISel/CombinerHelper.h
@@ -709,7 +709,8 @@ class CombinerHelper {
bool matchConstantFoldCastOp(MachineInstr &MI, APInt &MatchInfo) const;
/// Do constant folding when opportunities are exposed after MIR building.
- bool matchConstantFoldBitcast(MachineInstr &MI, BuildFnTy &MatchInfo) const;
+ bool matchConstantFoldBitcast(MachineOperand &DstOp, const APInt &Bits,
+ BuildFnTy &MatchInfo) const;
/// Do constant folding when opportunities are exposed after MIR building.
bool matchConstantFoldBinOp(MachineInstr &MI, APInt &MatchInfo) const;
diff --git a/llvm/include/llvm/Target/GlobalISel/Combine.td b/llvm/include/llvm/Target/GlobalISel/Combine.td
index 84064fb6550d2..ac266ae55addc 100644
--- a/llvm/include/llvm/Target/GlobalISel/Combine.td
+++ b/llvm/include/llvm/Target/GlobalISel/Combine.td
@@ -215,6 +215,10 @@ def unsigned_matchinfo: GIDefMatchData<"unsigned">;
def register_vector_matchinfo : GIDefMatchData<"SmallVector<Register>">;
def mi_vector_matchinfo : GIDefMatchData<"SmallVector<MachineInstr *>">;
+class BuildFnCombineRule<dag a0>
+ : GICombineRule<(defs root:$root, build_fn_matchinfo:$matchinfo), a0,
+ (apply [{ Helper.applyBuildFn(*${root}, ${matchinfo}); }])>;
+
def copy_prop : GICombineRule<
(defs root:$d),
(match (COPY $d, $s):$mi,
@@ -1390,19 +1394,19 @@ def constant_fold_cast_op : GICombineRule<
[{ return Helper.matchConstantFoldCastOp(*${d}, ${matchinfo}); }]),
(apply [{ Helper.replaceInstWithConstant(*${d}, ${matchinfo}); }])>;
-def constant_fold_bitcast_of_const : GICombineRule<
- (defs root:$d, build_fn_matchinfo:$matchinfo),
+
+def constant_fold_bitcast_of_const : BuildFnCombineRule<
(match (G_CONSTANT $src, $imm),
- (G_BITCAST $d, $src):$mi,
- [{ return Helper.matchConstantFoldBitcast(*${mi}, ${matchinfo}); }]),
- (apply [{ Helper.applyBuildFn(*${mi}, ${matchinfo}); }])>;
+ (G_BITCAST $d, $src):$root,
+ [{ return Helper.matchConstantFoldBitcast(
+ ${d}, ${imm}.getCImm()->getValue(), ${matchinfo}); }])>;
-def constant_fold_bitcast_of_fconst : GICombineRule<
- (defs root:$d, build_fn_matchinfo:$matchinfo),
+def constant_fold_bitcast_of_fconst : BuildFnCombineRule<
(match (G_FCONSTANT $src, $imm),
- (G_BITCAST $d, $src):$mi,
- [{ return Helper.matchConstantFoldBitcast(*${mi}, ${matchinfo}); }]),
- (apply [{ Helper.applyBuildFn(*${mi}, ${matchinfo}); }])>;
+ (G_BITCAST $d, $src):$root,
+ [{ return Helper.matchConstantFoldBitcast(
+ ${d}, ${imm}.getFPImm()->getValueAPF().bitcastToAPInt(),
+ ${matchinfo}); }])>;
def constant_fold_bitcast : GICombineGroup<[constant_fold_bitcast_of_const,
constant_fold_bitcast_of_fconst]>;
diff --git a/llvm/lib/CodeGen/GlobalISel/CombinerHelperCasts.cpp b/llvm/lib/CodeGen/GlobalISel/CombinerHelperCasts.cpp
index c5d36f9cbd770..f0e2ca0bc8377 100644
--- a/llvm/lib/CodeGen/GlobalISel/CombinerHelperCasts.cpp
+++ b/llvm/lib/CodeGen/GlobalISel/CombinerHelperCasts.cpp
@@ -414,41 +414,21 @@ bool CombinerHelper::matchRedundantSextInReg(MachineInstr &Root,
return true;
}
-bool CombinerHelper::matchConstantFoldBitcast(MachineInstr &MI,
+bool CombinerHelper::matchConstantFoldBitcast(MachineOperand &DstOp,
+ const APInt &Bits,
BuildFnTy &MatchInfo) const {
- assert(MI.getOpcode() == TargetOpcode::G_BITCAST);
-
- Register DstReg = MI.getOperand(0).getReg();
- Register SrcReg = MI.getOperand(1).getReg();
+ Register DstReg = DstOp.getReg();
LLT DstTy = MRI.getType(DstReg);
if (!DstTy.isScalar())
return false;
- if (const auto Cst = getIConstantVRegVal(SrcReg, MRI)) {
- if (DstTy.isFloat()) {
- const fltSemantics &Sem =
- APFloat::EnumToSemantics(DstTy.getFpSemantics());
- APFloat FPVal(Sem, *Cst);
- MatchInfo = [=](MachineIRBuilder &B) { B.buildFConstant(DstReg, FPVal); };
- } else {
- MatchInfo = [=](MachineIRBuilder &B) { B.buildConstant(DstReg, *Cst); };
- }
- return true;
- }
-
- if (const ConstantFP *CFP = getConstantFPVRegVal(SrcReg, MRI)) {
- APInt Bits = CFP->getValueAPF().bitcastToAPInt();
- if (DstTy.isFloat()) {
- const fltSemantics &Sem =
- APFloat::EnumToSemantics(DstTy.getFpSemantics());
- APFloat FPVal(Sem, Bits);
- MatchInfo = [=](MachineIRBuilder &B) { B.buildFConstant(DstReg, FPVal); };
- } else {
- MatchInfo = [=](MachineIRBuilder &B) { B.buildConstant(DstReg, Bits); };
- }
- return true;
+ if (DstTy.isFloat()) {
+ const fltSemantics &Sem = APFloat::EnumToSemantics(DstTy.getFpSemantics());
+ APFloat FPVal(Sem, Bits);
+ MatchInfo = [=](MachineIRBuilder &B) { B.buildFConstant(DstReg, FPVal); };
+ } else {
+ MatchInfo = [=](MachineIRBuilder &B) { B.buildConstant(DstReg, Bits); };
}
-
- return false;
+ return true;
}
>From b52db511a9770c96a02b79be4e35bbe98bc5d189 Mon Sep 17 00:00:00 2001
From: Alex MacLean <alex at alex-maclean.com>
Date: Wed, 22 Apr 2026 19:12:50 -0700
Subject: [PATCH 4/4] Update
llvm/test/CodeGen/AArch64/GlobalISel/combine-constant-fold-bitcast.mir
Co-authored-by: Matt Arsenault <arsenm2 at gmail.com>
---
.../AArch64/GlobalISel/combine-constant-fold-bitcast.mir | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/combine-constant-fold-bitcast.mir b/llvm/test/CodeGen/AArch64/GlobalISel/combine-constant-fold-bitcast.mir
index b0a7b407534ac..3ab2571144643 100644
--- a/llvm/test/CodeGen/AArch64/GlobalISel/combine-constant-fold-bitcast.mir
+++ b/llvm/test/CodeGen/AArch64/GlobalISel/combine-constant-fold-bitcast.mir
@@ -1,5 +1,5 @@
# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py
-# RUN: llc -mtriple aarch64 -run-pass=aarch64-prelegalizer-combiner -verify-machineinstrs %s -o - | FileCheck %s
+# RUN: llc -mtriple aarch64 -run-pass=aarch64-prelegalizer-combiner %s -o - | FileCheck %s
# 0x3F800000 = 1065353216 = IEEE 754 float 1.0
---
More information about the llvm-commits
mailing list