Add SMULL (vector), USHR (scalar), FCCMPE, FNMSUB, fixed a some instructions

This commit is contained in:
gdkchan 2018-02-20 14:39:03 -03:00
parent 01b7538560
commit b4a1cfde10
10 changed files with 205 additions and 130 deletions

View file

@ -47,6 +47,7 @@ namespace ChocolArm64
Set("x1011010100xxxxxxxxx01xxxxxxxxxx", AInstEmit.Csneg, typeof(AOpCodeCsel));
Set("11010101000000110011xxxx10111111", AInstEmit.Dmb, typeof(AOpCodeSystem));
Set("11010101000000110011xxxx10011111", AInstEmit.Dsb, typeof(AOpCodeSystem));
Set("x1001010xx1xxxxxxxxxxxxxxxxxxxxx", AInstEmit.Eon, typeof(AOpCodeAluRs));
Set("x10100100xxxxxxxxxxxxxxxxxxxxxxx", AInstEmit.Eor, typeof(AOpCodeAluImm));
Set("x1001010xx0xxxxxxxxxxxxxxxxxxxxx", AInstEmit.Eor, typeof(AOpCodeAluRs));
Set("x00100111x0xxxxxxxxxxxxxxxxxxxxx", AInstEmit.Extr, typeof(AOpCodeAluRs));
@ -147,6 +148,7 @@ namespace ChocolArm64
Set("00011110xx1xxxxx001010xxxxxxxxxx", AInstEmit.Fadd_S, typeof(AOpCodeSimdReg));
Set("0x0011100x1xxxxx110101xxxxxxxxxx", AInstEmit.Fadd_V, typeof(AOpCodeSimdReg));
Set("00011110xx1xxxxxxxxx01xxxxx0xxxx", AInstEmit.Fccmp_S, typeof(AOpCodeSimdFcond));
Set("00011110xx1xxxxxxxxx01xxxxx1xxxx", AInstEmit.Fccmpe_S, typeof(AOpCodeSimdFcond));
Set("00011110xx1xxxxx001000xxxxx0x000", AInstEmit.Fcmp_S, typeof(AOpCodeSimdReg));
Set("00011110xx1xxxxx001000xxxxx1x000", AInstEmit.Fcmpe_S, typeof(AOpCodeSimdReg));
Set("00011110xx1xxxxxxxxx11xxxxxxxxxx", AInstEmit.Fcsel_S, typeof(AOpCodeSimdFcond));
@ -183,6 +185,7 @@ namespace ChocolArm64
Set("0x1011100x1xxxxx110111xxxxxxxxxx", AInstEmit.Fmul_V, typeof(AOpCodeSimdReg));
Set("0x0011111<<xxxxx1001x0xxxxxxxxxx", AInstEmit.Fmul_Ve, typeof(AOpCodeSimdRegElem));
Set("00011110xx100001010000xxxxxxxxxx", AInstEmit.Fneg_S, typeof(AOpCodeSimdReg));
Set("00011111xx1xxxxx1xxxxxxxxxxxxxxx", AInstEmit.Fnmsub_S, typeof(AOpCodeSimdReg));
Set("00011110xx1xxxxx100010xxxxxxxxxx", AInstEmit.Fnmul_S, typeof(AOpCodeSimdReg));
Set("00011110xx100110010000xxxxxxxxxx", AInstEmit.Frinta_S, typeof(AOpCodeSimd));
Set("00011110xx100101010000xxxxxxxxxx", AInstEmit.Frintm_S, typeof(AOpCodeSimd));
@ -225,6 +228,7 @@ namespace ChocolArm64
Set("0x00111100>>>xxx100001xxxxxxxxxx", AInstEmit.Shrn_V, typeof(AOpCodeSimdShImm));
Set("0x001110<<1xxxxx011001xxxxxxxxxx", AInstEmit.Smax_V, typeof(AOpCodeSimdReg));
Set("0x001110<<1xxxxx011011xxxxxxxxxx", AInstEmit.Smin_V, typeof(AOpCodeSimdReg));
Set("0x001110<<1xxxxx110000xxxxxxxxxx", AInstEmit.Smull_V, typeof(AOpCodeSimdReg));
Set("0>001110<<1xxxxx010001xxxxxxxxxx", AInstEmit.Sshl_V, typeof(AOpCodeSimdReg));
Set("0x00111100>>>xxx101001xxxxxxxxxx", AInstEmit.Sshll_V, typeof(AOpCodeSimdShImm));
Set("010111110>>>>xxx000001xxxxxxxxxx", AInstEmit.Sshr_S, typeof(AOpCodeSimdShImm));
@ -251,6 +255,7 @@ namespace ChocolArm64
Set("0x001110000xxxxx001111xxxxxxxxxx", AInstEmit.Umov_S, typeof(AOpCodeSimdIns));
Set("0>101110<<1xxxxx010001xxxxxxxxxx", AInstEmit.Ushl_V, typeof(AOpCodeSimdReg));
Set("0x10111100>>>xxx101001xxxxxxxxxx", AInstEmit.Ushll_V, typeof(AOpCodeSimdShImm));
Set("011111110>>>>xxx000001xxxxxxxxxx", AInstEmit.Ushr_S, typeof(AOpCodeSimdShImm));
Set("0x1011110>>>>xxx000001xxxxxxxxxx", AInstEmit.Ushr_V, typeof(AOpCodeSimdShImm));
Set("0x1011110>>>>xxx000101xxxxxxxxxx", AInstEmit.Usra_V, typeof(AOpCodeSimdShImm));
Set("0x001110xx0xxxxx000110xxxxxxxxxx", AInstEmit.Uzp1_V, typeof(AOpCodeSimdReg));

View file

@ -107,6 +107,16 @@ namespace ChocolArm64.Instruction
Context.EmitStintzr(Op.Rd);
}
public static void Eon(AILEmitterCtx Context)
{
EmitDataLoadOpers(Context);
Context.Emit(OpCodes.Not);
Context.Emit(OpCodes.Xor);
EmitDataStore(Context);
}
public static void Eor(AILEmitterCtx Context) => EmitDataOp(Context, OpCodes.Xor);
public static void Extr(AILEmitterCtx Context)

View file

@ -145,5 +145,24 @@ namespace ChocolArm64.Instruction
Context.EmitStint(Op.Rd);
}
}
public static void EmitSetNZCV(AILEmitterCtx Context, int NZCV)
{
Context.EmitLdc_I4((NZCV >> 0) & 1);
Context.EmitStflg((int)APState.VBit);
Context.EmitLdc_I4((NZCV >> 1) & 1);
Context.EmitStflg((int)APState.CBit);
Context.EmitLdc_I4((NZCV >> 2) & 1);
Context.EmitStflg((int)APState.ZBit);
Context.EmitLdc_I4((NZCV >> 3) & 1);
Context.EmitStflg((int)APState.NBit);
}
}
}

View file

@ -36,7 +36,7 @@ namespace ChocolArm64.Instruction
if (Op.Pos + 1 == BitsCount)
{
EmitBfmShift(Context, OpCodes.Shr);
EmitSbfmShift(Context);
}
else if (Op.Pos < Op.Shift)
{
@ -87,7 +87,7 @@ namespace ChocolArm64.Instruction
if (Op.Pos + 1 == Op.GetBitsCount())
{
EmitBfmShift(Context, OpCodes.Shr_Un);
EmitUbfmShift(Context);
}
else if (Op.Pos < Op.Shift)
{
@ -166,19 +166,28 @@ namespace ChocolArm64.Instruction
Context.EmitStintzr(Op.Rd);
}
private static void EmitBfmShift(AILEmitterCtx Context, OpCode ILOp)
private static void EmitSbfmShift(AILEmitterCtx Context)
{
EmitBfmShift(Context, true);
}
private static void EmitUbfmShift(AILEmitterCtx Context)
{
EmitBfmShift(Context, false);
}
private static void EmitBfmShift(AILEmitterCtx Context, bool Signed)
{
AOpCodeBfm Op = (AOpCodeBfm)Context.CurrOp;
if (Op.Shift > 0)
{
Context.EmitLdintzr(Op.Rn);
Context.EmitLdc_I4(Op.Shift);
Context.EmitLdintzr(Op.Rn);
Context.EmitLdc_I4(Op.Shift);
Context.Emit(ILOp);
Context.Emit(Signed
? OpCodes.Shr
: OpCodes.Shr_Un);
Context.EmitStintzr(Op.Rd);
}
Context.EmitStintzr(Op.Rd);
}
private static void EmitBfmLsl(AILEmitterCtx Context)

View file

@ -215,6 +215,24 @@ namespace ChocolArm64.Instruction
});
}
public static void Fnmsub_S(AILEmitterCtx Context)
{
AOpCodeSimdReg Op = (AOpCodeSimdReg)Context.CurrOp;
int SizeF = Op.Size & 1;
EmitVectorExtractF(Context, Op.Rn, 0, SizeF);
EmitVectorExtractF(Context, Op.Rm, 0, SizeF);
Context.Emit(OpCodes.Mul);
EmitVectorExtractF(Context, Op.Ra, 0, SizeF);
Context.Emit(OpCodes.Sub);
EmitScalarSetF(Context, Op.Rd, SizeF);
}
public static void Frinta_S(AILEmitterCtx Context)
{
AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp;
@ -282,7 +300,7 @@ namespace ChocolArm64.Instruction
public static void Saddw_V(AILEmitterCtx Context)
{
EmitVectorWidenBinaryOpSx(Context, () => Context.Emit(OpCodes.Add));
EmitVectorWidenRmBinaryOpSx(Context, () => Context.Emit(OpCodes.Add));
}
public static void Smax_V(AILEmitterCtx Context)
@ -303,6 +321,11 @@ namespace ChocolArm64.Instruction
EmitVectorBinaryOpSx(Context, () => Context.EmitCall(MthdInfo));
}
public static void Smull_V(AILEmitterCtx Context)
{
EmitVectorWidenRnRmBinaryOpSx(Context, () => Context.Emit(OpCodes.Mul));
}
public static void Sub_S(AILEmitterCtx Context)
{
EmitScalarBinaryOpZx(Context, () => Context.Emit(OpCodes.Sub));
@ -333,7 +356,7 @@ namespace ChocolArm64.Instruction
public static void Uaddw_V(AILEmitterCtx Context)
{
EmitVectorWidenBinaryOpZx(Context, () => Context.Emit(OpCodes.Add));
EmitVectorWidenRmBinaryOpZx(Context, () => Context.Emit(OpCodes.Add));
}
}
}

View file

@ -4,6 +4,7 @@ using ChocolArm64.Translation;
using System;
using System.Reflection.Emit;
using static ChocolArm64.Instruction.AInstEmitAluHelper;
using static ChocolArm64.Instruction.AInstEmitSimdHelper;
namespace ChocolArm64.Instruction
@ -54,24 +55,9 @@ namespace ChocolArm64.Instruction
Context.EmitCondBranch(LblTrue, Op.Cond);
//TODO: Share this logic with Ccmp.
Context.EmitLdc_I4((Op.NZCV >> 0) & 1);
EmitSetNZCV(Context, Op.NZCV);
Context.EmitStflg((int)APState.VBit);
Context.EmitLdc_I4((Op.NZCV >> 1) & 1);
Context.EmitStflg((int)APState.CBit);
Context.EmitLdc_I4((Op.NZCV >> 2) & 1);
Context.EmitStflg((int)APState.ZBit);
Context.EmitLdc_I4((Op.NZCV >> 3) & 1);
Context.EmitStflg((int)APState.NBit);
Context.Emit(OpCodes.Br_S, LblEnd);
Context.Emit(OpCodes.Br, LblEnd);
Context.MarkLabel(LblTrue);
@ -80,12 +66,35 @@ namespace ChocolArm64.Instruction
Context.MarkLabel(LblEnd);
}
public static void Fccmpe_S(AILEmitterCtx Context)
{
Fccmp_S(Context);
}
public static void Fcmp_S(AILEmitterCtx Context)
{
AOpCodeSimdReg Op = (AOpCodeSimdReg)Context.CurrOp;
bool CmpWithZero = !(Op is AOpCodeSimdFcond) ? Op.Bit3 : false;
//Handle NaN case. If any number is NaN, then NZCV = 0011.
if (CmpWithZero)
{
EmitNaNCheck(Context, Op.Rn);
}
else
{
EmitNaNCheck(Context, Op.Rn);
EmitNaNCheck(Context, Op.Rm);
Context.Emit(OpCodes.Or);
}
AILLabel LblNaN = new AILLabel();
AILLabel LblEnd = new AILLabel();
Context.Emit(OpCodes.Brtrue_S, LblNaN);
void EmitLoadOpers()
{
EmitVectorExtractF(Context, Op.Rn, 0, Op.Size);
@ -102,7 +111,7 @@ namespace ChocolArm64.Instruction
//Z = Rn == Rm
EmitLoadOpers();
Context.Emit(OpCodes.Ceq);
Context.Emit(OpCodes.Dup);
@ -123,30 +132,18 @@ namespace ChocolArm64.Instruction
Context.EmitStflg((int)APState.NBit);
//Handle NaN case. If any number is NaN, then NZCV = 0011.
AILLabel LblNotNaN = new AILLabel();
//V = 0
Context.EmitLdc_I4(0);
if (CmpWithZero)
{
EmitNaNCheck(Context, Op.Rn);
}
else
{
EmitNaNCheck(Context, Op.Rn);
EmitNaNCheck(Context, Op.Rm);
Context.Emit(OpCodes.Or);
}
Context.Emit(OpCodes.Brfalse_S, LblNotNaN);
Context.EmitLdc_I4(1);
Context.EmitLdc_I4(1);
Context.EmitStflg((int)APState.CBit);
Context.EmitStflg((int)APState.VBit);
Context.MarkLabel(LblNotNaN);
Context.Emit(OpCodes.Br_S, LblEnd);
Context.MarkLabel(LblNaN);
EmitSetNZCV(Context, 0b0011);
Context.MarkLabel(LblEnd);
}
public static void Fcmpe_S(AILEmitterCtx Context)

View file

@ -91,7 +91,7 @@ namespace ChocolArm64.Instruction
{
AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp;
EmitVectorExtractSx(Context, Op.Rd, 0, Op.Size + 2);
EmitVectorExtractSx(Context, Op.Rn, 0, Op.Size + 2);
EmitFloatCast(Context, Op.Size);

View file

@ -133,7 +133,7 @@ namespace ChocolArm64.Instruction
public static void EmitScalarOp(AILEmitterCtx Context, Action Emit, OperFlags Opers, bool Signed)
{
AOpCodeSimdReg Op = (AOpCodeSimdReg)Context.CurrOp;
AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp;
if (Opers.HasFlag(OperFlags.Rd))
{
@ -147,7 +147,7 @@ namespace ChocolArm64.Instruction
if (Opers.HasFlag(OperFlags.Rm))
{
EmitVectorExtract(Context, Op.Rm, 0, Op.Size, Signed);
EmitVectorExtract(Context, ((AOpCodeSimdReg)Op).Rm, 0, Op.Size, Signed);
}
Emit();
@ -383,17 +383,17 @@ namespace ChocolArm64.Instruction
}
}
public static void EmitVectorWidenBinaryOpSx(AILEmitterCtx Context, Action Emit)
public static void EmitVectorWidenRmBinaryOpSx(AILEmitterCtx Context, Action Emit)
{
EmitVectorWidenBinaryOp(Context, Emit, true);
EmitVectorWidenRmBinaryOp(Context, Emit, true);
}
public static void EmitVectorWidenBinaryOpZx(AILEmitterCtx Context, Action Emit)
public static void EmitVectorWidenRmBinaryOpZx(AILEmitterCtx Context, Action Emit)
{
EmitVectorWidenBinaryOp(Context, Emit, false);
EmitVectorWidenRmBinaryOp(Context, Emit, false);
}
public static void EmitVectorWidenBinaryOp(AILEmitterCtx Context, Action Emit, bool Signed)
public static void EmitVectorWidenRmBinaryOp(AILEmitterCtx Context, Action Emit, bool Signed)
{
AOpCodeSimdReg Op = (AOpCodeSimdReg)Context.CurrOp;
@ -415,6 +415,38 @@ namespace ChocolArm64.Instruction
Context.EmitStvec(Op.Rd);
}
public static void EmitVectorWidenRnRmBinaryOpSx(AILEmitterCtx Context, Action Emit)
{
EmitVectorWidenRnRmBinaryOp(Context, Emit, true);
}
public static void EmitVectorWidenRnRmBinaryOpZx(AILEmitterCtx Context, Action Emit)
{
EmitVectorWidenRnRmBinaryOp(Context, Emit, false);
}
public static void EmitVectorWidenRnRmBinaryOp(AILEmitterCtx Context, Action Emit, bool Signed)
{
AOpCodeSimdReg Op = (AOpCodeSimdReg)Context.CurrOp;
int Elems = 8 >> Op.Size;
int Part = Op.RegisterSize == ARegisterSize.SIMD128 ? Elems : 0;
for (int Index = 0; Index < Elems; Index++)
{
EmitVectorExtract(Context, Op.Rn, Part + Index, Op.Size, Signed);
EmitVectorExtract(Context, Op.Rm, Part + Index, Op.Size, Signed);
Emit();
EmitVectorInsertTmp(Context, Index, Op.Size + 1);
}
Context.EmitLdvectmp();
Context.EmitStvec(Op.Rd);
}
public static void EmitScalarSet(AILEmitterCtx Context, int Reg, int Size)
{
EmitVectorZeroAll(Context, Reg);

View file

@ -10,15 +10,6 @@ namespace ChocolArm64.Instruction
{
static partial class AInstEmit
{
[Flags]
private enum ShrFlags
{
None = 0,
Signed = 1 << 0,
Rounding = 1 << 1,
Accumulate = 1 << 2
}
public static void Shl_S(AILEmitterCtx Context)
{
AOpCodeSimdShImm Op = (AOpCodeSimdShImm)Context.CurrOp;
@ -100,14 +91,43 @@ namespace ChocolArm64.Instruction
EmitVectorShImmWidenBinaryZx(Context, () => Context.Emit(OpCodes.Shl), Shift);
}
public static void Ushr_S(AILEmitterCtx Context)
{
AOpCodeSimdShImm Op = (AOpCodeSimdShImm)Context.CurrOp;
EmitScalarUnaryOpZx(Context, () =>
{
Context.EmitLdc_I4(GetImmShr(Op));
Context.Emit(OpCodes.Shr_Un);
});
}
public static void Ushr_V(AILEmitterCtx Context)
{
EmitVectorShr(Context, ShrFlags.None);
AOpCodeSimdShImm Op = (AOpCodeSimdShImm)Context.CurrOp;
EmitVectorUnaryOpZx(Context, () =>
{
Context.EmitLdc_I4(GetImmShr(Op));
Context.Emit(OpCodes.Shr_Un);
});
}
public static void Usra_V(AILEmitterCtx Context)
{
EmitVectorShr(Context, ShrFlags.Accumulate);
AOpCodeSimdShImm Op = (AOpCodeSimdShImm)Context.CurrOp;
Action Emit = () =>
{
Context.EmitLdc_I4(GetImmShr(Op));
Context.Emit(OpCodes.Shr_Un);
Context.Emit(OpCodes.Add);
};
EmitVectorOp(Context, Emit, OperFlags.RdRn, Signed: false);
}
private static void EmitVectorShl(AILEmitterCtx Context, bool Signed)
@ -173,35 +193,6 @@ namespace ChocolArm64.Instruction
}
}
private static void EmitVectorShr(AILEmitterCtx Context, ShrFlags Flags)
{
AOpCodeSimdShImm Op = (AOpCodeSimdShImm)Context.CurrOp;
int Shift = (8 << (Op.Size + 1)) - Op.Imm;
if (Flags.HasFlag(ShrFlags.Accumulate))
{
Action Emit = () =>
{
Context.EmitLdc_I4(Shift);
Context.Emit(OpCodes.Shr_Un);
Context.Emit(OpCodes.Add);
};
EmitVectorOp(Context, Emit, OperFlags.RdRn, Signed: false);
}
else
{
EmitVectorUnaryOpZx(Context, () =>
{
Context.EmitLdc_I4(Shift);
Context.Emit(OpCodes.Shr_Un);
});
}
}
private static void EmitVectorShImmBinarySx(AILEmitterCtx Context, Action Emit, int Imm)
{
EmitVectorShImmBinaryOp(Context, Emit, Imm, true);

View file

@ -1,6 +1,7 @@
using ChocolArm64.State;
using ChocolArm64.Translation;
using System;
using System.Numerics;
using System.Runtime.CompilerServices;
namespace ChocolArm64.Instruction
@ -101,6 +102,8 @@ namespace ChocolArm64.Instruction
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static int SatF32ToS32(float Value)
{
if (float.IsNaN(Value)) return 0;
return Value > int.MaxValue ? int.MaxValue :
Value < int.MinValue ? int.MinValue : (int)Value;
}
@ -108,6 +111,8 @@ namespace ChocolArm64.Instruction
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static long SatF32ToS64(float Value)
{
if (float.IsNaN(Value)) return 0;
return Value > long.MaxValue ? long.MaxValue :
Value < long.MinValue ? long.MinValue : (long)Value;
}
@ -115,6 +120,8 @@ namespace ChocolArm64.Instruction
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static uint SatF32ToU32(float Value)
{
if (float.IsNaN(Value)) return 0;
return Value > uint.MaxValue ? uint.MaxValue :
Value < uint.MinValue ? uint.MinValue : (uint)Value;
}
@ -122,6 +129,8 @@ namespace ChocolArm64.Instruction
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static ulong SatF32ToU64(float Value)
{
if (float.IsNaN(Value)) return 0;
return Value > ulong.MaxValue ? ulong.MaxValue :
Value < ulong.MinValue ? ulong.MinValue : (ulong)Value;
}
@ -129,6 +138,8 @@ namespace ChocolArm64.Instruction
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static int SatF64ToS32(double Value)
{
if (double.IsNaN(Value)) return 0;
return Value > int.MaxValue ? int.MaxValue :
Value < int.MinValue ? int.MinValue : (int)Value;
}
@ -136,6 +147,8 @@ namespace ChocolArm64.Instruction
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static long SatF64ToS64(double Value)
{
if (double.IsNaN(Value)) return 0;
return Value > long.MaxValue ? long.MaxValue :
Value < long.MinValue ? long.MinValue : (long)Value;
}
@ -143,6 +156,8 @@ namespace ChocolArm64.Instruction
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static uint SatF64ToU32(double Value)
{
if (double.IsNaN(Value)) return 0;
return Value > uint.MaxValue ? uint.MaxValue :
Value < uint.MinValue ? uint.MinValue : (uint)Value;
}
@ -150,46 +165,20 @@ namespace ChocolArm64.Instruction
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static ulong SatF64ToU64(double Value)
{
if (double.IsNaN(Value)) return 0;
return Value > ulong.MaxValue ? ulong.MaxValue :
Value < ulong.MinValue ? ulong.MinValue : (ulong)Value;
}
public static ulong SMulHi128(ulong LHS, ulong RHS)
public static long SMulHi128(long LHS, long RHS)
{
long LLo = (uint)(LHS >> 0);
long LHi = (int)(LHS >> 32);
long RLo = (uint)(RHS >> 0);
long RHi = (int)(RHS >> 32);
long LHiRHi = LHi * RHi;
long LHiRLo = LHi * RLo;
long LLoRHi = LLo * RHi;
long LLoRLo = LLo * RLo;
long Carry = ((uint)LHiRLo + ((uint)LLoRHi + (LLoRLo >> 32))) >> 32;
long ResHi = LHiRHi + (LHiRLo >> 32) + (LLoRHi >> 32) + Carry;
return (ulong)ResHi;
return (long)(BigInteger.Multiply(LHS, RHS) >> 64);
}
public static ulong UMulHi128(ulong LHS, ulong RHS)
{
ulong LLo = (uint)(LHS >> 0);
ulong LHi = (uint)(LHS >> 32);
ulong RLo = (uint)(RHS >> 0);
ulong RHi = (uint)(RHS >> 32);
ulong LHiRHi = LHi * RHi;
ulong LHiRLo = LHi * RLo;
ulong LLoRHi = LLo * RHi;
ulong LLoRLo = LLo * RLo;
ulong Carry = ((uint)LHiRLo + ((uint)LLoRHi + (LLoRLo >> 32))) >> 32;
ulong ResHi = LHiRHi + (LHiRLo >> 32) + (LLoRHi >> 32) + Carry;
return ResHi;
return (ulong)(BigInteger.Multiply(LHS, RHS) >> 64);
}
public static int CountSetBits8(byte Value)