authorgravatar for joachim.schmidt557@outlook.comJoachim Schmidt <joachim.schmidt557@outlook.com> 2021-01-10 20:50:38+01:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-01-16 12:06:31-08:00
logd2a297c2b3eb293b393f41640892ff7a5a71027f
tree08f48ee321f3114ba6eebc71c592f40ca8247d1c
parentfbd5fbe729b7d3f085d2d479ed9957decc019332

stage2 ARM: add extra load/store instructions


2 files changed, 151 insertions(+), 25 deletions(-)

src/codegen.zig+51-25
...@@ -2630,21 +2630,34 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -2630,21 +2630,34 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
2630 .register => |reg| {2630 .register => |reg| {
2631 const abi_size = ty.abiSize(self.target.*);2631 const abi_size = ty.abiSize(self.target.*);
2632 const adj_off = stack_offset + abi_size;2632 const adj_off = stack_offset + abi_size;
2633 const offset = if (adj_off <= math.maxInt(u12)) blk: {
2634 break :blk Instruction.Offset.imm(@intCast(u12, adj_off));
2635 } else Instruction.Offset.reg(try self.copyToTmpRegister(src, MCValue{ .immediate = adj_off }), 0);
26362633
2637 switch (abi_size) {2634 switch (abi_size) {
2638 1 => writeInt(u32, try self.code.addManyAsArray(4), Instruction.strb(.al, reg, .fp, .{2635 1, 4 => {
2639 .offset = offset,2636 const offset = if (adj_off <= math.maxInt(u12)) blk: {
2640 .positive = false,2637 break :blk Instruction.Offset.imm(@intCast(u12, adj_off));
2641 }).toU32()),2638 } else Instruction.Offset.reg(try self.copyToTmpRegister(src, MCValue{ .immediate = adj_off }), 0);
2642 2 => return self.fail(src, "TODO implement strh", .{}),2639 const str = switch (abi_size) {
2643 4 => writeInt(u32, try self.code.addManyAsArray(4), Instruction.str(.al, reg, .fp, .{2640 1 => Instruction.strb,
2644 .offset = offset,2641 4 => Instruction.str,
2645 .positive = false,2642 else => unreachable,
2646 }).toU32()),2643 };
2647 else => return self.fail(src, "TODO a type of size {} is not allowed in a register", .{abi_size}),2644
2645 writeInt(u32, try self.code.addManyAsArray(4), str(.al, reg, .fp, .{
2646 .offset = offset,
2647 .positive = false,
2648 }).toU32());
2649 },
2650 2 => {
2651 const offset = if (adj_off <= math.maxInt(u8)) blk: {
2652 break :blk Instruction.ExtraLoadStoreOffset.imm(@intCast(u8, adj_off));
2653 } else Instruction.ExtraLoadStoreOffset.reg(try self.copyToTmpRegister(src, MCValue{ .immediate = adj_off }));
2654
2655 writeInt(u32, try self.code.addManyAsArray(4), Instruction.strh(.al, reg, .fp, .{
2656 .offset = offset,
2657 .positive = false,
2658 }).toU32());
2659 },
2660 else => return self.fail(src, "TODO implement storing other types abi_size={}", .{abi_size}),
2648 }2661 }
2649 },2662 },
2650 .memory => |vaddr| {2663 .memory => |vaddr| {
...@@ -2836,20 +2849,33 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -2836,20 +2849,33 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
2836 // const abi_size = ty.abiSize(self.target.*);2849 // const abi_size = ty.abiSize(self.target.*);
2837 const abi_size = 4;2850 const abi_size = 4;
2838 const adj_off = unadjusted_off + abi_size;2851 const adj_off = unadjusted_off + abi_size;
2839 const offset = if (adj_off <= math.maxInt(u12)) blk: {
2840 break :blk Instruction.Offset.imm(@intCast(u12, adj_off));
2841 } else Instruction.Offset.reg(try self.copyToTmpRegister(src, MCValue{ .immediate = adj_off }), 0);
28422852
2843 switch (abi_size) {2853 switch (abi_size) {
2844 1 => writeInt(u32, try self.code.addManyAsArray(4), Instruction.ldrb(.al, reg, .fp, .{2854 1, 4 => {
2845 .offset = offset,2855 const offset = if (adj_off <= math.maxInt(u12)) blk: {
2846 .positive = false,2856 break :blk Instruction.Offset.imm(@intCast(u12, adj_off));
2847 }).toU32()),2857 } else Instruction.Offset.reg(try self.copyToTmpRegister(src, MCValue{ .immediate = adj_off }), 0);
2848 2 => return self.fail(src, "TODO implement ldrh", .{}),2858 const ldr = switch (abi_size) {
2849 4 => writeInt(u32, try self.code.addManyAsArray(4), Instruction.ldr(.al, reg, .fp, .{2859 1 => Instruction.ldrb,
2850 .offset = offset,2860 4 => Instruction.ldr,
2851 .positive = false,2861 else => unreachable,
2852 }).toU32()),2862 };
2863
2864 writeInt(u32, try self.code.addManyAsArray(4), ldr(.al, reg, .fp, .{
2865 .offset = offset,
2866 .positive = false,
2867 }).toU32());
2868 },
2869 2 => {
2870 const offset = if (adj_off <= math.maxInt(u8)) blk: {
2871 break :blk Instruction.ExtraLoadStoreOffset.imm(@intCast(u8, adj_off));
2872 } else Instruction.ExtraLoadStoreOffset.reg(try self.copyToTmpRegister(src, MCValue{ .immediate = adj_off }));
2873
2874 writeInt(u32, try self.code.addManyAsArray(4), Instruction.ldrh(.al, reg, .fp, .{
2875 .offset = offset,
2876 .positive = false,
2877 }).toU32());
2878 },
2853 else => return self.fail(src, "TODO a type of size {} is not allowed in a register", .{abi_size}),2879 else => return self.fail(src, "TODO a type of size {} is not allowed in a register", .{abi_size}),
2854 }2880 }
2855 },2881 },
src/codegen/arm.zig+100
...@@ -240,6 +240,22 @@ pub const Instruction = union(enum) {...@@ -240,6 +240,22 @@ pub const Instruction = union(enum) {
240 fixed: u2 = 0b01,240 fixed: u2 = 0b01,
241 cond: u4,241 cond: u4,
242 },242 },
243 ExtraLoadStore: packed struct {
244 imm4l: u4,
245 fixed_1: u1 = 0b1,
246 op2: u2,
247 fixed_2: u1 = 0b1,
248 imm4h: u4,
249 rt: u4,
250 rn: u4,
251 o1: u1,
252 write_back: u1,
253 imm: u1,
254 up_down: u1,
255 pre_index: u1,
256 fixed_3: u3 = 0b000,
257 cond: u4,
258 },
243 BlockDataTransfer: packed struct {259 BlockDataTransfer: packed struct {
244 register_list: u16,260 register_list: u16,
245 rn: u4,261 rn: u4,
...@@ -468,6 +484,29 @@ pub const Instruction = union(enum) {...@@ -468,6 +484,29 @@ pub const Instruction = union(enum) {
468 }484 }
469 };485 };
470486
487 /// Represents the offset operand of an extra load or store
488 /// instruction.
489 pub const ExtraLoadStoreOffset = union(enum) {
490 immediate: u8,
491 register: u4,
492
493 pub const none = ExtraLoadStoreOffset{
494 .immediate = 0,
495 };
496
497 pub fn reg(register: Register) ExtraLoadStoreOffset {
498 return ExtraLoadStoreOffset{
499 .register = register.id(),
500 };
501 }
502
503 pub fn imm(immediate: u8) ExtraLoadStoreOffset {
504 return ExtraLoadStoreOffset{
505 .immediate = immediate,
506 };
507 }
508 };
509
471 /// Represents the register list operand to a block data transfer510 /// Represents the register list operand to a block data transfer
472 /// instruction511 /// instruction
473 pub const RegisterList = packed struct {512 pub const RegisterList = packed struct {
...@@ -495,6 +534,7 @@ pub const Instruction = union(enum) {...@@ -495,6 +534,7 @@ pub const Instruction = union(enum) {
495 .Multiply => |v| @bitCast(u32, v),534 .Multiply => |v| @bitCast(u32, v),
496 .MultiplyLong => |v| @bitCast(u32, v),535 .MultiplyLong => |v| @bitCast(u32, v),
497 .SingleDataTransfer => |v| @bitCast(u32, v),536 .SingleDataTransfer => |v| @bitCast(u32, v),
537 .ExtraLoadStore => |v| @bitCast(u32, v),
498 .BlockDataTransfer => |v| @bitCast(u32, v),538 .BlockDataTransfer => |v| @bitCast(u32, v),
499 .Branch => |v| @bitCast(u32, v),539 .Branch => |v| @bitCast(u32, v),
500 .BranchExchange => |v| @bitCast(u32, v),540 .BranchExchange => |v| @bitCast(u32, v),
...@@ -617,6 +657,43 @@ pub const Instruction = union(enum) {...@@ -617,6 +657,43 @@ pub const Instruction = union(enum) {
617 };657 };
618 }658 }
619659
660 fn extraLoadStore(
661 cond: Condition,
662 pre_index: bool,
663 positive: bool,
664 write_back: bool,
665 o1: u1,
666 op2: u2,
667 rn: Register,
668 rt: Register,
669 offset: ExtraLoadStoreOffset,
670 ) Instruction {
671 const imm4l: u4 = switch (offset) {
672 .immediate => |imm| @truncate(u4, imm),
673 .register => |reg| reg,
674 };
675 const imm4h: u4 = switch (offset) {
676 .immediate => |imm| @truncate(u4, imm >> 4),
677 .register => |reg| 0b0000,
678 };
679
680 return Instruction{
681 .ExtraLoadStore = .{
682 .imm4l = imm4l,
683 .op2 = op2,
684 .imm4h = imm4h,
685 .rt = rt.id(),
686 .rn = rn.id(),
687 .o1 = o1,
688 .write_back = @boolToInt(write_back),
689 .imm = @boolToInt(offset == .immediate),
690 .up_down = @boolToInt(positive),
691 .pre_index = @boolToInt(pre_index),
692 .cond = @enumToInt(cond),
693 },
694 };
695 }
696
620 fn blockDataTransfer(697 fn blockDataTransfer(
621 cond: Condition,698 cond: Condition,
622 rn: Register,699 rn: Register,
...@@ -913,6 +990,23 @@ pub const Instruction = union(enum) {...@@ -913,6 +990,23 @@ pub const Instruction = union(enum) {
913 return singleDataTransfer(cond, rd, rn, args.offset, args.pre_index, args.positive, 1, args.write_back, 0);990 return singleDataTransfer(cond, rd, rn, args.offset, args.pre_index, args.positive, 1, args.write_back, 0);
914 }991 }
915992
993 // Extra load/store
994
995 pub const ExtraLoadStoreOffsetArgs = struct {
996 pre_index: bool = true,
997 positive: bool = true,
998 offset: ExtraLoadStoreOffset,
999 write_back: bool = false,
1000 };
1001
1002 pub fn strh(cond: Condition, rt: Register, rn: Register, args: ExtraLoadStoreOffsetArgs) Instruction {
1003 return extraLoadStore(cond, args.pre_index, args.positive, args.write_back, 0, 0b01, rn, rt, args.offset);
1004 }
1005
1006 pub fn ldrh(cond: Condition, rt: Register, rn: Register, args: ExtraLoadStoreOffsetArgs) Instruction {
1007 return extraLoadStore(cond, args.pre_index, args.positive, args.write_back, 1, 0b01, rn, rt, args.offset);
1008 }
1009
916 // Block data transfer1010 // Block data transfer
9171011
918 pub fn ldmda(cond: Condition, rn: Register, write_back: bool, reg_list: RegisterList) Instruction {1012 pub fn ldmda(cond: Condition, rn: Register, write_back: bool, reg_list: RegisterList) Instruction {
...@@ -1093,6 +1187,12 @@ test "serialize instructions" {...@@ -1093,6 +1187,12 @@ test "serialize instructions" {
1093 }),1187 }),
1094 .expected = 0b1110_01_0_1_1_0_0_0_0011_0000_000000000000,1188 .expected = 0b1110_01_0_1_1_0_0_0_0011_0000_000000000000,
1095 },1189 },
1190 .{ // strh r1, [r5]
1191 .inst = Instruction.strh(.al, .r1, .r5, .{
1192 .offset = Instruction.ExtraLoadStoreOffset.none,
1193 }),
1194 .expected = 0b1110_000_1_1_1_0_0_0101_0001_0000_1011_0000,
1195 },
1096 .{ // b #121196 .{ // b #12
1097 .inst = Instruction.b(.al, 12),1197 .inst = Instruction.b(.al, 12),
1098 .expected = 0b1110_101_0_0000_0000_0000_0000_0000_0011,1198 .expected = 0b1110_101_0_0000_0000_0000_0000_0000_0011,