166 lines
3.6 KiB
C
166 lines
3.6 KiB
C
/** @file izt/aop.c
|
|
Assembler Operand support.
|
|
*/
|
|
#include "izt.h"
|
|
|
|
asmop *_new(int type)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
asmop *_newForLiteral(operand *op)
|
|
{
|
|
asmop *aop = _new(AOP_TYPE_LITERAL);
|
|
aop->u.literal = op->operand.valOperand;
|
|
aop->size = getSize(operandType(op));
|
|
|
|
return aop;
|
|
}
|
|
|
|
asmop *_newForSymbol(symbol *sym, iCode *ic)
|
|
{
|
|
memmap *space;
|
|
asmop *aop;
|
|
|
|
wassert(ic);
|
|
wassert(sym);
|
|
wassert(sym->etype);
|
|
|
|
space = SPEC_OCLS(sym->etype);
|
|
|
|
if (sym->aop != NULL) {
|
|
// Already has one.
|
|
aop = sym->aop;
|
|
}
|
|
else if (sym->onStack || sym->iaccess) {
|
|
// On the stack or only available by indirect access.
|
|
aop = _new(AOP_TYPE_STACK);
|
|
aop->size = getSize(sym->type);
|
|
|
|
aop->u.stack = sym->stack;
|
|
}
|
|
else if (IS_FUNC(sym->type)) {
|
|
// Functions are special. The symbol is constant and available.
|
|
aop = _new(AOP_TYPE_IMMEDIATE);
|
|
aop->u.immediate = Safe_strdup(sym->rname);
|
|
// PENDING: Size of a function pointer.
|
|
aop->size = 2;
|
|
}
|
|
else {
|
|
// Somewhere in 'far' space. ie only accessable through a pointer register.
|
|
aop = _new(AOP_TYPE_SCRATCH_PTR);
|
|
aop->size = getSize(sym->type);
|
|
aop->u.scratch = sym->rname;
|
|
}
|
|
|
|
// Attach the asmop to the symbol.
|
|
sym->aop = aop;
|
|
|
|
return aop;
|
|
}
|
|
|
|
asmop *_newForRemat(symbol *sym)
|
|
{
|
|
char *s = buffer;
|
|
iCode *ic = sym->rematiCode;
|
|
asmop *aop = _new(AOP_TYPE_IMMEDIATE);
|
|
|
|
// Terminate the string first up.
|
|
*s = '\0';
|
|
|
|
// Combine up any offsets.
|
|
while (ic->op == '+' || ic->op == '-') {
|
|
sprintf(s, "0x%04X %c ", (int)operandLitValue(IC_RIGHT(ic)), ic->op);
|
|
s += strlen(s);
|
|
|
|
ic = OP_SYMBOL(IC_LEFT(ic))->rematiCode;
|
|
}
|
|
|
|
sprintf(s, "%s", OP_SYMBOL(IC_LEFT(ic))->rname);
|
|
|
|
aop->size = getSize(sym->type);
|
|
aop->u.immediate = Safe_strdup(buffer);
|
|
|
|
return aop;
|
|
};
|
|
|
|
asmop *_newForTemporary(operand *op, iCode *ic)
|
|
{
|
|
symbol *sym = OP_SYMBOL(op);
|
|
asmop *aop = NULL;
|
|
|
|
if (sym->regType == REG_TYPE_CND) {
|
|
// Conditionals have no size due to being stored in carry.
|
|
aop = _new(AOP_TYPE_CARRY);
|
|
aop->size = 0;
|
|
}
|
|
else if (sym->isspilt || sym->nRegs == 0) {
|
|
// No registers so it must be somewhere on the stack or remat.
|
|
if (sym->remat) {
|
|
aop = _newForRemat(sym);
|
|
}
|
|
else if (sym->accuse) {
|
|
// Packed into one of the normally unavailable registers.
|
|
wassert(0);
|
|
}
|
|
else if (sym->ruonly) {
|
|
// Only used in the return.
|
|
wassert(0);
|
|
}
|
|
else {
|
|
// Must be spilt.
|
|
aop = _newForSymbol(sym->usl.spillLoc, ic);
|
|
}
|
|
}
|
|
else {
|
|
// Must be in registers.
|
|
aop = _new(AOP_TYPE_REG);
|
|
aop->size = sym->nRegs;
|
|
aop->u.reg = sym->regs[0];
|
|
}
|
|
// Attach to the op and symbol.
|
|
op->aop = aop;
|
|
sym->aop = aop;
|
|
|
|
return aop;
|
|
}
|
|
|
|
/** Bind a new AOP to the given operand.
|
|
*/
|
|
void izt_bindAop(operand *op, iCode *ic)
|
|
{
|
|
if (op == NULL) {
|
|
// Do nothing. Just return.
|
|
}
|
|
else if (IS_OP_LITERAL(op)) {
|
|
op->aop = _newForLiteral(op);
|
|
}
|
|
else if (op->aop != NULL) {
|
|
// It already has one allocated. Use it.
|
|
// Do nothing.
|
|
}
|
|
else if (IS_SYMOP(op) && OP_SYMBOL(op)->aop != NULL) {
|
|
// The attached symbol already has an asmop. Reuse it.
|
|
op->aop = OP_SYMBOL(op)->aop;
|
|
}
|
|
else if (IS_TRUE_SYMOP(op)) {
|
|
// Its a true symbol, so bind in a symbol asmop.
|
|
op->aop = _newForSymbol(OP_SYMBOL(op), ic);
|
|
}
|
|
else {
|
|
// A temporary. Find where the temporary is stored and setup an asmop for it.
|
|
op->aop = _newForTemporary(op, ic);
|
|
}
|
|
}
|
|
|
|
/** Creates a new asmop that wraps the return value registers.
|
|
*/
|
|
asmop *izt_getAopForReturn(int size)
|
|
{
|
|
asmop *aop = _new(AOP_TYPE_REG);
|
|
aop->size = size;
|
|
aop->u.reg = izt_port->returnRegs[izt_util_binLog(size)];
|
|
|
|
return aop;
|
|
}
|