authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-10-28 15:59:14-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-10-28 15:59:14-07:00
logd2f9646d98615d85589d2c46237559d1249f2765
tree87c2297912251993970a282703f688c72932e228
parent234d94e42b832dd17eb9144f5523e03ef4fa8eb3

C backend: fix enough that zig test works

* test_functions: properly add dependencies of the array on test functions and test names so that the order comes out correctly. * fix lowering of struct literals to add parentheses around the type name. * omit const qualifier in slices because otherwise slices cannot be reassigned even when they are local variables. * special case pointer to functions and double pointer to functions in renderTypeAndName. This code will need to be cleaned up but for now it helps us make progress on other C backend stuff. * fix slice element access to lower to `.ptr[` instead of `[`. * airSliceElemVal: respect volatile slices

3 files changed, 117 insertions(+), 48 deletions(-)

src/Module.zig+6
......@@ -4734,6 +4734,10 @@ pub fn populateTestFunctions(mod: *Module) !void {
47344734 }),
47354735 .val = try Value.Tag.array.create(arena, test_fn_vals),
47364736 });
4737
4738 // Add a dependency on each test name and function pointer.
4739 try array_decl.dependencies.ensureUnusedCapacity(gpa, test_fn_vals.len * 2);
4740
47374741 for (mod.test_functions.keys()) |test_decl, i| {
47384742 const test_name_slice = mem.sliceTo(test_decl.name, 0);
47394743 const test_name_decl = n: {
......@@ -4747,6 +4751,8 @@ pub fn populateTestFunctions(mod: *Module) !void {
47474751 try test_name_decl.finalizeNewArena(&name_decl_arena);
47484752 break :n test_name_decl;
47494753 };
4754 array_decl.dependencies.putAssumeCapacityNoClobber(test_decl, {});
4755 array_decl.dependencies.putAssumeCapacityNoClobber(test_name_decl, {});
47504756 try mod.linkerUpdateDecl(test_name_decl);
47514757
47524758 const field_vals = try arena.create([3]Value);
src/codegen/c.zig+103-48
......@@ -397,8 +397,9 @@ pub const DeclGen = struct {
397397 .Struct => {
398398 const field_vals = val.castTag(.@"struct").?.data;
399399
400 try writer.writeAll("(");
400401 try dg.renderType(writer, ty);
401 try writer.writeAll("{");
402 try writer.writeAll("){");
402403
403404 for (field_vals) |field_val, i| {
404405 const field_ty = ty.structFieldType(i);
......@@ -529,9 +530,9 @@ pub const DeclGen = struct {
529530 const elem_type = t.elemType();
530531 try dg.renderType(bw, elem_type);
531532 try bw.writeAll(" *");
532 if (t.isConstPtr()) {
533 try bw.writeAll("const ");
534 }
533 // We skip the const qualifier because C's type system
534 // would not allow a local mutable variable which is this slice type
535 // to be overwritten with a new slice type.
535536 if (t.isVolatilePtr()) {
536537 try bw.writeAll("volatile ");
537538 }
......@@ -549,15 +550,40 @@ pub const DeclGen = struct {
549550 try t.copy(dg.typedefs_arena),
550551 .{ .name = name, .rendered = rendered },
551552 );
552 } else {
553 try dg.renderType(w, t.elemType());
554 try w.writeAll(" *");
555 if (t.isConstPtr()) {
556 try w.writeAll("const ");
553 return;
554 }
555 if (t.castPtrToFn()) |fn_ty| {
556 const fn_info = fn_ty.fnInfo();
557 try dg.renderType(w, fn_info.return_type);
558 try w.writeAll(" (*)(");
559 const param_len = fn_info.param_types.len;
560 const is_var_args = fn_info.is_var_args;
561 if (param_len == 0 and !is_var_args)
562 try w.writeAll("void")
563 else {
564 var index: usize = 0;
565 while (index < param_len) : (index += 1) {
566 if (index > 0) {
567 try w.writeAll(", ");
568 }
569 try dg.renderType(w, fn_info.param_types[index]);
570 }
557571 }
558 if (t.isVolatilePtr()) {
559 try w.writeAll("volatile ");
572 if (is_var_args) {
573 if (param_len != 0) try w.writeAll(", ");
574 try w.writeAll("...");
560575 }
576 try w.writeByte(')');
577 return;
578 }
579
580 try dg.renderType(w, t.elemType());
581 try w.writeAll(" *");
582 if (t.isConstPtr()) {
583 try w.writeAll("const ");
584 }
585 if (t.isVolatilePtr()) {
586 try w.writeAll("volatile ");
561587 }
562588 },
563589 .Array => {
......@@ -685,28 +711,7 @@ pub const DeclGen = struct {
685711 try dg.renderType(w, int_tag_ty);
686712 },
687713 .Union => return dg.fail("TODO: C backend: implement type Union", .{}),
688 .Fn => {
689 try dg.renderType(w, t.fnReturnType());
690 try w.writeAll(" (*)(");
691 const param_len = t.fnParamLen();
692 const is_var_args = t.fnIsVarArgs();
693 if (param_len == 0 and !is_var_args)
694 try w.writeAll("void")
695 else {
696 var index: usize = 0;
697 while (index < param_len) : (index += 1) {
698 if (index > 0) {
699 try w.writeAll(", ");
700 }
701 try dg.renderType(w, t.fnParamType(index));
702 }
703 }
704 if (is_var_args) {
705 if (param_len != 0) try w.writeAll(", ");
706 try w.writeAll("...");
707 }
708 try w.writeByte(')');
709 },
714 .Fn => unreachable, // This is a function body, not a function pointer.
710715 .Opaque => return dg.fail("TODO: C backend: implement type Opaque", .{}),
711716 .Frame => return dg.fail("TODO: C backend: implement type Frame", .{}),
712717 .AnyFrame => return dg.fail("TODO: C backend: implement type AnyFrame", .{}),
......@@ -742,8 +747,59 @@ pub const DeclGen = struct {
742747 render_ty = render_ty.elemType();
743748 }
744749
745 if (render_ty.zigTypeTag() == .Fn) {
746 const ret_ty = render_ty.fnReturnType();
750 // TODO this is duplicated from the code below and does not handle
751 // arbitrary nesting of pointers. This renderTypeAndName function
752 // needs to be reworked by someone who understands C's insane type syntax. That
753 // person might be future me but it is certainly not present me.
754 if (render_ty.zigTypeTag() == .Pointer and
755 render_ty.childType().zigTypeTag() == .Pointer and
756 render_ty.childType().childType().zigTypeTag() == .Fn)
757 {
758 const ptr2_ty = render_ty.childType();
759 const fn_info = ptr2_ty.childType().fnInfo();
760 const ret_ty = fn_info.return_type;
761 if (ret_ty.zigTypeTag() == .NoReturn) {
762 // noreturn attribute is not allowed here.
763 try w.writeAll("void");
764 } else {
765 try dg.renderType(w, ret_ty);
766 }
767 try w.writeAll(" (*");
768 switch (mutability) {
769 .Const => try w.writeAll("const "),
770 .Mut => {},
771 }
772 if (!ptr2_ty.ptrIsMutable()) {
773 try w.writeAll("*const ");
774 } else {
775 try w.writeAll("*");
776 }
777 try dg.writeCValue(w, name);
778 try w.writeAll(")(");
779 const param_len = fn_info.param_types.len;
780 const is_var_args = fn_info.is_var_args;
781 if (param_len == 0 and !is_var_args)
782 try w.writeAll("void")
783 else {
784 var index: usize = 0;
785 while (index < param_len) : (index += 1) {
786 if (index > 0) {
787 try w.writeAll(", ");
788 }
789 try dg.renderType(w, fn_info.param_types[index]);
790 }
791 }
792 if (is_var_args) {
793 if (param_len != 0) try w.writeAll(", ");
794 try w.writeAll("...");
795 }
796 try w.writeByte(')');
797 return;
798 }
799
800 if (render_ty.castPtrToFn()) |fn_ty| {
801 const fn_info = fn_ty.fnInfo();
802 const ret_ty = fn_info.return_type;
747803 if (ret_ty.zigTypeTag() == .NoReturn) {
748804 // noreturn attribute is not allowed here.
749805 try w.writeAll("void");
......@@ -757,8 +813,8 @@ pub const DeclGen = struct {
757813 }
758814 try dg.writeCValue(w, name);
759815 try w.writeAll(")(");
760 const param_len = render_ty.fnParamLen();
761 const is_var_args = render_ty.fnIsVarArgs();
816 const param_len = fn_info.param_types.len;
817 const is_var_args = fn_info.is_var_args;
762818 if (param_len == 0 and !is_var_args)
763819 try w.writeAll("void")
764820 else {
......@@ -767,7 +823,7 @@ pub const DeclGen = struct {
767823 if (index > 0) {
768824 try w.writeAll(", ");
769825 }
770 try dg.renderType(w, render_ty.fnParamType(index));
826 try dg.renderType(w, fn_info.param_types[index]);
771827 }
772828 }
773829 if (is_var_args) {
......@@ -1083,7 +1139,7 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO
10831139
10841140 .ptr_elem_val => try airPtrElemVal(f, inst, "["),
10851141 .ptr_elem_ptr => try airPtrElemPtr(f, inst),
1086 .slice_elem_val => try airSliceElemVal(f, inst, "["),
1142 .slice_elem_val => try airSliceElemVal(f, inst),
10871143 .slice_elem_ptr => try airSliceElemPtr(f, inst),
10881144 .array_elem_val => try airArrayElemVal(f, inst),
10891145
......@@ -1149,27 +1205,26 @@ fn airPtrElemPtr(f: *Function, inst: Air.Inst.Index) !CValue {
11491205 return f.fail("TODO: C backend: airPtrElemPtr", .{});
11501206}
11511207
1152fn airSliceElemVal(f: *Function, inst: Air.Inst.Index, prefix: []const u8) !CValue {
1153 const is_volatile = false; // TODO
1154 if (!is_volatile and f.liveness.isUnused(inst))
1155 return CValue.none;
1156
1208fn airSliceElemVal(f: *Function, inst: Air.Inst.Index) !CValue {
11571209 const bin_op = f.air.instructions.items(.data)[inst].bin_op;
1210 const slice_ty = f.air.typeOf(bin_op.lhs);
1211 if (!slice_ty.isVolatilePtr() and f.liveness.isUnused(inst)) return CValue.none;
1212
11581213 const slice = try f.resolveInst(bin_op.lhs);
11591214 const index = try f.resolveInst(bin_op.rhs);
11601215 const writer = f.object.writer();
11611216 const local = try f.allocLocal(f.air.typeOfIndex(inst), .Const);
11621217 try writer.writeAll(" = ");
11631218 try f.writeCValue(writer, slice);
1164 try writer.writeAll(prefix);
1219 try writer.writeAll(".ptr[");
11651220 try f.writeCValue(writer, index);
11661221 try writer.writeAll("];\n");
11671222 return local;
11681223}
11691224
11701225fn airSliceElemPtr(f: *Function, inst: Air.Inst.Index) !CValue {
1171 if (f.liveness.isUnused(inst))
1172 return CValue.none;
1226 if (f.liveness.isUnused(inst)) return CValue.none;
1227
11731228 const ty_pl = f.air.instructions.items(.data)[inst].ty_pl;
11741229 const bin_op = f.air.extraData(Air.Bin, ty_pl.payload).data;
11751230
......@@ -1179,7 +1234,7 @@ fn airSliceElemPtr(f: *Function, inst: Air.Inst.Index) !CValue {
11791234 const local = try f.allocLocal(f.air.typeOfIndex(inst), .Const);
11801235 try writer.writeAll(" = &");
11811236 try f.writeCValue(writer, slice);
1182 try writer.writeByte('[');
1237 try writer.writeAll(".ptr[");
11831238 try f.writeCValue(writer, index);
11841239 try writer.writeAll("];\n");
11851240 return local;
src/type.zig+8
......@@ -252,6 +252,14 @@ pub const Type = extern union {
252252 };
253253 }
254254
255 /// If it is a function pointer, returns the function type. Otherwise returns null.
256 pub fn castPtrToFn(ty: Type) ?Type {
257 if (ty.zigTypeTag() != .Pointer) return null;
258 const elem_ty = ty.childType();
259 if (elem_ty.zigTypeTag() != .Fn) return null;
260 return elem_ty;
261 }
262
255263 pub fn ptrIsMutable(ty: Type) bool {
256264 return switch (ty.tag()) {
257265 .single_const_pointer_to_comptime_int,