authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-04-06 23:19:46-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-04-06 23:19:46-07:00
log19cf987198ff4de0b1460263a62ff6c41e1e3915
tree1acbb85972fbef799c1deb4de6a8c753b9b28a9e
parentacf9151008d5a97e5d91b34cc29f73af79062b48

C backend: implement Enum types and values

They are lowered directly as the integer tag type, with no typedef.

3 files changed, 53 insertions(+), 9 deletions(-)

src/Sema.zig+14-5
...@@ -1918,11 +1918,20 @@ fn zirEnumToInt(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerErr...@@ -1918,11 +1918,20 @@ fn zirEnumToInt(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerErr
1918 switch (enum_tag.ty.tag()) {1918 switch (enum_tag.ty.tag()) {
1919 .enum_full => {1919 .enum_full => {
1920 const enum_full = enum_tag.ty.castTag(.enum_full).?.data;1920 const enum_full = enum_tag.ty.castTag(.enum_full).?.data;
1921 const val = enum_full.values.entries.items[field_index].key;1921 if (enum_full.values.count() != 0) {
1922 return mod.constInst(arena, src, .{1922 const val = enum_full.values.entries.items[field_index].key;
1923 .ty = int_tag_ty,1923 return mod.constInst(arena, src, .{
1924 .val = val,1924 .ty = int_tag_ty,
1925 });1925 .val = val,
1926 });
1927 } else {
1928 // Field index and integer values are the same.
1929 const val = try Value.Tag.int_u64.create(arena, field_index);
1930 return mod.constInst(arena, src, .{
1931 .ty = int_tag_ty,
1932 .val = val,
1933 });
1934 }
1926 },1935 },
1927 .enum_simple => {1936 .enum_simple => {
1928 // Field index and integer values are the same.1937 // Field index and integer values are the same.
src/codegen/c.zig+36-1
...@@ -172,7 +172,10 @@ pub const DeclGen = struct {...@@ -172,7 +172,10 @@ pub const DeclGen = struct {
172 val: Value,172 val: Value,
173 ) error{ OutOfMemory, AnalysisFail }!void {173 ) error{ OutOfMemory, AnalysisFail }!void {
174 if (val.isUndef()) {174 if (val.isUndef()) {
175 return dg.fail(.{ .node_offset = 0 }, "TODO: C backend: properly handle undefined in all cases (with debug safety?)", .{});175 // This should lower to 0xaa bytes in safe modes, and for unsafe modes should
176 // lower to leaving variables uninitialized (that might need to be implemented
177 // outside of this function).
178 return dg.fail(.{ .node_offset = 0 }, "TODO: C backend: implement renderValue undef", .{});
176 }179 }
177 switch (t.zigTypeTag()) {180 switch (t.zigTypeTag()) {
178 .Int => {181 .Int => {
...@@ -288,6 +291,31 @@ pub const DeclGen = struct {...@@ -288,6 +291,31 @@ pub const DeclGen = struct {
288 try writer.writeAll(", .error = 0 }");291 try writer.writeAll(", .error = 0 }");
289 }292 }
290 },293 },
294 .Enum => {
295 switch (val.tag()) {
296 .enum_field_index => {
297 const field_index = val.castTag(.enum_field_index).?.data;
298 switch (t.tag()) {
299 .enum_simple => return writer.print("{d}", .{field_index}),
300 .enum_full, .enum_nonexhaustive => {
301 const enum_full = t.cast(Type.Payload.EnumFull).?.data;
302 if (enum_full.values.count() != 0) {
303 const tag_val = enum_full.values.entries.items[field_index].key;
304 return dg.renderValue(writer, enum_full.tag_ty, tag_val);
305 } else {
306 return writer.print("{d}", .{field_index});
307 }
308 },
309 else => unreachable,
310 }
311 },
312 else => {
313 var int_tag_ty_buffer: Type.Payload.Bits = undefined;
314 const int_tag_ty = t.intTagType(&int_tag_ty_buffer);
315 return dg.renderValue(writer, int_tag_ty, val);
316 },
317 }
318 },
291 else => |e| return dg.fail(.{ .node_offset = 0 }, "TODO: C backend: implement value {s}", .{319 else => |e| return dg.fail(.{ .node_offset = 0 }, "TODO: C backend: implement value {s}", .{
292 @tagName(e),320 @tagName(e),
293 }),321 }),
...@@ -472,6 +500,13 @@ pub const DeclGen = struct {...@@ -472,6 +500,13 @@ pub const DeclGen = struct {
472 try w.writeAll(name);500 try w.writeAll(name);
473 dg.typedefs.putAssumeCapacityNoClobber(t, .{ .name = name, .rendered = rendered });501 dg.typedefs.putAssumeCapacityNoClobber(t, .{ .name = name, .rendered = rendered });
474 },502 },
503 .Enum => {
504 // For enums, we simply use the integer tag type.
505 var int_tag_ty_buffer: Type.Payload.Bits = undefined;
506 const int_tag_ty = t.intTagType(&int_tag_ty_buffer);
507
508 try dg.renderType(w, int_tag_ty);
509 },
475 .Null, .Undefined => unreachable, // must be const or comptime510 .Null, .Undefined => unreachable, // must be const or comptime
476 else => |e| return dg.fail(.{ .node_offset = 0 }, "TODO: C backend: implement type {s}", .{511 else => |e| return dg.fail(.{ .node_offset = 0 }, "TODO: C backend: implement type {s}", .{
477 @tagName(e),512 @tagName(e),
src/type.zig+3-3
...@@ -691,7 +691,7 @@ pub const Type = extern union {...@@ -691,7 +691,7 @@ pub const Type = extern union {
691 return struct_obj.owner_decl.renderFullyQualifiedName(writer);691 return struct_obj.owner_decl.renderFullyQualifiedName(writer);
692 },692 },
693 .enum_full, .enum_nonexhaustive => {693 .enum_full, .enum_nonexhaustive => {
694 const enum_full = ty.castTag(.enum_full).?.data;694 const enum_full = ty.cast(Payload.EnumFull).?.data;
695 return enum_full.owner_decl.renderFullyQualifiedName(writer);695 return enum_full.owner_decl.renderFullyQualifiedName(writer);
696 },696 },
697 .enum_simple => {697 .enum_simple => {
...@@ -1344,7 +1344,7 @@ pub const Type = extern union {...@@ -1344,7 +1344,7 @@ pub const Type = extern union {
1344 /// Asserts the type is an enum.1344 /// Asserts the type is an enum.
1345 pub fn intTagType(self: Type, buffer: *Payload.Bits) Type {1345 pub fn intTagType(self: Type, buffer: *Payload.Bits) Type {
1346 switch (self.tag()) {1346 switch (self.tag()) {
1347 .enum_full, .enum_nonexhaustive => return self.castTag(.enum_full).?.data.tag_ty,1347 .enum_full, .enum_nonexhaustive => return self.cast(Payload.EnumFull).?.data.tag_ty,
1348 .enum_simple => {1348 .enum_simple => {
1349 const enum_simple = self.castTag(.enum_simple).?.data;1349 const enum_simple = self.castTag(.enum_simple).?.data;
1350 const bits = std.math.log2_int_ceil(usize, enum_simple.fields.count());1350 const bits = std.math.log2_int_ceil(usize, enum_simple.fields.count());
...@@ -1969,7 +1969,7 @@ pub const Type = extern union {...@@ -1969,7 +1969,7 @@ pub const Type = extern union {
1969 return null;1969 return null;
1970 }1970 }
1971 },1971 },
1972 .enum_nonexhaustive => ty = ty.castTag(.enum_full).?.data.tag_ty,1972 .enum_nonexhaustive => ty = ty.castTag(.enum_nonexhaustive).?.data.tag_ty,
19731973
1974 .empty_struct, .empty_struct_literal => return Value.initTag(.empty_struct_value),1974 .empty_struct, .empty_struct_literal => return Value.initTag(.empty_struct_value),
1975 .void => return Value.initTag(.void_value),1975 .void => return Value.initTag(.void_value),