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 531 : inlineMALblock(MalBlkPtr mb, int pc, MalBlkPtr mc)
20 : {
21 531 : int i, k, l, n;
22 531 : InstrPtr *ns, p, q;
23 531 : int *nv;
24 :
25 531 : p = getInstrPtr(mb, pc);
26 531 : q = getInstrPtr(mc, 0);
27 531 : ns = GDKzalloc((l = (mb->ssize + mc->ssize + p->retc - 3)) * sizeof(InstrPtr));
28 531 : if (ns == NULL)
29 : return -1;
30 531 : nv = (int *) GDKmalloc(mc->vtop * sizeof(int));
31 531 : 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 28324 : for (n = 0; n < mc->vtop; n++) {
38 27793 : char *nme = mc->var[n].name;
39 27793 : if (nme && isExceptionVariable(nme)) {
40 1 : nv[n] = newVariable(mb, nme, strlen(nme), TYPE_str);
41 27792 : } else if (isVarTypedef(mc, n)) {
42 1 : nv[n] = newTypeVariable(mb, getVarType(mc, n));
43 27791 : } else if (isVarConstant(mc, n)) {
44 3388 : nv[n] = cpyConstant(mb, getVar(mc, n));
45 : } else {
46 24403 : nv[n] = newTmpVariable(mb, getVarType(mc, n));
47 : }
48 27793 : 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 1237 : for (n = p->retc; n < p->argc; n++)
57 706 : nv[getArg(q, n)] = getArg(p, n);
58 :
59 24099 : k = 0;
60 : /* find the return statement of the inline function */
61 24099 : for (i = 1; i < mc->stop - 1; i++) {
62 23568 : q = mc->stmt[i];
63 23568 : if (q->barrier == RETURNsymbol) {
64 : /* add the mapping of the return variables */
65 1058 : for (n = 0; n < p->retc; n++)
66 529 : nv[getArg(q, n)] = getArg(p, n);
67 : }
68 : }
69 :
70 : /* copy the stable part */
71 367590 : for (i = 0; i < pc; i++)
72 367059 : ns[k++] = mb->stmt[i];
73 :
74 8569 : for (i = 1; i < mc->stop - 1; i++) {
75 8556 : q = mc->stmt[i];
76 8556 : if (q->token == ENDsymbol)
77 : break;
78 :
79 : /* copy the instruction and fix variable references */
80 8038 : ns[k] = copyInstruction(q);
81 8038 : if (ns[k] == NULL) {
82 0 : GDKfree(nv);
83 0 : GDKfree(ns);
84 0 : return -1;
85 : }
86 :
87 30150 : for (n = 0; n < q->argc; n++)
88 22112 : getArg(ns[k], n) = nv[getArg(q, n)];
89 :
90 8038 : if (q->barrier == RETURNsymbol) {
91 1058 : for (n = 0; n < q->retc; n++)
92 529 : clrVarFixed(mb, getArg(ns[k], n)); /* for typing */
93 529 : setModuleId(ns[k], getModuleId(q));
94 529 : setFunctionId(ns[k], getFunctionId(q));
95 529 : ns[k]->typeresolved = false;
96 529 : ns[k]->barrier = 0;
97 529 : ns[k]->token = ASSIGNsymbol;
98 : }
99 8038 : k++;
100 : }
101 :
102 : /* copy the remainder of the stable part */
103 531 : freeInstruction(p);
104 20134 : for (i = pc + 1; i < mb->stop; i++) {
105 19603 : ns[k++] = mb->stmt[i];
106 : }
107 : /* remove any free instruction */
108 1276048 : for (; i < mb->ssize; i++)
109 1275517 : if (mb->stmt[i]) {
110 0 : freeInstruction(mb->stmt[i]);
111 0 : mb->stmt[i] = 0;
112 : }
113 531 : GDKfree(mb->stmt);
114 531 : mb->stmt = ns;
115 :
116 531 : mb->ssize = l;
117 531 : mb->stop = k;
118 531 : GDKfree(nv);
119 531 : return pc;
120 : }
121 :
122 : static bool
123 319 : isCorrectInline(MalBlkPtr mb)
124 : {
125 : /* make sure we have a simple inline function with a single return */
126 319 : InstrPtr p;
127 319 : int i, retseen = 0;
128 :
129 15251 : for (i = 1; i < mb->stop; i++) {
130 14932 : p = getInstrPtr(mb, i);
131 14932 : if (p->token == RETURNsymbol || p->barrier == RETURNsymbol)
132 317 : retseen++;
133 : }
134 319 : 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 568702 : OPTinlineImplementation(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
155 : {
156 568702 : int i;
157 568702 : InstrPtr q, sig;
158 568702 : int actions = 0;
159 568702 : str msg = MAL_SUCCEED;
160 :
161 568702 : (void) stk;
162 :
163 27922519 : for (i = 1; i < mb->stop; i++) {
164 27352585 : q = getInstrPtr(mb, i);
165 27352585 : 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 665 : if (sig->token == FUNCTIONsymbol && q->blk->inlineProp
178 319 : && isCorrectInline(q->blk)) {
179 319 : (void) inlineMALblock(mb, i, q->blk);
180 319 : i--;
181 319 : 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 569934 : if (actions > 0) {
189 250 : msg = chkTypes(cntxt->usermodule, mb, FALSE);
190 250 : if (!msg)
191 250 : msg = chkFlow(mb);
192 250 : if (!msg)
193 250 : msg = chkDeclarations(mb);
194 : }
195 : /* keep actions taken as a fake argument */
196 569934 : (void) pushInt(mb, pci, actions);
197 569521 : return msg;
198 : }
|