aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--qbe.c113
1 files changed, 58 insertions, 55 deletions
diff --git a/qbe.c b/qbe.c
index 69f1e4f..1cd1a6c 100644
--- a/qbe.c
+++ b/qbe.c
@@ -631,6 +631,62 @@ extend(struct func *f, struct type *t, struct value *v)
return funcinst(f, op, &i32, v);
}
+static struct value *
+convert(struct func *f, struct type *dst, struct type *src, struct value *l)
+{
+ enum instkind op;
+ struct value *r = NULL;
+
+ if (src->kind == TYPEPOINTER)
+ src = &typeulong;
+ if (dst->kind == TYPEPOINTER)
+ dst = &typeulong;
+ if (dst->kind == TYPEVOID)
+ return NULL;
+ if (!(src->prop & PROPREAL) || !(dst->prop & PROPREAL))
+ fatal("internal error; unsupported conversion");
+ if (dst->kind == TYPEBOOL) {
+ l = extend(f, src, l);
+ r = mkintconst(src->repr, 0);
+ if (src->prop & PROPINT)
+ op = src->size == 8 ? ICNEL : ICNEW;
+ else
+ op = src->size == 8 ? ICNED : ICNES;
+ } else if (dst->prop & PROPINT) {
+ if (src->prop & PROPINT) {
+ if (dst->size <= src->size) {
+ op = ICOPY;
+ } else {
+ switch (src->size) {
+ case 4: op = src->basic.issigned ? IEXTSW : IEXTUW; break;
+ case 2: op = src->basic.issigned ? IEXTSH : IEXTUH; break;
+ case 1: op = src->basic.issigned ? IEXTSB : IEXTUB; break;
+ default: fatal("internal error; unknown int conversion");
+ }
+ }
+ } else {
+ if (!dst->basic.issigned)
+ return ftou(f, dst->repr, l);
+ op = src->size == 8 ? IDTOSI : ISTOSI;
+ }
+ } else {
+ if (src->prop & PROPINT) {
+ if (!src->basic.issigned)
+ return utof(f, dst->repr, l);
+ op = src->size == 8 ? ISLTOF : ISWTOF;
+ } else {
+ if (src->size < dst->size)
+ op = IEXTS;
+ else if (src->size > dst->size)
+ op = ITRUNCD;
+ else
+ op = ICOPY;
+ }
+ }
+
+ return funcinst(f, op, dst->repr, l, r);
+}
+
struct value *
funcexpr(struct func *f, struct expr *e)
{
@@ -700,62 +756,9 @@ funcexpr(struct func *f, struct expr *e)
}
fatal("internal error; unknown unary expression");
break;
- case EXPRCAST: {
- struct type *src, *dst;
-
+ case EXPRCAST:
l = funcexpr(f, e->base);
- r = NULL;
-
- src = e->base->type;
- if (src->kind == TYPEPOINTER)
- src = &typeulong;
- dst = e->type;
- if (dst->kind == TYPEPOINTER)
- dst = &typeulong;
- if (dst->kind == TYPEVOID)
- return NULL;
- if (!(src->prop & PROPREAL) || !(dst->prop & PROPREAL))
- fatal("internal error; unsupported conversion");
- if (dst->kind == TYPEBOOL) {
- l = extend(f, src, l);
- r = mkintconst(src->repr, 0);
- if (src->prop & PROPINT)
- op = src->size == 8 ? ICNEL : ICNEW;
- else
- op = src->size == 8 ? ICNED : ICNES;
- } else if (dst->prop & PROPINT) {
- if (src->prop & PROPINT) {
- if (dst->size <= src->size) {
- op = ICOPY;
- } else {
- switch (src->size) {
- case 4: op = src->basic.issigned ? IEXTSW : IEXTUW; break;
- case 2: op = src->basic.issigned ? IEXTSH : IEXTUH; break;
- case 1: op = src->basic.issigned ? IEXTSB : IEXTUB; break;
- default: fatal("internal error; unknown int conversion");
- }
- }
- } else {
- if (!dst->basic.issigned)
- return ftou(f, dst->repr, l);
- op = src->size == 8 ? IDTOSI : ISTOSI;
- }
- } else {
- if (src->prop & PROPINT) {
- if (!src->basic.issigned)
- return utof(f, dst->repr, l);
- op = src->size == 8 ? ISLTOF : ISWTOF;
- } else {
- if (src->size < dst->size)
- op = IEXTS;
- else if (src->size > dst->size)
- op = ITRUNCD;
- else
- op = ICOPY;
- }
- }
- return funcinst(f, op, dst->repr, l, r);
- }
+ return convert(f, e->type, e->base->type, l);
case EXPRBINARY:
if (e->op == TLOR || e->op == TLAND) {
label[0] = mkblock("logic_right");