Index: llvm/include/llvm/CodeGen/GlobalISel/CombinerHelper.h =================================================================== --- llvm/include/llvm/CodeGen/GlobalISel/CombinerHelper.h +++ llvm/include/llvm/CodeGen/GlobalISel/CombinerHelper.h @@ -17,6 +17,7 @@ #ifndef LLVM_CODEGEN_GLOBALISEL_COMBINER_HELPER_H #define LLVM_CODEGEN_GLOBALISEL_COMBINER_HELPER_H +#include "llvm/ADT/APFloat.h" #include "llvm/CodeGen/LowLevelType.h" #include "llvm/CodeGen/Register.h" #include "llvm/Support/Alignment.h" @@ -243,6 +244,12 @@ 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, + Optional &Cst); + bool applyCombineConstantFoldFpUnary(MachineInstr &MI, + Optional &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 @@ -291,6 +291,51 @@ (apply [{ return Helper.applySimplifyAddToSub(*${root}, ${info});}]) >; +// Fold fneg(cst) to cst result of fneg operation +def constant_fneg_matchinfo: GIDefMatchData<"Optional">; +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.applyCombineConstantFoldFpUnary(*${root}, ${info}); }]) +>; + +// Fold fabs(cst) to cst result of fabs operation +def constant_fabs_matchinfo: GIDefMatchData<"Optional">; +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.applyCombineConstantFoldFpUnary(*${root}, ${info}); }]) +>; + +// Fold fptrunc(cst) to cst result of fptrunc operation +def constant_fptrunc_matchinfo: GIDefMatchData<"Optional">; +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.applyCombineConstantFoldFpUnary(*${root}, ${info}); }]) +>; + +// Fold fsqrt(cst) to cst result of fsqrt operation +def constant_fsqrt_matchinfo: GIDefMatchData<"Optional">; +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.applyCombineConstantFoldFpUnary(*${root}, ${info}); }]) +>; + +// Fold flog2(cst) to cst result of flog2 operation +def constant_flog2_matchinfo: GIDefMatchData<"Optional">; +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.applyCombineConstantFoldFpUnary(*${root}, ${info}); }]) +>; + // Fold int2ptr(ptr2int(x)) -> x def p2i_to_i2p_matchinfo: GIDefMatchData<"Register">; def p2i_to_i2p: GICombineRule< @@ -361,6 +406,10 @@ 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 select_combines : GICombineGroup<[select_undef_cmp, select_constant_cmp]>; def trivial_combines : GICombineGroup<[copy_prop, mul_to_shl, add_p2i_to_ptradd]>; @@ -370,4 +419,4 @@ hoist_logic_op_with_same_opcode_hands, shl_ashr_to_sext_inreg, sext_inreg_of_load, width_reduction_combines, select_combines, - known_bits_simplifications]>; + known_bits_simplifications, constant_fp_combines]>; Index: llvm/lib/CodeGen/GlobalISel/CombinerHelper.cpp =================================================================== --- llvm/lib/CodeGen/GlobalISel/CombinerHelper.cpp +++ llvm/lib/CodeGen/GlobalISel/CombinerHelper.cpp @@ -1433,6 +1433,83 @@ return false; } +static Optional constantFoldFpUnary(unsigned Opcode, LLT DstTy, + const Register Op, + const MachineRegisterInfo &MRI) { + const auto S16 = LLT::scalar(16); + const auto S32 = LLT::scalar(32); + const auto S64 = LLT::scalar(64); + const ConstantFP *MaybeCst = getConstantFPVRegVal(Op, MRI); + + if (!MaybeCst || !(DstTy == S16 || DstTy == S32 || DstTy == S64)) + return None; + APFloat V = MaybeCst->getValueAPF(); + switch (Opcode) { + default: + return None; + case TargetOpcode::G_FNEG: { + V.changeSign(); + return V; + } + case TargetOpcode::G_FABS: { + V.clearSign(); + return V; + } + case TargetOpcode::G_FPTRUNC: { + if (DstTy == S64) { + bool Unused; + V.convert(APFloat::IEEEdouble(), APFloat::rmNearestTiesToEven, &Unused); + return V; + } + break; + } + case TargetOpcode::G_FSQRT: { + bool Unused; + V.convert(APFloat::IEEEdouble(), APFloat::rmNearestTiesToEven, &Unused); + V = APFloat(sqrt(V.convertToDouble())); + break; + } + case TargetOpcode::G_FLOG2: { + bool Unused; + V.convert(APFloat::IEEEdouble(), APFloat::rmNearestTiesToEven, &Unused); + V = APFloat(log2(V.convertToDouble())); + break; + } + } + + // Convert `APFloat` to appropriate IEEE type depending on `DstTy`. Otherwise, + // `buildFConstant` will assert on size mismatch. Only `G_FPTRUNC`, `G_FSQRT`, + // and `G_FLOG2` reach here. + bool Unused; + if (DstTy == S16) + V.convert(APFloat::IEEEhalf(), APFloat::rmNearestTiesToEven, &Unused); + else if (DstTy == S32) + V.convert(APFloat::IEEEsingle(), APFloat::rmNearestTiesToEven, &Unused); + + return V; +} + +bool CombinerHelper::matchCombineConstantFoldFpUnary(MachineInstr &MI, + Optional &Cst) { + Register DstReg = MI.getOperand(0).getReg(); + Register SrcReg = MI.getOperand(1).getReg(); + LLT DstTy = MRI.getType(DstReg); + Cst = constantFoldFpUnary(MI.getOpcode(), DstTy, SrcReg, MRI); + return Cst.hasValue(); +} + +bool CombinerHelper::applyCombineConstantFoldFpUnary(MachineInstr &MI, + Optional &Cst) { + assert(Cst.hasValue() && "Optional is unexpectedly empty!"); + Builder.setInstrAndDebugLoc(MI); + MachineFunction &MF = Builder.getMF(); + auto *FPVal = ConstantFP::get(MF.getFunction().getContext(), *Cst); + Register DstReg = MI.getOperand(0).getReg(); + Builder.buildFConstant(DstReg, *FPVal); + MI.eraseFromParent(); + return true; +} + 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 +...