authorgravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2022-10-19 07:56:02-04:00
committergravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2022-10-25 05:11:29-04:00
log4765294ca4bd7dd54207892b199f3053702d9a2a
tree678317de9d228b5d4532805fd7457af240cc0110
parent912b84bbad698d18a6b844f9c05c074d2880e35b

cbe: get enough things working to support basic programs

* Enable advanced start support. * Enable advanced test_runner support. * Zig Language Reference's Hello World now works.

11 files changed, 321 insertions(+), 198 deletions(-)

lib/include/zig.h+6-1
...@@ -14,6 +14,12 @@...@@ -14,6 +14,12 @@
14#define zig_threadlocal zig_threadlocal_unavailable14#define zig_threadlocal zig_threadlocal_unavailable
15#endif15#endif
1616
17#if defined(_MSC_VER)
18#define ZIG_NAKED __declspec(naked)
19#else
20#define ZIG_NAKED __attribute__((naked))
21#endif
22
17#if __GNUC__23#if __GNUC__
18#define ZIG_COLD __attribute__ ((cold))24#define ZIG_COLD __attribute__ ((cold))
19#else25#else
...@@ -165,7 +171,6 @@...@@ -165,7 +171,6 @@
165#include <stdint.h>171#include <stdint.h>
166#include <stddef.h>172#include <stddef.h>
167#include <limits.h>173#include <limits.h>
168#include <math.h>
169174
170#define int128_t __int128175#define int128_t __int128
171#define uint128_t unsigned __int128176#define uint128_t unsigned __int128
lib/std/debug.zig+7-1
...@@ -1222,7 +1222,13 @@ pub const DebugInfo = struct {...@@ -1222,7 +1222,13 @@ pub const DebugInfo = struct {
1222 }1222 }
12231223
1224 pub fn getModuleForAddress(self: *DebugInfo, address: usize) !*ModuleDebugInfo {1224 pub fn getModuleForAddress(self: *DebugInfo, address: usize) !*ModuleDebugInfo {
1225 if (comptime builtin.target.isDarwin()) {1225 if (builtin.zig_backend == .stage2_c) {
1226 return @as(error{
1227 InvalidDebugInfo,
1228 MissingDebugInfo,
1229 UnsupportedBackend,
1230 }, error.UnsupportedBackend);
1231 } else if (comptime builtin.target.isDarwin()) {
1226 return self.lookupModuleDyld(address);1232 return self.lookupModuleDyld(address);
1227 } else if (native_os == .windows) {1233 } else if (native_os == .windows) {
1228 return self.lookupModuleWin32(address);1234 return self.lookupModuleWin32(address);
lib/std/os/linux/x86_64.zig+12-5
...@@ -108,11 +108,18 @@ pub extern fn clone(func: CloneFn, stack: usize, flags: usize, arg: usize, ptid:...@@ -108,11 +108,18 @@ pub extern fn clone(func: CloneFn, stack: usize, flags: usize, arg: usize, ptid:
108pub const restore = restore_rt;108pub const restore = restore_rt;
109109
110pub fn restore_rt() callconv(.Naked) void {110pub fn restore_rt() callconv(.Naked) void {
111 return asm volatile ("syscall"111 switch (@import("builtin").zig_backend) {
112 :112 .stage2_c => return asm volatile (std.fmt.comptimePrint(
113 : [number] "{rax}" (@enumToInt(SYS.rt_sigreturn)),113 \\ movl ${d}, %%eax
114 : "rcx", "r11", "memory"114 \\ syscall
115 );115 \\ retq
116 , .{@enumToInt(SYS.rt_sigreturn)}) ::: "rcx", "r11", "memory"),
117 else => return asm volatile ("syscall"
118 :
119 : [number] "{rax}" (@enumToInt(SYS.rt_sigreturn)),
120 : "rcx", "r11", "memory"
121 ),
122 }
116}123}
117124
118pub const mode_t = usize;125pub const mode_t = usize;
lib/std/start.zig+86-72
...@@ -23,7 +23,6 @@ comptime {...@@ -23,7 +23,6 @@ comptime {
23 // Until then, we have simplified logic here for self-hosted. TODO remove this once23 // Until then, we have simplified logic here for self-hosted. TODO remove this once
24 // self-hosted is capable enough to handle all of the real start.zig logic.24 // self-hosted is capable enough to handle all of the real start.zig logic.
25 if (builtin.zig_backend == .stage2_wasm or25 if (builtin.zig_backend == .stage2_wasm or
26 builtin.zig_backend == .stage2_c or
27 builtin.zig_backend == .stage2_x86_64 or26 builtin.zig_backend == .stage2_x86_64 or
28 builtin.zig_backend == .stage2_x86 or27 builtin.zig_backend == .stage2_x86 or
29 builtin.zig_backend == .stage2_aarch64 or28 builtin.zig_backend == .stage2_aarch64 or
...@@ -265,75 +264,90 @@ fn EfiMain(handle: uefi.Handle, system_table: *uefi.tables.SystemTable) callconv...@@ -265,75 +264,90 @@ fn EfiMain(handle: uefi.Handle, system_table: *uefi.tables.SystemTable) callconv
265}264}
266265
267fn _start() callconv(.Naked) noreturn {266fn _start() callconv(.Naked) noreturn {
268 switch (native_arch) {267 switch (builtin.zig_backend) {
269 .x86_64 => {268 .stage2_c => switch (native_arch) {
270 argc_argv_ptr = asm volatile (269 .x86_64 => {
271 \\ xor %%rbp, %%rbp270 @export(argc_argv_ptr, .{ .name = "argc_argv_ptr" });
272 : [argc] "={rsp}" (-> [*]usize),271 @export(posixCallMainAndExit, .{ .name = "_posixCallMainAndExit" });
273 );272 asm volatile (
274 },273 \\ xor %%rbp, %%rbp
275 .i386 => {274 \\ mov %%rsp, argc_argv_ptr
276 argc_argv_ptr = asm volatile (275 \\ call _posixCallMainAndExit
277 \\ xor %%ebp, %%ebp276 );
278 : [argc] "={esp}" (-> [*]usize),277 unreachable;
279 );278 },
280 },279 else => @compileError("unsupported arch"),
281 .aarch64, .aarch64_be, .arm, .armeb, .thumb => {
282 argc_argv_ptr = asm volatile (
283 \\ mov fp, #0
284 \\ mov lr, #0
285 : [argc] "={sp}" (-> [*]usize),
286 );
287 },
288 .riscv64 => {
289 argc_argv_ptr = asm volatile (
290 \\ li s0, 0
291 \\ li ra, 0
292 : [argc] "={sp}" (-> [*]usize),
293 );
294 },
295 .mips, .mipsel => {
296 // The lr is already zeroed on entry, as specified by the ABI.
297 argc_argv_ptr = asm volatile (
298 \\ move $fp, $0
299 : [argc] "={sp}" (-> [*]usize),
300 );
301 },
302 .powerpc => {
303 // Setup the initial stack frame and clear the back chain pointer.
304 argc_argv_ptr = asm volatile (
305 \\ mr 4, 1
306 \\ li 0, 0
307 \\ stwu 1,-16(1)
308 \\ stw 0, 0(1)
309 \\ mtlr 0
310 : [argc] "={r4}" (-> [*]usize),
311 :
312 : "r0"
313 );
314 },
315 .powerpc64le => {
316 // Setup the initial stack frame and clear the back chain pointer.
317 // TODO: Support powerpc64 (big endian) on ELFv2.
318 argc_argv_ptr = asm volatile (
319 \\ mr 4, 1
320 \\ li 0, 0
321 \\ stdu 0, -32(1)
322 \\ mtlr 0
323 : [argc] "={r4}" (-> [*]usize),
324 :
325 : "r0"
326 );
327 },280 },
328 .sparc64 => {281 else => switch (native_arch) {
329 // argc is stored after a register window (16 registers) plus stack bias282 .x86_64 => {
330 argc_argv_ptr = asm (283 argc_argv_ptr = asm volatile (
331 \\ mov %%g0, %%i6284 \\ xor %%rbp, %%rbp
332 \\ add %%o6, 2175, %[argc]285 : [argc] "={rsp}" (-> [*]usize),
333 : [argc] "=r" (-> [*]usize),286 );
334 );287 },
288 .i386 => {
289 argc_argv_ptr = asm volatile (
290 \\ xor %%ebp, %%ebp
291 : [argc] "={esp}" (-> [*]usize),
292 );
293 },
294 .aarch64, .aarch64_be, .arm, .armeb, .thumb => {
295 argc_argv_ptr = asm volatile (
296 \\ mov fp, #0
297 \\ mov lr, #0
298 : [argc] "={sp}" (-> [*]usize),
299 );
300 },
301 .riscv64 => {
302 argc_argv_ptr = asm volatile (
303 \\ li s0, 0
304 \\ li ra, 0
305 : [argc] "={sp}" (-> [*]usize),
306 );
307 },
308 .mips, .mipsel => {
309 // The lr is already zeroed on entry, as specified by the ABI.
310 argc_argv_ptr = asm volatile (
311 \\ move $fp, $0
312 : [argc] "={sp}" (-> [*]usize),
313 );
314 },
315 .powerpc => {
316 // Setup the initial stack frame and clear the back chain pointer.
317 argc_argv_ptr = asm volatile (
318 \\ mr 4, 1
319 \\ li 0, 0
320 \\ stwu 1,-16(1)
321 \\ stw 0, 0(1)
322 \\ mtlr 0
323 : [argc] "={r4}" (-> [*]usize),
324 :
325 : "r0"
326 );
327 },
328 .powerpc64le => {
329 // Setup the initial stack frame and clear the back chain pointer.
330 // TODO: Support powerpc64 (big endian) on ELFv2.
331 argc_argv_ptr = asm volatile (
332 \\ mr 4, 1
333 \\ li 0, 0
334 \\ stdu 0, -32(1)
335 \\ mtlr 0
336 : [argc] "={r4}" (-> [*]usize),
337 :
338 : "r0"
339 );
340 },
341 .sparc64 => {
342 // argc is stored after a register window (16 registers) plus stack bias
343 argc_argv_ptr = asm (
344 \\ mov %%g0, %%i6
345 \\ add %%o6, 2175, %[argc]
346 : [argc] "=r" (-> [*]usize),
347 );
348 },
349 else => @compileError("unsupported arch"),
335 },350 },
336 else => @compileError("unsupported arch"),
337 }351 }
338 // If LLVM inlines stack variables into _start, they will overwrite352 // If LLVM inlines stack variables into _start, they will overwrite
339 // the command line argument data.353 // the command line argument data.
...@@ -363,7 +377,7 @@ fn wWinMainCRTStartup() callconv(std.os.windows.WINAPI) noreturn {...@@ -363,7 +377,7 @@ fn wWinMainCRTStartup() callconv(std.os.windows.WINAPI) noreturn {
363 std.os.windows.kernel32.ExitProcess(@bitCast(std.os.windows.UINT, result));377 std.os.windows.kernel32.ExitProcess(@bitCast(std.os.windows.UINT, result));
364}378}
365379
366fn posixCallMainAndExit() noreturn {380fn posixCallMainAndExit() callconv(.C) noreturn {
367 @setAlignStack(16);381 @setAlignStack(16);
368382
369 const argc = argc_argv_ptr[0];383 const argc = argc_argv_ptr[0];
...@@ -462,7 +476,7 @@ fn callMainWithArgs(argc: usize, argv: [*][*:0]u8, envp: [][*:0]u8) u8 {...@@ -462,7 +476,7 @@ fn callMainWithArgs(argc: usize, argv: [*][*:0]u8, envp: [][*:0]u8) u8 {
462 return initEventLoopAndCallMain();476 return initEventLoopAndCallMain();
463}477}
464478
465fn main(c_argc: i32, c_argv: [*][*:0]u8, c_envp: [*:null]?[*:0]u8) callconv(.C) i32 {479fn main(c_argc: c_int, c_argv: [*c][*c]u8, c_envp: [*c][*c]u8) callconv(.C) c_int {
466 var env_count: usize = 0;480 var env_count: usize = 0;
467 while (c_envp[env_count] != null) : (env_count += 1) {}481 while (c_envp[env_count] != null) : (env_count += 1) {}
468 const envp = @ptrCast([*][*:0]u8, c_envp)[0..env_count];482 const envp = @ptrCast([*][*:0]u8, c_envp)[0..env_count];
...@@ -474,10 +488,10 @@ fn main(c_argc: i32, c_argv: [*][*:0]u8, c_envp: [*:null]?[*:0]u8) callconv(.C)...@@ -474,10 +488,10 @@ fn main(c_argc: i32, c_argv: [*][*:0]u8, c_envp: [*:null]?[*:0]u8) callconv(.C)
474 expandStackSize(phdrs);488 expandStackSize(phdrs);
475 }489 }
476490
477 return @call(.{ .modifier = .always_inline }, callMainWithArgs, .{ @intCast(usize, c_argc), c_argv, envp });491 return @call(.{ .modifier = .always_inline }, callMainWithArgs, .{ @intCast(usize, c_argc), @ptrCast([*][*:0]u8, c_argv), envp });
478}492}
479493
480fn mainWithoutEnv(c_argc: i32, c_argv: [*][*:0]u8) callconv(.C) usize {494fn mainWithoutEnv(c_argc: c_int, c_argv: [*c][*c]u8) callconv(.C) c_int {
481 std.os.argv = c_argv[0..@intCast(usize, c_argc)];495 std.os.argv = c_argv[0..@intCast(usize, c_argc)];
482 return @call(.{ .modifier = .always_inline }, callMain, .{});496 return @call(.{ .modifier = .always_inline }, callMain, .{});
483}497}
lib/test_runner.zig+2-1
...@@ -8,7 +8,8 @@ var log_err_count: usize = 0;...@@ -8,7 +8,8 @@ var log_err_count: usize = 0;
88
9pub fn main() void {9pub fn main() void {
10 if (builtin.zig_backend != .stage1 and10 if (builtin.zig_backend != .stage1 and
11 (builtin.zig_backend != .stage2_llvm or builtin.cpu.arch == .wasm32))11 (builtin.zig_backend != .stage2_llvm or builtin.cpu.arch == .wasm32) and
12 builtin.zig_backend != .stage2_c)
12 {13 {
13 return main2() catch @panic("test failure");14 return main2() catch @panic("test failure");
14 }15 }
src/codegen/c.zig+204-112
...@@ -34,8 +34,8 @@ pub const CValue = union(enum) {...@@ -34,8 +34,8 @@ pub const CValue = union(enum) {
34 /// By-value34 /// By-value
35 decl: Decl.Index,35 decl: Decl.Index,
36 decl_ref: Decl.Index,36 decl_ref: Decl.Index,
37 /// An undefined (void *) pointer (cannot be dereferenced)37 /// An undefined value (cannot be dereferenced)
38 undefined_ptr: Type,38 undef: Type,
39 /// Render the slice as an identifier (using fmtIdent)39 /// Render the slice as an identifier (using fmtIdent)
40 identifier: []const u8,40 identifier: []const u8,
41 /// Render these bytes literally.41 /// Render these bytes literally.
...@@ -342,8 +342,9 @@ pub const Function = struct {...@@ -342,8 +342,9 @@ pub const Function = struct {
342 const float_bits = float_ty.floatBits(target);342 const float_bits = float_ty.floatBits(target);
343 const is_longdouble = float_bits == CType.longdouble.sizeInBits(target);343 const is_longdouble = float_bits == CType.longdouble.sizeInBits(target);
344 const writer = f.object.writer();344 const writer = f.object.writer();
345 if (!is_longdouble and float_bits == 80) {345 try writer.writeAll("__");
346 try writer.writeAll("__");346 if (is_longdouble or float_bits != 80) {
347 try writer.writeAll("builtin_");
347 }348 }
348 try writer.writeAll(fn_name);349 try writer.writeAll(fn_name);
349 if (is_longdouble) {350 if (is_longdouble) {
...@@ -410,10 +411,17 @@ pub const DeclGen = struct {...@@ -410,10 +411,17 @@ pub const DeclGen = struct {
410 const decl = dg.module.declPtr(decl_index);411 const decl = dg.module.declPtr(decl_index);
411 assert(decl.has_tv);412 assert(decl.has_tv);
412413
414 // Render an undefined pointer if we have a pointer to a zero-bit or comptime type.
413 if (ty.isPtrAtRuntime() and !decl.ty.isFnOrHasRuntimeBits()) {415 if (ty.isPtrAtRuntime() and !decl.ty.isFnOrHasRuntimeBits()) {
414 return dg.writeCValue(writer, CValue{ .undefined_ptr = ty });416 return dg.writeCValue(writer, CValue{ .undef = ty });
415 }417 }
416418
419 // Chase function values in order to be able to reference the original function.
420 inline for (.{ .function, .extern_fn }) |tag|
421 if (decl.val.castTag(tag)) |func|
422 if (func.data.owner_decl != decl_index)
423 return dg.renderDeclValue(writer, ty, val, func.data.owner_decl);
424
417 if (ty.isSlice()) {425 if (ty.isSlice()) {
418 try writer.writeByte('(');426 try writer.writeByte('(');
419 try dg.renderTypecast(writer, ty);427 try dg.renderTypecast(writer, ty);
...@@ -588,9 +596,9 @@ pub const DeclGen = struct {...@@ -588,9 +596,9 @@ pub const DeclGen = struct {
588 try writer.writeByte('(');596 try writer.writeByte('(');
589 try dg.renderTypecast(writer, ty);597 try dg.renderTypecast(writer, ty);
590 try writer.writeAll("){ .payload = ");598 try writer.writeAll("){ .payload = ");
591 try dg.renderValue(writer, Type.bool, val, location);
592 try writer.writeAll(", .is_null = ");
593 try dg.renderValue(writer, payload_ty, val, location);599 try dg.renderValue(writer, payload_ty, val, location);
600 try writer.writeAll(", .is_null = ");
601 try dg.renderValue(writer, Type.bool, val, location);
594 return writer.writeAll(" }");602 return writer.writeAll(" }");
595 },603 },
596 .Struct => {604 .Struct => {
...@@ -635,7 +643,7 @@ pub const DeclGen = struct {...@@ -635,7 +643,7 @@ pub const DeclGen = struct {
635 try writer.writeAll("){ .payload = ");643 try writer.writeAll("){ .payload = ");
636 try dg.renderValue(writer, ty.errorUnionPayload(), val, location);644 try dg.renderValue(writer, ty.errorUnionPayload(), val, location);
637 return writer.print(", .error = {x} }}", .{645 return writer.print(", .error = {x} }}", .{
638 try dg.fmtIntLiteral(ty.errorUnionSet(), Value.undef),646 try dg.fmtIntLiteral(ty.errorUnionSet(), val),
639 });647 });
640 },648 },
641 .Array => {649 .Array => {
...@@ -844,13 +852,13 @@ pub const DeclGen = struct {...@@ -844,13 +852,13 @@ pub const DeclGen = struct {
844 }852 }
845 },853 },
846 .ErrorUnion => {854 .ErrorUnion => {
847 const error_type = ty.errorUnionSet();855 const error_ty = ty.errorUnionSet();
848 const payload_type = ty.errorUnionPayload();856 const payload_ty = ty.errorUnionPayload();
849857
850 if (!payload_type.hasRuntimeBits()) {858 if (!payload_ty.hasRuntimeBits()) {
851 // We use the error type directly as the type.859 // We use the error type directly as the type.
852 const err_val = if (val.errorUnionIsPayload()) Value.initTag(.zero) else val;860 const err_val = if (val.errorUnionIsPayload()) Value.initTag(.zero) else val;
853 return dg.renderValue(writer, error_type, err_val, location);861 return dg.renderValue(writer, error_ty, err_val, location);
854 }862 }
855863
856 try writer.writeByte('(');864 try writer.writeByte('(');
...@@ -859,11 +867,15 @@ pub const DeclGen = struct {...@@ -859,11 +867,15 @@ pub const DeclGen = struct {
859 if (val.castTag(.eu_payload)) |pl| {867 if (val.castTag(.eu_payload)) |pl| {
860 const payload_val = pl.data;868 const payload_val = pl.data;
861 try writer.writeAll(" .payload = ");869 try writer.writeAll(" .payload = ");
862 try dg.renderValue(writer, payload_type, payload_val, location);870 try dg.renderValue(writer, payload_ty, payload_val, location);
863 try writer.writeAll(", .error = 0 }");871 try writer.print(", .error = {} }}", .{
872 try dg.fmtIntLiteral(error_ty, Value.zero),
873 });
864 } else {874 } else {
865 try writer.writeAll(" .error = ");875 try writer.writeAll(" .payload = ");
866 try dg.renderValue(writer, error_type, val, location);876 try dg.renderValue(writer, payload_ty, Value.undef, location);
877 try writer.writeAll(", .error = ");
878 try dg.renderValue(writer, error_ty, val, location);
867 try writer.writeAll(" }");879 try writer.writeAll(" }");
868 }880 }
869 },881 },
...@@ -987,13 +999,16 @@ pub const DeclGen = struct {...@@ -987,13 +999,16 @@ pub const DeclGen = struct {
987 if (!is_global) {999 if (!is_global) {
988 try w.writeAll("static ");1000 try w.writeAll("static ");
989 }1001 }
1002 const fn_info = dg.decl.ty.fnInfo();
1003 if (fn_info.cc == .Naked) {
1004 try w.writeAll("ZIG_NAKED ");
1005 }
990 if (dg.decl.val.castTag(.function)) |func_payload| {1006 if (dg.decl.val.castTag(.function)) |func_payload| {
991 const func: *Module.Fn = func_payload.data;1007 const func: *Module.Fn = func_payload.data;
992 if (func.is_cold) {1008 if (func.is_cold) {
993 try w.writeAll("ZIG_COLD ");1009 try w.writeAll("ZIG_COLD ");
994 }1010 }
995 }1011 }
996 const fn_info = dg.decl.ty.fnInfo();
997 if (fn_info.return_type.hasRuntimeBits()) {1012 if (fn_info.return_type.hasRuntimeBits()) {
998 try dg.renderType(w, fn_info.return_type);1013 try dg.renderType(w, fn_info.return_type);
999 } else if (fn_info.return_type.isError()) {1014 } else if (fn_info.return_type.isError()) {
...@@ -1007,21 +1022,21 @@ pub const DeclGen = struct {...@@ -1007,21 +1022,21 @@ pub const DeclGen = struct {
1007 try dg.renderDeclName(w, dg.decl_index);1022 try dg.renderDeclName(w, dg.decl_index);
1008 try w.writeByte('(');1023 try w.writeByte('(');
10091024
1010 var params_written: usize = 0;1025 var index: usize = 0;
1011 for (fn_info.param_types) |param_type, index| {1026 for (fn_info.param_types) |param_type| {
1012 if (!param_type.hasRuntimeBitsIgnoreComptime()) continue;1027 if (!param_type.hasRuntimeBitsIgnoreComptime()) continue;
1013 if (params_written > 0) {1028 if (index > 0) {
1014 try w.writeAll(", ");1029 try w.writeAll(", ");
1015 }1030 }
1016 const name = CValue{ .arg = index };1031 const name = CValue{ .arg = index };
1017 try dg.renderTypeAndName(w, param_type, name, .Mut, 0);1032 try dg.renderTypeAndName(w, param_type, name, .Mut, 0);
1018 params_written += 1;1033 index += 1;
1019 }1034 }
10201035
1021 if (fn_info.is_var_args) {1036 if (fn_info.is_var_args) {
1022 if (params_written != 0) try w.writeAll(", ");1037 if (index > 0) try w.writeAll(", ");
1023 try w.writeAll("...");1038 try w.writeAll("...");
1024 } else if (params_written == 0) {1039 } else if (index == 0) {
1025 try w.writeAll("void");1040 try w.writeAll("void");
1026 }1041 }
1027 try w.writeByte(')');1042 try w.writeByte(')');
...@@ -1307,7 +1322,7 @@ pub const DeclGen = struct {...@@ -1307,7 +1322,7 @@ pub const DeclGen = struct {
13071322
1308 fn renderErrorUnionTypedef(dg: *DeclGen, t: Type) error{ OutOfMemory, AnalysisFail }![]const u8 {1323 fn renderErrorUnionTypedef(dg: *DeclGen, t: Type) error{ OutOfMemory, AnalysisFail }![]const u8 {
1309 const payload_ty = t.errorUnionPayload();1324 const payload_ty = t.errorUnionPayload();
1310 const error_ty = t.errorUnionSet();1325 assert(t.errorUnionSet().tag() == .anyerror);
13111326
1312 var buffer = std.ArrayList(u8).init(dg.typedefs.allocator);1327 var buffer = std.ArrayList(u8).init(dg.typedefs.allocator);
1313 defer buffer.deinit();1328 defer buffer.deinit();
...@@ -1328,15 +1343,7 @@ pub const DeclGen = struct {...@@ -1328,15 +1343,7 @@ pub const DeclGen = struct {
1328 }1343 }
13291344
1330 const name_begin = buffer.items.len;1345 const name_begin = buffer.items.len;
1331 if (error_ty.castTag(.error_set_inferred)) |inf_err_set_payload| {1346 try bw.print("zig_E_{}", .{typeToCIdentifier(payload_ty, dg.module)});
1332 const func = inf_err_set_payload.data.func;
1333 try bw.writeAll("zig_E_");
1334 try dg.renderDeclName(bw, func.owner_decl);
1335 } else {
1336 try bw.print("zig_E_{}_{}", .{
1337 typeToCIdentifier(error_ty, dg.module), typeToCIdentifier(payload_ty, dg.module),
1338 });
1339 }
1340 const name_end = buffer.items.len;1347 const name_end = buffer.items.len;
1341 try bw.writeAll(";\n");1348 try bw.writeAll(";\n");
13421349
...@@ -1505,11 +1512,11 @@ pub const DeclGen = struct {...@@ -1505,11 +1512,11 @@ pub const DeclGen = struct {
1505 },1512 },
1506 .Pointer => {1513 .Pointer => {
1507 if (t.isSlice()) {1514 if (t.isSlice()) {
1508 var slice_ty_pl = Type.Payload.ElemType{1515 var slice_pl = Type.Payload.ElemType{
1509 .base = .{ .tag = if (t.ptrIsMutable()) .mut_slice else .const_slice },1516 .base = .{ .tag = if (t.ptrIsMutable()) .mut_slice else .const_slice },
1510 .data = t.childType(),1517 .data = t.childType(),
1511 };1518 };
1512 const slice_ty = Type.initPayload(&slice_ty_pl.base);1519 const slice_ty = Type.initPayload(&slice_pl.base);
15131520
1514 const name = dg.getTypedefName(slice_ty) orelse1521 const name = dg.getTypedefName(slice_ty) orelse
1515 try dg.renderSliceTypedef(slice_ty);1522 try dg.renderSliceTypedef(slice_ty);
...@@ -1525,7 +1532,9 @@ pub const DeclGen = struct {...@@ -1525,7 +1532,9 @@ pub const DeclGen = struct {
1525 }1532 }
15261533
1527 const child_ty = t.childType();1534 const child_ty = t.childType();
1528 if (t.isCPtr() and child_ty.eql(Type.u8, dg.module) and dg.decl.val.tag() == .extern_fn) {1535 if (t.isCPtr() and child_ty.eql(Type.u8, dg.module) and
1536 (dg.decl.val.tag() == .extern_fn or std.mem.eql(u8, std.mem.span(dg.decl.name), "main")))
1537 {
1529 // This is a hack, since the c compiler expects a lot of external1538 // This is a hack, since the c compiler expects a lot of external
1530 // library functions to have char pointers in their signatures, but1539 // library functions to have char pointers in their signatures, but
1531 // u8 and i8 produce unsigned char and signed char respectively,1540 // u8 and i8 produce unsigned char and signed char respectively,
...@@ -1543,11 +1552,11 @@ pub const DeclGen = struct {...@@ -1543,11 +1552,11 @@ pub const DeclGen = struct {
1543 return w.writeAll(" *");1552 return w.writeAll(" *");
1544 },1553 },
1545 .Array => {1554 .Array => {
1546 var array_ty_pl = Type.Payload.Array{ .base = .{ .tag = .array }, .data = .{1555 var array_pl = Type.Payload.Array{ .base = .{ .tag = .array }, .data = .{
1547 .len = t.arrayLenIncludingSentinel(),1556 .len = t.arrayLenIncludingSentinel(),
1548 .elem_type = t.childType(),1557 .elem_type = t.childType(),
1549 } };1558 } };
1550 const array_ty = Type.initPayload(&array_ty_pl.base);1559 const array_ty = Type.initPayload(&array_pl.base);
15511560
1552 const name = dg.getTypedefName(array_ty) orelse1561 const name = dg.getTypedefName(array_ty) orelse
1553 try dg.renderArrayTypedef(array_ty);1562 try dg.renderArrayTypedef(array_ty);
...@@ -1582,8 +1591,13 @@ pub const DeclGen = struct {...@@ -1582,8 +1591,13 @@ pub const DeclGen = struct {
1582 return dg.renderType(w, Type.anyerror);1591 return dg.renderType(w, Type.anyerror);
1583 }1592 }
15841593
1585 const name = dg.getTypedefName(t) orelse1594 var error_union_pl = Type.Payload.ErrorUnion{
1586 try dg.renderErrorUnionTypedef(t);1595 .data = .{ .error_set = Type.anyerror, .payload = payload_ty },
1596 };
1597 const error_union_ty = Type.initPayload(&error_union_pl.base);
1598
1599 const name = dg.getTypedefName(error_union_ty) orelse
1600 try dg.renderErrorUnionTypedef(error_union_ty);
15871601
1588 return w.writeAll(name);1602 return w.writeAll(name);
1589 },1603 },
...@@ -1603,8 +1617,8 @@ pub const DeclGen = struct {...@@ -1603,8 +1617,8 @@ pub const DeclGen = struct {
1603 },1617 },
1604 .Enum => {1618 .Enum => {
1605 // For enums, we simply use the integer tag type.1619 // For enums, we simply use the integer tag type.
1606 var int_tag_ty_buffer: Type.Payload.Bits = undefined;1620 var int_tag_buf: Type.Payload.Bits = undefined;
1607 const int_tag_ty = t.intTagType(&int_tag_ty_buffer);1621 const int_tag_ty = t.intTagType(&int_tag_buf);
16081622
1609 try dg.renderType(w, int_tag_ty);1623 try dg.renderType(w, int_tag_ty);
1610 },1624 },
...@@ -1801,11 +1815,7 @@ pub const DeclGen = struct {...@@ -1801,11 +1815,7 @@ pub const DeclGen = struct {
1801 try w.writeByte('&');1815 try w.writeByte('&');
1802 return dg.renderDeclName(w, decl);1816 return dg.renderDeclName(w, decl);
1803 },1817 },
1804 .undefined_ptr => |ty| {1818 .undef => |ty| return dg.renderValue(w, ty, Value.undef, .Other),
1805 try w.writeAll("((");
1806 try dg.renderTypecast(w, ty);
1807 return w.print("){x})", .{try dg.fmtIntLiteral(Type.usize, Value.undef)});
1808 },
1809 .identifier => |ident| return w.print("{ }", .{fmtIdent(ident)}),1819 .identifier => |ident| return w.print("{ }", .{fmtIdent(ident)}),
1810 .bytes => |bytes| return w.writeAll(bytes),1820 .bytes => |bytes| return w.writeAll(bytes),
1811 }1821 }
...@@ -1824,7 +1834,7 @@ pub const DeclGen = struct {...@@ -1824,7 +1834,7 @@ pub const DeclGen = struct {
1824 return w.writeByte(')');1834 return w.writeByte(')');
1825 },1835 },
1826 .decl_ref => |decl| return dg.renderDeclName(w, decl),1836 .decl_ref => |decl| return dg.renderDeclName(w, decl),
1827 .undefined_ptr => unreachable,1837 .undef => unreachable,
1828 .identifier => |ident| return w.print("(*{ })", .{fmtIdent(ident)}),1838 .identifier => |ident| return w.print("(*{ })", .{fmtIdent(ident)}),
1829 .bytes => |bytes| {1839 .bytes => |bytes| {
1830 try w.writeAll("(*");1840 try w.writeAll("(*");
...@@ -2151,10 +2161,10 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO...@@ -2151,10 +2161,10 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO
21512161
2152 .mul_add => try airMulAdd(f, inst),2162 .mul_add => try airMulAdd(f, inst),
21532163
2154 .add_with_overflow => try airOverflow(f, inst, "addo_"),2164 .add_with_overflow => try airOverflow(f, inst, "addo_", .range),
2155 .sub_with_overflow => try airOverflow(f, inst, "subo_"),2165 .sub_with_overflow => try airOverflow(f, inst, "subo_", .range),
2156 .mul_with_overflow => try airOverflow(f, inst, "mulo_"),2166 .mul_with_overflow => try airOverflow(f, inst, "mulo_", .range),
2157 .shl_with_overflow => try airOverflow(f, inst, "shlo_"),2167 .shl_with_overflow => try airOverflow(f, inst, "shlo_", .bits),
21582168
2159 .min => try airMinMax(f, inst, "<"),2169 .min => try airMinMax(f, inst, "<"),
2160 .max => try airMinMax(f, inst, ">"),2170 .max => try airMinMax(f, inst, ">"),
...@@ -2284,8 +2294,8 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO...@@ -2284,8 +2294,8 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO
2284 .slice_ptr => try airSliceField(f, inst, " = ", ".ptr;\n"),2294 .slice_ptr => try airSliceField(f, inst, " = ", ".ptr;\n"),
2285 .slice_len => try airSliceField(f, inst, " = ", ".len;\n"),2295 .slice_len => try airSliceField(f, inst, " = ", ".len;\n"),
22862296
2287 .ptr_slice_len_ptr => try airSliceField(f, inst, " = &", ".len;\n"),2297 .ptr_slice_len_ptr => try airSliceField(f, inst, " = &", "->len;\n"),
2288 .ptr_slice_ptr_ptr => try airSliceField(f, inst, " = &", ".ptr;\n"),2298 .ptr_slice_ptr_ptr => try airSliceField(f, inst, " = &", "->ptr;\n"),
22892299
2290 .ptr_elem_val => try airPtrElemVal(f, inst),2300 .ptr_elem_val => try airPtrElemVal(f, inst),
2291 .ptr_elem_ptr => try airPtrElemPtr(f, inst),2301 .ptr_elem_ptr => try airPtrElemPtr(f, inst),
...@@ -2459,7 +2469,7 @@ fn airAlloc(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -2459,7 +2469,7 @@ fn airAlloc(f: *Function, inst: Air.Inst.Index) !CValue {
2459 const elem_type = inst_ty.elemType();2469 const elem_type = inst_ty.elemType();
2460 const mutability: Mutability = if (inst_ty.isConstPtr()) .Const else .Mut;2470 const mutability: Mutability = if (inst_ty.isConstPtr()) .Const else .Mut;
2461 if (!elem_type.isFnOrHasRuntimeBitsIgnoreComptime()) {2471 if (!elem_type.isFnOrHasRuntimeBitsIgnoreComptime()) {
2462 return CValue{ .undefined_ptr = inst_ty };2472 return CValue{ .undef = inst_ty };
2463 }2473 }
24642474
2465 const target = f.object.dg.module.getTarget();2475 const target = f.object.dg.module.getTarget();
...@@ -2474,9 +2484,13 @@ fn airRetPtr(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -2474,9 +2484,13 @@ fn airRetPtr(f: *Function, inst: Air.Inst.Index) !CValue {
2474 const writer = f.object.writer();2484 const writer = f.object.writer();
2475 const inst_ty = f.air.typeOfIndex(inst);2485 const inst_ty = f.air.typeOfIndex(inst);
24762486
2487 const elem_ty = inst_ty.elemType();
2488 if (!elem_ty.hasRuntimeBitsIgnoreComptime()) {
2489 return CValue{ .undef = inst_ty };
2490 }
2491
2477 // First line: the variable used as data storage.2492 // First line: the variable used as data storage.
2478 const elem_type = inst_ty.elemType();2493 const local = try f.allocLocal(elem_ty, .Mut);
2479 const local = try f.allocLocal(elem_type, .Mut);
2480 try writer.writeAll(";\n");2494 try writer.writeAll(";\n");
24812495
2482 return CValue{ .local_ref = local.local };2496 return CValue{ .local_ref = local.local };
...@@ -2507,8 +2521,7 @@ fn airLoad(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -2507,8 +2521,7 @@ fn airLoad(f: *Function, inst: Air.Inst.Index) !CValue {
2507 if (is_array) {2521 if (is_array) {
2508 // Insert a memcpy to initialize this array. The source operand is always a pointer2522 // Insert a memcpy to initialize this array. The source operand is always a pointer
2509 // and thus we only need to know size/type information from the local type/dest.2523 // and thus we only need to know size/type information from the local type/dest.
2510 try writer.writeByte(';');2524 try writer.writeAll(";\n");
2511 try f.object.indent_writer.insertNewline();
2512 try writer.writeAll("memcpy(");2525 try writer.writeAll("memcpy(");
2513 try f.writeCValue(writer, local);2526 try f.writeCValue(writer, local);
2514 try writer.writeAll(", ");2527 try writer.writeAll(", ");
...@@ -2535,7 +2548,8 @@ fn airRet(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -2535,7 +2548,8 @@ fn airRet(f: *Function, inst: Air.Inst.Index) !CValue {
2535 try writer.writeAll(";\n");2548 try writer.writeAll(";\n");
2536 } else if (ret_ty.isError()) {2549 } else if (ret_ty.isError()) {
2537 try writer.writeAll("return 0;");2550 try writer.writeAll("return 0;");
2538 } else {2551 } else if (f.object.dg.decl.ty.fnCallingConvention() != .Naked) {
2552 // Not even allowed to return void in a naked function.
2539 try writer.writeAll("return;\n");2553 try writer.writeAll("return;\n");
2540 }2554 }
2541 return CValue.none;2555 return CValue.none;
...@@ -2847,7 +2861,7 @@ fn airSatOp(f: *Function, inst: Air.Inst.Index, fn_op: [*:0]const u8) !CValue {...@@ -2847,7 +2861,7 @@ fn airSatOp(f: *Function, inst: Air.Inst.Index, fn_op: [*:0]const u8) !CValue {
2847 return ret;2861 return ret;
2848}2862}
28492863
2850fn airOverflow(f: *Function, inst: Air.Inst.Index, op_abbrev: [*:0]const u8) !CValue {2864fn airOverflow(f: *Function, inst: Air.Inst.Index, op_abbrev: [*:0]const u8, kind: enum { range, bits }) !CValue {
2851 if (f.liveness.isUnused(inst))2865 if (f.liveness.isUnused(inst))
2852 return CValue.none;2866 return CValue.none;
28532867
...@@ -2879,23 +2893,29 @@ fn airOverflow(f: *Function, inst: Air.Inst.Index, op_abbrev: [*:0]const u8) !CV...@@ -2879,23 +2893,29 @@ fn airOverflow(f: *Function, inst: Air.Inst.Index, op_abbrev: [*:0]const u8) !CV
2879 try w.writeAll(", &");2893 try w.writeAll(", &");
2880 try f.writeCValue(w, ret);2894 try f.writeCValue(w, ret);
2881 try w.writeAll(".field_0, ");2895 try w.writeAll(".field_0, ");
2882 {2896 switch (kind) {
2883 var arena = std.heap.ArenaAllocator.init(f.object.dg.module.gpa);2897 .range => {
2884 defer arena.deinit();2898 var arena = std.heap.ArenaAllocator.init(f.object.dg.module.gpa);
28852899 defer arena.deinit();
2886 const expected_contents = union { u: Value.Payload.U64, i: Value.Payload.I64 };2900
2887 var stack align(@alignOf(expected_contents)) =2901 const expected_contents = union { u: Value.Payload.U64, i: Value.Payload.I64 };
2888 std.heap.stackFallback(@sizeOf(expected_contents), arena.allocator());2902 var stack align(@alignOf(expected_contents)) =
28892903 std.heap.stackFallback(@sizeOf(expected_contents), arena.allocator());
2890 if (int_info.signedness == .signed) {2904
2891 const min_val = try scalar_ty.minInt(stack.get(), target);2905 if (int_info.signedness == .signed) {
2892 try w.print("{}, ", .{try f.fmtIntLiteral(scalar_ty, min_val)});2906 const min_val = try scalar_ty.minInt(stack.get(), target);
2893 }2907 try w.print("{}, ", .{try f.fmtIntLiteral(scalar_ty, min_val)});
2908 }
28942909
2895 const max_val = try scalar_ty.maxInt(stack.get(), target);2910 const max_val = try scalar_ty.maxInt(stack.get(), target);
2896 try w.print("{});", .{try f.fmtIntLiteral(scalar_ty, max_val)});2911 try w.print("{});\n", .{try f.fmtIntLiteral(scalar_ty, max_val)});
2912 },
2913 .bits => {
2914 var bits_pl = Value.Payload.U64{ .base = .{ .tag = .int_u64 }, .data = int_info.bits };
2915 const bits_val = Value.initPayload(&bits_pl.base);
2916 try w.print("{x});\n", .{try f.fmtIntLiteral(Type.u8, bits_val)});
2917 },
2897 }2918 }
2898 try f.object.indent_writer.insertNewline();
2899 return ret;2919 return ret;
2900}2920}
29012921
...@@ -3075,6 +3095,9 @@ fn airCall(...@@ -3075,6 +3095,9 @@ fn airCall(
3075 inst: Air.Inst.Index,3095 inst: Air.Inst.Index,
3076 modifier: std.builtin.CallOptions.Modifier,3096 modifier: std.builtin.CallOptions.Modifier,
3077) !CValue {3097) !CValue {
3098 // Not even allowed to call panic in a naked function.
3099 if (f.object.dg.decl.ty.fnCallingConvention() == .Naked) return .none;
3100
3078 switch (modifier) {3101 switch (modifier) {
3079 .auto => {},3102 .auto => {},
3080 .always_tail => return f.fail("TODO: C backend: call with always_tail attribute", .{}),3103 .always_tail => return f.fail("TODO: C backend: call with always_tail attribute", .{}),
...@@ -3094,10 +3117,10 @@ fn airCall(...@@ -3094,10 +3117,10 @@ fn airCall(
3094 const writer = f.object.writer();3117 const writer = f.object.writer();
30953118
3096 const result_local: CValue = r: {3119 const result_local: CValue = r: {
3097 if (f.liveness.isUnused(inst)) {3120 if (!loweredFnRetTyHasBits(fn_ty)) {
3098 if (loweredFnRetTyHasBits(fn_ty)) {3121 break :r .none;
3099 try writer.print("(void)", .{});3122 } else if (f.liveness.isUnused(inst)) {
3100 }3123 try writer.print("(void)", .{});
3101 break :r .none;3124 break :r .none;
3102 } else {3125 } else {
3103 const local = try f.allocLocal(fn_ty.fnReturnType(), .Const);3126 const local = try f.allocLocal(fn_ty.fnReturnType(), .Const);
...@@ -3107,6 +3130,7 @@ fn airCall(...@@ -3107,6 +3130,7 @@ fn airCall(
3107 };3130 };
31083131
3109 var is_extern = false;3132 var is_extern = false;
3133 var name: [*:0]const u8 = "";
3110 callee: {3134 callee: {
3111 known: {3135 known: {
3112 const fn_decl = fn_decl: {3136 const fn_decl = fn_decl: {
...@@ -3121,6 +3145,7 @@ fn airCall(...@@ -3121,6 +3145,7 @@ fn airCall(
3121 else => break :known,3145 else => break :known,
3122 };3146 };
3123 };3147 };
3148 name = f.object.dg.module.declPtr(fn_decl).name;
3124 try f.object.dg.renderDeclName(writer, fn_decl);3149 try f.object.dg.renderDeclName(writer, fn_decl);
3125 break :callee;3150 break :callee;
3126 }3151 }
...@@ -3137,7 +3162,9 @@ fn airCall(...@@ -3137,7 +3162,9 @@ fn airCall(
3137 if (args_written != 0) {3162 if (args_written != 0) {
3138 try writer.writeAll(", ");3163 try writer.writeAll(", ");
3139 }3164 }
3140 if (is_extern and ty.isCPtr() and ty.childType().tag() == .u8) {3165 if ((is_extern or std.mem.eql(u8, std.mem.span(name), "main")) and
3166 ty.isCPtr() and ty.childType().tag() == .u8)
3167 {
3141 // Corresponds with hack in renderType .Pointer case.3168 // Corresponds with hack in renderType .Pointer case.
3142 try writer.writeAll("(char");3169 try writer.writeAll("(char");
3143 if (ty.isConstPtr()) try writer.writeAll(" const");3170 if (ty.isConstPtr()) try writer.writeAll(" const");
...@@ -3286,15 +3313,27 @@ fn lowerTry(...@@ -3286,15 +3313,27 @@ fn lowerTry(
3286 }3313 }
3287 }3314 }
32883315
3289 const local = try f.allocLocal(result_ty, .Const);3316 const is_array = payload_ty.zigTypeTag() == .Array;
3290 if (operand_is_ptr or isByRef(payload_ty)) {3317 const local = try f.allocLocal(result_ty, if (is_array) .Mut else .Const);
3291 try writer.writeAll(" = &");3318 if (is_array) {
3319 try writer.writeAll(";\n");
3320 try writer.writeAll("memcpy(");
3321 try f.writeCValue(writer, local);
3322 try writer.writeAll(", ");
3292 try f.writeCValue(writer, err_union);3323 try f.writeCValue(writer, err_union);
3293 try writer.writeAll("->payload;\n");3324 try writer.writeAll(".payload, sizeof(");
3325 try f.writeCValue(writer, local);
3326 try writer.writeAll("));\n");
3294 } else {3327 } else {
3295 try writer.writeAll(" = ");3328 if (operand_is_ptr or isByRef(payload_ty)) {
3296 try f.writeCValue(writer, err_union);3329 try writer.writeAll(" = &");
3297 try writer.writeAll(".payload;\n");3330 try f.writeCValue(writer, err_union);
3331 try writer.writeAll("->payload;\n");
3332 } else {
3333 try writer.writeAll(" = ");
3334 try f.writeCValue(writer, err_union);
3335 try writer.writeAll(".payload;\n");
3336 }
3298 }3337 }
3299 return local;3338 return local;
3300}3339}
...@@ -3361,15 +3400,21 @@ fn airBreakpoint(f: *Function) !CValue {...@@ -3361,15 +3400,21 @@ fn airBreakpoint(f: *Function) !CValue {
33613400
3362fn airRetAddr(f: *Function, inst: Air.Inst.Index) !CValue {3401fn airRetAddr(f: *Function, inst: Air.Inst.Index) !CValue {
3363 if (f.liveness.isUnused(inst)) return CValue.none;3402 if (f.liveness.isUnused(inst)) return CValue.none;
3403 const writer = f.object.writer();
3364 const local = try f.allocLocal(Type.usize, .Const);3404 const local = try f.allocLocal(Type.usize, .Const);
3365 try f.object.writer().writeAll(" = zig_return_address();\n");3405 try writer.writeAll(" = (");
3406 try f.renderTypecast(writer, Type.usize);
3407 try writer.writeAll(")zig_return_address();\n");
3366 return local;3408 return local;
3367}3409}
33683410
3369fn airFrameAddress(f: *Function, inst: Air.Inst.Index) !CValue {3411fn airFrameAddress(f: *Function, inst: Air.Inst.Index) !CValue {
3370 if (f.liveness.isUnused(inst)) return CValue.none;3412 if (f.liveness.isUnused(inst)) return CValue.none;
3413 const writer = f.object.writer();
3371 const local = try f.allocLocal(Type.usize, .Const);3414 const local = try f.allocLocal(Type.usize, .Const);
3372 try f.object.writer().writeAll(" = zig_frame_address();\n");3415 try writer.writeAll(" = (");
3416 try f.renderTypecast(writer, Type.usize);
3417 try writer.writeAll(")zig_frame_address();\n");
3373 return local;3418 return local;
3374}3419}
33753420
...@@ -3385,6 +3430,9 @@ fn airFence(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -3385,6 +3430,9 @@ fn airFence(f: *Function, inst: Air.Inst.Index) !CValue {
3385}3430}
33863431
3387fn airUnreach(f: *Function) !CValue {3432fn airUnreach(f: *Function) !CValue {
3433 // Not even allowed to call unreachable in a naked function.
3434 if (f.object.dg.decl.ty.fnCallingConvention() == .Naked) return .none;
3435
3388 try f.object.writer().writeAll("zig_unreachable();\n");3436 try f.object.writer().writeAll("zig_unreachable();\n");
3389 return CValue.none;3437 return CValue.none;
3390}3438}
...@@ -3479,15 +3527,12 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -3479,15 +3527,12 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {
3479 const local = try f.allocLocal(inst_ty, .Mut);3527 const local = try f.allocLocal(inst_ty, .Mut);
3480 if (f.wantSafety()) {3528 if (f.wantSafety()) {
3481 try writer.writeAll(" = ");3529 try writer.writeAll(" = ");
3482 try f.object.dg.renderValue(writer, inst_ty, Value.undef, .Other);3530 try f.writeCValue(writer, .{ .undef = inst_ty });
3483 }3531 }
3484 try writer.writeAll(";\n");3532 try writer.writeAll(";\n");
3485 break :local local;3533 break :local local;
3486 } else .none;3534 } else .none;
34873535
3488 try writer.writeAll("{\n");
3489 f.object.indent_writer.pushIndent();
3490
3491 const output_locals_begin = f.next_local_index;3536 const output_locals_begin = f.next_local_index;
3492 f.next_local_index += outputs.len;3537 f.next_local_index += outputs.len;
3493 const constraints_extra_begin = extra_i;3538 const constraints_extra_begin = extra_i;
...@@ -3510,7 +3555,7 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -3510,7 +3555,7 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {
3510 try writer.writeAll("\")");3555 try writer.writeAll("\")");
3511 if (f.wantSafety()) {3556 if (f.wantSafety()) {
3512 try writer.writeAll(" = ");3557 try writer.writeAll(" = ");
3513 try f.object.dg.renderValue(writer, output_ty, Value.undef, .Other);3558 try f.writeCValue(writer, .{ .undef = output_ty });
3514 }3559 }
3515 try writer.writeAll(";\n");3560 try writer.writeAll(";\n");
3516 } else if (constraint.len < 2 or constraint[0] != '=') {3561 } else if (constraint.len < 2 or constraint[0] != '=') {
...@@ -3605,7 +3650,7 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -3605,7 +3650,7 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {
3605 } else {3650 } else {
3606 const input_val = try f.resolveInst(input);3651 const input_val = try f.resolveInst(input);
3607 try writer.print("{s}(", .{fmtStringLiteral(constraint)});3652 try writer.print("{s}(", .{fmtStringLiteral(constraint)});
3608 try f.writeCValue(writer, if (input_val == .constant) .{3653 try f.writeCValue(writer, if (input_val == .constant) CValue{
3609 .local = input_locals_begin + index,3654 .local = input_locals_begin + index,
3610 } else input_val);3655 } else input_val);
3611 }3656 }
...@@ -3647,9 +3692,6 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -3647,9 +3692,6 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {
3647 }3692 }
3648 }3693 }
36493694
3650 f.object.indent_writer.popIndent();
3651 try writer.writeAll("}\n");
3652
3653 return local;3695 return local;
3654}3696}
36553697
...@@ -3728,7 +3770,7 @@ fn airOptionalPayloadPtr(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -3728,7 +3770,7 @@ fn airOptionalPayloadPtr(f: *Function, inst: Air.Inst.Index) !CValue {
3728 const inst_ty = f.air.typeOfIndex(inst);3770 const inst_ty = f.air.typeOfIndex(inst);
37293771
3730 if (!inst_ty.childType().hasRuntimeBitsIgnoreComptime()) {3772 if (!inst_ty.childType().hasRuntimeBitsIgnoreComptime()) {
3731 return CValue{ .undefined_ptr = inst_ty };3773 return CValue{ .undef = inst_ty };
3732 }3774 }
37333775
3734 if (opt_ty.optionalReprIsPayload()) {3776 if (opt_ty.optionalReprIsPayload()) {
...@@ -3996,7 +4038,9 @@ fn airWrapErrUnionErr(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -3996,7 +4038,9 @@ fn airWrapErrUnionErr(f: *Function, inst: Air.Inst.Index) !CValue {
3996 }4038 }
39974039
3998 const local = try f.allocLocal(err_un_ty, .Const);4040 const local = try f.allocLocal(err_un_ty, .Const);
3999 try writer.writeAll(" = { .error = ");4041 try writer.writeAll(" = { .payload = ");
4042 try f.writeCValue(writer, .{ .undef = payload_ty });
4043 try writer.writeAll(", .error = ");
4000 try f.writeCValue(writer, operand);4044 try f.writeCValue(writer, operand);
4001 try writer.writeAll(" };\n");4045 try writer.writeAll(" };\n");
4002 return local;4046 return local;
...@@ -4059,10 +4103,25 @@ fn airWrapErrUnionPay(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -4059,10 +4103,25 @@ fn airWrapErrUnionPay(f: *Function, inst: Air.Inst.Index) !CValue {
4059 const operand = try f.resolveInst(ty_op.operand);4103 const operand = try f.resolveInst(ty_op.operand);
40604104
4061 const inst_ty = f.air.typeOfIndex(inst);4105 const inst_ty = f.air.typeOfIndex(inst);
4062 const local = try f.allocLocal(inst_ty, .Const);4106 const payload_ty = inst_ty.errorUnionPayload();
4063 try writer.writeAll(" = { .error = 0, .payload = ");4107 const is_array = payload_ty.zigTypeTag() == .Array;
4064 try f.writeCValue(writer, operand);4108 const local = try f.allocLocal(inst_ty, if (is_array) .Mut else .Const);
4065 try writer.writeAll(" };\n");4109 try writer.writeAll(" = { .payload = ");
4110 try f.writeCValue(writer, if (is_array) CValue{ .undef = payload_ty } else operand);
4111 try writer.print(", .error = {} }};\n", .{
4112 try f.fmtIntLiteral(inst_ty.errorUnionSet(), Value.zero),
4113 });
4114
4115 if (is_array) {
4116 try writer.writeAll("memcpy(");
4117 try f.writeCValue(writer, local);
4118 try writer.writeAll(".payload, ");
4119 try f.writeCValue(writer, operand);
4120 try writer.writeAll(", sizeof(");
4121 try f.writeCValue(writer, local);
4122 try writer.writeAll(".payload));\n");
4123 }
4124
4066 return local;4125 return local;
4067}4126}
40684127
...@@ -4114,11 +4173,11 @@ fn airArrayToSlice(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -4114,11 +4173,11 @@ fn airArrayToSlice(f: *Function, inst: Air.Inst.Index) !CValue {
4114 const array_len = f.air.typeOf(ty_op.operand).elemType().arrayLen();4173 const array_len = f.air.typeOf(ty_op.operand).elemType().arrayLen();
41154174
4116 try writer.writeAll(" = { .ptr = ");4175 try writer.writeAll(" = { .ptr = ");
4117 if (operand == .undefined_ptr) {4176 if (operand == .undef) {
4118 // Unfortunately, C does not support any equivalent to4177 // Unfortunately, C does not support any equivalent to
4119 // &(*(void *)p)[0], although LLVM does via GetElementPtr4178 // &(*(void *)p)[0], although LLVM does via GetElementPtr
4120 var buf: Type.SlicePtrFieldTypeBuffer = undefined;4179 var buf: Type.SlicePtrFieldTypeBuffer = undefined;
4121 try f.writeCValue(writer, CValue{ .undefined_ptr = inst_ty.slicePtrFieldType(&buf) });4180 try f.writeCValue(writer, CValue{ .undef = inst_ty.slicePtrFieldType(&buf) });
4122 } else {4181 } else {
4123 try writer.writeAll("&(");4182 try writer.writeAll("&(");
4124 try f.writeCValueDeref(writer, operand);4183 try f.writeCValueDeref(writer, operand);
...@@ -4528,9 +4587,12 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -4528,9 +4587,12 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue {
4528 const ty_pl = f.air.instructions.items(.data)[inst].ty_pl;4587 const ty_pl = f.air.instructions.items(.data)[inst].ty_pl;
4529 const len = @intCast(usize, inst_ty.arrayLen());4588 const len = @intCast(usize, inst_ty.arrayLen());
4530 const elements = @ptrCast([]const Air.Inst.Ref, f.air.extra[ty_pl.payload..][0..len]);4589 const elements = @ptrCast([]const Air.Inst.Ref, f.air.extra[ty_pl.payload..][0..len]);
4590 const mutability: Mutability = for (elements) |element| {
4591 if (f.air.typeOf(element).zigTypeTag() == .Array) break .Mut;
4592 } else .Const;
45314593
4532 const writer = f.object.writer();4594 const writer = f.object.writer();
4533 const local = try f.allocLocal(inst_ty, .Const);4595 const local = try f.allocLocal(inst_ty, mutability);
4534 try writer.writeAll(" = {");4596 try writer.writeAll(" = {");
4535 switch (inst_ty.zigTypeTag()) {4597 switch (inst_ty.zigTypeTag()) {
4536 .Array => {4598 .Array => {
...@@ -4547,6 +4609,7 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -4547,6 +4609,7 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue {
4547 empty = false;4609 empty = false;
4548 }4610 }
4549 if (empty) try writer.print("{}", .{try f.fmtIntLiteral(Type.u8, Value.zero)});4611 if (empty) try writer.print("{}", .{try f.fmtIntLiteral(Type.u8, Value.zero)});
4612 try writer.writeAll("};\n");
4550 },4613 },
4551 .Struct => {4614 .Struct => {
4552 var empty = true;4615 var empty = true;
...@@ -4557,15 +4620,44 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -4557,15 +4620,44 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue {
4557 if (!inst_ty.isTupleOrAnonStruct()) {4620 if (!inst_ty.isTupleOrAnonStruct()) {
4558 try writer.print(".{ } = ", .{fmtIdent(inst_ty.structFieldName(index))});4621 try writer.print(".{ } = ", .{fmtIdent(inst_ty.structFieldName(index))});
4559 }4622 }
4560 try f.writeCValue(writer, try f.resolveInst(element));4623
4624 const element_ty = f.air.typeOf(element);
4625 try f.writeCValue(writer, switch (element_ty.zigTypeTag()) {
4626 .Array => CValue{ .undef = element_ty },
4627 else => try f.resolveInst(element),
4628 });
4561 empty = false;4629 empty = false;
4562 }4630 }
4563 if (empty) try writer.print("{}", .{try f.fmtIntLiteral(Type.u8, Value.zero)});4631 if (empty) try writer.print("{}", .{try f.fmtIntLiteral(Type.u8, Value.zero)});
4632 try writer.writeAll("};\n");
4633
4634 for (elements) |element, index| {
4635 if (inst_ty.structFieldValueComptime(index)) |_| continue;
4636
4637 const element_ty = f.air.typeOf(element);
4638 if (element_ty.zigTypeTag() != .Array) continue;
4639
4640 var field_name_storage: ?[]u8 = null;
4641 defer if (field_name_storage) |storage| f.object.dg.gpa.free(storage);
4642 const field_name = if (inst_ty.isTupleOrAnonStruct()) field_name: {
4643 const name = try std.fmt.allocPrint(f.object.dg.gpa, "field_{d}", .{index});
4644 field_name_storage = name;
4645 break :field_name name;
4646 } else inst_ty.structFieldName(index);
4647
4648 try writer.writeAll(";\n");
4649 try writer.writeAll("memcpy(");
4650 try f.writeCValue(writer, local);
4651 try writer.print(".{ }, ", .{fmtIdent(field_name)});
4652 try f.writeCValue(writer, try f.resolveInst(element));
4653 try writer.writeAll(", sizeof(");
4654 try f.writeCValue(writer, local);
4655 try writer.print(".{ }));\n", .{fmtIdent(field_name)});
4656 }
4564 },4657 },
4565 .Vector => return f.fail("TODO: C backend: implement airAggregateInit for vectors", .{}),4658 .Vector => return f.fail("TODO: C backend: implement airAggregateInit for vectors", .{}),
4566 else => unreachable,4659 else => unreachable,
4567 }4660 }
4568 try writer.writeAll("};\n");
45694661
4570 return local;4662 return local;
4571}4663}
...@@ -4732,8 +4824,8 @@ fn airMulAdd(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -4732,8 +4824,8 @@ fn airMulAdd(f: *Function, inst: Air.Inst.Index) !CValue {
47324824
4733fn toMemoryOrder(order: std.builtin.AtomicOrder) [:0]const u8 {4825fn toMemoryOrder(order: std.builtin.AtomicOrder) [:0]const u8 {
4734 return switch (order) {4826 return switch (order) {
4735 .Unordered => "memory_order_relaxed",4827 // Note: unordered is actually even less atomic than relaxed
4736 .Monotonic => "memory_order_consume",4828 .Unordered, .Monotonic => "memory_order_relaxed",
4737 .Acquire => "memory_order_acquire",4829 .Acquire => "memory_order_acquire",
4738 .Release => "memory_order_release",4830 .Release => "memory_order_release",
4739 .AcqRel => "memory_order_acq_rel",4831 .AcqRel => "memory_order_acq_rel",
src/main.zig+4-1
...@@ -3018,7 +3018,10 @@ fn buildOutputType(...@@ -3018,7 +3018,10 @@ fn buildOutputType(
3018 const c_code_path = try fs.path.join(arena, &[_][]const u8{3018 const c_code_path = try fs.path.join(arena, &[_][]const u8{
3019 c_code_directory.path orelse ".", c_code_loc.basename,3019 c_code_directory.path orelse ".", c_code_loc.basename,
3020 });3020 });
3021 try test_exec_args.appendSlice(&.{ self_exe_path, "run", "-lc", c_code_path });3021 try test_exec_args.append(self_exe_path);
3022 try test_exec_args.append("run");
3023 if (link_libc) try test_exec_args.append("-lc");
3024 try test_exec_args.append(c_code_path);
3022 }3025 }
30233026
3024 const run_or_test = switch (arg_mode) {3027 const run_or_test = switch (arg_mode) {
test/behavior/bugs/3742.zig-1
...@@ -38,6 +38,5 @@ test "fixed" {...@@ -38,6 +38,5 @@ test "fixed" {
38 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;38 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
39 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;39 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
40 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;40 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
41 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
42 ArgSerializer.serializeCommand(GET.init("banana"));41 ArgSerializer.serializeCommand(GET.init("banana"));
43}42}
test/behavior/fn.zig-1
...@@ -272,7 +272,6 @@ test "void parameters" {...@@ -272,7 +272,6 @@ test "void parameters" {
272 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;272 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
273 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;273 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
274274
275 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
276 try voidFun(1, void{}, 2, {});275 try voidFun(1, void{}, 2, {});
277}276}
278fn voidFun(a: i32, b: void, c: i32, d: void) !void {277fn voidFun(a: i32, b: void, c: i32, d: void) !void {
test/behavior/struct.zig-2
...@@ -1163,7 +1163,6 @@ test "for loop over pointers to struct, getting field from struct pointer" {...@@ -1163,7 +1163,6 @@ test "for loop over pointers to struct, getting field from struct pointer" {
11631163
1164test "anon init through error unions and optionals" {1164test "anon init through error unions and optionals" {
1165 if (builtin.zig_backend == .stage1) return error.SkipZigTest;1165 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
1166 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
1167 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO1166 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
1168 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO1167 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1169 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1168 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
...@@ -1234,7 +1233,6 @@ test "anon init through error union" {...@@ -1234,7 +1233,6 @@ test "anon init through error union" {
12341233
1235test "typed init through error unions and optionals" {1234test "typed init through error unions and optionals" {
1236 if (builtin.zig_backend == .stage1) return error.SkipZigTest;1235 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
1237 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
1238 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO1236 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
1239 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO1237 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1240 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1238 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
test/behavior/translate_c_macros.zig-1
...@@ -100,7 +100,6 @@ test "nested comma operator" {...@@ -100,7 +100,6 @@ test "nested comma operator" {
100test "cast functions" {100test "cast functions" {
101 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO101 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
102 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO102 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
103 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
104 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO103 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
105 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO104 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
106105