mirror of
https://github.com/ziglang/zig.git
synced 2026-02-13 04:48:20 +00:00
Merge pull request #5583 from ziglang/zig-ast-to-zir
self-hosted: hook up Zig AST to ZIR
This commit is contained in:
commit
d337469e44
13
build.zig
13
build.zig
@ -72,9 +72,22 @@ pub fn build(b: *Builder) !void {
|
||||
if (!only_install_lib_files) {
|
||||
exe.install();
|
||||
}
|
||||
const tracy = b.option([]const u8, "tracy", "Enable Tracy integration. Supply path to Tracy source");
|
||||
const link_libc = b.option(bool, "force-link-libc", "Force self-hosted compiler to link libc") orelse false;
|
||||
if (link_libc) exe.linkLibC();
|
||||
|
||||
exe.addBuildOption(bool, "enable_tracy", tracy != null);
|
||||
if (tracy) |tracy_path| {
|
||||
const client_cpp = fs.path.join(
|
||||
b.allocator,
|
||||
&[_][]const u8{ tracy_path, "TracyClient.cpp" },
|
||||
) catch unreachable;
|
||||
exe.addIncludeDir(tracy_path);
|
||||
exe.addCSourceFile(client_cpp, &[_][]const u8{ "-DTRACY_ENABLE=1", "-fno-sanitize=undefined" });
|
||||
exe.linkSystemLibraryName("c++");
|
||||
exe.linkLibC();
|
||||
}
|
||||
|
||||
b.installDirectory(InstallDirectoryOptions{
|
||||
.source_dir = "lib",
|
||||
.install_dir = .Lib,
|
||||
|
||||
@ -1905,10 +1905,11 @@ pub const LibExeObjStep = struct {
|
||||
builder.allocator,
|
||||
&[_][]const u8{ builder.cache_root, builder.fmt("{}_build_options.zig", .{self.name}) },
|
||||
);
|
||||
try fs.cwd().writeFile(build_options_file, self.build_options_contents.span());
|
||||
const path_from_root = builder.pathFromRoot(build_options_file);
|
||||
try fs.cwd().writeFile(path_from_root, self.build_options_contents.span());
|
||||
try zig_args.append("--pkg-begin");
|
||||
try zig_args.append("build_options");
|
||||
try zig_args.append(builder.pathFromRoot(build_options_file));
|
||||
try zig_args.append(path_from_root);
|
||||
try zig_args.append("--pkg-end");
|
||||
}
|
||||
|
||||
|
||||
@ -1,4 +1,6 @@
|
||||
const std = @import("std.zig");
|
||||
const tokenizer = @import("zig/tokenizer.zig");
|
||||
|
||||
pub const Token = tokenizer.Token;
|
||||
pub const Tokenizer = tokenizer.Tokenizer;
|
||||
pub const parse = @import("zig/parse.zig").parse;
|
||||
@ -9,6 +11,21 @@ pub const ast = @import("zig/ast.zig");
|
||||
pub const system = @import("zig/system.zig");
|
||||
pub const CrossTarget = @import("zig/cross_target.zig").CrossTarget;
|
||||
|
||||
pub const SrcHash = [16]u8;
|
||||
|
||||
/// If the source is small enough, it is used directly as the hash.
|
||||
/// If it is long, blake3 hash is computed.
|
||||
pub fn hashSrc(src: []const u8) SrcHash {
|
||||
var out: SrcHash = undefined;
|
||||
if (src.len <= SrcHash.len) {
|
||||
std.mem.copy(u8, &out, src);
|
||||
std.mem.set(u8, out[src.len..], 0);
|
||||
} else {
|
||||
std.crypto.Blake3.hash(src, &out);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
pub fn findLineColumn(source: []const u8, byte_offset: usize) struct { line: usize, column: usize } {
|
||||
var line: usize = 0;
|
||||
var column: usize = 0;
|
||||
@ -26,6 +43,27 @@ pub fn findLineColumn(source: []const u8, byte_offset: usize) struct { line: usi
|
||||
return .{ .line = line, .column = column };
|
||||
}
|
||||
|
||||
/// Returns the standard file system basename of a binary generated by the Zig compiler.
|
||||
pub fn binNameAlloc(
|
||||
allocator: *std.mem.Allocator,
|
||||
root_name: []const u8,
|
||||
target: std.Target,
|
||||
output_mode: std.builtin.OutputMode,
|
||||
link_mode: ?std.builtin.LinkMode,
|
||||
) error{OutOfMemory}![]u8 {
|
||||
switch (output_mode) {
|
||||
.Exe => return std.fmt.allocPrint(allocator, "{}{}", .{ root_name, target.exeFileExt() }),
|
||||
.Lib => {
|
||||
const suffix = switch (link_mode orelse .Static) {
|
||||
.Static => target.staticLibSuffix(),
|
||||
.Dynamic => target.dynamicLibSuffix(),
|
||||
};
|
||||
return std.fmt.allocPrint(allocator, "{}{}{}", .{ target.libPrefix(), root_name, suffix });
|
||||
},
|
||||
.Obj => return std.fmt.allocPrint(allocator, "{}{}", .{ root_name, target.oFileExt() }),
|
||||
}
|
||||
}
|
||||
|
||||
test "" {
|
||||
@import("std").meta.refAllDecls(@This());
|
||||
}
|
||||
|
||||
@ -2260,6 +2260,8 @@ pub const Node = struct {
|
||||
}
|
||||
};
|
||||
|
||||
/// TODO break this into separate Break, Continue, Return AST Nodes to save memory.
|
||||
/// Could be further broken into LabeledBreak, LabeledContinue, and ReturnVoid to save even more.
|
||||
pub const ControlFlowExpression = struct {
|
||||
base: Node = Node{ .id = .ControlFlowExpression },
|
||||
ltoken: TokenIndex,
|
||||
|
||||
@ -3222,7 +3222,7 @@ const Parser = struct {
|
||||
}
|
||||
|
||||
/// Op* Child
|
||||
fn parsePrefixOpExpr(p: *Parser, opParseFn: NodeParseFn, childParseFn: NodeParseFn) Error!?*Node {
|
||||
fn parsePrefixOpExpr(p: *Parser, comptime opParseFn: NodeParseFn, comptime childParseFn: NodeParseFn) Error!?*Node {
|
||||
if (try opParseFn(p)) |first_op| {
|
||||
var rightmost_op = first_op;
|
||||
while (true) {
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -21,3 +21,11 @@ pub const Managed = struct {
|
||||
self.* = undefined;
|
||||
}
|
||||
};
|
||||
|
||||
/// Assumes arena allocation. Does a recursive copy.
|
||||
pub fn copy(self: TypedValue, allocator: *Allocator) error{OutOfMemory}!TypedValue {
|
||||
return TypedValue{
|
||||
.ty = try self.ty.copy(allocator),
|
||||
.val = try self.val.copy(allocator),
|
||||
};
|
||||
}
|
||||
|
||||
@ -10,6 +10,7 @@ const Module = @import("Module.zig");
|
||||
const ErrorMsg = Module.ErrorMsg;
|
||||
const Target = std.Target;
|
||||
const Allocator = mem.Allocator;
|
||||
const trace = @import("tracy.zig").trace;
|
||||
|
||||
pub const Result = union(enum) {
|
||||
/// The `code` parameter passed to `generateSymbol` has the value appended.
|
||||
@ -29,6 +30,9 @@ pub fn generateSymbol(
|
||||
/// A Decl that this symbol depends on had a semantic analysis failure.
|
||||
AnalysisFail,
|
||||
}!Result {
|
||||
const tracy = trace(@src());
|
||||
defer tracy.end();
|
||||
|
||||
switch (typed_value.ty.zigTypeTag()) {
|
||||
.Fn => {
|
||||
const module_fn = typed_value.val.cast(Value.Payload.Function).?.func;
|
||||
@ -178,6 +182,7 @@ const Function = struct {
|
||||
.ptrtoint => return self.genPtrToInt(inst.cast(ir.Inst.PtrToInt).?),
|
||||
.bitcast => return self.genBitCast(inst.cast(ir.Inst.BitCast).?),
|
||||
.ret => return self.genRet(inst.cast(ir.Inst.Ret).?),
|
||||
.retvoid => return self.genRetVoid(inst.cast(ir.Inst.RetVoid).?),
|
||||
.cmp => return self.genCmp(inst.cast(ir.Inst.Cmp).?),
|
||||
.condbr => return self.genCondBr(inst.cast(ir.Inst.CondBr).?),
|
||||
.isnull => return self.genIsNull(inst.cast(ir.Inst.IsNull).?),
|
||||
@ -213,7 +218,7 @@ const Function = struct {
|
||||
try self.code.resize(self.code.items.len + 7);
|
||||
self.code.items[self.code.items.len - 7 ..][0..3].* = [3]u8{ 0xff, 0x14, 0x25 };
|
||||
mem.writeIntLittle(u32, self.code.items[self.code.items.len - 4 ..][0..4], got_addr);
|
||||
const return_type = func.fn_type.fnReturnType();
|
||||
const return_type = func.owner_decl.typed_value.most_recent.typed_value.ty.fnReturnType();
|
||||
switch (return_type.zigTypeTag()) {
|
||||
.Void => return MCValue{ .none = {} },
|
||||
.NoReturn => return MCValue{ .unreach = {} },
|
||||
@ -230,16 +235,28 @@ const Function = struct {
|
||||
}
|
||||
}
|
||||
|
||||
fn genRet(self: *Function, inst: *ir.Inst.Ret) !MCValue {
|
||||
fn ret(self: *Function, src: usize, mcv: MCValue) !MCValue {
|
||||
if (mcv != .none) {
|
||||
return self.fail(src, "TODO implement return with non-void operand", .{});
|
||||
}
|
||||
switch (self.target.cpu.arch) {
|
||||
.i386, .x86_64 => {
|
||||
try self.code.append(0xc3); // ret
|
||||
},
|
||||
else => return self.fail(inst.base.src, "TODO implement return for {}", .{self.target.cpu.arch}),
|
||||
else => return self.fail(src, "TODO implement return for {}", .{self.target.cpu.arch}),
|
||||
}
|
||||
return .unreach;
|
||||
}
|
||||
|
||||
fn genRet(self: *Function, inst: *ir.Inst.Ret) !MCValue {
|
||||
const operand = try self.resolveInst(inst.args.operand);
|
||||
return self.ret(inst.base.src, operand);
|
||||
}
|
||||
|
||||
fn genRetVoid(self: *Function, inst: *ir.Inst.RetVoid) !MCValue {
|
||||
return self.ret(inst.base.src, .none);
|
||||
}
|
||||
|
||||
fn genCmp(self: *Function, inst: *ir.Inst.Cmp) !MCValue {
|
||||
switch (self.target.cpu.arch) {
|
||||
else => return self.fail(inst.base.src, "TODO implement cmp for {}", .{self.target.cpu.arch}),
|
||||
|
||||
@ -26,6 +26,7 @@ pub const Inst = struct {
|
||||
isnull,
|
||||
ptrtoint,
|
||||
ret,
|
||||
retvoid,
|
||||
unreach,
|
||||
};
|
||||
|
||||
@ -146,6 +147,14 @@ pub const Inst = struct {
|
||||
pub const Ret = struct {
|
||||
pub const base_tag = Tag.ret;
|
||||
base: Inst,
|
||||
args: struct {
|
||||
operand: *Inst,
|
||||
},
|
||||
};
|
||||
|
||||
pub const RetVoid = struct {
|
||||
pub const base_tag = Tag.retvoid;
|
||||
base: Inst,
|
||||
args: void,
|
||||
};
|
||||
|
||||
|
||||
@ -369,7 +369,7 @@ pub const ElfFile = struct {
|
||||
const file_size = self.options.program_code_size_hint;
|
||||
const p_align = 0x1000;
|
||||
const off = self.findFreeSpace(file_size, p_align);
|
||||
//std.debug.warn("found PT_LOAD free space 0x{x} to 0x{x}\n", .{ off, off + file_size });
|
||||
//std.log.debug(.link, "found PT_LOAD free space 0x{x} to 0x{x}\n", .{ off, off + file_size });
|
||||
try self.program_headers.append(self.allocator, .{
|
||||
.p_type = elf.PT_LOAD,
|
||||
.p_offset = off,
|
||||
@ -390,7 +390,7 @@ pub const ElfFile = struct {
|
||||
// page align.
|
||||
const p_align = 0x1000;
|
||||
const off = self.findFreeSpace(file_size, p_align);
|
||||
//std.debug.warn("found PT_LOAD free space 0x{x} to 0x{x}\n", .{ off, off + file_size });
|
||||
//std.log.debug(.link, "found PT_LOAD free space 0x{x} to 0x{x}\n", .{ off, off + file_size });
|
||||
// TODO instead of hard coding the vaddr, make a function to find a vaddr to put things at.
|
||||
// we'll need to re-use that function anyway, in case the GOT grows and overlaps something
|
||||
// else in virtual memory.
|
||||
@ -412,7 +412,7 @@ pub const ElfFile = struct {
|
||||
assert(self.shstrtab.items.len == 0);
|
||||
try self.shstrtab.append(self.allocator, 0); // need a 0 at position 0
|
||||
const off = self.findFreeSpace(self.shstrtab.items.len, 1);
|
||||
//std.debug.warn("found shstrtab free space 0x{x} to 0x{x}\n", .{ off, off + self.shstrtab.items.len });
|
||||
//std.log.debug(.link, "found shstrtab free space 0x{x} to 0x{x}\n", .{ off, off + self.shstrtab.items.len });
|
||||
try self.sections.append(self.allocator, .{
|
||||
.sh_name = try self.makeString(".shstrtab"),
|
||||
.sh_type = elf.SHT_STRTAB,
|
||||
@ -470,7 +470,7 @@ pub const ElfFile = struct {
|
||||
const each_size: u64 = if (small_ptr) @sizeOf(elf.Elf32_Sym) else @sizeOf(elf.Elf64_Sym);
|
||||
const file_size = self.options.symbol_count_hint * each_size;
|
||||
const off = self.findFreeSpace(file_size, min_align);
|
||||
//std.debug.warn("found symtab free space 0x{x} to 0x{x}\n", .{ off, off + file_size });
|
||||
//std.log.debug(.link, "found symtab free space 0x{x} to 0x{x}\n", .{ off, off + file_size });
|
||||
|
||||
try self.sections.append(self.allocator, .{
|
||||
.sh_name = try self.makeString(".symtab"),
|
||||
@ -586,7 +586,7 @@ pub const ElfFile = struct {
|
||||
shstrtab_sect.sh_offset = self.findFreeSpace(needed_size, 1);
|
||||
}
|
||||
shstrtab_sect.sh_size = needed_size;
|
||||
//std.debug.warn("shstrtab start=0x{x} end=0x{x}\n", .{ shstrtab_sect.sh_offset, shstrtab_sect.sh_offset + needed_size });
|
||||
//std.log.debug(.link, "shstrtab start=0x{x} end=0x{x}\n", .{ shstrtab_sect.sh_offset, shstrtab_sect.sh_offset + needed_size });
|
||||
|
||||
try self.file.?.pwriteAll(self.shstrtab.items, shstrtab_sect.sh_offset);
|
||||
if (!self.shdr_table_dirty) {
|
||||
@ -632,7 +632,7 @@ pub const ElfFile = struct {
|
||||
|
||||
for (buf) |*shdr, i| {
|
||||
shdr.* = self.sections.items[i];
|
||||
//std.debug.warn("writing section {}\n", .{shdr.*});
|
||||
//std.log.debug(.link, "writing section {}\n", .{shdr.*});
|
||||
if (foreign_endian) {
|
||||
bswapAllFields(elf.Elf64_Shdr, shdr);
|
||||
}
|
||||
@ -956,10 +956,10 @@ pub const ElfFile = struct {
|
||||
try self.offset_table_free_list.ensureCapacity(self.allocator, self.local_symbols.items.len);
|
||||
|
||||
if (self.local_symbol_free_list.popOrNull()) |i| {
|
||||
//std.debug.warn("reusing symbol index {} for {}\n", .{i, decl.name});
|
||||
//std.log.debug(.link, "reusing symbol index {} for {}\n", .{i, decl.name});
|
||||
decl.link.local_sym_index = i;
|
||||
} else {
|
||||
//std.debug.warn("allocating symbol index {} for {}\n", .{self.local_symbols.items.len, decl.name});
|
||||
//std.log.debug(.link, "allocating symbol index {} for {}\n", .{self.local_symbols.items.len, decl.name});
|
||||
decl.link.local_sym_index = @intCast(u32, self.local_symbols.items.len);
|
||||
_ = self.local_symbols.addOneAssumeCapacity();
|
||||
}
|
||||
@ -1002,7 +1002,7 @@ pub const ElfFile = struct {
|
||||
defer code_buffer.deinit();
|
||||
|
||||
const typed_value = decl.typed_value.most_recent.typed_value;
|
||||
const code = switch (try codegen.generateSymbol(self, decl.src, typed_value, &code_buffer)) {
|
||||
const code = switch (try codegen.generateSymbol(self, decl.src(), typed_value, &code_buffer)) {
|
||||
.externally_managed => |x| x,
|
||||
.appended => code_buffer.items,
|
||||
.fail => |em| {
|
||||
@ -1027,11 +1027,11 @@ pub const ElfFile = struct {
|
||||
!mem.isAlignedGeneric(u64, local_sym.st_value, required_alignment);
|
||||
if (need_realloc) {
|
||||
const vaddr = try self.growTextBlock(&decl.link, code.len, required_alignment);
|
||||
//std.debug.warn("growing {} from 0x{x} to 0x{x}\n", .{ decl.name, local_sym.st_value, vaddr });
|
||||
//std.log.debug(.link, "growing {} from 0x{x} to 0x{x}\n", .{ decl.name, local_sym.st_value, vaddr });
|
||||
if (vaddr != local_sym.st_value) {
|
||||
local_sym.st_value = vaddr;
|
||||
|
||||
//std.debug.warn(" (writing new offset table entry)\n", .{});
|
||||
//std.log.debug(.link, " (writing new offset table entry)\n", .{});
|
||||
self.offset_table.items[decl.link.offset_table_index] = vaddr;
|
||||
try self.writeOffsetTableEntry(decl.link.offset_table_index);
|
||||
}
|
||||
@ -1049,7 +1049,7 @@ pub const ElfFile = struct {
|
||||
const decl_name = mem.spanZ(decl.name);
|
||||
const name_str_index = try self.makeString(decl_name);
|
||||
const vaddr = try self.allocateTextBlock(&decl.link, code.len, required_alignment);
|
||||
//std.debug.warn("allocated text block for {} at 0x{x}\n", .{ decl_name, vaddr });
|
||||
//std.log.debug(.link, "allocated text block for {} at 0x{x}\n", .{ decl_name, vaddr });
|
||||
errdefer self.freeTextBlock(&decl.link);
|
||||
|
||||
local_sym.* = .{
|
||||
@ -1307,7 +1307,6 @@ pub const ElfFile = struct {
|
||||
.p32 => @sizeOf(elf.Elf32_Sym),
|
||||
.p64 => @sizeOf(elf.Elf64_Sym),
|
||||
};
|
||||
//std.debug.warn("symtab start=0x{x} end=0x{x}\n", .{ syms_sect.sh_offset, syms_sect.sh_offset + needed_size });
|
||||
const foreign_endian = self.options.target.cpu.arch.endian() != std.Target.current.cpu.arch.endian();
|
||||
const global_syms_off = syms_sect.sh_offset + self.local_symbols.items.len * sym_size;
|
||||
switch (self.ptr_width) {
|
||||
|
||||
@ -38,6 +38,29 @@ const usage =
|
||||
\\
|
||||
;
|
||||
|
||||
pub fn log(
|
||||
comptime level: std.log.Level,
|
||||
comptime scope: @TypeOf(.EnumLiteral),
|
||||
comptime format: []const u8,
|
||||
args: var,
|
||||
) void {
|
||||
if (@enumToInt(level) > @enumToInt(std.log.level))
|
||||
return;
|
||||
|
||||
const scope_prefix = "(" ++ switch (scope) {
|
||||
// Uncomment to hide logs
|
||||
//.compiler,
|
||||
.link => return,
|
||||
|
||||
else => @tagName(scope),
|
||||
} ++ "): ";
|
||||
|
||||
const prefix = "[" ++ @tagName(level) ++ "] " ++ scope_prefix;
|
||||
|
||||
// Print the message to stderr, silently ignoring any errors
|
||||
std.debug.print(prefix ++ format, args);
|
||||
}
|
||||
|
||||
pub fn main() !void {
|
||||
// TODO general purpose allocator in the zig std lib
|
||||
const gpa = if (std.builtin.link_libc) std.heap.c_allocator else std.heap.page_allocator;
|
||||
@ -86,7 +109,7 @@ const usage_build_generic =
|
||||
\\ zig build-obj <options> [files]
|
||||
\\
|
||||
\\Supported file types:
|
||||
\\ (planned) .zig Zig source code
|
||||
\\ .zig Zig source code
|
||||
\\ .zir Zig Intermediate Representation code
|
||||
\\ (planned) .o ELF object file
|
||||
\\ (planned) .o MACH-O (macOS) object file
|
||||
@ -407,21 +430,7 @@ fn buildOutputType(
|
||||
std.debug.warn("-fno-emit-bin not supported yet", .{});
|
||||
process.exit(1);
|
||||
},
|
||||
.yes_default_path => switch (output_mode) {
|
||||
.Exe => try std.fmt.allocPrint(arena, "{}{}", .{ root_name, target_info.target.exeFileExt() }),
|
||||
.Lib => blk: {
|
||||
const suffix = switch (link_mode orelse .Static) {
|
||||
.Static => target_info.target.staticLibSuffix(),
|
||||
.Dynamic => target_info.target.dynamicLibSuffix(),
|
||||
};
|
||||
break :blk try std.fmt.allocPrint(arena, "{}{}{}", .{
|
||||
target_info.target.libPrefix(),
|
||||
root_name,
|
||||
suffix,
|
||||
});
|
||||
},
|
||||
.Obj => try std.fmt.allocPrint(arena, "{}{}", .{ root_name, target_info.target.oFileExt() }),
|
||||
},
|
||||
.yes_default_path => try std.zig.binNameAlloc(arena, root_name, target_info.target, output_mode, link_mode),
|
||||
.yes => |p| p,
|
||||
};
|
||||
|
||||
@ -450,6 +459,7 @@ fn buildOutputType(
|
||||
.link_mode = link_mode,
|
||||
.object_format = object_format,
|
||||
.optimize_mode = build_mode,
|
||||
.keep_source_files_loaded = zir_out_path != null,
|
||||
});
|
||||
defer module.deinit();
|
||||
|
||||
@ -487,7 +497,9 @@ fn buildOutputType(
|
||||
}
|
||||
|
||||
fn updateModule(gpa: *Allocator, module: *Module, zir_out_path: ?[]const u8) !void {
|
||||
var timer = try std.time.Timer.start();
|
||||
try module.update();
|
||||
const update_nanos = timer.read();
|
||||
|
||||
var errors = try module.getAllErrorsAlloc();
|
||||
defer errors.deinit(module.allocator);
|
||||
@ -501,6 +513,8 @@ fn updateModule(gpa: *Allocator, module: *Module, zir_out_path: ?[]const u8) !vo
|
||||
full_err_msg.msg,
|
||||
});
|
||||
}
|
||||
} else {
|
||||
std.log.info(.compiler, "Update completed in {} ms\n", .{update_nanos / std.time.ns_per_ms});
|
||||
}
|
||||
|
||||
if (zir_out_path) |zop| {
|
||||
|
||||
@ -21,32 +21,7 @@ const ErrorMsg = struct {
|
||||
};
|
||||
|
||||
pub const TestContext = struct {
|
||||
// TODO: remove these. They are deprecated.
|
||||
zir_cmp_output_cases: std.ArrayList(ZIRCompareOutputCase),
|
||||
|
||||
/// TODO: find a way to treat cases as individual tests (shouldn't show "1 test passed" if there are 200 cases)
|
||||
zir_cases: std.ArrayList(ZIRCase),
|
||||
|
||||
// TODO: remove
|
||||
pub const ZIRCompareOutputCase = struct {
|
||||
name: []const u8,
|
||||
src_list: []const []const u8,
|
||||
expected_stdout_list: []const []const u8,
|
||||
};
|
||||
|
||||
pub const ZIRUpdateType = enum {
|
||||
/// A transformation update transforms the input ZIR and tests against
|
||||
/// the expected output
|
||||
Transformation,
|
||||
/// An error update attempts to compile bad code, and ensures that it
|
||||
/// fails to compile, and for the expected reasons
|
||||
Error,
|
||||
/// An execution update compiles and runs the input ZIR, feeding in
|
||||
/// provided input and ensuring that the outputs match what is expected
|
||||
Execution,
|
||||
/// A compilation update checks that the ZIR compiles without any issues
|
||||
Compiles,
|
||||
};
|
||||
zir_cases: std.ArrayList(Case),
|
||||
|
||||
pub const ZIRUpdate = struct {
|
||||
/// The input to the current update. We simulate an incremental update
|
||||
@ -57,58 +32,55 @@ pub const TestContext = struct {
|
||||
/// you can keep it mostly consistent, with small changes, testing the
|
||||
/// effects of the incremental compilation.
|
||||
src: [:0]const u8,
|
||||
case: union(ZIRUpdateType) {
|
||||
/// The expected output ZIR
|
||||
case: union(enum) {
|
||||
/// A transformation update transforms the input ZIR and tests against
|
||||
/// the expected output ZIR.
|
||||
Transformation: [:0]const u8,
|
||||
/// An error update attempts to compile bad code, and ensures that it
|
||||
/// fails to compile, and for the expected reasons.
|
||||
/// A slice containing the expected errors *in sequential order*.
|
||||
Error: []const ErrorMsg,
|
||||
|
||||
/// Input to feed to the program, and expected outputs.
|
||||
///
|
||||
/// If stdout, stderr, and exit_code are all null, addZIRCase will
|
||||
/// discard the test. To test for successful compilation, use a
|
||||
/// dedicated Compile update instead.
|
||||
Execution: struct {
|
||||
stdin: ?[]const u8,
|
||||
stdout: ?[]const u8,
|
||||
stderr: ?[]const u8,
|
||||
exit_code: ?u8,
|
||||
},
|
||||
/// A Compiles test checks only that compilation of the given ZIR
|
||||
/// succeeds. To test outputs, use an Execution test. It is good to
|
||||
/// use a Compiles test before an Execution, as the overhead should
|
||||
/// be low (due to incremental compilation) and TODO: provide a way
|
||||
/// to check changed / new / etc decls in testing mode
|
||||
/// (usingnamespace a debug info struct with a comptime flag?)
|
||||
Compiles: void,
|
||||
/// An execution update compiles and runs the input ZIR, feeding in
|
||||
/// provided input and ensuring that the stdout match what is expected.
|
||||
Execution: []const u8,
|
||||
},
|
||||
};
|
||||
|
||||
/// A ZIRCase consists of a set of *updates*. A update can transform ZIR,
|
||||
/// A Case consists of a set of *updates*. A update can transform ZIR,
|
||||
/// compile it, ensure that compilation fails, and more. The same Module is
|
||||
/// used for each update, so each update's source is treated as a single file
|
||||
/// being updated by the test harness and incrementally compiled.
|
||||
pub const ZIRCase = struct {
|
||||
pub const Case = struct {
|
||||
name: []const u8,
|
||||
/// The platform the ZIR targets. For non-native platforms, an emulator
|
||||
/// such as QEMU is required for tests to complete.
|
||||
target: std.zig.CrossTarget,
|
||||
updates: std.ArrayList(ZIRUpdate),
|
||||
output_mode: std.builtin.OutputMode,
|
||||
/// Either ".zir" or ".zig"
|
||||
extension: [4]u8,
|
||||
|
||||
/// Adds a subcase in which the module is updated with new ZIR, and the
|
||||
/// resulting ZIR is validated.
|
||||
pub fn addTransform(self: *ZIRCase, src: [:0]const u8, result: [:0]const u8) void {
|
||||
pub fn addTransform(self: *Case, src: [:0]const u8, result: [:0]const u8) void {
|
||||
self.updates.append(.{
|
||||
.src = src,
|
||||
.case = .{ .Transformation = result },
|
||||
}) catch unreachable;
|
||||
}
|
||||
|
||||
pub fn addCompareOutput(self: *Case, src: [:0]const u8, result: []const u8) void {
|
||||
self.updates.append(.{
|
||||
.src = src,
|
||||
.case = .{ .Execution = result },
|
||||
}) catch unreachable;
|
||||
}
|
||||
|
||||
/// Adds a subcase in which the module is updated with invalid ZIR, and
|
||||
/// ensures that compilation fails for the expected reasons.
|
||||
///
|
||||
/// Errors must be specified in sequential order.
|
||||
pub fn addError(self: *ZIRCase, src: [:0]const u8, errors: []const []const u8) void {
|
||||
pub fn addError(self: *Case, src: [:0]const u8, errors: []const []const u8) void {
|
||||
var array = self.updates.allocator.alloc(ErrorMsg, errors.len) catch unreachable;
|
||||
for (errors) |e, i| {
|
||||
if (e[0] != ':') {
|
||||
@ -146,15 +118,65 @@ pub const TestContext = struct {
|
||||
}
|
||||
};
|
||||
|
||||
pub fn addZIRMulti(
|
||||
pub fn addExeZIR(
|
||||
ctx: *TestContext,
|
||||
name: []const u8,
|
||||
target: std.zig.CrossTarget,
|
||||
) *ZIRCase {
|
||||
const case = ZIRCase{
|
||||
) *Case {
|
||||
const case = Case{
|
||||
.name = name,
|
||||
.target = target,
|
||||
.updates = std.ArrayList(ZIRUpdate).init(ctx.zir_cases.allocator),
|
||||
.output_mode = .Exe,
|
||||
.extension = ".zir".*,
|
||||
};
|
||||
ctx.zir_cases.append(case) catch unreachable;
|
||||
return &ctx.zir_cases.items[ctx.zir_cases.items.len - 1];
|
||||
}
|
||||
|
||||
pub fn addObjZIR(
|
||||
ctx: *TestContext,
|
||||
name: []const u8,
|
||||
target: std.zig.CrossTarget,
|
||||
) *Case {
|
||||
const case = Case{
|
||||
.name = name,
|
||||
.target = target,
|
||||
.updates = std.ArrayList(ZIRUpdate).init(ctx.zir_cases.allocator),
|
||||
.output_mode = .Obj,
|
||||
.extension = ".zir".*,
|
||||
};
|
||||
ctx.zir_cases.append(case) catch unreachable;
|
||||
return &ctx.zir_cases.items[ctx.zir_cases.items.len - 1];
|
||||
}
|
||||
|
||||
pub fn addExe(
|
||||
ctx: *TestContext,
|
||||
name: []const u8,
|
||||
target: std.zig.CrossTarget,
|
||||
) *Case {
|
||||
const case = Case{
|
||||
.name = name,
|
||||
.target = target,
|
||||
.updates = std.ArrayList(ZIRUpdate).init(ctx.zir_cases.allocator),
|
||||
.output_mode = .Exe,
|
||||
.extension = ".zig".*,
|
||||
};
|
||||
ctx.zir_cases.append(case) catch unreachable;
|
||||
return &ctx.zir_cases.items[ctx.zir_cases.items.len - 1];
|
||||
}
|
||||
|
||||
pub fn addObj(
|
||||
ctx: *TestContext,
|
||||
name: []const u8,
|
||||
target: std.zig.CrossTarget,
|
||||
) *Case {
|
||||
const case = Case{
|
||||
.name = name,
|
||||
.target = target,
|
||||
.updates = std.ArrayList(ZIRUpdate).init(ctx.zir_cases.allocator),
|
||||
.output_mode = .Obj,
|
||||
.extension = ".zig".*,
|
||||
};
|
||||
ctx.zir_cases.append(case) catch unreachable;
|
||||
return &ctx.zir_cases.items[ctx.zir_cases.items.len - 1];
|
||||
@ -163,14 +185,21 @@ pub const TestContext = struct {
|
||||
pub fn addZIRCompareOutput(
|
||||
ctx: *TestContext,
|
||||
name: []const u8,
|
||||
src_list: []const []const u8,
|
||||
expected_stdout_list: []const []const u8,
|
||||
src: [:0]const u8,
|
||||
expected_stdout: []const u8,
|
||||
) void {
|
||||
ctx.zir_cmp_output_cases.append(.{
|
||||
.name = name,
|
||||
.src_list = src_list,
|
||||
.expected_stdout_list = expected_stdout_list,
|
||||
}) catch unreachable;
|
||||
var c = ctx.addExeZIR(name, .{});
|
||||
c.addCompareOutput(src, expected_stdout);
|
||||
}
|
||||
|
||||
pub fn addCompareOutput(
|
||||
ctx: *TestContext,
|
||||
name: []const u8,
|
||||
src: [:0]const u8,
|
||||
expected_stdout: []const u8,
|
||||
) void {
|
||||
var c = ctx.addExe(name, .{});
|
||||
c.addCompareOutput(src, expected_stdout);
|
||||
}
|
||||
|
||||
pub fn addZIRTransform(
|
||||
@ -180,7 +209,7 @@ pub const TestContext = struct {
|
||||
src: [:0]const u8,
|
||||
result: [:0]const u8,
|
||||
) void {
|
||||
var c = ctx.addZIRMulti(name, target);
|
||||
var c = ctx.addObjZIR(name, target);
|
||||
c.addTransform(src, result);
|
||||
}
|
||||
|
||||
@ -191,20 +220,18 @@ pub const TestContext = struct {
|
||||
src: [:0]const u8,
|
||||
expected_errors: []const []const u8,
|
||||
) void {
|
||||
var c = ctx.addZIRMulti(name, target);
|
||||
var c = ctx.addObjZIR(name, target);
|
||||
c.addError(src, expected_errors);
|
||||
}
|
||||
|
||||
fn init() TestContext {
|
||||
const allocator = std.heap.page_allocator;
|
||||
return .{
|
||||
.zir_cmp_output_cases = std.ArrayList(ZIRCompareOutputCase).init(allocator),
|
||||
.zir_cases = std.ArrayList(ZIRCase).init(allocator),
|
||||
.zir_cases = std.ArrayList(Case).init(allocator),
|
||||
};
|
||||
}
|
||||
|
||||
fn deinit(self: *TestContext) void {
|
||||
self.zir_cmp_output_cases.deinit();
|
||||
for (self.zir_cases.items) |c| {
|
||||
for (c.updates.items) |u| {
|
||||
if (u.case == .Error) {
|
||||
@ -226,30 +253,32 @@ pub const TestContext = struct {
|
||||
|
||||
for (self.zir_cases.items) |case| {
|
||||
std.testing.base_allocator_instance.reset();
|
||||
const info = try std.zig.system.NativeTargetInfo.detect(std.testing.allocator, case.target);
|
||||
try self.runOneZIRCase(std.testing.allocator, root_node, case, info.target);
|
||||
try std.testing.allocator_instance.validate();
|
||||
}
|
||||
|
||||
// TODO: wipe the rest of this function
|
||||
for (self.zir_cmp_output_cases.items) |case| {
|
||||
std.testing.base_allocator_instance.reset();
|
||||
try self.runOneZIRCmpOutputCase(std.testing.allocator, root_node, case, native_info.target);
|
||||
var prg_node = root_node.start(case.name, case.updates.items.len);
|
||||
prg_node.activate();
|
||||
defer prg_node.end();
|
||||
|
||||
// So that we can see which test case failed when the leak checker goes off.
|
||||
progress.refresh();
|
||||
|
||||
const info = try std.zig.system.NativeTargetInfo.detect(std.testing.allocator, case.target);
|
||||
try self.runOneCase(std.testing.allocator, &prg_node, case, info.target);
|
||||
try std.testing.allocator_instance.validate();
|
||||
}
|
||||
}
|
||||
|
||||
fn runOneZIRCase(self: *TestContext, allocator: *Allocator, root_node: *std.Progress.Node, case: ZIRCase, target: std.Target) !void {
|
||||
fn runOneCase(self: *TestContext, allocator: *Allocator, prg_node: *std.Progress.Node, case: Case, target: std.Target) !void {
|
||||
var tmp = std.testing.tmpDir(.{});
|
||||
defer tmp.cleanup();
|
||||
|
||||
const tmp_src_path = "test_case.zir";
|
||||
const root_name = "test_case";
|
||||
const tmp_src_path = try std.fmt.allocPrint(allocator, "{}{}", .{ root_name, case.extension });
|
||||
defer allocator.free(tmp_src_path);
|
||||
const root_pkg = try Package.create(allocator, tmp.dir, ".", tmp_src_path);
|
||||
defer root_pkg.destroy();
|
||||
|
||||
var prg_node = root_node.start(case.name, case.updates.items.len);
|
||||
prg_node.activate();
|
||||
defer prg_node.end();
|
||||
const bin_name = try std.zig.binNameAlloc(allocator, root_name, target, case.output_mode, null);
|
||||
defer allocator.free(bin_name);
|
||||
|
||||
var module = try Module.init(allocator, .{
|
||||
.target = target,
|
||||
@ -259,16 +288,17 @@ pub const TestContext = struct {
|
||||
// TODO: support tests for object file building, and library builds
|
||||
// and linking. This will require a rework to support multi-file
|
||||
// tests.
|
||||
.output_mode = .Obj,
|
||||
.output_mode = case.output_mode,
|
||||
// TODO: support testing optimizations
|
||||
.optimize_mode = .Debug,
|
||||
.bin_file_dir = tmp.dir,
|
||||
.bin_file_path = "test_case.o",
|
||||
.bin_file_path = bin_name,
|
||||
.root_pkg = root_pkg,
|
||||
.keep_source_files_loaded = true,
|
||||
});
|
||||
defer module.deinit();
|
||||
|
||||
for (case.updates.items) |update| {
|
||||
for (case.updates.items) |update, update_index| {
|
||||
var update_node = prg_node.start("update", 4);
|
||||
update_node.activate();
|
||||
defer update_node.end();
|
||||
@ -280,6 +310,7 @@ pub const TestContext = struct {
|
||||
|
||||
var module_node = update_node.start("parse/analysis/codegen", null);
|
||||
module_node.activate();
|
||||
try module.makeBinFileWritable();
|
||||
try module.update();
|
||||
module_node.end();
|
||||
|
||||
@ -328,82 +359,41 @@ pub const TestContext = struct {
|
||||
}
|
||||
}
|
||||
},
|
||||
.Execution => |expected_stdout| {
|
||||
var exec_result = x: {
|
||||
var exec_node = update_node.start("execute", null);
|
||||
exec_node.activate();
|
||||
defer exec_node.end();
|
||||
|
||||
else => return error.unimplemented,
|
||||
}
|
||||
}
|
||||
}
|
||||
try module.makeBinFileExecutable();
|
||||
|
||||
fn runOneZIRCmpOutputCase(
|
||||
self: *TestContext,
|
||||
allocator: *Allocator,
|
||||
root_node: *std.Progress.Node,
|
||||
case: ZIRCompareOutputCase,
|
||||
target: std.Target,
|
||||
) !void {
|
||||
var tmp = std.testing.tmpDir(.{});
|
||||
defer tmp.cleanup();
|
||||
const exe_path = try std.fmt.allocPrint(allocator, "." ++ std.fs.path.sep_str ++ "{}", .{bin_name});
|
||||
defer allocator.free(exe_path);
|
||||
|
||||
const tmp_src_path = "test-case.zir";
|
||||
const root_pkg = try Package.create(allocator, tmp.dir, ".", tmp_src_path);
|
||||
defer root_pkg.destroy();
|
||||
|
||||
var prg_node = root_node.start(case.name, case.src_list.len);
|
||||
prg_node.activate();
|
||||
defer prg_node.end();
|
||||
|
||||
var module = try Module.init(allocator, .{
|
||||
.target = target,
|
||||
.output_mode = .Exe,
|
||||
.optimize_mode = .Debug,
|
||||
.bin_file_dir = tmp.dir,
|
||||
.bin_file_path = "a.out",
|
||||
.root_pkg = root_pkg,
|
||||
});
|
||||
defer module.deinit();
|
||||
|
||||
for (case.src_list) |source, i| {
|
||||
var src_node = prg_node.start("update", 2);
|
||||
src_node.activate();
|
||||
defer src_node.end();
|
||||
|
||||
try tmp.dir.writeFile(tmp_src_path, source);
|
||||
|
||||
var update_node = src_node.start("parse,analysis,codegen", null);
|
||||
update_node.activate();
|
||||
try module.makeBinFileWritable();
|
||||
try module.update();
|
||||
update_node.end();
|
||||
|
||||
var exec_result = x: {
|
||||
var exec_node = src_node.start("execute", null);
|
||||
exec_node.activate();
|
||||
defer exec_node.end();
|
||||
|
||||
try module.makeBinFileExecutable();
|
||||
break :x try std.ChildProcess.exec(.{
|
||||
.allocator = allocator,
|
||||
.argv = &[_][]const u8{"./a.out"},
|
||||
.cwd_dir = tmp.dir,
|
||||
});
|
||||
};
|
||||
defer allocator.free(exec_result.stdout);
|
||||
defer allocator.free(exec_result.stderr);
|
||||
switch (exec_result.term) {
|
||||
.Exited => |code| {
|
||||
if (code != 0) {
|
||||
std.debug.warn("elf file exited with code {}\n", .{code});
|
||||
return error.BinaryBadExitCode;
|
||||
break :x try std.ChildProcess.exec(.{
|
||||
.allocator = allocator,
|
||||
.argv = &[_][]const u8{exe_path},
|
||||
.cwd_dir = tmp.dir,
|
||||
});
|
||||
};
|
||||
defer allocator.free(exec_result.stdout);
|
||||
defer allocator.free(exec_result.stderr);
|
||||
switch (exec_result.term) {
|
||||
.Exited => |code| {
|
||||
if (code != 0) {
|
||||
std.debug.warn("elf file exited with code {}\n", .{code});
|
||||
return error.BinaryBadExitCode;
|
||||
}
|
||||
},
|
||||
else => return error.BinaryCrashed,
|
||||
}
|
||||
if (!std.mem.eql(u8, expected_stdout, exec_result.stdout)) {
|
||||
std.debug.panic(
|
||||
"update index {}, mismatched stdout\n====Expected (len={}):====\n{}\n====Actual (len={}):====\n{}\n========\n",
|
||||
.{ update_index, expected_stdout.len, expected_stdout, exec_result.stdout.len, exec_result.stdout },
|
||||
);
|
||||
}
|
||||
},
|
||||
else => return error.BinaryCrashed,
|
||||
}
|
||||
const expected_stdout = case.expected_stdout_list[i];
|
||||
if (!std.mem.eql(u8, expected_stdout, exec_result.stdout)) {
|
||||
std.debug.panic(
|
||||
"update index {}, mismatched stdout\n====Expected (len={}):====\n{}\n====Actual (len={}):====\n{}\n========\n",
|
||||
.{ i, expected_stdout.len, expected_stdout, exec_result.stdout.len, exec_result.stdout },
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
45
src-self-hosted/tracy.zig
Normal file
45
src-self-hosted/tracy.zig
Normal file
@ -0,0 +1,45 @@
|
||||
pub const std = @import("std");
|
||||
|
||||
pub const enable = if (std.builtin.is_test) false else @import("build_options").enable_tracy;
|
||||
|
||||
extern fn ___tracy_emit_zone_begin_callstack(
|
||||
srcloc: *const ___tracy_source_location_data,
|
||||
depth: c_int,
|
||||
active: c_int,
|
||||
) ___tracy_c_zone_context;
|
||||
|
||||
extern fn ___tracy_emit_zone_end(ctx: ___tracy_c_zone_context) void;
|
||||
|
||||
pub const ___tracy_source_location_data = extern struct {
|
||||
name: ?[*:0]const u8,
|
||||
function: [*:0]const u8,
|
||||
file: [*:0]const u8,
|
||||
line: u32,
|
||||
color: u32,
|
||||
};
|
||||
|
||||
pub const ___tracy_c_zone_context = extern struct {
|
||||
id: u32,
|
||||
active: c_int,
|
||||
|
||||
pub fn end(self: ___tracy_c_zone_context) void {
|
||||
___tracy_emit_zone_end(self);
|
||||
}
|
||||
};
|
||||
|
||||
pub const Ctx = if (enable) ___tracy_c_zone_context else struct {
|
||||
pub fn end(self: Ctx) void {}
|
||||
};
|
||||
|
||||
pub inline fn trace(comptime src: std.builtin.SourceLocation) Ctx {
|
||||
if (!enable) return .{};
|
||||
|
||||
const loc: ___tracy_source_location_data = .{
|
||||
.name = null,
|
||||
.function = src.fn_name.ptr,
|
||||
.file = src.file.ptr,
|
||||
.line = src.line,
|
||||
.color = 0,
|
||||
};
|
||||
return ___tracy_emit_zone_begin_callstack(&loc, 1, 1);
|
||||
}
|
||||
@ -54,6 +54,7 @@ pub const Type = extern union {
|
||||
.@"undefined" => return .Undefined,
|
||||
|
||||
.fn_noreturn_no_args => return .Fn,
|
||||
.fn_void_no_args => return .Fn,
|
||||
.fn_naked_noreturn_no_args => return .Fn,
|
||||
.fn_ccc_void_no_args => return .Fn,
|
||||
|
||||
@ -112,6 +113,12 @@ pub const Type = extern union {
|
||||
.Undefined => return true,
|
||||
.Null => return true,
|
||||
.Pointer => {
|
||||
// Hot path for common case:
|
||||
if (a.cast(Payload.SingleConstPointer)) |a_payload| {
|
||||
if (b.cast(Payload.SingleConstPointer)) |b_payload| {
|
||||
return eql(a_payload.pointee_type, b_payload.pointee_type);
|
||||
}
|
||||
}
|
||||
const is_slice_a = isSlice(a);
|
||||
const is_slice_b = isSlice(b);
|
||||
if (is_slice_a != is_slice_b)
|
||||
@ -163,6 +170,77 @@ pub const Type = extern union {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn copy(self: Type, allocator: *Allocator) error{OutOfMemory}!Type {
|
||||
if (self.tag_if_small_enough < Tag.no_payload_count) {
|
||||
return Type{ .tag_if_small_enough = self.tag_if_small_enough };
|
||||
} else switch (self.ptr_otherwise.tag) {
|
||||
.u8,
|
||||
.i8,
|
||||
.isize,
|
||||
.usize,
|
||||
.c_short,
|
||||
.c_ushort,
|
||||
.c_int,
|
||||
.c_uint,
|
||||
.c_long,
|
||||
.c_ulong,
|
||||
.c_longlong,
|
||||
.c_ulonglong,
|
||||
.c_longdouble,
|
||||
.c_void,
|
||||
.f16,
|
||||
.f32,
|
||||
.f64,
|
||||
.f128,
|
||||
.bool,
|
||||
.void,
|
||||
.type,
|
||||
.anyerror,
|
||||
.comptime_int,
|
||||
.comptime_float,
|
||||
.noreturn,
|
||||
.@"null",
|
||||
.@"undefined",
|
||||
.fn_noreturn_no_args,
|
||||
.fn_void_no_args,
|
||||
.fn_naked_noreturn_no_args,
|
||||
.fn_ccc_void_no_args,
|
||||
.single_const_pointer_to_comptime_int,
|
||||
.const_slice_u8,
|
||||
=> unreachable,
|
||||
|
||||
.array_u8_sentinel_0 => return self.copyPayloadShallow(allocator, Payload.Array_u8_Sentinel0),
|
||||
.array => {
|
||||
const payload = @fieldParentPtr(Payload.Array, "base", self.ptr_otherwise);
|
||||
const new_payload = try allocator.create(Payload.Array);
|
||||
new_payload.* = .{
|
||||
.base = payload.base,
|
||||
.len = payload.len,
|
||||
.elem_type = try payload.elem_type.copy(allocator),
|
||||
};
|
||||
return Type{ .ptr_otherwise = &new_payload.base };
|
||||
},
|
||||
.single_const_pointer => {
|
||||
const payload = @fieldParentPtr(Payload.SingleConstPointer, "base", self.ptr_otherwise);
|
||||
const new_payload = try allocator.create(Payload.SingleConstPointer);
|
||||
new_payload.* = .{
|
||||
.base = payload.base,
|
||||
.pointee_type = try payload.pointee_type.copy(allocator),
|
||||
};
|
||||
return Type{ .ptr_otherwise = &new_payload.base };
|
||||
},
|
||||
.int_signed => return self.copyPayloadShallow(allocator, Payload.IntSigned),
|
||||
.int_unsigned => return self.copyPayloadShallow(allocator, Payload.IntUnsigned),
|
||||
}
|
||||
}
|
||||
|
||||
fn copyPayloadShallow(self: Type, allocator: *Allocator, comptime T: type) error{OutOfMemory}!Type {
|
||||
const payload = @fieldParentPtr(T, "base", self.ptr_otherwise);
|
||||
const new_payload = try allocator.create(T);
|
||||
new_payload.* = payload.*;
|
||||
return Type{ .ptr_otherwise = &new_payload.base };
|
||||
}
|
||||
|
||||
pub fn format(
|
||||
self: Type,
|
||||
comptime fmt: []const u8,
|
||||
@ -206,6 +284,7 @@ pub const Type = extern union {
|
||||
|
||||
.const_slice_u8 => return out_stream.writeAll("[]const u8"),
|
||||
.fn_noreturn_no_args => return out_stream.writeAll("fn() noreturn"),
|
||||
.fn_void_no_args => return out_stream.writeAll("fn() void"),
|
||||
.fn_naked_noreturn_no_args => return out_stream.writeAll("fn() callconv(.Naked) noreturn"),
|
||||
.fn_ccc_void_no_args => return out_stream.writeAll("fn() callconv(.C) void"),
|
||||
.single_const_pointer_to_comptime_int => return out_stream.writeAll("*const comptime_int"),
|
||||
@ -269,6 +348,7 @@ pub const Type = extern union {
|
||||
.@"null" => return Value.initTag(.null_type),
|
||||
.@"undefined" => return Value.initTag(.undefined_type),
|
||||
.fn_noreturn_no_args => return Value.initTag(.fn_noreturn_no_args_type),
|
||||
.fn_void_no_args => return Value.initTag(.fn_void_no_args_type),
|
||||
.fn_naked_noreturn_no_args => return Value.initTag(.fn_naked_noreturn_no_args_type),
|
||||
.fn_ccc_void_no_args => return Value.initTag(.fn_ccc_void_no_args_type),
|
||||
.single_const_pointer_to_comptime_int => return Value.initTag(.single_const_pointer_to_comptime_int_type),
|
||||
@ -303,6 +383,7 @@ pub const Type = extern union {
|
||||
.bool,
|
||||
.anyerror,
|
||||
.fn_noreturn_no_args,
|
||||
.fn_void_no_args,
|
||||
.fn_naked_noreturn_no_args,
|
||||
.fn_ccc_void_no_args,
|
||||
.single_const_pointer_to_comptime_int,
|
||||
@ -333,6 +414,7 @@ pub const Type = extern union {
|
||||
.i8,
|
||||
.bool,
|
||||
.fn_noreturn_no_args, // represents machine code; not a pointer
|
||||
.fn_void_no_args, // represents machine code; not a pointer
|
||||
.fn_naked_noreturn_no_args, // represents machine code; not a pointer
|
||||
.fn_ccc_void_no_args, // represents machine code; not a pointer
|
||||
.array_u8_sentinel_0,
|
||||
@ -420,6 +502,7 @@ pub const Type = extern union {
|
||||
.array_u8_sentinel_0,
|
||||
.const_slice_u8,
|
||||
.fn_noreturn_no_args,
|
||||
.fn_void_no_args,
|
||||
.fn_naked_noreturn_no_args,
|
||||
.fn_ccc_void_no_args,
|
||||
.int_unsigned,
|
||||
@ -466,6 +549,7 @@ pub const Type = extern union {
|
||||
.single_const_pointer,
|
||||
.single_const_pointer_to_comptime_int,
|
||||
.fn_noreturn_no_args,
|
||||
.fn_void_no_args,
|
||||
.fn_naked_noreturn_no_args,
|
||||
.fn_ccc_void_no_args,
|
||||
.int_unsigned,
|
||||
@ -509,6 +593,7 @@ pub const Type = extern union {
|
||||
.array,
|
||||
.array_u8_sentinel_0,
|
||||
.fn_noreturn_no_args,
|
||||
.fn_void_no_args,
|
||||
.fn_naked_noreturn_no_args,
|
||||
.fn_ccc_void_no_args,
|
||||
.int_unsigned,
|
||||
@ -553,6 +638,7 @@ pub const Type = extern union {
|
||||
.@"null",
|
||||
.@"undefined",
|
||||
.fn_noreturn_no_args,
|
||||
.fn_void_no_args,
|
||||
.fn_naked_noreturn_no_args,
|
||||
.fn_ccc_void_no_args,
|
||||
.int_unsigned,
|
||||
@ -597,6 +683,7 @@ pub const Type = extern union {
|
||||
.@"null",
|
||||
.@"undefined",
|
||||
.fn_noreturn_no_args,
|
||||
.fn_void_no_args,
|
||||
.fn_naked_noreturn_no_args,
|
||||
.fn_ccc_void_no_args,
|
||||
.single_const_pointer,
|
||||
@ -642,6 +729,7 @@ pub const Type = extern union {
|
||||
.@"null",
|
||||
.@"undefined",
|
||||
.fn_noreturn_no_args,
|
||||
.fn_void_no_args,
|
||||
.fn_naked_noreturn_no_args,
|
||||
.fn_ccc_void_no_args,
|
||||
.single_const_pointer,
|
||||
@ -675,6 +763,7 @@ pub const Type = extern union {
|
||||
.@"null",
|
||||
.@"undefined",
|
||||
.fn_noreturn_no_args,
|
||||
.fn_void_no_args,
|
||||
.fn_naked_noreturn_no_args,
|
||||
.fn_ccc_void_no_args,
|
||||
.array,
|
||||
@ -721,6 +810,7 @@ pub const Type = extern union {
|
||||
.@"null",
|
||||
.@"undefined",
|
||||
.fn_noreturn_no_args,
|
||||
.fn_void_no_args,
|
||||
.fn_naked_noreturn_no_args,
|
||||
.fn_ccc_void_no_args,
|
||||
.array,
|
||||
@ -777,6 +867,7 @@ pub const Type = extern union {
|
||||
pub fn fnParamLen(self: Type) usize {
|
||||
return switch (self.tag()) {
|
||||
.fn_noreturn_no_args => 0,
|
||||
.fn_void_no_args => 0,
|
||||
.fn_naked_noreturn_no_args => 0,
|
||||
.fn_ccc_void_no_args => 0,
|
||||
|
||||
@ -823,6 +914,7 @@ pub const Type = extern union {
|
||||
pub fn fnParamTypes(self: Type, types: []Type) void {
|
||||
switch (self.tag()) {
|
||||
.fn_noreturn_no_args => return,
|
||||
.fn_void_no_args => return,
|
||||
.fn_naked_noreturn_no_args => return,
|
||||
.fn_ccc_void_no_args => return,
|
||||
|
||||
@ -869,7 +961,10 @@ pub const Type = extern union {
|
||||
return switch (self.tag()) {
|
||||
.fn_noreturn_no_args => Type.initTag(.noreturn),
|
||||
.fn_naked_noreturn_no_args => Type.initTag(.noreturn),
|
||||
.fn_ccc_void_no_args => Type.initTag(.void),
|
||||
|
||||
.fn_void_no_args,
|
||||
.fn_ccc_void_no_args,
|
||||
=> Type.initTag(.void),
|
||||
|
||||
.f16,
|
||||
.f32,
|
||||
@ -913,6 +1008,7 @@ pub const Type = extern union {
|
||||
pub fn fnCallingConvention(self: Type) std.builtin.CallingConvention {
|
||||
return switch (self.tag()) {
|
||||
.fn_noreturn_no_args => .Unspecified,
|
||||
.fn_void_no_args => .Unspecified,
|
||||
.fn_naked_noreturn_no_args => .Naked,
|
||||
.fn_ccc_void_no_args => .C,
|
||||
|
||||
@ -958,6 +1054,7 @@ pub const Type = extern union {
|
||||
pub fn fnIsVarArgs(self: Type) bool {
|
||||
return switch (self.tag()) {
|
||||
.fn_noreturn_no_args => false,
|
||||
.fn_void_no_args => false,
|
||||
.fn_naked_noreturn_no_args => false,
|
||||
.fn_ccc_void_no_args => false,
|
||||
|
||||
@ -1033,6 +1130,7 @@ pub const Type = extern union {
|
||||
.@"null",
|
||||
.@"undefined",
|
||||
.fn_noreturn_no_args,
|
||||
.fn_void_no_args,
|
||||
.fn_naked_noreturn_no_args,
|
||||
.fn_ccc_void_no_args,
|
||||
.array,
|
||||
@ -1070,6 +1168,7 @@ pub const Type = extern union {
|
||||
.type,
|
||||
.anyerror,
|
||||
.fn_noreturn_no_args,
|
||||
.fn_void_no_args,
|
||||
.fn_naked_noreturn_no_args,
|
||||
.fn_ccc_void_no_args,
|
||||
.single_const_pointer_to_comptime_int,
|
||||
@ -1126,6 +1225,7 @@ pub const Type = extern union {
|
||||
.type,
|
||||
.anyerror,
|
||||
.fn_noreturn_no_args,
|
||||
.fn_void_no_args,
|
||||
.fn_naked_noreturn_no_args,
|
||||
.fn_ccc_void_no_args,
|
||||
.single_const_pointer_to_comptime_int,
|
||||
@ -1180,6 +1280,7 @@ pub const Type = extern union {
|
||||
@"null",
|
||||
@"undefined",
|
||||
fn_noreturn_no_args,
|
||||
fn_void_no_args,
|
||||
fn_naked_noreturn_no_args,
|
||||
fn_ccc_void_no_args,
|
||||
single_const_pointer_to_comptime_int,
|
||||
|
||||
@ -49,6 +49,7 @@ pub const Value = extern union {
|
||||
null_type,
|
||||
undefined_type,
|
||||
fn_noreturn_no_args_type,
|
||||
fn_void_no_args_type,
|
||||
fn_naked_noreturn_no_args_type,
|
||||
fn_ccc_void_no_args_type,
|
||||
single_const_pointer_to_comptime_int_type,
|
||||
@ -78,8 +79,8 @@ pub const Value = extern union {
|
||||
pub const no_payload_count = @enumToInt(last_no_payload_tag) + 1;
|
||||
};
|
||||
|
||||
pub fn initTag(comptime small_tag: Tag) Value {
|
||||
comptime assert(@enumToInt(small_tag) < Tag.no_payload_count);
|
||||
pub fn initTag(small_tag: Tag) Value {
|
||||
assert(@enumToInt(small_tag) < Tag.no_payload_count);
|
||||
return .{ .tag_if_small_enough = @enumToInt(small_tag) };
|
||||
}
|
||||
|
||||
@ -107,6 +108,109 @@ pub const Value = extern union {
|
||||
return @fieldParentPtr(T, "base", self.ptr_otherwise);
|
||||
}
|
||||
|
||||
pub fn copy(self: Value, allocator: *Allocator) error{OutOfMemory}!Value {
|
||||
if (self.tag_if_small_enough < Tag.no_payload_count) {
|
||||
return Value{ .tag_if_small_enough = self.tag_if_small_enough };
|
||||
} else switch (self.ptr_otherwise.tag) {
|
||||
.u8_type,
|
||||
.i8_type,
|
||||
.isize_type,
|
||||
.usize_type,
|
||||
.c_short_type,
|
||||
.c_ushort_type,
|
||||
.c_int_type,
|
||||
.c_uint_type,
|
||||
.c_long_type,
|
||||
.c_ulong_type,
|
||||
.c_longlong_type,
|
||||
.c_ulonglong_type,
|
||||
.c_longdouble_type,
|
||||
.f16_type,
|
||||
.f32_type,
|
||||
.f64_type,
|
||||
.f128_type,
|
||||
.c_void_type,
|
||||
.bool_type,
|
||||
.void_type,
|
||||
.type_type,
|
||||
.anyerror_type,
|
||||
.comptime_int_type,
|
||||
.comptime_float_type,
|
||||
.noreturn_type,
|
||||
.null_type,
|
||||
.undefined_type,
|
||||
.fn_noreturn_no_args_type,
|
||||
.fn_void_no_args_type,
|
||||
.fn_naked_noreturn_no_args_type,
|
||||
.fn_ccc_void_no_args_type,
|
||||
.single_const_pointer_to_comptime_int_type,
|
||||
.const_slice_u8_type,
|
||||
.undef,
|
||||
.zero,
|
||||
.the_one_possible_value,
|
||||
.null_value,
|
||||
.bool_true,
|
||||
.bool_false,
|
||||
=> unreachable,
|
||||
|
||||
.ty => {
|
||||
const payload = @fieldParentPtr(Payload.Ty, "base", self.ptr_otherwise);
|
||||
const new_payload = try allocator.create(Payload.Ty);
|
||||
new_payload.* = .{
|
||||
.base = payload.base,
|
||||
.ty = try payload.ty.copy(allocator),
|
||||
};
|
||||
return Value{ .ptr_otherwise = &new_payload.base };
|
||||
},
|
||||
.int_u64 => return self.copyPayloadShallow(allocator, Payload.Int_u64),
|
||||
.int_i64 => return self.copyPayloadShallow(allocator, Payload.Int_i64),
|
||||
.int_big_positive => {
|
||||
@panic("TODO implement copying of big ints");
|
||||
},
|
||||
.int_big_negative => {
|
||||
@panic("TODO implement copying of big ints");
|
||||
},
|
||||
.function => return self.copyPayloadShallow(allocator, Payload.Function),
|
||||
.ref_val => {
|
||||
const payload = @fieldParentPtr(Payload.RefVal, "base", self.ptr_otherwise);
|
||||
const new_payload = try allocator.create(Payload.RefVal);
|
||||
new_payload.* = .{
|
||||
.base = payload.base,
|
||||
.val = try payload.val.copy(allocator),
|
||||
};
|
||||
return Value{ .ptr_otherwise = &new_payload.base };
|
||||
},
|
||||
.decl_ref => return self.copyPayloadShallow(allocator, Payload.DeclRef),
|
||||
.elem_ptr => {
|
||||
const payload = @fieldParentPtr(Payload.ElemPtr, "base", self.ptr_otherwise);
|
||||
const new_payload = try allocator.create(Payload.ElemPtr);
|
||||
new_payload.* = .{
|
||||
.base = payload.base,
|
||||
.array_ptr = try payload.array_ptr.copy(allocator),
|
||||
.index = payload.index,
|
||||
};
|
||||
return Value{ .ptr_otherwise = &new_payload.base };
|
||||
},
|
||||
.bytes => return self.copyPayloadShallow(allocator, Payload.Bytes),
|
||||
.repeated => {
|
||||
const payload = @fieldParentPtr(Payload.Repeated, "base", self.ptr_otherwise);
|
||||
const new_payload = try allocator.create(Payload.Repeated);
|
||||
new_payload.* = .{
|
||||
.base = payload.base,
|
||||
.val = try payload.val.copy(allocator),
|
||||
};
|
||||
return Value{ .ptr_otherwise = &new_payload.base };
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn copyPayloadShallow(self: Value, allocator: *Allocator, comptime T: type) error{OutOfMemory}!Value {
|
||||
const payload = @fieldParentPtr(T, "base", self.ptr_otherwise);
|
||||
const new_payload = try allocator.create(T);
|
||||
new_payload.* = payload.*;
|
||||
return Value{ .ptr_otherwise = &new_payload.base };
|
||||
}
|
||||
|
||||
pub fn format(
|
||||
self: Value,
|
||||
comptime fmt: []const u8,
|
||||
@ -144,6 +248,7 @@ pub const Value = extern union {
|
||||
.null_type => return out_stream.writeAll("@TypeOf(null)"),
|
||||
.undefined_type => return out_stream.writeAll("@TypeOf(undefined)"),
|
||||
.fn_noreturn_no_args_type => return out_stream.writeAll("fn() noreturn"),
|
||||
.fn_void_no_args_type => return out_stream.writeAll("fn() void"),
|
||||
.fn_naked_noreturn_no_args_type => return out_stream.writeAll("fn() callconv(.Naked) noreturn"),
|
||||
.fn_ccc_void_no_args_type => return out_stream.writeAll("fn() callconv(.C) void"),
|
||||
.single_const_pointer_to_comptime_int_type => return out_stream.writeAll("*const comptime_int"),
|
||||
@ -229,6 +334,7 @@ pub const Value = extern union {
|
||||
.null_type => Type.initTag(.@"null"),
|
||||
.undefined_type => Type.initTag(.@"undefined"),
|
||||
.fn_noreturn_no_args_type => Type.initTag(.fn_noreturn_no_args),
|
||||
.fn_void_no_args_type => Type.initTag(.fn_void_no_args),
|
||||
.fn_naked_noreturn_no_args_type => Type.initTag(.fn_naked_noreturn_no_args),
|
||||
.fn_ccc_void_no_args_type => Type.initTag(.fn_ccc_void_no_args),
|
||||
.single_const_pointer_to_comptime_int_type => Type.initTag(.single_const_pointer_to_comptime_int),
|
||||
@ -286,6 +392,7 @@ pub const Value = extern union {
|
||||
.null_type,
|
||||
.undefined_type,
|
||||
.fn_noreturn_no_args_type,
|
||||
.fn_void_no_args_type,
|
||||
.fn_naked_noreturn_no_args_type,
|
||||
.fn_ccc_void_no_args_type,
|
||||
.single_const_pointer_to_comptime_int_type,
|
||||
@ -345,6 +452,7 @@ pub const Value = extern union {
|
||||
.null_type,
|
||||
.undefined_type,
|
||||
.fn_noreturn_no_args_type,
|
||||
.fn_void_no_args_type,
|
||||
.fn_naked_noreturn_no_args_type,
|
||||
.fn_ccc_void_no_args_type,
|
||||
.single_const_pointer_to_comptime_int_type,
|
||||
@ -405,6 +513,7 @@ pub const Value = extern union {
|
||||
.null_type,
|
||||
.undefined_type,
|
||||
.fn_noreturn_no_args_type,
|
||||
.fn_void_no_args_type,
|
||||
.fn_naked_noreturn_no_args_type,
|
||||
.fn_ccc_void_no_args_type,
|
||||
.single_const_pointer_to_comptime_int_type,
|
||||
@ -470,6 +579,7 @@ pub const Value = extern union {
|
||||
.null_type,
|
||||
.undefined_type,
|
||||
.fn_noreturn_no_args_type,
|
||||
.fn_void_no_args_type,
|
||||
.fn_naked_noreturn_no_args_type,
|
||||
.fn_ccc_void_no_args_type,
|
||||
.single_const_pointer_to_comptime_int_type,
|
||||
@ -564,6 +674,7 @@ pub const Value = extern union {
|
||||
.null_type,
|
||||
.undefined_type,
|
||||
.fn_noreturn_no_args_type,
|
||||
.fn_void_no_args_type,
|
||||
.fn_naked_noreturn_no_args_type,
|
||||
.fn_ccc_void_no_args_type,
|
||||
.single_const_pointer_to_comptime_int_type,
|
||||
@ -620,6 +731,7 @@ pub const Value = extern union {
|
||||
.null_type,
|
||||
.undefined_type,
|
||||
.fn_noreturn_no_args_type,
|
||||
.fn_void_no_args_type,
|
||||
.fn_naked_noreturn_no_args_type,
|
||||
.fn_ccc_void_no_args_type,
|
||||
.single_const_pointer_to_comptime_int_type,
|
||||
@ -721,6 +833,7 @@ pub const Value = extern union {
|
||||
.null_type,
|
||||
.undefined_type,
|
||||
.fn_noreturn_no_args_type,
|
||||
.fn_void_no_args_type,
|
||||
.fn_naked_noreturn_no_args_type,
|
||||
.fn_ccc_void_no_args_type,
|
||||
.single_const_pointer_to_comptime_int_type,
|
||||
@ -783,6 +896,7 @@ pub const Value = extern union {
|
||||
.null_type,
|
||||
.undefined_type,
|
||||
.fn_noreturn_no_args_type,
|
||||
.fn_void_no_args_type,
|
||||
.fn_naked_noreturn_no_args_type,
|
||||
.fn_ccc_void_no_args_type,
|
||||
.single_const_pointer_to_comptime_int_type,
|
||||
@ -862,6 +976,7 @@ pub const Value = extern union {
|
||||
.null_type,
|
||||
.undefined_type,
|
||||
.fn_noreturn_no_args_type,
|
||||
.fn_void_no_args_type,
|
||||
.fn_naked_noreturn_no_args_type,
|
||||
.fn_ccc_void_no_args_type,
|
||||
.single_const_pointer_to_comptime_int_type,
|
||||
@ -929,11 +1044,6 @@ pub const Value = extern union {
|
||||
len: u64,
|
||||
};
|
||||
|
||||
pub const SingleConstPtrType = struct {
|
||||
base: Payload = Payload{ .tag = .single_const_ptr_type },
|
||||
elem_type: *Type,
|
||||
};
|
||||
|
||||
/// Represents a pointer to another immutable value.
|
||||
pub const RefVal = struct {
|
||||
base: Payload = Payload{ .tag = .ref_val },
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -5583,8 +5583,12 @@ static LLVMValueRef ir_render_memset(CodeGen *g, IrExecutableGen *executable, Ir
|
||||
|
||||
bool val_is_undef = value_is_all_undef(g, instruction->byte->value);
|
||||
LLVMValueRef fill_char;
|
||||
if (val_is_undef && ir_want_runtime_safety_scope(g, instruction->base.base.scope)) {
|
||||
fill_char = LLVMConstInt(LLVMInt8Type(), 0xaa, false);
|
||||
if (val_is_undef) {
|
||||
if (ir_want_runtime_safety_scope(g, instruction->base.base.scope)) {
|
||||
fill_char = LLVMConstInt(LLVMInt8Type(), 0xaa, false);
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
} else {
|
||||
fill_char = ir_llvm_value(g, instruction->byte);
|
||||
}
|
||||
@ -7473,6 +7477,12 @@ static LLVMValueRef gen_const_val(CodeGen *g, ZigValue *const_val, const char *n
|
||||
continue;
|
||||
}
|
||||
ZigValue *field_val = const_val->data.x_struct.fields[i];
|
||||
if (field_val == nullptr) {
|
||||
add_node_error(g, type_struct_field->decl_node,
|
||||
buf_sprintf("compiler bug: generating const value for struct field '%s'",
|
||||
buf_ptr(type_struct_field->name)));
|
||||
codegen_report_errors_and_exit(g);
|
||||
}
|
||||
ZigType *field_type = field_val->type;
|
||||
assert(field_type != nullptr);
|
||||
if ((err = ensure_const_val_repr(nullptr, g, nullptr, field_val, field_type))) {
|
||||
@ -9465,9 +9475,15 @@ void add_cc_args(CodeGen *g, ZigList<const char *> &args, const char *out_dep_pa
|
||||
const char *libcxx_include_path = buf_ptr(buf_sprintf("%s" OS_SEP "libcxx" OS_SEP "include",
|
||||
buf_ptr(g->zig_lib_dir)));
|
||||
|
||||
const char *libcxxabi_include_path = buf_ptr(buf_sprintf("%s" OS_SEP "libcxxabi" OS_SEP "include",
|
||||
buf_ptr(g->zig_lib_dir)));
|
||||
|
||||
args.append("-isystem");
|
||||
args.append(libcxx_include_path);
|
||||
|
||||
args.append("-isystem");
|
||||
args.append(libcxxabi_include_path);
|
||||
|
||||
if (target_abi_is_musl(g->zig_target->abi)) {
|
||||
args.append("-D_LIBCPP_HAS_MUSL_LIBC");
|
||||
}
|
||||
|
||||
@ -1,28 +1,121 @@
|
||||
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 these 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 {
|
||||
// TODO: re-enable these tests.
|
||||
// https://github.com/ziglang/zig/issues/1364
|
||||
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;
|
||||
}
|
||||
|
||||
//// hello world
|
||||
//try ctx.testCompareOutputLibC(
|
||||
// \\extern fn puts([*]const u8) void;
|
||||
// \\pub export fn main() c_int {
|
||||
// \\ puts("Hello, world!");
|
||||
// \\ return 0;
|
||||
// \\}
|
||||
//, "Hello, world!" ++ std.cstr.line_sep);
|
||||
|
||||
//// function calling another function
|
||||
//try ctx.testCompareOutputLibC(
|
||||
// \\extern fn puts(s: [*]const u8) void;
|
||||
// \\pub export fn main() c_int {
|
||||
// \\ return foo("OK");
|
||||
// \\}
|
||||
// \\fn foo(s: [*]const u8) c_int {
|
||||
// \\ puts(s);
|
||||
// \\ return 0;
|
||||
// \\}
|
||||
//, "OK" ++ std.cstr.line_sep);
|
||||
{
|
||||
var case = ctx.addExe("hello world with updates", linux_x64);
|
||||
// Regular old hello world
|
||||
case.addCompareOutput(
|
||||
\\export fn _start() noreturn {
|
||||
\\ print();
|
||||
\\
|
||||
\\ exit();
|
||||
\\}
|
||||
\\
|
||||
\\fn print() void {
|
||||
\\ asm volatile ("syscall"
|
||||
\\ :
|
||||
\\ : [number] "{rax}" (1),
|
||||
\\ [arg1] "{rdi}" (1),
|
||||
\\ [arg2] "{rsi}" (@ptrToInt("Hello, World!\n")),
|
||||
\\ [arg3] "{rdx}" (14)
|
||||
\\ : "rcx", "r11", "memory"
|
||||
\\ );
|
||||
\\ return;
|
||||
\\}
|
||||
\\
|
||||
\\fn exit() noreturn {
|
||||
\\ asm volatile ("syscall"
|
||||
\\ :
|
||||
\\ : [number] "{rax}" (231),
|
||||
\\ [arg1] "{rdi}" (0)
|
||||
\\ : "rcx", "r11", "memory"
|
||||
\\ );
|
||||
\\ unreachable;
|
||||
\\}
|
||||
,
|
||||
"Hello, World!\n",
|
||||
);
|
||||
// Now change the message only
|
||||
case.addCompareOutput(
|
||||
\\export fn _start() noreturn {
|
||||
\\ print();
|
||||
\\
|
||||
\\ exit();
|
||||
\\}
|
||||
\\
|
||||
\\fn print() void {
|
||||
\\ asm volatile ("syscall"
|
||||
\\ :
|
||||
\\ : [number] "{rax}" (1),
|
||||
\\ [arg1] "{rdi}" (1),
|
||||
\\ [arg2] "{rsi}" (@ptrToInt("What is up? This is a longer message that will force the data to be relocated in virtual address space.\n")),
|
||||
\\ [arg3] "{rdx}" (104)
|
||||
\\ : "rcx", "r11", "memory"
|
||||
\\ );
|
||||
\\ return;
|
||||
\\}
|
||||
\\
|
||||
\\fn exit() noreturn {
|
||||
\\ asm volatile ("syscall"
|
||||
\\ :
|
||||
\\ : [number] "{rax}" (231),
|
||||
\\ [arg1] "{rdi}" (0)
|
||||
\\ : "rcx", "r11", "memory"
|
||||
\\ );
|
||||
\\ unreachable;
|
||||
\\}
|
||||
,
|
||||
"What is up? This is a longer message that will force the data to be relocated in virtual address space.\n",
|
||||
);
|
||||
// Now we print it twice.
|
||||
case.addCompareOutput(
|
||||
\\export fn _start() noreturn {
|
||||
\\ print();
|
||||
\\ print();
|
||||
\\
|
||||
\\ exit();
|
||||
\\}
|
||||
\\
|
||||
\\fn print() void {
|
||||
\\ asm volatile ("syscall"
|
||||
\\ :
|
||||
\\ : [number] "{rax}" (1),
|
||||
\\ [arg1] "{rdi}" (1),
|
||||
\\ [arg2] "{rsi}" (@ptrToInt("What is up? This is a longer message that will force the data to be relocated in virtual address space.\n")),
|
||||
\\ [arg3] "{rdx}" (104)
|
||||
\\ : "rcx", "r11", "memory"
|
||||
\\ );
|
||||
\\ return;
|
||||
\\}
|
||||
\\
|
||||
\\fn exit() noreturn {
|
||||
\\ asm volatile ("syscall"
|
||||
\\ :
|
||||
\\ : [number] "{rax}" (231),
|
||||
\\ [arg1] "{rdi}" (0)
|
||||
\\ : "rcx", "r11", "memory"
|
||||
\\ );
|
||||
\\ unreachable;
|
||||
\\}
|
||||
,
|
||||
\\What is up? This is a longer message that will force the data to be relocated in virtual address space.
|
||||
\\What is up? This is a longer message that will force the data to be relocated in virtual address space.
|
||||
\\
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -27,9 +27,8 @@ pub fn addCases(ctx: *TestContext) !void {
|
||||
\\ %0 = call(@notafunc, [])
|
||||
\\})
|
||||
\\@0 = str("_start")
|
||||
\\@1 = ref(@0)
|
||||
\\@2 = export(@1, @start)
|
||||
, &[_][]const u8{":5:13: error: use of undeclared identifier 'notafunc'"});
|
||||
\\@1 = export(@0, "start")
|
||||
, &[_][]const u8{":5:13: error: decl 'notafunc' not found"});
|
||||
|
||||
// TODO: this error should occur at the call site, not the fntype decl
|
||||
ctx.addZIRError("call naked function", linux_x64,
|
||||
@ -41,8 +40,7 @@ pub fn addCases(ctx: *TestContext) !void {
|
||||
\\ %0 = call(@s, [])
|
||||
\\})
|
||||
\\@0 = str("_start")
|
||||
\\@1 = ref(@0)
|
||||
\\@2 = export(@1, @start)
|
||||
\\@1 = export(@0, "start")
|
||||
, &[_][]const u8{":4:9: error: unable to call function with naked calling convention"});
|
||||
|
||||
// TODO: re-enable these tests.
|
||||
|
||||
@ -14,23 +14,21 @@ pub fn addCases(ctx: *TestContext) void {
|
||||
\\@fnty = fntype([], @void, cc=C)
|
||||
\\
|
||||
\\@9 = str("entry")
|
||||
\\@10 = ref(@9)
|
||||
\\@11 = export(@10, @entry)
|
||||
\\@11 = export(@9, "entry")
|
||||
\\
|
||||
\\@entry = fn(@fnty, {
|
||||
\\ %11 = return()
|
||||
\\ %11 = returnvoid()
|
||||
\\})
|
||||
,
|
||||
\\@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()
|
||||
\\@9 = declref("9$0")
|
||||
\\@9$0 = str("entry")
|
||||
\\@unnamed$4 = str("entry")
|
||||
\\@unnamed$5 = export(@unnamed$4, "entry")
|
||||
\\@unnamed$6 = fntype([], @void, cc=C)
|
||||
\\@entry = fn(@unnamed$6, {
|
||||
\\ %0 = returnvoid()
|
||||
\\})
|
||||
\\
|
||||
);
|
||||
@ -45,11 +43,10 @@ pub fn addCases(ctx: *TestContext) void {
|
||||
\\
|
||||
\\@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)
|
||||
\\ %eptr0 = elemptr(%a, @0)
|
||||
\\ %eptr1 = elemptr(%a, @1)
|
||||
\\ %eptr2 = elemptr(%a, @2)
|
||||
\\ %eptr3 = elemptr(%a, @3)
|
||||
\\ %v0 = deref(%eptr0)
|
||||
\\ %v1 = deref(%eptr1)
|
||||
\\ %v2 = deref(%eptr2)
|
||||
@ -61,15 +58,14 @@ pub fn addCases(ctx: *TestContext) void {
|
||||
\\ %expected = int(69)
|
||||
\\ %ok = cmp(%result, eq, %expected)
|
||||
\\ %10 = condbr(%ok, {
|
||||
\\ %11 = return()
|
||||
\\ %11 = returnvoid()
|
||||
\\ }, {
|
||||
\\ %12 = breakpoint()
|
||||
\\ })
|
||||
\\})
|
||||
\\
|
||||
\\@9 = str("entry")
|
||||
\\@10 = ref(@9)
|
||||
\\@11 = export(@10, @entry)
|
||||
\\@11 = export(@9, "entry")
|
||||
,
|
||||
\\@void = primitive(void)
|
||||
\\@fnty = fntype([], @void, cc=C)
|
||||
@ -77,65 +73,62 @@ pub fn addCases(ctx: *TestContext) void {
|
||||
\\@1 = int(1)
|
||||
\\@2 = int(2)
|
||||
\\@3 = int(3)
|
||||
\\@unnamed$7 = fntype([], @void, cc=C)
|
||||
\\@entry = fn(@unnamed$7, {
|
||||
\\ %0 = return()
|
||||
\\@unnamed$6 = fntype([], @void, cc=C)
|
||||
\\@entry = fn(@unnamed$6, {
|
||||
\\ %0 = returnvoid()
|
||||
\\})
|
||||
\\@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)
|
||||
\\@entry$1 = str("2\x08\x01\n")
|
||||
\\@9 = declref("9$0")
|
||||
\\@9$0 = str("entry")
|
||||
\\@unnamed$11 = str("entry")
|
||||
\\@unnamed$12 = export(@unnamed$11, "entry")
|
||||
\\
|
||||
);
|
||||
|
||||
{
|
||||
var case = ctx.addZIRMulti("reference cycle with compile error in the cycle", linux_x64);
|
||||
var case = ctx.addObjZIR("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)
|
||||
\\@11 = export(@9, "entry")
|
||||
\\
|
||||
\\@entry = fn(@fnty, {
|
||||
\\ %0 = call(@a, [])
|
||||
\\ %1 = return()
|
||||
\\ %1 = returnvoid()
|
||||
\\})
|
||||
\\
|
||||
\\@a = fn(@fnty, {
|
||||
\\ %0 = call(@b, [])
|
||||
\\ %1 = return()
|
||||
\\ %1 = returnvoid()
|
||||
\\})
|
||||
\\
|
||||
\\@b = fn(@fnty, {
|
||||
\\ %0 = call(@a, [])
|
||||
\\ %1 = return()
|
||||
\\ %1 = returnvoid()
|
||||
\\})
|
||||
,
|
||||
\\@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, {
|
||||
\\@9 = declref("9$0")
|
||||
\\@9$0 = str("entry")
|
||||
\\@unnamed$4 = str("entry")
|
||||
\\@unnamed$5 = export(@unnamed$4, "entry")
|
||||
\\@unnamed$6 = fntype([], @void, cc=C)
|
||||
\\@entry = fn(@unnamed$6, {
|
||||
\\ %0 = call(@a, [], modifier=auto)
|
||||
\\ %1 = return()
|
||||
\\ %1 = returnvoid()
|
||||
\\})
|
||||
\\@unnamed$17 = fntype([], @void, cc=C)
|
||||
\\@a = fn(@unnamed$17, {
|
||||
\\@unnamed$8 = fntype([], @void, cc=C)
|
||||
\\@a = fn(@unnamed$8, {
|
||||
\\ %0 = call(@b, [], modifier=auto)
|
||||
\\ %1 = return()
|
||||
\\ %1 = returnvoid()
|
||||
\\})
|
||||
\\@unnamed$22 = fntype([], @void, cc=C)
|
||||
\\@b = fn(@unnamed$22, {
|
||||
\\@unnamed$10 = fntype([], @void, cc=C)
|
||||
\\@b = fn(@unnamed$10, {
|
||||
\\ %0 = call(@a, [], modifier=auto)
|
||||
\\ %1 = return()
|
||||
\\ %1 = returnvoid()
|
||||
\\})
|
||||
\\
|
||||
);
|
||||
@ -145,27 +138,26 @@ pub fn addCases(ctx: *TestContext) void {
|
||||
\\@fnty = fntype([], @void, cc=C)
|
||||
\\
|
||||
\\@9 = str("entry")
|
||||
\\@10 = ref(@9)
|
||||
\\@11 = export(@10, @entry)
|
||||
\\@11 = export(@9, "entry")
|
||||
\\
|
||||
\\@entry = fn(@fnty, {
|
||||
\\ %0 = call(@a, [])
|
||||
\\ %1 = return()
|
||||
\\ %1 = returnvoid()
|
||||
\\})
|
||||
\\
|
||||
\\@a = fn(@fnty, {
|
||||
\\ %0 = call(@b, [])
|
||||
\\ %1 = return()
|
||||
\\ %1 = returnvoid()
|
||||
\\})
|
||||
\\
|
||||
\\@b = fn(@fnty, {
|
||||
\\ %9 = compileerror("message")
|
||||
\\ %0 = call(@a, [])
|
||||
\\ %1 = return()
|
||||
\\ %1 = returnvoid()
|
||||
\\})
|
||||
,
|
||||
&[_][]const u8{
|
||||
":19:21: error: message",
|
||||
":18:21: error: message",
|
||||
},
|
||||
);
|
||||
// Now we remove the call to `a`. `a` and `b` form a cycle, but no entry points are
|
||||
@ -176,34 +168,32 @@ pub fn addCases(ctx: *TestContext) void {
|
||||
\\@fnty = fntype([], @void, cc=C)
|
||||
\\
|
||||
\\@9 = str("entry")
|
||||
\\@10 = ref(@9)
|
||||
\\@11 = export(@10, @entry)
|
||||
\\@11 = export(@9, "entry")
|
||||
\\
|
||||
\\@entry = fn(@fnty, {
|
||||
\\ %1 = return()
|
||||
\\ %0 = returnvoid()
|
||||
\\})
|
||||
\\
|
||||
\\@a = fn(@fnty, {
|
||||
\\ %0 = call(@b, [])
|
||||
\\ %1 = return()
|
||||
\\ %1 = returnvoid()
|
||||
\\})
|
||||
\\
|
||||
\\@b = fn(@fnty, {
|
||||
\\ %9 = compileerror("message")
|
||||
\\ %0 = call(@a, [])
|
||||
\\ %1 = return()
|
||||
\\ %1 = returnvoid()
|
||||
\\})
|
||||
,
|
||||
\\@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()
|
||||
\\@9 = declref("9$2")
|
||||
\\@9$2 = str("entry")
|
||||
\\@unnamed$4 = str("entry")
|
||||
\\@unnamed$5 = export(@unnamed$4, "entry")
|
||||
\\@unnamed$6 = fntype([], @void, cc=C)
|
||||
\\@entry = fn(@unnamed$6, {
|
||||
\\ %0 = returnvoid()
|
||||
\\})
|
||||
\\
|
||||
);
|
||||
@ -217,272 +207,101 @@ pub fn addCases(ctx: *TestContext) void {
|
||||
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("hello world ZIR",
|
||||
\\@noreturn = primitive(noreturn)
|
||||
\\@void = primitive(void)
|
||||
\\@usize = primitive(usize)
|
||||
\\@0 = int(0)
|
||||
\\@1 = int(1)
|
||||
\\@2 = int(2)
|
||||
\\@3 = int(3)
|
||||
\\
|
||||
\\@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 = str("syscall")
|
||||
\\ %sysoutreg = str("={rax}")
|
||||
\\ %rax = str("{rax}")
|
||||
\\ %rdi = str("{rdi}")
|
||||
\\ %rcx = str("rcx")
|
||||
\\ %rdx = str("{rdx}")
|
||||
\\ %rsi = str("{rsi}")
|
||||
\\ %r11 = str("r11")
|
||||
\\ %memory = str("memory")
|
||||
\\
|
||||
\\ %SYS_write = as(@usize, @1)
|
||||
\\ %STDOUT_FILENO = as(@usize, @1)
|
||||
\\
|
||||
\\ %msg_addr = ptrtoint(@msg)
|
||||
\\
|
||||
\\ %len_name = str("len")
|
||||
\\ %msg_len_ptr = fieldptr(@msg, %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")
|
||||
\\@11 = export(@9, "start")
|
||||
,
|
||||
\\Hello, world!
|
||||
\\
|
||||
);
|
||||
|
||||
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{""},
|
||||
);
|
||||
ctx.addZIRCompareOutput("function call with no args no return value",
|
||||
\\@noreturn = primitive(noreturn)
|
||||
\\@void = primitive(void)
|
||||
\\@usize = primitive(usize)
|
||||
\\@0 = int(0)
|
||||
\\@1 = int(1)
|
||||
\\@2 = int(2)
|
||||
\\@3 = int(3)
|
||||
\\
|
||||
\\@exit0_fnty = fntype([], @noreturn)
|
||||
\\@exit0 = fn(@exit0_fnty, {
|
||||
\\ %SYS_exit_group = int(231)
|
||||
\\ %exit_code = as(@usize, @0)
|
||||
\\
|
||||
\\ %syscall = str("syscall")
|
||||
\\ %sysoutreg = str("={rax}")
|
||||
\\ %rax = str("{rax}")
|
||||
\\ %rdi = str("{rdi}")
|
||||
\\ %rcx = str("rcx")
|
||||
\\ %r11 = str("r11")
|
||||
\\ %memory = str("memory")
|
||||
\\
|
||||
\\ %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")
|
||||
\\@11 = export(@9, "start")
|
||||
, "");
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user