From 0310d88d7e6a855b3641b59c25f5b0f13726d14f Mon Sep 17 00:00:00 2001 From: Koakuma Date: Thu, 26 May 2022 13:08:39 +0700 Subject: [PATCH] stage2: sparc64: Add cmp and mov synthetic instructions --- src/arch/sparc64/CodeGen.zig | 43 ++++++++++++++++++++++-------------- src/arch/sparc64/Emit.zig | 8 +++++++ src/arch/sparc64/Mir.zig | 20 ++++++++++++++--- 3 files changed, 51 insertions(+), 20 deletions(-) diff --git a/src/arch/sparc64/CodeGen.zig b/src/arch/sparc64/CodeGen.zig index ff066f78f2..8b6bcfcb06 100644 --- a/src/arch/sparc64/CodeGen.zig +++ b/src/arch/sparc64/CodeGen.zig @@ -1677,7 +1677,7 @@ fn binOp( const mir_tag: Mir.Inst.Tag = switch (tag) { .add => .add, - .cmp_eq => .subcc, + .cmp_eq => .cmp, else => unreachable, }; @@ -1903,6 +1903,13 @@ fn binOpImmediate( .rs2_or_imm = .{ .imm = @intCast(u6, rhs.immediate) }, }, }, + .cmp => .{ + .arithmetic_2op = .{ + .is_imm = true, + .rs1 = lhs_reg, + .rs2_or_imm = .{ .imm = @intCast(i13, rhs.immediate) }, + }, + }, else => unreachable, }; @@ -2012,6 +2019,13 @@ fn binOpRegister( .rs2_or_imm = .{ .rs2 = rhs_reg }, }, }, + .cmp => .{ + .arithmetic_2op = .{ + .is_imm = false, + .rs1 = lhs_reg, + .rs2_or_imm = .{ .rs2 = rhs_reg }, + }, + }, else => unreachable, }; @@ -2303,12 +2317,11 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void .immediate => |x| { if (x <= math.maxInt(u12)) { _ = try self.addInst(.{ - .tag = .@"or", + .tag = .mov, .data = .{ - .arithmetic_3op = .{ + .arithmetic_2op = .{ .is_imm = true, - .rd = reg, - .rs1 = .g0, + .rs1 = reg, .rs2_or_imm = .{ .imm = @truncate(u12, x) }, }, }, @@ -2400,14 +2413,12 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void if (src_reg.id() == reg.id()) return; - // or %g0, src, dst (aka mov src, dst) _ = try self.addInst(.{ - .tag = .@"or", + .tag = .mov, .data = .{ - .arithmetic_3op = .{ + .arithmetic_2op = .{ .is_imm = false, - .rd = reg, - .rs1 = .g0, + .rs1 = reg, .rs2_or_imm = .{ .rs2 = src_reg }, }, }, @@ -2625,12 +2636,11 @@ fn isErr(self: *Self, ty: Type, operand: MCValue) !MCValue { }; _ = try self.addInst(.{ - .tag = .subcc, - .data = .{ .arithmetic_3op = .{ + .tag = .cmp, + .data = .{ .arithmetic_2op = .{ .is_imm = true, .rs1 = reg_mcv.register, .rs2_or_imm = .{ .imm = 0 }, - .rd = .g0, } }, }); @@ -3163,12 +3173,11 @@ fn truncRegister( }, 64 => { _ = try self.addInst(.{ - .tag = .@"or", + .tag = .mov, .data = .{ - .arithmetic_3op = .{ + .arithmetic_2op = .{ .is_imm = true, - .rd = dest_reg, - .rs1 = .g0, + .rs1 = dest_reg, .rs2_or_imm = .{ .rs2 = operand_reg }, }, }, diff --git a/src/arch/sparc64/Emit.zig b/src/arch/sparc64/Emit.zig index 6f30f785c5..dc1b4caedc 100644 --- a/src/arch/sparc64/Emit.zig +++ b/src/arch/sparc64/Emit.zig @@ -121,6 +121,10 @@ pub fn emitMir( .subcc => try emit.mirArithmetic3Op(inst), .tcc => try emit.mirTrap(inst), + + .cmp => try emit.mirArithmetic2Op(inst), + + .mov => try emit.mirArithmetic2Op(inst), } } } @@ -179,12 +183,16 @@ fn mirArithmetic2Op(emit: *Emit, inst: Mir.Inst.Index) !void { const imm = data.rs2_or_imm.imm; switch (tag) { .@"return" => try emit.writeInstruction(Instruction.@"return"(i13, rs1, imm)), + .cmp => try emit.writeInstruction(Instruction.subcc(i13, rs1, imm, .g0)), + .mov => try emit.writeInstruction(Instruction.@"or"(i13, .g0, imm, rs1)), else => unreachable, } } else { const rs2 = data.rs2_or_imm.rs2; switch (tag) { .@"return" => try emit.writeInstruction(Instruction.@"return"(Register, rs1, rs2)), + .cmp => try emit.writeInstruction(Instruction.subcc(Register, rs1, rs2, .g0)), + .mov => try emit.writeInstruction(Instruction.@"or"(Register, .g0, rs2, rs1)), else => unreachable, } } diff --git a/src/arch/sparc64/Mir.zig b/src/arch/sparc64/Mir.zig index 441e151cea..2ef66a1fa4 100644 --- a/src/arch/sparc64/Mir.zig +++ b/src/arch/sparc64/Mir.zig @@ -125,9 +125,23 @@ pub const Inst = struct { /// This uses the trap field. tcc, - // TODO add synthetic instructions - // TODO add cmp synthetic instruction to avoid wasting a register when - // comparing with subcc + // SPARCv9 synthetic instructions + // Note that the instructions that is added here are only those that + // will simplify backend development. Synthetic instructions that is + // only used to provide syntactic sugar in, e.g. inline assembly should + // be deconstructed inside the parser instead. + // See also: G.3 Synthetic Instructions + // TODO add more synthetic instructions + + /// Comparison + /// This uses the arithmetic_2op field. + cmp, // cmp rs1, rs2/imm -> subcc rs1, rs2/imm, %g0 + + /// Copy register/immediate contents to another register + /// This uses the arithmetic_2op field, with rs1 + /// being the *destination* register. + // TODO is it okay to abuse rs1 in this way? + mov, // mov rs2/imm, rs1 -> or %g0, rs2/imm, rs1 }; /// The position of an MIR instruction within the `Mir` instructions array.