static struct symtab * addstr(char *n) { NODE *p = block(NAME, NIL, NIL, FLOAT, 0, 0); struct symtab *sp; NODE *q; struct attr *ap; struct rstack *rp; extern struct rstack *rpole; p->n_type = ctype(ULONGLONG); rpole = rp = bstruct(NULL, STNAME, NULL); soumemb(p, loti, 0); soumemb(p, hiti, 0); q = dclstruct(rp); sp = q->n_sp = lookup(addname(n), 0); defid(q, TYPEDEF); ap = attr_new(GCC_ATYP_MODE, 3); ap->sarg(0) = addname("TI"); ap->iarg(1) = 0; sp->sap = attr_add(sp->sap, ap); nfree(q); nfree(p); return sp; }
/* * The "initial exec" tls model. */ static NODE * tlsinitialexec(NODE *p) { NODE *q, *r, *s; char *s1, *s2; /* * movq %fs:0,%rax * addq x@GOTTPOFF(%rip),%rax */ q = bcon(0); q->n_type = STRTY; s = ccopy(r = tempnode(0, INCREF(p->n_type), p->n_df, p->n_ap)); r = mkx("=r", r); r = block(XASM, r, q, INT, 0, 0); s1 = "movq %%fs:0,%0\n\taddq "; s2 = "@GOTTPOFF(%%rip),%0"; if (attr_find(p->n_sp->sap, ATTR_SONAME) == NULL) { p->n_sp->sap = attr_add(p->n_sp->sap, attr_new(ATTR_SONAME, 1)); p->n_sp->sap->sarg(0) = p->n_sp->sname; } r->n_name = mk3str(s1, attr_find(p->n_sp->sap, ATTR_SONAME)->sarg(0), s2); r = block(COMOP, r, s, INCREF(p->n_type), p->n_df, p->n_ap); r = buildtree(UMUL, r, NIL); tfree(p); return r; }
/* * Declare a namespace. */ void dclns(NODE *attr, char *n) { struct symtab *sp; struct attr *ap = gcc_attr_parse(attr); if (cppdebug)printf("declaring namespace %s\n", n); n = addname(n); sp = sfind(n, nscur->sup); while (sp != NULL) { if (sp->sname == n && sp->sclass == NSPACE) break; sp = sfind(n, sp->snext); } if (sp == NULL) { /* New namespace */ sp = getsymtab(n, 0); sp->sclass = NSPACE; INSSYM(sp); } nscur = sp; if (cppdebug)printf("declaring namespace2 %s\n", nscur->sname); sp->sap = attr_add(sp->sap, ap); /* XXX check attributes */ }
void myp2tree(NODE *p) { struct attr *ap; struct symtab *sp, sps; static int dblxor, fltxor; int codeatyp(NODE *); if (p->n_op == STCALL || p->n_op == USTCALL) { /* save struct encoding */ p->n_ap = attr_add(p->n_ap, ap = attr_new(ATTR_AMD64_CMPLRET, 1)); ap->iarg(0) = codeatyp(p); } if (p->n_op == UMINUS && (p->n_type == FLOAT || p->n_type == DOUBLE)) { /* Store xor code for sign change */ if (dblxor == 0) { dblxor = getlab(); fltxor = getlab(); sps.stype = LDOUBLE; sps.squal = CON >> TSHIFT; sps.sflags = sps.sclass = 0; sps.sname = ""; sps.slevel = 1; sps.sap = NULL; sps.soffset = dblxor; locctr(DATA, &sps); defloc(&sps); printf("\t.long 0,0x80000000,0,0\n"); printf(LABFMT ":\n", fltxor); printf("\t.long 0x80000000,0,0,0\n"); } p->n_ap = attr_add(p->n_ap, ap = attr_new(ATTR_AMD64_XORLBL, 1)); ap->iarg(0) = p->n_type == FLOAT ? fltxor : dblxor; return; }
/* * Check if we may have to do a cast to/from TI. */ NODE * gcc_eval_ticast(int op, NODE *p1, NODE *p2) { struct attr *a1, *a2; int t; a2 = NULL; /* XXX flow analysis */ if ((a1 = isti(p1)) == NULL && (a2 = isti(p2)) == NULL) return NIL; if (op == RETURN) p1 = p1tcopy(p1); if (a1 == NULL) { if (a2 == NULL) cerror("gcc_eval_ticast error"); switch (p1->n_type) { case LDOUBLE: p2 = doacall(floatuntixfsp, nametree(floatuntixfsp), p2); tfree(p1); break; case ULONG: case LONG: p2 = cast(structref(p2, DOT, loti), p1->n_type, 0); tfree(p1); break; case VOID: return NIL; default: uerror("gcc_eval_ticast: %d", p1->n_type); } return p2; } /* p2 can be anything, but we must cast it to p1 */ t = a1->iarg(1); if (p2->n_type == STRTY && (a2 = attr_find(p2->n_ap, GCC_ATYP_MODE)) && strcmp(a2->sarg(0), TISTR) == 0) { /* Already TI, just add extra mode bits */ a2 = attr_new(GCC_ATYP_MODE, 3); a2->sarg(0) = TISTR; a2->iarg(1) = t; p2->n_ap = attr_add(p2->n_ap, a2); } else { p2 = ticast(p2, t); } tfree(p1); return p2; }
/* * Called when a identifier has been declared. */ void fixdef(struct symtab *sp) { struct attr *ga; #ifdef HAVE_WEAKREF /* not many as'es have this directive */ if ((ga = attr_find(sp->sap, GCC_ATYP_WEAKREF)) != NULL) { char *wr = ga->sarg(0); char *sn = getsoname(sp); if (wr == NULL) { if ((ga = attr_find(sp->sap, GCC_ATYP_ALIAS))) { wr = ga->sarg(0); } } if (wr == NULL) printf("\t.weak %s\n", sn); else printf("\t.weakref %s,%s\n", sn, wr); } else if ((ga = attr_find(sp->sap, GCC_ATYP_ALIAS)) != NULL) { char *an = ga->sarg(0); char *sn = getsoname(sp); char *v; v = attr_find(sp->sap, GCC_ATYP_WEAK) ? "weak" : "globl"; printf("\t.%s %s\n", v, sn); printf("\t.set %s,%s\n", sn, an); } if (alias != NULL && (sp->sclass != PARAM)) { char *name = getexname(sp); printf("\t.globl %s\n", name); printf("%s = ", name); printf("%s\n", exname(alias)); alias = NULL; } if ((constructor || destructor) && (sp->sclass != PARAM)) { NODE *p = p1alloc(); p->n_op = NAME; p->n_sp = (struct symtab *)(constructor ? "constructor" : "destructor"); sp->sap = attr_add(sp->sap, gcc_attr_parse(p)); constructor = destructor = 0; } #endif }
/* * Create a reference for a TLS variable. * This is the "General dynamic" version. */ static NODE * tlspic(NODE *p) { NODE *q, *r, *s; char *s1, *s2; /* * .byte 0x66 * leaq x@TLSGD(%rip),%rdi * .word 0x6666 * rex64 * call __tls_get_addr@PLT */ /* Need the .byte stuff around. Why? */ /* Use inline assembler */ q = mkx("%rdx", bcon(0)); q = cmop(q, mkx("%rcx", bcon(0))); q = cmop(q, mkx("%rsi", bcon(0))); q = cmop(q, mkx("%rdi", bcon(0))); q = cmop(q, mkx("%r8", bcon(0))); q = cmop(q, mkx("%r9", bcon(0))); q = cmop(q, mkx("%r10", bcon(0))); q = cmop(q, mkx("%r11", bcon(0))); s = ccopy(r = tempnode(0, INCREF(p->n_type), p->n_df, p->n_ap)); r = mkx("=a", r); r = block(XASM, r, q, INT, 0, 0); /* Create the magic string */ s1 = ".byte 0x66\n\tleaq "; s2 = "@TLSGD(%%rip),%%rdi\n" "\t.word 0x6666\n\trex64\n\tcall __tls_get_addr@PLT"; if (attr_find(p->n_sp->sap, ATTR_SONAME) == NULL) { p->n_sp->sap = attr_add(p->n_sp->sap, attr_new(ATTR_SONAME, 1)); p->n_sp->sap->sarg(0) = p->n_sp->sname; } r->n_name = addstring(mk3str(s1, attr_find(p->n_sp->sap, ATTR_SONAME)->sarg(0), s2)); r = block(COMOP, r, s, INCREF(p->n_type), p->n_df, p->n_ap); r = buildtree(UMUL, r, NIL); tfree(p); return r; }
/* * Extract attributes from a node tree and return attribute entries * based on its contents. */ struct attr * gcc_attr_parse(NODE *p) { struct attr *b, *c; if (p == NIL) return NULL; if (p->n_op != CM) { b = gcc_attribs(p); tfree(p); } else { b = gcc_attr_parse(p->n_left); c = gcc_attr_parse(p->n_right); nfree(p); b = b ? attr_add(b, c) : c; } return b; }
SLPError generic_set_val(struct xx_SLPAttributes *slp_attr, const char *tag, value_t *value, SLPInsertionPolicy policy, SLPType attr_type) /* Finds and sets the value named in tag. */ /* * slp_attr - The attr object to add to. * tag - the name of the tag to add to. * value - the already-allocated value object with fields set * policy - the policy to use when inserting. * attr_type - the type of the value being added. *****************************************************************************/ { var_t *var; /***** Create a new attribute. *****/ if ( (var = attr_val_find_str(slp_attr, tag)) == NULL) { /*** Couldn't find a value with this tag. Make a new one. ***/ var = var_new((char *)tag); if (var == NULL) { return SLP_MEMORY_ALLOC_FAILED; } var->type = attr_type; /** Add variable to list. **/ attr_add(slp_attr, var); } else { SLPError err; /*** The attribute already exists. ***/ /*** Verify type. ***/ err = attr_type_verify(slp_attr, var, attr_type); if (err == SLP_TYPE_ERROR && policy == SLP_REPLACE) { var_list_destroy(var); var->type = attr_type; } else if (err != SLP_OK) { value_free(value); return err; } } /***** Set value *****/ var_insert(var, value, policy); return SLP_OK; }
/* * Create a reference for an extern variable. */ static P1ND * picext(P1ND *p) { struct attr *ap; #if defined(ELFABI) P1ND *q, *r; struct symtab *sp; char *name; q = tempnode(gotnr, PTR|VOID, 0, 0); name = getexname(p->n_sp); #ifdef GCC_COMPAT if ((ap = attr_find(p->n_sp->sap, GCC_ATYP_VISIBILITY)) && strcmp(ap->sarg(0), "hidden") == 0) { /* For hidden vars use GOTOFF */ sp = picsymtab("", name, "@GOTOFF"); r = xbcon(0, sp, INT); q = buildtree(PLUS, q, r); q = block(UMUL, q, 0, p->n_type, p->n_df, p->n_ap); q->n_sp = p->n_sp; /* for init */ p1nfree(p); return q; } #endif sp = picsymtab("", name, "@GOT"); #ifdef GCC_COMPAT if (attr_find(p->n_sp->sap, GCC_ATYP_STDCALL) != NULL) p->n_sp->sflags |= SSTDCALL; #endif sp->sflags = p->n_sp->sflags & SSTDCALL; sp->sap = attr_add(p->n_sp->sap, sp->sap); r = xbcon(0, sp, INT); q = buildtree(PLUS, q, r); q = block(UMUL, q, 0, PTR|VOID, 0, 0); q = block(UMUL, q, 0, p->n_type, p->n_df, p->n_ap); q->n_sp = p->n_sp; /* for init */ p1nfree(p); return q; #elif defined(MACHOABI) P1ND *q, *r; struct symtab *sp; char buf2[256], *name, *pspn; name = getsoname(cftnsp); pspn = getexname(p->n_sp); if (p->n_sp->sclass == EXTDEF) { snprintf(buf2, 256, "-L%s$pb", name); sp = picsymtab("", pspn, buf2); } else { snprintf(buf2, 256, "$non_lazy_ptr-L%s$pb", name); sp = picsymtab("L", pspn, buf2); addstub(&nlplist, pspn); } sp->stype = p->n_sp->stype; q = tempnode(gotnr, PTR+VOID, 0, 0); r = xbcon(0, sp, INT); q = buildtree(PLUS, q, r); if (p->n_sp->sclass != EXTDEF) q = block(UMUL, q, 0, PTR+VOID, 0, 0); q = block(UMUL, q, 0, p->n_type, p->n_df, p->n_ap); q->n_sp = p->n_sp; /* for init */ p1nfree(p); return q; #else /* defined(PECOFFABI) || defined(AOUTABI) */ return p; #endif }
/* * Parse attributes from an argument list. */ static void gcc_attribs(NODE *p, void *arg) { NODE *q, *r; struct attr *apo = arg, *ap; char *name = NULL, *c; int cw, attr, narg, i; if (p->n_op == NAME) { name = (char *)p->n_sp; } else if (p->n_op == CALL || p->n_op == UCALL) { name = (char *)p->n_left->n_sp; } else cerror("bad variable attribute"); if ((attr = amatch(name, atax, GCC_ATYP_MAX)) == 0) { werror("unsupported attribute '%s'", name); goto out; } narg = 0; if (p->n_op == CALL) for (narg = 1, q = p->n_right; q->n_op == CM; q = q->n_left) narg++; cw = atax[attr].typ; if (!(cw & A_MANY) && ((narg > 3) || ((cw & (1 << narg)) == 0))) { uerror("wrong attribute arg count"); return; } ap = attr_new(attr, 3); /* XXX should be narg */ apo->next = attr_add(apo->next, ap); q = p->n_right; switch (narg) { default: /* XXX */ while (narg-- > 3) { r = q; q = q->n_left; tfree(r->n_right); nfree(r); } /* FALLTHROUGH */ case 3: setaarg(cw & (A3_NAME|A3_STR), &ap->aa[2], q->n_right); r = q; q = q->n_left; nfree(r); /* FALLTHROUGH */ case 2: setaarg(cw & (A2_NAME|A2_STR), &ap->aa[1], q->n_right); r = q; q = q->n_left; nfree(r); /* FALLTHROUGH */ case 1: setaarg(cw & (A1_NAME|A1_STR), &ap->aa[0], q); p->n_op = UCALL; /* FALLTHROUGH */ case 0: break; } /* some attributes must be massaged special */ switch (attr) { case GCC_ATYP_ALIGNED: if (narg == 0) ap->aa[0].iarg = ALMAX; else ap->aa[0].iarg *= SZCHAR; break; case GCC_ATYP_PACKED: if (narg == 0) ap->aa[0].iarg = 1; /* bitwise align */ else ap->aa[0].iarg *= SZCHAR; break; case GCC_ATYP_MODE: if ((i = amatch(ap->aa[0].sarg, mods, ATSZ)) == 0) werror("unknown mode arg %s", ap->aa[0].sarg); ap->aa[0].iarg = mods[i].typ; break; case GCC_ATYP_VISIBILITY: c = ap->aa[0].sarg; if (strcmp(c, "default") && strcmp(c, "hidden") && strcmp(c, "internal") && strcmp(c, "protected")) werror("unknown visibility %s", c); break; case GCC_ATYP_TLSMODEL: c = ap->aa[0].sarg; if (strcmp(c, "global-dynamic") && strcmp(c, "local-dynamic") && strcmp(c, "initial-exec") && strcmp(c, "local-exec")) werror("unknown tls model %s", c); break; default: break; } out: ; }
/* * Fixup types when modes given in defid(). */ void gcc_modefix(NODE *p) { struct attr *ap; #ifdef TARGET_TIMODE struct attr *a2; #endif struct symtab *sp; char *s; int i, u; if ((ap = attr_find(p->n_ap, GCC_ATYP_MODE)) == NULL) return; u = ISUNSIGNED(BTYPE(p->n_type)); if ((i = amatch(ap->aa[0].sarg, mods, ATSZ)) == 0) { werror("unknown mode arg %s", ap->aa[0].sarg); return; } i = mods[i].typ; if (i >= 1 && i <= MAXTYPES) { MODTYPE(p->n_type, ctype(i)); if (u) p->n_type = ENUNSIGN(p->n_type); } else switch (i) { #ifdef TARGET_TIMODE case 800: if (BTYPE(p->n_type) == STRTY) break; MODTYPE(p->n_type, tisp->stype); p->n_df = tisp->sdf; p->n_ap = tisp->sap; if (ap->iarg(1) == u) break; /* must add a new mode struct to avoid overwriting */ a2 = attr_new(GCC_ATYP_MODE, 3); a2->sarg(0) = ap->sarg(0); a2->iarg(1) = u; p->n_ap = attr_add(p->n_ap, a2); break; #endif case FCOMPLEX: case COMPLEX: case LCOMPLEX: /* Destination should have been converted to a struct already */ if (BTYPE(p->n_type) != STRTY) uerror("gcc_modefix: complex not STRTY"); i -= (FCOMPLEX-FLOAT); ap = strattr(p->n_ap); sp = ap->amlist; if (sp->stype == (unsigned)i) return; /* Already correct type */ /* we must change to another struct */ s = i == FLOAT ? "0f" : i == DOUBLE ? "0d" : i == LDOUBLE ? "0l" : 0; sp = lookup(addname(s), 0); for (ap = sp->sap; ap != NULL; ap = ap->next) p->n_ap = attr_add(p->n_ap, attr_dup(ap)); break; default: cerror("gcc_modefix"); } }
void gcc_init(void) { struct kw *kwp; NODE *p; TWORD t; int i, d_debug; d_debug = ddebug; ddebug = 0; for (kwp = kw; kwp->name; kwp++) kwp->ptr = addname(kwp->name); for (i = 0; i < 4; i++) { struct symtab *sp; t = ctype(g77t[i]); p = block(NAME, NIL, NIL, t, NULL, 0); sp = lookup(addname(g77n[i]), 0); p->n_sp = sp; defid(p, TYPEDEF); nfree(p); } ddebug = d_debug; #ifdef TARGET_TIMODE { struct attr *ap; loti = addname("__loti"); hiti = addname("__hiti"); TISTR = addname("TI"); tisp = addstr("0ti"); cmpti2sp = addftn("__cmpti2", INT); ucmpti2sp = addftn("__ucmpti2", INT); addvti3sp = addftn("__addvti3", STRTY); addvti3sp->sap = tisp->sap; subvti3sp = addftn("__subvti3", STRTY); subvti3sp->sap = tisp->sap; mulvti3sp = addftn("__mulvti3", STRTY); mulvti3sp->sap = tisp->sap; divti3sp = addftn("__divti3", STRTY); divti3sp->sap = tisp->sap; modti3sp = addftn("__modti3", STRTY); modti3sp->sap = tisp->sap; ap = attr_new(GCC_ATYP_MODE, 3); ap->sarg(0) = TISTR; ap->iarg(1) = 1; ap = attr_add(tisp->sap, ap); udivti3sp = addftn("__udivti3", STRTY); udivti3sp->sap = ap; umodti3sp = addftn("__umodti3", STRTY); umodti3sp->sap = ap; ashldi3sp = addftn("__ashldi3", ctype(LONGLONG)); ashldi3sp->sap = ap; ashrdi3sp = addftn("__ashrdi3", ctype(LONGLONG)); ashrdi3sp->sap = ap; lshrdi3sp = addftn("__lshrdi3", ctype(LONGLONG)); lshrdi3sp->sap = ap; floatuntixfsp = addftn("__floatuntixf", LDOUBLE); } #endif }