Browse Source

#899: Add cpblk and initblk instructions to ILAst.

pull/904/head
Daniel Grunwald 8 years ago
parent
commit
afcbc8c6cf
  1. 28
      ICSharpCode.Decompiler/CSharp/StatementBuilder.cs
  2. 4
      ICSharpCode.Decompiler/IL/ILReader.cs
  3. 338
      ICSharpCode.Decompiler/IL/Instructions.cs
  4. 10
      ICSharpCode.Decompiler/IL/Instructions.tt

28
ICSharpCode.Decompiler/CSharp/StatementBuilder.cs

@ -757,5 +757,33 @@ namespace ICSharpCode.Decompiler.CSharp @@ -757,5 +757,33 @@ namespace ICSharpCode.Decompiler.CSharp
return block.ChildIndex == container.Blocks.Count - 1
&& container == leave.TargetContainer;
}
protected internal override Statement VisitInitblk(Initblk inst)
{
var stmt = new ExpressionStatement(new InvocationExpression {
Target = new IdentifierExpression("memset"),
Arguments = {
exprBuilder.Translate(inst.Address),
exprBuilder.Translate(inst.Value),
exprBuilder.Translate(inst.Size)
}
});
stmt.AddChild(new Comment(" IL initblk instruction"), Roles.Comment);
return stmt;
}
protected internal override Statement VisitCpblk(Cpblk inst)
{
var stmt = new ExpressionStatement(new InvocationExpression {
Target = new IdentifierExpression("memcpy"),
Arguments = {
exprBuilder.Translate(inst.DestAddress),
exprBuilder.Translate(inst.SourceAddress),
exprBuilder.Translate(inst.Size)
}
});
stmt.AddChild(new Comment(" IL cpblk instruction"), Roles.Comment);
return stmt;
}
}
}

4
ICSharpCode.Decompiler/IL/ILReader.cs

@ -523,7 +523,7 @@ namespace ICSharpCode.Decompiler.IL @@ -523,7 +523,7 @@ namespace ICSharpCode.Decompiler.IL
case Cil.Code.Conv_Ovf_U_Un:
return Push(new Conv(Pop(), PrimitiveType.U, true, Sign.Unsigned));
case Cil.Code.Cpblk:
throw new NotImplementedException();
return new Cpblk(size: Pop(StackType.I4), sourceAddress: PopPointer(), destAddress: PopPointer());
case Cil.Code.Div:
return BinaryNumeric(BinaryNumericOperator.Div, false, Sign.Signed);
case Cil.Code.Div_Un:
@ -535,7 +535,7 @@ namespace ICSharpCode.Decompiler.IL @@ -535,7 +535,7 @@ namespace ICSharpCode.Decompiler.IL
case Cil.Code.Endfinally:
return new Leave(null);
case Cil.Code.Initblk:
throw new NotImplementedException();
return new Initblk(size: Pop(StackType.I4), value: Pop(StackType.I4), address: PopPointer());
case Cil.Code.Jmp:
throw new NotImplementedException();
case Cil.Code.Ldarg:

338
ICSharpCode.Decompiler/IL/Instructions.cs

@ -121,6 +121,10 @@ namespace ICSharpCode.Decompiler.IL @@ -121,6 +121,10 @@ namespace ICSharpCode.Decompiler.IL
LdMemberToken,
/// <summary>Allocates space in the stack frame</summary>
LocAlloc,
/// <summary>memcpy(destAddress, sourceAddress, size);</summary>
Cpblk,
/// <summary>memset(address, value, size)</summary>
Initblk,
/// <summary>Load address of instance field</summary>
LdFlda,
/// <summary>Load static field address</summary>
@ -2860,6 +2864,286 @@ namespace ICSharpCode.Decompiler.IL @@ -2860,6 +2864,286 @@ namespace ICSharpCode.Decompiler.IL
}
}
namespace ICSharpCode.Decompiler.IL
{
/// <summary>memcpy(destAddress, sourceAddress, size);</summary>
public sealed partial class Cpblk : ILInstruction, ISupportsVolatilePrefix, ISupportsUnalignedPrefix
{
public Cpblk(ILInstruction destAddress, ILInstruction sourceAddress, ILInstruction size) : base(OpCode.Cpblk)
{
this.DestAddress = destAddress;
this.SourceAddress = sourceAddress;
this.Size = size;
}
public static readonly SlotInfo DestAddressSlot = new SlotInfo("DestAddress", canInlineInto: true);
ILInstruction destAddress;
public ILInstruction DestAddress {
get { return this.destAddress; }
set {
ValidateChild(value);
SetChildInstruction(ref this.destAddress, value, 0);
}
}
public static readonly SlotInfo SourceAddressSlot = new SlotInfo("SourceAddress", canInlineInto: true);
ILInstruction sourceAddress;
public ILInstruction SourceAddress {
get { return this.sourceAddress; }
set {
ValidateChild(value);
SetChildInstruction(ref this.sourceAddress, value, 1);
}
}
public static readonly SlotInfo SizeSlot = new SlotInfo("Size", canInlineInto: true);
ILInstruction size;
public ILInstruction Size {
get { return this.size; }
set {
ValidateChild(value);
SetChildInstruction(ref this.size, value, 2);
}
}
protected sealed override int GetChildCount()
{
return 3;
}
protected sealed override ILInstruction GetChild(int index)
{
switch (index) {
case 0:
return this.destAddress;
case 1:
return this.sourceAddress;
case 2:
return this.size;
default:
throw new IndexOutOfRangeException();
}
}
protected sealed override void SetChild(int index, ILInstruction value)
{
switch (index) {
case 0:
this.DestAddress = value;
break;
case 1:
this.SourceAddress = value;
break;
case 2:
this.Size = value;
break;
default:
throw new IndexOutOfRangeException();
}
}
protected sealed override SlotInfo GetChildSlot(int index)
{
switch (index) {
case 0:
return DestAddressSlot;
case 1:
return SourceAddressSlot;
case 2:
return SizeSlot;
default:
throw new IndexOutOfRangeException();
}
}
public sealed override ILInstruction Clone()
{
var clone = (Cpblk)ShallowClone();
clone.DestAddress = this.destAddress.Clone();
clone.SourceAddress = this.sourceAddress.Clone();
clone.Size = this.size.Clone();
return clone;
}
/// <summary>Gets/Sets whether the memory access is volatile.</summary>
public bool IsVolatile { get; set; }
/// <summary>Returns the alignment specified by the 'unaligned' prefix; or 0 if there was no 'unaligned' prefix.</summary>
public byte UnalignedPrefix { get; set; }
public override StackType ResultType { get { return StackType.Void; } }
protected override InstructionFlags ComputeFlags()
{
return destAddress.Flags | sourceAddress.Flags | size.Flags | InstructionFlags.MayThrow | InstructionFlags.SideEffect;
}
public override InstructionFlags DirectFlags {
get {
return InstructionFlags.MayThrow | InstructionFlags.SideEffect;
}
}
public override void WriteTo(ITextOutput output, ILAstWritingOptions options)
{
if (IsVolatile)
output.Write("volatile.");
if (UnalignedPrefix > 0)
output.Write("unaligned(" + UnalignedPrefix + ").");
output.Write(OpCode);
output.Write('(');
this.destAddress.WriteTo(output, options);
output.Write(", ");
this.sourceAddress.WriteTo(output, options);
output.Write(", ");
this.size.WriteTo(output, options);
output.Write(')');
}
public override void AcceptVisitor(ILVisitor visitor)
{
visitor.VisitCpblk(this);
}
public override T AcceptVisitor<T>(ILVisitor<T> visitor)
{
return visitor.VisitCpblk(this);
}
public override T AcceptVisitor<C, T>(ILVisitor<C, T> visitor, C context)
{
return visitor.VisitCpblk(this, context);
}
protected internal override bool PerformMatch(ILInstruction other, ref Patterns.Match match)
{
var o = other as Cpblk;
return o != null && this.destAddress.PerformMatch(o.destAddress, ref match) && this.sourceAddress.PerformMatch(o.sourceAddress, ref match) && this.size.PerformMatch(o.size, ref match) && IsVolatile == o.IsVolatile && UnalignedPrefix == o.UnalignedPrefix;
}
}
}
namespace ICSharpCode.Decompiler.IL
{
/// <summary>memset(address, value, size)</summary>
public sealed partial class Initblk : ILInstruction, ISupportsVolatilePrefix, ISupportsUnalignedPrefix
{
public Initblk(ILInstruction address, ILInstruction value, ILInstruction size) : base(OpCode.Initblk)
{
this.Address = address;
this.Value = value;
this.Size = size;
}
public static readonly SlotInfo AddressSlot = new SlotInfo("Address", canInlineInto: true);
ILInstruction address;
public ILInstruction Address {
get { return this.address; }
set {
ValidateChild(value);
SetChildInstruction(ref this.address, value, 0);
}
}
public static readonly SlotInfo ValueSlot = new SlotInfo("Value", canInlineInto: true);
ILInstruction value;
public ILInstruction Value {
get { return this.value; }
set {
ValidateChild(value);
SetChildInstruction(ref this.value, value, 1);
}
}
public static readonly SlotInfo SizeSlot = new SlotInfo("Size", canInlineInto: true);
ILInstruction size;
public ILInstruction Size {
get { return this.size; }
set {
ValidateChild(value);
SetChildInstruction(ref this.size, value, 2);
}
}
protected sealed override int GetChildCount()
{
return 3;
}
protected sealed override ILInstruction GetChild(int index)
{
switch (index) {
case 0:
return this.address;
case 1:
return this.value;
case 2:
return this.size;
default:
throw new IndexOutOfRangeException();
}
}
protected sealed override void SetChild(int index, ILInstruction value)
{
switch (index) {
case 0:
this.Address = value;
break;
case 1:
this.Value = value;
break;
case 2:
this.Size = value;
break;
default:
throw new IndexOutOfRangeException();
}
}
protected sealed override SlotInfo GetChildSlot(int index)
{
switch (index) {
case 0:
return AddressSlot;
case 1:
return ValueSlot;
case 2:
return SizeSlot;
default:
throw new IndexOutOfRangeException();
}
}
public sealed override ILInstruction Clone()
{
var clone = (Initblk)ShallowClone();
clone.Address = this.address.Clone();
clone.Value = this.value.Clone();
clone.Size = this.size.Clone();
return clone;
}
/// <summary>Gets/Sets whether the memory access is volatile.</summary>
public bool IsVolatile { get; set; }
/// <summary>Returns the alignment specified by the 'unaligned' prefix; or 0 if there was no 'unaligned' prefix.</summary>
public byte UnalignedPrefix { get; set; }
public override StackType ResultType { get { return StackType.Void; } }
protected override InstructionFlags ComputeFlags()
{
return address.Flags | value.Flags | size.Flags | InstructionFlags.MayThrow | InstructionFlags.SideEffect;
}
public override InstructionFlags DirectFlags {
get {
return InstructionFlags.MayThrow | InstructionFlags.SideEffect;
}
}
public override void WriteTo(ITextOutput output, ILAstWritingOptions options)
{
if (IsVolatile)
output.Write("volatile.");
if (UnalignedPrefix > 0)
output.Write("unaligned(" + UnalignedPrefix + ").");
output.Write(OpCode);
output.Write('(');
this.address.WriteTo(output, options);
output.Write(", ");
this.value.WriteTo(output, options);
output.Write(", ");
this.size.WriteTo(output, options);
output.Write(')');
}
public override void AcceptVisitor(ILVisitor visitor)
{
visitor.VisitInitblk(this);
}
public override T AcceptVisitor<T>(ILVisitor<T> visitor)
{
return visitor.VisitInitblk(this);
}
public override T AcceptVisitor<C, T>(ILVisitor<C, T> visitor, C context)
{
return visitor.VisitInitblk(this, context);
}
protected internal override bool PerformMatch(ILInstruction other, ref Patterns.Match match)
{
var o = other as Initblk;
return o != null && this.address.PerformMatch(o.address, ref match) && this.value.PerformMatch(o.value, ref match) && this.size.PerformMatch(o.size, ref match) && IsVolatile == o.IsVolatile && UnalignedPrefix == o.UnalignedPrefix;
}
}
}
namespace ICSharpCode.Decompiler.IL
{
/// <summary>Load address of instance field</summary>
public sealed partial class LdFlda : ILInstruction, IInstructionWithFieldOperand
@ -4561,6 +4845,14 @@ namespace ICSharpCode.Decompiler.IL @@ -4561,6 +4845,14 @@ namespace ICSharpCode.Decompiler.IL
{
Default(inst);
}
protected internal virtual void VisitCpblk(Cpblk inst)
{
Default(inst);
}
protected internal virtual void VisitInitblk(Initblk inst)
{
Default(inst);
}
protected internal virtual void VisitLdFlda(LdFlda inst)
{
Default(inst);
@ -4847,6 +5139,14 @@ namespace ICSharpCode.Decompiler.IL @@ -4847,6 +5139,14 @@ namespace ICSharpCode.Decompiler.IL
{
return Default(inst);
}
protected internal virtual T VisitCpblk(Cpblk inst)
{
return Default(inst);
}
protected internal virtual T VisitInitblk(Initblk inst)
{
return Default(inst);
}
protected internal virtual T VisitLdFlda(LdFlda inst)
{
return Default(inst);
@ -5133,6 +5433,14 @@ namespace ICSharpCode.Decompiler.IL @@ -5133,6 +5433,14 @@ namespace ICSharpCode.Decompiler.IL
{
return Default(inst, context);
}
protected internal virtual T VisitCpblk(Cpblk inst, C context)
{
return Default(inst, context);
}
protected internal virtual T VisitInitblk(Initblk inst, C context)
{
return Default(inst, context);
}
protected internal virtual T VisitLdFlda(LdFlda inst, C context)
{
return Default(inst, context);
@ -5276,6 +5584,8 @@ namespace ICSharpCode.Decompiler.IL @@ -5276,6 +5584,8 @@ namespace ICSharpCode.Decompiler.IL
"ldtypetoken",
"ldmembertoken",
"localloc",
"cpblk",
"initblk",
"ldflda",
"ldsflda",
"castclass",
@ -5585,6 +5895,34 @@ namespace ICSharpCode.Decompiler.IL @@ -5585,6 +5895,34 @@ namespace ICSharpCode.Decompiler.IL
argument = default(ILInstruction);
return false;
}
public bool MatchCpblk(out ILInstruction destAddress, out ILInstruction sourceAddress, out ILInstruction size)
{
var inst = this as Cpblk;
if (inst != null) {
destAddress = inst.DestAddress;
sourceAddress = inst.SourceAddress;
size = inst.Size;
return true;
}
destAddress = default(ILInstruction);
sourceAddress = default(ILInstruction);
size = default(ILInstruction);
return false;
}
public bool MatchInitblk(out ILInstruction address, out ILInstruction value, out ILInstruction size)
{
var inst = this as Initblk;
if (inst != null) {
address = inst.Address;
value = inst.Value;
size = inst.Size;
return true;
}
address = default(ILInstruction);
value = default(ILInstruction);
size = default(ILInstruction);
return false;
}
public bool MatchLdFlda(out ILInstruction target, out IField field)
{
var inst = this as LdFlda;

10
ICSharpCode.Decompiler/IL/Instructions.tt

@ -176,7 +176,15 @@ @@ -176,7 +176,15 @@
CustomClassName("LdMemberToken"), NoArguments, HasMemberOperand, ResultType("O")),
new OpCode("localloc", "Allocates space in the stack frame",
CustomClassName("LocAlloc"), Unary, ResultType("I"), MayThrow),
new OpCode("cpblk", "memcpy(destAddress, sourceAddress, size);",
CustomArguments("destAddress", "sourceAddress", "size"),
MayThrow, MemoryAccess,
SupportsVolatilePrefix, SupportsUnalignedPrefix, ResultType("Void")),
new OpCode("initblk", "memset(address, value, size)",
CustomArguments("address", "value", "size"),
MayThrow, MemoryAccess,
SupportsVolatilePrefix, SupportsUnalignedPrefix, ResultType("Void")),
new OpCode("ldflda", "Load address of instance field",
CustomClassName("LdFlda"), CustomArguments("target"), MayThrowIfNotDelayed, HasFieldOperand, ResultType("Ref")),
new OpCode("ldsflda", "Load static field address",

Loading…
Cancel
Save