1/*
2 * This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
5 *
6 * Copyright 1997 - July 2008 CWI, August 2008 - 2019 MonetDB B.V.
7 */
8
9/* (c) Martin Kersten
10 */
11#include "monetdb_config.h"
12#include "opt_deadcode.h"
13
14str
15OPTdeadcodeImplementation(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
16{
17 int i, k, se,limit, slimit;
18 InstrPtr p=0, *old= mb->stmt;
19 int actions = 0;
20 int *varused=0;
21 char buf[256];
22 lng usec = GDKusec();
23 str msg= MAL_SUCCEED;
24
25 (void) cntxt;
26 (void) pci;
27 (void) stk; /* to fool compilers */
28
29 if ( mb->inlineProp )
30 return MAL_SUCCEED;
31
32 varused = GDKzalloc(mb->vtop * sizeof(int));
33 if (varused == NULL)
34 return MAL_SUCCEED;
35
36 limit = mb->stop;
37 slimit = mb->ssize;
38 if (newMalBlkStmt(mb, mb->ssize) < 0) {
39 msg= createException(MAL,"optimizer.deadcode", SQLSTATE(HY001) MAL_MALLOC_FAIL);
40 goto wrapup;
41 }
42
43 // Calculate the instructions in which a variable is used.
44 // Variables can be used multiple times in an instruction.
45 for (i = 1; i < limit; i++) {
46 p = old[i];
47 for( k=p->retc; k<p->argc; k++)
48 varused[getArg(p,k)]++;
49 if ( blockCntrl(p) )
50 for( k= 0; k < p->retc; k++)
51 varused[getArg(p,k)]++;
52 }
53
54 // Consolidate the actual need for variables
55 for (i = limit; i >= 0; i--) {
56 p = old[i];
57 if( p == 0)
58 continue; //left behind by others?
59
60 /* catched by the hasSideEffects
61 if( getModuleId(p)== sqlRef && getFunctionId(p)== assertRef ){
62 varused[getArg(p,0)]++; // force keeping
63 continue;
64 }
65*/
66 if ( getModuleId(p) == batRef && isUpdateInstruction(p) && !p->barrier){
67 /* bat.append and friends are intermediates that need not be retained
68 * unless they are not used outside of an update */
69 if( varused[getArg(p,1)] > 1 )
70 varused[getArg(p,0)]++; // force keeping it
71 } else
72 if (hasSideEffects(mb, p, FALSE) || !isLinearFlow(p) ||
73 (p->retc == 1 && mb->unsafeProp) || p->barrier /* ==side-effect */){
74 varused[getArg(p,0)]++; // force keeping it
75 continue;
76 }
77
78 // The results should be used somewhere
79 se = 0;
80 for ( k=0; k < p->retc; k++)
81 se += varused[getArg(p,k)] > 0;
82
83 // Reduce input variable count when garbage is detected
84 if (se == 0 )
85 for ( k=p->retc; k < p->argc; k++)
86 varused[getArg(p,k)]--;
87 }
88
89 // Now we can simply copy the intructions and discard useless ones.
90 pushInstruction(mb, old[0]);
91 for (i = 1; i < limit; i++) {
92 if ((p = old[i]) != NULL) {
93 if( p->token == ENDsymbol){
94 pushInstruction(mb,p);
95 // Also copy the optimizer trace information
96 for(i++; i<limit; i++)
97 if(old[i])
98 pushInstruction(mb,old[i]);
99 break;
100 }
101
102 // Is the instruction still relevant?
103 se = 0;
104 for ( k=0; k < p->retc; k++)
105 se += varused[getArg(p,k)] > 0;
106
107 if (se)
108 pushInstruction(mb,p);
109 else {
110 freeInstruction(p);
111 actions ++;
112 }
113 /* Enable when bugTracker-2012/Tests/mal_errors survives it
114 if ( getModuleId(p) == groupRef && p->retc == 3 && varused[getArg(p,2)] == 0 &&
115 (getFunctionId(p) == groupRef ||
116 getFunctionId(p) == subgroupRef ||
117 getFunctionId(p) == groupdoneRef ||
118 getFunctionId(p) == subgroupdoneRef)){
119 // remove the histogram unless needed
120 delArgument(p,2);
121 actions++;
122 }
123 */
124 }
125 }
126 for(; i<slimit; i++)
127 if( old[i])
128 freeInstruction(old[i]);
129 /* Defense line against incorrect plans */
130 /* we don't create or change existing structures */
131 //if( actions > 0){
132 chkTypes(cntxt->usermodule, mb, FALSE);
133 chkFlow(mb);
134 chkDeclarations(mb);
135 //}
136 /* keep all actions taken as a post block comment */
137 usec = GDKusec()- usec;
138 snprintf(buf,256,"%-20s actions=%2d time=" LLFMT " usec","deadcode",actions, usec);
139 newComment(mb,buf);
140 if( actions >= 0)
141 addtoMalBlkHistory(mb);
142
143wrapup:
144 if(old) GDKfree(old);
145 if(varused) GDKfree(varused);
146 if( OPTdebug & OPTdeadcode){
147 fprintf(stderr, "#DEADCODE optimizer exit\n");
148 fprintFunction(stderr, mb, 0, LIST_MAL_ALL);
149 }
150 return msg;
151}
152