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 @@...@@ -5,6 +5,7 @@
5#endif5#endif
6#include <float.h>6#include <float.h>
7#include <limits.h>7#include <limits.h>
8#include <stdarg.h>
8#include <stddef.h>9#include <stddef.h>
9#include <stdint.h>10#include <stdint.h>
1011
src/codegen/c.zig+89-4
...@@ -211,6 +211,15 @@ const reserved_idents = std.ComptimeStringMap(void, .{...@@ -211,6 +211,15 @@ const reserved_idents = std.ComptimeStringMap(void, .{
211 .{ "volatile", {} },211 .{ "volatile", {} },
212 .{ "while ", {} },212 .{ "while ", {} },
213213
214 // stdarg.h
215 .{ "va_start", {} },
216 .{ "va_arg", {} },
217 .{ "va_end", {} },
218 .{ "va_copy", {} },
219
220 // stddef.h
221 .{ "offsetof", {} },
222
214 // windows.h223 // windows.h
215 .{ "max", {} },224 .{ "max", {} },
216 .{ "min", {} },225 .{ "min", {} },
...@@ -2952,10 +2961,10 @@ fn genBodyInner(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail,...@@ -2952,10 +2961,10 @@ fn genBodyInner(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail,
2952 .error_set_has_value => return f.fail("TODO: C backend: implement error_set_has_value", .{}),2961 .error_set_has_value => return f.fail("TODO: C backend: implement error_set_has_value", .{}),
2953 .vector_store_elem => return f.fail("TODO: C backend: implement vector_store_elem", .{}),2962 .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", .{}),2964 .c_va_start => try airCVaStart(f, inst),
2956 .c_va_copy => return f.fail("TODO implement c_va_copy", .{}),2965 .c_va_arg => try airCVaArg(f, inst),
2957 .c_va_end => return f.fail("TODO implement c_va_end", .{}),2966 .c_va_end => try airCVaEnd(f, inst),
2958 .c_va_start => return f.fail("TODO implement c_va_start", .{}),2967 .c_va_copy => try airCVaCopy(f, inst),
2959 // zig fmt: on2968 // zig fmt: on
2960 };2969 };
2961 if (result_value == .new_local) {2970 if (result_value == .new_local) {
...@@ -6862,6 +6871,82 @@ fn airMulAdd(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -6862,6 +6871,82 @@ fn airMulAdd(f: *Function, inst: Air.Inst.Index) !CValue {
6862 return local;6871 return local;
6863}6872}
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
6865fn toMemoryOrder(order: std.builtin.AtomicOrder) [:0]const u8 {6950fn toMemoryOrder(order: std.builtin.AtomicOrder) [:0]const u8 {
6866 return switch (order) {6951 return switch (order) {
6867 // Note: unordered is actually even less atomic than relaxed6952 // 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 {...@@ -96,10 +96,9 @@ fn doNothingWithFirstArg(args: anytype) void {
96test "simple variadic function" {96test "simple variadic function" {
97 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO97 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
98 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO98 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
99 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
100 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO99 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
101 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO100 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) {
103 // https://github.com/ziglang/zig/issues/14096102 // https://github.com/ziglang/zig/issues/14096
104 return error.SkipZigTest;103 return error.SkipZigTest;
105 }104 }
...@@ -124,8 +123,10 @@ test "simple variadic function" {...@@ -124,8 +123,10 @@ test "simple variadic function" {
124 }123 }
125 };124 };
126125
127 try std.testing.expectEqual(@as(c_int, 0), S.simple(@as(c_int, 0)));126 if (builtin.zig_backend != .stage2_c) { // C doesn't support varargs without a preceding runtime arg.
128 try std.testing.expectEqual(@as(c_int, 1024), S.simple(@as(c_int, 1024)));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 }
129 try std.testing.expectEqual(@as(c_int, 0), S.add(0));130 try std.testing.expectEqual(@as(c_int, 0), S.add(0));
130 try std.testing.expectEqual(@as(c_int, 1), S.add(1, @as(c_int, 1)));131 try std.testing.expectEqual(@as(c_int, 1), S.add(1, @as(c_int, 1)));
131 try std.testing.expectEqual(@as(c_int, 3), S.add(2, @as(c_int, 1), @as(c_int, 2)));132 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" {...@@ -134,10 +135,9 @@ test "simple variadic function" {
134test "variadic functions" {135test "variadic functions" {
135 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO136 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
136 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO137 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
137 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
138 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO138 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
139 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO139 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) {
141 // https://github.com/ziglang/zig/issues/14096141 // https://github.com/ziglang/zig/issues/14096
142 return error.SkipZigTest;142 return error.SkipZigTest;
143 }143 }
...@@ -178,10 +178,9 @@ test "variadic functions" {...@@ -178,10 +178,9 @@ test "variadic functions" {
178test "copy VaList" {178test "copy VaList" {
179 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO179 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
180 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO180 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
181 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
182 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO181 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
183 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO182 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) {
185 // https://github.com/ziglang/zig/issues/14096184 // https://github.com/ziglang/zig/issues/14096
186 return error.SkipZigTest;185 return error.SkipZigTest;
187 }186 }