diff options
| author | joachimschmidt557 <joachim.schmidt557@outlook.com> | 2021-04-02 18:57:49 +0200 |
|---|---|---|
| committer | Andrew Kelley <andrew@ziglang.org> | 2021-04-02 14:46:30 -0700 |
| commit | 43d364afef7f0609f9d897c7ff129ba6b9b3cab0 (patch) | |
| tree | eb4cf7dc62230a55b03f166ffbecd8c463ef97e9 /src | |
| parent | 12e25237309a0e358418e17ed1a71e123b89a7be (diff) | |
| download | zig-43d364afef7f0609f9d897c7ff129ba6b9b3cab0.tar.gz zig-43d364afef7f0609f9d897c7ff129ba6b9b3cab0.zip | |
stage2 AArch64: Add ldrh and ldrb instructions
Diffstat (limited to 'src')
| -rw-r--r-- | src/codegen.zig | 37 | ||||
| -rw-r--r-- | src/codegen/aarch64.zig | 52 |
2 files changed, 75 insertions, 14 deletions
diff --git a/src/codegen.zig b/src/codegen.zig index beb3540d37..fbd412ceba 100644 --- a/src/codegen.zig +++ b/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) { diff --git a/src/codegen/aarch64.zig b/src/codegen/aarch64.zig index b80606fe93..38d2842df9 100644 --- a/src/codegen/aarch64.zig +++ b/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, |
