InstEmitSimdShift32.cs 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100
  1. using ARMeilleure.Decoders;
  2. using ARMeilleure.IntermediateRepresentation;
  3. using ARMeilleure.Translation;
  4. using System;
  5. using System.Diagnostics;
  6. using static ARMeilleure.Instructions.InstEmitSimdHelper32;
  7. using static ARMeilleure.IntermediateRepresentation.OperandHelper;
  8. namespace ARMeilleure.Instructions
  9. {
  10. static partial class InstEmit32
  11. {
  12. public static void Vshl(ArmEmitterContext context)
  13. {
  14. OpCode32SimdShImm op = (OpCode32SimdShImm)context.CurrOp;
  15. EmitVectorUnaryOpZx32(context, (op1) => context.ShiftLeft(op1, Const(op.Shift)));
  16. }
  17. public static void Vshl_I(ArmEmitterContext context)
  18. {
  19. OpCode32SimdReg op = (OpCode32SimdReg)context.CurrOp;
  20. if (op.U)
  21. {
  22. EmitVectorBinaryOpZx32(context, (op1, op2) => EmitShlRegOp(context, op2, op1, op.Size, true));
  23. }
  24. else
  25. {
  26. EmitVectorBinaryOpSx32(context, (op1, op2) => EmitShlRegOp(context, op2, op1, op.Size, false));
  27. }
  28. }
  29. public static void Vshr(ArmEmitterContext context)
  30. {
  31. OpCode32SimdShImm op = (OpCode32SimdShImm)context.CurrOp;
  32. int shift = (8 << op.Size) - op.Shift; // Shr amount is flipped.
  33. int maxShift = (8 << op.Size) - 1;
  34. if (op.U)
  35. {
  36. EmitVectorUnaryOpZx32(context, (op1) => (shift > maxShift) ? Const(op1.Type, 0) : context.ShiftRightUI(op1, Const(shift)));
  37. }
  38. else
  39. {
  40. EmitVectorUnaryOpSx32(context, (op1) => context.ShiftRightSI(op1, Const(Math.Min(maxShift, shift))));
  41. }
  42. }
  43. public static void Vshrn(ArmEmitterContext context)
  44. {
  45. OpCode32SimdShImm op = (OpCode32SimdShImm)context.CurrOp;
  46. int shift = (8 << op.Size) - op.Shift; // Shr amount is flipped.
  47. EmitVectorUnaryNarrowOp32(context, (op1) => context.ShiftRightUI(op1, Const(shift)));
  48. }
  49. private static Operand EmitShlRegOp(ArmEmitterContext context, Operand op, Operand shiftLsB, int size, bool unsigned)
  50. {
  51. if (shiftLsB.Type == OperandType.I64)
  52. {
  53. shiftLsB = context.ConvertI64ToI32(shiftLsB);
  54. }
  55. shiftLsB = context.SignExtend8(OperandType.I32, shiftLsB);
  56. Debug.Assert((uint)size < 4u);
  57. Operand negShiftLsB = context.Negate(shiftLsB);
  58. Operand isPositive = context.ICompareGreaterOrEqual(shiftLsB, Const(0));
  59. Operand shl = context.ShiftLeft(op, shiftLsB);
  60. Operand shr = unsigned ? context.ShiftRightUI(op, negShiftLsB) : context.ShiftRightSI(op, negShiftLsB);
  61. Operand res = context.ConditionalSelect(isPositive, shl, shr);
  62. if (unsigned)
  63. {
  64. Operand isOutOfRange = context.BitwiseOr(
  65. context.ICompareGreaterOrEqual(shiftLsB, Const(8 << size)),
  66. context.ICompareGreaterOrEqual(negShiftLsB, Const(8 << size)));
  67. return context.ConditionalSelect(isOutOfRange, Const(op.Type, 0), res);
  68. }
  69. else
  70. {
  71. Operand isOutOfRange0 = context.ICompareGreaterOrEqual(shiftLsB, Const(8 << size));
  72. Operand isOutOfRangeN = context.ICompareGreaterOrEqual(negShiftLsB, Const(8 << size));
  73. // Also zero if shift is too negative, but value was positive.
  74. isOutOfRange0 = context.BitwiseOr(isOutOfRange0, context.BitwiseAnd(isOutOfRangeN, context.ICompareGreaterOrEqual(op, Const(op.Type, 0))));
  75. Operand min = (op.Type == OperandType.I64) ? Const(-1L) : Const(-1);
  76. return context.ConditionalSelect(isOutOfRange0, Const(op.Type, 0), context.ConditionalSelect(isOutOfRangeN, min, res));
  77. }
  78. }
  79. }
  80. }