LCOV - code coverage report
Current view: top level - monetdb5/optimizer - opt_remap.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 167 255 65.5 %
Date: 2021-10-13 02:24:04 Functions: 4 4 100.0 %

          Line data    Source code
       1             : /*
       2             :  * This Source Code Form is subject to the terms of the Mozilla Public
       3             :  * License, v. 2.0.  If a copy of the MPL was not distributed with this
       4             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
       5             :  *
       6             :  * Copyright 1997 - July 2008 CWI, August 2008 - 2021 MonetDB B.V.
       7             :  */
       8             : 
       9             : /*
      10             :  * The first attempt of the multiplex optimizer is to locate
      11             :  * a properly typed multi-plexed implementation.
      12             :  * The policy is to search for bat<mod>.<fcn> before going
      13             :  * into the iterator code generation.
      14             :  */
      15             : #include "monetdb_config.h"
      16             : #include "opt_remap.h"
      17             : #include "opt_macro.h"
      18             : #include "opt_multiplex.h"
      19             : 
      20             : static int
      21      139443 : OPTremapDirect(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci, int idx, Module scope){
      22             :         str mod,fcn;
      23             :         char buf[1024];
      24      139443 :         int i, retc = pci->retc;
      25             :         InstrPtr p;
      26             :         const char *bufName, *fcnName;
      27             : 
      28             :         (void) cntxt;
      29             :         (void) stk;
      30      139443 :         mod = VALget(&getVar(mb, getArg(pci, retc+0))->value);
      31      139443 :         fcn = VALget(&getVar(mb, getArg(pci, retc+1))->value);
      32             : 
      33      139443 :         if(strncmp(mod,"bat",3)==0)
      34           0 :                 mod+=3;
      35             : 
      36             : 
      37      139443 :         snprintf(buf,1024,"bat%s",mod);
      38      139443 :         bufName = putName(buf);
      39      139443 :         fcnName = putName(fcn);
      40      139443 :         if(bufName == NULL || fcnName == NULL)
      41             :                 return 0;
      42             : 
      43      139443 :         p= newInstructionArgs(mb, bufName, fcnName, pci->argc + 2);
      44             : 
      45      278896 :         for(i=0; i<pci->retc; i++)
      46      139453 :                 if (i<1)
      47      139443 :                         getArg(p,i) = getArg(pci,i);
      48             :                 else
      49          10 :                         p = pushReturn(mb, p, getArg(pci,i));
      50      139443 :         p->retc= p->argc= pci->retc;
      51      437144 :         for(i= pci->retc+2; i<pci->argc; i++)
      52      297701 :                 p= addArgument(mb,p,getArg(pci,i));
      53      139443 :         if (p->retc == 1 &&
      54      139437 :                 ((bufName == batcalcRef &&
      55      139437 :                 (fcnName == mulRef || fcnName == divRef || fcnName == plusRef || fcnName == minusRef || fcnName == modRef)) || bufName == batmtimeRef || bufName == batstrRef)) {
      56       67442 :                 if (p->argc == 3 &&
      57             :                         /* these two filter out unary batcalc.- with a candidate list */
      58       48367 :                         getBatType(getArgType(mb, p, 1)) != TYPE_oid &&
      59       48367 :                         (getBatType(getArgType(mb, p, 2)) != TYPE_oid && !(isVarConstant(mb, getArg(p, 2)) && getArgType(mb, p, 2) == TYPE_bat))) {
      60             :                         /* add candidate lists */
      61       48166 :                         if (isaBatType(getArgType(mb, p, 1)))
      62       47956 :                                 p = pushNil(mb, p, TYPE_bat);
      63       48166 :                         if (isaBatType(getArgType(mb, p, 2)))
      64       25402 :                                 p = pushNil(mb, p, TYPE_bat);
      65             :                 }
      66             :         }
      67             : 
      68             :         /* now see if we can resolve the instruction */
      69      139443 :         typeChecker(scope,mb,p,idx,TRUE);
      70      139443 :         if( p->typechk== TYPE_UNKNOWN) {
      71         884 :                 freeInstruction(p);
      72         884 :                 return 0;
      73             :         }
      74      138559 :         pushInstruction(mb,p);
      75      138559 :         return 1;
      76             : }
      77             : 
      78             : /*
      79             :  * Multiplex inline functions should be done with care.
      80             :  * The approach taken is to make a temporary copy of the function to be inlined.
      81             :  * To change all the statements to reflect the new situation
      82             :  * and, if no error occurs, replaces the target instruction
      83             :  * with this new block.
      84             :  *
      85             :  * By the time we get here, we know that function is
      86             :  * side-effect free.
      87             :  *
      88             :  * The multiplex upgrade is targeted at all function
      89             :  * arguments whose actual is a BAT and its formal
      90             :  * is a scalar.
      91             :  * This seems sufficient for the SQL generated PSM code,
      92             :  * but does in general not hold.
      93             :  * For example,
      94             :  *
      95             :  * function foo(b:int,c:bat[:oid,:int])
      96             :  *      ... d:= batcalc.+(b,c)
      97             :  * and
      98             :  * multiplex("user","foo",ba:bat[:oid,:int],ca:bat[:oid,:int])
      99             :  * upgrades the first argument. The naive upgrade of
     100             :  * the statement that would fail. The code below catches
     101             :  * most of them by simple prepending "bat" to the MAL function
     102             :  * name and leave it to the type resolver to generate the
     103             :  * error.
     104             :  *
     105             :  * The process terminates as soon as we
     106             :  * find an instruction that does not have a multiplex
     107             :  * counterpart.
     108             :  */
     109             : static int
     110         212 : OPTmultiplexInline(Client cntxt, MalBlkPtr mb, InstrPtr p, int pc )
     111             : {
     112             :         MalBlkPtr mq;
     113             :         InstrPtr q = NULL, sig;
     114             :         char buf[1024];
     115             :         int i,j,k,m, actions=0;
     116         212 :         int refbat=0, retc = p->retc;
     117             :         bit *upgrade;
     118             :         str msg;
     119             : 
     120             : 
     121         212 :         str mod = VALget(&getVar(mb, getArg(p, retc+0))->value);
     122         212 :         str fcn = VALget(&getVar(mb, getArg(p, retc+1))->value);
     123             :         //Symbol s = findSymbol(cntxt->usermodule, mod,fcn);
     124         212 :         Symbol s = findSymbolInModule(getModule(putName(mod)), putName(fcn));
     125             : 
     126         212 :         if( s== NULL || !isSideEffectFree(s->def) ||
     127         135 :                 getInstrPtr(s->def,0)->retc != p->retc ) {
     128          77 :                 return 0;
     129             :         }
     130             :         /*
     131             :          * Determine the variables to be upgraded and adjust their type
     132             :          */
     133         135 :         if((mq = copyMalBlk(s->def)) == NULL) {
     134             :                 return 0;
     135             :         }
     136         135 :         sig= getInstrPtr(mq,0);
     137             : 
     138         135 :         upgrade = (bit*) GDKzalloc(sizeof(bit)*mq->vtop);
     139         135 :         if( upgrade == NULL) {
     140           0 :                 freeMalBlk(mq);
     141           0 :                 return 0;
     142             :         }
     143             : 
     144         135 :         setVarType(mq, 0,newBatType(getArgType(mb,p,0)));
     145         135 :         clrVarFixed(mq,getArg(getInstrPtr(mq,0),0)); /* for typing */
     146         135 :         upgrade[getArg(getInstrPtr(mq,0),0)] = TRUE;
     147             : 
     148         308 :         for(i=3; i<p->argc; i++){
     149         173 :                 if( !isaBatType( getArgType(mq,sig,i-2)) &&
     150         173 :                         isaBatType( getArgType(mb,p,i)) ){
     151             : 
     152         167 :                         if( getBatType(getArgType(mb,p,i)) != getArgType(mq,sig,i-2)){
     153           0 :                                 goto terminateMX;
     154             :                         }
     155             : 
     156         167 :                         setVarType(mq, i-2,newBatType(getArgType(mb,p,i)));
     157         167 :                         upgrade[getArg(sig,i-2)]= TRUE;
     158         167 :                         refbat= getArg(sig,i-2);
     159             :                 }
     160             :         }
     161             :         /*
     162             :          * The next step is to check each instruction of the
     163             :          * to-be-inlined function for arguments that require
     164             :          * an upgrade and resolve it afterwards.
     165             :          */
     166     2340045 :         for(i=1; i<mq->stop; i++) {
     167             :                 int fnd = 0;
     168             : 
     169     2340045 :                 q = getInstrPtr(mq,i);
     170     2340045 :                 if (q->token == ENDsymbol)
     171             :                         break;
     172     5221152 :                 for(j=0; j<q->argc && !fnd; j++)
     173     2881242 :                         if (upgrade[getArg(q,j)]) {
     174     3386884 :                                 for(k=0; k<q->retc; k++){
     175     1693442 :                                         setVarType(mq,getArg(q,j),newBatType(getArgType(mq, q, j)));
     176             :                                         /* for typing */
     177     1693442 :                                         clrVarFixed(mq,getArg(q,k));
     178     1693442 :                                         if (!upgrade[getArg(q,k)]) {
     179        4653 :                                                 upgrade[getArg(q,k)]= TRUE;
     180             :                                                 /* lets restart */
     181             :                                                 i = 0;
     182             :                                         }
     183             :                                 }
     184             :                                 fnd = 1;
     185             :                         }
     186             :                 /* nil:type -> nil:bat[:oid,:type] */
     187     2339910 :                 if (!getModuleId(q) && q->token == ASSIGNsymbol &&
     188      982106 :                         q->argc == 2 && isVarConstant(mq, getArg(q,1)) &&
     189      437575 :                         upgrade[getArg(q,0)] &&
     190       45283 :                         getArgType(mq,q,0) == TYPE_void &&
     191           0 :                         !isaBatType(getArgType(mq, q, 1)) ){
     192             :                                 /* handle nil assignment */
     193           0 :                                 if( ATOMcmp(getArgGDKType(mq, q, 1),
     194             :                                         VALptr(&getVar(mq, getArg(q,1))->value),
     195             :                                         ATOMnilptr(getArgType(mq, q, 1))) == 0) {
     196             :                                 ValRecord cst;
     197           0 :                                 int tpe = newBatType(getArgType(mq, q, 1));
     198             : 
     199           0 :                                 setVarType(mq,getArg(q,0),tpe);
     200           0 :                                 cst.vtype = TYPE_bat;
     201           0 :                                 cst.val.bval = bat_nil;
     202           0 :                                 cst.len = 0;
     203           0 :                                 m =defConstant(mq, tpe, &cst);
     204           0 :                                 if( m >= 0){
     205           0 :                                         getArg(q,1) = m;
     206           0 :                                         setVarType(mq, getArg(q,1), tpe);
     207             :                                 }
     208             :                         } else{
     209             :                                 /* handle constant tail setting */
     210           0 :                                 int tpe = newBatType(getArgType(mq, q, 1));
     211             : 
     212           0 :                                 setVarType(mq,getArg(q,0),tpe);
     213           0 :                                 setModuleId(q,algebraRef);
     214           0 :                                 setFunctionId(q,projectRef);
     215           0 :                                 q= addArgument(mb,q, getArg(q,1));
     216           0 :                                 mq->stmt[i] = q;
     217           0 :                                 getArg(q,1)= refbat;
     218             :                         }
     219             :                 }
     220             :         }
     221             : 
     222             :         /* now upgrade the statements */
     223        1415 :         for(i=1; i<mq->stop; i++){
     224        1415 :                 q= getInstrPtr(mq,i);
     225        1415 :                 if( q->token== ENDsymbol)
     226             :                         break;
     227        2905 :                 for(j=0; j<q->argc; j++)
     228        2037 :                         if ( upgrade[getArg(q,j)]){
     229        1011 :                                 if ( blockStart(q) ||
     230        1003 :                                          q->barrier== REDOsymbol || q->barrier==LEAVEsymbol )
     231           8 :                                         goto terminateMX;
     232        1003 :                                 if (getModuleId(q)){
     233         394 :                                         snprintf(buf,1024,"bat%s",getModuleId(q));
     234         394 :                                         setModuleId(q,putName(buf));
     235         394 :                                         q->typechk = TYPE_UNKNOWN;
     236         394 :                                         if (q->retc == 1 &&
     237         394 :                                                 ((getModuleId(q) == batcalcRef &&
     238         394 :                                                 (getFunctionId(q) == mulRef || getFunctionId(q) == divRef || getFunctionId(q) == plusRef || getFunctionId(q) == minusRef || getFunctionId(q) == modRef)) || getModuleId(q) == batmtimeRef || getModuleId(q) == batstrRef)) {
     239         322 :                                                 if (q->argc == 3 &&
     240             :                                                         /* these two filter out unary batcalc.- with a candidate list */
     241         227 :                                                         getBatType(getArgType(mq, q, 1)) != TYPE_oid &&
     242         227 :                                                         getBatType(getArgType(mq, q, 2)) != TYPE_oid) {
     243             :                                                         /* add candidate lists */
     244         227 :                                                         if (isaBatType(getArgType(mq, q, 1)))
     245         137 :                                                                 q = pushNil(mq, q, TYPE_bat);
     246         227 :                                                         if (isaBatType(getArgType(mq, q, 2)))
     247         120 :                                                                 q = pushNil(mq, q, TYPE_bat);
     248          95 :                                                 } else if (q->argc == 4 &&
     249          94 :                                                                    getBatType(getArgType(mq, q, 3)) == TYPE_bit &&
     250             :                                                                    /* these two filter out unary
     251             :                                                                         * batcalc.- with a candidate
     252             :                                                                         * list */
     253           0 :                                                                    getBatType(getArgType(mq, q, 1)) != TYPE_oid &&
     254           0 :                                                                    getBatType(getArgType(mq, q, 2)) != TYPE_oid) {
     255             :                                                         int a = getArg(q, 3);
     256           0 :                                                         q->argc--;
     257             :                                                         /* add candidate lists */
     258           0 :                                                         if (isaBatType(getArgType(mq, q, 1)))
     259           0 :                                                                 q = pushNil(mq, q, TYPE_bat);
     260           0 :                                                         if (isaBatType(getArgType(mq, q, 2)))
     261           0 :                                                                 q = pushNil(mq, q, TYPE_bat);
     262           0 :                                                         q = pushArgument(mq, q, a);
     263             :                                                 }
     264             :                                         }
     265             : 
     266             :                                         /* now see if we can resolve the instruction */
     267         394 :                                         typeChecker(cntxt->usermodule,mq,q,i,TRUE);
     268         394 :                                         if( q->typechk== TYPE_UNKNOWN)
     269           3 :                                                 goto terminateMX;
     270             :                                         actions++;
     271             :                                         break;
     272             :                                 }
     273             :                                 /* handle simple upgraded assignments as well */
     274         609 :                                 if ( q->token== ASSIGNsymbol &&
     275         609 :                                          q->argc == 2  &&
     276         609 :                                         !(isaBatType( getArgType(mq,q,1))) ){
     277          21 :                                         setModuleId(q,algebraRef);
     278          21 :                                         setFunctionId(q,projectRef);
     279          21 :                                         q= addArgument(mq,q, getArg(q,1));
     280          21 :                                         mq->stmt[i] = q;
     281          21 :                                         getArg(q,1)= refbat;
     282             : 
     283          21 :                                         q->typechk = TYPE_UNKNOWN;
     284          21 :                                         typeChecker(cntxt->usermodule,mq,q,i,TRUE);
     285          21 :                                         if( q->typechk== TYPE_UNKNOWN)
     286           0 :                                                 goto terminateMX;
     287             :                                         actions++;
     288             :                                         break;
     289             :                                 }
     290             :                 }
     291             :         }
     292             : 
     293             : 
     294         124 :         if(mq->errors){
     295           0 : terminateMX:
     296             : 
     297          11 :                 freeMalBlk(mq);
     298          11 :                 GDKfree(upgrade);
     299             : 
     300             :                 /* ugh ugh, fallback to non inline, but optimized code */
     301          11 :                 msg = OPTmultiplexSimple(cntxt, s->def);
     302          11 :                 if(msg)
     303           0 :                         freeException(msg);
     304          11 :                 s->def->inlineProp = 0;
     305          11 :                 return 0;
     306             :         }
     307             :         /*
     308             :          * We have successfully constructed a variant
     309             :          * of the to-be-inlined function. Put it in place
     310             :          * of the original multiplex.
     311             :          * But first, shift the arguments of the multiplex.
     312             :          */
     313         124 :         delArgument(p,2);
     314         124 :         delArgument(p,1);
     315         124 :         inlineMALblock(mb,pc,mq);
     316             : 
     317         124 :         freeMalBlk(mq);
     318         124 :         GDKfree(upgrade);
     319         124 :         return 1;
     320             : }
     321             : /*
     322             :  * The comparison multiplex operations with a constant head may be supported
     323             :  * by reverse of the operation.
     324             :  */
     325             : static struct{
     326             :         char *src, *dst;
     327             :         int len;
     328             : }OperatorMap[]={
     329             : {"<", ">",1},
     330             : {">", "<",1},
     331             : {">=", "<=",2},
     332             : {"<=", ">=",2},
     333             : {"==", "==",2},
     334             : {"!=", "!=",2},
     335             : {0,0,0}};
     336             : 
     337             : static int
     338         884 : OPTremapSwitched(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci, int idx, Module scope){
     339             :         char *fcn;
     340             :         int r,i;
     341             :         (void) stk;
     342             :         (void) scope;
     343             : 
     344         884 :         if( !isMultiplex(pci) &&
     345           0 :                 !isVarConstant(mb,getArg(pci,1)) &&
     346           0 :                 !isVarConstant(mb,getArg(pci,2)) &&
     347           0 :                 !isVarConstant(mb,getArg(pci,4)) &&
     348           0 :                 pci->argc != 5)
     349             :                         return 0;
     350         884 :         fcn = VALget(&getVar(mb, getArg(pci, 2))->value);
     351        6188 :         for(i=0;OperatorMap[i].src;i++)
     352        5304 :         if( strcmp(fcn,OperatorMap[i].src)==0){
     353             :                 /* found a candidate for a switch */
     354           0 :                 getVarConstant(mb, getArg(pci, 2)).val.sval = (char *) putNameLen(OperatorMap[i].dst,OperatorMap[i].len);
     355           0 :                 getVarConstant(mb, getArg(pci, 2)).len = OperatorMap[i].len;
     356           0 :                 r= getArg(pci,3); getArg(pci,3)=getArg(pci,4);getArg(pci,4)=r;
     357           0 :                 r= OPTremapDirect(cntxt,mb, stk, pci, idx, scope);
     358             : 
     359             :                 /* always restore the allocated function name */
     360           0 :                 getVarConstant(mb, getArg(pci, 2)).val.sval= fcn;
     361           0 :                 getVarConstant(mb, getArg(pci, 2)).len = strlen(fcn);
     362             : 
     363           0 :                 if (r) return 1;
     364             : 
     365             :                 /* restore the arguments */
     366           0 :                 r= getArg(pci,3); getArg(pci,3)=getArg(pci,4);getArg(pci,4)=r;
     367             :         }
     368             :         return 0;
     369             : }
     370             : 
     371             : str
     372      356723 : OPTremapImplementation(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
     373             : {
     374             :         InstrPtr *old, p;
     375             :         int i, limit, slimit, actions= 0;
     376      356723 :         Module scope = cntxt->usermodule;
     377             :         str msg = MAL_SUCCEED;
     378             : 
     379    20062381 :         for( i=0; i< mb->stop; i++){
     380    19725177 :                 p = getInstrPtr(mb, i);
     381    19725177 :                 if (isMultiplex(p) || (p->argc == 4 && getModuleId(p) == aggrRef && getFunctionId(p) == avgRef)){
     382             :                         break;
     383             :                 }
     384             :         }
     385      356722 :         if( i == mb->stop){
     386      337204 :                 goto wrapup;
     387             :         }
     388             : 
     389       19518 :         old = mb->stmt;
     390             :         limit = mb->stop;
     391       19518 :         slimit = mb->ssize;
     392       19518 :         if ( newMalBlkStmt(mb, mb->ssize) < 0 )
     393           0 :                 throw(MAL,"optmizer.remap", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     394             : 
     395     3994194 :         for (i = 0; i < limit; i++) {
     396     3974676 :                 p = old[i];
     397     3974676 :                 if (isMultiplex(p)){
     398             :                         /*
     399             :                          * The next step considered is to handle inlined functions.
     400             :                          * It means we have already skipped the most obvious ones,
     401             :                          * such as the calculator functions. It is particularly
     402             :                          * geared at handling the PSM code.
     403             :                          */
     404      139655 :                         str mod = VALget(&getVar(mb, getArg(p, p->retc+0))->value);
     405      139655 :                         str fcn = VALget(&getVar(mb, getArg(p, p->retc+1))->value);
     406             :                         //Symbol s = findSymbol(cntxt->usermodule, mod,fcn);
     407      139655 :                         Symbol s = findSymbolInModule(getModule(putName(mod)),putName(fcn));
     408             : 
     409      139655 :                         if (s && s->def->inlineProp ){
     410         212 :                                 pushInstruction(mb, p);
     411         212 :                                 if( OPTmultiplexInline(cntxt,mb,p,mb->stop-1) ){
     412         124 :                                         actions++;
     413             :                                 }
     414      140327 :                         } else if (OPTremapDirect(cntxt, mb, stk, p, i, scope) ||
     415         884 :                                 OPTremapSwitched(cntxt, mb, stk, p, i, scope)) {
     416      138559 :                                 freeInstruction(p);
     417      138559 :                                 actions++;
     418             :                         } else {
     419         884 :                                 pushInstruction(mb, p);
     420             :                         }
     421     3835022 :                 } else if (p->argc == 4 &&
     422      608162 :                         getModuleId(p) == aggrRef &&
     423           0 :                         getFunctionId(p) == avgRef) {
     424             :                         /* group aggr.avg -> aggr.sum/aggr.count */
     425             :                         InstrPtr sum, avg,t, iszero;
     426             :                         InstrPtr cnt;
     427           0 :                         sum = copyInstruction(p);
     428           0 :                         if( sum == NULL)
     429           0 :                                 throw(MAL, "remap", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     430           0 :                         cnt = copyInstruction(p);
     431           0 :                         if( cnt == NULL){
     432           0 :                                 freeInstruction(sum);
     433           0 :                                 throw(MAL, "remap", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     434             :                         }
     435           0 :                         setFunctionId(sum, sumRef);
     436           0 :                         setFunctionId(cnt, countRef);
     437           0 :                         getArg(sum,0) = newTmpVariable(mb, getArgType(mb, p, 1));
     438           0 :                         getArg(cnt,0) = newTmpVariable(mb, newBatType(TYPE_lng));
     439           0 :                         pushInstruction(mb, sum);
     440           0 :                         pushInstruction(mb, cnt);
     441             : 
     442           0 :                         t = newInstruction(mb, batcalcRef, eqRef);
     443           0 :                         getArg(t,0) = newTmpVariable(mb, newBatType(TYPE_bit));
     444           0 :                         t = addArgument(mb, t, getDestVar(cnt));
     445           0 :                         t = pushLng(mb, t, 0);
     446           0 :                         pushInstruction(mb, t);
     447             :                         iszero = t;
     448             : 
     449           0 :                         t = newInstruction(mb, batcalcRef, dblRef);
     450           0 :                         getArg(t,0) = newTmpVariable(mb, getArgType(mb, p, 0));
     451           0 :                         t = addArgument(mb, t, getDestVar(sum));
     452           0 :                         pushInstruction(mb, t);
     453             :                         sum = t;
     454             : 
     455           0 :                         t = newInstruction(mb, batcalcRef, ifthenelseRef);
     456           0 :                         getArg(t,0) = newTmpVariable(mb, getArgType(mb, p, 0));
     457           0 :                         t = addArgument(mb, t, getDestVar(iszero));
     458           0 :                         t = pushNil(mb, t, TYPE_dbl);
     459           0 :                         t = addArgument(mb, t, getDestVar(sum));
     460           0 :                         pushInstruction(mb, t);
     461             :                         sum = t;
     462             : 
     463           0 :                         t = newInstruction(mb, batcalcRef, dblRef);
     464           0 :                         getArg(t,0) = newTmpVariable(mb, getArgType(mb, p, 0));
     465           0 :                         t = addArgument(mb, t, getDestVar(cnt));
     466           0 :                         pushInstruction(mb, t);
     467             :                         cnt = t;
     468             : 
     469           0 :                         avg = newInstruction(mb, batcalcRef, divRef);
     470           0 :                         getArg(avg, 0) = getArg(p, 0);
     471           0 :                         avg = addArgument(mb, avg, getDestVar(sum));
     472           0 :                         avg = addArgument(mb, avg, getDestVar(cnt));
     473           0 :                         avg = pushNil(mb, avg, TYPE_bat);
     474           0 :                         avg = pushNil(mb, avg, TYPE_bat);
     475           0 :                         freeInstruction(p);
     476           0 :                         pushInstruction(mb, avg);
     477             :                 } else {
     478     3835022 :                         pushInstruction(mb, p);
     479             :                 }
     480             :         }
     481     2620075 :         for(; i<slimit; i++)
     482     2600557 :                 if( old[i])
     483           0 :                         pushInstruction(mb, old[i]);
     484       19518 :         GDKfree(old);
     485             : 
     486       19518 :         if (actions)
     487       19264 :                 msg = chkTypes(cntxt->usermodule,mb,TRUE);
     488             :         /* Defense line against incorrect plans */
     489       19518 :         if( msg == MAL_SUCCEED && actions > 0){
     490       19264 :                 msg = chkTypes(cntxt->usermodule, mb, FALSE);
     491       19264 :                 if (!msg)
     492       19264 :                         msg = chkFlow(mb);
     493       19264 :                 if (!msg)
     494       19264 :                         msg = chkDeclarations(mb);
     495             :         }
     496         254 : wrapup:
     497             :         /* keep actions taken as a fake argument*/
     498      356722 :         (void) pushInt(mb, pci, actions);
     499      356723 :         return msg;
     500             : }

Generated by: LCOV version 1.14