From 5060ab99c94dd8afc8b84e74fe4d050c88cdfc0a Mon Sep 17 00:00:00 2001 From: Jacob Young Date: Wed, 18 Jun 2025 10:59:09 -0400 Subject: aarch64: add new from scratch self-hosted backend --- test/behavior/pointers.zig | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) (limited to 'test/behavior/pointers.zig') diff --git a/test/behavior/pointers.zig b/test/behavior/pointers.zig index d98c1a73d9..ef2b4b9597 100644 --- a/test/behavior/pointers.zig +++ b/test/behavior/pointers.zig @@ -18,7 +18,6 @@ fn testDerefPtr() !void { } test "pointer-integer arithmetic" { - if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; @@ -232,7 +231,6 @@ test "peer type resolution with C pointer and const pointer" { test "implicit casting between C pointer and optional non-C pointer" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; @@ -248,8 +246,8 @@ test "implicit casting between C pointer and optional non-C pointer" { } test "implicit cast error unions with non-optional to optional pointer" { + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; @@ -298,7 +296,6 @@ test "allowzero pointer and slice" { test "assign null directly to C pointer and test null equality" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; @@ -366,7 +363,6 @@ test "array initialization types" { } test "null terminated pointer" { - if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; @@ -384,7 +380,6 @@ test "null terminated pointer" { } test "allow any sentinel" { - if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; @@ -401,7 +396,6 @@ test "allow any sentinel" { } test "pointer sentinel with enums" { - if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; @@ -515,7 +509,6 @@ test "@intFromPtr on null optional at comptime" { } test "indexing array with sentinel returns correct type" { - 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_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; @@ -525,7 +518,6 @@ test "indexing array with sentinel returns correct type" { } test "element pointer to slice" { - if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; @@ -548,7 +540,6 @@ test "element pointer to slice" { } test "element pointer arithmetic to slice" { - if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; @@ -604,7 +595,6 @@ test "pointer to constant decl preserves alignment" { test "ptrCast comptime known slice to C pointer" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; @@ -625,7 +615,6 @@ test "pointer alignment and element type include call expression" { } test "pointer to array has explicit alignment" { - if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; const S = struct { -- cgit v1.2.3 From 869ef00602328f97ea8c88358310cbd34d4391ab Mon Sep 17 00:00:00 2001 From: Jacob Young Date: Wed, 23 Jul 2025 12:50:41 -0400 Subject: aarch64: more progress - factor out `loadReg` - support all general system control registers in inline asm - fix asserts after iterating field offsets - fix typo in `slice_elem_val` - fix translation of argument locations --- src/codegen/aarch64.zig | 4 +- src/codegen/aarch64/Assemble.zig | 13 +- src/codegen/aarch64/Select.zig | 526 +++++++++++++++++------------------ src/codegen/aarch64/encoding.zig | 475 ++++++++++++++++++++++++++++--- src/codegen/aarch64/instructions.zon | 14 +- test/behavior/basic.zig | 3 - test/behavior/cast.zig | 1 - test/behavior/pointers.zig | 1 - 8 files changed, 721 insertions(+), 316 deletions(-) (limited to 'test/behavior/pointers.zig') diff --git a/src/codegen/aarch64.zig b/src/codegen/aarch64.zig index 6f95fff58e..f4b02a13c8 100644 --- a/src/codegen/aarch64.zig +++ b/src/codegen/aarch64.zig @@ -113,9 +113,7 @@ pub fn generate( }, .stack_slot => |stack_slot| { assert(stack_slot.base == .sp); - passed_vi.setParent(&isel, .{ - .stack_slot = named_stack_args.withOffset(stack_slot.offset), - }); + passed_vi.changeStackSlot(&isel, named_stack_args.withOffset(stack_slot.offset)); }, .address, .value, .constant => unreachable, } diff --git a/src/codegen/aarch64/Assemble.zig b/src/codegen/aarch64/Assemble.zig index 235c445411..080df667d7 100644 --- a/src/codegen/aarch64/Assemble.zig +++ b/src/codegen/aarch64/Assemble.zig @@ -215,6 +215,7 @@ fn nextToken(as: *Assemble, buf: *[token_buf_len]u8, comptime opts: struct { const SymbolSpec = union(enum) { reg: struct { format: aarch64.encoding.Register.Format, allow_sp: bool = false }, + systemreg, imm: struct { type: std.builtin.Type.Int, multiple_of: comptime_int = 1, @@ -227,6 +228,7 @@ const SymbolSpec = union(enum) { fn Storage(comptime spec: SymbolSpec) type { return switch (spec) { .reg => aarch64.encoding.Register, + .systemreg => aarch64.encoding.Register.System, .imm => |imm| @Type(.{ .int = imm.type }), .extend => Instruction.DataProcessingRegister.AddSubtractExtendedRegister.Option, .shift => Instruction.DataProcessingRegister.Shift.Op, @@ -238,8 +240,7 @@ const SymbolSpec = union(enum) { const Result = Storage(spec); switch (spec) { .reg => |reg_spec| { - var buf: [token_buf_len]u8 = undefined; - const reg = Result.parse(std.ascii.lowerString(&buf, token[0..@min(token.len, buf.len)])) orelse { + const reg = Result.parse(token) orelse { log.debug("invalid register: \"{f}\"", .{std.zig.fmtString(token)}); return null; }; @@ -253,6 +254,14 @@ const SymbolSpec = union(enum) { } return reg; }, + .systemreg => { + const systemreg = Result.parse(token) orelse { + log.debug("invalid system register: \"{f}\"", .{std.zig.fmtString(token)}); + return null; + }; + assert(systemreg.op0 >= 2); + return systemreg; + }, .imm => |imm_spec| { const imm = std.fmt.parseInt(Result, token, 0) catch { log.debug("invalid immediate: \"{f}\"", .{std.zig.fmtString(token)}); diff --git a/src/codegen/aarch64/Select.zig b/src/codegen/aarch64/Select.zig index 10cf4f40c2..f7da48d847 100644 --- a/src/codegen/aarch64/Select.zig +++ b/src/codegen/aarch64/Select.zig @@ -5535,7 +5535,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void { 2 => if (elem_is_vector) .ldr(elem_ra.h(), .{ .extended_register = .{ .base = base_mat.ra.x(), .index = index_mat.ra.x(), - .extend = .{ .lsl = 0 }, + .extend = .{ .lsl = 1 }, } }) else switch (elem_vi.value.signedness(isel)) { .signed => .ldrsh(elem_ra.w(), .{ .extended_register = .{ .base = base_mat.ra.x(), @@ -5558,15 +5558,14 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void { .index = index_mat.ra.x(), .extend = .{ .lsl = 3 }, } }), - 16 => .ldr(elem_ra.q(), .{ .extended_register = .{ + 16 => if (elem_is_vector) .ldr(elem_ra.q(), .{ .extended_register = .{ .base = base_mat.ra.x(), .index = index_mat.ra.x(), .extend = .{ .lsl = 4 }, - } }), + } }) else unreachable, }); try index_mat.finish(isel); try base_mat.finish(isel); - break :unused; } else { const elem_ptr_ra = try isel.allocIntReg(); defer isel.freeReg(elem_ptr_ra); @@ -5611,66 +5610,81 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void { const ptr_ty = isel.air.typeOf(bin_op.lhs, ip); const ptr_info = ptr_ty.ptrInfo(zcu); const elem_size = elem_vi.value.size(isel); - switch (elem_size) { + const elem_is_vector = elem_vi.value.isVector(isel); + if (switch (elem_size) { 0 => unreachable, - 1, 2, 4, 8 => { - const elem_ra = try elem_vi.value.defReg(isel) orelse break :unused; - const base_vi = try isel.use(bin_op.lhs); - const index_vi = try isel.use(bin_op.rhs); - const base_mat = try base_vi.matReg(isel); - const index_mat = try index_vi.matReg(isel); - try isel.emit(switch (elem_size) { - else => unreachable, - 1 => switch (elem_vi.value.signedness(isel)) { - .signed => .ldrsb(elem_ra.w(), .{ .extended_register = .{ - .base = base_mat.ra.x(), - .index = index_mat.ra.x(), - .extend = .{ .lsl = 0 }, - } }), - .unsigned => .ldrb(elem_ra.w(), .{ .extended_register = .{ - .base = base_mat.ra.x(), - .index = index_mat.ra.x(), - .extend = .{ .lsl = 0 }, - } }), - }, - 2 => switch (elem_vi.value.signedness(isel)) { - .signed => .ldrsh(elem_ra.w(), .{ .extended_register = .{ - .base = base_mat.ra.x(), - .index = index_mat.ra.x(), - .extend = .{ .lsl = 1 }, - } }), - .unsigned => .ldrh(elem_ra.w(), .{ .extended_register = .{ - .base = base_mat.ra.x(), - .index = index_mat.ra.x(), - .extend = .{ .lsl = 1 }, - } }), - }, - 4 => .ldr(elem_ra.w(), .{ .extended_register = .{ + 1, 2, 4, 8 => true, + 16 => elem_is_vector, + else => false, + }) { + const elem_ra = try elem_vi.value.defReg(isel) orelse break :unused; + const base_vi = try isel.use(bin_op.lhs); + const index_vi = try isel.use(bin_op.rhs); + const base_mat = try base_vi.matReg(isel); + const index_mat = try index_vi.matReg(isel); + try isel.emit(switch (elem_size) { + else => unreachable, + 1 => if (elem_is_vector) .ldr(elem_ra.b(), .{ .extended_register = .{ + .base = base_mat.ra.x(), + .index = index_mat.ra.x(), + .extend = .{ .lsl = 0 }, + } }) else switch (elem_vi.value.signedness(isel)) { + .signed => .ldrsb(elem_ra.w(), .{ .extended_register = .{ .base = base_mat.ra.x(), .index = index_mat.ra.x(), - .extend = .{ .lsl = 2 }, + .extend = .{ .lsl = 0 }, } }), - 8 => .ldr(elem_ra.x(), .{ .extended_register = .{ + .unsigned => .ldrb(elem_ra.w(), .{ .extended_register = .{ .base = base_mat.ra.x(), .index = index_mat.ra.x(), - .extend = .{ .lsl = 3 }, + .extend = .{ .lsl = 0 }, } }), - }); - try index_mat.finish(isel); - try base_mat.finish(isel); - }, - else => { - const elem_ptr_ra = try isel.allocIntReg(); - defer isel.freeReg(elem_ptr_ra); - if (!try elem_vi.value.load(isel, ptr_ty.elemType2(zcu), elem_ptr_ra, .{ - .@"volatile" = ptr_info.flags.is_volatile, - })) break :unused; - const base_vi = try isel.use(bin_op.lhs); - const base_mat = try base_vi.matReg(isel); - const index_vi = try isel.use(bin_op.rhs); - try isel.elemPtr(elem_ptr_ra, base_mat.ra, .add, elem_size, index_vi); - try base_mat.finish(isel); - }, + }, + 2 => if (elem_is_vector) .ldr(elem_ra.h(), .{ .extended_register = .{ + .base = base_mat.ra.x(), + .index = index_mat.ra.x(), + .extend = .{ .lsl = 1 }, + } }) else switch (elem_vi.value.signedness(isel)) { + .signed => .ldrsh(elem_ra.w(), .{ .extended_register = .{ + .base = base_mat.ra.x(), + .index = index_mat.ra.x(), + .extend = .{ .lsl = 1 }, + } }), + .unsigned => .ldrh(elem_ra.w(), .{ .extended_register = .{ + .base = base_mat.ra.x(), + .index = index_mat.ra.x(), + .extend = .{ .lsl = 1 }, + } }), + }, + 4 => .ldr(if (elem_is_vector) elem_ra.s() else elem_ra.w(), .{ .extended_register = .{ + .base = base_mat.ra.x(), + .index = index_mat.ra.x(), + .extend = .{ .lsl = 2 }, + } }), + 8 => .ldr(if (elem_is_vector) elem_ra.d() else elem_ra.x(), .{ .extended_register = .{ + .base = base_mat.ra.x(), + .index = index_mat.ra.x(), + .extend = .{ .lsl = 3 }, + } }), + 16 => if (elem_is_vector) .ldr(elem_ra.q(), .{ .extended_register = .{ + .base = base_mat.ra.x(), + .index = index_mat.ra.x(), + .extend = .{ .lsl = 4 }, + } }) else unreachable, + }); + try index_mat.finish(isel); + try base_mat.finish(isel); + } else { + const elem_ptr_ra = try isel.allocIntReg(); + defer isel.freeReg(elem_ptr_ra); + if (!try elem_vi.value.load(isel, ptr_ty.elemType2(zcu), elem_ptr_ra, .{ + .@"volatile" = ptr_info.flags.is_volatile, + })) break :unused; + const base_vi = try isel.use(bin_op.lhs); + const base_mat = try base_vi.matReg(isel); + const index_vi = try isel.use(bin_op.rhs); + try isel.elemPtr(elem_ptr_ra, base_mat.ra, .add, elem_size, index_vi); + try base_mat.finish(isel); } } if (air.next()) |next_air_tag| continue :air_tag next_air_tag; @@ -6250,11 +6264,12 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void { try agg_part_vi.?.move(isel, elems[field_index]); field_offset += field_size; } - assert(field_offset == agg_vi.value.size(isel)); + assert(loaded_struct.flagsUnordered(ip).alignment.forward(field_offset) == agg_vi.value.size(isel)); }, .tuple_type => |tuple_type| { const elems: []const Air.Inst.Ref = @ptrCast(isel.air.extra.items[ty_pl.payload..][0..tuple_type.types.len]); + var tuple_align: InternPool.Alignment = .@"1"; var field_offset: u64 = 0; for ( tuple_type.types.get(ip), @@ -6263,7 +6278,9 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void { ) |field_ty_index, field_val, elem| { if (field_val != .none) continue; const field_ty: ZigType = .fromInterned(field_ty_index); - field_offset = field_ty.abiAlignment(zcu).forward(field_offset); + const field_align = field_ty.abiAlignment(zcu); + tuple_align = tuple_align.maxStrict(field_align); + field_offset = field_align.forward(field_offset); const field_size = field_ty.abiSize(zcu); if (field_size == 0) continue; var agg_part_it = agg_vi.value.field(agg_ty, field_offset, field_size); @@ -6271,7 +6288,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void { try agg_part_vi.?.move(isel, elem); field_offset += field_size; } - assert(field_offset == agg_vi.value.size(isel)); + assert(tuple_align.forward(field_offset) == agg_vi.value.size(isel)); }, else => return isel.fail("aggregate init {f}", .{isel.fmtType(agg_ty)}), } @@ -7283,6 +7300,175 @@ fn ctzLimb( } } +fn loadReg( + isel: *Select, + ra: Register.Alias, + size: u64, + signedness: std.builtin.Signedness, + base_ra: Register.Alias, + offset: i65, +) !void { + switch (size) { + 0 => unreachable, + 1 => { + if (std.math.cast(u12, offset)) |unsigned_offset| return isel.emit(if (ra.isVector()) .ldr( + ra.b(), + .{ .unsigned_offset = .{ + .base = base_ra.x(), + .offset = unsigned_offset, + } }, + ) else switch (signedness) { + .signed => .ldrsb(ra.w(), .{ .unsigned_offset = .{ + .base = base_ra.x(), + .offset = unsigned_offset, + } }), + .unsigned => .ldrb(ra.w(), .{ .unsigned_offset = .{ + .base = base_ra.x(), + .offset = unsigned_offset, + } }), + }); + if (std.math.cast(i9, offset)) |signed_offset| return isel.emit(if (ra.isVector()) + .ldur(ra.b(), base_ra.x(), signed_offset) + else switch (signedness) { + .signed => .ldursb(ra.w(), base_ra.x(), signed_offset), + .unsigned => .ldurb(ra.w(), base_ra.x(), signed_offset), + }); + }, + 2 => { + if (std.math.cast(u13, offset)) |unsigned_offset| if (unsigned_offset % 2 == 0) + return isel.emit(if (ra.isVector()) .ldr( + ra.h(), + .{ .unsigned_offset = .{ + .base = base_ra.x(), + .offset = unsigned_offset, + } }, + ) else switch (signedness) { + .signed => .ldrsh( + ra.w(), + .{ .unsigned_offset = .{ + .base = base_ra.x(), + .offset = unsigned_offset, + } }, + ), + .unsigned => .ldrh( + ra.w(), + .{ .unsigned_offset = .{ + .base = base_ra.x(), + .offset = unsigned_offset, + } }, + ), + }); + if (std.math.cast(i9, offset)) |signed_offset| return isel.emit(if (ra.isVector()) + .ldur(ra.h(), base_ra.x(), signed_offset) + else switch (signedness) { + .signed => .ldursh(ra.w(), base_ra.x(), signed_offset), + .unsigned => .ldurh(ra.w(), base_ra.x(), signed_offset), + }); + }, + 3 => { + const lo16_ra = try isel.allocIntReg(); + defer isel.freeReg(lo16_ra); + try isel.emit(.orr(ra.w(), lo16_ra.w(), .{ .shifted_register = .{ + .register = ra.w(), + .shift = .{ .lsl = 16 }, + } })); + try isel.loadReg(ra, 1, signedness, base_ra, offset + 2); + return isel.loadReg(lo16_ra, 2, .unsigned, base_ra, offset); + }, + 4 => { + if (std.math.cast(u14, offset)) |unsigned_offset| if (unsigned_offset % 4 == 0) return isel.emit(.ldr( + if (ra.isVector()) ra.s() else ra.w(), + .{ .unsigned_offset = .{ + .base = base_ra.x(), + .offset = unsigned_offset, + } }, + )); + if (std.math.cast(i9, offset)) |signed_offset| return isel.emit(.ldur( + if (ra.isVector()) ra.s() else ra.w(), + base_ra.x(), + signed_offset, + )); + }, + 5, 6 => { + const lo32_ra = try isel.allocIntReg(); + defer isel.freeReg(lo32_ra); + try isel.emit(.orr(ra.x(), lo32_ra.x(), .{ .shifted_register = .{ + .register = ra.x(), + .shift = .{ .lsl = 32 }, + } })); + try isel.loadReg(ra, size - 4, signedness, base_ra, offset + 4); + return isel.loadReg(lo32_ra, 4, .unsigned, base_ra, offset); + }, + 7 => { + const lo32_ra = try isel.allocIntReg(); + defer isel.freeReg(lo32_ra); + const lo48_ra = try isel.allocIntReg(); + defer isel.freeReg(lo48_ra); + try isel.emit(.orr(ra.x(), lo48_ra.x(), .{ .shifted_register = .{ + .register = ra.x(), + .shift = .{ .lsl = 32 + 16 }, + } })); + try isel.loadReg(ra, 1, signedness, base_ra, offset + 4 + 2); + try isel.emit(.orr(lo48_ra.x(), lo32_ra.x(), .{ .shifted_register = .{ + .register = lo48_ra.x(), + .shift = .{ .lsl = 32 }, + } })); + try isel.loadReg(lo48_ra, 2, .unsigned, base_ra, offset + 4); + return isel.loadReg(lo32_ra, 4, .unsigned, base_ra, offset); + }, + 8 => { + if (std.math.cast(u15, offset)) |unsigned_offset| if (unsigned_offset % 8 == 0) return isel.emit(.ldr( + if (ra.isVector()) ra.d() else ra.x(), + .{ .unsigned_offset = .{ + .base = base_ra.x(), + .offset = unsigned_offset, + } }, + )); + if (std.math.cast(i9, offset)) |signed_offset| return isel.emit(.ldur( + if (ra.isVector()) ra.d() else ra.x(), + base_ra.x(), + signed_offset, + )); + }, + 16 => { + if (std.math.cast(u16, offset)) |unsigned_offset| if (unsigned_offset % 16 == 0) return isel.emit(.ldr( + ra.q(), + .{ .unsigned_offset = .{ + .base = base_ra.x(), + .offset = unsigned_offset, + } }, + )); + if (std.math.cast(i9, offset)) |signed_offset| return isel.emit(.ldur(ra.q(), base_ra.x(), signed_offset)); + }, + else => return isel.fail("bad load size: {d}", .{size}), + } + const ptr_ra = try isel.allocIntReg(); + defer isel.freeReg(ptr_ra); + try isel.loadReg(ra, size, signedness, ptr_ra, 0); + if (std.math.cast(u24, offset)) |pos_offset| { + const lo12: u12 = @truncate(pos_offset >> 0); + const hi12: u12 = @intCast(pos_offset >> 12); + if (hi12 > 0) try isel.emit(.add( + ptr_ra.x(), + if (lo12 > 0) ptr_ra.x() else base_ra.x(), + .{ .shifted_immediate = .{ .immediate = hi12, .lsl = .@"12" } }, + )); + if (lo12 > 0 or hi12 == 0) try isel.emit(.add(ptr_ra.x(), base_ra.x(), .{ .immediate = lo12 })); + } else if (std.math.cast(u24, -offset)) |neg_offset| { + const lo12: u12 = @truncate(neg_offset >> 0); + const hi12: u12 = @intCast(neg_offset >> 12); + if (hi12 > 0) try isel.emit(.sub( + ptr_ra.x(), + if (lo12 > 0) ptr_ra.x() else base_ra.x(), + .{ .shifted_immediate = .{ .immediate = hi12, .lsl = .@"12" } }, + )); + if (lo12 > 0 or hi12 == 0) try isel.emit(.sub(ptr_ra.x(), base_ra.x(), .{ .immediate = lo12 })); + } else { + try isel.emit(.add(ptr_ra.x(), base_ra.x(), .{ .register = ptr_ra.x() })); + try isel.movImmediate(ptr_ra.x(), @truncate(@as(u65, @bitCast(offset)))); + } +} + fn storeReg( isel: *Select, ra: Register.Alias, @@ -7558,6 +7744,13 @@ pub const Value = struct { }; } + pub fn changeStackSlot(vi: Value.Index, isel: *Select, new_stack_slot: Indirect) void { + const value = vi.get(isel); + assert(value.flags.parent_tag == .stack_slot); + value.flags.parent_tag = .unallocated; + vi.setParent(isel, .{ .stack_slot = new_stack_slot }); + } + pub fn parent(vi: Value.Index, isel: *Select) Parent { const value = vi.get(isel); return switch (value.flags.parent_tag) { @@ -8070,123 +8263,7 @@ pub const Value = struct { }), 64 => {}, }; - try isel.emit(emit: switch (part_size) { - else => return isel.fail("bad load size of {d}", .{part_size}), - 1 => if (part_is_vector) .ldr(part_ra.b(), .{ .unsigned_offset = .{ - .base = base_ra.x(), - .offset = @intCast(opts.offset), - } }) else switch (part_vi.signedness(isel)) { - .signed => .ldrsb(part_ra.w(), .{ .unsigned_offset = .{ - .base = base_ra.x(), - .offset = @intCast(opts.offset), - } }), - .unsigned => .ldrb(part_ra.w(), .{ .unsigned_offset = .{ - .base = base_ra.x(), - .offset = @intCast(opts.offset), - } }), - }, - 2 => if (part_is_vector) .ldr(part_ra.h(), .{ .unsigned_offset = .{ - .base = base_ra.x(), - .offset = @intCast(opts.offset), - } }) else switch (part_vi.signedness(isel)) { - .signed => .ldrsh(part_ra.w(), .{ .unsigned_offset = .{ - .base = base_ra.x(), - .offset = @intCast(opts.offset), - } }), - .unsigned => .ldrh(part_ra.w(), .{ .unsigned_offset = .{ - .base = base_ra.x(), - .offset = @intCast(opts.offset), - } }), - }, - 3 => { - const lo16_ra = try isel.allocIntReg(); - defer isel.freeReg(lo16_ra); - try isel.emit(.orr(part_ra.w(), lo16_ra.w(), .{ .shifted_register = .{ - .register = part_ra.w(), - .shift = .{ .lsl = 16 }, - } })); - try isel.emit(switch (part_vi.signedness(isel)) { - .signed => .ldrsb(part_ra.w(), .{ .unsigned_offset = .{ - .base = base_ra.x(), - .offset = @intCast(opts.offset + 2), - } }), - .unsigned => .ldrb(part_ra.w(), .{ .unsigned_offset = .{ - .base = base_ra.x(), - .offset = @intCast(opts.offset + 2), - } }), - }); - break :emit .ldrh(lo16_ra.w(), .{ .unsigned_offset = .{ - .base = base_ra.x(), - .offset = @intCast(opts.offset), - } }); - }, - 4 => .ldr(if (part_is_vector) part_ra.s() else part_ra.w(), .{ .unsigned_offset = .{ - .base = base_ra.x(), - .offset = @intCast(opts.offset), - } }), - 5 => { - const lo32_ra = try isel.allocIntReg(); - defer isel.freeReg(lo32_ra); - try isel.emit(.orr(part_ra.x(), lo32_ra.x(), .{ .shifted_register = .{ - .register = part_ra.x(), - .shift = .{ .lsl = 32 }, - } })); - try isel.emit(switch (part_vi.signedness(isel)) { - .signed => .ldrsb(part_ra.w(), .{ .unsigned_offset = .{ - .base = base_ra.x(), - .offset = @intCast(opts.offset + 4), - } }), - .unsigned => .ldrb(part_ra.w(), .{ .unsigned_offset = .{ - .base = base_ra.x(), - .offset = @intCast(opts.offset + 4), - } }), - }); - break :emit .ldr(lo32_ra.w(), .{ .unsigned_offset = .{ - .base = base_ra.x(), - .offset = @intCast(opts.offset), - } }); - }, - 7 => { - const lo32_ra = try isel.allocIntReg(); - defer isel.freeReg(lo32_ra); - const lo48_ra = try isel.allocIntReg(); - defer isel.freeReg(lo48_ra); - try isel.emit(.orr(part_ra.x(), lo48_ra.x(), .{ .shifted_register = .{ - .register = part_ra.x(), - .shift = .{ .lsl = 32 + 16 }, - } })); - try isel.emit(switch (part_vi.signedness(isel)) { - .signed => .ldrsb(part_ra.w(), .{ .unsigned_offset = .{ - .base = base_ra.x(), - .offset = @intCast(opts.offset + 4 + 2), - } }), - .unsigned => .ldrb(part_ra.w(), .{ .unsigned_offset = .{ - .base = base_ra.x(), - .offset = @intCast(opts.offset + 4 + 2), - } }), - }); - try isel.emit(.orr(lo48_ra.x(), lo32_ra.x(), .{ .shifted_register = .{ - .register = lo48_ra.x(), - .shift = .{ .lsl = 32 }, - } })); - try isel.emit(.ldrh(lo48_ra.w(), .{ .unsigned_offset = .{ - .base = base_ra.x(), - .offset = @intCast(opts.offset + 4), - } })); - break :emit .ldr(lo32_ra.w(), .{ .unsigned_offset = .{ - .base = base_ra.x(), - .offset = @intCast(opts.offset), - } }); - }, - 8 => .ldr(if (part_is_vector) part_ra.d() else part_ra.x(), .{ .unsigned_offset = .{ - .base = base_ra.x(), - .offset = @intCast(opts.offset), - } }), - 16 => .ldr(part_ra.q(), .{ .unsigned_offset = .{ - .base = base_ra.x(), - .offset = @intCast(opts.offset), - } }), - }); + try isel.loadReg(part_ra, part_size, part_vi.signedness(isel), base_ra, opts.offset); if (part_ra != .zr) { const live_vi = isel.live_registers.getPtr(part_ra); assert(live_vi.* == .allocating); @@ -9104,7 +9181,7 @@ pub const Value = struct { const live_vi = isel.live_registers.getPtr(mat.ra); assert(live_vi.* == .allocating); var vi = mat.vi; - var offset: i65 = 0; + var offset: u64 = 0; const size = mat.vi.size(isel); free: while (true) { if (vi.register(isel)) |ra| { @@ -9156,93 +9233,16 @@ pub const Value = struct { live_vi.* = mat.vi; return; }, - .stack_slot => |stack_slot| { - offset += stack_slot.offset; - break :free try isel.emit(switch (size) { - else => unreachable, - 1 => if (mat.ra.isVector()) .ldr(mat.ra.b(), .{ .unsigned_offset = .{ - .base = stack_slot.base.x(), - .offset = @intCast(offset), - } }) else switch (mat.vi.signedness(isel)) { - .signed => .ldrsb(mat.ra.w(), .{ .unsigned_offset = .{ - .base = stack_slot.base.x(), - .offset = @intCast(offset), - } }), - .unsigned => .ldrb(mat.ra.w(), .{ .unsigned_offset = .{ - .base = stack_slot.base.x(), - .offset = @intCast(offset), - } }), - }, - 2 => if (mat.ra.isVector()) .ldr(mat.ra.h(), .{ .unsigned_offset = .{ - .base = stack_slot.base.x(), - .offset = @intCast(offset), - } }) else switch (mat.vi.signedness(isel)) { - .signed => .ldrsh(mat.ra.w(), .{ .unsigned_offset = .{ - .base = stack_slot.base.x(), - .offset = @intCast(offset), - } }), - .unsigned => .ldrh(mat.ra.w(), .{ .unsigned_offset = .{ - .base = stack_slot.base.x(), - .offset = @intCast(offset), - } }), - }, - 4 => .ldr(if (mat.ra.isVector()) mat.ra.s() else mat.ra.w(), .{ .unsigned_offset = .{ - .base = stack_slot.base.x(), - .offset = @intCast(offset), - } }), - 8 => .ldr(if (mat.ra.isVector()) mat.ra.d() else mat.ra.x(), .{ .unsigned_offset = .{ - .base = stack_slot.base.x(), - .offset = @intCast(offset), - } }), - 16 => .ldr(mat.ra.q(), .{ .unsigned_offset = .{ - .base = stack_slot.base.x(), - .offset = @intCast(offset), - } }), - }); - }, + .stack_slot => |stack_slot| break :free try isel.loadReg( + mat.ra, + size, + mat.vi.signedness(isel), + stack_slot.base, + @as(i65, stack_slot.offset) + offset, + ), .address => |base_vi| { const base_mat = try base_vi.matReg(isel); - try isel.emit(switch (size) { - else => unreachable, - 1 => if (mat.ra.isVector()) .ldr(mat.ra.b(), .{ .unsigned_offset = .{ - .base = base_mat.ra.x(), - .offset = @intCast(offset), - } }) else switch (mat.vi.signedness(isel)) { - .signed => .ldrsb(mat.ra.w(), .{ .unsigned_offset = .{ - .base = base_mat.ra.x(), - .offset = @intCast(offset), - } }), - .unsigned => .ldrb(mat.ra.w(), .{ .unsigned_offset = .{ - .base = base_mat.ra.x(), - .offset = @intCast(offset), - } }), - }, - 2 => if (mat.ra.isVector()) .ldr(mat.ra.h(), .{ .unsigned_offset = .{ - .base = base_mat.ra.x(), - .offset = @intCast(offset), - } }) else switch (mat.vi.signedness(isel)) { - .signed => .ldrsh(mat.ra.w(), .{ .unsigned_offset = .{ - .base = base_mat.ra.x(), - .offset = @intCast(offset), - } }), - .unsigned => .ldrh(mat.ra.w(), .{ .unsigned_offset = .{ - .base = base_mat.ra.x(), - .offset = @intCast(offset), - } }), - }, - 4 => .ldr(if (mat.ra.isVector()) mat.ra.s() else mat.ra.w(), .{ .unsigned_offset = .{ - .base = base_mat.ra.x(), - .offset = @intCast(offset), - } }), - 8 => .ldr(if (mat.ra.isVector()) mat.ra.d() else mat.ra.x(), .{ .unsigned_offset = .{ - .base = base_mat.ra.x(), - .offset = @intCast(offset), - } }), - 16 => .ldr(mat.ra.q(), .{ .unsigned_offset = .{ - .base = base_mat.ra.x(), - .offset = @intCast(offset), - } }), - }); + try isel.loadReg(mat.ra, size, mat.vi.signedness(isel), base_mat.ra, offset); break :free try base_mat.finish(isel); }, .value => |parent_vi| vi = parent_vi, diff --git a/src/codegen/aarch64/encoding.zig b/src/codegen/aarch64/encoding.zig index 1aef2f40c2..1697b2957b 100644 --- a/src/codegen/aarch64/encoding.zig +++ b/src/codegen/aarch64/encoding.zig @@ -1072,7 +1072,7 @@ pub const Register = struct { } pub fn parse(reg: []const u8) ?Register { - return if (reg.len == 0) null else switch (reg[0]) { + return if (reg.len == 0) null else switch (std.ascii.toLower(reg[0])) { else => null, 'r' => if (std.fmt.parseInt(u5, reg[1..], 10)) |n| switch (n) { 0...30 => .{ @@ -1087,27 +1087,27 @@ pub const Register = struct { .format = .{ .integer = .doubleword }, }, 31 => null, - } else |_| if (std.mem.eql(u8, reg, "xzr")) .xzr else null, + } else |_| if (toLowerEqlAssertLower(reg, "xzr")) .xzr else null, 'w' => if (std.fmt.parseInt(u5, reg[1..], 10)) |n| switch (n) { 0...30 => .{ .alias = @enumFromInt(@intFromEnum(Alias.r0) + n), .format = .{ .integer = .word }, }, 31 => null, - } else |_| if (std.mem.eql(u8, reg, "wzr")) + } else |_| if (toLowerEqlAssertLower(reg, "wzr")) .wzr - else if (std.mem.eql(u8, reg, "wsp")) + else if (toLowerEqlAssertLower(reg, "wsp")) .wsp else null, - 'i' => return if (std.mem.eql(u8, reg, "ip") or std.mem.eql(u8, reg, "ip0")) + 'i' => return if (toLowerEqlAssertLower(reg, "ip") or toLowerEqlAssertLower(reg, "ip0")) .ip0 - else if (std.mem.eql(u8, reg, "ip1")) + else if (toLowerEqlAssertLower(reg, "ip1")) .ip1 else null, - 'f' => return if (std.mem.eql(u8, reg, "fp")) .fp else null, - 'p' => return if (std.mem.eql(u8, reg, "pc")) .pc else null, + 'f' => return if (toLowerEqlAssertLower(reg, "fp")) .fp else null, + 'p' => return if (toLowerEqlAssertLower(reg, "pc")) .pc else null, 'v' => if (std.fmt.parseInt(u5, reg[1..], 10)) |n| .{ .alias = @enumFromInt(@intFromEnum(Alias.v0) + n), .format = .alias, @@ -1123,7 +1123,7 @@ pub const Register = struct { 's' => if (std.fmt.parseInt(u5, reg[1..], 10)) |n| .{ .alias = @enumFromInt(@intFromEnum(Alias.v0) + n), .format = .{ .scalar = .single }, - } else |_| if (std.mem.eql(u8, reg, "sp")) .sp else null, + } else |_| if (toLowerEqlAssertLower(reg, "sp")) .sp else null, 'h' => if (std.fmt.parseInt(u5, reg[1..], 10)) |n| .{ .alias = @enumFromInt(@intFromEnum(Alias.v0) + n), .format = .{ .scalar = .half }, @@ -1141,6 +1141,422 @@ pub const Register = struct { pub fn fmtCase(reg: Register, case: aarch64.Disassemble.Case) aarch64.Disassemble.RegisterFormatter { return .{ .reg = reg, .case = case }; } + + pub const System = packed struct(u16) { + op2: u3, + CRm: u4, + CRn: u4, + op1: u3, + op0: u2, + + // D19.2 General system control registers + /// D19.2.1 ACCDATA_EL1, Accelerator Data + pub const accdata_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b1101, .CRm = 0b0000, .op2 = 0b101 }; + /// D19.2.2 ACTLR_EL1, Auxiliary Control Register (EL1) + pub const actlr_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0001, .CRm = 0b0000, .op2 = 0b001 }; + /// D19.2.3 ACTLR_EL2, Auxiliary Control Register (EL2) + pub const actlr_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0001, .CRm = 0b0000, .op2 = 0b001 }; + /// D19.2.4 ACTLR_EL3, Auxiliary Control Register (EL3) + pub const actlr_el3: System = .{ .op0 = 0b11, .op1 = 0b110, .CRn = 0b0001, .CRm = 0b0000, .op2 = 0b001 }; + /// D19.2.5 AFSR0_EL1, Auxiliary Fault Status Register 0 (EL1) + pub const afsr0_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0101, .CRm = 0b0001, .op2 = 0b000 }; + /// D19.2.5 AFSR0_EL12, Auxiliary Fault Status Register 0 (EL12) + pub const afsr0_el12: System = .{ .op0 = 0b11, .op1 = 0b101, .CRn = 0b0101, .CRm = 0b0001, .op2 = 0b000 }; + /// D19.2.6 AFSR0_EL2, Auxiliary Fault Status Register 0 (EL2) + pub const afsr0_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0101, .CRm = 0b0001, .op2 = 0b000 }; + /// D19.2.7 AFSR0_EL3, Auxiliary Fault Status Register 0 (EL3) + pub const afsr0_el3: System = .{ .op0 = 0b11, .op1 = 0b110, .CRn = 0b0101, .CRm = 0b0001, .op2 = 0b000 }; + /// D19.2.8 AFSR1_EL1, Auxiliary Fault Status Register 1 (EL1) + pub const afsr1_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0101, .CRm = 0b0001, .op2 = 0b001 }; + /// D19.2.8 AFSR1_EL12, Auxiliary Fault Status Register 1 (EL12) + pub const afsr1_el12: System = .{ .op0 = 0b11, .op1 = 0b101, .CRn = 0b0101, .CRm = 0b0001, .op2 = 0b001 }; + /// D19.2.9 AFSR1_EL2, Auxiliary Fault Status Register 1 (EL2) + pub const afsr1_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0101, .CRm = 0b0001, .op2 = 0b001 }; + /// D19.2.10 AFSR1_EL3, Auxiliary Fault Status Register 1 (EL3) + pub const afsr1_el3: System = .{ .op0 = 0b11, .op1 = 0b110, .CRn = 0b0101, .CRm = 0b0001, .op2 = 0b001 }; + /// D19.2.11 AIDR_EL1, Auxiliary ID Register + pub const aidr_el1: System = .{ .op0 = 0b11, .op1 = 0b001, .CRn = 0b0000, .CRm = 0b0000, .op2 = 0b111 }; + /// D19.2.12 AMAIR_EL1, Auxiliary Memory Attribute Indirection Register (EL1) + pub const amair_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b1010, .CRm = 0b0011, .op2 = 0b000 }; + /// D19.2.12 AMAIR_EL12, Auxiliary Memory Attribute Indirection Register (EL12) + pub const amair_el12: System = .{ .op0 = 0b11, .op1 = 0b101, .CRn = 0b1010, .CRm = 0b0011, .op2 = 0b000 }; + /// D19.2.13 AMAIR_EL2, Auxiliary Memory Attribute Indirection Register (EL2) + pub const amair_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b1010, .CRm = 0b0011, .op2 = 0b000 }; + /// D19.2.14 AMAIR_EL3, Auxiliary Memory Attribute Indirection Register (EL3) + pub const amair_el3: System = .{ .op0 = 0b11, .op1 = 0b110, .CRn = 0b1010, .CRm = 0b0011, .op2 = 0b000 }; + /// D19.2.15 APDAKeyHi_EL1, Pointer Authentication Key A for Data (bits[127:64]) + pub const apdakeyhi_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0010, .CRm = 0b0010, .op2 = 0b001 }; + /// D19.2.16 APDAKeyLo_EL1, Pointer Authentication Key A for Data (bits[63:0]) + pub const apdakeylo_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0010, .CRm = 0b0010, .op2 = 0b000 }; + /// D19.2.17 APDBKeyHi_EL1, Pointer Authentication Key B for Data (bits[127:64]) + pub const apdbkeyhi_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0010, .CRm = 0b0010, .op2 = 0b011 }; + /// D19.2.18 APDAKeyHi_EL1, Pointer Authentication Key B for Data (bits[63:0]) + pub const apdbkeylo_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0010, .CRm = 0b0010, .op2 = 0b010 }; + /// D19.2.19 APGAKeyHi_EL1, Pointer Authentication Key A for Code (bits[127:64]) + pub const apgakeyhi_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0010, .CRm = 0b0011, .op2 = 0b001 }; + /// D19.2.20 APGAKeyLo_EL1, Pointer Authentication Key A for Code (bits[63:0]) + pub const apgakeylo_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0010, .CRm = 0b0011, .op2 = 0b000 }; + /// D19.2.21 APIAKeyHi_EL1, Pointer Authentication Key A for Instruction (bits[127:64]) + pub const apiakeyhi_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0010, .CRm = 0b0001, .op2 = 0b001 }; + /// D19.2.22 APIAKeyLo_EL1, Pointer Authentication Key A for Instruction (bits[63:0]) + pub const apiakeylo_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0010, .CRm = 0b0001, .op2 = 0b000 }; + /// D19.2.23 APIBKeyHi_EL1, Pointer Authentication Key B for Instruction (bits[127:64]) + pub const apibkeyhi_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0010, .CRm = 0b0001, .op2 = 0b011 }; + /// D19.2.24 APIBKeyLo_EL1, Pointer Authentication Key B for Instruction (bits[63:0]) + pub const apibkeylo_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0010, .CRm = 0b0001, .op2 = 0b010 }; + /// D19.2.25 CCSIDR2_EL1, Current Cache Size ID Register 2 + pub const ccsidr2_el1: System = .{ .op0 = 0b11, .op1 = 0b001, .CRn = 0b0000, .CRm = 0b0000, .op2 = 0b010 }; + /// D19.2.26 CCSIDR_EL1, Current Cache Size ID Register + pub const ccsidr_el1: System = .{ .op0 = 0b11, .op1 = 0b001, .CRn = 0b0000, .CRm = 0b0000, .op2 = 0b000 }; + /// D19.2.27 CLIDR_EL1, Cache Level ID Register + pub const clidr_el1: System = .{ .op0 = 0b11, .op1 = 0b001, .CRn = 0b0000, .CRm = 0b0000, .op2 = 0b001 }; + /// D19.2.28 CONTEXTIDR_EL1, Context ID Register (EL1) + pub const contextidr_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b1101, .CRm = 0b0000, .op2 = 0b001 }; + /// D19.2.28 CONTEXTIDR_EL12, Context ID Register (EL12) + pub const contextidr_el12: System = .{ .op0 = 0b11, .op1 = 0b101, .CRn = 0b1101, .CRm = 0b0000, .op2 = 0b001 }; + /// D19.2.29 CONTEXTIDR_EL2, Context ID Register (EL2) + pub const contextidr_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b1101, .CRm = 0b0000, .op2 = 0b001 }; + /// D19.2.30 CPACR_EL1, Architectural Feature Access Control Register + pub const cpacr_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0001, .CRm = 0b0000, .op2 = 0b010 }; + /// D19.2.30 CPACR_EL12, Architectural Feature Access Control Register + pub const cpacr_el12: System = .{ .op0 = 0b11, .op1 = 0b101, .CRn = 0b0001, .CRm = 0b0000, .op2 = 0b010 }; + /// D19.2.31 CPACR_EL2, Architectural Feature Trap Register (EL2) + pub const cptr_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0001, .CRm = 0b0001, .op2 = 0b010 }; + /// D19.2.32 CPACR_EL3, Architectural Feature Trap Register (EL3) + pub const cptr_el3: System = .{ .op0 = 0b11, .op1 = 0b110, .CRn = 0b0001, .CRm = 0b0001, .op2 = 0b010 }; + /// D19.2.33 CSSELR_EL1, Cache Size Selection Register + pub const csselr_el1: System = .{ .op0 = 0b11, .op1 = 0b010, .CRn = 0b0000, .CRm = 0b0000, .op2 = 0b000 }; + /// D19.2.34 CTR_EL0, Cache Type Register + pub const ctr_el0: System = .{ .op0 = 0b11, .op1 = 0b011, .CRn = 0b0000, .CRm = 0b0000, .op2 = 0b001 }; + /// D19.2.35 DACR32_EL2, Domain Access Control Register + pub const dacr32_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0011, .CRm = 0b0000, .op2 = 0b000 }; + /// D19.2.36 DCZID_EL0, Data Cache Zero ID Register + pub const dczid_el0: System = .{ .op0 = 0b11, .op1 = 0b011, .CRn = 0b0000, .CRm = 0b0000, .op2 = 0b111 }; + /// D19.2.37 ESR_EL1, Exception Syndrome Register (EL1) + pub const esr_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0101, .CRm = 0b0010, .op2 = 0b000 }; + /// D19.2.37 ESR_EL12, Exception Syndrome Register (EL12) + pub const esr_el12: System = .{ .op0 = 0b11, .op1 = 0b101, .CRn = 0b0101, .CRm = 0b0010, .op2 = 0b000 }; + /// D19.2.38 ESR_EL2, Exception Syndrome Register (EL2) + pub const esr_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0101, .CRm = 0b0010, .op2 = 0b000 }; + /// D19.2.39 ESR_EL3, Exception Syndrome Register (EL3) + pub const esr_el3: System = .{ .op0 = 0b11, .op1 = 0b110, .CRn = 0b0101, .CRm = 0b0010, .op2 = 0b000 }; + /// D19.2.40 FAR_EL1, Fault Address Register (EL1) + pub const far_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0110, .CRm = 0b0000, .op2 = 0b000 }; + /// D19.2.40 FAR_EL12, Fault Address Register (EL12) + pub const far_el12: System = .{ .op0 = 0b11, .op1 = 0b101, .CRn = 0b0110, .CRm = 0b0000, .op2 = 0b000 }; + /// D19.2.41 FAR_EL2, Fault Address Register (EL2) + pub const far_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0110, .CRm = 0b0000, .op2 = 0b000 }; + /// D19.2.42 FAR_EL3, Fault Address Register (EL3) + pub const far_el3: System = .{ .op0 = 0b11, .op1 = 0b110, .CRn = 0b0110, .CRm = 0b0000, .op2 = 0b000 }; + /// D19.2.43 FPEXC32_EL2, Floating-Point Exception Control Register + pub const fpexc32_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0101, .CRm = 0b0011, .op2 = 0b000 }; + /// D19.2.44 GCR_EL1, Tag Control Register + pub const gcr_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0001, .CRm = 0b0000, .op2 = 0b110 }; + /// D19.2.45 GMID_EL1, Tag Control Register + pub const gmid_el1: System = .{ .op0 = 0b11, .op1 = 0b001, .CRn = 0b0000, .CRm = 0b0000, .op2 = 0b100 }; + /// D19.2.46 HACR_EL2, Hypervisor Auxiliary Control Register + pub const hacr_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0001, .CRm = 0b0001, .op2 = 0b111 }; + /// D19.2.47 HAFGRTR_EL2, Hypervisor Activity Monitors Fine-Grained Read Trap Register + pub const hafgrtr_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0011, .CRm = 0b0001, .op2 = 0b110 }; + /// D19.2.48 HCR_EL2, Hypervisor Configuration Register + pub const hcr_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0001, .CRm = 0b0001, .op2 = 0b000 }; + /// D19.2.49 HCRX_EL2, Extended Hypervisor Configuration Register + pub const hcrx_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0001, .CRm = 0b0010, .op2 = 0b010 }; + /// D19.2.50 HDFGRTR_EL2, Hypervisor Debug Fine-Grained Read Trap Register + pub const hdfgrtr_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0011, .CRm = 0b0001, .op2 = 0b100 }; + /// D19.2.51 HDFGWTR_EL2, Hypervisor Debug Fine-Grained Write Trap Register + pub const hdfgwtr_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0011, .CRm = 0b0001, .op2 = 0b101 }; + /// D19.2.52 HFGITR_EL2, Hypervisor Fine-Grained Instruction Trap Register + pub const hfgitr_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0001, .CRm = 0b0001, .op2 = 0b110 }; + /// D19.2.53 HFGRTR_EL2, Hypervisor Fine-Grained Read Trap Register + pub const hfgrtr_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0001, .CRm = 0b0001, .op2 = 0b100 }; + /// D19.2.54 HFGWTR_EL2, Hypervisor Fine-Grained Write Trap Register + pub const hfgwtr_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0001, .CRm = 0b0001, .op2 = 0b101 }; + /// D19.2.55 HPFAR_EL2, Hypervisor IPA Fault Address Register + pub const hpfar_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0110, .CRm = 0b0000, .op2 = 0b100 }; + /// D19.2.56 HSTR_EL2, Hypervisor System Trap Register + pub const hstr_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0001, .CRm = 0b0001, .op2 = 0b011 }; + /// D19.2.57 ID_AA64AFR0_EL1, AArch64 Auxiliary Feature Register 0 + pub const id_aa64afr0_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0101, .op2 = 0b100 }; + /// D19.2.58 ID_AA64AFR1_EL1, AArch64 Auxiliary Feature Register 1 + pub const id_aa64afr1_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0101, .op2 = 0b101 }; + /// D19.2.59 ID_AA64DFR0_EL1, AArch64 Debug Feature Register 0 + pub const id_aa64dfr0_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0101, .op2 = 0b000 }; + /// D19.2.60 ID_AA64DFR1_EL1, AArch64 Debug Feature Register 1 + pub const id_aa64dfr1_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0101, .op2 = 0b001 }; + /// D19.2.61 ID_AA64ISAR0_EL1, AArch64 Instruction Set Attribute Register 0 + pub const id_aa64isar0_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0110, .op2 = 0b000 }; + /// D19.2.62 ID_AA64ISAR1_EL1, AArch64 Instruction Set Attribute Register 1 + pub const id_aa64isar1_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0110, .op2 = 0b001 }; + /// D19.2.63 ID_AA64ISAR2_EL1, AArch64 Instruction Set Attribute Register 2 + pub const id_aa64isar2_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0110, .op2 = 0b010 }; + /// D19.2.64 ID_AA64MMFR0_EL1, AArch64 Memory Model Feature Register 0 + pub const id_aa64mmfr0_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0111, .op2 = 0b000 }; + /// D19.2.65 ID_AA64MMFR1_EL1, AArch64 Memory Model Feature Register 1 + pub const id_aa64mmfr1_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0111, .op2 = 0b001 }; + /// D19.2.66 ID_AA64MMFR2_EL1, AArch64 Memory Model Feature Register 2 + pub const id_aa64mmfr2_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0111, .op2 = 0b010 }; + /// D19.2.67 ID_AA64MMFR3_EL1, AArch64 Memory Model Feature Register 3 + pub const id_aa64mmfr3_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0111, .op2 = 0b011 }; + /// D19.2.68 ID_AA64MMFR4_EL1, AArch64 Memory Model Feature Register 4 + pub const id_aa64mmfr4_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0111, .op2 = 0b100 }; + /// D19.2.69 ID_AA64PFR0_EL1, AArch64 Processor Feature Register 0 + pub const id_aa64pfr0_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0100, .op2 = 0b000 }; + /// D19.2.70 ID_AA64PFR1_EL1, AArch64 Processor Feature Register 1 + pub const id_aa64pfr1_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0100, .op2 = 0b001 }; + /// D19.2.71 ID_AA64PFR2_EL1, AArch64 Processor Feature Register 2 + pub const id_aa64pfr2_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0100, .op2 = 0b010 }; + /// D19.2.72 ID_AA64SMFR0_EL1, SME Feature ID Register 0 + pub const id_aa64smfr0_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0100, .op2 = 0b101 }; + /// D19.2.73 ID_AA64ZFR0_EL1, SVE Feature ID Register 0 + pub const id_aa64zfr0_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0100, .op2 = 0b100 }; + /// D19.2.74 ID_AFR0_EL1, AArch32 Auxiliary Feature Register 0 + pub const id_afr0_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0001, .op2 = 0b011 }; + /// D19.2.75 ID_DFR0_EL1, AArch32 Debug Feature Register 0 + pub const id_dfr0_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0001, .op2 = 0b010 }; + /// D19.2.76 ID_DFR1_EL1, AArch32 Debug Feature Register 1 + pub const id_dfr1_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0011, .op2 = 0b101 }; + /// D19.2.77 ID_ISAR0_EL1, AArch32 Instruction Set Attribute Register 0 + pub const id_isar0_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0010, .op2 = 0b000 }; + /// D19.2.78 ID_ISAR1_EL1, AArch32 Instruction Set Attribute Register 1 + pub const id_isar1_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0010, .op2 = 0b001 }; + /// D19.2.79 ID_ISAR2_EL1, AArch32 Instruction Set Attribute Register 2 + pub const id_isar2_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0010, .op2 = 0b010 }; + /// D19.2.80 ID_ISAR3_EL1, AArch32 Instruction Set Attribute Register 3 + pub const id_isar3_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0010, .op2 = 0b011 }; + /// D19.2.81 ID_ISAR4_EL1, AArch32 Instruction Set Attribute Register 4 + pub const id_isar4_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0010, .op2 = 0b100 }; + /// D19.2.82 ID_ISAR5_EL1, AArch32 Instruction Set Attribute Register 5 + pub const id_isar5_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0010, .op2 = 0b101 }; + /// D19.2.83 ID_ISAR6_EL1, AArch32 Instruction Set Attribute Register 6 + pub const id_isar6_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0010, .op2 = 0b111 }; + /// D19.2.84 ID_MMFR0_EL1, AArch32 Memory Model Feature Register 0 + pub const id_mmfr0_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0001, .op2 = 0b100 }; + /// D19.2.85 ID_MMFR1_EL1, AArch32 Memory Model Feature Register 1 + pub const id_mmfr1_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0001, .op2 = 0b101 }; + /// D19.2.86 ID_MMFR2_EL1, AArch32 Memory Model Feature Register 2 + pub const id_mmfr2_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0001, .op2 = 0b110 }; + /// D19.2.87 ID_MMFR3_EL1, AArch32 Memory Model Feature Register 3 + pub const id_mmfr3_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0001, .op2 = 0b111 }; + /// D19.2.88 ID_MMFR4_EL1, AArch32 Memory Model Feature Register 4 + pub const id_mmfr4_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0010, .op2 = 0b110 }; + /// D19.2.89 ID_MMFR5_EL1, AArch32 Memory Model Feature Register 5 + pub const id_mmfr5_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0011, .op2 = 0b110 }; + /// D19.2.90 ID_PFR0_EL1, AArch32 Processor Feature Register 0 + pub const id_pfr0_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0001, .op2 = 0b000 }; + /// D19.2.91 ID_PFR1_EL1, AArch32 Processor Feature Register 1 + pub const id_pfr1_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0001, .op2 = 0b001 }; + /// D19.2.92 ID_PFR2_EL1, AArch32 Processor Feature Register 2 + pub const id_pfr2_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0011, .op2 = 0b100 }; + /// D19.2.93 IFSR32_EL2, Instruction Fault Status Register (EL2) + pub const ifsr32_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0101, .CRm = 0b0000, .op2 = 0b001 }; + /// D19.2.94 ISR_EL1, Interrupt Status Register + pub const isr_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b1100, .CRm = 0b0001, .op2 = 0b000 }; + /// D19.2.95 LORC_EL1, LORegion Control (EL1) + pub const lorc_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b1010, .CRm = 0b0100, .op2 = 0b011 }; + /// D19.2.96 LOREA_EL1, LORegion End Address (EL1) + pub const lorea_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b1010, .CRm = 0b0100, .op2 = 0b001 }; + /// D19.2.97 SORID_EL1, LORegionID (EL1) + pub const lorid_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b1010, .CRm = 0b0100, .op2 = 0b111 }; + /// D19.2.98 LORN_EL1, LORegion Number (EL1) + pub const lorn_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b1010, .CRm = 0b0100, .op2 = 0b010 }; + /// D19.2.99 LORSA_EL1, LORegion Start Address (EL1) + pub const lorsa_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b1010, .CRm = 0b0100, .op2 = 0b000 }; + /// D19.2.100 MAIR_EL1, Memory Attribute Indirection Register (EL1) + pub const mair_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b1010, .CRm = 0b0010, .op2 = 0b000 }; + /// D19.2.100 MAIR_EL12, Memory Attribute Indirection Register (EL12) + pub const mair_el12: System = .{ .op0 = 0b11, .op1 = 0b101, .CRn = 0b1010, .CRm = 0b0010, .op2 = 0b000 }; + /// D19.2.101 MAIR_EL2, Memory Attribute Indirection Register (EL2) + pub const mair_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b1010, .CRm = 0b0010, .op2 = 0b000 }; + /// D19.2.102 MAIR_EL3, Memory Attribute Indirection Register (EL3) + pub const mair_el3: System = .{ .op0 = 0b11, .op1 = 0b110, .CRn = 0b1010, .CRm = 0b0010, .op2 = 0b000 }; + /// D19.2.103 MIDR_EL1, Main ID Register + pub const midr_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0000, .op2 = 0b000 }; + /// D19.2.104 MPIDR_EL1, Multiprocessor Affinity Register + pub const mpidr_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0000, .op2 = 0b101 }; + /// D19.2.105 MVFR0_EL1, AArch32 Media and VFP Feature Register 0 + pub const mvfr0_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0011, .op2 = 0b000 }; + /// D19.2.106 MVFR1_EL1, AArch32 Media and VFP Feature Register 1 + pub const mvfr1_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0011, .op2 = 0b001 }; + /// D19.2.107 MVFR2_EL1, AArch32 Media and VFP Feature Register 2 + pub const mvfr2_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0011, .op2 = 0b010 }; + /// D19.2.108 PAR_EL1, Physical Address Register + pub const par_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0111, .CRm = 0b0100, .op2 = 0b000 }; + /// D19.2.109 REVIDR_EL1, Revision ID Register + pub const revidr_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0000, .op2 = 0b110 }; + /// D19.2.110 RGSR_EL1, Random Allocation Tag Seed Register + pub const rgsr_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0001, .CRm = 0b0000, .op2 = 0b101 }; + /// D19.2.111 RMR_EL1, Reset Management Register (EL1) + pub const rmr_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b1100, .CRm = 0b0000, .op2 = 0b010 }; + /// D19.2.112 RMR_EL2, Reset Management Register (EL2) + pub const rmr_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b1100, .CRm = 0b0000, .op2 = 0b010 }; + /// D19.2.113 RMR_EL3, Reset Management Register (EL3) + pub const rmr_el3: System = .{ .op0 = 0b11, .op1 = 0b110, .CRn = 0b1100, .CRm = 0b0000, .op2 = 0b010 }; + /// D19.2.114 RNDR, Random Number + pub const rndr: System = .{ .op0 = 0b11, .op1 = 0b011, .CRn = 0b0010, .CRm = 0b0100, .op2 = 0b000 }; + /// D19.2.115 RNDRRS, Reseeded Random Number + pub const rndrrs: System = .{ .op0 = 0b11, .op1 = 0b011, .CRn = 0b0010, .CRm = 0b0100, .op2 = 0b001 }; + /// D19.2.116 RVBAR_EL1, Reset Vector Base Address Register (if EL2 and EL3 not implemented) + pub const rvbar_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b1100, .CRm = 0b0000, .op2 = 0b001 }; + /// D19.2.117 RVBAR_EL2, Reset Vector Base Address Register (if EL3 not implemented) + pub const rvbar_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b1100, .CRm = 0b0000, .op2 = 0b001 }; + /// D19.2.118 RVBAR_EL3, Reset Vector Base Address Register (if EL3 implemented) + pub const rvbar_el3: System = .{ .op0 = 0b11, .op1 = 0b110, .CRn = 0b1100, .CRm = 0b0000, .op2 = 0b001 }; + /// D19.2.120 SCR_EL3, Secure Configuration Register + pub const scr_el3: System = .{ .op0 = 0b11, .op1 = 0b110, .CRn = 0b0001, .CRm = 0b0001, .op2 = 0b000 }; + /// D19.2.121 SCTLR2_EL1, System Control Register (EL1) + pub const sctlr2_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0001, .CRm = 0b0000, .op2 = 0b011 }; + /// D19.2.121 SCTLR2_EL12, System Control Register (EL12) + pub const sctlr2_el12: System = .{ .op0 = 0b11, .op1 = 0b101, .CRn = 0b0001, .CRm = 0b0000, .op2 = 0b011 }; + /// D19.2.122 SCTLR2_EL2, System Control Register (EL2) + pub const sctlr2_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0001, .CRm = 0b0000, .op2 = 0b011 }; + /// D19.2.123 SCTLR2_EL3, System Control Register (EL3) + pub const sctlr2_el3: System = .{ .op0 = 0b11, .op1 = 0b110, .CRn = 0b0001, .CRm = 0b0000, .op2 = 0b011 }; + /// D19.2.124 SCTLR_EL1, System Control Register (EL1) + pub const sctlr_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0001, .CRm = 0b0000, .op2 = 0b000 }; + /// D19.2.124 SCTLR_EL12, System Control Register (EL12) + pub const sctlr_el12: System = .{ .op0 = 0b11, .op1 = 0b101, .CRn = 0b0001, .CRm = 0b0000, .op2 = 0b000 }; + /// D19.2.125 SCTLR_EL2, System Control Register (EL2) + pub const sctlr_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0001, .CRm = 0b0000, .op2 = 0b000 }; + /// D19.2.126 SCTLR_EL3, System Control Register (EL3) + pub const sctlr_el3: System = .{ .op0 = 0b11, .op1 = 0b110, .CRn = 0b0001, .CRm = 0b0000, .op2 = 0b000 }; + /// D19.2.127 SCXTNUM_EL0, EL0 Read/Write Software Context Number + pub const scxtnum_el0: System = .{ .op0 = 0b11, .op1 = 0b011, .CRn = 0b1101, .CRm = 0b0000, .op2 = 0b111 }; + /// D19.2.128 SCXTNUM_EL1, EL1 Read/Write Software Context Number + pub const scxtnum_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b1101, .CRm = 0b0000, .op2 = 0b111 }; + /// D19.2.128 SCXTNUM_EL12, EL12 Read/Write Software Context Number + pub const scxtnum_el12: System = .{ .op0 = 0b11, .op1 = 0b101, .CRn = 0b1101, .CRm = 0b0000, .op2 = 0b111 }; + /// D19.2.129 SCXTNUM_EL2, EL2 Read/Write Software Context Number + pub const scxtnum_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b1101, .CRm = 0b0000, .op2 = 0b111 }; + /// D19.2.130 SCXTNUM_EL3, EL3 Read/Write Software Context Number + pub const scxtnum_el3: System = .{ .op0 = 0b11, .op1 = 0b110, .CRn = 0b1101, .CRm = 0b0000, .op2 = 0b111 }; + /// D19.2.131 SMCR_EL1, SME Control Register (EL1) + pub const smcr_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0001, .CRm = 0b0010, .op2 = 0b110 }; + /// D19.2.131 SMCR_EL12, SME Control Register (EL12) + pub const smcr_el12: System = .{ .op0 = 0b11, .op1 = 0b101, .CRn = 0b0001, .CRm = 0b0010, .op2 = 0b110 }; + /// D19.2.132 SMCR_EL2, SME Control Register (EL2) + pub const smcr_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0001, .CRm = 0b0010, .op2 = 0b110 }; + /// D19.2.133 SMCR_EL3, SME Control Register (EL3) + pub const smcr_el3: System = .{ .op0 = 0b11, .op1 = 0b110, .CRn = 0b0001, .CRm = 0b0010, .op2 = 0b110 }; + /// D19.2.134 SMIDR_EL1, Streaming Mode Identification Register + pub const smidr_el1: System = .{ .op0 = 0b11, .op1 = 0b001, .CRn = 0b0000, .CRm = 0b0000, .op2 = 0b110 }; + /// D19.2.135 SMPRIMAP_EL2, Streaming Mode Priority Mapping Register + pub const smprimap_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0001, .CRm = 0b0010, .op2 = 0b101 }; + /// D19.2.136 SMPRI_EL1, Streaming Mode Priority Register + pub const smpri_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0001, .CRm = 0b0010, .op2 = 0b100 }; + /// D19.2.137 TCR2_EL1, Extended Translation Control Register (EL1) + pub const tcr2_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0010, .CRm = 0b0000, .op2 = 0b011 }; + /// D19.2.137 TCR2_EL12, Extended Translation Control Register (EL12) + pub const tcr2_el12: System = .{ .op0 = 0b11, .op1 = 0b101, .CRn = 0b0010, .CRm = 0b0000, .op2 = 0b011 }; + /// D19.2.138 TCR2_EL2, Extended Translation Control Register (EL2) + pub const tcr2_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0010, .CRm = 0b0000, .op2 = 0b011 }; + /// D19.2.139 TCR_EL1, Translation Control Register (EL1) + pub const tcr_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0010, .CRm = 0b0000, .op2 = 0b010 }; + /// D19.2.139 TCR_EL12, Translation Control Register (EL12) + pub const tcr_el12: System = .{ .op0 = 0b11, .op1 = 0b101, .CRn = 0b0010, .CRm = 0b0000, .op2 = 0b010 }; + /// D19.2.140 TCR_EL2, Translation Control Register (EL2) + pub const tcr_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0010, .CRm = 0b0000, .op2 = 0b010 }; + /// D19.2.141 TCR_EL3, Translation Control Register (EL3) + pub const tcr_el3: System = .{ .op0 = 0b11, .op1 = 0b110, .CRn = 0b0010, .CRm = 0b0000, .op2 = 0b010 }; + /// D19.2.142 TFSRE0_EL1, Tag Fault Status Register (EL0) + pub const tfsre0_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0101, .CRm = 0b0110, .op2 = 0b001 }; + /// D19.2.143 TFSR_EL1, Tag Fault Status Register (EL1) + pub const tfsr_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0101, .CRm = 0b0110, .op2 = 0b000 }; + /// D19.2.143 TFSR_EL12, Tag Fault Status Register (EL12) + pub const tfsr_el12: System = .{ .op0 = 0b11, .op1 = 0b101, .CRn = 0b0101, .CRm = 0b0110, .op2 = 0b000 }; + /// D19.2.144 TFSR_EL2, Tag Fault Status Register (EL2) + pub const tfsr_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0101, .CRm = 0b0110, .op2 = 0b000 }; + /// D19.2.145 TFSR_EL3, Tag Fault Status Register (EL3) + pub const tfsr_el3: System = .{ .op0 = 0b11, .op1 = 0b110, .CRn = 0b0101, .CRm = 0b0110, .op2 = 0b000 }; + /// D19.2.146 TPIDR2_EL0, EL0 Read/Write Software Thread ID Register 2 + pub const tpidr2_el0: System = .{ .op0 = 0b11, .op1 = 0b011, .CRn = 0b1101, .CRm = 0b0000, .op2 = 0b101 }; + /// D19.2.147 TPIDR_EL0, EL0 Read/Write Software Thread ID Register + pub const tpidr_el0: System = .{ .op0 = 0b11, .op1 = 0b011, .CRn = 0b1101, .CRm = 0b0000, .op2 = 0b010 }; + /// D19.2.148 TPIDR_EL1, EL1 Read/Write Software Thread ID Register + pub const tpidr_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b1101, .CRm = 0b0000, .op2 = 0b100 }; + /// D19.2.149 TPIDR_EL2, EL2 Read/Write Software Thread ID Register + pub const tpidr_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b1101, .CRm = 0b0000, .op2 = 0b010 }; + /// D19.2.150 TPIDR_EL3, EL3 Read/Write Software Thread ID Register + pub const tpidr_el3: System = .{ .op0 = 0b11, .op1 = 0b110, .CRn = 0b1101, .CRm = 0b0000, .op2 = 0b010 }; + /// D19.2.151 TPIDRRO_EL0, EL0 Read-Only Software Thread ID Register + pub const tpidrro_el3: System = .{ .op0 = 0b11, .op1 = 0b011, .CRn = 0b1101, .CRm = 0b0000, .op2 = 0b011 }; + /// D19.2.152 TTBR0_EL1, Translation Table Base Register 0 (EL1) + pub const ttbr0_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0010, .CRm = 0b0000, .op2 = 0b000 }; + /// D19.2.152 TTBR0_EL12, Translation Table Base Register 0 (EL12) + pub const ttbr0_el12: System = .{ .op0 = 0b11, .op1 = 0b101, .CRn = 0b0010, .CRm = 0b0000, .op2 = 0b000 }; + /// D19.2.153 TTBR0_EL2, Translation Table Base Register 0 (EL2) + pub const ttbr0_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0010, .CRm = 0b0000, .op2 = 0b000 }; + /// D19.2.154 TTBR0_EL3, Translation Table Base Register 0 (EL3) + pub const ttbr0_el3: System = .{ .op0 = 0b11, .op1 = 0b110, .CRn = 0b0010, .CRm = 0b0000, .op2 = 0b000 }; + /// D19.2.155 TTBR1_EL1, Translation Table Base Register 1 (EL1) + pub const ttbr1_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0010, .CRm = 0b0000, .op2 = 0b001 }; + /// D19.2.155 TTBR1_EL12, Translation Table Base Register 1 (EL12) + pub const ttbr1_el12: System = .{ .op0 = 0b11, .op1 = 0b101, .CRn = 0b0010, .CRm = 0b0000, .op2 = 0b001 }; + /// D19.2.156 TTBR1_EL2, Translation Table Base Register 1 (EL2) + pub const ttbr1_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0010, .CRm = 0b0000, .op2 = 0b001 }; + /// D19.2.157 VBAR_EL1, Vector Base Address Register (EL1) + pub const vbar_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b1100, .CRm = 0b0000, .op2 = 0b000 }; + /// D19.2.157 VBAR_EL12, Vector Base Address Register (EL12) + pub const vbar_el12: System = .{ .op0 = 0b11, .op1 = 0b101, .CRn = 0b1100, .CRm = 0b0000, .op2 = 0b000 }; + /// D19.2.158 VBAR_EL2, Vector Base Address Register (EL2) + pub const vbar_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b1100, .CRm = 0b0000, .op2 = 0b000 }; + /// D19.2.159 VBAR_EL3, Vector Base Address Register (EL3) + pub const vbar_el3: System = .{ .op0 = 0b11, .op1 = 0b110, .CRn = 0b1100, .CRm = 0b0000, .op2 = 0b000 }; + /// D19.2.160 VMPIDR_EL2, Virtualization Multiprocessor ID Register + pub const vmpidr_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0000, .CRm = 0b0000, .op2 = 0b101 }; + /// D19.2.161 VNCR_EL2, Virtual Nested Control Register + pub const nvcr_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0010, .CRm = 0b0010, .op2 = 0b000 }; + /// D19.2.162 VPIDR_EL2, Virtualization Processor ID Register + pub const vpidr_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0000, .CRm = 0b0000, .op2 = 0b000 }; + /// D19.2.163 VSTCR_EL2, Virtualization Secure Translation Control Register + pub const vstcr_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0010, .CRm = 0b0110, .op2 = 0b010 }; + /// D19.2.164 VSTTBR_EL2, Virtualization Secure Translation Table Base Register + pub const vsttbr_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0010, .CRm = 0b0110, .op2 = 0b000 }; + /// D19.2.165 VTCR_EL2, Virtualization Translation Control Register + pub const vtcr_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0010, .CRm = 0b0001, .op2 = 0b010 }; + /// D19.2.166 VTTBR_EL2, Virtualization Translation Table Base Register + pub const vttbr_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0010, .CRm = 0b0001, .op2 = 0b000 }; + /// D19.2.167 ZCR_EL1, SVE Control Register (EL1) + pub const zcr_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0001, .CRm = 0b0010, .op2 = 0b000 }; + /// D19.2.167 ZCR_EL12, SVE Control Register (EL12) + pub const zcr_el12: System = .{ .op0 = 0b11, .op1 = 0b101, .CRn = 0b0001, .CRm = 0b0010, .op2 = 0b000 }; + /// D19.2.168 ZCR_EL2, SVE Control Register (EL2) + pub const zcr_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0001, .CRm = 0b0010, .op2 = 0b000 }; + /// D19.2.169 ZCR_EL3, SVE Control Register (EL3) + pub const zcr_el3: System = .{ .op0 = 0b11, .op1 = 0b110, .CRn = 0b0001, .CRm = 0b0010, .op2 = 0b000 }; + + pub fn parse(reg: []const u8) ?System { + if (reg.len >= 10 and std.ascii.toLower(reg[0]) == 's') encoded: { + var symbol_it = std.mem.splitScalar(u8, reg[1..], '_'); + const op0 = std.fmt.parseInt(u2, symbol_it.next() orelse break :encoded, 10) catch break :encoded; + if (op0 < 0b10) break :encoded; + const op1 = std.fmt.parseInt(u3, symbol_it.next() orelse break :encoded, 10) catch break :encoded; + const n = symbol_it.next() orelse break :encoded; + if (n.len == 0 or std.ascii.toLower(n[0]) != 'c') break :encoded; + const CRn = std.fmt.parseInt(u4, n[1..], 10) catch break :encoded; + const m = symbol_it.next() orelse break :encoded; + if (m.len == 0 or std.ascii.toLower(m[0]) != 'c') break :encoded; + const CRm = std.fmt.parseInt(u4, m[1..], 10) catch break :encoded; + const op2 = std.fmt.parseInt(u3, symbol_it.next() orelse break :encoded, 10) catch break :encoded; + if (symbol_it.next() != null) break :encoded; + return .{ .op0 = op0, .op1 = op1, .CRn = CRn, .CRm = CRm, .op2 = op2 }; + } + inline for (@typeInfo(System).@"struct".decls) |decl| { + if (@TypeOf(@field(System, decl.name)) != System) continue; + if (toLowerEqlAssertLower(reg, decl.name)) return @field(System, decl.name); + } + return null; + } + }; + + fn toLowerEqlAssertLower(lhs: []const u8, rhs: []const u8) bool { + if (lhs.len != rhs.len) return false; + for (lhs, rhs) |l, r| { + assert(!std.ascii.isUpper(r)); + if (std.ascii.toLower(l) != r) return false; + } + return true; + } }; /// C1.2.4 Condition code @@ -2385,12 +2801,7 @@ pub const Instruction = packed union { pub const Group = packed struct { Rt: Register.Encoded, - op2: u3, - CRm: u4, - CRn: u4, - op1: u3, - o0: u1, - decoded20: u1 = 0b1, + systemreg: Register.System, L: L, decoded22: u10 = 0b1101010100, }; @@ -2398,12 +2809,7 @@ pub const Instruction = packed union { /// C6.2.230 MSR (register) pub const Msr = packed struct { Rt: Register.Encoded, - op2: u3, - CRm: u4, - CRn: u4, - op1: u3, - o0: u1, - decoded20: u1 = 0b1, + systemreg: Register.System, L: L = .msr, decoded22: u10 = 0b1101010100, }; @@ -2411,12 +2817,7 @@ pub const Instruction = packed union { /// C6.2.228 MRS pub const Mrs = packed struct { Rt: Register.Encoded, - op2: u3, - CRm: u4, - CRn: u4, - op1: u3, - o0: u1, - decoded20: u1 = 0b1, + systemreg: Register.System, L: L = .mrs, decoded22: u10 = 0b1101010100, }; @@ -10585,30 +10986,22 @@ pub const Instruction = packed union { } } }; } /// C6.2.228 MRS - pub fn mrs(t: Register, op0: u2, op1: u3, n: u4, m: u4, op2: u3) Instruction { - assert(t.format.integer == .doubleword); + pub fn mrs(t: Register, systemreg: Register.System) Instruction { + assert(t.format.integer == .doubleword and systemreg.op0 >= 0b10); return .{ .branch_exception_generating_system = .{ .system_register_move = .{ .mrs = .{ .Rt = t.alias.encode(.{}), - .op2 = op2, - .CRm = m, - .CRn = n, - .op1 = op1, - .o0 = @intCast(op0 - 0b10), + .systemreg = systemreg, }, } } }; } /// C6.2.230 MSR (register) - pub fn msr(op0: u2, op1: u3, n: u4, m: u4, op2: u3, t: Register) Instruction { - assert(t.format.integer == .doubleword); + pub fn msr(systemreg: Register.System, t: Register) Instruction { + assert(systemreg.op0 >= 0b10 and t.format.integer == .doubleword); return .{ .branch_exception_generating_system = .{ .system_register_move = .{ .msr = .{ .Rt = t.alias.encode(.{}), - .op2 = op2, - .CRm = m, - .CRn = n, - .op1 = op1, - .o0 = @intCast(op0 - 0b10), + .systemreg = systemreg, }, } } }; } diff --git a/src/codegen/aarch64/instructions.zon b/src/codegen/aarch64/instructions.zon index 4aacf85e01..85de196050 100644 --- a/src/codegen/aarch64/instructions.zon +++ b/src/codegen/aarch64/instructions.zon @@ -851,11 +851,21 @@ }, // C6.2.228 MRS .{ - .pattern = "MRS , CTR_EL0", + .pattern = "MRS , ", .symbols = .{ .Xt = .{ .reg = .{ .format = .{ .integer = .doubleword } } }, + .systemreg = .systemreg, }, - .encode = .{ .mrs, .Xt, 0b11, 0b011, 0b0000, 0b0000, 0b001 }, + .encode = .{ .mrs, .Xt, .systemreg }, + }, + // C6.2.230 MSR (register) + .{ + .pattern = "MSR , ", + .symbols = .{ + .systemreg = .systemreg, + .Xt = .{ .reg = .{ .format = .{ .integer = .doubleword } } }, + }, + .encode = .{ .msr, .systemreg, .Xt }, }, // C6.2.234 NEG .{ diff --git a/test/behavior/basic.zig b/test/behavior/basic.zig index 1af3a692aa..c98caed91f 100644 --- a/test/behavior/basic.zig +++ b/test/behavior/basic.zig @@ -471,7 +471,6 @@ fn testPointerToVoidReturnType2() *const void { } test "array 2D const double ptr" { - if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; @@ -484,7 +483,6 @@ test "array 2D const double ptr" { } test "array 2D const double ptr with offset" { - if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; @@ -497,7 +495,6 @@ test "array 2D const double ptr with offset" { } test "array 3D const double ptr with offset" { - if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; diff --git a/test/behavior/cast.zig b/test/behavior/cast.zig index 6457d38447..8fcfbbd9a2 100644 --- a/test/behavior/cast.zig +++ b/test/behavior/cast.zig @@ -1816,7 +1816,6 @@ test "peer type resolution: C pointer and @TypeOf(null)" { } test "peer type resolution: three-way resolution combines error set and optional" { - if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; diff --git a/test/behavior/pointers.zig b/test/behavior/pointers.zig index ef2b4b9597..2a786ecdb6 100644 --- a/test/behavior/pointers.zig +++ b/test/behavior/pointers.zig @@ -436,7 +436,6 @@ test "pointer sentinel with optional element" { } test "pointer sentinel with +inf" { - if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; -- cgit v1.2.3