diff --git a/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp b/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp index 76c1a14fe0156..3324dd2e8fc21 100644 --- a/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp +++ b/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp @@ -968,6 +968,28 @@ static SDValue checkIntrinsicImmArg(SDValue Op, unsigned ImmOp, return SDValue(); } +static SDValue checkAndModifyXVPERMI_QIntrinsicImmArg(SDValue Op, + SelectionDAG &DAG) { + SDValue Op3 = Op->getOperand(3); + uint64_t Imm = Op3->getAsZExtVal(); + // Check the range of ImmArg. + if (!isUInt<8>(Imm)) { + DAG.getContext()->emitError(Op->getOperationName(0) + + ": argument out of range."); + return DAG.getNode(ISD::UNDEF, SDLoc(Op), Op.getValueType()); + } + + // For instruction xvpermi.q, only [1:0] and [5:4] bits of operands[3] + // are used. The unused bits in operands[3] need to be set to 0 to avoid + // causing undefined behavior on LA464. + if ((Imm & 0x33) != Imm) { + Op3 = DAG.getTargetConstant(Imm & 0x33, SDLoc(Op), Op3.getValueType()); + DAG.UpdateNodeOperands(Op.getNode(), Op->getOperand(0), Op->getOperand(1), + Op->getOperand(2), Op3); + } + return SDValue(); +} + SDValue LoongArchTargetLowering::lowerINTRINSIC_WO_CHAIN(SDValue Op, SelectionDAG &DAG) const { @@ -1225,13 +1247,14 @@ LoongArchTargetLowering::lowerINTRINSIC_WO_CHAIN(SDValue Op, case Intrinsic::loongarch_lsx_vextrins_d: case Intrinsic::loongarch_lasx_xvshuf4i_d: case Intrinsic::loongarch_lasx_xvpermi_w: - case Intrinsic::loongarch_lasx_xvpermi_q: case Intrinsic::loongarch_lasx_xvbitseli_b: case Intrinsic::loongarch_lasx_xvextrins_b: case Intrinsic::loongarch_lasx_xvextrins_h: case Intrinsic::loongarch_lasx_xvextrins_w: case Intrinsic::loongarch_lasx_xvextrins_d: return checkIntrinsicImmArg<8>(Op, 3, DAG); + case Intrinsic::loongarch_lasx_xvpermi_q: + return checkAndModifyXVPERMI_QIntrinsicImmArg(Op, DAG); case Intrinsic::loongarch_lsx_vrepli_b: case Intrinsic::loongarch_lsx_vrepli_h: case Intrinsic::loongarch_lsx_vrepli_w: diff --git a/llvm/test/CodeGen/LoongArch/lasx/intrinsic-permi.ll b/llvm/test/CodeGen/LoongArch/lasx/intrinsic-permi.ll index 0d9f9daabc448..92669d2e58955 100644 --- a/llvm/test/CodeGen/LoongArch/lasx/intrinsic-permi.ll +++ b/llvm/test/CodeGen/LoongArch/lasx/intrinsic-permi.ll @@ -36,3 +36,33 @@ entry: %res = call <32 x i8> @llvm.loongarch.lasx.xvpermi.q(<32 x i8> %va, <32 x i8> %vb, i32 1) ret <32 x i8> %res } + +define <32 x i8> @lasx_xvpermi_q_204(<32 x i8> %va, <32 x i8> %vb) nounwind { +; CHECK-LABEL: lasx_xvpermi_q_204: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: xvpermi.q $xr0, $xr1, 0 +; CHECK-NEXT: ret +entry: + %res = call <32 x i8> @llvm.loongarch.lasx.xvpermi.q(<32 x i8> %va, <32 x i8> %vb, i32 204) + ret <32 x i8> %res +} + +define <32 x i8> @lasx_xvpermi_q_221(<32 x i8> %va, <32 x i8> %vb) nounwind { +; CHECK-LABEL: lasx_xvpermi_q_221: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: xvpermi.q $xr0, $xr1, 17 +; CHECK-NEXT: ret +entry: + %res = call <32 x i8> @llvm.loongarch.lasx.xvpermi.q(<32 x i8> %va, <32 x i8> %vb, i32 221) + ret <32 x i8> %res +} + +define <32 x i8> @lasx_xvpermi_q_255(<32 x i8> %va, <32 x i8> %vb) nounwind { +; CHECK-LABEL: lasx_xvpermi_q_255: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: xvpermi.q $xr0, $xr1, 51 +; CHECK-NEXT: ret +entry: + %res = call <32 x i8> @llvm.loongarch.lasx.xvpermi.q(<32 x i8> %va, <32 x i8> %vb, i32 255) + ret <32 x i8> %res +}