Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Simplify the OPFLG processing logic in the VDBE for a speed boost in the VDBE processing loop and a reduction in code size. |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA1: |
3352b3eba545c3128efb7665ec91d4df |
User & Date: | drh 2009-11-13 19:43:44.000 |
Context
2009-11-13
| ||
20:52 | Performance improvements and size reductions on the OP_Seek* family of VDBE opcodes. (check-in: ed820f45cf user: drh tags: trunk) | |
19:43 | Simplify the OPFLG processing logic in the VDBE for a speed boost in the VDBE processing loop and a reduction in code size. (check-in: 3352b3eba5 user: drh tags: trunk) | |
17:05 | Force 8-byte memory alignment on memory allocated for VDBE cursors. (check-in: bdc45ba77f user: drh tags: trunk) | |
Changes
Changes to mkopcodeh.awk.
︙ | ︙ | |||
45 46 47 48 49 50 51 52 53 54 55 56 57 58 | sub("\r","",name) op[name] = -1 jump[name] = 0 out2_prerelease[name] = 0 in1[name] = 0 in2[name] = 0 in3[name] = 0 out3[name] = 0 for(i=3; i<NF; i++){ if($i=="same" && $(i+1)=="as"){ sym = $(i+2) sub(/,/,"",sym) op[name] = tk[sym] used[op[name]] = 1 | > | 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 | sub("\r","",name) op[name] = -1 jump[name] = 0 out2_prerelease[name] = 0 in1[name] = 0 in2[name] = 0 in3[name] = 0 out2[name] = 0 out3[name] = 0 for(i=3; i<NF; i++){ if($i=="same" && $(i+1)=="as"){ sym = $(i+2) sub(/,/,"",sym) op[name] = tk[sym] used[op[name]] = 1 |
︙ | ︙ | |||
66 67 68 69 70 71 72 73 74 75 76 77 78 79 | out2_prerelease[name] = 1 }else if(x=="in1"){ in1[name] = 1 }else if(x=="in2"){ in2[name] = 1 }else if(x=="in3"){ in3[name] = 1 }else if(x=="out3"){ out3[name] = 1 } } order[n_op++] = name; } | > > | 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 | out2_prerelease[name] = 1 }else if(x=="in1"){ in1[name] = 1 }else if(x=="in2"){ in2[name] = 1 }else if(x=="in3"){ in3[name] = 1 }else if(x=="out2"){ out2[name] = 1 }else if(x=="out3"){ out3[name] = 1 } } order[n_op++] = name; } |
︙ | ︙ | |||
121 122 123 124 125 126 127 | # bit 2: output to p1. release p1 before opcode runs # for(i=0; i<=max; i++) bv[i] = 0; for(i=0; i<n_op; i++){ name = order[i]; x = op[name] a0 = a1 = a2 = a3 = a4 = a5 = a6 = a7 = 0 | | > | > | | 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 | # bit 2: output to p1. release p1 before opcode runs # for(i=0; i<=max; i++) bv[i] = 0; for(i=0; i<n_op; i++){ name = order[i]; x = op[name] a0 = a1 = a2 = a3 = a4 = a5 = a6 = a7 = 0 # a7 = a9 = a10 = a11 = a12 = a13 = a14 = a15 = 0 if( jump[name] ) a0 = 1; if( out2_prerelease[name] ) a1 = 2; if( in1[name] ) a2 = 4; if( in2[name] ) a3 = 8; if( in3[name] ) a4 = 16; if( out2[name] ) a5 = 32; if( out3[name] ) a6 = 64; # bv[x] = a0+a1+a2+a3+a4+a5+a6+a7+a8+a9+a10+a11+a12+a13+a14+a15; bv[x] = a0+a1+a2+a3+a4+a5+a6+a7; } print "\n" print "/* Properties such as \"out2\" or \"jump\" that are specified in" print "** comments following the \"case\" for each opcode in the vdbe.c" print "** are encoded into bitvectors as follows:" print "*/" print "#define OPFLG_JUMP 0x0001 /* jump: P2 holds jmp target */" print "#define OPFLG_OUT2_PRERELEASE 0x0002 /* out2-prerelease: */" print "#define OPFLG_IN1 0x0004 /* in1: P1 is an input */" print "#define OPFLG_IN2 0x0008 /* in2: P2 is an input */" print "#define OPFLG_IN3 0x0010 /* in3: P3 is an input */" print "#define OPFLG_OUT2 0x0020 /* out2: P2 is an output */" print "#define OPFLG_OUT3 0x0040 /* out3: P3 is an output */" print "#define OPFLG_INITIALIZER {\\" for(i=0; i<=max; i++){ if( i%8==0 ) printf("/* %3d */",i) printf " 0x%02x,", bv[i] if( i%8==7 ) printf("\\\n"); } print "}" } |
Changes to src/vdbe.c.
︙ | ︙ | |||
673 674 675 676 677 678 679 | /* Do common setup processing for any opcode that is marked ** with the "out2-prerelease" tag. Such opcodes have a single ** output which is specified by the P2 parameter. The P2 register ** is initialized to a NULL. */ opProperty = opcodeProperty[pOp->opcode]; | > > > | | | | | | | | < < < < < < < < < < < < | | | | | > | | | < < < < | < < | > | | | | < | < < < < > | < < < < | > | | > | 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 | /* Do common setup processing for any opcode that is marked ** with the "out2-prerelease" tag. Such opcodes have a single ** output which is specified by the P2 parameter. The P2 register ** is initialized to a NULL. */ opProperty = opcodeProperty[pOp->opcode]; if( opProperty & (OPFLG_OUT2_PRERELEASE | OPFLG_IN1 | OPFLG_IN2 | OPFLG_IN3 | OPFLG_OUT2 | OPFLG_OUT3) ){ if( (opProperty & OPFLG_OUT2_PRERELEASE)!=0 ){ assert( pOp->p2>0 ); assert( pOp->p2<=p->nMem ); pOut = &p->aMem[pOp->p2]; sqlite3VdbeMemReleaseExternal(pOut); pOut->flags = MEM_Null; pOut->n = 0; }else{ if( (opProperty & OPFLG_IN1)!=0 ){ assert( pOp->p1>0 ); assert( pOp->p1<=p->nMem ); pIn1 = &p->aMem[pOp->p1]; REGISTER_TRACE(pOp->p1, pIn1); } if( (opProperty & (OPFLG_IN2|OPFLG_OUT2))!=0 ){ assert( pOp->p2>0 ); assert( pOp->p2<=p->nMem ); assert( (opProperty & OPFLG_OUT2)==0 || (opProperty & OPFLG_IN3)==0 ); pIn2 = pOut = &p->aMem[pOp->p2]; } if( (opProperty & (OPFLG_IN3|OPFLG_OUT3))!=0 ){ assert( pOp->p3>0 ); assert( pOp->p3<=p->nMem ); pIn3 = pOut = &p->aMem[pOp->p3]; } #ifdef SQLITE_DEBUG if( opProperty & OPFLG_IN2 ){ REGISTER_TRACE(pOp->p2, pIn2); } if( opProperty & OPFLG_IN3 ){ REGISTER_TRACE(pOp->p3, pIn3); } #endif } } switch( pOp->opcode ){ /***************************************************************************** ** What follows is a massive switch statement where each case implements a ** separate instruction in the virtual machine. If we follow the usual ** indentation conventions, each case should be indented by 6 spaces. But ** that is a lot of wasted space on the left margin. So the code within |
︙ | ︙ | |||
782 783 784 785 786 787 788 | } /* Opcode: Gosub P1 P2 * * * ** ** Write the current address onto register P1 ** and then jump to address P2. */ | | < < < | 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 | } /* Opcode: Gosub P1 P2 * * * ** ** Write the current address onto register P1 ** and then jump to address P2. */ case OP_Gosub: { /* jump, in1 */ assert( (pIn1->flags & MEM_Dyn)==0 ); pIn1->flags = MEM_Int; pIn1->u.i = pc; REGISTER_TRACE(pOp->p1, pIn1); pc = pOp->p2 - 1; break; } |
︙ | ︙ | |||
1071 1072 1073 1074 1075 1076 1077 | /* Opcode: Copy P1 P2 * * * ** ** Make a copy of register P1 into register P2. ** ** This instruction makes a deep copy of the value. A duplicate ** is made of any string or blob constant. See also OP_SCopy. */ | | < < < | < < < < | 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 | /* Opcode: Copy P1 P2 * * * ** ** Make a copy of register P1 into register P2. ** ** This instruction makes a deep copy of the value. A duplicate ** is made of any string or blob constant. See also OP_SCopy. */ case OP_Copy: { /* in1, out2 */ assert( pOut!=pIn1 ); sqlite3VdbeMemShallowCopy(pOut, pIn1, MEM_Ephem); Deephemeralize(pOut); REGISTER_TRACE(pOp->p2, pOut); break; } /* Opcode: SCopy P1 P2 * * * ** ** Make a shallow copy of register P1 into register P2. ** ** This instruction makes a shallow copy of the value. If the value ** is a string or blob, then the copy is only a pointer to the ** original and hence if the original changes so will the copy. ** Worse, if the original is deallocated, the copy becomes invalid. ** Thus the program must guarantee that the original will not change ** during the lifetime of the copy. Use OP_Copy to make a complete ** copy. */ case OP_SCopy: { /* in1, out2 */ assert( pOut!=pIn1 ); sqlite3VdbeMemShallowCopy(pOut, pIn1, MEM_Ephem); REGISTER_TRACE(pOp->p2, pOut); break; } /* Opcode: ResultRow P1 P2 * * * |
︙ | ︙ | |||
1941 1942 1943 1944 1945 1946 1947 | /* Opcode: Not P1 P2 * * * ** ** Interpret the value in register P1 as a boolean value. Store the ** boolean complement in register P2. If the value in register P1 is ** NULL, then a NULL is stored in P2. */ | | < | < | 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 | /* Opcode: Not P1 P2 * * * ** ** Interpret the value in register P1 as a boolean value. Store the ** boolean complement in register P2. If the value in register P1 is ** NULL, then a NULL is stored in P2. */ case OP_Not: { /* same as TK_NOT, in1, out2 */ if( pIn1->flags & MEM_Null ){ sqlite3VdbeMemSetNull(pOut); }else{ sqlite3VdbeMemSetInt64(pOut, !sqlite3VdbeIntValue(pIn1)); } break; } /* Opcode: BitNot P1 P2 * * * ** ** Interpret the content of register P1 as an integer. Store the ** ones-complement of the P1 value into register P2. If P1 holds ** a NULL then store a NULL in P2. */ case OP_BitNot: { /* same as TK_BITNOT, in1, out2 */ if( pIn1->flags & MEM_Null ){ sqlite3VdbeMemSetNull(pOut); }else{ sqlite3VdbeMemSetInt64(pOut, ~sqlite3VdbeIntValue(pIn1)); } break; } |
︙ | ︙ | |||
4329 4330 4331 4332 4333 4334 4335 | ** ** If the P1 index entry is less than the key value then jump to P2. ** Otherwise fall through to the next instruction. ** ** If P5 is non-zero then the key value is increased by an epsilon prior ** to the comparison. This makes the opcode work like IdxLE. */ | | | | 4298 4299 4300 4301 4302 4303 4304 4305 4306 4307 4308 4309 4310 4311 4312 4313 | ** ** If the P1 index entry is less than the key value then jump to P2. ** Otherwise fall through to the next instruction. ** ** If P5 is non-zero then the key value is increased by an epsilon prior ** to the comparison. This makes the opcode work like IdxLE. */ case OP_IdxLT: /* jump */ case OP_IdxGE: { /* jump */ VdbeCursor *pC; int res; UnpackedRecord r; assert( pOp->p1>=0 && pOp->p1<p->nCursor ); pC = p->apCsr[pOp->p1]; assert( pC!=0 ); |
︙ | ︙ | |||
4692 4693 4694 4695 4696 4697 4698 | /* Opcode: RowSetAdd P1 P2 * * * ** ** Insert the integer value held by register P2 into a boolean index ** held in register P1. ** ** An assertion fails if P2 is not an integer. */ | | < < < < < < | | | | | | < < < < | | | < | 4661 4662 4663 4664 4665 4666 4667 4668 4669 4670 4671 4672 4673 4674 4675 4676 4677 4678 4679 4680 4681 4682 4683 4684 4685 4686 4687 4688 4689 4690 4691 4692 4693 4694 4695 4696 4697 4698 4699 4700 4701 | /* Opcode: RowSetAdd P1 P2 * * * ** ** Insert the integer value held by register P2 into a boolean index ** held in register P1. ** ** An assertion fails if P2 is not an integer. */ case OP_RowSetAdd: { /* in1, in2 */ assert( (pIn2->flags & MEM_Int)!=0 ); if( (pIn1->flags & MEM_RowSet)==0 ){ sqlite3VdbeMemSetRowSet(pIn1); if( (pIn1->flags & MEM_RowSet)==0 ) goto no_mem; } sqlite3RowSetInsert(pIn1->u.pRowSet, pIn2->u.i); break; } /* Opcode: RowSetRead P1 P2 P3 * * ** ** Extract the smallest value from boolean index P1 and put that value into ** register P3. Or, if boolean index P1 is initially empty, leave P3 ** unchanged and jump to instruction P2. */ case OP_RowSetRead: { /* jump, in1, out3 */ i64 val; CHECK_FOR_INTERRUPT; if( (pIn1->flags & MEM_RowSet)==0 || sqlite3RowSetNext(pIn1->u.pRowSet, &val)==0 ){ /* The boolean index is empty */ sqlite3VdbeMemSetNull(pIn1); pc = pOp->p2 - 1; }else{ /* A value was pulled from the index */ sqlite3VdbeMemSetInt64(pOut, val); } break; } /* Opcode: RowSetTest P1 P2 P3 P4 ** |
︙ | ︙ |