📄 mal_function.mx
字号:
head = getHeadType(x); tail = getTailType(x); hx = getHeadIndex(x); tx = getTailIndex(x); if(v && hx == v && head == TYPE_any){ hx =0; head =t; } if(v && tx == v && tail == TYPE_any){ tx= 0; tail = t; } y= newBatType(head,tail); setAnyHeadIndex(y,hx); setAnyTailIndex(y,tx); setArgType(mb,p,i,y);#ifdef DEBUG_MAL_FCN stream_printf(GDKout," %d replaced %s->%s \n",i,getTypeName(x),getTypeName(y));#endif } else if(v>0 && getTailIndex(x) == v){#ifdef DEBUG_MAL_FCN stream_printf(GDKout," replace x= %s polymorphic\n",getTypeName(x));#endif setArgType(mb,p,i,t); } #ifdef DEBUG_MAL_FCN else stream_printf(GDKout," non x= %s %d\n",getTypeName(x),getTailIndex(x));#endif }#ifdef DEBUG_MAL_FCN printInstruction(GDKout,mb,p,LIST_MAL_ALL);#endif }}@-Upon cloning a function we should remove all the polymorphic flags.Otherwise we may end up with a recursive clone.@cSymbol cloneFunction(Module scope, Symbol proc, MalBlkPtr mb, InstrPtr p){ Symbol new; int i,v; InstrPtr pp;#ifdef DEBUG_CLONE stream_printf(GDKout,"clone the function %s to scope %s\n", proc->name,scope->name); printInstruction(GDKout,mb, p,LIST_MAL_ALL);#endif new= newFunction(putName(proc->name,strlen(proc->name)), getSignature(proc)->token ); new->def = copyMalBlk(proc->def); /* now change the definition of the original proc *//*printf("CLONED VERSION\n");printFunction(GDKout, new->def, LIST_MAL_ALL);*/ /* check for errors after fixation , TODO*/ pp = getSignature(new); for(i=0;i<pp->argc;i++) if( isPolymorphic(v= getArgType(new->def,pp,i)) ){ int t = getArgType(mb,p,i); if( isaBatType(t) ){ if( getHeadIndex(v) ) replaceTypeVar(new->def, pp, getHeadIndex(v), getHeadType(t)); if( getTailIndex(v) ) replaceTypeVar(new->def, pp, getTailIndex(v), getTailType(t)); } else replaceTypeVar(new->def, pp, getTailIndex(v), t); } #ifdef DEBUG_MAL_FCN else stream_printf(GDKout,"%d remains %s\n",i, getTypeName(v));#endif /* include the function at the proper place in the scope */ insertSymbol(scope,new); /* clear polymorphic and type to force analysis*/ for(i=0;i<new->def->stop;i++) { pp= getInstrPtr(new->def,i); pp->typechk= TYPE_UNKNOWN; pp->polymorphic= 0; } /* clear type fixations */ for(i=0;i< new->def->vtop; i++) new->def->var[i]->fixtype=0;#ifdef DEBUG_MAL_FCN printf("FUNCTION TO BE CHECKED\n"); printFunction(GDKout, new->def, LIST_MAL_ALL);#endif /* check for errors after fixation , TODO*/ /* beware, we should now ignore any cloning */ if(proc->def->errors == 0) { chkProgram(scope,new->def); if( new->def->errors){ showScriptException(new->def,0,MAL,"Error in cloned function");#ifdef DEBUG_MAL_FCN printFunction(GDKout,new->def, LIST_MAL_ALL);#endif } }#ifdef DEBUG_CLONE stream_printf(GDKout,"newly cloned function added to %s %d \n",scope->name,i); printFunction(GDKout,new->def, LIST_MAL_ALL);#endif return new;}@-For commands we do not have to clone the routine. We merely have toassure that the type-constraints are obeyed. The resulting typeis returned.@cvoid printFunction(stream *fd, MalBlkPtr mb, int flg){ int i; for(i=0;i<mb->stop;i++) printInstruction(fd,mb, getInstrPtr(mb,i),flg);}@- Lifespan analysisOptimizers may be interested in the characteristic of thebarrier blocks for making a decision.The variables have a lifespan in the code blocks, denoted by propertiesbeginLifespan,endLifespan. The beginLifespan denotes the intruction whereit receives its first value, the endLifespan the last instruction in which it was used as operand or target.If, however, the last use lies within a BARRIER block, we can not be sureabout its end of life status, because a block redo may implictlyrevive it. For these situations we associate the endLifespan withthe block exit.In many cases, we have to determine if the lifespan interferes with a optimization decision being prepared.The lifespan is calculated once at the beginning of the optimizer sequence.It should either be maintained to reflect the most accurate situation whileoptimizing the code base. In particular it means that any move/remove/additionof an instruction calls for either a recalculation or delta propagation.Unclear what will be the best strategy. For the time being we just recalc.Also take care of the nested block structure. Because the span shouldfall within a single block. This is handled by the chkflow already.@cvoiddebugLifespan(MalBlkPtr mb){ int i; for (i = 0; i < mb->vtop; i++) { VarPtr v = getVar(mb, i); if (isTmpVar(mb, i)) printf("%c%d ", TMPMARKER, v->tmpindex); else printf("%8s ", v->name); printf("%d - %d update %d scope= %d,%d\n", v->beginLifespan, v->endLifespan, v->lastUpdate, v->scope, v->depth); }}voidsetLifespan(MalBlkPtr mb){ int pc, j, k; InstrPtr p; for (k = 0; k < mb->vtop; k++) { VarPtr v = getVar(mb, k); v->lastUpdate = v->beginLifespan = v->endLifespan = 0; v->isused= 0; } for (pc = 0; pc < mb->stop; pc++) { p = getInstrPtr(mb, pc); for (k = 0; k < p->argc; k++) { VarPtr v = getVar(mb, p->argv[k]); if (v->beginLifespan == 0) v->beginLifespan = pc; if (k < p->retc && p->retc<p->argc) v->lastUpdate= pc; if (pc > v->endLifespan) { /* end only if the beginLifspan falls in the same blk */ /* otherwise it is the corresponding exit. */ v->endLifespan = pc; } }@-For all variables we keep track if it is used, cq modified.This simplifies subsequent optimization.@c if( p->token != NOOPsymbol) for(j= p->retc; j<p->argc; j++) setVarUsed(mb,getArg(p,j),!isTypeVar(mb,getArg(p,j)) ); if( blockCntrl(p) || blockStart(p) ) setVarUsed(mb,getDestVar(p),TRUE); } /* debugLifespan(mb); */}@cintisLoopBarrier(MalBlkPtr mb, int pc){ InstrPtr p; int varid; p= getInstrPtr(mb,pc); if( p->barrier != BARRIERsymbol) return 0; varid= getDestVar(p); for(pc++; pc< mb->stop; pc++){ p= getInstrPtr(mb,pc); if( p->barrier == REDOsymbol && getDestVar(p)== varid) return 1; if( p->barrier == EXITsymbol && getDestVar(p)== varid) break; } return 0;}@-Searching the beginning or end of an instruction block.@cintgetBlockBegin(MalBlkPtr mb,int pc){ InstrPtr p; int varid=0,i; for(i= pc; i< mb->stop; i++){ p= getInstrPtr(mb,i); if( p->barrier == EXITsymbol ){ varid= getDestVar(p); break; } } if( i==mb->stop) return 0; for(; pc> 0; pc--){ p= getInstrPtr(mb,pc); if( (p->barrier == BARRIERsymbol || p->barrier == CATCHsymbol) && getDestVar(p)== varid) return pc; } return 0;}intgetBlockExit(MalBlkPtr mb,int pc){ InstrPtr p; int varid; p= getInstrPtr(mb,pc); if( p->barrier != BARRIERsymbol && p->barrier != CATCHsymbol) return 0; varid= getDestVar(p); for(pc++; pc< mb->stop; pc++){ p= getInstrPtr(mb,pc); if( p->barrier == EXITsymbol && getDestVar(p)== varid) return pc; } return 0;}@- Variable declarationVariables are implicitly declared upon first use.This feature may become a source of runtime errors andcomplicates the analyse during optimization.Therefore, in line with the flow of control check,we make sure that all variables are properly initializedbefore being used. Since barrier blocks may be skipped atruntime, they actually introduce a separate scope.Variables declared within a block may not be used outside it.In many situation chkFlow and chkDeclarations should be calledtogether. Moreover, an erroneous chkFlow most likely implieserrors in the declarations as well.Since in interactive mode each statement is handled separately,we have to remember the scope assigned to a variable.@cvoid chkDeclarations(MalBlkPtr mb,int reset){ int pc,i, k,l; InstrPtr p; short s, blks[MAXDEPTH], top= 0, blkId=1; blks[top] = 1; blks[++top]= 0; if( reset) for(i=0; i<mb->vtop; i++){ getVarDepth(mb,i)=0; getVarScope(mb,i)=0; if( mb->var[i]->name == 0 && !isTmpVar(mb,i)){ showScriptException(mb,0,TYPE,"Name missing in variable %d",i); mb->errors++; } } /* all signature variables are declared at outer level */ p= getInstrPtr(mb,0); for(k=p->retc;k<p->argc; k++){ getVarScope(mb,p->argv[k])= 1; getVarDepth(mb,p->argv[k])= 0; } /* and the function name as well */ if( getFunctionId(p) == NULL){ showScriptException(mb,0, TYPE, "Function name missing in signature"); return; } /* printFunction(GDKout,mb, LIST_MAL_ALL);*/ for(pc=1;pc<mb->stop; pc++){ p= getInstrPtr(mb,pc); for(k=p->retc;k<p->argc; k++) { l=getArg(p,k); if( isConstant(mb, l) || isTypeVar(mb,l) ){ /* ok defined */ } else if( (s = getVarScope(mb,l) ) ==0 ) { showScriptException(mb,pc,TYPE, "'%s' may not be used before being initialized", getVarName(mb,l)); mb->errors++; } else if( getVarDepth(mb,l) >= top){ showScriptException(mb,pc,TYPE, "'%s' may not be used before being set in %s[%d]", getVarName(mb,l)); mb->errors++; } assert( isTmpVar(mb,l) < mb->vtop); } for(k=0; k<p->retc; k++){ l= getArg(p,k); assert( isTmpVar(mb,l) < mb->vtop); if( getVarScope(mb, l) == 0){ if( (p->barrier== RETURNsymbol || p->barrier== YIELDsymbol) && getVarType(mb,l) != TYPE_void && p->retc==p->argc){ showScriptException(mb,pc,TYPE, "'%s' returns before being initialized", getVarName(mb,l)); mb->errors++; } getVarScope(mb, l) = blks[top-1]; getVarDepth(mb, l) = top-1; } else { /* is the block still active ? */ s = getVarScope(mb,l); for( i=0; i< top; i++) if( blks[i] == s ) break; if( i< top && blks[i]!= s && !isTmpVar(mb, l)){ showScriptException(mb,pc,TYPE, "'%s' used outside declaration", getVarName(mb,l)); mb->errors++; } } } if( p->barrier){ if( blockStart(p)){ blkId++; if( top <MAXDEPTH-2){ blks[top]= blkId; blks[++top]= 0; } else { showScriptException(mb,pc,SYNTAX, "too deeply nested MAL program"); mb->errors++; return; } } if( blockExit(p) && top > 0) { top--; blks[top]= 0; } } }}@-Data flow analysis.Flow graph display is handy for debugging and analysis.A better flow analysis is needed, which takes into accountloops and side-effect functions.@cstatic voidshowOutFlow(MalBlkPtr mb, int pc, int varid, stream *f){ InstrPtr p; int i, k,found; for (i = pc + 1; i < mb->stop - 1; i++) { p = getInstrPtr(mb, i); found=0; for (k = p->retc; k < p->argc; k++) { if (p->argv[k] == varid ) { stream_printf(f, "n%d -> n%d\n", pc, i); found++; } } /* stop as soon you find a re-assignment */ for (k = 0; k < p->retc; k++) { if (getArg(p,k) == varid) i = mb->stop; } /* or a side-effect usage */ if( found && (p->retc== 0 || getArgType(mb,p,0)== TYPE_void) ) i = mb->stop; }}static voidshowInFlow(MalBlkPtr mb, int pc, int varid, stream *f){ InstrPtr p; int i, k; /* find last use, needed for operations with side effects */ for (i = pc -1; i >= 0; i-- ){ p = getInstrPtr(mb, i); for (k = 0; k < p->argc; k++) if (p->argv[k] == varid ){ stream_printf(f, "n%d -> n%d\n",i, pc); return; } }}@-At a later stage we could extend the flow details with the statusof crucial properties, e.g. processing time, cost, size@cstatic voidshowFlowDetails(MalBlkPtr mb, MalStkPtr stk, InstrPtr p, int pc, stream *f){ str s, msg; PropertySet ps; int i; (void) stk; /* fool the compiler */ msg = instruction2str(mb, p, 0); stream_printf(f, "n%d [fontsize=8, shape=box, label=\"", pc); for (s = msg+1; *s; s++) if (*s == '"') stream_printf(f, "\\\""); else stream_printf(f, "%c", *s); for(i=0;i<p->retc; i++){ stream_printf(f, "\\n%s",getArgName(mb,p,i)); stream_printf(f,":%s", s=getTypeName(getVarType(mb,getArg(p,i)))); GDKfree(s); ps = getProps(mb,getArg(p,i)); if( ps == 0) continue; s= propertySet2str(ps); for (; s && *s; s++) if (*s == '"') stream_printf(f, "\\\""); else stream_printf(f, "%c", *s); } /* later: add BAT runtime properties */ stream_printf(f, "\"];\n"); GDKfree(msg);}voidshowFlowGraph(MalBlkPtr mb, MalStkPtr stk, str fname){ stream *f; InstrPtr p; int i, k; (void) stk; /* fool the compiler */ if (idcmp(fname, "stdout") == 0) f = GDKout; else f = open_wastream(fname); setLifespan(mb); p = getInstrPtr(mb, 0); stream_printf(f, "digraph %s{\n", getFunctionId(p)); p = getInstrPtr(mb, 0); showFlowDetails(mb, stk, p, 0, f); for (k = p->retc; k < p->argc; k++) { showOutFlow(mb, 0, p->argv[k], f); } for (i = 1; i < mb->stop ; i++) { p = getInstrPtr(mb, i); showFlowDetails(mb, stk, p, i, f); for (k = 0; k < p->retc; k++) showOutFlow(mb, i, p->argv[k], f); if( p->retc== 0 || getArgType(mb,p,0)== TYPE_void) /* assume side effects */ for (k = p->retc; k < p->argc; k++) if (getArgType(mb,p,k) != TYPE_void && !isConstant(mb,getArg(p,k))) showOutFlow(mb, i, p->argv[k], f); if( getFunctionId(p)== 0) for (k =0; k< p->retc; k++) if( getArgType(mb,p,k) != TYPE_void) showInFlow(mb, i, p->argv[k], f); } stream_printf(f, "}\n"); if (f != GDKout) stream_close(f);}@}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -