diff options
| author | Koakuma <koachan@protonmail.com> | 2022-06-21 23:19:09 +0700 |
|---|---|---|
| committer | Koakuma <koachan@protonmail.com> | 2022-06-24 21:19:33 +0700 |
| commit | 65c5ef52e94323e15005cb943cd98b929119ce39 (patch) | |
| tree | d3615fced8c6f423282a269bff6a6537508eafe2 /src | |
| parent | 27adee3f12f1940a16e5042b7172ed61c32b1e76 (diff) | |
| download | zig-65c5ef52e94323e15005cb943cd98b929119ce39.tar.gz zig-65c5ef52e94323e15005cb943cd98b929119ce39.zip | |
stage2: sparc64: Implement airRem, airMod, and SPARCv9 s/udivx
Diffstat (limited to 'src')
| -rw-r--r-- | src/arch/sparc64/CodeGen.zig | 208 | ||||
| -rw-r--r-- | src/arch/sparc64/Emit.zig | 6 | ||||
| -rw-r--r-- | src/arch/sparc64/Mir.zig | 3 | ||||
| -rw-r--r-- | src/arch/sparc64/bits.zig | 16 |
4 files changed, 229 insertions, 4 deletions
diff --git a/src/arch/sparc64/CodeGen.zig b/src/arch/sparc64/CodeGen.zig index 4adbfdebc9..a28cb0002c 100644 --- a/src/arch/sparc64/CodeGen.zig +++ b/src/arch/sparc64/CodeGen.zig @@ -507,8 +507,8 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { .mul => @panic("TODO try self.airMul(inst)"), .mulwrap => @panic("TODO try self.airMulWrap(inst)"), .mul_sat => @panic("TODO try self.airMulSat(inst)"), - .rem => @panic("TODO try self.airRem(inst)"), - .mod => @panic("TODO try self.airMod(inst)"), + .rem => try self.airRem(inst), + .mod => try self.airMod(inst), .shl, .shl_exact => @panic("TODO try self.airShl(inst)"), .shl_sat => @panic("TODO try self.airShlSat(inst)"), .min => @panic("TODO try self.airMin(inst)"), @@ -1602,6 +1602,144 @@ fn airMemset(self: *Self, inst: Air.Inst.Index) !void { return self.fail("TODO implement airMemset for {}", .{self.target.cpu.arch}); } +fn airMod(self: *Self, inst: Air.Inst.Index) !void { + const bin_op = self.air.instructions.items(.data)[inst].bin_op; + const lhs = try self.resolveInst(bin_op.lhs); + const rhs = try self.resolveInst(bin_op.rhs); + const lhs_ty = self.air.typeOf(bin_op.lhs); + const rhs_ty = self.air.typeOf(bin_op.rhs); + assert(lhs_ty.eql(rhs_ty, self.bin_file.options.module.?)); + + if (self.liveness.isUnused(inst)) + return self.finishAir(inst, .dead, .{ bin_op.lhs, bin_op.rhs, .none }); + + // TODO add safety check + + // We use manual assembly emission to generate faster code + // First, ensure lhs, rhs, rem, and added are in registers + + const lhs_is_register = lhs == .register; + const rhs_is_register = rhs == .register; + + const lhs_reg = if (lhs_is_register) + lhs.register + else + try self.register_manager.allocReg(null, gp); + + const lhs_lock = self.register_manager.lockReg(lhs_reg); + defer if (lhs_lock) |reg| self.register_manager.unlockReg(reg); + + const rhs_reg = if (rhs_is_register) + rhs.register + else + try self.register_manager.allocReg(null, gp); + const rhs_lock = self.register_manager.lockReg(rhs_reg); + defer if (rhs_lock) |reg| self.register_manager.unlockReg(reg); + + if (!lhs_is_register) try self.genSetReg(lhs_ty, lhs_reg, lhs); + if (!rhs_is_register) try self.genSetReg(rhs_ty, rhs_reg, rhs); + + const regs = try self.register_manager.allocRegs(2, .{ null, null }, gp); + const regs_locks = self.register_manager.lockRegsAssumeUnused(2, regs); + defer for (regs_locks) |reg| { + self.register_manager.unlockReg(reg); + }; + + const add_reg = regs[0]; + const mod_reg = regs[1]; + + // mod_reg = @rem(lhs_reg, rhs_reg) + _ = try self.addInst(.{ + .tag = .sdivx, + .data = .{ + .arithmetic_3op = .{ + .is_imm = false, + .rd = mod_reg, + .rs1 = lhs_reg, + .rs2_or_imm = .{ .rs2 = rhs_reg }, + }, + }, + }); + + _ = try self.addInst(.{ + .tag = .mulx, + .data = .{ + .arithmetic_3op = .{ + .is_imm = false, + .rd = mod_reg, + .rs1 = mod_reg, + .rs2_or_imm = .{ .rs2 = rhs_reg }, + }, + }, + }); + + _ = try self.addInst(.{ + .tag = .sub, + .data = .{ + .arithmetic_3op = .{ + .is_imm = false, + .rd = mod_reg, + .rs1 = lhs_reg, + .rs2_or_imm = .{ .rs2 = mod_reg }, + }, + }, + }); + + // add_reg = mod_reg + rhs_reg + _ = try self.addInst(.{ + .tag = .add, + .data = .{ + .arithmetic_3op = .{ + .is_imm = false, + .rd = add_reg, + .rs1 = mod_reg, + .rs2_or_imm = .{ .rs2 = rhs_reg }, + }, + }, + }); + + // if (add_reg == rhs_reg) add_reg = 0 + _ = try self.addInst(.{ + .tag = .cmp, + .data = .{ + .arithmetic_2op = .{ + .is_imm = false, + .rs1 = add_reg, + .rs2_or_imm = .{ .rs2 = rhs_reg }, + }, + }, + }); + + _ = try self.addInst(.{ + .tag = .movcc, + .data = .{ + .conditional_move_int = .{ + .is_imm = true, + .ccr = .xcc, + .cond = .{ .icond = .eq }, + .rd = add_reg, + .rs2_or_imm = .{ .imm = 0 }, + }, + }, + }); + + // if (lhs_reg < 0) mod_reg = add_reg + _ = try self.addInst(.{ + .tag = .movr, + .data = .{ + .conditional_move_reg = .{ + .is_imm = false, + .cond = .lt_zero, + .rd = mod_reg, + .rs1 = lhs_reg, + .rs2_or_imm = .{ .rs2 = add_reg }, + }, + }, + }); + + return self.finishAir(inst, .{ .register = mod_reg }, .{ bin_op.lhs, bin_op.rhs, .none }); +} + fn airNot(self: *Self, inst: Air.Inst.Index) !void { const ty_op = self.air.instructions.items(.data)[inst].ty_op; const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { @@ -1704,6 +1842,27 @@ fn airPtrElemPtr(self: *Self, inst: Air.Inst.Index) !void { return self.finishAir(inst, result, .{ extra.lhs, extra.rhs, .none }); } +fn airRem(self: *Self, inst: Air.Inst.Index) !void { + const bin_op = self.air.instructions.items(.data)[inst].bin_op; + const lhs = try self.resolveInst(bin_op.lhs); + const rhs = try self.resolveInst(bin_op.rhs); + const lhs_ty = self.air.typeOf(bin_op.lhs); + const rhs_ty = self.air.typeOf(bin_op.rhs); + + // TODO add safety check + + // result = lhs - @divTrunc(lhs, rhs) * rhs + const result: MCValue = if (self.liveness.isUnused(inst)) blk: { + break :blk .dead; + } else blk: { + const tmp0 = try self.binOp(.div_trunc, lhs, rhs, lhs_ty, rhs_ty, null); + const tmp1 = try self.binOp(.mul, tmp0, rhs, lhs_ty, rhs_ty, null); + break :blk try self.binOp(.sub, lhs, tmp1, lhs_ty, rhs_ty, null); + }; + + return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); +} + fn airRet(self: *Self, inst: Air.Inst.Index) !void { const un_op = self.air.instructions.items(.data)[inst].un_op; const operand = try self.resolveInst(un_op); @@ -2077,7 +2236,10 @@ fn binOp( ) InnerError!MCValue { const mod = self.bin_file.options.module.?; switch (tag) { - .add, .cmp_eq => { + .add, + .sub, + .cmp_eq, + => { switch (lhs_ty.zigTypeTag()) { .Float => return self.fail("TODO binary operations on floats", .{}), .Vector => return self.fail("TODO binary operations on vectors", .{}), @@ -2103,6 +2265,7 @@ fn binOp( const mir_tag: Mir.Inst.Tag = switch (tag) { .add => .add, + .sub => .sub, .cmp_eq => .cmp, else => unreachable, }; @@ -2124,6 +2287,39 @@ fn binOp( } }, + .div_trunc => { + switch (lhs_ty.zigTypeTag()) { + .Vector => return self.fail("TODO binary operations on vectors", .{}), + .Int => { + assert(lhs_ty.eql(rhs_ty, mod)); + const int_info = lhs_ty.intInfo(self.target.*); + if (int_info.bits <= 64) { + const rhs_immediate_ok = switch (tag) { + .div_trunc => rhs == .immediate and rhs.immediate <= std.math.maxInt(u12), + else => unreachable, + }; + + const mir_tag: Mir.Inst.Tag = switch (tag) { + .div_trunc => switch (int_info.signedness) { + .signed => Mir.Inst.Tag.sdivx, + .unsigned => Mir.Inst.Tag.udivx, + }, + else => unreachable, + }; + + if (rhs_immediate_ok) { + return try self.binOpImmediate(mir_tag, lhs, rhs, lhs_ty, true, metadata); + } else { + return try self.binOpRegister(mir_tag, lhs, rhs, lhs_ty, rhs_ty, metadata); + } + } else { + return self.fail("TODO binary operations on int with bits > 64", .{}); + } + }, + else => unreachable, + } + }, + .mul => { switch (lhs_ty.zigTypeTag()) { .Vector => return self.fail("TODO binary operations on vectors", .{}), @@ -2382,6 +2578,9 @@ fn binOpImmediate( .xor, .xnor, .mulx, + .sdivx, + .udivx, + .sub, .subcc, => .{ .arithmetic_3op = .{ @@ -2503,6 +2702,9 @@ fn binOpRegister( .xor, .xnor, .mulx, + .sdivx, + .udivx, + .sub, .subcc, => .{ .arithmetic_3op = .{ diff --git a/src/arch/sparc64/Emit.zig b/src/arch/sparc64/Emit.zig index 44680c2e12..937431afae 100644 --- a/src/arch/sparc64/Emit.zig +++ b/src/arch/sparc64/Emit.zig @@ -105,6 +105,8 @@ pub fn emitMir( .movr => @panic("TODO implement sparc64 movr"), .mulx => try emit.mirArithmetic3Op(inst), + .sdivx => try emit.mirArithmetic3Op(inst), + .udivx => try emit.mirArithmetic3Op(inst), .nop => try emit.mirNop(), @@ -234,6 +236,8 @@ fn mirArithmetic3Op(emit: *Emit, inst: Mir.Inst.Index) !void { .xor => try emit.writeInstruction(Instruction.xor(i13, rs1, imm, rd)), .xnor => try emit.writeInstruction(Instruction.xnor(i13, rs1, imm, rd)), .mulx => try emit.writeInstruction(Instruction.mulx(i13, rs1, imm, rd)), + .sdivx => try emit.writeInstruction(Instruction.sdivx(i13, rs1, imm, rd)), + .udivx => try emit.writeInstruction(Instruction.udivx(i13, rs1, imm, rd)), .save => try emit.writeInstruction(Instruction.save(i13, rs1, imm, rd)), .restore => try emit.writeInstruction(Instruction.restore(i13, rs1, imm, rd)), .stb => try emit.writeInstruction(Instruction.stb(i13, rs1, imm, rd)), @@ -259,6 +263,8 @@ fn mirArithmetic3Op(emit: *Emit, inst: Mir.Inst.Index) !void { .xor => try emit.writeInstruction(Instruction.xor(Register, rs1, rs2, rd)), .xnor => try emit.writeInstruction(Instruction.xnor(Register, rs1, rs2, rd)), .mulx => try emit.writeInstruction(Instruction.mulx(Register, rs1, rs2, rd)), + .sdivx => try emit.writeInstruction(Instruction.sdivx(Register, rs1, rs2, rd)), + .udivx => try emit.writeInstruction(Instruction.udivx(Register, rs1, rs2, rd)), .save => try emit.writeInstruction(Instruction.save(Register, rs1, rs2, rd)), .restore => try emit.writeInstruction(Instruction.restore(Register, rs1, rs2, rd)), .stb => try emit.writeInstruction(Instruction.stb(Register, rs1, rs2, rd)), diff --git a/src/arch/sparc64/Mir.zig b/src/arch/sparc64/Mir.zig index 3ae84d0961..52dba34e56 100644 --- a/src/arch/sparc64/Mir.zig +++ b/src/arch/sparc64/Mir.zig @@ -92,8 +92,9 @@ pub const Inst = struct { /// A.37 Multiply and Divide (64-bit) /// This uses the arithmetic_3op field. - // TODO add other operations. mulx, + sdivx, + udivx, /// A.40 No Operation /// This uses the nop field. diff --git a/src/arch/sparc64/bits.zig b/src/arch/sparc64/bits.zig index a722d06dee..4c1a641d45 100644 --- a/src/arch/sparc64/bits.zig +++ b/src/arch/sparc64/bits.zig @@ -1281,6 +1281,22 @@ pub const Instruction = union(enum) { }; } + pub fn sdivx(comptime s2: type, rs1: Register, rs2: s2, rd: Register) Instruction { + return switch (s2) { + Register => format3a(0b10, 0b10_1101, rs1, rs2, rd), + i13 => format3b(0b10, 0b10_1101, rs1, rs2, rd), + else => unreachable, + }; + } + + pub fn udivx(comptime s2: type, rs1: Register, rs2: s2, rd: Register) Instruction { + return switch (s2) { + Register => format3a(0b10, 0b00_1101, rs1, rs2, rd), + i13 => format3b(0b10, 0b00_1101, rs1, rs2, rd), + else => unreachable, + }; + } + pub fn nop() Instruction { return sethi(0, .g0); } |
