aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew Kelley <andrew@ziglang.org>2021-04-12 21:46:20 -0700
committerAndrew Kelley <andrew@ziglang.org>2021-04-15 19:06:39 -0700
commit6dba9bc6fc6741e51af86f71e3057cffed7406a6 (patch)
tree14f01a271c9e633769804f8b86f7687f838c5aca
parentdf983b30d2b890e21fba214145ccc4f4a263359d (diff)
downloadzig-6dba9bc6fc6741e51af86f71e3057cffed7406a6.tar.gz
zig-6dba9bc6fc6741e51af86f71e3057cffed7406a6.zip
stage2: implement `@bitSizeOf`
-rw-r--r--src/AstGen.zig8
-rw-r--r--src/Sema.zig11
-rw-r--r--src/type.zig145
-rw-r--r--src/zir.zig4
4 files changed, 167 insertions, 1 deletions
diff --git a/src/AstGen.zig b/src/AstGen.zig
index 0830b95e77..f5a5b22645 100644
--- a/src/AstGen.zig
+++ b/src/AstGen.zig
@@ -1360,6 +1360,7 @@ fn blockExprStmts(
.enum_to_int,
.type_info,
.size_of,
+ .bit_size_of,
=> break :b false,
// ZIR instructions that are always either `noreturn` or `void`.
@@ -4349,6 +4350,12 @@ fn builtinCall(
return rvalue(gz, scope, rl, result, node);
},
+ .bit_size_of => {
+ const operand = try typeExpr(gz, scope, params[0]);
+ const result = try gz.addUnNode(.bit_size_of, operand, node);
+ return rvalue(gz, scope, rl, result, node);
+ },
+
.add_with_overflow,
.align_cast,
.align_of,
@@ -4357,7 +4364,6 @@ fn builtinCall(
.atomic_store,
.bit_offset_of,
.bool_to_int,
- .bit_size_of,
.mul_add,
.byte_swap,
.bit_reverse,
diff --git a/src/Sema.zig b/src/Sema.zig
index 3da3902baa..35edf86de8 100644
--- a/src/Sema.zig
+++ b/src/Sema.zig
@@ -265,6 +265,7 @@ pub fn analyzeBody(
.switch_capture_else_ref => try sema.zirSwitchCaptureElse(block, inst, true),
.type_info => try sema.zirTypeInfo(block, inst),
.size_of => try sema.zirSizeOf(block, inst),
+ .bit_size_of => try sema.zirBitSizeOf(block, inst),
.typeof => try sema.zirTypeof(block, inst),
.typeof_elem => try sema.zirTypeofElem(block, inst),
.typeof_peer => try sema.zirTypeofPeer(block, inst),
@@ -4365,6 +4366,16 @@ fn zirSizeOf(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!
return sema.mod.constIntUnsigned(sema.arena, src, Type.initTag(.comptime_int), abi_size);
}
+fn zirBitSizeOf(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
+ const inst_data = sema.code.instructions.items(.data)[inst].un_node;
+ const src = inst_data.src();
+ const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
+ const operand_ty = try sema.resolveType(block, operand_src, inst_data.operand);
+ const target = sema.mod.getTarget();
+ const bit_size = operand_ty.bitSize(target);
+ return sema.mod.constIntUnsigned(sema.arena, src, Type.initTag(.comptime_int), bit_size);
+}
+
fn zirTypeInfo(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
const inst_data = sema.code.instructions.items(.data)[inst].un_node;
const src = inst_data.src();
diff --git a/src/type.zig b/src/type.zig
index d05fa0f5e3..0429fd876a 100644
--- a/src/type.zig
+++ b/src/type.zig
@@ -1377,6 +1377,151 @@ pub const Type = extern union {
};
}
+ /// Asserts the type has the bit size already resolved.
+ pub fn bitSize(self: Type, target: Target) u64 {
+ return switch (self.tag()) {
+ .fn_noreturn_no_args => unreachable, // represents machine code; not a pointer
+ .fn_void_no_args => unreachable, // represents machine code; not a pointer
+ .fn_naked_noreturn_no_args => unreachable, // represents machine code; not a pointer
+ .fn_ccc_void_no_args => unreachable, // represents machine code; not a pointer
+ .function => unreachable, // represents machine code; not a pointer
+ .c_void => unreachable,
+ .void => unreachable,
+ .type => unreachable,
+ .comptime_int => unreachable,
+ .comptime_float => unreachable,
+ .noreturn => unreachable,
+ .@"null" => unreachable,
+ .@"undefined" => unreachable,
+ .enum_literal => unreachable,
+ .single_const_pointer_to_comptime_int => unreachable,
+ .empty_struct => unreachable,
+ .empty_struct_literal => unreachable,
+ .inferred_alloc_const => unreachable,
+ .inferred_alloc_mut => unreachable,
+ .@"opaque" => unreachable,
+ .var_args_param => unreachable,
+
+ .@"struct" => {
+ @panic("TODO bitSize struct");
+ },
+ .enum_simple, .enum_full, .enum_nonexhaustive => {
+ var buffer: Payload.Bits = undefined;
+ const int_tag_ty = self.intTagType(&buffer);
+ return int_tag_ty.bitSize(target);
+ },
+
+ .u8, .i8 => 8,
+
+ .bool => 1,
+
+ .array_u8 => 8 * self.castTag(.array_u8).?.data,
+ .array_u8_sentinel_0 => 8 * (self.castTag(.array_u8_sentinel_0).?.data + 1),
+ .array => {
+ const payload = self.castTag(.array).?.data;
+ const elem_size = std.math.max(payload.elem_type.abiAlignment(target), payload.elem_type.abiSize(target));
+ if (elem_size == 0 or payload.len == 0)
+ return 0;
+ return (payload.len - 1) * 8 * elem_size + payload.elem_type.bitSize(target);
+ },
+ .array_sentinel => {
+ const payload = self.castTag(.array_sentinel).?.data;
+ const elem_size = std.math.max(
+ payload.elem_type.abiAlignment(target),
+ payload.elem_type.abiSize(target),
+ );
+ return payload.len * 8 * elem_size + payload.elem_type.bitSize(target);
+ },
+ .i16, .u16, .f16 => 16,
+ .i32, .u32, .f32 => 32,
+ .i64, .u64, .f64 => 64,
+ .u128, .i128, .f128 => 128,
+
+ .isize, .usize => target.cpu.arch.ptrBitWidth(),
+
+ .const_slice,
+ .mut_slice,
+ => {
+ if (self.elemType().hasCodeGenBits()) {
+ return target.cpu.arch.ptrBitWidth() * 2;
+ } else {
+ return target.cpu.arch.ptrBitWidth();
+ }
+ },
+ .const_slice_u8 => target.cpu.arch.ptrBitWidth() * 2,
+
+ .optional_single_const_pointer,
+ .optional_single_mut_pointer,
+ => {
+ if (self.elemType().hasCodeGenBits()) {
+ return target.cpu.arch.ptrBitWidth();
+ } else {
+ return 1;
+ }
+ },
+
+ .single_const_pointer,
+ .single_mut_pointer,
+ .many_const_pointer,
+ .many_mut_pointer,
+ .c_const_pointer,
+ .c_mut_pointer,
+ .pointer,
+ => {
+ if (self.elemType().hasCodeGenBits()) {
+ return target.cpu.arch.ptrBitWidth();
+ } else {
+ return 0;
+ }
+ },
+
+ .c_short => return CType.short.sizeInBits(target),
+ .c_ushort => return CType.ushort.sizeInBits(target),
+ .c_int => return CType.int.sizeInBits(target),
+ .c_uint => return CType.uint.sizeInBits(target),
+ .c_long => return CType.long.sizeInBits(target),
+ .c_ulong => return CType.ulong.sizeInBits(target),
+ .c_longlong => return CType.longlong.sizeInBits(target),
+ .c_ulonglong => return CType.ulonglong.sizeInBits(target),
+ .c_longdouble => 128,
+
+ .error_set,
+ .error_set_single,
+ .anyerror_void_error_union,
+ .anyerror,
+ => return 16, // TODO revisit this when we have the concept of the error tag type
+
+ .int_signed, .int_unsigned => self.cast(Payload.Bits).?.data,
+
+ .optional => {
+ var buf: Payload.ElemType = undefined;
+ const child_type = self.optionalChild(&buf);
+ if (!child_type.hasCodeGenBits()) return 8;
+
+ if (child_type.zigTypeTag() == .Pointer and !child_type.isCPtr())
+ return target.cpu.arch.ptrBitWidth();
+
+ // Optional types are represented as a struct with the child type as the first
+ // field and a boolean as the second. Since the child type's abi alignment is
+ // guaranteed to be >= that of bool's (1 byte) the added size is exactly equal
+ // to the child type's ABI alignment.
+ return child_type.bitSize(target) + 1;
+ },
+
+ .error_union => {
+ const payload = self.castTag(.error_union).?.data;
+ if (!payload.error_set.hasCodeGenBits() and !payload.payload.hasCodeGenBits()) {
+ return 0;
+ } else if (!payload.error_set.hasCodeGenBits()) {
+ return payload.payload.bitSize(target);
+ } else if (!payload.payload.hasCodeGenBits()) {
+ return payload.error_set.bitSize(target);
+ }
+ @panic("TODO abiSize error union");
+ },
+ };
+ }
+
/// Asserts the type is an enum.
pub fn intTagType(self: Type, buffer: *Payload.Bits) Type {
switch (self.tag()) {
diff --git a/src/zir.zig b/src/zir.zig
index 075a09a239..44c22d41c7 100644
--- a/src/zir.zig
+++ b/src/zir.zig
@@ -697,6 +697,8 @@ pub const Inst = struct {
type_info,
/// Implements the `@sizeOf` builtin. Uses `un_node`.
size_of,
+ /// Implements the `@bitSizeOf` builtin. Uses `un_node`.
+ bit_size_of,
/// Returns whether the instruction is one of the control flow "noreturn" types.
/// Function calls do not count.
@@ -864,6 +866,7 @@ pub const Inst = struct {
.enum_to_int,
.type_info,
.size_of,
+ .bit_size_of,
=> false,
.@"break",
@@ -1674,6 +1677,7 @@ const Writer = struct {
.enum_to_int,
.type_info,
.size_of,
+ .bit_size_of,
=> try self.writeUnNode(stream, inst),
.ref,