Imported Upstream version 2.9.0
[debian/cc1111] / src / izt / aop.c
1 /** @file izt/aop.c
2     Assembler Operand support.
3 */
4 #include "izt.h"
5
6 asmop *_new(int type)
7 {
8     return NULL;
9 }
10
11 asmop *_newForLiteral(operand *op)
12 {
13     asmop *aop = _new(AOP_TYPE_LITERAL);
14     aop->u.literal = op->operand.valOperand;
15     aop->size = getSize(operandType(op));
16
17     return aop;
18 }
19
20 asmop *_newForSymbol(symbol *sym, iCode *ic)
21 {
22     memmap *space;
23     asmop *aop;
24
25     wassert(ic);
26     wassert(sym);
27     wassert(sym->etype);
28
29     space = SPEC_OCLS(sym->etype);
30
31     if (sym->aop != NULL) {
32         // Already has one.
33         aop = sym->aop;
34     }
35     else if (sym->onStack || sym->iaccess) {
36         // On the stack or only available by indirect access.
37         aop = _new(AOP_TYPE_STACK);
38         aop->size = getSize(sym->type);
39
40         aop->u.stack = sym->stack;
41     }
42     else if (IS_FUNC(sym->type)) {
43         // Functions are special.  The symbol is constant and available.
44         aop = _new(AOP_TYPE_IMMEDIATE);
45         aop->u.immediate = Safe_strdup(sym->rname);
46         // PENDING: Size of a function pointer.
47         aop->size = 2;
48     }
49     else {
50         // Somewhere in 'far' space.  ie only accessable through a pointer register.
51         aop = _new(AOP_TYPE_SCRATCH_PTR);
52         aop->size = getSize(sym->type);
53         aop->u.scratch = sym->rname;
54     }
55     
56     // Attach the asmop to the symbol.
57     sym->aop = aop;
58
59     return aop;     
60 }
61
62 asmop *_newForRemat(symbol *sym)
63 {
64     char *s = buffer;
65     iCode *ic = sym->rematiCode;
66     asmop *aop = _new(AOP_TYPE_IMMEDIATE);
67
68     // Terminate the string first up.
69     *s = '\0';
70
71     // Combine up any offsets.
72     while (ic->op == '+' || ic->op == '-') {
73         sprintf(s, "0x%04X %c ", (int)operandLitValue(IC_RIGHT(ic)), ic->op);
74         s += strlen(s);
75
76         ic = OP_SYMBOL(IC_LEFT(ic))->rematiCode;
77     }
78         
79     sprintf(s, "%s", OP_SYMBOL(IC_LEFT(ic))->rname);
80
81     aop->size = getSize(sym->type);
82     aop->u.immediate = Safe_strdup(buffer);
83     
84     return aop;
85 };
86
87 asmop *_newForTemporary(operand *op, iCode *ic)
88 {
89     symbol *sym = OP_SYMBOL(op);
90     asmop *aop = NULL;
91
92     if (sym->regType == REG_TYPE_CND) {
93         // Conditionals have no size due to being stored in carry.
94         aop = _new(AOP_TYPE_CARRY);
95         aop->size = 0;
96     }
97     else if (sym->isspilt || sym->nRegs == 0) {
98         // No registers so it must be somewhere on the stack or remat.
99         if (sym->remat) {
100             aop = _newForRemat(sym);
101         }
102         else if (sym->accuse) {
103             // Packed into one of the normally unavailable registers.
104             wassert(0);
105         }
106         else if (sym->ruonly) {
107             // Only used in the return.
108             wassert(0);
109         }
110         else {
111             // Must be spilt.
112             aop = _newForSymbol(sym->usl.spillLoc, ic);
113         }
114     }
115     else {
116         // Must be in registers.
117         aop = _new(AOP_TYPE_REG);
118         aop->size = sym->nRegs;
119         aop->u.reg = sym->regs[0];
120     }
121     // Attach to the op and symbol.
122     op->aop = aop;
123     sym->aop = aop;
124
125     return aop;
126 }
127
128 /** Bind a new AOP to the given operand.
129  */
130 void izt_bindAop(operand *op, iCode *ic)
131 {
132     if (op == NULL) {
133         // Do nothing.  Just return.
134     }
135     else if (IS_OP_LITERAL(op)) {
136         op->aop = _newForLiteral(op);
137     }
138     else if (op->aop != NULL) {
139         // It already has one allocated.  Use it.
140         // Do nothing.
141     }
142     else if (IS_SYMOP(op) && OP_SYMBOL(op)->aop != NULL) {
143         // The attached symbol already has an asmop.  Reuse it.
144         op->aop = OP_SYMBOL(op)->aop;
145     }
146     else if (IS_TRUE_SYMOP(op)) {
147         // Its a true symbol, so bind in a symbol asmop.
148         op->aop = _newForSymbol(OP_SYMBOL(op), ic);
149     }
150     else {
151         // A temporary.  Find where the temporary is stored and setup an asmop for it.
152         op->aop = _newForTemporary(op, ic);
153     }
154 }
155
156 /** Creates a new asmop that wraps the return value registers.
157  */
158 asmop *izt_getAopForReturn(int size)
159 {
160     asmop *aop = _new(AOP_TYPE_REG);
161     aop->size = size;
162     aop->u.reg = izt_port->returnRegs[izt_util_binLog(size)];
163
164     return aop;
165 }