| author | |
| committer | |
| log | d2a297c2b3eb293b393f41640892ff7a5a71027f |
| tree | 08f48ee321f3114ba6eebc71c592f40ca8247d1c |
| parent | fbd5fbe729b7d3f085d2d479ed9957decc019332 |
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 | 2630 | .register => |reg| { |
| 2631 | 2631 | const abi_size = ty.abiSize(self.target.*); |
| 2632 | 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); | |
| 2636 | 2633 | |
| 2637 | 2634 | switch (abi_size) { |
| 2638 | 1 => writeInt(u32, try self.code.addManyAsArray(4), Instruction.strb(.al, reg, .fp, .{ | |
| 2639 | .offset = offset, | |
| 2640 | .positive = false, | |
| 2641 | }).toU32()), | |
| 2642 | 2 => return self.fail(src, "TODO implement strh", .{}), | |
| 2643 | 4 => writeInt(u32, try self.code.addManyAsArray(4), Instruction.str(.al, reg, .fp, .{ | |
| 2644 | .offset = offset, | |
| 2645 | .positive = false, | |
| 2646 | }).toU32()), | |
| 2647 | else => return self.fail(src, "TODO a type of size {} is not allowed in a register", .{abi_size}), | |
| 2635 | 1, 4 => { | |
| 2636 | const offset = if (adj_off <= math.maxInt(u12)) blk: { | |
| 2637 | break :blk Instruction.Offset.imm(@intCast(u12, adj_off)); | |
| 2638 | } else Instruction.Offset.reg(try self.copyToTmpRegister(src, MCValue{ .immediate = adj_off }), 0); | |
| 2639 | const str = switch (abi_size) { | |
| 2640 | 1 => Instruction.strb, | |
| 2641 | 4 => Instruction.str, | |
| 2642 | else => unreachable, | |
| 2643 | }; | |
| 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 | 2663 | .memory => |vaddr| { |
| ... | ... | @@ -2836,20 +2849,33 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 2836 | 2849 | // const abi_size = ty.abiSize(self.target.*); |
| 2837 | 2850 | const abi_size = 4; |
| 2838 | 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); | |
| 2842 | 2852 | |
| 2843 | 2853 | switch (abi_size) { |
| 2844 | 1 => writeInt(u32, try self.code.addManyAsArray(4), Instruction.ldrb(.al, reg, .fp, .{ | |
| 2845 | .offset = offset, | |
| 2846 | .positive = false, | |
| 2847 | }).toU32()), | |
| 2848 | 2 => return self.fail(src, "TODO implement ldrh", .{}), | |
| 2849 | 4 => writeInt(u32, try self.code.addManyAsArray(4), Instruction.ldr(.al, reg, .fp, .{ | |
| 2850 | .offset = offset, | |
| 2851 | .positive = false, | |
| 2852 | }).toU32()), | |
| 2854 | 1, 4 => { | |
| 2855 | const offset = if (adj_off <= math.maxInt(u12)) blk: { | |
| 2856 | break :blk Instruction.Offset.imm(@intCast(u12, adj_off)); | |
| 2857 | } else Instruction.Offset.reg(try self.copyToTmpRegister(src, MCValue{ .immediate = adj_off }), 0); | |
| 2858 | const ldr = switch (abi_size) { | |
| 2859 | 1 => Instruction.ldrb, | |
| 2860 | 4 => Instruction.ldr, | |
| 2861 | else => unreachable, | |
| 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 | 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 | 240 | fixed: u2 = 0b01, |
| 241 | 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 | 259 | BlockDataTransfer: packed struct { |
| 244 | 260 | register_list: u16, |
| 245 | 261 | rn: u4, |
| ... | ... | @@ -468,6 +484,29 @@ pub const Instruction = union(enum) { |
| 468 | 484 | } |
| 469 | 485 | }; |
| 470 | 486 | |
| 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 | 510 | /// Represents the register list operand to a block data transfer |
| 472 | 511 | /// instruction |
| 473 | 512 | pub const RegisterList = packed struct { |
| ... | ... | @@ -495,6 +534,7 @@ pub const Instruction = union(enum) { |
| 495 | 534 | .Multiply => |v| @bitCast(u32, v), |
| 496 | 535 | .MultiplyLong => |v| @bitCast(u32, v), |
| 497 | 536 | .SingleDataTransfer => |v| @bitCast(u32, v), |
| 537 | .ExtraLoadStore => |v| @bitCast(u32, v), | |
| 498 | 538 | .BlockDataTransfer => |v| @bitCast(u32, v), |
| 499 | 539 | .Branch => |v| @bitCast(u32, v), |
| 500 | 540 | .BranchExchange => |v| @bitCast(u32, v), |
| ... | ... | @@ -617,6 +657,43 @@ pub const Instruction = union(enum) { |
| 617 | 657 | }; |
| 618 | 658 | } |
| 619 | 659 | |
| 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 | 697 | fn blockDataTransfer( |
| 621 | 698 | cond: Condition, |
| 622 | 699 | rn: Register, |
| ... | ... | @@ -913,6 +990,23 @@ pub const Instruction = union(enum) { |
| 913 | 990 | return singleDataTransfer(cond, rd, rn, args.offset, args.pre_index, args.positive, 1, args.write_back, 0); |
| 914 | 991 | } |
| 915 | 992 | |
| 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 | 1010 | // Block data transfer |
| 917 | 1011 | |
| 918 | 1012 | pub fn ldmda(cond: Condition, rn: Register, write_back: bool, reg_list: RegisterList) Instruction { |
| ... | ... | @@ -1093,6 +1187,12 @@ test "serialize instructions" { |
| 1093 | 1187 | }), |
| 1094 | 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 | 1196 | .{ // b #12 |
| 1097 | 1197 | .inst = Instruction.b(.al, 12), |
| 1098 | 1198 | .expected = 0b1110_101_0_0000_0000_0000_0000_0000_0011, |