@@ -582,6 +582,7 @@ void CodeGen::genHWIntrinsic(GenTreeHWIntrinsic* node)
582582 case NI_Sve_ConvertToInt32:
583583 case NI_Sve_ConvertToUInt32:
584584 case NI_Sve_ConvertToSingle:
585+ case NI_Sve2_ConvertToSingleEvenRoundToOdd:
585586 {
586587 embOpt = emitTypeSize (intrinEmbMask.baseType ) == EA_8BYTE ? INS_OPTS_D_TO_S
587588 : INS_OPTS_SCALABLE_S;
@@ -591,6 +592,7 @@ void CodeGen::genHWIntrinsic(GenTreeHWIntrinsic* node)
591592 case NI_Sve_ConvertToInt64:
592593 case NI_Sve_ConvertToUInt64:
593594 case NI_Sve_ConvertToDouble:
595+ case NI_Sve2_ConvertToDoubleOdd:
594596 {
595597 embOpt = emitTypeSize (intrinEmbMask.baseType ) == EA_4BYTE ? INS_OPTS_S_TO_D
596598 : INS_OPTS_SCALABLE_D;
@@ -2598,6 +2600,8 @@ void CodeGen::genHWIntrinsic(GenTreeHWIntrinsic* node)
25982600 }
25992601
26002602 case NI_Sve_TrigonometricMultiplyAddCoefficient:
2603+ case NI_Sve2_AddRotateComplex:
2604+ case NI_Sve2_AddSaturateRotateComplex:
26012605 {
26022606 assert (isRMW);
26032607
@@ -2618,6 +2622,8 @@ void CodeGen::genHWIntrinsic(GenTreeHWIntrinsic* node)
26182622 }
26192623
26202624 case NI_Sve_MultiplyAddRotateComplexBySelectedScalar:
2625+ case NI_Sve2_MultiplyAddRotateComplexBySelectedScalar:
2626+ case NI_Sve2_MultiplyAddRoundedDoublingSaturateHighRotateComplexBySelectedScalar:
26212627 {
26222628 assert (isRMW);
26232629 assert (hasImmediateOperand);
@@ -2640,39 +2646,67 @@ void CodeGen::genHWIntrinsic(GenTreeHWIntrinsic* node)
26402646 else
26412647 {
26422648 // Use the helper to generate a table. The table can only use a single lookup value, therefore
2643- // the two immediates index (0 to 1, in op4Reg) and rotation (0 to 3, in op5Reg) must be
2644- // combined to a single value (0 to 7)
2649+ // the two immediates index and rotation must be combined to a single value
26452650 assert (!intrin.op4 ->isContainedIntOrIImmed () && !intrin.op5 ->isContainedIntOrIImmed ());
26462651 emitAttr scalarSize = emitActualTypeSize (node->GetSimdBaseType ());
26472652
2648- // Combine the two immediates into op4Reg
2649- // Shift rotation left to be out of range of index
2650- GetEmitter ()->emitIns_R_R_I (INS_lsl, scalarSize, op5Reg, op5Reg, 1 );
2651- // Combine the two values by ORing
2652- GetEmitter ()->emitIns_R_R_R (INS_orr, scalarSize, op4Reg, op4Reg, op5Reg);
2653+ var_types baseType = node->GetSimdBaseType ();
26532654
2654- // Generate the table using the combined immediate
2655- HWIntrinsicImmOpHelper helper (this , op4Reg, 0 , 7 , node, (targetReg != op1Reg) ? 2 : 1 );
2656- for (helper.EmitBegin (); !helper.Done (); helper.EmitCaseEnd ())
2655+ if (baseType == TYP_SHORT || baseType == TYP_USHORT)
26572656 {
2658- if (targetReg != op1Reg)
2657+ GetEmitter ()->emitIns_R_R_I (INS_lsl, scalarSize, op5Reg, op5Reg, 2 );
2658+ GetEmitter ()->emitIns_R_R_R (INS_orr, scalarSize, op4Reg, op4Reg, op5Reg);
2659+
2660+ // index and rotation both take values 0 to 3 so must be
2661+ // combined to a single value (0 to 15)
2662+ HWIntrinsicImmOpHelper helper (this , op4Reg, 0 , 15 , node, (targetReg != op1Reg) ? 2 : 1 );
2663+ for (helper.EmitBegin (); !helper.Done (); helper.EmitCaseEnd ())
26592664 {
2660- assert (targetReg != op2Reg);
2661- assert (targetReg != op3Reg);
2662- GetEmitter ()->emitInsSve_R_R (INS_sve_movprfx, EA_SCALABLE, targetReg, op1Reg);
2665+ if (targetReg != op1Reg)
2666+ {
2667+ assert (targetReg != op2Reg);
2668+ assert (targetReg != op3Reg);
2669+ GetEmitter ()->emitInsSve_R_R (INS_sve_movprfx, EA_SCALABLE, targetReg, op1Reg);
2670+ }
2671+
2672+ const int value = helper.ImmValue ();
2673+ const ssize_t index = value & 3 ;
2674+ const ssize_t rotation = (value >> 2 ) & 3 ;
2675+ GetEmitter ()->emitInsSve_R_R_R_I_I (ins, emitSize, targetReg, op2Reg, op3Reg, index,
2676+ rotation, opt);
26632677 }
26642678
2665- // Extract index and rotation from the immediate
2666- const int value = helper.ImmValue ();
2667- const ssize_t index = value & 1 ;
2668- const ssize_t rotation = value >> 1 ;
2669- GetEmitter ()->emitInsSve_R_R_R_I_I (ins, emitSize, targetReg, op2Reg, op3Reg, index, rotation,
2670- opt);
2679+ GetEmitter ()->emitIns_R_R_I (INS_and, scalarSize, op4Reg, op4Reg, 3 );
2680+ GetEmitter ()->emitIns_R_R_I (INS_lsr, scalarSize, op5Reg, op5Reg, 2 );
26712681 }
2682+ else
2683+ {
2684+ assert (baseType == TYP_INT || baseType == TYP_UINT || baseType == TYP_FLOAT);
2685+ GetEmitter ()->emitIns_R_R_I (INS_lsl, scalarSize, op5Reg, op5Reg, 1 );
2686+ GetEmitter ()->emitIns_R_R_R (INS_orr, scalarSize, op4Reg, op4Reg, op5Reg);
26722687
2673- // Restore the original values in op4Reg and op5Reg
2674- GetEmitter ()->emitIns_R_R_I (INS_and, scalarSize, op4Reg, op4Reg, 1 );
2675- GetEmitter ()->emitIns_R_R_I (INS_lsr, scalarSize, op5Reg, op5Reg, 1 );
2688+ // index (0 to 1, in op4Reg) and rotation (0 to 3, in op5Reg) must be
2689+ // combined to a single value (0 to 7)
2690+ HWIntrinsicImmOpHelper helper (this , op4Reg, 0 , 7 , node, (targetReg != op1Reg) ? 2 : 1 );
2691+ for (helper.EmitBegin (); !helper.Done (); helper.EmitCaseEnd ())
2692+ {
2693+ if (targetReg != op1Reg)
2694+ {
2695+ assert (targetReg != op2Reg);
2696+ assert (targetReg != op3Reg);
2697+ GetEmitter ()->emitInsSve_R_R (INS_sve_movprfx, EA_SCALABLE, targetReg, op1Reg);
2698+ }
2699+
2700+ const int value = helper.ImmValue ();
2701+ const ssize_t index = value & 1 ;
2702+ const ssize_t rotation = value >> 1 ;
2703+ GetEmitter ()->emitInsSve_R_R_R_I_I (ins, emitSize, targetReg, op2Reg, op3Reg, index,
2704+ rotation, opt);
2705+ }
2706+
2707+ GetEmitter ()->emitIns_R_R_I (INS_and, scalarSize, op4Reg, op4Reg, 1 );
2708+ GetEmitter ()->emitIns_R_R_I (INS_lsr, scalarSize, op5Reg, op5Reg, 1 );
2709+ }
26762710 }
26772711
26782712 break ;
@@ -2737,6 +2771,8 @@ void CodeGen::genHWIntrinsic(GenTreeHWIntrinsic* node)
27372771 GetEmitter ()->emitInsSve_R_R_R (ins, emitSize, targetReg, op3Reg, op1Reg, INS_OPTS_SCALABLE_D);
27382772 break ;
27392773
2774+ case NI_Sve2_MultiplyAddRotateComplex:
2775+ case NI_Sve2_MultiplyAddRoundedDoublingSaturateHighRotateComplex:
27402776 case NI_Sve2_DotProductRotateComplex:
27412777 {
27422778 assert (isRMW);
0 commit comments