From 72fc4d4a3228c6d18a4395784792606f7bd93911 Mon Sep 17 00:00:00 2001 From: chriseth Date: Wed, 5 May 2021 10:12:12 +0200 Subject: [PATCH] Introduce ceil division helper function. --- libsolidity/codegen/YulUtilFunctions.cpp | 25 ++++++++++++++++++------ libsolidity/codegen/YulUtilFunctions.h | 7 +++++++ 2 files changed, 26 insertions(+), 6 deletions(-) diff --git a/libsolidity/codegen/YulUtilFunctions.cpp b/libsolidity/codegen/YulUtilFunctions.cpp index 26c7d0df2..686f3690c 100644 --- a/libsolidity/codegen/YulUtilFunctions.cpp +++ b/libsolidity/codegen/YulUtilFunctions.cpp @@ -541,6 +541,18 @@ string YulUtilFunctions::roundUpFunction() }); } +string YulUtilFunctions::divide32CeilFunction() +{ + return m_functionCollector.createFunction( + "divide_by_32_ceil", + [&](vector& _args, vector& _ret) { + _args = {"value"}; + _ret = {"result"}; + return "result := div(add(value, 31), 32)"; + } + ); +} + string YulUtilFunctions::overflowCheckedIntAddFunction(IntegerType const& _type) { string functionName = "checked_add_" + _type.identifier(); @@ -1257,14 +1269,14 @@ string YulUtilFunctions::cleanUpDynamicByteArrayEndSlotsFunction(ArrayType const return Whiskers(R"( if gt(len, 31) { let dataArea := (array) - let deleteStart := add(dataArea, div((startIndex), 32)) + let deleteStart := add(dataArea, (startIndex)) // If we are clearing array to be short byte array, we want to clear only data starting from array data area. if lt(startIndex, 32) { deleteStart := dataArea } - (deleteStart, add(dataArea, div(add(len, 31), 32))) + (deleteStart, add(dataArea, (len))) } )") ("dataLocation", arrayDataAreaFunction(_type)) - ("roundUp", roundUpFunction()) + ("div32Ceil", divide32CeilFunction()) ("clearStorageRange", clearStorageRangeFunction(*_type.baseType())) .render(); }); @@ -1279,13 +1291,13 @@ string YulUtilFunctions::decreaseByteArraySizeFunction(ArrayType const& _type) switch lt(newLen, 32) case 0 { let arrayDataStart := (array) - let deleteStart := add(arrayDataStart, div(add(newLen, 31), 32)) + let deleteStart := add(arrayDataStart, (newLen)) // we have to partially clear last slot that is still used let offset := and(newLen, 0x1f) if offset { (sub(deleteStart, 1), offset) } - (deleteStart, add(arrayDataStart, div(add(oldLen, 31), 32))) + (deleteStart, add(arrayDataStart, (oldLen))) sstore(array, or(mul(2, newLen), 1)) } @@ -1294,7 +1306,7 @@ string YulUtilFunctions::decreaseByteArraySizeFunction(ArrayType const& _type) case 1 { let arrayDataStart := (array) // clear whole old array, as we are transforming to short bytes array - (add(arrayDataStart, 1), add(arrayDataStart, div(add(oldLen, 31), 32))) + (add(arrayDataStart, 1), add(arrayDataStart, (oldLen))) (array, newLen) } default { @@ -1307,6 +1319,7 @@ string YulUtilFunctions::decreaseByteArraySizeFunction(ArrayType const& _type) ("partialClearStorageSlot", partialClearStorageSlotFunction()) ("clearStorageRange", clearStorageRangeFunction(*_type.baseType())) ("transitLongToShort", byteArrayTransitLongToShortFunction(_type)) + ("div32Ceil", divide32CeilFunction()) ("encodeUsedSetLen", shortByteArrayEncodeUsedAreaSetLengthFunction()) .render(); }); diff --git a/libsolidity/codegen/YulUtilFunctions.h b/libsolidity/codegen/YulUtilFunctions.h index 30f109b51..962d5e084 100644 --- a/libsolidity/codegen/YulUtilFunctions.h +++ b/libsolidity/codegen/YulUtilFunctions.h @@ -126,9 +126,16 @@ public: /// @returns the name of a function that rounds its input to the next multiple /// of 32 or the input if it is a multiple of 32. + /// Ignores overflow. /// signature: (value) -> result std::string roundUpFunction(); + /// @returns the name of a function that divides by 32 and rounds up during the division. + /// In other words, on input x it returns the smallest y such that y * 32 >= x. + /// Ignores overflow. + /// signature: (x) -> y + std::string divide32CeilFunction(); + /// signature: (x, y) -> sum std::string overflowCheckedIntAddFunction(IntegerType const& _type); /// signature: (x, y) -> sum