123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382 |
- using System;
- using System.Collections;
- using System.Collections.Generic;
- using System.IO;
- using System.Linq;
- using System.Text;
- using System.Reflection;
- using NUnit.Framework;
- using UnityEngine;
- using UnityEngine.TestTools;
- using Unity.Burst;
- using Unity.Burst.Editor;
- using UnityEditorInternal;
- using System.Runtime.CompilerServices;
-
- public class BurstDisassemblerTests
- {
- private BurstDisassembler _disassembler;
-
- [OneTimeSetUp]
- public void SetUp()
- {
- _disassembler = new BurstDisassembler();
- }
-
- private static string GetThisFilePath([CallerFilePath] string path = null) => path;
-
- // A Test behaves as an ordinary method
- [Test]
- public void GetBlockIdxFromTextIdxTest()
- {
- var thisPath = Path.GetDirectoryName(GetThisFilePath());
-
- Assert.IsTrue(_disassembler.Initialize(
- File.ReadAllText(Path.Combine(thisPath, "burstTestTarget.txt")),
- BurstDisassembler.AsmKind.Intel,
- false,
- false));
-
- for (int blockIdx = 0; blockIdx < _disassembler.Blocks.Count; blockIdx++)
- {
- int blockStart = 0;
- for (int i = 0; i < blockIdx; i++)
- {
- blockStart += _disassembler.GetOrRenderBlockToText(i).Length;
- }
-
- var blockStr = _disassembler.GetOrRenderBlockToText(blockIdx);
-
- Assert.AreEqual((blockIdx, blockStart),
- _disassembler.GetBlockIdxFromTextIdx(blockStart + 1),
- $"Block index was wrong for block with label {blockStr.Substring(0, blockStr.IndexOf('\n'))}");
- }
- }
-
- [Test]
- public void InstantiateRegistersUsedTest()
- {
- Assert.IsTrue(_disassembler.Initialize(simpleAssembly, BurstDisassembler.AsmKind.Intel));
-
- var regsUsed = _disassembler._registersUsedAtLine;
-
- // Match against expected:
- var expectedLines = from l in expected select l.lineNr;
-
- var failed = expectedLines.Except(regsUsed._linesRegisters.Keys);
- failed = failed.Concat(regsUsed._linesRegisters.Keys.Except(expectedLines)).Distinct();
- if (failed.Any())
- {
- // Not exact match
- foreach (var f in failed)
- {
- Debug.Log($"lineNumber {f} failed");
- }
- Assert.Fail();
- }
- }
-
- [Test]
- public void CleanRegisterListTest()
- {
- Assert.IsTrue(_disassembler.Initialize(simpleAssembly, BurstDisassembler.AsmKind.Intel));
-
- var regs = new List<string> { "rcx", "ecx", "rax" };
- var output = _disassembler._registersUsedAtLine.CleanRegs(regs);
-
- var expected = new List<string> { "rcx", "rax" };
- Assert.AreEqual(output, expected);
- }
-
- [Test]
- public void IndexOfRegisterTest()
- {
- var assembly =
- "\n" +
- " nop\n" +
- " movsxd rcx, cx\n" +
- " mov rax, qword ptr [rbp - 16]";
- Assert.IsTrue(_disassembler.Initialize(assembly, BurstDisassembler.AsmKind.Intel));
-
- string[,] regs =
- {
- { "rcx", "cx" },
- { "rax", "rbp" }
- };
- string[] lines =
- {
- " movsxd rcx, cx\n",
- " mov rax, qword ptr [rbp - 16]"
- };
- for (var i = 0; i < 2; i++)
- {
- var line = lines[i];
-
- var reg = regs[i, 0];
- var asmLine = _disassembler.Lines[i+1];
- var output = _disassembler.GetRegisterTokenIndex(asmLine, reg);
- var regIdx = _disassembler.Tokens[output].AlignedPosition - _disassembler.Tokens[asmLine.TokenIndex].AlignedPosition;
-
- var expected = line.IndexOf(reg) + 1;
- Assert.AreEqual(expected, regIdx, $"Failed for line \"{line}\"");
-
- reg = regs[i, 1];
- output = _disassembler.GetRegisterTokenIndex(asmLine, reg, output + 1);
- regIdx = _disassembler.Tokens[output].AlignedPosition - _disassembler.Tokens[asmLine.TokenIndex].AlignedPosition;
-
- expected = line.IndexOf(reg, expected + 1) + 1;
- Assert.AreEqual(expected, regIdx, $"Failed for line \"{line}\"");
- }
- }
-
- [Test]
- [TestCase("x86", new [] {"rdx","edx","dx","dl"}, "dl")]
- [TestCase("arm", new [] {"wsp", "sp"},"sp")]
- [TestCase("arm", new [] {"v0.2d", "s0", "q0", "h0", "d0", "b0"}, "b0")]
- [TestCase("arm", new [] {"w0","x0"}, "x0")]
- public void RegisterEqualityTest(string assemblyName, string[] assemblyLine, string register)
- {
- BurstDisassembler.AsmTokenKindProvider tokenProvider = BurstDisassembler.ARM64AsmTokenKindProvider.Instance;
- if (assemblyName == "x86")
- {
- tokenProvider = BurstDisassembler.X86AsmTokenKindProvider.Instance;
- }
-
- foreach (var reg in assemblyLine)
- {
- Assert.IsTrue(tokenProvider.RegisterEqual(reg, register), $"{reg} == {register}");
- }
-
- // Some special cases:
- tokenProvider = BurstDisassembler.ARM64AsmTokenKindProvider.Instance;
-
- Assert.IsFalse(tokenProvider.RegisterEqual("w8", "x0"), $"w8 != x0");
- Assert.IsFalse(tokenProvider.RegisterEqual("w0", "q0"), "w0 != q0");
- Assert.IsFalse(tokenProvider.RegisterEqual("x0", "q0"), "x0 != q0");
- }
-
- [Test]
- public void RegisterEqualTest()
- {
- // Only tests for x86, as the others are trivial.
- Assert.IsTrue(_disassembler.Initialize(simpleAssembly, BurstDisassembler.AsmKind.Intel));
-
- // Get all register strings:
- var tokenProvider = BurstDisassembler.X86AsmTokenKindProvider.Instance;
- var tokenProviderT = typeof(BurstDisassembler.AsmTokenKindProvider);
-
- var field = tokenProviderT.GetField("_tokenKinds",
- BindingFlags.Instance | BindingFlags.NonPublic);
-
- Assert.NotNull(field, "Could not find _tokenKinds field in AsmTokenKindProvider");
-
- var allTokens = (Dictionary<StringSlice, BurstDisassembler.AsmTokenKind>)field.GetValue(tokenProvider);
-
- var tokensToTest =
- from tok in allTokens.Keys
- where allTokens.TryGetValue(tok, out var kind)
- && kind == BurstDisassembler.AsmTokenKind.Register
- select tok.ToString();
-
- // Test that equality works for all registers:
- try
- {
- foreach (var reg in tokensToTest)
- {
- // Simply check whether all registers are processable:
- tokenProvider.RegisterEqual(reg, "rax");
- }
- }
- catch (Exception e)
- {
- Assert.Fail($"Not all registers works for register equality (x86). {e}");
- }
- }
-
- [Test]
- public void InstructionAlignmentTest()
- {
- var assembly =
- "\n" + // newline as BurstDisassembler ignores first line
- " push rbp\n" +
- " .seh_pushreg rbp\n" +
- " sub rsp, 32\n";
- (int, char)[] expectedPositions =
- {
- (1,' '), (10, 'p'), (14, ' '), (24, 'r'), (27, '\n'),
- (28, ' '), (37, '.'), (49, ' '), (50, 'r'), (53, '\n'),
- (54, ' '), (63, 's'), (66, ' '), (77, 'r'), (80, ','), (82, '3'), (84, '\n')
- };
-
- Assert.IsTrue(_disassembler.Initialize(assembly, BurstDisassembler.AsmKind.Intel));
-
- var builder = new StringBuilder();
- for (int i = 0; i < _disassembler.Blocks.Count; i++)
- {
- var text = _disassembler.GetOrRenderBlockToTextUncached(i, false);
- builder.Append(text);
- }
-
- var output = builder.ToString();
-
- for (var i = 0; i < expectedPositions.Length; i++)
- {
- Assert.AreEqual(expectedPositions[i].Item1, _disassembler.Tokens[i].AlignedPosition);
- }
-
- foreach (var (idx, c) in expectedPositions)
- {
- // -1 as token index for some reason aren't zero indexed.
- Assert.AreEqual(c, output[idx-1], $"Token position for index {idx} was wrong.");
- }
- }
-
- [Test]
- public void X86AsmTokenProviderSimdKindTest()
- {
- var tp = BurstDisassembler.X86AsmTokenKindProvider.Instance;
- BurstDisassembler.SIMDkind actual = tp.SimdKind(new StringSlice("vsqrtsd"));
- var expected = BurstDisassembler.SIMDkind.Scalar;
-
- Assert.AreEqual(expected, actual);
-
- actual = tp.SimdKind(new StringSlice("vroundpd"));
- expected = BurstDisassembler.SIMDkind.Packed;
- Assert.AreEqual(expected, actual);
-
- actual = tp.SimdKind(new StringSlice("xsaves"));
- expected = BurstDisassembler.SIMDkind.Infrastructure;
- Assert.AreEqual(expected,actual);
- }
-
- [Test]
- public void ARMAsmTokenProviderSimdKindTest()
- {
- var tp = BurstDisassembler.ARM64AsmTokenKindProvider.Instance;
-
- BurstDisassembler.SIMDkind actual = tp.SimdKind(new StringSlice("vaddw"));
- var expected = BurstDisassembler.SIMDkind.Scalar;
- Assert.AreEqual(expected, actual);
-
- actual = tp.SimdKind(new StringSlice("vadd.i8"));
- expected = BurstDisassembler.SIMDkind.Packed;
- Assert.AreEqual(expected, actual);
- }
-
- private string GetFirstColorTag(string line)
- {
- const string colorTag = "#XXXXXX";
- const string tag = "<color=";
- int idx = line.IndexOf('<');
- return line.Substring(idx + tag.Length, colorTag.Length);
- }
-
- private const string ARMsimdAssembly =
- "\n" +
- " ldr r0, [sp, #12]\n" +
- " vldr s0, [sp, #20]\n" +
- " vstr s0, [sp, #4]\n" +
- " ldr r1, [sp, #24]\n" +
- " vldr s0, [sp, #4]\n" +
- " vmov s2, r0\n" +
- " vadd.f32 s0, s0, s2\n" +
- " vstr s0, [sp, #20]";
-
- private const string X86SimdAssembly =
- "\n" +
- " mov rcx, qword ptr [rbp - 32]\n" +
- " vmovss xmm0, dword ptr [rbp - 12]\n" +
- " vmovss dword ptr [rbp - 40], xmm0\n" +
- " mov edx, dword ptr [rbp - 8]\n" +
- " call \"Unity.Collections.NativeArray`1<float>.get_Item(Unity.Collections.NativeArray`1<float>* this, int index) -> float_c303f72c9cc472e2ef84a442ead69ef2 from Unity.Burst.Editor.Tests, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null\"\n" +
- " vmovaps xmm1, xmm0\n" +
- " vmovss xmm0, dword ptr [rbp - 40]\n" +
- " vaddss xmm0, xmm0, xmm1\n" +
- " vmovss dword ptr [rbp - 12], xmm0\n" +
- " vzeroall";
- [Test]
- [TestCase(X86SimdAssembly, 0, BurstDisassembler.DarkColorInstructionSIMDScalar, 1)]
- [TestCase(X86SimdAssembly, 0, BurstDisassembler.DarkColorInstructionSIMDPacked, 5)]
- [TestCase(X86SimdAssembly, 0, BurstDisassembler.DarkColorInstructionSIMD, 9)]
- [TestCase(ARMsimdAssembly, 1, BurstDisassembler.DarkColorInstructionSIMDScalar, 1)]
- [TestCase(ARMsimdAssembly, 1, BurstDisassembler.DarkColorInstructionSIMDPacked, 6)]
- public void AssemblyColouringSmellTest(string asm, int asmkind, string colorTag, int lineIdx)
- {
- _disassembler.Initialize(asm, (BurstDisassembler.AsmKind)asmkind, true, true, true);
- var line = _disassembler.Lines[lineIdx];
- _disassembler._output.Clear();
- _disassembler.RenderLine(ref line, true);
- var lineString = _disassembler._output.ToString();
-
- _disassembler._output.Clear();
- Assert.AreEqual(colorTag, GetFirstColorTag(lineString));
- }
-
- private List<(int lineNr, List<string>)> expected = new List<(int lineNr, List<string>)>
- {
- (2, new List<string> { "rbp" }),
- (3, new List<string> { "rbp" }),
- (4, new List<string> { "rsp" }),
- (6, new List<string> { "rbp", "rsp" }),
- (7, new List<string> { "rbp" }),
- (11, new List<string> { "rsp" }),
- (12, new List<string> { "rbp" }),
- (26, new List<string> { "rbp" }),
- (27, new List<string> { "rbp" }),
- (28, new List<string> { "rsp" }),
- (30, new List<string> { "rbp", "rsp" }),
- (31, new List<string> { "rbp" }),
- (36, new List<string> { "rsp" }),
- (37, new List<string> { "rbp" }),
- };
- private string simpleAssembly =
- "\n" + // newline as BurstDisassembler ignores first line
- ".Lfunc_begin0:\n" +
- ".seh_proc 589a9d678dbb1201e550a054238fad11\n" +
- " push rbp\n" +
- " .seh_pushreg rbp\n" +
- " sub rsp, 32\n" +
- " .seh_stackalloc 32\n" +
- " lea rbp, [rsp + 32]\n" +
- " .seh_setframe rbp, 32\n" +
- " .seh_endprologue\n" +
- " call A.B.DoIt\n" +
- " nop\n" +
- " add rsp, 32\n" +
- " pop rbp\n" +
- " ret\n" +
- " .Lfunc_end0:\n" +
- " .seh_endproc\n" +
- " \n" +
- " .def burst.initialize;\n" +
- " .scl 2;\n" +
- " .type 32;\n" +
- " .endef\n" +
- " .globl burst.initialize\n" +
- " .p2align 4, 0x90\n" +
- " burst.initialize:\n" +
- " .Lfunc_begin1:\n" +
- " .seh_proc burst.initialize\n" +
- " push rbp\n" +
- " .seh_pushreg rbp\n" +
- " sub rsp, 32\n" +
- " .seh_stackalloc 32\n" +
- " lea rbp, [rsp + 32]\n" +
- " .seh_setframe rbp, 32\n" +
- " .seh_endprologue\n" +
- " call burst.initialize.externals\n" +
- " call burst.initialize.statics\n" +
- " nop\n" +
- " add rsp, 32\n" +
- " pop rbp\n" +
- " ret\n" +
- " .Lfunc_end1:\n" +
- " .seh_endproc\n" +
- " \n" +
- " .def burst.initialize.externals;\n" +
- " .scl 2;\n" +
- " .type 32;\n" +
- " .endef\n" +
- " .globl burst.initialize.externals\n" +
- " .p2align 4, 0x90";
- }
|