mirror of
https://github.com/ziglang/zig.git
synced 2026-02-12 20:37:54 +00:00
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
This commit is contained in:
parent
234d94e42b
commit
d2f9646d98
@ -4734,6 +4734,10 @@ pub fn populateTestFunctions(mod: *Module) !void {
|
||||
}),
|
||||
.val = try Value.Tag.array.create(arena, test_fn_vals),
|
||||
});
|
||||
|
||||
// Add a dependency on each test name and function pointer.
|
||||
try array_decl.dependencies.ensureUnusedCapacity(gpa, test_fn_vals.len * 2);
|
||||
|
||||
for (mod.test_functions.keys()) |test_decl, i| {
|
||||
const test_name_slice = mem.sliceTo(test_decl.name, 0);
|
||||
const test_name_decl = n: {
|
||||
@ -4747,6 +4751,8 @@ pub fn populateTestFunctions(mod: *Module) !void {
|
||||
try test_name_decl.finalizeNewArena(&name_decl_arena);
|
||||
break :n test_name_decl;
|
||||
};
|
||||
array_decl.dependencies.putAssumeCapacityNoClobber(test_decl, {});
|
||||
array_decl.dependencies.putAssumeCapacityNoClobber(test_name_decl, {});
|
||||
try mod.linkerUpdateDecl(test_name_decl);
|
||||
|
||||
const field_vals = try arena.create([3]Value);
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -252,6 +252,14 @@ pub const Type = extern union {
|
||||
};
|
||||
}
|
||||
|
||||
/// If it is a function pointer, returns the function type. Otherwise returns null.
|
||||
pub fn castPtrToFn(ty: Type) ?Type {
|
||||
if (ty.zigTypeTag() != .Pointer) return null;
|
||||
const elem_ty = ty.childType();
|
||||
if (elem_ty.zigTypeTag() != .Fn) return null;
|
||||
return elem_ty;
|
||||
}
|
||||
|
||||
pub fn ptrIsMutable(ty: Type) bool {
|
||||
return switch (ty.tag()) {
|
||||
.single_const_pointer_to_comptime_int,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user