authorgravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2023-02-23 00:28:49-05:00
committergravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2023-02-23 01:21:59-05:00
log57f6adf85da58c0c91a036deaa614c30df010b78
tree8f9e2fafe159bc4d51123ead1a22036f4a995eae
parent597e8011f7b2ea76755165fa5a09b2f725180268

CBE: implement c varargs

Removed some backend test skip checks for things disabled in std.

3 files changed, 97 insertions(+), 12 deletions(-)

lib/zig.h+1
......@@ -5,6 +5,7 @@
55#endif
66#include <float.h>
77#include <limits.h>
8#include <stdarg.h>
89#include <stddef.h>
910#include <stdint.h>
1011
src/codegen/c.zig+89-4
......@@ -211,6 +211,15 @@ const reserved_idents = std.ComptimeStringMap(void, .{
211211 .{ "volatile", {} },
212212 .{ "while ", {} },
213213
214 // stdarg.h
215 .{ "va_start", {} },
216 .{ "va_arg", {} },
217 .{ "va_end", {} },
218 .{ "va_copy", {} },
219
220 // stddef.h
221 .{ "offsetof", {} },
222
214223 // windows.h
215224 .{ "max", {} },
216225 .{ "min", {} },
......@@ -2952,10 +2961,10 @@ fn genBodyInner(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail,
29522961 .error_set_has_value => return f.fail("TODO: C backend: implement error_set_has_value", .{}),
29532962 .vector_store_elem => return f.fail("TODO: C backend: implement vector_store_elem", .{}),
29542963
2955 .c_va_arg => return f.fail("TODO implement c_va_arg", .{}),
2956 .c_va_copy => return f.fail("TODO implement c_va_copy", .{}),
2957 .c_va_end => return f.fail("TODO implement c_va_end", .{}),
2958 .c_va_start => return f.fail("TODO implement c_va_start", .{}),
2964 .c_va_start => try airCVaStart(f, inst),
2965 .c_va_arg => try airCVaArg(f, inst),
2966 .c_va_end => try airCVaEnd(f, inst),
2967 .c_va_copy => try airCVaCopy(f, inst),
29592968 // zig fmt: on
29602969 };
29612970 if (result_value == .new_local) {
......@@ -6862,6 +6871,82 @@ fn airMulAdd(f: *Function, inst: Air.Inst.Index) !CValue {
68626871 return local;
68636872}
68646873
6874fn airCVaStart(f: *Function, inst: Air.Inst.Index) !CValue {
6875 if (f.liveness.isUnused(inst)) return .none;
6876
6877 const inst_ty = f.air.typeOfIndex(inst);
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;
6881 if (param_len == 0)
6882 return f.fail("CBE: C requires at least one runtime argument for varargs functions", .{});
6883
6884 const writer = f.object.writer();
6885 const local = try f.allocLocal(inst, inst_ty);
6886 try writer.writeAll("va_start(*(va_list *)&");
6887 try f.writeCValue(writer, local, .Other);
6888 try writer.writeAll(", ");
6889 try f.writeCValue(writer, .{ .arg = param_len - 1 }, .FunctionArgument);
6890 try writer.writeAll(");\n");
6891 return local;
6892}
6893
6894fn airCVaArg(f: *Function, inst: Air.Inst.Index) !CValue {
6895 const ty_op = f.air.instructions.items(.data)[inst].ty_op;
6896 if (f.liveness.isUnused(inst)) {
6897 try reap(f, inst, &.{ty_op.operand});
6898 return .none;
6899 }
6900
6901 const inst_ty = f.air.typeOfIndex(inst);
6902 const va_list = try f.resolveInst(ty_op.operand);
6903 try reap(f, inst, &.{ty_op.operand});
6904
6905 const writer = f.object.writer();
6906 const local = try f.allocLocal(inst, inst_ty);
6907 try f.writeCValue(writer, local, .Other);
6908 try writer.writeAll(" = va_arg(*(va_list *)");
6909 try f.writeCValue(writer, va_list, .Other);
6910 try writer.writeAll(", ");
6911 try f.renderType(writer, f.air.getRefType(ty_op.ty));
6912 try writer.writeAll(");\n");
6913 return local;
6914}
6915
6916fn airCVaEnd(f: *Function, inst: Air.Inst.Index) !CValue {
6917 const un_op = f.air.instructions.items(.data)[inst].un_op;
6918
6919 const va_list = try f.resolveInst(un_op);
6920 try reap(f, inst, &.{un_op});
6921
6922 const writer = f.object.writer();
6923 try writer.writeAll("va_end(*(va_list *)");
6924 try f.writeCValue(writer, va_list, .Other);
6925 try writer.writeAll(");\n");
6926 return .none;
6927}
6928
6929fn airCVaCopy(f: *Function, inst: Air.Inst.Index) !CValue {
6930 const ty_op = f.air.instructions.items(.data)[inst].ty_op;
6931 if (f.liveness.isUnused(inst)) {
6932 try reap(f, inst, &.{ty_op.operand});
6933 return .none;
6934 }
6935
6936 const inst_ty = f.air.typeOfIndex(inst);
6937 const va_list = try f.resolveInst(ty_op.operand);
6938 try reap(f, inst, &.{ty_op.operand});
6939
6940 const writer = f.object.writer();
6941 const local = try f.allocLocal(inst, inst_ty);
6942 try writer.writeAll("va_copy(*(va_list *)&");
6943 try f.writeCValue(writer, local, .Other);
6944 try writer.writeAll(", *(va_list *)");
6945 try f.writeCValue(writer, va_list, .Other);
6946 try writer.writeAll(");\n");
6947 return local;
6948}
6949
68656950fn toMemoryOrder(order: std.builtin.AtomicOrder) [:0]const u8 {
68666951 return switch (order) {
68676952 // Note: unordered is actually even less atomic than relaxed
test/behavior/var_args.zig+7-8
......@@ -96,10 +96,9 @@ fn doNothingWithFirstArg(args: anytype) void {
9696test "simple variadic function" {
9797 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
9898 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
99 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
10099 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
101100 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
102 if (builtin.cpu.arch == .aarch64 and builtin.os.tag != .macos and builtin.zig_backend == .stage2_llvm) {
101 if (builtin.cpu.arch == .aarch64 and builtin.os.tag != .macos) {
103102 // https://github.com/ziglang/zig/issues/14096
104103 return error.SkipZigTest;
105104 }
......@@ -124,8 +123,10 @@ test "simple variadic function" {
124123 }
125124 };
126125
127 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)));
126 if (builtin.zig_backend != .stage2_c) { // C doesn't support varargs without a preceding runtime arg.
127 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)));
129 }
129130 try std.testing.expectEqual(@as(c_int, 0), S.add(0));
130131 try std.testing.expectEqual(@as(c_int, 1), S.add(1, @as(c_int, 1)));
131132 try std.testing.expectEqual(@as(c_int, 3), S.add(2, @as(c_int, 1), @as(c_int, 2)));
......@@ -134,10 +135,9 @@ test "simple variadic function" {
134135test "variadic functions" {
135136 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
136137 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
137 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
138138 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
139139 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
140 if (builtin.cpu.arch == .aarch64 and builtin.os.tag != .macos and builtin.zig_backend == .stage2_llvm) {
140 if (builtin.cpu.arch == .aarch64 and builtin.os.tag != .macos) {
141141 // https://github.com/ziglang/zig/issues/14096
142142 return error.SkipZigTest;
143143 }
......@@ -178,10 +178,9 @@ test "variadic functions" {
178178test "copy VaList" {
179179 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
180180 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
181 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
182181 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
183182 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
184 if (builtin.cpu.arch == .aarch64 and builtin.os.tag != .macos and builtin.zig_backend == .stage2_llvm) {
183 if (builtin.cpu.arch == .aarch64 and builtin.os.tag != .macos) {
185184 // https://github.com/ziglang/zig/issues/14096
186185 return error.SkipZigTest;
187186 }