Skip to content

Commit

Permalink
Add workaround for bitwise not operator ~
Browse files Browse the repository at this point in the history
MerlinVR committed Dec 21, 2020

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
1 parent bf59eb2 commit 17eb24f
Showing 3 changed files with 100 additions and 6 deletions.
83 changes: 78 additions & 5 deletions Assets/UdonSharp/Editor/UdonSharpASTVisitor.cs
Original file line number Diff line number Diff line change
@@ -806,23 +806,23 @@ public override void VisitPrefixUnaryExpression(PrefixUnaryExpressionSyntax node
break;
case SyntaxKind.BitwiseNotExpression:
case SyntaxKind.TildeToken:
throw new System.NotSupportedException("Udon does not support BitwiseNot at the moment (https://vrchat.canny.io/vrchat-udon-closed-alpha-feedback/p/bitwisenot-for-integer-built-in-types)");
//throw new System.NotSupportedException("Udon does not support BitwiseNot at the moment (https://vrchat.canny.io/vrchat-udon-closed-alpha-feedback/p/bitwisenot-for-integer-built-in-types)");
break;
default:
throw new System.NotImplementedException($"Handling for prefix token {node.OperatorToken.Kind()} is not implemented");
}

using (ExpressionCaptureScope operatorMethodCapture = new ExpressionCaptureScope(visitorContext, null, requestedDestination))
{
operatorMethodCapture.SetToMethods(operatorMethods.ToArray());

BuiltinOperatorType operatorType = SyntaxKindToBuiltinOperator(node.OperatorToken.Kind());

SymbolDefinition resultSymbol = null;

if (operatorType == BuiltinOperatorType.UnaryNegation ||
operatorType == BuiltinOperatorType.UnaryMinus ||
operatorType == BuiltinOperatorType.BitwiseNot)
operatorType == BuiltinOperatorType.UnaryMinus)
{
operatorMethodCapture.SetToMethods(operatorMethods.ToArray());

SymbolDefinition operandResult = operandCapture.ExecuteGet();

if (operatorType == BuiltinOperatorType.UnaryNegation &&
@@ -842,8 +842,80 @@ public override void VisitPrefixUnaryExpression(PrefixUnaryExpressionSyntax node
if (topScope != null)
topScope.SetToLocalSymbol(resultSymbol);
}
else if (operatorType == BuiltinOperatorType.BitwiseNot) // udon-workaround: 12/21/2020 It has been a year, we are still missing bitwise not.
{
try
{
System.Type operandType = operandCapture.GetReturnType();

if (!UdonSharpUtils.IsIntegerType(operandType)) throw new System.NotSupportedException();

object maxIntVal = operandType.GetField("MaxValue").GetValue(null);
SymbolDefinition maxValSymbol = visitorContext.topTable.CreateConstSymbol(operandType, maxIntVal);

SymbolDefinition operandValue = operandCapture.ExecuteGet();

operatorMethodCapture.SetToMethods(GetOperators(operandType, BuiltinOperatorType.LogicalXor));
resultSymbol = operatorMethodCapture.Invoke(new SymbolDefinition[] { operandValue, maxValSymbol });

if (UdonSharpUtils.IsSignedType(operandType)) // Signed types need handling for negating the sign
{
using (ExpressionCaptureScope negativeCheck = new ExpressionCaptureScope(visitorContext, null))
{
negativeCheck.SetToMethods(GetOperators(operandType, BuiltinOperatorType.LessThan));

SymbolDefinition isNegative = negativeCheck.Invoke(new SymbolDefinition[] { operandValue, visitorContext.topTable.CreateConstSymbol(operandType, System.Convert.ChangeType(0, operandType)) });

JumpLabel elseJump = visitorContext.labelTable.GetNewJumpLabel("bitwiseNegateElse");
JumpLabel exitJump = visitorContext.labelTable.GetNewJumpLabel("bitwiseNegateExit");

visitorContext.uasmBuilder.AddJumpIfFalse(elseJump, isNegative);

using (ExpressionCaptureScope ANDScope = new ExpressionCaptureScope(visitorContext, null, resultSymbol))
{
ANDScope.SetToMethods(GetOperators(operandType, BuiltinOperatorType.LogicalAnd));
resultSymbol = ANDScope.Invoke(new SymbolDefinition[] { resultSymbol, maxValSymbol });
}

visitorContext.uasmBuilder.AddJump(exitJump);

visitorContext.uasmBuilder.AddJumpLabel(elseJump);

long bitOr = 0;

if (operandType == typeof(sbyte))
bitOr = 1 << 7;
else if (operandType == typeof(short))
bitOr = 1 << 15;
else if (operandType == typeof(int))
bitOr = 1 << 31;
else if (operandType == typeof(long))
bitOr = 1 << 63;
else
throw new System.Exception();

using (ExpressionCaptureScope ORScope = new ExpressionCaptureScope(visitorContext, null, resultSymbol))
{
ORScope.SetToMethods(GetOperators(operandType, BuiltinOperatorType.LogicalOr));
resultSymbol = ORScope.Invoke(new SymbolDefinition[] { resultSymbol, visitorContext.topTable.CreateConstSymbol(operandType, System.Convert.ChangeType(bitOr, operandType)) });
}

visitorContext.uasmBuilder.AddJumpLabel(exitJump);
}
}
}
catch (System.Exception)
{
throw new System.ArgumentException($"Operator '{node.OperatorToken.Text}' cannot be applied to operand of type '{UdonSharpUtils.PrettifyTypeName(operandCapture.GetReturnType())}'");
}

if (topScope != null)
topScope.SetToLocalSymbol(resultSymbol);
}
else
{
operatorMethodCapture.SetToMethods(operatorMethods.ToArray());

SymbolDefinition valueConstant = visitorContext.topTable.CreateConstSymbol(operandCapture.GetReturnType(), System.Convert.ChangeType(1, operandCapture.GetReturnType()));

try
@@ -1171,6 +1243,7 @@ private BuiltinOperatorType SyntaxKindToBuiltinOperator(SyntaxKind syntaxKind)
case SyntaxKind.BarEqualsToken:
return BuiltinOperatorType.LogicalOr;
case SyntaxKind.BitwiseNotExpression:
case SyntaxKind.TildeToken:
return BuiltinOperatorType.BitwiseNot;
case SyntaxKind.ExclusiveOrExpression:
case SyntaxKind.ExclusiveOrAssignmentExpression:
2 changes: 1 addition & 1 deletion Assets/UdonSharp/Editor/UdonSharpOperatorMethodInfo.cs
Original file line number Diff line number Diff line change
@@ -49,7 +49,7 @@ public enum BuiltinOperatorType
LogicalAnd,
LogicalOr,
LogicalXor,
BitwiseNot, // Not implemented yet
BitwiseNot, // Now has hack workaround handling
}

/// <summary>
21 changes: 21 additions & 0 deletions Assets/UdonSharp/Tests/TestScripts/Core/ArithmeticTest.cs
Original file line number Diff line number Diff line change
@@ -30,6 +30,7 @@ public void ExecuteTests()
UintBitOps();
StringAddition();
DecimalOps();
BitwiseNot();
}

void IntBinaryOps()
@@ -301,5 +302,25 @@ void StringAddition()
s += string.Format("{0:x2}", 0x42);
tester.TestAssertion("String addition", s == "abcdef42");
}

void BitwiseNot()
{
int positiveInt = 30;

int resultInt = ~positiveInt;
tester.TestAssertion("Int bitwise not positive", resultInt == -31);
tester.TestAssertion("Int bitwise not positive 2", ~positiveInt == -31);

int negativeInt = -30;

resultInt = ~negativeInt;
tester.TestAssertion("Int bitwise not negative", resultInt == 29);
tester.TestAssertion("Int bitwise not negative 2", ~negativeInt == 29);

uint uintTest = 40;
uint resultUint = ~uintTest;
tester.TestAssertion("uint bitwise not", ~uintTest == 4294967255);
tester.TestAssertion("uint bitwise not 2", resultUint == 4294967255);
}
}
}

0 comments on commit 17eb24f

Please sign in to comment.