| ... | ... | @@ -582,10 +582,10 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 582 | 582 | |
| 583 | 583 | switch (air_tags[inst]) { |
| 584 | 584 | // zig fmt: off |
| 585 | | .add, .ptr_add => try self.airAdd(inst), |
| 585 | .add => try self.airAdd(inst), |
| 586 | 586 | .addwrap => try self.airAddWrap(inst), |
| 587 | 587 | .add_sat => try self.airAddSat(inst), |
| 588 | | .sub, .ptr_sub => try self.airSub(inst), |
| 588 | .sub => try self.airSub(inst), |
| 589 | 589 | .subwrap => try self.airSubWrap(inst), |
| 590 | 590 | .sub_sat => try self.airSubSat(inst), |
| 591 | 591 | .mul => try self.airMul(inst), |
| ... | ... | @@ -597,6 +597,8 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 597 | 597 | .shl_sat => try self.airShlSat(inst), |
| 598 | 598 | .min => try self.airMin(inst), |
| 599 | 599 | .max => try self.airMax(inst), |
| 600 | .ptr_add => try self.airPtrAdd(inst), |
| 601 | .ptr_sub => try self.airPtrSub(inst), |
| 600 | 602 | .slice => try self.airSlice(inst), |
| 601 | 603 | |
| 602 | 604 | .sqrt, |
| ... | ... | @@ -808,8 +810,8 @@ fn allocMem(self: *Self, inst: Air.Inst.Index, abi_size: u32, abi_align: u32) !u |
| 808 | 810 | if (abi_align > self.stack_align) |
| 809 | 811 | self.stack_align = abi_align; |
| 810 | 812 | // 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; |
| 813 | 815 | if (self.next_stack_offset > self.max_end_stack) |
| 814 | 816 | self.max_end_stack = self.next_stack_offset; |
| 815 | 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 | 823 | |
| 822 | 824 | /// Use a pointer instruction as the basis for allocating stack memory. |
| 823 | 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 | 829 | if (!elem_ty.hasRuntimeBits()) { |
| 827 | 830 | return self.allocMem(inst, 8, 8); |
| ... | ... | @@ -831,7 +834,7 @@ fn allocMemPtr(self: *Self, inst: Air.Inst.Index) !u32 { |
| 831 | 834 | return self.fail("type '{}' too big to fit into stack frame", .{elem_ty}); |
| 832 | 835 | }; |
| 833 | 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 | 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 | 967 | const reg: Register = blk: { |
| 965 | 968 | if (operand.isRegister()) { |
| 966 | 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 | 973 | const mcv = try self.copyToNewRegister(inst, src_ty, operand); |
| ... | ... | @@ -1068,13 +1071,81 @@ fn airMax(self: *Self, inst: Air.Inst.Index) !void { |
| 1068 | 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 | 1131 | fn airSlice(self: *Self, inst: Air.Inst.Index) !void { |
| 1072 | 1132 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 1073 | 1133 | 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 | |
| 1078 | 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 | 1449 | const dst_mcv: MCValue = blk: { |
| 1379 | 1450 | switch (operand) { |
| 1380 | 1451 | .stack_offset => |off| { |
| 1381 | | break :blk MCValue{ .stack_offset = off + 8 }; |
| 1452 | break :blk MCValue{ .stack_offset = off }; |
| 1382 | 1453 | }, |
| 1383 | 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 | 1466 | const dst_mcv: MCValue = blk: { |
| 1396 | 1467 | switch (operand) { |
| 1397 | 1468 | .stack_offset => |off| { |
| 1398 | | break :blk MCValue{ .stack_offset = off }; |
| 1469 | break :blk MCValue{ .stack_offset = off - 8 }; |
| 1399 | 1470 | }, |
| 1400 | 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 | 1534 | .reg2 = .rbp, |
| 1464 | 1535 | .flags = 0b01, |
| 1465 | 1536 | }).encode(), |
| 1466 | | .data = .{ .imm = @bitCast(u32, -@intCast(i32, off + 16)) }, |
| 1537 | .data = .{ .imm = @bitCast(u32, -@intCast(i32, off)) }, |
| 1467 | 1538 | }); |
| 1468 | 1539 | }, |
| 1469 | 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 | 1565 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 1495 | 1566 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 1496 | 1567 | const array_ty = self.air.typeOf(bin_op.lhs); |
| 1497 | | const array_abi_size = array_ty.abiSize(self.target.*); |
| 1498 | 1568 | const array = try self.resolveInst(bin_op.lhs); |
| 1499 | 1569 | array.freezeIfRegister(&self.register_manager); |
| 1500 | 1570 | defer array.unfreezeIfRegister(&self.register_manager); |
| ... | ... | @@ -1520,7 +1590,7 @@ fn airArrayElemVal(self: *Self, inst: Air.Inst.Index) !void { |
| 1520 | 1590 | .reg1 = addr_reg.to64(), |
| 1521 | 1591 | .reg2 = .rbp, |
| 1522 | 1592 | }).encode(), |
| 1523 | | .data = .{ .imm = @bitCast(u32, -(off + @intCast(i32, array_abi_size))) }, |
| 1593 | .data = .{ .imm = @bitCast(u32, -off) }, |
| 1524 | 1594 | }); |
| 1525 | 1595 | }, |
| 1526 | 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 | 1775 | return self.genSetStack(elem_ty, off, MCValue{ .register = tmp_reg }); |
| 1706 | 1776 | } |
| 1707 | 1777 | |
| 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); |
| 1738 | 1779 | }, |
| 1739 | 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 | 2057 | const mcv = try self.resolveInst(operand); |
| 2017 | 2058 | const ptr_ty = self.air.typeOf(operand); |
| 2018 | 2059 | const struct_ty = ptr_ty.childType(); |
| 2019 | | const struct_size = @intCast(u32, struct_ty.abiSize(self.target.*)); |
| 2020 | 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 | 2062 | const dst_mcv: MCValue = result: { |
| 2025 | 2063 | switch (mcv) { |
| ... | ... | @@ -2035,8 +2073,7 @@ fn structFieldPtr(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, inde |
| 2035 | 2073 | break :result dst_mcv; |
| 2036 | 2074 | }, |
| 2037 | 2075 | .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); |
| 2040 | 2077 | break :result MCValue{ .ptr_stack_offset = ptr_stack_offset }; |
| 2041 | 2078 | }, |
| 2042 | 2079 | .register => |reg| { |
| ... | ... | @@ -2076,15 +2113,12 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void { |
| 2076 | 2113 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 2077 | 2114 | const mcv = try self.resolveInst(operand); |
| 2078 | 2115 | const struct_ty = self.air.typeOf(operand); |
| 2079 | | const struct_size = struct_ty.abiSize(self.target.*); |
| 2080 | 2116 | const struct_field_offset = struct_ty.structFieldOffset(index, self.target.*); |
| 2081 | 2117 | const struct_field_ty = struct_ty.structFieldType(index); |
| 2082 | | const struct_field_size = struct_field_ty.abiSize(self.target.*); |
| 2083 | 2118 | |
| 2084 | 2119 | switch (mcv) { |
| 2085 | 2120 | .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); |
| 2088 | 2122 | break :result MCValue{ .stack_offset = stack_offset }; |
| 2089 | 2123 | }, |
| 2090 | 2124 | .register => |reg| { |
| ... | ... | @@ -2141,14 +2175,6 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void { |
| 2141 | 2175 | /// Currently, the following ops are supported: |
| 2142 | 2176 | /// ADD, SUB, XOR, OR, AND |
| 2143 | 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 | 2178 | // TODO: make this algorithm less bad |
| 2153 | 2179 | const lhs = try self.resolveInst(op_lhs); |
| 2154 | 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 | 2187 | const dst_ty = self.air.typeOfIndex(inst); |
| 2162 | 2188 | var dst_mcv: MCValue = undefined; |
| 2163 | 2189 | var src_mcv: MCValue = undefined; |
| 2190 | |
| 2164 | 2191 | if (self.reuseOperand(inst, op_lhs, 0, lhs)) { |
| 2165 | 2192 | // LHS dies; use it as the destination. |
| 2166 | 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 | 2234 | dst_mcv.freezeIfRegister(&self.register_manager); |
| 2208 | 2235 | defer dst_mcv.unfreezeIfRegister(&self.register_manager); |
| 2209 | 2236 | |
| 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); |
| 2212 | 2238 | } |
| 2213 | 2239 | }, |
| 2214 | 2240 | else => {}, |
| 2215 | 2241 | } |
| 2216 | 2242 | |
| 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), |
| 2221 | 2246 | .bool_or, .bit_or => try self.genBinMathOpMir(.@"or", dst_ty, dst_mcv, src_mcv), |
| 2222 | 2247 | .bool_and, .bit_and => try self.genBinMathOpMir(.@"and", dst_ty, dst_mcv, src_mcv), |
| 2223 | 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 | 2250 | .mul, .mulwrap => try self.genIMulOpMir(dst_ty, dst_mcv, src_mcv), |
| 2226 | 2251 | else => unreachable, |
| 2227 | 2252 | } |
| 2228 | | |
| 2229 | 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 | 2268 | .none => unreachable, |
| 2245 | 2269 | .undef => try self.genSetReg(dst_ty, dst_reg, .undef), |
| 2246 | 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 | 2277 | .ptr_embedded_in_code => unreachable, |
| 2249 | 2278 | .register => |src_reg| { |
| 2250 | 2279 | _ = try self.addInst(.{ |
| ... | ... | @@ -2265,21 +2294,21 @@ fn genBinMathOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MC |
| 2265 | 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 | 2302 | assert(abi_size <= 8); |
| 2270 | 2303 | self.register_manager.freezeRegs(&.{dst_reg}); |
| 2271 | 2304 | defer self.register_manager.unfreezeRegs(&.{dst_reg}); |
| 2272 | 2305 | const reg = try self.copyToTmpRegister(dst_ty, src_mcv); |
| 2273 | 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 | 2308 | .stack_offset => |off| { |
| 2279 | 2309 | if (off > math.maxInt(i32)) { |
| 2280 | 2310 | return self.fail("stack offset too large", .{}); |
| 2281 | 2311 | } |
| 2282 | | const adj_off = off + @intCast(i32, abi_size); |
| 2283 | 2312 | _ = try self.addInst(.{ |
| 2284 | 2313 | .tag = mir_tag, |
| 2285 | 2314 | .ops = (Mir.Ops{ |
| ... | ... | @@ -2287,7 +2316,7 @@ fn genBinMathOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MC |
| 2287 | 2316 | .reg2 = .rbp, |
| 2288 | 2317 | .flags = 0b01, |
| 2289 | 2318 | }).encode(), |
| 2290 | | .data = .{ .imm = @bitCast(u32, -adj_off) }, |
| 2319 | .data = .{ .imm = @bitCast(u32, -off) }, |
| 2291 | 2320 | }); |
| 2292 | 2321 | }, |
| 2293 | 2322 | .compare_flags_unsigned => { |
| ... | ... | @@ -2305,7 +2334,6 @@ fn genBinMathOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MC |
| 2305 | 2334 | if (abi_size > 8) { |
| 2306 | 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 | 2338 | switch (src_mcv) { |
| 2311 | 2339 | .none => unreachable, |
| ... | ... | @@ -2321,7 +2349,7 @@ fn genBinMathOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MC |
| 2321 | 2349 | .reg2 = registerAlias(src_reg, @intCast(u32, abi_size)), |
| 2322 | 2350 | .flags = 0b10, |
| 2323 | 2351 | }).encode(), |
| 2324 | | .data = .{ .imm = @bitCast(u32, -adj_off) }, |
| 2352 | .data = .{ .imm = @bitCast(u32, -off) }, |
| 2325 | 2353 | }); |
| 2326 | 2354 | }, |
| 2327 | 2355 | .immediate => |imm| { |
| ... | ... | @@ -2342,7 +2370,7 @@ fn genBinMathOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MC |
| 2342 | 2370 | else => unreachable, |
| 2343 | 2371 | }; |
| 2344 | 2372 | const payload = try self.addExtra(Mir.ImmPair{ |
| 2345 | | .dest_off = @bitCast(u32, -adj_off), |
| 2373 | .dest_off = @bitCast(u32, -off), |
| 2346 | 2374 | .operand = @truncate(u32, imm), |
| 2347 | 2375 | }); |
| 2348 | 2376 | _ = try self.addInst(.{ |
| ... | ... | @@ -2493,9 +2521,16 @@ fn airArg(self: *Self, inst: Air.Inst.Index) !void { |
| 2493 | 2521 | self.arg_index += 1; |
| 2494 | 2522 | |
| 2495 | 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 | 2530 | const payload = try self.addExtra(Mir.ArgDbgInfo{ |
| 2497 | 2531 | .air_inst = inst, |
| 2498 | 2532 | .arg_index = arg_index, |
| 2533 | .max_stack = @intCast(u32, max_stack), |
| 2499 | 2534 | }); |
| 2500 | 2535 | _ = try self.addInst(.{ |
| 2501 | 2536 | .tag = .arg_dbg_info, |
| ... | ... | @@ -2511,11 +2546,9 @@ fn airArg(self: *Self, inst: Air.Inst.Index) !void { |
| 2511 | 2546 | self.register_manager.getRegAssumeFree(reg.to64(), inst); |
| 2512 | 2547 | break :blk mcv; |
| 2513 | 2548 | }, |
| 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 }; |
| 2519 | 2552 | }, |
| 2520 | 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 | 2591 | var info = try self.resolveCallingConventionValues(fn_ty); |
| 2559 | 2592 | defer info.deinit(self); |
| 2560 | 2593 | |
| 2561 | | var stack_adjustment: u32 = 0; |
| 2594 | var stack_adjustment: ?u32 = null; |
| 2562 | 2595 | for (args) |arg, arg_i| { |
| 2563 | 2596 | const mc_arg = info.args[arg_i]; |
| 2564 | 2597 | const arg_ty = self.air.typeOf(arg); |
| ... | ... | @@ -2572,9 +2605,10 @@ fn airCall(self: *Self, inst: Air.Inst.Index) !void { |
| 2572 | 2605 | try self.genSetReg(arg_ty, reg, arg_mcv); |
| 2573 | 2606 | }, |
| 2574 | 2607 | .stack_offset => |off| { |
| 2575 | | const abi_size = @intCast(u32, arg_ty.abiSize(self.target.*)); |
| 2576 | 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 | 2613 | .ptr_stack_offset => { |
| 2580 | 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 | 2629 | } |
| 2596 | 2630 | } |
| 2597 | 2631 | |
| 2598 | | if (stack_adjustment > 0) { |
| 2632 | if (stack_adjustment) |off| { |
| 2599 | 2633 | // Adjust the stack |
| 2600 | 2634 | _ = try self.addInst(.{ |
| 2601 | 2635 | .tag = .sub, |
| 2602 | 2636 | .ops = (Mir.Ops{ |
| 2603 | 2637 | .reg1 = .rsp, |
| 2604 | 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 | 2764 | } |
| 2731 | 2765 | } else unreachable; |
| 2732 | 2766 | |
| 2733 | | if (stack_adjustment > 0) { |
| 2767 | if (stack_adjustment) |off| { |
| 2734 | 2768 | // Readjust the stack |
| 2735 | 2769 | _ = try self.addInst(.{ |
| 2736 | 2770 | .tag = .add, |
| 2737 | 2771 | .ops = (Mir.Ops{ |
| 2738 | 2772 | .reg1 = .rsp, |
| 2739 | 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 | 3527 | return self.genSetStackArg(ty, stack_offset, .{ .register = reg }); |
| 3494 | 3528 | }, |
| 3495 | 3529 | .immediate => |imm| { |
| 3496 | | const off = stack_offset + @intCast(i32, abi_size); |
| 3497 | 3530 | switch (abi_size) { |
| 3498 | 3531 | 1, 2, 4 => { |
| 3499 | 3532 | // We have a positive stack offset value but we want a twos complement negative |
| 3500 | 3533 | // offset from rbp, which is at the top of the stack frame. |
| 3501 | 3534 | // mov [rbp+offset], immediate |
| 3502 | 3535 | const payload = try self.addExtra(Mir.ImmPair{ |
| 3503 | | .dest_off = @bitCast(u32, -off), |
| 3536 | .dest_off = @bitCast(u32, -stack_offset), |
| 3504 | 3537 | .operand = @truncate(u32, imm), |
| 3505 | 3538 | }); |
| 3506 | 3539 | _ = try self.addInst(.{ |
| ... | ... | @@ -3540,62 +3573,7 @@ fn genSetStackArg(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerE |
| 3540 | 3573 | return self.genSetStackArg(ty, stack_offset, MCValue{ .register = reg }); |
| 3541 | 3574 | } |
| 3542 | 3575 | |
| 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); |
| 3599 | 3577 | }, |
| 3600 | 3578 | .register => |reg| { |
| 3601 | 3579 | _ = try self.addInst(.{ |
| ... | ... | @@ -3605,48 +3583,20 @@ fn genSetStackArg(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerE |
| 3605 | 3583 | .reg2 = registerAlias(reg, @intCast(u32, abi_size)), |
| 3606 | 3584 | .flags = 0b10, |
| 3607 | 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 | 3589 | .ptr_stack_offset => { |
| 3612 | 3590 | const reg = try self.copyToTmpRegister(ty, mcv); |
| 3613 | 3591 | return self.genSetStackArg(ty, stack_offset, MCValue{ .register = reg }); |
| 3614 | 3592 | }, |
| 3615 | | .stack_offset => |unadjusted_off| { |
| 3593 | .stack_offset => { |
| 3616 | 3594 | if (abi_size <= 8) { |
| 3617 | 3595 | const reg = try self.copyToTmpRegister(ty, mcv); |
| 3618 | 3596 | return self.genSetStackArg(ty, stack_offset, MCValue{ .register = reg }); |
| 3619 | 3597 | } |
| 3620 | 3598 | |
| 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); |
| 3650 | 3600 | }, |
| 3651 | 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 | 3627 | return self.genSetStack(ty, stack_offset, .{ .register = reg }); |
| 3678 | 3628 | }, |
| 3679 | 3629 | .immediate => |x_big| { |
| 3680 | | const adj_off = stack_offset + @intCast(i32, abi_size); |
| 3681 | | if (adj_off > 128) { |
| 3630 | if (stack_offset > 128) { |
| 3682 | 3631 | return self.fail("TODO implement set stack variable with large stack offset", .{}); |
| 3683 | 3632 | } |
| 3684 | 3633 | switch (abi_size) { |
| 3685 | 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 | 3635 | const payload = try self.addExtra(Mir.ImmPair{ |
| 3690 | | .dest_off = @bitCast(u32, -adj_off), |
| 3636 | .dest_off = @bitCast(u32, -stack_offset), |
| 3691 | 3637 | .operand = @truncate(u32, x_big), |
| 3692 | 3638 | }); |
| 3693 | 3639 | _ = try self.addInst(.{ |
| ... | ... | @@ -3705,15 +3651,11 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerErro |
| 3705 | 3651 | }); |
| 3706 | 3652 | }, |
| 3707 | 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 | 3654 | // 64 bit write to memory would take two mov's anyways so we |
| 3713 | 3655 | // insted just use two 32 bit writes to avoid register allocation |
| 3714 | 3656 | { |
| 3715 | 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 | 3659 | .operand = @truncate(u32, x_big >> 32), |
| 3718 | 3660 | }); |
| 3719 | 3661 | _ = try self.addInst(.{ |
| ... | ... | @@ -3727,7 +3669,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerErro |
| 3727 | 3669 | } |
| 3728 | 3670 | { |
| 3729 | 3671 | const payload = try self.addExtra(Mir.ImmPair{ |
| 3730 | | .dest_off = @bitCast(u32, negative_offset), |
| 3672 | .dest_off = @bitCast(u32, -stack_offset), |
| 3731 | 3673 | .operand = @truncate(u32, x_big), |
| 3732 | 3674 | }); |
| 3733 | 3675 | _ = try self.addInst(.{ |
| ... | ... | @@ -3749,16 +3691,54 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerErro |
| 3749 | 3691 | if (stack_offset > math.maxInt(i32)) { |
| 3750 | 3692 | return self.fail("stack offset too large", .{}); |
| 3751 | 3693 | } |
| 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 | } |
| 3762 | 3742 | }, |
| 3763 | 3743 | .memory, |
| 3764 | 3744 | .embedded_in_code, |
| ... | ... | @@ -3770,65 +3750,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerErro |
| 3770 | 3750 | return self.genSetStack(ty, stack_offset, MCValue{ .register = reg }); |
| 3771 | 3751 | } |
| 3772 | 3752 | |
| 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); |
| 3832 | 3754 | }, |
| 3833 | 3755 | .ptr_stack_offset => { |
| 3834 | 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 | 3767 | return self.genSetStack(ty, stack_offset, MCValue{ .register = reg }); |
| 3846 | 3768 | } |
| 3847 | 3769 | |
| 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 | } |
| 3850 | 3774 | |
| 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]; |
| 3775 | fn genInlineMemcpy(self: *Self, stack_offset: i32, stack_reg: Register, ty: Type, val: MCValue) InnerError!void { |
| 3776 | const abi_size = ty.abiSize(self.target.*); |
| 3855 | 3777 | |
| 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); |
| 3858 | 3780 | |
| 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 }); |
| 3867 | 3783 | |
| 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 | }; |
| 3870 | 3843 | |
| 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) }); |
| 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 | 3853 | // mov rcx, 0 |
| 3891 | 3854 | _ = try self.addInst(.{ |
| 3892 | 3855 | .tag = .mov, |
| ... | ... | @@ -3939,7 +3902,7 @@ fn genInlineMemcpy( |
| 3939 | 3902 | .reg1 = stack_reg, |
| 3940 | 3903 | .reg2 = tmp_reg.to8(), |
| 3941 | 3904 | }).encode(), |
| 3942 | | .data = .{ .imm = @bitCast(u32, stack_offset) }, |
| 3905 | .data = .{ .imm = @bitCast(u32, -stack_offset) }, |
| 3943 | 3906 | }); |
| 3944 | 3907 | |
| 3945 | 3908 | // add rcx, 1 |
| ... | ... | @@ -3983,11 +3946,10 @@ fn genInlineMemcpy( |
| 3983 | 3946 | fn genInlineMemset(self: *Self, ty: Type, stack_offset: i32, value: MCValue) InnerError!void { |
| 3984 | 3947 | try self.register_manager.getReg(.rax, null); |
| 3985 | 3948 | 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) { |
| 3988 | 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 | 3954 | // We are actually counting `abi_size` bytes; however, we reuse the index register |
| 3993 | 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 | 4037 | const abi_size = ty.abiSize(self.target.*); |
| 4076 | 4038 | switch (mcv) { |
| 4077 | 4039 | .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| { |
| 4082 | 4041 | if (off < std.math.minInt(i32) or off > std.math.maxInt(i32)) { |
| 4083 | 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 | 4260 | } |
| 4302 | 4261 | } |
| 4303 | 4262 | }, |
| 4304 | | .stack_offset => |unadjusted_off| { |
| 4305 | | const off = unadjusted_off + @intCast(i32, abi_size); |
| 4263 | .stack_offset => |off| { |
| 4306 | 4264 | if (off < std.math.minInt(i32) or off > std.math.maxInt(i32)) { |
| 4307 | 4265 | return self.fail("stack offset too large", .{}); |
| 4308 | 4266 | } |
| ... | ... | @@ -4379,8 +4337,8 @@ fn airArrayToSlice(self: *Self, inst: Air.Inst.Index) !void { |
| 4379 | 4337 | const array_len = array_ty.arrayLenIncludingSentinel(); |
| 4380 | 4338 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else blk: { |
| 4381 | 4339 | 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 }); |
| 4384 | 4342 | break :blk .{ .stack_offset = stack_offset }; |
| 4385 | 4343 | }; |
| 4386 | 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 | 4578 | } |
| 4621 | 4579 | |
| 4622 | 4580 | switch (typed_value.ty.zigTypeTag()) { |
| 4581 | .Array => { |
| 4582 | return self.lowerUnnamedConst(typed_value); |
| 4583 | }, |
| 4623 | 4584 | .Pointer => switch (typed_value.ty.ptrSize()) { |
| 4624 | 4585 | .Slice => { |
| 4625 | 4586 | return self.lowerUnnamedConst(typed_value); |
| ... | ... | @@ -4790,7 +4751,6 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues { |
| 4790 | 4751 | var next_stack_offset: u32 = 0; |
| 4791 | 4752 | var count: usize = param_types.len; |
| 4792 | 4753 | while (count > 0) : (count -= 1) { |
| 4793 | | // for (param_types) |ty, i| { |
| 4794 | 4754 | const i = count - 1; |
| 4795 | 4755 | const ty = param_types[i]; |
| 4796 | 4756 | if (!ty.hasRuntimeBits()) { |
| ... | ... | @@ -4799,6 +4759,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues { |
| 4799 | 4759 | continue; |
| 4800 | 4760 | } |
| 4801 | 4761 | const param_size = @intCast(u32, ty.abiSize(self.target.*)); |
| 4762 | const param_align = @intCast(u32, ty.abiAlignment(self.target.*)); |
| 4802 | 4763 | if (by_reg.get(i)) |int_reg| { |
| 4803 | 4764 | const aliased_reg = registerAlias(c_abi_int_param_regs[int_reg], param_size); |
| 4804 | 4765 | result.args[i] = .{ .register = aliased_reg }; |
| ... | ... | @@ -4809,8 +4770,9 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues { |
| 4809 | 4770 | // such as ptr and len of slices as separate registers. |
| 4810 | 4771 | // TODO: also we need to honor the C ABI for relevant types rather than passing on |
| 4811 | 4772 | // 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; |
| 4814 | 4776 | } |
| 4815 | 4777 | } |
| 4816 | 4778 | |
| ... | ... | @@ -4883,8 +4845,8 @@ fn parseRegName(name: []const u8) ?Register { |
| 4883 | 4845 | return std.meta.stringToEnum(Register, name); |
| 4884 | 4846 | } |
| 4885 | 4847 | |
| 4848 | /// Returns register wide enough to hold at least `size_bytes`. |
| 4886 | 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 | 4850 | if (size_bytes == 0) { |
| 4889 | 4851 | unreachable; // should be comptime known |
| 4890 | 4852 | } else if (size_bytes <= 1) { |