diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp index 7fa4cda42510b2..8e4cec7d0f9b21 100644 --- a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp +++ b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp @@ -1960,29 +1960,37 @@ static SDValue lowerBUILD_VECTOR(SDValue Op, SelectionDAG &DAG, int64_t StepNumerator = SimpleVID->StepNumerator; unsigned StepDenominator = SimpleVID->StepDenominator; int64_t Addend = SimpleVID->Addend; + + assert(StepNumerator != 0 && "Invalid step"); + bool Negate = false; + int64_t SplatStepVal = StepNumerator; + unsigned StepOpcode = ISD::MUL; + if (StepNumerator != 1) { + if (isPowerOf2_64(std::abs(StepNumerator))) { + Negate = StepNumerator < 0; + StepOpcode = ISD::SHL; + SplatStepVal = Log2_64(std::abs(StepNumerator)); + } + } + // Only emit VIDs with suitably-small steps/addends. We use imm5 is a // threshold since it's the immediate value many RVV instructions accept. - if (isInt<5>(StepNumerator) && isPowerOf2_32(StepDenominator) && - isInt<5>(Addend)) { + // There is no vmul.vi instruction so ensure multiply constant can fit in + // a single addi instruction. + if (((StepOpcode == ISD::MUL && isInt<12>(SplatStepVal)) || + (StepOpcode == ISD::SHL && isUInt<5>(SplatStepVal))) && + isPowerOf2_32(StepDenominator) && isInt<5>(Addend)) { SDValue VID = DAG.getNode(RISCVISD::VID_VL, DL, ContainerVT, Mask, VL); // Convert right out of the scalable type so we can use standard ISD // nodes for the rest of the computation. If we used scalable types with // these, we'd lose the fixed-length vector info and generate worse // vsetvli code. VID = convertFromScalableVector(VT, VID, DAG, Subtarget); - assert(StepNumerator != 0 && "Invalid step"); - bool Negate = false; - if (StepNumerator != 1) { - int64_t SplatStepVal = StepNumerator; - unsigned Opcode = ISD::MUL; - if (isPowerOf2_64(std::abs(StepNumerator))) { - Negate = StepNumerator < 0; - Opcode = ISD::SHL; - SplatStepVal = Log2_64(std::abs(StepNumerator)); - } + if ((StepOpcode == ISD::MUL && SplatStepVal != 1) || + (StepOpcode == ISD::SHL && SplatStepVal != 0)) { SDValue SplatStep = DAG.getSplatVector( VT, DL, DAG.getConstant(SplatStepVal, DL, XLenVT)); - VID = DAG.getNode(Opcode, DL, VT, VID, SplatStep); + VID = DAG.getNode(StepOpcode, DL, VT, VID, SplatStep); } if (StepDenominator != 1) { SDValue SplatStep = DAG.getSplatVector( diff --git a/llvm/test/CodeGen/RISCV/rvv/fixed-vectors-int-buildvec.ll b/llvm/test/CodeGen/RISCV/rvv/fixed-vectors-int-buildvec.ll index 83417365d729d4..10ccb1d85d1131 100644 --- a/llvm/test/CodeGen/RISCV/rvv/fixed-vectors-int-buildvec.ll +++ b/llvm/test/CodeGen/RISCV/rvv/fixed-vectors-int-buildvec.ll @@ -638,3 +638,28 @@ define void @buildvec_vid_stepn1o4_addn5_v8i8(<8 x i8>* %z0) { store <8 x i8> , <8 x i8>* %z0 ret void } + +define void @buildvec_vid_mpy_imm_v8i16(<8 x i16>* %x) { +; CHECK-LABEL: buildvec_vid_mpy_imm_v8i16: +; CHECK: # %bb.0: +; CHECK-NEXT: vsetivli zero, 8, e16, m1, ta, mu +; CHECK-NEXT: vid.v v8 +; CHECK-NEXT: li a1, 17 +; CHECK-NEXT: vmul.vx v8, v8, a1 +; CHECK-NEXT: vse16.v v8, (a0) +; CHECK-NEXT: ret + store <8 x i16> , <8 x i16>* %x + ret void +} + +define void @buildvec_vid_shl_imm_v8i16(<8 x i16>* %x) { +; CHECK-LABEL: buildvec_vid_shl_imm_v8i16: +; CHECK: # %bb.0: +; CHECK-NEXT: vsetivli zero, 8, e16, m1, ta, mu +; CHECK-NEXT: vid.v v8 +; CHECK-NEXT: vsll.vi v8, v8, 9 +; CHECK-NEXT: vse16.v v8, (a0) +; CHECK-NEXT: ret + store <8 x i16> , <8 x i16>* %x + ret void +}