authorgravatar for koachan@protonmail.comKoakuma <koachan@protonmail.com> 2022-06-13 00:25:24+07:00
committergravatar for koachan@protonmail.comKoakuma <koachan@protonmail.com> 2022-06-24 21:08:41+07:00
loge7fde5f64e29ad5a730f18e82485dda00f658db8
tree074f093ae025bcff4616ac78b8b62f097cf9adb6
parentaccc3bad6377394531a9ee772e1f90018d058d06

stage2: sparc64: Introduce condition_register MCValue type

Introduce condition_register MCValue type for future uses with BPr/MOVr (mostly when needing to compare a signed value with zero)

4 files changed, 98 insertions(+), 7 deletions(-)

src/arch/sparc64/CodeGen.zig+57-3
...@@ -96,6 +96,9 @@ stack: std.AutoHashMapUnmanaged(u32, StackAllocation) = .{},...@@ -96,6 +96,9 @@ stack: std.AutoHashMapUnmanaged(u32, StackAllocation) = .{},
96/// Tracks the current instruction allocated to the condition flags96/// Tracks the current instruction allocated to the condition flags
97condition_flags_inst: ?Air.Inst.Index = null,97condition_flags_inst: ?Air.Inst.Index = null,
9898
99/// Tracks the current instruction allocated to the condition register
100condition_register_inst: ?Air.Inst.Index = null,
101
99/// Offset from the stack base, representing the end of the stack frame.102/// Offset from the stack base, representing the end of the stack frame.
100max_end_stack: u32 = 0,103max_end_stack: u32 = 0,
101/// Represents the current end stack offset. If there is no existing slot104/// Represents the current end stack offset. If there is no existing slot
...@@ -148,6 +151,13 @@ const MCValue = union(enum) {...@@ -148,6 +151,13 @@ const MCValue = union(enum) {
148 cond: Instruction.Condition,151 cond: Instruction.Condition,
149 ccr: Instruction.CCR,152 ccr: Instruction.CCR,
150 },153 },
154 /// The value is in the specified Register. The value is 1 (if
155 /// the type is u1) or true (if the type in bool) iff the
156 /// specified condition is true.
157 condition_register: struct {
158 cond: Instruction.RCondition,
159 reg: Register,
160 },
151161
152 fn isMemory(mcv: MCValue) bool {162 fn isMemory(mcv: MCValue) bool {
153 return switch (mcv) {163 return switch (mcv) {
...@@ -171,6 +181,8 @@ const MCValue = union(enum) {...@@ -171,6 +181,8 @@ const MCValue = union(enum) {
171181
172 .immediate,182 .immediate,
173 .memory,183 .memory,
184 .condition_flags,
185 .condition_register,
174 .ptr_stack_offset,186 .ptr_stack_offset,
175 .undef,187 .undef,
176 => false,188 => false,
...@@ -1748,7 +1760,7 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {...@@ -1748,7 +1760,7 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {
1748 _ = try self.addInst(.{1760 _ = try self.addInst(.{
1749 .tag = .movcc,1761 .tag = .movcc,
1750 .data = .{1762 .data = .{
1751 .conditional_move = .{1763 .conditional_move_int = .{
1752 .ccr = rwo.flag.ccr,1764 .ccr = rwo.flag.ccr,
1753 .cond = .{ .icond = rwo.flag.cond },1765 .cond = .{ .icond = rwo.flag.cond },
1754 .is_imm = true,1766 .is_imm = true,
...@@ -2401,6 +2413,17 @@ fn condBr(self: *Self, condition: MCValue) !Mir.Inst.Index {...@@ -2401,6 +2413,17 @@ fn condBr(self: *Self, condition: MCValue) !Mir.Inst.Index {
2401 },2413 },
2402 },2414 },
2403 }),2415 }),
2416 .condition_register => |reg| try self.addInst(.{
2417 .tag = .bpr,
2418 .data = .{
2419 .branch_predict_reg = .{
2420 .rs1 = reg.reg,
2421 // Here we map to the opposite condition because the jump is to the false branch.
2422 .cond = reg.cond.negate(),
2423 .inst = undefined, // Will be filled by performReloc
2424 },
2425 },
2426 }),
2404 else => blk: {2427 else => blk: {
2405 const reg = switch (condition) {2428 const reg = switch (condition) {
2406 .register => |r| r,2429 .register => |r| r,
...@@ -2655,7 +2678,7 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void...@@ -2655,7 +2678,7 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
2655 _ = try self.addInst(.{2678 _ = try self.addInst(.{
2656 .tag = .movcc,2679 .tag = .movcc,
2657 .data = .{2680 .data = .{
2658 .conditional_move = .{2681 .conditional_move_int = .{
2659 .ccr = ccr,2682 .ccr = ccr,
2660 .cond = condition,2683 .cond = condition,
2661 .is_imm = true,2684 .is_imm = true,
...@@ -2665,6 +2688,34 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void...@@ -2665,6 +2688,34 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
2665 },2688 },
2666 });2689 });
2667 },2690 },
2691 .condition_register => |op| {
2692 const condition = op.cond;
2693 const register = op.reg;
2694
2695 _ = try self.addInst(.{
2696 .tag = .mov,
2697 .data = .{
2698 .arithmetic_2op = .{
2699 .is_imm = false,
2700 .rs1 = reg,
2701 .rs2_or_imm = .{ .rs2 = .g0 },
2702 },
2703 },
2704 });
2705
2706 _ = try self.addInst(.{
2707 .tag = .movr,
2708 .data = .{
2709 .conditional_move_reg = .{
2710 .cond = condition,
2711 .is_imm = true,
2712 .rd = reg,
2713 .rs1 = register,
2714 .rs2_or_imm = .{ .imm = 1 },
2715 },
2716 },
2717 });
2718 },
2668 .undef => {2719 .undef => {
2669 if (!self.wantSafety())2720 if (!self.wantSafety())
2670 return; // The already existing value will do just fine.2721 return; // The already existing value will do just fine.
...@@ -2832,6 +2883,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro...@@ -2832,6 +2883,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro
2832 }2883 }
2833 },2884 },
2834 .condition_flags,2885 .condition_flags,
2886 .condition_register,
2835 .immediate,2887 .immediate,
2836 .ptr_stack_offset,2888 .ptr_stack_offset,
2837 => {2889 => {
...@@ -2872,7 +2924,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro...@@ -2872,7 +2924,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro
2872 _ = try self.addInst(.{2924 _ = try self.addInst(.{
2873 .tag = .movcc,2925 .tag = .movcc,
2874 .data = .{2926 .data = .{
2875 .conditional_move = .{2927 .conditional_move_int = .{
2876 .ccr = rwo.flag.ccr,2928 .ccr = rwo.flag.ccr,
2877 .cond = .{ .icond = rwo.flag.cond },2929 .cond = .{ .icond = rwo.flag.cond },
2878 .is_imm = true,2930 .is_imm = true,
...@@ -3124,6 +3176,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo...@@ -3124,6 +3176,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo
3124 .unreach => unreachable,3176 .unreach => unreachable,
3125 .dead => unreachable,3177 .dead => unreachable,
3126 .condition_flags,3178 .condition_flags,
3179 .condition_register,
3127 .register_with_overflow,3180 .register_with_overflow,
3128 => unreachable, // cannot hold an address3181 => unreachable, // cannot hold an address
3129 .immediate => |imm| try self.setRegOrMem(elem_ty, dst_mcv, .{ .memory = imm }),3182 .immediate => |imm| try self.setRegOrMem(elem_ty, dst_mcv, .{ .memory = imm }),
...@@ -3475,6 +3528,7 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type...@@ -3475,6 +3528,7 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type
3475 .unreach => unreachable,3528 .unreach => unreachable,
3476 .dead => unreachable,3529 .dead => unreachable,
3477 .condition_flags,3530 .condition_flags,
3531 .condition_register,
3478 .register_with_overflow,3532 .register_with_overflow,
3479 => unreachable, // cannot hold an address3533 => unreachable, // cannot hold an address
3480 .immediate => |imm| {3534 .immediate => |imm| {
src/arch/sparc64/Emit.zig+3-1
...@@ -99,6 +99,8 @@ pub fn emitMir(...@@ -99,6 +99,8 @@ pub fn emitMir(
9999
100 .movcc => try emit.mirConditionalMove(inst),100 .movcc => try emit.mirConditionalMove(inst),
101101
102 .movr => @panic("TODO implement sparc64 movr"),
103
102 .mulx => try emit.mirArithmetic3Op(inst),104 .mulx => try emit.mirArithmetic3Op(inst),
103105
104 .nop => try emit.mirNop(),106 .nop => try emit.mirNop(),
...@@ -314,7 +316,7 @@ fn mirConditionalMove(emit: *Emit, inst: Mir.Inst.Index) !void {...@@ -314,7 +316,7 @@ fn mirConditionalMove(emit: *Emit, inst: Mir.Inst.Index) !void {
314316
315 switch (tag) {317 switch (tag) {
316 .movcc => {318 .movcc => {
317 const data = emit.mir.instructions.items(.data)[inst].conditional_move;319 const data = emit.mir.instructions.items(.data)[inst].conditional_move_int;
318 if (data.is_imm) {320 if (data.is_imm) {
319 try emit.writeInstruction(Instruction.movcc(321 try emit.writeInstruction(Instruction.movcc(
320 i11,322 i11,
src/arch/sparc64/Mir.zig+23-3
...@@ -78,9 +78,13 @@ pub const Inst = struct {...@@ -78,9 +78,13 @@ pub const Inst = struct {
78 xnor,78 xnor,
7979
80 /// A.35 Move Integer Register on Condition (MOVcc)80 /// A.35 Move Integer Register on Condition (MOVcc)
81 /// This uses the conditional_move field.81 /// This uses the conditional_move_int field.
82 movcc,82 movcc,
8383
84 /// A.36 Move Integer Register on Register Condition (MOVr)
85 /// This uses the conditional_move_reg field.
86 movr,
87
84 /// A.37 Multiply and Divide (64-bit)88 /// A.37 Multiply and Divide (64-bit)
85 /// This uses the arithmetic_3op field.89 /// This uses the arithmetic_3op field.
86 // TODO add other operations.90 // TODO add other operations.
...@@ -230,12 +234,12 @@ pub const Inst = struct {...@@ -230,12 +234,12 @@ pub const Inst = struct {
230 inst: Index,234 inst: Index,
231 },235 },
232236
233 /// Conditional move.237 /// Conditional move, checking the integer status code
234 /// if is_imm true then it uses the imm field of rs2_or_imm,238 /// if is_imm true then it uses the imm field of rs2_or_imm,
235 /// otherwise it uses rs2 field.239 /// otherwise it uses rs2 field.
236 ///240 ///
237 /// Used by e.g. movcc241 /// Used by e.g. movcc
238 conditional_move: struct {242 conditional_move_int: struct {
239 is_imm: bool,243 is_imm: bool,
240 ccr: Instruction.CCR,244 ccr: Instruction.CCR,
241 cond: Instruction.Condition,245 cond: Instruction.Condition,
...@@ -246,6 +250,22 @@ pub const Inst = struct {...@@ -246,6 +250,22 @@ pub const Inst = struct {
246 },250 },
247 },251 },
248252
253 /// Conditional move, comparing a register's content with zero
254 /// if is_imm true then it uses the imm field of rs2_or_imm,
255 /// otherwise it uses rs2 field.
256 ///
257 /// Used by e.g. movr
258 conditional_move_reg: struct {
259 is_imm: bool,
260 cond: Instruction.RCondition,
261 rd: Register,
262 rs1: Register,
263 rs2_or_imm: union {
264 rs2: Register,
265 imm: i10,
266 },
267 },
268
249 /// No additional data269 /// No additional data
250 ///270 ///
251 /// Used by e.g. flushw271 /// Used by e.g. flushw
src/arch/sparc64/bits.zig+15
...@@ -475,6 +475,21 @@ pub const Instruction = union(enum) {...@@ -475,6 +475,21 @@ pub const Instruction = union(enum) {
475 ne_zero,475 ne_zero,
476 gt_zero,476 gt_zero,
477 ge_zero,477 ge_zero,
478
479 /// Returns the condition which is true iff the given condition is
480 /// false (if such a condition exists).
481 pub fn negate(cond: RCondition) RCondition {
482 return switch (cond) {
483 .eq_zero => .ne_zero,
484 .ne_zero => .eq_zero,
485 .lt_zero => .ge_zero,
486 .ge_zero => .lt_zero,
487 .le_zero => .gt_zero,
488 .gt_zero => .le_zero,
489 .reserved1 => unreachable,
490 .reserved2 => unreachable,
491 };
492 }
478 };493 };
479494
480 pub const ASI = enum(u8) {495 pub const ASI = enum(u8) {