authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-04-12 21:46:20-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-04-15 19:06:39-07:00
log6dba9bc6fc6741e51af86f71e3057cffed7406a6
tree14f01a271c9e633769804f8b86f7687f838c5aca
parentdf983b30d2b890e21fba214145ccc4f4a263359d

stage2: implement `@bitSizeOf`


4 files changed, 167 insertions(+), 1 deletions(-)

src/AstGen.zig+7-1
...@@ -1360,6 +1360,7 @@ fn blockExprStmts(...@@ -1360,6 +1360,7 @@ fn blockExprStmts(
1360 .enum_to_int,1360 .enum_to_int,
1361 .type_info,1361 .type_info,
1362 .size_of,1362 .size_of,
1363 .bit_size_of,
1363 => break :b false,1364 => break :b false,
13641365
1365 // ZIR instructions that are always either `noreturn` or `void`.1366 // ZIR instructions that are always either `noreturn` or `void`.
...@@ -4349,6 +4350,12 @@ fn builtinCall(...@@ -4349,6 +4350,12 @@ fn builtinCall(
4349 return rvalue(gz, scope, rl, result, node);4350 return rvalue(gz, scope, rl, result, node);
4350 },4351 },
43514352
4353 .bit_size_of => {
4354 const operand = try typeExpr(gz, scope, params[0]);
4355 const result = try gz.addUnNode(.bit_size_of, operand, node);
4356 return rvalue(gz, scope, rl, result, node);
4357 },
4358
4352 .add_with_overflow,4359 .add_with_overflow,
4353 .align_cast,4360 .align_cast,
4354 .align_of,4361 .align_of,
...@@ -4357,7 +4364,6 @@ fn builtinCall(...@@ -4357,7 +4364,6 @@ fn builtinCall(
4357 .atomic_store,4364 .atomic_store,
4358 .bit_offset_of,4365 .bit_offset_of,
4359 .bool_to_int,4366 .bool_to_int,
4360 .bit_size_of,
4361 .mul_add,4367 .mul_add,
4362 .byte_swap,4368 .byte_swap,
4363 .bit_reverse,4369 .bit_reverse,
src/Sema.zig+11
...@@ -265,6 +265,7 @@ pub fn analyzeBody(...@@ -265,6 +265,7 @@ pub fn analyzeBody(
265 .switch_capture_else_ref => try sema.zirSwitchCaptureElse(block, inst, true),265 .switch_capture_else_ref => try sema.zirSwitchCaptureElse(block, inst, true),
266 .type_info => try sema.zirTypeInfo(block, inst),266 .type_info => try sema.zirTypeInfo(block, inst),
267 .size_of => try sema.zirSizeOf(block, inst),267 .size_of => try sema.zirSizeOf(block, inst),
268 .bit_size_of => try sema.zirBitSizeOf(block, inst),
268 .typeof => try sema.zirTypeof(block, inst),269 .typeof => try sema.zirTypeof(block, inst),
269 .typeof_elem => try sema.zirTypeofElem(block, inst),270 .typeof_elem => try sema.zirTypeofElem(block, inst),
270 .typeof_peer => try sema.zirTypeofPeer(block, inst),271 .typeof_peer => try sema.zirTypeofPeer(block, inst),
...@@ -4365,6 +4366,16 @@ fn zirSizeOf(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!...@@ -4365,6 +4366,16 @@ fn zirSizeOf(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!
4365 return sema.mod.constIntUnsigned(sema.arena, src, Type.initTag(.comptime_int), abi_size);4366 return sema.mod.constIntUnsigned(sema.arena, src, Type.initTag(.comptime_int), abi_size);
4366}4367}
43674368
4369fn zirBitSizeOf(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
4370 const inst_data = sema.code.instructions.items(.data)[inst].un_node;
4371 const src = inst_data.src();
4372 const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
4373 const operand_ty = try sema.resolveType(block, operand_src, inst_data.operand);
4374 const target = sema.mod.getTarget();
4375 const bit_size = operand_ty.bitSize(target);
4376 return sema.mod.constIntUnsigned(sema.arena, src, Type.initTag(.comptime_int), bit_size);
4377}
4378
4368fn zirTypeInfo(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {4379fn zirTypeInfo(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
4369 const inst_data = sema.code.instructions.items(.data)[inst].un_node;4380 const inst_data = sema.code.instructions.items(.data)[inst].un_node;
4370 const src = inst_data.src();4381 const src = inst_data.src();
src/type.zig+145
...@@ -1377,6 +1377,151 @@ pub const Type = extern union {...@@ -1377,6 +1377,151 @@ pub const Type = extern union {
1377 };1377 };
1378 }1378 }
13791379
1380 /// Asserts the type has the bit size already resolved.
1381 pub fn bitSize(self: Type, target: Target) u64 {
1382 return switch (self.tag()) {
1383 .fn_noreturn_no_args => unreachable, // represents machine code; not a pointer
1384 .fn_void_no_args => unreachable, // represents machine code; not a pointer
1385 .fn_naked_noreturn_no_args => unreachable, // represents machine code; not a pointer
1386 .fn_ccc_void_no_args => unreachable, // represents machine code; not a pointer
1387 .function => unreachable, // represents machine code; not a pointer
1388 .c_void => unreachable,
1389 .void => unreachable,
1390 .type => unreachable,
1391 .comptime_int => unreachable,
1392 .comptime_float => unreachable,
1393 .noreturn => unreachable,
1394 .@"null" => unreachable,
1395 .@"undefined" => unreachable,
1396 .enum_literal => unreachable,
1397 .single_const_pointer_to_comptime_int => unreachable,
1398 .empty_struct => unreachable,
1399 .empty_struct_literal => unreachable,
1400 .inferred_alloc_const => unreachable,
1401 .inferred_alloc_mut => unreachable,
1402 .@"opaque" => unreachable,
1403 .var_args_param => unreachable,
1404
1405 .@"struct" => {
1406 @panic("TODO bitSize struct");
1407 },
1408 .enum_simple, .enum_full, .enum_nonexhaustive => {
1409 var buffer: Payload.Bits = undefined;
1410 const int_tag_ty = self.intTagType(&buffer);
1411 return int_tag_ty.bitSize(target);
1412 },
1413
1414 .u8, .i8 => 8,
1415
1416 .bool => 1,
1417
1418 .array_u8 => 8 * self.castTag(.array_u8).?.data,
1419 .array_u8_sentinel_0 => 8 * (self.castTag(.array_u8_sentinel_0).?.data + 1),
1420 .array => {
1421 const payload = self.castTag(.array).?.data;
1422 const elem_size = std.math.max(payload.elem_type.abiAlignment(target), payload.elem_type.abiSize(target));
1423 if (elem_size == 0 or payload.len == 0)
1424 return 0;
1425 return (payload.len - 1) * 8 * elem_size + payload.elem_type.bitSize(target);
1426 },
1427 .array_sentinel => {
1428 const payload = self.castTag(.array_sentinel).?.data;
1429 const elem_size = std.math.max(
1430 payload.elem_type.abiAlignment(target),
1431 payload.elem_type.abiSize(target),
1432 );
1433 return payload.len * 8 * elem_size + payload.elem_type.bitSize(target);
1434 },
1435 .i16, .u16, .f16 => 16,
1436 .i32, .u32, .f32 => 32,
1437 .i64, .u64, .f64 => 64,
1438 .u128, .i128, .f128 => 128,
1439
1440 .isize, .usize => target.cpu.arch.ptrBitWidth(),
1441
1442 .const_slice,
1443 .mut_slice,
1444 => {
1445 if (self.elemType().hasCodeGenBits()) {
1446 return target.cpu.arch.ptrBitWidth() * 2;
1447 } else {
1448 return target.cpu.arch.ptrBitWidth();
1449 }
1450 },
1451 .const_slice_u8 => target.cpu.arch.ptrBitWidth() * 2,
1452
1453 .optional_single_const_pointer,
1454 .optional_single_mut_pointer,
1455 => {
1456 if (self.elemType().hasCodeGenBits()) {
1457 return target.cpu.arch.ptrBitWidth();
1458 } else {
1459 return 1;
1460 }
1461 },
1462
1463 .single_const_pointer,
1464 .single_mut_pointer,
1465 .many_const_pointer,
1466 .many_mut_pointer,
1467 .c_const_pointer,
1468 .c_mut_pointer,
1469 .pointer,
1470 => {
1471 if (self.elemType().hasCodeGenBits()) {
1472 return target.cpu.arch.ptrBitWidth();
1473 } else {
1474 return 0;
1475 }
1476 },
1477
1478 .c_short => return CType.short.sizeInBits(target),
1479 .c_ushort => return CType.ushort.sizeInBits(target),
1480 .c_int => return CType.int.sizeInBits(target),
1481 .c_uint => return CType.uint.sizeInBits(target),
1482 .c_long => return CType.long.sizeInBits(target),
1483 .c_ulong => return CType.ulong.sizeInBits(target),
1484 .c_longlong => return CType.longlong.sizeInBits(target),
1485 .c_ulonglong => return CType.ulonglong.sizeInBits(target),
1486 .c_longdouble => 128,
1487
1488 .error_set,
1489 .error_set_single,
1490 .anyerror_void_error_union,
1491 .anyerror,
1492 => return 16, // TODO revisit this when we have the concept of the error tag type
1493
1494 .int_signed, .int_unsigned => self.cast(Payload.Bits).?.data,
1495
1496 .optional => {
1497 var buf: Payload.ElemType = undefined;
1498 const child_type = self.optionalChild(&buf);
1499 if (!child_type.hasCodeGenBits()) return 8;
1500
1501 if (child_type.zigTypeTag() == .Pointer and !child_type.isCPtr())
1502 return target.cpu.arch.ptrBitWidth();
1503
1504 // Optional types are represented as a struct with the child type as the first
1505 // field and a boolean as the second. Since the child type's abi alignment is
1506 // guaranteed to be >= that of bool's (1 byte) the added size is exactly equal
1507 // to the child type's ABI alignment.
1508 return child_type.bitSize(target) + 1;
1509 },
1510
1511 .error_union => {
1512 const payload = self.castTag(.error_union).?.data;
1513 if (!payload.error_set.hasCodeGenBits() and !payload.payload.hasCodeGenBits()) {
1514 return 0;
1515 } else if (!payload.error_set.hasCodeGenBits()) {
1516 return payload.payload.bitSize(target);
1517 } else if (!payload.payload.hasCodeGenBits()) {
1518 return payload.error_set.bitSize(target);
1519 }
1520 @panic("TODO abiSize error union");
1521 },
1522 };
1523 }
1524
1380 /// Asserts the type is an enum.1525 /// Asserts the type is an enum.
1381 pub fn intTagType(self: Type, buffer: *Payload.Bits) Type {1526 pub fn intTagType(self: Type, buffer: *Payload.Bits) Type {
1382 switch (self.tag()) {1527 switch (self.tag()) {
src/zir.zig+4
...@@ -697,6 +697,8 @@ pub const Inst = struct {...@@ -697,6 +697,8 @@ pub const Inst = struct {
697 type_info,697 type_info,
698 /// Implements the `@sizeOf` builtin. Uses `un_node`.698 /// Implements the `@sizeOf` builtin. Uses `un_node`.
699 size_of,699 size_of,
700 /// Implements the `@bitSizeOf` builtin. Uses `un_node`.
701 bit_size_of,
700702
701 /// Returns whether the instruction is one of the control flow "noreturn" types.703 /// Returns whether the instruction is one of the control flow "noreturn" types.
702 /// Function calls do not count.704 /// Function calls do not count.
...@@ -864,6 +866,7 @@ pub const Inst = struct {...@@ -864,6 +866,7 @@ pub const Inst = struct {
864 .enum_to_int,866 .enum_to_int,
865 .type_info,867 .type_info,
866 .size_of,868 .size_of,
869 .bit_size_of,
867 => false,870 => false,
868871
869 .@"break",872 .@"break",
...@@ -1674,6 +1677,7 @@ const Writer = struct {...@@ -1674,6 +1677,7 @@ const Writer = struct {
1674 .enum_to_int,1677 .enum_to_int,
1675 .type_info,1678 .type_info,
1676 .size_of,1679 .size_of,
1680 .bit_size_of,
1677 => try self.writeUnNode(stream, inst),1681 => try self.writeUnNode(stream, inst),
16781682
1679 .ref,1683 .ref,