* Module: improve doc comments * C backend: improve const-correctness * C backend: introduce renderTypeAndName * C backend: put `static` on functions when appropriate * C backend: fix not handling errors in genBinOp * C backend: handle more IR instructions - alloc, store, boolean comparisons, ret_ptr * C backend: call instruction properly stores its result * test harness: ensure execution tests have empty stderr
343 lines
10 KiB
Zig
343 lines
10 KiB
Zig
const std = @import("std");
|
|
const TestContext = @import("../../src/test.zig").TestContext;
|
|
|
|
// These tests should work with all platforms, but we're using linux_x64 for
|
|
// now for consistency. Will be expanded eventually.
|
|
const linux_x64 = std.zig.CrossTarget{
|
|
.cpu_arch = .x86_64,
|
|
.os_tag = .linux,
|
|
};
|
|
|
|
pub fn addCases(ctx: *TestContext) !void {
|
|
{
|
|
var case = ctx.exeFromCompiledC("hello world with updates", .{});
|
|
|
|
// Regular old hello world
|
|
case.addCompareOutput(
|
|
\\extern fn puts(s: [*:0]const u8) c_int;
|
|
\\export fn main() c_int {
|
|
\\ _ = puts("hello world!");
|
|
\\ return 0;
|
|
\\}
|
|
, "hello world!" ++ std.cstr.line_sep);
|
|
|
|
// Now change the message only
|
|
// TODO fix C backend not supporting updates
|
|
// https://github.com/ziglang/zig/issues/7589
|
|
//case.addCompareOutput(
|
|
// \\extern fn puts(s: [*:0]const u8) c_int;
|
|
// \\export fn main() c_int {
|
|
// \\ _ = puts("yo");
|
|
// \\ return 0;
|
|
// \\}
|
|
//, "yo" ++ std.cstr.line_sep);
|
|
}
|
|
|
|
{
|
|
var case = ctx.exeFromCompiledC("alloc and retptr", .{});
|
|
|
|
case.addCompareOutput(
|
|
\\fn add(a: i32, b: i32) i32 {
|
|
\\ return a + b;
|
|
\\}
|
|
\\
|
|
\\fn addIndirect(a: i32, b: i32) i32 {
|
|
\\ return add(a, b);
|
|
\\}
|
|
\\
|
|
\\export fn main() c_int {
|
|
\\ return addIndirect(1, 2) - 3;
|
|
\\}
|
|
, "");
|
|
}
|
|
|
|
ctx.c("empty start function", linux_x64,
|
|
\\export fn _start() noreturn {
|
|
\\ unreachable;
|
|
\\}
|
|
,
|
|
\\zig_noreturn void _start(void) {
|
|
\\ zig_breakpoint();
|
|
\\ zig_unreachable();
|
|
\\}
|
|
\\
|
|
);
|
|
ctx.h("simple header", linux_x64,
|
|
\\export fn start() void{}
|
|
,
|
|
\\void start(void);
|
|
\\
|
|
);
|
|
ctx.c("less empty start function", linux_x64,
|
|
\\fn main() noreturn {
|
|
\\ unreachable;
|
|
\\}
|
|
\\
|
|
\\export fn _start() noreturn {
|
|
\\ main();
|
|
\\}
|
|
,
|
|
\\static zig_noreturn void main(void);
|
|
\\
|
|
\\zig_noreturn void _start(void) {
|
|
\\ main();
|
|
\\}
|
|
\\
|
|
\\static zig_noreturn void main(void) {
|
|
\\ zig_breakpoint();
|
|
\\ zig_unreachable();
|
|
\\}
|
|
\\
|
|
);
|
|
// TODO: implement return values
|
|
// TODO: figure out a way to prevent asm constants from being generated
|
|
ctx.c("inline asm", linux_x64,
|
|
\\fn exitGood() noreturn {
|
|
\\ asm volatile ("syscall"
|
|
\\ :
|
|
\\ : [number] "{rax}" (231),
|
|
\\ [arg1] "{rdi}" (0)
|
|
\\ );
|
|
\\ unreachable;
|
|
\\}
|
|
\\
|
|
\\export fn _start() noreturn {
|
|
\\ exitGood();
|
|
\\}
|
|
,
|
|
\\static zig_noreturn void exitGood(void);
|
|
\\
|
|
\\static uint8_t exitGood__anon_0[6] = "{rax}";
|
|
\\static uint8_t exitGood__anon_1[6] = "{rdi}";
|
|
\\static uint8_t exitGood__anon_2[8] = "syscall";
|
|
\\
|
|
\\zig_noreturn void _start(void) {
|
|
\\ exitGood();
|
|
\\}
|
|
\\
|
|
\\static zig_noreturn void exitGood(void) {
|
|
\\ register uintptr_t rax_constant __asm__("rax") = 231;
|
|
\\ register uintptr_t rdi_constant __asm__("rdi") = 0;
|
|
\\ __asm volatile ("syscall" :: ""(rax_constant), ""(rdi_constant));
|
|
\\ zig_breakpoint();
|
|
\\ zig_unreachable();
|
|
\\}
|
|
\\
|
|
);
|
|
ctx.c("exit with parameter", linux_x64,
|
|
\\export fn _start() noreturn {
|
|
\\ exit(0);
|
|
\\}
|
|
\\
|
|
\\fn exit(code: usize) noreturn {
|
|
\\ asm volatile ("syscall"
|
|
\\ :
|
|
\\ : [number] "{rax}" (231),
|
|
\\ [arg1] "{rdi}" (code)
|
|
\\ );
|
|
\\ unreachable;
|
|
\\}
|
|
\\
|
|
,
|
|
\\static zig_noreturn void exit(uintptr_t arg0);
|
|
\\
|
|
\\static uint8_t exit__anon_0[6] = "{rax}";
|
|
\\static uint8_t exit__anon_1[6] = "{rdi}";
|
|
\\static uint8_t exit__anon_2[8] = "syscall";
|
|
\\
|
|
\\zig_noreturn void _start(void) {
|
|
\\ exit(0);
|
|
\\}
|
|
\\
|
|
\\static zig_noreturn void exit(uintptr_t arg0) {
|
|
\\ register uintptr_t rax_constant __asm__("rax") = 231;
|
|
\\ register uintptr_t rdi_constant __asm__("rdi") = arg0;
|
|
\\ __asm volatile ("syscall" :: ""(rax_constant), ""(rdi_constant));
|
|
\\ zig_breakpoint();
|
|
\\ zig_unreachable();
|
|
\\}
|
|
\\
|
|
);
|
|
ctx.c("exit with u8 parameter", linux_x64,
|
|
\\export fn _start() noreturn {
|
|
\\ exit(0);
|
|
\\}
|
|
\\
|
|
\\fn exit(code: u8) noreturn {
|
|
\\ asm volatile ("syscall"
|
|
\\ :
|
|
\\ : [number] "{rax}" (231),
|
|
\\ [arg1] "{rdi}" (code)
|
|
\\ );
|
|
\\ unreachable;
|
|
\\}
|
|
\\
|
|
,
|
|
\\static zig_noreturn void exit(uint8_t arg0);
|
|
\\
|
|
\\static uint8_t exit__anon_0[6] = "{rax}";
|
|
\\static uint8_t exit__anon_1[6] = "{rdi}";
|
|
\\static uint8_t exit__anon_2[8] = "syscall";
|
|
\\
|
|
\\zig_noreturn void _start(void) {
|
|
\\ exit(0);
|
|
\\}
|
|
\\
|
|
\\static zig_noreturn void exit(uint8_t arg0) {
|
|
\\ uintptr_t const __temp_0 = (uintptr_t)arg0;
|
|
\\ register uintptr_t rax_constant __asm__("rax") = 231;
|
|
\\ register uintptr_t rdi_constant __asm__("rdi") = __temp_0;
|
|
\\ __asm volatile ("syscall" :: ""(rax_constant), ""(rdi_constant));
|
|
\\ zig_breakpoint();
|
|
\\ zig_unreachable();
|
|
\\}
|
|
\\
|
|
);
|
|
ctx.c("exit with u8 arithmetic", linux_x64,
|
|
\\export fn _start() noreturn {
|
|
\\ exitMath(1);
|
|
\\}
|
|
\\
|
|
\\fn exitMath(a: u8) noreturn {
|
|
\\ exit(0 + a - a);
|
|
\\}
|
|
\\
|
|
\\fn exit(code: u8) noreturn {
|
|
\\ asm volatile ("syscall"
|
|
\\ :
|
|
\\ : [number] "{rax}" (231),
|
|
\\ [arg1] "{rdi}" (code)
|
|
\\ );
|
|
\\ unreachable;
|
|
\\}
|
|
\\
|
|
,
|
|
\\static zig_noreturn void exitMath(uint8_t arg0);
|
|
\\static zig_noreturn void exit(uint8_t arg0);
|
|
\\
|
|
\\static uint8_t exit__anon_0[6] = "{rax}";
|
|
\\static uint8_t exit__anon_1[6] = "{rdi}";
|
|
\\static uint8_t exit__anon_2[8] = "syscall";
|
|
\\
|
|
\\zig_noreturn void _start(void) {
|
|
\\ exitMath(1);
|
|
\\}
|
|
\\
|
|
\\static zig_noreturn void exitMath(uint8_t arg0) {
|
|
\\ uint8_t const __temp_0 = 0 + arg0;
|
|
\\ uint8_t const __temp_1 = __temp_0 - arg0;
|
|
\\ exit(__temp_1);
|
|
\\}
|
|
\\
|
|
\\static zig_noreturn void exit(uint8_t arg0) {
|
|
\\ uintptr_t const __temp_0 = (uintptr_t)arg0;
|
|
\\ register uintptr_t rax_constant __asm__("rax") = 231;
|
|
\\ register uintptr_t rdi_constant __asm__("rdi") = __temp_0;
|
|
\\ __asm volatile ("syscall" :: ""(rax_constant), ""(rdi_constant));
|
|
\\ zig_breakpoint();
|
|
\\ zig_unreachable();
|
|
\\}
|
|
\\
|
|
);
|
|
ctx.c("exit with u8 arithmetic inverted", linux_x64,
|
|
\\export fn _start() noreturn {
|
|
\\ exitMath(1);
|
|
\\}
|
|
\\
|
|
\\fn exitMath(a: u8) noreturn {
|
|
\\ exit(a + 0 - a);
|
|
\\}
|
|
\\
|
|
\\fn exit(code: u8) noreturn {
|
|
\\ asm volatile ("syscall"
|
|
\\ :
|
|
\\ : [number] "{rax}" (231),
|
|
\\ [arg1] "{rdi}" (code)
|
|
\\ );
|
|
\\ unreachable;
|
|
\\}
|
|
\\
|
|
,
|
|
\\static zig_noreturn void exitMath(uint8_t arg0);
|
|
\\static zig_noreturn void exit(uint8_t arg0);
|
|
\\
|
|
\\static uint8_t exit__anon_0[6] = "{rax}";
|
|
\\static uint8_t exit__anon_1[6] = "{rdi}";
|
|
\\static uint8_t exit__anon_2[8] = "syscall";
|
|
\\
|
|
\\zig_noreturn void _start(void) {
|
|
\\ exitMath(1);
|
|
\\}
|
|
\\
|
|
\\static zig_noreturn void exitMath(uint8_t arg0) {
|
|
\\ uint8_t const __temp_0 = arg0 + 0;
|
|
\\ uint8_t const __temp_1 = __temp_0 - arg0;
|
|
\\ exit(__temp_1);
|
|
\\}
|
|
\\
|
|
\\static zig_noreturn void exit(uint8_t arg0) {
|
|
\\ uintptr_t const __temp_0 = (uintptr_t)arg0;
|
|
\\ register uintptr_t rax_constant __asm__("rax") = 231;
|
|
\\ register uintptr_t rdi_constant __asm__("rdi") = __temp_0;
|
|
\\ __asm volatile ("syscall" :: ""(rax_constant), ""(rdi_constant));
|
|
\\ zig_breakpoint();
|
|
\\ zig_unreachable();
|
|
\\}
|
|
\\
|
|
);
|
|
ctx.h("header with single param function", linux_x64,
|
|
\\export fn start(a: u8) void{}
|
|
,
|
|
\\void start(uint8_t arg0);
|
|
\\
|
|
);
|
|
ctx.h("header with multiple param function", linux_x64,
|
|
\\export fn start(a: u8, b: u8, c: u8) void{}
|
|
,
|
|
\\void start(uint8_t arg0, uint8_t arg1, uint8_t arg2);
|
|
\\
|
|
);
|
|
ctx.h("header with u32 param function", linux_x64,
|
|
\\export fn start(a: u32) void{}
|
|
,
|
|
\\void start(uint32_t arg0);
|
|
\\
|
|
);
|
|
ctx.h("header with usize param function", linux_x64,
|
|
\\export fn start(a: usize) void{}
|
|
,
|
|
\\void start(uintptr_t arg0);
|
|
\\
|
|
);
|
|
ctx.h("header with bool param function", linux_x64,
|
|
\\export fn start(a: bool) void{}
|
|
,
|
|
\\void start(bool arg0);
|
|
\\
|
|
);
|
|
ctx.h("header with noreturn function", linux_x64,
|
|
\\export fn start() noreturn {
|
|
\\ unreachable;
|
|
\\}
|
|
,
|
|
\\zig_noreturn void start(void);
|
|
\\
|
|
);
|
|
ctx.h("header with multiple functions", linux_x64,
|
|
\\export fn a() void{}
|
|
\\export fn b() void{}
|
|
\\export fn c() void{}
|
|
,
|
|
\\void a(void);
|
|
\\void b(void);
|
|
\\void c(void);
|
|
\\
|
|
);
|
|
ctx.h("header with multiple includes", linux_x64,
|
|
\\export fn start(a: u32, b: usize) void{}
|
|
,
|
|
\\void start(uint32_t arg0, uintptr_t arg1);
|
|
\\
|
|
);
|
|
}
|