gbdk-releases/sdcc/src/izt/aop.c
2015-01-10 16:25:09 +01:00

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;
}