Line data Source code
1 : /*
2 : * SPDX-License-Identifier: MPL-2.0
3 : *
4 : * This Source Code Form is subject to the terms of the Mozilla Public
5 : * License, v. 2.0. If a copy of the MPL was not distributed with this
6 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
7 : *
8 : * Copyright 2024 MonetDB Foundation;
9 : * Copyright August 2008 - 2023 MonetDB B.V.;
10 : * Copyright 1997 - July 2008 CWI.
11 : */
12 :
13 : #include "monetdb_config.h"
14 : #include "opt_evaluate.h"
15 : #include "opt_aliases.h"
16 :
17 : static bool
18 21780477 : OPTallConstant(Client cntxt, MalBlkPtr mb, InstrPtr p)
19 : {
20 21780477 : int i;
21 21780477 : (void) cntxt;
22 :
23 21780477 : if (p->token != ASSIGNsymbol
24 21779218 : && getModuleId(p) != calcRef
25 21635884 : && getModuleId(p) != strRef
26 21635327 : && getModuleId(p) != mtimeRef
27 21634768 : && getModuleId(p) != mmathRef)
28 : return false;
29 145962 : if (getModuleId(p) == mmathRef && strcmp(getFunctionId(p), "rand") == 0)
30 : return false;
31 :
32 347553 : for (i = p->retc; i < p->argc; i++)
33 241283 : if (isVarConstant(mb, getArg(p, i)) == FALSE)
34 : return false;
35 212377 : for (i = 0; i < p->retc; i++) {
36 106182 : if (isaBatType(getArgType(mb, p, i)))
37 : return false;
38 106182 : if (p->unsafeProp || mb->unsafeProp)
39 : return false;
40 : }
41 : return true;
42 : }
43 :
44 : static bool
45 212 : OPTsimpleflow(MalBlkPtr mb, int pc)
46 : {
47 212 : int i, block = 0;
48 212 : bool simple = true;
49 212 : InstrPtr p;
50 :
51 2746 : for (i = pc; i < mb->stop; i++) {
52 2746 : p = getInstrPtr(mb, i);
53 2746 : if (blockStart(p))
54 227 : block++;
55 2746 : if (blockExit(p))
56 227 : block--;
57 2746 : if (blockCntrl(p))
58 178 : simple = false;
59 2746 : if (block == 0) {
60 212 : return simple;
61 : }
62 : }
63 : return false;
64 : }
65 :
66 : /* barrier blocks can only be dropped when they are fully excluded. */
67 : static str
68 372 : OPTremoveUnusedBlocks(Client cntxt, MalBlkPtr mb)
69 : {
70 : /* catch and remove constant bounded blocks */
71 372 : int i, j = 0, action = 0, block = -1, skip = 0, multipass = 1;
72 372 : InstrPtr p;
73 372 : str msg = MAL_SUCCEED;
74 :
75 747 : while (multipass--) {
76 : block = -1;
77 : skip = 0;
78 : j = 0;
79 30510 : for (i = 0; i < mb->stop; i++) {
80 30135 : p = mb->stmt[i];
81 30135 : if (blockExit(p) && block == getArg(p, 0)) {
82 315 : block = -1;
83 315 : skip = 0;
84 315 : freeInstruction(p);
85 315 : mb->stmt[i] = 0;
86 315 : continue;
87 : }
88 29820 : if (p->argc == 2 && blockStart(p) && block < 0
89 507 : && isVarConstant(mb, getArg(p, 1))
90 507 : && getArgType(mb, p, 1) == TYPE_bit) {
91 411 : if (getVarConstant(mb, getArg(p, 1)).val.btval == 0) {
92 186 : block = getArg(p, 0);
93 186 : skip++;
94 186 : action++;
95 : }
96 : // Try to remove the barrier statement itself (when true).
97 411 : if (getVarConstant(mb, getArg(p, 1)).val.btval == 1
98 212 : && OPTsimpleflow(mb, i)) {
99 129 : block = getArg(p, 0);
100 129 : skip = 0;
101 129 : action++;
102 129 : freeInstruction(p);
103 129 : mb->stmt[i] = 0;
104 129 : continue;
105 : }
106 29409 : } else if (p->argc == 2 && blockStart(p) && block >= 0 && skip == 0
107 7 : && isVarConstant(mb, getArg(p, 1))
108 7 : && getArgType(mb, p, 1) == TYPE_bit && multipass == 0)
109 29691 : multipass++;
110 29691 : if (skip) {
111 559 : freeInstruction(p);
112 559 : mb->stmt[i] = 0;
113 : } else
114 29132 : mb->stmt[j++] = p;
115 : }
116 375 : mb->stop = j;
117 1378 : for (; j < i; j++)
118 1003 : mb->stmt[j] = NULL;
119 : }
120 372 : if (action)
121 113 : msg = chkTypes(cntxt->usermodule, mb, TRUE);
122 372 : return msg;
123 : }
124 :
125 : str
126 499044 : OPTevaluateImplementation(Client cntxt, MalBlkPtr mb, MalStkPtr stk,
127 : InstrPtr pci)
128 : {
129 499044 : InstrPtr p;
130 499044 : int i, k, limit, *alias = 0, barrier;
131 499044 : MalStkPtr env = NULL;
132 499044 : int actions = 0, constantblock = 0;
133 499044 : int *assigned = 0, use;
134 499044 : str msg = MAL_SUCCEED;
135 :
136 499044 : (void) stk;
137 :
138 499044 : if (mb->inlineProp)
139 : return MAL_SUCCEED;
140 :
141 499044 : assigned = (int *) GDKzalloc(sizeof(int) * mb->vtop);
142 499172 : if (assigned == NULL)
143 0 : throw(MAL, "optimizer.evaluate", SQLSTATE(HY013) MAL_MALLOC_FAIL);
144 :
145 499172 : alias = (int *) GDKzalloc(mb->vsize * sizeof(int) * 2); /* we introduce more */
146 499183 : if (alias == NULL) {
147 0 : GDKfree(assigned);
148 0 : throw(MAL, "optimizer.evaluate", SQLSTATE(HY013) MAL_MALLOC_FAIL);
149 : }
150 : // arguments are implicitly assigned by context
151 499183 : p = getInstrPtr(mb, 0);
152 500056 : for (k = p->retc; k < p->argc; k++) {
153 873 : assert(getArg(p, k) >= 0);
154 873 : assigned[getArg(p, k)]++;
155 : }
156 499183 : limit = mb->stop;
157 23496145 : for (i = 1; i < limit; i++) {
158 22996962 : p = getInstrPtr(mb, i);
159 : // The double count emerging from a barrier exit is ignored.
160 22996962 : if (!blockExit(p) || (blockExit(p) && p->retc != p->argc))
161 46282322 : for (k = 0; k < p->retc; k++)
162 23286619 : if (p->retc != p->argc || p->token != ASSIGNsymbol) {
163 23286247 : assert(getArg(p, k) >= 0);
164 23286247 : assigned[getArg(p, k)]++;
165 : }
166 : }
167 :
168 23503784 : for (i = 1; i < limit && cntxt->mode != FINISHCLIENT; i++) {
169 23004619 : p = getInstrPtr(mb, i);
170 : // to avoid management of duplicate assignments over multiple blocks
171 : // we limit ourselves to evaluation of the first assignment only.
172 23004619 : assert(getArg(p, 0) >= 0);
173 23004619 : use = assigned[getArg(p, 0)] == 1 && !(p->argc == p->retc
174 12226247 : && blockExit(p));
175 54492104 : for (k = p->retc; k < p->argc; k++)
176 31487485 : if (alias[getArg(p, k)])
177 105631 : getArg(p, k) = alias[getArg(p, k)];
178 : /* be aware that you only assign once to a variable */
179 23004619 : if (use && p->retc == 1 && getFunctionId(p)
180 21779351 : && OPTallConstant(cntxt, mb, p) && !isUnsafeFunction(p)) {
181 105326 : barrier = p->barrier;
182 105326 : p->barrier = 0;
183 105326 : if (env == NULL) {
184 27797 : env = prepareMALstack(mb, 2 * mb->vsize);
185 27851 : if (!env) {
186 0 : msg = createException(MAL, "optimizer.evaluate",
187 : SQLSTATE(HY013) MAL_MALLOC_FAIL);
188 0 : p->barrier = barrier;
189 0 : goto wrapup;
190 : }
191 27851 : env->keepAlive = TRUE;
192 : }
193 105380 : msg = reenterMAL(cntxt, mb, i, i + 1, env);
194 105270 : p->barrier = barrier;
195 105270 : if (msg == MAL_SUCCEED) {
196 104775 : int nvar;
197 104775 : ValRecord cst;
198 :
199 104775 : actions++;
200 104775 : cst.vtype = 0;
201 104775 : if (VALcopy(&cst, &env->stk[getArg(p, 0)]) == NULL) {
202 0 : msg = createException(MAL, "optimizer.evaluate",
203 : SQLSTATE(HY013) MAL_MALLOC_FAIL);
204 0 : goto wrapup;
205 : }
206 : /* You may not overwrite constants. They may be used by
207 : * other instructions */
208 104854 : nvar = defConstant(mb, getArgType(mb, p, 0), &cst);
209 104880 : if (nvar >= 0)
210 104887 : getArg(p, 1) = nvar;
211 104880 : if (nvar >= env->stktop) {
212 53711 : if (VALcopy(&env->stk[getArg(p, 1)],
213 53712 : &getVarConstant(mb, getArg(p, 1))) == NULL) {
214 0 : msg = createException(MAL, "optimizer.evaluate",
215 : SQLSTATE(HY013) MAL_MALLOC_FAIL);
216 0 : goto wrapup;
217 : }
218 53711 : env->stktop = getArg(p, 1) + 1;
219 : }
220 104879 : alias[getArg(p, 0)] = getArg(p, 1);
221 104879 : p->argc = 2;
222 104879 : p->token = ASSIGNsymbol;
223 104879 : clrFunction(p);
224 104905 : p->barrier = barrier;
225 : /* freeze the type */
226 104905 : setVarFixed(mb, getArg(p, 1));
227 : } else {
228 : /* if there is an error, we should postpone message handling,
229 : as the actual error (eg. division by zero ) may not happen) */
230 495 : freeException(msg);
231 495 : msg = MAL_SUCCEED;
232 495 : mb->errors = 0;
233 : }
234 : }
235 46008406 : constantblock += blockStart(p) && OPTallConstant(cntxt, mb, p); /* default */
236 : }
237 : // produces errors in SQL when enabled
238 499165 : if (constantblock)
239 372 : msg = OPTremoveUnusedBlocks(cntxt, mb);
240 :
241 : /* Defense line against incorrect plans */
242 : /* Plan is unaffected */
243 499165 : if (!msg)
244 499152 : msg = chkTypes(cntxt->usermodule, mb, FALSE);
245 499140 : if (!msg)
246 499116 : msg = chkFlow(mb);
247 499135 : if (!msg)
248 499135 : msg = chkDeclarations(mb);
249 : /* keep all actions taken as a post block comment */
250 :
251 0 : wrapup:
252 : /* keep actions taken as a fake argument */
253 499161 : (void) pushInt(mb, pci, actions);
254 :
255 499137 : if (env) {
256 27846 : assert(env->stktop < env->stksize);
257 27846 : freeStack(env);
258 : }
259 499147 : if (assigned)
260 499147 : GDKfree(assigned);
261 499175 : if (alias)
262 499175 : GDKfree(alias);
263 499175 : return msg;
264 : }
|