int canrepresent(CTy *l, CTy *r) { if(!isitype(l) || !isitype(r)) panic("internal error"); return getmaxval(l) <= getmaxval(r) && getminval(l) >= getminval(r); }
static void incdec(Node *n) { if(!isitype(n->type) && !isptr(n->type)) panic("unimplemented incdec"); addr(n->Incdec.operand); pushq("rax"); load(n->type); if(isptr(n->type)) { if(n->Incdec.op == TOKINC) outi("add $%d, %%rax\n", n->type->Ptr.subty->size); else outi("add $%d, %%rax\n", -n->type->Ptr.subty->size); } else { if(n->Incdec.op == TOKINC) outi("inc %%rax\n"); else outi("dec %%rax\n"); } outi("movq %%rax, %%rcx\n"); popq("rax"); store(n->type); outi("movq %%rcx, %%rax\n"); if(n->Incdec.post == 1) { if(n->Incdec.op == TOKINC) outi("dec %%rax\n"); else outi("inc %%rax\n"); } }
static void assign(Node *n) { Node *l, *r; int op; op = n->Assign.op; l = n->Assign.l; r = n->Assign.r; if(op == '=') { expr(r); pushq("rax"); addr(l); popq("rcx"); if(!isptr(l->type) && !isitype(l->type) && !isstruct(l->type)) errorf("unimplemented assign\n"); store(l->type); outi("movq %%rcx, %%rax\n"); return; } addr(l); pushq("rax"); load(l->type); pushq("rax"); expr(r); outi("movq %%rax, %%rcx\n"); popq("rax"); /* XXX this type is not correct for comparison ops works anyway, but should be changed*/ obinop(op, n->type); outi("movq %%rax, %%rcx\n"); popq("rax"); store(l->type); outi("movq %%rcx, %%rax\n"); }
static void load(CTy *t) { if(isitype(t) || isptr(t)) { switch(t->size) { case 8: outi("movq (%%rax), %%rax\n"); break; case 4: outi("movslq (%%rax), %%rax\n"); break; case 2: outi("movswq (%%rax), %%rax\n"); break; case 1: outi("movsbq (%%rax), %%rax\n"); break; default: panic("internal error\n"); } return; } if(isstruct(t)) { return; } if(isarray(t)) { return; } if(isfunc(t)) { return; } errorf("unimplemented load %d\n", t->t); }
static void call(Node *n) { int i, nargs, nintargs, cleanup; Vec *args; Node *arg; args = n->Call.args; i = nargs = args->len; /* Push args in reverse order */ while(i-- != 0) { arg = vecget(args, i); if(!isitype(arg->type) && !isptr(arg->type) && !isarray(arg->type) && !isfunc(arg->type)) errorposf(&arg->pos, "unimplemented arg type\n"); expr(arg); pushq("rax"); } nintargs = nargs; if(nintargs > 6) nintargs = 6; for(i = 0; i < nintargs; i++) popq(intargregs[i]); expr(n->Call.funclike); outi("call *%%rax\n"); cleanup = 8 * (nargs - nintargs); if(cleanup) { outi("add $%d, %%rsp\n", cleanup); stackoffset -= cleanup; } }
void emitsym(Sym *sym) { out("# emit sym %s\n", sym->name); switch(sym->k){ case SYMGLOBAL: if(sym->Global.sclass == SCEXTERN) break; if(isfunc(sym->type)) { func(sym->init, sym->Global.label, sym->Global.sclass == SCGLOBAL); break; } penddata(sym->Global.label, sym->type, sym->init, sym->Global.sclass == SCGLOBAL); break; case SYMLOCAL: if(sym->init) { expr(sym->init); pushq("rax"); outi("leaq %d(%%rbp), %%rax\n", sym->Local.slot->offset); popq("rcx"); if(!isptr(sym->type) && !isitype(sym->type) && !isstruct(sym->type)) errorf("unimplemented init\n"); store(sym->type); } break; case SYMENUM: case SYMTYPE: panic("internal error"); } out("\n"); }
static void data(Data *d) { InitMember *initmemb; int i, offset; char *l; if(!d->init) { out(".comm %s, %d, %d\n", d->label, d->type->size, d->type->align); return; } if(d->isglobal) out(".globl %s\n", d->label); out("%s:\n", d->label); if(ischararray(d->type)) if(d->init->t == NSTR) { out(".string %s\n", d->init->Str.v); return; } if(ischarptr(d->type)) if(d->init->t == NSTR) { l = newlabel(); out(".quad %s\n", l); out("%s:\n", l); out(".string %s\n", d->init->Str.v); return; } if(isitype(d->type) || isptr(d->type)) { itypedata(d->init); return; } if(isarray(d->type) || isstruct(d->type)) { if(d->init->t != NINIT) errorposf(&d->init->pos, "array/struct expects a '{' style initializer"); offset = 0; for(i = 0; i < d->init->Init.inits->len ; i++) { initmemb = vecget(d->init->Init.inits, i); if(initmemb->offset != offset) out(".fill %d, 1, 0\n", initmemb->offset - offset); itypedata(initmemb->n); offset = initmemb->offset + initmemb->n->type->size; } if(offset < d->type->size) out(".fill %d, 1, 0\n", d->type->size - offset); return; } panic("internal error"); }
static void cast(Node *n) { CTy *from; CTy *to; expr(n->Cast.operand); from = n->Cast.operand->type; to = n->type; if(isptr(from) && isptr(to)) return; if(isptr(to) && isitype(from)) return; if(isptr(from) && isitype(to)) return; if(isitype(from) && isitype(to)) return; if(isfunc(from) && isptr(to)) return; if(isarray(from) && isptr(to)) return; errorf("unimplemented cast %d %d\n", from->t, to->t); }
static Node * ipromote(Node *n) { if(!isitype(n->type)) errorposf(&n->pos, "internal error - ipromote expects itype got %d", n->type->t); switch(n->type->Prim.type) { case PRIMCHAR: case PRIMSHORT: if(n->type->Prim.issigned) return mkcast(&n->pos, n, cint); else return mkcast(&n->pos, n, cuint); } return n; }
static void ereturn(Node *r) { CTy *ty; if(r->Return.expr) { ty = r->Return.expr->type; if(!isitype(ty) && !isptr(ty)) errorposf(&r->pos, "unimplemented return type"); expr(r->Return.expr); } /* No need to cleanup with leave */ outi("leave\n"); outi("ret\n"); }
static void func(Node *f, char *label, int isglobal) { Vec *v; Sym *sym; int i; calcslotoffsets(f); out("\n"); out(".text\n"); out("# function %s\n", f->Func.name); if(isglobal) out(".globl %s\n", label); out("%s:\n", label); pushq("rbp"); outi("movq %%rsp, %%rbp\n"); if(f->type->Func.isvararg) { stackoffset += 176; outi("sub $176, %%rsp\n"); outi("movq %%rdi, (%%rsp)\n"); outi("movq %%rsi, 8(%%rsp)\n"); outi("movq %%rdx, 16(%%rsp)\n"); outi("movq %%rcx, 24(%%rsp)\n"); outi("movq %%r8, 32(%%rsp)\n"); outi("movq %%r9, 40(%%rsp)\n"); } if(f->Func.localsz) { outi("sub $%d, %%rsp\n", f->Func.localsz); stackoffset += f->Func.localsz; } v = f->Func.params; for(i = 0; i < v->len; i++) { sym = vecget(v, i); if(!isitype(sym->type) && !isptr(sym->type) && !isarray(sym->type)) errorposf(&f->pos, "unimplemented arg type"); if(i < 6) { outi("movq %%%s, %d(%%rbp)\n", intargregs[i], sym->Local.slot->offset); } else { outi("movq %d(%%rbp), %%rcx\n", 16 + 8 * (i - 6)); outi("leaq %d(%%rbp), %%rax\n", sym->Local.slot->offset); store(sym->type); } } block(f->Func.body); outi("leave\n"); outi("ret\n"); }
static void itypedata(Node *prim) { Const *c; if(!isitype(prim->type) && !isptr(prim->type)) panic("internal error %d"); c = foldexpr(prim); if(!c) errorposf(&prim->pos, "not a constant expression"); if(c->p) { switch(prim->type->size) { case 8: out(".quad %s + %d\n", c->p, c->v); return; case 4: out(".long %s + %d\n", c->p, c->v); return; case 2: out(".short %s + %d\n", c->p, c->v); return; case 1: out(".byte %s + %d\n", c->p, c->v); return; default: panic("unimplemented"); } } switch(prim->type->size) { case 8: out(".quad %d\n", c->v); return; case 4: out(".long %d\n", c->v); return; case 2: out(".short %d\n", c->v); return; case 1: out(".byte %d\n", c->v); return; default: panic("unimplemented"); } panic("internal error"); }
static void cond(Node *n) { char *lfalse, *lend; if(!isitype(n->type) && !isptr(n->type)) panic("unimplemented emit cond"); expr(n->Cond.cond); lfalse = newlabel(); lend = newlabel(); outi("test %%rax, %%rax\n"); outi("jz %s\n", lfalse); expr(n->Cond.iftrue); outi("jmp %s\n", lend); out("%s:\n", lfalse); expr(n->Cond.iffalse); out("%s:\n", lend); }
static void store(CTy *t) { if(isitype(t) || isptr(t)) { switch(t->size) { case 8: outi("movq %%rcx, (%%rax)\n"); break; case 4: outi("movl %%ecx, (%%rax)\n"); break; case 2: outi("movw %%cx, (%%rax)\n"); break; case 1: outi("movb %%cl, (%%rax)\n"); break; default: panic("internal error\n"); } return; } if(isstruct(t)) { pushq("rdi"); pushq("rsi"); pushq("rcx"); outi("movq %%rcx, %%rsi\n"); outi("movq %%rax, %%rdi\n"); outi("movq $%d, %%rcx\n", t->size); outi("rep movsb\n"); popq("rcx"); popq("rsi"); popq("rdi"); return; } errorf("unimplemented store\n"); }
static void obinop(int op, CTy *t) { char *lset; char *lafter; char *opc; if(!isitype(t) && !isptr(t)) panic("unimplemented binary operator type\n"); switch(op) { case '+': outi("addq %%rcx, %%rax\n"); break; case '-': outi("subq %%rcx, %%rax\n"); break; case '*': outi("imul %%rcx, %%rax\n"); break; case '/': outi("cqto\n"); outi("idiv %%rcx\n"); break; case '%': outi("cqto\n"); outi("idiv %%rcx\n"); outi("mov %%rdx, %%rax\n"); break; case '|': outi("or %%rcx, %%rax\n"); break; case '&': outi("and %%rcx, %%rax\n"); break; case '^': outi("xor %%rcx, %%rax\n"); break; case TOKSHR: outi("sar %%cl, %%rax\n"); break; case TOKSHL: outi("sal %%cl, %%rax\n"); break; case TOKEQL: case TOKNEQ: case TOKGEQ: case TOKLEQ: case '>': case '<': lset = newlabel(); lafter = newlabel(); switch(op) { case TOKEQL: opc = "jz"; break; case TOKNEQ: opc = "jnz"; break; case '<': opc = "jl"; break; case '>': opc = "jg"; break; case TOKGEQ: opc = "jge"; break; case TOKLEQ: opc = "jle"; break; } outi("cmp %%rcx, %%rax\n"); outi("%s %s\n", opc, lset); outi("movq $0, %%rax\n"); outi("jmp %s\n", lafter); out("%s:\n", lset); outi("movq $1, %%rax\n"); out("%s:\n", lafter); break; default: errorf("unimplemented binop %d\n", op); } }
int isarithtype(CTy *t) { return isftype(t) || isitype(t); }