[llvm] [GlobalIsel] combine ext of trunc with flags (PR #87115)
Thorsten Schütt via llvm-commits
llvm-commits at lists.llvm.org
Fri Mar 29 14:53:53 PDT 2024
https://github.com/tschuett created https://github.com/llvm/llvm-project/pull/87115
https://github.com/llvm/llvm-project/pull/85592
https://discourse.llvm.org/t/rfc-add-nowrap-flags-to-trunc/77453
>From dd76ca5d7e23129f636aa5688b8696d0fdbdc153 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Thorsten=20Sch=C3=BCtt?= <schuett at gmail.com>
Date: Fri, 29 Mar 2024 18:41:08 +0100
Subject: [PATCH] [GlobalIsel] combine ext of trunc with flags
https://github.com/llvm/llvm-project/pull/85592
https://discourse.llvm.org/t/rfc-add-nowrap-flags-to-trunc/77453
---
.../llvm/CodeGen/GlobalISel/CombinerHelper.h | 10 ++
.../CodeGen/GlobalISel/GenericMachineInstrs.h | 52 ++++++
.../include/llvm/Target/GlobalISel/Combine.td | 19 ++-
.../lib/CodeGen/GlobalISel/CombinerHelper.cpp | 66 ++++++++
.../AArch64/GlobalISel/combine-with-flags.mir | 156 ++++++++++++++++++
5 files changed, 302 insertions(+), 1 deletion(-)
create mode 100644 llvm/test/CodeGen/AArch64/GlobalISel/combine-with-flags.mir
diff --git a/llvm/include/llvm/CodeGen/GlobalISel/CombinerHelper.h b/llvm/include/llvm/CodeGen/GlobalISel/CombinerHelper.h
index 28d9cf6260d620..c29998cd42a770 100644
--- a/llvm/include/llvm/CodeGen/GlobalISel/CombinerHelper.h
+++ b/llvm/include/llvm/CodeGen/GlobalISel/CombinerHelper.h
@@ -805,6 +805,12 @@ class CombinerHelper {
/// Match constant LHS ops that should be commuted.
bool matchCommuteConstantToRHS(MachineInstr &MI);
+ /// Combine sext of trunc.
+ bool matchSextOfTrunc(const MachineOperand &MO, BuildFnTy &MatchInfo);
+
+ /// Combine zext of trunc.
+ bool matchZextOfTrunc(const MachineOperand &MO, BuildFnTy &MatchInfo);
+
/// Match constant LHS FP ops that should be commuted.
bool matchCommuteFPConstantToRHS(MachineInstr &MI);
@@ -823,6 +829,10 @@ class CombinerHelper {
/// Combine addos.
bool matchAddOverflow(MachineInstr &MI, BuildFnTy &MatchInfo);
+ /// Use a function which takes in a MachineIRBuilder to perform a combine.
+ /// By default, it erases the instruction \p MI from the function.
+ void applyBuildFnMO(const MachineOperand &MO, BuildFnTy &MatchInfo);
+
private:
/// Checks for legality of an indexed variant of \p LdSt.
bool isIndexedLoadStoreLegal(GLoadStore &LdSt) const;
diff --git a/llvm/include/llvm/CodeGen/GlobalISel/GenericMachineInstrs.h b/llvm/include/llvm/CodeGen/GlobalISel/GenericMachineInstrs.h
index 261cfcf504d5fe..d5523e5ee0c7ab 100644
--- a/llvm/include/llvm/CodeGen/GlobalISel/GenericMachineInstrs.h
+++ b/llvm/include/llvm/CodeGen/GlobalISel/GenericMachineInstrs.h
@@ -739,6 +739,58 @@ class GOr : public GLogicalBinOp {
};
};
+/// Represents a cast operation.
+/// It models the llvm::CastInst concept.
+/// The exception is bitcast.
+class GCastOp : public GenericMachineInstr {
+public:
+ Register getSrcReg() const { return getOperand(1).getReg(); }
+
+ static bool classof(const MachineInstr *MI) {
+ switch (MI->getOpcode()) {
+ case TargetOpcode::G_ADDRSPACE_CAST:
+ case TargetOpcode::G_FPEXT:
+ case TargetOpcode::G_FPTOSI:
+ case TargetOpcode::G_FPTOUI:
+ case TargetOpcode::G_FPTRUNC:
+ case TargetOpcode::G_INTTOPTR:
+ case TargetOpcode::G_PTRTOINT:
+ case TargetOpcode::G_SEXT:
+ case TargetOpcode::G_SITOFP:
+ case TargetOpcode::G_TRUNC:
+ case TargetOpcode::G_UITOFP:
+ case TargetOpcode::G_ZEXT:
+ return true;
+ default:
+ return false;
+ }
+ };
+};
+
+/// Represents a sext.
+class GSext : public GCastOp {
+public:
+ static bool classof(const MachineInstr *MI) {
+ return MI->getOpcode() == TargetOpcode::G_SEXT;
+ };
+};
+
+/// Represents a zext.
+class GZext : public GCastOp {
+public:
+ static bool classof(const MachineInstr *MI) {
+ return MI->getOpcode() == TargetOpcode::G_ZEXT;
+ };
+};
+
+/// Represents a trunc.
+class GTrunc : public GCastOp {
+public:
+ static bool classof(const MachineInstr *MI) {
+ return MI->getOpcode() == TargetOpcode::G_TRUNC;
+ };
+};
+
} // namespace llvm
#endif // LLVM_CODEGEN_GLOBALISEL_GENERICMACHINEINSTRS_H
diff --git a/llvm/include/llvm/Target/GlobalISel/Combine.td b/llvm/include/llvm/Target/GlobalISel/Combine.td
index 72d3c0ea69bcd2..e6443d8fa8ab39 100644
--- a/llvm/include/llvm/Target/GlobalISel/Combine.td
+++ b/llvm/include/llvm/Target/GlobalISel/Combine.td
@@ -180,6 +180,8 @@ def FmContract : MIFlagEnum<"FmContract">;
def FmAfn : MIFlagEnum<"FmAfn">;
def FmReassoc : MIFlagEnum<"FmReassoc">;
def IsExact : MIFlagEnum<"IsExact">;
+def NoSWrap : MIFlagEnum<"NoSWrap">;
+def NoUWrap : MIFlagEnum<"NoUWrap">;
def MIFlags;
// def not; -> Already defined as a SDNode
@@ -1305,6 +1307,20 @@ def match_addos : GICombineRule<
[{ return Helper.matchAddOverflow(*${root}, ${matchinfo}); }]),
(apply [{ Helper.applyBuildFn(*${root}, ${matchinfo}); }])>;
+def sext_trunc : GICombineRule<
+ (defs root:$root, build_fn_matchinfo:$matchinfo),
+ (match (G_TRUNC $src, $x, (MIFlags NoSWrap)),
+ (G_SEXT $root, $src),
+ [{ return Helper.matchSextOfTrunc(${root}, ${matchinfo}); }]),
+ (apply [{ Helper.applyBuildFnMO(${root}, ${matchinfo}); }])>;
+
+def zext_trunc : GICombineRule<
+ (defs root:$root, build_fn_matchinfo:$matchinfo),
+ (match (G_TRUNC $src, $x, (MIFlags NoUWrap)),
+ (G_ZEXT $root, $src),
+ [{ return Helper.matchZextOfTrunc(${root}, ${matchinfo}); }]),
+ (apply [{ Helper.applyBuildFnMO(${root}, ${matchinfo}); }])>;
+
// Combines concat operations
def concat_matchinfo : GIDefMatchData<"SmallVector<Register>">;
def combine_concat_vector : GICombineRule<
@@ -1388,7 +1404,8 @@ def all_combines : GICombineGroup<[trivial_combines, insert_vec_elt_combines,
and_or_disjoint_mask, fma_combines, fold_binop_into_select,
sub_add_reg, select_to_minmax, redundant_binop_in_equality,
fsub_to_fneg, commute_constant_to_rhs, match_ands, match_ors,
- combine_concat_vector, double_icmp_zero_and_or_combine, match_addos]>;
+ combine_concat_vector, double_icmp_zero_and_or_combine, match_addos,
+ sext_trunc, zext_trunc]>;
// A combine group used to for prelegalizer combiners at -O0. The combines in
// this group have been selected based on experiments to balance code size and
diff --git a/llvm/lib/CodeGen/GlobalISel/CombinerHelper.cpp b/llvm/lib/CodeGen/GlobalISel/CombinerHelper.cpp
index 98e7c73a801f59..baf6c98a386322 100644
--- a/llvm/lib/CodeGen/GlobalISel/CombinerHelper.cpp
+++ b/llvm/lib/CodeGen/GlobalISel/CombinerHelper.cpp
@@ -7138,3 +7138,69 @@ bool CombinerHelper::matchAddOverflow(MachineInstr &MI, BuildFnTy &MatchInfo) {
return false;
}
+
+void CombinerHelper::applyBuildFnMO(const MachineOperand &MO,
+ BuildFnTy &MatchInfo) {
+ MachineInstr *Root = getDefIgnoringCopies(MO.getReg(), MRI);
+ Builder.setInstrAndDebugLoc(*Root);
+ MatchInfo(Builder);
+ Root->eraseFromParent();
+}
+
+bool CombinerHelper::matchSextOfTrunc(const MachineOperand &MO,
+ BuildFnTy &MatchInfo) {
+ GSext *Sext = getOpcodeDef<GSext>(MO.getReg(), MRI);
+ if (!Sext)
+ return false;
+
+ GTrunc *Trunc = getOpcodeDef<GTrunc>(Sext->getSrcReg(), MRI);
+ if (!Trunc)
+ return false;
+
+ // The trunc must have the nsw flag.
+ if (!Trunc->getFlag(MachineInstr::MIFlag::NoSWrap))
+ return false;
+
+ Register Dst = Sext->getReg(0);
+ Register Src = Trunc->getSrcReg();
+
+ LLT DstTy = MRI.getType(Dst);
+ LLT SrcTy = MRI.getType(Src);
+
+ // The types have to match for a no-op.
+ if (DstTy != SrcTy)
+ return false;
+
+ MatchInfo = [=](MachineIRBuilder &B) { B.buildCopy(Dst, Src); };
+
+ return true;
+}
+
+bool CombinerHelper::matchZextOfTrunc(const MachineOperand &MO,
+ BuildFnTy &MatchInfo) {
+ GZext *Zext = getOpcodeDef<GZext>(MO.getReg(), MRI);
+ if (!Zext)
+ return false;
+
+ GTrunc *Trunc = getOpcodeDef<GTrunc>(Zext->getSrcReg(), MRI);
+ if (!Trunc)
+ return false;
+
+ // The trunc must have the nuw flag.
+ if (!Trunc->getFlag(MachineInstr::MIFlag::NoUWrap))
+ return false;
+
+ Register Dst = Zext->getReg(0);
+ Register Src = Trunc->getSrcReg();
+
+ LLT DstTy = MRI.getType(Dst);
+ LLT SrcTy = MRI.getType(Src);
+
+ // The types have to match for a no-op.
+ if (DstTy != SrcTy)
+ return false;
+
+ MatchInfo = [=](MachineIRBuilder &B) { B.buildCopy(Dst, Src); };
+
+ return true;
+}
diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/combine-with-flags.mir b/llvm/test/CodeGen/AArch64/GlobalISel/combine-with-flags.mir
new file mode 100644
index 00000000000000..8bcfb1fec1f23b
--- /dev/null
+++ b/llvm/test/CodeGen/AArch64/GlobalISel/combine-with-flags.mir
@@ -0,0 +1,156 @@
+# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py
+# RUN: llc -run-pass=aarch64-prelegalizer-combiner -verify-machineinstrs -mtriple aarch64-unknown-unknown %s -o - | FileCheck %s
+
+---
+name: zext_trunc_nuw
+body: |
+ bb.0:
+ liveins: $w0, $w1
+ ; CHECK-LABEL: name: zext_trunc_nuw
+ ; CHECK: liveins: $w0, $w1
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: [[COPY:%[0-9]+]]:_(s64) = COPY $x0
+ ; CHECK-NEXT: $x1 = COPY [[COPY]](s64)
+ %0:_(s64) = COPY $x0
+ %2:_(s32) = nuw G_TRUNC %0
+ %3:_(s64) = G_ZEXT %2
+ $x1 = COPY %3
+...
+---
+name: zext_trunc_nsw
+body: |
+ bb.0:
+ liveins: $w0, $w1
+ ; CHECK-LABEL: name: zext_trunc_nsw
+ ; CHECK: liveins: $w0, $w1
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: [[COPY:%[0-9]+]]:_(s64) = COPY $x0
+ ; CHECK-NEXT: [[TRUNC:%[0-9]+]]:_(s32) = nsw G_TRUNC [[COPY]](s64)
+ ; CHECK-NEXT: [[ZEXT:%[0-9]+]]:_(s64) = G_ZEXT [[TRUNC]](s32)
+ ; CHECK-NEXT: $x1 = COPY [[ZEXT]](s64)
+ %0:_(s64) = COPY $x0
+ %2:_(s32) = nsw G_TRUNC %0
+ %3:_(s64) = G_ZEXT %2
+ $x1 = COPY %3
+...
+---
+name: zext_trunc
+body: |
+ bb.0:
+ liveins: $w0, $w1
+ ; CHECK-LABEL: name: zext_trunc
+ ; CHECK: liveins: $w0, $w1
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: [[COPY:%[0-9]+]]:_(s64) = COPY $x0
+ ; CHECK-NEXT: [[TRUNC:%[0-9]+]]:_(s32) = G_TRUNC [[COPY]](s64)
+ ; CHECK-NEXT: [[ZEXT:%[0-9]+]]:_(s64) = G_ZEXT [[TRUNC]](s32)
+ ; CHECK-NEXT: $x1 = COPY [[ZEXT]](s64)
+ %0:_(s64) = COPY $x0
+ %2:_(s32) = G_TRUNC %0
+ %3:_(s64) = G_ZEXT %2
+ $x1 = COPY %3
+...
+---
+name: zext_trunc_nuw_vector
+body: |
+ bb.0:
+ liveins: $w0, $w1
+ ; CHECK-LABEL: name: zext_trunc_nuw_vector
+ ; CHECK: liveins: $w0, $w1
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: [[COPY:%[0-9]+]]:_(s32) = COPY $w0
+ ; CHECK-NEXT: [[COPY1:%[0-9]+]]:_(s32) = COPY $w1
+ ; CHECK-NEXT: %bv0:_(<4 x s32>) = G_BUILD_VECTOR [[COPY]](s32), [[COPY1]](s32), [[COPY]](s32), [[COPY1]](s32)
+ ; CHECK-NEXT: $q0 = COPY %bv0(<4 x s32>)
+ ; CHECK-NEXT: RET_ReallyLR implicit $w0
+ %0:_(s32) = COPY $w0
+ %1:_(s32) = COPY $w1
+ %2:_(s32) = COPY $w2
+ %3:_(s32) = COPY $w3
+ %bv0:_(<4 x s32>) = G_BUILD_VECTOR %0:_(s32), %1:_(s32), %0:_(s32), %1:_(s32)
+ %trunc:_(<4 x s16>) = nuw G_TRUNC %bv0
+ %zext:_(<4 x s32>) = G_ZEXT %trunc
+ $q0 = COPY %zext(<4 x s32>)
+ RET_ReallyLR implicit $w0
+...
+---
+name: sext_trunc_nsw
+body: |
+ bb.0:
+ liveins: $w0, $w1
+ ; CHECK-LABEL: name: sext_trunc_nsw
+ ; CHECK: liveins: $w0, $w1
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: [[COPY:%[0-9]+]]:_(s64) = COPY $x0
+ ; CHECK-NEXT: $x1 = COPY [[COPY]](s64)
+ %0:_(s64) = COPY $x0
+ %2:_(s32) = nsw G_TRUNC %0
+ %3:_(s64) = G_SEXT %2
+ $x1 = COPY %3
+...
+---
+name: sext_trunc_nuw
+body: |
+ bb.0:
+ liveins: $w0, $w1
+ ; CHECK-LABEL: name: sext_trunc_nuw
+ ; CHECK: liveins: $w0, $w1
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: [[COPY:%[0-9]+]]:_(s64) = COPY $x0
+ ; CHECK-NEXT: [[TRUNC:%[0-9]+]]:_(s32) = nuw G_TRUNC [[COPY]](s64)
+ ; CHECK-NEXT: [[SEXT:%[0-9]+]]:_(s64) = G_SEXT [[TRUNC]](s32)
+ ; CHECK-NEXT: $x1 = COPY [[SEXT]](s64)
+ %0:_(s64) = COPY $x0
+ %2:_(s32) = nuw G_TRUNC %0
+ %3:_(s64) = G_SEXT %2
+ $x1 = COPY %3
+...
+---
+name: sext_trunc
+body: |
+ bb.0:
+ liveins: $w0, $w1
+ ; CHECK-LABEL: name: sext_trunc
+ ; CHECK: liveins: $w0, $w1
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: [[COPY:%[0-9]+]]:_(s64) = COPY $x0
+ ; CHECK-NEXT: [[TRUNC:%[0-9]+]]:_(s32) = G_TRUNC [[COPY]](s64)
+ ; CHECK-NEXT: [[SEXT:%[0-9]+]]:_(s64) = G_SEXT [[TRUNC]](s32)
+ ; CHECK-NEXT: $x1 = COPY [[SEXT]](s64)
+ %0:_(s64) = COPY $x0
+ %2:_(s32) = G_TRUNC %0
+ %3:_(s64) = G_SEXT %2
+ $x1 = COPY %3
+...
+---
+name: sext_trunc_nsw_types_wrong
+body: |
+ bb.0:
+ liveins: $w0, $w1
+ ; CHECK-LABEL: name: sext_trunc_nsw_types_wrong
+ ; CHECK: liveins: $w0, $w1
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: [[COPY:%[0-9]+]]:_(s64) = COPY $x0
+ ; CHECK-NEXT: [[TRUNC:%[0-9]+]]:_(s16) = nsw G_TRUNC [[COPY]](s64)
+ ; CHECK-NEXT: [[SEXT:%[0-9]+]]:_(s32) = G_SEXT [[TRUNC]](s16)
+ ; CHECK-NEXT: $w1 = COPY [[SEXT]](s32)
+ %0:_(s64) = COPY $x0
+ %2:_(s16) = nsw G_TRUNC %0
+ %3:_(s32) = G_SEXT %2
+ $w1 = COPY %3
+...
+---
+name: sext_trunc_nsw_nuw
+body: |
+ bb.0:
+ liveins: $w0, $w1
+ ; CHECK-LABEL: name: sext_trunc_nsw_nuw
+ ; CHECK: liveins: $w0, $w1
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: [[COPY:%[0-9]+]]:_(s64) = COPY $x0
+ ; CHECK-NEXT: $x1 = COPY [[COPY]](s64)
+ %0:_(s64) = COPY $x0
+ %2:_(s32) = nsw nuw G_TRUNC %0
+ %3:_(s64) = G_SEXT %2
+ $x1 = COPY %3
+...
More information about the llvm-commits
mailing list