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" @@ -266,6 +267,12 @@ bool matchCombineUnmergeZExtToZExt(MachineInstr &MI); bool applyCombineUnmergeZExtToZExt(MachineInstr &MI); + /// 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/CodeGen/LowLevelType.h =================================================================== --- llvm/include/llvm/CodeGen/LowLevelType.h +++ llvm/include/llvm/CodeGen/LowLevelType.h @@ -23,6 +23,7 @@ class DataLayout; class Type; +struct fltSemantics; /// Construct a low-level type based on an LLVM type. LLT getLLTForType(Type &Ty, const DataLayout &DL); @@ -35,6 +36,9 @@ /// scalarable vector types, and will assert if used. LLT getLLTForMVT(MVT Ty); +/// Get the appropriate floating point arithmetic semantic based on the bit size +/// of the given scalar LLT. +const llvm::fltSemantics &getFltSemanticForLLT(LLT Ty); } #endif // LLVM_CODEGEN_LOWLEVELTYPE_H Index: llvm/include/llvm/Target/GlobalISel/Combine.td =================================================================== --- llvm/include/llvm/Target/GlobalISel/Combine.td +++ llvm/include/llvm/Target/GlobalISel/Combine.td @@ -303,6 +303,15 @@ (apply [{ return Helper.applySimplifyAddToSub(*${root}, ${info});}]) >; +// Fold fp_op(cst) to the constant result of the floating point operation. +def constant_fp_op_matchinfo: GIDefMatchData<"Optional">; +def constant_fp_op: GICombineRule < + (defs root:$root, constant_fp_op_matchinfo:$info), + (match (wip_match_opcode G_FNEG, G_FABS, G_FPTRUNC, G_FSQRT, 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< @@ -505,4 +514,5 @@ known_bits_simplifications, ext_ext_fold, not_cmp_fold, opt_brcond_by_inverting_cond, unmerge_merge, fabs_fabs_fold, unmerge_cst, unmerge_dead_to_trunc, - unmerge_zext_to_zext, trunc_ext_fold, trunc_shl]>; + unmerge_zext_to_zext, trunc_ext_fold, trunc_shl, + constant_fp_op]>; Index: llvm/lib/CodeGen/GlobalISel/CombinerHelper.cpp =================================================================== --- llvm/lib/CodeGen/GlobalISel/CombinerHelper.cpp +++ llvm/lib/CodeGen/GlobalISel/CombinerHelper.cpp @@ -1430,6 +1430,69 @@ 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: + llvm_unreachable("Unexpected opcode!"); + case TargetOpcode::G_FNEG: { + V.changeSign(); + return V; + } + case TargetOpcode::G_FABS: { + V.clearSign(); + return V; + } + case TargetOpcode::G_FPTRUNC: + 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; + V.convert(getFltSemanticForLLT(DstTy), 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/lib/CodeGen/LowLevelType.cpp =================================================================== --- llvm/lib/CodeGen/LowLevelType.cpp +++ llvm/lib/CodeGen/LowLevelType.cpp @@ -12,6 +12,7 @@ //===----------------------------------------------------------------------===// #include "llvm/CodeGen/LowLevelType.h" +#include "llvm/ADT/APFloat.h" #include "llvm/IR/DataLayout.h" #include "llvm/IR/DerivedTypes.h" #include "llvm/Support/raw_ostream.h" @@ -58,3 +59,18 @@ return LLT::vector(Ty.getVectorNumElements(), Ty.getVectorElementType().getSizeInBits()); } + +const llvm::fltSemantics &llvm::getFltSemanticForLLT(LLT Ty) { + assert(Ty.isScalar() && "Expected a scalar type."); + switch (Ty.getSizeInBits()) { + case 16: + return APFloat::IEEEhalf(); + case 32: + return APFloat::IEEEsingle(); + case 64: + return APFloat::IEEEdouble(); + case 128: + return APFloat::IEEEquad(); + } + llvm_unreachable("Invalid FP type size."); +} Index: llvm/test/CodeGen/AArch64/GlobalISel/combine-fabs.mir =================================================================== --- llvm/test/CodeGen/AArch64/GlobalISel/combine-fabs.mir +++ llvm/test/CodeGen/AArch64/GlobalISel/combine-fabs.mir @@ -30,3 +30,73 @@ %2:_(<2 x s32>) = G_FABS %1(<2 x s32>) $x0 = COPY %2(<2 x s32>) ... +--- +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,36 @@ +# 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: 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 =================================================================== --- llvm/test/CodeGen/AArch64/GlobalISel/combine-fneg.mir +++ llvm/test/CodeGen/AArch64/GlobalISel/combine-fneg.mir @@ -26,3 +26,69 @@ %2:_(<2 x s32>) = G_FNEG %1(<2 x s32>) $x0 = COPY %2(<2 x s32>) ... +--- +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,36 @@ +# 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: 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,39 @@ +# 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: 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 +...