diff --git a/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp b/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp index 51a235bf2ca18..920657a198d9b 100644 --- a/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp +++ b/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp @@ -3517,6 +3517,11 @@ bool RISCVDAGToDAGISel::performCombineVMergeAndVOps(SDNode *N) { if (!Info) return false; + // When Mask is not a true mask, this transformation is illegal for some + // operations whose results are affected by mask, like viota.m. + if (Info->MaskAffectsResult && Mask && !usesAllOnesMask(Mask, Glue)) + return false; + if (HasTiedDest && !isImplicitDef(True->getOperand(0))) { // The vmerge instruction must be TU. // FIXME: This could be relaxed, but we need to handle the policy for the diff --git a/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.h b/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.h index 5c182a8699ec0..77e174135a599 100644 --- a/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.h +++ b/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.h @@ -263,6 +263,7 @@ struct RISCVMaskedPseudoInfo { uint16_t MaskedPseudo; uint16_t UnmaskedPseudo; uint8_t MaskOpIdx; + uint8_t MaskAffectsResult : 1; }; #define GET_RISCVVSSEGTable_DECL diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfoVPseudos.td b/llvm/lib/Target/RISCV/RISCVInstrInfoVPseudos.td index bec67153b6543..83faa5bbef793 100644 --- a/llvm/lib/Target/RISCV/RISCVInstrInfoVPseudos.td +++ b/llvm/lib/Target/RISCV/RISCVInstrInfoVPseudos.td @@ -570,16 +570,17 @@ def RISCVVIntrinsicsTable : GenericTable { // unmasked variant. For all but compares, both the masked and // unmasked variant have a passthru and policy operand. For compares, // neither has a policy op, and only the masked version has a passthru. -class RISCVMaskedPseudo MaskIdx> { +class RISCVMaskedPseudo MaskIdx, bit MaskAffectsRes=false> { Pseudo MaskedPseudo = !cast(NAME); Pseudo UnmaskedPseudo = !cast(!subst("_MASK", "", NAME)); bits<4> MaskOpIdx = MaskIdx; + bit MaskAffectsResult = MaskAffectsRes; } def RISCVMaskedPseudosTable : GenericTable { let FilterClass = "RISCVMaskedPseudo"; let CppTypeName = "RISCVMaskedPseudoInfo"; - let Fields = ["MaskedPseudo", "UnmaskedPseudo", "MaskOpIdx"]; + let Fields = ["MaskedPseudo", "UnmaskedPseudo", "MaskOpIdx", "MaskAffectsResult"]; let PrimaryKey = ["MaskedPseudo"]; let PrimaryKeyName = "getMaskedPseudoInfo"; } @@ -2092,7 +2093,7 @@ multiclass VPseudoVIOT_M { SchedUnary<"WriteVMIotV", "ReadVMIotV", mx, forceMergeOpRead=true>; def "_" # mx # "_MASK" : VPseudoUnaryMask, - RISCVMaskedPseudo, + RISCVMaskedPseudo, SchedUnary<"WriteVMIotV", "ReadVMIotV", mx, forceMergeOpRead=true>; } diff --git a/llvm/test/CodeGen/RISCV/rvv/rvv-peephole-vmerge-masked-vops.ll b/llvm/test/CodeGen/RISCV/rvv/rvv-peephole-vmerge-masked-vops.ll index 7e137d6a61969..f6d9d1e711e71 100644 --- a/llvm/test/CodeGen/RISCV/rvv/rvv-peephole-vmerge-masked-vops.ll +++ b/llvm/test/CodeGen/RISCV/rvv/rvv-peephole-vmerge-masked-vops.ll @@ -258,3 +258,19 @@ entry: %res = call @llvm.vp.merge.nxv2i32( %m, %i, %passthru, i32 %evl) ret %res } + +; Test VIOTA_M +declare @llvm.riscv.viota.mask.nxv2i32(, , , i64, i64) +define @vpmerge_viota( %passthru, %m, %vm, i32 zeroext %vl) { +; CHECK-LABEL: vpmerge_viota: +; CHECK: # %bb.0: +; CHECK-NEXT: vsetvli zero, a0, e32, m1, tu, mu +; CHECK-NEXT: viota.m v8, v9, v0.t +; CHECK-NEXT: ret + %1 = zext i32 %vl to i64 + %a = call @llvm.riscv.viota.mask.nxv2i32( undef, %vm, %m, i64 %1, i64 0) + %splat = insertelement poison, i1 -1, i32 0 + %mask = shufflevector %splat, poison, zeroinitializer + %b = call @llvm.riscv.vmerge.nxv2i32.nxv2i32( %passthru, %passthru, %a, %mask, i64 %1) + ret %b +} diff --git a/llvm/test/CodeGen/RISCV/rvv/rvv-peephole-vmerge-vops.ll b/llvm/test/CodeGen/RISCV/rvv/rvv-peephole-vmerge-vops.ll index 1ea2b7ef57cf0..df119435611d1 100644 --- a/llvm/test/CodeGen/RISCV/rvv/rvv-peephole-vmerge-vops.ll +++ b/llvm/test/CodeGen/RISCV/rvv/rvv-peephole-vmerge-vops.ll @@ -279,13 +279,15 @@ define @vpmerge_vid( %passthru, %b } -; Test riscv.viota +; Test not combine VIOTA_M and VMERGE_VVM without true mask. declare @llvm.riscv.viota.nxv2i32(, , i64) define @vpmerge_viota( %passthru, %m, %vm, i32 zeroext %vl) { ; CHECK-LABEL: vpmerge_viota: ; CHECK: # %bb.0: -; CHECK-NEXT: vsetvli zero, a0, e32, m1, tu, mu -; CHECK-NEXT: viota.m v8, v9, v0.t +; CHECK-NEXT: vsetvli zero, a0, e32, m1, ta, ma +; CHECK-NEXT: viota.m v10, v9 +; CHECK-NEXT: vsetvli zero, zero, e32, m1, tu, ma +; CHECK-NEXT: vmerge.vvm v8, v8, v10, v0 ; CHECK-NEXT: ret %1 = zext i32 %vl to i64 %a = call @llvm.riscv.viota.nxv2i32( undef, %vm, i64 %1) @@ -293,6 +295,21 @@ define @vpmerge_viota( %passthru, %b } +; Test combine VIOTA_M and VMERGE_VVM with true mask. +define @vpmerge_viota2( %passthru, %vm, i32 zeroext %vl) { +; CHECK-LABEL: vpmerge_viota2: +; CHECK: # %bb.0: +; CHECK-NEXT: vsetvli zero, a0, e32, m1, tu, ma +; CHECK-NEXT: viota.m v8, v0 +; CHECK-NEXT: ret + %1 = zext i32 %vl to i64 + %a = call @llvm.riscv.viota.nxv2i32( undef, %vm, i64 %1) + %splat = insertelement poison, i1 -1, i32 0 + %true = shufflevector %splat, poison, zeroinitializer + %b = call @llvm.vp.merge.nxv2i32( %true, %a, %passthru, i32 %vl) + ret %b +} + ; Test riscv.vfclass declare @llvm.riscv.vfclass.nxv2i32(, , i64) define @vpmerge_vflcass( %passthru, %vf, %m, i32 zeroext %vl) { @@ -730,8 +747,9 @@ define @vpselect_vid( %passthru, @vpselect_viota( %passthru, %m, %vm, i32 zeroext %vl) { ; CHECK-LABEL: vpselect_viota: ; CHECK: # %bb.0: -; CHECK-NEXT: vsetvli zero, a0, e32, m1, ta, mu -; CHECK-NEXT: viota.m v8, v9, v0.t +; CHECK-NEXT: vsetvli zero, a0, e32, m1, ta, ma +; CHECK-NEXT: viota.m v10, v9 +; CHECK-NEXT: vmerge.vvm v8, v8, v10, v0 ; CHECK-NEXT: ret %1 = zext i32 %vl to i64 %a = call @llvm.riscv.viota.nxv2i32( undef, %vm, i64 %1)