From: drh <> Date: Sun, 29 Mar 2026 19:06:36 +0000 (+0000) Subject: Avoid using unsigned 64-bit integer division on platforms that do not support X-Git-Tag: major-release~27 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=03f13d77a52d409c1830bf5bd9fc9cdea7e1e0de;p=thirdparty%2Fsqlite.git Avoid using unsigned 64-bit integer division on platforms that do not support it in hardware. FossilOrigin-Name: 2197677491dfc5ec87b57bbf807776875248a250f80ce9a5ce94ae385bb1d2bc --- diff --git a/Makefile.msc b/Makefile.msc index 76b9ddfc3b..8e06c11cb6 100644 --- a/Makefile.msc +++ b/Makefile.msc @@ -2630,8 +2630,8 @@ smoketest: $(TESTPROGS) # Measure the performance of floating-point conversions. # fp-speed-test: fp-speed-1.exe fp-speed-2.exe - fp-speed-1 10000000 - fp-speed-2 10000000 + fp-speed-1 1000000 + fp-speed-2 1000000 shelltest: $(TCLSH_CMD) $(TOP)\test\testrunner.tcl release shell diff --git a/main.mk b/main.mk index fa6d35c8ae..0b13b7da6d 100644 --- a/main.mk +++ b/main.mk @@ -1923,8 +1923,8 @@ shelltest: # Test performance of floating-point conversions. # fp-speed-test: fp-speed-1$(T.exe) fp-speed-2$(T.exe) - ./fp-speed-1 10000000 - ./fp-speed-2 10000000 + ./fp-speed-1 1000000 + ./fp-speed-2 1000000 # # sqlite3_analyzer.c build depends on $(LINK_TOOLS_DYNAMICALLY). diff --git a/manifest b/manifest index 32e9801322..94a5edf85b 100644 --- a/manifest +++ b/manifest @@ -1,12 +1,12 @@ -C The\s_umulh()\sintrinsic\sfunction\sis\snot\savailable\son\s32-bit\swindows.\s\sSo\sdon't\nuse\sit\sthere. -D 2026-03-29T10:32:25.815 +C Avoid\susing\sunsigned\s64-bit\sinteger\sdivision\son\splatforms\sthat\sdo\snot\ssupport\nit\sin\shardware. +D 2026-03-29T19:06:36.213 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md 6bc480fc673fb4acbc4094e77edb326267dd460162d7723c7f30bee2d3d9e97d F Makefile.in 3ce07126d7e87c7464301482e161fdae6a51d0a2aa06b200b8f0000ef4d6163b F Makefile.linux-generic bd3e3cacd369821a6241d4ea1967395c962dfe3057e38cb0a435cee0e8b789d0 -F Makefile.msc 05dffae7914a3e3accd6056d71ec2bf5dff563a728592373b828882a52141067 +F Makefile.msc 92391304cf70f4c178b127aa83b88637abd28d1b83ede451616144037ea1d3dd F README.md 3fa51fc7ababc32edd175ae8b2986c86d5ea120c1cb1e57c7f7849492d1405ec F VERSION 31435e19ded2aae3c1c67dacf06a995a37fd1b253baec5899b78d64cd29db4f7 F art/icon-243x273.gif 9750b734f82fdb3dc43127753d5e6fbf3b62c9f4e136c2fbf573b2f57ea87af5 @@ -655,7 +655,7 @@ F ext/wasm/tests/opfs/sahpool/index.html be736567fd92d3ecb9754c145755037cbbd2bca F ext/wasm/tests/opfs/sahpool/sahpool-pausing.js f264925cfc82155de38cecb3d204c36e0f6991460fff0cb7c15079454679a4e2 F ext/wasm/tests/opfs/sahpool/sahpool-worker.js bd25a43fc2ab2d1bafd8f2854ad3943ef673f7c3be03e95ecf1612ff6e8e2a61 F magic.txt 5ade0bc977aa135e79e3faaea894d5671b26107cc91e70783aa7dc83f22f3ba0 -F main.mk ac1cafc6f08d108f99cf74f686f1a7f8a08569279341f9d6ffb7745c1fba66f6 +F main.mk 0ed98e9faa3a8e2ce40ec5b55781101048c13c6970bc50d456d4c2834e74f4ea F make.bat a136fd0b1c93e89854a86d5f4edcf0386d211e5d5ec2434480f6eea436c7420c F mptest/config01.test 3c6adcbc50b991866855f1977ff172eb6d901271 F mptest/config02.test 4415dfe36c48785f751e16e32c20b077c28ae504 @@ -738,7 +738,7 @@ F src/shell.c.in 91ee40ec3f75192362cbaa0ad85316140b8dde00a184113d73a837fb6173dbc F src/sqlite.h.in e7acbb01518f05c5a342149ec1eeb1afcdccf9b90a6e9770a4893ae9a3c756ae F src/sqlite3.rc 015537e6ac1eec6c7050e17b616c2ffe6f70fca241835a84a4f0d5937383c479 F src/sqlite3ext.h 1b7a0ee438bb5c2896d0609c537e917d8057b3340f6ad004d2de44f03e3d3cca -F src/sqliteInt.h 9716721fb57e32938a1d30a84560ce7633c63860a2209e188c87afad15d4b464 +F src/sqliteInt.h 9d6e04c079cade18c32bcf615552ac5dfba6a151b29abd2319c368764a5d297e F src/sqliteLimit.h c70656b67ab5b96741a8f1c812bdd80c81f2b1c1e443d0cc3ea8c33bb1f1a092 F src/status.c 7565d63a79aa2f326339a24a0461a60096d0bd2bce711fefb50b5c89335f3592 F src/table.c 0f141b58a16de7e2fbe81c308379e7279f4c6b50eb08efeec5892794a0ba30d1 @@ -798,7 +798,7 @@ F src/trigger.c 4bf3bfb3851d165e4404a9f9e69357345f3f7103378c07e07139fdd8aeb7bd20 F src/update.c 3e5e7ff66fa19ebe4d1b113d480639a24cc1175adbefabbd1a948a07f28e37cf F src/upsert.c 215328c3f91623c520ec8672c44323553f12caeb4f01b1090ebdca99fdf7b4f1 F src/utf.c 7267c3fb9e2467020507601af3354c2446c61f444387e094c779dccd5ca62165 -F src/util.c 1fe895c652b3b1b9f4a298b95ebfcfd95e3383952dd26a5baf1c47655c483e5d +F src/util.c f264a84eda716ae009089f1d788b55718062810792b0bfa331e7899f2add39c6 F src/vacuum.c d3d35d8ae893d419ade5fa196d761a83bddcbb62137a1a157ae751ef38b26e82 F src/vdbe.c 6c57525d7db0232d52687d30da1093db0c152f14206c2ef1adf0c19a09d863e3 F src/vdbe.h 70e862ac8a11b590f8c1eaac17a0078429d42bc4ea3f757a9af0f451dd966a71 @@ -2196,8 +2196,8 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee F tool/warnings.sh a554d13f6e5cf3760f041b87939e3d616ec6961859c3245e8ef701d1eafc2ca2 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c -P ff9008e7615d877e6cc852c60097777006b274971646d368eaa56b99a7acf6c7 -R ff4274da2fda9408dbca94e175d79321 +P e75f30c7e66e725a2f3f46c7d4d69a2ff925e2de9a86c3a6ec38897545b43a58 +R afdcaa646f7e2c48f9521367d5bf245b U drh -Z 399684f83892f09fa733c31059114ff6 +Z d27904683472a5531629ef5a5e64c8f1 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index f5219e16ef..8946699b1f 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -e75f30c7e66e725a2f3f46c7d4d69a2ff925e2de9a86c3a6ec38897545b43a58 +2197677491dfc5ec87b57bbf807776875248a250f80ce9a5ce94ae385bb1d2bc diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 26a1947824..5aa8972035 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -4828,17 +4828,22 @@ struct PrintfArguments { sqlite3_value **apArg; /* The argument values */ }; +/* +** Maxium number of base-10 digits in an unsigned 64-bit integer +*/ +#define SQLITE_U64_DIGITS 20 + /* ** An instance of this object receives the decoding of a floating point ** value into an approximate decimal representation. */ struct FpDecode { - int n; /* Significant digits in the decode */ - int iDP; /* Location of the decimal point */ - char *z; /* Start of significant digits */ - char zBuf[20]; /* Storage for significant digits */ - char sign; /* '+' or '-' */ - char isSpecial; /* 1: Infinity 2: NaN */ + int n; /* Significant digits in the decode */ + int iDP; /* Location of the decimal point */ + char *z; /* Start of significant digits */ + char zBuf[SQLITE_U64_DIGITS+1]; /* Storage for significant digits */ + char sign; /* '+' or '-' */ + char isSpecial; /* 1: Infinity 2: NaN */ }; void sqlite3FpDecode(FpDecode*,double,int,int); diff --git a/src/util.c b/src/util.c index eae618da31..9a0456f214 100644 --- a/src/util.c +++ b/src/util.c @@ -998,6 +998,69 @@ static const union { "90919293949596979899" }; +/* +** ARMv6, ARMv7, PPC32 are known to not support hardware u64 division. +*/ +#if (defined(__arm__) && !defined(__aarch64__)) || \ + (defined(__ppc__) && !defined(__ppc64__)) +# define SQLITE_AVOID_U64_DIVIDE 1 +#endif + +#ifdef SQLITE_AVOID_U64_DIVIDE +/* +** Render an unsigned 64-bit integer as text onto the end of a 2-byte +** aligned buffer that is SQLITE_U64_DIGIT+1 bytes long. The last byte +** of the buffer will be filled with a \000 byte. +** +** Return the index into the buffer of the first byte. +** +** This routine is used on platforms where u64-division is slow because +** it is not available in hardware and has to be emulated in software. +** It seeks to minimize the number of u64 divisions and use u32 divisions +** instead. It is slower on platforms that have hardware u64 division, +** but much faster on platforms that do not. +*/ +static int sqlite3UInt64ToText(u64 v, char *zOut){ + u32 x32, kk; + int i; + zOut[SQLITE_U64_DIGITS] = 0; + i = SQLITE_U64_DIGITS; + assert( TWO_BYTE_ALIGNMENT(&sqlite3DigitPairs.a[0]) ); + assert( TWO_BYTE_ALIGNMENT(zOut) ); + while( (v>>32)!=0 ){ + u32 y, x0, x1, y0, y1; + x32 = v % 100000000; + v = v / 100000000; + y = x32 % 10000; + x32 /= 10000; + x1 = x32 / 100; + x0 = x32 % 100; + y1 = y / 100; + y0 = y % 100; + assert( i>=8 ); + i -= 8; + *(u16*)(&zOut[i]) = *(u16*)&sqlite3DigitPairs.a[x1*2]; + *(u16*)(&zOut[i+2]) = *(u16*)&sqlite3DigitPairs.a[x0*2]; + *(u16*)(&zOut[i+4]) = *(u16*)&sqlite3DigitPairs.a[y1*2]; + *(u16*)(&zOut[i+6]) = *(u16*)&sqlite3DigitPairs.a[y0*2]; + } + x32 = v; + while( x32>=10 ){ + kk = x32 % 100; + x32 = x32 / 100; + assert( TWO_BYTE_ALIGNMENT(&sqlite3DigitPairs.a[kk*2]) ); + assert( i>=2 ); + i -= 2; + assert( TWO_BYTE_ALIGNMENT(&zOut[i]) ); + *(u16*)(&zOut[i]) = *(u16*)&sqlite3DigitPairs.a[kk*2]; + } + if( x32 ){ + assert( i>0 ); + zOut[--i] = x32 + '0'; + } + return i; +} +#endif /* defined(SQLITE_AVOID_U64_DIVIDE) */ /* ** Render an signed 64-bit integer as text. Store the result in zOut[] and @@ -1011,7 +1074,7 @@ int sqlite3Int64ToText(i64 v, char *zOut){ int i; u64 x; union { - char a[23]; + char a[SQLITE_U64_DIGITS+1]; u16 forceAlignment; } u; if( v>0 ){ @@ -1023,6 +1086,9 @@ int sqlite3Int64ToText(i64 v, char *zOut){ }else{ x = (v==SMALLEST_INT64) ? ((u64)1)<<63 : (u64)-v; } +#ifdef SQLITE_AVOID_U64_DIVIDE + i = sqlite3UInt64ToText(x, u.a); +#else i = sizeof(u.a)-1; u.a[i] = 0; while( x>=10 ){ @@ -1036,6 +1102,7 @@ int sqlite3Int64ToText(i64 v, char *zOut){ if( x ){ u.a[--i] = x + '0'; } +#endif /* SQLITE_AVOID_U64_DIVIDE */ if( v<0 ) u.a[--i] = '-'; memcpy(zOut, &u.a[i], sizeof(u.a)-i); return sizeof(u.a)-1-i; @@ -1355,37 +1422,43 @@ void sqlite3FpDecode(FpDecode *p, double r, int iRound, int mxRound){ /* Extract significant digits, start at the right-most slot in p->zBuf ** and working back to the right. "i" keeps track of the next slot in ** which to store a digit. */ - i = sizeof(p->zBuf)-1; - zBuf = p->zBuf; + assert( sizeof(p->zBuf)==SQLITE_U64_DIGITS+1 ); assert( v>0 ); + zBuf = p->zBuf; +#ifdef SQLITE_AVOID_U64_DIVIDE + i = sqlite3UInt64ToText(v, zBuf); +#else + i = SQLITE_U64_DIGITS; while( v>=10 ){ int kk = (v%100)*2; assert( TWO_BYTE_ALIGNMENT(&sqlite3DigitPairs.a[kk]) ); - assert( TWO_BYTE_ALIGNMENT(&zBuf[i-1]) ); - *(u16*)(&zBuf[i-1]) = *(u16*)&sqlite3DigitPairs.a[kk]; + assert( TWO_BYTE_ALIGNMENT(&zBuf[i]) ); + assert( i-2>=0 ); + *(u16*)(&zBuf[i-2]) = *(u16*)&sqlite3DigitPairs.a[kk]; i -= 2; v /= 100; } if( v ){ assert( v<10 ); - zBuf[i--] = v + '0'; + assert( i>0 ); + zBuf[--i] = v + '0'; } - assert( i>=0 && izBuf)-1 ); - n = sizeof(p->zBuf) - 1 - i; /* Total number of digits extracted */ +#endif /* SQLITE_AVOID_U64_DIVIDE */ + assert( i>=0 && i0 ); - assert( nzBuf) ); - testcase( n==sizeof(p->zBuf)-1 ); + assert( n<=SQLITE_U64_DIGITS ); p->iDP = n + exp; if( iRound<=0 ){ iRound = p->iDP - iRound; - if( iRound==0 && zBuf[i+1]>='5' ){ + if( iRound==0 && zBuf[i]>='5' ){ iRound = 1; - zBuf[i--] = '0'; + zBuf[--i] = '0'; n++; p->iDP++; } } - z = &zBuf[i+1]; /* z points to the first digit */ + z = &zBuf[i]; /* z points to the first digit */ if( iRound>0 && (iRoundmxRound) ){ if( iRound>mxRound ) iRound = mxRound; if( iRound==17 ){