authorgravatar for koachan@protonmail.comKoakuma <koachan@protonmail.com> 2022-05-26 20:20:48+07:00
committergravatar for koachan@protonmail.comKoakuma <koachan@protonmail.com> 2022-06-06 20:34:53+07:00
log093332c02ed828c6c24d6c7e113ae2804ba7e6f3
tree3012fb6b684e016a778c24c280be07f5af3841e9
parent38aa431e03b19897a7c3c8505f66f4305d8c29b2

stage2: sparc64: Implement condition code spilling


3 files changed, 90 insertions(+), 20 deletions(-)

src/arch/sparc64/CodeGen.zig+68-20
......@@ -131,12 +131,18 @@ const MCValue = union(enum) {
131131 stack_offset: u32,
132132 /// The value is a pointer to one of the stack variables (payload is stack offset).
133133 ptr_stack_offset: u32,
134 /// The value is in the compare flags assuming an unsigned operation,
135 /// with this operator applied on top of it.
136 compare_flags_unsigned: math.CompareOperator,
137 /// The value is in the compare flags assuming a signed operation,
138 /// with this operator applied on top of it.
139 compare_flags_signed: math.CompareOperator,
134 /// The value is in the specified CCR assuming an unsigned operation,
135 /// with the operator applied on top of it.
136 compare_flags_unsigned: struct {
137 cmp: math.CompareOperator,
138 ccr: Instruction.CCR,
139 },
140 /// The value is in the specified CCR assuming an signed operation,
141 /// with the operator applied on top of it.
142 compare_flags_signed: struct {
143 cmp: math.CompareOperator,
144 ccr: Instruction.CCR,
145 },
140146
141147 fn isMemory(mcv: MCValue) bool {
142148 return switch (mcv) {
......@@ -1086,8 +1092,8 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void {
10861092 self.compare_flags_inst = inst;
10871093
10881094 break :result switch (int_info.signedness) {
1089 .signed => MCValue{ .compare_flags_signed = op },
1090 .unsigned => MCValue{ .compare_flags_unsigned = op },
1095 .signed => MCValue{ .compare_flags_signed = .{ .cmp = op, .ccr = .xcc } },
1096 .unsigned => MCValue{ .compare_flags_unsigned = .{ .cmp = op, .ccr = .xcc } },
10911097 };
10921098 } else {
10931099 return self.fail("TODO SPARCv9 cmp for ints > 64 bits", .{});
......@@ -1113,16 +1119,20 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void {
11131119 .tag = .bpcc,
11141120 .data = .{
11151121 .branch_predict_int = .{
1116 .ccr = .xcc,
1122 .ccr = switch (cond) {
1123 .compare_flags_signed => |cmp_op| cmp_op.ccr,
1124 .compare_flags_unsigned => |cmp_op| cmp_op.ccr,
1125 else => unreachable,
1126 },
11171127 .cond = switch (cond) {
11181128 .compare_flags_signed => |cmp_op| blk: {
11191129 // Here we map to the opposite condition because the jump is to the false branch.
1120 const condition = Instruction.ICondition.fromCompareOperatorSigned(cmp_op);
1130 const condition = Instruction.ICondition.fromCompareOperatorSigned(cmp_op.cmp);
11211131 break :blk condition.negate();
11221132 },
11231133 .compare_flags_unsigned => |cmp_op| blk: {
11241134 // Here we map to the opposite condition because the jump is to the false branch.
1125 const condition = Instruction.ICondition.fromCompareOperatorUnsigned(cmp_op);
1135 const condition = Instruction.ICondition.fromCompareOperatorUnsigned(cmp_op.cmp);
11261136 break :blk condition.negate();
11271137 },
11281138 else => unreachable,
......@@ -2290,8 +2300,47 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
22902300 switch (mcv) {
22912301 .dead => unreachable,
22922302 .unreach, .none => return, // Nothing to do.
2293 .compare_flags_signed => return self.fail("TODO: genSetReg for compare_flags_signed", .{}),
2294 .compare_flags_unsigned => return self.fail("TODO: genSetReg for compare_flags_unsigned", .{}),
2303 .compare_flags_signed,
2304 .compare_flags_unsigned,
2305 => {
2306 const condition = switch (mcv) {
2307 .compare_flags_unsigned => |op| Instruction.ICondition.fromCompareOperatorUnsigned(op.cmp),
2308 .compare_flags_signed => |op| Instruction.ICondition.fromCompareOperatorSigned(op.cmp),
2309 else => unreachable,
2310 };
2311
2312 const ccr = switch (mcv) {
2313 .compare_flags_unsigned => |op| op.ccr,
2314 .compare_flags_signed => |op| op.ccr,
2315 else => unreachable,
2316 };
2317 // TODO handle floating point CCRs
2318 assert(ccr == .xcc or ccr == .icc);
2319
2320 _ = try self.addInst(.{
2321 .tag = .mov,
2322 .data = .{
2323 .arithmetic_2op = .{
2324 .is_imm = false,
2325 .rs1 = reg,
2326 .rs2_or_imm = .{ .rs2 = .g0 },
2327 },
2328 },
2329 });
2330
2331 _ = try self.addInst(.{
2332 .tag = .movcc,
2333 .data = .{
2334 .conditional_move = .{
2335 .ccr = ccr,
2336 .cond = .{ .icond = condition },
2337 .is_imm = true,
2338 .rd = reg,
2339 .rs2_or_imm = .{ .imm = 1 },
2340 },
2341 },
2342 });
2343 },
22952344 .undef => {
22962345 if (!self.wantSafety())
22972346 return; // The already existing value will do just fine.
......@@ -2644,7 +2693,7 @@ fn isErr(self: *Self, ty: Type, operand: MCValue) !MCValue {
26442693 } },
26452694 });
26462695
2647 return MCValue{ .compare_flags_unsigned = .gt };
2696 return MCValue{ .compare_flags_unsigned = .{ .cmp = .gt, .ccr = .xcc } };
26482697 } else {
26492698 return self.fail("TODO isErr for errors with size > 8", .{});
26502699 }
......@@ -2658,8 +2707,8 @@ fn isNonErr(self: *Self, ty: Type, operand: MCValue) !MCValue {
26582707 const is_err_result = try self.isErr(ty, operand);
26592708 switch (is_err_result) {
26602709 .compare_flags_unsigned => |op| {
2661 assert(op == .gt);
2662 return MCValue{ .compare_flags_unsigned = .lte };
2710 assert(op.cmp == .gt);
2711 return MCValue{ .compare_flags_unsigned = .{ .cmp = .gt, .ccr = op.ccr } };
26632712 },
26642713 .immediate => |imm| {
26652714 assert(imm == 0);
......@@ -3014,14 +3063,13 @@ fn setRegOrMem(self: *Self, ty: Type, loc: MCValue, val: MCValue) !void {
30143063fn spillCompareFlagsIfOccupied(self: *Self) !void {
30153064 if (self.compare_flags_inst) |inst_to_save| {
30163065 const mcv = self.getResolvedInstValue(inst_to_save);
3017 switch (mcv) {
3066 const new_mcv = switch (mcv) {
30183067 .compare_flags_signed,
30193068 .compare_flags_unsigned,
3020 => {},
3069 => try self.allocRegOrMem(inst_to_save, true),
30213070 else => unreachable, // mcv doesn't occupy the compare flags
3022 }
3071 };
30233072
3024 const new_mcv = try self.allocRegOrMem(inst_to_save, true);
30253073 try self.setRegOrMem(self.air.typeOfIndex(inst_to_save), new_mcv, mcv);
30263074 log.debug("spilling {d} to mcv {any}", .{ inst_to_save, new_mcv });
30273075
src/arch/sparc64/Emit.zig+2
......@@ -94,6 +94,8 @@ pub fn emitMir(
9494
9595 .@"or" => try emit.mirArithmetic3Op(inst),
9696
97 .movcc => @panic("TODO implement sparc64 movcc"),
98
9799 .mulx => try emit.mirArithmetic3Op(inst),
98100
99101 .nop => try emit.mirNop(),
src/arch/sparc64/Mir.zig+20
......@@ -74,6 +74,10 @@ pub const Inst = struct {
7474 // TODO add other operations.
7575 @"or",
7676
77 /// A.35 Move Integer Register on Condition (MOVcc)
78 /// This uses the conditional_move field.
79 movcc,
80
7781 /// A.37 Multiply and Divide (64-bit)
7882 /// This uses the arithmetic_3op field.
7983 // TODO add other operations.
......@@ -216,6 +220,22 @@ pub const Inst = struct {
216220 inst: Index,
217221 },
218222
223 /// Conditional move.
224 /// if is_imm true then it uses the imm field of rs2_or_imm,
225 /// otherwise it uses rs2 field.
226 ///
227 /// Used by e.g. movcc
228 conditional_move: struct {
229 is_imm: bool,
230 ccr: Instruction.CCR,
231 cond: Instruction.Condition,
232 rd: Register,
233 rs2_or_imm: union {
234 rs2: Register,
235 imm: i11,
236 },
237 },
238
219239 /// No additional data
220240 ///
221241 /// Used by e.g. flushw