Implement FP & SIMD comparison instructions, and some fixes
This commit is contained in:
parent
bb3ccccd3c
commit
ca3a73dd4e
12 changed files with 914 additions and 124 deletions
|
@ -77,6 +77,10 @@ namespace ARMeilleure.CodeGen.X86
|
||||||
Add(X86Instruction.Cmp, new InstInfo(0x00000039, 0x07000083, 0x07000081, BadOp, 0x0000003b, InstFlags.None));
|
Add(X86Instruction.Cmp, new InstInfo(0x00000039, 0x07000083, 0x07000081, BadOp, 0x0000003b, InstFlags.None));
|
||||||
Add(X86Instruction.Cmppd, new InstInfo(BadOp, BadOp, BadOp, BadOp, 0x00000fc2, InstFlags.Vex | InstFlags.Prefix66));
|
Add(X86Instruction.Cmppd, new InstInfo(BadOp, BadOp, BadOp, BadOp, 0x00000fc2, InstFlags.Vex | InstFlags.Prefix66));
|
||||||
Add(X86Instruction.Cmpps, new InstInfo(BadOp, BadOp, BadOp, BadOp, 0x00000fc2, InstFlags.Vex));
|
Add(X86Instruction.Cmpps, new InstInfo(BadOp, BadOp, BadOp, BadOp, 0x00000fc2, InstFlags.Vex));
|
||||||
|
Add(X86Instruction.Cmpsd, new InstInfo(BadOp, BadOp, BadOp, BadOp, 0x00000fc2, InstFlags.Vex | InstFlags.PrefixF2));
|
||||||
|
Add(X86Instruction.Cmpss, new InstInfo(BadOp, BadOp, BadOp, BadOp, 0x00000fc2, InstFlags.Vex | InstFlags.PrefixF3));
|
||||||
|
Add(X86Instruction.Comisd, new InstInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f2f, InstFlags.Vex | InstFlags.Prefix66));
|
||||||
|
Add(X86Instruction.Comiss, new InstInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f2f, InstFlags.Vex));
|
||||||
Add(X86Instruction.Cvtdq2pd, new InstInfo(BadOp, BadOp, BadOp, BadOp, 0x00000fe6, InstFlags.Vex | InstFlags.PrefixF3));
|
Add(X86Instruction.Cvtdq2pd, new InstInfo(BadOp, BadOp, BadOp, BadOp, 0x00000fe6, InstFlags.Vex | InstFlags.PrefixF3));
|
||||||
Add(X86Instruction.Cvtdq2ps, new InstInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f5b, InstFlags.Vex));
|
Add(X86Instruction.Cvtdq2ps, new InstInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f5b, InstFlags.Vex));
|
||||||
Add(X86Instruction.Cvtpd2dq, new InstInfo(BadOp, BadOp, BadOp, BadOp, 0x00000fe6, InstFlags.Vex | InstFlags.PrefixF2));
|
Add(X86Instruction.Cvtpd2dq, new InstInfo(BadOp, BadOp, BadOp, BadOp, 0x00000fe6, InstFlags.Vex | InstFlags.PrefixF2));
|
||||||
|
@ -313,9 +317,9 @@ namespace ARMeilleure.CodeGen.X86
|
||||||
WriteRRMOpCode(dest, source, info.Flags, info.OpRRM | (int)condition);
|
WriteRRMOpCode(dest, source, info.Flags, info.OpRRM | (int)condition);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Cmp(Operand src1, Operand src2)
|
public void Cmp(Operand source1, Operand source2)
|
||||||
{
|
{
|
||||||
WriteInstruction(src1, src2, X86Instruction.Cmp);
|
WriteInstruction(source1, source2, X86Instruction.Cmp);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Cqo()
|
public void Cqo()
|
||||||
|
@ -338,6 +342,30 @@ namespace ARMeilleure.CodeGen.X86
|
||||||
WriteByte(imm);
|
WriteByte(imm);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void Cmpsd(Operand dest, Operand source, Operand source1, byte imm)
|
||||||
|
{
|
||||||
|
WriteInstruction(dest, source, X86Instruction.Cmpsd, source1);
|
||||||
|
|
||||||
|
WriteByte(imm);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Cmpss(Operand dest, Operand source, Operand source1, byte imm)
|
||||||
|
{
|
||||||
|
WriteInstruction(dest, source, X86Instruction.Cmpss, source1);
|
||||||
|
|
||||||
|
WriteByte(imm);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Comisd(Operand source1, Operand source2)
|
||||||
|
{
|
||||||
|
WriteInstruction(source1, source2, X86Instruction.Comisd);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Comiss(Operand source1, Operand source2)
|
||||||
|
{
|
||||||
|
WriteInstruction(source1, source2, X86Instruction.Comiss);
|
||||||
|
}
|
||||||
|
|
||||||
public void Cvtdq2pd(Operand dest, Operand source)
|
public void Cvtdq2pd(Operand dest, Operand source)
|
||||||
{
|
{
|
||||||
WriteInstruction(dest, source, X86Instruction.Cvtdq2pd);
|
WriteInstruction(dest, source, X86Instruction.Cvtdq2pd);
|
||||||
|
|
|
@ -88,6 +88,14 @@ namespace ARMeilleure.CodeGen.X86
|
||||||
Add(Instruction.X86Andnps, GenerateX86Andnps);
|
Add(Instruction.X86Andnps, GenerateX86Andnps);
|
||||||
Add(Instruction.X86Cmppd, GenerateX86Cmppd);
|
Add(Instruction.X86Cmppd, GenerateX86Cmppd);
|
||||||
Add(Instruction.X86Cmpps, GenerateX86Cmpps);
|
Add(Instruction.X86Cmpps, GenerateX86Cmpps);
|
||||||
|
Add(Instruction.X86Cmpsd, GenerateX86Cmpsd);
|
||||||
|
Add(Instruction.X86Cmpss, GenerateX86Cmpss);
|
||||||
|
Add(Instruction.X86Comisdeq, GenerateX86Comisdeq);
|
||||||
|
Add(Instruction.X86Comisdge, GenerateX86Comisdge);
|
||||||
|
Add(Instruction.X86Comisdlt, GenerateX86Comisdlt);
|
||||||
|
Add(Instruction.X86Comisseq, GenerateX86Comisseq);
|
||||||
|
Add(Instruction.X86Comissge, GenerateX86Comissge);
|
||||||
|
Add(Instruction.X86Comisslt, GenerateX86Comisslt);
|
||||||
Add(Instruction.X86Cvtdq2pd, GenerateX86Cvtdq2pd);
|
Add(Instruction.X86Cvtdq2pd, GenerateX86Cvtdq2pd);
|
||||||
Add(Instruction.X86Cvtdq2ps, GenerateX86Cvtdq2ps);
|
Add(Instruction.X86Cvtdq2ps, GenerateX86Cvtdq2ps);
|
||||||
Add(Instruction.X86Cvtpd2dq, GenerateX86Cvtpd2dq);
|
Add(Instruction.X86Cvtpd2dq, GenerateX86Cvtpd2dq);
|
||||||
|
@ -1026,6 +1034,60 @@ namespace ARMeilleure.CodeGen.X86
|
||||||
operation.GetSource(2).AsByte());
|
operation.GetSource(2).AsByte());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void GenerateX86Cmpsd(CodeGenContext context, Operation operation)
|
||||||
|
{
|
||||||
|
context.Assembler.Cmpsd(
|
||||||
|
operation.Dest,
|
||||||
|
operation.GetSource(1),
|
||||||
|
operation.GetSource(0),
|
||||||
|
operation.GetSource(2).AsByte());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void GenerateX86Cmpss(CodeGenContext context, Operation operation)
|
||||||
|
{
|
||||||
|
context.Assembler.Cmpss(
|
||||||
|
operation.Dest,
|
||||||
|
operation.GetSource(1),
|
||||||
|
operation.GetSource(0),
|
||||||
|
operation.GetSource(2).AsByte());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void GenerateX86Comisdeq(CodeGenContext context, Operation operation)
|
||||||
|
{
|
||||||
|
context.Assembler.Comisd(operation.GetSource(0), operation.GetSource(1));
|
||||||
|
context.Assembler.Setcc(operation.Dest, X86Condition.Equal);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void GenerateX86Comisdge(CodeGenContext context, Operation operation)
|
||||||
|
{
|
||||||
|
context.Assembler.Comisd(operation.GetSource(0), operation.GetSource(1));
|
||||||
|
context.Assembler.Setcc(operation.Dest, X86Condition.AboveOrEqual);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void GenerateX86Comisdlt(CodeGenContext context, Operation operation)
|
||||||
|
{
|
||||||
|
context.Assembler.Comisd(operation.GetSource(0), operation.GetSource(1));
|
||||||
|
context.Assembler.Setcc(operation.Dest, X86Condition.Below);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void GenerateX86Comisseq(CodeGenContext context, Operation operation)
|
||||||
|
{
|
||||||
|
context.Assembler.Comiss(operation.GetSource(0), operation.GetSource(1));
|
||||||
|
context.Assembler.Setcc(operation.Dest, X86Condition.Equal);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void GenerateX86Comissge(CodeGenContext context, Operation operation)
|
||||||
|
{
|
||||||
|
context.Assembler.Comiss(operation.GetSource(0), operation.GetSource(1));
|
||||||
|
context.Assembler.Setcc(operation.Dest, X86Condition.AboveOrEqual);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void GenerateX86Comisslt(CodeGenContext context, Operation operation)
|
||||||
|
{
|
||||||
|
context.Assembler.Comiss(operation.GetSource(0), operation.GetSource(1));
|
||||||
|
context.Assembler.Setcc(operation.Dest, X86Condition.Below);
|
||||||
|
}
|
||||||
|
|
||||||
private static void GenerateX86Cvtdq2pd(CodeGenContext context, Operation operation)
|
private static void GenerateX86Cvtdq2pd(CodeGenContext context, Operation operation)
|
||||||
{
|
{
|
||||||
context.Assembler.Cvtdq2pd(operation.Dest, operation.GetSource(0));
|
context.Assembler.Cvtdq2pd(operation.Dest, operation.GetSource(0));
|
||||||
|
|
|
@ -106,7 +106,7 @@ namespace ARMeilleure.CodeGen.X86
|
||||||
//Comparison instructions uses CMOVcc, which does not zero the
|
//Comparison instructions uses CMOVcc, which does not zero the
|
||||||
//upper bits of the register (since it's R8), we need to ensure it
|
//upper bits of the register (since it's R8), we need to ensure it
|
||||||
//is zero by zeroing it beforehand.
|
//is zero by zeroing it beforehand.
|
||||||
if (inst.IsComparison())
|
if (inst.IsComparison() || IsComparisonIntrinsic(inst))
|
||||||
{
|
{
|
||||||
Operation copyOp = new Operation(Instruction.Copy, operation.Dest, Const(0));
|
Operation copyOp = new Operation(Instruction.Copy, operation.Dest, Const(0));
|
||||||
|
|
||||||
|
@ -121,12 +121,12 @@ namespace ARMeilleure.CodeGen.X86
|
||||||
ReplaceConvertToFPUIWithSI(node, operation);
|
ReplaceConvertToFPUIWithSI(node, operation);
|
||||||
}
|
}
|
||||||
|
|
||||||
//There's no SSE FP negate instruction, so we need to transform that into:
|
//There's no SSE FP negate instruction, so we need to transform that into
|
||||||
//r = 0 - n or
|
//a XOR of the value to be negated with a mask with the highest bit set.
|
||||||
//r = n ^ (1 << (OperandSize - 1))
|
//This also produces -0 for a negation of the value 0.
|
||||||
if (inst == Instruction.Negate && !operation.GetSource(0).Type.IsInteger())
|
if (inst == Instruction.Negate && !operation.GetSource(0).Type.IsInteger())
|
||||||
{
|
{
|
||||||
ReplaceNegateWithSubtract(node, operation);
|
ReplaceNegateWithXor(node, operation);
|
||||||
}
|
}
|
||||||
|
|
||||||
AddFixedRegisterCopy(node, operation);
|
AddFixedRegisterCopy(node, operation);
|
||||||
|
@ -272,19 +272,32 @@ namespace ARMeilleure.CodeGen.X86
|
||||||
Delete(node, operation);
|
Delete(node, operation);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void ReplaceNegateWithSubtract(LinkedListNode<Node> node, Operation operation)
|
private static void ReplaceNegateWithXor(LinkedListNode<Node> node, Operation operation)
|
||||||
{
|
{
|
||||||
Operand dest = operation.Dest;
|
Operand dest = operation.Dest;
|
||||||
Operand source = operation.GetSource(0);
|
Operand source = operation.GetSource(0);
|
||||||
|
|
||||||
|
Debug.Assert(dest.Type == OperandType.FP32 ||
|
||||||
|
dest.Type == OperandType.FP64, $"Invalid destination type \"{dest.Type}\".");
|
||||||
|
|
||||||
LinkedList<Node> nodes = node.List;
|
LinkedList<Node> nodes = node.List;
|
||||||
|
|
||||||
LinkedListNode<Node> temp = node;
|
LinkedListNode<Node> temp = node;
|
||||||
|
|
||||||
Operand res = Local(dest.Type);
|
Operand res = Local(dest.Type);
|
||||||
|
|
||||||
temp = nodes.AddAfter(temp, new Operation(Instruction.VectorZero, res));
|
temp = nodes.AddAfter(temp, new Operation(Instruction.X86Pcmpeqw, res, res, res));
|
||||||
temp = nodes.AddAfter(temp, new Operation(Instruction.Subtract, res, res, source));
|
|
||||||
|
if (dest.Type == OperandType.FP32)
|
||||||
|
{
|
||||||
|
temp = nodes.AddAfter(temp, new Operation(Instruction.X86Pslld, res, res, Const(31)));
|
||||||
|
}
|
||||||
|
else /* if (dest.Type == OperandType.FP64) */
|
||||||
|
{
|
||||||
|
temp = nodes.AddAfter(temp, new Operation(Instruction.X86Psllq, res, res, Const(63)));
|
||||||
|
}
|
||||||
|
|
||||||
|
temp = nodes.AddAfter(temp, new Operation(Instruction.X86Xorps, res, res, source));
|
||||||
temp = nodes.AddAfter(temp, new Operation(Instruction.Copy, dest, res));
|
temp = nodes.AddAfter(temp, new Operation(Instruction.Copy, dest, res));
|
||||||
|
|
||||||
Delete(node, operation);
|
Delete(node, operation);
|
||||||
|
@ -700,5 +713,21 @@ namespace ARMeilleure.CodeGen.X86
|
||||||
return inst > Instruction.X86Intrinsic_Start &&
|
return inst > Instruction.X86Intrinsic_Start &&
|
||||||
inst < Instruction.X86Intrinsic_End;
|
inst < Instruction.X86Intrinsic_End;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static bool IsComparisonIntrinsic(Instruction inst)
|
||||||
|
{
|
||||||
|
switch (inst)
|
||||||
|
{
|
||||||
|
case Instruction.X86Comisdeq:
|
||||||
|
case Instruction.X86Comisdge:
|
||||||
|
case Instruction.X86Comisdlt:
|
||||||
|
case Instruction.X86Comisseq:
|
||||||
|
case Instruction.X86Comissge:
|
||||||
|
case Instruction.X86Comisslt:
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -17,6 +17,10 @@ namespace ARMeilleure.CodeGen.X86
|
||||||
Cmp,
|
Cmp,
|
||||||
Cmppd,
|
Cmppd,
|
||||||
Cmpps,
|
Cmpps,
|
||||||
|
Cmpsd,
|
||||||
|
Cmpss,
|
||||||
|
Comisd,
|
||||||
|
Comiss,
|
||||||
Cvtdq2pd,
|
Cvtdq2pd,
|
||||||
Cvtdq2ps,
|
Cvtdq2ps,
|
||||||
Cvtpd2dq,
|
Cvtpd2dq,
|
||||||
|
|
|
@ -211,28 +211,28 @@ namespace ARMeilleure.Decoders
|
||||||
SetA64("0x101110011xxxxx000111xxxxxxxxxx", InstName.Bsl_V, InstEmit.Bsl_V, typeof(OpCodeSimdReg));
|
SetA64("0x101110011xxxxx000111xxxxxxxxxx", InstName.Bsl_V, InstEmit.Bsl_V, typeof(OpCodeSimdReg));
|
||||||
SetA64("0x001110<<100000010010xxxxxxxxxx", InstName.Cls_V, InstEmit.Cls_V, typeof(OpCodeSimd));
|
SetA64("0x001110<<100000010010xxxxxxxxxx", InstName.Cls_V, InstEmit.Cls_V, typeof(OpCodeSimd));
|
||||||
SetA64("0x101110<<100000010010xxxxxxxxxx", InstName.Clz_V, InstEmit.Clz_V, typeof(OpCodeSimd));
|
SetA64("0x101110<<100000010010xxxxxxxxxx", InstName.Clz_V, InstEmit.Clz_V, typeof(OpCodeSimd));
|
||||||
SetA64("01111110111xxxxx100011xxxxxxxxxx", InstName.Cmeq_S, null, typeof(OpCodeSimdReg));
|
SetA64("01111110111xxxxx100011xxxxxxxxxx", InstName.Cmeq_S, InstEmit.Cmeq_S, typeof(OpCodeSimdReg));
|
||||||
SetA64("0101111011100000100110xxxxxxxxxx", InstName.Cmeq_S, null, typeof(OpCodeSimd));
|
SetA64("0101111011100000100110xxxxxxxxxx", InstName.Cmeq_S, InstEmit.Cmeq_S, typeof(OpCodeSimd));
|
||||||
SetA64("0>101110<<1xxxxx100011xxxxxxxxxx", InstName.Cmeq_V, null, typeof(OpCodeSimdReg));
|
SetA64("0>101110<<1xxxxx100011xxxxxxxxxx", InstName.Cmeq_V, InstEmit.Cmeq_V, typeof(OpCodeSimdReg));
|
||||||
SetA64("0>001110<<100000100110xxxxxxxxxx", InstName.Cmeq_V, null, typeof(OpCodeSimd));
|
SetA64("0>001110<<100000100110xxxxxxxxxx", InstName.Cmeq_V, InstEmit.Cmeq_V, typeof(OpCodeSimd));
|
||||||
SetA64("01011110111xxxxx001111xxxxxxxxxx", InstName.Cmge_S, null, typeof(OpCodeSimdReg));
|
SetA64("01011110111xxxxx001111xxxxxxxxxx", InstName.Cmge_S, InstEmit.Cmge_S, typeof(OpCodeSimdReg));
|
||||||
SetA64("0111111011100000100010xxxxxxxxxx", InstName.Cmge_S, null, typeof(OpCodeSimd));
|
SetA64("0111111011100000100010xxxxxxxxxx", InstName.Cmge_S, InstEmit.Cmge_S, typeof(OpCodeSimd));
|
||||||
SetA64("0>001110<<1xxxxx001111xxxxxxxxxx", InstName.Cmge_V, null, typeof(OpCodeSimdReg));
|
SetA64("0>001110<<1xxxxx001111xxxxxxxxxx", InstName.Cmge_V, InstEmit.Cmge_V, typeof(OpCodeSimdReg));
|
||||||
SetA64("0>101110<<100000100010xxxxxxxxxx", InstName.Cmge_V, null, typeof(OpCodeSimd));
|
SetA64("0>101110<<100000100010xxxxxxxxxx", InstName.Cmge_V, InstEmit.Cmge_V, typeof(OpCodeSimd));
|
||||||
SetA64("01011110111xxxxx001101xxxxxxxxxx", InstName.Cmgt_S, null, typeof(OpCodeSimdReg));
|
SetA64("01011110111xxxxx001101xxxxxxxxxx", InstName.Cmgt_S, InstEmit.Cmgt_S, typeof(OpCodeSimdReg));
|
||||||
SetA64("0101111011100000100010xxxxxxxxxx", InstName.Cmgt_S, null, typeof(OpCodeSimd));
|
SetA64("0101111011100000100010xxxxxxxxxx", InstName.Cmgt_S, InstEmit.Cmgt_S, typeof(OpCodeSimd));
|
||||||
SetA64("0>001110<<1xxxxx001101xxxxxxxxxx", InstName.Cmgt_V, null, typeof(OpCodeSimdReg));
|
SetA64("0>001110<<1xxxxx001101xxxxxxxxxx", InstName.Cmgt_V, InstEmit.Cmgt_V, typeof(OpCodeSimdReg));
|
||||||
SetA64("0>001110<<100000100010xxxxxxxxxx", InstName.Cmgt_V, null, typeof(OpCodeSimd));
|
SetA64("0>001110<<100000100010xxxxxxxxxx", InstName.Cmgt_V, InstEmit.Cmgt_V, typeof(OpCodeSimd));
|
||||||
SetA64("01111110111xxxxx001101xxxxxxxxxx", InstName.Cmhi_S, null, typeof(OpCodeSimdReg));
|
SetA64("01111110111xxxxx001101xxxxxxxxxx", InstName.Cmhi_S, InstEmit.Cmhi_S, typeof(OpCodeSimdReg));
|
||||||
SetA64("0>101110<<1xxxxx001101xxxxxxxxxx", InstName.Cmhi_V, null, typeof(OpCodeSimdReg));
|
SetA64("0>101110<<1xxxxx001101xxxxxxxxxx", InstName.Cmhi_V, InstEmit.Cmhi_V, typeof(OpCodeSimdReg));
|
||||||
SetA64("01111110111xxxxx001111xxxxxxxxxx", InstName.Cmhs_S, null, typeof(OpCodeSimdReg));
|
SetA64("01111110111xxxxx001111xxxxxxxxxx", InstName.Cmhs_S, InstEmit.Cmhs_S, typeof(OpCodeSimdReg));
|
||||||
SetA64("0>101110<<1xxxxx001111xxxxxxxxxx", InstName.Cmhs_V, null, typeof(OpCodeSimdReg));
|
SetA64("0>101110<<1xxxxx001111xxxxxxxxxx", InstName.Cmhs_V, InstEmit.Cmhs_V, typeof(OpCodeSimdReg));
|
||||||
SetA64("0111111011100000100110xxxxxxxxxx", InstName.Cmle_S, null, typeof(OpCodeSimd));
|
SetA64("0111111011100000100110xxxxxxxxxx", InstName.Cmle_S, InstEmit.Cmle_S, typeof(OpCodeSimd));
|
||||||
SetA64("0>101110<<100000100110xxxxxxxxxx", InstName.Cmle_V, null, typeof(OpCodeSimd));
|
SetA64("0>101110<<100000100110xxxxxxxxxx", InstName.Cmle_V, InstEmit.Cmle_V, typeof(OpCodeSimd));
|
||||||
SetA64("0101111011100000101010xxxxxxxxxx", InstName.Cmlt_S, null, typeof(OpCodeSimd));
|
SetA64("0101111011100000101010xxxxxxxxxx", InstName.Cmlt_S, InstEmit.Cmlt_S, typeof(OpCodeSimd));
|
||||||
SetA64("0>001110<<100000101010xxxxxxxxxx", InstName.Cmlt_V, null, typeof(OpCodeSimd));
|
SetA64("0>001110<<100000101010xxxxxxxxxx", InstName.Cmlt_V, InstEmit.Cmlt_V, typeof(OpCodeSimd));
|
||||||
SetA64("01011110111xxxxx100011xxxxxxxxxx", InstName.Cmtst_S, null, typeof(OpCodeSimdReg));
|
SetA64("01011110111xxxxx100011xxxxxxxxxx", InstName.Cmtst_S, InstEmit.Cmtst_S, typeof(OpCodeSimdReg));
|
||||||
SetA64("0>001110<<1xxxxx100011xxxxxxxxxx", InstName.Cmtst_V, null, typeof(OpCodeSimdReg));
|
SetA64("0>001110<<1xxxxx100011xxxxxxxxxx", InstName.Cmtst_V, InstEmit.Cmtst_V, typeof(OpCodeSimdReg));
|
||||||
SetA64("0x00111000100000010110xxxxxxxxxx", InstName.Cnt_V, InstEmit.Cnt_V, typeof(OpCodeSimd));
|
SetA64("0x00111000100000010110xxxxxxxxxx", InstName.Cnt_V, InstEmit.Cnt_V, typeof(OpCodeSimd));
|
||||||
SetA64("0>001110000x<>>>000011xxxxxxxxxx", InstName.Dup_Gp, InstEmit.Dup_Gp, typeof(OpCodeSimdIns));
|
SetA64("0>001110000x<>>>000011xxxxxxxxxx", InstName.Dup_Gp, InstEmit.Dup_Gp, typeof(OpCodeSimdIns));
|
||||||
SetA64("01011110000xxxxx000001xxxxxxxxxx", InstName.Dup_S, InstEmit.Dup_S, typeof(OpCodeSimdIns));
|
SetA64("01011110000xxxxx000001xxxxxxxxxx", InstName.Dup_S, InstEmit.Dup_S, typeof(OpCodeSimdIns));
|
||||||
|
@ -247,26 +247,26 @@ namespace ARMeilleure.Decoders
|
||||||
SetA64("0>0011100<1xxxxx110101xxxxxxxxxx", InstName.Fadd_V, InstEmit.Fadd_V, typeof(OpCodeSimdReg));
|
SetA64("0>0011100<1xxxxx110101xxxxxxxxxx", InstName.Fadd_V, InstEmit.Fadd_V, typeof(OpCodeSimdReg));
|
||||||
SetA64("011111100x110000110110xxxxxxxxxx", InstName.Faddp_S, InstEmit.Faddp_S, typeof(OpCodeSimd));
|
SetA64("011111100x110000110110xxxxxxxxxx", InstName.Faddp_S, InstEmit.Faddp_S, typeof(OpCodeSimd));
|
||||||
SetA64("0>1011100<1xxxxx110101xxxxxxxxxx", InstName.Faddp_V, InstEmit.Faddp_V, typeof(OpCodeSimdReg));
|
SetA64("0>1011100<1xxxxx110101xxxxxxxxxx", InstName.Faddp_V, InstEmit.Faddp_V, typeof(OpCodeSimdReg));
|
||||||
SetA64("000111100x1xxxxxxxxx01xxxxx0xxxx", InstName.Fccmp_S, null, typeof(OpCodeSimdFcond));
|
SetA64("000111100x1xxxxxxxxx01xxxxx0xxxx", InstName.Fccmp_S, InstEmit.Fccmp_S, typeof(OpCodeSimdFcond));
|
||||||
SetA64("000111100x1xxxxxxxxx01xxxxx1xxxx", InstName.Fccmpe_S, null, typeof(OpCodeSimdFcond));
|
SetA64("000111100x1xxxxxxxxx01xxxxx1xxxx", InstName.Fccmpe_S, InstEmit.Fccmpe_S, typeof(OpCodeSimdFcond));
|
||||||
SetA64("010111100x1xxxxx111001xxxxxxxxxx", InstName.Fcmeq_S, null, typeof(OpCodeSimdReg));
|
SetA64("010111100x1xxxxx111001xxxxxxxxxx", InstName.Fcmeq_S, InstEmit.Fcmeq_S, typeof(OpCodeSimdReg));
|
||||||
SetA64("010111101x100000110110xxxxxxxxxx", InstName.Fcmeq_S, null, typeof(OpCodeSimd));
|
SetA64("010111101x100000110110xxxxxxxxxx", InstName.Fcmeq_S, InstEmit.Fcmeq_S, typeof(OpCodeSimd));
|
||||||
SetA64("0>0011100<1xxxxx111001xxxxxxxxxx", InstName.Fcmeq_V, null, typeof(OpCodeSimdReg));
|
SetA64("0>0011100<1xxxxx111001xxxxxxxxxx", InstName.Fcmeq_V, InstEmit.Fcmeq_V, typeof(OpCodeSimdReg));
|
||||||
SetA64("0>0011101<100000110110xxxxxxxxxx", InstName.Fcmeq_V, null, typeof(OpCodeSimd));
|
SetA64("0>0011101<100000110110xxxxxxxxxx", InstName.Fcmeq_V, InstEmit.Fcmeq_V, typeof(OpCodeSimd));
|
||||||
SetA64("011111100x1xxxxx111001xxxxxxxxxx", InstName.Fcmge_S, null, typeof(OpCodeSimdReg));
|
SetA64("011111100x1xxxxx111001xxxxxxxxxx", InstName.Fcmge_S, InstEmit.Fcmge_S, typeof(OpCodeSimdReg));
|
||||||
SetA64("011111101x100000110010xxxxxxxxxx", InstName.Fcmge_S, null, typeof(OpCodeSimd));
|
SetA64("011111101x100000110010xxxxxxxxxx", InstName.Fcmge_S, InstEmit.Fcmge_S, typeof(OpCodeSimd));
|
||||||
SetA64("0>1011100<1xxxxx111001xxxxxxxxxx", InstName.Fcmge_V, null, typeof(OpCodeSimdReg));
|
SetA64("0>1011100<1xxxxx111001xxxxxxxxxx", InstName.Fcmge_V, InstEmit.Fcmge_V, typeof(OpCodeSimdReg));
|
||||||
SetA64("0>1011101<100000110010xxxxxxxxxx", InstName.Fcmge_V, null, typeof(OpCodeSimd));
|
SetA64("0>1011101<100000110010xxxxxxxxxx", InstName.Fcmge_V, InstEmit.Fcmge_V, typeof(OpCodeSimd));
|
||||||
SetA64("011111101x1xxxxx111001xxxxxxxxxx", InstName.Fcmgt_S, null, typeof(OpCodeSimdReg));
|
SetA64("011111101x1xxxxx111001xxxxxxxxxx", InstName.Fcmgt_S, InstEmit.Fcmgt_S, typeof(OpCodeSimdReg));
|
||||||
SetA64("010111101x100000110010xxxxxxxxxx", InstName.Fcmgt_S, null, typeof(OpCodeSimd));
|
SetA64("010111101x100000110010xxxxxxxxxx", InstName.Fcmgt_S, InstEmit.Fcmgt_S, typeof(OpCodeSimd));
|
||||||
SetA64("0>1011101<1xxxxx111001xxxxxxxxxx", InstName.Fcmgt_V, null, typeof(OpCodeSimdReg));
|
SetA64("0>1011101<1xxxxx111001xxxxxxxxxx", InstName.Fcmgt_V, InstEmit.Fcmgt_V, typeof(OpCodeSimdReg));
|
||||||
SetA64("0>0011101<100000110010xxxxxxxxxx", InstName.Fcmgt_V, null, typeof(OpCodeSimd));
|
SetA64("0>0011101<100000110010xxxxxxxxxx", InstName.Fcmgt_V, InstEmit.Fcmgt_V, typeof(OpCodeSimd));
|
||||||
SetA64("011111101x100000110110xxxxxxxxxx", InstName.Fcmle_S, null, typeof(OpCodeSimd));
|
SetA64("011111101x100000110110xxxxxxxxxx", InstName.Fcmle_S, InstEmit.Fcmle_S, typeof(OpCodeSimd));
|
||||||
SetA64("0>1011101<100000110110xxxxxxxxxx", InstName.Fcmle_V, null, typeof(OpCodeSimd));
|
SetA64("0>1011101<100000110110xxxxxxxxxx", InstName.Fcmle_V, InstEmit.Fcmle_V, typeof(OpCodeSimd));
|
||||||
SetA64("010111101x100000111010xxxxxxxxxx", InstName.Fcmlt_S, null, typeof(OpCodeSimd));
|
SetA64("010111101x100000111010xxxxxxxxxx", InstName.Fcmlt_S, InstEmit.Fcmlt_S, typeof(OpCodeSimd));
|
||||||
SetA64("0>0011101<100000111010xxxxxxxxxx", InstName.Fcmlt_V, null, typeof(OpCodeSimd));
|
SetA64("0>0011101<100000111010xxxxxxxxxx", InstName.Fcmlt_V, InstEmit.Fcmlt_V, typeof(OpCodeSimd));
|
||||||
SetA64("000111100x1xxxxx001000xxxxx0x000", InstName.Fcmp_S, null, typeof(OpCodeSimdReg));
|
SetA64("000111100x1xxxxx001000xxxxx0x000", InstName.Fcmp_S, InstEmit.Fcmp_S, typeof(OpCodeSimdReg));
|
||||||
SetA64("000111100x1xxxxx001000xxxxx1x000", InstName.Fcmpe_S, null, typeof(OpCodeSimdReg));
|
SetA64("000111100x1xxxxx001000xxxxx1x000", InstName.Fcmpe_S, InstEmit.Fcmpe_S, typeof(OpCodeSimdReg));
|
||||||
SetA64("000111100x1xxxxxxxxx11xxxxxxxxxx", InstName.Fcsel_S, InstEmit.Fcsel_S, typeof(OpCodeSimdFcond));
|
SetA64("000111100x1xxxxxxxxx11xxxxxxxxxx", InstName.Fcsel_S, InstEmit.Fcsel_S, typeof(OpCodeSimdFcond));
|
||||||
SetA64("000111100x10001xx10000xxxxxxxxxx", InstName.Fcvt_S, InstEmit.Fcvt_S, typeof(OpCodeSimd));
|
SetA64("000111100x10001xx10000xxxxxxxxxx", InstName.Fcvt_S, InstEmit.Fcvt_S, typeof(OpCodeSimd));
|
||||||
SetA64("x00111100x100100000000xxxxxxxxxx", InstName.Fcvtas_Gp, InstEmit.Fcvtas_Gp, typeof(OpCodeSimdCvt));
|
SetA64("x00111100x100100000000xxxxxxxxxx", InstName.Fcvtas_Gp, InstEmit.Fcvtas_Gp, typeof(OpCodeSimdCvt));
|
||||||
|
|
|
@ -59,11 +59,7 @@ namespace ARMeilleure.Instructions
|
||||||
context.Copy(GetFlag(PState.CFlag), context.ICompareGreaterOrEqualUI(n, m));
|
context.Copy(GetFlag(PState.CFlag), context.ICompareGreaterOrEqualUI(n, m));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void EmitSubsVCheck(
|
public static void EmitSubsVCheck(EmitterContext context, Operand n, Operand m, Operand d)
|
||||||
EmitterContext context,
|
|
||||||
Operand n,
|
|
||||||
Operand m,
|
|
||||||
Operand d)
|
|
||||||
{
|
{
|
||||||
//V = (Rd ^ Rn) & (Rn ^ Rm) < 0
|
//V = (Rd ^ Rn) & (Rn ^ Rm) < 0
|
||||||
Operand vOut = context.BitwiseExclusiveOr(d, n);
|
Operand vOut = context.BitwiseExclusiveOr(d, n);
|
||||||
|
@ -158,23 +154,6 @@ namespace ARMeilleure.Instructions
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void EmitSetNzcv(EmitterContext context, Operand nzcv)
|
|
||||||
{
|
|
||||||
Operand Extract(Operand value, int bit)
|
|
||||||
{
|
|
||||||
value = context.ShiftRightUI(value, Const(bit));
|
|
||||||
|
|
||||||
value = context.BitwiseAnd(value, Const(1));
|
|
||||||
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
context.Copy(GetFlag(PState.VFlag), Extract(nzcv, 0));
|
|
||||||
context.Copy(GetFlag(PState.CFlag), Extract(nzcv, 1));
|
|
||||||
context.Copy(GetFlag(PState.ZFlag), Extract(nzcv, 2));
|
|
||||||
context.Copy(GetFlag(PState.NFlag), Extract(nzcv, 3));
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Exception InvalidOpCodeType(OpCode opCode)
|
private static Exception InvalidOpCodeType(OpCode opCode)
|
||||||
{
|
{
|
||||||
return new InvalidOperationException($"Invalid OpCode type \"{opCode?.GetType().Name ?? "null"}\".");
|
return new InvalidOperationException($"Invalid OpCode type \"{opCode?.GetType().Name ?? "null"}\".");
|
||||||
|
|
705
ARMeilleure/Instructions/InstEmitSimdCmp.cs
Normal file
705
ARMeilleure/Instructions/InstEmitSimdCmp.cs
Normal file
|
@ -0,0 +1,705 @@
|
||||||
|
using ARMeilleure.Decoders;
|
||||||
|
using ARMeilleure.IntermediateRepresentation;
|
||||||
|
using ARMeilleure.State;
|
||||||
|
using ARMeilleure.Translation;
|
||||||
|
using System;
|
||||||
|
using System.Reflection;
|
||||||
|
|
||||||
|
using static ARMeilleure.Instructions.InstEmitHelper;
|
||||||
|
using static ARMeilleure.Instructions.InstEmitSimdHelper;
|
||||||
|
using static ARMeilleure.IntermediateRepresentation.OperandHelper;
|
||||||
|
|
||||||
|
namespace ARMeilleure.Instructions
|
||||||
|
{
|
||||||
|
using Func2I = Func<Operand, Operand, Operand>;
|
||||||
|
|
||||||
|
static partial class InstEmit
|
||||||
|
{
|
||||||
|
public static void Cmeq_S(EmitterContext context)
|
||||||
|
{
|
||||||
|
EmitCmpOp(context, (op1, op2) => context.ICompareEqual(op1, op2), scalar: true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Cmeq_V(EmitterContext context)
|
||||||
|
{
|
||||||
|
if (Optimizations.UseSse41)
|
||||||
|
{
|
||||||
|
OpCodeSimd op = (OpCodeSimd)context.CurrOp;
|
||||||
|
|
||||||
|
Operand n = GetVec(op.Rn);
|
||||||
|
Operand m;
|
||||||
|
|
||||||
|
if (op is OpCodeSimdReg binOp)
|
||||||
|
{
|
||||||
|
m = GetVec(op.Rn);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m = context.VectorZero();
|
||||||
|
}
|
||||||
|
|
||||||
|
Instruction cmpInst = X86PcmpeqInstruction[op.Size];
|
||||||
|
|
||||||
|
Operand res = context.AddIntrinsic(cmpInst, n, m);
|
||||||
|
|
||||||
|
if (op.RegisterSize == RegisterSize.Simd64)
|
||||||
|
{
|
||||||
|
res = context.VectorZeroUpper64(res);
|
||||||
|
}
|
||||||
|
|
||||||
|
context.Copy(GetVec(op.Rd), res);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
EmitCmpOp(context, (op1, op2) => context.ICompareEqual(op1, op2), scalar: false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Cmge_S(EmitterContext context)
|
||||||
|
{
|
||||||
|
EmitCmpOp(context, (op1, op2) => context.ICompareGreaterOrEqual(op1, op2), scalar: true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Cmge_V(EmitterContext context)
|
||||||
|
{
|
||||||
|
if (Optimizations.UseSse42)
|
||||||
|
{
|
||||||
|
OpCodeSimd op = (OpCodeSimd)context.CurrOp;
|
||||||
|
|
||||||
|
Operand n = GetVec(op.Rn);
|
||||||
|
Operand m;
|
||||||
|
|
||||||
|
if (op is OpCodeSimdReg binOp)
|
||||||
|
{
|
||||||
|
m = GetVec(op.Rn);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m = context.VectorZero();
|
||||||
|
}
|
||||||
|
|
||||||
|
Instruction cmpInst = X86PcmpgtInstruction[op.Size];
|
||||||
|
|
||||||
|
Operand res = context.AddIntrinsic(cmpInst, n, m);
|
||||||
|
|
||||||
|
Operand mask = X86GetAllElements(context, -1L);
|
||||||
|
|
||||||
|
res = context.AddIntrinsic(Instruction.X86Pandn, res, mask);
|
||||||
|
|
||||||
|
if (op.RegisterSize == RegisterSize.Simd64)
|
||||||
|
{
|
||||||
|
res = context.VectorZeroUpper64(res);
|
||||||
|
}
|
||||||
|
|
||||||
|
context.Copy(GetVec(op.Rd), res);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
EmitCmpOp(context, (op1, op2) => context.ICompareGreaterOrEqual(op1, op2), scalar: false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Cmgt_S(EmitterContext context)
|
||||||
|
{
|
||||||
|
EmitCmpOp(context, (op1, op2) => context.ICompareGreater(op1, op2), scalar: true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Cmgt_V(EmitterContext context)
|
||||||
|
{
|
||||||
|
if (Optimizations.UseSse42)
|
||||||
|
{
|
||||||
|
OpCodeSimd op = (OpCodeSimd)context.CurrOp;
|
||||||
|
|
||||||
|
Operand n = GetVec(op.Rn);
|
||||||
|
Operand m;
|
||||||
|
|
||||||
|
if (op is OpCodeSimdReg binOp)
|
||||||
|
{
|
||||||
|
m = GetVec(op.Rn);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m = context.VectorZero();
|
||||||
|
}
|
||||||
|
|
||||||
|
Instruction cmpInst = X86PcmpgtInstruction[op.Size];
|
||||||
|
|
||||||
|
Operand res = context.AddIntrinsic(cmpInst, n, m);
|
||||||
|
|
||||||
|
if (op.RegisterSize == RegisterSize.Simd64)
|
||||||
|
{
|
||||||
|
res = context.VectorZeroUpper64(res);
|
||||||
|
}
|
||||||
|
|
||||||
|
context.Copy(GetVec(op.Rd), res);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
EmitCmpOp(context, (op1, op2) => context.ICompareGreater(op1, op2), scalar: false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Cmhi_S(EmitterContext context)
|
||||||
|
{
|
||||||
|
EmitCmpOp(context, (op1, op2) => context.ICompareGreaterUI(op1, op2), scalar: true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Cmhi_V(EmitterContext context)
|
||||||
|
{
|
||||||
|
OpCodeSimdReg op = (OpCodeSimdReg)context.CurrOp;
|
||||||
|
|
||||||
|
if (Optimizations.UseSse41 && op.Size < 3)
|
||||||
|
{
|
||||||
|
Operand n = GetVec(op.Rn);
|
||||||
|
Operand m = GetVec(op.Rm);
|
||||||
|
|
||||||
|
Instruction maxInst = X86PmaxuInstruction[op.Size];
|
||||||
|
|
||||||
|
Operand res = context.AddIntrinsic(maxInst, m, n);
|
||||||
|
|
||||||
|
Instruction cmpInst = X86PcmpeqInstruction[op.Size];
|
||||||
|
|
||||||
|
res = context.AddIntrinsic(cmpInst, res, m);
|
||||||
|
|
||||||
|
Operand mask = X86GetAllElements(context, -1L);
|
||||||
|
|
||||||
|
res = context.AddIntrinsic(Instruction.X86Pandn, res, mask);
|
||||||
|
|
||||||
|
if (op.RegisterSize == RegisterSize.Simd64)
|
||||||
|
{
|
||||||
|
res = context.VectorZeroUpper64(res);
|
||||||
|
}
|
||||||
|
|
||||||
|
context.Copy(GetVec(op.Rd), res);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
EmitCmpOp(context, (op1, op2) => context.ICompareGreaterUI(op1, op2), scalar: false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Cmhs_S(EmitterContext context)
|
||||||
|
{
|
||||||
|
EmitCmpOp(context, (op1, op2) => context.ICompareGreaterOrEqualUI(op1, op2), scalar: true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Cmhs_V(EmitterContext context)
|
||||||
|
{
|
||||||
|
OpCodeSimdReg op = (OpCodeSimdReg)context.CurrOp;
|
||||||
|
|
||||||
|
if (Optimizations.UseSse41 && op.Size < 3)
|
||||||
|
{
|
||||||
|
Operand n = GetVec(op.Rn);
|
||||||
|
Operand m = GetVec(op.Rm);
|
||||||
|
|
||||||
|
Instruction maxInst = X86PmaxuInstruction[op.Size];
|
||||||
|
|
||||||
|
Operand res = context.AddIntrinsic(maxInst, n, m);
|
||||||
|
|
||||||
|
Instruction cmpInst = X86PcmpeqInstruction[op.Size];
|
||||||
|
|
||||||
|
res = context.AddIntrinsic(cmpInst, res, n);
|
||||||
|
|
||||||
|
if (op.RegisterSize == RegisterSize.Simd64)
|
||||||
|
{
|
||||||
|
res = context.VectorZeroUpper64(res);
|
||||||
|
}
|
||||||
|
|
||||||
|
context.Copy(GetVec(op.Rd), res);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
EmitCmpOp(context, (op1, op2) => context.ICompareGreaterOrEqualUI(op1, op2), scalar: false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Cmle_S(EmitterContext context)
|
||||||
|
{
|
||||||
|
EmitCmpOp(context, (op1, op2) => context.ICompareLessOrEqual(op1, op2), scalar: true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Cmle_V(EmitterContext context)
|
||||||
|
{
|
||||||
|
if (Optimizations.UseSse42)
|
||||||
|
{
|
||||||
|
OpCodeSimd op = (OpCodeSimd)context.CurrOp;
|
||||||
|
|
||||||
|
Operand n = GetVec(op.Rn);
|
||||||
|
|
||||||
|
Instruction cmpInst = X86PcmpgtInstruction[op.Size];
|
||||||
|
|
||||||
|
Operand res = context.AddIntrinsic(cmpInst, n, context.VectorZero());
|
||||||
|
|
||||||
|
Operand mask = X86GetAllElements(context, -1L);
|
||||||
|
|
||||||
|
res = context.AddIntrinsic(Instruction.X86Pandn, res, mask);
|
||||||
|
|
||||||
|
if (op.RegisterSize == RegisterSize.Simd64)
|
||||||
|
{
|
||||||
|
res = context.VectorZeroUpper64(res);
|
||||||
|
}
|
||||||
|
|
||||||
|
context.Copy(GetVec(op.Rd), res);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
EmitCmpOp(context, (op1, op2) => context.ICompareLessOrEqual(op1, op2), scalar: false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Cmlt_S(EmitterContext context)
|
||||||
|
{
|
||||||
|
EmitCmpOp(context, (op1, op2) => context.ICompareLess(op1, op2), scalar: true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Cmlt_V(EmitterContext context)
|
||||||
|
{
|
||||||
|
if (Optimizations.UseSse42)
|
||||||
|
{
|
||||||
|
OpCodeSimd op = (OpCodeSimd)context.CurrOp;
|
||||||
|
|
||||||
|
Operand n = GetVec(op.Rn);
|
||||||
|
|
||||||
|
Instruction cmpInst = X86PcmpgtInstruction[op.Size];
|
||||||
|
|
||||||
|
Operand res = context.AddIntrinsic(cmpInst, context.VectorZero(), n);
|
||||||
|
|
||||||
|
if (op.RegisterSize == RegisterSize.Simd64)
|
||||||
|
{
|
||||||
|
res = context.VectorZeroUpper64(res);
|
||||||
|
}
|
||||||
|
|
||||||
|
context.Copy(GetVec(op.Rd), res);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
EmitCmpOp(context, (op1, op2) => context.ICompareLess(op1, op2), scalar: false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Cmtst_S(EmitterContext context)
|
||||||
|
{
|
||||||
|
EmitCmtstOp(context, scalar: true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Cmtst_V(EmitterContext context)
|
||||||
|
{
|
||||||
|
EmitCmtstOp(context, scalar: false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Fccmp_S(EmitterContext context)
|
||||||
|
{
|
||||||
|
EmitFccmpOrFccmpe(context, signalNaNs: false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Fccmpe_S(EmitterContext context)
|
||||||
|
{
|
||||||
|
EmitFccmpOrFccmpe(context, signalNaNs: true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Fcmeq_S(EmitterContext context)
|
||||||
|
{
|
||||||
|
if (Optimizations.FastFP && Optimizations.UseSse2)
|
||||||
|
{
|
||||||
|
EmitCmpSseOrSse2OpF(context, CmpCondition.Equal, scalar: true);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
EmitCmpOpF(context, nameof(SoftFloat32.FPCompareEQ), scalar: true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Fcmeq_V(EmitterContext context)
|
||||||
|
{
|
||||||
|
if (Optimizations.FastFP && Optimizations.UseSse2)
|
||||||
|
{
|
||||||
|
EmitCmpSseOrSse2OpF(context, CmpCondition.Equal, scalar: false);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
EmitCmpOpF(context, nameof(SoftFloat32.FPCompareEQ), scalar: false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Fcmge_S(EmitterContext context)
|
||||||
|
{
|
||||||
|
if (Optimizations.FastFP && Optimizations.UseSse2)
|
||||||
|
{
|
||||||
|
EmitCmpSseOrSse2OpF(context, CmpCondition.GreaterThanOrEqual, scalar: true);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
EmitCmpOpF(context, nameof(SoftFloat32.FPCompareGE), scalar: true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Fcmge_V(EmitterContext context)
|
||||||
|
{
|
||||||
|
if (Optimizations.FastFP && Optimizations.UseSse2)
|
||||||
|
{
|
||||||
|
EmitCmpSseOrSse2OpF(context, CmpCondition.GreaterThanOrEqual, scalar: false);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
EmitCmpOpF(context, nameof(SoftFloat32.FPCompareGE), scalar: false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Fcmgt_S(EmitterContext context)
|
||||||
|
{
|
||||||
|
if (Optimizations.FastFP && Optimizations.UseSse2)
|
||||||
|
{
|
||||||
|
EmitCmpSseOrSse2OpF(context, CmpCondition.GreaterThan, scalar: true);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
EmitCmpOpF(context, nameof(SoftFloat32.FPCompareGT), scalar: true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Fcmgt_V(EmitterContext context)
|
||||||
|
{
|
||||||
|
if (Optimizations.FastFP && Optimizations.UseSse2)
|
||||||
|
{
|
||||||
|
EmitCmpSseOrSse2OpF(context, CmpCondition.GreaterThan, scalar: false);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
EmitCmpOpF(context, nameof(SoftFloat32.FPCompareGT), scalar: false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Fcmle_S(EmitterContext context)
|
||||||
|
{
|
||||||
|
if (Optimizations.FastFP && Optimizations.UseSse2)
|
||||||
|
{
|
||||||
|
EmitCmpSseOrSse2OpF(context, CmpCondition.GreaterThanOrEqual, scalar: true, isLeOrLt: true);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
EmitCmpOpF(context, nameof(SoftFloat32.FPCompareLE), scalar: true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Fcmle_V(EmitterContext context)
|
||||||
|
{
|
||||||
|
if (Optimizations.FastFP && Optimizations.UseSse2)
|
||||||
|
{
|
||||||
|
EmitCmpSseOrSse2OpF(context, CmpCondition.GreaterThanOrEqual, scalar: false, isLeOrLt: true);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
EmitCmpOpF(context, nameof(SoftFloat32.FPCompareLE), scalar: false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Fcmlt_S(EmitterContext context)
|
||||||
|
{
|
||||||
|
if (Optimizations.FastFP && Optimizations.UseSse2)
|
||||||
|
{
|
||||||
|
EmitCmpSseOrSse2OpF(context, CmpCondition.GreaterThan, scalar: true, isLeOrLt: true);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
EmitCmpOpF(context, nameof(SoftFloat32.FPCompareLT), scalar: true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Fcmlt_V(EmitterContext context)
|
||||||
|
{
|
||||||
|
if (Optimizations.FastFP && Optimizations.UseSse2)
|
||||||
|
{
|
||||||
|
EmitCmpSseOrSse2OpF(context, CmpCondition.GreaterThan, scalar: false, isLeOrLt: true);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
EmitCmpOpF(context, nameof(SoftFloat32.FPCompareLT), scalar: false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Fcmp_S(EmitterContext context)
|
||||||
|
{
|
||||||
|
EmitFcmpOrFcmpe(context, signalNaNs: false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Fcmpe_S(EmitterContext context)
|
||||||
|
{
|
||||||
|
EmitFcmpOrFcmpe(context, signalNaNs: true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void EmitFccmpOrFccmpe(EmitterContext context, bool signalNaNs)
|
||||||
|
{
|
||||||
|
OpCodeSimdFcond op = (OpCodeSimdFcond)context.CurrOp;
|
||||||
|
|
||||||
|
Operand lblTrue = Label();
|
||||||
|
Operand lblEnd = Label();
|
||||||
|
|
||||||
|
context.BranchIfTrue(lblTrue, InstEmitFlowHelper.GetCondTrue(context, op.Cond));
|
||||||
|
|
||||||
|
EmitSetNzcv(context, Const(op.Nzcv));
|
||||||
|
|
||||||
|
context.Branch(lblEnd);
|
||||||
|
|
||||||
|
context.MarkLabel(lblTrue);
|
||||||
|
|
||||||
|
EmitFcmpOrFcmpe(context, signalNaNs);
|
||||||
|
|
||||||
|
context.MarkLabel(lblEnd);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void EmitFcmpOrFcmpe(EmitterContext context, bool signalNaNs)
|
||||||
|
{
|
||||||
|
OpCodeSimdReg op = (OpCodeSimdReg)context.CurrOp;
|
||||||
|
|
||||||
|
const int cmpOrdered = 7;
|
||||||
|
|
||||||
|
bool cmpWithZero = !(op is OpCodeSimdFcond) ? op.Bit3 : false;
|
||||||
|
|
||||||
|
if (Optimizations.FastFP && Optimizations.UseSse2)
|
||||||
|
{
|
||||||
|
Operand n = GetVec(op.Rn);
|
||||||
|
Operand m = cmpWithZero ? context.VectorZero() : GetVec(op.Rm);
|
||||||
|
|
||||||
|
Operand lblNaN = Label();
|
||||||
|
Operand lblEnd = Label();
|
||||||
|
|
||||||
|
if (op.Size == 0)
|
||||||
|
{
|
||||||
|
Operand ordMask = context.AddIntrinsic(Instruction.X86Cmpss, n, m, Const(cmpOrdered));
|
||||||
|
|
||||||
|
Operand isOrdered = context.VectorExtract16(ordMask, Local(OperandType.I32), 0);
|
||||||
|
|
||||||
|
context.BranchIfFalse(lblNaN, isOrdered);
|
||||||
|
|
||||||
|
Operand cf = context.AddIntrinsicInt(Instruction.X86Comissge, n, m);
|
||||||
|
Operand zf = context.AddIntrinsicInt(Instruction.X86Comisseq, n, m);
|
||||||
|
Operand nf = context.AddIntrinsicInt(Instruction.X86Comisslt, n, m);
|
||||||
|
|
||||||
|
context.Copy(GetFlag(PState.VFlag), Const(0));
|
||||||
|
context.Copy(GetFlag(PState.CFlag), cf);
|
||||||
|
context.Copy(GetFlag(PState.ZFlag), zf);
|
||||||
|
context.Copy(GetFlag(PState.NFlag), nf);
|
||||||
|
}
|
||||||
|
else /* if (op.Size == 1) */
|
||||||
|
{
|
||||||
|
Operand ordMask = context.AddIntrinsic(Instruction.X86Cmpsd, n, m, Const(cmpOrdered));
|
||||||
|
|
||||||
|
Operand isOrdered = context.VectorExtract16(ordMask, Local(OperandType.I32), 0);
|
||||||
|
|
||||||
|
context.BranchIfFalse(lblNaN, isOrdered);
|
||||||
|
|
||||||
|
Operand cf = context.AddIntrinsicInt(Instruction.X86Comisdge, n, m);
|
||||||
|
Operand zf = context.AddIntrinsicInt(Instruction.X86Comisdeq, n, m);
|
||||||
|
Operand nf = context.AddIntrinsicInt(Instruction.X86Comisdlt, n, m);
|
||||||
|
|
||||||
|
context.Copy(GetFlag(PState.VFlag), Const(0));
|
||||||
|
context.Copy(GetFlag(PState.CFlag), cf);
|
||||||
|
context.Copy(GetFlag(PState.ZFlag), zf);
|
||||||
|
context.Copy(GetFlag(PState.NFlag), nf);
|
||||||
|
}
|
||||||
|
|
||||||
|
context.Branch(lblEnd);
|
||||||
|
|
||||||
|
context.MarkLabel(lblNaN);
|
||||||
|
|
||||||
|
context.Copy(GetFlag(PState.VFlag), Const(1));
|
||||||
|
context.Copy(GetFlag(PState.CFlag), Const(1));
|
||||||
|
context.Copy(GetFlag(PState.ZFlag), Const(0));
|
||||||
|
context.Copy(GetFlag(PState.NFlag), Const(0));
|
||||||
|
|
||||||
|
context.MarkLabel(lblEnd);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
OperandType type = op.Size != 0 ? OperandType.FP64 : OperandType.FP32;
|
||||||
|
|
||||||
|
Operand ne = context.VectorExtract(GetVec(op.Rn), Local(type), 0);
|
||||||
|
Operand me;
|
||||||
|
|
||||||
|
if (cmpWithZero)
|
||||||
|
{
|
||||||
|
me = op.Size == 0 ? ConstF(0f) : ConstF(0d);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
me = context.VectorExtract(GetVec(op.Rm), Local(type), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
Operand nzcv = EmitSoftFloatCall(context, nameof(SoftFloat32.FPCompare), ne, me, Const(signalNaNs));
|
||||||
|
|
||||||
|
EmitSetNzcv(context, nzcv);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void EmitSetNzcv(EmitterContext context, Operand nzcv)
|
||||||
|
{
|
||||||
|
Operand Extract(Operand value, int bit)
|
||||||
|
{
|
||||||
|
if (bit != 0)
|
||||||
|
{
|
||||||
|
value = context.ShiftRightUI(value, Const(bit));
|
||||||
|
}
|
||||||
|
|
||||||
|
value = context.BitwiseAnd(value, Const(1));
|
||||||
|
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
context.Copy(GetFlag(PState.VFlag), Extract(nzcv, 0));
|
||||||
|
context.Copy(GetFlag(PState.CFlag), Extract(nzcv, 1));
|
||||||
|
context.Copy(GetFlag(PState.ZFlag), Extract(nzcv, 2));
|
||||||
|
context.Copy(GetFlag(PState.NFlag), Extract(nzcv, 3));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void EmitCmpOp(EmitterContext context, Func2I emitCmp, bool scalar)
|
||||||
|
{
|
||||||
|
OpCodeSimd op = (OpCodeSimd)context.CurrOp;
|
||||||
|
|
||||||
|
Operand res = context.VectorZero();
|
||||||
|
|
||||||
|
int elems = !scalar ? op.GetBytesCount() >> op.Size : 1;
|
||||||
|
|
||||||
|
ulong szMask = ulong.MaxValue >> (64 - (8 << op.Size));
|
||||||
|
|
||||||
|
for (int index = 0; index < elems; index++)
|
||||||
|
{
|
||||||
|
Operand ne = EmitVectorExtractSx(context, op.Rn, index, op.Size);
|
||||||
|
Operand me;
|
||||||
|
|
||||||
|
if (op is OpCodeSimdReg binOp)
|
||||||
|
{
|
||||||
|
me = EmitVectorExtractSx(context, binOp.Rm, index, op.Size);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
me = Const(0L);
|
||||||
|
}
|
||||||
|
|
||||||
|
Operand isTrue = emitCmp(ne, me);
|
||||||
|
|
||||||
|
Operand mask = context.ConditionalSelect(isTrue, Const(szMask), Const(0L));
|
||||||
|
|
||||||
|
res = EmitVectorInsert(context, res, mask, index, op.Size);
|
||||||
|
}
|
||||||
|
|
||||||
|
context.Copy(GetVec(op.Rd), res);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void EmitCmtstOp(EmitterContext context, bool scalar)
|
||||||
|
{
|
||||||
|
OpCodeSimdReg op = (OpCodeSimdReg)context.CurrOp;
|
||||||
|
|
||||||
|
Operand res = context.VectorZero();
|
||||||
|
|
||||||
|
int elems = !scalar ? op.GetBytesCount() >> op.Size : 1;
|
||||||
|
|
||||||
|
ulong szMask = ulong.MaxValue >> (64 - (8 << op.Size));
|
||||||
|
|
||||||
|
for (int index = 0; index < elems; index++)
|
||||||
|
{
|
||||||
|
Operand ne = EmitVectorExtractZx(context, op.Rn, index, op.Size);
|
||||||
|
Operand me = EmitVectorExtractZx(context, op.Rm, index, op.Size);
|
||||||
|
|
||||||
|
Operand test = context.BitwiseAnd(ne, me);
|
||||||
|
|
||||||
|
Operand isTrue = context.ICompareNotEqual(test, Const(0L));
|
||||||
|
|
||||||
|
Operand mask = context.ConditionalSelect(isTrue, Const(szMask), Const(0L));
|
||||||
|
|
||||||
|
res = EmitVectorInsert(context, res, mask, index, op.Size);
|
||||||
|
}
|
||||||
|
|
||||||
|
context.Copy(GetVec(op.Rd), res);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void EmitCmpOpF(EmitterContext context, string name, bool scalar)
|
||||||
|
{
|
||||||
|
OpCodeSimd op = (OpCodeSimd)context.CurrOp;
|
||||||
|
|
||||||
|
Operand res = context.VectorZero();
|
||||||
|
|
||||||
|
int sizeF = op.Size & 1;
|
||||||
|
|
||||||
|
OperandType type = sizeF != 0 ? OperandType.FP64 : OperandType.FP32;
|
||||||
|
|
||||||
|
int elems = !scalar ? op.GetBytesCount() >> sizeF + 2 : 1;
|
||||||
|
|
||||||
|
for (int index = 0; index < elems; index++)
|
||||||
|
{
|
||||||
|
Operand ne = context.VectorExtract(GetVec(op.Rn), Local(type), index);
|
||||||
|
Operand me;
|
||||||
|
|
||||||
|
if (op is OpCodeSimdReg binOp)
|
||||||
|
{
|
||||||
|
me = context.VectorExtract(GetVec(binOp.Rm), Local(type), index);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
me = sizeF == 0 ? ConstF(0f) : ConstF(0d);
|
||||||
|
}
|
||||||
|
|
||||||
|
Operand e = EmitSoftFloatCall(context, name, ne, me);
|
||||||
|
|
||||||
|
res = context.VectorInsert(res, e, index);
|
||||||
|
}
|
||||||
|
|
||||||
|
context.Copy(GetVec(op.Rd), res);
|
||||||
|
}
|
||||||
|
|
||||||
|
private enum CmpCondition
|
||||||
|
{
|
||||||
|
Equal = 0,
|
||||||
|
GreaterThanOrEqual = 5,
|
||||||
|
GreaterThan = 6
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void EmitCmpSseOrSse2OpF(
|
||||||
|
EmitterContext context,
|
||||||
|
CmpCondition cond,
|
||||||
|
bool scalar,
|
||||||
|
bool isLeOrLt = false)
|
||||||
|
{
|
||||||
|
OpCodeSimd op = (OpCodeSimd)context.CurrOp;
|
||||||
|
|
||||||
|
Operand n = GetVec(op.Rn);
|
||||||
|
Operand m = op is OpCodeSimdReg binOp ? GetVec(binOp.Rm) : context.VectorZero();
|
||||||
|
|
||||||
|
int sizeF = op.Size & 1;
|
||||||
|
|
||||||
|
if (sizeF == 0)
|
||||||
|
{
|
||||||
|
Instruction inst = scalar ? Instruction.X86Cmpss : Instruction.X86Cmpps;
|
||||||
|
|
||||||
|
Operand res = isLeOrLt
|
||||||
|
? context.AddIntrinsic(inst, m, n, Const((int)cond))
|
||||||
|
: context.AddIntrinsic(inst, n, m, Const((int)cond));
|
||||||
|
|
||||||
|
if (scalar)
|
||||||
|
{
|
||||||
|
res = context.VectorZeroUpper96(res);
|
||||||
|
}
|
||||||
|
else if (op.RegisterSize == RegisterSize.Simd64)
|
||||||
|
{
|
||||||
|
res = context.VectorZeroUpper64(res);
|
||||||
|
}
|
||||||
|
|
||||||
|
context.Copy(GetVec(op.Rd), res);
|
||||||
|
}
|
||||||
|
else /* if (sizeF == 1) */
|
||||||
|
{
|
||||||
|
Instruction inst = scalar ? Instruction.X86Cmpsd : Instruction.X86Cmppd;
|
||||||
|
|
||||||
|
Operand res = isLeOrLt
|
||||||
|
? context.AddIntrinsic(inst, m, n, Const((int)cond))
|
||||||
|
: context.AddIntrinsic(inst, n, m, Const((int)cond));
|
||||||
|
|
||||||
|
if (scalar)
|
||||||
|
{
|
||||||
|
res = context.VectorZeroUpper64(res);
|
||||||
|
}
|
||||||
|
|
||||||
|
context.Copy(GetVec(op.Rd), res);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -669,8 +669,10 @@ namespace ARMeilleure.Instructions
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int FPCompare(float value1, float value2, bool signalNaNs, ExecutionContext context)
|
public static int FPCompare(float value1, float value2, bool signalNaNs)
|
||||||
{
|
{
|
||||||
|
ExecutionContext context = NativeInterface.GetContext();
|
||||||
|
|
||||||
value1 = value1.FPUnpack(out FPType type1, out bool sign1, out _, context);
|
value1 = value1.FPUnpack(out FPType type1, out bool sign1, out _, context);
|
||||||
value2 = value2.FPUnpack(out FPType type2, out bool sign2, out _, context);
|
value2 = value2.FPUnpack(out FPType type2, out bool sign2, out _, context);
|
||||||
|
|
||||||
|
@ -1730,8 +1732,10 @@ namespace ARMeilleure.Instructions
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int FPCompare(double value1, double value2, bool signalNaNs, ExecutionContext context)
|
public static int FPCompare(double value1, double value2, bool signalNaNs)
|
||||||
{
|
{
|
||||||
|
ExecutionContext context = NativeInterface.GetContext();
|
||||||
|
|
||||||
value1 = value1.FPUnpack(out FPType type1, out bool sign1, out _, context);
|
value1 = value1.FPUnpack(out FPType type1, out bool sign1, out _, context);
|
||||||
value2 = value2.FPUnpack(out FPType type2, out bool sign2, out _, context);
|
value2 = value2.FPUnpack(out FPType type2, out bool sign2, out _, context);
|
||||||
|
|
||||||
|
|
|
@ -76,6 +76,14 @@ namespace ARMeilleure.IntermediateRepresentation
|
||||||
X86Andnps,
|
X86Andnps,
|
||||||
X86Cmppd,
|
X86Cmppd,
|
||||||
X86Cmpps,
|
X86Cmpps,
|
||||||
|
X86Cmpsd,
|
||||||
|
X86Cmpss,
|
||||||
|
X86Comisdeq,
|
||||||
|
X86Comisdge,
|
||||||
|
X86Comisdlt,
|
||||||
|
X86Comisseq,
|
||||||
|
X86Comissge,
|
||||||
|
X86Comisslt,
|
||||||
X86Cvtdq2pd,
|
X86Cvtdq2pd,
|
||||||
X86Cvtdq2ps,
|
X86Cvtdq2ps,
|
||||||
X86Cvtpd2dq,
|
X86Cvtpd2dq,
|
||||||
|
|
|
@ -10,6 +10,11 @@ namespace ARMeilleure.IntermediateRepresentation
|
||||||
return type == OperandType.I32 ? new Operand((int)value) : new Operand(value);
|
return type == OperandType.I32 ? new Operand((int)value) : new Operand(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Operand Const(bool value)
|
||||||
|
{
|
||||||
|
return new Operand(value ? 1 : 0);
|
||||||
|
}
|
||||||
|
|
||||||
public static Operand Const(int value)
|
public static Operand Const(int value)
|
||||||
{
|
{
|
||||||
return new Operand(value);
|
return new Operand(value);
|
||||||
|
|
|
@ -7,9 +7,9 @@ namespace ARMeilleure.State
|
||||||
private ulong _e0;
|
private ulong _e0;
|
||||||
private ulong _e1;
|
private ulong _e1;
|
||||||
|
|
||||||
public V128(float value) : this(value, value, value, value) { }
|
public V128(float value) : this(value, 0, 0, 0) { }
|
||||||
|
|
||||||
public V128(double value) : this(value, value) { }
|
public V128(double value) : this(value, 0) { }
|
||||||
|
|
||||||
public V128(float e0, float e1, float e2, float e3)
|
public V128(float e0, float e1, float e2, float e3)
|
||||||
{
|
{
|
||||||
|
@ -84,12 +84,15 @@ namespace ARMeilleure.State
|
||||||
|
|
||||||
public uint GetUInt32(int index)
|
public uint GetUInt32(int index)
|
||||||
{
|
{
|
||||||
if ((uint)index > 3)
|
switch (index)
|
||||||
{
|
{
|
||||||
throw new ArgumentOutOfRangeException(nameof(index));
|
case 0: return (uint)(_e0 >> 0);
|
||||||
|
case 1: return (uint)(_e0 >> 32);
|
||||||
|
case 2: return (uint)(_e1 >> 0);
|
||||||
|
case 3: return (uint)(_e1 >> 32);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (uint)(GetUInt64(index >> 1) >> (index & 1));
|
throw new ArgumentOutOfRangeException(nameof(index));
|
||||||
}
|
}
|
||||||
|
|
||||||
public ulong GetUInt64(int index)
|
public ulong GetUInt64(int index)
|
||||||
|
|
|
@ -7,46 +7,6 @@ namespace Ryujinx.Tests.Unicorn
|
||||||
private ulong _e0;
|
private ulong _e0;
|
||||||
private ulong _e1;
|
private ulong _e1;
|
||||||
|
|
||||||
public SimdValue(float value) : this(value, value, value, value) { }
|
|
||||||
|
|
||||||
public SimdValue(double value) : this(value, value) { }
|
|
||||||
|
|
||||||
public SimdValue(float e0, float e1, float e2, float e3)
|
|
||||||
{
|
|
||||||
_e0 = (ulong)(uint)BitConverter.SingleToInt32Bits(e0) << 0;
|
|
||||||
_e0 |= (ulong)(uint)BitConverter.SingleToInt32Bits(e1) << 32;
|
|
||||||
_e1 = (ulong)(uint)BitConverter.SingleToInt32Bits(e2) << 0;
|
|
||||||
_e1 |= (ulong)(uint)BitConverter.SingleToInt32Bits(e3) << 32;
|
|
||||||
}
|
|
||||||
|
|
||||||
public SimdValue(double e0, double e1)
|
|
||||||
{
|
|
||||||
_e0 = (ulong)BitConverter.DoubleToInt64Bits(e0);
|
|
||||||
_e1 = (ulong)BitConverter.DoubleToInt64Bits(e1);
|
|
||||||
}
|
|
||||||
|
|
||||||
public SimdValue(int e0, int e1, int e2, int e3)
|
|
||||||
{
|
|
||||||
_e0 = (ulong)(uint)e0 << 0;
|
|
||||||
_e0 |= (ulong)(uint)e1 << 32;
|
|
||||||
_e1 = (ulong)(uint)e2 << 0;
|
|
||||||
_e1 |= (ulong)(uint)e3 << 32;
|
|
||||||
}
|
|
||||||
|
|
||||||
public SimdValue(uint e0, uint e1, uint e2, uint e3)
|
|
||||||
{
|
|
||||||
_e0 = (ulong)e0 << 0;
|
|
||||||
_e0 |= (ulong)e1 << 32;
|
|
||||||
_e1 = (ulong)e2 << 0;
|
|
||||||
_e1 |= (ulong)e3 << 32;
|
|
||||||
}
|
|
||||||
|
|
||||||
public SimdValue(long e0, long e1)
|
|
||||||
{
|
|
||||||
_e0 = (ulong)e0;
|
|
||||||
_e1 = (ulong)e1;
|
|
||||||
}
|
|
||||||
|
|
||||||
public SimdValue(ulong e0, ulong e1)
|
public SimdValue(ulong e0, ulong e1)
|
||||||
{
|
{
|
||||||
_e0 = e0;
|
_e0 = e0;
|
||||||
|
@ -84,12 +44,15 @@ namespace Ryujinx.Tests.Unicorn
|
||||||
|
|
||||||
public uint GetUInt32(int index)
|
public uint GetUInt32(int index)
|
||||||
{
|
{
|
||||||
if ((uint)index > 3)
|
switch (index)
|
||||||
{
|
{
|
||||||
throw new ArgumentOutOfRangeException(nameof(index));
|
case 0: return (uint)(_e0 >> 0);
|
||||||
|
case 1: return (uint)(_e0 >> 32);
|
||||||
|
case 2: return (uint)(_e1 >> 0);
|
||||||
|
case 3: return (uint)(_e1 >> 32);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (uint)(GetUInt64(index >> 1) >> (index & 1));
|
throw new ArgumentOutOfRangeException(nameof(index));
|
||||||
}
|
}
|
||||||
|
|
||||||
public ulong GetUInt64(int index)
|
public ulong GetUInt64(int index)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue