Index: llvm/include/llvm/CodeGen/GlobalISel/CombinerHelper.h =================================================================== --- llvm/include/llvm/CodeGen/GlobalISel/CombinerHelper.h +++ llvm/include/llvm/CodeGen/GlobalISel/CombinerHelper.h @@ -190,6 +190,19 @@ bool applyCombineShiftToUnmerge(MachineInstr &MI, const unsigned &ShiftVal); bool tryCombineShiftToUnmerge(MachineInstr &MI, unsigned TargetShiftAmount); + /// Return true if any explicit use operand on \p MI is defined by a + /// G_IMPLICIT_DEF. + bool matchAnyExplicitUseIsUndef(MachineInstr &MI); + + /// Replace an instruction with a G_FCONSTANT with value \p C. + bool replaceInstWithFConstant(MachineInstr &MI, double C); + + /// Replace an instruction with a G_CONSTANT with value \p C. + bool replaceInstWithConstant(MachineInstr &MI, int64_t C); + + /// Replace an instruction with a G_IMPLICIT_DEF. + bool replaceInstWithUndef(MachineInstr &MI); + /// Try to transform \p MI by using all of the above /// combine functions. Returns true if changed. bool tryCombine(MachineInstr &MI); Index: llvm/include/llvm/Target/GlobalISel/Combine.td =================================================================== --- llvm/include/llvm/Target/GlobalISel/Combine.td +++ llvm/include/llvm/Target/GlobalISel/Combine.td @@ -142,7 +142,34 @@ [{ return Helper.matchCombineMulToShl(*${mi}, ${matchinfo}); }]), (apply [{ Helper.applyCombineMulToShl(*${mi}, ${matchinfo}); }])>; +// [us]itofp(undef) = 0, because the result value is bounded. +def undef_to_fp_zero : GICombineRule< + (defs root:$root), + (match (wip_match_opcode G_UITOFP, G_SITOFP):$root, + [{ return Helper.matchAnyExplicitUseIsUndef(*${root}); }]), + (apply [{ Helper.replaceInstWithFConstant(*${root}, 0.0); }])>; + +def undef_to_int_zero: GICombineRule< + (defs root:$root), + (match (wip_match_opcode G_AND, G_MUL):$root, + [{ return Helper.matchAnyExplicitUseIsUndef(*${root}); }]), + (apply [{ Helper.replaceInstWithConstant(*${root}, 0); }])>; + +def undef_to_negative_one: GICombineRule< + (defs root:$root), + (match (wip_match_opcode G_OR):$root, + [{ return Helper.matchAnyExplicitUseIsUndef(*${root}); }]), + (apply [{ Helper.replaceInstWithConstant(*${root}, -1); }])>; + +def propagate_undef: GICombineRule< + (defs root:$root), + (match (wip_match_opcode G_ADD, G_FPTOSI, G_FPTOUI, G_SUB, G_XOR):$root, + [{ return Helper.matchAnyExplicitUseIsUndef(*${root}); }]), + (apply [{ Helper.replaceInstWithUndef(*${root}); }])>; + +def undef_combines : GICombineGroup<[undef_to_fp_zero, undef_to_int_zero, + undef_to_negative_one, propagate_undef]>; + def trivial_combines : GICombineGroup<[copy_prop, mul_to_shl]>; def all_combines : GICombineGroup<[trivial_combines, ptr_add_immed_chain, - combines_for_extload, combine_indexed_load_store]>; - + combines_for_extload, combine_indexed_load_store, undef_combines]>; Index: llvm/lib/CodeGen/GlobalISel/CombinerHelper.cpp =================================================================== --- llvm/lib/CodeGen/GlobalISel/CombinerHelper.cpp +++ llvm/lib/CodeGen/GlobalISel/CombinerHelper.cpp @@ -1483,6 +1483,37 @@ return false; } +bool CombinerHelper::matchAnyExplicitUseIsUndef(MachineInstr &MI) { + return any_of(MI.explicit_uses(), [this](const MachineOperand &MO) { + return MO.isReg() && + getOpcodeDef(TargetOpcode::G_IMPLICIT_DEF, MO.getReg(), MRI); + }); +} + +bool CombinerHelper::replaceInstWithFConstant(MachineInstr &MI, double C) { + assert(MI.getNumDefs() == 1 && "Expected only one def?"); + Builder.setInstr(MI); + Builder.buildFConstant(MI.getOperand(0), C); + MI.eraseFromParent(); + return true; +} + +bool CombinerHelper::replaceInstWithConstant(MachineInstr &MI, int64_t C) { + assert(MI.getNumDefs() == 1 && "Expected only one def?"); + Builder.setInstr(MI); + Builder.buildConstant(MI.getOperand(0), C); + MI.eraseFromParent(); + return true; +} + +bool CombinerHelper::replaceInstWithUndef(MachineInstr &MI) { + assert(MI.getNumDefs() == 1 && "Expected only one def?"); + Builder.setInstr(MI); + Builder.buildUndef(MI.getOperand(0)); + MI.eraseFromParent(); + return true; +} + bool CombinerHelper::tryCombine(MachineInstr &MI) { if (tryCombineCopy(MI)) return true; Index: llvm/test/CodeGen/AArch64/GlobalISel/arm64-fallback.ll =================================================================== --- llvm/test/CodeGen/AArch64/GlobalISel/arm64-fallback.ll +++ llvm/test/CodeGen/AArch64/GlobalISel/arm64-fallback.ll @@ -167,16 +167,6 @@ ret void } -; FALLBACK-WITH-REPORT-ERR: remark: :0:0: cannot select: %{{[0-9]+}}:gpr64(s64), %{{[0-9]+}}:gpr(s1) = G_UADDE %{{[0-9]+}}:gpr, %{{[0-9]+}}:gpr, %{{[0-9]+}}:gpr (in function: nonpow2_store_narrowing) -; FALLBACK-WITH-REPORT-ERR: warning: Instruction selection used fallback path for nonpow2_store_narrowing -; FALLBACK-WITH-REPORT-OUT-LABEL: nonpow2_store_narrowing: -define void @nonpow2_store_narrowing(i96* %c) { - %a = add i128 undef, undef - %b = trunc i128 %a to i96 - store i96 %b, i96* %c - ret void -} - ; Currently can't handle vector lengths that aren't an exact multiple of ; natively supported vector lengths. Test that the fall-back works for those. ; FALLBACK-WITH-REPORT-ERR-G_IMPLICIT_DEF-LEGALIZABLE: (FIXME: this is what is expected once we can legalize non-pow-of-2 G_IMPLICIT_DEF) remark: :0:0: unable to legalize instruction: %1:_(<7 x s64>) = G_ADD %0, %0 (in function: nonpow2_vector_add_fewerelements Index: llvm/test/CodeGen/AArch64/GlobalISel/prelegalizercombiner-undef.mir =================================================================== --- /dev/null +++ llvm/test/CodeGen/AArch64/GlobalISel/prelegalizercombiner-undef.mir @@ -0,0 +1,168 @@ +# 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 + +name: uitofp_to_zero +alignment: 4 +tracksRegLiveness: true +body: | + bb.0: + ; CHECK-LABEL: name: uitofp_to_zero + ; CHECK: [[C:%[0-9]+]]:_(s32) = G_FCONSTANT float 0.000000e+00 + ; CHECK: $s0 = COPY [[C]](s32) + ; CHECK: RET_ReallyLR implicit $s0 + %0:_(s32) = G_IMPLICIT_DEF + %1:_(s32) = G_UITOFP %0(s32) + $s0 = COPY %1(s32) + RET_ReallyLR implicit $s0 + +... +--- +name: sitofp_to_zero +alignment: 4 +tracksRegLiveness: true +body: | + bb.0: + ; CHECK-LABEL: name: sitofp_to_zero + ; CHECK: [[C:%[0-9]+]]:_(s32) = G_FCONSTANT float 0.000000e+00 + ; CHECK: $s0 = COPY [[C]](s32) + ; CHECK: RET_ReallyLR implicit $s0 + %0:_(s32) = G_IMPLICIT_DEF + %1:_(s32) = G_SITOFP %0(s32) + $s0 = COPY %1(s32) + RET_ReallyLR implicit $s0 + +... +--- +name: and_to_zero +alignment: 4 +tracksRegLiveness: true +body: | + bb.0: + ; CHECK-LABEL: name: and_to_zero + ; CHECK: [[C:%[0-9]+]]:_(s32) = G_CONSTANT i32 0 + ; CHECK: $w0 = COPY [[C]](s32) + ; CHECK: RET_ReallyLR implicit $w0 + %0:_(s32) = G_CONSTANT i32 10 + %1:_(s32) = G_IMPLICIT_DEF + %2:_(s32) = G_AND %0, %1 + $w0 = COPY %2(s32) + RET_ReallyLR implicit $w0 + +... +--- +name: mul_to_zero +alignment: 4 +tracksRegLiveness: true +body: | + bb.0: + ; CHECK-LABEL: name: mul_to_zero + ; CHECK: [[C:%[0-9]+]]:_(s32) = G_CONSTANT i32 0 + ; CHECK: $w0 = COPY [[C]](s32) + ; CHECK: RET_ReallyLR implicit $w0 + %0:_(s32) = G_CONSTANT i32 10 + %1:_(s32) = G_IMPLICIT_DEF + %2:_(s32) = G_MUL %0, %1 + $w0 = COPY %2(s32) + RET_ReallyLR implicit $w0 + +... +--- +name: or_to_negative_one +alignment: 4 +tracksRegLiveness: true +body: | + bb.0: + ; CHECK-LABEL: name: or_to_negative_one + ; CHECK: [[C:%[0-9]+]]:_(s32) = G_CONSTANT i32 -1 + ; CHECK: $w0 = COPY [[C]](s32) + ; CHECK: RET_ReallyLR implicit $w0 + %0:_(s32) = G_CONSTANT i32 10 + %1:_(s32) = G_IMPLICIT_DEF + %2:_(s32) = G_OR %0, %1 + $w0 = COPY %2(s32) + RET_ReallyLR implicit $w0 + +... +--- +name: xor_to_undef +alignment: 4 +tracksRegLiveness: true +body: | + bb.0: + ; CHECK-LABEL: name: xor_to_undef + ; CHECK: [[DEF:%[0-9]+]]:_(s32) = G_IMPLICIT_DEF + ; CHECK: $w0 = COPY [[DEF]](s32) + ; CHECK: RET_ReallyLR implicit $w0 + %0:_(s32) = G_CONSTANT i32 10 + %1:_(s32) = G_IMPLICIT_DEF + %2:_(s32) = G_XOR %0, %1 + $w0 = COPY %2(s32) + RET_ReallyLR implicit $w0 + +... +--- +name: add_to_undef +alignment: 4 +tracksRegLiveness: true +body: | + bb.0: + ; CHECK-LABEL: name: add_to_undef + ; CHECK: [[DEF:%[0-9]+]]:_(s32) = G_IMPLICIT_DEF + ; CHECK: $w0 = COPY [[DEF]](s32) + ; CHECK: RET_ReallyLR implicit $w0 + %0:_(s32) = G_CONSTANT i32 10 + %1:_(s32) = G_IMPLICIT_DEF + %2:_(s32) = G_ADD %0, %1 + $w0 = COPY %2(s32) + RET_ReallyLR implicit $w0 + +... +--- +name: sub_to_undef +alignment: 4 +tracksRegLiveness: true +body: | + bb.0: + ; CHECK-LABEL: name: sub_to_undef + ; CHECK: [[DEF:%[0-9]+]]:_(s32) = G_IMPLICIT_DEF + ; CHECK: $w0 = COPY [[DEF]](s32) + ; CHECK: RET_ReallyLR implicit $w0 + %0:_(s32) = G_CONSTANT i32 10 + %1:_(s32) = G_IMPLICIT_DEF + %2:_(s32) = G_SUB %0, %1 + $w0 = COPY %2(s32) + RET_ReallyLR implicit $w0 + +... +--- +name: fptoui_to_undef +alignment: 4 +tracksRegLiveness: true +body: | + bb.0: + ; CHECK-LABEL: name: fptoui_to_undef + ; CHECK: [[DEF:%[0-9]+]]:_(s32) = G_IMPLICIT_DEF + ; CHECK: $w0 = COPY [[DEF]](s32) + ; CHECK: RET_ReallyLR implicit $w0 + %0:_(s32) = G_IMPLICIT_DEF + %1:_(s32) = G_FPTOUI %0(s32) + $w0 = COPY %1(s32) + RET_ReallyLR implicit $w0 + +... +--- +name: fptosi_to_undef +alignment: 4 +tracksRegLiveness: true +body: | + bb.0: + ; CHECK-LABEL: name: fptosi_to_undef + ; CHECK: [[DEF:%[0-9]+]]:_(s32) = G_IMPLICIT_DEF + ; CHECK: $w0 = COPY [[DEF]](s32) + ; CHECK: RET_ReallyLR implicit $w0 + %0:_(s32) = G_IMPLICIT_DEF + %1:_(s32) = G_FPTOSI %0(s32) + $w0 = COPY %1(s32) + RET_ReallyLR implicit $w0 + +...