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_inline.h"
15 :
16 : #define MAXEXPANSION 256
17 :
18 : int
19 521 : inlineMALblock(MalBlkPtr mb, int pc, MalBlkPtr mc)
20 : {
21 521 : int i, k, l, n;
22 521 : InstrPtr *ns, p, q;
23 521 : int *nv;
24 :
25 521 : p = getInstrPtr(mb, pc);
26 521 : q = getInstrPtr(mc, 0);
27 521 : ns = GDKzalloc((l = (mb->ssize + mc->ssize + p->retc - 3)) * sizeof(InstrPtr));
28 521 : if (ns == NULL)
29 : return -1;
30 521 : nv = (int *) GDKmalloc(mc->vtop * sizeof(int));
31 521 : if (nv == 0) {
32 0 : GDKfree(ns);
33 0 : return -1;
34 : }
35 :
36 : /* add all variables of the new block to the target environment */
37 27874 : for (n = 0; n < mc->vtop; n++) {
38 27353 : char *nme = mc->var[n].name;
39 27353 : if (nme && isExceptionVariable(nme)) {
40 1 : nv[n] = newVariable(mb, nme, strlen(nme), TYPE_str);
41 27352 : } else if (isVarTypedef(mc, n)) {
42 1 : nv[n] = newTypeVariable(mb, getVarType(mc, n));
43 27351 : } else if (isVarConstant(mc, n)) {
44 3318 : nv[n] = cpyConstant(mb, getVar(mc, n));
45 : } else {
46 24033 : nv[n] = newTmpVariable(mb, getVarType(mc, n));
47 : }
48 27353 : if (nv[n] < 0) {
49 0 : GDKfree(nv);
50 0 : GDKfree(ns);
51 0 : return -1;
52 : }
53 : }
54 :
55 : /* use an alias mapping to keep track of the actual arguments */
56 1217 : for (n = p->retc; n < p->argc; n++)
57 696 : nv[getArg(q, n)] = getArg(p, n);
58 :
59 23729 : k = 0;
60 : /* find the return statement of the inline function */
61 23729 : for (i = 1; i < mc->stop - 1; i++) {
62 23208 : q = mc->stmt[i];
63 23208 : if (q->barrier == RETURNsymbol) {
64 : /* add the mapping of the return variables */
65 1038 : for (n = 0; n < p->retc; n++)
66 519 : nv[getArg(q, n)] = getArg(p, n);
67 : }
68 : }
69 :
70 : /* copy the stable part */
71 391186 : for (i = 0; i < pc; i++)
72 390665 : ns[k++] = mb->stmt[i];
73 :
74 8499 : for (i = 1; i < mc->stop - 1; i++) {
75 8486 : q = mc->stmt[i];
76 8486 : if (q->token == ENDsymbol)
77 : break;
78 :
79 : /* copy the instruction and fix variable references */
80 7978 : ns[k] = copyInstruction(q);
81 7978 : if (ns[k] == NULL) {
82 0 : GDKfree(nv);
83 0 : GDKfree(ns);
84 0 : return -1;
85 : }
86 :
87 29995 : for (n = 0; n < q->argc; n++)
88 22017 : getArg(ns[k], n) = nv[getArg(q, n)];
89 :
90 7978 : if (q->barrier == RETURNsymbol) {
91 1038 : for (n = 0; n < q->retc; n++)
92 519 : clrVarFixed(mb, getArg(ns[k], n)); /* for typing */
93 519 : setModuleId(ns[k], getModuleId(q));
94 519 : setFunctionId(ns[k], getFunctionId(q));
95 519 : ns[k]->typeresolved = false;
96 519 : ns[k]->barrier = 0;
97 519 : ns[k]->token = ASSIGNsymbol;
98 : }
99 7978 : k++;
100 : }
101 :
102 : /* copy the remainder of the stable part */
103 521 : freeInstruction(p);
104 19932 : for (i = pc + 1; i < mb->stop; i++) {
105 19411 : ns[k++] = mb->stmt[i];
106 : }
107 : /* remove any free instruction */
108 1284890 : for (; i < mb->ssize; i++)
109 1284369 : if (mb->stmt[i]) {
110 0 : freeInstruction(mb->stmt[i]);
111 0 : mb->stmt[i] = 0;
112 : }
113 521 : GDKfree(mb->stmt);
114 521 : mb->stmt = ns;
115 :
116 521 : mb->ssize = l;
117 521 : mb->stop = k;
118 521 : GDKfree(nv);
119 521 : return pc;
120 : }
121 :
122 : static bool
123 313 : isCorrectInline(MalBlkPtr mb)
124 : {
125 : /* make sure we have a simple inline function with a single return */
126 313 : InstrPtr p;
127 313 : int i, retseen = 0;
128 :
129 15023 : for (i = 1; i < mb->stop; i++) {
130 14710 : p = getInstrPtr(mb, i);
131 14710 : if (p->token == RETURNsymbol || p->barrier == RETURNsymbol)
132 311 : retseen++;
133 : }
134 313 : return retseen <= 1;
135 : }
136 :
137 :
138 : static bool
139 0 : OPTinlineMultiplex(MalBlkPtr mb, InstrPtr p)
140 : {
141 0 : Symbol s;
142 0 : str mod, fcn;
143 :
144 0 : int plus_one = getArgType(mb, p, p->retc) == TYPE_lng ? 1 : 0;
145 0 : mod = VALget(&getVar(mb, getArg(p, p->retc + 0 + plus_one))->value);
146 0 : fcn = VALget(&getVar(mb, getArg(p, p->retc + 1 + plus_one))->value);
147 0 : if ((s = findSymbolInModule(getModule(putName(mod)), putName(fcn))) == 0)
148 : return false;
149 0 : return s->def->inlineProp;
150 : }
151 :
152 :
153 : str
154 554481 : OPTinlineImplementation(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
155 : {
156 554481 : int i;
157 554481 : InstrPtr q, sig;
158 554481 : int actions = 0;
159 554481 : str msg = MAL_SUCCEED;
160 :
161 554481 : (void) stk;
162 :
163 27064644 : for (i = 1; i < mb->stop; i++) {
164 26510166 : q = getInstrPtr(mb, i);
165 26510166 : if (q->blk) {
166 662 : sig = getInstrPtr(q->blk, 0);
167 : /*
168 : * Time for inlining functions that are used in multiplex operations.
169 : * They are produced by SQL compiler.
170 : */
171 662 : if (isMultiplex(q)) {
172 0 : OPTinlineMultiplex(mb, q);
173 : } else
174 : /*
175 : * Check if the function definition is tagged as being inlined.
176 : */
177 659 : if (sig->token == FUNCTIONsymbol && q->blk->inlineProp
178 313 : && isCorrectInline(q->blk)) {
179 313 : (void) inlineMALblock(mb, i, q->blk);
180 313 : i--;
181 313 : actions++;
182 : }
183 : }
184 : }
185 :
186 : //mnstr_printf(cntxt->fdout,"inline limit %d ssize %d vtop %d vsize %d\n", mb->stop, (int)(mb->ssize), mb->vtop, (int)(mb->vsize));
187 : /* Defense line against incorrect plans */
188 554478 : if (actions > 0) {
189 244 : msg = chkTypes(cntxt->usermodule, mb, FALSE);
190 244 : if (!msg)
191 244 : msg = chkFlow(mb);
192 244 : if (!msg)
193 244 : msg = chkDeclarations(mb);
194 : }
195 : /* keep actions taken as a fake argument */
196 554478 : (void) pushInt(mb, pci, actions);
197 554474 : return msg;
198 : }
|