| ... | @@ -586,11 +586,11 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { | ... | @@ -586,11 +586,11 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 586 | | 586 | |
| 587 | switch (air_tags[inst]) { | 587 | switch (air_tags[inst]) { |
| 588 | // zig fmt: off | 588 | // zig fmt: off |
| 589 | .add => try self.airAdd(inst), | 589 | .add => try self.airBinOp(inst), |
| 590 | .addwrap => try self.airAdd(inst), | 590 | .addwrap => try self.airBinOp(inst), |
| 591 | .add_sat => try self.airAddSat(inst), | 591 | .add_sat => try self.airAddSat(inst), |
| 592 | .sub => try self.airSub(inst), | 592 | .sub => try self.airBinOp(inst), |
| 593 | .subwrap => try self.airSub(inst), | 593 | .subwrap => try self.airBinOp(inst), |
| 594 | .sub_sat => try self.airSubSat(inst), | 594 | .sub_sat => try self.airSubSat(inst), |
| 595 | .mul => try self.airMul(inst), | 595 | .mul => try self.airMul(inst), |
| 596 | .mulwrap => try self.airMul(inst), | 596 | .mulwrap => try self.airMul(inst), |
| ... | @@ -601,8 +601,8 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { | ... | @@ -601,8 +601,8 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 601 | .shl_sat => try self.airShlSat(inst), | 601 | .shl_sat => try self.airShlSat(inst), |
| 602 | .min => try self.airMin(inst), | 602 | .min => try self.airMin(inst), |
| 603 | .max => try self.airMax(inst), | 603 | .max => try self.airMax(inst), |
| 604 | .ptr_add => try self.airPtrAdd(inst), | 604 | .ptr_add => try self.airBinOp(inst), |
| 605 | .ptr_sub => try self.airPtrSub(inst), | 605 | .ptr_sub => try self.airBinOp(inst), |
| 606 | .slice => try self.airSlice(inst), | 606 | .slice => try self.airSlice(inst), |
| 607 | | 607 | |
| 608 | .sqrt, | 608 | .sqrt, |
| ... | @@ -638,11 +638,11 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { | ... | @@ -638,11 +638,11 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 638 | .cmp_vector => try self.airCmpVector(inst), | 638 | .cmp_vector => try self.airCmpVector(inst), |
| 639 | .cmp_lt_errors_len => try self.airCmpLtErrorsLen(inst), | 639 | .cmp_lt_errors_len => try self.airCmpLtErrorsLen(inst), |
| 640 | | 640 | |
| 641 | .bool_and => try self.airBoolOp(inst), | 641 | .bool_and => try self.airBinOp(inst), |
| 642 | .bool_or => try self.airBoolOp(inst), | 642 | .bool_or => try self.airBinOp(inst), |
| 643 | .bit_and => try self.airBitAnd(inst), | 643 | .bit_and => try self.airBinOp(inst), |
| 644 | .bit_or => try self.airBitOr(inst), | 644 | .bit_or => try self.airBinOp(inst), |
| 645 | .xor => try self.airXor(inst), | 645 | .xor => try self.airBinOp(inst), |
| 646 | .shr, .shr_exact => try self.airShr(inst), | 646 | .shr, .shr_exact => try self.airShr(inst), |
| 647 | | 647 | |
| 648 | .alloc => try self.airAlloc(inst), | 648 | .alloc => try self.airAlloc(inst), |
| ... | @@ -1122,7 +1122,7 @@ fn airNot(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1122,7 +1122,7 @@ fn airNot(self: *Self, inst: Air.Inst.Index) !void { |
| 1122 | }, | 1122 | }, |
| 1123 | else => {}, | 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 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); | 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,7 +1159,7 @@ fn airMin(self: *Self, inst: Air.Inst.Index) !void { |
| 1159 | }; | 1159 | }; |
| 1160 | defer if (rhs_lock) |lock| self.register_manager.unlockReg(lock); | 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 | const dst_mcv = try self.copyToRegisterWithInstTracking(inst, ty, rhs_mcv); | 1164 | const dst_mcv = try self.copyToRegisterWithInstTracking(inst, ty, rhs_mcv); |
| 1165 | _ = try self.addInst(.{ | 1165 | _ = try self.addInst(.{ |
| ... | @@ -1185,63 +1185,12 @@ fn airMax(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1185,63 +1185,12 @@ fn airMax(self: *Self, inst: Air.Inst.Index) !void { |
| 1185 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); | 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 | fn airPtrAdd(self: *Self, inst: Air.Inst.Index) !void { | 1188 | fn airPtrAdd(self: *Self, inst: Air.Inst.Index) !void { |
| 1240 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; | 1189 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 1241 | const result = if (self.liveness.isUnused(inst)) | 1190 | const result = if (self.liveness.isUnused(inst)) |
| 1242 | .dead | 1191 | .dead |
| 1243 | else | 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 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); | 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,7 +1199,7 @@ fn airPtrSub(self: *Self, inst: Air.Inst.Index) !void { |
| 1250 | const result = if (self.liveness.isUnused(inst)) | 1199 | const result = if (self.liveness.isUnused(inst)) |
| 1251 | .dead | 1200 | .dead |
| 1252 | else | 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 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); | 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,21 +1224,12 @@ fn airSlice(self: *Self, inst: Air.Inst.Index) !void { |
| 1275 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); | 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 { | 1227 | fn airBinOp(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 { | | |
| 1288 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; | 1228 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 1289 | const result: MCValue = if (self.liveness.isUnused(inst)) | 1229 | const result: MCValue = if (self.liveness.isUnused(inst)) |
| 1290 | .dead | 1230 | .dead |
| 1291 | else | 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 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); | 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,60 +1242,6 @@ fn airAddSat(self: *Self, inst: Air.Inst.Index) !void { |
| 1302 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); | 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 | fn airSubSat(self: *Self, inst: Air.Inst.Index) !void { | 1245 | fn airSubSat(self: *Self, inst: Air.Inst.Index) !void { |
| 1360 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; | 1246 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 1361 | const result: MCValue = if (self.liveness.isUnused(inst)) | 1247 | const result: MCValue = if (self.liveness.isUnused(inst)) |
| ... | @@ -1422,7 +1308,7 @@ fn airAddWithOverflow(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1422,7 +1308,7 @@ fn airAddWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 1422 | try self.spillCompareFlagsIfOccupied(); | 1308 | try self.spillCompareFlagsIfOccupied(); |
| 1423 | self.compare_flags_inst = inst; | 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 | const result: MCValue = switch (int_info.signedness) { | 1312 | const result: MCValue = switch (int_info.signedness) { |
| 1427 | .signed => .{ .register_overflow_signed = partial.register }, | 1313 | .signed => .{ .register_overflow_signed = partial.register }, |
| 1428 | .unsigned => .{ .register_overflow_unsigned = partial.register }, | 1314 | .unsigned => .{ .register_overflow_unsigned = partial.register }, |
| ... | @@ -1454,7 +1340,7 @@ fn airSubWithOverflow(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1454,7 +1340,7 @@ fn airSubWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 1454 | try self.spillCompareFlagsIfOccupied(); | 1340 | try self.spillCompareFlagsIfOccupied(); |
| 1455 | self.compare_flags_inst = inst; | 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 | const result: MCValue = switch (int_info.signedness) { | 1344 | const result: MCValue = switch (int_info.signedness) { |
| 1459 | .signed => .{ .register_overflow_signed = partial.register }, | 1345 | .signed => .{ .register_overflow_signed = partial.register }, |
| 1460 | .unsigned => .{ .register_overflow_unsigned = partial.register }, | 1346 | .unsigned => .{ .register_overflow_unsigned = partial.register }, |
| ... | @@ -1605,7 +1491,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1605,7 +1491,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 1605 | const scratch_reg = temp_regs[1]; | 1491 | const scratch_reg = temp_regs[1]; |
| 1606 | try self.genSetReg(extended_ty, scratch_reg, .{ .register = dst_reg }); | 1492 | try self.genSetReg(extended_ty, scratch_reg, .{ .register = dst_reg }); |
| 1607 | try self.truncateRegister(ty, scratch_reg); | 1493 | try self.truncateRegister(ty, scratch_reg); |
| 1608 | try self.genBinMathOpMir( | 1494 | try self.genBinOpMir( |
| 1609 | .cmp, | 1495 | .cmp, |
| 1610 | extended_ty, | 1496 | extended_ty, |
| 1611 | .{ .register = dst_reg }, | 1497 | .{ .register = dst_reg }, |
| ... | @@ -1622,7 +1508,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1622,7 +1508,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 1622 | .data = undefined, | 1508 | .data = undefined, |
| 1623 | }); | 1509 | }); |
| 1624 | | 1510 | |
| 1625 | try self.genBinMathOpMir( | 1511 | try self.genBinOpMir( |
| 1626 | .@"or", | 1512 | .@"or", |
| 1627 | Type.u8, | 1513 | Type.u8, |
| 1628 | .{ .register = overflow_reg }, | 1514 | .{ .register = overflow_reg }, |
| ... | @@ -1781,7 +1667,7 @@ fn genInlineIntDivFloor(self: *Self, ty: Type, lhs: MCValue, rhs: MCValue) !MCVa | ... | @@ -1781,7 +1667,7 @@ fn genInlineIntDivFloor(self: *Self, ty: Type, lhs: MCValue, rhs: MCValue) !MCVa |
| 1781 | }).encode(), | 1667 | }).encode(), |
| 1782 | .data = undefined, | 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 | return MCValue{ .register = divisor }; | 1671 | return MCValue{ .register = divisor }; |
| 1786 | } | 1672 | } |
| 1787 | | 1673 | |
| ... | @@ -1945,7 +1831,7 @@ fn airMod(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1945,7 +1831,7 @@ fn airMod(self: *Self, inst: Air.Inst.Index) !void { |
| 1945 | try self.genIntMulComplexOpMir(ty, div_floor, rhs); | 1831 | try self.genIntMulComplexOpMir(ty, div_floor, rhs); |
| 1946 | | 1832 | |
| 1947 | const result = try self.copyToRegisterWithInstTracking(inst, ty, lhs); | 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 | break :result result; | 1836 | break :result result; |
| 1951 | }, | 1837 | }, |
| ... | @@ -1955,33 +1841,6 @@ fn airMod(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1955,33 +1841,6 @@ fn airMod(self: *Self, inst: Air.Inst.Index) !void { |
| 1955 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); | 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 | fn airShl(self: *Self, inst: Air.Inst.Index) !void { | 1844 | fn airShl(self: *Self, inst: Air.Inst.Index) !void { |
| 1986 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; | 1845 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 1987 | if (self.liveness.isUnused(inst)) { | 1846 | if (self.liveness.isUnused(inst)) { |
| ... | @@ -1989,6 +1848,7 @@ fn airShl(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1989,6 +1848,7 @@ fn airShl(self: *Self, inst: Air.Inst.Index) !void { |
| 1989 | } | 1848 | } |
| 1990 | | 1849 | |
| 1991 | const ty = self.air.typeOfIndex(inst); | 1850 | const ty = self.air.typeOfIndex(inst); |
| | 1851 | |
| 1992 | const tag = self.air.instructions.items(.tag)[inst]; | 1852 | const tag = self.air.instructions.items(.tag)[inst]; |
| 1993 | switch (tag) { | 1853 | switch (tag) { |
| 1994 | .shl_exact => return self.fail("TODO implement {} for type {}", .{ tag, ty.fmtDebug() }), | 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,7 +2330,7 @@ fn genSliceElemPtr(self: *Self, lhs: Air.Inst.Ref, rhs: Air.Inst.Ref) !MCValue { |
| 2470 | } | 2330 | } |
| 2471 | // TODO we could allocate register here, but need to expect addr register and potentially | 2331 | // TODO we could allocate register here, but need to expect addr register and potentially |
| 2472 | // offset register. | 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 | .register = offset_reg, | 2334 | .register = offset_reg, |
| 2475 | }); | 2335 | }); |
| 2476 | return MCValue{ .register = addr_reg.to64() }; | 2336 | return MCValue{ .register = addr_reg.to64() }; |
| ... | @@ -2573,7 +2433,7 @@ fn airArrayElemVal(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -2573,7 +2433,7 @@ fn airArrayElemVal(self: *Self, inst: Air.Inst.Index) !void { |
| 2573 | // TODO we could allocate register here, but need to expect addr register and potentially | 2433 | // TODO we could allocate register here, but need to expect addr register and potentially |
| 2574 | // offset register. | 2434 | // offset register. |
| 2575 | const dst_mcv = try self.allocRegOrMem(inst, false); | 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 | try self.load(dst_mcv, .{ .register = addr_reg.to64() }, array_ty); | 2437 | try self.load(dst_mcv, .{ .register = addr_reg.to64() }, array_ty); |
| 2578 | | 2438 | |
| 2579 | return self.finishAir(inst, dst_mcv, .{ bin_op.lhs, bin_op.rhs, .none }); | 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,7 +2473,7 @@ fn airPtrElemVal(self: *Self, inst: Air.Inst.Index) !void { |
| 2613 | defer self.register_manager.unlockReg(offset_reg_lock); | 2473 | defer self.register_manager.unlockReg(offset_reg_lock); |
| 2614 | | 2474 | |
| 2615 | const dst_mcv = try self.copyToRegisterWithInstTracking(inst, ptr_ty, ptr); | 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 | const result: MCValue = result: { | 2478 | const result: MCValue = result: { |
| 2619 | if (elem_abi_size > 8) { | 2479 | if (elem_abi_size > 8) { |
| ... | @@ -2667,7 +2527,7 @@ fn airPtrElemPtr(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -2667,7 +2527,7 @@ fn airPtrElemPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 2667 | defer self.register_manager.unlockReg(offset_reg_lock); | 2527 | defer self.register_manager.unlockReg(offset_reg_lock); |
| 2668 | | 2528 | |
| 2669 | const dst_mcv = try self.copyToRegisterWithInstTracking(inst, ptr_ty, ptr); | 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 | return self.finishAir(inst, dst_mcv, .{ extra.lhs, extra.rhs, .none }); | 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,7 +2560,7 @@ fn airSetUnionTag(self: *Self, inst: Air.Inst.Index) !void { |
| 2700 | const adjusted_ptr: MCValue = if (layout.payload_size > 0 and layout.tag_align < layout.payload_align) blk: { | 2560 | const adjusted_ptr: MCValue = if (layout.payload_size > 0 and layout.tag_align < layout.payload_align) blk: { |
| 2701 | // TODO reusing the operand | 2561 | // TODO reusing the operand |
| 2702 | const reg = try self.copyToTmpRegister(ptr_ty, ptr); | 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 | break :blk MCValue{ .register = reg }; | 2564 | break :blk MCValue{ .register = reg }; |
| 2705 | } else ptr; | 2565 | } else ptr; |
| 2706 | | 2566 | |
| ... | @@ -3267,7 +3127,7 @@ fn structFieldPtr(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, inde | ... | @@ -3267,7 +3127,7 @@ fn structFieldPtr(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, inde |
| 3267 | defer self.register_manager.unlockReg(offset_reg_lock); | 3127 | defer self.register_manager.unlockReg(offset_reg_lock); |
| 3268 | | 3128 | |
| 3269 | const dst_mcv = try self.copyToRegisterWithInstTracking(inst, ptr_ty, mcv); | 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 | break :result dst_mcv; | 3131 | break :result dst_mcv; |
| 3272 | }, | 3132 | }, |
| 3273 | .ptr_stack_offset => |off| { | 3133 | .ptr_stack_offset => |off| { |
| ... | @@ -3297,7 +3157,7 @@ fn structFieldPtr(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, inde | ... | @@ -3297,7 +3157,7 @@ fn structFieldPtr(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, inde |
| 3297 | const result_reg_lock = self.register_manager.lockReg(result_reg); | 3157 | const result_reg_lock = self.register_manager.lockReg(result_reg); |
| 3298 | defer if (result_reg_lock) |lock| self.register_manager.unlockReg(lock); | 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 | break :result MCValue{ .register = result_reg }; | 3161 | break :result MCValue{ .register = result_reg }; |
| 3302 | }, | 3162 | }, |
| 3303 | else => return self.fail("TODO implement codegen struct_field_ptr for {}", .{mcv}), | 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,7 +3217,7 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void { |
| 3357 | const mask = (~@as(u64, 0)) >> mask_shift; | 3217 | const mask = (~@as(u64, 0)) >> mask_shift; |
| 3358 | | 3218 | |
| 3359 | const tmp_reg = try self.copyToTmpRegister(Type.usize, .{ .immediate = mask }); | 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 | const signedness: std.builtin.Signedness = blk: { | 3222 | const signedness: std.builtin.Signedness = blk: { |
| 3363 | if (struct_field_ty.zigTypeTag() != .Int) break :blk .unsigned; | 3223 | if (struct_field_ty.zigTypeTag() != .Int) break :blk .unsigned; |
| ... | @@ -3426,8 +3286,39 @@ fn airFieldParentPtr(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -3426,8 +3286,39 @@ fn airFieldParentPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 3426 | } | 3286 | } |
| 3427 | | 3287 | |
| 3428 | /// Result is always a register. | 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 | const dst_ty = self.air.typeOf(op_lhs); | 3320 | const dst_ty = self.air.typeOf(op_lhs); |
| | 3321 | const src_ty = self.air.typeOf(op_rhs); |
| 3431 | | 3322 | |
| 3432 | const lhs = try self.resolveInst(op_lhs); | 3323 | const lhs = try self.resolveInst(op_lhs); |
| 3433 | const lhs_lock: ?RegisterLock = switch (lhs) { | 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,7 +3339,7 @@ fn genBinMathOp(self: *Self, inst: Air.Inst.Index, op_lhs: Air.Inst.Ref, op_rhs: |
| 3448 | if (self.reuseOperand(inst, op_lhs, 0, lhs) and lhs.isRegister()) { | 3339 | if (self.reuseOperand(inst, op_lhs, 0, lhs) and lhs.isRegister()) { |
| 3449 | break :blk lhs; | 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 | flipped = true; | 3343 | flipped = true; |
| 3453 | break :blk rhs; | 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,7 +3354,7 @@ fn genBinMathOp(self: *Self, inst: Air.Inst.Index, op_lhs: Air.Inst.Ref, op_rhs: |
| 3463 | const src_mcv: MCValue = blk: { | 3354 | const src_mcv: MCValue = blk: { |
| 3464 | const mcv = if (flipped) lhs else rhs; | 3355 | const mcv = if (flipped) lhs else rhs; |
| 3465 | if (mcv.isRegister() or mcv.isMemory()) break :blk mcv; | 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 | const src_mcv_lock: ?RegisterLock = switch (src_mcv) { | 3359 | const src_mcv_lock: ?RegisterLock = switch (src_mcv) { |
| 3469 | .register => |reg| self.register_manager.lockReg(reg), | 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,18 +3362,39 @@ fn genBinMathOp(self: *Self, inst: Air.Inst.Index, op_lhs: Air.Inst.Ref, op_rhs: |
| 3471 | }; | 3362 | }; |
| 3472 | defer if (src_mcv_lock) |lock| self.register_manager.unlockReg(lock); | 3363 | defer if (src_mcv_lock) |lock| self.register_manager.unlockReg(lock); |
| 3473 | | 3364 | |
| 3474 | const tag = self.air.instructions.items(.tag)[inst]; | | |
| 3475 | switch (tag) { | 3365 | switch (tag) { |
| 3476 | .add, .addwrap, .add_with_overflow => try self.genBinMathOpMir(.add, dst_ty, dst_mcv, src_mcv), | 3366 | .add, |
| 3477 | .bool_or, .bit_or => try self.genBinMathOpMir(.@"or", dst_ty, dst_mcv, src_mcv), | 3367 | .addwrap, |
| 3478 | .bool_and, .bit_and => try self.genBinMathOpMir(.@"and", dst_ty, dst_mcv, src_mcv), | 3368 | .add_with_overflow, |
| 3479 | .xor, .not => try self.genBinMathOpMir(.xor, dst_ty, dst_mcv, src_mcv), | 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 | else => unreachable, | 3392 | else => unreachable, |
| 3481 | } | 3393 | } |
| 3482 | return dst_mcv; | 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 | const abi_size = @intCast(u32, dst_ty.abiSize(self.target.*)); | 3398 | const abi_size = @intCast(u32, dst_ty.abiSize(self.target.*)); |
| 3487 | switch (dst_mcv) { | 3399 | switch (dst_mcv) { |
| 3488 | .none => unreachable, | 3400 | .none => unreachable, |
| ... | @@ -3504,7 +3416,7 @@ fn genBinMathOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MC | ... | @@ -3504,7 +3416,7 @@ fn genBinMathOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MC |
| 3504 | defer if (dst_reg_lock) |lock| self.register_manager.unlockReg(lock); | 3416 | defer if (dst_reg_lock) |lock| self.register_manager.unlockReg(lock); |
| 3505 | | 3417 | |
| 3506 | const reg = try self.copyToTmpRegister(dst_ty, src_mcv); | 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 | .register => |src_reg| { | 3421 | .register => |src_reg| { |
| 3510 | _ = try self.addInst(.{ | 3422 | _ = try self.addInst(.{ |
| ... | @@ -3536,7 +3448,7 @@ fn genBinMathOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MC | ... | @@ -3536,7 +3448,7 @@ fn genBinMathOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MC |
| 3536 | defer if (dst_reg_lock) |lock| self.register_manager.unlockReg(lock); | 3448 | defer if (dst_reg_lock) |lock| self.register_manager.unlockReg(lock); |
| 3537 | | 3449 | |
| 3538 | const reg = try self.copyToTmpRegister(dst_ty, src_mcv); | 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 | .stack_offset => |off| { | 3453 | .stack_offset => |off| { |
| 3542 | if (off > math.maxInt(i32)) { | 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,7 +3549,7 @@ fn genBinMathOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MC |
| 3637 | | 3549 | |
| 3638 | /// Performs multi-operand integer multiplication between dst_mcv and src_mcv, storing the result in dst_mcv. | 3550 | /// Performs multi-operand integer multiplication between dst_mcv and src_mcv, storing the result in dst_mcv. |
| 3639 | /// Does not support byte-size operands. | 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 | const abi_size = @intCast(u32, dst_ty.abiSize(self.target.*)); | 3553 | const abi_size = @intCast(u32, dst_ty.abiSize(self.target.*)); |
| 3642 | switch (dst_mcv) { | 3554 | switch (dst_mcv) { |
| 3643 | .none => unreachable, | 3555 | .none => unreachable, |
| ... | @@ -3733,11 +3645,17 @@ fn genIntMulComplexOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: M | ... | @@ -3733,11 +3645,17 @@ fn genIntMulComplexOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: M |
| 3733 | .data = undefined, | 3645 | .data = undefined, |
| 3734 | }); | 3646 | }); |
| 3735 | // copy dst_reg back out | 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| { | 3650 | .immediate => { |
| 3739 | _ = imm; | 3651 | // copy dst to a register |
| 3740 | return self.fail("TODO implement x86 multiply source immediate", .{}); | 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 | .memory, .stack_offset => { | 3660 | .memory, .stack_offset => { |
| 3743 | return self.fail("TODO implement x86 multiply source memory", .{}); | 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,7 +4131,7 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void { |
| 4213 | // This instruction supports only signed 32-bit immediates at most. | 4131 | // This instruction supports only signed 32-bit immediates at most. |
| 4214 | const src_mcv = try self.limitImmediateType(bin_op.rhs, i32); | 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 | break :result switch (signedness) { | 4135 | break :result switch (signedness) { |
| 4218 | .signed => MCValue{ .compare_flags_signed = op }, | 4136 | .signed => MCValue{ .compare_flags_signed = op }, |
| 4219 | .unsigned => MCValue{ .compare_flags_unsigned = op }, | 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,7 +4524,7 @@ fn isNull(self: *Self, inst: Air.Inst.Index, ty: Type, operand: MCValue) !MCValu |
| 4606 | break :blk if (payload_ty.hasRuntimeBits()) Type.bool else ty; | 4524 | break :blk if (payload_ty.hasRuntimeBits()) Type.bool else ty; |
| 4607 | } else ty; | 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 | return MCValue{ .compare_flags_unsigned = .eq }; | 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,13 +4547,13 @@ fn isErr(self: *Self, inst: Air.Inst.Index, ty: Type, operand: MCValue) !MCValue |
| 4629 | | 4547 | |
| 4630 | if (!payload_type.hasRuntimeBits()) { | 4548 | if (!payload_type.hasRuntimeBits()) { |
| 4631 | if (err_type.abiSize(self.target.*) <= 8) { | 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 | return MCValue{ .compare_flags_unsigned = .gt }; | 4551 | return MCValue{ .compare_flags_unsigned = .gt }; |
| 4634 | } else { | 4552 | } else { |
| 4635 | return self.fail("TODO isErr for errors with size larger than register size", .{}); | 4553 | return self.fail("TODO isErr for errors with size larger than register size", .{}); |
| 4636 | } | 4554 | } |
| 4637 | } else { | 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 | return MCValue{ .compare_flags_unsigned = .gt }; | 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,21 +4971,6 @@ fn airBr(self: *Self, inst: Air.Inst.Index) !void { |
| 5053 | return self.finishAir(inst, .dead, .{ branch.operand, .none, .none }); | 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 | fn br(self: *Self, block: Air.Inst.Index, operand: Air.Inst.Ref) !void { | 4974 | fn br(self: *Self, block: Air.Inst.Index, operand: Air.Inst.Ref) !void { |
| 5072 | const block_data = self.blocks.getPtr(block).?; | 4975 | const block_data = self.blocks.getPtr(block).?; |
| 5073 | | 4976 | |
| ... | @@ -5844,7 +5747,7 @@ fn genInlineMemset( | ... | @@ -5844,7 +5747,7 @@ fn genInlineMemset( |
| 5844 | defer self.register_manager.unlockReg(addr_reg_lock); | 5747 | defer self.register_manager.unlockReg(addr_reg_lock); |
| 5845 | | 5748 | |
| 5846 | try self.genSetReg(Type.usize, .rax, len); | 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 | // loop: | 5752 | // loop: |
| 5850 | // cmp rax, -1 | 5753 | // cmp rax, -1 |
| ... | @@ -6963,10 +6866,10 @@ fn truncateRegister(self: *Self, ty: Type, reg: Register) !void { | ... | @@ -6963,10 +6866,10 @@ fn truncateRegister(self: *Self, ty: Type, reg: Register) !void { |
| 6963 | const shift = @intCast(u6, max_reg_bit_width - int_info.bits); | 6866 | const shift = @intCast(u6, max_reg_bit_width - int_info.bits); |
| 6964 | const mask = (~@as(u64, 0)) >> shift; | 6867 | const mask = (~@as(u64, 0)) >> shift; |
| 6965 | if (int_info.bits <= 32) { | 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 | } else { | 6870 | } else { |
| 6968 | const tmp_reg = try self.copyToTmpRegister(Type.usize, .{ .immediate = mask }); | 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 | } |