@@ -83,6 +83,8 @@ max_end_stack: u32 = 0,
8383/// to place a new stack allocation, it goes here, and then bumps `max_end_stack`.
8484next_stack_offset : u32 = 0 ,
8585
86+ saved_regs_stack_space : u32 = 0 ,
87+
8688/// Debug field, used to find bugs in the compiler.
8789air_bookkeeping : @TypeOf (air_bookkeeping_init ) = air_bookkeeping_init ,
8890
@@ -350,12 +352,7 @@ pub fn addExtraAssumeCapacity(self: *Self, extra: anytype) u32 {
350352fn gen (self : * Self ) ! void {
351353 const cc = self .fn_type .fnCallingConvention ();
352354 if (cc != .Naked ) {
353- // TODO Finish function prologue and epilogue for aarch64.
354-
355355 // stp fp, lr, [sp, #-16]!
356- // mov fp, sp
357- // sub sp, sp, #reloc
358-
359356 _ = try self .addInst (.{
360357 .tag = .stp ,
361358 .data = .{ .load_store_register_pair = .{
@@ -366,11 +363,19 @@ fn gen(self: *Self) !void {
366363 } },
367364 });
368365
366+ // <store other registers>
367+ const backpatch_save_registers = try self .addInst (.{
368+ .tag = .nop ,
369+ .data = .{ .nop = {} },
370+ });
371+
372+ // mov fp, sp
369373 _ = try self .addInst (.{
370374 .tag = .mov_to_from_sp ,
371375 .data = .{ .rr = .{ .rd = .x29 , .rn = .xzr } },
372376 });
373377
378+ // sub sp, sp, #reloc
374379 const backpatch_reloc = try self .addInst (.{
375380 .tag = .nop ,
376381 .data = .{ .nop = {} },
@@ -383,10 +388,33 @@ fn gen(self: *Self) !void {
383388
384389 try self .genBody (self .air .getMainBody ());
385390
391+ // Backpatch push callee saved regs
392+ var saved_regs : u32 = 0 ;
393+ self .saved_regs_stack_space = 16 ;
394+ inline for (callee_preserved_regs ) | reg | {
395+ if (self .register_manager .isRegAllocated (reg )) {
396+ saved_regs |= @as (u32 , 1 ) << reg .id ();
397+ self .saved_regs_stack_space += 8 ;
398+ }
399+ }
400+
401+ // Emit.mirPopPushRegs automatically adds extra empty space so
402+ // that sp is always aligned to 16
403+ if (! std .mem .isAlignedGeneric (u32 , self .saved_regs_stack_space , 16 )) {
404+ self .saved_regs_stack_space += 8 ;
405+ }
406+ assert (std .mem .isAlignedGeneric (u32 , self .saved_regs_stack_space , 16 ));
407+
408+ self .mir_instructions .set (backpatch_save_registers , .{
409+ .tag = .push_regs ,
410+ .data = .{ .reg_list = saved_regs },
411+ });
412+
386413 // Backpatch stack offset
387- const stack_end = self .max_end_stack ;
388- const aligned_stack_end = mem .alignForward (stack_end , self .stack_align );
389- if (math .cast (u12 , aligned_stack_end )) | size | {
414+ const total_stack_size = self .max_end_stack + self .saved_regs_stack_space ;
415+ const aligned_total_stack_end = mem .alignForwardGeneric (u32 , total_stack_size , self .stack_align );
416+ const stack_size = aligned_total_stack_end - self .saved_regs_stack_space ;
417+ if (math .cast (u12 , stack_size )) | size | {
390418 self .mir_instructions .set (backpatch_reloc , .{
391419 .tag = .sub_immediate ,
392420 .data = .{ .rr_imm12_sh = .{ .rd = .xzr , .rn = .xzr , .imm12 = size } },
@@ -418,7 +446,13 @@ fn gen(self: *Self) !void {
418446 // add sp, sp, #stack_size
419447 _ = try self .addInst (.{
420448 .tag = .add_immediate ,
421- .data = .{ .rr_imm12_sh = .{ .rd = .xzr , .rn = .xzr , .imm12 = @intCast (u12 , aligned_stack_end ) } },
449+ .data = .{ .rr_imm12_sh = .{ .rd = .xzr , .rn = .xzr , .imm12 = @intCast (u12 , stack_size ) } },
450+ });
451+
452+ // <load other registers>
453+ _ = try self .addInst (.{
454+ .tag = .pop_regs ,
455+ .data = .{ .reg_list = saved_regs },
422456 });
423457
424458 // ldp fp, lr, [sp], #16
@@ -1754,7 +1788,7 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void {
17541788 },
17551789 },
17561790 }),
1757- else = > return self .fail ("TODO implement condr when condition is {s}" , .{@tagName (cond )}),
1791+ else = > return self .fail ("TODO implement condbr when condition is {s}" , .{@tagName (cond )}),
17581792 };
17591793
17601794 // Capture the state of register and stack allocation state so that we can revert to it.
0 commit comments