authorgravatar for joachim.schmidt557@outlook.comJoachim Schmidt <joachim.schmidt557@outlook.com> 2022-03-08 14:20:15+01:00
committergravatar for joachim.schmidt557@outlook.comJoachim Schmidt <joachim.schmidt557@outlook.com> 2022-03-08 21:10:04+01:00
log95fc41b2b433ccfa751c8877ec7edac3b9bffbd6
tree1237575d07c872659fe6d59f38ddcff8573f8842
parent55ccf4c7a8451edca47d8d6d82bddd9fe192744a

stage2 ARM: implement ret_load


13 files changed, 76 insertions(+), 36 deletions(-)

src/arch/arm/CodeGen.zig+76-20
...@@ -864,8 +864,27 @@ fn airAlloc(self: *Self, inst: Air.Inst.Index) !void {...@@ -864,8 +864,27 @@ fn airAlloc(self: *Self, inst: Air.Inst.Index) !void {
864}864}
865865
866fn airRetPtr(self: *Self, inst: Air.Inst.Index) !void {866fn airRetPtr(self: *Self, inst: Air.Inst.Index) !void {
867 const stack_offset = try self.allocMemPtr(inst);867 const result: MCValue = switch (self.ret_mcv) {
868 return self.finishAir(inst, .{ .ptr_stack_offset = stack_offset }, .{ .none, .none, .none });868 .none, .register => .{ .ptr_stack_offset = try self.allocMemPtr(inst) },
869 .stack_offset => blk: {
870 // self.ret_mcv is an address to where this function
871 // should store its result into
872 const ret_ty = self.fn_type.fnReturnType();
873 var ptr_ty_payload: Type.Payload.ElemType = .{
874 .base = .{ .tag = .single_mut_pointer },
875 .data = ret_ty,
876 };
877 const ptr_ty = Type.initPayload(&ptr_ty_payload.base);
878
879 // addr_reg will contain the address of where to store the
880 // result into
881 const addr_reg = try self.copyToTmpRegister(ptr_ty, self.ret_mcv);
882 break :blk .{ .register = addr_reg };
883 },
884 else => unreachable, // invalid return result
885 };
886
887 return self.finishAir(inst, result, .{ .none, .none, .none });
869}888}
870889
871fn airFptrunc(self: *Self, inst: Air.Inst.Index) !void {890fn airFptrunc(self: *Self, inst: Air.Inst.Index) !void {
...@@ -1577,9 +1596,6 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo...@@ -1577,9 +1596,6 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo
1577 .ptr_embedded_in_code => |off| {1596 .ptr_embedded_in_code => |off| {
1578 try self.setRegOrMem(elem_ty, dst_mcv, .{ .embedded_in_code = off });1597 try self.setRegOrMem(elem_ty, dst_mcv, .{ .embedded_in_code = off });
1579 },1598 },
1580 .embedded_in_code => {
1581 return self.fail("TODO implement loading from MCValue.embedded_in_code", .{});
1582 },
1583 .register => |reg| {1599 .register => |reg| {
1584 self.register_manager.freezeRegs(&.{reg});1600 self.register_manager.freezeRegs(&.{reg});
1585 defer self.register_manager.unfreezeRegs(&.{reg});1601 defer self.register_manager.unfreezeRegs(&.{reg});
...@@ -1626,6 +1642,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo...@@ -1626,6 +1642,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo
1626 }1642 }
1627 },1643 },
1628 .memory,1644 .memory,
1645 .embedded_in_code,
1629 .stack_offset,1646 .stack_offset,
1630 .stack_argument_offset,1647 .stack_argument_offset,
1631 => {1648 => {
...@@ -1684,9 +1701,6 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type...@@ -1684,9 +1701,6 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type
1684 .ptr_embedded_in_code => |off| {1701 .ptr_embedded_in_code => |off| {
1685 try self.setRegOrMem(value_ty, .{ .embedded_in_code = off }, value);1702 try self.setRegOrMem(value_ty, .{ .embedded_in_code = off }, value);
1686 },1703 },
1687 .embedded_in_code => {
1688 return self.fail("TODO implement storing to MCValue.embedded_in_code", .{});
1689 },
1690 .register => |addr_reg| {1704 .register => |addr_reg| {
1691 self.register_manager.freezeRegs(&.{addr_reg});1705 self.register_manager.freezeRegs(&.{addr_reg});
1692 defer self.register_manager.unfreezeRegs(&.{addr_reg});1706 defer self.register_manager.unfreezeRegs(&.{addr_reg});
...@@ -1719,7 +1733,7 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type...@@ -1719,7 +1733,7 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type
1719 switch (value) {1733 switch (value) {
1720 .stack_offset => |off| {1734 .stack_offset => |off| {
1721 // sub src_reg, fp, #off1735 // sub src_reg, fp, #off
1722 try self.genSetReg(ptr_ty, dst_reg, .{ .ptr_stack_offset = off });1736 try self.genSetReg(ptr_ty, src_reg, .{ .ptr_stack_offset = off });
1723 },1737 },
1724 .memory => |addr| try self.genSetReg(Type.usize, src_reg, .{ .immediate = @intCast(u32, addr) }),1738 .memory => |addr| try self.genSetReg(Type.usize, src_reg, .{ .immediate = @intCast(u32, addr) }),
1725 else => return self.fail("TODO store {} to register", .{value}),1739 else => return self.fail("TODO store {} to register", .{value}),
...@@ -1735,6 +1749,7 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type...@@ -1735,6 +1749,7 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type
1735 }1749 }
1736 },1750 },
1737 .memory,1751 .memory,
1752 .embedded_in_code,
1738 .stack_offset,1753 .stack_offset,
1739 .stack_argument_offset,1754 .stack_argument_offset,
1740 => {1755 => {
...@@ -2656,13 +2671,16 @@ fn airCall(self: *Self, inst: Air.Inst.Index) !void {...@@ -2656,13 +2671,16 @@ fn airCall(self: *Self, inst: Air.Inst.Index) !void {
2656 return bt.finishAir(result);2671 return bt.finishAir(result);
2657}2672}
26582673
2659fn ret(self: *Self, mcv: MCValue) !void {2674fn airRet(self: *Self, inst: Air.Inst.Index) !void {
2675 const un_op = self.air.instructions.items(.data)[inst].un_op;
2676 const operand = try self.resolveInst(un_op);
2660 const ret_ty = self.fn_type.fnReturnType();2677 const ret_ty = self.fn_type.fnReturnType();
2678
2661 switch (self.ret_mcv) {2679 switch (self.ret_mcv) {
2662 .none => {},2680 .none => {},
2663 .register => |reg| {2681 .register => |reg| {
2664 // Return result by value2682 // Return result by value
2665 try self.genSetReg(ret_ty, reg, mcv);2683 try self.genSetReg(ret_ty, reg, operand);
2666 },2684 },
2667 .stack_offset => {2685 .stack_offset => {
2668 // Return result by reference2686 // Return result by reference
...@@ -2674,28 +2692,66 @@ fn ret(self: *Self, mcv: MCValue) !void {...@@ -2674,28 +2692,66 @@ fn ret(self: *Self, mcv: MCValue) !void {
2674 .data = ret_ty,2692 .data = ret_ty,
2675 };2693 };
2676 const ptr_ty = Type.initPayload(&ptr_ty_payload.base);2694 const ptr_ty = Type.initPayload(&ptr_ty_payload.base);
2677 try self.store(self.ret_mcv, mcv, ptr_ty, ret_ty);2695 try self.store(self.ret_mcv, operand, ptr_ty, ret_ty);
2678 },2696 },
2679 else => unreachable, // invalid return result2697 else => unreachable, // invalid return result
2680 }2698 }
26812699
2682 // Just add space for an instruction, patch this later2700 // Just add space for an instruction, patch this later
2683 try self.exitlude_jump_relocs.append(self.gpa, try self.addNop());2701 try self.exitlude_jump_relocs.append(self.gpa, try self.addNop());
2684}
26852702
2686fn airRet(self: *Self, inst: Air.Inst.Index) !void {
2687 const un_op = self.air.instructions.items(.data)[inst].un_op;
2688 const operand = try self.resolveInst(un_op);
2689 try self.ret(operand);
2690 return self.finishAir(inst, .dead, .{ un_op, .none, .none });2703 return self.finishAir(inst, .dead, .{ un_op, .none, .none });
2691}2704}
26922705
2693fn airRetLoad(self: *Self, inst: Air.Inst.Index) !void {2706fn airRetLoad(self: *Self, inst: Air.Inst.Index) !void {
2694 const un_op = self.air.instructions.items(.data)[inst].un_op;2707 const un_op = self.air.instructions.items(.data)[inst].un_op;
2695 const ptr = try self.resolveInst(un_op);2708 const ptr = try self.resolveInst(un_op);
2696 _ = ptr;2709 const ptr_ty = self.air.typeOf(un_op);
2697 return self.fail("TODO implement airRetLoad for {}", .{self.target.cpu.arch});2710 const ret_ty = self.fn_type.fnReturnType();
2698 //return self.finishAir(inst, .dead, .{ un_op, .none, .none });2711
2712 switch (self.ret_mcv) {
2713 .none => {},
2714 .register => {
2715 // Return result by value
2716 try self.load(self.ret_mcv, ptr, ptr_ty);
2717 },
2718 .stack_offset => {
2719 // Return result by reference
2720 //
2721 // self.ret_mcv is an address to where this function
2722 // should store its result into
2723 //
2724 // If the operand is a ret_ptr instruction, we are done
2725 // here. Else we need to load the result from the location
2726 // pointed to by the operand and store it to the result
2727 // location.
2728 const op_inst = Air.refToIndex(un_op).?;
2729 if (self.air.instructions.items(.tag)[op_inst] != .ret_ptr) {
2730 const abi_size = @intCast(u32, ret_ty.abiSize(self.target.*));
2731 const abi_align = ret_ty.abiAlignment(self.target.*);
2732
2733 // This is essentially allocMem without the
2734 // instruction tracking
2735 if (abi_align > self.stack_align)
2736 self.stack_align = abi_align;
2737 // TODO find a free slot instead of always appending
2738 const offset = mem.alignForwardGeneric(u32, self.next_stack_offset, abi_align);
2739 self.next_stack_offset = offset + abi_size;
2740 if (self.next_stack_offset > self.max_end_stack)
2741 self.max_end_stack = self.next_stack_offset;
2742
2743 const tmp_mcv = MCValue{ .stack_offset = offset };
2744 try self.load(tmp_mcv, ptr, ptr_ty);
2745 try self.store(self.ret_mcv, tmp_mcv, ptr_ty, ret_ty);
2746 }
2747 },
2748 else => unreachable, // invalid return result
2749 }
2750
2751 // Just add space for an instruction, patch this later
2752 try self.exitlude_jump_relocs.append(self.gpa, try self.addNop());
2753
2754 return self.finishAir(inst, .dead, .{ un_op, .none, .none });
2699}2755}
27002756
2701fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void {2757fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void {
test/behavior/basic.zig-1
...@@ -285,7 +285,6 @@ fn fB() []const u8 {...@@ -285,7 +285,6 @@ fn fB() []const u8 {
285285
286test "call function pointer in struct" {286test "call function pointer in struct" {
287 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;287 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
288 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
289 if (builtin.zig_backend == .stage1) return error.SkipZigTest;288 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
290289
291 try expect(mem.eql(u8, f3(true), "a"));290 try expect(mem.eql(u8, f3(true), "a"));
test/behavior/bugs/1735.zig-1
...@@ -44,7 +44,6 @@ const a = struct {...@@ -44,7 +44,6 @@ const a = struct {
44test "initialization" {44test "initialization" {
45 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;45 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
46 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;46 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
47 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
48 var t = a.init();47 var t = a.init();
49 try std.testing.expect(t.foo.len == 0);48 try std.testing.expect(t.foo.len == 0);
50}49}
test/behavior/bugs/4328.zig-1
...@@ -57,7 +57,6 @@ test "Peer resolution of extern function calls in @TypeOf" {...@@ -57,7 +57,6 @@ test "Peer resolution of extern function calls in @TypeOf" {
5757
58test "Extern function calls, dereferences and field access in @TypeOf" {58test "Extern function calls, dereferences and field access in @TypeOf" {
59 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;59 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
60 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
61 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;60 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
6261
63 const Test = struct {62 const Test = struct {
test/behavior/byval_arg_var.zig-1
...@@ -5,7 +5,6 @@ var result: []const u8 = "wrong";...@@ -5,7 +5,6 @@ var result: []const u8 = "wrong";
55
6test "pass string literal byvalue to a generic var param" {6test "pass string literal byvalue to a generic var param" {
7 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;7 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
8 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
9 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;8 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
109
11 start();10 start();
test/behavior/cast.zig-1
...@@ -1266,7 +1266,6 @@ test "cast between *[N]void and []void" {...@@ -1266,7 +1266,6 @@ test "cast between *[N]void and []void" {
12661266
1267test "peer resolve arrays of different size to const slice" {1267test "peer resolve arrays of different size to const slice" {
1268 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;1268 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1269 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
12701269
1271 try expect(mem.eql(u8, boolToStr(true), "true"));1270 try expect(mem.eql(u8, boolToStr(true), "true"));
1272 try expect(mem.eql(u8, boolToStr(false), "false"));1271 try expect(mem.eql(u8, boolToStr(false), "false"));
test/behavior/defer.zig-1
...@@ -32,7 +32,6 @@ test "defer and labeled break" {...@@ -32,7 +32,6 @@ test "defer and labeled break" {
32}32}
3333
34test "errdefer does not apply to fn inside fn" {34test "errdefer does not apply to fn inside fn" {
35 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
36 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;35 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
3736
38 if (testNestedFnErrDefer()) |_| @panic("expected error") else |e| try expect(e == error.Bad);37 if (testNestedFnErrDefer()) |_| @panic("expected error") else |e| try expect(e == error.Bad);
test/behavior/generics.zig-1
...@@ -17,7 +17,6 @@ fn checkSize(comptime T: type) usize {...@@ -17,7 +17,6 @@ fn checkSize(comptime T: type) usize {
17}17}
1818
19test "simple generic fn" {19test "simple generic fn" {
20 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
21 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;20 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
2221
23 try expect(max(i32, 3, -1) == 3);22 try expect(max(i32, 3, -1) == 3);
test/behavior/incomplete_struct_param_tld.zig-1
...@@ -22,7 +22,6 @@ fn foo(a: A) i32 {...@@ -22,7 +22,6 @@ fn foo(a: A) i32 {
22}22}
2323
24test "incomplete struct param top level declaration" {24test "incomplete struct param top level declaration" {
25 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
26 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;25 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
27 const a = A{26 const a = A{
28 .b = B{27 .b = B{
test/behavior/struct.zig-3
...@@ -138,7 +138,6 @@ fn returnEmptyStructInstance() StructWithNoFields {...@@ -138,7 +138,6 @@ fn returnEmptyStructInstance() StructWithNoFields {
138138
139test "fn call of struct field" {139test "fn call of struct field" {
140 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;140 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
141 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
142141
143 const Foo = struct {142 const Foo = struct {
144 ptr: fn () i32,143 ptr: fn () i32,
...@@ -196,7 +195,6 @@ const MemberFnRand = struct {...@@ -196,7 +195,6 @@ const MemberFnRand = struct {
196195
197test "return struct byval from function" {196test "return struct byval from function" {
198 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;197 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
199 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
200198
201 const bar = makeBar2(1234, 5678);199 const bar = makeBar2(1234, 5678);
202 try expect(bar.y == 5678);200 try expect(bar.y == 5678);
...@@ -325,7 +323,6 @@ test "return empty struct from fn" {...@@ -325,7 +323,6 @@ test "return empty struct from fn" {
325 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;323 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
326 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO324 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
327 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO325 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
328 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
329326
330 _ = testReturnEmptyStructFromFn();327 _ = testReturnEmptyStructFromFn();
331}328}
test/behavior/switch.zig-1
...@@ -108,7 +108,6 @@ fn returnsFive() i32 {...@@ -108,7 +108,6 @@ fn returnsFive() i32 {
108}108}
109109
110test "switch on type" {110test "switch on type" {
111 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
112 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO111 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
113112
114 try expect(trueIfBoolFalseOtherwise(bool));113 try expect(trueIfBoolFalseOtherwise(bool));
test/behavior/usingnamespace.zig-2
...@@ -37,7 +37,6 @@ test "usingnamespace does not redeclare an imported variable" {...@@ -37,7 +37,6 @@ test "usingnamespace does not redeclare an imported variable" {
3737
38usingnamespace @import("usingnamespace/foo.zig");38usingnamespace @import("usingnamespace/foo.zig");
39test "usingnamespace omits mixing in private functions" {39test "usingnamespace omits mixing in private functions" {
40 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
41 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;40 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
4241
43 try expect(@This().privateFunction());42 try expect(@This().privateFunction());
...@@ -53,7 +52,6 @@ test {...@@ -53,7 +52,6 @@ test {
5352
54usingnamespace @import("usingnamespace/a.zig");53usingnamespace @import("usingnamespace/a.zig");
55test "two files usingnamespace import each other" {54test "two files usingnamespace import each other" {
56 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
57 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;55 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
5856
59 try expect(@This().ok());57 try expect(@This().ok());
test/behavior/while.zig-2
...@@ -3,7 +3,6 @@ const builtin = @import("builtin");...@@ -3,7 +3,6 @@ const builtin = @import("builtin");
3const expect = std.testing.expect;3const expect = std.testing.expect;
44
5test "while loop" {5test "while loop" {
6 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
7 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;6 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
87
9 var i: i32 = 0;8 var i: i32 = 0;
...@@ -23,7 +22,6 @@ fn whileLoop2() i32 {...@@ -23,7 +22,6 @@ fn whileLoop2() i32 {
23}22}
2423
25test "static eval while" {24test "static eval while" {
26 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
27 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;25 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
2826
29 try expect(static_eval_while_number == 1);27 try expect(static_eval_while_number == 1);