casting explicitly to boolean values in early out logic

This commit is contained in:
Wolfgang (Blub) Bumiller 2012-11-21 19:36:28 +01:00
parent 21c2fcb929
commit ebc6954bf5
3 changed files with 53 additions and 1 deletions

31
ast.c
View file

@ -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;
}

View file

@ -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 */

22
ir.c
View file

@ -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;