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 518 : inlineMALblock(MalBlkPtr mb, int pc, MalBlkPtr mc)
20 : {
21 518 : int i, k, l, n;
22 518 : InstrPtr *ns, p, q;
23 518 : int *nv;
24 :
25 518 : p = getInstrPtr(mb, pc);
26 518 : q = getInstrPtr(mc, 0);
27 518 : ns = GDKzalloc((l = (mb->ssize + mc->ssize + p->retc - 3)) * sizeof(InstrPtr));
28 518 : if (ns == NULL)
29 : return -1;
30 518 : nv = (int *) GDKmalloc(mc->vtop * sizeof(int));
31 518 : 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 27915 : for (n = 0; n < mc->vtop; n++) {
38 27397 : char *nme = mc->var[n].name;
39 27397 : if (nme && isExceptionVariable(nme)) {
40 1 : nv[n] = newVariable(mb, nme, strlen(nme), TYPE_str);
41 27396 : } else if (isVarTypedef(mc, n)) {
42 1 : nv[n] = newTypeVariable(mb, getVarType(mc, n));
43 27395 : } else if (isVarConstant(mc, n)) {
44 3326 : nv[n] = cpyConstant(mb, getVar(mc, n));
45 : } else {
46 24069 : nv[n] = newTmpVariable(mb, getVarType(mc, n));
47 : }
48 27397 : 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 1205 : for (n = p->retc; n < p->argc; n++)
57 687 : nv[getArg(q, n)] = getArg(p, n);
58 :
59 23755 : k = 0;
60 : /* find the return statement of the inline function */
61 23755 : for (i = 1; i < mc->stop - 1; i++) {
62 23237 : q = mc->stmt[i];
63 23237 : if (q->barrier == RETURNsymbol) {
64 : /* add the mapping of the return variables */
65 1032 : for (n = 0; n < p->retc; n++)
66 516 : nv[getArg(q, n)] = getArg(p, n);
67 : }
68 : }
69 :
70 : /* copy the stable part */
71 476022 : for (i = 0; i < pc; i++)
72 475504 : ns[k++] = mb->stmt[i];
73 :
74 8615 : for (i = 1; i < mc->stop - 1; i++) {
75 8602 : q = mc->stmt[i];
76 8602 : if (q->token == ENDsymbol)
77 : break;
78 :
79 : /* copy the instruction and fix variable references */
80 8097 : ns[k] = copyInstruction(q);
81 8097 : if (ns[k] == NULL) {
82 0 : GDKfree(nv);
83 0 : GDKfree(ns);
84 0 : return -1;
85 : }
86 :
87 30580 : for (n = 0; n < q->argc; n++)
88 22483 : getArg(ns[k], n) = nv[getArg(q, n)];
89 :
90 8097 : if (q->barrier == RETURNsymbol) {
91 1032 : for (n = 0; n < q->retc; n++)
92 516 : clrVarFixed(mb, getArg(ns[k], n)); /* for typing */
93 516 : setModuleId(ns[k], getModuleId(q));
94 516 : setFunctionId(ns[k], getFunctionId(q));
95 516 : ns[k]->typeresolved = false;
96 516 : ns[k]->barrier = 0;
97 516 : ns[k]->token = ASSIGNsymbol;
98 : }
99 8097 : k++;
100 : }
101 :
102 : /* copy the remainder of the stable part */
103 518 : freeInstruction(p);
104 24272 : for (i = pc + 1; i < mb->stop; i++) {
105 23754 : ns[k++] = mb->stmt[i];
106 : }
107 : /* remove any free instruction */
108 1349562 : for (; i < mb->ssize; i++)
109 1349044 : if (mb->stmt[i]) {
110 0 : freeInstruction(mb->stmt[i]);
111 0 : mb->stmt[i] = 0;
112 : }
113 518 : GDKfree(mb->stmt);
114 518 : mb->stmt = ns;
115 :
116 518 : mb->ssize = l;
117 518 : mb->stop = k;
118 518 : GDKfree(nv);
119 518 : return pc;
120 : }
121 :
122 : static bool
123 312 : isCorrectInline(MalBlkPtr mb)
124 : {
125 : /* make sure we have a simple inline function with a singe return */
126 312 : InstrPtr p;
127 312 : int i, retseen = 0;
128 :
129 15123 : for (i = 1; i < mb->stop; i++) {
130 14811 : p = getInstrPtr(mb, i);
131 14811 : if (p->token == RETURNsymbol || p->barrier == RETURNsymbol)
132 310 : retseen++;
133 : }
134 312 : 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 547012 : OPTinlineImplementation(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
155 : {
156 547012 : int i;
157 547012 : InstrPtr q, sig;
158 547012 : int actions = 0;
159 547012 : str msg = MAL_SUCCEED;
160 :
161 547012 : (void) stk;
162 :
163 26272855 : for (i = 1; i < mb->stop; i++) {
164 25724806 : q = getInstrPtr(mb, i);
165 25724806 : 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 646 : if (sig->token == FUNCTIONsymbol && q->blk->inlineProp
178 312 : && isCorrectInline(q->blk)) {
179 312 : (void) inlineMALblock(mb, i, q->blk);
180 312 : i--;
181 312 : 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 548049 : if (actions > 0) {
189 242 : msg = chkTypes(cntxt->usermodule, mb, FALSE);
190 242 : if (!msg)
191 242 : msg = chkFlow(mb);
192 242 : if (!msg)
193 242 : msg = chkDeclarations(mb);
194 : }
195 : /* keep actions taken as a fake argument */
196 548049 : (void) pushInt(mb, pci, actions);
197 547793 : return msg;
198 : }
|