authorgravatar for joachim.schmidt557@outlook.comJoachim Schmidt <joachim.schmidt557@outlook.com> 2021-04-02 18:57:49+02:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-04-02 14:46:30-07:00
log43d364afef7f0609f9d897c7ff129ba6b9b3cab0
treeeb4cf7dc62230a55b03f166ffbecd8c463ef97e9
parent12e25237309a0e358418e17ed1a71e123b89a7be

stage2 AArch64: Add ldrh and ldrb instructions


2 files changed, 75 insertions(+), 14 deletions(-)

src/codegen.zig+37
...@@ -3302,6 +3302,43 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -3302,6 +3302,43 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
3302 mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.ldr(reg, .{ .register = .{ .rn = reg } }).toU32());3302 mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.ldr(reg, .{ .register = .{ .rn = reg } }).toU32());
3303 }3303 }
3304 },3304 },
3305 .stack_offset => |unadjusted_off| {
3306 // TODO: maybe addressing from sp instead of fp
3307 const abi_size = ty.abiSize(self.target.*);
3308 const adj_off = unadjusted_off + abi_size;
3309
3310 const rn: Register = switch (arch) {
3311 .aarch64, .aarch64_be => .x29,
3312 .aarch64_32 => .w29,
3313 else => unreachable,
3314 };
3315
3316 const offset = if (math.cast(i9, adj_off)) |imm|
3317 Instruction.LoadStoreOffset.imm_post_index(-imm)
3318 else |_|
3319 Instruction.LoadStoreOffset.reg(try self.copyToTmpRegister(src, Type.initTag(.u64), MCValue{ .immediate = adj_off }));
3320
3321 switch (abi_size) {
3322 1, 2 => {
3323 const ldr = switch (abi_size) {
3324 1 => Instruction.ldrb,
3325 2 => Instruction.ldrh,
3326 else => unreachable, // unexpected abi size
3327 };
3328
3329 writeInt(u32, try self.code.addManyAsArray(4), ldr(reg, rn, .{
3330 .offset = offset,
3331 }).toU32());
3332 },
3333 4, 8 => {
3334 writeInt(u32, try self.code.addManyAsArray(4), Instruction.ldr(reg, .{ .register = .{
3335 .rn = rn,
3336 .offset = offset,
3337 } }).toU32());
3338 },
3339 else => return self.fail(src, "TODO implement genSetReg other types abi_size={}", .{abi_size}),
3340 }
3341 },
3305 else => return self.fail(src, "TODO implement genSetReg for aarch64 {}", .{mcv}),3342 else => return self.fail(src, "TODO implement genSetReg for aarch64 {}", .{mcv}),
3306 },3343 },
3307 .riscv64 => switch (mcv) {3344 .riscv64 => switch (mcv) {
src/codegen/aarch64.zig+38-14
...@@ -487,11 +487,17 @@ pub const Instruction = union(enum) {...@@ -487,11 +487,17 @@ pub const Instruction = union(enum) {
487 /// Which kind of load/store to perform487 /// Which kind of load/store to perform
488 const LoadStoreVariant = enum {488 const LoadStoreVariant = enum {
489 /// 32-bit or 64-bit489 /// 32-bit or 64-bit
490 normal,490 str,
491 /// 16-bit491 /// 16-bit, zero-extended
492 half,492 strh,
493 /// 8-bit493 /// 8-bit, zero-extended
494 byte,494 strb,
495 /// 32-bit or 64-bit
496 ldr,
497 /// 16-bit, zero-extended
498 ldrh,
499 /// 8-bit, zero-extended
500 ldrb,
495 };501 };
496502
497 fn loadStoreRegister(503 fn loadStoreRegister(
...@@ -499,7 +505,6 @@ pub const Instruction = union(enum) {...@@ -499,7 +505,6 @@ pub const Instruction = union(enum) {
499 rn: Register,505 rn: Register,
500 offset: LoadStoreOffset,506 offset: LoadStoreOffset,
501 variant: LoadStoreVariant,507 variant: LoadStoreVariant,
502 load: bool,
503 ) Instruction {508 ) Instruction {
504 const off = offset.toU12();509 const off = offset.toU12();
505 const op1: u2 = blk: {510 const op1: u2 = blk: {
...@@ -512,7 +517,10 @@ pub const Instruction = union(enum) {...@@ -512,7 +517,10 @@ pub const Instruction = union(enum) {
512 }517 }
513 break :blk 0b00;518 break :blk 0b00;
514 };519 };
515 const opc: u2 = if (load) 0b01 else 0b00;520 const opc: u2 = switch (variant) {
521 .ldr, .ldrh, .ldrb => 0b01,
522 .str, .strh, .strb => 0b00,
523 };
516 return Instruction{524 return Instruction{
517 .LoadStoreRegister = .{525 .LoadStoreRegister = .{
518 .rt = rt.id(),526 .rt = rt.id(),
...@@ -523,13 +531,13 @@ pub const Instruction = union(enum) {...@@ -523,13 +531,13 @@ pub const Instruction = union(enum) {
523 .v = 0,531 .v = 0,
524 .size = blk: {532 .size = blk: {
525 switch (variant) {533 switch (variant) {
526 .normal => switch (rt.size()) {534 .ldr, .str => switch (rt.size()) {
527 32 => break :blk 0b10,535 32 => break :blk 0b10,
528 64 => break :blk 0b11,536 64 => break :blk 0b11,
529 else => unreachable, // unexpected register size537 else => unreachable, // unexpected register size
530 },538 },
531 .half => break :blk 0b01,539 .ldrh, .strh => break :blk 0b01,
532 .byte => break :blk 0b00,540 .ldrb, .strb => break :blk 0b00,
533 }541 }
534 },542 },
535 },543 },
...@@ -756,25 +764,33 @@ pub const Instruction = union(enum) {...@@ -756,25 +764,33 @@ pub const Instruction = union(enum) {
756764
757 pub fn ldr(rt: Register, args: LdrArgs) Instruction {765 pub fn ldr(rt: Register, args: LdrArgs) Instruction {
758 switch (args) {766 switch (args) {
759 .register => |info| return loadStoreRegister(rt, info.rn, info.offset, .normal, true),767 .register => |info| return loadStoreRegister(rt, info.rn, info.offset, .ldr),
760 .literal => |literal| return loadLiteral(rt, literal),768 .literal => |literal| return loadLiteral(rt, literal),
761 }769 }
762 }770 }
763771
772 pub fn ldrh(rt: Register, rn: Register, args: StrArgs) Instruction {
773 return loadStoreRegister(rt, rn, args.offset, .ldrh);
774 }
775
776 pub fn ldrb(rt: Register, rn: Register, args: StrArgs) Instruction {
777 return loadStoreRegister(rt, rn, args.offset, .ldrb);
778 }
779
764 pub const StrArgs = struct {780 pub const StrArgs = struct {
765 offset: LoadStoreOffset = LoadStoreOffset.none,781 offset: LoadStoreOffset = LoadStoreOffset.none,
766 };782 };
767783
768 pub fn str(rt: Register, rn: Register, args: StrArgs) Instruction {784 pub fn str(rt: Register, rn: Register, args: StrArgs) Instruction {
769 return loadStoreRegister(rt, rn, args.offset, .normal, false);785 return loadStoreRegister(rt, rn, args.offset, .str);
770 }786 }
771787
772 pub fn strh(rt: Register, rn: Register, args: StrArgs) Instruction {788 pub fn strh(rt: Register, rn: Register, args: StrArgs) Instruction {
773 return loadStoreRegister(rt, rn, args.offset, .half, false);789 return loadStoreRegister(rt, rn, args.offset, .strh);
774 }790 }
775791
776 pub fn strb(rt: Register, rn: Register, args: StrArgs) Instruction {792 pub fn strb(rt: Register, rn: Register, args: StrArgs) Instruction {
777 return loadStoreRegister(rt, rn, args.offset, .byte, false);793 return loadStoreRegister(rt, rn, args.offset, .strb);
778 }794 }
779795
780 // Load or store pair of registers796 // Load or store pair of registers
...@@ -1004,6 +1020,14 @@ test "serialize instructions" {...@@ -1004,6 +1020,14 @@ test "serialize instructions" {
1004 .inst = Instruction.ldr(.x2, .{ .literal = 0x1 }),1020 .inst = Instruction.ldr(.x2, .{ .literal = 0x1 }),
1005 .expected = 0b01_011_0_00_0000000000000000001_00010,1021 .expected = 0b01_011_0_00_0000000000000000001_00010,
1006 },1022 },
1023 .{ // ldrh x7, [x4], #0xaa
1024 .inst = Instruction.ldrh(.x7, .x4, .{ .offset = Instruction.LoadStoreOffset.imm_post_index(0xaa) }),
1025 .expected = 0b01_111_0_00_01_0_010101010_01_00100_00111,
1026 },
1027 .{ // ldrb x9, [x15, #0xff]!
1028 .inst = Instruction.ldrb(.x9, .x15, .{ .offset = Instruction.LoadStoreOffset.imm_pre_index(0xff) }),
1029 .expected = 0b00_111_0_00_01_0_011111111_11_01111_01001,
1030 },
1007 .{ // str x2, [x1]1031 .{ // str x2, [x1]
1008 .inst = Instruction.str(.x2, .x1, .{}),1032 .inst = Instruction.str(.x2, .x1, .{}),
1009 .expected = 0b11_111_0_01_00_000000000000_00001_00010,1033 .expected = 0b11_111_0_01_00_000000000000_00001_00010,