authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-12-29 17:56:30-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-12-29 17:56:30-07:00
logd18b6785bb394955eb092c82818e0214e456aced
tree8ff1a615bc30e0bbc707a2934cca8a969ec4a314
parentbbe2cca1ae32af322abcf4cc4a6d6bee671bf5b8

stage2: C backend improvements

* Module: improve doc comments * C backend: improve const-correctness * C backend: introduce renderTypeAndName * C backend: put `static` on functions when appropriate * C backend: fix not handling errors in genBinOp * C backend: handle more IR instructions - alloc, store, boolean comparisons, ret_ptr * C backend: call instruction properly stores its result * test harness: ensure execution tests have empty stderr

6 files changed, 178 insertions(+), 81 deletions(-)

src/Module.zig+1
......@@ -37,6 +37,7 @@ root_scope: *Scope,
3737/// It's rare for a decl to be exported, so we save memory by having a sparse map of
3838/// Decl pointers to details about them being exported.
3939/// The Export memory is owned by the `export_owners` table; the slice itself is owned by this table.
40/// The slice is guaranteed to not be empty.
4041decl_exports: std.AutoArrayHashMapUnmanaged(*Decl, []*Export) = .{},
4142/// We track which export is associated with the given symbol name for quick
4243/// detection of symbol collisions.
src/codegen/c.zig+129-56
......@@ -21,6 +21,34 @@ fn map(allocator: *std.mem.Allocator, name: []const u8) ![]const u8 {
2121 return allocator.dupe(u8, name);
2222}
2323
24const Mutability = enum { Const, Mut };
25
26fn renderTypeAndName(
27 ctx: *Context,
28 writer: Writer,
29 ty: Type,
30 name: []const u8,
31 mutability: Mutability,
32) error{ OutOfMemory, AnalysisFail }!void {
33 var suffix = std.ArrayList(u8).init(&ctx.arena.allocator);
34
35 var render_ty = ty;
36 while (render_ty.zigTypeTag() == .Array) {
37 const sentinel_bit = @boolToInt(render_ty.sentinel() != null);
38 const c_len = render_ty.arrayLen() + sentinel_bit;
39 try suffix.writer().print("[{d}]", .{c_len});
40 render_ty = render_ty.elemType();
41 }
42
43 try renderType(ctx, writer, render_ty);
44
45 const const_prefix = switch (mutability) {
46 .Const => "const ",
47 .Mut => "",
48 };
49 try writer.print(" {s}{s}{s}", .{ const_prefix, name, suffix.items });
50}
51
2452fn renderType(
2553 ctx: *Context,
2654 writer: Writer,
......@@ -74,14 +102,14 @@ fn renderType(
74102 if (t.isSlice()) {
75103 return ctx.fail(ctx.decl.src(), "TODO: C backend: implement slices", .{});
76104 } else {
105 try renderType(ctx, writer, t.elemType());
106 try writer.writeAll(" *");
77107 if (t.isConstPtr()) {
78108 try writer.writeAll("const ");
79109 }
80110 if (t.isVolatilePtr()) {
81111 try writer.writeAll("volatile ");
82112 }
83 try renderType(ctx, writer, t.elemType());
84 try writer.writeAll(" *");
85113 }
86114 },
87115 .Array => {
......@@ -176,12 +204,27 @@ fn renderFunctionSignature(
176204 decl: *Decl,
177205) !void {
178206 const tv = decl.typed_value.most_recent.typed_value;
207 // Determine whether the function is globally visible.
208 const is_global = blk: {
209 switch (tv.val.tag()) {
210 .extern_fn => break :blk true,
211 .function => {
212 const func = tv.val.cast(Value.Payload.Function).?.func;
213 break :blk ctx.module.decl_exports.contains(func.owner_decl);
214 },
215 else => unreachable,
216 }
217 };
218 if (!is_global) {
219 try writer.writeAll("static ");
220 }
179221 try renderType(ctx, writer, tv.ty.fnReturnType());
180222 // Use the child allocator directly, as we know the name can be freed before
181223 // the rest of the arena.
182 const name = try map(ctx.arena.child_allocator, mem.spanZ(decl.name));
224 const decl_name = mem.span(decl.name);
225 const name = try map(ctx.arena.child_allocator, decl_name);
183226 defer ctx.arena.child_allocator.free(name);
184 try writer.print(" {}(", .{name});
227 try writer.print(" {s}(", .{name});
185228 var param_len = tv.ty.fnParamLen();
186229 if (param_len == 0)
187230 try writer.writeAll("void")
......@@ -205,7 +248,7 @@ fn indent(file: *C) !void {
205248 try file.main.writer().writeByteNTimes(' ', indent_amt);
206249}
207250
208pub fn generate(file: *C, decl: *Decl) !void {
251pub fn generate(file: *C, module: *Module, decl: *Decl) !void {
209252 const tv = decl.typed_value.most_recent.typed_value;
210253
211254 var arena = std.heap.ArenaAllocator.init(file.base.allocator);
......@@ -218,6 +261,7 @@ pub fn generate(file: *C, decl: *Decl) !void {
218261 .inst_map = &inst_map,
219262 .target = file.base.options.target,
220263 .header = &file.header,
264 .module = module,
221265 };
222266 defer {
223267 file.error_msg = ctx.error_msg;
......@@ -236,17 +280,26 @@ pub fn generate(file: *C, decl: *Decl) !void {
236280 try writer.writeAll("\n");
237281 for (instructions) |inst| {
238282 if (switch (inst.tag) {
283 .add => try genBinOp(&ctx, file, inst.castTag(.add).?, "+"),
284 .alloc => try genAlloc(&ctx, file, inst.castTag(.alloc).?),
285 .arg => try genArg(&ctx),
239286 .assembly => try genAsm(&ctx, file, inst.castTag(.assembly).?),
287 .block => try genBlock(&ctx, file, inst.castTag(.block).?),
288 .breakpoint => try genBreakpoint(file, inst.castTag(.breakpoint).?),
240289 .call => try genCall(&ctx, file, inst.castTag(.call).?),
241 .add => try genBinOp(&ctx, file, inst.cast(Inst.BinOp).?, "+"),
242 .sub => try genBinOp(&ctx, file, inst.cast(Inst.BinOp).?, "-"),
290 .cmp_eq => try genBinOp(&ctx, file, inst.castTag(.cmp_eq).?, "=="),
291 .cmp_gt => try genBinOp(&ctx, file, inst.castTag(.cmp_gt).?, ">"),
292 .cmp_gte => try genBinOp(&ctx, file, inst.castTag(.cmp_gte).?, ">="),
293 .cmp_lt => try genBinOp(&ctx, file, inst.castTag(.cmp_lt).?, "<"),
294 .cmp_lte => try genBinOp(&ctx, file, inst.castTag(.cmp_lte).?, "<="),
295 .cmp_neq => try genBinOp(&ctx, file, inst.castTag(.cmp_neq).?, "!="),
296 .dbg_stmt => try genDbgStmt(&ctx, inst.castTag(.dbg_stmt).?),
297 .intcast => try genIntCast(&ctx, file, inst.castTag(.intcast).?),
243298 .ret => try genRet(&ctx, file, inst.castTag(.ret).?),
244299 .retvoid => try genRetVoid(file),
245 .arg => try genArg(&ctx),
246 .dbg_stmt => try genDbgStmt(&ctx, inst.castTag(.dbg_stmt).?),
247 .breakpoint => try genBreakpoint(file, inst.castTag(.breakpoint).?),
300 .store => try genStore(&ctx, file, inst.castTag(.store).?),
301 .sub => try genBinOp(&ctx, file, inst.castTag(.sub).?, "-"),
248302 .unreach => try genUnreach(file, inst.castTag(.unreach).?),
249 .intcast => try genIntCast(&ctx, file, inst.castTag(.intcast).?),
250303 else => |e| return ctx.fail(decl.src(), "TODO: C backend: implement codegen for {}", .{e}),
251304 }) |name| {
252305 try ctx.inst_map.putNoClobber(inst, name);
......@@ -264,19 +317,7 @@ pub fn generate(file: *C, decl: *Decl) !void {
264317 // TODO ask the Decl if it is const
265318 // https://github.com/ziglang/zig/issues/7582
266319
267 var suffix = std.ArrayList(u8).init(file.base.allocator);
268 defer suffix.deinit();
269
270 var render_ty = tv.ty;
271 while (render_ty.zigTypeTag() == .Array) {
272 const sentinel_bit = @boolToInt(render_ty.sentinel() != null);
273 const c_len = render_ty.arrayLen() + sentinel_bit;
274 try suffix.writer().print("[{d}]", .{c_len});
275 render_ty = render_ty.elemType();
276 }
277
278 try renderType(&ctx, writer, render_ty);
279 try writer.print(" {s}{s}", .{ decl.name, suffix.items });
320 try renderTypeAndName(&ctx, writer, tv.ty, mem.span(decl.name), .Mut);
280321
281322 try writer.writeAll(" = ");
282323 try renderValue(&ctx, writer, tv.ty, tv.val);
......@@ -304,6 +345,7 @@ pub fn generateHeader(
304345 .inst_map = &inst_map,
305346 .target = comp.getTarget(),
306347 .header = header,
348 .module = module,
307349 };
308350 const writer = header.buf.writer();
309351 renderFunctionSignature(&ctx, writer, decl) catch |err| {
......@@ -327,17 +369,15 @@ const Context = struct {
327369 error_msg: *Compilation.ErrorMsg = undefined,
328370 target: std.Target,
329371 header: *C.Header,
372 module: *Module,
330373
331374 fn resolveInst(self: *Context, inst: *Inst) ![]u8 {
332 if (inst.cast(Inst.Constant)) |const_inst| {
375 if (inst.value()) |val| {
333376 var out = std.ArrayList(u8).init(&self.arena.allocator);
334 try renderValue(self, out.writer(), inst.ty, const_inst.val);
377 try renderValue(self, out.writer(), inst.ty, val);
335378 return out.toOwnedSlice();
336379 }
337 if (self.inst_map.get(inst)) |val| {
338 return val;
339 }
340 unreachable;
380 return self.inst_map.get(inst).?; // Instruction does not dominate all uses!
341381 }
342382
343383 fn name(self: *Context) ![]u8 {
......@@ -356,6 +396,27 @@ const Context = struct {
356396 }
357397};
358398
399fn genAlloc(ctx: *Context, file: *C, alloc: *Inst.NoOp) !?[]u8 {
400 const writer = file.main.writer();
401
402 // First line: the variable used as data storage.
403 try indent(file);
404 const local_name = try ctx.name();
405 const elem_type = alloc.base.ty.elemType();
406 const mutability: Mutability = if (alloc.base.ty.isConstPtr()) .Const else .Mut;
407 try renderTypeAndName(ctx, writer, elem_type, local_name, mutability);
408 try writer.writeAll(";\n");
409
410 // Second line: a pointer to it so that we can refer to it as the allocation.
411 // One line for the variable, one line for the pointer to the variable, which we return.
412 try indent(file);
413 const ptr_local_name = try ctx.name();
414 try renderTypeAndName(ctx, writer, alloc.base.ty, ptr_local_name, .Const);
415 try writer.print(" = &{s};\n", .{local_name});
416
417 return ptr_local_name;
418}
419
359420fn genArg(ctx: *Context) !?[]u8 {
360421 const name = try std.fmt.allocPrint(&ctx.arena.allocator, "arg{}", .{ctx.argdex});
361422 ctx.argdex += 1;
......@@ -371,20 +432,10 @@ fn genRetVoid(file: *C) !?[]u8 {
371432fn genRet(ctx: *Context, file: *C, inst: *Inst.UnOp) !?[]u8 {
372433 try indent(file);
373434 const writer = file.main.writer();
374 try writer.writeAll("return ");
375 try genValue(ctx, writer, inst.operand);
376 try writer.writeAll(";\n");
435 try writer.print("return {s};\n", .{try ctx.resolveInst(inst.operand)});
377436 return null;
378437}
379438
380fn genValue(ctx: *Context, writer: Writer, inst: *Inst) !void {
381 if (inst.value()) |val| {
382 try renderValue(ctx, writer, inst.ty, val);
383 return;
384 }
385 return ctx.fail(ctx.decl.src(), "TODO: C backend: genValue for non-constant value", .{});
386}
387
388439fn genIntCast(ctx: *Context, file: *C, inst: *Inst.UnOp) !?[]u8 {
389440 if (inst.base.isUnused())
390441 return null;
......@@ -393,25 +444,34 @@ fn genIntCast(ctx: *Context, file: *C, inst: *Inst.UnOp) !?[]u8 {
393444 const writer = file.main.writer();
394445 const name = try ctx.name();
395446 const from = try ctx.resolveInst(inst.operand);
396 try writer.writeAll("const ");
397 try renderType(ctx, writer, inst.base.ty);
398 try writer.print(" {} = (", .{name});
447
448 try renderTypeAndName(ctx, writer, inst.base.ty, name, .Const);
449 try writer.writeAll(" = (");
399450 try renderType(ctx, writer, inst.base.ty);
400 try writer.print("){};\n", .{from});
451 try writer.print("){s};\n", .{from});
401452 return name;
402453}
403454
404fn genBinOp(ctx: *Context, file: *C, inst: *Inst.BinOp, comptime operator: []const u8) !?[]u8 {
455fn genStore(ctx: *Context, file: *C, inst: *Inst.BinOp) !?[]u8 {
456 // *a = b;
457 try indent(file);
458 const writer = file.main.writer();
459 const dest_ptr_name = try ctx.resolveInst(inst.lhs);
460 const src_val_name = try ctx.resolveInst(inst.rhs);
461 try writer.print("*{s} = {s};\n", .{ dest_ptr_name, src_val_name });
462 return null;
463}
464
465fn genBinOp(ctx: *Context, file: *C, inst: *Inst.BinOp, operator: []const u8) !?[]u8 {
405466 if (inst.base.isUnused())
406467 return null;
407468 try indent(file);
408 const lhs = ctx.resolveInst(inst.lhs);
409 const rhs = ctx.resolveInst(inst.rhs);
469 const lhs = try ctx.resolveInst(inst.lhs);
470 const rhs = try ctx.resolveInst(inst.rhs);
410471 const writer = file.main.writer();
411472 const name = try ctx.name();
412 try writer.writeAll("const ");
413 try renderType(ctx, writer, inst.base.ty);
414 try writer.print(" {} = {} " ++ operator ++ " {};\n", .{ name, lhs, rhs });
473 try renderTypeAndName(ctx, writer, inst.base.ty, name, .Const);
474 try writer.print(" = {s} {s} {s};\n", .{ lhs, operator, rhs });
415475 return name;
416476}
417477
......@@ -428,13 +488,22 @@ fn genCall(ctx: *Context, file: *C, inst: *Inst.Call) !?[]u8 {
428488 unreachable;
429489
430490 const fn_ty = fn_decl.typed_value.most_recent.typed_value.ty;
431 const ret_ty = fn_ty.fnReturnType().tag();
432 if (fn_ty.fnReturnType().hasCodeGenBits() and inst.base.isUnused()) {
433 try writer.print("(void)", .{});
491 const ret_ty = fn_ty.fnReturnType();
492 const unused_result = inst.base.isUnused();
493 var result_name: ?[]u8 = null;
494 if (unused_result) {
495 if (ret_ty.hasCodeGenBits()) {
496 try writer.print("(void)", .{});
497 }
498 } else {
499 const local_name = try ctx.name();
500 try renderTypeAndName(ctx, writer, ret_ty, local_name, .Const);
501 try writer.writeAll(" = ");
502 result_name = local_name;
434503 }
435504 const fn_name = mem.spanZ(fn_decl.name);
436505 if (file.called.get(fn_name) == null) {
437 try file.called.put(fn_name, void{});
506 try file.called.put(fn_name, {});
438507 try renderFunctionSignature(ctx, header, fn_decl);
439508 try header.writeAll(";\n");
440509 }
......@@ -453,10 +522,10 @@ fn genCall(ctx: *Context, file: *C, inst: *Inst.Call) !?[]u8 {
453522 }
454523 }
455524 try writer.writeAll(");\n");
525 return result_name;
456526 } else {
457527 return ctx.fail(ctx.decl.src(), "TODO: C backend: implement function pointers", .{});
458528 }
459 return null;
460529}
461530
462531fn genDbgStmt(ctx: *Context, inst: *Inst.NoOp) !?[]u8 {
......@@ -464,6 +533,10 @@ fn genDbgStmt(ctx: *Context, inst: *Inst.NoOp) !?[]u8 {
464533 return null;
465534}
466535
536fn genBlock(ctx: *Context, file: *C, inst: *Inst.Block) !?[]u8 {
537 return ctx.fail(ctx.decl.src(), "TODO: C backend: implement blocks", .{});
538}
539
467540fn genBreakpoint(file: *C, inst: *Inst.NoOp) !?[]u8 {
468541 try indent(file);
469542 try file.main.writer().writeAll("zig_breakpoint();\n");
src/link/C.zig+1-1
......@@ -90,7 +90,7 @@ pub fn deinit(self: *C) void {
9090}
9191
9292pub fn updateDecl(self: *C, module: *Module, decl: *Module.Decl) !void {
93 codegen.generate(self, decl) catch |err| {
93 codegen.generate(self, module, decl) catch |err| {
9494 if (err == error.AnalysisFail) {
9595 try module.failed_decls.put(module.gpa, decl, self.error_msg);
9696 }
src/test.zig+1
......@@ -863,6 +863,7 @@ pub const TestContext = struct {
863863 },
864864 }
865865 std.testing.expectEqualStrings(expected_stdout, exec_result.stdout);
866 std.testing.expectEqualStrings("", exec_result.stderr);
866867 },
867868 }
868869 }
src/zir_sema.zig+5-1
......@@ -352,7 +352,11 @@ fn analyzeInstCoerceToPtrElem(mod: *Module, scope: *Scope, inst: *zir.Inst.Coerc
352352}
353353
354354fn analyzeInstRetPtr(mod: *Module, scope: *Scope, inst: *zir.Inst.NoOp) InnerError!*Inst {
355 return mod.fail(scope, inst.base.src, "TODO implement analyzeInstRetPtr", .{});
355 const b = try mod.requireFunctionBlock(scope, inst.base.src);
356 const fn_ty = b.func.?.owner_decl.typed_value.most_recent.typed_value.ty;
357 const ret_type = fn_ty.fnReturnType();
358 const ptr_type = try mod.simplePtrType(scope, inst.base.src, ret_type, true, .One);
359 return mod.addNoOp(b, inst.base.src, ptr_type, .alloc);
356360}
357361
358362fn analyzeInstRef(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst {
test/stage2/cbe.zig+41-23
......@@ -33,6 +33,24 @@ pub fn addCases(ctx: *TestContext) !void {
3333 //, "yo" ++ std.cstr.line_sep);
3434 }
3535
36 {
37 var case = ctx.exeFromCompiledC("alloc and retptr", .{});
38
39 case.addCompareOutput(
40 \\fn add(a: i32, b: i32) i32 {
41 \\ return a + b;
42 \\}
43 \\
44 \\fn addIndirect(a: i32, b: i32) i32 {
45 \\ return add(a, b);
46 \\}
47 \\
48 \\export fn main() c_int {
49 \\ return addIndirect(1, 2) - 3;
50 \\}
51 , "");
52 }
53
3654 ctx.c("empty start function", linux_x64,
3755 \\export fn _start() noreturn {
3856 \\ unreachable;
......@@ -59,13 +77,13 @@ pub fn addCases(ctx: *TestContext) !void {
5977 \\ main();
6078 \\}
6179 ,
62 \\zig_noreturn void main(void);
80 \\static zig_noreturn void main(void);
6381 \\
6482 \\zig_noreturn void _start(void) {
6583 \\ main();
6684 \\}
6785 \\
68 \\zig_noreturn void main(void) {
86 \\static zig_noreturn void main(void) {
6987 \\ zig_breakpoint();
7088 \\ zig_unreachable();
7189 \\}
......@@ -87,7 +105,7 @@ pub fn addCases(ctx: *TestContext) !void {
87105 \\ exitGood();
88106 \\}
89107 ,
90 \\zig_noreturn void exitGood(void);
108 \\static zig_noreturn void exitGood(void);
91109 \\
92110 \\static uint8_t exitGood__anon_0[6] = "{rax}";
93111 \\static uint8_t exitGood__anon_1[6] = "{rdi}";
......@@ -97,7 +115,7 @@ pub fn addCases(ctx: *TestContext) !void {
97115 \\ exitGood();
98116 \\}
99117 \\
100 \\zig_noreturn void exitGood(void) {
118 \\static zig_noreturn void exitGood(void) {
101119 \\ register uintptr_t rax_constant __asm__("rax") = 231;
102120 \\ register uintptr_t rdi_constant __asm__("rdi") = 0;
103121 \\ __asm volatile ("syscall" :: ""(rax_constant), ""(rdi_constant));
......@@ -121,7 +139,7 @@ pub fn addCases(ctx: *TestContext) !void {
121139 \\}
122140 \\
123141 ,
124 \\zig_noreturn void exit(uintptr_t arg0);
142 \\static zig_noreturn void exit(uintptr_t arg0);
125143 \\
126144 \\static uint8_t exit__anon_0[6] = "{rax}";
127145 \\static uint8_t exit__anon_1[6] = "{rdi}";
......@@ -131,7 +149,7 @@ pub fn addCases(ctx: *TestContext) !void {
131149 \\ exit(0);
132150 \\}
133151 \\
134 \\zig_noreturn void exit(uintptr_t arg0) {
152 \\static zig_noreturn void exit(uintptr_t arg0) {
135153 \\ register uintptr_t rax_constant __asm__("rax") = 231;
136154 \\ register uintptr_t rdi_constant __asm__("rdi") = arg0;
137155 \\ __asm volatile ("syscall" :: ""(rax_constant), ""(rdi_constant));
......@@ -155,7 +173,7 @@ pub fn addCases(ctx: *TestContext) !void {
155173 \\}
156174 \\
157175 ,
158 \\zig_noreturn void exit(uint8_t arg0);
176 \\static zig_noreturn void exit(uint8_t arg0);
159177 \\
160178 \\static uint8_t exit__anon_0[6] = "{rax}";
161179 \\static uint8_t exit__anon_1[6] = "{rdi}";
......@@ -165,8 +183,8 @@ pub fn addCases(ctx: *TestContext) !void {
165183 \\ exit(0);
166184 \\}
167185 \\
168 \\zig_noreturn void exit(uint8_t arg0) {
169 \\ const uintptr_t __temp_0 = (uintptr_t)arg0;
186 \\static zig_noreturn void exit(uint8_t arg0) {
187 \\ uintptr_t const __temp_0 = (uintptr_t)arg0;
170188 \\ register uintptr_t rax_constant __asm__("rax") = 231;
171189 \\ register uintptr_t rdi_constant __asm__("rdi") = __temp_0;
172190 \\ __asm volatile ("syscall" :: ""(rax_constant), ""(rdi_constant));
......@@ -194,8 +212,8 @@ pub fn addCases(ctx: *TestContext) !void {
194212 \\}
195213 \\
196214 ,
197 \\zig_noreturn void exitMath(uint8_t arg0);
198 \\zig_noreturn void exit(uint8_t arg0);
215 \\static zig_noreturn void exitMath(uint8_t arg0);
216 \\static zig_noreturn void exit(uint8_t arg0);
199217 \\
200218 \\static uint8_t exit__anon_0[6] = "{rax}";
201219 \\static uint8_t exit__anon_1[6] = "{rdi}";
......@@ -205,14 +223,14 @@ pub fn addCases(ctx: *TestContext) !void {
205223 \\ exitMath(1);
206224 \\}
207225 \\
208 \\zig_noreturn void exitMath(uint8_t arg0) {
209 \\ const uint8_t __temp_0 = 0 + arg0;
210 \\ const uint8_t __temp_1 = __temp_0 - arg0;
226 \\static zig_noreturn void exitMath(uint8_t arg0) {
227 \\ uint8_t const __temp_0 = 0 + arg0;
228 \\ uint8_t const __temp_1 = __temp_0 - arg0;
211229 \\ exit(__temp_1);
212230 \\}
213231 \\
214 \\zig_noreturn void exit(uint8_t arg0) {
215 \\ const uintptr_t __temp_0 = (uintptr_t)arg0;
232 \\static zig_noreturn void exit(uint8_t arg0) {
233 \\ uintptr_t const __temp_0 = (uintptr_t)arg0;
216234 \\ register uintptr_t rax_constant __asm__("rax") = 231;
217235 \\ register uintptr_t rdi_constant __asm__("rdi") = __temp_0;
218236 \\ __asm volatile ("syscall" :: ""(rax_constant), ""(rdi_constant));
......@@ -240,8 +258,8 @@ pub fn addCases(ctx: *TestContext) !void {
240258 \\}
241259 \\
242260 ,
243 \\zig_noreturn void exitMath(uint8_t arg0);
244 \\zig_noreturn void exit(uint8_t arg0);
261 \\static zig_noreturn void exitMath(uint8_t arg0);
262 \\static zig_noreturn void exit(uint8_t arg0);
245263 \\
246264 \\static uint8_t exit__anon_0[6] = "{rax}";
247265 \\static uint8_t exit__anon_1[6] = "{rdi}";
......@@ -251,14 +269,14 @@ pub fn addCases(ctx: *TestContext) !void {
251269 \\ exitMath(1);
252270 \\}
253271 \\
254 \\zig_noreturn void exitMath(uint8_t arg0) {
255 \\ const uint8_t __temp_0 = arg0 + 0;
256 \\ const uint8_t __temp_1 = __temp_0 - arg0;
272 \\static zig_noreturn void exitMath(uint8_t arg0) {
273 \\ uint8_t const __temp_0 = arg0 + 0;
274 \\ uint8_t const __temp_1 = __temp_0 - arg0;
257275 \\ exit(__temp_1);
258276 \\}
259277 \\
260 \\zig_noreturn void exit(uint8_t arg0) {
261 \\ const uintptr_t __temp_0 = (uintptr_t)arg0;
278 \\static zig_noreturn void exit(uint8_t arg0) {
279 \\ uintptr_t const __temp_0 = (uintptr_t)arg0;
262280 \\ register uintptr_t rax_constant __asm__("rax") = 231;
263281 \\ register uintptr_t rdi_constant __asm__("rdi") = __temp_0;
264282 \\ __asm volatile ("syscall" :: ""(rax_constant), ""(rdi_constant));