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 {...@@ -592,8 +592,8 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
592 .sub => try self.airBinOp(inst),592 .sub => try self.airBinOp(inst),
593 .subwrap => try self.airBinOp(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.airBinOp(inst),
596 .mulwrap => try self.airMul(inst),596 .mulwrap => try self.airBinOp(inst),
597 .mul_sat => try self.airMulSat(inst),597 .mul_sat => try self.airMulSat(inst),
598 .rem => try self.airRem(inst),598 .rem => try self.airRem(inst),
599 .mod => try self.airMod(inst),599 .mod => try self.airMod(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.genBinOp(inst, ty_op.operand, .bool_true);1125 break :result try self.genBinOp(inst, ty_op.operand, .bool_true, 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}
...@@ -1185,24 +1185,6 @@ fn airMax(self: *Self, inst: Air.Inst.Index) !void {...@@ -1185,24 +1185,6 @@ 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}
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
1206fn airSlice(self: *Self, inst: Air.Inst.Index) !void {1188fn airSlice(self: *Self, inst: Air.Inst.Index) !void {
1207 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;1189 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
1208 const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data;1190 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 {...@@ -1229,7 +1211,7 @@ fn airBinOp(self: *Self, inst: Air.Inst.Index) !void {
1229 const result: MCValue = if (self.liveness.isUnused(inst))1211 const result: MCValue = if (self.liveness.isUnused(inst))
1230 .dead1212 .dead
1231 else1213 else
1232 try self.genBinOp(inst, bin_op.lhs, bin_op.rhs);1214 try self.genBinOp(inst, bin_op.lhs, bin_op.rhs, true);
1233 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });1215 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
1234}1216}
12351217
...@@ -1251,36 +1233,6 @@ fn airSubSat(self: *Self, inst: Air.Inst.Index) !void {...@@ -1251,36 +1233,6 @@ fn airSubSat(self: *Self, inst: Air.Inst.Index) !void {
1251 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 });
1252}1234}
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
1284fn airMulSat(self: *Self, inst: Air.Inst.Index) !void {1236fn airMulSat(self: *Self, inst: Air.Inst.Index) !void {
1285 const bin_op = self.air.instructions.items(.data)[inst].bin_op;1237 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
1286 const result: MCValue = if (self.liveness.isUnused(inst))1238 const result: MCValue = if (self.liveness.isUnused(inst))
...@@ -1308,7 +1260,7 @@ fn airAddWithOverflow(self: *Self, inst: Air.Inst.Index) !void {...@@ -1308,7 +1260,7 @@ fn airAddWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
1308 try self.spillCompareFlagsIfOccupied();1260 try self.spillCompareFlagsIfOccupied();
1309 self.compare_flags_inst = inst;1261 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);
1312 const result: MCValue = switch (int_info.signedness) {1264 const result: MCValue = switch (int_info.signedness) {
1313 .signed => .{ .register_overflow_signed = partial.register },1265 .signed => .{ .register_overflow_signed = partial.register },
1314 .unsigned => .{ .register_overflow_unsigned = partial.register },1266 .unsigned => .{ .register_overflow_unsigned = partial.register },
...@@ -1340,7 +1292,7 @@ fn airSubWithOverflow(self: *Self, inst: Air.Inst.Index) !void {...@@ -1340,7 +1292,7 @@ fn airSubWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
1340 try self.spillCompareFlagsIfOccupied();1292 try self.spillCompareFlagsIfOccupied();
1341 self.compare_flags_inst = inst;1293 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);
1344 const result: MCValue = switch (int_info.signedness) {1296 const result: MCValue = switch (int_info.signedness) {
1345 .signed => .{ .register_overflow_signed = partial.register },1297 .signed => .{ .register_overflow_signed = partial.register },
1346 .unsigned => .{ .register_overflow_unsigned = partial.register },1298 .unsigned => .{ .register_overflow_unsigned = partial.register },
...@@ -1373,34 +1325,17 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {...@@ -1373,34 +1325,17 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
1373 return self.fail("TODO implement mul_with_overflow for Ints larger than 64bits", .{});1325 return self.fail("TODO implement mul_with_overflow for Ints larger than 64bits", .{});
1374 }1326 }
13751327
1328 try self.spillCompareFlagsIfOccupied();
1329
1376 if (math.isPowerOfTwo(int_info.bits)) {1330 if (math.isPowerOfTwo(int_info.bits)) {
1377 try self.spillCompareFlagsIfOccupied();
1378 self.compare_flags_inst = inst;1331 self.compare_flags_inst = inst;
13791332 const partial = try self.genBinOp(inst, bin_op.lhs, bin_op.rhs, true);
1380 // Spill .rax and .rdx upfront to ensure we don't spill the operands too late.1333 break :result switch (int_info.signedness) {
1381 try self.register_manager.getReg(.rax, inst);1334 .signed => MCValue{ .register_overflow_signed = partial.register },
1382 try self.register_manager.getReg(.rdx, null);1335 .unsigned => MCValue{ .register_overflow_unsigned = partial.register },
1383 const reg_locks = self.register_manager.lockRegsAssumeUnused(2, .{ .rax, .rdx });
1384 defer for (reg_locks) |reg| {
1385 self.register_manager.unlockReg(reg);
1386 };1336 };
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;
1401 }1337 }
14021338
1403 try self.spillCompareFlagsIfOccupied();
1404 self.compare_flags_inst = null;1339 self.compare_flags_inst = null;
14051340
1406 const dst_reg: Register = dst_reg: {1341 const dst_reg: Register = dst_reg: {
...@@ -1437,20 +1372,8 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {...@@ -1437,20 +1372,8 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
1437 break :dst_reg dst_reg;1372 break :dst_reg dst_reg;
1438 },1373 },
1439 .unsigned => {1374 .unsigned => {
1440 // Spill .rax and .rdx upfront to ensure we don't spill the operands too late.1375 const dst_mcv = try self.genBinOp(inst, bin_op.lhs, bin_op.rhs, false);
1441 try self.register_manager.getReg(.rax, null);1376 break :dst_reg dst_mcv.register;
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.*)));
1454 },1377 },
1455 }1378 }
1456 };1379 };
...@@ -3291,6 +3214,7 @@ fn genBinOp(...@@ -3291,6 +3214,7 @@ fn genBinOp(
3291 inst: Air.Inst.Index,3214 inst: Air.Inst.Index,
3292 op_lhs: Air.Inst.Ref,3215 op_lhs: Air.Inst.Ref,
3293 op_rhs: Air.Inst.Ref,3216 op_rhs: Air.Inst.Ref,
3217 track: bool,
3294) !MCValue {3218) !MCValue {
3295 const tag = self.air.instructions.items(.tag)[inst];3219 const tag = self.air.instructions.items(.tag)[inst];
3296 const is_commutative: bool = switch (tag) {3220 const is_commutative: bool = switch (tag) {
...@@ -3309,6 +3233,8 @@ fn genBinOp(...@@ -3309,6 +3233,8 @@ fn genBinOp(
3309 .subwrap,3233 .subwrap,
3310 .sub_with_overflow,3234 .sub_with_overflow,
3311 .mul,3235 .mul,
3236 .mulwrap,
3237 .mul_with_overflow,
3312 .shl,3238 .shl,
3313 .shr,3239 .shr,
3314 .ptr_add,3240 .ptr_add,
...@@ -3320,6 +3246,43 @@ fn genBinOp(...@@ -3320,6 +3246,43 @@ fn genBinOp(
3320 const dst_ty = self.air.typeOf(op_lhs);3246 const dst_ty = self.air.typeOf(op_lhs);
3321 const src_ty = self.air.typeOf(op_rhs);3247 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
3323 const lhs = try self.resolveInst(op_lhs);3286 const lhs = try self.resolveInst(op_lhs);
3324 const lhs_lock: ?RegisterLock = switch (lhs) {3287 const lhs_lock: ?RegisterLock = switch (lhs) {
3325 .register => |reg| self.register_manager.lockRegAssumeUnused(reg),3288 .register => |reg| self.register_manager.lockRegAssumeUnused(reg),
...@@ -3343,7 +3306,11 @@ fn genBinOp(...@@ -3343,7 +3306,11 @@ fn genBinOp(
3343 flipped = true;3306 flipped = true;
3344 break :blk rhs;3307 break :blk rhs;
3345 }3308 }
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 }
3347 };3314 };
3348 const dst_mcv_lock: ?RegisterLock = switch (dst_mcv) {3315 const dst_mcv_lock: ?RegisterLock = switch (dst_mcv) {
3349 .register => |reg| self.register_manager.lockReg(reg),3316 .register => |reg| self.register_manager.lockReg(reg),