Skip to content

Commit

Permalink
Fix: reworked ConvertConvertRule.
Browse files Browse the repository at this point in the history
ConvertConvertRule was failing in some cases. Added unit tests for each occurrence of the sequence CONVERT(CONVERT(e, ...), ...) in the codebase.
  • Loading branch information
uxmal committed May 10, 2024
1 parent 42bb62e commit 76502ad
Show file tree
Hide file tree
Showing 58 changed files with 181,921 additions and 181,977 deletions.
2 changes: 1 addition & 1 deletion src/Arch/X86/Rewriter/X86Rewriter.Alu.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1198,7 +1198,7 @@ private void RewriteSet(ConditionCode cc)
m.Assign(dst, m.Convert(
CreateTestCondition(cc, instrCur.Mnemonic),
PrimitiveType.Bool,
PrimitiveType.Create(Domain.SignedInt, dst.DataType.BitSize)));
PrimitiveType.CreateWord(dst.DataType.BitSize)));
}

private void RewriteSetFlag(FlagGroupStorage flags, Constant value)
Expand Down
46 changes: 32 additions & 14 deletions src/Decompiler/Evaluation/ConvertConvertRule.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
using Reko.Core;
using Reko.Core.Expressions;
using Reko.Core.Types;
using System;

namespace Reko.Evaluation
{
Expand All @@ -37,35 +38,52 @@ public ConvertConvertRule()
var origExp = innerC.Expression;
var innerConv = innerC;

var ptC = c.DataType as PrimitiveType;
var ptOuter = c.DataType as PrimitiveType;
var ptInner = innerC.DataType as PrimitiveType;
var ptExp = origExp.DataType as PrimitiveType;
if (ptC == null || ptInner == null || ptExp == null)
if (ptOuter is null || ptInner is null || ptExp is null)
return null;

// If the cast is identical, we don't have to do it twice.
if (ptC == ptInner)
if (ptOuter == ptInner)
{
origExp = innerC;
return innerC;
}
else
if (ptOuter.Domain == Domain.Real)
{
// Only match widening / narrowing.
if (!ptC.IsWord && !ptInner.IsWord &&
(ptC.Domain != ptInner.Domain || ptC.Domain != ptExp.Domain) &&
ptExp.Domain != Domain.Boolean)
if (ptInner.Domain != Domain.Real)
{
if (innerConv.SourceDataType.BitSize < ptInner.BitSize)
{
return new Conversion(origExp, innerConv.SourceDataType, ptOuter);
}
return null;
}
if (ptInner.BitSize > ptOuter.BitSize)
{
if (ptExp.BitSize == ptOuter.BitSize)
return origExp;
return new Conversion(origExp, innerC.SourceDataType, ptOuter);
}

if (ptExp.BitSize == ptOuter.BitSize)
{
if (ptInner.BitSize == ptOuter.BitSize)
return origExp;
return null;
}
return new Conversion(origExp, innerConv.SourceDataType, ptOuter);
}

// ptExp <= ptInner <= ptC
if (ptExp.BitSize <= ptInner.BitSize && ptInner.BitSize <= ptC.BitSize)
if (ptExp.BitSize <= ptInner.BitSize && ptInner.BitSize <= ptOuter.BitSize)
{
if (ptExp.BitSize == ptC.BitSize)
if (ptExp.BitSize == ptOuter.BitSize)
return origExp;
else
return new Conversion(origExp, innerConv.SourceDataType, ptC);
return new Conversion(origExp, innerConv.SourceDataType, ptOuter);
}
return origExp;
return null;
}
}
}
4 changes: 2 additions & 2 deletions src/UnitTests/Arch/X86/Rewriter/X86Rewriter_32bitTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -476,7 +476,7 @@ public void X86rw_seto()
Run32bitTest("0f90c1");
AssertCode(
"0|L--|10000000(3): 1 instructions",
"1|L--|cl = CONVERT(Test(OV,O), bool, int8)");
"1|L--|cl = CONVERT(Test(OV,O), bool, byte)");
}

[Test]
Expand All @@ -503,7 +503,7 @@ public void X86rw_setc()
Run32bitTest("0F92C1");
AssertCode(
"0|L--|10000000(3): 1 instructions",
"1|L--|cl = CONVERT(Test(ULT,C), bool, int8)");
"1|L--|cl = CONVERT(Test(ULT,C), bool, byte)");
}

[Test]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@
using Reko.UnitTests.Mocks;
using System;
using System.Numerics;
using static Reko.UnitTests.Decompiler.Analysis.SegmentedAccessClassifierTests;

namespace Reko.UnitTests.Decompiler.Evaluation
{
Expand Down Expand Up @@ -1329,4 +1328,4 @@ public void Exs_SliceMemPtrIdPlusIntConst()
Assert.AreEqual("Mem0[id_3 + 2<32>:word32]", exp.ToString());
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,204 @@
using Moq;
using NUnit.Framework;
using Reko.Core.Intrinsics;
using Reko.Core.Types;
using Reko.Core;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Reko.UnitTests.Mocks;
using Reko.Analysis;
using Reko.Core.Memory;
using Reko.Evaluation;
using Reko.Core.Expressions;

namespace Reko.UnitTests.Decompiler.Evaluation
{
[TestFixture]
public class ExpressionSimplifier_ConvertConvertTests
{
private static readonly PrimitiveType bool1 = PrimitiveType.Bool;
private static readonly PrimitiveType int8 = PrimitiveType.Int8;
private static readonly PrimitiveType int16 = PrimitiveType.Int16;
private static readonly PrimitiveType int32 = PrimitiveType.Int32;
private static readonly PrimitiveType int64 = PrimitiveType.Int64;
private static readonly PrimitiveType uint8 = PrimitiveType.UInt8;
private static readonly PrimitiveType uint16 = PrimitiveType.UInt16;
private static readonly PrimitiveType uint32 = PrimitiveType.UInt32;
private static readonly PrimitiveType uint64 = PrimitiveType.UInt64;
private static readonly PrimitiveType byte8 = PrimitiveType.Byte;
private static readonly PrimitiveType word16 = PrimitiveType.Word16;
private static readonly PrimitiveType word32 = PrimitiveType.Word32;
private static readonly PrimitiveType real32 = PrimitiveType.Real32;
private static readonly PrimitiveType real64 = PrimitiveType.Real64;
private static readonly PrimitiveType real80 = PrimitiveType.Real80;
private static readonly PrimitiveType real96 = PrimitiveType.Real96;

private ProcedureBuilder m;
private Mock<IProcessorArchitecture> arch;
private ExpressionSimplifier simplifier;
private Expression e_bool;
private Expression e_byte;
private Expression e_real32;
private Expression e_real64;
private Expression e_real96;
private Expression e_int32;
private Expression e_word16;
private Expression e_word32;


[SetUp]
public void Setup()
{
m = new ProcedureBuilder();
arch = new Mock<IProcessorArchitecture>();
arch.Setup(a => a.MemoryGranularity).Returns(8);
var dynamicLinker = new Mock<IDynamicLinker>();
var mem = new Mock<IMemory>();
var listener = new FakeDecompilerEventListener();
var ssaIds = new SsaIdentifierCollection();
e_bool = MakeId(ssaIds, bool1);
e_byte = MakeId(ssaIds, byte8);
e_real32 = MakeId(ssaIds, real32);
e_real64 = MakeId(ssaIds, real64);
e_real96 = MakeId(ssaIds, real96);
e_int32 = MakeId(ssaIds, int32);
e_word16 = MakeId(ssaIds, word16);
e_word32 = MakeId(ssaIds, word32);

var ssaCtx = new SsaEvaluationContext(arch.Object, ssaIds, dynamicLinker.Object);
simplifier = new ExpressionSimplifier(mem.Object, ssaCtx, listener);
}

private Expression MakeId(SsaIdentifierCollection ssaIds, PrimitiveType dt)
{
var id = Identifier.CreateTemporary($"e_{dt.Name}", dt);
var sid = ssaIds.Add(id, null, false);
return sid.Identifier;
}

private void RunTest(string sExpected, Expression e)
{
var result = e.Accept(simplifier);
var (actual, changed) = result;
Assert.AreEqual(sExpected, actual.ToString());
}

[Test]
public void ConvConv_bool1_int32_word32_uint64()
{
RunTest("CONVERT(e_bool, bool, uint64)", m.Convert(m.Convert(e_bool, bool1, int32), word32, uint64));
}

[Test]
public void ConvConv_bool1_int8_uint8_word32()
{
RunTest("CONVERT(e_bool, bool, word32)", m.Convert(m.Convert(e_bool, bool1, int8), uint8, word32));
}

[Test]
public void ConvConv_bool1_word16_word16_uint32()
{
RunTest("CONVERT(e_bool, bool, uint32)", m.Convert(m.Convert(e_bool, bool1, word16), word16, uint32));
}

[Test]
public void ConvConv_bool1_word32_word32_uint64()
{
RunTest("CONVERT(e_bool, bool, uint64)", m.Convert(m.Convert(e_bool, bool1, word32), word32, uint64));
}

[Test]
public void ConvConv_byte8_int32_uint32_uint64()
{
RunTest("CONVERT(e_byte, byte, uint64)", m.Convert(m.Convert(e_byte, byte8, int32), uint32, uint64));
}

[Test]
public void ConvConv_byte8_word16_word16_int32()
{
RunTest("CONVERT(e_byte, byte, int32)", m.Convert(m.Convert(e_byte, byte8, word16), word16, int32));
}

[Test]
public void ConvConv_byte8_word16_word16_word32()
{
RunTest("CONVERT(e_byte, byte, word32)", m.Convert(m.Convert(e_byte, byte8, word16), word16, word32));
}

[Test]
public void ConvConv_byte8_word32_word32_uint64()
{
RunTest("CONVERT(e_byte, byte, uint64)", m.Convert(m.Convert(e_byte, byte8, word32), word32, uint64));
}

[Test]
public void ConvConv_int8_int16_int16_int32()
{
RunTest("CONVERT(e_byte, int8, int32)", m.Convert(m.Convert(e_byte, int8, int16), int16, int32));
}

[Test]
public void ConvConv_uint8_int16_int16_int32()
{
RunTest("CONVERT(e_byte, uint8, int32)", m.Convert(m.Convert(e_byte, uint8, int16), int16, int32));
}

[Test]
public void ConvConv_uint8_uint16_int16_int32()
{
RunTest("CONVERT(e_byte, uint8, int32)", m.Convert(m.Convert(e_byte, uint8, uint16), int16, int32));
}

[Test]
public void ConvConv_uint8_uint32_uint32_uint64()
{
RunTest("CONVERT(e_byte, uint8, uint64)", m.Convert(m.Convert(e_byte, uint8, uint32), uint32, uint64));
}

[Test]
public void ConvConv_real64_real32_real32_real64()
{
RunTest("CONVERT(e_real64, real64, real32)", m.Convert(m.Convert(m.Convert(e_real64, real64, real32), real32, real64), real64, real32));
}

[Test]
public void ConvConv_real32_real64_real64_real32()
{
RunTest("e_real32", m.Convert(m.Convert(e_real32, real32, real64), real64, real32));
}

[Test]
public void ConvConv_int32_real32_real32_real64()
{
RunTest("CONVERT(e_int32, int32, real32)", m.Convert(m.Convert(e_int32, int32, real32), real32, real32));
}

[Test]
public void ConvConv_real64_real80_real80_real64()
{
RunTest("e_real64", m.Convert(m.Convert(e_real64, real64, real80), real80, real64));
}

[Test]
public void ConvConv_real96_real80_real80_real96()
{
RunTest("CONVERT(CONVERT(e_real96, real96, real80), real80, real96)", m.Convert(m.Convert(e_real96, real96, real80), real80, real96));
}

[Test]
public void ConvConv_word16_word32_word32_uint64()
{
RunTest("CONVERT(e_word16, word16, uint64)", m.Convert(m.Convert(e_word16, word16, word32), word32, uint64));
}

[Test]
public void ConvConv_int32_real96_real96_real80()
{
RunTest("CONVERT(e_word32, int32, real80)", m.Convert(m.Convert(e_word32, int32, real96), real96, real80));
}
}
}

2 changes: 1 addition & 1 deletion src/UserInterfaces/WindowsForms/PreviewInteractor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ private void PreviewTimer_Tick(object sender, EventArgs e)
var rcF = previewSpan.ContentExtent;
var rc = mixedCodeDataControl.ClientRectangle;
var ptScreen = mixedCodeDataControl.PointToScreen(
new System.Drawing.Point(100, (int)rcF.Bottom));
new Point(100, (int)rcF.Bottom));

var nested = new MixedCodeDataControl
{
Expand Down
2 changes: 1 addition & 1 deletion src/tests/Arch/X86/RwReg00006.exp
Original file line number Diff line number Diff line change
Expand Up @@ -220,7 +220,7 @@ l10000146:
l1000014C:
ecx = Mem0[esi + 4<i32>:word32]
SCZO = cond(Mem0[ecx + 0xE0<32>:word32] - ebp)
bl = CONVERT(Test(NE,Z), bool, int8)
bl = CONVERT(Test(NE,Z), bool, byte)
// succ: l10000158
l10000158:
esp = esp - 4<i32>
Expand Down
2 changes: 1 addition & 1 deletion src/tests/Arch/X86/RwTestCondition.exp
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ l0C00_0000:
C = false
ax = ax - bx
SCZO = cond(ax)
cl = CONVERT(Test(EQ,Z), bool, int8)
cl = CONVERT(Test(EQ,Z), bool, byte)
Mem0[ds:0x300<16>:word32] = ecx
SCZO = cond(ax - 0x30<16>)
branch Test(LT,SO) l0C00_0016
Expand Down
Loading

0 comments on commit 76502ad

Please sign in to comment.