static void assert2_pair_addresses_mapped( msgc_context_t *context, word w ) { { #ifndef NDEBUG2 if (isptr(pair_cdr(w)) && ! gc_is_address_mapped( context->gc, ptrof(pair_cdr(w)), FALSE )) { gc_is_address_mapped( context->gc, ptrof(pair_cdr(w)), TRUE ); consolemsg("unmapped address, pair 0x%08x in gen %d, cdr = 0x%08x", w, gen_of(w), pair_cdr(w)); consolemsg("(gno count: %d)", context->gc->gno_count); assert2(0); } if (isptr(pair_car(w)) && ! gc_is_address_mapped( context->gc, ptrof(pair_car(w)), FALSE )) { gc_is_address_mapped( context->gc, ptrof(pair_car(w)), TRUE ); consolemsg("unmapped address, pair 0x%08x in gen %d, car = 0x%08x", w, gen_of(w), pair_car(w)); consolemsg("(gno count: %d)", context->gc->gno_count); assert2(0); } #endif } }
static int compatible(Type ty1, Type ty2) { ty1 = unqual(ty1); ty2 = unqual(ty2); return isptr(ty1) && !isfunc(ty1->type) && isptr(ty2) && !isfunc(ty2->type) && eqtype(unqual(ty1->type), unqual(ty2->type), 0); }
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 Tree addtree(int op, Tree l, Tree r) { Type ty = inttype; if (isarith(l->type) && isarith(r->type)) { ty = binary(l->type, r->type); l = cast(l, ty); r = cast(r, ty); } else if (isptr(l->type) && isint(r->type)) return addtree(ADD, r, l); else if ( isptr(r->type) && isint(l->type) && !isfunc(r->type->type)) { long n; ty = unqual(r->type); n = unqual(ty->type)->size; if (n == 0) error("unknown size for type `%t'\n", ty->type); l = cast(l, promote(l->type)); if (n > 1) l = multree(MUL, cnsttree(signedptr, n), l); if (isunsigned(l->type)) l = cast(l, unsignedptr); else l = cast(l, signedptr); if (YYcheck && !isaddrop(r->op)) /* omit */ return nullcall(ty, YYcheck, r, l); /* omit */ return simplify(ADD, ty, l, r); } else typeerror(op, l, r); return simplify(op, ty, l, r); }
int isassignable(CTy *to, CTy *from) { if((isarithtype(to) || isptr(to)) && (isarithtype(from) || isptr(from))) return 1; if(compatiblestruct(to, from)) return 1; return 0; }
gint wr_equal_term(glb* g, gint x, gint y, int uniquestrflag) { gptr db; gint encx,ency; gptr xptr,yptr; int xlen,ylen,uselen,i,ilimit; gint eqencx; // used by the WR_EQUAL_TERM macro #ifdef DEBUG printf("wr_equal_term called with x %d and y %d\n",x,y); #endif // first check if immediately same: return 1 if yes if (x==y) return 1; // handle immediate check cases: for these bit suffixes x is equal to y iff x==y encx=(x&NORMALPTRMASK); if ((encx==LONGSTRBITS && uniquestrflag) || encx==SMALLINTBITS || encx==NORMALPTRMASK) return 0; // immediate value: must be unequal since x==y checked before if (!isptr(x) || !isptr(y)) return 0; // here both x and y are ptr types // quick type check: last two bits if (((x)&NONPTRBITS)!=((y)&NONPTRBITS)) return 0; // if one is datarec, the other must be as well if (!isdatarec(x)) { if (isdatarec(y)) return 0; // neither x nor y are datarecs // need to check pointed values if (wr_equal_ptr_primitives(g,x,y,uniquestrflag)) return 1; else return 0; } else { if (!isdatarec(y)) return 0; // both x and y are datarecs db=g->db; xptr=decode_record(db,x); yptr=decode_record(db,y); xlen=get_record_len(xptr); ylen=get_record_len(yptr); if (g->unify_samelen) { if (xlen!=ylen) return 0; uselen=xlen; } else { if (xlen<=ylen) uselen=xlen; else uselen=ylen; } if (g->unify_maxuseterms) { if (((g->unify_maxuseterms)+(g->unify_firstuseterm))<uselen) uselen=(g->unify_firstuseterm)+(g->unify_maxuseterms); } ilimit=RECORD_HEADER_GINTS+uselen; for(i=RECORD_HEADER_GINTS+(g->unify_firstuseterm); i<ilimit; i++) { encx=*(xptr+i); ency=*(yptr+i); if (!WR_EQUAL_TERM(g,encx,ency,uniquestrflag)) return 0; } return 1; } }
/* Simulation of new write barrier */ void C_simulate_new_barrier( void ) { word *genv; word lhs; word rhs; unsigned gl, gr; word **ssbtopv, **ssblimv; int isvec = 0; genv = (word*)globals[ G_GENV ]; lhs = globals[ G_RESULT ]; rhs = globals[ G_ARGREG2 ]; wb_total_assignments++; if (tagof(lhs) == VEC_TAG || tagof(lhs) == PROC_TAG) { isvec = 1; wb_array_assignments++; if (genv[pageof(lhs)] == 0) { wb_lhs_young_or_remembered++; return; } else if (gc_isremembered( the_gc(globals), lhs )) { wb_lhs_young_or_remembered++; return; } else if (!isptr( rhs )) { wb_rhs_constant++; return; } } else if (!isptr(rhs)) return; record_trans: gl = genv[pageof(lhs)]; gr = genv[pageof(rhs)]; if (gl <= gr) { if (isvec) wb_cross_gen_check++; /* not old->young */ return; } if (isvec) wb_trans_recorded++; ssbtopv = (word**)globals[G_SSBTOPV]; ssblimv = (word**)globals[G_SSBLIMV]; *ssbtopv[gl] = lhs; ssbtopv[gl] += 1; if (ssbtopv[gl] == ssblimv[gl]) C_wb_compact( gl ); }
/* subtree - construct tree for l - r */ static Tree subtree(int op, Tree l, Tree r) { long n; Type ty = inttype; if (isarith(l->type) && isarith(r->type)) { ty = binary(l->type, r->type); l = cast(l, ty); r = cast(r, ty); } else if (isptr(l->type) && !isfunc(l->type->type) && isint(r->type)) { ty = unqual(l->type); n = unqual(ty->type)->size; if (n == 0) error("unknown size for type `%t'\n", ty->type); r = cast(r, promote(r->type)); if (n > 1) r = multree(MUL, cnsttree(signedptr, n), r); if (isunsigned(r->type)) r = cast(r, unsignedptr); else r = cast(r, signedptr); return simplify(SUB+P, ty, l, r); } else if (compatible(l->type, r->type)) { ty = unqual(l->type); n = unqual(ty->type)->size; if (n == 0) error("unknown size for type `%t'\n", ty->type); l = simplify(SUB+U, unsignedptr, cast(l, unsignedptr), cast(r, unsignedptr)); return simplify(DIV+I, longtype, cast(l, longtype), cnsttree(longtype, n)); } else typeerror(op, l, r); return simplify(op, ty, l, r); }
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"); }
//set a 2 operand reg/??? instruction using the given bytes void AssemblyInstruction::setreg(int rtype, intptr_t regn, int type2, intptr_t val2, string ocbyteconstant, string ocbigconstant, int yy, string ocspecialconstant, string ocvalat) { //reg/constant if (type2 == TCONSTANT) { //EAX = AX = AL, all share the special if (regn == EAX && ocspecialconstant.length() > 0) { if (rtype == TREG8) bytes.assign(ocspecialconstant).append(1, (char)(val2)); else bytes.assign(ocspecialconstant).append(rtype == TREG16 ? to2bytes((int)(val2)) : to4bytes((int)(val2))); //byte constant with any reg } else if (rtype == TREG8 || (val2 >= -128 && val2 <= 127 && ocbyteconstant.compare("") != 0)) bytes.assign(ocbyteconstant).append(1, (char)(yy + regn)).append(1, (char)(val2)); //word or dword constant else bytes.assign(ocbigconstant).append(1, (char)(yy + regn)).append(rtype == TREG16 ? to2bytes((int)(val2)) : to4bytes((int)(val2))); //reg/reg } else if (isreg(type2)) bytes.assign(ocvalat).append(1, (char)(0xC0 + regn * 8 + val2)); //reg/ptr else if (isptr(type2)) bytes.assign(ocvalat).append(((MEMPTR*)(val2))->toptr(0, (char)(regn))); //reg/data ptr else if (isdataptr(type2)) { set(rtype, regn, ptrfromreg(rtype), blankdataptr); tag = TAGREGDATAPTR; tag2 = val2; tag3 = rtype; tag4 = regn; } }
/* Request is ignored -- doesn't make sense in nursery. */ static void collect( young_heap_t *heap, int nbytes, int request ) { young_data_t *data = DATA(heap); supremely_annoyingmsg( "nursery: promoting (free=%d; request=%d)%s", free_space( heap ), nbytes, (nbytes == 0 ? " [stack overflow]" : "" ) ); #if PROFILE_FOR_FAST_REMSET { word *p; word *globals = data->globals; for ( p=(word*)globals[G_EBOT]; p < (word*)globals[G_ETOP] ; p++ ) { nursery.words_scanned++; if ((((word)p ^ *p) & BLOCKMASK) == 0) nursery.fast_check_succeeds++; if (isptr(*p)) { nursery.ptrs_scanned++; if ((((word)p ^ *p) & BLOCKMASK) == 0) nursery.ptr_same_block++; } } } #endif /* Why did Lars pass 0 instead of nbytes below? */ gc_collect( heap->collector, data->gen_no, 0, GCTYPE_EVACUATE ); data->nbytes_wanted = nbytes; /* For use in after_collection() */ }
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 Node * mkunop(SrcPos *p, int op, Node *o) { Node *n; n = mknode(NUNOP, p); n->Unop.op = op; switch(op) { case '&': if(!islval(o)) errorposf(&o->pos, "& expects an lvalue"); n->type = mkptr(o->type); break; case '*': if(!isptr(o->type)) errorposf(&o->pos, "cannot deref non pointer"); n->type = o->type->Ptr.subty; break; default: o = ipromote(o); n->type = o->type; break; } n->Unop.operand = o; return n; }
void retcode(Tree p) { Type ty; if (p == NULL) { if (events.returns) apply(events.returns, cfunc, NULL); return; } p = pointer(p); ty = assign(freturn(cfunc->type), p); if (ty == NULL) { error("illegal return type; found `%t' expected `%t'\n", p->type, freturn(cfunc->type)); return; } p = cast(p, ty); if (retv) { if (iscallb(p)) p = tree(RIGHT, p->type, tree(CALL+B, p->type, p->kids[0]->kids[0], idtree(retv)), rvalue(idtree(retv))); else { Type ty = retv->type->type; assert(isstruct(ty)); if (ty->u.sym->u.s.cfields) { ty->u.sym->u.s.cfields = 0; p = asgntree(ASGN, rvalue(idtree(retv)), p); ty->u.sym->u.s.cfields = 1; } else p = asgntree(ASGN, rvalue(idtree(retv)), p); } walk(p, 0, 0); if (events.returns) apply(events.returns, cfunc, rvalue(idtree(retv))); return; } if (events.returns) { Symbol t1 = genident(AUTO, p->type, level); addlocal(t1); walk(asgn(t1, p), 0, 0); apply(events.returns, cfunc, idtree(t1)); p = idtree(t1); } if (!isfloat(p->type)) p = cast(p, promote(p->type)); if (isptr(p->type)) { Symbol q = localaddr(p); if (q && (q->computed || q->generated)) warning("pointer to a %s is an illegal return value\n", q->scope == PARAM ? "parameter" : "local"); else if (q) warning("pointer to %s `%s' is an illegal return value\n", q->scope == PARAM ? "parameter" : "local", q->name); } walk(tree(mkop(RET,p->type), p->type, p, NULL), 0, 0); }
static void assert2_root_address_mapped( msgc_context_t *context, word *loc ) { #ifndef NDEBUG2 if (isptr(*loc) && ! gc_is_address_mapped( context->gc, ptrof(*loc), FALSE )) { assert2(0); } #endif }
//set the DEC void DEC::set(int type, intptr_t val) { if (type == TREG32) bytes.assign(1, (char)(0x48 + val)); else if (type == TREG16) bytes.assign("\x66").append(1, (char)(0x48 + val)); else if (type == TREG8 || isptr(type)) setregptr(type, val, "\xFF", "\x66\xFF", "\xFE", 8); else if (isdataptr(type)) setdataptr(type, val); }
/* dbxout - output .stabs entry for type ty */ static void dbxout(Type ty) { ty = unqual(ty); if (!ty->x.printed) { int col = 0; print(".stabs \""), col += 8; if (ty->u.sym && !(isfunc(ty) || isarray(ty) || isptr(ty))) print("%s", ty->u.sym->name), col += strlen(ty->u.sym->name); print(":%c", isstruct(ty) || isenum(ty) ? 'T' : 't'), col += 2; emittype(ty, 0, col); print("\",%d,0,0,0\n", N_LSYM); } }
bool msgc_object_marked_p( msgc_context_t *context, word obj ) { word bit_idx, word_idx, bit; assert2( isptr( obj ) ); assert2( context->lowest_heap_address <= ptrof( obj ) && ptrof( obj ) < context->highest_heap_address ); bit_idx = (obj - (word)context->lowest_heap_address) >> BIT_IDX_SHIFT; word_idx = bit_idx >> BITS_TO_WORDS; bit = 1 << (bit_idx & BIT_IN_WORD_MASK); return (context->bitmap[ word_idx ] & bit); }
static void addr(Node *n) { int sz; int offset; Sym *sym; switch(n->t) { case NUNOP: expr(n->Unop.operand); break; case NSEL: expr(n->Sel.operand); if(isptr(n->Sel.operand->type)) offset = structoffsetfromname(n->Sel.operand->type->Ptr.subty, n->Sel.name); else if(isstruct(n->Sel.operand->type)) offset = structoffsetfromname(n->Sel.operand->type, n->Sel.name); else panic("internal error"); if(offset < 0) panic("internal error"); outi("addq $%d, %%rax\n", offset); break; case NIDENT: sym = n->Ident.sym; switch(sym->k) { case SYMGLOBAL: outi("leaq %s(%%rip), %%rax\n", sym->Global.label); break; case SYMLOCAL: outi("leaq %d(%%rbp), %%rax\n", sym->Local.slot->offset); break; default: panic("internal error"); } break; case NIDX: expr(n->Idx.idx); sz = n->type->size; if(sz != 1) { outi("imul $%d, %%rax\n", sz); } pushq("rax"); expr(n->Idx.operand); popq("rcx"); outi("addq %%rcx, %%rax\n"); break; default: errorf("unimplemented addr\n"); } }
static Tree addrtree(Tree e, long n, Type ty) { Symbol p = e->u.sym, q; if (p->scope == GLOBAL || p->sclass == STATIC || p->sclass == EXTERN) NEW0(q, PERM); else NEW0(q, FUNC); q->name = stringd(genlabel(1)); q->sclass = p->sclass; q->scope = p->scope; assert(isptr(ty) || isarray(ty)); q->type = isptr(ty) ? ty->type : ty; q->temporary = p->temporary; q->generated = p->generated; q->addressed = p->addressed; q->computed = 1; q->defined = 1; q->ref = 1; assert(IR->address); if (p->scope == GLOBAL || p->sclass == STATIC || p->sclass == EXTERN) { if (p->sclass == AUTO) q->sclass = STATIC; (*IR->address)(q, p, n); } else { Code cp; addlocal(p); cp = code(Address); cp->u.addr.sym = q; cp->u.addr.base = p; cp->u.addr.offset = n; } e = tree(e->op, ty, NULL, NULL); e->u.sym = q; return e; }
Tree asgntree(int op, Tree l, Tree r) { Type aty, ty; r = pointer(r); ty = assign(l->type, r); if (ty) r = cast(r, ty); else { typeerror(ASGN, l, r); if (r->type == voidtype) r = retype(r, inttype); ty = r->type; } if (l->op != FIELD) l = lvalue(l); aty = l->type; if (isptr(aty)) aty = unqual(aty)->type; if (isconst(aty) || (isstruct(aty) && unqual(aty)->u.sym->u.s.cfields)) { if (isaddrop(l->op) && !l->u.sym->computed && !l->u.sym->generated) error("assignment to const identifier `%s'\n", l->u.sym->name); else error("assignment to const location\n"); } if (l->op == FIELD) { long n = 8 * l->u.field->type->size - fieldsize(l->u.field); if (n > 0 && isunsigned(l->u.field->type)) r = bittree(BAND, r, cnsttree(r->type, (unsigned long)fieldmask(l->u.field))); else if (n > 0) { if (r->op == CNST + I) { n = r->u.v.i; if (n & (1 << (fieldsize(l->u.field) - 1))) n |= ~0UL << fieldsize(l->u.field); r = cnsttree(r->type, n); } else r = shtree(RSH, shtree(LSH, r, cnsttree(inttype, n)), cnsttree(inttype, n)); } } if (isstruct(ty) && isaddrop(l->op) && iscallb(r)) return tree(RIGHT, ty, tree(CALL + B, ty, r->kids[0]->kids[0], l), idtree(l->u.sym)); return tree(mkop(op, ty), ty, l, r); }
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 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 assert2_object_contents_mapped( msgc_context_t *context, word w, int n ) { #ifndef NDEBUG2 int i; for ( i=0 ; i < n ; i++ ) { if (isptr(vector_ref( w, i )) && ! gc_is_address_mapped( context->gc, ptrof(vector_ref( w, i )), FALSE )) { consolemsg("unmapped address, vector 0x%08x in gen %d, elem [%d] = 0x%08x", w, gen_of( w ), i, vector_ref( w, i )); consolemsg("(gno count: %d)", context->gc->gno_count); assert2(0); } } #endif }
StructMember * getstructmember(CTy *t, char *n) { int i; StructMember *sm; if(isptr(t)) t = t->Ptr.subty; if(!isstruct(t)) panic("internal error"); for(i = 0; i < t->Struct.members->len; i++) { sm = vecget(t->Struct.members, i); if(strcmp(n, sm->name) == 0) return sm; } return 0; }
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"); }
/* stabsym - output a stab entry for symbol p */ void stabsym(Symbol p) { int code, tc, sz = p->type->size; if (p->generated || p->computed) return; if (isfunc(p->type)) { print(".stabs \"%s:%c%d\",%d,0,0,%s\n", p->name, p->sclass == STATIC ? 'f' : 'F', dbxtype(freturn(p->type)), N_FUN, p->x.name); return; } if (!IR->wants_argb && p->scope == PARAM && p->structarg) { assert(isptr(p->type) && isstruct(p->type->type)); tc = dbxtype(p->type->type); sz = p->type->type->size; } else tc = dbxtype(p->type); if (p->sclass == AUTO && p->scope == GLOBAL || p->sclass == EXTERN) { print(".stabs \"%s:G", p->name); code = N_GSYM; } else if (p->sclass == STATIC) { print(".stabs \"%s:%c%d\",%d,0,0,%s\n", p->name, p->scope == GLOBAL ? 'S' : 'V', tc, p->u.seg == BSS ? N_LCSYM : N_STSYM, p->x.name); return; } else if (p->sclass == REGISTER) { if (p->x.regnode) { int r = p->x.regnode->number; if (p->x.regnode->set == FREG) r += 32; /* floating point */ print(".stabs \"%s:%c%d\",%d,0,", p->name, p->scope == PARAM ? 'P' : 'r', tc, N_RSYM); print("%d,%d\n", sz, r); } return; } else if (p->scope == PARAM) { print(".stabs \"%s:p", p->name); code = N_PSYM; } else if (p->scope >= LOCAL) { print(".stabs \"%s:", p->name); code = N_LSYM; } else assert(0); print("%d\",%d,0,0,%s\n", tc, code, p->scope >= PARAM && p->sclass != EXTERN ? p->x.name : "0"); }