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 {
864864}
865865
866866fn airRetPtr(self: *Self, inst: Air.Inst.Index) !void {
867 const stack_offset = try self.allocMemPtr(inst);
868 return self.finishAir(inst, .{ .ptr_stack_offset = stack_offset }, .{ .none, .none, .none });
867 const result: MCValue = switch (self.ret_mcv) {
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 });
869888}
870889
871890fn 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
15771596 .ptr_embedded_in_code => |off| {
15781597 try self.setRegOrMem(elem_ty, dst_mcv, .{ .embedded_in_code = off });
15791598 },
1580 .embedded_in_code => {
1581 return self.fail("TODO implement loading from MCValue.embedded_in_code", .{});
1582 },
15831599 .register => |reg| {
15841600 self.register_manager.freezeRegs(&.{reg});
15851601 defer self.register_manager.unfreezeRegs(&.{reg});
......@@ -1626,6 +1642,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo
16261642 }
16271643 },
16281644 .memory,
1645 .embedded_in_code,
16291646 .stack_offset,
16301647 .stack_argument_offset,
16311648 => {
......@@ -1684,9 +1701,6 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type
16841701 .ptr_embedded_in_code => |off| {
16851702 try self.setRegOrMem(value_ty, .{ .embedded_in_code = off }, value);
16861703 },
1687 .embedded_in_code => {
1688 return self.fail("TODO implement storing to MCValue.embedded_in_code", .{});
1689 },
16901704 .register => |addr_reg| {
16911705 self.register_manager.freezeRegs(&.{addr_reg});
16921706 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
17191733 switch (value) {
17201734 .stack_offset => |off| {
17211735 // 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 });
17231737 },
17241738 .memory => |addr| try self.genSetReg(Type.usize, src_reg, .{ .immediate = @intCast(u32, addr) }),
17251739 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
17351749 }
17361750 },
17371751 .memory,
1752 .embedded_in_code,
17381753 .stack_offset,
17391754 .stack_argument_offset,
17401755 => {
......@@ -2656,13 +2671,16 @@ fn airCall(self: *Self, inst: Air.Inst.Index) !void {
26562671 return bt.finishAir(result);
26572672}
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);
26602677 const ret_ty = self.fn_type.fnReturnType();
2678
26612679 switch (self.ret_mcv) {
26622680 .none => {},
26632681 .register => |reg| {
26642682 // Return result by value
2665 try self.genSetReg(ret_ty, reg, mcv);
2683 try self.genSetReg(ret_ty, reg, operand);
26662684 },
26672685 .stack_offset => {
26682686 // Return result by reference
......@@ -2674,28 +2692,66 @@ fn ret(self: *Self, mcv: MCValue) !void {
26742692 .data = ret_ty,
26752693 };
26762694 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);
26782696 },
26792697 else => unreachable, // invalid return result
26802698 }
26812699
26822700 // Just add space for an instruction, patch this later
26832701 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);
26902703 return self.finishAir(inst, .dead, .{ un_op, .none, .none });
26912704}
26922705
26932706fn airRetLoad(self: *Self, inst: Air.Inst.Index) !void {
26942707 const un_op = self.air.instructions.items(.data)[inst].un_op;
26952708 const ptr = try self.resolveInst(un_op);
2696 _ = ptr;
2697 return self.fail("TODO implement airRetLoad for {}", .{self.target.cpu.arch});
2698 //return self.finishAir(inst, .dead, .{ un_op, .none, .none });
2709 const ptr_ty = self.air.typeOf(un_op);
2710 const ret_ty = self.fn_type.fnReturnType();
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 });
26992755}
27002756
27012757fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void {
test/behavior/basic.zig-1
......@@ -285,7 +285,6 @@ fn fB() []const u8 {
285285
286286test "call function pointer in struct" {
287287 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
288 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
289288 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
290289
291290 try expect(mem.eql(u8, f3(true), "a"));
test/behavior/bugs/1735.zig-1
......@@ -44,7 +44,6 @@ const a = struct {
4444test "initialization" {
4545 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
4646 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
47 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
4847 var t = a.init();
4948 try std.testing.expect(t.foo.len == 0);
5049}
test/behavior/bugs/4328.zig-1
......@@ -57,7 +57,6 @@ test "Peer resolution of extern function calls in @TypeOf" {
5757
5858test "Extern function calls, dereferences and field access in @TypeOf" {
5959 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
60 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
6160 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
6261
6362 const Test = struct {
test/behavior/byval_arg_var.zig-1
......@@ -5,7 +5,6 @@ var result: []const u8 = "wrong";
55
66test "pass string literal byvalue to a generic var param" {
77 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
8 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
98 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
109
1110 start();
test/behavior/cast.zig-1
......@@ -1266,7 +1266,6 @@ test "cast between *[N]void and []void" {
12661266
12671267test "peer resolve arrays of different size to const slice" {
12681268 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1269 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
12701269
12711270 try expect(mem.eql(u8, boolToStr(true), "true"));
12721271 try expect(mem.eql(u8, boolToStr(false), "false"));
test/behavior/defer.zig-1
......@@ -32,7 +32,6 @@ test "defer and labeled break" {
3232}
3333
3434test "errdefer does not apply to fn inside fn" {
35 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
3635 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
3736
3837 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 {
1717}
1818
1919test "simple generic fn" {
20 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
2120 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
2221
2322 try expect(max(i32, 3, -1) == 3);
test/behavior/incomplete_struct_param_tld.zig-1
......@@ -22,7 +22,6 @@ fn foo(a: A) i32 {
2222}
2323
2424test "incomplete struct param top level declaration" {
25 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
2625 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
2726 const a = A{
2827 .b = B{
test/behavior/struct.zig-3
......@@ -138,7 +138,6 @@ fn returnEmptyStructInstance() StructWithNoFields {
138138
139139test "fn call of struct field" {
140140 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
141 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
142141
143142 const Foo = struct {
144143 ptr: fn () i32,
......@@ -196,7 +195,6 @@ const MemberFnRand = struct {
196195
197196test "return struct byval from function" {
198197 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
199 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
200198
201199 const bar = makeBar2(1234, 5678);
202200 try expect(bar.y == 5678);
......@@ -325,7 +323,6 @@ test "return empty struct from fn" {
325323 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
326324 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
327325 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
328 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
329326
330327 _ = testReturnEmptyStructFromFn();
331328}
test/behavior/switch.zig-1
......@@ -108,7 +108,6 @@ fn returnsFive() i32 {
108108}
109109
110110test "switch on type" {
111 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
112111 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
113112
114113 try expect(trueIfBoolFalseOtherwise(bool));
test/behavior/usingnamespace.zig-2
......@@ -37,7 +37,6 @@ test "usingnamespace does not redeclare an imported variable" {
3737
3838usingnamespace @import("usingnamespace/foo.zig");
3939test "usingnamespace omits mixing in private functions" {
40 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
4140 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
4241
4342 try expect(@This().privateFunction());
......@@ -53,7 +52,6 @@ test {
5352
5453usingnamespace @import("usingnamespace/a.zig");
5554test "two files usingnamespace import each other" {
56 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
5755 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
5856
5957 try expect(@This().ok());
test/behavior/while.zig-2
......@@ -3,7 +3,6 @@ const builtin = @import("builtin");
33const expect = std.testing.expect;
44
55test "while loop" {
6 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
76 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
87
98 var i: i32 = 0;
......@@ -23,7 +22,6 @@ fn whileLoop2() i32 {
2322}
2423
2524test "static eval while" {
26 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
2725 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
2826
2927 try expect(static_eval_while_number == 1);