aboutsummaryrefslogtreecommitdiff
path: root/src/codegen/c.zig
diff options
context:
space:
mode:
authorAndrew Kelley <andrew@ziglang.org>2021-10-28 15:59:14 -0700
committerAndrew Kelley <andrew@ziglang.org>2021-10-28 15:59:14 -0700
commitd2f9646d98615d85589d2c46237559d1249f2765 (patch)
tree87c2297912251993970a282703f688c72932e228 /src/codegen/c.zig
parent234d94e42b832dd17eb9144f5523e03ef4fa8eb3 (diff)
downloadzig-d2f9646d98615d85589d2c46237559d1249f2765.tar.gz
zig-d2f9646d98615d85589d2c46237559d1249f2765.zip
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
Diffstat (limited to 'src/codegen/c.zig')
-rw-r--r--src/codegen/c.zig151
1 files changed, 103 insertions, 48 deletions
diff --git a/src/codegen/c.zig b/src/codegen/c.zig
index dd71590566..139809aac2 100644
--- a/src/codegen/c.zig
+++ b/src/codegen/c.zig
@@ -397,8 +397,9 @@ pub const DeclGen = struct {
.Struct => {
const field_vals = val.castTag(.@"struct").?.data;
+ try writer.writeAll("(");
try dg.renderType(writer, ty);
- try writer.writeAll("{");
+ try writer.writeAll("){");
for (field_vals) |field_val, i| {
const field_ty = ty.structFieldType(i);
@@ -529,9 +530,9 @@ pub const DeclGen = struct {
const elem_type = t.elemType();
try dg.renderType(bw, elem_type);
try bw.writeAll(" *");
- if (t.isConstPtr()) {
- try bw.writeAll("const ");
- }
+ // We skip the const qualifier because C's type system
+ // would not allow a local mutable variable which is this slice type
+ // to be overwritten with a new slice type.
if (t.isVolatilePtr()) {
try bw.writeAll("volatile ");
}
@@ -549,15 +550,40 @@ pub const DeclGen = struct {
try t.copy(dg.typedefs_arena),
.{ .name = name, .rendered = rendered },
);
- } else {
- try dg.renderType(w, t.elemType());
- try w.writeAll(" *");
- if (t.isConstPtr()) {
- try w.writeAll("const ");
+ return;
+ }
+ if (t.castPtrToFn()) |fn_ty| {
+ const fn_info = fn_ty.fnInfo();
+ try dg.renderType(w, fn_info.return_type);
+ try w.writeAll(" (*)(");
+ const param_len = fn_info.param_types.len;
+ const is_var_args = fn_info.is_var_args;
+ if (param_len == 0 and !is_var_args)
+ try w.writeAll("void")
+ else {
+ var index: usize = 0;
+ while (index < param_len) : (index += 1) {
+ if (index > 0) {
+ try w.writeAll(", ");
+ }
+ try dg.renderType(w, fn_info.param_types[index]);
+ }
}
- if (t.isVolatilePtr()) {
- try w.writeAll("volatile ");
+ if (is_var_args) {
+ if (param_len != 0) try w.writeAll(", ");
+ try w.writeAll("...");
}
+ try w.writeByte(')');
+ return;
+ }
+
+ try dg.renderType(w, t.elemType());
+ try w.writeAll(" *");
+ if (t.isConstPtr()) {
+ try w.writeAll("const ");
+ }
+ if (t.isVolatilePtr()) {
+ try w.writeAll("volatile ");
}
},
.Array => {
@@ -685,28 +711,7 @@ pub const DeclGen = struct {
try dg.renderType(w, int_tag_ty);
},
.Union => return dg.fail("TODO: C backend: implement type Union", .{}),
- .Fn => {
- try dg.renderType(w, t.fnReturnType());
- try w.writeAll(" (*)(");
- const param_len = t.fnParamLen();
- const is_var_args = t.fnIsVarArgs();
- if (param_len == 0 and !is_var_args)
- try w.writeAll("void")
- else {
- var index: usize = 0;
- while (index < param_len) : (index += 1) {
- if (index > 0) {
- try w.writeAll(", ");
- }
- try dg.renderType(w, t.fnParamType(index));
- }
- }
- if (is_var_args) {
- if (param_len != 0) try w.writeAll(", ");
- try w.writeAll("...");
- }
- try w.writeByte(')');
- },
+ .Fn => unreachable, // This is a function body, not a function pointer.
.Opaque => return dg.fail("TODO: C backend: implement type Opaque", .{}),
.Frame => return dg.fail("TODO: C backend: implement type Frame", .{}),
.AnyFrame => return dg.fail("TODO: C backend: implement type AnyFrame", .{}),
@@ -742,8 +747,59 @@ pub const DeclGen = struct {
render_ty = render_ty.elemType();
}
- if (render_ty.zigTypeTag() == .Fn) {
- const ret_ty = render_ty.fnReturnType();
+ // TODO this is duplicated from the code below and does not handle
+ // arbitrary nesting of pointers. This renderTypeAndName function
+ // needs to be reworked by someone who understands C's insane type syntax. That
+ // person might be future me but it is certainly not present me.
+ if (render_ty.zigTypeTag() == .Pointer and
+ render_ty.childType().zigTypeTag() == .Pointer and
+ render_ty.childType().childType().zigTypeTag() == .Fn)
+ {
+ const ptr2_ty = render_ty.childType();
+ const fn_info = ptr2_ty.childType().fnInfo();
+ const ret_ty = fn_info.return_type;
+ if (ret_ty.zigTypeTag() == .NoReturn) {
+ // noreturn attribute is not allowed here.
+ try w.writeAll("void");
+ } else {
+ try dg.renderType(w, ret_ty);
+ }
+ try w.writeAll(" (*");
+ switch (mutability) {
+ .Const => try w.writeAll("const "),
+ .Mut => {},
+ }
+ if (!ptr2_ty.ptrIsMutable()) {
+ try w.writeAll("*const ");
+ } else {
+ try w.writeAll("*");
+ }
+ try dg.writeCValue(w, name);
+ try w.writeAll(")(");
+ const param_len = fn_info.param_types.len;
+ const is_var_args = fn_info.is_var_args;
+ if (param_len == 0 and !is_var_args)
+ try w.writeAll("void")
+ else {
+ var index: usize = 0;
+ while (index < param_len) : (index += 1) {
+ if (index > 0) {
+ try w.writeAll(", ");
+ }
+ try dg.renderType(w, fn_info.param_types[index]);
+ }
+ }
+ if (is_var_args) {
+ if (param_len != 0) try w.writeAll(", ");
+ try w.writeAll("...");
+ }
+ try w.writeByte(')');
+ return;
+ }
+
+ if (render_ty.castPtrToFn()) |fn_ty| {
+ const fn_info = fn_ty.fnInfo();
+ const ret_ty = fn_info.return_type;
if (ret_ty.zigTypeTag() == .NoReturn) {
// noreturn attribute is not allowed here.
try w.writeAll("void");
@@ -757,8 +813,8 @@ pub const DeclGen = struct {
}
try dg.writeCValue(w, name);
try w.writeAll(")(");
- const param_len = render_ty.fnParamLen();
- const is_var_args = render_ty.fnIsVarArgs();
+ const param_len = fn_info.param_types.len;
+ const is_var_args = fn_info.is_var_args;
if (param_len == 0 and !is_var_args)
try w.writeAll("void")
else {
@@ -767,7 +823,7 @@ pub const DeclGen = struct {
if (index > 0) {
try w.writeAll(", ");
}
- try dg.renderType(w, render_ty.fnParamType(index));
+ try dg.renderType(w, fn_info.param_types[index]);
}
}
if (is_var_args) {
@@ -1083,7 +1139,7 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO
.ptr_elem_val => try airPtrElemVal(f, inst, "["),
.ptr_elem_ptr => try airPtrElemPtr(f, inst),
- .slice_elem_val => try airSliceElemVal(f, inst, "["),
+ .slice_elem_val => try airSliceElemVal(f, inst),
.slice_elem_ptr => try airSliceElemPtr(f, inst),
.array_elem_val => try airArrayElemVal(f, inst),
@@ -1149,27 +1205,26 @@ fn airPtrElemPtr(f: *Function, inst: Air.Inst.Index) !CValue {
return f.fail("TODO: C backend: airPtrElemPtr", .{});
}
-fn airSliceElemVal(f: *Function, inst: Air.Inst.Index, prefix: []const u8) !CValue {
- const is_volatile = false; // TODO
- if (!is_volatile and f.liveness.isUnused(inst))
- return CValue.none;
-
+fn airSliceElemVal(f: *Function, inst: Air.Inst.Index) !CValue {
const bin_op = f.air.instructions.items(.data)[inst].bin_op;
+ const slice_ty = f.air.typeOf(bin_op.lhs);
+ if (!slice_ty.isVolatilePtr() and f.liveness.isUnused(inst)) return CValue.none;
+
const slice = try f.resolveInst(bin_op.lhs);
const index = try f.resolveInst(bin_op.rhs);
const writer = f.object.writer();
const local = try f.allocLocal(f.air.typeOfIndex(inst), .Const);
try writer.writeAll(" = ");
try f.writeCValue(writer, slice);
- try writer.writeAll(prefix);
+ try writer.writeAll(".ptr[");
try f.writeCValue(writer, index);
try writer.writeAll("];\n");
return local;
}
fn airSliceElemPtr(f: *Function, inst: Air.Inst.Index) !CValue {
- if (f.liveness.isUnused(inst))
- return CValue.none;
+ if (f.liveness.isUnused(inst)) return CValue.none;
+
const ty_pl = f.air.instructions.items(.data)[inst].ty_pl;
const bin_op = f.air.extraData(Air.Bin, ty_pl.payload).data;
@@ -1179,7 +1234,7 @@ fn airSliceElemPtr(f: *Function, inst: Air.Inst.Index) !CValue {
const local = try f.allocLocal(f.air.typeOfIndex(inst), .Const);
try writer.writeAll(" = &");
try f.writeCValue(writer, slice);
- try writer.writeByte('[');
+ try writer.writeAll(".ptr[");
try f.writeCValue(writer, index);
try writer.writeAll("];\n");
return local;