diff --git a/llvm/lib/CodeGen/SelectionDAG/LegalizeIntegerTypes.cpp b/llvm/lib/CodeGen/SelectionDAG/LegalizeIntegerTypes.cpp --- a/llvm/lib/CodeGen/SelectionDAG/LegalizeIntegerTypes.cpp +++ b/llvm/lib/CodeGen/SelectionDAG/LegalizeIntegerTypes.cpp @@ -141,7 +141,9 @@ Res = PromoteIntRes_EXTEND_VECTOR_INREG(N); break; case ISD::SIGN_EXTEND: + case ISD::VP_SIGN_EXTEND: case ISD::ZERO_EXTEND: + case ISD::VP_ZERO_EXTEND: case ISD::ANY_EXTEND: Res = PromoteIntRes_INT_EXTEND(N); break; case ISD::VP_FP_TO_SINT: @@ -760,8 +762,8 @@ assert(Res.getValueType().bitsLE(NVT) && "Extension doesn't make sense!"); // If the result and operand types are the same after promotion, simplify - // to an in-register extension. - if (NVT == Res.getValueType()) { + // to an in-register extension. Unless this is a VP_*_EXTEND. + if (NVT == Res.getValueType() && N->getNumOperands() == 1) { // The high bits are not guaranteed to be anything. Insert an extend. if (N->getOpcode() == ISD::SIGN_EXTEND) return DAG.getNode(ISD::SIGN_EXTEND_INREG, dl, NVT, Res, @@ -774,6 +776,12 @@ } // Otherwise, just extend the original operand all the way to the larger type. + if (N->getNumOperands() != 1) { + assert(N->getNumOperands() == 3 && "Unexpected number of operands!"); + assert(N->isVPOpcode() && "Expected VP opcode"); + return DAG.getNode(N->getOpcode(), dl, NVT, N->getOperand(0), + N->getOperand(1), N->getOperand(2)); + } return DAG.getNode(N->getOpcode(), dl, NVT, N->getOperand(0)); } @@ -1663,6 +1671,7 @@ case ISD::VP_SETCC: case ISD::SETCC: Res = PromoteIntOp_SETCC(N, OpNo); break; case ISD::SIGN_EXTEND: Res = PromoteIntOp_SIGN_EXTEND(N); break; + case ISD::VP_SIGN_EXTEND: Res = PromoteIntOp_VP_SIGN_EXTEND(N); break; case ISD::VP_SINT_TO_FP: case ISD::SINT_TO_FP: Res = PromoteIntOp_SINT_TO_FP(N); break; case ISD::STRICT_SINT_TO_FP: Res = PromoteIntOp_STRICT_SINT_TO_FP(N); break; @@ -1684,6 +1693,7 @@ case ISD::UINT_TO_FP: Res = PromoteIntOp_UINT_TO_FP(N); break; case ISD::STRICT_UINT_TO_FP: Res = PromoteIntOp_STRICT_UINT_TO_FP(N); break; case ISD::ZERO_EXTEND: Res = PromoteIntOp_ZERO_EXTEND(N); break; + case ISD::VP_ZERO_EXTEND: Res = PromoteIntOp_VP_ZERO_EXTEND(N); break; case ISD::EXTRACT_SUBVECTOR: Res = PromoteIntOp_EXTRACT_SUBVECTOR(N); break; case ISD::INSERT_SUBVECTOR: Res = PromoteIntOp_INSERT_SUBVECTOR(N); break; @@ -2013,6 +2023,23 @@ Op, DAG.getValueType(N->getOperand(0).getValueType())); } +SDValue DAGTypeLegalizer::PromoteIntOp_VP_SIGN_EXTEND(SDNode *N) { + SDLoc dl(N); + EVT VT = N->getValueType(0); + SDValue Op = GetPromotedInteger(N->getOperand(0)); + // FIXME: There is no VP_ANY_EXTEND yet. + Op = DAG.getNode(ISD::VP_ZERO_EXTEND, dl, VT, Op, N->getOperand(1), + N->getOperand(2)); + unsigned Diff = + VT.getScalarSizeInBits() - N->getOperand(0).getScalarValueSizeInBits(); + SDValue ShAmt = DAG.getShiftAmountConstant(Diff, VT, dl); + // FIXME: There is no VP_SIGN_EXTEND_INREG so use a pair of shifts. + SDValue Shl = DAG.getNode(ISD::VP_SHL, dl, VT, Op, ShAmt, N->getOperand(1), + N->getOperand(2)); + return DAG.getNode(ISD::VP_ASHR, dl, VT, Shl, ShAmt, N->getOperand(1), + N->getOperand(2)); +} + SDValue DAGTypeLegalizer::PromoteIntOp_SINT_TO_FP(SDNode *N) { if (N->getOpcode() == ISD::VP_SINT_TO_FP) return SDValue(DAG.UpdateNodeOperands(N, @@ -2164,6 +2191,19 @@ return DAG.getZeroExtendInReg(Op, dl, N->getOperand(0).getValueType()); } +SDValue DAGTypeLegalizer::PromoteIntOp_VP_ZERO_EXTEND(SDNode *N) { + SDLoc dl(N); + EVT VT = N->getValueType(0); + SDValue Op = GetPromotedInteger(N->getOperand(0)); + // FIXME: There is no VP_ANY_EXTEND yet. + Op = DAG.getNode(ISD::VP_ZERO_EXTEND, dl, VT, Op, N->getOperand(1), + N->getOperand(2)); + APInt Imm = APInt::getLowBitsSet(VT.getScalarSizeInBits(), + N->getOperand(0).getScalarValueSizeInBits()); + return DAG.getNode(ISD::VP_AND, dl, VT, Op, DAG.getConstant(Imm, dl, VT), + N->getOperand(1), N->getOperand(2)); +} + SDValue DAGTypeLegalizer::PromoteIntOp_ADDSUBO_CARRY(SDNode *N, unsigned OpNo) { assert(OpNo == 2 && "Don't know how to promote this operand!"); diff --git a/llvm/lib/CodeGen/SelectionDAG/LegalizeTypes.h b/llvm/lib/CodeGen/SelectionDAG/LegalizeTypes.h --- a/llvm/lib/CodeGen/SelectionDAG/LegalizeTypes.h +++ b/llvm/lib/CodeGen/SelectionDAG/LegalizeTypes.h @@ -385,6 +385,7 @@ SDValue PromoteIntOp_Shift(SDNode *N); SDValue PromoteIntOp_FunnelShift(SDNode *N); SDValue PromoteIntOp_SIGN_EXTEND(SDNode *N); + SDValue PromoteIntOp_VP_SIGN_EXTEND(SDNode *N); SDValue PromoteIntOp_SINT_TO_FP(SDNode *N); SDValue PromoteIntOp_STRICT_SINT_TO_FP(SDNode *N); SDValue PromoteIntOp_STORE(StoreSDNode *N, unsigned OpNo); @@ -392,6 +393,7 @@ SDValue PromoteIntOp_UINT_TO_FP(SDNode *N); SDValue PromoteIntOp_STRICT_UINT_TO_FP(SDNode *N); SDValue PromoteIntOp_ZERO_EXTEND(SDNode *N); + SDValue PromoteIntOp_VP_ZERO_EXTEND(SDNode *N); SDValue PromoteIntOp_MSTORE(MaskedStoreSDNode *N, unsigned OpNo); SDValue PromoteIntOp_MLOAD(MaskedLoadSDNode *N, unsigned OpNo); SDValue PromoteIntOp_MSCATTER(MaskedScatterSDNode *N, unsigned OpNo); diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp --- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp +++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp @@ -6923,7 +6923,9 @@ return N1; break; case ISD::VP_TRUNCATE: - // Don't create noop vp_truncate. + case ISD::VP_SIGN_EXTEND: + case ISD::VP_ZERO_EXTEND: + // Don't create noop casts. if (N1.getValueType() == VT) return N1; break; diff --git a/llvm/test/CodeGen/RISCV/rvv/fixed-vectors-sext-vp.ll b/llvm/test/CodeGen/RISCV/rvv/fixed-vectors-sext-vp.ll --- a/llvm/test/CodeGen/RISCV/rvv/fixed-vectors-sext-vp.ll +++ b/llvm/test/CodeGen/RISCV/rvv/fixed-vectors-sext-vp.ll @@ -201,3 +201,56 @@ %v = call <32 x i64> @llvm.vp.sext.v32i64.v32i32(<32 x i32> %va, <32 x i1> shufflevector (<32 x i1> insertelement (<32 x i1> undef, i1 true, i32 0), <32 x i1> undef, <32 x i32> zeroinitializer), i32 %evl) ret <32 x i64> %v } + +declare <4 x i16> @llvm.vp.sext.v4i16.v4i7(<4 x i7>, <4 x i1>, i32) + +define <4 x i16> @vsext_v4i16_v4i7(<4 x i7> %va, <4 x i1> %m, i32 zeroext %evl) { +; CHECK-LABEL: vsext_v4i16_v4i7: +; CHECK: # %bb.0: +; CHECK-NEXT: vsetvli zero, a0, e16, mf2, ta, ma +; CHECK-NEXT: vzext.vf2 v9, v8, v0.t +; CHECK-NEXT: vsll.vi v8, v9, 9, v0.t +; CHECK-NEXT: vsra.vi v8, v8, 9, v0.t +; CHECK-NEXT: ret + %v = call <4 x i16> @llvm.vp.sext.v4i16.v4i7(<4 x i7> %va, <4 x i1> %m, i32 %evl) + ret <4 x i16> %v +} + +declare <4 x i8> @llvm.vp.sext.v4i8.v4i7(<4 x i7>, <4 x i1>, i32) + +define <4 x i8> @vsext_v4i8_v4i7(<4 x i7> %va, <4 x i1> %m, i32 zeroext %evl) { +; CHECK-LABEL: vsext_v4i8_v4i7: +; CHECK: # %bb.0: +; CHECK-NEXT: vsetvli zero, a0, e8, mf4, ta, ma +; CHECK-NEXT: vsll.vi v8, v8, 1, v0.t +; CHECK-NEXT: vsra.vi v8, v8, 1, v0.t +; CHECK-NEXT: ret + %v = call <4 x i8> @llvm.vp.sext.v4i8.v4i7(<4 x i7> %va, <4 x i1> %m, i32 %evl) + ret <4 x i8> %v +} + +declare <4 x i15> @llvm.vp.sext.v4i15.v4i8(<4 x i8>, <4 x i1>, i32) + +define <4 x i15> @vsext_v4i15_v4i8(<4 x i8> %va, <4 x i1> %m, i32 zeroext %evl) { +; CHECK-LABEL: vsext_v4i15_v4i8: +; CHECK: # %bb.0: +; CHECK-NEXT: vsetvli zero, a0, e16, mf2, ta, ma +; CHECK-NEXT: vsext.vf2 v9, v8, v0.t +; CHECK-NEXT: vmv1r.v v8, v9 +; CHECK-NEXT: ret + %v = call <4 x i15> @llvm.vp.sext.v4i15.v4i8(<4 x i8> %va, <4 x i1> %m, i32 %evl) + ret <4 x i15> %v +} + +declare <4 x i15> @llvm.vp.sext.v4i15.v4i9(<4 x i9>, <4 x i1>, i32) + +define <4 x i15> @vsext_v4i15_v4i9(<4 x i9> %va, <4 x i1> %m, i32 zeroext %evl) { +; CHECK-LABEL: vsext_v4i15_v4i9: +; CHECK: # %bb.0: +; CHECK-NEXT: vsetvli zero, a0, e16, mf2, ta, ma +; CHECK-NEXT: vsll.vi v8, v8, 7, v0.t +; CHECK-NEXT: vsra.vi v8, v8, 7, v0.t +; CHECK-NEXT: ret + %v = call <4 x i15> @llvm.vp.sext.v4i15.v4i9(<4 x i9> %va, <4 x i1> %m, i32 %evl) + ret <4 x i15> %v +} diff --git a/llvm/test/CodeGen/RISCV/rvv/fixed-vectors-zext-vp.ll b/llvm/test/CodeGen/RISCV/rvv/fixed-vectors-zext-vp.ll --- a/llvm/test/CodeGen/RISCV/rvv/fixed-vectors-zext-vp.ll +++ b/llvm/test/CodeGen/RISCV/rvv/fixed-vectors-zext-vp.ll @@ -201,3 +201,56 @@ %v = call <32 x i64> @llvm.vp.zext.v32i64.v32i32(<32 x i32> %va, <32 x i1> shufflevector (<32 x i1> insertelement (<32 x i1> undef, i1 true, i32 0), <32 x i1> undef, <32 x i32> zeroinitializer), i32 %evl) ret <32 x i64> %v } + +declare <4 x i16> @llvm.vp.zext.v4i16.v4i7(<4 x i7>, <4 x i1>, i32) + +define <4 x i16> @vzext_v4i16_v4i7(<4 x i7> %va, <4 x i1> %m, i32 zeroext %evl) { +; CHECK-LABEL: vzext_v4i16_v4i7: +; CHECK: # %bb.0: +; CHECK-NEXT: vsetvli zero, a0, e16, mf2, ta, ma +; CHECK-NEXT: vzext.vf2 v9, v8, v0.t +; CHECK-NEXT: li a0, 127 +; CHECK-NEXT: vand.vx v8, v9, a0, v0.t +; CHECK-NEXT: ret + %v = call <4 x i16> @llvm.vp.zext.v4i16.v4i7(<4 x i7> %va, <4 x i1> %m, i32 %evl) + ret <4 x i16> %v +} + +declare <4 x i8> @llvm.vp.zext.v4i8.v4i7(<4 x i7>, <4 x i1>, i32) + +define <4 x i8> @vzext_v4i8_v4i7(<4 x i7> %va, <4 x i1> %m, i32 zeroext %evl) { +; CHECK-LABEL: vzext_v4i8_v4i7: +; CHECK: # %bb.0: +; CHECK-NEXT: li a1, 127 +; CHECK-NEXT: vsetvli zero, a0, e8, mf4, ta, ma +; CHECK-NEXT: vand.vx v8, v8, a1, v0.t +; CHECK-NEXT: ret + %v = call <4 x i8> @llvm.vp.zext.v4i8.v4i7(<4 x i7> %va, <4 x i1> %m, i32 %evl) + ret <4 x i8> %v +} + +declare <4 x i15> @llvm.vp.zext.v4i15.v4i8(<4 x i8>, <4 x i1>, i32) + +define <4 x i15> @vzext_v4i15_v4i8(<4 x i8> %va, <4 x i1> %m, i32 zeroext %evl) { +; CHECK-LABEL: vzext_v4i15_v4i8: +; CHECK: # %bb.0: +; CHECK-NEXT: vsetvli zero, a0, e16, mf2, ta, ma +; CHECK-NEXT: vzext.vf2 v9, v8, v0.t +; CHECK-NEXT: vmv1r.v v8, v9 +; CHECK-NEXT: ret + %v = call <4 x i15> @llvm.vp.zext.v4i15.v4i8(<4 x i8> %va, <4 x i1> %m, i32 %evl) + ret <4 x i15> %v +} + +declare <4 x i15> @llvm.vp.zext.v4i15.v4i9(<4 x i9>, <4 x i1>, i32) + +define <4 x i15> @vzext_v4i15_v4i9(<4 x i9> %va, <4 x i1> %m, i32 zeroext %evl) { +; CHECK-LABEL: vzext_v4i15_v4i9: +; CHECK: # %bb.0: +; CHECK-NEXT: li a1, 511 +; CHECK-NEXT: vsetvli zero, a0, e16, mf2, ta, ma +; CHECK-NEXT: vand.vx v8, v8, a1, v0.t +; CHECK-NEXT: ret + %v = call <4 x i15> @llvm.vp.zext.v4i15.v4i9(<4 x i9> %va, <4 x i1> %m, i32 %evl) + ret <4 x i15> %v +}