-
Notifications
You must be signed in to change notification settings - Fork 4.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Optimization for full range checks (#70145) #70222
Changes from 8 commits
8f2935d
81523b6
05022dd
ebbaa3e
5548ead
4d7aaec
2da383c
01d7d48
8acf1cc
9a85185
d11970c
7c2cbd5
4faafae
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -11406,6 +11406,21 @@ GenTree* Compiler::fgMorphSmpOp(GenTree* tree, MorphAddrContext* mac) | |||||
assert(op2 == tree->AsOp()->gtGetOp2()); | ||||||
} | ||||||
|
||||||
if (opts.OptimizationEnabled() && fgGlobalMorph) | ||||||
{ | ||||||
if (op2->IsIntegralConst() || op1->IsIntegralConst()) | ||||||
{ | ||||||
if (tree->OperIs(GT_GT, GT_LT, GT_LE, GT_GE)) | ||||||
{ | ||||||
tree = fgOptimizeRelationalComparisonWithFullRangeConst(tree->AsOp()); | ||||||
if (tree->OperIs(GT_CNS_INT, GT_COMMA)) | ||||||
{ | ||||||
return tree; | ||||||
} | ||||||
} | ||||||
} | ||||||
} | ||||||
|
||||||
COMPARE: | ||||||
|
||||||
noway_assert(tree->OperIsCompare()); | ||||||
|
@@ -12631,6 +12646,90 @@ GenTree* Compiler::fgOptimizeEqualityComparisonWithConst(GenTreeOp* cmp) | |||||
return cmp; | ||||||
} | ||||||
|
||||||
//------------------------------------------------------------------------ | ||||||
// fgOptimizeRelationalComparisonWithFullRangeConst: optimizes a comparison operation. | ||||||
// | ||||||
// Recognizes "Always false" comparisons against various full range constant operands and morphs | ||||||
// them into zero. | ||||||
// | ||||||
// Arguments: | ||||||
// cmp - the GT_LT/GT_GT tree to morph. | ||||||
// | ||||||
// Return Value: | ||||||
// 1. The unmodified "cmp" tree. | ||||||
// 2. A CNS_INT node containing zero. | ||||||
// 3. A GT_COMMA node containing side effects along with a CNS_INT node containing zero | ||||||
// Assumptions: | ||||||
// The second operand is an integral constant or the first operand is an integral constant. | ||||||
// | ||||||
GenTree* Compiler::fgOptimizeRelationalComparisonWithFullRangeConst(GenTreeOp* cmp) | ||||||
{ | ||||||
|
||||||
int64_t lhsMin; | ||||||
int64_t lhsMax; | ||||||
if (cmp->gtGetOp1()->IsIntegralConst()) | ||||||
{ | ||||||
lhsMin = cmp->gtGetOp1()->AsIntConCommon()->IntegralValue(); | ||||||
lhsMax = lhsMin; | ||||||
} | ||||||
else | ||||||
{ | ||||||
IntegralRange lhsRange = IntegralRange::ForNode(cmp->gtGetOp1(), this); | ||||||
lhsMin = IntegralRange::SymbolicToRealValue(lhsRange.GetLowerBound()); | ||||||
lhsMax = IntegralRange::SymbolicToRealValue(lhsRange.GetUpperBound()); | ||||||
} | ||||||
|
||||||
int64_t rhsMin; | ||||||
int64_t rhsMax; | ||||||
if (cmp->gtGetOp2()->IsIntegralConst()) | ||||||
{ | ||||||
rhsMin = cmp->gtGetOp2()->AsIntConCommon()->IntegralValue(); | ||||||
rhsMax = rhsMin; | ||||||
} | ||||||
else | ||||||
{ | ||||||
IntegralRange rhsRange = IntegralRange::ForNode(cmp->gtGetOp2(), this); | ||||||
rhsMin = IntegralRange::SymbolicToRealValue(rhsRange.GetLowerBound()); | ||||||
rhsMax = IntegralRange::SymbolicToRealValue(rhsRange.GetUpperBound()); | ||||||
} | ||||||
|
||||||
genTreeOps op = cmp->gtOper; | ||||||
if ((op != GT_LT) && (op != GT_LE)) | ||||||
{ | ||||||
op = GenTree::SwapRelop(op); | ||||||
std::swap(lhsMin, rhsMin); | ||||||
std::swap(lhsMax, rhsMax); | ||||||
} | ||||||
|
||||||
int64_t lefOpValue = lhsMin; | ||||||
int64_t rightOpValue = rhsMax; | ||||||
|
||||||
if (cmp->IsUnsigned() && lefOpValue == -1 && lhsMax == -1) | ||||||
{ | ||||||
rightOpValue = -1; | ||||||
} | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What's an example this catches? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't like the part of code, but I haven't come up with an idea how to get ride of the magic number (-1) yet. The idea here is that
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. For unsigned comparisons a signed interval that spans 0 represents two distinct intervals, i.e. for
So the "generalized" code here would need to check these conditions. I agree this is a bit tricky, so it is fine with me to special case this, although it would be nice to find a way to shape the code such that we avoid the "normal" check below in the special case. Also, I think the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The tricky part here is that when rhs is ulong then
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Could you please explain this idea in more details, I'm not sure I can understand how to apply this. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I guess you would do something like: if (cmp->IsUnsigned())
{
if ((lhsMin < 0) && (lhsMax >= 0))
{
// [0, (uint64_t)lhsMax] U [(uint64_t)lhsMin, MaxValue]
lhsMin = 0;
lhsMax = -1;
}
if ((rhsMin < 0) && (rhsMax >= 0))
{
// [0, (uint64_t)rhsMax] U [(uint64_t)rhsMin, MaxValue]
rhsMin = 0;
rhsMax = -1;
}
}
int foldValue;
if (cmp->IsUnsigned())
{
if ((op == GT_LT && ((uint64_t)lhsMax < (uint64_t)rhsMin) ||
(op == GT_LE && ((uint64_t)lhsMax <= (uint64_t)rhsMin))
{
foldValue = 1;
}
else if ((op == GT_LT && ((uint64_t)lhsMin >= (uint64_t)rhsMax) ||
(op == GT_LE && ((uint64_t)lhsMin > (uint64_t)rhsMax))
{
foldValue = 0;
}
else
{
return;
}
}
else
{
if ((op == GT_LT && (lhsMax < rhsMin) ||
(op == GT_LE && (lhsMax <= rhsMin))
{
foldValue = 1;
}
else if ((op == GT_LT && (lhsMin >= rhsMax) ||
(op == GT_LE && (lhsMin > rhsMax))
{
foldValue = 0;
}
else
{
return;
}
}
// fold to foldValue here But, it's hard to get all the cases right :-) I would probably double check with something like https://github.com/jakobbotsch/Fuzzlyn. I will definitely run that on this PR before merging. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. For example, running Fuzzlyn on your PR in the current shape quickly finds examples. I did: > .\Fuzzlyn.exe --host C:\dev\dotnet\runtime2\artifacts\tests\coreclr\windows.x64.Checked\Tests\Core_Root\corerun.exe --num-programs 10000000 --parallelism 8
Found example with seed 10360326530109389226
> .\Fuzzlyn.exe --host C:\dev\dotnet\runtime2\artifacts\tests\coreclr\windows.x64.Checked\Tests\Core_Root\corerun.exe --reduce --seed 10360326530109389226
Simplifying Coarsely. Total elapsed: 00:00:10. Method 51/51.
Simplifying Statements. Total elapsed: 00:00:15. Iter: 107/107
Simplifying Expressions. Total elapsed: 00:00:16. Iter: 478/478
Simplifying Members. Total elapsed: 00:00:19. Iter: 9/9
Simplifying Statements. Total elapsed: 00:00:19. Iter: 12/12
Simplifying Expressions. Total elapsed: 00:00:19. Iter: 45/45
Simplifying Members. Total elapsed: 00:00:20. Iter: 7/7
Simplifying Statements. Total elapsed: 00:00:20. Iter: 8/8
Simplifying Expressions. Total elapsed: 00:00:20. Iter: 35/35
Simplifying Members. Total elapsed: 00:00:20. Iter: 6/6
Simplifying Statements. Total elapsed: 00:00:20. Iter: 8/8
Simplifying Expressions. Total elapsed: 00:00:20. Iter: 34/34
Simplifying Members. Total elapsed: 00:00:20. Iter: 6/6 which outputs: // Generated by Fuzzlyn v1.5 on 2022-06-14 19:20:16
// Run on X64 Windows
// Seed: 10360326530109389226
// Reduced from 64.1 KiB to 0.5 KiB in 00:00:23
// Debug:
// Release: Outputs 0
public class Program
{
public static IRuntime s_rt;
public static uint s_4;
public static void Main()
{
s_rt = new Runtime();
bool vr1 = M1(0);
}
public static bool M1(short arg0)
{
if ((12729537629719743250UL < (uint)arg0))
{
s_rt.WriteLine(s_4);
}
return true;
}
}
public interface IRuntime
{
void WriteLine<T>(T value);
}
public class Runtime : IRuntime
{
public void WriteLine<T>(T value) => System.Console.WriteLine(value);
} This program is incorrect with the current PR. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Looks like an amazing tool. I played with it a little bit and got something like this: // Generated by Fuzzlyn v1.5 on 2022-06-15 09:15:55
// Run on X64 Windows
// Seed: 6538447736931409473
// Reduced from 109.8 KiB to 0.2 KiB in 00:00:53
// Debug: Outputs True
// Release: Outputs False
public class Program
{
public static long s_33 = 1;
public static bool s_50;
public static void Main()
{
uint vr0 = (uint)(-s_33);
s_50 = 4038847739U < vr0;
System.Console.WriteLine(s_50);
}
} Does it mean that if I cut out the code (from main) and build it in Debug then it returns True and if I build it in Release then it returns False? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, that's what it means (and also tiered compilation has to be disabled). There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. FWIW, your treatment of unsigned comparisons is still wrong, you cannot use the signed comparisons for the interval checks in that case. It is probably the reason for this problem. I would suggest you shape the code somewhat like the example I posted earlier. |
||||||
|
||||||
if ((op == GT_LT && lefOpValue == rightOpValue) || (op == GT_LE && lefOpValue > rightOpValue)) | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Shouldn't the first check be generalized to There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
It may work with GT_LT, but what about GT_LE? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, by "first check" I meant the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Then it would look like There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ah, I just meant |
||||||
{ | ||||||
GenTree* ret = gtNewZeroConNode(TYP_INT); | ||||||
|
||||||
if (gtTreeHasSideEffects(cmp, GTF_SIDE_EFFECT)) | ||||||
{ | ||||||
return cmp; | ||||||
} | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Trying to presave the side effects gave me many regressions, so I decided to cut it out for now. |
||||||
|
||||||
ret->SetVNsFromNode(cmp); | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
(Given that we folded, this is more precise) |
||||||
|
||||||
DEBUG_DESTROY_NODE(cmp); | ||||||
|
||||||
INDEBUG(ret->gtDebugFlags |= GTF_DEBUG_NODE_MORPHED); | ||||||
|
||||||
return ret; | ||||||
} | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It doesn't seem right that this can only fold things into false. What about when the comparison is always true? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I can't think of a case when the comparison is always true. There are 7 typical trees which I'm testing on (value types may vary but the trees are always generalized to the 7 cases):
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. So for example: There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. One example would be: There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We generally do not see There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do you know how to generate the always true condition but with GT_LE? I'm considering should we be bothered with such a case at all. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Given that you already have the intervals I think the actual check itself is so simple that there is no reason not to add it, it should not be more than a couple of lines. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I tried to apply this condition, which considering only LT for simplicity and it gave me 1700+ improvements during the spmi asmdiff run, which is suspicious :)
Then I tried to check which Op is const to make the condition more strict:
It works fine and there are not so many improvements. What do you think of this? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||||||
|
||||||
return cmp; | ||||||
} | ||||||
|
||||||
//------------------------------------------------------------------------ | ||||||
// fgOptimizeRelationalComparisonWithConst: optimizes a comparison operation. | ||||||
// | ||||||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,204 @@ | ||
// Licensed to the .NET Foundation under one or more agreements. | ||
// The .NET Foundation licenses this file to you under the MIT license. | ||
|
||
// unit test for the full range comparison optimization | ||
|
||
using System; | ||
using System.Runtime.CompilerServices; | ||
|
||
public class FullRangeComparisonTest | ||
{ | ||
// Class for testing side effects promotion | ||
public class SideEffects | ||
{ | ||
public byte B; | ||
} | ||
|
||
[MethodImpl(MethodImplOptions.NoInlining)] | ||
public static bool EqualsOrGreaterThan_MinValue_RHSConst_Byte(byte b) => b >= 0; | ||
|
||
[MethodImpl(MethodImplOptions.NoInlining)] | ||
public static bool EqualsOrGreaterThan_MinValue_RHSConst_Short(short s) => s >= short.MinValue; | ||
|
||
[MethodImpl(MethodImplOptions.NoInlining)] | ||
public static bool EqualsOrGreaterThan_MinValue_RHSConst_Int(int i) => i >= int.MinValue; | ||
|
||
[MethodImpl(MethodImplOptions.NoInlining)] | ||
public static bool EqualsOrGreaterThan_MinValue_RHSConst_Long(long l) => l >= long.MinValue; | ||
|
||
[MethodImpl(MethodImplOptions.NoInlining)] | ||
public static bool EqualsOrLessThan_MaxValue_RHSConst_Byte(byte b) => b <= byte.MaxValue; | ||
|
||
[MethodImpl(MethodImplOptions.NoInlining)] | ||
public static bool EqualsOrLessThan_MaxValue_RHSConst_Short(short s) => s <= short.MaxValue; | ||
|
||
[MethodImpl(MethodImplOptions.NoInlining)] | ||
public static bool EqualsOrLessThan_MaxValue_RHSConst_Int(int i) => i <= int.MaxValue; | ||
|
||
[MethodImpl(MethodImplOptions.NoInlining)] | ||
public static bool EqualsOrLessThan_MaxValue_RHSConst_Long(long l) => l <= long.MaxValue; | ||
|
||
[MethodImpl(MethodImplOptions.NoInlining)] | ||
public static bool EqualsOrLessThan_MaxValue_RHSConst_UShort(ushort us) => us <= ushort.MaxValue; | ||
|
||
[MethodImpl(MethodImplOptions.NoInlining)] | ||
public static bool EqualsOrLessThan_MaxValue_RHSConst_UInt(uint ui) => ui <= uint.MaxValue; | ||
|
||
[MethodImpl(MethodImplOptions.NoInlining)] | ||
public static bool EqualsOrLessThan_MaxValue_RHSConst_ULong(ulong ul) => ul <= uint.MaxValue; | ||
|
||
[MethodImpl(MethodImplOptions.NoInlining)] | ||
public static bool EqualsOrLessThan_MinValue_LHSConst_Byte(byte b) => 0 <= b; | ||
[MethodImpl(MethodImplOptions.NoInlining)] | ||
public static bool EqualsOrGreaterThan_MinValue_LHSConst_Short(short i) => short.MinValue <= i; | ||
|
||
[MethodImpl(MethodImplOptions.NoInlining)] | ||
public static bool EqualsOrLessThan_MinValue_LHSConst_Int(int i) => int.MinValue <= i; | ||
|
||
[MethodImpl(MethodImplOptions.NoInlining)] | ||
public static bool EqualsOrLessThan_MinValue_LHSConst_Long(long l) => long.MinValue <= l; | ||
|
||
[MethodImpl(MethodImplOptions.NoInlining)] | ||
public static bool EqualsOrGreaterThan_MaxValue_LHSConst_Byte(byte b) => byte.MaxValue >= b; | ||
|
||
[MethodImpl(MethodImplOptions.NoInlining)] | ||
public static bool EqualsOrGreaterThan_MaxValue_LHSConst_Short(short s) => short.MaxValue >= s; | ||
|
||
[MethodImpl(MethodImplOptions.NoInlining)] | ||
public static bool EqualsOrGreaterThan_MaxValue_LHSConst_Int(int i) => int.MaxValue >= i; | ||
|
||
[MethodImpl(MethodImplOptions.NoInlining)] | ||
public static bool EqualsOrGreaterThan_MaxValue_LHSConst_Long(long l) => long.MaxValue >= l; | ||
|
||
[MethodImpl(MethodImplOptions.NoInlining)] | ||
public static bool EqualsOrGreaterThan_MaxValue_LHSConst_SideEffects(SideEffects c) => c.B <= 255; | ||
public static int Main() | ||
{ | ||
// Optimize comparison with full range values | ||
// RHS Const Optimization | ||
if (!EqualsOrGreaterThan_MinValue_RHSConst_Byte(10)) | ||
{ | ||
Console.WriteLine("FullRangeComparisonTest:EqualsOrGreaterThan_MinValue_RHSConst_Byte(10) failed"); | ||
return 101; | ||
} | ||
|
||
if (!EqualsOrGreaterThan_MinValue_RHSConst_Short(-10)) | ||
{ | ||
Console.WriteLine("FullRangeComparisonTest:EqualsOrGreaterThan_MinValue_RHSConst_Short(10) failed"); | ||
return 101; | ||
} | ||
|
||
if (!EqualsOrGreaterThan_MinValue_RHSConst_Int(-10)) | ||
{ | ||
Console.WriteLine("FullRangeComparisonTest:EqualsOrGreaterThan_MinValue_RHSConst_Int(10) failed"); | ||
return 101; | ||
} | ||
|
||
if (!EqualsOrGreaterThan_MinValue_RHSConst_Long(-10)) | ||
{ | ||
Console.WriteLine("FullRangeComparisonTest:EqualsOrGreaterThan_MinValue_RHSConst_Long(10) failed"); | ||
return 101; | ||
} | ||
|
||
if (!EqualsOrLessThan_MaxValue_RHSConst_Byte(10)) | ||
{ | ||
Console.WriteLine("FullRangeComparisonTest:EqualsOrLessThan_MaxValue_RHSConst_Byte(10) failed"); | ||
return 101; | ||
} | ||
|
||
if (!EqualsOrLessThan_MaxValue_RHSConst_Short(10)) | ||
{ | ||
Console.WriteLine("FullRangeComparisonTest:EqualsOrLessThan_MaxValue_RHSConst_Short(10) failed"); | ||
return 101; | ||
} | ||
|
||
if (!EqualsOrLessThan_MaxValue_RHSConst_Int(10)) | ||
{ | ||
Console.WriteLine("FullRangeComparisonTest:EqualsOrLessThan_MaxValue_RHSConst_Int(10) failed"); | ||
return 101; | ||
} | ||
|
||
if (!EqualsOrLessThan_MaxValue_RHSConst_Long(10)) | ||
{ | ||
Console.WriteLine("FullRangeComparisonTest:EqualsOrLessThan_MaxValue_RHSConst_Long(10) failed"); | ||
return 101; | ||
} | ||
|
||
// LHS Const Optimization | ||
if (!EqualsOrLessThan_MinValue_LHSConst_Byte(10)) | ||
{ | ||
Console.WriteLine("FullRangeComparisonTest:EqualsOrLessThan_MinValue_LHSConst_Byte(10) failed"); | ||
return 101; | ||
} | ||
|
||
if (!EqualsOrLessThan_MinValue_LHSConst_Int(-10)) | ||
{ | ||
Console.WriteLine("FullRangeComparisonTest:EqualsOrLessThan_MinValue_LHSConst_Int(10) failed"); | ||
return 101; | ||
} | ||
|
||
if (!EqualsOrLessThan_MinValue_LHSConst_Long(-10)) | ||
{ | ||
Console.WriteLine("FullRangeComparisonTest:EqualsOrLessThan_MinValue_LHSConst_Long(10) failed"); | ||
return 101; | ||
} | ||
|
||
if (!EqualsOrGreaterThan_MaxValue_LHSConst_Byte(10)) | ||
{ | ||
Console.WriteLine("FullRangeComparisonTest:EqualsOrGreaterThan_MaxValue_LHSConst_Byte(10) failed"); | ||
return 101; | ||
} | ||
|
||
if (!EqualsOrGreaterThan_MaxValue_LHSConst_Int(10)) | ||
{ | ||
Console.WriteLine("FullRangeComparisonTest:EqualsOrGreaterThan_MaxValue_LHSConst_Int(10) failed"); | ||
return 101; | ||
} | ||
|
||
if (!EqualsOrGreaterThan_MaxValue_LHSConst_Long(10)) | ||
{ | ||
Console.WriteLine("FullRangeComparisonTest:EqualsOrGreaterThan_MaxValue_LHSConst_Long(10) failed"); | ||
return 101; | ||
} | ||
|
||
|
||
// Unsigned values | ||
if (!EqualsOrLessThan_MaxValue_RHSConst_UShort(10)) | ||
{ | ||
Console.WriteLine("FullRangeComparisonTest:EqualsOrLessThan_MaxValue_RHSConst_UShort(10) failed"); | ||
return 101; | ||
} | ||
|
||
if (!EqualsOrLessThan_MaxValue_RHSConst_UInt(10)) | ||
{ | ||
Console.WriteLine("FullRangeComparisonTest:EqualsOrLessThan_MaxValue_RHSConst_UInt(10) failed"); | ||
return 101; | ||
} | ||
|
||
if (!EqualsOrLessThan_MaxValue_RHSConst_ULong(10)) | ||
{ | ||
Console.WriteLine("FullRangeComparisonTest:EqualsOrLessThan_MaxValue_RHSConst_ULong(10) failed"); | ||
return 101; | ||
} | ||
|
||
// Side effects persist | ||
try | ||
{ | ||
EqualsOrGreaterThan_MaxValue_LHSConst_SideEffects(null); | ||
Console.WriteLine("FullRangeComparisonTest:EqualsOrGreaterThan_MaxValue_LHSConst_SideEffects(null) failed"); | ||
return 101; | ||
} | ||
catch (NullReferenceException ex) | ||
{ | ||
|
||
} | ||
catch (Exception ex) | ||
{ | ||
Console.WriteLine("FullRangeComparisonTest:EqualsOrGreaterThan_MaxValue_LHSConst_SideEffects(null) failed"); | ||
return 101; | ||
} | ||
|
||
Console.WriteLine("PASSED"); | ||
return 100; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
<Project Sdk="Microsoft.NET.Sdk"> | ||
<PropertyGroup> | ||
<OutputType>Exe</OutputType> | ||
</PropertyGroup> | ||
<PropertyGroup> | ||
<DebugType>PdbOnly</DebugType> | ||
<Optimize>True</Optimize> | ||
</PropertyGroup> | ||
<ItemGroup> | ||
<Compile Include="$(MSBuildProjectName).cs" /> | ||
</ItemGroup> | ||
</Project> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks like it needs to be updated.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ditto for the "Always false" in the summary above.