diff --git a/src/all_types.hpp b/src/all_types.hpp index 59f63e58f0..b28099ba2f 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -1452,6 +1452,7 @@ enum IrInstructionId { IrInstructionIdSliceType, IrInstructionIdAsm, IrInstructionIdCompileVar, + IrInstructionIdSizeOf, }; struct IrInstruction { @@ -1742,6 +1743,12 @@ struct IrInstructionCompileVar { IrInstruction *name; }; +struct IrInstructionSizeOf { + IrInstruction base; + + IrInstruction *type_value; +}; + enum LValPurpose { LValPurposeNone, LValPurposeAssign, diff --git a/src/codegen.cpp b/src/codegen.cpp index 89af7dedab..6ed09db852 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -1444,6 +1444,7 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, case IrInstructionIdArrayType: case IrInstructionIdSliceType: case IrInstructionIdCompileVar: + case IrInstructionIdSizeOf: zig_unreachable(); case IrInstructionIdReturn: return ir_render_return(g, executable, (IrInstructionReturn *)instruction); diff --git a/src/ir.cpp b/src/ir.cpp index 8d3ae9ac69..34b6bcaed9 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -222,6 +222,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionCompileVar *) { return IrInstructionIdCompileVar; } +static constexpr IrInstructionId ir_instruction_id(IrInstructionSizeOf *) { + return IrInstructionIdSizeOf; +} + template static T *ir_create_instruction(IrExecutable *exec, AstNode *source_node) { T *special_instruction = allocate(1); @@ -865,6 +869,15 @@ static IrInstruction *ir_build_compile_var(IrBuilder *irb, AstNode *source_node, return &instruction->base; } +static IrInstruction *ir_build_size_of(IrBuilder *irb, AstNode *source_node, IrInstruction *type_value) { + IrInstructionSizeOf *instruction = ir_build_instruction(irb, source_node); + instruction->type_value = type_value; + + ir_ref_instruction(type_value); + + return &instruction->base; +} + static void ir_gen_defers_for_block(IrBuilder *irb, BlockContext *inner_block, BlockContext *outer_block, bool gen_error_defers, bool gen_maybe_defers) { @@ -1356,9 +1369,17 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, AstNode *node) { return ir_build_compile_var(irb, node, arg0_value); } + case BuiltinFnIdSizeof: + { + AstNode *arg0_node = node->data.fn_call_expr.params.at(0); + IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, node->block_context); + if (arg0_value == irb->codegen->invalid_instruction) + return arg0_value; + + return ir_build_size_of(irb, node, arg0_value); + } case BuiltinFnIdMemcpy: case BuiltinFnIdMemset: - case BuiltinFnIdSizeof: case BuiltinFnIdAlignof: case BuiltinFnIdMaxValue: case BuiltinFnIdMinValue: @@ -4417,6 +4438,56 @@ static TypeTableEntry *ir_analyze_instruction_compile_var(IrAnalyze *ira, zig_unreachable(); } +static TypeTableEntry *ir_analyze_instruction_size_of(IrAnalyze *ira, + IrInstructionSizeOf *size_of_instruction) +{ + IrInstruction *type_value = size_of_instruction->type_value->other; + TypeTableEntry *type_entry = ir_resolve_type(ira, type_value); + TypeTableEntry *canon_type_entry = get_underlying_type(type_entry); + switch (canon_type_entry->id) { + case TypeTableEntryIdInvalid: + return ira->codegen->builtin_types.entry_invalid; + case TypeTableEntryIdTypeDecl: + zig_unreachable(); + case TypeTableEntryIdVar: + case TypeTableEntryIdUnreachable: + case TypeTableEntryIdUndefLit: + case TypeTableEntryIdNullLit: + case TypeTableEntryIdBlock: + case TypeTableEntryIdNumLitFloat: + case TypeTableEntryIdNumLitInt: + case TypeTableEntryIdGenericFn: + case TypeTableEntryIdMetaType: + case TypeTableEntryIdFn: + case TypeTableEntryIdNamespace: + add_node_error(ira->codegen, size_of_instruction->base.source_node, + buf_sprintf("no size available for type '%s'", buf_ptr(&type_entry->name))); + // TODO if this is a typedecl, add error note showing the declaration of the type decl + return ira->codegen->builtin_types.entry_invalid; + case TypeTableEntryIdVoid: + case TypeTableEntryIdBool: + case TypeTableEntryIdInt: + case TypeTableEntryIdFloat: + case TypeTableEntryIdPointer: + case TypeTableEntryIdArray: + case TypeTableEntryIdStruct: + case TypeTableEntryIdMaybe: + case TypeTableEntryIdErrorUnion: + case TypeTableEntryIdPureError: + case TypeTableEntryIdEnum: + case TypeTableEntryIdUnion: + { + uint64_t size_in_bytes = type_size(ira->codegen, type_entry); + bool depends_on_compile_var = false; // TODO types should be able to depend on compile var + ConstExprValue *out_val = ir_build_const_from(ira, &size_of_instruction->base, + depends_on_compile_var); + bignum_init_unsigned(&out_val->data.x_bignum, size_in_bytes); + return ira->codegen->builtin_types.entry_num_lit_int; + } + } + zig_unreachable(); +} + static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstruction *instruction) { switch (instruction->id) { case IrInstructionIdInvalid: @@ -4471,6 +4542,8 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi return ir_analyze_instruction_array_type(ira, (IrInstructionArrayType *)instruction); case IrInstructionIdCompileVar: return ir_analyze_instruction_compile_var(ira, (IrInstructionCompileVar *)instruction); + case IrInstructionIdSizeOf: + return ir_analyze_instruction_size_of(ira, (IrInstructionSizeOf *)instruction); case IrInstructionIdSwitchBr: case IrInstructionIdCast: case IrInstructionIdContainerInitList: @@ -4580,6 +4653,7 @@ bool ir_has_side_effects(IrInstruction *instruction) { case IrInstructionIdArrayType: case IrInstructionIdSliceType: case IrInstructionIdCompileVar: + case IrInstructionIdSizeOf: return false; case IrInstructionIdAsm: { @@ -5248,24 +5322,6 @@ IrInstruction *ir_exec_const_result(IrExecutable *exec) { // // return builtin_fn->return_type; // } -// case BuiltinFnIdSizeof: -// { -// AstNode *type_node = node->data.fn_call_expr.params.at(0); -// TypeTableEntry *type_entry = analyze_type_expr(g, import, context, type_node); -// if (type_entry->id == TypeTableEntryIdInvalid) { -// return g->builtin_types.entry_invalid; -// } else if (type_entry->id == TypeTableEntryIdUnreachable) { -// add_node_error(g, first_executing_node(type_node), -// buf_sprintf("no size available for type '%s'", buf_ptr(&type_entry->name))); -// return g->builtin_types.entry_invalid; -// } else { -// uint64_t size_in_bytes = type_size(g, type_entry); -// bool depends_on_compile_var = (type_entry == g->builtin_types.entry_usize || -// type_entry == g->builtin_types.entry_isize); -// return resolve_expr_const_val_as_unsigned_num_lit(g, node, expected_type, -// size_in_bytes, depends_on_compile_var); -// } -// } // case BuiltinFnIdAlignof: // { // AstNode *type_node = node->data.fn_call_expr.params.at(0); @@ -8044,7 +8100,6 @@ static void analyze_goto_pass2(CodeGen *g, ImportTableEntry *import, AstNode *no // LLVMBuildCall(g->builder, builtin_fn->fn_val, params, 5, ""); // return nullptr; // } -// case BuiltinFnIdSizeof: // case BuiltinFnIdAlignof: // case BuiltinFnIdMinValue: // case BuiltinFnIdMaxValue: diff --git a/src/ir_print.cpp b/src/ir_print.cpp index 7ae1794a28..c65334d0d7 100644 --- a/src/ir_print.cpp +++ b/src/ir_print.cpp @@ -36,7 +36,8 @@ static void ir_print_const_value(IrPrint *irp, TypeTableEntry *type_entry, Const } switch (type_entry->id) { case TypeTableEntryIdInvalid: - zig_unreachable(); + fprintf(irp->f, "(invalid)"); + break; case TypeTableEntryIdVoid: fprintf(irp->f, "{}"); break; @@ -490,6 +491,12 @@ static void ir_print_compile_var(IrPrint *irp, IrInstructionCompileVar *instruct fprintf(irp->f, ")"); } +static void ir_print_size_of(IrPrint *irp, IrInstructionSizeOf *instruction) { + fprintf(irp->f, "@sizeOf("); + ir_print_other_instruction(irp, instruction->type_value); + fprintf(irp->f, ")"); +} + static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { ir_print_prefix(irp, instruction); switch (instruction->id) { @@ -582,6 +589,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { case IrInstructionIdCompileVar: ir_print_compile_var(irp, (IrInstructionCompileVar *)instruction); break; + case IrInstructionIdSizeOf: + ir_print_size_of(irp, (IrInstructionSizeOf *)instruction); + break; case IrInstructionIdSwitchBr: zig_panic("TODO print more IR instructions"); }