public void Generate() { var filename = genTypes.Dirs.GetRustFilename("instruction_internal.rs"); new FileUpdater(TargetLanguage.Rust, "RegToAddrSize", filename).Generate(writer => { var registerType = genTypes[TypeIds.Register]; var icedConstantsName = genTypes.GetConstantsType(TypeIds.IcedConstants).Name(idConverter); var regCountName = idConverter.Constant(IcedConstants.GetEnumCountName(TypeIds.Register)); writer.WriteLine(RustConstants.AttributeNoRustFmt); writer.WriteLine($"static REG_TO_ADDR_SIZE: [u8; {icedConstantsName}::{regCountName}] = ["); using (writer.Indent()) { foreach (var regEnum in registerType.Values) { var reg = (Register)regEnum.Value; var size = GetAddrSize(reg); if (size > byte.MaxValue) { throw new InvalidOperationException(); } writer.WriteLine($"{size}, // {regEnum.Name(idConverter)}"); } } writer.WriteLine("];"); }); }
public void Generate() { var genTypes = generatorContext.Types; var icedConstants = genTypes.GetConstantsType(TypeIds.IcedConstants); var defs = genTypes.GetObject <InstructionDefs>(TypeIds.InstructionDefs).Defs; var mnemonicName = genTypes[TypeIds.Mnemonic].Name(idConverter); using (var writer = new FileWriter(TargetLanguage.Rust, FileUtils.OpenWrite(generatorContext.Types.Dirs.GetRustFilename("mnemonics.rs")))) { writer.WriteFileHeader(); writer.WriteLine($"use crate::iced_constants::{icedConstants.Name(idConverter)};"); writer.WriteLine($"use crate::{genTypes[TypeIds.Mnemonic].Name(idConverter)};"); writer.WriteLine(); writer.WriteLine(RustConstants.AttributeNoRustFmt); writer.WriteLine($"pub(super) static TO_MNEMONIC: [{mnemonicName}; {icedConstants.Name(idConverter)}::{icedConstants[IcedConstants.GetEnumCountName(TypeIds.Code)].Name(idConverter)}] = ["); using (writer.Indent()) { foreach (var def in defs) { if (def.Mnemonic.Value > ushort.MaxValue) { throw new InvalidOperationException(); } writer.WriteLine($"{idConverter.ToDeclTypeAndValue(def.Mnemonic)},// {def.Code.Name(idConverter)}"); } } writer.WriteLine("];"); } }
public void Generate() { var icedConstants = genTypes.GetConstantsType(TypeIds.IcedConstants); var defs = genTypes.GetObject <InstructionDefs>(TypeIds.InstructionDefs).Defs; const string ClassName = "InstructionMemorySizes"; var memSizeName = genTypes[TypeIds.MemorySize].Name(idConverter); using (var writer = new FileWriter(TargetLanguage.CSharp, FileUtils.OpenWrite(CSharpConstants.GetFilename(genTypes, CSharpConstants.IcedNamespace, ClassName + ".g.cs")))) { writer.WriteFileHeader(); writer.WriteLine($"namespace {CSharpConstants.IcedNamespace} {{"); using (writer.Indent()) { writer.WriteLine($"static class {ClassName} {{"); using (writer.Indent()) { writer.WriteCommentLine("0 = memory size"); writer.WriteCommentLine("1 = broadcast memory size"); writer.WriteLineNoIndent($"#if {CSharpConstants.HasSpanDefine}"); writer.WriteLine($"internal static System.ReadOnlySpan<byte> Sizes => new byte[{icedConstants.Name(idConverter)}.{icedConstants[IcedConstants.GetEnumCountName(TypeIds.Code)].Name(idConverter)} * 2] {{"); writer.WriteLineNoIndent("#else"); writer.WriteLine($"internal static readonly byte[] Sizes = new byte[{icedConstants.Name(idConverter)}.{icedConstants[IcedConstants.GetEnumCountName(TypeIds.Code)].Name(idConverter)} * 2] {{"); writer.WriteLineNoIndent("#endif"); using (writer.Indent()) { foreach (var def in defs) { if (def.Memory.Value > byte.MaxValue) { throw new InvalidOperationException(); } string value; if (def.Memory.Value == 0) { value = "0"; } else { value = $"(byte){memSizeName}.{def.Memory.Name(idConverter)}"; } writer.WriteLine($"{value},// {def.Code.Name(idConverter)}"); } foreach (var def in defs) { if (def.MemoryBroadcast.Value > byte.MaxValue) { throw new InvalidOperationException(); } string value; if (def.MemoryBroadcast.Value == 0) { value = "0"; } else { value = $"(byte){memSizeName}.{def.MemoryBroadcast.Name(idConverter)}"; } writer.WriteLine($"{value},// {def.Code.Name(idConverter)}"); } } writer.WriteLine("};"); } writer.WriteLine("}"); } writer.WriteLine("}"); } }
public void Generate() { var genTypes = generatorContext.Types; var icedConstants = genTypes.GetConstantsType(TypeIds.IcedConstants); var defs = genTypes.GetObject <InstructionDefs>(TypeIds.InstructionDefs).Defs; var memSizeName = genTypes[TypeIds.MemorySize].Name(idConverter); using (var writer = new FileWriter(TargetLanguage.Rust, FileUtils.OpenWrite(generatorContext.Types.Dirs.GetRustFilename("instruction_memory_sizes.rs")))) { writer.WriteFileHeader(); writer.WriteLine($"use crate::iced_constants::{icedConstants.Name(idConverter)};"); writer.WriteLine($"use crate::{genTypes[TypeIds.MemorySize].Name(idConverter)};"); writer.WriteLine(); writer.WriteLine(RustConstants.AttributeNoRustFmt); writer.WriteLine($"pub(super) static SIZES_NORMAL: [{memSizeName}; {icedConstants.Name(idConverter)}::{icedConstants[IcedConstants.GetEnumCountName(TypeIds.Code)].Name(idConverter)}] = ["); using (writer.Indent()) { foreach (var def in defs) { if (def.Memory.Value > byte.MaxValue) { throw new InvalidOperationException(); } string value = $"{memSizeName}::{def.Memory.Name(idConverter)}"; writer.WriteLine($"{value},// {def.Code.Name(idConverter)}"); } } writer.WriteLine("];"); writer.WriteLine(); writer.WriteLine(RustConstants.AttributeNoRustFmt); writer.WriteLine($"pub(super) static SIZES_BCST: [{memSizeName}; {icedConstants.Name(idConverter)}::{icedConstants[IcedConstants.GetEnumCountName(TypeIds.Code)].Name(idConverter)}] = ["); using (writer.Indent()) { foreach (var def in defs) { if (def.MemoryBroadcast.Value > byte.MaxValue) { throw new InvalidOperationException(); } string value = $"{memSizeName}::{def.MemoryBroadcast.Name(idConverter)}"; writer.WriteLine($"{value},// {def.Code.Name(idConverter)}"); } } writer.WriteLine("];"); } }
public void Generate() { var icedConstants = genTypes.GetConstantsType(TypeIds.IcedConstants); var defs = genTypes.GetObject <InstructionDefs>(TypeIds.InstructionDefs).Defs; const string ClassName = "MnemonicUtilsData"; var mnemonicName = genTypes[TypeIds.Mnemonic].Name(idConverter); using (var writer = new FileWriter(TargetLanguage.CSharp, FileUtils.OpenWrite(CSharpConstants.GetFilename(genTypes, CSharpConstants.IcedNamespace, ClassName + ".g.cs")))) { writer.WriteFileHeader(); writer.WriteLine($"namespace {CSharpConstants.IcedNamespace} {{"); using (writer.Indent()) { writer.WriteLine($"static class {ClassName} {{"); using (writer.Indent()) { writer.WriteLine($"internal static readonly ushort[] toMnemonic = new ushort[{icedConstants.Name(idConverter)}.{icedConstants[IcedConstants.GetEnumCountName(TypeIds.Code)].Name(idConverter)}] {{"); using (writer.Indent()) { foreach (var def in defs) { if (def.Mnemonic.Value > ushort.MaxValue) { throw new InvalidOperationException(); } writer.WriteLine($"(ushort){mnemonicName}.{def.Mnemonic.Name(idConverter)},// {def.Code.Name(idConverter)}"); } } writer.WriteLine("};"); } writer.WriteLine("}"); } writer.WriteLine("}"); } }
void WriteEnumCore(FileWriter writer, PartialEnumFileInfo info, EnumType enumType) { docWriter.WriteSummary(writer, enumType.Documentation, enumType.RawName); var enumTypeName = enumType.Name(idConverter); foreach (var attr in info.Attributes) { writer.WriteLine(attr); } if (enumType.IsPublic && enumType.IsMissingDocs) { writer.WriteLine(RustConstants.AttributeAllowMissingDocs); } if (!enumType.IsPublic) { writer.WriteLine(RustConstants.AttributeAllowDeadCode); } var pub = enumType.IsPublic ? "pub " : "pub(crate) "; writer.WriteLine($"{pub}enum {enumTypeName} {{"); // Identical enum values aren't allowed so just remove them var enumValues = enumType.Values.Where(a => !a.DeprecatedInfo.IsDeprecatedAndRenamed).ToArray(); using (writer.Indent()) { uint expectedValue = 0; foreach (var value in enumValues) { docWriter.WriteSummary(writer, value.Documentation, enumType.RawName); deprecatedWriter.WriteDeprecated(writer, value); if (expectedValue != value.Value || enumType.IsPublic) { writer.WriteLine($"{value.Name(idConverter)} = {value.Value},"); } else { writer.WriteLine($"{value.Name(idConverter)},"); } expectedValue = value.Value + 1; } } writer.WriteLine("}"); var arrayName = idConverter.Constant("GenDebug" + enumType.RawName); var feature = info.Attributes.FirstOrDefault(a => a.StartsWith(RustConstants.FeaturePrefix, StringComparison.Ordinal) && a.Contains("(feature", StringComparison.Ordinal)); if (feature is not null) { writer.WriteLine(feature); } writer.WriteLine(RustConstants.AttributeNoRustFmt); writer.WriteLine($"static {arrayName}: [&str; {enumValues.Length}] = ["); using (writer.Indent()) { foreach (var value in enumValues) { writer.WriteLine($"\"{value.Name(idConverter)}\","); } } writer.WriteLine("];"); // #[derive(Debug)] isn't used since it generates a big switch statement. This code // uses a simple array lookup which has very little code. For small enums the default // implementation might be better though. if (feature is not null) { writer.WriteLine(feature); } writer.WriteLine($"impl fmt::Debug for {enumTypeName} {{"); using (writer.Indent()) { writer.WriteLine(RustConstants.AttributeInline); writer.WriteLine($"fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {{"); using (writer.Indent()) writer.WriteLine($"write!(f, \"{{}}\", {arrayName}[*self as usize])"); writer.WriteLine("}"); } writer.WriteLine("}"); if (feature is not null) { writer.WriteLine(feature); } writer.WriteLine($"impl Default for {enumTypeName} {{"); using (writer.Indent()) { writer.WriteLine(RustConstants.AttributeMustUse); writer.WriteLine(RustConstants.AttributeInline); writer.WriteLine("fn default() -> Self {"); using (writer.Indent()) { var defaultValue = enumValues[0]; // The first one should always have value 0 (eg. "None" field), and if the first one doesn't // have value 0, there must be no other enum fields == 0. if (defaultValue.Value != 0 && enumValues.Any(a => a.Value == 0)) { throw new InvalidOperationException(); } writer.WriteLine($"{enumTypeName}::{defaultValue.Name(idConverter)}"); } writer.WriteLine("}"); } writer.WriteLine("}"); if (enumType.IsPublic) { var enumIterType = $"{enumTypeName}Iterator"; var icedConstValue = "IcedConstants::" + idConverter.Constant(IcedConstants.GetEnumCountName(enumType.TypeId)); var enumUnderlyingType = GetUnderlyingTypeStr(enumType); // Associated method: values() if (feature is not null) { writer.WriteLine(feature); } writer.WriteLine(RustConstants.AttributeNoRustFmt); writer.WriteLine($"impl {enumTypeName} {{"); using (writer.Indent()) { writer.WriteLine($"/// Iterates over all `{enumTypeName}` enum values"); writer.WriteLine("#[inline]"); writer.WriteLine($"pub fn values() -> impl Iterator<Item = {enumTypeName}> + DoubleEndedIterator + ExactSizeIterator + FusedIterator {{"); using (writer.Indent()) { if (enumType.Values.Length == 1) { writer.WriteLine($"static VALUES: [{enumTypeName}; 1] = [{enumTypeName}::{enumType.Values[0].Name(idConverter)}];"); writer.WriteLine($"VALUES.iter().copied()"); } else { writer.WriteLine("// SAFETY: all values 0-max are valid enum values"); writer.WriteLine($"(0..{icedConstValue}).map(|x| unsafe {{ mem::transmute::<{enumUnderlyingType}, {enumTypeName}>(x as {enumUnderlyingType}) }})"); } } writer.WriteLine("}"); } writer.WriteLine("}"); writer.WriteLine("#[test]"); if (feature is not null) { writer.WriteLine(feature); } writer.WriteLine(RustConstants.AttributeNoRustFmt); writer.WriteLine($"fn test_{enumTypeName.ToLowerInvariant()}_values() {{"); using (writer.Indent()) { writer.WriteLine($"let mut iter = {enumTypeName}::values();"); writer.WriteLine($"assert_eq!(iter.size_hint(), ({icedConstValue}, Some({icedConstValue})));"); writer.WriteLine($"assert_eq!(iter.len(), {icedConstValue});"); writer.WriteLine("assert!(iter.next().is_some());"); writer.WriteLine($"assert_eq!(iter.size_hint(), ({icedConstValue} - 1, Some({icedConstValue} - 1)));"); writer.WriteLine($"assert_eq!(iter.len(), {icedConstValue} - 1);"); writer.WriteLine(); writer.WriteLine($"let values: Vec<{enumTypeName}> = {enumTypeName}::values().collect();"); writer.WriteLine($"assert_eq!(values.len(), {icedConstValue});"); writer.WriteLine("for (i, value) in values.into_iter().enumerate() {"); using (writer.Indent()) writer.WriteLine("assert_eq!(i, value as usize);"); writer.WriteLine("}"); writer.WriteLine(); writer.WriteLine($"let values1: Vec<{enumTypeName}> = {enumTypeName}::values().collect();"); writer.WriteLine($"let mut values2: Vec<{enumTypeName}> = {enumTypeName}::values().rev().collect();"); writer.WriteLine("values2.reverse();"); writer.WriteLine("assert_eq!(values1, values2);"); } writer.WriteLine("}"); // impl trait TryFrom var tryFromTypes = new string[] { "usize", //"u32", }; foreach (var tryFromType in tryFromTypes) { var castToFromType = tryFromType == "usize" ? string.Empty : $" as {tryFromType}"; if (feature is not null) { writer.WriteLine(feature); } writer.WriteLine(RustConstants.AttributeNoRustFmt); writer.WriteLine($"impl TryFrom<{tryFromType}> for {enumTypeName} {{"); using (writer.Indent()) { writer.WriteLine("type Error = IcedError;"); writer.WriteLine("#[inline]"); writer.WriteLine($"fn try_from(value: {tryFromType}) -> Result<Self, Self::Error> {{"); using (writer.Indent()) { writer.WriteLine($"if value < {icedConstValue}{castToFromType} {{"); using (writer.Indent()) { if (enumType.Values.Length == 1) { writer.WriteLine($"Ok({enumTypeName}::{enumType.Values[0].Name(idConverter)})"); } else { writer.WriteLine("// SAFETY: all values 0-max are valid enum values"); writer.WriteLine($"Ok(unsafe {{ mem::transmute(value as {enumUnderlyingType}) }})"); } } writer.WriteLine("} else {"); using (writer.Indent()) writer.WriteLine($"Err(IcedError::new(\"Invalid {enumTypeName} value\"))"); writer.WriteLine("}"); } writer.WriteLine("}"); } writer.WriteLine("}"); if (feature is not null) { writer.WriteLine(feature); } writer.WriteLine("#[test]"); writer.WriteLine(RustConstants.AttributeNoRustFmt); writer.WriteLine($"fn test_{enumTypeName.ToLowerInvariant()}_try_from_{tryFromType}() {{"); using (writer.Indent()) { writer.WriteLine($"for value in {enumTypeName}::values() {{"); using (writer.Indent()) { writer.WriteLine($"let converted = <{enumTypeName} as TryFrom<{tryFromType}>>::try_from(value as {tryFromType}).unwrap();"); writer.WriteLine("assert_eq!(converted, value);"); } writer.WriteLine("}"); writer.WriteLine($"assert!(<{enumTypeName} as TryFrom<{tryFromType}>>::try_from({icedConstValue}{castToFromType}).is_err());"); writer.WriteLine($"assert!(<{enumTypeName} as TryFrom<{tryFromType}>>::try_from(core::{tryFromType}::MAX).is_err());"); } writer.WriteLine("}"); } } }
public void Generate() { var icedConstants = genTypes.GetConstantsType(TypeIds.IcedConstants); var defs = genTypes.GetObject <InstructionDefs>(TypeIds.InstructionDefs).Defs; const string ClassName = "InstructionOpCounts"; using (var writer = new FileWriter(TargetLanguage.CSharp, FileUtils.OpenWrite(CSharpConstants.GetFilename(genTypes, CSharpConstants.IcedNamespace, ClassName + ".g.cs")))) { writer.WriteFileHeader(); writer.WriteLine($"namespace {CSharpConstants.IcedNamespace} {{"); using (writer.Indent()) { writer.WriteLine($"static class {ClassName} {{"); using (writer.Indent()) { writer.WriteLineNoIndent($"#if {CSharpConstants.HasSpanDefine}"); writer.WriteLine($"internal static System.ReadOnlySpan<byte> OpCount => new byte[{icedConstants.Name(idConverter)}.{icedConstants[IcedConstants.GetEnumCountName(TypeIds.Code)].Name(idConverter)}] {{"); writer.WriteLineNoIndent("#else"); writer.WriteLine($"internal static readonly byte[] OpCount = new byte[{icedConstants.Name(idConverter)}.{icedConstants[IcedConstants.GetEnumCountName(TypeIds.Code)].Name(idConverter)}] {{"); writer.WriteLineNoIndent("#endif"); using (writer.Indent()) { foreach (var def in defs) { writer.WriteLine($"{def.OpCount},// {def.Code.Name(idConverter)}"); } } writer.WriteLine("};"); } writer.WriteLine("}"); } writer.WriteLine("}"); } }
protected void TestInstructionInfo(int bitness, string hexBytes, Code code, DecoderOptions options, int lineNo, InstructionInfoTestCase testCase) { var codeBytes = HexUtils.ToByteArray(hexBytes); Instruction instruction; if (testCase.IsSpecial) { if (bitness == 16 && code == Code.Popw_CS && hexBytes == "0F") { instruction = default; instruction.Code = Code.Popw_CS; instruction.Op0Kind = OpKind.Register; instruction.Op0Register = Register.CS; instruction.CodeSize = CodeSize.Code16; instruction.Length = 1; } else if (code <= Code.DeclareQword) { instruction = default; instruction.Code = code; instruction.DeclareDataCount = 1; Assert.Equal(64, bitness); instruction.CodeSize = CodeSize.Code64; switch (code) { case Code.DeclareByte: Assert.Equal("66", hexBytes); instruction.SetDeclareByteValue(0, 0x66); break; case Code.DeclareWord: Assert.Equal("6644", hexBytes); instruction.SetDeclareWordValue(0, 0x4466); break; case Code.DeclareDword: Assert.Equal("664422EE", hexBytes); instruction.SetDeclareDwordValue(0, 0xEE224466); break; case Code.DeclareQword: Assert.Equal("664422EE12345678", hexBytes); instruction.SetDeclareQwordValue(0, 0x78563412EE224466); break; default: throw new InvalidOperationException(); } } else if (code == Code.Zero_bytes) { instruction = default; instruction.Code = code; Assert.Equal(64, bitness); instruction.CodeSize = CodeSize.Code64; Assert.Equal("", hexBytes); } else { var decoder = CreateDecoder(bitness, codeBytes, testCase.IP, options); instruction = decoder.Decode(); if (codeBytes.Length > 1 && codeBytes[0] == 0x9B && instruction.Length == 1) { instruction = decoder.Decode(); instruction.Code = instruction.Code switch { Code.Fnstenv_m14byte => Code.Fstenv_m14byte, Code.Fnstenv_m28byte => Code.Fstenv_m28byte, Code.Fnstcw_m2byte => Code.Fstcw_m2byte, Code.Fneni => Code.Feni, Code.Fndisi => Code.Fdisi, Code.Fnclex => Code.Fclex, Code.Fninit => Code.Finit, Code.Fnsetpm => Code.Fsetpm, Code.Fnsave_m94byte => Code.Fsave_m94byte, Code.Fnsave_m108byte => Code.Fsave_m108byte, Code.Fnstsw_m2byte => Code.Fstsw_m2byte, Code.Fnstsw_AX => Code.Fstsw_AX, Code.Fnstdw_AX => Code.Fstdw_AX, Code.Fnstsg_AX => Code.Fstsg_AX, _ => throw new InvalidOperationException(), }; } else { throw new InvalidOperationException(); } } } else { var decoder = CreateDecoder(bitness, codeBytes, testCase.IP, options); instruction = decoder.Decode(); } Assert.Equal(code, instruction.Code); Assert.Equal(testCase.StackPointerIncrement, instruction.StackPointerIncrement); var info = new InstructionInfoFactory().GetInfo(instruction); Assert.Equal(testCase.Op0Access, info.Op0Access); Assert.Equal(testCase.Op1Access, info.Op1Access); Assert.Equal(testCase.Op2Access, info.Op2Access); Assert.Equal(testCase.Op3Access, info.Op3Access); Assert.Equal(testCase.Op4Access, info.Op4Access); var fpuInfo = instruction.GetFpuStackIncrementInfo(); Assert.Equal(testCase.FpuTopIncrement, fpuInfo.Increment); Assert.Equal(testCase.FpuConditionalTop, fpuInfo.Conditional); Assert.Equal(testCase.FpuWritesTop, fpuInfo.WritesTop); Assert.Equal( new HashSet <UsedMemory>(testCase.UsedMemory, UsedMemoryEqualityComparer.Instance), new HashSet <UsedMemory>(info.GetUsedMemory(), UsedMemoryEqualityComparer.Instance)); Assert.Equal( new HashSet <UsedRegister>(GetUsedRegisters(testCase.UsedRegisters), UsedRegisterEqualityComparer.Instance), new HashSet <UsedRegister>(GetUsedRegisters(info.GetUsedRegisters()), UsedRegisterEqualityComparer.Instance)); Static.Assert(IcedConstants.MaxOpCount == 5 ? 0 : -1); Debug.Assert(instruction.OpCount <= IcedConstants.MaxOpCount); for (int i = 0; i < instruction.OpCount; i++) { switch (i) { case 0: Assert.Equal(testCase.Op0Access, info.GetOpAccess(i)); break; case 1: Assert.Equal(testCase.Op1Access, info.GetOpAccess(i)); break; case 2: Assert.Equal(testCase.Op2Access, info.GetOpAccess(i)); break; case 3: Assert.Equal(testCase.Op3Access, info.GetOpAccess(i)); break; case 4: Assert.Equal(testCase.Op4Access, info.GetOpAccess(i)); break; default: throw new InvalidOperationException(); } } for (int i = instruction.OpCount; i < IcedConstants.MaxOpCount; i++) { Assert.Equal(OpAccess.None, info.GetOpAccess(i)); } var info2 = new InstructionInfoFactory().GetInfo(instruction, InstructionInfoOptions.None); CheckEqual(ref info, ref info2, hasRegs2: true, hasMem2: true); info2 = new InstructionInfoFactory().GetInfo(instruction, InstructionInfoOptions.NoMemoryUsage); CheckEqual(ref info, ref info2, hasRegs2: true, hasMem2: false); info2 = new InstructionInfoFactory().GetInfo(instruction, InstructionInfoOptions.NoRegisterUsage); CheckEqual(ref info, ref info2, hasRegs2: false, hasMem2: true); info2 = new InstructionInfoFactory().GetInfo(instruction, InstructionInfoOptions.NoRegisterUsage | InstructionInfoOptions.NoMemoryUsage); CheckEqual(ref info, ref info2, hasRegs2: false, hasMem2: false); Assert.Equal(testCase.Encoding, instruction.Code.Encoding()); #if ENCODER && OPCODE_INFO Assert.Equal(code.ToOpCode().Encoding, testCase.Encoding); #endif Assert.Equal(testCase.CpuidFeatures, instruction.Code.CpuidFeatures()); Assert.Equal(testCase.FlowControl, instruction.Code.FlowControl()); Assert.Equal(testCase.IsPrivileged, instruction.Code.IsPrivileged()); Assert.Equal(testCase.IsStackInstruction, instruction.Code.IsStackInstruction()); Assert.Equal(testCase.IsSaveRestoreInstruction, instruction.Code.IsSaveRestoreInstruction()); Assert.Equal(testCase.Encoding, instruction.Encoding); #if MVEX if (instruction.Encoding == EncodingKind.MVEX) { Assert.True(IcedConstants.IsMvex(instruction.Code)); } else { Assert.False(IcedConstants.IsMvex(instruction.Code)); } #endif Assert.Equal(testCase.CpuidFeatures, instruction.CpuidFeatures); Assert.Equal(testCase.FlowControl, instruction.FlowControl); Assert.Equal(testCase.IsPrivileged, instruction.IsPrivileged); Assert.Equal(testCase.IsStackInstruction, instruction.IsStackInstruction); Assert.Equal(testCase.IsSaveRestoreInstruction, instruction.IsSaveRestoreInstruction); Assert.Equal(testCase.RflagsRead, instruction.RflagsRead); Assert.Equal(testCase.RflagsWritten, instruction.RflagsWritten); Assert.Equal(testCase.RflagsCleared, instruction.RflagsCleared); Assert.Equal(testCase.RflagsSet, instruction.RflagsSet); Assert.Equal(testCase.RflagsUndefined, instruction.RflagsUndefined); Assert.Equal(testCase.RflagsWritten | testCase.RflagsCleared | testCase.RflagsSet | testCase.RflagsUndefined, instruction.RflagsModified); Assert.Equal(RflagsBits.None, instruction.RflagsWritten & (instruction.RflagsCleared | instruction.RflagsSet | instruction.RflagsUndefined)); Assert.Equal(RflagsBits.None, instruction.RflagsCleared & (instruction.RflagsWritten | instruction.RflagsSet | instruction.RflagsUndefined)); Assert.Equal(RflagsBits.None, instruction.RflagsSet & (instruction.RflagsWritten | instruction.RflagsCleared | instruction.RflagsUndefined)); Assert.Equal(RflagsBits.None, instruction.RflagsUndefined & (instruction.RflagsWritten | instruction.RflagsCleared | instruction.RflagsSet)); }
public void Generate() { var genTypes = generatorContext.Types; var icedConstants = genTypes.GetConstantsType(TypeIds.IcedConstants); var defs = genTypes.GetObject <InstructionDefs>(TypeIds.InstructionDefs).Defs; using (var writer = new FileWriter(TargetLanguage.Rust, FileUtils.OpenWrite(generatorContext.Types.Dirs.GetRustFilename("instruction_op_counts.rs")))) { writer.WriteFileHeader(); writer.WriteLine($"use super::iced_constants::{icedConstants.Name(idConverter)};"); writer.WriteLine(); writer.WriteLine(RustConstants.AttributeNoRustFmt); writer.WriteLine($"pub(super) static OP_COUNT: [u8; {icedConstants.Name(idConverter)}::{icedConstants[IcedConstants.GetEnumCountName(TypeIds.Code)].Name(idConverter)}] = ["); using (writer.Indent()) { foreach (var def in defs) { writer.WriteLine($"{def.OpCount},// {def.Code.Name(idConverter)}"); } } writer.WriteLine("];"); } }