ARMeilleure: replace else-ifs with switch statements #124

Closed
LukeWarnut wants to merge 1 commits from switch-st into master
20 changed files with 675 additions and 651 deletions

View File

@ -1445,17 +1445,16 @@ namespace ARMeilleure.CodeGen.Arm64
return false; return false;
} }
if (currentOp.Instruction == Instruction.Load) switch (currentOp.Instruction)
{ {
context.Assembler.LdpRiUn(currentOp.Destination, nextOp.Destination, op1Base, op1Offset); case Instruction.Load:
} context.Assembler.LdpRiUn(currentOp.Destination, nextOp.Destination, op1Base, op1Offset);
else if (currentOp.Instruction == Instruction.Store) break;
{ case Instruction.Store:
context.Assembler.StpRiUn(currentOp.GetSource(1), nextOp.GetSource(1), op1Base, op1Offset); context.Assembler.StpRiUn(currentOp.GetSource(1), nextOp.GetSource(1), op1Base, op1Offset);
} break;
else default:
{ return false;
return false;
} }
return true; return true;

View File

@ -1099,17 +1099,14 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
private static int GetOperandId(Operand operand) private static int GetOperandId(Operand operand)
{ {
if (operand.Kind == OperandKind.LocalVariable) switch (operand.Kind)
{ {
return operand.GetLocalNumber(); case OperandKind.LocalVariable:
} return operand.GetLocalNumber();
else if (operand.Kind == OperandKind.Register) case OperandKind.Register:
{ return GetRegisterId(operand.GetRegister());
return GetRegisterId(operand.GetRegister()); default:
} throw new ArgumentException($"Invalid operand kind \"{operand.Kind}\".");
else
{
throw new ArgumentException($"Invalid operand kind \"{operand.Kind}\".");
} }
} }

View File

@ -33,17 +33,14 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
public int GetAvailableRegisters(RegisterType type) public int GetAvailableRegisters(RegisterType type)
{ {
if (type == RegisterType.Integer) switch (type)
{ {
return IntAvailableRegisters; case RegisterType.Integer:
} return IntAvailableRegisters;
else if (type == RegisterType.Vector) case RegisterType.Vector:
{ return VecAvailableRegisters;
return VecAvailableRegisters; default:
} throw new ArgumentException($"Invalid register type \"{type}\".");
else
{
throw new ArgumentException($"Invalid register type \"{type}\".");
} }
} }
} }

View File

@ -754,73 +754,79 @@ namespace ARMeilleure.CodeGen.X86
if (source != default) 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) 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)
{ {
WriteByte((byte)rexPrefix); WriteOpCode(dest, default, default, type, info.Flags, info.OpRMImm8);
WriteByte((byte)imm);
} }
else if (inst == X86Instruction.Mov16)
WriteByte((byte)(info.OpRImm64 + (dest.GetRegister().Index & 0b111)));
if (HasRelocs && source.Relocatable)
{ {
_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, WriteByte((byte)rexPrefix);
Position = (int)_stream.Position, }
Symbol = source.Symbol,
}); 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); break;
}
else case OperandKind.Register when info.OpRMR != BadOp:
{ WriteOpCode(dest, default, source, type, info.Flags, info.OpRMR);
throw new ArgumentException($"Failed to encode constant 0x{imm:X}."); break;
} default:
} if (info.OpRRM != BadOp)
else if (source.Kind == OperandKind.Register && info.OpRMR != BadOp) {
{ WriteOpCode(dest, default, source, type, info.Flags, info.OpRRM, rrm: true);
WriteOpCode(dest, default, source, type, info.Flags, info.OpRMR); }
} else
else if (info.OpRRM != BadOp) {
{ throw new ArgumentException($"Invalid source operand kind \"{source.Kind}\".");
WriteOpCode(dest, default, source, type, info.Flags, info.OpRRM, rrm: true); }
}
else break;
{
throw new ArgumentException($"Invalid source operand kind \"{source.Kind}\".");
} }
} }
else if (info.OpRRM != BadOp) else if (info.OpRRM != BadOp)
@ -848,32 +854,39 @@ namespace ARMeilleure.CodeGen.X86
if (src2 != default) 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) if ((byte)imm == imm && info.OpRMImm8 != BadOp)
{ {
WriteOpCode(dest, src1, default, type, info.Flags, info.OpRMImm8); WriteOpCode(dest, src1, default, type, info.Flags, info.OpRMImm8);
WriteByte((byte)imm); WriteByte((byte)imm);
} }
else else
{ {
throw new ArgumentException($"Failed to encode constant 0x{imm:X}."); throw new ArgumentException($"Failed to encode constant 0x{imm:X}.");
} }
}
else if (src2.Kind == OperandKind.Register && info.OpRMR != BadOp) break;
{
WriteOpCode(dest, src1, src2, type, info.Flags, info.OpRMR); case OperandKind.Register when info.OpRMR != BadOp:
} WriteOpCode(dest, src1, src2, type, info.Flags, info.OpRMR);
else if (info.OpRRM != BadOp) break;
{
WriteOpCode(dest, src1, src2, type, info.Flags, info.OpRRM, rrm: true); default:
} if (info.OpRRM != BadOp)
else {
{ WriteOpCode(dest, src1, src2, type, info.Flags, info.OpRRM, rrm: true);
throw new ArgumentException($"Invalid source operand kind \"{src2.Kind}\"."); }
else
{
throw new ArgumentException($"Invalid source operand kind \"{src2.Kind}\".");
}
break;
} }
} }
else if (info.OpRRM != BadOp) else if (info.OpRRM != BadOp)
@ -913,49 +926,53 @@ namespace ARMeilleure.CodeGen.X86
if (dest != default) 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) if ((flags & InstructionFlags.Reg8Dest) != 0 && regIndex >= 4)
{ {
rexPrefix |= RexPrefix; rexPrefix |= RexPrefix;
} }
}
else if (dest.Kind == OperandKind.Memory) break;
{
memOp = dest.GetMemory(); case OperandKind.Memory:
hasMemOp = true; memOp = dest.GetMemory();
} hasMemOp = true;
else break;
{
throw new ArgumentException("Invalid destination operand kind \"" + dest.Kind + "\"."); default:
throw new ArgumentException("Invalid destination operand kind \"" + dest.Kind + "\".");
} }
} }
if (src2 != default) 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) if ((flags & InstructionFlags.Reg8Src) != 0 && regIndex >= 4)
{ {
rexPrefix |= RexPrefix; rexPrefix |= RexPrefix;
} }
}
else if (src2.Kind == OperandKind.Memory && !hasMemOp) break;
{
memOp = src2.GetMemory(); case OperandKind.Memory when !hasMemOp:
hasMemOp = true; memOp = src2.GetMemory();
} hasMemOp = true;
else break;
{
throw new ArgumentException("Invalid source operand kind \"" + src2.Kind + "\"."); default:
throw new ArgumentException("Invalid source operand kind \"" + src2.Kind + "\".");
} }
} }

View File

@ -423,25 +423,24 @@ namespace ARMeilleure.CodeGen.X86
Debug.Assert(!dest.Type.IsInteger()); Debug.Assert(!dest.Type.IsInteger());
if (info.Inst == X86Instruction.Blendvpd && HardwareCapabilities.SupportsVexEncoding) switch (info.Inst)
{ {
context.Assembler.WriteInstruction(X86Instruction.Vblendvpd, dest, src1, src2, src3); case X86Instruction.Blendvpd when HardwareCapabilities.SupportsVexEncoding:
} context.Assembler.WriteInstruction(X86Instruction.Vblendvpd, dest, src1, src2, src3);
else if (info.Inst == X86Instruction.Blendvps && HardwareCapabilities.SupportsVexEncoding) break;
{ case X86Instruction.Blendvps when HardwareCapabilities.SupportsVexEncoding:
context.Assembler.WriteInstruction(X86Instruction.Vblendvps, dest, src1, src2, src3); context.Assembler.WriteInstruction(X86Instruction.Vblendvps, dest, src1, src2, src3);
} break;
else if (info.Inst == X86Instruction.Pblendvb && HardwareCapabilities.SupportsVexEncoding) case X86Instruction.Pblendvb when HardwareCapabilities.SupportsVexEncoding:
{ context.Assembler.WriteInstruction(X86Instruction.Vpblendvb, dest, src1, src2, src3);
context.Assembler.WriteInstruction(X86Instruction.Vpblendvb, dest, src1, src2, src3); break;
} default:
else EnsureSameReg(dest, src1);
{
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; 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) if (HardwareCapabilities.SupportsSse41)
{ {
context.Assembler.Insertps(dest, src1, src2, (byte)(index << 4)); context.Assembler.Pinsrd(dest, src1, src2, index);
} }
else 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 else
{ {
int mask0 = 0b11_10_01_00; context.Assembler.Movss(dest, src1, src2);
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
{
context.Assembler.Movss(dest, src1, src2);
}
}
else /* if (src2.Type == OperandType.FP64) */
{
Debug.Assert(index < 2);
if (index != 0) break;
{ }
context.Assembler.Movlhps(dest, src1, src2);
} default:
else Debug.Assert(index < 2);
{
context.Assembler.Movsd(dest, src1, src2); if (index != 0)
} {
context.Assembler.Movlhps(dest, src1, src2);
}
else
{
context.Assembler.Movsd(dest, src1, src2);
}
break;
} }
} }

View File

@ -141,19 +141,18 @@ namespace ARMeilleure.CodeGen.X86
Operand constOp; Operand constOp;
Operand otherOp; Operand otherOp;
if (src1.Kind == OperandKind.Constant && src2.Kind == OperandKind.LocalVariable) switch (src1.Kind)
{ {
constOp = src1; case OperandKind.Constant when src2.Kind == OperandKind.LocalVariable:
otherOp = src2; constOp = src1;
} otherOp = src2;
else if (src1.Kind == OperandKind.LocalVariable && src2.Kind == OperandKind.Constant) break;
{ case OperandKind.LocalVariable when src2.Kind == OperandKind.Constant:
constOp = src2; constOp = src2;
otherOp = src1; otherOp = src1;
} break;
else default:
{ return 0;
return 0;
} }
// If we have addition by 64-bits constant, then we can't optimize it further, // If we have addition by 64-bits constant, then we can't optimize it further,

View File

@ -10,30 +10,31 @@ namespace ARMeilleure.Decoders
public OpCodeAluImm(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode) 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; Immediate <<= shift * 12;
} break;
else if (DataOp == DataOp.Logical)
{
var bm = DecoderHelper.DecodeBitMask(opCode, true);
if (bm.IsUndefined) case DataOp.Logical:
{ var bm = DecoderHelper.DecodeBitMask(opCode, true);
Instruction = InstDescriptor.Undefined;
return; if (bm.IsUndefined)
} {
Instruction = InstDescriptor.Undefined;
Immediate = bm.WMask; return;
} }
else
{ Immediate = bm.WMask;
throw new ArgumentException($"Invalid data operation: {DataOp}", nameof(opCode)); break;
default:
throw new ArgumentException($"Invalid data operation: {DataOp}", nameof(opCode));
} }
} }
} }

View File

@ -1438,27 +1438,28 @@ namespace ARMeilleure.Decoders
// but 00 isn't. // but 00 isn't.
char chr = encoding[index]; char chr = encoding[index];
if (chr == '1') switch (chr)
{ {
value |= 1 << bit; case '1':
} value |= 1 << bit;
else if (chr == 'x') break;
{ case 'x':
xMask |= 1 << bit; xMask |= 1 << bit;
} break;
else if (chr == '>') case '>':
{ xPos[xBits++] = bit;
xPos[xBits++] = bit; break;
} case '<':
else if (chr == '<') xPos[xBits++] = bit;
{ blacklisted |= 1 << bit;
xPos[xBits++] = bit; break;
default:
if (chr != '0')
{
throw new ArgumentException($"Invalid encoding: {encoding}", nameof(encoding));
}
blacklisted |= 1 << bit; break;
}
else if (chr != '0')
{
throw new ArgumentException($"Invalid encoding: {encoding}", nameof(encoding));
} }
} }

View File

@ -1214,17 +1214,17 @@ namespace ARMeilleure.Instructions
elementAction(tempD, nByte, mByte); elementAction(tempD, nByte, mByte);
if (b == 0) switch (b)
{ {
result = context.ZeroExtend8(OperandType.I32, tempD); case 0:
} result = context.ZeroExtend8(OperandType.I32, tempD);
else if (b < 3) break;
{ case < 3:
result = context.BitwiseOr(result, context.ShiftLeft(context.ZeroExtend8(OperandType.I32, tempD), Const(b * 8))); result = context.BitwiseOr(result, context.ShiftLeft(context.ZeroExtend8(OperandType.I32, tempD), Const(b * 8)));
} break;
else default:
{ result = context.BitwiseOr(result, context.ShiftLeft(tempD, Const(24)));
result = context.BitwiseOr(result, context.ShiftLeft(tempD, Const(24))); break;
} }
} }

View File

@ -69,32 +69,37 @@ namespace ARMeilleure.Instructions
// read all the data at once. For a 32-bits pairwise load, we do a // 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 // simple 64-bits load, for a 128-bits load, we need to call a special
// method to read 128-bits atomically. // 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.Rt, valueLow);
SetIntOrZR(context, op.Rt2, valueHigh); SetIntOrZR(context, op.Rt2, valueHigh);
} break;
else if (op.Size == 3) }
{
Operand value = EmitLoadExclusive(context, address, exclusive, 4);
Operand valueLow = context.VectorExtract(OperandType.I64, value, 0); case 3:
Operand valueHigh = context.VectorExtract(OperandType.I64, value, 1); {
Operand value = EmitLoadExclusive(context, address, exclusive, 4);
SetIntOrZR(context, op.Rt, valueLow); Operand valueLow = context.VectorExtract(OperandType.I64, value, 0);
SetIntOrZR(context, op.Rt2, valueHigh); Operand valueHigh = context.VectorExtract(OperandType.I64, value, 1);
}
else SetIntOrZR(context, op.Rt, valueLow);
{ SetIntOrZR(context, op.Rt2, valueHigh);
throw new InvalidOperationException($"Invalid load size of {1 << op.Size} bytes."); break;
}
default:
throw new InvalidOperationException($"Invalid load size of {1 << op.Size} bytes.");
} }
} }
else else

View File

@ -338,17 +338,17 @@ namespace ARMeilleure.Instructions
value = context.ConvertI64ToI32(value); value = context.ConvertI64ToI32(value);
} }
if (size == 0) switch (size)
{ {
context.Store8(physAddr, value); case 0:
} context.Store8(physAddr, value);
else if (size == 1) break;
{ case 1:
context.Store16(physAddr, value); context.Store16(physAddr, value);
} break;
else default:
{ context.Store(physAddr, value);
context.Store(physAddr, value); break;
} }
} }

View File

@ -100,40 +100,48 @@ namespace ARMeilleure.Instructions
{ {
Operand res = GetVec(op.Rn); Operand res = GetVec(op.Rn);
if (op.Size == 0) switch (op.Size)
{ {
if (op.DstIndex != 0) case 0:
{ if (op.DstIndex != 0)
res = context.AddIntrinsic(Intrinsic.X86Psrldq, res, Const(op.DstIndex)); {
} res = context.AddIntrinsic(Intrinsic.X86Psrldq, res, Const(op.DstIndex));
}
res = context.AddIntrinsic(Intrinsic.X86Punpcklbw, res, res); res = context.AddIntrinsic(Intrinsic.X86Punpcklbw, res, res);
res = context.AddIntrinsic(Intrinsic.X86Punpcklwd, res, res); res = context.AddIntrinsic(Intrinsic.X86Punpcklwd, res, res);
res = context.AddIntrinsic(Intrinsic.X86Shufps, res, res, Const(0)); res = context.AddIntrinsic(Intrinsic.X86Shufps, res, res, Const(0));
} break;
else if (op.Size == 1)
{
if (op.DstIndex != 0)
{
res = context.AddIntrinsic(Intrinsic.X86Psrldq, res, Const(op.DstIndex * 2));
}
res = context.AddIntrinsic(Intrinsic.X86Punpcklwd, res, res); case 1:
res = context.AddIntrinsic(Intrinsic.X86Shufps, res, res, Const(0)); if (op.DstIndex != 0)
} {
else if (op.Size == 2) res = context.AddIntrinsic(Intrinsic.X86Psrldq, res, Const(op.DstIndex * 2));
{ }
int mask = op.DstIndex * 0b01010101;
res = context.AddIntrinsic(Intrinsic.X86Shufps, res, res, Const(mask)); res = context.AddIntrinsic(Intrinsic.X86Punpcklwd, res, res);
} res = context.AddIntrinsic(Intrinsic.X86Shufps, res, res, Const(0));
else if (op.DstIndex == 0 && op.RegisterSize != RegisterSize.Simd64) break;
{
res = context.AddIntrinsic(Intrinsic.X86Movlhps, res, res); case 2:
} {
else if (op.DstIndex == 1) int mask = op.DstIndex * 0b01010101;
{
res = context.AddIntrinsic(Intrinsic.X86Movhlps, res, res); 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) if (op.RegisterSize == RegisterSize.Simd64)

View File

@ -221,54 +221,60 @@ namespace ARMeilleure.Instructions
if (op.U) if (op.U)
{ {
if (op.Size < 2) switch (op.Size)
{ {
EmitVectorUnaryOpZx32(context, (op1) => case < 2:
{ EmitVectorUnaryOpZx32(context, (op1) =>
op1 = context.Add(op1, Const(op1.Type, roundConst)); {
op1 = context.Add(op1, Const(op1.Type, roundConst));
return context.ShiftRightUI(op1, Const(shift)); return context.ShiftRightUI(op1, Const(shift));
}, accumulate); }, accumulate);
} break;
else if (op.Size == 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))); case 2:
}, accumulate); EmitVectorUnaryOpZx32(context, (op1) =>
} {
else /* if (op.Size == 3) */ op1 = context.ZeroExtend32(OperandType.I64, op1);
{ op1 = context.Add(op1, Const(op1.Type, roundConst));
EmitVectorUnaryOpZx32(context, (op1) => EmitShrImm64(context, op1, signed: false, roundConst, shift), accumulate);
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 else
{ {
if (op.Size < 2) switch (op.Size)
{ {
EmitVectorUnaryOpSx32(context, (op1) => case < 2:
{ EmitVectorUnaryOpSx32(context, (op1) =>
op1 = context.Add(op1, Const(op1.Type, roundConst)); {
op1 = context.Add(op1, Const(op1.Type, roundConst));
return context.ShiftRightSI(op1, Const(shift)); return context.ShiftRightSI(op1, Const(shift));
}, accumulate); }, accumulate);
} break;
else if (op.Size == 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))); case 2:
}, accumulate); EmitVectorUnaryOpSx32(context, (op1) =>
} {
else /* if (op.Size == 3) */ op1 = context.SignExtend32(OperandType.I64, op1);
{ op1 = context.Add(op1, Const(op1.Type, roundConst));
EmitVectorUnaryOpZx32(context, (op1) => EmitShrImm64(context, op1, signed: true, roundConst, shift), accumulate);
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;
} }
} }
} }

View File

@ -495,33 +495,33 @@ namespace ARMeilleure.Instructions
double result; double result;
if (type == FPType.SNaN || type == FPType.QNaN) switch (type)
{ {
if ((context.Fpcr & FPCR.Dn) != 0) case FPType.SNaN:
{ case FPType.QNaN:
result = SoftFloat64.FPDefaultNaN(); if ((context.Fpcr & FPCR.Dn) != 0)
} {
else result = SoftFloat64.FPDefaultNaN();
{ }
result = FPConvertNaN(valueBits); else
} {
result = FPConvertNaN(valueBits);
}
if (type == FPType.SNaN) if (type == FPType.SNaN)
{ {
SoftFloat.FPProcessException(FPException.InvalidOp, context); SoftFloat.FPProcessException(FPException.InvalidOp, context);
} }
} break;
else if (type == FPType.Infinity) case FPType.Infinity:
{ result = SoftFloat64.FPInfinity(sign);
result = SoftFloat64.FPInfinity(sign); break;
} case FPType.Zero:
else if (type == FPType.Zero) result = SoftFloat64.FPZero(sign);
{ break;
result = SoftFloat64.FPZero(sign); default:
} result = FPRoundCv(real, context);
else break;
{
result = FPRoundCv(real, context);
} }
return result; return result;
@ -672,46 +672,49 @@ namespace ARMeilleure.Instructions
ushort resultBits; 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); resultBits = SoftFloat16.FPZero(sign);
} break;
else if ((context.Fpcr & FPCR.Dn) != 0)
{
resultBits = SoftFloat16.FPDefaultNaN();
}
else
{
resultBits = FPConvertNaN(valueBits);
}
if (type == FPType.SNaN || altHp) default:
{ resultBits = SoftFloat16.FPRoundCv(real, context);
SoftFloat.FPProcessException(FPException.InvalidOp, context); break;
}
}
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);
} }
return resultBits; return resultBits;
@ -1056,46 +1059,46 @@ namespace ARMeilleure.Instructions
{ {
if (value1 > value2) if (value1 > value2)
{ {
if (type1 == FPType.Infinity) switch (type1)
{ {
result = FPInfinity(sign1); case FPType.Infinity:
} result = FPInfinity(sign1);
else if (type1 == FPType.Zero) break;
{ case FPType.Zero:
result = FPZero(sign1 && sign2); result = FPZero(sign1 && sign2);
} break;
else default:
{ result = value1;
result = value1;
if ((fpcr & FPCR.Fz) != 0 && float.IsSubnormal(result)) if ((fpcr & FPCR.Fz) != 0 && float.IsSubnormal(result))
{ {
context.Fpsr |= FPSR.Ufc; context.Fpsr |= FPSR.Ufc;
result = FPZero(result < 0f); result = FPZero(result < 0f);
} }
break;
} }
} }
else else
{ {
if (type2 == FPType.Infinity) switch (type2)
{ {
result = FPInfinity(sign2); case FPType.Infinity:
} result = FPInfinity(sign2);
else if (type2 == FPType.Zero) break;
{ case FPType.Zero:
result = FPZero(sign1 && sign2); result = FPZero(sign1 && sign2);
} break;
else default:
{ result = value2;
result = value2;
if ((fpcr & FPCR.Fz) != 0 && float.IsSubnormal(result)) if ((fpcr & FPCR.Fz) != 0 && float.IsSubnormal(result))
{ {
context.Fpsr |= FPSR.Ufc; context.Fpsr |= FPSR.Ufc;
result = FPZero(result < 0f); result = FPZero(result < 0f);
} }
break;
} }
} }
} }
@ -1147,46 +1150,46 @@ namespace ARMeilleure.Instructions
{ {
if (value1 < value2) if (value1 < value2)
{ {
if (type1 == FPType.Infinity) switch (type1)
{ {
result = FPInfinity(sign1); case FPType.Infinity:
} result = FPInfinity(sign1);
else if (type1 == FPType.Zero) break;
{ case FPType.Zero:
result = FPZero(sign1 || sign2); result = FPZero(sign1 || sign2);
} break;
else default:
{ result = value1;
result = value1;
if ((fpcr & FPCR.Fz) != 0 && float.IsSubnormal(result)) if ((fpcr & FPCR.Fz) != 0 && float.IsSubnormal(result))
{ {
context.Fpsr |= FPSR.Ufc; context.Fpsr |= FPSR.Ufc;
result = FPZero(result < 0f); result = FPZero(result < 0f);
} }
break;
} }
} }
else else
{ {
if (type2 == FPType.Infinity) switch (type2)
{ {
result = FPInfinity(sign2); case FPType.Infinity:
} result = FPInfinity(sign2);
else if (type2 == FPType.Zero) break;
{ case FPType.Zero:
result = FPZero(sign1 || sign2); result = FPZero(sign1 || sign2);
} break;
else default:
{ result = value2;
result = value2;
if ((fpcr & FPCR.Fz) != 0 && float.IsSubnormal(result)) if ((fpcr & FPCR.Fz) != 0 && float.IsSubnormal(result))
{ {
context.Fpsr |= FPSR.Ufc; context.Fpsr |= FPSR.Ufc;
result = FPZero(result < 0f); result = FPZero(result < 0f);
} }
break;
} }
} }
} }

View File

@ -184,41 +184,36 @@ namespace ARMeilleure.State
public unsafe static int GetRegisterOffset(Register reg) public unsafe static int GetRegisterOffset(Register reg)
{ {
if (reg.Type == RegisterType.Integer) switch (reg.Type)
{ {
if ((uint)reg.Index >= RegisterConsts.IntRegsCount) case RegisterType.Integer:
{ if ((uint)reg.Index >= RegisterConsts.IntRegsCount)
throw new ArgumentException("Invalid register."); {
} throw new ArgumentException("Invalid register.");
}
return StorageOffset(ref _dummyStorage, ref _dummyStorage.X[reg.Index]); return StorageOffset(ref _dummyStorage, ref _dummyStorage.X[reg.Index]);
} case RegisterType.Vector:
else if (reg.Type == RegisterType.Vector) if ((uint)reg.Index >= RegisterConsts.VecRegsCount)
{ {
if ((uint)reg.Index >= RegisterConsts.VecRegsCount) throw new ArgumentException("Invalid register.");
{ }
throw new ArgumentException("Invalid register.");
}
return StorageOffset(ref _dummyStorage, ref _dummyStorage.V[reg.Index * 2]); return StorageOffset(ref _dummyStorage, ref _dummyStorage.V[reg.Index * 2]);
} case RegisterType.Flag:
else if (reg.Type == RegisterType.Flag) if ((uint)reg.Index >= RegisterConsts.FlagsCount)
{ {
if ((uint)reg.Index >= RegisterConsts.FlagsCount) throw new ArgumentException("Invalid register.");
{ }
throw new ArgumentException("Invalid register.");
}
return StorageOffset(ref _dummyStorage, ref _dummyStorage.Flags[reg.Index]); return StorageOffset(ref _dummyStorage, ref _dummyStorage.Flags[reg.Index]);
} default: // case RegisterType.FpFlag
else /* if (reg.Type == RegisterType.FpFlag) */ if ((uint)reg.Index >= RegisterConsts.FpFlagsCount)
{ {
if ((uint)reg.Index >= RegisterConsts.FpFlagsCount) throw new ArgumentException("Invalid register.");
{ }
throw new ArgumentException("Invalid register.");
}
return StorageOffset(ref _dummyStorage, ref _dummyStorage.FpFlags[reg.Index]); return StorageOffset(ref _dummyStorage, ref _dummyStorage.FpFlags[reg.Index]);
} }
} }

View File

@ -137,20 +137,20 @@ namespace ARMeilleure.Translation.Cache
Debug.Assert(allocSize % 8 == 0); Debug.Assert(allocSize % 8 == 0);
if (allocSize <= 128) switch (allocSize)
{ {
_unwindInfo->UnwindCodes[codeIndex++] = PackUnwindOp(UnwindOp.AllocSmall, entry.PrologOffset, (allocSize / 8) - 1); case <= 128:
} _unwindInfo->UnwindCodes[codeIndex++] = PackUnwindOp(UnwindOp.AllocSmall, entry.PrologOffset, (allocSize / 8) - 1);
else if (allocSize <= 0x7FFF8) break;
{ case <= 0x7FFF8:
_unwindInfo->UnwindCodes[codeIndex++] = PackUnwindOp(UnwindOp.AllocLarge, entry.PrologOffset, 0); _unwindInfo->UnwindCodes[codeIndex++] = PackUnwindOp(UnwindOp.AllocLarge, entry.PrologOffset, 0);
_unwindInfo->UnwindCodes[codeIndex++] = (ushort)(allocSize / 8); _unwindInfo->UnwindCodes[codeIndex++] = (ushort)(allocSize / 8);
} break;
else default:
{ _unwindInfo->UnwindCodes[codeIndex++] = PackUnwindOp(UnwindOp.AllocLarge, entry.PrologOffset, 1);
_unwindInfo->UnwindCodes[codeIndex++] = PackUnwindOp(UnwindOp.AllocLarge, entry.PrologOffset, 1); _unwindInfo->UnwindCodes[codeIndex++] = (ushort)(allocSize >> 0);
_unwindInfo->UnwindCodes[codeIndex++] = (ushort)(allocSize >> 0); _unwindInfo->UnwindCodes[codeIndex++] = (ushort)(allocSize >> 16);
_unwindInfo->UnwindCodes[codeIndex++] = (ushort)(allocSize >> 16); break;
} }
break; break;

View File

@ -108,36 +108,36 @@ namespace ARMeilleure.Translation
protected static OperandType GetOperandType(Type type) protected static OperandType GetOperandType(Type type)
{ {
if (type == typeof(bool) || type == typeof(byte) || switch (Type.GetTypeCode(type))
type == typeof(char) || type == typeof(short) ||
type == typeof(int) || type == typeof(sbyte) ||
type == typeof(ushort) || type == typeof(uint))
{ {
return OperandType.I32; case TypeCode.Boolean:
} case TypeCode.Byte:
else if (type == typeof(long) || type == typeof(ulong)) case TypeCode.Char:
{ case TypeCode.Int16:
return OperandType.I64; case TypeCode.Int32:
} case TypeCode.SByte:
else if (type == typeof(double)) case TypeCode.UInt16:
{ case TypeCode.UInt32:
return OperandType.FP64; return OperandType.I32;
}
else if (type == typeof(float)) case TypeCode.Int64:
{ case TypeCode.UInt64:
return OperandType.FP32; return OperandType.I64;
}
else if (type == typeof(V128)) case TypeCode.Double:
{ return OperandType.FP64;
return OperandType.V128;
} case TypeCode.Single:
else if (type == typeof(void)) return OperandType.FP32;
{
return OperandType.None; case TypeCode.Object when type == typeof(V128):
} return OperandType.V128;
else
{ case TypeCode.Object when type == typeof(void):
throw new ArgumentException($"Invalid type \"{type.Name}\"."); return OperandType.None;
default:
throw new ArgumentException($"Invalid type \"{type.Name}\".");
} }
} }

View File

@ -152,17 +152,16 @@ namespace ARMeilleure.Translation
while (node != null) while (node != null)
{ {
int cmp = key.CompareTo(node.Start); int cmp = key.CompareTo(node.Start);
if (cmp < 0) switch (cmp)
{ {
node = node.Left; case < 0:
} node = node.Left;
else if (cmp > 0) break;
{ case > 0:
node = node.Right; node = node.Right;
} break;
else default:
{ return node;
return node;
} }
} }
return null; return null;
@ -272,43 +271,42 @@ namespace ARMeilleure.Translation
{ {
parent = node; parent = node;
int cmp = start.CompareTo(node.Start); int cmp = start.CompareTo(node.Start);
if (cmp < 0) switch (cmp)
{ {
node = node.Left; case < 0:
} node = node.Left;
else if (cmp > 0) break;
{ case > 0:
node = node.Right; node = node.Right;
} break;
else default:
{ outNode = node;
outNode = node;
if (updateFactoryCallback != null) if (updateFactoryCallback != null)
{
// Replace
node.Value = updateFactoryCallback(start, node.Value);
int endCmp = end.CompareTo(node.End);
if (endCmp > 0)
{ {
node.End = end; // Replace
if (end.CompareTo(node.Max) > 0) node.Value = updateFactoryCallback(start, node.Value);
int endCmp = end.CompareTo(node.End);
if (endCmp > 0)
{ {
node.Max = end; node.End = end;
PropagateIncrease(node); if (end.CompareTo(node.Max) > 0)
RestoreBalanceAfterInsertion(node); {
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); IntervalTreeNode<TK, TV> newNode = new(start, end, value, parent);

View File

@ -977,27 +977,24 @@ namespace ARMeilleure.Translation.PTC
private static FeatureInfo GetFeatureInfo() private static FeatureInfo GetFeatureInfo()
{ {
if (RuntimeInformation.ProcessArchitecture == Architecture.Arm64) switch (RuntimeInformation.ProcessArchitecture)
{ {
return new FeatureInfo( case Architecture.Arm64:
(ulong)Arm64HardwareCapabilities.LinuxFeatureInfoHwCap, return new FeatureInfo(
(ulong)Arm64HardwareCapabilities.LinuxFeatureInfoHwCap2, (ulong)Arm64HardwareCapabilities.LinuxFeatureInfoHwCap,
(ulong)Arm64HardwareCapabilities.MacOsFeatureInfo, (ulong)Arm64HardwareCapabilities.LinuxFeatureInfoHwCap2,
0, (ulong)Arm64HardwareCapabilities.MacOsFeatureInfo,
0); 0,
} 0);
else if (RuntimeInformation.ProcessArchitecture == Architecture.X64) case Architecture.X64:
{ return new FeatureInfo(
return new FeatureInfo( (ulong)X86HardwareCapabilities.FeatureInfo1Ecx,
(ulong)X86HardwareCapabilities.FeatureInfo1Ecx, (ulong)X86HardwareCapabilities.FeatureInfo1Edx,
(ulong)X86HardwareCapabilities.FeatureInfo1Edx, (ulong)X86HardwareCapabilities.FeatureInfo7Ebx,
(ulong)X86HardwareCapabilities.FeatureInfo7Ebx, (ulong)X86HardwareCapabilities.FeatureInfo7Ecx,
(ulong)X86HardwareCapabilities.FeatureInfo7Ecx, (ulong)X86HardwareCapabilities.Xcr0InfoEax);
(ulong)X86HardwareCapabilities.Xcr0InfoEax); default:
} return new FeatureInfo(0, 0, 0, 0, 0);
else
{
return new FeatureInfo(0, 0, 0, 0, 0);
} }
} }

View File

@ -244,21 +244,20 @@ namespace ARMeilleure.Translation
{ {
Register reg = operand.GetRegister(); Register reg = operand.GetRegister();
if (reg.Type == RegisterType.Integer) switch (reg.Type)
{ {
result = reg.Index; case RegisterType.Integer:
} result = reg.Index;
else if (reg.Type == RegisterType.Vector) break;
{ case RegisterType.Vector:
result = RegisterConsts.IntRegsCount + reg.Index; result = RegisterConsts.IntRegsCount + reg.Index;
} break;
else if (reg.Type == RegisterType.Flag) case RegisterType.Flag:
{ result = RegisterConsts.IntAndVecRegsCount + reg.Index;
result = RegisterConsts.IntAndVecRegsCount + reg.Index; break;
} default: // case RegisterType.FpFlag
else /* if (reg.Type == RegisterType.FpFlag) */ result = RegisterConsts.FpFlagsOffset + reg.Index;
{ break;
result = RegisterConsts.FpFlagsOffset + reg.Index;
} }
return true; return true;