Skip to content

Implement @bitSizeOf #4202

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jan 16, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 14 additions & 1 deletion doc/langref.html.in
Original file line number Diff line number Diff line change
Expand Up @@ -6815,6 +6815,19 @@ async fn func(y: *i32) void {
</p>
{#header_close#}

{#header_open|@bitSizeOf#}
<pre>{#syntax#}@bitSizeOf(comptime T: type) comptime_int{#endsyntax#}</pre>
<p>
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.
</p>
<p>
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#}.
</p>
{#see_also|@sizeOf|@typeInfo#}
{#header_close#}

{#header_open|@breakpoint#}
<pre>{#syntax#}@breakpoint(){#endsyntax#}</pre>
<p>
Expand Down Expand Up @@ -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#}.
</p>
{#see_also|@typeInfo#}
{#see_also|@bitSizeOf|@typeInfo#}
{#header_close#}

{#header_open|@sliceToBytes#}
Expand Down
4 changes: 4 additions & 0 deletions src/all_types.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -358,6 +358,8 @@ struct LazyValueSizeOf {

IrAnalyze *ira;
IrInstruction *target_type;

bool bit_size;
};

struct LazyValueSliceType {
Expand Down Expand Up @@ -1754,6 +1756,7 @@ enum BuiltinFnId {
BuiltinFnIdFrameSize,
BuiltinFnIdAs,
BuiltinFnIdCall,
BuiltinFnIdBitSizeof,
};

struct BuiltinFnEntry {
Expand Down Expand Up @@ -3146,6 +3149,7 @@ struct IrInstructionAsmGen {
struct IrInstructionSizeOf {
IrInstruction base;

bool bit_size;
IrInstruction *type_value;
};

Expand Down
1 change: 1 addition & 0 deletions src/codegen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
12 changes: 9 additions & 3 deletions src/ir.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<IrInstructionSizeOf>(irb, scope, source_node);
instruction->type_value = type_value;
instruction->bit_size = bit_size;

ir_ref_instruction(type_value, irb->current_basic_block);

Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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;
Expand Down
5 changes: 4 additions & 1 deletion src/ir_print.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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, ")");
}
Expand Down
11 changes: 11 additions & 0 deletions test/stage1/behavior/sizeof_and_typeof.zig
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}