| 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,6 +570,35 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 570 | try self.dbgSetEpilogueBegin(); | 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 | else => { | 602 | else => { |
| 574 | try self.dbgSetPrologueEnd(); | 603 | try self.dbgSetPrologueEnd(); |
| 575 | try self.genBody(self.mod_fn.analysis.success); | 604 | try self.genBody(self.mod_fn.analysis.success); |
| ... | @@ -1504,13 +1533,10 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { | ... | @@ -1504,13 +1533,10 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 1504 | else | 1533 | else |
| 1505 | unreachable; | 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 | try self.genSetReg(inst.base.src, .lr, .{ .memory = got_addr }); | 1536 | try self.genSetReg(inst.base.src, .lr, .{ .memory = got_addr }); |
| 1513 | 1537 | ||
| 1538 | // TODO: add Instruction.supportedOn | ||
| 1539 | // function for ARM | ||
| 1514 | if (Target.arm.featureSetHas(self.target.cpu.features, .has_v5t)) { | 1540 | if (Target.arm.featureSetHas(self.target.cpu.features, .has_v5t)) { |
| 1515 | mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.blx(.al, .lr).toU32()); | 1541 | mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.blx(.al, .lr).toU32()); |
| 1516 | } else { | 1542 | } else { |
| ... | @@ -1636,6 +1662,9 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { | ... | @@ -1636,6 +1662,9 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 1636 | }, | 1662 | }, |
| 1637 | .arm => { | 1663 | .arm => { |
| 1638 | mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.bx(.al, .lr).toU32()); | 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 | else => return self.fail(src, "TODO implement return for {}", .{self.target.cpu.arch}), | 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,6 +2800,8 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 2771 | } else { | 2800 | } else { |
| 2772 | return self.fail(src, "TODO MCValues with multiple registers", .{}); | 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 | } else { | 2805 | } else { |
| 2775 | ncrn = 4; | 2806 | ncrn = 4; |
| 2776 | if (ty.abiAlignment(self.target.*) == 8) { | 2807 | if (ty.abiAlignment(self.target.*) == 8) { |
src/codegen/arm.zig+48-8| ... | @@ -446,7 +446,7 @@ pub const Instruction = union(enum) { | ... | @@ -446,7 +446,7 @@ pub const Instruction = union(enum) { |
| 446 | pre_post: u1, | 446 | pre_post: u1, |
| 447 | up_down: u1, | 447 | up_down: u1, |
| 448 | psr_or_user: u1, | 448 | psr_or_user: u1, |
| 449 | write_back: u1, | 449 | write_back: bool, |
| 450 | load_store: u1, | 450 | load_store: u1, |
| 451 | ) Instruction { | 451 | ) Instruction { |
| 452 | return Instruction{ | 452 | return Instruction{ |
| ... | @@ -454,7 +454,7 @@ pub const Instruction = union(enum) { | ... | @@ -454,7 +454,7 @@ pub const Instruction = union(enum) { |
| 454 | .register_list = @bitCast(u16, reg_list), | 454 | .register_list = @bitCast(u16, reg_list), |
| 455 | .rn = rn.id(), | 455 | .rn = rn.id(), |
| 456 | .load_store = load_store, | 456 | .load_store = load_store, |
| 457 | .write_back = write_back, | 457 | .write_back = if (write_back) 1 else 0, |
| 458 | .psr_or_user = psr_or_user, | 458 | .psr_or_user = psr_or_user, |
| 459 | .up_down = up_down, | 459 | .up_down = up_down, |
| 460 | .pre_post = pre_post, | 460 | .pre_post = pre_post, |
| ... | @@ -644,14 +644,50 @@ pub const Instruction = union(enum) { | ... | @@ -644,14 +644,50 @@ pub const Instruction = union(enum) { |
| 644 | 644 | ||
| 645 | // Block data transfer | 645 | // Block data transfer |
| 646 | 646 | ||
| 647 | pub fn ldm(cond: Condition, rn: Register, reg_list: RegisterList) Instruction { | 647 | pub fn ldmda(cond: Condition, rn: Register, write_back: bool, reg_list: RegisterList) Instruction { |
| 648 | return blockDataTransfer(cond, rn, reg_list, 1, 0, 0, 0, 1); | 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 { | 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, 0, 0); | 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 | // Branch | 691 | // Branch |
| 656 | 692 | ||
| 657 | pub fn b(cond: Condition, offset: i24) Instruction { | 693 | pub fn b(cond: Condition, offset: i24) Instruction { |
| ... | @@ -738,10 +774,14 @@ test "serialize instructions" { | ... | @@ -738,10 +774,14 @@ test "serialize instructions" { |
| 738 | .inst = Instruction.bkpt(42), | 774 | .inst = Instruction.bkpt(42), |
| 739 | .expected = 0b1110_0001_0010_000000000010_0111_1010, | 775 | .expected = 0b1110_0001_0010_000000000010_0111_1010, |
| 740 | }, | 776 | }, |
| 741 | .{ // stmfd r9, {r0} | 777 | .{ // stmdb r9, {r0} |
| 742 | .inst = Instruction.stm(.al, .r9, .{ .r0 = true }), | 778 | .inst = Instruction.stmdb(.al, .r9, false, .{ .r0 = true }), |
| 743 | .expected = 0b1110_100_1_0_0_0_0_1001_0000000000000001, | 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 | for (testcases) |case| { | 787 | for (testcases) |case| { |