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. 8
      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;

8
ICSharpCode.Decompiler/IL/Instructions.tt

@ -176,6 +176,14 @@ @@ -176,6 +176,14 @@
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")),

Loading…
Cancel
Save