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 20433167 : OPTallConstant(Client cntxt, MalBlkPtr mb, InstrPtr p)
19 : {
20 20433167 : int i;
21 20433167 : (void) cntxt;
22 :
23 20433167 : if (p->token != ASSIGNsymbol
24 20432050 : && getModuleId(p) != calcRef
25 20290429 : && getModuleId(p) != strRef
26 20289976 : && getModuleId(p) != mtimeRef
27 20289488 : && getModuleId(p) != mmathRef)
28 : return false;
29 143920 : if (getModuleId(p) == mmathRef && strcmp(getFunctionId(p), "rand") == 0)
30 : return false;
31 :
32 342029 : for (i = p->retc; i < p->argc; i++)
33 236517 : if (isVarConstant(mb, getArg(p, i)) == FALSE)
34 : return false;
35 210979 : for (i = 0; i < p->retc; i++) {
36 105512 : if (isaBatType(getArgType(mb, p, i)))
37 : return false;
38 105512 : if (mb->unsafeProp)
39 : return false;
40 : }
41 : return true;
42 : }
43 :
44 : static bool
45 141 : OPTsimpleflow(MalBlkPtr mb, int pc)
46 : {
47 141 : int i, block = 0;
48 141 : bool simple = true;
49 141 : InstrPtr p;
50 :
51 633 : for (i = pc; i < mb->stop; i++) {
52 633 : p = getInstrPtr(mb, i);
53 633 : if (blockStart(p))
54 152 : block++;
55 633 : if (blockExit(p))
56 152 : block--;
57 633 : if (blockCntrl(p))
58 26 : simple = false;
59 633 : if (block == 0) {
60 141 : 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 307 : OPTremoveUnusedBlocks(Client cntxt, MalBlkPtr mb)
69 : {
70 : /* catch and remove constant bounded blocks */
71 307 : int i, j = 0, action = 0, block = -1, skip = 0, multipass = 1;
72 307 : InstrPtr p;
73 307 : str msg = MAL_SUCCEED;
74 :
75 617 : while (multipass--) {
76 : block = -1;
77 : skip = 0;
78 : j = 0;
79 25265 : for (i = 0; i < mb->stop; i++) {
80 24955 : p = mb->stmt[i];
81 24955 : if (blockExit(p) && block == getArg(p, 0)) {
82 313 : block = -1;
83 313 : skip = 0;
84 313 : freeInstruction(p);
85 313 : mb->stmt[i] = 0;
86 313 : continue;
87 : }
88 24642 : if (p->argc == 2 && blockStart(p) && block < 0
89 435 : && isVarConstant(mb, getArg(p, 1))
90 339 : && getArgType(mb, p, 1) == TYPE_bit) {
91 339 : if (getVarConstant(mb, getArg(p, 1)).val.btval == 0) {
92 185 : block = getArg(p, 0);
93 185 : skip++;
94 185 : action++;
95 : }
96 : // Try to remove the barrier statement itself (when true).
97 339 : if (getVarConstant(mb, getArg(p, 1)).val.btval == 1
98 141 : && OPTsimpleflow(mb, i)) {
99 128 : block = getArg(p, 0);
100 128 : skip = 0;
101 128 : action++;
102 128 : freeInstruction(p);
103 128 : mb->stmt[i] = 0;
104 128 : continue;
105 : }
106 24303 : } 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 24514 : multipass++;
110 24514 : if (skip) {
111 548 : freeInstruction(p);
112 548 : mb->stmt[i] = 0;
113 : } else
114 23966 : mb->stmt[j++] = p;
115 : }
116 310 : mb->stop = j;
117 1299 : for (; j < i; j++)
118 989 : mb->stmt[j] = NULL;
119 : }
120 307 : if (action)
121 112 : msg = chkTypes(cntxt->usermodule, mb, TRUE);
122 307 : return msg;
123 : }
124 :
125 : str
126 467675 : OPTevaluateImplementation(Client cntxt, MalBlkPtr mb, MalStkPtr stk,
127 : InstrPtr pci)
128 : {
129 467675 : InstrPtr p;
130 467675 : int i, k, limit, *alias = 0, barrier;
131 467675 : MalStkPtr env = NULL;
132 467675 : int actions = 0, constantblock = 0;
133 467675 : int *assigned = 0, use;
134 467675 : str msg = MAL_SUCCEED;
135 :
136 467675 : (void) stk;
137 :
138 467675 : if (mb->inlineProp)
139 : return MAL_SUCCEED;
140 :
141 467675 : assigned = (int *) GDKzalloc(sizeof(int) * mb->vtop);
142 467673 : if (assigned == NULL)
143 0 : throw(MAL, "optimizer.evaluate", SQLSTATE(HY013) MAL_MALLOC_FAIL);
144 :
145 467673 : alias = (int *) GDKzalloc(mb->vsize * sizeof(int) * 2); /* we introduce more */
146 467659 : 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 467659 : p = getInstrPtr(mb, 0);
152 468528 : for (k = p->retc; k < p->argc; k++) {
153 869 : assert(getArg(p, k) >= 0);
154 869 : assigned[getArg(p, k)]++;
155 : }
156 467659 : limit = mb->stop;
157 22033948 : for (i = 1; i < limit; i++) {
158 21566289 : p = getInstrPtr(mb, i);
159 : // The double count emerging from a barrier exit is ignored.
160 21566289 : if (!blockExit(p) || (blockExit(p) && p->retc != p->argc))
161 43390188 : for (k = 0; k < p->retc; k++)
162 21825016 : if (p->retc != p->argc || p->token != ASSIGNsymbol) {
163 21824646 : assert(getArg(p, k) >= 0);
164 21824646 : assigned[getArg(p, k)]++;
165 : }
166 : }
167 :
168 22035166 : for (i = 1; i < limit && cntxt->mode != FINISHCLIENT; i++) {
169 21567507 : 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 21567507 : assert(getArg(p, 0) >= 0);
173 21567507 : use = assigned[getArg(p, 0)] == 1 && !(p->argc == p->retc
174 11408522 : && blockExit(p));
175 51039508 : for (k = p->retc; k < p->argc; k++)
176 29472001 : if (alias[getArg(p, k)])
177 105212 : getArg(p, k) = alias[getArg(p, k)];
178 : /* be aware that you only assign once to a variable */
179 21567507 : if (use && p->retc == 1 && getFunctionId(p)
180 20432006 : && OPTallConstant(cntxt, mb, p) && !isUnsafeFunction(p)) {
181 104748 : barrier = p->barrier;
182 104748 : p->barrier = 0;
183 104748 : if (env == NULL) {
184 26894 : env = prepareMALstack(mb, 2 * mb->vsize);
185 26894 : 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 26894 : env->keepAlive = TRUE;
192 : }
193 104748 : msg = reenterMAL(cntxt, mb, i, i + 1, env);
194 104749 : p->barrier = barrier;
195 104749 : if (msg == MAL_SUCCEED) {
196 104221 : int nvar;
197 104221 : ValRecord cst;
198 :
199 104221 : actions++;
200 104221 : cst.vtype = 0;
201 104221 : 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 104221 : nvar = defConstant(mb, getArgType(mb, p, 0), &cst);
209 104220 : if (nvar >= 0)
210 104220 : getArg(p, 1) = nvar;
211 104220 : if (nvar >= env->stktop) {
212 52894 : if (VALcopy(&env->stk[getArg(p, 1)],
213 52894 : &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 52894 : env->stktop = getArg(p, 1) + 1;
219 : }
220 104220 : alias[getArg(p, 0)] = getArg(p, 1);
221 104220 : p->argc = 2;
222 104220 : p->token = ASSIGNsymbol;
223 104220 : clrFunction(p);
224 104219 : p->barrier = barrier;
225 : /* freeze the type */
226 104219 : 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 528 : freeException(msg);
231 528 : msg = MAL_SUCCEED;
232 528 : mb->errors = 0;
233 : }
234 : }
235 43134294 : constantblock += blockStart(p) && OPTallConstant(cntxt, mb, p); /* default */
236 : }
237 : // produces errors in SQL when enabled
238 467659 : if (constantblock)
239 307 : msg = OPTremoveUnusedBlocks(cntxt, mb);
240 :
241 : /* Defense line against incorrect plans */
242 : /* Plan is unaffected */
243 467659 : if (!msg)
244 467659 : msg = chkTypes(cntxt->usermodule, mb, FALSE);
245 467667 : if (!msg)
246 467669 : msg = chkFlow(mb);
247 467666 : if (!msg)
248 467666 : 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 467664 : (void) pushInt(mb, pci, actions);
254 :
255 467671 : if (env) {
256 26895 : assert(env->stktop < env->stksize);
257 26895 : freeStack(env);
258 : }
259 467670 : if (assigned)
260 467670 : GDKfree(assigned);
261 467675 : if (alias)
262 467675 : GDKfree(alias);
263 467675 : return msg;
264 : }
|