ARMeilleure: replace else-ifs with switch statements #124
@ -1445,17 +1445,16 @@ namespace ARMeilleure.CodeGen.Arm64
|
||||
return false;
|
||||
}
|
||||
|
||||
if (currentOp.Instruction == Instruction.Load)
|
||||
switch (currentOp.Instruction)
|
||||
{
|
||||
context.Assembler.LdpRiUn(currentOp.Destination, nextOp.Destination, op1Base, op1Offset);
|
||||
}
|
||||
else if (currentOp.Instruction == Instruction.Store)
|
||||
{
|
||||
context.Assembler.StpRiUn(currentOp.GetSource(1), nextOp.GetSource(1), op1Base, op1Offset);
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
case Instruction.Load:
|
||||
context.Assembler.LdpRiUn(currentOp.Destination, nextOp.Destination, op1Base, op1Offset);
|
||||
break;
|
||||
case Instruction.Store:
|
||||
context.Assembler.StpRiUn(currentOp.GetSource(1), nextOp.GetSource(1), op1Base, op1Offset);
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -1099,17 +1099,14 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
|
||||
|
||||
private static int GetOperandId(Operand operand)
|
||||
{
|
||||
if (operand.Kind == OperandKind.LocalVariable)
|
||||
switch (operand.Kind)
|
||||
{
|
||||
return operand.GetLocalNumber();
|
||||
}
|
||||
else if (operand.Kind == OperandKind.Register)
|
||||
{
|
||||
return GetRegisterId(operand.GetRegister());
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new ArgumentException($"Invalid operand kind \"{operand.Kind}\".");
|
||||
case OperandKind.LocalVariable:
|
||||
return operand.GetLocalNumber();
|
||||
case OperandKind.Register:
|
||||
return GetRegisterId(operand.GetRegister());
|
||||
default:
|
||||
throw new ArgumentException($"Invalid operand kind \"{operand.Kind}\".");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -33,17 +33,14 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
|
||||
|
||||
public int GetAvailableRegisters(RegisterType type)
|
||||
{
|
||||
if (type == RegisterType.Integer)
|
||||
switch (type)
|
||||
{
|
||||
return IntAvailableRegisters;
|
||||
}
|
||||
else if (type == RegisterType.Vector)
|
||||
{
|
||||
return VecAvailableRegisters;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new ArgumentException($"Invalid register type \"{type}\".");
|
||||
case RegisterType.Integer:
|
||||
return IntAvailableRegisters;
|
||||
case RegisterType.Vector:
|
||||
return VecAvailableRegisters;
|
||||
default:
|
||||
throw new ArgumentException($"Invalid register type \"{type}\".");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -754,73 +754,79 @@ namespace ARMeilleure.CodeGen.X86
|
||||
|
||||
if (source != default)
|
||||
{
|
||||
if (source.Kind == OperandKind.Constant)
|
||||
switch (source.Kind)
|
||||
{
|
||||
ulong imm = source.Value;
|
||||
case OperandKind.Constant:
|
||||
ulong imm = source.Value;
|
||||
|
||||
if (inst == X86Instruction.Mov8)
|
||||
{
|
||||
WriteOpCode(dest, default, default, type, info.Flags, info.OpRMImm8);
|
||||
|
||||
WriteByte((byte)imm);
|
||||
}
|
||||
else if (inst == X86Instruction.Mov16)
|
||||
{
|
||||
WriteOpCode(dest, default, default, type, info.Flags, info.OpRMImm32);
|
||||
|
||||
WriteInt16((short)imm);
|
||||
}
|
||||
else if (IsImm8(imm, type) && info.OpRMImm8 != BadOp)
|
||||
{
|
||||
WriteOpCode(dest, default, default, type, info.Flags, info.OpRMImm8);
|
||||
|
||||
WriteByte((byte)imm);
|
||||
}
|
||||
else if (!source.Relocatable && IsImm32(imm, type) && info.OpRMImm32 != BadOp)
|
||||
{
|
||||
WriteOpCode(dest, default, default, type, info.Flags, info.OpRMImm32);
|
||||
|
||||
WriteInt32((int)imm);
|
||||
}
|
||||
else if (dest != default && dest.Kind == OperandKind.Register && info.OpRImm64 != BadOp)
|
||||
{
|
||||
int rexPrefix = GetRexPrefix(dest, source, type, rrm: false);
|
||||
|
||||
if (rexPrefix != 0)
|
||||
if (inst == X86Instruction.Mov8)
|
||||
{
|
||||
WriteByte((byte)rexPrefix);
|
||||
WriteOpCode(dest, default, default, type, info.Flags, info.OpRMImm8);
|
||||
|
||||
WriteByte((byte)imm);
|
||||
}
|
||||
|
||||
WriteByte((byte)(info.OpRImm64 + (dest.GetRegister().Index & 0b111)));
|
||||
|
||||
if (HasRelocs && source.Relocatable)
|
||||
else if (inst == X86Instruction.Mov16)
|
||||
{
|
||||
_relocs.Add(new Reloc
|
||||
WriteOpCode(dest, default, default, type, info.Flags, info.OpRMImm32);
|
||||
|
||||
WriteInt16((short)imm);
|
||||
}
|
||||
else if (IsImm8(imm, type) && info.OpRMImm8 != BadOp)
|
||||
{
|
||||
WriteOpCode(dest, default, default, type, info.Flags, info.OpRMImm8);
|
||||
|
||||
WriteByte((byte)imm);
|
||||
}
|
||||
else if (!source.Relocatable && IsImm32(imm, type) && info.OpRMImm32 != BadOp)
|
||||
{
|
||||
WriteOpCode(dest, default, default, type, info.Flags, info.OpRMImm32);
|
||||
|
||||
WriteInt32((int)imm);
|
||||
}
|
||||
else if (dest != default && dest.Kind == OperandKind.Register && info.OpRImm64 != BadOp)
|
||||
{
|
||||
int rexPrefix = GetRexPrefix(dest, source, type, rrm: false);
|
||||
|
||||
if (rexPrefix != 0)
|
||||
{
|
||||
JumpIndex = _jumps.Count - 1,
|
||||
Position = (int)_stream.Position,
|
||||
Symbol = source.Symbol,
|
||||
});
|
||||
WriteByte((byte)rexPrefix);
|
||||
}
|
||||
|
||||
WriteByte((byte)(info.OpRImm64 + (dest.GetRegister().Index & 0b111)));
|
||||
|
||||
if (HasRelocs && source.Relocatable)
|
||||
{
|
||||
_relocs.Add(new Reloc
|
||||
{
|
||||
JumpIndex = _jumps.Count - 1,
|
||||
Position = (int)_stream.Position,
|
||||
Symbol = source.Symbol,
|
||||
});
|
||||
}
|
||||
|
||||
WriteUInt64(imm);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new ArgumentException($"Failed to encode constant 0x{imm:X}.");
|
||||
}
|
||||
|
||||
WriteUInt64(imm);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new ArgumentException($"Failed to encode constant 0x{imm:X}.");
|
||||
}
|
||||
}
|
||||
else if (source.Kind == OperandKind.Register && info.OpRMR != BadOp)
|
||||
{
|
||||
WriteOpCode(dest, default, source, type, info.Flags, info.OpRMR);
|
||||
}
|
||||
else if (info.OpRRM != BadOp)
|
||||
{
|
||||
WriteOpCode(dest, default, source, type, info.Flags, info.OpRRM, rrm: true);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new ArgumentException($"Invalid source operand kind \"{source.Kind}\".");
|
||||
break;
|
||||
|
||||
case OperandKind.Register when info.OpRMR != BadOp:
|
||||
WriteOpCode(dest, default, source, type, info.Flags, info.OpRMR);
|
||||
break;
|
||||
default:
|
||||
if (info.OpRRM != BadOp)
|
||||
{
|
||||
WriteOpCode(dest, default, source, type, info.Flags, info.OpRRM, rrm: true);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new ArgumentException($"Invalid source operand kind \"{source.Kind}\".");
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (info.OpRRM != BadOp)
|
||||
@ -848,32 +854,39 @@ namespace ARMeilleure.CodeGen.X86
|
||||
|
||||
if (src2 != default)
|
||||
{
|
||||
if (src2.Kind == OperandKind.Constant)
|
||||
switch (src2.Kind)
|
||||
{
|
||||
ulong imm = src2.Value;
|
||||
case OperandKind.Constant:
|
||||
ulong imm = src2.Value;
|
||||
|
||||
if ((byte)imm == imm && info.OpRMImm8 != BadOp)
|
||||
{
|
||||
WriteOpCode(dest, src1, default, type, info.Flags, info.OpRMImm8);
|
||||
if ((byte)imm == imm && info.OpRMImm8 != BadOp)
|
||||
{
|
||||
WriteOpCode(dest, src1, default, type, info.Flags, info.OpRMImm8);
|
||||
|
||||
WriteByte((byte)imm);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new ArgumentException($"Failed to encode constant 0x{imm:X}.");
|
||||
}
|
||||
}
|
||||
else if (src2.Kind == OperandKind.Register && info.OpRMR != BadOp)
|
||||
{
|
||||
WriteOpCode(dest, src1, src2, type, info.Flags, info.OpRMR);
|
||||
}
|
||||
else if (info.OpRRM != BadOp)
|
||||
{
|
||||
WriteOpCode(dest, src1, src2, type, info.Flags, info.OpRRM, rrm: true);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new ArgumentException($"Invalid source operand kind \"{src2.Kind}\".");
|
||||
WriteByte((byte)imm);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new ArgumentException($"Failed to encode constant 0x{imm:X}.");
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case OperandKind.Register when info.OpRMR != BadOp:
|
||||
WriteOpCode(dest, src1, src2, type, info.Flags, info.OpRMR);
|
||||
break;
|
||||
|
||||
default:
|
||||
if (info.OpRRM != BadOp)
|
||||
{
|
||||
WriteOpCode(dest, src1, src2, type, info.Flags, info.OpRRM, rrm: true);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new ArgumentException($"Invalid source operand kind \"{src2.Kind}\".");
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (info.OpRRM != BadOp)
|
||||
@ -913,49 +926,53 @@ namespace ARMeilleure.CodeGen.X86
|
||||
|
||||
if (dest != default)
|
||||
{
|
||||
if (dest.Kind == OperandKind.Register)
|
||||
switch (dest.Kind)
|
||||
{
|
||||
int regIndex = dest.GetRegister().Index;
|
||||
case OperandKind.Register:
|
||||
int regIndex = dest.GetRegister().Index;
|
||||
|
||||
modRM |= (regIndex & 0b111) << (rrm ? 3 : 0);
|
||||
modRM |= (regIndex & 0b111) << (rrm ? 3 : 0);
|
||||
|
||||
if ((flags & InstructionFlags.Reg8Dest) != 0 && regIndex >= 4)
|
||||
{
|
||||
rexPrefix |= RexPrefix;
|
||||
}
|
||||
}
|
||||
else if (dest.Kind == OperandKind.Memory)
|
||||
{
|
||||
memOp = dest.GetMemory();
|
||||
hasMemOp = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new ArgumentException("Invalid destination operand kind \"" + dest.Kind + "\".");
|
||||
if ((flags & InstructionFlags.Reg8Dest) != 0 && regIndex >= 4)
|
||||
{
|
||||
rexPrefix |= RexPrefix;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case OperandKind.Memory:
|
||||
memOp = dest.GetMemory();
|
||||
hasMemOp = true;
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new ArgumentException("Invalid destination operand kind \"" + dest.Kind + "\".");
|
||||
}
|
||||
}
|
||||
|
||||
if (src2 != default)
|
||||
{
|
||||
if (src2.Kind == OperandKind.Register)
|
||||
switch (src2.Kind)
|
||||
{
|
||||
int regIndex = src2.GetRegister().Index;
|
||||
case OperandKind.Register:
|
||||
int regIndex = src2.GetRegister().Index;
|
||||
|
||||
modRM |= (regIndex & 0b111) << (rrm ? 0 : 3);
|
||||
modRM |= (regIndex & 0b111) << (rrm ? 0 : 3);
|
||||
|
||||
if ((flags & InstructionFlags.Reg8Src) != 0 && regIndex >= 4)
|
||||
{
|
||||
rexPrefix |= RexPrefix;
|
||||
}
|
||||
}
|
||||
else if (src2.Kind == OperandKind.Memory && !hasMemOp)
|
||||
{
|
||||
memOp = src2.GetMemory();
|
||||
hasMemOp = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new ArgumentException("Invalid source operand kind \"" + src2.Kind + "\".");
|
||||
if ((flags & InstructionFlags.Reg8Src) != 0 && regIndex >= 4)
|
||||
{
|
||||
rexPrefix |= RexPrefix;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case OperandKind.Memory when !hasMemOp:
|
||||
memOp = src2.GetMemory();
|
||||
hasMemOp = true;
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new ArgumentException("Invalid source operand kind \"" + src2.Kind + "\".");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -423,25 +423,24 @@ namespace ARMeilleure.CodeGen.X86
|
||||
|
||||
Debug.Assert(!dest.Type.IsInteger());
|
||||
|
||||
if (info.Inst == X86Instruction.Blendvpd && HardwareCapabilities.SupportsVexEncoding)
|
||||
switch (info.Inst)
|
||||
{
|
||||
context.Assembler.WriteInstruction(X86Instruction.Vblendvpd, dest, src1, src2, src3);
|
||||
}
|
||||
else if (info.Inst == X86Instruction.Blendvps && HardwareCapabilities.SupportsVexEncoding)
|
||||
{
|
||||
context.Assembler.WriteInstruction(X86Instruction.Vblendvps, dest, src1, src2, src3);
|
||||
}
|
||||
else if (info.Inst == X86Instruction.Pblendvb && HardwareCapabilities.SupportsVexEncoding)
|
||||
{
|
||||
context.Assembler.WriteInstruction(X86Instruction.Vpblendvb, dest, src1, src2, src3);
|
||||
}
|
||||
else
|
||||
{
|
||||
EnsureSameReg(dest, src1);
|
||||
case X86Instruction.Blendvpd when HardwareCapabilities.SupportsVexEncoding:
|
||||
context.Assembler.WriteInstruction(X86Instruction.Vblendvpd, dest, src1, src2, src3);
|
||||
break;
|
||||
case X86Instruction.Blendvps when HardwareCapabilities.SupportsVexEncoding:
|
||||
context.Assembler.WriteInstruction(X86Instruction.Vblendvps, dest, src1, src2, src3);
|
||||
break;
|
||||
case X86Instruction.Pblendvb when HardwareCapabilities.SupportsVexEncoding:
|
||||
context.Assembler.WriteInstruction(X86Instruction.Vpblendvb, dest, src1, src2, src3);
|
||||
break;
|
||||
default:
|
||||
EnsureSameReg(dest, src1);
|
||||
|
||||
Debug.Assert(src3.GetRegister().Index == 0);
|
||||
Debug.Assert(src3.GetRegister().Index == 0);
|
||||
|
||||
context.Assembler.WriteInstruction(info.Inst, dest, src1, src2);
|
||||
context.Assembler.WriteInstruction(info.Inst, dest, src1, src2);
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
@ -1406,88 +1405,91 @@ namespace ARMeilleure.CodeGen.X86
|
||||
}
|
||||
}
|
||||
|
||||
if (src2.Type == OperandType.I32)
|
||||
switch (src2.Type)
|
||||
{
|
||||
Debug.Assert(index < 4);
|
||||
case OperandType.I32:
|
||||
Debug.Assert(index < 4);
|
||||
|
||||
if (HardwareCapabilities.SupportsSse41)
|
||||
{
|
||||
context.Assembler.Pinsrd(dest, src1, src2, index);
|
||||
}
|
||||
else
|
||||
{
|
||||
InsertIntSse2(2);
|
||||
}
|
||||
}
|
||||
else if (src2.Type == OperandType.I64)
|
||||
{
|
||||
Debug.Assert(index < 2);
|
||||
|
||||
if (HardwareCapabilities.SupportsSse41)
|
||||
{
|
||||
context.Assembler.Pinsrq(dest, src1, src2, index);
|
||||
}
|
||||
else
|
||||
{
|
||||
InsertIntSse2(4);
|
||||
}
|
||||
}
|
||||
else if (src2.Type == OperandType.FP32)
|
||||
{
|
||||
Debug.Assert(index < 4);
|
||||
|
||||
if (index != 0)
|
||||
{
|
||||
if (HardwareCapabilities.SupportsSse41)
|
||||
{
|
||||
context.Assembler.Insertps(dest, src1, src2, (byte)(index << 4));
|
||||
context.Assembler.Pinsrd(dest, src1, src2, index);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (src1.GetRegister() == src2.GetRegister())
|
||||
InsertIntSse2(2);
|
||||
}
|
||||
break;
|
||||
case OperandType.I64:
|
||||
Debug.Assert(index < 2);
|
||||
|
||||
if (HardwareCapabilities.SupportsSse41)
|
||||
{
|
||||
context.Assembler.Pinsrq(dest, src1, src2, index);
|
||||
}
|
||||
else
|
||||
{
|
||||
InsertIntSse2(4);
|
||||
}
|
||||
break;
|
||||
case OperandType.FP32:
|
||||
{
|
||||
Debug.Assert(index < 4);
|
||||
|
||||
if (index != 0)
|
||||
{
|
||||
int mask = 0b11_10_01_00;
|
||||
if (HardwareCapabilities.SupportsSse41)
|
||||
{
|
||||
context.Assembler.Insertps(dest, src1, src2, (byte)(index << 4));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (src1.GetRegister() == src2.GetRegister())
|
||||
{
|
||||
int mask = 0b11_10_01_00;
|
||||
|
||||
mask &= ~(0b11 << index * 2);
|
||||
mask &= ~(0b11 << index * 2);
|
||||
|
||||
context.Assembler.Pshufd(dest, src1, (byte)mask);
|
||||
context.Assembler.Pshufd(dest, src1, (byte)mask);
|
||||
}
|
||||
else
|
||||
{
|
||||
int mask0 = 0b11_10_01_00;
|
||||
int mask1 = 0b11_10_01_00;
|
||||
|
||||
mask0 = BitUtils.RotateRight(mask0, index * 2, 8);
|
||||
mask1 = BitUtils.RotateRight(mask1, 8 - index * 2, 8);
|
||||
|
||||
context.Assembler.Pshufd(src1, src1, (byte)mask0); // Lane to be inserted in position 0.
|
||||
context.Assembler.Movss(dest, src1, src2); // dest[127:0] = src1[127:32] | src2[31:0]
|
||||
context.Assembler.Pshufd(dest, dest, (byte)mask1); // Inserted lane in original position.
|
||||
|
||||
if (dest.GetRegister() != src1.GetRegister())
|
||||
{
|
||||
context.Assembler.Pshufd(src1, src1, (byte)mask1); // Restore src1.
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
int mask0 = 0b11_10_01_00;
|
||||
int mask1 = 0b11_10_01_00;
|
||||
|
||||
mask0 = BitUtils.RotateRight(mask0, index * 2, 8);
|
||||
mask1 = BitUtils.RotateRight(mask1, 8 - index * 2, 8);
|
||||
|
||||
context.Assembler.Pshufd(src1, src1, (byte)mask0); // Lane to be inserted in position 0.
|
||||
context.Assembler.Movss(dest, src1, src2); // dest[127:0] = src1[127:32] | src2[31:0]
|
||||
context.Assembler.Pshufd(dest, dest, (byte)mask1); // Inserted lane in original position.
|
||||
|
||||
if (dest.GetRegister() != src1.GetRegister())
|
||||
{
|
||||
context.Assembler.Pshufd(src1, src1, (byte)mask1); // Restore src1.
|
||||
}
|
||||
context.Assembler.Movss(dest, src1, src2);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
context.Assembler.Movss(dest, src1, src2);
|
||||
}
|
||||
}
|
||||
else /* if (src2.Type == OperandType.FP64) */
|
||||
{
|
||||
Debug.Assert(index < 2);
|
||||
|
||||
if (index != 0)
|
||||
{
|
||||
context.Assembler.Movlhps(dest, src1, src2);
|
||||
}
|
||||
else
|
||||
{
|
||||
context.Assembler.Movsd(dest, src1, src2);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
Debug.Assert(index < 2);
|
||||
|
||||
if (index != 0)
|
||||
{
|
||||
context.Assembler.Movlhps(dest, src1, src2);
|
||||
}
|
||||
else
|
||||
{
|
||||
context.Assembler.Movsd(dest, src1, src2);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -141,19 +141,18 @@ namespace ARMeilleure.CodeGen.X86
|
||||
Operand constOp;
|
||||
Operand otherOp;
|
||||
|
||||
if (src1.Kind == OperandKind.Constant && src2.Kind == OperandKind.LocalVariable)
|
||||
switch (src1.Kind)
|
||||
{
|
||||
constOp = src1;
|
||||
otherOp = src2;
|
||||
}
|
||||
else if (src1.Kind == OperandKind.LocalVariable && src2.Kind == OperandKind.Constant)
|
||||
{
|
||||
constOp = src2;
|
||||
otherOp = src1;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
case OperandKind.Constant when src2.Kind == OperandKind.LocalVariable:
|
||||
constOp = src1;
|
||||
otherOp = src2;
|
||||
break;
|
||||
case OperandKind.LocalVariable when src2.Kind == OperandKind.Constant:
|
||||
constOp = src2;
|
||||
otherOp = src1;
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
// If we have addition by 64-bits constant, then we can't optimize it further,
|
||||
|
@ -10,30 +10,31 @@ namespace ARMeilleure.Decoders
|
||||
|
||||
public OpCodeAluImm(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
|
||||
{
|
||||
if (DataOp == DataOp.Arithmetic)
|
||||
switch (DataOp)
|
||||
{
|
||||
Immediate = (opCode >> 10) & 0xfff;
|
||||
case DataOp.Arithmetic:
|
||||
Immediate = opCode >> 10 & 0xfff;
|
||||
|
||||
int shift = (opCode >> 22) & 3;
|
||||
int shift = opCode >> 22 & 3;
|
||||
|
||||
Immediate <<= shift * 12;
|
||||
}
|
||||
else if (DataOp == DataOp.Logical)
|
||||
{
|
||||
var bm = DecoderHelper.DecodeBitMask(opCode, true);
|
||||
Immediate <<= shift * 12;
|
||||
break;
|
||||
|
||||
if (bm.IsUndefined)
|
||||
{
|
||||
Instruction = InstDescriptor.Undefined;
|
||||
case DataOp.Logical:
|
||||
var bm = DecoderHelper.DecodeBitMask(opCode, true);
|
||||
|
||||
return;
|
||||
}
|
||||
if (bm.IsUndefined)
|
||||
{
|
||||
Instruction = InstDescriptor.Undefined;
|
||||
|
||||
Immediate = bm.WMask;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new ArgumentException($"Invalid data operation: {DataOp}", nameof(opCode));
|
||||
return;
|
||||
}
|
||||
|
||||
Immediate = bm.WMask;
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new ArgumentException($"Invalid data operation: {DataOp}", nameof(opCode));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1438,27 +1438,28 @@ namespace ARMeilleure.Decoders
|
||||
// but 00 isn't.
|
||||
char chr = encoding[index];
|
||||
|
||||
if (chr == '1')
|
||||
switch (chr)
|
||||
{
|
||||
value |= 1 << bit;
|
||||
}
|
||||
else if (chr == 'x')
|
||||
{
|
||||
xMask |= 1 << bit;
|
||||
}
|
||||
else if (chr == '>')
|
||||
{
|
||||
xPos[xBits++] = bit;
|
||||
}
|
||||
else if (chr == '<')
|
||||
{
|
||||
xPos[xBits++] = bit;
|
||||
case '1':
|
||||
value |= 1 << bit;
|
||||
break;
|
||||
case 'x':
|
||||
xMask |= 1 << bit;
|
||||
break;
|
||||
case '>':
|
||||
xPos[xBits++] = bit;
|
||||
break;
|
||||
case '<':
|
||||
xPos[xBits++] = bit;
|
||||
blacklisted |= 1 << bit;
|
||||
break;
|
||||
default:
|
||||
if (chr != '0')
|
||||
{
|
||||
throw new ArgumentException($"Invalid encoding: {encoding}", nameof(encoding));
|
||||
}
|
||||
|
||||
blacklisted |= 1 << bit;
|
||||
}
|
||||
else if (chr != '0')
|
||||
{
|
||||
throw new ArgumentException($"Invalid encoding: {encoding}", nameof(encoding));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1214,17 +1214,17 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
elementAction(tempD, nByte, mByte);
|
||||
|
||||
if (b == 0)
|
||||
switch (b)
|
||||
{
|
||||
result = context.ZeroExtend8(OperandType.I32, tempD);
|
||||
}
|
||||
else if (b < 3)
|
||||
{
|
||||
result = context.BitwiseOr(result, context.ShiftLeft(context.ZeroExtend8(OperandType.I32, tempD), Const(b * 8)));
|
||||
}
|
||||
else
|
||||
{
|
||||
result = context.BitwiseOr(result, context.ShiftLeft(tempD, Const(24)));
|
||||
case 0:
|
||||
result = context.ZeroExtend8(OperandType.I32, tempD);
|
||||
break;
|
||||
case < 3:
|
||||
result = context.BitwiseOr(result, context.ShiftLeft(context.ZeroExtend8(OperandType.I32, tempD), Const(b * 8)));
|
||||
break;
|
||||
default:
|
||||
result = context.BitwiseOr(result, context.ShiftLeft(tempD, Const(24)));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -69,32 +69,37 @@ namespace ARMeilleure.Instructions
|
||||
// read all the data at once. For a 32-bits pairwise load, we do a
|
||||
// simple 64-bits load, for a 128-bits load, we need to call a special
|
||||
// method to read 128-bits atomically.
|
||||
if (op.Size == 2)
|
||||
switch (op.Size)
|
||||
{
|
||||
Operand value = EmitLoadExclusive(context, address, exclusive, 3);
|
||||
case 2:
|
||||
{
|
||||
Operand value = EmitLoadExclusive(context, address, exclusive, 3);
|
||||
|
||||
Operand valueLow = context.ConvertI64ToI32(value);
|
||||
Operand valueLow = context.ConvertI64ToI32(value);
|
||||
|
||||
valueLow = context.ZeroExtend32(OperandType.I64, valueLow);
|
||||
valueLow = context.ZeroExtend32(OperandType.I64, valueLow);
|
||||
|
||||
Operand valueHigh = context.ShiftRightUI(value, Const(32));
|
||||
Operand valueHigh = context.ShiftRightUI(value, Const(32));
|
||||
|
||||
SetIntOrZR(context, op.Rt, valueLow);
|
||||
SetIntOrZR(context, op.Rt2, valueHigh);
|
||||
}
|
||||
else if (op.Size == 3)
|
||||
{
|
||||
Operand value = EmitLoadExclusive(context, address, exclusive, 4);
|
||||
SetIntOrZR(context, op.Rt, valueLow);
|
||||
SetIntOrZR(context, op.Rt2, valueHigh);
|
||||
break;
|
||||
}
|
||||
|
||||
Operand valueLow = context.VectorExtract(OperandType.I64, value, 0);
|
||||
Operand valueHigh = context.VectorExtract(OperandType.I64, value, 1);
|
||||
case 3:
|
||||
{
|
||||
Operand value = EmitLoadExclusive(context, address, exclusive, 4);
|
||||
|
||||
SetIntOrZR(context, op.Rt, valueLow);
|
||||
SetIntOrZR(context, op.Rt2, valueHigh);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new InvalidOperationException($"Invalid load size of {1 << op.Size} bytes.");
|
||||
Operand valueLow = context.VectorExtract(OperandType.I64, value, 0);
|
||||
Operand valueHigh = context.VectorExtract(OperandType.I64, value, 1);
|
||||
|
||||
SetIntOrZR(context, op.Rt, valueLow);
|
||||
SetIntOrZR(context, op.Rt2, valueHigh);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
throw new InvalidOperationException($"Invalid load size of {1 << op.Size} bytes.");
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -338,17 +338,17 @@ namespace ARMeilleure.Instructions
|
||||
value = context.ConvertI64ToI32(value);
|
||||
}
|
||||
|
||||
if (size == 0)
|
||||
switch (size)
|
||||
{
|
||||
context.Store8(physAddr, value);
|
||||
}
|
||||
else if (size == 1)
|
||||
{
|
||||
context.Store16(physAddr, value);
|
||||
}
|
||||
else
|
||||
{
|
||||
context.Store(physAddr, value);
|
||||
case 0:
|
||||
context.Store8(physAddr, value);
|
||||
break;
|
||||
case 1:
|
||||
context.Store16(physAddr, value);
|
||||
break;
|
||||
default:
|
||||
context.Store(physAddr, value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -100,40 +100,48 @@ namespace ARMeilleure.Instructions
|
||||
{
|
||||
Operand res = GetVec(op.Rn);
|
||||
|
||||
if (op.Size == 0)
|
||||
switch (op.Size)
|
||||
{
|
||||
if (op.DstIndex != 0)
|
||||
{
|
||||
res = context.AddIntrinsic(Intrinsic.X86Psrldq, res, Const(op.DstIndex));
|
||||
}
|
||||
case 0:
|
||||
if (op.DstIndex != 0)
|
||||
{
|
||||
res = context.AddIntrinsic(Intrinsic.X86Psrldq, res, Const(op.DstIndex));
|
||||
}
|
||||
|
||||
res = context.AddIntrinsic(Intrinsic.X86Punpcklbw, res, res);
|
||||
res = context.AddIntrinsic(Intrinsic.X86Punpcklwd, res, res);
|
||||
res = context.AddIntrinsic(Intrinsic.X86Shufps, res, res, Const(0));
|
||||
}
|
||||
else if (op.Size == 1)
|
||||
{
|
||||
if (op.DstIndex != 0)
|
||||
{
|
||||
res = context.AddIntrinsic(Intrinsic.X86Psrldq, res, Const(op.DstIndex * 2));
|
||||
}
|
||||
res = context.AddIntrinsic(Intrinsic.X86Punpcklbw, res, res);
|
||||
res = context.AddIntrinsic(Intrinsic.X86Punpcklwd, res, res);
|
||||
res = context.AddIntrinsic(Intrinsic.X86Shufps, res, res, Const(0));
|
||||
break;
|
||||
|
||||
res = context.AddIntrinsic(Intrinsic.X86Punpcklwd, res, res);
|
||||
res = context.AddIntrinsic(Intrinsic.X86Shufps, res, res, Const(0));
|
||||
}
|
||||
else if (op.Size == 2)
|
||||
{
|
||||
int mask = op.DstIndex * 0b01010101;
|
||||
case 1:
|
||||
if (op.DstIndex != 0)
|
||||
{
|
||||
res = context.AddIntrinsic(Intrinsic.X86Psrldq, res, Const(op.DstIndex * 2));
|
||||
}
|
||||
|
||||
res = context.AddIntrinsic(Intrinsic.X86Shufps, res, res, Const(mask));
|
||||
}
|
||||
else if (op.DstIndex == 0 && op.RegisterSize != RegisterSize.Simd64)
|
||||
{
|
||||
res = context.AddIntrinsic(Intrinsic.X86Movlhps, res, res);
|
||||
}
|
||||
else if (op.DstIndex == 1)
|
||||
{
|
||||
res = context.AddIntrinsic(Intrinsic.X86Movhlps, res, res);
|
||||
res = context.AddIntrinsic(Intrinsic.X86Punpcklwd, res, res);
|
||||
res = context.AddIntrinsic(Intrinsic.X86Shufps, res, res, Const(0));
|
||||
break;
|
||||
|
||||
case 2:
|
||||
{
|
||||
int mask = op.DstIndex * 0b01010101;
|
||||
|
||||
res = context.AddIntrinsic(Intrinsic.X86Shufps, res, res, Const(mask));
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
if (op.DstIndex == 0 && op.RegisterSize != RegisterSize.Simd64)
|
||||
{
|
||||
res = context.AddIntrinsic(Intrinsic.X86Movlhps, res, res);
|
||||
}
|
||||
else if (op.DstIndex == 1)
|
||||
{
|
||||
res = context.AddIntrinsic(Intrinsic.X86Movhlps, res, res);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (op.RegisterSize == RegisterSize.Simd64)
|
||||
|
@ -221,54 +221,60 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
if (op.U)
|
||||
{
|
||||
if (op.Size < 2)
|
||||
switch (op.Size)
|
||||
{
|
||||
EmitVectorUnaryOpZx32(context, (op1) =>
|
||||
{
|
||||
op1 = context.Add(op1, Const(op1.Type, roundConst));
|
||||
case < 2:
|
||||
EmitVectorUnaryOpZx32(context, (op1) =>
|
||||
{
|
||||
op1 = context.Add(op1, Const(op1.Type, roundConst));
|
||||
|
||||
return context.ShiftRightUI(op1, Const(shift));
|
||||
}, accumulate);
|
||||
}
|
||||
else if (op.Size == 2)
|
||||
{
|
||||
EmitVectorUnaryOpZx32(context, (op1) =>
|
||||
{
|
||||
op1 = context.ZeroExtend32(OperandType.I64, op1);
|
||||
op1 = context.Add(op1, Const(op1.Type, roundConst));
|
||||
return context.ShiftRightUI(op1, Const(shift));
|
||||
}, accumulate);
|
||||
break;
|
||||
|
||||
return context.ConvertI64ToI32(context.ShiftRightUI(op1, Const(shift)));
|
||||
}, accumulate);
|
||||
}
|
||||
else /* if (op.Size == 3) */
|
||||
{
|
||||
EmitVectorUnaryOpZx32(context, (op1) => EmitShrImm64(context, op1, signed: false, roundConst, shift), accumulate);
|
||||
case 2:
|
||||
EmitVectorUnaryOpZx32(context, (op1) =>
|
||||
{
|
||||
op1 = context.ZeroExtend32(OperandType.I64, op1);
|
||||
op1 = context.Add(op1, Const(op1.Type, roundConst));
|
||||
|
||||
return context.ConvertI64ToI32(context.ShiftRightUI(op1, Const(shift)));
|
||||
}, accumulate);
|
||||
break;
|
||||
|
||||
default: // case 3
|
||||
{
|
||||
EmitVectorUnaryOpZx32(context, (op1) => EmitShrImm64(context, op1, signed: false, roundConst, shift), accumulate);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (op.Size < 2)
|
||||
switch (op.Size)
|
||||
{
|
||||
EmitVectorUnaryOpSx32(context, (op1) =>
|
||||
{
|
||||
op1 = context.Add(op1, Const(op1.Type, roundConst));
|
||||
case < 2:
|
||||
EmitVectorUnaryOpSx32(context, (op1) =>
|
||||
{
|
||||
op1 = context.Add(op1, Const(op1.Type, roundConst));
|
||||
|
||||
return context.ShiftRightSI(op1, Const(shift));
|
||||
}, accumulate);
|
||||
}
|
||||
else if (op.Size == 2)
|
||||
{
|
||||
EmitVectorUnaryOpSx32(context, (op1) =>
|
||||
{
|
||||
op1 = context.SignExtend32(OperandType.I64, op1);
|
||||
op1 = context.Add(op1, Const(op1.Type, roundConst));
|
||||
return context.ShiftRightSI(op1, Const(shift));
|
||||
}, accumulate);
|
||||
break;
|
||||
|
||||
return context.ConvertI64ToI32(context.ShiftRightSI(op1, Const(shift)));
|
||||
}, accumulate);
|
||||
}
|
||||
else /* if (op.Size == 3) */
|
||||
{
|
||||
EmitVectorUnaryOpZx32(context, (op1) => EmitShrImm64(context, op1, signed: true, roundConst, shift), accumulate);
|
||||
case 2:
|
||||
EmitVectorUnaryOpSx32(context, (op1) =>
|
||||
{
|
||||
op1 = context.SignExtend32(OperandType.I64, op1);
|
||||
op1 = context.Add(op1, Const(op1.Type, roundConst));
|
||||
|
||||
return context.ConvertI64ToI32(context.ShiftRightSI(op1, Const(shift)));
|
||||
}, accumulate);
|
||||
break;
|
||||
|
||||
default: // case 3
|
||||
EmitVectorUnaryOpZx32(context, (op1) => EmitShrImm64(context, op1, signed: true, roundConst, shift), accumulate);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -495,33 +495,33 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
double result;
|
||||
|
||||
if (type == FPType.SNaN || type == FPType.QNaN)
|
||||
switch (type)
|
||||
{
|
||||
if ((context.Fpcr & FPCR.Dn) != 0)
|
||||
{
|
||||
result = SoftFloat64.FPDefaultNaN();
|
||||
}
|
||||
else
|
||||
{
|
||||
result = FPConvertNaN(valueBits);
|
||||
}
|
||||
case FPType.SNaN:
|
||||
case FPType.QNaN:
|
||||
if ((context.Fpcr & FPCR.Dn) != 0)
|
||||
{
|
||||
result = SoftFloat64.FPDefaultNaN();
|
||||
}
|
||||
else
|
||||
{
|
||||
result = FPConvertNaN(valueBits);
|
||||
}
|
||||
|
||||
if (type == FPType.SNaN)
|
||||
{
|
||||
SoftFloat.FPProcessException(FPException.InvalidOp, context);
|
||||
}
|
||||
}
|
||||
else if (type == FPType.Infinity)
|
||||
{
|
||||
result = SoftFloat64.FPInfinity(sign);
|
||||
}
|
||||
else if (type == FPType.Zero)
|
||||
{
|
||||
result = SoftFloat64.FPZero(sign);
|
||||
}
|
||||
else
|
||||
{
|
||||
result = FPRoundCv(real, context);
|
||||
if (type == FPType.SNaN)
|
||||
{
|
||||
SoftFloat.FPProcessException(FPException.InvalidOp, context);
|
||||
}
|
||||
break;
|
||||
case FPType.Infinity:
|
||||
result = SoftFloat64.FPInfinity(sign);
|
||||
break;
|
||||
case FPType.Zero:
|
||||
result = SoftFloat64.FPZero(sign);
|
||||
break;
|
||||
default:
|
||||
result = FPRoundCv(real, context);
|
||||
break;
|
||||
}
|
||||
|
||||
return result;
|
||||
@ -672,46 +672,49 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
ushort resultBits;
|
||||
|
||||
if (type == FPType.SNaN || type == FPType.QNaN)
|
||||
switch (type)
|
||||
{
|
||||
if (altHp)
|
||||
{
|
||||
case FPType.SNaN:
|
||||
case FPType.QNaN:
|
||||
if (altHp)
|
||||
{
|
||||
resultBits = SoftFloat16.FPZero(sign);
|
||||
}
|
||||
else if ((context.Fpcr & FPCR.Dn) != 0)
|
||||
{
|
||||
resultBits = SoftFloat16.FPDefaultNaN();
|
||||
}
|
||||
else
|
||||
{
|
||||
resultBits = FPConvertNaN(valueBits);
|
||||
}
|
||||
|
||||
if (type == FPType.SNaN || altHp)
|
||||
{
|
||||
SoftFloat.FPProcessException(FPException.InvalidOp, context);
|
||||
}
|
||||
break;
|
||||
|
||||
case FPType.Infinity:
|
||||
if (altHp)
|
||||
{
|
||||
resultBits = (ushort)((sign ? 1u : 0u) << 15 | 0x7FFFu);
|
||||
|
||||
SoftFloat.FPProcessException(FPException.InvalidOp, context);
|
||||
}
|
||||
else
|
||||
{
|
||||
resultBits = SoftFloat16.FPInfinity(sign);
|
||||
}
|
||||
break;
|
||||
|
||||
case FPType.Zero:
|
||||
resultBits = SoftFloat16.FPZero(sign);
|
||||
}
|
||||
else if ((context.Fpcr & FPCR.Dn) != 0)
|
||||
{
|
||||
resultBits = SoftFloat16.FPDefaultNaN();
|
||||
}
|
||||
else
|
||||
{
|
||||
resultBits = FPConvertNaN(valueBits);
|
||||
}
|
||||
break;
|
||||
|
||||
if (type == FPType.SNaN || altHp)
|
||||
{
|
||||
SoftFloat.FPProcessException(FPException.InvalidOp, context);
|
||||
}
|
||||
}
|
||||
else if (type == FPType.Infinity)
|
||||
{
|
||||
if (altHp)
|
||||
{
|
||||
resultBits = (ushort)((sign ? 1u : 0u) << 15 | 0x7FFFu);
|
||||
|
||||
SoftFloat.FPProcessException(FPException.InvalidOp, context);
|
||||
}
|
||||
else
|
||||
{
|
||||
resultBits = SoftFloat16.FPInfinity(sign);
|
||||
}
|
||||
}
|
||||
else if (type == FPType.Zero)
|
||||
{
|
||||
resultBits = SoftFloat16.FPZero(sign);
|
||||
}
|
||||
else
|
||||
{
|
||||
resultBits = SoftFloat16.FPRoundCv(real, context);
|
||||
default:
|
||||
resultBits = SoftFloat16.FPRoundCv(real, context);
|
||||
break;
|
||||
}
|
||||
|
||||
return resultBits;
|
||||
@ -1056,46 +1059,46 @@ namespace ARMeilleure.Instructions
|
||||
{
|
||||
if (value1 > value2)
|
||||
{
|
||||
if (type1 == FPType.Infinity)
|
||||
switch (type1)
|
||||
{
|
||||
result = FPInfinity(sign1);
|
||||
}
|
||||
else if (type1 == FPType.Zero)
|
||||
{
|
||||
result = FPZero(sign1 && sign2);
|
||||
}
|
||||
else
|
||||
{
|
||||
result = value1;
|
||||
case FPType.Infinity:
|
||||
result = FPInfinity(sign1);
|
||||
break;
|
||||
case FPType.Zero:
|
||||
result = FPZero(sign1 && sign2);
|
||||
break;
|
||||
default:
|
||||
result = value1;
|
||||
|
||||
if ((fpcr & FPCR.Fz) != 0 && float.IsSubnormal(result))
|
||||
{
|
||||
context.Fpsr |= FPSR.Ufc;
|
||||
if ((fpcr & FPCR.Fz) != 0 && float.IsSubnormal(result))
|
||||
{
|
||||
context.Fpsr |= FPSR.Ufc;
|
||||
|
||||
result = FPZero(result < 0f);
|
||||
}
|
||||
result = FPZero(result < 0f);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (type2 == FPType.Infinity)
|
||||
switch (type2)
|
||||
{
|
||||
result = FPInfinity(sign2);
|
||||
}
|
||||
else if (type2 == FPType.Zero)
|
||||
{
|
||||
result = FPZero(sign1 && sign2);
|
||||
}
|
||||
else
|
||||
{
|
||||
result = value2;
|
||||
case FPType.Infinity:
|
||||
result = FPInfinity(sign2);
|
||||
break;
|
||||
case FPType.Zero:
|
||||
result = FPZero(sign1 && sign2);
|
||||
break;
|
||||
default:
|
||||
result = value2;
|
||||
|
||||
if ((fpcr & FPCR.Fz) != 0 && float.IsSubnormal(result))
|
||||
{
|
||||
context.Fpsr |= FPSR.Ufc;
|
||||
if ((fpcr & FPCR.Fz) != 0 && float.IsSubnormal(result))
|
||||
{
|
||||
context.Fpsr |= FPSR.Ufc;
|
||||
|
||||
result = FPZero(result < 0f);
|
||||
}
|
||||
result = FPZero(result < 0f);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1147,46 +1150,46 @@ namespace ARMeilleure.Instructions
|
||||
{
|
||||
if (value1 < value2)
|
||||
{
|
||||
if (type1 == FPType.Infinity)
|
||||
switch (type1)
|
||||
{
|
||||
result = FPInfinity(sign1);
|
||||
}
|
||||
else if (type1 == FPType.Zero)
|
||||
{
|
||||
result = FPZero(sign1 || sign2);
|
||||
}
|
||||
else
|
||||
{
|
||||
result = value1;
|
||||
case FPType.Infinity:
|
||||
result = FPInfinity(sign1);
|
||||
break;
|
||||
case FPType.Zero:
|
||||
result = FPZero(sign1 || sign2);
|
||||
break;
|
||||
default:
|
||||
result = value1;
|
||||
|
||||
if ((fpcr & FPCR.Fz) != 0 && float.IsSubnormal(result))
|
||||
{
|
||||
context.Fpsr |= FPSR.Ufc;
|
||||
if ((fpcr & FPCR.Fz) != 0 && float.IsSubnormal(result))
|
||||
{
|
||||
context.Fpsr |= FPSR.Ufc;
|
||||
|
||||
result = FPZero(result < 0f);
|
||||
}
|
||||
result = FPZero(result < 0f);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (type2 == FPType.Infinity)
|
||||
switch (type2)
|
||||
{
|
||||
result = FPInfinity(sign2);
|
||||
}
|
||||
else if (type2 == FPType.Zero)
|
||||
{
|
||||
result = FPZero(sign1 || sign2);
|
||||
}
|
||||
else
|
||||
{
|
||||
result = value2;
|
||||
case FPType.Infinity:
|
||||
result = FPInfinity(sign2);
|
||||
break;
|
||||
case FPType.Zero:
|
||||
result = FPZero(sign1 || sign2);
|
||||
break;
|
||||
default:
|
||||
result = value2;
|
||||
|
||||
if ((fpcr & FPCR.Fz) != 0 && float.IsSubnormal(result))
|
||||
{
|
||||
context.Fpsr |= FPSR.Ufc;
|
||||
if ((fpcr & FPCR.Fz) != 0 && float.IsSubnormal(result))
|
||||
{
|
||||
context.Fpsr |= FPSR.Ufc;
|
||||
|
||||
result = FPZero(result < 0f);
|
||||
}
|
||||
result = FPZero(result < 0f);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -184,41 +184,36 @@ namespace ARMeilleure.State
|
||||
|
||||
public unsafe static int GetRegisterOffset(Register reg)
|
||||
{
|
||||
if (reg.Type == RegisterType.Integer)
|
||||
switch (reg.Type)
|
||||
{
|
||||
if ((uint)reg.Index >= RegisterConsts.IntRegsCount)
|
||||
{
|
||||
throw new ArgumentException("Invalid register.");
|
||||
}
|
||||
case RegisterType.Integer:
|
||||
if ((uint)reg.Index >= RegisterConsts.IntRegsCount)
|
||||
{
|
||||
throw new ArgumentException("Invalid register.");
|
||||
}
|
||||
|
||||
return StorageOffset(ref _dummyStorage, ref _dummyStorage.X[reg.Index]);
|
||||
}
|
||||
else if (reg.Type == RegisterType.Vector)
|
||||
{
|
||||
if ((uint)reg.Index >= RegisterConsts.VecRegsCount)
|
||||
{
|
||||
throw new ArgumentException("Invalid register.");
|
||||
}
|
||||
return StorageOffset(ref _dummyStorage, ref _dummyStorage.X[reg.Index]);
|
||||
case RegisterType.Vector:
|
||||
if ((uint)reg.Index >= RegisterConsts.VecRegsCount)
|
||||
{
|
||||
throw new ArgumentException("Invalid register.");
|
||||
}
|
||||
|
||||
return StorageOffset(ref _dummyStorage, ref _dummyStorage.V[reg.Index * 2]);
|
||||
}
|
||||
else if (reg.Type == RegisterType.Flag)
|
||||
{
|
||||
if ((uint)reg.Index >= RegisterConsts.FlagsCount)
|
||||
{
|
||||
throw new ArgumentException("Invalid register.");
|
||||
}
|
||||
return StorageOffset(ref _dummyStorage, ref _dummyStorage.V[reg.Index * 2]);
|
||||
case RegisterType.Flag:
|
||||
if ((uint)reg.Index >= RegisterConsts.FlagsCount)
|
||||
{
|
||||
throw new ArgumentException("Invalid register.");
|
||||
}
|
||||
|
||||
return StorageOffset(ref _dummyStorage, ref _dummyStorage.Flags[reg.Index]);
|
||||
}
|
||||
else /* if (reg.Type == RegisterType.FpFlag) */
|
||||
{
|
||||
if ((uint)reg.Index >= RegisterConsts.FpFlagsCount)
|
||||
{
|
||||
throw new ArgumentException("Invalid register.");
|
||||
}
|
||||
return StorageOffset(ref _dummyStorage, ref _dummyStorage.Flags[reg.Index]);
|
||||
default: // case RegisterType.FpFlag
|
||||
if ((uint)reg.Index >= RegisterConsts.FpFlagsCount)
|
||||
{
|
||||
throw new ArgumentException("Invalid register.");
|
||||
}
|
||||
|
||||
return StorageOffset(ref _dummyStorage, ref _dummyStorage.FpFlags[reg.Index]);
|
||||
return StorageOffset(ref _dummyStorage, ref _dummyStorage.FpFlags[reg.Index]);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -137,20 +137,20 @@ namespace ARMeilleure.Translation.Cache
|
||||
|
||||
Debug.Assert(allocSize % 8 == 0);
|
||||
|
||||
if (allocSize <= 128)
|
||||
switch (allocSize)
|
||||
{
|
||||
_unwindInfo->UnwindCodes[codeIndex++] = PackUnwindOp(UnwindOp.AllocSmall, entry.PrologOffset, (allocSize / 8) - 1);
|
||||
}
|
||||
else if (allocSize <= 0x7FFF8)
|
||||
{
|
||||
_unwindInfo->UnwindCodes[codeIndex++] = PackUnwindOp(UnwindOp.AllocLarge, entry.PrologOffset, 0);
|
||||
_unwindInfo->UnwindCodes[codeIndex++] = (ushort)(allocSize / 8);
|
||||
}
|
||||
else
|
||||
{
|
||||
_unwindInfo->UnwindCodes[codeIndex++] = PackUnwindOp(UnwindOp.AllocLarge, entry.PrologOffset, 1);
|
||||
_unwindInfo->UnwindCodes[codeIndex++] = (ushort)(allocSize >> 0);
|
||||
_unwindInfo->UnwindCodes[codeIndex++] = (ushort)(allocSize >> 16);
|
||||
case <= 128:
|
||||
_unwindInfo->UnwindCodes[codeIndex++] = PackUnwindOp(UnwindOp.AllocSmall, entry.PrologOffset, (allocSize / 8) - 1);
|
||||
break;
|
||||
case <= 0x7FFF8:
|
||||
_unwindInfo->UnwindCodes[codeIndex++] = PackUnwindOp(UnwindOp.AllocLarge, entry.PrologOffset, 0);
|
||||
_unwindInfo->UnwindCodes[codeIndex++] = (ushort)(allocSize / 8);
|
||||
break;
|
||||
default:
|
||||
_unwindInfo->UnwindCodes[codeIndex++] = PackUnwindOp(UnwindOp.AllocLarge, entry.PrologOffset, 1);
|
||||
_unwindInfo->UnwindCodes[codeIndex++] = (ushort)(allocSize >> 0);
|
||||
_unwindInfo->UnwindCodes[codeIndex++] = (ushort)(allocSize >> 16);
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
|
@ -108,36 +108,36 @@ namespace ARMeilleure.Translation
|
||||
|
||||
protected static OperandType GetOperandType(Type type)
|
||||
{
|
||||
if (type == typeof(bool) || type == typeof(byte) ||
|
||||
type == typeof(char) || type == typeof(short) ||
|
||||
type == typeof(int) || type == typeof(sbyte) ||
|
||||
type == typeof(ushort) || type == typeof(uint))
|
||||
switch (Type.GetTypeCode(type))
|
||||
{
|
||||
return OperandType.I32;
|
||||
}
|
||||
else if (type == typeof(long) || type == typeof(ulong))
|
||||
{
|
||||
return OperandType.I64;
|
||||
}
|
||||
else if (type == typeof(double))
|
||||
{
|
||||
return OperandType.FP64;
|
||||
}
|
||||
else if (type == typeof(float))
|
||||
{
|
||||
return OperandType.FP32;
|
||||
}
|
||||
else if (type == typeof(V128))
|
||||
{
|
||||
return OperandType.V128;
|
||||
}
|
||||
else if (type == typeof(void))
|
||||
{
|
||||
return OperandType.None;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new ArgumentException($"Invalid type \"{type.Name}\".");
|
||||
case TypeCode.Boolean:
|
||||
case TypeCode.Byte:
|
||||
case TypeCode.Char:
|
||||
case TypeCode.Int16:
|
||||
case TypeCode.Int32:
|
||||
case TypeCode.SByte:
|
||||
case TypeCode.UInt16:
|
||||
case TypeCode.UInt32:
|
||||
return OperandType.I32;
|
||||
|
||||
case TypeCode.Int64:
|
||||
case TypeCode.UInt64:
|
||||
return OperandType.I64;
|
||||
|
||||
case TypeCode.Double:
|
||||
return OperandType.FP64;
|
||||
|
||||
case TypeCode.Single:
|
||||
return OperandType.FP32;
|
||||
|
||||
case TypeCode.Object when type == typeof(V128):
|
||||
return OperandType.V128;
|
||||
|
||||
case TypeCode.Object when type == typeof(void):
|
||||
return OperandType.None;
|
||||
|
||||
default:
|
||||
throw new ArgumentException($"Invalid type \"{type.Name}\".");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -152,17 +152,16 @@ namespace ARMeilleure.Translation
|
||||
while (node != null)
|
||||
{
|
||||
int cmp = key.CompareTo(node.Start);
|
||||
if (cmp < 0)
|
||||
switch (cmp)
|
||||
{
|
||||
node = node.Left;
|
||||
}
|
||||
else if (cmp > 0)
|
||||
{
|
||||
node = node.Right;
|
||||
}
|
||||
else
|
||||
{
|
||||
return node;
|
||||
case < 0:
|
||||
node = node.Left;
|
||||
break;
|
||||
case > 0:
|
||||
node = node.Right;
|
||||
break;
|
||||
default:
|
||||
return node;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
@ -272,43 +271,42 @@ namespace ARMeilleure.Translation
|
||||
{
|
||||
parent = node;
|
||||
int cmp = start.CompareTo(node.Start);
|
||||
if (cmp < 0)
|
||||
switch (cmp)
|
||||
{
|
||||
node = node.Left;
|
||||
}
|
||||
else if (cmp > 0)
|
||||
{
|
||||
node = node.Right;
|
||||
}
|
||||
else
|
||||
{
|
||||
outNode = node;
|
||||
case < 0:
|
||||
node = node.Left;
|
||||
break;
|
||||
case > 0:
|
||||
node = node.Right;
|
||||
break;
|
||||
default:
|
||||
outNode = node;
|
||||
|
||||
if (updateFactoryCallback != null)
|
||||
{
|
||||
// Replace
|
||||
node.Value = updateFactoryCallback(start, node.Value);
|
||||
|
||||
int endCmp = end.CompareTo(node.End);
|
||||
|
||||
if (endCmp > 0)
|
||||
if (updateFactoryCallback != null)
|
||||
{
|
||||
node.End = end;
|
||||
if (end.CompareTo(node.Max) > 0)
|
||||
// Replace
|
||||
node.Value = updateFactoryCallback(start, node.Value);
|
||||
|
||||
int endCmp = end.CompareTo(node.End);
|
||||
|
||||
if (endCmp > 0)
|
||||
{
|
||||
node.Max = end;
|
||||
PropagateIncrease(node);
|
||||
RestoreBalanceAfterInsertion(node);
|
||||
node.End = end;
|
||||
if (end.CompareTo(node.Max) > 0)
|
||||
{
|
||||
node.Max = end;
|
||||
PropagateIncrease(node);
|
||||
RestoreBalanceAfterInsertion(node);
|
||||
}
|
||||
}
|
||||
else if (endCmp < 0)
|
||||
{
|
||||
node.End = end;
|
||||
PropagateFull(node);
|
||||
}
|
||||
}
|
||||
else if (endCmp < 0)
|
||||
{
|
||||
node.End = end;
|
||||
PropagateFull(node);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
IntervalTreeNode<TK, TV> newNode = new(start, end, value, parent);
|
||||
|
@ -977,27 +977,24 @@ namespace ARMeilleure.Translation.PTC
|
||||
|
||||
private static FeatureInfo GetFeatureInfo()
|
||||
{
|
||||
if (RuntimeInformation.ProcessArchitecture == Architecture.Arm64)
|
||||
switch (RuntimeInformation.ProcessArchitecture)
|
||||
{
|
||||
return new FeatureInfo(
|
||||
(ulong)Arm64HardwareCapabilities.LinuxFeatureInfoHwCap,
|
||||
(ulong)Arm64HardwareCapabilities.LinuxFeatureInfoHwCap2,
|
||||
(ulong)Arm64HardwareCapabilities.MacOsFeatureInfo,
|
||||
0,
|
||||
0);
|
||||
}
|
||||
else if (RuntimeInformation.ProcessArchitecture == Architecture.X64)
|
||||
{
|
||||
return new FeatureInfo(
|
||||
(ulong)X86HardwareCapabilities.FeatureInfo1Ecx,
|
||||
(ulong)X86HardwareCapabilities.FeatureInfo1Edx,
|
||||
(ulong)X86HardwareCapabilities.FeatureInfo7Ebx,
|
||||
(ulong)X86HardwareCapabilities.FeatureInfo7Ecx,
|
||||
(ulong)X86HardwareCapabilities.Xcr0InfoEax);
|
||||
}
|
||||
else
|
||||
{
|
||||
return new FeatureInfo(0, 0, 0, 0, 0);
|
||||
case Architecture.Arm64:
|
||||
return new FeatureInfo(
|
||||
(ulong)Arm64HardwareCapabilities.LinuxFeatureInfoHwCap,
|
||||
(ulong)Arm64HardwareCapabilities.LinuxFeatureInfoHwCap2,
|
||||
(ulong)Arm64HardwareCapabilities.MacOsFeatureInfo,
|
||||
0,
|
||||
0);
|
||||
case Architecture.X64:
|
||||
return new FeatureInfo(
|
||||
(ulong)X86HardwareCapabilities.FeatureInfo1Ecx,
|
||||
(ulong)X86HardwareCapabilities.FeatureInfo1Edx,
|
||||
(ulong)X86HardwareCapabilities.FeatureInfo7Ebx,
|
||||
(ulong)X86HardwareCapabilities.FeatureInfo7Ecx,
|
||||
(ulong)X86HardwareCapabilities.Xcr0InfoEax);
|
||||
default:
|
||||
return new FeatureInfo(0, 0, 0, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -244,21 +244,20 @@ namespace ARMeilleure.Translation
|
||||
{
|
||||
Register reg = operand.GetRegister();
|
||||
|
||||
if (reg.Type == RegisterType.Integer)
|
||||
switch (reg.Type)
|
||||
{
|
||||
result = reg.Index;
|
||||
}
|
||||
else if (reg.Type == RegisterType.Vector)
|
||||
{
|
||||
result = RegisterConsts.IntRegsCount + reg.Index;
|
||||
}
|
||||
else if (reg.Type == RegisterType.Flag)
|
||||
{
|
||||
result = RegisterConsts.IntAndVecRegsCount + reg.Index;
|
||||
}
|
||||
else /* if (reg.Type == RegisterType.FpFlag) */
|
||||
{
|
||||
result = RegisterConsts.FpFlagsOffset + reg.Index;
|
||||
case RegisterType.Integer:
|
||||
result = reg.Index;
|
||||
break;
|
||||
case RegisterType.Vector:
|
||||
result = RegisterConsts.IntRegsCount + reg.Index;
|
||||
break;
|
||||
case RegisterType.Flag:
|
||||
result = RegisterConsts.IntAndVecRegsCount + reg.Index;
|
||||
break;
|
||||
default: // case RegisterType.FpFlag
|
||||
result = RegisterConsts.FpFlagsOffset + reg.Index;
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
Loading…
x
Reference in New Issue
Block a user