From cf9ceecb2f8cad2fb694b15c14ca1cf98e9524e7 Mon Sep 17 00:00:00 2001 From: Rui Ueyama Date: Tue, 22 Sep 2020 18:28:37 +0900 Subject: [PATCH] Add flonum ==, !=, < and <= --- codegen.c | 49 +++++++++++++++++++++++++++++++++++++++++++++++++ test/float.c | 20 ++++++++++++++++++++ type.c | 5 +++++ 3 files changed, 74 insertions(+) diff --git a/codegen.c b/codegen.c index fb3f806..a775136 100644 --- a/codegen.c +++ b/codegen.c @@ -34,6 +34,18 @@ static void pop(char *arg) { depth--; } +static void pushf(void) { + println(" sub $8, %%rsp"); + println(" movsd %%xmm0, (%%rsp)"); + depth++; +} + +static void popf(char *arg) { + println(" movsd (%%rsp), %s", arg); + println(" add $8, %%rsp"); + depth--; +} + // Round up `n` to the nearest multiple of `align`. For instance, // align_to(5, 8) returns 8 and align_to(11, 8) returns 16. int align_to(int n, int align) { @@ -403,6 +415,43 @@ static void gen_expr(Node *node) { } } + if (is_flonum(node->lhs->ty)) { + gen_expr(node->rhs); + pushf(); + gen_expr(node->lhs); + popf("%xmm1"); + + char *sz = (node->lhs->ty->kind == TY_FLOAT) ? "ss" : "sd"; + + switch (node->kind) { + case ND_EQ: + case ND_NE: + case ND_LT: + case ND_LE: + println(" ucomi%s %%xmm0, %%xmm1", sz); + + if (node->kind == ND_EQ) { + println(" sete %%al"); + println(" setnp %%dl"); + println(" and %%dl, %%al"); + } else if (node->kind == ND_NE) { + println(" setne %%al"); + println(" setp %%dl"); + println(" or %%dl, %%al"); + } else if (node->kind == ND_LT) { + println(" seta %%al"); + } else { + println(" setae %%al"); + } + + println(" and $1, %%al"); + println(" movzb %%al, %%rax"); + return; + } + + error_tok(node->tok, "invalid expression"); + } + gen_expr(node->rhs); push(); gen_expr(node->lhs); diff --git a/test/float.c b/test/float.c index c41e4ae..082a9fa 100644 --- a/test/float.c +++ b/test/float.c @@ -39,6 +39,26 @@ int main() { ASSERT(-2147483648, (double)(unsigned long)(long)-1); + ASSERT(1, 2e3==2e3); + ASSERT(0, 2e3==2e5); + ASSERT(1, 2.0==2); + ASSERT(0, 5.1<5); + ASSERT(0, 5.0<5); + ASSERT(1, 4.9<5); + ASSERT(0, 5.1<=5); + ASSERT(1, 5.0<=5); + ASSERT(1, 4.9<=5); + + ASSERT(1, 2e3f==2e3); + ASSERT(0, 2e3f==2e5); + ASSERT(1, 2.0f==2); + ASSERT(0, 5.1f<5); + ASSERT(0, 5.0f<5); + ASSERT(1, 4.9f<5); + ASSERT(0, 5.1f<=5); + ASSERT(1, 5.0f<=5); + ASSERT(1, 4.9f<=5); + printf("OK\n"); return 0; } diff --git a/type.c b/type.c index 7bcec3d..358919f 100644 --- a/type.c +++ b/type.c @@ -73,6 +73,11 @@ static Type *get_common_type(Type *ty1, Type *ty2) { if (ty1->base) return pointer_to(ty1->base); + if (ty1->kind == TY_DOUBLE || ty2->kind == TY_DOUBLE) + return ty_double; + if (ty1->kind == TY_FLOAT || ty2->kind == TY_FLOAT) + return ty_float; + if (ty1->size < 4) ty1 = ty_int; if (ty2->size < 4)