489 lines
16 KiB
Zig
489 lines
16 KiB
Zig
const std = @import("std");
|
|
const TestContext = @import("../../src-self-hosted/test.zig").TestContext;
|
|
// self-hosted does not yet support PE executable files / COFF object files
|
|
// or mach-o files. So we do the ZIR transform test cases cross compiling for
|
|
// x86_64-linux.
|
|
const linux_x64 = std.zig.CrossTarget{
|
|
.cpu_arch = .x86_64,
|
|
.os_tag = .linux,
|
|
};
|
|
|
|
pub fn addCases(ctx: *TestContext) void {
|
|
ctx.addZIRTransform("referencing decls which appear later in the file", linux_x64,
|
|
\\@void = primitive(void)
|
|
\\@fnty = fntype([], @void, cc=C)
|
|
\\
|
|
\\@9 = str("entry")
|
|
\\@10 = ref(@9)
|
|
\\@11 = export(@10, @entry)
|
|
\\
|
|
\\@entry = fn(@fnty, {
|
|
\\ %11 = return()
|
|
\\})
|
|
,
|
|
\\@void = primitive(void)
|
|
\\@fnty = fntype([], @void, cc=C)
|
|
\\@9 = str("entry")
|
|
\\@10 = ref(@9)
|
|
\\@unnamed$6 = str("entry")
|
|
\\@unnamed$7 = ref(@unnamed$6)
|
|
\\@unnamed$8 = export(@unnamed$7, @entry)
|
|
\\@unnamed$10 = fntype([], @void, cc=C)
|
|
\\@entry = fn(@unnamed$10, {
|
|
\\ %0 = return()
|
|
\\})
|
|
\\
|
|
);
|
|
ctx.addZIRTransform("elemptr, add, cmp, condbr, return, breakpoint", linux_x64,
|
|
\\@void = primitive(void)
|
|
\\@usize = primitive(usize)
|
|
\\@fnty = fntype([], @void, cc=C)
|
|
\\@0 = int(0)
|
|
\\@1 = int(1)
|
|
\\@2 = int(2)
|
|
\\@3 = int(3)
|
|
\\
|
|
\\@entry = fn(@fnty, {
|
|
\\ %a = str("\x32\x08\x01\x0a")
|
|
\\ %aref = ref(%a)
|
|
\\ %eptr0 = elemptr(%aref, @0)
|
|
\\ %eptr1 = elemptr(%aref, @1)
|
|
\\ %eptr2 = elemptr(%aref, @2)
|
|
\\ %eptr3 = elemptr(%aref, @3)
|
|
\\ %v0 = deref(%eptr0)
|
|
\\ %v1 = deref(%eptr1)
|
|
\\ %v2 = deref(%eptr2)
|
|
\\ %v3 = deref(%eptr3)
|
|
\\ %x0 = add(%v0, %v1)
|
|
\\ %x1 = add(%v2, %v3)
|
|
\\ %result = add(%x0, %x1)
|
|
\\
|
|
\\ %expected = int(69)
|
|
\\ %ok = cmp(%result, eq, %expected)
|
|
\\ %10 = condbr(%ok, {
|
|
\\ %11 = return()
|
|
\\ }, {
|
|
\\ %12 = breakpoint()
|
|
\\ })
|
|
\\})
|
|
\\
|
|
\\@9 = str("entry")
|
|
\\@10 = ref(@9)
|
|
\\@11 = export(@10, @entry)
|
|
,
|
|
\\@void = primitive(void)
|
|
\\@fnty = fntype([], @void, cc=C)
|
|
\\@0 = int(0)
|
|
\\@1 = int(1)
|
|
\\@2 = int(2)
|
|
\\@3 = int(3)
|
|
\\@unnamed$7 = fntype([], @void, cc=C)
|
|
\\@entry = fn(@unnamed$7, {
|
|
\\ %0 = return()
|
|
\\})
|
|
\\@a = str("2\x08\x01\n")
|
|
\\@9 = str("entry")
|
|
\\@10 = ref(@9)
|
|
\\@unnamed$14 = str("entry")
|
|
\\@unnamed$15 = ref(@unnamed$14)
|
|
\\@unnamed$16 = export(@unnamed$15, @entry)
|
|
\\
|
|
);
|
|
|
|
{
|
|
var case = ctx.addZIRMulti("reference cycle with compile error in the cycle", linux_x64);
|
|
case.addTransform(
|
|
\\@void = primitive(void)
|
|
\\@fnty = fntype([], @void, cc=C)
|
|
\\
|
|
\\@9 = str("entry")
|
|
\\@10 = ref(@9)
|
|
\\@11 = export(@10, @entry)
|
|
\\
|
|
\\@entry = fn(@fnty, {
|
|
\\ %0 = call(@a, [])
|
|
\\ %1 = return()
|
|
\\})
|
|
\\
|
|
\\@a = fn(@fnty, {
|
|
\\ %0 = call(@b, [])
|
|
\\ %1 = return()
|
|
\\})
|
|
\\
|
|
\\@b = fn(@fnty, {
|
|
\\ %0 = call(@a, [])
|
|
\\ %1 = return()
|
|
\\})
|
|
,
|
|
\\@void = primitive(void)
|
|
\\@fnty = fntype([], @void, cc=C)
|
|
\\@9 = str("entry")
|
|
\\@10 = ref(@9)
|
|
\\@unnamed$6 = str("entry")
|
|
\\@unnamed$7 = ref(@unnamed$6)
|
|
\\@unnamed$8 = export(@unnamed$7, @entry)
|
|
\\@unnamed$12 = fntype([], @void, cc=C)
|
|
\\@entry = fn(@unnamed$12, {
|
|
\\ %0 = call(@a, [], modifier=auto)
|
|
\\ %1 = return()
|
|
\\})
|
|
\\@unnamed$17 = fntype([], @void, cc=C)
|
|
\\@a = fn(@unnamed$17, {
|
|
\\ %0 = call(@b, [], modifier=auto)
|
|
\\ %1 = return()
|
|
\\})
|
|
\\@unnamed$22 = fntype([], @void, cc=C)
|
|
\\@b = fn(@unnamed$22, {
|
|
\\ %0 = call(@a, [], modifier=auto)
|
|
\\ %1 = return()
|
|
\\})
|
|
\\
|
|
);
|
|
// Now we introduce a compile error
|
|
case.addError(
|
|
\\@void = primitive(void)
|
|
\\@fnty = fntype([], @void, cc=C)
|
|
\\
|
|
\\@9 = str("entry")
|
|
\\@10 = ref(@9)
|
|
\\@11 = export(@10, @entry)
|
|
\\
|
|
\\@entry = fn(@fnty, {
|
|
\\ %0 = call(@a, [])
|
|
\\ %1 = return()
|
|
\\})
|
|
\\
|
|
\\@a = fn(@fnty, {
|
|
\\ %0 = call(@b, [])
|
|
\\ %1 = return()
|
|
\\})
|
|
\\
|
|
\\@b = fn(@fnty, {
|
|
\\ %9 = compileerror("message")
|
|
\\ %0 = call(@a, [])
|
|
\\ %1 = return()
|
|
\\})
|
|
,
|
|
&[_][]const u8{
|
|
":19:21: error: message",
|
|
},
|
|
);
|
|
// Now we remove the call to `a`. `a` and `b` form a cycle, but no entry points are
|
|
// referencing either of them. This tests that the cycle is detected, and the error
|
|
// goes away.
|
|
case.addTransform(
|
|
\\@void = primitive(void)
|
|
\\@fnty = fntype([], @void, cc=C)
|
|
\\
|
|
\\@9 = str("entry")
|
|
\\@10 = ref(@9)
|
|
\\@11 = export(@10, @entry)
|
|
\\
|
|
\\@entry = fn(@fnty, {
|
|
\\ %1 = return()
|
|
\\})
|
|
\\
|
|
\\@a = fn(@fnty, {
|
|
\\ %0 = call(@b, [])
|
|
\\ %1 = return()
|
|
\\})
|
|
\\
|
|
\\@b = fn(@fnty, {
|
|
\\ %9 = compileerror("message")
|
|
\\ %0 = call(@a, [])
|
|
\\ %1 = return()
|
|
\\})
|
|
,
|
|
\\@void = primitive(void)
|
|
\\@fnty = fntype([], @void, cc=C)
|
|
\\@9 = str("entry")
|
|
\\@10 = ref(@9)
|
|
\\@unnamed$6 = str("entry")
|
|
\\@unnamed$7 = ref(@unnamed$6)
|
|
\\@unnamed$8 = export(@unnamed$7, @entry)
|
|
\\@unnamed$10 = fntype([], @void, cc=C)
|
|
\\@entry = fn(@unnamed$10, {
|
|
\\ %0 = return()
|
|
\\})
|
|
\\
|
|
);
|
|
}
|
|
|
|
if (std.Target.current.os.tag != .linux or
|
|
std.Target.current.cpu.arch != .x86_64)
|
|
{
|
|
// TODO implement self-hosted PE (.exe file) linking
|
|
// TODO implement more ZIR so we don't depend on x86_64-linux
|
|
return;
|
|
}
|
|
|
|
ctx.addZIRCompareOutput(
|
|
"hello world ZIR, update msg",
|
|
&[_][]const u8{
|
|
\\@noreturn = primitive(noreturn)
|
|
\\@void = primitive(void)
|
|
\\@usize = primitive(usize)
|
|
\\@0 = int(0)
|
|
\\@1 = int(1)
|
|
\\@2 = int(2)
|
|
\\@3 = int(3)
|
|
\\
|
|
\\@syscall_array = str("syscall")
|
|
\\@sysoutreg_array = str("={rax}")
|
|
\\@rax_array = str("{rax}")
|
|
\\@rdi_array = str("{rdi}")
|
|
\\@rcx_array = str("rcx")
|
|
\\@r11_array = str("r11")
|
|
\\@rdx_array = str("{rdx}")
|
|
\\@rsi_array = str("{rsi}")
|
|
\\@memory_array = str("memory")
|
|
\\@len_array = str("len")
|
|
\\
|
|
\\@msg = str("Hello, world!\n")
|
|
\\
|
|
\\@start_fnty = fntype([], @noreturn, cc=Naked)
|
|
\\@start = fn(@start_fnty, {
|
|
\\ %SYS_exit_group = int(231)
|
|
\\ %exit_code = as(@usize, @0)
|
|
\\
|
|
\\ %syscall = ref(@syscall_array)
|
|
\\ %sysoutreg = ref(@sysoutreg_array)
|
|
\\ %rax = ref(@rax_array)
|
|
\\ %rdi = ref(@rdi_array)
|
|
\\ %rcx = ref(@rcx_array)
|
|
\\ %rdx = ref(@rdx_array)
|
|
\\ %rsi = ref(@rsi_array)
|
|
\\ %r11 = ref(@r11_array)
|
|
\\ %memory = ref(@memory_array)
|
|
\\
|
|
\\ %SYS_write = as(@usize, @1)
|
|
\\ %STDOUT_FILENO = as(@usize, @1)
|
|
\\
|
|
\\ %msg_ptr = ref(@msg)
|
|
\\ %msg_addr = ptrtoint(%msg_ptr)
|
|
\\
|
|
\\ %len_name = ref(@len_array)
|
|
\\ %msg_len_ptr = fieldptr(%msg_ptr, %len_name)
|
|
\\ %msg_len = deref(%msg_len_ptr)
|
|
\\ %rc_write = asm(%syscall, @usize,
|
|
\\ volatile=1,
|
|
\\ output=%sysoutreg,
|
|
\\ inputs=[%rax, %rdi, %rsi, %rdx],
|
|
\\ clobbers=[%rcx, %r11, %memory],
|
|
\\ args=[%SYS_write, %STDOUT_FILENO, %msg_addr, %msg_len])
|
|
\\
|
|
\\ %rc_exit = asm(%syscall, @usize,
|
|
\\ volatile=1,
|
|
\\ output=%sysoutreg,
|
|
\\ inputs=[%rax, %rdi],
|
|
\\ clobbers=[%rcx, %r11, %memory],
|
|
\\ args=[%SYS_exit_group, %exit_code])
|
|
\\
|
|
\\ %99 = unreachable()
|
|
\\});
|
|
\\
|
|
\\@9 = str("_start")
|
|
\\@10 = ref(@9)
|
|
\\@11 = export(@10, @start)
|
|
,
|
|
\\@noreturn = primitive(noreturn)
|
|
\\@void = primitive(void)
|
|
\\@usize = primitive(usize)
|
|
\\@0 = int(0)
|
|
\\@1 = int(1)
|
|
\\@2 = int(2)
|
|
\\@3 = int(3)
|
|
\\
|
|
\\@syscall_array = str("syscall")
|
|
\\@sysoutreg_array = str("={rax}")
|
|
\\@rax_array = str("{rax}")
|
|
\\@rdi_array = str("{rdi}")
|
|
\\@rcx_array = str("rcx")
|
|
\\@r11_array = str("r11")
|
|
\\@rdx_array = str("{rdx}")
|
|
\\@rsi_array = str("{rsi}")
|
|
\\@memory_array = str("memory")
|
|
\\@len_array = str("len")
|
|
\\
|
|
\\@msg = str("Hello, world!\n")
|
|
\\@msg2 = str("HELL WORLD\n")
|
|
\\
|
|
\\@start_fnty = fntype([], @noreturn, cc=Naked)
|
|
\\@start = fn(@start_fnty, {
|
|
\\ %SYS_exit_group = int(231)
|
|
\\ %exit_code = as(@usize, @0)
|
|
\\
|
|
\\ %syscall = ref(@syscall_array)
|
|
\\ %sysoutreg = ref(@sysoutreg_array)
|
|
\\ %rax = ref(@rax_array)
|
|
\\ %rdi = ref(@rdi_array)
|
|
\\ %rcx = ref(@rcx_array)
|
|
\\ %rdx = ref(@rdx_array)
|
|
\\ %rsi = ref(@rsi_array)
|
|
\\ %r11 = ref(@r11_array)
|
|
\\ %memory = ref(@memory_array)
|
|
\\
|
|
\\ %SYS_write = as(@usize, @1)
|
|
\\ %STDOUT_FILENO = as(@usize, @1)
|
|
\\
|
|
\\ %msg_ptr = ref(@msg2)
|
|
\\ %msg_addr = ptrtoint(%msg_ptr)
|
|
\\
|
|
\\ %len_name = ref(@len_array)
|
|
\\ %msg_len_ptr = fieldptr(%msg_ptr, %len_name)
|
|
\\ %msg_len = deref(%msg_len_ptr)
|
|
\\ %rc_write = asm(%syscall, @usize,
|
|
\\ volatile=1,
|
|
\\ output=%sysoutreg,
|
|
\\ inputs=[%rax, %rdi, %rsi, %rdx],
|
|
\\ clobbers=[%rcx, %r11, %memory],
|
|
\\ args=[%SYS_write, %STDOUT_FILENO, %msg_addr, %msg_len])
|
|
\\
|
|
\\ %rc_exit = asm(%syscall, @usize,
|
|
\\ volatile=1,
|
|
\\ output=%sysoutreg,
|
|
\\ inputs=[%rax, %rdi],
|
|
\\ clobbers=[%rcx, %r11, %memory],
|
|
\\ args=[%SYS_exit_group, %exit_code])
|
|
\\
|
|
\\ %99 = unreachable()
|
|
\\});
|
|
\\
|
|
\\@9 = str("_start")
|
|
\\@10 = ref(@9)
|
|
\\@11 = export(@10, @start)
|
|
,
|
|
\\@noreturn = primitive(noreturn)
|
|
\\@void = primitive(void)
|
|
\\@usize = primitive(usize)
|
|
\\@0 = int(0)
|
|
\\@1 = int(1)
|
|
\\@2 = int(2)
|
|
\\@3 = int(3)
|
|
\\
|
|
\\@syscall_array = str("syscall")
|
|
\\@sysoutreg_array = str("={rax}")
|
|
\\@rax_array = str("{rax}")
|
|
\\@rdi_array = str("{rdi}")
|
|
\\@rcx_array = str("rcx")
|
|
\\@r11_array = str("r11")
|
|
\\@rdx_array = str("{rdx}")
|
|
\\@rsi_array = str("{rsi}")
|
|
\\@memory_array = str("memory")
|
|
\\@len_array = str("len")
|
|
\\
|
|
\\@msg = str("Hello, world!\n")
|
|
\\@msg2 = str("Editing the same msg2 decl but this time with a much longer message which will\ncause the data to need to be relocated in virtual address space.\n")
|
|
\\
|
|
\\@start_fnty = fntype([], @noreturn, cc=Naked)
|
|
\\@start = fn(@start_fnty, {
|
|
\\ %SYS_exit_group = int(231)
|
|
\\ %exit_code = as(@usize, @0)
|
|
\\
|
|
\\ %syscall = ref(@syscall_array)
|
|
\\ %sysoutreg = ref(@sysoutreg_array)
|
|
\\ %rax = ref(@rax_array)
|
|
\\ %rdi = ref(@rdi_array)
|
|
\\ %rcx = ref(@rcx_array)
|
|
\\ %rdx = ref(@rdx_array)
|
|
\\ %rsi = ref(@rsi_array)
|
|
\\ %r11 = ref(@r11_array)
|
|
\\ %memory = ref(@memory_array)
|
|
\\
|
|
\\ %SYS_write = as(@usize, @1)
|
|
\\ %STDOUT_FILENO = as(@usize, @1)
|
|
\\
|
|
\\ %msg_ptr = ref(@msg2)
|
|
\\ %msg_addr = ptrtoint(%msg_ptr)
|
|
\\
|
|
\\ %len_name = ref(@len_array)
|
|
\\ %msg_len_ptr = fieldptr(%msg_ptr, %len_name)
|
|
\\ %msg_len = deref(%msg_len_ptr)
|
|
\\ %rc_write = asm(%syscall, @usize,
|
|
\\ volatile=1,
|
|
\\ output=%sysoutreg,
|
|
\\ inputs=[%rax, %rdi, %rsi, %rdx],
|
|
\\ clobbers=[%rcx, %r11, %memory],
|
|
\\ args=[%SYS_write, %STDOUT_FILENO, %msg_addr, %msg_len])
|
|
\\
|
|
\\ %rc_exit = asm(%syscall, @usize,
|
|
\\ volatile=1,
|
|
\\ output=%sysoutreg,
|
|
\\ inputs=[%rax, %rdi],
|
|
\\ clobbers=[%rcx, %r11, %memory],
|
|
\\ args=[%SYS_exit_group, %exit_code])
|
|
\\
|
|
\\ %99 = unreachable()
|
|
\\});
|
|
\\
|
|
\\@9 = str("_start")
|
|
\\@10 = ref(@9)
|
|
\\@11 = export(@10, @start)
|
|
},
|
|
&[_][]const u8{
|
|
\\Hello, world!
|
|
\\
|
|
,
|
|
\\HELL WORLD
|
|
\\
|
|
,
|
|
\\Editing the same msg2 decl but this time with a much longer message which will
|
|
\\cause the data to need to be relocated in virtual address space.
|
|
\\
|
|
},
|
|
);
|
|
|
|
ctx.addZIRCompareOutput(
|
|
"function call with no args no return value",
|
|
&[_][]const u8{
|
|
\\@noreturn = primitive(noreturn)
|
|
\\@void = primitive(void)
|
|
\\@usize = primitive(usize)
|
|
\\@0 = int(0)
|
|
\\@1 = int(1)
|
|
\\@2 = int(2)
|
|
\\@3 = int(3)
|
|
\\
|
|
\\@syscall_array = str("syscall")
|
|
\\@sysoutreg_array = str("={rax}")
|
|
\\@rax_array = str("{rax}")
|
|
\\@rdi_array = str("{rdi}")
|
|
\\@rcx_array = str("rcx")
|
|
\\@r11_array = str("r11")
|
|
\\@memory_array = str("memory")
|
|
\\
|
|
\\@exit0_fnty = fntype([], @noreturn)
|
|
\\@exit0 = fn(@exit0_fnty, {
|
|
\\ %SYS_exit_group = int(231)
|
|
\\ %exit_code = as(@usize, @0)
|
|
\\
|
|
\\ %syscall = ref(@syscall_array)
|
|
\\ %sysoutreg = ref(@sysoutreg_array)
|
|
\\ %rax = ref(@rax_array)
|
|
\\ %rdi = ref(@rdi_array)
|
|
\\ %rcx = ref(@rcx_array)
|
|
\\ %r11 = ref(@r11_array)
|
|
\\ %memory = ref(@memory_array)
|
|
\\
|
|
\\ %rc = asm(%syscall, @usize,
|
|
\\ volatile=1,
|
|
\\ output=%sysoutreg,
|
|
\\ inputs=[%rax, %rdi],
|
|
\\ clobbers=[%rcx, %r11, %memory],
|
|
\\ args=[%SYS_exit_group, %exit_code])
|
|
\\
|
|
\\ %99 = unreachable()
|
|
\\});
|
|
\\
|
|
\\@start_fnty = fntype([], @noreturn, cc=Naked)
|
|
\\@start = fn(@start_fnty, {
|
|
\\ %0 = call(@exit0, [])
|
|
\\})
|
|
\\@9 = str("_start")
|
|
\\@10 = ref(@9)
|
|
\\@11 = export(@10, @start)
|
|
},
|
|
&[_][]const u8{""},
|
|
);
|
|
}
|