﻿// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

using System;
using System.Diagnostics;
using System.Reflection.Metadata;
using Roslyn.Utilities;

namespace Microsoft.CodeAnalysis.CodeGen
{
    internal static partial class ILOpCodeExtensions
    {
        public static int Size(this ILOpCode opcode)
        {
            int code = (int)opcode;
            if (code <= 0xff)
            {
                Debug.Assert(code < 0xf0);
                return 1;
            }
            else
            {
                Debug.Assert((code & 0xff00) == 0xfe00);
                return 2;
            }
        }

        public static ILOpCode GetLeaveOpcode(this ILOpCode opcode)
        {
            switch (opcode)
            {
                case ILOpCode.Br:
                    return ILOpCode.Leave;

                case ILOpCode.Br_s:
                    return ILOpCode.Leave_s;
            }

            throw ExceptionUtilities.UnexpectedValue(opcode);
        }

        public static bool HasVariableStackBehavior(this ILOpCode opcode)
        {
            switch (opcode)
            {
                case ILOpCode.Call:
                case ILOpCode.Calli:
                case ILOpCode.Callvirt:
                case ILOpCode.Newobj:
                case ILOpCode.Ret:
                    return true;
            }
            return false;
        }

        /// <summary>
        /// These opcodes represent control transfer.
        /// They should not appear inside basic blocks.
        /// </summary>
        public static bool IsControlTransfer(this ILOpCode opcode)
        {
            if (opcode.IsBranch())
            {
                return true;
            }

            switch (opcode)
            {
                case ILOpCode.Ret:
                case ILOpCode.Throw:
                case ILOpCode.Rethrow:
                case ILOpCode.Endfilter:
                case ILOpCode.Endfinally:
                case ILOpCode.Switch:
                case ILOpCode.Jmp:
                    return true;
            }
            return false;
        }

        public static bool IsConditionalBranch(this ILOpCode opcode)
        {
            switch (opcode)
            {
                case ILOpCode.Brtrue:
                case ILOpCode.Brtrue_s:
                case ILOpCode.Brfalse:
                case ILOpCode.Brfalse_s:
                case ILOpCode.Beq:
                case ILOpCode.Beq_s:
                case ILOpCode.Bne_un:
                case ILOpCode.Bne_un_s:
                case ILOpCode.Bge:
                case ILOpCode.Bge_s:
                case ILOpCode.Bge_un:
                case ILOpCode.Bge_un_s:
                case ILOpCode.Bgt:
                case ILOpCode.Bgt_s:
                case ILOpCode.Bgt_un:
                case ILOpCode.Bgt_un_s:
                case ILOpCode.Ble:
                case ILOpCode.Ble_s:
                case ILOpCode.Ble_un:
                case ILOpCode.Ble_un_s:
                case ILOpCode.Blt:
                case ILOpCode.Blt_s:
                case ILOpCode.Blt_un:
                case ILOpCode.Blt_un_s:
                    return true;
                    // these are not conditional

                    //case ILOpCode.Br:
                    //case ILOpCode.Br_s:
                    //case ILOpCode.Leave:
                    //case ILOpCode.Leave_s:

                    // this is treated specially. It will not use regular single label
                    //case ILOpCode.Switch
            }

            return false;
        }

        public static bool IsRelationalBranch(this ILOpCode opcode)
        {
            switch (opcode)
            {
                case ILOpCode.Beq:
                case ILOpCode.Beq_s:
                case ILOpCode.Bne_un:
                case ILOpCode.Bne_un_s:
                case ILOpCode.Bge:
                case ILOpCode.Bge_s:
                case ILOpCode.Bge_un:
                case ILOpCode.Bge_un_s:
                case ILOpCode.Bgt:
                case ILOpCode.Bgt_s:
                case ILOpCode.Bgt_un:
                case ILOpCode.Bgt_un_s:
                case ILOpCode.Ble:
                case ILOpCode.Ble_s:
                case ILOpCode.Ble_un:
                case ILOpCode.Ble_un_s:
                case ILOpCode.Blt:
                case ILOpCode.Blt_s:
                case ILOpCode.Blt_un:
                case ILOpCode.Blt_un_s:
                    return true;
            }

            return false;
        }

        /// <summary>
        /// Opcodes that represents a branch to a label.
        /// </summary>
        public static bool CanFallThrough(this ILOpCode opcode)
        {
            //12.4.2.8.1  Most instructions can allow control to fall through after their execution—only unconditional branches,
            //ret, jmp, leave(.s), endfinally, endfault, endfilter, throw, and rethrow do not.
            switch (opcode)
            {
                case ILOpCode.Br:
                case ILOpCode.Br_s:
                case ILOpCode.Ret:
                case ILOpCode.Jmp:
                case ILOpCode.Throw:
                //NOTE: from the codegen view endfilter is a logical  "brfalse <continueHandlerSearch>" 
                //      endfilter must be used once at the end of the filter and must be lexically followed by the handler
                //      to which the control returns if filter result was 1.
                //case ILOpCode.Endfilter:
                case ILOpCode.Endfinally:
                case ILOpCode.Leave:
                case ILOpCode.Leave_s:
                case ILOpCode.Rethrow:
                    return false;
            }

            return true;
        }

        public static int NetStackBehavior(this ILOpCode opcode)
        {
            Debug.Assert(!opcode.HasVariableStackBehavior());
            return opcode.StackPushCount() - opcode.StackPopCount();
        }

        public static int StackPopCount(this ILOpCode opcode)
        {
            switch (opcode)
            {
                case ILOpCode.Nop:
                case ILOpCode.Break:
                case ILOpCode.Ldarg_0:
                case ILOpCode.Ldarg_1:
                case ILOpCode.Ldarg_2:
                case ILOpCode.Ldarg_3:
                case ILOpCode.Ldloc_0:
                case ILOpCode.Ldloc_1:
                case ILOpCode.Ldloc_2:
                case ILOpCode.Ldloc_3:
                    return 0;
                case ILOpCode.Stloc_0:
                case ILOpCode.Stloc_1:
                case ILOpCode.Stloc_2:
                case ILOpCode.Stloc_3:
                    return 1;
                case ILOpCode.Ldarg_s:
                case ILOpCode.Ldarga_s:
                    return 0;
                case ILOpCode.Starg_s:
                    return 1;
                case ILOpCode.Ldloc_s:
                case ILOpCode.Ldloca_s:
                    return 0;
                case ILOpCode.Stloc_s:
                    return 1;
                case ILOpCode.Ldnull:
                case ILOpCode.Ldc_i4_m1:
                case ILOpCode.Ldc_i4_0:
                case ILOpCode.Ldc_i4_1:
                case ILOpCode.Ldc_i4_2:
                case ILOpCode.Ldc_i4_3:
                case ILOpCode.Ldc_i4_4:
                case ILOpCode.Ldc_i4_5:
                case ILOpCode.Ldc_i4_6:
                case ILOpCode.Ldc_i4_7:
                case ILOpCode.Ldc_i4_8:
                case ILOpCode.Ldc_i4_s:
                case ILOpCode.Ldc_i4:
                case ILOpCode.Ldc_i8:
                case ILOpCode.Ldc_r4:
                case ILOpCode.Ldc_r8:
                    return 0;
                case ILOpCode.Dup:
                case ILOpCode.Pop:
                    return 1;
                case ILOpCode.Jmp:
                    return 0;
                case ILOpCode.Call:
                case ILOpCode.Calli:
                case ILOpCode.Ret:
                    return -1; // Variable
                case ILOpCode.Br_s:
                    return 0;
                case ILOpCode.Brfalse_s:
                case ILOpCode.Brtrue_s:
                    return 1;
                case ILOpCode.Beq_s:
                case ILOpCode.Bge_s:
                case ILOpCode.Bgt_s:
                case ILOpCode.Ble_s:
                case ILOpCode.Blt_s:
                case ILOpCode.Bne_un_s:
                case ILOpCode.Bge_un_s:
                case ILOpCode.Bgt_un_s:
                case ILOpCode.Ble_un_s:
                case ILOpCode.Blt_un_s:
                    return 2;
                case ILOpCode.Br:
                    return 0;
                case ILOpCode.Brfalse:
                case ILOpCode.Brtrue:
                    return 1;
                case ILOpCode.Beq:
                case ILOpCode.Bge:
                case ILOpCode.Bgt:
                case ILOpCode.Ble:
                case ILOpCode.Blt:
                case ILOpCode.Bne_un:
                case ILOpCode.Bge_un:
                case ILOpCode.Bgt_un:
                case ILOpCode.Ble_un:
                case ILOpCode.Blt_un:
                    return 2;
                case ILOpCode.Switch:
                case ILOpCode.Ldind_i1:
                case ILOpCode.Ldind_u1:
                case ILOpCode.Ldind_i2:
                case ILOpCode.Ldind_u2:
                case ILOpCode.Ldind_i4:
                case ILOpCode.Ldind_u4:
                case ILOpCode.Ldind_i8:
                case ILOpCode.Ldind_i:
                case ILOpCode.Ldind_r4:
                case ILOpCode.Ldind_r8:
                case ILOpCode.Ldind_ref:
                    return 1;
                case ILOpCode.Stind_ref:
                case ILOpCode.Stind_i1:
                case ILOpCode.Stind_i2:
                case ILOpCode.Stind_i4:
                case ILOpCode.Stind_i8:
                case ILOpCode.Stind_r4:
                case ILOpCode.Stind_r8:
                case ILOpCode.Add:
                case ILOpCode.Sub:
                case ILOpCode.Mul:
                case ILOpCode.Div:
                case ILOpCode.Div_un:
                case ILOpCode.Rem:
                case ILOpCode.Rem_un:
                case ILOpCode.And:
                case ILOpCode.Or:
                case ILOpCode.Xor:
                case ILOpCode.Shl:
                case ILOpCode.Shr:
                case ILOpCode.Shr_un:
                    return 2;
                case ILOpCode.Neg:
                case ILOpCode.Not:
                case ILOpCode.Conv_i1:
                case ILOpCode.Conv_i2:
                case ILOpCode.Conv_i4:
                case ILOpCode.Conv_i8:
                case ILOpCode.Conv_r4:
                case ILOpCode.Conv_r8:
                case ILOpCode.Conv_u4:
                case ILOpCode.Conv_u8:
                    return 1;
                case ILOpCode.Callvirt:
                    return -1; // Variable
                case ILOpCode.Cpobj:
                    return 2;
                case ILOpCode.Ldobj:
                    return 1;
                case ILOpCode.Ldstr:
                    return 0;
                case ILOpCode.Newobj:
                    return -1; // Variable
                case ILOpCode.Castclass:
                case ILOpCode.Isinst:
                case ILOpCode.Conv_r_un:
                case ILOpCode.Unbox:
                case ILOpCode.Throw:
                case ILOpCode.Ldfld:
                case ILOpCode.Ldflda:
                    return 1;
                case ILOpCode.Stfld:
                    return 2;
                case ILOpCode.Ldsfld:
                case ILOpCode.Ldsflda:
                    return 0;
                case ILOpCode.Stsfld:
                    return 1;
                case ILOpCode.Stobj:
                    return 2;
                case ILOpCode.Conv_ovf_i1_un:
                case ILOpCode.Conv_ovf_i2_un:
                case ILOpCode.Conv_ovf_i4_un:
                case ILOpCode.Conv_ovf_i8_un:
                case ILOpCode.Conv_ovf_u1_un:
                case ILOpCode.Conv_ovf_u2_un:
                case ILOpCode.Conv_ovf_u4_un:
                case ILOpCode.Conv_ovf_u8_un:
                case ILOpCode.Conv_ovf_i_un:
                case ILOpCode.Conv_ovf_u_un:
                case ILOpCode.Box:
                case ILOpCode.Newarr:
                case ILOpCode.Ldlen:
                    return 1;
                case ILOpCode.Ldelema:
                case ILOpCode.Ldelem_i1:
                case ILOpCode.Ldelem_u1:
                case ILOpCode.Ldelem_i2:
                case ILOpCode.Ldelem_u2:
                case ILOpCode.Ldelem_i4:
                case ILOpCode.Ldelem_u4:
                case ILOpCode.Ldelem_i8:
                case ILOpCode.Ldelem_i:
                case ILOpCode.Ldelem_r4:
                case ILOpCode.Ldelem_r8:
                case ILOpCode.Ldelem_ref:
                    return 2;
                case ILOpCode.Stelem_i:
                case ILOpCode.Stelem_i1:
                case ILOpCode.Stelem_i2:
                case ILOpCode.Stelem_i4:
                case ILOpCode.Stelem_i8:
                case ILOpCode.Stelem_r4:
                case ILOpCode.Stelem_r8:
                case ILOpCode.Stelem_ref:
                    return 3;
                case ILOpCode.Ldelem:
                    return 2;
                case ILOpCode.Stelem:
                    return 3;
                case ILOpCode.Unbox_any:
                case ILOpCode.Conv_ovf_i1:
                case ILOpCode.Conv_ovf_u1:
                case ILOpCode.Conv_ovf_i2:
                case ILOpCode.Conv_ovf_u2:
                case ILOpCode.Conv_ovf_i4:
                case ILOpCode.Conv_ovf_u4:
                case ILOpCode.Conv_ovf_i8:
                case ILOpCode.Conv_ovf_u8:
                case ILOpCode.Refanyval:
                case ILOpCode.Ckfinite:
                case ILOpCode.Mkrefany:
                    return 1;
                case ILOpCode.Ldtoken:
                    return 0;
                case ILOpCode.Conv_u2:
                case ILOpCode.Conv_u1:
                case ILOpCode.Conv_i:
                case ILOpCode.Conv_ovf_i:
                case ILOpCode.Conv_ovf_u:
                    return 1;
                case ILOpCode.Add_ovf:
                case ILOpCode.Add_ovf_un:
                case ILOpCode.Mul_ovf:
                case ILOpCode.Mul_ovf_un:
                case ILOpCode.Sub_ovf:
                case ILOpCode.Sub_ovf_un:
                    return 2;
                case ILOpCode.Endfinally:
                case ILOpCode.Leave:
                case ILOpCode.Leave_s:
                    return 0;
                case ILOpCode.Stind_i:
                    return 2;
                case ILOpCode.Conv_u:
                    return 1;
                case ILOpCode.Arglist:
                    return 0;
                case ILOpCode.Ceq:
                case ILOpCode.Cgt:
                case ILOpCode.Cgt_un:
                case ILOpCode.Clt:
                case ILOpCode.Clt_un:
                    return 2;
                case ILOpCode.Ldftn:
                    return 0;
                case ILOpCode.Ldvirtftn:
                    return 1;
                case ILOpCode.Ldarg:
                case ILOpCode.Ldarga:
                    return 0;
                case ILOpCode.Starg:
                    return 1;
                case ILOpCode.Ldloc:
                case ILOpCode.Ldloca:
                    return 0;
                case ILOpCode.Stloc:
                case ILOpCode.Localloc:
                case ILOpCode.Endfilter:
                    return 1;
                case ILOpCode.Unaligned:
                case ILOpCode.Volatile:
                case ILOpCode.Tail:
                    return 0;
                case ILOpCode.Initobj:
                    return 1;
                case ILOpCode.Constrained:
                    return 0;
                case ILOpCode.Cpblk:
                case ILOpCode.Initblk:
                    return 3;
                case ILOpCode.Rethrow:
                case ILOpCode.Sizeof:
                    return 0;
                case ILOpCode.Refanytype:
                    return 1;
                case ILOpCode.Readonly:
                    return 0;
            }

            throw ExceptionUtilities.UnexpectedValue(opcode);
        }

        public static int StackPushCount(this ILOpCode opcode)
        {
            switch (opcode)
            {
                case ILOpCode.Nop:
                case ILOpCode.Break:
                    return 0;
                case ILOpCode.Ldarg_0:
                case ILOpCode.Ldarg_1:
                case ILOpCode.Ldarg_2:
                case ILOpCode.Ldarg_3:
                case ILOpCode.Ldloc_0:
                case ILOpCode.Ldloc_1:
                case ILOpCode.Ldloc_2:
                case ILOpCode.Ldloc_3:
                    return 1;
                case ILOpCode.Stloc_0:
                case ILOpCode.Stloc_1:
                case ILOpCode.Stloc_2:
                case ILOpCode.Stloc_3:
                    return 0;
                case ILOpCode.Ldarg_s:
                case ILOpCode.Ldarga_s:
                    return 1;
                case ILOpCode.Starg_s:
                    return 0;
                case ILOpCode.Ldloc_s:
                case ILOpCode.Ldloca_s:
                    return 1;
                case ILOpCode.Stloc_s:
                    return 0;
                case ILOpCode.Ldnull:
                case ILOpCode.Ldc_i4_m1:
                case ILOpCode.Ldc_i4_0:
                case ILOpCode.Ldc_i4_1:
                case ILOpCode.Ldc_i4_2:
                case ILOpCode.Ldc_i4_3:
                case ILOpCode.Ldc_i4_4:
                case ILOpCode.Ldc_i4_5:
                case ILOpCode.Ldc_i4_6:
                case ILOpCode.Ldc_i4_7:
                case ILOpCode.Ldc_i4_8:
                case ILOpCode.Ldc_i4_s:
                case ILOpCode.Ldc_i4:
                case ILOpCode.Ldc_i8:
                case ILOpCode.Ldc_r4:
                case ILOpCode.Ldc_r8:
                    return 1;
                case ILOpCode.Dup:
                    return 2;
                case ILOpCode.Pop:
                case ILOpCode.Jmp:
                    return 0;
                case ILOpCode.Call:
                case ILOpCode.Calli:
                    return -1; // Variable
                case ILOpCode.Ret:
                case ILOpCode.Br_s:
                case ILOpCode.Brfalse_s:
                case ILOpCode.Brtrue_s:
                case ILOpCode.Beq_s:
                case ILOpCode.Bge_s:
                case ILOpCode.Bgt_s:
                case ILOpCode.Ble_s:
                case ILOpCode.Blt_s:
                case ILOpCode.Bne_un_s:
                case ILOpCode.Bge_un_s:
                case ILOpCode.Bgt_un_s:
                case ILOpCode.Ble_un_s:
                case ILOpCode.Blt_un_s:
                case ILOpCode.Br:
                case ILOpCode.Brfalse:
                case ILOpCode.Brtrue:
                case ILOpCode.Beq:
                case ILOpCode.Bge:
                case ILOpCode.Bgt:
                case ILOpCode.Ble:
                case ILOpCode.Blt:
                case ILOpCode.Bne_un:
                case ILOpCode.Bge_un:
                case ILOpCode.Bgt_un:
                case ILOpCode.Ble_un:
                case ILOpCode.Blt_un:
                case ILOpCode.Switch:
                    return 0;
                case ILOpCode.Ldind_i1:
                case ILOpCode.Ldind_u1:
                case ILOpCode.Ldind_i2:
                case ILOpCode.Ldind_u2:
                case ILOpCode.Ldind_i4:
                case ILOpCode.Ldind_u4:
                case ILOpCode.Ldind_i8:
                case ILOpCode.Ldind_i:
                case ILOpCode.Ldind_r4:
                case ILOpCode.Ldind_r8:
                case ILOpCode.Ldind_ref:
                    return 1;
                case ILOpCode.Stind_ref:
                case ILOpCode.Stind_i1:
                case ILOpCode.Stind_i2:
                case ILOpCode.Stind_i4:
                case ILOpCode.Stind_i8:
                case ILOpCode.Stind_r4:
                case ILOpCode.Stind_r8:
                    return 0;
                case ILOpCode.Add:
                case ILOpCode.Sub:
                case ILOpCode.Mul:
                case ILOpCode.Div:
                case ILOpCode.Div_un:
                case ILOpCode.Rem:
                case ILOpCode.Rem_un:
                case ILOpCode.And:
                case ILOpCode.Or:
                case ILOpCode.Xor:
                case ILOpCode.Shl:
                case ILOpCode.Shr:
                case ILOpCode.Shr_un:
                case ILOpCode.Neg:
                case ILOpCode.Not:
                case ILOpCode.Conv_i1:
                case ILOpCode.Conv_i2:
                case ILOpCode.Conv_i4:
                case ILOpCode.Conv_i8:
                case ILOpCode.Conv_r4:
                case ILOpCode.Conv_r8:
                case ILOpCode.Conv_u4:
                case ILOpCode.Conv_u8:
                    return 1;
                case ILOpCode.Callvirt:
                    return -1; // Variable
                case ILOpCode.Cpobj:
                    return 0;
                case ILOpCode.Ldobj:
                case ILOpCode.Ldstr:
                case ILOpCode.Newobj:
                case ILOpCode.Castclass:
                case ILOpCode.Isinst:
                case ILOpCode.Conv_r_un:
                case ILOpCode.Unbox:
                    return 1;
                case ILOpCode.Throw:
                    return 0;
                case ILOpCode.Ldfld:
                case ILOpCode.Ldflda:
                    return 1;
                case ILOpCode.Stfld:
                    return 0;
                case ILOpCode.Ldsfld:
                case ILOpCode.Ldsflda:
                    return 1;
                case ILOpCode.Stsfld:
                case ILOpCode.Stobj:
                    return 0;
                case ILOpCode.Conv_ovf_i1_un:
                case ILOpCode.Conv_ovf_i2_un:
                case ILOpCode.Conv_ovf_i4_un:
                case ILOpCode.Conv_ovf_i8_un:
                case ILOpCode.Conv_ovf_u1_un:
                case ILOpCode.Conv_ovf_u2_un:
                case ILOpCode.Conv_ovf_u4_un:
                case ILOpCode.Conv_ovf_u8_un:
                case ILOpCode.Conv_ovf_i_un:
                case ILOpCode.Conv_ovf_u_un:
                case ILOpCode.Box:
                case ILOpCode.Newarr:
                case ILOpCode.Ldlen:
                case ILOpCode.Ldelema:
                case ILOpCode.Ldelem_i1:
                case ILOpCode.Ldelem_u1:
                case ILOpCode.Ldelem_i2:
                case ILOpCode.Ldelem_u2:
                case ILOpCode.Ldelem_i4:
                case ILOpCode.Ldelem_u4:
                case ILOpCode.Ldelem_i8:
                case ILOpCode.Ldelem_i:
                case ILOpCode.Ldelem_r4:
                case ILOpCode.Ldelem_r8:
                case ILOpCode.Ldelem_ref:
                    return 1;
                case ILOpCode.Stelem_i:
                case ILOpCode.Stelem_i1:
                case ILOpCode.Stelem_i2:
                case ILOpCode.Stelem_i4:
                case ILOpCode.Stelem_i8:
                case ILOpCode.Stelem_r4:
                case ILOpCode.Stelem_r8:
                case ILOpCode.Stelem_ref:
                    return 0;
                case ILOpCode.Ldelem:
                    return 1;
                case ILOpCode.Stelem:
                    return 0;
                case ILOpCode.Unbox_any:
                case ILOpCode.Conv_ovf_i1:
                case ILOpCode.Conv_ovf_u1:
                case ILOpCode.Conv_ovf_i2:
                case ILOpCode.Conv_ovf_u2:
                case ILOpCode.Conv_ovf_i4:
                case ILOpCode.Conv_ovf_u4:
                case ILOpCode.Conv_ovf_i8:
                case ILOpCode.Conv_ovf_u8:
                case ILOpCode.Refanyval:
                case ILOpCode.Ckfinite:
                case ILOpCode.Mkrefany:
                case ILOpCode.Ldtoken:
                case ILOpCode.Conv_u2:
                case ILOpCode.Conv_u1:
                case ILOpCode.Conv_i:
                case ILOpCode.Conv_ovf_i:
                case ILOpCode.Conv_ovf_u:
                case ILOpCode.Add_ovf:
                case ILOpCode.Add_ovf_un:
                case ILOpCode.Mul_ovf:
                case ILOpCode.Mul_ovf_un:
                case ILOpCode.Sub_ovf:
                case ILOpCode.Sub_ovf_un:
                    return 1;
                case ILOpCode.Endfinally:
                case ILOpCode.Leave:
                case ILOpCode.Leave_s:
                case ILOpCode.Stind_i:
                    return 0;
                case ILOpCode.Conv_u:
                case ILOpCode.Arglist:
                case ILOpCode.Ceq:
                case ILOpCode.Cgt:
                case ILOpCode.Cgt_un:
                case ILOpCode.Clt:
                case ILOpCode.Clt_un:
                case ILOpCode.Ldftn:
                case ILOpCode.Ldvirtftn:
                case ILOpCode.Ldarg:
                case ILOpCode.Ldarga:
                    return 1;
                case ILOpCode.Starg:
                    return 0;
                case ILOpCode.Ldloc:
                case ILOpCode.Ldloca:
                    return 1;
                case ILOpCode.Stloc:
                    return 0;
                case ILOpCode.Localloc:
                    return 1;
                case ILOpCode.Endfilter:
                case ILOpCode.Unaligned:
                case ILOpCode.Volatile:
                case ILOpCode.Tail:
                case ILOpCode.Initobj:
                case ILOpCode.Constrained:
                case ILOpCode.Cpblk:
                case ILOpCode.Initblk:
                case ILOpCode.Rethrow:
                    return 0;
                case ILOpCode.Sizeof:
                case ILOpCode.Refanytype:
                    return 1;
                case ILOpCode.Readonly:
                    return 0;
            }

            throw ExceptionUtilities.UnexpectedValue(opcode);
        }
    }
}
