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 21079669 : OPTallConstant(Client cntxt, MalBlkPtr mb, InstrPtr p)
19 : {
20 21079669 : int i;
21 21079669 : (void) cntxt;
22 :
23 21079669 : if (p->token != ASSIGNsymbol
24 21078480 : && getModuleId(p) != calcRef
25 20935675 : && getModuleId(p) != strRef
26 20935235 : && getModuleId(p) != mtimeRef
27 20934677 : && getModuleId(p) != mmathRef)
28 : return false;
29 145243 : if (getModuleId(p) == mmathRef && strcmp(getFunctionId(p), "rand") == 0)
30 : return false;
31 :
32 346114 : for (i = p->retc; i < p->argc; i++)
33 240418 : if (isVarConstant(mb, getArg(p, i)) == FALSE)
34 : return false;
35 211316 : for (i = 0; i < p->retc; i++) {
36 105696 : if (isaBatType(getArgType(mb, p, i)))
37 : return false;
38 105696 : if (p->unsafeProp || mb->unsafeProp)
39 : return false;
40 : }
41 : return true;
42 : }
43 :
44 : static bool
45 142 : OPTsimpleflow(MalBlkPtr mb, int pc)
46 : {
47 142 : int i, block = 0;
48 142 : bool simple = true;
49 142 : InstrPtr p;
50 :
51 628 : for (i = pc; i < mb->stop; i++) {
52 628 : p = getInstrPtr(mb, i);
53 628 : if (blockStart(p))
54 153 : block++;
55 628 : if (blockExit(p))
56 153 : block--;
57 628 : if (blockCntrl(p))
58 26 : simple = false;
59 628 : if (block == 0) {
60 142 : 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 309 : OPTremoveUnusedBlocks(Client cntxt, MalBlkPtr mb)
69 : {
70 : /* catch and remove constant bounded blocks */
71 309 : int i, j = 0, action = 0, block = -1, skip = 0, multipass = 1;
72 309 : InstrPtr p;
73 309 : str msg = MAL_SUCCEED;
74 :
75 621 : while (multipass--) {
76 : block = -1;
77 : skip = 0;
78 : j = 0;
79 25144 : for (i = 0; i < mb->stop; i++) {
80 24832 : p = mb->stmt[i];
81 24832 : 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 24517 : if (p->argc == 2 && blockStart(p) && block < 0
89 437 : && isVarConstant(mb, getArg(p, 1))
90 437 : && getArgType(mb, p, 1) == TYPE_bit) {
91 341 : 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 341 : if (getVarConstant(mb, getArg(p, 1)).val.btval == 1
98 142 : && 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 24176 : } 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 24388 : multipass++;
110 24388 : if (skip) {
111 559 : freeInstruction(p);
112 559 : mb->stmt[i] = 0;
113 : } else
114 23829 : mb->stmt[j++] = p;
115 : }
116 312 : mb->stop = j;
117 1315 : for (; j < i; j++)
118 1003 : mb->stmt[j] = NULL;
119 : }
120 309 : if (action)
121 113 : msg = chkTypes(cntxt->usermodule, mb, TRUE);
122 309 : return msg;
123 : }
124 :
125 : str
126 483209 : OPTevaluateImplementation(Client cntxt, MalBlkPtr mb, MalStkPtr stk,
127 : InstrPtr pci)
128 : {
129 483209 : InstrPtr p;
130 483209 : int i, k, limit, *alias = 0, barrier;
131 483209 : MalStkPtr env = NULL;
132 483209 : int actions = 0, constantblock = 0;
133 483209 : int *assigned = 0, use;
134 483209 : str msg = MAL_SUCCEED;
135 :
136 483209 : (void) stk;
137 :
138 483209 : if (mb->inlineProp)
139 : return MAL_SUCCEED;
140 :
141 483209 : assigned = (int *) GDKzalloc(sizeof(int) * mb->vtop);
142 483210 : if (assigned == NULL)
143 0 : throw(MAL, "optimizer.evaluate", SQLSTATE(HY013) MAL_MALLOC_FAIL);
144 :
145 483210 : alias = (int *) GDKzalloc(mb->vsize * sizeof(int) * 2); /* we introduce more */
146 483200 : 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 483200 : p = getInstrPtr(mb, 0);
152 484073 : for (k = p->retc; k < p->argc; k++) {
153 873 : assert(getArg(p, k) >= 0);
154 873 : assigned[getArg(p, k)]++;
155 : }
156 483200 : limit = mb->stop;
157 22746359 : for (i = 1; i < limit; i++) {
158 22263159 : p = getInstrPtr(mb, i);
159 : // The double count emerging from a barrier exit is ignored.
160 22263159 : if (!blockExit(p) || (blockExit(p) && p->retc != p->argc))
161 44808258 : for (k = 0; k < p->retc; k++)
162 22546288 : if (p->retc != p->argc || p->token != ASSIGNsymbol) {
163 22545916 : assert(getArg(p, k) >= 0);
164 22545916 : assigned[getArg(p, k)]++;
165 : }
166 : }
167 :
168 22747405 : for (i = 1; i < limit && cntxt->mode != FINISHCLIENT; i++) {
169 22264202 : 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 22264202 : assert(getArg(p, 0) >= 0);
173 22264202 : use = assigned[getArg(p, 0)] == 1 && !(p->argc == p->retc
174 11813577 : && blockExit(p));
175 52484759 : for (k = p->retc; k < p->argc; k++)
176 30220557 : if (alias[getArg(p, k)])
177 105379 : getArg(p, k) = alias[getArg(p, k)];
178 : /* be aware that you only assign once to a variable */
179 22264202 : if (use && p->retc == 1 && getFunctionId(p)
180 21078445 : && OPTallConstant(cntxt, mb, p) && !isUnsafeFunction(p)) {
181 104896 : barrier = p->barrier;
182 104896 : p->barrier = 0;
183 104896 : if (env == NULL) {
184 27565 : env = prepareMALstack(mb, 2 * mb->vsize);
185 27563 : 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 27563 : env->keepAlive = TRUE;
192 : }
193 104894 : msg = reenterMAL(cntxt, mb, i, i + 1, env);
194 104897 : p->barrier = barrier;
195 104897 : if (msg == MAL_SUCCEED) {
196 104406 : int nvar;
197 104406 : ValRecord cst;
198 :
199 104406 : actions++;
200 104406 : cst.vtype = 0;
201 104406 : 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 104406 : nvar = defConstant(mb, getArgType(mb, p, 0), &cst);
209 104403 : if (nvar >= 0)
210 104403 : getArg(p, 1) = nvar;
211 104403 : if (nvar >= env->stktop) {
212 53356 : if (VALcopy(&env->stk[getArg(p, 1)],
213 53354 : &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 53356 : env->stktop = getArg(p, 1) + 1;
219 : }
220 104405 : alias[getArg(p, 0)] = getArg(p, 1);
221 104405 : p->argc = 2;
222 104405 : p->token = ASSIGNsymbol;
223 104405 : clrFunction(p);
224 104406 : p->barrier = barrier;
225 : /* freeze the type */
226 104406 : 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 491 : freeException(msg);
231 491 : msg = MAL_SUCCEED;
232 491 : mb->errors = 0;
233 : }
234 : }
235 44527684 : constantblock += blockStart(p) && OPTallConstant(cntxt, mb, p); /* default */
236 : }
237 : // produces errors in SQL when enabled
238 483203 : if (constantblock)
239 309 : msg = OPTremoveUnusedBlocks(cntxt, mb);
240 :
241 : /* Defense line against incorrect plans */
242 : /* Plan is unaffected */
243 483203 : if (!msg)
244 483203 : msg = chkTypes(cntxt->usermodule, mb, FALSE);
245 483205 : if (!msg)
246 483208 : msg = chkFlow(mb);
247 483206 : if (!msg)
248 483206 : 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 483195 : (void) pushInt(mb, pci, actions);
254 :
255 483202 : if (env) {
256 27561 : assert(env->stktop < env->stksize);
257 27561 : freeStack(env);
258 : }
259 483207 : if (assigned)
260 483207 : GDKfree(assigned);
261 483209 : if (alias)
262 483209 : GDKfree(alias);
263 483209 : return msg;
264 : }
|