LCOV - code coverage report
Current view: top level - monetdb5/optimizer - opt_macro.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 90 275 32.7 %
Date: 2021-10-13 02:24:04 Functions: 5 11 45.5 %

          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             : #include "monetdb_config.h"
      10             : #include "opt_prelude.h"
      11             : #include "opt_macro.h"
      12             : #include "mal_interpreter.h"
      13             : #include "mal_instruction.h"
      14             : 
      15             : static int
      16           0 : malMatch(InstrPtr p1, InstrPtr p2)
      17             : {
      18             :         int i, j;
      19             : 
      20           0 :         if (getFunctionId(p1) == 0 && getFunctionId(p2) != 0)
      21             :                 return 0;
      22           0 :         if (getModuleId(p1) == 0 && getModuleId(p2) != 0)
      23             :                 return 0;
      24           0 :         if (getModuleId(p1) != getModuleId(p2))
      25             :                 return 0;
      26           0 :         if (getFunctionId(p2) == 0)
      27             :                 return 0;
      28           0 :         if (getFunctionId(p1) != getFunctionId(p2))
      29             :                 return 0;
      30           0 :         if (p1->retc != p2->retc)
      31             :                 return 0;
      32           0 :         if (p1->argc != p2->argc)
      33             :                 return 0;
      34           0 :         if (p1->barrier != p2->barrier)
      35             :                 return 0;
      36           0 :         for (i = 0; i < p1->argc; i++)
      37           0 :                 for (j = i + 1; j < p1->argc; j++)
      38           0 :                         if ((getArg(p1, i) == getArg(p1, j)) != (getArg(p2, i) == getArg(p2, j)))
      39             :                                 return 0;
      40             :         return 1;
      41             : }
      42             : 
      43             : /*
      44             :  * Matching a block calls for building two variable lists used.
      45             :  * The isomorphism can be determined after-wards using a single scan.
      46             :  * The candidate block is matched with mb starting at a given pc.
      47             :  * The candidate block is expected to defined as a function, including
      48             :  * a signature and end-statement. They are ignored in the comparison
      49             :  *
      50             :  * Beware, the variables in the block being removed, could be
      51             :  * used furtheron in the program. [tricky to detect, todo]
      52             :  */
      53             : static int
      54           0 : malFcnMatch(MalBlkPtr mc, MalBlkPtr mb, int pc)
      55             : {
      56             :         int i, j, k, lim;
      57             :         int *cvar, *mvar;
      58             :         int ctop = 0, mtop = 0;
      59             :         InstrPtr p, q;
      60             : 
      61           0 :         if (mb->stop - pc < mc->stop - 2)
      62             :                 return 0;
      63             : 
      64           0 :         cvar = (int *) GDKmalloc(mc->vtop * mc->maxarg * sizeof(*cvar));
      65           0 :         if (cvar == NULL)
      66             :                 return 0;
      67           0 :         mvar = (int *) GDKmalloc(mb->vtop * mc->maxarg * sizeof(*mvar));
      68           0 :         if (mvar == NULL){
      69           0 :                 GDKfree(cvar);
      70           0 :                 return 0;
      71             :         }
      72             :         /* also trim the return statement */
      73           0 :         lim = pc + mc->stop - 3;
      74             :         k = 1;
      75           0 :         for (i = pc; i < lim; i++, k++) {
      76           0 :                 p = getInstrPtr(mb, i);
      77           0 :                 q = getInstrPtr(mc, k);
      78           0 :                 if (malMatch(p, q) == 0){
      79           0 :                         GDKfree(cvar);
      80           0 :                         GDKfree(mvar);
      81           0 :                         return 0;
      82             :                 }
      83           0 :                 for (j = 0; j < p->argc; j++)
      84           0 :                         cvar[ctop++] = getArg(p, j);
      85             : 
      86           0 :                 for (j = 0; j < q->argc; j++)
      87           0 :                         mvar[mtop++] = getArg(q, j);
      88             :         }
      89           0 :         assert(mtop == ctop);   /*shouldn't happen */
      90             : 
      91           0 :         for (i = 0; i < ctop; i++)
      92           0 :                 for (j = i + 1; j < ctop; j++)
      93           0 :                         if ((cvar[i] == cvar[j]) != (mvar[i] == mvar[j])) {
      94           0 :                                 GDKfree(cvar);
      95           0 :                                 GDKfree(mvar);
      96           0 :                                 return 0;
      97             :                         }
      98           0 :         GDKfree(cvar);
      99           0 :         GDKfree(mvar);
     100           0 :         return 1;
     101             : }
     102             : /*
     103             :  * Macro expansions
     104             :  * The macro expansion routine walks through the MAL code block in search
     105             :  * for the function to be expanded.
     106             :  * The macro expansion process is restarted at the first new instruction.
     107             :  * A global is used to protect at (direct) recursive expansions
     108             :  */
     109             : #define MAXEXPANSION 256
     110             : 
     111             : int
     112         387 : inlineMALblock(MalBlkPtr mb, int pc, MalBlkPtr mc)
     113             : {
     114             :         int i, k, l, n;
     115             :         InstrPtr *ns, p,q;
     116             :         int *nv;
     117             : 
     118         387 :         p = getInstrPtr(mb, pc);
     119         387 :         q = getInstrPtr(mc, 0);
     120         387 :         ns = GDKzalloc((l = (mb->ssize + mc->ssize + p->retc - 3)) * sizeof(InstrPtr));
     121         387 :         if (ns == NULL)
     122             :                 return -1;
     123         387 :         nv = (int*) GDKmalloc(mc->vtop * sizeof(int));
     124         387 :         if (nv == 0){
     125           0 :                 GDKfree(ns);
     126           0 :                 return -1;
     127             :         }
     128             : 
     129             :         /* add all variables of the new block to the target environment */
     130       20404 :         for (n = 0; n < mc->vtop; n++) {
     131       20017 :                 if (isExceptionVariable(getVarName(mc,n))) {
     132           1 :                         nv[n] = newVariable(mb, getVarName(mc,n), strlen(getVarName(mc,n)), TYPE_str);
     133       20016 :                 } else if (isVarTypedef(mc,n)) {
     134           1 :                         nv[n] = newTypeVariable(mb,getVarType(mc,n));
     135       20015 :                 } else if (isVarConstant(mc,n)) {
     136        2291 :                         nv[n] = cpyConstant(mb,getVar(mc,n));
     137             :                 } else {
     138       17724 :                         nv[n] = newTmpVariable(mb, getVarType(mc, n));
     139             :                 }
     140             :         }
     141             : 
     142             :         /* use an alias mapping to keep track of the actual arguments */
     143         860 :         for (n = p->retc; n < p->argc; n++)
     144         473 :                 nv[getArg(q,n)] = getArg(p, n);
     145             : 
     146             :         k = 0;
     147             :         /* find the return statement of the inline function */
     148       17491 :         for (i = 1; i < mc->stop - 1; i++) {
     149       17104 :                 q = mc->stmt[i];
     150       17104 :                 if( q->barrier== RETURNsymbol || q->barrier== YIELDsymbol){
     151             :                         /* add the mapping of the return variables */
     152         770 :                         for(n=0; n<p->retc; n++)
     153         385 :                                 nv[getArg(q,n)] = getArg(p,n);
     154             :                 }
     155             :         }
     156             : 
     157             :         /* copy the stable part */
     158      258071 :         for (i = 0; i < pc; i++)
     159      257684 :                 ns[k++] = mb->stmt[i];
     160             : 
     161        6281 :         for (i = 1; i < mc->stop - 1; i++) {
     162        6268 :                 q = mc->stmt[i];
     163        6268 :                 if( q->token == ENDsymbol)
     164             :                         break;
     165             : 
     166             :                 /* copy the instruction and fix variable references */
     167        5894 :                 ns[k] = copyInstruction(q);
     168        5894 :                 if( ns[k] == NULL){
     169           0 :                         GDKfree(nv);
     170           0 :                         GDKfree(ns);
     171           0 :                         return -1;
     172             :                 }
     173             : 
     174       22224 :                 for (n = 0; n < q->argc; n++)
     175       16330 :                         getArg(ns[k], n) = nv[getArg(q, n)];
     176             : 
     177        5894 :                 if (q->barrier == RETURNsymbol || q->barrier == YIELDsymbol) {
     178         770 :                         for(n=0; n<q->retc; n++)
     179         385 :                                 clrVarFixed(mb,getArg(ns[k],n)); /* for typing */
     180         385 :                         setModuleId(ns[k],getModuleId(q));
     181         385 :                         setFunctionId(ns[k],getFunctionId(q));
     182         385 :                         ns[k]->typechk = TYPE_UNKNOWN;
     183         385 :                         ns[k]->barrier = 0;
     184         385 :                         ns[k]->token = ASSIGNsymbol;
     185             :                 }
     186        5894 :                 k++;
     187             :         }
     188             : 
     189             :         /* copy the remainder of the stable part */
     190         387 :         freeInstruction(p);
     191       19333 :         for (i = pc + 1; i < mb->stop; i++){
     192       18946 :                 ns[k++] = mb->stmt[i];
     193             :         }
     194             :         /* remove any free instruction */
     195      724444 :         for(; i<mb->ssize; i++)
     196      724057 :         if( mb->stmt[i]){
     197           0 :                 freeInstruction(mb->stmt[i]);
     198           0 :                 mb->stmt[i]= 0;
     199             :         }
     200         387 :         GDKfree(mb->stmt);
     201         387 :         mb->stmt = ns;
     202             : 
     203         387 :         mb->ssize = l;
     204         387 :         mb->stop = k;
     205         387 :         GDKfree(nv);
     206         387 :         return pc;
     207             : }
     208             : 
     209             : /*
     210             :  * The macro processor should be careful in replacing the
     211             :  * instruction. In particular, any RETURN or YIELD statement
     212             :  * should be replaced by a jump. For the time being,
     213             :  * we only allow for a single return statement at the end
     214             :  * of the block.
     215             :  * The semantic test is encapsulated in a routines.
     216             :  */
     217             : 
     218             : static str
     219           4 : MACROvalidate(MalBlkPtr mb)
     220             : {
     221             :         int retseen = 0;
     222             :         int i;
     223             :         InstrPtr p = 0;
     224             : 
     225           4 :         if (getArgType(mb, getInstrPtr(mb, 0), 0) == TYPE_void)
     226             :                 return MAL_SUCCEED;
     227             : 
     228          16 :         for (i = 1; retseen == 0 && i < mb->stop; i++) {
     229          14 :                 p = getInstrPtr(mb, i);
     230          14 :                 retseen = p->token == RETURNsymbol || p->token == YIELDsymbol || p->barrier == RETURNsymbol || p->barrier == YIELDsymbol;
     231             :         }
     232           2 :         if (retseen && i != mb->stop - 1)
     233           0 :                 throw(MAL, "optimizer.MACROvalidate", SQLSTATE(HY002) MACRO_SYNTAX_ERROR);
     234             :         return MAL_SUCCEED;
     235             : }
     236             : 
     237             : static int
     238           2 : MACROprocessor(Client cntxt, MalBlkPtr mb, Symbol t)
     239             : {
     240             :         InstrPtr q;
     241             :         int i, cnt = 0, last = -1;
     242             :         str msg = MAL_SUCCEED;
     243             : 
     244             :         (void) cntxt;
     245           2 :         if (t == NULL)
     246             :                 return 0;
     247           2 :         if ((msg = MACROvalidate(t->def))) {
     248           0 :                 freeException(msg);
     249           0 :                 return 0;
     250             :         }
     251           6 :         for (i = 0; i < mb->stop; i++) {
     252           4 :                 q = getInstrPtr(mb, i);
     253           4 :                 if (getFunctionId(q) && idcmp(getFunctionId(q), t->name) == 0 &&
     254           0 :                         getSignature(t)->token == FUNCTIONsymbol) {
     255           0 :                         if (i == last) /* Duplicate macro expansion */
     256           0 :                                 return cnt;
     257             : 
     258             :                         last = i;
     259           0 :                         i = inlineMALblock(mb, i, t->def);
     260           0 :                         if( i < 0) /* Allocation failure */
     261           0 :                                 return cnt;
     262             : 
     263           0 :                         cnt++;
     264           0 :                         if (cnt > MAXEXPANSION) /* Too many macro expansions */
     265           0 :                                 return cnt;
     266             :                 }
     267             :         }
     268             :         return cnt;
     269             : }
     270             : 
     271             : /*
     272             :  * Macro inversions map a consecutive sequences of MAL instructions
     273             :  * into a single call. Subsequent resolution will bind it with the proper
     274             :  * function. The pattern being replaced should be a self-standing
     275             :  * assignment. [could be improved]
     276             :  *
     277             :  * The function being replaced should assign the result to
     278             :  * the signature variables. Otherwise it will be difficult
     279             :  * to assess which result to retain.
     280             :  */
     281             : static int
     282           0 : replaceMALblock(MalBlkPtr mb, int pc, MalBlkPtr mc)
     283             : {
     284             :         int i, j, k, lim;
     285             :         InstrPtr p, q, rq;
     286             :         int *cvar, *mvar;
     287             :         int ctop = 0, mtop = 0;
     288             : 
     289             :         /* collect variable map */
     290           0 :         cvar = (int *) GDKmalloc(mc->vtop * mc->maxarg * sizeof(*cvar));
     291           0 :         if (cvar == NULL)
     292             :                 return -1;
     293           0 :         mvar = (int *) GDKmalloc(mb->vtop * mc->maxarg * sizeof(*mvar));
     294           0 :         if (mvar == NULL){
     295           0 :                 GDKfree(cvar);
     296           0 :                 return -1;
     297             :         }
     298           0 :         lim = pc + mc->stop - 3;
     299             :         k = 1;
     300           0 :         for (i = pc; i < lim; i++, k++) {
     301           0 :                 p = getInstrPtr(mb, i);
     302           0 :                 q = getInstrPtr(mc, k);
     303           0 :                 for (j = 0; j < q->argc; j++)
     304           0 :                         cvar[ctop++] = getArg(q, j);
     305           0 :                 assert(ctop < mc->vtop *mc->maxarg);
     306             : 
     307           0 :                 for (j = 0; j < p->argc; j++)
     308           0 :                         mvar[mtop++] = getArg(p, j);
     309             :         }
     310           0 :         assert(mtop == ctop);   /*shouldn't happen */
     311             : 
     312           0 :         p = getInstrPtr(mb, pc);
     313           0 :         q = copyInstruction(getInstrPtr(mc, 0));        /* the signature */
     314           0 :         if( q == NULL){
     315           0 :                 GDKfree(cvar);
     316           0 :                 GDKfree(mvar);
     317           0 :                 return -1;
     318             :         }
     319           0 :         q->token = ASSIGNsymbol;
     320           0 :         mb->stmt[pc] = q;
     321             : 
     322           0 :         for (i = q->retc; i < q->argc; i++)
     323           0 :                 for (j = 0; j < ctop; j++)
     324           0 :                         if (q->argv[i] == cvar[j]) {
     325           0 :                                 q->argv[i] = mvar[j];
     326           0 :                                 break;
     327             :                         }
     328             :         /* take the return expression  and match the variables*/
     329           0 :         rq = getInstrPtr(mc, mc->stop - 2);
     330           0 :         for (i = 0; i < rq->retc; i++)
     331           0 :                 for (j = 0; j < ctop; j++)
     332           0 :                         if (rq->argv[i+rq->retc] == cvar[j]) {
     333           0 :                                 q->argv[i] = mvar[j];
     334           0 :                                 break;
     335             :                         }
     336           0 :         freeInstruction(p);
     337             : 
     338             :         /* strip signature, return, and end statements */
     339           0 :         k = mc->stop - 3;
     340           0 :         j = pc + k;
     341           0 :         for (i = pc + 1; i < pc + k; i++)
     342           0 :                 freeInstruction(mb->stmt[i]);
     343             : 
     344           0 :         for (i = pc + 1; i < mb->stop - k; i++)
     345           0 :                 mb->stmt[i] = mb->stmt[j++];
     346             : 
     347             :         k = i;
     348           0 :         for (; i < mb->stop; i++)
     349           0 :                 mb->stmt[i] = 0;
     350             : 
     351           0 :         mb->stop = k;
     352           0 :         GDKfree(cvar);
     353           0 :         GDKfree(mvar);
     354           0 :         return pc;
     355             : }
     356             : 
     357             : static str
     358           0 : ORCAMprocessor(Client cntxt, MalBlkPtr mb, Symbol t, int *actions)
     359             : {
     360             :         MalBlkPtr mc;
     361             :         int i;
     362             :         str msg = MAL_SUCCEED;
     363             : 
     364           0 :         if (t == NULL )
     365             :                 return msg;     /* ignore the call */
     366           0 :         mc = t->def;
     367           0 :         if ( mc->stop < 3)
     368             :                 return msg;     /* ignore small call */
     369             : 
     370             :         /* strip signature, return, and end statements */
     371           0 :         for (i = 1; i < mb->stop - mc->stop + 3; i++)
     372           0 :                 if (malFcnMatch(mc, mb, i)) {
     373           0 :                         msg = MACROvalidate(mc);
     374           0 :                         if (msg == MAL_SUCCEED){
     375           0 :                                 if( replaceMALblock(mb, i, mc) < 0)
     376           0 :                                         throw(MAL,"orcam", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     377           0 :                                 (*actions)++;
     378             :                         } else
     379             :                                 break;
     380             :                 }
     381           0 :         if (!msg)
     382           0 :                 msg = chkTypes(cntxt->usermodule, mb, FALSE);
     383           0 :         if (!msg)
     384           0 :                 msg = chkFlow(mb);
     385           0 :         if (!msg)
     386           0 :                 msg = chkDeclarations(mb);
     387             :         return msg;
     388             : }
     389             : 
     390             : static int
     391           2 : OPTmacroImplementation(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr p)
     392             : {
     393             :         MalBlkPtr target= mb;
     394             :         Module s;
     395             :         Symbol t;
     396             :         str mod,fcn;
     397             :         int j, actions = 0;
     398             : 
     399             :         (void) stk;
     400             : 
     401           2 :         if( p->argc == 3){
     402           2 :                 mod= getArgDefault(mb,p,1);
     403           2 :                 fcn= getArgDefault(mb,p,2);
     404             :         } else {
     405           0 :                 mod= getArgDefault(mb,p,1);
     406           0 :                 fcn= getArgDefault(mb,p,2);
     407           0 :                 t= findSymbol(cntxt->usermodule, putName(mod), fcn);
     408           0 :                 if( t == 0)
     409             :                         return 0;
     410           0 :                 target= t->def;
     411           0 :                 mod= getArgDefault(mb,p,3);
     412           0 :                 fcn= getArgDefault(mb,p,4);
     413             :         }
     414           2 :         s = findModule(cntxt->usermodule, putName(mod));
     415           2 :         if (s == 0)
     416             :                 return 0;
     417           2 :         if (s->space) {
     418           2 :                 j = getSymbolIndex(fcn);
     419           4 :                 for (t = s->space[j]; t != NULL; t = t->peer)
     420           2 :                         if (t->def->errors == 0) {
     421           2 :                                 if (getSignature(t)->token == FUNCTIONsymbol){
     422           2 :                                         actions += MACROprocessor(cntxt, target, t);
     423             :                                 }
     424             :                         }
     425             :         }
     426             :         return actions;
     427             : }
     428             : /*
     429             :  * The optimizer call infrastructure is identical to the liners
     430             :  * function with the exception that here we inline all possible
     431             :  * functions, regardless their
     432             :  */
     433             : 
     434             : static str
     435           0 : OPTorcamImplementation(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr p, int *actions)
     436             : {
     437             :         MalBlkPtr target= mb;
     438             :         Module s;
     439             :         Symbol t;
     440             :         str mod,fcn;
     441             :         int j;
     442             :         str msg = MAL_SUCCEED;
     443             : 
     444             :         (void) cntxt;
     445             :         (void) stk;
     446             : 
     447           0 :         if( p->argc == 3){
     448           0 :                 mod= getArgDefault(mb,p,1);
     449           0 :                 fcn= getArgDefault(mb,p,2);
     450             :         } else {
     451           0 :                 mod= getArgDefault(mb,p,1);
     452           0 :                 fcn= getArgDefault(mb,p,2);
     453           0 :                 t= findSymbol(cntxt->usermodule, putName(mod), fcn);
     454           0 :                 if( t == 0)
     455             :                         return 0;
     456           0 :                 target= t->def;
     457           0 :                 mod= getArgDefault(mb,p,3);
     458           0 :                 fcn= getArgDefault(mb,p,4);
     459             :         }
     460           0 :         s = findModule(cntxt->usermodule, putName(mod));
     461           0 :         if (s == 0)
     462             :                 return 0;
     463           0 :         if (s->space) {
     464           0 :                 j = getSymbolIndex(fcn);
     465           0 :                 for (t = s->space[j]; t != NULL; t = t->peer)
     466           0 :                         if (t->def->errors == 0) {
     467           0 :                                 if (getSignature(t)->token == FUNCTIONsymbol) {
     468           0 :                                         freeException(msg);
     469           0 :                                         msg =ORCAMprocessor(cntxt, target, t, actions);
     470             :                                 }
     471             :                         }
     472             :         }
     473             :         return msg;
     474             : }
     475             : 
     476           2 : str OPTmacro(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr p){
     477             :         Symbol t;
     478             :         str msg = MAL_SUCCEED, mod, fcn;
     479             :         int actions = 0;
     480             : 
     481           2 :         if( p ==NULL )
     482             :                 return 0;
     483           2 :         removeInstruction(mb, p);
     484           2 :         if( p->argc == 3){
     485           2 :                 mod= getArgDefault(mb,p,1);
     486           2 :                 fcn= getArgDefault(mb,p,2);
     487             :         } else {
     488           0 :                 mod= getArgDefault(mb,p,3);
     489           0 :                 fcn= getArgDefault(mb,p,4);
     490             :         }
     491           2 :         t= findSymbol(cntxt->usermodule, putName(mod), fcn);
     492           2 :         if( t == 0)
     493             :                 return 0;
     494             : 
     495           2 :         msg = MACROvalidate(t->def);
     496           2 :         if( msg)
     497             :                 return msg;
     498           2 :         if( mb->errors == 0)
     499           2 :                 actions = OPTmacroImplementation(cntxt,mb,stk,p);
     500             : 
     501             :         /* Defense line against incorrect plans */
     502           2 :         if (actions > 0){
     503           0 :                 msg = chkTypes(cntxt->usermodule, mb, FALSE);
     504           0 :                 if (!msg)
     505           0 :                         msg = chkFlow(mb);
     506           0 :                 if (!msg)
     507           0 :                         msg = chkDeclarations(mb);
     508             :         }
     509             :         /* keep actions taken as a fake argument*/
     510           2 :         (void) pushInt(mb, p, actions);
     511           2 :         return msg;
     512             : }
     513             : 
     514           0 : str OPTorcam(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr p){
     515             :         Symbol t;
     516             :         str msg = MAL_SUCCEED, mod, fcn;
     517           0 :         int actions = 0;
     518             : 
     519           0 :         if( p ==NULL )
     520             :                 return 0;
     521           0 :         removeInstruction(mb, p);
     522           0 :         if( p->argc == 3){
     523           0 :                 mod= getArgDefault(mb,p,1);
     524           0 :                 fcn= getArgDefault(mb,p,2);
     525             :         } else {
     526           0 :                 mod= getArgDefault(mb,p,3);
     527           0 :                 fcn= getArgDefault(mb,p,4);
     528             :         }
     529           0 :         t= findSymbol(cntxt->usermodule, putName(mod), fcn);
     530           0 :         if( t == 0)
     531             :                 return 0;
     532             : 
     533           0 :         msg = MACROvalidate(t->def);
     534           0 :         if( msg)
     535             :                 return msg;
     536           0 :         if( mb->errors == 0)
     537           0 :                 msg= OPTorcamImplementation(cntxt,mb,stk,p, &actions);
     538           0 :         if( msg)
     539             :                 return msg;
     540             :         /* Defense line against incorrect plans */
     541           0 :         if (actions > 0){
     542           0 :                 msg = chkTypes(cntxt->usermodule, mb, FALSE);
     543           0 :                 if (!msg)
     544           0 :                         msg = chkFlow(mb);
     545           0 :                 if (!msg)
     546           0 :                         msg = chkDeclarations(mb);
     547             :         }
     548             :         /* keep actions taken as a fake argument*/
     549           0 :         (void) pushInt(mb, p, actions);
     550           0 :         return msg;
     551             : }

Generated by: LCOV version 1.14