authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-05-25 17:18:43+02:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-05-25 17:18:43+02:00
log7000395a7d002a6d242d717de60614516f4e29af
treec78a0a7480d91d5e0d512265358b8a6b4dda1a21
parent5fb7070642b660a83a2333a23d9163032f0dfcb9

x64: use new condition codes enum for register with overflow mcv


1 files changed, 55 insertions(+), 82 deletions(-)

src/arch/x86_64/CodeGen.zig+55-82
...@@ -128,12 +128,8 @@ pub const MCValue = union(enum) {...@@ -128,12 +128,8 @@ pub const MCValue = union(enum) {
128 immediate: u64,128 immediate: u64,
129 /// The value is in a GP register.129 /// The value is in a GP register.
130 register: Register,130 register: Register,
131 /// The value is a tuple { wrapped, overflow } where wrapped value is stored in the GP register,131 /// The value is a tuple { wrapped, overflow } where wrapped value is stored in the GP register.
132 /// and the operation is an unsigned operation.132 register_overflow: struct { reg: Register, eflags: Condition },
133 register_overflow_unsigned: Register,
134 /// The value is a tuple { wrapped, overflow } where wrapped value is stored in the GP register,
135 /// and the operation is a signed operation.
136 register_overflow_signed: Register,
137 /// The value is in memory at a hard-coded address.133 /// The value is in memory at a hard-coded address.
138 /// If the type is a pointer, it means the pointer address is at this memory location.134 /// If the type is a pointer, it means the pointer address is at this memory location.
139 memory: u64,135 memory: u64,
...@@ -183,8 +179,7 @@ pub const MCValue = union(enum) {...@@ -183,8 +179,7 @@ pub const MCValue = union(enum) {
183 .eflags,179 .eflags,
184 .ptr_stack_offset,180 .ptr_stack_offset,
185 .undef,181 .undef,
186 .register_overflow_unsigned,182 .register_overflow,
187 .register_overflow_signed,
188 => false,183 => false,
189184
190 .register,185 .register,
...@@ -774,8 +769,8 @@ fn processDeath(self: *Self, inst: Air.Inst.Index) void {...@@ -774,8 +769,8 @@ fn processDeath(self: *Self, inst: Air.Inst.Index) void {
774 .register => |reg| {769 .register => |reg| {
775 self.register_manager.freeReg(reg.to64());770 self.register_manager.freeReg(reg.to64());
776 },771 },
777 .register_overflow_signed, .register_overflow_unsigned => |reg| {772 .register_overflow => |ro| {
778 self.register_manager.freeReg(reg.to64());773 self.register_manager.freeReg(ro.reg.to64());
779 self.eflags_inst = null;774 self.eflags_inst = null;
780 },775 },
781 .eflags => {776 .eflags => {
...@@ -809,20 +804,22 @@ fn finishAir(self: *Self, inst: Air.Inst.Index, result: MCValue, operands: [Live...@@ -809,20 +804,22 @@ fn finishAir(self: *Self, inst: Air.Inst.Index, result: MCValue, operands: [Live
809 const branch = &self.branch_stack.items[self.branch_stack.items.len - 1];804 const branch = &self.branch_stack.items[self.branch_stack.items.len - 1];
810 branch.inst_table.putAssumeCapacityNoClobber(inst, result);805 branch.inst_table.putAssumeCapacityNoClobber(inst, result);
811806
807 // In some cases (such as bitcast), an operand
808 // may be the same MCValue as the result. If
809 // that operand died and was a register, it
810 // was freed by processDeath. We have to
811 // "re-allocate" the register.
812 switch (result) {812 switch (result) {
813 .register,813 .register => |reg| {
814 .register_overflow_signed,
815 .register_overflow_unsigned,
816 => |reg| {
817 // In some cases (such as bitcast), an operand
818 // may be the same MCValue as the result. If
819 // that operand died and was a register, it
820 // was freed by processDeath. We have to
821 // "re-allocate" the register.
822 if (self.register_manager.isRegFree(reg)) {814 if (self.register_manager.isRegFree(reg)) {
823 self.register_manager.getRegAssumeFree(reg, inst);815 self.register_manager.getRegAssumeFree(reg, inst);
824 }816 }
825 },817 },
818 .register_overflow => |ro| {
819 if (self.register_manager.isRegFree(ro.reg)) {
820 self.register_manager.getRegAssumeFree(ro.reg, inst);
821 }
822 },
826 else => {},823 else => {},
827 }824 }
828 }825 }
...@@ -912,12 +909,12 @@ pub fn spillInstruction(self: *Self, reg: Register, inst: Air.Inst.Index) !void...@@ -912,12 +909,12 @@ pub fn spillInstruction(self: *Self, reg: Register, inst: Air.Inst.Index) !void
912 log.debug("spilling {d} to stack mcv {any}", .{ inst, stack_mcv });909 log.debug("spilling {d} to stack mcv {any}", .{ inst, stack_mcv });
913 const reg_mcv = self.getResolvedInstValue(inst);910 const reg_mcv = self.getResolvedInstValue(inst);
914 switch (reg_mcv) {911 switch (reg_mcv) {
915 .register,912 .register => |other| {
916 .register_overflow_unsigned,
917 .register_overflow_signed,
918 => |other| {
919 assert(reg.to64() == other.to64());913 assert(reg.to64() == other.to64());
920 },914 },
915 .register_overflow => |ro| {
916 assert(reg.to64() == ro.reg.to64());
917 },
921 else => {},918 else => {},
922 }919 }
923 const branch = &self.branch_stack.items[self.branch_stack.items.len - 1];920 const branch = &self.branch_stack.items[self.branch_stack.items.len - 1];
...@@ -929,9 +926,7 @@ pub fn spillEflagsIfOccupied(self: *Self) !void {...@@ -929,9 +926,7 @@ pub fn spillEflagsIfOccupied(self: *Self) !void {
929 if (self.eflags_inst) |inst_to_save| {926 if (self.eflags_inst) |inst_to_save| {
930 const mcv = self.getResolvedInstValue(inst_to_save);927 const mcv = self.getResolvedInstValue(inst_to_save);
931 const new_mcv = switch (mcv) {928 const new_mcv = switch (mcv) {
932 .register_overflow_signed,929 .register_overflow => try self.allocRegOrMem(inst_to_save, false),
933 .register_overflow_unsigned,
934 => try self.allocRegOrMem(inst_to_save, false),
935 .eflags => try self.allocRegOrMem(inst_to_save, true),930 .eflags => try self.allocRegOrMem(inst_to_save, true),
936 else => unreachable,931 else => unreachable,
937 };932 };
...@@ -947,9 +942,7 @@ pub fn spillEflagsIfOccupied(self: *Self) !void {...@@ -947,9 +942,7 @@ pub fn spillEflagsIfOccupied(self: *Self) !void {
947 // TODO consolidate with register manager and spillInstruction942 // TODO consolidate with register manager and spillInstruction
948 // this call should really belong in the register manager!943 // this call should really belong in the register manager!
949 switch (mcv) {944 switch (mcv) {
950 .register_overflow_signed,945 .register_overflow => |ro| self.register_manager.freeReg(ro.reg),
951 .register_overflow_unsigned,
952 => |reg| self.register_manager.freeReg(reg),
953 else => {},946 else => {},
954 }947 }
955 }948 }
...@@ -1339,11 +1332,14 @@ fn airAddSubShlWithOverflow(self: *Self, inst: Air.Inst.Index) !void {...@@ -1339,11 +1332,14 @@ fn airAddSubShlWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
1339 if (math.isPowerOfTwo(int_info.bits) and int_info.bits >= 8) {1332 if (math.isPowerOfTwo(int_info.bits) and int_info.bits >= 8) {
1340 self.eflags_inst = inst;1333 self.eflags_inst = inst;
13411334
1342 const result: MCValue = switch (int_info.signedness) {1335 const cc: Condition = switch (int_info.signedness) {
1343 .signed => .{ .register_overflow_signed = partial.register },1336 .unsigned => .c,
1344 .unsigned => .{ .register_overflow_unsigned = partial.register },1337 .signed => .o,
1345 };1338 };
1346 break :result result;1339 break :result MCValue{ .register_overflow = .{
1340 .reg = partial.register,
1341 .eflags = cc,
1342 } };
1347 }1343 }
13481344
1349 self.eflags_inst = null;1345 self.eflags_inst = null;
...@@ -1460,10 +1456,14 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {...@@ -1460,10 +1456,14 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
1460 const rhs = try self.resolveInst(bin_op.rhs);1456 const rhs = try self.resolveInst(bin_op.rhs);
14611457
1462 const partial = try self.genMulDivBinOp(.mul, null, ty, lhs, rhs);1458 const partial = try self.genMulDivBinOp(.mul, null, ty, lhs, rhs);
1463 break :result switch (int_info.signedness) {1459 const cc: Condition = switch (int_info.signedness) {
1464 .signed => MCValue{ .register_overflow_signed = partial.register },1460 .unsigned => .c,
1465 .unsigned => MCValue{ .register_overflow_unsigned = partial.register },1461 .signed => .o,
1466 };1462 };
1463 break :result MCValue{ .register_overflow = .{
1464 .reg = partial.register,
1465 .eflags = cc,
1466 } };
1467 }1467 }
14681468
1469 try self.spillEflagsIfOccupied();1469 try self.spillEflagsIfOccupied();
...@@ -2486,8 +2486,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo...@@ -2486,8 +2486,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo
2486 .unreach => unreachable,2486 .unreach => unreachable,
2487 .dead => unreachable,2487 .dead => unreachable,
2488 .eflags => unreachable,2488 .eflags => unreachable,
2489 .register_overflow_unsigned => unreachable,2489 .register_overflow => unreachable,
2490 .register_overflow_signed => unreachable,
2491 .immediate => |imm| {2490 .immediate => |imm| {
2492 try self.setRegOrMem(elem_ty, dst_mcv, .{ .memory = imm });2491 try self.setRegOrMem(elem_ty, dst_mcv, .{ .memory = imm });
2493 },2492 },
...@@ -2610,8 +2609,7 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type...@@ -2610,8 +2609,7 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type
2610 .unreach => unreachable,2609 .unreach => unreachable,
2611 .dead => unreachable,2610 .dead => unreachable,
2612 .eflags => unreachable,2611 .eflags => unreachable,
2613 .register_overflow_unsigned => unreachable,2612 .register_overflow => unreachable,
2614 .register_overflow_signed => unreachable,
2615 .immediate => |imm| {2613 .immediate => |imm| {
2616 try self.setRegOrMem(value_ty, .{ .memory = imm }, value);2614 try self.setRegOrMem(value_ty, .{ .memory = imm }, value);
2617 },2615 },
...@@ -2997,31 +2995,24 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {...@@ -2997,31 +2995,24 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {
29972995
2998 break :result dst_mcv;2996 break :result dst_mcv;
2999 },2997 },
3000 .register_overflow_unsigned,2998 .register_overflow => |ro| {
3001 .register_overflow_signed,
3002 => |reg| {
3003 switch (index) {2999 switch (index) {
3004 0 => {3000 0 => {
3005 // Get wrapped value for overflow operation.3001 // Get wrapped value for overflow operation.
3006 break :result MCValue{ .register = reg };3002 break :result MCValue{ .register = ro.reg };
3007 },3003 },
3008 1 => {3004 1 => {
3009 // Get overflow bit.3005 // Get overflow bit.
3010 const reg_lock = self.register_manager.lockRegAssumeUnused(reg);3006 const reg_lock = self.register_manager.lockRegAssumeUnused(ro.reg);
3011 defer self.register_manager.unlockReg(reg_lock);3007 defer self.register_manager.unlockReg(reg_lock);
30123008
3013 const dst_reg = try self.register_manager.allocReg(inst, gp);3009 const dst_reg = try self.register_manager.allocReg(inst, gp);
3014 const cc: Condition = switch (mcv) {
3015 .register_overflow_unsigned => .c,
3016 .register_overflow_signed => .o,
3017 else => unreachable,
3018 };
3019 _ = try self.addInst(.{3010 _ = try self.addInst(.{
3020 .tag = .cond_set_byte,3011 .tag = .cond_set_byte,
3021 .ops = Mir.Inst.Ops.encode(.{3012 .ops = Mir.Inst.Ops.encode(.{
3022 .reg1 = dst_reg.to8(),3013 .reg1 = dst_reg.to8(),
3023 }),3014 }),
3024 .data = .{ .cc = cc },3015 .data = .{ .cc = ro.eflags },
3025 });3016 });
3026 break :result MCValue{ .register = dst_reg.to8() };3017 break :result MCValue{ .register = dst_reg.to8() };
3027 },3018 },
...@@ -3449,15 +3440,13 @@ fn genBinOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MCValu...@@ -3449,15 +3440,13 @@ fn genBinOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MCValu
3449 .undef => unreachable,3440 .undef => unreachable,
3450 .dead, .unreach, .immediate => unreachable,3441 .dead, .unreach, .immediate => unreachable,
3451 .eflags => unreachable,3442 .eflags => unreachable,
3452 .register_overflow_unsigned => unreachable,3443 .register_overflow => unreachable,
3453 .register_overflow_signed => unreachable,
3454 .register => |dst_reg| {3444 .register => |dst_reg| {
3455 switch (src_mcv) {3445 switch (src_mcv) {
3456 .none => unreachable,3446 .none => unreachable,
3457 .undef => unreachable,3447 .undef => unreachable,
3458 .dead, .unreach => unreachable,3448 .dead, .unreach => unreachable,
3459 .register_overflow_unsigned => unreachable,3449 .register_overflow => unreachable,
3460 .register_overflow_signed => unreachable,
3461 .ptr_stack_offset => {3450 .ptr_stack_offset => {
3462 const dst_reg_lock = self.register_manager.lockReg(dst_reg);3451 const dst_reg_lock = self.register_manager.lockReg(dst_reg);
3463 defer if (dst_reg_lock) |lock| self.register_manager.unlockReg(lock);3452 defer if (dst_reg_lock) |lock| self.register_manager.unlockReg(lock);
...@@ -3564,8 +3553,7 @@ fn genBinOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MCValu...@@ -3564,8 +3553,7 @@ fn genBinOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MCValu
3564 .none => unreachable,3553 .none => unreachable,
3565 .undef => unreachable,3554 .undef => unreachable,
3566 .dead, .unreach => unreachable,3555 .dead, .unreach => unreachable,
3567 .register_overflow_unsigned => unreachable,3556 .register_overflow => unreachable,
3568 .register_overflow_signed => unreachable,
3569 .register => |src_reg| {3557 .register => |src_reg| {
3570 _ = try self.addInst(.{3558 _ = try self.addInst(.{
3571 .tag = mir_tag,3559 .tag = mir_tag,
...@@ -3640,16 +3628,14 @@ fn genIntMulComplexOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: M...@@ -3640,16 +3628,14 @@ fn genIntMulComplexOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: M
3640 .dead, .unreach, .immediate => unreachable,3628 .dead, .unreach, .immediate => unreachable,
3641 .eflags => unreachable,3629 .eflags => unreachable,
3642 .ptr_stack_offset => unreachable,3630 .ptr_stack_offset => unreachable,
3643 .register_overflow_unsigned => unreachable,3631 .register_overflow => unreachable,
3644 .register_overflow_signed => unreachable,
3645 .register => |dst_reg| {3632 .register => |dst_reg| {
3646 switch (src_mcv) {3633 switch (src_mcv) {
3647 .none => unreachable,3634 .none => unreachable,
3648 .undef => try self.genSetReg(dst_ty, dst_reg, .undef),3635 .undef => try self.genSetReg(dst_ty, dst_reg, .undef),
3649 .dead, .unreach => unreachable,3636 .dead, .unreach => unreachable,
3650 .ptr_stack_offset => unreachable,3637 .ptr_stack_offset => unreachable,
3651 .register_overflow_unsigned => unreachable,3638 .register_overflow => unreachable,
3652 .register_overflow_signed => unreachable,
3653 .register => |src_reg| {3639 .register => |src_reg| {
3654 // register, register3640 // register, register
3655 _ = try self.addInst(.{3641 _ = try self.addInst(.{
...@@ -3708,8 +3694,7 @@ fn genIntMulComplexOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: M...@@ -3708,8 +3694,7 @@ fn genIntMulComplexOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: M
3708 .undef => return self.genSetStack(dst_ty, off, .undef, .{}),3694 .undef => return self.genSetStack(dst_ty, off, .undef, .{}),
3709 .dead, .unreach => unreachable,3695 .dead, .unreach => unreachable,
3710 .ptr_stack_offset => unreachable,3696 .ptr_stack_offset => unreachable,
3711 .register_overflow_unsigned => unreachable,3697 .register_overflow => unreachable,
3712 .register_overflow_signed => unreachable,
3713 .register => |src_reg| {3698 .register => |src_reg| {
3714 // copy dst to a register3699 // copy dst to a register
3715 const dst_reg = try self.copyToTmpRegister(dst_ty, dst_mcv);3700 const dst_reg = try self.copyToTmpRegister(dst_ty, dst_mcv);
...@@ -3915,8 +3900,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions....@@ -3915,8 +3900,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions.
3915 .got_load => unreachable,3900 .got_load => unreachable,
3916 .direct_load => unreachable,3901 .direct_load => unreachable,
3917 .eflags => unreachable,3902 .eflags => unreachable,
3918 .register_overflow_signed => unreachable,3903 .register_overflow => unreachable,
3919 .register_overflow_unsigned => unreachable,
3920 }3904 }
3921 }3905 }
39223906
...@@ -5291,9 +5275,7 @@ fn genSetStackArg(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerE...@@ -5291,9 +5275,7 @@ fn genSetStackArg(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerE
5291 .{ .dest_stack_base = .rsp },5275 .{ .dest_stack_base = .rsp },
5292 );5276 );
5293 },5277 },
5294 .register_overflow_unsigned,5278 .register_overflow => return self.fail("TODO genSetStackArg for register with overflow bit", .{}),
5295 .register_overflow_signed,
5296 => return self.fail("TODO genSetStackArg for register with overflow bit", .{}),
5297 .eflags => {5279 .eflags => {
5298 const reg = try self.copyToTmpRegister(ty, mcv);5280 const reg = try self.copyToTmpRegister(ty, mcv);
5299 return self.genSetStackArg(ty, stack_offset, .{ .register = reg });5281 return self.genSetStackArg(ty, stack_offset, .{ .register = reg });
...@@ -5429,29 +5411,22 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue, opts: Inl...@@ -5429,29 +5411,22 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue, opts: Inl
5429 ),5411 ),
5430 }5412 }
5431 },5413 },
5432 .register_overflow_unsigned,5414 .register_overflow => |ro| {
5433 .register_overflow_signed,5415 const reg_lock = self.register_manager.lockReg(ro.reg);
5434 => |reg| {
5435 const reg_lock = self.register_manager.lockReg(reg);
5436 defer if (reg_lock) |lock| self.register_manager.unlockReg(lock);5416 defer if (reg_lock) |lock| self.register_manager.unlockReg(lock);
54375417
5438 const wrapped_ty = ty.structFieldType(0);5418 const wrapped_ty = ty.structFieldType(0);
5439 try self.genSetStack(wrapped_ty, stack_offset, .{ .register = reg }, .{});5419 try self.genSetStack(wrapped_ty, stack_offset, .{ .register = ro.reg }, .{});
54405420
5441 const overflow_bit_ty = ty.structFieldType(1);5421 const overflow_bit_ty = ty.structFieldType(1);
5442 const overflow_bit_offset = ty.structFieldOffset(1, self.target.*);5422 const overflow_bit_offset = ty.structFieldOffset(1, self.target.*);
5443 const tmp_reg = try self.register_manager.allocReg(null, gp);5423 const tmp_reg = try self.register_manager.allocReg(null, gp);
5444 const cc: Condition = switch (mcv) {
5445 .register_overflow_unsigned => .c,
5446 .register_overflow_signed => .o,
5447 else => unreachable,
5448 };
5449 _ = try self.addInst(.{5424 _ = try self.addInst(.{
5450 .tag = .cond_set_byte,5425 .tag = .cond_set_byte,
5451 .ops = Mir.Inst.Ops.encode(.{5426 .ops = Mir.Inst.Ops.encode(.{
5452 .reg1 = tmp_reg.to8(),5427 .reg1 = tmp_reg.to8(),
5453 }),5428 }),
5454 .data = .{ .cc = cc },5429 .data = .{ .cc = ro.eflags },
5455 });5430 });
54565431
5457 return self.genSetStack(5432 return self.genSetStack(
...@@ -5956,9 +5931,7 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void...@@ -5956,9 +5931,7 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
5956 const abi_size = @intCast(u32, ty.abiSize(self.target.*));5931 const abi_size = @intCast(u32, ty.abiSize(self.target.*));
5957 switch (mcv) {5932 switch (mcv) {
5958 .dead => unreachable,5933 .dead => unreachable,
5959 .register_overflow_unsigned,5934 .register_overflow => unreachable,
5960 .register_overflow_signed,
5961 => unreachable,
5962 .ptr_stack_offset => |off| {5935 .ptr_stack_offset => |off| {
5963 if (off < std.math.minInt(i32) or off > std.math.maxInt(i32)) {5936 if (off < std.math.minInt(i32) or off > std.math.maxInt(i32)) {
5964 return self.fail("stack offset too large", .{});5937 return self.fail("stack offset too large", .{});