iced/Iced/Intel/InstructionInfoFactory.cs

1974 lines
89 KiB
C#

/*
Copyright (C) 2018-2019 de4dot@gmail.com
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#if !NO_INSTR_INFO
using System;
using System.Diagnostics;
using System.Runtime.CompilerServices;
using Iced.Intel.InstructionInfoInternal;
namespace Iced.Intel {
/// <summary>
/// Instruction info options
/// </summary>
[Flags]
public enum InstructionInfoOptions : uint {
/// <summary>
/// No option is enabled
/// </summary>
None = 0,
/// <summary>
/// Don't include memory usage, eg. <see cref="InstructionInfo.GetUsedMemory"/> will return an empty iterator. All
/// registers that are used by memory operands are still returned by <see cref="InstructionInfo.GetUsedRegisters"/>.
/// </summary>
NoMemoryUsage = 0x00000001,
/// <summary>
/// Don't include register usage, eg. <see cref="InstructionInfo.GetUsedRegisters"/> will return an empty iterator
/// </summary>
NoRegisterUsage = 0x00000002,
}
/// <summary>
/// Creates <see cref="InstructionInfo"/>s but minimizes allocations
/// </summary>
public sealed class InstructionInfoFactory {
const int defaultRegisterArrayCount = 2;
const int defaultMemoryArrayCount = 1;
SimpleList<UsedRegister> usedRegisters;
SimpleList<UsedMemory> usedMemoryLocations;
[Flags]
enum Flags : uint {
None = 0,
NoMemoryUsage = 0x00000001,
NoRegisterUsage = 0x00000002,
Is64Bit = 0x00000004,
ZeroExtVecRegs = 0x00000008,
}
/// <summary>
/// Constructor
/// </summary>
public InstructionInfoFactory() {
usedRegisters = new SimpleList<UsedRegister>(new UsedRegister[10]);
usedMemoryLocations = new SimpleList<UsedMemory>(new UsedMemory[8]);
}
/// <summary>
/// Creates an <see cref="InstructionInfo"/>. The return value is only valid until this instance creates a new <see cref="InstructionInfo"/> value.
/// </summary>
/// <param name="instruction">Instruction</param>
/// <returns></returns>
public InstructionInfo GetInfo(in Instruction instruction) =>
Create(instruction, ref usedRegisters, ref usedMemoryLocations, InstructionInfoOptions.None);
/// <summary>
/// Creates an <see cref="InstructionInfo"/>. The return value is only valid until this instance creates a new <see cref="InstructionInfo"/> value.
/// </summary>
/// <param name="instruction">Instruction</param>
/// <param name="options">Options</param>
/// <returns></returns>
public InstructionInfo GetInfo(in Instruction instruction, InstructionInfoOptions options) =>
Create(instruction, ref usedRegisters, ref usedMemoryLocations, options);
internal static unsafe InstructionInfo Create(in Instruction instruction, ref SimpleList<UsedRegister> usedRegisters, ref SimpleList<UsedMemory> usedMemoryLocations, InstructionInfoOptions options) {
usedRegisters.ValidLength = 0;
usedMemoryLocations.ValidLength = 0;
var data = InfoHandlers.Data;
var index = (uint)instruction.Code << 1;
var flags1 = data[(int)index];
var flags2 = data[(int)index + 1];
if ((flags2 & (uint)InfoFlags2.AVX2_Check) != 0 && instruction.Op1Kind == OpKind.Register) {
flags2 = (flags2 & ~((uint)InfoFlags2.CpuidFeatureMask << (int)InfoFlags2.CpuidFeatureShift)) |
((uint)CpuidFeatureInternal.AVX2 << (int)InfoFlags2.CpuidFeatureShift);
}
var codeSize = instruction.CodeSize;
Debug.Assert((uint)InstructionInfoOptions.NoMemoryUsage == (uint)Flags.NoMemoryUsage);
Debug.Assert((uint)InstructionInfoOptions.NoRegisterUsage == (uint)Flags.NoRegisterUsage);
var flags = (Flags)options & (Flags.NoMemoryUsage | Flags.NoRegisterUsage);
if (codeSize == CodeSize.Code64 || codeSize == CodeSize.Unknown)
flags |= Flags.Is64Bit;
if ((flags2 & ((uint)InfoFlags2.EncodingMask << (int)InfoFlags2.EncodingShift)) != ((uint)EncodingKind.Legacy << (int)InfoFlags2.EncodingShift))
flags |= Flags.ZeroExtVecRegs;
OpAccess op0Access;
switch ((OpInfo0)(flags2 & (uint)InfoFlags2.OpInfo0Mask)) {
default:
case OpInfo0.None:
op0Access = OpAccess.None;
break;
case OpInfo0.Read:
op0Access = OpAccess.Read;
break;
case OpInfo0.Write:
if (instruction.HasOpMask && instruction.MergingMasking)
op0Access = OpAccess.ReadWrite;
else
op0Access = OpAccess.Write;
break;
case OpInfo0.WriteForce:
op0Access = OpAccess.Write;
break;
case OpInfo0.CondWrite:
op0Access = OpAccess.CondWrite;
break;
case OpInfo0.CondWrite32_ReadWrite64:
if ((flags & Flags.Is64Bit) != 0)
op0Access = OpAccess.ReadWrite;
else
op0Access = OpAccess.CondWrite;
break;
case OpInfo0.ReadWrite:
op0Access = OpAccess.ReadWrite;
break;
case OpInfo0.ReadCondWrite:
op0Access = OpAccess.ReadCondWrite;
break;
case OpInfo0.NoMemAccess:
op0Access = OpAccess.NoMemAccess;
break;
case OpInfo0.WriteMem_ReadWriteReg:
if (instruction.Internal_Op0IsNotReg_or_Op0IsNotReg)
op0Access = OpAccess.Write;
else
op0Access = OpAccess.ReadWrite;
break;
}
Debug.Assert(instruction.OpCount <= DecoderConstants.MaxOpCount);
var accesses = stackalloc OpAccess[DecoderConstants.MaxOpCount];
accesses[0] = op0Access;
var op1info = (OpInfo1)((flags2 >> (int)InfoFlags2.OpInfo1Shift) & (uint)InfoFlags2.OpInfo1Mask);
accesses[1] = InfoHandlers.Op1Accesses[(int)op1info];
accesses[2] = InfoHandlers.Op2Accesses[(int)((flags2 >> (int)InfoFlags2.OpInfo2Shift) & (uint)InfoFlags2.OpInfo2Mask)];
if ((flags2 & (((uint)InfoFlags2.OpInfo3Mask) << (int)InfoFlags2.OpInfo3Shift)) != 0)
accesses[3] = OpAccess.Read;
if ((flags2 & (((uint)InfoFlags2.OpInfo4Mask) << (int)InfoFlags2.OpInfo4Shift)) != 0)
accesses[4] = OpAccess.Read;
Debug.Assert(DecoderConstants.MaxOpCount == 5);
int opCount = instruction.OpCount;
for (int i = 0; i < opCount; i++) {
var access = accesses[i];
if (access == OpAccess.None)
continue;
switch (instruction.GetOpKind(i)) {
case OpKind.Register:
if (access == OpAccess.NoMemAccess) {
access = OpAccess.Read;
accesses[i] = OpAccess.Read;
}
if ((flags & Flags.NoRegisterUsage) == 0) {
if (i == 1 && op1info == OpInfo1.ReadP3) {
var reg = instruction.Op1Register;
Debug.Assert(Register.XMM0 <= reg && reg <= InstructionInfoConstants.VMM_last);
reg = InstructionInfoConstants.VMM_first + ((reg - InstructionInfoConstants.VMM_first) & ~3);
for (int j = 0; j < 4; j++)
AddRegister(flags, ref usedRegisters, reg + j, access);
}
else
AddRegister(flags, ref usedRegisters, instruction.GetOpRegister(i), access);
}
break;
case OpKind.Memory64:
if ((flags & Flags.NoMemoryUsage) == 0)
AddMemory(ref usedMemoryLocations, instruction.MemorySegment, Register.None, Register.None, 1, instruction.MemoryAddress64, instruction.MemorySize, access);
if ((flags & Flags.NoRegisterUsage) == 0)
AddMemorySegmentRegister(flags, ref usedRegisters, instruction.MemorySegment, OpAccess.Read);
break;
case OpKind.Memory:
Debug.Assert((uint)InfoFlags1.NoSegmentRead == (1U << 31));
Debug.Assert(Register.None == 0);
var segReg = (Register)((uint)instruction.MemorySegment & ~(uint)((int)flags1 >> 31));
var baseReg = instruction.MemoryBase;
if (baseReg == Register.RIP) {
if ((flags & Flags.NoMemoryUsage) == 0)
AddMemory(ref usedMemoryLocations, segReg, Register.None, Register.None, 1, instruction.NextIP + (ulong)(int)instruction.MemoryDisplacement, instruction.MemorySize, access);
if ((flags & Flags.NoRegisterUsage) == 0 && segReg != Register.None)
AddMemorySegmentRegister(flags, ref usedRegisters, segReg, OpAccess.Read);
}
else if (baseReg == Register.EIP) {
if ((flags & Flags.NoMemoryUsage) == 0)
AddMemory(ref usedMemoryLocations, segReg, Register.None, Register.None, 1, instruction.NextIP32 + instruction.MemoryDisplacement, instruction.MemorySize, access);
if ((flags & Flags.NoRegisterUsage) == 0 && segReg != Register.None)
AddMemorySegmentRegister(flags, ref usedRegisters, segReg, OpAccess.Read);
}
else {
ulong displ;
var indexReg = instruction.MemoryIndex;
if (InstructionUtils.GetAddressSizeInBytes(baseReg, indexReg, instruction.MemoryDisplSize, codeSize) == 8)
displ = (ulong)(int)instruction.MemoryDisplacement;
else
displ = instruction.MemoryDisplacement;
if ((flags & Flags.NoMemoryUsage) == 0)
AddMemory(ref usedMemoryLocations, segReg, baseReg, indexReg, instruction.MemoryIndexScale, displ, instruction.MemorySize, access);
if ((flags & Flags.NoRegisterUsage) == 0) {
if (segReg != Register.None)
AddMemorySegmentRegister(flags, ref usedRegisters, segReg, OpAccess.Read);
if (baseReg != Register.None)
AddRegister(flags, ref usedRegisters, baseReg, OpAccess.Read);
if (indexReg != Register.None)
AddRegister(flags, ref usedRegisters, indexReg, OpAccess.Read);
}
}
break;
}
}
var rflagsInfo = (RflagsInfo)((flags1 >> (int)InfoFlags1.RflagsInfoShift) & (uint)InfoFlags1.RflagsInfoMask);
var codeInfo = (CodeInfo)((flags1 >> (int)InfoFlags1.CodeInfoShift) & (uint)InfoFlags1.CodeInfoMask);
if (codeInfo != CodeInfo.None)
CodeInfoHandler(codeInfo, instruction, ref usedRegisters, ref usedMemoryLocations, ref rflagsInfo, flags, accesses);
if (instruction.HasOpMask && (flags & Flags.NoRegisterUsage) == 0)
AddRegister(flags, ref usedRegisters, instruction.OpMask, (flags2 & (uint)InfoFlags2.OpMaskRegReadWrite) != 0 ? OpAccess.ReadWrite : OpAccess.Read);
// Inlined ctor
InstructionInfo result;
Debug.Assert(DecoderConstants.MaxOpCount == 5);
Debug2.Assert(!(usedRegisters.Array is null));
result.usedRegisters = usedRegisters.Array;
Debug2.Assert(!(usedMemoryLocations.Array is null));
result.usedMemoryLocations = usedMemoryLocations.Array;
Debug.Assert((uint)usedRegisters.ValidLength <= ushort.MaxValue);
result.usedRegistersLength = (ushort)usedRegisters.ValidLength;
Debug.Assert((uint)usedMemoryLocations.ValidLength <= ushort.MaxValue);
result.usedMemoryLocationsLength = (ushort)usedMemoryLocations.ValidLength;
result.opMaskFlags = (ushort)((uint)accesses[0] |
((uint)accesses[1] << (int)InstructionInfo.OpMaskFlags.Op1AccessShift) |
((uint)accesses[2] << (int)InstructionInfo.OpMaskFlags.Op2AccessShift) |
((uint)accesses[3] << (int)InstructionInfo.OpMaskFlags.Op3AccessShift) |
((uint)accesses[4] << (int)InstructionInfo.OpMaskFlags.Op4AccessShift));
Debug.Assert(((flags2 >> (int)InfoFlags2.CpuidFeatureShift) & (uint)InfoFlags2.CpuidFeatureMask) <= byte.MaxValue);
result.cpuidFeature = (byte)((flags2 >> (int)InfoFlags2.CpuidFeatureShift) & (uint)InfoFlags2.CpuidFeatureMask);
Debug.Assert(((flags2 >> (int)InfoFlags2.FlowControlShift) & (uint)InfoFlags2.FlowControlMask) <= byte.MaxValue);
result.flowControl = (byte)((flags2 >> (int)InfoFlags2.FlowControlShift) & (uint)InfoFlags2.FlowControlMask);
Debug.Assert(((flags2 >> (int)InfoFlags2.EncodingShift) & (uint)InfoFlags2.EncodingMask) <= byte.MaxValue);
result.encoding = (byte)((flags2 >> (int)InfoFlags2.EncodingShift) & (uint)InfoFlags2.EncodingMask);
Debug.Assert((uint)rflagsInfo <= byte.MaxValue);
Debug.Assert((uint)rflagsInfo < (uint)RflagsInfo.Last);
result.rflagsInfo = (byte)rflagsInfo;
Debug.Assert((uint)InfoFlags1.SaveRestore == 0x08000000);
Debug.Assert((uint)InfoFlags1.StackInstruction == 0x10000000);
Debug.Assert((uint)InfoFlags1.ProtectedMode == 0x20000000);
Debug.Assert((uint)InfoFlags1.Privileged == 0x40000000);
Debug.Assert((uint)InstructionInfo.Flags.SaveRestore == 0x01);
Debug.Assert((uint)InstructionInfo.Flags.StackInstruction == 0x02);
Debug.Assert((uint)InstructionInfo.Flags.ProtectedMode == 0x04);
Debug.Assert((uint)InstructionInfo.Flags.Privileged == 0x08);
// Bit 4 could be set but we don't use it so we don't need to mask it out
result.flags = (byte)(flags1 >> 27);
return result;
}
static Register GetXSP(CodeSize codeSize, out ulong xspMask) {
if (codeSize == CodeSize.Code64 || codeSize == CodeSize.Unknown) {
xspMask = ulong.MaxValue;
return Register.RSP;
}
if (codeSize == CodeSize.Code32) {
xspMask = uint.MaxValue;
return Register.ESP;
}
Debug.Assert(codeSize == CodeSize.Code16);
xspMask = ushort.MaxValue;
return Register.SP;
}
static unsafe void CodeInfoHandler(CodeInfo codeInfo, in Instruction instruction, ref SimpleList<UsedRegister> usedRegisters, ref SimpleList<UsedMemory> usedMemoryLocations, ref RflagsInfo rflagsInfo, Flags flags, OpAccess* accesses) {
Debug.Assert(codeInfo != CodeInfo.None);
ulong xspMask;
ulong displ;
Register xsp;
Register baseReg;
MemorySize memSize;
Code code;
switch (codeInfo) {
case CodeInfo.RW_AX:
if ((flags & Flags.NoRegisterUsage) == 0)
AddRegister(flags, ref usedRegisters, Register.AX, OpAccess.ReadWrite);
break;
case CodeInfo.RW_AL:
if ((flags & Flags.NoRegisterUsage) == 0)
AddRegister(flags, ref usedRegisters, Register.AL, OpAccess.ReadWrite);
break;
case CodeInfo.Salc:
if ((flags & Flags.NoRegisterUsage) == 0)
AddRegister(flags, ref usedRegisters, Register.AL, OpAccess.Write);
break;
case CodeInfo.R_AL_W_AH:
if ((flags & Flags.NoRegisterUsage) == 0) {
AddRegister(flags, ref usedRegisters, Register.AL, OpAccess.Read);
AddRegister(flags, ref usedRegisters, Register.AH, OpAccess.Write);
}
break;
case CodeInfo.R_AL_W_AX:
if ((flags & Flags.NoRegisterUsage) == 0) {
AddRegister(flags, ref usedRegisters, Register.AL, OpAccess.Read);
AddRegister(flags, ref usedRegisters, Register.AX, OpAccess.Write);
}
break;
case CodeInfo.Cwde:
if ((flags & Flags.NoRegisterUsage) == 0) {
AddRegister(flags, ref usedRegisters, Register.AX, OpAccess.Read);
AddRegister(flags, ref usedRegisters, Register.EAX, OpAccess.Write);
}
break;
case CodeInfo.Cdqe:
if ((flags & Flags.NoRegisterUsage) == 0) {
AddRegister(flags, ref usedRegisters, Register.EAX, OpAccess.Read);
AddRegister(flags, ref usedRegisters, Register.RAX, OpAccess.Write);
}
break;
case CodeInfo.Cwd:
if ((flags & Flags.NoRegisterUsage) == 0) {
AddRegister(flags, ref usedRegisters, Register.AX, OpAccess.Read);
AddRegister(flags, ref usedRegisters, Register.DX, OpAccess.Write);
}
break;
case CodeInfo.Cdq:
if ((flags & Flags.NoRegisterUsage) == 0) {
AddRegister(flags, ref usedRegisters, Register.EAX, OpAccess.Read);
AddRegister(flags, ref usedRegisters, Register.EDX, OpAccess.Write);
}
break;
case CodeInfo.Cqo:
if ((flags & Flags.NoRegisterUsage) == 0) {
AddRegister(flags, ref usedRegisters, Register.RAX, OpAccess.Read);
AddRegister(flags, ref usedRegisters, Register.RDX, OpAccess.Write);
}
break;
case CodeInfo.R_XMM0:
if ((flags & Flags.NoRegisterUsage) == 0)
AddRegister(flags, ref usedRegisters, Register.XMM0, OpAccess.Read);
break;
case CodeInfo.Push_2:
xsp = GetXSP(instruction.CodeSize, out xspMask);
if ((flags & Flags.NoRegisterUsage) == 0) {
if ((flags & Flags.Is64Bit) == 0)
AddRegister(flags, ref usedRegisters, Register.SS, OpAccess.Read);
AddRegister(flags, ref usedRegisters, xsp, OpAccess.ReadWrite);
}
if ((flags & Flags.NoMemoryUsage) == 0)
AddMemory(ref usedMemoryLocations, Register.SS, xsp, Register.None, 1, 0xFFFF_FFFF_FFFF_FFFE & xspMask, MemorySize.UInt16, OpAccess.Write);
break;
case CodeInfo.Push_4:
xsp = GetXSP(instruction.CodeSize, out xspMask);
if ((flags & Flags.NoRegisterUsage) == 0) {
if ((flags & Flags.Is64Bit) == 0)
AddRegister(flags, ref usedRegisters, Register.SS, OpAccess.Read);
AddRegister(flags, ref usedRegisters, xsp, OpAccess.ReadWrite);
}
if ((flags & Flags.NoMemoryUsage) == 0)
AddMemory(ref usedMemoryLocations, Register.SS, xsp, Register.None, 1, 0xFFFF_FFFF_FFFF_FFFC & xspMask, MemorySize.UInt32, OpAccess.Write);
break;
case CodeInfo.Push_8:
xsp = GetXSP(instruction.CodeSize, out xspMask);
if ((flags & Flags.NoRegisterUsage) == 0) {
if ((flags & Flags.Is64Bit) == 0)
AddRegister(flags, ref usedRegisters, Register.SS, OpAccess.Read);
AddRegister(flags, ref usedRegisters, xsp, OpAccess.ReadWrite);
}
if ((flags & Flags.NoMemoryUsage) == 0)
AddMemory(ref usedMemoryLocations, Register.SS, xsp, Register.None, 1, 0xFFFF_FFFF_FFFF_FFF8 & xspMask, MemorySize.UInt64, OpAccess.Write);
break;
case CodeInfo.Push_2_2:
xsp = GetXSP(instruction.CodeSize, out xspMask);
if ((flags & Flags.NoRegisterUsage) == 0) {
if ((flags & Flags.Is64Bit) == 0)
AddRegister(flags, ref usedRegisters, Register.SS, OpAccess.Read);
AddRegister(flags, ref usedRegisters, xsp, OpAccess.ReadWrite);
}
if ((flags & Flags.NoMemoryUsage) == 0) {
AddMemory(ref usedMemoryLocations, Register.SS, xsp, Register.None, 1, 0xFFFF_FFFF_FFFF_FFFE & xspMask, MemorySize.UInt16, OpAccess.Write);
AddMemory(ref usedMemoryLocations, Register.SS, xsp, Register.None, 1, 0xFFFF_FFFF_FFFF_FFFC & xspMask, MemorySize.UInt16, OpAccess.Write);
}
break;
case CodeInfo.Push_4_4:
xsp = GetXSP(instruction.CodeSize, out xspMask);
if ((flags & Flags.NoRegisterUsage) == 0) {
if ((flags & Flags.Is64Bit) == 0)
AddRegister(flags, ref usedRegisters, Register.SS, OpAccess.Read);
AddRegister(flags, ref usedRegisters, xsp, OpAccess.ReadWrite);
}
if ((flags & Flags.NoMemoryUsage) == 0) {
AddMemory(ref usedMemoryLocations, Register.SS, xsp, Register.None, 1, 0xFFFF_FFFF_FFFF_FFFC & xspMask, MemorySize.UInt32, OpAccess.Write);
AddMemory(ref usedMemoryLocations, Register.SS, xsp, Register.None, 1, 0xFFFF_FFFF_FFFF_FFF8 & xspMask, MemorySize.UInt32, OpAccess.Write);
}
break;
case CodeInfo.Push_8_8:
xsp = GetXSP(instruction.CodeSize, out xspMask);
if ((flags & Flags.NoRegisterUsage) == 0) {
if ((flags & Flags.Is64Bit) == 0)
AddRegister(flags, ref usedRegisters, Register.SS, OpAccess.Read);
AddRegister(flags, ref usedRegisters, xsp, OpAccess.ReadWrite);
}
if ((flags & Flags.NoMemoryUsage) == 0) {
AddMemory(ref usedMemoryLocations, Register.SS, xsp, Register.None, 1, 0xFFFF_FFFF_FFFF_FFF8 & xspMask, MemorySize.UInt64, OpAccess.Write);
AddMemory(ref usedMemoryLocations, Register.SS, xsp, Register.None, 1, 0xFFFF_FFFF_FFFF_FFF0 & xspMask, MemorySize.UInt64, OpAccess.Write);
}
break;
case CodeInfo.Pop_2:
xsp = GetXSP(instruction.CodeSize, out xspMask);
if ((flags & Flags.NoRegisterUsage) == 0) {
if ((flags & Flags.Is64Bit) == 0)
AddRegister(flags, ref usedRegisters, Register.SS, OpAccess.Read);
AddRegister(flags, ref usedRegisters, xsp, OpAccess.ReadWrite);
}
if ((flags & Flags.NoMemoryUsage) == 0)
AddMemory(ref usedMemoryLocations, Register.SS, xsp, Register.None, 1, 0, MemorySize.UInt16, OpAccess.Read);
break;
case CodeInfo.Pop_4:
xsp = GetXSP(instruction.CodeSize, out xspMask);
if ((flags & Flags.NoRegisterUsage) == 0) {
if ((flags & Flags.Is64Bit) == 0)
AddRegister(flags, ref usedRegisters, Register.SS, OpAccess.Read);
AddRegister(flags, ref usedRegisters, xsp, OpAccess.ReadWrite);
}
if ((flags & Flags.NoMemoryUsage) == 0)
AddMemory(ref usedMemoryLocations, Register.SS, xsp, Register.None, 1, 0, MemorySize.UInt32, OpAccess.Read);
break;
case CodeInfo.Pop_8:
xsp = GetXSP(instruction.CodeSize, out xspMask);
if ((flags & Flags.NoRegisterUsage) == 0) {
if ((flags & Flags.Is64Bit) == 0)
AddRegister(flags, ref usedRegisters, Register.SS, OpAccess.Read);
AddRegister(flags, ref usedRegisters, xsp, OpAccess.ReadWrite);
}
if ((flags & Flags.NoMemoryUsage) == 0)
AddMemory(ref usedMemoryLocations, Register.SS, xsp, Register.None, 1, 0, MemorySize.UInt64, OpAccess.Read);
break;
case CodeInfo.Pop_2_2:
xsp = GetXSP(instruction.CodeSize, out xspMask);
if ((flags & Flags.NoRegisterUsage) == 0) {
if ((flags & Flags.Is64Bit) == 0)
AddRegister(flags, ref usedRegisters, Register.SS, OpAccess.Read);
AddRegister(flags, ref usedRegisters, xsp, OpAccess.ReadWrite);
}
if ((flags & Flags.NoMemoryUsage) == 0) {
AddMemory(ref usedMemoryLocations, Register.SS, xsp, Register.None, 1, 0, MemorySize.UInt16, OpAccess.Read);
AddMemory(ref usedMemoryLocations, Register.SS, xsp, Register.None, 1, 2, MemorySize.UInt16, OpAccess.Read);
}
break;
case CodeInfo.Pop_4_4:
xsp = GetXSP(instruction.CodeSize, out xspMask);
if ((flags & Flags.NoRegisterUsage) == 0) {
if ((flags & Flags.Is64Bit) == 0)
AddRegister(flags, ref usedRegisters, Register.SS, OpAccess.Read);
AddRegister(flags, ref usedRegisters, xsp, OpAccess.ReadWrite);
}
if ((flags & Flags.NoMemoryUsage) == 0) {
AddMemory(ref usedMemoryLocations, Register.SS, xsp, Register.None, 1, 0, MemorySize.UInt32, OpAccess.Read);
AddMemory(ref usedMemoryLocations, Register.SS, xsp, Register.None, 1, 4, MemorySize.UInt32, OpAccess.Read);
}
break;
case CodeInfo.Pop_8_8:
xsp = GetXSP(instruction.CodeSize, out xspMask);
if ((flags & Flags.NoRegisterUsage) == 0) {
if ((flags & Flags.Is64Bit) == 0)
AddRegister(flags, ref usedRegisters, Register.SS, OpAccess.Read);
AddRegister(flags, ref usedRegisters, xsp, OpAccess.ReadWrite);
}
if ((flags & Flags.NoMemoryUsage) == 0) {
AddMemory(ref usedMemoryLocations, Register.SS, xsp, Register.None, 1, 0, MemorySize.UInt64, OpAccess.Read);
AddMemory(ref usedMemoryLocations, Register.SS, xsp, Register.None, 1, 8, MemorySize.UInt64, OpAccess.Read);
}
break;
case CodeInfo.Pop_Ev:
xsp = GetXSP(instruction.CodeSize, out xspMask);
if ((flags & Flags.NoRegisterUsage) == 0) {
if ((flags & Flags.Is64Bit) == 0)
AddRegister(flags, ref usedRegisters, Register.SS, OpAccess.Read);
AddRegister(flags, ref usedRegisters, xsp, OpAccess.ReadWrite);
}
if ((flags & Flags.NoMemoryUsage) == 0) {
code = instruction.Code;
uint size;
if (code == Code.Pop_rm64) {
memSize = MemorySize.UInt64;
size = 8;
}
else if (code == Code.Pop_rm32) {
memSize = MemorySize.UInt32;
size = 4;
}
else {
Debug.Assert(instruction.Code == Code.Pop_rm16);
memSize = MemorySize.UInt16;
size = 2;
}
if (instruction.Op0Kind == OpKind.Memory) {
Debug.Assert(usedMemoryLocations.ValidLength == 1);
if (instruction.MemoryBase == Register.RSP || instruction.MemoryBase == Register.ESP) {
ref var mem = ref usedMemoryLocations.Array[0];
displ = mem.Displacement + size;
if (instruction.MemoryBase == Register.ESP)
displ = (uint)displ;
usedMemoryLocations.Array[0] = new UsedMemory(mem.Segment, mem.Base, mem.Index, mem.Scale, displ, mem.MemorySize, mem.Access);
}
}
AddMemory(ref usedMemoryLocations, Register.SS, xsp, Register.None, 1, 0, memSize, OpAccess.Read);
}
break;
case CodeInfo.Pusha:
xsp = GetXSP(instruction.CodeSize, out xspMask);
if ((flags & Flags.NoRegisterUsage) == 0) {
if ((flags & Flags.Is64Bit) == 0)
AddRegister(flags, ref usedRegisters, Register.SS, OpAccess.Read);
AddRegister(flags, ref usedRegisters, xsp, OpAccess.ReadWrite);
}
if (instruction.Code == Code.Pushad) {
displ = 0xFFFF_FFFF_FFFF_FFFC;
memSize = MemorySize.UInt32;
baseReg = Register.EAX;
}
else {
Debug.Assert(instruction.Code == Code.Pushaw);
displ = 0xFFFF_FFFF_FFFF_FFFE;
memSize = MemorySize.UInt16;
baseReg = Register.AX;
}
for (int i = 0; i < 8; i++) {
if ((flags & Flags.NoRegisterUsage) == 0)
AddRegister(flags, ref usedRegisters, baseReg + i, OpAccess.Read);
if ((flags & Flags.NoMemoryUsage) == 0)
AddMemory(ref usedMemoryLocations, Register.SS, xsp, Register.None, 1, (ulong)((long)displ * (i + 1)) & xspMask, memSize, OpAccess.Write);
}
break;
case CodeInfo.Popa:
xsp = GetXSP(instruction.CodeSize, out xspMask);
if ((flags & Flags.NoRegisterUsage) == 0) {
if ((flags & Flags.Is64Bit) == 0)
AddRegister(flags, ref usedRegisters, Register.SS, OpAccess.Read);
AddRegister(flags, ref usedRegisters, xsp, OpAccess.ReadWrite);
}
if (instruction.Code == Code.Popad) {
displ = 4;
memSize = MemorySize.UInt32;
baseReg = Register.EAX;
}
else {
Debug.Assert(instruction.Code == Code.Popaw);
displ = 2;
memSize = MemorySize.UInt16;
baseReg = Register.AX;
}
for (int i = 0; i < 8; i++) {
// Ignore eSP
if (i != 3) {
if ((flags & Flags.NoRegisterUsage) == 0)
AddRegister(flags, ref usedRegisters, baseReg + 7 - i, OpAccess.Write);
if ((flags & Flags.NoMemoryUsage) == 0)
AddMemory(ref usedMemoryLocations, Register.SS, xsp, Register.None, 1, displ * (uint)i & xspMask, memSize, OpAccess.Read);
}
}
break;
case CodeInfo.Ins:
if (instruction.Internal_HasRepeOrRepnePrefix) {
accesses[0] = OpAccess.CondWrite;
accesses[1] = OpAccess.CondRead;
Debug.Assert(OpKind.MemoryESDI + 1 == OpKind.MemoryESEDI);
Debug.Assert(OpKind.MemoryESDI + 2 == OpKind.MemoryESRDI);
Debug.Assert(Register.DI + 16 == Register.EDI);
Debug.Assert(Register.DI + 32 == Register.RDI);
Debug.Assert(Register.CX + 16 == Register.ECX);
Debug.Assert(Register.CX + 32 == Register.RCX);
baseReg = ((instruction.Op0Kind - OpKind.MemoryESDI) << 4) + Register.DI;
if ((flags & Flags.NoMemoryUsage) == 0)
AddMemory(ref usedMemoryLocations, Register.ES, baseReg, Register.None, 1, 0, MemorySize.Unknown, OpAccess.CondWrite);
if ((flags & Flags.NoRegisterUsage) == 0) {
Debug.Assert(usedRegisters.ValidLength == 1);
usedRegisters.Array[0] = new UsedRegister(Register.DX, OpAccess.CondRead);
AddRegister(flags, ref usedRegisters, ((instruction.Op0Kind - OpKind.MemoryESDI) << 4) + Register.CX, OpAccess.ReadCondWrite);
if ((flags & Flags.Is64Bit) == 0)
AddRegister(flags, ref usedRegisters, Register.ES, OpAccess.CondRead);
AddRegister(flags, ref usedRegisters, baseReg, OpAccess.CondRead);
AddRegister(flags, ref usedRegisters, baseReg, OpAccess.CondWrite);
}
}
else {
Debug.Assert(OpKind.MemoryESDI + 1 == OpKind.MemoryESEDI);
Debug.Assert(OpKind.MemoryESDI + 2 == OpKind.MemoryESRDI);
Debug.Assert(Register.DI + 16 == Register.EDI);
Debug.Assert(Register.DI + 32 == Register.RDI);
baseReg = ((instruction.Op0Kind - OpKind.MemoryESDI) << 4) + Register.DI;
if ((flags & Flags.NoMemoryUsage) == 0)
AddMemory(ref usedMemoryLocations, Register.ES, baseReg, Register.None, 1, 0, instruction.MemorySize, OpAccess.Write);
if ((flags & Flags.NoRegisterUsage) == 0) {
if ((flags & Flags.Is64Bit) == 0)
AddRegister(flags, ref usedRegisters, Register.ES, OpAccess.Read);
AddRegister(flags, ref usedRegisters, baseReg, OpAccess.ReadWrite);
}
}
break;
case CodeInfo.Outs:
if (instruction.Internal_HasRepeOrRepnePrefix) {
accesses[0] = OpAccess.CondRead;
accesses[1] = OpAccess.CondRead;
Debug.Assert(OpKind.MemorySegSI + 1 == OpKind.MemorySegESI);
Debug.Assert(OpKind.MemorySegSI + 2 == OpKind.MemorySegRSI);
Debug.Assert(Register.SI + 16 == Register.ESI);
Debug.Assert(Register.SI + 32 == Register.RSI);
Debug.Assert(Register.CX + 16 == Register.ECX);
Debug.Assert(Register.CX + 32 == Register.RCX);
baseReg = ((instruction.Op1Kind - OpKind.MemorySegSI) << 4) + Register.SI;
if ((flags & Flags.NoMemoryUsage) == 0)
AddMemory(ref usedMemoryLocations, instruction.MemorySegment, baseReg, Register.None, 1, 0, MemorySize.Unknown, OpAccess.CondRead);
if ((flags & Flags.NoRegisterUsage) == 0) {
Debug.Assert(usedRegisters.ValidLength == 1);
usedRegisters.Array[0] = new UsedRegister(Register.DX, OpAccess.CondRead);
AddRegister(flags, ref usedRegisters, ((instruction.Op1Kind - OpKind.MemorySegSI) << 4) + Register.CX, OpAccess.ReadCondWrite);
AddMemorySegmentRegister(flags, ref usedRegisters, instruction.MemorySegment, OpAccess.CondRead);
AddRegister(flags, ref usedRegisters, baseReg, OpAccess.CondRead);
AddRegister(flags, ref usedRegisters, baseReg, OpAccess.CondWrite);
}
}
else {
Debug.Assert(OpKind.MemorySegSI + 1 == OpKind.MemorySegESI);
Debug.Assert(OpKind.MemorySegSI + 2 == OpKind.MemorySegRSI);
Debug.Assert(Register.SI + 16 == Register.ESI);
Debug.Assert(Register.SI + 32 == Register.RSI);
baseReg = ((instruction.Op1Kind - OpKind.MemorySegSI) << 4) + Register.SI;
if ((flags & Flags.NoMemoryUsage) == 0)
AddMemory(ref usedMemoryLocations, instruction.MemorySegment, baseReg, Register.None, 1, 0, instruction.MemorySize, OpAccess.Read);
if ((flags & Flags.NoRegisterUsage) == 0) {
AddMemorySegmentRegister(flags, ref usedRegisters, instruction.MemorySegment, OpAccess.Read);
AddRegister(flags, ref usedRegisters, baseReg, OpAccess.ReadWrite);
}
}
break;
case CodeInfo.Movs:
if (instruction.Internal_HasRepeOrRepnePrefix) {
accesses[0] = OpAccess.CondWrite;
accesses[1] = OpAccess.CondRead;
Debug.Assert(OpKind.MemoryESDI + 1 == OpKind.MemoryESEDI);
Debug.Assert(OpKind.MemoryESDI + 2 == OpKind.MemoryESRDI);
Debug.Assert(Register.DI + 16 == Register.EDI);
Debug.Assert(Register.DI + 32 == Register.RDI);
Debug.Assert(Register.CX + 16 == Register.ECX);
Debug.Assert(Register.CX + 32 == Register.RCX);
baseReg = ((instruction.Op0Kind - OpKind.MemoryESDI) << 4) + Register.DI;
if ((flags & Flags.NoMemoryUsage) == 0)
AddMemory(ref usedMemoryLocations, Register.ES, baseReg, Register.None, 1, 0, MemorySize.Unknown, OpAccess.CondWrite);
if ((flags & Flags.NoRegisterUsage) == 0) {
AddRegister(flags, ref usedRegisters, ((instruction.Op0Kind - OpKind.MemoryESDI) << 4) + Register.CX, OpAccess.ReadCondWrite);
if ((flags & Flags.Is64Bit) == 0)
AddRegister(flags, ref usedRegisters, Register.ES, OpAccess.CondRead);
AddRegister(flags, ref usedRegisters, baseReg, OpAccess.CondRead);
AddRegister(flags, ref usedRegisters, baseReg, OpAccess.CondWrite);
}
Debug.Assert(OpKind.MemorySegSI + 1 == OpKind.MemorySegESI);
Debug.Assert(OpKind.MemorySegSI + 2 == OpKind.MemorySegRSI);
Debug.Assert(Register.SI + 16 == Register.ESI);
Debug.Assert(Register.SI + 32 == Register.RSI);
baseReg = ((instruction.Op1Kind - OpKind.MemorySegSI) << 4) + Register.SI;
if ((flags & Flags.NoMemoryUsage) == 0)
AddMemory(ref usedMemoryLocations, instruction.MemorySegment, baseReg, Register.None, 1, 0, MemorySize.Unknown, OpAccess.CondRead);
if ((flags & Flags.NoRegisterUsage) == 0) {
AddMemorySegmentRegister(flags, ref usedRegisters, instruction.MemorySegment, OpAccess.CondRead);
AddRegister(flags, ref usedRegisters, baseReg, OpAccess.CondRead);
AddRegister(flags, ref usedRegisters, baseReg, OpAccess.CondWrite);
}
}
else {
Debug.Assert(OpKind.MemoryESDI + 1 == OpKind.MemoryESEDI);
Debug.Assert(OpKind.MemoryESDI + 2 == OpKind.MemoryESRDI);
Debug.Assert(Register.DI + 16 == Register.EDI);
Debug.Assert(Register.DI + 32 == Register.RDI);
baseReg = ((instruction.Op0Kind - OpKind.MemoryESDI) << 4) + Register.DI;
if ((flags & Flags.NoMemoryUsage) == 0)
AddMemory(ref usedMemoryLocations, Register.ES, baseReg, Register.None, 1, 0, instruction.MemorySize, OpAccess.Write);
if ((flags & Flags.NoRegisterUsage) == 0) {
if ((flags & Flags.Is64Bit) == 0)
AddRegister(flags, ref usedRegisters, Register.ES, OpAccess.Read);
AddRegister(flags, ref usedRegisters, baseReg, OpAccess.ReadWrite);
}
Debug.Assert(OpKind.MemorySegSI + 1 == OpKind.MemorySegESI);
Debug.Assert(OpKind.MemorySegSI + 2 == OpKind.MemorySegRSI);
Debug.Assert(Register.SI + 16 == Register.ESI);
Debug.Assert(Register.SI + 32 == Register.RSI);
baseReg = ((instruction.Op1Kind - OpKind.MemorySegSI) << 4) + Register.SI;
if ((flags & Flags.NoMemoryUsage) == 0)
AddMemory(ref usedMemoryLocations, instruction.MemorySegment, baseReg, Register.None, 1, 0, instruction.MemorySize, OpAccess.Read);
if ((flags & Flags.NoRegisterUsage) == 0) {
AddMemorySegmentRegister(flags, ref usedRegisters, instruction.MemorySegment, OpAccess.Read);
AddRegister(flags, ref usedRegisters, baseReg, OpAccess.ReadWrite);
}
}
break;
case CodeInfo.Cmps:
if (instruction.Internal_HasRepeOrRepnePrefix) {
accesses[0] = OpAccess.CondRead;
accesses[1] = OpAccess.CondRead;
Debug.Assert(OpKind.MemorySegSI + 1 == OpKind.MemorySegESI);
Debug.Assert(OpKind.MemorySegSI + 2 == OpKind.MemorySegRSI);
Debug.Assert(Register.SI + 16 == Register.ESI);
Debug.Assert(Register.SI + 32 == Register.RSI);
Debug.Assert(Register.CX + 16 == Register.ECX);
Debug.Assert(Register.CX + 32 == Register.RCX);
baseReg = ((instruction.Op0Kind - OpKind.MemorySegSI) << 4) + Register.SI;
if ((flags & Flags.NoMemoryUsage) == 0)
AddMemory(ref usedMemoryLocations, instruction.MemorySegment, baseReg, Register.None, 1, 0, MemorySize.Unknown, OpAccess.CondRead);
if ((flags & Flags.NoRegisterUsage) == 0) {
AddRegister(flags, ref usedRegisters, ((instruction.Op0Kind - OpKind.MemorySegSI) << 4) + Register.CX, OpAccess.ReadCondWrite);
AddMemorySegmentRegister(flags, ref usedRegisters, instruction.MemorySegment, OpAccess.CondRead);
AddRegister(flags, ref usedRegisters, baseReg, OpAccess.CondRead);
AddRegister(flags, ref usedRegisters, baseReg, OpAccess.CondWrite);
}
Debug.Assert(OpKind.MemoryESDI + 1 == OpKind.MemoryESEDI);
Debug.Assert(OpKind.MemoryESDI + 2 == OpKind.MemoryESRDI);
Debug.Assert(Register.DI + 16 == Register.EDI);
Debug.Assert(Register.DI + 32 == Register.RDI);
baseReg = ((instruction.Op1Kind - OpKind.MemoryESDI) << 4) + Register.DI;
if ((flags & Flags.NoMemoryUsage) == 0)
AddMemory(ref usedMemoryLocations, Register.ES, baseReg, Register.None, 1, 0, MemorySize.Unknown, OpAccess.CondRead);
if ((flags & Flags.NoRegisterUsage) == 0) {
if ((flags & Flags.Is64Bit) == 0)
AddRegister(flags, ref usedRegisters, Register.ES, OpAccess.CondRead);
AddRegister(flags, ref usedRegisters, baseReg, OpAccess.CondRead);
AddRegister(flags, ref usedRegisters, baseReg, OpAccess.CondWrite);
}
}
else {
Debug.Assert(OpKind.MemorySegSI + 1 == OpKind.MemorySegESI);
Debug.Assert(OpKind.MemorySegSI + 2 == OpKind.MemorySegRSI);
Debug.Assert(Register.SI + 16 == Register.ESI);
Debug.Assert(Register.SI + 32 == Register.RSI);
baseReg = ((instruction.Op0Kind - OpKind.MemorySegSI) << 4) + Register.SI;
if ((flags & Flags.NoMemoryUsage) == 0)
AddMemory(ref usedMemoryLocations, instruction.MemorySegment, baseReg, Register.None, 1, 0, instruction.MemorySize, OpAccess.Read);
if ((flags & Flags.NoRegisterUsage) == 0) {
AddMemorySegmentRegister(flags, ref usedRegisters, instruction.MemorySegment, OpAccess.Read);
AddRegister(flags, ref usedRegisters, baseReg, OpAccess.ReadWrite);
}
Debug.Assert(OpKind.MemoryESDI + 1 == OpKind.MemoryESEDI);
Debug.Assert(OpKind.MemoryESDI + 2 == OpKind.MemoryESRDI);
Debug.Assert(Register.DI + 16 == Register.EDI);
Debug.Assert(Register.DI + 32 == Register.RDI);
baseReg = ((instruction.Op1Kind - OpKind.MemoryESDI) << 4) + Register.DI;
if ((flags & Flags.NoMemoryUsage) == 0)
AddMemory(ref usedMemoryLocations, Register.ES, baseReg, Register.None, 1, 0, instruction.MemorySize, OpAccess.Read);
if ((flags & Flags.NoRegisterUsage) == 0) {
if ((flags & Flags.Is64Bit) == 0)
AddRegister(flags, ref usedRegisters, Register.ES, OpAccess.Read);
AddRegister(flags, ref usedRegisters, baseReg, OpAccess.ReadWrite);
}
}
break;
case CodeInfo.Stos:
if (instruction.Internal_HasRepeOrRepnePrefix) {
accesses[0] = OpAccess.CondWrite;
accesses[1] = OpAccess.CondRead;
Debug.Assert(OpKind.MemoryESDI + 1 == OpKind.MemoryESEDI);
Debug.Assert(OpKind.MemoryESDI + 2 == OpKind.MemoryESRDI);
Debug.Assert(Register.DI + 16 == Register.EDI);
Debug.Assert(Register.DI + 32 == Register.RDI);
Debug.Assert(Register.CX + 16 == Register.ECX);
Debug.Assert(Register.CX + 32 == Register.RCX);
baseReg = ((instruction.Op0Kind - OpKind.MemoryESDI) << 4) + Register.DI;
if ((flags & Flags.NoMemoryUsage) == 0)
AddMemory(ref usedMemoryLocations, Register.ES, baseReg, Register.None, 1, 0, MemorySize.Unknown, OpAccess.CondWrite);
if ((flags & Flags.NoRegisterUsage) == 0) {
Debug.Assert(usedRegisters.ValidLength == 1);
usedRegisters.Array[0] = new UsedRegister(usedRegisters.Array[0].Register, OpAccess.CondRead);
AddRegister(flags, ref usedRegisters, ((instruction.Op0Kind - OpKind.MemoryESDI) << 4) + Register.CX, OpAccess.ReadCondWrite);
if ((flags & Flags.Is64Bit) == 0)
AddRegister(flags, ref usedRegisters, Register.ES, OpAccess.CondRead);
AddRegister(flags, ref usedRegisters, baseReg, OpAccess.CondRead);
AddRegister(flags, ref usedRegisters, baseReg, OpAccess.CondWrite);
}
}
else {
Debug.Assert(OpKind.MemoryESDI + 1 == OpKind.MemoryESEDI);
Debug.Assert(OpKind.MemoryESDI + 2 == OpKind.MemoryESRDI);
Debug.Assert(Register.DI + 16 == Register.EDI);
Debug.Assert(Register.DI + 32 == Register.RDI);
baseReg = ((instruction.Op0Kind - OpKind.MemoryESDI) << 4) + Register.DI;
if ((flags & Flags.NoMemoryUsage) == 0)
AddMemory(ref usedMemoryLocations, Register.ES, baseReg, Register.None, 1, 0, instruction.MemorySize, OpAccess.Write);
if ((flags & Flags.NoRegisterUsage) == 0) {
if ((flags & Flags.Is64Bit) == 0)
AddRegister(flags, ref usedRegisters, Register.ES, OpAccess.Read);
AddRegister(flags, ref usedRegisters, baseReg, OpAccess.ReadWrite);
}
}
break;
case CodeInfo.Lods:
if (instruction.Internal_HasRepeOrRepnePrefix) {
accesses[0] = OpAccess.CondWrite;
accesses[1] = OpAccess.CondRead;
Debug.Assert(OpKind.MemorySegSI + 1 == OpKind.MemorySegESI);
Debug.Assert(OpKind.MemorySegSI + 2 == OpKind.MemorySegRSI);
Debug.Assert(Register.SI + 16 == Register.ESI);
Debug.Assert(Register.SI + 32 == Register.RSI);
Debug.Assert(Register.CX + 16 == Register.ECX);
Debug.Assert(Register.CX + 32 == Register.RCX);
baseReg = ((instruction.Op1Kind - OpKind.MemorySegSI) << 4) + Register.SI;
if ((flags & Flags.NoMemoryUsage) == 0)
AddMemory(ref usedMemoryLocations, instruction.MemorySegment, baseReg, Register.None, 1, 0, MemorySize.Unknown, OpAccess.CondRead);
if ((flags & Flags.NoRegisterUsage) == 0) {
Debug.Assert(usedRegisters.ValidLength == 1);
usedRegisters.Array[0] = new UsedRegister(usedRegisters.Array[0].Register, OpAccess.CondWrite);
AddRegister(flags, ref usedRegisters, ((instruction.Op1Kind - OpKind.MemorySegSI) << 4) + Register.CX, OpAccess.ReadCondWrite);
AddMemorySegmentRegister(flags, ref usedRegisters, instruction.MemorySegment, OpAccess.CondRead);
AddRegister(flags, ref usedRegisters, baseReg, OpAccess.CondRead);
AddRegister(flags, ref usedRegisters, baseReg, OpAccess.CondWrite);
}
}
else {
Debug.Assert(OpKind.MemorySegSI + 1 == OpKind.MemorySegESI);
Debug.Assert(OpKind.MemorySegSI + 2 == OpKind.MemorySegRSI);
Debug.Assert(Register.SI + 16 == Register.ESI);
Debug.Assert(Register.SI + 32 == Register.RSI);
baseReg = ((instruction.Op1Kind - OpKind.MemorySegSI) << 4) + Register.SI;
if ((flags & Flags.NoMemoryUsage) == 0)
AddMemory(ref usedMemoryLocations, instruction.MemorySegment, baseReg, Register.None, 1, 0, instruction.MemorySize, OpAccess.Read);
if ((flags & Flags.NoRegisterUsage) == 0) {
AddMemorySegmentRegister(flags, ref usedRegisters, instruction.MemorySegment, OpAccess.Read);
AddRegister(flags, ref usedRegisters, baseReg, OpAccess.ReadWrite);
}
}
break;
case CodeInfo.Scas:
if (instruction.Internal_HasRepeOrRepnePrefix) {
accesses[0] = OpAccess.CondRead;
accesses[1] = OpAccess.CondRead;
Debug.Assert(OpKind.MemoryESDI + 1 == OpKind.MemoryESEDI);
Debug.Assert(OpKind.MemoryESDI + 2 == OpKind.MemoryESRDI);
Debug.Assert(Register.DI + 16 == Register.EDI);
Debug.Assert(Register.DI + 32 == Register.RDI);
Debug.Assert(Register.CX + 16 == Register.ECX);
Debug.Assert(Register.CX + 32 == Register.RCX);
baseReg = ((instruction.Op1Kind - OpKind.MemoryESDI) << 4) + Register.DI;
if ((flags & Flags.NoMemoryUsage) == 0)
AddMemory(ref usedMemoryLocations, Register.ES, baseReg, Register.None, 1, 0, MemorySize.Unknown, OpAccess.CondRead);
if ((flags & Flags.NoRegisterUsage) == 0) {
Debug.Assert(usedRegisters.ValidLength == 1);
usedRegisters.Array[0] = new UsedRegister(usedRegisters.Array[0].Register, OpAccess.CondRead);
AddRegister(flags, ref usedRegisters, ((instruction.Op1Kind - OpKind.MemoryESDI) << 4) + Register.CX, OpAccess.ReadCondWrite);
if ((flags & Flags.Is64Bit) == 0)
AddRegister(flags, ref usedRegisters, Register.ES, OpAccess.CondRead);
AddRegister(flags, ref usedRegisters, baseReg, OpAccess.CondRead);
AddRegister(flags, ref usedRegisters, baseReg, OpAccess.CondWrite);
}
}
else {
Debug.Assert(OpKind.MemoryESDI + 1 == OpKind.MemoryESEDI);
Debug.Assert(OpKind.MemoryESDI + 2 == OpKind.MemoryESRDI);
Debug.Assert(Register.DI + 16 == Register.EDI);
Debug.Assert(Register.DI + 32 == Register.RDI);
baseReg = ((instruction.Op1Kind - OpKind.MemoryESDI) << 4) + Register.DI;
if ((flags & Flags.NoMemoryUsage) == 0)
AddMemory(ref usedMemoryLocations, Register.ES, baseReg, Register.None, 1, 0, instruction.MemorySize, OpAccess.Read);
if ((flags & Flags.NoRegisterUsage) == 0) {
if ((flags & Flags.Is64Bit) == 0)
AddRegister(flags, ref usedRegisters, Register.ES, OpAccess.Read);
AddRegister(flags, ref usedRegisters, baseReg, OpAccess.ReadWrite);
}
}
break;
case CodeInfo.Cmpxchg:
if ((flags & Flags.NoRegisterUsage) == 0) {
code = instruction.Code;
if (code == Code.Cmpxchg_rm64_r64)
AddRegister(flags, ref usedRegisters, Register.RAX, OpAccess.ReadCondWrite);
else if (code == Code.Cmpxchg_rm32_r32 || code == Code.Cmpxchg486_rm32_r32)
AddRegister(flags, ref usedRegisters, Register.EAX, OpAccess.ReadCondWrite);
else if (code == Code.Cmpxchg_rm16_r16 || code == Code.Cmpxchg486_rm16_r16)
AddRegister(flags, ref usedRegisters, Register.AX, OpAccess.ReadCondWrite);
else {
Debug.Assert(code == Code.Cmpxchg_rm8_r8 || code == Code.Cmpxchg486_rm8_r8);
AddRegister(flags, ref usedRegisters, Register.AL, OpAccess.ReadCondWrite);
}
}
break;
case CodeInfo.Cmpxchg8b:
if ((flags & Flags.NoRegisterUsage) == 0) {
if (instruction.Code == Code.Cmpxchg16b_m128) {
AddRegister(flags, ref usedRegisters, Register.RDX, OpAccess.ReadCondWrite);
AddRegister(flags, ref usedRegisters, Register.RAX, OpAccess.ReadCondWrite);
AddRegister(flags, ref usedRegisters, Register.RCX, OpAccess.CondRead);
AddRegister(flags, ref usedRegisters, Register.RBX, OpAccess.CondRead);
}
else {
Debug.Assert(instruction.Code == Code.Cmpxchg8b_m64);
AddRegister(flags, ref usedRegisters, Register.EDX, OpAccess.ReadCondWrite);
AddRegister(flags, ref usedRegisters, Register.EAX, OpAccess.ReadCondWrite);
AddRegister(flags, ref usedRegisters, Register.ECX, OpAccess.CondRead);
AddRegister(flags, ref usedRegisters, Register.EBX, OpAccess.CondRead);
}
}
break;
case CodeInfo.Cpuid:
if ((flags & Flags.NoRegisterUsage) == 0) {
AddRegister(flags, ref usedRegisters, Register.EAX, OpAccess.ReadWrite);
AddRegister(flags, ref usedRegisters, Register.ECX, OpAccess.CondRead);
AddRegister(flags, ref usedRegisters, Register.ECX, OpAccess.Write);
AddRegister(flags, ref usedRegisters, Register.EDX, OpAccess.Write);
AddRegister(flags, ref usedRegisters, Register.EBX, OpAccess.Write);
}
break;
case CodeInfo.Div:
if ((flags & Flags.NoRegisterUsage) == 0) {
code = instruction.Code;
if (code == Code.Idiv_rm64 || code == Code.Div_rm64) {
AddRegister(flags, ref usedRegisters, Register.RDX, OpAccess.ReadWrite);
AddRegister(flags, ref usedRegisters, Register.RAX, OpAccess.ReadWrite);
}
else if (code == Code.Idiv_rm32 || code == Code.Div_rm32) {
AddRegister(flags, ref usedRegisters, Register.EDX, OpAccess.ReadWrite);
AddRegister(flags, ref usedRegisters, Register.EAX, OpAccess.ReadWrite);
}
else if (code == Code.Idiv_rm16 || code == Code.Div_rm16) {
AddRegister(flags, ref usedRegisters, Register.DX, OpAccess.ReadWrite);
AddRegister(flags, ref usedRegisters, Register.AX, OpAccess.ReadWrite);
}
else {
Debug.Assert(code == Code.Idiv_rm8 || code == Code.Div_rm8);
AddRegister(flags, ref usedRegisters, Register.AX, OpAccess.ReadWrite);
}
}
break;
case CodeInfo.Mul:
if ((flags & Flags.NoRegisterUsage) == 0) {
code = instruction.Code;
if (code == Code.Imul_rm64 || code == Code.Mul_rm64) {
AddRegister(flags, ref usedRegisters, Register.RAX, OpAccess.ReadWrite);
AddRegister(flags, ref usedRegisters, Register.RDX, OpAccess.Write);
}
else if (code == Code.Imul_rm32 || code == Code.Mul_rm32) {
AddRegister(flags, ref usedRegisters, Register.EAX, OpAccess.ReadWrite);
AddRegister(flags, ref usedRegisters, Register.EDX, OpAccess.Write);
}
else if (code == Code.Imul_rm16 || code == Code.Mul_rm16) {
AddRegister(flags, ref usedRegisters, Register.AX, OpAccess.ReadWrite);
AddRegister(flags, ref usedRegisters, Register.DX, OpAccess.Write);
}
else {
Debug.Assert(code == Code.Imul_rm8 || code == Code.Mul_rm8);
AddRegister(flags, ref usedRegisters, Register.AL, OpAccess.Read);
AddRegister(flags, ref usedRegisters, Register.AX, OpAccess.Write);
}
}
break;
case CodeInfo.Enter:
xsp = GetXSP(instruction.CodeSize, out xspMask);
if ((flags & Flags.NoRegisterUsage) == 0) {
if ((flags & Flags.Is64Bit) == 0)
AddRegister(flags, ref usedRegisters, Register.SS, OpAccess.Read);
AddRegister(flags, ref usedRegisters, xsp, OpAccess.ReadWrite);
}
uint opSize;
code = instruction.Code;
Register rSP;
if (code == Code.Enterq_imm16_imm8) {
opSize = 8;
memSize = MemorySize.UInt64;
rSP = Register.RSP;
}
else if (code == Code.Enterd_imm16_imm8) {
opSize = 4;
memSize = MemorySize.UInt32;
rSP = Register.ESP;
}
else {
Debug.Assert(code == Code.Enterw_imm16_imm8);
opSize = 2;
memSize = MemorySize.UInt16;
rSP = Register.SP;
}
if (rSP != xsp && (flags & Flags.NoRegisterUsage) == 0)
AddRegister(flags, ref usedRegisters, rSP, OpAccess.ReadWrite);
int nestingLevel = instruction.Immediate8_2nd & 0x1F;
ulong xspOffset = 0;
// push rBP
if ((flags & Flags.NoRegisterUsage) == 0)
AddRegister(flags, ref usedRegisters, rSP + 1, OpAccess.ReadWrite);
if ((flags & Flags.NoMemoryUsage) == 0)
AddMemory(ref usedMemoryLocations, Register.SS, xsp, Register.None, 1, (xspOffset -= opSize) & xspMask, memSize, OpAccess.Write);
if (nestingLevel != 0) {
var xbp = xsp + 1;// rBP immediately follows rSP
ulong xbpOffset = 0;
for (int i = 1; i < nestingLevel; i++) {
if (i == 1 && rSP + 1 != xbp && (flags & Flags.NoRegisterUsage) == 0)
AddRegister(flags, ref usedRegisters, xbp, OpAccess.ReadWrite);
// push [xbp]
if ((flags & Flags.NoMemoryUsage) == 0) {
AddMemory(ref usedMemoryLocations, Register.SS, xbp, Register.None, 1, (xbpOffset -= opSize) & xspMask, memSize, OpAccess.Read);
AddMemory(ref usedMemoryLocations, Register.SS, xsp, Register.None, 1, (xspOffset -= opSize) & xspMask, memSize, OpAccess.Write);
}
}
// push frameTemp
if ((flags & Flags.NoMemoryUsage) == 0)
AddMemory(ref usedMemoryLocations, Register.SS, xsp, Register.None, 1, (xspOffset -= opSize) & xspMask, memSize, OpAccess.Write);
}
break;
case CodeInfo.Leave:
xsp = GetXSP(instruction.CodeSize, out xspMask);
if ((flags & Flags.NoRegisterUsage) == 0) {
if ((flags & Flags.Is64Bit) == 0)
AddRegister(flags, ref usedRegisters, Register.SS, OpAccess.Read);
AddRegister(flags, ref usedRegisters, xsp, OpAccess.Write);
}
code = instruction.Code;
if (code == Code.Leaveq) {
if ((flags & Flags.NoMemoryUsage) == 0)
AddMemory(ref usedMemoryLocations, Register.SS, xsp + 1, Register.None, 1, 0, MemorySize.UInt64, OpAccess.Read);
if ((flags & Flags.NoRegisterUsage) == 0) {
if (xsp + 1 == Register.RBP)
AddRegister(flags, ref usedRegisters, Register.RBP, OpAccess.ReadWrite);
else {
AddRegister(flags, ref usedRegisters, xsp + 1, OpAccess.Read);
AddRegister(flags, ref usedRegisters, Register.RBP, OpAccess.Write);
}
}
}
else if (code == Code.Leaved) {
if ((flags & Flags.NoMemoryUsage) == 0)
AddMemory(ref usedMemoryLocations, Register.SS, xsp + 1, Register.None, 1, 0, MemorySize.UInt32, OpAccess.Read);
if ((flags & Flags.NoRegisterUsage) == 0) {
if (xsp + 1 == Register.EBP)
AddRegister(flags, ref usedRegisters, Register.EBP, OpAccess.ReadWrite);
else {
AddRegister(flags, ref usedRegisters, xsp + 1, OpAccess.Read);
AddRegister(flags, ref usedRegisters, Register.EBP, OpAccess.Write);
}
}
}
else {
Debug.Assert(code == Code.Leavew);
if ((flags & Flags.NoMemoryUsage) == 0)
AddMemory(ref usedMemoryLocations, Register.SS, xsp + 1, Register.None, 1, 0, MemorySize.UInt16, OpAccess.Read);
if ((flags & Flags.NoRegisterUsage) == 0) {
if (xsp + 1 == Register.BP)
AddRegister(flags, ref usedRegisters, Register.BP, OpAccess.ReadWrite);
else {
AddRegister(flags, ref usedRegisters, xsp + 1, OpAccess.Read);
AddRegister(flags, ref usedRegisters, Register.BP, OpAccess.Write);
}
}
}
break;
case CodeInfo.Iret:
xsp = GetXSP(instruction.CodeSize, out xspMask);
if ((flags & Flags.NoRegisterUsage) == 0) {
AddRegister(flags, ref usedRegisters, Register.SS, (flags & Flags.Is64Bit) != 0 ? OpAccess.Write : OpAccess.Read);
AddRegister(flags, ref usedRegisters, xsp, OpAccess.ReadWrite);
}
if ((flags & Flags.NoMemoryUsage) == 0) {
code = instruction.Code;
if (code == Code.Iretq) {
AddMemory(ref usedMemoryLocations, Register.SS, xsp, Register.None, 1, 0 * 8, MemorySize.UInt64, OpAccess.Read);
AddMemory(ref usedMemoryLocations, Register.SS, xsp, Register.None, 1, 1 * 8, MemorySize.UInt64, OpAccess.Read);
AddMemory(ref usedMemoryLocations, Register.SS, xsp, Register.None, 1, 2 * 8, MemorySize.UInt64, OpAccess.Read);
AddMemory(ref usedMemoryLocations, Register.SS, xsp, Register.None, 1, 3 * 8, MemorySize.UInt64, OpAccess.Read);
AddMemory(ref usedMemoryLocations, Register.SS, xsp, Register.None, 1, 4 * 8, MemorySize.UInt64, OpAccess.Read);
}
else if (code == Code.Iretd) {
AddMemory(ref usedMemoryLocations, Register.SS, xsp, Register.None, 1, 0 * 4, MemorySize.UInt32, OpAccess.Read);
AddMemory(ref usedMemoryLocations, Register.SS, xsp, Register.None, 1, 1 * 4, MemorySize.UInt32, OpAccess.Read);
AddMemory(ref usedMemoryLocations, Register.SS, xsp, Register.None, 1, 2 * 4, MemorySize.UInt32, OpAccess.Read);
if (instruction.CodeSize == CodeSize.Code64) {
AddMemory(ref usedMemoryLocations, Register.SS, xsp, Register.None, 1, 3 * 4, MemorySize.UInt32, OpAccess.Read);
AddMemory(ref usedMemoryLocations, Register.SS, xsp, Register.None, 1, 4 * 4, MemorySize.UInt32, OpAccess.Read);
}
}
else {
Debug.Assert(code == Code.Iretw);
AddMemory(ref usedMemoryLocations, Register.SS, xsp, Register.None, 1, 0 * 2, MemorySize.UInt16, OpAccess.Read);
AddMemory(ref usedMemoryLocations, Register.SS, xsp, Register.None, 1, 1 * 2, MemorySize.UInt16, OpAccess.Read);
AddMemory(ref usedMemoryLocations, Register.SS, xsp, Register.None, 1, 2 * 2, MemorySize.UInt16, OpAccess.Read);
if (instruction.CodeSize == CodeSize.Code64) {
AddMemory(ref usedMemoryLocations, Register.SS, xsp, Register.None, 1, 3 * 2, MemorySize.UInt16, OpAccess.Read);
AddMemory(ref usedMemoryLocations, Register.SS, xsp, Register.None, 1, 4 * 2, MemorySize.UInt16, OpAccess.Read);
}
}
}
break;
case CodeInfo.Vzeroall:
if ((flags & Flags.NoRegisterUsage) == 0) {
OpAccess access;
if (instruction.Code == Code.VEX_Vzeroupper)
access = OpAccess.ReadWrite;
else {
Debug.Assert(instruction.Code == Code.VEX_Vzeroall);
access = OpAccess.Write;
}
int maxVecRegs;
if ((flags & Flags.Is64Bit) != 0)
maxVecRegs = InstructionInfoConstants.VMM_last - InstructionInfoConstants.VMM_first + 1;
else
maxVecRegs = 8;
for (int i = 0; i < maxVecRegs; i++)
AddRegister(flags, ref usedRegisters, InstructionInfoConstants.VMM_first + i, access);
}
break;
case CodeInfo.Jrcxz:
if ((flags & Flags.NoRegisterUsage) == 0) {
code = instruction.Code;
if (code == Code.Jrcxz_rel8_64 || code == Code.Jrcxz_rel8_16)
AddRegister(flags, ref usedRegisters, Register.RCX, OpAccess.Read);
else if (code == Code.Jecxz_rel8_64 || code == Code.Jecxz_rel8_32 || code == Code.Jecxz_rel8_16)
AddRegister(flags, ref usedRegisters, Register.ECX, OpAccess.Read);
else {
Debug.Assert(code == Code.Jcxz_rel8_32 || code == Code.Jcxz_rel8_16);
AddRegister(flags, ref usedRegisters, Register.CX, OpAccess.Read);
}
}
break;
case CodeInfo.Loop:
if ((flags & Flags.NoRegisterUsage) == 0) {
code = instruction.Code;
if (code == Code.Loopne_rel8_64_RCX || code == Code.Loope_rel8_64_RCX || code == Code.Loop_rel8_64_RCX ||
code == Code.Loopne_rel8_16_RCX || code == Code.Loope_rel8_16_RCX || code == Code.Loop_rel8_16_RCX)
AddRegister(flags, ref usedRegisters, Register.RCX, OpAccess.ReadWrite);
else if (code == Code.Loopne_rel8_16_ECX || code == Code.Loopne_rel8_32_ECX || code == Code.Loopne_rel8_64_ECX ||
code == Code.Loope_rel8_16_ECX || code == Code.Loope_rel8_32_ECX || code == Code.Loope_rel8_64_ECX ||
code == Code.Loop_rel8_16_ECX || code == Code.Loop_rel8_32_ECX || code == Code.Loop_rel8_64_ECX)
AddRegister(flags, ref usedRegisters, Register.ECX, OpAccess.ReadWrite);
else {
Debug.Assert(code == Code.Loopne_rel8_16_CX || code == Code.Loopne_rel8_32_CX ||
code == Code.Loope_rel8_16_CX || code == Code.Loope_rel8_32_CX ||
code == Code.Loop_rel8_16_CX || code == Code.Loop_rel8_32_CX);
AddRegister(flags, ref usedRegisters, Register.CX, OpAccess.ReadWrite);
}
}
break;
case CodeInfo.Lahf:
if ((flags & Flags.NoRegisterUsage) == 0)
AddRegister(flags, ref usedRegisters, Register.AH, instruction.Code == Code.Sahf ? OpAccess.Read : OpAccess.Write);
break;
case CodeInfo.Lds:
if ((flags & Flags.NoRegisterUsage) == 0) {
code = instruction.Code;
if (Code.Lfs_r16_m32 <= code && code <= Code.Lfs_r64_m80)
AddRegister(flags, ref usedRegisters, Register.FS, OpAccess.Write);
else if (Code.Lgs_r16_m32 <= code && code <= Code.Lgs_r64_m80)
AddRegister(flags, ref usedRegisters, Register.GS, OpAccess.Write);
else if (Code.Lss_r16_m32 <= code && code <= Code.Lss_r64_m80)
AddRegister(flags, ref usedRegisters, Register.SS, OpAccess.Write);
else if (Code.Lds_r16_m32 <= code && code <= Code.Lds_r32_m48)
AddRegister(flags, ref usedRegisters, Register.DS, OpAccess.Write);
else {
Debug.Assert(Code.Les_r16_m32 <= code && code <= Code.Les_r32_m48);
AddRegister(flags, ref usedRegisters, Register.ES, OpAccess.Write);
}
}
break;
case CodeInfo.Maskmovq:
switch (instruction.Op0Kind) {
case OpKind.MemorySegDI:
baseReg = Register.DI;
break;
case OpKind.MemorySegEDI:
baseReg = Register.EDI;
break;
default:
Debug.Assert(instruction.Op0Kind == OpKind.MemorySegRDI);
baseReg = Register.RDI;
break;
}
if ((flags & Flags.NoMemoryUsage) == 0)
AddMemory(ref usedMemoryLocations, instruction.MemorySegment, baseReg, Register.None, 1, 0, instruction.MemorySize, OpAccess.Write);
if ((flags & Flags.NoRegisterUsage) == 0) {
AddMemorySegmentRegister(flags, ref usedRegisters, instruction.MemorySegment, OpAccess.Read);
AddRegister(flags, ref usedRegisters, baseReg, OpAccess.Read);
}
break;
case CodeInfo.Monitor:
code = instruction.Code;
if (code == Code.Monitorq || code == Code.Monitorxq)
baseReg = Register.RAX;
else if (code == Code.Monitord || code == Code.Monitorxd)
baseReg = Register.EAX;
else {
Debug.Assert(code == Code.Monitorw || code == Code.Monitorxw);
baseReg = Register.AX;
}
var seg = instruction.SegmentPrefix;
if (seg == Register.None)
seg = Register.DS;
if ((flags & Flags.NoMemoryUsage) == 0)
AddMemory(ref usedMemoryLocations, seg, baseReg, Register.None, 1, 0, MemorySize.Unknown, OpAccess.Read);
if ((flags & Flags.NoRegisterUsage) == 0) {
AddMemorySegmentRegister(flags, ref usedRegisters, seg, OpAccess.Read);
AddRegister(flags, ref usedRegisters, baseReg, OpAccess.Read);
if ((flags & Flags.Is64Bit) != 0) {
AddRegister(flags, ref usedRegisters, Register.RCX, OpAccess.Read);
AddRegister(flags, ref usedRegisters, Register.RDX, OpAccess.Read);
}
else {
AddRegister(flags, ref usedRegisters, Register.ECX, OpAccess.Read);
AddRegister(flags, ref usedRegisters, Register.EDX, OpAccess.Read);
}
}
break;
case CodeInfo.Mwait:
if ((flags & Flags.NoRegisterUsage) == 0) {
if ((flags & Flags.Is64Bit) != 0) {
AddRegister(flags, ref usedRegisters, Register.RAX, OpAccess.Read);
AddRegister(flags, ref usedRegisters, Register.RCX, OpAccess.Read);
}
else {
AddRegister(flags, ref usedRegisters, Register.EAX, OpAccess.Read);
AddRegister(flags, ref usedRegisters, Register.ECX, OpAccess.Read);
}
}
break;
case CodeInfo.Mwaitx:
if ((flags & Flags.NoRegisterUsage) == 0) {
if ((flags & Flags.Is64Bit) != 0) {
AddRegister(flags, ref usedRegisters, Register.RAX, OpAccess.Read);
AddRegister(flags, ref usedRegisters, Register.RCX, OpAccess.Read);
AddRegister(flags, ref usedRegisters, Register.RBX, OpAccess.CondRead);
}
else {
AddRegister(flags, ref usedRegisters, Register.EAX, OpAccess.Read);
AddRegister(flags, ref usedRegisters, Register.ECX, OpAccess.Read);
AddRegister(flags, ref usedRegisters, Register.EBX, OpAccess.CondRead);
}
}
break;
case CodeInfo.Mulx:
if ((flags & Flags.NoRegisterUsage) == 0) {
if (instruction.Code == Code.VEX_Mulx_r32_r32_rm32)
AddRegister(flags, ref usedRegisters, Register.EDX, OpAccess.Read);
else {
Debug.Assert(instruction.Code == Code.VEX_Mulx_r64_r64_rm64);
AddRegister(flags, ref usedRegisters, Register.RDX, OpAccess.Read);
}
}
break;
case CodeInfo.PcmpXstrY:
if ((flags & Flags.NoRegisterUsage) == 0) {
code = instruction.Code;
if (code == Code.Pcmpestrm_xmm_xmmm128_imm8 || code == Code.VEX_Vpcmpestrm_xmm_xmmm128_imm8 ||
code == Code.Pcmpestri_xmm_xmmm128_imm8 || code == Code.VEX_Vpcmpestri_xmm_xmmm128_imm8) {
AddRegister(flags, ref usedRegisters, Register.EAX, OpAccess.Read);
AddRegister(flags, ref usedRegisters, Register.EDX, OpAccess.Read);
}
else if (code == Code.Pcmpestrm64_xmm_xmmm128_imm8 || code == Code.VEX_Vpcmpestrm64_xmm_xmmm128_imm8 ||
code == Code.Pcmpestri64_xmm_xmmm128_imm8 || code == Code.VEX_Vpcmpestri64_xmm_xmmm128_imm8) {
AddRegister(flags, ref usedRegisters, Register.RAX, OpAccess.Read);
AddRegister(flags, ref usedRegisters, Register.RDX, OpAccess.Read);
}
if (code == Code.Pcmpestrm_xmm_xmmm128_imm8 || code == Code.VEX_Vpcmpestrm_xmm_xmmm128_imm8 ||
code == Code.Pcmpestrm64_xmm_xmmm128_imm8 || code == Code.VEX_Vpcmpestrm64_xmm_xmmm128_imm8 ||
code == Code.Pcmpistrm_xmm_xmmm128_imm8 || code == Code.VEX_Vpcmpistrm_xmm_xmmm128_imm8) {
AddRegister(flags, ref usedRegisters, Register.XMM0, OpAccess.Write);
}
else {
Debug.Assert(code == Code.Pcmpestri_xmm_xmmm128_imm8 || code == Code.VEX_Vpcmpestri_xmm_xmmm128_imm8 ||
code == Code.Pcmpestri64_xmm_xmmm128_imm8 || code == Code.VEX_Vpcmpestri64_xmm_xmmm128_imm8 ||
code == Code.Pcmpistri_xmm_xmmm128_imm8 || code == Code.VEX_Vpcmpistri_xmm_xmmm128_imm8);
AddRegister(flags, ref usedRegisters, Register.ECX, OpAccess.Write);
}
}
break;
case CodeInfo.Shift_Ib_MASK1FMOD9:
if ((instruction.Immediate8 & 0x1F) % 9 == 0)
rflagsInfo = RflagsInfo.None;
break;
case CodeInfo.Shift_Ib_MASK1FMOD11:
if ((instruction.Immediate8 & 0x1F) % 17 == 0)
rflagsInfo = RflagsInfo.None;
break;
case CodeInfo.Shift_Ib_MASK1F:
if ((instruction.Immediate8 & 0x1F) == 0)
rflagsInfo = RflagsInfo.None;
break;
case CodeInfo.Shift_Ib_MASK3F:
if ((instruction.Immediate8 & 0x3F) == 0)
rflagsInfo = RflagsInfo.None;
break;
case CodeInfo.R_EAX_EDX:
if ((flags & Flags.NoRegisterUsage) == 0) {
AddRegister(flags, ref usedRegisters, Register.EAX, OpAccess.Read);
AddRegister(flags, ref usedRegisters, Register.EDX, OpAccess.Read);
}
break;
case CodeInfo.R_ECX_W_EAX_EDX:
if ((flags & Flags.NoRegisterUsage) == 0) {
AddRegister(flags, ref usedRegisters, Register.EAX, OpAccess.Write);
AddRegister(flags, ref usedRegisters, Register.ECX, OpAccess.Read);
AddRegister(flags, ref usedRegisters, Register.EDX, OpAccess.Write);
}
break;
case CodeInfo.R_EAX_ECX_EDX:
if ((flags & Flags.NoRegisterUsage) == 0) {
AddRegister(flags, ref usedRegisters, Register.EAX, OpAccess.Read);
AddRegister(flags, ref usedRegisters, Register.ECX, OpAccess.Read);
AddRegister(flags, ref usedRegisters, Register.EDX, OpAccess.Read);
}
break;
case CodeInfo.W_EAX_EDX:
if ((flags & Flags.NoRegisterUsage) == 0) {
AddRegister(flags, ref usedRegisters, Register.EAX, OpAccess.Write);
AddRegister(flags, ref usedRegisters, Register.EDX, OpAccess.Write);
}
break;
case CodeInfo.W_EAX_ECX_EDX:
if ((flags & Flags.NoRegisterUsage) == 0) {
AddRegister(flags, ref usedRegisters, Register.EAX, OpAccess.Write);
AddRegister(flags, ref usedRegisters, Register.ECX, OpAccess.Write);
AddRegister(flags, ref usedRegisters, Register.EDX, OpAccess.Write);
}
break;
case CodeInfo.Pconfig:
if ((flags & Flags.NoRegisterUsage) == 0) {
AddRegister(flags, ref usedRegisters, Register.EAX, OpAccess.ReadWrite);
baseReg = (flags & Flags.Is64Bit) != 0 ? Register.RAX : Register.EAX;
AddRegister(flags, ref usedRegisters, baseReg + 1, OpAccess.CondRead);
AddRegister(flags, ref usedRegisters, baseReg + 2, OpAccess.CondRead);
AddRegister(flags, ref usedRegisters, baseReg + 3, OpAccess.CondRead);
}
break;
case CodeInfo.Syscall:
if ((flags & Flags.NoRegisterUsage) == 0) {
code = instruction.Code;
if (code == Code.Syscall) {
AddRegister(flags, ref usedRegisters, Register.ECX, OpAccess.Write);
if ((flags & Flags.Is64Bit) != 0)
AddRegister(flags, ref usedRegisters, Register.R11, OpAccess.Write);
}
else if (code == Code.Sysenter)
AddRegister(flags, ref usedRegisters, (flags & Flags.Is64Bit) != 0 ? Register.RSP : Register.ESP, OpAccess.Write);
else if (code == Code.Sysretq) {
AddRegister(flags, ref usedRegisters, Register.RCX, OpAccess.Read);
AddRegister(flags, ref usedRegisters, Register.R11, OpAccess.Read);
}
else if (code == Code.Sysexitq) {
AddRegister(flags, ref usedRegisters, Register.RCX, OpAccess.Read);
AddRegister(flags, ref usedRegisters, Register.RDX, OpAccess.Read);
AddRegister(flags, ref usedRegisters, Register.RSP, OpAccess.Write);
}
else if (code == Code.Sysretd) {
AddRegister(flags, ref usedRegisters, Register.ECX, OpAccess.Read);
if ((flags & Flags.Is64Bit) != 0)
AddRegister(flags, ref usedRegisters, Register.R11, OpAccess.Read);
}
else {
Debug.Assert(code == Code.Sysexitd);
AddRegister(flags, ref usedRegisters, Register.ECX, OpAccess.Read);
AddRegister(flags, ref usedRegisters, Register.EDX, OpAccess.Read);
AddRegister(flags, ref usedRegisters, (flags & Flags.Is64Bit) != 0 ? Register.RSP : Register.ESP, OpAccess.Write);
}
}
break;
case CodeInfo.Encls:
if ((flags & Flags.NoRegisterUsage) == 0) {
baseReg = (flags & Flags.Is64Bit) != 0 ? Register.RAX : Register.EAX;
AddRegister(flags, ref usedRegisters, Register.EAX, OpAccess.Read);
// rcx/ecx
AddRegister(flags, ref usedRegisters, baseReg + 1, OpAccess.CondRead);
AddRegister(flags, ref usedRegisters, baseReg + 1, OpAccess.CondWrite);
// rdx/edx
AddRegister(flags, ref usedRegisters, baseReg + 2, OpAccess.CondRead);
AddRegister(flags, ref usedRegisters, baseReg + 2, OpAccess.CondWrite);
// rbx/ebx
AddRegister(flags, ref usedRegisters, baseReg + 3, OpAccess.CondRead);
AddRegister(flags, ref usedRegisters, baseReg + 3, OpAccess.CondWrite);
}
break;
case CodeInfo.Vmfunc:
if ((flags & Flags.NoRegisterUsage) == 0) {
AddRegister(flags, ref usedRegisters, Register.EAX, OpAccess.Read);
AddRegister(flags, ref usedRegisters, Register.ECX, OpAccess.Read);
}
break;
case CodeInfo.Vmload:
code = instruction.Code;
if (code == Code.Vmloadq || code == Code.Vmsaveq || code == Code.Vmrunq)
baseReg = Register.RAX;
else if (code == Code.Vmloadd || code == Code.Vmsaved || code == Code.Vmrund)
baseReg = Register.EAX;
else {
Debug.Assert(code == Code.Vmloadw || code == Code.Vmsavew || code == Code.Vmrunw);
baseReg = Register.AX;
}
if ((flags & Flags.NoRegisterUsage) == 0)
AddRegister(flags, ref usedRegisters, baseReg, OpAccess.Read);
break;
case CodeInfo.R_CR0:
if ((flags & Flags.NoRegisterUsage) == 0)
AddRegister(flags, ref usedRegisters, Register.CR0, OpAccess.Read);
break;
case CodeInfo.RW_CR0:
if ((flags & Flags.NoRegisterUsage) == 0)
AddRegister(flags, ref usedRegisters, Register.CR0, OpAccess.ReadWrite);
break;
case CodeInfo.RW_ST0:
if ((flags & Flags.NoRegisterUsage) == 0)
AddRegister(flags, ref usedRegisters, Register.ST0, OpAccess.ReadWrite);
break;
case CodeInfo.R_ST0:
if ((flags & Flags.NoRegisterUsage) == 0)
AddRegister(flags, ref usedRegisters, Register.ST0, OpAccess.Read);
break;
case CodeInfo.W_ST0:
if ((flags & Flags.NoRegisterUsage) == 0)
AddRegister(flags, ref usedRegisters, Register.ST0, OpAccess.Write);
break;
case CodeInfo.R_ST0_ST1:
if ((flags & Flags.NoRegisterUsage) == 0) {
AddRegister(flags, ref usedRegisters, Register.ST0, OpAccess.Read);
AddRegister(flags, ref usedRegisters, Register.ST1, OpAccess.Read);
}
break;
case CodeInfo.R_ST0_R_ST1:
if ((flags & Flags.NoRegisterUsage) == 0) {
AddRegister(flags, ref usedRegisters, Register.ST0, OpAccess.Read);
AddRegister(flags, ref usedRegisters, Register.ST1, OpAccess.Read);
}
break;
case CodeInfo.R_ST0_RW_ST1:
if ((flags & Flags.NoRegisterUsage) == 0) {
AddRegister(flags, ref usedRegisters, Register.ST0, OpAccess.Read);
AddRegister(flags, ref usedRegisters, Register.ST1, OpAccess.ReadWrite);
}
break;
case CodeInfo.RW_ST0_R_ST1:
if ((flags & Flags.NoRegisterUsage) == 0) {
AddRegister(flags, ref usedRegisters, Register.ST0, OpAccess.ReadWrite);
AddRegister(flags, ref usedRegisters, Register.ST1, OpAccess.Read);
}
break;
case CodeInfo.Clzero:
if ((flags & Flags.NoRegisterUsage) == 0) {
code = instruction.Code;
if (code == Code.Clzeroq)
baseReg = Register.RAX;
else if (code == Code.Clzerod)
baseReg = Register.EAX;
else {
Debug.Assert(code == Code.Clzerow);
baseReg = Register.AX;
}
AddRegister(flags, ref usedRegisters, baseReg, OpAccess.Read);
if ((flags & Flags.NoRegisterUsage) == 0) {
baseReg = instruction.SegmentPrefix;
if (baseReg == Register.None)
baseReg = Register.DS;
AddMemorySegmentRegister(flags, ref usedRegisters, baseReg, OpAccess.Read);
}
}
break;
case CodeInfo.Invlpga:
if ((flags & Flags.NoRegisterUsage) == 0) {
code = instruction.Code;
if (code == Code.Invlpgaq)
baseReg = Register.RAX;
else if (code == Code.Invlpgad)
baseReg = Register.EAX;
else {
Debug.Assert(code == Code.Invlpgaw);
baseReg = Register.AX;
}
AddRegister(flags, ref usedRegisters, baseReg, OpAccess.Read);
AddRegister(flags, ref usedRegisters, Register.ECX, OpAccess.Read);
}
break;
case CodeInfo.Llwpcb:
if ((flags & (Flags.NoRegisterUsage | Flags.Is64Bit)) == 0)
AddRegister(flags, ref usedRegisters, Register.DS, OpAccess.Read);
if ((flags & Flags.NoMemoryUsage) == 0)
AddMemory(ref usedMemoryLocations, Register.DS, instruction.Op0Register, Register.None, 1, 0, MemorySize.Unknown, OpAccess.Read);
break;
case CodeInfo.Loadall386:
if ((flags & Flags.NoRegisterUsage) == 0) {
AddRegister(flags, ref usedRegisters, Register.ES, OpAccess.Read);
AddRegister(flags, ref usedRegisters, Register.EDI, OpAccess.Read);
}
break;
case CodeInfo.Xbts:
if ((flags & Flags.NoRegisterUsage) == 0) {
code = instruction.Code;
if (code == Code.Xbts_r32_rm32 || code == Code.Ibts_rm32_r32)
AddRegister(flags, ref usedRegisters, Register.EAX, OpAccess.Read);
else {
Debug.Assert(code == Code.Xbts_r16_rm16 || code == Code.Ibts_rm16_r16);
AddRegister(flags, ref usedRegisters, Register.AX, OpAccess.Read);
}
AddRegister(flags, ref usedRegisters, Register.CL, OpAccess.Read);
}
break;
case CodeInfo.Umonitor:
baseReg = instruction.SegmentPrefix;
if (baseReg == Register.None)
baseReg = Register.DS;
if ((flags & Flags.NoRegisterUsage) == 0)
AddMemorySegmentRegister(flags, ref usedRegisters, baseReg, OpAccess.Read);
if ((flags & Flags.NoMemoryUsage) == 0)
AddMemory(ref usedMemoryLocations, baseReg, instruction.Op0Register, Register.None, 1, 0, MemorySize.UInt8, OpAccess.Read);
break;
case CodeInfo.Movdir64b:
if ((flags & Flags.Is64Bit) == 0 && (flags & Flags.NoRegisterUsage) == 0)
AddRegister(flags, ref usedRegisters, Register.ES, OpAccess.Read);
if ((flags & Flags.NoMemoryUsage) == 0)
AddMemory(ref usedMemoryLocations, Register.ES, instruction.Op0Register, Register.None, 1, 0, MemorySize.UInt512, OpAccess.Write);
break;
case CodeInfo.Clear_rflags:
if (instruction.Op0Register != instruction.Op1Register)
break;
if (instruction.Op0Kind != OpKind.Register || instruction.Op1Kind != OpKind.Register)
break;
accesses[0] = OpAccess.Write;
accesses[1] = OpAccess.None;
rflagsInfo = RflagsInfo.C_cos_S_pz_U_a;
if ((flags & Flags.NoRegisterUsage) == 0) {
Debug.Assert(usedRegisters.ValidLength == 2 || usedRegisters.ValidLength == 3);
usedRegisters.ValidLength = 0;
AddRegister(flags, ref usedRegisters, instruction.Op0Register, OpAccess.Write);
}
break;
case CodeInfo.Clear_reg_regmem:
if (instruction.Op0Register != instruction.Op1Register)
break;
if (instruction.Op1Kind != OpKind.Register)
break;
accesses[0] = OpAccess.Write;
accesses[1] = OpAccess.None;
if ((flags & Flags.NoRegisterUsage) == 0) {
Debug.Assert(usedRegisters.ValidLength == 2 || usedRegisters.ValidLength == 3);
usedRegisters.Array[0] = new UsedRegister(instruction.Op0Register, OpAccess.Write);
usedRegisters.ValidLength = 1;
}
break;
case CodeInfo.Clear_reg_reg_regmem:
if (instruction.Op1Register != instruction.Op2Register)
break;
if (instruction.Op2Kind != OpKind.Register)
break;
accesses[1] = OpAccess.None;
accesses[2] = OpAccess.None;
if ((flags & Flags.NoRegisterUsage) == 0) {
Debug.Assert(usedRegisters.ValidLength == 3 || usedRegisters.ValidLength == 4);
Debug.Assert(usedRegisters.Array[usedRegisters.ValidLength - 2].Register == instruction.Op1Register);
Debug.Assert(usedRegisters.Array[usedRegisters.ValidLength - 1].Register == instruction.Op2Register);
usedRegisters.ValidLength -= 2;
}
break;
case CodeInfo.Montmul:
Debug.Assert(Code.Montmul_16 + 1 == Code.Montmul_32);
Debug.Assert(Code.Montmul_16 + 2 == Code.Montmul_64);
Debug.Assert(Register.AX + 16 == Register.EAX);
Debug.Assert(Register.AX + 32 == Register.RAX);
if (instruction.Internal_HasRepeOrRepnePrefix) {
baseReg = (Register)((instruction.Code - Code.Montmul_16) << 4);
if ((flags & Flags.NoMemoryUsage) == 0)
AddMemory(ref usedMemoryLocations, Register.ES, Register.SI + (int)baseReg, Register.None, 1, 0, MemorySize.Unknown, OpAccess.CondRead);
if ((flags & Flags.NoRegisterUsage) == 0) {
Debug.Assert(usedRegisters.ValidLength == 0);
AddRegister(flags, ref usedRegisters, baseReg == 0 ? Register.ECX : Register.CX + (int)baseReg, OpAccess.ReadCondWrite);
if ((flags & Flags.Is64Bit) == 0)
AddRegister(flags, ref usedRegisters, Register.ES, OpAccess.CondRead);
AddRegister(flags, ref usedRegisters, Register.SI + (int)baseReg, OpAccess.CondRead);
AddRegister(flags, ref usedRegisters, Register.EAX, OpAccess.CondRead);
AddRegister(flags, ref usedRegisters, Register.EAX, OpAccess.CondWrite);
AddRegister(flags, ref usedRegisters, Register.EDX, OpAccess.CondWrite);
}
}
else {
baseReg = (Register)((instruction.Code - Code.Montmul_16) << 4);
if ((flags & Flags.NoMemoryUsage) == 0)
AddMemory(ref usedMemoryLocations, Register.ES, Register.SI + (int)baseReg, Register.None, 1, 0, instruction.MemorySize, OpAccess.Read);
if ((flags & Flags.NoRegisterUsage) == 0) {
if ((flags & Flags.Is64Bit) == 0)
AddRegister(flags, ref usedRegisters, Register.ES, OpAccess.Read);
AddRegister(flags, ref usedRegisters, Register.SI + (int)baseReg, OpAccess.Read);
AddRegister(flags, ref usedRegisters, Register.EAX, OpAccess.ReadWrite);
AddRegister(flags, ref usedRegisters, Register.EDX, OpAccess.Write);
}
}
break;
case CodeInfo.Xsha:
Debug.Assert(Code.Xsha1_16 + 1 == Code.Xsha1_32);
Debug.Assert(Code.Xsha1_16 + 2 == Code.Xsha1_64);
Debug.Assert(Code.Xsha1_16 + 3 == Code.Xsha256_16);
Debug.Assert(Code.Xsha1_16 + 4 == Code.Xsha256_32);
Debug.Assert(Code.Xsha1_16 + 5 == Code.Xsha256_64);
Debug.Assert(Register.AX + 16 == Register.EAX);
Debug.Assert(Register.AX + 32 == Register.RAX);
if (instruction.Internal_HasRepeOrRepnePrefix) {
baseReg = (Register)(((instruction.Code - Code.Xsha1_16) % 3) << 4);
if ((flags & Flags.NoMemoryUsage) == 0) {
AddMemory(ref usedMemoryLocations, Register.ES, Register.SI + (int)baseReg, Register.None, 1, 0, MemorySize.Unknown, OpAccess.CondRead);
AddMemory(ref usedMemoryLocations, Register.ES, Register.DI + (int)baseReg, Register.None, 1, 0, MemorySize.Unknown, OpAccess.CondRead);
AddMemory(ref usedMemoryLocations, Register.ES, Register.DI + (int)baseReg, Register.None, 1, 0, MemorySize.Unknown, OpAccess.CondWrite);
}
if ((flags & Flags.NoRegisterUsage) == 0) {
Debug.Assert(usedRegisters.ValidLength == 0);
AddRegister(flags, ref usedRegisters, Register.CX + (int)baseReg, OpAccess.ReadCondWrite);
if ((flags & Flags.Is64Bit) == 0)
AddRegister(flags, ref usedRegisters, Register.ES, OpAccess.CondRead);
AddRegister(flags, ref usedRegisters, Register.SI + (int)baseReg, OpAccess.CondRead);
AddRegister(flags, ref usedRegisters, Register.SI + (int)baseReg, OpAccess.CondWrite);
AddRegister(flags, ref usedRegisters, Register.DI + (int)baseReg, OpAccess.CondRead);
AddRegister(flags, ref usedRegisters, Register.DI + (int)baseReg, OpAccess.CondWrite);
AddRegister(flags, ref usedRegisters, Register.AX + (int)baseReg, OpAccess.CondRead);
AddRegister(flags, ref usedRegisters, Register.AX + (int)baseReg, OpAccess.CondWrite);
}
}
else {
baseReg = (Register)(((instruction.Code - Code.Xsha1_16) % 3) << 4);
if ((flags & Flags.NoMemoryUsage) == 0) {
AddMemory(ref usedMemoryLocations, Register.ES, Register.SI + (int)baseReg, Register.None, 1, 0, instruction.MemorySize, OpAccess.Read);
AddMemory(ref usedMemoryLocations, Register.ES, Register.DI + (int)baseReg, Register.None, 1, 0, instruction.MemorySize, OpAccess.ReadWrite);
}
if ((flags & Flags.NoRegisterUsage) == 0) {
if ((flags & Flags.Is64Bit) == 0)
AddRegister(flags, ref usedRegisters, Register.ES, OpAccess.Read);
AddRegister(flags, ref usedRegisters, Register.SI + (int)baseReg, OpAccess.ReadWrite);
AddRegister(flags, ref usedRegisters, Register.DI + (int)baseReg, OpAccess.ReadWrite);
}
}
break;
case CodeInfo.Xcrypt:
Debug.Assert(Code.XcryptEcb_16 + 1 == Code.XcryptEcb_32);
Debug.Assert(Code.XcryptEcb_16 + 2 == Code.XcryptEcb_64);
Debug.Assert(Code.XcryptEcb_16 + 3 == Code.XcryptCbc_16);
Debug.Assert(Code.XcryptEcb_16 + 4 == Code.XcryptCbc_32);
Debug.Assert(Code.XcryptEcb_16 + 5 == Code.XcryptCbc_64);
Debug.Assert(Code.XcryptEcb_16 + 6 == Code.XcryptCtr_16);
Debug.Assert(Code.XcryptEcb_16 + 7 == Code.XcryptCtr_32);
Debug.Assert(Code.XcryptEcb_16 + 8 == Code.XcryptCtr_64);
Debug.Assert(Code.XcryptEcb_16 + 9 == Code.XcryptCfb_16);
Debug.Assert(Code.XcryptEcb_16 + 10 == Code.XcryptCfb_32);
Debug.Assert(Code.XcryptEcb_16 + 11 == Code.XcryptCfb_64);
Debug.Assert(Code.XcryptEcb_16 + 12 == Code.XcryptOfb_16);
Debug.Assert(Code.XcryptEcb_16 + 13 == Code.XcryptOfb_32);
Debug.Assert(Code.XcryptEcb_16 + 14 == Code.XcryptOfb_64);
Debug.Assert(Register.AX + 16 == Register.EAX);
Debug.Assert(Register.AX + 32 == Register.RAX);
if (instruction.Internal_HasRepeOrRepnePrefix) {
Debug.Assert(OpKind.MemoryESDI + 1 == OpKind.MemoryESEDI);
Debug.Assert(OpKind.MemoryESDI + 2 == OpKind.MemoryESRDI);
Debug.Assert(Register.DI + 16 == Register.EDI);
Debug.Assert(Register.DI + 32 == Register.RDI);
Debug.Assert(Register.CX + 16 == Register.ECX);
Debug.Assert(Register.CX + 32 == Register.RCX);
baseReg = (Register)(((instruction.Code - Code.XcryptEcb_16) % 3) << 4);
if ((flags & Flags.NoMemoryUsage) == 0) {
// Check if not XcryptEcb
if (instruction.Code >= Code.XcryptCbc_16) {
AddMemory(ref usedMemoryLocations, Register.ES, Register.AX + (int)baseReg, Register.None, 1, 0, MemorySize.Unknown, OpAccess.CondRead);
AddMemory(ref usedMemoryLocations, Register.ES, Register.AX + (int)baseReg, Register.None, 1, 0, MemorySize.Unknown, OpAccess.CondWrite);
}
AddMemory(ref usedMemoryLocations, Register.ES, Register.DX + (int)baseReg, Register.None, 1, 0, MemorySize.Unknown, OpAccess.CondRead);
AddMemory(ref usedMemoryLocations, Register.ES, Register.BX + (int)baseReg, Register.None, 1, 0, MemorySize.Unknown, OpAccess.CondRead);
AddMemory(ref usedMemoryLocations, Register.ES, Register.SI + (int)baseReg, Register.None, 1, 0, MemorySize.Unknown, OpAccess.CondRead);
AddMemory(ref usedMemoryLocations, Register.ES, Register.DI + (int)baseReg, Register.None, 1, 0, MemorySize.Unknown, OpAccess.CondWrite);
}
if ((flags & Flags.NoRegisterUsage) == 0) {
Debug.Assert(usedRegisters.ValidLength == 0);
AddRegister(flags, ref usedRegisters, Register.CX + (int)baseReg, OpAccess.ReadCondWrite);
if ((flags & Flags.Is64Bit) == 0)
AddRegister(flags, ref usedRegisters, Register.ES, OpAccess.CondRead);
// Check if not XcryptEcb
if (instruction.Code >= Code.XcryptCbc_16) {
AddRegister(flags, ref usedRegisters, Register.AX + (int)baseReg, OpAccess.CondRead);
AddRegister(flags, ref usedRegisters, Register.AX + (int)baseReg, OpAccess.CondWrite);
}
AddRegister(flags, ref usedRegisters, Register.DX + (int)baseReg, OpAccess.CondRead);
AddRegister(flags, ref usedRegisters, Register.BX + (int)baseReg, OpAccess.CondRead);
AddRegister(flags, ref usedRegisters, Register.SI + (int)baseReg, OpAccess.CondRead);
AddRegister(flags, ref usedRegisters, Register.SI + (int)baseReg, OpAccess.CondWrite);
AddRegister(flags, ref usedRegisters, Register.DI + (int)baseReg, OpAccess.CondRead);
AddRegister(flags, ref usedRegisters, Register.DI + (int)baseReg, OpAccess.CondWrite);
}
}
else {
Debug.Assert(OpKind.MemoryESDI + 1 == OpKind.MemoryESEDI);
Debug.Assert(OpKind.MemoryESDI + 2 == OpKind.MemoryESRDI);
Debug.Assert(Register.DI + 16 == Register.EDI);
Debug.Assert(Register.DI + 32 == Register.RDI);
baseReg = (Register)(((instruction.Code - Code.XcryptEcb_16) % 3) << 4);
if ((flags & Flags.NoMemoryUsage) == 0) {
// Check if not XcryptEcb
if (instruction.Code >= Code.XcryptCbc_16)
AddMemory(ref usedMemoryLocations, Register.ES, Register.AX + (int)baseReg, Register.None, 1, 0, instruction.MemorySize, OpAccess.ReadWrite);
AddMemory(ref usedMemoryLocations, Register.ES, Register.DX + (int)baseReg, Register.None, 1, 0, instruction.MemorySize, OpAccess.Read);
AddMemory(ref usedMemoryLocations, Register.ES, Register.BX + (int)baseReg, Register.None, 1, 0, instruction.MemorySize, OpAccess.Read);
AddMemory(ref usedMemoryLocations, Register.ES, Register.SI + (int)baseReg, Register.None, 1, 0, instruction.MemorySize, OpAccess.Read);
AddMemory(ref usedMemoryLocations, Register.ES, Register.DI + (int)baseReg, Register.None, 1, 0, instruction.MemorySize, OpAccess.Write);
}
if ((flags & Flags.NoRegisterUsage) == 0) {
if ((flags & Flags.Is64Bit) == 0)
AddRegister(flags, ref usedRegisters, Register.ES, OpAccess.Read);
// Check if not XcryptEcb
if (instruction.Code >= Code.XcryptCbc_16)
AddRegister(flags, ref usedRegisters, Register.AX + (int)baseReg, OpAccess.ReadWrite);
AddRegister(flags, ref usedRegisters, Register.DX + (int)baseReg, OpAccess.Read);
AddRegister(flags, ref usedRegisters, Register.BX + (int)baseReg, OpAccess.Read);
AddRegister(flags, ref usedRegisters, Register.SI + (int)baseReg, OpAccess.ReadWrite);
AddRegister(flags, ref usedRegisters, Register.DI + (int)baseReg, OpAccess.ReadWrite);
}
}
break;
case CodeInfo.Xstore:
Debug.Assert(Code.Xstore_16 + 1 == Code.Xstore_32);
Debug.Assert(Code.Xstore_16 + 2 == Code.Xstore_64);
Debug.Assert(Register.AX + 16 == Register.EAX);
Debug.Assert(Register.AX + 32 == Register.RAX);
if (instruction.Internal_HasRepeOrRepnePrefix) {
baseReg = (Register)((instruction.Code - Code.Xstore_16) << 4);
if ((flags & Flags.NoMemoryUsage) == 0)
AddMemory(ref usedMemoryLocations, Register.ES, Register.DI + (int)baseReg, Register.None, 1, 0, MemorySize.Unknown, OpAccess.CondWrite);
if ((flags & Flags.NoRegisterUsage) == 0) {
Debug.Assert(usedRegisters.ValidLength == 0);
AddRegister(flags, ref usedRegisters, Register.CX + (int)baseReg, OpAccess.ReadCondWrite);
if ((flags & Flags.Is64Bit) == 0)
AddRegister(flags, ref usedRegisters, Register.ES, OpAccess.CondRead);
AddRegister(flags, ref usedRegisters, Register.DI + (int)baseReg, OpAccess.CondRead);
AddRegister(flags, ref usedRegisters, Register.DI + (int)baseReg, OpAccess.CondWrite);
AddRegister(flags, ref usedRegisters, Register.EAX, OpAccess.CondWrite);
AddRegister(flags, ref usedRegisters, Register.EDX, OpAccess.CondRead);
}
}
else {
baseReg = (Register)((instruction.Code - Code.Xstore_16) << 4);
if ((flags & Flags.NoMemoryUsage) == 0)
AddMemory(ref usedMemoryLocations, Register.ES, Register.DI + (int)baseReg, Register.None, 1, 0, instruction.MemorySize, OpAccess.Write);
if ((flags & Flags.NoRegisterUsage) == 0) {
if ((flags & Flags.Is64Bit) == 0)
AddRegister(flags, ref usedRegisters, Register.ES, OpAccess.Read);
AddRegister(flags, ref usedRegisters, Register.DI + (int)baseReg, OpAccess.ReadWrite);
AddRegister(flags, ref usedRegisters, Register.EAX, OpAccess.Write);
AddRegister(flags, ref usedRegisters, Register.EDX, OpAccess.Read);
}
}
break;
case CodeInfo.KP1:
Debug.Assert(Register.K0 <= instruction.Op0Register && instruction.Op0Register <= Register.K7);
if ((flags & Flags.NoRegisterUsage) == 0) {
Debug.Assert(((int)Register.K0 & 1) == 1);
if (((int)instruction.Op0Register & 1) != 0)
AddRegister(flags, ref usedRegisters, instruction.Op0Register + 1, OpAccess.Write);
else
AddRegister(flags, ref usedRegisters, instruction.Op0Register - 1, OpAccess.Write);
}
break;
case CodeInfo.None:
default:
throw new InvalidOperationException();
}
}
static void AddMemory(ref SimpleList<UsedMemory> usedMemoryLocations, Register segReg, Register baseReg, Register indexReg, int scale, ulong displ, MemorySize memorySize, OpAccess access) {
if (access != OpAccess.NoMemAccess) {
int arrayLength = usedMemoryLocations.Array.Length;
int validLen = usedMemoryLocations.ValidLength;
if (arrayLength == validLen) {
if (arrayLength == 0)
usedMemoryLocations.Array = new UsedMemory[defaultMemoryArrayCount];
else
Array.Resize(ref usedMemoryLocations.Array, arrayLength * 2);
}
usedMemoryLocations.Array[validLen] = new UsedMemory(segReg, baseReg, indexReg, scale, displ, memorySize, access);
usedMemoryLocations.ValidLength = validLen + 1;
}
}
[MethodImpl(MethodImplOptions2.AggressiveInlining)]
static void AddMemorySegmentRegister(Flags flags, ref SimpleList<UsedRegister> regs, Register seg, OpAccess access) {
Debug.Assert(Register.ES <= seg && seg <= Register.GS);
// Ignore es,cs,ss,ds memory operand segment registers in 64-bit mode
if ((flags & Flags.Is64Bit) == 0 || seg >= Register.FS)
AddRegister(flags, ref regs, seg, access);
}
static void AddRegister(Flags flags, ref SimpleList<UsedRegister> regs, Register reg, OpAccess access) {
Debug.Assert((flags & Flags.NoRegisterUsage) == 0, "Caller should check flags before calling this method");
var writeReg = reg;
if ((flags & (Flags.Is64Bit | Flags.ZeroExtVecRegs)) != 0) {
Debug.Assert(OpAccess.Write + 1 == OpAccess.CondWrite);
Debug.Assert(OpAccess.Write + 2 == OpAccess.ReadWrite);
Debug.Assert(OpAccess.Write + 3 == OpAccess.ReadCondWrite);
if ((uint)(access - OpAccess.Write) <= 3) {
int index;
Debug.Assert(InstructionInfoConstants.VMM_first == Register.ZMM0);
const uint VecRegCount = InstructionInfoConstants.VMM_last - InstructionInfoConstants.VMM_first + 1;
Debug.Assert((VecRegCount & (VecRegCount - 1)) == 0);// Verify that it's a power of 2
if ((flags & Flags.Is64Bit) != 0 && (uint)(index = reg - Register.EAX) <= (Register.R15D - Register.EAX))
writeReg = Register.RAX + index;
else if ((flags & Flags.ZeroExtVecRegs) != 0 && (uint)(index = reg - Register.XMM0) <= InstructionInfoConstants.VMM_last - Register.XMM0)
writeReg = Register.ZMM0 + (index & ((int)VecRegCount - 1));
if (access != OpAccess.ReadWrite && access != OpAccess.ReadCondWrite)
reg = writeReg;
}
}
var array = regs.Array;
int validLen = regs.ValidLength;
int arrayLength = array.Length;
int numRegs = writeReg == reg ? 1 : 2;
if (validLen + numRegs > arrayLength) {
if (arrayLength == 0) {
// The code below that resizes the array assumes there's at least 2 new free elements, so the minimum array length is 2.
Debug.Assert(defaultRegisterArrayCount >= 2);
regs.Array = array = new UsedRegister[defaultRegisterArrayCount];
}
else {
Debug.Assert(arrayLength * 2 >= arrayLength + numRegs);
Array.Resize(ref regs.Array, arrayLength * 2);
array = regs.Array;
}
}
if (writeReg == reg) {
array[validLen] = new UsedRegister(reg, access);
regs.ValidLength = validLen + 1;
}
else {
Debug.Assert(access == OpAccess.ReadWrite || access == OpAccess.ReadCondWrite);
array[validLen] = new UsedRegister(reg, OpAccess.Read);
validLen++;
var lastAccess = access == OpAccess.ReadWrite ? OpAccess.Write : OpAccess.CondWrite;
array[validLen] = new UsedRegister(writeReg, lastAccess);
regs.ValidLength = validLen + 1;
}
}
}
}
#endif