diff --git a/src/arch/aarch64/CodeGen.zig b/src/arch/aarch64/CodeGen.zig index fade038eb0..8bd5324ed1 100644 --- a/src/arch/aarch64/CodeGen.zig +++ b/src/arch/aarch64/CodeGen.zig @@ -894,6 +894,7 @@ 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: { const operand = try self.resolveInst(ty_op.operand); + const operand_ty = self.air.typeOf(ty_op.operand); switch (operand) { .dead => unreachable, .unreach => unreachable, @@ -924,7 +925,14 @@ fn airNot(self: *Self, inst: Air.Inst.Index) !void { break :result r; }, else => { - return self.fail("TODO implement NOT for {}", .{self.target.cpu.arch}); + switch (operand_ty.zigTypeTag()) { + .Bool => { + // TODO convert this to mvn + and + const dest = try self.binOp(.xor, null, operand, .{ .immediate = 1 }, operand_ty, Type.bool); + break :result dest; + }, + else => return self.fail("TODO bitwise not", .{}), + } }, } }; @@ -1013,6 +1021,7 @@ fn binOpRegister( const mir_tag: Mir.Inst.Tag = switch (tag) { .add => .add_shifted_register, .sub => .sub_shifted_register, + .xor => .eor_shifted_register, else => unreachable, }; const mir_data: Mir.Inst.Data = switch (tag) { @@ -1025,6 +1034,13 @@ fn binOpRegister( .imm6 = 0, .shift = .lsl, } }, + .xor => .{ .rrr_imm6_logical_shift = .{ + .rd = dest_reg, + .rn = lhs_reg, + .rm = rhs_reg, + .imm6 = 0, + .shift = .lsl, + } }, else => unreachable, }; @@ -1137,6 +1153,7 @@ fn binOp( rhs_ty: Type, ) !MCValue { switch (tag) { + // Arithmetic operations on integers and floats .add, .sub, => { @@ -1177,6 +1194,19 @@ fn binOp( else => unreachable, } }, + // Bitwise operations on integers + .xor => { + switch (lhs_ty.zigTypeTag()) { + .Vector => return self.fail("TODO binary operations on vectors", .{}), + .Int => return self.fail("TODO binary operations on vectors", .{}), + .Bool => { + assert(lhs_ty.eql(rhs_ty)); + // TODO boolean operations with immediates + return try self.binOpRegister(tag, maybe_inst, lhs, rhs, lhs_ty, rhs_ty); + }, + else => unreachable, + } + }, .ptr_add, .ptr_sub, => return self.fail("TODO ptr_add, ptr_sub", .{}), diff --git a/src/arch/aarch64/Emit.zig b/src/arch/aarch64/Emit.zig index 1772f08aa8..bc37cb56c6 100644 --- a/src/arch/aarch64/Emit.zig +++ b/src/arch/aarch64/Emit.zig @@ -106,6 +106,8 @@ pub fn emitMir( .dbg_prologue_end => try emit.mirDebugPrologueEnd(), .dbg_epilogue_begin => try emit.mirDebugEpilogueBegin(), + .eor_shifted_register => try emit.mirLogicalShiftedRegister(inst), + .load_memory => try emit.mirLoadMemory(inst), .ldp => try emit.mirLoadStoreRegisterPair(inst), @@ -134,6 +136,7 @@ pub fn emitMir( .mov_register => try emit.mirMoveRegister(inst), .mov_to_from_sp => try emit.mirMoveRegister(inst), + .mvn => try emit.mirMoveRegister(inst), .movk => try emit.mirMoveWideImmediate(inst), .movz => try emit.mirMoveWideImmediate(inst), @@ -638,6 +641,21 @@ fn mirConditionalSelect(emit: *Emit, inst: Mir.Inst.Index) !void { } } +fn mirLogicalShiftedRegister(emit: *Emit, inst: Mir.Inst.Index) !void { + const tag = emit.mir.instructions.items(.tag)[inst]; + const rrr_imm6_logical_shift = emit.mir.instructions.items(.data)[inst].rrr_imm6_logical_shift; + const rd = rrr_imm6_logical_shift.rd; + const rn = rrr_imm6_logical_shift.rn; + const rm = rrr_imm6_logical_shift.rm; + const shift = rrr_imm6_logical_shift.shift; + const imm6 = rrr_imm6_logical_shift.imm6; + + switch (tag) { + .eor_shifted_register => try emit.writeInstruction(Instruction.eor(rd, rn, rm, shift, imm6)), + else => unreachable, + } +} + fn mirLoadMemory(emit: *Emit, inst: Mir.Inst.Index) !void { assert(emit.mir.instructions.items(.tag)[inst] == .load_memory); const payload = emit.mir.instructions.items(.data)[inst].payload; @@ -821,11 +839,19 @@ fn mirLoadStoreRegisterRegister(emit: *Emit, inst: Mir.Inst.Index) !void { fn mirMoveRegister(emit: *Emit, inst: Mir.Inst.Index) !void { const tag = emit.mir.instructions.items(.tag)[inst]; - const rr = emit.mir.instructions.items(.data)[inst].rr; - switch (tag) { - .mov_register => try emit.writeInstruction(Instruction.orr(rr.rd, .xzr, rr.rn, Instruction.Shift.none)), - .mov_to_from_sp => try emit.writeInstruction(Instruction.add(rr.rd, rr.rn, 0, false)), + .mov_register => { + const rr = emit.mir.instructions.items(.data)[inst].rr; + try emit.writeInstruction(Instruction.orr(rr.rd, .xzr, rr.rn, .lsl, 0)); + }, + .mov_to_from_sp => { + const rr = emit.mir.instructions.items(.data)[inst].rr; + try emit.writeInstruction(Instruction.add(rr.rd, rr.rn, 0, false)); + }, + .mvn => { + const rr_imm6_shift = emit.mir.instructions.items(.data)[inst].rr_imm6_shift; + try emit.writeInstruction(Instruction.orn(rr_imm6_shift.rd, .xzr, rr_imm6_shift.rm, .lsl, 0)); + }, else => unreachable, } } diff --git a/src/arch/aarch64/Mir.zig b/src/arch/aarch64/Mir.zig index 65b80549a9..92b0604347 100644 --- a/src/arch/aarch64/Mir.zig +++ b/src/arch/aarch64/Mir.zig @@ -54,6 +54,8 @@ pub const Inst = struct { dbg_epilogue_begin, /// Pseudo-instruction: Update debug line dbg_line, + /// Bitwise Exclusive OR (shifted register) + eor_shifted_register, /// Pseudo-instruction: Load memory /// /// Payload is `LoadMemory` @@ -88,6 +90,8 @@ pub const Inst = struct { movz, /// Multiply mul, + /// Bitwise NOT + mvn, /// No Operation nop, /// Pseudo-instruction: Pop multiple registers @@ -217,6 +221,15 @@ pub const Inst = struct { imm12: u12, sh: u1 = 0, }, + /// Two registers and a shift (shift type and 6-bit amount) + /// + /// Used by e.g. mvn + rr_imm6_shift: struct { + rd: Register, + rm: Register, + imm6: u6, + shift: bits.Instruction.AddSubtractShiftedRegisterShift, + }, /// Two registers /// /// Used by e.g. mul @@ -235,6 +248,17 @@ pub const Inst = struct { imm6: u6, shift: bits.Instruction.AddSubtractShiftedRegisterShift, }, + /// Three registers and a shift (logical instruction version) + /// (shift type and 6-bit amount) + /// + /// Used by e.g. eor_shifted_register + rrr_imm6_logical_shift: struct { + rd: Register, + rn: Register, + rm: Register, + imm6: u6, + shift: bits.Instruction.LogicalShiftedRegisterShift, + }, /// Two registers and a LoadStoreOffsetImmediate /// /// Used by e.g. str_immediate diff --git a/src/arch/aarch64/bits.zig b/src/arch/aarch64/bits.zig index 540a055c8e..a5d56cfcc7 100644 --- a/src/arch/aarch64/bits.zig +++ b/src/arch/aarch64/bits.zig @@ -344,23 +344,6 @@ pub const Instruction = union(enum) { sf: u1, }, - pub const Shift = struct { - shift: Type = .lsl, - amount: u6 = 0, - - pub const Type = enum(u2) { - lsl, - lsr, - asr, - ror, - }; - - pub const none = Shift{ - .shift = .lsl, - .amount = 0, - }; - }; - pub const Condition = enum(u4) { /// Integer: Equal /// Floating point: Equal @@ -819,25 +802,28 @@ pub const Instruction = union(enum) { }; } + pub const LogicalShiftedRegisterShift = enum(u2) { lsl, lsr, asr, ror }; + fn logicalShiftedRegister( opc: u2, n: u1, - shift: Shift, rd: Register, rn: Register, rm: Register, + shift: LogicalShiftedRegisterShift, + amount: u6, ) Instruction { switch (rd.size()) { 32 => { - assert(shift.amount < 32); + assert(amount < 32); return Instruction{ .logical_shifted_register = .{ .rd = rd.id(), .rn = rn.id(), - .imm6 = shift.amount, + .imm6 = amount, .rm = rm.id(), .n = n, - .shift = @enumToInt(shift.shift), + .shift = @enumToInt(shift), .opc = opc, .sf = 0b0, }, @@ -848,10 +834,10 @@ pub const Instruction = union(enum) { .logical_shifted_register = .{ .rd = rd.id(), .rn = rn.id(), - .imm6 = shift.amount, + .imm6 = amount, .rm = rm.id(), .n = n, - .shift = @enumToInt(shift.shift), + .shift = @enumToInt(shift), .opc = opc, .sf = 0b1, }, @@ -1159,36 +1145,84 @@ pub const Instruction = union(enum) { // Logical (shifted register) - pub fn @"and"(rd: Register, rn: Register, rm: Register, shift: Shift) Instruction { - return logicalShiftedRegister(0b00, 0b0, shift, rd, rn, rm); + pub fn @"and"( + rd: Register, + rn: Register, + rm: Register, + shift: LogicalShiftedRegisterShift, + amount: u6, + ) Instruction { + return logicalShiftedRegister(0b00, 0b0, rd, rn, rm, shift, amount); } - pub fn bic(rd: Register, rn: Register, rm: Register, shift: Shift) Instruction { - return logicalShiftedRegister(0b00, 0b1, shift, rd, rn, rm); + pub fn bic( + rd: Register, + rn: Register, + rm: Register, + shift: LogicalShiftedRegisterShift, + amount: u6, + ) Instruction { + return logicalShiftedRegister(0b00, 0b1, rd, rn, rm, shift, amount); } - pub fn orr(rd: Register, rn: Register, rm: Register, shift: Shift) Instruction { - return logicalShiftedRegister(0b01, 0b0, shift, rd, rn, rm); + pub fn orr( + rd: Register, + rn: Register, + rm: Register, + shift: LogicalShiftedRegisterShift, + amount: u6, + ) Instruction { + return logicalShiftedRegister(0b01, 0b0, rd, rn, rm, shift, amount); } - pub fn orn(rd: Register, rn: Register, rm: Register, shift: Shift) Instruction { - return logicalShiftedRegister(0b01, 0b1, shift, rd, rn, rm); + pub fn orn( + rd: Register, + rn: Register, + rm: Register, + shift: LogicalShiftedRegisterShift, + amount: u6, + ) Instruction { + return logicalShiftedRegister(0b01, 0b1, rd, rn, rm, shift, amount); } - pub fn eor(rd: Register, rn: Register, rm: Register, shift: Shift) Instruction { - return logicalShiftedRegister(0b10, 0b0, shift, rd, rn, rm); + pub fn eor( + rd: Register, + rn: Register, + rm: Register, + shift: LogicalShiftedRegisterShift, + amount: u6, + ) Instruction { + return logicalShiftedRegister(0b10, 0b0, rd, rn, rm, shift, amount); } - pub fn eon(rd: Register, rn: Register, rm: Register, shift: Shift) Instruction { - return logicalShiftedRegister(0b10, 0b1, shift, rd, rn, rm); + pub fn eon( + rd: Register, + rn: Register, + rm: Register, + shift: LogicalShiftedRegisterShift, + amount: u6, + ) Instruction { + return logicalShiftedRegister(0b10, 0b1, rd, rn, rm, shift, amount); } - pub fn ands(rd: Register, rn: Register, rm: Register, shift: Shift) Instruction { - return logicalShiftedRegister(0b11, 0b0, shift, rd, rn, rm); + pub fn ands( + rd: Register, + rn: Register, + rm: Register, + shift: LogicalShiftedRegisterShift, + amount: u6, + ) Instruction { + return logicalShiftedRegister(0b11, 0b0, rd, rn, rm, shift, amount); } - pub fn bics(rd: Register, rn: Register, rm: Register, shift: Shift) Instruction { - return logicalShiftedRegister(0b11, 0b1, shift, rd, rn, rm); + pub fn bics( + rd: Register, + rn: Register, + rm: Register, + shift: LogicalShiftedRegisterShift, + amount: u6, + ) Instruction { + return logicalShiftedRegister(0b11, 0b1, rd, rn, rm, shift, amount); } // Add/subtract (immediate) @@ -1316,11 +1350,11 @@ test "serialize instructions" { const testcases = [_]Testcase{ .{ // orr x0, xzr, x1 - .inst = Instruction.orr(.x0, .xzr, .x1, Instruction.Shift.none), + .inst = Instruction.orr(.x0, .xzr, .x1, .lsl, 0), .expected = 0b1_01_01010_00_0_00001_000000_11111_00000, }, .{ // orn x0, xzr, x1 - .inst = Instruction.orn(.x0, .xzr, .x1, Instruction.Shift.none), + .inst = Instruction.orn(.x0, .xzr, .x1, .lsl, 0), .expected = 0b1_01_01010_00_1_00001_000000_11111_00000, }, .{ // movz x1, #4 @@ -1440,11 +1474,11 @@ test "serialize instructions" { .expected = 0b10_101_0_001_1_0000010_00010_11111_00001, }, .{ // and x0, x4, x2 - .inst = Instruction.@"and"(.x0, .x4, .x2, .{}), + .inst = Instruction.@"and"(.x0, .x4, .x2, .lsl, 0), .expected = 0b1_00_01010_00_0_00010_000000_00100_00000, }, .{ // and x0, x4, x2, lsl #0x8 - .inst = Instruction.@"and"(.x0, .x4, .x2, .{ .shift = .lsl, .amount = 0x8 }), + .inst = Instruction.@"and"(.x0, .x4, .x2, .lsl, 0x8), .expected = 0b1_00_01010_00_0_00010_001000_00100_00000, }, .{ // add x0, x10, #10