mirror of
https://github.com/ziglang/zig.git
synced 2025-12-06 06:13:07 +00:00
stage2 ARM: implement ret_load
This commit is contained in:
parent
55ccf4c7a8
commit
95fc41b2b4
@ -864,8 +864,27 @@ fn airAlloc(self: *Self, inst: Air.Inst.Index) !void {
|
||||
}
|
||||
|
||||
fn airRetPtr(self: *Self, inst: Air.Inst.Index) !void {
|
||||
const stack_offset = try self.allocMemPtr(inst);
|
||||
return self.finishAir(inst, .{ .ptr_stack_offset = stack_offset }, .{ .none, .none, .none });
|
||||
const result: MCValue = switch (self.ret_mcv) {
|
||||
.none, .register => .{ .ptr_stack_offset = try self.allocMemPtr(inst) },
|
||||
.stack_offset => blk: {
|
||||
// self.ret_mcv is an address to where this function
|
||||
// should store its result into
|
||||
const ret_ty = self.fn_type.fnReturnType();
|
||||
var ptr_ty_payload: Type.Payload.ElemType = .{
|
||||
.base = .{ .tag = .single_mut_pointer },
|
||||
.data = ret_ty,
|
||||
};
|
||||
const ptr_ty = Type.initPayload(&ptr_ty_payload.base);
|
||||
|
||||
// addr_reg will contain the address of where to store the
|
||||
// result into
|
||||
const addr_reg = try self.copyToTmpRegister(ptr_ty, self.ret_mcv);
|
||||
break :blk .{ .register = addr_reg };
|
||||
},
|
||||
else => unreachable, // invalid return result
|
||||
};
|
||||
|
||||
return self.finishAir(inst, result, .{ .none, .none, .none });
|
||||
}
|
||||
|
||||
fn 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
|
||||
.ptr_embedded_in_code => |off| {
|
||||
try self.setRegOrMem(elem_ty, dst_mcv, .{ .embedded_in_code = off });
|
||||
},
|
||||
.embedded_in_code => {
|
||||
return self.fail("TODO implement loading from MCValue.embedded_in_code", .{});
|
||||
},
|
||||
.register => |reg| {
|
||||
self.register_manager.freezeRegs(&.{reg});
|
||||
defer self.register_manager.unfreezeRegs(&.{reg});
|
||||
@ -1626,6 +1642,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo
|
||||
}
|
||||
},
|
||||
.memory,
|
||||
.embedded_in_code,
|
||||
.stack_offset,
|
||||
.stack_argument_offset,
|
||||
=> {
|
||||
@ -1684,9 +1701,6 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type
|
||||
.ptr_embedded_in_code => |off| {
|
||||
try self.setRegOrMem(value_ty, .{ .embedded_in_code = off }, value);
|
||||
},
|
||||
.embedded_in_code => {
|
||||
return self.fail("TODO implement storing to MCValue.embedded_in_code", .{});
|
||||
},
|
||||
.register => |addr_reg| {
|
||||
self.register_manager.freezeRegs(&.{addr_reg});
|
||||
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
|
||||
switch (value) {
|
||||
.stack_offset => |off| {
|
||||
// sub src_reg, fp, #off
|
||||
try self.genSetReg(ptr_ty, dst_reg, .{ .ptr_stack_offset = off });
|
||||
try self.genSetReg(ptr_ty, src_reg, .{ .ptr_stack_offset = off });
|
||||
},
|
||||
.memory => |addr| try self.genSetReg(Type.usize, src_reg, .{ .immediate = @intCast(u32, addr) }),
|
||||
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
|
||||
}
|
||||
},
|
||||
.memory,
|
||||
.embedded_in_code,
|
||||
.stack_offset,
|
||||
.stack_argument_offset,
|
||||
=> {
|
||||
@ -2656,13 +2671,16 @@ fn airCall(self: *Self, inst: Air.Inst.Index) !void {
|
||||
return bt.finishAir(result);
|
||||
}
|
||||
|
||||
fn ret(self: *Self, mcv: MCValue) !void {
|
||||
fn airRet(self: *Self, inst: Air.Inst.Index) !void {
|
||||
const un_op = self.air.instructions.items(.data)[inst].un_op;
|
||||
const operand = try self.resolveInst(un_op);
|
||||
const ret_ty = self.fn_type.fnReturnType();
|
||||
|
||||
switch (self.ret_mcv) {
|
||||
.none => {},
|
||||
.register => |reg| {
|
||||
// Return result by value
|
||||
try self.genSetReg(ret_ty, reg, mcv);
|
||||
try self.genSetReg(ret_ty, reg, operand);
|
||||
},
|
||||
.stack_offset => {
|
||||
// Return result by reference
|
||||
@ -2674,28 +2692,66 @@ fn ret(self: *Self, mcv: MCValue) !void {
|
||||
.data = ret_ty,
|
||||
};
|
||||
const ptr_ty = Type.initPayload(&ptr_ty_payload.base);
|
||||
try self.store(self.ret_mcv, mcv, ptr_ty, ret_ty);
|
||||
try self.store(self.ret_mcv, operand, ptr_ty, ret_ty);
|
||||
},
|
||||
else => unreachable, // invalid return result
|
||||
}
|
||||
|
||||
// Just add space for an instruction, patch this later
|
||||
try self.exitlude_jump_relocs.append(self.gpa, try self.addNop());
|
||||
}
|
||||
|
||||
fn airRet(self: *Self, inst: Air.Inst.Index) !void {
|
||||
const un_op = self.air.instructions.items(.data)[inst].un_op;
|
||||
const operand = try self.resolveInst(un_op);
|
||||
try self.ret(operand);
|
||||
return self.finishAir(inst, .dead, .{ un_op, .none, .none });
|
||||
}
|
||||
|
||||
fn airRetLoad(self: *Self, inst: Air.Inst.Index) !void {
|
||||
const un_op = self.air.instructions.items(.data)[inst].un_op;
|
||||
const ptr = try self.resolveInst(un_op);
|
||||
_ = ptr;
|
||||
return self.fail("TODO implement airRetLoad for {}", .{self.target.cpu.arch});
|
||||
//return self.finishAir(inst, .dead, .{ un_op, .none, .none });
|
||||
const ptr_ty = self.air.typeOf(un_op);
|
||||
const ret_ty = self.fn_type.fnReturnType();
|
||||
|
||||
switch (self.ret_mcv) {
|
||||
.none => {},
|
||||
.register => {
|
||||
// Return result by value
|
||||
try self.load(self.ret_mcv, ptr, ptr_ty);
|
||||
},
|
||||
.stack_offset => {
|
||||
// Return result by reference
|
||||
//
|
||||
// self.ret_mcv is an address to where this function
|
||||
// should store its result into
|
||||
//
|
||||
// If the operand is a ret_ptr instruction, we are done
|
||||
// here. Else we need to load the result from the location
|
||||
// pointed to by the operand and store it to the result
|
||||
// location.
|
||||
const op_inst = Air.refToIndex(un_op).?;
|
||||
if (self.air.instructions.items(.tag)[op_inst] != .ret_ptr) {
|
||||
const abi_size = @intCast(u32, ret_ty.abiSize(self.target.*));
|
||||
const abi_align = ret_ty.abiAlignment(self.target.*);
|
||||
|
||||
// This is essentially allocMem without the
|
||||
// instruction tracking
|
||||
if (abi_align > self.stack_align)
|
||||
self.stack_align = abi_align;
|
||||
// TODO find a free slot instead of always appending
|
||||
const offset = mem.alignForwardGeneric(u32, self.next_stack_offset, abi_align);
|
||||
self.next_stack_offset = offset + abi_size;
|
||||
if (self.next_stack_offset > self.max_end_stack)
|
||||
self.max_end_stack = self.next_stack_offset;
|
||||
|
||||
const tmp_mcv = MCValue{ .stack_offset = offset };
|
||||
try self.load(tmp_mcv, ptr, ptr_ty);
|
||||
try self.store(self.ret_mcv, tmp_mcv, ptr_ty, ret_ty);
|
||||
}
|
||||
},
|
||||
else => unreachable, // invalid return result
|
||||
}
|
||||
|
||||
// Just add space for an instruction, patch this later
|
||||
try self.exitlude_jump_relocs.append(self.gpa, try self.addNop());
|
||||
|
||||
return self.finishAir(inst, .dead, .{ un_op, .none, .none });
|
||||
}
|
||||
|
||||
fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void {
|
||||
|
||||
@ -285,7 +285,6 @@ fn fB() []const u8 {
|
||||
|
||||
test "call function pointer in struct" {
|
||||
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage1) return error.SkipZigTest;
|
||||
|
||||
try expect(mem.eql(u8, f3(true), "a"));
|
||||
|
||||
@ -44,7 +44,6 @@ const a = struct {
|
||||
test "initialization" {
|
||||
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
|
||||
var t = a.init();
|
||||
try std.testing.expect(t.foo.len == 0);
|
||||
}
|
||||
|
||||
@ -57,7 +57,6 @@ test "Peer resolution of extern function calls in @TypeOf" {
|
||||
|
||||
test "Extern function calls, dereferences and field access in @TypeOf" {
|
||||
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
|
||||
|
||||
const Test = struct {
|
||||
|
||||
@ -5,7 +5,6 @@ var result: []const u8 = "wrong";
|
||||
|
||||
test "pass string literal byvalue to a generic var param" {
|
||||
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
|
||||
|
||||
start();
|
||||
|
||||
@ -1266,7 +1266,6 @@ test "cast between *[N]void and []void" {
|
||||
|
||||
test "peer resolve arrays of different size to const slice" {
|
||||
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
|
||||
|
||||
try expect(mem.eql(u8, boolToStr(true), "true"));
|
||||
try expect(mem.eql(u8, boolToStr(false), "false"));
|
||||
|
||||
@ -32,7 +32,6 @@ test "defer and labeled break" {
|
||||
}
|
||||
|
||||
test "errdefer does not apply to fn inside fn" {
|
||||
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
|
||||
|
||||
if (testNestedFnErrDefer()) |_| @panic("expected error") else |e| try expect(e == error.Bad);
|
||||
|
||||
@ -17,7 +17,6 @@ fn checkSize(comptime T: type) usize {
|
||||
}
|
||||
|
||||
test "simple generic fn" {
|
||||
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
|
||||
|
||||
try expect(max(i32, 3, -1) == 3);
|
||||
|
||||
@ -22,7 +22,6 @@ fn foo(a: A) i32 {
|
||||
}
|
||||
|
||||
test "incomplete struct param top level declaration" {
|
||||
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
|
||||
const a = A{
|
||||
.b = B{
|
||||
|
||||
@ -138,7 +138,6 @@ fn returnEmptyStructInstance() StructWithNoFields {
|
||||
|
||||
test "fn call of struct field" {
|
||||
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
|
||||
|
||||
const Foo = struct {
|
||||
ptr: fn () i32,
|
||||
@ -196,7 +195,6 @@ const MemberFnRand = struct {
|
||||
|
||||
test "return struct byval from function" {
|
||||
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
|
||||
|
||||
const bar = makeBar2(1234, 5678);
|
||||
try expect(bar.y == 5678);
|
||||
@ -325,7 +323,6 @@ test "return empty struct from fn" {
|
||||
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
|
||||
|
||||
_ = testReturnEmptyStructFromFn();
|
||||
}
|
||||
|
||||
@ -108,7 +108,6 @@ fn returnsFive() i32 {
|
||||
}
|
||||
|
||||
test "switch on type" {
|
||||
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
|
||||
|
||||
try expect(trueIfBoolFalseOtherwise(bool));
|
||||
|
||||
@ -37,7 +37,6 @@ test "usingnamespace does not redeclare an imported variable" {
|
||||
|
||||
usingnamespace @import("usingnamespace/foo.zig");
|
||||
test "usingnamespace omits mixing in private functions" {
|
||||
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
|
||||
|
||||
try expect(@This().privateFunction());
|
||||
@ -53,7 +52,6 @@ test {
|
||||
|
||||
usingnamespace @import("usingnamespace/a.zig");
|
||||
test "two files usingnamespace import each other" {
|
||||
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
|
||||
|
||||
try expect(@This().ok());
|
||||
|
||||
@ -3,7 +3,6 @@ const builtin = @import("builtin");
|
||||
const expect = std.testing.expect;
|
||||
|
||||
test "while loop" {
|
||||
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
|
||||
|
||||
var i: i32 = 0;
|
||||
@ -23,7 +22,6 @@ fn whileLoop2() i32 {
|
||||
}
|
||||
|
||||
test "static eval while" {
|
||||
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
|
||||
|
||||
try expect(static_eval_while_number == 1);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user