Commit 7e76aab98a

joachimschmidt557 <joachim.schmidt557@outlook.com>
2022-01-13 17:45:19
stage2 AArch64: split ldr/str into {ldr,str}_register and _immediate
1 parent e945619
Changed files (3)
src
src/arch/aarch64/bits.zig
@@ -521,69 +521,73 @@ pub const Instruction = union(enum) {
         };
     }
 
+    pub const LoadStoreOffsetImmediate = union(enum) {
+        post_index: i9,
+        pre_index: i9,
+        unsigned: u12,
+    };
+
+    pub const LoadStoreOffsetRegister = struct {
+        rm: u5,
+        shift: union(enum) {
+            uxtw: u2,
+            lsl: u2,
+            sxtw: u2,
+            sxtx: u2,
+        },
+    };
+
     /// Represents the offset operand of a load or store instruction.
     /// Data can be loaded from memory with either an immediate offset
     /// or an offset that is stored in some register.
     pub const LoadStoreOffset = union(enum) {
-        Immediate: union(enum) {
-            PostIndex: i9,
-            PreIndex: i9,
-            Unsigned: u12,
-        },
-        Register: struct {
-            rm: u5,
-            shift: union(enum) {
-                Uxtw: u2,
-                Lsl: u2,
-                Sxtw: u2,
-                Sxtx: u2,
-            },
-        },
+        immediate: LoadStoreOffsetImmediate,
+        register: LoadStoreOffsetRegister,
 
         pub const none = LoadStoreOffset{
-            .Immediate = .{ .Unsigned = 0 },
+            .immediate = .{ .unsigned = 0 },
         };
 
         pub fn toU12(self: LoadStoreOffset) u12 {
             return switch (self) {
-                .Immediate => |imm_type| switch (imm_type) {
-                    .PostIndex => |v| (@intCast(u12, @bitCast(u9, v)) << 2) + 1,
-                    .PreIndex => |v| (@intCast(u12, @bitCast(u9, v)) << 2) + 3,
-                    .Unsigned => |v| v,
+                .immediate => |imm_type| switch (imm_type) {
+                    .post_index => |v| (@intCast(u12, @bitCast(u9, v)) << 2) + 1,
+                    .pre_index => |v| (@intCast(u12, @bitCast(u9, v)) << 2) + 3,
+                    .unsigned => |v| v,
                 },
-                .Register => |r| switch (r.shift) {
-                    .Uxtw => |v| (@intCast(u12, r.rm) << 6) + (@intCast(u12, v) << 2) + 16 + 2050,
-                    .Lsl => |v| (@intCast(u12, r.rm) << 6) + (@intCast(u12, v) << 2) + 24 + 2050,
-                    .Sxtw => |v| (@intCast(u12, r.rm) << 6) + (@intCast(u12, v) << 2) + 48 + 2050,
-                    .Sxtx => |v| (@intCast(u12, r.rm) << 6) + (@intCast(u12, v) << 2) + 56 + 2050,
+                .register => |r| switch (r.shift) {
+                    .uxtw => |v| (@intCast(u12, r.rm) << 6) + (@intCast(u12, v) << 2) + 16 + 2050,
+                    .lsl => |v| (@intCast(u12, r.rm) << 6) + (@intCast(u12, v) << 2) + 24 + 2050,
+                    .sxtw => |v| (@intCast(u12, r.rm) << 6) + (@intCast(u12, v) << 2) + 48 + 2050,
+                    .sxtx => |v| (@intCast(u12, r.rm) << 6) + (@intCast(u12, v) << 2) + 56 + 2050,
                 },
             };
         }
 
         pub fn imm(offset: u12) LoadStoreOffset {
             return .{
-                .Immediate = .{ .Unsigned = offset },
+                .immediate = .{ .unsigned = offset },
             };
         }
 
         pub fn imm_post_index(offset: i9) LoadStoreOffset {
             return .{
-                .Immediate = .{ .PostIndex = offset },
+                .immediate = .{ .post_index = offset },
             };
         }
 
         pub fn imm_pre_index(offset: i9) LoadStoreOffset {
             return .{
-                .Immediate = .{ .PreIndex = offset },
+                .immediate = .{ .pre_index = offset },
             };
         }
 
         pub fn reg(rm: Register) LoadStoreOffset {
             return .{
-                .Register = .{
+                .register = .{
                     .rm = rm.id(),
                     .shift = .{
-                        .Lsl = 0,
+                        .lsl = 0,
                     },
                 },
             };
@@ -592,10 +596,10 @@ pub const Instruction = union(enum) {
         pub fn reg_uxtw(rm: Register, shift: u2) LoadStoreOffset {
             assert(rm.size() == 32 and (shift == 0 or shift == 2));
             return .{
-                .Register = .{
+                .register = .{
                     .rm = rm.id(),
                     .shift = .{
-                        .Uxtw = shift,
+                        .uxtw = shift,
                     },
                 },
             };
@@ -604,10 +608,10 @@ pub const Instruction = union(enum) {
         pub fn reg_lsl(rm: Register, shift: u2) LoadStoreOffset {
             assert(rm.size() == 64 and (shift == 0 or shift == 3));
             return .{
-                .Register = .{
+                .register = .{
                     .rm = rm.id(),
                     .shift = .{
-                        .Lsl = shift,
+                        .lsl = shift,
                     },
                 },
             };
@@ -616,10 +620,10 @@ pub const Instruction = union(enum) {
         pub fn reg_sxtw(rm: Register, shift: u2) LoadStoreOffset {
             assert(rm.size() == 32 and (shift == 0 or shift == 2));
             return .{
-                .Register = .{
+                .register = .{
                     .rm = rm.id(),
                     .shift = .{
-                        .Sxtw = shift,
+                        .sxtw = shift,
                     },
                 },
             };
@@ -628,10 +632,10 @@ pub const Instruction = union(enum) {
         pub fn reg_sxtx(rm: Register, shift: u2) LoadStoreOffset {
             assert(rm.size() == 64 and (shift == 0 or shift == 3));
             return .{
-                .Register = .{
+                .register = .{
                     .rm = rm.id(),
                     .shift = .{
-                        .Sxtx = shift,
+                        .sxtx = shift,
                     },
                 },
             };
@@ -663,8 +667,8 @@ pub const Instruction = union(enum) {
         const off = offset.toU12();
         const op1: u2 = blk: {
             switch (offset) {
-                .Immediate => |imm| switch (imm) {
-                    .Unsigned => break :blk 0b01,
+                .immediate => |imm| switch (imm) {
+                    .unsigned => break :blk 0b01,
                     else => {},
                 },
                 else => {},
@@ -1023,26 +1027,26 @@ pub const Instruction = union(enum) {
 
     pub const LoadStorePairOffset = struct {
         encoding: enum(u2) {
-            PostIndex = 0b01,
-            Signed = 0b10,
-            PreIndex = 0b11,
+            post_index = 0b01,
+            signed = 0b10,
+            pre_index = 0b11,
         },
         offset: i9,
 
         pub fn none() LoadStorePairOffset {
-            return .{ .encoding = .Signed, .offset = 0 };
+            return .{ .encoding = .signed, .offset = 0 };
         }
 
         pub fn post_index(imm: i9) LoadStorePairOffset {
-            return .{ .encoding = .PostIndex, .offset = imm };
+            return .{ .encoding = .post_index, .offset = imm };
         }
 
         pub fn pre_index(imm: i9) LoadStorePairOffset {
-            return .{ .encoding = .PreIndex, .offset = imm };
+            return .{ .encoding = .pre_index, .offset = imm };
         }
 
         pub fn signed(imm: i9) LoadStorePairOffset {
-            return .{ .encoding = .Signed, .offset = imm };
+            return .{ .encoding = .signed, .offset = imm };
         }
     };
 
src/arch/aarch64/Emit.zig
@@ -112,12 +112,19 @@ pub fn emitMir(
             .strb_stack => try emit.mirLoadStoreStack(inst),
             .strh_stack => try emit.mirLoadStoreStack(inst),
 
-            .ldr => try emit.mirLoadStoreRegister(inst),
-            .ldrb => try emit.mirLoadStoreRegister(inst),
-            .ldrh => try emit.mirLoadStoreRegister(inst),
-            .str => try emit.mirLoadStoreRegister(inst),
-            .strb => try emit.mirLoadStoreRegister(inst),
-            .strh => try emit.mirLoadStoreRegister(inst),
+            .ldr_register => try emit.mirLoadStoreRegisterRegister(inst),
+            .ldrb_register => try emit.mirLoadStoreRegisterRegister(inst),
+            .ldrh_register => try emit.mirLoadStoreRegisterRegister(inst),
+            .str_register => try emit.mirLoadStoreRegisterRegister(inst),
+            .strb_register => try emit.mirLoadStoreRegisterRegister(inst),
+            .strh_register => try emit.mirLoadStoreRegisterRegister(inst),
+
+            .ldr_immediate => try emit.mirLoadStoreRegisterImmediate(inst),
+            .ldrb_immediate => try emit.mirLoadStoreRegisterImmediate(inst),
+            .ldrh_immediate => try emit.mirLoadStoreRegisterImmediate(inst),
+            .str_immediate => try emit.mirLoadStoreRegisterImmediate(inst),
+            .strb_immediate => try emit.mirLoadStoreRegisterImmediate(inst),
+            .strh_immediate => try emit.mirLoadStoreRegisterImmediate(inst),
 
             .mov_register => try emit.mirMoveRegister(inst),
             .mov_to_from_sp => try emit.mirMoveRegister(inst),
@@ -737,41 +744,38 @@ fn mirLoadStoreStack(emit: *Emit, inst: Mir.Inst.Index) !void {
     }
 }
 
-fn mirLoadStoreRegister(emit: *Emit, inst: Mir.Inst.Index) !void {
+fn mirLoadStoreRegisterImmediate(emit: *Emit, inst: Mir.Inst.Index) !void {
     const tag = emit.mir.instructions.items(.tag)[inst];
-    const load_store_register = emit.mir.instructions.items(.data)[inst].load_store_register;
+    const load_store_register_immediate = emit.mir.instructions.items(.data)[inst].load_store_register_immediate;
+    const rt = load_store_register_immediate.rt;
+    const rn = load_store_register_immediate.rn;
+    const offset = Instruction.LoadStoreOffset{ .immediate = load_store_register_immediate.offset };
 
     switch (tag) {
-        .ldr => try emit.writeInstruction(Instruction.ldr(
-            load_store_register.rt,
-            load_store_register.rn,
-            load_store_register.offset,
-        )),
-        .ldrb => try emit.writeInstruction(Instruction.ldrb(
-            load_store_register.rt,
-            load_store_register.rn,
-            load_store_register.offset,
-        )),
-        .ldrh => try emit.writeInstruction(Instruction.ldrh(
-            load_store_register.rt,
-            load_store_register.rn,
-            load_store_register.offset,
-        )),
-        .str => try emit.writeInstruction(Instruction.str(
-            load_store_register.rt,
-            load_store_register.rn,
-            load_store_register.offset,
-        )),
-        .strb => try emit.writeInstruction(Instruction.strb(
-            load_store_register.rt,
-            load_store_register.rn,
-            load_store_register.offset,
-        )),
-        .strh => try emit.writeInstruction(Instruction.strh(
-            load_store_register.rt,
-            load_store_register.rn,
-            load_store_register.offset,
-        )),
+        .ldr_immediate => try emit.writeInstruction(Instruction.ldr(rt, rn, offset)),
+        .ldrb_immediate => try emit.writeInstruction(Instruction.ldrb(rt, rn, offset)),
+        .ldrh_immediate => try emit.writeInstruction(Instruction.ldrh(rt, rn, offset)),
+        .str_immediate => try emit.writeInstruction(Instruction.str(rt, rn, offset)),
+        .strb_immediate => try emit.writeInstruction(Instruction.strb(rt, rn, offset)),
+        .strh_immediate => try emit.writeInstruction(Instruction.strh(rt, rn, offset)),
+        else => unreachable,
+    }
+}
+
+fn mirLoadStoreRegisterRegister(emit: *Emit, inst: Mir.Inst.Index) !void {
+    const tag = emit.mir.instructions.items(.tag)[inst];
+    const load_store_register_register = emit.mir.instructions.items(.data)[inst].load_store_register_register;
+    const rt = load_store_register_register.rt;
+    const rn = load_store_register_register.rn;
+    const offset = Instruction.LoadStoreOffset{ .register = load_store_register_register.offset };
+
+    switch (tag) {
+        .ldr_register => try emit.writeInstruction(Instruction.ldr(rt, rn, offset)),
+        .ldrb_register => try emit.writeInstruction(Instruction.ldrb(rt, rn, offset)),
+        .ldrh_register => try emit.writeInstruction(Instruction.ldrh(rt, rn, offset)),
+        .str_register => try emit.writeInstruction(Instruction.str(rt, rn, offset)),
+        .strb_register => try emit.writeInstruction(Instruction.strb(rt, rn, offset)),
+        .strh_register => try emit.writeInstruction(Instruction.strh(rt, rn, offset)),
         else => unreachable,
     }
 }
src/arch/aarch64/Mir.zig
@@ -58,19 +58,22 @@ pub const Inst = struct {
         ldp,
         /// Pseudo-instruction: Load from stack
         ldr_stack,
-        /// Load Register
-        // TODO: split into ldr_immediate and ldr_register
-        ldr,
+        /// Load Register (immediate)
+        ldr_immediate,
+        /// Load Register (register)
+        ldr_register,
         /// Pseudo-instruction: Load byte from stack
         ldrb_stack,
-        /// Load Register Byte
-        // TODO: split into ldrb_immediate and ldrb_register
-        ldrb,
+        /// Load Register Byte (immediate)
+        ldrb_immediate,
+        /// Load Register Byte (register)
+        ldrb_register,
         /// Pseudo-instruction: Load halfword from stack
         ldrh_stack,
-        /// Load Register Halfword
-        // TODO: split into ldrh_immediate and ldrh_register
-        ldrh,
+        /// Load Register Halfword (immediate)
+        ldrh_immediate,
+        /// Load Register Halfword (register)
+        ldrh_register,
         /// Move (to/from SP)
         mov_to_from_sp,
         /// Move (register)
@@ -91,19 +94,22 @@ pub const Inst = struct {
         stp,
         /// Pseudo-instruction: Store to stack
         str_stack,
-        /// Store Register
-        // TODO: split into str_immediate and str_register
-        str,
+        /// Store Register (immediate)
+        str_immediate,
+        /// Store Register (register)
+        str_register,
         /// Pseudo-instruction: Store byte to stack
         strb_stack,
-        /// Store Register Byte
-        // TODO: split into strb_immediate and strb_register
-        strb,
+        /// Store Register Byte (immediate)
+        strb_immediate,
+        /// Store Register Byte (register)
+        strb_register,
         /// Pseudo-instruction: Store halfword to stack
         strh_stack,
-        /// Store Register Halfword
-        // TODO: split into strh_immediate and strh_register
-        strh,
+        /// Store Register Halfword (immediate)
+        strh_immediate,
+        /// Store Register Halfword (register)
+        strh_register,
         /// Subtract (immediate)
         sub_immediate,
         /// Supervisor Call
@@ -195,13 +201,21 @@ pub const Inst = struct {
             rm: Register,
             cond: bits.Instruction.Condition,
         },
-        /// Two registers and a LoadStoreOffset
+        /// Two registers and a LoadStoreOffsetImmediate
         ///
         /// Used by e.g. str_register
-        load_store_register: struct {
+        load_store_register_immediate: struct {
             rt: Register,
             rn: Register,
-            offset: bits.Instruction.LoadStoreOffset,
+            offset: bits.Instruction.LoadStoreOffsetImmediate,
+        },
+        /// Two registers and a LoadStoreOffsetRegister
+        ///
+        /// Used by e.g. str_register
+        load_store_register_register: struct {
+            rt: Register,
+            rn: Register,
+            offset: bits.Instruction.LoadStoreOffsetRegister,
         },
         /// A registers and a stack offset
         ///
@@ -230,11 +244,11 @@ pub const Inst = struct {
 
     // Make sure we don't accidentally make instructions bigger than expected.
     // Note that in Debug builds, Zig is allowed to insert a secret field for safety checks.
-    // comptime {
-    //     if (builtin.mode != .Debug) {
-    //         assert(@sizeOf(Inst) == 8);
-    //     }
-    // }
+    comptime {
+        if (builtin.mode != .Debug) {
+            assert(@sizeOf(Data) == 8);
+        }
+    }
 };
 
 pub fn deinit(mir: *Mir, gpa: std.mem.Allocator) void {