mirror of
https://github.com/ziglang/zig.git
synced 2025-12-06 06:13:07 +00:00
stage2 ARM: implement ptr_elem_val
This commit is contained in:
parent
a0a7d15142
commit
b976997e16
@ -2258,89 +2258,84 @@ fn airPtrSlicePtrPtr(self: *Self, inst: Air.Inst.Index) !void {
|
|||||||
return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
|
return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn ptrElemVal(
|
||||||
|
self: *Self,
|
||||||
|
ptr_bind: ReadArg.Bind,
|
||||||
|
index_bind: ReadArg.Bind,
|
||||||
|
ptr_ty: Type,
|
||||||
|
maybe_inst: ?Air.Inst.Index,
|
||||||
|
) !MCValue {
|
||||||
|
const elem_ty = ptr_ty.childType();
|
||||||
|
const elem_size = @intCast(u32, elem_ty.abiSize(self.target.*));
|
||||||
|
|
||||||
|
switch (elem_size) {
|
||||||
|
1, 4 => {
|
||||||
|
var base_reg: Register = undefined;
|
||||||
|
var index_reg: Register = undefined;
|
||||||
|
var dest_reg: Register = undefined;
|
||||||
|
|
||||||
|
const read_args = [_]ReadArg{
|
||||||
|
.{ .ty = ptr_ty, .bind = ptr_bind, .class = gp, .reg = &base_reg },
|
||||||
|
.{ .ty = Type.usize, .bind = index_bind, .class = gp, .reg = &index_reg },
|
||||||
|
};
|
||||||
|
const write_args = [_]WriteArg{
|
||||||
|
.{ .ty = elem_ty, .bind = .none, .class = gp, .reg = &dest_reg },
|
||||||
|
};
|
||||||
|
try self.allocRegs(
|
||||||
|
&read_args,
|
||||||
|
&write_args,
|
||||||
|
if (maybe_inst) |inst| .{
|
||||||
|
.corresponding_inst = inst,
|
||||||
|
.operand_mapping = &.{ 0, 1 },
|
||||||
|
} else null,
|
||||||
|
);
|
||||||
|
|
||||||
|
const tag: Mir.Inst.Tag = switch (elem_size) {
|
||||||
|
1 => .ldrb,
|
||||||
|
4 => .ldr,
|
||||||
|
else => unreachable,
|
||||||
|
};
|
||||||
|
const shift: u5 = switch (elem_size) {
|
||||||
|
1 => 0,
|
||||||
|
4 => 2,
|
||||||
|
else => unreachable,
|
||||||
|
};
|
||||||
|
|
||||||
|
_ = try self.addInst(.{
|
||||||
|
.tag = tag,
|
||||||
|
.data = .{ .rr_offset = .{
|
||||||
|
.rt = dest_reg,
|
||||||
|
.rn = base_reg,
|
||||||
|
.offset = .{ .offset = Instruction.Offset.reg(index_reg, .{ .lsl = shift }) },
|
||||||
|
} },
|
||||||
|
});
|
||||||
|
|
||||||
|
return MCValue{ .register = dest_reg };
|
||||||
|
},
|
||||||
|
else => {
|
||||||
|
const addr = try self.ptrArithmetic(.ptr_add, ptr_bind, index_bind, ptr_ty, Type.usize, null);
|
||||||
|
|
||||||
|
const dest = try self.allocRegOrMem(elem_ty, true, maybe_inst);
|
||||||
|
try self.load(dest, addr, ptr_ty);
|
||||||
|
return dest;
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void {
|
fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void {
|
||||||
const is_volatile = false; // TODO
|
|
||||||
const bin_op = self.air.instructions.items(.data)[inst].bin_op;
|
const bin_op = self.air.instructions.items(.data)[inst].bin_op;
|
||||||
|
const slice_ty = self.air.typeOf(bin_op.lhs);
|
||||||
if (!is_volatile and self.liveness.isUnused(inst)) return self.finishAir(inst, .dead, .{ bin_op.lhs, bin_op.rhs, .none });
|
const result: MCValue = if (!slice_ty.isVolatilePtr() and self.liveness.isUnused(inst)) .dead else result: {
|
||||||
const result: MCValue = result: {
|
|
||||||
const slice_mcv = try self.resolveInst(bin_op.lhs);
|
|
||||||
|
|
||||||
// TODO optimize for the case where the index is a constant,
|
|
||||||
// i.e. index_mcv == .immediate
|
|
||||||
const index_mcv = try self.resolveInst(bin_op.rhs);
|
|
||||||
const index_is_register = index_mcv == .register;
|
|
||||||
|
|
||||||
const slice_ty = self.air.typeOf(bin_op.lhs);
|
|
||||||
const elem_ty = slice_ty.childType();
|
|
||||||
const elem_size = @intCast(u32, elem_ty.abiSize(self.target.*));
|
|
||||||
|
|
||||||
var buf: Type.SlicePtrFieldTypeBuffer = undefined;
|
var buf: Type.SlicePtrFieldTypeBuffer = undefined;
|
||||||
const slice_ptr_field_type = slice_ty.slicePtrFieldType(&buf);
|
const ptr_ty = slice_ty.slicePtrFieldType(&buf);
|
||||||
|
|
||||||
const index_lock: ?RegisterLock = if (index_is_register)
|
|
||||||
self.register_manager.lockRegAssumeUnused(index_mcv.register)
|
|
||||||
else
|
|
||||||
null;
|
|
||||||
defer if (index_lock) |reg| self.register_manager.unlockReg(reg);
|
|
||||||
|
|
||||||
|
const slice_mcv = try self.resolveInst(bin_op.lhs);
|
||||||
const base_mcv = slicePtr(slice_mcv);
|
const base_mcv = slicePtr(slice_mcv);
|
||||||
|
|
||||||
switch (elem_size) {
|
const base_bind: ReadArg.Bind = .{ .mcv = base_mcv };
|
||||||
1, 4 => {
|
const index_bind: ReadArg.Bind = .{ .inst = bin_op.rhs };
|
||||||
const base_reg = switch (base_mcv) {
|
|
||||||
.register => |r| r,
|
|
||||||
else => try self.copyToTmpRegister(slice_ptr_field_type, base_mcv),
|
|
||||||
};
|
|
||||||
const base_reg_lock = self.register_manager.lockRegAssumeUnused(base_reg);
|
|
||||||
defer self.register_manager.unlockReg(base_reg_lock);
|
|
||||||
|
|
||||||
const dst_reg = try self.register_manager.allocReg(inst, gp);
|
break :result try self.ptrElemVal(base_bind, index_bind, ptr_ty, inst);
|
||||||
const dst_mcv = MCValue{ .register = dst_reg };
|
|
||||||
const dst_reg_lock = self.register_manager.lockRegAssumeUnused(dst_reg);
|
|
||||||
defer self.register_manager.unlockReg(dst_reg_lock);
|
|
||||||
|
|
||||||
const index_reg: Register = switch (index_mcv) {
|
|
||||||
.register => |reg| reg,
|
|
||||||
else => try self.copyToTmpRegister(Type.usize, index_mcv),
|
|
||||||
};
|
|
||||||
const index_reg_lock = self.register_manager.lockReg(index_reg);
|
|
||||||
defer if (index_reg_lock) |lock| self.register_manager.unlockReg(lock);
|
|
||||||
|
|
||||||
const tag: Mir.Inst.Tag = switch (elem_size) {
|
|
||||||
1 => .ldrb,
|
|
||||||
4 => .ldr,
|
|
||||||
else => unreachable,
|
|
||||||
};
|
|
||||||
const shift: u5 = switch (elem_size) {
|
|
||||||
1 => 0,
|
|
||||||
4 => 2,
|
|
||||||
else => unreachable,
|
|
||||||
};
|
|
||||||
|
|
||||||
_ = try self.addInst(.{
|
|
||||||
.tag = tag,
|
|
||||||
.data = .{ .rr_offset = .{
|
|
||||||
.rt = dst_reg,
|
|
||||||
.rn = base_reg,
|
|
||||||
.offset = .{ .offset = Instruction.Offset.reg(index_reg, .{ .lsl = shift }) },
|
|
||||||
} },
|
|
||||||
});
|
|
||||||
|
|
||||||
break :result dst_mcv;
|
|
||||||
},
|
|
||||||
else => {
|
|
||||||
const dest = try self.allocRegOrMem(self.air.typeOfIndex(inst), true, inst);
|
|
||||||
|
|
||||||
const base_bind: ReadArg.Bind = .{ .mcv = base_mcv };
|
|
||||||
const index_bind: ReadArg.Bind = .{ .mcv = index_mcv };
|
|
||||||
|
|
||||||
const addr = try self.ptrArithmetic(.ptr_add, base_bind, index_bind, slice_ptr_field_type, Type.usize, null);
|
|
||||||
try self.load(dest, addr, slice_ptr_field_type);
|
|
||||||
|
|
||||||
break :result dest;
|
|
||||||
},
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
|
return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
|
||||||
}
|
}
|
||||||
@ -2371,9 +2366,14 @@ fn airArrayElemVal(self: *Self, inst: Air.Inst.Index) !void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn airPtrElemVal(self: *Self, inst: Air.Inst.Index) !void {
|
fn airPtrElemVal(self: *Self, inst: Air.Inst.Index) !void {
|
||||||
const is_volatile = false; // TODO
|
|
||||||
const bin_op = self.air.instructions.items(.data)[inst].bin_op;
|
const bin_op = self.air.instructions.items(.data)[inst].bin_op;
|
||||||
const result: MCValue = if (!is_volatile and self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement ptr_elem_val for {}", .{self.target.cpu.arch});
|
const ptr_ty = self.air.typeOf(bin_op.lhs);
|
||||||
|
const result: MCValue = if (!ptr_ty.isVolatilePtr() and self.liveness.isUnused(inst)) .dead else result: {
|
||||||
|
const base_bind: ReadArg.Bind = .{ .inst = bin_op.lhs };
|
||||||
|
const index_bind: ReadArg.Bind = .{ .inst = bin_op.rhs };
|
||||||
|
|
||||||
|
break :result try self.ptrElemVal(base_bind, index_bind, ptr_ty, inst);
|
||||||
|
};
|
||||||
return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
|
return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -641,7 +641,6 @@ test "global constant is loaded with a runtime-known index" {
|
|||||||
|
|
||||||
test "multiline string literal is null terminated" {
|
test "multiline string literal is null terminated" {
|
||||||
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
|
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
|
||||||
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
|
|
||||||
|
|
||||||
const s1 =
|
const s1 =
|
||||||
\\one
|
\\one
|
||||||
|
|||||||
@ -576,7 +576,6 @@ fn testCastPtrOfArrayToSliceAndPtr() !void {
|
|||||||
test "cast *[1][*]const u8 to [*]const ?[*]const u8" {
|
test "cast *[1][*]const u8 to [*]const ?[*]const u8" {
|
||||||
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
|
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
|
||||||
if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
|
if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
|
||||||
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
|
|
||||||
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
|
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
|
||||||
|
|
||||||
const window_name = [1][*]const u8{"window name"};
|
const window_name = [1][*]const u8{"window name"};
|
||||||
@ -919,7 +918,6 @@ test "peer cast *[N:x]T to *[N]T" {
|
|||||||
|
|
||||||
test "peer cast [*:x]T to [*]T" {
|
test "peer cast [*:x]T to [*]T" {
|
||||||
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
|
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
|
||||||
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
|
|
||||||
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
|
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
|
||||||
|
|
||||||
const S = struct {
|
const S = struct {
|
||||||
@ -1004,7 +1002,6 @@ test "variable initialization uses result locations properly with regards to the
|
|||||||
|
|
||||||
test "cast between C pointer with different but compatible types" {
|
test "cast between C pointer with different but compatible types" {
|
||||||
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
|
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
|
||||||
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
|
|
||||||
|
|
||||||
const S = struct {
|
const S = struct {
|
||||||
fn foo(arg: [*]c_ushort) u16 {
|
fn foo(arg: [*]c_ushort) u16 {
|
||||||
|
|||||||
@ -9,7 +9,6 @@ var argv: [*]const [*]const u8 = undefined;
|
|||||||
test "const slice child" {
|
test "const slice child" {
|
||||||
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
|
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
|
||||||
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
|
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
|
||||||
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
|
|
||||||
|
|
||||||
const strs = [_][*]const u8{ "one", "two", "three" };
|
const strs = [_][*]const u8{ "one", "two", "three" };
|
||||||
argv = &strs;
|
argv = &strs;
|
||||||
|
|||||||
@ -137,7 +137,6 @@ test "pointer to type" {
|
|||||||
test "a type constructed in a global expression" {
|
test "a type constructed in a global expression" {
|
||||||
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
|
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
|
||||||
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
|
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
|
||||||
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
|
|
||||||
|
|
||||||
var l: List = undefined;
|
var l: List = undefined;
|
||||||
l.array[0] = 10;
|
l.array[0] = 10;
|
||||||
@ -804,7 +803,6 @@ test "array concatenation sets the sentinel - value" {
|
|||||||
test "array concatenation sets the sentinel - pointer" {
|
test "array concatenation sets the sentinel - pointer" {
|
||||||
if (builtin.zig_backend == .stage1) return error.SkipZigTest;
|
if (builtin.zig_backend == .stage1) return error.SkipZigTest;
|
||||||
if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
|
if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
|
||||||
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
|
|
||||||
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
|
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
|
||||||
|
|
||||||
var a = [2]u3{ 1, 7 };
|
var a = [2]u3{ 1, 7 };
|
||||||
@ -1071,7 +1069,6 @@ test "comptime break operand passing through runtime switch converted to runtime
|
|||||||
|
|
||||||
test "no dependency loop for alignment of self struct" {
|
test "no dependency loop for alignment of self struct" {
|
||||||
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
|
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
|
||||||
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
|
|
||||||
|
|
||||||
const S = struct {
|
const S = struct {
|
||||||
fn doTheTest() !void {
|
fn doTheTest() !void {
|
||||||
@ -1108,7 +1105,6 @@ test "no dependency loop for alignment of self struct" {
|
|||||||
|
|
||||||
test "no dependency loop for alignment of self bare union" {
|
test "no dependency loop for alignment of self bare union" {
|
||||||
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
|
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
|
||||||
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
|
|
||||||
|
|
||||||
const S = struct {
|
const S = struct {
|
||||||
fn doTheTest() !void {
|
fn doTheTest() !void {
|
||||||
@ -1145,7 +1141,6 @@ test "no dependency loop for alignment of self bare union" {
|
|||||||
|
|
||||||
test "no dependency loop for alignment of self tagged union" {
|
test "no dependency loop for alignment of self tagged union" {
|
||||||
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
|
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
|
||||||
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
|
|
||||||
|
|
||||||
const S = struct {
|
const S = struct {
|
||||||
fn doTheTest() !void {
|
fn doTheTest() !void {
|
||||||
|
|||||||
@ -91,7 +91,6 @@ fn max_f64(a: f64, b: f64) f64 {
|
|||||||
|
|
||||||
test "type constructed by comptime function call" {
|
test "type constructed by comptime function call" {
|
||||||
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
|
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;
|
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
|
||||||
|
|
||||||
var l: SimpleList(10) = undefined;
|
var l: SimpleList(10) = undefined;
|
||||||
|
|||||||
@ -18,7 +18,6 @@ fn testDerefPtr() !void {
|
|||||||
|
|
||||||
test "pointer arithmetic" {
|
test "pointer arithmetic" {
|
||||||
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
|
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;
|
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
|
||||||
|
|
||||||
var ptr: [*]const u8 = "abcd";
|
var ptr: [*]const u8 = "abcd";
|
||||||
@ -280,7 +279,6 @@ test "array initialization types" {
|
|||||||
|
|
||||||
test "null terminated pointer" {
|
test "null terminated pointer" {
|
||||||
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
|
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
|
||||||
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
|
|
||||||
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
|
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
|
||||||
|
|
||||||
const S = struct {
|
const S = struct {
|
||||||
@ -298,7 +296,6 @@ test "null terminated pointer" {
|
|||||||
|
|
||||||
test "allow any sentinel" {
|
test "allow any sentinel" {
|
||||||
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
|
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
|
||||||
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
|
|
||||||
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
|
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
|
||||||
|
|
||||||
const S = struct {
|
const S = struct {
|
||||||
@ -314,7 +311,6 @@ test "allow any sentinel" {
|
|||||||
|
|
||||||
test "pointer sentinel with enums" {
|
test "pointer sentinel with enums" {
|
||||||
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
|
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
|
||||||
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
|
|
||||||
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
|
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
|
||||||
|
|
||||||
const S = struct {
|
const S = struct {
|
||||||
|
|||||||
@ -92,7 +92,6 @@ const FooExtern = extern union {
|
|||||||
};
|
};
|
||||||
|
|
||||||
test "basic extern unions" {
|
test "basic extern unions" {
|
||||||
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
|
|
||||||
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
|
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
|
||||||
|
|
||||||
var foo = FooExtern{ .int = 1 };
|
var foo = FooExtern{ .int = 1 };
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user