explicit casting works with IR

master
Andrew Kelley 2016-10-09 02:20:01 -04:00
parent 07fe60ded1
commit 77ae3442ef
7 changed files with 835 additions and 670 deletions

View File

@ -29,6 +29,7 @@ struct TypeStructField;
struct CodeGen;
struct ConstExprValue;
struct IrInstruction;
struct IrInstructionCast;
struct IrBasicBlock;
struct IrExecutable {
@ -1121,7 +1122,7 @@ struct FnTableEntry {
AstNode *fn_test_set_node;
AstNode *fn_static_eval_set_node;
ZigList<AstNode *> cast_alloca_list;
ZigList<IrInstructionCast *> cast_alloca_list;
ZigList<StructValExprCodeGen *> struct_val_expr_alloca_list;
ZigList<VariableTableEntry *> variable_list;
ZigList<AstNode *> goto_list;
@ -1435,6 +1436,7 @@ struct IrInstruction {
// if ref_count is zero, instruction can be omitted in codegen
size_t ref_count;
IrInstruction *other;
ReturnKnowledge return_knowledge;
};
struct IrInstructionCondBr {
@ -1547,7 +1549,8 @@ struct IrInstructionCast {
IrInstruction *value;
IrInstruction *dest_type;
bool is_implicit;
CastOp cast_op;
LLVMValueRef tmp_ptr;
};
#endif

View File

@ -25,8 +25,6 @@ static VariableTableEntry *analyze_variable_declaration(CodeGen *g, ImportTableE
BlockContext *context, TypeTableEntry *expected_type, AstNode *node);
static void resolve_struct_type(CodeGen *g, ImportTableEntry *import, TypeTableEntry *struct_type);
static TypeTableEntry *unwrapped_node_type(AstNode *node);
static TypeTableEntry *analyze_cast_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
AstNode *node);
static TypeTableEntry *analyze_error_literal_expr(CodeGen *g, ImportTableEntry *import,
BlockContext *context, AstNode *node, Buf *err_name);
static TypeTableEntry *analyze_block_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
@ -115,7 +113,7 @@ AstNode *first_executing_node(AstNode *node) {
zig_unreachable();
}
static void mark_impure_fn(CodeGen *g, BlockContext *context, AstNode *node) {
void mark_impure_fn(CodeGen *g, BlockContext *context, AstNode *node) {
if (!context->fn_entry) return;
if (!context->fn_entry->is_pure) return;
@ -261,11 +259,6 @@ uint64_t type_size(CodeGen *g, TypeTableEntry *type_entry) {
}
}
static bool is_u8(TypeTableEntry *type) {
return type->id == TypeTableEntryIdInt &&
!type->data.integral.is_signed && type->data.integral.bit_count == 8;
}
static bool is_slice(TypeTableEntry *type) {
return type->id == TypeTableEntryIdStruct && type->data.structure.is_slice;
}
@ -4466,30 +4459,7 @@ static TypeTableEntry *analyze_min_max_value(CodeGen *g, ImportTableEntry *impor
}
}
static TypeTableEntry *resolve_cast(CodeGen *g, BlockContext *context, AstNode *node,
AstNode *expr_node, TypeTableEntry *wanted_type, CastOp op, bool need_alloca)
{
node->data.fn_call_expr.cast_op = op;
ConstExprValue *other_val = &get_resolved_expr(expr_node)->const_val;
TypeTableEntry *other_type = get_resolved_expr(expr_node)->type_entry;
ConstExprValue *const_val = &get_resolved_expr(node)->const_val;
if (other_val->ok) {
eval_const_expr_implicit_cast(node->data.fn_call_expr.cast_op, other_val, other_type,
const_val, wanted_type);
}
if (need_alloca) {
if (context->fn_entry) {
context->fn_entry->cast_alloca_list.append(node);
} else {
assert(get_resolved_expr(node)->const_val.ok);
}
}
return wanted_type;
}
static bool type_is_codegen_pointer(TypeTableEntry *type) {
bool type_is_codegen_pointer(TypeTableEntry *type) {
if (type->id == TypeTableEntryIdPointer) return true;
if (type->id == TypeTableEntryIdFn) return true;
if (type->id == TypeTableEntryIdMaybe) {
@ -4499,256 +4469,6 @@ static bool type_is_codegen_pointer(TypeTableEntry *type) {
return false;
}
static TypeTableEntry *analyze_cast_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
AstNode *node)
{
assert(node->type == NodeTypeFnCallExpr);
AstNode *fn_ref_expr = node->data.fn_call_expr.fn_ref_expr;
size_t actual_param_count = node->data.fn_call_expr.params.length;
if (actual_param_count != 1) {
add_node_error(g, fn_ref_expr, buf_sprintf("cast expression expects exactly one parameter"));
return g->builtin_types.entry_invalid;
}
AstNode *expr_node = node->data.fn_call_expr.params.at(0);
TypeTableEntry *wanted_type = resolve_type(g, fn_ref_expr);
TypeTableEntry *actual_type = analyze_expression(g, import, context, nullptr, expr_node);
TypeTableEntry *wanted_type_canon = get_underlying_type(wanted_type);
TypeTableEntry *actual_type_canon = get_underlying_type(actual_type);
if (wanted_type_canon->id == TypeTableEntryIdInvalid ||
actual_type_canon->id == TypeTableEntryIdInvalid)
{
return g->builtin_types.entry_invalid;
}
// explicit match or non-const to const
if (types_match_const_cast_only(wanted_type, actual_type)) {
return resolve_cast(g, context, node, expr_node, wanted_type, CastOpNoop, false);
}
// explicit cast from bool to int
if (wanted_type_canon->id == TypeTableEntryIdInt &&
actual_type_canon->id == TypeTableEntryIdBool)
{
return resolve_cast(g, context, node, expr_node, wanted_type, CastOpBoolToInt, false);
}
// explicit cast from pointer to isize or usize
if ((wanted_type_canon == g->builtin_types.entry_isize || wanted_type_canon == g->builtin_types.entry_usize) &&
type_is_codegen_pointer(actual_type_canon))
{
return resolve_cast(g, context, node, expr_node, wanted_type, CastOpPtrToInt, false);
}
// explicit cast from isize or usize to pointer
if (wanted_type_canon->id == TypeTableEntryIdPointer &&
(actual_type_canon == g->builtin_types.entry_isize || actual_type_canon == g->builtin_types.entry_usize))
{
return resolve_cast(g, context, node, expr_node, wanted_type, CastOpIntToPtr, false);
}
// explicit widening or shortening cast
if ((wanted_type_canon->id == TypeTableEntryIdInt &&
actual_type_canon->id == TypeTableEntryIdInt) ||
(wanted_type_canon->id == TypeTableEntryIdFloat &&
actual_type_canon->id == TypeTableEntryIdFloat))
{
return resolve_cast(g, context, node, expr_node, wanted_type, CastOpWidenOrShorten, false);
}
// explicit cast from int to float
if (wanted_type_canon->id == TypeTableEntryIdFloat &&
actual_type_canon->id == TypeTableEntryIdInt)
{
return resolve_cast(g, context, node, expr_node, wanted_type, CastOpIntToFloat, false);
}
// explicit cast from float to int
if (wanted_type_canon->id == TypeTableEntryIdInt &&
actual_type_canon->id == TypeTableEntryIdFloat)
{
return resolve_cast(g, context, node, expr_node, wanted_type, CastOpFloatToInt, false);
}
// explicit cast from array to slice
if (is_slice(wanted_type) &&
actual_type->id == TypeTableEntryIdArray &&
types_match_const_cast_only(
wanted_type->data.structure.fields[0].type_entry->data.pointer.child_type,
actual_type->data.array.child_type))
{
return resolve_cast(g, context, node, expr_node, wanted_type, CastOpToUnknownSizeArray, true);
}
// explicit cast from []T to []u8 or []u8 to []T
if (is_slice(wanted_type) && is_slice(actual_type) &&
(is_u8(wanted_type->data.structure.fields[0].type_entry->data.pointer.child_type) ||
is_u8(actual_type->data.structure.fields[0].type_entry->data.pointer.child_type)) &&
(wanted_type->data.structure.fields[0].type_entry->data.pointer.is_const ||
!actual_type->data.structure.fields[0].type_entry->data.pointer.is_const))
{
mark_impure_fn(g, context, node);
return resolve_cast(g, context, node, expr_node, wanted_type, CastOpResizeSlice, true);
}
// explicit cast from [N]u8 to []T
if (is_slice(wanted_type) &&
actual_type->id == TypeTableEntryIdArray &&
is_u8(actual_type->data.array.child_type))
{
mark_impure_fn(g, context, node);
uint64_t child_type_size = type_size(g,
wanted_type->data.structure.fields[0].type_entry->data.pointer.child_type);
if (actual_type->data.array.len % child_type_size == 0) {
return resolve_cast(g, context, node, expr_node, wanted_type, CastOpBytesToSlice, true);
} else {
add_node_error(g, node,
buf_sprintf("unable to convert %s to %s: size mismatch",
buf_ptr(&actual_type->name), buf_ptr(&wanted_type->name)));
return g->builtin_types.entry_invalid;
}
}
// explicit cast from pointer to another pointer
if ((actual_type->id == TypeTableEntryIdPointer || actual_type->id == TypeTableEntryIdFn) &&
(wanted_type->id == TypeTableEntryIdPointer || wanted_type->id == TypeTableEntryIdFn))
{
return resolve_cast(g, context, node, expr_node, wanted_type, CastOpPointerReinterpret, false);
}
// explicit cast from maybe pointer to another maybe pointer
if (actual_type->id == TypeTableEntryIdMaybe &&
(actual_type->data.maybe.child_type->id == TypeTableEntryIdPointer ||
actual_type->data.maybe.child_type->id == TypeTableEntryIdFn) &&
wanted_type->id == TypeTableEntryIdMaybe &&
(wanted_type->data.maybe.child_type->id == TypeTableEntryIdPointer ||
wanted_type->data.maybe.child_type->id == TypeTableEntryIdFn))
{
return resolve_cast(g, context, node, expr_node, wanted_type, CastOpPointerReinterpret, false);
}
// explicit cast from child type of maybe type to maybe type
if (wanted_type->id == TypeTableEntryIdMaybe) {
if (types_match_const_cast_only(wanted_type->data.maybe.child_type, actual_type)) {
get_resolved_expr(node)->return_knowledge = ReturnKnowledgeKnownNonNull;
return resolve_cast(g, context, node, expr_node, wanted_type, CastOpMaybeWrap, true);
} else if (actual_type->id == TypeTableEntryIdNumLitInt ||
actual_type->id == TypeTableEntryIdNumLitFloat)
{
if (num_lit_fits_in_other_type(g, expr_node, wanted_type->data.maybe.child_type)) {
get_resolved_expr(node)->return_knowledge = ReturnKnowledgeKnownNonNull;
return resolve_cast(g, context, node, expr_node, wanted_type, CastOpMaybeWrap, true);
} else {
return g->builtin_types.entry_invalid;
}
}
}
// explicit cast from null literal to maybe type
if (wanted_type->id == TypeTableEntryIdMaybe &&
actual_type->id == TypeTableEntryIdNullLit)
{
get_resolved_expr(node)->return_knowledge = ReturnKnowledgeKnownNull;
return resolve_cast(g, context, node, expr_node, wanted_type, CastOpNullToMaybe, true);
}
// explicit cast from child type of error type to error type
if (wanted_type->id == TypeTableEntryIdErrorUnion) {
if (types_match_const_cast_only(wanted_type->data.error.child_type, actual_type)) {
get_resolved_expr(node)->return_knowledge = ReturnKnowledgeKnownNonError;
return resolve_cast(g, context, node, expr_node, wanted_type, CastOpErrorWrap, true);
} else if (actual_type->id == TypeTableEntryIdNumLitInt ||
actual_type->id == TypeTableEntryIdNumLitFloat)
{
if (num_lit_fits_in_other_type(g, expr_node, wanted_type->data.error.child_type)) {
get_resolved_expr(node)->return_knowledge = ReturnKnowledgeKnownNonError;
return resolve_cast(g, context, node, expr_node, wanted_type, CastOpErrorWrap, true);
} else {
return g->builtin_types.entry_invalid;
}
}
}
// explicit cast from pure error to error union type
if (wanted_type->id == TypeTableEntryIdErrorUnion &&
actual_type->id == TypeTableEntryIdPureError)
{
get_resolved_expr(node)->return_knowledge = ReturnKnowledgeKnownError;
return resolve_cast(g, context, node, expr_node, wanted_type, CastOpPureErrorWrap, false);
}
// explicit cast from number literal to another type
if (actual_type->id == TypeTableEntryIdNumLitFloat ||
actual_type->id == TypeTableEntryIdNumLitInt)
{
if (num_lit_fits_in_other_type(g, expr_node, wanted_type_canon)) {
CastOp op;
if ((actual_type->id == TypeTableEntryIdNumLitFloat &&
wanted_type_canon->id == TypeTableEntryIdFloat) ||
(actual_type->id == TypeTableEntryIdNumLitInt &&
wanted_type_canon->id == TypeTableEntryIdInt))
{
op = CastOpNoop;
} else if (wanted_type_canon->id == TypeTableEntryIdInt) {
op = CastOpFloatToInt;
} else if (wanted_type_canon->id == TypeTableEntryIdFloat) {
op = CastOpIntToFloat;
} else {
zig_unreachable();
}
return resolve_cast(g, context, node, expr_node, wanted_type, op, false);
} else {
return g->builtin_types.entry_invalid;
}
}
// explicit cast from %void to integer type which can fit it
bool actual_type_is_void_err = actual_type->id == TypeTableEntryIdErrorUnion &&
!type_has_bits(actual_type->data.error.child_type);
bool actual_type_is_pure_err = actual_type->id == TypeTableEntryIdPureError;
if ((actual_type_is_void_err || actual_type_is_pure_err) &&
wanted_type->id == TypeTableEntryIdInt)
{
BigNum bn;
bignum_init_unsigned(&bn, g->error_decls.length);
if (bignum_fits_in_bits(&bn, wanted_type->data.integral.bit_count,
wanted_type->data.integral.is_signed))
{
return resolve_cast(g, context, node, expr_node, wanted_type, CastOpErrToInt, false);
} else {
add_node_error(g, node,
buf_sprintf("too many error values to fit in '%s'", buf_ptr(&wanted_type->name)));
return g->builtin_types.entry_invalid;
}
}
// explicit cast from integer to enum type with no payload
if (actual_type->id == TypeTableEntryIdInt &&
wanted_type->id == TypeTableEntryIdEnum &&
wanted_type->data.enumeration.gen_field_count == 0)
{
return resolve_cast(g, context, node, expr_node, wanted_type, CastOpIntToEnum, false);
}
// explicit cast from enum type with no payload to integer
if (wanted_type->id == TypeTableEntryIdInt &&
actual_type->id == TypeTableEntryIdEnum &&
actual_type->data.enumeration.gen_field_count == 0)
{
return resolve_cast(g, context, node, expr_node, wanted_type, CastOpEnumToInt, false);
}
add_node_error(g, node,
buf_sprintf("invalid cast from type '%s' to '%s'",
buf_ptr(&actual_type->name),
buf_ptr(&wanted_type->name)));
return g->builtin_types.entry_invalid;
}
static TypeTableEntry *analyze_import(CodeGen *g, ImportTableEntry *import, BlockContext *context,
AstNode *node)
{
@ -5866,13 +5586,14 @@ static TypeTableEntry *analyze_fn_call_ptr(CodeGen *g, ImportTableEntry *import,
}
}
if (handle_is_ptr(return_type)) {
if (context->fn_entry) {
context->fn_entry->cast_alloca_list.append(node);
} else if (!result_val->ok) {
add_node_error(g, node, buf_sprintf("unable to evaluate constant expression"));
}
}
// TODO
//if (handle_is_ptr(return_type)) {
// if (context->fn_entry) {
// context->fn_entry->cast_alloca_list.append(node);
// } else if (!result_val->ok) {
// add_node_error(g, node, buf_sprintf("unable to evaluate constant expression"));
// }
//}
return return_type;
}
@ -6110,7 +5831,7 @@ static TypeTableEntry *analyze_fn_call_expr(CodeGen *g, ImportTableEntry *import
if (const_val->ok) {
if (invoke_type_entry->id == TypeTableEntryIdMetaType) {
return analyze_cast_expr(g, import, context, node);
zig_unreachable();
} else if (invoke_type_entry->id == TypeTableEntryIdFn) {
AstNode *struct_node;
if (fn_ref_expr->type == NodeTypeFieldAccessExpr &&

View File

@ -49,10 +49,14 @@ TypeTableEntry *resolve_peer_type_compatibility(CodeGen *g, ImportTableEntry *im
BlockContext *block_context, AstNode *parent_source_node,
AstNode **child_nodes, TypeTableEntry **child_types, size_t child_count);
bool types_match_const_cast_only(TypeTableEntry *expected_type, TypeTableEntry *actual_type);
VariableTableEntry *find_variable(CodeGen *g, BlockContext *orig_context, Buf *name);
AstNode *find_decl(BlockContext *context, Buf *name);
void resolve_top_level_decl(CodeGen *g, AstNode *node, bool pointer_only);
TopLevelDecl *get_as_top_level_decl(AstNode *node);
void mark_impure_fn(CodeGen *g, BlockContext *context, AstNode *node);
bool type_is_codegen_pointer(TypeTableEntry *type);
#endif

File diff suppressed because it is too large Load Diff

View File

@ -773,6 +773,7 @@ void eval_const_expr_implicit_cast(CastOp cast_op,
case CastOpEnumToInt:
bignum_init_unsigned(&const_val->data.x_bignum, other_val->data.x_enum.tag);
const_val->ok = true;
break;
}
}

View File

@ -1,6 +1,7 @@
#include "analyze.hpp"
#include "ir.hpp"
#include "error.hpp"
#include "eval.hpp"
#include "ir.hpp"
struct IrVarSlot {
ConstExprValue value;
@ -100,12 +101,12 @@ static T *ir_build_instruction(IrBuilder *irb, AstNode *source_node) {
}
static IrInstruction *ir_build_cast(IrBuilder *irb, AstNode *source_node, IrInstruction *dest_type,
IrInstruction *value, bool is_implicit)
IrInstruction *value, CastOp cast_op)
{
IrInstructionCast *cast_instruction = ir_build_instruction<IrInstructionCast>(irb, source_node);
cast_instruction->dest_type = dest_type;
cast_instruction->value = value;
cast_instruction->is_implicit = is_implicit;
cast_instruction->cast_op = cast_op;
return &cast_instruction->base;
}
@ -117,6 +118,13 @@ static IrInstruction *ir_build_return(IrBuilder *irb, AstNode *source_node, IrIn
return &return_instruction->base;
}
static IrInstruction *ir_build_const(IrBuilder *irb, AstNode *source_node, TypeTableEntry *type_entry) {
IrInstructionConst *const_instruction = ir_build_instruction<IrInstructionConst>(irb, source_node);
const_instruction->base.type_entry = type_entry;
const_instruction->base.static_value.ok = true;
return &const_instruction->base;
}
static IrInstruction *ir_build_const_void(IrBuilder *irb, AstNode *source_node) {
IrInstructionConst *const_instruction = ir_build_instruction<IrInstructionConst>(irb, source_node);
const_instruction->base.type_entry = irb->codegen->builtin_types.entry_void;
@ -133,14 +141,20 @@ static IrInstruction *ir_build_const_bignum(IrBuilder *irb, AstNode *source_node
return &const_instruction->base;
}
static IrInstruction *ir_build_const_type(IrBuilder *irb, AstNode *source_node, TypeTableEntry *type_entry) {
IrInstructionConst *const_instruction = ir_build_instruction<IrInstructionConst>(irb, source_node);
static IrInstruction *ir_create_const_type(IrBuilder *irb, AstNode *source_node, TypeTableEntry *type_entry) {
IrInstructionConst *const_instruction = ir_create_instruction<IrInstructionConst>(irb->exec, source_node);
const_instruction->base.type_entry = irb->codegen->builtin_types.entry_type;
const_instruction->base.static_value.ok = true;
const_instruction->base.static_value.data.x_type = type_entry;
return &const_instruction->base;
}
static IrInstruction *ir_build_const_type(IrBuilder *irb, AstNode *source_node, TypeTableEntry *type_entry) {
IrInstruction *instruction = ir_create_const_type(irb, source_node, type_entry);
ir_instruction_append(irb->current_basic_block, instruction);
return instruction;
}
static IrInstruction *ir_build_const_fn(IrBuilder *irb, AstNode *source_node, FnTableEntry *fn_entry) {
IrInstructionConst *const_instruction = ir_build_instruction<IrInstructionConst>(irb, source_node);
const_instruction->base.type_entry = fn_entry->type_entry;
@ -174,6 +188,16 @@ static IrInstruction *ir_build_load_var(IrBuilder *irb, AstNode *source_node, Va
return &load_var_instruction->base;
}
static IrInstruction *ir_build_call(IrBuilder *irb, AstNode *source_node,
IrInstruction *fn, size_t arg_count, IrInstruction **args)
{
IrInstructionCall *call_instruction = ir_build_instruction<IrInstructionCall>(irb, source_node);
call_instruction->fn = fn;
call_instruction->arg_count = arg_count;
call_instruction->args = args;
return &call_instruction->base;
}
//static size_t get_conditional_defer_count(BlockContext *inner_block, BlockContext *outer_block) {
// size_t result = 0;
@ -409,6 +433,26 @@ static IrInstruction *ir_gen_symbol(IrBuilder *irb, AstNode *node, bool pointer_
return irb->codegen->invalid_instruction;
}
static IrInstruction *ir_gen_fn_call(IrBuilder *irb, AstNode *node) {
assert(node->type == NodeTypeFnCallExpr);
if (node->data.fn_call_expr.is_builtin) {
zig_panic("TODO ir gen builtin fn");
}
AstNode *fn_ref_node = node->data.fn_call_expr.fn_ref_expr;
IrInstruction *fn = ir_gen_node(irb, fn_ref_node, node->block_context);
size_t arg_count = node->data.fn_call_expr.params.length;
IrInstruction **args = allocate<IrInstruction*>(arg_count);
for (size_t i = 0; i < arg_count; i += 1) {
AstNode *arg_node = node->data.fn_call_expr.params.at(i);
args[i] = ir_gen_node(irb, arg_node, node->block_context);
}
return ir_build_call(irb, node, fn, arg_count, args);
}
static IrInstruction *ir_gen_node_extra(IrBuilder *irb, AstNode *node, BlockContext *block_context,
bool pointer_only)
{
@ -423,12 +467,13 @@ static IrInstruction *ir_gen_node_extra(IrBuilder *irb, AstNode *node, BlockCont
return ir_gen_num_lit(irb, node);
case NodeTypeSymbol:
return ir_gen_symbol(irb, node, pointer_only);
case NodeTypeFnCallExpr:
return ir_gen_fn_call(irb, node);
case NodeTypeUnwrapErrorExpr:
case NodeTypeReturnExpr:
case NodeTypeDefer:
case NodeTypeVariableDeclaration:
case NodeTypePrefixOpExpr:
case NodeTypeFnCallExpr:
case NodeTypeArrayAccessExpr:
case NodeTypeSliceExpr:
case NodeTypeFieldAccessExpr:
@ -782,6 +827,296 @@ static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, IrInstruction *pare
return ir_determine_peer_types(ira, parent_instruction, instructions, instruction_count);
}
static IrInstruction *ir_resolve_cast(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *value,
IrInstruction *dest_type, CastOp cast_op, bool need_alloca)
{
assert(dest_type->type_entry->id == TypeTableEntryIdMetaType);
assert(dest_type->static_value.ok);
TypeTableEntry *wanted_type = dest_type->static_value.data.x_type;
if (value->static_value.ok) {
IrInstruction *result = ir_build_const(&ira->new_irb, source_instr->source_node, wanted_type);
eval_const_expr_implicit_cast(cast_op, &value->static_value, value->type_entry,
&result->static_value, wanted_type);
return result;
} else {
IrInstruction *result = ir_build_cast(&ira->new_irb, source_instr->source_node,
dest_type->other, value->other, cast_op);
result->type_entry = wanted_type;
if (need_alloca && source_instr->source_node->block_context->fn_entry) {
IrInstructionCast *cast_instruction = (IrInstructionCast *)result;
source_instr->source_node->block_context->fn_entry->cast_alloca_list.append(cast_instruction);
}
return result;
}
}
static bool is_slice(TypeTableEntry *type) {
return type->id == TypeTableEntryIdStruct && type->data.structure.is_slice;
}
static bool is_u8(TypeTableEntry *type) {
return type->id == TypeTableEntryIdInt &&
!type->data.integral.is_signed && type->data.integral.bit_count == 8;
}
static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_instr,
IrInstruction *dest_type, IrInstruction *value)
{
assert(dest_type->type_entry->id == TypeTableEntryIdMetaType);
assert(dest_type->static_value.ok);
TypeTableEntry *wanted_type = dest_type->static_value.data.x_type;
TypeTableEntry *actual_type = value->type_entry;
TypeTableEntry *wanted_type_canon = get_underlying_type(wanted_type);
TypeTableEntry *actual_type_canon = get_underlying_type(actual_type);
TypeTableEntry *isize_type = ira->codegen->builtin_types.entry_isize;
TypeTableEntry *usize_type = ira->codegen->builtin_types.entry_usize;
if (wanted_type_canon->id == TypeTableEntryIdInvalid ||
actual_type_canon->id == TypeTableEntryIdInvalid)
{
return ira->codegen->invalid_instruction;
}
// explicit match or non-const to const
if (types_match_const_cast_only(wanted_type, actual_type)) {
return ir_resolve_cast(ira, source_instr, value, dest_type, CastOpNoop, false);
}
// explicit cast from bool to int
if (wanted_type_canon->id == TypeTableEntryIdInt &&
actual_type_canon->id == TypeTableEntryIdBool)
{
return ir_resolve_cast(ira, source_instr, value, dest_type, CastOpBoolToInt, false);
}
// explicit cast from pointer to isize or usize
if ((wanted_type_canon == isize_type || wanted_type_canon == usize_type) &&
type_is_codegen_pointer(actual_type_canon))
{
return ir_resolve_cast(ira, source_instr, value, dest_type, CastOpPtrToInt, false);
}
// explicit cast from isize or usize to pointer
if (wanted_type_canon->id == TypeTableEntryIdPointer &&
(actual_type_canon == isize_type || actual_type_canon == usize_type))
{
return ir_resolve_cast(ira, source_instr, value, dest_type, CastOpIntToPtr, false);
}
// explicit widening or shortening cast
if ((wanted_type_canon->id == TypeTableEntryIdInt &&
actual_type_canon->id == TypeTableEntryIdInt) ||
(wanted_type_canon->id == TypeTableEntryIdFloat &&
actual_type_canon->id == TypeTableEntryIdFloat))
{
return ir_resolve_cast(ira, source_instr, value, dest_type, CastOpWidenOrShorten, false);
}
// explicit cast from int to float
if (wanted_type_canon->id == TypeTableEntryIdFloat &&
actual_type_canon->id == TypeTableEntryIdInt)
{
return ir_resolve_cast(ira, source_instr, value, dest_type, CastOpIntToFloat, false);
}
// explicit cast from float to int
if (wanted_type_canon->id == TypeTableEntryIdInt &&
actual_type_canon->id == TypeTableEntryIdFloat)
{
return ir_resolve_cast(ira, source_instr, value, dest_type, CastOpFloatToInt, false);
}
// explicit cast from array to slice
if (is_slice(wanted_type) &&
actual_type->id == TypeTableEntryIdArray &&
types_match_const_cast_only(
wanted_type->data.structure.fields[0].type_entry->data.pointer.child_type,
actual_type->data.array.child_type))
{
return ir_resolve_cast(ira, source_instr, value, dest_type, CastOpToUnknownSizeArray, true);
}
// explicit cast from []T to []u8 or []u8 to []T
if (is_slice(wanted_type) && is_slice(actual_type) &&
(is_u8(wanted_type->data.structure.fields[0].type_entry->data.pointer.child_type) ||
is_u8(actual_type->data.structure.fields[0].type_entry->data.pointer.child_type)) &&
(wanted_type->data.structure.fields[0].type_entry->data.pointer.is_const ||
!actual_type->data.structure.fields[0].type_entry->data.pointer.is_const))
{
mark_impure_fn(ira->codegen, source_instr->source_node->block_context, source_instr->source_node);
return ir_resolve_cast(ira, source_instr, value, dest_type, CastOpResizeSlice, true);
}
// explicit cast from [N]u8 to []T
if (is_slice(wanted_type) &&
actual_type->id == TypeTableEntryIdArray &&
is_u8(actual_type->data.array.child_type))
{
mark_impure_fn(ira->codegen, source_instr->source_node->block_context, source_instr->source_node);
uint64_t child_type_size = type_size(ira->codegen,
wanted_type->data.structure.fields[0].type_entry->data.pointer.child_type);
if (actual_type->data.array.len % child_type_size == 0) {
return ir_resolve_cast(ira, source_instr, value, dest_type, CastOpBytesToSlice, true);
} else {
add_node_error(ira->codegen, source_instr->source_node,
buf_sprintf("unable to convert %s to %s: size mismatch",
buf_ptr(&actual_type->name), buf_ptr(&wanted_type->name)));
return ira->codegen->invalid_instruction;
}
}
// explicit cast from pointer to another pointer
if ((actual_type->id == TypeTableEntryIdPointer || actual_type->id == TypeTableEntryIdFn) &&
(wanted_type->id == TypeTableEntryIdPointer || wanted_type->id == TypeTableEntryIdFn))
{
return ir_resolve_cast(ira, source_instr, value, dest_type, CastOpPointerReinterpret, false);
}
// explicit cast from maybe pointer to another maybe pointer
if (actual_type->id == TypeTableEntryIdMaybe &&
(actual_type->data.maybe.child_type->id == TypeTableEntryIdPointer ||
actual_type->data.maybe.child_type->id == TypeTableEntryIdFn) &&
wanted_type->id == TypeTableEntryIdMaybe &&
(wanted_type->data.maybe.child_type->id == TypeTableEntryIdPointer ||
wanted_type->data.maybe.child_type->id == TypeTableEntryIdFn))
{
return ir_resolve_cast(ira, source_instr, value, dest_type, CastOpPointerReinterpret, false);
}
// explicit cast from child type of maybe type to maybe type
if (wanted_type->id == TypeTableEntryIdMaybe) {
if (types_match_const_cast_only(wanted_type->data.maybe.child_type, actual_type)) {
IrInstruction *cast_instruction = ir_resolve_cast(ira, source_instr, value, dest_type,
CastOpMaybeWrap, true);
cast_instruction->return_knowledge = ReturnKnowledgeKnownNonNull;
return cast_instruction;
} else if (actual_type->id == TypeTableEntryIdNumLitInt ||
actual_type->id == TypeTableEntryIdNumLitFloat)
{
if (ir_num_lit_fits_in_other_type(ira, value, wanted_type->data.maybe.child_type)) {
IrInstruction *cast_instruction = ir_resolve_cast(ira, source_instr, value, dest_type,
CastOpMaybeWrap, true);
cast_instruction->return_knowledge = ReturnKnowledgeKnownNonNull;
return cast_instruction;
} else {
return ira->codegen->invalid_instruction;
}
}
}
// explicit cast from null literal to maybe type
if (wanted_type->id == TypeTableEntryIdMaybe &&
actual_type->id == TypeTableEntryIdNullLit)
{
IrInstruction *cast_instruction = ir_resolve_cast(ira, source_instr, value, dest_type,
CastOpNullToMaybe, true);
cast_instruction->return_knowledge = ReturnKnowledgeKnownNull;
return cast_instruction;
}
// explicit cast from child type of error type to error type
if (wanted_type->id == TypeTableEntryIdErrorUnion) {
if (types_match_const_cast_only(wanted_type->data.error.child_type, actual_type)) {
IrInstruction *cast_instruction = ir_resolve_cast(ira, source_instr, value, dest_type,
CastOpErrorWrap, true);
cast_instruction->return_knowledge = ReturnKnowledgeKnownNonError;
return cast_instruction;
} else if (actual_type->id == TypeTableEntryIdNumLitInt ||
actual_type->id == TypeTableEntryIdNumLitFloat)
{
if (ir_num_lit_fits_in_other_type(ira, value, wanted_type->data.error.child_type)) {
IrInstruction *cast_instruction = ir_resolve_cast(ira, source_instr, value, dest_type,
CastOpErrorWrap, true);
cast_instruction->return_knowledge = ReturnKnowledgeKnownNonError;
return cast_instruction;
} else {
return ira->codegen->invalid_instruction;
}
}
}
// explicit cast from pure error to error union type
if (wanted_type->id == TypeTableEntryIdErrorUnion &&
actual_type->id == TypeTableEntryIdPureError)
{
IrInstruction *cast_instruction = ir_resolve_cast(ira, source_instr, value, dest_type,
CastOpPureErrorWrap, false);
cast_instruction->return_knowledge = ReturnKnowledgeKnownError;
return cast_instruction;
}
// explicit cast from number literal to another type
if (actual_type->id == TypeTableEntryIdNumLitFloat ||
actual_type->id == TypeTableEntryIdNumLitInt)
{
if (ir_num_lit_fits_in_other_type(ira, value, wanted_type_canon)) {
CastOp op;
if ((actual_type->id == TypeTableEntryIdNumLitFloat &&
wanted_type_canon->id == TypeTableEntryIdFloat) ||
(actual_type->id == TypeTableEntryIdNumLitInt &&
wanted_type_canon->id == TypeTableEntryIdInt))
{
op = CastOpNoop;
} else if (wanted_type_canon->id == TypeTableEntryIdInt) {
op = CastOpFloatToInt;
} else if (wanted_type_canon->id == TypeTableEntryIdFloat) {
op = CastOpIntToFloat;
} else {
zig_unreachable();
}
return ir_resolve_cast(ira, source_instr, value, dest_type, op, false);
} else {
return ira->codegen->invalid_instruction;
}
}
// explicit cast from %void to integer type which can fit it
bool actual_type_is_void_err = actual_type->id == TypeTableEntryIdErrorUnion &&
!type_has_bits(actual_type->data.error.child_type);
bool actual_type_is_pure_err = actual_type->id == TypeTableEntryIdPureError;
if ((actual_type_is_void_err || actual_type_is_pure_err) &&
wanted_type->id == TypeTableEntryIdInt)
{
BigNum bn;
bignum_init_unsigned(&bn, ira->codegen->error_decls.length);
if (bignum_fits_in_bits(&bn, wanted_type->data.integral.bit_count,
wanted_type->data.integral.is_signed))
{
return ir_resolve_cast(ira, source_instr, value, dest_type, CastOpErrToInt, false);
} else {
add_node_error(ira->codegen, source_instr->source_node,
buf_sprintf("too many error values to fit in '%s'", buf_ptr(&wanted_type->name)));
return ira->codegen->invalid_instruction;
}
}
// explicit cast from integer to enum type with no payload
if (actual_type->id == TypeTableEntryIdInt &&
wanted_type->id == TypeTableEntryIdEnum &&
wanted_type->data.enumeration.gen_field_count == 0)
{
return ir_resolve_cast(ira, source_instr, value, dest_type, CastOpIntToEnum, false);
}
// explicit cast from enum type with no payload to integer
if (wanted_type->id == TypeTableEntryIdInt &&
actual_type->id == TypeTableEntryIdEnum &&
actual_type->data.enumeration.gen_field_count == 0)
{
return ir_resolve_cast(ira, source_instr, value, dest_type, CastOpEnumToInt, false);
}
add_node_error(ira->codegen, source_instr->source_node,
buf_sprintf("invalid cast from type '%s' to '%s'",
buf_ptr(&actual_type->name),
buf_ptr(&wanted_type->name)));
return ira->codegen->invalid_instruction;
}
static IrInstruction *ir_get_casted_value(IrAnalyze *ira, IrInstruction *value, TypeTableEntry *expected_type) {
assert(value);
assert(value != ira->old_irb.codegen->invalid_instruction);
@ -806,10 +1141,8 @@ static IrInstruction *ir_get_casted_value(IrAnalyze *ira, IrInstruction *value,
case ImplicitCastMatchResultYes:
{
IrInstruction *dest_type = ir_build_const_type(&ira->new_irb, value->source_node, expected_type);
bool is_implicit = true;
IrInstruction *cast_instruction = ir_build_cast(&ira->new_irb, value->source_node, dest_type,
value, is_implicit);
IrInstruction *dest_type = ir_create_const_type(&ira->new_irb, value->source_node, expected_type);
IrInstruction *cast_instruction = ir_analyze_cast(ira, value, dest_type, value);
return cast_instruction;
}
case ImplicitCastMatchResultReportedError:
@ -849,18 +1182,41 @@ static TypeTableEntry *ir_analyze_bin_op_bool(IrAnalyze *ira, IrInstructionBinOp
IrInstruction *op1 = bin_op_instruction->op1;
IrInstruction *op2 = bin_op_instruction->op2;
IrInstruction *casted_op1 = ir_get_casted_value(ira, op1->other, ira->old_irb.codegen->builtin_types.entry_bool);
TypeTableEntry *bool_type = ira->old_irb.codegen->builtin_types.entry_bool;
IrInstruction *casted_op1 = ir_get_casted_value(ira, op1->other, bool_type);
if (casted_op1 == ira->old_irb.codegen->invalid_instruction)
return ira->old_irb.codegen->builtin_types.entry_invalid;
IrInstruction *casted_op2 = ir_get_casted_value(ira, op2->other, ira->old_irb.codegen->builtin_types.entry_bool);
IrInstruction *casted_op2 = ir_get_casted_value(ira, op2->other, bool_type);
if (casted_op2 == ira->old_irb.codegen->invalid_instruction)
return ira->old_irb.codegen->builtin_types.entry_invalid;
ConstExprValue *op1_val = &casted_op1->static_value;
ConstExprValue *op2_val = &casted_op2->static_value;
if (op1_val->ok && op2_val->ok) {
ConstExprValue *out_val = &bin_op_instruction->base.static_value;
bin_op_instruction->base.other = &bin_op_instruction->base;
assert(op1->type_entry->id == TypeTableEntryIdBool);
assert(op2->type_entry->id == TypeTableEntryIdBool);
if (bin_op_instruction->op_id == IrBinOpBoolOr) {
out_val->data.x_bool = op1_val->data.x_bool || op2_val->data.x_bool;
} else if (bin_op_instruction->op_id == IrBinOpBoolAnd) {
out_val->data.x_bool = op1_val->data.x_bool && op2_val->data.x_bool;
} else {
zig_unreachable();
}
out_val->ok = true;
out_val->depends_on_compile_var = op1_val->depends_on_compile_var ||
op2_val->depends_on_compile_var;
return bool_type;
}
ir_link_new(ir_build_bin_op(&ira->new_irb, bin_op_instruction->base.source_node,
bin_op_instruction->op_id, op1->other, op2->other), &bin_op_instruction->base);
return ira->old_irb.codegen->builtin_types.entry_bool;
return bool_type;
}
static TypeTableEntry *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp *bin_op_instruction) {
@ -925,12 +1281,109 @@ static TypeTableEntry *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp
zig_unreachable();
}
zig_panic("TODO interpret bin_op_cmp");
ir_link_new(ir_build_bin_op(&ira->new_irb, bin_op_instruction->base.source_node,
op_id, op1->other, op2->other), &bin_op_instruction->base);
return ira->old_irb.codegen->builtin_types.entry_bool;
}
static uint64_t max_unsigned_val(TypeTableEntry *type_entry) {
assert(type_entry->id == TypeTableEntryIdInt);
if (type_entry->data.integral.bit_count == 64) {
return UINT64_MAX;
} else if (type_entry->data.integral.bit_count == 32) {
return UINT32_MAX;
} else if (type_entry->data.integral.bit_count == 16) {
return UINT16_MAX;
} else if (type_entry->data.integral.bit_count == 8) {
return UINT8_MAX;
} else {
zig_unreachable();
}
}
static int ir_eval_bignum(ConstExprValue *op1_val, ConstExprValue *op2_val,
ConstExprValue *out_val, bool (*bignum_fn)(BigNum *, BigNum *, BigNum *),
TypeTableEntry *type, bool wrapping_op)
{
bool overflow = bignum_fn(&out_val->data.x_bignum, &op1_val->data.x_bignum, &op2_val->data.x_bignum);
if (overflow) {
return ErrorOverflow;
}
if (type->id == TypeTableEntryIdInt && !bignum_fits_in_bits(&out_val->data.x_bignum,
type->data.integral.bit_count, type->data.integral.is_signed))
{
if (wrapping_op) {
if (type->data.integral.is_signed) {
out_val->data.x_bignum.data.x_uint = max_unsigned_val(type) - out_val->data.x_bignum.data.x_uint + 1;
out_val->data.x_bignum.is_negative = !out_val->data.x_bignum.is_negative;
} else if (out_val->data.x_bignum.is_negative) {
out_val->data.x_bignum.data.x_uint = max_unsigned_val(type) - out_val->data.x_bignum.data.x_uint + 1;
out_val->data.x_bignum.is_negative = false;
} else {
bignum_truncate(&out_val->data.x_bignum, type->data.integral.bit_count);
}
} else {
return ErrorOverflow;
}
}
out_val->ok = true;
out_val->depends_on_compile_var = op1_val->depends_on_compile_var || op2_val->depends_on_compile_var;
return 0;
}
static int ir_eval_math_op(ConstExprValue *op1_val, TypeTableEntry *op1_type,
IrBinOp op_id, ConstExprValue *op2_val, TypeTableEntry *op2_type, ConstExprValue *out_val)
{
switch (op_id) {
case IrBinOpInvalid:
case IrBinOpBoolOr:
case IrBinOpBoolAnd:
case IrBinOpCmpEq:
case IrBinOpCmpNotEq:
case IrBinOpCmpLessThan:
case IrBinOpCmpGreaterThan:
case IrBinOpCmpLessOrEq:
case IrBinOpCmpGreaterOrEq:
case IrBinOpArrayCat:
case IrBinOpArrayMult:
zig_unreachable();
case IrBinOpBinOr:
return ir_eval_bignum(op1_val, op2_val, out_val, bignum_or, op1_type, false);
case IrBinOpBinXor:
return ir_eval_bignum(op1_val, op2_val, out_val, bignum_xor, op1_type, false);
case IrBinOpBinAnd:
return ir_eval_bignum(op1_val, op2_val, out_val, bignum_and, op1_type, false);
case IrBinOpBitShiftLeft:
return ir_eval_bignum(op1_val, op2_val, out_val, bignum_shl, op1_type, false);
case IrBinOpBitShiftLeftWrap:
return ir_eval_bignum(op1_val, op2_val, out_val, bignum_shl, op1_type, true);
case IrBinOpBitShiftRight:
return ir_eval_bignum(op1_val, op2_val, out_val, bignum_shr, op1_type, false);
case IrBinOpAdd:
return ir_eval_bignum(op1_val, op2_val, out_val, bignum_add, op1_type, false);
case IrBinOpAddWrap:
return ir_eval_bignum(op1_val, op2_val, out_val, bignum_add, op1_type, true);
case IrBinOpSub:
return ir_eval_bignum(op1_val, op2_val, out_val, bignum_sub, op1_type, false);
case IrBinOpSubWrap:
return ir_eval_bignum(op1_val, op2_val, out_val, bignum_sub, op1_type, true);
case IrBinOpMult:
return ir_eval_bignum(op1_val, op2_val, out_val, bignum_mul, op1_type, false);
case IrBinOpMultWrap:
return ir_eval_bignum(op1_val, op2_val, out_val, bignum_mul, op1_type, true);
case IrBinOpDiv:
return ir_eval_bignum(op1_val, op2_val, out_val, bignum_div, op1_type, false);
case IrBinOpMod:
return ir_eval_bignum(op1_val, op2_val, out_val, bignum_mod, op1_type, false);
}
zig_unreachable();
}
static TypeTableEntry *ir_analyze_bin_op_math(IrAnalyze *ira, IrInstructionBinOp *bin_op_instruction) {
IrInstruction *op1 = bin_op_instruction->op1;
IrInstruction *op2 = bin_op_instruction->op2;
@ -955,12 +1408,39 @@ static TypeTableEntry *ir_analyze_bin_op_math(IrAnalyze *ira, IrInstructionBinOp
// float
} else {
AstNode *source_node = bin_op_instruction->base.source_node;
add_node_error(ira->old_irb.codegen, source_node, buf_sprintf("invalid operands to binary expression: '%s' and '%s'",
add_node_error(ira->old_irb.codegen, source_node,
buf_sprintf("invalid operands to binary expression: '%s' and '%s'",
buf_ptr(&op1->type_entry->name),
buf_ptr(&op2->type_entry->name)));
return ira->old_irb.codegen->builtin_types.entry_invalid;
}
if (op1->static_value.ok && op2->static_value.ok) {
ConstExprValue *op1_val = &op1->static_value;
ConstExprValue *op2_val = &op2->static_value;
ConstExprValue *out_val = &bin_op_instruction->base.static_value;
bin_op_instruction->base.other = &bin_op_instruction->base;
int err;
if ((err = ir_eval_math_op(op1_val, resolved_type, op_id, op2_val, resolved_type, out_val))) {
if (err == ErrorDivByZero) {
add_node_error(ira->codegen, bin_op_instruction->base.source_node,
buf_sprintf("division by zero is undefined"));
return ira->codegen->builtin_types.entry_invalid;
} else if (err == ErrorOverflow) {
add_node_error(ira->codegen, bin_op_instruction->base.source_node,
buf_sprintf("value cannot be represented in any integer type"));
return ira->codegen->builtin_types.entry_invalid;
}
return ira->codegen->builtin_types.entry_invalid;
}
ir_num_lit_fits_in_other_type(ira, &bin_op_instruction->base, resolved_type);
return resolved_type;
}
ir_link_new(ir_build_bin_op(&ira->new_irb, bin_op_instruction->base.source_node,
op_id, op1->other, op2->other), &bin_op_instruction->base);
@ -1011,6 +1491,40 @@ static TypeTableEntry *ir_analyze_instruction_load_var(IrAnalyze *ira, IrInstruc
return load_var_instruction->var->type;
}
static TypeTableEntry *ir_analyze_instruction_call(IrAnalyze *ira, IrInstructionCall *call_instruction) {
IrInstruction *fn_ref = call_instruction->fn->other;
if (fn_ref->type_entry->id == TypeTableEntryIdInvalid)
return ira->codegen->builtin_types.entry_invalid;
if (fn_ref->static_value.ok) {
if (fn_ref->type_entry->id == TypeTableEntryIdMetaType) {
size_t actual_param_count = call_instruction->arg_count;
if (actual_param_count != 1) {
add_node_error(ira->codegen, call_instruction->base.source_node,
buf_sprintf("cast expression expects exactly one parameter"));
return ira->codegen->builtin_types.entry_invalid;
}
IrInstruction *arg = call_instruction->args[0];
IrInstruction *cast_instruction = ir_analyze_cast(ira, &call_instruction->base, fn_ref, arg);
if (cast_instruction == ira->codegen->invalid_instruction)
return ira->codegen->builtin_types.entry_invalid;
ir_link_new(cast_instruction, &call_instruction->base);
return cast_instruction->type_entry;
} else {
zig_panic("TODO analyze more fn call types");
}
} else {
//ir_link_new(ir_build_call(&ira->new_irb, call_instruction->base.source_node,
// call_instruction->fn, call_instruction->arg_count, call_instruction->args),
// &call_instruction->base);
zig_panic("TODO analyze fn call");
}
}
static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstruction *instruction) {
switch (instruction->id) {
case IrInstructionIdInvalid:
@ -1023,11 +1537,12 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi
return ir_analyze_instruction_bin_op(ira, (IrInstructionBinOp *)instruction);
case IrInstructionIdLoadVar:
return ir_analyze_instruction_load_var(ira, (IrInstructionLoadVar *)instruction);
case IrInstructionIdCall:
return ir_analyze_instruction_call(ira, (IrInstructionCall *)instruction);
case IrInstructionIdCondBr:
case IrInstructionIdSwitchBr:
case IrInstructionIdPhi:
case IrInstructionIdStoreVar:
case IrInstructionIdCall:
case IrInstructionIdBuiltinCall:
case IrInstructionIdCast:
zig_panic("TODO analyze more instructions");

View File

@ -20,7 +20,7 @@ static void ir_print_prefix(IrPrint *irp, IrInstruction *instruction) {
static void ir_print_return(IrPrint *irp, IrInstructionReturn *return_instruction) {
ir_print_prefix(irp, &return_instruction->base);
assert(return_instruction->value);
fprintf(irp->f, "return #%zu;\n", return_instruction->value->debug_id);
fprintf(irp->f, "return #%zu\n", return_instruction->value->debug_id);
}
static void ir_print_const(IrPrint *irp, IrInstructionConst *const_instruction) {
@ -43,8 +43,10 @@ static void ir_print_const(IrPrint *irp, IrInstructionConst *const_instruction)
fprintf(irp->f, "%s%llu\n", negative_str, bignum->data.x_uint);
break;
}
case TypeTableEntryIdVar:
case TypeTableEntryIdMetaType:
fprintf(irp->f, "%s\n", buf_ptr(&const_instruction->base.static_value.data.x_type->name));
break;
case TypeTableEntryIdVar:
case TypeTableEntryIdBool:
case TypeTableEntryIdUnreachable:
case TypeTableEntryIdInt:
@ -139,6 +141,25 @@ static void ir_print_load_var(IrPrint *irp, IrInstructionLoadVar *load_var_instr
buf_ptr(&load_var_instruction->var->name));
}
static void ir_print_cast(IrPrint *irp, IrInstructionCast *cast_instruction) {
ir_print_prefix(irp, &cast_instruction->base);
fprintf(irp->f, "cast #%zu to #%zu\n",
cast_instruction->value->debug_id,
cast_instruction->dest_type->debug_id);
}
static void ir_print_call(IrPrint *irp, IrInstructionCall *call_instruction) {
ir_print_prefix(irp, &call_instruction->base);
fprintf(irp->f, "#%zu(", call_instruction->fn->debug_id);
for (size_t i = 0; i < call_instruction->arg_count; i += 1) {
IrInstruction *arg = call_instruction->args[i];
if (i != 0)
fprintf(irp->f, ", ");
fprintf(irp->f, "#%zu", arg->debug_id);
}
fprintf(irp->f, ")\n");
}
static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
switch (instruction->id) {
case IrInstructionIdInvalid:
@ -155,13 +176,17 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
case IrInstructionIdLoadVar:
ir_print_load_var(irp, (IrInstructionLoadVar *)instruction);
break;
case IrInstructionIdCast:
ir_print_cast(irp, (IrInstructionCast *)instruction);
break;
case IrInstructionIdCall:
ir_print_call(irp, (IrInstructionCall *)instruction);
break;
case IrInstructionIdCondBr:
case IrInstructionIdSwitchBr:
case IrInstructionIdPhi:
case IrInstructionIdStoreVar:
case IrInstructionIdCall:
case IrInstructionIdBuiltinCall:
case IrInstructionIdCast:
zig_panic("TODO print more IR instructions");
}
}