Commit 2082c27557

Jakub Konka <kubkon@jakubkonka.com>
2020-12-09 17:15:00
stage2+aarch64: clean up offset helper structs
1 parent e91dbab
Changed files (2)
src/codegen/aarch64.zig
@@ -290,123 +290,6 @@ pub const Instruction = union(enum) {
         };
     }
 
-    /// 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 Offset = 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,
-            },
-        },
-
-        pub const none = Offset{
-            .Immediate = .{ .Unsigned = 0 },
-        };
-
-        pub fn toU12(self: Offset) 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,
-                },
-                .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) Offset {
-            return Offset{
-                .Immediate = .{ .Unsigned = offset },
-            };
-        }
-
-        pub fn imm_post_index(offset: i9) Offset {
-            return Offset{
-                .Immediate = .{ .PostIndex = offset },
-            };
-        }
-
-        pub fn imm_pre_index(offset: i9) Offset {
-            return Offset{
-                .Immediate = .{ .PreIndex = offset },
-            };
-        }
-
-        pub fn reg(rm: Register) Offset {
-            return Offset{
-                .Register = .{
-                    .rm = rm.id(),
-                    .shift = .{
-                        .Lsl = 0,
-                    },
-                },
-            };
-        }
-
-        pub fn reg_uxtw(rm: Register, shift: u2) Offset {
-            assert(rm.size() == 32 and (shift == 0 or shift == 2));
-            return Offset{
-                .Register = .{
-                    .rm = rm.id(),
-                    .shift = .{
-                        .Uxtw = shift,
-                    },
-                },
-            };
-        }
-
-        pub fn reg_lsl(rm: Register, shift: u2) Offset {
-            assert(rm.size() == 64 and (shift == 0 or shift == 3));
-            return Offset{
-                .Register = .{
-                    .rm = rm.id(),
-                    .shift = .{
-                        .Lsl = shift,
-                    },
-                },
-            };
-        }
-
-        pub fn reg_sxtw(rm: Register, shift: u2) Offset {
-            assert(rm.size() == 32 and (shift == 0 or shift == 2));
-            return Offset{
-                .Register = .{
-                    .rm = rm.id(),
-                    .shift = .{
-                        .Sxtw = shift,
-                    },
-                },
-            };
-        }
-
-        pub fn reg_sxtx(rm: Register, shift: u2) Offset {
-            assert(rm.size() == 64 and (shift == 0 or shift == 3));
-            return Offset{
-                .Register = .{
-                    .rm = rm.id(),
-                    .shift = .{
-                        .Sxtx = shift,
-                    },
-                },
-            };
-        }
-    };
-
     pub const RegisterShift = struct {
         rn: u5,
         imm6: u6,
@@ -514,7 +397,124 @@ pub const Instruction = union(enum) {
         };
     }
 
-    fn loadStoreRegister(rt: Register, rn: Register, offset: Offset, load: bool) Instruction {
+    /// 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,
+            },
+        },
+
+        pub const none = LoadStoreOffset{
+            .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,
+                },
+                .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 },
+            };
+        }
+
+        pub fn imm_post_index(offset: i9) LoadStoreOffset {
+            return .{
+                .Immediate = .{ .PostIndex = offset },
+            };
+        }
+
+        pub fn imm_pre_index(offset: i9) LoadStoreOffset {
+            return .{
+                .Immediate = .{ .PreIndex = offset },
+            };
+        }
+
+        pub fn reg(rm: Register) LoadStoreOffset {
+            return .{
+                .Register = .{
+                    .rm = rm.id(),
+                    .shift = .{
+                        .Lsl = 0,
+                    },
+                },
+            };
+        }
+
+        pub fn reg_uxtw(rm: Register, shift: u2) LoadStoreOffset {
+            assert(rm.size() == 32 and (shift == 0 or shift == 2));
+            return .{
+                .Register = .{
+                    .rm = rm.id(),
+                    .shift = .{
+                        .Uxtw = shift,
+                    },
+                },
+            };
+        }
+
+        pub fn reg_lsl(rm: Register, shift: u2) LoadStoreOffset {
+            assert(rm.size() == 64 and (shift == 0 or shift == 3));
+            return .{
+                .Register = .{
+                    .rm = rm.id(),
+                    .shift = .{
+                        .Lsl = shift,
+                    },
+                },
+            };
+        }
+
+        pub fn reg_sxtw(rm: Register, shift: u2) LoadStoreOffset {
+            assert(rm.size() == 32 and (shift == 0 or shift == 2));
+            return .{
+                .Register = .{
+                    .rm = rm.id(),
+                    .shift = .{
+                        .Sxtw = shift,
+                    },
+                },
+            };
+        }
+
+        pub fn reg_sxtx(rm: Register, shift: u2) LoadStoreOffset {
+            assert(rm.size() == 64 and (shift == 0 or shift == 3));
+            return .{
+                .Register = .{
+                    .rm = rm.id(),
+                    .shift = .{
+                        .Sxtx = shift,
+                    },
+                },
+            };
+        }
+    };
+
+    fn loadStoreRegister(rt: Register, rn: Register, offset: LoadStoreOffset, load: bool) Instruction {
         const off = offset.toU12();
         const op1: u2 = blk: {
             switch (offset) {
@@ -709,9 +709,10 @@ pub const Instruction = union(enum) {
 
     pub const LdrArgs = struct {
         rn: ?Register = null,
-        offset: Offset = Offset.none,
+        offset: LoadStoreOffset = LoadStoreOffset.none,
         literal: ?u19 = null,
     };
+
     pub fn ldr(rt: Register, args: LdrArgs) Instruction {
         if (args.rn) |rn| {
             return loadStoreRegister(rt, rn, args.offset, true);
@@ -721,29 +722,50 @@ pub const Instruction = union(enum) {
     }
 
     pub const StrArgs = struct {
-        offset: Offset = Offset.none,
+        offset: LoadStoreOffset = LoadStoreOffset.none,
     };
+
     pub fn str(rt: Register, rn: Register, args: StrArgs) Instruction {
         return loadStoreRegister(rt, rn, args.offset, false);
     }
 
     // Load or store pair of registers
 
-    pub const LoadStorePairEncoding = enum(u2) {
-        PostIndex = 0b01,
-        SignedOffset = 0b10,
-        PreIndex = 0b11,
+    pub const LoadStorePairOffset = struct {
+        encoding: enum(u2) {
+            PostIndex = 0b01,
+            Signed = 0b10,
+            PreIndex = 0b11,
+        },
+        offset: i9,
+
+        pub fn none() LoadStorePairOffset {
+            return .{ .encoding = .Signed, .offset = 0 };
+        }
+
+        pub fn post_index(imm: i9) LoadStorePairOffset {
+            return .{ .encoding = .PostIndex, .offset = imm };
+        }
+
+        pub fn pre_index(imm: i9) LoadStorePairOffset {
+            return .{ .encoding = .PreIndex, .offset = imm };
+        }
+
+        pub fn signed(imm: i9) LoadStorePairOffset {
+            return .{ .encoding = .Signed, .offset = imm };
+        }
     };
-    pub fn ldp(rt1: Register, rt2: Register, rn: Register, offset: i9, encoding: LoadStorePairEncoding) Instruction {
-        return loadStorePairOfRegisters(rt1, rt2, rn, offset, @enumToInt(encoding), true);
+
+    pub fn ldp(rt1: Register, rt2: Register, rn: Register, offset: LoadStorePairOffset) Instruction {
+        return loadStorePairOfRegisters(rt1, rt2, rn, offset.offset, @enumToInt(offset.encoding), true);
     }
 
     pub fn ldnp(rt1: Register, rt2: Register, rn: Register, offset: i9) Instruction {
         return loadStorePairOfRegisters(rt1, rt2, rn, offset, 0, true);
     }
 
-    pub fn stp(rt1: Register, rt2: Register, rn: Register, offset: i9, encoding: LoadStorePairEncoding) Instruction {
-        return loadStorePairOfRegisters(rt1, rt2, rn, offset, @enumToInt(encoding), false);
+    pub fn stp(rt1: Register, rt2: Register, rn: Register, offset: LoadStorePairOffset) Instruction {
+        return loadStorePairOfRegisters(rt1, rt2, rn, offset.offset, @enumToInt(offset.encoding), false);
     }
 
     pub fn stnp(rt1: Register, rt2: Register, rn: Register, offset: i9) Instruction {
@@ -867,15 +889,15 @@ test "serialize instructions" {
             .expected = 0b11_111_0_01_01_000000000000_00001_00010,
         },
         .{ // ldr x2, [x1, #1]!
-            .inst = Instruction.ldr(.x2, .{ .rn = .x1, .offset = Instruction.Offset.imm_pre_index(1) }),
+            .inst = Instruction.ldr(.x2, .{ .rn = .x1, .offset = Instruction.LoadStoreOffset.imm_pre_index(1) }),
             .expected = 0b11_111_0_00_01_0_000000001_11_00001_00010,
         },
         .{ // ldr x2, [x1], #-1
-            .inst = Instruction.ldr(.x2, .{ .rn = .x1, .offset = Instruction.Offset.imm_post_index(-1) }),
+            .inst = Instruction.ldr(.x2, .{ .rn = .x1, .offset = Instruction.LoadStoreOffset.imm_post_index(-1) }),
             .expected = 0b11_111_0_00_01_0_111111111_01_00001_00010,
         },
         .{ // ldr x2, [x1], (x3)
-            .inst = Instruction.ldr(.x2, .{ .rn = .x1, .offset = Instruction.Offset.reg(.x3) }),
+            .inst = Instruction.ldr(.x2, .{ .rn = .x1, .offset = Instruction.LoadStoreOffset.reg(.x3) }),
             .expected = 0b11_111_0_00_01_1_00011_011_0_10_00001_00010,
         },
         .{ // ldr x2, label
@@ -887,7 +909,7 @@ test "serialize instructions" {
             .expected = 0b11_111_0_01_00_000000000000_00001_00010,
         },
         .{ // str x2, [x1], (x3)
-            .inst = Instruction.str(.x2, .x1, .{ .offset = Instruction.Offset.reg(.x3) }),
+            .inst = Instruction.str(.x2, .x1, .{ .offset = Instruction.LoadStoreOffset.reg(.x3) }),
             .expected = 0b11_111_0_00_00_1_00011_011_0_10_00001_00010,
         },
         .{ // adr x2, #0x8
@@ -907,20 +929,20 @@ test "serialize instructions" {
             .expected = 0b1_00_10000_1111111111111111110_00010,
         },
         .{ // stp x1, x2, [sp, #8]
-            .inst = Instruction.stp(.x1, .x2, Register.sp, 8, .SignedOffset),
+            .inst = Instruction.stp(.x1, .x2, Register.sp, Instruction.LoadStorePairOffset.signed(8)),
             .expected = 0b10_101_0_010_0_0000001_00010_11111_00001,
         },
-        .{ // stp x1, x2, [sp, #-16]
-            .inst = Instruction.stp(.x1, .x2, Register.sp, -16, .SignedOffset),
-            .expected = 0b10_101_0_010_0_1111110_00010_11111_00001,
-        },
         .{ // ldp x1, x2, [sp, #8]
-            .inst = Instruction.ldp(.x1, .x2, Register.sp, 8, .SignedOffset),
+            .inst = Instruction.ldp(.x1, .x2, Register.sp, Instruction.LoadStorePairOffset.signed(8)),
             .expected = 0b10_101_0_010_1_0000001_00010_11111_00001,
         },
-        .{ // ldp x1, x2, [sp, #16]
-            .inst = Instruction.ldp(.x1, .x2, Register.sp, 16, .SignedOffset),
-            .expected = 0b10_101_0_010_1_0000010_00010_11111_00001,
+        .{ // stp x1, x2, [sp, #-16]!
+            .inst = Instruction.stp(.x1, .x2, Register.sp, Instruction.LoadStorePairOffset.pre_index(-16)),
+            .expected = 0b10_101_0_011_0_1111110_00010_11111_00001,
+        },
+        .{ // ldp x1, x2, [sp], #16
+            .inst = Instruction.ldp(.x1, .x2, Register.sp, Instruction.LoadStorePairOffset.post_index(16)),
+            .expected = 0b10_101_0_001_1_0000010_00010_11111_00001,
         },
     };
 
src/codegen.zig
@@ -2736,7 +2736,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
                                 // https://community.arm.com/developer/ip-products/processors/b/processors-ip-blog/posts/using-the-stack-in-aarch64-implementing-push-and-pop)
                                 // str x28, [sp, #-16]
                                 mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.str(.x28, Register.sp, .{
-                                    .offset = Instruction.Offset.imm_pre_index(-16),
+                                    .offset = Instruction.LoadStoreOffset.imm_pre_index(-16),
                                 }).toU32());
                                 // adr x28, #8
                                 mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.adr(.x28, 8).toU32());
@@ -2760,7 +2760,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
                                 // ldr x28, [sp], #16
                                 mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.ldr(.x28, .{
                                     .rn = Register.sp,
-                                    .offset = Instruction.Offset.imm_post_index(16),
+                                    .offset = Instruction.LoadStoreOffset.imm_post_index(16),
                                 }).toU32());
                             } else {
                                 // stp x0, x28, [sp, #-16]
@@ -2768,8 +2768,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
                                     .x0,
                                     .x28,
                                     Register.sp,
-                                    -16,
-                                    .PreIndex,
+                                    Instruction.LoadStorePairOffset.pre_index(-16),
                                 ).toU32());
                                 // adr x28, #8
                                 mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.adr(.x28, 8).toU32());
@@ -2795,8 +2794,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
                                     .x0,
                                     .x28,
                                     Register.sp,
-                                    16,
-                                    .PostIndex,
+                                    Instruction.LoadStorePairOffset.post_index(16),
                                 ).toU32());
                             }
                         } else {