diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/c.c | 394 | ||||
| -rw-r--r-- | src/c_builtin.c | 2 | ||||
| -rw-r--r-- | src/c_eval.c | 1 | ||||
| -rw-r--r-- | src/c_lex.c | 28 | ||||
| -rw-r--r-- | src/c_type.c | 38 | ||||
| -rw-r--r-- | src/c_type.h | 2 | ||||
| -rw-r--r-- | src/ir.c | 1 | ||||
| -rw-r--r-- | src/ir_abi0.c | 17 | ||||
| -rw-r--r-- | src/ir_dump.c | 2 | ||||
| -rw-r--r-- | src/t_aarch64_aapcs.c | 15 | ||||
| -rw-r--r-- | src/t_x86-64_sysv.c | 4 |
11 files changed, 436 insertions, 68 deletions
@@ -1530,6 +1530,7 @@ iniwrite(CComp *cm, InitParser *ip, uint off, uint bitsiz, uint bitoff, Type ty, .bitoff = bitoff, .ex = *ex }, *new = alloccopy(&cm->exarena, &val, sizeof val, 0); + assert(ex->ty.bits == ty.bits); *init->tail = new; init->tail = &new->next; if (!bitsiz) for (uint i = off, end = i + typesize(ex->ty); i < end; ++i) { @@ -1811,7 +1812,7 @@ initializer(CComp *cm, Type *ty, enum evalmode ev, bool globl, } else { if (ev && !eval(&ex, ev) && ev != EVFOLD) error(&ex.span, "cannot evaluate expression statically"); - else + else if (ev == EVSTATICINI || !isscalar(*ty)) iniwrite(cm, ip, 0, 0, 0, *ty, &ex); } if (ip->dyn) @@ -2964,6 +2965,7 @@ structcopy(Function *fn, Type ty, Ref dst, Ref src) static Ref structreturn(Function *fn, const Expr *src) { + assert(isagg(src->ty)); return expraddr(fn, src); } @@ -3104,6 +3106,13 @@ genstore(Function *fn, Type t, Ref ptr, Ref val) static void genbitfstore(Function *fn, const Type ty, Ref addr, const ExprGetFld *fld, Ref tmp, Ref val); +typedef struct { Ref a, b; } Ref2; +static Ref complex2addr_cvt(Function *, Type, const Expr *); +static Ref complex2scalar(Function *fn, Type to, const Expr *ex); +static Ref2 cvt2complex(Function *fn, Type base, const Expr *ex); +Ref2 compcomplexex(Function *, const Expr *, bool discard); +static void complexstore(Function *fn, Type base, Ref, Ref2); + static void geninit(Function *fn, Type t, Ref dst, const Expr *src) { @@ -3151,6 +3160,8 @@ geninit(Function *fn, Type t, Ref dst, const Expr *src) geninit(fn, ex->ty, adr, ex); } else if (isagg(ex->ty)) { structcopy(fn, ex->ty, adr, expraddr(fn, ex)); + } else if (iscomplex(ex->ty)) { + complexstore(fn, typechild(ex->ty), adr, compcomplexex(fn, ex, 0)); } else if (!val->bitsiz) { genstore(fn, ex->ty, adr, exprvalue(fn, ex)); } else { @@ -3358,7 +3369,10 @@ Recur: ex = &ex->sub[0]; goto Recur; } else { - putcondbranch(fn, exprvalue(fn, ex), tr, fl); + Ref r; + if (!iscomplex(ex->ty)) r = exprvalue(fn, ex); + else r = complex2scalar(fn, mktype(TYBOOL), ex); + putcondbranch(fn, r, tr, fl); } } @@ -3406,10 +3420,16 @@ Recur: if (!phi) { expreffects(fn, ex); } else { - Ref val = exprvalue(fn, ex); - if (isscalar(phi->typ)) - val = scalarcvt(fn, phi->typ, ex->ty, val); - else assert(ex->ty.bits == phi->typ.bits); + Ref val; + if (!iscomplex(ex->ty)) { + val = exprvalue(fn, ex); + if (isscalar(phi->typ)) + val = scalarcvt(fn, phi->typ, ex->ty, val); + else assert(ex->ty.bits == phi->typ.bits); + } else { + assert(isint(phi->typ)); + val = complex2scalar(fn, phi->typ, ex); + } vpush(&phi->refs, val); } if (fn->curblk) @@ -3454,7 +3474,7 @@ compilecall(Function *fn, const Expr *ex) return declsbuf.p[sub[0].decl].builtin->comp(fn, (Expr *)ex, 0); } ins.op = Ocall; - if (isagg(ex->ty)) { + if (isagg(ex->ty) || iscomplex(ex->ty)) { ins.cls = KPTR; } else { assert(isscalar(ex->ty) || ex->ty.t == TYVOID); @@ -3465,7 +3485,11 @@ compilecall(Function *fn, const Expr *ex) for (int i = 0; i < ex->narg; ++i) { Expr *arg = &sub[i+1]; Type ty = i < td->nmemb ? td->param[i] : argpromote(arg->ty); - Ref r = scalarcvt(fn, ty, typedecay(arg->ty), exprvalue(fn, arg)); + Ref r; + if (!iscomplex(ty)) + r = scalarcvt(fn, ty, typedecay(arg->ty), exprvalue(fn, arg)); + else + r = complex2addr_cvt(fn, ty, arg); vpush(&insns, mkarginstr(mkirtype(ty), r)); } for (int i = 0; i < insns.n; ++i) @@ -3562,24 +3586,26 @@ knowntruthy(bool *t, Expr *ex) Ref compileexpr(Function *fn, const Expr *ex, bool discard) { - Type ty; - Ref l, r, q, adr; - uint bitsiz; - enum op op; - enum irclass cls = type2cls[scalartypet(ex->ty)]; - int swp = 0; - Expr *sub; - - //eval((Expr *)ex, EVFOLD); - sub = ex->sub; - if (ex->ty.t != TYVOID && !isscalar(ex->ty)) { /* fn & array designators evaluate to their address; * so do aggregates for the purpose of code generation */ if (isagg(ex->ty) && isincomplete(ex->ty)) error(&ex->span, "use of incomplete type '%ty'", ex->ty); return expraddr(fn, ex); + } else if (iscomplex(ex->ty)) { + assert(discard); + (void)compcomplexex(fn, ex, discard); + return NOREF; } + + Type ty; + Ref l, r, q, adr; + uint bitsiz; + enum op op; + int swp; + enum irclass cls = type2cls[scalartypet(ex->ty)]; + Expr *sub = ex->sub; + switch (ex->t) { case ENUMLIT: if (discard) return NOREF; @@ -3625,12 +3651,16 @@ compileexpr(Function *fn, const Expr *ex, bool discard) l = scalarcvt(fn, ex->ty, sub->ty, l); return irunop(fn, op, cls, l); case ELOGNOT: - for (; sub->t == ELOGNOT; ex = sub, sub = sub->sub) + for (swp = 0; sub->t == ELOGNOT; ex = sub, sub = sub->sub) swp ^= 1; op = Oequ + swp; - l = compileexpr(fn, sub, discard); - if (discard) return NOREF; - l = scalarcvt(fn, ex->ty, sub->ty, l); + if (!iscomplex(sub->ty) || discard) { + l = compileexpr(fn, sub, discard); + if (discard) return NOREF; + l = scalarcvt(fn, ex->ty, sub->ty, l); + } else { + l = complex2scalar(fn, mktype(TYBOOL), sub); + } r = mkintcon(cls, 0); return irbinop(fn, op, cls, l, r); case EDEREF: @@ -3744,15 +3774,26 @@ compileexpr(Function *fn, const Expr *ex, bool discard) Cmp: ty = cvtarith(sub[0].ty, sub[1].ty); if (!ty.t) ty.t = TYPTR; - if (isunsigned(ty) && in_range(op, Olth, Ogte)) - op += Oulth - Olth; - l = compileexpr(fn, &sub[0], discard); - r = compileexpr(fn, &sub[1], discard); - if (discard) return NOREF; - l = scalarcvt(fn, ty, sub[0].ty, l); - r = scalarcvt(fn, ty, sub[1].ty, r); - cls = type2cls[ty.t]; - return irbinop(fn, op, cls, l, r); + if (!iscomplex(ty) || discard) { + if (isint(ty) && isunsigned(ty) && in_range(op, Olth, Ogte)) + op += Oulth - Olth; + l = compileexpr(fn, &sub[0], discard); + r = compileexpr(fn, &sub[1], discard); + if (discard) return NOREF; + l = scalarcvt(fn, ty, sub[0].ty, l); + r = scalarcvt(fn, ty, sub[1].ty, r); + cls = type2cls[ty.t]; + return irbinop(fn, op, cls, l, r); + } else { + assert(op == Oequ || op == Oneq); + Type base = typechild(ty); + Ref2 z1 = cvt2complex(fn, base, &sub[0]), + z2 = cvt2complex(fn, base, &sub[1]); + /* meh */ + l = irbinop(fn, op, type2cls[base.t], z1.a, z2.a); + r = irbinop(fn, op, type2cls[base.t], z1.b, z2.b); + return irbinop(fn, op == Oequ ? Oand : Oior, KI32, l, r); + } case ESET: assert(isscalar(ex->ty)); q = scalarcvt(fn, sub[0].ty, sub[1].ty, exprvalue(fn, &sub[1])); @@ -3868,6 +3909,275 @@ compileexpr(Function *fn, const Expr *ex, bool discard) } } +static Ref +complex2scalar(Function *fn, Type to, const Expr *ex) +{ + Ref2 c = compcomplexex(fn, ex, 0); + Type base = typechild(ex->ty); + to.t = scalartypet(to); + if (to.t == TYBOOL) { /* implicit != 0.0 */ + /* meh */ + Ref r = scalarcvt(fn, mktype(TYBOOL), base, c.a), + i = scalarcvt(fn, mktype(TYBOOL), base, c.b); + return irbinop(fn, Oior, KI32, r, i); + } else { + return scalarcvt(fn, to, base, c.a); + } +} + +static Ref2 +cvt2complex(Function *fn, Type base, const Expr *ex) +{ + assert(isscalar(base) && isflt(base)); + if (iscomplex(ex->ty)) { + Ref2 c = compcomplexex(fn, ex, 0); + Type base2 = typechild(ex->ty); + if (base2.bits != base.bits) { + c.a = scalarcvt(fn, base, base2, c.a); + c.b = scalarcvt(fn, base, base2, c.b); + } + return c; + } + return (Ref2){scalarcvt(fn, base, ex->ty, exprvalue(fn, ex)), mkfltcon(type2cls[base.t], 0)}; +} + +static Ref2 +complexload(Function *fn, Type base, Ref adr, bool volatyl) +{ + assert(isscalar(base) && isflt(base)); + return (Ref2){ + genload(fn, base, adr, volatyl), + genload(fn, base, irbinop(fn, Oadd, KPTR, adr, mkref(RICON, targ_primsizes[base.t])), volatyl) + }; +} + +static void +complexstore(Function *fn, Type base, Ref adr, Ref2 c) +{ + assert(isscalar(base) && isflt(base)); + genstore(fn, base, adr, c.a); + genstore(fn, base, irbinop(fn, Oadd, KPTR, adr, mkref(RICON, targ_primsizes[base.t])), c.b); +} + +static Ref +complex2addr(Function *fn, const Expr *ex) +{ + assert(iscomplex(ex->ty)); + if (islvalue(ex)) return expraddr(fn, ex); + Type base = typechild(ex->ty); + Ref2 uv = compcomplexex(fn, ex, 0); + Ref r = addinstr(fn, mkalloca(targ_primsizes[base.t]*2, targ_primalign[base.t])); + complexstore(fn, base, r, uv); + return r; +} + +static Ref +complex2addr_cvt(Function *fn, Type to, const Expr *ex) +{ + assert(iscomplex(to)); + if (ex->ty.bits == to.bits && islvalue(ex)) + return expraddr(fn, ex); + Type base = typechild(to); + Ref2 uv = cvt2complex(fn, base, ex); + Ref r = addinstr(fn, mkalloca(targ_primsizes[base.t]*2, targ_primalign[base.t])); + complexstore(fn, base, r, uv); + return r; +} + +Ref2 +compcomplexex(Function *fn, const Expr *ex, bool discard) +{ + static const Ref2 NIL = { 0 }; + assert(iscomplex(ex->ty)); + Type sty = typechild(ex->ty); + assert(isflt(sty)); + enum irclass cls = type2cls[sty.t]; + Ref adr, r; + Ref2 q, w, z; + const Expr *sub = ex->sub; + Type ty; + enum op op; + switch (ex->t) { + case ENUMLIT: /* imaginary literal e.g. 1.0iF */ + if (discard) return NIL; + return (Ref2){mkfltcon(cls, 0.0), mkfltcon(cls, ex->f)}; + case ESYM: + if (discard && !(ex->qual & QVOLATILE)) return NIL; + adr = expraddr(fn, ex); + Load: + return complexload(fn, sty, adr, ex->qual & QVOLATILE); + case EVAARG: + adr = builtin_va_arg_comp(fn, ex, discard); + if (discard) return NIL; + goto Load; + case EGETF: + if (discard && !(ex->qual & QVOLATILE)) return NIL; + adr = expraddr(fn, ex); + goto Load; + case ECAST: + /* fallthru */ + case EPLUS: + if (discard) { + expreffects(fn, sub); + return NIL; + } + return cvt2complex(fn, sty, sub); + case ENEG: + q = compcomplexex(fn, sub, discard); + if (discard) return q; + assert(sub->ty.bits == ex->ty.bits); + return (Ref2){irunop(fn, Oneg, cls, q.a), irunop(fn, Oneg, cls, q.b)}; + case EDEREF: + discard &= (ex->qual & QVOLATILE) == 0; + adr = compileexpr(fn, sub, discard); + if (discard) return NIL; + goto Load; + case ESUB: + op = Osub; + goto Additive; + case EADD: + op = Oadd; + Additive: + if (discard) { + expreffects(fn, &sub[0]), expreffects(fn, &sub[1]); + return NIL; + } + q = cvt2complex(fn, sty, &sub[0]); + w = cvt2complex(fn, sty, &sub[1]); + /* per ISO C, must avoid unnecessarily addition of constant 0.0, not a NO-OP in IEE754 */ + if (iscomplex(sub[0].ty) && iscomplex(sub[1].ty)) { /* complex + complex */ + CmplxCmplx: + return (Ref2){ + irbinop(fn, op, cls, q.a, w.a), + irbinop(fn, op, cls, q.b, w.b), + }; + } else if (iscomplex(sub[0].ty)) { /* complex + real */ + return (Ref2){ irbinop(fn, op, cls, q.a, w.a), q.b }; + } else { /* real + complex */ + if (op == Osub) goto CmplxCmplx; + return (Ref2){ irbinop(fn, op, cls, q.a, w.a), w.b }; + } + case EMUL: + if (discard) { + expreffects(fn, &sub[0]), expreffects(fn, &sub[1]); + return NIL; + } + int swp = 0; + if (iscomplex(sub[0].ty) && !iscomplex(sub[1].ty)) { /* complex * real */ + Scale: + q = cvt2complex(fn, sty, &sub[swp]); + r = scalarcvt(fn, sty, sub[swp^1].ty, exprvalue(fn, &sub[swp^1])); + return (Ref2){ + irbinop(fn, Omul, cls, q.a, r), + irbinop(fn, Omul, cls, q.b, r), + }; + } else if (!iscomplex(sub[0].ty) && iscomplex(sub[1].ty)) { /* real * complex */ + swp = 1; + goto Scale; + } else RuntimeCall: { /* complex * complex */ + /* call runtime function */ + static const char *rtfn[][3] = { + {"__mulsc3", "__muldc3", "__mulxc3"}, + {"__divsc3", "__divdc3", "__divxc3"}, + }; + Instr ins = {Ocall, KPTR}; + IRType typ = mkirtype(ex->ty); + q.a = complex2addr_cvt(fn, ex->ty, &sub[0]); + q.b = complex2addr_cvt(fn, ex->ty, &sub[1]); + addinstr(fn, mkarginstr(typ, q.a)); + addinstr(fn, mkarginstr(typ, q.b)); + ins.l = mksymref(intern(rtfn[ex->t == EDIV][sty.t - TYFLOAT]), SFUNC); + ins.r = mkcallarg(mkirtype(ex->ty), 2, -1); + adr = addinstr(fn, ins); + goto Load; + } + case EDIV: + if (discard) { + expreffects(fn, &sub[0]), expreffects(fn, &sub[1]); + return NIL; + } + if (iscomplex(sub[0].ty) && !iscomplex(sub[1].ty)) { /* complex / real */ + q = cvt2complex(fn, sty, &sub[0]); + r = scalarcvt(fn, sty, sub[1].ty, exprvalue(fn, &sub[1])); + return (Ref2){ + irbinop(fn, Odiv, cls, q.a, r), + irbinop(fn, Odiv, cls, q.b, r), + }; + } else { /* any / complex */ + goto RuntimeCall; + } + case ESET: + assert(sub[0].ty.bits == ex->ty.bits); + q = cvt2complex(fn, sty, &sub[1]); + adr = expraddr(fn, &sub[0]); + genstore(fn, ex->ty, adr, q.a); + genstore(fn, ex->ty, + irbinop(fn, Oadd, KPTR, adr, mkref(RICON, targ_primsizes[sty.t])), q.b); + return q; + case EPREINC: + case EPOSTINC: + case EPREDEC: + case EPOSTDEC: + assert(ex->ty.bits == sub->ty.bits); + adr = expraddr(fn, sub); + q = complexload(fn, sty, adr, sub->qual & QVOLATILE); + w.a = irbinop(fn, ex->t < EPREDEC ? Oadd : Osub, cls, q.a, mkfltcon(cls, 1.0)); + w.b = q.b; + complexstore(fn, sty, adr, w); + return (ex->t == EPREINC || ex->t == EPREDEC) ? w : q; + case ESETMUL: + case ESETDIV: + case ESETSUB: + case ESETADD: + ty = cvtarith(sub[0].ty, sub[1].ty); + adr = expraddr(fn, &sub[0]); + w = cvt2complex(fn, sty, &sub[1]); + q = compcomplexex(fn, + &mkexpr(ex->t - ESETADD + EADD, ex->span, ty, .sub = (Expr *)sub), 0); + if (sub[0].ty.bits == sub[1].ty.bits) { + complexstore(fn, sty, adr, q); + } else { + Type to = typechild(sub[0].ty), from = typechild(ty); + w.a = scalarcvt(fn, to, from, q.a); + w.b = scalarcvt(fn, to, from, q.b); + complexstore(fn, sty, adr, w); + } + return q; + case ECALL: + adr = compilecall(fn, ex); + if (discard) return NIL; + goto Load; + case ECOND: + for (bool c; knowntruthy(&c, &ex->sub[0]);) { + r = compileexpr(fn, &ex->sub[2-c], discard); + if (discard) return NIL; + assert(ex->sub[2-c].ty.bits == ex->ty.bits); + return compcomplexex(fn, &ex->sub[2-c], 0); + } + + Block *tr, *fl, *end; + condjump(fn, &sub[0], tr = newblk(fn), fl = newblk(fn)); + useblk(fn, tr); + q = compcomplexex(fn, &sub[1], discard); + end = newblk(fn); + if (fn->curblk) + putbranch(fn, end); + useblk(fn, fl); + w = compcomplexex(fn, &sub[2], discard); + if (fn->curblk) + putbranch(fn, end); + useblk(fn, end); + if (discard) return NIL; + z.a = addphi(fn, cls, (Ref[2]){q.a, w.a}); + z.b = addphi(fn, cls, (Ref[2]){q.b, w.b}); + return z; + case ESEQ: + expreffects(fn, &sub[0]); + return compcomplexex(fn, &sub[1], discard); + default: assert(!"nyi cmplx expr"); + } +} + /************************************/ /* Statements parsing & compilation */ /************************************/ @@ -4383,12 +4693,16 @@ stmt(CComp *cm, Function *fn) ex.ty, fn->retty); } EMITS { - if (isscalar(fn->retty)) - r = scalarcvt(fn, fn->retty, ex.ty, exprvalue(fn, &ex)); - else if (fn->retty.t == TYVOID) + if (isscalar(fn->retty) && !iscomplex(fn->retty)) { + if (iscomplex(ex.ty)) r = complex2scalar(fn, fn->retty, &ex); + else r = scalarcvt(fn, fn->retty, ex.ty, exprvalue(fn, &ex)); + } else if (iscomplex(fn->retty)) { + r = complex2addr_cvt(fn, fn->retty, &ex); + } else if (fn->retty.t == TYVOID) { r = (expreffects(fn, &ex), NOREF); - else + } else { r = structreturn(fn, &ex); + } putreturn(fn, r, NOREF); } } else { @@ -4492,7 +4806,11 @@ localdecl(CComp *cm, Function *fn, bool forini) geninit(fn, ty, mkref(RTMP, decl.id), &ini); else if (isagg(ty)) structcopy(fn, ty, mkref(RTMP, decl.id), exprvalue(fn, &ini)); - else { + else if (iscomplex(ty)) { + Type base = typechild(ty); + complexstore(fn, base, mkref(RTMP, decl.id), + cvt2complex(fn, base, &ini)); + } else { genstore(fn, ty, mkref(RTMP, decl.id), scalarcvt(fn, ty, ini.ty, exprvalue(fn, &ini))); } @@ -4581,7 +4899,7 @@ function(CComp *cm, Function *fn, internstr *pnames, const Span *pspans, uchar * Decl arg = { .ty = td->param[i], .qual = pquals ? pquals[i] : 0, .name = pnames[i], .scls = SCAUTO, .span = pspans[i] }; EMITS { - if (isscalar(arg.ty)) { + if (isscalar(arg.ty) && !iscomplex(arg.ty)) { arg.id = addinstr(fn, mkalloca(typesize(arg.ty), typealign(arg.ty))).i; genstore(fn, arg.ty, mkref(RTMP, arg.id), mkref(RTMP, i)); } else { diff --git a/src/c_builtin.c b/src/c_builtin.c index 522c4dc..79bdcc7 100644 --- a/src/c_builtin.c +++ b/src/c_builtin.c @@ -147,7 +147,7 @@ Ref builtin_va_arg_comp(Function *fn, const Expr *ex, bool discard) { assert(ex->t == EVAARG && ex->ty.t); - enum irclass k = isagg(ex->ty) ? KPTR : type2cls[scalartypet(ex->ty)]; + enum irclass k = (isagg(ex->ty) || iscomplex(ex->ty)) ? KPTR : type2cls[scalartypet(ex->ty)]; return addinstr(fn, mkinstr2(Ovaarg, k, compileexpr(fn, ex->sub, 0), mktyperef(mkirtype(ex->ty)))); } diff --git a/src/c_eval.c b/src/c_eval.c index 0efa7bd..0eb6df2 100644 --- a/src/c_eval.c +++ b/src/c_eval.c @@ -400,6 +400,7 @@ binop(Expr *ex, enum evalmode mode) bool eval(Expr *ex, enum evalmode mode) { + if (iscomplex(ex->ty)) return 0; switch (ex->t) { case EGETF: goto Unop; case ESEQ: diff --git a/src/c_lex.c b/src/c_lex.c index fe8edb5..c5e16aa 100644 --- a/src/c_lex.c +++ b/src/c_lex.c @@ -138,24 +138,26 @@ parsenumlit(u64int *outi, double *outf, const Token *tk, bool ispp) } else if (memchr(tk->s, '.', tk->len)) { extern double strtod(const char *, char **); double f; - char buf[80], *suffix; + char buf[80], *s; Float: /* float literal */ assert(tk->len < sizeof buf - 1 && "numlit too big"); memcpy(buf, tk->s, tk->len); buf[tk->len] = 0; - f = strtod(buf, &suffix); - if (suffix == buf) + f = strtod(buf, &s); + if (s == buf) return 0; - if (!*suffix) { - if (outf) *outf = f; - return TYDOUBLE; - } else if ((suffix[0]|0x20) == 'f' && !suffix[1]) { - if (outf) *outf = f; - return TYFLOAT; - } else if ((suffix[0]|0x20) == 'l' && !suffix[1]) { - if (outf) *outf = f; - return TYLDOUBLE; + if (outf) *outf = f; + if (!*s) return TYDOUBLE; + for (char *p = s; *p; ++p) { + if ((*p |= 0x20) == 'j') *p = 'i'; } + if (s[0] == 'f' && !s[1]) return TYFLOAT; + else if (s[0] == 'l' && !s[1]) return TYLDOUBLE; + else if (s[0] == 'i' && !s[1]) return TYCOMPLEX; + else if (s[0] == 'i' && s[1] == 'f' && !s[2]) return TYCOMPLEXF; + else if (s[0] == 'f' && s[1] == 'i' && !s[2]) return TYCOMPLEXF; + else if (s[0] == 'i' && s[1] == 'l' && !s[2]) return TYCOMPLEXL; + else if (s[0] == 'l' && s[1] == 'i' && !s[2]) return TYCOMPLEXL; return 0; } else { /* int literal */ static u64int max4typ[TYUVLONG-TYINT+1]; @@ -2432,7 +2434,7 @@ addpredefmacros(Arena **tmparena) }; static const char cpredefs[] = - "__antcc__\0__STDC__\0__STDC_NO_ATOMICS__\0__STDC_NO_COMPLEX__\0__STDC_NO_THREADS__\0__STDC_NO_VLA__\0", + "__antcc__\0__STDC__\0__STDC_NO_ATOMICS__\0__STDC_NO_THREADS__\0__STDC_NO_VLA__\0", cstdver[][8] = { [STDC89] = "199409L", [STDC99] = "199901L", diff --git a/src/c_type.c b/src/c_type.c index ef4770d..c34d7df 100644 --- a/src/c_type.c +++ b/src/c_type.c @@ -224,7 +224,7 @@ completetype(internstr name, int id, TypeData *td) assert(tagtypetags[id] == name && "bad redefn"); else tagtypetags[id] = name; - return mktype(td->t, .flag = td->flag, .dat = interntd(td)); + return mktype(td->t, .dat = interntd(td)); } Type @@ -312,9 +312,24 @@ cvtarith(Type a, Type b) if (!isarith(a) || !isarith(b)) return none; if (a.t == TYENUM) a = typechild(a); if (b.t == TYENUM) b = typechild(b); + if (iscomplex(a)) { + if (iscomplex(b)) { + /* when both are complex, choose type with greatest rank */ + /* enumeration order of type tags reflects arithmetic type rank */ + return a.t > b.t ? a : b; + } + /* complex float + double -> complex double */ + if (a.t - TYCOMPLEXF + TYFLOAT < b.t) + a.t = b.t + TYCOMPLEXF - TYFLOAT; + return a; + } else if (iscomplex(b)) { + /* double + complex float -> complex double */ + if (b.t - TYCOMPLEXF + TYFLOAT < a.t) + b.t = a.t + TYCOMPLEXF - TYFLOAT; + return b; + } if (isflt(a) || isflt(b)) { /* when one type is float, choose type with greatest rank */ - /* enumeration order of type tags reflects arithmetic type rank */ return a.t > b.t ? a : b; } a.t = intpromote(a.t); @@ -340,4 +355,23 @@ cvtarith(Type a, Type b) } } +/* transform 'complex T' -> struct 'complex T' { T real, imag; } */ +Type +complex2struct(Type t) +{ + assert(iscomplex(t)); + static Type cache[3]; + if (cache[t.t-TYCOMPLEXF].t) return cache[t.t-TYCOMPLEXF]; + static const char *names[] = { + "complex$float", "complex$double", "complex$longdouble" + }; + Type base = mktype(t.t - TYCOMPLEXF + TYFLOAT); + return cache[t.t-TYCOMPLEXF] = mktagtype(intern(names[t.t-TYCOMPLEXF]), &(TypeData){ + TYSTRUCT, .fld = (NamedField [2]){ + {intern("real"), {.t = base, .off = 0}}, + {intern("imag"), {.t = base, .off = typesize(base)}}, + }, .nmemb = 2, .align = typealign(base), .siz = typesize(base) * 2 + }); +} + /* vim:set ts=3 sw=3 expandtab: */ diff --git a/src/c_type.h b/src/c_type.h index 6ef1bc3..1347fcc 100644 --- a/src/c_type.h +++ b/src/c_type.h @@ -137,10 +137,12 @@ Type typedecay(Type); bool assigncompat(Type dst, Type src); enum typetag intpromote(enum typetag); Type cvtarith(Type a, Type b); +Type complex2struct(Type); static inline Type typechild(Type t) { if (t.t == TYENUM) return mktype(typedata[t.dat].backing); + if (iscomplex(t)) return mktype(t.t - TYCOMPLEXF + TYFLOAT); if (t.flag & TFCHLDPRIM) return mktype(t.child); if (t.flag & TFCHLDISDAT) { Type chld = mktype(typedata[t.dat].t, .flag = typedata[t.dat].flag, .dat = t.dat); @@ -127,6 +127,7 @@ newxcon(const IRCon *con) IRType mkirtype(Type t) { + if (iscomplex(t)) t = complex2struct(t); if (t.t == TYVOID || isscalar(t)) return (IRType) { .cls = type2cls[scalartypet(t)] }; assert(isagg(t)); diff --git a/src/ir_abi0.c b/src/ir_abi0.c index b8ae90f..7a976fe 100644 --- a/src/ir_abi0.c +++ b/src/ir_abi0.c @@ -297,6 +297,7 @@ abi0_call(Function *fn, Instr *ins, Block *blk, int *curi) for (int i = 0, i2 = ni + sretarghidden; i < call->narg; ++i) { int arginst = *curi - (call->narg - i); Instr *arg = &instrtab[blk->ins.p[arginst]]; + assert(arg->op == Oarg); IRType pty = ref2type(arg->l); uchar r2off; int first = abiargs.n; @@ -361,14 +362,16 @@ abi0(Function *fn) uchar r2off; Block *blk; Ref sret = {0}; + Type retty = fn->retty; + if (iscomplex(retty)) retty = complex2struct(retty); FREQUIRE(FNUSE); - if (fn->retty.t == TYVOID) { + if (retty.t == TYVOID) { fn->nabiret = 0; } else { - fn->nabiret = abiret(fn->abiret, &abiargs, &r2off, &ni, mkirtype(fn->retty)); - if (!fn->nabiret && isagg(fn->retty)) { /* ret agg by hidden pointer */ + fn->nabiret = abiret(fn->abiret, &abiargs, &r2off, &ni, mkirtype(retty)); + if (!fn->nabiret && isagg(retty)) { /* ret agg by hidden pointer */ Instr param = copyparam(fn, NULL, 0, abiargs.p[0]); sret = insertinstr(fn->entry, 0, param); ++istart; @@ -392,7 +395,7 @@ abi0(Function *fn) fn->nabiarg = abiargs.n; vfree(&abiargs); - if (!fn->nabiret && isagg(fn->retty)) { + if (!fn->nabiret && isagg(retty)) { /* for structures returned by hidden pointer argument, * if all return instrs return local var X, make X point to the result location, * (return value optimization (RVO)) */ @@ -428,13 +431,13 @@ abi0(Function *fn) } /* adjust returns */ - if (isagg(fn->retty) && blk->jmp.t == Jret && blk->jmp.arg[0].bits) { + if (isagg(retty) && blk->jmp.t == Jret && blk->jmp.arg[0].bits) { assert(!blk->jmp.arg[1].bits); if (fn->nabiret) { /* aggregate return in register(s) */ deluse(blk, USERJUMP, blk->jmp.arg[0]); Ref r[2]; int curi = blk->ins.n; - load2regs(r, mkirtype(fn->retty), blk->jmp.arg[0], fn->nabiret, fn->abiret, r2off, blk, &curi); + load2regs(r, mkirtype(retty), blk->jmp.arg[0], fn->nabiret, fn->abiret, r2off, blk, &curi); for (int i = 0; i < fn->nabiret; ++i) { blk->jmp.arg[i] = r[i]; adduse(blk, USERJUMP, r[i]); @@ -443,7 +446,7 @@ abi0(Function *fn) /* aggregate return (arg[0] is pointer to return value) */ if (rvovar == -1) { /* blit %sret, %arg */ - IRType typ = mkirtype(fn->retty); + IRType typ = mkirtype(retty); insertinstr(blk, blk->ins.n, mkarginstr(typ, sret)); insertinstr(blk, blk->ins.n, mkarginstr(typ, blk->jmp.arg[0])); insertinstr(blk, blk->ins.n, mkintrin(INstructcopy, 0, 2)); diff --git a/src/ir_dump.c b/src/ir_dump.c index daa2b2f..d2f5e41 100644 --- a/src/ir_dump.c +++ b/src/ir_dump.c @@ -272,7 +272,7 @@ dumpblk(Function *fn, Block *blk) if (prinums) bfmt(out, "%-4d", blk->inumstart + 1 + i); bfmt(out, " %s ", jnames[blk->jmp.t]); - if (blk->jmp.t == Jret && blk->jmp.arg[0].bits && !fn->nabiret && isagg(fn->retty)) { + if (blk->jmp.t == Jret && blk->jmp.arg[0].bits && !fn->nabiret && (isagg(fn->retty) || iscomplex(fn->retty))) { /* un-lowered struct return */ dumpref(0, mktyperef(mkirtype(fn->retty))); bfmt(out, " "); diff --git a/src/t_aarch64_aapcs.c b/src/t_aarch64_aapcs.c index 5389a49..a1be63d 100644 --- a/src/t_aarch64_aapcs.c +++ b/src/t_aarch64_aapcs.c @@ -2,12 +2,15 @@ /* Ref: https://github.com/ARM-software/abi-aa/blob/2025Q4/aapcs64/aapcs64.rst */ + static bool -hfa_scalar(enum typetag *hfa_t, enum typetag t) +hfa_scalar(enum typetag *hfa_t, Type t) { - if (!isfltt(t)) return 0; - if (!*hfa_t) *hfa_t = t; - else if (*hfa_t != t) return 0; + enum typetag tt; + if (isflt(t)) tt = scalartypet(t); + if (iscomplex(t)) tt = t.t - TYCOMPLEXF + TYFLOAT; + if (!*hfa_t) *hfa_t = tt; + else if (*hfa_t != tt) return 0; return 1; } @@ -21,7 +24,7 @@ hfa_arr(enum typetag *hfa_t, Type ty) return cls_hfa(hfa_t, &typedata[chld.dat]); if (chld.t == TYARRAY) return hfa_arr(hfa_t, chld); - return hfa_scalar(hfa_t, scalartypet(chld)); + return hfa_scalar(hfa_t, chld); } static bool @@ -38,7 +41,7 @@ cls_hfa(enum typetag *hfa_t, const TypeData *td) if (!hfa_arr(hfa_t, fld->t)) return 0; } else { - if (!hfa_scalar(hfa_t, scalartypet(fld->t))) + if (!hfa_scalar(hfa_t, fld->t)) return 0; } } diff --git a/src/t_x86-64_sysv.c b/src/t_x86-64_sysv.c index 8686571..9f1d59c 100644 --- a/src/t_x86-64_sysv.c +++ b/src/t_x86-64_sysv.c @@ -5,6 +5,10 @@ static int classify(uchar cls[2], const TypeData *td, uint off); static void clsscalar(uchar cls[2], uint off, Type ty) { + if (iscomplex(ty)) { + classify(cls, &typedata[complex2struct(ty).dat], off); + return; + } enum irclass k = type2cls[scalartypet(ty)]; uchar *fcls = &cls[off/8]; if (isflt(ty)) { /* SSE */ |