@@ -2737,6 +2737,116 @@ void CodeGen::genHWIntrinsic(GenTreeHWIntrinsic* node)
27372737 GetEmitter ()->emitInsSve_R_R_R (ins, emitSize, targetReg, op3Reg, op1Reg, INS_OPTS_SCALABLE_D);
27382738 break ;
27392739
2740+ case NI_Sve2_DotProductRotateComplex:
2741+ {
2742+ assert (isRMW);
2743+ assert (hasImmediateOperand);
2744+
2745+ HWIntrinsicImmOpHelper helper (this , intrin.op4 , node, (targetReg != op1Reg) ? 2 : 1 );
2746+
2747+ for (helper.EmitBegin (); !helper.Done (); helper.EmitCaseEnd ())
2748+ {
2749+ if (targetReg != op1Reg)
2750+ {
2751+ assert (targetReg != op2Reg);
2752+
2753+ GetEmitter ()->emitInsSve_R_R (INS_sve_movprfx, EA_SCALABLE, targetReg, op1Reg);
2754+ }
2755+
2756+ GetEmitter ()->emitInsSve_R_R_R_I (ins, emitSize, targetReg, op2Reg, op3Reg, helper.ImmValue (), opt);
2757+ }
2758+ break ;
2759+ }
2760+
2761+ case NI_Sve2_DotProductRotateComplexBySelectedIndex:
2762+ {
2763+ assert (isRMW);
2764+ assert (hasImmediateOperand);
2765+
2766+ // If both immediates are constant, we don't need a jump table
2767+ if (intrin.op4 ->IsCnsIntOrI () && intrin.op5 ->IsCnsIntOrI ())
2768+ {
2769+ if (targetReg != op1Reg)
2770+ {
2771+ assert (targetReg != op2Reg);
2772+ assert (targetReg != op3Reg);
2773+ GetEmitter ()->emitInsSve_R_R (INS_sve_movprfx, EA_SCALABLE, targetReg, op1Reg);
2774+ }
2775+
2776+ assert (intrin.op4 ->isContainedIntOrIImmed () && intrin.op5 ->isContainedIntOrIImmed ());
2777+ GetEmitter ()->emitInsSve_R_R_R_I_I (ins, emitSize, targetReg, op2Reg, op3Reg,
2778+ intrin.op4 ->AsIntCon ()->gtIconVal ,
2779+ intrin.op5 ->AsIntCon ()->gtIconVal , opt);
2780+ }
2781+ else
2782+ {
2783+ // Use the helper to generate a table. The table can only use a single lookup value, therefore
2784+ // the two immediates index and rotation must be combined to a single value
2785+ assert (!intrin.op4 ->isContainedIntOrIImmed () && !intrin.op5 ->isContainedIntOrIImmed ());
2786+ emitAttr scalarSize = emitActualTypeSize (node->GetSimdBaseType ());
2787+
2788+ var_types baseType = node->GetSimdBaseType ();
2789+
2790+ if (baseType == TYP_BYTE)
2791+ {
2792+ GetEmitter ()->emitIns_R_R_I (INS_lsl, scalarSize, op5Reg, op5Reg, 2 );
2793+ GetEmitter ()->emitIns_R_R_R (INS_orr, scalarSize, op4Reg, op4Reg, op5Reg);
2794+
2795+ // index and rotation both take values 0 to 3 so must be
2796+ // combined to a single value (0 to 15)
2797+ HWIntrinsicImmOpHelper helper (this , op4Reg, 0 , 15 , node, (targetReg != op1Reg) ? 2 : 1 );
2798+ for (helper.EmitBegin (); !helper.Done (); helper.EmitCaseEnd ())
2799+ {
2800+ if (targetReg != op1Reg)
2801+ {
2802+ assert (targetReg != op2Reg);
2803+ assert (targetReg != op3Reg);
2804+ GetEmitter ()->emitInsSve_R_R (INS_sve_movprfx, EA_SCALABLE, targetReg, op1Reg);
2805+ }
2806+
2807+ const int value = helper.ImmValue ();
2808+ const ssize_t index = value & 3 ;
2809+ const ssize_t rotation = (value >> 2 ) & 3 ;
2810+ GetEmitter ()->emitInsSve_R_R_R_I_I (ins, emitSize, targetReg, op2Reg, op3Reg, index,
2811+ rotation, opt);
2812+ }
2813+
2814+ GetEmitter ()->emitIns_R_R_I (INS_and, scalarSize, op4Reg, op4Reg, 3 );
2815+ GetEmitter ()->emitIns_R_R_I (INS_lsr, scalarSize, op5Reg, op5Reg, 2 );
2816+ }
2817+ else
2818+ {
2819+ assert (baseType == TYP_SHORT);
2820+ GetEmitter ()->emitIns_R_R_I (INS_lsl, scalarSize, op5Reg, op5Reg, 1 );
2821+ GetEmitter ()->emitIns_R_R_R (INS_orr, scalarSize, op4Reg, op4Reg, op5Reg);
2822+
2823+ // index (0 to 1, in op4Reg) and rotation (0 to 3, in op5Reg) must be
2824+ // combined to a single value (0 to 7)
2825+ HWIntrinsicImmOpHelper helper (this , op4Reg, 0 , 7 , node, (targetReg != op1Reg) ? 2 : 1 );
2826+ for (helper.EmitBegin (); !helper.Done (); helper.EmitCaseEnd ())
2827+ {
2828+ if (targetReg != op1Reg)
2829+ {
2830+ assert (targetReg != op2Reg);
2831+ assert (targetReg != op3Reg);
2832+ GetEmitter ()->emitInsSve_R_R (INS_sve_movprfx, EA_SCALABLE, targetReg, op1Reg);
2833+ }
2834+
2835+ const int value = helper.ImmValue ();
2836+ const ssize_t index = value & 1 ;
2837+ const ssize_t rotation = value >> 1 ;
2838+ GetEmitter ()->emitInsSve_R_R_R_I_I (ins, emitSize, targetReg, op2Reg, op3Reg, index,
2839+ rotation, opt);
2840+ }
2841+
2842+ GetEmitter ()->emitIns_R_R_I (INS_and, scalarSize, op4Reg, op4Reg, 1 );
2843+ GetEmitter ()->emitIns_R_R_I (INS_lsr, scalarSize, op5Reg, op5Reg, 1 );
2844+ }
2845+ }
2846+
2847+ break ;
2848+ }
2849+
27402850 case NI_Sve2_SubtractWideningEven:
27412851 {
27422852 var_types returnType = node->AsHWIntrinsic ()->GetSimdBaseType ();
0 commit comments