Skip to content

[No merge] Reproing an assert in outerloop #106152

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 8 commits into from
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
Loading