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 20561764 : OPTallConstant(Client cntxt, MalBlkPtr mb, InstrPtr p)
19 : {
20 20561764 : int i;
21 20561764 : (void) cntxt;
22 :
23 20561764 : if (p->token != ASSIGNsymbol
24 20560705 : && getModuleId(p) != calcRef
25 20464122 : && getModuleId(p) != strRef
26 20463724 : && getModuleId(p) != mtimeRef
27 20463210 : && getModuleId(p) != mmathRef)
28 : return false;
29 98783 : if (getModuleId(p) == mmathRef && strcmp(getFunctionId(p), "rand") == 0)
30 : return false;
31 :
32 210133 : for (i = p->retc; i < p->argc; i++)
33 149145 : if (isVarConstant(mb, getArg(p, i)) == FALSE)
34 : return false;
35 121816 : for (i = 0; i < p->retc; i++) {
36 60903 : if (isaBatType(getArgType(mb, p, i)))
37 : return false;
38 60903 : if (p->unsafeProp || mb->unsafeProp)
39 : return false;
40 : }
41 : return true;
42 : }
43 :
44 : static bool
45 136 : OPTsimpleflow(MalBlkPtr mb, int pc)
46 : {
47 136 : int i, block = 0;
48 136 : bool simple = true;
49 136 : InstrPtr p;
50 :
51 610 : for (i = pc; i < mb->stop; i++) {
52 610 : p = getInstrPtr(mb, i);
53 610 : if (blockStart(p))
54 147 : block++;
55 610 : if (blockExit(p))
56 147 : block--;
57 610 : if (blockCntrl(p))
58 26 : simple = false;
59 610 : if (block == 0) {
60 136 : 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 299 : OPTremoveUnusedBlocks(Client cntxt, MalBlkPtr mb)
69 : {
70 : /* catch and remove constant bounded blocks */
71 299 : int i, j = 0, action = 0, block = -1, skip = 0, multipass = 1;
72 299 : InstrPtr p;
73 299 : str msg = MAL_SUCCEED;
74 :
75 601 : while (multipass--) {
76 : block = -1;
77 : skip = 0;
78 : j = 0;
79 24752 : for (i = 0; i < mb->stop; i++) {
80 24450 : p = mb->stmt[i];
81 24450 : if (blockExit(p) && block == getArg(p, 0)) {
82 305 : block = -1;
83 305 : skip = 0;
84 305 : freeInstruction(p);
85 305 : mb->stmt[i] = 0;
86 305 : continue;
87 : }
88 24145 : if (p->argc == 2 && blockStart(p) && block < 0
89 425 : && isVarConstant(mb, getArg(p, 1))
90 425 : && getArgType(mb, p, 1) == TYPE_bit) {
91 329 : if (getVarConstant(mb, getArg(p, 1)).val.btval == 0) {
92 182 : block = getArg(p, 0);
93 182 : skip++;
94 182 : action++;
95 : }
96 : // Try to remove the barrier statement itself (when true).
97 329 : if (getVarConstant(mb, getArg(p, 1)).val.btval == 1
98 136 : && OPTsimpleflow(mb, i)) {
99 123 : block = getArg(p, 0);
100 123 : skip = 0;
101 123 : action++;
102 123 : freeInstruction(p);
103 123 : mb->stmt[i] = 0;
104 123 : continue;
105 : }
106 23816 : } 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 24022 : multipass++;
110 24022 : if (skip) {
111 539 : freeInstruction(p);
112 539 : mb->stmt[i] = 0;
113 : } else
114 23483 : mb->stmt[j++] = p;
115 : }
116 302 : mb->stop = j;
117 1269 : for (; j < i; j++)
118 967 : mb->stmt[j] = NULL;
119 : }
120 299 : if (action)
121 108 : msg = chkTypes(cntxt->usermodule, mb, TRUE);
122 299 : return msg;
123 : }
124 :
125 : str
126 477354 : OPTevaluateImplementation(Client cntxt, MalBlkPtr mb, MalStkPtr stk,
127 : InstrPtr pci)
128 : {
129 477354 : InstrPtr p;
130 477354 : int i, k, limit, *alias = 0, barrier;
131 477354 : MalStkPtr env = NULL;
132 477354 : int actions = 0, constantblock = 0;
133 477354 : int *assigned = 0, use;
134 477354 : str msg = MAL_SUCCEED;
135 :
136 477354 : (void) stk;
137 :
138 477354 : if (mb->inlineProp)
139 : return MAL_SUCCEED;
140 :
141 477354 : assigned = (int *) GDKzalloc(sizeof(int) * mb->vtop);
142 477468 : if (assigned == NULL)
143 0 : throw(MAL, "optimizer.evaluate", SQLSTATE(HY013) MAL_MALLOC_FAIL);
144 :
145 477468 : alias = (int *) GDKzalloc(mb->vsize * sizeof(int) * 2); /* we introduce more */
146 477466 : 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 477466 : p = getInstrPtr(mb, 0);
152 478291 : for (k = p->retc; k < p->argc; k++) {
153 825 : assert(getArg(p, k) >= 0);
154 825 : assigned[getArg(p, k)]++;
155 : }
156 477466 : limit = mb->stop;
157 22178980 : for (i = 1; i < limit; i++) {
158 21701514 : p = getInstrPtr(mb, i);
159 : // The double count emerging from a barrier exit is ignored.
160 21701514 : if (!blockExit(p) || (blockExit(p) && p->retc != p->argc))
161 43649445 : for (k = 0; k < p->retc; k++)
162 21948987 : if (p->retc != p->argc || p->token != ASSIGNsymbol) {
163 21948625 : assert(getArg(p, k) >= 0);
164 21948625 : assigned[getArg(p, k)]++;
165 : }
166 : }
167 :
168 22182230 : for (i = 1; i < limit && cntxt->mode != FINISHCLIENT; i++) {
169 21704786 : 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 21704786 : assert(getArg(p, 0) >= 0);
173 21704786 : use = assigned[getArg(p, 0)] == 1 && !(p->argc == p->retc
174 11660535 : && blockExit(p));
175 50887676 : for (k = p->retc; k < p->argc; k++)
176 29182890 : if (alias[getArg(p, k)])
177 60597 : getArg(p, k) = alias[getArg(p, k)];
178 : /* be aware that you only assign once to a variable */
179 21704786 : if (use && p->retc == 1 && getFunctionId(p)
180 20560813 : && OPTallConstant(cntxt, mb, p) && !isUnsafeFunction(p)) {
181 60174 : barrier = p->barrier;
182 60174 : p->barrier = 0;
183 60174 : if (env == NULL) {
184 26844 : env = prepareMALstack(mb, 2 * mb->vsize);
185 26881 : 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 26881 : env->keepAlive = TRUE;
192 : }
193 60211 : msg = reenterMAL(cntxt, mb, i, i + 1, env);
194 60147 : p->barrier = barrier;
195 60147 : if (msg == MAL_SUCCEED) {
196 59683 : int nvar;
197 59683 : ValRecord cst;
198 :
199 59683 : actions++;
200 59683 : cst.vtype = 0;
201 59683 : 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 59712 : nvar = defConstant(mb, getArgType(mb, p, 0), &cst);
209 59694 : if (nvar >= 0)
210 59697 : getArg(p, 1) = nvar;
211 59694 : if (nvar >= env->stktop) {
212 51713 : if (VALcopy(&env->stk[getArg(p, 1)],
213 51705 : &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 51713 : env->stktop = getArg(p, 1) + 1;
219 : }
220 59702 : alias[getArg(p, 0)] = getArg(p, 1);
221 59702 : p->argc = 2;
222 59702 : p->token = ASSIGNsymbol;
223 59702 : clrFunction(p);
224 59736 : p->barrier = barrier;
225 : /* freeze the type */
226 59736 : 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 464 : freeException(msg);
231 464 : msg = MAL_SUCCEED;
232 464 : mb->errors = 0;
233 : }
234 : }
235 43408826 : constantblock += blockStart(p) && OPTallConstant(cntxt, mb, p); /* default */
236 : }
237 : // produces errors in SQL when enabled
238 477444 : if (constantblock)
239 299 : msg = OPTremoveUnusedBlocks(cntxt, mb);
240 :
241 : /* Defense line against incorrect plans */
242 : /* Plan is unaffected */
243 477444 : if (!msg)
244 477435 : msg = chkTypes(cntxt->usermodule, mb, FALSE);
245 477445 : if (!msg)
246 477417 : msg = chkFlow(mb);
247 477438 : if (!msg)
248 477438 : 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 477434 : (void) pushInt(mb, pci, actions);
254 :
255 477419 : if (env) {
256 26863 : assert(env->stktop < env->stksize);
257 26863 : freeStack(env);
258 : }
259 477447 : if (assigned)
260 477447 : GDKfree(assigned);
261 477465 : if (alias)
262 477465 : GDKfree(alias);
263 477465 : return msg;
264 : }
|