authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-07-27 18:59:00-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-07-27 18:59:13-07:00
logb8e22d20022f533de701b5efa9e28a196de664f3
tree2882fa1565e69151cae9a22d5b74cacd8aa0296e
parent3e0a46281c91f7706add98df2a009697170822cb

stage2: implement integer return values


3 files changed, 113 insertions(+), 42 deletions(-)

src-self-hosted/codegen.zig+82-42
......@@ -206,6 +206,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
206206 code: *std.ArrayList(u8),
207207 err_msg: ?*ErrorMsg,
208208 args: []MCValue,
209 ret_mcv: MCValue,
209210 arg_index: usize,
210211 src: usize,
211212
......@@ -333,11 +334,6 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
333334 const module_fn = typed_value.val.cast(Value.Payload.Function).?.func;
334335
335336 const fn_type = module_fn.owner_decl.typed_value.most_recent.typed_value.ty;
336 const param_types = try bin_file.allocator.alloc(Type, fn_type.fnParamLen());
337 defer bin_file.allocator.free(param_types);
338 fn_type.fnParamTypes(param_types);
339 var mc_args = try bin_file.allocator.alloc(MCValue, param_types.len);
340 defer bin_file.allocator.free(mc_args);
341337
342338 var branch_stack = std.ArrayList(Branch).init(bin_file.allocator);
343339 defer {
......@@ -355,17 +351,22 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
355351 .mod_fn = module_fn,
356352 .code = code,
357353 .err_msg = null,
358 .args = mc_args,
354 .args = undefined, // populated after `resolveCallingConventionValues`
355 .ret_mcv = undefined, // populated after `resolveCallingConventionValues`
359356 .arg_index = 0,
360357 .branch_stack = &branch_stack,
361358 .src = src,
362359 };
363360
364 const cc = fn_type.fnCallingConvention();
365 branch.max_end_stack = function.resolveParameters(src, cc, param_types, mc_args) catch |err| switch (err) {
361 var call_info = function.resolveCallingConventionValues(src, fn_type) catch |err| switch (err) {
366362 error.CodegenFail => return Result{ .fail = function.err_msg.? },
367363 else => |e| return e,
368364 };
365 defer call_info.deinit(&function);
366
367 function.args = call_info.args;
368 function.ret_mcv = call_info.return_value;
369 branch.max_end_stack = call_info.stack_byte_count;
369370
370371 function.gen() catch |err| switch (err) {
371372 error.CodegenFail => return Result{ .fail = function.err_msg.? },
......@@ -705,18 +706,12 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
705706 }
706707
707708 fn genCall(self: *Self, inst: *ir.Inst.Call) !MCValue {
708 const fn_ty = inst.func.ty;
709 const cc = fn_ty.fnCallingConvention();
710 const param_types = try self.gpa.alloc(Type, fn_ty.fnParamLen());
711 defer self.gpa.free(param_types);
712 fn_ty.fnParamTypes(param_types);
713 var mc_args = try self.gpa.alloc(MCValue, param_types.len);
714 defer self.gpa.free(mc_args);
715 const stack_byte_count = try self.resolveParameters(inst.base.src, cc, param_types, mc_args);
709 var info = try self.resolveCallingConventionValues(inst.base.src, inst.func.ty);
710 defer info.deinit(self);
716711
717712 switch (arch) {
718713 .x86_64 => {
719 for (mc_args) |mc_arg, arg_i| {
714 for (info.args) |mc_arg, arg_i| {
720715 const arg = inst.args[arg_i];
721716 const arg_mcv = try self.resolveInst(inst.args[arg_i]);
722717 switch (mc_arg) {
......@@ -761,18 +756,11 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
761756 else => return self.fail(inst.base.src, "TODO implement call for {}", .{self.target.cpu.arch}),
762757 }
763758
764 const return_type = fn_ty.fnReturnType();
765 switch (return_type.zigTypeTag()) {
766 .Void => return MCValue{ .none = {} },
767 .NoReturn => return MCValue{ .unreach = {} },
768 else => return self.fail(inst.base.src, "TODO implement fn call with non-void return value", .{}),
769 }
759 return info.return_value;
770760 }
771761
772762 fn ret(self: *Self, src: usize, mcv: MCValue) !MCValue {
773 if (mcv != .none) {
774 return self.fail(src, "TODO implement return with non-void operand", .{});
775 }
763 try self.setRegOrStack(src, self.ret_mcv, mcv);
776764 switch (arch) {
777765 .i386 => {
778766 try self.code.append(0xc3); // ret
......@@ -1024,12 +1012,23 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
10241012 }
10251013 }
10261014
1015 /// Sets the value without any modifications to register allocation metadata or stack allocation metadata.
1016 fn setRegOrStack(self: *Self, src: usize, loc: MCValue, val: MCValue) !void {
1017 switch (loc) {
1018 .none => return,
1019 .register => |reg| return self.genSetReg(src, reg, val),
1020 .stack_offset => {
1021 return self.fail(src, "TODO implement setRegOrStack for stack offset", .{});
1022 },
1023 else => unreachable,
1024 }
1025 }
1026
10271027 fn genSetReg(self: *Self, src: usize, reg: Register, mcv: MCValue) error{ CodegenFail, OutOfMemory }!void {
10281028 switch (arch) {
10291029 .x86_64 => switch (mcv) {
10301030 .dead => unreachable,
1031 .none => unreachable,
1032 .unreach => unreachable,
1031 .unreach, .none => return, // Nothing to do.
10331032 .compare_flags_unsigned => |op| {
10341033 try self.code.ensureCapacity(self.code.items.len + 3);
10351034 self.rex(.{ .b = reg.isExtended(), .w = reg.size() == 64 });
......@@ -1131,6 +1130,10 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
11311130 mem.writeIntLittle(i32, imm_ptr, offset);
11321131 },
11331132 .register => |src_reg| {
1133 // If the registers are the same, nothing to do.
1134 if (src_reg == reg)
1135 return;
1136
11341137 if (reg.size() != 64) {
11351138 return self.fail(src, "TODO decide whether to implement non-64-bit loads", .{});
11361139 }
......@@ -1211,7 +1214,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
12111214 return self.fail(src, "TODO implement genSetReg for stack variables", .{});
12121215 },
12131216 },
1214 else => return self.fail(src, "TODO implement genSetReg for more architectures", .{}),
1217 else => return self.fail(src, "TODO implement getSetReg for {}", .{self.target.cpu.arch}),
12151218 }
12161219 }
12171220
......@@ -1320,19 +1323,40 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
13201323 }
13211324 }
13221325
1323 fn resolveParameters(
1324 self: *Self,
1325 src: usize,
1326 cc: std.builtin.CallingConvention,
1327 param_types: []const Type,
1328 results: []MCValue,
1329 ) !u32 {
1326 const CallMCValues = struct {
1327 args: []MCValue,
1328 return_value: MCValue,
1329 stack_byte_count: u32,
1330
1331 fn deinit(self: *CallMCValues, func: *Self) void {
1332 func.gpa.free(self.args);
1333 self.* = undefined;
1334 }
1335 };
1336
1337 /// Caller must call `CallMCValues.deinit`.
1338 fn resolveCallingConventionValues(self: *Self, src: usize, fn_ty: Type) !CallMCValues {
1339 const cc = fn_ty.fnCallingConvention();
1340 const param_types = try self.gpa.alloc(Type, fn_ty.fnParamLen());
1341 defer self.gpa.free(param_types);
1342 fn_ty.fnParamTypes(param_types);
1343 var result: CallMCValues = .{
1344 .args = try self.gpa.alloc(MCValue, param_types.len),
1345 .return_value = undefined,
1346 .stack_byte_count = undefined,
1347 };
1348 errdefer self.gpa.free(result.args);
1349
1350 const ret_ty = fn_ty.fnReturnType();
1351
13301352 switch (arch) {
13311353 .x86_64 => {
13321354 switch (cc) {
13331355 .Naked => {
1334 assert(results.len == 0);
1335 return 0;
1356 assert(result.args.len == 0);
1357 result.return_value = .{ .unreach = {} };
1358 result.stack_byte_count = 0;
1359 return result;
13361360 },
13371361 .Unspecified, .C => {
13381362 var next_int_reg: usize = 0;
......@@ -1342,23 +1366,39 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
13421366 switch (ty.zigTypeTag()) {
13431367 .Bool, .Int => {
13441368 if (next_int_reg >= c_abi_int_param_regs.len) {
1345 results[i] = .{ .stack_offset = next_stack_offset };
1369 result.args[i] = .{ .stack_offset = next_stack_offset };
13461370 next_stack_offset += @intCast(u32, ty.abiSize(self.target.*));
13471371 } else {
1348 results[i] = .{ .register = c_abi_int_param_regs[next_int_reg] };
1372 result.args[i] = .{ .register = c_abi_int_param_regs[next_int_reg] };
13491373 next_int_reg += 1;
13501374 }
13511375 },
13521376 else => return self.fail(src, "TODO implement function parameters of type {}", .{@tagName(ty.zigTypeTag())}),
13531377 }
13541378 }
1355 return next_stack_offset;
1379 result.stack_byte_count = next_stack_offset;
13561380 },
13571381 else => return self.fail(src, "TODO implement function parameters for {}", .{cc}),
13581382 }
13591383 },
1360 else => return self.fail(src, "TODO implement C ABI support for {}", .{self.target.cpu.arch}),
1384 else => return self.fail(src, "TODO implement codegen parameters for {}", .{self.target.cpu.arch}),
1385 }
1386
1387 if (ret_ty.zigTypeTag() == .NoReturn) {
1388 result.return_value = .{ .unreach = {} };
1389 } else if (!ret_ty.hasCodeGenBits()) {
1390 result.return_value = .{ .none = {} };
1391 } else switch (arch) {
1392 .x86_64 => switch (cc) {
1393 .Naked => unreachable,
1394 .Unspecified, .C => {
1395 result.return_value = .{ .register = c_abi_int_return_regs[0] };
1396 },
1397 else => return self.fail(src, "TODO implement function return values for {}", .{cc}),
1398 },
1399 else => return self.fail(src, "TODO implement codegen return values for {}", .{self.target.cpu.arch}),
13611400 }
1401 return result;
13621402 }
13631403
13641404 fn fail(self: *Self, src: usize, comptime format: []const u8, args: anytype) error{ CodegenFail, OutOfMemory } {
src-self-hosted/codegen/x86_64.zig+1
......@@ -88,3 +88,4 @@ pub const Register = enum(u8) {
8888/// These registers belong to the called function.
8989pub const callee_preserved_regs = [_]Register{ .rax, .rcx, .rdx, .rsi, .rdi, .r8, .r9, .r10, .r11 };
9090pub const c_abi_int_param_regs = [_]Register{ .rdi, .rsi, .rdx, .rcx, .r8, .r9 };
91pub const c_abi_int_return_regs = [_]Register{ .rax, .rdx };
test/stage2/compare_output.zig+30
......@@ -333,5 +333,35 @@ pub fn addCases(ctx: *TestContext) !void {
333333 ,
334334 "",
335335 );
336
337 // Now we test integer return values.
338 case.addCompareOutput(
339 \\export fn _start() noreturn {
340 \\ assert(add(3, 4) == 7);
341 \\ assert(add(20, 10) == 30);
342 \\
343 \\ exit();
344 \\}
345 \\
346 \\fn add(a: u32, b: u32) u32 {
347 \\ return a + b;
348 \\}
349 \\
350 \\pub fn assert(ok: bool) void {
351 \\ if (!ok) unreachable; // assertion failure
352 \\}
353 \\
354 \\fn exit() noreturn {
355 \\ asm volatile ("syscall"
356 \\ :
357 \\ : [number] "{rax}" (231),
358 \\ [arg1] "{rdi}" (0)
359 \\ : "rcx", "r11", "memory"
360 \\ );
361 \\ unreachable;
362 \\}
363 ,
364 "",
365 );
336366 }
337367}