Index: llvm/include/llvm/CodeGen/GlobalISel/CombinerHelper.h =================================================================== --- llvm/include/llvm/CodeGen/GlobalISel/CombinerHelper.h +++ llvm/include/llvm/CodeGen/GlobalISel/CombinerHelper.h @@ -243,6 +243,9 @@ bool applyCombineShiftToUnmerge(MachineInstr &MI, const unsigned &ShiftVal); bool tryCombineShiftToUnmerge(MachineInstr &MI, unsigned TargetShiftAmount); + /// Transform fp_instr(cst) to constant result of the fp operation. + bool matchCombineConstantFoldFpUnary(MachineInstr &MI, double &Cst); + /// Transform IntToPtr(PtrToInt(x)) to x if cast is in the same address space. bool matchCombineI2PToP2I(MachineInstr &MI, Register &Reg); bool applyCombineI2PToP2I(MachineInstr &MI, Register &Reg); Index: llvm/include/llvm/Target/GlobalISel/Combine.td =================================================================== --- llvm/include/llvm/Target/GlobalISel/Combine.td +++ llvm/include/llvm/Target/GlobalISel/Combine.td @@ -273,6 +273,51 @@ (apply [{ return Helper.applySimplifyAddToSub(*${root}, ${info});}]) >; +// Fold fneg(cst) to cst result of fneg operation +def constant_fneg_matchinfo: GIDefMatchData<"double">; +def constant_fneg: GICombineRule < + (defs root:$root, constant_fneg_matchinfo:$info), + (match (wip_match_opcode G_FNEG):$root, + [{ return Helper.matchCombineConstantFoldFpUnary(*${root}, ${info}); }]), + (apply [{ return Helper.replaceInstWithFConstant(*${root}, ${info}); }]) +>; + +// Fold fabs(cst) to cst result of fabs operation +def constant_fabs_matchinfo: GIDefMatchData<"double">; +def constant_fabs: GICombineRule < + (defs root:$root, constant_fabs_matchinfo:$info), + (match (wip_match_opcode G_FABS):$root, + [{ return Helper.matchCombineConstantFoldFpUnary(*${root}, ${info}); }]), + (apply [{ return Helper.replaceInstWithFConstant(*${root}, ${info}); }]) +>; + +// Fold fptrunc(cst) to cst result of fptrunc operation +def constant_fptrunc_matchinfo: GIDefMatchData<"double">; +def constant_fptrunc: GICombineRule < + (defs root:$root, constant_fptrunc_matchinfo:$info), + (match (wip_match_opcode G_FPTRUNC):$root, + [{ return Helper.matchCombineConstantFoldFpUnary(*${root}, ${info}); }]), + (apply [{ return Helper.replaceInstWithFConstant(*${root}, ${info}); }]) +>; + +// Fold fsqrt(cst) to cst result of fsqrt operation +def constant_fsqrt_matchinfo: GIDefMatchData<"double">; +def constant_fsqrt: GICombineRule < + (defs root:$root, constant_fsqrt_matchinfo:$info), + (match (wip_match_opcode G_FSQRT):$root, + [{ return Helper.matchCombineConstantFoldFpUnary(*${root}, ${info}); }]), + (apply [{ return Helper.replaceInstWithFConstant(*${root}, ${info}); }]) +>; + +// Fold flog2(cst) to cst result of flog2 operation +def constant_flog2_matchinfo: GIDefMatchData<"double">; +def constant_flog2: GICombineRule < + (defs root:$root, constant_flog2_matchinfo:$info), + (match (wip_match_opcode G_FLOG2):$root, + [{ return Helper.matchCombineConstantFoldFpUnary(*${root}, ${info}); }]), + (apply [{ return Helper.replaceInstWithFConstant(*${root}, ${info}); }]) +>; + // Fold int2ptr(ptr2int(x)) -> x def p2i_to_i2p_matchinfo: GIDefMatchData<"Register">; def p2i_to_i2p: GICombineRule< @@ -331,10 +376,14 @@ def width_reduction_combines : GICombineGroup<[reduce_shl_of_extend]>; +def constant_fp_combines : GICombineGroup<[constant_fneg, constant_fabs, + constant_fptrunc, constant_fsqrt, + constant_flog2]>; + 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, undef_combines, identity_combines, simplify_add_to_sub, hoist_logic_op_with_same_opcode_hands, shl_ashr_to_sext_inreg, sext_inreg_of_load, - width_reduction_combines]>; + width_reduction_combines, constant_fp_combines]>; Index: llvm/lib/CodeGen/GlobalISel/CombinerHelper.cpp =================================================================== --- llvm/lib/CodeGen/GlobalISel/CombinerHelper.cpp +++ llvm/lib/CodeGen/GlobalISel/CombinerHelper.cpp @@ -1435,6 +1435,71 @@ return false; } +static Optional constantFoldFpUnary(unsigned Opcode, LLT DstTy, + const Register Op, + const MachineRegisterInfo &MRI) { + const ConstantFP *MaybeCst = getConstantFPVRegVal(Op, MRI); + if (!MaybeCst) + return None; + APFloat V = MaybeCst->getValueAPF(); + switch (Opcode) { + default: + break; + case TargetOpcode::G_FNEG: { + V.changeSign(); + return V; + } + case TargetOpcode::G_FABS: { + V.clearSign(); + return V; + } + case TargetOpcode::G_FLOG2: { + bool Unused; + V.convert(APFloat::IEEEdouble(), APFloat::rmNearestTiesToEven, &Unused); + double InVal = V.convertToDouble(); + return DstTy == LLT::scalar(32) ? APFloat(log2(static_cast(InVal))) + : APFloat(log2(InVal)); + } + case TargetOpcode::G_FPTRUNC: { + bool Unused; + if (DstTy == LLT::scalar(16)) + V.convert(APFloat::IEEEhalf(), APFloat::rmTowardZero, &Unused); + else if (DstTy == LLT::scalar(32)) + V.convert(APFloat::IEEEsingle(), APFloat::rmTowardZero, &Unused); + else + return None; + return V; + } + case TargetOpcode::G_FSQRT: { + bool Unused; + V.convert(APFloat::IEEEdouble(), APFloat::rmNearestTiesToEven, &Unused); + double InVal = V.convertToDouble(); + InVal = sqrt(InVal); + return APFloat(static_cast(InVal)); + } + } + return None; +} + +bool CombinerHelper::matchCombineConstantFoldFpUnary(MachineInstr &MI, + double &Cst) { + Register DstReg = MI.getOperand(0).getReg(); + Register SrcReg = MI.getOperand(1).getReg(); + LLT DstTy = MRI.getType(DstReg); + + auto MaybeCst = constantFoldFpUnary(MI.getOpcode(), DstTy, SrcReg, MRI); + if (MaybeCst) { + // Convert up to double so we can pass the constant value to the replacement + // function. + bool Unused; + MaybeCst->convert(APFloat::IEEEdouble(), APFloat::rmNearestTiesToEven, + &Unused); + Cst = MaybeCst->convertToDouble(); + } + + return MaybeCst.hasValue(); +} + bool CombinerHelper::matchPtrAddImmedChain(MachineInstr &MI, PtrAddChain &MatchInfo) { // We're trying to match the following pattern: Index: llvm/test/CodeGen/AArch64/GlobalISel/combine-fabs.mir =================================================================== --- /dev/null +++ llvm/test/CodeGen/AArch64/GlobalISel/combine-fabs.mir @@ -0,0 +1,74 @@ +# 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 +# RUN: llc -debugify-and-strip-all-safe -run-pass=aarch64-prelegalizer-combiner -verify-machineinstrs -mtriple aarch64-unknown-unknown %s -o - | FileCheck %s + +--- +name: test_combine_half_fabs_neg_constant +body: | + bb.1: + ; CHECK-LABEL: name: test_combine_half_fabs_neg_constant + ; CHECK: [[C:%[0-9]+]]:_(s16) = G_FCONSTANT half 0xH4580 + ; CHECK: $h0 = COPY [[C]](s16) + %0:_(s16) = G_FCONSTANT half 0xHC580 + %1:_(s16) = G_FABS %0 + $h0 = COPY %1(s16) +... +--- +name: test_combine_half_fabs_pos_constant +body: | + bb.1: + ; CHECK-LABEL: name: test_combine_half_fabs_pos_constant + ; CHECK: [[C:%[0-9]+]]:_(s16) = G_FCONSTANT half 0xH4580 + ; CHECK: $h0 = COPY [[C]](s16) + %0:_(s16) = G_FCONSTANT half 0xH4580 + %1:_(s16) = G_FABS %0 + $h0 = COPY %1(s16) +... +--- +name: test_combine_float_fabs_neg_constant +body: | + bb.1: + liveins: $w0 + ; CHECK-LABEL: name: test_combine_float_fabs_neg_constant + ; CHECK: [[C:%[0-9]+]]:_(s32) = G_FCONSTANT float 5.500000e+00 + ; CHECK: $w0 = COPY [[C]](s32) + %0:_(s32) = G_FCONSTANT float -5.500000e+00 + %1:_(s32) = G_FABS %0 + $w0 = COPY %1(s32) +... +--- +name: test_combine_float_fabs_pos_constant +body: | + bb.1: + liveins: $w0 + ; CHECK-LABEL: name: test_combine_float_fabs_pos_constant + ; CHECK: [[C:%[0-9]+]]:_(s32) = G_FCONSTANT float 5.500000e+00 + ; CHECK: $w0 = COPY [[C]](s32) + %0:_(s32) = G_FCONSTANT float -5.500000e+00 + %1:_(s32) = G_FABS %0 + $w0 = COPY %1(s32) +... +--- +name: test_combine_double_fabs_neg_constant +body: | + bb.1: + liveins: $x0 + ; CHECK-LABEL: name: test_combine_double_fabs_neg_constant + ; CHECK: [[C:%[0-9]+]]:_(s64) = G_FCONSTANT double 4.200000e+00 + ; CHECK: $x0 = COPY [[C]](s64) + %0:_(s64) = G_FCONSTANT double -4.200000e+00 + %1:_(s64) = G_FABS %0 + $x0 = COPY %1(s64) +... +--- +name: test_combine_double_fabs_pos_constant +body: | + bb.1: + liveins: $x0 + ; CHECK-LABEL: name: test_combine_double_fabs_pos_constant + ; CHECK: [[C:%[0-9]+]]:_(s64) = G_FCONSTANT double 4.200000e+00 + ; CHECK: $x0 = COPY [[C]](s64) + %0:_(s64) = G_FCONSTANT double 4.200000e+00 + %1:_(s64) = G_FABS %0 + $x0 = COPY %0(s64) +... Index: llvm/test/CodeGen/AArch64/GlobalISel/combine-flog2.mir =================================================================== --- /dev/null +++ llvm/test/CodeGen/AArch64/GlobalISel/combine-flog2.mir @@ -0,0 +1,37 @@ +# 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 +# RUN: llc -debugify-and-strip-all-safe -run-pass=aarch64-prelegalizer-combiner -verify-machineinstrs -mtriple aarch64-unknown-unknown %s -o - | FileCheck %s + +--- +name: test_combine_half_flog2_constant +body: | + bb.1: + ; CHECK-LABEL: name: test_combine_half_flog2_constant + ; CHECK: [[C:%[0-9]+]]:_(s16) = G_FCONSTANT half 0xH4000 + ; CHECK: $h0 = COPY [[C]](s16) + %0:_(s16) = G_FCONSTANT half 4.000000e+00 + %1:_(s16) = G_FLOG2 %0 + $h0 = COPY %1(s16) +... +--- +name: test_combine_float_flog2_constant +body: | + bb.1: + ; CHECK-LABEL: name: test_combine_float_flog2_constant + ; CHECK: [[C:%[0-9]+]]:_(s32) = G_FCONSTANT float 2.000000e+00 + ; CHECK: $w0 = COPY [[C]](s32) + %0:_(s32) = G_FCONSTANT float 4.000000e+00 + %1:_(s32) = G_FLOG2 %0 + $w0 = COPY %1(s32) +... +--- +name: test_combine_double_flog2_constant +body: | + bb.1: + ; CHECK-LABEL: name: test_combine_double_flog2_constant + ; CHECK: [[C:%[0-9]+]]:_(s64) = G_FCONSTANT double 2.000000e+00 + ; CHECK: $x0 = COPY [[C]](s64) + %0:_(s64) = G_FCONSTANT double 4.000000e+00 + %1:_(s64) = G_FLOG2 %0 + $x0 = COPY %1(s64) +... Index: llvm/test/CodeGen/AArch64/GlobalISel/combine-fneg.mir =================================================================== --- /dev/null +++ llvm/test/CodeGen/AArch64/GlobalISel/combine-fneg.mir @@ -0,0 +1,70 @@ +# 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 +# RUN: llc -debugify-and-strip-all-safe -run-pass=aarch64-prelegalizer-combiner -verify-machineinstrs -mtriple aarch64-unknown-unknown %s -o - | FileCheck %s + +--- +name: test_combine_half_fneg_neg_constant +body: | + bb.1: + ; CHECK-LABEL: name: test_combine_half_fneg_neg_constant + ; CHECK: [[C:%[0-9]+]]:_(s16) = G_FCONSTANT half 0xH4580 + ; CHECK: $h0 = COPY [[C]](s16) + %0:_(s16) = G_FCONSTANT half 0xHC580 + %1:_(s16) = G_FNEG %0 + $h0 = COPY %1(s16) +... +--- +name: test_combine_half_fneg_pos_constant +body: | + bb.1: + ; CHECK-LABEL: name: test_combine_half_fneg_pos_constant + ; CHECK: [[C:%[0-9]+]]:_(s16) = G_FCONSTANT half 0xHC580 + ; CHECK: $h0 = COPY [[C]](s16) + %0:_(s16) = G_FCONSTANT half 0xH4580 + %1:_(s16) = G_FNEG %0 + $h0 = COPY %1(s16) +... +--- +name: test_combine_float_fneg_neg_constant +body: | + bb.1: + ; CHECK-LABEL: name: test_combine_float_fneg_neg_constant + ; CHECK: [[C:%[0-9]+]]:_(s32) = G_FCONSTANT float 5.500000e+00 + ; CHECK: $w0 = COPY [[C]](s32) + %0:_(s32) = G_FCONSTANT float -5.500000e+00 + %1:_(s32) = G_FNEG %0 + $w0 = COPY %1(s32) +... +--- +name: test_combine_float_fneg_pos_constant +body: | + bb.1: + ; CHECK-LABEL: name: test_combine_float_fneg_pos_constant + ; CHECK: [[C:%[0-9]+]]:_(s32) = G_FCONSTANT float -5.500000e+00 + ; CHECK: $w0 = COPY [[C]](s32) + %0:_(s32) = G_FCONSTANT float 5.500000e+00 + %1:_(s32) = G_FNEG %0 + $w0 = COPY %1(s32) +... +--- +name: test_combine_double_fneg_neg_constant +body: | + bb.1: + ; CHECK-LABEL: name: test_combine_double_fneg_neg_constant + ; CHECK: [[C:%[0-9]+]]:_(s64) = G_FCONSTANT double 4.200000e+00 + ; CHECK: $x0 = COPY [[C]](s64) + %0:_(s64) = G_FCONSTANT double -4.200000e+00 + %1:_(s64) = G_FNEG %0 + $x0 = COPY %1(s64) +... +--- +name: test_combine_double_fneg_pos_constant +body: | + bb.1: + ; CHECK-LABEL: name: test_combine_double_fneg_pos_constant + ; CHECK: [[C:%[0-9]+]]:_(s64) = G_FCONSTANT double -4.200000e+00 + ; CHECK: $x0 = COPY [[C]](s64) + %0:_(s64) = G_FCONSTANT double 4.200000e+00 + %1:_(s64) = G_FNEG %0 + $x0 = COPY %1(s64) +... Index: llvm/test/CodeGen/AArch64/GlobalISel/combine-fptrunc.mir =================================================================== --- /dev/null +++ llvm/test/CodeGen/AArch64/GlobalISel/combine-fptrunc.mir @@ -0,0 +1,37 @@ +# 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 +# RUN: llc -debugify-and-strip-all-safe -run-pass=aarch64-prelegalizer-combiner -verify-machineinstrs -mtriple aarch64-unknown-unknown %s -o - | FileCheck %s + +--- +name: test_combine_float_to_half_fptrunc_constant +body: | + bb.1: + ; CHECK-LABEL: name: test_combine_float_to_half_fptrunc_constant + ; CHECK: [[C:%[0-9]+]]:_(s16) = G_FCONSTANT half 0xH4580 + ; CHECK: $h0 = COPY [[C]](s16) + %0:_(s32) = G_FCONSTANT float 5.500000e+00 + %1:_(s16) = G_FPTRUNC %0(s32) + $h0 = COPY %1(s16) +... +--- +name: test_combine_double_to_half_fptrunc_constant +body: | + bb.1: + ; CHECK-LABEL: name: test_combine_double_to_half_fptrunc_constant + ; CHECK: [[C:%[0-9]+]]:_(s16) = G_FCONSTANT half 0xH4433 + ; CHECK: $h0 = COPY [[C]](s16) + %0:_(s64) = G_FCONSTANT double 4.200000e+00 + %1:_(s16) = G_FPTRUNC %0(s64) + $h0 = COPY %1(s16) +... +--- +name: test_combine_double_to_foat_fptrunc_constant +body: | + bb.1: + ; CHECK-LABEL: name: test_combine_double_to_foat_fptrunc_constant + ; CHECK: [[C:%[0-9]+]]:_(s32) = G_FCONSTANT float 0x4010CCCCC0000000 + ; CHECK: $w0 = COPY [[C]](s32) + %0:_(s64) = G_FCONSTANT double 4.200000e+00 + %1:_(s32) = G_FPTRUNC %0(s64) + $w0 = COPY %1(s32) +... Index: llvm/test/CodeGen/AArch64/GlobalISel/combine-fsqrt.mir =================================================================== --- /dev/null +++ llvm/test/CodeGen/AArch64/GlobalISel/combine-fsqrt.mir @@ -0,0 +1,40 @@ +# 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 +# RUN: llc -debugify-and-strip-all-safe -run-pass=aarch64-prelegalizer-combiner -verify-machineinstrs -mtriple aarch64-unknown-unknown %s -o - | FileCheck %s + +--- +name: test_combine_half_fsqrt_constant +body: | + bb.1: + liveins: + ; CHECK-LABEL: name: test_combine_half_fsqrt_constant + ; CHECK: [[C:%[0-9]+]]:_(s16) = G_FCONSTANT half 0xH4000 + ; CHECK: $h0 = COPY [[C]](s16) + %0:_(s16) = G_FCONSTANT half 4.000000e+00 + %1:_(s16) = G_FSQRT %0 + $h0 = COPY %1 +... +--- +name: test_combine_float_fsqrt_constant +body: | + bb.1: + liveins: + ; CHECK-LABEL: name: test_combine_float_fsqrt_constant + ; CHECK: [[C:%[0-9]+]]:_(s32) = G_FCONSTANT float 2.000000e+00 + ; CHECK: $w0 = COPY [[C]](s32) + %0:_(s32) = G_FCONSTANT float 4.000000e+00 + %1:_(s32) = G_FSQRT %0 + $w0 = COPY %1 +... +--- +name: test_combine_double_fsqrt_constant +body: | + bb.1: + liveins: + ; CHECK-LABEL: name: test_combine_double_fsqrt_constant + ; CHECK: [[C:%[0-9]+]]:_(s64) = G_FCONSTANT double 2.000000e+00 + ; CHECK: $x0 = COPY [[C]](s64) + %0:_(s64) = G_FCONSTANT double 4.000000e+00 + %1:_(s64) = G_FSQRT %0 + $x0 = COPY %1 +...