Skip to content
Closed
Original file line number Diff line number Diff line change
Expand Up @@ -659,6 +659,67 @@ public MethodIL GetMethodILWithInlinedSubstitutions(MethodIL method)
return new SubstitutedMethodIL(method.GetMethodILDefinition(), newBody, newEHRegions.ToArray(), debugInfo, newStrings.ToArray());
}

private bool TryGetMethodConstantValue(MethodDesc method, out int constant, int level = 0)
{
method = method.GetTypicalMethodDefinition();

TypeFlags returnType = method.Signature.ReturnType.UnderlyingType.Category;
if (returnType is < TypeFlags.Boolean or > TypeFlags.UInt32
|| method.IsIntrinsic
|| _nestedILProvider.GetMethodIL(method) is not MethodIL methodIL)
{
constant = 0;
return false;
}

var reader = new ILReader(methodIL.GetILBytes());
var opcode = reader.ReadILOpcode();
switch (opcode)
{
case ILOpcode.ldc_i4: constant = (int)reader.ReadILUInt32(); break;
case ILOpcode.ldc_i4_s: constant = (sbyte)reader.ReadILByte(); break;
case >= ILOpcode.ldc_i4_0 and <= ILOpcode.ldc_i4_8: constant = opcode - ILOpcode.ldc_i4_0; break;
case ILOpcode.ldc_i4_m1: constant = -1; break;

case ILOpcode.call:
{
MethodDesc callee = (MethodDesc)methodIL.GetObject(reader.ReadILToken());
if (reader.ReadILOpcode() != ILOpcode.ret)
{
constant = 0;
return false;
}

BodySubstitution substitution = _substitutionProvider.GetSubstitution(method);
if (substitution != null && substitution.Value is int c)
{
constant = c;
return true;
}

if (level > 4)
{
constant = 0;
return false;
}

return TryGetMethodConstantValue(callee, out constant, level + 1);
}

default:
constant = 0;
return false;
}

if (reader.ReadILOpcode() != ILOpcode.ret)
{
constant = 0;
return false;
}

return true;
}

private bool TryGetConstantArgument(MethodIL methodIL, byte[] body, OpcodeFlags[] flags, int offset, int argIndex, out int constant)
{
if ((flags[offset] & OpcodeFlags.BasicBlockStart) != 0)
Expand Down Expand Up @@ -686,6 +747,11 @@ private bool TryGetConstantArgument(MethodIL methodIL, byte[] body, OpcodeFlags[
constant = (int)substitution.Value;
return true;
}
if ((opcode != ILOpcode.callvirt || !method.IsVirtual)
&& TryGetMethodConstantValue(method, out constant))
{
return true;
}
else if (method.IsIntrinsic && method.Name is "get_IsValueType" or "get_IsEnum"
&& method.OwningType is MetadataType mdt
&& mdt.Name == "Type" && mdt.Namespace == "System" && mdt.Module == mdt.Context.SystemModule
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ public static int Run()
TestAbstractNeverDerivedWithDevirtualizedCall.Run();
TestAbstractDerivedByUnrelatedTypeWithDevirtualizedCall.Run();
TestUnusedDefaultInterfaceMethod.Run();
TestInlinedDeadBranchElimination.Run();
TestArrayElementTypeOperations.Run();
TestStaticVirtualMethodOptimizations.Run();
TestTypeEquals.Run();
Expand Down Expand Up @@ -251,6 +252,37 @@ public static void Run()
}
}

class TestInlinedDeadBranchElimination
{
static int GetIntConstant() => 42;
static int GetIntConstantWrapper() => GetIntConstant();

class NeverReferenced1 { }

enum MyEnum { One, Two }

static MyEnum GetEnumConstant() => MyEnum.Two;

class NeverReferenced2 { }

public static void Run()
{
if (GetIntConstantWrapper() == 1)
{
Activator.CreateInstance(typeof(NeverReferenced1));
}

ThrowIfPresent(typeof(TestInlinedDeadBranchElimination), nameof(NeverReferenced1));

if (GetEnumConstant() == MyEnum.One)
{
Activator.CreateInstance(typeof(NeverReferenced2));
}

ThrowIfPresent(typeof(TestInlinedDeadBranchElimination), nameof(NeverReferenced2));
}
}

class TestArrayElementTypeOperations
{
public static void Run()
Expand Down