Skip to content

Commit

Permalink
Refactor float<->float ptr->int and int->enum casts to expressions.
Browse files Browse the repository at this point in the history
  • Loading branch information
lerno committed Jan 5, 2025
1 parent 35812bd commit 8612476
Show file tree
Hide file tree
Showing 11 changed files with 121 additions and 75 deletions.
2 changes: 2 additions & 0 deletions src/compiler/c_codegen.c
Original file line number Diff line number Diff line change
Expand Up @@ -395,9 +395,11 @@ static void c_emit_expr(GenContext *c, CValue *value, Expr *expr)
{
switch (expr->expr_kind)
{
case EXPR_ENUM_FROM_ORD:
case EXPR_PTR_ACCESS:
case EXPR_INT_TO_FLOAT:
case EXPR_INT_TO_PTR:
case EXPR_PTR_TO_INT:
case EXPR_FLOAT_TO_INT:
case EXPR_SLICE_LEN:
case EXPR_DISCARD:
Expand Down
20 changes: 20 additions & 0 deletions src/compiler/compiler_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -3371,8 +3371,10 @@ static inline void expr_set_span(Expr *expr, SourceSpan loc)
return;
case EXPR_SPLAT:
case EXPR_PTR_ACCESS:
case EXPR_ENUM_FROM_ORD:
case EXPR_INT_TO_FLOAT:
case EXPR_INT_TO_PTR:
case EXPR_PTR_TO_INT:
case EXPR_FLOAT_TO_INT:
case EXPR_SLICE_LEN:
case EXPR_DISCARD:
Expand Down Expand Up @@ -3730,6 +3732,16 @@ INLINE void expr_rewrite_ptr_access(Expr *expr, Expr *inner, Type *type)
expr->resolve_status = RESOLVE_DONE;
}

INLINE void expr_rewrite_enum_from_ord(Expr *expr, Type *type)
{
Expr *inner = expr_copy(expr);
assert(inner->resolve_status == RESOLVE_DONE);
expr->expr_kind = EXPR_ENUM_FROM_ORD;
expr->inner_expr = inner;
expr->type = type;
expr->resolve_status = RESOLVE_DONE;
}


INLINE void expr_rewrite_slice_len(Expr *expr, Expr *inner, Type *type)
{
Expand Down Expand Up @@ -3838,6 +3850,14 @@ INLINE void expr_rewrite_to_int_to_ptr(Expr *expr, Type *type)
expr->type = type;
}

INLINE void expr_rewrite_to_ptr_to_int(Expr *expr, Type *type)
{
Expr *inner = expr_copy(expr);
expr->expr_kind = EXPR_PTR_TO_INT;
expr->inner_expr = inner;
expr->type = type;
}

INLINE void expr_rewrite_to_float_to_int(Expr *expr, Type *type)
{
Expr *inner = expr_copy(expr);
Expand Down
2 changes: 2 additions & 0 deletions src/compiler/copying.c
Original file line number Diff line number Diff line change
Expand Up @@ -476,8 +476,10 @@ Expr *copy_expr(CopyStruct *c, Expr *source_expr)
case EXPR_SPLAT:
case EXPR_STRINGIFY:
case EXPR_PTR_ACCESS:
case EXPR_ENUM_FROM_ORD:
case EXPR_INT_TO_FLOAT:
case EXPR_INT_TO_PTR:
case EXPR_PTR_TO_INT:
case EXPR_FLOAT_TO_INT:
case EXPR_SLICE_LEN:
case EXPR_DISCARD:
Expand Down
5 changes: 2 additions & 3 deletions src/compiler/enums.h
Original file line number Diff line number Diff line change
Expand Up @@ -546,9 +546,6 @@ typedef enum
CAST_BSBOOL,
CAST_ERROR,
CAST_EUER,
CAST_FPFP,
CAST_INTENUM,
CAST_PTRINT,
CAST_SLARR,
CAST_VECARR,
CAST_EXPVEC,
Expand Down Expand Up @@ -770,6 +767,7 @@ typedef enum
EXPR_INITIALIZER_LIST,
EXPR_INT_TO_FLOAT,
EXPR_INT_TO_PTR,
EXPR_PTR_TO_INT,
EXPR_LAMBDA,
EXPR_LAST_FAULT,
EXPR_MACRO_BLOCK,
Expand All @@ -781,6 +779,7 @@ typedef enum
EXPR_NOP,
EXPR_OPERATOR_CHARS,
EXPR_OPTIONAL,
EXPR_ENUM_FROM_ORD,
EXPR_OTHER_CONTEXT,
EXPR_POINTER_OFFSET,
EXPR_ADDR_CONVERSION,
Expand Down
9 changes: 6 additions & 3 deletions src/compiler/expr.c
Original file line number Diff line number Diff line change
Expand Up @@ -84,9 +84,11 @@ bool expr_may_addr(Expr *expr)
case EXPR_TEST_HOOK:
case EXPR_VECTOR_FROM_ARRAY:
case EXPR_PTR_ACCESS:
case EXPR_ENUM_FROM_ORD:
case EXPR_FLOAT_TO_INT:
case EXPR_INT_TO_FLOAT:
case EXPR_INT_TO_PTR:
case EXPR_PTR_TO_INT:
case EXPR_SLICE_LEN:
case EXPR_RVALUE:
case EXPR_RECAST:
Expand Down Expand Up @@ -208,6 +210,8 @@ bool expr_is_runtime_const(Expr *expr)
case EXPR_ADDR_CONVERSION:
case EXPR_DISCARD:
case EXPR_INT_TO_PTR:
case EXPR_PTR_TO_INT:
case EXPR_ENUM_FROM_ORD:
return expr_is_runtime_const(expr->inner_expr);
case EXPR_MAKE_ANY:
if (!expr_is_runtime_const(expr->make_any_expr.typeid)) return false;
Expand Down Expand Up @@ -361,15 +365,12 @@ static inline bool expr_cast_is_runtime_const(Expr *expr)
{
case CAST_ERROR:
UNREACHABLE
case CAST_INTENUM:
case CAST_EUER:
case CAST_FPFP:
case CAST_VECARR:
return exprid_is_runtime_const(expr->cast_expr.expr);
case CAST_APTSA:
case CAST_EXPVEC:
return exprid_is_runtime_const(expr->cast_expr.expr);
case CAST_PTRINT:
case CAST_BSBOOL:
case CAST_SLARR:
return exprid_is_runtime_const(expr->cast_expr.expr);
Expand Down Expand Up @@ -606,8 +607,10 @@ bool expr_is_pure(Expr *expr)
case EXPR_MAKE_ANY:
return expr_is_pure(expr->make_any_expr.inner) && expr_is_pure(expr->make_any_expr.typeid);
case EXPR_PTR_ACCESS:
case EXPR_ENUM_FROM_ORD:
case EXPR_INT_TO_FLOAT:
case EXPR_INT_TO_PTR:
case EXPR_PTR_TO_INT:
case EXPR_FLOAT_TO_INT:
case EXPR_SLICE_LEN:
case EXPR_DISCARD:
Expand Down
2 changes: 2 additions & 0 deletions src/compiler/json_output.c
Original file line number Diff line number Diff line change
Expand Up @@ -275,6 +275,8 @@ void print_var_expr(FILE *file, Expr *expr)
case EXPR_FLOAT_TO_INT:
case EXPR_INT_TO_FLOAT:
case EXPR_INT_TO_PTR:
case EXPR_PTR_TO_INT:
case EXPR_ENUM_FROM_ORD:
TODO
break;
case EXPR_PTR_ACCESS:
Expand Down
100 changes: 57 additions & 43 deletions src/compiler/llvm_codegen_expr.c
Original file line number Diff line number Diff line change
Expand Up @@ -1457,10 +1457,6 @@ void llvm_emit_cast(GenContext *c, CastKind cast_kind, Expr *expr, BEValue *valu
return;
case CAST_ERROR:
UNREACHABLE
case CAST_PTRINT:
llvm_value_rvalue(c, value);
value->value = LLVMBuildPtrToInt(c->builder, value->value, llvm_get_type(c, to_type), "ptrxi");
break;
case CAST_APTSA:
llvm_emit_arr_to_slice_cast(c, value, to_type);
break;
Expand All @@ -1470,42 +1466,6 @@ void llvm_emit_cast(GenContext *c, CastKind cast_kind, Expr *expr, BEValue *valu
case CAST_EUER:
REMINDER("Improve fault to err comparison");
break;
case CAST_FPFP:
llvm_value_rvalue(c, value);
value->value = type_convert_will_trunc(to_type, from_type)
? LLVMBuildFPTrunc(c->builder, value->value, llvm_get_type(c, to_type), "fpfptrunc")
: LLVMBuildFPExt(c->builder, value->value, llvm_get_type(c, to_type), "fpfpext");
break;
case CAST_INTENUM:
if (safe_mode_enabled() && c->builder != c->global_builder)
{
llvm_value_rvalue(c, value);
BEValue check;
Decl *decl = to_type_original->canonical->decl;
unsigned max = vec_size(decl->enums.values);
if (type_is_signed(value->type))
{
scratch_buffer_clear();
scratch_buffer_printf("Attempt to convert a negative value (%%d) to enum '%s' failed.", decl->name);
llvm_emit_int_comp_zero(c, &check, value, BINARYOP_LT);
BEValue val;
llvm_emit_panic_on_true(c, check.value, "Attempt to convert negative value to enum failed.", expr->span, scratch_buffer_copy(), value, NULL);
}
scratch_buffer_clear();
scratch_buffer_printf("Attempting to convert %%d to enum '%s' failed as the value exceeds the max ordinal (%u).", decl->name, max - 1);
LLVMValueRef val = llvm_const_int(c, value->type, max);
llvm_emit_int_comp_raw(c, &check, value->type, value->type, value->value, val, BINARYOP_GE);
llvm_emit_panic_on_true(c, check.value, "Failed integer to enum conversion", expr->span, scratch_buffer_copy(), value, NULL);
}
// We might need to extend or truncate.
if (type_size(to_type) != type_size(from_type))
{
llvm_value_rvalue(c, value);
llvm_value_set(value, llvm_zext_trunc(c, value->value, llvm_get_type(c, to_type)), to_type);
return;
}
value->type = type_lowering(to_type);
return;
}
value->type = type_lowering(to_type);
}
Expand Down Expand Up @@ -7227,9 +7187,55 @@ static void llvm_emit_ext_trunc(GenContext *c, BEValue *value, Expr *expr)
llvm_value_rvalue(c, value);
Type *to_type = type_lowering(expr->type);
LLVMTypeRef to = llvm_get_type(c, to_type);
llvm_value_set(value, expr->ext_trunc_expr.is_signed
? llvm_sext_trunc(c, value->value, to)
: llvm_zext_trunc(c, value->value, to), to_type);
LLVMValueRef val;
if (type_is_floatlike(to_type))
{
val = type_convert_will_trunc(to_type, value->type)
? LLVMBuildFPTrunc(c->builder, value->value, llvm_get_type(c, to_type), "fpfptrunc")
: LLVMBuildFPExt(c->builder, value->value, llvm_get_type(c, to_type), "fpfpext");

}
else
{
val = expr->ext_trunc_expr.is_signed
? llvm_sext_trunc(c, value->value, to)
: llvm_zext_trunc(c, value->value, to);
}
llvm_value_set(value, val, to_type);
}
void llvm_emit_enum_from_ord(GenContext *c, BEValue *value, Expr *expr)
{
llvm_emit_expr(c, value, expr->inner_expr);

if (safe_mode_enabled() && c->builder != c->global_builder)
{
llvm_value_rvalue(c, value);
BEValue check;
Decl *decl = type_flatten(expr->type)->decl;
unsigned max = vec_size(decl->enums.values);
if (type_is_signed(value->type))
{
scratch_buffer_clear();
scratch_buffer_printf("Attempt to convert a negative value (%%d) to enum '%s' failed.", decl->name);
llvm_emit_int_comp_zero(c, &check, value, BINARYOP_LT);
BEValue val;
llvm_emit_panic_on_true(c, check.value, "Attempt to convert negative value to enum failed.", expr->span, scratch_buffer_copy(), value, NULL);
}
scratch_buffer_clear();
scratch_buffer_printf("Attempting to convert %%d to enum '%s' failed as the value exceeds the max ordinal (%u).", decl->name, max - 1);
LLVMValueRef val = llvm_const_int(c, value->type, max);
llvm_emit_int_comp_raw(c, &check, value->type, value->type, value->value, val, BINARYOP_GE);
llvm_emit_panic_on_true(c, check.value, "Failed integer to enum conversion", expr->span, scratch_buffer_copy(), value, NULL);
}
// We might need to extend or truncate.
Type *to_type = type_lowering(expr->type);
if (type_size(to_type) != type_size(value->type))
{
llvm_value_rvalue(c, value);
llvm_value_set(value, llvm_zext_trunc(c, value->value, llvm_get_type(c, to_type)), to_type);
return;
}
value->type = type_lowering(to_type);
}

void llvm_emit_expr(GenContext *c, BEValue *value, Expr *expr)
Expand All @@ -7250,6 +7256,9 @@ void llvm_emit_expr(GenContext *c, BEValue *value, Expr *expr)
case EXPR_MEMBER_GET:
case EXPR_NAMED_ARGUMENT:
UNREACHABLE
case EXPR_ENUM_FROM_ORD:
llvm_emit_enum_from_ord(c, value, expr);
return;
case EXPR_MAKE_ANY:
llvm_emit_make_any(c, value, expr);
return;
Expand Down Expand Up @@ -7279,6 +7288,11 @@ void llvm_emit_expr(GenContext *c, BEValue *value, Expr *expr)
llvm_value_set(value, NULL, type_void);
llvm_emit_ignored_expr(c, expr->inner_expr);
return;
case EXPR_PTR_TO_INT:
llvm_emit_expr(c, value, expr->inner_expr);
llvm_value_rvalue(c, value);
llvm_value_set(value, LLVMBuildPtrToInt(c->builder, value->value, llvm_get_type(c, expr->type), "ptrxi"), expr->type);
return;
case EXPR_INT_TO_PTR:
llvm_emit_expr(c, value, expr->inner_expr);
llvm_value_rvalue(c, value);
Expand Down
28 changes: 13 additions & 15 deletions src/compiler/sema_casts.c
Original file line number Diff line number Diff line change
Expand Up @@ -454,16 +454,6 @@ Expr *recursive_may_narrow(Expr *expr, Type *type)
case EXPR_CAST:
switch (expr->cast_expr.kind)
{
case CAST_FPFP:
// If this is a narrowing cast that makes it smaller that then target type
// we're done.
if (type_size(type) >= type_size(expr->type))
{
return NULL;
}
// Otherwise just look through it.
expr = exprptr(expr->cast_expr.expr);
goto RETRY;
default:
// For all other casts we regard them as opaque.
goto CHECK_SIZE;
Expand Down Expand Up @@ -1536,7 +1526,11 @@ static void cast_float_to_float(SemaContext *context, Expr *expr, Type *type)
ASSERT0(type_flatten(type) != type_flatten(expr->type));

// Insert runtime cast if needed.
if (insert_runtime_cast_unless_const(expr, CAST_FPFP, type)) return;
if (!sema_cast_const(expr))
{
expr_rewrite_ext_trunc(expr, type, true);
return;
}

// Otherwise rewrite the const, which may cause rounding.
expr_rewrite_const_float(expr, type, expr->const_expr.fxx.f);
Expand Down Expand Up @@ -1573,7 +1567,11 @@ static void cast_int_to_enum(SemaContext *context, Expr *expr, Type *type)
SEMA_DEPRECATED(expr, "Using casts to convert integers to enums is deprecated in favour of using 'MyEnum.from_ordinal(i)`.");
Type *canonical = type_flatten(type);
ASSERT0(canonical->type_kind == TYPE_ENUM);
if (insert_runtime_cast_unless_const(expr, CAST_INTENUM, type)) return;
if (!sema_cast_const(expr))
{
expr_rewrite_enum_from_ord(expr, type);
return;
}

Decl *enum_decl = canonical->decl;
// Fold the const into the actual enum.
Expand All @@ -1595,7 +1593,7 @@ static void cast_int_to_int(SemaContext *context, Expr *expr, Type *type)
{
// Fold pointer casts if narrowing
// So (int)(uptr)&x => (int)&x in the backend.
if (expr->expr_kind == EXPR_CAST && expr->cast_expr.kind == CAST_PTRINT
if (expr->expr_kind == EXPR_PTR_TO_INT
&& type_size(type) <= type_size(expr->type))
{
expr->type = type;
Expand Down Expand Up @@ -1723,7 +1721,7 @@ static void cast_vec_to_vec(SemaContext *context, Expr *expr, Type *to_type)
switch (to_element->type_kind)
{
case ALL_FLOATS:
insert_runtime_cast(expr, CAST_FPFP, to_type);
expr_rewrite_ext_trunc(expr, to_type, true);
return;
case TYPE_BOOL:
{
Expand Down Expand Up @@ -1959,7 +1957,7 @@ static void cast_ptr_to_int(SemaContext *context, Expr *expr, Type *type)
expr_rewrite_const_int(expr, type, expr->const_expr.ptr);
return;
}
insert_runtime_cast(expr, CAST_PTRINT, type);
expr_rewrite_to_ptr_to_int(expr, type);
}

/**
Expand Down
Loading

0 comments on commit 8612476

Please sign in to comment.