| ... | ... | @@ -586,11 +586,11 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 586 | 586 | |
| 587 | 587 | switch (air_tags[inst]) { |
| 588 | 588 | // zig fmt: off |
| 589 | | .add => try self.airAdd(inst), |
| 590 | | .addwrap => try self.airAdd(inst), |
| 589 | .add => try self.airBinOp(inst), |
| 590 | .addwrap => try self.airBinOp(inst), |
| 591 | 591 | .add_sat => try self.airAddSat(inst), |
| 592 | | .sub => try self.airSub(inst), |
| 593 | | .subwrap => try self.airSub(inst), |
| 592 | .sub => try self.airBinOp(inst), |
| 593 | .subwrap => try self.airBinOp(inst), |
| 594 | 594 | .sub_sat => try self.airSubSat(inst), |
| 595 | 595 | .mul => try self.airMul(inst), |
| 596 | 596 | .mulwrap => try self.airMul(inst), |
| ... | ... | @@ -601,8 +601,8 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 601 | 601 | .shl_sat => try self.airShlSat(inst), |
| 602 | 602 | .min => try self.airMin(inst), |
| 603 | 603 | .max => try self.airMax(inst), |
| 604 | | .ptr_add => try self.airPtrAdd(inst), |
| 605 | | .ptr_sub => try self.airPtrSub(inst), |
| 604 | .ptr_add => try self.airBinOp(inst), |
| 605 | .ptr_sub => try self.airBinOp(inst), |
| 606 | 606 | .slice => try self.airSlice(inst), |
| 607 | 607 | |
| 608 | 608 | .sqrt, |
| ... | ... | @@ -638,11 +638,11 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 638 | 638 | .cmp_vector => try self.airCmpVector(inst), |
| 639 | 639 | .cmp_lt_errors_len => try self.airCmpLtErrorsLen(inst), |
| 640 | 640 | |
| 641 | | .bool_and => try self.airBoolOp(inst), |
| 642 | | .bool_or => try self.airBoolOp(inst), |
| 643 | | .bit_and => try self.airBitAnd(inst), |
| 644 | | .bit_or => try self.airBitOr(inst), |
| 645 | | .xor => try self.airXor(inst), |
| 641 | .bool_and => try self.airBinOp(inst), |
| 642 | .bool_or => try self.airBinOp(inst), |
| 643 | .bit_and => try self.airBinOp(inst), |
| 644 | .bit_or => try self.airBinOp(inst), |
| 645 | .xor => try self.airBinOp(inst), |
| 646 | 646 | .shr, .shr_exact => try self.airShr(inst), |
| 647 | 647 | |
| 648 | 648 | .alloc => try self.airAlloc(inst), |
| ... | ... | @@ -1122,7 +1122,7 @@ fn airNot(self: *Self, inst: Air.Inst.Index) !void { |
| 1122 | 1122 | }, |
| 1123 | 1123 | else => {}, |
| 1124 | 1124 | } |
| 1125 | | break :result try self.genBinMathOp(inst, ty_op.operand, .bool_true); |
| 1125 | break :result try self.genBinOp(inst, ty_op.operand, .bool_true); |
| 1126 | 1126 | }; |
| 1127 | 1127 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| 1128 | 1128 | } |
| ... | ... | @@ -1159,7 +1159,7 @@ fn airMin(self: *Self, inst: Air.Inst.Index) !void { |
| 1159 | 1159 | }; |
| 1160 | 1160 | defer if (rhs_lock) |lock| self.register_manager.unlockReg(lock); |
| 1161 | 1161 | |
| 1162 | | try self.genBinMathOpMir(.cmp, ty, .{ .register = lhs_reg }, rhs_mcv); |
| 1162 | try self.genBinOpMir(.cmp, ty, .{ .register = lhs_reg }, rhs_mcv); |
| 1163 | 1163 | |
| 1164 | 1164 | const dst_mcv = try self.copyToRegisterWithInstTracking(inst, ty, rhs_mcv); |
| 1165 | 1165 | _ = try self.addInst(.{ |
| ... | ... | @@ -1185,63 +1185,12 @@ fn airMax(self: *Self, inst: Air.Inst.Index) !void { |
| 1185 | 1185 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 1186 | 1186 | } |
| 1187 | 1187 | |
| 1188 | | fn genPtrBinMathOp(self: *Self, inst: Air.Inst.Index, op_lhs: Air.Inst.Ref, op_rhs: Air.Inst.Ref) !MCValue { |
| 1189 | | const dst_ty = self.air.typeOfIndex(inst); |
| 1190 | | const elem_size = dst_ty.elemType2().abiSize(self.target.*); |
| 1191 | | const ptr = try self.resolveInst(op_lhs); |
| 1192 | | const offset = try self.resolveInst(op_rhs); |
| 1193 | | const offset_ty = self.air.typeOf(op_rhs); |
| 1194 | | |
| 1195 | | const offset_lock: ?RegisterLock = switch (offset) { |
| 1196 | | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), |
| 1197 | | else => null, |
| 1198 | | }; |
| 1199 | | defer if (offset_lock) |lock| self.register_manager.unlockReg(lock); |
| 1200 | | |
| 1201 | | const dst_mcv: MCValue = blk: { |
| 1202 | | if (self.reuseOperand(inst, op_lhs, 0, ptr)) { |
| 1203 | | if (ptr.isMemory() or ptr.isRegister()) break :blk ptr; |
| 1204 | | } |
| 1205 | | break :blk MCValue{ .register = try self.copyToTmpRegister(dst_ty, ptr) }; |
| 1206 | | }; |
| 1207 | | |
| 1208 | | const dst_mcv_lock: ?RegisterLock = switch (dst_mcv) { |
| 1209 | | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), |
| 1210 | | else => null, |
| 1211 | | }; |
| 1212 | | defer if (dst_mcv_lock) |lock| self.register_manager.unlockReg(lock); |
| 1213 | | |
| 1214 | | const offset_mcv: MCValue = blk: { |
| 1215 | | if (self.reuseOperand(inst, op_rhs, 1, offset)) { |
| 1216 | | if (offset.isRegister()) break :blk offset; |
| 1217 | | } |
| 1218 | | break :blk MCValue{ .register = try self.copyToTmpRegister(offset_ty, offset) }; |
| 1219 | | }; |
| 1220 | | |
| 1221 | | const offset_mcv_lock: ?RegisterLock = switch (offset_mcv) { |
| 1222 | | .register => |reg| self.register_manager.lockReg(reg), |
| 1223 | | else => null, |
| 1224 | | }; |
| 1225 | | defer if (offset_mcv_lock) |lock| self.register_manager.unlockReg(lock); |
| 1226 | | |
| 1227 | | try self.genIntMulComplexOpMir(offset_ty, offset_mcv, .{ .immediate = elem_size }); |
| 1228 | | |
| 1229 | | const tag = self.air.instructions.items(.tag)[inst]; |
| 1230 | | switch (tag) { |
| 1231 | | .ptr_add => try self.genBinMathOpMir(.add, dst_ty, dst_mcv, offset_mcv), |
| 1232 | | .ptr_sub => try self.genBinMathOpMir(.sub, dst_ty, dst_mcv, offset_mcv), |
| 1233 | | else => unreachable, |
| 1234 | | } |
| 1235 | | |
| 1236 | | return dst_mcv; |
| 1237 | | } |
| 1238 | | |
| 1239 | 1188 | fn airPtrAdd(self: *Self, inst: Air.Inst.Index) !void { |
| 1240 | 1189 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 1241 | 1190 | const result = if (self.liveness.isUnused(inst)) |
| 1242 | 1191 | .dead |
| 1243 | 1192 | else |
| 1244 | | try self.genPtrBinMathOp(inst, bin_op.lhs, bin_op.rhs); |
| 1193 | try self.genBinOp(inst, bin_op.lhs, bin_op.rhs); |
| 1245 | 1194 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 1246 | 1195 | } |
| 1247 | 1196 | |
| ... | ... | @@ -1250,7 +1199,7 @@ fn airPtrSub(self: *Self, inst: Air.Inst.Index) !void { |
| 1250 | 1199 | const result = if (self.liveness.isUnused(inst)) |
| 1251 | 1200 | .dead |
| 1252 | 1201 | else |
| 1253 | | try self.genPtrBinMathOp(inst, bin_op.lhs, bin_op.rhs); |
| 1202 | try self.genBinOp(inst, bin_op.lhs, bin_op.rhs); |
| 1254 | 1203 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 1255 | 1204 | } |
| 1256 | 1205 | |
| ... | ... | @@ -1275,21 +1224,12 @@ fn airSlice(self: *Self, inst: Air.Inst.Index) !void { |
| 1275 | 1224 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 1276 | 1225 | } |
| 1277 | 1226 | |
| 1278 | | fn airAdd(self: *Self, inst: Air.Inst.Index) !void { |
| 1279 | | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 1280 | | const result: MCValue = if (self.liveness.isUnused(inst)) |
| 1281 | | .dead |
| 1282 | | else |
| 1283 | | try self.genBinMathOp(inst, bin_op.lhs, bin_op.rhs); |
| 1284 | | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 1285 | | } |
| 1286 | | |
| 1287 | | fn airAddWrap(self: *Self, inst: Air.Inst.Index) !void { |
| 1227 | fn airBinOp(self: *Self, inst: Air.Inst.Index) !void { |
| 1288 | 1228 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 1289 | 1229 | const result: MCValue = if (self.liveness.isUnused(inst)) |
| 1290 | 1230 | .dead |
| 1291 | 1231 | else |
| 1292 | | try self.genBinMathOp(inst, bin_op.lhs, bin_op.rhs); |
| 1232 | try self.genBinOp(inst, bin_op.lhs, bin_op.rhs); |
| 1293 | 1233 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 1294 | 1234 | } |
| 1295 | 1235 | |
| ... | ... | @@ -1302,60 +1242,6 @@ fn airAddSat(self: *Self, inst: Air.Inst.Index) !void { |
| 1302 | 1242 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 1303 | 1243 | } |
| 1304 | 1244 | |
| 1305 | | /// Result is always a register. |
| 1306 | | fn genSubOp(self: *Self, inst: Air.Inst.Index, op_lhs: Air.Inst.Ref, op_rhs: Air.Inst.Ref) !MCValue { |
| 1307 | | const dst_ty = self.air.typeOf(op_lhs); |
| 1308 | | |
| 1309 | | const lhs = try self.resolveInst(op_lhs); |
| 1310 | | const lhs_lock: ?RegisterLock = switch (lhs) { |
| 1311 | | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), |
| 1312 | | else => null, |
| 1313 | | }; |
| 1314 | | defer if (lhs_lock) |lock| self.register_manager.unlockReg(lock); |
| 1315 | | |
| 1316 | | const rhs = try self.resolveInst(op_rhs); |
| 1317 | | const rhs_lock: ?RegisterLock = switch (rhs) { |
| 1318 | | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), |
| 1319 | | else => null, |
| 1320 | | }; |
| 1321 | | defer if (rhs_lock) |lock| self.register_manager.unlockReg(lock); |
| 1322 | | |
| 1323 | | const dst_mcv: MCValue = blk: { |
| 1324 | | if (self.reuseOperand(inst, op_lhs, 0, lhs) and lhs.isRegister()) { |
| 1325 | | break :blk lhs; |
| 1326 | | } |
| 1327 | | break :blk try self.copyToRegisterWithInstTracking(inst, dst_ty, lhs); |
| 1328 | | }; |
| 1329 | | const dst_mcv_lock: ?RegisterLock = switch (dst_mcv) { |
| 1330 | | .register => |reg| self.register_manager.lockReg(reg), |
| 1331 | | else => null, |
| 1332 | | }; |
| 1333 | | defer if (dst_mcv_lock) |lock| self.register_manager.unlockReg(lock); |
| 1334 | | |
| 1335 | | const rhs_mcv: MCValue = blk: { |
| 1336 | | if (rhs.isMemory() or rhs.isRegister()) break :blk rhs; |
| 1337 | | break :blk MCValue{ .register = try self.copyToTmpRegister(dst_ty, rhs) }; |
| 1338 | | }; |
| 1339 | | const rhs_mcv_lock: ?RegisterLock = switch (rhs_mcv) { |
| 1340 | | .register => |reg| self.register_manager.lockReg(reg), |
| 1341 | | else => null, |
| 1342 | | }; |
| 1343 | | defer if (rhs_mcv_lock) |lock| self.register_manager.unlockReg(lock); |
| 1344 | | |
| 1345 | | try self.genBinMathOpMir(.sub, dst_ty, dst_mcv, rhs_mcv); |
| 1346 | | |
| 1347 | | return dst_mcv; |
| 1348 | | } |
| 1349 | | |
| 1350 | | fn airSub(self: *Self, inst: Air.Inst.Index) !void { |
| 1351 | | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 1352 | | const result: MCValue = if (self.liveness.isUnused(inst)) |
| 1353 | | .dead |
| 1354 | | else |
| 1355 | | try self.genSubOp(inst, bin_op.lhs, bin_op.rhs); |
| 1356 | | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 1357 | | } |
| 1358 | | |
| 1359 | 1245 | fn airSubSat(self: *Self, inst: Air.Inst.Index) !void { |
| 1360 | 1246 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 1361 | 1247 | const result: MCValue = if (self.liveness.isUnused(inst)) |
| ... | ... | @@ -1422,7 +1308,7 @@ fn airAddWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 1422 | 1308 | try self.spillCompareFlagsIfOccupied(); |
| 1423 | 1309 | self.compare_flags_inst = inst; |
| 1424 | 1310 | |
| 1425 | | const partial = try self.genBinMathOp(inst, bin_op.lhs, bin_op.rhs); |
| 1311 | const partial = try self.genBinOp(inst, bin_op.lhs, bin_op.rhs); |
| 1426 | 1312 | const result: MCValue = switch (int_info.signedness) { |
| 1427 | 1313 | .signed => .{ .register_overflow_signed = partial.register }, |
| 1428 | 1314 | .unsigned => .{ .register_overflow_unsigned = partial.register }, |
| ... | ... | @@ -1454,7 +1340,7 @@ fn airSubWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 1454 | 1340 | try self.spillCompareFlagsIfOccupied(); |
| 1455 | 1341 | self.compare_flags_inst = inst; |
| 1456 | 1342 | |
| 1457 | | const partial = try self.genSubOp(inst, bin_op.lhs, bin_op.rhs); |
| 1343 | const partial = try self.genBinOp(inst, bin_op.lhs, bin_op.rhs); |
| 1458 | 1344 | const result: MCValue = switch (int_info.signedness) { |
| 1459 | 1345 | .signed => .{ .register_overflow_signed = partial.register }, |
| 1460 | 1346 | .unsigned => .{ .register_overflow_unsigned = partial.register }, |
| ... | ... | @@ -1605,7 +1491,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 1605 | 1491 | const scratch_reg = temp_regs[1]; |
| 1606 | 1492 | try self.genSetReg(extended_ty, scratch_reg, .{ .register = dst_reg }); |
| 1607 | 1493 | try self.truncateRegister(ty, scratch_reg); |
| 1608 | | try self.genBinMathOpMir( |
| 1494 | try self.genBinOpMir( |
| 1609 | 1495 | .cmp, |
| 1610 | 1496 | extended_ty, |
| 1611 | 1497 | .{ .register = dst_reg }, |
| ... | ... | @@ -1622,7 +1508,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 1622 | 1508 | .data = undefined, |
| 1623 | 1509 | }); |
| 1624 | 1510 | |
| 1625 | | try self.genBinMathOpMir( |
| 1511 | try self.genBinOpMir( |
| 1626 | 1512 | .@"or", |
| 1627 | 1513 | Type.u8, |
| 1628 | 1514 | .{ .register = overflow_reg }, |
| ... | ... | @@ -1781,7 +1667,7 @@ fn genInlineIntDivFloor(self: *Self, ty: Type, lhs: MCValue, rhs: MCValue) !MCVa |
| 1781 | 1667 | }).encode(), |
| 1782 | 1668 | .data = undefined, |
| 1783 | 1669 | }); |
| 1784 | | try self.genBinMathOpMir(.add, Type.isize, .{ .register = divisor }, .{ .register = .rax }); |
| 1670 | try self.genBinOpMir(.add, Type.isize, .{ .register = divisor }, .{ .register = .rax }); |
| 1785 | 1671 | return MCValue{ .register = divisor }; |
| 1786 | 1672 | } |
| 1787 | 1673 | |
| ... | ... | @@ -1945,7 +1831,7 @@ fn airMod(self: *Self, inst: Air.Inst.Index) !void { |
| 1945 | 1831 | try self.genIntMulComplexOpMir(ty, div_floor, rhs); |
| 1946 | 1832 | |
| 1947 | 1833 | const result = try self.copyToRegisterWithInstTracking(inst, ty, lhs); |
| 1948 | | try self.genBinMathOpMir(.sub, ty, result, div_floor); |
| 1834 | try self.genBinOpMir(.sub, ty, result, div_floor); |
| 1949 | 1835 | |
| 1950 | 1836 | break :result result; |
| 1951 | 1837 | }, |
| ... | ... | @@ -1955,33 +1841,6 @@ fn airMod(self: *Self, inst: Air.Inst.Index) !void { |
| 1955 | 1841 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 1956 | 1842 | } |
| 1957 | 1843 | |
| 1958 | | fn airBitAnd(self: *Self, inst: Air.Inst.Index) !void { |
| 1959 | | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 1960 | | const result: MCValue = if (self.liveness.isUnused(inst)) |
| 1961 | | .dead |
| 1962 | | else |
| 1963 | | try self.genBinMathOp(inst, bin_op.lhs, bin_op.rhs); |
| 1964 | | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 1965 | | } |
| 1966 | | |
| 1967 | | fn airBitOr(self: *Self, inst: Air.Inst.Index) !void { |
| 1968 | | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 1969 | | const result: MCValue = if (self.liveness.isUnused(inst)) |
| 1970 | | .dead |
| 1971 | | else |
| 1972 | | try self.genBinMathOp(inst, bin_op.lhs, bin_op.rhs); |
| 1973 | | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 1974 | | } |
| 1975 | | |
| 1976 | | fn airXor(self: *Self, inst: Air.Inst.Index) !void { |
| 1977 | | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 1978 | | const result: MCValue = if (self.liveness.isUnused(inst)) |
| 1979 | | .dead |
| 1980 | | else |
| 1981 | | try self.genBinMathOp(inst, bin_op.lhs, bin_op.rhs); |
| 1982 | | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 1983 | | } |
| 1984 | | |
| 1985 | 1844 | fn airShl(self: *Self, inst: Air.Inst.Index) !void { |
| 1986 | 1845 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 1987 | 1846 | if (self.liveness.isUnused(inst)) { |
| ... | ... | @@ -1989,6 +1848,7 @@ fn airShl(self: *Self, inst: Air.Inst.Index) !void { |
| 1989 | 1848 | } |
| 1990 | 1849 | |
| 1991 | 1850 | const ty = self.air.typeOfIndex(inst); |
| 1851 | |
| 1992 | 1852 | const tag = self.air.instructions.items(.tag)[inst]; |
| 1993 | 1853 | switch (tag) { |
| 1994 | 1854 | .shl_exact => return self.fail("TODO implement {} for type {}", .{ tag, ty.fmtDebug() }), |
| ... | ... | @@ -2470,7 +2330,7 @@ fn genSliceElemPtr(self: *Self, lhs: Air.Inst.Ref, rhs: Air.Inst.Ref) !MCValue { |
| 2470 | 2330 | } |
| 2471 | 2331 | // TODO we could allocate register here, but need to expect addr register and potentially |
| 2472 | 2332 | // offset register. |
| 2473 | | try self.genBinMathOpMir(.add, slice_ptr_field_type, .{ .register = addr_reg }, .{ |
| 2333 | try self.genBinOpMir(.add, slice_ptr_field_type, .{ .register = addr_reg }, .{ |
| 2474 | 2334 | .register = offset_reg, |
| 2475 | 2335 | }); |
| 2476 | 2336 | return MCValue{ .register = addr_reg.to64() }; |
| ... | ... | @@ -2573,7 +2433,7 @@ fn airArrayElemVal(self: *Self, inst: Air.Inst.Index) !void { |
| 2573 | 2433 | // TODO we could allocate register here, but need to expect addr register and potentially |
| 2574 | 2434 | // offset register. |
| 2575 | 2435 | const dst_mcv = try self.allocRegOrMem(inst, false); |
| 2576 | | try self.genBinMathOpMir(.add, Type.usize, .{ .register = addr_reg }, .{ .register = offset_reg }); |
| 2436 | try self.genBinOpMir(.add, Type.usize, .{ .register = addr_reg }, .{ .register = offset_reg }); |
| 2577 | 2437 | try self.load(dst_mcv, .{ .register = addr_reg.to64() }, array_ty); |
| 2578 | 2438 | |
| 2579 | 2439 | return self.finishAir(inst, dst_mcv, .{ bin_op.lhs, bin_op.rhs, .none }); |
| ... | ... | @@ -2613,7 +2473,7 @@ fn airPtrElemVal(self: *Self, inst: Air.Inst.Index) !void { |
| 2613 | 2473 | defer self.register_manager.unlockReg(offset_reg_lock); |
| 2614 | 2474 | |
| 2615 | 2475 | const dst_mcv = try self.copyToRegisterWithInstTracking(inst, ptr_ty, ptr); |
| 2616 | | try self.genBinMathOpMir(.add, ptr_ty, dst_mcv, .{ .register = offset_reg }); |
| 2476 | try self.genBinOpMir(.add, ptr_ty, dst_mcv, .{ .register = offset_reg }); |
| 2617 | 2477 | |
| 2618 | 2478 | const result: MCValue = result: { |
| 2619 | 2479 | if (elem_abi_size > 8) { |
| ... | ... | @@ -2667,7 +2527,7 @@ fn airPtrElemPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 2667 | 2527 | defer self.register_manager.unlockReg(offset_reg_lock); |
| 2668 | 2528 | |
| 2669 | 2529 | const dst_mcv = try self.copyToRegisterWithInstTracking(inst, ptr_ty, ptr); |
| 2670 | | try self.genBinMathOpMir(.add, ptr_ty, dst_mcv, .{ .register = offset_reg }); |
| 2530 | try self.genBinOpMir(.add, ptr_ty, dst_mcv, .{ .register = offset_reg }); |
| 2671 | 2531 | |
| 2672 | 2532 | return self.finishAir(inst, dst_mcv, .{ extra.lhs, extra.rhs, .none }); |
| 2673 | 2533 | } |
| ... | ... | @@ -2700,7 +2560,7 @@ fn airSetUnionTag(self: *Self, inst: Air.Inst.Index) !void { |
| 2700 | 2560 | const adjusted_ptr: MCValue = if (layout.payload_size > 0 and layout.tag_align < layout.payload_align) blk: { |
| 2701 | 2561 | // TODO reusing the operand |
| 2702 | 2562 | const reg = try self.copyToTmpRegister(ptr_ty, ptr); |
| 2703 | | try self.genBinMathOpMir(.add, ptr_ty, .{ .register = reg }, .{ .immediate = layout.payload_size }); |
| 2563 | try self.genBinOpMir(.add, ptr_ty, .{ .register = reg }, .{ .immediate = layout.payload_size }); |
| 2704 | 2564 | break :blk MCValue{ .register = reg }; |
| 2705 | 2565 | } else ptr; |
| 2706 | 2566 | |
| ... | ... | @@ -3267,7 +3127,7 @@ fn structFieldPtr(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, inde |
| 3267 | 3127 | defer self.register_manager.unlockReg(offset_reg_lock); |
| 3268 | 3128 | |
| 3269 | 3129 | const dst_mcv = try self.copyToRegisterWithInstTracking(inst, ptr_ty, mcv); |
| 3270 | | try self.genBinMathOpMir(.add, ptr_ty, dst_mcv, .{ .register = offset_reg }); |
| 3130 | try self.genBinOpMir(.add, ptr_ty, dst_mcv, .{ .register = offset_reg }); |
| 3271 | 3131 | break :result dst_mcv; |
| 3272 | 3132 | }, |
| 3273 | 3133 | .ptr_stack_offset => |off| { |
| ... | ... | @@ -3297,7 +3157,7 @@ fn structFieldPtr(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, inde |
| 3297 | 3157 | const result_reg_lock = self.register_manager.lockReg(result_reg); |
| 3298 | 3158 | defer if (result_reg_lock) |lock| self.register_manager.unlockReg(lock); |
| 3299 | 3159 | |
| 3300 | | try self.genBinMathOpMir(.add, ptr_ty, .{ .register = result_reg }, .{ .register = offset_reg }); |
| 3160 | try self.genBinOpMir(.add, ptr_ty, .{ .register = result_reg }, .{ .register = offset_reg }); |
| 3301 | 3161 | break :result MCValue{ .register = result_reg }; |
| 3302 | 3162 | }, |
| 3303 | 3163 | else => return self.fail("TODO implement codegen struct_field_ptr for {}", .{mcv}), |
| ... | ... | @@ -3357,7 +3217,7 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void { |
| 3357 | 3217 | const mask = (~@as(u64, 0)) >> mask_shift; |
| 3358 | 3218 | |
| 3359 | 3219 | const tmp_reg = try self.copyToTmpRegister(Type.usize, .{ .immediate = mask }); |
| 3360 | | try self.genBinMathOpMir(.@"and", Type.usize, dst_mcv, .{ .register = tmp_reg }); |
| 3220 | try self.genBinOpMir(.@"and", Type.usize, dst_mcv, .{ .register = tmp_reg }); |
| 3361 | 3221 | |
| 3362 | 3222 | const signedness: std.builtin.Signedness = blk: { |
| 3363 | 3223 | if (struct_field_ty.zigTypeTag() != .Int) break :blk .unsigned; |
| ... | ... | @@ -3426,8 +3286,39 @@ fn airFieldParentPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 3426 | 3286 | } |
| 3427 | 3287 | |
| 3428 | 3288 | /// Result is always a register. |
| 3429 | | fn genBinMathOp(self: *Self, inst: Air.Inst.Index, op_lhs: Air.Inst.Ref, op_rhs: Air.Inst.Ref) !MCValue { |
| 3289 | fn genBinOp( |
| 3290 | self: *Self, |
| 3291 | inst: Air.Inst.Index, |
| 3292 | op_lhs: Air.Inst.Ref, |
| 3293 | op_rhs: Air.Inst.Ref, |
| 3294 | ) !MCValue { |
| 3295 | const tag = self.air.instructions.items(.tag)[inst]; |
| 3296 | const is_commutative: bool = switch (tag) { |
| 3297 | .add, |
| 3298 | .addwrap, |
| 3299 | .add_with_overflow, |
| 3300 | .bool_or, |
| 3301 | .bit_or, |
| 3302 | .bool_and, |
| 3303 | .bit_and, |
| 3304 | .xor, |
| 3305 | .not, |
| 3306 | => true, |
| 3307 | |
| 3308 | .sub, |
| 3309 | .subwrap, |
| 3310 | .sub_with_overflow, |
| 3311 | .mul, |
| 3312 | .shl, |
| 3313 | .shr, |
| 3314 | .ptr_add, |
| 3315 | .ptr_sub, |
| 3316 | => false, |
| 3317 | |
| 3318 | else => unreachable, |
| 3319 | }; |
| 3430 | 3320 | const dst_ty = self.air.typeOf(op_lhs); |
| 3321 | const src_ty = self.air.typeOf(op_rhs); |
| 3431 | 3322 | |
| 3432 | 3323 | const lhs = try self.resolveInst(op_lhs); |
| 3433 | 3324 | const lhs_lock: ?RegisterLock = switch (lhs) { |
| ... | ... | @@ -3448,7 +3339,7 @@ fn genBinMathOp(self: *Self, inst: Air.Inst.Index, op_lhs: Air.Inst.Ref, op_rhs: |
| 3448 | 3339 | if (self.reuseOperand(inst, op_lhs, 0, lhs) and lhs.isRegister()) { |
| 3449 | 3340 | break :blk lhs; |
| 3450 | 3341 | } |
| 3451 | | if (self.reuseOperand(inst, op_rhs, 1, rhs) and rhs.isRegister()) { |
| 3342 | if (is_commutative and self.reuseOperand(inst, op_rhs, 1, rhs) and rhs.isRegister()) { |
| 3452 | 3343 | flipped = true; |
| 3453 | 3344 | break :blk rhs; |
| 3454 | 3345 | } |
| ... | ... | @@ -3463,7 +3354,7 @@ fn genBinMathOp(self: *Self, inst: Air.Inst.Index, op_lhs: Air.Inst.Ref, op_rhs: |
| 3463 | 3354 | const src_mcv: MCValue = blk: { |
| 3464 | 3355 | const mcv = if (flipped) lhs else rhs; |
| 3465 | 3356 | if (mcv.isRegister() or mcv.isMemory()) break :blk mcv; |
| 3466 | | break :blk MCValue{ .register = try self.copyToTmpRegister(dst_ty, mcv) }; |
| 3357 | break :blk MCValue{ .register = try self.copyToTmpRegister(src_ty, mcv) }; |
| 3467 | 3358 | }; |
| 3468 | 3359 | const src_mcv_lock: ?RegisterLock = switch (src_mcv) { |
| 3469 | 3360 | .register => |reg| self.register_manager.lockReg(reg), |
| ... | ... | @@ -3471,18 +3362,39 @@ fn genBinMathOp(self: *Self, inst: Air.Inst.Index, op_lhs: Air.Inst.Ref, op_rhs: |
| 3471 | 3362 | }; |
| 3472 | 3363 | defer if (src_mcv_lock) |lock| self.register_manager.unlockReg(lock); |
| 3473 | 3364 | |
| 3474 | | const tag = self.air.instructions.items(.tag)[inst]; |
| 3475 | 3365 | switch (tag) { |
| 3476 | | .add, .addwrap, .add_with_overflow => try self.genBinMathOpMir(.add, dst_ty, dst_mcv, src_mcv), |
| 3477 | | .bool_or, .bit_or => try self.genBinMathOpMir(.@"or", dst_ty, dst_mcv, src_mcv), |
| 3478 | | .bool_and, .bit_and => try self.genBinMathOpMir(.@"and", dst_ty, dst_mcv, src_mcv), |
| 3479 | | .xor, .not => try self.genBinMathOpMir(.xor, dst_ty, dst_mcv, src_mcv), |
| 3366 | .add, |
| 3367 | .addwrap, |
| 3368 | .add_with_overflow, |
| 3369 | => try self.genBinOpMir(.add, dst_ty, dst_mcv, src_mcv), |
| 3370 | |
| 3371 | .sub, |
| 3372 | .subwrap, |
| 3373 | .sub_with_overflow, |
| 3374 | => try self.genBinOpMir(.sub, dst_ty, dst_mcv, src_mcv), |
| 3375 | |
| 3376 | .ptr_add, |
| 3377 | .ptr_sub, |
| 3378 | => { |
| 3379 | const mir_tag: Mir.Inst.Tag = switch (tag) { |
| 3380 | .ptr_add => .add, |
| 3381 | .ptr_sub => .sub, |
| 3382 | else => unreachable, |
| 3383 | }; |
| 3384 | const elem_size = dst_ty.elemType2().abiSize(self.target.*); |
| 3385 | try self.genIntMulComplexOpMir(src_ty, src_mcv, .{ .immediate = elem_size }); |
| 3386 | try self.genBinOpMir(mir_tag, dst_ty, dst_mcv, src_mcv); |
| 3387 | }, |
| 3388 | |
| 3389 | .bool_or, .bit_or => try self.genBinOpMir(.@"or", dst_ty, dst_mcv, src_mcv), |
| 3390 | .bool_and, .bit_and => try self.genBinOpMir(.@"and", dst_ty, dst_mcv, src_mcv), |
| 3391 | .xor, .not => try self.genBinOpMir(.xor, dst_ty, dst_mcv, src_mcv), |
| 3480 | 3392 | else => unreachable, |
| 3481 | 3393 | } |
| 3482 | 3394 | return dst_mcv; |
| 3483 | 3395 | } |
| 3484 | 3396 | |
| 3485 | | fn genBinMathOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MCValue, src_mcv: MCValue) !void { |
| 3397 | fn genBinOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MCValue, src_mcv: MCValue) !void { |
| 3486 | 3398 | const abi_size = @intCast(u32, dst_ty.abiSize(self.target.*)); |
| 3487 | 3399 | switch (dst_mcv) { |
| 3488 | 3400 | .none => unreachable, |
| ... | ... | @@ -3504,7 +3416,7 @@ fn genBinMathOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MC |
| 3504 | 3416 | defer if (dst_reg_lock) |lock| self.register_manager.unlockReg(lock); |
| 3505 | 3417 | |
| 3506 | 3418 | const reg = try self.copyToTmpRegister(dst_ty, src_mcv); |
| 3507 | | return self.genBinMathOpMir(mir_tag, dst_ty, dst_mcv, .{ .register = reg }); |
| 3419 | return self.genBinOpMir(mir_tag, dst_ty, dst_mcv, .{ .register = reg }); |
| 3508 | 3420 | }, |
| 3509 | 3421 | .register => |src_reg| { |
| 3510 | 3422 | _ = try self.addInst(.{ |
| ... | ... | @@ -3536,7 +3448,7 @@ fn genBinMathOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MC |
| 3536 | 3448 | defer if (dst_reg_lock) |lock| self.register_manager.unlockReg(lock); |
| 3537 | 3449 | |
| 3538 | 3450 | const reg = try self.copyToTmpRegister(dst_ty, src_mcv); |
| 3539 | | return self.genBinMathOpMir(mir_tag, dst_ty, dst_mcv, .{ .register = reg }); |
| 3451 | return self.genBinOpMir(mir_tag, dst_ty, dst_mcv, .{ .register = reg }); |
| 3540 | 3452 | }, |
| 3541 | 3453 | .stack_offset => |off| { |
| 3542 | 3454 | if (off > math.maxInt(i32)) { |
| ... | ... | @@ -3637,7 +3549,7 @@ fn genBinMathOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MC |
| 3637 | 3549 | |
| 3638 | 3550 | /// Performs multi-operand integer multiplication between dst_mcv and src_mcv, storing the result in dst_mcv. |
| 3639 | 3551 | /// Does not support byte-size operands. |
| 3640 | | fn genIntMulComplexOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: MCValue) !void { |
| 3552 | fn genIntMulComplexOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: MCValue) InnerError!void { |
| 3641 | 3553 | const abi_size = @intCast(u32, dst_ty.abiSize(self.target.*)); |
| 3642 | 3554 | switch (dst_mcv) { |
| 3643 | 3555 | .none => unreachable, |
| ... | ... | @@ -3733,11 +3645,17 @@ fn genIntMulComplexOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: M |
| 3733 | 3645 | .data = undefined, |
| 3734 | 3646 | }); |
| 3735 | 3647 | // copy dst_reg back out |
| 3736 | | return self.genSetStack(dst_ty, off, MCValue{ .register = dst_reg }, .{}); |
| 3648 | return self.genSetStack(dst_ty, off, .{ .register = dst_reg }, .{}); |
| 3737 | 3649 | }, |
| 3738 | | .immediate => |imm| { |
| 3739 | | _ = imm; |
| 3740 | | return self.fail("TODO implement x86 multiply source immediate", .{}); |
| 3650 | .immediate => { |
| 3651 | // copy dst to a register |
| 3652 | const dst_reg = try self.copyToTmpRegister(dst_ty, dst_mcv); |
| 3653 | const dst_reg_lock = self.register_manager.lockRegAssumeUnused(dst_reg); |
| 3654 | defer self.register_manager.unlockReg(dst_reg_lock); |
| 3655 | |
| 3656 | try self.genIntMulComplexOpMir(dst_ty, .{ .register = dst_reg }, src_mcv); |
| 3657 | |
| 3658 | return self.genSetStack(dst_ty, off, .{ .register = dst_reg }, .{}); |
| 3741 | 3659 | }, |
| 3742 | 3660 | .memory, .stack_offset => { |
| 3743 | 3661 | return self.fail("TODO implement x86 multiply source memory", .{}); |
| ... | ... | @@ -4213,7 +4131,7 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void { |
| 4213 | 4131 | // This instruction supports only signed 32-bit immediates at most. |
| 4214 | 4132 | const src_mcv = try self.limitImmediateType(bin_op.rhs, i32); |
| 4215 | 4133 | |
| 4216 | | try self.genBinMathOpMir(.cmp, ty, dst_mcv, src_mcv); |
| 4134 | try self.genBinOpMir(.cmp, ty, dst_mcv, src_mcv); |
| 4217 | 4135 | break :result switch (signedness) { |
| 4218 | 4136 | .signed => MCValue{ .compare_flags_signed = op }, |
| 4219 | 4137 | .unsigned => MCValue{ .compare_flags_unsigned = op }, |
| ... | ... | @@ -4606,7 +4524,7 @@ fn isNull(self: *Self, inst: Air.Inst.Index, ty: Type, operand: MCValue) !MCValu |
| 4606 | 4524 | break :blk if (payload_ty.hasRuntimeBits()) Type.bool else ty; |
| 4607 | 4525 | } else ty; |
| 4608 | 4526 | |
| 4609 | | try self.genBinMathOpMir(.cmp, cmp_ty, operand, MCValue{ .immediate = 0 }); |
| 4527 | try self.genBinOpMir(.cmp, cmp_ty, operand, MCValue{ .immediate = 0 }); |
| 4610 | 4528 | |
| 4611 | 4529 | return MCValue{ .compare_flags_unsigned = .eq }; |
| 4612 | 4530 | } |
| ... | ... | @@ -4629,13 +4547,13 @@ fn isErr(self: *Self, inst: Air.Inst.Index, ty: Type, operand: MCValue) !MCValue |
| 4629 | 4547 | |
| 4630 | 4548 | if (!payload_type.hasRuntimeBits()) { |
| 4631 | 4549 | if (err_type.abiSize(self.target.*) <= 8) { |
| 4632 | | try self.genBinMathOpMir(.cmp, err_type, operand, MCValue{ .immediate = 0 }); |
| 4550 | try self.genBinOpMir(.cmp, err_type, operand, MCValue{ .immediate = 0 }); |
| 4633 | 4551 | return MCValue{ .compare_flags_unsigned = .gt }; |
| 4634 | 4552 | } else { |
| 4635 | 4553 | return self.fail("TODO isErr for errors with size larger than register size", .{}); |
| 4636 | 4554 | } |
| 4637 | 4555 | } else { |
| 4638 | | try self.genBinMathOpMir(.cmp, err_type, operand, MCValue{ .immediate = 0 }); |
| 4556 | try self.genBinOpMir(.cmp, err_type, operand, MCValue{ .immediate = 0 }); |
| 4639 | 4557 | return MCValue{ .compare_flags_unsigned = .gt }; |
| 4640 | 4558 | } |
| 4641 | 4559 | } |
| ... | ... | @@ -5053,21 +4971,6 @@ fn airBr(self: *Self, inst: Air.Inst.Index) !void { |
| 5053 | 4971 | return self.finishAir(inst, .dead, .{ branch.operand, .none, .none }); |
| 5054 | 4972 | } |
| 5055 | 4973 | |
| 5056 | | fn airBoolOp(self: *Self, inst: Air.Inst.Index) !void { |
| 5057 | | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 5058 | | const air_tags = self.air.instructions.items(.tag); |
| 5059 | | const result: MCValue = if (self.liveness.isUnused(inst)) |
| 5060 | | .dead |
| 5061 | | else switch (air_tags[inst]) { |
| 5062 | | // lhs AND rhs |
| 5063 | | .bool_and => try self.genBinMathOp(inst, bin_op.lhs, bin_op.rhs), |
| 5064 | | // lhs OR rhs |
| 5065 | | .bool_or => try self.genBinMathOp(inst, bin_op.lhs, bin_op.rhs), |
| 5066 | | else => unreachable, // Not a boolean operation |
| 5067 | | }; |
| 5068 | | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 5069 | | } |
| 5070 | | |
| 5071 | 4974 | fn br(self: *Self, block: Air.Inst.Index, operand: Air.Inst.Ref) !void { |
| 5072 | 4975 | const block_data = self.blocks.getPtr(block).?; |
| 5073 | 4976 | |
| ... | ... | @@ -5844,7 +5747,7 @@ fn genInlineMemset( |
| 5844 | 5747 | defer self.register_manager.unlockReg(addr_reg_lock); |
| 5845 | 5748 | |
| 5846 | 5749 | try self.genSetReg(Type.usize, .rax, len); |
| 5847 | | try self.genBinMathOpMir(.sub, Type.usize, .{ .register = .rax }, .{ .immediate = 1 }); |
| 5750 | try self.genBinOpMir(.sub, Type.usize, .{ .register = .rax }, .{ .immediate = 1 }); |
| 5848 | 5751 | |
| 5849 | 5752 | // loop: |
| 5850 | 5753 | // cmp rax, -1 |
| ... | ... | @@ -6963,10 +6866,10 @@ fn truncateRegister(self: *Self, ty: Type, reg: Register) !void { |
| 6963 | 6866 | const shift = @intCast(u6, max_reg_bit_width - int_info.bits); |
| 6964 | 6867 | const mask = (~@as(u64, 0)) >> shift; |
| 6965 | 6868 | if (int_info.bits <= 32) { |
| 6966 | | try self.genBinMathOpMir(.@"and", Type.usize, .{ .register = reg }, .{ .immediate = mask }); |
| 6869 | try self.genBinOpMir(.@"and", Type.usize, .{ .register = reg }, .{ .immediate = mask }); |
| 6967 | 6870 | } else { |
| 6968 | 6871 | const tmp_reg = try self.copyToTmpRegister(Type.usize, .{ .immediate = mask }); |
| 6969 | | try self.genBinMathOpMir(.@"and", Type.usize, .{ .register = reg }, .{ .register = tmp_reg }); |
| 6872 | try self.genBinOpMir(.@"and", Type.usize, .{ .register = reg }, .{ .register = tmp_reg }); |
| 6970 | 6873 | } |
| 6971 | 6874 | }, |
| 6972 | 6875 | } |