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 511 : inlineMALblock(MalBlkPtr mb, int pc, MalBlkPtr mc)
20 : {
21 511 : int i, k, l, n;
22 511 : InstrPtr *ns, p, q;
23 511 : int *nv;
24 :
25 511 : p = getInstrPtr(mb, pc);
26 511 : q = getInstrPtr(mc, 0);
27 511 : ns = GDKzalloc((l = (mb->ssize + mc->ssize + p->retc - 3)) * sizeof(InstrPtr));
28 511 : if (ns == NULL)
29 : return -1;
30 511 : nv = (int *) GDKmalloc(mc->vtop * sizeof(int));
31 511 : 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 27377 : for (n = 0; n < mc->vtop; n++) {
38 26866 : char *nme = mc->var[n].name;
39 26866 : if (nme && isExceptionVariable(nme)) {
40 1 : nv[n] = newVariable(mb, nme, strlen(nme), TYPE_str);
41 26865 : } else if (isVarTypedef(mc, n)) {
42 1 : nv[n] = newTypeVariable(mb, getVarType(mc, n));
43 26864 : } else if (isVarConstant(mc, n)) {
44 3277 : nv[n] = cpyConstant(mb, getVar(mc, n));
45 : } else {
46 23587 : nv[n] = newTmpVariable(mb, getVarType(mc, n));
47 : }
48 26866 : 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 1199 : for (n = p->retc; n < p->argc; n++)
57 688 : nv[getArg(q, n)] = getArg(p, n);
58 :
59 23277 : k = 0;
60 : /* find the return statement of the inline function */
61 23277 : for (i = 1; i < mc->stop - 1; i++) {
62 22766 : q = mc->stmt[i];
63 22766 : if (q->barrier == RETURNsymbol) {
64 : /* add the mapping of the return variables */
65 1018 : for (n = 0; n < p->retc; n++)
66 509 : nv[getArg(q, n)] = getArg(p, n);
67 : }
68 : }
69 :
70 : /* copy the stable part */
71 391091 : for (i = 0; i < pc; i++)
72 390580 : ns[k++] = mb->stmt[i];
73 :
74 8347 : for (i = 1; i < mc->stop - 1; i++) {
75 8334 : q = mc->stmt[i];
76 8334 : if (q->token == ENDsymbol)
77 : break;
78 :
79 : /* copy the instruction and fix variable references */
80 7836 : ns[k] = copyInstruction(q);
81 7836 : if (ns[k] == NULL) {
82 0 : GDKfree(nv);
83 0 : GDKfree(ns);
84 0 : return -1;
85 : }
86 :
87 29394 : for (n = 0; n < q->argc; n++)
88 21558 : getArg(ns[k], n) = nv[getArg(q, n)];
89 :
90 7836 : if (q->barrier == RETURNsymbol) {
91 1018 : for (n = 0; n < q->retc; n++)
92 509 : clrVarFixed(mb, getArg(ns[k], n)); /* for typing */
93 509 : setModuleId(ns[k], getModuleId(q));
94 509 : setFunctionId(ns[k], getFunctionId(q));
95 509 : ns[k]->typeresolved = false;
96 509 : ns[k]->barrier = 0;
97 509 : ns[k]->token = ASSIGNsymbol;
98 : }
99 7836 : k++;
100 : }
101 :
102 : /* copy the remainder of the stable part */
103 511 : freeInstruction(p);
104 19578 : for (i = pc + 1; i < mb->stop; i++) {
105 19067 : ns[k++] = mb->stmt[i];
106 : }
107 : /* remove any free instruction */
108 1282251 : for (; i < mb->ssize; i++)
109 1281740 : if (mb->stmt[i]) {
110 0 : freeInstruction(mb->stmt[i]);
111 0 : mb->stmt[i] = 0;
112 : }
113 511 : GDKfree(mb->stmt);
114 511 : mb->stmt = ns;
115 :
116 511 : mb->ssize = l;
117 511 : mb->stop = k;
118 511 : GDKfree(nv);
119 511 : return pc;
120 : }
121 :
122 : static bool
123 303 : isCorrectInline(MalBlkPtr mb)
124 : {
125 : /* make sure we have a simple inline function with a single return */
126 303 : InstrPtr p;
127 303 : int i, retseen = 0;
128 :
129 14561 : for (i = 1; i < mb->stop; i++) {
130 14258 : p = getInstrPtr(mb, i);
131 14258 : if (p->token == RETURNsymbol || p->barrier == RETURNsymbol)
132 301 : retseen++;
133 : }
134 303 : 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 563013 : OPTinlineImplementation(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
155 : {
156 563013 : int i;
157 563013 : InstrPtr q, sig;
158 563013 : int actions = 0;
159 563013 : str msg = MAL_SUCCEED;
160 :
161 563013 : (void) stk;
162 :
163 27566290 : for (i = 1; i < mb->stop; i++) {
164 27002336 : q = getInstrPtr(mb, i);
165 27002336 : if (q->blk) {
166 0 : 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 0 : if (isMultiplex(q)) {
172 0 : OPTinlineMultiplex(mb, q);
173 : } else
174 : /*
175 : * Check if the function definition is tagged as being inlined.
176 : */
177 640 : if (sig->token == FUNCTIONsymbol && q->blk->inlineProp
178 303 : && isCorrectInline(q->blk)) {
179 303 : (void) inlineMALblock(mb, i, q->blk);
180 303 : i--;
181 303 : 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 563954 : if (actions > 0) {
189 236 : msg = chkTypes(cntxt->usermodule, mb, FALSE);
190 236 : if (!msg)
191 236 : msg = chkFlow(mb);
192 236 : if (!msg)
193 236 : msg = chkDeclarations(mb);
194 : }
195 : /* keep actions taken as a fake argument */
196 563954 : (void) pushInt(mb, pci, actions);
197 563671 : return msg;
198 : }
|