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 - 2019 MonetDB B.V. |
7 | */ |
8 | |
9 | #include "monetdb_config.h" |
10 | #include "opt_multiplex.h" |
11 | #include "manifold.h" |
12 | #include "mal_interpreter.h" |
13 | |
14 | /* |
15 | * The generic solution to the multiplex operators is to translate |
16 | * them to a MAL loop. |
17 | * The call optimizer.multiplex(MOD,FCN,A1,...An) introduces the following code |
18 | * structure: |
19 | * |
20 | * resB:= bat.new(A1); |
21 | * barrier (h,t1):= iterator.new(A1); |
22 | * t2:= algebra.fetch(A2,h) |
23 | * ... |
24 | * cr:= MOD.FCN(t1,...,tn); |
25 | * bat.append(resB,cr); |
26 | * redo (h,t):= iterator.next(A1); |
27 | * end h; |
28 | * |
29 | * The algorithm consists of two phases: phase one deals with |
30 | * collecting the relevant information, phase two is the actual |
31 | * code construction. |
32 | */ |
33 | static str |
34 | OPTexpandMultiplex(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci) |
35 | { |
36 | int i = 2, iter = 0; |
37 | int hvar, tvar; |
38 | str mod, fcn; |
39 | int *alias, *resB; |
40 | InstrPtr q; |
41 | int tt; |
42 | int bat = (getModuleId(pci) == batmalRef) ; |
43 | |
44 | //if ( optimizerIsApplied(mb,"multiplex")) |
45 | //return 0; |
46 | (void) cntxt; |
47 | (void) stk; |
48 | for (i = 0; i < pci->retc; i++) { |
49 | tt = getBatType(getArgType(mb, pci, i)); |
50 | if (tt== TYPE_any) |
51 | throw(MAL, "optimizer.multiplex" , SQLSTATE(HY002) "Target tail type is missing" ); |
52 | if (isAnyExpression(getArgType(mb, pci, i))) |
53 | throw(MAL, "optimizer.multiplex" , SQLSTATE(HY002) "Target type is missing" ); |
54 | } |
55 | |
56 | mod = VALget(&getVar(mb, getArg(pci, pci->retc))->value); |
57 | mod = putName(mod); |
58 | fcn = VALget(&getVar(mb, getArg(pci, pci->retc+1))->value); |
59 | fcn = putName(fcn); |
60 | if(mod == NULL || fcn == NULL) |
61 | throw(MAL, "optimizer.multiplex" , SQLSTATE(HY001) MAL_MALLOC_FAIL); |
62 | fprintf(stderr,"#WARNING To speedup %s.%s a bulk operator implementation is needed\n#" , mod,fcn); |
63 | fprintInstruction(stderr, mb, stk, pci, LIST_MAL_ALL); |
64 | |
65 | /* search the iterator bat */ |
66 | for (i = pci->retc+2; i < pci->argc; i++) |
67 | if (isaBatType(getArgType(mb, pci, i))) { |
68 | iter = getArg(pci, i); |
69 | break; |
70 | } |
71 | if( i == pci->argc) |
72 | throw(MAL, "optimizer.multiplex" , SQLSTATE(HY002) "Iterator BAT type is missing" ); |
73 | |
74 | if( OPTdebug & OPTmultiplex) |
75 | { char *tpenme; |
76 | fprintf(stderr,"#calling the optimize multiplex script routine\n" ); |
77 | fprintFunction(stderr,mb, 0, LIST_MAL_ALL ); |
78 | tpenme = getTypeName(getVarType(mb,iter)); |
79 | fprintf(stderr,"#multiplex against operator %d %s\n" ,iter, tpenme); |
80 | GDKfree(tpenme); |
81 | fprintInstruction(stderr,mb, 0, pci,LIST_MAL_ALL); |
82 | } |
83 | |
84 | /* |
85 | * Beware, the operator constant (arg=1) is passed along as well, |
86 | * because in the end we issue a recursive function call that should |
87 | * find the actual arguments at the proper place of the callee. |
88 | */ |
89 | |
90 | alias= (int*) GDKmalloc(sizeof(int) * pci->maxarg); |
91 | resB = (int*) GDKmalloc(sizeof(int) * pci->retc); |
92 | if (alias == NULL || resB == NULL) { |
93 | GDKfree(alias); |
94 | GDKfree(resB); |
95 | throw(MAL, "optimizer.multiplex" , SQLSTATE(HY001) MAL_MALLOC_FAIL); |
96 | } |
97 | |
98 | /* resB := new(refBat) */ |
99 | for (i = 0; i < pci->retc; i++) { |
100 | q = newFcnCall(mb, batRef, newRef); |
101 | resB[i] = getArg(q, 0); |
102 | |
103 | tt = getBatType(getArgType(mb, pci, i)); |
104 | |
105 | setVarType(mb, getArg(q, 0), newBatType(tt)); |
106 | q = pushType(mb, q, tt); |
107 | } |
108 | |
109 | /* barrier (h,r) := iterator.new(refBat); */ |
110 | q = newFcnCall(mb, iteratorRef, newRef); |
111 | q->barrier = BARRIERsymbol; |
112 | hvar = newTmpVariable(mb, TYPE_any); |
113 | getArg(q,0) = hvar; |
114 | tvar = newTmpVariable(mb, TYPE_any); |
115 | q= pushReturn(mb, q, tvar); |
116 | (void) pushArgument(mb,q,iter); |
117 | |
118 | /* $1:= algebra.fetch(Ai,h) or constant */ |
119 | for (i = pci->retc+2; i < pci->argc; i++) { |
120 | if (getArg(pci, i) != iter && isaBatType(getArgType(mb, pci, i))) { |
121 | q = newFcnCall(mb, algebraRef, "fetch" ); |
122 | alias[i] = newTmpVariable(mb, getBatType(getArgType(mb, pci, i))); |
123 | getArg(q, 0) = alias[i]; |
124 | q= pushArgument(mb, q, getArg(pci, i)); |
125 | (void) pushArgument(mb, q, hvar); |
126 | } |
127 | } |
128 | |
129 | /* cr:= mod.CMD($1,...,$n); */ |
130 | q = newFcnCall(mb, mod, fcn); |
131 | for (i = 0; i < pci->retc; i++) { |
132 | int nvar = 0; |
133 | if (bat) { |
134 | tt = getBatType(getArgType(mb, pci, i)); |
135 | nvar = newTmpVariable(mb, newBatType(tt)); |
136 | } else { |
137 | nvar = newTmpVariable(mb, TYPE_any); |
138 | } |
139 | if (i) |
140 | q = pushReturn(mb, q, nvar); |
141 | else |
142 | getArg(q, 0) = nvar; |
143 | } |
144 | |
145 | for (i = pci->retc+2; i < pci->argc; i++) { |
146 | if (getArg(pci, i) == iter) { |
147 | q = pushArgument(mb, q, tvar); |
148 | } else if (isaBatType(getArgType(mb, pci, i))) { |
149 | q = pushArgument(mb, q, alias[i]); |
150 | } else { |
151 | q = pushArgument(mb, q, getArg(pci, i)); |
152 | } |
153 | } |
154 | |
155 | for (i = 0; i < pci->retc; i++) { |
156 | InstrPtr a = newFcnCall(mb, batRef, appendRef); |
157 | a = pushArgument(mb, a, resB[i]); |
158 | a = pushArgument(mb, a, getArg(q,i)); |
159 | getArg(a,0) = resB[i]; |
160 | } |
161 | |
162 | /* redo (h,r):= iterator.next(refBat); */ |
163 | q = newFcnCall(mb, iteratorRef, nextRef); |
164 | q->barrier = REDOsymbol; |
165 | getArg(q,0) = hvar; |
166 | q= pushReturn(mb, q, tvar); |
167 | (void) pushArgument(mb,q,iter); |
168 | |
169 | q = newAssignment(mb); |
170 | q->barrier = EXITsymbol; |
171 | getArg(q,0) = hvar; |
172 | (void) pushReturn(mb, q, tvar); |
173 | |
174 | for (i = 0; i < pci->retc; i++) { |
175 | q = newAssignment(mb); |
176 | getArg(q, 0) = getArg(pci, i); |
177 | (void) pushArgument(mb, q, resB[i]); |
178 | } |
179 | GDKfree(alias); |
180 | GDKfree(resB); |
181 | return MAL_SUCCEED; |
182 | } |
183 | |
184 | /* |
185 | * The multiplexSimple is called by the MAL scenario. It bypasses |
186 | * the optimizer infrastructure, to avoid excessive space allocation |
187 | * and interpretation overhead. |
188 | */ |
189 | str |
190 | OPTmultiplexSimple(Client cntxt, MalBlkPtr mb) |
191 | { |
192 | //MalBlkPtr mb= cntxt->curprg->def; |
193 | int i, doit=0; |
194 | InstrPtr p; |
195 | str msg = MAL_SUCCEED; |
196 | |
197 | if(mb) |
198 | for( i=0; i<mb->stop; i++){ |
199 | p= getInstrPtr(mb,i); |
200 | if(isMultiplex(p)) { |
201 | p->typechk = TYPE_UNKNOWN; |
202 | doit++; |
203 | } |
204 | } |
205 | if( doit) { |
206 | msg = OPTmultiplexImplementation(cntxt, mb, 0, 0); |
207 | chkTypes(cntxt->usermodule, mb,TRUE); |
208 | chkFlow(mb); |
209 | chkDeclarations(mb); |
210 | } |
211 | return msg; |
212 | } |
213 | |
214 | str |
215 | OPTmultiplexImplementation(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci) |
216 | { |
217 | InstrPtr *old = 0, p; |
218 | int i, limit, slimit, actions= 0; |
219 | str msg= MAL_SUCCEED; |
220 | char buf[256]; |
221 | lng usec = GDKusec(); |
222 | |
223 | (void) stk; |
224 | (void) pci; |
225 | |
226 | old = mb->stmt; |
227 | limit = mb->stop; |
228 | slimit = mb->ssize; |
229 | if ( newMalBlkStmt(mb, mb->ssize) < 0 ) |
230 | throw(MAL,"optimizer.mergetable" , SQLSTATE(HY001) MAL_MALLOC_FAIL); |
231 | |
232 | for (i = 0; i < limit; i++) { |
233 | p = old[i]; |
234 | if (msg == MAL_SUCCEED && isMultiplex(p)) { |
235 | if ( MANIFOLDtypecheck(cntxt,mb,p,0) != NULL){ |
236 | setFunctionId(p, manifoldRef); |
237 | p->typechk = TYPE_UNKNOWN; |
238 | pushInstruction(mb, p); |
239 | actions++; |
240 | continue; |
241 | } |
242 | msg = OPTexpandMultiplex(cntxt, mb, stk, p); |
243 | if( msg== MAL_SUCCEED){ |
244 | freeInstruction(p); |
245 | old[i]=0; |
246 | actions++; |
247 | continue; |
248 | } |
249 | |
250 | pushInstruction(mb, p); |
251 | actions++; |
252 | } else if( old[i]) |
253 | pushInstruction(mb, p); |
254 | } |
255 | for(;i<slimit; i++) |
256 | if( old[i]) |
257 | freeInstruction(old[i]); |
258 | GDKfree(old); |
259 | |
260 | /* Defense line against incorrect plans */ |
261 | if( msg == MAL_SUCCEED && actions > 0){ |
262 | chkTypes(cntxt->usermodule, mb, FALSE); |
263 | chkFlow(mb); |
264 | chkDeclarations(mb); |
265 | } |
266 | /* keep all actions taken as a post block comment */ |
267 | usec = GDKusec()- usec; |
268 | snprintf(buf,256,"%-20s actions=%2d time=" LLFMT " usec" ,"multiplex" ,actions, usec); |
269 | newComment(mb,buf); |
270 | if( actions >= 0) |
271 | addtoMalBlkHistory(mb); |
272 | |
273 | if( OPTdebug & OPTmultiplex){ |
274 | fprintf(stderr, "#MULTIPLEX optimizer exit\n" ); |
275 | fprintFunction(stderr, mb, 0, LIST_MAL_ALL); |
276 | } |
277 | return msg; |
278 | } |
279 | |