Skip to content

Commit

Permalink
Made integer values automatically promote to floating-point when used…
Browse files Browse the repository at this point in the history
… as on operand to a math expression where the other operand is a floating-point value
  • Loading branch information
IsaacShelton committed May 25, 2024
1 parent 8960337 commit 45dcbb9
Show file tree
Hide file tree
Showing 8 changed files with 77 additions and 14 deletions.
1 change: 1 addition & 0 deletions include/DRVR/compiler.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
1 change: 1 addition & 0 deletions include/IRGEN/ir_gen_expr.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 ----------------
Expand Down
5 changes: 3 additions & 2 deletions include/IRGEN/ir_gen_type.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 ----------------
Expand Down Expand Up @@ -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
Expand Down
11 changes: 11 additions & 0 deletions src/BKEND/ir_to_llvm.c
Original file line number Diff line number Diff line change
Expand Up @@ -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");
}
Expand Down Expand Up @@ -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);

Expand Down
35 changes: 27 additions & 8 deletions src/IRGEN/ir_gen_expr.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
}
Expand Down Expand Up @@ -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)
Expand All @@ -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)
Expand All @@ -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;
}
}

Expand Down
28 changes: 24 additions & 4 deletions src/IRGEN/ir_gen_type.c
Original file line number Diff line number Diff line change
Expand Up @@ -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(
((
Expand Down Expand Up @@ -765,17 +777,25 @@ 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
// NOTE: This is basically a two-way version of ast_types_conform()
// 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){
Expand Down
1 change: 1 addition & 0 deletions tests/e2e/e2e-runner.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
9 changes: 9 additions & 0 deletions tests/e2e/src/int_to_float_promotion_in_math/main.adept
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@

import basics

func main {
x int = 3
y double = 4

print(x * y)
}

0 comments on commit 45dcbb9

Please sign in to comment.