From c992b259085070b4faef10f498840d2d3ce394fa Mon Sep 17 00:00:00 2001 From: Annika L Date: Fri, 1 Apr 2022 00:28:46 -0700 Subject: [PATCH 1/2] C backend: Fix array declarations --- src/codegen/c.zig | 66 ++++++++++++++++++++++++----------------- test/behavior/array.zig | 18 ++++++++++- test/behavior/fn.zig | 11 ++++++- 3 files changed, 66 insertions(+), 29 deletions(-) diff --git a/src/codegen/c.zig b/src/codegen/c.zig index a0b1bc30b9..464f144f5a 100644 --- a/src/codegen/c.zig +++ b/src/codegen/c.zig @@ -61,6 +61,11 @@ const FormatTypeAsCIdentContext = struct { mod: *Module, }; +const ValueRenderLocation = enum { + FunctionArgument, + Other, +}; + /// TODO make this not cut off at 128 bytes fn formatTypeAsCIdentifier( data: FormatTypeAsCIdentContext, @@ -259,7 +264,7 @@ pub const Function = struct { 0, ); try writer.writeAll(" = "); - try f.object.dg.renderValue(writer, ty, val); + try f.object.dg.renderValue(writer, ty, val, .Other); try writer.writeAll(";\n "); return decl_c_value; }, @@ -298,7 +303,7 @@ pub const Function = struct { .constant => |inst| { const ty = f.air.typeOf(inst); const val = f.air.value(inst).?; - return f.object.dg.renderValue(w, ty, val); + return f.object.dg.renderValue(w, ty, val, .Other); }, else => return f.object.dg.writeCValue(w, c_value), } @@ -310,7 +315,7 @@ pub const Function = struct { const ty = f.air.typeOf(inst); const val = f.air.value(inst).?; try w.writeAll("(*"); - try f.object.dg.renderValue(w, ty, val); + try f.object.dg.renderValue(w, ty, val, .Other); return w.writeByte(')'); }, else => return f.object.dg.writeCValueDeref(w, c_value), @@ -384,7 +389,7 @@ pub const DeclGen = struct { try dg.renderTypecast(writer, ty); try writer.writeAll("){"); var buf: Type.SlicePtrFieldTypeBuffer = undefined; - try dg.renderValue(writer, ty.slicePtrFieldType(&buf), val.slicePtr()); + try dg.renderValue(writer, ty.slicePtrFieldType(&buf), val.slicePtr(), .Other); try writer.writeAll(", "); try writer.print("{d}", .{val.sliceLen(dg.module)}); try writer.writeAll("}"); @@ -544,6 +549,7 @@ pub const DeclGen = struct { writer: anytype, ty: Type, val: Value, + location: ValueRenderLocation, ) error{ OutOfMemory, AnalysisFail }!void { const target = dg.module.getTarget(); if (val.isUndefDeep()) { @@ -636,9 +642,9 @@ pub const DeclGen = struct { try writer.writeByte('('); try dg.renderTypecast(writer, ty); try writer.writeAll("){"); - try dg.renderValue(writer, ty.slicePtrFieldType(&buf), slice.ptr); + try dg.renderValue(writer, ty.slicePtrFieldType(&buf), slice.ptr, location); try writer.writeAll(", "); - try dg.renderValue(writer, Type.usize, slice.len); + try dg.renderValue(writer, Type.usize, slice.len, location); try writer.writeAll("}"); }, .function => { @@ -670,7 +676,7 @@ pub const DeclGen = struct { try writer.writeByte('{'); const ai = ty.arrayInfo(); if (ai.sentinel) |s| { - try dg.renderValue(writer, ai.elem_type, s); + try dg.renderValue(writer, ai.elem_type, s, location); } try writer.writeByte('}'); }, @@ -680,17 +686,23 @@ pub const DeclGen = struct { defer arena.deinit(); const arena_allocator = arena.allocator(); + if (location == .FunctionArgument) { + try writer.writeByte('('); + try dg.renderTypecast(writer, ty); + try writer.writeByte(')'); + } + try writer.writeByte('{'); const ai = ty.arrayInfo(); var index: usize = 0; while (index < ai.len) : (index += 1) { if (index != 0) try writer.writeAll(","); const elem_val = try val.elemValue(dg.module, arena_allocator, index); - try dg.renderValue(writer, ai.elem_type, elem_val); + try dg.renderValue(writer, ai.elem_type, elem_val, .Other); } if (ai.sentinel) |s| { if (index != 0) try writer.writeAll(","); - try dg.renderValue(writer, ai.elem_type, s); + try dg.renderValue(writer, ai.elem_type, s, .Other); } try writer.writeByte('}'); }, @@ -701,7 +713,7 @@ pub const DeclGen = struct { var opt_buf: Type.Payload.ElemType = undefined; const payload_type = ty.optionalChild(&opt_buf); if (ty.isPtrLikeOptional()) { - return dg.renderValue(writer, payload_type, val); + return dg.renderValue(writer, payload_type, val, location); } if (payload_type.abiSize(target) == 0) { const is_null = val.castTag(.opt_payload) == null; @@ -713,7 +725,7 @@ pub const DeclGen = struct { if (val.castTag(.opt_payload)) |pl| { const payload_val = pl.data; try writer.writeAll(" .is_null = false, .payload = "); - try dg.renderValue(writer, payload_type, payload_val); + try dg.renderValue(writer, payload_type, payload_val, location); try writer.writeAll(" }"); } else { try writer.writeAll(" .is_null = true }"); @@ -740,7 +752,7 @@ pub const DeclGen = struct { if (!payload_type.hasRuntimeBits()) { // We use the error type directly as the type. const err_val = if (val.errorUnionIsPayload()) Value.initTag(.zero) else val; - return dg.renderValue(writer, error_type, err_val); + return dg.renderValue(writer, error_type, err_val, location); } try writer.writeByte('('); @@ -749,11 +761,11 @@ pub const DeclGen = struct { if (val.castTag(.eu_payload)) |pl| { const payload_val = pl.data; try writer.writeAll(" .payload = "); - try dg.renderValue(writer, payload_type, payload_val); + try dg.renderValue(writer, payload_type, payload_val, location); try writer.writeAll(", .error = 0 }"); } else { try writer.writeAll(" .error = "); - try dg.renderValue(writer, error_type, val); + try dg.renderValue(writer, error_type, val, location); try writer.writeAll(" }"); } }, @@ -767,7 +779,7 @@ pub const DeclGen = struct { const enum_full = ty.cast(Type.Payload.EnumFull).?.data; if (enum_full.values.count() != 0) { const tag_val = enum_full.values.keys()[field_index]; - return dg.renderValue(writer, enum_full.tag_ty, tag_val); + return dg.renderValue(writer, enum_full.tag_ty, tag_val, location); } else { return writer.print("{d}", .{field_index}); } @@ -776,7 +788,7 @@ pub const DeclGen = struct { const enum_obj = ty.castTag(.enum_numbered).?.data; if (enum_obj.values.count() != 0) { const tag_val = enum_obj.values.keys()[field_index]; - return dg.renderValue(writer, enum_obj.tag_ty, tag_val); + return dg.renderValue(writer, enum_obj.tag_ty, tag_val, location); } else { return writer.print("{d}", .{field_index}); } @@ -787,7 +799,7 @@ pub const DeclGen = struct { else => { var int_tag_ty_buffer: Type.Payload.Bits = undefined; const int_tag_ty = ty.intTagType(&int_tag_ty_buffer); - return dg.renderValue(writer, int_tag_ty, val); + return dg.renderValue(writer, int_tag_ty, val, location); }, } }, @@ -814,7 +826,7 @@ pub const DeclGen = struct { if (!field_ty.hasRuntimeBits()) continue; if (i != 0) try writer.writeAll(","); - try dg.renderValue(writer, field_ty, field_val); + try dg.renderValue(writer, field_ty, field_val, location); } try writer.writeAll("}"); @@ -831,7 +843,7 @@ pub const DeclGen = struct { if (ty.unionTagType()) |tag_ty| { if (layout.tag_size != 0) { try writer.writeAll(".tag = "); - try dg.renderValue(writer, tag_ty, union_obj.tag); + try dg.renderValue(writer, tag_ty, union_obj.tag, location); try writer.writeAll(", "); } try writer.writeAll(".payload = {"); @@ -842,7 +854,7 @@ pub const DeclGen = struct { const field_name = ty.unionFields().keys()[index]; if (field_ty.hasRuntimeBits()) { try writer.print(".{ } = ", .{fmtIdent(field_name)}); - try dg.renderValue(writer, field_ty, union_obj.val); + try dg.renderValue(writer, field_ty, union_obj.val, location); } if (ty.unionTagType()) |_| { try writer.writeAll("}"); @@ -988,7 +1000,7 @@ pub const DeclGen = struct { } if (ptr_sentinel) |s| { try bw.writeAll("_s_"); - try dg.renderValue(bw, child_type, s); + try dg.renderValue(bw, child_type, s, .Other); } try bw.writeAll(";\n"); @@ -1629,7 +1641,7 @@ pub fn genDecl(o: *Object) !void { try o.dg.renderTypeAndName(w, o.dg.decl.ty, decl_c_value, .Mut, o.dg.decl.@"align"); try w.writeAll(" = "); if (variable.init.tag() != .unreachable_value) { - try o.dg.renderValue(w, tv.ty, variable.init); + try o.dg.renderValue(w, tv.ty, variable.init, .Other); } try w.writeAll(";"); try o.indent_writer.insertNewline(); @@ -1644,7 +1656,7 @@ pub fn genDecl(o: *Object) !void { try o.dg.renderTypeAndName(writer, tv.ty, decl_c_value, .Mut, o.dg.decl.@"align"); try writer.writeAll(" = "); - try o.dg.renderValue(writer, tv.ty, tv.val); + try o.dg.renderValue(writer, tv.ty, tv.val, .Other); try writer.writeAll(";\n"); } } @@ -2748,7 +2760,7 @@ fn airCall( try writer.writeAll(", "); } if (f.air.value(arg)) |val| { - try f.object.dg.renderValue(writer, f.air.typeOf(arg), val); + try f.object.dg.renderValue(writer, f.air.typeOf(arg), val, .FunctionArgument); } else { const val = try f.resolveInst(arg); try f.writeCValue(writer, val); @@ -2964,7 +2976,7 @@ fn airSwitchBr(f: *Function, inst: Air.Inst.Index) !CValue { for (items) |item| { try f.object.indent_writer.insertNewline(); try writer.writeAll("case "); - try f.object.dg.renderValue(writer, condition_ty, f.air.value(item).?); + try f.object.dg.renderValue(writer, condition_ty, f.air.value(item).?, .Other); try writer.writeAll(": "); } // The case body must be noreturn so we don't need to insert a break. @@ -3414,14 +3426,14 @@ fn airErrUnionPayloadPtrSet(f: *Function, inst: Air.Inst.Index) !CValue { if (!payload_ty.hasRuntimeBitsIgnoreComptime()) { try f.writeCValueDeref(writer, operand); try writer.writeAll(" = "); - try f.object.dg.renderValue(writer, error_ty, Value.zero); + try f.object.dg.renderValue(writer, error_ty, Value.zero, .Other); try writer.writeAll(";\n "); return operand; } try f.writeCValueDeref(writer, operand); try writer.writeAll(".error = "); - try f.object.dg.renderValue(writer, error_ty, Value.zero); + try f.object.dg.renderValue(writer, error_ty, Value.zero, .Other); try writer.writeAll(";\n"); // Then return the payload pointer (only if it is used) diff --git a/test/behavior/array.zig b/test/behavior/array.zig index 13a4763a91..bf5e74e819 100644 --- a/test/behavior/array.zig +++ b/test/behavior/array.zig @@ -148,7 +148,7 @@ test "void arrays" { try expect(array.len == 4); } -test "nested arrays" { +test "nested arrays of strings" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; @@ -162,6 +162,22 @@ test "nested arrays" { } } +test "nested arrays of integers" { + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; + + const array_of_numbers = [_][2]u8{ + [2]u8{ 1, 2 }, + [2]u8{ 3, 4 }, + }; + + try expect(array_of_numbers[0][0] == 1); + try expect(array_of_numbers[0][1] == 2); + try expect(array_of_numbers[1][0] == 3); + try expect(array_of_numbers[1][1] == 4); +} + test "implicit comptime in array type size" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; diff --git a/test/behavior/fn.zig b/test/behavior/fn.zig index 7d02229ff4..eabb6c77f4 100644 --- a/test/behavior/fn.zig +++ b/test/behavior/fn.zig @@ -349,7 +349,6 @@ fn numberLiteralArg(a: anytype) !void { } test "function call with anon list literal" { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; @@ -364,9 +363,19 @@ test "function call with anon list literal" { try expect(vec[1] == 8); try expect(vec[2] == 7); } + + fn doThe2DTest() !void { + try consume2DVec(.{ .{ 9, 8 }, .{ 7, 6 } }); + } + + fn consume2DVec(vec: [2][2]f32) !void { + _ = vec; + } }; try S.doTheTest(); comptime try S.doTheTest(); + try S.doThe2DTest(); + comptime try S.doThe2DTest(); } test "ability to give comptime types and non comptime types to same parameter" { From 0e830b16306945ffc74ef95198eb74743ab9f184 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Fri, 22 Apr 2022 07:52:21 -0700 Subject: [PATCH 2/2] clean up behavior tests Split big test into the two separate things it is testing. Add missing checks to the test which revealed the test is not actually passing yet for the C backend. --- test/behavior/array.zig | 6 +++--- test/behavior/fn.zig | 30 +++++++++++++++++++++--------- 2 files changed, 24 insertions(+), 12 deletions(-) diff --git a/test/behavior/array.zig b/test/behavior/array.zig index bf5e74e819..728e05271a 100644 --- a/test/behavior/array.zig +++ b/test/behavior/array.zig @@ -163,9 +163,9 @@ test "nested arrays of strings" { } test "nested arrays of integers" { - if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO const array_of_numbers = [_][2]u8{ [2]u8{ 1, 2 }, diff --git a/test/behavior/fn.zig b/test/behavior/fn.zig index eabb6c77f4..26185f6ac1 100644 --- a/test/behavior/fn.zig +++ b/test/behavior/fn.zig @@ -349,9 +349,9 @@ fn numberLiteralArg(a: anytype) !void { } test "function call with anon list literal" { - if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO const S = struct { fn doTheTest() !void { @@ -363,19 +363,31 @@ test "function call with anon list literal" { try expect(vec[1] == 8); try expect(vec[2] == 7); } + }; + try S.doTheTest(); + comptime try S.doTheTest(); +} - fn doThe2DTest() !void { - try consume2DVec(.{ .{ 9, 8 }, .{ 7, 6 } }); +test "function call with anon list literal - 2D" { + if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO + + const S = struct { + fn doTheTest() !void { + try consumeVec(.{ .{ 9, 8 }, .{ 7, 6 } }); } - fn consume2DVec(vec: [2][2]f32) !void { - _ = vec; + fn consumeVec(vec: [2][2]f32) !void { + try expect(vec[0][0] == 9); + try expect(vec[0][1] == 8); + try expect(vec[1][0] == 7); + try expect(vec[1][1] == 6); } }; try S.doTheTest(); comptime try S.doTheTest(); - try S.doThe2DTest(); - comptime try S.doThe2DTest(); } test "ability to give comptime types and non comptime types to same parameter" {