CBE: implement c varargs

Removed some backend test skip checks for things disabled in std.
This commit is contained in:
Jacob Young 2023-02-23 00:28:49 -05:00
parent 597e8011f7
commit 57f6adf85d
3 changed files with 97 additions and 12 deletions

View File

@ -5,6 +5,7 @@
#endif
#include <float.h>
#include <limits.h>
#include <stdarg.h>
#include <stddef.h>
#include <stdint.h>

View File

@ -211,6 +211,15 @@ const reserved_idents = std.ComptimeStringMap(void, .{
.{ "volatile", {} },
.{ "while ", {} },
// stdarg.h
.{ "va_start", {} },
.{ "va_arg", {} },
.{ "va_end", {} },
.{ "va_copy", {} },
// stddef.h
.{ "offsetof", {} },
// windows.h
.{ "max", {} },
.{ "min", {} },
@ -2952,10 +2961,10 @@ fn genBodyInner(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail,
.error_set_has_value => return f.fail("TODO: C backend: implement error_set_has_value", .{}),
.vector_store_elem => return f.fail("TODO: C backend: implement vector_store_elem", .{}),
.c_va_arg => return f.fail("TODO implement c_va_arg", .{}),
.c_va_copy => return f.fail("TODO implement c_va_copy", .{}),
.c_va_end => return f.fail("TODO implement c_va_end", .{}),
.c_va_start => return f.fail("TODO implement c_va_start", .{}),
.c_va_start => try airCVaStart(f, inst),
.c_va_arg => try airCVaArg(f, inst),
.c_va_end => try airCVaEnd(f, inst),
.c_va_copy => try airCVaCopy(f, inst),
// zig fmt: on
};
if (result_value == .new_local) {
@ -6862,6 +6871,82 @@ fn airMulAdd(f: *Function, inst: Air.Inst.Index) !CValue {
return local;
}
fn airCVaStart(f: *Function, inst: Air.Inst.Index) !CValue {
if (f.liveness.isUnused(inst)) return .none;
const inst_ty = f.air.typeOfIndex(inst);
const fn_cty = try f.typeToCType(f.object.dg.decl.?.ty, .complete);
const param_len = fn_cty.castTag(.varargs_function).?.data.param_types.len;
if (param_len == 0)
return f.fail("CBE: C requires at least one runtime argument for varargs functions", .{});
const writer = f.object.writer();
const local = try f.allocLocal(inst, inst_ty);
try writer.writeAll("va_start(*(va_list *)&");
try f.writeCValue(writer, local, .Other);
try writer.writeAll(", ");
try f.writeCValue(writer, .{ .arg = param_len - 1 }, .FunctionArgument);
try writer.writeAll(");\n");
return local;
}
fn airCVaArg(f: *Function, inst: Air.Inst.Index) !CValue {
const ty_op = f.air.instructions.items(.data)[inst].ty_op;
if (f.liveness.isUnused(inst)) {
try reap(f, inst, &.{ty_op.operand});
return .none;
}
const inst_ty = f.air.typeOfIndex(inst);
const va_list = try f.resolveInst(ty_op.operand);
try reap(f, inst, &.{ty_op.operand});
const writer = f.object.writer();
const local = try f.allocLocal(inst, inst_ty);
try f.writeCValue(writer, local, .Other);
try writer.writeAll(" = va_arg(*(va_list *)");
try f.writeCValue(writer, va_list, .Other);
try writer.writeAll(", ");
try f.renderType(writer, f.air.getRefType(ty_op.ty));
try writer.writeAll(");\n");
return local;
}
fn airCVaEnd(f: *Function, inst: Air.Inst.Index) !CValue {
const un_op = f.air.instructions.items(.data)[inst].un_op;
const va_list = try f.resolveInst(un_op);
try reap(f, inst, &.{un_op});
const writer = f.object.writer();
try writer.writeAll("va_end(*(va_list *)");
try f.writeCValue(writer, va_list, .Other);
try writer.writeAll(");\n");
return .none;
}
fn airCVaCopy(f: *Function, inst: Air.Inst.Index) !CValue {
const ty_op = f.air.instructions.items(.data)[inst].ty_op;
if (f.liveness.isUnused(inst)) {
try reap(f, inst, &.{ty_op.operand});
return .none;
}
const inst_ty = f.air.typeOfIndex(inst);
const va_list = try f.resolveInst(ty_op.operand);
try reap(f, inst, &.{ty_op.operand});
const writer = f.object.writer();
const local = try f.allocLocal(inst, inst_ty);
try writer.writeAll("va_copy(*(va_list *)&");
try f.writeCValue(writer, local, .Other);
try writer.writeAll(", *(va_list *)");
try f.writeCValue(writer, va_list, .Other);
try writer.writeAll(");\n");
return local;
}
fn toMemoryOrder(order: std.builtin.AtomicOrder) [:0]const u8 {
return switch (order) {
// Note: unordered is actually even less atomic than relaxed

View File

@ -96,10 +96,9 @@ fn doNothingWithFirstArg(args: anytype) void {
test "simple variadic function" {
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
if (builtin.cpu.arch == .aarch64 and builtin.os.tag != .macos and builtin.zig_backend == .stage2_llvm) {
if (builtin.cpu.arch == .aarch64 and builtin.os.tag != .macos) {
// https://github.com/ziglang/zig/issues/14096
return error.SkipZigTest;
}
@ -124,8 +123,10 @@ test "simple variadic function" {
}
};
try std.testing.expectEqual(@as(c_int, 0), S.simple(@as(c_int, 0)));
try std.testing.expectEqual(@as(c_int, 1024), S.simple(@as(c_int, 1024)));
if (builtin.zig_backend != .stage2_c) { // C doesn't support varargs without a preceding runtime arg.
try std.testing.expectEqual(@as(c_int, 0), S.simple(@as(c_int, 0)));
try std.testing.expectEqual(@as(c_int, 1024), S.simple(@as(c_int, 1024)));
}
try std.testing.expectEqual(@as(c_int, 0), S.add(0));
try std.testing.expectEqual(@as(c_int, 1), S.add(1, @as(c_int, 1)));
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" {
test "variadic functions" {
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
if (builtin.cpu.arch == .aarch64 and builtin.os.tag != .macos and builtin.zig_backend == .stage2_llvm) {
if (builtin.cpu.arch == .aarch64 and builtin.os.tag != .macos) {
// https://github.com/ziglang/zig/issues/14096
return error.SkipZigTest;
}
@ -178,10 +178,9 @@ test "variadic functions" {
test "copy VaList" {
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
if (builtin.cpu.arch == .aarch64 and builtin.os.tag != .macos and builtin.zig_backend == .stage2_llvm) {
if (builtin.cpu.arch == .aarch64 and builtin.os.tag != .macos) {
// https://github.com/ziglang/zig/issues/14096
return error.SkipZigTest;
}