From bf97431cdbc3e8201013e673bee2d205d48cd7d6 Mon Sep 17 00:00:00 2001 From: Brian Fiete Date: Tue, 11 Jan 2022 10:36:22 -0500 Subject: [PATCH] Improvements to overflow arithmetic --- BeefLibs/corlib/src/Int32.bf | 2 +- BeefLibs/corlib/src/Int64.bf | 2 +- BeefLibs/corlib/src/Random.bf | 2 +- .../corlib/src/Security/Cryptography/MD5.bf | 24 ++++++++--------- .../src/Security/Cryptography/SHA256.bf | 26 +++++++++---------- BeefLibs/corlib/src/String.bf | 16 ++++++------ IDEHelper/Backend/BeMCContext.cpp | 10 ++++--- IDEHelper/Backend/BeMCContext.h | 1 + IDEHelper/Compiler/BfAst.cpp | 20 +++++++++++++- IDEHelper/Compiler/BfAst.h | 7 ++++- IDEHelper/Compiler/BfExprEvaluator.cpp | 2 ++ IDEHelper/Compiler/BfParser.cpp | 24 ++++++++++++++--- 12 files changed, 91 insertions(+), 45 deletions(-) diff --git a/BeefLibs/corlib/src/Int32.bf b/BeefLibs/corlib/src/Int32.bf index f1c8ae66..b16f1e70 100644 --- a/BeefLibs/corlib/src/Int32.bf +++ b/BeefLibs/corlib/src/Int32.bf @@ -73,7 +73,7 @@ namespace System } while (valLeft < 0) { - strChars[char8Idx] = (char8)('0' - (valLeft % 10)); + strChars[char8Idx] = (char8)('0' &- (valLeft % 10)); valLeft /= 10; char8Idx--; } diff --git a/BeefLibs/corlib/src/Int64.bf b/BeefLibs/corlib/src/Int64.bf index 89bd1cc4..5f530620 100644 --- a/BeefLibs/corlib/src/Int64.bf +++ b/BeefLibs/corlib/src/Int64.bf @@ -91,7 +91,7 @@ namespace System } while ((valLeft < 0) || (minNumeralsLeft > 0)) { - strChars[char8Idx] = (char8)('0' - (valLeft % 10)); + strChars[char8Idx] = (char8)('0' &- (valLeft % 10)); valLeft /= 10; char8Idx--; minNumeralsLeft--; diff --git a/BeefLibs/corlib/src/Random.bf b/BeefLibs/corlib/src/Random.bf index 40274e77..9c607c42 100644 --- a/BeefLibs/corlib/src/Random.bf +++ b/BeefLibs/corlib/src/Random.bf @@ -80,7 +80,7 @@ namespace System { for (int32 i = 1; i < 56; i++) { - SeedArray[i] -= SeedArray[1 + (i + 30) % 55]; + SeedArray[i] &-= SeedArray[1 + (i + 30) % 55]; if (SeedArray[i] < 0) SeedArray[i] += MBIG; } } diff --git a/BeefLibs/corlib/src/Security/Cryptography/MD5.bf b/BeefLibs/corlib/src/Security/Cryptography/MD5.bf index d5b917d5..8b40a62b 100644 --- a/BeefLibs/corlib/src/Security/Cryptography/MD5.bf +++ b/BeefLibs/corlib/src/Security/Cryptography/MD5.bf @@ -129,27 +129,27 @@ namespace System.Security.Cryptography // The MD5 transformation for all four rounds. mixin STEP_F(var a, var b, var c, var d, var x, var t, var s) { - a += F!(b, c, d) + x + t; + a &+= F!(b, c, d) &+ x &+ t; a = ((a << s) | ((a & 0xffffffff) >> (32 - s))); - a += b; + a &+= b; } mixin STEP_G(var a, var b, var c, var d, var x, var t, var s) { - a += G!(b, c, d) + x + t; + a &+= G!(b, c, d) &+ x &+ t; a = ((a << s) | ((a & 0xffffffff) >> (32 - s))); - a += b; + a &+= b; } mixin STEP_H(var a, var b, var c, var d, var x, var t, var s) { - a += H!(b, c, d) + x + t; + a &+= H!(b, c, d) &+ x &+ t; a = ((a << s) | ((a & 0xffffffff) >> (32 - s))); - a += b; + a &+= b; } mixin STEP_I(var a, var b, var c, var d, var x, var t, var s) { - a += I!(b, c, d) + x + t; + a &+= I!(b, c, d) &+ x &+ t; a = ((a << s) | ((a & 0xffffffff) >> (32 - s))); - a += b; + a &+= b; } // SET reads 4 input bytes in little-endian byte order and stores them @@ -249,10 +249,10 @@ namespace System.Security.Cryptography STEP_I!(c, d, a, b, GET!(2), 0x2ad7d2bb, 15); STEP_I!(b, c, d, a, GET!(9), 0xeb86d391, 21); - a += saved_a; - b += saved_b; - c += saved_c; - d += saved_d; + a &+= saved_a; + b &+= saved_b; + c &+= saved_c; + d &+= saved_d; ptr += 64; } diff --git a/BeefLibs/corlib/src/Security/Cryptography/SHA256.bf b/BeefLibs/corlib/src/Security/Cryptography/SHA256.bf index 32c21a6a..6c365638 100644 --- a/BeefLibs/corlib/src/Security/Cryptography/SHA256.bf +++ b/BeefLibs/corlib/src/Security/Cryptography/SHA256.bf @@ -142,7 +142,7 @@ namespace System.Security.Cryptography for (i = 0, j = 0; i < 16; ++i, j += 4) m[i] = ((uint32)mData[j] << 24) | ((uint32)mData[j + 1] << 16) | ((uint32)mData[j + 2] << 8) | ((uint32)mData[j + 3]); for ( ; i < 64; ++i) - m[i] = SIG1!(m[i - 2]) + m[i - 7] + SIG0!(m[i - 15]) + m[i - 16]; + m[i] = SIG1!(m[i - 2]) &+ m[i - 7] &+ SIG0!(m[i - 15]) &+ m[i - 16]; a = mState[0]; b = mState[1]; @@ -155,26 +155,26 @@ namespace System.Security.Cryptography for (i = 0; i < 64; ++i) { - t1 = h + EP1!(e) + CH!(e,f,g) + k[i] + m[i]; - t2 = EP0!(a) + MAJ!(a,b,c); + t1 = h &+ EP1!(e) &+ CH!(e,f,g) &+ k[i] &+ m[i]; + t2 = EP0!(a) &+ MAJ!(a,b,c); h = g; g = f; f = e; - e = d + t1; + e = d &+ t1; d = c; c = b; b = a; - a = t1 + t2; + a = t1 &+ t2; } - mState[0] += a; - mState[1] += b; - mState[2] += c; - mState[3] += d; - mState[4] += e; - mState[5] += f; - mState[6] += g; - mState[7] += h; + mState[0] &+= a; + mState[1] &+= b; + mState[2] &+= c; + mState[3] &+= d; + mState[4] &+= e; + mState[5] &+= f; + mState[6] &+= g; + mState[7] &+= h; } public void Update(Span data) diff --git a/BeefLibs/corlib/src/String.bf b/BeefLibs/corlib/src/String.bf index 25bc0c8d..9e30bf2f 100644 --- a/BeefLibs/corlib/src/String.bf +++ b/BeefLibs/corlib/src/String.bf @@ -397,14 +397,14 @@ namespace System let intSize = sizeof(int); while (charsLeft >= intSize) { - hash = (hash ^ *((int*)curPtr)) + (hash * 16777619); + hash = (hash ^ *((int*)curPtr)) &+ (hash &* 16777619); charsLeft -= intSize; curPtr += intSize; } while (charsLeft > 1) { - hash = ((hash ^ (int)*curPtr) << 5) - hash; + hash = ((hash ^ (int)*curPtr) << 5) &- hash; charsLeft--; curPtr++; } @@ -1774,8 +1774,8 @@ namespace System //Contract.Assert((char8A | char8B) <= 0x7F, "strings have to be ASCII"); // uppercase both chars - notice that we need just one compare per char - if ((uint32)(charA - 'a') <= (uint32)('z' - 'a')) charA -= 0x20; - if ((uint32)(charB - 'a') <= (uint32)('z' - 'a')) charB -= 0x20; + if ((uint32)(charA &- 'a') <= (uint32)('z' - 'a')) charA -= 0x20; + if ((uint32)(charB &- 'a') <= (uint32)('z' - 'a')) charB -= 0x20; //Return the (case-insensitive) difference between them. if (charA != charB) @@ -1807,8 +1807,8 @@ namespace System //Contract.Assert((char8A | char8B) <= 0x7F, "strings have to be ASCII"); // uppercase both chars - notice that we need just one compare per char - if ((uint32)(charA - 'a') <= (uint32)('z' - 'a')) charA -= 0x20; - if ((uint32)(charB - 'a') <= (uint32)('z' - 'a')) charB -= 0x20; + if ((uint32)(charA &- 'a') <= (uint32)('z' - 'a')) charA -= 0x20; + if ((uint32)(charB &- 'a') <= (uint32)('z' - 'a')) charB -= 0x20; //Return the (case-insensitive) difference between them. if (charA != charB) @@ -1835,8 +1835,8 @@ namespace System //Contract.Assert((char8A | char8B) <= 0x7F, "strings have to be ASCII"); // uppercase both chars - notice that we need just one compare per char - if ((uint32)(charA - 'a') <= (uint32)('z' - 'a')) charA -= 0x20; - if ((uint32)(charB - 'a') <= (uint32)('z' - 'a')) charB -= 0x20; + if ((uint32)(charA &- 'a') <= (uint32)('z' - 'a')) charA -= 0x20; + if ((uint32)(charB &- 'a') <= (uint32)('z' - 'a')) charB -= 0x20; //Return the (case-insensitive) difference between them. if (charA != charB) diff --git a/IDEHelper/Backend/BeMCContext.cpp b/IDEHelper/Backend/BeMCContext.cpp index 2d7e9096..ab00061c 100644 --- a/IDEHelper/Backend/BeMCContext.cpp +++ b/IDEHelper/Backend/BeMCContext.cpp @@ -9226,7 +9226,7 @@ bool BeMCContext::DoLegalization() else { bool addCanBeLEA = - ((inst->mKind == BeMCInstKind_Sub) || (inst->mKind == BeMCInstKind_Add)) && + ((inst->mKind == BeMCInstKind_Sub) || (inst->mKind == BeMCInstKind_Add)) && (!inst->mDisableShortForm) && (arg0Type->mSize >= 2) && // Int8s don't have an LEA (GetFixedOperand(inst->mResult).IsNativeReg()) && (arg0.IsNativeReg()) && (arg1.IsImmediateInt()); @@ -10209,7 +10209,7 @@ bool BeMCContext::DoLegalization() handled = true; } - if (handled) + if (!handled) { if (inst->mResult) { @@ -14338,6 +14338,7 @@ void BeMCContext::DoCodeEmission() { if ((inst->mResult) && (inst->mResult != inst->mArg0)) { + BF_ASSERT(!inst->mDisableShortForm); BF_ASSERT(inst->mResult.IsNativeReg()); BF_ASSERT(inst->mArg0.IsNativeReg()); BF_ASSERT(inst->mArg1.IsImmediate()); @@ -14538,9 +14539,9 @@ void BeMCContext::DoCodeEmission() if (result) { BF_ASSERT(inst->mArg1.IsImmediate()); - if ((inst->mArg0.IsNativeReg()) && + if ((inst->mArg0.IsNativeReg()) && (!inst->mDisableShortForm) && ((inst->mArg1.mImmediate == 2) || (inst->mArg1.mImmediate == 4) || (inst->mArg1.mImmediate == 8))) - { + { // LEA form auto resultType = GetType(inst->mArg0); if (resultType->mTypeCode != BeTypeCode_Int8) @@ -16030,6 +16031,7 @@ BeMCOperand BeMCContext::AllocBinaryOp(BeMCInstKind instKind, const BeMCOperand& if (overflowCheckKind != BeMCOverflowCheckKind_None) { + mcInst->mDisableShortForm = true; AllocInst(BeMCInstKind_CondBr, BeMCOperand::FromImmediate(1), BeMCOperand::FromCmpKind((overflowCheckKind == BeMCOverflowCheckKind_B) ? BeCmpKind_NB : BeCmpKind_NO)); AllocInst(BeMCInstKind_DbgBreak); } diff --git a/IDEHelper/Backend/BeMCContext.h b/IDEHelper/Backend/BeMCContext.h index 8d3c9610..9010c317 100644 --- a/IDEHelper/Backend/BeMCContext.h +++ b/IDEHelper/Backend/BeMCContext.h @@ -564,6 +564,7 @@ class BeMCInst { public: BeMCInstKind mKind; + bool mDisableShortForm; BeMCOperand mResult; BeMCOperand mArg0; diff --git a/IDEHelper/Compiler/BfAst.cpp b/IDEHelper/Compiler/BfAst.cpp index c55e9d5d..3d4f2a1f 100644 --- a/IDEHelper/Compiler/BfAst.cpp +++ b/IDEHelper/Compiler/BfAst.cpp @@ -1513,6 +1513,12 @@ const char* Beefy::BfTokenToString(BfToken token) return "&+"; case BfToken_AndStar: return "&*"; + case BfToken_AndMinusEquals: + return "&-="; + case BfToken_AndPlusEquals: + return "&+="; + case BfToken_AndStarEquals: + return "&*="; case BfToken_OrEquals: return "|="; case BfToken_XorEquals: @@ -1620,6 +1626,12 @@ BfBinaryOp Beefy::BfAssignOpToBinaryOp(BfAssignmentOp assignmentOp) return BfBinaryOp_Multiply; case BfAssignmentOp_Divide: return BfBinaryOp_Divide; + case BfAssignmentOp_OverflowAdd: + return BfBinaryOp_OverflowAdd; + case BfAssignmentOp_OverflowSubtract: + return BfBinaryOp_OverflowSubtract; + case BfAssignmentOp_OverflowMultiply: + return BfBinaryOp_OverflowMultiply; case BfAssignmentOp_Modulus: return BfBinaryOp_Modulus; case BfAssignmentOp_ShiftLeft: @@ -1898,7 +1910,13 @@ BfAssignmentOp Beefy::BfTokenToAssignmentOp(BfToken token) case BfToken_MinusEquals: return BfAssignmentOp_Subtract; case BfToken_MultiplyEquals: - return BfAssignmentOp_Multiply; + return BfAssignmentOp_Multiply; + case BfToken_AndPlusEquals: + return BfAssignmentOp_OverflowAdd; + case BfToken_AndMinusEquals: + return BfAssignmentOp_OverflowSubtract; + case BfToken_AndStarEquals: + return BfAssignmentOp_OverflowMultiply; case BfToken_DivideEquals: return BfAssignmentOp_Divide; case BfToken_ModulusEquals: diff --git a/IDEHelper/Compiler/BfAst.h b/IDEHelper/Compiler/BfAst.h index ce8b7093..741ee3c8 100644 --- a/IDEHelper/Compiler/BfAst.h +++ b/IDEHelper/Compiler/BfAst.h @@ -205,7 +205,6 @@ enum BfToken : uint8 BfToken_PlusEquals, BfToken_MinusEquals, BfToken_MultiplyEquals, - BfToken_DivideEquals, BfToken_ModulusEquals, BfToken_ShiftLeftEquals, @@ -214,6 +213,9 @@ enum BfToken : uint8 BfToken_AndMinus, BfToken_AndPlus, BfToken_AndStar, + BfToken_AndMinusEquals, + BfToken_AndPlusEquals, + BfToken_AndStarEquals, BfToken_OrEquals, BfToken_XorEquals, BfToken_NullCoalsceEquals, @@ -1843,6 +1845,9 @@ enum BfAssignmentOp BfAssignmentOp_Add, BfAssignmentOp_Subtract, BfAssignmentOp_Multiply, + BfAssignmentOp_OverflowAdd, + BfAssignmentOp_OverflowSubtract, + BfAssignmentOp_OverflowMultiply, BfAssignmentOp_Divide, BfAssignmentOp_Modulus, BfAssignmentOp_ShiftLeft, diff --git a/IDEHelper/Compiler/BfExprEvaluator.cpp b/IDEHelper/Compiler/BfExprEvaluator.cpp index 97856791..dadc1856 100644 --- a/IDEHelper/Compiler/BfExprEvaluator.cpp +++ b/IDEHelper/Compiler/BfExprEvaluator.cpp @@ -22667,6 +22667,8 @@ void BfExprEvaluator::PerformBinaryOperation(BfType* resultType, BfIRValue convL auto _GetOverflowKind = [&](bool wantOverflow) { + if (resultType->IsFloat()) + return BfOverflowCheckKind_None; if (!wantOverflow) return BfOverflowCheckKind_None; if (mModule->GetDefaultCheckedKind() != BfCheckedKind_Checked) diff --git a/IDEHelper/Compiler/BfParser.cpp b/IDEHelper/Compiler/BfParser.cpp index e69c5ca5..d72553da 100644 --- a/IDEHelper/Compiler/BfParser.cpp +++ b/IDEHelper/Compiler/BfParser.cpp @@ -1559,17 +1559,35 @@ void BfParser::NextToken(int endIdx, bool outerIsInterpolate) } else if (mSrc[mSrcIdx] == '+') { - mToken = BfToken_AndPlus; + if (mSrc[mSrcIdx + 1] == '=') + { + mToken = BfToken_AndPlusEquals; + ++mSrcIdx; + } + else + mToken = BfToken_AndPlus; mTokenEnd = ++mSrcIdx; } else if (mSrc[mSrcIdx] == '-') { - mToken = BfToken_AndMinus; + if (mSrc[mSrcIdx + 1] == '=') + { + mToken = BfToken_AndMinusEquals; + ++mSrcIdx; + } + else + mToken = BfToken_AndMinus; mTokenEnd = ++mSrcIdx; } else if (mSrc[mSrcIdx] == '*') { - mToken = BfToken_AndStar; + if (mSrc[mSrcIdx + 1] == '=') + { + mToken = BfToken_AndStarEquals; + ++mSrcIdx; + } + else + mToken = BfToken_AndStar; mTokenEnd = ++mSrcIdx; } else