Index: llvm/lib/Target/AArch64/AArch64ExpandPseudoInsts.cpp =================================================================== --- llvm/lib/Target/AArch64/AArch64ExpandPseudoInsts.cpp +++ llvm/lib/Target/AArch64/AArch64ExpandPseudoInsts.cpp @@ -467,7 +467,10 @@ std::tie(PredIdx, DOPIdx, SrcIdx) = std::make_tuple(1, 2, 3); break; case AArch64::DestructiveUnaryPassthru: - std::tie(PredIdx, DOPIdx, SrcIdx) = std::make_tuple(2, 3, 3); + if (FalseZero) + std::tie(PredIdx, DOPIdx, SrcIdx) = std::make_tuple(2, 0, 3); + else + std::tie(PredIdx, DOPIdx, SrcIdx) = std::make_tuple(2, 3, 3); break; case AArch64::DestructiveTernaryCommWithRev: std::tie(PredIdx, DOPIdx, SrcIdx, Src2Idx) = std::make_tuple(1, 2, 3, 4); @@ -1012,8 +1015,8 @@ int OrigInstr = AArch64::getSVEPseudoMap(MI.getOpcode()); if (OrigInstr != -1) { auto &Orig = TII->get(OrigInstr); - if ((Orig.TSFlags & AArch64::DestructiveInstTypeMask) - != AArch64::NotDestructive) { + if ((Orig.TSFlags & AArch64::DestructiveInstTypeMask) != + AArch64::NotDestructive) { return expand_DestructiveOp(MI, MBB, MBBI); } } Index: llvm/lib/Target/AArch64/AArch64SVEInstrInfo.td =================================================================== --- llvm/lib/Target/AArch64/AArch64SVEInstrInfo.td +++ llvm/lib/Target/AArch64/AArch64SVEInstrInfo.td @@ -3523,7 +3523,7 @@ let Predicates = [HasSVE2orSME] in { // SVE2 floating-point base 2 logarithm as integer - defm FLOGB_ZPmZ : sve2_fp_flogb<"flogb", int_aarch64_sve_flogb>; + defm FLOGB_ZPmZ : sve2_fp_flogb<"flogb", "FLOGB_ZPZZ", int_aarch64_sve_flogb, DestructiveUnaryPassthru>; // SVE2 floating-point convert precision defm FCVTXNT_ZPmZ : sve2_fp_convert_down_odd_rounding_top<"fcvtxnt", "int_aarch64_sve_fcvtxnt">; @@ -3565,6 +3565,10 @@ def EXT_ZZI_B : sve2_int_perm_extract_i_cons<"ext">; } // End HasSVE2orSME +let Predicates = [HasSVE2orSME, UseExperimentalZeroingPseudos] in { + defm FLOGB_ZPZZ : sve2_fp_un_pred_zeroing_hsd; +} // End HasSVE2orSME, UseExperimentalZeroingPseudos + let Predicates = [HasSVE2] in { // SVE2 non-temporal gather loads defm LDNT1SB_ZZR_S : sve2_mem_gldnt_vs_32_ptrs<0b00000, "ldnt1sb", AArch64ldnt1s_gather_z, nxv4i8>; Index: llvm/lib/Target/AArch64/SVEInstrFormats.td =================================================================== --- llvm/lib/Target/AArch64/SVEInstrFormats.td +++ llvm/lib/Target/AArch64/SVEInstrFormats.td @@ -480,6 +480,11 @@ Operand vt3, Instruction inst> : Pat<(vtd (op vt1:$Op1, (vselect vt1:$Op1, vt2:$Op2, (SVEDup0)), (i32 (vt3:$Op3)))), (inst $Op1, $Op2, vt3:$Op3)>; + +class SVE_2_Op_Pat_Zero + : Pat<(vtd (op (vtd (SVEDup0)), vt1:$Op1, vt2:$Op2)), + (inst (IMPLICIT_DEF), $Op1, $Op2)>; } // @@ -629,9 +634,12 @@ // Pseudos for passthru operands // let hasNoSchedulingInfo = 1 in { - class PredOneOpPassthruPseudo + class PredOneOpPassthruPseudo : SVEPseudo2Instr, - Pseudo<(outs zprty:$Zd), (ins zprty:$Passthru, PPR3bAny:$Pg, zprty:$Zs), []>; + Pseudo<(outs zprty:$Zd), (ins zprty:$Passthru, PPR3bAny:$Pg, zprty:$Zs), []> { + let FalseLanes = flags; + } } //===----------------------------------------------------------------------===// @@ -2787,16 +2795,31 @@ defm : SVE_1_Op_PassthruUndef_Pat(NAME # _UNDEF_D)>; } -multiclass sve2_fp_flogb { - def _H : sve_fp_2op_p_zd<0b0011010, asm, ZPR16, ZPR16, ElementSizeH>; - def _S : sve_fp_2op_p_zd<0b0011100, asm, ZPR32, ZPR32, ElementSizeS>; - def _D : sve_fp_2op_p_zd<0b0011110, asm, ZPR64, ZPR64, ElementSizeD>; +multiclass sve2_fp_flogb { + let DestructiveInstType = flags in { + def _H : sve_fp_2op_p_zd<0b0011010, asm, ZPR16, ZPR16, ElementSizeH>, + SVEPseudo2Instr; + def _S : sve_fp_2op_p_zd<0b0011100, asm, ZPR32, ZPR32, ElementSizeS>, + SVEPseudo2Instr; + def _D : sve_fp_2op_p_zd<0b0011110, asm, ZPR64, ZPR64, ElementSizeD>, + SVEPseudo2Instr; + } def : SVE_3_Op_Pat(NAME # _H)>; def : SVE_3_Op_Pat(NAME # _S)>; def : SVE_3_Op_Pat(NAME # _D)>; } +multiclass sve2_fp_un_pred_zeroing_hsd { + def _ZERO_H : PredOneOpPassthruPseudo; + def _ZERO_S : PredOneOpPassthruPseudo; + def _ZERO_D : PredOneOpPassthruPseudo; + + def : SVE_2_Op_Pat_Zero(NAME # _ZERO_H)>; + def : SVE_2_Op_Pat_Zero(NAME # _ZERO_S)>; + def : SVE_2_Op_Pat_Zero(NAME # _ZERO_D)>; +} + multiclass sve2_fp_convert_down_odd_rounding { def _DtoS : sve_fp_2op_p_zd<0b0001010, asm, ZPR64, ZPR32, ElementSizeD>; def : SVE_3_Op_Pat(op # _f32f64), nxv4f32, nxv2i1, nxv2f64, !cast(NAME # _DtoS)>; Index: llvm/test/CodeGen/AArch64/sve2-intrinsics-fp-int-binary-logarithm-zeroing.ll =================================================================== --- /dev/null +++ llvm/test/CodeGen/AArch64/sve2-intrinsics-fp-int-binary-logarithm-zeroing.ll @@ -0,0 +1,47 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc -mtriple=aarch64-linux-gnu -mattr=+sve2 -mattr=+use-experimental-zeroing-pseudos -asm-verbose=1 < %s | FileCheck %s + +; +; FLOGB +; + +; NOTE: The %unused paramter ensures z0 is free, leading to a simpler test. +define @flogb_f16( %unused, %pg, %a) { +; CHECK-LABEL: flogb_f16: +; CHECK: // %bb.0: +; CHECK-NEXT: movprfx z0.h, p0/z, z0.h +; CHECK-NEXT: flogb z0.h, p0/m, z1.h +; CHECK-NEXT: ret + %out = call @llvm.aarch64.sve.flogb.nxv8f16( zeroinitializer, + %pg, + %a) + ret %out +} + +define @flogb_f32( %unused, %pg, %a) { +; CHECK-LABEL: flogb_f32: +; CHECK: // %bb.0: +; CHECK-NEXT: movprfx z0.s, p0/z, z0.s +; CHECK-NEXT: flogb z0.s, p0/m, z1.s +; CHECK-NEXT: ret + %out = call @llvm.aarch64.sve.flogb.nxv4f32( zeroinitializer, + %pg, + %a) + ret %out +} + +define @flogb_f64( %unused, %pg, %a) { +; CHECK-LABEL: flogb_f64: +; CHECK: // %bb.0: +; CHECK-NEXT: movprfx z0.d, p0/z, z0.d +; CHECK-NEXT: flogb z0.d, p0/m, z1.d +; CHECK-NEXT: ret + %out = call @llvm.aarch64.sve.flogb.nxv2f64( zeroinitializer, + %pg, + %a) + ret %out +} + +declare @llvm.aarch64.sve.flogb.nxv8f16(, , ) +declare @llvm.aarch64.sve.flogb.nxv4f32(, , ) +declare @llvm.aarch64.sve.flogb.nxv2f64(, , )