From d475d3641f6e795bfbc781cb5ff22a15d1010700 Mon Sep 17 00:00:00 2001 From: Brian Fiete Date: Thu, 15 Jul 2021 06:01:17 -0700 Subject: [PATCH] Added overflow operators &+, &-, &* --- IDEHelper/Compiler/BfAst.cpp | 22 +++++++++- IDEHelper/Compiler/BfAst.h | 6 +++ IDEHelper/Compiler/BfExprEvaluator.cpp | 59 +++++++++++++++++--------- IDEHelper/Compiler/BfMangler.cpp | 18 ++++++++ IDEHelper/Compiler/BfParser.cpp | 15 +++++++ IDEHelper/DbgExprEvaluator.cpp | 7 ++- IDEHelper/Tests/src/Operators.bf | 49 +++++++++++++++++++++ 7 files changed, 151 insertions(+), 25 deletions(-) diff --git a/IDEHelper/Compiler/BfAst.cpp b/IDEHelper/Compiler/BfAst.cpp index 752fa5c3..dfb61177 100644 --- a/IDEHelper/Compiler/BfAst.cpp +++ b/IDEHelper/Compiler/BfAst.cpp @@ -1500,6 +1500,12 @@ const char* Beefy::BfTokenToString(BfToken token) return ">>="; case BfToken_AndEquals: return "&="; + case BfToken_AndMinus: + return "&-"; + case BfToken_AndPlus: + return "&+"; + case BfToken_AndStar: + return "&*"; case BfToken_OrEquals: return "|="; case BfToken_XorEquals: @@ -1630,11 +1636,14 @@ int Beefy::BfGetBinaryOpPrecendence(BfBinaryOp binOp) switch (binOp) { case BfBinaryOp_Multiply: + case BfBinaryOp_OverflowMultiply: case BfBinaryOp_Divide: - case BfBinaryOp_Modulus: + case BfBinaryOp_Modulus: return 13; case BfBinaryOp_Add: - case BfBinaryOp_Subtract: + case BfBinaryOp_Subtract: + case BfBinaryOp_OverflowAdd: + case BfBinaryOp_OverflowSubtract: return 12; case BfBinaryOp_LeftShift: case BfBinaryOp_RightShift: @@ -1682,6 +1691,9 @@ const char* Beefy::BfGetOpName(BfBinaryOp binOp) case BfBinaryOp_Add: return "+"; case BfBinaryOp_Subtract: return "-"; case BfBinaryOp_Multiply: return "*"; + case BfBinaryOp_OverflowAdd: return "&+"; + case BfBinaryOp_OverflowSubtract: return "&-"; + case BfBinaryOp_OverflowMultiply: return "&*"; case BfBinaryOp_Divide: return "/"; case BfBinaryOp_Modulus: return "%"; case BfBinaryOp_BitwiseAnd: return "&"; @@ -1742,6 +1754,12 @@ BfBinaryOp Beefy::BfTokenToBinaryOp(BfToken token) return BfBinaryOp_Subtract; case BfToken_Star: return BfBinaryOp_Multiply; + case BfToken_AndPlus: + return BfBinaryOp_OverflowAdd; + case BfToken_AndMinus: + return BfBinaryOp_OverflowSubtract; + case BfToken_AndStar: + return BfBinaryOp_OverflowMultiply; case BfToken_ForwardSlash: return BfBinaryOp_Divide; case BfToken_Modulus: diff --git a/IDEHelper/Compiler/BfAst.h b/IDEHelper/Compiler/BfAst.h index 111b1786..b28e3d24 100644 --- a/IDEHelper/Compiler/BfAst.h +++ b/IDEHelper/Compiler/BfAst.h @@ -210,6 +210,9 @@ enum BfToken : uint8 BfToken_ShiftLeftEquals, BfToken_ShiftRightEquals, BfToken_AndEquals, + BfToken_AndMinus, + BfToken_AndPlus, + BfToken_AndStar, BfToken_OrEquals, BfToken_XorEquals, BfToken_NullCoalsceEquals, @@ -1795,6 +1798,9 @@ enum BfBinaryOp BfBinaryOp_Add, BfBinaryOp_Subtract, BfBinaryOp_Multiply, + BfBinaryOp_OverflowAdd, + BfBinaryOp_OverflowSubtract, + BfBinaryOp_OverflowMultiply, BfBinaryOp_Divide, BfBinaryOp_Modulus, BfBinaryOp_BitwiseAnd, diff --git a/IDEHelper/Compiler/BfExprEvaluator.cpp b/IDEHelper/Compiler/BfExprEvaluator.cpp index 8bb3f776..d70f74ca 100644 --- a/IDEHelper/Compiler/BfExprEvaluator.cpp +++ b/IDEHelper/Compiler/BfExprEvaluator.cpp @@ -21177,11 +21177,20 @@ void BfExprEvaluator::PerformBinaryOperation(BfAstNode* leftExpression, BfAstNod BfBinaryOp findBinaryOp = binaryOp; bool isComparison = (binaryOp >= BfBinaryOp_Equality) && (binaryOp <= BfBinaryOp_LessThanOrEqual); - + for (int pass = 0; pass < 2; pass++) { BfBinaryOp oppositeBinaryOp = BfGetOppositeBinaryOp(findBinaryOp); - bool foundOp = false; + BfBinaryOp overflowBinaryOp = BfBinaryOp_None; + + if (findBinaryOp == BfBinaryOp_OverflowAdd) + overflowBinaryOp = BfBinaryOp_Add; + else if (findBinaryOp == BfBinaryOp_OverflowSubtract) + overflowBinaryOp = BfBinaryOp_Subtract; + else if (findBinaryOp == BfBinaryOp_OverflowMultiply) + overflowBinaryOp = BfBinaryOp_Multiply; + + bool foundOp = false; BfResolvedArg leftArg; leftArg.mExpression = leftExpression; @@ -21225,7 +21234,7 @@ void BfExprEvaluator::PerformBinaryOperation(BfAstNode* leftExpression, BfAstNod bool invertResult = false; BfType* operatorConstraintReturnType = NULL; - bool wasTransformedUsage = pass == 1; + bool wasTransformedUsage = (pass == 1); while (true) { @@ -21288,7 +21297,7 @@ void BfExprEvaluator::PerformBinaryOperation(BfAstNode* leftExpression, BfAstNod } } } - else if (operatorDef->mOperatorDeclaration->mBinOp == oppositeBinaryOp) + else if ((operatorDef->mOperatorDeclaration->mBinOp == oppositeBinaryOp) || (operatorDef->mOperatorDeclaration->mBinOp == overflowBinaryOp)) oppositeOperatorDefs.Add(operatorDef); } @@ -21309,7 +21318,8 @@ void BfExprEvaluator::PerformBinaryOperation(BfAstNode* leftExpression, BfAstNod methodMatcher.mBestMethodDef = oppositeOperatorDef; methodMatcher.mBestMethodTypeInstance = checkType; methodMatcher.mSelfType = entry.mSrcType; - wasTransformedUsage = true; + if (oppositeBinaryOp != BfBinaryOp_None) + wasTransformedUsage = true; } } else @@ -21322,7 +21332,8 @@ void BfExprEvaluator::PerformBinaryOperation(BfAstNode* leftExpression, BfAstNod { operatorConstraintReturnType = returnType; methodMatcher.mSelfType = entry.mSrcType; - wasTransformedUsage = true; + if (oppositeBinaryOp != BfBinaryOp_None) + wasTransformedUsage = true; } } } @@ -21332,7 +21343,8 @@ void BfExprEvaluator::PerformBinaryOperation(BfAstNode* leftExpression, BfAstNod if (methodMatcher.CheckMethod(NULL, checkType, oppositeOperatorDef, false)) { methodMatcher.mSelfType = entry.mSrcType; - wasTransformedUsage = true; + if (oppositeBinaryOp != BfBinaryOp_None) + wasTransformedUsage = true; } } } @@ -21526,12 +21538,12 @@ void BfExprEvaluator::PerformBinaryOperation(BfAstNode* leftExpression, BfAstNod if (pass == 1) break; - - auto flippedBinaryOp = BfGetFlippedBinaryOp(findBinaryOp); + + auto flippedBinaryOp = BfGetFlippedBinaryOp(findBinaryOp); if (flippedBinaryOp != BfBinaryOp_None) - findBinaryOp = flippedBinaryOp; + findBinaryOp = flippedBinaryOp; } - + auto prevResultType = resultType; if ((leftValue.mType->IsPrimitiveType()) && (!rightValue.mType->IsTypedPrimitive())) resultType = leftValue.mType; @@ -21567,7 +21579,7 @@ void BfExprEvaluator::PerformBinaryOperation(BfAstNode* leftExpression, BfAstNod } //TODO: Allow all pointer comparisons, but only allow SUBTRACTION between equal pointer types - if (binaryOp == BfBinaryOp_Subtract) + if ((binaryOp == BfBinaryOp_Subtract) || (binaryOp == BfBinaryOp_OverflowSubtract)) { if (!mModule->CanCast(*otherTypedValue, resultType)) { @@ -21622,7 +21634,7 @@ void BfExprEvaluator::PerformBinaryOperation(BfAstNode* leftExpression, BfAstNod // One pointer if ((!otherType->IsIntegral()) || - ((binaryOp != BfBinaryOp_Add) && (binaryOp != BfBinaryOp_Subtract))) + ((binaryOp != BfBinaryOp_Add) && (binaryOp != BfBinaryOp_Subtract) && (binaryOp != BfBinaryOp_OverflowAdd) && (binaryOp != BfBinaryOp_OverflowSubtract))) { _OpFail(); return; @@ -21632,7 +21644,7 @@ void BfExprEvaluator::PerformBinaryOperation(BfAstNode* leftExpression, BfAstNod BfIRValue addValue = otherTypedValue->mValue; if ((!otherTypedValue->mType->IsSigned()) && (otherTypedValue->mType->mSize < mModule->mSystem->mPtrSize)) addValue = mModule->mBfIRBuilder->CreateNumericCast(addValue, false, BfTypeCode_UIntPtr); - if (binaryOp == BfBinaryOp_Subtract) + if ((binaryOp == BfBinaryOp_Subtract) || (binaryOp == BfBinaryOp_OverflowSubtract)) { if (resultTypeSrc == rightExpression) mModule->Fail("Cannot subtract a pointer from an integer", resultTypeSrc); @@ -21731,7 +21743,7 @@ void BfExprEvaluator::PerformBinaryOperation(BfAstNode* leftExpression, BfAstNod } // Allow integer offsetting - if ((binaryOp == BfBinaryOp_Add) || (binaryOp == BfBinaryOp_Subtract)) + if ((binaryOp == BfBinaryOp_Add) || (binaryOp == BfBinaryOp_Subtract) || (binaryOp == BfBinaryOp_OverflowAdd) || (binaryOp == BfBinaryOp_OverflowSubtract)) { if (otherType->IsIntegral()) needsOtherCast = false; @@ -21954,7 +21966,7 @@ void BfExprEvaluator::PerformBinaryOperation(BfAstNode* leftExpression, BfAstNod if (rightValue.mType->IsIntegral()) explicitCast = true; } - else if (((binaryOp == BfBinaryOp_Add) || (binaryOp == BfBinaryOp_Subtract)) && (resultType->IsChar()) && (otherType->IsInteger())) + else if (((binaryOp == BfBinaryOp_Add) || (binaryOp == BfBinaryOp_Subtract) || (binaryOp == BfBinaryOp_OverflowAdd) || (binaryOp == BfBinaryOp_OverflowSubtract)) && (resultType->IsChar()) && (otherType->IsInteger())) { // charVal += intVal; explicitCast = true; @@ -21980,14 +21992,15 @@ void BfExprEvaluator::PerformBinaryOperation(BfAstNode* leftExpression, BfAstNod } else { - if ((binaryOp == BfBinaryOp_Subtract) && (resultType->IsChar()) && (otherType->IsChar())) + if (((binaryOp == BfBinaryOp_Subtract) || (binaryOp == BfBinaryOp_OverflowSubtract)) && + (resultType->IsChar()) && (otherType->IsChar())) { // "wchar - char" subtraction will always fit into int32, because of unicode range resultType = mModule->GetPrimitiveType(BfTypeCode_Int32); explicitCast = true; } else if ((otherType->IsChar()) && - ((binaryOp == BfBinaryOp_Add) || (binaryOp == BfBinaryOp_Subtract))) + ((binaryOp == BfBinaryOp_Add) || (binaryOp == BfBinaryOp_Subtract) || (binaryOp == BfBinaryOp_OverflowAdd) || (binaryOp == BfBinaryOp_OverflowSubtract))) { mModule->Fail(StrFormat("Cannot perform operation between types '%s' and '%s'", mModule->TypeToString(leftValue.mType).c_str(), @@ -22142,6 +22155,7 @@ void BfExprEvaluator::PerformBinaryOperation(BfType* resultType, BfIRValue convL if ((resultType->IsChar()) && ((binaryOp == BfBinaryOp_Multiply) || + (binaryOp == BfBinaryOp_OverflowMultiply) || (binaryOp == BfBinaryOp_Divide) || (binaryOp == BfBinaryOp_Modulus))) { @@ -22151,15 +22165,18 @@ void BfExprEvaluator::PerformBinaryOperation(BfType* resultType, BfIRValue convL switch (binaryOp) { - case BfBinaryOp_Add: + case BfBinaryOp_Add: + case BfBinaryOp_OverflowAdd: mResult = BfTypedValue(mModule->mBfIRBuilder->CreateAdd(convLeftValue, convRightValue), resultType); mModule->CheckRangeError(resultType, opToken); break; - case BfBinaryOp_Subtract: + case BfBinaryOp_Subtract: + case BfBinaryOp_OverflowSubtract: mResult = BfTypedValue(mModule->mBfIRBuilder->CreateSub(convLeftValue, convRightValue), resultType); mModule->CheckRangeError(resultType, opToken); break; - case BfBinaryOp_Multiply: + case BfBinaryOp_Multiply: + case BfBinaryOp_OverflowMultiply: mResult = BfTypedValue(mModule->mBfIRBuilder->CreateMul(convLeftValue, convRightValue), resultType); mModule->CheckRangeError(resultType, opToken); break; diff --git a/IDEHelper/Compiler/BfMangler.cpp b/IDEHelper/Compiler/BfMangler.cpp index 1405c0b6..372a6fd3 100644 --- a/IDEHelper/Compiler/BfMangler.cpp +++ b/IDEHelper/Compiler/BfMangler.cpp @@ -754,6 +754,15 @@ String BfGNUMangler::Mangle(BfMethodInstance* methodInst) case BfBinaryOp_Multiply: methodName = "ml"; break; + case BfBinaryOp_OverflowAdd: + methodName = "opl"; + break; + case BfBinaryOp_OverflowSubtract: + methodName = "omi"; + break; + case BfBinaryOp_OverflowMultiply: + methodName = "oml"; + break; case BfBinaryOp_Divide: methodName = "dv"; break; @@ -1872,6 +1881,15 @@ void BfMSMangler::Mangle(StringImpl& name, bool is64Bit, BfMethodInstance* metho case BfBinaryOp_Multiply: name += "?D"; break; + case BfBinaryOp_OverflowAdd: + name += "?OH"; + break; + case BfBinaryOp_OverflowSubtract: + name += "?OG"; + break; + case BfBinaryOp_OverflowMultiply: + name += "?OD"; + break; case BfBinaryOp_Divide: name += "?K"; break; diff --git a/IDEHelper/Compiler/BfParser.cpp b/IDEHelper/Compiler/BfParser.cpp index 4575fb10..a4deab7c 100644 --- a/IDEHelper/Compiler/BfParser.cpp +++ b/IDEHelper/Compiler/BfParser.cpp @@ -1549,6 +1549,21 @@ void BfParser::NextToken(int endIdx, bool outerIsInterpolate) mToken = BfToken_AndEquals; mTokenEnd = ++mSrcIdx; } + else if (mSrc[mSrcIdx] == '+') + { + mToken = BfToken_AndPlus; + mTokenEnd = ++mSrcIdx; + } + else if (mSrc[mSrcIdx] == '-') + { + mToken = BfToken_AndMinus; + mTokenEnd = ++mSrcIdx; + } + else if (mSrc[mSrcIdx] == '*') + { + mToken = BfToken_AndStar; + mTokenEnd = ++mSrcIdx; + } else mToken = BfToken_Ampersand; mSyntaxToken = BfSyntaxToken_Token; diff --git a/IDEHelper/DbgExprEvaluator.cpp b/IDEHelper/DbgExprEvaluator.cpp index 5591e8f7..78c6967c 100644 --- a/IDEHelper/DbgExprEvaluator.cpp +++ b/IDEHelper/DbgExprEvaluator.cpp @@ -5975,13 +5975,13 @@ void DbgExprEvaluator::PerformBinaryOperation(ASTREF(BfExpression*)& leftExpress // One pointer if ((!otherType->IsInteger()) || - ((binaryOp != BfBinaryOp_Add) && (binaryOp != BfBinaryOp_Subtract) && (!isCompare))) + ((binaryOp != BfBinaryOp_Add) && (binaryOp != BfBinaryOp_Subtract) && (binaryOp != BfBinaryOp_OverflowAdd) && (binaryOp != BfBinaryOp_OverflowSubtract) && (!isCompare))) { Fail("Can only add or subtract integer values from pointers", rightExpression); return; } - if ((binaryOp == BfBinaryOp_Add) || (binaryOp == BfBinaryOp_Subtract)) + if ((binaryOp == BfBinaryOp_Add) || (binaryOp == BfBinaryOp_Subtract) || (binaryOp == BfBinaryOp_OverflowAdd) || (binaryOp == BfBinaryOp_OverflowSubtract)) { auto underlyingType = otherType->GetUnderlyingType(); mResult.mType = resultType; @@ -6262,6 +6262,7 @@ void DbgExprEvaluator::PerformBinaryOperation(DbgType* resultType, DbgTypedValue switch (binaryOp) { case BfBinaryOp_Add: + case BfBinaryOp_OverflowAdd: if (resultType->mTypeCode == DbgType_Single) mResult.mSingle = convLeftValue.mSingle + convRightValue.mSingle; else if (resultType->mTypeCode == DbgType_Double) @@ -6270,6 +6271,7 @@ void DbgExprEvaluator::PerformBinaryOperation(DbgType* resultType, DbgTypedValue mResult.mInt64 = convLeftValue.GetInt64() + convRightValue.GetInt64(); break; case BfBinaryOp_Subtract: + case BfBinaryOp_OverflowSubtract: if (resultType->mTypeCode == DbgType_Single) mResult.mSingle = convLeftValue.mSingle - convRightValue.mSingle; else if (resultType->mTypeCode == DbgType_Double) @@ -6278,6 +6280,7 @@ void DbgExprEvaluator::PerformBinaryOperation(DbgType* resultType, DbgTypedValue mResult.mInt64 = convLeftValue.GetInt64() - convRightValue.GetInt64(); break; case BfBinaryOp_Multiply: + case BfBinaryOp_OverflowMultiply: if (resultType->mTypeCode == DbgType_Single) mResult.mSingle = convLeftValue.mSingle * convRightValue.mSingle; else if (resultType->mTypeCode == DbgType_Double) diff --git a/IDEHelper/Tests/src/Operators.bf b/IDEHelper/Tests/src/Operators.bf index 3358b3a5..cdd1d04a 100644 --- a/IDEHelper/Tests/src/Operators.bf +++ b/IDEHelper/Tests/src/Operators.bf @@ -198,6 +198,41 @@ namespace Tests } } + struct StructH + { + public static int operator+(StructH lhs, int rhs) + { + return 1; + } + + public static int operator+(int lhs, StructH rhs) + { + return 2; + } + + [Commutable] + public static int operator+(StructH lhs, float rhs) + { + return 3; + } + + public static int operator&+(StructH lhs, int rhs) + { + return 4; + } + + public static int operator&+(int lhs, StructH rhs) + { + return 5; + } + + [Commutable] + public static int operator&+(StructH lhs, float rhs) + { + return 6; + } + } + struct StructOp where T : operator T + T2 { public T DoIt(T val, T2 val2) @@ -428,6 +463,20 @@ namespace Tests Test.Assert(10 + sf == 2); Test.Assert(sf + 1.0f == 3); Test.Assert(2.0f + sf == 3); + Test.Assert(sf &+ 10 == 1); + Test.Assert(10 &+ sf == 2); + Test.Assert(sf &+ 1.0f == 3); + Test.Assert(2.0f &+ sf == 3); + + StructH sh = default; + Test.Assert(sh + 10 == 1); + Test.Assert(10 + sh == 2); + Test.Assert(sh + 1.0f == 3); + Test.Assert(2.0f + sh == 3); + Test.Assert(sh &+ 10 == 4); + Test.Assert(10 &+ sh == 5); + Test.Assert(sh &+ 1.0f == 6); + Test.Assert(2.0f &+ sh == 6); StructG sg = .(100); StructG sg2 = .(200);