authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-02-17 18:05:30+01:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2022-02-17 18:05:30+01:00
logd1c74ac42dd4f1306a0dcb7acbbf1f95fe515627
tree9d288ff59ca03006e2c8bc243216a27fb9d0138c
parentbaead472d7641bdd96130354bafadc1fb1ed223b
parent3193cc1c1ea1796df2ae40d5a11396d8626a8070
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #10914 from ziglang/x64-more-codegen

stage2,x64: refactor stack mgmt mechanics, implement slice, fix ptr_add and ptr_sub

7 files changed, 284 insertions(+), 326 deletions(-)

src/arch/x86_64/CodeGen.zig+276-314
...@@ -582,10 +582,10 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {...@@ -582,10 +582,10 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
582582
583 switch (air_tags[inst]) {583 switch (air_tags[inst]) {
584 // zig fmt: off584 // zig fmt: off
585 .add, .ptr_add => try self.airAdd(inst),585 .add => try self.airAdd(inst),
586 .addwrap => try self.airAddWrap(inst),586 .addwrap => try self.airAddWrap(inst),
587 .add_sat => try self.airAddSat(inst),587 .add_sat => try self.airAddSat(inst),
588 .sub, .ptr_sub => try self.airSub(inst),588 .sub => try self.airSub(inst),
589 .subwrap => try self.airSubWrap(inst),589 .subwrap => try self.airSubWrap(inst),
590 .sub_sat => try self.airSubSat(inst),590 .sub_sat => try self.airSubSat(inst),
591 .mul => try self.airMul(inst),591 .mul => try self.airMul(inst),
...@@ -597,6 +597,8 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {...@@ -597,6 +597,8 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
597 .shl_sat => try self.airShlSat(inst),597 .shl_sat => try self.airShlSat(inst),
598 .min => try self.airMin(inst),598 .min => try self.airMin(inst),
599 .max => try self.airMax(inst),599 .max => try self.airMax(inst),
600 .ptr_add => try self.airPtrAdd(inst),
601 .ptr_sub => try self.airPtrSub(inst),
600 .slice => try self.airSlice(inst),602 .slice => try self.airSlice(inst),
601603
602 .sqrt,604 .sqrt,
...@@ -808,8 +810,8 @@ fn allocMem(self: *Self, inst: Air.Inst.Index, abi_size: u32, abi_align: u32) !u...@@ -808,8 +810,8 @@ fn allocMem(self: *Self, inst: Air.Inst.Index, abi_size: u32, abi_align: u32) !u
808 if (abi_align > self.stack_align)810 if (abi_align > self.stack_align)
809 self.stack_align = abi_align;811 self.stack_align = abi_align;
810 // TODO find a free slot instead of always appending812 // TODO find a free slot instead of always appending
811 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);
812 self.next_stack_offset = offset + abi_size;814 self.next_stack_offset = offset;
813 if (self.next_stack_offset > self.max_end_stack)815 if (self.next_stack_offset > self.max_end_stack)
814 self.max_end_stack = self.next_stack_offset;816 self.max_end_stack = self.next_stack_offset;
815 try self.stack.putNoClobber(self.gpa, offset, .{817 try self.stack.putNoClobber(self.gpa, offset, .{
...@@ -821,7 +823,8 @@ fn allocMem(self: *Self, inst: Air.Inst.Index, abi_size: u32, abi_align: u32) !u...@@ -821,7 +823,8 @@ fn allocMem(self: *Self, inst: Air.Inst.Index, abi_size: u32, abi_align: u32) !u
821823
822/// Use a pointer instruction as the basis for allocating stack memory.824/// Use a pointer instruction as the basis for allocating stack memory.
823fn allocMemPtr(self: *Self, inst: Air.Inst.Index) !u32 {825fn allocMemPtr(self: *Self, inst: Air.Inst.Index) !u32 {
824 const elem_ty = self.air.typeOfIndex(inst).elemType();826 const ptr_ty = self.air.typeOfIndex(inst);
827 const elem_ty = ptr_ty.elemType();
825828
826 if (!elem_ty.hasRuntimeBits()) {829 if (!elem_ty.hasRuntimeBits()) {
827 return self.allocMem(inst, 8, 8);830 return self.allocMem(inst, 8, 8);
...@@ -831,7 +834,7 @@ fn allocMemPtr(self: *Self, inst: Air.Inst.Index) !u32 {...@@ -831,7 +834,7 @@ fn allocMemPtr(self: *Self, inst: Air.Inst.Index) !u32 {
831 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});
832 };835 };
833 // TODO swap this for inst.ty.ptrAlign836 // TODO swap this for inst.ty.ptrAlign
834 const abi_align = elem_ty.abiAlignment(self.target.*);837 const abi_align = ptr_ty.ptrAlignment(self.target.*);
835 return self.allocMem(inst, abi_size, abi_align);838 return self.allocMem(inst, abi_size, abi_align);
836}839}
837840
...@@ -964,7 +967,7 @@ fn airTrunc(self: *Self, inst: Air.Inst.Index) !void {...@@ -964,7 +967,7 @@ fn airTrunc(self: *Self, inst: Air.Inst.Index) !void {
964 const reg: Register = blk: {967 const reg: Register = blk: {
965 if (operand.isRegister()) {968 if (operand.isRegister()) {
966 if (self.reuseOperand(inst, ty_op.operand, 0, operand)) {969 if (self.reuseOperand(inst, ty_op.operand, 0, operand)) {
967 break :blk operand.register;970 break :blk operand.register.to64();
968 }971 }
969 }972 }
970 const mcv = try self.copyToNewRegister(inst, src_ty, operand);973 const mcv = try self.copyToNewRegister(inst, src_ty, operand);
...@@ -1068,13 +1071,81 @@ fn airMax(self: *Self, inst: Air.Inst.Index) !void {...@@ -1068,13 +1071,81 @@ fn airMax(self: *Self, inst: Air.Inst.Index) !void {
1068 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });1071 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
1069}1072}
10701073
1074fn genPtrBinMathOp(self: *Self, inst: Air.Inst.Index, op_lhs: Air.Inst.Ref, op_rhs: Air.Inst.Ref) !MCValue {
1075 const dst_ty = self.air.typeOfIndex(inst);
1076 const elem_size = dst_ty.elemType2().abiSize(self.target.*);
1077 const ptr = try self.resolveInst(op_lhs);
1078 const offset = try self.resolveInst(op_rhs);
1079 const offset_ty = self.air.typeOf(op_rhs);
1080
1081 ptr.freezeIfRegister(&self.register_manager);
1082 defer ptr.unfreezeIfRegister(&self.register_manager);
1083
1084 offset.freezeIfRegister(&self.register_manager);
1085 defer offset.unfreezeIfRegister(&self.register_manager);
1086
1087 const dst_mcv = blk: {
1088 if (self.reuseOperand(inst, op_lhs, 0, ptr)) {
1089 if (ptr.isMemory() or ptr.isRegister()) break :blk ptr;
1090 }
1091 break :blk try self.copyToNewRegister(inst, dst_ty, ptr);
1092 };
1093
1094 const offset_mcv = blk: {
1095 if (self.reuseOperand(inst, op_rhs, 1, offset)) {
1096 if (offset.isRegister()) break :blk offset;
1097 }
1098 break :blk MCValue{ .register = try self.copyToTmpRegister(offset_ty, offset) };
1099 };
1100
1101 try self.genIMulOpMir(offset_ty, offset_mcv, .{ .immediate = elem_size });
1102
1103 const tag = self.air.instructions.items(.tag)[inst];
1104 switch (tag) {
1105 .ptr_add => try self.genBinMathOpMir(.add, dst_ty, dst_mcv, offset_mcv),
1106 .ptr_sub => try self.genBinMathOpMir(.sub, dst_ty, dst_mcv, offset_mcv),
1107 else => unreachable,
1108 }
1109
1110 return dst_mcv;
1111}
1112
1113fn airPtrAdd(self: *Self, inst: Air.Inst.Index) !void {
1114 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
1115 const result = if (self.liveness.isUnused(inst))
1116 .dead
1117 else
1118 try self.genPtrBinMathOp(inst, bin_op.lhs, bin_op.rhs);
1119 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
1120}
1121
1122fn airPtrSub(self: *Self, inst: Air.Inst.Index) !void {
1123 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
1124 const result = if (self.liveness.isUnused(inst))
1125 .dead
1126 else
1127 try self.genPtrBinMathOp(inst, bin_op.lhs, bin_op.rhs);
1128 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
1129}
1130
1071fn airSlice(self: *Self, inst: Air.Inst.Index) !void {1131fn airSlice(self: *Self, inst: Air.Inst.Index) !void {
1072 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;1132 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
1073 const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data;1133 const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data;
1074 const result: MCValue = if (self.liveness.isUnused(inst))1134
1075 .dead1135 if (self.liveness.isUnused(inst)) {
1076 else1136 return self.finishAir(inst, .dead, .{ bin_op.lhs, bin_op.rhs, .none });
1077 return self.fail("TODO implement slice for {}", .{self.target.cpu.arch});1137 }
1138
1139 const ptr = try self.resolveInst(bin_op.lhs);
1140 const ptr_ty = self.air.typeOf(bin_op.lhs);
1141 const len = try self.resolveInst(bin_op.rhs);
1142 const len_ty = self.air.typeOf(bin_op.rhs);
1143
1144 const stack_offset = @intCast(i32, try self.allocMem(inst, 16, 16));
1145 try self.genSetStack(ptr_ty, stack_offset, ptr);
1146 try self.genSetStack(len_ty, stack_offset - 8, len);
1147 const result = MCValue{ .stack_offset = stack_offset };
1148
1078 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });1149 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
1079}1150}
10801151
...@@ -1378,7 +1449,7 @@ fn airSlicePtr(self: *Self, inst: Air.Inst.Index) !void {...@@ -1378,7 +1449,7 @@ fn airSlicePtr(self: *Self, inst: Air.Inst.Index) !void {
1378 const dst_mcv: MCValue = blk: {1449 const dst_mcv: MCValue = blk: {
1379 switch (operand) {1450 switch (operand) {
1380 .stack_offset => |off| {1451 .stack_offset => |off| {
1381 break :blk MCValue{ .stack_offset = off + 8 };1452 break :blk MCValue{ .stack_offset = off };
1382 },1453 },
1383 else => return self.fail("TODO implement slice_ptr for {}", .{operand}),1454 else => return self.fail("TODO implement slice_ptr for {}", .{operand}),
1384 }1455 }
...@@ -1395,7 +1466,7 @@ fn airSliceLen(self: *Self, inst: Air.Inst.Index) !void {...@@ -1395,7 +1466,7 @@ fn airSliceLen(self: *Self, inst: Air.Inst.Index) !void {
1395 const dst_mcv: MCValue = blk: {1466 const dst_mcv: MCValue = blk: {
1396 switch (operand) {1467 switch (operand) {
1397 .stack_offset => |off| {1468 .stack_offset => |off| {
1398 break :blk MCValue{ .stack_offset = off };1469 break :blk MCValue{ .stack_offset = off - 8 };
1399 },1470 },
1400 else => return self.fail("TODO implement slice_len for {}", .{operand}),1471 else => return self.fail("TODO implement slice_len for {}", .{operand}),
1401 }1472 }
...@@ -1463,7 +1534,7 @@ fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void {...@@ -1463,7 +1534,7 @@ fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void {
1463 .reg2 = .rbp,1534 .reg2 = .rbp,
1464 .flags = 0b01,1535 .flags = 0b01,
1465 }).encode(),1536 }).encode(),
1466 .data = .{ .imm = @bitCast(u32, -@intCast(i32, off + 16)) },1537 .data = .{ .imm = @bitCast(u32, -@intCast(i32, off)) },
1467 });1538 });
1468 },1539 },
1469 else => return self.fail("TODO implement slice_elem_val when slice is {}", .{slice_mcv}),1540 else => return self.fail("TODO implement slice_elem_val when slice is {}", .{slice_mcv}),
...@@ -1494,7 +1565,6 @@ fn airArrayElemVal(self: *Self, inst: Air.Inst.Index) !void {...@@ -1494,7 +1565,6 @@ fn airArrayElemVal(self: *Self, inst: Air.Inst.Index) !void {
1494 const bin_op = self.air.instructions.items(.data)[inst].bin_op;1565 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
1495 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {1566 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
1496 const array_ty = self.air.typeOf(bin_op.lhs);1567 const array_ty = self.air.typeOf(bin_op.lhs);
1497 const array_abi_size = array_ty.abiSize(self.target.*);
1498 const array = try self.resolveInst(bin_op.lhs);1568 const array = try self.resolveInst(bin_op.lhs);
1499 array.freezeIfRegister(&self.register_manager);1569 array.freezeIfRegister(&self.register_manager);
1500 defer array.unfreezeIfRegister(&self.register_manager);1570 defer array.unfreezeIfRegister(&self.register_manager);
...@@ -1520,7 +1590,7 @@ fn airArrayElemVal(self: *Self, inst: Air.Inst.Index) !void {...@@ -1520,7 +1590,7 @@ fn airArrayElemVal(self: *Self, inst: Air.Inst.Index) !void {
1520 .reg1 = addr_reg.to64(),1590 .reg1 = addr_reg.to64(),
1521 .reg2 = .rbp,1591 .reg2 = .rbp,
1522 }).encode(),1592 }).encode(),
1523 .data = .{ .imm = @bitCast(u32, -(off + @intCast(i32, array_abi_size))) },1593 .data = .{ .imm = @bitCast(u32, -off) },
1524 });1594 });
1525 },1595 },
1526 else => return self.fail("TODO implement array_elem_val when array is {}", .{array}),1596 else => return self.fail("TODO implement array_elem_val when array is {}", .{array}),
...@@ -1705,36 +1775,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo...@@ -1705,36 +1775,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo
1705 return self.genSetStack(elem_ty, off, MCValue{ .register = tmp_reg });1775 return self.genSetStack(elem_ty, off, MCValue{ .register = tmp_reg });
1706 }1776 }
17071777
1708 self.register_manager.freezeRegs(&.{ .rax, .rcx });1778 try self.genInlineMemcpy(off, .rbp, elem_ty, ptr);
1709 defer self.register_manager.unfreezeRegs(&.{ .rax, .rcx });
1710
1711 const regs = try self.register_manager.allocRegs(3, .{ null, null, null });
1712 const addr_reg = regs[0];
1713 const count_reg = regs[1];
1714 const tmp_reg = regs[2];
1715
1716 _ = try self.addInst(.{
1717 .tag = .mov,
1718 .ops = (Mir.Ops{
1719 .reg1 = registerAlias(addr_reg, @divExact(reg.size(), 8)),
1720 .reg2 = reg,
1721 }).encode(),
1722 .data = undefined,
1723 });
1724
1725 try self.register_manager.getReg(.rax, null);
1726 try self.register_manager.getReg(.rcx, null);
1727
1728 // TODO allow for abi size to be u64
1729 try self.genSetReg(Type.u32, count_reg, .{ .immediate = @intCast(u32, abi_size) });
1730
1731 return self.genInlineMemcpy(
1732 -(off + @intCast(i32, abi_size)),
1733 .rbp,
1734 registerAlias(addr_reg, @divExact(reg.size(), 8)),
1735 count_reg.to64(),
1736 tmp_reg.to8(),
1737 );
1738 },1779 },
1739 else => return self.fail("TODO implement loading from register into {}", .{dst_mcv}),1780 else => return self.fail("TODO implement loading from register into {}", .{dst_mcv}),
1740 }1781 }
...@@ -2016,10 +2057,7 @@ fn structFieldPtr(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, inde...@@ -2016,10 +2057,7 @@ fn structFieldPtr(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, inde
2016 const mcv = try self.resolveInst(operand);2057 const mcv = try self.resolveInst(operand);
2017 const ptr_ty = self.air.typeOf(operand);2058 const ptr_ty = self.air.typeOf(operand);
2018 const struct_ty = ptr_ty.childType();2059 const struct_ty = ptr_ty.childType();
2019 const struct_size = @intCast(u32, struct_ty.abiSize(self.target.*));
2020 const struct_field_offset = @intCast(u32, struct_ty.structFieldOffset(index, self.target.*));2060 const struct_field_offset = @intCast(u32, struct_ty.structFieldOffset(index, self.target.*));
2021 const struct_field_ty = struct_ty.structFieldType(index);
2022 const struct_field_size = @intCast(u32, struct_field_ty.abiSize(self.target.*));
20232061
2024 const dst_mcv: MCValue = result: {2062 const dst_mcv: MCValue = result: {
2025 switch (mcv) {2063 switch (mcv) {
...@@ -2035,8 +2073,7 @@ fn structFieldPtr(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, inde...@@ -2035,8 +2073,7 @@ fn structFieldPtr(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, inde
2035 break :result dst_mcv;2073 break :result dst_mcv;
2036 },2074 },
2037 .ptr_stack_offset => |off| {2075 .ptr_stack_offset => |off| {
2038 const offset_to_field = struct_size - struct_field_offset - struct_field_size;2076 const ptr_stack_offset = off - @intCast(i32, struct_field_offset);
2039 const ptr_stack_offset = off + @intCast(i32, offset_to_field);
2040 break :result MCValue{ .ptr_stack_offset = ptr_stack_offset };2077 break :result MCValue{ .ptr_stack_offset = ptr_stack_offset };
2041 },2078 },
2042 .register => |reg| {2079 .register => |reg| {
...@@ -2076,15 +2113,12 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {...@@ -2076,15 +2113,12 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {
2076 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {2113 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
2077 const mcv = try self.resolveInst(operand);2114 const mcv = try self.resolveInst(operand);
2078 const struct_ty = self.air.typeOf(operand);2115 const struct_ty = self.air.typeOf(operand);
2079 const struct_size = struct_ty.abiSize(self.target.*);
2080 const struct_field_offset = struct_ty.structFieldOffset(index, self.target.*);2116 const struct_field_offset = struct_ty.structFieldOffset(index, self.target.*);
2081 const struct_field_ty = struct_ty.structFieldType(index);2117 const struct_field_ty = struct_ty.structFieldType(index);
2082 const struct_field_size = struct_field_ty.abiSize(self.target.*);
20832118
2084 switch (mcv) {2119 switch (mcv) {
2085 .stack_offset => |off| {2120 .stack_offset => |off| {
2086 const offset_to_field = struct_size - struct_field_offset - struct_field_size;2121 const stack_offset = off - @intCast(i32, struct_field_offset);
2087 const stack_offset = off + @intCast(i32, offset_to_field);
2088 break :result MCValue{ .stack_offset = stack_offset };2122 break :result MCValue{ .stack_offset = stack_offset };
2089 },2123 },
2090 .register => |reg| {2124 .register => |reg| {
...@@ -2141,14 +2175,6 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {...@@ -2141,14 +2175,6 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {
2141/// Currently, the following ops are supported:2175/// Currently, the following ops are supported:
2142/// ADD, SUB, XOR, OR, AND2176/// ADD, SUB, XOR, OR, AND
2143fn genBinMathOp(self: *Self, inst: Air.Inst.Index, op_lhs: Air.Inst.Ref, op_rhs: Air.Inst.Ref) !MCValue {2177fn genBinMathOp(self: *Self, inst: Air.Inst.Index, op_lhs: Air.Inst.Ref, op_rhs: Air.Inst.Ref) !MCValue {
2144 // We'll handle these ops in two steps.
2145 // 1) Prepare an output location (register or memory)
2146 // This location will be the location of the operand that dies (if one exists)
2147 // or just a temporary register (if one doesn't exist)
2148 // 2) Perform the op with the other argument
2149 // 3) Sometimes, the output location is memory but the op doesn't support it.
2150 // In this case, copy that location to a register, then perform the op to that register instead.
2151 //
2152 // TODO: make this algorithm less bad2178 // TODO: make this algorithm less bad
2153 const lhs = try self.resolveInst(op_lhs);2179 const lhs = try self.resolveInst(op_lhs);
2154 const rhs = try self.resolveInst(op_rhs);2180 const rhs = try self.resolveInst(op_rhs);
...@@ -2161,6 +2187,7 @@ fn genBinMathOp(self: *Self, inst: Air.Inst.Index, op_lhs: Air.Inst.Ref, op_rhs:...@@ -2161,6 +2187,7 @@ fn genBinMathOp(self: *Self, inst: Air.Inst.Index, op_lhs: Air.Inst.Ref, op_rhs:
2161 const dst_ty = self.air.typeOfIndex(inst);2187 const dst_ty = self.air.typeOfIndex(inst);
2162 var dst_mcv: MCValue = undefined;2188 var dst_mcv: MCValue = undefined;
2163 var src_mcv: MCValue = undefined;2189 var src_mcv: MCValue = undefined;
2190
2164 if (self.reuseOperand(inst, op_lhs, 0, lhs)) {2191 if (self.reuseOperand(inst, op_lhs, 0, lhs)) {
2165 // LHS dies; use it as the destination.2192 // LHS dies; use it as the destination.
2166 // Both operands cannot be memory.2193 // Both operands cannot be memory.
...@@ -2207,17 +2234,15 @@ fn genBinMathOp(self: *Self, inst: Air.Inst.Index, op_lhs: Air.Inst.Ref, op_rhs:...@@ -2207,17 +2234,15 @@ fn genBinMathOp(self: *Self, inst: Air.Inst.Index, op_lhs: Air.Inst.Ref, op_rhs:
2207 dst_mcv.freezeIfRegister(&self.register_manager);2234 dst_mcv.freezeIfRegister(&self.register_manager);
2208 defer dst_mcv.unfreezeIfRegister(&self.register_manager);2235 defer dst_mcv.unfreezeIfRegister(&self.register_manager);
22092236
2210 const tmp_reg = try self.copyToTmpRegister(Type.u64, src_mcv);2237 src_mcv = try self.copyToNewRegister(inst, Type.u64, src_mcv);
2211 src_mcv = MCValue{ .register = tmp_reg };
2212 }2238 }
2213 },2239 },
2214 else => {},2240 else => {},
2215 }2241 }
22162242
2217 // Now for step 2, we assing an MIR instruction2243 const tag = self.air.instructions.items(.tag)[inst];
2218 const air_tags = self.air.instructions.items(.tag);2244 switch (tag) {
2219 switch (air_tags[inst]) {2245 .add, .addwrap => try self.genBinMathOpMir(.add, dst_ty, dst_mcv, src_mcv),
2220 .add, .addwrap, .ptr_add => try self.genBinMathOpMir(.add, dst_ty, dst_mcv, src_mcv),
2221 .bool_or, .bit_or => try self.genBinMathOpMir(.@"or", dst_ty, dst_mcv, src_mcv),2246 .bool_or, .bit_or => try self.genBinMathOpMir(.@"or", dst_ty, dst_mcv, src_mcv),
2222 .bool_and, .bit_and => try self.genBinMathOpMir(.@"and", dst_ty, dst_mcv, src_mcv),2247 .bool_and, .bit_and => try self.genBinMathOpMir(.@"and", dst_ty, dst_mcv, src_mcv),
2223 .sub, .subwrap => try self.genBinMathOpMir(.sub, dst_ty, dst_mcv, src_mcv),2248 .sub, .subwrap => try self.genBinMathOpMir(.sub, dst_ty, dst_mcv, src_mcv),
...@@ -2225,7 +2250,6 @@ fn genBinMathOp(self: *Self, inst: Air.Inst.Index, op_lhs: Air.Inst.Ref, op_rhs:...@@ -2225,7 +2250,6 @@ fn genBinMathOp(self: *Self, inst: Air.Inst.Index, op_lhs: Air.Inst.Ref, op_rhs:
2225 .mul, .mulwrap => try self.genIMulOpMir(dst_ty, dst_mcv, src_mcv),2250 .mul, .mulwrap => try self.genIMulOpMir(dst_ty, dst_mcv, src_mcv),
2226 else => unreachable,2251 else => unreachable,
2227 }2252 }
2228
2229 return dst_mcv;2253 return dst_mcv;
2230}2254}
22312255
...@@ -2244,7 +2268,12 @@ fn genBinMathOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MC...@@ -2244,7 +2268,12 @@ fn genBinMathOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MC
2244 .none => unreachable,2268 .none => unreachable,
2245 .undef => try self.genSetReg(dst_ty, dst_reg, .undef),2269 .undef => try self.genSetReg(dst_ty, dst_reg, .undef),
2246 .dead, .unreach => unreachable,2270 .dead, .unreach => unreachable,
2247 .ptr_stack_offset => unreachable,2271 .ptr_stack_offset => {
2272 self.register_manager.freezeRegs(&.{dst_reg});
2273 defer self.register_manager.unfreezeRegs(&.{dst_reg});
2274 const reg = try self.copyToTmpRegister(dst_ty, src_mcv);
2275 return self.genBinMathOpMir(mir_tag, dst_ty, dst_mcv, .{ .register = reg });
2276 },
2248 .ptr_embedded_in_code => unreachable,2277 .ptr_embedded_in_code => unreachable,
2249 .register => |src_reg| {2278 .register => |src_reg| {
2250 _ = try self.addInst(.{2279 _ = try self.addInst(.{
...@@ -2265,21 +2294,21 @@ fn genBinMathOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MC...@@ -2265,21 +2294,21 @@ fn genBinMathOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MC
2265 .data = .{ .imm = @truncate(u32, imm) },2294 .data = .{ .imm = @truncate(u32, imm) },
2266 });2295 });
2267 },2296 },
2268 .embedded_in_code, .memory => {2297 .embedded_in_code,
2298 .memory,
2299 .got_load,
2300 .direct_load,
2301 => {
2269 assert(abi_size <= 8);2302 assert(abi_size <= 8);
2270 self.register_manager.freezeRegs(&.{dst_reg});2303 self.register_manager.freezeRegs(&.{dst_reg});
2271 defer self.register_manager.unfreezeRegs(&.{dst_reg});2304 defer self.register_manager.unfreezeRegs(&.{dst_reg});
2272 const reg = try self.copyToTmpRegister(dst_ty, src_mcv);2305 const reg = try self.copyToTmpRegister(dst_ty, src_mcv);
2273 return self.genBinMathOpMir(mir_tag, dst_ty, dst_mcv, .{ .register = reg });2306 return self.genBinMathOpMir(mir_tag, dst_ty, dst_mcv, .{ .register = reg });
2274 },2307 },
2275 .got_load, .direct_load => {
2276 return self.fail("TODO implement x86 ADD/SUB/CMP source symbol at index in linker", .{});
2277 },
2278 .stack_offset => |off| {2308 .stack_offset => |off| {
2279 if (off > math.maxInt(i32)) {2309 if (off > math.maxInt(i32)) {
2280 return self.fail("stack offset too large", .{});2310 return self.fail("stack offset too large", .{});
2281 }2311 }
2282 const adj_off = off + @intCast(i32, abi_size);
2283 _ = try self.addInst(.{2312 _ = try self.addInst(.{
2284 .tag = mir_tag,2313 .tag = mir_tag,
2285 .ops = (Mir.Ops{2314 .ops = (Mir.Ops{
...@@ -2287,7 +2316,7 @@ fn genBinMathOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MC...@@ -2287,7 +2316,7 @@ fn genBinMathOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MC
2287 .reg2 = .rbp,2316 .reg2 = .rbp,
2288 .flags = 0b01,2317 .flags = 0b01,
2289 }).encode(),2318 }).encode(),
2290 .data = .{ .imm = @bitCast(u32, -adj_off) },2319 .data = .{ .imm = @bitCast(u32, -off) },
2291 });2320 });
2292 },2321 },
2293 .compare_flags_unsigned => {2322 .compare_flags_unsigned => {
...@@ -2305,7 +2334,6 @@ fn genBinMathOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MC...@@ -2305,7 +2334,6 @@ fn genBinMathOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MC
2305 if (abi_size > 8) {2334 if (abi_size > 8) {
2306 return self.fail("TODO implement ADD/SUB/CMP for stack dst with large ABI", .{});2335 return self.fail("TODO implement ADD/SUB/CMP for stack dst with large ABI", .{});
2307 }2336 }
2308 const adj_off = off + @intCast(i32, abi_size);
23092337
2310 switch (src_mcv) {2338 switch (src_mcv) {
2311 .none => unreachable,2339 .none => unreachable,
...@@ -2321,7 +2349,7 @@ fn genBinMathOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MC...@@ -2321,7 +2349,7 @@ fn genBinMathOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MC
2321 .reg2 = registerAlias(src_reg, @intCast(u32, abi_size)),2349 .reg2 = registerAlias(src_reg, @intCast(u32, abi_size)),
2322 .flags = 0b10,2350 .flags = 0b10,
2323 }).encode(),2351 }).encode(),
2324 .data = .{ .imm = @bitCast(u32, -adj_off) },2352 .data = .{ .imm = @bitCast(u32, -off) },
2325 });2353 });
2326 },2354 },
2327 .immediate => |imm| {2355 .immediate => |imm| {
...@@ -2342,7 +2370,7 @@ fn genBinMathOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MC...@@ -2342,7 +2370,7 @@ fn genBinMathOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MC
2342 else => unreachable,2370 else => unreachable,
2343 };2371 };
2344 const payload = try self.addExtra(Mir.ImmPair{2372 const payload = try self.addExtra(Mir.ImmPair{
2345 .dest_off = @bitCast(u32, -adj_off),2373 .dest_off = @bitCast(u32, -off),
2346 .operand = @truncate(u32, imm),2374 .operand = @truncate(u32, imm),
2347 });2375 });
2348 _ = try self.addInst(.{2376 _ = try self.addInst(.{
...@@ -2493,9 +2521,16 @@ fn airArg(self: *Self, inst: Air.Inst.Index) !void {...@@ -2493,9 +2521,16 @@ fn airArg(self: *Self, inst: Air.Inst.Index) !void {
2493 self.arg_index += 1;2521 self.arg_index += 1;
24942522
2495 const mcv = self.args[arg_index];2523 const mcv = self.args[arg_index];
2524 const max_stack = loop: for (self.args) |arg| {
2525 switch (arg) {
2526 .stack_offset => |last| break :loop last,
2527 else => {},
2528 }
2529 } else 0;
2496 const payload = try self.addExtra(Mir.ArgDbgInfo{2530 const payload = try self.addExtra(Mir.ArgDbgInfo{
2497 .air_inst = inst,2531 .air_inst = inst,
2498 .arg_index = arg_index,2532 .arg_index = arg_index,
2533 .max_stack = @intCast(u32, max_stack),
2499 });2534 });
2500 _ = try self.addInst(.{2535 _ = try self.addInst(.{
2501 .tag = .arg_dbg_info,2536 .tag = .arg_dbg_info,
...@@ -2511,11 +2546,9 @@ fn airArg(self: *Self, inst: Air.Inst.Index) !void {...@@ -2511,11 +2546,9 @@ fn airArg(self: *Self, inst: Air.Inst.Index) !void {
2511 self.register_manager.getRegAssumeFree(reg.to64(), inst);2546 self.register_manager.getRegAssumeFree(reg.to64(), inst);
2512 break :blk mcv;2547 break :blk mcv;
2513 },2548 },
2514 .stack_offset => {2549 .stack_offset => |off| {
2515 const ty = self.air.typeOfIndex(inst);2550 const offset = max_stack - off + 16;
2516 const abi_size = ty.abiSize(self.target.*);2551 break :blk MCValue{ .stack_offset = -offset };
2517 const off = @intCast(i32, (arg_index + 1) * abi_size) + 16;
2518 break :blk MCValue{ .stack_offset = -off };
2519 },2552 },
2520 else => return self.fail("TODO implement arg for {}", .{mcv}),2553 else => return self.fail("TODO implement arg for {}", .{mcv}),
2521 }2554 }
...@@ -2558,7 +2591,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index) !void {...@@ -2558,7 +2591,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index) !void {
2558 var info = try self.resolveCallingConventionValues(fn_ty);2591 var info = try self.resolveCallingConventionValues(fn_ty);
2559 defer info.deinit(self);2592 defer info.deinit(self);
25602593
2561 var stack_adjustment: u32 = 0;2594 var stack_adjustment: ?u32 = null;
2562 for (args) |arg, arg_i| {2595 for (args) |arg, arg_i| {
2563 const mc_arg = info.args[arg_i];2596 const mc_arg = info.args[arg_i];
2564 const arg_ty = self.air.typeOf(arg);2597 const arg_ty = self.air.typeOf(arg);
...@@ -2572,9 +2605,10 @@ fn airCall(self: *Self, inst: Air.Inst.Index) !void {...@@ -2572,9 +2605,10 @@ fn airCall(self: *Self, inst: Air.Inst.Index) !void {
2572 try self.genSetReg(arg_ty, reg, arg_mcv);2605 try self.genSetReg(arg_ty, reg, arg_mcv);
2573 },2606 },
2574 .stack_offset => |off| {2607 .stack_offset => |off| {
2575 const abi_size = @intCast(u32, arg_ty.abiSize(self.target.*));
2576 try self.genSetStackArg(arg_ty, off, arg_mcv);2608 try self.genSetStackArg(arg_ty, off, arg_mcv);
2577 stack_adjustment += abi_size;2609 if (stack_adjustment == null) {
2610 stack_adjustment = @intCast(u32, off);
2611 }
2578 },2612 },
2579 .ptr_stack_offset => {2613 .ptr_stack_offset => {
2580 return self.fail("TODO implement calling with MCValue.ptr_stack_offset arg", .{});2614 return self.fail("TODO implement calling with MCValue.ptr_stack_offset arg", .{});
...@@ -2595,14 +2629,14 @@ fn airCall(self: *Self, inst: Air.Inst.Index) !void {...@@ -2595,14 +2629,14 @@ fn airCall(self: *Self, inst: Air.Inst.Index) !void {
2595 }2629 }
2596 }2630 }
25972631
2598 if (stack_adjustment > 0) {2632 if (stack_adjustment) |off| {
2599 // Adjust the stack2633 // Adjust the stack
2600 _ = try self.addInst(.{2634 _ = try self.addInst(.{
2601 .tag = .sub,2635 .tag = .sub,
2602 .ops = (Mir.Ops{2636 .ops = (Mir.Ops{
2603 .reg1 = .rsp,2637 .reg1 = .rsp,
2604 }).encode(),2638 }).encode(),
2605 .data = .{ .imm = stack_adjustment },2639 .data = .{ .imm = off },
2606 });2640 });
2607 }2641 }
26082642
...@@ -2730,14 +2764,14 @@ fn airCall(self: *Self, inst: Air.Inst.Index) !void {...@@ -2730,14 +2764,14 @@ fn airCall(self: *Self, inst: Air.Inst.Index) !void {
2730 }2764 }
2731 } else unreachable;2765 } else unreachable;
27322766
2733 if (stack_adjustment > 0) {2767 if (stack_adjustment) |off| {
2734 // Readjust the stack2768 // Readjust the stack
2735 _ = try self.addInst(.{2769 _ = try self.addInst(.{
2736 .tag = .add,2770 .tag = .add,
2737 .ops = (Mir.Ops{2771 .ops = (Mir.Ops{
2738 .reg1 = .rsp,2772 .reg1 = .rsp,
2739 }).encode(),2773 }).encode(),
2740 .data = .{ .imm = stack_adjustment },2774 .data = .{ .imm = off },
2741 });2775 });
2742 }2776 }
27432777
...@@ -3493,14 +3527,13 @@ fn genSetStackArg(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerE...@@ -3493,14 +3527,13 @@ fn genSetStackArg(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerE
3493 return self.genSetStackArg(ty, stack_offset, .{ .register = reg });3527 return self.genSetStackArg(ty, stack_offset, .{ .register = reg });
3494 },3528 },
3495 .immediate => |imm| {3529 .immediate => |imm| {
3496 const off = stack_offset + @intCast(i32, abi_size);
3497 switch (abi_size) {3530 switch (abi_size) {
3498 1, 2, 4 => {3531 1, 2, 4 => {
3499 // We have a positive stack offset value but we want a twos complement negative3532 // We have a positive stack offset value but we want a twos complement negative
3500 // offset from rbp, which is at the top of the stack frame.3533 // offset from rbp, which is at the top of the stack frame.
3501 // mov [rbp+offset], immediate3534 // mov [rbp+offset], immediate
3502 const payload = try self.addExtra(Mir.ImmPair{3535 const payload = try self.addExtra(Mir.ImmPair{
3503 .dest_off = @bitCast(u32, -off),3536 .dest_off = @bitCast(u32, -stack_offset),
3504 .operand = @truncate(u32, imm),3537 .operand = @truncate(u32, imm),
3505 });3538 });
3506 _ = try self.addInst(.{3539 _ = try self.addInst(.{
...@@ -3540,62 +3573,7 @@ fn genSetStackArg(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerE...@@ -3540,62 +3573,7 @@ fn genSetStackArg(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerE
3540 return self.genSetStackArg(ty, stack_offset, MCValue{ .register = reg });3573 return self.genSetStackArg(ty, stack_offset, MCValue{ .register = reg });
3541 }3574 }
35423575
3543 self.register_manager.freezeRegs(&.{ .rax, .rcx });3576 try self.genInlineMemcpy(stack_offset, .rsp, ty, mcv);
3544 defer self.register_manager.unfreezeRegs(&.{ .rax, .rcx });
3545
3546 const addr_reg: Register = blk: {
3547 switch (mcv) {
3548 .got_load,
3549 .direct_load,
3550 => |sym_index| {
3551 const flags: u2 = switch (mcv) {
3552 .got_load => 0b00,
3553 .direct_load => 0b01,
3554 else => unreachable,
3555 };
3556 const addr_reg = try self.register_manager.allocReg(null);
3557 _ = try self.addInst(.{
3558 .tag = .lea_pie,
3559 .ops = (Mir.Ops{
3560 .reg1 = addr_reg.to64(),
3561 .flags = flags,
3562 }).encode(),
3563 .data = .{
3564 .load_reloc = .{
3565 .atom_index = self.mod_fn.owner_decl.link.macho.local_sym_index,
3566 .sym_index = sym_index,
3567 },
3568 },
3569 });
3570 break :blk addr_reg;
3571 },
3572 .memory => |addr| {
3573 const addr_reg = try self.copyToTmpRegister(Type.usize, .{ .immediate = addr });
3574 break :blk addr_reg;
3575 },
3576 else => unreachable,
3577 }
3578 };
3579
3580 self.register_manager.freezeRegs(&.{addr_reg});
3581 defer self.register_manager.unfreezeRegs(&.{addr_reg});
3582
3583 const regs = try self.register_manager.allocRegs(2, .{ null, null });
3584 const count_reg = regs[0];
3585 const tmp_reg = regs[1];
3586
3587 try self.register_manager.getReg(.rax, null);
3588 try self.register_manager.getReg(.rcx, null);
3589
3590 // TODO allow for abi_size to be u64
3591 try self.genSetReg(Type.u32, count_reg, .{ .immediate = @intCast(u32, abi_size) });
3592 try self.genInlineMemcpy(
3593 -(stack_offset + @intCast(i32, abi_size)),
3594 .rsp,
3595 addr_reg.to64(),
3596 count_reg.to64(),
3597 tmp_reg.to8(),
3598 );
3599 },3577 },
3600 .register => |reg| {3578 .register => |reg| {
3601 _ = try self.addInst(.{3579 _ = try self.addInst(.{
...@@ -3605,48 +3583,20 @@ fn genSetStackArg(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerE...@@ -3605,48 +3583,20 @@ fn genSetStackArg(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerE
3605 .reg2 = registerAlias(reg, @intCast(u32, abi_size)),3583 .reg2 = registerAlias(reg, @intCast(u32, abi_size)),
3606 .flags = 0b10,3584 .flags = 0b10,
3607 }).encode(),3585 }).encode(),
3608 .data = .{ .imm = @bitCast(u32, -(stack_offset + @intCast(i32, abi_size))) },3586 .data = .{ .imm = @bitCast(u32, -stack_offset) },
3609 });3587 });
3610 },3588 },
3611 .ptr_stack_offset => {3589 .ptr_stack_offset => {
3612 const reg = try self.copyToTmpRegister(ty, mcv);3590 const reg = try self.copyToTmpRegister(ty, mcv);
3613 return self.genSetStackArg(ty, stack_offset, MCValue{ .register = reg });3591 return self.genSetStackArg(ty, stack_offset, MCValue{ .register = reg });
3614 },3592 },
3615 .stack_offset => |unadjusted_off| {3593 .stack_offset => {
3616 if (abi_size <= 8) {3594 if (abi_size <= 8) {
3617 const reg = try self.copyToTmpRegister(ty, mcv);3595 const reg = try self.copyToTmpRegister(ty, mcv);
3618 return self.genSetStackArg(ty, stack_offset, MCValue{ .register = reg });3596 return self.genSetStackArg(ty, stack_offset, MCValue{ .register = reg });
3619 }3597 }
36203598
3621 self.register_manager.freezeRegs(&.{ .rax, .rcx });3599 try self.genInlineMemcpy(stack_offset, .rsp, ty, mcv);
3622 defer self.register_manager.unfreezeRegs(&.{ .rax, .rcx });
3623
3624 const regs = try self.register_manager.allocRegs(3, .{ null, null, null });
3625 const addr_reg = regs[0];
3626 const count_reg = regs[1];
3627 const tmp_reg = regs[2];
3628
3629 try self.register_manager.getReg(.rax, null);
3630 try self.register_manager.getReg(.rcx, null);
3631
3632 _ = try self.addInst(.{
3633 .tag = .lea,
3634 .ops = (Mir.Ops{
3635 .reg1 = addr_reg.to64(),
3636 .reg2 = .rbp,
3637 }).encode(),
3638 .data = .{ .imm = @bitCast(u32, -(unadjusted_off + @intCast(i32, abi_size))) },
3639 });
3640
3641 // TODO allow for abi_size to be u64
3642 try self.genSetReg(Type.u32, count_reg, .{ .immediate = @intCast(u32, abi_size) });
3643 try self.genInlineMemcpy(
3644 -(stack_offset + @intCast(i32, abi_size)),
3645 .rsp,
3646 addr_reg.to64(),
3647 count_reg.to64(),
3648 tmp_reg.to8(),
3649 );
3650 },3600 },
3651 else => return self.fail("TODO implement args on stack for {}", .{mcv}),3601 else => return self.fail("TODO implement args on stack for {}", .{mcv}),
3652 }3602 }
...@@ -3677,17 +3627,13 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerErro...@@ -3677,17 +3627,13 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerErro
3677 return self.genSetStack(ty, stack_offset, .{ .register = reg });3627 return self.genSetStack(ty, stack_offset, .{ .register = reg });
3678 },3628 },
3679 .immediate => |x_big| {3629 .immediate => |x_big| {
3680 const adj_off = stack_offset + @intCast(i32, abi_size);3630 if (stack_offset > 128) {
3681 if (adj_off > 128) {
3682 return self.fail("TODO implement set stack variable with large stack offset", .{});3631 return self.fail("TODO implement set stack variable with large stack offset", .{});
3683 }3632 }
3684 switch (abi_size) {3633 switch (abi_size) {
3685 1, 2, 4 => {3634 1, 2, 4 => {
3686 // We have a positive stack offset value but we want a twos complement negative
3687 // offset from rbp, which is at the top of the stack frame.
3688 // mov [rbp+offset], immediate
3689 const payload = try self.addExtra(Mir.ImmPair{3635 const payload = try self.addExtra(Mir.ImmPair{
3690 .dest_off = @bitCast(u32, -adj_off),3636 .dest_off = @bitCast(u32, -stack_offset),
3691 .operand = @truncate(u32, x_big),3637 .operand = @truncate(u32, x_big),
3692 });3638 });
3693 _ = try self.addInst(.{3639 _ = try self.addInst(.{
...@@ -3705,15 +3651,11 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerErro...@@ -3705,15 +3651,11 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerErro
3705 });3651 });
3706 },3652 },
3707 8 => {3653 8 => {
3708 // We have a positive stack offset value but we want a twos complement negative
3709 // offset from rbp, which is at the top of the stack frame.
3710 const negative_offset = -adj_off;
3711
3712 // 64 bit write to memory would take two mov's anyways so we3654 // 64 bit write to memory would take two mov's anyways so we
3713 // insted just use two 32 bit writes to avoid register allocation3655 // insted just use two 32 bit writes to avoid register allocation
3714 {3656 {
3715 const payload = try self.addExtra(Mir.ImmPair{3657 const payload = try self.addExtra(Mir.ImmPair{
3716 .dest_off = @bitCast(u32, negative_offset + 4),3658 .dest_off = @bitCast(u32, -stack_offset + 4),
3717 .operand = @truncate(u32, x_big >> 32),3659 .operand = @truncate(u32, x_big >> 32),
3718 });3660 });
3719 _ = try self.addInst(.{3661 _ = try self.addInst(.{
...@@ -3727,7 +3669,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerErro...@@ -3727,7 +3669,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerErro
3727 }3669 }
3728 {3670 {
3729 const payload = try self.addExtra(Mir.ImmPair{3671 const payload = try self.addExtra(Mir.ImmPair{
3730 .dest_off = @bitCast(u32, negative_offset),3672 .dest_off = @bitCast(u32, -stack_offset),
3731 .operand = @truncate(u32, x_big),3673 .operand = @truncate(u32, x_big),
3732 });3674 });
3733 _ = try self.addInst(.{3675 _ = try self.addInst(.{
...@@ -3749,16 +3691,54 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerErro...@@ -3749,16 +3691,54 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerErro
3749 if (stack_offset > math.maxInt(i32)) {3691 if (stack_offset > math.maxInt(i32)) {
3750 return self.fail("stack offset too large", .{});3692 return self.fail("stack offset too large", .{});
3751 }3693 }
3752 const adj_off = stack_offset + @intCast(i32, abi_size);3694
3753 _ = try self.addInst(.{3695 const is_power_of_two = (abi_size % 2) == 0;
3754 .tag = .mov,3696 if (!is_power_of_two) {
3755 .ops = (Mir.Ops{3697 self.register_manager.freezeRegs(&.{reg});
3756 .reg1 = .rbp,3698 defer self.register_manager.unfreezeRegs(&.{reg});
3757 .reg2 = registerAlias(reg, @intCast(u32, abi_size)),3699
3758 .flags = 0b10,3700 const tmp_reg = try self.copyToTmpRegister(ty, mcv);
3759 }).encode(),3701
3760 .data = .{ .imm = @bitCast(u32, -adj_off) },3702 var next_offset = stack_offset;
3761 });3703 var remainder = abi_size;
3704 while (remainder > 0) {
3705 const closest_power_of_two = @as(u6, 1) << @intCast(u3, math.log2(remainder));
3706
3707 _ = try self.addInst(.{
3708 .tag = .mov,
3709 .ops = (Mir.Ops{
3710 .reg1 = .rbp,
3711 .reg2 = registerAlias(tmp_reg, closest_power_of_two),
3712 .flags = 0b10,
3713 }).encode(),
3714 .data = .{ .imm = @bitCast(u32, -next_offset) },
3715 });
3716
3717 if (closest_power_of_two > 1) {
3718 _ = try self.addInst(.{
3719 .tag = .shr,
3720 .ops = (Mir.Ops{
3721 .reg1 = tmp_reg,
3722 .flags = 0b10,
3723 }).encode(),
3724 .data = .{ .imm = closest_power_of_two * 8 },
3725 });
3726 }
3727
3728 remainder -= closest_power_of_two;
3729 next_offset -= closest_power_of_two;
3730 }
3731 } else {
3732 _ = try self.addInst(.{
3733 .tag = .mov,
3734 .ops = (Mir.Ops{
3735 .reg1 = .rbp,
3736 .reg2 = registerAlias(reg, @intCast(u32, abi_size)),
3737 .flags = 0b10,
3738 }).encode(),
3739 .data = .{ .imm = @bitCast(u32, -stack_offset) },
3740 });
3741 }
3762 },3742 },
3763 .memory,3743 .memory,
3764 .embedded_in_code,3744 .embedded_in_code,
...@@ -3770,65 +3750,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerErro...@@ -3770,65 +3750,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerErro
3770 return self.genSetStack(ty, stack_offset, MCValue{ .register = reg });3750 return self.genSetStack(ty, stack_offset, MCValue{ .register = reg });
3771 }3751 }
37723752
3773 try self.register_manager.getReg(.rax, null);3753 try self.genInlineMemcpy(stack_offset, .rbp, ty, mcv);
3774 try self.register_manager.getReg(.rcx, null);
3775
3776 self.register_manager.freezeRegs(&.{ .rax, .rcx, .rbp });
3777 defer self.register_manager.unfreezeRegs(&.{ .rax, .rcx, .rbp });
3778
3779 const addr_reg: Register = blk: {
3780 switch (mcv) {
3781 .memory => |addr| {
3782 const reg = try self.copyToTmpRegister(Type.usize, .{ .immediate = addr });
3783 break :blk reg;
3784 },
3785 .direct_load,
3786 .got_load,
3787 => |sym_index| {
3788 const flags: u2 = switch (mcv) {
3789 .got_load => 0b00,
3790 .direct_load => 0b01,
3791 else => unreachable,
3792 };
3793 const addr_reg = try self.register_manager.allocReg(null);
3794 _ = try self.addInst(.{
3795 .tag = .lea_pie,
3796 .ops = (Mir.Ops{
3797 .reg1 = addr_reg.to64(),
3798 .flags = flags,
3799 }).encode(),
3800 .data = .{
3801 .load_reloc = .{
3802 .atom_index = self.mod_fn.owner_decl.link.macho.local_sym_index,
3803 .sym_index = sym_index,
3804 },
3805 },
3806 });
3807 break :blk addr_reg;
3808 },
3809 else => {
3810 return self.fail("TODO implement memcpy for setting stack from {}", .{mcv});
3811 },
3812 }
3813 };
3814
3815 self.register_manager.freezeRegs(&.{addr_reg});
3816 defer self.register_manager.unfreezeRegs(&.{addr_reg});
3817
3818 const regs = try self.register_manager.allocRegs(2, .{ null, null });
3819 const count_reg = regs[0];
3820 const tmp_reg = regs[1];
3821
3822 // TODO allow for abi_size to be u64
3823 try self.genSetReg(Type.u32, count_reg, .{ .immediate = @intCast(u32, abi_size) });
3824
3825 return self.genInlineMemcpy(
3826 -(stack_offset + @intCast(i32, abi_size)),
3827 .rbp,
3828 addr_reg.to64(),
3829 count_reg.to64(),
3830 tmp_reg.to8(),
3831 );
3832 },3754 },
3833 .ptr_stack_offset => {3755 .ptr_stack_offset => {
3834 const reg = try self.copyToTmpRegister(ty, mcv);3756 const reg = try self.copyToTmpRegister(ty, mcv);
...@@ -3845,48 +3767,89 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerErro...@@ -3845,48 +3767,89 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerErro
3845 return self.genSetStack(ty, stack_offset, MCValue{ .register = reg });3767 return self.genSetStack(ty, stack_offset, MCValue{ .register = reg });
3846 }3768 }
38473769
3848 self.register_manager.freezeRegs(&.{ .rax, .rcx, .rbp });3770 try self.genInlineMemcpy(stack_offset, .rbp, ty, mcv);
3849 defer self.register_manager.unfreezeRegs(&.{ .rax, .rcx, .rbp });3771 },
3772 }
3773}
38503774
3851 const regs = try self.register_manager.allocRegs(3, .{ null, null, null });3775fn genInlineMemcpy(self: *Self, stack_offset: i32, stack_reg: Register, ty: Type, val: MCValue) InnerError!void {
3852 const addr_reg = regs[0];3776 const abi_size = ty.abiSize(self.target.*);
3853 const count_reg = regs[1];
3854 const tmp_reg = regs[2];
38553777
3856 try self.register_manager.getReg(.rax, null);3778 try self.register_manager.getReg(.rax, null);
3857 try self.register_manager.getReg(.rcx, null);3779 try self.register_manager.getReg(.rcx, null);
38583780
3859 _ = try self.addInst(.{3781 self.register_manager.freezeRegs(&.{ .rax, .rcx, .rbp });
3860 .tag = .lea,3782 defer self.register_manager.unfreezeRegs(&.{ .rax, .rcx, .rbp });
3861 .ops = (Mir.Ops{
3862 .reg1 = addr_reg.to64(),
3863 .reg2 = .rbp,
3864 }).encode(),
3865 .data = .{ .imm = @bitCast(u32, -(off + @intCast(i32, abi_size))) },
3866 });
38673783
3868 // TODO allow for abi_size to be u643784 const addr_reg: Register = blk: {
3869 try self.genSetReg(Type.u32, count_reg, .{ .immediate = @intCast(u32, abi_size) });3785 switch (val) {
3786 .memory => |addr| {
3787 const reg = try self.copyToTmpRegister(Type.usize, .{ .immediate = addr });
3788 break :blk reg;
3789 },
3790 .direct_load,
3791 .got_load,
3792 => |sym_index| {
3793 const flags: u2 = switch (val) {
3794 .got_load => 0b00,
3795 .direct_load => 0b01,
3796 else => unreachable,
3797 };
3798 const addr_reg = (try self.register_manager.allocReg(null)).to64();
3799 _ = try self.addInst(.{
3800 .tag = .lea_pie,
3801 .ops = (Mir.Ops{
3802 .reg1 = addr_reg,
3803 .flags = flags,
3804 }).encode(),
3805 .data = .{
3806 .load_reloc = .{
3807 .atom_index = self.mod_fn.owner_decl.link.macho.local_sym_index,
3808 .sym_index = sym_index,
3809 },
3810 },
3811 });
3812 break :blk addr_reg;
3813 },
3814 .stack_offset => |off| {
3815 const addr_reg = (try self.register_manager.allocReg(null)).to64();
3816 _ = try self.addInst(.{
3817 .tag = .lea,
3818 .ops = (Mir.Ops{
3819 .reg1 = addr_reg,
3820 .reg2 = .rbp,
3821 }).encode(),
3822 .data = .{ .imm = @bitCast(u32, -off) },
3823 });
3824 break :blk addr_reg;
3825 },
3826 .register => |reg| {
3827 const addr_reg = try self.register_manager.allocReg(null);
3828 _ = try self.addInst(.{
3829 .tag = .mov,
3830 .ops = (Mir.Ops{
3831 .reg1 = registerAlias(addr_reg, @divExact(reg.size(), 8)),
3832 .reg2 = reg,
3833 }).encode(),
3834 .data = undefined,
3835 });
3836 break :blk addr_reg.to64();
3837 },
3838 else => {
3839 return self.fail("TODO implement memcpy for setting stack from {}", .{val});
3840 },
3841 }
3842 };
38703843
3871 return self.genInlineMemcpy(3844 self.register_manager.freezeRegs(&.{addr_reg});
3872 -(stack_offset + @intCast(i32, abi_size)),3845 defer self.register_manager.unfreezeRegs(&.{addr_reg});
3873 .rbp,3846
3874 addr_reg.to64(),3847 const regs = try self.register_manager.allocRegs(2, .{ null, null });
3875 count_reg.to64(),3848 const count_reg = regs[0].to64();
3876 tmp_reg.to8(),3849 const tmp_reg = regs[1].to8();
3877 );3850
3878 },3851 try self.genSetReg(Type.u32, count_reg, .{ .immediate = @intCast(u32, abi_size) });
3879 }
3880}
38813852
3882fn genInlineMemcpy(
3883 self: *Self,
3884 stack_offset: i32,
3885 stack_reg: Register,
3886 addr_reg: Register,
3887 count_reg: Register,
3888 tmp_reg: Register,
3889) InnerError!void {
3890 // mov rcx, 03853 // mov rcx, 0
3891 _ = try self.addInst(.{3854 _ = try self.addInst(.{
3892 .tag = .mov,3855 .tag = .mov,
...@@ -3939,7 +3902,7 @@ fn genInlineMemcpy(...@@ -3939,7 +3902,7 @@ fn genInlineMemcpy(
3939 .reg1 = stack_reg,3902 .reg1 = stack_reg,
3940 .reg2 = tmp_reg.to8(),3903 .reg2 = tmp_reg.to8(),
3941 }).encode(),3904 }).encode(),
3942 .data = .{ .imm = @bitCast(u32, stack_offset) },3905 .data = .{ .imm = @bitCast(u32, -stack_offset) },
3943 });3906 });
39443907
3945 // add rcx, 13908 // add rcx, 1
...@@ -3983,11 +3946,10 @@ fn genInlineMemcpy(...@@ -3983,11 +3946,10 @@ fn genInlineMemcpy(
3983fn genInlineMemset(self: *Self, ty: Type, stack_offset: i32, value: MCValue) InnerError!void {3946fn genInlineMemset(self: *Self, ty: Type, stack_offset: i32, value: MCValue) InnerError!void {
3984 try self.register_manager.getReg(.rax, null);3947 try self.register_manager.getReg(.rax, null);
3985 const abi_size = ty.abiSize(self.target.*);3948 const abi_size = ty.abiSize(self.target.*);
3986 const adj_off = stack_offset + @intCast(i32, abi_size);3949 if (stack_offset > 128) {
3987 if (adj_off > 128) {
3988 return self.fail("TODO inline memset with large stack offset", .{});3950 return self.fail("TODO inline memset with large stack offset", .{});
3989 }3951 }
3990 const negative_offset = @bitCast(u32, -adj_off);3952 const negative_offset = @bitCast(u32, -stack_offset);
39913953
3992 // We are actually counting `abi_size` bytes; however, we reuse the index register3954 // We are actually counting `abi_size` bytes; however, we reuse the index register
3993 // as both the counter and offset scaler, hence we need to subtract one from `abi_size`3955 // as both the counter and offset scaler, hence we need to subtract one from `abi_size`
...@@ -4075,10 +4037,7 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void...@@ -4075,10 +4037,7 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
4075 const abi_size = ty.abiSize(self.target.*);4037 const abi_size = ty.abiSize(self.target.*);
4076 switch (mcv) {4038 switch (mcv) {
4077 .dead => unreachable,4039 .dead => unreachable,
4078 .ptr_stack_offset => |unadjusted_off| {4040 .ptr_stack_offset => |off| {
4079 const elem_ty = ty.childType();
4080 const elem_abi_size = elem_ty.abiSize(self.target.*);
4081 const off = unadjusted_off + @intCast(i32, elem_abi_size);
4082 if (off < std.math.minInt(i32) or off > std.math.maxInt(i32)) {4041 if (off < std.math.minInt(i32) or off > std.math.maxInt(i32)) {
4083 return self.fail("stack offset too large", .{});4042 return self.fail("stack offset too large", .{});
4084 }4043 }
...@@ -4301,8 +4260,7 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void...@@ -4301,8 +4260,7 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
4301 }4260 }
4302 }4261 }
4303 },4262 },
4304 .stack_offset => |unadjusted_off| {4263 .stack_offset => |off| {
4305 const off = unadjusted_off + @intCast(i32, abi_size);
4306 if (off < std.math.minInt(i32) or off > std.math.maxInt(i32)) {4264 if (off < std.math.minInt(i32) or off > std.math.maxInt(i32)) {
4307 return self.fail("stack offset too large", .{});4265 return self.fail("stack offset too large", .{});
4308 }4266 }
...@@ -4379,8 +4337,8 @@ fn airArrayToSlice(self: *Self, inst: Air.Inst.Index) !void {...@@ -4379,8 +4337,8 @@ fn airArrayToSlice(self: *Self, inst: Air.Inst.Index) !void {
4379 const array_len = array_ty.arrayLenIncludingSentinel();4337 const array_len = array_ty.arrayLenIncludingSentinel();
4380 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else blk: {4338 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else blk: {
4381 const stack_offset = @intCast(i32, try self.allocMem(inst, 16, 16));4339 const stack_offset = @intCast(i32, try self.allocMem(inst, 16, 16));
4382 try self.genSetStack(ptr_ty, stack_offset + 8, ptr);4340 try self.genSetStack(ptr_ty, stack_offset, ptr);
4383 try self.genSetStack(Type.initTag(.u64), stack_offset, .{ .immediate = array_len });4341 try self.genSetStack(Type.initTag(.u64), stack_offset - 8, .{ .immediate = array_len });
4384 break :blk .{ .stack_offset = stack_offset };4342 break :blk .{ .stack_offset = stack_offset };
4385 };4343 };
4386 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });4344 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
...@@ -4620,6 +4578,9 @@ fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue {...@@ -4620,6 +4578,9 @@ fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue {
4620 }4578 }
46214579
4622 switch (typed_value.ty.zigTypeTag()) {4580 switch (typed_value.ty.zigTypeTag()) {
4581 .Array => {
4582 return self.lowerUnnamedConst(typed_value);
4583 },
4623 .Pointer => switch (typed_value.ty.ptrSize()) {4584 .Pointer => switch (typed_value.ty.ptrSize()) {
4624 .Slice => {4585 .Slice => {
4625 return self.lowerUnnamedConst(typed_value);4586 return self.lowerUnnamedConst(typed_value);
...@@ -4790,7 +4751,6 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues {...@@ -4790,7 +4751,6 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues {
4790 var next_stack_offset: u32 = 0;4751 var next_stack_offset: u32 = 0;
4791 var count: usize = param_types.len;4752 var count: usize = param_types.len;
4792 while (count > 0) : (count -= 1) {4753 while (count > 0) : (count -= 1) {
4793 // for (param_types) |ty, i| {
4794 const i = count - 1;4754 const i = count - 1;
4795 const ty = param_types[i];4755 const ty = param_types[i];
4796 if (!ty.hasRuntimeBits()) {4756 if (!ty.hasRuntimeBits()) {
...@@ -4799,6 +4759,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues {...@@ -4799,6 +4759,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues {
4799 continue;4759 continue;
4800 }4760 }
4801 const param_size = @intCast(u32, ty.abiSize(self.target.*));4761 const param_size = @intCast(u32, ty.abiSize(self.target.*));
4762 const param_align = @intCast(u32, ty.abiAlignment(self.target.*));
4802 if (by_reg.get(i)) |int_reg| {4763 if (by_reg.get(i)) |int_reg| {
4803 const aliased_reg = registerAlias(c_abi_int_param_regs[int_reg], param_size);4764 const aliased_reg = registerAlias(c_abi_int_param_regs[int_reg], param_size);
4804 result.args[i] = .{ .register = aliased_reg };4765 result.args[i] = .{ .register = aliased_reg };
...@@ -4809,8 +4770,9 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues {...@@ -4809,8 +4770,9 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues {
4809 // such as ptr and len of slices as separate registers.4770 // such as ptr and len of slices as separate registers.
4810 // TODO: also we need to honor the C ABI for relevant types rather than passing on4771 // TODO: also we need to honor the C ABI for relevant types rather than passing on
4811 // the stack here.4772 // the stack here.
4812 result.args[i] = .{ .stack_offset = @intCast(i32, next_stack_offset) };4773 const offset = mem.alignForwardGeneric(u32, next_stack_offset + param_size, param_align);
4813 next_stack_offset += param_size;4774 result.args[i] = .{ .stack_offset = @intCast(i32, offset) };
4775 next_stack_offset = offset;
4814 }4776 }
4815 }4777 }
48164778
...@@ -4883,8 +4845,8 @@ fn parseRegName(name: []const u8) ?Register {...@@ -4883,8 +4845,8 @@ fn parseRegName(name: []const u8) ?Register {
4883 return std.meta.stringToEnum(Register, name);4845 return std.meta.stringToEnum(Register, name);
4884}4846}
48854847
4848/// Returns register wide enough to hold at least `size_bytes`.
4886fn registerAlias(reg: Register, size_bytes: u32) Register {4849fn registerAlias(reg: Register, size_bytes: u32) Register {
4887 // For x86_64 we have to pick a smaller register alias depending on abi size.
4888 if (size_bytes == 0) {4850 if (size_bytes == 0) {
4889 unreachable; // should be comptime known4851 unreachable; // should be comptime known
4890 } else if (size_bytes <= 1) {4852 } else if (size_bytes <= 1) {
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 {
test/behavior/align.zig-1
...@@ -273,7 +273,6 @@ fn whyWouldYouEverDoThis(comptime align_bytes: u8) align(align_bytes) u8 {...@@ -273,7 +273,6 @@ fn whyWouldYouEverDoThis(comptime align_bytes: u8) align(align_bytes) u8 {
273test "runtime known array index has best alignment possible" {273test "runtime known array index has best alignment possible" {
274 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;274 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
275 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;275 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
276 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
277 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;276 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
278277
279 // take full advantage of over-alignment278 // take full advantage of over-alignment
test/behavior/array.zig+1
...@@ -8,6 +8,7 @@ const expectEqual = testing.expectEqual;...@@ -8,6 +8,7 @@ const expectEqual = testing.expectEqual;
8test "array to slice" {8test "array to slice" {
9 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;9 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
10 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;10 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
11 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
1112
12 const a: u32 align(4) = 3;13 const a: u32 align(4) = 3;
13 const b: u32 align(8) = 4;14 const b: u32 align(8) = 4;
test/behavior/cast.zig+2-3
...@@ -199,7 +199,7 @@ fn MakeType(comptime T: type) type {...@@ -199,7 +199,7 @@ fn MakeType(comptime T: type) type {
199199
200test "implicit cast from *[N]T to [*c]T" {200test "implicit cast from *[N]T to [*c]T" {
201 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;201 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
202 if (builtin.zig_backend == .stage2_x86_64 or builtin.zig_backend == .stage2_arm) return error.SkipZigTest;202 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
203203
204 var x: [4]u16 = [4]u16{ 0, 1, 2, 3 };204 var x: [4]u16 = [4]u16{ 0, 1, 2, 3 };
205 var y: [*c]u16 = &x;205 var y: [*c]u16 = &x;
...@@ -274,7 +274,7 @@ test "*const ?[*]const T to [*c]const [*c]const T" {...@@ -274,7 +274,7 @@ test "*const ?[*]const T to [*c]const [*c]const T" {
274274
275test "array coersion to undefined at runtime" {275test "array coersion to undefined at runtime" {
276 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;276 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
277 if (builtin.zig_backend == .stage2_x86_64 or builtin.zig_backend == .stage2_arm) return error.SkipZigTest;277 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
278278
279 @setRuntimeSafety(true);279 @setRuntimeSafety(true);
280280
...@@ -339,7 +339,6 @@ test "peer type unsigned int to signed" {...@@ -339,7 +339,6 @@ test "peer type unsigned int to signed" {
339test "expected [*c]const u8, found [*:0]const u8" {339test "expected [*c]const u8, found [*:0]const u8" {
340 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;340 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
341 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;341 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
342 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
343342
344 var a: [*:0]const u8 = "hello";343 var a: [*:0]const u8 = "hello";
345 var b: [*c]const u8 = a;344 var b: [*c]const u8 = a;
test/behavior/slice.zig-3
...@@ -29,7 +29,6 @@ comptime {...@@ -29,7 +29,6 @@ comptime {
29test "slicing" {29test "slicing" {
30 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;30 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
31 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;31 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
32 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
33 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO32 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
3433
35 var array: [20]i32 = undefined;34 var array: [20]i32 = undefined;
...@@ -223,7 +222,6 @@ test "compile time slice of pointer to hard coded address" {...@@ -223,7 +222,6 @@ test "compile time slice of pointer to hard coded address" {
223test "slice string literal has correct type" {222test "slice string literal has correct type" {
224 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;223 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
225 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;224 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
226 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
227225
228 comptime {226 comptime {
229 try expect(@TypeOf("aoeu"[0..]) == *const [4:0]u8);227 try expect(@TypeOf("aoeu"[0..]) == *const [4:0]u8);
...@@ -365,7 +363,6 @@ test "empty array to slice" {...@@ -365,7 +363,6 @@ test "empty array to slice" {
365test "@ptrCast slice to pointer" {363test "@ptrCast slice to pointer" {
366 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;364 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
367 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;365 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
368 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
369366
370 const S = struct {367 const S = struct {
371 fn doTheTest() !void {368 fn doTheTest() !void {