initial commit
This commit is contained in:
parent
6715289efe
commit
788c3389af
37645 changed files with 2526849 additions and 80 deletions
|
|
@ -0,0 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: a2b1c4300b7e37aea22a3646af54828f
|
||||
folderAsset: yes
|
||||
|
|
@ -0,0 +1,189 @@
|
|||
using System;
|
||||
using System.Text;
|
||||
using System.Reflection;
|
||||
using System.Linq;
|
||||
using System.Collections.Generic;
|
||||
using NUnit.Framework;
|
||||
using Unity.Burst.Editor;
|
||||
using UnityEngine;
|
||||
using Unity.Burst;
|
||||
using Random = System.Random;
|
||||
|
||||
[TestFixture]
|
||||
public class BurstDisassemblerCoreInstructionTests
|
||||
{
|
||||
// Use chooser enum instead of BurstDisassembler.AsmKind because of accessibility level.
|
||||
public enum Chooser
|
||||
{
|
||||
ARM,
|
||||
INTEL,
|
||||
LLVMIR,
|
||||
Wasm
|
||||
}
|
||||
|
||||
[Test]
|
||||
[TestCase(Chooser.ARM)]
|
||||
[TestCase(Chooser.INTEL)]
|
||||
// [TestCase(Chooser.LLVMIR)]
|
||||
[TestCase(Chooser.Wasm)]
|
||||
public void TestInfo(Chooser provider)
|
||||
{
|
||||
BurstDisassembler.AsmTokenKindProvider tokenProvider;
|
||||
switch (provider)
|
||||
{
|
||||
case Chooser.ARM:
|
||||
tokenProvider = BurstDisassembler.ARM64AsmTokenKindProvider.Instance;
|
||||
break;
|
||||
case Chooser.INTEL:
|
||||
tokenProvider = BurstDisassembler.X86AsmTokenKindProvider.Instance;
|
||||
break;
|
||||
case Chooser.Wasm:
|
||||
tokenProvider = BurstDisassembler.WasmAsmTokenKindProvider.Instance;
|
||||
break;
|
||||
default:
|
||||
throw new Exception("Oops you forgot to add a switch case in the test *quirky smiley*.");
|
||||
}
|
||||
|
||||
|
||||
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.Qualifier
|
||||
&& kind != BurstDisassembler.AsmTokenKind.Register
|
||||
select tok.ToString();
|
||||
|
||||
var count = 0;
|
||||
foreach (var token in tokensToTest)
|
||||
{
|
||||
var res = false;
|
||||
switch (provider)
|
||||
{
|
||||
case Chooser.ARM:
|
||||
res = BurstDisassembler.ARM64InstructionInfo.GetARM64Info(token, out var _);
|
||||
break;
|
||||
case Chooser.INTEL:
|
||||
res = BurstDisassembler.X86AsmInstructionInfo.GetX86InstructionInfo(token, out var _);
|
||||
break;
|
||||
case Chooser.LLVMIR:
|
||||
res = BurstDisassembler.LLVMIRInstructionInfo.GetLLVMIRInfo(token, out var _);
|
||||
break;
|
||||
case Chooser.Wasm:
|
||||
res = BurstDisassembler.WasmInstructionInfo.GetWasmInfo(token, out var _);
|
||||
break;
|
||||
}
|
||||
|
||||
if (!res)
|
||||
{
|
||||
Debug.Log($"Token \"{token}\" from {provider} does not have information associated.");
|
||||
count++;
|
||||
}
|
||||
}
|
||||
Assert.Zero(count, $"{provider.ToString()} is missing information for {count} token(s).");
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Tests whether all instructions in available burst jobs are displayed correctly.
|
||||
/// </summary>
|
||||
[Test]
|
||||
[TestCase(Chooser.ARM)]
|
||||
[TestCase(Chooser.INTEL)]
|
||||
[TestCase(Chooser.Wasm)]
|
||||
public void TestInstructionsPresent(Chooser asmKind)
|
||||
{
|
||||
BurstTargetCpu targetCpu;
|
||||
BurstDisassembler.AsmKind targetKind;
|
||||
switch (asmKind)
|
||||
{
|
||||
case Chooser.INTEL:
|
||||
targetCpu = BurstTargetCpu.X64_SSE4;
|
||||
targetKind = BurstDisassembler.AsmKind.Intel;
|
||||
break;
|
||||
case Chooser.ARM:
|
||||
targetCpu = BurstTargetCpu.ARMV7A_NEON32;
|
||||
targetKind = BurstDisassembler.AsmKind.ARM;
|
||||
break;
|
||||
default: // WASM as LLVMIR is not tested.
|
||||
targetCpu = BurstTargetCpu.WASM32;
|
||||
targetKind = BurstDisassembler.AsmKind.Wasm;
|
||||
break;
|
||||
}
|
||||
|
||||
// Find all possible burst compile targets.
|
||||
var jobList = BurstReflection.FindExecuteMethods(
|
||||
BurstReflection.EditorAssembliesThatCanPossiblyContainJobs,
|
||||
BurstReflectionAssemblyOptions.None).CompileTargets;
|
||||
|
||||
var missingInstructions = new Dictionary<string, string>();
|
||||
var disassembler = new BurstDisassembler();
|
||||
foreach (var target in jobList)
|
||||
{
|
||||
// Get disassembly of target.
|
||||
var options = new StringBuilder();
|
||||
|
||||
target.Options.TryGetOptions(target.JobType, true, out var defaultOptions);
|
||||
options.AppendLine(defaultOptions);
|
||||
// Disables the 2 current warnings generated from code (since they clutter up the inspector display)
|
||||
// BC1370 - throw inside code not guarded with ConditionalSafetyCheck attribute
|
||||
// BC1322 - loop intrinsic on loop that has been optimised away
|
||||
options.AppendLine($"{BurstCompilerOptions.GetOption(BurstCompilerOptions.OptionDisableWarnings, "BC1370;BC1322")}");
|
||||
options.AppendLine($"{BurstCompilerOptions.GetOption(BurstCompilerOptions.OptionTarget, Enum.GetNames(typeof(BurstTargetCpu))[(int)targetCpu])}");
|
||||
options.AppendLine($"{BurstCompilerOptions.GetOption(BurstCompilerOptions.OptionDebug, "0")}");
|
||||
|
||||
var baseOptions = options.ToString();
|
||||
var append = BurstInspectorGUI.GetDisasmOptions()[(int)DisassemblyKind.Asm];
|
||||
|
||||
// Setup disAssembler with the job:
|
||||
var text = BurstInspectorGUI.GetDisassembly(target.Method, baseOptions + append);
|
||||
|
||||
// Bail out if there was a Burst compiler error, because we'll have all sorts of unexpected tokens.
|
||||
if (BurstInspectorGUI.IsBurstError(text))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
text = text.TrimStart('\n');
|
||||
Assert.IsTrue(disassembler.Initialize(text, targetKind, true, false), "Could not initialize disassembler.");
|
||||
|
||||
// Get all tokens labeled as AsmTokenKind.Identifier that do not start with '.' nor ends on ':'.
|
||||
// If this number exceeds 0 we are missing instructions (I believe).
|
||||
const int INSTRUCTION_PRE_PADDING = 8;
|
||||
var tokens =
|
||||
(from tok in disassembler.Tokens
|
||||
where tok.Kind == BurstDisassembler.AsmTokenKind.Identifier
|
||||
&& !disassembler.GetTokenAsText(tok).StartsWith(".")
|
||||
&& !disassembler.GetTokenAsText(tok).EndsWith(":")
|
||||
&& text[tok.Position - INSTRUCTION_PRE_PADDING - 1] == '\n'
|
||||
select tok).ToList();
|
||||
|
||||
foreach (var token in tokens)
|
||||
{
|
||||
if (missingInstructions.ContainsKey(token.ToString(text)))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
missingInstructions.Add(token.ToString(text), target.GetDisplayName());
|
||||
}
|
||||
}
|
||||
// Convey result.
|
||||
if (missingInstructions.Count > 0)
|
||||
{
|
||||
foreach (var itm in missingInstructions)
|
||||
{
|
||||
var token = itm.Key;
|
||||
var name = itm.Value;
|
||||
Debug.Log($"Token \"{token}\" was not recognised as instruction for {targetKind} (Found in job {name}).");
|
||||
}
|
||||
Assert.Fail($"{missingInstructions.Count} missing instructions, see log. Add missing instructions and call both this test and {nameof(TestInfo)}.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: c68d1e883c8136a89133cc095391d26b
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,383 @@
|
|||
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);
|
||||
int blockEnd = blockStart + blockStr.Length - 1;
|
||||
|
||||
Assert.AreEqual((blockIdx, blockStart, blockEnd),
|
||||
_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";
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 35ff2f449e6f335cb4f69ebb36ecf3e5
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,588 @@
|
|||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using Unity.Burst.Editor;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using UnityEngine.TestTools;
|
||||
using Unity.Collections;
|
||||
using Unity.Burst;
|
||||
using Unity.Jobs;
|
||||
|
||||
[TestFixture]
|
||||
[UnityPlatform(RuntimePlatform.WindowsEditor, RuntimePlatform.OSXEditor)]
|
||||
public class BurstInspectorGUITests
|
||||
{
|
||||
private readonly WaitUntil _waitForInitialized =
|
||||
new WaitUntil(() => EditorWindow.GetWindow<BurstInspectorGUI>()._initialized);
|
||||
|
||||
private IEnumerator SelectJobAwaitLoad(string assemblyName)
|
||||
{
|
||||
EditorWindow.GetWindow<BurstInspectorGUI>()._treeView.TrySelectByDisplayName(assemblyName);
|
||||
return new WaitUntil(() =>
|
||||
EditorWindow.GetWindow<BurstInspectorGUI>()._textArea.IsTextSet(assemblyName)
|
||||
);
|
||||
}
|
||||
|
||||
[UnitySetUp]
|
||||
public IEnumerator SetUp()
|
||||
{
|
||||
// Close down window if it's open, to start with a fresh inspector.
|
||||
EditorWindow.GetWindow<BurstInspectorGUI>().Close();
|
||||
EditorWindow.GetWindow<BurstInspectorGUI>().Show();
|
||||
|
||||
// Make sure window is actually initialized before continuing.
|
||||
yield return _waitForInitialized;
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator TestInspectorOpenDuringDomainReloadDoesNotLogErrors()
|
||||
{
|
||||
// Show Inspector window
|
||||
EditorWindow.GetWindow<BurstInspectorGUI>().Show();
|
||||
|
||||
Assert.IsTrue(EditorWindow.HasOpenInstances<BurstInspectorGUI>());
|
||||
|
||||
// Ask for domain reload
|
||||
EditorUtility.RequestScriptReload();
|
||||
|
||||
// Wait for the domain reload to be completed
|
||||
yield return new WaitForDomainReload();
|
||||
|
||||
Assert.IsTrue(EditorWindow.HasOpenInstances<BurstInspectorGUI>());
|
||||
|
||||
// Hide Inspector window
|
||||
EditorWindow.GetWindow<BurstInspectorGUI>().Close();
|
||||
|
||||
Assert.IsFalse(EditorWindow.HasOpenInstances<BurstInspectorGUI>());
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator DisassemblerNotChangingUnexpectedlyTest()
|
||||
{
|
||||
const string jobName2 = "BurstReflectionTests.MyJob - (IJob)";
|
||||
const string jobName = "BurstInspectorGUITests.MyJob - (IJob)";
|
||||
|
||||
// Selecting a specific assembly.
|
||||
yield return SelectJobAwaitLoad(jobName);
|
||||
var window = EditorWindow.GetWindow<BurstInspectorGUI>();
|
||||
|
||||
try
|
||||
{
|
||||
// Sending event to set the displayname, to avoid it resetting _scrollPos because of target change.
|
||||
window.SendEvent(new Event()
|
||||
{
|
||||
type = EventType.Repaint,
|
||||
mousePosition = new Vector2(window.position.width / 2f, window.position.height / 2f)
|
||||
});
|
||||
yield return null;
|
||||
|
||||
// Doing actual test work:
|
||||
var prev = new BurstDisassemblerWithCopy(window._burstDisassembler);
|
||||
window.SendEvent(new Event()
|
||||
{
|
||||
type = EventType.Repaint,
|
||||
mousePosition = new Vector2(window.position.width / 2f, window.position.height / 2f)
|
||||
});
|
||||
yield return null;
|
||||
Assert.IsTrue(prev.Equals(window._burstDisassembler),
|
||||
"Public fields changed in burstDisassembler even though they shouldn't");
|
||||
|
||||
prev = new BurstDisassemblerWithCopy(window._burstDisassembler);
|
||||
window.SendEvent(new Event() { type = EventType.MouseUp, mousePosition = Vector2.zero });
|
||||
yield return null;
|
||||
Assert.IsTrue(prev.Equals(window._burstDisassembler),
|
||||
"Public fields changed in burstDisassembler even though they shouldn't");
|
||||
|
||||
prev = new BurstDisassemblerWithCopy(window._burstDisassembler);
|
||||
yield return SelectJobAwaitLoad(jobName2);
|
||||
window = EditorWindow.GetWindow<BurstInspectorGUI>();
|
||||
|
||||
|
||||
window.SendEvent(new Event()
|
||||
{
|
||||
type = EventType.Repaint,
|
||||
mousePosition = new Vector2(window.position.width / 2f, window.position.height / 2f)
|
||||
});
|
||||
yield return null;
|
||||
Assert.IsFalse(prev.Equals(window._burstDisassembler), "Public fields of burstDisassembler did not change");
|
||||
}
|
||||
finally
|
||||
{
|
||||
window.Close();
|
||||
}
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator InspectorStallingLoadTest()
|
||||
{
|
||||
// Error was triggered by selecting a display name, filtering it out, and then doing a script recompilation.
|
||||
yield return SelectJobAwaitLoad("BurstInspectorGUITests.MyJob - (IJob)");
|
||||
|
||||
var win = EditorWindow.GetWindow<BurstInspectorGUI>();
|
||||
win._searchFieldJobs.SetFocus();
|
||||
yield return null;
|
||||
|
||||
// Simulate event for sending "a" as it will filter out the chosen job.
|
||||
win.SendEvent(Event.KeyboardEvent("a"));
|
||||
yield return null;
|
||||
|
||||
// Send RequestScriptReload to try and trigger the bug
|
||||
// and wait for it to return
|
||||
EditorUtility.RequestScriptReload();
|
||||
yield return new WaitForDomainReload();
|
||||
|
||||
win = EditorWindow.GetWindow<BurstInspectorGUI>();
|
||||
// Wait for it to actually initialize.
|
||||
yield return _waitForInitialized;
|
||||
|
||||
Assert.IsTrue(win._initialized, "BurstInspector did not initialize properly after script reload");
|
||||
|
||||
win.Close();
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator FontStyleDuringDomainReloadTest()
|
||||
{
|
||||
// Enter play mod
|
||||
yield return new EnterPlayMode();
|
||||
|
||||
// Exit play mode
|
||||
yield return new ExitPlayMode();
|
||||
|
||||
// Wait for the inspector to actually reload
|
||||
yield return _waitForInitialized;
|
||||
|
||||
var inspectorWindow = EditorWindow.GetWindow<BurstInspectorGUI>();
|
||||
|
||||
#if UNITY_2023_1_OR_NEWER
|
||||
Assert.AreEqual("RobotoMono-Regular", inspectorWindow._font.name);
|
||||
#else
|
||||
if (Application.platform == RuntimePlatform.WindowsEditor)
|
||||
{
|
||||
Assert.AreEqual("Consolas", inspectorWindow._font.name);
|
||||
}
|
||||
else
|
||||
{
|
||||
Assert.AreEqual("Courier", inspectorWindow._font.name);
|
||||
}
|
||||
#endif
|
||||
|
||||
inspectorWindow.Close();
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator BranchHoverTest()
|
||||
{
|
||||
const string jobName = "BurstInspectorGUITests.MyJob - (IJob)";
|
||||
|
||||
yield return SelectJobAwaitLoad(jobName);
|
||||
var info = SetupBranchTest();
|
||||
var window = EditorWindow.GetWindow<BurstInspectorGUI>();
|
||||
|
||||
window.SendEvent(new Event() { type = EventType.MouseUp, mousePosition = info.mousePos });
|
||||
var branch = window._textArea.hoveredBranch;
|
||||
yield return null;
|
||||
|
||||
// Close window to avoid it sending more events
|
||||
window.Close();
|
||||
|
||||
Assert.AreNotEqual(branch, default(LongTextArea.Branch), "Mouse is not hovering any branch.");
|
||||
Assert.AreEqual(info.blockIdx.src, branch.Edge.OriginRef.BlockIndex);
|
||||
Assert.AreEqual(info.blockIdx.dst, branch.Edge.LineRef.BlockIndex);
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator ClickBranchTest()
|
||||
{
|
||||
const string jobName = "BurstInspectorGUITests.MyJob - (IJob)";
|
||||
|
||||
yield return SelectJobAwaitLoad(jobName);
|
||||
var info = SetupBranchTest();
|
||||
|
||||
var window = EditorWindow.GetWindow<BurstInspectorGUI>();
|
||||
|
||||
|
||||
// Seeing if clicking the branch takes us to a spot where branch is still hovered.
|
||||
window.SendEvent(new Event() { type = EventType.MouseDown, mousePosition = info.mousePos });
|
||||
var branch = window._textArea.hoveredBranch;
|
||||
yield return null;
|
||||
|
||||
Assert.AreNotEqual(branch, default(LongTextArea.Branch), "Mouse is not hovering any branch.");
|
||||
Assert.AreEqual(info.blockIdx.src, branch.Edge.OriginRef.BlockIndex);
|
||||
Assert.AreEqual(info.blockIdx.dst, branch.Edge.LineRef.BlockIndex);
|
||||
|
||||
// Going back again.
|
||||
window.SendEvent(new Event() { type = EventType.MouseDown, mousePosition = info.mousePos });
|
||||
var branch2 = window._textArea.hoveredBranch;
|
||||
yield return null;
|
||||
|
||||
Assert.AreNotEqual(branch2, default(LongTextArea.Branch), "Mouse is not hovering any branch.");
|
||||
Assert.AreEqual(info.blockIdx.src, branch2.Edge.OriginRef.BlockIndex);
|
||||
Assert.AreEqual(info.blockIdx.dst, branch2.Edge.LineRef.BlockIndex);
|
||||
|
||||
// Close window to avoid it sending more events.
|
||||
window.Close();
|
||||
}
|
||||
|
||||
private struct InfoThingy
|
||||
{
|
||||
public (int src, int dst) blockIdx;
|
||||
public Vector2 mousePos;
|
||||
}
|
||||
|
||||
private InfoThingy SetupBranchTest()
|
||||
{
|
||||
var window = EditorWindow.GetWindow<BurstInspectorGUI>();
|
||||
|
||||
// Make sure we use fontSize 12:
|
||||
window.fontSizeIndex = 4;
|
||||
window._textArea.Invalidate();
|
||||
window.fixedFontStyle = null;
|
||||
// Force window size to actually show branch arrows.
|
||||
window.position = new Rect(window.position.x, window.position.y, 390, 405);
|
||||
|
||||
// Sending event to set the displayname, to avoid it resetting _scrollPos because of target change.
|
||||
// Sending two events as initial guess for buttonbar width might be off, and it will be a precise calculation after second event.
|
||||
window.SendEvent(new Event() { type = EventType.Repaint, mousePosition = new Vector2(window.position.width / 2f, window.position.height / 2f) });
|
||||
window.SendEvent(new Event() { type = EventType.Repaint, mousePosition = new Vector2(window.position.width / 2f, window.position.height / 2f) });
|
||||
|
||||
// Setting up for the test.
|
||||
// Finding an edge:
|
||||
int dstBlockIdx = -1;
|
||||
int srcBlockIdx = -1;
|
||||
int line = -1;
|
||||
for (int idx = 0; idx < window._burstDisassembler.Blocks.Count; idx++)
|
||||
{
|
||||
var block = window._burstDisassembler.Blocks[idx];
|
||||
if (block.Edges != null)
|
||||
{
|
||||
foreach (var edge in block.Edges)
|
||||
{
|
||||
if (edge.Kind == BurstDisassembler.AsmEdgeKind.OutBound)
|
||||
{
|
||||
dstBlockIdx = edge.LineRef.BlockIndex;
|
||||
line = window._textArea.blockLine[dstBlockIdx];
|
||||
if ((dstBlockIdx == idx + 1 && edge.LineRef.LineIndex == 0)) // pointing to next line
|
||||
{
|
||||
continue;
|
||||
}
|
||||
srcBlockIdx = idx;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (srcBlockIdx != -1)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (srcBlockIdx == -1)
|
||||
{
|
||||
window.Close();
|
||||
throw new System.Exception("No edges present in assembly for \"BurstInspectorGUITests.MyJob - (IJob)\"");
|
||||
}
|
||||
|
||||
float dist = window._textArea.fontHeight * line;
|
||||
|
||||
float x = (window.position.width - (window._inspectorView.width + BurstInspectorGUI._scrollbarThickness)) + window._textArea.horizontalPad - (2*window._textArea.fontWidth);
|
||||
|
||||
// setting _ScrollPos so end of arrow is at bottom of screen, to make sure there is actually room for the scrolling.
|
||||
window._scrollPos = new Vector2(0, dist - window._inspectorView.height * 0.93f);
|
||||
|
||||
// Setting mousePos to bottom of inspector view.
|
||||
float topOfInspectorToBranchArrow = window._buttonOverlapInspectorView + 66.5f;//66.5f is the size of space over the treeview of different jobs.
|
||||
|
||||
var mousePos = new Vector2(x, topOfInspectorToBranchArrow + window._inspectorView.height - 0.5f*window._textArea.fontHeight);
|
||||
|
||||
return new InfoThingy() { blockIdx = (srcBlockIdx, dstBlockIdx), mousePos = mousePos};
|
||||
}
|
||||
|
||||
public static IEnumerable ValueSource
|
||||
{
|
||||
get
|
||||
{
|
||||
yield return "BurstInspectorGUITests.MyJob - (IJob)";
|
||||
yield return "BurstReflectionTests.GenericType`1.NestedGeneric`1[System.Int32,System.Single].TestMethod3()";
|
||||
yield return "BurstReflectionTests.GenericType`1.NestedNonGeneric[System.Int32].TestMethod2()";
|
||||
yield return "BurstReflectionTests.GenericParallelForJob`1[System.Int32] - (IJobParallelFor)";
|
||||
}
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator FocusCodeTest([ValueSource(nameof(ValueSource))] string job)
|
||||
{
|
||||
var win = EditorWindow.GetWindow<BurstInspectorGUI>();
|
||||
|
||||
yield return SelectJobAwaitLoad(job);
|
||||
|
||||
// Doesn't check that it's at the right spot, simply that it actually moves
|
||||
Assert.IsFalse(Mathf.Approximately(win._inspectorView.y, 0f), "Inspector view did not change");
|
||||
win.Close();
|
||||
}
|
||||
|
||||
public static IEnumerable FocusCodeNotBranchesSource
|
||||
{
|
||||
get
|
||||
{
|
||||
yield return (1000, false);
|
||||
yield return (563, true);
|
||||
}
|
||||
}
|
||||
[UnityTest]
|
||||
public IEnumerator FocusCodeNotBranchesTest([ValueSource(nameof(FocusCodeNotBranchesSource))] (int, bool) input)
|
||||
{
|
||||
var (width, doFocus) = input;
|
||||
const string case1 = "BurstInspectorGUITests.BranchArrows - (IJob)";
|
||||
const string case2 = "BurstInspectorGUITests.BranchArrows2 - (IJob)";
|
||||
|
||||
var win = EditorWindow.GetWindow<BurstInspectorGUI>();
|
||||
|
||||
// Force window size to be small enough for it to position it more to the right.
|
||||
win.position = new Rect(win.position.x, win.position.y, width, 405);
|
||||
|
||||
// Test one where it should focus.
|
||||
yield return SelectJobAwaitLoad(case1);
|
||||
|
||||
var val1 = win._inspectorView.x;
|
||||
var result1 = Mathf.Approximately(val1, 0f);
|
||||
|
||||
|
||||
// Test two with no focus.
|
||||
win._assemblyKind = BurstInspectorGUI.AssemblyOptions.PlainWithDebugInformation;
|
||||
yield return SelectJobAwaitLoad(case2);
|
||||
|
||||
var val2 = win._inspectorView.x;
|
||||
var result2 = Mathf.Approximately(val2, 0f);
|
||||
|
||||
// Cleanup and test assertions.
|
||||
win.Close();
|
||||
Assert.AreEqual(doFocus, result1 == doFocus, $"Inspector view wrong.");
|
||||
//Assert.IsFalse(result1, $"Inspector view did not change (Is {val1}).");
|
||||
Assert.IsTrue(result2, $"Inspector view changed unexpectedly (Is {val2}).");
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator SelectionNotOutsideBoundsTest()
|
||||
{
|
||||
void MoveSelection(BurstInspectorGUI gui, LongTextArea.Direction dir)
|
||||
{
|
||||
switch (dir)
|
||||
{
|
||||
case LongTextArea.Direction.Down:
|
||||
gui._textArea.SelectAll();
|
||||
gui._textArea.MoveSelectionDown(gui._inspectorView, true);
|
||||
break;
|
||||
case LongTextArea.Direction.Right:
|
||||
gui._textArea.SelectAll();
|
||||
gui._textArea.MoveSelectionRight(gui._inspectorView, true);
|
||||
break;
|
||||
case LongTextArea.Direction.Left:
|
||||
gui._textArea.selectDragPos = Vector2.zero;
|
||||
gui._textArea.MoveSelectionLeft(gui._inspectorView, true);
|
||||
break;
|
||||
case LongTextArea.Direction.Up:
|
||||
gui._textArea.selectDragPos = Vector2.zero;
|
||||
gui._textArea.MoveSelectionUp(gui._inspectorView, true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
var win = EditorWindow.GetWindow<BurstInspectorGUI>();
|
||||
|
||||
yield return SelectJobAwaitLoad("BurstInspectorGUITests.MyJob - (IJob)");
|
||||
|
||||
try
|
||||
{
|
||||
foreach (var dir in Enum.GetValues(typeof(LongTextArea.Direction)))
|
||||
{
|
||||
MoveSelection(win, (LongTextArea.Direction)dir);
|
||||
yield return null;
|
||||
|
||||
// Check that no errors have happened.
|
||||
LogAssert.NoUnexpectedReceived();
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
win.Close();
|
||||
}
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator SelectionInAssemblySearchBarTest()
|
||||
{
|
||||
yield return SelectJobAwaitLoad("BurstInspectorGUITests.MyJob - (IJob)");
|
||||
var win = EditorWindow.GetWindow<BurstInspectorGUI>();
|
||||
|
||||
win._searchFieldAssembly.SetFocus();
|
||||
yield return null;
|
||||
|
||||
// Send events to input some text.
|
||||
win.SendEvent(Event.KeyboardEvent("a"));
|
||||
win.SendEvent(Event.KeyboardEvent("b"));
|
||||
|
||||
yield return null;
|
||||
|
||||
// Move select some using keyboard input
|
||||
win.SendEvent(Event.KeyboardEvent("left"));
|
||||
win.SendEvent(Event.KeyboardEvent("#right"));
|
||||
|
||||
yield return null;
|
||||
|
||||
// Do a copy
|
||||
var savedClipBoard = EditorGUIUtility.systemCopyBuffer;
|
||||
win.SendEvent(SystemInfo.operatingSystemFamily == OperatingSystemFamily.MacOSX
|
||||
? Event.KeyboardEvent("%c")
|
||||
: Event.KeyboardEvent("^c"));
|
||||
yield return null;
|
||||
|
||||
var copiedText = EditorGUIUtility.systemCopyBuffer;
|
||||
EditorGUIUtility.systemCopyBuffer = savedClipBoard;
|
||||
|
||||
// Check that all is good
|
||||
win.Close();
|
||||
|
||||
Assert.AreEqual("b", copiedText, "Copied text did not match expectation.");
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator GoToNextSearchTargetTest()
|
||||
{
|
||||
var active = -1;
|
||||
var nextActive = -1;
|
||||
|
||||
yield return SelectJobAwaitLoad("BurstInspectorGUITests.MyJob - (IJob)");
|
||||
var win = EditorWindow.GetWindow<BurstInspectorGUI>();
|
||||
|
||||
try
|
||||
{
|
||||
win._searchFieldAssembly.SetFocus();
|
||||
yield return null;
|
||||
|
||||
// Do a search in the text.
|
||||
win.SendEvent(Event.KeyboardEvent("p"));
|
||||
win.SendEvent(Event.KeyboardEvent("u"));
|
||||
win.SendEvent(Event.KeyboardEvent("return"));
|
||||
yield return null;
|
||||
|
||||
active = win._textArea._activeSearchHitIdx;
|
||||
|
||||
// Select next search target.
|
||||
win.SendEvent(Event.KeyboardEvent("return"));
|
||||
yield return null;
|
||||
|
||||
nextActive = win._textArea._activeSearchHitIdx;
|
||||
}
|
||||
finally
|
||||
{
|
||||
win.Close();
|
||||
}
|
||||
|
||||
Assert.AreNotEqual(active, nextActive, "Active search target was not changed.");
|
||||
}
|
||||
|
||||
[BurstCompile]
|
||||
private struct MyJob : IJob
|
||||
{
|
||||
[ReadOnly]
|
||||
public NativeArray<float> Inpút;
|
||||
|
||||
[WriteOnly]
|
||||
public NativeArray<float> Output;
|
||||
|
||||
public void Execute()
|
||||
{
|
||||
float result = 0.0f;
|
||||
for (int i = 0; i < Inpút.Length; i++)
|
||||
{
|
||||
result += Inpút[i];
|
||||
}
|
||||
Output[0] = result;
|
||||
}
|
||||
}
|
||||
|
||||
[BurstCompile]
|
||||
private struct BranchArrows : IJob
|
||||
{
|
||||
[ReadOnly]
|
||||
public NativeArray<float> Inpút;
|
||||
|
||||
[WriteOnly]
|
||||
public NativeArray<float> Output;
|
||||
|
||||
public void Execute()
|
||||
{
|
||||
float result = 0.0f;
|
||||
for (int i = 0; i < Inpút.Length; i++)
|
||||
{
|
||||
if (Inpút[i] < 10) { result += 1; }
|
||||
else if (Inpút[i] < 20) { result += 2; }
|
||||
else if (Inpút[i] < 30) { result += 3; }
|
||||
else if (Inpút[i] < 40) { result += 4; }
|
||||
else if (Inpút[i] < 50) { result += 5; }
|
||||
else if (Inpút[i] < 60) { result += 6; }
|
||||
else if (Inpút[i] < 70) { result += 7; }
|
||||
else if (Inpút[i] < 80) { result += 8; }
|
||||
else if (Inpút[i] < 90) { result += 9; }
|
||||
result += Inpút[i];
|
||||
}
|
||||
Output[0] = result;
|
||||
}
|
||||
}
|
||||
|
||||
[BurstCompile]
|
||||
private struct BranchArrows2 : IJob
|
||||
{
|
||||
[ReadOnly]
|
||||
public NativeArray<float> Inpút;
|
||||
|
||||
[WriteOnly]
|
||||
public NativeArray<float> Output;
|
||||
|
||||
public void Execute()
|
||||
{
|
||||
float result = 0.0f;
|
||||
for (int i = 0; i < Inpút.Length; i++)
|
||||
{
|
||||
if (Inpút[i] < 10) { result += 1; }
|
||||
else if (Inpút[i] < 20) { result += 2; }
|
||||
else if (Inpút[i] < 30) { result += 3; }
|
||||
else if (Inpút[i] < 40) { result += 4; }
|
||||
else if (Inpút[i] < 50) { result += 5; }
|
||||
else if (Inpút[i] < 60) { result += 6; }
|
||||
else if (Inpút[i] < 70) { result += 7; }
|
||||
else if (Inpút[i] < 80) { result += 8; }
|
||||
else if (Inpút[i] < 90) { result += 9; }
|
||||
result += Inpút[i];
|
||||
}
|
||||
Output[0] = result;
|
||||
}
|
||||
}
|
||||
|
||||
private class BurstDisassemblerWithCopy : BurstDisassembler
|
||||
{
|
||||
public List<AsmBlock> BlocksCopy;
|
||||
public bool IsColoredCopy;
|
||||
public List<AsmLine> LinesCopy;
|
||||
public List<AsmToken> TokensCopy;
|
||||
public BurstDisassemblerWithCopy(BurstDisassembler disassembler) : base()
|
||||
{
|
||||
IsColoredCopy = disassembler.IsColored;
|
||||
|
||||
BlocksCopy = new List<AsmBlock>(disassembler.Blocks);
|
||||
LinesCopy = new List<AsmLine>(disassembler.Lines);
|
||||
TokensCopy = new List<AsmToken>(disassembler.Tokens);
|
||||
}
|
||||
|
||||
public bool Equals(BurstDisassembler other)
|
||||
{
|
||||
return IsColoredCopy == other.IsColored
|
||||
&& BlocksCopy.SequenceEqual(other.Blocks)
|
||||
&& LinesCopy.SequenceEqual(other.Lines)
|
||||
&& TokensCopy.SequenceEqual(other.Tokens);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 5c2988be6da139988b149bb3b60dc9ca
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
using NUnit.Framework;
|
||||
using Unity.Burst.Editor;
|
||||
|
||||
public class BurstMathTests
|
||||
{
|
||||
[Test]
|
||||
[TestCase(1f, 3f, 3f, true)]
|
||||
[TestCase(1f, 3f, 2f, true)]
|
||||
[TestCase(1f, 3f, 3.00001f, false)]
|
||||
public void WithinRangeTest(float start, float end, float num, bool res)
|
||||
{
|
||||
Assert.That(BurstMath.WithinRange(start, end, num), Is.EqualTo(res));
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 6a647d1cecc83c4eaf9750af7ae6a1d0
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,280 @@
|
|||
using System;
|
||||
using NUnit.Framework;
|
||||
using Unity.Burst.Editor;
|
||||
using Unity.Burst;
|
||||
using Unity.Jobs;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEditor.IMGUI.Controls;
|
||||
|
||||
public class BurstMethodTreeViewTests
|
||||
{
|
||||
/*
|
||||
Consists of a tree looking like:
|
||||
Root
|
||||
│
|
||||
└►BurstMethodTreeViewTests
|
||||
│
|
||||
│►Job1
|
||||
│ │
|
||||
│ └►TestMethod1
|
||||
│
|
||||
│►Job2
|
||||
│ │
|
||||
│ └►TestMethod1
|
||||
│
|
||||
│►Job3
|
||||
│ │
|
||||
│ └►TestMethod1(System.IntPtr)
|
||||
│
|
||||
│►Job4
|
||||
│ │
|
||||
│ └►TestMethod1
|
||||
│
|
||||
└►Job5 - (IJob)
|
||||
*/
|
||||
private BurstMethodTreeView _treeView;
|
||||
|
||||
private List<BurstCompileTarget> _targets;
|
||||
|
||||
private string _filter;
|
||||
|
||||
[SetUp]
|
||||
public void SetUp()
|
||||
{
|
||||
_filter = string.Empty;
|
||||
|
||||
_treeView = new BurstMethodTreeView(
|
||||
new TreeViewState(),
|
||||
() => _filter,
|
||||
() => (true, true)
|
||||
);
|
||||
|
||||
string name = "TestMethod1";
|
||||
_targets = new List<BurstCompileTarget>
|
||||
{
|
||||
new BurstCompileTarget(typeof(Job1).GetMethod(name), typeof(Job1), null, true),
|
||||
new BurstCompileTarget(typeof(Job2).GetMethod(name), typeof(Job2), null, true),
|
||||
new BurstCompileTarget(typeof(Job3).GetMethod(name), typeof(Job3), null, true),
|
||||
new BurstCompileTarget(typeof(Job4).GetMethod(name), typeof(Job4), null, true),
|
||||
new BurstCompileTarget(typeof(Job5).GetMethod("Execute"), typeof(Job5), typeof(IJob), false),
|
||||
};
|
||||
}
|
||||
|
||||
private void testEquality<T>(List<T> exp, List<T> act)
|
||||
{
|
||||
Assert.AreEqual(exp.Count, act.Count, "List length did not match.");
|
||||
|
||||
if (exp is List<TreeViewItem> elist && act is List<TreeViewItem> alist)
|
||||
{
|
||||
for (int i = 0; i < act.Count; i++)
|
||||
{
|
||||
Assert.IsTrue(alist[i].CompareTo(elist[i]) == 0,
|
||||
$"expected: {elist[i].displayName}\nactual: {alist[i].displayName}");
|
||||
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < act.Count; i++)
|
||||
{
|
||||
Assert.AreEqual(exp[i], act[i], $"list items did not match at index {i}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ProcessNewItemTest()
|
||||
{
|
||||
// Test for method containing . in name:
|
||||
List<StringSlice> oldNameSpace = new List<StringSlice>();
|
||||
int idJ = 0;
|
||||
var (idn, newtarget, nameSpace) =
|
||||
BurstMethodTreeView.ProcessNewItem(0, ++idJ, _targets[2], oldNameSpace);
|
||||
|
||||
Assert.AreEqual(-2, idn);
|
||||
var expTargets = new List<TreeViewItem>
|
||||
{
|
||||
new TreeViewItem(-1, 0, $"{nameof(BurstMethodTreeViewTests)}"),
|
||||
new TreeViewItem(-2,1,$"{nameof(Job3)}"),
|
||||
new TreeViewItem(1, 2, "TestMethod1(System.IntPtr)")
|
||||
};
|
||||
var expNS = new List<StringSlice>
|
||||
{
|
||||
new StringSlice($"{nameof(BurstMethodTreeViewTests)}"),
|
||||
new StringSlice($"{nameof(Job3)}")
|
||||
};
|
||||
testEquality(expTargets, newtarget);
|
||||
testEquality(expNS, nameSpace);
|
||||
|
||||
// Test for method with . and with thing in namespace:
|
||||
(idn, newtarget, nameSpace) = BurstMethodTreeView.ProcessNewItem(idn, ++idJ, _targets[2], nameSpace);
|
||||
Assert.AreEqual(-2, idn); // no new non-leafs added.
|
||||
expTargets = new List<TreeViewItem>
|
||||
{
|
||||
new TreeViewItem(2, 2, "TestMethod1(System.IntPtr)")
|
||||
};
|
||||
testEquality(expTargets, newtarget);
|
||||
testEquality(expNS, nameSpace);
|
||||
|
||||
// Test with IJob instead of static method:
|
||||
(idn, newtarget, nameSpace) = BurstMethodTreeView.ProcessNewItem(0, ++idJ, _targets[4], oldNameSpace);
|
||||
Assert.AreEqual(-1, idn); // no new non-leafs added.
|
||||
expTargets = new List<TreeViewItem>
|
||||
{
|
||||
new TreeViewItem(-1, 0, $"{nameof(BurstMethodTreeViewTests)}"),
|
||||
new TreeViewItem(2, 2, $"{nameof(Job5)} - ({nameof(IJob)})")
|
||||
};
|
||||
expNS = new List<StringSlice> { new StringSlice($"{nameof(BurstMethodTreeViewTests)}"), };
|
||||
testEquality(expTargets, newtarget);
|
||||
testEquality(expNS, nameSpace);
|
||||
}
|
||||
|
||||
|
||||
private readonly (string, string[])[] _findNameSpacesTestInput =
|
||||
{
|
||||
("Burst.Compiler.IL.Tests.TestGenerics+GenericStructOuter2`2+GenericStructInner`1[[Burst.Compiler.IL.Tests.TestGenerics+MyValueData1, Unity.Burst.Tests.UnitTests, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null],[Burst.Compiler.IL.Tests.TestGenerics+MyValueData2, Unity.Burst.Tests.UnitTests, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null],[Burst.Compiler.IL.Tests.TestGenerics+MyValueData2, Unity.Burst.Tests.UnitTests, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null]]",
|
||||
new []{ "Burst.Compiler.IL.Tests.TestGenerics", "GenericStructOuter2`2" })
|
||||
};
|
||||
|
||||
[Test]
|
||||
public void ExtractNameSpacesTest()
|
||||
{
|
||||
foreach (var (displayName, expectedNameSpaces) in _findNameSpacesTestInput)
|
||||
{
|
||||
var (nameSpaces, methodNameIdx) = BurstMethodTreeView.ExtractNameSpaces(displayName);
|
||||
|
||||
Assert.AreEqual(2, nameSpaces.Count, "Amount of namespaces found is wrong.");
|
||||
int len = expectedNameSpaces.Length;
|
||||
int expectedNSIdx = 0;
|
||||
for (int i = 0; i < len; i++)
|
||||
{
|
||||
expectedNSIdx += expectedNameSpaces[i].Length + 1;
|
||||
Assert.AreEqual(expectedNameSpaces[i], nameSpaces[i].ToString(), "Wrong namespace name retrieval.");
|
||||
}
|
||||
Assert.AreEqual(expectedNSIdx, methodNameIdx, "Wrong index of method name.");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
[Test]
|
||||
public void InitializeTest()
|
||||
{
|
||||
const int numNodes = 1 + 5; // Root + internal nodes.
|
||||
_treeView.Initialize(_targets, false);
|
||||
Assert.AreEqual(numNodes, _treeView.GetExpanded().Count, "All menu items should be expanded");
|
||||
|
||||
_treeView.SetExpanded(-2, false);
|
||||
Assert.AreEqual(numNodes-1, _treeView.GetExpanded().Count, "First Job should be folded.");
|
||||
|
||||
_treeView.Initialize(_targets, true);
|
||||
Assert.AreEqual(numNodes-1, _treeView.GetExpanded().Count);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void BuildRootTest()
|
||||
{
|
||||
_treeView.Initialize(_targets, false);
|
||||
|
||||
int dexp = 0;
|
||||
int idNexp = -1;
|
||||
int idLexp = 1;
|
||||
foreach (TreeViewItem twi in _treeView.GetRows())
|
||||
{
|
||||
Assert.AreEqual(dexp++, twi.depth, $"Depth of item \"{twi}\" was wrong.");
|
||||
if (dexp > 2) { dexp = 1; }
|
||||
|
||||
Assert.AreEqual(twi.hasChildren ? idNexp-- : idLexp++, twi.id, $"ID of item \"{twi}\" was wrong.");
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetSelection()
|
||||
{
|
||||
_treeView.Initialize(_targets, false);
|
||||
|
||||
IList<int> actual = _treeView.GetSelection();
|
||||
Assert.IsEmpty(actual, "Selection count wrong.");
|
||||
|
||||
_treeView.SelectAllRows();
|
||||
actual = _treeView.GetSelection();
|
||||
Assert.IsEmpty(actual, "Selection count wrong. Multirow selection not allowed.");
|
||||
|
||||
_treeView.SetSelection(new List<int> { -2 });
|
||||
actual = _treeView.GetSelection();
|
||||
Assert.AreEqual(0, actual.Count, "Selection count wrong. Label selection not allowed.");
|
||||
|
||||
_treeView.SetSelection(new List<int> { 1 });
|
||||
actual = _treeView.GetSelection();
|
||||
Assert.AreEqual(1, actual.Count, "Selection count wrong.");
|
||||
Assert.AreEqual(1, actual[0], "Selection ID wrong.");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TrySelectByDisplayNameTest()
|
||||
{
|
||||
const string name = "BurstMethodTreeViewTests.Job1.TestMethod1()";
|
||||
_treeView.Initialize(_targets, false);
|
||||
|
||||
Assert.IsFalse(_treeView.TrySelectByDisplayName("Not present"));
|
||||
|
||||
Assert.IsTrue(_treeView.TrySelectByDisplayName(name), "TreeView Could not find method.");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ProcessEntireTestProject()
|
||||
{
|
||||
// Make it filter out some jobs:
|
||||
_filter = "Unity";
|
||||
|
||||
// Get all target jobs!
|
||||
var assemblyList = BurstReflection.EditorAssembliesThatCanPossiblyContainJobs;
|
||||
var result = BurstReflection.FindExecuteMethods(assemblyList, BurstReflectionAssemblyOptions.None).CompileTargets;
|
||||
result.Sort((left, right) => string.Compare(left.GetDisplayName(), right.GetDisplayName(), StringComparison.Ordinal));
|
||||
|
||||
// Initialize the tree view:
|
||||
_treeView.Initialize(result, false);
|
||||
|
||||
// Check if everything is good and ready:
|
||||
var visibleJobs = _treeView.GetRows().Where(twi => !twi.hasChildren);
|
||||
foreach (TreeViewItem twi in visibleJobs)
|
||||
{
|
||||
var actual = result[twi.id - 1];
|
||||
var expected = twi.displayName;
|
||||
|
||||
Assert.IsTrue(actual.GetDisplayName().Contains(expected), $"Retrieved the wrong target base on id.\nGot \"{actual.GetDisplayName()}\"\nExpected \"{expected}\"");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
[BurstCompile]
|
||||
private struct Job1
|
||||
{
|
||||
[BurstCompile]
|
||||
public static void TestMethod1() { }
|
||||
}
|
||||
[BurstCompile]
|
||||
private struct Job2
|
||||
{
|
||||
[BurstCompile]
|
||||
public static void TestMethod1() { }
|
||||
}
|
||||
[BurstCompile]
|
||||
private struct Job3
|
||||
{
|
||||
[BurstCompile]
|
||||
public static void TestMethod1(System.IntPtr ptr) { }
|
||||
}
|
||||
[BurstCompile]
|
||||
private struct Job4
|
||||
{
|
||||
[BurstCompile]
|
||||
public static void TestMethod1() { }
|
||||
}
|
||||
|
||||
[BurstCompile]
|
||||
private struct Job5 : IJob
|
||||
{
|
||||
public void Execute() { }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: dec061e3cbd730ce8117c465ee02452c
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,197 @@
|
|||
using NUnit.Framework;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Unity.Burst;
|
||||
using Unity.Burst.Editor;
|
||||
using Unity.Jobs;
|
||||
|
||||
// This concrete generic type is only referenced in this assembly-level attribute,
|
||||
// not anywhere else in code. This is to test that such types can be picked up
|
||||
// by BurstReflection.
|
||||
[assembly: BurstReflectionTests.RegisterGenericJobType(typeof(BurstReflectionTests.GenericParallelForJob<int>))]
|
||||
|
||||
[TestFixture]
|
||||
public class BurstReflectionTests
|
||||
{
|
||||
private List<System.Reflection.Assembly> _assemblies;
|
||||
|
||||
[OneTimeSetUp]
|
||||
public void SetUp()
|
||||
{
|
||||
_assemblies = BurstReflection.EditorAssembliesThatCanPossiblyContainJobs;
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void CanGetAssemblyList()
|
||||
{
|
||||
Assert.That(_assemblies, Has.Count.GreaterThan(0));
|
||||
}
|
||||
|
||||
[Test]
|
||||
[TestCase("BurstReflectionTests.MyJob - (IJob)")]
|
||||
[TestCase("BurstReflectionTests.MyGenericJob`1[System.Int32] - (IJob)")]
|
||||
[TestCase("BurstReflectionTests.MyGenericJob2`1[System.Int32] - (BurstReflectionTests.IMyGenericJob`1[System.Int32])")]
|
||||
[TestCase("BurstReflectionTests.MyGenericJob2`1[System.Double] - (BurstReflectionTests.IMyGenericJob`1[System.Double])")]
|
||||
[TestCase("BurstReflectionTests.NonGenericType.TestMethod1()")]
|
||||
[TestCase("BurstReflectionTests.GenericType`1[System.Int32].TestMethod1()")]
|
||||
[TestCase("BurstReflectionTests.GenericType`1.NestedNonGeneric[System.Int32].TestMethod2()")]
|
||||
[TestCase("BurstReflectionTests.GenericType`1.NestedGeneric`1[System.Int32,System.Single].TestMethod3()")]
|
||||
[TestCase("BurstReflectionTests.MyGenericJobSeparateAssembly`1[System.Int32] - (BurstReflectionTestsSeparateAssembly.IMyGenericJobSeparateAssembly`1[System.Int32])")]
|
||||
[TestCase("BurstReflectionTests.GenericParallelForJob`1[System.Int32] - (IJobParallelFor)")]
|
||||
public void CanFindJobType(string compileTargetName)
|
||||
{
|
||||
var result = BurstReflection.FindExecuteMethods(_assemblies, BurstReflectionAssemblyOptions.None);
|
||||
|
||||
Assert.That(result.LogMessages, Is.Empty);
|
||||
|
||||
var compileTarget = result.CompileTargets.Find(x => x.GetDisplayName() == compileTargetName);
|
||||
Assert.That(compileTarget, Is.Not.Null);
|
||||
}
|
||||
|
||||
[BurstCompile]
|
||||
private struct MyJob : IJob
|
||||
{
|
||||
public void Execute() { }
|
||||
}
|
||||
|
||||
[BurstCompile]
|
||||
private struct MyGenericJob<T> : IJob
|
||||
{
|
||||
public void Execute() { }
|
||||
|
||||
private static void UseConcreteType()
|
||||
{
|
||||
new MyGenericJob<int>().Execute();
|
||||
}
|
||||
}
|
||||
|
||||
[Unity.Jobs.LowLevel.Unsafe.JobProducerType(typeof(MyJobProducer<,>))]
|
||||
private interface IMyGenericJob<T>
|
||||
{
|
||||
void Execute();
|
||||
}
|
||||
|
||||
[BurstCompile]
|
||||
private struct MyGenericJob2<T> : IMyGenericJob<T>
|
||||
{
|
||||
public void Execute() { }
|
||||
|
||||
private static void UseConcreteType()
|
||||
{
|
||||
new MyGenericJob2<int>().Execute();
|
||||
}
|
||||
}
|
||||
|
||||
private static class MyJobProducer<TJob, T>
|
||||
{
|
||||
public static void Execute(ref TJob job)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private struct MyGenericJob2Wrapper<T1, T2>
|
||||
{
|
||||
public MyGenericJob2<T2> Job;
|
||||
|
||||
private static void UseConcreteType()
|
||||
{
|
||||
var x = new MyGenericJob2Wrapper<float, double>();
|
||||
x.Job.Execute();
|
||||
}
|
||||
}
|
||||
|
||||
[BurstCompile]
|
||||
private struct NonGenericType
|
||||
{
|
||||
[BurstCompile]
|
||||
public static void TestMethod1() { }
|
||||
}
|
||||
|
||||
[BurstCompile]
|
||||
private struct GenericType<T>
|
||||
{
|
||||
public static Action Delegate1;
|
||||
public static Action Delegate2;
|
||||
public static Action Delegate3;
|
||||
|
||||
[BurstCompile]
|
||||
public static void TestMethod1() { }
|
||||
|
||||
[BurstCompile]
|
||||
public class NestedNonGeneric
|
||||
{
|
||||
[BurstCompile]
|
||||
public static void TestMethod2() { }
|
||||
}
|
||||
|
||||
[BurstCompile]
|
||||
public class NestedGeneric<T2>
|
||||
{
|
||||
[BurstCompile]
|
||||
public static void TestMethod3() { }
|
||||
}
|
||||
|
||||
private static void UseConcreteType()
|
||||
{
|
||||
// Store the delegates to static fields to avoid
|
||||
// them being optimized-away in Release builds
|
||||
Delegate1 = GenericType<int>.TestMethod1;
|
||||
Delegate2 = GenericType<int>.NestedNonGeneric.TestMethod2;
|
||||
Delegate3 = GenericType<int>.NestedGeneric<float>.TestMethod3;
|
||||
}
|
||||
}
|
||||
|
||||
[BurstCompile]
|
||||
private struct MyGenericJobSeparateAssembly<T> : BurstReflectionTestsSeparateAssembly.IMyGenericJobSeparateAssembly<T>
|
||||
{
|
||||
public void Execute() { }
|
||||
|
||||
private static void UseConcreteType()
|
||||
{
|
||||
new MyGenericJobSeparateAssembly<int>().Execute();
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
[TestCase("BurstReflectionTests.GenericMethodContainer.GenericMethod(T)")]
|
||||
public void ExcludesGenericMethods(string compileTargetName)
|
||||
{
|
||||
var result = BurstReflection.FindExecuteMethods(_assemblies, BurstReflectionAssemblyOptions.None);
|
||||
|
||||
Assert.That(result.LogMessages, Is.Empty);
|
||||
|
||||
var compileTarget = result.CompileTargets.Find(x => x.GetDisplayName() == compileTargetName);
|
||||
Assert.That(compileTarget, Is.Null);
|
||||
}
|
||||
|
||||
[BurstCompile]
|
||||
private static class GenericMethodContainer
|
||||
{
|
||||
[BurstCompile]
|
||||
private static void GenericMethod<T>(T p)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
|
||||
internal class RegisterGenericJobTypeAttribute : Attribute
|
||||
{
|
||||
public Type ConcreteType;
|
||||
|
||||
public RegisterGenericJobTypeAttribute(Type type)
|
||||
{
|
||||
ConcreteType = type;
|
||||
}
|
||||
}
|
||||
|
||||
[BurstCompile]
|
||||
internal struct GenericParallelForJob<T> : IJobParallelFor
|
||||
where T : struct
|
||||
{
|
||||
public void Execute(int index)
|
||||
{
|
||||
throw new System.NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: fde1edfe51dc3deaa53f0952dddf2b02
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,131 @@
|
|||
using System;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using NUnit.Framework;
|
||||
using Unity.Burst;
|
||||
using Unity.Burst.Editor;
|
||||
|
||||
public class BurstStringSearchTests
|
||||
{
|
||||
private BurstDisassembler GetDisassemblerandText(string compileTargetName, int debugLvl, out string textToRender)
|
||||
{
|
||||
// Get target job assembly:
|
||||
var assemblies = BurstReflection.EditorAssembliesThatCanPossiblyContainJobs;
|
||||
var result = BurstReflection.FindExecuteMethods(assemblies, BurstReflectionAssemblyOptions.None);
|
||||
var compileTarget = result.CompileTargets.Find(x => x.GetDisplayName() == compileTargetName);
|
||||
|
||||
Assert.IsTrue(compileTarget != default, $"Could not find compile target: {compileTarget}");
|
||||
|
||||
BurstDisassembler disassembler = new BurstDisassembler();
|
||||
|
||||
var options = new StringBuilder();
|
||||
|
||||
compileTarget.Options.TryGetOptions(compileTarget.JobType, true, out string defaultOptions);
|
||||
options.AppendLine(defaultOptions);
|
||||
// Disables the 2 current warnings generated from code (since they clutter up the inspector display)
|
||||
// BC1370 - throw inside code not guarded with ConditionalSafetyCheck attribute
|
||||
// BC1322 - loop intrinsic on loop that has been optimised away
|
||||
options.AppendLine($"{BurstCompilerOptions.GetOption(BurstCompilerOptions.OptionDisableWarnings, "BC1370;BC1322")}");
|
||||
|
||||
options.AppendLine($"{BurstCompilerOptions.GetOption(BurstCompilerOptions.OptionTarget, BurstTargetCpu.X64_SSE4)}");
|
||||
|
||||
options.AppendLine($"{BurstCompilerOptions.GetOption(BurstCompilerOptions.OptionDebug, $"{debugLvl}")}");
|
||||
|
||||
var baseOptions = options.ToString();
|
||||
|
||||
var append = BurstInspectorGUI.GetDisasmOptions()[(int)DisassemblyKind.Asm];
|
||||
|
||||
// Setup disAssembler with the job:
|
||||
compileTarget.RawDisassembly = BurstInspectorGUI.GetDisassembly(compileTarget.Method, baseOptions + append);
|
||||
textToRender = compileTarget.RawDisassembly.TrimStart('\n');
|
||||
|
||||
return disassembler;
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void FindLineNrTest()
|
||||
{
|
||||
// Load in a test text
|
||||
var disassembler = GetDisassemblerandText("BurstInspectorGUITests.MyJob - (IJob)", 1, out string textToRender);
|
||||
disassembler.Initialize(textToRender, BurstDisassembler.AsmKind.Intel, true, true);
|
||||
|
||||
var text = disassembler.GetOrRenderBlockToText(0);
|
||||
|
||||
// Call find line nr for:
|
||||
// first line
|
||||
// Around middle
|
||||
// Last line
|
||||
Assert.AreEqual(0, BurstStringSearch.FindLineNr(text, text.IndexOf('\n') - 1), "Couldn't find line 0");
|
||||
|
||||
Assert.AreEqual(2, BurstStringSearch.FindLineNr(text, text.IndexOf('\n', text.IndexOf('\n') + 1) + 1), "Couldn't find line in middle");
|
||||
|
||||
Assert.AreEqual(disassembler.Blocks[0].Length-1, BurstStringSearch.FindLineNr(text, text.Length-1), "Couldn't find last line");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetEndIndexOfPlainLineTest()
|
||||
{
|
||||
Assert.AreEqual(("This\nIs\nPerfect".Length-1, 6),
|
||||
BurstStringSearch.GetEndIndexOfPlainLine("This\nIs\nPerfect", 2),
|
||||
"Failed finding in well formed string");
|
||||
|
||||
const string text1 = "No line endings";
|
||||
Assert.AreEqual((text1.Length-1, text1.Length-1),
|
||||
BurstStringSearch.GetEndIndexOfPlainLine(text1, 0),
|
||||
"Failed for missing line ending");
|
||||
|
||||
const string text2 = "No Line endings too many lines";
|
||||
Assert.Throws<ArgumentOutOfRangeException>(() => BurstStringSearch.GetEndIndexOfPlainLine(text2, 2),
|
||||
"Failed for missing line ending and too high line number");
|
||||
|
||||
const string text3 = "Line ending\n";
|
||||
Assert.AreEqual((text3.Length-1, text3.Length-1),
|
||||
BurstStringSearch.GetEndIndexOfPlainLine(text3, 0),
|
||||
"Failed with line ending");
|
||||
|
||||
const string text4 = "Line ending too many lines\n";
|
||||
Assert.Throws<ArgumentOutOfRangeException>(() => BurstStringSearch.GetEndIndexOfPlainLine(text4, 2),
|
||||
"Failed with line endings and too high line number");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void FindMatchTest()
|
||||
{
|
||||
_ = GetDisassemblerandText("BurstInspectorGUITests.MyJob - (IJob)", 2, out var textToRender);
|
||||
|
||||
var expectedNormal = textToRender.IndexOf("def");
|
||||
var tmp = Regex.Match(textToRender, @"\bdef\b");
|
||||
var expectedWhole = tmp.Success ? tmp.Index : -1;
|
||||
|
||||
|
||||
// Normal search
|
||||
Assert.AreEqual((expectedNormal, 3),
|
||||
BurstStringSearch.FindMatch(textToRender,
|
||||
new SearchCriteria("def", false, false, false), default),
|
||||
"Standard search failed"); // standard search: Match def in .endef
|
||||
Assert.AreEqual((expectedWhole, 3),
|
||||
BurstStringSearch.FindMatch(textToRender,
|
||||
new SearchCriteria("def", false, true, false), default),
|
||||
"Standard whole words failed"); // whole word search: Match def in .def
|
||||
|
||||
// Regex search
|
||||
const RegexOptions opt = RegexOptions.CultureInvariant;
|
||||
Assert.AreEqual((expectedNormal, 3),
|
||||
BurstStringSearch.FindMatch(textToRender,
|
||||
new SearchCriteria("def", false, false, true),
|
||||
new Regex("def", opt | RegexOptions.IgnoreCase)),
|
||||
"Regex search failed"); // standard search: Match def in .endef
|
||||
Assert.AreEqual((expectedWhole, tmp.Success ? 3 : 0),
|
||||
BurstStringSearch.FindMatch(textToRender,
|
||||
new SearchCriteria(@"\bdef\b", false, true, true),
|
||||
new Regex(@"\bdef\b", opt)),
|
||||
"Regex whole word failed"); // whole word search: Match def in .def
|
||||
|
||||
// Across lines and blocks
|
||||
Assert.AreEqual((12, 4),
|
||||
BurstStringSearch.FindMatch(textToRender,
|
||||
new SearchCriteria(@"t[\n]+..", false, false, true),
|
||||
new Regex(@"t[\n]+..", opt | RegexOptions.IgnoreCase)),
|
||||
"Regex across lines failed");
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 2d306d2ea7783099abe61e86c377ca92
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,712 @@
|
|||
using System;
|
||||
using System.Collections;
|
||||
using NUnit.Framework;
|
||||
using UnityEngine;
|
||||
using Unity.Jobs.LowLevel.Unsafe;
|
||||
using UnityEngine.TestTools;
|
||||
using Unity.Burst;
|
||||
using Unity.Collections;
|
||||
using Unity.Jobs;
|
||||
using System.Threading;
|
||||
using System.Diagnostics;
|
||||
using UnityEditor;
|
||||
using Debug = UnityEngine.Debug;
|
||||
using System.Text.RegularExpressions;
|
||||
using Unity.Profiling;
|
||||
using UnityEditor.Compilation;
|
||||
using System.IO;
|
||||
|
||||
[TestFixture]
|
||||
public class EditModeTest
|
||||
{
|
||||
private const int MaxIterations = 500;
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator CheckBurstJobEnabledDisabled()
|
||||
{
|
||||
BurstCompiler.Options.EnableBurstCompileSynchronously = true;
|
||||
try
|
||||
{
|
||||
foreach(var item in CheckBurstJobDisabled()) yield return item;
|
||||
foreach(var item in CheckBurstJobEnabled()) yield return item;
|
||||
}
|
||||
finally
|
||||
{
|
||||
BurstCompiler.Options.EnableBurstCompilation = true;
|
||||
}
|
||||
}
|
||||
|
||||
private IEnumerable CheckBurstJobEnabled()
|
||||
{
|
||||
BurstCompiler.Options.EnableBurstCompilation = true;
|
||||
|
||||
yield return null;
|
||||
|
||||
using (var jobTester = new BurstJobTester2())
|
||||
{
|
||||
var result = jobTester.Calculate();
|
||||
Assert.AreNotEqual(0.0f, result);
|
||||
}
|
||||
}
|
||||
|
||||
private IEnumerable CheckBurstJobDisabled()
|
||||
{
|
||||
BurstCompiler.Options.EnableBurstCompilation = false;
|
||||
|
||||
yield return null;
|
||||
|
||||
using (var jobTester = new BurstJobTester2())
|
||||
{
|
||||
var result = jobTester.Calculate();
|
||||
Assert.AreEqual(0.0f, result);
|
||||
}
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator CheckJobWithNativeArray()
|
||||
{
|
||||
BurstCompiler.Options.EnableBurstCompileSynchronously = true;
|
||||
BurstCompiler.Options.EnableBurstCompilation = true;
|
||||
|
||||
yield return null;
|
||||
|
||||
var job = new BurstJobTester2.MyJobCreatingAndDisposingNativeArray()
|
||||
{
|
||||
Length = 128,
|
||||
Result = new NativeArray<int>(16, Allocator.TempJob)
|
||||
};
|
||||
var handle = job.Schedule();
|
||||
handle.Complete();
|
||||
try
|
||||
{
|
||||
Assert.AreEqual(job.Length, job.Result[0]);
|
||||
}
|
||||
finally
|
||||
{
|
||||
job.Result.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#if UNITY_BURST_BUG_FUNCTION_POINTER_FIXED
|
||||
[UnityTest]
|
||||
public IEnumerator CheckBurstFunctionPointerException()
|
||||
{
|
||||
BurstCompiler.Options.EnableBurstCompileSynchronously = true;
|
||||
BurstCompiler.Options.EnableBurstCompilation = true;
|
||||
|
||||
yield return null;
|
||||
|
||||
using (var jobTester = new BurstJobTester())
|
||||
{
|
||||
var exception = Assert.Throws<InvalidOperationException>(() => jobTester.CheckFunctionPointer());
|
||||
StringAssert.Contains("Exception was thrown from a function compiled with Burst", exception.Message);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
[BurstCompile(CompileSynchronously = true)]
|
||||
private struct HashTestJob : IJob
|
||||
{
|
||||
public NativeArray<int> Hashes;
|
||||
|
||||
public void Execute()
|
||||
{
|
||||
Hashes[0] = BurstRuntime.GetHashCode32<int>();
|
||||
Hashes[1] = TypeHashWrapper.GetIntHash();
|
||||
|
||||
Hashes[2] = BurstRuntime.GetHashCode32<TypeHashWrapper.SomeStruct<int>>();
|
||||
Hashes[3] = TypeHashWrapper.GetGenericHash<int>();
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public static void TestTypeHash()
|
||||
{
|
||||
HashTestJob job = new HashTestJob
|
||||
{
|
||||
Hashes = new NativeArray<int>(4, Allocator.TempJob)
|
||||
};
|
||||
job.Schedule().Complete();
|
||||
|
||||
var hash0 = job.Hashes[0];
|
||||
var hash1 = job.Hashes[1];
|
||||
|
||||
var hash2 = job.Hashes[2];
|
||||
var hash3 = job.Hashes[3];
|
||||
|
||||
job.Hashes.Dispose();
|
||||
|
||||
Assert.AreEqual(hash0, hash1, "BurstRuntime.GetHashCode32<int>() has returned two different hashes");
|
||||
Assert.AreEqual(hash2, hash3, "BurstRuntime.GetHashCode32<SomeStruct<int>>() has returned two different hashes");
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator CheckSafetyChecksWithDomainReload()
|
||||
{
|
||||
{
|
||||
var job = new SafetyCheckJobWithDomainReload();
|
||||
{
|
||||
// Run with safety-checks true
|
||||
BurstCompiler.Options.EnableBurstSafetyChecks = true;
|
||||
job.Result = new NativeArray<int>(1, Allocator.TempJob);
|
||||
try
|
||||
{
|
||||
var handle = job.Schedule();
|
||||
handle.Complete();
|
||||
Assert.AreEqual(2, job.Result[0]);
|
||||
}
|
||||
finally
|
||||
{
|
||||
job.Result.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
// Run with safety-checks false
|
||||
BurstCompiler.Options.EnableBurstSafetyChecks = false;
|
||||
job.Result = new NativeArray<int>(1, Allocator.TempJob);
|
||||
bool hasException = false;
|
||||
try
|
||||
{
|
||||
var handle = job.Schedule();
|
||||
handle.Complete();
|
||||
Assert.AreEqual(1, job.Result[0]);
|
||||
}
|
||||
catch
|
||||
{
|
||||
hasException = true;
|
||||
throw;
|
||||
}
|
||||
finally
|
||||
{
|
||||
job.Result.Dispose();
|
||||
if (hasException)
|
||||
{
|
||||
BurstCompiler.Options.EnableBurstSafetyChecks = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Ask for domain reload
|
||||
EditorUtility.RequestScriptReload();
|
||||
|
||||
// Wait for the domain reload to be completed
|
||||
yield return new WaitForDomainReload();
|
||||
|
||||
{
|
||||
// The safety checks should have been disabled by the previous code
|
||||
Assert.False(BurstCompiler.Options.EnableBurstSafetyChecks);
|
||||
// Restore safety checks
|
||||
BurstCompiler.Options.EnableBurstSafetyChecks = true;
|
||||
}
|
||||
}
|
||||
|
||||
[BurstCompile(CompileSynchronously = true)]
|
||||
private struct DebugLogJob : IJob
|
||||
{
|
||||
public int Value;
|
||||
|
||||
public void Execute()
|
||||
{
|
||||
UnityEngine.Debug.Log($"This is a string logged from a job with burst with the following {Value}");
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public static void TestDebugLog()
|
||||
{
|
||||
var job = new DebugLogJob
|
||||
{
|
||||
Value = 256
|
||||
};
|
||||
job.Schedule().Complete();
|
||||
}
|
||||
|
||||
[BurstCompile(CompileSynchronously = true, Debug = true)]
|
||||
struct DebugLogErrorJob : IJob
|
||||
{
|
||||
public void Execute()
|
||||
{
|
||||
UnityEngine.Debug.LogError("X");
|
||||
}
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator DebugLogError()
|
||||
{
|
||||
LogAssert.Expect(LogType.Error, "X");
|
||||
|
||||
var jobData = new DebugLogErrorJob();
|
||||
jobData.Run();
|
||||
|
||||
yield return null;
|
||||
}
|
||||
|
||||
|
||||
|
||||
[BurstCompile(CompileSynchronously = true)]
|
||||
private struct SafetyCheckJobWithDomainReload : IJob
|
||||
{
|
||||
public NativeArray<int> Result;
|
||||
|
||||
public void Execute()
|
||||
{
|
||||
Result[0] = 1;
|
||||
SetResultWithSafetyChecksOnly();
|
||||
}
|
||||
|
||||
[Conditional("ENABLE_UNITY_COLLECTIONS_CHECKS")]
|
||||
private void SetResultWithSafetyChecksOnly()
|
||||
{
|
||||
Result[0] = 2;
|
||||
}
|
||||
}
|
||||
|
||||
[Conditional("ENABLE_UNITY_COLLECTIONS_CHECKS")]
|
||||
private static void SafelySetSomeBool(ref bool b)
|
||||
{
|
||||
b = true;
|
||||
}
|
||||
|
||||
[BurstCompile(DisableSafetyChecks = false)]
|
||||
private struct EnabledSafetyChecksJob : IJob
|
||||
{
|
||||
[WriteOnly] public NativeArray<int> WasHit;
|
||||
|
||||
public void Execute()
|
||||
{
|
||||
var b = false;
|
||||
SafelySetSomeBool(ref b);
|
||||
WasHit[0] = b ? 1 : 0;
|
||||
}
|
||||
}
|
||||
|
||||
[BurstCompile(DisableSafetyChecks = true)]
|
||||
private struct DisabledSafetyChecksJob : IJob
|
||||
{
|
||||
[WriteOnly] public NativeArray<int> WasHit;
|
||||
|
||||
public void Execute()
|
||||
{
|
||||
var b = false;
|
||||
SafelySetSomeBool(ref b);
|
||||
WasHit[0] = b ? 1 : 0;
|
||||
}
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator CheckSafetyChecksOffGloballyAndOnInJob()
|
||||
{
|
||||
BurstCompiler.Options.EnableBurstSafetyChecks = false;
|
||||
BurstCompiler.Options.ForceEnableBurstSafetyChecks = false;
|
||||
|
||||
yield return null;
|
||||
|
||||
var job = new EnabledSafetyChecksJob()
|
||||
{
|
||||
WasHit = new NativeArray<int>(1, Allocator.TempJob)
|
||||
};
|
||||
|
||||
job.Schedule().Complete();
|
||||
|
||||
try
|
||||
{
|
||||
// Safety checks are off globally which overwrites the job having safety checks on.
|
||||
Assert.AreEqual(0, job.WasHit[0]);
|
||||
}
|
||||
finally
|
||||
{
|
||||
job.WasHit.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator CheckSafetyChecksOffGloballyAndOffInJob()
|
||||
{
|
||||
BurstCompiler.Options.EnableBurstSafetyChecks = false;
|
||||
BurstCompiler.Options.ForceEnableBurstSafetyChecks = false;
|
||||
|
||||
yield return null;
|
||||
|
||||
var job = new DisabledSafetyChecksJob()
|
||||
{
|
||||
WasHit = new NativeArray<int>(1, Allocator.TempJob)
|
||||
};
|
||||
|
||||
job.Schedule().Complete();
|
||||
|
||||
try
|
||||
{
|
||||
// Safety checks are off globally and off in job.
|
||||
Assert.AreEqual(0, job.WasHit[0]);
|
||||
}
|
||||
finally
|
||||
{
|
||||
job.WasHit.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator CheckSafetyChecksOnGloballyAndOnInJob()
|
||||
{
|
||||
BurstCompiler.Options.EnableBurstSafetyChecks = true;
|
||||
BurstCompiler.Options.ForceEnableBurstSafetyChecks = false;
|
||||
|
||||
yield return null;
|
||||
|
||||
var job = new EnabledSafetyChecksJob()
|
||||
{
|
||||
WasHit = new NativeArray<int>(1, Allocator.TempJob)
|
||||
};
|
||||
|
||||
job.Schedule().Complete();
|
||||
|
||||
try
|
||||
{
|
||||
// Safety checks are on globally and on in job.
|
||||
Assert.AreEqual(1, job.WasHit[0]);
|
||||
}
|
||||
finally
|
||||
{
|
||||
job.WasHit.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator CheckSafetyChecksOnGloballyAndOffInJob()
|
||||
{
|
||||
BurstCompiler.Options.EnableBurstSafetyChecks = true;
|
||||
BurstCompiler.Options.ForceEnableBurstSafetyChecks = false;
|
||||
|
||||
yield return null;
|
||||
|
||||
var job = new DisabledSafetyChecksJob()
|
||||
{
|
||||
WasHit = new NativeArray<int>(1, Allocator.TempJob)
|
||||
};
|
||||
|
||||
job.Schedule().Complete();
|
||||
|
||||
try
|
||||
{
|
||||
// Safety checks are on globally but off in job.
|
||||
Assert.AreEqual(0, job.WasHit[0]);
|
||||
}
|
||||
finally
|
||||
{
|
||||
job.WasHit.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator CheckForceSafetyChecksWorks()
|
||||
{
|
||||
BurstCompiler.Options.ForceEnableBurstSafetyChecks = true;
|
||||
|
||||
yield return null;
|
||||
|
||||
var job = new DisabledSafetyChecksJob()
|
||||
{
|
||||
WasHit = new NativeArray<int>(1, Allocator.TempJob)
|
||||
};
|
||||
|
||||
job.Schedule().Complete();
|
||||
|
||||
try
|
||||
{
|
||||
// Even though the job has set disabled safety checks, the menu item 'Force On'
|
||||
// has been set which overrides any other requested behaviour.
|
||||
Assert.AreEqual(1, job.WasHit[0]);
|
||||
}
|
||||
finally
|
||||
{
|
||||
job.WasHit.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator CheckSharedStaticWithDomainReload()
|
||||
{
|
||||
// Check that on a first access, SharedStatic is always empty
|
||||
AssertTestSharedStaticEmpty();
|
||||
|
||||
// Fill with some data
|
||||
TestSharedStatic.SharedValue.Data = new TestSharedStatic(1, 2, 3, 4);
|
||||
|
||||
Assert.AreEqual(1, TestSharedStatic.SharedValue.Data.Value1);
|
||||
Assert.AreEqual(2, TestSharedStatic.SharedValue.Data.Value2);
|
||||
Assert.AreEqual(3, TestSharedStatic.SharedValue.Data.Value3);
|
||||
Assert.AreEqual(4, TestSharedStatic.SharedValue.Data.Value4);
|
||||
|
||||
// Ask for domain reload
|
||||
EditorUtility.RequestScriptReload();
|
||||
|
||||
// Wait for the domain reload to be completed
|
||||
yield return new WaitForDomainReload();
|
||||
|
||||
// Make sure that after a domain reload everything is initialized back to zero
|
||||
AssertTestSharedStaticEmpty();
|
||||
}
|
||||
|
||||
private static void AssertTestSharedStaticEmpty()
|
||||
{
|
||||
Assert.AreEqual(0, TestSharedStatic.SharedValue.Data.Value1);
|
||||
Assert.AreEqual(0, TestSharedStatic.SharedValue.Data.Value2);
|
||||
Assert.AreEqual(0, TestSharedStatic.SharedValue.Data.Value3);
|
||||
Assert.AreEqual(0, TestSharedStatic.SharedValue.Data.Value4);
|
||||
}
|
||||
|
||||
private struct TestSharedStatic
|
||||
{
|
||||
public static readonly SharedStatic<TestSharedStatic> SharedValue = SharedStatic<TestSharedStatic>.GetOrCreate<TestSharedStatic>();
|
||||
|
||||
public TestSharedStatic(int value1, long value2, long value3, long value4)
|
||||
{
|
||||
Value1 = value1;
|
||||
Value2 = value2;
|
||||
Value3 = value3;
|
||||
Value4 = value4;
|
||||
}
|
||||
|
||||
public int Value1;
|
||||
public long Value2;
|
||||
public long Value3;
|
||||
public long Value4;
|
||||
}
|
||||
|
||||
static EditModeTest()
|
||||
{
|
||||
// UnityEngine.Debug.Log("Domain Reload");
|
||||
}
|
||||
[BurstCompile]
|
||||
private static class FunctionPointers
|
||||
{
|
||||
public delegate int SafetyChecksDelegate();
|
||||
|
||||
[BurstCompile(DisableSafetyChecks = false)]
|
||||
public static int WithSafetyChecksEnabled()
|
||||
{
|
||||
var b = false;
|
||||
SafelySetSomeBool(ref b);
|
||||
return b ? 1 : 0;
|
||||
}
|
||||
|
||||
[BurstCompile(DisableSafetyChecks = true)]
|
||||
public static int WithSafetyChecksDisabled()
|
||||
{
|
||||
var b = false;
|
||||
SafelySetSomeBool(ref b);
|
||||
return b ? 1 : 0;
|
||||
}
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator CheckSafetyChecksOffGloballyAndOffInFunctionPointer()
|
||||
{
|
||||
BurstCompiler.Options.EnableBurstSafetyChecks = false;
|
||||
BurstCompiler.Options.ForceEnableBurstSafetyChecks = false;
|
||||
|
||||
yield return null;
|
||||
|
||||
var funcPtr = BurstCompiler.CompileFunctionPointer<FunctionPointers.SafetyChecksDelegate>(FunctionPointers.WithSafetyChecksDisabled);
|
||||
|
||||
// Safety Checks are off globally and off in the job.
|
||||
Assert.AreEqual(0, funcPtr.Invoke());
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator CheckSafetyChecksOffGloballyAndOnInFunctionPointer()
|
||||
{
|
||||
BurstCompiler.Options.EnableBurstSafetyChecks = false;
|
||||
BurstCompiler.Options.ForceEnableBurstSafetyChecks = false;
|
||||
|
||||
yield return null;
|
||||
|
||||
var funcPtr = BurstCompiler.CompileFunctionPointer<FunctionPointers.SafetyChecksDelegate>(FunctionPointers.WithSafetyChecksEnabled);
|
||||
|
||||
// Safety Checks are off globally and on in job, but the global setting takes precedence.
|
||||
Assert.AreEqual(0, funcPtr.Invoke());
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator CheckSafetyChecksOnGloballyAndOffInFunctionPointer()
|
||||
{
|
||||
BurstCompiler.Options.EnableBurstSafetyChecks = true;
|
||||
BurstCompiler.Options.ForceEnableBurstSafetyChecks = false;
|
||||
|
||||
yield return null;
|
||||
|
||||
var funcPtr = BurstCompiler.CompileFunctionPointer<FunctionPointers.SafetyChecksDelegate>(FunctionPointers.WithSafetyChecksDisabled);
|
||||
|
||||
// Safety Checks are on globally and off in the job, so the job takes predence.
|
||||
Assert.AreEqual(0, funcPtr.Invoke());
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator CheckSafetyChecksOnGloballyAndOnInFunctionPointer()
|
||||
{
|
||||
BurstCompiler.Options.EnableBurstSafetyChecks = true;
|
||||
BurstCompiler.Options.ForceEnableBurstSafetyChecks = false;
|
||||
|
||||
yield return null;
|
||||
|
||||
var funcPtr = BurstCompiler.CompileFunctionPointer<FunctionPointers.SafetyChecksDelegate>(FunctionPointers.WithSafetyChecksEnabled);
|
||||
|
||||
// Safety Checks are on globally and on in the job.
|
||||
Assert.AreEqual(1, funcPtr.Invoke());
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator CheckFunctionPointerForceSafetyChecksWorks()
|
||||
{
|
||||
BurstCompiler.Options.ForceEnableBurstSafetyChecks = true;
|
||||
|
||||
yield return null;
|
||||
|
||||
var funcPtr = BurstCompiler.CompileFunctionPointer<FunctionPointers.SafetyChecksDelegate>(FunctionPointers.WithSafetyChecksDisabled);
|
||||
|
||||
// Even though the job has set disabled safety checks, the menu item 'Force On'
|
||||
// has been set which overrides any other requested behaviour.
|
||||
Assert.AreEqual(1, funcPtr.Invoke());
|
||||
}
|
||||
|
||||
[BurstCompile(CompileSynchronously = true)]
|
||||
private struct DebugDrawLineJob : IJob
|
||||
{
|
||||
public void Execute()
|
||||
{
|
||||
Debug.DrawLine(new Vector3(0, 0, 0), new Vector3(5, 0, 0), Color.green);
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestDebugDrawLine()
|
||||
{
|
||||
var job = new DebugDrawLineJob();
|
||||
job.Schedule().Complete();
|
||||
}
|
||||
|
||||
[BurstCompile]
|
||||
private static class ProfilerMarkerWrapper
|
||||
{
|
||||
private static readonly ProfilerMarker StaticMarker = new ProfilerMarker("TestStaticBurst");
|
||||
|
||||
[BurstCompile(CompileSynchronously = true)]
|
||||
public static int CreateAndUseProfilerMarker(int start)
|
||||
{
|
||||
using (StaticMarker.Auto())
|
||||
{
|
||||
var p = new ProfilerMarker("TestBurst");
|
||||
p.Begin();
|
||||
var result = 0;
|
||||
for (var i = start; i < start + 100000; i++)
|
||||
{
|
||||
result += i;
|
||||
}
|
||||
p.End();
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private delegate int IntReturnIntDelegate(int param);
|
||||
|
||||
[Test]
|
||||
public void TestCreateProfilerMarker()
|
||||
{
|
||||
var fp = BurstCompiler.CompileFunctionPointer<IntReturnIntDelegate>(ProfilerMarkerWrapper.CreateAndUseProfilerMarker);
|
||||
fp.Invoke(5);
|
||||
}
|
||||
|
||||
[BurstCompile]
|
||||
private static class EnsureAssemblyBuilderDoesNotInvalidFunctionPointers
|
||||
{
|
||||
[BurstDiscard]
|
||||
private static void MessOnManaged(ref int x) => x = 42;
|
||||
|
||||
[BurstCompile(CompileSynchronously = true)]
|
||||
public static int WithBurst()
|
||||
{
|
||||
int x = 13;
|
||||
MessOnManaged(ref x);
|
||||
return x;
|
||||
}
|
||||
}
|
||||
|
||||
#if !UNITY_2023_1_OR_NEWER
|
||||
[Test]
|
||||
public void TestAssemblyBuilder()
|
||||
{
|
||||
var preBuilder = EnsureAssemblyBuilderDoesNotInvalidFunctionPointers.WithBurst();
|
||||
Assert.AreEqual(13, preBuilder);
|
||||
|
||||
var tempDirectory = Path.GetTempPath();
|
||||
|
||||
var script = Path.Combine(tempDirectory, "BurstGeneratedAssembly.cs");
|
||||
|
||||
File.WriteAllText(script, @"
|
||||
using Unity.Burst;
|
||||
|
||||
namespace BurstGeneratedAssembly
|
||||
{
|
||||
[BurstCompile]
|
||||
public static class MyStuff
|
||||
{
|
||||
[BurstCompile(CompileSynchronously = true)]
|
||||
public static int BurstedFunction(int x) => x + 1;
|
||||
}
|
||||
}
|
||||
|
||||
");
|
||||
|
||||
var dll = Path.Combine(tempDirectory, "BurstGeneratedAssembly.dll");
|
||||
|
||||
var builder = new AssemblyBuilder(dll, script);
|
||||
|
||||
Assert.IsTrue(builder.Build());
|
||||
|
||||
// Busy wait for the build to be done.
|
||||
while (builder.status != AssemblyBuilderStatus.Finished)
|
||||
{
|
||||
Assert.AreEqual(preBuilder, EnsureAssemblyBuilderDoesNotInvalidFunctionPointers.WithBurst());
|
||||
Thread.Sleep(10);
|
||||
}
|
||||
|
||||
Assert.AreEqual(preBuilder, EnsureAssemblyBuilderDoesNotInvalidFunctionPointers.WithBurst());
|
||||
}
|
||||
#endif
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator CheckChangingScriptOptimizationMode()
|
||||
{
|
||||
static void CheckBurstIsEnabled()
|
||||
{
|
||||
using (var jobTester = new BurstJobTester2())
|
||||
{
|
||||
var result = jobTester.Calculate();
|
||||
Assert.AreNotEqual(0.0f, result);
|
||||
}
|
||||
}
|
||||
|
||||
CheckBurstIsEnabled();
|
||||
|
||||
// Switch scripting code optimization mode from Release to Debug.
|
||||
Assert.AreEqual(CodeOptimization.Release, CompilationPipeline.codeOptimization);
|
||||
CompilationPipeline.codeOptimization = CodeOptimization.Debug;
|
||||
|
||||
// Wait for the domain reload to be completed
|
||||
yield return new WaitForDomainReload();
|
||||
|
||||
CheckBurstIsEnabled();
|
||||
|
||||
// Set scripting code optimization mode back to Release.
|
||||
CompilationPipeline.codeOptimization = CodeOptimization.Release;
|
||||
|
||||
// Wait for the domain reload to be completed
|
||||
yield return new WaitForDomainReload();
|
||||
|
||||
CheckBurstIsEnabled();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 581193df6bcc393285dee7fedd436195
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,777 @@
|
|||
using System;
|
||||
using System.Reflection;
|
||||
using NUnit.Framework;
|
||||
using UnityEngine;
|
||||
using UnityEditor;
|
||||
using Unity.Burst.Editor;
|
||||
using System.Text;
|
||||
using Unity.Burst;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using UnityEngine.TestTools.Utils;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
|
||||
[TestFixture]
|
||||
public class LongTextAreaTests
|
||||
{
|
||||
private LongTextArea _textArea;
|
||||
|
||||
[OneTimeSetUp]
|
||||
public void SetUp()
|
||||
{
|
||||
_textArea = new LongTextArea();
|
||||
}
|
||||
|
||||
[Test]
|
||||
[TestCase("", " push rbp\n .seh_pushreg rbp\n", 7, true)]
|
||||
[TestCase("<color=#CCCCCC>", " push rbp\n .seh_pushreg rbp\n", 25, true)]
|
||||
[TestCase("<color=#d7ba7d>", " push rbp\n .seh_pushreg rbp\n", 21 + 15 + 8 + 15, true)]
|
||||
[TestCase("", "\n# hulahop hejsa\n", 5, false)]
|
||||
public void GetStartingColorTagTest(string tag, string text, int textIdx, bool syntaxHighlight)
|
||||
{
|
||||
var disAssembler = new BurstDisassembler();
|
||||
_textArea.SetText("", text, true, disAssembler, disAssembler.Initialize(text, BurstDisassembler.AsmKind.Intel, true, syntaxHighlight));
|
||||
if (!_textArea.CopyColorTags) _textArea.ChangeCopyMode();
|
||||
|
||||
Assert.That(_textArea.GetStartingColorTag(0, textIdx), Is.EqualTo(tag));
|
||||
}
|
||||
|
||||
[Test]
|
||||
[TestCase("", " push rbp\n .seh_pushreg rbp\n", 7, true)]
|
||||
[TestCase("</color>", " push rbp\n .seh_pushreg rbp\n", 25, true)]
|
||||
[TestCase("</color>", " push rbp\n .seh_pushreg rbp\n", 21 + 15 + 8 + 15, true)]
|
||||
[TestCase("", " push rbp\n .seh_pushreg rbp\n", 14 + 15 + 8, true)]
|
||||
[TestCase("", "\n# hulahop hejsa\n", 5, false)]
|
||||
public void GetEndingColorTagTest(string tag, string text, int textIdx, bool syntaxHighlight)
|
||||
{
|
||||
var disAssembler = new BurstDisassembler();
|
||||
_textArea.SetText("", text, true, disAssembler, disAssembler.Initialize(text, BurstDisassembler.AsmKind.Intel, true, syntaxHighlight));
|
||||
if (!_textArea.CopyColorTags) _textArea.ChangeCopyMode();
|
||||
|
||||
Assert.That(_textArea.GetEndingColorTag(0, textIdx), Is.EqualTo(tag));
|
||||
}
|
||||
|
||||
[Test]
|
||||
[TestCase("<color=#FFFF00>hulahop</color> <color=#DCDCAA>hejsa</color>\n", 0, 16, 16)]
|
||||
[TestCase("<color=#FFFF00>hulahop</color>\n <color=#DCDCAA>hejsa</color>\n", 1, 40, 9)]
|
||||
[TestCase("<color=#FFFF00>hulahop</color>\n <color=#DCDCAA>hejsa</color>\n hej", 2, 67, 3)]
|
||||
[TestCase("<color=#FFFF00>hulahop</color> <color=#DCDCAA>hejsa</color>", 0, 15, 15)]
|
||||
[TestCase("\n <color=#4EC9B0>je</color> <color=#d4d4d4>.LBB11_4</color>", 1, 34, 33)]
|
||||
// Test cases for when on enhanced text and not coloured.
|
||||
[TestCase("hulahop hejsa\n", 0, 16, 16)]
|
||||
[TestCase("hulahop\n hejsa\n", 1, 17, 9)]
|
||||
[TestCase("hulahop\n hejsa\n hej", 2, 21, 3)]
|
||||
[TestCase("hulahop hejsa", 0, 15, 15)]
|
||||
public void GetEndIndexOfColoredLineTest(string text, int line, int resTotal, int resRel)
|
||||
{
|
||||
Assert.That(_textArea.GetEndIndexOfColoredLine(text, line), Is.EqualTo((resTotal, resRel)));
|
||||
}
|
||||
|
||||
[Test]
|
||||
[TestCase("hulahop hejsa\n", 0, 16, 16)]
|
||||
[TestCase("hulahop\n hejsa\n", 1, 17, 9)]
|
||||
[TestCase("hulahop\n hejsa\n hej", 2, 21, 3)]
|
||||
[TestCase("hulahop hejsa", 0, 15, 15)]
|
||||
[TestCase("\nhulahop hejsa", 1, 16, 15)]
|
||||
public void GetEndIndexOfPlainLineTest(string text, int line, int resTotal, int resRel)
|
||||
{
|
||||
Assert.That(_textArea.GetEndIndexOfPlainLine(text, line), Is.EqualTo((resTotal, resRel)));
|
||||
}
|
||||
|
||||
[Test]
|
||||
[TestCase("<color=#FFFF00>hulahop</color>\n <color=#DCDCAA>hejsa</color>\n hej", 2, 2, 0)]
|
||||
[TestCase("<color=#FFFF00>hulahop</color>\n <color=#DCDCAA>hejsa</color>\n hej", 1, 5, 15)]
|
||||
[TestCase("<color=#FFFF00>hulahop</color> <color=#DCDCAA>hejsa</color>:", 0, 17, 46)]
|
||||
public void BumpSelectionXByColortagTest(string text, int lineNum, int charsIn, int colourTagFiller)
|
||||
{
|
||||
var (idxTotal, idxRel) = _textArea.GetEndIndexOfColoredLine(text, lineNum);
|
||||
Assert.That(_textArea.BumpSelectionXByColorTag(text, idxTotal - idxRel, charsIn), Is.EqualTo(charsIn + colourTagFiller));
|
||||
}
|
||||
|
||||
[Test]
|
||||
[TestCase(" push rbp\n .seh_pushreg rbp\n", false)]
|
||||
[TestCase(" push rbp\n .seh_pushreg rbp\n", true)]
|
||||
public void SelectAllTest(string text, bool useDisassembler)
|
||||
{
|
||||
if (useDisassembler)
|
||||
{
|
||||
var disAssembler = new BurstDisassembler();
|
||||
_textArea.SetText("", text, true, disAssembler, disAssembler.Initialize(text, BurstDisassembler.AsmKind.Intel));
|
||||
_textArea.LayoutEnhanced(GUIStyle.none, Rect.zero, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
_textArea.SetText("", text, true, null, false);
|
||||
}
|
||||
|
||||
|
||||
_textArea.selectPos = new Vector2(2, 2);
|
||||
// There is no inserted comments or similar in my test example, so finalAreaSize, should be equivalent for the two.
|
||||
_textArea.finalAreaSize = new Vector2(7.5f * text.Length, 15.2f);
|
||||
|
||||
_textArea.SelectAll();
|
||||
Assert.That(_textArea.selectPos, Is.EqualTo(Vector2.zero));
|
||||
Assert.That(_textArea.selectDragPos, Is.EqualTo(new Vector2(7.5f * text.Length, 15.2f)));
|
||||
|
||||
if (!useDisassembler)
|
||||
{
|
||||
Assert.That(_textArea.textSelectionIdx, Is.EqualTo((0, text.Length)));
|
||||
}
|
||||
}
|
||||
|
||||
private BurstDisassembler GetDisassemblerandText(string compileTargetName, int debugLvl, out string textToRender)
|
||||
{
|
||||
// Get target job assembly:
|
||||
var assemblies = BurstReflection.EditorAssembliesThatCanPossiblyContainJobs;
|
||||
var result = BurstReflection.FindExecuteMethods(assemblies, BurstReflectionAssemblyOptions.None);
|
||||
var compileTarget = result.CompileTargets.Find(x => x.GetDisplayName() == compileTargetName);
|
||||
|
||||
Assert.IsTrue(compileTarget != default, $"Could not find compile target: {compileTarget}");
|
||||
|
||||
BurstDisassembler disassembler = new BurstDisassembler();
|
||||
|
||||
var options = new StringBuilder();
|
||||
|
||||
compileTarget.Options.TryGetOptions(compileTarget.JobType, true, out string defaultOptions);
|
||||
options.AppendLine(defaultOptions);
|
||||
// Disables the 2 current warnings generated from code (since they clutter up the inspector display)
|
||||
// BC1370 - throw inside code not guarded with ConditionalSafetyCheck attribute
|
||||
// BC1322 - loop intrinsic on loop that has been optimised away
|
||||
options.AppendLine($"{BurstCompilerOptions.GetOption(BurstCompilerOptions.OptionDisableWarnings, "BC1370;BC1322")}");
|
||||
|
||||
options.AppendLine($"{BurstCompilerOptions.GetOption(BurstCompilerOptions.OptionTarget, BurstTargetCpu.X64_SSE4)}");
|
||||
|
||||
options.AppendLine($"{BurstCompilerOptions.GetOption(BurstCompilerOptions.OptionDebug, $"{debugLvl}")}");
|
||||
|
||||
var baseOptions = options.ToString();
|
||||
|
||||
var append = BurstInspectorGUI.GetDisasmOptions()[(int)DisassemblyKind.Asm];
|
||||
|
||||
// Setup disAssembler with the job:
|
||||
compileTarget.RawDisassembly = BurstInspectorGUI.GetDisassembly(compileTarget.Method, baseOptions + append);
|
||||
textToRender = compileTarget.RawDisassembly.TrimStart('\n');
|
||||
|
||||
return disassembler;
|
||||
}
|
||||
|
||||
[Test]
|
||||
[TestCase(true, true, 2)]
|
||||
[TestCase(true, true, 1)]
|
||||
[TestCase(true, false, 2)]
|
||||
[TestCase(true, false, 1)]
|
||||
[TestCase(false, true, 2)]
|
||||
[TestCase(false, true, 1)]
|
||||
[TestCase(false, false, 2)]
|
||||
[TestCase(false, false, 1)]
|
||||
public void CopyAllTest(bool useDisassembler, bool coloured, int debugLvl)
|
||||
{
|
||||
// Get target job assembly:
|
||||
var disassembler = new BurstDisassembler();
|
||||
var thisPath = Path.GetDirectoryName(GetThisFilePath());
|
||||
var textToRender = File.ReadAllText(Path.Combine(thisPath, _burstJobPath));
|
||||
|
||||
|
||||
if (useDisassembler)
|
||||
{
|
||||
_textArea.SetText("", textToRender, true, disassembler, disassembler.Initialize(textToRender, BurstDisassembler.AsmKind.Intel, true, coloured));
|
||||
_textArea.ExpandAllBlocks();
|
||||
|
||||
var builder = new StringBuilder();
|
||||
|
||||
for (int i = 0; i < disassembler.Blocks.Count; i++)
|
||||
{
|
||||
builder.Append(disassembler.GetOrRenderBlockToText(i));
|
||||
}
|
||||
|
||||
textToRender = builder.ToString();
|
||||
}
|
||||
else
|
||||
{
|
||||
_textArea.SetText("", textToRender, true, null, false);
|
||||
}
|
||||
|
||||
_textArea.Layout(GUIStyle.none, _textArea.horizontalPad);
|
||||
|
||||
_textArea.SelectAll();
|
||||
_textArea.DoSelectionCopy();
|
||||
|
||||
Assert.AreEqual(textToRender, EditorGUIUtility.systemCopyBuffer);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void CopyAllTextWithoutColorTagsTest()
|
||||
{
|
||||
// Setup:
|
||||
var disassembler = new BurstDisassembler();
|
||||
var thisPath = Path.GetDirectoryName(GetThisFilePath());
|
||||
var textToRender = File.ReadAllText(Path.Combine(thisPath, _burstJobPath));
|
||||
|
||||
_textArea.SetText("", textToRender, true, disassembler,
|
||||
disassembler.Initialize(
|
||||
textToRender,
|
||||
BurstDisassembler.AsmKind.Intel));
|
||||
|
||||
_textArea.Layout(GUIStyle.none, _textArea.horizontalPad);
|
||||
_textArea.LayoutEnhanced(GUIStyle.none, Rect.zero, true);
|
||||
|
||||
// Actual test to reproduce error:
|
||||
_textArea.ChangeCopyMode();
|
||||
_textArea.SelectAll();
|
||||
Assert.DoesNotThrow(_textArea.DoSelectionCopy);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void CopyTextAfterSelectionMovedTest()
|
||||
{
|
||||
// Setup:
|
||||
const bool sbm = true;
|
||||
var wa = Rect.zero;
|
||||
|
||||
var disassembler = new BurstDisassembler();
|
||||
var thisPath = Path.GetDirectoryName(GetThisFilePath());
|
||||
var textToRender = File.ReadAllText(Path.Combine(thisPath, _burstJobPath));
|
||||
|
||||
_textArea.SetText("", textToRender, true, disassembler,
|
||||
disassembler.Initialize(
|
||||
textToRender,
|
||||
BurstDisassembler.AsmKind.Intel));
|
||||
|
||||
_textArea.Layout(GUIStyle.none, _textArea.horizontalPad);
|
||||
_textArea.LayoutEnhanced(GUIStyle.none, Rect.zero, sbm);
|
||||
|
||||
// Actual test to reproduce error:
|
||||
_textArea.ChangeCopyMode();
|
||||
|
||||
_textArea.MoveSelectionDown(wa, sbm);
|
||||
_textArea.MoveSelectionDown(wa, sbm);
|
||||
_textArea.MoveSelectionLeft(wa, sbm);
|
||||
|
||||
Assert.DoesNotThrow(_textArea.DoSelectionCopy);
|
||||
|
||||
_textArea.MoveSelectionRight(wa, sbm);
|
||||
Assert.DoesNotThrow(_textArea.DoSelectionCopy);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void CopyTextIdenticalWithAndWithoutColorTags()
|
||||
{
|
||||
// We don't wanna go messing with the users system buffer. At least if user didn't break anything.
|
||||
var savedSystemBuffer = EditorGUIUtility.systemCopyBuffer;
|
||||
|
||||
// Get target job assembly:
|
||||
var disassembler = new BurstDisassembler();
|
||||
var thisPath = Path.GetDirectoryName(GetThisFilePath());
|
||||
var textToRender = File.ReadAllText(Path.Combine(thisPath, _burstJobPath));
|
||||
|
||||
_textArea.SetText("", textToRender, true, disassembler,
|
||||
disassembler.Initialize(
|
||||
textToRender,
|
||||
BurstDisassembler.AsmKind.Intel));
|
||||
|
||||
_textArea.Layout(GUIStyle.none, _textArea.horizontalPad);
|
||||
_textArea.LayoutEnhanced(GUIStyle.none, Rect.zero, true);
|
||||
for (var i=0; i<disassembler.Blocks[0].Length+50; i++) _textArea.MoveSelectionDown(Rect.zero, true);
|
||||
|
||||
_textArea.LayoutEnhanced(GUIStyle.none, Rect.zero, true);
|
||||
_textArea.UpdateEnhancedSelectTextIdx(_textArea.horizontalPad);
|
||||
|
||||
_textArea.DoSelectionCopy();
|
||||
var copiedText1 = EditorGUIUtility.systemCopyBuffer;
|
||||
|
||||
_textArea.ChangeCopyMode();
|
||||
_textArea.DoSelectionCopy();
|
||||
var copiedText2 = EditorGUIUtility.systemCopyBuffer;
|
||||
|
||||
var regx = new Regex(@"(<color=#[0-9A-Za-z]*>)|(</color>)");
|
||||
|
||||
if (!_textArea.CopyColorTags)
|
||||
{
|
||||
(copiedText1, copiedText2) = (copiedText2, copiedText1);
|
||||
}
|
||||
copiedText2 = regx.Replace(copiedText2, "");
|
||||
|
||||
EditorGUIUtility.systemCopyBuffer = savedSystemBuffer;
|
||||
Assert.AreEqual(copiedText1, copiedText2,
|
||||
"Copy with color tags did not match copy without " +
|
||||
"(Color tags is removed from the copy to make it comparable with the color-tag-less copy).");
|
||||
}
|
||||
|
||||
// Disabled due to https://jira.unity3d.com/browse/BUR-2207
|
||||
[Test]
|
||||
[TestCase(true)]
|
||||
[TestCase(false)]
|
||||
public void KeepingSelectionWhenMovingTest(bool useDisassembler)
|
||||
{
|
||||
const string jobName = "BurstInspectorGUITests.MyJob - (IJob)";
|
||||
BurstDisassembler disassembler = new BurstDisassembler();
|
||||
var thisPath = Path.GetDirectoryName(GetThisFilePath());
|
||||
var textToRender = File.ReadAllText(Path.Combine(thisPath, _burstJobPath));
|
||||
Rect workingArea = new Rect();
|
||||
|
||||
if (useDisassembler)
|
||||
{
|
||||
_textArea.SetText(jobName, textToRender, true, disassembler, disassembler.Initialize(textToRender, BurstDisassembler.AsmKind.Intel));
|
||||
_textArea.LayoutEnhanced(GUIStyle.none, workingArea, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
_textArea.SetText(jobName, textToRender, false, null, false);
|
||||
}
|
||||
_textArea.Layout(GUIStyle.none, _textArea.horizontalPad);
|
||||
|
||||
Assert.IsFalse(_textArea.HasSelection);
|
||||
|
||||
Vector2 start = _textArea.selectDragPos;
|
||||
if (useDisassembler) start.x = _textArea.horizontalPad + _textArea.fontWidth / 2;
|
||||
|
||||
// Horizontal movement:
|
||||
_textArea.MoveSelectionRight(workingArea, true);
|
||||
Assert.IsTrue(_textArea.HasSelection);
|
||||
Assert.AreEqual(start + new Vector2(_textArea.fontWidth, 0), _textArea.selectDragPos);
|
||||
|
||||
_textArea.MoveSelectionLeft(workingArea, true);
|
||||
Assert.IsTrue(_textArea.HasSelection);
|
||||
Assert.AreEqual(start, _textArea.selectDragPos);
|
||||
|
||||
// Vertical movement:
|
||||
_textArea.MoveSelectionDown(workingArea, true);
|
||||
Assert.IsTrue(_textArea.HasSelection);
|
||||
Assert.AreEqual(start + new Vector2(0, _textArea.fontHeight), _textArea.selectDragPos);
|
||||
|
||||
_textArea.MoveSelectionUp(workingArea, true);
|
||||
Assert.IsTrue(_textArea.HasSelection);
|
||||
Assert.AreEqual(start, _textArea.selectDragPos);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetFragNrFromBlockIdxTest()
|
||||
{
|
||||
var disassembler = new BurstDisassembler();
|
||||
var thisPath = Path.GetDirectoryName(GetThisFilePath());
|
||||
var textToRender = File.ReadAllText(Path.Combine(thisPath, _burstJobPath));
|
||||
|
||||
_textArea.SetText("", textToRender, true, disassembler,
|
||||
disassembler.Initialize(textToRender, BurstDisassembler.AsmKind.Intel, false, false));
|
||||
|
||||
|
||||
var garbageVariable = 0f;
|
||||
var numBlocks = disassembler.Blocks.Count;
|
||||
|
||||
// Want to get the last fragment possible
|
||||
var expectedFragNr = 0;
|
||||
for (var i = 0; i < _textArea.blocksFragmentsPlain.Length-1; i++)
|
||||
{
|
||||
expectedFragNr += _textArea.GetPlainFragments(i).Count;
|
||||
}
|
||||
|
||||
Assert.AreEqual(expectedFragNr, _textArea.GetFragNrFromBlockIdx(numBlocks-1, 0, 0, ref garbageVariable));
|
||||
|
||||
Assert.AreEqual(3, _textArea.GetFragNrFromBlockIdx(3, 1, 1, ref garbageVariable));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetFragNrFromEnhancedTextIdxTest()
|
||||
{
|
||||
const string jobName = "BurstJobTester2.MyJob - (IJob)";
|
||||
|
||||
var disassembler = new BurstDisassembler();
|
||||
var thisPath = Path.GetDirectoryName(GetThisFilePath());
|
||||
var textToRender = File.ReadAllText(Path.Combine(thisPath, _burstJobPath));
|
||||
_textArea.SetText(jobName, textToRender, true, disassembler,
|
||||
disassembler.Initialize(textToRender, BurstDisassembler.AsmKind.Intel, false, false));
|
||||
|
||||
var garbageVariable = 0f;
|
||||
const int blockIdx = 2;
|
||||
|
||||
var fragments = _textArea.RecomputeFragmentsFromBlock(blockIdx);
|
||||
var text = _textArea.GetText;
|
||||
var expectedFrag = blockIdx + fragments.Count - 1;
|
||||
|
||||
var info = disassembler.BlockIdxs[blockIdx];
|
||||
|
||||
var extraFragLen = fragments.Count > 1
|
||||
? fragments[0].text.Length + 1 // job only contains 2 fragments at max
|
||||
: 0;
|
||||
|
||||
var idx = info.startIdx + extraFragLen + 1;
|
||||
|
||||
var expected = (expectedFrag, info.startIdx + extraFragLen);
|
||||
var actual = _textArea.GetFragNrFromEnhancedTextIdx(idx, 0, 0, 0, ref garbageVariable);
|
||||
|
||||
Assert.AreEqual(expected, actual);
|
||||
}
|
||||
|
||||
[Test]
|
||||
[TestCase(true)]
|
||||
[TestCase(false)]
|
||||
public void SearchTextEnhancedTest(bool colored)
|
||||
{
|
||||
var disassembler = new BurstDisassembler();
|
||||
var thisPath = Path.GetDirectoryName(GetThisFilePath());
|
||||
var textToRender = File.ReadAllText(Path.Combine(thisPath, _burstJobPath));
|
||||
_textArea.SetText("", textToRender, true, disassembler, disassembler.Initialize(textToRender, BurstDisassembler.AsmKind.Intel, true, colored));
|
||||
|
||||
var workingArea = new Rect(0, 0, 10, 10);
|
||||
_textArea.SearchText(new SearchCriteria(".Ltmp.:", true, false, true), new Regex(@"\.Ltmp.:"), ref workingArea);
|
||||
|
||||
Assert.AreEqual(10, _textArea.NrSearchHits);
|
||||
|
||||
// Check that they are filled out probably
|
||||
int nr = 0;
|
||||
foreach (var fragHits in _textArea.searchHits.Values)
|
||||
{
|
||||
foreach (var hit in fragHits)
|
||||
{
|
||||
Assert.AreEqual((0, 7, nr++), hit);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void SelectOnOneLineTest()
|
||||
{
|
||||
const string testCase = "\n<color=#d4d4d4>.Ltmp12</color>: ...";
|
||||
|
||||
var disassembler = new BurstDisassembler();
|
||||
_textArea.SetText("", testCase, false, disassembler, disassembler.Initialize(testCase, BurstDisassembler.AsmKind.Intel));
|
||||
|
||||
// Set fontWidth and fontHeight
|
||||
_textArea.Layout(GUIStyle.none, 20f);
|
||||
|
||||
// Set selection markers.
|
||||
// Error happened when selection started at the lowest point of a line.
|
||||
_textArea.selectPos = new Vector2(0, _textArea.fontHeight);
|
||||
// Select further down to make sure it wont be switched with selectPos.
|
||||
_textArea.selectDragPos = new Vector2(10 * _textArea.fontWidth, _textArea.fontHeight*2);
|
||||
|
||||
// Hopefully it wont throw anything
|
||||
Assert.DoesNotThrow(() =>
|
||||
_textArea.PrepareInfoForSelection(0, 0, _textArea.fontHeight,
|
||||
new LongTextArea.Fragment() { text = testCase.TrimStart('\n'), lineCount = 1 },
|
||||
_textArea.GetEndIndexOfColoredLine));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetLineHighlightTest()
|
||||
{
|
||||
const float hPad = 20f;
|
||||
const int linePressed = 4 + 13;
|
||||
// Get target job assembly:
|
||||
var disassembler = new BurstDisassembler();
|
||||
var thisPath = Path.GetDirectoryName(GetThisFilePath());
|
||||
var textToRender = File.ReadAllText(Path.Combine(thisPath, _burstJobPath));
|
||||
|
||||
// Set up dependencies for GetLineHighlight(.)
|
||||
_textArea.SetText("", textToRender, true, disassembler,
|
||||
disassembler.Initialize(
|
||||
textToRender,
|
||||
BurstDisassembler.AsmKind.Intel)
|
||||
);
|
||||
|
||||
_textArea.Layout(GUIStyle.none, hPad);
|
||||
_textArea.LayoutEnhanced(GUIStyle.none,
|
||||
new Rect(0,0, _textArea.fontWidth*50,_textArea.fontHeight*50),
|
||||
false
|
||||
);
|
||||
|
||||
// Setup simple cache.
|
||||
var cache = new LongTextArea.LineRegRectsCache();
|
||||
var rect = _textArea.GetLineHighlight(ref cache, hPad, linePressed);
|
||||
Assert.IsFalse(cache.IsRegistersCached(linePressed));
|
||||
Assert.IsTrue(cache.IsLineHighlightCached(linePressed, false));
|
||||
|
||||
var expectedX = hPad;
|
||||
var b = 0;
|
||||
for (; b < disassembler.Blocks.Count; b++)
|
||||
{
|
||||
if (disassembler.Blocks[b].LineIndex > linePressed)
|
||||
{
|
||||
b--;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
var expectedY = (_textArea.blockLine[b] + (linePressed - disassembler.Blocks[b].LineIndex)) * _textArea.fontHeight + _textArea.fontHeight;
|
||||
var lineStr = _textArea.GetLineString(disassembler.Lines[linePressed]);
|
||||
var lineLen = lineStr.Length * _textArea.fontWidth;
|
||||
|
||||
var expected = new Rect(expectedX,
|
||||
expectedY,
|
||||
lineLen,
|
||||
2f
|
||||
);
|
||||
|
||||
var result = Mathf.Approximately(expectedX, rect.x)
|
||||
&& Mathf.Approximately(expectedY, rect.y)
|
||||
&& Mathf.Approximately(lineLen, rect.width)
|
||||
&& Mathf.Approximately(2f, rect.height);
|
||||
|
||||
Assert.IsTrue(result, $"line highlight for \"{lineStr}\" was wrong.\nExpected: {expected}\nBut was: {rect}");
|
||||
}
|
||||
|
||||
|
||||
[Test]
|
||||
public void GetRegRectsTest()
|
||||
{
|
||||
#region Initialize-test-states
|
||||
const float hPad = 20f;
|
||||
const int linePressed = 8 + 13;
|
||||
// Get target job assembly:
|
||||
var disassembler = new BurstDisassembler();
|
||||
var thisPath = Path.GetDirectoryName(GetThisFilePath());
|
||||
var textToRender = File.ReadAllText(Path.Combine(thisPath, _burstJobPath));
|
||||
|
||||
// Set up dependencies for GetLineHighlight(.)
|
||||
_textArea.SetText("", textToRender, true, disassembler,
|
||||
disassembler.Initialize(
|
||||
textToRender,
|
||||
BurstDisassembler.AsmKind.Intel)
|
||||
);
|
||||
// Setting up variables to determine view size:
|
||||
_textArea.Layout(GUIStyle.none, hPad);
|
||||
_textArea.LayoutEnhanced(GUIStyle.none, Rect.zero, false);
|
||||
#endregion
|
||||
|
||||
// Find the block index to put within view:
|
||||
var blockIdx = disassembler.Blocks.Count/2;
|
||||
for (; blockIdx > 0; blockIdx--)
|
||||
{
|
||||
// Take the first block where we know the lastLine will be in the next block.
|
||||
if (!_textArea._folded[blockIdx + 1] && disassembler.Blocks[blockIdx].Length >= 5) break;
|
||||
}
|
||||
// Initialize states with regards to view:
|
||||
_textArea.Layout(GUIStyle.none, hPad);
|
||||
_textArea.LayoutEnhanced(GUIStyle.none,
|
||||
new Rect(0,0, _textArea.fontWidth*100,_textArea.fontHeight*(_textArea.blockLine[blockIdx]+1)),
|
||||
false
|
||||
);
|
||||
|
||||
#region Function-to-test-call
|
||||
var cache = new LongTextArea.LineRegRectsCache();
|
||||
var registersUsed = new List<string> { "rbp", "rsp" };
|
||||
var rects = _textArea.GetRegisterRects(hPad, ref cache, linePressed, registersUsed);
|
||||
#endregion
|
||||
#region Expected-variables
|
||||
var lastLine = disassembler.Blocks[_textArea._renderBlockEnd+1].LineIndex + 4;
|
||||
|
||||
var expectedRbp =
|
||||
(from pair in disassembler._registersUsedAtLine._linesRegisters.TakeWhile(x => x.Key < lastLine)
|
||||
where pair.Value.Contains("rbp") && disassembler.Lines[pair.Key].Kind != BurstDisassembler.AsmLineKind.Directive
|
||||
select pair);
|
||||
var expectedRsp =
|
||||
(from pair in disassembler._registersUsedAtLine._linesRegisters.TakeWhile(x => x.Key < lastLine)
|
||||
where pair.Value.Contains("rsp") && disassembler.Lines[pair.Key].Kind != BurstDisassembler.AsmLineKind.Directive
|
||||
select pair);
|
||||
|
||||
// Check that they are correctly placed!
|
||||
// Only check the last here, as under development the "hardest" behaviour was from within the lowest blocks.
|
||||
var lastRectLineIdx = expectedRbp.Last().Key;
|
||||
var lastRectLine = disassembler.Lines[lastRectLineIdx];
|
||||
var lastRectLineStr = _textArea.GetLineString(lastRectLine);
|
||||
|
||||
var expectedX = lastRectLineStr.Substring(0, lastRectLineStr.IndexOf("rbp")).Length * _textArea.fontWidth + hPad + 2f;
|
||||
#endregion
|
||||
|
||||
Assert.IsTrue(cache.IsRegistersCached(linePressed), "Register Rect cache not probarly setup.");
|
||||
Assert.IsFalse(cache.IsLineHighlightCached(linePressed, false), "Line highlight cache faultily set to cached.");
|
||||
|
||||
Assert.AreEqual(2, rects.Length, "Register Rect cache does not have correct number of registered registers.");
|
||||
Assert.AreEqual(expectedRbp.Count(), rects[0].Count, "Did not find all \"rbp\" registers.");
|
||||
Assert.AreEqual(expectedRsp.Count(), rects[1].Count, "Did not find all \"rsp\" registers.");
|
||||
Assert.That(rects[0][rects[0].Count - 1].x, Is.EqualTo(expectedX).Using(FloatEqualityComparer.Instance),
|
||||
"Wrong x position for last found \"rbp\" rect.");
|
||||
// Note: Does not check Y position, as this is highly dependent on architecture, making it annoyingly hard
|
||||
// to reason about.
|
||||
}
|
||||
|
||||
|
||||
[Test]
|
||||
public void RegsRectCacheTest()
|
||||
{
|
||||
const float hPad = 20f;
|
||||
const int linePressed = 8 + 13;
|
||||
// Get target job assembly:
|
||||
var disassembler = new BurstDisassembler();
|
||||
var thisPath = Path.GetDirectoryName(GetThisFilePath());
|
||||
var textToRender = File.ReadAllText(Path.Combine(thisPath, _burstJobPath));
|
||||
|
||||
// Set up dependencies for GetLineHighlight(.)
|
||||
_textArea.SetText("", textToRender, true, disassembler,
|
||||
disassembler.Initialize(
|
||||
textToRender,
|
||||
BurstDisassembler.AsmKind.Intel)
|
||||
);
|
||||
|
||||
_textArea.Layout(GUIStyle.none, hPad);
|
||||
var yStart = 0f;
|
||||
var yHeight = _textArea.fontHeight*44;
|
||||
_textArea.LayoutEnhanced(GUIStyle.none,
|
||||
new Rect(0,yStart, _textArea.fontWidth*100,yHeight),
|
||||
false
|
||||
);
|
||||
|
||||
var cache = new LongTextArea.LineRegRectsCache();
|
||||
var registersUsed = new List<string> { "rbp", "rsp" };
|
||||
var rects = _textArea.GetRegisterRects(hPad, ref cache, linePressed, registersUsed);
|
||||
Assert.IsTrue(cache.IsRegistersCached(linePressed));
|
||||
var cachedItems =
|
||||
(from elm in rects
|
||||
select elm.Count).Sum();
|
||||
|
||||
yStart = yHeight;
|
||||
_textArea.Layout(GUIStyle.none, hPad);
|
||||
_textArea.LayoutEnhanced(GUIStyle.none,
|
||||
new Rect(0,yStart, _textArea.fontWidth*100,yHeight),
|
||||
false
|
||||
);
|
||||
|
||||
rects = _textArea.GetRegisterRects(hPad, ref cache, linePressed, registersUsed);
|
||||
Assert.IsTrue(cache.IsRegistersCached(linePressed));
|
||||
var cachedItems2 =
|
||||
(from elm in rects
|
||||
select elm.Count).Sum();
|
||||
Assert.IsTrue(cachedItems2 >= cachedItems);
|
||||
}
|
||||
|
||||
[Test]
|
||||
[TestCase("\n xor r9d, r9d\n", "r9d")]
|
||||
[TestCase("\n push edx rdx\n", "rdx")]
|
||||
public void SameRegisterUsedTwiceTest(string line, string reg)
|
||||
{
|
||||
const float hPad = 20f;
|
||||
const int linePressed = 0;
|
||||
|
||||
// Get target job assembly:
|
||||
var disassembler = new BurstDisassembler();
|
||||
|
||||
// Set up dependencies for GetLineHighlight(.)
|
||||
_textArea.SetText("", line, true, disassembler,
|
||||
disassembler.Initialize(
|
||||
line,
|
||||
BurstDisassembler.AsmKind.Intel)
|
||||
);
|
||||
|
||||
_textArea.Layout(GUIStyle.none, hPad);
|
||||
var yStart = 0f;
|
||||
var yHeight = _textArea.fontHeight;
|
||||
_textArea.LayoutEnhanced(GUIStyle.none,
|
||||
new Rect(0,yStart, _textArea.fontWidth*100,yHeight),
|
||||
false
|
||||
);
|
||||
|
||||
var cache = new LongTextArea.LineRegRectsCache();
|
||||
var registersUsed = new List<string> { reg };
|
||||
var rects = _textArea.GetRegisterRects(hPad, ref cache, linePressed, registersUsed);
|
||||
Assert.IsTrue(cache.IsRegistersCached(linePressed));
|
||||
Assert.IsTrue(rects.Length == 1);
|
||||
Assert.IsTrue(rects[0].Count == 2, "Did not find exactly both registers.");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This test should check whether line press information is cleared when it is necessary.
|
||||
/// It does not check whether it is unnecessarily cleared.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void ClearLinePressTest()
|
||||
{
|
||||
void SetupCache(float pad, int lineNr, ref LongTextArea.LineRegRectsCache cache, List<string> regsUsed)
|
||||
{
|
||||
_textArea._pressedLine = lineNr;
|
||||
_ = _textArea.GetRegisterRects(pad, ref cache, lineNr, regsUsed);
|
||||
_ = _textArea.GetLineHighlight(ref cache, pad, lineNr);
|
||||
}
|
||||
|
||||
// Test setup:
|
||||
var registersUsed = new List<string> { "rbp", "rsp" };
|
||||
const float hPad = 20f;
|
||||
const int linePressed = 4 + 13;
|
||||
|
||||
var disassembler = new BurstDisassembler();
|
||||
var thisPath = Path.GetDirectoryName(GetThisFilePath());
|
||||
Assert.NotNull(thisPath, "Could not retrieve path for current directory.");
|
||||
var textToRender = File.ReadAllText(Path.Combine(thisPath, _burstJobPath));
|
||||
|
||||
// Set up dependencies for GetLineHighlight(.)
|
||||
_textArea.SetText("", textToRender, true, disassembler,
|
||||
disassembler.Initialize(
|
||||
textToRender,
|
||||
BurstDisassembler.AsmKind.Intel)
|
||||
);
|
||||
|
||||
// Setting up variables to determine view size:
|
||||
_textArea.Layout(GUIStyle.none, hPad);
|
||||
_textArea.LayoutEnhanced(GUIStyle.none, Rect.zero, false);
|
||||
|
||||
var blockIdx = _textArea.GetLinesBlockIdx(linePressed);
|
||||
|
||||
_textArea.Layout(GUIStyle.none, hPad);
|
||||
_textArea.LayoutEnhanced(GUIStyle.none,
|
||||
new Rect(0,0, _textArea.fontWidth*100,_textArea.fontHeight*(_textArea.blockLine[blockIdx]+1)),
|
||||
false);
|
||||
|
||||
|
||||
void TestCache(bool isLineRect, bool isRect, bool isLine, string msg)
|
||||
{
|
||||
Assert.AreEqual(isLineRect,
|
||||
_textArea._lineRegCache.IsLineHighlightCached(linePressed, _textArea._folded[blockIdx]),
|
||||
msg + " Line highlight failed.");
|
||||
Assert.AreEqual(isRect,
|
||||
_textArea._lineRegCache.IsRegistersCached(linePressed),
|
||||
msg + " Register cache failed.");
|
||||
|
||||
msg += " Line press failed.";
|
||||
if (!isLine)
|
||||
{
|
||||
Assert.AreEqual(-1, _textArea._pressedLine, msg);
|
||||
}
|
||||
else
|
||||
{
|
||||
Assert.AreNotEqual(-1, _textArea._pressedLine, msg);
|
||||
}
|
||||
|
||||
SetupCache(hPad, linePressed, ref _textArea._lineRegCache, registersUsed);
|
||||
}
|
||||
|
||||
|
||||
SetupCache(hPad, linePressed, ref _textArea._lineRegCache, registersUsed);
|
||||
TestCache(true, true, true, "Initial setup failed.");
|
||||
|
||||
// Following changes should result in clearing everything, as assembly text might have changed:
|
||||
// * Expand all.
|
||||
_textArea.ExpandAllBlocks();
|
||||
TestCache(false, false, false, "Expanding blocks failed.");
|
||||
|
||||
// * Focus code.
|
||||
_textArea.FocusCodeBlocks();
|
||||
TestCache(false, false, false, "Focusing code blocks failed.");
|
||||
|
||||
// * disassembly kind, Target change, Safety check changes, Assembly kind changes e.g. by amount of debug info.
|
||||
_textArea.SetText("", textToRender, true, disassembler,
|
||||
disassembler.Initialize(
|
||||
textToRender,
|
||||
BurstDisassembler.AsmKind.Intel)
|
||||
);
|
||||
TestCache(false, false, false, "Setting up new text failed.");
|
||||
|
||||
// Following changes should only result in Rec change clear, as line number still resembles same line:
|
||||
// * Font size.
|
||||
_textArea.Invalidate();
|
||||
TestCache(false, false, true, "Changing font size failed.");
|
||||
|
||||
// * Show branch flow.
|
||||
_textArea.LayoutEnhanced(GUIStyle.none,
|
||||
new Rect(0,0, _textArea.fontWidth*100,_textArea.fontHeight*(_textArea.blockLine[blockIdx]+1)),
|
||||
true);
|
||||
TestCache(false, false, true, "Changing font size failed.");
|
||||
|
||||
// * Smell test (This will however clear everything as ´SetText()´ required).
|
||||
// Hence tested in the cases for fill clear.
|
||||
}
|
||||
|
||||
|
||||
private static string GetThisFilePath([CallerFilePath] string path = null) => path;
|
||||
private readonly string _burstJobPath = "burstTestTarget.txt";
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: b866f2ae2314368d97e916270883416e
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: fa45014e48e13a5ea49fd421043ee143
|
||||
folderAsset: yes
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
public class BurstReflectionTestsSeparateAssembly
|
||||
{
|
||||
[Unity.Jobs.LowLevel.Unsafe.JobProducerType(typeof(MyJobProducerSeparateAssembly<,>))]
|
||||
public interface IMyGenericJobSeparateAssembly<T>
|
||||
{
|
||||
void Execute();
|
||||
}
|
||||
|
||||
private static class MyJobProducerSeparateAssembly<TJob, T>
|
||||
{
|
||||
public static void Execute(ref TJob job)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 9c07004be90d3814b9a09f7d08b26eb1
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
{
|
||||
"name": "SeparateAssembly",
|
||||
"references": [
|
||||
"Unity.Burst"
|
||||
],
|
||||
"includePlatforms": [],
|
||||
"optionalUnityReferences": [
|
||||
"TestAssemblies"
|
||||
],
|
||||
"excludePlatforms": [],
|
||||
"allowUnsafeCode": true,
|
||||
"overrideReferences": true,
|
||||
"autoReferenced": false,
|
||||
"defineConstraints": [
|
||||
"UNITY_INCLUDE_TESTS"
|
||||
],
|
||||
"versionDefines": [],
|
||||
"noEngineReferences": false
|
||||
}
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 3ce0cf2654ad3464aa58eb2e27f77f0d
|
||||
AssemblyDefinitionImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
using Unity.Burst;
|
||||
|
||||
public static class TypeHashWrapper
|
||||
{
|
||||
public static int GetIntHash()
|
||||
{
|
||||
return BurstRuntime.GetHashCode32<int>();
|
||||
}
|
||||
|
||||
public static int GetGenericHash<T>()
|
||||
{
|
||||
return BurstRuntime.GetHashCode32<SomeStruct<T>>();
|
||||
}
|
||||
|
||||
public struct SomeStruct<T> { }
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 581a69eadade3f4985faa44d7b02aa3d
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
using System;
|
||||
using NUnit.Framework;
|
||||
using Unity.Burst.Editor;
|
||||
|
||||
public class StringSliceTests
|
||||
{
|
||||
private const string _someText = "This is some text we are going to take StringSlice from.";
|
||||
private const string _target = "StringSlice";
|
||||
private readonly StringSlice _ssTarget = new StringSlice(_someText, _someText.IndexOf(_target, StringComparison.InvariantCulture), _target.Length);
|
||||
|
||||
[Test]
|
||||
public void StringSliceStringRepresentationTest()
|
||||
{
|
||||
Assert.AreEqual(_target, _ssTarget.ToString());
|
||||
Assert.AreEqual('S', _ssTarget[0]);
|
||||
Assert.IsTrue(_ssTarget == new StringSlice(_target));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void StartsWithTest()
|
||||
{
|
||||
Assert.IsFalse(_ssTarget.StartsWith("This"));
|
||||
Assert.IsTrue(_ssTarget.StartsWith("S"));
|
||||
Assert.IsTrue(_ssTarget.StartsWith(_target));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ContainsTest()
|
||||
{
|
||||
Assert.IsFalse(_ssTarget.Contains('T'));
|
||||
Assert.IsFalse(_ssTarget.Contains('s'));
|
||||
Assert.IsTrue(_ssTarget.Contains('S'));
|
||||
Assert.IsTrue(_ssTarget.Contains('g'));
|
||||
Assert.IsTrue(_ssTarget.Contains('e'));
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 8361860cac3b3a12bc041994c9c1638c
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
{
|
||||
"name": "Unity.Burst.Editor.Tests",
|
||||
"references": [
|
||||
"Unity.Burst",
|
||||
"Unity.Mathematics",
|
||||
"Unity.Burst.Tests.UnitTests",
|
||||
"SeparateAssembly",
|
||||
"Unity.Burst.Editor"
|
||||
],
|
||||
"optionalUnityReferences": [
|
||||
"TestAssemblies"
|
||||
],
|
||||
"includePlatforms": [
|
||||
"Editor"
|
||||
],
|
||||
"excludePlatforms": [],
|
||||
"allowUnsafeCode": true,
|
||||
"overrideReferences": true,
|
||||
"precompiledReferences": [
|
||||
"nunit.framework.dll"
|
||||
],
|
||||
"autoReferenced": false,
|
||||
"defineConstraints": [
|
||||
"UNITY_INCLUDE_TESTS"
|
||||
],
|
||||
"versionDefines": [],
|
||||
"noEngineReferences": false
|
||||
}
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 15ce69d7d9d9370c9704e0797a0ab06b
|
||||
AssemblyDefinitionImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,662 @@
|
|||
.text
|
||||
.def @feat.00;
|
||||
.scl 3;
|
||||
.type 0;
|
||||
.endef
|
||||
.globl @feat.00
|
||||
.set @feat.00, 0
|
||||
.intel_syntax noprefix
|
||||
.file "main"
|
||||
.def burst.initialize;
|
||||
.scl 2;
|
||||
.type 32;
|
||||
.endef
|
||||
.globl burst.initialize
|
||||
.p2align 4, 0x90
|
||||
burst.initialize:
|
||||
.Lfunc_begin0:
|
||||
.seh_proc burst.initialize
|
||||
push rbp
|
||||
.seh_pushreg rbp
|
||||
mov rbp, rsp
|
||||
.seh_setframe rbp, 0
|
||||
.seh_endprologue
|
||||
pop rbp
|
||||
ret
|
||||
.Lfunc_end0:
|
||||
.seh_endproc
|
||||
|
||||
.def burst.initialize.externals;
|
||||
.scl 2;
|
||||
.type 32;
|
||||
.endef
|
||||
.globl burst.initialize.externals
|
||||
.p2align 4, 0x90
|
||||
burst.initialize.externals:
|
||||
.Lfunc_begin1:
|
||||
.seh_proc burst.initialize.externals
|
||||
push rbp
|
||||
.seh_pushreg rbp
|
||||
mov rbp, rsp
|
||||
.seh_setframe rbp, 0
|
||||
.seh_endprologue
|
||||
pop rbp
|
||||
ret
|
||||
.Lfunc_end1:
|
||||
.seh_endproc
|
||||
|
||||
.def burst.initialize.statics;
|
||||
.scl 2;
|
||||
.type 32;
|
||||
.endef
|
||||
.globl burst.initialize.statics
|
||||
.p2align 4, 0x90
|
||||
burst.initialize.statics:
|
||||
.Lfunc_begin2:
|
||||
.seh_proc burst.initialize.statics
|
||||
push rbp
|
||||
.seh_pushreg rbp
|
||||
mov rbp, rsp
|
||||
.seh_setframe rbp, 0
|
||||
.seh_endprologue
|
||||
pop rbp
|
||||
ret
|
||||
.Lfunc_end2:
|
||||
.seh_endproc
|
||||
|
||||
.def d675c2aa053244579b646ec09368a505;
|
||||
.scl 2;
|
||||
.type 32;
|
||||
.endef
|
||||
.globl d675c2aa053244579b646ec09368a505
|
||||
.p2align 4, 0x90
|
||||
d675c2aa053244579b646ec09368a505:
|
||||
.Lfunc_begin3:
|
||||
.seh_proc d675c2aa053244579b646ec09368a505
|
||||
push rbp
|
||||
.seh_pushreg rbp
|
||||
sub rsp, 48
|
||||
.seh_stackalloc 48
|
||||
lea rbp, [rsp + 48]
|
||||
.seh_setframe rbp, 48
|
||||
.seh_endprologue
|
||||
mov eax, dword ptr [rbp + 48]
|
||||
mov dword ptr [rsp + 32], eax
|
||||
call "Unity.Jobs.IJobExtensions.JobStruct`1<BurstInspectorGUITests.MyJob>.Execute(ref BurstInspectorGUITests.MyJob data, System.IntPtr additionalPtr, System.IntPtr bufferRangePatchData, ref Unity.Jobs.LowLevel.Unsafe.JobRanges ranges, int jobIndex) -> void_930e313844f708dd8e72e0cb41431524 from UnityEngine.CoreModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
nop
|
||||
add rsp, 48
|
||||
pop rbp
|
||||
ret
|
||||
.Lfunc_end3:
|
||||
.seh_endproc
|
||||
|
||||
.def "Unity.Jobs.IJobExtensions.JobStruct`1<BurstInspectorGUITests.MyJob>.Execute(ref BurstInspectorGUITests.MyJob data, System.IntPtr additionalPtr, System.IntPtr bufferRangePatchData, ref Unity.Jobs.LowLevel.Unsafe.JobRanges ranges, int jobIndex) -> void_930e313844f708dd8e72e0cb41431524 from UnityEngine.CoreModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null";
|
||||
.scl 3;
|
||||
.type 32;
|
||||
.endef
|
||||
.p2align 4, 0x90
|
||||
"Unity.Jobs.IJobExtensions.JobStruct`1<BurstInspectorGUITests.MyJob>.Execute(ref BurstInspectorGUITests.MyJob data, System.IntPtr additionalPtr, System.IntPtr bufferRangePatchData, ref Unity.Jobs.LowLevel.Unsafe.JobRanges ranges, int jobIndex) -> void_930e313844f708dd8e72e0cb41431524 from UnityEngine.CoreModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null":
|
||||
.Lfunc_begin4:
|
||||
.cv_func_id 0
|
||||
.cv_file 1 "C:\\UnitySrc\\unity\\Runtime\\Jobs\\Managed\\IJob.cs"
|
||||
.cv_loc 0 1 57 0
|
||||
.seh_proc "Unity.Jobs.IJobExtensions.JobStruct`1<BurstInspectorGUITests.MyJob>.Execute(ref BurstInspectorGUITests.MyJob data, System.IntPtr additionalPtr, System.IntPtr bufferRangePatchData, ref Unity.Jobs.LowLevel.Unsafe.JobRanges ranges, int jobIndex) -> void_930e313844f708dd8e72e0cb41431524 from UnityEngine.CoreModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
push rbp
|
||||
.seh_pushreg rbp
|
||||
mov rbp, rsp
|
||||
.seh_setframe rbp, 0
|
||||
.seh_endprologue
|
||||
.Ltmp0:
|
||||
.cv_file 2 "C:\\UnitySrc\\unity\\Runtime\\Export\\NativeArray\\NativeArray.cs"
|
||||
.cv_inline_site_id 1 within 0 inlined_at 1 58 0
|
||||
.cv_file 3 "C:\\UnitySrc\\burst\\src\\com.unity.burst\\Tests\\Editor\\BurstInspectorGUITests.cs"
|
||||
.cv_inline_site_id 2 within 1 inlined_at 3 393 0
|
||||
.cv_loc 2 2 130 0
|
||||
mov eax, dword ptr [rcx + 8]
|
||||
test rax, rax
|
||||
.Ltmp1:
|
||||
.cv_loc 1 3 393 0
|
||||
je .LBB4_1
|
||||
mov rdx, qword ptr [rcx]
|
||||
vxorps xmm0, xmm0, xmm0
|
||||
.p2align 4, 0x90
|
||||
.LBB4_3:
|
||||
.cv_loc 1 3 395 0
|
||||
vaddss xmm0, xmm0, dword ptr [rdx]
|
||||
.cv_loc 1 3 393 0
|
||||
add rdx, 4
|
||||
dec rax
|
||||
jne .LBB4_3
|
||||
jmp .LBB4_4
|
||||
.LBB4_1:
|
||||
vxorps xmm0, xmm0, xmm0
|
||||
.LBB4_4:
|
||||
.Ltmp2:
|
||||
.cv_inline_site_id 3 within 1 inlined_at 3 397 0
|
||||
.cv_loc 3 2 194 0
|
||||
mov rax, qword ptr [rcx + 48]
|
||||
vmovss dword ptr [rax], xmm0
|
||||
.Ltmp3:
|
||||
.cv_loc 0 1 59 0
|
||||
pop rbp
|
||||
ret
|
||||
.Ltmp4:
|
||||
.Lfunc_end4:
|
||||
.seh_endproc
|
||||
|
||||
.section .drectve,"yn"
|
||||
.ascii " /EXPORT:\"burst.initialize\""
|
||||
.ascii " /EXPORT:\"burst.initialize.externals\""
|
||||
.ascii " /EXPORT:\"burst.initialize.statics\""
|
||||
.ascii " /EXPORT:d675c2aa053244579b646ec09368a505"
|
||||
.section .debug$S,"dr"
|
||||
.p2align 2
|
||||
.long 4
|
||||
.long 241
|
||||
.long .Ltmp6-.Ltmp5
|
||||
.Ltmp5:
|
||||
.short .Ltmp8-.Ltmp7
|
||||
.Ltmp7:
|
||||
.short 4353
|
||||
.long 0
|
||||
.byte 0
|
||||
.p2align 2
|
||||
.Ltmp8:
|
||||
.short .Ltmp10-.Ltmp9
|
||||
.Ltmp9:
|
||||
.short 4412
|
||||
.long 0
|
||||
.short 208
|
||||
.short 0
|
||||
.short 0
|
||||
.short 91
|
||||
.short 0
|
||||
.short 14006
|
||||
.short 0
|
||||
.short 0
|
||||
.short 0
|
||||
.asciz "Burst 0.0.91.0 (Frontend Version : 040e20f6-d3e4-45d8-b45b-06c6d673cedb)"
|
||||
.p2align 2
|
||||
.Ltmp10:
|
||||
.Ltmp6:
|
||||
.p2align 2
|
||||
.long 246
|
||||
.long .Ltmp12-.Ltmp11
|
||||
.Ltmp11:
|
||||
.long 0
|
||||
|
||||
|
||||
.long 4112
|
||||
.cv_filechecksumoffset 3
|
||||
.long 391
|
||||
|
||||
|
||||
.long 4115
|
||||
.cv_filechecksumoffset 2
|
||||
.long 129
|
||||
|
||||
|
||||
.long 4118
|
||||
.cv_filechecksumoffset 2
|
||||
.long 192
|
||||
.Ltmp12:
|
||||
.p2align 2
|
||||
.long 241
|
||||
.long .Ltmp14-.Ltmp13
|
||||
.Ltmp13:
|
||||
.short .Ltmp16-.Ltmp15
|
||||
.Ltmp15:
|
||||
.short 4422
|
||||
.long 0
|
||||
.long 0
|
||||
.long 0
|
||||
.long .Lfunc_end4-"Unity.Jobs.IJobExtensions.JobStruct`1<BurstInspectorGUITests.MyJob>.Execute(ref BurstInspectorGUITests.MyJob data, System.IntPtr additionalPtr, System.IntPtr bufferRangePatchData, ref Unity.Jobs.LowLevel.Unsafe.JobRanges ranges, int jobIndex) -> void_930e313844f708dd8e72e0cb41431524 from UnityEngine.CoreModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
.long 0
|
||||
.long 0
|
||||
.long 4126
|
||||
.secrel32 "Unity.Jobs.IJobExtensions.JobStruct`1<BurstInspectorGUITests.MyJob>.Execute(ref BurstInspectorGUITests.MyJob data, System.IntPtr additionalPtr, System.IntPtr bufferRangePatchData, ref Unity.Jobs.LowLevel.Unsafe.JobRanges ranges, int jobIndex) -> void_930e313844f708dd8e72e0cb41431524 from UnityEngine.CoreModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
.secidx "Unity.Jobs.IJobExtensions.JobStruct`1<BurstInspectorGUITests.MyJob>.Execute(ref BurstInspectorGUITests.MyJob data, System.IntPtr additionalPtr, System.IntPtr bufferRangePatchData, ref Unity.Jobs.LowLevel.Unsafe.JobRanges ranges, int jobIndex) -> void_930e313844f708dd8e72e0cb41431524 from UnityEngine.CoreModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
.byte 0
|
||||
.asciz "Unity.Jobs.IJobExtensions.JobStruct`1<BurstInspectorGUITests.MyJob>.Execute(ref BurstInspectorGUITests.MyJob data, System.IntPtr additionalPtr, System.IntPtr bufferRangePatchData, ref Unity.Jobs.LowLevel.Unsafe.JobRanges ranges, int jobIndex) -> void_930e313844f708dd8e72e0cb41431524 from UnityEngine.CoreModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
.p2align 2
|
||||
.Ltmp16:
|
||||
.short .Ltmp18-.Ltmp17
|
||||
.Ltmp17:
|
||||
.short 4114
|
||||
.long 8
|
||||
.long 0
|
||||
.long 0
|
||||
.long 0
|
||||
.long 0
|
||||
.short 0
|
||||
.long 1212416
|
||||
.p2align 2
|
||||
.Ltmp18:
|
||||
.short .Ltmp20-.Ltmp19
|
||||
.Ltmp19:
|
||||
.short 4429
|
||||
.long 0
|
||||
.long 0
|
||||
.long 4112
|
||||
.cv_inline_linetable 1 3 391 .Lfunc_begin4 .Lfunc_end4
|
||||
.p2align 2
|
||||
.Ltmp20:
|
||||
.short .Ltmp22-.Ltmp21
|
||||
.Ltmp21:
|
||||
.short 4429
|
||||
.long 0
|
||||
.long 0
|
||||
.long 4115
|
||||
.cv_inline_linetable 2 2 129 .Lfunc_begin4 .Lfunc_end4
|
||||
.p2align 2
|
||||
.Ltmp22:
|
||||
.short 2
|
||||
.short 4430
|
||||
.short .Ltmp24-.Ltmp23
|
||||
.Ltmp23:
|
||||
.short 4429
|
||||
.long 0
|
||||
.long 0
|
||||
.long 4118
|
||||
.cv_inline_linetable 3 2 192 .Lfunc_begin4 .Lfunc_end4
|
||||
.p2align 2
|
||||
.Ltmp24:
|
||||
.short 2
|
||||
.short 4430
|
||||
.short 2
|
||||
.short 4430
|
||||
.short 2
|
||||
.short 4431
|
||||
.Ltmp14:
|
||||
.p2align 2
|
||||
.cv_linetable 0, "Unity.Jobs.IJobExtensions.JobStruct`1<BurstInspectorGUITests.MyJob>.Execute(ref BurstInspectorGUITests.MyJob data, System.IntPtr additionalPtr, System.IntPtr bufferRangePatchData, ref Unity.Jobs.LowLevel.Unsafe.JobRanges ranges, int jobIndex) -> void_930e313844f708dd8e72e0cb41431524 from UnityEngine.CoreModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null", .Lfunc_end4
|
||||
.long 241
|
||||
.long .Ltmp26-.Ltmp25
|
||||
.Ltmp25:
|
||||
.short .Ltmp28-.Ltmp27
|
||||
.Ltmp27:
|
||||
.short 4360
|
||||
.long 4099
|
||||
.asciz "BurstInspectorGUITests/MyJob"
|
||||
.p2align 2
|
||||
.Ltmp28:
|
||||
.short .Ltmp30-.Ltmp29
|
||||
.Ltmp29:
|
||||
.short 4360
|
||||
.long 4104
|
||||
.asciz "Unity.Collections.NativeArray`1<System.Single>"
|
||||
.p2align 2
|
||||
.Ltmp30:
|
||||
.short .Ltmp32-.Ltmp31
|
||||
.Ltmp31:
|
||||
.short 4360
|
||||
.long 4107
|
||||
.asciz "Unity.Collections.LowLevel.Unsafe.AtomicSafetyHandle"
|
||||
.p2align 2
|
||||
.Ltmp32:
|
||||
.short .Ltmp34-.Ltmp33
|
||||
.Ltmp33:
|
||||
.short 4360
|
||||
.long 4124
|
||||
.asciz "Unity.Jobs.LowLevel.Unsafe.JobRanges"
|
||||
.p2align 2
|
||||
.Ltmp34:
|
||||
.Ltmp26:
|
||||
.p2align 2
|
||||
.cv_filechecksums
|
||||
.cv_stringtable
|
||||
.long 241
|
||||
.long .Ltmp36-.Ltmp35
|
||||
.Ltmp35:
|
||||
.short .Ltmp38-.Ltmp37
|
||||
.Ltmp37:
|
||||
.short 4428
|
||||
.long 4130
|
||||
.p2align 2
|
||||
.Ltmp38:
|
||||
.Ltmp36:
|
||||
.p2align 2
|
||||
.section .debug$T,"dr"
|
||||
.p2align 2
|
||||
.long 4
|
||||
.short 0x32
|
||||
.short 0x1505
|
||||
.short 0x0
|
||||
.short 0x80
|
||||
.long 0x0
|
||||
.long 0x0
|
||||
.long 0x0
|
||||
.short 0x0
|
||||
.asciz "BurstInspectorGUITests/MyJob"
|
||||
.byte 241
|
||||
.short 0x46
|
||||
.short 0x1505
|
||||
.short 0x0
|
||||
.short 0x80
|
||||
.long 0x0
|
||||
.long 0x0
|
||||
.long 0x0
|
||||
.short 0x0
|
||||
.asciz "Unity.Collections.NativeArray`1<System.Single>"
|
||||
.byte 243
|
||||
.byte 242
|
||||
.byte 241
|
||||
.short 0x2a
|
||||
.short 0x1203
|
||||
.short 0x150d
|
||||
.short 0x3
|
||||
.long 0x1001
|
||||
.short 0x0
|
||||
.asciz "Inp\303\272t"
|
||||
.byte 243
|
||||
.byte 242
|
||||
.byte 241
|
||||
.short 0x150d
|
||||
.short 0x3
|
||||
.long 0x1001
|
||||
.short 0x30
|
||||
.asciz "Output"
|
||||
.byte 243
|
||||
.byte 242
|
||||
.byte 241
|
||||
.short 0x32
|
||||
.short 0x1505
|
||||
.short 0x2
|
||||
.short 0x0
|
||||
.long 0x1002
|
||||
.long 0x0
|
||||
.long 0x0
|
||||
.short 0x60
|
||||
.asciz "BurstInspectorGUITests/MyJob"
|
||||
.byte 241
|
||||
.short 0x42
|
||||
.short 0x1605
|
||||
.long 0x0
|
||||
.asciz "C:\\UnitySrc\\burst\\src\\Unity.Burst.Tester\\unknown\\unknown"
|
||||
.byte 243
|
||||
.byte 242
|
||||
.byte 241
|
||||
.short 0xe
|
||||
.short 0x1606
|
||||
.long 0x1003
|
||||
.long 0x1004
|
||||
.long 0x0
|
||||
.short 0x4a
|
||||
.short 0x1505
|
||||
.short 0x0
|
||||
.short 0x80
|
||||
.long 0x0
|
||||
.long 0x0
|
||||
.long 0x0
|
||||
.short 0x0
|
||||
.asciz "Unity.Collections.LowLevel.Unsafe.AtomicSafetyHandle"
|
||||
.byte 241
|
||||
.short 0x8a
|
||||
.short 0x1203
|
||||
.short 0x150d
|
||||
.short 0x3
|
||||
.long 0x620
|
||||
.short 0x0
|
||||
.asciz "m_Buffer"
|
||||
.byte 241
|
||||
.short 0x150d
|
||||
.short 0x3
|
||||
.long 0x74
|
||||
.short 0x8
|
||||
.asciz "m_Length"
|
||||
.byte 241
|
||||
.short 0x150d
|
||||
.short 0x3
|
||||
.long 0x74
|
||||
.short 0xc
|
||||
.asciz "m_MinIndex"
|
||||
.byte 243
|
||||
.byte 242
|
||||
.byte 241
|
||||
.short 0x150d
|
||||
.short 0x3
|
||||
.long 0x74
|
||||
.short 0x10
|
||||
.asciz "m_MaxIndex"
|
||||
.byte 243
|
||||
.byte 242
|
||||
.byte 241
|
||||
.short 0x150d
|
||||
.short 0x3
|
||||
.long 0x1006
|
||||
.short 0x18
|
||||
.asciz "m_Safety"
|
||||
.byte 241
|
||||
.short 0x150d
|
||||
.short 0x3
|
||||
.long 0x74
|
||||
.short 0x28
|
||||
.asciz "m_AllocatorLabel"
|
||||
.byte 241
|
||||
.short 0x46
|
||||
.short 0x1505
|
||||
.short 0x6
|
||||
.short 0x0
|
||||
.long 0x1007
|
||||
.long 0x0
|
||||
.long 0x0
|
||||
.short 0x30
|
||||
.asciz "Unity.Collections.NativeArray`1<System.Single>"
|
||||
.byte 243
|
||||
.byte 242
|
||||
.byte 241
|
||||
.short 0xe
|
||||
.short 0x1606
|
||||
.long 0x1008
|
||||
.long 0x1004
|
||||
.long 0x0
|
||||
.short 0x4a
|
||||
.short 0x1203
|
||||
.short 0x150d
|
||||
.short 0x3
|
||||
.long 0x620
|
||||
.short 0x0
|
||||
.asciz "versionNode"
|
||||
.byte 242
|
||||
.byte 241
|
||||
.short 0x150d
|
||||
.short 0x3
|
||||
.long 0x74
|
||||
.short 0x8
|
||||
.asciz "version"
|
||||
.byte 242
|
||||
.byte 241
|
||||
.short 0x150d
|
||||
.short 0x3
|
||||
.long 0x74
|
||||
.short 0xc
|
||||
.asciz "staticSafetyId"
|
||||
.byte 243
|
||||
.byte 242
|
||||
.byte 241
|
||||
.short 0x4a
|
||||
.short 0x1505
|
||||
.short 0x3
|
||||
.short 0x0
|
||||
.long 0x100a
|
||||
.long 0x0
|
||||
.long 0x0
|
||||
.short 0x10
|
||||
.asciz "Unity.Collections.LowLevel.Unsafe.AtomicSafetyHandle"
|
||||
.byte 241
|
||||
.short 0xe
|
||||
.short 0x1606
|
||||
.long 0x100b
|
||||
.long 0x1004
|
||||
.long 0x0
|
||||
.short 0xa
|
||||
.short 0x1002
|
||||
.long 0x1000
|
||||
.long 0x1000c
|
||||
.short 0x6
|
||||
.short 0x1201
|
||||
.long 0x0
|
||||
.short 0x1a
|
||||
.short 0x1009
|
||||
.long 0x3
|
||||
.long 0x1000
|
||||
.long 0x100d
|
||||
.byte 0x0
|
||||
.byte 0x0
|
||||
.short 0x0
|
||||
.long 0x100e
|
||||
.long 0x0
|
||||
.short 0x32
|
||||
.short 0x1602
|
||||
.long 0x1000
|
||||
.long 0x100f
|
||||
.asciz "BurstInspectorGUITests.MyJob.Execute"
|
||||
.byte 243
|
||||
.byte 242
|
||||
.byte 241
|
||||
.short 0xa
|
||||
.short 0x1002
|
||||
.long 0x1001
|
||||
.long 0x1000c
|
||||
.short 0x1a
|
||||
.short 0x1009
|
||||
.long 0x74
|
||||
.long 0x1001
|
||||
.long 0x1011
|
||||
.byte 0x0
|
||||
.byte 0x0
|
||||
.short 0x0
|
||||
.long 0x100e
|
||||
.long 0x0
|
||||
.short 0x3e
|
||||
.short 0x1602
|
||||
.long 0x1001
|
||||
.long 0x1012
|
||||
.asciz "Unity.Collections.NativeArray`1<float>.get_Length"
|
||||
.byte 242
|
||||
.byte 241
|
||||
.short 0xe
|
||||
.short 0x1201
|
||||
.long 0x2
|
||||
.long 0x74
|
||||
.long 0x40
|
||||
.short 0x1a
|
||||
.short 0x1009
|
||||
.long 0x3
|
||||
.long 0x1001
|
||||
.long 0x1011
|
||||
.byte 0x0
|
||||
.byte 0x0
|
||||
.short 0x2
|
||||
.long 0x1014
|
||||
.long 0x0
|
||||
.short 0x3a
|
||||
.short 0x1602
|
||||
.long 0x1001
|
||||
.long 0x1015
|
||||
.asciz "Unity.Collections.NativeArray`1<float>.set_Item"
|
||||
.short 0x3a
|
||||
.short 0x1505
|
||||
.short 0x0
|
||||
.short 0x80
|
||||
.long 0x0
|
||||
.long 0x0
|
||||
.long 0x0
|
||||
.short 0x0
|
||||
.asciz "Unity.Jobs.LowLevel.Unsafe.JobRanges"
|
||||
.byte 241
|
||||
.short 0xa
|
||||
.short 0x1002
|
||||
.long 0x1017
|
||||
.long 0x1000c
|
||||
.short 0x1a
|
||||
.short 0x1201
|
||||
.long 0x5
|
||||
.long 0x100d
|
||||
.long 0x620
|
||||
.long 0x620
|
||||
.long 0x1018
|
||||
.long 0x74
|
||||
.short 0xe
|
||||
.short 0x1008
|
||||
.long 0x3
|
||||
.byte 0x0
|
||||
.byte 0x0
|
||||
.short 0x5
|
||||
.long 0x1019
|
||||
.short 0x62
|
||||
.short 0x1203
|
||||
.short 0x150d
|
||||
.short 0x3
|
||||
.long 0x74
|
||||
.short 0x0
|
||||
.asciz "BatchSize"
|
||||
.short 0x150d
|
||||
.short 0x3
|
||||
.long 0x74
|
||||
.short 0x4
|
||||
.asciz "NumJobs"
|
||||
.byte 242
|
||||
.byte 241
|
||||
.short 0x150d
|
||||
.short 0x3
|
||||
.long 0x74
|
||||
.short 0x8
|
||||
.asciz "TotalIterationCount"
|
||||
.byte 242
|
||||
.byte 241
|
||||
.short 0x150d
|
||||
.short 0x3
|
||||
.long 0x620
|
||||
.short 0x10
|
||||
.asciz "StartEndIndex"
|
||||
.short 0x3a
|
||||
.short 0x1505
|
||||
.short 0x4
|
||||
.short 0x0
|
||||
.long 0x101b
|
||||
.long 0x0
|
||||
.long 0x0
|
||||
.short 0x18
|
||||
.asciz "Unity.Jobs.LowLevel.Unsafe.JobRanges"
|
||||
.byte 241
|
||||
.short 0xe
|
||||
.short 0x1606
|
||||
.long 0x101c
|
||||
.long 0x1004
|
||||
.long 0x0
|
||||
.short 0x17a
|
||||
.short 0x1601
|
||||
.long 0x0
|
||||
.long 0x101a
|
||||
.asciz "Unity.Jobs.IJobExtensions.JobStruct`1<BurstInspectorGUITests.MyJob>.Execute(ref BurstInspectorGUITests.MyJob data, System.IntPtr additionalPtr, System.IntPtr bufferRangePatchData, ref Unity.Jobs.LowLevel.Unsafe.JobRanges ranges, int jobIndex) -> void_930e313844f708dd8e72e0cb41431524 from UnityEngine.CoreModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null"
|
||||
.byte 241
|
||||
.short 0x3a
|
||||
.short 0x1605
|
||||
.long 0x0
|
||||
.asciz "C:\\UnitySrc\\burst\\src\\Unity.Burst.Tester\\unknown"
|
||||
.byte 243
|
||||
.byte 242
|
||||
.byte 241
|
||||
.short 0xe
|
||||
.short 0x1605
|
||||
.long 0x0
|
||||
.asciz "unknown"
|
||||
.short 0xa
|
||||
.short 0x1605
|
||||
.long 0x0
|
||||
.byte 0
|
||||
.byte 243
|
||||
.byte 242
|
||||
.byte 241
|
||||
.short 0x1a
|
||||
.short 0x1603
|
||||
.short 0x5
|
||||
.long 0x101f
|
||||
.long 0x0
|
||||
.long 0x1020
|
||||
.long 0x1021
|
||||
.long 0x0
|
||||
.byte 242
|
||||
.byte 241
|
||||
.globl _fltused
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
fileFormatVersion: 2
|
||||
guid: e98313e850883648a977ddbceaaca946
|
||||
TextScriptImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: dfcfd8358b733176a9227f0cf438af69
|
||||
folderAsset: yes
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
{
|
||||
"name": "OverloadedFunctionPointers",
|
||||
"rootNamespace": "",
|
||||
"references": [
|
||||
"Unity.Burst"
|
||||
],
|
||||
"includePlatforms": [],
|
||||
"excludePlatforms": [],
|
||||
"allowUnsafeCode": true,
|
||||
"overrideReferences": false,
|
||||
"precompiledReferences": [],
|
||||
"optionalUnityReferences": [
|
||||
"TestAssemblies"
|
||||
],
|
||||
"autoReferenced": false,
|
||||
"defineConstraints": [
|
||||
"UNITY_INCLUDE_TESTS"
|
||||
],
|
||||
"versionDefines": [],
|
||||
"noEngineReferences": false
|
||||
}
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
fileFormatVersion: 2
|
||||
guid: ee94adce07250884391eeae8a50c225e
|
||||
AssemblyDefinitionImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
namespace OverloadedFunctionPointers
|
||||
{
|
||||
#if UNITY_2021_2_OR_NEWER && UNITY_EDITOR
|
||||
public unsafe struct Callable
|
||||
{
|
||||
public int Value;
|
||||
|
||||
private Callable(int x)
|
||||
{
|
||||
Value = x;
|
||||
}
|
||||
|
||||
public static Callable Create<T1, T2>(delegate* unmanaged[Cdecl] < T1, T2, void > function) => new Callable(2);
|
||||
public static Callable Create<T1, TRet>(delegate* unmanaged[Cdecl] < T1, TRet > function) => new Callable(3);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 66ab7ac009493f37ae82d74f0f5f952e
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: bc9ed20d6388316e806d5f03d0ab3b25
|
||||
folderAsset: yes
|
||||
|
|
@ -0,0 +1,223 @@
|
|||
using System;
|
||||
using System.Diagnostics;
|
||||
using Unity.Burst;
|
||||
using Unity.Collections;
|
||||
using Unity.Jobs;
|
||||
using Unity.Mathematics;
|
||||
using UnityEngine;
|
||||
|
||||
/// <summary>
|
||||
/// Shared class used for Unit tests and <see cref="MyBurstBehavior"/>
|
||||
/// </summary>
|
||||
[BurstCompile] // attribute added just to check that static methods are getting compiled
|
||||
public class BurstJobTester2 : IDisposable
|
||||
{
|
||||
private NativeArray<float> _array;
|
||||
private NativeArray<float> _arrayAsyncJobDefault;
|
||||
private NativeArray<float> _arrayAsyncJobFast;
|
||||
|
||||
public BurstJobTester2()
|
||||
{
|
||||
_array = new NativeArray<float>(10, Allocator.Persistent);
|
||||
_arrayAsyncJobDefault = new NativeArray<float>(10, Allocator.Persistent);
|
||||
_arrayAsyncJobFast = new NativeArray<float>(10, Allocator.Persistent);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_array.Dispose();
|
||||
_arrayAsyncJobDefault.Dispose();
|
||||
_arrayAsyncJobFast.Dispose();
|
||||
}
|
||||
|
||||
public float Calculate()
|
||||
{
|
||||
// Schedule the job on each frame to make sure that it will be compiled async on the next frame
|
||||
_array[0] = 0.0f;
|
||||
// Launch synchronous job
|
||||
var job = new MyJob { Result = _array };
|
||||
job.Schedule().Complete();
|
||||
var rotation = job.Result[0];
|
||||
|
||||
// Launch an async compilation
|
||||
var asyncJobNoOptim = new MyJobWithDefaultOptimizations() {Result = _arrayAsyncJobDefault};
|
||||
var asyncJobFastOptim = new MyJobWithFastOptimizations() {Result = _arrayAsyncJobFast};
|
||||
var asyncJobNoOptimHandle = asyncJobNoOptim.Schedule();
|
||||
var asyncJobFastOptimHandle = asyncJobFastOptim.Schedule();
|
||||
|
||||
// Wait for async completion
|
||||
asyncJobNoOptimHandle.Complete();
|
||||
asyncJobFastOptimHandle.Complete();
|
||||
|
||||
return rotation;
|
||||
}
|
||||
|
||||
public float CheckFunctionPointer()
|
||||
{
|
||||
var functionPointer1 = BurstCompiler.CompileFunctionPointer<Add2NumbersDelegate>(Add2Numbers);
|
||||
var result = functionPointer1.Invoke(1.0f, 2.0f);
|
||||
|
||||
var functionPointer2 = BurstCompiler.CompileFunctionPointer<Add2NumbersDelegate>(Add2NumbersThrows);
|
||||
return functionPointer2.Invoke(1.0f, 2.0f);
|
||||
}
|
||||
|
||||
[BurstCompile(CompileSynchronously = true)] // attribute used for a static method
|
||||
public static float Add2Numbers(float a, float b)
|
||||
{
|
||||
DiscardFunction(ref a);
|
||||
DiscardFunction(ref b);
|
||||
return a + b;
|
||||
}
|
||||
|
||||
[BurstCompile(CompileSynchronously = true)] // attribute used for a static method
|
||||
public static float Add2NumbersThrows(float a, float b)
|
||||
{
|
||||
DiscardFunction(ref a);
|
||||
DiscardFunction(ref b);
|
||||
if (a > 0) ThrowNewArgumentException();
|
||||
return a + b;
|
||||
}
|
||||
|
||||
[Conditional("ENABLE_UNITY_COLLECTIONS_CHECKS")]
|
||||
private static void ThrowNewArgumentException()
|
||||
{
|
||||
throw new ArgumentException("Invalid a must be < 0");
|
||||
}
|
||||
|
||||
[BurstDiscard]
|
||||
private static void DiscardFunction(ref float x)
|
||||
{
|
||||
x = 0;
|
||||
}
|
||||
|
||||
public delegate float Add2NumbersDelegate(float a, float b);
|
||||
|
||||
[BurstCompile(CompileSynchronously = true)]
|
||||
public struct MyJob : IJob
|
||||
{
|
||||
[WriteOnly]
|
||||
public NativeArray<float> Result;
|
||||
|
||||
public void Execute()
|
||||
{
|
||||
Result[0] = ChangeValue();
|
||||
EraseRotation();
|
||||
}
|
||||
|
||||
// Use an indirection: Execute -> instance method -> static method
|
||||
// (to check caching manually, change "1.0f" in ChangeValue() and 2.0f in ChangeValueStatic())
|
||||
private float ChangeValue()
|
||||
{
|
||||
return 1.0f + ChangeValueStatic();
|
||||
}
|
||||
|
||||
private static float ChangeValueStatic()
|
||||
{
|
||||
return 2.0f;
|
||||
}
|
||||
|
||||
// Use BurstDiscard, if burst is not available, this method will get executed and it will make the cube static on the screen.
|
||||
[BurstDiscard]
|
||||
private void EraseRotation()
|
||||
{
|
||||
Result[0] = 0.0f;
|
||||
}
|
||||
|
||||
// static method in a burst job, but we still want to compile separately
|
||||
[BurstCompile(FloatMode = FloatMode.Deterministic, CompileSynchronously = true)]
|
||||
public static float CheckFmaSlow(float a, float b, float c)
|
||||
{
|
||||
return a * b + c + math.sin(c);
|
||||
}
|
||||
|
||||
// static method in a burst job, but we still want to compile separately
|
||||
// Used only to check that compilation is working for different burst compile options
|
||||
[BurstCompile(FloatPrecision.Low, FloatMode.Fast, CompileSynchronously = true)]
|
||||
public static float CheckFmaFast(float a, float b, float c)
|
||||
{
|
||||
return a * b + c + math.sin(c);
|
||||
}
|
||||
}
|
||||
|
||||
[BurstCompile(CompileSynchronously = false)]
|
||||
public struct MyJobAsync : IJob
|
||||
{
|
||||
[WriteOnly]
|
||||
public NativeArray<float> Result;
|
||||
|
||||
public void Execute()
|
||||
{
|
||||
Result[0] = ChangeValue();
|
||||
EraseRotation();
|
||||
}
|
||||
|
||||
private float ChangeValue()
|
||||
{
|
||||
return 1.0f + ChangeValueStatic();
|
||||
}
|
||||
|
||||
private static float ChangeValueStatic()
|
||||
{
|
||||
return 2.0f;
|
||||
}
|
||||
|
||||
[BurstDiscard]
|
||||
private void EraseRotation()
|
||||
{
|
||||
Result[0] = 0.0f;
|
||||
}
|
||||
}
|
||||
|
||||
[BurstCompile]
|
||||
public struct MyJobWithDefaultOptimizations : IJob
|
||||
{
|
||||
public NativeArray<float> Result;
|
||||
|
||||
public void Execute()
|
||||
{
|
||||
Result[0] = math.cos(Result[0]);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This Job is checking that we can allocate and dispose a NativeArray from a Burst Job
|
||||
/// </summary>
|
||||
[BurstCompile(CompileSynchronously = true)]
|
||||
public struct MyJobCreatingAndDisposingNativeArray : IJob
|
||||
{
|
||||
public int Length;
|
||||
|
||||
public NativeArray<int> Result;
|
||||
|
||||
public void Execute()
|
||||
{
|
||||
var array = new NativeArray<float>(Length, Allocator.Temp);
|
||||
for (int i = 0; i < array.Length; i++)
|
||||
{
|
||||
array[i] = i;
|
||||
}
|
||||
int result = array.Length;
|
||||
array.Dispose();
|
||||
DiscardFromManaged(ref result);
|
||||
Result[0] = result;
|
||||
}
|
||||
|
||||
[BurstDiscard]
|
||||
public static void DiscardFromManaged(ref int result)
|
||||
{
|
||||
result = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Used only to check that compilation is working for different burst compile options
|
||||
[BurstCompile(FloatPrecision.Low, FloatMode.Fast)]
|
||||
public struct MyJobWithFastOptimizations : IJob
|
||||
{
|
||||
public NativeArray<float> Result;
|
||||
|
||||
public void Execute()
|
||||
{
|
||||
Result[0] = math.cos(Result[0]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 3decc8d6366d3d668648f9b79f2a980f
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,237 @@
|
|||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using AOT;
|
||||
using NUnit.Framework;
|
||||
using Unity.Burst;
|
||||
using UnityEngine;
|
||||
using UnityEngine.TestTools;
|
||||
#if UNITY_2021_2_OR_NEWER
|
||||
using System.Runtime.CompilerServices;
|
||||
using Unity.Collections;
|
||||
using Unity.Collections.LowLevel.Unsafe;
|
||||
using Unity.Jobs;
|
||||
#if UNITY_EDITOR
|
||||
using OverloadedFunctionPointers;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
[TestFixture, BurstCompile]
|
||||
public class FunctionPointerTests
|
||||
{
|
||||
[BurstCompile(CompileSynchronously = true)]
|
||||
private static T StaticFunctionNoArgsGenericReturnType<T>()
|
||||
{
|
||||
return default;
|
||||
}
|
||||
|
||||
private delegate int DelegateNoArgsIntReturnType();
|
||||
|
||||
[Test]
|
||||
public void TestCompileFunctionPointerNoArgsGenericReturnType()
|
||||
{
|
||||
Assert.Throws<InvalidOperationException>(
|
||||
() => BurstCompiler.CompileFunctionPointer<DelegateNoArgsIntReturnType>(StaticFunctionNoArgsGenericReturnType<int>),
|
||||
"The method `Int32 StaticFunctionNoArgsGenericReturnType[Int32]()` must be a non-generic method");
|
||||
}
|
||||
|
||||
[BurstCompile(CompileSynchronously = true)]
|
||||
private static int StaticFunctionConcreteReturnType()
|
||||
{
|
||||
return default;
|
||||
}
|
||||
|
||||
private delegate T DelegateGenericReturnType<T>();
|
||||
|
||||
[Test]
|
||||
public void TestCompileFunctionPointerDelegateNoArgsGenericReturnType()
|
||||
{
|
||||
Assert.Throws<InvalidOperationException>(
|
||||
() => BurstCompiler.CompileFunctionPointer<DelegateGenericReturnType<int>>(StaticFunctionConcreteReturnType),
|
||||
"The delegate type `FunctionPointerTests+DelegateGenericReturnType`1[System.Int32]` must be a non-generic type");
|
||||
}
|
||||
|
||||
private static class GenericClass<T>
|
||||
{
|
||||
public delegate int DelegateNoArgsIntReturnType();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestCompileFunctionPointerDelegateNoArgsGenericDeclaringType()
|
||||
{
|
||||
Assert.Throws<InvalidOperationException>(
|
||||
() => BurstCompiler.CompileFunctionPointer<GenericClass<int>.DelegateNoArgsIntReturnType>(StaticFunctionConcreteReturnType),
|
||||
"The delegate type `FunctionPointerTests+GenericClass`1+DelegateNoArgsIntReturnType[System.Int32]` must be a non-generic type");
|
||||
}
|
||||
|
||||
// Doesn't work with IL2CPP yet - waiting for Unity fix to land. Once it does, remove `&& UNITY_EDITOR`
|
||||
#if UNITY_2021_2_OR_NEWER && UNITY_EDITOR
|
||||
[UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvCdecl) })]
|
||||
[BurstCompile]
|
||||
private static int CSharpFunctionPointerCallback(int value) => value * 2;
|
||||
|
||||
[BurstCompile(CompileSynchronously = true)]
|
||||
public unsafe struct StructWithCSharpFunctionPointer : IJob
|
||||
{
|
||||
[NativeDisableUnsafePtrRestriction]
|
||||
[ReadOnly]
|
||||
public IntPtr Callback;
|
||||
|
||||
[ReadOnly]
|
||||
public NativeArray<int> Input;
|
||||
|
||||
[WriteOnly]
|
||||
public NativeArray<int> Output;
|
||||
|
||||
public void Execute()
|
||||
{
|
||||
delegate* unmanaged[Cdecl]<int, int> callback = (delegate* unmanaged[Cdecl]<int, int>)Callback;
|
||||
Output[0] = callback(Input[0]);
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public unsafe void CSharpFunctionPointerInsideJobStructTest()
|
||||
{
|
||||
using (var input = new NativeArray<int>(new int[1] { 40 }, Allocator.Persistent))
|
||||
using (var output = new NativeArray<int>(new int[1], Allocator.Persistent))
|
||||
{
|
||||
delegate* unmanaged[Cdecl]<int, int> callback = &CSharpFunctionPointerCallback;
|
||||
|
||||
var job = new StructWithCSharpFunctionPointer
|
||||
{
|
||||
Callback = (IntPtr)callback,
|
||||
Input = input,
|
||||
Output = output
|
||||
};
|
||||
|
||||
job.Run();
|
||||
|
||||
Assert.AreEqual(40 * 2, output[0]);
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public unsafe void CSharpFunctionPointerInStaticMethodSignature()
|
||||
{
|
||||
var fp = BurstCompiler.CompileFunctionPointer<DelegateWithCSharpFunctionPointerParameter>(EntryPointWithCSharpFunctionPointerParameter);
|
||||
delegate* unmanaged[Cdecl]<int, int> callback = &CSharpFunctionPointerCallback;
|
||||
|
||||
var result = fp.Invoke((IntPtr)callback);
|
||||
|
||||
Assert.AreEqual(10, result);
|
||||
}
|
||||
|
||||
[BurstCompile(CompileSynchronously = true)]
|
||||
private static unsafe int EntryPointWithCSharpFunctionPointerParameter(IntPtr callback)
|
||||
{
|
||||
delegate* unmanaged[Cdecl]<int, int> typedCallback = (delegate* unmanaged[Cdecl]<int, int>)callback;
|
||||
return typedCallback(5);
|
||||
}
|
||||
|
||||
private unsafe delegate int DelegateWithCSharpFunctionPointerParameter(IntPtr callback);
|
||||
|
||||
[Test]
|
||||
public unsafe void FunctionPointerReturnedFromBurstFunction()
|
||||
{
|
||||
var fp = BurstCompiler.CompileFunctionPointer<DelegateWithCSharpFunctionPointerReturn>(EntryPointWithCSharpFunctionPointerReturn);
|
||||
|
||||
var fpInner = fp.Invoke();
|
||||
|
||||
delegate* unmanaged[Cdecl]<float, float, float, float, float, float, float> callback = (delegate* unmanaged[Cdecl]<float, float, float, float, float, float, float>)fpInner;
|
||||
|
||||
var result = callback(1, 2, 4, 8, 16, 32);
|
||||
|
||||
Assert.AreEqual((float)(1 + 2 + 4 + 8 + 16 + 32), result);
|
||||
}
|
||||
|
||||
[BurstCompile(CompileSynchronously = true)]
|
||||
private static unsafe IntPtr EntryPointWithCSharpFunctionPointerReturn()
|
||||
{
|
||||
delegate* unmanaged[Cdecl]<float, float, float, float, float, float, float> fp = &EntryPointWithCSharpFunctionPointerReturnHelper;
|
||||
return (IntPtr)fp;
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvCdecl) })]
|
||||
[BurstCompile(CompileSynchronously = true)]
|
||||
private static unsafe float EntryPointWithCSharpFunctionPointerReturnHelper(float p1, float p2, float p3, float p4, float p5, float p6)
|
||||
{
|
||||
return p1 + p2 + p3 + p4 + p5 + p6;
|
||||
}
|
||||
|
||||
[BurstCompile]
|
||||
[UnmanagedCallersOnly(CallConvs = new [] {typeof(CallConvCdecl)})]
|
||||
static long UnmanagedFunction(long burstCount) => 1;
|
||||
|
||||
[BurstCompile]
|
||||
static unsafe void GetUnmanagedCallableWithReturn(out Callable fn)
|
||||
{
|
||||
fn = Callable.Create<long, long>(&UnmanagedFunction);
|
||||
}
|
||||
|
||||
[Test]
|
||||
[UnityPlatform(RuntimePlatform.WindowsEditor, RuntimePlatform.OSXEditor, RuntimePlatform.LinuxEditor)]
|
||||
|
||||
public void CallOverloadedFunctionWithFpArg()
|
||||
{
|
||||
GetUnmanagedCallableWithReturn(out var a);
|
||||
Assert.AreEqual(3, a.Value);
|
||||
}
|
||||
|
||||
private delegate int Doer(int x);
|
||||
|
||||
static int DoCompileFunctionPointerNestedStaticMethod(int x)
|
||||
{
|
||||
[BurstCompile]
|
||||
static int DoIt(int x) => x * 2 - 1;
|
||||
|
||||
return BurstCompiler.CompileFunctionPointer<Doer>(DoIt).Invoke(x);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestCompileFunctionPointerNestedStaticMethod()
|
||||
{
|
||||
Assert.AreEqual(3, DoCompileFunctionPointerNestedStaticMethod(2));
|
||||
}
|
||||
|
||||
private unsafe delegate IntPtr DelegateWithCSharpFunctionPointerReturn();
|
||||
|
||||
// Note that there are 6 float parameters to try to catch any issues with calling conventions.
|
||||
private unsafe delegate float DelegateWithCSharpFunctionPointerReturnHelper(float p1, float p2, float p3, float p4, float p5, float p6);
|
||||
#endif
|
||||
|
||||
[Test]
|
||||
public void TestDelegateWithCustomAttributeThatIsNotUnmanagedFunctionPointerAttribute()
|
||||
{
|
||||
var fp = BurstCompiler.CompileFunctionPointer<TestDelegateWithCustomAttributeThatIsNotUnmanagedFunctionPointerAttributeDelegate>(TestDelegateWithCustomAttributeThatIsNotUnmanagedFunctionPointerAttributeHelper);
|
||||
|
||||
var result = fp.Invoke(42);
|
||||
|
||||
Assert.AreEqual(43, result);
|
||||
}
|
||||
[BurstCompile(CompileSynchronously = true)]
|
||||
private static int TestDelegateWithCustomAttributeThatIsNotUnmanagedFunctionPointerAttributeHelper(int x) => x + 1;
|
||||
|
||||
[MyCustomAttribute("Foo")]
|
||||
private delegate int TestDelegateWithCustomAttributeThatIsNotUnmanagedFunctionPointerAttributeDelegate(int x);
|
||||
|
||||
private sealed class MyCustomAttributeAttribute : Attribute
|
||||
{
|
||||
public MyCustomAttributeAttribute(string param) { }
|
||||
}
|
||||
}
|
||||
|
||||
#if UNITY_2021_2_OR_NEWER
|
||||
// UnmanagedCallersOnlyAttribute is new in .NET 5.0. This attribute is required
|
||||
// when you declare an unmanaged function pointer with an explicit calling convention.
|
||||
// Fortunately, Roslyn lets us declare the attribute class ourselves, and it will be used.
|
||||
// Users will need this same declaration in their own projects, in order to use
|
||||
// C# 9.0 function pointers.
|
||||
namespace System.Runtime.InteropServices
|
||||
{
|
||||
[AttributeUsage(System.AttributeTargets.Method, Inherited = false)]
|
||||
public sealed class UnmanagedCallersOnlyAttribute : Attribute
|
||||
{
|
||||
public Type[] CallConvs;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: c02f830887253c6eaf1f7780c59c5432
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,433 @@
|
|||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Runtime.InteropServices;
|
||||
using NUnit.Framework;
|
||||
using System.Text.RegularExpressions;
|
||||
using Unity.Burst;
|
||||
using Unity.Collections.LowLevel.Unsafe;
|
||||
using Unity.Jobs;
|
||||
using UnityEngine;
|
||||
using UnityEngine.TestTools;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace ExceptionsFromBurstJobs
|
||||
{
|
||||
[BurstCompile]
|
||||
class ManagedExceptionsBurstJobs
|
||||
{
|
||||
[Conditional("ENABLE_UNITY_COLLECTIONS_CHECKS")]
|
||||
private static void ThrowNewArgumentException()
|
||||
{
|
||||
throw new ArgumentException("A");
|
||||
}
|
||||
|
||||
[BurstCompile(CompileSynchronously = true)]
|
||||
struct ThrowArgumentExceptionJob : IJob
|
||||
{
|
||||
public void Execute()
|
||||
{
|
||||
ThrowNewArgumentException();
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
[UnityPlatform(RuntimePlatform.WindowsEditor, RuntimePlatform.OSXEditor, RuntimePlatform.LinuxEditor)]
|
||||
[Description("Requires ENABLE_UNITY_COLLECTIONS_CHECKS which is currently only enabled in the Editor")]
|
||||
public void ThrowArgumentException()
|
||||
{
|
||||
LogAssert.Expect(LogType.Exception, new Regex("ArgumentException: A"));
|
||||
|
||||
var jobData = new ThrowArgumentExceptionJob();
|
||||
jobData.Run();
|
||||
}
|
||||
|
||||
[Conditional("ENABLE_UNITY_COLLECTIONS_CHECKS")]
|
||||
private static void ThrowNewArgumentNullException()
|
||||
{
|
||||
throw new ArgumentNullException("N");
|
||||
}
|
||||
|
||||
[BurstCompile(CompileSynchronously = true)]
|
||||
struct ThrowArgumentNullExceptionJob : IJob
|
||||
{
|
||||
public void Execute()
|
||||
{
|
||||
ThrowNewArgumentNullException();
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
[UnityPlatform(RuntimePlatform.WindowsEditor, RuntimePlatform.OSXEditor, RuntimePlatform.LinuxEditor)]
|
||||
[Description("Requires ENABLE_UNITY_COLLECTIONS_CHECKS which is currently only enabled in the Editor")]
|
||||
public void ThrowArgumentNullException()
|
||||
{
|
||||
LogAssert.Expect(LogType.Exception, new Regex("System.ArgumentNullException: N"));
|
||||
|
||||
var jobData = new ThrowArgumentNullExceptionJob();
|
||||
jobData.Run();
|
||||
}
|
||||
|
||||
[Conditional("ENABLE_UNITY_COLLECTIONS_CHECKS")]
|
||||
private static void ThrowNewNullReferenceException()
|
||||
{
|
||||
throw new NullReferenceException("N");
|
||||
}
|
||||
|
||||
[BurstCompile(CompileSynchronously = true)]
|
||||
struct ThrowNullReferenceExceptionJob : IJob
|
||||
{
|
||||
public void Execute()
|
||||
{
|
||||
ThrowNewNullReferenceException();
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
[UnityPlatform(RuntimePlatform.WindowsEditor, RuntimePlatform.OSXEditor, RuntimePlatform.LinuxEditor)]
|
||||
[Description("Requires ENABLE_UNITY_COLLECTIONS_CHECKS which is currently only enabled in the Editor")]
|
||||
public void ThrowNullReferenceException()
|
||||
{
|
||||
LogAssert.Expect(LogType.Exception, new Regex("NullReferenceException: N"));
|
||||
|
||||
var jobData = new ThrowNullReferenceExceptionJob();
|
||||
jobData.Run();
|
||||
}
|
||||
|
||||
[Conditional("ENABLE_UNITY_COLLECTIONS_CHECKS")]
|
||||
private static void ThrowNewInvalidOperationException()
|
||||
{
|
||||
throw new InvalidOperationException("IO");
|
||||
}
|
||||
|
||||
[BurstCompile(CompileSynchronously = true)]
|
||||
struct ThrowInvalidOperationExceptionJob : IJob
|
||||
{
|
||||
public void Execute()
|
||||
{
|
||||
ThrowNewInvalidOperationException();
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
[UnityPlatform(RuntimePlatform.WindowsEditor, RuntimePlatform.OSXEditor, RuntimePlatform.LinuxEditor)]
|
||||
[Description("Requires ENABLE_UNITY_COLLECTIONS_CHECKS which is currently only enabled in the Editor")]
|
||||
public void ThrowInvalidOperationException()
|
||||
{
|
||||
LogAssert.Expect(LogType.Exception, new Regex("InvalidOperationException: IO"));
|
||||
|
||||
var jobData = new ThrowInvalidOperationExceptionJob();
|
||||
jobData.Run();
|
||||
}
|
||||
|
||||
[Conditional("ENABLE_UNITY_COLLECTIONS_CHECKS")]
|
||||
private static void ThrowNewNotSupportedException()
|
||||
{
|
||||
throw new NotSupportedException("NS");
|
||||
}
|
||||
|
||||
[BurstCompile(CompileSynchronously = true)]
|
||||
struct ThrowNotSupportedExceptionJob : IJob
|
||||
{
|
||||
public void Execute()
|
||||
{
|
||||
ThrowNewNotSupportedException();
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
[UnityPlatform(RuntimePlatform.WindowsEditor, RuntimePlatform.OSXEditor, RuntimePlatform.LinuxEditor)]
|
||||
[Description("Requires ENABLE_UNITY_COLLECTIONS_CHECKS which is currently only enabled in the Editor")]
|
||||
public void ThrowNotSupportedException()
|
||||
{
|
||||
LogAssert.Expect(LogType.Exception, new Regex("NotSupportedException: NS"));
|
||||
|
||||
var jobData = new ThrowNotSupportedExceptionJob();
|
||||
jobData.Run();
|
||||
}
|
||||
|
||||
[Conditional("ENABLE_UNITY_COLLECTIONS_CHECKS")]
|
||||
private static void ThrowNewUnityException()
|
||||
{
|
||||
throw new UnityException("UE");
|
||||
}
|
||||
|
||||
[BurstCompile(CompileSynchronously = true)]
|
||||
struct ThrowUnityExceptionJob : IJob
|
||||
{
|
||||
public void Execute()
|
||||
{
|
||||
ThrowNewUnityException();
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
[UnityPlatform(RuntimePlatform.WindowsEditor, RuntimePlatform.OSXEditor, RuntimePlatform.LinuxEditor)]
|
||||
[Description("Requires ENABLE_UNITY_COLLECTIONS_CHECKS which is currently only enabled in the Editor")]
|
||||
public void ThrowUnityException()
|
||||
{
|
||||
LogAssert.Expect(LogType.Exception, new Regex("UnityException: UE"));
|
||||
|
||||
var jobData = new ThrowUnityExceptionJob();
|
||||
jobData.Run();
|
||||
}
|
||||
|
||||
[Conditional("ENABLE_UNITY_COLLECTIONS_CHECKS")]
|
||||
private static void ThrowNewIndexOutOfRangeException()
|
||||
{
|
||||
throw new IndexOutOfRangeException("IOOR");
|
||||
}
|
||||
|
||||
[BurstCompile(CompileSynchronously = true)]
|
||||
struct ThrowIndexOutOfRangeExceptionJob : IJob
|
||||
{
|
||||
public void Execute()
|
||||
{
|
||||
ThrowNewIndexOutOfRangeException();
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
[UnityPlatform(RuntimePlatform.WindowsEditor, RuntimePlatform.OSXEditor, RuntimePlatform.LinuxEditor)]
|
||||
[Description("Requires ENABLE_UNITY_COLLECTIONS_CHECKS which is currently only enabled in the Editor")]
|
||||
public void ThrowIndexOutOfRange()
|
||||
{
|
||||
LogAssert.Expect(LogType.Exception, new Regex("IndexOutOfRangeException: IOOR"));
|
||||
|
||||
var jobData = new ThrowIndexOutOfRangeExceptionJob();
|
||||
jobData.Run();
|
||||
}
|
||||
|
||||
[BurstCompile(CompileSynchronously = true)]
|
||||
private unsafe struct ThrowFromDereferenceNullJob : IJob
|
||||
{
|
||||
[NativeDisableUnsafePtrRestriction]
|
||||
public int* Ptr;
|
||||
|
||||
public void Execute()
|
||||
{
|
||||
*Ptr = 42;
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
[UnityPlatform(RuntimePlatform.WindowsEditor, RuntimePlatform.OSXEditor, RuntimePlatform.LinuxEditor)]
|
||||
[Description("Requires ENABLE_UNITY_COLLECTIONS_CHECKS which is currently only enabled in the Editor")]
|
||||
public void ThrowFromDereferenceNull()
|
||||
{
|
||||
LogAssert.Expect(LogType.Exception, new Regex("NullReferenceException: Object reference not set to an instance of an object"));
|
||||
|
||||
var jobData = new ThrowFromDereferenceNullJob() { Ptr = null };
|
||||
jobData.Run();
|
||||
}
|
||||
|
||||
[BurstCompile(CompileSynchronously = true)]
|
||||
private unsafe struct ThrowFromDivideByZeroJob : IJob
|
||||
{
|
||||
public int Int;
|
||||
|
||||
public void Execute()
|
||||
{
|
||||
Int = 42 / Int;
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
[UnityPlatform(RuntimePlatform.WindowsEditor, RuntimePlatform.OSXEditor, RuntimePlatform.LinuxEditor)]
|
||||
[Description("Requires ENABLE_UNITY_COLLECTIONS_CHECKS which is currently only enabled in the Editor")]
|
||||
public void ThrowFromDivideByZero()
|
||||
{
|
||||
if (RuntimeInformation.OSArchitecture == Architecture.Arm64)
|
||||
{
|
||||
// Arm64 does not throw a divide-by-zero exception, instead it flushes the result to zero.
|
||||
return;
|
||||
}
|
||||
|
||||
LogAssert.Expect(LogType.Exception, new Regex("DivideByZeroException: Attempted to divide by zero"));
|
||||
|
||||
var jobData = new ThrowFromDivideByZeroJob() { Int = 0 };
|
||||
jobData.Run();
|
||||
}
|
||||
|
||||
private unsafe delegate void ExceptionDelegate(int* a);
|
||||
|
||||
[BurstCompile(CompileSynchronously = true)]
|
||||
private static unsafe void DereferenceNull(int* a)
|
||||
{
|
||||
*a = 42;
|
||||
}
|
||||
|
||||
[BurstCompile(CompileSynchronously = true)]
|
||||
unsafe struct ThrowFromFunctionPointerJob : IJob
|
||||
{
|
||||
#pragma warning disable 649
|
||||
[NativeDisableUnsafePtrRestriction] public IntPtr FuncPtr;
|
||||
[NativeDisableUnsafePtrRestriction] public int* Ptr;
|
||||
#pragma warning restore 649
|
||||
|
||||
public void Execute()
|
||||
{
|
||||
new FunctionPointer<ExceptionDelegate>(FuncPtr).Invoke(Ptr);
|
||||
|
||||
// Set Ptr to non null which should never be hit because the above will throw.
|
||||
Ptr = (int*)0x42;
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
[UnityPlatform(RuntimePlatform.WindowsEditor, RuntimePlatform.OSXEditor, RuntimePlatform.LinuxEditor)]
|
||||
[Description("Requires ENABLE_UNITY_COLLECTIONS_CHECKS which is currently only enabled in the Editor")]
|
||||
public unsafe void ThrowFromFunctionPointer()
|
||||
{
|
||||
var funcPtr = BurstCompiler.CompileFunctionPointer<ExceptionDelegate>(DereferenceNull);
|
||||
LogAssert.Expect(LogType.Exception, new Regex("NullReferenceException: Object reference not set to an instance of an object"));
|
||||
var job = new ThrowFromFunctionPointerJob { FuncPtr = funcPtr.Value, Ptr = null };
|
||||
job.Run();
|
||||
Assert.AreEqual((IntPtr)job.Ptr, (IntPtr)0);
|
||||
}
|
||||
|
||||
[BurstCompile(CompileSynchronously = true)]
|
||||
private unsafe struct ThrowFromDereferenceNullParallelJob : IJobParallelFor
|
||||
{
|
||||
[NativeDisableUnsafePtrRestriction]
|
||||
public int* Ptr;
|
||||
|
||||
public void Execute(int index)
|
||||
{
|
||||
*Ptr = index;
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
// No RuntimePlatform.OSXEditor in this list because of a subtle Mojave only bug.
|
||||
[UnityPlatform(RuntimePlatform.WindowsEditor, RuntimePlatform.LinuxEditor)]
|
||||
[Description("Requires ENABLE_UNITY_COLLECTIONS_CHECKS which is currently only enabled in the Editor")]
|
||||
public void ThrowFromDereferenceNullParallel()
|
||||
{
|
||||
var messageCount = 0;
|
||||
|
||||
void OnMessage(string message, string stackTrace, LogType type)
|
||||
{
|
||||
Assert.AreEqual(LogType.Exception, type);
|
||||
StringAssert.Contains("NullReferenceException: Object reference not set to an instance of an object", message);
|
||||
messageCount++;
|
||||
}
|
||||
|
||||
LogAssert.ignoreFailingMessages = true;
|
||||
Application.logMessageReceivedThreaded += OnMessage;
|
||||
|
||||
try
|
||||
{
|
||||
var jobData = new ThrowFromDereferenceNullParallelJob() { Ptr = null };
|
||||
jobData.Schedule(128, 1).Complete();
|
||||
|
||||
Assert.GreaterOrEqual(messageCount, 1);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Application.logMessageReceivedThreaded -= OnMessage;
|
||||
LogAssert.ignoreFailingMessages = false;
|
||||
}
|
||||
}
|
||||
|
||||
private unsafe struct ThrowFromDereferenceNullManagedJob : IJob
|
||||
{
|
||||
[NativeDisableUnsafePtrRestriction]
|
||||
public int* Ptr;
|
||||
|
||||
public void Execute()
|
||||
{
|
||||
*Ptr = 42;
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
[UnityPlatform(RuntimePlatform.WindowsEditor, RuntimePlatform.OSXEditor, RuntimePlatform.LinuxEditor)]
|
||||
[Description("Requires ENABLE_UNITY_COLLECTIONS_CHECKS which is currently only enabled in the Editor")]
|
||||
public void ThrowFromDereferenceNullManaged()
|
||||
{
|
||||
LogAssert.Expect(LogType.Exception, new Regex("NullReferenceException: Object reference not set to an instance of an object"));
|
||||
|
||||
var jobData = new ThrowFromDereferenceNullManagedJob() { Ptr = null };
|
||||
jobData.Run();
|
||||
}
|
||||
|
||||
[Test]
|
||||
[UnityPlatform(RuntimePlatform.WindowsEditor, RuntimePlatform.OSXEditor, RuntimePlatform.LinuxEditor)]
|
||||
[Description("Requires ENABLE_UNITY_COLLECTIONS_CHECKS which is currently only enabled in the Editor")]
|
||||
public void ThrowFromDereferenceNullBurstDisabled()
|
||||
{
|
||||
var previous = BurstCompiler.Options.EnableBurstCompilation;
|
||||
BurstCompiler.Options.EnableBurstCompilation = false;
|
||||
|
||||
LogAssert.Expect(LogType.Exception, new Regex("NullReferenceException: Object reference not set to an instance of an object"));
|
||||
|
||||
var jobData = new ThrowFromDereferenceNullJob() { Ptr = null };
|
||||
jobData.Run();
|
||||
|
||||
BurstCompiler.Options.EnableBurstCompilation = previous;
|
||||
}
|
||||
|
||||
|
||||
[BurstCompile]
|
||||
struct Thrower : IJob
|
||||
{
|
||||
public int X;
|
||||
|
||||
[BurstCompile(CompileSynchronously = true)]
|
||||
[Conditional("ENABLE_UNITY_COLLECTIONS_CHECKS")]
|
||||
[MethodImpl(MethodImplOptions.NoInlining)]
|
||||
public static void ConditionalThrowWithSideEffect(int x)
|
||||
{
|
||||
if (x == -1)
|
||||
throw new InvalidOperationException();
|
||||
|
||||
UnityEngine.Debug.Log("wow");
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
|
||||
public void Execute()
|
||||
{
|
||||
ConditionalThrowWithSideEffect(X);
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
[UnityPlatform(RuntimePlatform.WindowsEditor, RuntimePlatform.OSXEditor, RuntimePlatform.LinuxEditor)]
|
||||
[Description("Requires ENABLE_UNITY_COLLECTIONS_CHECKS which is currently only enabled in the Editor")]
|
||||
public void TestConditionalThrowWithSideEffect()
|
||||
{
|
||||
LogAssert.Expect(LogType.Log, "wow");
|
||||
LogAssert.Expect(LogType.Exception, new Regex(".+InvalidOperation.+"));
|
||||
|
||||
new Thrower() { X = 0 }.Run();
|
||||
}
|
||||
|
||||
private unsafe struct ThrowFromManagedStackOverflowJob : IJob
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)]
|
||||
private static int DoStackOverflow(ref int x)
|
||||
{
|
||||
// Copy just to make the stack grow.
|
||||
var copy = x;
|
||||
return copy + DoStackOverflow(ref x);
|
||||
}
|
||||
|
||||
public int Int;
|
||||
|
||||
public void Execute()
|
||||
{
|
||||
Int = DoStackOverflow(ref Int);
|
||||
}
|
||||
}
|
||||
|
||||
//[Test]
|
||||
//[UnityPlatform(RuntimePlatform.WindowsEditor, RuntimePlatform.OSXEditor, RuntimePlatform.LinuxEditor)]
|
||||
public void ThrowFromManagedStackOverflow()
|
||||
{
|
||||
LogAssert.Expect(LogType.Exception, new Regex("StackOverflowException: The requested operation caused a stack overflow"));
|
||||
|
||||
var jobData = new ThrowFromManagedStackOverflowJob() { Int = 1 };
|
||||
jobData.Run();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: d54dbb53d4313cc8b7d8289a75202585
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,94 @@
|
|||
using NUnit.Framework;
|
||||
using System.Text.RegularExpressions;
|
||||
using Unity.Burst;
|
||||
using Unity.Collections;
|
||||
using Unity.Collections.LowLevel.Unsafe;
|
||||
using Unity.Jobs;
|
||||
using UnityEngine;
|
||||
using UnityEngine.TestTools;
|
||||
|
||||
namespace ExceptionsFromBurstJobs
|
||||
{
|
||||
class NativeTriggeredManagedExceptionsBurstJobs
|
||||
{
|
||||
[BurstCompile(CompileSynchronously = true)]
|
||||
struct RaiseMonoExceptionJob : IJob
|
||||
{
|
||||
public float output;
|
||||
public void Execute()
|
||||
{
|
||||
output = Time.deltaTime;
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
[UnityPlatform(RuntimePlatform.WindowsEditor, RuntimePlatform.OSXEditor, RuntimePlatform.LinuxEditor)]
|
||||
[Description("Requires ENABLE_UNITY_COLLECTIONS_CHECKS which is currently only enabled in the Editor")]
|
||||
public void RaiseMonoException()
|
||||
{
|
||||
var job = new RaiseMonoExceptionJob();
|
||||
LogAssert.Expect(LogType.Exception, new Regex(
|
||||
"UnityEngine::UnityException: get_deltaTime can only be called from the main thread." + "[\\s]*" +
|
||||
"Constructors and field initializers will be executed from the loading thread when loading a scene." + "[\\s]*" +
|
||||
"Don't use this function in the constructor or field initializers, instead move initialization code to the Awake or Start function." + "[\\s]*" +
|
||||
"This Exception was thrown from a job compiled with Burst, which has limited exception support."
|
||||
));
|
||||
job.Run();
|
||||
}
|
||||
|
||||
[BurstCompile(CompileSynchronously = true)]
|
||||
struct RaiseInvalidOperationExceptionJob : IJob
|
||||
{
|
||||
[ReadOnly]
|
||||
public NativeArray<int> test;
|
||||
public void Execute()
|
||||
{
|
||||
test[0] = 5;
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
[UnityPlatform(RuntimePlatform.WindowsEditor, RuntimePlatform.OSXEditor, RuntimePlatform.LinuxEditor)]
|
||||
[Description("Requires ENABLE_UNITY_COLLECTIONS_CHECKS which is currently only enabled in the Editor")]
|
||||
public void RaiseInvalidOperationException()
|
||||
{
|
||||
var jobData = new RaiseInvalidOperationExceptionJob();
|
||||
var testArray = new NativeArray<int>(1, Allocator.Persistent);
|
||||
jobData.test = testArray;
|
||||
|
||||
LogAssert.Expect(LogType.Exception, new Regex(
|
||||
"System::InvalidOperationException: The .+ has been declared as \\[ReadOnly\\] in the job( .+)?, but you are writing to it\\." + "[\\s]*" +
|
||||
"This Exception was thrown from a job compiled with Burst, which has limited exception support."
|
||||
));
|
||||
jobData.Run();
|
||||
testArray.Dispose();
|
||||
}
|
||||
|
||||
[BurstCompile(CompileSynchronously = true)]
|
||||
unsafe struct RaiseArgumentNullExceptionJob : IJob
|
||||
{
|
||||
#pragma warning disable 649
|
||||
[NativeDisableUnsafePtrRestriction] public void* dst;
|
||||
#pragma warning restore 649
|
||||
public void Execute()
|
||||
{
|
||||
UnsafeUtility.MemCpy(dst, null, 10);
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
[UnityPlatform(RuntimePlatform.WindowsEditor, RuntimePlatform.OSXEditor, RuntimePlatform.LinuxEditor)]
|
||||
[Description("Requires ENABLE_UNITY_COLLECTIONS_CHECKS which is currently only enabled in the Editor")]
|
||||
unsafe public void RaiseArgumentNullException()
|
||||
{
|
||||
var jobData = new RaiseArgumentNullExceptionJob();
|
||||
jobData.dst = UnsafeUtility.Malloc(10, 4, Allocator.Temp);
|
||||
LogAssert.Expect(LogType.Exception, new Regex(
|
||||
"System.ArgumentNullException: source" + "[\\s]*" +
|
||||
"This Exception was thrown from a job compiled with Burst, which has limited exception support."
|
||||
));
|
||||
jobData.Run();
|
||||
UnsafeUtility.Free(jobData.dst, Allocator.Temp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: ac74b11ef46b35938b5d3ca8a4109efa
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,289 @@
|
|||
using System.Collections;
|
||||
using NUnit.Framework;
|
||||
using Unity.Burst;
|
||||
using UnityEngine;
|
||||
using Unity.Jobs.LowLevel.Unsafe;
|
||||
using UnityEngine.TestTools;
|
||||
using System;
|
||||
using Unity.Jobs;
|
||||
|
||||
[TestFixture]
|
||||
public class PlaymodeTest
|
||||
{
|
||||
// [UnityTest]
|
||||
public IEnumerator CheckBurstJobEnabledDisabled()
|
||||
{
|
||||
BurstCompiler.Options.EnableBurstCompileSynchronously = true;
|
||||
foreach(var item in CheckBurstJobDisabled()) yield return item;
|
||||
foreach(var item in CheckBurstJobEnabled()) yield return item;
|
||||
}
|
||||
|
||||
private IEnumerable CheckBurstJobEnabled()
|
||||
{
|
||||
BurstCompiler.Options.EnableBurstCompilation = true;
|
||||
|
||||
yield return null;
|
||||
|
||||
using (var jobTester = new BurstJobTester2())
|
||||
{
|
||||
var result = jobTester.Calculate();
|
||||
Assert.AreNotEqual(0.0f, result);
|
||||
}
|
||||
}
|
||||
|
||||
private IEnumerable CheckBurstJobDisabled()
|
||||
{
|
||||
BurstCompiler.Options.EnableBurstCompilation = false;
|
||||
|
||||
yield return null;
|
||||
|
||||
using (var jobTester = new BurstJobTester2())
|
||||
{
|
||||
var result = jobTester.Calculate();
|
||||
Assert.AreEqual(0.0f, result);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
[BurstCompile(CompileSynchronously = true)]
|
||||
private struct ThrowingJob : IJob
|
||||
{
|
||||
public int I;
|
||||
|
||||
public void Execute()
|
||||
{
|
||||
if (I < 0)
|
||||
{
|
||||
throw new System.Exception("Some Exception!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void NoSafetyCheckExceptionWarningInEditor()
|
||||
{
|
||||
var job = new ThrowingJob { I = 42 };
|
||||
job.Schedule().Complete();
|
||||
|
||||
// UNITY_BURST_DEBUG enables additional logging which messes with our check.
|
||||
if (null == System.Environment.GetEnvironmentVariable("UNITY_BURST_DEBUG"))
|
||||
{
|
||||
LogAssert.NoUnexpectedReceived();
|
||||
}
|
||||
}
|
||||
|
||||
private struct MyKey { public struct MySubKey0 { } public struct MySubKey1 { } }
|
||||
private struct SomeGenericStruct<T> {}
|
||||
|
||||
private static readonly SharedStatic<int> SharedStaticOneType = SharedStatic<int>.GetOrCreate<MyKey>();
|
||||
private static readonly SharedStatic<double> SharedStaticTwoTypes0 = SharedStatic<double>.GetOrCreate<MyKey, MyKey.MySubKey0>();
|
||||
private static readonly SharedStatic<double> SharedStaticTwoTypes1 = SharedStatic<double>.GetOrCreate<MyKey, MyKey.MySubKey1>();
|
||||
|
||||
private struct MyGenericContainingStruct<T>
|
||||
{
|
||||
public static readonly SharedStatic<int> Data0 = SharedStatic<int>.GetOrCreate<T>();
|
||||
public static readonly SharedStatic<int> Data1 = SharedStatic<int>.GetOrCreate<SomeGenericStruct<MyKey>, T>();
|
||||
public static readonly SharedStatic<int> Data2 = SharedStatic<int>.GetOrCreate<SomeGenericStruct<T>, MyKey>();
|
||||
}
|
||||
|
||||
private static readonly SharedStatic<int> SharedStaticWithSystemTypes0 = SharedStatic<int>.GetOrCreate<IntPtr>();
|
||||
private static readonly SharedStatic<int> SharedStaticWithSystemTypes1 = SharedStatic<int>.GetOrCreate<IntPtr, MyKey>();
|
||||
private static readonly SharedStatic<int> SharedStaticWithSystemTypes2 = SharedStatic<int>.GetOrCreate<MyKey, IntPtr>();
|
||||
private static readonly SharedStatic<int> SharedStaticWithSystemTypes3 = SharedStatic<int>.GetOrCreate<IntPtr, IntPtr>();
|
||||
|
||||
[Test]
|
||||
public unsafe void SharedStaticPostProcessedTests()
|
||||
{
|
||||
var oneType = SharedStatic<int>.GetOrCreate(typeof(MyKey));
|
||||
Assert.AreEqual((IntPtr)oneType.UnsafeDataPointer, (IntPtr)SharedStaticOneType.UnsafeDataPointer);
|
||||
Assert.AreNotEqual((IntPtr)oneType.UnsafeDataPointer, (IntPtr)SharedStaticTwoTypes0.UnsafeDataPointer);
|
||||
Assert.AreNotEqual((IntPtr)oneType.UnsafeDataPointer, (IntPtr)SharedStaticTwoTypes1.UnsafeDataPointer);
|
||||
|
||||
var twoTypes0 = SharedStatic<double>.GetOrCreate(typeof(MyKey), typeof(MyKey.MySubKey0));
|
||||
Assert.AreEqual((IntPtr)twoTypes0.UnsafeDataPointer, (IntPtr)SharedStaticTwoTypes0.UnsafeDataPointer);
|
||||
Assert.AreNotEqual((IntPtr)twoTypes0.UnsafeDataPointer, (IntPtr)SharedStaticOneType.UnsafeDataPointer);
|
||||
Assert.AreNotEqual((IntPtr)twoTypes0.UnsafeDataPointer, (IntPtr)SharedStaticTwoTypes1.UnsafeDataPointer);
|
||||
|
||||
var twoTypes1 = SharedStatic<double>.GetOrCreate(typeof(MyKey), typeof(MyKey.MySubKey1));
|
||||
Assert.AreEqual((IntPtr)twoTypes1.UnsafeDataPointer, (IntPtr)SharedStaticTwoTypes1.UnsafeDataPointer);
|
||||
Assert.AreNotEqual((IntPtr)twoTypes1.UnsafeDataPointer, (IntPtr)SharedStaticOneType.UnsafeDataPointer);
|
||||
Assert.AreNotEqual((IntPtr)twoTypes1.UnsafeDataPointer, (IntPtr)SharedStaticTwoTypes0.UnsafeDataPointer);
|
||||
|
||||
// A shared static in a generic struct, that uses the same type for `GetOrCreate`, will resolve to the same shared static.
|
||||
Assert.AreEqual((IntPtr)oneType.UnsafeDataPointer, (IntPtr)MyGenericContainingStruct<MyKey>.Data0.UnsafeDataPointer);
|
||||
|
||||
// These two test partial evaluations of shared statics (where we can evaluate one of the template arguments at ILPP time
|
||||
// but not both).
|
||||
Assert.AreEqual(
|
||||
(IntPtr)MyGenericContainingStruct<MyKey>.Data1.UnsafeDataPointer,
|
||||
(IntPtr)MyGenericContainingStruct<MyKey>.Data2.UnsafeDataPointer);
|
||||
|
||||
// Check that system type evaluations all match up.
|
||||
Assert.AreEqual(
|
||||
(IntPtr)SharedStatic<int>.GetOrCreate(typeof(IntPtr)).UnsafeDataPointer,
|
||||
(IntPtr)SharedStaticWithSystemTypes0.UnsafeDataPointer);
|
||||
Assert.AreEqual(
|
||||
(IntPtr)SharedStatic<int>.GetOrCreate(typeof(IntPtr), typeof(MyKey)).UnsafeDataPointer,
|
||||
(IntPtr)SharedStaticWithSystemTypes1.UnsafeDataPointer);
|
||||
Assert.AreEqual(
|
||||
(IntPtr)SharedStatic<int>.GetOrCreate(typeof(MyKey), typeof(IntPtr)).UnsafeDataPointer,
|
||||
(IntPtr)SharedStaticWithSystemTypes2.UnsafeDataPointer);
|
||||
Assert.AreEqual(
|
||||
(IntPtr)SharedStatic<int>.GetOrCreate(typeof(IntPtr), typeof(IntPtr)).UnsafeDataPointer,
|
||||
(IntPtr)SharedStaticWithSystemTypes3.UnsafeDataPointer);
|
||||
}
|
||||
|
||||
[BurstCompile]
|
||||
public struct SomeFunctionPointers
|
||||
{
|
||||
[BurstDiscard]
|
||||
private static void MessWith(ref int a) => a += 13;
|
||||
|
||||
[BurstCompile]
|
||||
public static int A(int a, int b)
|
||||
{
|
||||
MessWith(ref a);
|
||||
return a + b;
|
||||
}
|
||||
|
||||
[BurstCompile(DisableDirectCall = true)]
|
||||
public static int B(int a, int b)
|
||||
{
|
||||
MessWith(ref a);
|
||||
return a - b;
|
||||
}
|
||||
|
||||
[BurstCompile(CompileSynchronously = true)]
|
||||
public static int C(int a, int b)
|
||||
{
|
||||
MessWith(ref a);
|
||||
return a * b;
|
||||
}
|
||||
|
||||
[BurstCompile(CompileSynchronously = true, DisableDirectCall = true)]
|
||||
public static int D(int a, int b)
|
||||
{
|
||||
MessWith(ref a);
|
||||
return a / b;
|
||||
}
|
||||
|
||||
public delegate int Delegate(int a, int b);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestDirectCalls()
|
||||
{
|
||||
Assert.IsTrue(BurstCompiler.IsEnabled);
|
||||
|
||||
// a can either be (42 + 13) + 53 or 42 + 53 (depending on whether it was burst compiled).
|
||||
var a = SomeFunctionPointers.A(42, 53);
|
||||
Assert.IsTrue((a == ((42 + 13) + 53)) || (a == (42 + 53)));
|
||||
|
||||
// b can only be (42 + 13) - 53, because direct call is disabled and so we always call the managed method.
|
||||
var b = SomeFunctionPointers.B(42, 53);
|
||||
Assert.AreEqual((42 + 13) - 53, b);
|
||||
|
||||
// c can only be 42 * 53, because synchronous compilation is enabled.
|
||||
var c = SomeFunctionPointers.C(42, 53);
|
||||
Assert.AreEqual(42 * 53, c);
|
||||
|
||||
// d can only be (42 + 13) / 53, because even though synchronous compilation is enabled, direct call is disabled.
|
||||
var d = SomeFunctionPointers.D(42, 53);
|
||||
Assert.AreEqual((42 + 13) / 53, d);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestDirectCallInNamespacedClass()
|
||||
{
|
||||
void onCompileILPPMethod2()
|
||||
{
|
||||
Assert.Fail("BurstCompiler.CompileILPPMethod2 should not have been called at this time");
|
||||
}
|
||||
|
||||
// We expect BurstCompiler.CompileILPPMethod2 to have been called at startup, via
|
||||
// [InitializeOnLoad] or [RuntimeInitializeOnLoadMethod]. If it's called when we invoke
|
||||
// N.C.A(), then something has gone wrong.
|
||||
|
||||
try
|
||||
{
|
||||
BurstCompiler.OnCompileILPPMethod2 += onCompileILPPMethod2;
|
||||
|
||||
var result = N.C.A();
|
||||
Assert.AreEqual(42, result);
|
||||
}
|
||||
finally
|
||||
{
|
||||
BurstCompiler.OnCompileILPPMethod2 -= onCompileILPPMethod2;
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestFunctionPointers()
|
||||
{
|
||||
Assert.IsTrue(BurstCompiler.IsEnabled);
|
||||
|
||||
var A = BurstCompiler.CompileFunctionPointer<SomeFunctionPointers.Delegate>(SomeFunctionPointers.A);
|
||||
var B = BurstCompiler.CompileFunctionPointer<SomeFunctionPointers.Delegate>(SomeFunctionPointers.B);
|
||||
var C = BurstCompiler.CompileFunctionPointer<SomeFunctionPointers.Delegate>(SomeFunctionPointers.C);
|
||||
var D = BurstCompiler.CompileFunctionPointer<SomeFunctionPointers.Delegate>(SomeFunctionPointers.D);
|
||||
|
||||
// a can either be (42 + 13) + 53 or 42 + 53 (depending on whether it was burst compiled).
|
||||
var a = A.Invoke(42, 53);
|
||||
Assert.IsTrue((a == ((42 + 13) + 53)) || (a == (42 + 53)));
|
||||
|
||||
// b can either be (42 + 13) - 53 or 42 - 53 (depending on whether it was burst compiled).
|
||||
var b = B.Invoke(42, 53);
|
||||
Assert.IsTrue((b == ((42 + 13) - 53)) || (b == (42 - 53)));
|
||||
|
||||
// c can only be 42 * 53, because synchronous compilation is enabled.
|
||||
var c = C.Invoke(42, 53);
|
||||
Assert.AreEqual(42 * 53, c);
|
||||
|
||||
// d can only be 42 / 53, because synchronous compilation is enabled.
|
||||
var d = D.Invoke(42, 53);
|
||||
Assert.AreEqual(42 / 53, d);
|
||||
}
|
||||
|
||||
[BurstCompile]
|
||||
public static class GenericClass<T>
|
||||
{
|
||||
[BurstCompile]
|
||||
public static int ConcreteMethod() => 3;
|
||||
}
|
||||
|
||||
public delegate int NoArgsIntReturnDelegate();
|
||||
|
||||
[Test]
|
||||
public void TestGenericClassConcreteMethodFunctionPointer()
|
||||
{
|
||||
Assert.IsTrue(BurstCompiler.IsEnabled);
|
||||
var F = BurstCompiler.CompileFunctionPointer<NoArgsIntReturnDelegate>(GenericClass<int>.ConcreteMethod);
|
||||
Assert.AreEqual(3, F.Invoke());
|
||||
}
|
||||
}
|
||||
|
||||
// This test class is intentionally in a namespace to ensure that our
|
||||
// direct-call [RuntimeInitializeOnLoadMethod] works correctly in that
|
||||
// scenario.
|
||||
namespace N
|
||||
{
|
||||
[BurstCompile]
|
||||
internal static class C
|
||||
{
|
||||
public static int A() => B();
|
||||
|
||||
[BurstCompile(CompileSynchronously = true)]
|
||||
private static int B()
|
||||
{
|
||||
var x = 42;
|
||||
DiscardedMethod(ref x);
|
||||
return x;
|
||||
}
|
||||
|
||||
[BurstDiscard]
|
||||
private static void DiscardedMethod(ref int x)
|
||||
{
|
||||
x += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: eb7078968c7e3322a80bb099e19fb2e8
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 30b8c33e57eb30adbfd9b640a4edaef8
|
||||
folderAsset: yes
|
||||
|
|
@ -0,0 +1,246 @@
|
|||
using NUnit.Framework;
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using Unity.Burst;
|
||||
using Unity.Mathematics;
|
||||
|
||||
namespace Burst.Compiler.IL.Tests
|
||||
{
|
||||
/// <summary>
|
||||
/// Tests types
|
||||
/// </summary>
|
||||
[BurstCompile]
|
||||
internal class NotSupported
|
||||
{
|
||||
[TestCompiler(ExpectCompilerException = true, ExpectedDiagnosticId = DiagnosticId.ERR_OnlyStaticMethodsAllowed)]
|
||||
public int InstanceMethod()
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
[TestCompiler(1, ExpectCompilerException = true, ExpectedDiagnosticIds = new[] { DiagnosticId.ERR_CallingManagedMethodNotSupported })]
|
||||
public static int TestDelegate(int data)
|
||||
{
|
||||
return ProcessData(i => i + 1, data);
|
||||
}
|
||||
|
||||
private static int ProcessData(Func<int, int> yo, int value)
|
||||
{
|
||||
return yo(value);
|
||||
}
|
||||
|
||||
public struct HasMarshalAttribute
|
||||
{
|
||||
[MarshalAs(UnmanagedType.U1)] public bool A;
|
||||
}
|
||||
|
||||
//[TestCompiler(ExpectCompilerException = true)]
|
||||
[TestCompiler] // Because MarshalAs is used in mathematics we cannot disable it for now
|
||||
public static void TestStructWithMarshalAs()
|
||||
{
|
||||
#pragma warning disable 0219
|
||||
var x = new HasMarshalAttribute();
|
||||
#pragma warning restore 0219
|
||||
}
|
||||
|
||||
public struct HasMarshalAsSysIntAttribute
|
||||
{
|
||||
[MarshalAs(UnmanagedType.SysInt)] public bool A;
|
||||
}
|
||||
|
||||
[TestCompiler(ExpectCompilerException = true, ExpectedDiagnosticId = DiagnosticId.ERR_MarshalAsOnFieldNotSupported)]
|
||||
public static void TestStructWithMarshalAsSysInt()
|
||||
{
|
||||
#pragma warning disable 0219
|
||||
var x = new HasMarshalAsSysIntAttribute();
|
||||
#pragma warning restore 0219
|
||||
}
|
||||
|
||||
[TestCompiler(42, ExpectCompilerException = true, ExpectedDiagnosticId = DiagnosticId.ERR_MarshalAsOnParameterNotSupported)]
|
||||
public static void TestMethodWithMarshalAsParameter([MarshalAs(UnmanagedType.I8)] int x)
|
||||
{
|
||||
}
|
||||
|
||||
[TestCompiler(ExpectCompilerException = true, ExpectedDiagnosticId = DiagnosticId.ERR_MarshalAsOnReturnTypeNotSupported)]
|
||||
[return: MarshalAs(UnmanagedType.I8)]
|
||||
public static int TestMethodWithMarshalAsReturnType()
|
||||
{
|
||||
return 42;
|
||||
}
|
||||
|
||||
private static float3 a = new float3(1, 2, 3);
|
||||
|
||||
[TestCompiler(ExpectCompilerException = true, ExpectedDiagnosticId = DiagnosticId.ERR_LoadingFromNonReadonlyStaticFieldNotSupported)]
|
||||
public static bool TestStaticLoad()
|
||||
{
|
||||
var cmp = a == new float3(1, 2, 3);
|
||||
|
||||
return cmp.x && cmp.y && cmp.z;
|
||||
}
|
||||
|
||||
[TestCompiler(ExpectCompilerException = true, ExpectedDiagnosticId = DiagnosticId.ERR_LoadingFromManagedNonReadonlyStaticFieldNotSupported)]
|
||||
public static void TestStaticStore()
|
||||
{
|
||||
a.x = 42;
|
||||
}
|
||||
|
||||
private interface ISomething
|
||||
{
|
||||
void DoSomething();
|
||||
}
|
||||
|
||||
private struct Something : ISomething
|
||||
{
|
||||
public byte A;
|
||||
|
||||
public void DoSomething()
|
||||
{
|
||||
A = 42;
|
||||
}
|
||||
}
|
||||
|
||||
private static ISomething something = new Something { A = 13 };
|
||||
|
||||
[TestCompiler(ExpectCompilerException = true, ExpectedDiagnosticId = DiagnosticId.ERR_LoadingFromManagedNonReadonlyStaticFieldNotSupported)]
|
||||
public static void TestStaticInterfaceStore()
|
||||
{
|
||||
something.DoSomething();
|
||||
}
|
||||
|
||||
private static int i = 42;
|
||||
|
||||
[TestCompiler(ExpectCompilerException = true, ExpectedDiagnosticId = DiagnosticId.ERR_LoadingFromNonReadonlyStaticFieldNotSupported)]
|
||||
public static int TestStaticIntLoad()
|
||||
{
|
||||
return i;
|
||||
}
|
||||
|
||||
[TestCompiler(ExpectCompilerException = true, ExpectedDiagnosticId = DiagnosticId.ERR_InstructionStsfldNotSupported)]
|
||||
public static void TestStaticIntStore()
|
||||
{
|
||||
i = 13;
|
||||
}
|
||||
|
||||
public delegate char CharbyValueDelegate(char c);
|
||||
|
||||
#if BURST_TESTS_ONLY
|
||||
[BurstCompile]
|
||||
#endif
|
||||
public static char CharbyValue(char c)
|
||||
{
|
||||
return c;
|
||||
}
|
||||
|
||||
public struct CharbyValueFunc : IFunctionPointerProvider
|
||||
{
|
||||
public FunctionPointer<CharbyValueDelegate> FunctionPointer;
|
||||
|
||||
public object FromIntPtr(IntPtr ptr)
|
||||
{
|
||||
return new CharbyValueFunc() { FunctionPointer = new FunctionPointer<CharbyValueDelegate>(ptr) };
|
||||
}
|
||||
}
|
||||
|
||||
[TestCompiler(nameof(CharbyValue), 0x1234, ExpectCompilerException = true, ExpectedDiagnosticIds = new[] { DiagnosticId.ERR_TypeNotBlittableForFunctionPointer, DiagnosticId.ERR_StructsWithNonUnicodeCharsNotSupported })]
|
||||
public static int TestCharbyValue(ref CharbyValueFunc fp, int i)
|
||||
{
|
||||
var c = (char)i;
|
||||
return fp.FunctionPointer.Invoke(c);
|
||||
}
|
||||
|
||||
struct Halfs
|
||||
{
|
||||
public static readonly half3 h3_h = new half3(new half(42.0f));
|
||||
public static readonly half3 h3_d = new half3(0.5);
|
||||
public static readonly half3 h3_v2s = new half3(new half2(new half(1.0f), new half(2.0f)), new half(0.5f));
|
||||
public static readonly half3 h3_sv2 = new half3(new half(0.5f), new half2(new half(1.0f), new half(2.0f)));
|
||||
public static readonly half3 h3_v3 = new half3(new half(0.5f), new half(42.0f), new half(13.0f));
|
||||
}
|
||||
|
||||
[TestCompiler]
|
||||
public static float TestStaticHalf3()
|
||||
{
|
||||
var result = (float3)Halfs.h3_h + Halfs.h3_d + Halfs.h3_v2s + Halfs.h3_sv2 + Halfs.h3_v3;
|
||||
return result.x + result.y + result.z;
|
||||
}
|
||||
|
||||
[TestCompiler(42, 13, ExpectCompilerException = true, ExpectedDiagnosticId = DiagnosticId.ERR_AssertTypeNotSupported)]
|
||||
public static void TestAreEqual(int a, int b)
|
||||
{
|
||||
Assert.AreEqual(a, b, "unsupported", new object[0]);
|
||||
}
|
||||
|
||||
[TestCompiler(ExpectCompilerException = true, ExpectedDiagnosticId = DiagnosticId.ERR_InstructionLdtokenTypeNotSupported)]
|
||||
public static bool TestTypeof()
|
||||
{
|
||||
return typeof(int).IsPrimitive;
|
||||
}
|
||||
|
||||
public class AwfulClass
|
||||
{
|
||||
public int Foo;
|
||||
}
|
||||
|
||||
public struct BetterStruct
|
||||
{
|
||||
public int Foo;
|
||||
}
|
||||
|
||||
public struct MixedStaticInits
|
||||
{
|
||||
public static readonly AwfulClass AC = new AwfulClass { Foo = 42 };
|
||||
public static readonly BetterStruct BS = new BetterStruct { Foo = 42 };
|
||||
}
|
||||
|
||||
[TestCompiler(ExpectCompilerException = true, ExpectedDiagnosticIds = new[] { DiagnosticId.ERR_InstructionNewobjWithManagedTypeNotSupported, DiagnosticId.ERR_ManagedStaticConstructor })]
|
||||
public static int TestMixedStaticInits()
|
||||
{
|
||||
return MixedStaticInits.BS.Foo;
|
||||
}
|
||||
|
||||
public struct StaticArrayWrapper
|
||||
{
|
||||
private const int ArrayLength = 4;
|
||||
public static readonly int[] StaticArray = new int[4];
|
||||
|
||||
static StaticArrayWrapper()
|
||||
{
|
||||
for (int i = 0; i < ArrayLength; ++i)
|
||||
{
|
||||
StaticArray[i] = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[TestCompiler]
|
||||
public unsafe static int TestStaticArrayWrapper()
|
||||
{
|
||||
return StaticArrayWrapper.StaticArray[0];
|
||||
}
|
||||
|
||||
class NestedArrayHolder
|
||||
{
|
||||
public static readonly int4[][] SomeOffsetThing =
|
||||
{
|
||||
new[] {new int4(0), new int4(0, 0, 1, 0), new int4(0, 1, 0, 0), new int4(0, 1, 1, 0)},
|
||||
new[] {new int4(0), new int4(1, 0, 0, 0), new int4(0, 0, 1, 0), new int4(1, 0, 1, 0)},
|
||||
new[] {new int4(0), new int4(0, 1, 0, 0), new int4(1, 0, 0, 0), new int4(1, 1, 0, 0)},
|
||||
};
|
||||
}
|
||||
|
||||
[TestCompiler]
|
||||
public unsafe static int TestNestedManagedArrays()
|
||||
{
|
||||
return NestedArrayHolder.SomeOffsetThing[0][0].x;
|
||||
}
|
||||
|
||||
public static readonly int[,] SomeMultiDimensionalThing = new int[2, 4]
|
||||
{
|
||||
{ 1, 2, 3, 4 },
|
||||
{ -1, -2, -3, -4 },
|
||||
};
|
||||
|
||||
[TestCompiler(ExpectCompilerException = true, ExpectedDiagnosticIds = new[] { DiagnosticId.ERR_ConstructorNotSupported, DiagnosticId.ERR_MultiDimensionalArrayUnsupported })]
|
||||
public static int TestMultiDimensionalArray() => SomeMultiDimensionalThing[1, 1];
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 5eb12402c8b53dbaa40d67a6ccd1b4f6
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,158 @@
|
|||
using System;
|
||||
using Unity.Collections.LowLevel.Unsafe;
|
||||
|
||||
namespace Burst.Compiler.IL.Tests
|
||||
{
|
||||
#if UNITY_2021_2_OR_NEWER || BURST_INTERNAL
|
||||
/// <summary>
|
||||
/// Test <see cref="System.ReadOnlySpan{T}"/>.
|
||||
/// </summary>
|
||||
internal partial class ReadOnlySpan
|
||||
{
|
||||
[TestCompiler]
|
||||
public static int CreateDefault()
|
||||
{
|
||||
var span = new ReadOnlySpan<int>();
|
||||
|
||||
return span.Length;
|
||||
}
|
||||
|
||||
[TestCompiler]
|
||||
public static int CreateStackalloc()
|
||||
{
|
||||
ReadOnlySpan<int> span = stackalloc int[42];
|
||||
|
||||
return span.Length;
|
||||
}
|
||||
|
||||
[TestCompiler(42)]
|
||||
public static int CreateFromNullPointer(int size)
|
||||
{
|
||||
ReadOnlySpan<double> span;
|
||||
|
||||
unsafe
|
||||
{
|
||||
span = new ReadOnlySpan<double>(null, size);
|
||||
}
|
||||
|
||||
return span.Length;
|
||||
}
|
||||
|
||||
[TestCompiler]
|
||||
public static unsafe double CreateFromMalloc()
|
||||
{
|
||||
double* malloc = (double*)UnsafeUtility.Malloc(UnsafeUtility.SizeOf<double>(), UnsafeUtility.AlignOf<double>(), Unity.Collections.Allocator.Persistent);
|
||||
*malloc = 42.0f;
|
||||
|
||||
var span = new ReadOnlySpan<double>(malloc, 1);
|
||||
|
||||
double result = span[0];
|
||||
|
||||
UnsafeUtility.Free(malloc, Unity.Collections.Allocator.Persistent);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
[TestCompiler]
|
||||
public static int GetItem()
|
||||
{
|
||||
ReadOnlySpan<int> span = stackalloc int[42];
|
||||
return span[41];
|
||||
}
|
||||
|
||||
[TestCompiler]
|
||||
public static int SliceFromStart()
|
||||
{
|
||||
ReadOnlySpan<int> span = stackalloc int[42];
|
||||
|
||||
var newSpan = span.Slice(10);
|
||||
|
||||
return newSpan[0] + newSpan.Length;
|
||||
}
|
||||
|
||||
[TestCompiler]
|
||||
public static int SliceFromStartWithLength()
|
||||
{
|
||||
ReadOnlySpan<int> span = stackalloc int[42];
|
||||
|
||||
var newSpan = span.Slice(10, 4);
|
||||
|
||||
return newSpan[3] + newSpan.Length;
|
||||
}
|
||||
|
||||
[TestCompiler]
|
||||
public static int CopyTo()
|
||||
{
|
||||
Span<int> span = stackalloc int[42];
|
||||
|
||||
for (int i = 0; i < span.Length; i++)
|
||||
{
|
||||
span[i] = i;
|
||||
}
|
||||
|
||||
ReadOnlySpan<int> other = stackalloc int[4];
|
||||
|
||||
other.CopyTo(span);
|
||||
|
||||
int result = 0;
|
||||
|
||||
for (int i = 0; i < span.Length; i++)
|
||||
{
|
||||
result += span[i];
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
[TestCompiler]
|
||||
public static int IsEmpty() => new ReadOnlySpan<int>().IsEmpty ? 1 : 0;
|
||||
|
||||
[TestCompiler]
|
||||
public static int Empty() => ReadOnlySpan<double>.Empty.Length;
|
||||
|
||||
[TestCompiler]
|
||||
public static int GetEnumerator()
|
||||
{
|
||||
ReadOnlySpan<int> span = stackalloc int[42];
|
||||
|
||||
int result = 0;
|
||||
|
||||
var enumerator = span.GetEnumerator();
|
||||
|
||||
while (enumerator.MoveNext())
|
||||
{
|
||||
result += enumerator.Current;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
[TestCompiler]
|
||||
public static int OperatorEquality() => new ReadOnlySpan<double>() == ReadOnlySpan<double>.Empty ? 1 : 0;
|
||||
|
||||
[TestCompiler]
|
||||
public static int OperatorInEquality() => new ReadOnlySpan<double>() != ReadOnlySpan<double>.Empty ? 1 : 0;
|
||||
|
||||
[TestCompiler]
|
||||
public static int Fixed()
|
||||
{
|
||||
Span<int> span = stackalloc int[42];
|
||||
|
||||
for (int i = 0; i < span.Length; i++)
|
||||
{
|
||||
span[i] = i;
|
||||
}
|
||||
|
||||
ReadOnlySpan<int> readOnlySpan = span;
|
||||
|
||||
unsafe
|
||||
{
|
||||
fixed (int* ptr = readOnlySpan)
|
||||
{
|
||||
return ptr[41];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 0bed5c1e3949386481f894d4b987c939
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,227 @@
|
|||
using System;
|
||||
using Unity.Collections.LowLevel.Unsafe;
|
||||
|
||||
namespace Burst.Compiler.IL.Tests
|
||||
{
|
||||
#if UNITY_2021_2_OR_NEWER || BURST_INTERNAL
|
||||
/// <summary>
|
||||
/// Test <see cref="System.Span{T}"/>.
|
||||
/// </summary>
|
||||
internal partial class Span
|
||||
{
|
||||
[TestCompiler]
|
||||
public static int CreateDefault()
|
||||
{
|
||||
var span = new Span<int>();
|
||||
|
||||
return span.Length;
|
||||
}
|
||||
|
||||
[TestCompiler]
|
||||
public static int CreateStackalloc()
|
||||
{
|
||||
Span<int> span = stackalloc int[42];
|
||||
|
||||
return span.Length;
|
||||
}
|
||||
|
||||
[TestCompiler(42)]
|
||||
public static int CreateFromNullPointer(int size)
|
||||
{
|
||||
Span<double> span;
|
||||
|
||||
unsafe
|
||||
{
|
||||
span = new Span<double>(null, size);
|
||||
}
|
||||
|
||||
return span.Length;
|
||||
}
|
||||
|
||||
[TestCompiler]
|
||||
public static unsafe double CreateFromMalloc()
|
||||
{
|
||||
double* malloc = (double*)UnsafeUtility.Malloc(UnsafeUtility.SizeOf<double>(), UnsafeUtility.AlignOf<double>(), Unity.Collections.Allocator.Persistent);
|
||||
*malloc = 42.0f;
|
||||
|
||||
Span<double> span = new Span<double>(malloc, 1);
|
||||
|
||||
double result = span[0];
|
||||
|
||||
UnsafeUtility.Free(malloc, Unity.Collections.Allocator.Persistent);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
[TestCompiler]
|
||||
public static int GetItem()
|
||||
{
|
||||
Span<int> span = stackalloc int[42];
|
||||
return span[41];
|
||||
}
|
||||
|
||||
[TestCompiler]
|
||||
public static int SetItem()
|
||||
{
|
||||
Span<int> span = stackalloc int[42];
|
||||
span[41] = 13;
|
||||
return span[41];
|
||||
}
|
||||
|
||||
[TestCompiler]
|
||||
public static int Clear()
|
||||
{
|
||||
Span<int> span = stackalloc int[42];
|
||||
|
||||
for (int i = 0; i < span.Length; i++)
|
||||
{
|
||||
span[i] = i;
|
||||
}
|
||||
|
||||
span.Clear();
|
||||
|
||||
int result = 0;
|
||||
|
||||
for (int i = 0; i < span.Length; i++)
|
||||
{
|
||||
result += span[i];
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
[TestCompiler]
|
||||
public static int SliceFromStart()
|
||||
{
|
||||
Span<int> span = stackalloc int[42];
|
||||
|
||||
for (int i = 0; i < span.Length; i++)
|
||||
{
|
||||
span[i] = i;
|
||||
}
|
||||
|
||||
var newSpan = span.Slice(10);
|
||||
|
||||
return newSpan[0] + newSpan.Length;
|
||||
}
|
||||
|
||||
[TestCompiler]
|
||||
public static int SliceFromStartWithLength()
|
||||
{
|
||||
Span<int> span = stackalloc int[42];
|
||||
|
||||
for (int i = 0; i < span.Length; i++)
|
||||
{
|
||||
span[i] = i;
|
||||
}
|
||||
|
||||
var newSpan = span.Slice(10, 4);
|
||||
|
||||
return newSpan[3] + newSpan.Length;
|
||||
}
|
||||
|
||||
[TestCompiler]
|
||||
public static int CopyTo()
|
||||
{
|
||||
Span<int> span = stackalloc int[42];
|
||||
|
||||
for (int i = 0; i < span.Length; i++)
|
||||
{
|
||||
span[i] = i;
|
||||
}
|
||||
|
||||
Span<int> other = stackalloc int[4];
|
||||
|
||||
for (int i = 0; i < other.Length; i++)
|
||||
{
|
||||
other[i] = -i - 1;
|
||||
}
|
||||
|
||||
other.CopyTo(span);
|
||||
|
||||
int result = 0;
|
||||
|
||||
for (int i = 0; i < span.Length; i++)
|
||||
{
|
||||
result += span[i];
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
[TestCompiler]
|
||||
public static int Fill()
|
||||
{
|
||||
Span<int> span = stackalloc int[42];
|
||||
|
||||
span.Fill(123);
|
||||
|
||||
int result = 0;
|
||||
|
||||
for (int i = 0; i < span.Length; i++)
|
||||
{
|
||||
result += span[i];
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
[TestCompiler]
|
||||
public static int IsEmpty() => new Span<int>().IsEmpty ? 1 : 0;
|
||||
|
||||
[TestCompiler]
|
||||
public static int Empty() => Span<double>.Empty.Length;
|
||||
|
||||
[TestCompiler]
|
||||
public static int GetEnumerator()
|
||||
{
|
||||
Span<int> span = stackalloc int[42];
|
||||
|
||||
int result = 0;
|
||||
|
||||
var enumerator = span.GetEnumerator();
|
||||
|
||||
while (enumerator.MoveNext())
|
||||
{
|
||||
result += enumerator.Current;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
[TestCompiler]
|
||||
public static int OperatorEquality() => new Span<double>() == Span<double>.Empty ? 1 : 0;
|
||||
|
||||
[TestCompiler]
|
||||
public static int OperatorInEquality() => new Span<double>() != Span<double>.Empty ? 1 : 0;
|
||||
|
||||
[TestCompiler]
|
||||
public static int OperatorImplicit()
|
||||
{
|
||||
ReadOnlySpan<double> span = new Span<double>();
|
||||
|
||||
return span.Length;
|
||||
}
|
||||
|
||||
[TestCompiler]
|
||||
public static int Fixed()
|
||||
{
|
||||
Span<int> span = stackalloc int[42];
|
||||
|
||||
for (int i = 0; i < span.Length; i++)
|
||||
{
|
||||
span[i] = i;
|
||||
}
|
||||
|
||||
unsafe
|
||||
{
|
||||
fixed (int* ptr = span)
|
||||
{
|
||||
*ptr = 42;
|
||||
return ptr[41];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: fec1bb67579b3feda3e2fddd7ecbc304
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,542 @@
|
|||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using Unity.Collections.LowLevel.Unsafe;
|
||||
using Unity.Burst;
|
||||
using UnityBenchShared;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
#if UNITY_2022_1_OR_NEWER
|
||||
// Enables support for { init; } keyword globally: https://docs.unity3d.com/2022.1/Documentation/Manual/CSharpCompiler.html
|
||||
namespace System.Runtime.CompilerServices
|
||||
{
|
||||
[ComponentModel.EditorBrowsable(ComponentModel.EditorBrowsableState.Never)]
|
||||
public static class IsExternalInit { }
|
||||
}
|
||||
#endif
|
||||
|
||||
namespace Burst.Compiler.IL.Tests
|
||||
{
|
||||
/// <summary>
|
||||
/// Tests types
|
||||
/// </summary>
|
||||
internal partial class Types
|
||||
{
|
||||
[TestCompiler]
|
||||
public static int Bool()
|
||||
{
|
||||
return sizeof(bool);
|
||||
}
|
||||
|
||||
[TestCompiler(true)]
|
||||
[TestCompiler(false)]
|
||||
public static bool BoolArgAndReturn(bool value)
|
||||
{
|
||||
return !value;
|
||||
}
|
||||
|
||||
private static bool BoolArgAndReturnSubFunction(bool value)
|
||||
{
|
||||
return !value;
|
||||
}
|
||||
|
||||
[TestCompiler(true)]
|
||||
[TestCompiler(false)]
|
||||
public static bool BoolArgAndReturnCall(bool value)
|
||||
{
|
||||
return BoolArgAndReturnSubFunction(value);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.NoInlining)]
|
||||
[return: MarshalAs(UnmanagedType.U1)]
|
||||
private static bool BoolMarshalAsU1(bool b) => b;
|
||||
|
||||
[TestCompiler(true)]
|
||||
[TestCompiler(false)]
|
||||
public static bool BoolMarshalAsU1Call(bool value)
|
||||
{
|
||||
return BoolMarshalAsU1(value);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.NoInlining)]
|
||||
[return: MarshalAs(UnmanagedType.I1)]
|
||||
private static bool BoolMarshalAsI1(bool b) => b;
|
||||
|
||||
[TestCompiler(true)]
|
||||
[TestCompiler(false)]
|
||||
public static bool BoolMarshalAsI1Call(bool value)
|
||||
{
|
||||
return BoolMarshalAsI1(value);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.NoInlining)]
|
||||
[return: MarshalAs(UnmanagedType.R4)]
|
||||
private static bool BoolMarshalAsR4(bool b) => b;
|
||||
|
||||
[TestCompiler(true, ExpectCompilerException = true, ExpectedDiagnosticId = DiagnosticId.ERR_MarshalAsNativeTypeOnReturnTypeNotSupported)]
|
||||
public static bool BoolMarshalAsR4Call(bool value)
|
||||
{
|
||||
return BoolMarshalAsR4(value);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.NoInlining)]
|
||||
private static bool BoolMarshalAsU1Param([MarshalAs(UnmanagedType.U1)] bool b) => b;
|
||||
|
||||
[TestCompiler(true)]
|
||||
[TestCompiler(false)]
|
||||
public static bool BoolMarshalAsU1CallParam(bool value)
|
||||
{
|
||||
return BoolMarshalAsU1Param(value);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.NoInlining)]
|
||||
private static bool BoolMarshalAsI1Param([MarshalAs(UnmanagedType.I1)] bool b) => b;
|
||||
|
||||
[TestCompiler(true)]
|
||||
[TestCompiler(false)]
|
||||
public static bool BoolMarshalAsI1CallParam(bool value)
|
||||
{
|
||||
return BoolMarshalAsI1Param(value);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.NoInlining)]
|
||||
private static bool BoolMarshalAsR4Param([MarshalAs(UnmanagedType.R4)] bool b) => b;
|
||||
|
||||
[TestCompiler(true, ExpectCompilerException = true, ExpectedDiagnosticId = DiagnosticId.ERR_MarshalAsOnParameterNotSupported)]
|
||||
public static bool BoolMarshalAsR4CallParam(bool value)
|
||||
{
|
||||
return BoolMarshalAsR4Param(value);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.NoInlining)]
|
||||
[return: MarshalAs(UnmanagedType.U1)]
|
||||
private static bool BoolMarshalAsU1AndI1Param([MarshalAs(UnmanagedType.I1)] bool b) => b;
|
||||
|
||||
[TestCompiler(true)]
|
||||
[TestCompiler(false)]
|
||||
public static bool BoolMarshalAsU1AndI1CallParam(bool value)
|
||||
{
|
||||
return BoolMarshalAsU1AndI1Param(value);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.NoInlining)]
|
||||
[return: MarshalAs(UnmanagedType.I1)]
|
||||
private static bool BoolMarshalAsI1AndU1Param([MarshalAs(UnmanagedType.U1)] bool b) => b;
|
||||
|
||||
[TestCompiler(true)]
|
||||
[TestCompiler(false)]
|
||||
public static bool BoolMarshalAsI1AndU1CallParam(bool value)
|
||||
{
|
||||
return BoolMarshalAsI1AndU1Param(value);
|
||||
}
|
||||
|
||||
[TestCompiler]
|
||||
public static int Char()
|
||||
{
|
||||
return sizeof(char);
|
||||
}
|
||||
|
||||
[TestCompiler]
|
||||
public static int Int8()
|
||||
{
|
||||
return sizeof(sbyte);
|
||||
}
|
||||
|
||||
[TestCompiler]
|
||||
public static int Int16()
|
||||
{
|
||||
return sizeof(short);
|
||||
}
|
||||
|
||||
[TestCompiler]
|
||||
public static int Int32()
|
||||
{
|
||||
return sizeof(int);
|
||||
}
|
||||
|
||||
[TestCompiler]
|
||||
public static int Int64()
|
||||
{
|
||||
return sizeof(long);
|
||||
}
|
||||
|
||||
[TestCompiler]
|
||||
public static int UInt8()
|
||||
{
|
||||
return sizeof(byte);
|
||||
}
|
||||
|
||||
[TestCompiler]
|
||||
public static int UInt16()
|
||||
{
|
||||
return sizeof(ushort);
|
||||
}
|
||||
|
||||
[TestCompiler]
|
||||
public static int UInt32()
|
||||
{
|
||||
return sizeof(uint);
|
||||
}
|
||||
|
||||
[TestCompiler]
|
||||
public static int UInt64()
|
||||
{
|
||||
return sizeof(ulong);
|
||||
}
|
||||
|
||||
[TestCompiler]
|
||||
public static int EnumSizeOf()
|
||||
{
|
||||
return sizeof(MyEnum);
|
||||
}
|
||||
|
||||
|
||||
[TestCompiler]
|
||||
public static int EnumByteSizeOf()
|
||||
{
|
||||
return sizeof(MyEnumByte);
|
||||
}
|
||||
|
||||
[TestCompiler(MyEnumByte.Tada2)]
|
||||
public static MyEnumByte CheckEnumByte(ref MyEnumByte value)
|
||||
{
|
||||
// Check stloc for enum
|
||||
value = MyEnumByte.Tada1;
|
||||
return value;
|
||||
}
|
||||
|
||||
[TestCompiler(MyEnum.Value15)]
|
||||
public static int EnumByParam(MyEnum value)
|
||||
{
|
||||
return 1 + (int)value;
|
||||
}
|
||||
|
||||
[TestCompiler]
|
||||
public static float Struct()
|
||||
{
|
||||
var value = new MyStruct(1,2,3,4);
|
||||
return value.x + value.y + value.z + value.w;
|
||||
}
|
||||
|
||||
[TestCompiler]
|
||||
public static long StructAccess()
|
||||
{
|
||||
var s = new InterleavedBoolStruct();
|
||||
s.b1 = true;
|
||||
s.i2 = -1;
|
||||
s.b3 = true;
|
||||
s.i5 = 3;
|
||||
return s.i5;
|
||||
}
|
||||
|
||||
[TestCompiler(true)]
|
||||
[TestCompiler(false)]
|
||||
public static bool StructWithBool(bool value)
|
||||
{
|
||||
// This method test that storage of boolean between local and struct is working
|
||||
// (as they could have different layout)
|
||||
var b = new BoolStruct();
|
||||
b.b1 = !value;
|
||||
return b.b1;
|
||||
}
|
||||
|
||||
[TestCompiler(ExpectCompilerException = true, ExpectedDiagnosticId = DiagnosticId.ERR_CallingManagedMethodNotSupported)]
|
||||
public static int TestUsingReferenceType()
|
||||
{
|
||||
return "this is not supported by burst".Length;
|
||||
}
|
||||
|
||||
private struct MyStruct
|
||||
{
|
||||
public MyStruct(float x, float y, float z, float w)
|
||||
{
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.z = z;
|
||||
this.w = w;
|
||||
}
|
||||
|
||||
public float x;
|
||||
public float y;
|
||||
public float z;
|
||||
public float w;
|
||||
}
|
||||
|
||||
private struct BoolStruct
|
||||
{
|
||||
#pragma warning disable 0649
|
||||
public bool b1;
|
||||
public bool b2;
|
||||
#pragma warning restore 0649
|
||||
}
|
||||
|
||||
private unsafe struct BoolFixedStruct
|
||||
{
|
||||
#pragma warning disable 0649
|
||||
public fixed bool Values[16];
|
||||
#pragma warning restore 0649
|
||||
}
|
||||
|
||||
private struct InterleavedBoolStruct
|
||||
{
|
||||
#pragma warning disable 0649
|
||||
public bool b1;
|
||||
public int i2;
|
||||
public bool b3;
|
||||
public bool b4;
|
||||
public long i5;
|
||||
public MyEnum e6;
|
||||
#pragma warning restore 0649
|
||||
}
|
||||
|
||||
public enum MyEnum
|
||||
{
|
||||
Value1 = 1,
|
||||
Value15 = 15,
|
||||
}
|
||||
|
||||
|
||||
[StructLayout(LayoutKind.Explicit)]
|
||||
private struct ExplicitLayoutStruct
|
||||
{
|
||||
[FieldOffset(0)]
|
||||
public int FieldA;
|
||||
|
||||
[FieldOffset(0)]
|
||||
public int FieldB;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Size = 1024)]
|
||||
private struct StructWithSize
|
||||
{
|
||||
public int FieldA;
|
||||
|
||||
public int FieldB;
|
||||
}
|
||||
|
||||
private struct EmptyStruct
|
||||
{
|
||||
}
|
||||
|
||||
public enum MyEnumByte : byte
|
||||
{
|
||||
Tada1 = 1,
|
||||
|
||||
Tada2 = 2
|
||||
}
|
||||
|
||||
private static ValueTuple<int> ReturnValueTuple1() => ValueTuple.Create(42);
|
||||
|
||||
[TestCompiler]
|
||||
public static long TestValueTuple1Return()
|
||||
{
|
||||
var tuple = ReturnValueTuple1();
|
||||
|
||||
return tuple.Item1;
|
||||
}
|
||||
|
||||
private static (int, uint) ReturnValueTuple2() => (42, 13);
|
||||
|
||||
[TestCompiler]
|
||||
public static long TestValueTuple2Return()
|
||||
{
|
||||
var tuple = ReturnValueTuple2();
|
||||
|
||||
return tuple.Item1 + tuple.Item2;
|
||||
}
|
||||
|
||||
private static (int, uint, byte) ReturnValueTuple3() => (42, 13, 13);
|
||||
|
||||
[TestCompiler]
|
||||
public static long TestValueTuple3Return()
|
||||
{
|
||||
var tuple = ReturnValueTuple3();
|
||||
|
||||
return tuple.Item1 + tuple.Item2 + tuple.Item3;
|
||||
}
|
||||
|
||||
private static (int, uint, byte, sbyte) ReturnValueTuple4() => (42, 13, 13, -13);
|
||||
|
||||
[TestCompiler]
|
||||
public static long TestValueTuple4Return()
|
||||
{
|
||||
var tuple = ReturnValueTuple4();
|
||||
|
||||
return tuple.Item1 + tuple.Item2 + tuple.Item3 + tuple.Item4;
|
||||
}
|
||||
|
||||
private static (int, uint, byte, sbyte, long) ReturnValueTuple5() => (42, 13, 13, -13, 53);
|
||||
|
||||
[TestCompiler]
|
||||
public static long TestValueTuple5Return()
|
||||
{
|
||||
var tuple = ReturnValueTuple5();
|
||||
|
||||
return tuple.Item1 + tuple.Item2 + tuple.Item3 + tuple.Item4 + tuple.Item5;
|
||||
}
|
||||
|
||||
private struct SomeStruct
|
||||
{
|
||||
public int X;
|
||||
}
|
||||
|
||||
private static (int, uint, byte, sbyte, long, SomeStruct) ReturnValueTuple6() => (42, 13, 13, -13, 535353, new SomeStruct { X = 42 } );
|
||||
|
||||
[TestCompiler]
|
||||
public static long TestValueTuple6Return()
|
||||
{
|
||||
var tuple = ReturnValueTuple6();
|
||||
|
||||
return tuple.Item1 + tuple.Item2 + tuple.Item3 + tuple.Item4 + tuple.Item5 + tuple.Item6.X;
|
||||
}
|
||||
|
||||
private static (int, uint, byte, sbyte, long, SomeStruct, short) ReturnValueTuple7() => (42, 13, 13, -13, 535353, new SomeStruct { X = 42 }, 400);
|
||||
|
||||
[TestCompiler]
|
||||
public static long TestValueTuple7Return()
|
||||
{
|
||||
var tuple = ReturnValueTuple7();
|
||||
|
||||
return tuple.Item1 + tuple.Item2 + tuple.Item3 + tuple.Item4 + tuple.Item5 + tuple.Item6.X + tuple.Item7;
|
||||
}
|
||||
|
||||
private static (int, uint, byte, sbyte, long, SomeStruct, short, int) ReturnValueTuple8() => (42, 13, 13, -13, 535353, new SomeStruct { X = 42 }, 400, -400);
|
||||
|
||||
[TestCompiler]
|
||||
public static long TestValueTuple8Return()
|
||||
{
|
||||
var tuple = ReturnValueTuple8();
|
||||
|
||||
return tuple.Item1 + tuple.Item2 + tuple.Item3 + tuple.Item4 + tuple.Item5 + tuple.Item6.X + tuple.Item7 + tuple.Item8;
|
||||
}
|
||||
|
||||
private static (int, uint, byte, sbyte, long, SomeStruct, short, int, long) ReturnValueTuple9() => (42, 13, 13, -13, 535353, new SomeStruct { X = 42 }, 400, -400, 48);
|
||||
|
||||
[TestCompiler]
|
||||
public static long TestValueTuple9Return()
|
||||
{
|
||||
var tuple = ReturnValueTuple9();
|
||||
|
||||
return tuple.Item1 + tuple.Item2 + tuple.Item3 + tuple.Item4 + tuple.Item5 + tuple.Item6.X + tuple.Item7 + tuple.Item8 + tuple.Item9;
|
||||
}
|
||||
|
||||
private static long ValueTuple1Arg(ValueTuple<int> tuple)
|
||||
{
|
||||
return tuple.Item1;
|
||||
}
|
||||
|
||||
[TestCompiler]
|
||||
public static long TestValueTuple1Arg()
|
||||
{
|
||||
return ValueTuple1Arg(ValueTuple.Create(42));
|
||||
}
|
||||
|
||||
private static long ValueTuple2Arg((int, uint) tuple)
|
||||
{
|
||||
return tuple.Item1 + tuple.Item2;
|
||||
}
|
||||
|
||||
[TestCompiler]
|
||||
public static long TestValueTuple2Arg()
|
||||
{
|
||||
return ValueTuple2Arg((42, 13));
|
||||
}
|
||||
|
||||
private static long ValueTuple3Arg((int, uint, byte) tuple)
|
||||
{
|
||||
return tuple.Item1 + tuple.Item2 + tuple.Item3;
|
||||
}
|
||||
|
||||
[TestCompiler]
|
||||
public static long TestValueTuple3Arg()
|
||||
{
|
||||
return ValueTuple3Arg((42, 13, 13));
|
||||
}
|
||||
|
||||
private static long ValueTuple4Arg((int, uint, byte, sbyte) tuple)
|
||||
{
|
||||
return tuple.Item1 + tuple.Item2 + tuple.Item3 + tuple.Item4;
|
||||
}
|
||||
|
||||
[TestCompiler]
|
||||
public static long TestValueTuple4Arg()
|
||||
{
|
||||
return ValueTuple4Arg((42, 13, 13, -13));
|
||||
}
|
||||
|
||||
private static long ValueTuple5Arg((int, uint, byte, sbyte, long) tuple)
|
||||
{
|
||||
return tuple.Item1 + tuple.Item2 + tuple.Item3 + tuple.Item4 + tuple.Item5;
|
||||
}
|
||||
|
||||
[TestCompiler]
|
||||
public static long TestValueTuple5Arg()
|
||||
{
|
||||
return ValueTuple5Arg((42, 13, 13, -13, 535353));
|
||||
}
|
||||
|
||||
private static long ValueTuple6Arg((int, uint, byte, sbyte, long, SomeStruct) tuple)
|
||||
{
|
||||
return tuple.Item1 + tuple.Item2 + tuple.Item3 + tuple.Item4 + tuple.Item5 + tuple.Item6.X;
|
||||
}
|
||||
|
||||
[TestCompiler]
|
||||
public static long TestValueTuple6Arg()
|
||||
{
|
||||
return ValueTuple6Arg((42, 13, 13, -13, 535353, new SomeStruct { X = 42 }));
|
||||
}
|
||||
|
||||
private static long ValueTuple7Arg((int, uint, byte, sbyte, long, SomeStruct, short) tuple)
|
||||
{
|
||||
return tuple.Item1 + tuple.Item2 + tuple.Item3 + tuple.Item4 + tuple.Item5 + tuple.Item6.X + tuple.Item7;
|
||||
}
|
||||
|
||||
[TestCompiler]
|
||||
public static long TestValueTuple7Arg()
|
||||
{
|
||||
return ValueTuple7Arg((42, 13, 13, -13, 535353, new SomeStruct { X = 42 }, 400));
|
||||
}
|
||||
|
||||
private static long ValueTuple8Arg((int, uint, byte, sbyte, long, SomeStruct, short, int) tuple)
|
||||
{
|
||||
return tuple.Item1 + tuple.Item2 + tuple.Item3 + tuple.Item4 + tuple.Item5 + tuple.Item6.X + tuple.Item7 + tuple.Item8;
|
||||
}
|
||||
|
||||
[TestCompiler]
|
||||
public static long TestValueTuple8Arg()
|
||||
{
|
||||
return ValueTuple8Arg((42, 13, 13, -13, 535353, new SomeStruct { X = 42 }, 400, -400));
|
||||
}
|
||||
|
||||
private static long ValueTuple9Arg((int, uint, byte, sbyte, long, SomeStruct, short, int, long) tuple)
|
||||
{
|
||||
return tuple.Item1 + tuple.Item2 + tuple.Item3 + tuple.Item4 + tuple.Item5 + tuple.Item6.X + tuple.Item7 + tuple.Item8 + tuple.Item9;
|
||||
}
|
||||
|
||||
[TestCompiler]
|
||||
public static long TestValueTuple9Arg()
|
||||
{
|
||||
return ValueTuple9Arg((42, 13, 13, -13, 535353, new SomeStruct { X = 42 }, 400, -400, 48));
|
||||
}
|
||||
|
||||
// This needs to be here because the static delegate registry refers to it.
|
||||
public struct SomeStructWithValueTuple
|
||||
{
|
||||
public ValueTuple<int, float> X;
|
||||
|
||||
public struct Provider : IArgumentProvider
|
||||
{
|
||||
public object Value => new SomeStructWithValueTuple { X = (42, 42.0f) };
|
||||
}
|
||||
}
|
||||
|
||||
#if UNITY_2022_1_OR_NEWER
|
||||
public readonly struct InitOnly
|
||||
{
|
||||
public readonly float Value { get; init; }
|
||||
}
|
||||
|
||||
[TestCompiler]
|
||||
public static float TestInitOnly() => new InitOnly { Value = default }.Value;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: a0499a50a9b63d9a90fc428e1f5c89e9
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
File diff suppressed because it is too large
Load diff
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 953d1f4d7d69334fbc9657d7d82a855b
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,928 @@
|
|||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using Unity.Burst;
|
||||
using Unity.Collections;
|
||||
using Unity.Collections.LowLevel.Unsafe;
|
||||
using Unity.Jobs;
|
||||
using Unity.Mathematics;
|
||||
using UnityBenchShared;
|
||||
|
||||
namespace Burst.Compiler.IL.Tests
|
||||
{
|
||||
internal class Pointers
|
||||
{
|
||||
[TestCompiler(1)]
|
||||
[TestCompiler(4)]
|
||||
[TestCompiler(5)]
|
||||
public static int CheckAddressOf(int a)
|
||||
{
|
||||
var value = new MyIntValue(a);
|
||||
ref int intValue = ref value.GetValuePtr();
|
||||
return intValue * 10 + 1;
|
||||
}
|
||||
|
||||
public struct MyIntValue
|
||||
{
|
||||
public MyIntValue(int value)
|
||||
{
|
||||
Value = value;
|
||||
}
|
||||
|
||||
public int Value;
|
||||
|
||||
public unsafe ref int GetValuePtr()
|
||||
{
|
||||
fixed (void* ptr = &this)
|
||||
{
|
||||
return ref *(int*) ptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[TestCompiler(0, MyCastEnum.Value2)]
|
||||
[TestCompiler(1, MyCastEnum.Value0)]
|
||||
[TestCompiler(2, MyCastEnum.Value3)]
|
||||
public static unsafe MyCastEnum PointerCastEnum(int value, MyCastEnum newValue)
|
||||
{
|
||||
var ptvalue = new IntPtr(&value);
|
||||
var pEnum = (MyCastEnum*) ptvalue;
|
||||
*pEnum = newValue;
|
||||
return *pEnum;
|
||||
}
|
||||
|
||||
[TestCompiler(0, 0)]
|
||||
[TestCompiler(0, 1)]
|
||||
[TestCompiler(1, 0)]
|
||||
public static unsafe bool PointerCompare(IntPtr a, IntPtr b)
|
||||
{
|
||||
return a == b;
|
||||
}
|
||||
|
||||
[TestCompiler(0)]
|
||||
[TestCompiler(1)]
|
||||
[TestCompiler(2)]
|
||||
public static unsafe bool RawPointerCompare(IntPtr value)
|
||||
{
|
||||
return (void*)value == (void*)1;
|
||||
}
|
||||
|
||||
[TestCompiler(0)]
|
||||
[TestCompiler(1)]
|
||||
[TestCompiler(42424242)]
|
||||
public static unsafe int PointerHash(IntPtr value)
|
||||
{
|
||||
return value.GetHashCode();
|
||||
}
|
||||
|
||||
[TestCompiler(0)]
|
||||
[TestCompiler(1)]
|
||||
[TestCompiler(42424242)]
|
||||
public static unsafe IntPtr PointerToPointer(IntPtr value)
|
||||
{
|
||||
return new IntPtr(value.ToPointer());
|
||||
}
|
||||
|
||||
[TestCompiler(0, ExpectCompilerException = true, ExpectedDiagnosticId = DiagnosticId.ERR_MethodNotSupported)]
|
||||
public static unsafe int PointerToString(IntPtr value)
|
||||
{
|
||||
return value.ToString().Length;
|
||||
}
|
||||
|
||||
[TestCompiler(1)]
|
||||
[TestCompiler(255)]
|
||||
[TestCompiler(12351235)]
|
||||
public static unsafe int PointerAdd(int a)
|
||||
{
|
||||
var pA = (byte*)&a;
|
||||
var pDest = pA + 3;
|
||||
*pDest = (byte)a;
|
||||
return a;
|
||||
}
|
||||
|
||||
[TestCompiler(1)]
|
||||
[TestCompiler(255)]
|
||||
[TestCompiler(12351235)]
|
||||
public static unsafe int PointerSub(int a)
|
||||
{
|
||||
var pA = (byte*)&a;
|
||||
var pDest = pA + 3;
|
||||
*(pDest - 1) = (byte)a;
|
||||
return a;
|
||||
}
|
||||
|
||||
[TestCompiler]
|
||||
public static unsafe int PointerPointerSub()
|
||||
{
|
||||
var value = new StructForPointerPointerSub();
|
||||
int* pa = &value.A;
|
||||
int* pb = &value.B;
|
||||
var auto = (pb - pa);
|
||||
return (int)auto;
|
||||
}
|
||||
|
||||
[TestCompiler]
|
||||
public static unsafe int WhileWithPointer()
|
||||
{
|
||||
var check = new CheckPointers { X = 1, Y = 2, Z = 3, W = 4 };
|
||||
int* pstart = &check.X;
|
||||
int* pend = &check.W;
|
||||
int result = 0;
|
||||
while (pstart <= pend)
|
||||
{
|
||||
result += *pstart;
|
||||
pstart++;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
struct StructForPointerPointerSub
|
||||
{
|
||||
public int A;
|
||||
public int B;
|
||||
}
|
||||
|
||||
|
||||
|
||||
[TestCompiler(1)]
|
||||
[TestCompiler(255)]
|
||||
[TestCompiler(12351235)]
|
||||
public static IntPtr IntPtrConstructor(int a)
|
||||
{
|
||||
return new IntPtr(a);
|
||||
}
|
||||
|
||||
[TestCompiler(1U)]
|
||||
[TestCompiler(255U)]
|
||||
[TestCompiler(12351235U)]
|
||||
public static UIntPtr UIntPtrConstructor(uint a)
|
||||
{
|
||||
return new UIntPtr(a);
|
||||
}
|
||||
|
||||
[TestCompiler(1)]
|
||||
[TestCompiler(255)]
|
||||
[TestCompiler(12351235)]
|
||||
public static int IntPtrToInt32(int a)
|
||||
{
|
||||
return new IntPtr(a).ToInt32();
|
||||
}
|
||||
|
||||
[TestCompiler(1)]
|
||||
[TestCompiler(255)]
|
||||
[TestCompiler(12351235)]
|
||||
public static long IntPtrToInt64(int a)
|
||||
{
|
||||
return new IntPtr(a).ToInt64();
|
||||
}
|
||||
|
||||
[TestCompiler(OverrideOn32BitNative = 4)]
|
||||
public static int IntPtrSize()
|
||||
{
|
||||
return IntPtr.Size;
|
||||
}
|
||||
|
||||
// asserted in IntPtrProcessor
|
||||
[TestCompiler(OverrideOn32BitNative = true)]
|
||||
public static bool IntPtrSizeCompared()
|
||||
{
|
||||
return IntPtr.Size == 4;
|
||||
}
|
||||
|
||||
[TestCompiler]
|
||||
public static IntPtr IntPtrZero()
|
||||
{
|
||||
return IntPtr.Zero;
|
||||
}
|
||||
|
||||
[TestCompiler(1)]
|
||||
[TestCompiler(5)]
|
||||
public static IntPtr IntPtrAdd(IntPtr a)
|
||||
{
|
||||
return IntPtr.Add(a, 1);
|
||||
}
|
||||
|
||||
|
||||
[TestCompiler(1)]
|
||||
[TestCompiler(5)]
|
||||
public static IntPtr IntPtrAdd2(IntPtr a)
|
||||
{
|
||||
return a + 1;
|
||||
}
|
||||
|
||||
[TestCompiler(1)]
|
||||
[TestCompiler(5)]
|
||||
public static IntPtr IntPtrSub(IntPtr a)
|
||||
{
|
||||
return IntPtr.Subtract(a, 1);
|
||||
}
|
||||
|
||||
|
||||
[TestCompiler(1)]
|
||||
[TestCompiler(5)]
|
||||
public static IntPtr IntPtrSub2(IntPtr a)
|
||||
{
|
||||
return a - 1;
|
||||
}
|
||||
|
||||
[TestCompiler]
|
||||
public static UIntPtr UIntPtrZero()
|
||||
{
|
||||
return UIntPtr.Zero;
|
||||
}
|
||||
|
||||
[TestCompiler(1U)]
|
||||
[TestCompiler(5U)]
|
||||
public static UIntPtr UIntPtrAdd(UIntPtr a)
|
||||
{
|
||||
return UIntPtr.Add(a, 1);
|
||||
}
|
||||
|
||||
[TestCompiler(1U)]
|
||||
[TestCompiler(5U)]
|
||||
public static UIntPtr UIntPtrSubstract(UIntPtr a)
|
||||
{
|
||||
return UIntPtr.Subtract(a, 1);
|
||||
}
|
||||
|
||||
[TestCompiler(1)]
|
||||
public static unsafe int PointerAccess(int a)
|
||||
{
|
||||
var value = a;
|
||||
var pValue = &value;
|
||||
pValue[0] = a + 5;
|
||||
return value;
|
||||
}
|
||||
|
||||
[TestCompiler(0)] // Keep it at 0 only!
|
||||
public static unsafe int PointerAccess2(int a)
|
||||
{
|
||||
int value = 15;
|
||||
var pValue = &value;
|
||||
pValue[a] = value + 5;
|
||||
return value;
|
||||
}
|
||||
|
||||
[TestCompiler(0)] // Keep it at 0 only!
|
||||
public static unsafe float PointerAccess3(int a)
|
||||
{
|
||||
float value = 15.0f;
|
||||
var pValue = &value;
|
||||
pValue[a] = value + 5.0f;
|
||||
return value;
|
||||
}
|
||||
|
||||
[TestCompiler(0)]
|
||||
public static unsafe int PointerCompareViaInt(int a)
|
||||
{
|
||||
int b;
|
||||
if (&a == &b)
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
[TestCompiler(0)]
|
||||
public static unsafe int IntPtrCompare(int a)
|
||||
{
|
||||
int b;
|
||||
IntPtr aPtr = (IntPtr)(&a);
|
||||
IntPtr bPtr = (IntPtr)(&b);
|
||||
if (aPtr == bPtr)
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
[TestCompiler(typeof(IntPtrZeroProvider), 1)]
|
||||
[TestCompiler(typeof(IntPtrOneProvider), 2)]
|
||||
public static unsafe int UnsafeCompare(int* a, int b)
|
||||
{
|
||||
if (a == null)
|
||||
{
|
||||
return 1 + b;
|
||||
}
|
||||
|
||||
return 2 + b;
|
||||
}
|
||||
|
||||
unsafe struct NativeQueueBlockHeader
|
||||
{
|
||||
#pragma warning disable 0649
|
||||
public byte* nextBlock;
|
||||
public int itemsInBlock;
|
||||
#pragma warning restore 0649
|
||||
}
|
||||
|
||||
[TestCompiler]
|
||||
public static unsafe void PointerCastWithStruct()
|
||||
{
|
||||
|
||||
byte* currentWriteBlock = null;
|
||||
if (currentWriteBlock != null && ((NativeQueueBlockHeader*) currentWriteBlock)->itemsInBlock == 100)
|
||||
{
|
||||
((NativeQueueBlockHeader*) currentWriteBlock)->itemsInBlock = 5;
|
||||
}
|
||||
}
|
||||
|
||||
private class IntPtrZeroProvider : IArgumentProvider
|
||||
{
|
||||
public object Value => IntPtr.Zero;
|
||||
}
|
||||
|
||||
private class IntPtrOneProvider : IArgumentProvider
|
||||
{
|
||||
public object Value => new IntPtr(1);
|
||||
}
|
||||
|
||||
[TestCompiler]
|
||||
public static unsafe int FixedField()
|
||||
{
|
||||
var fixedStruct = new MyStructWithFixed();
|
||||
fixedStruct.Values[0] = 1;
|
||||
fixedStruct.Values[1] = 2;
|
||||
fixedStruct.Values[2] = 3;
|
||||
fixedStruct.Values[9] = 9;
|
||||
|
||||
int result = 0;
|
||||
for (int i = 0; i < 10; i++)
|
||||
{
|
||||
result += fixedStruct.Values[i];
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
[TestCompiler(typeof(MyStructWithFixedProvider), 1)]
|
||||
//[TestCompiler(typeof(MyStructWithFixedProvider), 2)]
|
||||
public static unsafe int FixedFieldViaPointer(ref MyStructWithFixed fixedStruct, int i)
|
||||
{
|
||||
fixed (MyStructWithFixed* check = &fixedStruct)
|
||||
{
|
||||
int* data = check->Values;
|
||||
return data[i];
|
||||
}
|
||||
}
|
||||
|
||||
[TestCompiler(typeof(MyStructWithFixedProvider))]
|
||||
public static unsafe int FixedInt32AndRefInt32(ref MyStructWithFixed fixedStruct)
|
||||
{
|
||||
fixed (int* data = &fixedStruct.Value)
|
||||
{
|
||||
// We do a call to ProcessInt after with a ref int
|
||||
// to check that we don't collide with the PinnedType introduced by the previous
|
||||
// fixed statement
|
||||
ProcessInt(ref *data);
|
||||
}
|
||||
|
||||
return fixedStruct.Value;
|
||||
}
|
||||
|
||||
private static void ProcessInt(ref int value)
|
||||
{
|
||||
value += 5;
|
||||
}
|
||||
|
||||
public unsafe struct ConditionalTestStruct
|
||||
{
|
||||
public void* a;
|
||||
public void* b;
|
||||
}
|
||||
|
||||
public unsafe struct PointerConditional : IJob, IDisposable
|
||||
{
|
||||
public ConditionalTestStruct* t;
|
||||
|
||||
public void Execute()
|
||||
{
|
||||
t->b = t->a != null ? t->a : null;
|
||||
}
|
||||
|
||||
|
||||
public struct Provider : IArgumentProvider
|
||||
{
|
||||
public object Value
|
||||
{
|
||||
get
|
||||
{
|
||||
var value = new PointerConditional();
|
||||
value.t = (ConditionalTestStruct*)UnsafeUtility.Malloc(UnsafeUtility.SizeOf<ConditionalTestStruct>(), 4, Allocator.Persistent);
|
||||
value.t->a = (void*)0x12345678;
|
||||
value.t->b = null;
|
||||
return value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
UnsafeUtility.Free(t, Allocator.Persistent);
|
||||
}
|
||||
}
|
||||
|
||||
[TestCompiler(typeof(PointerConditional.Provider))]
|
||||
public static unsafe bool TestConditionalPointer([NoAlias] ref PointerConditional job)
|
||||
{
|
||||
job.Execute();
|
||||
return job.t->a == job.t->b;
|
||||
}
|
||||
|
||||
#if BURST_TESTS_ONLY
|
||||
[TestCompiler]
|
||||
public static int TestFieldOffset()
|
||||
{
|
||||
var t = default(StructWithFields);
|
||||
return (int)Unsafe.ByteOffset(ref Unsafe.As<int, bool>(ref t.a), ref t.d);
|
||||
}
|
||||
#endif
|
||||
|
||||
public struct StructWithFields
|
||||
{
|
||||
public int a;
|
||||
public int b;
|
||||
public bool c;
|
||||
public bool d;
|
||||
public bool e;
|
||||
public bool f;
|
||||
}
|
||||
|
||||
public unsafe struct MyStructWithFixed
|
||||
{
|
||||
public fixed int Values[10];
|
||||
public int Value;
|
||||
}
|
||||
|
||||
private struct MyStructWithFixedProvider : IArgumentProvider
|
||||
{
|
||||
public unsafe object Value
|
||||
{
|
||||
get
|
||||
{
|
||||
var field = new MyStructWithFixed();
|
||||
for (int i = 0; i < 10; i++)
|
||||
{
|
||||
field.Values[i] = (i + 1) * 5;
|
||||
}
|
||||
|
||||
field.Value = 1235;
|
||||
|
||||
return field;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[TestCompiler(0)]
|
||||
public static unsafe void TestCellVisibleInternal(int length)
|
||||
{
|
||||
int3* cellVisibleRequest = (int3*)0;
|
||||
bool*cellVisibleResult = (bool*)0;
|
||||
int3* visibleCells = (int3*)0;
|
||||
IsCellVisibleInternal(cellVisibleRequest, cellVisibleResult, visibleCells, length, length);
|
||||
}
|
||||
|
||||
static unsafe void IsCellVisibleInternal(int3* cellVisibleRequest, bool* cellVisibleResult, int3* visibleCells, int requestLength, int visibleCellsLength)
|
||||
{
|
||||
for (int r = 0; r < requestLength; r++)
|
||||
{
|
||||
cellVisibleResult[r] = false;
|
||||
for (int i = 0; i < visibleCellsLength; i++)
|
||||
{
|
||||
if (visibleCells[i].x == cellVisibleRequest[r].x && visibleCells[i].y == cellVisibleRequest[r].y && visibleCells[i].z == cellVisibleRequest[r].z)
|
||||
{
|
||||
cellVisibleResult[r] = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public enum MyCastEnum
|
||||
{
|
||||
Value0 = 0,
|
||||
Value1 = 1,
|
||||
Value2 = 2,
|
||||
Value3 = 3,
|
||||
}
|
||||
|
||||
public struct CheckPointers
|
||||
{
|
||||
public int X;
|
||||
public int Y;
|
||||
public int Z;
|
||||
public int W;
|
||||
}
|
||||
|
||||
// From https://github.com/Unity-Technologies/ECSJobDemos/issues/244
|
||||
[TestCompiler]
|
||||
public static unsafe int InitialiseViaCastedPointer()
|
||||
{
|
||||
int value = 0;
|
||||
|
||||
void* ptr = &value;
|
||||
|
||||
byte* asBytePtr = (byte*)ptr;
|
||||
|
||||
((int*)asBytePtr)[0] = -1;
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
[TestCompiler(1)]
|
||||
public static unsafe int PointerWriteArg(int a)
|
||||
{
|
||||
return (int)TestPointerAndGeneric<float>((int*) a);
|
||||
}
|
||||
|
||||
private static unsafe int* TestPointerAndGeneric<T>(int* p) where T : struct
|
||||
{
|
||||
p = (int*)(IntPtr)26;
|
||||
return p;
|
||||
}
|
||||
|
||||
|
||||
[TestCompiler(ExpectedDiagnosticId = DiagnosticId.WRN_ExceptionThrownInNonSafetyCheckGuardedFunction)]
|
||||
public static void TestBlobAssetReferenceData()
|
||||
{
|
||||
var blob = new BlobAssetReferenceData(IntPtr.Zero);
|
||||
blob.Validate();
|
||||
}
|
||||
|
||||
|
||||
[StructLayout(LayoutKind.Explicit, Size = 16)]
|
||||
internal unsafe struct BlobAssetHeader
|
||||
{
|
||||
[FieldOffset(0)] public void* ValidationPtr;
|
||||
[FieldOffset(8)] public int Length;
|
||||
[FieldOffset(12)] public Allocator Allocator;
|
||||
}
|
||||
|
||||
internal unsafe struct BlobAssetReferenceData
|
||||
{
|
||||
[NativeDisableUnsafePtrRestriction]
|
||||
public byte* _ptr;
|
||||
|
||||
public BlobAssetReferenceData(IntPtr zero)
|
||||
{
|
||||
_ptr = (byte*)zero;
|
||||
}
|
||||
|
||||
internal BlobAssetHeader* Header => ((BlobAssetHeader*)_ptr) - 1;
|
||||
|
||||
public void Validate()
|
||||
{
|
||||
if (_ptr != null)
|
||||
if (Header->ValidationPtr != _ptr)
|
||||
throw new InvalidOperationException("The BlobAssetReference is not valid. Likely it has already been unloaded or released");
|
||||
}
|
||||
}
|
||||
|
||||
internal unsafe struct StackAllocCheck
|
||||
{
|
||||
public int* ptr;
|
||||
|
||||
[MethodImpl(MethodImplOptions.NoInlining)]
|
||||
public void AddToPtr(int* otherPtr)
|
||||
{
|
||||
*otherPtr = 42;
|
||||
*ptr += 1;
|
||||
*ptr += *otherPtr;
|
||||
}
|
||||
|
||||
public class Provider : IArgumentProvider
|
||||
{
|
||||
public object Value => new StackAllocCheck();
|
||||
}
|
||||
}
|
||||
|
||||
[TestCompiler(typeof(StackAllocCheck.Provider))]
|
||||
public static unsafe bool StackAllocAliasCheck([NoAlias] ref StackAllocCheck stackAllocCheck)
|
||||
{
|
||||
int* ptr = stackalloc int[1];
|
||||
*ptr = 13;
|
||||
|
||||
stackAllocCheck.ptr = ptr;
|
||||
|
||||
stackAllocCheck.AddToPtr(ptr);
|
||||
|
||||
if (*ptr != 86)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
*stackAllocCheck.ptr = -4;
|
||||
*ptr += 1;
|
||||
*ptr += *stackAllocCheck.ptr;
|
||||
|
||||
if (*ptr != -6)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
[TestCompiler(1)]
|
||||
public static unsafe int NativeIntAddCheck(int a)
|
||||
{
|
||||
return (int)(&a + 1) - (int)&a;
|
||||
}
|
||||
|
||||
public unsafe struct PointerArithmetic : IJob, IDisposable
|
||||
{
|
||||
[NativeDisableUnsafePtrRestriction] public int** pointers;
|
||||
|
||||
public void Execute()
|
||||
{
|
||||
pointers[10] = pointers[10] + +1;
|
||||
pointers[20] = pointers[20] - +1;
|
||||
pointers[30] = pointers[30] - -1;
|
||||
pointers[40] = pointers[40] + -1;
|
||||
}
|
||||
|
||||
public struct Provider : IArgumentProvider
|
||||
{
|
||||
public object Value
|
||||
{
|
||||
get
|
||||
{
|
||||
var value = new PointerArithmetic();
|
||||
value.pointers = (int**)UnsafeUtility.Malloc(1000*sizeof(int*), 8, Allocator.Persistent);
|
||||
UnsafeUtility.MemClear(value.pointers, 1000 * sizeof(int*));
|
||||
return value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
UnsafeUtility.Free(pointers, Allocator.Persistent);
|
||||
}
|
||||
}
|
||||
|
||||
// The arithmetic test has been split to make it easier to see the mismatched value (rather than true!=false)
|
||||
// According to : https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/language-specification/unsafe-code#pointer-types
|
||||
// Conversion between pointers and integrals is "Implementation Defined".
|
||||
|
||||
|
||||
[TestCompiler(typeof(PointerArithmetic.Provider))]
|
||||
public static unsafe Int64 TestArithmeticPointerA(ref PointerArithmetic job)
|
||||
{
|
||||
job.Execute();
|
||||
if (sizeof(int*) == 4)
|
||||
return (Int64)(UInt32)(job.pointers[10]); // Workaround IL2CPP 32bit Bug : https://fogbugz.unity3d.com/f/cases/1254635/
|
||||
return (Int64)job.pointers[10];
|
||||
}
|
||||
|
||||
[TestCompiler(typeof(PointerArithmetic.Provider))]
|
||||
public static unsafe Int64 TestArithmeticPointerB(ref PointerArithmetic job)
|
||||
{
|
||||
job.Execute();
|
||||
if (sizeof(int*) == 4)
|
||||
return (Int64)(UInt32)(job.pointers[20]); // Workaround IL2CPP 32bit Bug : https://fogbugz.unity3d.com/f/cases/1254635/
|
||||
return (Int64)job.pointers[20];
|
||||
}
|
||||
|
||||
[TestCompiler(typeof(PointerArithmetic.Provider))]
|
||||
public static unsafe Int64 TestArithmeticPointerC(ref PointerArithmetic job)
|
||||
{
|
||||
job.Execute();
|
||||
if (sizeof(int*) == 4)
|
||||
return (Int64)(UInt32)(job.pointers[30]); // Workaround IL2CPP 32bit Bug : https://fogbugz.unity3d.com/f/cases/1254635/
|
||||
return (Int64)job.pointers[30];
|
||||
}
|
||||
|
||||
[TestCompiler(typeof(PointerArithmetic.Provider))]
|
||||
public static unsafe Int64 TestArithmeticPointerD(ref PointerArithmetic job)
|
||||
{
|
||||
job.Execute();
|
||||
if (sizeof(int*) == 4)
|
||||
return (Int64)(UInt32)(job.pointers[40]); // Workaround IL2CPP 32bit Bug : https://fogbugz.unity3d.com/f/cases/1254635/
|
||||
return (Int64)job.pointers[40];
|
||||
}
|
||||
|
||||
private struct TestData
|
||||
{
|
||||
public int3 Min;
|
||||
public int Size;
|
||||
}
|
||||
|
||||
[TestCompiler]
|
||||
public static unsafe int TestPointerWithIn()
|
||||
{
|
||||
var foo = stackalloc TestData[1];
|
||||
|
||||
*foo = new TestData { Min = new int3(0, 1, 2), Size = 3 };
|
||||
|
||||
return SubFunctionWithInPointer(in foo);
|
||||
}
|
||||
|
||||
private static unsafe int SubFunctionWithInPointer(in TestData* node)
|
||||
{
|
||||
int3 data = node->Min;
|
||||
|
||||
return node->Size + data.x + data.y + data.z;
|
||||
}
|
||||
|
||||
[TestCompiler]
|
||||
public static unsafe int TestSystemBufferMemoryCopy()
|
||||
{
|
||||
var a = stackalloc int[2];
|
||||
a[0] = 42;
|
||||
System.Buffer.MemoryCopy(a + 0, a + 1, UnsafeUtility.SizeOf<int>(), UnsafeUtility.SizeOf<int>());
|
||||
return a[1];
|
||||
}
|
||||
|
||||
[TestCompiler(0ul, byte.MinValue)]
|
||||
[TestCompiler(0ul, byte.MaxValue)]
|
||||
public static unsafe IntPtr PointerMathAddPNTypesByte(UInt64 p,byte a)
|
||||
{
|
||||
var pointer = (byte*)p;
|
||||
return new IntPtr(pointer + a); // Pointer LHS
|
||||
}
|
||||
|
||||
[TestCompiler(0ul, byte.MinValue)]
|
||||
[TestCompiler(0ul, byte.MaxValue)]
|
||||
public static unsafe IntPtr PointerMathAddNPTypesByte(UInt64 p,byte a)
|
||||
{
|
||||
var pointer = (byte*)p;
|
||||
return new IntPtr(a + pointer); // Pointer RHS
|
||||
}
|
||||
|
||||
[TestCompiler(0ul, byte.MinValue)]
|
||||
[TestCompiler(0ul, byte.MaxValue)]
|
||||
public static unsafe IntPtr PointerMathSubPNTypesByte(UInt64 p,byte a)
|
||||
{
|
||||
var pointer = (byte*)p;
|
||||
return new IntPtr(pointer - a); // Pointer LHS (no RHS since not legal in C#)
|
||||
}
|
||||
|
||||
[TestCompiler(0ul, sbyte.MinValue)]
|
||||
[TestCompiler(0ul, sbyte.MaxValue)]
|
||||
public static unsafe IntPtr PointerMathAddPNTypesSByte(UInt64 p,sbyte a)
|
||||
{
|
||||
var pointer = (sbyte*)p;
|
||||
return new IntPtr(pointer + a); // Pointer LHS
|
||||
}
|
||||
|
||||
[TestCompiler(0ul, sbyte.MinValue)]
|
||||
[TestCompiler(0ul, sbyte.MaxValue)]
|
||||
public static unsafe IntPtr PointerMathAddNPTypesSByte(UInt64 p,sbyte a)
|
||||
{
|
||||
var pointer = (sbyte*)p;
|
||||
return new IntPtr(a + pointer); // Pointer RHS
|
||||
}
|
||||
|
||||
[TestCompiler(0ul, sbyte.MinValue)]
|
||||
[TestCompiler(0ul, sbyte.MaxValue)]
|
||||
public static unsafe IntPtr PointerMathSubPNTypesSByte(UInt64 p,sbyte a)
|
||||
{
|
||||
var pointer = (sbyte*)p;
|
||||
return new IntPtr(pointer - a); // Pointer LHS (no RHS since not legal in C#)
|
||||
}
|
||||
|
||||
[TestCompiler(0ul, short.MinValue)]
|
||||
[TestCompiler(0ul, short.MaxValue)]
|
||||
public static unsafe IntPtr PointerMathAddPNTypesShort(UInt64 p,short a)
|
||||
{
|
||||
var pointer = (short*)p;
|
||||
return new IntPtr(pointer + a); // Pointer LHS
|
||||
}
|
||||
|
||||
[TestCompiler(0ul, short.MinValue)]
|
||||
[TestCompiler(0ul, short.MaxValue)]
|
||||
public static unsafe IntPtr PointerMathAddNPTypesShort(UInt64 p,short a)
|
||||
{
|
||||
var pointer = (short*)p;
|
||||
return new IntPtr(a + pointer); // Pointer RHS
|
||||
}
|
||||
|
||||
[TestCompiler(0ul, short.MinValue)]
|
||||
[TestCompiler(0ul, short.MaxValue)]
|
||||
public static unsafe IntPtr PointerMathSubPNTypesShort(UInt64 p,short a)
|
||||
{
|
||||
var pointer = (short*)p;
|
||||
return new IntPtr(pointer - a); // Pointer LHS (no RHS since not legal in C#)
|
||||
}
|
||||
|
||||
[TestCompiler(0ul, ushort.MinValue)]
|
||||
[TestCompiler(0ul, ushort.MaxValue)]
|
||||
public static unsafe IntPtr PointerMathAddPNTypesUShort(UInt64 p,ushort a)
|
||||
{
|
||||
var pointer = (ushort*)p;
|
||||
return new IntPtr(pointer + a); // Pointer LHS
|
||||
}
|
||||
|
||||
[TestCompiler(0ul, ushort.MinValue)]
|
||||
[TestCompiler(0ul, ushort.MaxValue)]
|
||||
public static unsafe IntPtr PointerMathAddNPTypesUShort(UInt64 p,ushort a)
|
||||
{
|
||||
var pointer = (ushort*)p;
|
||||
return new IntPtr(a + pointer); // Pointer RHS
|
||||
}
|
||||
|
||||
[TestCompiler(0ul, ushort.MinValue)]
|
||||
[TestCompiler(0ul, ushort.MaxValue)]
|
||||
public static unsafe IntPtr PointerMathSubPNTypesUShort(UInt64 p,ushort a)
|
||||
{
|
||||
var pointer = (ushort*)p;
|
||||
return new IntPtr(pointer - a); // Pointer LHS (no RHS since not legal in C#)
|
||||
}
|
||||
|
||||
[TestCompiler(0ul, int.MinValue)]
|
||||
[TestCompiler(0ul, int.MaxValue)]
|
||||
public static unsafe IntPtr PointerMathAddPNTypesInt(UInt64 p,int a)
|
||||
{
|
||||
var pointer = (int*)p;
|
||||
return new IntPtr(pointer + a); // Pointer LHS
|
||||
}
|
||||
|
||||
[TestCompiler(0ul, int.MinValue)]
|
||||
[TestCompiler(0ul, int.MaxValue)]
|
||||
public static unsafe IntPtr PointerMathAddNPTypesInt(UInt64 p,int a)
|
||||
{
|
||||
var pointer = (int*)p;
|
||||
return new IntPtr(a + pointer); // Pointer RHS
|
||||
}
|
||||
|
||||
[TestCompiler(0ul, int.MinValue)]
|
||||
[TestCompiler(0ul, int.MaxValue)]
|
||||
public static unsafe IntPtr PointerMathSubPNTypesInt(UInt64 p,int a)
|
||||
{
|
||||
var pointer = (int*)p;
|
||||
return new IntPtr(pointer - a); // Pointer LHS (no RHS since not legal in C#)
|
||||
}
|
||||
|
||||
[TestCompiler(0ul, uint.MinValue)]
|
||||
[TestCompiler(0ul, uint.MaxValue)]
|
||||
public static unsafe IntPtr PointerMathAddPNTypesUInt(UInt64 p,uint a)
|
||||
{
|
||||
var pointer = (uint*)p;
|
||||
return new IntPtr(pointer + a); // Pointer LHS
|
||||
}
|
||||
|
||||
[TestCompiler(0ul, uint.MinValue)]
|
||||
[TestCompiler(0ul, uint.MaxValue)]
|
||||
public static unsafe IntPtr PointerMathAddNPTypesUInt(UInt64 p,uint a)
|
||||
{
|
||||
var pointer = (uint*)p;
|
||||
return new IntPtr(a + pointer); // Pointer RHS
|
||||
}
|
||||
|
||||
[TestCompiler(0ul, uint.MinValue)]
|
||||
[TestCompiler(0ul, uint.MaxValue)]
|
||||
public static unsafe IntPtr PointerMathSubPNTypesUInt(UInt64 p,uint a)
|
||||
{
|
||||
var pointer = (uint*)p;
|
||||
return new IntPtr(pointer - a); // Pointer LHS (no RHS since not legal in C#)
|
||||
}
|
||||
|
||||
[TestCompiler(0ul, long.MinValue)]
|
||||
[TestCompiler(0ul, long.MaxValue)]
|
||||
public static unsafe IntPtr PolongerMathAddPNTypesLong(UInt64 p,long a)
|
||||
{
|
||||
var polonger = (long*)p;
|
||||
return new IntPtr(polonger + a); // Polonger LHS
|
||||
}
|
||||
|
||||
[TestCompiler(0ul, long.MinValue)]
|
||||
[TestCompiler(0ul, long.MaxValue)]
|
||||
public static unsafe IntPtr PolongerMathAddNPTypesLong(UInt64 p,long a)
|
||||
{
|
||||
var polonger = (long*)p;
|
||||
return new IntPtr(a + polonger); // Polonger RHS
|
||||
}
|
||||
|
||||
[TestCompiler(0ul, long.MinValue)]
|
||||
[TestCompiler(0ul, long.MaxValue)]
|
||||
public static unsafe IntPtr PolongerMathSubPNTypesLong(UInt64 p,long a)
|
||||
{
|
||||
var polonger = (long*)p;
|
||||
return new IntPtr(polonger - a); // Polonger LHS (no RHS since not legal in C#)
|
||||
}
|
||||
|
||||
[TestCompiler(0ul, ulong.MinValue)]
|
||||
[TestCompiler(0ul, ulong.MaxValue)]
|
||||
public static unsafe IntPtr PolongerMathAddPNTypesULong(UInt64 p,ulong a)
|
||||
{
|
||||
var polonger = (ulong*)p;
|
||||
return new IntPtr(polonger + a); // Polonger LHS
|
||||
}
|
||||
|
||||
[TestCompiler(0ul, ulong.MinValue)]
|
||||
[TestCompiler(0ul, ulong.MaxValue)]
|
||||
public static unsafe IntPtr PolongerMathAddNPTypesULong(UInt64 p,ulong a)
|
||||
{
|
||||
var polonger = (ulong*)p;
|
||||
return new IntPtr(a + polonger); // Polonger RHS
|
||||
}
|
||||
|
||||
[TestCompiler(0ul, ulong.MinValue)]
|
||||
[TestCompiler(0ul, ulong.MaxValue)]
|
||||
public static unsafe IntPtr PolongerMathSubPNTypesULong(UInt64 p,ulong a)
|
||||
{
|
||||
var polonger = (ulong*)p;
|
||||
return new IntPtr(polonger - a); // Polonger LHS (no RHS since not legal in C#)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 3d218d6a948d3d8c98c40cca55189572
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,66 @@
|
|||
namespace Burst.Compiler.IL.Tests.Shared
|
||||
{
|
||||
public class Patterns
|
||||
{
|
||||
[TestCompiler(2)]
|
||||
[TestCompiler(1)]
|
||||
[TestCompiler(0)]
|
||||
public static int PropertyPattern(int x)
|
||||
{
|
||||
var point = new Point { X = x, Y = 5 };
|
||||
|
||||
return point switch
|
||||
{
|
||||
{ X: 2 } => 10,
|
||||
{ X: 1 } => 5,
|
||||
_ => 0
|
||||
};
|
||||
}
|
||||
|
||||
private struct Point
|
||||
{
|
||||
public int X;
|
||||
public int Y;
|
||||
}
|
||||
|
||||
[TestCompiler(1, 2)]
|
||||
[TestCompiler(2, 4)]
|
||||
[TestCompiler(0, 0)]
|
||||
public static int TuplePattern(int x, int y)
|
||||
{
|
||||
return (x, y) switch
|
||||
{
|
||||
(1, 2) => 10,
|
||||
(2, 4) => 5,
|
||||
_ => 0
|
||||
};
|
||||
}
|
||||
|
||||
private struct DeconstructablePoint
|
||||
{
|
||||
public int X;
|
||||
public int Y;
|
||||
|
||||
public void Deconstruct(out int x, out int y) => (x, y) = (X, Y);
|
||||
}
|
||||
|
||||
[TestCompiler(1, -1)]
|
||||
[TestCompiler(-1, 1)]
|
||||
[TestCompiler(1, 1)]
|
||||
[TestCompiler(-1, -1)]
|
||||
public static int PositionalPattern(int pointX, int pointY)
|
||||
{
|
||||
var point = new DeconstructablePoint { X = pointX, Y = pointY };
|
||||
|
||||
return point switch
|
||||
{
|
||||
(0, 0) => 0,
|
||||
var (x, y) when x > 0 && y > 0 => 1,
|
||||
var (x, y) when x < 0 && y > 0 => 2,
|
||||
var (x, y) when x < 0 && y < 0 => 3,
|
||||
var (x, y) when x > 0 && y < 0 => 4,
|
||||
var (_, _) => 5
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 50c3d62ace6136cb9c85f8e2a44b7aec
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,144 @@
|
|||
using System.Runtime.CompilerServices;
|
||||
using Unity.Burst;
|
||||
using Unity.Burst.CompilerServices;
|
||||
using UnityBenchShared;
|
||||
|
||||
namespace Burst.Compiler.IL.Tests
|
||||
{
|
||||
internal class Functions
|
||||
{
|
||||
[TestCompiler]
|
||||
public static int CheckFunctionCall()
|
||||
{
|
||||
return AnotherFunction();
|
||||
}
|
||||
|
||||
private static int AnotherFunction()
|
||||
{
|
||||
return 150;
|
||||
}
|
||||
|
||||
[TestCompiler(ExpectCompilerException = true, ExpectedDiagnosticId = DiagnosticId.ERR_UnableToAccessManagedMethod)]
|
||||
public static void Boxing()
|
||||
{
|
||||
var a = new CustomStruct();
|
||||
// This will box CustomStruct, so this method should fail when compiling
|
||||
a.GetType();
|
||||
}
|
||||
|
||||
private struct CustomStruct
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public static int NotDiscardable()
|
||||
{
|
||||
return 3;
|
||||
}
|
||||
|
||||
[BurstDiscard]
|
||||
public static void Discardable()
|
||||
{
|
||||
}
|
||||
|
||||
[TestCompiler]
|
||||
public static int TestCallsOfDiscardedMethodRegression()
|
||||
{
|
||||
// The regression was that we would queue all calls of a method, but if we encountered a discardable one
|
||||
// We would stop visiting pending methods. This resulting in method bodies not being visited.
|
||||
Discardable();
|
||||
return NotDiscardable();
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.NoInlining)]
|
||||
public static int NoInline(int x)
|
||||
{
|
||||
return x;
|
||||
}
|
||||
|
||||
[TestCompiler(42)]
|
||||
public static int TestNoInline(int x)
|
||||
{
|
||||
return NoInline(x);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.NoOptimization)]
|
||||
public static int NoOptimization(int x)
|
||||
{
|
||||
return x;
|
||||
}
|
||||
|
||||
[TestCompiler(42)]
|
||||
public static int TestNoOptimization(int x)
|
||||
{
|
||||
return NoOptimization(x);
|
||||
}
|
||||
|
||||
[TestCompiler(42)]
|
||||
public static int TestImplicitCapture(int x)
|
||||
{
|
||||
return SomeFunction();
|
||||
|
||||
int SomeFunction()
|
||||
{
|
||||
return x;
|
||||
}
|
||||
}
|
||||
|
||||
public struct Pair
|
||||
{
|
||||
public int X;
|
||||
public int Y;
|
||||
|
||||
public struct Provider : IArgumentProvider
|
||||
{
|
||||
public object Value => new Pair { X = 13, Y = 42 };
|
||||
}
|
||||
}
|
||||
|
||||
[TestCompiler(42, typeof(Pair.Provider))]
|
||||
public static int TestImplicitCaptureInLoop(int x, ref Pair rp)
|
||||
{
|
||||
int total = 0;
|
||||
Pair p = rp;
|
||||
|
||||
for (int i = 0; i < x; i++)
|
||||
{
|
||||
total += SomeFunction(42, 42, 42, 42, 42, i);
|
||||
|
||||
int SomeFunction(int a, int b, int c, int d, int e, int otherI)
|
||||
{
|
||||
if (p.Y != 0)
|
||||
{
|
||||
return (otherI == i) ? 56 : -13;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return total;
|
||||
}
|
||||
|
||||
[TestCompiler(42)]
|
||||
[IgnoreWarning((int)DiagnosticId.WRN_ExceptionThrownInNonSafetyCheckGuardedFunction)]
|
||||
public static void NoWarningsWithSingle(int i)
|
||||
{
|
||||
if ((6 * 8) == i)
|
||||
{
|
||||
throw new System.Exception("Not the meaning of life!");
|
||||
}
|
||||
}
|
||||
|
||||
[TestCompiler(42)]
|
||||
[IgnoreWarning((int)DiagnosticId.WRN_LoopIntrinsicCalledButLoopOptimizedAway)]
|
||||
[IgnoreWarning((int)DiagnosticId.WRN_ExceptionThrownInNonSafetyCheckGuardedFunction)]
|
||||
public static void NoWarningsWithMultiple(int i)
|
||||
{
|
||||
if ((6 * 8) == i)
|
||||
{
|
||||
throw new System.Exception("Not the meaning of life!");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: c6f9aa18fd4b3d1d9ef249e3c61af783
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,260 @@
|
|||
// Doesn't work with IL2CPP yet - waiting for Unity fix to land.
|
||||
#if BURST_INTERNAL //|| UNITY_2021_2_OR_NEWER
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using NUnit.Framework;
|
||||
using Unity.Burst;
|
||||
using UnityBenchShared;
|
||||
#if BURST_INTERNAL
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using Burst.Compiler.IL.Aot;
|
||||
#endif
|
||||
|
||||
namespace Burst.Compiler.IL.Tests
|
||||
{
|
||||
[RestrictPlatform("Mono on linux crashes to what appears to be a mono bug", Platform.Linux, exclude: true)]
|
||||
internal class TestCSharpFunctionPointers
|
||||
{
|
||||
[TestCompiler]
|
||||
public static unsafe int TestCSharpFunctionPointer()
|
||||
{
|
||||
delegate* unmanaged[Cdecl]<int, int> callback = &TestCSharpFunctionPointerCallback;
|
||||
return TestCSharpFunctionPointerHelper(callback);
|
||||
}
|
||||
|
||||
private static unsafe int TestCSharpFunctionPointerHelper(delegate* unmanaged[Cdecl]<int, int> callback)
|
||||
{
|
||||
return callback(5);
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvCdecl) })]
|
||||
private static int TestCSharpFunctionPointerCallback(int value) => value + 1;
|
||||
|
||||
[TestCompiler]
|
||||
public static unsafe int TestCSharpFunctionPointerCastingParameterPtrFromVoid()
|
||||
{
|
||||
delegate* unmanaged[Cdecl]<void*, int> callback = &TestCSharpFunctionPointerCallbackVoidPtr;
|
||||
delegate* unmanaged[Cdecl]<int*, int> callbackCasted = callback;
|
||||
|
||||
int i = 5;
|
||||
|
||||
return callbackCasted(&i);
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvCdecl) })]
|
||||
private static unsafe int TestCSharpFunctionPointerCallbackVoidPtr(void* value) => *((int*)value) + 1;
|
||||
|
||||
[TestCompiler]
|
||||
public static unsafe int TestCSharpFunctionPointerCastingParameterPtrToVoid()
|
||||
{
|
||||
delegate* unmanaged[Cdecl]<int*, int> callback = &TestCSharpFunctionPointerCallbackIntPtr;
|
||||
delegate* unmanaged[Cdecl]<void*, int> callbackCasted = (delegate* unmanaged[Cdecl]<void*, int>)callback;
|
||||
|
||||
int i = 5;
|
||||
|
||||
return callbackCasted(&i);
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvCdecl) })]
|
||||
private static unsafe int TestCSharpFunctionPointerCallbackIntPtr(int* value) => *value + 1;
|
||||
|
||||
[TestCompiler]
|
||||
public static unsafe int TestCSharpFunctionPointerCastingToAndFromVoidPtr()
|
||||
{
|
||||
delegate* unmanaged[Cdecl]<int*, int> callback = &TestCSharpFunctionPointerCallbackIntPtr;
|
||||
void* callbackAsVoidPtr = callback;
|
||||
delegate* unmanaged[Cdecl]<int*, int> callbackCasted = (delegate* unmanaged[Cdecl]<int*, int>)callbackAsVoidPtr;
|
||||
|
||||
int i = 5;
|
||||
|
||||
return callbackCasted(&i);
|
||||
}
|
||||
|
||||
public struct CSharpFunctionPointerProvider : IArgumentProvider
|
||||
{
|
||||
public unsafe object Value
|
||||
{
|
||||
get
|
||||
{
|
||||
delegate* unmanaged[Cdecl]<int, int> callback = &TestCSharpFunctionPointerCallback;
|
||||
return (IntPtr)callback;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[TestCompiler(typeof(CSharpFunctionPointerProvider))]
|
||||
public static unsafe int TestCSharpFunctionPointerPassedInFromOutside(IntPtr callbackAsIntPtr)
|
||||
{
|
||||
delegate* unmanaged[Cdecl]<int, int> callback = (delegate* unmanaged[Cdecl]<int, int>)callbackAsIntPtr;
|
||||
return TestCSharpFunctionPointerHelper(callback);
|
||||
}
|
||||
|
||||
private struct TestCSharpFunctionPointerWithStructParameterStruct
|
||||
{
|
||||
public int X;
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvCdecl) })]
|
||||
private static int TestCSharpFunctionPointerWithStructParameterCallback(TestCSharpFunctionPointerWithStructParameterStruct value) => value.X + 1;
|
||||
|
||||
public struct CSharpFunctionPointerWithStructParameterProvider : IArgumentProvider
|
||||
{
|
||||
public unsafe object Value
|
||||
{
|
||||
get
|
||||
{
|
||||
delegate* unmanaged[Cdecl]<TestCSharpFunctionPointerWithStructParameterStruct, int> callback = &TestCSharpFunctionPointerWithStructParameterCallback;
|
||||
return (IntPtr)callback;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[TestCompiler(typeof(CSharpFunctionPointerWithStructParameterProvider))]
|
||||
public static unsafe int TestCSharpFunctionPointerPassedInFromOutsideWithStructParameter(IntPtr untypedFp)
|
||||
{
|
||||
return TestHashingFunctionPointerTypeHelper((delegate* unmanaged[Cdecl]<TestCSharpFunctionPointerWithStructParameterStruct, int>)untypedFp);
|
||||
}
|
||||
|
||||
private static unsafe int TestHashingFunctionPointerTypeHelper(delegate* unmanaged[Cdecl]<TestCSharpFunctionPointerWithStructParameterStruct, int> fp)
|
||||
{
|
||||
return fp(new TestCSharpFunctionPointerWithStructParameterStruct { X = 42 });
|
||||
}
|
||||
|
||||
[TestCompiler(ExpectCompilerException = true, ExpectedDiagnosticId = DiagnosticId.ERR_CalliNonCCallingConventionNotSupported)]
|
||||
public static unsafe int TestCSharpFunctionPointerInvalidCallingConvention()
|
||||
{
|
||||
delegate*<int, int> callback = &TestCSharpFunctionPointerInvalidCallingConventionCallback;
|
||||
return callback(5);
|
||||
}
|
||||
|
||||
private static int TestCSharpFunctionPointerInvalidCallingConventionCallback(int value) => value + 1;
|
||||
|
||||
[TestCompiler]
|
||||
public static unsafe int TestCSharpFunctionPointerMissingBurstCompileAttribute()
|
||||
{
|
||||
delegate* unmanaged[Cdecl]<int, int> callback = &TestCSharpFunctionPointerCallbackMissingBurstCompileAttribute;
|
||||
return callback(5);
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvCdecl) })]
|
||||
private static int TestCSharpFunctionPointerCallbackMissingBurstCompileAttribute(int value) => value + 1;
|
||||
|
||||
[Test]
|
||||
public unsafe void TestFunctionPointerReturnedFromBurstFunction()
|
||||
{
|
||||
#if BURST_INTERNAL
|
||||
var libraryCacheFolderName = Path.Combine(
|
||||
Path.GetDirectoryName(GetType().Assembly.Location),
|
||||
nameof(TestCSharpFunctionPointers),
|
||||
nameof(TestFunctionPointerReturnedFromBurstFunction));
|
||||
if (Directory.Exists(libraryCacheFolderName))
|
||||
{
|
||||
Directory.Delete(libraryCacheFolderName, true);
|
||||
}
|
||||
using var globalContext = new Server.GlobalContext(libraryCacheFolderName);
|
||||
var jitOptions = new AotCompilerOptions();
|
||||
using var methodCompiler = new Helpers.MethodCompiler(globalContext, jitOptions.BackendName, name => IntPtr.Zero);
|
||||
|
||||
BurstCompiler.InternalCompiler = del =>
|
||||
{
|
||||
var getMethod = del.GetType().GetMethod("get_Method", BindingFlags.Public | BindingFlags.Instance);
|
||||
var methodInfo = (MethodInfo)getMethod.Invoke(del, new object[0]);
|
||||
var compiledResult = methodCompiler.CompileMethod(methodInfo, jitOptions);
|
||||
|
||||
return compiledResult.FunctionPointer;
|
||||
};
|
||||
#endif
|
||||
|
||||
var fp = BurstCompiler.CompileFunctionPointer<DelegateWithCSharpFunctionPointerReturn>(EntryPointWithCSharpFunctionPointerReturn);
|
||||
|
||||
var fpInner = fp.Invoke();
|
||||
|
||||
delegate* unmanaged[Cdecl]<float, float, float, float, float, float, float> callback = (delegate* unmanaged[Cdecl]<float, float, float, float, float, float, float>)fpInner;
|
||||
|
||||
var result = callback(1, 2, 4, 8, 16, 32);
|
||||
|
||||
Assert.AreEqual((float)(1 + 2 + 4 + 8 + 16 + 32), result);
|
||||
}
|
||||
|
||||
[BurstCompile(CompileSynchronously = true)]
|
||||
private static unsafe IntPtr EntryPointWithCSharpFunctionPointerReturn()
|
||||
{
|
||||
delegate* unmanaged[Cdecl]<float, float, float, float, float, float, float> fp = &EntryPointWithCSharpFunctionPointerReturnHelper;
|
||||
return (IntPtr)fp;
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvCdecl) })]
|
||||
private static unsafe float EntryPointWithCSharpFunctionPointerReturnHelper(float p1, float p2, float p3, float p4, float p5, float p6)
|
||||
{
|
||||
return p1 + p2 + p3 + p4 + p5 + p6;
|
||||
}
|
||||
|
||||
private unsafe delegate IntPtr DelegateWithCSharpFunctionPointerReturn();
|
||||
|
||||
// Note that there are 6 float parameters to try to catch any issues with calling conventions.
|
||||
private unsafe delegate float DelegateWithCSharpFunctionPointerReturnHelper(float p1, float p2, float p3, float p4, float p5, float p6);
|
||||
|
||||
// Note that this test previously had a `out int i` parameter, but a bugfix in Roslyn
|
||||
// means that ref parameters in UnmanagedCallersOnly methods now result in a compilation error:
|
||||
// https://github.com/dotnet/roslyn/issues/57025
|
||||
// So we've updated this test to use a pointer.
|
||||
[UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvCdecl) })]
|
||||
private static unsafe void TestCSharpFunctionPointerCallbackWithOut(int* i)
|
||||
{
|
||||
TestCSharpFunctionPointerCallbackWithOut(out *i);
|
||||
}
|
||||
|
||||
private static void TestCSharpFunctionPointerCallbackWithOut(out int i)
|
||||
{
|
||||
i = 42;
|
||||
}
|
||||
|
||||
[TestCompiler]
|
||||
public static unsafe int TestCSharpFunctionPointerWithOut()
|
||||
{
|
||||
delegate* unmanaged[Cdecl]<int*, void> callback = &TestCSharpFunctionPointerCallbackWithOut;
|
||||
|
||||
int i;
|
||||
callback(&i);
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
#if BURST_TESTS_ONLY
|
||||
[DllImport("burst-dllimport-native")]
|
||||
private static extern unsafe int callFunctionPointer(delegate* unmanaged[Cdecl]<int, int> f);
|
||||
|
||||
// Ignored on wasm since dynamic linking is not supported at present.
|
||||
// Override result on Mono because it throws a StackOverflowException for some reason related to the function pointer.
|
||||
// We should use OverrideResultOnMono, but OverrideResultOnMono still runs the managed version, which causes a crash,
|
||||
// so we use OverrideManagedResult.
|
||||
[TestCompiler(IgnoreOnPlatform = Backend.TargetPlatform.Wasm, OverrideManagedResult = 43)]
|
||||
public static unsafe int TestPassingFunctionPointerToNativeCode()
|
||||
{
|
||||
return callFunctionPointer(&TestCSharpFunctionPointerCallback);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
// This attribute is also included in com.unity.burst/Tests/Runtime/FunctionPointerTests.cs,
|
||||
// so we want to exclude it here when we're running inside Unity otherwise we'll get a
|
||||
// duplicate definition error.
|
||||
#if BURST_TESTS_ONLY
|
||||
// UnmanagedCallersOnlyAttribute is new in .NET 5.0. This attribute is required
|
||||
// when you declare an unmanaged function pointer with an explicit calling convention.
|
||||
// Fortunately, Roslyn lets us declare the attribute class ourselves, and it will be used.
|
||||
// Users will need this same declaration in their own projects, in order to use
|
||||
// C# 9.0 function pointers.
|
||||
namespace System.Runtime.InteropServices
|
||||
{
|
||||
[AttributeUsage(System.AttributeTargets.Method, Inherited = false)]
|
||||
public sealed class UnmanagedCallersOnlyAttribute : Attribute
|
||||
{
|
||||
public Type[] CallConvs;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 7a3d2b4e287138d6b5a68635fcda35ae
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,112 @@
|
|||
#if UNITY_ANDROID && !UNITY_EDITOR
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Burst.Compiler.IL.Tests
|
||||
{
|
||||
public class DllImportAndroid
|
||||
{
|
||||
public unsafe struct HandleStruct
|
||||
{
|
||||
public void* Handle;
|
||||
}
|
||||
|
||||
public struct NestedHandleStruct
|
||||
{
|
||||
public HandleStruct Handle;
|
||||
}
|
||||
|
||||
public unsafe struct TypedHandleStruct
|
||||
{
|
||||
public byte* Handle;
|
||||
}
|
||||
|
||||
public struct IntInStruct
|
||||
{
|
||||
public int Handle;
|
||||
}
|
||||
|
||||
public struct LongInStruct
|
||||
{
|
||||
public long Handle;
|
||||
}
|
||||
|
||||
[DllImport("burst-dllimport-native")]
|
||||
public static extern void allVoid();
|
||||
|
||||
[TestCompiler]
|
||||
public static void AllVoid()
|
||||
{
|
||||
allVoid();
|
||||
}
|
||||
|
||||
[DllImport("burst-dllimport-native")]
|
||||
public static extern int incrementByOne(int x);
|
||||
|
||||
[TestCompiler]
|
||||
public static int UseDllImportedFunction()
|
||||
{
|
||||
return incrementByOne(41);
|
||||
}
|
||||
|
||||
[DllImport("burst-dllimport-native")]
|
||||
public static extern int readFromPtr(ref int x);
|
||||
|
||||
[TestCompiler]
|
||||
public static int ReadFromPtr()
|
||||
{
|
||||
int x = 37;
|
||||
return readFromPtr(ref x);
|
||||
}
|
||||
|
||||
[DllImport("burst-dllimport-native")]
|
||||
public static extern HandleStruct handleStruct(HandleStruct handle);
|
||||
|
||||
[TestCompiler]
|
||||
public unsafe static long HandleStructByVal()
|
||||
{
|
||||
var handle = new HandleStruct { Handle = (void*)0x42 };
|
||||
return (long)handleStruct(handle).Handle;
|
||||
}
|
||||
|
||||
[DllImport("burst-dllimport-native")]
|
||||
public static extern NestedHandleStruct nestedHandleStruct(NestedHandleStruct handle);
|
||||
|
||||
[TestCompiler]
|
||||
public unsafe static long NestedHandleStructByVal()
|
||||
{
|
||||
var handle = new NestedHandleStruct { Handle = new HandleStruct { Handle = (void*)0x42 } };
|
||||
return (long)nestedHandleStruct(handle).Handle.Handle;
|
||||
}
|
||||
|
||||
[DllImport("burst-dllimport-native")]
|
||||
public static extern TypedHandleStruct typedHandleStruct(TypedHandleStruct handle);
|
||||
|
||||
[TestCompiler]
|
||||
public unsafe static long TypedHandleStructByVal()
|
||||
{
|
||||
var handle = new TypedHandleStruct { Handle = (byte*)0x42 };
|
||||
return (long)typedHandleStruct(handle).Handle;
|
||||
}
|
||||
|
||||
[DllImport("burst-dllimport-native")]
|
||||
public static extern IntInStruct intInStruct(IntInStruct handle);
|
||||
|
||||
[TestCompiler]
|
||||
public unsafe static long IntInStructByVal()
|
||||
{
|
||||
var handle = new IntInStruct { Handle = 0x42424242 };
|
||||
return (long)intInStruct(handle).Handle;
|
||||
}
|
||||
|
||||
[DllImport("burst-dllimport-native")]
|
||||
public static extern LongInStruct longInStruct(LongInStruct handle);
|
||||
|
||||
[TestCompiler]
|
||||
public unsafe static long LongInStructByVal()
|
||||
{
|
||||
var handle = new LongInStruct { Handle = 0x4242424242424242 };
|
||||
return (long)longInStruct(handle).Handle;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: bb0c92e22ce4395fae3821dcc85a3113
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,852 @@
|
|||
using System;
|
||||
using NUnit.Framework;
|
||||
using Unity.Burst;
|
||||
using Unity.Collections;
|
||||
using Unity.Jobs;
|
||||
using Unity.Mathematics;
|
||||
|
||||
namespace Burst.Compiler.IL.Tests
|
||||
{
|
||||
internal class ControlFlows
|
||||
{
|
||||
[TestCompiler]
|
||||
public static int For()
|
||||
{
|
||||
var counter = 0;
|
||||
for (var i = 0; i < 10; i++)
|
||||
counter++;
|
||||
return counter;
|
||||
}
|
||||
|
||||
[TestCompiler(10)]
|
||||
public static int ForBreak(int a)
|
||||
{
|
||||
int result = 0;
|
||||
for (int i = 0; i < a; i++)
|
||||
{
|
||||
if (i == 5)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
result += 2;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
[TestCompiler(10, 5)]
|
||||
public static int ForContinue(int a, int b)
|
||||
{
|
||||
int result = 0;
|
||||
for (int i = 0; i < a; i++)
|
||||
{
|
||||
if (i == b)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
result += i;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
[TestCompiler]
|
||||
public static int ForBreak2()
|
||||
{
|
||||
int i = 0;
|
||||
while (true)
|
||||
{
|
||||
if (i == 5)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
i++;
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
[TestCompiler(10)]
|
||||
public static float ForDynamicCondition(ref int b)
|
||||
{
|
||||
var counter = 0.0f;
|
||||
for (var i = 0; i < b; i++)
|
||||
counter++;
|
||||
return counter;
|
||||
}
|
||||
|
||||
[TestCompiler(5, 5)]
|
||||
public static int ForNestedIf(int a, int b)
|
||||
{
|
||||
var counter = 0;
|
||||
for (var i = 0; i < a; i++)
|
||||
for (var i2 = 0; i != b; i++)
|
||||
{
|
||||
counter += i;
|
||||
counter += i2;
|
||||
}
|
||||
return counter;
|
||||
}
|
||||
|
||||
[TestCompiler(5, 5)]
|
||||
public static int DoWhileNested(int a, int b)
|
||||
{
|
||||
var total = 0;
|
||||
var counter2 = 0;
|
||||
do
|
||||
{
|
||||
var counter1 = 0;
|
||||
do
|
||||
{
|
||||
total++;
|
||||
counter1++;
|
||||
} while (counter1 < a);
|
||||
counter2++;
|
||||
} while (counter2 < b);
|
||||
|
||||
return total;
|
||||
}
|
||||
|
||||
[TestCompiler(5)]
|
||||
public static int While(int a)
|
||||
{
|
||||
var i = 0;
|
||||
var counter = 0;
|
||||
while (i < a)
|
||||
{
|
||||
i++;
|
||||
counter += i;
|
||||
}
|
||||
return counter;
|
||||
}
|
||||
|
||||
[TestCompiler(5)]
|
||||
public static int ForForIf(int a)
|
||||
{
|
||||
var counter = 0;
|
||||
for (var i = 0; i != a; i++)
|
||||
for (var j = 0; j < 4; j++)
|
||||
if (j > 2)
|
||||
counter = counter + i;
|
||||
return counter;
|
||||
}
|
||||
|
||||
[TestCompiler(5)]
|
||||
public static int ForNestedComplex1(int a)
|
||||
{
|
||||
var x = 0;
|
||||
var y = 0;
|
||||
for (var i = 0; i < a; i++)
|
||||
{
|
||||
y = y + 1;
|
||||
for (var j = 0; j < 4; j++)
|
||||
{
|
||||
if (y > 1)
|
||||
{
|
||||
x = x + i;
|
||||
if (x > 2)
|
||||
{
|
||||
for (int k = 0; k < 3; k++)
|
||||
{
|
||||
y = y + 1;
|
||||
if (y > 3)
|
||||
{
|
||||
x = x + 1;
|
||||
}
|
||||
else if (x > 6)
|
||||
{
|
||||
y = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
x--;
|
||||
}
|
||||
x++;
|
||||
}
|
||||
if (y > 2)
|
||||
{
|
||||
x = x + 1;
|
||||
}
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
[TestCompiler(5)]
|
||||
public static int ForNestedComplex2(int a)
|
||||
{
|
||||
var x = 0;
|
||||
for (var i = 0; i < a; i++)
|
||||
{
|
||||
var insideLoop1 = 0;
|
||||
for (var j = 0; j < 4; j++)
|
||||
{
|
||||
x = x + i;
|
||||
if (x > 2)
|
||||
{
|
||||
insideLoop1++;
|
||||
for (int k = 0; k < 3; k++)
|
||||
{
|
||||
if (insideLoop1 > 3)
|
||||
{
|
||||
x = x + 1;
|
||||
}
|
||||
else if (x > 6)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (insideLoop1 > 2)
|
||||
{
|
||||
x = x + 1 + insideLoop1;
|
||||
}
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
|
||||
[TestCompiler(5)]
|
||||
[TestCompiler(-5)]
|
||||
public static int IfReturn(int a)
|
||||
{
|
||||
if (a < 0)
|
||||
return 55;
|
||||
return 111;
|
||||
}
|
||||
|
||||
[TestCompiler(5)]
|
||||
[TestCompiler(-5)]
|
||||
public static int IfElseReturn(int a)
|
||||
{
|
||||
int b = 0;
|
||||
if (a < 0)
|
||||
{
|
||||
b = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
b = 2;
|
||||
}
|
||||
return b;
|
||||
}
|
||||
|
||||
[TestCompiler(5)]
|
||||
[TestCompiler(-5)]
|
||||
public static int IfElseReturnDynamic(int a)
|
||||
{
|
||||
int b;
|
||||
if (a < 0)
|
||||
{
|
||||
b = a;
|
||||
}
|
||||
else
|
||||
{
|
||||
b = a + 1;
|
||||
}
|
||||
return b;
|
||||
}
|
||||
|
||||
|
||||
[TestCompiler(10)]
|
||||
public static int WhileFunction(int a)
|
||||
{
|
||||
while (condition_helper(a))
|
||||
{
|
||||
a--;
|
||||
}
|
||||
return a;
|
||||
}
|
||||
|
||||
[TestCompiler(10)]
|
||||
public static int WhileDynamic(ref int a)
|
||||
{
|
||||
while (a > 2)
|
||||
{
|
||||
a--;
|
||||
}
|
||||
return a;
|
||||
}
|
||||
|
||||
|
||||
[TestCompiler(5, 6, 7)]
|
||||
[TestCompiler(-5, -6, -7)]
|
||||
public static int IfDeep(int a, int b, int c)
|
||||
{
|
||||
int result = 0;
|
||||
if (a < 0)
|
||||
{
|
||||
if (b > 1)
|
||||
{
|
||||
if (c < 2)
|
||||
{
|
||||
result = 55;
|
||||
}
|
||||
else
|
||||
{
|
||||
result = 66;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
result = 77;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (b < 0)
|
||||
{
|
||||
if (c < -2)
|
||||
{
|
||||
result = 88;
|
||||
}
|
||||
else
|
||||
{
|
||||
result = 99;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
result = 100;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
[TestCompiler(5)]
|
||||
public static int CallRecursive(int n)
|
||||
{
|
||||
return InternalCallRecursive(n);
|
||||
}
|
||||
|
||||
private static int InternalCallRecursive(int n)
|
||||
{
|
||||
if (n <= 1)
|
||||
return 1;
|
||||
return n * InternalCallRecursive(n - 1);
|
||||
}
|
||||
|
||||
[TestCompiler(3f, 8f)]
|
||||
[TestCompiler(6f, 8f)]
|
||||
public static float IfCompareFloat(float a, float b)
|
||||
{
|
||||
if (a > 5f)
|
||||
return 10f;
|
||||
return b;
|
||||
}
|
||||
|
||||
[TestCompiler(10)]
|
||||
[TestCompiler(0)]
|
||||
public static float TernaryCompareFloat(int input)
|
||||
{
|
||||
return input > 5 ? 2.5f : 1.2F;
|
||||
}
|
||||
|
||||
[TestCompiler(0)]
|
||||
[TestCompiler(1)]
|
||||
public static int TernaryMask(int a)
|
||||
{
|
||||
return (a & 1) != 0 ? 5 : 4;
|
||||
}
|
||||
|
||||
[TestCompiler(0)]
|
||||
[TestCompiler(1)]
|
||||
public static int IfElseMash(int a)
|
||||
{
|
||||
if ((a & 1) != 0)
|
||||
return 5;
|
||||
else
|
||||
return 4;
|
||||
}
|
||||
|
||||
[TestCompiler(0)]
|
||||
public static int IfCallCondition(int a)
|
||||
{
|
||||
if (a > 0 && condition_helper(++a))
|
||||
{
|
||||
return a;
|
||||
}
|
||||
return -10 + a;
|
||||
}
|
||||
|
||||
[TestCompiler(1)]
|
||||
[TestCompiler(0)]
|
||||
[TestCompiler(-1)]
|
||||
public static int IfIncrementCondition(int a)
|
||||
{
|
||||
if (a < 0 || condition_helper(++a))
|
||||
{
|
||||
return a;
|
||||
}
|
||||
return -10 + a;
|
||||
}
|
||||
|
||||
|
||||
private static bool condition_helper(int value)
|
||||
{
|
||||
return value > 2;
|
||||
}
|
||||
|
||||
[TestCompiler(1, 8)]
|
||||
public static int IfWhileGotoForward(int a, int b)
|
||||
{
|
||||
if (a > 0)
|
||||
{
|
||||
while (a < 10)
|
||||
{
|
||||
a++;
|
||||
if (a == b)
|
||||
{
|
||||
a--;
|
||||
goto TestLabel;
|
||||
}
|
||||
}
|
||||
a++;
|
||||
}
|
||||
TestLabel:
|
||||
a--;
|
||||
return a;
|
||||
}
|
||||
|
||||
[TestCompiler(1, 5)]
|
||||
public static int IfWhileGotoBackward(int a, int b)
|
||||
{
|
||||
RewindLabel:
|
||||
if (a > 0)
|
||||
{
|
||||
while (a < 10)
|
||||
{
|
||||
a++;
|
||||
if (a == b)
|
||||
{
|
||||
a++;
|
||||
goto RewindLabel;
|
||||
}
|
||||
}
|
||||
a++;
|
||||
}
|
||||
a--;
|
||||
return a;
|
||||
}
|
||||
|
||||
[TestCompiler(-1, 0)]
|
||||
[TestCompiler(0, 0)]
|
||||
[TestCompiler(0, -1)]
|
||||
public static int IfAssignCondition(int a, int b)
|
||||
{
|
||||
int result = 0;
|
||||
if (++a > 0 && ++b > 0)
|
||||
{
|
||||
result = a + b;
|
||||
}
|
||||
else
|
||||
{
|
||||
result = a * 10 + b;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
private static bool ProcessFirstInt(int a, out float b)
|
||||
{
|
||||
b = a + 1;
|
||||
return b < 10;
|
||||
}
|
||||
|
||||
private static bool ProcessNextInt(int a, ref float b)
|
||||
{
|
||||
b = a + 2;
|
||||
return b < 20;
|
||||
}
|
||||
|
||||
[TestCompiler(1, 10)]
|
||||
public static float ForWhileNestedCall(int a, int b)
|
||||
{
|
||||
float value = 0;
|
||||
for (int i = 0; i < b * 3; i++)
|
||||
{
|
||||
var flag = ProcessFirstInt(a, out value);
|
||||
int num2 = 0;
|
||||
while (flag && num2 < 2)
|
||||
{
|
||||
bool flag2 = i == a;
|
||||
if (flag2)
|
||||
{
|
||||
flag = ProcessNextInt(a + i, ref value);
|
||||
}
|
||||
else
|
||||
{
|
||||
value++;
|
||||
flag = ProcessNextInt(a + b + i, ref value);
|
||||
}
|
||||
num2++;
|
||||
}
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
#if BURST_TESTS_ONLY
|
||||
[TestCompiler(true)]
|
||||
[TestCompiler(false)]
|
||||
public static bool CheckDup(bool value)
|
||||
{
|
||||
return ILTestsHelper.CheckDupBeforeJump(value);
|
||||
}
|
||||
#endif
|
||||
|
||||
[TestCompiler(1)]
|
||||
public static int WhileIfContinue(int a)
|
||||
{
|
||||
while (a > 10)
|
||||
{
|
||||
if (a < 5)
|
||||
{
|
||||
a++;
|
||||
if (a == 8)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
a++;
|
||||
}
|
||||
return a;
|
||||
}
|
||||
|
||||
[TestCompiler(0)]
|
||||
[TestCompiler(1)]
|
||||
[TestCompiler(2)]
|
||||
[TestCompiler(3)]
|
||||
[TestCompiler(4)]
|
||||
public static int SwitchReturn(int a)
|
||||
{
|
||||
switch (a)
|
||||
{
|
||||
case 1:
|
||||
return 100;
|
||||
case 2:
|
||||
return 200;
|
||||
case 3:
|
||||
return 300;
|
||||
case 10:
|
||||
return 300;
|
||||
default:
|
||||
return 1000;
|
||||
}
|
||||
}
|
||||
|
||||
[TestCompiler(0)]
|
||||
[TestCompiler(1)]
|
||||
[TestCompiler(2)]
|
||||
[TestCompiler(3)]
|
||||
[TestCompiler(4)]
|
||||
public static int SwitchBreak(int a)
|
||||
{
|
||||
switch (a)
|
||||
{
|
||||
case 1:
|
||||
return 100;
|
||||
case 2:
|
||||
break;
|
||||
default:
|
||||
return 1000;
|
||||
}
|
||||
|
||||
return 200;
|
||||
}
|
||||
|
||||
[TestCompiler((byte)0)]
|
||||
[TestCompiler((byte)1)]
|
||||
[TestCompiler((byte)2)]
|
||||
[TestCompiler((byte)3)]
|
||||
[TestCompiler((byte)4)]
|
||||
public static int SwitchBreakByte(byte a)
|
||||
{
|
||||
switch (a)
|
||||
{
|
||||
case 1:
|
||||
return 100;
|
||||
case 2:
|
||||
break;
|
||||
default:
|
||||
return 1000;
|
||||
}
|
||||
|
||||
return 200;
|
||||
}
|
||||
|
||||
public static byte GetValueAsByte(int a)
|
||||
{
|
||||
return (byte)a;
|
||||
}
|
||||
|
||||
[TestCompiler(0)]
|
||||
[TestCompiler(1)]
|
||||
[TestCompiler(2)]
|
||||
[TestCompiler(3)]
|
||||
public static byte SwitchByteReturnFromFunction(int a)
|
||||
{
|
||||
switch (GetValueAsByte(a))
|
||||
{
|
||||
case 0:
|
||||
return 1;
|
||||
case 1:
|
||||
return 2;
|
||||
case 2:
|
||||
return 3;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
[TestCompiler(long.MaxValue)]
|
||||
[TestCompiler(long.MinValue)]
|
||||
[TestCompiler(0)]
|
||||
public static byte SwitchOnLong(long a)
|
||||
{
|
||||
switch (a)
|
||||
{
|
||||
case long.MaxValue:
|
||||
return 1;
|
||||
case long.MinValue:
|
||||
return 2;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
public static byte TestSwitchByteReturn(NativeArray<byte> _results, int a)
|
||||
{
|
||||
if (_results.Length > a)
|
||||
{
|
||||
switch (_results[a])
|
||||
{
|
||||
case 0:
|
||||
return 1;
|
||||
case 1:
|
||||
return 2;
|
||||
case 2:
|
||||
return 3;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 99;
|
||||
}
|
||||
|
||||
[TestCompiler(EnumSwitch.Case1)]
|
||||
[TestCompiler(EnumSwitch.Case2)]
|
||||
[TestCompiler(EnumSwitch.Case3)]
|
||||
public static int SwitchEnum(EnumSwitch a)
|
||||
{
|
||||
switch (a)
|
||||
{
|
||||
case EnumSwitch.Case1:
|
||||
return 100;
|
||||
case EnumSwitch.Case3:
|
||||
break;
|
||||
default:
|
||||
return 1000;
|
||||
}
|
||||
|
||||
return 200;
|
||||
}
|
||||
|
||||
public enum EnumSwitch
|
||||
{
|
||||
Case1,
|
||||
|
||||
Case2,
|
||||
|
||||
Case3,
|
||||
}
|
||||
|
||||
[TestCompiler(long.MaxValue)]
|
||||
[TestCompiler(long.MinValue)]
|
||||
[TestCompiler(0)]
|
||||
public static byte SwitchExpression(long a)
|
||||
{
|
||||
return a switch
|
||||
{
|
||||
long.MaxValue => 1,
|
||||
long.MinValue => 2,
|
||||
_ => 0,
|
||||
};
|
||||
}
|
||||
|
||||
[TestCompiler(ExpectedException = typeof(InvalidOperationException), ExpectedDiagnosticId = DiagnosticId.WRN_ExceptionThrownInNonSafetyCheckGuardedFunction)]
|
||||
[MonoOnly(".NET CLR does not support burst.abort correctly")]
|
||||
public static int ExceptionReachedReturn()
|
||||
{
|
||||
throw new InvalidOperationException("This is bad 1");
|
||||
}
|
||||
|
||||
[TestCompiler(ExpectedException = typeof(InvalidOperationException), ExpectedDiagnosticId = DiagnosticId.WRN_ExceptionThrownInNonSafetyCheckGuardedFunction)]
|
||||
[MonoOnly(".NET CLR does not support burst.abort correctly")]
|
||||
public static void ExceptionReached()
|
||||
{
|
||||
throw new InvalidOperationException("This is bad 2");
|
||||
}
|
||||
|
||||
[TestCompiler(1, ExpectedDiagnosticId = DiagnosticId.WRN_ExceptionThrownInNonSafetyCheckGuardedFunction)]
|
||||
[TestCompiler(2, ExpectedDiagnosticId = DiagnosticId.WRN_ExceptionThrownInNonSafetyCheckGuardedFunction)]
|
||||
public static void ExceptionNotReached(int a)
|
||||
{
|
||||
if (a > 10)
|
||||
{
|
||||
throw new InvalidOperationException("This is bad 2");
|
||||
}
|
||||
}
|
||||
|
||||
[TestCompiler(1, ExpectedDiagnosticId = DiagnosticId.WRN_ExceptionThrownInNonSafetyCheckGuardedFunction)]
|
||||
[TestCompiler(2, ExpectedDiagnosticId = DiagnosticId.WRN_ExceptionThrownInNonSafetyCheckGuardedFunction)]
|
||||
public static void ExceptionMultipleNotReached(int a)
|
||||
{
|
||||
if (a > 10)
|
||||
{
|
||||
if (a > 15)
|
||||
{
|
||||
throw new InvalidOperationException("This is bad 2");
|
||||
}
|
||||
else
|
||||
{
|
||||
if (a < 8)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
else
|
||||
{
|
||||
a = a + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private struct SmallStruct
|
||||
{
|
||||
public int I;
|
||||
public float F;
|
||||
}
|
||||
|
||||
private static SmallStruct UnreachedException(bool b)
|
||||
{
|
||||
if (b)
|
||||
{
|
||||
throw new Exception("Never here!");
|
||||
}
|
||||
|
||||
return new SmallStruct { I = 42, F = 42.0f };
|
||||
}
|
||||
|
||||
[TestCompiler(0, ExpectedDiagnosticId = DiagnosticId.WRN_ExceptionThrownInNonSafetyCheckGuardedFunction)]
|
||||
public static double UnreachedExceptionInCalledFunction(int a)
|
||||
{
|
||||
var result = UnreachedException(a != 0);
|
||||
|
||||
return result.I + result.F;
|
||||
}
|
||||
|
||||
[TestCompiler(1, ExpectedDiagnosticId = DiagnosticId.WRN_ExceptionThrownInNonSafetyCheckGuardedFunction)]
|
||||
public static int ExceptionNotReachedReturn(int a)
|
||||
{
|
||||
int b = a;
|
||||
if (a > 10)
|
||||
{
|
||||
b = 5;
|
||||
throw new InvalidOperationException("This is bad 2");
|
||||
}
|
||||
return b;
|
||||
}
|
||||
|
||||
|
||||
[TestCompiler(13, ExpectedDiagnosticId = DiagnosticId.WRN_ExceptionThrownInNonSafetyCheckGuardedFunction)]
|
||||
[TestCompiler(1, ExpectedDiagnosticId = DiagnosticId.WRN_ExceptionThrownInNonSafetyCheckGuardedFunction)]
|
||||
public static int ExceptionMultipleNotReachedReturn(int a)
|
||||
{
|
||||
if (a > 10)
|
||||
{
|
||||
if (a > 15)
|
||||
{
|
||||
throw new InvalidOperationException("This is bad 2");
|
||||
}
|
||||
else
|
||||
{
|
||||
if (a < 12)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
else
|
||||
{
|
||||
a = a + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
return a;
|
||||
}
|
||||
|
||||
[TestCompiler]
|
||||
public static void TestInternalError()
|
||||
{
|
||||
var job = new InternalErrorVariableNotFound();
|
||||
job.Execute();
|
||||
}
|
||||
|
||||
public struct InternalErrorVariableNotFound : IJob
|
||||
{
|
||||
public void Execute()
|
||||
{
|
||||
CausesError(3);
|
||||
}
|
||||
|
||||
static int CausesError(int x)
|
||||
{
|
||||
int y = 0;
|
||||
while (y != 0 && y != 1)
|
||||
{
|
||||
if (x > 0)
|
||||
x = y++;
|
||||
}
|
||||
return y;
|
||||
}
|
||||
}
|
||||
|
||||
[TestCompiler(true)]
|
||||
public static int TestPopNonInitialTrailingPush(bool x)
|
||||
{
|
||||
return (x ? 1 : -1) * math.min(16, 1);
|
||||
}
|
||||
|
||||
[TestCompiler]
|
||||
// Check unsigned ternary comparison (Bxx_Un) opcodes
|
||||
public static ulong TestUnsignedTernary()
|
||||
{
|
||||
ulong a = 0;
|
||||
ulong b = ~0UL;
|
||||
ulong c = (a < b) ? 1UL : 0;
|
||||
ulong d = (a <= b) ? 1UL : 0;
|
||||
ulong e = (a > b) ? 0: 1UL;
|
||||
ulong f = (a >= b) ? 0: 1UL;
|
||||
|
||||
return c + d + e + f;
|
||||
}
|
||||
|
||||
[TestCompiler((byte)0)]
|
||||
[TestCompiler((byte) 1)]
|
||||
public static int TestByteAndIntFlow(byte value)
|
||||
{
|
||||
var position = value == 0 ? -1 : value;
|
||||
if (position < 0)
|
||||
{
|
||||
position = 17;
|
||||
}
|
||||
return position;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 945f727e6eb43c81ae49f4e92e3d98c2
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,372 @@
|
|||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using Unity.Burst;
|
||||
using Unity.Collections;
|
||||
using Unity.Collections.LowLevel.Unsafe;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace Burst.Compiler.IL.Tests
|
||||
{
|
||||
internal class ControlFlowsTryCatchFinally
|
||||
{
|
||||
[TestCompiler(-10)]
|
||||
[TestCompiler(0)]
|
||||
[TestCompiler(10)]
|
||||
public static int TryFinallySimple(int i)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (i == 0) // case 0
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
else if (i > 0) // case 10
|
||||
{
|
||||
i = i * 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
i = i * 3; // case -10
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
i = i + 1;
|
||||
}
|
||||
|
||||
return i; // both case 10 and -10
|
||||
}
|
||||
|
||||
static void Oof()
|
||||
{
|
||||
}
|
||||
|
||||
[TestCompiler]
|
||||
public static void TryFinallyFirstBlock()
|
||||
{
|
||||
try
|
||||
{
|
||||
}
|
||||
finally
|
||||
{
|
||||
Oof();
|
||||
}
|
||||
}
|
||||
|
||||
static int MagicA(int b, int f, int h, CustomBuffer s)
|
||||
{
|
||||
return b+s.Hash()+f-h;
|
||||
}
|
||||
|
||||
static bool MagicB(int c,out int t)
|
||||
{
|
||||
t = 0;
|
||||
if (c>10)
|
||||
{
|
||||
t = c;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// This test catches an issue with the de-stackifier. (see ILBuilder.cs:1254 (flushStack))
|
||||
// Needs to be unoptimised to trigger
|
||||
[TestCompiler(0)]
|
||||
[TestCompiler(99)]
|
||||
[MethodImpl(MethodImplOptions.NoOptimization | MethodImplOptions.NoInlining)]
|
||||
public static int TryUnbalancedFinally(int i)
|
||||
{
|
||||
// this if is required to force the destackifier to process the final block, before processing the block the contains the endfinally
|
||||
if (i == 99)
|
||||
{
|
||||
return default;
|
||||
}
|
||||
|
||||
int resultB = i;
|
||||
|
||||
using var buffer = new CustomBuffer(32);
|
||||
|
||||
return resultB + MagicA(i,
|
||||
MagicB(i*2, out var r) ? r : default,
|
||||
MagicB(i, out var t) ? t : default,
|
||||
buffer);
|
||||
}
|
||||
|
||||
|
||||
[TestCompiler(-3)]
|
||||
[TestCompiler(0)]
|
||||
[TestCompiler(3)]
|
||||
public static int TryFinallyComplex1(int i)
|
||||
{
|
||||
try
|
||||
{
|
||||
try
|
||||
{
|
||||
if (i == 0)
|
||||
{
|
||||
return i - 1;
|
||||
}
|
||||
|
||||
i += 3;
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (i == 0) // case i: -3
|
||||
{
|
||||
i = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
i = i * 10; // case i: 3
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
i = i * 2; // both -3 and 3
|
||||
}
|
||||
|
||||
return i + 1;
|
||||
}
|
||||
|
||||
[TestCompiler(-10)]
|
||||
[TestCompiler(0)] // case 0
|
||||
[TestCompiler(10)]
|
||||
public static int TryFinallyComplex2(int i)
|
||||
{
|
||||
// First block of nested try/catch
|
||||
try
|
||||
{
|
||||
try
|
||||
{
|
||||
if (i == 0) // case 0
|
||||
{
|
||||
return i - 1;
|
||||
}
|
||||
|
||||
i = i * 2;
|
||||
}
|
||||
finally
|
||||
{
|
||||
i++;
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
i = i * 3;
|
||||
}
|
||||
|
||||
// Second block of nested try/catch
|
||||
try
|
||||
{
|
||||
i = i - 2;
|
||||
|
||||
try
|
||||
{
|
||||
if (i < 0) // case -10
|
||||
{
|
||||
return i * 5;
|
||||
}
|
||||
|
||||
i += 3; // case 10
|
||||
}
|
||||
finally
|
||||
{
|
||||
i += 11;
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
i = i * 3;
|
||||
}
|
||||
|
||||
return i + 1; // case 10
|
||||
}
|
||||
|
||||
|
||||
[TestCompiler(0)]
|
||||
[TestCompiler(1)]
|
||||
[TestCompiler(10)]
|
||||
[TestCompiler(20)]
|
||||
public static int TryFinallyComplex3(int x)
|
||||
{
|
||||
bool k = true;
|
||||
int num = 0;
|
||||
try
|
||||
{
|
||||
while (k)
|
||||
{
|
||||
if (x < 10)
|
||||
{
|
||||
num |= 2;
|
||||
try
|
||||
{
|
||||
if (x == 1) return num;
|
||||
}
|
||||
finally
|
||||
{
|
||||
k = false;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
num |= 1;
|
||||
try
|
||||
{
|
||||
if (x == 20) return num;
|
||||
}
|
||||
finally
|
||||
{
|
||||
k = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
num |= 4;
|
||||
}
|
||||
|
||||
return num;
|
||||
}
|
||||
|
||||
[TestCompiler]
|
||||
public static int TryUsingDispose()
|
||||
{
|
||||
using (var buffer = new CustomBuffer(32))
|
||||
{
|
||||
return buffer.Hash();
|
||||
}
|
||||
}
|
||||
|
||||
[TestCompiler]
|
||||
public static int ForEachTryFinally()
|
||||
{
|
||||
int hashCode = 0;
|
||||
foreach (var value in new RangeEnumerable(1, 100))
|
||||
{
|
||||
hashCode = (hashCode * 397) ^ value;
|
||||
}
|
||||
return hashCode;
|
||||
}
|
||||
|
||||
[TestCompiler(ExpectCompilerException = true, ExpectedDiagnosticId = DiagnosticId.ERR_CatchConstructionNotSupported)]
|
||||
public static int TryCatch()
|
||||
{
|
||||
try
|
||||
{
|
||||
return default(int);
|
||||
}
|
||||
catch (InvalidOperationException)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
private unsafe struct CustomBuffer : IDisposable
|
||||
{
|
||||
private readonly int _size;
|
||||
private byte* _buffer;
|
||||
|
||||
public CustomBuffer(int size)
|
||||
{
|
||||
_size = size;
|
||||
_buffer = (byte*)UnsafeUtility.Malloc(size, 4, Allocator.Persistent);
|
||||
for (int i = 0; i < size; i++)
|
||||
{
|
||||
_buffer[i] = (byte)(i + 1);
|
||||
}
|
||||
}
|
||||
|
||||
public int Hash()
|
||||
{
|
||||
int hashCode = _size;
|
||||
for (int i = 0; i < _size; i++)
|
||||
{
|
||||
hashCode = (hashCode * 397) ^ (byte)_buffer[i];
|
||||
}
|
||||
return hashCode;
|
||||
}
|
||||
|
||||
public unsafe void Dispose()
|
||||
{
|
||||
if (_buffer != null)
|
||||
{
|
||||
UnsafeUtility.Free(_buffer, Allocator.Persistent);
|
||||
_buffer = (byte*) 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private struct RangeEnumerable : IEnumerable<int>
|
||||
{
|
||||
private readonly int _from;
|
||||
private readonly int _to;
|
||||
|
||||
public RangeEnumerable(int from, int to)
|
||||
{
|
||||
_from = @from;
|
||||
_to = to;
|
||||
}
|
||||
|
||||
public Enumerator GetEnumerator()
|
||||
{
|
||||
return new Enumerator();
|
||||
}
|
||||
|
||||
IEnumerator<int> IEnumerable<int>.GetEnumerator()
|
||||
{
|
||||
return GetEnumerator();
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
return GetEnumerator();
|
||||
}
|
||||
|
||||
public struct Enumerator : IEnumerator<int>
|
||||
{
|
||||
private readonly int _from;
|
||||
private readonly int _to;
|
||||
|
||||
public Enumerator(int from, int to)
|
||||
{
|
||||
_from = @from;
|
||||
_to = to;
|
||||
Current = -1;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
// nothing to do
|
||||
}
|
||||
|
||||
public bool MoveNext()
|
||||
{
|
||||
if (Current < 0)
|
||||
{
|
||||
Current = _from;
|
||||
return true;
|
||||
}
|
||||
|
||||
int nextIndex = Current + 1;
|
||||
if (nextIndex >= _from && nextIndex <= _to)
|
||||
{
|
||||
Current = nextIndex;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
}
|
||||
|
||||
public int Current { get; private set; }
|
||||
|
||||
object IEnumerator.Current => Current;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 701a30a4d0f73d51a92f908b568cea9d
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
File diff suppressed because it is too large
Load diff
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 06cc7660b5c739eca022daad2ed2e0a4
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,731 @@
|
|||
// -----------------------------------------------------------
|
||||
// This file was generated automatically from 050-TestStructsLayout.cs
|
||||
// DO NOT EDIT THIS FILE MANUALLY
|
||||
// -----------------------------------------------------------
|
||||
using Unity.Collections.LowLevel.Unsafe;
|
||||
|
||||
namespace Burst.Compiler.IL.Tests
|
||||
{
|
||||
partial class TestStructsLayout
|
||||
{
|
||||
[TestCompiler]
|
||||
public static int Test_CheckHoleInner_Size()
|
||||
{
|
||||
return UnsafeUtility.SizeOf<CheckHoleInner>();
|
||||
}
|
||||
|
||||
[TestCompiler]
|
||||
public static unsafe int Test_CheckHoleInner_FieldOffset_m_Ptr()
|
||||
{
|
||||
var value = new CheckHoleInner();
|
||||
var addressStart = &value;
|
||||
var addressField = &value.m_Ptr;
|
||||
return (int)((byte*)addressField - (byte*)addressStart);
|
||||
}
|
||||
|
||||
// Commented out until upstream IL2CPP bug is fixed
|
||||
#if BURST_TESTS_ONLY
|
||||
[TestCompiler(OverrideOn32BitNative = 20)]
|
||||
public static int Test_CheckHoleOuter_Size()
|
||||
{
|
||||
return UnsafeUtility.SizeOf<CheckHoleOuter>();
|
||||
}
|
||||
#endif
|
||||
|
||||
[TestCompiler]
|
||||
public static unsafe int Test_CheckHoleOuter_FieldOffset_a()
|
||||
{
|
||||
var value = new CheckHoleOuter();
|
||||
var addressStart = &value;
|
||||
var addressField = &value.a;
|
||||
return (int)((byte*)addressField - (byte*)addressStart);
|
||||
}
|
||||
|
||||
[TestCompiler]
|
||||
public static unsafe int Test_CheckHoleOuter_FieldOffset_b()
|
||||
{
|
||||
var value = new CheckHoleOuter();
|
||||
var addressStart = &value;
|
||||
var addressField = &value.b;
|
||||
return (int)((byte*)addressField - (byte*)addressStart);
|
||||
}
|
||||
|
||||
// Commented out until upstream IL2CPP bug is fixed
|
||||
#if BURST_TESTS_ONLY
|
||||
[TestCompiler(OverrideOn32BitNative = 12)]
|
||||
public static unsafe int Test_CheckHoleOuter_FieldOffset_c()
|
||||
{
|
||||
var value = new CheckHoleOuter();
|
||||
var addressStart = &value;
|
||||
var addressField = &value.c;
|
||||
return (int)((byte*)addressField - (byte*)addressStart);
|
||||
}
|
||||
#endif
|
||||
|
||||
[TestCompiler]
|
||||
public static int Test_ExplicitStructWithoutSize2_Size()
|
||||
{
|
||||
return UnsafeUtility.SizeOf<ExplicitStructWithoutSize2>();
|
||||
}
|
||||
|
||||
[TestCompiler]
|
||||
public static unsafe int Test_ExplicitStructWithoutSize2_FieldOffset_a()
|
||||
{
|
||||
var value = new ExplicitStructWithoutSize2();
|
||||
var addressStart = &value;
|
||||
var addressField = &value.a;
|
||||
return (int)((byte*)addressField - (byte*)addressStart);
|
||||
}
|
||||
|
||||
[TestCompiler]
|
||||
public static unsafe int Test_ExplicitStructWithoutSize2_FieldOffset_b()
|
||||
{
|
||||
var value = new ExplicitStructWithoutSize2();
|
||||
var addressStart = &value;
|
||||
var addressField = &value.b;
|
||||
return (int)((byte*)addressField - (byte*)addressStart);
|
||||
}
|
||||
|
||||
[TestCompiler]
|
||||
public static unsafe int Test_ExplicitStructWithoutSize2_FieldOffset_c()
|
||||
{
|
||||
var value = new ExplicitStructWithoutSize2();
|
||||
var addressStart = &value;
|
||||
var addressField = &value.c;
|
||||
return (int)((byte*)addressField - (byte*)addressStart);
|
||||
}
|
||||
|
||||
[TestCompiler]
|
||||
public static int Test_ExplicitStructWithoutSize_Size()
|
||||
{
|
||||
return UnsafeUtility.SizeOf<ExplicitStructWithoutSize>();
|
||||
}
|
||||
|
||||
[TestCompiler]
|
||||
public static unsafe int Test_ExplicitStructWithoutSize_FieldOffset_a()
|
||||
{
|
||||
var value = new ExplicitStructWithoutSize();
|
||||
var addressStart = &value;
|
||||
var addressField = &value.a;
|
||||
return (int)((byte*)addressField - (byte*)addressStart);
|
||||
}
|
||||
|
||||
[TestCompiler]
|
||||
public static unsafe int Test_ExplicitStructWithoutSize_FieldOffset_b()
|
||||
{
|
||||
var value = new ExplicitStructWithoutSize();
|
||||
var addressStart = &value;
|
||||
var addressField = &value.b;
|
||||
return (int)((byte*)addressField - (byte*)addressStart);
|
||||
}
|
||||
|
||||
[TestCompiler]
|
||||
public static unsafe int Test_ExplicitStructWithoutSize_FieldOffset_c()
|
||||
{
|
||||
var value = new ExplicitStructWithoutSize();
|
||||
var addressStart = &value;
|
||||
var addressField = &value.c;
|
||||
return (int)((byte*)addressField - (byte*)addressStart);
|
||||
}
|
||||
|
||||
[TestCompiler]
|
||||
public static int Test_SequentialStructWithSize3_Size()
|
||||
{
|
||||
return UnsafeUtility.SizeOf<SequentialStructWithSize3>();
|
||||
}
|
||||
|
||||
[TestCompiler]
|
||||
public static unsafe int Test_SequentialStructWithSize3_FieldOffset_a()
|
||||
{
|
||||
var value = new SequentialStructWithSize3();
|
||||
var addressStart = &value;
|
||||
var addressField = &value.a;
|
||||
return (int)((byte*)addressField - (byte*)addressStart);
|
||||
}
|
||||
|
||||
[TestCompiler]
|
||||
public static unsafe int Test_SequentialStructWithSize3_FieldOffset_b()
|
||||
{
|
||||
var value = new SequentialStructWithSize3();
|
||||
var addressStart = &value;
|
||||
var addressField = &value.b;
|
||||
return (int)((byte*)addressField - (byte*)addressStart);
|
||||
}
|
||||
|
||||
[TestCompiler]
|
||||
public static unsafe int Test_SequentialStructWithSize3_FieldOffset_c()
|
||||
{
|
||||
var value = new SequentialStructWithSize3();
|
||||
var addressStart = &value;
|
||||
var addressField = &value.c;
|
||||
return (int)((byte*)addressField - (byte*)addressStart);
|
||||
}
|
||||
|
||||
[TestCompiler]
|
||||
public static int Test_SequentialStructWithoutSize_Size()
|
||||
{
|
||||
return UnsafeUtility.SizeOf<SequentialStructWithoutSize>();
|
||||
}
|
||||
|
||||
[TestCompiler]
|
||||
public static unsafe int Test_SequentialStructWithoutSize_FieldOffset_a()
|
||||
{
|
||||
var value = new SequentialStructWithoutSize();
|
||||
var addressStart = &value;
|
||||
var addressField = &value.a;
|
||||
return (int)((byte*)addressField - (byte*)addressStart);
|
||||
}
|
||||
|
||||
[TestCompiler]
|
||||
public static unsafe int Test_SequentialStructWithoutSize_FieldOffset_b()
|
||||
{
|
||||
var value = new SequentialStructWithoutSize();
|
||||
var addressStart = &value;
|
||||
var addressField = &value.b;
|
||||
return (int)((byte*)addressField - (byte*)addressStart);
|
||||
}
|
||||
|
||||
[TestCompiler]
|
||||
public static unsafe int Test_SequentialStructWithoutSize_FieldOffset_c()
|
||||
{
|
||||
var value = new SequentialStructWithoutSize();
|
||||
var addressStart = &value;
|
||||
var addressField = &value.c;
|
||||
return (int)((byte*)addressField - (byte*)addressStart);
|
||||
}
|
||||
|
||||
[TestCompiler]
|
||||
public static int Test_SequentialStructEmptyNoAttributes_Size()
|
||||
{
|
||||
return UnsafeUtility.SizeOf<SequentialStructEmptyNoAttributes>();
|
||||
}
|
||||
|
||||
[TestCompiler]
|
||||
public static int Test_ExplicitStructWithEmptySequentialFields_Size()
|
||||
{
|
||||
return UnsafeUtility.SizeOf<ExplicitStructWithEmptySequentialFields>();
|
||||
}
|
||||
|
||||
[TestCompiler]
|
||||
public static unsafe int Test_ExplicitStructWithEmptySequentialFields_FieldOffset_FieldA()
|
||||
{
|
||||
var value = new ExplicitStructWithEmptySequentialFields();
|
||||
var addressStart = &value;
|
||||
var addressField = &value.FieldA;
|
||||
return (int)((byte*)addressField - (byte*)addressStart);
|
||||
}
|
||||
|
||||
[TestCompiler]
|
||||
public static unsafe int Test_ExplicitStructWithEmptySequentialFields_FieldOffset_FieldB()
|
||||
{
|
||||
var value = new ExplicitStructWithEmptySequentialFields();
|
||||
var addressStart = &value;
|
||||
var addressField = &value.FieldB;
|
||||
return (int)((byte*)addressField - (byte*)addressStart);
|
||||
}
|
||||
|
||||
[TestCompiler]
|
||||
public static int Test_ExplicitStrictWithEmptyAndNonEmptySequentialFields_Size()
|
||||
{
|
||||
return UnsafeUtility.SizeOf<ExplicitStrictWithEmptyAndNonEmptySequentialFields>();
|
||||
}
|
||||
|
||||
[TestCompiler]
|
||||
public static unsafe int Test_ExplicitStrictWithEmptyAndNonEmptySequentialFields_FieldOffset_FieldA()
|
||||
{
|
||||
var value = new ExplicitStrictWithEmptyAndNonEmptySequentialFields();
|
||||
var addressStart = &value;
|
||||
var addressField = &value.FieldA;
|
||||
return (int)((byte*)addressField - (byte*)addressStart);
|
||||
}
|
||||
|
||||
[TestCompiler]
|
||||
public static unsafe int Test_ExplicitStrictWithEmptyAndNonEmptySequentialFields_FieldOffset_FieldB()
|
||||
{
|
||||
var value = new ExplicitStrictWithEmptyAndNonEmptySequentialFields();
|
||||
var addressStart = &value;
|
||||
var addressField = &value.FieldB;
|
||||
return (int)((byte*)addressField - (byte*)addressStart);
|
||||
}
|
||||
|
||||
[TestCompiler]
|
||||
public static int Test_StructWithPack8_Size()
|
||||
{
|
||||
return UnsafeUtility.SizeOf<StructWithPack8>();
|
||||
}
|
||||
|
||||
[TestCompiler]
|
||||
public static unsafe int Test_StructWithPack8_FieldOffset_FieldA()
|
||||
{
|
||||
var value = new StructWithPack8();
|
||||
var addressStart = &value;
|
||||
var addressField = &value.FieldA;
|
||||
return (int)((byte*)addressField - (byte*)addressStart);
|
||||
}
|
||||
|
||||
[TestCompiler]
|
||||
public static unsafe int Test_StructWithPack8_FieldOffset_FieldB()
|
||||
{
|
||||
var value = new StructWithPack8();
|
||||
var addressStart = &value;
|
||||
var addressField = &value.FieldB;
|
||||
return (int)((byte*)addressField - (byte*)addressStart);
|
||||
}
|
||||
|
||||
[TestCompiler]
|
||||
public static int Test_StructPack2WithBytesAndInt_Size()
|
||||
{
|
||||
return UnsafeUtility.SizeOf<StructPack2WithBytesAndInt>();
|
||||
}
|
||||
|
||||
[TestCompiler]
|
||||
public static unsafe int Test_StructPack2WithBytesAndInt_FieldOffset_FieldA()
|
||||
{
|
||||
var value = new StructPack2WithBytesAndInt();
|
||||
var addressStart = &value;
|
||||
var addressField = &value.FieldA;
|
||||
return (int)((byte*)addressField - (byte*)addressStart);
|
||||
}
|
||||
|
||||
[TestCompiler]
|
||||
public static unsafe int Test_StructPack2WithBytesAndInt_FieldOffset_FieldB()
|
||||
{
|
||||
var value = new StructPack2WithBytesAndInt();
|
||||
var addressStart = &value;
|
||||
var addressField = &value.FieldB;
|
||||
return (int)((byte*)addressField - (byte*)addressStart);
|
||||
}
|
||||
|
||||
[TestCompiler]
|
||||
public static unsafe int Test_StructPack2WithBytesAndInt_FieldOffset_FieldC()
|
||||
{
|
||||
var value = new StructPack2WithBytesAndInt();
|
||||
var addressStart = &value;
|
||||
var addressField = &value.FieldC;
|
||||
return (int)((byte*)addressField - (byte*)addressStart);
|
||||
}
|
||||
|
||||
[TestCompiler]
|
||||
public static int Test_StructPack2WithBytesAndInts_Size()
|
||||
{
|
||||
return UnsafeUtility.SizeOf<StructPack2WithBytesAndInts>();
|
||||
}
|
||||
|
||||
[TestCompiler]
|
||||
public static unsafe int Test_StructPack2WithBytesAndInts_FieldOffset_FieldA()
|
||||
{
|
||||
var value = new StructPack2WithBytesAndInts();
|
||||
var addressStart = &value;
|
||||
var addressField = &value.FieldA;
|
||||
return (int)((byte*)addressField - (byte*)addressStart);
|
||||
}
|
||||
|
||||
[TestCompiler]
|
||||
public static unsafe int Test_StructPack2WithBytesAndInts_FieldOffset_FieldB()
|
||||
{
|
||||
var value = new StructPack2WithBytesAndInts();
|
||||
var addressStart = &value;
|
||||
var addressField = &value.FieldB;
|
||||
return (int)((byte*)addressField - (byte*)addressStart);
|
||||
}
|
||||
|
||||
[TestCompiler]
|
||||
public static unsafe int Test_StructPack2WithBytesAndInts_FieldOffset_FieldC()
|
||||
{
|
||||
var value = new StructPack2WithBytesAndInts();
|
||||
var addressStart = &value;
|
||||
var addressField = &value.FieldC;
|
||||
return (int)((byte*)addressField - (byte*)addressStart);
|
||||
}
|
||||
|
||||
[TestCompiler]
|
||||
public static unsafe int Test_StructPack2WithBytesAndInts_FieldOffset_FieldD()
|
||||
{
|
||||
var value = new StructPack2WithBytesAndInts();
|
||||
var addressStart = &value;
|
||||
var addressField = &value.FieldD;
|
||||
return (int)((byte*)addressField - (byte*)addressStart);
|
||||
}
|
||||
|
||||
[TestCompiler]
|
||||
public static int Test_StructPack1WithBytesAndInt_Size()
|
||||
{
|
||||
return UnsafeUtility.SizeOf<StructPack1WithBytesAndInt>();
|
||||
}
|
||||
|
||||
[TestCompiler]
|
||||
public static unsafe int Test_StructPack1WithBytesAndInt_FieldOffset_FieldA()
|
||||
{
|
||||
var value = new StructPack1WithBytesAndInt();
|
||||
var addressStart = &value;
|
||||
var addressField = &value.FieldA;
|
||||
return (int)((byte*)addressField - (byte*)addressStart);
|
||||
}
|
||||
|
||||
[TestCompiler]
|
||||
public static unsafe int Test_StructPack1WithBytesAndInt_FieldOffset_FieldB()
|
||||
{
|
||||
var value = new StructPack1WithBytesAndInt();
|
||||
var addressStart = &value;
|
||||
var addressField = &value.FieldB;
|
||||
return (int)((byte*)addressField - (byte*)addressStart);
|
||||
}
|
||||
|
||||
[TestCompiler]
|
||||
public static unsafe int Test_StructPack1WithBytesAndInt_FieldOffset_FieldC()
|
||||
{
|
||||
var value = new StructPack1WithBytesAndInt();
|
||||
var addressStart = &value;
|
||||
var addressField = &value.FieldC;
|
||||
return (int)((byte*)addressField - (byte*)addressStart);
|
||||
}
|
||||
|
||||
[TestCompiler]
|
||||
public static int Test_StructPack1WithByteAndInt_Size()
|
||||
{
|
||||
return UnsafeUtility.SizeOf<StructPack1WithByteAndInt>();
|
||||
}
|
||||
|
||||
[TestCompiler]
|
||||
public static unsafe int Test_StructPack1WithByteAndInt_FieldOffset_FieldA()
|
||||
{
|
||||
var value = new StructPack1WithByteAndInt();
|
||||
var addressStart = &value;
|
||||
var addressField = &value.FieldA;
|
||||
return (int)((byte*)addressField - (byte*)addressStart);
|
||||
}
|
||||
|
||||
[TestCompiler]
|
||||
public static unsafe int Test_StructPack1WithByteAndInt_FieldOffset_FieldB()
|
||||
{
|
||||
var value = new StructPack1WithByteAndInt();
|
||||
var addressStart = &value;
|
||||
var addressField = &value.FieldB;
|
||||
return (int)((byte*)addressField - (byte*)addressStart);
|
||||
}
|
||||
|
||||
[TestCompiler]
|
||||
public static int Test_StructPack1WithByteAndIntWrapper_Size()
|
||||
{
|
||||
return UnsafeUtility.SizeOf<StructPack1WithByteAndIntWrapper>();
|
||||
}
|
||||
|
||||
[TestCompiler]
|
||||
public static unsafe int Test_StructPack1WithByteAndIntWrapper_FieldOffset_FieldA()
|
||||
{
|
||||
var value = new StructPack1WithByteAndIntWrapper();
|
||||
var addressStart = &value;
|
||||
var addressField = &value.FieldA;
|
||||
return (int)((byte*)addressField - (byte*)addressStart);
|
||||
}
|
||||
|
||||
[TestCompiler]
|
||||
public static unsafe int Test_StructPack1WithByteAndIntWrapper_FieldOffset_FieldB()
|
||||
{
|
||||
var value = new StructPack1WithByteAndIntWrapper();
|
||||
var addressStart = &value;
|
||||
var addressField = &value.FieldB;
|
||||
return (int)((byte*)addressField - (byte*)addressStart);
|
||||
}
|
||||
|
||||
[TestCompiler]
|
||||
public static int Test_StructPack1WithByteAndIntWrapper2_Size()
|
||||
{
|
||||
return UnsafeUtility.SizeOf<StructPack1WithByteAndIntWrapper2>();
|
||||
}
|
||||
|
||||
[TestCompiler]
|
||||
public static unsafe int Test_StructPack1WithByteAndIntWrapper2_FieldOffset_FieldA()
|
||||
{
|
||||
var value = new StructPack1WithByteAndIntWrapper2();
|
||||
var addressStart = &value;
|
||||
var addressField = &value.FieldA;
|
||||
return (int)((byte*)addressField - (byte*)addressStart);
|
||||
}
|
||||
|
||||
[TestCompiler]
|
||||
public static unsafe int Test_StructPack1WithByteAndIntWrapper2_FieldOffset_FieldB()
|
||||
{
|
||||
var value = new StructPack1WithByteAndIntWrapper2();
|
||||
var addressStart = &value;
|
||||
var addressField = &value.FieldB;
|
||||
return (int)((byte*)addressField - (byte*)addressStart);
|
||||
}
|
||||
|
||||
[TestCompiler]
|
||||
public static int Test_StructWithSizeAndPack_Size()
|
||||
{
|
||||
return UnsafeUtility.SizeOf<StructWithSizeAndPack>();
|
||||
}
|
||||
|
||||
[TestCompiler]
|
||||
public static unsafe int Test_StructWithSizeAndPack_FieldOffset_FieldA()
|
||||
{
|
||||
var value = new StructWithSizeAndPack();
|
||||
var addressStart = &value;
|
||||
var addressField = &value.FieldA;
|
||||
return (int)((byte*)addressField - (byte*)addressStart);
|
||||
}
|
||||
|
||||
[TestCompiler]
|
||||
public static unsafe int Test_StructWithSizeAndPack_FieldOffset_FieldB()
|
||||
{
|
||||
var value = new StructWithSizeAndPack();
|
||||
var addressStart = &value;
|
||||
var addressField = &value.FieldB;
|
||||
return (int)((byte*)addressField - (byte*)addressStart);
|
||||
}
|
||||
|
||||
[TestCompiler]
|
||||
public static int Test_StructWithSizeAndPackWrapper_Size()
|
||||
{
|
||||
return UnsafeUtility.SizeOf<StructWithSizeAndPackWrapper>();
|
||||
}
|
||||
|
||||
[TestCompiler]
|
||||
public static unsafe int Test_StructWithSizeAndPackWrapper_FieldOffset_FieldA()
|
||||
{
|
||||
var value = new StructWithSizeAndPackWrapper();
|
||||
var addressStart = &value;
|
||||
var addressField = &value.FieldA;
|
||||
return (int)((byte*)addressField - (byte*)addressStart);
|
||||
}
|
||||
|
||||
[TestCompiler]
|
||||
public static unsafe int Test_StructWithSizeAndPackWrapper_FieldOffset_FieldB()
|
||||
{
|
||||
var value = new StructWithSizeAndPackWrapper();
|
||||
var addressStart = &value;
|
||||
var addressField = &value.FieldB;
|
||||
return (int)((byte*)addressField - (byte*)addressStart);
|
||||
}
|
||||
|
||||
[TestCompiler]
|
||||
public static int Test_StructWithSizeAndPack4_Size()
|
||||
{
|
||||
return UnsafeUtility.SizeOf<StructWithSizeAndPack4>();
|
||||
}
|
||||
|
||||
[TestCompiler]
|
||||
public static unsafe int Test_StructWithSizeAndPack4_FieldOffset_FieldA()
|
||||
{
|
||||
var value = new StructWithSizeAndPack4();
|
||||
var addressStart = &value;
|
||||
var addressField = &value.FieldA;
|
||||
return (int)((byte*)addressField - (byte*)addressStart);
|
||||
}
|
||||
|
||||
[TestCompiler]
|
||||
public static unsafe int Test_StructWithSizeAndPack4_FieldOffset_FieldB()
|
||||
{
|
||||
var value = new StructWithSizeAndPack4();
|
||||
var addressStart = &value;
|
||||
var addressField = &value.FieldB;
|
||||
return (int)((byte*)addressField - (byte*)addressStart);
|
||||
}
|
||||
|
||||
// Commented out until upstream IL2CPP bug is fixed
|
||||
#if BURST_TESTS_ONLY
|
||||
[TestCompiler]
|
||||
public static int Test_StructWithSizeAndPack4Wrapper_Size()
|
||||
{
|
||||
return UnsafeUtility.SizeOf<StructWithSizeAndPack4Wrapper>();
|
||||
}
|
||||
#endif
|
||||
|
||||
[TestCompiler]
|
||||
public static unsafe int Test_StructWithSizeAndPack4Wrapper_FieldOffset_FieldA()
|
||||
{
|
||||
var value = new StructWithSizeAndPack4Wrapper();
|
||||
var addressStart = &value;
|
||||
var addressField = &value.FieldA;
|
||||
return (int)((byte*)addressField - (byte*)addressStart);
|
||||
}
|
||||
|
||||
// Commented out until upstream IL2CPP bug is fixed
|
||||
#if BURST_TESTS_ONLY
|
||||
[TestCompiler]
|
||||
public static unsafe int Test_StructWithSizeAndPack4Wrapper_FieldOffset_FieldB()
|
||||
{
|
||||
var value = new StructWithSizeAndPack4Wrapper();
|
||||
var addressStart = &value;
|
||||
var addressField = &value.FieldB;
|
||||
return (int)((byte*)addressField - (byte*)addressStart);
|
||||
}
|
||||
#endif
|
||||
|
||||
[TestCompiler]
|
||||
public static int Test_StructExplicitPack1WithByteAndInt_Size()
|
||||
{
|
||||
return UnsafeUtility.SizeOf<StructExplicitPack1WithByteAndInt>();
|
||||
}
|
||||
|
||||
[TestCompiler]
|
||||
public static unsafe int Test_StructExplicitPack1WithByteAndInt_FieldOffset_FieldA()
|
||||
{
|
||||
var value = new StructExplicitPack1WithByteAndInt();
|
||||
var addressStart = &value;
|
||||
var addressField = &value.FieldA;
|
||||
return (int)((byte*)addressField - (byte*)addressStart);
|
||||
}
|
||||
|
||||
[TestCompiler]
|
||||
public static unsafe int Test_StructExplicitPack1WithByteAndInt_FieldOffset_FieldB()
|
||||
{
|
||||
var value = new StructExplicitPack1WithByteAndInt();
|
||||
var addressStart = &value;
|
||||
var addressField = &value.FieldB;
|
||||
return (int)((byte*)addressField - (byte*)addressStart);
|
||||
}
|
||||
|
||||
[TestCompiler]
|
||||
public static int Test_StructExplicitPack1WithByteAndIntWrapper_Size()
|
||||
{
|
||||
return UnsafeUtility.SizeOf<StructExplicitPack1WithByteAndIntWrapper>();
|
||||
}
|
||||
|
||||
[TestCompiler]
|
||||
public static unsafe int Test_StructExplicitPack1WithByteAndIntWrapper_FieldOffset_FieldA()
|
||||
{
|
||||
var value = new StructExplicitPack1WithByteAndIntWrapper();
|
||||
var addressStart = &value;
|
||||
var addressField = &value.FieldA;
|
||||
return (int)((byte*)addressField - (byte*)addressStart);
|
||||
}
|
||||
|
||||
[TestCompiler]
|
||||
public static unsafe int Test_StructExplicitPack1WithByteAndIntWrapper_FieldOffset_FieldB()
|
||||
{
|
||||
var value = new StructExplicitPack1WithByteAndIntWrapper();
|
||||
var addressStart = &value;
|
||||
var addressField = &value.FieldB;
|
||||
return (int)((byte*)addressField - (byte*)addressStart);
|
||||
}
|
||||
|
||||
[TestCompiler]
|
||||
public static int Test_StructExplicitPack1WithByteAndIntWrapper2_Size()
|
||||
{
|
||||
return UnsafeUtility.SizeOf<StructExplicitPack1WithByteAndIntWrapper2>();
|
||||
}
|
||||
|
||||
[TestCompiler]
|
||||
public static unsafe int Test_StructExplicitPack1WithByteAndIntWrapper2_FieldOffset_FieldA()
|
||||
{
|
||||
var value = new StructExplicitPack1WithByteAndIntWrapper2();
|
||||
var addressStart = &value;
|
||||
var addressField = &value.FieldA;
|
||||
return (int)((byte*)addressField - (byte*)addressStart);
|
||||
}
|
||||
|
||||
[TestCompiler]
|
||||
public static unsafe int Test_StructExplicitPack1WithByteAndIntWrapper2_FieldOffset_FieldB()
|
||||
{
|
||||
var value = new StructExplicitPack1WithByteAndIntWrapper2();
|
||||
var addressStart = &value;
|
||||
var addressField = &value.FieldB;
|
||||
return (int)((byte*)addressField - (byte*)addressStart);
|
||||
}
|
||||
|
||||
[TestCompiler]
|
||||
public static int Test_StructExplicitWithSizeAndPack_Size()
|
||||
{
|
||||
return UnsafeUtility.SizeOf<StructExplicitWithSizeAndPack>();
|
||||
}
|
||||
|
||||
[TestCompiler]
|
||||
public static unsafe int Test_StructExplicitWithSizeAndPack_FieldOffset_FieldA()
|
||||
{
|
||||
var value = new StructExplicitWithSizeAndPack();
|
||||
var addressStart = &value;
|
||||
var addressField = &value.FieldA;
|
||||
return (int)((byte*)addressField - (byte*)addressStart);
|
||||
}
|
||||
|
||||
[TestCompiler]
|
||||
public static unsafe int Test_StructExplicitWithSizeAndPack_FieldOffset_FieldB()
|
||||
{
|
||||
var value = new StructExplicitWithSizeAndPack();
|
||||
var addressStart = &value;
|
||||
var addressField = &value.FieldB;
|
||||
return (int)((byte*)addressField - (byte*)addressStart);
|
||||
}
|
||||
|
||||
[TestCompiler]
|
||||
public static int Test_StructExplicitWithSizeAndPackWrapper_Size()
|
||||
{
|
||||
return UnsafeUtility.SizeOf<StructExplicitWithSizeAndPackWrapper>();
|
||||
}
|
||||
|
||||
[TestCompiler]
|
||||
public static unsafe int Test_StructExplicitWithSizeAndPackWrapper_FieldOffset_FieldA()
|
||||
{
|
||||
var value = new StructExplicitWithSizeAndPackWrapper();
|
||||
var addressStart = &value;
|
||||
var addressField = &value.FieldA;
|
||||
return (int)((byte*)addressField - (byte*)addressStart);
|
||||
}
|
||||
|
||||
[TestCompiler]
|
||||
public static unsafe int Test_StructExplicitWithSizeAndPackWrapper_FieldOffset_FieldB()
|
||||
{
|
||||
var value = new StructExplicitWithSizeAndPackWrapper();
|
||||
var addressStart = &value;
|
||||
var addressField = &value.FieldB;
|
||||
return (int)((byte*)addressField - (byte*)addressStart);
|
||||
}
|
||||
|
||||
[TestCompiler]
|
||||
public static int Test_StructExplicitWithSizeAndPack4_Size()
|
||||
{
|
||||
return UnsafeUtility.SizeOf<StructExplicitWithSizeAndPack4>();
|
||||
}
|
||||
|
||||
[TestCompiler]
|
||||
public static unsafe int Test_StructExplicitWithSizeAndPack4_FieldOffset_FieldA()
|
||||
{
|
||||
var value = new StructExplicitWithSizeAndPack4();
|
||||
var addressStart = &value;
|
||||
var addressField = &value.FieldA;
|
||||
return (int)((byte*)addressField - (byte*)addressStart);
|
||||
}
|
||||
|
||||
[TestCompiler]
|
||||
public static unsafe int Test_StructExplicitWithSizeAndPack4_FieldOffset_FieldB()
|
||||
{
|
||||
var value = new StructExplicitWithSizeAndPack4();
|
||||
var addressStart = &value;
|
||||
var addressField = &value.FieldB;
|
||||
return (int)((byte*)addressField - (byte*)addressStart);
|
||||
}
|
||||
|
||||
// Commented out until upstream IL2CPP bug is fixed
|
||||
#if BURST_TESTS_ONLY
|
||||
[TestCompiler]
|
||||
public static int Test_StructExplicitWithSizeAndPack4Wrapper_Size()
|
||||
{
|
||||
return UnsafeUtility.SizeOf<StructExplicitWithSizeAndPack4Wrapper>();
|
||||
}
|
||||
#endif
|
||||
|
||||
[TestCompiler]
|
||||
public static unsafe int Test_StructExplicitWithSizeAndPack4Wrapper_FieldOffset_FieldA()
|
||||
{
|
||||
var value = new StructExplicitWithSizeAndPack4Wrapper();
|
||||
var addressStart = &value;
|
||||
var addressField = &value.FieldA;
|
||||
return (int)((byte*)addressField - (byte*)addressStart);
|
||||
}
|
||||
|
||||
// Commented out until upstream IL2CPP bug is fixed
|
||||
#if BURST_TESTS_ONLY
|
||||
[TestCompiler]
|
||||
public static unsafe int Test_StructExplicitWithSizeAndPack4Wrapper_FieldOffset_FieldB()
|
||||
{
|
||||
var value = new StructExplicitWithSizeAndPack4Wrapper();
|
||||
var addressStart = &value;
|
||||
var addressField = &value.FieldB;
|
||||
return (int)((byte*)addressField - (byte*)addressStart);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 10c2b0100e723deab40f35dc43e40cd5
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,248 @@
|
|||
// NOTE: Please read this before adding or changing anything in this file.
|
||||
//
|
||||
// This file doesn't contain any actual tests. It only contains structs.
|
||||
// Tests are automatically generated from all structs in this file,
|
||||
// which test:
|
||||
// - the size of the struct
|
||||
// - the offsets of each field
|
||||
//
|
||||
// When a struct contains a pointer, the test needs to use
|
||||
// OverrideOn32BitNative so that wasm tests can compare with the correct
|
||||
// values when testing 32-bit wasm on a 64-bit host platform.
|
||||
// While it would be possible to use Roslyn to calculate these
|
||||
// values automatically, for simplicity we use a couple of
|
||||
// generator-specific attributes to set these manually:
|
||||
// - [TestGeneratorOverride32BitSize(20)] should be set on a struct
|
||||
// - [TestGeneratorOverride32BitOffset(12)] should be set on a field
|
||||
// See the file below for examples.
|
||||
//
|
||||
// The test generation code lives in Burst.Compiler.IL.Tests.CodeGen.
|
||||
// After making changes to this file, please run that project.
|
||||
//
|
||||
// The generated tests are in 050-TestStructsLayout.Generated.cs.
|
||||
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Burst.Compiler.IL.Tests
|
||||
{
|
||||
partial class TestStructsLayout
|
||||
{
|
||||
[StructLayout(LayoutKind.Explicit, Size = 8)]
|
||||
private unsafe struct CheckHoleInner
|
||||
{
|
||||
[FieldOffset(0)]
|
||||
public byte* m_Ptr;
|
||||
}
|
||||
|
||||
[TestGeneratorOverride32BitSize(20)]
|
||||
private struct CheckHoleOuter
|
||||
{
|
||||
public CheckHoleInner a;
|
||||
public int b;
|
||||
[TestGeneratorOverride32BitOffset(12)]
|
||||
public CheckHoleInner c;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Explicit)]
|
||||
private struct ExplicitStructWithoutSize2
|
||||
{
|
||||
[FieldOffset(0)] public long a;
|
||||
[FieldOffset(8)] public sbyte b;
|
||||
[FieldOffset(9)] public int c;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Explicit)]
|
||||
private struct ExplicitStructWithoutSize
|
||||
{
|
||||
[FieldOffset(0)] public int a;
|
||||
[FieldOffset(4)] public sbyte b;
|
||||
[FieldOffset(5)] public int c;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Size = 12)]
|
||||
private struct SequentialStructWithSize3
|
||||
{
|
||||
public int a;
|
||||
public int b;
|
||||
public sbyte c;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
private struct SequentialStructWithoutSize
|
||||
{
|
||||
public int a;
|
||||
public int b;
|
||||
public sbyte c;
|
||||
}
|
||||
|
||||
private struct SequentialStructEmptyNoAttributes { }
|
||||
|
||||
[StructLayout(LayoutKind.Explicit)]
|
||||
private struct ExplicitStructWithEmptySequentialFields
|
||||
{
|
||||
[FieldOffset(0)] public SequentialStructEmptyNoAttributes FieldA;
|
||||
[FieldOffset(0)] public SequentialStructEmptyNoAttributes FieldB;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Explicit)]
|
||||
private struct ExplicitStrictWithEmptyAndNonEmptySequentialFields
|
||||
{
|
||||
[FieldOffset(0)] public SequentialStructEmptyNoAttributes FieldA;
|
||||
[FieldOffset(0)] public SequentialStructWithoutSize FieldB;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 8)]
|
||||
private struct StructWithPack8
|
||||
{
|
||||
public int FieldA;
|
||||
public int FieldB;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 2)]
|
||||
private struct StructPack2WithBytesAndInt
|
||||
{
|
||||
public byte FieldA;
|
||||
public byte FieldB;
|
||||
public int FieldC;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 2)]
|
||||
private struct StructPack2WithBytesAndInts
|
||||
{
|
||||
public byte FieldA;
|
||||
public byte FieldB;
|
||||
public int FieldC;
|
||||
public int FieldD;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
private struct StructPack1WithBytesAndInt
|
||||
{
|
||||
public byte FieldA;
|
||||
public byte FieldB;
|
||||
public int FieldC;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
private struct StructPack1WithByteAndInt
|
||||
{
|
||||
public byte FieldA;
|
||||
public int FieldB;
|
||||
}
|
||||
|
||||
private struct StructPack1WithByteAndIntWrapper
|
||||
{
|
||||
public StructPack1WithByteAndInt FieldA;
|
||||
public StructPack1WithByteAndInt FieldB;
|
||||
}
|
||||
|
||||
private struct StructPack1WithByteAndIntWrapper2
|
||||
{
|
||||
public StructPack1WithByteAndIntWrapper FieldA;
|
||||
public StructPack1WithByteAndIntWrapper FieldB;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Size = 12, Pack = 1)]
|
||||
private struct StructWithSizeAndPack
|
||||
{
|
||||
public double FieldA;
|
||||
public int FieldB;
|
||||
}
|
||||
|
||||
private struct StructWithSizeAndPackWrapper
|
||||
{
|
||||
public byte FieldA;
|
||||
public StructWithSizeAndPack FieldB;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Explicit, Size = 12, Pack = 4)]
|
||||
private struct StructWithSizeAndPack4
|
||||
{
|
||||
[FieldOffset(0)]
|
||||
public double FieldA;
|
||||
[FieldOffset(8)]
|
||||
public int FieldB;
|
||||
}
|
||||
|
||||
private struct StructWithSizeAndPack4Wrapper
|
||||
{
|
||||
public byte FieldA;
|
||||
public StructWithSizeAndPack4 FieldB;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Explicit, Pack = 1)]
|
||||
private struct StructExplicitPack1WithByteAndInt
|
||||
{
|
||||
[FieldOffset(0)]
|
||||
public byte FieldA;
|
||||
|
||||
[FieldOffset(1)]
|
||||
public int FieldB;
|
||||
}
|
||||
|
||||
private struct StructExplicitPack1WithByteAndIntWrapper
|
||||
{
|
||||
public StructExplicitPack1WithByteAndInt FieldA;
|
||||
public StructExplicitPack1WithByteAndInt FieldB;
|
||||
}
|
||||
|
||||
private struct StructExplicitPack1WithByteAndIntWrapper2
|
||||
{
|
||||
public StructExplicitPack1WithByteAndIntWrapper FieldA;
|
||||
public StructExplicitPack1WithByteAndIntWrapper FieldB;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Explicit, Size = 12, Pack = 1)]
|
||||
private struct StructExplicitWithSizeAndPack
|
||||
{
|
||||
[FieldOffset(0)]
|
||||
public double FieldA;
|
||||
[FieldOffset(8)]
|
||||
public int FieldB;
|
||||
}
|
||||
|
||||
private struct StructExplicitWithSizeAndPackWrapper
|
||||
{
|
||||
public byte FieldA;
|
||||
public StructExplicitWithSizeAndPack FieldB;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Explicit, Size = 12, Pack = 4)]
|
||||
private struct StructExplicitWithSizeAndPack4
|
||||
{
|
||||
[FieldOffset(0)]
|
||||
public double FieldA;
|
||||
[FieldOffset(8)]
|
||||
public int FieldB;
|
||||
}
|
||||
|
||||
private struct StructExplicitWithSizeAndPack4Wrapper
|
||||
{
|
||||
public byte FieldA;
|
||||
public StructExplicitWithSizeAndPack4 FieldB;
|
||||
}
|
||||
}
|
||||
|
||||
[AttributeUsage(AttributeTargets.Struct)]
|
||||
internal sealed class TestGeneratorOverride32BitSizeAttribute : Attribute
|
||||
{
|
||||
public readonly int Size;
|
||||
|
||||
public TestGeneratorOverride32BitSizeAttribute(int size)
|
||||
{
|
||||
Size = size;
|
||||
}
|
||||
}
|
||||
|
||||
[AttributeUsage(AttributeTargets.Field)]
|
||||
internal sealed class TestGeneratorOverride32BitOffsetAttribute : Attribute
|
||||
{
|
||||
public readonly int Offset;
|
||||
|
||||
public TestGeneratorOverride32BitOffsetAttribute(int offset)
|
||||
{
|
||||
Offset = offset;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 828266174e573a6da71055ba8f017778
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
File diff suppressed because it is too large
Load diff
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 5eb3e1cf0e2a3614927c245069c69baf
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,183 @@
|
|||
|
||||
using UnityBenchShared;
|
||||
|
||||
namespace Burst.Compiler.IL.Tests
|
||||
{
|
||||
internal class TestFixed
|
||||
{
|
||||
public unsafe struct SomeStruct
|
||||
{
|
||||
public static readonly int[] Ints = new int[4] { 1, 2, 3, 4 };
|
||||
|
||||
public struct OtherStruct
|
||||
{
|
||||
public int x;
|
||||
}
|
||||
|
||||
public static readonly OtherStruct[] Structs = new OtherStruct[2] { new OtherStruct { x = 42 }, new OtherStruct { x = 13 } };
|
||||
|
||||
public fixed ushort array[42];
|
||||
|
||||
public struct Provider : IArgumentProvider
|
||||
{
|
||||
public object Value
|
||||
{
|
||||
get
|
||||
{
|
||||
var s = new SomeStruct();
|
||||
|
||||
for (ushort i = 0; i < 42; i++)
|
||||
{
|
||||
s.array[i] = i;
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[TestCompiler]
|
||||
public static unsafe int ReadInts()
|
||||
{
|
||||
fixed (int* ptr = SomeStruct.Ints)
|
||||
{
|
||||
return ptr[2];
|
||||
}
|
||||
}
|
||||
|
||||
[TestCompiler]
|
||||
public static unsafe int ReadIntsElement()
|
||||
{
|
||||
fixed (int* ptr = &SomeStruct.Ints[1])
|
||||
{
|
||||
return ptr[0];
|
||||
}
|
||||
}
|
||||
|
||||
[TestCompiler]
|
||||
public static unsafe int ReadStructs()
|
||||
{
|
||||
fixed (SomeStruct.OtherStruct* ptr = SomeStruct.Structs)
|
||||
{
|
||||
return ptr[1].x;
|
||||
}
|
||||
}
|
||||
|
||||
[TestCompiler]
|
||||
public static unsafe int ReadStructsElement()
|
||||
{
|
||||
fixed (SomeStruct.OtherStruct* ptr = &SomeStruct.Structs[1])
|
||||
{
|
||||
return ptr[0].x;
|
||||
}
|
||||
}
|
||||
|
||||
[TestCompiler(typeof(SomeStruct.Provider))]
|
||||
public static unsafe ushort ReadFromFixedArray(ref SomeStruct s)
|
||||
{
|
||||
fixed (ushort* ptr = s.array)
|
||||
{
|
||||
ushort total = 0;
|
||||
|
||||
for (ushort i = 0; i < 42; i++)
|
||||
{
|
||||
total += ptr[i];
|
||||
}
|
||||
|
||||
return total;
|
||||
}
|
||||
}
|
||||
|
||||
// The below tests are designed to verify the indexer is treated correctly for various fixed arrays (only the smallest case)
|
||||
//(the bug was actually to do with pointer addition, so see 031-Pointer.cs for additional coverage)
|
||||
//Its not perfect as if the indexer is treated as signed, then in burst we will read off the beginning of the array
|
||||
//which might be into another array or off the beginning of the struct... and the value might accidently be correct.
|
||||
public unsafe struct IndexerStructTestSByte
|
||||
{
|
||||
public fixed sbyte sbyteArray[256];
|
||||
|
||||
public struct Provider : IArgumentProvider
|
||||
{
|
||||
public object Value
|
||||
{
|
||||
get
|
||||
{
|
||||
var s = new IndexerStructTestSByte();
|
||||
|
||||
for (int a=0;a<256;a++)
|
||||
{
|
||||
s.sbyteArray[a] = sbyte.MinValue;
|
||||
}
|
||||
|
||||
s.sbyteArray[127] = 127;
|
||||
s.sbyteArray[128] = 63;
|
||||
s.sbyteArray[255] = 23;
|
||||
|
||||
return s;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
public unsafe struct IndexerStructTestByte
|
||||
{
|
||||
public fixed byte byteArray[256];
|
||||
|
||||
public struct Provider : IArgumentProvider
|
||||
{
|
||||
public object Value
|
||||
{
|
||||
get
|
||||
{
|
||||
var s = new IndexerStructTestByte();
|
||||
|
||||
for (int a=0;a<256;a++)
|
||||
{
|
||||
s.byteArray[a] = byte.MinValue;
|
||||
}
|
||||
|
||||
s.byteArray[127] = 129;
|
||||
s.byteArray[128] = 212;
|
||||
s.byteArray[255] = 165;
|
||||
|
||||
return s;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// SByte array with different indexer types
|
||||
[TestCompiler(typeof(IndexerStructTestSByte.Provider),(byte)0)]
|
||||
[TestCompiler(typeof(IndexerStructTestSByte.Provider),(byte)128)]
|
||||
[TestCompiler(typeof(IndexerStructTestSByte.Provider),(byte)255)]
|
||||
public static unsafe sbyte IndexerReadFromSByteArrayWithByteOffset(ref IndexerStructTestSByte s, byte offset)
|
||||
{
|
||||
return s.sbyteArray[offset];
|
||||
}
|
||||
|
||||
[TestCompiler(typeof(IndexerStructTestSByte.Provider),(sbyte)0)]
|
||||
[TestCompiler(typeof(IndexerStructTestSByte.Provider),(sbyte)127)] // signed offset so limited
|
||||
public static unsafe sbyte IndexerReadFromSByteArrayWithSByteOffset(ref IndexerStructTestSByte s, sbyte offset)
|
||||
{
|
||||
return s.sbyteArray[offset];
|
||||
}
|
||||
|
||||
// Byte array with different indexer types
|
||||
[TestCompiler(typeof(IndexerStructTestByte.Provider),(byte)0)]
|
||||
[TestCompiler(typeof(IndexerStructTestByte.Provider),(byte)128)]
|
||||
[TestCompiler(typeof(IndexerStructTestByte.Provider),(byte)255)]
|
||||
public static unsafe byte IndexerReadFromByteArrayWithByteOffset(ref IndexerStructTestByte s, byte offset)
|
||||
{
|
||||
return s.byteArray[offset];
|
||||
}
|
||||
|
||||
[TestCompiler(typeof(IndexerStructTestByte.Provider),(sbyte)0)]
|
||||
[TestCompiler(typeof(IndexerStructTestByte.Provider),(sbyte)127)] // signed offset so limited
|
||||
public static unsafe byte IndexerReadFromByteArrayWithSByteOffset(ref IndexerStructTestByte s, sbyte offset)
|
||||
{
|
||||
return s.byteArray[offset];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 36990957b5d73a9681ce7dd9f4d5a7b0
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,313 @@
|
|||
using NUnit.Framework;
|
||||
using Unity.Burst;
|
||||
using Unity.Mathematics;
|
||||
|
||||
namespace Burst.Compiler.IL.Tests
|
||||
{
|
||||
internal class TestConstArrays
|
||||
{
|
||||
[TestCompiler]
|
||||
public static int ReadFromIntArray()
|
||||
{
|
||||
return StructWithConstArray1.IntValues[1];
|
||||
}
|
||||
|
||||
[TestCompiler]
|
||||
public static unsafe int ReadViaFixed()
|
||||
{
|
||||
fixed (int* ptr = StructWithConstArray1.IntValues)
|
||||
{
|
||||
return ptr[2];
|
||||
}
|
||||
}
|
||||
|
||||
[TestCompiler]
|
||||
public static int ReadFromColorArray()
|
||||
{
|
||||
var color = StructWithConstArrayWithStruct1.Colors[1];
|
||||
return ((color.R * 255) + color.G) * 255 + color.B;
|
||||
}
|
||||
|
||||
[TestCompiler]
|
||||
public static int ReadFromColorArray2()
|
||||
{
|
||||
var color = StaticArrayStruct.Colors[1];
|
||||
return ((color.R * 255) + color.G) * 255 + color.B;
|
||||
}
|
||||
|
||||
struct StructWithConstArray1
|
||||
{
|
||||
public static readonly int[] IntValues = new int[4] { 1, 2, 3, 4 };
|
||||
}
|
||||
|
||||
struct StructWithConstArrayWithStruct1
|
||||
{
|
||||
public static readonly Color[] Colors = { new Color(), new Color(1, 2, 3, 255) };
|
||||
}
|
||||
|
||||
private struct Color
|
||||
{
|
||||
public Color(byte r, byte g, byte b, byte a)
|
||||
{
|
||||
R = r;
|
||||
G = g;
|
||||
B = b;
|
||||
A = a;
|
||||
}
|
||||
|
||||
public byte R, G, B, A;
|
||||
}
|
||||
|
||||
private struct StaticArrayStruct
|
||||
{
|
||||
public static readonly double[] Doubles = { 3, 6, 9, 42, 43 };
|
||||
public static readonly byte[] Bytes = { 1, 2, 3 };
|
||||
public static readonly ushort[] UShorts = { 2, 6, 8, 2, 0 };
|
||||
public static readonly int[] Ints = { -6, 6, 50 };
|
||||
public static readonly int[] ZeroData = { 0, 0, 0, 0 };
|
||||
public static readonly int[] ZeroLength = { };
|
||||
public static readonly Color[] ZeroLengthStruct = { };
|
||||
public static readonly Color[] Colors = { new Color(), new Color(1, 2, 3, 255) };
|
||||
public static readonly int3[] Positions = { new int3(0, 0, 1), new int3(0, 1, 0), new int3(1, 0, 0) };
|
||||
}
|
||||
|
||||
[TestCompiler]
|
||||
public static int TestStaticReadonlyArrayLength()
|
||||
{
|
||||
return StaticArrayStruct.Doubles.Length + StaticArrayStruct.Bytes.Length +
|
||||
StaticArrayStruct.UShorts.Length + StaticArrayStruct.Ints.Length +
|
||||
StaticArrayStruct.ZeroData.Length + StaticArrayStruct.ZeroLength.Length +
|
||||
StaticArrayStruct.ZeroLengthStruct.Length + StaticArrayStruct.Colors.Length +
|
||||
StaticArrayStruct.Positions.Length;
|
||||
}
|
||||
|
||||
private struct StructP
|
||||
{
|
||||
public static readonly int[] Value = new int[One()];
|
||||
|
||||
public static int One()
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
[TestCompiler]
|
||||
public static int TestStaticReadonlyArrayNonConstantLength()
|
||||
{
|
||||
return StructP.Value.Length;
|
||||
}
|
||||
|
||||
private struct StructQ
|
||||
{
|
||||
public static readonly int[] Value = new int[10];
|
||||
|
||||
public static int One()
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
static StructQ()
|
||||
{
|
||||
Value[One()] = 1;
|
||||
}
|
||||
}
|
||||
|
||||
[TestCompiler]
|
||||
public static int TestStaticReadonlyArrayWithNonConstantStelemIndex()
|
||||
{
|
||||
return StructQ.Value[1];
|
||||
}
|
||||
|
||||
private struct StructR
|
||||
{
|
||||
#pragma warning disable 0649
|
||||
public static int[] Value;
|
||||
#pragma warning restore 0649
|
||||
|
||||
static StructR()
|
||||
{
|
||||
Value[0] = 1;
|
||||
}
|
||||
}
|
||||
|
||||
[TestCompiler(ExpectCompilerException = true, ExpectedDiagnosticId = DiagnosticId.ERR_LoadingFromManagedNonReadonlyStaticFieldNotSupported)]
|
||||
public static int TestStaticReadonlyArrayExplicitConstructionOfUninitialized()
|
||||
{
|
||||
return StructR.Value.Length;
|
||||
}
|
||||
|
||||
private struct StructS
|
||||
{
|
||||
public static readonly int[] Value = new int[10];
|
||||
|
||||
static StructS()
|
||||
{
|
||||
Value[0] = 1;
|
||||
Value[1] = 2;
|
||||
Value[2] = 8;
|
||||
Value[3] = 2;
|
||||
Value[4] = 0;
|
||||
Value[5] = 2;
|
||||
Value[6] = 1;
|
||||
Value[7] = 2;
|
||||
Value[8] = 2;
|
||||
Value[9] = 3;
|
||||
}
|
||||
}
|
||||
|
||||
[TestCompiler]
|
||||
public static int TestStaticReadonlyArrayExplicitConstruction()
|
||||
{
|
||||
int sum = 0;
|
||||
for (int i = 0; i < 10; i++) sum += StructS.Value[i];
|
||||
return sum;
|
||||
}
|
||||
|
||||
[TestCompiler]
|
||||
public static int TestStaticReadonlyArrayLdelem()
|
||||
{
|
||||
var doubles = StaticArrayStruct.Doubles[0];
|
||||
for (int i = 1; i < StaticArrayStruct.Doubles.Length; i++) doubles += StaticArrayStruct.Doubles[i];
|
||||
|
||||
var bytes = StaticArrayStruct.Bytes[0];
|
||||
for (int i = 1; i < StaticArrayStruct.Bytes.Length; i++) bytes += StaticArrayStruct.Bytes[i];
|
||||
|
||||
var ushorts = StaticArrayStruct.UShorts[0];
|
||||
for (int i = 1; i < StaticArrayStruct.UShorts.Length; i++) ushorts += StaticArrayStruct.UShorts[i];
|
||||
|
||||
var ints = StaticArrayStruct.Ints[0];
|
||||
for (int i = 1; i < StaticArrayStruct.Ints.Length; i++) ints += StaticArrayStruct.Ints[i];
|
||||
|
||||
ints += StaticArrayStruct.ZeroData[0];
|
||||
for (int i = 1; i < StaticArrayStruct.ZeroData.Length; i++) ints += StaticArrayStruct.ZeroData[i];
|
||||
|
||||
for (int i = 0; i < StaticArrayStruct.ZeroLength.Length; i++) doubles += StaticArrayStruct.ZeroLength[i];
|
||||
|
||||
bytes = (byte)(StaticArrayStruct.Colors[0].R + StaticArrayStruct.Colors[0].G
|
||||
+ StaticArrayStruct.Colors[0].B
|
||||
+ StaticArrayStruct.Colors[0].A);
|
||||
|
||||
for (int i = 1; i < StaticArrayStruct.Colors.Length; i++)
|
||||
bytes += (byte)(StaticArrayStruct.Colors[i].R + StaticArrayStruct.Colors[i].G
|
||||
+ StaticArrayStruct.Colors[i].B
|
||||
+ StaticArrayStruct.Colors[i].A);
|
||||
|
||||
for (int i = 1; i < StaticArrayStruct.Positions.Length; i++)
|
||||
ints += math.dot(StaticArrayStruct.Positions[i - 1], StaticArrayStruct.Positions[i]);
|
||||
|
||||
return (int)doubles + bytes + ushorts + ints;
|
||||
}
|
||||
|
||||
private static T TakesRef<T>(ref T x)
|
||||
{
|
||||
return x;
|
||||
}
|
||||
|
||||
[TestCompiler]
|
||||
public static int TestStaticReadonlyArrayWithElementRef()
|
||||
{
|
||||
return TakesRef(ref StaticArrayStruct.Ints[1]);
|
||||
}
|
||||
|
||||
[TestCompiler]
|
||||
public static int TestStaticReadonlyArrayWithElementVectorRef()
|
||||
{
|
||||
var x = TakesRef(ref StaticArrayStruct.Positions[1]);
|
||||
return math.dot(x, x);
|
||||
}
|
||||
|
||||
[TestCompiler(1)]
|
||||
[TestCompiler(2)]
|
||||
[TestCompiler(3)]
|
||||
[TestCompiler(4)]
|
||||
public static int TestStaticReadonlyArrayWithDynamicLdelem(int count)
|
||||
{
|
||||
int sum = 0;
|
||||
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
sum += (int)StaticArrayStruct.Doubles[i];
|
||||
}
|
||||
|
||||
return sum;
|
||||
}
|
||||
|
||||
public struct ContainerStruct
|
||||
{
|
||||
public SmallStruct A;
|
||||
public SmallStruct B;
|
||||
|
||||
public static readonly ContainerStruct[] CoolStructs =
|
||||
{
|
||||
new ContainerStruct
|
||||
{
|
||||
A = new SmallStruct { a = 3, b = 5 },
|
||||
B = new SmallStruct { a = 9, b = 10 }
|
||||
},
|
||||
new ContainerStruct
|
||||
{
|
||||
A = new SmallStruct { a = 1, b = 5 },
|
||||
B = new SmallStruct { a = 7, b = 8 }
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
[TestCompiler]
|
||||
public static int TestStaticReadonlyArrayOfStructOfStructs()
|
||||
{
|
||||
return ContainerStruct.CoolStructs[0].A.a + ContainerStruct.CoolStructs[0].A.b +
|
||||
ContainerStruct.CoolStructs[0].B.a + ContainerStruct.CoolStructs[0].B.b +
|
||||
ContainerStruct.CoolStructs[1].A.a + ContainerStruct.CoolStructs[1].A.b +
|
||||
ContainerStruct.CoolStructs[1].B.a + ContainerStruct.CoolStructs[1].B.b;
|
||||
}
|
||||
|
||||
/* There's currently no way of settings the safety checks on from here
|
||||
[TestCompiler(0xFFFFFFF, ExpectedException = typeof(IndexOutOfRangeException))]
|
||||
public static int TestStaticReadonlyLdelemDynamicIndexOfBounds(int x)
|
||||
{
|
||||
return StaticArrayStruct.Ints[x];
|
||||
}
|
||||
*/
|
||||
|
||||
public struct SmallStruct
|
||||
{
|
||||
public int a;
|
||||
public int b;
|
||||
}
|
||||
|
||||
public struct NullArrayHolder
|
||||
{
|
||||
public static readonly int[] Array = null;
|
||||
}
|
||||
|
||||
[TestCompiler()]
|
||||
public static int TestStaticReadonlyNullArray()
|
||||
{
|
||||
if (NullArrayHolder.Array == null)
|
||||
{
|
||||
return 40;
|
||||
}
|
||||
|
||||
return 3;
|
||||
}
|
||||
|
||||
private static readonly int[] SomeArray = { 42, 13 };
|
||||
|
||||
[TestCompiler(42)]
|
||||
public static int StoreNullIntoLocalArray(int x)
|
||||
{
|
||||
int[] someArray;
|
||||
|
||||
if (x == 0)
|
||||
{
|
||||
someArray = SomeArray;
|
||||
}
|
||||
else
|
||||
{
|
||||
someArray = null;
|
||||
}
|
||||
|
||||
return someArray?.Length ?? 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 1b192164f6d13e9aaf88fbb6833566c4
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,201 @@
|
|||
using Burst.Compiler.IL.Tests.Helpers;
|
||||
using Unity.Burst.CompilerServices;
|
||||
using Unity.Mathematics;
|
||||
|
||||
namespace Burst.Compiler.IL.Tests
|
||||
{
|
||||
internal class Peephole
|
||||
{
|
||||
[TestCompiler(DataRange.ZeroExclusiveTo100, FastMath = true)]
|
||||
public static int SqrtEqualFast(float f)
|
||||
{
|
||||
return math.sqrt(f) == 2 ? 42 : 13;
|
||||
}
|
||||
|
||||
[TestCompiler(DataRange.ZeroExclusiveTo100, FastMath = true)]
|
||||
public static int SqrtNotEqualFast(float f)
|
||||
{
|
||||
return math.sqrt(f) != 2 ? 42 : 13;
|
||||
}
|
||||
|
||||
[TestCompiler(DataRange.ZeroExclusiveTo100)]
|
||||
public static int SqrtLessThan(float f)
|
||||
{
|
||||
return math.sqrt(f) < 2 ? 42 : 13;
|
||||
}
|
||||
|
||||
[TestCompiler(DataRange.ZeroExclusiveTo100, FastMath = true)]
|
||||
public static int SqrtLessThanFast(float f)
|
||||
{
|
||||
return math.sqrt(f) < 2 ? 42 : 13;
|
||||
}
|
||||
|
||||
[TestCompiler(DataRange.ZeroExclusiveTo100, FastMath = true)]
|
||||
public static int SqrtLessThanLargeConstant(float f)
|
||||
{
|
||||
return math.sqrt(f) < float.MaxValue ? 42 : 13;
|
||||
}
|
||||
|
||||
[TestCompiler(DataRange.ZeroExclusiveTo100, FastMath = true)]
|
||||
public static int SqrtLessThanFastVector(ref float4 f)
|
||||
{
|
||||
return math.all(math.sqrt(f) < 2) ? 42 : 13;
|
||||
}
|
||||
|
||||
[TestCompiler(DataRange.ZeroExclusiveTo100, FastMath = true)]
|
||||
public static int SqrtLessThanLargeConstantVector(ref float4 f)
|
||||
{
|
||||
return math.all(math.sqrt(f) < new float4(1, 2, 3, float.MaxValue)) ? 42 : 13;
|
||||
}
|
||||
|
||||
[TestCompiler(DataRange.ZeroExclusiveTo100)]
|
||||
public static int SqrtGreaterThan(float f)
|
||||
{
|
||||
return math.sqrt(f) > 2 ? 42 : 13;
|
||||
}
|
||||
|
||||
[TestCompiler(DataRange.ZeroExclusiveTo100, FastMath = true)]
|
||||
public static int SqrtGreaterThanFast(float f)
|
||||
{
|
||||
return math.sqrt(f) > 2 ? 42 : 13;
|
||||
}
|
||||
|
||||
[TestCompiler(DataRange.ZeroExclusiveTo100, FastMath = true)]
|
||||
public static int SqrtGreaterThanLargeConstant(float f)
|
||||
{
|
||||
return math.sqrt(f) > float.MaxValue ? 42 : 13;
|
||||
}
|
||||
|
||||
[TestCompiler(DataRange.ZeroExclusiveTo100, FastMath = true)]
|
||||
public static int SqrtGreaterThanFastVector(ref float4 f)
|
||||
{
|
||||
return math.all(math.sqrt(f) > 2) ? 42 : 13;
|
||||
}
|
||||
|
||||
[TestCompiler(DataRange.ZeroExclusiveTo100, FastMath = true)]
|
||||
public static int SqrtGreaterThanLargeConstantVector(ref float4 f)
|
||||
{
|
||||
return math.all(math.sqrt(f) > new float4(1, 2, 3, float.MaxValue)) ? 42 : 13;
|
||||
}
|
||||
|
||||
[TestCompiler(DataRange.ZeroExclusiveTo100)]
|
||||
public static int SqrtLessThanEqual(float f)
|
||||
{
|
||||
return math.sqrt(f) <= 2 ? 42 : 13;
|
||||
}
|
||||
|
||||
[TestCompiler(DataRange.ZeroExclusiveTo100, FastMath = true)]
|
||||
public static int SqrtLessThanEqualFast(float f)
|
||||
{
|
||||
return math.sqrt(f) <= 2 ? 42 : 13;
|
||||
}
|
||||
|
||||
[TestCompiler(DataRange.ZeroExclusiveTo100, FastMath = true)]
|
||||
public static int SqrtLessThanEqualLargeConstant(float f)
|
||||
{
|
||||
return math.sqrt(f) <= float.MaxValue ? 42 : 13;
|
||||
}
|
||||
|
||||
[TestCompiler(DataRange.ZeroExclusiveTo100, FastMath = true)]
|
||||
public static int SqrtLessThanEqualFastVector(ref float4 f)
|
||||
{
|
||||
return math.all(math.sqrt(f) <= 2) ? 42 : 13;
|
||||
}
|
||||
|
||||
[TestCompiler(DataRange.ZeroExclusiveTo100, FastMath = true)]
|
||||
public static int SqrtLessThanEqualLargeConstantVector(ref float4 f)
|
||||
{
|
||||
return math.all(math.sqrt(f) <= new float4(1, 2, 3, float.MaxValue)) ? 42 : 13;
|
||||
}
|
||||
|
||||
[TestCompiler(DataRange.ZeroExclusiveTo100)]
|
||||
public static int SqrtGreaterThanEqual(float f)
|
||||
{
|
||||
return math.sqrt(f) >= 2 ? 42 : 13;
|
||||
}
|
||||
|
||||
[TestCompiler(DataRange.ZeroExclusiveTo100, FastMath = true)]
|
||||
public static int SqrtGreaterThanEqualFast(float f)
|
||||
{
|
||||
return math.sqrt(f) >= 2 ? 42 : 13;
|
||||
}
|
||||
|
||||
[TestCompiler(DataRange.ZeroExclusiveTo100, FastMath = true)]
|
||||
public static int SqrtGreaterThanEqualLargeConstant(float f)
|
||||
{
|
||||
return math.sqrt(f) >= float.MaxValue ? 42 : 13;
|
||||
}
|
||||
|
||||
[TestCompiler(DataRange.ZeroExclusiveTo100, FastMath = true)]
|
||||
public static int SqrtGreaterThanEqualFastVector(ref float4 f)
|
||||
{
|
||||
return math.all(math.sqrt(f) >= 2) ? 42 : 13;
|
||||
}
|
||||
|
||||
[TestCompiler(DataRange.ZeroExclusiveTo100, FastMath = true)]
|
||||
public static int SqrtGreaterThanEqualLargeConstantVector(ref float4 f)
|
||||
{
|
||||
return math.all(math.sqrt(f) >= new float4(1, 2, 3, float.MaxValue)) ? 42 : 13;
|
||||
}
|
||||
|
||||
[TestCompiler(DataRange.ZeroExclusiveTo100, DataRange.ZeroExclusiveTo100, FastMath = true)]
|
||||
public static int SqrtAndSqrtFast(ref float4 a, ref float4 b)
|
||||
{
|
||||
return math.all(math.sqrt(a) >= math.sqrt(b)) ? 42 : 13;
|
||||
}
|
||||
|
||||
[TestCompiler(0)]
|
||||
public static float FloatExp2FromInt(int a)
|
||||
{
|
||||
return math.exp2(a);
|
||||
}
|
||||
|
||||
[TestCompiler(0)]
|
||||
public static double DoubleExp2FromInt(int a)
|
||||
{
|
||||
return math.exp2((double)a);
|
||||
}
|
||||
|
||||
[TestCompiler((ushort)0)]
|
||||
public static float FloatExp2FromUShort(ushort a)
|
||||
{
|
||||
return math.exp2(a);
|
||||
}
|
||||
|
||||
[TestCompiler((ushort)0)]
|
||||
public static double DoubleExp2FromUShort(ushort a)
|
||||
{
|
||||
return math.exp2((double)a);
|
||||
}
|
||||
|
||||
[TestCompiler(0)]
|
||||
public static float FloatPowFromInt(int a)
|
||||
{
|
||||
return math.pow(2.0f, a);
|
||||
}
|
||||
|
||||
[TestCompiler(0)]
|
||||
public static double DoublePowFromInt(int a)
|
||||
{
|
||||
return math.pow(2.0, a);
|
||||
}
|
||||
|
||||
[TestCompiler(0u)]
|
||||
public static float FloatPowFromUInt(uint a)
|
||||
{
|
||||
return math.pow(2.0f, a);
|
||||
}
|
||||
|
||||
[TestCompiler(0u)]
|
||||
public static double DoublePowFromUInt(uint a)
|
||||
{
|
||||
return math.pow(2.0, a);
|
||||
}
|
||||
|
||||
[TestCompiler(int.MaxValue)]
|
||||
public static int AShrToLShr([AssumeRange(0, int.MaxValue)] int a)
|
||||
{
|
||||
return a >> 4;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 1d15bef20cb43dc49f6156cde028d37a
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,108 @@
|
|||
namespace Burst.Compiler.IL.Tests.Shared
|
||||
{
|
||||
internal class TestStackalloc
|
||||
{
|
||||
[TestCompiler]
|
||||
public static unsafe int Stackalloc1ByteWithInitializer()
|
||||
{
|
||||
var value = stackalloc byte[1] { 0xA4 };
|
||||
return value[0];
|
||||
}
|
||||
|
||||
[TestCompiler]
|
||||
public static unsafe int Stackalloc16BytesWithInitializer()
|
||||
{
|
||||
// Roslyn generates quite different IL when the number of bytes is larger than 8.
|
||||
var value = stackalloc byte[16] { 0xA4, 0xA1, 0x20, 0xA5, 0x80, 0x17, 0xF6, 0x4F, 0xBD, 0x18, 0x16, 0x73, 0x43, 0xC5, 0xAF, 0x16 };
|
||||
return value[9];
|
||||
}
|
||||
|
||||
[TestCompiler]
|
||||
public static unsafe int Stackalloc16IntsWithInitializer()
|
||||
{
|
||||
var value = stackalloc int[16] { 0xA4, 0xA1, 0x20, 0xA5, 0x80, 0x17, 0xF6, 0x4F, 0xBD, 0x18, 0x16, 0x73, 0x43, 0xC5, 0xAF, 0x16 };
|
||||
return value[9];
|
||||
}
|
||||
|
||||
[TestCompiler(1)]
|
||||
public static unsafe int StackallocInBranch(int takeBranch)
|
||||
{
|
||||
int* array = null;
|
||||
|
||||
if (takeBranch != 0)
|
||||
{
|
||||
int* elem = stackalloc int[1];
|
||||
array = elem;
|
||||
}
|
||||
|
||||
if (takeBranch != 0)
|
||||
{
|
||||
int* elem = stackalloc int[1];
|
||||
|
||||
if (array == elem)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
[TestCompiler(4)]
|
||||
public static unsafe int StackallocInLoop(int iterations)
|
||||
{
|
||||
int** array = stackalloc int*[iterations];
|
||||
|
||||
for (int i = 0; i < iterations; i++)
|
||||
{
|
||||
int* elem = stackalloc int[1];
|
||||
array[i] = elem;
|
||||
}
|
||||
|
||||
for (int i = 0; i < iterations; i++)
|
||||
{
|
||||
for (int k = i + 1; k < iterations; k++)
|
||||
{
|
||||
// Make sure all the stack allocations within the loop are unique addresses.
|
||||
if (array[i] == array[k])
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
[TestCompiler]
|
||||
public static unsafe int StackallocWithUnmanagedConstructedType()
|
||||
{
|
||||
var value = stackalloc[]
|
||||
{
|
||||
new Point<int> { X = 1, Y = 2 },
|
||||
new Point<int> { X = 42, Y = 5 },
|
||||
new Point<int> { X = 3, Y = -1 },
|
||||
};
|
||||
return value[1].X;
|
||||
}
|
||||
|
||||
private struct Point<T>
|
||||
{
|
||||
public T X;
|
||||
public T Y;
|
||||
}
|
||||
|
||||
#if UNITY_2021_2_OR_NEWER || BURST_INTERNAL
|
||||
[TestCompiler]
|
||||
public static int StackallocInNestedExpression()
|
||||
{
|
||||
return StackallocInNestedExpressionHelper(stackalloc[] { 2, 4, 6, 8 });
|
||||
}
|
||||
|
||||
private static int StackallocInNestedExpressionHelper(System.Span<int> span)
|
||||
{
|
||||
return span[2];
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 614354dff06f39c4b6ef0e21f5a45d23
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,151 @@
|
|||
using System;
|
||||
using NUnit.Framework;
|
||||
using UnityBenchShared;
|
||||
|
||||
namespace Burst.Compiler.IL.Tests
|
||||
{
|
||||
/// <summary>
|
||||
/// Test with enums.
|
||||
/// </summary>
|
||||
internal partial class TestEnums
|
||||
{
|
||||
[System.Flags]
|
||||
public enum MyEnum
|
||||
{
|
||||
Hello = 5,
|
||||
Something = 10
|
||||
}
|
||||
|
||||
[TestCompiler]
|
||||
public static int test_enum_cast_to_int()
|
||||
{
|
||||
MyEnum value = MyEnum.Hello;
|
||||
return (int)value;
|
||||
}
|
||||
|
||||
[TestCompiler(MyEnum.Hello)]
|
||||
[TestCompiler(MyEnum.Something)]
|
||||
public static int test_enum_compare(MyEnum value)
|
||||
{
|
||||
if (value == MyEnum.Hello)
|
||||
return 0;
|
||||
else
|
||||
return 1;
|
||||
}
|
||||
|
||||
//[TestCompiler(typeof(StructContainingEnumProvider))]
|
||||
//public static int test_enum_in_struct(ref StructContainingEnum myStruct)
|
||||
//{
|
||||
// return myStruct.intValue + (int)myStruct.value;
|
||||
//}
|
||||
|
||||
[TestCompiler(MyEnum.Hello)]
|
||||
[TestCompiler(MyEnum.Something)]
|
||||
[Ignore("Failure")]
|
||||
public static int test_enum_has_flag(MyEnum value)
|
||||
{
|
||||
return value.HasFlag(MyEnum.Hello) ? 3 : 4;
|
||||
}
|
||||
|
||||
[TestCompiler(MyEnum.Hello)]
|
||||
[TestCompiler(MyEnum.Something)]
|
||||
public static int test_enum_and_mask(MyEnum value)
|
||||
{
|
||||
return (value & MyEnum.Hello) != 0 ? 3 : 4;
|
||||
}
|
||||
|
||||
[TestCompiler(1)]
|
||||
[TestCompiler(2)]
|
||||
public static int TestEnumSwitchCase(IntPtr value)
|
||||
{
|
||||
var enumValue = (SmallEnum) value.ToInt32();
|
||||
// Need at least 3 cases to generate a proper switch
|
||||
// otherwise Roslyn will generate an if/else
|
||||
switch (enumValue)
|
||||
{
|
||||
case SmallEnum.One:
|
||||
return 7;
|
||||
case SmallEnum.Two:
|
||||
return 8;
|
||||
case SmallEnum.Three:
|
||||
return 9;
|
||||
default:
|
||||
return 10;
|
||||
}
|
||||
}
|
||||
|
||||
private static int GetToInt32(int value)
|
||||
{
|
||||
return value;
|
||||
}
|
||||
|
||||
[TestCompiler]
|
||||
public static int test_enum_sizeof_small_enum()
|
||||
{
|
||||
return sizeof(SmallEnum);
|
||||
}
|
||||
|
||||
|
||||
[TestCompiler(SmallEnum.Three)]
|
||||
public static int test_enum_sizeof_small_enum_in_struct_access(SmallEnum value)
|
||||
{
|
||||
var s = new MySmallEnumStruct
|
||||
{
|
||||
a = value,
|
||||
b = value,
|
||||
c = value
|
||||
};
|
||||
return (int)s.a + (int)s.b + (int)s.c;
|
||||
}
|
||||
|
||||
public struct StructContainingEnum
|
||||
{
|
||||
public MyEnum value;
|
||||
public int intValue;
|
||||
}
|
||||
|
||||
|
||||
public enum SmallEnum : byte
|
||||
{
|
||||
One,
|
||||
Two,
|
||||
Three
|
||||
}
|
||||
|
||||
|
||||
public struct MySmallEnumStruct
|
||||
{
|
||||
public SmallEnum a;
|
||||
public SmallEnum b;
|
||||
public SmallEnum c;
|
||||
public SmallEnum d;
|
||||
}
|
||||
|
||||
public enum SomeByteEnum : byte
|
||||
{
|
||||
First = 0,
|
||||
Last = 255
|
||||
}
|
||||
|
||||
public unsafe struct FixedByte4Struct
|
||||
{
|
||||
fixed byte bytes[4];
|
||||
|
||||
public SomeByteEnum this[SomeByteEnum index]
|
||||
{
|
||||
get { return (SomeByteEnum)bytes[(int)index]; }
|
||||
}
|
||||
|
||||
public struct Provider : IArgumentProvider
|
||||
{
|
||||
public object Value => new FixedByte4Struct { };
|
||||
}
|
||||
}
|
||||
|
||||
[TestCompiler(typeof(FixedByte4Struct.Provider))]
|
||||
public static SomeByteEnum test_enum_indexer(ref FixedByte4Struct bytes)
|
||||
{
|
||||
return bytes[0];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 7771e50c9f91376ca0db91c33bfccfda
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,173 @@
|
|||
using System;
|
||||
using System.Threading;
|
||||
|
||||
namespace Burst.Compiler.IL.Tests
|
||||
{
|
||||
/// <summary>
|
||||
/// Tests of the <see cref="Interlocked"/> functions.
|
||||
/// </summary>
|
||||
internal class TestAtomics
|
||||
{
|
||||
[TestCompiler(1)]
|
||||
[TestCompiler(-1)]
|
||||
public static int test_atomic_increment_int(ref int value)
|
||||
{
|
||||
return Interlocked.Increment(ref value);
|
||||
}
|
||||
|
||||
[TestCompiler(1L)]
|
||||
[TestCompiler(-1L)]
|
||||
public static long test_atomic_increment_long(ref long value)
|
||||
{
|
||||
return Interlocked.Increment(ref value);
|
||||
}
|
||||
|
||||
[TestCompiler(1)]
|
||||
[TestCompiler(-1)]
|
||||
public static int test_atomic_add_int(ref int value)
|
||||
{
|
||||
return Interlocked.Add(ref value, 2);
|
||||
}
|
||||
|
||||
[TestCompiler(1L)]
|
||||
[TestCompiler(-1L)]
|
||||
public static long test_atomic_add_long(ref long value)
|
||||
{
|
||||
return Interlocked.Add(ref value, 2);
|
||||
}
|
||||
|
||||
[TestCompiler(1, 2, 1)]
|
||||
[TestCompiler(1, 10, 1)]
|
||||
[TestCompiler(1, 2, 2)]
|
||||
[TestCompiler(7, 2, 1)]
|
||||
[TestCompiler(7, 10, 1)]
|
||||
[TestCompiler(7, 2, 2)]
|
||||
public static int test_atomic_compare_and_exchange_int(ref int location, int value, int compareAnd)
|
||||
{
|
||||
return Interlocked.CompareExchange(ref location, value, compareAnd);
|
||||
}
|
||||
|
||||
[TestCompiler(1L, 2L, 1L)]
|
||||
[TestCompiler(1L, 10L, 1L)]
|
||||
[TestCompiler(1L, 2L, 2L)]
|
||||
[TestCompiler(7L, 2L, 1L)]
|
||||
[TestCompiler(7L, 10L, 1L)]
|
||||
[TestCompiler(7L, 2L, 2L)]
|
||||
public static long test_atomic_compare_and_exchange_long(ref long location, long value, long compareAnd)
|
||||
{
|
||||
return Interlocked.CompareExchange(ref location, value, compareAnd);
|
||||
}
|
||||
|
||||
[TestCompiler(1)]
|
||||
[TestCompiler(-1)]
|
||||
public static int test_atomic_decrement_int(ref int value)
|
||||
{
|
||||
return Interlocked.Decrement(ref value);
|
||||
}
|
||||
|
||||
[TestCompiler(1L)]
|
||||
[TestCompiler(-1L)]
|
||||
public static long test_atomic_decrement_long(ref long value)
|
||||
{
|
||||
return Interlocked.Decrement(ref value);
|
||||
}
|
||||
|
||||
[TestCompiler(1)]
|
||||
public static int test_atomic_exchange_int(ref int value)
|
||||
{
|
||||
return Interlocked.Exchange(ref value, 5);
|
||||
}
|
||||
|
||||
[TestCompiler(1L)]
|
||||
public static long test_atomic_exchange_long(ref long value)
|
||||
{
|
||||
return Interlocked.Exchange(ref value, 5);
|
||||
}
|
||||
|
||||
[TestCompiler(1)]
|
||||
public static IntPtr ExchangeIntPtr(IntPtr value)
|
||||
{
|
||||
return Interlocked.Exchange(ref value, new IntPtr(5));
|
||||
}
|
||||
|
||||
[TestCompiler(1, 2, 1)]
|
||||
[TestCompiler(1, 10, 1)]
|
||||
[TestCompiler(1, 2, 2)]
|
||||
public static IntPtr CompareExchangeIntPtr(IntPtr location, IntPtr value, IntPtr compareAnd)
|
||||
{
|
||||
return Interlocked.CompareExchange(ref location, value, compareAnd);
|
||||
}
|
||||
|
||||
[TestCompiler]
|
||||
public static void test_atomic_memorybarrier()
|
||||
{
|
||||
Interlocked.MemoryBarrier();
|
||||
}
|
||||
|
||||
[TestCompiler(0)]
|
||||
public static int Case1111040(int val)
|
||||
{
|
||||
int test = val;
|
||||
Interlocked.Increment(ref test);
|
||||
Interlocked.Decrement(ref test);
|
||||
return test;
|
||||
}
|
||||
|
||||
[TestCompiler(42.0f)]
|
||||
public static float ExchangeFloat(ref float f)
|
||||
{
|
||||
if (Interlocked.Exchange(ref f, 13) == 42)
|
||||
{
|
||||
return f;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
[TestCompiler(42.0)]
|
||||
public static double ExchangeDouble(ref double d)
|
||||
{
|
||||
if (Interlocked.Exchange(ref d, 13) == 42)
|
||||
{
|
||||
return d;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if !BURST_APPLE_SILICON_TESTING // https://jira.unity3d.com/browse/UUM-9159
|
||||
[TestCompiler(42.0f)]
|
||||
public static float CompareExchangeFloat(ref float f)
|
||||
{
|
||||
if (Interlocked.CompareExchange(ref f, 13, 42) == 42)
|
||||
{
|
||||
return f;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
[TestCompiler(42.0)]
|
||||
public static double CompareExchangeDouble(ref double d)
|
||||
{
|
||||
if (Interlocked.CompareExchange(ref d, 13, 42) == 42)
|
||||
{
|
||||
return d;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
[TestCompiler(42L)]
|
||||
public static double Read(ref long l)
|
||||
{
|
||||
if (Interlocked.Read(ref l) == 42)
|
||||
{
|
||||
return l;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: a1bc4bf3e38931c9b2014cc764d03dea
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,265 @@
|
|||
using System;
|
||||
using Burst.Compiler.IL.Tests.Helpers;
|
||||
|
||||
namespace Burst.Compiler.IL.Tests
|
||||
{
|
||||
/// <summary>
|
||||
/// Tests of the <see cref="System.Math"/> functions.
|
||||
/// </summary>
|
||||
internal class TestSystemMath
|
||||
{
|
||||
[TestCompiler(DataRange.Standard)]
|
||||
public static double TestCos(float value)
|
||||
{
|
||||
return Math.Cos(value);
|
||||
}
|
||||
|
||||
[TestCompiler(DataRange.Standard)]
|
||||
public static double TestSin(float value)
|
||||
{
|
||||
return Math.Sin(value);
|
||||
}
|
||||
|
||||
[TestCompiler(DataRange.Standard)]
|
||||
public static float TestTan(float value)
|
||||
{
|
||||
return (float) Math.Tan(value);
|
||||
}
|
||||
|
||||
[TestCompiler(DataRange.Standard11)]
|
||||
public static double TestAcos(float value)
|
||||
{
|
||||
return Math.Acos(value);
|
||||
}
|
||||
|
||||
[TestCompiler(DataRange.Standard11)]
|
||||
public static double TestAsin(float value)
|
||||
{
|
||||
return Math.Asin(value);
|
||||
}
|
||||
|
||||
[TestCompiler(DataRange.Standard11)]
|
||||
public static float TestAtan(float value)
|
||||
{
|
||||
return (float)Math.Atan(value);
|
||||
}
|
||||
|
||||
[TestCompiler(DataRange.ZeroExclusiveToOneInclusive, DataRange.ZeroExclusiveToOneInclusive)]
|
||||
public static float TestAtan2(float y, float x)
|
||||
{
|
||||
return (float)Math.Atan2(y, x);
|
||||
}
|
||||
|
||||
[TestCompiler(DataRange.Standard)]
|
||||
public static double TestCosh(float value)
|
||||
{
|
||||
return Math.Cosh(value);
|
||||
}
|
||||
|
||||
[TestCompiler(DataRange.Standard)]
|
||||
public static double TestSinh(float value)
|
||||
{
|
||||
return Math.Sinh(value);
|
||||
}
|
||||
|
||||
[TestCompiler(DataRange.Standard)]
|
||||
public static float TestTanh(float value)
|
||||
{
|
||||
return (float)Math.Tanh(value);
|
||||
}
|
||||
|
||||
[TestCompiler(DataRange.StandardPositive)]
|
||||
public static double TestSqrt(float value)
|
||||
{
|
||||
return Math.Sqrt(value);
|
||||
}
|
||||
|
||||
[TestCompiler(DataRange.StandardPositive & ~DataRange.Zero)]
|
||||
public static double TestLog(float value)
|
||||
{
|
||||
return Math.Log(value);
|
||||
}
|
||||
|
||||
[TestCompiler(DataRange.StandardPositive & ~DataRange.Zero)]
|
||||
public static double TestLog10(float value)
|
||||
{
|
||||
return Math.Log10(value);
|
||||
}
|
||||
|
||||
[TestCompiler(DataRange.StandardPositive)]
|
||||
public static double TestExp(float value)
|
||||
{
|
||||
return Math.Exp(value);
|
||||
}
|
||||
|
||||
[TestCompiler(DataRange.Standard & ~(DataRange.Zero|DataRange.NaN), DataRange.Standard)]
|
||||
[TestCompiler(DataRange.Standard & ~DataRange.Zero, DataRange.Standard & ~DataRange.Zero)]
|
||||
public static double TestPow(float value, float power)
|
||||
{
|
||||
return Math.Pow(value, power);
|
||||
}
|
||||
|
||||
[TestCompiler(DataRange.Standard)]
|
||||
public static sbyte TestAbsSByte(sbyte value)
|
||||
{
|
||||
return Math.Abs(value);
|
||||
}
|
||||
|
||||
[TestCompiler(DataRange.Standard)]
|
||||
public static short TestAbsShort(short value)
|
||||
{
|
||||
return Math.Abs(value);
|
||||
}
|
||||
|
||||
[TestCompiler(DataRange.Standard)]
|
||||
public static int TestAbsInt(int value)
|
||||
{
|
||||
return Math.Abs(value);
|
||||
}
|
||||
|
||||
[TestCompiler(DataRange.Standard)]
|
||||
public static long TestAbsLong(long value)
|
||||
{
|
||||
return Math.Abs(value);
|
||||
}
|
||||
|
||||
[TestCompiler(DataRange.Standard)]
|
||||
public static float TestAbsFloat(float value)
|
||||
{
|
||||
return Math.Abs(value);
|
||||
}
|
||||
|
||||
[TestCompiler(DataRange.Standard)]
|
||||
public static double TestAbsDouble(double value)
|
||||
{
|
||||
return Math.Abs(value);
|
||||
}
|
||||
|
||||
[TestCompiler(DataRange.Standard, DataRange.Standard)]
|
||||
public static int TestMaxInt(int left, int right)
|
||||
{
|
||||
return Math.Max(left, right);
|
||||
}
|
||||
|
||||
[TestCompiler(DataRange.Standard, DataRange.Standard)]
|
||||
public static int TestMinInt(int left, int right)
|
||||
{
|
||||
return Math.Min(left, right);
|
||||
}
|
||||
|
||||
[TestCompiler(DataRange.Standard, DataRange.Standard)]
|
||||
public static double TestMaxDouble(double left, double right)
|
||||
{
|
||||
return Math.Max(left, right);
|
||||
}
|
||||
|
||||
[TestCompiler(DataRange.Standard, DataRange.Standard)]
|
||||
public static double TestMinDouble(double left, double right)
|
||||
{
|
||||
return Math.Min(left, right);
|
||||
}
|
||||
|
||||
[TestCompiler(DataRange.Standard)]
|
||||
public static int TestSignInt(int value)
|
||||
{
|
||||
return Math.Sign(value);
|
||||
}
|
||||
|
||||
[TestCompiler(DataRange.Standard & ~DataRange.NaN)]
|
||||
public static int TestSignFloat(float value)
|
||||
{
|
||||
return Math.Sign(value);
|
||||
}
|
||||
|
||||
[TestCompiler(float.NaN, ExpectedException = typeof(ArithmeticException))]
|
||||
[MonoOnly(".NET CLR does not support burst.abort correctly")]
|
||||
public static int TestSignException(float value)
|
||||
{
|
||||
return Math.Sign(value);
|
||||
}
|
||||
|
||||
[TestCompiler(DataRange.Standard & ~DataRange.NaN)]
|
||||
public static int TestSignDouble(double value)
|
||||
{
|
||||
return Math.Sign(value);
|
||||
}
|
||||
|
||||
[TestCompiler(DataRange.Standard)]
|
||||
public static double TestCeilingDouble(double value)
|
||||
{
|
||||
return Math.Ceiling(value);
|
||||
}
|
||||
|
||||
[TestCompiler(DataRange.Standard)]
|
||||
public static double TestFloorDouble(double value)
|
||||
{
|
||||
return Math.Floor(value);
|
||||
}
|
||||
|
||||
[TestCompiler(DataRange.Standard)]
|
||||
public static double TestRoundDouble(double value)
|
||||
{
|
||||
return Math.Round(value);
|
||||
}
|
||||
|
||||
[TestCompiler(DataRange.Standard)]
|
||||
public static double TestTruncateDouble(double value)
|
||||
{
|
||||
return Math.Truncate(value);
|
||||
}
|
||||
|
||||
[TestCompiler(DataRange.Standard, DataRange.Standard & ~DataRange.Zero)]
|
||||
public static int TestDivRemInt(int a, int b)
|
||||
{
|
||||
int remResult;
|
||||
var divResult = Math.DivRem(a, b, out remResult);
|
||||
return divResult + remResult * 7;
|
||||
}
|
||||
|
||||
[TestCompiler(DataRange.Standard, DataRange.Standard)]
|
||||
[TestCompiler(int.MaxValue, DataRange.Standard)]
|
||||
public static long TestBigMulInt(int a, int b)
|
||||
{
|
||||
return Math.BigMul(a, b);
|
||||
}
|
||||
|
||||
[TestCompiler(DataRange.Standard & ~DataRange.Zero, DataRange.Standard & ~DataRange.Zero)]
|
||||
public static double TestLogWithBaseDouble(double a, double newBase)
|
||||
{
|
||||
return Math.Log(a, newBase);
|
||||
}
|
||||
|
||||
//[TestCompiler(1.0, 2.0)]
|
||||
//[TestCompiler(10.0, 3.0)]
|
||||
//[TestCompiler(15.0, 4.0)]
|
||||
//[Ignore("Not yet supported")]
|
||||
//public static double TestIEEERemainder(double a, double newBase)
|
||||
//{
|
||||
// return Math.IEEERemainder(a, newBase);
|
||||
//}
|
||||
|
||||
[TestCompiler(DataRange.Standard)]
|
||||
public static bool TestIsNanDouble(double a)
|
||||
{
|
||||
return double.IsNaN(a);
|
||||
}
|
||||
|
||||
[TestCompiler(DataRange.Standard)]
|
||||
public static bool TestIsNanFloat(float a)
|
||||
{
|
||||
return float.IsNaN(a);
|
||||
}
|
||||
|
||||
[TestCompiler(DataRange.Standard)]
|
||||
public static bool TestIsInfinityDouble(double a)
|
||||
{
|
||||
return double.IsInfinity(a);
|
||||
}
|
||||
|
||||
[TestCompiler(DataRange.Standard)]
|
||||
public static bool TestIsInfinityFloat(float a)
|
||||
{
|
||||
return float.IsInfinity(a);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 47108b7d7a79385f98626b40f17ef46d
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,192 @@
|
|||
using System;
|
||||
using System.Threading;
|
||||
using UnityBenchShared;
|
||||
|
||||
namespace Burst.Compiler.IL.Tests
|
||||
{
|
||||
/// <summary>
|
||||
/// Tests of the <see cref="System.Threading"/> functions.
|
||||
/// </summary>
|
||||
internal class TestSystemThreading
|
||||
{
|
||||
[TestCompiler]
|
||||
public static void TestMemoryBarrier()
|
||||
{
|
||||
Thread.MemoryBarrier();
|
||||
}
|
||||
|
||||
[TestCompiler]
|
||||
public static int TestReadBool()
|
||||
{
|
||||
var data = false;
|
||||
return (Volatile.Read(ref data) ? 1 : 0) + (Volatile.Read(ref data) ? 1 : 0);
|
||||
}
|
||||
|
||||
[TestCompiler((byte)42)]
|
||||
public static int TestReadByte(ref byte data)
|
||||
{
|
||||
return Volatile.Read(ref data) + Volatile.Read(ref data);
|
||||
}
|
||||
|
||||
[TestCompiler((sbyte)42)]
|
||||
public static int TestReadSByte(ref sbyte data)
|
||||
{
|
||||
return Volatile.Read(ref data) + Volatile.Read(ref data);
|
||||
}
|
||||
|
||||
[TestCompiler((short)42)]
|
||||
public static int TestReadShort(ref short data)
|
||||
{
|
||||
return Volatile.Read(ref data) + Volatile.Read(ref data);
|
||||
}
|
||||
|
||||
[TestCompiler((ushort)42)]
|
||||
public static int TestReadUShort(ref ushort data)
|
||||
{
|
||||
return Volatile.Read(ref data) + Volatile.Read(ref data);
|
||||
}
|
||||
|
||||
[TestCompiler(42)]
|
||||
public static int TestReadInt(ref int data)
|
||||
{
|
||||
return Volatile.Read(ref data) + Volatile.Read(ref data);
|
||||
}
|
||||
|
||||
[TestCompiler(42u)]
|
||||
public static uint TestReadUInt(ref uint data)
|
||||
{
|
||||
return Volatile.Read(ref data) + Volatile.Read(ref data);
|
||||
}
|
||||
|
||||
[TestCompiler((long)42)]
|
||||
public static long TestReadLong(ref long data)
|
||||
{
|
||||
return Volatile.Read(ref data) + Volatile.Read(ref data);
|
||||
}
|
||||
|
||||
[TestCompiler((ulong)42)]
|
||||
public static ulong TestReadULong(ref ulong data)
|
||||
{
|
||||
return Volatile.Read(ref data) + Volatile.Read(ref data);
|
||||
}
|
||||
|
||||
[TestCompiler(42.0f)]
|
||||
public static float TestReadFloat(ref float data)
|
||||
{
|
||||
return Volatile.Read(ref data);
|
||||
}
|
||||
|
||||
[TestCompiler(42.0)]
|
||||
public static double TestReadDouble(ref double data)
|
||||
{
|
||||
return Volatile.Read(ref data);
|
||||
}
|
||||
|
||||
public struct UIntPtrProvider : IArgumentProvider
|
||||
{
|
||||
public object Value => UIntPtr.Zero;
|
||||
}
|
||||
|
||||
[TestCompiler(typeof(UIntPtrProvider))]
|
||||
public static UIntPtr TestReadUIntPtr(ref UIntPtr data)
|
||||
{
|
||||
return Volatile.Read(ref data);
|
||||
}
|
||||
|
||||
[TestCompiler]
|
||||
public static int TestWriteBool()
|
||||
{
|
||||
var data = false;
|
||||
Volatile.Write(ref data, true);
|
||||
return data ? 1 : 0;
|
||||
}
|
||||
|
||||
[TestCompiler((byte)42)]
|
||||
public static int TestWriteByte(ref byte data)
|
||||
{
|
||||
var result = data;
|
||||
Volatile.Write(ref data, 1);
|
||||
return result + data;
|
||||
}
|
||||
|
||||
[TestCompiler((sbyte)42)]
|
||||
public static int TestWriteSByte(ref sbyte data)
|
||||
{
|
||||
var result = data;
|
||||
Volatile.Write(ref data, 2);
|
||||
return result + data;
|
||||
}
|
||||
|
||||
[TestCompiler((short)42)]
|
||||
public static int TestWriteShort(ref short data)
|
||||
{
|
||||
var result = data;
|
||||
Volatile.Write(ref data, 3);
|
||||
return result + data;
|
||||
}
|
||||
|
||||
[TestCompiler((ushort)42)]
|
||||
public static int TestWriteUShort(ref ushort data)
|
||||
{
|
||||
var result = data;
|
||||
Volatile.Write(ref data, 4);
|
||||
return result + data;
|
||||
}
|
||||
|
||||
[TestCompiler(42)]
|
||||
public static int TestWriteInt(ref int data)
|
||||
{
|
||||
var result = data;
|
||||
Volatile.Write(ref data, 5);
|
||||
return result + data;
|
||||
}
|
||||
|
||||
[TestCompiler(42u)]
|
||||
public static uint TestWriteUInt(ref uint data)
|
||||
{
|
||||
var result = data;
|
||||
Volatile.Write(ref data, 6);
|
||||
return result + data;
|
||||
}
|
||||
|
||||
[TestCompiler((long)42)]
|
||||
public static long TestWriteLong(ref long data)
|
||||
{
|
||||
var result = data;
|
||||
Volatile.Write(ref data, 7);
|
||||
return result + data;
|
||||
}
|
||||
|
||||
[TestCompiler((ulong)42)]
|
||||
public static ulong TestWriteULong(ref ulong data)
|
||||
{
|
||||
var result = data;
|
||||
Volatile.Write(ref data, 8);
|
||||
return result + data;
|
||||
}
|
||||
|
||||
[TestCompiler(42.0f)]
|
||||
public static float TestWriteFloat(ref float data)
|
||||
{
|
||||
var result = data;
|
||||
Volatile.Write(ref data, 9);
|
||||
return result + data;
|
||||
}
|
||||
|
||||
[TestCompiler(42.0)]
|
||||
public static double TestWriteDouble(ref double data)
|
||||
{
|
||||
var result = data;
|
||||
Volatile.Write(ref data, 10);
|
||||
return result + data;
|
||||
}
|
||||
|
||||
[TestCompiler(typeof(UIntPtrProvider))]
|
||||
public static UIntPtr TestWriteUIntPtr(ref UIntPtr data)
|
||||
{
|
||||
var result = data;
|
||||
Volatile.Write(ref data, new UIntPtr(11));
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 631a9c909a1e35999f140f79ef90911a
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,351 @@
|
|||
using Burst.Compiler.IL.Tests.Helpers;
|
||||
using System.Linq.Expressions;
|
||||
using Unity.Mathematics;
|
||||
|
||||
namespace Burst.Compiler.IL.Tests
|
||||
{
|
||||
/// <summary>
|
||||
/// Tests a few single float functions for <see cref="Unity.Mathematics.math"/> functions.
|
||||
/// </summary>
|
||||
internal class TestUnityMath
|
||||
{
|
||||
[TestCompiler(DataRange.Standard)]
|
||||
public static float TestCos(float value)
|
||||
{
|
||||
return math.cos(value);
|
||||
}
|
||||
|
||||
[TestCompiler(DataRange.Standard)]
|
||||
public static float TestSin(float value)
|
||||
{
|
||||
return math.sin(value);
|
||||
}
|
||||
|
||||
[TestCompiler(DataRange.Standard)]
|
||||
public static float TestTan(float value)
|
||||
{
|
||||
return (float) math.tan(value);
|
||||
}
|
||||
|
||||
[TestCompiler(-1000000f)]
|
||||
[TestCompiler(-1.2f)]
|
||||
public static float TestTan2(float value)
|
||||
{
|
||||
return (float)math.tan(value);
|
||||
}
|
||||
|
||||
[TestCompiler(DataRange.Standard11)]
|
||||
public static float TestAcos(float value)
|
||||
{
|
||||
return math.acos(value);
|
||||
}
|
||||
|
||||
[TestCompiler(DataRange.Standard11)]
|
||||
public static float TestAsin(float value)
|
||||
{
|
||||
return math.asin(value);
|
||||
}
|
||||
|
||||
[TestCompiler(DataRange.Standard11)]
|
||||
public static float TestAtan(float value)
|
||||
{
|
||||
return (float)math.atan(value);
|
||||
}
|
||||
|
||||
[TestCompiler(DataRange.Standard)]
|
||||
public static float TestCosh(float value)
|
||||
{
|
||||
return math.cosh(value);
|
||||
}
|
||||
|
||||
[TestCompiler(DataRange.Standard)]
|
||||
public static float TestSinh(float value)
|
||||
{
|
||||
return math.sinh(value);
|
||||
}
|
||||
|
||||
[TestCompiler(DataRange.Standard)]
|
||||
public static float TestTanh(float value)
|
||||
{
|
||||
return (float)math.tanh(value);
|
||||
}
|
||||
|
||||
[TestCompiler(DataRange.StandardPositive)]
|
||||
public static float TestSqrt(float value)
|
||||
{
|
||||
return math.sqrt(value);
|
||||
}
|
||||
|
||||
[TestCompiler(DataRange.StandardPositive & ~DataRange.Zero)]
|
||||
public static float TestLog(float value)
|
||||
{
|
||||
return math.log(value);
|
||||
}
|
||||
|
||||
[TestCompiler(DataRange.StandardPositive & ~DataRange.Zero)]
|
||||
public static float TestLog10(float value)
|
||||
{
|
||||
return math.log10(value);
|
||||
}
|
||||
|
||||
[TestCompiler(DataRange.StandardPositive)]
|
||||
public static float TestExp(float value)
|
||||
{
|
||||
return math.exp(value);
|
||||
}
|
||||
|
||||
[TestCompiler(DataRange.Standard & ~(DataRange.Zero|DataRange.NaN), DataRange.Standard)]
|
||||
[TestCompiler(DataRange.Standard & ~DataRange.Zero, DataRange.Standard & ~DataRange.Zero)]
|
||||
public static float TestPow(float value, float power)
|
||||
{
|
||||
return math.pow(value, power);
|
||||
}
|
||||
|
||||
[TestCompiler(DataRange.Standard)]
|
||||
public static float TestAbsFloat(float value)
|
||||
{
|
||||
return math.abs(value);
|
||||
}
|
||||
|
||||
[TestCompiler(DataRange.Standard, DataRange.Standard)]
|
||||
public static int TestMaxInt(int left, int right)
|
||||
{
|
||||
return math.max(left, right);
|
||||
}
|
||||
|
||||
[TestCompiler(DataRange.Standard, DataRange.Standard)]
|
||||
public static int TestMinInt(int left, int right)
|
||||
{
|
||||
return math.min(left, right);
|
||||
}
|
||||
|
||||
[TestCompiler(DataRange.Standard, DataRange.Standard)]
|
||||
public static float TestMaxfloat(float left, float right)
|
||||
{
|
||||
return math.max(left, right);
|
||||
}
|
||||
|
||||
[TestCompiler(DataRange.Standard, DataRange.Standard)]
|
||||
public static float TestMinfloat(float left, float right)
|
||||
{
|
||||
return math.min(left, right);
|
||||
}
|
||||
|
||||
[TestCompiler(DataRange.Standard & ~DataRange.NaN)]
|
||||
public static float TestSignFloat(float value)
|
||||
{
|
||||
return math.sign(value);
|
||||
}
|
||||
|
||||
[TestCompiler(-123.45)]
|
||||
[TestCompiler(-1E-20)]
|
||||
[TestCompiler(0.0)]
|
||||
[TestCompiler(1E-10)]
|
||||
[TestCompiler(123.45)]
|
||||
[TestCompiler(double.NegativeInfinity)]
|
||||
[TestCompiler(double.NaN)]
|
||||
[TestCompiler(double.PositiveInfinity)]
|
||||
public static double TestSignDouble(double value)
|
||||
{
|
||||
return math.sign(value);
|
||||
}
|
||||
|
||||
[TestCompiler(DataRange.Standard)]
|
||||
public static float TestCeilingfloat(float value)
|
||||
{
|
||||
return math.ceil(value);
|
||||
}
|
||||
|
||||
[TestCompiler(DataRange.Standard)]
|
||||
public static float TestFloorfloat(float value)
|
||||
{
|
||||
return math.floor(value);
|
||||
}
|
||||
|
||||
[TestCompiler(DataRange.Standard)]
|
||||
public static float TestRoundfloat(float value)
|
||||
{
|
||||
return math.round(value);
|
||||
}
|
||||
|
||||
[TestCompiler(DataRange.Standard)]
|
||||
public static float TestTruncatefloat(float value)
|
||||
{
|
||||
return math.trunc(value);
|
||||
}
|
||||
|
||||
private readonly static float3 a = new float3(1, 2, 3);
|
||||
|
||||
[TestCompiler]
|
||||
public static bool TestStaticLoad()
|
||||
{
|
||||
var cmp = a == new float3(1, 2, 3);
|
||||
|
||||
return cmp.x && cmp.y && cmp.z;
|
||||
}
|
||||
|
||||
[TestCompiler(42L)]
|
||||
public static long TestLongCountbits(long value)
|
||||
{
|
||||
return math.countbits(value) - 1;
|
||||
}
|
||||
|
||||
[TestCompiler(42L)]
|
||||
public static long TestLongLzcnt(long value)
|
||||
{
|
||||
return math.lzcnt(value) - 1;
|
||||
}
|
||||
|
||||
[TestCompiler(42L)]
|
||||
public static long TestLongTzcnt(long value)
|
||||
{
|
||||
return math.tzcnt(value) - 1;
|
||||
}
|
||||
|
||||
[TestCompiler(typeof(ReturnBox), (ushort)42)]
|
||||
public static unsafe void TestUshortAddInt2(int2* o, ushort i)
|
||||
{
|
||||
*o = i + new int2(0, 0);
|
||||
}
|
||||
|
||||
[TestCompiler(typeof(ReturnBox), (ushort)42)]
|
||||
public static unsafe void TestInt2AddUshort(int2* o, ushort i)
|
||||
{
|
||||
*o = new int2(0, 0) + i;
|
||||
}
|
||||
|
||||
[TestCompiler(typeof(ReturnBox), (ushort)42)]
|
||||
public static unsafe void TestUshortSubInt2(int2* o, ushort i)
|
||||
{
|
||||
*o = i - new int2(0, 0);
|
||||
}
|
||||
|
||||
[TestCompiler(typeof(ReturnBox), (ushort)42)]
|
||||
public static unsafe void TestInt2SubUshort(int2* o, ushort i)
|
||||
{
|
||||
*o = new int2(0, 0) - i;
|
||||
}
|
||||
|
||||
[TestCompiler(typeof(ReturnBox), (ushort)42)]
|
||||
public static unsafe void TestUshortMulInt2(int2* o, ushort i)
|
||||
{
|
||||
*o = i * new int2(0, 0);
|
||||
}
|
||||
|
||||
[TestCompiler(typeof(ReturnBox), (ushort)42)]
|
||||
public static unsafe void TestInt2MulUshort(int2* o, ushort i)
|
||||
{
|
||||
*o = new int2(0, 0) * i;
|
||||
}
|
||||
|
||||
[TestCompiler(typeof(ReturnBox), (ushort)42)]
|
||||
public static unsafe void TestUshortDivInt2(int2* o, ushort i)
|
||||
{
|
||||
*o = i / new int2(1, 1);
|
||||
}
|
||||
|
||||
[TestCompiler(typeof(ReturnBox), (ushort)42)]
|
||||
public static unsafe void TestInt2DivUshort(int2* o, ushort i)
|
||||
{
|
||||
*o = new int2(0, 0) / i;
|
||||
}
|
||||
|
||||
[TestCompiler(typeof(ReturnBox), (ushort)42)]
|
||||
public static unsafe void TestUshortModInt2(int2* o, ushort i)
|
||||
{
|
||||
*o = i % new int2(1, 1);
|
||||
}
|
||||
|
||||
[TestCompiler(typeof(ReturnBox), (ushort)42)]
|
||||
public static unsafe void TestInt2ModUshort(int2* o, ushort i)
|
||||
{
|
||||
*o = new int2(0, 0) % i;
|
||||
}
|
||||
|
||||
[TestCompiler((ushort)42)]
|
||||
public static unsafe int TestUshortEqInt2(ushort i)
|
||||
{
|
||||
return math.all(i == new int2(0, 0)) ? 1 : 0;
|
||||
}
|
||||
|
||||
[TestCompiler((ushort)42)]
|
||||
public static unsafe int TestInt2EqUshort(ushort i)
|
||||
{
|
||||
return math.all(new int2(0, 0) == i) ? 1 : 0;
|
||||
}
|
||||
|
||||
[TestCompiler((ushort)42)]
|
||||
public static unsafe int TestUshortNeInt2(ushort i)
|
||||
{
|
||||
return math.all(i != new int2(0, 0)) ? 1 : 0;
|
||||
}
|
||||
|
||||
[TestCompiler((ushort)42)]
|
||||
public static unsafe int TestInt2NeUshort(ushort i)
|
||||
{
|
||||
return math.all(new int2(0, 0) != i) ? 1 : 0;
|
||||
}
|
||||
|
||||
[TestCompiler((ushort)42)]
|
||||
public static unsafe int TestUshortGeInt2(ushort i)
|
||||
{
|
||||
return math.all(i >= new int2(0, 0)) ? 1 : 0;
|
||||
}
|
||||
|
||||
[TestCompiler((ushort)42)]
|
||||
public static unsafe int TestInt2GeUshort(ushort i)
|
||||
{
|
||||
return math.all(new int2(0, 0) >= i) ? 1 : 0;
|
||||
}
|
||||
|
||||
[TestCompiler((ushort)42)]
|
||||
public static unsafe int TestUshortGtInt2(ushort i)
|
||||
{
|
||||
return math.all(i > new int2(0, 0)) ? 1 : 0;
|
||||
}
|
||||
|
||||
[TestCompiler((ushort)42)]
|
||||
public static unsafe int TestInt2GtUshort(ushort i)
|
||||
{
|
||||
return math.all(new int2(0, 0) > i) ? 1 : 0;
|
||||
}
|
||||
|
||||
[TestCompiler((ushort)42)]
|
||||
public static unsafe int TestUshortLtInt2(ushort i)
|
||||
{
|
||||
return math.all(i < new int2(0, 0)) ? 1 : 0;
|
||||
}
|
||||
|
||||
[TestCompiler((ushort)42)]
|
||||
public static unsafe int TestInt2LtUshort(ushort i)
|
||||
{
|
||||
return math.all(new int2(0, 0) < i) ? 1 : 0;
|
||||
}
|
||||
|
||||
[TestCompiler((ushort)42)]
|
||||
public static unsafe int TestUshortLeInt2(ushort i)
|
||||
{
|
||||
return math.all(i <= new int2(0, 0)) ? 1 : 0;
|
||||
}
|
||||
|
||||
[TestCompiler((ushort)42)]
|
||||
public static unsafe int TestInt2LeUshort(ushort i)
|
||||
{
|
||||
return math.all(new int2(0, 0) <= i) ? 1 : 0;
|
||||
}
|
||||
|
||||
[TestCompiler(42.0f)]
|
||||
public static float TestSqrtAndAcosIsDefinedBehaviour(float a)
|
||||
{
|
||||
// This sqrt call will get folded away, but we need it here because it exhibits the bug.
|
||||
if (math.sqrt(4) == 2)
|
||||
{
|
||||
return math.acos(a);
|
||||
}
|
||||
else
|
||||
{
|
||||
return 42;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 3d355504e32f39b89ef31f85cad154a5
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,184 @@
|
|||
using Unity.Collections.LowLevel.Unsafe;
|
||||
using Unity.Burst;
|
||||
using Unity.Burst.CompilerServices;
|
||||
|
||||
#if BURST_TESTS_ONLY
|
||||
namespace Unity.Collections.LowLevel.Unsafe
|
||||
{
|
||||
internal class DisposeSentinel
|
||||
{
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
namespace Burst.Compiler.IL.Tests
|
||||
{
|
||||
/// <summary>
|
||||
/// Tests related to usage of partial managed objects (e.g loading null or storing null
|
||||
/// reference to a struct, typically used by NativeArray DisposeSentinel)
|
||||
/// </summary>
|
||||
internal class PartialManaged
|
||||
{
|
||||
#if BURST_TESTS_ONLY || ENABLE_UNITY_COLLECTIONS_CHECKS
|
||||
[TestCompiler]
|
||||
public static int TestWriteNullReference()
|
||||
{
|
||||
var element = new Element();
|
||||
WriteNullReference(out element.Reference);
|
||||
return element.Value;
|
||||
}
|
||||
|
||||
[BurstDiscard]
|
||||
private static void WriteNullReference(out DisposeSentinel reference)
|
||||
{
|
||||
reference = null;
|
||||
}
|
||||
|
||||
private struct Element
|
||||
{
|
||||
#pragma warning disable 0649
|
||||
public int Value;
|
||||
public DisposeSentinel Reference;
|
||||
#pragma warning restore 0649
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
[TestCompiler]
|
||||
public static void AssignNullToLocalVariableClass()
|
||||
{
|
||||
MyClass x = null;
|
||||
#pragma warning disable 0219
|
||||
MyClass value = x;
|
||||
#pragma warning restore 0219
|
||||
}
|
||||
|
||||
[TestCompiler(ExpectCompilerException = true, ExpectedDiagnosticId = DiagnosticId.ERR_CallingManagedMethodNotSupported)]
|
||||
public static int GetIndexOfCharFomString()
|
||||
{
|
||||
return "abc".IndexOf('b');
|
||||
}
|
||||
|
||||
struct StructWithManaged
|
||||
{
|
||||
#pragma warning disable 0649
|
||||
public MyClass myClassValue;
|
||||
public string stringValue;
|
||||
public object objectValue;
|
||||
public float[] arrayValue;
|
||||
|
||||
public int value;
|
||||
#pragma warning restore 0649
|
||||
}
|
||||
|
||||
[TestCompiler(ExpectCompilerException = true, ExpectedDiagnosticId = DiagnosticId.ERR_TypeNotSupported)]
|
||||
public static int AccessClassFromStruct()
|
||||
{
|
||||
var val = new StructWithManaged();
|
||||
val.myClassValue.value = val.value;
|
||||
return val.myClassValue.value;
|
||||
}
|
||||
|
||||
[TestCompiler(ExpectCompilerException = true, ExpectedDiagnosticId = DiagnosticId.ERR_TypeNotSupported)]
|
||||
public static void AccessStringFromStruct()
|
||||
{
|
||||
var val = new StructWithManaged();
|
||||
#pragma warning disable 0219
|
||||
var p = val.stringValue = "abc";
|
||||
#pragma warning restore 0219
|
||||
}
|
||||
|
||||
[TestCompiler(ExpectCompilerException = true, ExpectedDiagnosticId = DiagnosticId.ERR_TypeNotSupported)]
|
||||
public static void AccessObjectFromStruct()
|
||||
{
|
||||
var val = new StructWithManaged();
|
||||
#pragma warning disable 0219
|
||||
var p = val.objectValue;
|
||||
p = new object();
|
||||
#pragma warning restore 0219
|
||||
}
|
||||
|
||||
[TestCompiler(ExpectCompilerException = true, ExpectedDiagnosticId = DiagnosticId.ERR_TypeNotSupported)]
|
||||
public static void AccessArrayFromStruct()
|
||||
{
|
||||
var val = new StructWithManaged();
|
||||
var p = val.arrayValue;
|
||||
p[0] = val.value;
|
||||
}
|
||||
|
||||
[TestCompiler(ExpectCompilerException = true, ExpectedDiagnosticId = DiagnosticId.ERR_TypeNotSupported)]
|
||||
public static int GetValueFromStructWithClassField()
|
||||
{
|
||||
var val = new StructWithManaged();
|
||||
val.value = 5;
|
||||
|
||||
return val.value;
|
||||
}
|
||||
|
||||
[TestCompiler(ExpectCompilerException = true, ExpectedDiagnosticId = DiagnosticId.ERR_InstructionNewobjWithManagedTypeNotSupported)]
|
||||
public static void NewMyClass()
|
||||
{
|
||||
#pragma warning disable 0219
|
||||
var value = new MyClass();
|
||||
#pragma warning restore 0219
|
||||
}
|
||||
|
||||
private class MyClass
|
||||
{
|
||||
public int value;
|
||||
}
|
||||
|
||||
private class SomeClassWithMixedStatics
|
||||
{
|
||||
public static int SomeInt = 42;
|
||||
|
||||
public static readonly SharedStatic<int> SomeSharedStatic = SharedStatic<int>.GetOrCreate<int>();
|
||||
|
||||
[BurstDiscard]
|
||||
private static void DoSomethingWithStaticInt(ref int x) => x = SomeInt;
|
||||
|
||||
[IgnoreWarning(1371)]
|
||||
public static int DoSomething()
|
||||
{
|
||||
ref var data = ref SomeSharedStatic.Data;
|
||||
DoSomethingWithStaticInt(ref data);
|
||||
return SomeSharedStatic.Data;
|
||||
}
|
||||
}
|
||||
|
||||
[TestCompiler(OverrideManagedResult = 0)]
|
||||
public static int DoSomethingThatUsesMixedStatics()
|
||||
{
|
||||
return SomeClassWithMixedStatics.DoSomething();
|
||||
}
|
||||
|
||||
private class SomeClassWithMixedStaticsWithExplicitStaticConstructor
|
||||
{
|
||||
public static int SomeInt = 42;
|
||||
|
||||
public static readonly SharedStatic<int> SomeSharedStatic = SharedStatic<int>.GetOrCreate<int>();
|
||||
|
||||
static SomeClassWithMixedStaticsWithExplicitStaticConstructor()
|
||||
{
|
||||
SomeInt = 1;
|
||||
}
|
||||
|
||||
[BurstDiscard]
|
||||
private static void DoSomethingWithStaticInt(ref int x) => x = SomeInt;
|
||||
|
||||
[IgnoreWarning(1371)]
|
||||
public static int DoSomething()
|
||||
{
|
||||
ref var data = ref SomeSharedStatic.Data;
|
||||
DoSomethingWithStaticInt(ref data);
|
||||
return SomeSharedStatic.Data;
|
||||
}
|
||||
}
|
||||
|
||||
[TestCompiler(OverrideManagedResult = 0)]
|
||||
public static int DoSomethingThatUsesMixedStaticsWithExplicitStaticConstructor()
|
||||
{
|
||||
return SomeClassWithMixedStaticsWithExplicitStaticConstructor.DoSomething();
|
||||
}
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue