InstEmitSimdCmp.cs
1 using ARMeilleure.Decoders; 2 using ARMeilleure.IntermediateRepresentation; 3 using ARMeilleure.State; 4 using ARMeilleure.Translation; 5 using System; 6 using static ARMeilleure.Instructions.InstEmitHelper; 7 using static ARMeilleure.Instructions.InstEmitSimdHelper; 8 using static ARMeilleure.IntermediateRepresentation.Operand.Factory; 9 10 namespace ARMeilleure.Instructions 11 { 12 using Func2I = Func<Operand, Operand, Operand>; 13 14 static partial class InstEmit 15 { 16 public static void Cmeq_S(ArmEmitterContext context) 17 { 18 EmitCmpOp(context, (op1, op2) => context.ICompareEqual(op1, op2), scalar: true); 19 } 20 21 public static void Cmeq_V(ArmEmitterContext context) 22 { 23 if (Optimizations.UseSse41) 24 { 25 OpCodeSimd op = (OpCodeSimd)context.CurrOp; 26 27 Operand n = GetVec(op.Rn); 28 Operand m; 29 30 if (op is OpCodeSimdReg binOp) 31 { 32 m = GetVec(binOp.Rm); 33 } 34 else 35 { 36 m = context.VectorZero(); 37 } 38 39 Intrinsic cmpInst = X86PcmpeqInstruction[op.Size]; 40 41 Operand res = context.AddIntrinsic(cmpInst, n, m); 42 43 if (op.RegisterSize == RegisterSize.Simd64) 44 { 45 res = context.VectorZeroUpper64(res); 46 } 47 48 context.Copy(GetVec(op.Rd), res); 49 } 50 else 51 { 52 EmitCmpOp(context, (op1, op2) => context.ICompareEqual(op1, op2), scalar: false); 53 } 54 } 55 56 public static void Cmge_S(ArmEmitterContext context) 57 { 58 EmitCmpOp(context, (op1, op2) => context.ICompareGreaterOrEqual(op1, op2), scalar: true); 59 } 60 61 public static void Cmge_V(ArmEmitterContext context) 62 { 63 if (Optimizations.UseSse42) 64 { 65 OpCodeSimd op = (OpCodeSimd)context.CurrOp; 66 67 Operand n = GetVec(op.Rn); 68 Operand m; 69 70 if (op is OpCodeSimdReg binOp) 71 { 72 m = GetVec(binOp.Rm); 73 } 74 else 75 { 76 m = context.VectorZero(); 77 } 78 79 Intrinsic cmpInst = X86PcmpgtInstruction[op.Size]; 80 81 Operand res = context.AddIntrinsic(cmpInst, m, n); 82 83 Operand mask = X86GetAllElements(context, -1L); 84 85 res = context.AddIntrinsic(Intrinsic.X86Pandn, res, mask); 86 87 if (op.RegisterSize == RegisterSize.Simd64) 88 { 89 res = context.VectorZeroUpper64(res); 90 } 91 92 context.Copy(GetVec(op.Rd), res); 93 } 94 else 95 { 96 EmitCmpOp(context, (op1, op2) => context.ICompareGreaterOrEqual(op1, op2), scalar: false); 97 } 98 } 99 100 public static void Cmgt_S(ArmEmitterContext context) 101 { 102 EmitCmpOp(context, (op1, op2) => context.ICompareGreater(op1, op2), scalar: true); 103 } 104 105 public static void Cmgt_V(ArmEmitterContext context) 106 { 107 if (Optimizations.UseSse42) 108 { 109 OpCodeSimd op = (OpCodeSimd)context.CurrOp; 110 111 Operand n = GetVec(op.Rn); 112 Operand m; 113 114 if (op is OpCodeSimdReg binOp) 115 { 116 m = GetVec(binOp.Rm); 117 } 118 else 119 { 120 m = context.VectorZero(); 121 } 122 123 Intrinsic cmpInst = X86PcmpgtInstruction[op.Size]; 124 125 Operand res = context.AddIntrinsic(cmpInst, n, m); 126 127 if (op.RegisterSize == RegisterSize.Simd64) 128 { 129 res = context.VectorZeroUpper64(res); 130 } 131 132 context.Copy(GetVec(op.Rd), res); 133 } 134 else 135 { 136 EmitCmpOp(context, (op1, op2) => context.ICompareGreater(op1, op2), scalar: false); 137 } 138 } 139 140 public static void Cmhi_S(ArmEmitterContext context) 141 { 142 EmitCmpOp(context, (op1, op2) => context.ICompareGreaterUI(op1, op2), scalar: true); 143 } 144 145 public static void Cmhi_V(ArmEmitterContext context) 146 { 147 OpCodeSimdReg op = (OpCodeSimdReg)context.CurrOp; 148 149 if (Optimizations.UseSse41 && op.Size < 3) 150 { 151 Operand n = GetVec(op.Rn); 152 Operand m = GetVec(op.Rm); 153 154 Intrinsic maxInst = X86PmaxuInstruction[op.Size]; 155 156 Operand res = context.AddIntrinsic(maxInst, m, n); 157 158 Intrinsic cmpInst = X86PcmpeqInstruction[op.Size]; 159 160 res = context.AddIntrinsic(cmpInst, res, m); 161 162 Operand mask = X86GetAllElements(context, -1L); 163 164 res = context.AddIntrinsic(Intrinsic.X86Pandn, res, mask); 165 166 if (op.RegisterSize == RegisterSize.Simd64) 167 { 168 res = context.VectorZeroUpper64(res); 169 } 170 171 context.Copy(GetVec(op.Rd), res); 172 } 173 else 174 { 175 EmitCmpOp(context, (op1, op2) => context.ICompareGreaterUI(op1, op2), scalar: false); 176 } 177 } 178 179 public static void Cmhs_S(ArmEmitterContext context) 180 { 181 EmitCmpOp(context, (op1, op2) => context.ICompareGreaterOrEqualUI(op1, op2), scalar: true); 182 } 183 184 public static void Cmhs_V(ArmEmitterContext context) 185 { 186 OpCodeSimdReg op = (OpCodeSimdReg)context.CurrOp; 187 188 if (Optimizations.UseSse41 && op.Size < 3) 189 { 190 Operand n = GetVec(op.Rn); 191 Operand m = GetVec(op.Rm); 192 193 Intrinsic maxInst = X86PmaxuInstruction[op.Size]; 194 195 Operand res = context.AddIntrinsic(maxInst, n, m); 196 197 Intrinsic cmpInst = X86PcmpeqInstruction[op.Size]; 198 199 res = context.AddIntrinsic(cmpInst, res, n); 200 201 if (op.RegisterSize == RegisterSize.Simd64) 202 { 203 res = context.VectorZeroUpper64(res); 204 } 205 206 context.Copy(GetVec(op.Rd), res); 207 } 208 else 209 { 210 EmitCmpOp(context, (op1, op2) => context.ICompareGreaterOrEqualUI(op1, op2), scalar: false); 211 } 212 } 213 214 public static void Cmle_S(ArmEmitterContext context) 215 { 216 EmitCmpOp(context, (op1, op2) => context.ICompareLessOrEqual(op1, op2), scalar: true); 217 } 218 219 public static void Cmle_V(ArmEmitterContext context) 220 { 221 if (Optimizations.UseSse42) 222 { 223 OpCodeSimd op = (OpCodeSimd)context.CurrOp; 224 225 Operand n = GetVec(op.Rn); 226 227 Intrinsic cmpInst = X86PcmpgtInstruction[op.Size]; 228 229 Operand res = context.AddIntrinsic(cmpInst, n, context.VectorZero()); 230 231 Operand mask = X86GetAllElements(context, -1L); 232 233 res = context.AddIntrinsic(Intrinsic.X86Pandn, res, mask); 234 235 if (op.RegisterSize == RegisterSize.Simd64) 236 { 237 res = context.VectorZeroUpper64(res); 238 } 239 240 context.Copy(GetVec(op.Rd), res); 241 } 242 else 243 { 244 EmitCmpOp(context, (op1, op2) => context.ICompareLessOrEqual(op1, op2), scalar: false); 245 } 246 } 247 248 public static void Cmlt_S(ArmEmitterContext context) 249 { 250 EmitCmpOp(context, (op1, op2) => context.ICompareLess(op1, op2), scalar: true); 251 } 252 253 public static void Cmlt_V(ArmEmitterContext context) 254 { 255 if (Optimizations.UseSse42) 256 { 257 OpCodeSimd op = (OpCodeSimd)context.CurrOp; 258 259 Operand n = GetVec(op.Rn); 260 261 Intrinsic cmpInst = X86PcmpgtInstruction[op.Size]; 262 263 Operand res = context.AddIntrinsic(cmpInst, context.VectorZero(), n); 264 265 if (op.RegisterSize == RegisterSize.Simd64) 266 { 267 res = context.VectorZeroUpper64(res); 268 } 269 270 context.Copy(GetVec(op.Rd), res); 271 } 272 else 273 { 274 EmitCmpOp(context, (op1, op2) => context.ICompareLess(op1, op2), scalar: false); 275 } 276 } 277 278 public static void Cmtst_S(ArmEmitterContext context) 279 { 280 EmitCmtstOp(context, scalar: true); 281 } 282 283 public static void Cmtst_V(ArmEmitterContext context) 284 { 285 EmitCmtstOp(context, scalar: false); 286 } 287 288 public static void Facge_S(ArmEmitterContext context) 289 { 290 if (Optimizations.FastFP && Optimizations.UseAvx) 291 { 292 EmitSse2OrAvxCmpOpF(context, CmpCondition.GreaterThanOrEqual, scalar: true, absolute: true); 293 } 294 else 295 { 296 EmitCmpOpF(context, nameof(SoftFloat32.FPCompareGE), scalar: true, absolute: true); 297 } 298 } 299 300 public static void Facge_V(ArmEmitterContext context) 301 { 302 if (Optimizations.FastFP && Optimizations.UseAvx) 303 { 304 EmitSse2OrAvxCmpOpF(context, CmpCondition.GreaterThanOrEqual, scalar: false, absolute: true); 305 } 306 else 307 { 308 EmitCmpOpF(context, nameof(SoftFloat32.FPCompareGE), scalar: false, absolute: true); 309 } 310 } 311 312 public static void Facgt_S(ArmEmitterContext context) 313 { 314 if (Optimizations.FastFP && Optimizations.UseAvx) 315 { 316 EmitSse2OrAvxCmpOpF(context, CmpCondition.GreaterThan, scalar: true, absolute: true); 317 } 318 else 319 { 320 EmitCmpOpF(context, nameof(SoftFloat32.FPCompareGT), scalar: true, absolute: true); 321 } 322 } 323 324 public static void Facgt_V(ArmEmitterContext context) 325 { 326 if (Optimizations.FastFP && Optimizations.UseAvx) 327 { 328 EmitSse2OrAvxCmpOpF(context, CmpCondition.GreaterThan, scalar: false, absolute: true); 329 } 330 else 331 { 332 EmitCmpOpF(context, nameof(SoftFloat32.FPCompareGT), scalar: false, absolute: true); 333 } 334 } 335 336 public static void Fccmp_S(ArmEmitterContext context) 337 { 338 EmitFccmpOrFccmpe(context, signalNaNs: false); 339 } 340 341 public static void Fccmpe_S(ArmEmitterContext context) 342 { 343 EmitFccmpOrFccmpe(context, signalNaNs: true); 344 } 345 346 public static void Fcmeq_S(ArmEmitterContext context) 347 { 348 if (Optimizations.FastFP && Optimizations.UseSse2) 349 { 350 EmitSse2OrAvxCmpOpF(context, CmpCondition.Equal, scalar: true); 351 } 352 else 353 { 354 EmitCmpOpF(context, nameof(SoftFloat32.FPCompareEQ), scalar: true); 355 } 356 } 357 358 public static void Fcmeq_V(ArmEmitterContext context) 359 { 360 if (Optimizations.FastFP && Optimizations.UseSse2) 361 { 362 EmitSse2OrAvxCmpOpF(context, CmpCondition.Equal, scalar: false); 363 } 364 else 365 { 366 EmitCmpOpF(context, nameof(SoftFloat32.FPCompareEQ), scalar: false); 367 } 368 } 369 370 public static void Fcmge_S(ArmEmitterContext context) 371 { 372 if (Optimizations.FastFP && Optimizations.UseAvx) 373 { 374 EmitSse2OrAvxCmpOpF(context, CmpCondition.GreaterThanOrEqual, scalar: true); 375 } 376 else 377 { 378 EmitCmpOpF(context, nameof(SoftFloat32.FPCompareGE), scalar: true); 379 } 380 } 381 382 public static void Fcmge_V(ArmEmitterContext context) 383 { 384 if (Optimizations.FastFP && Optimizations.UseAvx) 385 { 386 EmitSse2OrAvxCmpOpF(context, CmpCondition.GreaterThanOrEqual, scalar: false); 387 } 388 else 389 { 390 EmitCmpOpF(context, nameof(SoftFloat32.FPCompareGE), scalar: false); 391 } 392 } 393 394 public static void Fcmgt_S(ArmEmitterContext context) 395 { 396 if (Optimizations.FastFP && Optimizations.UseAvx) 397 { 398 EmitSse2OrAvxCmpOpF(context, CmpCondition.GreaterThan, scalar: true); 399 } 400 else 401 { 402 EmitCmpOpF(context, nameof(SoftFloat32.FPCompareGT), scalar: true); 403 } 404 } 405 406 public static void Fcmgt_V(ArmEmitterContext context) 407 { 408 if (Optimizations.FastFP && Optimizations.UseAvx) 409 { 410 EmitSse2OrAvxCmpOpF(context, CmpCondition.GreaterThan, scalar: false); 411 } 412 else 413 { 414 EmitCmpOpF(context, nameof(SoftFloat32.FPCompareGT), scalar: false); 415 } 416 } 417 418 public static void Fcmle_S(ArmEmitterContext context) 419 { 420 if (Optimizations.FastFP && Optimizations.UseSse2) 421 { 422 EmitSse2OrAvxCmpOpF(context, CmpCondition.LessThanOrEqual, scalar: true); 423 } 424 else 425 { 426 EmitCmpOpF(context, nameof(SoftFloat32.FPCompareLE), scalar: true); 427 } 428 } 429 430 public static void Fcmle_V(ArmEmitterContext context) 431 { 432 if (Optimizations.FastFP && Optimizations.UseSse2) 433 { 434 EmitSse2OrAvxCmpOpF(context, CmpCondition.LessThanOrEqual, scalar: false); 435 } 436 else 437 { 438 EmitCmpOpF(context, nameof(SoftFloat32.FPCompareLE), scalar: false); 439 } 440 } 441 442 public static void Fcmlt_S(ArmEmitterContext context) 443 { 444 if (Optimizations.FastFP && Optimizations.UseSse2) 445 { 446 EmitSse2OrAvxCmpOpF(context, CmpCondition.LessThan, scalar: true); 447 } 448 else 449 { 450 EmitCmpOpF(context, nameof(SoftFloat32.FPCompareLT), scalar: true); 451 } 452 } 453 454 public static void Fcmlt_V(ArmEmitterContext context) 455 { 456 if (Optimizations.FastFP && Optimizations.UseSse2) 457 { 458 EmitSse2OrAvxCmpOpF(context, CmpCondition.LessThan, scalar: false); 459 } 460 else 461 { 462 EmitCmpOpF(context, nameof(SoftFloat32.FPCompareLT), scalar: false); 463 } 464 } 465 466 public static void Fcmp_S(ArmEmitterContext context) 467 { 468 if (Optimizations.UseAdvSimd) 469 { 470 InstEmitSimdHelperArm64.EmitFcmpOrFcmpe(context, signalNaNs: false); 471 } 472 else 473 { 474 EmitFcmpOrFcmpe(context, signalNaNs: false); 475 } 476 } 477 478 public static void Fcmpe_S(ArmEmitterContext context) 479 { 480 if (Optimizations.UseAdvSimd) 481 { 482 InstEmitSimdHelperArm64.EmitFcmpOrFcmpe(context, signalNaNs: true); 483 } 484 else 485 { 486 EmitFcmpOrFcmpe(context, signalNaNs: true); 487 } 488 } 489 490 private static void EmitFccmpOrFccmpe(ArmEmitterContext context, bool signalNaNs) 491 { 492 OpCodeSimdFcond op = (OpCodeSimdFcond)context.CurrOp; 493 494 Operand lblTrue = Label(); 495 Operand lblEnd = Label(); 496 497 context.BranchIfTrue(lblTrue, InstEmitFlowHelper.GetCondTrue(context, op.Cond)); 498 499 EmitSetNzcv(context, op.Nzcv); 500 501 context.Branch(lblEnd); 502 503 context.MarkLabel(lblTrue); 504 505 EmitFcmpOrFcmpe(context, signalNaNs); 506 507 context.MarkLabel(lblEnd); 508 } 509 510 private static void EmitSetNzcv(ArmEmitterContext context, int nzcv) 511 { 512 static Operand Extract(int value, int bit) 513 { 514 if (bit != 0) 515 { 516 value >>= bit; 517 } 518 519 value &= 1; 520 521 return Const(value); 522 } 523 524 SetFlag(context, PState.VFlag, Extract(nzcv, 0)); 525 SetFlag(context, PState.CFlag, Extract(nzcv, 1)); 526 SetFlag(context, PState.ZFlag, Extract(nzcv, 2)); 527 SetFlag(context, PState.NFlag, Extract(nzcv, 3)); 528 } 529 530 private static void EmitFcmpOrFcmpe(ArmEmitterContext context, bool signalNaNs) 531 { 532 OpCodeSimdReg op = (OpCodeSimdReg)context.CurrOp; 533 534 bool cmpWithZero = op is not OpCodeSimdFcond && op.Bit3; 535 536 if (Optimizations.FastFP && (signalNaNs ? Optimizations.UseAvx : Optimizations.UseSse2)) 537 { 538 Operand n = GetVec(op.Rn); 539 Operand m = cmpWithZero ? context.VectorZero() : GetVec(op.Rm); 540 541 CmpCondition cmpOrdered = signalNaNs ? CmpCondition.OrderedS : CmpCondition.OrderedQ; 542 543 Operand lblNaN = Label(); 544 Operand lblEnd = Label(); 545 546 if (op.Size == 0) 547 { 548 Operand ordMask = context.AddIntrinsic(Intrinsic.X86Cmpss, n, m, Const((int)cmpOrdered)); 549 550 Operand isOrdered = context.AddIntrinsicInt(Intrinsic.X86Cvtsi2si, ordMask); 551 552 context.BranchIfFalse(lblNaN, isOrdered); 553 554 Operand nCopy = context.Copy(n); 555 Operand mCopy = cmpWithZero ? context.VectorZero() : context.Copy(m); 556 557 Operand cf = context.AddIntrinsicInt(Intrinsic.X86Comissge, nCopy, mCopy); 558 Operand zf = context.AddIntrinsicInt(Intrinsic.X86Comisseq, nCopy, mCopy); 559 Operand nf = context.AddIntrinsicInt(Intrinsic.X86Comisslt, nCopy, mCopy); 560 561 SetFlag(context, PState.VFlag, Const(0)); 562 SetFlag(context, PState.CFlag, cf); 563 SetFlag(context, PState.ZFlag, zf); 564 SetFlag(context, PState.NFlag, nf); 565 } 566 else /* if (op.Size == 1) */ 567 { 568 Operand ordMask = context.AddIntrinsic(Intrinsic.X86Cmpsd, n, m, Const((int)cmpOrdered)); 569 570 Operand isOrdered = context.AddIntrinsicLong(Intrinsic.X86Cvtsi2si, ordMask); 571 572 context.BranchIfFalse(lblNaN, isOrdered); 573 574 Operand nCopy = context.Copy(n); 575 Operand mCopy = cmpWithZero ? context.VectorZero() : context.Copy(m); 576 577 Operand cf = context.AddIntrinsicInt(Intrinsic.X86Comisdge, nCopy, mCopy); 578 Operand zf = context.AddIntrinsicInt(Intrinsic.X86Comisdeq, nCopy, mCopy); 579 Operand nf = context.AddIntrinsicInt(Intrinsic.X86Comisdlt, nCopy, mCopy); 580 581 SetFlag(context, PState.VFlag, Const(0)); 582 SetFlag(context, PState.CFlag, cf); 583 SetFlag(context, PState.ZFlag, zf); 584 SetFlag(context, PState.NFlag, nf); 585 } 586 587 context.Branch(lblEnd); 588 589 context.MarkLabel(lblNaN); 590 591 SetFlag(context, PState.VFlag, Const(1)); 592 SetFlag(context, PState.CFlag, Const(1)); 593 SetFlag(context, PState.ZFlag, Const(0)); 594 SetFlag(context, PState.NFlag, Const(0)); 595 596 context.MarkLabel(lblEnd); 597 } 598 else 599 { 600 OperandType type = op.Size != 0 ? OperandType.FP64 : OperandType.FP32; 601 602 Operand ne = context.VectorExtract(type, GetVec(op.Rn), 0); 603 Operand me; 604 605 if (cmpWithZero) 606 { 607 me = op.Size == 0 ? ConstF(0f) : ConstF(0d); 608 } 609 else 610 { 611 me = context.VectorExtract(type, GetVec(op.Rm), 0); 612 } 613 614 Operand nzcv = EmitSoftFloatCall(context, nameof(SoftFloat32.FPCompare), ne, me, Const(signalNaNs)); 615 616 EmitSetNzcv(context, nzcv); 617 } 618 } 619 620 private static void EmitSetNzcv(ArmEmitterContext context, Operand nzcv) 621 { 622 Operand Extract(Operand value, int bit) 623 { 624 if (bit != 0) 625 { 626 value = context.ShiftRightUI(value, Const(bit)); 627 } 628 629 value = context.BitwiseAnd(value, Const(1)); 630 631 return value; 632 } 633 634 SetFlag(context, PState.VFlag, Extract(nzcv, 0)); 635 SetFlag(context, PState.CFlag, Extract(nzcv, 1)); 636 SetFlag(context, PState.ZFlag, Extract(nzcv, 2)); 637 SetFlag(context, PState.NFlag, Extract(nzcv, 3)); 638 } 639 640 private static void EmitCmpOp(ArmEmitterContext context, Func2I emitCmp, bool scalar) 641 { 642 OpCodeSimd op = (OpCodeSimd)context.CurrOp; 643 644 Operand res = context.VectorZero(); 645 646 int elems = !scalar ? op.GetBytesCount() >> op.Size : 1; 647 648 ulong szMask = ulong.MaxValue >> (64 - (8 << op.Size)); 649 650 for (int index = 0; index < elems; index++) 651 { 652 Operand ne = EmitVectorExtractSx(context, op.Rn, index, op.Size); 653 Operand me; 654 655 if (op is OpCodeSimdReg binOp) 656 { 657 me = EmitVectorExtractSx(context, binOp.Rm, index, op.Size); 658 } 659 else 660 { 661 me = Const(0L); 662 } 663 664 Operand isTrue = emitCmp(ne, me); 665 666 Operand mask = context.ConditionalSelect(isTrue, Const(szMask), Const(0L)); 667 668 res = EmitVectorInsert(context, res, mask, index, op.Size); 669 } 670 671 context.Copy(GetVec(op.Rd), res); 672 } 673 674 private static void EmitCmtstOp(ArmEmitterContext context, bool scalar) 675 { 676 OpCodeSimdReg op = (OpCodeSimdReg)context.CurrOp; 677 678 Operand res = context.VectorZero(); 679 680 int elems = !scalar ? op.GetBytesCount() >> op.Size : 1; 681 682 ulong szMask = ulong.MaxValue >> (64 - (8 << op.Size)); 683 684 for (int index = 0; index < elems; index++) 685 { 686 Operand ne = EmitVectorExtractZx(context, op.Rn, index, op.Size); 687 Operand me = EmitVectorExtractZx(context, op.Rm, index, op.Size); 688 689 Operand test = context.BitwiseAnd(ne, me); 690 691 Operand isTrue = context.ICompareNotEqual(test, Const(0L)); 692 693 Operand mask = context.ConditionalSelect(isTrue, Const(szMask), Const(0L)); 694 695 res = EmitVectorInsert(context, res, mask, index, op.Size); 696 } 697 698 context.Copy(GetVec(op.Rd), res); 699 } 700 701 private static void EmitCmpOpF(ArmEmitterContext context, string name, bool scalar, bool absolute = false) 702 { 703 OpCodeSimd op = (OpCodeSimd)context.CurrOp; 704 705 Operand res = context.VectorZero(); 706 707 int sizeF = op.Size & 1; 708 709 OperandType type = sizeF != 0 ? OperandType.FP64 : OperandType.FP32; 710 711 int elems = !scalar ? op.GetBytesCount() >> sizeF + 2 : 1; 712 713 for (int index = 0; index < elems; index++) 714 { 715 Operand ne = context.VectorExtract(type, GetVec(op.Rn), index); 716 Operand me; 717 718 if (op is OpCodeSimdReg binOp) 719 { 720 me = context.VectorExtract(type, GetVec(binOp.Rm), index); 721 } 722 else 723 { 724 me = sizeF == 0 ? ConstF(0f) : ConstF(0d); 725 } 726 727 if (absolute) 728 { 729 ne = EmitUnaryMathCall(context, nameof(Math.Abs), ne); 730 me = EmitUnaryMathCall(context, nameof(Math.Abs), me); 731 } 732 733 Operand e = EmitSoftFloatCall(context, name, ne, me); 734 735 res = context.VectorInsert(res, e, index); 736 } 737 738 context.Copy(GetVec(op.Rd), res); 739 } 740 741 private static void EmitSse2OrAvxCmpOpF(ArmEmitterContext context, CmpCondition cond, bool scalar, bool absolute = false) 742 { 743 OpCodeSimd op = (OpCodeSimd)context.CurrOp; 744 745 Operand n = GetVec(op.Rn); 746 Operand m = op is OpCodeSimdReg binOp ? GetVec(binOp.Rm) : context.VectorZero(); 747 748 int sizeF = op.Size & 1; 749 750 if (sizeF == 0) 751 { 752 if (absolute) 753 { 754 Operand mask = scalar ? X86GetScalar(context, int.MaxValue) : X86GetAllElements(context, int.MaxValue); 755 756 n = context.AddIntrinsic(Intrinsic.X86Andps, n, mask); 757 m = context.AddIntrinsic(Intrinsic.X86Andps, m, mask); 758 } 759 760 Intrinsic inst = scalar ? Intrinsic.X86Cmpss : Intrinsic.X86Cmpps; 761 762 Operand res = context.AddIntrinsic(inst, n, m, Const((int)cond)); 763 764 if (scalar) 765 { 766 res = context.VectorZeroUpper96(res); 767 } 768 else if (op.RegisterSize == RegisterSize.Simd64) 769 { 770 res = context.VectorZeroUpper64(res); 771 } 772 773 context.Copy(GetVec(op.Rd), res); 774 } 775 else /* if (sizeF == 1) */ 776 { 777 if (absolute) 778 { 779 Operand mask = scalar ? X86GetScalar(context, long.MaxValue) : X86GetAllElements(context, long.MaxValue); 780 781 n = context.AddIntrinsic(Intrinsic.X86Andpd, n, mask); 782 m = context.AddIntrinsic(Intrinsic.X86Andpd, m, mask); 783 } 784 785 Intrinsic inst = scalar ? Intrinsic.X86Cmpsd : Intrinsic.X86Cmppd; 786 787 Operand res = context.AddIntrinsic(inst, n, m, Const((int)cond)); 788 789 if (scalar) 790 { 791 res = context.VectorZeroUpper64(res); 792 } 793 794 context.Copy(GetVec(op.Rd), res); 795 } 796 } 797 } 798 }