// LoongArchFloat32InstrInfo.td - Single-Precision Float instr --*- tablegen -*- // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // // This file describes the baisc single-precision floating-point instructions. // //===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===// // LoongArch specific DAG Nodes. //===----------------------------------------------------------------------===// def SDT_LoongArchMOVGR2FR_W_LA64 : SDTypeProfile<1, 1, [SDTCisVT<0, f32>, SDTCisVT<1, i64>]>; def SDT_LoongArchMOVFR2GR_S_LA64 : SDTypeProfile<1, 1, [SDTCisVT<0, i64>, SDTCisVT<1, f32>]>; def SDT_LoongArchFTINT : SDTypeProfile<1, 1, [SDTCisFP<0>, SDTCisFP<1>]>; def loongarch_movgr2fr_w_la64 : SDNode<"LoongArchISD::MOVGR2FR_W_LA64", SDT_LoongArchMOVGR2FR_W_LA64>; def loongarch_movfr2gr_s_la64 : SDNode<"LoongArchISD::MOVFR2GR_S_LA64", SDT_LoongArchMOVFR2GR_S_LA64>; def loongarch_ftint : SDNode<"LoongArchISD::FTINT", SDT_LoongArchFTINT>; //===----------------------------------------------------------------------===// // Instructions //===----------------------------------------------------------------------===// let Predicates = [HasBasicF] in { // Arithmetic Operation Instructions def FADD_S : FP_ALU_3R<0x01008000>; def FSUB_S : FP_ALU_3R<0x01028000>; def FMUL_S : FP_ALU_3R<0x01048000>; def FDIV_S : FP_ALU_3R<0x01068000>; def FMADD_S : FP_ALU_4R<0x08100000>; def FMSUB_S : FP_ALU_4R<0x08500000>; def FNMADD_S : FP_ALU_4R<0x08900000>; def FNMSUB_S : FP_ALU_4R<0x08d00000>; def FMAX_S : FP_ALU_3R<0x01088000>; def FMIN_S : FP_ALU_3R<0x010a8000>; def FMAXA_S : FP_ALU_3R<0x010c8000>; def FMINA_S : FP_ALU_3R<0x010e8000>; def FABS_S : FP_ALU_2R<0x01140400>; def FNEG_S : FP_ALU_2R<0x01141400>; def FSQRT_S : FP_ALU_2R<0x01144400>; def FRECIP_S : FP_ALU_2R<0x01145400>; def FRSQRT_S : FP_ALU_2R<0x01146400>; def FSCALEB_S : FP_ALU_3R<0x01108000>; def FLOGB_S : FP_ALU_2R<0x01142400>; def FCOPYSIGN_S : FP_ALU_3R<0x01128000>; def FCLASS_S : FP_ALU_2R<0x01143400>; // Comparison Instructions def FCMP_CAF_S : FP_CMP<0x0c100000>; def FCMP_CUN_S : FP_CMP<0x0c140000>; def FCMP_CEQ_S : FP_CMP<0x0c120000>; def FCMP_CUEQ_S : FP_CMP<0x0c160000>; def FCMP_CLT_S : FP_CMP<0x0c110000>; def FCMP_CULT_S : FP_CMP<0x0c150000>; def FCMP_CLE_S : FP_CMP<0x0c130000>; def FCMP_CULE_S : FP_CMP<0x0c170000>; def FCMP_CNE_S : FP_CMP<0x0c180000>; def FCMP_COR_S : FP_CMP<0x0c1a0000>; def FCMP_CUNE_S : FP_CMP<0x0c1c0000>; def FCMP_SAF_S : FP_CMP<0x0c108000>; def FCMP_SUN_S : FP_CMP<0x0c148000>; def FCMP_SEQ_S : FP_CMP<0x0c128000>; def FCMP_SUEQ_S : FP_CMP<0x0c168000>; def FCMP_SLT_S : FP_CMP<0x0c118000>; def FCMP_SULT_S : FP_CMP<0x0c158000>; def FCMP_SLE_S : FP_CMP<0x0c138000>; def FCMP_SULE_S : FP_CMP<0x0c178000>; def FCMP_SNE_S : FP_CMP<0x0c188000>; def FCMP_SOR_S : FP_CMP<0x0c1a8000>; def FCMP_SUNE_S : FP_CMP<0x0c1c8000>; // Conversion Instructions def FFINT_S_W : FP_CONV<0x011d1000>; def FTINT_W_S : FP_CONV<0x011b0400>; def FTINTRM_W_S : FP_CONV<0x011a0400>; def FTINTRP_W_S : FP_CONV<0x011a4400>; def FTINTRZ_W_S : FP_CONV<0x011a8400>; def FTINTRNE_W_S : FP_CONV<0x011ac400>; def FRINT_S : FP_CONV<0x011e4400>; // Move Instructions def FSEL_xS : FP_SEL<0x0d000000>; def FMOV_S : FP_MOV<0x01149400>; def MOVGR2FR_W : FP_MOV<0x0114a400, FPR32, GPR>; def MOVFR2GR_S : FP_MOV<0x0114b400, GPR, FPR32>; let hasSideEffects = 1 in { def MOVGR2FCSR : FP_MOV<0x0114c000, FCSR, GPR>; def MOVFCSR2GR : FP_MOV<0x0114c800, GPR, FCSR>; } // hasSideEffects = 1 def MOVFR2CF_xS : FP_MOV<0x0114d000, CFR, FPR32>; def MOVCF2FR_xS : FP_MOV<0x0114d400, FPR32, CFR>; def MOVGR2CF : FP_MOV<0x0114d800, CFR, GPR>; def MOVCF2GR : FP_MOV<0x0114dc00, GPR, CFR>; // Branch Instructions def BCEQZ : FP_BRANCH<0x48000000>; def BCNEZ : FP_BRANCH<0x48000100>; // Common Memory Access Instructions def FLD_S : FP_LOAD_2RI12<0x2b000000>; def FST_S : FP_STORE_2RI12<0x2b400000>; def FLDX_S : FP_LOAD_3R<0x38300000>; def FSTX_S : FP_STORE_3R<0x38380000>; // Bound Check Memory Access Instructions def FLDGT_S : FP_LOAD_3R<0x38740000>; def FLDLE_S : FP_LOAD_3R<0x38750000>; def FSTGT_S : FP_STORE_3R<0x38760000>; def FSTLE_S : FP_STORE_3R<0x38770000>; // Pseudo instructions for spill/reload CFRs. let hasSideEffects = 0, mayLoad = 0, mayStore = 1 in def PseudoST_CFR : Pseudo<(outs), (ins CFR:$ccd, GPR:$rj, grlenimm:$imm)>; let hasSideEffects = 0, mayLoad = 1, mayStore = 0 in def PseudoLD_CFR : Pseudo<(outs CFR:$ccd), (ins GPR:$rj, grlenimm:$imm)>; // SET_CFR_{FALSE,TRUE} // These instructions are defined in order to avoid expensive check error if // regular instruction patterns are used. // fcmp.caf.s $dst, $fa0, $fa0 def SET_CFR_FALSE : SET_CFR<0x0c100000, "fcmp.caf.s">; // fcmp.cueq.s $dst, $fa0, $fa0 def SET_CFR_TRUE : SET_CFR<0x0c160000, "fcmp.cueq.s">; // Pseudo instruction for copying CFRs. def PseudoCopyCFR : Pseudo<(outs CFR:$dst), (ins CFR:$src)> { let mayLoad = 0; let mayStore = 0; let hasSideEffects = 0; let Size = 12; } } // Predicates = [HasBasicF] //===----------------------------------------------------------------------===// // Pseudo-instructions and codegen patterns //===----------------------------------------------------------------------===// /// Generic pattern classes class PatFpr : Pat<(OpNode RegTy:$fj), (Inst $fj)>; class PatFprFpr : Pat<(OpNode RegTy:$fj, RegTy:$fk), (Inst $fj, $fk)>; let Predicates = [HasBasicF] in { /// Float arithmetic operations def : PatFprFpr; def : PatFprFpr; def : PatFprFpr; def : PatFprFpr; def : PatFprFpr; def : PatFprFpr; def : PatFprFpr; def : PatFpr; def : PatFpr; def : PatFpr; def : Pat<(fdiv fpimm1, (fsqrt FPR32:$fj)), (FRSQRT_S FPR32:$fj)>; def : Pat<(fcanonicalize FPR32:$fj), (FMAX_S $fj, $fj)>; /// Setcc // Match non-signaling comparison class PatFPSetcc : Pat<(any_fsetcc RegTy:$fj, RegTy:$fk, cc), (CmpInst RegTy:$fj, RegTy:$fk)>; // SETOGT/SETOGE/SETUGT/SETUGE/SETGE/SETNE/SETGT will expand into // SETOLT/SETOLE/SETULT/SETULE/SETLE/SETEQ/SETLT. def : PatFPSetcc; def : PatFPSetcc; def : PatFPSetcc; def : PatFPSetcc; def : PatFPSetcc; def : PatFPSetcc; def : PatFPSetcc; def : PatFPSetcc; def : PatFPSetcc; def : PatFPSetcc; def : PatFPSetcc; def : PatFPSetcc; def : PatFPSetcc; multiclass PatFPBrcond { def : Pat<(brcond (xor (GRLenVT (setcc RegTy:$fj, RegTy:$fk, cc)), -1), bb:$imm21), (BCEQZ (CmpInst RegTy:$fj, RegTy:$fk), bb:$imm21)>; def : Pat<(brcond (GRLenVT (setcc RegTy:$fj, RegTy:$fk, cc)), bb:$imm21), (BCNEZ (CmpInst RegTy:$fj, RegTy:$fk), bb:$imm21)>; } defm : PatFPBrcond; defm : PatFPBrcond; defm : PatFPBrcond; defm : PatFPBrcond; defm : PatFPBrcond; defm : PatFPBrcond; defm : PatFPBrcond; defm : PatFPBrcond; defm : PatFPBrcond; defm : PatFPBrcond; defm : PatFPBrcond; // Match signaling comparison class PatStrictFsetccs : Pat<(strict_fsetccs RegTy:$fj, RegTy:$fk, cc), (CmpInst RegTy:$fj, RegTy:$fk)>; def : PatStrictFsetccs; def : PatStrictFsetccs; def : PatStrictFsetccs; def : PatStrictFsetccs; def : PatStrictFsetccs; def : PatStrictFsetccs; def : PatStrictFsetccs; def : PatStrictFsetccs; def : PatStrictFsetccs; def : PatStrictFsetccs; def : PatStrictFsetccs; /// Select def : Pat<(select CFR:$cc, FPR32:$fk, FPR32:$fj), (FSEL_xS FPR32:$fj, FPR32:$fk, CFR:$cc)>; /// Selectcc class PatFPSelectcc : Pat<(select (GRLenVT (setcc RegTy:$a, RegTy:$b, cc)), RegTy:$t, RegTy:$f), (SelInst RegTy:$f, RegTy:$t, (CmpInst RegTy:$a, RegTy:$b))>; def : PatFPSelectcc; def : PatFPSelectcc; def : PatFPSelectcc; def : PatFPSelectcc; def : PatFPSelectcc; def : PatFPSelectcc; def : PatFPSelectcc; def : PatFPSelectcc; def : PatFPSelectcc; def : PatFPSelectcc; /// Loads defm : LdPat; def : RegRegLdPat; /// Stores defm : StPat; def : RegRegStPat; /// Floating point constants def : Pat<(f32 fpimm0), (MOVGR2FR_W R0)>; def : Pat<(f32 fpimm0neg), (FNEG_S (MOVGR2FR_W R0))>; def : Pat<(f32 fpimm1), (FFINT_S_W (MOVGR2FR_W (ADDI_W R0, 1)))>; // FP Conversion def : Pat<(loongarch_ftint FPR32:$src), (FTINTRZ_W_S FPR32:$src)>; // FP reciprocal operation def : Pat<(fdiv fpimm1, FPR32:$src), (FRECIP_S $src)>; // fmadd.s: fj * fk + fa def : Pat<(fma FPR32:$fj, FPR32:$fk, FPR32:$fa), (FMADD_S $fj, $fk, $fa)>; // fmsub.s: fj * fk - fa def : Pat<(fma FPR32:$fj, FPR32:$fk, (fneg FPR32:$fa)), (FMSUB_S FPR32:$fj, FPR32:$fk, FPR32:$fa)>; // fnmadd.s: -(fj * fk + fa) def : Pat<(fneg (fma FPR32:$fj, FPR32:$fk, FPR32:$fa)), (FNMADD_S FPR32:$fj, FPR32:$fk, FPR32:$fa)>; // fnmadd.s: -fj * fk - fa (the nsz flag on the FMA) def : Pat<(fma_nsz (fneg FPR32:$fj), FPR32:$fk, (fneg FPR32:$fa)), (FNMADD_S FPR32:$fj, FPR32:$fk, FPR32:$fa)>; // fnmsub.s: -fj * fk + fa def : Pat<(fma (fneg FPR32:$fj), FPR32:$fk, FPR32:$fa), (FNMSUB_S FPR32:$fj, FPR32:$fk, FPR32:$fa)>; } // Predicates = [HasBasicF] let Predicates = [HasBasicF, IsLA64] in { // GPR -> FPR def : Pat<(loongarch_movgr2fr_w_la64 GPR:$src), (MOVGR2FR_W GPR:$src)>; // FPR -> GPR def : Pat<(loongarch_movfr2gr_s_la64 FPR32:$src), (MOVFR2GR_S FPR32:$src)>; // int -> f32 def : Pat<(f32 (sint_to_fp (i64 (sexti32 (i64 GPR:$src))))), (FFINT_S_W (MOVGR2FR_W GPR:$src))>; // uint -> f32 def : Pat<(f32 (uint_to_fp (i64 (sexti32 (i64 GPR:$src))))), (FFINT_S_W (MOVGR2FR_W GPR:$src))>; } // Predicates = [HasBasicF, IsLA64] // FP Rounding let Predicates = [HasBasicF, IsLA64] in { def : PatFpr; } // Predicates = [HasBasicF, IsLA64] let Predicates = [HasBasicF, IsLA32] in { // GPR -> FPR def : Pat<(bitconvert (i32 GPR:$src)), (MOVGR2FR_W GPR:$src)>; // FPR -> GPR def : Pat<(i32 (bitconvert FPR32:$src)), (MOVFR2GR_S FPR32:$src)>; // int -> f32 def : Pat<(f32 (sint_to_fp (i32 GPR:$src))), (FFINT_S_W (MOVGR2FR_W GPR:$src))>; } // Predicates = [HasBasicF, IsLA32]