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
signature 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 {
582582
583583 switch (air_tags[inst]) {
584584 // zig fmt: off
585 .add, .ptr_add => try self.airAdd(inst),
585 .add => try self.airAdd(inst),
586586 .addwrap => try self.airAddWrap(inst),
587587 .add_sat => try self.airAddSat(inst),
588 .sub, .ptr_sub => try self.airSub(inst),
588 .sub => try self.airSub(inst),
589589 .subwrap => try self.airSubWrap(inst),
590590 .sub_sat => try self.airSubSat(inst),
591591 .mul => try self.airMul(inst),
......@@ -597,6 +597,8 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
597597 .shl_sat => try self.airShlSat(inst),
598598 .min => try self.airMin(inst),
599599 .max => try self.airMax(inst),
600 .ptr_add => try self.airPtrAdd(inst),
601 .ptr_sub => try self.airPtrSub(inst),
600602 .slice => try self.airSlice(inst),
601603
602604 .sqrt,
......@@ -808,8 +810,8 @@ fn allocMem(self: *Self, inst: Air.Inst.Index, abi_size: u32, abi_align: u32) !u
808810 if (abi_align > self.stack_align)
809811 self.stack_align = abi_align;
810812 // TODO find a free slot instead of always appending
811 const offset = mem.alignForwardGeneric(u32, self.next_stack_offset, abi_align);
812 self.next_stack_offset = offset + abi_size;
813 const offset = mem.alignForwardGeneric(u32, self.next_stack_offset + abi_size, abi_align);
814 self.next_stack_offset = offset;
813815 if (self.next_stack_offset > self.max_end_stack)
814816 self.max_end_stack = self.next_stack_offset;
815817 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
821823
822824/// Use a pointer instruction as the basis for allocating stack memory.
823825fn 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
826829 if (!elem_ty.hasRuntimeBits()) {
827830 return self.allocMem(inst, 8, 8);
......@@ -831,7 +834,7 @@ fn allocMemPtr(self: *Self, inst: Air.Inst.Index) !u32 {
831834 return self.fail("type '{}' too big to fit into stack frame", .{elem_ty});
832835 };
833836 // 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.*);
835838 return self.allocMem(inst, abi_size, abi_align);
836839}
837840
......@@ -964,7 +967,7 @@ fn airTrunc(self: *Self, inst: Air.Inst.Index) !void {
964967 const reg: Register = blk: {
965968 if (operand.isRegister()) {
966969 if (self.reuseOperand(inst, ty_op.operand, 0, operand)) {
967 break :blk operand.register;
970 break :blk operand.register.to64();
968971 }
969972 }
970973 const mcv = try self.copyToNewRegister(inst, src_ty, operand);
......@@ -1068,13 +1071,81 @@ fn airMax(self: *Self, inst: Air.Inst.Index) !void {
10681071 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
10691072}
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
10711131fn airSlice(self: *Self, inst: Air.Inst.Index) !void {
10721132 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
10731133 const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data;
1074 const result: MCValue = if (self.liveness.isUnused(inst))
1075 .dead
1076 else
1077 return self.fail("TODO implement slice for {}", .{self.target.cpu.arch});
1134
1135 if (self.liveness.isUnused(inst)) {
1136 return self.finishAir(inst, .dead, .{ bin_op.lhs, bin_op.rhs, .none });
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
10781149 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
10791150}
10801151
......@@ -1378,7 +1449,7 @@ fn airSlicePtr(self: *Self, inst: Air.Inst.Index) !void {
13781449 const dst_mcv: MCValue = blk: {
13791450 switch (operand) {
13801451 .stack_offset => |off| {
1381 break :blk MCValue{ .stack_offset = off + 8 };
1452 break :blk MCValue{ .stack_offset = off };
13821453 },
13831454 else => return self.fail("TODO implement slice_ptr for {}", .{operand}),
13841455 }
......@@ -1395,7 +1466,7 @@ fn airSliceLen(self: *Self, inst: Air.Inst.Index) !void {
13951466 const dst_mcv: MCValue = blk: {
13961467 switch (operand) {
13971468 .stack_offset => |off| {
1398 break :blk MCValue{ .stack_offset = off };
1469 break :blk MCValue{ .stack_offset = off - 8 };
13991470 },
14001471 else => return self.fail("TODO implement slice_len for {}", .{operand}),
14011472 }
......@@ -1463,7 +1534,7 @@ fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void {
14631534 .reg2 = .rbp,
14641535 .flags = 0b01,
14651536 }).encode(),
1466 .data = .{ .imm = @bitCast(u32, -@intCast(i32, off + 16)) },
1537 .data = .{ .imm = @bitCast(u32, -@intCast(i32, off)) },
14671538 });
14681539 },
14691540 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 {
14941565 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
14951566 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
14961567 const array_ty = self.air.typeOf(bin_op.lhs);
1497 const array_abi_size = array_ty.abiSize(self.target.*);
14981568 const array = try self.resolveInst(bin_op.lhs);
14991569 array.freezeIfRegister(&self.register_manager);
15001570 defer array.unfreezeIfRegister(&self.register_manager);
......@@ -1520,7 +1590,7 @@ fn airArrayElemVal(self: *Self, inst: Air.Inst.Index) !void {
15201590 .reg1 = addr_reg.to64(),
15211591 .reg2 = .rbp,
15221592 }).encode(),
1523 .data = .{ .imm = @bitCast(u32, -(off + @intCast(i32, array_abi_size))) },
1593 .data = .{ .imm = @bitCast(u32, -off) },
15241594 });
15251595 },
15261596 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
17051775 return self.genSetStack(elem_ty, off, MCValue{ .register = tmp_reg });
17061776 }
17071777
1708 self.register_manager.freezeRegs(&.{ .rax, .rcx });
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 );
1778 try self.genInlineMemcpy(off, .rbp, elem_ty, ptr);
17381779 },
17391780 else => return self.fail("TODO implement loading from register into {}", .{dst_mcv}),
17401781 }
......@@ -2016,10 +2057,7 @@ fn structFieldPtr(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, inde
20162057 const mcv = try self.resolveInst(operand);
20172058 const ptr_ty = self.air.typeOf(operand);
20182059 const struct_ty = ptr_ty.childType();
2019 const struct_size = @intCast(u32, struct_ty.abiSize(self.target.*));
20202060 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
20242062 const dst_mcv: MCValue = result: {
20252063 switch (mcv) {
......@@ -2035,8 +2073,7 @@ fn structFieldPtr(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, inde
20352073 break :result dst_mcv;
20362074 },
20372075 .ptr_stack_offset => |off| {
2038 const offset_to_field = struct_size - struct_field_offset - struct_field_size;
2039 const ptr_stack_offset = off + @intCast(i32, offset_to_field);
2076 const ptr_stack_offset = off - @intCast(i32, struct_field_offset);
20402077 break :result MCValue{ .ptr_stack_offset = ptr_stack_offset };
20412078 },
20422079 .register => |reg| {
......@@ -2076,15 +2113,12 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {
20762113 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
20772114 const mcv = try self.resolveInst(operand);
20782115 const struct_ty = self.air.typeOf(operand);
2079 const struct_size = struct_ty.abiSize(self.target.*);
20802116 const struct_field_offset = struct_ty.structFieldOffset(index, self.target.*);
20812117 const struct_field_ty = struct_ty.structFieldType(index);
2082 const struct_field_size = struct_field_ty.abiSize(self.target.*);
20832118
20842119 switch (mcv) {
20852120 .stack_offset => |off| {
2086 const offset_to_field = struct_size - struct_field_offset - struct_field_size;
2087 const stack_offset = off + @intCast(i32, offset_to_field);
2121 const stack_offset = off - @intCast(i32, struct_field_offset);
20882122 break :result MCValue{ .stack_offset = stack_offset };
20892123 },
20902124 .register => |reg| {
......@@ -2141,14 +2175,6 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {
21412175/// Currently, the following ops are supported:
21422176/// ADD, SUB, XOR, OR, AND
21432177fn 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 //
21522178 // TODO: make this algorithm less bad
21532179 const lhs = try self.resolveInst(op_lhs);
21542180 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:
21612187 const dst_ty = self.air.typeOfIndex(inst);
21622188 var dst_mcv: MCValue = undefined;
21632189 var src_mcv: MCValue = undefined;
2190
21642191 if (self.reuseOperand(inst, op_lhs, 0, lhs)) {
21652192 // LHS dies; use it as the destination.
21662193 // Both operands cannot be memory.
......@@ -2207,17 +2234,15 @@ fn genBinMathOp(self: *Self, inst: Air.Inst.Index, op_lhs: Air.Inst.Ref, op_rhs:
22072234 dst_mcv.freezeIfRegister(&self.register_manager);
22082235 defer dst_mcv.unfreezeIfRegister(&self.register_manager);
22092236
2210 const tmp_reg = try self.copyToTmpRegister(Type.u64, src_mcv);
2211 src_mcv = MCValue{ .register = tmp_reg };
2237 src_mcv = try self.copyToNewRegister(inst, Type.u64, src_mcv);
22122238 }
22132239 },
22142240 else => {},
22152241 }
22162242
2217 // Now for step 2, we assing an MIR instruction
2218 const air_tags = self.air.instructions.items(.tag);
2219 switch (air_tags[inst]) {
2220 .add, .addwrap, .ptr_add => try self.genBinMathOpMir(.add, dst_ty, dst_mcv, src_mcv),
2243 const tag = self.air.instructions.items(.tag)[inst];
2244 switch (tag) {
2245 .add, .addwrap => try self.genBinMathOpMir(.add, dst_ty, dst_mcv, src_mcv),
22212246 .bool_or, .bit_or => try self.genBinMathOpMir(.@"or", dst_ty, dst_mcv, src_mcv),
22222247 .bool_and, .bit_and => try self.genBinMathOpMir(.@"and", dst_ty, dst_mcv, src_mcv),
22232248 .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:
22252250 .mul, .mulwrap => try self.genIMulOpMir(dst_ty, dst_mcv, src_mcv),
22262251 else => unreachable,
22272252 }
2228
22292253 return dst_mcv;
22302254}
22312255
......@@ -2244,7 +2268,12 @@ fn genBinMathOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MC
22442268 .none => unreachable,
22452269 .undef => try self.genSetReg(dst_ty, dst_reg, .undef),
22462270 .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 },
22482277 .ptr_embedded_in_code => unreachable,
22492278 .register => |src_reg| {
22502279 _ = try self.addInst(.{
......@@ -2265,21 +2294,21 @@ fn genBinMathOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MC
22652294 .data = .{ .imm = @truncate(u32, imm) },
22662295 });
22672296 },
2268 .embedded_in_code, .memory => {
2297 .embedded_in_code,
2298 .memory,
2299 .got_load,
2300 .direct_load,
2301 => {
22692302 assert(abi_size <= 8);
22702303 self.register_manager.freezeRegs(&.{dst_reg});
22712304 defer self.register_manager.unfreezeRegs(&.{dst_reg});
22722305 const reg = try self.copyToTmpRegister(dst_ty, src_mcv);
22732306 return self.genBinMathOpMir(mir_tag, dst_ty, dst_mcv, .{ .register = reg });
22742307 },
2275 .got_load, .direct_load => {
2276 return self.fail("TODO implement x86 ADD/SUB/CMP source symbol at index in linker", .{});
2277 },
22782308 .stack_offset => |off| {
22792309 if (off > math.maxInt(i32)) {
22802310 return self.fail("stack offset too large", .{});
22812311 }
2282 const adj_off = off + @intCast(i32, abi_size);
22832312 _ = try self.addInst(.{
22842313 .tag = mir_tag,
22852314 .ops = (Mir.Ops{
......@@ -2287,7 +2316,7 @@ fn genBinMathOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MC
22872316 .reg2 = .rbp,
22882317 .flags = 0b01,
22892318 }).encode(),
2290 .data = .{ .imm = @bitCast(u32, -adj_off) },
2319 .data = .{ .imm = @bitCast(u32, -off) },
22912320 });
22922321 },
22932322 .compare_flags_unsigned => {
......@@ -2305,7 +2334,6 @@ fn genBinMathOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MC
23052334 if (abi_size > 8) {
23062335 return self.fail("TODO implement ADD/SUB/CMP for stack dst with large ABI", .{});
23072336 }
2308 const adj_off = off + @intCast(i32, abi_size);
23092337
23102338 switch (src_mcv) {
23112339 .none => unreachable,
......@@ -2321,7 +2349,7 @@ fn genBinMathOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MC
23212349 .reg2 = registerAlias(src_reg, @intCast(u32, abi_size)),
23222350 .flags = 0b10,
23232351 }).encode(),
2324 .data = .{ .imm = @bitCast(u32, -adj_off) },
2352 .data = .{ .imm = @bitCast(u32, -off) },
23252353 });
23262354 },
23272355 .immediate => |imm| {
......@@ -2342,7 +2370,7 @@ fn genBinMathOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MC
23422370 else => unreachable,
23432371 };
23442372 const payload = try self.addExtra(Mir.ImmPair{
2345 .dest_off = @bitCast(u32, -adj_off),
2373 .dest_off = @bitCast(u32, -off),
23462374 .operand = @truncate(u32, imm),
23472375 });
23482376 _ = try self.addInst(.{
......@@ -2493,9 +2521,16 @@ fn airArg(self: *Self, inst: Air.Inst.Index) !void {
24932521 self.arg_index += 1;
24942522
24952523 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;
24962530 const payload = try self.addExtra(Mir.ArgDbgInfo{
24972531 .air_inst = inst,
24982532 .arg_index = arg_index,
2533 .max_stack = @intCast(u32, max_stack),
24992534 });
25002535 _ = try self.addInst(.{
25012536 .tag = .arg_dbg_info,
......@@ -2511,11 +2546,9 @@ fn airArg(self: *Self, inst: Air.Inst.Index) !void {
25112546 self.register_manager.getRegAssumeFree(reg.to64(), inst);
25122547 break :blk mcv;
25132548 },
2514 .stack_offset => {
2515 const ty = self.air.typeOfIndex(inst);
2516 const abi_size = ty.abiSize(self.target.*);
2517 const off = @intCast(i32, (arg_index + 1) * abi_size) + 16;
2518 break :blk MCValue{ .stack_offset = -off };
2549 .stack_offset => |off| {
2550 const offset = max_stack - off + 16;
2551 break :blk MCValue{ .stack_offset = -offset };
25192552 },
25202553 else => return self.fail("TODO implement arg for {}", .{mcv}),
25212554 }
......@@ -2558,7 +2591,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index) !void {
25582591 var info = try self.resolveCallingConventionValues(fn_ty);
25592592 defer info.deinit(self);
25602593
2561 var stack_adjustment: u32 = 0;
2594 var stack_adjustment: ?u32 = null;
25622595 for (args) |arg, arg_i| {
25632596 const mc_arg = info.args[arg_i];
25642597 const arg_ty = self.air.typeOf(arg);
......@@ -2572,9 +2605,10 @@ fn airCall(self: *Self, inst: Air.Inst.Index) !void {
25722605 try self.genSetReg(arg_ty, reg, arg_mcv);
25732606 },
25742607 .stack_offset => |off| {
2575 const abi_size = @intCast(u32, arg_ty.abiSize(self.target.*));
25762608 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 }
25782612 },
25792613 .ptr_stack_offset => {
25802614 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 {
25952629 }
25962630 }
25972631
2598 if (stack_adjustment > 0) {
2632 if (stack_adjustment) |off| {
25992633 // Adjust the stack
26002634 _ = try self.addInst(.{
26012635 .tag = .sub,
26022636 .ops = (Mir.Ops{
26032637 .reg1 = .rsp,
26042638 }).encode(),
2605 .data = .{ .imm = stack_adjustment },
2639 .data = .{ .imm = off },
26062640 });
26072641 }
26082642
......@@ -2730,14 +2764,14 @@ fn airCall(self: *Self, inst: Air.Inst.Index) !void {
27302764 }
27312765 } else unreachable;
27322766
2733 if (stack_adjustment > 0) {
2767 if (stack_adjustment) |off| {
27342768 // Readjust the stack
27352769 _ = try self.addInst(.{
27362770 .tag = .add,
27372771 .ops = (Mir.Ops{
27382772 .reg1 = .rsp,
27392773 }).encode(),
2740 .data = .{ .imm = stack_adjustment },
2774 .data = .{ .imm = off },
27412775 });
27422776 }
27432777
......@@ -3493,14 +3527,13 @@ fn genSetStackArg(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerE
34933527 return self.genSetStackArg(ty, stack_offset, .{ .register = reg });
34943528 },
34953529 .immediate => |imm| {
3496 const off = stack_offset + @intCast(i32, abi_size);
34973530 switch (abi_size) {
34983531 1, 2, 4 => {
34993532 // We have a positive stack offset value but we want a twos complement negative
35003533 // offset from rbp, which is at the top of the stack frame.
35013534 // mov [rbp+offset], immediate
35023535 const payload = try self.addExtra(Mir.ImmPair{
3503 .dest_off = @bitCast(u32, -off),
3536 .dest_off = @bitCast(u32, -stack_offset),
35043537 .operand = @truncate(u32, imm),
35053538 });
35063539 _ = try self.addInst(.{
......@@ -3540,62 +3573,7 @@ fn genSetStackArg(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerE
35403573 return self.genSetStackArg(ty, stack_offset, MCValue{ .register = reg });
35413574 }
35423575
3543 self.register_manager.freezeRegs(&.{ .rax, .rcx });
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 );
3576 try self.genInlineMemcpy(stack_offset, .rsp, ty, mcv);
35993577 },
36003578 .register => |reg| {
36013579 _ = try self.addInst(.{
......@@ -3605,48 +3583,20 @@ fn genSetStackArg(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerE
36053583 .reg2 = registerAlias(reg, @intCast(u32, abi_size)),
36063584 .flags = 0b10,
36073585 }).encode(),
3608 .data = .{ .imm = @bitCast(u32, -(stack_offset + @intCast(i32, abi_size))) },
3586 .data = .{ .imm = @bitCast(u32, -stack_offset) },
36093587 });
36103588 },
36113589 .ptr_stack_offset => {
36123590 const reg = try self.copyToTmpRegister(ty, mcv);
36133591 return self.genSetStackArg(ty, stack_offset, MCValue{ .register = reg });
36143592 },
3615 .stack_offset => |unadjusted_off| {
3593 .stack_offset => {
36163594 if (abi_size <= 8) {
36173595 const reg = try self.copyToTmpRegister(ty, mcv);
36183596 return self.genSetStackArg(ty, stack_offset, MCValue{ .register = reg });
36193597 }
36203598
3621 self.register_manager.freezeRegs(&.{ .rax, .rcx });
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 );
3599 try self.genInlineMemcpy(stack_offset, .rsp, ty, mcv);
36503600 },
36513601 else => return self.fail("TODO implement args on stack for {}", .{mcv}),
36523602 }
......@@ -3677,17 +3627,13 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerErro
36773627 return self.genSetStack(ty, stack_offset, .{ .register = reg });
36783628 },
36793629 .immediate => |x_big| {
3680 const adj_off = stack_offset + @intCast(i32, abi_size);
3681 if (adj_off > 128) {
3630 if (stack_offset > 128) {
36823631 return self.fail("TODO implement set stack variable with large stack offset", .{});
36833632 }
36843633 switch (abi_size) {
36853634 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
36893635 const payload = try self.addExtra(Mir.ImmPair{
3690 .dest_off = @bitCast(u32, -adj_off),
3636 .dest_off = @bitCast(u32, -stack_offset),
36913637 .operand = @truncate(u32, x_big),
36923638 });
36933639 _ = try self.addInst(.{
......@@ -3705,15 +3651,11 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerErro
37053651 });
37063652 },
37073653 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
37123654 // 64 bit write to memory would take two mov's anyways so we
37133655 // insted just use two 32 bit writes to avoid register allocation
37143656 {
37153657 const payload = try self.addExtra(Mir.ImmPair{
3716 .dest_off = @bitCast(u32, negative_offset + 4),
3658 .dest_off = @bitCast(u32, -stack_offset + 4),
37173659 .operand = @truncate(u32, x_big >> 32),
37183660 });
37193661 _ = try self.addInst(.{
......@@ -3727,7 +3669,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerErro
37273669 }
37283670 {
37293671 const payload = try self.addExtra(Mir.ImmPair{
3730 .dest_off = @bitCast(u32, negative_offset),
3672 .dest_off = @bitCast(u32, -stack_offset),
37313673 .operand = @truncate(u32, x_big),
37323674 });
37333675 _ = try self.addInst(.{
......@@ -3749,16 +3691,54 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerErro
37493691 if (stack_offset > math.maxInt(i32)) {
37503692 return self.fail("stack offset too large", .{});
37513693 }
3752 const adj_off = stack_offset + @intCast(i32, abi_size);
3753 _ = try self.addInst(.{
3754 .tag = .mov,
3755 .ops = (Mir.Ops{
3756 .reg1 = .rbp,
3757 .reg2 = registerAlias(reg, @intCast(u32, abi_size)),
3758 .flags = 0b10,
3759 }).encode(),
3760 .data = .{ .imm = @bitCast(u32, -adj_off) },
3761 });
3694
3695 const is_power_of_two = (abi_size % 2) == 0;
3696 if (!is_power_of_two) {
3697 self.register_manager.freezeRegs(&.{reg});
3698 defer self.register_manager.unfreezeRegs(&.{reg});
3699
3700 const tmp_reg = try self.copyToTmpRegister(ty, mcv);
3701
3702 var next_offset = stack_offset;
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 }
37623742 },
37633743 .memory,
37643744 .embedded_in_code,
......@@ -3770,65 +3750,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerErro
37703750 return self.genSetStack(ty, stack_offset, MCValue{ .register = reg });
37713751 }
37723752
3773 try self.register_manager.getReg(.rax, null);
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 );
3753 try self.genInlineMemcpy(stack_offset, .rbp, ty, mcv);
38323754 },
38333755 .ptr_stack_offset => {
38343756 const reg = try self.copyToTmpRegister(ty, mcv);
......@@ -3845,48 +3767,89 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerErro
38453767 return self.genSetStack(ty, stack_offset, MCValue{ .register = reg });
38463768 }
38473769
3848 self.register_manager.freezeRegs(&.{ .rax, .rcx, .rbp });
3849 defer self.register_manager.unfreezeRegs(&.{ .rax, .rcx, .rbp });
3770 try self.genInlineMemcpy(stack_offset, .rbp, ty, mcv);
3771 },
3772 }
3773}
38503774
3851 const regs = try self.register_manager.allocRegs(3, .{ null, null, null });
3852 const addr_reg = regs[0];
3853 const count_reg = regs[1];
3854 const tmp_reg = regs[2];
3775fn genInlineMemcpy(self: *Self, stack_offset: i32, stack_reg: Register, ty: Type, val: MCValue) InnerError!void {
3776 const abi_size = ty.abiSize(self.target.*);
38553777
3856 try self.register_manager.getReg(.rax, null);
3857 try self.register_manager.getReg(.rcx, null);
3778 try self.register_manager.getReg(.rax, null);
3779 try self.register_manager.getReg(.rcx, null);
38583780
3859 _ = try self.addInst(.{
3860 .tag = .lea,
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 });
3781 self.register_manager.freezeRegs(&.{ .rax, .rcx, .rbp });
3782 defer self.register_manager.unfreezeRegs(&.{ .rax, .rcx, .rbp });
38673783
3868 // TODO allow for abi_size to be u64
3869 try self.genSetReg(Type.u32, count_reg, .{ .immediate = @intCast(u32, abi_size) });
3784 const addr_reg: Register = blk: {
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(
3872 -(stack_offset + @intCast(i32, abi_size)),
3873 .rbp,
3874 addr_reg.to64(),
3875 count_reg.to64(),
3876 tmp_reg.to8(),
3877 );
3878 },
3879 }
3880}
3844 self.register_manager.freezeRegs(&.{addr_reg});
3845 defer self.register_manager.unfreezeRegs(&.{addr_reg});
3846
3847 const regs = try self.register_manager.allocRegs(2, .{ null, null });
3848 const count_reg = regs[0].to64();
3849 const tmp_reg = regs[1].to8();
3850
3851 try self.genSetReg(Type.u32, count_reg, .{ .immediate = @intCast(u32, abi_size) });
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 {
38903853 // mov rcx, 0
38913854 _ = try self.addInst(.{
38923855 .tag = .mov,
......@@ -3939,7 +3902,7 @@ fn genInlineMemcpy(
39393902 .reg1 = stack_reg,
39403903 .reg2 = tmp_reg.to8(),
39413904 }).encode(),
3942 .data = .{ .imm = @bitCast(u32, stack_offset) },
3905 .data = .{ .imm = @bitCast(u32, -stack_offset) },
39433906 });
39443907
39453908 // add rcx, 1
......@@ -3983,11 +3946,10 @@ fn genInlineMemcpy(
39833946fn genInlineMemset(self: *Self, ty: Type, stack_offset: i32, value: MCValue) InnerError!void {
39843947 try self.register_manager.getReg(.rax, null);
39853948 const abi_size = ty.abiSize(self.target.*);
3986 const adj_off = stack_offset + @intCast(i32, abi_size);
3987 if (adj_off > 128) {
3949 if (stack_offset > 128) {
39883950 return self.fail("TODO inline memset with large stack offset", .{});
39893951 }
3990 const negative_offset = @bitCast(u32, -adj_off);
3952 const negative_offset = @bitCast(u32, -stack_offset);
39913953
39923954 // We are actually counting `abi_size` bytes; however, we reuse the index register
39933955 // 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
40754037 const abi_size = ty.abiSize(self.target.*);
40764038 switch (mcv) {
40774039 .dead => unreachable,
4078 .ptr_stack_offset => |unadjusted_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);
4040 .ptr_stack_offset => |off| {
40824041 if (off < std.math.minInt(i32) or off > std.math.maxInt(i32)) {
40834042 return self.fail("stack offset too large", .{});
40844043 }
......@@ -4301,8 +4260,7 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
43014260 }
43024261 }
43034262 },
4304 .stack_offset => |unadjusted_off| {
4305 const off = unadjusted_off + @intCast(i32, abi_size);
4263 .stack_offset => |off| {
43064264 if (off < std.math.minInt(i32) or off > std.math.maxInt(i32)) {
43074265 return self.fail("stack offset too large", .{});
43084266 }
......@@ -4379,8 +4337,8 @@ fn airArrayToSlice(self: *Self, inst: Air.Inst.Index) !void {
43794337 const array_len = array_ty.arrayLenIncludingSentinel();
43804338 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else blk: {
43814339 const stack_offset = @intCast(i32, try self.allocMem(inst, 16, 16));
4382 try self.genSetStack(ptr_ty, stack_offset + 8, ptr);
4383 try self.genSetStack(Type.initTag(.u64), stack_offset, .{ .immediate = array_len });
4340 try self.genSetStack(ptr_ty, stack_offset, ptr);
4341 try self.genSetStack(Type.initTag(.u64), stack_offset - 8, .{ .immediate = array_len });
43844342 break :blk .{ .stack_offset = stack_offset };
43854343 };
43864344 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
......@@ -4620,6 +4578,9 @@ fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue {
46204578 }
46214579
46224580 switch (typed_value.ty.zigTypeTag()) {
4581 .Array => {
4582 return self.lowerUnnamedConst(typed_value);
4583 },
46234584 .Pointer => switch (typed_value.ty.ptrSize()) {
46244585 .Slice => {
46254586 return self.lowerUnnamedConst(typed_value);
......@@ -4790,7 +4751,6 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues {
47904751 var next_stack_offset: u32 = 0;
47914752 var count: usize = param_types.len;
47924753 while (count > 0) : (count -= 1) {
4793 // for (param_types) |ty, i| {
47944754 const i = count - 1;
47954755 const ty = param_types[i];
47964756 if (!ty.hasRuntimeBits()) {
......@@ -4799,6 +4759,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues {
47994759 continue;
48004760 }
48014761 const param_size = @intCast(u32, ty.abiSize(self.target.*));
4762 const param_align = @intCast(u32, ty.abiAlignment(self.target.*));
48024763 if (by_reg.get(i)) |int_reg| {
48034764 const aliased_reg = registerAlias(c_abi_int_param_regs[int_reg], param_size);
48044765 result.args[i] = .{ .register = aliased_reg };
......@@ -4809,8 +4770,9 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues {
48094770 // such as ptr and len of slices as separate registers.
48104771 // TODO: also we need to honor the C ABI for relevant types rather than passing on
48114772 // the stack here.
4812 result.args[i] = .{ .stack_offset = @intCast(i32, next_stack_offset) };
4813 next_stack_offset += param_size;
4773 const offset = mem.alignForwardGeneric(u32, next_stack_offset + param_size, param_align);
4774 result.args[i] = .{ .stack_offset = @intCast(i32, offset) };
4775 next_stack_offset = offset;
48144776 }
48154777 }
48164778
......@@ -4883,8 +4845,8 @@ fn parseRegName(name: []const u8) ?Register {
48834845 return std.meta.stringToEnum(Register, name);
48844846}
48854847
4848/// Returns register wide enough to hold at least `size_bytes`.
48864849fn registerAlias(reg: Register, size_bytes: u32) Register {
4887 // For x86_64 we have to pick a smaller register alias depending on abi size.
48884850 if (size_bytes == 0) {
48894851 unreachable; // should be comptime known
48904852 } 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 {
931931 const payload = emit.mir.instructions.items(.data)[inst].payload;
932932 const arg_dbg_info = emit.mir.extraData(Mir.ArgDbgInfo, payload).data;
933933 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);
935935}
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 {
938938 const ty_str = emit.mir.function.air.instructions.items(.data)[inst].ty_str;
939939 const zir = &emit.mir.function.mod_fn.owner_decl.getFileScope().zir;
940940 const name = zir.nullTerminatedString(ty_str.str);
941941 const name_with_null = name.ptr[0 .. name.len + 1];
942942 const ty = emit.mir.function.air.getRefType(ty_str.ty);
943 const abi_size = ty.abiSize(emit.bin_file.options.target);
944943
945944 switch (mcv) {
946945 .register => |reg| {
......@@ -960,7 +959,7 @@ fn genArgDbgInfo(emit: *Emit, inst: Air.Inst.Index, mcv: MCValue, arg_index: u32
960959 .none => {},
961960 }
962961 },
963 .stack_offset => {
962 .stack_offset => |off| {
964963 switch (emit.debug_output) {
965964 .dwarf => |dbg_out| {
966965 // 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
968967 // prologue, and 8 bytes for return address.
969968 // TODO we need to make this more generic if we don't use rbp as the frame pointer
970969 // 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;
972971 try dbg_out.dbg_info.ensureUnusedCapacity(8);
973972 dbg_out.dbg_info.appendAssumeCapacity(link.File.Elf.abbrev_parameter);
974973 const fixup = dbg_out.dbg_info.items.len;
src/arch/x86_64/Mir.zig+1
......@@ -413,6 +413,7 @@ pub const DbgLineColumn = struct {
413413pub const ArgDbgInfo = struct {
414414 air_inst: Air.Inst.Index,
415415 arg_index: u32,
416 max_stack: u32,
416417};
417418
418419pub 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 {
273273test "runtime known array index has best alignment possible" {
274274 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
275275 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
276 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
277276 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
278277
279278 // take full advantage of over-alignment
test/behavior/array.zig+1
......@@ -8,6 +8,7 @@ const expectEqual = testing.expectEqual;
88test "array to slice" {
99 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1010 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
11 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
1112
1213 const a: u32 align(4) = 3;
1314 const b: u32 align(8) = 4;
test/behavior/cast.zig+2-3
......@@ -199,7 +199,7 @@ fn MakeType(comptime T: type) type {
199199
200200test "implicit cast from *[N]T to [*c]T" {
201201 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
204204 var x: [4]u16 = [4]u16{ 0, 1, 2, 3 };
205205 var y: [*c]u16 = &x;
......@@ -274,7 +274,7 @@ test "*const ?[*]const T to [*c]const [*c]const T" {
274274
275275test "array coersion to undefined at runtime" {
276276 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
279279 @setRuntimeSafety(true);
280280
......@@ -339,7 +339,6 @@ test "peer type unsigned int to signed" {
339339test "expected [*c]const u8, found [*:0]const u8" {
340340 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
341341 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
342 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
343342
344343 var a: [*:0]const u8 = "hello";
345344 var b: [*c]const u8 = a;
test/behavior/slice.zig-3
......@@ -29,7 +29,6 @@ comptime {
2929test "slicing" {
3030 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
3131 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
32 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
3332 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
3433
3534 var array: [20]i32 = undefined;
......@@ -223,7 +222,6 @@ test "compile time slice of pointer to hard coded address" {
223222test "slice string literal has correct type" {
224223 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
225224 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
226 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
227225
228226 comptime {
229227 try expect(@TypeOf("aoeu"[0..]) == *const [4:0]u8);
......@@ -365,7 +363,6 @@ test "empty array to slice" {
365363test "@ptrCast slice to pointer" {
366364 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
367365 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
368 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
369366
370367 const S = struct {
371368 fn doTheTest() !void {