853 lines
21 KiB
C#
853 lines
21 KiB
C#
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;
|
|
}
|
|
}
|
|
}
|