authorgravatar for koachan@protonmail.comKoakuma <koachan@protonmail.com> 2022-03-28 22:37:55+07:00
committergravatar for koachan@protonmail.comKoakuma <koachan@protonmail.com> 2022-04-14 22:18:05+07:00
log1ba52272167b12ea14f688df7d0d34940d98ff5b
tree4e85306b3797cfcfcb0b5f4f517350e17a5f8221
parenta5a89fde1354892c6714c41ea691922bfa10c442

stage2: sparcv9: Initial resolveCallingConventionValues implementation


2 files changed, 92 insertions(+), 9 deletions(-)

src/arch/sparcv9/CodeGen.zig+90-7
...@@ -193,7 +193,6 @@ const CallMCValues = struct {...@@ -193,7 +193,6 @@ const CallMCValues = struct {
193 }193 }
194};194};
195195
196
197pub fn generate(196pub fn generate(
198 bin_file: *link.File,197 bin_file: *link.File,
199 src_loc: Module.SrcLoc,198 src_loc: Module.SrcLoc,
...@@ -242,7 +241,7 @@ pub fn generate(...@@ -242,7 +241,7 @@ pub fn generate(
242 defer function.blocks.deinit(bin_file.allocator);241 defer function.blocks.deinit(bin_file.allocator);
243 defer function.exitlude_jump_relocs.deinit(bin_file.allocator);242 defer function.exitlude_jump_relocs.deinit(bin_file.allocator);
244243
245 var call_info = function.resolveCallingConventionValues(fn_type) catch |err| switch (err) {244 var call_info = function.resolveCallingConventionValues(fn_type, false) catch |err| switch (err) {
246 error.CodegenFail => return FnResult{ .fail = function.err_msg.? },245 error.CodegenFail => return FnResult{ .fail = function.err_msg.? },
247 error.OutOfRegisters => return FnResult{246 error.OutOfRegisters => return FnResult{
248 .fail = try ErrorMsg.create(bin_file.allocator, src_loc, "CodeGen ran out of registers. This is a bug in the Zig compiler.", .{}),247 .fail = try ErrorMsg.create(bin_file.allocator, src_loc, "CodeGen ran out of registers. This is a bug in the Zig compiler.", .{}),
...@@ -296,13 +295,90 @@ pub fn generate(...@@ -296,13 +295,90 @@ pub fn generate(
296}295}
297296
298/// Caller must call `CallMCValues.deinit`.297/// Caller must call `CallMCValues.deinit`.
299fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues {298fn resolveCallingConventionValues(self: *Self, fn_ty: Type, is_caller: bool) !CallMCValues {
300 _ = self;299 const cc = fn_ty.fnCallingConvention();
301 _ = fn_ty;300 const param_types = try self.gpa.alloc(Type, fn_ty.fnParamLen());
301 defer self.gpa.free(param_types);
302 fn_ty.fnParamTypes(param_types);
303 var result: CallMCValues = .{
304 .args = try self.gpa.alloc(MCValue, param_types.len),
305 // These undefined values must be populated before returning from this function.
306 .return_value = undefined,
307 .stack_byte_count = undefined,
308 .stack_align = undefined,
309 };
310 errdefer self.gpa.free(result.args);
302311
303 @panic("TODO implement resolveCallingConventionValues");312 const ret_ty = fn_ty.fnReturnType();
304}313
314 switch (cc) {
315 .Naked => {
316 assert(result.args.len == 0);
317 result.return_value = .{ .unreach = {} };
318 result.stack_byte_count = 0;
319 result.stack_align = 1;
320 return result;
321 },
322 .Unspecified, .C => {
323 // SPARC Compliance Definition 2.4.1, Chapter 3
324 // Low-Level System Information (64-bit psABI) - Function Calling Sequence
325
326 var next_register: usize = 0;
327 var next_stack_offset: u32 = 0;
328
329 // The caller puts the argument in %o0-%o5, which becomes %i0-%i5 inside the callee.
330 const argument_registers = if (is_caller) abi.c_abi_int_param_regs_caller_view else abi.c_abi_int_param_regs_callee_view;
331
332 for (param_types) |ty, i| {
333 const param_size = @intCast(u32, ty.abiSize(self.target.*));
334 if (param_size <= 8) {
335 if (next_register < argument_registers.len) {
336 result.args[i] = .{ .register = argument_registers[next_register] };
337 next_register += 1;
338 } else {
339 result.args[i] = .{ .stack_offset = next_stack_offset };
340 next_register += next_stack_offset;
341 }
342 } else if (param_size <= 16) {
343 if (next_register < argument_registers.len - 1) {
344 return self.fail("TODO MCValues with 2 registers", .{});
345 } else if (next_register < argument_registers.len) {
346 return self.fail("TODO MCValues split register + stack", .{});
347 } else {
348 result.args[i] = .{ .stack_offset = next_stack_offset };
349 next_register += next_stack_offset;
350 }
351 } else {
352 result.args[i] = .{ .stack_offset = next_stack_offset };
353 next_register += next_stack_offset;
354 }
355 }
356
357 result.stack_byte_count = next_stack_offset;
358 result.stack_align = 16;
359 },
360 else => return self.fail("TODO implement function parameters for {} on sparcv9", .{cc}),
361 }
305362
363 if (ret_ty.zigTypeTag() == .NoReturn) {
364 result.return_value = .{ .unreach = {} };
365 } else if (!ret_ty.hasRuntimeBits()) {
366 result.return_value = .{ .none = {} };
367 } else switch (cc) {
368 .Naked => unreachable,
369 .Unspecified, .C => {
370 const ret_ty_size = @intCast(u32, ret_ty.abiSize(self.target.*));
371 // The callee puts the return values in %i0-%i3, which becomes %o0-%o3 inside the caller.
372 if (ret_ty_size <= 8) {
373 result.return_value = if (is_caller) .{ .register = abi.c_abi_int_return_regs_caller_view[0] } else .{ .register = abi.c_abi_int_return_regs_callee_view[0] };
374 } else {
375 return self.fail("TODO support more return values for sparcv9", .{});
376 }
377 },
378 else => return self.fail("TODO implement function return values for {} on sparcv9", .{cc}),
379 }
380 return result;
381}
306382
307/// Caller must call `CallMCValues.deinit`.383/// Caller must call `CallMCValues.deinit`.
308fn gen(self: *Self) !void {384fn gen(self: *Self) !void {
...@@ -310,3 +386,10 @@ fn gen(self: *Self) !void {...@@ -310,3 +386,10 @@ fn gen(self: *Self) !void {
310386
311 @panic("TODO implement gen");387 @panic("TODO implement gen");
312}388}
389
390fn fail(self: *Self, comptime format: []const u8, args: anytype) InnerError {
391 @setCold(true);
392 assert(self.err_msg == null);
393 self.err_msg = try ErrorMsg.create(self.bin_file.allocator, self.src_loc, format, args);
394 return error.CodegenFail;
395}
src/arch/sparcv9/abi.zig+2-2
...@@ -8,5 +8,5 @@ pub const callee_preserved_regs = [_]Register{};...@@ -8,5 +8,5 @@ pub const callee_preserved_regs = [_]Register{};
8pub const c_abi_int_param_regs_caller_view = [_]Register{ .o0, .o1, .o2, .o3, .o4, .o5 };8pub const c_abi_int_param_regs_caller_view = [_]Register{ .o0, .o1, .o2, .o3, .o4, .o5 };
9pub const c_abi_int_param_regs_callee_view = [_]Register{ .@"i0", .@"i1", .@"i2", .@"i3", .@"i4", .@"i5" };9pub const c_abi_int_param_regs_callee_view = [_]Register{ .@"i0", .@"i1", .@"i2", .@"i3", .@"i4", .@"i5" };
1010
11pub const c_abi_int_return_regs_caller_view = [_]Register{ .o0, .o1, .o2, .o3, .o4, .o5 };11pub const c_abi_int_return_regs_caller_view = [_]Register{ .o0, .o1, .o2, .o3 };
12pub const c_abi_int_return_regs_callee_view = [_]Register{ .@"i0", .@"i1", .@"i2", .@"i3", .@"i4", .@"i5" };12pub const c_abi_int_return_regs_callee_view = [_]Register{ .@"i0", .@"i1", .@"i2", .@"i3" };