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 27751 : for (n = 0; n < mc->vtop; n++) {
38 27230 : if (isExceptionVariable(getVarName(mc, n))) {
39 1 : nv[n] = newVariable(mb, getVarName(mc, n),
40 1 : strlen(getVarName(mc, n)), TYPE_str);
41 27229 : } else if (isVarTypedef(mc, n)) {
42 1 : nv[n] = newTypeVariable(mb, getVarType(mc, n));
43 27228 : } else if (isVarConstant(mc, n)) {
44 3005 : nv[n] = cpyConstant(mb, getVar(mc, n));
45 : } else {
46 24223 : nv[n] = newTmpVariable(mb, getVarType(mc, n));
47 : }
48 27230 : 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 1214 : for (n = p->retc; n < p->argc; n++)
57 693 : nv[getArg(q, n)] = getArg(p, n);
58 :
59 23908 : k = 0;
60 : /* find the return statement of the inline function */
61 23908 : for (i = 1; i < mc->stop - 1; i++) {
62 23387 : q = mc->stmt[i];
63 23387 : 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 487209 : for (i = 0; i < pc; i++)
72 486688 : ns[k++] = mb->stmt[i];
73 :
74 8678 : for (i = 1; i < mc->stop - 1; i++) {
75 8665 : q = mc->stmt[i];
76 8665 : if (q->token == ENDsymbol)
77 : break;
78 :
79 : /* copy the instruction and fix variable references */
80 8157 : ns[k] = copyInstruction(q);
81 8157 : if (ns[k] == NULL) {
82 0 : GDKfree(nv);
83 0 : GDKfree(ns);
84 0 : return -1;
85 : }
86 :
87 30730 : for (n = 0; n < q->argc; n++)
88 22573 : getArg(ns[k], n) = nv[getArg(q, n)];
89 :
90 8157 : 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]->typechk = TYPE_UNKNOWN;
96 519 : ns[k]->barrier = 0;
97 519 : ns[k]->token = ASSIGNsymbol;
98 : }
99 8157 : k++;
100 : }
101 :
102 : /* copy the remainder of the stable part */
103 521 : freeInstruction(p);
104 23228 : for (i = pc + 1; i < mb->stop; i++) {
105 22707 : ns[k++] = mb->stmt[i];
106 : }
107 : /* remove any free instruction */
108 1386785 : for (; i < mb->ssize; i++)
109 1386264 : 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 315 : isCorrectInline(MalBlkPtr mb)
124 : {
125 : /* make sure we have a simple inline function with a singe return */
126 315 : InstrPtr p;
127 315 : int i, retseen = 0;
128 :
129 15256 : for (i = 1; i < mb->stop; i++) {
130 14941 : p = getInstrPtr(mb, i);
131 14941 : if (p->token == RETURNsymbol || p->barrier == RETURNsymbol)
132 313 : retseen++;
133 : }
134 315 : return retseen <= 1;
135 : }
136 :
137 :
138 : static bool
139 146927 : OPTinlineMultiplex(MalBlkPtr mb, InstrPtr p)
140 : {
141 146927 : Symbol s;
142 146927 : str mod, fcn;
143 :
144 146927 : int plus_one = getArgType(mb, p, p->retc) == TYPE_lng ? 1 : 0;
145 146927 : mod = VALget(&getVar(mb, getArg(p, p->retc + 0 + plus_one))->value);
146 146927 : fcn = VALget(&getVar(mb, getArg(p, p->retc + 1 + plus_one))->value);
147 146927 : if ((s = findSymbolInModule(getModule(putName(mod)), putName(fcn))) == 0)
148 : return false;
149 146910 : return s->def->inlineProp;
150 : }
151 :
152 :
153 : str
154 538709 : OPTinlineImplementation(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
155 : {
156 538709 : int i;
157 538709 : InstrPtr q, sig;
158 538709 : int actions = 0;
159 538709 : str msg = MAL_SUCCEED;
160 :
161 538709 : (void) stk;
162 :
163 26242786 : for (i = 1; i < mb->stop; i++) {
164 25704102 : q = getInstrPtr(mb, i);
165 25704102 : if (q->blk) {
166 21897729 : 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 21897729 : if (isMultiplex(q)) {
172 146927 : OPTinlineMultiplex(mb, q);
173 : } else
174 : /*
175 : * Check if the function definition is tagged as being inlined.
176 : */
177 21750777 : if (sig->token == FUNCTIONsymbol && q->blk->inlineProp
178 315 : && isCorrectInline(q->blk)) {
179 315 : (void) inlineMALblock(mb, i, q->blk);
180 315 : i--;
181 315 : 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 538684 : if (actions > 0) {
189 245 : msg = chkTypes(cntxt->usermodule, mb, FALSE);
190 245 : if (!msg)
191 245 : msg = chkFlow(mb);
192 245 : if (!msg)
193 245 : msg = chkDeclarations(mb);
194 : }
195 : /* keep actions taken as a fake argument */
196 538684 : (void) pushInt(mb, pci, actions);
197 538690 : return msg;
198 : }
|