Skip to content

Commit e2fa2d7

Browse files
authored
Add bit shift intrinsic functions (#8569)
* add LeftShift, RightShift, RightShiftUnsigned intrinsic functions * Add "fast path" for all bit operator functions; change unit test to use Shouldly because fail messages will show the name of the failing function * Update to standardize on invoking IntrinsicFunctions methods, and add missing Modulo * Add IntrinsicFunctions.Unescape
1 parent 1af12df commit e2fa2d7

File tree

3 files changed

+119
-17
lines changed

3 files changed

+119
-17
lines changed

src/Build.UnitTests/Evaluation/Expander_Tests.cs

Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3400,22 +3400,25 @@ public void PropertyFunctionStaticMethodIntrinsicMaths()
34003400

34013401
double expectedResult = 9223372036854775807D + 20D;
34023402
Assert.Equal(expectedResult.ToString(), result);
3403+
}
34033404

3404-
result = expander.ExpandIntoStringLeaveEscaped(@"$([MSBuild]::BitwiseOr(40, 2))", ExpanderOptions.ExpandProperties, MockElementLocation.Instance);
3405-
3406-
Assert.Equal((40 | 2).ToString(), result);
3407-
3408-
result = expander.ExpandIntoStringLeaveEscaped(@"$([MSBuild]::BitwiseAnd(42, 2))", ExpanderOptions.ExpandProperties, MockElementLocation.Instance);
3409-
3410-
Assert.Equal((42 & 2).ToString(), result);
3411-
3412-
result = expander.ExpandIntoStringLeaveEscaped(@"$([MSBuild]::BitwiseXor(213, 255))", ExpanderOptions.ExpandProperties, MockElementLocation.Instance);
3413-
3414-
Assert.Equal((213 ^ 255).ToString(), result);
3405+
/// <summary>
3406+
/// Expand intrinsic property functions that call a bit operator
3407+
/// </summary>
3408+
[Fact]
3409+
public void PropertyFunctionStaticMethodIntrinsicBitOperations()
3410+
{
3411+
PropertyDictionary<ProjectPropertyInstance> pg = new PropertyDictionary<ProjectPropertyInstance>();
34153412

3416-
result = expander.ExpandIntoStringLeaveEscaped(@"$([MSBuild]::BitwiseNot(-43))", ExpanderOptions.ExpandProperties, MockElementLocation.Instance);
3413+
Expander<ProjectPropertyInstance, ProjectItemInstance> expander = new Expander<ProjectPropertyInstance, ProjectItemInstance>(pg, FileSystems.Default);
34173414

3418-
Assert.Equal((~-43).ToString(), result);
3415+
expander.ExpandIntoStringLeaveEscaped(@"$([MSBuild]::BitwiseOr(40, 2))", ExpanderOptions.ExpandProperties, MockElementLocation.Instance).ShouldBe((40 | 2).ToString());
3416+
expander.ExpandIntoStringLeaveEscaped(@"$([MSBuild]::BitwiseAnd(42, 2))", ExpanderOptions.ExpandProperties, MockElementLocation.Instance).ShouldBe((42 & 2).ToString());
3417+
expander.ExpandIntoStringLeaveEscaped(@"$([MSBuild]::BitwiseXor(213, 255))", ExpanderOptions.ExpandProperties, MockElementLocation.Instance).ShouldBe((213 ^ 255).ToString());
3418+
expander.ExpandIntoStringLeaveEscaped(@"$([MSBuild]::BitwiseNot(-43))", ExpanderOptions.ExpandProperties, MockElementLocation.Instance).ShouldBe((~-43).ToString());
3419+
expander.ExpandIntoStringLeaveEscaped(@"$([MSBuild]::LeftShift(1, 2))", ExpanderOptions.ExpandProperties, MockElementLocation.Instance).ShouldBe((1 << 2).ToString());
3420+
expander.ExpandIntoStringLeaveEscaped(@"$([MSBuild]::RightShift(-8, 2))", ExpanderOptions.ExpandProperties, MockElementLocation.Instance).ShouldBe((-8 >> 2).ToString());
3421+
expander.ExpandIntoStringLeaveEscaped(@"$([MSBuild]::RightShiftUnsigned(-8, 2))", ExpanderOptions.ExpandProperties, MockElementLocation.Instance).ShouldBe((-8 >>> 2).ToString());
34193422
}
34203423

34213424
/// <summary>

src/Build/Evaluation/Expander.cs

Lines changed: 88 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3887,6 +3887,14 @@ private bool TryExecuteWellKnownFunction(out object returnVal, object objectInst
38873887
return true;
38883888
}
38893889
}
3890+
else if (string.Equals(_methodMethodName, nameof(IntrinsicFunctions.Unescape), StringComparison.OrdinalIgnoreCase))
3891+
{
3892+
if (TryGetArg(args, out string arg0))
3893+
{
3894+
returnVal = IntrinsicFunctions.Unescape(arg0);
3895+
return true;
3896+
}
3897+
}
38903898
else if (string.Equals(_methodMethodName, nameof(IntrinsicFunctions.GetPathOfFileAbove), StringComparison.OrdinalIgnoreCase))
38913899
{
38923900
if (TryGetArgs(args, out string arg0, out string arg1))
@@ -3899,31 +3907,39 @@ private bool TryExecuteWellKnownFunction(out object returnVal, object objectInst
38993907
{
39003908
if (TryGetArgs(args, out double arg0, out double arg1))
39013909
{
3902-
returnVal = arg0 + arg1;
3910+
returnVal = IntrinsicFunctions.Add(arg0, arg1);
39033911
return true;
39043912
}
39053913
}
39063914
else if (string.Equals(_methodMethodName, nameof(IntrinsicFunctions.Subtract), StringComparison.OrdinalIgnoreCase))
39073915
{
39083916
if (TryGetArgs(args, out double arg0, out double arg1))
39093917
{
3910-
returnVal = arg0 - arg1;
3918+
returnVal = IntrinsicFunctions.Subtract(arg0, arg1);
39113919
return true;
39123920
}
39133921
}
39143922
else if (string.Equals(_methodMethodName, nameof(IntrinsicFunctions.Multiply), StringComparison.OrdinalIgnoreCase))
39153923
{
39163924
if (TryGetArgs(args, out double arg0, out double arg1))
39173925
{
3918-
returnVal = arg0 * arg1;
3926+
returnVal = IntrinsicFunctions.Multiply(arg0, arg1);
39193927
return true;
39203928
}
39213929
}
39223930
else if (string.Equals(_methodMethodName, nameof(IntrinsicFunctions.Divide), StringComparison.OrdinalIgnoreCase))
39233931
{
39243932
if (TryGetArgs(args, out double arg0, out double arg1))
39253933
{
3926-
returnVal = arg0 / arg1;
3934+
returnVal = IntrinsicFunctions.Divide(arg0, arg1);
3935+
return true;
3936+
}
3937+
}
3938+
else if (string.Equals(_methodMethodName, nameof(IntrinsicFunctions.Modulo), StringComparison.OrdinalIgnoreCase))
3939+
{
3940+
if (TryGetArgs(args, out double arg0, out double arg1))
3941+
{
3942+
returnVal = IntrinsicFunctions.Modulo(arg0, arg1);
39273943
return true;
39283944
}
39293945
}
@@ -4113,6 +4129,62 @@ private bool TryExecuteWellKnownFunction(out object returnVal, object objectInst
41134129
return true;
41144130
}
41154131
}
4132+
else if (string.Equals(_methodMethodName, nameof(IntrinsicFunctions.BitwiseOr), StringComparison.OrdinalIgnoreCase))
4133+
{
4134+
if (TryGetArgs(args, out int arg0, out int arg1))
4135+
{
4136+
returnVal = IntrinsicFunctions.BitwiseOr(arg0, arg1);
4137+
return true;
4138+
}
4139+
}
4140+
else if (string.Equals(_methodMethodName, nameof(IntrinsicFunctions.BitwiseAnd), StringComparison.OrdinalIgnoreCase))
4141+
{
4142+
if (TryGetArgs(args, out int arg0, out int arg1))
4143+
{
4144+
returnVal = IntrinsicFunctions.BitwiseAnd(arg0, arg1);
4145+
return true;
4146+
}
4147+
}
4148+
else if (string.Equals(_methodMethodName, nameof(IntrinsicFunctions.BitwiseXor), StringComparison.OrdinalIgnoreCase))
4149+
{
4150+
if (TryGetArgs(args, out int arg0, out int arg1))
4151+
{
4152+
returnVal = IntrinsicFunctions.BitwiseXor(arg0, arg1);
4153+
return true;
4154+
}
4155+
}
4156+
else if (string.Equals(_methodMethodName, nameof(IntrinsicFunctions.BitwiseNot), StringComparison.OrdinalIgnoreCase))
4157+
{
4158+
if (TryGetArgs(args, out int arg0))
4159+
{
4160+
returnVal = IntrinsicFunctions.BitwiseNot(arg0);
4161+
return true;
4162+
}
4163+
}
4164+
else if (string.Equals(_methodMethodName, nameof(IntrinsicFunctions.LeftShift), StringComparison.OrdinalIgnoreCase))
4165+
{
4166+
if (TryGetArgs(args, out int arg0, out int arg1))
4167+
{
4168+
returnVal = IntrinsicFunctions.LeftShift(arg0, arg1);
4169+
return true;
4170+
}
4171+
}
4172+
else if (string.Equals(_methodMethodName, nameof(IntrinsicFunctions.RightShift), StringComparison.OrdinalIgnoreCase))
4173+
{
4174+
if (TryGetArgs(args, out int arg0, out int arg1))
4175+
{
4176+
returnVal = IntrinsicFunctions.RightShift(arg0, arg1);
4177+
return true;
4178+
}
4179+
}
4180+
else if (string.Equals(_methodMethodName, nameof(IntrinsicFunctions.RightShiftUnsigned), StringComparison.OrdinalIgnoreCase))
4181+
{
4182+
if (TryGetArgs(args, out int arg0, out int arg1))
4183+
{
4184+
returnVal = IntrinsicFunctions.RightShiftUnsigned(arg0, arg1);
4185+
return true;
4186+
}
4187+
}
41164188
}
41174189
else if (_receiverType == typeof(Path))
41184190
{
@@ -4489,6 +4561,18 @@ private static bool TryGetArgs(object[] args, out string arg0, out StringCompari
44894561
return Enum.TryParse(comparisonTypeName, out arg1);
44904562
}
44914563

4564+
private static bool TryGetArgs(object[] args, out int arg0)
4565+
{
4566+
arg0 = 0;
4567+
4568+
if (args.Length != 1)
4569+
{
4570+
return false;
4571+
}
4572+
4573+
return TryConvertToInt(args[0], out arg0);
4574+
}
4575+
44924576
private static bool TryGetArgs(object[] args, out int arg0, out int arg1)
44934577
{
44944578
arg0 = 0;

src/Build/Evaluation/IntrinsicFunctions.cs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,21 @@ internal static int BitwiseNot(int first)
165165
return ~first;
166166
}
167167

168+
internal static int LeftShift(int operand, int count)
169+
{
170+
return operand << count;
171+
}
172+
173+
internal static int RightShift(int operand, int count)
174+
{
175+
return operand >> count;
176+
}
177+
178+
internal static int RightShiftUnsigned(int operand, int count)
179+
{
180+
return operand >>> count;
181+
}
182+
168183
/// <summary>
169184
/// Get the value of the registry key and value, default value is null
170185
/// </summary>

0 commit comments

Comments
 (0)