authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-01-05 13:59:33-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-01-05 17:41:14-07:00
logcd95444e4729761033f35d689a3b6ad6f4630552
treeda260237a3505ef174406590380364c36fbb3160
parent58cfaa5982fc6c216627fb6f2cfd0d0e4e89d92b

stage2: C backend: remove format() hackery

All C backend tests passing now, except for emit-h tests. Next task in the branch is to restore emit-h.

4 files changed, 187 insertions(+), 294 deletions(-)

src/codegen/c.zig+70-61
...@@ -27,42 +27,6 @@ pub const CValue = union(enum) {...@@ -27,42 +27,6 @@ pub const CValue = union(enum) {
27 arg: usize,27 arg: usize,
28 /// By-value28 /// By-value
29 decl: *Decl,29 decl: *Decl,
30
31 pub fn printed(value: CValue, object: *Object) Printed {
32 return .{
33 .value = value,
34 .object = object,
35 };
36 }
37
38 pub const Printed = struct {
39 value: CValue,
40 object: *Object,
41
42 /// TODO this got unwieldly, I want to remove the ability to print this way
43 pub fn format(
44 self: Printed,
45 comptime fmt: []const u8,
46 options: std.fmt.FormatOptions,
47 writer: anytype,
48 ) error{OutOfMemory}!void {
49 if (fmt.len != 0) @compileError("Unknown format string: '" ++ fmt ++ "'");
50 switch (self.value) {
51 .none => unreachable,
52 .local => |i| return std.fmt.format(writer, "t{d}", .{i}),
53 .local_ref => |i| return std.fmt.format(writer, "&t{d}", .{i}),
54 .constant => |inst| {
55 const o = self.object;
56 o.dg.renderValue(writer, inst.ty, inst.value().?) catch |err| switch (err) {
57 error.OutOfMemory => return error.OutOfMemory,
58 error.AnalysisFail => return,
59 };
60 },
61 .arg => |i| return std.fmt.format(writer, "a{d}", .{i}),
62 .decl => |decl| return writer.writeAll(mem.span(decl.name)),
63 }
64 }
65 };
66};30};
6731
68pub const CValueMap = std.AutoHashMap(*Inst, CValue);32pub const CValueMap = std.AutoHashMap(*Inst, CValue);
...@@ -103,6 +67,17 @@ pub const Object = struct {...@@ -103,6 +67,17 @@ pub const Object = struct {
103 try o.code.writer().writeByteNTimes(' ', indent_amt);67 try o.code.writer().writeByteNTimes(' ', indent_amt);
104 }68 }
10569
70 fn writeCValue(o: *Object, writer: Writer, c_value: CValue) !void {
71 switch (c_value) {
72 .none => unreachable,
73 .local => |i| return writer.print("t{d}", .{i}),
74 .local_ref => |i| return writer.print("&t{d}", .{i}),
75 .constant => |inst| return o.dg.renderValue(writer, inst.ty, inst.value().?),
76 .arg => |i| return writer.print("a{d}", .{i}),
77 .decl => |decl| return writer.writeAll(mem.span(decl.name)),
78 }
79 }
80
106 fn renderTypeAndName(81 fn renderTypeAndName(
107 o: *Object,82 o: *Object,
108 writer: Writer,83 writer: Writer,
...@@ -127,7 +102,9 @@ pub const Object = struct {...@@ -127,7 +102,9 @@ pub const Object = struct {
127 .Const => "const ",102 .Const => "const ",
128 .Mut => "",103 .Mut => "",
129 };104 };
130 try writer.print(" {s}{}{s}", .{ const_prefix, name.printed(o), suffix.items });105 try writer.print(" {s}", .{const_prefix});
106 try o.writeCValue(writer, name);
107 try writer.writeAll(suffix.items);
131 }108 }
132};109};
133110
...@@ -353,7 +330,7 @@ pub fn genDecl(o: *Object) !void {...@@ -353,7 +330,7 @@ pub fn genDecl(o: *Object) !void {
353 try writer.writeAll("\n");330 try writer.writeAll("\n");
354 for (instructions) |inst| {331 for (instructions) |inst| {
355 const result_value = switch (inst.tag) {332 const result_value = switch (inst.tag) {
356 .add => try genBinOp(o, inst.castTag(.add).?, "+"),333 .add => try genBinOp(o, inst.castTag(.add).?, " + "),
357 .alloc => try genAlloc(o, inst.castTag(.alloc).?),334 .alloc => try genAlloc(o, inst.castTag(.alloc).?),
358 .arg => genArg(o),335 .arg => genArg(o),
359 .assembly => try genAsm(o, inst.castTag(.assembly).?),336 .assembly => try genAsm(o, inst.castTag(.assembly).?),
...@@ -361,19 +338,19 @@ pub fn genDecl(o: *Object) !void {...@@ -361,19 +338,19 @@ pub fn genDecl(o: *Object) !void {
361 .bitcast => try genBitcast(o, inst.castTag(.bitcast).?),338 .bitcast => try genBitcast(o, inst.castTag(.bitcast).?),
362 .breakpoint => try genBreakpoint(o, inst.castTag(.breakpoint).?),339 .breakpoint => try genBreakpoint(o, inst.castTag(.breakpoint).?),
363 .call => try genCall(o, inst.castTag(.call).?),340 .call => try genCall(o, inst.castTag(.call).?),
364 .cmp_eq => try genBinOp(o, inst.castTag(.cmp_eq).?, "=="),341 .cmp_eq => try genBinOp(o, inst.castTag(.cmp_eq).?, " == "),
365 .cmp_gt => try genBinOp(o, inst.castTag(.cmp_gt).?, ">"),342 .cmp_gt => try genBinOp(o, inst.castTag(.cmp_gt).?, " > "),
366 .cmp_gte => try genBinOp(o, inst.castTag(.cmp_gte).?, ">="),343 .cmp_gte => try genBinOp(o, inst.castTag(.cmp_gte).?, " >= "),
367 .cmp_lt => try genBinOp(o, inst.castTag(.cmp_lt).?, "<"),344 .cmp_lt => try genBinOp(o, inst.castTag(.cmp_lt).?, " < "),
368 .cmp_lte => try genBinOp(o, inst.castTag(.cmp_lte).?, "<="),345 .cmp_lte => try genBinOp(o, inst.castTag(.cmp_lte).?, " <= "),
369 .cmp_neq => try genBinOp(o, inst.castTag(.cmp_neq).?, "!="),346 .cmp_neq => try genBinOp(o, inst.castTag(.cmp_neq).?, " != "),
370 .dbg_stmt => try genDbgStmt(o, inst.castTag(.dbg_stmt).?),347 .dbg_stmt => try genDbgStmt(o, inst.castTag(.dbg_stmt).?),
371 .intcast => try genIntCast(o, inst.castTag(.intcast).?),348 .intcast => try genIntCast(o, inst.castTag(.intcast).?),
372 .load => try genLoad(o, inst.castTag(.load).?),349 .load => try genLoad(o, inst.castTag(.load).?),
373 .ret => try genRet(o, inst.castTag(.ret).?),350 .ret => try genRet(o, inst.castTag(.ret).?),
374 .retvoid => try genRetVoid(o),351 .retvoid => try genRetVoid(o),
375 .store => try genStore(o, inst.castTag(.store).?),352 .store => try genStore(o, inst.castTag(.store).?),
376 .sub => try genBinOp(o, inst.castTag(.sub).?, "-"),353 .sub => try genBinOp(o, inst.castTag(.sub).?, " - "),
377 .unreach => try genUnreach(o, inst.castTag(.unreach).?),354 .unreach => try genUnreach(o, inst.castTag(.unreach).?),
378 else => |e| return o.dg.fail(o.dg.decl.src(), "TODO: C backend: implement codegen for {}", .{e}),355 else => |e| return o.dg.fail(o.dg.decl.src(), "TODO: C backend: implement codegen for {}", .{e}),
379 };356 };
...@@ -457,10 +434,14 @@ fn genLoad(o: *Object, inst: *Inst.UnOp) !CValue {...@@ -457,10 +434,14 @@ fn genLoad(o: *Object, inst: *Inst.UnOp) !CValue {
457 switch (operand) {434 switch (operand) {
458 .local_ref => |i| {435 .local_ref => |i| {
459 const wrapped: CValue = .{ .local = i };436 const wrapped: CValue = .{ .local = i };
460 try writer.print(" = {};\n", .{wrapped.printed(o)});437 try writer.writeAll(" = ");
438 try o.writeCValue(writer, wrapped);
439 try writer.writeAll(";\n");
461 },440 },
462 else => {441 else => {
463 try writer.print(" = *{};\n", .{operand.printed(o)});442 try writer.writeAll(" = *");
443 try o.writeCValue(writer, operand);
444 try writer.writeAll(";\n");
464 },445 },
465 }446 }
466 return local;447 return local;
...@@ -469,7 +450,10 @@ fn genLoad(o: *Object, inst: *Inst.UnOp) !CValue {...@@ -469,7 +450,10 @@ fn genLoad(o: *Object, inst: *Inst.UnOp) !CValue {
469fn genRet(o: *Object, inst: *Inst.UnOp) !CValue {450fn genRet(o: *Object, inst: *Inst.UnOp) !CValue {
470 const operand = try o.resolveInst(inst.operand);451 const operand = try o.resolveInst(inst.operand);
471 try o.indent();452 try o.indent();
472 try o.code.writer().print("return {};\n", .{operand.printed(o)});453 const writer = o.code.writer();
454 try writer.writeAll("return ");
455 try o.writeCValue(writer, operand);
456 try writer.writeAll(";\n");
473 return CValue.none;457 return CValue.none;
474}458}
475459
...@@ -484,7 +468,9 @@ fn genIntCast(o: *Object, inst: *Inst.UnOp) !CValue {...@@ -484,7 +468,9 @@ fn genIntCast(o: *Object, inst: *Inst.UnOp) !CValue {
484 const local = try o.allocLocal(inst.base.ty, .Const);468 const local = try o.allocLocal(inst.base.ty, .Const);
485 try writer.writeAll(" = (");469 try writer.writeAll(" = (");
486 try o.dg.renderType(writer, inst.base.ty);470 try o.dg.renderType(writer, inst.base.ty);
487 try writer.print("){};\n", .{from.printed(o)});471 try writer.writeAll(")");
472 try o.writeCValue(writer, from);
473 try writer.writeAll(";\n");
488 return local;474 return local;
489}475}
490476
...@@ -498,10 +484,17 @@ fn genStore(o: *Object, inst: *Inst.BinOp) !CValue {...@@ -498,10 +484,17 @@ fn genStore(o: *Object, inst: *Inst.BinOp) !CValue {
498 switch (dest_ptr) {484 switch (dest_ptr) {
499 .local_ref => |i| {485 .local_ref => |i| {
500 const dest: CValue = .{ .local = i };486 const dest: CValue = .{ .local = i };
501 try writer.print("{} = {};\n", .{ dest.printed(o), src_val.printed(o) });487 try o.writeCValue(writer, dest);
488 try writer.writeAll(" = ");
489 try o.writeCValue(writer, src_val);
490 try writer.writeAll(";\n");
502 },491 },
503 else => {492 else => {
504 try writer.print("*{} = {};\n", .{ dest_ptr.printed(o), src_val.printed(o) });493 try writer.writeAll("*");
494 try o.writeCValue(writer, dest_ptr);
495 try writer.writeAll(" = ");
496 try o.writeCValue(writer, src_val);
497 try writer.writeAll(";\n");
505 },498 },
506 }499 }
507 return CValue.none;500 return CValue.none;
...@@ -517,7 +510,13 @@ fn genBinOp(o: *Object, inst: *Inst.BinOp, operator: []const u8) !CValue {...@@ -517,7 +510,13 @@ fn genBinOp(o: *Object, inst: *Inst.BinOp, operator: []const u8) !CValue {
517 try o.indent();510 try o.indent();
518 const writer = o.code.writer();511 const writer = o.code.writer();
519 const local = try o.allocLocal(inst.base.ty, .Const);512 const local = try o.allocLocal(inst.base.ty, .Const);
520 try writer.print(" = {} {s} {};\n", .{ lhs.printed(o), operator, rhs.printed(o) });513
514 try writer.writeAll(" = ");
515 try o.writeCValue(writer, lhs);
516 try writer.writeAll(operator);
517 try o.writeCValue(writer, rhs);
518 try writer.writeAll(";\n");
519
521 return local;520 return local;
522}521}
523522
...@@ -556,7 +555,7 @@ fn genCall(o: *Object, inst: *Inst.Call) !CValue {...@@ -556,7 +555,7 @@ fn genCall(o: *Object, inst: *Inst.Call) !CValue {
556 try o.dg.renderValue(writer, arg.ty, val);555 try o.dg.renderValue(writer, arg.ty, val);
557 } else {556 } else {
558 const val = try o.resolveInst(arg);557 const val = try o.resolveInst(arg);
559 try writer.print("{}", .{val.printed(o)});558 try o.writeCValue(writer, val);
560 }559 }
561 }560 }
562 }561 }
...@@ -585,16 +584,25 @@ fn genBitcast(o: *Object, inst: *Inst.UnOp) !CValue {...@@ -585,16 +584,25 @@ fn genBitcast(o: *Object, inst: *Inst.UnOp) !CValue {
585 const local = try o.allocLocal(inst.base.ty, .Const);584 const local = try o.allocLocal(inst.base.ty, .Const);
586 try writer.writeAll(" = (");585 try writer.writeAll(" = (");
587 try o.dg.renderType(writer, inst.base.ty);586 try o.dg.renderType(writer, inst.base.ty);
588 try writer.print("){};\n", .{operand.printed(o)});587
588 try writer.writeAll(")");
589 try o.writeCValue(writer, operand);
590 try writer.writeAll(";\n");
589 return local;591 return local;
590 }592 }
591593
592 const local = try o.allocLocal(inst.base.ty, .Mut);594 const local = try o.allocLocal(inst.base.ty, .Mut);
593 try writer.writeAll(";\n");595 try writer.writeAll(";\n");
594 try o.indent();596 try o.indent();
595 try writer.print("memcpy(&{}, &{}, sizeof {});\n", .{597
596 local.printed(o), operand.printed(o), local.printed(o),598 try writer.writeAll("memcpy(&");
597 });599 try o.writeCValue(writer, local);
600 try writer.writeAll(", &");
601 try o.writeCValue(writer, operand);
602 try writer.writeAll(", sizeof ");
603 try o.writeCValue(writer, local);
604 try writer.writeAll(");\n");
605
598 return local;606 return local;
599}607}
600608
...@@ -623,9 +631,10 @@ fn genAsm(o: *Object, as: *Inst.Assembly) !CValue {...@@ -623,9 +631,10 @@ fn genAsm(o: *Object, as: *Inst.Assembly) !CValue {
623 try o.indent();631 try o.indent();
624 try writer.writeAll("register ");632 try writer.writeAll("register ");
625 try o.dg.renderType(writer, arg.ty);633 try o.dg.renderType(writer, arg.ty);
626 try writer.print(" {s}_constant __asm__(\"{s}\") = {};\n", .{634
627 reg, reg, arg_c_value.printed(o),635 try writer.print(" {s}_constant __asm__(\"{s}\") = ", .{ reg, reg });
628 });636 try o.writeCValue(writer, arg_c_value);
637 try writer.writeAll(";\n");
629 } else {638 } else {
630 return o.dg.fail(o.dg.decl.src(), "TODO non-explicit inline asm regs", .{});639 return o.dg.fail(o.dg.decl.src(), "TODO non-explicit inline asm regs", .{});
631 }640 }
...@@ -648,7 +657,7 @@ fn genAsm(o: *Object, as: *Inst.Assembly) !CValue {...@@ -648,7 +657,7 @@ fn genAsm(o: *Object, as: *Inst.Assembly) !CValue {
648 if (index > 0) {657 if (index > 0) {
649 try writer.writeAll(", ");658 try writer.writeAll(", ");
650 }659 }
651 try writer.print("\"\"({s}_constant)", .{reg});660 try writer.print("\"r\"({s}_constant)", .{reg});
652 } else {661 } else {
653 // This is blocked by the earlier test662 // This is blocked by the earlier test
654 unreachable;663 unreachable;
src/link/C.zig+4-6
...@@ -101,14 +101,12 @@ pub fn updateDecl(self: *C, module: *Module, decl: *Module.Decl) !void {...@@ -101,14 +101,12 @@ pub fn updateDecl(self: *C, module: *Module, decl: *Module.Decl) !void {
101 defer object.dg.fwd_decl.deinit();101 defer object.dg.fwd_decl.deinit();
102102
103 codegen.genDecl(&object) catch |err| switch (err) {103 codegen.genDecl(&object) catch |err| switch (err) {
104 error.AnalysisFail => {},104 error.AnalysisFail => {
105 try module.failed_decls.put(module.gpa, decl, object.dg.error_msg.?);
106 return;
107 },
105 else => |e| return e,108 else => |e| return e,
106 };109 };
107 // The code may populate this error without returning error.AnalysisFail.
108 if (object.dg.error_msg) |msg| {
109 try module.failed_decls.put(module.gpa, decl, msg);
110 return;
111 }
112110
113 fwd_decl.* = object.dg.fwd_decl.moveToUnmanaged();111 fwd_decl.* = object.dg.fwd_decl.moveToUnmanaged();
114 code.* = object.code.moveToUnmanaged();112 code.* = object.code.moveToUnmanaged();
src/link/C/zig.h+17-10
...@@ -22,24 +22,31 @@...@@ -22,24 +22,31 @@
22#define zig_unreachable()22#define zig_unreachable()
23#endif23#endif
2424
25#if defined(_MSC_VER)25#if __STDC_VERSION__ >= 199901L
26#define zig_breakpoint __debugbreak()26#define zig_restrict restrict
27#elif defined(__GNUC__)
28#define zig_restrict __restrict
27#else29#else
28#if defined(__MINGW32__) || defined(__MINGW64__)30#define zig_restrict
29#define zig_breakpoint __debugbreak()31#endif
32
33#if defined(_MSC_VER)
34#define zig_breakpoint() __debugbreak()
35#elif defined(__MINGW32__) || defined(__MINGW64__)
36#define zig_breakpoint() __debugbreak()
30#elif defined(__clang__)37#elif defined(__clang__)
31#define zig_breakpoint __builtin_debugtrap()38#define zig_breakpoint() __builtin_debugtrap()
32#elif defined(__GNUC__)39#elif defined(__GNUC__)
33#define zig_breakpoint __builtin_trap()40#define zig_breakpoint() __builtin_trap()
34#elif defined(__i386__) || defined(__x86_64__)41#elif defined(__i386__) || defined(__x86_64__)
35#define zig_breakpoint __asm__ volatile("int $0x03");42#define zig_breakpoint() __asm__ volatile("int $0x03");
36#else43#else
37#define zig_breakpoint raise(SIGTRAP)44#define zig_breakpoint() raise(SIGTRAP)
38#endif
39#endif45#endif
4046
41#include <stdint.h>47#include <stdint.h>
48#include <stddef.h>
42#define int128_t __int12849#define int128_t __int128
43#define uint128_t unsigned __int12850#define uint128_t unsigned __int128
44#include <string.h>51void *memcpy (void *zig_restrict, const void *zig_restrict, size_t);
4552
test/stage2/cbe.zig+96-217
...@@ -31,6 +31,100 @@ pub fn addCases(ctx: *TestContext) !void {...@@ -31,6 +31,100 @@ pub fn addCases(ctx: *TestContext) !void {
31 , "yo" ++ std.cstr.line_sep);31 , "yo" ++ std.cstr.line_sep);
32 }32 }
3333
34 {
35 var case = ctx.exeFromCompiledC("x86_64-linux inline assembly", linux_x64);
36
37 // Exit with 0
38 case.addCompareOutput(
39 \\fn exitGood() noreturn {
40 \\ asm volatile ("syscall"
41 \\ :
42 \\ : [number] "{rax}" (231),
43 \\ [arg1] "{rdi}" (0)
44 \\ );
45 \\ unreachable;
46 \\}
47 \\
48 \\export fn main() c_int {
49 \\ exitGood();
50 \\}
51 , "");
52
53 // Pass a usize parameter to exit
54 case.addCompareOutput(
55 \\export fn main() c_int {
56 \\ exit(0);
57 \\}
58 \\
59 \\fn exit(code: usize) noreturn {
60 \\ asm volatile ("syscall"
61 \\ :
62 \\ : [number] "{rax}" (231),
63 \\ [arg1] "{rdi}" (code)
64 \\ );
65 \\ unreachable;
66 \\}
67 , "");
68
69 // Change the parameter to u8
70 case.addCompareOutput(
71 \\export fn main() c_int {
72 \\ exit(0);
73 \\}
74 \\
75 \\fn exit(code: u8) noreturn {
76 \\ asm volatile ("syscall"
77 \\ :
78 \\ : [number] "{rax}" (231),
79 \\ [arg1] "{rdi}" (code)
80 \\ );
81 \\ unreachable;
82 \\}
83 , "");
84
85 // Do some arithmetic at the exit callsite
86 case.addCompareOutput(
87 \\export fn main() c_int {
88 \\ exitMath(1);
89 \\}
90 \\
91 \\fn exitMath(a: u8) noreturn {
92 \\ exit(0 + a - a);
93 \\}
94 \\
95 \\fn exit(code: u8) noreturn {
96 \\ asm volatile ("syscall"
97 \\ :
98 \\ : [number] "{rax}" (231),
99 \\ [arg1] "{rdi}" (code)
100 \\ );
101 \\ unreachable;
102 \\}
103 \\
104 , "");
105
106 // Invert the arithmetic
107 case.addCompareOutput(
108 \\export fn main() c_int {
109 \\ exitMath(1);
110 \\}
111 \\
112 \\fn exitMath(a: u8) noreturn {
113 \\ exit(a + 0 - a);
114 \\}
115 \\
116 \\fn exit(code: u8) noreturn {
117 \\ asm volatile ("syscall"
118 \\ :
119 \\ : [number] "{rax}" (231),
120 \\ [arg1] "{rdi}" (code)
121 \\ );
122 \\ unreachable;
123 \\}
124 \\
125 , "");
126 }
127
34 {128 {
35 var case = ctx.exeFromCompiledC("alloc and retptr", .{});129 var case = ctx.exeFromCompiledC("alloc and retptr", .{});
36130
...@@ -86,6 +180,8 @@ pub fn addCases(ctx: *TestContext) !void {...@@ -86,6 +180,8 @@ pub fn addCases(ctx: *TestContext) !void {
86 \\ unreachable;180 \\ unreachable;
87 \\}181 \\}
88 ,182 ,
183 \\zig_noreturn void _start(void);
184 \\
89 \\zig_noreturn void _start(void) {185 \\zig_noreturn void _start(void) {
90 \\ zig_breakpoint();186 \\ zig_breakpoint();
91 \\ zig_unreachable();187 \\ zig_unreachable();
...@@ -98,223 +194,6 @@ pub fn addCases(ctx: *TestContext) !void {...@@ -98,223 +194,6 @@ pub fn addCases(ctx: *TestContext) !void {
98 \\void start(void);194 \\void start(void);
99 \\195 \\
100 );196 );
101 ctx.c("less empty start function", linux_x64,
102 \\fn main() noreturn {
103 \\ unreachable;
104 \\}
105 \\
106 \\export fn _start() noreturn {
107 \\ main();
108 \\}
109 ,
110 \\static zig_noreturn void main(void);
111 \\
112 \\static zig_noreturn void main(void) {
113 \\ zig_breakpoint();
114 \\ zig_unreachable();
115 \\}
116 \\
117 \\zig_noreturn void _start(void) {
118 \\ main();
119 \\}
120 \\
121 );
122 // TODO: implement return values
123 // TODO: figure out a way to prevent asm constants from being generated
124 ctx.c("inline asm", linux_x64,
125 \\fn exitGood() noreturn {
126 \\ asm volatile ("syscall"
127 \\ :
128 \\ : [number] "{rax}" (231),
129 \\ [arg1] "{rdi}" (0)
130 \\ );
131 \\ unreachable;
132 \\}
133 \\
134 \\export fn _start() noreturn {
135 \\ exitGood();
136 \\}
137 ,
138 \\static zig_noreturn void exitGood(void);
139 \\
140 \\static uint8_t exitGood__anon_0[6] = "{rax}";
141 \\static uint8_t exitGood__anon_1[6] = "{rdi}";
142 \\static uint8_t exitGood__anon_2[8] = "syscall";
143 \\
144 \\static zig_noreturn void exitGood(void) {
145 \\ register uintptr_t rax_constant __asm__("rax") = 231;
146 \\ register uintptr_t rdi_constant __asm__("rdi") = 0;
147 \\ __asm volatile ("syscall" :: ""(rax_constant), ""(rdi_constant));
148 \\ zig_breakpoint();
149 \\ zig_unreachable();
150 \\}
151 \\
152 \\zig_noreturn void _start(void) {
153 \\ exitGood();
154 \\}
155 \\
156 );
157 ctx.c("exit with parameter", linux_x64,
158 \\export fn _start() noreturn {
159 \\ exit(0);
160 \\}
161 \\
162 \\fn exit(code: usize) noreturn {
163 \\ asm volatile ("syscall"
164 \\ :
165 \\ : [number] "{rax}" (231),
166 \\ [arg1] "{rdi}" (code)
167 \\ );
168 \\ unreachable;
169 \\}
170 \\
171 ,
172 \\static zig_noreturn void exit(uintptr_t arg0);
173 \\
174 \\static uint8_t exit__anon_0[6] = "{rax}";
175 \\static uint8_t exit__anon_1[6] = "{rdi}";
176 \\static uint8_t exit__anon_2[8] = "syscall";
177 \\
178 \\zig_noreturn void _start(void) {
179 \\ exit(0);
180 \\}
181 \\
182 \\static zig_noreturn void exit(uintptr_t arg0) {
183 \\ register uintptr_t rax_constant __asm__("rax") = 231;
184 \\ register uintptr_t rdi_constant __asm__("rdi") = arg0;
185 \\ __asm volatile ("syscall" :: ""(rax_constant), ""(rdi_constant));
186 \\ zig_breakpoint();
187 \\ zig_unreachable();
188 \\}
189 \\
190 );
191 ctx.c("exit with u8 parameter", linux_x64,
192 \\export fn _start() noreturn {
193 \\ exit(0);
194 \\}
195 \\
196 \\fn exit(code: u8) noreturn {
197 \\ asm volatile ("syscall"
198 \\ :
199 \\ : [number] "{rax}" (231),
200 \\ [arg1] "{rdi}" (code)
201 \\ );
202 \\ unreachable;
203 \\}
204 \\
205 ,
206 \\static zig_noreturn void exit(uint8_t arg0);
207 \\
208 \\static uint8_t exit__anon_0[6] = "{rax}";
209 \\static uint8_t exit__anon_1[6] = "{rdi}";
210 \\static uint8_t exit__anon_2[8] = "syscall";
211 \\
212 \\zig_noreturn void _start(void) {
213 \\ exit(0);
214 \\}
215 \\
216 \\static zig_noreturn void exit(uint8_t arg0) {
217 \\ uintptr_t const __temp_0 = (uintptr_t)arg0;
218 \\ register uintptr_t rax_constant __asm__("rax") = 231;
219 \\ register uintptr_t rdi_constant __asm__("rdi") = __temp_0;
220 \\ __asm volatile ("syscall" :: ""(rax_constant), ""(rdi_constant));
221 \\ zig_breakpoint();
222 \\ zig_unreachable();
223 \\}
224 \\
225 );
226 ctx.c("exit with u8 arithmetic", linux_x64,
227 \\export fn _start() noreturn {
228 \\ exitMath(1);
229 \\}
230 \\
231 \\fn exitMath(a: u8) noreturn {
232 \\ exit(0 + a - a);
233 \\}
234 \\
235 \\fn exit(code: u8) noreturn {
236 \\ asm volatile ("syscall"
237 \\ :
238 \\ : [number] "{rax}" (231),
239 \\ [arg1] "{rdi}" (code)
240 \\ );
241 \\ unreachable;
242 \\}
243 \\
244 ,
245 \\static zig_noreturn void exitMath(uint8_t arg0);
246 \\static zig_noreturn void exit(uint8_t arg0);
247 \\
248 \\static uint8_t exit__anon_0[6] = "{rax}";
249 \\static uint8_t exit__anon_1[6] = "{rdi}";
250 \\static uint8_t exit__anon_2[8] = "syscall";
251 \\
252 \\zig_noreturn void _start(void) {
253 \\ exitMath(1);
254 \\}
255 \\
256 \\static zig_noreturn void exitMath(uint8_t arg0) {
257 \\ uint8_t const __temp_0 = 0 + arg0;
258 \\ uint8_t const __temp_1 = __temp_0 - arg0;
259 \\ exit(__temp_1);
260 \\}
261 \\
262 \\static zig_noreturn void exit(uint8_t arg0) {
263 \\ uintptr_t const __temp_0 = (uintptr_t)arg0;
264 \\ register uintptr_t rax_constant __asm__("rax") = 231;
265 \\ register uintptr_t rdi_constant __asm__("rdi") = __temp_0;
266 \\ __asm volatile ("syscall" :: ""(rax_constant), ""(rdi_constant));
267 \\ zig_breakpoint();
268 \\ zig_unreachable();
269 \\}
270 \\
271 );
272 ctx.c("exit with u8 arithmetic inverted", linux_x64,
273 \\export fn _start() noreturn {
274 \\ exitMath(1);
275 \\}
276 \\
277 \\fn exitMath(a: u8) noreturn {
278 \\ exit(a + 0 - a);
279 \\}
280 \\
281 \\fn exit(code: u8) noreturn {
282 \\ asm volatile ("syscall"
283 \\ :
284 \\ : [number] "{rax}" (231),
285 \\ [arg1] "{rdi}" (code)
286 \\ );
287 \\ unreachable;
288 \\}
289 \\
290 ,
291 \\static zig_noreturn void exitMath(uint8_t arg0);
292 \\static zig_noreturn void exit(uint8_t arg0);
293 \\
294 \\static uint8_t exit__anon_0[6] = "{rax}";
295 \\static uint8_t exit__anon_1[6] = "{rdi}";
296 \\static uint8_t exit__anon_2[8] = "syscall";
297 \\
298 \\zig_noreturn void _start(void) {
299 \\ exitMath(1);
300 \\}
301 \\
302 \\static zig_noreturn void exitMath(uint8_t arg0) {
303 \\ uint8_t const __temp_0 = arg0 + 0;
304 \\ uint8_t const __temp_1 = __temp_0 - arg0;
305 \\ exit(__temp_1);
306 \\}
307 \\
308 \\static zig_noreturn void exit(uint8_t arg0) {
309 \\ uintptr_t const __temp_0 = (uintptr_t)arg0;
310 \\ register uintptr_t rax_constant __asm__("rax") = 231;
311 \\ register uintptr_t rdi_constant __asm__("rdi") = __temp_0;
312 \\ __asm volatile ("syscall" :: ""(rax_constant), ""(rdi_constant));
313 \\ zig_breakpoint();
314 \\ zig_unreachable();
315 \\}
316 \\
317 );
318 ctx.h("header with single param function", linux_x64,197 ctx.h("header with single param function", linux_x64,
319 \\export fn start(a: u8) void{}198 \\export fn start(a: u8) void{}
320 ,199 ,