| author | |
| committer | |
| log | 35b228630cf1972868fe820baeb41a09801f2fbb |
| tree | 8a7004ac9f4e3b02ed8ea9f94b08902760187f5e |
| parent | 0a54f04dbc4ce9a0a1d1b5fe9d1a5a502030b47e |
2 files changed, 84 insertions(+), 13 deletions(-)
src/codegen.zig+36-5| ... | ... | @@ -570,6 +570,35 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 570 | 570 | try self.dbgSetEpilogueBegin(); |
| 571 | 571 | } |
| 572 | 572 | }, |
| 573 | .arm => { | |
| 574 | const cc = self.fn_type.fnCallingConvention(); | |
| 575 | if (cc != .Naked) { | |
| 576 | // push {fp, lr} | |
| 577 | // mov fp, sp | |
| 578 | // sub sp, sp, #reloc | |
| 579 | // mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.mov(.al, .fp, Instruction.Operand.reg(.sp, Instruction.Operand.Shift.none)).toU32()); | |
| 580 | // const backpatch_reloc = try self.code.addManyAsArray(4); | |
| 581 | ||
| 582 | try self.dbgSetPrologueEnd(); | |
| 583 | ||
| 584 | try self.genBody(self.mod_fn.analysis.success); | |
| 585 | ||
| 586 | // Backpatch stack offset | |
| 587 | // const stack_end = self.max_end_stack; | |
| 588 | // const aligned_stack_end = mem.alignForward(stack_end, self.stack_align); | |
| 589 | // mem.writeIntLittle(u32, backpatch_reloc, Instruction.sub(.al, .sp, .sp, Instruction.Operand.imm())); | |
| 590 | ||
| 591 | try self.dbgSetEpilogueBegin(); | |
| 592 | ||
| 593 | // mov sp, fp | |
| 594 | // pop {fp, pc} | |
| 595 | mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.mov(.al, .sp, Instruction.Operand.reg(.fp, Instruction.Operand.Shift.none)).toU32()); | |
| 596 | } else { | |
| 597 | try self.dbgSetPrologueEnd(); | |
| 598 | try self.genBody(self.mod_fn.analysis.success); | |
| 599 | try self.dbgSetEpilogueBegin(); | |
| 600 | } | |
| 601 | }, | |
| 573 | 602 | else => { |
| 574 | 603 | try self.dbgSetPrologueEnd(); |
| 575 | 604 | try self.genBody(self.mod_fn.analysis.success); |
| ... | ... | @@ -1504,13 +1533,10 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 1504 | 1533 | else |
| 1505 | 1534 | unreachable; |
| 1506 | 1535 | |
| 1507 | // TODO only works with leaf functions | |
| 1508 | // at the moment, which works fine for | |
| 1509 | // Hello World, but not for real code | |
| 1510 | // of course. Add pushing lr to stack | |
| 1511 | // and popping after call | |
| 1512 | 1536 | try self.genSetReg(inst.base.src, .lr, .{ .memory = got_addr }); |
| 1513 | 1537 | |
| 1538 | // TODO: add Instruction.supportedOn | |
| 1539 | // function for ARM | |
| 1514 | 1540 | if (Target.arm.featureSetHas(self.target.cpu.features, .has_v5t)) { |
| 1515 | 1541 | mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.blx(.al, .lr).toU32()); |
| 1516 | 1542 | } else { |
| ... | ... | @@ -1636,6 +1662,9 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 1636 | 1662 | }, |
| 1637 | 1663 | .arm => { |
| 1638 | 1664 | mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.bx(.al, .lr).toU32()); |
| 1665 | // // Just add space for an instruction, patch this later | |
| 1666 | // try self.code.resize(self.code.items.len + 4); | |
| 1667 | // try self.exitlude_jump_relocs.append(self.gpa, self.code.items.len - 4); | |
| 1639 | 1668 | }, |
| 1640 | 1669 | else => return self.fail(src, "TODO implement return for {}", .{self.target.cpu.arch}), |
| 1641 | 1670 | } |
| ... | ... | @@ -2771,6 +2800,8 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 2771 | 2800 | } else { |
| 2772 | 2801 | return self.fail(src, "TODO MCValues with multiple registers", .{}); |
| 2773 | 2802 | } |
| 2803 | } else if (ncrn < 4 and nsaa == 0) { | |
| 2804 | return self.fail(src, "TODO MCValues split between registers and stack", .{}); | |
| 2774 | 2805 | } else { |
| 2775 | 2806 | ncrn = 4; |
| 2776 | 2807 | if (ty.abiAlignment(self.target.*) == 8) { |
src/codegen/arm.zig+48-8| ... | ... | @@ -446,7 +446,7 @@ pub const Instruction = union(enum) { |
| 446 | 446 | pre_post: u1, |
| 447 | 447 | up_down: u1, |
| 448 | 448 | psr_or_user: u1, |
| 449 | write_back: u1, | |
| 449 | write_back: bool, | |
| 450 | 450 | load_store: u1, |
| 451 | 451 | ) Instruction { |
| 452 | 452 | return Instruction{ |
| ... | ... | @@ -454,7 +454,7 @@ pub const Instruction = union(enum) { |
| 454 | 454 | .register_list = @bitCast(u16, reg_list), |
| 455 | 455 | .rn = rn.id(), |
| 456 | 456 | .load_store = load_store, |
| 457 | .write_back = write_back, | |
| 457 | .write_back = if (write_back) 1 else 0, | |
| 458 | 458 | .psr_or_user = psr_or_user, |
| 459 | 459 | .up_down = up_down, |
| 460 | 460 | .pre_post = pre_post, |
| ... | ... | @@ -644,14 +644,50 @@ pub const Instruction = union(enum) { |
| 644 | 644 | |
| 645 | 645 | // Block data transfer |
| 646 | 646 | |
| 647 | pub fn ldm(cond: Condition, rn: Register, reg_list: RegisterList) Instruction { | |
| 648 | return blockDataTransfer(cond, rn, reg_list, 1, 0, 0, 0, 1); | |
| 647 | pub fn ldmda(cond: Condition, rn: Register, write_back: bool, reg_list: RegisterList) Instruction { | |
| 648 | return blockDataTransfer(cond, rn, reg_list, 0, 0, 0, write_back, 1); | |
| 649 | 649 | } |
| 650 | 650 | |
| 651 | pub fn stm(cond: Condition, rn: Register, reg_list: RegisterList) Instruction { | |
| 652 | return blockDataTransfer(cond, rn, reg_list, 1, 0, 0, 0, 0); | |
| 651 | pub fn ldmdb(cond: Condition, rn: Register, write_back: bool, reg_list: RegisterList) Instruction { | |
| 652 | return blockDataTransfer(cond, rn, reg_list, 1, 0, 0, write_back, 1); | |
| 653 | } | |
| 654 | ||
| 655 | pub fn ldmib(cond: Condition, rn: Register, write_back: bool, reg_list: RegisterList) Instruction { | |
| 656 | return blockDataTransfer(cond, rn, reg_list, 1, 1, 0, write_back, 1); | |
| 657 | } | |
| 658 | ||
| 659 | pub fn ldmia(cond: Condition, rn: Register, write_back: bool, reg_list: RegisterList) Instruction { | |
| 660 | return blockDataTransfer(cond, rn, reg_list, 0, 1, 0, write_back, 1); | |
| 661 | } | |
| 662 | ||
| 663 | pub const ldmfa = ldmda; | |
| 664 | pub const ldmea = ldmdb; | |
| 665 | pub const ldmed = ldmib; | |
| 666 | pub const ldmfd = ldmia; | |
| 667 | pub const ldm = ldmia; | |
| 668 | ||
| 669 | pub fn stmda(cond: Condition, rn: Register, write_back: bool, reg_list: RegisterList) Instruction { | |
| 670 | return blockDataTransfer(cond, rn, reg_list, 0, 0, 0, write_back, 0); | |
| 653 | 671 | } |
| 654 | 672 | |
| 673 | pub fn stmdb(cond: Condition, rn: Register, write_back: bool, reg_list: RegisterList) Instruction { | |
| 674 | return blockDataTransfer(cond, rn, reg_list, 1, 0, 0, write_back, 0); | |
| 675 | } | |
| 676 | ||
| 677 | pub fn stmib(cond: Condition, rn: Register, write_back: bool, reg_list: RegisterList) Instruction { | |
| 678 | return blockDataTransfer(cond, rn, reg_list, 1, 1, 0, write_back, 0); | |
| 679 | } | |
| 680 | ||
| 681 | pub fn stmia(cond: Condition, rn: Register, write_back: bool, reg_list: RegisterList) Instruction { | |
| 682 | return blockDataTransfer(cond, rn, reg_list, 0, 1, 0, write_back, 0); | |
| 683 | } | |
| 684 | ||
| 685 | pub const stmed = stmda; | |
| 686 | pub const stmfd = stmdb; | |
| 687 | pub const stmfa = stmib; | |
| 688 | pub const stmea = stmia; | |
| 689 | pub const stm = stmia; | |
| 690 | ||
| 655 | 691 | // Branch |
| 656 | 692 | |
| 657 | 693 | pub fn b(cond: Condition, offset: i24) Instruction { |
| ... | ... | @@ -738,10 +774,14 @@ test "serialize instructions" { |
| 738 | 774 | .inst = Instruction.bkpt(42), |
| 739 | 775 | .expected = 0b1110_0001_0010_000000000010_0111_1010, |
| 740 | 776 | }, |
| 741 | .{ // stmfd r9, {r0} | |
| 742 | .inst = Instruction.stm(.al, .r9, .{ .r0 = true }), | |
| 777 | .{ // stmdb r9, {r0} | |
| 778 | .inst = Instruction.stmdb(.al, .r9, false, .{ .r0 = true }), | |
| 743 | 779 | .expected = 0b1110_100_1_0_0_0_0_1001_0000000000000001, |
| 744 | 780 | }, |
| 781 | .{ // ldmea r4!, {r2, r5} | |
| 782 | .inst = Instruction.ldmea(.al, .r4, true, .{ .r2 = true, .r5 = true }), | |
| 783 | .expected = 0b1110_100_1_0_0_1_1_0100_0000000000100100, | |
| 784 | }, | |
| 745 | 785 | }; |
| 746 | 786 | |
| 747 | 787 | for (testcases) |case| { |