| ... | @@ -382,12 +382,10 @@ fn gen(self: *Self) InnerError!void { | ... | @@ -382,12 +382,10 @@ fn gen(self: *Self) InnerError!void { |
| 382 | // yet know how big it will be, so we leave room for a 4-byte stack size. | 382 | // yet know how big it will be, so we leave room for a 4-byte stack size. |
| 383 | // TODO During semantic analysis, check if there are no function calls. If there | 383 | // TODO During semantic analysis, check if there are no function calls. If there |
| 384 | // are none, here we can omit the part where we subtract and then add rsp. | 384 | // are none, here we can omit the part where we subtract and then add rsp. |
| 385 | const backpatch_reloc = try self.addInst(.{ | 385 | const backpatch_stack_sub = try self.addInst(.{ |
| 386 | .tag = .sub, | 386 | .tag = .nop, |
| 387 | .ops = (Mir.Ops{ | 387 | .ops = undefined, |
| 388 | .reg1 = .rsp, | 388 | .data = undefined, |
| 389 | }).encode(), | | |
| 390 | .data = .{ .imm = 0 }, | | |
| 391 | }); | 389 | }); |
| 392 | | 390 | |
| 393 | _ = try self.addInst(.{ | 391 | _ = try self.addInst(.{ |
| ... | @@ -398,21 +396,6 @@ fn gen(self: *Self) InnerError!void { | ... | @@ -398,21 +396,6 @@ fn gen(self: *Self) InnerError!void { |
| 398 | | 396 | |
| 399 | try self.genBody(self.air.getMainBody()); | 397 | try self.genBody(self.air.getMainBody()); |
| 400 | | 398 | |
| 401 | const stack_end = self.max_end_stack; | | |
| 402 | if (stack_end > math.maxInt(i32)) { | | |
| 403 | return self.failSymbol("too much stack used in call parameters", .{}); | | |
| 404 | } | | |
| 405 | const aligned_stack_end = mem.alignForward(stack_end, self.stack_align); | | |
| 406 | if (aligned_stack_end > 0) { | | |
| 407 | self.mir_instructions.items(.data)[backpatch_reloc].imm = @intCast(i32, aligned_stack_end); | | |
| 408 | } else { | | |
| 409 | self.mir_instructions.set(backpatch_reloc, .{ | | |
| 410 | .tag = .nop, | | |
| 411 | .ops = undefined, | | |
| 412 | .data = undefined, | | |
| 413 | }); | | |
| 414 | } | | |
| 415 | | | |
| 416 | if (self.exitlude_jump_relocs.items.len == 1) { | 399 | if (self.exitlude_jump_relocs.items.len == 1) { |
| 417 | self.mir_instructions.len -= 1; | 400 | self.mir_instructions.len -= 1; |
| 418 | } else for (self.exitlude_jump_relocs.items) |jmp_reloc| { | 401 | } else for (self.exitlude_jump_relocs.items) |jmp_reloc| { |
| ... | @@ -425,16 +408,12 @@ fn gen(self: *Self) InnerError!void { | ... | @@ -425,16 +408,12 @@ fn gen(self: *Self) InnerError!void { |
| 425 | .data = undefined, | 408 | .data = undefined, |
| 426 | }); | 409 | }); |
| 427 | | 410 | |
| 428 | if (aligned_stack_end > 0) { | 411 | // Maybe add rsp, x if required. This is backpatched later. |
| 429 | // add rsp, x | 412 | const backpatch_stack_add = try self.addInst(.{ |
| 430 | _ = try self.addInst(.{ | 413 | .tag = .nop, |
| 431 | .tag = .add, | 414 | .ops = undefined, |
| 432 | .ops = (Mir.Ops{ | 415 | .data = undefined, |
| 433 | .reg1 = .rsp, | 416 | }); |
| 434 | }).encode(), | | |
| 435 | .data = .{ .imm = @intCast(i32, aligned_stack_end) }, | | |
| 436 | }); | | |
| 437 | } | | |
| 438 | | 417 | |
| 439 | _ = try self.addInst(.{ | 418 | _ = try self.addInst(.{ |
| 440 | .tag = .pop, | 419 | .tag = .pop, |
| ... | @@ -443,11 +422,26 @@ fn gen(self: *Self) InnerError!void { | ... | @@ -443,11 +422,26 @@ fn gen(self: *Self) InnerError!void { |
| 443 | }).encode(), | 422 | }).encode(), |
| 444 | .data = undefined, | 423 | .data = undefined, |
| 445 | }); | 424 | }); |
| | 425 | |
| 446 | // calculate the data for callee_preserved_regs to be pushed and popped | 426 | // calculate the data for callee_preserved_regs to be pushed and popped |
| 447 | var callee_preserved_regs_push_data: u32 = 0x0; | 427 | var callee_preserved_regs_push_data: u32 = 0x0; |
| | 428 | // TODO this is required on macOS since macOS actively checks for stack alignment |
| | 429 | // at every extern call site. As far as I can tell, macOS accounts for the typical |
| | 430 | // function prologue first 2 instructions of: |
| | 431 | // ... |
| | 432 | // push rbp |
| | 433 | // mov rsp, rbp |
| | 434 | // ... |
| | 435 | // Thus we don't need to adjust the stack for the first push instruction. However, |
| | 436 | // any subsequent push of values on the stack such as when preserving registers, |
| | 437 | // needs to be taken into account here. |
| | 438 | var stack_adjustment: i32 = 0; |
| 448 | inline for (callee_preserved_regs) |reg, i| { | 439 | inline for (callee_preserved_regs) |reg, i| { |
| 449 | if (self.register_manager.isRegAllocated(reg)) { | 440 | if (self.register_manager.isRegAllocated(reg)) { |
| 450 | callee_preserved_regs_push_data |= 1 << @intCast(u5, i); | 441 | callee_preserved_regs_push_data |= 1 << @intCast(u5, i); |
| | 442 | if (self.target.isDarwin()) { |
| | 443 | stack_adjustment += @divExact(reg.size(), 8); |
| | 444 | } |
| 451 | } | 445 | } |
| 452 | } | 446 | } |
| 453 | const data = self.mir_instructions.items(.data); | 447 | const data = self.mir_instructions.items(.data); |
| ... | @@ -466,6 +460,29 @@ fn gen(self: *Self) InnerError!void { | ... | @@ -466,6 +460,29 @@ fn gen(self: *Self) InnerError!void { |
| 466 | }).encode(), | 460 | }).encode(), |
| 467 | .data = undefined, | 461 | .data = undefined, |
| 468 | }); | 462 | }); |
| | 463 | |
| | 464 | // Adjust the stack |
| | 465 | const stack_end = self.max_end_stack; |
| | 466 | if (stack_end > math.maxInt(i32) - stack_adjustment) { |
| | 467 | return self.failSymbol("too much stack used in call parameters", .{}); |
| | 468 | } |
| | 469 | const aligned_stack_end = mem.alignForward(stack_end, self.stack_align); |
| | 470 | if (aligned_stack_end > 0 or stack_adjustment > 0) { |
| | 471 | self.mir_instructions.set(backpatch_stack_sub, .{ |
| | 472 | .tag = .sub, |
| | 473 | .ops = (Mir.Ops{ |
| | 474 | .reg1 = .rsp, |
| | 475 | }).encode(), |
| | 476 | .data = .{ .imm = @intCast(i32, aligned_stack_end) + stack_adjustment }, |
| | 477 | }); |
| | 478 | self.mir_instructions.set(backpatch_stack_add, .{ |
| | 479 | .tag = .add, |
| | 480 | .ops = (Mir.Ops{ |
| | 481 | .reg1 = .rsp, |
| | 482 | }).encode(), |
| | 483 | .data = .{ .imm = @intCast(i32, aligned_stack_end) + stack_adjustment }, |
| | 484 | }); |
| | 485 | } |
| 469 | } else { | 486 | } else { |
| 470 | _ = try self.addInst(.{ | 487 | _ = try self.addInst(.{ |
| 471 | .tag = .dbg_prologue_end, | 488 | .tag = .dbg_prologue_end, |