Skip to content

Commit 25237a1

Browse files
committed
Merge pull request icsharpcode#205 - Decompilation of lifted operators
This decompiles the C# generated code for lifted operators back to the original short form. This can result in a significant improvement to the readability of the resulting code in some more complex functions because C# generates 2 temporary locals for lifted operators that can now be inlined. As a byproduct the following improvements are also included: more thorough boolean logic decompilation; various project/solution file improvements; Ldloca support for variable splitting; simplified shift operators (already in icsharpcode branch); significant performance improvement for stack analysis of variables to offset the added complexity from ldloca support; decompilation of compound assignment with overloaded operators; some type analysis refactoring.
2 parents 6d22ff9 + 41e71ea commit 25237a1

27 files changed

+1769
-156
lines changed

AvalonEdit/ICSharpCode.AvalonEdit/ICSharpCode.AvalonEdit.csproj

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@
3333
<DefineConstants>DEBUG;TRACE;DOTNET4</DefineConstants>
3434
</PropertyGroup>
3535
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
36-
<DebugSymbols>false</DebugSymbols>
36+
<DebugSymbols>true</DebugSymbols>
3737
<DebugType>PdbOnly</DebugType>
3838
<Optimize>True</Optimize>
3939
<CheckForOverflowUnderflow>False</CheckForOverflowUnderflow>
@@ -42,9 +42,8 @@
4242
<PropertyGroup Condition=" '$(Platform)' == 'AnyCPU' ">
4343
<RegisterForComInterop>False</RegisterForComInterop>
4444
<GenerateSerializationAssemblies>Auto</GenerateSerializationAssemblies>
45-
<BaseAddress>4194304</BaseAddress>
45+
<BaseAddress>452984832</BaseAddress>
4646
<PlatformTarget>AnyCPU</PlatformTarget>
47-
<FileAlignment>4096</FileAlignment>
4847
</PropertyGroup>
4948
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.Targets" />
5049
<ItemGroup>

ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -421,7 +421,13 @@ AstNode TransformByteCode(ILExpression byteCode)
421421
case ILCode.CompoundAssignment:
422422
{
423423
CastExpression cast = arg1 as CastExpression;
424-
BinaryOperatorExpression boe = (BinaryOperatorExpression)(cast != null ? cast.Expression : arg1);
424+
var boe = cast != null ? (BinaryOperatorExpression)cast.Expression : arg1 as BinaryOperatorExpression;
425+
// AssignmentExpression doesn't support overloaded operators so they have to be processed to BinaryOperatorExpression
426+
if (boe == null) {
427+
var tmp = new ParenthesizedExpression(arg1);
428+
ReplaceMethodCallsWithOperators.ProcessInvocationExpression((InvocationExpression)arg1);
429+
boe = (BinaryOperatorExpression)tmp.Expression;
430+
}
425431
var assignment = new Ast.AssignmentExpression {
426432
Left = boe.Left.Detach(),
427433
Operator = ReplaceMethodCallsWithOperators.GetAssignmentOperatorForBinaryOperator(boe.Operator),
@@ -440,17 +446,25 @@ AstNode TransformByteCode(ILExpression byteCode)
440446
#endregion
441447
#region Comparison
442448
case ILCode.Ceq: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Equality, arg2);
449+
case ILCode.Cne: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.InEquality, arg2);
443450
case ILCode.Cgt: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.GreaterThan, arg2);
444451
case ILCode.Cgt_Un: {
445452
// can also mean Inequality, when used with object references
446453
TypeReference arg1Type = byteCode.Arguments[0].InferredType;
447-
if (arg1Type != null && !arg1Type.IsValueType)
448-
return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.InEquality, arg2);
449-
else
450-
return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.GreaterThan, arg2);
454+
if (arg1Type != null && !arg1Type.IsValueType) goto case ILCode.Cne;
455+
goto case ILCode.Cgt;
456+
}
457+
case ILCode.Cle_Un: {
458+
// can also mean Equality, when used with object references
459+
TypeReference arg1Type = byteCode.Arguments[0].InferredType;
460+
if (arg1Type != null && !arg1Type.IsValueType) goto case ILCode.Ceq;
461+
goto case ILCode.Cle;
451462
}
463+
case ILCode.Cle: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.LessThanOrEqual, arg2);
464+
case ILCode.Cge_Un:
465+
case ILCode.Cge: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.GreaterThanOrEqual, arg2);
466+
case ILCode.Clt_Un:
452467
case ILCode.Clt: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.LessThan, arg2);
453-
case ILCode.Clt_Un: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.LessThan, arg2);
454468
#endregion
455469
#region Logical
456470
case ILCode.LogicNot: return new Ast.UnaryOperatorExpression(UnaryOperatorType.Not, arg1);
@@ -792,8 +806,12 @@ AstNode TransformByteCode(ILExpression byteCode)
792806
}
793807
case ILCode.InitializedObject:
794808
return new InitializedObjectExpression();
809+
case ILCode.Wrap:
810+
return arg1.WithAnnotation(PushNegation.LiftedOperatorAnnotation);
795811
case ILCode.AddressOf:
796812
return MakeRef(arg1);
813+
case ILCode.NullableOf:
814+
case ILCode.ValueOf: return arg1;
797815
default:
798816
throw new Exception("Unknown OpCode: " + byteCode.Code);
799817
}

ICSharpCode.Decompiler/Ast/NameVariables.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,10 @@ string GenerateNameForVariable(ILVariable variable, ILBlock methodBody)
175175
case ILCode.Clt_Un:
176176
case ILCode.Cgt:
177177
case ILCode.Cgt_Un:
178+
case ILCode.Cle:
179+
case ILCode.Cle_Un:
180+
case ILCode.Cge:
181+
case ILCode.Cge_Un:
178182
ILVariable loadVar;
179183
if (expr.Arguments[0].Match(ILCode.Ldloc, out loadVar) && loadVar == variable) {
180184
isLoopCounter = true;

ICSharpCode.Decompiler/Ast/Transforms/PushNegation.cs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,18 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
2626
{
2727
public class PushNegation: DepthFirstAstVisitor<object, object>, IAstTransform
2828
{
29+
sealed class LiftedOperator { }
30+
/// <summary>
31+
/// Annotation for lifted operators that cannot be transformed by PushNegation
32+
/// </summary>
33+
public static readonly object LiftedOperatorAnnotation = new LiftedOperator();
34+
2935
public override object VisitUnaryOperatorExpression(UnaryOperatorExpression unary, object data)
3036
{
37+
// lifted operators can't be transformed
38+
if (unary.Annotation<LiftedOperator>() != null || unary.Expression.Annotation<LiftedOperator>() != null)
39+
return base.VisitUnaryOperatorExpression(unary, data);
40+
3141
// Remove double negation
3242
// !!a
3343
if (unary.Operator == UnaryOperatorType.Not &&
@@ -108,6 +118,10 @@ unary.Expression is UnaryOperatorExpression &&
108118

109119
public override object VisitBinaryOperatorExpression(BinaryOperatorExpression binaryOperatorExpression, object data)
110120
{
121+
// lifted operators can't be transformed
122+
if (binaryOperatorExpression.Annotation<LiftedOperator>() != null)
123+
return base.VisitBinaryOperatorExpression(binaryOperatorExpression, data);
124+
111125
BinaryOperatorType op = binaryOperatorExpression.Operator;
112126
bool? rightOperand = null;
113127
if (binaryOperatorExpression.Right is PrimitiveExpression)

ICSharpCode.Decompiler/Ast/Transforms/ReplaceMethodCallsWithOperators.cs

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,11 @@ public override object VisitInvocationExpression(InvocationExpression invocation
5151
{
5252
base.VisitInvocationExpression(invocationExpression, data);
5353

54+
return ProcessInvocationExpression(invocationExpression);
55+
}
56+
57+
internal static object ProcessInvocationExpression(InvocationExpression invocationExpression)
58+
{
5459
MethodReference methodRef = invocationExpression.Annotation<MethodReference>();
5560
if (methodRef == null)
5661
return null;
@@ -115,7 +120,7 @@ public override object VisitInvocationExpression(InvocationExpression invocation
115120
return null;
116121
}
117122

118-
BinaryOperatorType? GetBinaryOperatorTypeFromMetadataName(string name)
123+
static BinaryOperatorType? GetBinaryOperatorTypeFromMetadataName(string name)
119124
{
120125
switch (name) {
121126
case "op_Addition":
@@ -132,7 +137,7 @@ public override object VisitInvocationExpression(InvocationExpression invocation
132137
return BinaryOperatorType.BitwiseAnd;
133138
case "op_BitwiseOr":
134139
return BinaryOperatorType.BitwiseOr;
135-
case "op_ExlusiveOr":
140+
case "op_ExclusiveOr":
136141
return BinaryOperatorType.ExclusiveOr;
137142
case "op_LeftShift":
138143
return BinaryOperatorType.ShiftLeft;
@@ -155,7 +160,7 @@ public override object VisitInvocationExpression(InvocationExpression invocation
155160
}
156161
}
157162

158-
UnaryOperatorType? GetUnaryOperatorTypeFromMetadataName(string name)
163+
static UnaryOperatorType? GetUnaryOperatorTypeFromMetadataName(string name)
159164
{
160165
switch (name) {
161166
case "op_LogicalNot":

ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,7 @@
1919
<PlatformTarget>AnyCPU</PlatformTarget>
2020
<RegisterForComInterop>False</RegisterForComInterop>
2121
<GenerateSerializationAssemblies>Auto</GenerateSerializationAssemblies>
22-
<BaseAddress>4194304</BaseAddress>
23-
<FileAlignment>4096</FileAlignment>
22+
<BaseAddress>448462848</BaseAddress>
2423
</PropertyGroup>
2524
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
2625
<OutputPath>bin\Debug\</OutputPath>
@@ -32,8 +31,8 @@
3231
</PropertyGroup>
3332
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
3433
<OutputPath>bin\Release\</OutputPath>
35-
<DebugSymbols>False</DebugSymbols>
36-
<DebugType>None</DebugType>
34+
<DebugSymbols>true</DebugSymbols>
35+
<DebugType>PdbOnly</DebugType>
3736
<Optimize>True</Optimize>
3837
<CheckForOverflowUnderflow>False</CheckForOverflowUnderflow>
3938
<DefineConstants>TRACE</DefineConstants>
@@ -96,6 +95,7 @@
9695
<Compile Include="FlowAnalysis\SsaOptimization.cs" />
9796
<Compile Include="FlowAnalysis\SsaVariable.cs" />
9897
<Compile Include="FlowAnalysis\TransformToSsa.cs" />
98+
<Compile Include="ILAst\LiftedOperators.cs" />
9999
<Compile Include="ILAst\InitializerPeepholeTransforms.cs" />
100100
<Compile Include="ILAst\DefaultDictionary.cs" />
101101
<Compile Include="ILAst\GotoRemoval.cs" />

ICSharpCode.Decompiler/ILAst/ILAstBuilder.cs

Lines changed: 40 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -339,9 +339,10 @@ List<ByteCode> StackAnalysis(MethodDefinition methodDef)
339339

340340
// Calculate new variable state
341341
VariableSlot[] newVariableState = VariableSlot.CloneVariableState(byteCode.VariablesBefore);
342-
if (byteCode.Code == ILCode.Stloc) {
342+
if (byteCode.Code == ILCode.Stloc || byteCode.Code == ILCode.Ldloca) {
343343
int varIndex = ((VariableReference)byteCode.Operand).Index;
344-
newVariableState[varIndex] = new VariableSlot(byteCode);
344+
newVariableState[varIndex] = byteCode.Code == ILCode.Stloc || byteCode.Next.Code == ILCode.Initobj ?
345+
new VariableSlot(byteCode) : new VariableSlot(newVariableState[varIndex].StoredBy.Union(byteCode), false);
345346
}
346347

347348
// After the leave, finally block might have touched the variables
@@ -523,17 +524,20 @@ void ConvertLocalVariables(List<ByteCode> body)
523524

524525
for(int variableIndex = 0; variableIndex < varCount; variableIndex++) {
525526
// Find all stores and loads for this variable
526-
List<ByteCode> stores = body.Where(b => b.Code == ILCode.Stloc && b.Operand is VariableDefinition && b.OperandAsVariable.Index == variableIndex).ToList();
527-
List<ByteCode> loads = body.Where(b => (b.Code == ILCode.Ldloc || b.Code == ILCode.Ldloca) && b.Operand is VariableDefinition && b.OperandAsVariable.Index == variableIndex).ToList();
527+
var stores = body.Where(b => (b.Code == ILCode.Stloc || b.Code == ILCode.Ldloca) && b.Operand is VariableDefinition && b.OperandAsVariable.Index == variableIndex).ToList();
528+
// ldloca on an uninitialized variable or followed by initobj isn't considered a load
529+
var loads = body.Where(b =>
530+
(b.Code == ILCode.Ldloc || (b.Code == ILCode.Ldloca && b.Next.Code != ILCode.Initobj &&
531+
(b.VariablesBefore[variableIndex].StoredBy.Length != 0 || b.VariablesBefore[variableIndex].StoredByAll)))
532+
&& b.Operand is VariableDefinition && b.OperandAsVariable.Index == variableIndex).ToList();
528533
TypeReference varType = methodDef.Body.Variables[variableIndex].VariableType;
529534

530535
List<VariableInfo> newVars;
531536

532537
bool isPinned = methodDef.Body.Variables[variableIndex].IsPinned;
533538
// If the variable is pinned, use single variable.
534539
// If any of the loads is from "all", use single variable
535-
// If any of the loads is ldloca, fallback to single variable as well
536-
if (isPinned || loads.Any(b => b.VariablesBefore[variableIndex].StoredByAll || b.Code == ILCode.Ldloca)) {
540+
if (isPinned || loads.Any(b => b.VariablesBefore[variableIndex].StoredByAll)) {
537541
newVars = new List<VariableInfo>(1) { new VariableInfo() {
538542
Variable = new ILVariable() {
539543
Name = "var_" + variableIndex,
@@ -545,7 +549,12 @@ void ConvertLocalVariables(List<ByteCode> body)
545549
}};
546550
} else {
547551
// Create a new variable for each store
548-
newVars = stores.Select(st => new VariableInfo() {
552+
newVars = stores.Where(st =>
553+
{
554+
if (st.Code == ILCode.Stloc || st.Next.Code == ILCode.Initobj) return true;
555+
var storedBy = st.VariablesBefore[variableIndex].StoredBy;
556+
return storedBy.Length == 0 || storedBy[0] == st;
557+
}).Select(st => new VariableInfo() {
549558
Variable = new ILVariable() {
550559
Name = "var_" + variableIndex + "_" + st.Offset.ToString("X2"),
551560
Type = varType,
@@ -582,14 +591,16 @@ void ConvertLocalVariables(List<ByteCode> body)
582591
} else if (storedBy.Length == 1) {
583592
VariableInfo newVar = newVars.Single(v => v.Stores.Contains(storedBy[0]));
584593
newVar.Loads.Add(load);
594+
if (load.Code == ILCode.Ldloca) newVar.Stores.Add(load);
585595
} else {
586-
List<VariableInfo> mergeVars = newVars.Where(v => v.Stores.Union(storedBy).Any()).ToList();
596+
List<VariableInfo> mergeVars = newVars.Where(v => v.Stores.Intersect(storedBy).Any()).ToList();
587597
VariableInfo mergedVar = new VariableInfo() {
588598
Variable = mergeVars[0].Variable,
589599
Stores = mergeVars.SelectMany(v => v.Stores).ToList(),
590600
Loads = mergeVars.SelectMany(v => v.Loads).ToList()
591601
};
592602
mergedVar.Loads.Add(load);
603+
if (load.Code == ILCode.Ldloca) mergedVar.Stores.Add(load);
593604
newVars = newVars.Except(mergeVars).ToList();
594605
newVars.Add(mergedVar);
595606
}
@@ -819,15 +830,34 @@ public static List<T> CutRange<T>(this List<T> list, int start, int count)
819830
list.RemoveRange(start, count);
820831
return ret;
821832
}
833+
834+
public static T[] Union<T>(this T[] a, T b)
835+
{
836+
if (a.Length == 0)
837+
return new[] { b };
838+
if (Array.IndexOf(a, b) >= 0)
839+
return a;
840+
var res = new T[a.Length + 1];
841+
Array.Copy(a, res, a.Length);
842+
res[res.Length - 1] = b;
843+
return res;
844+
}
822845

823846
public static T[] Union<T>(this T[] a, T[] b)
824847
{
848+
if (a == b)
849+
return a;
825850
if (a.Length == 0)
826851
return b;
827852
if (b.Length == 0)
828853
return a;
829-
if (a.Length == 1 && b.Length == 1 && a[0].Equals(b[0]))
830-
return a;
854+
if (a.Length == 1) {
855+
if (b.Length == 1)
856+
return a[0].Equals(b[0]) ? a : new[] { a[0], b[0] };
857+
return b.Union(a[0]);
858+
}
859+
if (b.Length == 1)
860+
return a.Union(b[0]);
831861
return Enumerable.Union(a, b).ToArray();
832862
}
833863
}

ICSharpCode.Decompiler/ILAst/ILAstOptimizer.cs

Lines changed: 24 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -42,10 +42,12 @@ public enum ILAstOptimizationStep
4242
SimplifyTernaryOperator,
4343
SimplifyNullCoalescing,
4444
JoinBasicBlocks,
45+
SimplifyLogicNot,
4546
SimplifyShiftOperators,
4647
TransformDecimalCtorToConstant,
4748
SimplifyLdObjAndStObj,
4849
SimplifyCustomShortCircuit,
50+
SimplifyLiftedOperators,
4951
TransformArrayInitializers,
5052
TransformMultidimensionalArrayInitializers,
5153
TransformObjectInitializers,
@@ -134,6 +136,9 @@ public void Optimize(DecompilerContext context, ILBlock method, ILAstOptimizatio
134136
if (abortBeforeStep == ILAstOptimizationStep.JoinBasicBlocks) return;
135137
modified |= block.RunOptimization(new SimpleControlFlow(context, method).JoinBasicBlocks);
136138

139+
if (abortBeforeStep == ILAstOptimizationStep.SimplifyLogicNot) return;
140+
modified |= block.RunOptimization(SimplifyLogicNot);
141+
137142
if (abortBeforeStep == ILAstOptimizationStep.SimplifyShiftOperators) return;
138143
modified |= block.RunOptimization(SimplifyShiftOperators);
139144

@@ -146,6 +151,9 @@ public void Optimize(DecompilerContext context, ILBlock method, ILAstOptimizatio
146151

147152
if (abortBeforeStep == ILAstOptimizationStep.SimplifyCustomShortCircuit) return;
148153
modified |= block.RunOptimization(new SimpleControlFlow(context, method).SimplifyCustomShortCircuit);
154+
155+
if (abortBeforeStep == ILAstOptimizationStep.SimplifyLiftedOperators) return;
156+
modified |= block.RunOptimization(SimplifyLiftedOperators);
149157

150158
if (abortBeforeStep == ILAstOptimizationStep.TransformArrayInitializers) return;
151159
modified |= block.RunOptimization(TransformArrayInitializers);
@@ -307,27 +315,30 @@ void ReduceBranchInstructionSet(ILBlock block)
307315
for (int i = 0; i < block.Body.Count; i++) {
308316
ILExpression expr = block.Body[i] as ILExpression;
309317
if (expr != null && expr.Prefixes == null) {
318+
ILCode op;
310319
switch(expr.Code) {
311320
case ILCode.Switch:
312321
case ILCode.Brtrue:
313322
expr.Arguments.Single().ILRanges.AddRange(expr.ILRanges);
314323
expr.ILRanges.Clear();
315324
continue;
316-
case ILCode.__Brfalse: block.Body[i] = new ILExpression(ILCode.Brtrue, expr.Operand, new ILExpression(ILCode.LogicNot, null, expr.Arguments.Single())); break;
317-
case ILCode.__Beq: block.Body[i] = new ILExpression(ILCode.Brtrue, expr.Operand, new ILExpression(ILCode.Ceq, null, expr.Arguments)); break;
318-
case ILCode.__Bne_Un: block.Body[i] = new ILExpression(ILCode.Brtrue, expr.Operand, new ILExpression(ILCode.LogicNot, null, new ILExpression(ILCode.Ceq, null, expr.Arguments))); break;
319-
case ILCode.__Bgt: block.Body[i] = new ILExpression(ILCode.Brtrue, expr.Operand, new ILExpression(ILCode.Cgt, null, expr.Arguments)); break;
320-
case ILCode.__Bgt_Un: block.Body[i] = new ILExpression(ILCode.Brtrue, expr.Operand, new ILExpression(ILCode.Cgt_Un, null, expr.Arguments)); break;
321-
case ILCode.__Ble: block.Body[i] = new ILExpression(ILCode.Brtrue, expr.Operand, new ILExpression(ILCode.LogicNot, null, new ILExpression(ILCode.Cgt, null, expr.Arguments))); break;
322-
case ILCode.__Ble_Un: block.Body[i] = new ILExpression(ILCode.Brtrue, expr.Operand, new ILExpression(ILCode.LogicNot, null, new ILExpression(ILCode.Cgt_Un, null, expr.Arguments))); break;
323-
case ILCode.__Blt: block.Body[i] = new ILExpression(ILCode.Brtrue, expr.Operand, new ILExpression(ILCode.Clt, null, expr.Arguments)); break;
324-
case ILCode.__Blt_Un: block.Body[i] = new ILExpression(ILCode.Brtrue, expr.Operand, new ILExpression(ILCode.Clt_Un, null, expr.Arguments)); break;
325-
case ILCode.__Bge: block.Body[i] = new ILExpression(ILCode.Brtrue, expr.Operand, new ILExpression(ILCode.LogicNot, null, new ILExpression(ILCode.Clt, null, expr.Arguments))); break;
326-
case ILCode.__Bge_Un: block.Body[i] = new ILExpression(ILCode.Brtrue, expr.Operand, new ILExpression(ILCode.LogicNot, null, new ILExpression(ILCode.Clt_Un, null, expr.Arguments))); break;
325+
case ILCode.__Brfalse: op = ILCode.LogicNot; break;
326+
case ILCode.__Beq: op = ILCode.Ceq; break;
327+
case ILCode.__Bne_Un: op = ILCode.Cne; break;
328+
case ILCode.__Bgt: op = ILCode.Cgt; break;
329+
case ILCode.__Bgt_Un: op = ILCode.Cgt_Un; break;
330+
case ILCode.__Ble: op = ILCode.Cle; break;
331+
case ILCode.__Ble_Un: op = ILCode.Cle_Un; break;
332+
case ILCode.__Blt: op = ILCode.Clt; break;
333+
case ILCode.__Blt_Un: op = ILCode.Clt_Un; break;
334+
case ILCode.__Bge: op = ILCode.Cge; break;
335+
case ILCode.__Bge_Un: op = ILCode.Cge_Un; break;
327336
default:
328337
continue;
329338
}
330-
((ILExpression)block.Body[i]).Arguments.Single().ILRanges.AddRange(expr.ILRanges);
339+
var newExpr = new ILExpression(op, null, expr.Arguments);
340+
block.Body[i] = new ILExpression(ILCode.Brtrue, expr.Operand, newExpr);
341+
newExpr.ILRanges = expr.ILRanges;
331342
}
332343
}
333344
}
@@ -721,6 +732,7 @@ public static bool HasNoSideEffects(this ILExpression expr)
721732
case ILCode.Ldc_I8:
722733
case ILCode.Ldc_R4:
723734
case ILCode.Ldc_R8:
735+
case ILCode.Ldc_Decimal:
724736
return true;
725737
default:
726738
return false;

0 commit comments

Comments
 (0)