struct LLVMOpaqueValue *bllvm_compile_rirbop(const struct rir_expression *expr, struct llvm_traversal_ctx *ctx) { LLVMValueRef ret; LLVMValueRef left = bllvm_value_from_rir_value_or_die(expr->binaryop.a, ctx); LLVMValueRef right = bllvm_value_from_rir_value_or_die(expr->binaryop.b, ctx); switch(expr->type) { case RIR_EXPRESSION_ADD: ret = LLVMBuildAdd(ctx->builder, left, right, ""); break; case RIR_EXPRESSION_SUB: ret = LLVMBuildSub(ctx->builder, left, right, ""); break; case RIR_EXPRESSION_MUL: ret = LLVMBuildMul(ctx->builder, left, right, ""); break; case RIR_EXPRESSION_DIV: ret = LLVMBuildUDiv(ctx->builder, left, right, ""); break; default: RF_CRITICAL_FAIL("Should never get anything other than binaryop here"); break; } return ret; }
const struct RFstring *ast_identifier_analyzed_str(const struct ast_node *n) { RF_ASSERT(n->type == AST_IDENTIFIER || n->type == AST_XIDENTIFIER, "Unexpected ast node type"); AST_NODE_ASSERT_STATE(n, AST_NODE_STATE_ANALYZER_PASS1); RF_CRITICAL_FAIL("function not implemented yet"); return NULL; #if 0 // this is not used anywhere atm. If that changes either pass the module // or each node should know which module it belongs to. if (n->type == AST_IDENTIFIER) { return string_table_get_str(a->identifiers_table, n->identifier.hash); } return string_table_get_str(a->identifiers_table, n->xidentifier.id->identifier.hash); #endif }
// populate for generic non-top level type element static bool analyzer_populate_symbol_table_typeelement(struct analyzer_traversal_ctx *ctx, struct ast_node *n) { switch (n->type) { case AST_TYPE_LEAF: return analyzer_populate_symbol_table_typeleaf(ctx, n); case AST_TYPE_OPERATOR: return analyzer_populate_symbol_table_typeelement(ctx, ast_typeop_left(n)) && analyzer_populate_symbol_table_typeelement(ctx, ast_typeop_right(n)); case AST_TYPE_DESCRIPTION: // don't go further into a recursive top level typedesc. Should be handled by the // main loop case AST_XIDENTIFIER: //fallthrough // don't do anything for right part of leaves that are simply identifiers return true; default: RF_CRITICAL_FAIL("Case should never happen"); return false; } }
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; } }
LLVMValueRef bllvm_compile_comparison(const struct rir_expression *expr, struct llvm_traversal_ctx *ctx) { LLVMValueRef left = bllvm_value_from_rir_value_or_die(expr->binaryop.a, ctx); LLVMValueRef right = bllvm_value_from_rir_value_or_die(expr->binaryop.b, ctx); struct rir_type *typea = expr->binaryop.a->type; struct rir_type *typeb = expr->binaryop.b->type; RF_ASSERT(rir_type_is_elementary(typea), "Backend comparisons should only happen with elementary types"); RF_ASSERT(rir_type_is_elementary(typeb), "Backend comparisons should only happen with elementary types"); RF_ASSERT(typea->etype == typeb->etype, "Comparison should only happen with same type"); // TODO: Maybe take into account signedness? if (elementary_type_is_float(typea->etype)) { LLVMRealPredicate llvm_real_compare_type; switch(expr->type) { case RIR_EXPRESSION_CMP_EQ: llvm_real_compare_type = LLVMRealOEQ; break; case RIR_EXPRESSION_CMP_NE: llvm_real_compare_type = LLVMRealONE; break; case RIR_EXPRESSION_CMP_GE: llvm_real_compare_type = LLVMRealOGE; break; case RIR_EXPRESSION_CMP_GT: llvm_real_compare_type = LLVMRealOGT; break; case RIR_EXPRESSION_CMP_LE: llvm_real_compare_type = LLVMRealOLE; break; case RIR_EXPRESSION_CMP_LT: llvm_real_compare_type = LLVMRealOLT; break; default: RF_CRITICAL_FAIL("Illegal operand types at comparison code generation"); return NULL; break; } return LLVMBuildFCmp(ctx->builder, llvm_real_compare_type, left, right, ""); } LLVMIntPredicate llvm_int_compare_type; switch(expr->type) { case RIR_EXPRESSION_CMP_EQ: llvm_int_compare_type = LLVMIntEQ; break; case RIR_EXPRESSION_CMP_NE: llvm_int_compare_type = LLVMIntNE; break; case RIR_EXPRESSION_CMP_GE: llvm_int_compare_type = LLVMIntUGE; break; case RIR_EXPRESSION_CMP_GT: llvm_int_compare_type = LLVMIntUGT; break; case RIR_EXPRESSION_CMP_LE: llvm_int_compare_type = LLVMIntULE; break; case RIR_EXPRESSION_CMP_LT: llvm_int_compare_type = LLVMIntULT; break; default: RF_CRITICAL_FAIL("Illegal operand types at comparison code generation"); return NULL; break; } return LLVMBuildICmp(ctx->builder, llvm_int_compare_type, left, right, ""); }