Commit e088a17f56

joachimschmidt557 <joachim.schmidt557@outlook.com>
2021-03-27 21:39:55
stage2 AArch64: implement strb and strh
1 parent 501b4af
Changed files (2)
src/codegen/aarch64.zig
@@ -484,7 +484,23 @@ pub const Instruction = union(enum) {
         }
     };
 
-    fn loadStoreRegister(rt: Register, rn: Register, offset: LoadStoreOffset, load: bool) Instruction {
+    /// Which kind of load/store to perform
+    const LoadStoreVariant = enum {
+        /// 32-bit or 64-bit
+        normal,
+        /// 16-bit
+        half,
+        /// 8-bit
+        byte,
+    };
+
+    fn loadStoreRegister(
+        rt: Register,
+        rn: Register,
+        offset: LoadStoreOffset,
+        variant: LoadStoreVariant,
+        load: bool,
+    ) Instruction {
         const off = offset.toU12();
         const op1: u2 = blk: {
             switch (offset) {
@@ -497,35 +513,27 @@ pub const Instruction = union(enum) {
             break :blk 0b00;
         };
         const opc: u2 = if (load) 0b01 else 0b00;
-        switch (rt.size()) {
-            32 => {
-                return Instruction{
-                    .LoadStoreRegister = .{
-                        .rt = rt.id(),
-                        .rn = rn.id(),
-                        .offset = offset.toU12(),
-                        .opc = opc,
-                        .op1 = op1,
-                        .v = 0,
-                        .size = 0b10,
-                    },
-                };
-            },
-            64 => {
-                return Instruction{
-                    .LoadStoreRegister = .{
-                        .rt = rt.id(),
-                        .rn = rn.id(),
-                        .offset = offset.toU12(),
-                        .opc = opc,
-                        .op1 = op1,
-                        .v = 0,
-                        .size = 0b11,
-                    },
-                };
+        return Instruction{
+            .LoadStoreRegister = .{
+                .rt = rt.id(),
+                .rn = rn.id(),
+                .offset = off,
+                .opc = opc,
+                .op1 = op1,
+                .v = 0,
+                .size = blk: {
+                    switch (variant) {
+                        .normal => switch (rt.size()) {
+                            32 => break :blk 0b10,
+                            64 => break :blk 0b11,
+                            else => unreachable, // unexpected register size
+                        },
+                        .half => break :blk 0b01,
+                        .byte => break :blk 0b00,
+                    }
+                },
             },
-            else => unreachable, // unexpected register size
-        }
+        };
     }
 
     fn loadStorePairOfRegisters(
@@ -748,7 +756,7 @@ pub const Instruction = union(enum) {
 
     pub fn ldr(rt: Register, args: LdrArgs) Instruction {
         switch (args) {
-            .register => |info| return loadStoreRegister(rt, info.rn, info.offset, true),
+            .register => |info| return loadStoreRegister(rt, info.rn, info.offset, .normal, true),
             .literal => |literal| return loadLiteral(rt, literal),
         }
     }
@@ -758,7 +766,15 @@ pub const Instruction = union(enum) {
     };
 
     pub fn str(rt: Register, rn: Register, args: StrArgs) Instruction {
-        return loadStoreRegister(rt, rn, args.offset, false);
+        return loadStoreRegister(rt, rn, args.offset, .normal, false);
+    }
+
+    pub fn strh(rt: Register, rn: Register, args: StrArgs) Instruction {
+        return loadStoreRegister(rt, rn, args.offset, .half, false);
+    }
+
+    pub fn strb(rt: Register, rn: Register, args: StrArgs) Instruction {
+        return loadStoreRegister(rt, rn, args.offset, .byte, false);
     }
 
     // Load or store pair of registers
@@ -996,6 +1012,14 @@ test "serialize instructions" {
             .inst = Instruction.str(.x2, .x1, .{ .offset = Instruction.LoadStoreOffset.reg(.x3) }),
             .expected = 0b11_111_0_00_00_1_00011_011_0_10_00001_00010,
         },
+        .{ // strh w0, [x1]
+            .inst = Instruction.strh(.w0, .x1, .{}),
+            .expected = 0b01_111_0_01_00_000000000000_00001_00000,
+        },
+        .{ // strb w8, [x9]
+            .inst = Instruction.strb(.w8, .x9, .{}),
+            .expected = 0b00_111_0_01_00_000000000000_01001_01000,
+        },
         .{ // adr x2, #0x8
             .inst = Instruction.adr(.x2, 0x8),
             .expected = 0b0_00_10000_0000000000000000010_00010,
src/codegen.zig
@@ -3111,7 +3111,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
                         const adj_off = stack_offset + abi_size;
 
                         switch (abi_size) {
-                            4, 8 => {
+                            1, 2, 4, 8 => {
                                 const offset = if (math.cast(i9, adj_off)) |imm|
                                     Instruction.LoadStoreOffset.imm_post_index(-imm)
                                 else |_|
@@ -3121,8 +3121,14 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
                                     .aarch64_32 => .w29,
                                     else => unreachable,
                                 };
+                                const str = switch (abi_size) {
+                                    1 => Instruction.strb,
+                                    2 => Instruction.strh,
+                                    4, 8 => Instruction.str,
+                                    else => unreachable, // unexpected abi size
+                                };
 
-                                writeInt(u32, try self.code.addManyAsArray(4), Instruction.str(reg, rn, .{
+                                writeInt(u32, try self.code.addManyAsArray(4), str(reg, rn, .{
                                     .offset = offset,
                                 }).toU32());
                             },