authorgravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2023-03-19 02:43:55-04:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2023-03-21 08:49:54+01:00
logbbd05e2d972b26038bf307f03aa569a7e7a2ac2c
treea3a1325faa481ff31b295166ee72f686344d3fdf
parent80427796df5f8eb23ac7ca8ee03ac572b737757f

x86_64: improve codegen for neg and not


5 files changed, 263 insertions(+), 80 deletions(-)

src/arch/x86_64/CodeGen.zig+244-79
...@@ -813,6 +813,9 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {...@@ -813,6 +813,9 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
813813
814 switch (air_tags[inst]) {814 switch (air_tags[inst]) {
815 // zig fmt: off815 // zig fmt: off
816 .not,
817 => |tag| try self.airUnOp(inst, tag),
818
816 .add,819 .add,
817 .addwrap,820 .addwrap,
818 .sub,821 .sub,
...@@ -905,7 +908,6 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {...@@ -905,7 +908,6 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
905 .is_err_ptr => try self.airIsErrPtr(inst),908 .is_err_ptr => try self.airIsErrPtr(inst),
906 .load => try self.airLoad(inst),909 .load => try self.airLoad(inst),
907 .loop => try self.airLoop(inst),910 .loop => try self.airLoop(inst),
908 .not => try self.airNot(inst),
909 .ptrtoint => try self.airPtrToInt(inst),911 .ptrtoint => try self.airPtrToInt(inst),
910 .ret => try self.airRet(inst),912 .ret => try self.airRet(inst),
911 .ret_load => try self.airRetLoad(inst),913 .ret_load => try self.airRetLoad(inst),
...@@ -1419,8 +1421,7 @@ fn airTrunc(self: *Self, inst: Air.Inst.Index) !void {...@@ -1419,8 +1421,7 @@ fn airTrunc(self: *Self, inst: Air.Inst.Index) !void {
14191421
1420 // when truncating a `u16` to `u5`, for example, those top 3 bits in the result1422 // when truncating a `u16` to `u5`, for example, those top 3 bits in the result
1421 // have to be removed. this only happens if the dst if not a power-of-two size.1423 // have to be removed. this only happens if the dst if not a power-of-two size.
1422 const dst_bit_size = dst_ty.bitSize(self.target.*);1424 if (self.regExtraBits(dst_ty) > 0) {
1423 if (!math.isPowerOfTwo(dst_bit_size) or dst_bit_size < 8) {
1424 try self.truncateRegister(dst_ty, reg);1425 try self.truncateRegister(dst_ty, reg);
1425 }1426 }
14261427
...@@ -1434,58 +1435,6 @@ fn airBoolToInt(self: *Self, inst: Air.Inst.Index) !void {...@@ -1434,58 +1435,6 @@ fn airBoolToInt(self: *Self, inst: Air.Inst.Index) !void {
1434 return self.finishAir(inst, result, .{ un_op, .none, .none });1435 return self.finishAir(inst, result, .{ un_op, .none, .none });
1435}1436}
14361437
1437fn airNot(self: *Self, inst: Air.Inst.Index) !void {
1438 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
1439
1440 if (self.liveness.isUnused(inst)) {
1441 return self.finishAir(inst, .dead, .{ ty_op.operand, .none, .none });
1442 }
1443
1444 const operand_ty = self.air.typeOf(ty_op.operand);
1445 const operand = try self.resolveInst(ty_op.operand);
1446
1447 const result: MCValue = result: {
1448 switch (operand) {
1449 .dead => unreachable,
1450 .unreach => unreachable,
1451 .eflags => |cc| {
1452 break :result MCValue{ .eflags = cc.negate() };
1453 },
1454 else => {},
1455 }
1456
1457 const operand_lock: ?RegisterLock = switch (operand) {
1458 .register => |reg| self.register_manager.lockRegAssumeUnused(reg),
1459 else => null,
1460 };
1461 defer if (operand_lock) |lock| self.register_manager.unlockReg(lock);
1462
1463 const dst_mcv: MCValue = blk: {
1464 if (self.reuseOperand(inst, ty_op.operand, 0, operand) and operand.isRegister()) {
1465 break :blk operand;
1466 }
1467 break :blk try self.copyToRegisterWithInstTracking(inst, operand_ty, operand);
1468 };
1469 const dst_mcv_lock: ?RegisterLock = switch (dst_mcv) {
1470 .register => |reg| self.register_manager.lockReg(reg),
1471 else => null,
1472 };
1473 defer if (dst_mcv_lock) |lock| self.register_manager.unlockReg(lock);
1474
1475 const mask = switch (operand_ty.abiSize(self.target.*)) {
1476 1 => ~@as(u8, 0),
1477 2 => ~@as(u16, 0),
1478 4 => ~@as(u32, 0),
1479 8 => ~@as(u64, 0),
1480 else => unreachable,
1481 };
1482 try self.genBinOpMir(.xor, operand_ty, dst_mcv, .{ .immediate = mask });
1483
1484 break :result dst_mcv;
1485 };
1486 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
1487}
1488
1489fn airSlice(self: *Self, inst: Air.Inst.Index) !void {1438fn airSlice(self: *Self, inst: Air.Inst.Index) !void {
1490 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;1439 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
1491 const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data;1440 const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data;
...@@ -1507,6 +1456,16 @@ fn airSlice(self: *Self, inst: Air.Inst.Index) !void {...@@ -1507,6 +1456,16 @@ fn airSlice(self: *Self, inst: Air.Inst.Index) !void {
1507 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });1456 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
1508}1457}
15091458
1459fn airUnOp(self: *Self, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void {
1460 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
1461
1462 const result = if (self.liveness.isUnused(inst))
1463 .dead
1464 else
1465 try self.genUnOp(inst, tag, ty_op.operand);
1466 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
1467}
1468
1510fn airBinOp(self: *Self, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void {1469fn airBinOp(self: *Self, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void {
1511 const bin_op = self.air.instructions.items(.data)[inst].bin_op;1470 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
15121471
...@@ -2602,7 +2561,6 @@ fn airClz(self: *Self, inst: Air.Inst.Index) !void {...@@ -2602,7 +2561,6 @@ fn airClz(self: *Self, inst: Air.Inst.Index) !void {
26022561
2603 const dst_ty = self.air.typeOfIndex(inst);2562 const dst_ty = self.air.typeOfIndex(inst);
2604 const src_ty = self.air.typeOf(ty_op.operand);2563 const src_ty = self.air.typeOf(ty_op.operand);
2605 const src_bits = src_ty.bitSize(self.target.*);
26062564
2607 const src_mcv = try self.resolveInst(ty_op.operand);2565 const src_mcv = try self.resolveInst(ty_op.operand);
2608 const mat_src_mcv = switch (src_mcv) {2566 const mat_src_mcv = switch (src_mcv) {
...@@ -2622,14 +2580,14 @@ fn airClz(self: *Self, inst: Air.Inst.Index) !void {...@@ -2622,14 +2580,14 @@ fn airClz(self: *Self, inst: Air.Inst.Index) !void {
26222580
2623 if (Target.x86.featureSetHas(self.target.cpu.features, .lzcnt)) {2581 if (Target.x86.featureSetHas(self.target.cpu.features, .lzcnt)) {
2624 try self.genBinOpMir(.lzcnt, src_ty, dst_mcv, mat_src_mcv);2582 try self.genBinOpMir(.lzcnt, src_ty, dst_mcv, mat_src_mcv);
2625 const src_abi_size = @intCast(u32, src_ty.abiSize(self.target.*));2583 const extra_bits = self.regExtraBits(src_ty);
2626 const extra_bits = registerAlias(dst_reg, src_abi_size).bitSize() - src_bits;
2627 if (extra_bits > 0) {2584 if (extra_bits > 0) {
2628 try self.genBinOpMir(.sub, dst_ty, dst_mcv, .{ .immediate = extra_bits });2585 try self.genBinOpMir(.sub, dst_ty, dst_mcv, .{ .immediate = extra_bits });
2629 }2586 }
2630 break :result dst_mcv;2587 break :result dst_mcv;
2631 }2588 }
26322589
2590 const src_bits = src_ty.bitSize(self.target.*);
2633 const width_reg = try self.copyToTmpRegister(dst_ty, .{ .immediate = src_bits });2591 const width_reg = try self.copyToTmpRegister(dst_ty, .{ .immediate = src_bits });
2634 const width_mcv = MCValue{ .register = width_reg };2592 const width_mcv = MCValue{ .register = width_reg };
2635 try self.genBinOpMir(.bsr, src_ty, dst_mcv, mat_src_mcv);2593 try self.genBinOpMir(.bsr, src_ty, dst_mcv, mat_src_mcv);
...@@ -2673,8 +2631,7 @@ fn airCtz(self: *Self, inst: Air.Inst.Index) !void {...@@ -2673,8 +2631,7 @@ fn airCtz(self: *Self, inst: Air.Inst.Index) !void {
2673 defer if (dst_lock) |lock| self.register_manager.unlockReg(lock);2631 defer if (dst_lock) |lock| self.register_manager.unlockReg(lock);
26742632
2675 if (Target.x86.featureSetHas(self.target.cpu.features, .bmi)) {2633 if (Target.x86.featureSetHas(self.target.cpu.features, .bmi)) {
2676 const src_abi_size = @intCast(u32, src_ty.abiSize(self.target.*));2634 const extra_bits = self.regExtraBits(src_ty);
2677 const extra_bits = registerAlias(dst_reg, src_abi_size).bitSize() - src_bits;
2678 const masked_mcv = if (extra_bits > 0) masked: {2635 const masked_mcv = if (extra_bits > 0) masked: {
2679 const mask_mcv = MCValue{2636 const mask_mcv = MCValue{
2680 .immediate = ((@as(u64, 1) << @intCast(u6, extra_bits)) - 1) << @intCast(u6, src_bits),2637 .immediate = ((@as(u64, 1) << @intCast(u6, extra_bits)) - 1) << @intCast(u6, src_bits),
...@@ -3293,6 +3250,106 @@ fn airFieldParentPtr(self: *Self, inst: Air.Inst.Index) !void {...@@ -3293,6 +3250,106 @@ fn airFieldParentPtr(self: *Self, inst: Air.Inst.Index) !void {
3293 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });3250 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
3294}3251}
32953252
3253fn genUnOp(self: *Self, maybe_inst: ?Air.Inst.Index, tag: Air.Inst.Tag, src_air: Air.Inst.Ref) !MCValue {
3254 const src_ty = self.air.typeOf(src_air);
3255 const src_mcv = try self.resolveInst(src_air);
3256 if (src_ty.zigTypeTag() == .Vector) {
3257 return self.fail("TODO implement genBinOp for {}", .{src_ty.fmt(self.bin_file.options.module.?)});
3258 }
3259 if (src_ty.abiSize(self.target.*) > 8) {
3260 return self.fail("TODO implement genBinOp for {}", .{src_ty.fmt(self.bin_file.options.module.?)});
3261 }
3262
3263 switch (src_mcv) {
3264 .eflags => |cc| switch (tag) {
3265 .not => return .{ .eflags = cc.negate() },
3266 else => {},
3267 },
3268 else => {},
3269 }
3270
3271 const src_lock = switch (src_mcv) {
3272 .register => |reg| self.register_manager.lockRegAssumeUnused(reg),
3273 else => null,
3274 };
3275 defer if (src_lock) |lock| self.register_manager.unlockReg(lock);
3276
3277 const dst_mcv: MCValue = if (maybe_inst) |inst|
3278 if (self.reuseOperand(inst, src_air, 0, src_mcv))
3279 src_mcv
3280 else
3281 try self.copyToRegisterWithInstTracking(inst, src_ty, src_mcv)
3282 else
3283 .{ .register = try self.copyToTmpRegister(src_ty, src_mcv) };
3284 const dst_lock = switch (dst_mcv) {
3285 .register => |reg| self.register_manager.lockReg(reg),
3286 else => null,
3287 };
3288 defer if (dst_lock) |lock| self.register_manager.unlockReg(lock);
3289
3290 switch (tag) {
3291 .not => {
3292 const int_info = if (src_ty.tag() == .bool)
3293 std.builtin.Type.Int{ .signedness = .unsigned, .bits = 1 }
3294 else
3295 src_ty.intInfo(self.target.*);
3296 const extra_bits = self.regExtraBits(src_ty);
3297 if (int_info.signedness == .unsigned and extra_bits > 0) {
3298 const mask = (@as(u64, 1) << @intCast(u6, src_ty.bitSize(self.target.*))) - 1;
3299 try self.genBinOpMir(.xor, src_ty, dst_mcv, .{ .immediate = mask });
3300 } else try self.genUnOpMir(.not, src_ty, dst_mcv);
3301 },
3302
3303 .neg => try self.genUnOpMir(.neg, src_ty, dst_mcv),
3304
3305 else => unreachable,
3306 }
3307 return dst_mcv;
3308}
3309
3310fn genUnOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MCValue) !void {
3311 const abi_size = @intCast(u32, dst_ty.abiSize(self.target.*));
3312 switch (dst_mcv) {
3313 .none => unreachable,
3314 .undef => unreachable,
3315 .dead, .unreach, .immediate => unreachable,
3316 .eflags => unreachable,
3317 .register_overflow => unreachable,
3318 .register => |dst_reg| try self.asmRegister(mir_tag, registerAlias(dst_reg, abi_size)),
3319 .ptr_stack_offset, .stack_offset => |off| {
3320 if (off > math.maxInt(i32)) {
3321 return self.fail("stack offset too large", .{});
3322 }
3323 if (abi_size > 8) {
3324 return self.fail("TODO implement {} for stack dst with large ABI", .{mir_tag});
3325 }
3326
3327 try self.asmMemory(mir_tag, Memory.sib(Memory.PtrSize.fromSize(abi_size), .{
3328 .base = .rbp,
3329 .disp = -off,
3330 }));
3331 },
3332 .memory, .linker_load => {
3333 const addr_reg = (try self.register_manager.allocReg(null, gp)).to64();
3334 const addr_reg_lock = self.register_manager.lockRegAssumeUnused(addr_reg);
3335 defer self.register_manager.unlockReg(addr_reg_lock);
3336
3337 try self.loadMemPtrIntoRegister(addr_reg, Type.usize, dst_mcv);
3338
3339 // To get the actual address of the value we want to modify we have to go through the GOT
3340 try self.asmRegisterMemory(.mov, addr_reg, Memory.sib(.qword, .{
3341 .base = addr_reg,
3342 .disp = 0,
3343 }));
3344
3345 try self.asmMemory(mir_tag, Memory.sib(Memory.PtrSize.fromSize(abi_size), .{
3346 .base = addr_reg,
3347 .disp = 0,
3348 }));
3349 },
3350 }
3351}
3352
3296/// Clobbers .rcx for non-immediate shift value.3353/// Clobbers .rcx for non-immediate shift value.
3297fn genShiftBinOpMir(self: *Self, tag: Mir.Inst.Tag, ty: Type, reg: Register, shift: MCValue) !void {3354fn genShiftBinOpMir(self: *Self, tag: Mir.Inst.Tag, ty: Type, reg: Register, shift: MCValue) !void {
3298 assert(reg.to64() != .rcx);3355 assert(reg.to64() != .rcx);
...@@ -3573,6 +3630,17 @@ fn genBinOp(...@@ -3573,6 +3630,17 @@ fn genBinOp(
3573 return self.fail("TODO implement genBinOp for {}", .{lhs_ty.fmt(self.bin_file.options.module.?)});3630 return self.fail("TODO implement genBinOp for {}", .{lhs_ty.fmt(self.bin_file.options.module.?)});
3574 }3631 }
35753632
3633 switch (lhs) {
3634 .immediate => |imm| switch (imm) {
3635 0 => switch (tag) {
3636 .sub, .subwrap => return self.genUnOp(maybe_inst, .neg, rhs_air),
3637 else => {},
3638 },
3639 else => {},
3640 },
3641 else => {},
3642 }
3643
3576 const is_commutative: bool = switch (tag) {3644 const is_commutative: bool = switch (tag) {
3577 .add,3645 .add,
3578 .addwrap,3646 .addwrap,
...@@ -3595,7 +3663,7 @@ fn genBinOp(...@@ -3595,7 +3663,7 @@ fn genBinOp(
3595 defer if (lhs_lock) |lock| self.register_manager.unlockReg(lock);3663 defer if (lhs_lock) |lock| self.register_manager.unlockReg(lock);
35963664
3597 const rhs_lock: ?RegisterLock = switch (rhs) {3665 const rhs_lock: ?RegisterLock = switch (rhs) {
3598 .register => |reg| self.register_manager.lockRegAssumeUnused(reg),3666 .register => |reg| self.register_manager.lockReg(reg),
3599 else => null,3667 else => null,
3600 };3668 };
3601 defer if (rhs_lock) |lock| self.register_manager.unlockReg(lock);3669 defer if (rhs_lock) |lock| self.register_manager.unlockReg(lock);
...@@ -3740,7 +3808,28 @@ fn genBinOp(...@@ -3740,7 +3808,28 @@ fn genBinOp(
37403808
3741 const abi_size = @intCast(u32, lhs_ty.abiSize(self.target.*));3809 const abi_size = @intCast(u32, lhs_ty.abiSize(self.target.*));
3742 switch (dst_mcv) {3810 switch (dst_mcv) {
3811 .none,
3812 .undef,
3813 .dead,
3814 .unreach,
3815 .immediate,
3816 .eflags,
3817 .register_overflow,
3818 .stack_offset,
3819 .ptr_stack_offset,
3820 .memory,
3821 .linker_load,
3822 => unreachable,
3743 .register => |dst_reg| switch (mat_src_mcv) {3823 .register => |dst_reg| switch (mat_src_mcv) {
3824 .none,
3825 .undef,
3826 .dead,
3827 .unreach,
3828 .immediate,
3829 .eflags,
3830 .register_overflow,
3831 .ptr_stack_offset,
3832 => unreachable,
3744 .register => |src_reg| try self.asmCmovccRegisterRegister(3833 .register => |src_reg| try self.asmCmovccRegisterRegister(
3745 registerAlias(dst_reg, abi_size),3834 registerAlias(dst_reg, abi_size),
3746 registerAlias(src_reg, abi_size),3835 registerAlias(src_reg, abi_size),
...@@ -3748,12 +3837,36 @@ fn genBinOp(...@@ -3748,12 +3837,36 @@ fn genBinOp(
3748 ),3837 ),
3749 .stack_offset => |off| try self.asmCmovccRegisterMemory(3838 .stack_offset => |off| try self.asmCmovccRegisterMemory(
3750 registerAlias(dst_reg, abi_size),3839 registerAlias(dst_reg, abi_size),
3751 Memory.sib(Memory.PtrSize.fromSize(abi_size), .{ .base = .rbp, .disp = -off }),3840 Memory.sib(Memory.PtrSize.fromSize(abi_size), .{
3841 .base = .rbp,
3842 .disp = -off,
3843 }),
3752 cc,3844 cc,
3753 ),3845 ),
3754 else => unreachable,3846 .memory, .linker_load => {
3847 const addr_reg = (try self.register_manager.allocReg(null, gp)).to64();
3848 const addr_reg_lock = self.register_manager.lockRegAssumeUnused(addr_reg);
3849 defer self.register_manager.unlockReg(addr_reg_lock);
3850
3851 try self.loadMemPtrIntoRegister(addr_reg, Type.usize, dst_mcv);
3852
3853 // To get the actual address of the value we want to modify we
3854 // we have to go through the GOT
3855 try self.asmRegisterMemory(.mov, addr_reg, Memory.sib(.qword, .{
3856 .base = addr_reg,
3857 .disp = 0,
3858 }));
3859
3860 try self.asmCmovccRegisterMemory(
3861 registerAlias(dst_reg, abi_size),
3862 Memory.sib(Memory.PtrSize.fromSize(abi_size), .{
3863 .base = addr_reg,
3864 .disp = 0,
3865 }),
3866 cc,
3867 );
3868 },
3755 },3869 },
3756 else => unreachable,
3757 }3870 }
3758 },3871 },
3759 .Float => try self.genBinOpMir(switch (lhs_ty.tag()) {3872 .Float => try self.genBinOpMir(switch (lhs_ty.tag()) {
...@@ -3813,16 +3926,15 @@ fn genBinOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MCValu...@@ -3813,16 +3926,15 @@ fn genBinOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MCValu
3813 ),3926 ),
3814 },3927 },
3815 .immediate => |imm| {3928 .immediate => |imm| {
3816 switch (abi_size) {3929 switch (self.regBitSize(dst_ty)) {
3817 0 => unreachable,3930 8, 16, 32 => {
3818 1...4 => {
3819 try self.asmRegisterImmediate(3931 try self.asmRegisterImmediate(
3820 mir_tag,3932 mir_tag,
3821 registerAlias(dst_reg, abi_size),3933 registerAlias(dst_reg, abi_size),
3822 Immediate.u(@intCast(u32, imm)),3934 Immediate.u(@intCast(u32, imm)),
3823 );3935 );
3824 },3936 },
3825 5...8 => {3937 64 => {
3826 if (math.cast(i32, @bitCast(i64, imm))) |small| {3938 if (math.cast(i32, @bitCast(i64, imm))) |small| {
3827 try self.asmRegisterImmediate(3939 try self.asmRegisterImmediate(
3828 mir_tag,3940 mir_tag,
...@@ -3883,11 +3995,40 @@ fn genBinOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MCValu...@@ -3883,11 +3995,40 @@ fn genBinOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MCValu
3883 }), registerAlias(src_reg, abi_size));3995 }), registerAlias(src_reg, abi_size));
3884 },3996 },
3885 .immediate => |imm| {3997 .immediate => |imm| {
3886 // TODO3998 switch (self.regBitSize(dst_ty)) {
3887 try self.asmMemoryImmediate(mir_tag, Memory.sib(Memory.PtrSize.fromSize(abi_size), .{3999 8, 16, 32 => {
3888 .base = .rbp,4000 try self.asmMemoryImmediate(
3889 .disp = -off,4001 mir_tag,
3890 }), Immediate.u(@intCast(u32, imm)));4002 Memory.sib(Memory.PtrSize.fromSize(abi_size), .{
4003 .base = .rbp,
4004 .disp = -off,
4005 }),
4006 Immediate.u(@intCast(u32, imm)),
4007 );
4008 },
4009 64 => {
4010 if (math.cast(i32, @bitCast(i64, imm))) |small| {
4011 try self.asmMemoryImmediate(
4012 mir_tag,
4013 Memory.sib(Memory.PtrSize.fromSize(abi_size), .{
4014 .base = .rbp,
4015 .disp = -off,
4016 }),
4017 Immediate.s(small),
4018 );
4019 } else {
4020 try self.asmMemoryRegister(
4021 mir_tag,
4022 Memory.sib(Memory.PtrSize.fromSize(abi_size), .{
4023 .base = .rbp,
4024 .disp = -off,
4025 }),
4026 registerAlias(try self.copyToTmpRegister(dst_ty, src_mcv), abi_size),
4027 );
4028 }
4029 },
4030 else => return self.fail("TODO getBinOpMir implement large immediate ABI", .{}),
4031 }
3891 },4032 },
3892 .memory,4033 .memory,
3893 .stack_offset,4034 .stack_offset,
...@@ -4119,17 +4260,20 @@ fn airBreakpoint(self: *Self) !void {...@@ -4119,17 +4260,20 @@ fn airBreakpoint(self: *Self) !void {
4119}4260}
41204261
4121fn airRetAddr(self: *Self, inst: Air.Inst.Index) !void {4262fn airRetAddr(self: *Self, inst: Air.Inst.Index) !void {
4122 const result: MCValue = if (self.liveness.isUnused(inst))4263 const result = if (self.liveness.isUnused(inst)) .dead else result: {
4123 .dead4264 const dst_mcv = try self.allocRegOrMem(inst, true);
4124 else4265 try self.setRegOrMem(Type.usize, dst_mcv, .{
4125 .{ .stack_offset = -@as(i32, @divExact(self.target.cpu.arch.ptrBitWidth(), 8)) };4266 .stack_offset = -@as(i32, @divExact(self.target.cpu.arch.ptrBitWidth(), 8)),
4267 });
4268 break :result dst_mcv;
4269 };
4126 return self.finishAir(inst, result, .{ .none, .none, .none });4270 return self.finishAir(inst, result, .{ .none, .none, .none });
4127}4271}
41284272
4129fn airFrameAddress(self: *Self, inst: Air.Inst.Index) !void {4273fn airFrameAddress(self: *Self, inst: Air.Inst.Index) !void {
4130 const result = if (self.liveness.isUnused(inst)) .dead else result: {4274 const result = if (self.liveness.isUnused(inst)) .dead else result: {
4131 const dst_mcv = try self.allocRegOrMem(inst, true);4275 const dst_mcv = try self.allocRegOrMem(inst, true);
4132 try self.genBinOpMir(.mov, Type.usize, dst_mcv, .{ .register = .rbp });4276 try self.setRegOrMem(Type.usize, dst_mcv, .{ .register = .rbp });
4133 break :result dst_mcv;4277 break :result dst_mcv;
4134 };4278 };
4135 return self.finishAir(inst, result, .{ .none, .none, .none });4279 return self.finishAir(inst, result, .{ .none, .none, .none });
...@@ -5864,7 +6008,7 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void...@@ -5864,7 +6008,7 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
5864 .undef => {6008 .undef => {
5865 if (!self.wantSafety()) return; // The already existing value will do just fine.6009 if (!self.wantSafety()) return; // The already existing value will do just fine.
5866 // Write the debug undefined value.6010 // Write the debug undefined value.
5867 switch (registerAlias(reg, abi_size).bitSize()) {6011 switch (self.regBitSize(ty)) {
5868 8 => return self.genSetReg(ty, reg, .{ .immediate = 0xaa }),6012 8 => return self.genSetReg(ty, reg, .{ .immediate = 0xaa }),
5869 16 => return self.genSetReg(ty, reg, .{ .immediate = 0xaaaa }),6013 16 => return self.genSetReg(ty, reg, .{ .immediate = 0xaaaa }),
5870 32 => return self.genSetReg(ty, reg, .{ .immediate = 0xaaaaaaaa }),6014 32 => return self.genSetReg(ty, reg, .{ .immediate = 0xaaaaaaaa }),
...@@ -6763,6 +6907,27 @@ fn truncateRegister(self: *Self, ty: Type, reg: Register) !void {...@@ -6763,6 +6907,27 @@ fn truncateRegister(self: *Self, ty: Type, reg: Register) !void {
6763 }6907 }
6764}6908}
67656909
6910fn regBitSize(self: *Self, ty: Type) u64 {
6911 return switch (ty.zigTypeTag()) {
6912 else => switch (ty.abiSize(self.target.*)) {
6913 1 => 8,
6914 2 => 16,
6915 3...4 => 32,
6916 5...8 => 64,
6917 else => unreachable,
6918 },
6919 .Float => switch (ty.abiSize(self.target.*)) {
6920 1...16 => 128,
6921 17...32 => 256,
6922 else => unreachable,
6923 },
6924 };
6925}
6926
6927fn regExtraBits(self: *Self, ty: Type) u64 {
6928 return self.regBitSize(ty) - ty.bitSize(self.target.*);
6929}
6930
6766fn intrinsicsAllowed(target: Target, ty: Type) bool {6931fn intrinsicsAllowed(target: Target, ty: Type) bool {
6767 return switch (ty.tag()) {6932 return switch (ty.tag()) {
6768 .f32,6933 .f32,
src/arch/x86_64/Emit.zig+2
...@@ -95,7 +95,9 @@ pub fn lowerMir(emit: *Emit) InnerError!void {...@@ -95,7 +95,9 @@ pub fn lowerMir(emit: *Emit) InnerError!void {
95 .mov,95 .mov,
96 .movzx,96 .movzx,
97 .mul,97 .mul,
98 .neg,
98 .nop,99 .nop,
100 .not,
99 .@"or",101 .@"or",
100 .pop,102 .pop,
101 .popcnt,103 .popcnt,
src/arch/x86_64/Encoding.zig+1-1
...@@ -327,7 +327,7 @@ pub const Mnemonic = enum {...@@ -327,7 +327,7 @@ pub const Mnemonic = enum {
327 mov,327 mov,
328 movs, movsb, movsd, movsq, movsw,328 movs, movsb, movsd, movsq, movsw,
329 movsx, movsxd, movzx, mul,329 movsx, movsxd, movzx, mul,
330 nop,330 neg, nop, not,
331 @"or",331 @"or",
332 pop, popcnt, push,332 pop, popcnt, push,
333 ret,333 ret,
src/arch/x86_64/Mir.zig+4
...@@ -84,8 +84,12 @@ pub const Inst = struct {...@@ -84,8 +84,12 @@ pub const Inst = struct {
84 movzx,84 movzx,
85 /// Multiply85 /// Multiply
86 mul,86 mul,
87 /// Two's complement negation
88 neg,
87 /// No-op89 /// No-op
88 nop,90 nop,
91 /// One's complement negation
92 not,
89 /// Logical or93 /// Logical or
90 @"or",94 @"or",
91 /// Pop95 /// Pop
src/arch/x86_64/encodings.zig+12
...@@ -379,8 +379,20 @@ pub const table = &[_]Entry{...@@ -379,8 +379,20 @@ pub const table = &[_]Entry{
379 .{ .mul, .m, .rm32, .none, .none, .none, &.{ 0xf7 }, 4, .none },379 .{ .mul, .m, .rm32, .none, .none, .none, &.{ 0xf7 }, 4, .none },
380 .{ .mul, .m, .rm64, .none, .none, .none, &.{ 0xf7 }, 4, .long },380 .{ .mul, .m, .rm64, .none, .none, .none, &.{ 0xf7 }, 4, .long },
381381
382 .{ .neg, .m, .rm8, .none, .none, .none, &.{ 0xf6 }, 3, .none },
383 .{ .neg, .m, .rm8, .none, .none, .none, &.{ 0xf6 }, 3, .rex },
384 .{ .neg, .m, .rm16, .none, .none, .none, &.{ 0xf7 }, 3, .none },
385 .{ .neg, .m, .rm32, .none, .none, .none, &.{ 0xf7 }, 3, .none },
386 .{ .neg, .m, .rm64, .none, .none, .none, &.{ 0xf7 }, 3, .long },
387
382 .{ .nop, .np, .none, .none, .none, .none, &.{ 0x90 }, 0, .none },388 .{ .nop, .np, .none, .none, .none, .none, &.{ 0x90 }, 0, .none },
383389
390 .{ .not, .m, .rm8, .none, .none, .none, &.{ 0xf6 }, 2, .none },
391 .{ .not, .m, .rm8, .none, .none, .none, &.{ 0xf6 }, 2, .rex },
392 .{ .not, .m, .rm16, .none, .none, .none, &.{ 0xf7 }, 2, .none },
393 .{ .not, .m, .rm32, .none, .none, .none, &.{ 0xf7 }, 2, .none },
394 .{ .not, .m, .rm64, .none, .none, .none, &.{ 0xf7 }, 2, .long },
395
384 .{ .@"or", .zi, .al, .imm8, .none, .none, &.{ 0x0c }, 0, .none },396 .{ .@"or", .zi, .al, .imm8, .none, .none, &.{ 0x0c }, 0, .none },
385 .{ .@"or", .zi, .ax, .imm16, .none, .none, &.{ 0x0d }, 0, .none },397 .{ .@"or", .zi, .ax, .imm16, .none, .none, &.{ 0x0d }, 0, .none },
386 .{ .@"or", .zi, .eax, .imm32, .none, .none, &.{ 0x0d }, 0, .none },398 .{ .@"or", .zi, .eax, .imm32, .none, .none, &.{ 0x0d }, 0, .none },