authorgravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2023-02-23 21:18:26-05:00
committergravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2023-02-23 21:25:29-05:00
logf8aecef6705a75a4c35754bcac32c27602b84711
tree96a98d4ea9cb935a3eec830b00c80a2658363ed3
parent1f3d9f79c19c225b2043a1d0355cbc74addcf03a

CBE: implement the future

Turns out f(...) will be supported one day.

2 files changed, 14 insertions(+), 6 deletions(-)

src/codegen/c.zig+4-5
...@@ -6876,17 +6876,16 @@ fn airCVaStart(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -6876,17 +6876,16 @@ fn airCVaStart(f: *Function, inst: Air.Inst.Index) !CValue {
68766876
6877 const inst_ty = f.air.typeOfIndex(inst);6877 const inst_ty = f.air.typeOfIndex(inst);
6878 const fn_cty = try f.typeToCType(f.object.dg.decl.?.ty, .complete);6878 const fn_cty = try f.typeToCType(f.object.dg.decl.?.ty, .complete);
6879
6880 const param_len = fn_cty.castTag(.varargs_function).?.data.param_types.len;6879 const param_len = fn_cty.castTag(.varargs_function).?.data.param_types.len;
6881 if (param_len == 0)
6882 return f.fail("CBE: C requires at least one runtime argument for varargs functions", .{});
68836880
6884 const writer = f.object.writer();6881 const writer = f.object.writer();
6885 const local = try f.allocLocal(inst, inst_ty);6882 const local = try f.allocLocal(inst, inst_ty);
6886 try writer.writeAll("va_start(*(va_list *)&");6883 try writer.writeAll("va_start(*(va_list *)&");
6887 try f.writeCValue(writer, local, .Other);6884 try f.writeCValue(writer, local, .Other);
6888 try writer.writeAll(", ");6885 if (param_len > 0) {
6889 try f.writeCValue(writer, .{ .arg = param_len - 1 }, .FunctionArgument);6886 try writer.writeAll(", ");
6887 try f.writeCValue(writer, .{ .arg = param_len - 1 }, .FunctionArgument);
6888 }
6890 try writer.writeAll(");\n");6889 try writer.writeAll(");\n");
6891 return local;6890 return local;
6892}6891}
test/behavior/var_args.zig+10-1
...@@ -111,6 +111,12 @@ test "simple variadic function" {...@@ -111,6 +111,12 @@ test "simple variadic function" {
111 return @cVaArg(&ap, c_int);111 return @cVaArg(&ap, c_int);
112 }112 }
113113
114 fn compatible(_: c_int, ...) callconv(.C) c_int {
115 var ap = @cVaStart();
116 defer @cVaEnd(&ap);
117 return @cVaArg(&ap, c_int);
118 }
119
114 fn add(count: c_int, ...) callconv(.C) c_int {120 fn add(count: c_int, ...) callconv(.C) c_int {
115 var ap = @cVaStart();121 var ap = @cVaStart();
116 defer @cVaEnd(&ap);122 defer @cVaEnd(&ap);
...@@ -123,10 +129,13 @@ test "simple variadic function" {...@@ -123,10 +129,13 @@ test "simple variadic function" {
123 }129 }
124 };130 };
125131
126 if (builtin.zig_backend != .stage2_c) { // C doesn't support varargs without a preceding runtime arg.132 if (builtin.zig_backend != .stage2_c) {
133 // pre C23 doesn't support varargs without a preceding runtime arg.
127 try std.testing.expectEqual(@as(c_int, 0), S.simple(@as(c_int, 0)));134 try std.testing.expectEqual(@as(c_int, 0), S.simple(@as(c_int, 0)));
128 try std.testing.expectEqual(@as(c_int, 1024), S.simple(@as(c_int, 1024)));135 try std.testing.expectEqual(@as(c_int, 1024), S.simple(@as(c_int, 1024)));
129 }136 }
137 try std.testing.expectEqual(@as(c_int, 0), S.compatible(undefined, @as(c_int, 0)));
138 try std.testing.expectEqual(@as(c_int, 1024), S.compatible(undefined, @as(c_int, 1024)));
130 try std.testing.expectEqual(@as(c_int, 0), S.add(0));139 try std.testing.expectEqual(@as(c_int, 0), S.add(0));
131 try std.testing.expectEqual(@as(c_int, 1), S.add(1, @as(c_int, 1)));140 try std.testing.expectEqual(@as(c_int, 1), S.add(1, @as(c_int, 1)));
132 try std.testing.expectEqual(@as(c_int, 3), S.add(2, @as(c_int, 1), @as(c_int, 2)));141 try std.testing.expectEqual(@as(c_int, 3), S.add(2, @as(c_int, 1), @as(c_int, 2)));