authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-05-09 23:50:01+02:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-05-09 23:50:01+02:00
log7b9f8bfbd80aa37afc160c39b341c59fdd3cbad8
treee4def2bad75bdf226a51fbc31e156e762751dcc7
parent20e7f1218b997e3da5d10cb5d038ed782d772716

x64: migrate mul to new genBinOp helper


1 files changed, 59 insertions(+), 92 deletions(-)

src/arch/x86_64/CodeGen.zig+59-92
......@@ -592,8 +592,8 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
592592 .sub => try self.airBinOp(inst),
593593 .subwrap => try self.airBinOp(inst),
594594 .sub_sat => try self.airSubSat(inst),
595 .mul => try self.airMul(inst),
596 .mulwrap => try self.airMul(inst),
595 .mul => try self.airBinOp(inst),
596 .mulwrap => try self.airBinOp(inst),
597597 .mul_sat => try self.airMulSat(inst),
598598 .rem => try self.airRem(inst),
599599 .mod => try self.airMod(inst),
......@@ -1122,7 +1122,7 @@ fn airNot(self: *Self, inst: Air.Inst.Index) !void {
11221122 },
11231123 else => {},
11241124 }
1125 break :result try self.genBinOp(inst, ty_op.operand, .bool_true);
1125 break :result try self.genBinOp(inst, ty_op.operand, .bool_true, true);
11261126 };
11271127 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
11281128}
......@@ -1185,24 +1185,6 @@ fn airMax(self: *Self, inst: Air.Inst.Index) !void {
11851185 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
11861186}
11871187
1188fn airPtrAdd(self: *Self, inst: Air.Inst.Index) !void {
1189 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
1190 const result = if (self.liveness.isUnused(inst))
1191 .dead
1192 else
1193 try self.genBinOp(inst, bin_op.lhs, bin_op.rhs);
1194 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
1195}
1196
1197fn airPtrSub(self: *Self, inst: Air.Inst.Index) !void {
1198 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
1199 const result = if (self.liveness.isUnused(inst))
1200 .dead
1201 else
1202 try self.genBinOp(inst, bin_op.lhs, bin_op.rhs);
1203 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
1204}
1205
12061188fn airSlice(self: *Self, inst: Air.Inst.Index) !void {
12071189 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
12081190 const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data;
......@@ -1229,7 +1211,7 @@ fn airBinOp(self: *Self, inst: Air.Inst.Index) !void {
12291211 const result: MCValue = if (self.liveness.isUnused(inst))
12301212 .dead
12311213 else
1232 try self.genBinOp(inst, bin_op.lhs, bin_op.rhs);
1214 try self.genBinOp(inst, bin_op.lhs, bin_op.rhs, true);
12331215 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
12341216}
12351217
......@@ -1251,36 +1233,6 @@ fn airSubSat(self: *Self, inst: Air.Inst.Index) !void {
12511233 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
12521234}
12531235
1254fn airMul(self: *Self, inst: Air.Inst.Index) !void {
1255 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
1256 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
1257 const ty = self.air.typeOfIndex(inst);
1258
1259 if (ty.zigTypeTag() != .Int) {
1260 return self.fail("TODO implement 'mul' for operands of dst type {}", .{ty.zigTypeTag()});
1261 }
1262
1263 // Spill .rax and .rdx upfront to ensure we don't spill the operands too late.
1264 try self.register_manager.getReg(.rax, inst);
1265 try self.register_manager.getReg(.rdx, null);
1266 const reg_locks = self.register_manager.lockRegsAssumeUnused(2, .{ .rax, .rdx });
1267 defer for (reg_locks) |reg| {
1268 self.register_manager.unlockReg(reg);
1269 };
1270
1271 const lhs = try self.resolveInst(bin_op.lhs);
1272 const rhs = try self.resolveInst(bin_op.rhs);
1273
1274 const signedness = ty.intInfo(self.target.*).signedness;
1275 try self.genIntMulDivOpMir(switch (signedness) {
1276 .signed => .imul,
1277 .unsigned => .mul,
1278 }, ty, signedness, lhs, rhs);
1279 break :result MCValue{ .register = .rax };
1280 };
1281 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
1282}
1283
12841236fn airMulSat(self: *Self, inst: Air.Inst.Index) !void {
12851237 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
12861238 const result: MCValue = if (self.liveness.isUnused(inst))
......@@ -1308,7 +1260,7 @@ fn airAddWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
13081260 try self.spillCompareFlagsIfOccupied();
13091261 self.compare_flags_inst = inst;
13101262
1311 const partial = try self.genBinOp(inst, bin_op.lhs, bin_op.rhs);
1263 const partial = try self.genBinOp(inst, bin_op.lhs, bin_op.rhs, true);
13121264 const result: MCValue = switch (int_info.signedness) {
13131265 .signed => .{ .register_overflow_signed = partial.register },
13141266 .unsigned => .{ .register_overflow_unsigned = partial.register },
......@@ -1340,7 +1292,7 @@ fn airSubWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
13401292 try self.spillCompareFlagsIfOccupied();
13411293 self.compare_flags_inst = inst;
13421294
1343 const partial = try self.genBinOp(inst, bin_op.lhs, bin_op.rhs);
1295 const partial = try self.genBinOp(inst, bin_op.lhs, bin_op.rhs, true);
13441296 const result: MCValue = switch (int_info.signedness) {
13451297 .signed => .{ .register_overflow_signed = partial.register },
13461298 .unsigned => .{ .register_overflow_unsigned = partial.register },
......@@ -1373,34 +1325,17 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
13731325 return self.fail("TODO implement mul_with_overflow for Ints larger than 64bits", .{});
13741326 }
13751327
1328 try self.spillCompareFlagsIfOccupied();
1329
13761330 if (math.isPowerOfTwo(int_info.bits)) {
1377 try self.spillCompareFlagsIfOccupied();
13781331 self.compare_flags_inst = inst;
1379
1380 // Spill .rax and .rdx upfront to ensure we don't spill the operands too late.
1381 try self.register_manager.getReg(.rax, inst);
1382 try self.register_manager.getReg(.rdx, null);
1383 const reg_locks = self.register_manager.lockRegsAssumeUnused(2, .{ .rax, .rdx });
1384 defer for (reg_locks) |reg| {
1385 self.register_manager.unlockReg(reg);
1332 const partial = try self.genBinOp(inst, bin_op.lhs, bin_op.rhs, true);
1333 break :result switch (int_info.signedness) {
1334 .signed => MCValue{ .register_overflow_signed = partial.register },
1335 .unsigned => MCValue{ .register_overflow_unsigned = partial.register },
13861336 };
1387
1388 const lhs = try self.resolveInst(bin_op.lhs);
1389 const rhs = try self.resolveInst(bin_op.rhs);
1390
1391 try self.genIntMulDivOpMir(switch (int_info.signedness) {
1392 .signed => .imul,
1393 .unsigned => .mul,
1394 }, ty, int_info.signedness, lhs, rhs);
1395
1396 const result: MCValue = switch (int_info.signedness) {
1397 .signed => .{ .register_overflow_signed = .rax },
1398 .unsigned => .{ .register_overflow_unsigned = .rax },
1399 };
1400 break :result result;
14011337 }
14021338
1403 try self.spillCompareFlagsIfOccupied();
14041339 self.compare_flags_inst = null;
14051340
14061341 const dst_reg: Register = dst_reg: {
......@@ -1437,20 +1372,8 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
14371372 break :dst_reg dst_reg;
14381373 },
14391374 .unsigned => {
1440 // Spill .rax and .rdx upfront to ensure we don't spill the operands too late.
1441 try self.register_manager.getReg(.rax, null);
1442 try self.register_manager.getReg(.rdx, null);
1443 const reg_locks = self.register_manager.lockRegsAssumeUnused(2, .{ .rax, .rdx });
1444 defer for (reg_locks) |reg| {
1445 self.register_manager.unlockReg(reg);
1446 };
1447
1448 const lhs = try self.resolveInst(bin_op.lhs);
1449 const rhs = try self.resolveInst(bin_op.rhs);
1450
1451 try self.genIntMulDivOpMir(.mul, ty, .unsigned, lhs, rhs);
1452
1453 break :dst_reg registerAlias(.rax, @intCast(u32, ty.abiSize(self.target.*)));
1375 const dst_mcv = try self.genBinOp(inst, bin_op.lhs, bin_op.rhs, false);
1376 break :dst_reg dst_mcv.register;
14541377 },
14551378 }
14561379 };
......@@ -3291,6 +3214,7 @@ fn genBinOp(
32913214 inst: Air.Inst.Index,
32923215 op_lhs: Air.Inst.Ref,
32933216 op_rhs: Air.Inst.Ref,
3217 track: bool,
32943218) !MCValue {
32953219 const tag = self.air.instructions.items(.tag)[inst];
32963220 const is_commutative: bool = switch (tag) {
......@@ -3309,6 +3233,8 @@ fn genBinOp(
33093233 .subwrap,
33103234 .sub_with_overflow,
33113235 .mul,
3236 .mulwrap,
3237 .mul_with_overflow,
33123238 .shl,
33133239 .shr,
33143240 .ptr_add,
......@@ -3320,6 +3246,43 @@ fn genBinOp(
33203246 const dst_ty = self.air.typeOf(op_lhs);
33213247 const src_ty = self.air.typeOf(op_rhs);
33223248
3249 if (dst_ty.zigTypeTag() == .Vector or dst_ty.zigTypeTag() == .Float) {
3250 return self.fail("TODO implement genBinOp for {}", .{dst_ty.fmtDebug()});
3251 }
3252 if (dst_ty.abiSize(self.target.*) > 8) {
3253 return self.fail("TODO implement genBinOp for {}", .{dst_ty.fmtDebug()});
3254 }
3255
3256 switch (tag) {
3257 .mul,
3258 .mulwrap,
3259 .mul_with_overflow,
3260 => {
3261 // Spill .rax and .rdx upfront to ensure we don't spill the operands too late.
3262 try self.register_manager.getReg(.rax, if (track) inst else null);
3263 try self.register_manager.getReg(.rdx, null);
3264 const reg_locks = self.register_manager.lockRegsAssumeUnused(2, .{ .rax, .rdx });
3265 defer for (reg_locks) |reg| {
3266 self.register_manager.unlockReg(reg);
3267 };
3268
3269 const lhs = try self.resolveInst(op_lhs);
3270 const rhs = try self.resolveInst(op_rhs);
3271
3272 const int_info = dst_ty.intInfo(self.target.*);
3273 try self.genIntMulDivOpMir(switch (int_info.signedness) {
3274 .signed => .imul,
3275 .unsigned => .mul,
3276 }, dst_ty, int_info.signedness, lhs, rhs);
3277
3278 return switch (int_info.signedness) {
3279 .signed => MCValue{ .register = .rax },
3280 .unsigned => MCValue{ .register = registerAlias(.rax, @intCast(u32, dst_ty.abiSize(self.target.*))) },
3281 };
3282 },
3283 else => {},
3284 }
3285
33233286 const lhs = try self.resolveInst(op_lhs);
33243287 const lhs_lock: ?RegisterLock = switch (lhs) {
33253288 .register => |reg| self.register_manager.lockRegAssumeUnused(reg),
......@@ -3343,7 +3306,11 @@ fn genBinOp(
33433306 flipped = true;
33443307 break :blk rhs;
33453308 }
3346 break :blk try self.copyToRegisterWithInstTracking(inst, dst_ty, lhs);
3309 if (track) {
3310 break :blk try self.copyToRegisterWithInstTracking(inst, dst_ty, lhs);
3311 } else {
3312 break :blk MCValue{ .register = try self.copyToTmpRegister(dst_ty, lhs) };
3313 }
33473314 };
33483315 const dst_mcv_lock: ?RegisterLock = switch (dst_mcv) {
33493316 .register => |reg| self.register_manager.lockReg(reg),