authorgravatar for koachan@protonmail.comKoakuma <koachan@protonmail.com> 2022-06-12 23:24:04+07:00
committergravatar for koachan@protonmail.comKoakuma <koachan@protonmail.com> 2022-06-24 21:08:40+07:00
log8b3f7d2ad8953009ecb983dfb466ce3995a4cb38
tree772194365c6ddbc4212b2554378184ad40db7abc
parent7c87f9c828282aa12fb2d77c9c6a2318d83b8dff

stage2: sparc64: Merge the compare_flag structs into condition_flags

This follows the design in the aarch64 backend (commit 61844b6bd405b4cca3ab673284609aa6a651d506).

2 files changed, 77 insertions(+), 116 deletions(-)

src/arch/sparc64/CodeGen.zig+53-109
......@@ -93,8 +93,8 @@ register_manager: RegisterManager = .{},
9393/// Maps offset to what is stored there.
9494stack: std.AutoHashMapUnmanaged(u32, StackAllocation) = .{},
9595
96/// Tracks the current instruction allocated to the compare flags
97compare_flags_inst: ?Air.Inst.Index = null,
96/// Tracks the current instruction allocated to the condition flags
97condition_flags_inst: ?Air.Inst.Index = null,
9898
9999/// Offset from the stack base, representing the end of the stack frame.
100100max_end_stack: u32 = 0,
......@@ -141,16 +141,11 @@ const MCValue = union(enum) {
141141 stack_offset: u32,
142142 /// The value is a pointer to one of the stack variables (payload is stack offset).
143143 ptr_stack_offset: u32,
144 /// The value is in the specified CCR assuming an unsigned operation,
145 /// with the operator applied on top of it.
146 compare_flags_unsigned: struct {
147 cmp: math.CompareOperator,
148 ccr: Instruction.CCR,
149 },
150 /// The value is in the specified CCR assuming an signed operation,
151 /// with the operator applied on top of it.
152 compare_flags_signed: struct {
153 cmp: math.CompareOperator,
144 /// The value is in the specified CCR. The value is 1 (if
145 /// the type is u1) or true (if the type in bool) iff the
146 /// specified condition is true.
147 condition_flags: struct {
148 cond: Instruction.Condition,
154149 ccr: Instruction.CCR,
155150 },
156151
......@@ -738,8 +733,8 @@ fn airAddSubWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
738733 else => unreachable,
739734 };
740735
741 try self.spillCompareFlagsIfOccupied();
742 self.compare_flags_inst = inst;
736 try self.spillConditionFlagsIfOccupied();
737 self.condition_flags_inst = inst;
743738
744739 const dest = blk: {
745740 if (rhs_immediate_ok) {
......@@ -1072,7 +1067,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions.
10721067
10731068 // CCR is volatile across function calls
10741069 // (SCD 2.4.1, page 3P-10)
1075 try self.spillCompareFlagsIfOccupied();
1070 try self.spillConditionFlagsIfOccupied();
10761071
10771072 for (info.args) |mc_arg, arg_i| {
10781073 const arg = args[arg_i];
......@@ -1208,12 +1203,18 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void {
12081203 .inst = inst,
12091204 });
12101205
1211 try self.spillCompareFlagsIfOccupied();
1212 self.compare_flags_inst = inst;
1206 try self.spillConditionFlagsIfOccupied();
1207 self.condition_flags_inst = inst;
12131208
12141209 break :result switch (int_info.signedness) {
1215 .signed => MCValue{ .compare_flags_signed = .{ .cmp = op, .ccr = .xcc } },
1216 .unsigned => MCValue{ .compare_flags_unsigned = .{ .cmp = op, .ccr = .xcc } },
1210 .signed => MCValue{ .condition_flags = .{
1211 .cond = .{ .icond = Instruction.ICondition.fromCompareOperatorSigned(op) },
1212 .ccr = .xcc,
1213 } },
1214 .unsigned => MCValue{ .condition_flags = .{
1215 .cond = .{ .icond = Instruction.ICondition.fromCompareOperatorUnsigned(op) },
1216 .ccr = .xcc,
1217 } },
12171218 };
12181219 } else {
12191220 return self.fail("TODO SPARCv9 cmp for ints > 64 bits", .{});
......@@ -1224,7 +1225,7 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void {
12241225
12251226fn airCondBr(self: *Self, inst: Air.Inst.Index) !void {
12261227 const pl_op = self.air.instructions.items(.data)[inst].pl_op;
1227 const cond = try self.resolveInst(pl_op.operand);
1228 const condition = try self.resolveInst(pl_op.operand);
12281229 const extra = self.air.extraData(Air.CondBr, pl_op.payload);
12291230 const then_body = self.air.extra[extra.end..][0..extra.data.then_body_len];
12301231 const else_body = self.air.extra[extra.end + then_body.len ..][0..extra.data.else_body_len];
......@@ -1232,39 +1233,22 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void {
12321233
12331234 // Here we either emit a BPcc for branching on CCR content,
12341235 // or emit a BPr to branch on register content.
1235 const reloc: Mir.Inst.Index = switch (cond) {
1236 .compare_flags_signed,
1237 .compare_flags_unsigned,
1238 => try self.addInst(.{
1236 const reloc: Mir.Inst.Index = switch (condition) {
1237 .condition_flags => |flags| try self.addInst(.{
12391238 .tag = .bpcc,
12401239 .data = .{
12411240 .branch_predict_int = .{
1242 .ccr = switch (cond) {
1243 .compare_flags_signed => |cmp_op| cmp_op.ccr,
1244 .compare_flags_unsigned => |cmp_op| cmp_op.ccr,
1245 else => unreachable,
1246 },
1247 .cond = switch (cond) {
1248 .compare_flags_signed => |cmp_op| blk: {
1249 // Here we map to the opposite condition because the jump is to the false branch.
1250 const condition = Instruction.ICondition.fromCompareOperatorSigned(cmp_op.cmp);
1251 break :blk condition.negate();
1252 },
1253 .compare_flags_unsigned => |cmp_op| blk: {
1254 // Here we map to the opposite condition because the jump is to the false branch.
1255 const condition = Instruction.ICondition.fromCompareOperatorUnsigned(cmp_op.cmp);
1256 break :blk condition.negate();
1257 },
1258 else => unreachable,
1259 },
1241 .ccr = flags.ccr,
1242 // Here we map to the opposite condition because the jump is to the false branch.
1243 .cond = flags.cond.icond.negate(),
12601244 .inst = undefined, // Will be filled by performReloc
12611245 },
12621246 },
12631247 }),
12641248 else => blk: {
1265 const reg = switch (cond) {
1249 const reg = switch (condition) {
12661250 .register => |r| r,
1267 else => try self.copyToTmpRegister(Type.bool, cond),
1251 else => try self.copyToTmpRegister(Type.bool, condition),
12681252 };
12691253
12701254 break :blk try self.addInst(.{
......@@ -1305,7 +1289,7 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void {
13051289 var parent_stack = try self.stack.clone(self.gpa);
13061290 defer parent_stack.deinit(self.gpa);
13071291 const parent_registers = self.register_manager.registers;
1308 const parent_compare_flags_inst = self.compare_flags_inst;
1292 const parent_condition_flags_inst = self.condition_flags_inst;
13091293
13101294 try self.branch_stack.append(.{});
13111295 errdefer {
......@@ -1324,7 +1308,7 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void {
13241308 defer saved_then_branch.deinit(self.gpa);
13251309
13261310 self.register_manager.registers = parent_registers;
1327 self.compare_flags_inst = parent_compare_flags_inst;
1311 self.condition_flags_inst = parent_condition_flags_inst;
13281312
13291313 self.stack.deinit(self.gpa);
13301314 self.stack = parent_stack;
......@@ -1537,37 +1521,13 @@ fn airNot(self: *Self, inst: Air.Inst.Index) !void {
15371521 switch (operand) {
15381522 .dead => unreachable,
15391523 .unreach => unreachable,
1540 .compare_flags_unsigned => |op| {
1541 const r = MCValue{
1542 .compare_flags_unsigned = .{
1543 .cmp = switch (op.cmp) {
1544 .gte => .lt,
1545 .gt => .lte,
1546 .neq => .eq,
1547 .lt => .gte,
1548 .lte => .gt,
1549 .eq => .neq,
1550 },
1524 .condition_flags => |op| {
1525 break :result MCValue{
1526 .condition_flags = .{
1527 .cond = op.cond.negate(),
15511528 .ccr = op.ccr,
15521529 },
15531530 };
1554 break :result r;
1555 },
1556 .compare_flags_signed => |op| {
1557 const r = MCValue{
1558 .compare_flags_signed = .{
1559 .cmp = switch (op.cmp) {
1560 .gte => .lt,
1561 .gt => .lte,
1562 .neq => .eq,
1563 .lt => .gte,
1564 .lte => .gt,
1565 .eq => .neq,
1566 },
1567 .ccr = op.ccr,
1568 },
1569 };
1570 break :result r;
15711531 },
15721532 else => {
15731533 switch (operand_ty.zigTypeTag()) {
......@@ -2667,20 +2627,10 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
26672627 switch (mcv) {
26682628 .dead => unreachable,
26692629 .unreach, .none => return, // Nothing to do.
2670 .compare_flags_signed,
2671 .compare_flags_unsigned,
2672 => {
2673 const condition = switch (mcv) {
2674 .compare_flags_unsigned => |op| Instruction.ICondition.fromCompareOperatorUnsigned(op.cmp),
2675 .compare_flags_signed => |op| Instruction.ICondition.fromCompareOperatorSigned(op.cmp),
2676 else => unreachable,
2677 };
2630 .condition_flags => |op| {
2631 const condition = op.cond;
2632 const ccr = op.ccr;
26782633
2679 const ccr = switch (mcv) {
2680 .compare_flags_unsigned => |op| op.ccr,
2681 .compare_flags_signed => |op| op.ccr,
2682 else => unreachable,
2683 };
26842634 // TODO handle floating point CCRs
26852635 assert(ccr == .xcc or ccr == .icc);
26862636
......@@ -2700,7 +2650,7 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
27002650 .data = .{
27012651 .conditional_move = .{
27022652 .ccr = ccr,
2703 .cond = .{ .icond = condition },
2653 .cond = condition,
27042654 .is_imm = true,
27052655 .rd = reg,
27062656 .rs2_or_imm = .{ .imm = 1 },
......@@ -2874,8 +2824,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro
28742824 else => return self.fail("TODO implement memset", .{}),
28752825 }
28762826 },
2877 .compare_flags_unsigned,
2878 .compare_flags_signed,
2827 .condition_flags,
28792828 .immediate,
28802829 .ptr_stack_offset,
28812830 => {
......@@ -3103,7 +3052,7 @@ fn isErr(self: *Self, ty: Type, operand: MCValue) !MCValue {
31033052 } },
31043053 });
31053054
3106 return MCValue{ .compare_flags_unsigned = .{ .cmp = .gt, .ccr = .xcc } };
3055 return MCValue{ .condition_flags = .{ .cond = .{ .icond = .gu }, .ccr = .xcc } };
31073056 } else {
31083057 return self.fail("TODO isErr for errors with size > 8", .{});
31093058 }
......@@ -3116,9 +3065,8 @@ fn isNonErr(self: *Self, ty: Type, operand: MCValue) !MCValue {
31163065 // Call isErr, then negate the result.
31173066 const is_err_result = try self.isErr(ty, operand);
31183067 switch (is_err_result) {
3119 .compare_flags_unsigned => |op| {
3120 assert(op.cmp == .gt);
3121 return MCValue{ .compare_flags_unsigned = .{ .cmp = .lte, .ccr = op.ccr } };
3068 .condition_flags => |op| {
3069 return MCValue{ .condition_flags = .{ .cond = op.cond.negate(), .ccr = op.ccr } };
31223070 },
31233071 .immediate => |imm| {
31243072 assert(imm == 0);
......@@ -3168,8 +3116,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo
31683116 .undef => unreachable,
31693117 .unreach => unreachable,
31703118 .dead => unreachable,
3171 .compare_flags_unsigned,
3172 .compare_flags_signed,
3119 .condition_flags,
31733120 .register_with_overflow,
31743121 => unreachable, // cannot hold an address
31753122 .immediate => |imm| try self.setRegOrMem(elem_ty, dst_mcv, .{ .memory = imm }),
......@@ -3181,7 +3128,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo
31813128 switch (dst_mcv) {
31823129 .dead => unreachable,
31833130 .undef => unreachable,
3184 .compare_flags_signed, .compare_flags_unsigned => unreachable,
3131 .condition_flags => unreachable,
31853132 .register => |dst_reg| {
31863133 try self.genLoad(dst_reg, addr_reg, i13, 0, elem_size);
31873134 },
......@@ -3277,10 +3224,10 @@ fn processDeath(self: *Self, inst: Air.Inst.Index) void {
32773224 },
32783225 .register_with_overflow => |rwo| {
32793226 self.register_manager.freeReg(rwo.reg);
3280 self.compare_flags_inst = null;
3227 self.condition_flags_inst = null;
32813228 },
3282 .compare_flags_signed, .compare_flags_unsigned => {
3283 self.compare_flags_inst = null;
3229 .condition_flags => {
3230 self.condition_flags_inst = null;
32843231 },
32853232 else => {}, // TODO process stack allocation death
32863233 }
......@@ -3474,15 +3421,13 @@ fn setRegOrMem(self: *Self, ty: Type, loc: MCValue, val: MCValue) !void {
34743421 }
34753422}
34763423
3477/// Save the current instruction stored in the compare flags if
3424/// Save the current instruction stored in the condition flags if
34783425/// occupied
3479fn spillCompareFlagsIfOccupied(self: *Self) !void {
3480 if (self.compare_flags_inst) |inst_to_save| {
3426fn spillConditionFlagsIfOccupied(self: *Self) !void {
3427 if (self.condition_flags_inst) |inst_to_save| {
34813428 const mcv = self.getResolvedInstValue(inst_to_save);
34823429 const new_mcv = switch (mcv) {
3483 .compare_flags_signed,
3484 .compare_flags_unsigned,
3485 => try self.allocRegOrMem(inst_to_save, true),
3430 .condition_flags => try self.allocRegOrMem(inst_to_save, true),
34863431 .register_with_overflow => try self.allocRegOrMem(inst_to_save, false),
34873432 else => unreachable, // mcv doesn't occupy the compare flags
34883433 };
......@@ -3493,7 +3438,7 @@ fn spillCompareFlagsIfOccupied(self: *Self) !void {
34933438 const branch = &self.branch_stack.items[self.branch_stack.items.len - 1];
34943439 try branch.inst_table.put(self.gpa, inst_to_save, new_mcv);
34953440
3496 self.compare_flags_inst = null;
3441 self.condition_flags_inst = null;
34973442
34983443 // TODO consolidate with register manager and spillInstruction
34993444 // this call should really belong in the register manager!
......@@ -3522,8 +3467,7 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type
35223467 .undef => unreachable,
35233468 .unreach => unreachable,
35243469 .dead => unreachable,
3525 .compare_flags_unsigned,
3526 .compare_flags_signed,
3470 .condition_flags,
35273471 .register_with_overflow,
35283472 => unreachable, // cannot hold an address
35293473 .immediate => |imm| {
src/arch/sparc64/bits.zig+24-7
......@@ -673,10 +673,27 @@ pub const Instruction = union(enum) {
673673 }
674674 };
675675
676 pub const Condition = packed union {
676 pub const ConditionTag = enum { fcond, icond };
677 pub const Condition = union(ConditionTag) {
677678 fcond: FCondition,
678679 icond: ICondition,
679 encoded: u4,
680
681 /// Encodes the condition into the instruction bit pattern.
682 pub fn enc(cond: Condition) u4 {
683 return switch (cond) {
684 .icond => |c| @enumToInt(c),
685 .fcond => |c| @enumToInt(c),
686 };
687 }
688
689 /// Returns the condition which is true iff the given condition is
690 /// false (if such a condition exists).
691 pub fn negate(cond: Condition) Condition {
692 return switch (cond) {
693 .icond => |c| .{ .icond = c.negate() },
694 .fcond => |c| .{ .fcond = c.negate() },
695 };
696 }
680697 };
681698
682699 pub fn toU32(self: Instruction) u32 {
......@@ -755,7 +772,7 @@ pub const Instruction = union(enum) {
755772 return Instruction{
756773 .format_2b = .{
757774 .a = @boolToInt(annul),
758 .cond = cond.encoded,
775 .cond = cond.enc(),
759776 .op2 = op2,
760777 .disp22 = udisp_truncated,
761778 },
......@@ -776,7 +793,7 @@ pub const Instruction = union(enum) {
776793 return Instruction{
777794 .format_2c = .{
778795 .a = @boolToInt(annul),
779 .cond = cond.encoded,
796 .cond = cond.enc(),
780797 .op2 = op2,
781798 .cc1 = ccr_cc1,
782799 .cc0 = ccr_cc0,
......@@ -1057,7 +1074,7 @@ pub const Instruction = union(enum) {
10571074 .rd = rd.enc(),
10581075 .op3 = op3,
10591076 .cc2 = ccr_cc2,
1060 .cond = cond.encoded,
1077 .cond = cond.enc(),
10611078 .cc1 = ccr_cc1,
10621079 .cc0 = ccr_cc0,
10631080 .rs2 = rs2.enc(),
......@@ -1074,7 +1091,7 @@ pub const Instruction = union(enum) {
10741091 .rd = rd.enc(),
10751092 .op3 = op3,
10761093 .cc2 = ccr_cc2,
1077 .cond = cond.encoded,
1094 .cond = cond.enc(),
10781095 .cc1 = ccr_cc1,
10791096 .cc0 = ccr_cc0,
10801097 .simm11 = @bitCast(u11, imm),
......@@ -1122,7 +1139,7 @@ pub const Instruction = union(enum) {
11221139 .format_4g = .{
11231140 .rd = rd.enc(),
11241141 .op3 = op3,
1125 .cond = cond.encoded,
1142 .cond = cond.enc(),
11261143 .opf_cc = opf_cc,
11271144 .opf_low = opf_low,
11281145 .rs2 = rs2.enc(),