mirror of
https://github.com/Dongyifengs/AssetStudio-Genshin-MoYi.git
synced 2025-04-22 20:49:18 +08:00
222 lines
5.3 KiB
C#
222 lines
5.3 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Text;
|
|
|
|
namespace SpirV
|
|
{
|
|
public struct ModuleHeader
|
|
{
|
|
public Version Version { get; set; }
|
|
public string GeneratorVendor { get; set; }
|
|
public string GeneratorName { get; set; }
|
|
public int GeneratorVersion { get; set; }
|
|
public uint Bound { get; set; }
|
|
public uint Reserved { get; set; }
|
|
}
|
|
|
|
[Flags]
|
|
public enum DisassemblyOptions
|
|
{
|
|
None,
|
|
ShowTypes,
|
|
ShowNames,
|
|
Default = ShowTypes | ShowNames
|
|
}
|
|
|
|
public class Disassembler
|
|
{
|
|
public string Disassemble (Module module)
|
|
{
|
|
return Disassemble(module, DisassemblyOptions.Default);
|
|
}
|
|
|
|
public string Disassemble(Module module, DisassemblyOptions options)
|
|
{
|
|
m_sb.AppendLine("; SPIR-V");
|
|
m_sb.Append("; Version: ").Append(module.Header.Version).AppendLine();
|
|
if (module.Header.GeneratorName == null)
|
|
{
|
|
m_sb.Append("; Generator: unknown; ").Append(module.Header.GeneratorVersion).AppendLine();
|
|
}
|
|
else
|
|
{
|
|
m_sb.Append("; Generator: ").Append(module.Header.GeneratorVendor).Append(' ').
|
|
Append(module.Header.GeneratorName).Append("; ").Append(module.Header.GeneratorVersion).AppendLine();
|
|
}
|
|
m_sb.Append("; Bound: ").Append(module.Header.Bound).AppendLine();
|
|
m_sb.Append("; Schema: ").Append(module.Header.Reserved).AppendLine();
|
|
|
|
string[] lines = new string[module.Instructions.Count + 1];
|
|
lines[0] = m_sb.ToString();
|
|
m_sb.Clear();
|
|
|
|
for (int i = 0; i < module.Instructions.Count; i++)
|
|
{
|
|
ParsedInstruction instruction = module.Instructions[i];
|
|
PrintInstruction(m_sb, instruction, options);
|
|
lines[i + 1] = m_sb.ToString();
|
|
m_sb.Clear();
|
|
}
|
|
|
|
int longestPrefix = 0;
|
|
for (int i = 0; i < lines.Length; i++)
|
|
{
|
|
string line = lines[i];
|
|
longestPrefix = Math.Max(longestPrefix, line.IndexOf('='));
|
|
if (longestPrefix > 50)
|
|
{
|
|
longestPrefix = 50;
|
|
break;
|
|
}
|
|
}
|
|
|
|
m_sb.Append(lines[0]);
|
|
for (int i = 1; i < lines.Length; i++)
|
|
{
|
|
string line = lines[i];
|
|
int index = line.IndexOf('=');
|
|
if (index == -1)
|
|
{
|
|
m_sb.Append(' ', longestPrefix + 4);
|
|
m_sb.Append(line);
|
|
}
|
|
else
|
|
{
|
|
int pad = Math.Max(0, longestPrefix - index);
|
|
m_sb.Append(' ', pad);
|
|
m_sb.Append(line, 0, index);
|
|
m_sb.Append('=');
|
|
m_sb.Append(line, index + 1, line.Length - index - 1);
|
|
}
|
|
m_sb.AppendLine();
|
|
}
|
|
|
|
string result = m_sb.ToString();
|
|
m_sb.Clear();
|
|
return result;
|
|
}
|
|
|
|
private static void PrintInstruction(StringBuilder sb, ParsedInstruction instruction, DisassemblyOptions options)
|
|
{
|
|
if (instruction.Operands.Count == 0)
|
|
{
|
|
sb.Append(instruction.Instruction.Name);
|
|
return;
|
|
}
|
|
|
|
int currentOperand = 0;
|
|
if (instruction.Instruction.Operands[currentOperand].Type is IdResultType)
|
|
{
|
|
if (options.HasFlag(DisassemblyOptions.ShowTypes))
|
|
{
|
|
instruction.ResultType.ToString(sb).Append(' ');
|
|
}
|
|
++currentOperand;
|
|
}
|
|
|
|
if (currentOperand < instruction.Operands.Count && instruction.Instruction.Operands[currentOperand].Type is IdResult)
|
|
{
|
|
if (!options.HasFlag(DisassemblyOptions.ShowNames) || string.IsNullOrWhiteSpace(instruction.Name))
|
|
{
|
|
PrintOperandValue(sb, instruction.Operands[currentOperand].Value, options);
|
|
}
|
|
else
|
|
{
|
|
sb.Append(instruction.Name);
|
|
}
|
|
sb.Append(" = ");
|
|
|
|
++currentOperand;
|
|
}
|
|
|
|
sb.Append(instruction.Instruction.Name);
|
|
sb.Append(' ');
|
|
|
|
for (; currentOperand < instruction.Operands.Count; ++currentOperand)
|
|
{
|
|
PrintOperandValue(sb, instruction.Operands[currentOperand].Value, options);
|
|
sb.Append(' ');
|
|
}
|
|
}
|
|
|
|
private static void PrintOperandValue(StringBuilder sb, object value, DisassemblyOptions options)
|
|
{
|
|
switch (value)
|
|
{
|
|
case System.Type t:
|
|
sb.Append(t.Name);
|
|
break;
|
|
|
|
case string s:
|
|
{
|
|
sb.Append('"');
|
|
sb.Append(s);
|
|
sb.Append('"');
|
|
}
|
|
break;
|
|
|
|
case ObjectReference or:
|
|
{
|
|
if (options.HasFlag(DisassemblyOptions.ShowNames) && or.Reference != null && !string.IsNullOrWhiteSpace(or.Reference.Name))
|
|
{
|
|
sb.Append(or.Reference.Name);
|
|
}
|
|
else
|
|
{
|
|
or.ToString(sb);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case IBitEnumOperandValue beov:
|
|
PrintBitEnumValue(sb, beov, options);
|
|
break;
|
|
|
|
case IValueEnumOperandValue veov:
|
|
PrintValueEnumValue(sb, veov, options);
|
|
break;
|
|
|
|
case VaryingOperandValue varOpVal:
|
|
varOpVal.ToString(sb);
|
|
break;
|
|
|
|
default:
|
|
sb.Append(value);
|
|
break;
|
|
}
|
|
}
|
|
|
|
private static void PrintBitEnumValue(StringBuilder sb, IBitEnumOperandValue enumOperandValue, DisassemblyOptions options)
|
|
{
|
|
foreach (uint key in enumOperandValue.Values.Keys)
|
|
{
|
|
sb.Append(enumOperandValue.EnumerationType.GetEnumName(key));
|
|
IReadOnlyList<object> value = enumOperandValue.Values[key];
|
|
if (value.Count != 0)
|
|
{
|
|
sb.Append(' ');
|
|
foreach (object v in value)
|
|
{
|
|
PrintOperandValue(sb, v, options);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private static void PrintValueEnumValue(StringBuilder sb, IValueEnumOperandValue valueOperandValue, DisassemblyOptions options)
|
|
{
|
|
sb.Append(valueOperandValue.Key);
|
|
if (valueOperandValue.Value is IList<object> valueList && valueList.Count > 0)
|
|
{
|
|
sb.Append(' ');
|
|
foreach (object v in valueList)
|
|
{
|
|
PrintOperandValue(sb, v, options);
|
|
}
|
|
}
|
|
}
|
|
|
|
private readonly StringBuilder m_sb = new StringBuilder();
|
|
}
|
|
}
|