| ... | @@ -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 { |
| 582 | | 582 | |
| 583 | switch (air_tags[inst]) { | 583 | switch (air_tags[inst]) { |
| 584 | // zig fmt: off | 584 | // 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), |
| 601 | | 603 | |
| 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 appending | 812 | // 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 |
| 821 | | 823 | |
| 822 | /// Use a pointer instruction as the basis for allocating stack memory. | 824 | /// Use a pointer instruction as the basis for allocating stack memory. |
| 823 | fn allocMemPtr(self: *Self, inst: Air.Inst.Index) !u32 { | 825 | fn 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(); |
| 825 | | 828 | |
| 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.ptrAlign | 836 | // 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 | } |
| 837 | | 840 | |
| ... | @@ -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 | } |
| 1070 | | 1073 | |
| | 1074 | fn 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 | |
| | 1113 | fn 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 | |
| | 1122 | fn 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 | |
| 1071 | fn airSlice(self: *Self, inst: Air.Inst.Index) !void { | 1131 | fn 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 | .dead | 1135 | if (self.liveness.isUnused(inst)) { |
| 1076 | else | 1136 | 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 | } |
| 1080 | | 1151 | |
| ... | @@ -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 | } |
| 1707 | | 1777 | |
| 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.*)); | | |
| 2023 | | 2061 | |
| 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.*); | | |
| 2083 | | 2118 | |
| 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, AND | 2176 | /// ADD, SUB, XOR, OR, AND |
| 2143 | fn genBinMathOp(self: *Self, inst: Air.Inst.Index, op_lhs: Air.Inst.Ref, op_rhs: Air.Inst.Ref) !MCValue { | 2177 | fn 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 bad | 2178 | // 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); |
| 2209 | | 2236 | |
| 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 | } |
| 2216 | | 2242 | |
| 2217 | // Now for step 2, we assing an MIR instruction | 2243 | 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 | } |
| 2231 | | 2255 | |
| ... | @@ -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); | | |
| 2309 | | 2337 | |
| 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; |
| 2494 | | 2522 | |
| 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); |
| 2560 | | 2593 | |
| 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 | } |
| 2597 | | 2631 | |
| 2598 | if (stack_adjustment > 0) { | 2632 | if (stack_adjustment) |off| { |
| 2599 | // Adjust the stack | 2633 | // 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 | } |
| 2608 | | 2642 | |
| ... | @@ -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; |
| 2732 | | 2766 | |
| 2733 | if (stack_adjustment > 0) { | 2767 | if (stack_adjustment) |off| { |
| 2734 | // Readjust the stack | 2768 | // 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 | } |
| 2743 | | 2777 | |
| ... | @@ -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 negative | 3532 | // 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], immediate | 3534 | // 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 | } |
| 3542 | | 3575 | |
| 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 | } |
| 3620 | | 3598 | |
| 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 we | 3654 | // 64 bit write to memory would take two mov's anyways so we |
| 3713 | // insted just use two 32 bit writes to avoid register allocation | 3655 | // 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 | } |
| 3772 | | 3752 | |
| 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 | } |
| 3847 | | 3769 | |
| 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 | } |
| 3850 | | 3774 | |
| 3851 | const regs = try self.register_manager.allocRegs(3, .{ null, null, null }); | 3775 | fn 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]; | | |
| 3855 | | 3777 | |
| 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); |
| 3858 | | 3780 | |
| 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 | }); | | |
| 3867 | | 3783 | |
| 3868 | // TODO allow for abi_size to be u64 | 3784 | 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 | }; |
| 3870 | | 3843 | |
| 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 | } | | |
| 3881 | | 3852 | |
| 3882 | fn 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, 0 | 3853 | // 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 | }); |
| 3944 | | 3907 | |
| 3945 | // add rcx, 1 | 3908 | // add rcx, 1 |
| ... | @@ -3983,11 +3946,10 @@ fn genInlineMemcpy( | ... | @@ -3983,11 +3946,10 @@ fn genInlineMemcpy( |
| 3983 | fn genInlineMemset(self: *Self, ty: Type, stack_offset: i32, value: MCValue) InnerError!void { | 3946 | fn 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); |
| 3991 | | 3953 | |
| 3992 | // We are actually counting `abi_size` bytes; however, we reuse the index register | 3954 | // 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 | } |
| 4621 | | 4579 | |
| 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 on | 4771 | // 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 | } |
| 4816 | | 4778 | |
| ... | @@ -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 | } |
| 4885 | | 4847 | |
| | 4848 | /// Returns register wide enough to hold at least `size_bytes`. |
| 4886 | fn registerAlias(reg: Register, size_bytes: u32) Register { | 4849 | fn 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 known | 4851 | unreachable; // should be comptime known |
| 4890 | } else if (size_bytes <= 1) { | 4852 | } else if (size_bytes <= 1) { |