aboutsummaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/c.c394
-rw-r--r--src/c_builtin.c2
-rw-r--r--src/c_eval.c1
-rw-r--r--src/c_lex.c28
-rw-r--r--src/c_type.c38
-rw-r--r--src/c_type.h2
-rw-r--r--src/ir.c1
-rw-r--r--src/ir_abi0.c17
-rw-r--r--src/ir_dump.c2
-rw-r--r--src/t_aarch64_aapcs.c15
-rw-r--r--src/t_x86-64_sysv.c4
11 files changed, 436 insertions, 68 deletions
diff --git a/src/c.c b/src/c.c
index c1993e2..30c2c96 100644
--- a/src/c.c
+++ b/src/c.c
@@ -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);
diff --git a/src/ir.c b/src/ir.c
index c32ff4d..4639b86 100644
--- a/src/ir.c
+++ b/src/ir.c
@@ -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 */