From: drh Date: Tue, 1 Apr 2008 18:04:11 +0000 (+0000) Subject: Avoid factoring single-instruction constants that end up getting replaced X-Git-Tag: version-3.6.10~1225 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=47de955ea9f3ba1529035b17dd59f1312be68a6e;p=thirdparty%2Fsqlite.git Avoid factoring single-instruction constants that end up getting replaced by an SCopy instruction. (CVS 4952) FossilOrigin-Name: e84ff57b6217afa84d60547dcc3a270b5e116818 --- diff --git a/manifest b/manifest index 33ab66fec1..eec6525f37 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Add\sthe\stestcase()\smacro.\s\sAdditional\sCSE\stest\scoverage.\s(CVS\s4951) -D 2008-04-01T15:06:34 +C Avoid\sfactoring\ssingle-instruction\sconstants\sthat\send\sup\sgetting\sreplaced\nby\san\sSCopy\sinstruction.\s(CVS\s4952) +D 2008-04-01T18:04:11 F Makefile.arm-wince-mingw32ce-gcc ac5f7b2cef0cd850d6f755ba6ee4ab961b1fadf7 F Makefile.in b861627d91df5ee422c54237aa38296954dc0151 F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654 @@ -95,7 +95,7 @@ F src/complete.c 4cf68fd75d60257524cbe74f87351b9848399131 F src/date.c e41ce4513fb0e359dc678d6bddb4ace135fe365d F src/delete.c 74d5c9c824848a14d7dee37264ec302b168c4ddb F src/experimental.c 1b2d1a6cd62ecc39610e97670332ca073c50792b -F src/expr.c bc7ab980abcc211083148eeaea571c4511f41238 +F src/expr.c acc695135dc7f7a3080139ae48c16b92d1fa54fb F src/fault.c 83057e86815d473e526f7df0b0108dfdd022ff23 F src/func.c c9e8c7ff4c45027edee89bde7adbf86a3a3b2afe F src/hash.c 53655c312280211444bfe23af6490a460aec2980 @@ -140,7 +140,7 @@ F src/server.c 087b92a39d883e3fa113cae259d64e4c7438bc96 F src/shell.c 22297fffa6f00a6c6d44020fa13b1184a1bb372d F src/sqlite.h.in b1ac824d9fc163a5d2226ebf5990b09a02a11117 F src/sqlite3ext.h faacd0e6a81aabee0861c6d7883c9172e74ef5b3 -F src/sqliteInt.h 3b9a1f2338d6b0d4361b1901543c830a45a45637 +F src/sqliteInt.h cfe0b6c4b1a9b4be22f856ca8058ccd1bf0e41a8 F src/sqliteLimit.h f435e728c6b620ef7312814d660a81f9356eb5c8 F src/table.c 2c48c575dd59b3a6c5c306bc55f51a9402cf429a F src/tclsqlite.c 1367762764772a233643524c3585b4711a9adcda @@ -248,7 +248,7 @@ F test/crash5.test c7ddcf7ca83abc19901b977732144234ac72a938 F test/crash6.test 873d851c5ba2a46e0f9974c54e1d4a77d9a587d5 F test/crashtest1.c 09c1c7d728ccf4feb9e481671e29dda5669bbcc2 F test/createtab.test 199cf68f44e5d9e87a0b8afc7130fdeb4def3272 -F test/cse.test cb548fa3000a246c80fde7adaa0ee4bd85cbc5e9 +F test/cse.test 4b8a49decaefccb835ecc67249277be491713f6c F test/date.test 8db95a0ba2c8f4c8762ce66859a036c51959a6be F test/default.test 252298e42a680146b1dd64f563b95bdf088d94fb F test/delete.test 57533e88e886608bf5ae0f394e14c2eb1b1f7754 @@ -621,7 +621,7 @@ F www/tclsqlite.tcl 8be95ee6dba05eabcd27a9d91331c803f2ce2130 F www/vdbe.tcl 87a31ace769f20d3627a64fa1fade7fed47b90d0 F www/version3.tcl 890248cf7b70e60c383b0e84d77d5132b3ead42b F www/whentouse.tcl fc46eae081251c3c181bd79c5faef8195d7991a5 -P e25939fb25ec8bde8500a672ca5be3cbb514ac3a -R 739e5874578bdbb30904d6eb328630e7 +P 492490f9c86e52c7a706d9e1bf0ba216d5bb8aba +R 7e48962315256c1abf42d78eded0235b U drh -Z 3436b9a596d9596333afb3b553896141 +Z 215272a1406ad9bddb53b4c21cd1bc47 diff --git a/manifest.uuid b/manifest.uuid index 66aa29daea..d4e940d718 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -492490f9c86e52c7a706d9e1bf0ba216d5bb8aba \ No newline at end of file +e84ff57b6217afa84d60547dcc3a270b5e116818 \ No newline at end of file diff --git a/src/expr.c b/src/expr.c index aa01fb9a39..a17085cc47 100644 --- a/src/expr.c +++ b/src/expr.c @@ -12,7 +12,7 @@ ** This file contains routines used for analyzing expressions and ** for generating VDBE code that evaluates expressions in SQLite. ** -** $Id: expr.c,v 1.364 2008/04/01 15:06:34 drh Exp $ +** $Id: expr.c,v 1.365 2008/04/01 18:04:11 drh Exp $ */ #include "sqliteInt.h" #include @@ -2682,16 +2682,95 @@ int sqlite3ExprCodeAndCache(Parse *pParse, Expr *pExpr, int target){ } /* -** If pExpr is a constant expression, then evaluate the expression +** Return TRUE if pExpr is an constant expression that is appropriate +** for factoring out of a loop. Appropriate expressions are: +** +** * Any expression that evaluates to two or more opcodes. +** +** * Any OP_Integer, OP_Real, OP_String, OP_Blob, OP_Null, +** or OP_Variable that does not need to be placed in a +** specific register. +** +** There is no point in factoring out single-instruction constant +** expressions that need to be placed in a particular register. +** We could factor them out, but then we would end up adding an +** OP_SCopy instruction to move the value into the correct register +** later. We might as well just use the original instruction and +** avoid the OP_SCopy. +*/ +static int isAppropriateForFactoring(Expr *p){ + if( !sqlite3ExprIsConstantNotJoin(p) ){ + return 0; /* Only constant expressions are appropriate for factoring */ + } + if( (p->flags & EP_FixedDest)==0 ){ + return 1; /* Any constant without a fixed destination is appropriate */ + } + while( p->op==TK_UPLUS ) p = p->pLeft; + switch( p->op ){ +#ifndef SQLITE_OMIT_BLOB_LITERAL + case TK_BLOB: +#endif + case TK_VARIABLE: + case TK_INTEGER: + case TK_FLOAT: + case TK_NULL: + case TK_STRING: { + testcase( p->op==TK_BLOB ); + testcase( p->op==TK_VARIABLE ); + testcase( p->op==TK_INTEGER ); + testcase( p->op==TK_FLOAT ); + testcase( p->op==TK_NULL ); + testcase( p->op==TK_STRING ); + /* Single-instruction constants with a fixed destination are + ** better done in-line. If we factor them, they will just end + ** up generating an OP_SCopy to move the value to the destination + ** register. */ + return 0; + } + case TK_UMINUS: { + if( p->pLeft->op==TK_FLOAT || p->pLeft->op==TK_INTEGER ){ + return 0; + } + break; + } + default: { + break; + } + } + return 1; +} + +/* +** If pExpr is a constant expression that is appropriate for +** factoring out of a loop, then evaluate the expression ** into a register and convert the expression into a TK_REGISTER ** expression. */ static int evalConstExpr(void *pArg, Expr *pExpr){ Parse *pParse = (Parse*)pArg; - if( pExpr->op==TK_REGISTER ){ - return 1; + switch( pExpr->op ){ + case TK_REGISTER: { + return 1; + } + case TK_FUNCTION: + case TK_AGG_FUNCTION: + case TK_CONST_FUNC: { + /* The arguments to a function have a fixed destination. + ** Mark them this way to avoid generated unneeded OP_SCopy + ** instructions. + */ + ExprList *pList = pExpr->pList; + if( pList ){ + int i = pList->nExpr; + struct ExprList_item *pItem = pList->a; + for(; i>0; i--, pItem++){ + if( pItem->pExpr ) pItem->pExpr->flags |= EP_FixedDest; + } + } + break; + } } - if( sqlite3ExprIsConstantNotJoin(pExpr) ){ + if( isAppropriateForFactoring(pExpr) ){ int r1 = ++pParse->nMem; int r2; r2 = sqlite3ExprCodeTarget(pParse, pExpr, r1); diff --git a/src/sqliteInt.h b/src/sqliteInt.h index de3a46a231..cc63a04cd3 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -11,7 +11,7 @@ ************************************************************************* ** Internal interface definitions for SQLite. ** -** @(#) $Id: sqliteInt.h,v 1.687 2008/04/01 15:06:34 drh Exp $ +** @(#) $Id: sqliteInt.h,v 1.688 2008/04/01 18:04:11 drh Exp $ */ #ifndef _SQLITEINT_H_ #define _SQLITEINT_H_ @@ -1154,6 +1154,7 @@ struct Expr { #define EP_InfixFunc 0x0080 /* True for an infix function: LIKE, GLOB, etc */ #define EP_ExpCollate 0x0100 /* Collating sequence specified explicitly */ #define EP_AnyAff 0x0200 /* Can take a cached column of any affinity */ +#define EP_FixedDest 0x0400 /* Result needed in a specific register */ /* ** These macros can be used to test, set, or clear bits in the diff --git a/test/cse.test b/test/cse.test index 836e15aba9..ce78c27786 100644 --- a/test/cse.test +++ b/test/cse.test @@ -13,7 +13,7 @@ # factoring constant expressions out of loops and for # common subexpression eliminations. # -# $Id: cse.test,v 1.4 2008/04/01 15:06:34 drh Exp $ +# $Id: cse.test,v 1.5 2008/04/01 18:04:11 drh Exp $ # set testdir [file dirname $argv0] @@ -49,11 +49,31 @@ do_test cse-1.5 { SELECT CASE a WHEN 1 THEN b WHEN 2 THEN c ELSE d END, b, c, d FROM t1 } } {11 11 12 13 22 21 22 23} -do_test cse-1.6 { +do_test cse-1.6.1 { execsql { SELECT CASE b WHEN 11 THEN -b WHEN 21 THEN -c ELSE -d END, b, c, d FROM t1 } } {-11 11 12 13 -22 21 22 23} +do_test cse-1.6.2 { + execsql { + SELECT CASE b+1 WHEN c THEN d WHEN e THEN f ELSE 999 END, b, c, d FROM t1 + } +} {13 11 12 13 23 21 22 23} +do_test cse-1.6.3 { + execsql { + SELECT CASE WHEN b THEN d WHEN e THEN f ELSE 999 END, b, c, d FROM t1 + } +} {13 11 12 13 23 21 22 23} +do_test cse-1.6.4 { + execsql { + SELECT b, c, d, CASE WHEN b THEN d WHEN e THEN f ELSE 999 END FROM t1 + } +} {11 12 13 13 21 22 23 23} +do_test cse-1.6.5 { + execsql { + SELECT b, c, d, CASE WHEN 0 THEN d WHEN e THEN f ELSE 999 END FROM t1 + } +} {11 12 13 15 21 22 23 25} do_test cse-1.7 { execsql { SELECT a, -a, ~a, NOT a, NOT NOT a, a-a, a+a, a*a, a/a, a FROM t1 @@ -89,17 +109,11 @@ do_test cse-1.12 { } } {21 2 21 22 23 24 14 14 13 12 11 1} do_test cse-1.13 { - explain { - SELECT upper(b), typeof(b), b FROM t1 - } execsql { SELECT upper(b), typeof(b), b FROM t1 } } {11 integer 11 21 integer 21} do_test cse-1.14 { - explain { - SELECT b, typeof(b), upper(b), typeof(b), b FROM t1 - } execsql { SELECT b, typeof(b), upper(b), typeof(b), b FROM t1 }