authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-02-16 20:35:03+01:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-02-16 20:35:03+01:00
log09d468b237e58dd70cfa0a4311efab5ddabc9f95
tree47d75db266872db5e4c4cad0c95ee1a2ba51febe
parentd3edf298d18ff89bb0e0a3bfcee84a9fb63b1c6b

x64: overhaul stack handling mechanics

Now, the abstracted stack offsets grow in the same direction as the real stack values in hardware, and allocating stack memory is done by the taking the last stack offset, adding required abi size and aligning to the required abi align. Stack handling is now more natural as it aligns itself with how it works in hardware; hence stepping through the debugger and printing out different stack values is intuitive. Finally, the stack pointers are now correctly aligned to the required (and not necessarily natural) alignment.

3 files changed, 64 insertions(+), 81 deletions(-)

src/arch/x86_64/CodeGen.zig+59-76
...@@ -810,8 +810,8 @@ fn allocMem(self: *Self, inst: Air.Inst.Index, abi_size: u32, abi_align: u32) !u...@@ -810,8 +810,8 @@ fn allocMem(self: *Self, inst: Air.Inst.Index, abi_size: u32, abi_align: u32) !u
810 if (abi_align > self.stack_align)810 if (abi_align > self.stack_align)
811 self.stack_align = abi_align;811 self.stack_align = abi_align;
812 // TODO find a free slot instead of always appending812 // TODO find a free slot instead of always appending
813 const offset = mem.alignForwardGeneric(u32, self.next_stack_offset, abi_align);813 const offset = mem.alignForwardGeneric(u32, self.next_stack_offset + abi_size, abi_align);
814 self.next_stack_offset = offset + abi_size;814 self.next_stack_offset = offset;
815 if (self.next_stack_offset > self.max_end_stack)815 if (self.next_stack_offset > self.max_end_stack)
816 self.max_end_stack = self.next_stack_offset;816 self.max_end_stack = self.next_stack_offset;
817 try self.stack.putNoClobber(self.gpa, offset, .{817 try self.stack.putNoClobber(self.gpa, offset, .{
...@@ -823,7 +823,8 @@ fn allocMem(self: *Self, inst: Air.Inst.Index, abi_size: u32, abi_align: u32) !u...@@ -823,7 +823,8 @@ fn allocMem(self: *Self, inst: Air.Inst.Index, abi_size: u32, abi_align: u32) !u
823823
824/// Use a pointer instruction as the basis for allocating stack memory.824/// Use a pointer instruction as the basis for allocating stack memory.
825fn allocMemPtr(self: *Self, inst: Air.Inst.Index) !u32 {825fn allocMemPtr(self: *Self, inst: Air.Inst.Index) !u32 {
826 const elem_ty = self.air.typeOfIndex(inst).elemType();826 const ptr_ty = self.air.typeOfIndex(inst);
827 const elem_ty = ptr_ty.elemType();
827828
828 if (!elem_ty.hasRuntimeBits()) {829 if (!elem_ty.hasRuntimeBits()) {
829 return self.allocMem(inst, 8, 8);830 return self.allocMem(inst, 8, 8);
...@@ -833,7 +834,7 @@ fn allocMemPtr(self: *Self, inst: Air.Inst.Index) !u32 {...@@ -833,7 +834,7 @@ fn allocMemPtr(self: *Self, inst: Air.Inst.Index) !u32 {
833 return self.fail("type '{}' too big to fit into stack frame", .{elem_ty});834 return self.fail("type '{}' too big to fit into stack frame", .{elem_ty});
834 };835 };
835 // TODO swap this for inst.ty.ptrAlign836 // TODO swap this for inst.ty.ptrAlign
836 const abi_align = elem_ty.abiAlignment(self.target.*);837 const abi_align = ptr_ty.ptrAlignment(self.target.*);
837 return self.allocMem(inst, abi_size, abi_align);838 return self.allocMem(inst, abi_size, abi_align);
838}839}
839840
...@@ -1148,8 +1149,8 @@ fn airSlice(self: *Self, inst: Air.Inst.Index) !void {...@@ -1148,8 +1149,8 @@ fn airSlice(self: *Self, inst: Air.Inst.Index) !void {
1148 const len_ty = self.air.typeOf(bin_op.rhs);1149 const len_ty = self.air.typeOf(bin_op.rhs);
11491150
1150 const stack_offset = @intCast(i32, try self.allocMem(inst, 16, 16));1151 const stack_offset = @intCast(i32, try self.allocMem(inst, 16, 16));
1151 try self.genSetStack(ptr_ty, stack_offset + 8, ptr);1152 try self.genSetStack(ptr_ty, stack_offset, ptr);
1152 try self.genSetStack(len_ty, stack_offset, len);1153 try self.genSetStack(len_ty, stack_offset - 8, len);
1153 const result = MCValue{ .stack_offset = stack_offset };1154 const result = MCValue{ .stack_offset = stack_offset };
11541155
1155 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });1156 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
...@@ -1455,7 +1456,7 @@ fn airSlicePtr(self: *Self, inst: Air.Inst.Index) !void {...@@ -1455,7 +1456,7 @@ fn airSlicePtr(self: *Self, inst: Air.Inst.Index) !void {
1455 const dst_mcv: MCValue = blk: {1456 const dst_mcv: MCValue = blk: {
1456 switch (operand) {1457 switch (operand) {
1457 .stack_offset => |off| {1458 .stack_offset => |off| {
1458 break :blk MCValue{ .stack_offset = off + 8 };1459 break :blk MCValue{ .stack_offset = off };
1459 },1460 },
1460 else => return self.fail("TODO implement slice_ptr for {}", .{operand}),1461 else => return self.fail("TODO implement slice_ptr for {}", .{operand}),
1461 }1462 }
...@@ -1472,7 +1473,7 @@ fn airSliceLen(self: *Self, inst: Air.Inst.Index) !void {...@@ -1472,7 +1473,7 @@ fn airSliceLen(self: *Self, inst: Air.Inst.Index) !void {
1472 const dst_mcv: MCValue = blk: {1473 const dst_mcv: MCValue = blk: {
1473 switch (operand) {1474 switch (operand) {
1474 .stack_offset => |off| {1475 .stack_offset => |off| {
1475 break :blk MCValue{ .stack_offset = off };1476 break :blk MCValue{ .stack_offset = off - 8 };
1476 },1477 },
1477 else => return self.fail("TODO implement slice_len for {}", .{operand}),1478 else => return self.fail("TODO implement slice_len for {}", .{operand}),
1478 }1479 }
...@@ -1540,7 +1541,7 @@ fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void {...@@ -1540,7 +1541,7 @@ fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void {
1540 .reg2 = .rbp,1541 .reg2 = .rbp,
1541 .flags = 0b01,1542 .flags = 0b01,
1542 }).encode(),1543 }).encode(),
1543 .data = .{ .imm = @bitCast(u32, -@intCast(i32, off + 16)) },1544 .data = .{ .imm = @bitCast(u32, -@intCast(i32, off)) },
1544 });1545 });
1545 },1546 },
1546 else => return self.fail("TODO implement slice_elem_val when slice is {}", .{slice_mcv}),1547 else => return self.fail("TODO implement slice_elem_val when slice is {}", .{slice_mcv}),
...@@ -1571,7 +1572,6 @@ fn airArrayElemVal(self: *Self, inst: Air.Inst.Index) !void {...@@ -1571,7 +1572,6 @@ fn airArrayElemVal(self: *Self, inst: Air.Inst.Index) !void {
1571 const bin_op = self.air.instructions.items(.data)[inst].bin_op;1572 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
1572 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {1573 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
1573 const array_ty = self.air.typeOf(bin_op.lhs);1574 const array_ty = self.air.typeOf(bin_op.lhs);
1574 const array_abi_size = array_ty.abiSize(self.target.*);
1575 const array = try self.resolveInst(bin_op.lhs);1575 const array = try self.resolveInst(bin_op.lhs);
1576 array.freezeIfRegister(&self.register_manager);1576 array.freezeIfRegister(&self.register_manager);
1577 defer array.unfreezeIfRegister(&self.register_manager);1577 defer array.unfreezeIfRegister(&self.register_manager);
...@@ -1597,7 +1597,7 @@ fn airArrayElemVal(self: *Self, inst: Air.Inst.Index) !void {...@@ -1597,7 +1597,7 @@ fn airArrayElemVal(self: *Self, inst: Air.Inst.Index) !void {
1597 .reg1 = addr_reg.to64(),1597 .reg1 = addr_reg.to64(),
1598 .reg2 = .rbp,1598 .reg2 = .rbp,
1599 }).encode(),1599 }).encode(),
1600 .data = .{ .imm = @bitCast(u32, -(off + @intCast(i32, array_abi_size))) },1600 .data = .{ .imm = @bitCast(u32, -off) },
1601 });1601 });
1602 },1602 },
1603 else => return self.fail("TODO implement array_elem_val when array is {}", .{array}),1603 else => return self.fail("TODO implement array_elem_val when array is {}", .{array}),
...@@ -1806,7 +1806,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo...@@ -1806,7 +1806,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo
1806 try self.genSetReg(Type.u32, count_reg, .{ .immediate = @intCast(u32, abi_size) });1806 try self.genSetReg(Type.u32, count_reg, .{ .immediate = @intCast(u32, abi_size) });
18071807
1808 return self.genInlineMemcpy(1808 return self.genInlineMemcpy(
1809 -(off + @intCast(i32, abi_size)),1809 -off,
1810 .rbp,1810 .rbp,
1811 registerAlias(addr_reg, @divExact(reg.size(), 8)),1811 registerAlias(addr_reg, @divExact(reg.size(), 8)),
1812 count_reg.to64(),1812 count_reg.to64(),
...@@ -2093,10 +2093,7 @@ fn structFieldPtr(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, inde...@@ -2093,10 +2093,7 @@ fn structFieldPtr(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, inde
2093 const mcv = try self.resolveInst(operand);2093 const mcv = try self.resolveInst(operand);
2094 const ptr_ty = self.air.typeOf(operand);2094 const ptr_ty = self.air.typeOf(operand);
2095 const struct_ty = ptr_ty.childType();2095 const struct_ty = ptr_ty.childType();
2096 const struct_size = @intCast(u32, struct_ty.abiSize(self.target.*));
2097 const struct_field_offset = @intCast(u32, struct_ty.structFieldOffset(index, self.target.*));2096 const struct_field_offset = @intCast(u32, struct_ty.structFieldOffset(index, self.target.*));
2098 const struct_field_ty = struct_ty.structFieldType(index);
2099 const struct_field_size = @intCast(u32, struct_field_ty.abiSize(self.target.*));
21002097
2101 const dst_mcv: MCValue = result: {2098 const dst_mcv: MCValue = result: {
2102 switch (mcv) {2099 switch (mcv) {
...@@ -2112,8 +2109,7 @@ fn structFieldPtr(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, inde...@@ -2112,8 +2109,7 @@ fn structFieldPtr(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, inde
2112 break :result dst_mcv;2109 break :result dst_mcv;
2113 },2110 },
2114 .ptr_stack_offset => |off| {2111 .ptr_stack_offset => |off| {
2115 const offset_to_field = struct_size - struct_field_offset - struct_field_size;2112 const ptr_stack_offset = off - @intCast(i32, struct_field_offset);
2116 const ptr_stack_offset = off + @intCast(i32, offset_to_field);
2117 break :result MCValue{ .ptr_stack_offset = ptr_stack_offset };2113 break :result MCValue{ .ptr_stack_offset = ptr_stack_offset };
2118 },2114 },
2119 .register => |reg| {2115 .register => |reg| {
...@@ -2153,15 +2149,12 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {...@@ -2153,15 +2149,12 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {
2153 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {2149 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
2154 const mcv = try self.resolveInst(operand);2150 const mcv = try self.resolveInst(operand);
2155 const struct_ty = self.air.typeOf(operand);2151 const struct_ty = self.air.typeOf(operand);
2156 const struct_size = struct_ty.abiSize(self.target.*);
2157 const struct_field_offset = struct_ty.structFieldOffset(index, self.target.*);2152 const struct_field_offset = struct_ty.structFieldOffset(index, self.target.*);
2158 const struct_field_ty = struct_ty.structFieldType(index);2153 const struct_field_ty = struct_ty.structFieldType(index);
2159 const struct_field_size = struct_field_ty.abiSize(self.target.*);
21602154
2161 switch (mcv) {2155 switch (mcv) {
2162 .stack_offset => |off| {2156 .stack_offset => |off| {
2163 const offset_to_field = struct_size - struct_field_offset - struct_field_size;2157 const stack_offset = off - @intCast(i32, struct_field_offset);
2164 const stack_offset = off + @intCast(i32, offset_to_field);
2165 break :result MCValue{ .stack_offset = stack_offset };2158 break :result MCValue{ .stack_offset = stack_offset };
2166 },2159 },
2167 .register => |reg| {2160 .register => |reg| {
...@@ -2369,7 +2362,6 @@ fn genBinMathOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MC...@@ -2369,7 +2362,6 @@ fn genBinMathOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MC
2369 if (off > math.maxInt(i32)) {2362 if (off > math.maxInt(i32)) {
2370 return self.fail("stack offset too large", .{});2363 return self.fail("stack offset too large", .{});
2371 }2364 }
2372 const adj_off = off + @intCast(i32, abi_size);
2373 _ = try self.addInst(.{2365 _ = try self.addInst(.{
2374 .tag = mir_tag,2366 .tag = mir_tag,
2375 .ops = (Mir.Ops{2367 .ops = (Mir.Ops{
...@@ -2377,7 +2369,7 @@ fn genBinMathOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MC...@@ -2377,7 +2369,7 @@ fn genBinMathOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MC
2377 .reg2 = .rbp,2369 .reg2 = .rbp,
2378 .flags = 0b01,2370 .flags = 0b01,
2379 }).encode(),2371 }).encode(),
2380 .data = .{ .imm = @bitCast(u32, -adj_off) },2372 .data = .{ .imm = @bitCast(u32, -off) },
2381 });2373 });
2382 },2374 },
2383 .compare_flags_unsigned => {2375 .compare_flags_unsigned => {
...@@ -2395,7 +2387,6 @@ fn genBinMathOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MC...@@ -2395,7 +2387,6 @@ fn genBinMathOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MC
2395 if (abi_size > 8) {2387 if (abi_size > 8) {
2396 return self.fail("TODO implement ADD/SUB/CMP for stack dst with large ABI", .{});2388 return self.fail("TODO implement ADD/SUB/CMP for stack dst with large ABI", .{});
2397 }2389 }
2398 const adj_off = off + @intCast(i32, abi_size);
23992390
2400 switch (src_mcv) {2391 switch (src_mcv) {
2401 .none => unreachable,2392 .none => unreachable,
...@@ -2411,7 +2402,7 @@ fn genBinMathOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MC...@@ -2411,7 +2402,7 @@ fn genBinMathOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MC
2411 .reg2 = registerAlias(src_reg, @intCast(u32, abi_size)),2402 .reg2 = registerAlias(src_reg, @intCast(u32, abi_size)),
2412 .flags = 0b10,2403 .flags = 0b10,
2413 }).encode(),2404 }).encode(),
2414 .data = .{ .imm = @bitCast(u32, -adj_off) },2405 .data = .{ .imm = @bitCast(u32, -off) },
2415 });2406 });
2416 },2407 },
2417 .immediate => |imm| {2408 .immediate => |imm| {
...@@ -2432,7 +2423,7 @@ fn genBinMathOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MC...@@ -2432,7 +2423,7 @@ fn genBinMathOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MC
2432 else => unreachable,2423 else => unreachable,
2433 };2424 };
2434 const payload = try self.addExtra(Mir.ImmPair{2425 const payload = try self.addExtra(Mir.ImmPair{
2435 .dest_off = @bitCast(u32, -adj_off),2426 .dest_off = @bitCast(u32, -off),
2436 .operand = @truncate(u32, imm),2427 .operand = @truncate(u32, imm),
2437 });2428 });
2438 _ = try self.addInst(.{2429 _ = try self.addInst(.{
...@@ -2583,9 +2574,16 @@ fn airArg(self: *Self, inst: Air.Inst.Index) !void {...@@ -2583,9 +2574,16 @@ fn airArg(self: *Self, inst: Air.Inst.Index) !void {
2583 self.arg_index += 1;2574 self.arg_index += 1;
25842575
2585 const mcv = self.args[arg_index];2576 const mcv = self.args[arg_index];
2577 const max_stack = loop: for (self.args) |arg| {
2578 switch (arg) {
2579 .stack_offset => |last| break :loop last,
2580 else => {},
2581 }
2582 } else 0;
2586 const payload = try self.addExtra(Mir.ArgDbgInfo{2583 const payload = try self.addExtra(Mir.ArgDbgInfo{
2587 .air_inst = inst,2584 .air_inst = inst,
2588 .arg_index = arg_index,2585 .arg_index = arg_index,
2586 .max_stack = @intCast(u32, max_stack),
2589 });2587 });
2590 _ = try self.addInst(.{2588 _ = try self.addInst(.{
2591 .tag = .arg_dbg_info,2589 .tag = .arg_dbg_info,
...@@ -2601,11 +2599,9 @@ fn airArg(self: *Self, inst: Air.Inst.Index) !void {...@@ -2601,11 +2599,9 @@ fn airArg(self: *Self, inst: Air.Inst.Index) !void {
2601 self.register_manager.getRegAssumeFree(reg.to64(), inst);2599 self.register_manager.getRegAssumeFree(reg.to64(), inst);
2602 break :blk mcv;2600 break :blk mcv;
2603 },2601 },
2604 .stack_offset => {2602 .stack_offset => |off| {
2605 const ty = self.air.typeOfIndex(inst);2603 const offset = max_stack - off + 16;
2606 const abi_size = ty.abiSize(self.target.*);2604 break :blk MCValue{ .stack_offset = -offset };
2607 const off = @intCast(i32, (arg_index + 1) * abi_size) + 16;
2608 break :blk MCValue{ .stack_offset = -off };
2609 },2605 },
2610 else => return self.fail("TODO implement arg for {}", .{mcv}),2606 else => return self.fail("TODO implement arg for {}", .{mcv}),
2611 }2607 }
...@@ -2648,7 +2644,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index) !void {...@@ -2648,7 +2644,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index) !void {
2648 var info = try self.resolveCallingConventionValues(fn_ty);2644 var info = try self.resolveCallingConventionValues(fn_ty);
2649 defer info.deinit(self);2645 defer info.deinit(self);
26502646
2651 var stack_adjustment: u32 = 0;2647 var stack_adjustment: ?u32 = null;
2652 for (args) |arg, arg_i| {2648 for (args) |arg, arg_i| {
2653 const mc_arg = info.args[arg_i];2649 const mc_arg = info.args[arg_i];
2654 const arg_ty = self.air.typeOf(arg);2650 const arg_ty = self.air.typeOf(arg);
...@@ -2662,9 +2658,10 @@ fn airCall(self: *Self, inst: Air.Inst.Index) !void {...@@ -2662,9 +2658,10 @@ fn airCall(self: *Self, inst: Air.Inst.Index) !void {
2662 try self.genSetReg(arg_ty, reg, arg_mcv);2658 try self.genSetReg(arg_ty, reg, arg_mcv);
2663 },2659 },
2664 .stack_offset => |off| {2660 .stack_offset => |off| {
2665 const abi_size = @intCast(u32, arg_ty.abiSize(self.target.*));
2666 try self.genSetStackArg(arg_ty, off, arg_mcv);2661 try self.genSetStackArg(arg_ty, off, arg_mcv);
2667 stack_adjustment += abi_size;2662 if (stack_adjustment == null) {
2663 stack_adjustment = @intCast(u32, off);
2664 }
2668 },2665 },
2669 .ptr_stack_offset => {2666 .ptr_stack_offset => {
2670 return self.fail("TODO implement calling with MCValue.ptr_stack_offset arg", .{});2667 return self.fail("TODO implement calling with MCValue.ptr_stack_offset arg", .{});
...@@ -2685,14 +2682,14 @@ fn airCall(self: *Self, inst: Air.Inst.Index) !void {...@@ -2685,14 +2682,14 @@ fn airCall(self: *Self, inst: Air.Inst.Index) !void {
2685 }2682 }
2686 }2683 }
26872684
2688 if (stack_adjustment > 0) {2685 if (stack_adjustment) |off| {
2689 // Adjust the stack2686 // Adjust the stack
2690 _ = try self.addInst(.{2687 _ = try self.addInst(.{
2691 .tag = .sub,2688 .tag = .sub,
2692 .ops = (Mir.Ops{2689 .ops = (Mir.Ops{
2693 .reg1 = .rsp,2690 .reg1 = .rsp,
2694 }).encode(),2691 }).encode(),
2695 .data = .{ .imm = stack_adjustment },2692 .data = .{ .imm = off },
2696 });2693 });
2697 }2694 }
26982695
...@@ -2820,14 +2817,14 @@ fn airCall(self: *Self, inst: Air.Inst.Index) !void {...@@ -2820,14 +2817,14 @@ fn airCall(self: *Self, inst: Air.Inst.Index) !void {
2820 }2817 }
2821 } else unreachable;2818 } else unreachable;
28222819
2823 if (stack_adjustment > 0) {2820 if (stack_adjustment) |off| {
2824 // Readjust the stack2821 // Readjust the stack
2825 _ = try self.addInst(.{2822 _ = try self.addInst(.{
2826 .tag = .add,2823 .tag = .add,
2827 .ops = (Mir.Ops{2824 .ops = (Mir.Ops{
2828 .reg1 = .rsp,2825 .reg1 = .rsp,
2829 }).encode(),2826 }).encode(),
2830 .data = .{ .imm = stack_adjustment },2827 .data = .{ .imm = off },
2831 });2828 });
2832 }2829 }
28332830
...@@ -3583,14 +3580,13 @@ fn genSetStackArg(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerE...@@ -3583,14 +3580,13 @@ fn genSetStackArg(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerE
3583 return self.genSetStackArg(ty, stack_offset, .{ .register = reg });3580 return self.genSetStackArg(ty, stack_offset, .{ .register = reg });
3584 },3581 },
3585 .immediate => |imm| {3582 .immediate => |imm| {
3586 const off = stack_offset + @intCast(i32, abi_size);
3587 switch (abi_size) {3583 switch (abi_size) {
3588 1, 2, 4 => {3584 1, 2, 4 => {
3589 // We have a positive stack offset value but we want a twos complement negative3585 // We have a positive stack offset value but we want a twos complement negative
3590 // offset from rbp, which is at the top of the stack frame.3586 // offset from rbp, which is at the top of the stack frame.
3591 // mov [rbp+offset], immediate3587 // mov [rbp+offset], immediate
3592 const payload = try self.addExtra(Mir.ImmPair{3588 const payload = try self.addExtra(Mir.ImmPair{
3593 .dest_off = @bitCast(u32, -off),3589 .dest_off = @bitCast(u32, -stack_offset),
3594 .operand = @truncate(u32, imm),3590 .operand = @truncate(u32, imm),
3595 });3591 });
3596 _ = try self.addInst(.{3592 _ = try self.addInst(.{
...@@ -3680,7 +3676,7 @@ fn genSetStackArg(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerE...@@ -3680,7 +3676,7 @@ fn genSetStackArg(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerE
3680 // TODO allow for abi_size to be u643676 // TODO allow for abi_size to be u64
3681 try self.genSetReg(Type.u32, count_reg, .{ .immediate = @intCast(u32, abi_size) });3677 try self.genSetReg(Type.u32, count_reg, .{ .immediate = @intCast(u32, abi_size) });
3682 try self.genInlineMemcpy(3678 try self.genInlineMemcpy(
3683 -(stack_offset + @intCast(i32, abi_size)),3679 -stack_offset,
3684 .rsp,3680 .rsp,
3685 addr_reg.to64(),3681 addr_reg.to64(),
3686 count_reg.to64(),3682 count_reg.to64(),
...@@ -3695,14 +3691,14 @@ fn genSetStackArg(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerE...@@ -3695,14 +3691,14 @@ fn genSetStackArg(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerE
3695 .reg2 = registerAlias(reg, @intCast(u32, abi_size)),3691 .reg2 = registerAlias(reg, @intCast(u32, abi_size)),
3696 .flags = 0b10,3692 .flags = 0b10,
3697 }).encode(),3693 }).encode(),
3698 .data = .{ .imm = @bitCast(u32, -(stack_offset + @intCast(i32, abi_size))) },3694 .data = .{ .imm = @bitCast(u32, -stack_offset) },
3699 });3695 });
3700 },3696 },
3701 .ptr_stack_offset => {3697 .ptr_stack_offset => {
3702 const reg = try self.copyToTmpRegister(ty, mcv);3698 const reg = try self.copyToTmpRegister(ty, mcv);
3703 return self.genSetStackArg(ty, stack_offset, MCValue{ .register = reg });3699 return self.genSetStackArg(ty, stack_offset, MCValue{ .register = reg });
3704 },3700 },
3705 .stack_offset => |unadjusted_off| {3701 .stack_offset => |off| {
3706 if (abi_size <= 8) {3702 if (abi_size <= 8) {
3707 const reg = try self.copyToTmpRegister(ty, mcv);3703 const reg = try self.copyToTmpRegister(ty, mcv);
3708 return self.genSetStackArg(ty, stack_offset, MCValue{ .register = reg });3704 return self.genSetStackArg(ty, stack_offset, MCValue{ .register = reg });
...@@ -3725,13 +3721,13 @@ fn genSetStackArg(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerE...@@ -3725,13 +3721,13 @@ fn genSetStackArg(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerE
3725 .reg1 = addr_reg.to64(),3721 .reg1 = addr_reg.to64(),
3726 .reg2 = .rbp,3722 .reg2 = .rbp,
3727 }).encode(),3723 }).encode(),
3728 .data = .{ .imm = @bitCast(u32, -(unadjusted_off + @intCast(i32, abi_size))) },3724 .data = .{ .imm = @bitCast(u32, -off) },
3729 });3725 });
37303726
3731 // TODO allow for abi_size to be u643727 // TODO allow for abi_size to be u64
3732 try self.genSetReg(Type.u32, count_reg, .{ .immediate = @intCast(u32, abi_size) });3728 try self.genSetReg(Type.u32, count_reg, .{ .immediate = @intCast(u32, abi_size) });
3733 try self.genInlineMemcpy(3729 try self.genInlineMemcpy(
3734 -(stack_offset + @intCast(i32, abi_size)),3730 -stack_offset,
3735 .rsp,3731 .rsp,
3736 addr_reg.to64(),3732 addr_reg.to64(),
3737 count_reg.to64(),3733 count_reg.to64(),
...@@ -3767,17 +3763,13 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerErro...@@ -3767,17 +3763,13 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerErro
3767 return self.genSetStack(ty, stack_offset, .{ .register = reg });3763 return self.genSetStack(ty, stack_offset, .{ .register = reg });
3768 },3764 },
3769 .immediate => |x_big| {3765 .immediate => |x_big| {
3770 const adj_off = stack_offset + @intCast(i32, abi_size);3766 if (stack_offset > 128) {
3771 if (adj_off > 128) {
3772 return self.fail("TODO implement set stack variable with large stack offset", .{});3767 return self.fail("TODO implement set stack variable with large stack offset", .{});
3773 }3768 }
3774 switch (abi_size) {3769 switch (abi_size) {
3775 1, 2, 4 => {3770 1, 2, 4 => {
3776 // We have a positive stack offset value but we want a twos complement negative
3777 // offset from rbp, which is at the top of the stack frame.
3778 // mov [rbp+offset], immediate
3779 const payload = try self.addExtra(Mir.ImmPair{3771 const payload = try self.addExtra(Mir.ImmPair{
3780 .dest_off = @bitCast(u32, -adj_off),3772 .dest_off = @bitCast(u32, -stack_offset),
3781 .operand = @truncate(u32, x_big),3773 .operand = @truncate(u32, x_big),
3782 });3774 });
3783 _ = try self.addInst(.{3775 _ = try self.addInst(.{
...@@ -3795,15 +3787,11 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerErro...@@ -3795,15 +3787,11 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerErro
3795 });3787 });
3796 },3788 },
3797 8 => {3789 8 => {
3798 // We have a positive stack offset value but we want a twos complement negative
3799 // offset from rbp, which is at the top of the stack frame.
3800 const negative_offset = -adj_off;
3801
3802 // 64 bit write to memory would take two mov's anyways so we3790 // 64 bit write to memory would take two mov's anyways so we
3803 // insted just use two 32 bit writes to avoid register allocation3791 // insted just use two 32 bit writes to avoid register allocation
3804 {3792 {
3805 const payload = try self.addExtra(Mir.ImmPair{3793 const payload = try self.addExtra(Mir.ImmPair{
3806 .dest_off = @bitCast(u32, negative_offset + 4),3794 .dest_off = @bitCast(u32, -stack_offset + 4),
3807 .operand = @truncate(u32, x_big >> 32),3795 .operand = @truncate(u32, x_big >> 32),
3808 });3796 });
3809 _ = try self.addInst(.{3797 _ = try self.addInst(.{
...@@ -3817,7 +3805,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerErro...@@ -3817,7 +3805,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerErro
3817 }3805 }
3818 {3806 {
3819 const payload = try self.addExtra(Mir.ImmPair{3807 const payload = try self.addExtra(Mir.ImmPair{
3820 .dest_off = @bitCast(u32, negative_offset),3808 .dest_off = @bitCast(u32, -stack_offset),
3821 .operand = @truncate(u32, x_big),3809 .operand = @truncate(u32, x_big),
3822 });3810 });
3823 _ = try self.addInst(.{3811 _ = try self.addInst(.{
...@@ -3839,7 +3827,6 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerErro...@@ -3839,7 +3827,6 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerErro
3839 if (stack_offset > math.maxInt(i32)) {3827 if (stack_offset > math.maxInt(i32)) {
3840 return self.fail("stack offset too large", .{});3828 return self.fail("stack offset too large", .{});
3841 }3829 }
3842 const adj_off = stack_offset + @intCast(i32, abi_size);
3843 _ = try self.addInst(.{3830 _ = try self.addInst(.{
3844 .tag = .mov,3831 .tag = .mov,
3845 .ops = (Mir.Ops{3832 .ops = (Mir.Ops{
...@@ -3847,7 +3834,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerErro...@@ -3847,7 +3834,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerErro
3847 .reg2 = registerAlias(reg, @intCast(u32, abi_size)),3834 .reg2 = registerAlias(reg, @intCast(u32, abi_size)),
3848 .flags = 0b10,3835 .flags = 0b10,
3849 }).encode(),3836 }).encode(),
3850 .data = .{ .imm = @bitCast(u32, -adj_off) },3837 .data = .{ .imm = @bitCast(u32, -stack_offset) },
3851 });3838 });
3852 },3839 },
3853 .memory,3840 .memory,
...@@ -3913,7 +3900,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerErro...@@ -3913,7 +3900,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerErro
3913 try self.genSetReg(Type.u32, count_reg, .{ .immediate = @intCast(u32, abi_size) });3900 try self.genSetReg(Type.u32, count_reg, .{ .immediate = @intCast(u32, abi_size) });
39143901
3915 return self.genInlineMemcpy(3902 return self.genInlineMemcpy(
3916 -(stack_offset + @intCast(i32, abi_size)),3903 -stack_offset,
3917 .rbp,3904 .rbp,
3918 addr_reg.to64(),3905 addr_reg.to64(),
3919 count_reg.to64(),3906 count_reg.to64(),
...@@ -3952,14 +3939,14 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerErro...@@ -3952,14 +3939,14 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerErro
3952 .reg1 = addr_reg.to64(),3939 .reg1 = addr_reg.to64(),
3953 .reg2 = .rbp,3940 .reg2 = .rbp,
3954 }).encode(),3941 }).encode(),
3955 .data = .{ .imm = @bitCast(u32, -(off + @intCast(i32, abi_size))) },3942 .data = .{ .imm = @bitCast(u32, -off) },
3956 });3943 });
39573944
3958 // TODO allow for abi_size to be u643945 // TODO allow for abi_size to be u64
3959 try self.genSetReg(Type.u32, count_reg, .{ .immediate = @intCast(u32, abi_size) });3946 try self.genSetReg(Type.u32, count_reg, .{ .immediate = @intCast(u32, abi_size) });
39603947
3961 return self.genInlineMemcpy(3948 return self.genInlineMemcpy(
3962 -(stack_offset + @intCast(i32, abi_size)),3949 -stack_offset,
3963 .rbp,3950 .rbp,
3964 addr_reg.to64(),3951 addr_reg.to64(),
3965 count_reg.to64(),3952 count_reg.to64(),
...@@ -4073,11 +4060,10 @@ fn genInlineMemcpy(...@@ -4073,11 +4060,10 @@ fn genInlineMemcpy(
4073fn genInlineMemset(self: *Self, ty: Type, stack_offset: i32, value: MCValue) InnerError!void {4060fn genInlineMemset(self: *Self, ty: Type, stack_offset: i32, value: MCValue) InnerError!void {
4074 try self.register_manager.getReg(.rax, null);4061 try self.register_manager.getReg(.rax, null);
4075 const abi_size = ty.abiSize(self.target.*);4062 const abi_size = ty.abiSize(self.target.*);
4076 const adj_off = stack_offset + @intCast(i32, abi_size);4063 if (stack_offset > 128) {
4077 if (adj_off > 128) {
4078 return self.fail("TODO inline memset with large stack offset", .{});4064 return self.fail("TODO inline memset with large stack offset", .{});
4079 }4065 }
4080 const negative_offset = @bitCast(u32, -adj_off);4066 const negative_offset = @bitCast(u32, -stack_offset);
40814067
4082 // We are actually counting `abi_size` bytes; however, we reuse the index register4068 // We are actually counting `abi_size` bytes; however, we reuse the index register
4083 // as both the counter and offset scaler, hence we need to subtract one from `abi_size`4069 // as both the counter and offset scaler, hence we need to subtract one from `abi_size`
...@@ -4165,10 +4151,7 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void...@@ -4165,10 +4151,7 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
4165 const abi_size = ty.abiSize(self.target.*);4151 const abi_size = ty.abiSize(self.target.*);
4166 switch (mcv) {4152 switch (mcv) {
4167 .dead => unreachable,4153 .dead => unreachable,
4168 .ptr_stack_offset => |unadjusted_off| {4154 .ptr_stack_offset => |off| {
4169 const elem_ty = ty.childType();
4170 const elem_abi_size = elem_ty.abiSize(self.target.*);
4171 const off = unadjusted_off + @intCast(i32, elem_abi_size);
4172 if (off < std.math.minInt(i32) or off > std.math.maxInt(i32)) {4155 if (off < std.math.minInt(i32) or off > std.math.maxInt(i32)) {
4173 return self.fail("stack offset too large", .{});4156 return self.fail("stack offset too large", .{});
4174 }4157 }
...@@ -4391,8 +4374,7 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void...@@ -4391,8 +4374,7 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
4391 }4374 }
4392 }4375 }
4393 },4376 },
4394 .stack_offset => |unadjusted_off| {4377 .stack_offset => |off| {
4395 const off = unadjusted_off + @intCast(i32, abi_size);
4396 if (off < std.math.minInt(i32) or off > std.math.maxInt(i32)) {4378 if (off < std.math.minInt(i32) or off > std.math.maxInt(i32)) {
4397 return self.fail("stack offset too large", .{});4379 return self.fail("stack offset too large", .{});
4398 }4380 }
...@@ -4469,8 +4451,8 @@ fn airArrayToSlice(self: *Self, inst: Air.Inst.Index) !void {...@@ -4469,8 +4451,8 @@ fn airArrayToSlice(self: *Self, inst: Air.Inst.Index) !void {
4469 const array_len = array_ty.arrayLenIncludingSentinel();4451 const array_len = array_ty.arrayLenIncludingSentinel();
4470 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else blk: {4452 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else blk: {
4471 const stack_offset = @intCast(i32, try self.allocMem(inst, 16, 16));4453 const stack_offset = @intCast(i32, try self.allocMem(inst, 16, 16));
4472 try self.genSetStack(ptr_ty, stack_offset + 8, ptr);4454 try self.genSetStack(ptr_ty, stack_offset, ptr);
4473 try self.genSetStack(Type.initTag(.u64), stack_offset, .{ .immediate = array_len });4455 try self.genSetStack(Type.initTag(.u64), stack_offset - 8, .{ .immediate = array_len });
4474 break :blk .{ .stack_offset = stack_offset };4456 break :blk .{ .stack_offset = stack_offset };
4475 };4457 };
4476 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });4458 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
...@@ -4883,7 +4865,6 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues {...@@ -4883,7 +4865,6 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues {
4883 var next_stack_offset: u32 = 0;4865 var next_stack_offset: u32 = 0;
4884 var count: usize = param_types.len;4866 var count: usize = param_types.len;
4885 while (count > 0) : (count -= 1) {4867 while (count > 0) : (count -= 1) {
4886 // for (param_types) |ty, i| {
4887 const i = count - 1;4868 const i = count - 1;
4888 const ty = param_types[i];4869 const ty = param_types[i];
4889 if (!ty.hasRuntimeBits()) {4870 if (!ty.hasRuntimeBits()) {
...@@ -4892,6 +4873,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues {...@@ -4892,6 +4873,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues {
4892 continue;4873 continue;
4893 }4874 }
4894 const param_size = @intCast(u32, ty.abiSize(self.target.*));4875 const param_size = @intCast(u32, ty.abiSize(self.target.*));
4876 const param_align = @intCast(u32, ty.abiAlignment(self.target.*));
4895 if (by_reg.get(i)) |int_reg| {4877 if (by_reg.get(i)) |int_reg| {
4896 const aliased_reg = registerAlias(c_abi_int_param_regs[int_reg], param_size);4878 const aliased_reg = registerAlias(c_abi_int_param_regs[int_reg], param_size);
4897 result.args[i] = .{ .register = aliased_reg };4879 result.args[i] = .{ .register = aliased_reg };
...@@ -4902,8 +4884,9 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues {...@@ -4902,8 +4884,9 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues {
4902 // such as ptr and len of slices as separate registers.4884 // such as ptr and len of slices as separate registers.
4903 // TODO: also we need to honor the C ABI for relevant types rather than passing on4885 // TODO: also we need to honor the C ABI for relevant types rather than passing on
4904 // the stack here.4886 // the stack here.
4905 result.args[i] = .{ .stack_offset = @intCast(i32, next_stack_offset) };4887 const offset = mem.alignForwardGeneric(u32, next_stack_offset + param_size, param_align);
4906 next_stack_offset += param_size;4888 result.args[i] = .{ .stack_offset = @intCast(i32, offset) };
4889 next_stack_offset = offset;
4907 }4890 }
4908 }4891 }
49094892
src/arch/x86_64/Emit.zig+4-5
...@@ -931,16 +931,15 @@ fn mirArgDbgInfo(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {...@@ -931,16 +931,15 @@ fn mirArgDbgInfo(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
931 const payload = emit.mir.instructions.items(.data)[inst].payload;931 const payload = emit.mir.instructions.items(.data)[inst].payload;
932 const arg_dbg_info = emit.mir.extraData(Mir.ArgDbgInfo, payload).data;932 const arg_dbg_info = emit.mir.extraData(Mir.ArgDbgInfo, payload).data;
933 const mcv = emit.mir.function.args[arg_dbg_info.arg_index];933 const mcv = emit.mir.function.args[arg_dbg_info.arg_index];
934 try emit.genArgDbgInfo(arg_dbg_info.air_inst, mcv, arg_dbg_info.arg_index);934 try emit.genArgDbgInfo(arg_dbg_info.air_inst, mcv, arg_dbg_info.max_stack);
935}935}
936936
937fn genArgDbgInfo(emit: *Emit, inst: Air.Inst.Index, mcv: MCValue, arg_index: u32) !void {937fn genArgDbgInfo(emit: *Emit, inst: Air.Inst.Index, mcv: MCValue, max_stack: u32) !void {
938 const ty_str = emit.mir.function.air.instructions.items(.data)[inst].ty_str;938 const ty_str = emit.mir.function.air.instructions.items(.data)[inst].ty_str;
939 const zir = &emit.mir.function.mod_fn.owner_decl.getFileScope().zir;939 const zir = &emit.mir.function.mod_fn.owner_decl.getFileScope().zir;
940 const name = zir.nullTerminatedString(ty_str.str);940 const name = zir.nullTerminatedString(ty_str.str);
941 const name_with_null = name.ptr[0 .. name.len + 1];941 const name_with_null = name.ptr[0 .. name.len + 1];
942 const ty = emit.mir.function.air.getRefType(ty_str.ty);942 const ty = emit.mir.function.air.getRefType(ty_str.ty);
943 const abi_size = ty.abiSize(emit.bin_file.options.target);
944943
945 switch (mcv) {944 switch (mcv) {
946 .register => |reg| {945 .register => |reg| {
...@@ -960,7 +959,7 @@ fn genArgDbgInfo(emit: *Emit, inst: Air.Inst.Index, mcv: MCValue, arg_index: u32...@@ -960,7 +959,7 @@ fn genArgDbgInfo(emit: *Emit, inst: Air.Inst.Index, mcv: MCValue, arg_index: u32
960 .none => {},959 .none => {},
961 }960 }
962 },961 },
963 .stack_offset => {962 .stack_offset => |off| {
964 switch (emit.debug_output) {963 switch (emit.debug_output) {
965 .dwarf => |dbg_out| {964 .dwarf => |dbg_out| {
966 // we add here +16 like we do in airArg in CodeGen since we refer directly to965 // we add here +16 like we do in airArg in CodeGen since we refer directly to
...@@ -968,7 +967,7 @@ fn genArgDbgInfo(emit: *Emit, inst: Air.Inst.Index, mcv: MCValue, arg_index: u32...@@ -968,7 +967,7 @@ fn genArgDbgInfo(emit: *Emit, inst: Air.Inst.Index, mcv: MCValue, arg_index: u32
968 // prologue, and 8 bytes for return address.967 // prologue, and 8 bytes for return address.
969 // TODO we need to make this more generic if we don't use rbp as the frame pointer968 // TODO we need to make this more generic if we don't use rbp as the frame pointer
970 // for example when -fomit-frame-pointer is set.969 // for example when -fomit-frame-pointer is set.
971 const disp = @intCast(i32, arg_index * abi_size + 16);970 const disp = @intCast(i32, max_stack) - off + 16;
972 try dbg_out.dbg_info.ensureUnusedCapacity(8);971 try dbg_out.dbg_info.ensureUnusedCapacity(8);
973 dbg_out.dbg_info.appendAssumeCapacity(link.File.Elf.abbrev_parameter);972 dbg_out.dbg_info.appendAssumeCapacity(link.File.Elf.abbrev_parameter);
974 const fixup = dbg_out.dbg_info.items.len;973 const fixup = dbg_out.dbg_info.items.len;
src/arch/x86_64/Mir.zig+1
...@@ -413,6 +413,7 @@ pub const DbgLineColumn = struct {...@@ -413,6 +413,7 @@ pub const DbgLineColumn = struct {
413pub const ArgDbgInfo = struct {413pub const ArgDbgInfo = struct {
414 air_inst: Air.Inst.Index,414 air_inst: Air.Inst.Index,
415 arg_index: u32,415 arg_index: u32,
416 max_stack: u32,
416};417};
417418
418pub fn deinit(mir: *Mir, gpa: std.mem.Allocator) void {419pub fn deinit(mir: *Mir, gpa: std.mem.Allocator) void {