| ... | @@ -809,10 +809,9 @@ fn allocMem(self: *Self, inst: Air.Inst.Index, abi_size: u32, abi_align: u32) !u | ... | @@ -809,10 +809,9 @@ fn allocMem(self: *Self, inst: Air.Inst.Index, abi_size: u32, abi_align: u32) !u |
| 809 | if (abi_align > self.stack_align) | 809 | if (abi_align > self.stack_align) |
| 810 | self.stack_align = abi_align; | 810 | self.stack_align = abi_align; |
| 811 | // TODO find a free slot instead of always appending | 811 | // TODO find a free slot instead of always appending |
| 812 | const offset = mem.alignForwardGeneric(u32, self.next_stack_offset, abi_align); | 812 | const offset = mem.alignForwardGeneric(u32, self.next_stack_offset, abi_align) + abi_size; |
| 813 | self.next_stack_offset = offset + abi_size; | 813 | self.next_stack_offset = offset; |
| 814 | if (self.next_stack_offset > self.max_end_stack) | 814 | self.max_end_stack = @maximum(self.max_end_stack, self.next_stack_offset); |
| 815 | self.max_end_stack = self.next_stack_offset; | | |
| 816 | try self.stack.putNoClobber(self.gpa, offset, .{ | 815 | try self.stack.putNoClobber(self.gpa, offset, .{ |
| 817 | .inst = inst, | 816 | .inst = inst, |
| 818 | .size = abi_size, | 817 | .size = abi_size, |
| ... | @@ -825,9 +824,10 @@ fn allocMemPtr(self: *Self, inst: Air.Inst.Index) !u32 { | ... | @@ -825,9 +824,10 @@ fn allocMemPtr(self: *Self, inst: Air.Inst.Index) !u32 { |
| 825 | const elem_ty = self.air.typeOfIndex(inst).elemType(); | 824 | const elem_ty = self.air.typeOfIndex(inst).elemType(); |
| 826 | | 825 | |
| 827 | if (!elem_ty.hasRuntimeBits()) { | 826 | if (!elem_ty.hasRuntimeBits()) { |
| 828 | // As this stack item will never be dereferenced at runtime, | 827 | // return the stack offset 0. Stack offset 0 will be where all |
| 829 | // return the current stack offset | 828 | // zero-sized stack allocations live as non-zero-sized |
| 830 | return self.next_stack_offset; | 829 | // allocations will always have an offset > 0. |
| | 830 | return @as(u32, 0); |
| 831 | } | 831 | } |
| 832 | | 832 | |
| 833 | const target = self.target.*; | 833 | const target = self.target.*; |
| ... | @@ -1097,8 +1097,8 @@ fn airSlice(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1097,8 +1097,8 @@ fn airSlice(self: *Self, inst: Air.Inst.Index) !void { |
| 1097 | const ptr_bytes = @divExact(ptr_bits, 8); | 1097 | const ptr_bytes = @divExact(ptr_bits, 8); |
| 1098 | | 1098 | |
| 1099 | const stack_offset = try self.allocMem(inst, ptr_bytes * 2, ptr_bytes * 2); | 1099 | const stack_offset = try self.allocMem(inst, ptr_bytes * 2, ptr_bytes * 2); |
| 1100 | try self.genSetStack(ptr_ty, stack_offset + ptr_bytes, ptr); | 1100 | try self.genSetStack(ptr_ty, stack_offset, ptr); |
| 1101 | try self.genSetStack(len_ty, stack_offset, len); | 1101 | try self.genSetStack(len_ty, stack_offset - ptr_bytes, len); |
| 1102 | break :result MCValue{ .stack_offset = stack_offset }; | 1102 | break :result MCValue{ .stack_offset = stack_offset }; |
| 1103 | }; | 1103 | }; |
| 1104 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); | 1104 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); |
| ... | @@ -1515,7 +1515,13 @@ fn binOp( | ... | @@ -1515,7 +1515,13 @@ fn binOp( |
| 1515 | const elem_size = elem_ty.abiSize(self.target.*); | 1515 | const elem_size = elem_ty.abiSize(self.target.*); |
| 1516 | | 1516 | |
| 1517 | if (elem_size == 1) { | 1517 | if (elem_size == 1) { |
| 1518 | return try self.binOpRegister(tag, maybe_inst, lhs, rhs, lhs_ty, rhs_ty); | 1518 | const base_tag: Air.Inst.Tag = switch (tag) { |
| | 1519 | .ptr_add => .add, |
| | 1520 | .ptr_sub => .sub, |
| | 1521 | else => unreachable, |
| | 1522 | }; |
| | 1523 | |
| | 1524 | return try self.binOpRegister(base_tag, maybe_inst, lhs, rhs, lhs_ty, rhs_ty); |
| 1519 | } else { | 1525 | } else { |
| 1520 | // convert the offset into a byte offset by | 1526 | // convert the offset into a byte offset by |
| 1521 | // multiplying it with elem_size | 1527 | // multiplying it with elem_size |
| ... | @@ -1724,14 +1730,12 @@ fn airWrapErrUnionErr(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1724,14 +1730,12 @@ fn airWrapErrUnionErr(self: *Self, inst: Air.Inst.Index) !void { |
| 1724 | fn airSlicePtr(self: *Self, inst: Air.Inst.Index) !void { | 1730 | fn airSlicePtr(self: *Self, inst: Air.Inst.Index) !void { |
| 1725 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | 1731 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 1726 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { | 1732 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 1727 | const ptr_bits = self.target.cpu.arch.ptrBitWidth(); | | |
| 1728 | const ptr_bytes = @divExact(ptr_bits, 8); | | |
| 1729 | const mcv = try self.resolveInst(ty_op.operand); | 1733 | const mcv = try self.resolveInst(ty_op.operand); |
| 1730 | switch (mcv) { | 1734 | switch (mcv) { |
| 1731 | .dead, .unreach, .none => unreachable, | 1735 | .dead, .unreach, .none => unreachable, |
| 1732 | .register => unreachable, // a slice doesn't fit in one register | 1736 | .register => unreachable, // a slice doesn't fit in one register |
| 1733 | .stack_offset => |off| { | 1737 | .stack_offset => |off| { |
| 1734 | break :result MCValue{ .stack_offset = off + ptr_bytes }; | 1738 | break :result MCValue{ .stack_offset = off }; |
| 1735 | }, | 1739 | }, |
| 1736 | .memory => |addr| { | 1740 | .memory => |addr| { |
| 1737 | break :result MCValue{ .memory = addr }; | 1741 | break :result MCValue{ .memory = addr }; |
| ... | @@ -1752,7 +1756,7 @@ fn airSliceLen(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1752,7 +1756,7 @@ fn airSliceLen(self: *Self, inst: Air.Inst.Index) !void { |
| 1752 | .dead, .unreach, .none => unreachable, | 1756 | .dead, .unreach, .none => unreachable, |
| 1753 | .register => unreachable, // a slice doesn't fit in one register | 1757 | .register => unreachable, // a slice doesn't fit in one register |
| 1754 | .stack_offset => |off| { | 1758 | .stack_offset => |off| { |
| 1755 | break :result MCValue{ .stack_offset = off }; | 1759 | break :result MCValue{ .stack_offset = off - ptr_bytes }; |
| 1756 | }, | 1760 | }, |
| 1757 | .memory => |addr| { | 1761 | .memory => |addr| { |
| 1758 | break :result MCValue{ .memory = addr + ptr_bytes }; | 1762 | break :result MCValue{ .memory = addr + ptr_bytes }; |
| ... | @@ -1772,7 +1776,7 @@ fn airPtrSliceLenPtr(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1772,7 +1776,7 @@ fn airPtrSliceLenPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 1772 | switch (mcv) { | 1776 | switch (mcv) { |
| 1773 | .dead, .unreach, .none => unreachable, | 1777 | .dead, .unreach, .none => unreachable, |
| 1774 | .ptr_stack_offset => |off| { | 1778 | .ptr_stack_offset => |off| { |
| 1775 | break :result MCValue{ .ptr_stack_offset = off + ptr_bytes }; | 1779 | break :result MCValue{ .ptr_stack_offset = off - ptr_bytes }; |
| 1776 | }, | 1780 | }, |
| 1777 | else => return self.fail("TODO implement ptr_slice_len_ptr for {}", .{mcv}), | 1781 | else => return self.fail("TODO implement ptr_slice_len_ptr for {}", .{mcv}), |
| 1778 | } | 1782 | } |
| ... | @@ -1819,7 +1823,7 @@ fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1819,7 +1823,7 @@ fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void { |
| 1819 | defer if (index_is_register) self.register_manager.unfreezeRegs(&.{index_mcv.register}); | 1823 | defer if (index_is_register) self.register_manager.unfreezeRegs(&.{index_mcv.register}); |
| 1820 | | 1824 | |
| 1821 | const base_mcv: MCValue = switch (slice_mcv) { | 1825 | const base_mcv: MCValue = switch (slice_mcv) { |
| 1822 | .stack_offset => |off| .{ .register = try self.copyToTmpRegister(slice_ptr_field_type, .{ .stack_offset = off + 8 }) }, | 1826 | .stack_offset => |off| .{ .register = try self.copyToTmpRegister(slice_ptr_field_type, .{ .stack_offset = off }) }, |
| 1823 | else => return self.fail("TODO slice_elem_val when slice is {}", .{slice_mcv}), | 1827 | else => return self.fail("TODO slice_elem_val when slice is {}", .{slice_mcv}), |
| 1824 | }; | 1828 | }; |
| 1825 | self.register_manager.freezeRegs(&.{base_mcv.register}); | 1829 | self.register_manager.freezeRegs(&.{base_mcv.register}); |
| ... | @@ -2293,13 +2297,10 @@ fn structFieldPtr(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, inde | ... | @@ -2293,13 +2297,10 @@ fn structFieldPtr(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, inde |
| 2293 | const mcv = try self.resolveInst(operand); | 2297 | const mcv = try self.resolveInst(operand); |
| 2294 | const ptr_ty = self.air.typeOf(operand); | 2298 | const ptr_ty = self.air.typeOf(operand); |
| 2295 | const struct_ty = ptr_ty.childType(); | 2299 | const struct_ty = ptr_ty.childType(); |
| 2296 | const struct_size = @intCast(u32, struct_ty.abiSize(self.target.*)); | | |
| 2297 | const struct_field_offset = @intCast(u32, struct_ty.structFieldOffset(index, self.target.*)); | 2300 | const struct_field_offset = @intCast(u32, struct_ty.structFieldOffset(index, self.target.*)); |
| 2298 | const struct_field_ty = struct_ty.structFieldType(index); | | |
| 2299 | const struct_field_size = @intCast(u32, struct_field_ty.abiSize(self.target.*)); | | |
| 2300 | switch (mcv) { | 2301 | switch (mcv) { |
| 2301 | .ptr_stack_offset => |off| { | 2302 | .ptr_stack_offset => |off| { |
| 2302 | break :result MCValue{ .ptr_stack_offset = off + struct_size - struct_field_offset - struct_field_size }; | 2303 | break :result MCValue{ .ptr_stack_offset = off - struct_field_offset }; |
| 2303 | }, | 2304 | }, |
| 2304 | else => { | 2305 | else => { |
| 2305 | const offset_reg = try self.copyToTmpRegister(ptr_ty, .{ | 2306 | const offset_reg = try self.copyToTmpRegister(ptr_ty, .{ |
| ... | @@ -2621,11 +2622,15 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void { | ... | @@ -2621,11 +2622,15 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void { |
| 2621 | .Pointer => Type.usize, | 2622 | .Pointer => Type.usize, |
| 2622 | .ErrorSet => Type.initTag(.u16), | 2623 | .ErrorSet => Type.initTag(.u16), |
| 2623 | .Optional => blk: { | 2624 | .Optional => blk: { |
| 2624 | if (lhs_ty.isPtrLikeOptional()) { | 2625 | var opt_buffer: Type.Payload.ElemType = undefined; |
| | 2626 | const payload_ty = lhs_ty.optionalChild(&opt_buffer); |
| | 2627 | if (!payload_ty.hasRuntimeBitsIgnoreComptime()) { |
| | 2628 | break :blk Type.initTag(.u1); |
| | 2629 | } else if (lhs_ty.isPtrLikeOptional()) { |
| 2625 | break :blk Type.usize; | 2630 | break :blk Type.usize; |
| | 2631 | } else { |
| | 2632 | return self.fail("TODO AArch64 cmp non-pointer optionals", .{}); |
| 2626 | } | 2633 | } |
| 2627 | | | |
| 2628 | return self.fail("TODO AArch64 cmp optionals", .{}); | | |
| 2629 | }, | 2634 | }, |
| 2630 | .Float => return self.fail("TODO AArch64 cmp floats", .{}), | 2635 | .Float => return self.fail("TODO AArch64 cmp floats", .{}), |
| 2631 | else => unreachable, | 2636 | else => unreachable, |
| ... | @@ -3318,8 +3323,6 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro | ... | @@ -3318,8 +3323,6 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro |
| 3318 | return self.genSetStack(ty, stack_offset, MCValue{ .register = reg }); | 3323 | return self.genSetStack(ty, stack_offset, MCValue{ .register = reg }); |
| 3319 | }, | 3324 | }, |
| 3320 | .register => |reg| { | 3325 | .register => |reg| { |
| 3321 | const adj_off = stack_offset + abi_size; | | |
| 3322 | | | |
| 3323 | switch (abi_size) { | 3326 | switch (abi_size) { |
| 3324 | 1, 2, 4, 8 => { | 3327 | 1, 2, 4, 8 => { |
| 3325 | const tag: Mir.Inst.Tag = switch (abi_size) { | 3328 | const tag: Mir.Inst.Tag = switch (abi_size) { |
| ... | @@ -3334,7 +3337,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro | ... | @@ -3334,7 +3337,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro |
| 3334 | .tag = tag, | 3337 | .tag = tag, |
| 3335 | .data = .{ .load_store_stack = .{ | 3338 | .data = .{ .load_store_stack = .{ |
| 3336 | .rt = rt, | 3339 | .rt = rt, |
| 3337 | .offset = @intCast(u32, adj_off), | 3340 | .offset = @intCast(u32, stack_offset), |
| 3338 | } }, | 3341 | } }, |
| 3339 | }); | 3342 | }); |
| 3340 | }, | 3343 | }, |
| ... | @@ -3430,13 +3433,9 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void | ... | @@ -3430,13 +3433,9 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void |
| 3430 | else => unreachable, // unexpected register size | 3433 | else => unreachable, // unexpected register size |
| 3431 | } | 3434 | } |
| 3432 | }, | 3435 | }, |
| 3433 | .ptr_stack_offset => |unadjusted_off| { | 3436 | .ptr_stack_offset => |off| { |
| 3434 | // TODO: maybe addressing from sp instead of fp | 3437 | // TODO: maybe addressing from sp instead of fp |
| 3435 | const elem_ty = ty.childType(); | 3438 | const imm12 = math.cast(u12, off) catch |
| 3436 | const abi_size = elem_ty.abiSize(self.target.*); | | |
| 3437 | const adj_off = unadjusted_off + abi_size; | | |
| 3438 | | | |
| 3439 | const imm12 = math.cast(u12, adj_off) catch | | |
| 3440 | return self.fail("TODO larger stack offsets", .{}); | 3439 | return self.fail("TODO larger stack offsets", .{}); |
| 3441 | | 3440 | |
| 3442 | _ = try self.addInst(.{ | 3441 | _ = try self.addInst(.{ |
| ... | @@ -3526,9 +3525,8 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void | ... | @@ -3526,9 +3525,8 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void |
| 3526 | try self.genSetReg(ty, reg, .{ .immediate = addr }); | 3525 | try self.genSetReg(ty, reg, .{ .immediate = addr }); |
| 3527 | try self.genLdrRegister(reg, reg, ty.abiSize(self.target.*)); | 3526 | try self.genLdrRegister(reg, reg, ty.abiSize(self.target.*)); |
| 3528 | }, | 3527 | }, |
| 3529 | .stack_offset => |unadjusted_off| { | 3528 | .stack_offset => |off| { |
| 3530 | const abi_size = ty.abiSize(self.target.*); | 3529 | const abi_size = ty.abiSize(self.target.*); |
| 3531 | const adj_off = unadjusted_off + abi_size; | | |
| 3532 | | 3530 | |
| 3533 | switch (abi_size) { | 3531 | switch (abi_size) { |
| 3534 | 1, 2, 4, 8 => { | 3532 | 1, 2, 4, 8 => { |
| ... | @@ -3548,7 +3546,7 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void | ... | @@ -3548,7 +3546,7 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void |
| 3548 | .tag = tag, | 3546 | .tag = tag, |
| 3549 | .data = .{ .load_store_stack = .{ | 3547 | .data = .{ .load_store_stack = .{ |
| 3550 | .rt = rt, | 3548 | .rt = rt, |
| 3551 | .offset = @intCast(u32, adj_off), | 3549 | .offset = @intCast(u32, off), |
| 3552 | } }, | 3550 | } }, |
| 3553 | }); | 3551 | }); |
| 3554 | }, | 3552 | }, |
| ... | @@ -3583,8 +3581,8 @@ fn airArrayToSlice(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -3583,8 +3581,8 @@ fn airArrayToSlice(self: *Self, inst: Air.Inst.Index) !void { |
| 3583 | const ptr_bytes = @divExact(ptr_bits, 8); | 3581 | const ptr_bytes = @divExact(ptr_bits, 8); |
| 3584 | | 3582 | |
| 3585 | const stack_offset = try self.allocMem(inst, ptr_bytes * 2, ptr_bytes * 2); | 3583 | const stack_offset = try self.allocMem(inst, ptr_bytes * 2, ptr_bytes * 2); |
| 3586 | try self.genSetStack(ptr_ty, stack_offset + ptr_bytes, ptr); | 3584 | try self.genSetStack(ptr_ty, stack_offset, ptr); |
| 3587 | try self.genSetStack(Type.initTag(.usize), stack_offset, .{ .immediate = array_len }); | 3585 | try self.genSetStack(Type.initTag(.usize), stack_offset - ptr_bytes, .{ .immediate = array_len }); |
| 3588 | break :result MCValue{ .stack_offset = stack_offset }; | 3586 | break :result MCValue{ .stack_offset = stack_offset }; |
| 3589 | }; | 3587 | }; |
| 3590 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); | 3588 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |