New test.
[mono.git] / mono / mini / cprop.c
1 /*
2  * cprop.c: Constant propagation.
3  *
4  * Author:
5  *   Paolo Molaro (lupus@ximian.com)
6  *
7  * (C) 2003 Ximian, Inc.
8  */
9
10 /* dumb list-based implementation for now */
11
12 typedef struct _MiniACP MiniACP;
13
14 struct _MiniACP {
15         MiniACP *next;
16         short dreg;
17         short sreg;
18         int type;
19 };
20
21 static int
22 copy_value (MiniACP *acp, int reg, int type)
23 {
24         MiniACP *tmp = acp;
25
26         //g_print ("search reg %d '%c'\n", reg, type);
27         while (tmp) {
28         //      g_print ("considering dreg %d, sreg %d '%c'\n", tmp->dreg, tmp->sreg, tmp->type);
29                 if (tmp->type == type && tmp->dreg == reg) {
30         //              g_print ("copy prop from %d to %d\n", tmp->sreg, tmp->dreg);
31                         return tmp->sreg;
32                 }
33                 tmp = tmp->next;
34         }
35         return reg;
36 }
37
38 static MiniACP*
39 remove_acp (MiniACP *acp, int reg, int type)
40 {
41         MiniACP *tmp = acp;
42         MiniACP *prev = NULL;
43
44         while (tmp) {
45                 if (tmp->type == type && (tmp->dreg == reg || tmp->sreg == reg)) {
46                         if (prev)
47                                 prev->next = tmp->next;
48                         else
49                                 acp = tmp->next;
50                 } else {
51                         prev = tmp;
52                 }
53                 tmp = tmp->next;
54         }
55         return acp;
56 }
57
58 static MiniACP*
59 add_acp (MonoCompile *cfg, MiniACP *acp, int sreg, int dreg, int type)
60 {
61         MiniACP *newacp = mono_mempool_alloc (cfg->mempool, sizeof (MiniACP));;
62         newacp->type = type;
63         newacp->sreg = sreg;
64         newacp->dreg = dreg;
65
66         newacp->next = acp;
67         return newacp;
68 }
69
70 static void
71 local_copy_prop (MonoCompile *cfg, MonoInst *code)
72 {
73         MiniACP *acp = NULL;
74         const char *spec;
75         MonoInst *ins = code;
76
77         //g_print ("starting BB\n");
78
79         while (ins) {
80                 spec = ins_spec [ins->opcode];
81                 //print_ins (0, ins);
82
83                 if (spec [MONO_INST_CLOB] != 's' && spec [MONO_INST_CLOB] != '1' && spec [MONO_INST_CLOB] != 'd' && spec [MONO_INST_CLOB] != 'a' && spec [MONO_INST_CLOB] != 'c') {
84                         if (spec [MONO_INST_SRC1] == 'f') {
85                                 ins->sreg1 = copy_value (acp, ins->sreg1, 'f');
86                         } else if (spec [MONO_INST_SRC1]) {
87                                 ins->sreg1 = copy_value (acp, ins->sreg1, 'i');
88                         }
89                 }
90
91                 if (spec [MONO_INST_CLOB] != 's') {
92                         if (spec [MONO_INST_SRC2] == 'f') {
93                                 ins->sreg2 = copy_value (acp, ins->sreg2, 'f');
94                         } else if (spec [MONO_INST_SRC2]) {
95                                 ins->sreg2 = copy_value (acp, ins->sreg2, 'i');
96                         }
97                 }
98
99                 /* invalidate pairs */
100                 if (spec [MONO_INST_DEST] == 'f') {
101                         acp = remove_acp (acp, ins->dreg, 'f');
102                 } else if (spec [MONO_INST_DEST]) {
103                         acp = remove_acp (acp, ins->dreg, 'i');
104                 }
105
106                 /* insert pairs */
107                 /*
108                  * Later copy-propagate also immediate values and memory stores.
109                  */
110                 if (ins->opcode == OP_MOVE && ins->sreg1 != ins->dreg) {
111         //              g_print ("added acp of %d <- %d '%c'\n", ins->dreg, ins->sreg1, spec [MONO_INST_SRC1]);
112                         acp = add_acp (cfg, acp, ins->sreg1, ins->dreg, spec [MONO_INST_SRC1]);
113                 }
114
115                 if (spec [MONO_INST_CLOB] == 'c') {
116                         /* this is a call, invalidate all the pairs */
117                         acp = NULL;
118                 } else if ((ins->opcode) == CEE_BR || (ins->opcode >= CEE_BEQ && ins->opcode <= CEE_BLT) ||
119                                 (ins->opcode >= CEE_BNE_UN && ins->opcode <= CEE_BLT_UN)) {
120                         acp = NULL; /* invalidate all pairs */
121                         /* it's not enough to invalidate the pairs, because we don't always
122                          * generate extended basic blocks (the BRANCH_LABEL stuff in the burg rules)
123                          * This issue is going to reduce a lot the possibilities for optimization!
124                          */
125                         return;
126                 }
127                 ins = ins->next;
128         }
129 }
130