static inline bool rir_binaryop_init(struct rir_binaryop *op, const struct rir_value *a, const struct rir_value *b, struct rir_ctx *ctx) { struct rir_expression *e; // for operations on pointers, first create a read from memory if (a->type->is_pointer) { if (!(e = rir_read_create(a, ctx))) { return false; } rirctx_block_add(ctx, e); a = &e->val; } if (b->type->is_pointer) { if (!(e = rir_read_create(b, ctx))) { return false; } rirctx_block_add(ctx, e); b = &e->val; } // in addition if any of the two operands are not the same make a conversion // of the largest type, to the smallest type. if (!rir_type_equal(a->type, b->type)) { struct rir_object *obj; if (rir_type_bytesize(a->type) >= rir_type_bytesize(b->type)) { if (!(obj = rir_convert_create_obj_maybeadd(a, b->type, ctx))) { return false; } a = rir_object_value(obj); } else { if (!(obj = rir_convert_create_obj_maybeadd(b, a->type, ctx))) { return false; } b = rir_object_value(obj); } } op->a = a; op->b = b; return true; }
const struct rir_value *rir_maybe_convert(const struct rir_value *val, const struct rir_type *checktype, struct rir_ctx *ctx) { if (!rir_type_equal(val->type, checktype)) { struct rir_object *obj; if (!(obj = rir_convert_create_obj_maybeadd(val, rir_type_create_from_other(checktype, false), ctx))) { return NULL; } val = rir_object_value(obj); } return val; }
struct rir_object *rirctx_alloc_write_add( struct rir_type *t, struct rir_value *value_to_write, struct rir_ctx *ctx) { // allocate and initialize the object struct rir_object *obj = rir_alloca_create_obj(t, NULL, RIRPOS_AST, ctx); if (!obj) { return NULL; } rir_common_block_add(&ctx->common, &obj->expr); struct rir_expression *writeobj = rir_write_create( rir_object_value(obj), value_to_write, RIRPOS_AST, ctx ); if (!writeobj) { return NULL; } rir_common_block_add(&ctx->common, writeobj); return obj; }
static struct rir_object *rir_convert_init(const struct rir_value *convval, const struct rir_type *totype, struct rir_ctx *ctx) { struct rir_object *retobj = NULL; // at the moment only conversion to string requires special work if (!rir_type_is_specific_elementary(totype, ELEMENTARY_TYPE_STRING)) { if ((!(retobj = rir_object_create(RIR_OBJ_EXPRESSION, ctx->rir)))) { return NULL; } retobj->expr.convert.val = convval; retobj->expr.convert.type = totype; retobj->expr.type = RIR_EXPRESSION_PLACEHOLDER; // to signify we must continue return retobj; } // from here and down it's only about conversion to string if (convval->category == RIR_VALUE_CONSTANT) { // constant value to string conversion can be done easily here at compile time RFS_PUSH(); const struct RFstring *temps = rir_constant_string(convval); if (!(retobj = rir_global_addorget_string(ctx, temps))) { RF_ERROR("Failed to add or get a global string literal to the RIR"); } RFS_POP(); return retobj; } else if (rir_type_is_specific_elementary(convval->type, ELEMENTARY_TYPE_BOOL)) { struct rir_object *obj; // boolean to string conversion requires some branching logic retobj = rir_alloca_create_obj( rir_type_elem_create(ELEMENTARY_TYPE_STRING, false), 0, ctx ); if (!retobj) { return NULL; } rirctx_block_add(ctx, &retobj->expr); struct rir_value *allocv = rir_object_value(retobj); // create the blocks struct rir_block *prev_block = ctx->current_block; struct rir_block *taken_block = rir_block_create(NULL, false, ctx); if (!taken_block) { return NULL; } struct rir_block *fallthrough_block = rir_block_create(NULL, false, ctx); if (!fallthrough_block) { return NULL; } struct rir_block *after_block = rir_block_create(NULL, false, ctx); if (!after_block) { return NULL; } // create the conditional branch to connect to if/else if (!rir_block_exit_init_condbranch( &prev_block->exit, convval, &taken_block->label, &fallthrough_block->label )) { return NULL; } // populate taken block ctx->current_block = taken_block; if (!(obj = rir_global_addorget_string(ctx, &g_str_true))) { RF_ERROR("Failed to add a global string literal to the RIR"); return NULL; } struct rir_expression *e = rir_write_create(allocv, rir_object_value(obj), ctx); if (!e) { return NULL; } rirctx_block_add(ctx, e); if (!rir_block_exit_init_branch(&taken_block->exit, &after_block->label)) { return NULL; } rir_fndef_add_block(ctx->current_fn, taken_block); // populate fallthrough block ctx->current_block = fallthrough_block; if (!(obj = rir_global_addorget_string(ctx, &g_str_false))) { RF_ERROR("Failed to add a global string literal to the RIR"); return NULL; } if (!(e = rir_write_create(allocv, rir_object_value(obj), ctx))) { return NULL; } rirctx_block_add(ctx, e); if (!rir_block_exit_init_branch(&fallthrough_block->exit, &after_block->label)) { return NULL; } rir_fndef_add_block(ctx->current_fn, fallthrough_block); // finally let's go to the after block and return the populated alloca which // should hold the value of the conversion rir_fndef_add_block(ctx->current_fn, after_block); ctx->current_block = after_block; return retobj; } else { RF_CRITICAL_FAIL("Unexpected conversion at RIR formation"); return NULL; } }
struct rir_value *rir_map_getobj_value(struct rir_common *c, const struct RFstring *id) { struct rir_object *obj = rir_map_getobj(c, id); return obj ? rir_object_value(obj) : NULL; }