Commit 43d364afef

joachimschmidt557 <joachim.schmidt557@outlook.com>
2021-04-02 18:57:49
stage2 AArch64: Add ldrh and ldrb instructions
1 parent 12e2523
Changed files (2)
src/codegen/aarch64.zig
@@ -487,11 +487,17 @@ pub const Instruction = union(enum) {
     /// Which kind of load/store to perform
     const LoadStoreVariant = enum {
         /// 32-bit or 64-bit
-        normal,
-        /// 16-bit
-        half,
-        /// 8-bit
-        byte,
+        str,
+        /// 16-bit, zero-extended
+        strh,
+        /// 8-bit, zero-extended
+        strb,
+        /// 32-bit or 64-bit
+        ldr,
+        /// 16-bit, zero-extended
+        ldrh,
+        /// 8-bit, zero-extended
+        ldrb,
     };
 
     fn loadStoreRegister(
@@ -499,7 +505,6 @@ pub const Instruction = union(enum) {
         rn: Register,
         offset: LoadStoreOffset,
         variant: LoadStoreVariant,
-        load: bool,
     ) Instruction {
         const off = offset.toU12();
         const op1: u2 = blk: {
@@ -512,7 +517,10 @@ pub const Instruction = union(enum) {
             }
             break :blk 0b00;
         };
-        const opc: u2 = if (load) 0b01 else 0b00;
+        const opc: u2 = switch (variant) {
+            .ldr, .ldrh, .ldrb => 0b01,
+            .str, .strh, .strb => 0b00,
+        };
         return Instruction{
             .LoadStoreRegister = .{
                 .rt = rt.id(),
@@ -523,13 +531,13 @@ pub const Instruction = union(enum) {
                 .v = 0,
                 .size = blk: {
                     switch (variant) {
-                        .normal => switch (rt.size()) {
+                        .ldr, .str => switch (rt.size()) {
                             32 => break :blk 0b10,
                             64 => break :blk 0b11,
                             else => unreachable, // unexpected register size
                         },
-                        .half => break :blk 0b01,
-                        .byte => break :blk 0b00,
+                        .ldrh, .strh => break :blk 0b01,
+                        .ldrb, .strb => break :blk 0b00,
                     }
                 },
             },
@@ -756,25 +764,33 @@ pub const Instruction = union(enum) {
 
     pub fn ldr(rt: Register, args: LdrArgs) Instruction {
         switch (args) {
-            .register => |info| return loadStoreRegister(rt, info.rn, info.offset, .normal, true),
+            .register => |info| return loadStoreRegister(rt, info.rn, info.offset, .ldr),
             .literal => |literal| return loadLiteral(rt, literal),
         }
     }
 
+    pub fn ldrh(rt: Register, rn: Register, args: StrArgs) Instruction {
+        return loadStoreRegister(rt, rn, args.offset, .ldrh);
+    }
+
+    pub fn ldrb(rt: Register, rn: Register, args: StrArgs) Instruction {
+        return loadStoreRegister(rt, rn, args.offset, .ldrb);
+    }
+
     pub const StrArgs = struct {
         offset: LoadStoreOffset = LoadStoreOffset.none,
     };
 
     pub fn str(rt: Register, rn: Register, args: StrArgs) Instruction {
-        return loadStoreRegister(rt, rn, args.offset, .normal, false);
+        return loadStoreRegister(rt, rn, args.offset, .str);
     }
 
     pub fn strh(rt: Register, rn: Register, args: StrArgs) Instruction {
-        return loadStoreRegister(rt, rn, args.offset, .half, false);
+        return loadStoreRegister(rt, rn, args.offset, .strh);
     }
 
     pub fn strb(rt: Register, rn: Register, args: StrArgs) Instruction {
-        return loadStoreRegister(rt, rn, args.offset, .byte, false);
+        return loadStoreRegister(rt, rn, args.offset, .strb);
     }
 
     // Load or store pair of registers
@@ -1004,6 +1020,14 @@ test "serialize instructions" {
             .inst = Instruction.ldr(.x2, .{ .literal = 0x1 }),
             .expected = 0b01_011_0_00_0000000000000000001_00010,
         },
+        .{ // ldrh x7, [x4], #0xaa
+            .inst = Instruction.ldrh(.x7, .x4, .{ .offset = Instruction.LoadStoreOffset.imm_post_index(0xaa) }),
+            .expected = 0b01_111_0_00_01_0_010101010_01_00100_00111,
+        },
+        .{ // ldrb x9, [x15, #0xff]!
+            .inst = Instruction.ldrb(.x9, .x15, .{ .offset = Instruction.LoadStoreOffset.imm_pre_index(0xff) }),
+            .expected = 0b00_111_0_00_01_0_011111111_11_01111_01001,
+        },
         .{ // str x2, [x1]
             .inst = Instruction.str(.x2, .x1, .{}),
             .expected = 0b11_111_0_01_00_000000000000_00001_00010,
src/codegen.zig
@@ -3302,6 +3302,43 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
                             mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.ldr(reg, .{ .register = .{ .rn = reg } }).toU32());
                         }
                     },
+                    .stack_offset => |unadjusted_off| {
+                        // TODO: maybe addressing from sp instead of fp
+                        const abi_size = ty.abiSize(self.target.*);
+                        const adj_off = unadjusted_off + abi_size;
+
+                        const rn: Register = switch (arch) {
+                            .aarch64, .aarch64_be => .x29,
+                            .aarch64_32 => .w29,
+                            else => unreachable,
+                        };
+
+                        const offset = if (math.cast(i9, adj_off)) |imm|
+                            Instruction.LoadStoreOffset.imm_post_index(-imm)
+                        else |_|
+                            Instruction.LoadStoreOffset.reg(try self.copyToTmpRegister(src, Type.initTag(.u64), MCValue{ .immediate = adj_off }));
+
+                        switch (abi_size) {
+                            1, 2 => {
+                                const ldr = switch (abi_size) {
+                                    1 => Instruction.ldrb,
+                                    2 => Instruction.ldrh,
+                                    else => unreachable, // unexpected abi size
+                                };
+
+                                writeInt(u32, try self.code.addManyAsArray(4), ldr(reg, rn, .{
+                                    .offset = offset,
+                                }).toU32());
+                            },
+                            4, 8 => {
+                                writeInt(u32, try self.code.addManyAsArray(4), Instruction.ldr(reg, .{ .register = .{
+                                    .rn = rn,
+                                    .offset = offset,
+                                } }).toU32());
+                            },
+                            else => return self.fail(src, "TODO implement genSetReg other types abi_size={}", .{abi_size}),
+                        }
+                    },
                     else => return self.fail(src, "TODO implement genSetReg for aarch64 {}", .{mcv}),
                 },
                 .riscv64 => switch (mcv) {