authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-10-05 21:38:47-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-10-05 21:38:47-07:00
logcb616cb7972bb2f38ea4527c7ec0ae3cc0d64c7c
treebb34a640825465b95c7be5c712da5a5a17217192
parent941b2f0d5e50521c41e6db3912085a72b6c16813

stage2: implement runtime `@intToEnum`

* Update AIR instruction `intcast` to allow the dest type to be an enum. * LLVM backend: update `intcast` to support when the bit counts of operand and dest type are the same. This was already a requirement of the instruction previously. * Type: `intInfo` supports the case when the type is an enum, and retrieves the info for the integer tag type. This makes it pretty easy for backends to implement `intcast` without having to care explicitly that the new type is an enum. As a bonus, simple enums never have to go through the type system; their signedness and bit count are computed directly. The "int to enum" behavior test case is now passing for stage2 in the LLVM backend.

6 files changed, 71 insertions(+), 588 deletions(-)

src/Air.zig+4-1
......@@ -272,8 +272,11 @@ pub const Inst = struct {
272272 /// Uses the `ty_op` field.
273273 fpext,
274274 /// Returns an integer with a different type than the operand. The new type may have
275 /// fewer, the same, or more bits than the operand type. However, the instruction
275 /// fewer, the same, or more bits than the operand type. The new type may also
276 /// differ in signedness from the operand type. However, the instruction
276277 /// guarantees that the same integer value fits in both types.
278 /// The new type may also be an enum type, in which case the integer cast operates on
279 /// the integer tag type of the enum.
277280 /// See `trunc` for integer truncation.
278281 /// Uses the `ty_op` field.
279282 intcast,
src/Sema.zig+3-1
......@@ -4312,7 +4312,8 @@ fn zirIntToEnum(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
43124312 }
43134313
43144314 try sema.requireRuntimeBlock(block, src);
4315 return block.addTyOp(.bitcast, dest_ty, operand);
4315 // TODO insert safety check to make sure the value matches an enum value
4316 return block.addTyOp(.intcast, dest_ty, operand);
43164317}
43174318
43184319/// Pointer in, pointer out.
......@@ -5050,6 +5051,7 @@ fn zirIntCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
50505051 }
50515052
50525053 try sema.requireRuntimeBlock(block, operand_src);
5054 // TODO insert safety check to make sure the value fits in the dest type
50535055 return block.addTyOp(.intcast, dest_type, operand);
50545056}
50555057
src/codegen/llvm.zig+4-1
......@@ -2381,8 +2381,11 @@ pub const FuncGen = struct {
23812381 .signed => return self.builder.buildSExt(operand, dest_llvm_ty, ""),
23822382 .unsigned => return self.builder.buildZExt(operand, dest_llvm_ty, ""),
23832383 }
2384 } else if (operand_info.bits > dest_info.bits) {
2385 return self.builder.buildTrunc(operand, dest_llvm_ty, "");
2386 } else {
2387 return operand;
23842388 }
2385 return self.builder.buildTrunc(operand, dest_llvm_ty, "");
23862389 }
23872390
23882391 fn airTrunc(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
src/type.zig+49-36
......@@ -2657,38 +2657,49 @@ pub const Type = extern union {
26572657 };
26582658 }
26592659
2660 /// Asserts the type is an integer.
2660 /// Asserts the type is an integer or enum.
26612661 pub fn intInfo(self: Type, target: Target) struct { signedness: std.builtin.Signedness, bits: u16 } {
2662 return switch (self.tag()) {
2663 .int_unsigned => .{
2662 var ty = self;
2663 while (true) switch (ty.tag()) {
2664 .int_unsigned => return .{
26642665 .signedness = .unsigned,
2665 .bits = self.castTag(.int_unsigned).?.data,
2666 .bits = ty.castTag(.int_unsigned).?.data,
26662667 },
2667 .int_signed => .{
2668 .int_signed => return .{
26682669 .signedness = .signed,
2669 .bits = self.castTag(.int_signed).?.data,
2670 },
2671 .u1 => .{ .signedness = .unsigned, .bits = 1 },
2672 .u8 => .{ .signedness = .unsigned, .bits = 8 },
2673 .i8 => .{ .signedness = .signed, .bits = 8 },
2674 .u16 => .{ .signedness = .unsigned, .bits = 16 },
2675 .i16 => .{ .signedness = .signed, .bits = 16 },
2676 .u32 => .{ .signedness = .unsigned, .bits = 32 },
2677 .i32 => .{ .signedness = .signed, .bits = 32 },
2678 .u64 => .{ .signedness = .unsigned, .bits = 64 },
2679 .i64 => .{ .signedness = .signed, .bits = 64 },
2680 .u128 => .{ .signedness = .unsigned, .bits = 128 },
2681 .i128 => .{ .signedness = .signed, .bits = 128 },
2682 .usize => .{ .signedness = .unsigned, .bits = target.cpu.arch.ptrBitWidth() },
2683 .isize => .{ .signedness = .signed, .bits = target.cpu.arch.ptrBitWidth() },
2684 .c_short => .{ .signedness = .signed, .bits = CType.short.sizeInBits(target) },
2685 .c_ushort => .{ .signedness = .unsigned, .bits = CType.ushort.sizeInBits(target) },
2686 .c_int => .{ .signedness = .signed, .bits = CType.int.sizeInBits(target) },
2687 .c_uint => .{ .signedness = .unsigned, .bits = CType.uint.sizeInBits(target) },
2688 .c_long => .{ .signedness = .signed, .bits = CType.long.sizeInBits(target) },
2689 .c_ulong => .{ .signedness = .unsigned, .bits = CType.ulong.sizeInBits(target) },
2690 .c_longlong => .{ .signedness = .signed, .bits = CType.longlong.sizeInBits(target) },
2691 .c_ulonglong => .{ .signedness = .unsigned, .bits = CType.ulonglong.sizeInBits(target) },
2670 .bits = ty.castTag(.int_signed).?.data,
2671 },
2672 .u1 => return .{ .signedness = .unsigned, .bits = 1 },
2673 .u8 => return .{ .signedness = .unsigned, .bits = 8 },
2674 .i8 => return .{ .signedness = .signed, .bits = 8 },
2675 .u16 => return .{ .signedness = .unsigned, .bits = 16 },
2676 .i16 => return .{ .signedness = .signed, .bits = 16 },
2677 .u32 => return .{ .signedness = .unsigned, .bits = 32 },
2678 .i32 => return .{ .signedness = .signed, .bits = 32 },
2679 .u64 => return .{ .signedness = .unsigned, .bits = 64 },
2680 .i64 => return .{ .signedness = .signed, .bits = 64 },
2681 .u128 => return .{ .signedness = .unsigned, .bits = 128 },
2682 .i128 => return .{ .signedness = .signed, .bits = 128 },
2683 .usize => return .{ .signedness = .unsigned, .bits = target.cpu.arch.ptrBitWidth() },
2684 .isize => return .{ .signedness = .signed, .bits = target.cpu.arch.ptrBitWidth() },
2685 .c_short => return .{ .signedness = .signed, .bits = CType.short.sizeInBits(target) },
2686 .c_ushort => return .{ .signedness = .unsigned, .bits = CType.ushort.sizeInBits(target) },
2687 .c_int => return .{ .signedness = .signed, .bits = CType.int.sizeInBits(target) },
2688 .c_uint => return .{ .signedness = .unsigned, .bits = CType.uint.sizeInBits(target) },
2689 .c_long => return .{ .signedness = .signed, .bits = CType.long.sizeInBits(target) },
2690 .c_ulong => return .{ .signedness = .unsigned, .bits = CType.ulong.sizeInBits(target) },
2691 .c_longlong => return .{ .signedness = .signed, .bits = CType.longlong.sizeInBits(target) },
2692 .c_ulonglong => return .{ .signedness = .unsigned, .bits = CType.ulonglong.sizeInBits(target) },
2693
2694 .enum_full, .enum_nonexhaustive => ty = ty.cast(Payload.EnumFull).?.data.tag_ty,
2695 .enum_numbered => ty = self.castTag(.enum_numbered).?.data.tag_ty,
2696 .enum_simple => {
2697 const enum_obj = self.castTag(.enum_simple).?.data;
2698 return .{
2699 .signedness = .unsigned,
2700 .bits = smallestUnsignedBits(enum_obj.fields.count()),
2701 };
2702 },
26922703
26932704 else => unreachable,
26942705 };
......@@ -3905,20 +3916,22 @@ pub const Type = extern union {
39053916 return Type.initPayload(&type_payload.base);
39063917 }
39073918
3919 pub fn smallestUnsignedBits(max: u64) u16 {
3920 if (max == 0) return 0;
3921 const base = std.math.log2(max);
3922 const upper = (@as(u64, 1) << @intCast(u6, base)) - 1;
3923 return @intCast(u16, base + @boolToInt(upper < max));
3924 }
3925
39083926 pub fn smallestUnsignedInt(arena: *Allocator, max: u64) !Type {
3909 const bits = bits: {
3910 if (max == 0) break :bits 0;
3911 const base = std.math.log2(max);
3912 const upper = (@as(u64, 1) << @intCast(u6, base)) - 1;
3913 break :bits base + @boolToInt(upper < max);
3914 };
3915 return switch (@intCast(u16, bits)) {
3927 const bits = smallestUnsignedBits(max);
3928 return switch (bits) {
39163929 1 => initTag(.u1),
39173930 8 => initTag(.u8),
39183931 16 => initTag(.u16),
39193932 32 => initTag(.u32),
39203933 64 => initTag(.u64),
3921 else => |b| return Tag.int_unsigned.create(arena, b),
3934 else => return Tag.int_unsigned.create(arena, bits),
39223935 };
39233936 }
39243937};
test/behavior/enum.zig+9
......@@ -17,6 +17,15 @@ test "enum to int" {
1717 try shouldEqual(Number.Four, 4);
1818}
1919
20fn testIntToEnumEval(x: i32) !void {
21 try expect(@intToEnum(IntToEnumNumber, x) == IntToEnumNumber.Three);
22}
23const IntToEnumNumber = enum { Zero, One, Two, Three, Four };
24
25test "int to enum" {
26 try testIntToEnumEval(3);
27}
28
2029const ValueCount1 = enum {
2130 I0,
2231};
test/behavior/enum_stage1.zig+2-549
......@@ -104,18 +104,6 @@ const Bar = enum { A, B, C, D };
104104
105105const Number = enum { Zero, One, Two, Three, Four };
106106
107fn shouldEqual(n: Number, expected: u3) !void {
108 try expect(@enumToInt(n) == expected);
109}
110
111test "int to enum" {
112 try testIntToEnumEval(3);
113}
114fn testIntToEnumEval(x: i32) !void {
115 try expect(@intToEnum(IntToEnumNumber, x) == IntToEnumNumber.Three);
116}
117const IntToEnumNumber = enum { Zero, One, Two, Three, Four };
118
119107test "@tagName" {
120108 try expect(mem.eql(u8, testEnumTagNameBare(BareNumber.Three), "Three"));
121109 comptime try expect(mem.eql(u8, testEnumTagNameBare(BareNumber.Three), "Three"));
......@@ -131,544 +119,9 @@ fn testEnumTagNameBare(n: anytype) []const u8 {
131119}
132120
133121const BareNumber = enum { One, Two, Three };
134
135122const NonExhaustive = enum(u8) { A, B, _ };
136
137const ValueCount1 = enum {
138 I0,
139};
140const ValueCount2 = enum {
141 I0,
142 I1,
143};
144const ValueCount256 = enum {
145 I0,
146 I1,
147 I2,
148 I3,
149 I4,
150 I5,
151 I6,
152 I7,
153 I8,
154 I9,
155 I10,
156 I11,
157 I12,
158 I13,
159 I14,
160 I15,
161 I16,
162 I17,
163 I18,
164 I19,
165 I20,
166 I21,
167 I22,
168 I23,
169 I24,
170 I25,
171 I26,
172 I27,
173 I28,
174 I29,
175 I30,
176 I31,
177 I32,
178 I33,
179 I34,
180 I35,
181 I36,
182 I37,
183 I38,
184 I39,
185 I40,
186 I41,
187 I42,
188 I43,
189 I44,
190 I45,
191 I46,
192 I47,
193 I48,
194 I49,
195 I50,
196 I51,
197 I52,
198 I53,
199 I54,
200 I55,
201 I56,
202 I57,
203 I58,
204 I59,
205 I60,
206 I61,
207 I62,
208 I63,
209 I64,
210 I65,
211 I66,
212 I67,
213 I68,
214 I69,
215 I70,
216 I71,
217 I72,
218 I73,
219 I74,
220 I75,
221 I76,
222 I77,
223 I78,
224 I79,
225 I80,
226 I81,
227 I82,
228 I83,
229 I84,
230 I85,
231 I86,
232 I87,
233 I88,
234 I89,
235 I90,
236 I91,
237 I92,
238 I93,
239 I94,
240 I95,
241 I96,
242 I97,
243 I98,
244 I99,
245 I100,
246 I101,
247 I102,
248 I103,
249 I104,
250 I105,
251 I106,
252 I107,
253 I108,
254 I109,
255 I110,
256 I111,
257 I112,
258 I113,
259 I114,
260 I115,
261 I116,
262 I117,
263 I118,
264 I119,
265 I120,
266 I121,
267 I122,
268 I123,
269 I124,
270 I125,
271 I126,
272 I127,
273 I128,
274 I129,
275 I130,
276 I131,
277 I132,
278 I133,
279 I134,
280 I135,
281 I136,
282 I137,
283 I138,
284 I139,
285 I140,
286 I141,
287 I142,
288 I143,
289 I144,
290 I145,
291 I146,
292 I147,
293 I148,
294 I149,
295 I150,
296 I151,
297 I152,
298 I153,
299 I154,
300 I155,
301 I156,
302 I157,
303 I158,
304 I159,
305 I160,
306 I161,
307 I162,
308 I163,
309 I164,
310 I165,
311 I166,
312 I167,
313 I168,
314 I169,
315 I170,
316 I171,
317 I172,
318 I173,
319 I174,
320 I175,
321 I176,
322 I177,
323 I178,
324 I179,
325 I180,
326 I181,
327 I182,
328 I183,
329 I184,
330 I185,
331 I186,
332 I187,
333 I188,
334 I189,
335 I190,
336 I191,
337 I192,
338 I193,
339 I194,
340 I195,
341 I196,
342 I197,
343 I198,
344 I199,
345 I200,
346 I201,
347 I202,
348 I203,
349 I204,
350 I205,
351 I206,
352 I207,
353 I208,
354 I209,
355 I210,
356 I211,
357 I212,
358 I213,
359 I214,
360 I215,
361 I216,
362 I217,
363 I218,
364 I219,
365 I220,
366 I221,
367 I222,
368 I223,
369 I224,
370 I225,
371 I226,
372 I227,
373 I228,
374 I229,
375 I230,
376 I231,
377 I232,
378 I233,
379 I234,
380 I235,
381 I236,
382 I237,
383 I238,
384 I239,
385 I240,
386 I241,
387 I242,
388 I243,
389 I244,
390 I245,
391 I246,
392 I247,
393 I248,
394 I249,
395 I250,
396 I251,
397 I252,
398 I253,
399 I254,
400 I255,
401};
402const ValueCount257 = enum {
403 I0,
404 I1,
405 I2,
406 I3,
407 I4,
408 I5,
409 I6,
410 I7,
411 I8,
412 I9,
413 I10,
414 I11,
415 I12,
416 I13,
417 I14,
418 I15,
419 I16,
420 I17,
421 I18,
422 I19,
423 I20,
424 I21,
425 I22,
426 I23,
427 I24,
428 I25,
429 I26,
430 I27,
431 I28,
432 I29,
433 I30,
434 I31,
435 I32,
436 I33,
437 I34,
438 I35,
439 I36,
440 I37,
441 I38,
442 I39,
443 I40,
444 I41,
445 I42,
446 I43,
447 I44,
448 I45,
449 I46,
450 I47,
451 I48,
452 I49,
453 I50,
454 I51,
455 I52,
456 I53,
457 I54,
458 I55,
459 I56,
460 I57,
461 I58,
462 I59,
463 I60,
464 I61,
465 I62,
466 I63,
467 I64,
468 I65,
469 I66,
470 I67,
471 I68,
472 I69,
473 I70,
474 I71,
475 I72,
476 I73,
477 I74,
478 I75,
479 I76,
480 I77,
481 I78,
482 I79,
483 I80,
484 I81,
485 I82,
486 I83,
487 I84,
488 I85,
489 I86,
490 I87,
491 I88,
492 I89,
493 I90,
494 I91,
495 I92,
496 I93,
497 I94,
498 I95,
499 I96,
500 I97,
501 I98,
502 I99,
503 I100,
504 I101,
505 I102,
506 I103,
507 I104,
508 I105,
509 I106,
510 I107,
511 I108,
512 I109,
513 I110,
514 I111,
515 I112,
516 I113,
517 I114,
518 I115,
519 I116,
520 I117,
521 I118,
522 I119,
523 I120,
524 I121,
525 I122,
526 I123,
527 I124,
528 I125,
529 I126,
530 I127,
531 I128,
532 I129,
533 I130,
534 I131,
535 I132,
536 I133,
537 I134,
538 I135,
539 I136,
540 I137,
541 I138,
542 I139,
543 I140,
544 I141,
545 I142,
546 I143,
547 I144,
548 I145,
549 I146,
550 I147,
551 I148,
552 I149,
553 I150,
554 I151,
555 I152,
556 I153,
557 I154,
558 I155,
559 I156,
560 I157,
561 I158,
562 I159,
563 I160,
564 I161,
565 I162,
566 I163,
567 I164,
568 I165,
569 I166,
570 I167,
571 I168,
572 I169,
573 I170,
574 I171,
575 I172,
576 I173,
577 I174,
578 I175,
579 I176,
580 I177,
581 I178,
582 I179,
583 I180,
584 I181,
585 I182,
586 I183,
587 I184,
588 I185,
589 I186,
590 I187,
591 I188,
592 I189,
593 I190,
594 I191,
595 I192,
596 I193,
597 I194,
598 I195,
599 I196,
600 I197,
601 I198,
602 I199,
603 I200,
604 I201,
605 I202,
606 I203,
607 I204,
608 I205,
609 I206,
610 I207,
611 I208,
612 I209,
613 I210,
614 I211,
615 I212,
616 I213,
617 I214,
618 I215,
619 I216,
620 I217,
621 I218,
622 I219,
623 I220,
624 I221,
625 I222,
626 I223,
627 I224,
628 I225,
629 I226,
630 I227,
631 I228,
632 I229,
633 I230,
634 I231,
635 I232,
636 I233,
637 I234,
638 I235,
639 I236,
640 I237,
641 I238,
642 I239,
643 I240,
644 I241,
645 I242,
646 I243,
647 I244,
648 I245,
649 I246,
650 I247,
651 I248,
652 I249,
653 I250,
654 I251,
655 I252,
656 I253,
657 I254,
658 I255,
659 I256,
660};
661
662const Small2 = enum(u2) {
663 One,
664 Two,
665};
666const Small = enum(u2) {
667 One,
668 Two,
669 Three,
670 Four,
671};
123const Small2 = enum(u2) { One, Two };
124const Small = enum(u2) { One, Two, Three, Four };
672125
673126test "set enum tag type" {
674127 {