diff options
| author | Andrew Kelley <andrew@ziglang.org> | 2021-04-12 21:46:20 -0700 |
|---|---|---|
| committer | Andrew Kelley <andrew@ziglang.org> | 2021-04-15 19:06:39 -0700 |
| commit | 6dba9bc6fc6741e51af86f71e3057cffed7406a6 (patch) | |
| tree | 14f01a271c9e633769804f8b86f7687f838c5aca /src | |
| parent | df983b30d2b890e21fba214145ccc4f4a263359d (diff) | |
| download | zig-6dba9bc6fc6741e51af86f71e3057cffed7406a6.tar.gz zig-6dba9bc6fc6741e51af86f71e3057cffed7406a6.zip | |
stage2: implement `@bitSizeOf`
Diffstat (limited to 'src')
| -rw-r--r-- | src/AstGen.zig | 8 | ||||
| -rw-r--r-- | src/Sema.zig | 11 | ||||
| -rw-r--r-- | src/type.zig | 145 | ||||
| -rw-r--r-- | src/zir.zig | 4 |
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, |
