]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Avoid factoring single-instruction constants that end up getting replaced
authordrh <drh@noemail.net>
Tue, 1 Apr 2008 18:04:11 +0000 (18:04 +0000)
committerdrh <drh@noemail.net>
Tue, 1 Apr 2008 18:04:11 +0000 (18:04 +0000)
by an SCopy instruction. (CVS 4952)

FossilOrigin-Name: e84ff57b6217afa84d60547dcc3a270b5e116818

manifest
manifest.uuid
src/expr.c
src/sqliteInt.h
test/cse.test

index 33ab66fec15a241ebffbaf7800ea06ce02234ba5..eec6525f378f04bb3e624c0b0264ce001c7f37b8 100644 (file)
--- 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
index 66aa29daeaf6ed9b3d354d010a16a07592a61df9..d4e940d71860f6b02d305b25a82c23ad7dedd8ea 100644 (file)
@@ -1 +1 @@
-492490f9c86e52c7a706d9e1bf0ba216d5bb8aba
\ No newline at end of file
+e84ff57b6217afa84d60547dcc3a270b5e116818
\ No newline at end of file
index aa01fb9a39c8d0bf8c94c08a4969d93f2b75fb56..a17085cc4788074dd21482e9198e69d2d1dd57dc 100644 (file)
@@ -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 <ctype.h>
@@ -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);
index de3a46a231edd8bd078b87cac5d1fce9e9e21ffa..cc63a04cd34f3c624e32b446307308572d7d8732 100644 (file)
@@ -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 
index 836e15aba983660d7bf93eb6be9385481351c1b9..ce78c277869d4d7c4f52925e6888b4ec68831313 100644 (file)
@@ -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
   }