From df03fcf5f07e0d5d16e5b837658265f6c468cbe4 Mon Sep 17 00:00:00 2001 From: Vexu Date: Thu, 16 Jan 2020 17:12:43 +0200 Subject: [PATCH] implement `@bitSizeOf` --- doc/langref.html.in | 15 ++++++++++++++- src/all_types.hpp | 4 ++++ src/codegen.cpp | 1 + src/ir.cpp | 12 +++++++++--- src/ir_print.cpp | 5 ++++- test/stage1/behavior/sizeof_and_typeof.zig | 11 +++++++++++ 6 files changed, 43 insertions(+), 5 deletions(-) diff --git a/doc/langref.html.in b/doc/langref.html.in index 092e303013..88e6b41983 100644 --- a/doc/langref.html.in +++ b/doc/langref.html.in @@ -6815,6 +6815,19 @@ async fn func(y: *i32) void {

{#header_close#} + {#header_open|@bitSizeOf#} +
{#syntax#}@bitSizeOf(comptime T: type) comptime_int{#endsyntax#}
+

+ This function returns the number of bits it takes to store {#syntax#}T{#endsyntax#} in memory. + The result is a target-specific compile time constant. +

+

+ This function measures the size at runtime. For types that are disallowed at runtime, such as + {#syntax#}comptime_int{#endsyntax#} and {#syntax#}type{#endsyntax#}, the result is {#syntax#}0{#endsyntax#}. +

+ {#see_also|@sizeOf|@typeInfo#} + {#header_close#} + {#header_open|@breakpoint#}
{#syntax#}@breakpoint(){#endsyntax#}

@@ -8044,7 +8057,7 @@ test "@setRuntimeSafety" { This function measures the size at runtime. For types that are disallowed at runtime, such as {#syntax#}comptime_int{#endsyntax#} and {#syntax#}type{#endsyntax#}, the result is {#syntax#}0{#endsyntax#}.

- {#see_also|@typeInfo#} + {#see_also|@bitSizeOf|@typeInfo#} {#header_close#} {#header_open|@sliceToBytes#} diff --git a/src/all_types.hpp b/src/all_types.hpp index 0fed73f7b2..4d6f68daff 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -358,6 +358,8 @@ struct LazyValueSizeOf { IrAnalyze *ira; IrInstruction *target_type; + + bool bit_size; }; struct LazyValueSliceType { @@ -1754,6 +1756,7 @@ enum BuiltinFnId { BuiltinFnIdFrameSize, BuiltinFnIdAs, BuiltinFnIdCall, + BuiltinFnIdBitSizeof, }; struct BuiltinFnEntry { @@ -3146,6 +3149,7 @@ struct IrInstructionAsmGen { struct IrInstructionSizeOf { IrInstruction base; + bool bit_size; IrInstruction *type_value; }; diff --git a/src/codegen.cpp b/src/codegen.cpp index 95b55675bb..cd009b3bea 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -8299,6 +8299,7 @@ static void define_builtin_fns(CodeGen *g) { create_builtin_fn(g, BuiltinFnIdFrameSize, "frameSize", 1); create_builtin_fn(g, BuiltinFnIdAs, "as", 2); create_builtin_fn(g, BuiltinFnIdCall, "call", 3); + create_builtin_fn(g, BuiltinFnIdBitSizeof, "bitSizeOf", 1); } static const char *bool_to_str(bool b) { diff --git a/src/ir.cpp b/src/ir.cpp index d871aa27a0..c3ca366456 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -2392,9 +2392,10 @@ static IrInstruction *ir_build_asm_gen(IrAnalyze *ira, Scope *scope, AstNode *so return &instruction->base; } -static IrInstruction *ir_build_size_of(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *type_value) { +static IrInstruction *ir_build_size_of(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *type_value, bool bit_size) { IrInstructionSizeOf *instruction = ir_build_instruction(irb, scope, source_node); instruction->type_value = type_value; + instruction->bit_size = bit_size; ir_ref_instruction(type_value, irb->current_basic_block); @@ -5249,13 +5250,14 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo return ir_lval_wrap(irb, scope, set_float_mode, lval, result_loc); } case BuiltinFnIdSizeof: + case BuiltinFnIdBitSizeof: { AstNode *arg0_node = node->data.fn_call_expr.params.at(0); IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope); if (arg0_value == irb->codegen->invalid_instruction) return arg0_value; - IrInstruction *size_of = ir_build_size_of(irb, scope, node, arg0_value); + IrInstruction *size_of = ir_build_size_of(irb, scope, node, arg0_value, builtin_fn->id == BuiltinFnIdBitSizeof); return ir_lval_wrap(irb, scope, size_of, lval, result_loc); } case BuiltinFnIdImport: @@ -21065,6 +21067,7 @@ static IrInstruction *ir_analyze_instruction_size_of(IrAnalyze *ira, IrInstructi lazy_size_of->ira = ira; ira_ref(ira); result->value->data.x_lazy = &lazy_size_of->base; lazy_size_of->base.id = LazyValueIdSizeOf; + lazy_size_of->bit_size = instruction->bit_size; lazy_size_of->target_type = instruction->type_value->child; if (ir_resolve_type_lazy(ira, lazy_size_of->target_type) == nullptr) @@ -29415,7 +29418,10 @@ static Error ir_resolve_lazy_raw(AstNode *source_node, ZigValue *val) { val->special = ConstValSpecialStatic; assert(val->type->id == ZigTypeIdComptimeInt || val->type->id == ZigTypeIdInt); - bigint_init_unsigned(&val->data.x_bigint, abi_size); + if (lazy_size_of->bit_size) + bigint_init_unsigned(&val->data.x_bigint, size_in_bits); + else + bigint_init_unsigned(&val->data.x_bigint, abi_size); // We can't free the lazy value here, because multiple other ZigValues might be pointing to it. return ErrorNone; diff --git a/src/ir_print.cpp b/src/ir_print.cpp index 90ab410e4d..24e030f501 100644 --- a/src/ir_print.cpp +++ b/src/ir_print.cpp @@ -1039,7 +1039,10 @@ static void ir_print_asm_gen(IrPrint *irp, IrInstructionAsmGen *instruction) { } static void ir_print_size_of(IrPrint *irp, IrInstructionSizeOf *instruction) { - fprintf(irp->f, "@sizeOf("); + if (instruction->bit_size) + fprintf(irp->f, "@bitSizeOf("); + else + fprintf(irp->f, "@sizeOf("); ir_print_other_instruction(irp, instruction->type_value); fprintf(irp->f, ")"); } diff --git a/test/stage1/behavior/sizeof_and_typeof.zig b/test/stage1/behavior/sizeof_and_typeof.zig index d46cdccd0d..a738dbbbf9 100644 --- a/test/stage1/behavior/sizeof_and_typeof.zig +++ b/test/stage1/behavior/sizeof_and_typeof.zig @@ -124,3 +124,14 @@ fn fn1(alpha: bool) void { test "lazy @sizeOf result is checked for definedness" { const f = fn1; } + +test "@bitSizeOf" { + expect(@bitSizeOf(u2) == 2); + expect(@bitSizeOf(u8) == @sizeOf(u8) * 8); + expect(@bitSizeOf(struct { + a: u2 + }) == 8); + expect(@bitSizeOf(packed struct { + a: u2 + }) == 2); +}