diff --git a/llvm/include/llvm/CodeGen/GlobalISel/CombinerHelper.h b/llvm/include/llvm/CodeGen/GlobalISel/CombinerHelper.h index 4f1c9642e117c..ecaece8b68342 100644 --- a/llvm/include/llvm/CodeGen/GlobalISel/CombinerHelper.h +++ b/llvm/include/llvm/CodeGen/GlobalISel/CombinerHelper.h @@ -599,10 +599,6 @@ class CombinerHelper { /// This variant does not erase \p MI after calling the build function. void applyBuildFnNoErase(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); - bool matchOrShiftToFunnelShift(MachineInstr &MI, BuildFnTy &MatchInfo); bool matchFunnelShiftToRotate(MachineInstr &MI); void applyFunnelShiftToRotate(MachineInstr &MI); @@ -814,6 +810,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); @@ -857,6 +859,9 @@ class CombinerHelper { /// register and different indices. bool matchExtractVectorElementWithDifferentIndices(const MachineOperand &MO, BuildFnTy &MatchInfo); + /// Use a function which takes in a MachineIRBuilder to perform a combine. + /// By default, it erases the instruction def'd on \p MO from the function. + void applyBuildFnMO(const MachineOperand &MO, BuildFnTy &MatchInfo); /// Combine insert vector element OOB. bool matchInsertVectorElementOOB(MachineInstr &MI, BuildFnTy &MatchInfo); diff --git a/llvm/include/llvm/CodeGen/GlobalISel/GenericMachineInstrs.h b/llvm/include/llvm/CodeGen/GlobalISel/GenericMachineInstrs.h index 705ef0fa7f2ba..2a3145b635e6c 100644 --- a/llvm/include/llvm/CodeGen/GlobalISel/GenericMachineInstrs.h +++ b/llvm/include/llvm/CodeGen/GlobalISel/GenericMachineInstrs.h @@ -792,6 +792,59 @@ class GFreeze : public GenericMachineInstr { } }; +/// 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: + case TargetOpcode::G_ANYEXT: + 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/CodeGen/GlobalISel/MachineIRBuilder.h b/llvm/include/llvm/CodeGen/GlobalISel/MachineIRBuilder.h index e15f7a7172e1a..92e05ee858a75 100644 --- a/llvm/include/llvm/CodeGen/GlobalISel/MachineIRBuilder.h +++ b/llvm/include/llvm/CodeGen/GlobalISel/MachineIRBuilder.h @@ -746,7 +746,8 @@ class MachineIRBuilder { /// \pre \p Op must be smaller than \p Res /// /// \return The newly created instruction. - MachineInstrBuilder buildZExt(const DstOp &Res, const SrcOp &Op); + MachineInstrBuilder buildZExt(const DstOp &Res, const SrcOp &Op, + std::optional Flags = std::nullopt); /// Build and insert \p Res = G_SEXT \p Op, \p Res = G_TRUNC \p Op, or /// \p Res = COPY \p Op depending on the differing sizes of \p Res and \p Op. @@ -1231,7 +1232,8 @@ class MachineIRBuilder { /// \pre \p Res must be smaller than \p Op /// /// \return The newly created instruction. - MachineInstrBuilder buildTrunc(const DstOp &Res, const SrcOp &Op); + MachineInstrBuilder buildTrunc(const DstOp &Res, const SrcOp &Op, + std::optional Flags = std::nullopt); /// Build and insert a \p Res = G_ICMP \p Pred, \p Op0, \p Op1 /// diff --git a/llvm/include/llvm/Target/GlobalISel/Combine.td b/llvm/include/llvm/Target/GlobalISel/Combine.td index 72c5de03f4e77..d0e1253903475 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 @@ -1501,6 +1503,20 @@ def extract_vector_element_freeze : GICombineRule< [{ return Helper.matchExtractVectorElementWithFreeze(${root}, ${matchinfo}); }]), (apply [{ Helper.applyBuildFnMO(${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}); }])>; + def extract_vector_element_shuffle_vector : GICombineRule< (defs root:$root, build_fn_matchinfo:$matchinfo), (match (G_SHUFFLE_VECTOR $src, $src1, $src2, $mask), @@ -1666,7 +1682,7 @@ def all_combines : GICombineGroup<[trivial_combines, vector_ops_combines, 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_shuffle_concat]>; + sext_trunc, zext_trunc, combine_shuffle_concat]>; // 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 653e7689b5774..9999776b98260 100644 --- a/llvm/lib/CodeGen/GlobalISel/CombinerHelper.cpp +++ b/llvm/lib/CodeGen/GlobalISel/CombinerHelper.cpp @@ -4137,14 +4137,6 @@ void CombinerHelper::applyBuildFn( MI.eraseFromParent(); } -void CombinerHelper::applyBuildFnMO(const MachineOperand &MO, - BuildFnTy &MatchInfo) { - MachineInstr *Root = getDefIgnoringCopies(MO.getReg(), MRI); - Builder.setInstrAndDebugLoc(*Root); - MatchInfo(Builder); - Root->eraseFromParent(); -} - void CombinerHelper::applyBuildFnNoErase( MachineInstr &MI, std::function &MatchInfo) { MatchInfo(Builder); @@ -7252,3 +7244,78 @@ bool CombinerHelper::matchAddOverflow(MachineInstr &MI, BuildFnTy &MatchInfo) { return false; } + +void CombinerHelper::applyBuildFnMO(const MachineOperand &MO, + BuildFnTy &MatchInfo) { + MachineInstr *Root = getDefIgnoringCopies(MO.getReg(), MRI); + MatchInfo(Builder); + Root->eraseFromParent(); +} + +bool CombinerHelper::matchSextOfTrunc(const MachineOperand &MO, + BuildFnTy &MatchInfo) { + GSext *Sext = cast(getDefIgnoringCopies(MO.getReg(), MRI)); + GTrunc *Trunc = cast(getDefIgnoringCopies(Sext->getSrcReg(), MRI)); + + Register Dst = Sext->getReg(0); + Register Src = Trunc->getSrcReg(); + + LLT DstTy = MRI.getType(Dst); + LLT SrcTy = MRI.getType(Src); + + if (DstTy == SrcTy) { + MatchInfo = [=](MachineIRBuilder &B) { B.buildCopy(Dst, Src); }; + return true; + } + + if (DstTy.getScalarSizeInBits() < SrcTy.getScalarSizeInBits() && + isLegalOrBeforeLegalizer({TargetOpcode::G_TRUNC, {DstTy, SrcTy}})) { + MatchInfo = [=](MachineIRBuilder &B) { + B.buildTrunc(Dst, Src, MachineInstr::MIFlag::NoSWrap); + }; + return true; + } + + if (DstTy.getScalarSizeInBits() > SrcTy.getScalarSizeInBits() && + isLegalOrBeforeLegalizer({TargetOpcode::G_SEXT, {DstTy, SrcTy}})) { + MatchInfo = [=](MachineIRBuilder &B) { B.buildSExt(Dst, Src); }; + return true; + } + + return false; +} + +bool CombinerHelper::matchZextOfTrunc(const MachineOperand &MO, + BuildFnTy &MatchInfo) { + GZext *Zext = cast(getDefIgnoringCopies(MO.getReg(), MRI)); + GTrunc *Trunc = cast(getDefIgnoringCopies(Zext->getSrcReg(), MRI)); + + Register Dst = Zext->getReg(0); + Register Src = Trunc->getSrcReg(); + + LLT DstTy = MRI.getType(Dst); + LLT SrcTy = MRI.getType(Src); + + if (DstTy == SrcTy) { + MatchInfo = [=](MachineIRBuilder &B) { B.buildCopy(Dst, Src); }; + return true; + } + + if (DstTy.getScalarSizeInBits() < SrcTy.getScalarSizeInBits() && + isLegalOrBeforeLegalizer({TargetOpcode::G_TRUNC, {DstTy, SrcTy}})) { + MatchInfo = [=](MachineIRBuilder &B) { + B.buildTrunc(Dst, Src, MachineInstr::MIFlag::NoUWrap); + }; + return true; + } + + if (DstTy.getScalarSizeInBits() > SrcTy.getScalarSizeInBits() && + isLegalOrBeforeLegalizer({TargetOpcode::G_ZEXT, {DstTy, SrcTy}})) { + MatchInfo = [=](MachineIRBuilder &B) { + B.buildZExt(Dst, Src, MachineInstr::MIFlag::NonNeg); + }; + return true; + } + + return false; +} diff --git a/llvm/lib/CodeGen/GlobalISel/GISelKnownBits.cpp b/llvm/lib/CodeGen/GlobalISel/GISelKnownBits.cpp index 529e50c8ebe05..c8199a42d15c3 100644 --- a/llvm/lib/CodeGen/GlobalISel/GISelKnownBits.cpp +++ b/llvm/lib/CodeGen/GlobalISel/GISelKnownBits.cpp @@ -64,8 +64,11 @@ KnownBits GISelKnownBits::getKnownBits(MachineInstr &MI) { KnownBits GISelKnownBits::getKnownBits(Register R) { const LLT Ty = MRI.getType(R); + // Since the number of lanes in a scalable vector is unknown at compile time, + // we track one bit which is implicitly broadcast to all lanes. This means + // that all lanes in a scalable vector are considered demanded. APInt DemandedElts = - Ty.isVector() ? APInt::getAllOnes(Ty.getNumElements()) : APInt(1, 1); + Ty.isFixedVector() ? APInt::getAllOnes(Ty.getNumElements()) : APInt(1, 1); return getKnownBits(R, DemandedElts); } diff --git a/llvm/lib/CodeGen/GlobalISel/MachineIRBuilder.cpp b/llvm/lib/CodeGen/GlobalISel/MachineIRBuilder.cpp index 2e8407813ba64..afe2703569407 100644 --- a/llvm/lib/CodeGen/GlobalISel/MachineIRBuilder.cpp +++ b/llvm/lib/CodeGen/GlobalISel/MachineIRBuilder.cpp @@ -490,8 +490,9 @@ MachineInstrBuilder MachineIRBuilder::buildSExt(const DstOp &Res, } MachineInstrBuilder MachineIRBuilder::buildZExt(const DstOp &Res, - const SrcOp &Op) { - return buildInstr(TargetOpcode::G_ZEXT, Res, Op); + const SrcOp &Op, + std::optional Flags) { + return buildInstr(TargetOpcode::G_ZEXT, Res, Op, Flags); } unsigned MachineIRBuilder::getBoolExtOp(bool IsVec, bool IsFP) const { @@ -869,9 +870,10 @@ MachineInstrBuilder MachineIRBuilder::buildIntrinsic(Intrinsic::ID ID, return buildIntrinsic(ID, Results, HasSideEffects, isConvergent); } -MachineInstrBuilder MachineIRBuilder::buildTrunc(const DstOp &Res, - const SrcOp &Op) { - return buildInstr(TargetOpcode::G_TRUNC, Res, Op); +MachineInstrBuilder +MachineIRBuilder::buildTrunc(const DstOp &Res, const SrcOp &Op, + std::optional Flags) { + return buildInstr(TargetOpcode::G_TRUNC, Res, Op, Flags); } MachineInstrBuilder 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 0000000000000..6eece5c56258d --- /dev/null +++ b/llvm/test/CodeGen/AArch64/GlobalISel/combine-with-flags.mir @@ -0,0 +1,353 @@ +# 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]+]]:_(s32) = nsw G_TRUNC [[COPY]](s64) + ; CHECK-NEXT: $w1 = COPY [[TRUNC]](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 +... +--- +name: sext_trunc_nsw_nuw_vector +body: | + bb.0: + liveins: $w0, $w1 + ; CHECK-LABEL: name: sext_trunc_nsw_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: [[COPY2:%[0-9]+]]:_(s32) = COPY $w2 + ; CHECK-NEXT: [[COPY3:%[0-9]+]]:_(s32) = COPY $w3 + ; CHECK-NEXT: %bv0:_(<4 x s32>) = G_BUILD_VECTOR [[COPY]](s32), [[COPY1]](s32), [[COPY2]](s32), [[COPY3]](s32) + ; CHECK-NEXT: $q0 = COPY %bv0(<4 x s32>) + %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), %2:_(s32), %3:_(s32) + %t:_(<4 x s16>) = nsw nuw G_TRUNC %bv0 + %s:_(<4 x s32>) = G_SEXT %t + $q0 = COPY %s +... +--- +name: zext_trunc_vector +body: | + bb.0: + liveins: $w0, $w1 + ; CHECK-LABEL: name: zext_trunc_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: [[COPY2:%[0-9]+]]:_(s32) = COPY $w2 + ; CHECK-NEXT: [[COPY3:%[0-9]+]]:_(s32) = COPY $w3 + ; CHECK-NEXT: %bv0:_(<4 x s32>) = G_BUILD_VECTOR [[COPY]](s32), [[COPY1]](s32), [[COPY2]](s32), [[COPY3]](s32) + ; CHECK-NEXT: %t:_(<4 x s16>) = G_TRUNC %bv0(<4 x s32>) + ; CHECK-NEXT: %z:_(<4 x s32>) = G_ZEXT %t(<4 x s16>) + ; CHECK-NEXT: $q0 = COPY %z(<4 x s32>) + %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), %2:_(s32), %3:_(s32) + %t:_(<4 x s16>) = G_TRUNC %bv0 + %z:_(<4 x s32>) = G_ZEXT %t + $q0 = COPY %z +... +--- +name: zext_trunc_nsw_vector +body: | + bb.0: + liveins: $w0, $w1 + ; CHECK-LABEL: name: zext_trunc_nsw_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: [[COPY2:%[0-9]+]]:_(s32) = COPY $w2 + ; CHECK-NEXT: [[COPY3:%[0-9]+]]:_(s32) = COPY $w3 + ; CHECK-NEXT: %bv0:_(<4 x s32>) = G_BUILD_VECTOR [[COPY]](s32), [[COPY1]](s32), [[COPY2]](s32), [[COPY3]](s32) + ; CHECK-NEXT: %t:_(<4 x s16>) = nsw G_TRUNC %bv0(<4 x s32>) + ; CHECK-NEXT: %z:_(<4 x s32>) = G_ZEXT %t(<4 x s16>) + ; CHECK-NEXT: $q0 = COPY %z(<4 x s32>) + %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), %2:_(s32), %3:_(s32) + %t:_(<4 x s16>) = nsw G_TRUNC %bv0 + %z:_(<4 x s32>) = G_ZEXT %t + $q0 = COPY %z +... +--- +name: zext_trunc_nuw_vector2 +body: | + bb.0: + liveins: $w0, $w1 + ; CHECK-LABEL: name: zext_trunc_nuw_vector2 + ; CHECK: liveins: $w0, $w1 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: [[COPY:%[0-9]+]]:_(s32) = COPY $w0 + ; CHECK-NEXT: [[COPY1:%[0-9]+]]:_(s32) = COPY $w1 + ; CHECK-NEXT: [[COPY2:%[0-9]+]]:_(s32) = COPY $w2 + ; CHECK-NEXT: [[COPY3:%[0-9]+]]:_(s32) = COPY $w3 + ; CHECK-NEXT: %bv0:_(<4 x s32>) = G_BUILD_VECTOR [[COPY]](s32), [[COPY1]](s32), [[COPY2]](s32), [[COPY3]](s32) + ; CHECK-NEXT: $q0 = COPY %bv0(<4 x s32>) + %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), %2:_(s32), %3:_(s32) + %t:_(<4 x s16>) = nuw G_TRUNC %bv0 + %z:_(<4 x s32>) = G_ZEXT %t + $q0 = COPY %z +... +--- +name: zext_trunc_nuw_vector_wrong_type +body: | + bb.0: + liveins: $w0, $w1 + ; CHECK-LABEL: name: zext_trunc_nuw_vector_wrong_type + ; CHECK: liveins: $w0, $w1 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: [[COPY:%[0-9]+]]:_(s64) = COPY $x0 + ; CHECK-NEXT: [[COPY1:%[0-9]+]]:_(s64) = COPY $x1 + ; CHECK-NEXT: %bv0:_(<2 x s64>) = G_BUILD_VECTOR [[COPY]](s64), [[COPY1]](s64) + ; CHECK-NEXT: %z:_(<2 x s32>) = nuw G_TRUNC %bv0(<2 x s64>) + ; CHECK-NEXT: $d0 = COPY %z(<2 x s32>) + %0:_(s64) = COPY $x0 + %1:_(s64) = COPY $x1 + %bv0:_(<2 x s64>) = G_BUILD_VECTOR %0:_(s64), %1:_(s64) + %t:_(<2 x s16>) = nuw G_TRUNC %bv0 + %z:_(<2 x s32>) = G_ZEXT %t + $d0 = COPY %z +... +--- +name: zext_trunc_nuw_scalable_vector +body: | + bb.0: + liveins: $w0, $w1 + ; CHECK-LABEL: name: zext_trunc_nuw_scalable_vector + ; CHECK: liveins: $w0, $w1 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: [[COPY:%[0-9]+]]:_(s64) = COPY $x0 + ; CHECK-NEXT: %sv0:_() = G_SPLAT_VECTOR [[COPY]](s64) + ; CHECK-NEXT: $z0 = COPY %sv0() + %0:_(s64) = COPY $x0 + %1:_(s64) = COPY $x1 + %sv0:_() = G_SPLAT_VECTOR %0:_(s64) + %t:_() = nuw G_TRUNC %sv0 + %z:_() = G_ZEXT %t + $z0 = COPY %z +... +--- +name: zext_trunc_nuw_to_zext +body: | + bb.0: + liveins: $w0, $w1 + ; CHECK-LABEL: name: zext_trunc_nuw_to_zext + ; CHECK: liveins: $w0, $w1 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: [[COPY:%[0-9]+]]:_(s32) = COPY $w0 + ; CHECK-NEXT: %2:_(s64) = nneg G_ZEXT [[COPY]](s32) + ; CHECK-NEXT: $x1 = COPY %2(s64) + %0:_(s32) = COPY $w0 + %2:_(s16) = nuw G_TRUNC %0 + %3:_(s64) = G_ZEXT %2 + $x1 = COPY %3 +... +--- +name: zext_trunc_nuw_to_trunc +body: | + bb.0: + liveins: $w0, $w1 + ; CHECK-LABEL: name: zext_trunc_nuw_to_trunc + ; 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: $w1 = COPY [[TRUNC]](s32) + %0:_(s64) = COPY $x0 + %2:_(s16) = nuw G_TRUNC %0 + %3:_(s32) = G_ZEXT %2 + $w1 = COPY %3 +... +--- +name: sext_trunc_nsw_to_sext +body: | + bb.0: + liveins: $w0, $w1 + ; CHECK-LABEL: name: sext_trunc_nsw_to_sext + ; CHECK: liveins: $w0, $w1 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: [[COPY:%[0-9]+]]:_(s32) = COPY $w0 + ; CHECK-NEXT: [[SEXT:%[0-9]+]]:_(s64) = G_SEXT [[COPY]](s32) + ; CHECK-NEXT: $x1 = COPY [[SEXT]](s64) + %0:_(s32) = COPY $w0 + %2:_(s16) = nsw G_TRUNC %0 + %3:_(s64) = G_SEXT %2 + $x1 = COPY %3 +... +--- +name: sext_trunc_nsw_to_trunc +body: | + bb.0: + liveins: $w0, $w1 + ; CHECK-LABEL: name: sext_trunc_nsw_to_trunc + ; 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: $w1 = COPY [[TRUNC]](s32) + %0:_(s64) = COPY $x0 + %2:_(s16) = nsw G_TRUNC %0 + %3:_(s32) = G_SEXT %2 + $w1 = COPY %3 +...