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);
+}