diff options
| -rw-r--r-- | src/arch/aarch64/CodeGen.zig | 49 | ||||
| -rw-r--r-- | src/arch/aarch64/Emit.zig | 19 | ||||
| -rw-r--r-- | src/arch/aarch64/Mir.zig | 6 | ||||
| -rw-r--r-- | src/arch/aarch64/bits.zig | 52 |
4 files changed, 111 insertions, 15 deletions
diff --git a/src/arch/aarch64/CodeGen.zig b/src/arch/aarch64/CodeGen.zig index 1a8765ac3a..911aac336f 100644 --- a/src/arch/aarch64/CodeGen.zig +++ b/src/arch/aarch64/CodeGen.zig @@ -541,7 +541,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { .mul_sat => try self.airMulSat(inst), .rem => try self.airRem(inst), .mod => try self.airMod(inst), - .shl, .shl_exact => try self.airShl(inst), + .shl, .shl_exact => try self.airBinOp(inst), .shl_sat => try self.airShlSat(inst), .min => try self.airMin(inst), .max => try self.airMax(inst), @@ -581,7 +581,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { .bit_and => try self.airBinOp(inst), .bit_or => try self.airBinOp(inst), .xor => try self.airBinOp(inst), - .shr, .shr_exact => try self.airShr(inst), + .shr, .shr_exact => try self.airBinOp(inst), .alloc => try self.airAlloc(inst), .ret_ptr => try self.airRetPtr(inst), @@ -1156,6 +1156,15 @@ fn binOpRegister( .bit_or, .bool_or, => .orr_shifted_register, + .shl, + .shl_exact, + => .lsl_register, + .shr, + .shr_exact, + => switch (lhs_ty.intInfo(self.target.*).signedness) { + .signed => Mir.Inst.Tag.asr_register, + .unsigned => Mir.Inst.Tag.lsr_register, + }, .xor => .eor_shifted_register, else => unreachable, }; @@ -1171,7 +1180,12 @@ fn binOpRegister( .imm6 = 0, .shift = .lsl, } }, - .mul => .{ .rrr = .{ + .mul, + .shl, + .shl_exact, + .shr, + .shr_exact, + => .{ .rrr = .{ .rd = dest_reg, .rn = lhs_reg, .rm = rhs_reg, @@ -1385,6 +1399,23 @@ fn binOp( else => unreachable, } }, + .shl, + .shr, + => { + switch (lhs_ty.zigTypeTag()) { + .Vector => return self.fail("TODO binary operations on vectors", .{}), + .Int => { + const int_info = lhs_ty.intInfo(self.target.*); + if (int_info.bits <= 64) { + // TODO immediate shifts + return try self.binOpRegister(tag, maybe_inst, lhs, rhs, lhs_ty, rhs_ty); + } else { + return self.fail("TODO binary operations on int with bits > 64", .{}); + } + }, + else => unreachable, + } + }, .bool_and, .bool_or, => { @@ -1514,24 +1545,12 @@ fn airMod(self: *Self, inst: Air.Inst.Index) !void { return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); } -fn airShl(self: *Self, inst: Air.Inst.Index) !void { - const bin_op = self.air.instructions.items(.data)[inst].bin_op; - const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement shl for {}", .{self.target.cpu.arch}); - return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); -} - fn airShlSat(self: *Self, inst: Air.Inst.Index) !void { const bin_op = self.air.instructions.items(.data)[inst].bin_op; const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement shl_sat for {}", .{self.target.cpu.arch}); return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); } -fn airShr(self: *Self, inst: Air.Inst.Index) !void { - const bin_op = self.air.instructions.items(.data)[inst].bin_op; - const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement shr for {}", .{self.target.cpu.arch}); - return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); -} - fn airOptionalPayload(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 return self.fail("TODO implement .optional_payload for {}", .{self.target.cpu.arch}); diff --git a/src/arch/aarch64/Emit.zig b/src/arch/aarch64/Emit.zig index 84bb559824..1a3e522e36 100644 --- a/src/arch/aarch64/Emit.zig +++ b/src/arch/aarch64/Emit.zig @@ -80,6 +80,10 @@ pub fn emitMir( .cmp_immediate => try emit.mirAddSubtractImmediate(inst), .sub_immediate => try emit.mirAddSubtractImmediate(inst), + .asr_register => try emit.mirShiftRegister(inst), + .lsl_register => try emit.mirShiftRegister(inst), + .lsr_register => try emit.mirShiftRegister(inst), + .b_cond => try emit.mirConditionalBranchImmediate(inst), .b => try emit.mirBranch(inst), @@ -469,6 +473,21 @@ fn mirAddSubtractImmediate(emit: *Emit, inst: Mir.Inst.Index) !void { } } +fn mirShiftRegister(emit: *Emit, inst: Mir.Inst.Index) !void { + const tag = emit.mir.instructions.items(.tag)[inst]; + const rrr = emit.mir.instructions.items(.data)[inst].rrr; + const rd = rrr.rd; + const rn = rrr.rn; + const rm = rrr.rm; + + switch (tag) { + .asr_register => try emit.writeInstruction(Instruction.asrv(rd, rn, rm)), + .lsl_register => try emit.writeInstruction(Instruction.lslv(rd, rn, rm)), + .lsr_register => try emit.writeInstruction(Instruction.lsrv(rd, rn, rm)), + else => unreachable, + } +} + fn mirConditionalBranchImmediate(emit: *Emit, inst: Mir.Inst.Index) !void { const tag = emit.mir.instructions.items(.tag)[inst]; const inst_cond = emit.mir.instructions.items(.data)[inst].inst_cond; diff --git a/src/arch/aarch64/Mir.zig b/src/arch/aarch64/Mir.zig index 9d5837f2f5..4cae413bc6 100644 --- a/src/arch/aarch64/Mir.zig +++ b/src/arch/aarch64/Mir.zig @@ -30,6 +30,8 @@ pub const Inst = struct { add_shifted_register, /// Bitwise AND (shifted register) and_shifted_register, + /// Arithmetic Shift Right (register) + asr_register, /// Branch conditionally b_cond, /// Branch @@ -96,6 +98,10 @@ pub const Inst = struct { ldrh_immediate, /// Load Register Halfword (register) ldrh_register, + /// Logical Shift Left (register) + lsl_register, + /// Logical Shift Right (register) + lsr_register, /// Move (to/from SP) mov_to_from_sp, /// Move (register) diff --git a/src/arch/aarch64/bits.zig b/src/arch/aarch64/bits.zig index afe14f3204..3f6e302b84 100644 --- a/src/arch/aarch64/bits.zig +++ b/src/arch/aarch64/bits.zig @@ -356,6 +356,16 @@ pub const Instruction = union(enum) { op54: u2, sf: u1, }, + data_processing_2_source: packed struct { + rd: u5, + rn: u5, + opcode: u6, + rm: u5, + fixed_1: u8 = 0b11010110, + s: u1, + fixed_2: u1 = 0b0, + sf: u1, + }, pub const Condition = enum(u4) { /// Integer: Equal @@ -479,6 +489,7 @@ pub const Instruction = union(enum) { .compare_and_branch => |v| @as(u32, v.rt) | (@as(u32, v.imm19) << 5) | (@as(u32, v.op) << 24) | (@as(u32, v.fixed) << 25) | (@as(u32, v.sf) << 31), .conditional_select => |v| @as(u32, v.rd) | @as(u32, v.rn) << 5 | @as(u32, v.op2) << 10 | @as(u32, v.cond) << 12 | @as(u32, v.rm) << 16 | @as(u32, v.fixed) << 21 | @as(u32, v.s) << 29 | @as(u32, v.op) << 30 | @as(u32, v.sf) << 31, .data_processing_3_source => |v| @bitCast(u32, v), + .data_processing_2_source => |v| @bitCast(u32, v), }; } @@ -1031,6 +1042,29 @@ pub const Instruction = union(enum) { }; } + fn dataProcessing2Source( + s: u1, + opcode: u6, + rd: Register, + rn: Register, + rm: Register, + ) Instruction { + return Instruction{ + .data_processing_2_source = .{ + .rd = rd.enc(), + .rn = rn.enc(), + .opcode = opcode, + .rm = rm.enc(), + .s = s, + .sf = switch (rd.size()) { + 32 => 0b0, + 64 => 0b1, + else => unreachable, // unexpected register size + }, + }, + }; + } + // Helper functions for assembly syntax functions // Move wide (immediate) @@ -1393,6 +1427,20 @@ pub const Instruction = union(enum) { pub fn mneg(rd: Register, rn: Register, rm: Register) Instruction { return msub(rd, rn, rm, .xzr); } + + // Data processing (2 source) + + pub fn lslv(rd: Register, rn: Register, rm: Register) Instruction { + return dataProcessing2Source(0b0, 0b001000, rd, rn, rm); + } + + pub fn lsrv(rd: Register, rn: Register, rm: Register) Instruction { + return dataProcessing2Source(0b0, 0b001001, rd, rn, rm); + } + + pub fn asrv(rd: Register, rn: Register, rm: Register) Instruction { + return dataProcessing2Source(0b0, 0b001010, rd, rn, rm); + } }; test { @@ -1570,6 +1618,10 @@ test "serialize instructions" { .inst = Instruction.eorImmediate(.x3, .x5, 0b000000, 0b000000, 0b1), .expected = 0b1_10_100100_1_000000_000000_00101_00011, }, + .{ // lslv x6, x9, x10 + .inst = Instruction.lslv(.x6, .x9, .x10), + .expected = 0b1_0_0_11010110_01010_0010_00_01001_00110, + }, }; for (testcases) |case| { |
