@@ -18432,4 +18432,212 @@ void emitter::getInsSveExecutionCharacteristics(instrDesc* id, insExecutionChara
18432
18432
}
18433
18433
#endif // defined(DEBUG) || defined(LATE_DISASM)
18434
18434
18435
+ #ifdef DEBUG
18436
+ /*****************************************************************************
18437
+ *
18438
+ * Sanity check two instructions are valid when placed next to each other
18439
+ */
18440
+
18441
+ void emitter::emitInsPairSanityCheck(instrDesc* firstId, instrDesc* secondId)
18442
+ {
18443
+ if (firstId == nullptr || secondId == nullptr)
18444
+ {
18445
+ return;
18446
+ }
18447
+
18448
+ // Currently only concerned with instructions that follow movprfx
18449
+ if (firstId->idIns() != INS_sve_movprfx)
18450
+ {
18451
+ return;
18452
+ }
18453
+
18454
+ bool movprefxIsPredicated = false;
18455
+ if (firstId->idInsFmt() == IF_SVE_AH_3A)
18456
+ {
18457
+ movprefxIsPredicated = true;
18458
+ }
18459
+ else
18460
+ {
18461
+ // Unpredicated version
18462
+ assert(firstId->idInsFmt() == IF_SVE_BI_2A);
18463
+ }
18464
+
18465
+ // Quoted sections are taken from the Arm manual.
18466
+
18467
+ // "It is required that the prefixed instruction at PC+4 must be an SVE destructive binary or ternary
18468
+ // instruction encoding, or a unary operation with merging predication, but excluding other MOVPRFX instructions."
18469
+ // "The prefixed instruction must not use the destination register in any other operand position, even if
18470
+ // they have different names but refer to the same architectural register state."
18471
+ // "A predicated MOVPRFX cannot be used with an unpredicated instruction."
18472
+ switch (secondId->idInsFmt())
18473
+ {
18474
+ case IF_SVE_BN_1A: // <Zdn>.D{, <pattern>{, MUL #<imm>}}
18475
+ case IF_SVE_BP_1A: // <Zdn>.D{, <pattern>{, MUL #<imm>}}
18476
+ case IF_SVE_CC_2A: // <Zdn>.<T>, <V><m>
18477
+ case IF_SVE_CD_2A: // <Zdn>.<T>, <R><m>
18478
+ case IF_SVE_DN_2A: // <Zdn>.<T>, <Pm>.<T>
18479
+ case IF_SVE_DP_2A: // <Zdn>.<T>, <Pm>.<T>
18480
+ // Tied registers
18481
+ case IF_SVE_BS_1A: // <Zdn>.<T>, <Zdn>.<T>, #<const>
18482
+ case IF_SVE_EC_1A: // <Zdn>.<T>, <Zdn>.<T>, #<imm>{, <shift>}
18483
+ case IF_SVE_ED_1A: // <Zdn>.<T>, <Zdn>.<T>, #<imm>
18484
+ case IF_SVE_EE_1A: // <Zdn>.<T>, <Zdn>.<T>, #<imm>
18485
+ assert(!movprefxIsPredicated);
18486
+ break;
18487
+
18488
+ case IF_SVE_BU_2A: // <Zd>.<T>, <Pg>/M, #<const>
18489
+ case IF_SVE_BV_2A_A: // <Zd>.<T>, <Pg>/M, #<imm>{, <shift>}
18490
+ case IF_SVE_BV_2A_J: // <Zd>.<T>, <Pg>/M, #<imm>{, <shift>}
18491
+ case IF_SVE_BV_2B: // <Zd>.<T>, <Pg>/M, #0.0
18492
+ case IF_SVE_CQ_3A: // <Zd>.<T>, <Pg>/M, <R><n|SP>
18493
+ // Tied registers
18494
+ case IF_SVE_AM_2A: // <Zdn>.<T>, <Pg>/M, <Zdn>.<T>, #<const>
18495
+ case IF_SVE_HM_2A: // <Zdn>.<T>, <Pg>/M, <Zdn>.<T>, <const>
18496
+ break;
18497
+
18498
+ case IF_SVE_FU_2A: // <Zda>.<T>, <Zn>.<T>, #<const>
18499
+ // Tied registers
18500
+ case IF_SVE_AW_2A: // <Zdn>.<T>, <Zdn>.<T>, <Zm>.<T>, #<const>
18501
+ case IF_SVE_BY_2A: // <Zdn>.B, <Zdn>.B, <Zm>.B, #<imm>
18502
+ case IF_SVE_FV_2A: // <Zdn>.<T>, <Zdn>.<T>, <Zm>.<T>, <const>
18503
+ case IF_SVE_HN_2A: // <Zdn>.<T>, <Zdn>.<T>, <Zm>.<T>, #<imm>
18504
+ assert(!movprefxIsPredicated);
18505
+ assert(secondId->idReg1() != secondId->idReg2());
18506
+ break;
18507
+
18508
+ case IF_SVE_AP_3A: // <Zd>.<T>, <Pg>/M, <Zn>.<T>
18509
+ case IF_SVE_AQ_3A: // <Zd>.<T>, <Pg>/M, <Zn>.<T>
18510
+ case IF_SVE_CP_3A: // <Zd>.<T>, <Pg>/M, <V><n>
18511
+ case IF_SVE_CT_3A: // <Zd>.Q, <Pg>/M, <Zn>.Q
18512
+ case IF_SVE_CU_3A: // <Zd>.<T>, <Pg>/M, <Zn>.<T>
18513
+ case IF_SVE_ES_3A: // <Zd>.<T>, <Pg>/M, <Zn>.<T>
18514
+ case IF_SVE_EQ_3A: // <Zda>.<T>, <Pg>/M, <Zn>.<Tb>
18515
+ case IF_SVE_HO_3A: // <Zd>.H, <Pg>/M, <Zn>.S
18516
+ case IF_SVE_HO_3B: // <Zd>.D, <Pg>/M, <Zn>.S
18517
+ case IF_SVE_HO_3C: // <Zd>.S, <Pg>/M, <Zn>.D
18518
+ case IF_SVE_HP_3A: // <Zd>.<T>, <Pg>/M, <Zn>.<T>
18519
+ case IF_SVE_HQ_3A: // <Zd>.<T>, <Pg>/M, <Zn>.<T>
18520
+ case IF_SVE_HR_3A: // <Zd>.<T>, <Pg>/M, <Zn>.<T>
18521
+ case IF_SVE_HS_3A: // <Zd>.<H|S|D>, <Pg>/M, <Zn>.<H|S|D>
18522
+ case IF_SVE_HP_3B: // <Zd>.<H|S|D>, <Pg>/M, <Zn>.<H|S|D>
18523
+ // Tied registers
18524
+ case IF_SVE_AA_3A: // <Zdn>.<T>, <Pg>/M, <Zdn>.<T>, <Zm>.<T>
18525
+ case IF_SVE_AB_3B: // <Zdn>.D, <Pg>/M, <Zdn>.D, <Zm>.D
18526
+ case IF_SVE_AC_3A: // <Zdn>.<T>, <Pg>/M, <Zdn>.<T>, <Zm>.<T>
18527
+ case IF_SVE_AO_3A: // <Zdn>.<T>, <Pg>/M, <Zdn>.<T>, <Zm>.D
18528
+ case IF_SVE_CM_3A: // <Zdn>.<T>, <Pg>, <Zdn>.<T>, <Zm>.<T>
18529
+ case IF_SVE_GP_3A: // <Zdn>.<T>, <Pg>/M, <Zdn>.<T>, <Zm>.<T>, <const>
18530
+ case IF_SVE_GR_3A: // <Zdn>.<T>, <Pg>/M, <Zdn>.<T>, <Zm>.<T>
18531
+ case IF_SVE_HL_3A: // <Zdn>.<T>, <Pg>/M, <Zdn>.<T>, <Zm>.<T>
18532
+ case IF_SVE_HL_3B: // <Zdn>.H, <Pg>/M, <Zdn>.H, <Zm>.H
18533
+ assert(secondId->idReg1() != secondId->idReg3());
18534
+ break;
18535
+
18536
+ case IF_SVE_EF_3A: // <Zda>.S, <Zn>.H, <Zm>.H
18537
+ case IF_SVE_EG_3A: // <Zda>.S, <Zn>.H, <Zm>.H[<imm>]
18538
+ case IF_SVE_EH_3A: // <Zda>.<T>, <Zn>.<Tb>, <Zm>.<Tb>
18539
+ case IF_SVE_EI_3A: // <Zda>.S, <Zn>.B, <Zm>.B
18540
+ case IF_SVE_EJ_3A: // <Zda>.<T>, <Zn>.<Tb>, <Zm>.<Tb>, <const>
18541
+ case IF_SVE_EK_3A: // <Zda>.<T>, <Zn>.<T>, <Zm>.<T>, <const>
18542
+ case IF_SVE_EL_3A: // <Zda>.<T>, <Zn>.<Tb>, <Zm>.<Tb>
18543
+ case IF_SVE_EM_3A: // <Zda>.<T>, <Zn>.<T>, <Zm>.<T>
18544
+ case IF_SVE_EW_3A: // <Zda>.D, <Zn>.D, <Zm>.D
18545
+ case IF_SVE_EW_3B: // <Zdn>.D, <Zm>.D, <Za>.D
18546
+ case IF_SVE_EY_3A: // <Zda>.S, <Zn>.B, <Zm>.B[<imm>]
18547
+ case IF_SVE_EY_3B: // <Zda>.D, <Zn>.H, <Zm>.H[<imm>]
18548
+ case IF_SVE_EZ_3A: // <Zda>.S, <Zn>.B, <Zm>.B[<imm>]
18549
+ case IF_SVE_FA_3A: // <Zda>.S, <Zn>.B, <Zm>.B[<imm>], <const>
18550
+ case IF_SVE_FA_3B: // <Zda>.D, <Zn>.H, <Zm>.H[<imm>], <const>
18551
+ case IF_SVE_FB_3A: // <Zda>.H, <Zn>.H, <Zm>.H[<imm>], <const>
18552
+ case IF_SVE_FB_3B: // <Zda>.S, <Zn>.S, <Zm>.S[<imm>], <const>
18553
+ case IF_SVE_FC_3A: // <Zda>.H, <Zn>.H, <Zm>.H[<imm>], <const>
18554
+ case IF_SVE_FC_3B: // <Zda>.S, <Zn>.S, <Zm>.S[<imm>], <const>
18555
+ case IF_SVE_FF_3A: // <Zda>.H, <Zn>.H, <Zm>.H[<imm>]
18556
+ case IF_SVE_FF_3B: // <Zda>.S, <Zn>.S, <Zm>.S[<imm>]
18557
+ case IF_SVE_FF_3C: // <Zda>.D, <Zn>.D, <Zm>.D[<imm>]
18558
+ case IF_SVE_FG_3A: // <Zda>.S, <Zn>.H, <Zm>.H[<imm>]
18559
+ case IF_SVE_FG_3B: // <Zda>.D, <Zn>.S, <Zm>.S[<imm>]
18560
+ case IF_SVE_FJ_3A: // <Zda>.S, <Zn>.H, <Zm>.H[<imm>]
18561
+ case IF_SVE_FJ_3B: // <Zda>.D, <Zn>.S, <Zm>.S[<imm>]
18562
+ case IF_SVE_FK_3A: // <Zda>.H, <Zn>.H, <Zm>.H[<imm>]
18563
+ case IF_SVE_FK_3B: // <Zda>.S, <Zn>.S, <Zm>.S[<imm>]
18564
+ case IF_SVE_FK_3C: // <Zda>.D, <Zn>.D, <Zm>.D[<imm>]
18565
+ case IF_SVE_FO_3A: // <Zda>.S, <Zn>.B, <Zm>.B
18566
+ case IF_SVE_FW_3A: // <Zda>.<T>, <Zn>.<T>, <Zm>.<T>
18567
+ case IF_SVE_FY_3A: // <Zda>.<T>, <Zn>.<T>, <Zm>.<T>
18568
+ case IF_SVE_GM_3A: // <Zda>.H, <Zn>.B, <Zm>.B[<imm>]
18569
+ case IF_SVE_GN_3A: // <Zda>.H, <Zn>.B, <Zm>.B
18570
+ case IF_SVE_GO_3A: // <Zda>.S, <Zn>.B, <Zm>.B
18571
+ case IF_SVE_GU_3A: // <Zda>.S, <Zn>.S, <Zm>.S[<imm>]
18572
+ case IF_SVE_GU_3B: // <Zda>.D, <Zn>.D, <Zm>.D[<imm>]
18573
+ case IF_SVE_GU_3C: // <Zda>.H, <Zn>.H, <Zm>.H[<imm>]
18574
+ case IF_SVE_GV_3A: // <Zda>.S, <Zn>.S, <Zm>.S[<imm>], <const>
18575
+ case IF_SVE_GW_3B: // <Zd>.H, <Zn>.H, <Zm>.H
18576
+ case IF_SVE_GY_3A: // <Zda>.H, <Zn>.B, <Zm>.B[<imm>]
18577
+ case IF_SVE_GY_3B: // <Zda>.S, <Zn>.H, <Zm>.H[<imm>]
18578
+ case IF_SVE_GY_3B_D: // <Zda>.S, <Zn>.B, <Zm>.B[<imm>]
18579
+ case IF_SVE_GZ_3A: // <Zda>.S, <Zn>.H, <Zm>.H[<imm>]
18580
+ case IF_SVE_HA_3A: // <Zda>.S, <Zn>.H, <Zm>.H
18581
+ case IF_SVE_HA_3A_E: // <Zda>.H, <Zn>.B, <Zm>.B
18582
+ case IF_SVE_HA_3A_F: // <Zda>.S, <Zn>.B, <Zm>.B
18583
+ case IF_SVE_HB_3A: // <Zda>.S, <Zn>.H, <Zm>.H
18584
+ case IF_SVE_HC_3A: // <Zda>.S, <Zn>.B, <Zm>.B[<imm>]
18585
+ case IF_SVE_HD_3A: // <Zda>.S, <Zn>.H, <Zm>.H
18586
+ case IF_SVE_HD_3A_A: // <Zda>.D, <Zn>.D, <Zm>.D
18587
+ // Tied registers
18588
+ case IF_SVE_AV_3A: // <Zdn>.D, <Zdn>.D, <Zm>.D, <Zk>.D
18589
+ assert(!movprefxIsPredicated);
18590
+ assert(secondId->idReg1() != secondId->idReg2());
18591
+ assert(secondId->idReg1() != secondId->idReg3());
18592
+ break;
18593
+
18594
+ case IF_SVE_AR_4A: // <Zda>.<T>, <Pg>/M, <Zn>.<T>, <Zm>.<T>
18595
+ case IF_SVE_AS_4A: // <Zdn>.<T>, <Pg>/M, <Zm>.<T>, <Za>.<T>
18596
+ case IF_SVE_GT_4A: // <Zda>.<T>, <Pg>/M, <Zn>.<T>, <Zm>.<T>, <const>
18597
+ case IF_SVE_HU_4A: // <Zda>.<T>, <Pg>/M, <Zn>.<T>, <Zm>.<T>
18598
+ case IF_SVE_HU_4B: // <Zda>.H, <Pg>/M, <Zn>.H, <Zm>.H
18599
+ case IF_SVE_HV_4A: // <Zdn>.<T>, <Pg>/M, <Zm>.<T>, <Za>.<T>
18600
+ assert(secondId->idReg1() != secondId->idReg3());
18601
+ assert(secondId->idReg1() != secondId->idReg4());
18602
+ break;
18603
+
18604
+ case IF_SVE_AT_3A: // <Zd>.<T>, <Zn>.<T>, <Zm>.<T>
18605
+ // Only a subset of this group is valid
18606
+ switch (secondId->idIns())
18607
+ {
18608
+ case INS_sve_sclamp:
18609
+ case INS_sve_uclamp:
18610
+ case INS_sve_eorbt:
18611
+ case INS_sve_eortb:
18612
+ case INS_sve_fclamp:
18613
+ break;
18614
+ default:
18615
+ assert(!"Got unexpected instruction format within group after MOVPRFX");
18616
+ }
18617
+ assert(!movprefxIsPredicated);
18618
+ assert(secondId->idReg1() != secondId->idReg2());
18619
+ assert(secondId->idReg1() != secondId->idReg3());
18620
+ break;
18621
+
18622
+ default:
18623
+ assert(!"Got unexpected instruction format after MOVPRFX");
18624
+ break;
18625
+ }
18626
+
18627
+ // "The prefixed instruction must specify the same destination vector as the MOVPRFX instruction."
18628
+ assert(firstId->idReg1() == secondId->idReg1());
18629
+
18630
+ if (movprefxIsPredicated)
18631
+ {
18632
+ // "The prefixed instruction must specify the same predicate register"
18633
+ assert(isPredicateRegister(firstId->idReg2()));
18634
+ assert(isPredicateRegister(secondId->idReg2()));
18635
+ assert(firstId->idReg2() == secondId->idReg2());
18636
+
18637
+ // "predicated using the same governing predicate register and source element size as this instruction."
18638
+ assert(firstId->idInsOpt() == secondId->idInsOpt());
18639
+ }
18640
+ }
18641
+ #endif // DEBUG
18642
+
18435
18643
#endif // TARGET_ARM64
0 commit comments