| ... | ... | @@ -193,7 +193,6 @@ const CallMCValues = struct { |
| 193 | 193 | } |
| 194 | 194 | }; |
| 195 | 195 | |
| 196 | | |
| 197 | 196 | pub fn generate( |
| 198 | 197 | bin_file: *link.File, |
| 199 | 198 | src_loc: Module.SrcLoc, |
| ... | ... | @@ -242,7 +241,7 @@ pub fn generate( |
| 242 | 241 | defer function.blocks.deinit(bin_file.allocator); |
| 243 | 242 | defer function.exitlude_jump_relocs.deinit(bin_file.allocator); |
| 244 | 243 | |
| 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 | 245 | error.CodegenFail => return FnResult{ .fail = function.err_msg.? }, |
| 247 | 246 | error.OutOfRegisters => return FnResult{ |
| 248 | 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 | 295 | } |
| 297 | 296 | |
| 298 | 297 | /// Caller must call `CallMCValues.deinit`. |
| 299 | | fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues { |
| 300 | | _ = self; |
| 301 | | _ = fn_ty; |
| 298 | fn resolveCallingConventionValues(self: *Self, fn_ty: Type, is_caller: bool) !CallMCValues { |
| 299 | const cc = fn_ty.fnCallingConvention(); |
| 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); |
| 302 | 311 | |
| 303 | | @panic("TODO implement resolveCallingConventionValues"); |
| 304 | | } |
| 312 | const ret_ty = fn_ty.fnReturnType(); |
| 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 | } |
| 305 | 362 | |
| 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 | } |
| 306 | 382 | |
| 307 | 383 | /// Caller must call `CallMCValues.deinit`. |
| 308 | 384 | fn gen(self: *Self) !void { |
| ... | ... | @@ -310,3 +386,10 @@ fn gen(self: *Self) !void { |
| 310 | 386 | |
| 311 | 387 | @panic("TODO implement gen"); |
| 312 | 388 | } |
| 389 | |
| 390 | fn 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 | } |