Index: src/vdbe.c ================================================================== --- src/vdbe.c +++ src/vdbe.c @@ -3890,14 +3890,14 @@ ** The IdxGE opcode will be skipped if this opcode succeeds, but the ** IdxGE opcode will be used on subsequent loop iterations. ** ** See also: Found, NotFound, SeekGt, SeekGe, SeekLt */ -case OP_SeekLT: /* jump, in3 */ -case OP_SeekLE: /* jump, in3 */ -case OP_SeekGE: /* jump, in3 */ -case OP_SeekGT: { /* jump, in3 */ +case OP_SeekLT: /* jump, in3, group */ +case OP_SeekLE: /* jump, in3, group */ +case OP_SeekGE: /* jump, in3, group */ +case OP_SeekGT: { /* jump, in3, group */ int res; /* Comparison result */ int oc; /* Opcode */ VdbeCursor *pC; /* The cursor to seek */ UnpackedRecord r; /* The key to seek for */ int nField; /* Number of columns or fields in the key */ @@ -7217,12 +7217,12 @@ ** the sqlite3_context object occurs only once, rather than once for each ** evaluation of the function. ** ** See also: Function0, AggStep, AggFinal */ -case OP_PureFunc0: -case OP_Function0: { +case OP_PureFunc0: /* group */ +case OP_Function0: { /* group */ int n; sqlite3_context *pCtx; assert( pOp->p4type==P4_FUNCDEF ); n = pOp->p5; @@ -7242,12 +7242,12 @@ assert( OP_PureFunc == OP_PureFunc0+2 ); assert( OP_Function == OP_Function0+2 ); pOp->opcode += 2; /* Fall through into OP_Function */ } -case OP_PureFunc: -case OP_Function: { +case OP_PureFunc: /* group */ +case OP_Function: { /* group */ int i; sqlite3_context *pCtx; assert( pOp->p4type==P4_FUNCCTX ); pCtx = pOp->p4.pCtx; Index: tool/mkopcodeh.tcl ================================================================== --- tool/mkopcodeh.tcl +++ tool/mkopcodeh.tcl @@ -22,20 +22,22 @@ # code to translate from one to the other is avoided. This makes the # code generator smaller and faster. # # This script also scans for lines of the form: # -# case OP_aaaa: /* jump, in1, in2, in3, out2-prerelease, out3 */ +# case OP_aaaa: /* jump, in1, in2, in3, out2, out3 */ # # When such comments are found on an opcode, it means that certain # properties apply to that opcode. Set corresponding flags using the # OPFLG_INITIALIZER macro. # set in stdin set currentOp {} +set prevName {} set nOp 0 +set nGroup 0 while {![eof $in]} { set line [gets $in] # Remember the TK_ values from the parse.h file. # NB: The "TK_" prefix stands for "ToKen", not the graphical Tk toolkit @@ -75,10 +77,11 @@ if {[regexp {^case OP_} $line]} { set line [split $line] set name [string trim [lindex $line 1] :] if {$name=="OP_Abortable"} continue; # put OP_Abortable last set op($name) -1 + set group($name) 0 set jump($name) 0 set in1($name) 0 set in2($name) 0 set in3($name) 0 set out2($name) 0 @@ -95,19 +98,35 @@ set used($val) 1 set sameas($val) $sym set def($val) $name } } - jump {set jump($name) 1} - in1 {set in1($name) 1} - in2 {set in2($name) 1} - in3 {set in3($name) 1} - out2 {set out2($name) 1} - out3 {set out3($name) 1} + group {set group($name) 1} + jump {set jump($name) 1} + in1 {set in1($name) 1} + in2 {set in2($name) 1} + in3 {set in3($name) 1} + out2 {set out2($name) 1} + out3 {set out3($name) 1} } + } + if {$group($name)} { + set newGroup 0 + if {[info exists groups($nGroup)]} { + if {$prevName=="" || !$group($prevName)} { + set newGroup 1 + } + } + lappend groups($nGroup) $name + if {$newGroup} {incr nGroup} + } else { + if {$prevName!="" && $group($prevName)} { + incr nGroup + } } set order($nOp) $name + set prevName $name incr nOp } } # Assign numbers to all opcodes and output the result. @@ -179,12 +198,43 @@ set name $order($i) if {$jump($name) && $op($name)>$mxJump} {set mxJump $op($name)} } -# Generate the numeric values for all remaining opcodes +# Generate the numeric values for all remaining opcodes, while +# preserving any groupings of opcodes (i.e. those that must be +# together). # +for {set g 0} {$g<$nGroup} {incr g} { + set gLen [llength $groups($g)] + set ok 0; set start -1 + while {!$ok} { + set seek $cnt; incr seek + while {[info exists used($seek)]} {incr seek} + set ok 1; set start $seek + for {set j 0} {$j<$gLen} {incr j} { + incr seek + if {[info exists used($seek)]} { + set ok 0; break + } + } + } + if {$ok} { + set next $start + for {set j 0} {$j<$gLen} {incr j} { + set name [lindex $groups($g) $j] + if {$op($name)>=0} continue + set op($name) $next + set used($next) 1 + set def($next) $name + incr next + } + } else { + error "cannot find opcodes for group: $groups($g)" + } +} + for {set i 0} {$i<$nOp} {incr i} { set name $order($i) if {$op($name)<0} { incr cnt while {[info exists used($cnt)]} {incr cnt} @@ -201,11 +251,11 @@ } if {$i>$max} {set max $i} set name $def($i) puts -nonewline [format {#define %-16s %3d} $name $i] set com {} - if {$jump($name)} { + if {[info exists jump($name)] && $jump($name)} { lappend com "jump" } if {[info exists sameas($i)]} { lappend com "same as $sameas($i)" }