diff --git a/include/DRVR/compiler.h b/include/DRVR/compiler.h index 226aa645..f253d86e 100644 --- a/include/DRVR/compiler.h +++ b/include/DRVR/compiler.h @@ -138,6 +138,7 @@ typedef struct compiler { #define CROSS_COMPILE_WINDOWS 0x01 #define CROSS_COMPILE_MACOS 0x02 #define CROSS_COMPILE_WASM32 0x03 +#define CROSS_COMPILE_LINUX 0x04 // ---------------- compiler_run ---------------- // Runs a compiler with the given arguments. diff --git a/include/IRGEN/ir_gen_expr.h b/include/IRGEN/ir_gen_expr.h index 7ae5fb8f..f55077ef 100644 --- a/include/IRGEN/ir_gen_expr.h +++ b/include/IRGEN/ir_gen_expr.h @@ -48,6 +48,7 @@ typedef struct { maybe_null_weak_cstr_t override; bool commutative : 1; bool result_is_boolean : 1; + bool allow_type_merging : 1; } ir_gen_math_spec_t; // ---------------- ir_gen_expr ---------------- diff --git a/include/IRGEN/ir_gen_type.h b/include/IRGEN/ir_gen_type.h index 950a8d2f..e6ad96f7 100644 --- a/include/IRGEN/ir_gen_type.h +++ b/include/IRGEN/ir_gen_type.h @@ -40,13 +40,14 @@ #define CONFORM_MODE_CLASS_POINTERS TRAIT_B // Allow conforming class pointers #define CONFORM_MODE_USER_EXPLICIT TRAIT_C // Allow explicit user-defined conversions via __as__ #define CONFORM_MODE_USER_IMPLICIT TRAIT_D // Allow implicit user-defined conversions via __as__ +#define CONFORM_MODE_INT_TO_FLOAT TRAIT_E // Allow implicit conversion from integers to floats #define CONFORM_MODE_ALL TRAIT_ALL // Allow all conformation methods #define CONFORM_MODE_CALL_ARGUMENTS CONFORM_MODE_STANDARD #define CONFORM_MODE_CALL_ARGUMENTS_LOOSE_NOUSER CONFORM_MODE_PRIMITIVES | CONFORM_MODE_VARIADIC | CONFORM_MODE_POINTERPTR | CONFORM_MODE_PTR_TO_BOOL | CONFORM_MODE_CLASS_POINTERS #define CONFORM_MODE_CALL_ARGUMENTS_LOOSE CONFORM_MODE_CALL_ARGUMENTS_LOOSE_NOUSER | CONFORM_MODE_USER_IMPLICIT #define CONFORM_MODE_ASSIGNING CONFORM_MODE_PRIMITIVES | CONFORM_MODE_POINTERPTR | CONFORM_MODE_PTR_TO_BOOL | CONFORM_MODE_INT_TO_BOOL | CONFORM_MODE_CLASS_POINTERS | CONFORM_MODE_USER_IMPLICIT -#define CONFORM_MODE_CALCULATION CONFORM_MODE_PRIMITIVES | CONFORM_MODE_POINTERPTR | CONFORM_MODE_PTR_TO_BOOL | CONFORM_MODE_INT_TO_BOOL +#define CONFORM_MODE_CALCULATION CONFORM_MODE_PRIMITIVES | CONFORM_MODE_POINTERPTR | CONFORM_MODE_PTR_TO_BOOL | CONFORM_MODE_INT_TO_BOOL | CONFORM_MODE_INT_TO_FLOAT #define CONFORM_MODE_RETURN CONFORM_MODE_CALCULATION | CONFORM_MODE_USER_IMPLICIT // ---------------- ir_gen_type_mappings ---------------- @@ -75,7 +76,7 @@ errorcode_t ir_gen_merge_unknown_enum_like_into_plural_unknown_enum(ir_builder_t // Attempts to find a common AST type for two IR values // and merge them into a common AST type. Returns true // if successfully merged them to a common AST type. -successful_t ast_types_merge(ir_builder_t *builder, ir_value_t **ir_value_a, ir_value_t **ir_value_b, ast_type_t *ast_type_a, ast_type_t *ast_type_b); +successful_t ast_types_merge(ir_builder_t *builder, ir_value_t **ir_value_a, ir_value_t **ir_value_b, ast_type_t *ast_type_a, ast_type_t *ast_type_b, ast_type_t *out_common_type, trait_t mode); // ---------------- ast_layout_bone_to_ir_type ---------------- // Converts an ast_layout_bone_t to an ir_type_t diff --git a/src/BKEND/ir_to_llvm.c b/src/BKEND/ir_to_llvm.c index 1280d2ba..91f19a88 100644 --- a/src/BKEND/ir_to_llvm.c +++ b/src/BKEND/ir_to_llvm.c @@ -60,6 +60,8 @@ static char *get_triple(compiler_t *compiler){ return LLVMCreateMessage("x86_64-pc-windows-gnu"); case CROSS_COMPILE_MACOS: return LLVMCreateMessage("x86_64-apple-darwin19.6.0"); + case CROSS_COMPILE_LINUX: + return LLVMCreateMessage("x86_64-unknown-linux-gnu"); case CROSS_COMPILE_WASM32: return LLVMCreateMessage("wasm32-unknown-unknown"); } @@ -519,6 +521,15 @@ errorcode_t ir_to_llvm(compiler_t *compiler, object_t *object){ free(link_command); return SUCCESS; } + + if(compiler->cross_compile_for == CROSS_COMPILE_LINUX){ + // Don't support linking output Mach-O object files + printf("GNU/Linux Object File Generated (Requires Manual Linking)\n"); + printf("\nLink Command: '%s'\n", link_command); + free(objfile_filename); + free(link_command); + return SUCCESS; + } debug_signal(compiler, DEBUG_SIGNAL_AT_LINKING, NULL); diff --git a/src/IRGEN/ir_gen_expr.c b/src/IRGEN/ir_gen_expr.c index 9bbc7866..614242c7 100644 --- a/src/IRGEN/ir_gen_expr.c +++ b/src/IRGEN/ir_gen_expr.c @@ -139,11 +139,12 @@ errorcode_t ir_gen_expr(ir_builder_t *builder, ast_expr_t *expr, ir_value_t **ir case EXPR_BIT_LGC_LSHIFT: case EXPR_BIT_RSHIFT: case EXPR_BIT_LGC_RSHIFT: { - const ir_gen_math_spec_t *info = &ir_gen_math_specs[expr->id]; + ir_gen_math_spec_t info = ir_gen_math_specs[expr->id]; + info.allow_type_merging = true; - assert(info->choices.method != INSTR_CHOOSING_METHOD_NONE); + assert(info.choices.method != INSTR_CHOOSING_METHOD_NONE); - if(ir_gen_expr_math(builder, (ast_expr_math_t*) expr, ir_value, out_expr_type, info)){ + if(ir_gen_expr_math(builder, (ast_expr_math_t*) expr, ir_value, out_expr_type, &info)){ return FAILURE; } } @@ -2689,8 +2690,21 @@ errorcode_t ir_gen_math( ast_type_t *out_expr_type, const ir_gen_math_spec_t *info ){ - // Conform the second value to the type of the first - if(!ast_types_conform(builder, &ops->rhs, ops->rhs_type, ops->lhs_type, CONFORM_MODE_CALCULATION)){ + ast_type_t common_ast_type = AST_TYPE_NONE; + + if(info->allow_type_merging) { + // Merge the values + if(!ast_types_merge(builder, &ops->lhs, &ops->rhs, ops->lhs_type, ops->rhs_type, &common_ast_type, CONFORM_MODE_CALCULATION)){ + common_ast_type = AST_TYPE_NONE; + } + } else { + // Conform the second value to the type of the first + if(ast_types_conform(builder, &ops->rhs, ops->rhs_type, ops->lhs_type, CONFORM_MODE_CALCULATION)){ + common_ast_type = ast_type_clone(ops->lhs_type); + } + } + + if(AST_TYPE_IS_NONE(common_ast_type)){ if(info->override){ *ir_value = info->commutative ? handle_math_management_allow_other_direction(builder, ops, source, out_expr_type, info->override) @@ -2708,10 +2722,14 @@ errorcode_t ir_gen_math( return FAILURE; } + ir_type_t *common_ir_type = ops->lhs->type; + // Determine which instruction to use - ir_instr_id_t instr_id = ir_instr_choosing_run(&info->choices, ops->lhs->type); + ir_instr_id_t instr_id = ir_instr_choosing_run(&info->choices, common_ir_type); if(instr_id == INSTRUCTION_NONE){ + ast_type_free(&common_ast_type); + // Try to use the overriden function if it exists *ir_value = info->override ? handle_math_management(builder, ops, source, out_expr_type, info->override) @@ -2729,14 +2747,15 @@ errorcode_t ir_gen_math( return FAILURE; } - *ir_value = build_math(builder, instr_id, ops->lhs, ops->rhs, info->result_is_boolean ? ir_builder_bool(builder) : ops->lhs->type); + *ir_value = build_math(builder, instr_id, ops->lhs, ops->rhs, info->result_is_boolean ? ir_builder_bool(builder) : common_ir_type); // Write the result type, will either be a boolean or the same type as the given arguments if(out_expr_type != NULL){ if(info->result_is_boolean){ *out_expr_type = ast_type_make_base(strclone("bool")); + ast_type_free(&common_ast_type); } else { - *out_expr_type = ast_type_clone(ops->lhs_type); + *out_expr_type = common_ast_type; } } diff --git a/src/IRGEN/ir_gen_type.c b/src/IRGEN/ir_gen_type.c index 54bd4d26..8dc6cb8f 100644 --- a/src/IRGEN/ir_gen_type.c +++ b/src/IRGEN/ir_gen_type.c @@ -379,6 +379,18 @@ successful_t ast_types_conform(ir_builder_t *builder, ir_value_t **ir_value, ast return true; } + // Integer to float + if(mode & CONFORM_MODE_INT_TO_FLOAT && from_traits & TYPE_TRAIT_INTEGER && (to_type_kind == TYPE_KIND_FLOAT || to_type_kind == TYPE_KIND_DOUBLE)){ + if(ir_gen_resolve_type(builder->compiler, builder->object, ast_to_type, &ir_to_type)) return false; + + if (IS_TYPE_KIND_SIGNED(from_type_kind)) { + *ir_value = build_sitofp(builder, *ir_value, ir_to_type); + } else { + *ir_value = build_uitofp(builder, *ir_value, ir_to_type); + } + return true; + } + // Do bitcast if appropriate if( (( @@ -765,7 +777,7 @@ errorcode_t ir_gen_merge_unknown_enum_like_into_plural_unknown_enum(ir_builder_t return FAILURE; } -successful_t ast_types_merge(ir_builder_t *builder, ir_value_t **ir_value_a, ir_value_t **ir_value_b, ast_type_t *ast_type_a, ast_type_t *ast_type_b){ +successful_t ast_types_merge(ir_builder_t *builder, ir_value_t **ir_value_a, ir_value_t **ir_value_b, ast_type_t *ast_type_a, ast_type_t *ast_type_b, ast_type_t *out_common_type, trait_t mode){ // NOTE: _____RETURNS TRUE ON SUCCESSFUL MERGE_____ // NOTE: If the types are not identical, then this function will attempt to make // the two values have a common type @@ -773,9 +785,17 @@ successful_t ast_types_merge(ir_builder_t *builder, ir_value_t **ir_value_a, ir_ // NOTE: This function can be used as a substitute for ast_types_identical if the desired // behavior is to make two values conform to each other, for one-way casting use ast_types_conform() - if(ast_types_conform(builder, ir_value_a, ast_type_a, ast_type_b, CONFORM_MODE_STANDARD)) return false; - if(ast_types_conform(builder, ir_value_b, ast_type_b, ast_type_a, CONFORM_MODE_STANDARD)) return false; - return true; + if(ast_types_conform(builder, ir_value_a, ast_type_a, ast_type_b, mode)){ + *out_common_type = ast_type_clone(ast_type_b); + return true; + } + + if(ast_types_conform(builder, ir_value_b, ast_type_b, ast_type_a, mode)){ + *out_common_type = ast_type_clone(ast_type_a); + return true; + } + + return false; } ir_type_t *ast_layout_bone_to_ir_type(compiler_t *compiler, object_t *object, ast_layout_bone_t *bone, ast_poly_catalog_t *optional_catalog){ diff --git a/tests/e2e/e2e-runner.py b/tests/e2e/e2e-runner.py index f38b32ca..171965af 100644 --- a/tests/e2e/e2e-runner.py +++ b/tests/e2e/e2e-runner.py @@ -175,6 +175,7 @@ def run_all_tests(): test("inner_struct", [executable, join(src_dir, "inner_struct/main.adept")], compiles) test("inner_struct_polymorphic", [executable, join(src_dir, "inner_struct_polymorphic/main.adept")], compiles) test("int_ptr_cast", [executable, join(src_dir, "int_ptr_cast/main.adept")], compiles) + test("int_to_float_promotion_in_math", [executable, join(src_dir, "int_to_float_promotion_in_math/main.adept")], compiles) test("internal_deference", [executable, join(src_dir, "internal_deference/main.adept")], compiles) test("internal_deference_generic", [executable, join(src_dir, "internal_deference_generic/main.adept")], compiles) test("list_map", [executable, join(src_dir, "list_map/main.adept")], compiles) diff --git a/tests/e2e/src/int_to_float_promotion_in_math/main.adept b/tests/e2e/src/int_to_float_promotion_in_math/main.adept new file mode 100644 index 00000000..75d183ea --- /dev/null +++ b/tests/e2e/src/int_to_float_promotion_in_math/main.adept @@ -0,0 +1,9 @@ + +import basics + +func main { + x int = 3 + y double = 4 + + print(x * y) +}