| author | |
| committer | |
| log | 7e76aab98abe94e01cfd8b01ce288360ed67dbc7 |
| tree | 8a6f96e1edca471e5571f60be72e5c3b659cd37d |
| parent | e945619728110affb389402ff1ce06d65470cdd2 |
3 files changed, 132 insertions(+), 110 deletions(-)
src/arch/aarch64/Emit.zig+42-38| ... | ... | @@ -112,12 +112,19 @@ pub fn emitMir( |
| 112 | 112 | .strb_stack => try emit.mirLoadStoreStack(inst), |
| 113 | 113 | .strh_stack => try emit.mirLoadStoreStack(inst), |
| 114 | 114 | |
| 115 | .ldr => try emit.mirLoadStoreRegister(inst), | |
| 116 | .ldrb => try emit.mirLoadStoreRegister(inst), | |
| 117 | .ldrh => try emit.mirLoadStoreRegister(inst), | |
| 118 | .str => try emit.mirLoadStoreRegister(inst), | |
| 119 | .strb => try emit.mirLoadStoreRegister(inst), | |
| 120 | .strh => try emit.mirLoadStoreRegister(inst), | |
| 115 | .ldr_register => try emit.mirLoadStoreRegisterRegister(inst), | |
| 116 | .ldrb_register => try emit.mirLoadStoreRegisterRegister(inst), | |
| 117 | .ldrh_register => try emit.mirLoadStoreRegisterRegister(inst), | |
| 118 | .str_register => try emit.mirLoadStoreRegisterRegister(inst), | |
| 119 | .strb_register => try emit.mirLoadStoreRegisterRegister(inst), | |
| 120 | .strh_register => try emit.mirLoadStoreRegisterRegister(inst), | |
| 121 | ||
| 122 | .ldr_immediate => try emit.mirLoadStoreRegisterImmediate(inst), | |
| 123 | .ldrb_immediate => try emit.mirLoadStoreRegisterImmediate(inst), | |
| 124 | .ldrh_immediate => try emit.mirLoadStoreRegisterImmediate(inst), | |
| 125 | .str_immediate => try emit.mirLoadStoreRegisterImmediate(inst), | |
| 126 | .strb_immediate => try emit.mirLoadStoreRegisterImmediate(inst), | |
| 127 | .strh_immediate => try emit.mirLoadStoreRegisterImmediate(inst), | |
| 121 | 128 | |
| 122 | 129 | .mov_register => try emit.mirMoveRegister(inst), |
| 123 | 130 | .mov_to_from_sp => try emit.mirMoveRegister(inst), |
| ... | ... | @@ -737,41 +744,38 @@ fn mirLoadStoreStack(emit: *Emit, inst: Mir.Inst.Index) !void { |
| 737 | 744 | } |
| 738 | 745 | } |
| 739 | 746 | |
| 740 | fn mirLoadStoreRegister(emit: *Emit, inst: Mir.Inst.Index) !void { | |
| 747 | fn mirLoadStoreRegisterImmediate(emit: *Emit, inst: Mir.Inst.Index) !void { | |
| 741 | 748 | const tag = emit.mir.instructions.items(.tag)[inst]; |
| 742 | const load_store_register = emit.mir.instructions.items(.data)[inst].load_store_register; | |
| 749 | const load_store_register_immediate = emit.mir.instructions.items(.data)[inst].load_store_register_immediate; | |
| 750 | const rt = load_store_register_immediate.rt; | |
| 751 | const rn = load_store_register_immediate.rn; | |
| 752 | const offset = Instruction.LoadStoreOffset{ .immediate = load_store_register_immediate.offset }; | |
| 743 | 753 | |
| 744 | 754 | switch (tag) { |
| 745 | .ldr => try emit.writeInstruction(Instruction.ldr( | |
| 746 | load_store_register.rt, | |
| 747 | load_store_register.rn, | |
| 748 | load_store_register.offset, | |
| 749 | )), | |
| 750 | .ldrb => try emit.writeInstruction(Instruction.ldrb( | |
| 751 | load_store_register.rt, | |
| 752 | load_store_register.rn, | |
| 753 | load_store_register.offset, | |
| 754 | )), | |
| 755 | .ldrh => try emit.writeInstruction(Instruction.ldrh( | |
| 756 | load_store_register.rt, | |
| 757 | load_store_register.rn, | |
| 758 | load_store_register.offset, | |
| 759 | )), | |
| 760 | .str => try emit.writeInstruction(Instruction.str( | |
| 761 | load_store_register.rt, | |
| 762 | load_store_register.rn, | |
| 763 | load_store_register.offset, | |
| 764 | )), | |
| 765 | .strb => try emit.writeInstruction(Instruction.strb( | |
| 766 | load_store_register.rt, | |
| 767 | load_store_register.rn, | |
| 768 | load_store_register.offset, | |
| 769 | )), | |
| 770 | .strh => try emit.writeInstruction(Instruction.strh( | |
| 771 | load_store_register.rt, | |
| 772 | load_store_register.rn, | |
| 773 | load_store_register.offset, | |
| 774 | )), | |
| 755 | .ldr_immediate => try emit.writeInstruction(Instruction.ldr(rt, rn, offset)), | |
| 756 | .ldrb_immediate => try emit.writeInstruction(Instruction.ldrb(rt, rn, offset)), | |
| 757 | .ldrh_immediate => try emit.writeInstruction(Instruction.ldrh(rt, rn, offset)), | |
| 758 | .str_immediate => try emit.writeInstruction(Instruction.str(rt, rn, offset)), | |
| 759 | .strb_immediate => try emit.writeInstruction(Instruction.strb(rt, rn, offset)), | |
| 760 | .strh_immediate => try emit.writeInstruction(Instruction.strh(rt, rn, offset)), | |
| 761 | else => unreachable, | |
| 762 | } | |
| 763 | } | |
| 764 | ||
| 765 | fn mirLoadStoreRegisterRegister(emit: *Emit, inst: Mir.Inst.Index) !void { | |
| 766 | const tag = emit.mir.instructions.items(.tag)[inst]; | |
| 767 | const load_store_register_register = emit.mir.instructions.items(.data)[inst].load_store_register_register; | |
| 768 | const rt = load_store_register_register.rt; | |
| 769 | const rn = load_store_register_register.rn; | |
| 770 | const offset = Instruction.LoadStoreOffset{ .register = load_store_register_register.offset }; | |
| 771 | ||
| 772 | switch (tag) { | |
| 773 | .ldr_register => try emit.writeInstruction(Instruction.ldr(rt, rn, offset)), | |
| 774 | .ldrb_register => try emit.writeInstruction(Instruction.ldrb(rt, rn, offset)), | |
| 775 | .ldrh_register => try emit.writeInstruction(Instruction.ldrh(rt, rn, offset)), | |
| 776 | .str_register => try emit.writeInstruction(Instruction.str(rt, rn, offset)), | |
| 777 | .strb_register => try emit.writeInstruction(Instruction.strb(rt, rn, offset)), | |
| 778 | .strh_register => try emit.writeInstruction(Instruction.strh(rt, rn, offset)), | |
| 775 | 779 | else => unreachable, |
| 776 | 780 | } |
| 777 | 781 | } |
src/arch/aarch64/Mir.zig+40-26| ... | ... | @@ -58,19 +58,22 @@ pub const Inst = struct { |
| 58 | 58 | ldp, |
| 59 | 59 | /// Pseudo-instruction: Load from stack |
| 60 | 60 | ldr_stack, |
| 61 | /// Load Register | |
| 62 | // TODO: split into ldr_immediate and ldr_register | |
| 63 | ldr, | |
| 61 | /// Load Register (immediate) | |
| 62 | ldr_immediate, | |
| 63 | /// Load Register (register) | |
| 64 | ldr_register, | |
| 64 | 65 | /// Pseudo-instruction: Load byte from stack |
| 65 | 66 | ldrb_stack, |
| 66 | /// Load Register Byte | |
| 67 | // TODO: split into ldrb_immediate and ldrb_register | |
| 68 | ldrb, | |
| 67 | /// Load Register Byte (immediate) | |
| 68 | ldrb_immediate, | |
| 69 | /// Load Register Byte (register) | |
| 70 | ldrb_register, | |
| 69 | 71 | /// Pseudo-instruction: Load halfword from stack |
| 70 | 72 | ldrh_stack, |
| 71 | /// Load Register Halfword | |
| 72 | // TODO: split into ldrh_immediate and ldrh_register | |
| 73 | ldrh, | |
| 73 | /// Load Register Halfword (immediate) | |
| 74 | ldrh_immediate, | |
| 75 | /// Load Register Halfword (register) | |
| 76 | ldrh_register, | |
| 74 | 77 | /// Move (to/from SP) |
| 75 | 78 | mov_to_from_sp, |
| 76 | 79 | /// Move (register) |
| ... | ... | @@ -91,19 +94,22 @@ pub const Inst = struct { |
| 91 | 94 | stp, |
| 92 | 95 | /// Pseudo-instruction: Store to stack |
| 93 | 96 | str_stack, |
| 94 | /// Store Register | |
| 95 | // TODO: split into str_immediate and str_register | |
| 96 | str, | |
| 97 | /// Store Register (immediate) | |
| 98 | str_immediate, | |
| 99 | /// Store Register (register) | |
| 100 | str_register, | |
| 97 | 101 | /// Pseudo-instruction: Store byte to stack |
| 98 | 102 | strb_stack, |
| 99 | /// Store Register Byte | |
| 100 | // TODO: split into strb_immediate and strb_register | |
| 101 | strb, | |
| 103 | /// Store Register Byte (immediate) | |
| 104 | strb_immediate, | |
| 105 | /// Store Register Byte (register) | |
| 106 | strb_register, | |
| 102 | 107 | /// Pseudo-instruction: Store halfword to stack |
| 103 | 108 | strh_stack, |
| 104 | /// Store Register Halfword | |
| 105 | // TODO: split into strh_immediate and strh_register | |
| 106 | strh, | |
| 109 | /// Store Register Halfword (immediate) | |
| 110 | strh_immediate, | |
| 111 | /// Store Register Halfword (register) | |
| 112 | strh_register, | |
| 107 | 113 | /// Subtract (immediate) |
| 108 | 114 | sub_immediate, |
| 109 | 115 | /// Supervisor Call |
| ... | ... | @@ -195,13 +201,21 @@ pub const Inst = struct { |
| 195 | 201 | rm: Register, |
| 196 | 202 | cond: bits.Instruction.Condition, |
| 197 | 203 | }, |
| 198 | /// Two registers and a LoadStoreOffset | |
| 204 | /// Two registers and a LoadStoreOffsetImmediate | |
| 199 | 205 | /// |
| 200 | 206 | /// Used by e.g. str_register |
| 201 | load_store_register: struct { | |
| 207 | load_store_register_immediate: struct { | |
| 202 | 208 | rt: Register, |
| 203 | 209 | rn: Register, |
| 204 | offset: bits.Instruction.LoadStoreOffset, | |
| 210 | offset: bits.Instruction.LoadStoreOffsetImmediate, | |
| 211 | }, | |
| 212 | /// Two registers and a LoadStoreOffsetRegister | |
| 213 | /// | |
| 214 | /// Used by e.g. str_register | |
| 215 | load_store_register_register: struct { | |
| 216 | rt: Register, | |
| 217 | rn: Register, | |
| 218 | offset: bits.Instruction.LoadStoreOffsetRegister, | |
| 205 | 219 | }, |
| 206 | 220 | /// A registers and a stack offset |
| 207 | 221 | /// |
| ... | ... | @@ -230,11 +244,11 @@ pub const Inst = struct { |
| 230 | 244 | |
| 231 | 245 | // Make sure we don't accidentally make instructions bigger than expected. |
| 232 | 246 | // Note that in Debug builds, Zig is allowed to insert a secret field for safety checks. |
| 233 | // comptime { | |
| 234 | // if (builtin.mode != .Debug) { | |
| 235 | // assert(@sizeOf(Inst) == 8); | |
| 236 | // } | |
| 237 | // } | |
| 247 | comptime { | |
| 248 | if (builtin.mode != .Debug) { | |
| 249 | assert(@sizeOf(Data) == 8); | |
| 250 | } | |
| 251 | } | |
| 238 | 252 | }; |
| 239 | 253 | |
| 240 | 254 | pub fn deinit(mir: *Mir, gpa: std.mem.Allocator) void { |
src/arch/aarch64/bits.zig+50-46| ... | ... | @@ -521,69 +521,73 @@ pub const Instruction = union(enum) { |
| 521 | 521 | }; |
| 522 | 522 | } |
| 523 | 523 | |
| 524 | pub const LoadStoreOffsetImmediate = union(enum) { | |
| 525 | post_index: i9, | |
| 526 | pre_index: i9, | |
| 527 | unsigned: u12, | |
| 528 | }; | |
| 529 | ||
| 530 | pub const LoadStoreOffsetRegister = struct { | |
| 531 | rm: u5, | |
| 532 | shift: union(enum) { | |
| 533 | uxtw: u2, | |
| 534 | lsl: u2, | |
| 535 | sxtw: u2, | |
| 536 | sxtx: u2, | |
| 537 | }, | |
| 538 | }; | |
| 539 | ||
| 524 | 540 | /// Represents the offset operand of a load or store instruction. |
| 525 | 541 | /// Data can be loaded from memory with either an immediate offset |
| 526 | 542 | /// or an offset that is stored in some register. |
| 527 | 543 | pub const LoadStoreOffset = union(enum) { |
| 528 | Immediate: union(enum) { | |
| 529 | PostIndex: i9, | |
| 530 | PreIndex: i9, | |
| 531 | Unsigned: u12, | |
| 532 | }, | |
| 533 | Register: struct { | |
| 534 | rm: u5, | |
| 535 | shift: union(enum) { | |
| 536 | Uxtw: u2, | |
| 537 | Lsl: u2, | |
| 538 | Sxtw: u2, | |
| 539 | Sxtx: u2, | |
| 540 | }, | |
| 541 | }, | |
| 544 | immediate: LoadStoreOffsetImmediate, | |
| 545 | register: LoadStoreOffsetRegister, | |
| 542 | 546 | |
| 543 | 547 | pub const none = LoadStoreOffset{ |
| 544 | .Immediate = .{ .Unsigned = 0 }, | |
| 548 | .immediate = .{ .unsigned = 0 }, | |
| 545 | 549 | }; |
| 546 | 550 | |
| 547 | 551 | pub fn toU12(self: LoadStoreOffset) u12 { |
| 548 | 552 | return switch (self) { |
| 549 | .Immediate => |imm_type| switch (imm_type) { | |
| 550 | .PostIndex => |v| (@intCast(u12, @bitCast(u9, v)) << 2) + 1, | |
| 551 | .PreIndex => |v| (@intCast(u12, @bitCast(u9, v)) << 2) + 3, | |
| 552 | .Unsigned => |v| v, | |
| 553 | .immediate => |imm_type| switch (imm_type) { | |
| 554 | .post_index => |v| (@intCast(u12, @bitCast(u9, v)) << 2) + 1, | |
| 555 | .pre_index => |v| (@intCast(u12, @bitCast(u9, v)) << 2) + 3, | |
| 556 | .unsigned => |v| v, | |
| 553 | 557 | }, |
| 554 | .Register => |r| switch (r.shift) { | |
| 555 | .Uxtw => |v| (@intCast(u12, r.rm) << 6) + (@intCast(u12, v) << 2) + 16 + 2050, | |
| 556 | .Lsl => |v| (@intCast(u12, r.rm) << 6) + (@intCast(u12, v) << 2) + 24 + 2050, | |
| 557 | .Sxtw => |v| (@intCast(u12, r.rm) << 6) + (@intCast(u12, v) << 2) + 48 + 2050, | |
| 558 | .Sxtx => |v| (@intCast(u12, r.rm) << 6) + (@intCast(u12, v) << 2) + 56 + 2050, | |
| 558 | .register => |r| switch (r.shift) { | |
| 559 | .uxtw => |v| (@intCast(u12, r.rm) << 6) + (@intCast(u12, v) << 2) + 16 + 2050, | |
| 560 | .lsl => |v| (@intCast(u12, r.rm) << 6) + (@intCast(u12, v) << 2) + 24 + 2050, | |
| 561 | .sxtw => |v| (@intCast(u12, r.rm) << 6) + (@intCast(u12, v) << 2) + 48 + 2050, | |
| 562 | .sxtx => |v| (@intCast(u12, r.rm) << 6) + (@intCast(u12, v) << 2) + 56 + 2050, | |
| 559 | 563 | }, |
| 560 | 564 | }; |
| 561 | 565 | } |
| 562 | 566 | |
| 563 | 567 | pub fn imm(offset: u12) LoadStoreOffset { |
| 564 | 568 | return .{ |
| 565 | .Immediate = .{ .Unsigned = offset }, | |
| 569 | .immediate = .{ .unsigned = offset }, | |
| 566 | 570 | }; |
| 567 | 571 | } |
| 568 | 572 | |
| 569 | 573 | pub fn imm_post_index(offset: i9) LoadStoreOffset { |
| 570 | 574 | return .{ |
| 571 | .Immediate = .{ .PostIndex = offset }, | |
| 575 | .immediate = .{ .post_index = offset }, | |
| 572 | 576 | }; |
| 573 | 577 | } |
| 574 | 578 | |
| 575 | 579 | pub fn imm_pre_index(offset: i9) LoadStoreOffset { |
| 576 | 580 | return .{ |
| 577 | .Immediate = .{ .PreIndex = offset }, | |
| 581 | .immediate = .{ .pre_index = offset }, | |
| 578 | 582 | }; |
| 579 | 583 | } |
| 580 | 584 | |
| 581 | 585 | pub fn reg(rm: Register) LoadStoreOffset { |
| 582 | 586 | return .{ |
| 583 | .Register = .{ | |
| 587 | .register = .{ | |
| 584 | 588 | .rm = rm.id(), |
| 585 | 589 | .shift = .{ |
| 586 | .Lsl = 0, | |
| 590 | .lsl = 0, | |
| 587 | 591 | }, |
| 588 | 592 | }, |
| 589 | 593 | }; |
| ... | ... | @@ -592,10 +596,10 @@ pub const Instruction = union(enum) { |
| 592 | 596 | pub fn reg_uxtw(rm: Register, shift: u2) LoadStoreOffset { |
| 593 | 597 | assert(rm.size() == 32 and (shift == 0 or shift == 2)); |
| 594 | 598 | return .{ |
| 595 | .Register = .{ | |
| 599 | .register = .{ | |
| 596 | 600 | .rm = rm.id(), |
| 597 | 601 | .shift = .{ |
| 598 | .Uxtw = shift, | |
| 602 | .uxtw = shift, | |
| 599 | 603 | }, |
| 600 | 604 | }, |
| 601 | 605 | }; |
| ... | ... | @@ -604,10 +608,10 @@ pub const Instruction = union(enum) { |
| 604 | 608 | pub fn reg_lsl(rm: Register, shift: u2) LoadStoreOffset { |
| 605 | 609 | assert(rm.size() == 64 and (shift == 0 or shift == 3)); |
| 606 | 610 | return .{ |
| 607 | .Register = .{ | |
| 611 | .register = .{ | |
| 608 | 612 | .rm = rm.id(), |
| 609 | 613 | .shift = .{ |
| 610 | .Lsl = shift, | |
| 614 | .lsl = shift, | |
| 611 | 615 | }, |
| 612 | 616 | }, |
| 613 | 617 | }; |
| ... | ... | @@ -616,10 +620,10 @@ pub const Instruction = union(enum) { |
| 616 | 620 | pub fn reg_sxtw(rm: Register, shift: u2) LoadStoreOffset { |
| 617 | 621 | assert(rm.size() == 32 and (shift == 0 or shift == 2)); |
| 618 | 622 | return .{ |
| 619 | .Register = .{ | |
| 623 | .register = .{ | |
| 620 | 624 | .rm = rm.id(), |
| 621 | 625 | .shift = .{ |
| 622 | .Sxtw = shift, | |
| 626 | .sxtw = shift, | |
| 623 | 627 | }, |
| 624 | 628 | }, |
| 625 | 629 | }; |
| ... | ... | @@ -628,10 +632,10 @@ pub const Instruction = union(enum) { |
| 628 | 632 | pub fn reg_sxtx(rm: Register, shift: u2) LoadStoreOffset { |
| 629 | 633 | assert(rm.size() == 64 and (shift == 0 or shift == 3)); |
| 630 | 634 | return .{ |
| 631 | .Register = .{ | |
| 635 | .register = .{ | |
| 632 | 636 | .rm = rm.id(), |
| 633 | 637 | .shift = .{ |
| 634 | .Sxtx = shift, | |
| 638 | .sxtx = shift, | |
| 635 | 639 | }, |
| 636 | 640 | }, |
| 637 | 641 | }; |
| ... | ... | @@ -663,8 +667,8 @@ pub const Instruction = union(enum) { |
| 663 | 667 | const off = offset.toU12(); |
| 664 | 668 | const op1: u2 = blk: { |
| 665 | 669 | switch (offset) { |
| 666 | .Immediate => |imm| switch (imm) { | |
| 667 | .Unsigned => break :blk 0b01, | |
| 670 | .immediate => |imm| switch (imm) { | |
| 671 | .unsigned => break :blk 0b01, | |
| 668 | 672 | else => {}, |
| 669 | 673 | }, |
| 670 | 674 | else => {}, |
| ... | ... | @@ -1023,26 +1027,26 @@ pub const Instruction = union(enum) { |
| 1023 | 1027 | |
| 1024 | 1028 | pub const LoadStorePairOffset = struct { |
| 1025 | 1029 | encoding: enum(u2) { |
| 1026 | PostIndex = 0b01, | |
| 1027 | Signed = 0b10, | |
| 1028 | PreIndex = 0b11, | |
| 1030 | post_index = 0b01, | |
| 1031 | signed = 0b10, | |
| 1032 | pre_index = 0b11, | |
| 1029 | 1033 | }, |
| 1030 | 1034 | offset: i9, |
| 1031 | 1035 | |
| 1032 | 1036 | pub fn none() LoadStorePairOffset { |
| 1033 | return .{ .encoding = .Signed, .offset = 0 }; | |
| 1037 | return .{ .encoding = .signed, .offset = 0 }; | |
| 1034 | 1038 | } |
| 1035 | 1039 | |
| 1036 | 1040 | pub fn post_index(imm: i9) LoadStorePairOffset { |
| 1037 | return .{ .encoding = .PostIndex, .offset = imm }; | |
| 1041 | return .{ .encoding = .post_index, .offset = imm }; | |
| 1038 | 1042 | } |
| 1039 | 1043 | |
| 1040 | 1044 | pub fn pre_index(imm: i9) LoadStorePairOffset { |
| 1041 | return .{ .encoding = .PreIndex, .offset = imm }; | |
| 1045 | return .{ .encoding = .pre_index, .offset = imm }; | |
| 1042 | 1046 | } |
| 1043 | 1047 | |
| 1044 | 1048 | pub fn signed(imm: i9) LoadStorePairOffset { |
| 1045 | return .{ .encoding = .Signed, .offset = imm }; | |
| 1049 | return .{ .encoding = .signed, .offset = imm }; | |
| 1046 | 1050 | } |
| 1047 | 1051 | }; |
| 1048 | 1052 |