Skip to content

Commit

Permalink
Merge pull request #1300 from ptomin/multi-dimensional-arrays
Browse files Browse the repository at this point in the history
  • Loading branch information
uxmal authored Dec 3, 2023
2 parents bf2f86b + faacfdf commit a38f295
Show file tree
Hide file tree
Showing 26 changed files with 50,230 additions and 47,506 deletions.
40 changes: 39 additions & 1 deletion src/Decompiler/Typing/ExpressionTypeDescender.cs
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ public class ExpressionTypeDescender : ExpressionVisitor<bool, TypeVariable>
protected readonly TypeStore store;
protected readonly TypeFactory factory;
protected readonly Unifier unifier;
protected readonly ArrayExpressionMatcher aem;
protected readonly Identifier globals;
protected readonly IReadOnlyDictionary<Identifier,LinearInductionVariable> ivs;

Expand All @@ -67,6 +68,7 @@ public ExpressionTypeDescender(IReadOnlyProgram program, TypeStore store, TypeFa
this.store = store;
this.factory = factory;
this.unifier = new DataTypeBuilderUnifier(factory, store);
this.aem = new ArrayExpressionMatcher(program.Platform.PointerType);
}

protected virtual TypeVariable TypeVar(Expression exp)
Expand Down Expand Up @@ -216,7 +218,20 @@ private TypeVariable ArrayField(
TypeVariable tvField)
{
var dtElement = factory.CreateStructureType(null, elementSize);
dtElement.Fields.Add(0, tvField);
if (
tvField.DataType is StructureType strField &&
// Structures with different sizes are not compatible
(strField.Size == 0 || strField.Size == elementSize))
{
foreach (var f in strField.Fields)
{
dtElement.Fields.Add(f);
}
}
else
{
dtElement.Fields.Add(0, tvField);
}
var tvElement = store.CreateTypeVariable(factory);
tvElement.DataType = dtElement;
tvElement.OriginalDataType = dtElement;
Expand Down Expand Up @@ -263,6 +278,7 @@ public bool VisitBinaryExpression(BinaryExpression binExp, TypeVariable tv)
{
case OperatorType.IAdd:
{
PushArrayElement(binExp);
var dt = PushAddendDataType(tvBin.DataType, tvRight.DataType);
if (dt != null)
MeetDataType(eLeft, dt);
Expand Down Expand Up @@ -439,6 +455,28 @@ public bool VisitBinaryExpression(BinaryExpression binExp, TypeVariable tv)
return dtSum;
}

private void PushArrayElement(BinaryExpression binExp)
{
var eLeft = binExp.Left;
var tvBin = TypeVar(binExp);
if (tvBin.DataType is not Pointer binPtr)
return;
if (!aem.Match(binExp))
return;
if (aem.ArrayPointer == eLeft)
{
if (binPtr.Pointee is not TypeVariable tvField)
{
tvField = store.CreateTypeVariable(factory);
tvField.DataType = binPtr.Pointee;
tvField.OriginalDataType = binPtr.Pointee;
}
ArrayField(
null, eLeft, eLeft.DataType.BitSize, 0,
OffsetOf(aem.ElementSize!), 0, tvField);
}
}

private static DataType PushMinuendDataType(DataType dtDiff, DataType dtSub)
{
if (dtDiff.Domain == Domain.Pointer)
Expand Down
41 changes: 41 additions & 0 deletions src/UnitTests/Decompiler/Typing/TypedExpressionRewriterTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1567,5 +1567,46 @@ define main
RunStringTest(pb.BuildProgram(), sExp);
}

[Test]
public void TerMultiDimensionalArray()
{
var sExp =
#region Expected
@"// Before ///////
// main
// Return size: 0
define main
main_entry:
// succ: l1
l1:
r0 = Mem0[a + r1 * 0x20<32> + r2 * 4<32>:word32]
main_exit:
// After ///////
// main
// Return size: 0
define main
main_entry:
// succ: l1
l1:
r0 = (a + r1)->a0000[r2]
main_exit:
";
#endregion
var pb = new ProgramBuilder();
pb.Add("main", m =>
{
var r0 = m.Register("r0");
var r1 = m.Register("r1");
var r2 = m.Register("r2");
var a = m.Temp(PrimitiveType.Word32, "a");
m.Assign(
r0,
m.Mem32(m.IAdd(m.IAdd(a, m.IMul(r1, 32)), m.IMul(r2, 4)))
);
});
RunStringTest(pb.BuildProgram(), sExp);
}
}
}
Loading

0 comments on commit a38f295

Please sign in to comment.