| ... | @@ -193,7 +193,6 @@ const CallMCValues = struct { | ... | @@ -193,7 +193,6 @@ const CallMCValues = struct { |
| 193 | } | 193 | } |
| 194 | }; | 194 | }; |
| 195 | | 195 | |
| 196 | | | |
| 197 | pub fn generate( | 196 | pub 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); |
| 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 | 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 | } |
| 297 | | 296 | |
| 298 | /// Caller must call `CallMCValues.deinit`. | 297 | /// Caller must call `CallMCValues.deinit`. |
| 299 | fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues { | 298 | fn 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); |
| 302 | | 311 | |
| 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 | } |
| 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 | /// Caller must call `CallMCValues.deinit`. | 383 | /// Caller must call `CallMCValues.deinit`. |
| 308 | fn gen(self: *Self) !void { | 384 | fn gen(self: *Self) !void { |
| ... | @@ -310,3 +386,10 @@ fn gen(self: *Self) !void { | ... | @@ -310,3 +386,10 @@ fn gen(self: *Self) !void { |
| 310 | | 386 | |
| 311 | @panic("TODO implement gen"); | 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 | } |