Skip to content

Commit

Permalink
Feature: long constant fusion for PowerPC.
Browse files Browse the repository at this point in the history
  • Loading branch information
uxmal committed Oct 15, 2024
1 parent a79b964 commit b9aeed6
Show file tree
Hide file tree
Showing 10 changed files with 357 additions and 33 deletions.
228 changes: 228 additions & 0 deletions src/Arch/PowerPC/LongConstantFuser.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,228 @@
#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;

namespace Reko.Arch.PowerPC
{
public class LongConstantFuser : IEnumerable<MachineInstruction>
{
private PowerPcDisassembler dasm;

public LongConstantFuser(PowerPcDisassembler dasm)
{
this.dasm = dasm;
}

public IEnumerator<MachineInstruction> GetEnumerator()
{
ImmediateOperand immLo;
var e = new LookaheadEnumerator<PowerPcInstruction>(dasm);
while (e.MoveNext())
{
var instrHi = e.Current;
switch (instrHi.Mnemonic)
{
case Mnemonic.addis:
case Mnemonic.oris:
if (((RegisterStorage) instrHi.Operands[1]).Number != 0 ||
!e.TryPeek(1, out var instrLo))
{
break;
}
if (instrLo.Mnemonic == Mnemonic.ori)
{
if (instrHi.Operands[0] == instrLo.Operands[0] &&
instrLo.Operands[0] == instrLo.Operands[1])
{
// Mutate the addis/oris and ori
var immHi = (ImmediateOperand) instrHi.Operands[2];
immLo = (ImmediateOperand) instrLo.Operands[2];
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;
instrLo.Operands[2] = loOp;
}
}
if (instrLo.Mnemonic == Mnemonic.addi)
{
if (instrHi.Operands[0] == instrLo.Operands[0] &&
instrLo.Operands[0] == instrLo.Operands[1])
{
// Mutate the addis/oris and addi
var immHi = (ImmediateOperand) instrHi.Operands[2];
immLo = (ImmediateOperand) instrLo.Operands[2];
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;
instrLo.Operands[2] = loOp;
}
}
else if (IsMemoryInstruction(instrLo.Mnemonic) &&
instrLo.Operands[1] is MemoryOperand memOp)
{
if (instrHi.Operands[0] == memOp.BaseRegister &&
memOp.Offset is ImmediateOperand imm)
{
var immHi = (ImmediateOperand) instrHi.Operands[2];
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[2] = 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.lbz or
Mnemonic.lbzcix or
Mnemonic.lbzu or
Mnemonic.lbzux or
Mnemonic.lbzx or
Mnemonic.ld or
Mnemonic.ldat or
Mnemonic.ldarx or
Mnemonic.ldcix or
Mnemonic.ldmx or
Mnemonic.ldu or
Mnemonic.ldux or
Mnemonic.ldx or
Mnemonic.lfd or
Mnemonic.lfdp or
Mnemonic.lfdu or
Mnemonic.lfdux or
Mnemonic.lfdx or
Mnemonic.lfs or
Mnemonic.lfsu or
Mnemonic.lfsux or
Mnemonic.lfsx or
Mnemonic.lha or
Mnemonic.lhau or
Mnemonic.lhaux or
Mnemonic.lhax or
Mnemonic.lhbrx or
Mnemonic.lhz or
Mnemonic.lhzu or
Mnemonic.lhzux or
Mnemonic.lhzx or
Mnemonic.lq or
Mnemonic.lwa or
Mnemonic.lwarx or
Mnemonic.lwax or
Mnemonic.lwbrx or
Mnemonic.lwz or
Mnemonic.lwzu or
Mnemonic.lwzux or
Mnemonic.lwzx or

Mnemonic.stb or
Mnemonic.stbcix or
Mnemonic.stbcx or
Mnemonic.stbu or
Mnemonic.stbux or
Mnemonic.stbx or
Mnemonic.std or
Mnemonic.stdat or
Mnemonic.stdbrx or
Mnemonic.stdcx or
Mnemonic.stdcix or
Mnemonic.stdu or
Mnemonic.stdx or
Mnemonic.stfd or
Mnemonic.stfdp or
Mnemonic.stfdu or
Mnemonic.stfdux or
Mnemonic.stfdx or
Mnemonic.stfiwx or
Mnemonic.stfs or
Mnemonic.stfsu or
Mnemonic.stfsux or
Mnemonic.stfsx or
Mnemonic.sth or
Mnemonic.sthbrx or
Mnemonic.sthcix or
Mnemonic.sthcx or
Mnemonic.sthu or
Mnemonic.sthx or
Mnemonic.stmw or
Mnemonic.stop or
Mnemonic.stq or
Mnemonic.stqcx or
Mnemonic.stqdx or
Mnemonic.stswi or
Mnemonic.stswx or
Mnemonic.stvebx or
Mnemonic.stvehx or
Mnemonic.stvewx or
Mnemonic.stvx or
Mnemonic.stvxl or
Mnemonic.stw or
Mnemonic.stwat or
Mnemonic.stwbrx or
Mnemonic.stwcix or
Mnemonic.stwcx or
Mnemonic.stwu or
Mnemonic.stwux or
Mnemonic.stwx or
Mnemonic.stxsd or
Mnemonic.stxsdx or
Mnemonic.stxsihx or
Mnemonic.stxsiwx or
Mnemonic.stxsix or
Mnemonic.stxssp => true,
_ => false
};
}
}
}
33 changes: 25 additions & 8 deletions src/Arch/PowerPC/MemoryOperand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,30 +19,47 @@
#endregion

using Reko.Core;
using Reko.Core.Expressions;
using Reko.Core.Machine;
using Reko.Core.Types;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Reko.Arch.PowerPC
{
public class MemoryOperand : AbstractMachineOperand
{
public MemoryOperand(PrimitiveType size, RegisterStorage reg, int offset) : base(size)
public MemoryOperand(PrimitiveType size, RegisterStorage reg, MachineOperand offset) : base(size)
{
this.BaseRegister = reg;
this.Offset = offset;
}

public RegisterStorage BaseRegister { get; }
public int Offset { get; }
public MachineOperand Offset { get; set; }

protected override void DoRender(MachineInstructionRenderer renderer, MachineInstructionRendererOptions options)
{
renderer.WriteString($"{Offset}({BaseRegister})");
if (Offset is SliceOperand slice)
{
renderer.WriteString($"{slice}({BaseRegister})");
}
else
{
var offset = (ImmediateOperand) this.Offset;
renderer.WriteString($"{offset.Value.ToInt32()}({BaseRegister.Name})");
}
}

public int IntOffset()
{
ImmediateOperand offset;
if (this.Offset is SliceOperand slice)
{
offset = slice.Value;
}
else
{
offset = (ImmediateOperand) this.Offset;
}
return offset.Value.ToInt32();
}
}
}
5 changes: 3 additions & 2 deletions src/Arch/PowerPC/PowerPcArchitecture.cs
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,8 @@ public PowerPcDisassembler CreateDisassemblerImpl(EndianImageReader rdr)

public override IEnumerable<MachineInstruction> CreateDisassembler(EndianImageReader rdr)
{
return new PowerPcDisassembler(this, EnsureDecoders(), rdr, WordWidth);
var dasm = new PowerPcDisassembler(this, EnsureDecoders(), rdr, WordWidth);
return new LongConstantFuser(dasm);
}

public override IProcessorEmulator CreateEmulator(SegmentMap segmentMap, IPlatformEmulator envEmulator)
Expand Down Expand Up @@ -230,7 +231,7 @@ public override abstract IEnumerable<Address> CreatePointerScanner(
return null;
if (mem.BaseRegister != reg)
return null;
uAddr = (uint)((int)uAddr + mem.Offset);
uAddr = (uint)((int)uAddr + mem.IntOffset());
reg = (RegisterStorage)e.Current.Operands[0];

if (!e.MoveNext() || e.Current.Mnemonic != Mnemonic.mtctr)
Expand Down
3 changes: 2 additions & 1 deletion src/Arch/PowerPC/PowerPcDisassembler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -656,7 +656,8 @@ internal static Bitfield[] BeFields(params (int bitPos, int bitLength)[] fieldDe

private MachineOperand MemOff(uint reg, uint wInstr)
{
return new MemoryOperand(PrimitiveType.Word32, arch.Registers[(int)reg & 0x1F], (short) wInstr);
return new MemoryOperand(PrimitiveType.Word32, arch.Registers[(int)reg & 0x1F],
ImmediateOperand.Int32((short) wInstr));
}

private RegisterStorage CRegFromBits(uint r)
Expand Down
11 changes: 6 additions & 5 deletions src/Arch/PowerPC/PowerPcRewriter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -731,21 +731,22 @@ private Expression EffectiveAddress(MachineOperand operand, RtlEmitter emitter)
{
var mop = (MemoryOperand) operand;
var reg = binder.EnsureRegister(mop.BaseRegister);
var offset = mop.Offset;
var offset = mop.IntOffset();
return emitter.IAddS(reg, offset);
}

private Expression EffectiveAddress_r0(int iOp, int extraOffset = 0)
{
var mop = (MemoryOperand) instr.Operands[iOp];
var offset = mop.IntOffset();
if (mop.BaseRegister.Number == 0)
{
return Constant.Word32(mop.Offset + extraOffset);
return Constant.Word32(offset + extraOffset);
}
else
{
var reg = binder.EnsureRegister(mop.BaseRegister);
var offset = mop.Offset + extraOffset;
offset = offset + extraOffset;
if (offset != 0)
return m.IAddS(reg, offset);
else
Expand All @@ -756,14 +757,14 @@ private Expression EffectiveAddress_r0(int iOp, int extraOffset = 0)
private Expression EffectiveAddress_r0(MachineOperand operand)
{
var mop = (MemoryOperand) operand;
var offset = mop.IntOffset();
if (mop.BaseRegister.Number == 0)
{
return Constant.Word32(mop.Offset);
return Constant.Word32(offset);
}
else
{
var reg = binder.EnsureRegister(mop.BaseRegister);
var offset = mop.Offset;
if (offset != 0)
return m.IAddS(reg, offset);
else
Expand Down
Loading

0 comments on commit b9aeed6

Please sign in to comment.