Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 36 additions & 10 deletions src/Core/Echo/Memory/BitVectorSpan.Integer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -609,8 +609,9 @@ private Trilean IntegerMultiplyLle(BitVectorSpan other)
/// Interprets the bit vector as an integer and divides it by a second integer.
/// </summary>
/// <param name="other">The integer to divide the current integer by.</param>
/// <param name="signed">Indicates whether the integers should be interpreted as signed or unsigned integers.</param>
/// <exception cref="ArgumentException">Occurs when the sizes of the integers do not match in bit length.</exception>
public void IntegerDivide(BitVectorSpan other)
public void IntegerDivide(BitVectorSpan other, bool signed)
{
AssertSameBitSize(other);

Expand All @@ -624,19 +625,31 @@ public void IntegerDivide(BitVectorSpan other)
switch (Count)
{
case 8:
U8 /= other.U8;
if (signed)
I8 /= other.I8;
else
U8 /= other.U8;
return;

case 16:
U16 /= other.U16;
if (signed)
I16 /= other.I16;
else
U16 /= other.U16;
return;

case 32:
U32 /= other.U32;
if (signed)
I32 /= other.I32;
else
U32 /= other.U32;
return;

case 64:
U64 /= other.U64;
if (signed)
I64 /= other.I64;
else
U64 /= other.U64;
return;

default:
Expand All @@ -650,8 +663,9 @@ public void IntegerDivide(BitVectorSpan other)
/// Interprets the bit vector as an integer, divides it by a second integer and produces the remainder.
/// </summary>
/// <param name="other">The integer to divide the current integer by.</param>
/// <param name="signed">Indicates whether the integers should be interpreted as signed or unsigned integers.</param>
/// <exception cref="ArgumentException">Occurs when the sizes of the integers do not match in bit length.</exception>
public void IntegerRemainder(BitVectorSpan other)
public void IntegerRemainder(BitVectorSpan other, bool signed)
{
AssertSameBitSize(other);

Expand All @@ -665,19 +679,31 @@ public void IntegerRemainder(BitVectorSpan other)
switch (Count)
{
case 8:
U8 %= other.U8;
if (signed)
I8 %= other.I8;
else
U8 %= other.U8;
return;

case 16:
U16 %= other.U16;
if (signed)
I16 %= other.I16;
else
U16 %= other.U16;
return;

case 32:
U32 %= other.U32;
if (signed)
I32 %= other.I32;
else
U32 %= other.U32;
return;

case 64:
U64 %= other.U64;
if (signed)
I64 %= other.I64;
else
U64 %= other.U64;
return;

default:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ protected override CilDispatchResult Evaluate(CilExecutionContext context, CilIn
var argument2Value = argument2.Contents.AsSpan();

if (argument1.TypeHint == StackSlotTypeHint.Integer)
argument1Value.IntegerDivide(argument2Value);
argument1Value.IntegerDivide(argument2Value, IsSignedOperation(instruction));
else
argument1Value.FloatDivide(argument2Value);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ protected override CilDispatchResult Evaluate(
var argument2Value = argument2.Contents.AsSpan();

if (argument1.TypeHint == StackSlotTypeHint.Integer)
argument1Value.IntegerRemainder(argument2Value);
argument1Value.IntegerRemainder(argument2Value, IsSignedOperation(instruction));
else
argument1Value.FloatRemainder(argument2Value);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,51 @@ protected void AssertCorrect(CilOpCode code, ulong a, ulong b, ulong expected)
Assert.Equal(64, slot.Contents.Count);
Assert.Equal(expected, slot.Contents.AsSpan().U64);
}

protected void AssertCorrect(CilOpCode code, long a, long b, long expected)
{
var stack = Context.CurrentFrame.EvaluationStack;

stack.Push(new StackSlot(a, StackSlotTypeHint.Integer));
stack.Push(new StackSlot(b, StackSlotTypeHint.Integer));

var result = Dispatcher.Dispatch(Context, new CilInstruction(code));

Assert.True(result.IsSuccess);
var slot = Context.CurrentFrame.EvaluationStack.Peek();
Assert.Equal(64, slot.Contents.Count);
Assert.Equal(expected, slot.Contents.AsSpan().I64);
}

protected void AssertCorrect(CilOpCode code, int a, long b, long expected)
{
var stack = Context.CurrentFrame.EvaluationStack;

stack.Push(new StackSlot(a, StackSlotTypeHint.Integer));
stack.Push(new StackSlot(b, StackSlotTypeHint.Integer));

var result = Dispatcher.Dispatch(Context, new CilInstruction(code));

Assert.True(result.IsSuccess);
var slot = Context.CurrentFrame.EvaluationStack.Peek();
Assert.Equal(64, slot.Contents.Count);
Assert.Equal(expected, slot.Contents.AsSpan().I64);
}

protected void AssertCorrect(CilOpCode code, long a, int b, long expected)
{
var stack = Context.CurrentFrame.EvaluationStack;

stack.Push(new StackSlot(a, StackSlotTypeHint.Integer));
stack.Push(new StackSlot(b, StackSlotTypeHint.Integer));

var result = Dispatcher.Dispatch(Context, new CilInstruction(code));

Assert.True(result.IsSuccess);
var slot = Context.CurrentFrame.EvaluationStack.Peek();
Assert.Equal(64, slot.Contents.Count);
Assert.Equal(expected, slot.Contents.AsSpan().I64);
}

protected void AssertCorrect(CilOpCode code, double a, double b, double expected)
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
using System;
using AsmResolver.PE.DotNet.Cil;
using Echo.Platforms.AsmResolver.Emulation;
using Echo.Platforms.AsmResolver.Emulation.Stack;
using Echo.Platforms.AsmResolver.Tests.Mock;
using Xunit;
Expand All @@ -15,18 +14,32 @@ public DivHandlerTest(MockModuleFixture fixture)
}

[Fact]
public void DivI4ToI4() => AssertCorrect(CilOpCodes.Div, 1000u, 20u, 50u);
public void DivI4ToI4() => AssertCorrect(CilOpCodes.Div, -1000, 20, -50);

[Fact]
public void DivI4ToI8() => AssertCorrect(CilOpCodes.Div, -1000, 20L, -50L);

[Fact]
public void DivI8ToI4() => AssertCorrect(CilOpCodes.Div, -1000L, 20, -50L);

[Fact]
public void DivI8ToI8() => AssertCorrect(CilOpCodes.Div, -1000L, 20L, -50L);

[Theory]
[InlineData(1000u, 20u, 50u)]
public void DivU4ToU4(uint a, uint b, uint expected) => AssertCorrect(CilOpCodes.Div_Un, a, b, expected);

[Theory]
[InlineData(1000u, 20ul, 50ul)]
public void DivI4ToI8(uint a, ulong b, ulong expected) => AssertCorrect(CilOpCodes.Div, a, b, expected);
public void DivU4ToU8(uint a, ulong b, ulong expected) => AssertCorrect(CilOpCodes.Div_Un, a, b, expected);

[Theory]
[InlineData(1000ul, 20u, 50ul)]
public void DivI8ToI4(ulong a, uint b, ulong expected) => AssertCorrect(CilOpCodes.Div, a, b, expected);
public void DivU8ToU4(ulong a, uint b, ulong expected) => AssertCorrect(CilOpCodes.Div_Un, a, b, expected);

[Fact]
public void DivI8ToI8() => AssertCorrect(CilOpCodes.Div, 1000ul, 20ul, 50ul);
[Theory]
[InlineData(1000ul, 20ul, 50ul)]
public void DivU8ToU8(ulong a, ulong b, ulong expected) => AssertCorrect(CilOpCodes.Div_Un, a, b, expected);

[Fact]
public void DivR8ToR8() => AssertCorrect(CilOpCodes.Div, 1000.0, 20.0, 50.0);
Expand All @@ -47,5 +60,4 @@ public void DivR4ToI4ShouldThrow()
Assert.Equal(typeof(InvalidProgramException).FullName, type.FullName);
}
}

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,15 @@ public OrHandlerTest(MockModuleFixture fixture)
}

[Fact]
public void OrI4ToI4() => AssertCorrect(CilOpCodes.Or, 0x22220000u, 0x00001111, 0x22221111);
public void OrI4ToI4() => AssertCorrect(CilOpCodes.Or, 0x22220000, 0x00001111, 0x22221111);

[Fact]
public void OrI4ToI8() => AssertCorrect(CilOpCodes.Or, 0x22222222u, 0x11111111_00000000ul, 0x11111111_22222222ul);
public void OrI4ToI8() => AssertCorrect(CilOpCodes.Or, 0x22222222, 0x11111111_00000000L, 0x11111111_22222222L);

[Fact]
public void OrI8ToI4() => AssertCorrect(CilOpCodes.Or, 0x11111111_00000000ul, 0x22222222u, 0x11111111_22222222ul);
public void OrI8ToI4() => AssertCorrect(CilOpCodes.Or, 0x11111111_00000000L, 0x22222222, 0x11111111_22222222L);

[Fact]
public void OrI8ToI8() => AssertCorrect(CilOpCodes.Or, 0x11111111_00000000ul, 0x00000000_22222222ul, 0x11111111_22222222ul);
public void OrI8ToI8() => AssertCorrect(CilOpCodes.Or, 0x11111111_00000000L, 0x00000000_22222222L, 0x11111111_22222222L);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,30 +14,50 @@ public RemHandlerTest(MockModuleFixture fixture)
{
}

[Theory]
[InlineData(-1000, 20, 0)]
[InlineData(-1000, 999, -1)]
public void RemI4ToI4(int a, int b, int expected) => AssertCorrect(CilOpCodes.Rem, a, b, expected);

[Theory]
[InlineData(-1000, 20L, 0L)]
[InlineData(-1000, 999L, -1L)]
public void RemI4ToI8(int a, long b, long expected) => AssertCorrect(CilOpCodes.Rem, a, b, expected);

[Theory]
[InlineData(-1000L, 20, 0L)]
[InlineData(-1000L, 999, -1L)]
public void RemI8ToI4(long a, int b, long expected) => AssertCorrect(CilOpCodes.Rem, a, b, expected);

[Theory]
[InlineData(-1000L, 20L, 0L)]
[InlineData(-1000L, 999L, -1L)]
public void RemI8ToI8(long a, long b, long expected) => AssertCorrect(CilOpCodes.Rem, a, b, expected);

[Theory]
[InlineData(1000u, 20u, 0u)]
[InlineData(1000u, 999u, 1u)]
public void I4ToI4(uint a, uint b, uint expected) => AssertCorrect(CilOpCodes.Rem, a, b, expected);
public void RemU4ToU4(uint a, uint b, uint expected) => AssertCorrect(CilOpCodes.Rem_Un, a, b, expected);

[Theory]
[InlineData(1000u, 20ul, 0ul)]
[InlineData(1000u, 999ul, 1ul)]
public void I4ToI8(uint a, ulong b, ulong expected) => AssertCorrect(CilOpCodes.Rem, a, b, expected);
public void RemU4ToU8(uint a, ulong b, ulong expected) => AssertCorrect(CilOpCodes.Rem_Un, a, b, expected);

[Theory]
[InlineData(1000ul, 20u, 0ul)]
[InlineData(1000ul, 999u, 1ul)]
public void I8ToI4(ulong a, uint b, ulong expected) => AssertCorrect(CilOpCodes.Rem, a, b, expected);
public void RemU8ToU4(ulong a, uint b, ulong expected) => AssertCorrect(CilOpCodes.Rem_Un, a, b, expected);

[Theory]
[InlineData(1000ul, 20ul, 0ul)]
[InlineData(1000ul, 999ul, 1ul)]
public void I8ToI8(ulong a, ulong b, ulong expected) => AssertCorrect(CilOpCodes.Rem, a, b, expected);
public void RemU8ToU8(ulong a, ulong b, ulong expected) => AssertCorrect(CilOpCodes.Rem_Un, a, b, expected);

[Theory]
[InlineData(1000.0, 20.0, 1000.0 % 20.0)]
[InlineData(1000.0, 999.0, 1000.0 % 999.0)]
public void R8ToR8(double a, double b, double expected) => AssertCorrect(CilOpCodes.Rem, a, b, expected);
[InlineData(1000.0, 20.0, 0.0)]
[InlineData(1000.0, 999.0, 1.0)]
public void RemR8ToR8(double a, double b, double expected) => AssertCorrect(CilOpCodes.Rem, a, b, expected);

[Fact]
public void R4ToI4ShouldThrow()
Expand All @@ -55,4 +75,4 @@ public void R4ToI4ShouldThrow()
Assert.Equal(typeof(InvalidProgramException).FullName, type.FullName);
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,20 +15,22 @@ public SubHandlerTest(MockModuleFixture fixture)
}

[Fact]
public void SubI4ToI4() => AssertCorrect(CilOpCodes.Sub, 0x1234, 0x234u, 0x1000u);
public void SubI4ToI4() => AssertCorrect(CilOpCodes.Sub, 0x1234, 0x234, 0x1000);

[Theory]
[InlineData(1234, 234, 1000)]
[InlineData(0x0000_0000, 1, 0xffff_ffff_ffff_ffff)]
public void SubI4ToI8(uint a, ulong b, ulong expected) => AssertCorrect(CilOpCodes.Sub, a, b, expected);

[Theory]
[InlineData(1234, 234, 1000)]
[InlineData(0x0000_0000, 1, 0xffff_ffff_ffff_ffff)]
public void SubI8ToI4(ulong a, uint b, ulong expected) => AssertCorrect(CilOpCodes.Sub, a, b, expected);
[Fact]
public void SubI4ToI8() => AssertCorrect(CilOpCodes.Sub, 1234, 234L, 1000L);

[Fact]
public void SubI8ToI8() => AssertCorrect(CilOpCodes.Sub, 0x1234ul, 0x1000ul, 0x234ul);
public void SubU4ToU8() => AssertCorrect(CilOpCodes.Sub, 0x0000_0000, 1L, 0xffff_ffff_ffff_ffffL);

[Fact]
public void SubI8ToI4() => AssertCorrect(CilOpCodes.Sub, 1234L, 234, 1000L);

[Fact]
public void SubU8ToU4() => AssertCorrect(CilOpCodes.Sub, 0x0000_0000L, 1, 0xffff_ffff_ffff_ffffL);

[Fact]
public void SubI8ToI8() => AssertCorrect(CilOpCodes.Sub, 0x1234L, 0x1000L, 0x234L);

[Fact]
public void SubR8ToR8() => AssertCorrect(CilOpCodes.Sub, 6.912D, 1.234D, 5.678D);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,15 @@ public XorHandlerTest(MockModuleFixture fixture)
}

[Fact]
public void XorI4ToI4() => AssertCorrect(CilOpCodes.Xor, 0x22220000u, 0x00001111, 0x22221111);
public void XorI4ToI4() => AssertCorrect(CilOpCodes.Xor, 0x22220000, 0x00001111, 0x22221111);

[Fact]
public void XorI4ToI8() => AssertCorrect(CilOpCodes.Xor, 0x22222222u, 0x11111111_00000000ul, 0x11111111_22222222ul);
public void XorI4ToI8() => AssertCorrect(CilOpCodes.Xor, 0x22222222, 0x11111111_00000000L, 0x11111111_22222222);

[Fact]
public void XorI8ToI4() => AssertCorrect(CilOpCodes.Xor, 0x11111111_00000000ul, 0x22222222u, 0x11111111_22222222ul);
public void XorI8ToI4() => AssertCorrect(CilOpCodes.Xor, 0x11111111_00000000L, 0x22222222, 0x11111111_22222222);

[Fact]
public void XorI8ToI8() => AssertCorrect(CilOpCodes.Xor, 0x11111111_00000000ul, 0x00000000_22222222ul, 0x11111111_22222222ul);
public void XorI8ToI8() => AssertCorrect(CilOpCodes.Xor, 0x11111111_00000000L, 0x00000000_22222222L, 0x11111111_22222222L);
}
}
Loading