| ... | @@ -433,7 +433,7 @@ pub fn generate( | ... | @@ -433,7 +433,7 @@ pub fn generate( |
| 433 | .prev_di_pc = 0, | 433 | .prev_di_pc = 0, |
| 434 | .prev_di_line = module_fn.lbrace_line, | 434 | .prev_di_line = module_fn.lbrace_line, |
| 435 | .prev_di_column = module_fn.lbrace_column, | 435 | .prev_di_column = module_fn.lbrace_column, |
| 436 | .stack_size = mem.alignForwardGeneric(u32, function.max_end_stack, function.stack_align), | 436 | .stack_size = function.max_end_stack, |
| 437 | .saved_regs_stack_space = function.saved_regs_stack_space, | 437 | .saved_regs_stack_space = function.saved_regs_stack_space, |
| 438 | }; | 438 | }; |
| 439 | defer emit.deinit(); | 439 | defer emit.deinit(); |
| ... | @@ -560,6 +560,7 @@ fn gen(self: *Self) !void { | ... | @@ -560,6 +560,7 @@ fn gen(self: *Self) !void { |
| 560 | const total_stack_size = self.max_end_stack + self.saved_regs_stack_space; | 560 | const total_stack_size = self.max_end_stack + self.saved_regs_stack_space; |
| 561 | const aligned_total_stack_end = mem.alignForwardGeneric(u32, total_stack_size, self.stack_align); | 561 | const aligned_total_stack_end = mem.alignForwardGeneric(u32, total_stack_size, self.stack_align); |
| 562 | const stack_size = aligned_total_stack_end - self.saved_regs_stack_space; | 562 | const stack_size = aligned_total_stack_end - self.saved_regs_stack_space; |
| | 563 | self.max_end_stack = stack_size; |
| 563 | if (math.cast(u12, stack_size)) |size| { | 564 | if (math.cast(u12, stack_size)) |size| { |
| 564 | self.mir_instructions.set(backpatch_reloc, .{ | 565 | self.mir_instructions.set(backpatch_reloc, .{ |
| 565 | .tag = .sub_immediate, | 566 | .tag = .sub_immediate, |
| ... | @@ -982,11 +983,16 @@ fn allocMem( | ... | @@ -982,11 +983,16 @@ fn allocMem( |
| 982 | assert(abi_size > 0); | 983 | assert(abi_size > 0); |
| 983 | assert(abi_align > 0); | 984 | assert(abi_align > 0); |
| 984 | | 985 | |
| 985 | if (abi_align > self.stack_align) | 986 | // In order to efficiently load and store stack items that fit |
| 986 | self.stack_align = abi_align; | 987 | // into registers, we bump up the alignment to the next power of |
| | 988 | // two. |
| | 989 | const adjusted_align = if (abi_size > 8) |
| | 990 | abi_align |
| | 991 | else |
| | 992 | std.math.ceilPowerOfTwoAssert(u32, abi_size); |
| 987 | | 993 | |
| 988 | // TODO find a free slot instead of always appending | 994 | // TODO find a free slot instead of always appending |
| 989 | const offset = mem.alignForwardGeneric(u32, self.next_stack_offset, abi_align) + abi_size; | 995 | const offset = mem.alignForwardGeneric(u32, self.next_stack_offset, adjusted_align) + abi_size; |
| 990 | self.next_stack_offset = offset; | 996 | self.next_stack_offset = offset; |
| 991 | self.max_end_stack = @max(self.max_end_stack, self.next_stack_offset); | 997 | self.max_end_stack = @max(self.max_end_stack, self.next_stack_offset); |
| 992 | | 998 | |
| ... | @@ -5396,7 +5402,7 @@ fn setRegOrMem(self: *Self, ty: Type, loc: MCValue, val: MCValue) !void { | ... | @@ -5396,7 +5402,7 @@ fn setRegOrMem(self: *Self, ty: Type, loc: MCValue, val: MCValue) !void { |
| 5396 | } | 5402 | } |
| 5397 | | 5403 | |
| 5398 | fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerError!void { | 5404 | fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerError!void { |
| 5399 | const abi_size = ty.abiSize(self.target.*); | 5405 | const abi_size = @intCast(u32, ty.abiSize(self.target.*)); |
| 5400 | switch (mcv) { | 5406 | switch (mcv) { |
| 5401 | .dead => unreachable, | 5407 | .dead => unreachable, |
| 5402 | .unreach, .none => return, // Nothing to do. | 5408 | .unreach, .none => return, // Nothing to do. |
| ... | @@ -5404,7 +5410,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro | ... | @@ -5404,7 +5410,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro |
| 5404 | if (!self.wantSafety()) | 5410 | if (!self.wantSafety()) |
| 5405 | return; // The already existing value will do just fine. | 5411 | return; // The already existing value will do just fine. |
| 5406 | // TODO Upgrade this to a memset call when we have that available. | 5412 | // TODO Upgrade this to a memset call when we have that available. |
| 5407 | switch (ty.abiSize(self.target.*)) { | 5413 | switch (abi_size) { |
| 5408 | 1 => return self.genSetStack(ty, stack_offset, .{ .immediate = 0xaa }), | 5414 | 1 => return self.genSetStack(ty, stack_offset, .{ .immediate = 0xaa }), |
| 5409 | 2 => return self.genSetStack(ty, stack_offset, .{ .immediate = 0xaaaa }), | 5415 | 2 => return self.genSetStack(ty, stack_offset, .{ .immediate = 0xaaaa }), |
| 5410 | 4 => return self.genSetStack(ty, stack_offset, .{ .immediate = 0xaaaaaaaa }), | 5416 | 4 => return self.genSetStack(ty, stack_offset, .{ .immediate = 0xaaaaaaaa }), |
| ... | @@ -5426,6 +5432,8 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro | ... | @@ -5426,6 +5432,8 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro |
| 5426 | .register => |reg| { | 5432 | .register => |reg| { |
| 5427 | switch (abi_size) { | 5433 | switch (abi_size) { |
| 5428 | 1, 2, 4, 8 => { | 5434 | 1, 2, 4, 8 => { |
| | 5435 | assert(std.mem.isAlignedGeneric(u32, stack_offset, abi_size)); |
| | 5436 | |
| 5429 | const tag: Mir.Inst.Tag = switch (abi_size) { | 5437 | const tag: Mir.Inst.Tag = switch (abi_size) { |
| 5430 | 1 => .strb_stack, | 5438 | 1 => .strb_stack, |
| 5431 | 2 => .strh_stack, | 5439 | 2 => .strh_stack, |
| ... | @@ -5438,7 +5446,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro | ... | @@ -5438,7 +5446,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro |
| 5438 | .tag = tag, | 5446 | .tag = tag, |
| 5439 | .data = .{ .load_store_stack = .{ | 5447 | .data = .{ .load_store_stack = .{ |
| 5440 | .rt = rt, | 5448 | .rt = rt, |
| 5441 | .offset = @intCast(u32, stack_offset), | 5449 | .offset = stack_offset, |
| 5442 | } }, | 5450 | } }, |
| 5443 | }); | 5451 | }); |
| 5444 | }, | 5452 | }, |
| ... | @@ -6001,9 +6009,10 @@ fn airSelect(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -6001,9 +6009,10 @@ fn airSelect(self: *Self, inst: Air.Inst.Index) !void { |
| 6001 | } | 6009 | } |
| 6002 | | 6010 | |
| 6003 | fn airShuffle(self: *Self, inst: Air.Inst.Index) !void { | 6011 | fn airShuffle(self: *Self, inst: Air.Inst.Index) !void { |
| 6004 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | 6012 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| | 6013 | const extra = self.air.extraData(Air.Shuffle, ty_pl.payload).data; |
| 6005 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement airShuffle for {}", .{self.target.cpu.arch}); | 6014 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement airShuffle for {}", .{self.target.cpu.arch}); |
| 6006 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); | 6015 | return self.finishAir(inst, result, .{ extra.a, extra.b, .none }); |
| 6007 | } | 6016 | } |
| 6008 | | 6017 | |
| 6009 | fn airReduce(self: *Self, inst: Air.Inst.Index) !void { | 6018 | fn airReduce(self: *Self, inst: Air.Inst.Index) !void { |