Bug in var->Def
[pspdecompiler.git] / constants.c
blobb045b785c9b15e8457f7bd66fee2f41b9ee0c6ba
1 /**
2 * Author: Humberto Naves (hsnaves@gmail.com)
3 */
6 #include "code.h"
7 #include "utils.h"
9 static
10 uint32 get_constant_value (struct value *val)
12 if (val->type == VAL_SSAVAR)
13 return val->val.variable->value;
14 else
15 return val->val.intval;
18 static
19 void combine_constants (struct ssavar *out, struct value *val)
21 uint32 constant;
22 if (CONST_TYPE (out->status) == VAR_STAT_NOTCONSTANT) return;
24 if (val->type == VAL_REGISTER) {
25 CONST_SETTYPE (out->status, VAR_STAT_NOTCONSTANT);
28 if (val->type == VAL_SSAVAR) {
29 if (CONST_TYPE (val->val.variable->status) == VAR_STAT_UNKCONSTANT)
30 return;
31 if (CONST_TYPE (val->val.variable->status) == VAR_STAT_NOTCONSTANT) {
32 CONST_SETTYPE (out->status, VAR_STAT_NOTCONSTANT);
33 return;
37 constant = get_constant_value (val);
38 if (CONST_TYPE (out->status) == VAR_STAT_UNKCONSTANT) {
39 CONST_SETTYPE (out->status, VAR_STAT_CONSTANT);
40 out->value = constant;
41 } else {
42 if (out->value != constant)
43 CONST_SETTYPE (out->status, VAR_STAT_NOTCONSTANT);
47 void propagate_constants (struct subroutine *sub)
49 list worklist = list_alloc (sub->code->lstpool);
50 element varel;
52 varel = list_head (sub->ssavars);
53 while (varel) {
54 struct ssavar *var = element_getvalue (varel);
55 struct operation *op = var->def;
56 CONST_SETTYPE (var->status, VAR_STAT_UNKCONSTANT);
57 if (op->type == OP_ASM ||
58 op->type == OP_CALL ||
59 op->type == OP_START ||
60 !(IS_BIT_SET (regmask_localvars, var->name.val.intval)))
61 CONST_SETTYPE (var->status, VAR_STAT_NOTCONSTANT);
62 else {
63 var->mark = 1;
64 list_inserttail (worklist, var);
66 varel = element_next (varel);
69 while (list_size (worklist) != 0) {
70 struct ssavar *aux, *var = list_removehead (worklist);
71 struct ssavar temp;
72 struct value *val;
73 struct operation *op;
74 element opel;
76 var->mark = 0;
77 op = var->def;
78 op->status &= ~OP_STAT_CONSTANT;
80 if (CONST_TYPE (var->status) == VAR_STAT_NOTCONSTANT) continue;
82 if (op->type == OP_PHI) {
83 temp.status = VAR_STAT_UNKCONSTANT;
85 opel = list_head (op->operands);
86 while (opel) {
87 val = element_getvalue (opel);
88 combine_constants (&temp, val);
89 opel = element_next (opel);
91 } else {
92 temp.status = VAR_STAT_CONSTANT;
94 opel = list_head (op->operands);
95 while (opel) {
96 val = element_getvalue (opel);
97 if (val->type == VAL_SSAVAR) {
98 aux = val->val.variable;
99 if (CONST_TYPE (aux->status) == VAR_STAT_NOTCONSTANT) {
100 temp.status = VAR_STAT_NOTCONSTANT;
101 break;
102 } else if (CONST_TYPE (aux->status) == VAR_STAT_UNKCONSTANT)
103 temp.status = VAR_STAT_UNKCONSTANT;
105 opel = element_next (opel);
108 if (temp.status == VAR_STAT_CONSTANT) {
109 if (op->type == OP_MOVE) {
110 val = list_headvalue (op->operands);
111 temp.value = get_constant_value (val);
112 op->status |= OP_STAT_CONSTANT;
113 } else if (op->type == OP_INSTRUCTION) {
114 uint32 val1, val2;
115 switch (op->info.iop.insn) {
116 case I_ADD:
117 case I_ADDU:
118 val1 = get_constant_value (list_headvalue (op->operands));
119 val2 = get_constant_value (list_tailvalue (op->operands));
120 op->status |= OP_STAT_CONSTANT;
121 temp.value = val1 + val2;
122 break;
123 case I_OR:
124 val1 = get_constant_value (list_headvalue (op->operands));
125 val2 = get_constant_value (list_tailvalue (op->operands));
126 op->status |= OP_STAT_CONSTANT;
127 temp.value = val1 | val2;
128 break;
129 default:
130 temp.status = VAR_STAT_NOTCONSTANT;
131 break;
137 if (temp.status != CONST_TYPE (var->status)) {
138 element useel;
139 useel = list_head (var->uses);
140 while (useel) {
141 struct operation *use = element_getvalue (useel);
142 if (use->type == OP_INSTRUCTION || use->type == OP_MOVE || use->type == OP_PHI) {
143 varel = list_head (use->results);
144 while (varel) {
145 val = element_getvalue (varel);
146 if (val->type == VAL_SSAVAR) {
147 aux = val->val.variable;
148 if (!(aux->mark)) {
149 aux->mark = 1;
150 list_inserttail (worklist, aux);
153 varel = element_next (varel);
156 useel = element_next (useel);
159 CONST_SETTYPE (var->status, temp.status);
160 var->value = temp.value;
163 list_free (worklist);
166 varel = list_head (sub->ssavars);
167 while (varel) {
168 struct ssavar *var = element_getvalue (varel);
169 struct operation *op = var->def;
170 element useel;
172 if (CONST_TYPE (var->status) == VAR_STAT_CONSTANT) {
173 op->status |= OP_STAT_DEFERRED;
174 useel = list_head (var->uses);
175 while (useel) {
176 struct operation *use = element_getvalue (useel);
177 if (use->type == OP_PHI) {
178 struct value *val = list_headvalue (use->results);
179 if (val->type != VAL_SSAVAR) break;
180 if (CONST_TYPE (val->val.variable->status) != VAR_STAT_CONSTANT)
181 break;
182 } else if (use->type == OP_ASM) break;
183 useel = element_next (useel);
185 if (useel) {
186 op->status &= ~OP_STAT_DEFERRED;
190 varel = element_next (varel);