📄 opt_multiplex.mx
字号:
@' The contents of this file are subject to the MonetDB Public License@' Version 1.1 (the "License"); you may not use this file except in@' compliance with the License. You may obtain a copy of the License at@' http://monetdb.cwi.nl/Legal/MonetDBLicense-1.1.html@'@' Software distributed under the License is distributed on an "AS IS"@' basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the@' License for the specific language governing rights and limitations@' under the License.@'@' The Original Code is the MonetDB Database System.@'@' The Initial Developer of the Original Code is CWI.@' Portions created by CWI are Copyright (C) 1997-2007 CWI.@' All Rights Reserved.@' @f opt_multiplex@a M. Kersten@- Multiplex CompilationThe MonetDB operator multiplex concept has been pivotal toeasily apply any scalar function to elements in a containers.Any operator @sc{cmd} came with its multiplex variant [@sc{cmd}].Given the signature @sc{cmd(T1,..,Tn) : Tr}, it could beapplied also as@sc{[CMD](bat[:any_1,:T1],...,bat[any_1,Tn]) :bat[any_1,Tr]}.The semantics of the multiplex is to perform thenatural join on all bat-valued parameters, and to execute the CMD for each combination of matching tuples. All results are collected in a result BAT. All but one argument may be replaced by a scalar value.The generic solution to the multiplex operators is to translatethem to a MAL loop. A snippet of its behaviour:@verbatim b:= bat.new(:int,:int); bat.insert(b,1,1); c:bat[:int,:int]:= optimizer.multiplex("calc.+",b,1);@end verbatimThe current implementation requires the target type to be mentionedexplicitly. The result of the optimizer is:@verbatim b := bat.new(:int,:int); bat.insert(b,1,1); _8 := bat.new(:int,:int);barrier (_11,_12,_13):= bat.newIterator(b); _15 := calc.+(_13,1); bat.insert(_8,_12,_15); redo (_11,_12,_13):= bat.hasMoreElements(b);catch MALException; #ignore any error redo (_11,_12,_13):= bat.hasMoreElements(b);exit MALException;exit (_11,_12,_13); c := _8;@end verbatim@-[WARNING] the semantics does not align precisely with M4.For, in search for efficientoperators we assume aligned BATs and the script version doesnot deal with duplicates in the head of the bats.[/WARNING]@{@malpattern optimizer.multiplex(CMD:str, a:any...):anyaddress OPTmultiplexcomment "Compiler for multiplexed instructions.";@h#ifndef _OPT_MULTIPLEX_H_#define _OPT_MULTIPLEX_H_#include "mal.h"#include "mal_builder.h"#include "opt_prelude.h"#include "opt_support.h"#endif /* _OPT_MULTIPLEX_H_ */@+ Code generationThe MAL block is replaced by a new one, with the multiplexcode in place.The subsequent call to the typechecker ensures we end up witha valid program.@c#include "mal_config.h"#include "opt_multiplex.h"#include "mal_interpreter.h"@-The generic solution to the multiplex operators is to translatethem to a MAL loop. The call optimizer.multiplex(CMD,A1,...An) introduces the following codestructure:@verbatim resB:= bat.new(A1);barrier (mloop,h,t):= bat.newIterator(A1); $1:= algebra.find(A1,h); $2:= A2; # in case of constant? ... cr:= mod.CMD($1,...,$n); bat.insert(resB,h,cr); redo (mloop,h,t):= bat.hasMoreElements(A1);end mloop;@end verbatimThe algorithm consists of two phases: phase one deals withcollecting the relevant information, phase two is the actualcode construction.@cstatic strOPTexpandMultiplex(MalBlkPtr mb, MalStkPtr stk, InstrPtr pci){ int i = 2, k, mloop, resB, iter = 0, cr; int hvar, tvar; str mod, fcn; str msg = MAL_SUCCEED; int alias[MAXARG]; InstrPtr q; int ht, tt; (void) stk; mod = VALget(&getVar(mb, getArg(pci, 1))->value); mod = putName(mod,strlen(mod)); fcn = VALget(&getVar(mb, getArg(pci, 2))->value); fcn = putName(fcn,strlen(fcn)); /* search the iterator bat */ iter = getArg(pci, 3); for (i = 3; i < pci->argc; i++) if (isaBatType(getArgType(mb, pci, i))) { iter = getArg(pci, i); break; }#ifdef DEBUG_OPT_MULTIPLEX printf("calling the optimize multiplex script routine\n"); printFunction(GDKout,mb,LIST_MAL_ALL); printf("multiplex against operator %d %s\n",iter, getTypeName(getVarType(mb,iter))); printInstruction(GDKout,mb,pci,LIST_MAL_ALL);#endif@-Beware, the operator constant (arg=1) is passed along as well,because in the end we issue a recursive function call that shouldfind the actual arguments at the proper place of the callee.@c /* resB := new(refBat) */ q = newFcnCall(mb, batRef, newRef); resB = getArg(q, 0); if (isAnyExpression(getArgType(mb, pci, 0))) msg = createException(MAL, "optimizer.multiplex", "Target type is missing"); ht = getHeadType(getArgType(mb, pci, 0)); tt = getTailType(getArgType(mb, pci, 0)); setVarType(mb, getArg(q, 0), newBatType(ht, tt)); q = pushNil(mb, q, ht); freezeVarType(mb,getArg(q,q->argc-1)); q = pushNil(mb, q, tt); freezeVarType(mb,getArg(q,q->argc-1)); /* barrier (mloop,h,r) := newIterator(refBat); */ q = newFcnCall(mb, batRef, "newIterator"); q->barrier = BARRIERsymbol; getArg(q, 0) = mloop = newTmpVariable(mb, TYPE_lng); hvar = newTmpVariable(mb, TYPE_any); pushReturn(mb, q, hvar); tvar = newTmpVariable(mb, TYPE_any); pushReturn(mb, q, tvar); pushArgument(mb, q, iter); /* $1:= bat.find(Ai,h) or constant */ alias[i] = tvar; for (i++; i < pci->argc; i++) if (isaBatType(getArgType(mb, pci, i))) { q = newFcnCall(mb, algebraRef, "find"); alias[i] = newTmpVariable(mb, getTailType(getArgType(mb, pci, i))); getArg(q, 0) = alias[i]; pushArgument(mb, q, getArg(pci, i)); pushArgument(mb, q, hvar); } /* cr:= mod.CMD($1,...,$n); */ q = newFcnCall(mb, mod, fcn); cr = getArg(q, 0) = newTmpVariable(mb, TYPE_any); for (i = 3; i < pci->argc; i++) if (isaBatType(getArgType(mb, pci, i))) { pushArgument(mb, q, alias[i]); } else { q = pushArgument(mb, q, getArg(pci, i)); } /* insert(resB,h,cr); not append(resB, cr); the head type (oid) may dynamically change */ q = newFcnCall(mb, batRef, insertRef); pushArgument(mb, q, resB); pushArgument(mb, q, hvar); pushArgument(mb, q, cr);/* redo (mloop,h,r):= hasMoreElements(refBat); */ q = newFcnCall(mb, batRef, "hasMoreElements"); q->barrier = REDOsymbol; getArg(q, 0) = mloop; pushReturn(mb, q, hvar); pushReturn(mb, q, tvar); pushArgument(mb, q, iter);/* catch MALException and ignore them and replace value with nil*/ q = newInstruction(mb,CATCHsymbol); k = newVariable(mb, GDKstrdup(exceptionToString(MAL)), TYPE_str); getVar(mb,k)->isudftype = 1; pushReturn(mb, q, k); pushInstruction(mb, q);/* redo (mloop,h,r):= hasMoreElements(refBat); *//* ignore the error and continue */ q = newFcnCall(mb, batRef, "hasMoreElements"); q->barrier = REDOsymbol; getArg(q, 0) = mloop; pushReturn(mb, q, hvar); pushReturn(mb, q, tvar); pushArgument(mb, q, iter);/* finalized the catch block */ q= newInstruction(mb,EXITsymbol); pushReturn(mb,q,k); pushInstruction(mb,q); q = newAssignment(mb); q->barrier = EXITsymbol; getArg(q, 0) = mloop; pushReturn(mb, q, hvar); pushReturn(mb, q, tvar); q = newAssignment(mb); getArg(q, 0) = getArg(pci, 0); pushArgument(mb, q, resB); return msg;}@-This optimizer is directly called for the current routine.It is more a code generator then an optimizer per se.@hopt_export str OPTmultiplex(MalBlkPtr mb, MalStkPtr stk, InstrPtr pci);@cstrOPTmultiplex(MalBlkPtr mb, MalStkPtr stk, InstrPtr pci){ InstrPtr *old, p; int i,j, limit,doit= 0, init=0; lng clk=GDKusec(); (void) stk; (void) pci; old = mb->stmt; limit = mb->stop; for (i = 0; i < limit; i++) { p = old[i]; if (getModuleId(p) == optimizerRef && getFunctionId(p) == multiplexRef) { if(init==0){ newMalBlkStmt(mb, mb->stop); for(j= 0; j<i; j++) pushInstruction(mb,old[j]); init++; } OPTexpandMultiplex(mb, stk, p); /* freeInstruction(p);*/ doit++; } else if( init ) pushInstruction(mb, p); } if( init){ GDKfree(old); optimizerCheck(mb, "optimizer.multiplex", doit, GDKusec() - clk,OPT_CHECK_ALL); } return MAL_SUCCEED;}@}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -