Skip to content

Commit

Permalink
Feature: long constant fusion for MIPS disassembly.
Browse files Browse the repository at this point in the history
  • Loading branch information
uxmal committed Oct 15, 2024
1 parent b9aeed6 commit d2755b9
Show file tree
Hide file tree
Showing 33 changed files with 10,425 additions and 10,168 deletions.
34 changes: 25 additions & 9 deletions src/Arch/Mips/IndirectOperand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,30 +32,46 @@ namespace Reko.Arch.Mips
{
public class IndirectOperand : AbstractMachineOperand
{
public int Offset;
public RegisterStorage Base;

public IndirectOperand(PrimitiveType dataWidth, int offset, RegisterStorage baseReg) : base(dataWidth)
public IndirectOperand(PrimitiveType dataWidth, MachineOperand offset, RegisterStorage baseReg) : base(dataWidth)
{
this.Offset = offset;
this.Base = baseReg;
}

public MachineOperand Offset { get; set; }

public RegisterStorage Base { get; }

protected override void DoRender(MachineInstructionRenderer renderer, MachineInstructionRendererOptions options)
{
if (Offset is SliceOperand slice)
{
slice.Render(renderer, options);
renderer.WriteFormat("({0})", Base);
return;
}
string fmt;
int offset;
if (Offset >= 0)
int offset = ((ImmediateOperand) Offset).Value.ToInt32();
if (offset >= 0)
{
fmt = "{0:X4}({1})";
offset = Offset;
}
else
{
fmt = "-{0:X4}({1})";
offset = -Offset;
offset = -offset;
}
renderer.WriteString(string.Format(fmt, offset, Base));
renderer.WriteFormat(fmt, offset, Base);
}

public int IntOffset()
{
ImmediateOperand offset;
if (Offset is SliceOperand slice)
offset = slice.Value;
else
offset = (ImmediateOperand) Offset;
return offset.Value.ToInt32();
}
}
}
124 changes: 124 additions & 0 deletions src/Arch/Mips/LongConstantFuser.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
#region License
/*
* Copyright (C) 1999-2024 John Källén.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 or or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful or
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not or write to
* the Free Software Foundation or 675 Mass Ave or Cambridge or MA 02139 or USA.
*/
#endregion

using Reko.Core;
using Reko.Core.Collections;
using Reko.Core.Expressions;
using Reko.Core.Machine;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Security.Cryptography;

namespace Reko.Arch.Mips
{
public class LongConstantFuser : IEnumerable<MachineInstruction>
{
private readonly IEnumerable<MipsInstruction> dasm;

public LongConstantFuser(IEnumerable<MipsInstruction> dasm)
{
this.dasm = dasm;
}

public IEnumerator<MachineInstruction> GetEnumerator()
{
ImmediateOperand immLo;
var e = new LookaheadEnumerator<MipsInstruction>(dasm);
while (e.MoveNext())
{
var instrHi = e.Current;
switch (instrHi.Mnemonic)
{
case Mnemonic.lui:
if (!e.TryPeek(1, out var instrLo))
{
break;
}
if (instrLo.Mnemonic == Mnemonic.addiu)
{
if (instrLo.Operands[0] == instrLo.Operands[1])
{
// Mutate the lui and addiu
var immHi = (ImmediateOperand) instrHi.Operands[1];
immLo = (ImmediateOperand) instrLo.Operands[2];
var longConst = new ImmediateOperand(
Constant.Create(
instrHi.Operands[0].Width,
(uint)((immHi.Value.ToInt32() << 16) |
immLo.Value.ToInt32())));
var hiOp = new SliceOperand(SliceType.Hi, immHi, longConst);
var loOp = new SliceOperand(SliceType.Lo, immLo, longConst);
instrHi.Operands[1] = hiOp;
instrLo.Operands[2] = loOp;
}
}
else if (IsMemoryInstruction(instrLo.Mnemonic) &&
instrLo.Operands[1] is IndirectOperand memOp)
{
if (instrHi.Operands[0] == memOp.Base &&
memOp.Offset is ImmediateOperand imm)
{
var immHi = (ImmediateOperand) instrHi.Operands[1];
immLo = imm;
// Mutate the addis/oris and the memory operand
var longConst = new ImmediateOperand(
Constant.Create(
instrHi.Operands[0].Width,
(immHi.Value.ToInt32() << 16) +
immLo.Value.ToInt32()));
var hiOp = new SliceOperand(SliceType.Hi, immHi, longConst);
var loOp = new SliceOperand(SliceType.Lo, immLo, longConst);
instrHi.Operands[1] = hiOp;
memOp.Offset = loOp;
}
}
break;
default:
break;
}
yield return e.Current;
}
}

IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();

private static bool IsMemoryInstruction(Mnemonic mnemonic)
{
return mnemonic switch
{
Mnemonic.lb or
Mnemonic.lbu or
Mnemonic.ld or
Mnemonic.lh or
Mnemonic.lhu or
Mnemonic.lui or
Mnemonic.lw or
Mnemonic.lwu or

Mnemonic.sb or
Mnemonic.sd or
Mnemonic.sh or
Mnemonic.sw => true,
_ => false
};
}
}
}
20 changes: 16 additions & 4 deletions src/Arch/Mips/MicroMipsDisassembler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -259,7 +259,10 @@ private static Mutator<MicroMipsDisassembler> Ms(PrimitiveType dt)
var baseReg = d.arch.GetRegister(iBase)!;
var offset = offsetField.ReadSigned(u) * dt.Size;
var mop = new IndirectOperand(dt, offset, baseReg);
var mop = new IndirectOperand(
dt,
ImmediateOperand.Int32(offset),
baseReg);
d.ops.Add(mop);
return true;
};
Expand All @@ -276,7 +279,10 @@ private static Mutator<MicroMipsDisassembler> M(PrimitiveType dt)
var iBase = (int) baseField.Read(u);
var baseReg = d.arch.GetRegister(iBase)!;
var offset = offsetField.ReadSigned(u);
var mop = new IndirectOperand(dt, offset, baseReg);
var mop = new IndirectOperand(
dt,
ImmediateOperand.Int32(offset),
baseReg);
d.ops.Add(mop);
return true;
};
Expand All @@ -296,7 +302,10 @@ private static bool mb(uint uInstr, MicroMipsDisassembler dasm)
var baseReg = dasm.arch.GetRegister(iBase)!;
var encOffset = offsetField16.Read(uInstr);
var offset = encodedByteOffsets[encOffset];
var mop = new IndirectOperand(PrimitiveType.Byte, offset, baseReg);
var mop = new IndirectOperand(
PrimitiveType.Byte,
ImmediateOperand.Int32(offset),
baseReg);
dasm.ops.Add(mop);
return true;
}
Expand All @@ -311,7 +320,10 @@ private static Mutator<MicroMipsDisassembler> m(PrimitiveType dt)
var iBase32 = threeBitRegisterEncodings[iBase];
var baseReg = d.arch.GetRegister(iBase32)!;
var offset = offsetField.ReadSigned(u) * dt.Size;
var mop = new IndirectOperand(dt, offset, baseReg);
var mop = new IndirectOperand(
dt,
ImmediateOperand.Int32(offset),
baseReg);
d.ops.Add(mop);
return true;
};
Expand Down
25 changes: 20 additions & 5 deletions src/Arch/Mips/Mips16eDisassembler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -432,7 +432,10 @@ private static Mutator<Mips16eDisassembler> Msp(PrimitiveType dt, Bitfield field
return (u, d) =>
{
var offset = (int) (fieldOffset.Read(u) * dt.Size);
var mem = new IndirectOperand(dt, offset, d.arch.StackRegister);
var mem = new IndirectOperand(
dt,
ImmediateOperand.Int32(offset),
d.arch.StackRegister);
d.ops.Add(mem);
return true;
};
Expand All @@ -453,7 +456,10 @@ private static Mutator<Mips16eDisassembler> Mpc(PrimitiveType dt, Bitfield field
return (u, d) =>
{
var offset = (int) (fieldOffset.Read(u) * dt.Size);
var mem = new IndirectOperand(dt, offset, d.arch.pc);
var mem = new IndirectOperand(
dt,
ImmediateOperand.Int32(offset),
d.arch.pc);
d.ops.Add(mem);
return true;
};
Expand All @@ -480,7 +486,10 @@ private static bool MptrSp8(uint uInstr, Mips16eDisassembler dasm)
// var uExtend = Bitfield.ReadFields(bf_extend, dasm.extend.Value) << bf0_5.Length;
// offset = (int) Bits.SignExtend(uExtend | bf0_5.Read(uInstr), bf0_5.Length + 11);
int offset = (int) bf0_8.Read(uInstr) << 2;
var mem = new IndirectOperand(dasm.arch.PointerType, offset, dasm.arch.StackRegister);
var mem = new IndirectOperand(
dasm.arch.PointerType,
ImmediateOperand.Int32(offset),
dasm.arch.StackRegister);
dasm.ops.Add(mem);
return true;
}
Expand All @@ -489,7 +498,10 @@ private static bool MptrSp8Ex(uint uInstr, Mips16eDisassembler dasm)
{
var uExtend = Bitfield.ReadFields(bf_extend5, dasm.extend!.Value) << bf0_5.Length;
var offset = (int) Bits.SignExtend(uExtend | bf0_5.Read(uInstr), bf0_5.Length + 11);
var mem = new IndirectOperand(dasm.arch.PointerType, offset, dasm.arch.StackRegister);
var mem = new IndirectOperand(
dasm.arch.PointerType,
ImmediateOperand.Int32(offset),
dasm.arch.StackRegister);
dasm.ops.Add(mem);
return true;
}
Expand All @@ -511,7 +523,10 @@ private static Mutator<Mips16eDisassembler> M(PrimitiveType dt, Bitfield fieldre
}
var encReg = fieldreg.Read(u);
var reg = registerEncoding[encReg];
var mem = new IndirectOperand(dt, offset, reg);
var mem = new IndirectOperand(
dt,
ImmediateOperand.Int32(offset),
reg);
d.ops.Add(mem);
return true;
};
Expand Down
4 changes: 2 additions & 2 deletions src/Arch/Mips/Mips16eRewriter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -151,12 +151,12 @@ private Expression Rewrite(MachineOperand op)
Expression ea;
if (mem.Base == arch.pc)
{
ea = dasm.Current.Address + mem.Offset;
ea = dasm.Current.Address + mem.IntOffset();
}
else
{
ea = binder.EnsureRegister(mem.Base);
ea = m.AddSubSignedInt(ea, mem.Offset);
ea = m.AddSubSignedInt(ea, mem.IntOffset());
}
return m.Mem(op.Width, ea);
}
Expand Down
5 changes: 4 additions & 1 deletion src/Arch/Mips/MipsDisassembler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,10 @@ private Address LargeBranch(uint wInstr)
private IndirectOperand Ea(uint wInstr, PrimitiveType dataWidth, int shift, short offset)
{
var baseReg = arch.GetRegister((int) (wInstr >> shift) & 0x1F)!;
return new IndirectOperand(dataWidth, offset, baseReg);
return new IndirectOperand(
dataWidth,
ImmediateOperand.Int32(offset),
baseReg);
}
}
}
3 changes: 2 additions & 1 deletion src/Arch/Mips/MipsProcessorArchitecture.cs
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,8 @@ public MipsProcessorArchitecture(IServiceProvider services, string archId, Endia

public override IEnumerable<MachineInstruction> CreateDisassembler(EndianImageReader imageReader)
{
return CreateDisassemblerInternal(imageReader);
var dasm = CreateDisassemblerInternal(imageReader);
return new LongConstantFuser(dasm);
}

private IEnumerable<MipsInstruction> CreateDisassemblerInternal(EndianImageReader imageReader)
Expand Down
12 changes: 6 additions & 6 deletions src/Arch/Mips/MipsRewriter.Alu.cs
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,7 @@ private void RewriteLdl(MipsInstruction instr)
opDst,
m.Fn(intrinsics.ldl,
binder.EnsureRegister(opSrc.Base),
m.Int32(opSrc.Offset)));
m.Int32(opSrc.IntOffset())));
}

private void RewriteLdr(MipsInstruction instr)
Expand All @@ -196,7 +196,7 @@ private void RewriteLdr(MipsInstruction instr)
opDst,
m.Fn(intrinsics.ldr,
binder.EnsureRegister(opSrc.Base),
m.Int32(opSrc.Offset)));
m.Int32(opSrc.IntOffset())));
}
private void RewriteLoad(MipsInstruction instr, PrimitiveType dtSmall, PrimitiveType? dtSmall64 = null)
{
Expand Down Expand Up @@ -344,7 +344,7 @@ private void RewriteLwm(MipsInstruction instr)
int rt = ((RegisterStorage) instr.Operands[0]).Number;
var mem = ((IndirectOperand) instr.Operands[1]);
var rs = binder.EnsureRegister(mem.Base);
int offset = mem.Offset;
int offset = mem.IntOffset();
int count = ((ImmediateOperand) instr.Operands[2]).Value.ToInt32();
while (i != count)
{
Expand Down Expand Up @@ -621,7 +621,7 @@ private void RewriteSdl(MipsInstruction instr)
m.SideEffect(m.Fn(
intrinsics.sdl,
binder.EnsureRegister(opDst.Base),
m.Int32(opDst.Offset),
m.Int32(opDst.IntOffset()),
opSrc));
}

Expand All @@ -632,7 +632,7 @@ private void RewriteSdr(MipsInstruction instr)
m.SideEffect(m.Fn(
intrinsics.sdr,
binder.EnsureRegister(opDst.Base),
m.Int32(opDst.Offset),
m.Int32(opDst.IntOffset()),
opSrc));
}

Expand Down Expand Up @@ -743,7 +743,7 @@ private void RewriteSwm(MipsInstruction instr)
var rt = ((RegisterStorage) instr.Operands[0]).Number;
var count = ((ImmediateOperand) instr.Operands[2]).Value.ToInt32();
var ind = (IndirectOperand) instr.Operands[1];
var offset = ind.Offset;
var offset = ind.IntOffset();
var rs = binder.EnsureRegister(ind.Base);
for (int i = 0; i < count; ++i) {
int this_rt;
Expand Down
Loading

0 comments on commit d2755b9

Please sign in to comment.