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 | |
14 | str |
15 | OPTdeadcodeImplementation(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 | |
143 | wrapup: |
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 | |