Commit 1c37622659

joachimschmidt557 <joachim.schmidt557@outlook.com>
2022-02-12 18:37:11
stage2 AArch64: Implement not for booleans
1 parent 3a33f31
Changed files (4)
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
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", .{}),
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,
     }
 }
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