From ebc6954bf566a1e7f66eee8be5f4d9b06fb05212 Mon Sep 17 00:00:00 2001 From: "Wolfgang (Blub) Bumiller" Date: Wed, 21 Nov 2012 19:36:28 +0100 Subject: [PATCH] casting explicitly to boolean values in early out logic --- ast.c | 31 ++++++++++++++++++++++++++++++- gmqcc.h | 1 + ir.c | 22 ++++++++++++++++++++++ 3 files changed, 53 insertions(+), 1 deletion(-) diff --git a/ast.c b/ast.c index cb68f06..b04acc6 100644 --- a/ast.c +++ b/ast.c @@ -1521,6 +1521,16 @@ bool ast_binary_codegen(ast_binary *self, ast_function *func, bool lvalue, ir_va ir_block *from_left, *from_right; ir_instr *phi; size_t merge_id; + uint16_t notop; + + /* Note about casting to true boolean values: + * We use a single NOT for sub expressions, and an + * overall NOT at the end, and for that purpose swap + * all the jump conditions in order for the NOT to get + * doubled. + * ie: (a && b) usually becomes (!!a ? !!b : !!a) + * but we translate this to (!(!a ? !a : !b)) + */ merge_id = vec_size(func->blocks); merge = ir_function_create_block(func->ir_func, ast_function_label(func, "sce_merge")); @@ -1528,10 +1538,17 @@ bool ast_binary_codegen(ast_binary *self, ast_function *func, bool lvalue, ir_va cgen = self->left->expression.codegen; if (!(*cgen)((ast_expression*)(self->left), func, false, &left)) return false; + notop = type_not_instr[left->vtype]; + if (notop == AINSTR_END) { + asterror(ast_ctx(self), "don't know how to cast to bool..."); + return false; + } + left = ir_block_create_unary(func->curblock, ast_function_label(func, "sce_not"), notop, left); from_left = func->curblock; + other = ir_function_create_block(func->ir_func, ast_function_label(func, "sce_other")); - if (self->op == INSTR_AND) { + if (self->op == INSTR_OR) { if (!ir_block_create_if(func->curblock, left, other, merge)) return false; } else { @@ -1545,6 +1562,12 @@ bool ast_binary_codegen(ast_binary *self, ast_function *func, bool lvalue, ir_va cgen = self->right->expression.codegen; if (!(*cgen)((ast_expression*)(self->right), func, false, &right)) return false; + notop = type_not_instr[right->vtype]; + if (notop == AINSTR_END) { + asterror(ast_ctx(self), "don't know how to cast to bool..."); + return false; + } + right = ir_block_create_unary(func->curblock, ast_function_label(func, "sce_not"), notop, right); from_right = func->curblock; if (!ir_block_create_jump(func->curblock, merge)) @@ -1558,6 +1581,12 @@ bool ast_binary_codegen(ast_binary *self, ast_function *func, bool lvalue, ir_va ir_phi_add(phi, from_left, left); ir_phi_add(phi, from_right, right); *out = ir_phi_value(phi); + notop = type_not_instr[(*out)->vtype]; + if (notop == AINSTR_END) { + asterror(ast_ctx(self), "don't know how to cast to bool..."); + return false; + } + *out = ir_block_create_unary(func->curblock, ast_function_label(func, "sce_final_not"), notop, *out); self->expression.outr = *out; return true; } diff --git a/gmqcc.h b/gmqcc.h index 265bee5..7861f09 100644 --- a/gmqcc.h +++ b/gmqcc.h @@ -292,6 +292,7 @@ extern uint16_t type_storep_instr[TYPE_COUNT]; /* other useful lists */ extern uint16_t type_eq_instr[TYPE_COUNT]; extern uint16_t type_ne_instr[TYPE_COUNT]; +extern uint16_t type_not_instr[TYPE_COUNT]; typedef struct { uint32_t offset; /* Offset in file of where data begins */ diff --git a/ir.c b/ir.c index 232bd69..91e8d7f 100644 --- a/ir.c +++ b/ir.c @@ -171,6 +171,28 @@ uint16_t type_ne_instr[TYPE_COUNT] = { AINSTR_END, /* array */ }; +uint16_t type_not_instr[TYPE_COUNT] = { + INSTR_NOT_F, /* should use I when having integer support */ + INSTR_NOT_S, + INSTR_NOT_F, + INSTR_NOT_V, + INSTR_NOT_ENT, + INSTR_NOT_ENT, + INSTR_NOT_FNC, + INSTR_NOT_ENT, /* should use I */ +#if 0 + INSTR_NOT_I, /* integer type */ +#else + INSTR_NOT_F, +#endif + + INSTR_NOT_V, /* variant, should never be accessed */ + + AINSTR_END, /* struct */ + AINSTR_END, /* union */ + AINSTR_END, /* array */ +}; + static void irerror(lex_ctx ctx, const char *msg, ...) { va_list ap; -- 2.39.2