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 --- src/codegen/aarch64.zig | 194 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 194 insertions(+) create mode 100644 src/codegen/aarch64.zig (limited to 'src/codegen/aarch64.zig') diff --git a/src/codegen/aarch64.zig b/src/codegen/aarch64.zig new file mode 100644 index 0000000000..6f95fff58e --- /dev/null +++ b/src/codegen/aarch64.zig @@ -0,0 +1,194 @@ +pub const abi = @import("aarch64/abi.zig"); +pub const Assemble = @import("aarch64/Assemble.zig"); +pub const Disassemble = @import("aarch64/Disassemble.zig"); +pub const encoding = @import("aarch64/encoding.zig"); +pub const Mir = @import("aarch64/Mir.zig"); +pub const Select = @import("aarch64/Select.zig"); + +pub fn legalizeFeatures(_: *const std.Target) ?*Air.Legalize.Features { + return null; +} + +pub fn generate( + _: *link.File, + pt: Zcu.PerThread, + _: Zcu.LazySrcLoc, + func_index: InternPool.Index, + air: *const Air, + liveness: *const ?Air.Liveness, +) !Mir { + const zcu = pt.zcu; + const gpa = zcu.gpa; + const func = zcu.funcInfo(func_index); + const func_type = zcu.intern_pool.indexToKey(func.ty).func_type; + assert(liveness.* == null); + + const mod = zcu.navFileScope(func.owner_nav).mod.?; + var isel: Select = .{ + .pt = pt, + .target = &mod.resolved_target.result, + .air = air.*, + .nav_index = zcu.funcInfo(func_index).owner_nav, + + .def_order = .empty, + .blocks = .empty, + .loops = .empty, + .active_loops = .empty, + .loop_live = .{ + .set = .empty, + .list = .empty, + }, + .dom_start = 0, + .dom_len = 0, + .dom = .empty, + + .saved_registers = comptime .initEmpty(), + .instructions = .empty, + .literals = .empty, + .nav_relocs = .empty, + .uav_relocs = .empty, + .global_relocs = .empty, + .literal_relocs = .empty, + + .returns = false, + .va_list = undefined, + .stack_size = 0, + .stack_align = .@"16", + + .live_registers = comptime .initFill(.free), + .live_values = .empty, + .values = .empty, + }; + defer isel.deinit(); + + const air_main_body = air.getMainBody(); + var param_it: Select.CallAbiIterator = .init; + const air_args = for (air_main_body, 0..) |air_inst_index, body_index| { + if (air.instructions.items(.tag)[@intFromEnum(air_inst_index)] != .arg) break air_main_body[0..body_index]; + const param_ty = air.instructions.items(.data)[@intFromEnum(air_inst_index)].arg.ty.toType(); + const param_vi = try param_it.param(&isel, param_ty); + tracking_log.debug("${d} <- %{d}", .{ @intFromEnum(param_vi.?), @intFromEnum(air_inst_index) }); + try isel.live_values.putNoClobber(gpa, air_inst_index, param_vi.?); + } else unreachable; + + const saved_gra_start = if (mod.strip) param_it.ngrn else Select.CallAbiIterator.ngrn_start; + const saved_gra_end = if (func_type.is_var_args) Select.CallAbiIterator.ngrn_end else param_it.ngrn; + const saved_gra_len = @intFromEnum(saved_gra_end) - @intFromEnum(saved_gra_start); + + const saved_vra_start = if (mod.strip) param_it.nsrn else Select.CallAbiIterator.nsrn_start; + const saved_vra_end = if (func_type.is_var_args) Select.CallAbiIterator.nsrn_end else param_it.nsrn; + const saved_vra_len = @intFromEnum(saved_vra_end) - @intFromEnum(saved_vra_start); + + const frame_record = 2; + const named_stack_args: Select.Value.Indirect = .{ + .base = .fp, + .offset = 8 * std.mem.alignForward(u7, frame_record + saved_gra_len, 2), + }; + isel.va_list = .{ + .__stack = named_stack_args.withOffset(param_it.nsaa), + .__gr_top = named_stack_args, + .__vr_top = .{ .base = .fp, .offset = 0 }, + }; + + // translate arg locations from caller-based to callee-based + for (air_args) |air_inst_index| { + assert(air.instructions.items(.tag)[@intFromEnum(air_inst_index)] == .arg); + const arg_vi = isel.live_values.get(air_inst_index).?; + const passed_vi = switch (arg_vi.parent(&isel)) { + .unallocated, .stack_slot => arg_vi, + .value, .constant => unreachable, + .address => |address_vi| address_vi, + }; + switch (passed_vi.parent(&isel)) { + .unallocated => if (!mod.strip) { + var part_it = arg_vi.parts(&isel); + const first_passed_part_vi = part_it.next() orelse passed_vi; + const hint_ra = first_passed_part_vi.hint(&isel).?; + passed_vi.setParent(&isel, .{ .stack_slot = if (hint_ra.isVector()) + isel.va_list.__vr_top.withOffset(@as(i8, -16) * + (@intFromEnum(saved_vra_end) - @intFromEnum(hint_ra))) + else + isel.va_list.__gr_top.withOffset(@as(i8, -8) * + (@intFromEnum(saved_gra_end) - @intFromEnum(hint_ra))) }); + }, + .stack_slot => |stack_slot| { + assert(stack_slot.base == .sp); + passed_vi.setParent(&isel, .{ + .stack_slot = named_stack_args.withOffset(stack_slot.offset), + }); + }, + .address, .value, .constant => unreachable, + } + } + + ret: { + var ret_it: Select.CallAbiIterator = .init; + const ret_vi = try ret_it.ret(&isel, .fromInterned(func_type.return_type)) orelse break :ret; + tracking_log.debug("${d} <- %main", .{@intFromEnum(ret_vi)}); + try isel.live_values.putNoClobber(gpa, Select.Block.main, ret_vi); + } + + assert(!(try isel.blocks.getOrPut(gpa, Select.Block.main)).found_existing); + try isel.analyze(air_main_body); + try isel.finishAnalysis(); + isel.verify(false); + + isel.blocks.values()[0] = .{ + .live_registers = isel.live_registers, + .target_label = @intCast(isel.instructions.items.len), + }; + try isel.body(air_main_body); + if (isel.live_values.fetchRemove(Select.Block.main)) |ret_vi| { + switch (ret_vi.value.parent(&isel)) { + .unallocated, .stack_slot => {}, + .value, .constant => unreachable, + .address => |address_vi| try address_vi.liveIn( + &isel, + address_vi.hint(&isel).?, + comptime &.initFill(.free), + ), + } + ret_vi.value.deref(&isel); + } + isel.verify(true); + + const prologue = isel.instructions.items.len; + const epilogue = try isel.layout( + param_it, + func_type.is_var_args, + saved_gra_len, + saved_vra_len, + mod, + ); + + const instructions = try isel.instructions.toOwnedSlice(gpa); + var mir: Mir = .{ + .prologue = instructions[prologue..epilogue], + .body = instructions[0..prologue], + .epilogue = instructions[epilogue..], + .literals = &.{}, + .nav_relocs = &.{}, + .uav_relocs = &.{}, + .global_relocs = &.{}, + .literal_relocs = &.{}, + }; + errdefer mir.deinit(gpa); + mir.literals = try isel.literals.toOwnedSlice(gpa); + mir.nav_relocs = try isel.nav_relocs.toOwnedSlice(gpa); + mir.uav_relocs = try isel.uav_relocs.toOwnedSlice(gpa); + mir.global_relocs = try isel.global_relocs.toOwnedSlice(gpa); + mir.literal_relocs = try isel.literal_relocs.toOwnedSlice(gpa); + return mir; +} + +test { + _ = Assemble; +} + +const Air = @import("../Air.zig"); +const assert = std.debug.assert; +const InternPool = @import("../InternPool.zig"); +const link = @import("../link.zig"); +const std = @import("std"); +const tracking_log = std.log.scoped(.tracking); +const Zcu = @import("../Zcu.zig"); -- 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 'src/codegen/aarch64.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 From 69abc945e45af3f447f9ee07d426d1ec40cf3f15 Mon Sep 17 00:00:00 2001 From: Jacob Young Date: Sat, 26 Jul 2025 03:09:55 -0400 Subject: aarch64: implement some safety checks Closes #24553 --- src/Compilation.zig | 10 +- src/arch/x86_64/CodeGen.zig | 6 +- src/arch/x86_64/Emit.zig | 11 +- src/codegen/aarch64.zig | 7 +- src/codegen/aarch64/Assemble.zig | 32 +- src/codegen/aarch64/Mir.zig | 139 +++- src/codegen/aarch64/Select.zig | 806 ++++++++++++++++----- src/codegen/aarch64/instructions.zon | 190 +++++ src/target.zig | 6 +- test/behavior/error.zig | 3 - test/behavior/return_address.zig | 1 - test/cases/array_in_anon_struct.zig | 2 +- .../callconv_interrupt_on_unsupported_platform.zig | 4 +- test/cases/compile_errors/error_set_membership.zig | 2 +- .../compile_errors/function_ptr_alignment.zig | 2 +- .../issue_15572_break_on_inline_while.zig | 2 +- .../compile_errors/switch_on_non_err_union.zig | 2 +- test/cases/pic_freestanding.zig | 2 +- test/cases/safety/@alignCast misaligned.zig | 2 +- .../@enumFromInt - no matching tag value.zig | 2 +- .../@enumFromInt truncated bits - exhaustive.zig | 2 +- ...@enumFromInt truncated bits - nonexhaustive.zig | 2 +- ...@errorCast error not present in destination.zig | 2 +- ...rrorCast error union casted to disjoint set.zig | 2 +- test/cases/safety/@intCast to u0.zig | 2 +- ...omFloat cannot fit - boundary case - i0 max.zig | 2 +- ...omFloat cannot fit - boundary case - i0 min.zig | 2 +- ...oat cannot fit - boundary case - signed max.zig | 2 +- ...oat cannot fit - boundary case - signed min.zig | 2 +- ...omFloat cannot fit - boundary case - u0 max.zig | 2 +- ...omFloat cannot fit - boundary case - u0 min.zig | 2 +- ...t cannot fit - boundary case - unsigned max.zig | 2 +- ...t cannot fit - boundary case - unsigned min.zig | 2 +- ...oat cannot fit - boundary case - vector max.zig | 2 +- ...oat cannot fit - boundary case - vector min.zig | 2 +- ...romFloat cannot fit - negative out of range.zig | 2 +- ...FromFloat cannot fit - negative to unsigned.zig | 2 +- ...romFloat cannot fit - positive out of range.zig | 2 +- ...s zero to non-optional byte-aligned pointer.zig | 2 +- ...romInt address zero to non-optional pointer.zig | 2 +- .../safety/@ptrFromInt with misaligned address.zig | 2 +- .../safety/@tagName on corrupted enum value.zig | 2 +- .../safety/@tagName on corrupted union value.zig | 2 +- .../array slice sentinel mismatch vector.zig | 2 +- .../cases/safety/array slice sentinel mismatch.zig | 2 +- test/cases/safety/bad union field access.zig | 2 +- test/cases/safety/calling panic.zig | 2 +- .../cast []u8 to bigger slice of wrong size.zig | 2 +- ...integer to global error and no code matches.zig | 2 +- .../empty slice with sentinel out of bounds.zig | 2 +- .../safety/exact division failure - vectors.zig | 2 +- test/cases/safety/exact division failure.zig | 2 +- test/cases/safety/for_len_mismatch.zig | 2 +- test/cases/safety/for_len_mismatch_three.zig | 2 +- .../safety/ignored expression integer overflow.zig | 2 +- test/cases/safety/integer addition overflow.zig | 2 +- .../safety/integer division by zero - vectors.zig | 2 +- test/cases/safety/integer division by zero.zig | 2 +- .../safety/integer multiplication overflow.zig | 2 +- test/cases/safety/integer negation overflow.zig | 2 +- test/cases/safety/integer subtraction overflow.zig | 2 +- test/cases/safety/memcpy_alias.zig | 2 +- test/cases/safety/memcpy_len_mismatch.zig | 2 +- test/cases/safety/memmove_len_mismatch.zig | 2 +- test/cases/safety/memset_array_undefined_bytes.zig | 2 +- test/cases/safety/memset_array_undefined_large.zig | 2 +- test/cases/safety/memset_slice_undefined_bytes.zig | 2 +- test/cases/safety/memset_slice_undefined_large.zig | 2 +- test/cases/safety/modrem by zero.zig | 2 +- test/cases/safety/modulus by zero.zig | 2 +- test/cases/safety/noreturn returned.zig | 2 +- .../optional unwrap operator on C pointer.zig | 2 +- .../optional unwrap operator on null pointer.zig | 2 +- test/cases/safety/optional_empty_error_set.zig | 2 +- .../safety/out of bounds array slice by length.zig | 2 +- test/cases/safety/out of bounds slice access.zig | 2 +- ...ointer casting null to non-optional pointer.zig | 2 +- .../pointer casting to null function pointer.zig | 2 +- .../safety/pointer slice sentinel mismatch.zig | 2 +- test/cases/safety/remainder division by zero.zig | 2 +- test/cases/safety/shift left by huge amount.zig | 2 +- test/cases/safety/shift right by huge amount.zig | 2 +- .../signed integer division overflow - vectors.zig | 2 +- .../safety/signed integer division overflow.zig | 2 +- ...ting in cast to unsigned integer - widening.zig | 2 +- ...ger not fitting in cast to unsigned integer.zig | 2 +- test/cases/safety/signed shift left overflow.zig | 2 +- test/cases/safety/signed shift right overflow.zig | 2 +- test/cases/safety/signed-unsigned vector cast.zig | 2 +- .../slice by length sentinel mismatch on lhs.zig | 2 +- .../slice by length sentinel mismatch on rhs.zig | 2 +- .../safety/slice sentinel mismatch - floats.zig | 2 +- ...slice sentinel mismatch - optional pointers.zig | 2 +- .../cases/safety/slice slice sentinel mismatch.zig | 2 +- .../slice start index greater than end index.zig | 2 +- ...e with sentinel out of bounds - runtime len.zig | 2 +- .../safety/slice with sentinel out of bounds.zig | 2 +- test/cases/safety/slice_cast_change_len_0.zig | 2 +- test/cases/safety/slice_cast_change_len_1.zig | 2 +- test/cases/safety/slice_cast_change_len_2.zig | 2 +- .../slicing null C pointer - runtime len.zig | 2 +- test/cases/safety/slicing null C pointer.zig | 2 +- ...itch else on corrupt enum value - one prong.zig | 2 +- .../switch else on corrupt enum value - union.zig | 2 +- .../safety/switch else on corrupt enum value.zig | 2 +- .../safety/switch on corrupted enum value.zig | 2 +- .../safety/switch on corrupted union value.zig | 2 +- test/cases/safety/truncating vector cast.zig | 2 +- test/cases/safety/unreachable.zig | 2 +- ... in cast to signed integer - same bit count.zig | 2 +- test/cases/safety/unsigned shift left overflow.zig | 2 +- .../cases/safety/unsigned shift right overflow.zig | 2 +- test/cases/safety/unsigned-signed vector cast.zig | 2 +- test/cases/safety/unwrap error switch.zig | 2 +- test/cases/safety/unwrap error.zig | 2 +- .../value does not fit in shortening cast - u0.zig | 2 +- .../value does not fit in shortening cast.zig | 2 +- .../safety/vector integer addition overflow.zig | 2 +- .../vector integer multiplication overflow.zig | 2 +- .../safety/vector integer negation overflow.zig | 2 +- .../safety/vector integer subtraction overflow.zig | 2 +- test/cases/safety/zero casted to error.zig | 2 +- .../taking_pointer_of_global_tagged_union.zig | 2 +- test/src/Cases.zig | 6 +- 124 files changed, 1078 insertions(+), 365 deletions(-) (limited to 'src/codegen/aarch64.zig') diff --git a/src/Compilation.zig b/src/Compilation.zig index 4ed2e8c0ca..3796ed6acc 100644 --- a/src/Compilation.zig +++ b/src/Compilation.zig @@ -1816,10 +1816,12 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil if (options.skip_linker_dependencies) break :s .none; const want = options.want_compiler_rt orelse is_exe_or_dyn_lib; if (!want) break :s .none; - if (have_zcu) { + if (have_zcu and target_util.canBuildLibCompilerRt(target, use_llvm, build_options.have_llvm and use_llvm)) { if (output_mode == .Obj) break :s .zcu; - if (target.ofmt == .coff and target_util.zigBackend(target, use_llvm) == .stage2_x86_64) - break :s if (is_exe_or_dyn_lib) .dyn_lib else .zcu; + if (switch (target_util.zigBackend(target, use_llvm)) { + else => false, + .stage2_aarch64, .stage2_x86_64 => target.ofmt == .coff, + }) break :s if (is_exe_or_dyn_lib) .dyn_lib else .zcu; } if (is_exe_or_dyn_lib) break :s .lib; break :s .obj; @@ -1854,7 +1856,7 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil const want_ubsan_rt = options.want_ubsan_rt orelse (can_build_ubsan_rt and any_sanitize_c == .full and is_exe_or_dyn_lib); if (!want_ubsan_rt) break :s .none; if (options.skip_linker_dependencies) break :s .none; - if (have_zcu) break :s .zcu; + if (have_zcu and target_util.canBuildLibUbsanRt(target, use_llvm, build_options.have_llvm and use_llvm)) break :s .zcu; if (is_exe_or_dyn_lib) break :s .lib; break :s .obj; }; diff --git a/src/arch/x86_64/CodeGen.zig b/src/arch/x86_64/CodeGen.zig index 89a23d3514..70de299143 100644 --- a/src/arch/x86_64/CodeGen.zig +++ b/src/arch/x86_64/CodeGen.zig @@ -168141,7 +168141,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .unused, .unused, }, - .dst_temps = .{ .{ .cc = .b }, .unused }, + .dst_temps = .{ .{ .cc = .be }, .unused }, .clobbers = .{ .eflags = true }, .each = .{ .once = &.{ .{ ._, ._, .lea, .tmp1p, .lea(.tmp0), ._, ._ }, @@ -168165,7 +168165,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .unused, .unused, }, - .dst_temps = .{ .{ .cc = .b }, .unused }, + .dst_temps = .{ .{ .cc = .be }, .unused }, .clobbers = .{ .eflags = true }, .each = .{ .once = &.{ .{ ._, ._, .lea, .tmp1p, .lea(.tmp0), ._, ._ }, @@ -168189,7 +168189,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .unused, .unused, }, - .dst_temps = .{ .{ .cc = .b }, .unused }, + .dst_temps = .{ .{ .cc = .be }, .unused }, .clobbers = .{ .eflags = true }, .each = .{ .once = &.{ .{ ._, ._, .lea, .tmp1p, .lea(.tmp0), ._, ._ }, diff --git a/src/arch/x86_64/Emit.zig b/src/arch/x86_64/Emit.zig index da15dc6bfb..49c67620d5 100644 --- a/src/arch/x86_64/Emit.zig +++ b/src/arch/x86_64/Emit.zig @@ -168,11 +168,12 @@ pub fn emitMir(emit: *Emit) Error!void { else if (emit.bin_file.cast(.macho)) |macho_file| macho_file.getZigObject().?.getOrCreateMetadataForLazySymbol(macho_file, emit.pt, lazy_sym) catch |err| return emit.fail("{s} creating lazy symbol", .{@errorName(err)}) - else if (emit.bin_file.cast(.coff)) |coff_file| sym_index: { - const atom = coff_file.getOrCreateAtomForLazySymbol(emit.pt, lazy_sym) catch |err| - return emit.fail("{s} creating lazy symbol", .{@errorName(err)}); - break :sym_index coff_file.getAtom(atom).getSymbolIndex().?; - } else if (emit.bin_file.cast(.plan9)) |p9_file| + else if (emit.bin_file.cast(.coff)) |coff_file| + if (coff_file.getOrCreateAtomForLazySymbol(emit.pt, lazy_sym)) |atom| + coff_file.getAtom(atom).getSymbolIndex().? + else |err| + return emit.fail("{s} creating lazy symbol", .{@errorName(err)}) + else if (emit.bin_file.cast(.plan9)) |p9_file| p9_file.getOrCreateAtomForLazySymbol(emit.pt, lazy_sym) catch |err| return emit.fail("{s} creating lazy symbol", .{@errorName(err)}) else diff --git a/src/codegen/aarch64.zig b/src/codegen/aarch64.zig index f4b02a13c8..4cb3e8ecc8 100644 --- a/src/codegen/aarch64.zig +++ b/src/codegen/aarch64.zig @@ -47,6 +47,7 @@ pub fn generate( .literals = .empty, .nav_relocs = .empty, .uav_relocs = .empty, + .lazy_relocs = .empty, .global_relocs = .empty, .literal_relocs = .empty, @@ -101,8 +102,8 @@ pub fn generate( }; switch (passed_vi.parent(&isel)) { .unallocated => if (!mod.strip) { - var part_it = arg_vi.parts(&isel); - const first_passed_part_vi = part_it.next() orelse passed_vi; + var part_it = passed_vi.parts(&isel); + const first_passed_part_vi = part_it.next().?; const hint_ra = first_passed_part_vi.hint(&isel).?; passed_vi.setParent(&isel, .{ .stack_slot = if (hint_ra.isVector()) isel.va_list.__vr_top.withOffset(@as(i8, -16) * @@ -167,6 +168,7 @@ pub fn generate( .literals = &.{}, .nav_relocs = &.{}, .uav_relocs = &.{}, + .lazy_relocs = &.{}, .global_relocs = &.{}, .literal_relocs = &.{}, }; @@ -174,6 +176,7 @@ pub fn generate( mir.literals = try isel.literals.toOwnedSlice(gpa); mir.nav_relocs = try isel.nav_relocs.toOwnedSlice(gpa); mir.uav_relocs = try isel.uav_relocs.toOwnedSlice(gpa); + mir.lazy_relocs = try isel.lazy_relocs.toOwnedSlice(gpa); mir.global_relocs = try isel.global_relocs.toOwnedSlice(gpa); mir.literal_relocs = try isel.literal_relocs.toOwnedSlice(gpa); return mir; diff --git a/src/codegen/aarch64/Assemble.zig b/src/codegen/aarch64/Assemble.zig index 080df667d7..494e012d80 100644 --- a/src/codegen/aarch64/Assemble.zig +++ b/src/codegen/aarch64/Assemble.zig @@ -6,14 +6,19 @@ pub const Operand = union(enum) { }; pub fn nextInstruction(as: *Assemble) !?Instruction { - @setEvalBranchQuota(37_000); + @setEvalBranchQuota(42_000); comptime var ct_token_buf: [token_buf_len]u8 = undefined; var token_buf: [token_buf_len]u8 = undefined; const original_source = while (true) { const original_source = as.source; const source_token = try as.nextToken(&token_buf, .{}); - if (source_token.len == 0) return null; - if (source_token[0] != '\n') break original_source; + switch (source_token.len) { + 0 => return null, + else => switch (source_token[0]) { + else => break original_source, + '\n', ';' => {}, + }, + } }; log.debug( \\. @@ -52,7 +57,13 @@ pub fn nextInstruction(as: *Assemble) !?Instruction { std.zig.fmtString(source_token), }); if (pattern_token.len == 0) { - if (source_token.len > 0 and source_token[0] != '\n') break :next_pattern; + switch (source_token.len) { + 0 => {}, + else => switch (source_token[0]) { + else => break :next_pattern, + '\n', ';' => {}, + }, + } const encode = @field(Instruction, @tagName(instruction.encode[0])); const Encode = @TypeOf(encode); var args: std.meta.ArgsTuple(Encode) = undefined; @@ -65,7 +76,7 @@ pub fn nextInstruction(as: *Assemble) !?Instruction { const symbol = &@field(symbols, symbol_name); symbol.* = zonCast(SymbolSpec, @field(instruction.symbols, symbol_name), .{}).parse(source_token) orelse break :next_pattern; log.debug("{s} = {any}", .{ symbol_name, symbol.* }); - } else if (!std.ascii.eqlIgnoreCase(pattern_token, source_token)) break :next_pattern; + } else if (!toUpperEqlAssertUpper(source_token, pattern_token)) break :next_pattern; } } log.debug("'{s}' not matched...", .{instruction.pattern}); @@ -125,6 +136,15 @@ fn zonCast(comptime Result: type, zon_value: anytype, symbols: anytype) Result { } } +fn toUpperEqlAssertUpper(lhs: []const u8, rhs: []const u8) bool { + if (lhs.len != rhs.len) return false; + for (lhs, rhs) |l, r| { + assert(!std.ascii.isLower(r)); + if (std.ascii.toUpper(l) != r) return false; + } + return true; +} + const token_buf_len = "v31.b[15]".len; fn nextToken(as: *Assemble, buf: *[token_buf_len]u8, comptime opts: struct { operands: bool = false, @@ -134,7 +154,7 @@ fn nextToken(as: *Assemble, buf: *[token_buf_len]u8, comptime opts: struct { while (true) c: switch (as.source[0]) { 0 => return as.source[0..0], '\t', '\n' + 1...'\r', ' ' => as.source = as.source[1..], - '\n', '!', '#', ',', '[', ']' => { + '\n', '!', '#', ',', ';', '[', ']' => { defer as.source = as.source[1..]; return as.source[0..1]; }, diff --git a/src/codegen/aarch64/Mir.zig b/src/codegen/aarch64/Mir.zig index 1446238888..b6598b7ea7 100644 --- a/src/codegen/aarch64/Mir.zig +++ b/src/codegen/aarch64/Mir.zig @@ -4,6 +4,7 @@ epilogue: []const Instruction, literals: []const u32, nav_relocs: []const Reloc.Nav, uav_relocs: []const Reloc.Uav, +lazy_relocs: []const Reloc.Lazy, global_relocs: []const Reloc.Global, literal_relocs: []const Reloc.Literal, @@ -21,8 +22,13 @@ pub const Reloc = struct { reloc: Reloc, }; + pub const Lazy = struct { + symbol: link.File.LazySymbol, + reloc: Reloc, + }; + pub const Global = struct { - global: [*:0]const u8, + name: [*:0]const u8, reloc: Reloc, }; @@ -38,6 +44,7 @@ pub fn deinit(mir: *Mir, gpa: std.mem.Allocator) void { gpa.free(mir.literals); gpa.free(mir.nav_relocs); gpa.free(mir.uav_relocs); + gpa.free(mir.lazy_relocs); gpa.free(mir.global_relocs); gpa.free(mir.literal_relocs); mir.* = undefined; @@ -119,16 +126,37 @@ pub fn emit( body_end - Instruction.size * (1 + uav_reloc.reloc.label), uav_reloc.reloc.addend, ); + for (mir.lazy_relocs) |lazy_reloc| try emitReloc( + lf, + zcu, + func.owner_nav, + if (lf.cast(.elf)) |ef| + ef.zigObjectPtr().?.getOrCreateMetadataForLazySymbol(ef, pt, lazy_reloc.symbol) catch |err| + return zcu.codegenFail(func.owner_nav, "{s} creating lazy symbol", .{@errorName(err)}) + else if (lf.cast(.macho)) |mf| + mf.getZigObject().?.getOrCreateMetadataForLazySymbol(mf, pt, lazy_reloc.symbol) catch |err| + return zcu.codegenFail(func.owner_nav, "{s} creating lazy symbol", .{@errorName(err)}) + else if (lf.cast(.coff)) |cf| + if (cf.getOrCreateAtomForLazySymbol(pt, lazy_reloc.symbol)) |atom| + cf.getAtom(atom).getSymbolIndex().? + else |err| + return zcu.codegenFail(func.owner_nav, "{s} creating lazy symbol", .{@errorName(err)}) + else + return zcu.codegenFail(func.owner_nav, "external symbols unimplemented for {s}", .{@tagName(lf.tag)}), + mir.body[lazy_reloc.reloc.label], + body_end - Instruction.size * (1 + lazy_reloc.reloc.label), + lazy_reloc.reloc.addend, + ); for (mir.global_relocs) |global_reloc| try emitReloc( lf, zcu, func.owner_nav, if (lf.cast(.elf)) |ef| - try ef.getGlobalSymbol(std.mem.span(global_reloc.global), null) + try ef.getGlobalSymbol(std.mem.span(global_reloc.name), null) else if (lf.cast(.macho)) |mf| - try mf.getGlobalSymbol(std.mem.span(global_reloc.global), null) + try mf.getGlobalSymbol(std.mem.span(global_reloc.name), null) else if (lf.cast(.coff)) |cf| - try cf.getGlobalSymbol(std.mem.span(global_reloc.global), "compiler_rt") + try cf.getGlobalSymbol(std.mem.span(global_reloc.name), "compiler_rt") else return zcu.codegenFail(func.owner_nav, "external symbols unimplemented for {s}", .{@tagName(lf.tag)}), mir.body[global_reloc.reloc.label], @@ -172,35 +200,6 @@ fn emitReloc( const gpa = zcu.gpa; switch (instruction.decode()) { else => unreachable, - .branch_exception_generating_system => |decoded| if (lf.cast(.elf)) |ef| { - const zo = ef.zigObjectPtr().?; - const atom = zo.symbol(try zo.getOrCreateMetadataForNav(zcu, owner_nav)).atom(ef).?; - const r_type: std.elf.R_AARCH64 = switch (decoded.decode().unconditional_branch_immediate.group.op) { - .b => .JUMP26, - .bl => .CALL26, - }; - try atom.addReloc(gpa, .{ - .r_offset = offset, - .r_info = @as(u64, sym_index) << 32 | @intFromEnum(r_type), - .r_addend = @bitCast(addend), - }, zo); - } else if (lf.cast(.macho)) |mf| { - const zo = mf.getZigObject().?; - const atom = zo.symbols.items[try zo.getOrCreateMetadataForNav(mf, owner_nav)].getAtom(mf).?; - try atom.addReloc(mf, .{ - .tag = .@"extern", - .offset = offset, - .target = sym_index, - .addend = @bitCast(addend), - .type = .branch, - .meta = .{ - .pcrel = true, - .has_subtractor = false, - .length = 2, - .symbolnum = @intCast(sym_index), - }, - }); - }, .data_processing_immediate => |decoded| if (lf.cast(.elf)) |ef| { const zo = ef.zigObjectPtr().?; const atom = zo.symbol(try zo.getOrCreateMetadataForNav(zcu, owner_nav)).atom(ef).?; @@ -259,6 +258,80 @@ fn emitReloc( }, } }, + .branch_exception_generating_system => |decoded| if (lf.cast(.elf)) |ef| { + const zo = ef.zigObjectPtr().?; + const atom = zo.symbol(try zo.getOrCreateMetadataForNav(zcu, owner_nav)).atom(ef).?; + const r_type: std.elf.R_AARCH64 = switch (decoded.decode().unconditional_branch_immediate.group.op) { + .b => .JUMP26, + .bl => .CALL26, + }; + try atom.addReloc(gpa, .{ + .r_offset = offset, + .r_info = @as(u64, sym_index) << 32 | @intFromEnum(r_type), + .r_addend = @bitCast(addend), + }, zo); + } else if (lf.cast(.macho)) |mf| { + const zo = mf.getZigObject().?; + const atom = zo.symbols.items[try zo.getOrCreateMetadataForNav(mf, owner_nav)].getAtom(mf).?; + try atom.addReloc(mf, .{ + .tag = .@"extern", + .offset = offset, + .target = sym_index, + .addend = @bitCast(addend), + .type = .branch, + .meta = .{ + .pcrel = true, + .has_subtractor = false, + .length = 2, + .symbolnum = @intCast(sym_index), + }, + }); + }, + .load_store => |decoded| if (lf.cast(.elf)) |ef| { + const zo = ef.zigObjectPtr().?; + const atom = zo.symbol(try zo.getOrCreateMetadataForNav(zcu, owner_nav)).atom(ef).?; + const r_type: std.elf.R_AARCH64 = switch (decoded.decode().register_unsigned_immediate.decode()) { + .integer => |integer| switch (integer.decode()) { + .unallocated, .prfm => unreachable, + .strb, .ldrb, .ldrsb => .LDST8_ABS_LO12_NC, + .strh, .ldrh, .ldrsh => .LDST16_ABS_LO12_NC, + .ldrsw => .LDST32_ABS_LO12_NC, + inline .str, .ldr => |encoded| switch (encoded.sf) { + .word => .LDST32_ABS_LO12_NC, + .doubleword => .LDST64_ABS_LO12_NC, + }, + }, + .vector => |vector| switch (vector.group.opc1.decode(vector.group.size)) { + .byte => .LDST8_ABS_LO12_NC, + .half => .LDST16_ABS_LO12_NC, + .single => .LDST32_ABS_LO12_NC, + .double => .LDST64_ABS_LO12_NC, + .quad => .LDST128_ABS_LO12_NC, + .scalable, .predicate => unreachable, + }, + }; + try atom.addReloc(gpa, .{ + .r_offset = offset, + .r_info = @as(u64, sym_index) << 32 | @intFromEnum(r_type), + .r_addend = @bitCast(addend), + }, zo); + } else if (lf.cast(.macho)) |mf| { + const zo = mf.getZigObject().?; + const atom = zo.symbols.items[try zo.getOrCreateMetadataForNav(mf, owner_nav)].getAtom(mf).?; + try atom.addReloc(mf, .{ + .tag = .@"extern", + .offset = offset, + .target = sym_index, + .addend = @bitCast(addend), + .type = .pageoff, + .meta = .{ + .pcrel = false, + .has_subtractor = false, + .length = 2, + .symbolnum = @intCast(sym_index), + }, + }); + }, } } diff --git a/src/codegen/aarch64/Select.zig b/src/codegen/aarch64/Select.zig index b0b1297a93..6ceb3f3a59 100644 --- a/src/codegen/aarch64/Select.zig +++ b/src/codegen/aarch64/Select.zig @@ -22,6 +22,7 @@ instructions: std.ArrayListUnmanaged(codegen.aarch64.encoding.Instruction), literals: std.ArrayListUnmanaged(u32), nav_relocs: std.ArrayListUnmanaged(codegen.aarch64.Mir.Reloc.Nav), uav_relocs: std.ArrayListUnmanaged(codegen.aarch64.Mir.Reloc.Uav), +lazy_relocs: std.ArrayListUnmanaged(codegen.aarch64.Mir.Reloc.Lazy), global_relocs: std.ArrayListUnmanaged(codegen.aarch64.Mir.Reloc.Global), literal_relocs: std.ArrayListUnmanaged(codegen.aarch64.Mir.Reloc.Literal), @@ -50,11 +51,11 @@ pub const Block = struct { std.math.maxInt(@typeInfo(Air.Inst.Index).@"enum".tag_type), ); - fn branch(block: *const Block, isel: *Select) !void { - if (isel.instructions.items.len > block.target_label) { - try isel.emit(.b(@intCast((isel.instructions.items.len + 1 - block.target_label) << 2))); + fn branch(target_block: *const Block, isel: *Select) !void { + if (isel.instructions.items.len > target_block.target_label) { + try isel.emit(.b(@intCast((isel.instructions.items.len + 1 - target_block.target_label) << 2))); } - try isel.merge(&block.live_registers, .{}); + try isel.merge(&target_block.live_registers, .{}); } }; @@ -84,12 +85,12 @@ pub const Loop = struct { pub const empty_list: u32 = std.math.maxInt(u32); - fn branch(loop: *Loop, isel: *Select) !void { + fn branch(target_loop: *Loop, isel: *Select) !void { try isel.instructions.ensureUnusedCapacity(isel.pt.zcu.gpa, 1); - const repeat_list_tail = loop.repeat_list; - loop.repeat_list = @intCast(isel.instructions.items.len); + const repeat_list_tail = target_loop.repeat_list; + target_loop.repeat_list = @intCast(isel.instructions.items.len); isel.instructions.appendAssumeCapacity(@bitCast(repeat_list_tail)); - try isel.merge(&loop.live_registers, .{}); + try isel.merge(&target_loop.live_registers, .{}); } }; @@ -108,6 +109,7 @@ pub fn deinit(isel: *Select) void { isel.literals.deinit(gpa); isel.nav_relocs.deinit(gpa); isel.uav_relocs.deinit(gpa); + isel.lazy_relocs.deinit(gpa); isel.global_relocs.deinit(gpa); isel.literal_relocs.deinit(gpa); @@ -864,7 +866,7 @@ pub fn finishAnalysis(isel: *Select) !void { } } -pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void { +pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory, CodegenFail }!void { const zcu = isel.pt.zcu; const ip = &zcu.intern_pool; const gpa = zcu.gpa; @@ -946,7 +948,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void { } if (air.next()) |next_air_tag| continue :air_tag next_air_tag; }, - .add, .add_optimized, .add_wrap, .sub, .sub_optimized, .sub_wrap => |air_tag| { + .add, .add_safe, .add_optimized, .add_wrap, .sub, .sub_safe, .sub_optimized, .sub_wrap => |air_tag| { if (isel.live_values.fetchRemove(air.inst_index)) |res_vi| unused: { defer res_vi.value.deref(isel); @@ -954,13 +956,16 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void { const ty = isel.air.typeOf(bin_op.lhs, ip); if (!ty.isRuntimeFloat()) try res_vi.value.addOrSubtract(isel, ty, try isel.use(bin_op.lhs), switch (air_tag) { else => unreachable, - .add, .add_wrap => .add, - .sub, .sub_wrap => .sub, - }, try isel.use(bin_op.rhs), .{ .wrap = switch (air_tag) { - else => unreachable, - .add, .sub => false, - .add_wrap, .sub_wrap => true, - } }) else switch (ty.floatBits(isel.target)) { + .add, .add_safe, .add_wrap => .add, + .sub, .sub_safe, .sub_wrap => .sub, + }, try isel.use(bin_op.rhs), .{ + .overflow = switch (air_tag) { + else => unreachable, + .add, .sub => .@"unreachable", + .add_safe, .sub_safe => .{ .panic = .integer_overflow }, + .add_wrap, .sub_wrap => .wrap, + }, + }) else switch (ty.floatBits(isel.target)) { else => unreachable, 16, 32, 64 => |bits| { const res_ra = try res_vi.value.defReg(isel) orelse break :unused; @@ -1021,7 +1026,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void { try call.prepareCallee(isel); try isel.global_relocs.append(gpa, .{ - .global = switch (air_tag) { + .name = switch (air_tag) { else => unreachable, .add, .add_optimized => switch (bits) { else => unreachable, @@ -1336,7 +1341,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void { try call.prepareCallee(isel); try isel.global_relocs.append(gpa, .{ - .global = switch (bits) { + .name = switch (bits) { else => unreachable, 16 => "__mulhf3", 32 => "__mulsf3", @@ -1379,6 +1384,143 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void { } if (air.next()) |next_air_tag| continue :air_tag next_air_tag; }, + .mul_safe => |air_tag| { + if (isel.live_values.fetchRemove(air.inst_index)) |res_vi| unused: { + defer res_vi.value.deref(isel); + + const bin_op = air.data(air.inst_index).bin_op; + const ty = isel.air.typeOf(bin_op.lhs, ip); + if (!ty.isAbiInt(zcu)) return isel.fail("bad {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) }); + const int_info = ty.intInfo(zcu); + switch (int_info.signedness) { + .signed => switch (int_info.bits) { + 0 => unreachable, + 1 => { + const res_ra = try res_vi.value.defReg(isel) orelse break :unused; + const lhs_vi = try isel.use(bin_op.lhs); + const rhs_vi = try isel.use(bin_op.rhs); + const lhs_mat = try lhs_vi.matReg(isel); + const rhs_mat = try rhs_vi.matReg(isel); + try isel.emit(.orr(res_ra.w(), lhs_mat.ra.w(), .{ .register = rhs_mat.ra.w() })); + const skip_label = isel.instructions.items.len; + try isel.emitPanic(.integer_overflow); + try isel.emit(.@"b."( + .invert(.ne), + @intCast((isel.instructions.items.len + 1 - skip_label) << 2), + )); + try isel.emit(.ands(.wzr, lhs_mat.ra.w(), .{ .register = rhs_mat.ra.w() })); + try rhs_mat.finish(isel); + try lhs_mat.finish(isel); + }, + else => return isel.fail("too big {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) }), + }, + .unsigned => switch (int_info.bits) { + 0 => unreachable, + 1 => { + const res_ra = try res_vi.value.defReg(isel) orelse break :unused; + const lhs_vi = try isel.use(bin_op.lhs); + const rhs_vi = try isel.use(bin_op.rhs); + const lhs_mat = try lhs_vi.matReg(isel); + const rhs_mat = try rhs_vi.matReg(isel); + try isel.emit(.@"and"(res_ra.w(), lhs_mat.ra.w(), .{ .register = rhs_mat.ra.w() })); + try rhs_mat.finish(isel); + try lhs_mat.finish(isel); + }, + 2...16 => |bits| { + const res_ra = try res_vi.value.defReg(isel) orelse break :unused; + const lhs_vi = try isel.use(bin_op.lhs); + const rhs_vi = try isel.use(bin_op.rhs); + const lhs_mat = try lhs_vi.matReg(isel); + const rhs_mat = try rhs_vi.matReg(isel); + const skip_label = isel.instructions.items.len; + try isel.emitPanic(.integer_overflow); + try isel.emit(.@"b."( + .eq, + @intCast((isel.instructions.items.len + 1 - skip_label) << 2), + )); + try isel.emit(.ands(.wzr, res_ra.w(), .{ .immediate = .{ + .N = .word, + .immr = @intCast(32 - bits), + .imms = @intCast(32 - bits - 1), + } })); + try isel.emit(.madd(res_ra.w(), lhs_mat.ra.w(), rhs_mat.ra.w(), .wzr)); + try rhs_mat.finish(isel); + try lhs_mat.finish(isel); + }, + 17...32 => |bits| { + const res_ra = try res_vi.value.defReg(isel) orelse break :unused; + const lhs_vi = try isel.use(bin_op.lhs); + const rhs_vi = try isel.use(bin_op.rhs); + const lhs_mat = try lhs_vi.matReg(isel); + const rhs_mat = try rhs_vi.matReg(isel); + const skip_label = isel.instructions.items.len; + try isel.emitPanic(.integer_overflow); + try isel.emit(.@"b."( + .eq, + @intCast((isel.instructions.items.len + 1 - skip_label) << 2), + )); + try isel.emit(.ands(.xzr, res_ra.x(), .{ .immediate = .{ + .N = .doubleword, + .immr = @intCast(64 - bits), + .imms = @intCast(64 - bits - 1), + } })); + try isel.emit(.umaddl(res_ra.x(), lhs_mat.ra.w(), rhs_mat.ra.w(), .xzr)); + try rhs_mat.finish(isel); + try lhs_mat.finish(isel); + }, + 33...63 => |bits| { + const lo64_ra = try res_vi.value.defReg(isel) orelse break :unused; + const lhs_vi = try isel.use(bin_op.lhs); + const rhs_vi = try isel.use(bin_op.rhs); + const lhs_mat = try lhs_vi.matReg(isel); + const rhs_mat = try rhs_vi.matReg(isel); + const hi64_ra = hi64_ra: { + const lo64_lock = isel.tryLockReg(lo64_ra); + defer lo64_lock.unlock(isel); + break :hi64_ra try isel.allocIntReg(); + }; + defer isel.freeReg(hi64_ra); + const skip_label = isel.instructions.items.len; + try isel.emitPanic(.integer_overflow); + try isel.emit(.cbz( + hi64_ra.x(), + @intCast((isel.instructions.items.len + 1 - skip_label) << 2), + )); + try isel.emit(.orr(hi64_ra.x(), hi64_ra.x(), .{ .shifted_register = .{ + .register = lo64_ra.x(), + .shift = .{ .lsr = @intCast(bits) }, + } })); + try isel.emit(.madd(lo64_ra.x(), lhs_mat.ra.x(), rhs_mat.ra.x(), .xzr)); + try isel.emit(.umulh(hi64_ra.x(), lhs_mat.ra.x(), rhs_mat.ra.x())); + try rhs_mat.finish(isel); + try lhs_mat.finish(isel); + }, + 64 => { + const res_ra = try res_vi.value.defReg(isel) orelse break :unused; + const lhs_vi = try isel.use(bin_op.lhs); + const rhs_vi = try isel.use(bin_op.rhs); + const lhs_mat = try lhs_vi.matReg(isel); + const rhs_mat = try rhs_vi.matReg(isel); + try isel.emit(.madd(res_ra.x(), lhs_mat.ra.x(), rhs_mat.ra.x(), .xzr)); + const hi64_ra = try isel.allocIntReg(); + defer isel.freeReg(hi64_ra); + const skip_label = isel.instructions.items.len; + try isel.emitPanic(.integer_overflow); + try isel.emit(.cbz( + hi64_ra.x(), + @intCast((isel.instructions.items.len + 1 - skip_label) << 2), + )); + try isel.emit(.umulh(hi64_ra.x(), lhs_mat.ra.x(), rhs_mat.ra.x())); + try rhs_mat.finish(isel); + try lhs_mat.finish(isel); + }, + 65...128 => return isel.fail("bad {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) }), + else => return isel.fail("too big {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) }), + }, + } + } + if (air.next()) |next_air_tag| continue :air_tag next_air_tag; + }, .mul_sat => |air_tag| { if (isel.live_values.fetchRemove(air.inst_index)) |res_vi| unused: { defer res_vi.value.deref(isel); @@ -1674,7 +1816,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void { try call.prepareCallee(isel); try isel.global_relocs.append(gpa, .{ - .global = switch (bits) { + .name = switch (bits) { else => unreachable, 16 => "__divhf3", 32 => "__divsf3", @@ -1813,7 +1955,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void { try call.prepareCallee(isel); try isel.global_relocs.append(gpa, .{ - .global = switch (int_info.signedness) { + .name = switch (int_info.signedness) { .signed => "__divti3", .unsigned => "__udivti3", }, @@ -1917,7 +2059,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void { else => unreachable, .div_trunc, .div_trunc_optimized => { try isel.global_relocs.append(gpa, .{ - .global = switch (bits) { + .name = switch (bits) { else => unreachable, 16 => "__trunch", 32 => "truncf", @@ -1931,7 +2073,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void { }, .div_floor, .div_floor_optimized => { try isel.global_relocs.append(gpa, .{ - .global = switch (bits) { + .name = switch (bits) { else => unreachable, 16 => "__floorh", 32 => "floorf", @@ -1946,7 +2088,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void { .div_exact, .div_exact_optimized => {}, } try isel.global_relocs.append(gpa, .{ - .global = switch (bits) { + .name = switch (bits) { else => unreachable, 16 => "__divhf3", 32 => "__divsf3", @@ -2046,7 +2188,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void { try call.prepareCallee(isel); try isel.global_relocs.append(gpa, .{ - .global = switch (bits) { + .name = switch (bits) { else => unreachable, 16 => "__fmodh", 32 => "fmodf", @@ -2212,7 +2354,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void { try call.prepareCallee(isel); try isel.global_relocs.append(gpa, .{ - .global = switch (air_tag) { + .name = switch (air_tag) { else => unreachable, .max => switch (bits) { else => unreachable, @@ -2284,7 +2426,9 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void { else => unreachable, .add_with_overflow => .add, .sub_with_overflow => .sub, - }, rhs_vi, .{ .wrap = true, .overflow_ra = try overflow_vi.?.defReg(isel) orelse .zr }); + }, rhs_vi, .{ + .overflow = if (try overflow_vi.?.defReg(isel)) |overflow_ra| .{ .ra = overflow_ra } else .wrap, + }); } if (air.next()) |next_air_tag| continue :air_tag next_air_tag; }, @@ -3092,7 +3236,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void { try call.prepareCallee(isel); try isel.global_relocs.append(gpa, .{ - .global = "memcpy", + .name = "memcpy", .reloc = .{ .label = @intCast(isel.instructions.items.len) }, }); try isel.emit(.bl(0)); @@ -3119,7 +3263,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void { try call.prepareCallee(isel); try isel.global_relocs.append(gpa, .{ - .global = "memcpy", + .name = "memcpy", .reloc = .{ .label = @intCast(isel.instructions.items.len) }, }); try isel.emit(.bl(0)); @@ -3139,19 +3283,9 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void { .block => { const ty_pl = air.data(air.inst_index).ty_pl; const extra = isel.air.extraData(Air.Block, ty_pl.payload); - - if (ty_pl.ty != .noreturn_type) { - isel.blocks.putAssumeCapacityNoClobber(air.inst_index, .{ - .live_registers = isel.live_registers, - .target_label = @intCast(isel.instructions.items.len), - }); - } - try isel.body(@ptrCast(isel.air.extra.items[extra.end..][0..extra.data.body_len])); - if (ty_pl.ty != .noreturn_type) { - const block_entry = isel.blocks.pop().?; - assert(block_entry.key == air.inst_index); - if (isel.live_values.fetchRemove(air.inst_index)) |result_vi| result_vi.value.deref(isel); - } + try isel.block(air.inst_index, ty_pl.ty.toType(), @ptrCast( + isel.air.extra.items[extra.end..][0..extra.data.body_len], + )); if (air.next()) |next_air_tag| continue :air_tag next_air_tag; }, .loop => { @@ -3175,11 +3309,11 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void { } // IT'S DOM TIME!!! - for (isel.blocks.values(), 0..) |*block, dom_index| { + for (isel.blocks.values(), 0..) |*dom_block, dom_index| { if (@as(u1, @truncate(isel.dom.items[ loop.dom + dom_index / @bitSizeOf(DomInt) ] >> @truncate(dom_index))) == 0) continue; - var live_reg_it = block.live_registers.iterator(); + var live_reg_it = dom_block.live_registers.iterator(); while (live_reg_it.next()) |live_reg_entry| switch (live_reg_entry.value.*) { _ => |live_vi| try live_vi.mat(isel), .allocating => unreachable, @@ -3211,8 +3345,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void { }, .br => { const br = air.data(air.inst_index).br; - const block = isel.blocks.getPtr(br.block_inst).?; - try block.branch(isel); + try isel.blocks.getPtr(br.block_inst).?.branch(isel); if (isel.live_values.get(br.block_inst)) |dst_vi| try dst_vi.move(isel, br.operand); if (air.next()) |next_air_tag| continue :air_tag next_air_tag; }, @@ -3224,6 +3357,22 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void { try isel.emit(.brk(0xf000)); if (air.next()) |next_air_tag| continue :air_tag next_air_tag; }, + .ret_addr => { + if (isel.live_values.fetchRemove(air.inst_index)) |addr_vi| unused: { + defer addr_vi.value.deref(isel); + const addr_ra = try addr_vi.value.defReg(isel) orelse break :unused; + try isel.emit(.ldr(addr_ra.x(), .{ .unsigned_offset = .{ .base = .fp, .offset = 8 } })); + } + if (air.next()) |next_air_tag| continue :air_tag next_air_tag; + }, + .frame_addr => { + if (isel.live_values.fetchRemove(air.inst_index)) |addr_vi| unused: { + defer addr_vi.value.deref(isel); + const addr_ra = try addr_vi.value.defReg(isel) orelse break :unused; + try isel.emit(.orr(addr_ra.x(), .xzr, .{ .register = .fp })); + } + if (air.next()) |next_air_tag| continue :air_tag next_air_tag; + }, .call => { const pl_op = air.data(air.inst_index).pl_op; const extra = isel.air.extraData(Air.Call, pl_op.payload); @@ -3312,7 +3461,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void { var param_part_it = passed_vi.parts(isel); var arg_part_it = arg_vi.parts(isel); if (arg_part_it.only()) |_| { - try isel.values.ensureUnusedCapacity(isel.pt.zcu.gpa, param_part_it.remaining); + try isel.values.ensureUnusedCapacity(gpa, param_part_it.remaining); arg_vi.setParts(isel, param_part_it.remaining); while (param_part_it.next()) |param_part_vi| _ = arg_vi.addPart( isel, @@ -3659,7 +3808,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void { try call.prepareCallee(isel); try isel.global_relocs.append(gpa, .{ - .global = switch (air_tag) { + .name = switch (air_tag) { else => unreachable, .sqrt => switch (bits) { else => unreachable, @@ -3751,7 +3900,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void { try call.prepareCallee(isel); try isel.global_relocs.append(gpa, .{ - .global = switch (air_tag) { + .name = switch (air_tag) { else => unreachable, .sin => switch (bits) { else => unreachable, @@ -4239,7 +4388,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void { try call.prepareCallee(isel); try isel.global_relocs.append(gpa, .{ - .global = switch (bits) { + .name = switch (bits) { else => unreachable, 16 => "__cmphf2", 32 => "__cmpsf2", @@ -4629,6 +4778,14 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void { try isel.emit(.nop()); if (air.next()) |next_air_tag| continue :air_tag next_air_tag; }, + .dbg_inline_block => { + const ty_pl = air.data(air.inst_index).ty_pl; + const extra = isel.air.extraData(Air.DbgInlineBlock, ty_pl.payload); + try isel.block(air.inst_index, ty_pl.ty.toType(), @ptrCast( + isel.air.extra.items[extra.end..][0..extra.data.body_len], + )); + if (air.next()) |next_air_tag| continue :air_tag next_air_tag; + }, .dbg_var_ptr, .dbg_var_val, .dbg_arg_inline => { if (air.next()) |next_air_tag| continue :air_tag next_air_tag; }, @@ -4724,7 +4881,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void { try call.prepareCallee(isel); try isel.global_relocs.append(gpa, .{ - .global = "memcpy", + .name = "memcpy", .reloc = .{ .label = @intCast(isel.instructions.items.len) }, }); try isel.emit(.bl(0)); @@ -4816,10 +4973,8 @@ 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); if (ptr_info.packed_offset.host_size > 0) return isel.fail("packed store", .{}); - if (bin_op.rhs.toInterned()) |rhs_val| if (ip.isUndef(rhs_val)) { - if (air.next()) |next_air_tag| continue :air_tag next_air_tag; - break :air_tag; - }; + if (bin_op.rhs.toInterned()) |rhs_val| if (ip.isUndef(rhs_val)) + break :air_tag if (air.next()) |next_air_tag| continue :air_tag next_air_tag; const src_vi = try isel.use(bin_op.rhs); const size = src_vi.size(isel); @@ -4833,8 +4988,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void { }); try ptr_mat.finish(isel); - if (air.next()) |next_air_tag| continue :air_tag next_air_tag; - break :air_tag; + break :air_tag if (air.next()) |next_air_tag| continue :air_tag next_air_tag; }, else => {}, }; @@ -4843,7 +4997,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void { try call.prepareCallee(isel); try isel.global_relocs.append(gpa, .{ - .global = "memcpy", + .name = "memcpy", .reloc = .{ .label = @intCast(isel.instructions.items.len) }, }); try isel.emit(.bl(0)); @@ -4906,7 +5060,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void { try call.prepareCallee(isel); try isel.global_relocs.append(gpa, .{ - .global = switch (dst_bits) { + .name = switch (dst_bits) { else => unreachable, 16 => switch (src_bits) { else => unreachable, @@ -5060,6 +5214,108 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void { } if (air.next()) |next_air_tag| continue :air_tag next_air_tag; }, + .intcast_safe => |air_tag| { + if (isel.live_values.fetchRemove(air.inst_index)) |dst_vi| unused: { + defer dst_vi.value.deref(isel); + + const ty_op = air.data(air.inst_index).ty_op; + const dst_ty = ty_op.ty.toType(); + const dst_int_info = dst_ty.intInfo(zcu); + const src_ty = isel.air.typeOf(ty_op.operand, ip); + const src_int_info = src_ty.intInfo(zcu); + const can_be_negative = dst_int_info.signedness == .signed and + src_int_info.signedness == .signed; + const panic_id: Zcu.SimplePanicId = panic_id: switch (dst_ty.zigTypeTag(zcu)) { + else => unreachable, + .int => .integer_out_of_bounds, + .@"enum" => { + if (!dst_ty.isNonexhaustiveEnum(zcu)) { + return isel.fail("bad {s} {f} {f}", .{ @tagName(air_tag), isel.fmtType(dst_ty), isel.fmtType(src_ty) }); + } + break :panic_id .invalid_enum_value; + }, + }; + if (dst_ty.toIntern() == src_ty.toIntern()) { + try dst_vi.value.move(isel, ty_op.operand); + } else if (dst_int_info.bits <= 64 and src_int_info.bits <= 64) { + const dst_ra = try dst_vi.value.defReg(isel) orelse break :unused; + const src_vi = try isel.use(ty_op.operand); + const dst_active_bits = dst_int_info.bits - @intFromBool(dst_int_info.signedness == .signed); + const src_active_bits = src_int_info.bits - @intFromBool(src_int_info.signedness == .signed); + if ((dst_int_info.signedness != .unsigned or src_int_info.signedness != .signed) and dst_active_bits >= src_active_bits) { + const src_mat = try src_vi.matReg(isel); + try isel.emit(if (can_be_negative and dst_active_bits > 32 and src_active_bits <= 32) + .sbfm(dst_ra.x(), src_mat.ra.x(), .{ + .N = .doubleword, + .immr = 0, + .imms = @intCast(src_int_info.bits - 1), + }) + else switch (src_int_info.bits) { + else => unreachable, + 1...32 => .orr(dst_ra.w(), .wzr, .{ .register = src_mat.ra.w() }), + 33...64 => .orr(dst_ra.x(), .xzr, .{ .register = src_mat.ra.x() }), + }); + try src_mat.finish(isel); + } else { + const skip_label = isel.instructions.items.len; + try isel.emitPanic(panic_id); + try isel.emit(.@"b."( + .eq, + @intCast((isel.instructions.items.len + 1 - skip_label) << 2), + )); + if (can_be_negative) { + const src_mat = src_mat: { + const dst_lock = isel.lockReg(dst_ra); + defer dst_lock.unlock(isel); + break :src_mat try src_vi.matReg(isel); + }; + try isel.emit(switch (src_int_info.bits) { + else => unreachable, + 1...32 => .subs(.wzr, dst_ra.w(), .{ .register = src_mat.ra.w() }), + 33...64 => .subs(.xzr, dst_ra.x(), .{ .register = src_mat.ra.x() }), + }); + try isel.emit(switch (@max(dst_int_info.bits, src_int_info.bits)) { + else => unreachable, + 1...32 => .sbfm(dst_ra.w(), src_mat.ra.w(), .{ + .N = .word, + .immr = 0, + .imms = @intCast(dst_int_info.bits - 1), + }), + 33...64 => .sbfm(dst_ra.x(), src_mat.ra.x(), .{ + .N = .doubleword, + .immr = 0, + .imms = @intCast(dst_int_info.bits - 1), + }), + }); + try src_mat.finish(isel); + } else { + const src_mat = try src_vi.matReg(isel); + try isel.emit(switch (@min(dst_int_info.bits, src_int_info.bits)) { + else => unreachable, + 1...32 => .orr(dst_ra.w(), .wzr, .{ .register = src_mat.ra.w() }), + 33...64 => .orr(dst_ra.x(), .xzr, .{ .register = src_mat.ra.x() }), + }); + const active_bits = @min(dst_active_bits, src_active_bits); + try isel.emit(switch (src_int_info.bits) { + else => unreachable, + 1...32 => .ands(.wzr, src_mat.ra.w(), .{ .immediate = .{ + .N = .word, + .immr = @intCast(32 - active_bits), + .imms = @intCast(32 - active_bits - 1), + } }), + 33...64 => .ands(.xzr, src_mat.ra.x(), .{ .immediate = .{ + .N = .doubleword, + .immr = @intCast(64 - active_bits), + .imms = @intCast(64 - active_bits - 1), + } }), + }); + try src_mat.finish(isel); + } + } + } else return isel.fail("too big {s} {f} {f}", .{ @tagName(air_tag), isel.fmtType(dst_ty), isel.fmtType(src_ty) }); + } + if (air.next()) |next_air_tag| continue :air_tag next_air_tag; + }, .trunc => |air_tag| { if (isel.live_values.fetchRemove(air.inst_index)) |dst_vi| unused: { defer dst_vi.value.deref(isel); @@ -5832,7 +6088,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void { try call.prepareCallee(isel); try isel.global_relocs.append(gpa, .{ - .global = switch (dst_int_info.bits) { + .name = switch (dst_int_info.bits) { else => unreachable, 1...32 => switch (dst_int_info.signedness) { .signed => switch (src_bits) { @@ -5972,7 +6228,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void { try call.prepareCallee(isel); try isel.global_relocs.append(gpa, .{ - .global = switch (src_int_info.bits) { + .name = switch (src_int_info.bits) { else => unreachable, 1...32 => switch (src_int_info.signedness) { .signed => switch (dst_bits) { @@ -6055,14 +6311,20 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void { } if (air.next()) |next_air_tag| continue :air_tag next_air_tag; }, - .memset => |air_tag| { + .memset, .memset_safe => |air_tag| { const bin_op = air.data(air.inst_index).bin_op; const dst_ty = isel.air.typeOf(bin_op.lhs, ip); const dst_info = dst_ty.ptrInfo(zcu); const fill_byte: union(enum) { constant: u8, value: Air.Inst.Ref } = fill_byte: { - if (bin_op.rhs.toInterned()) |fill_val| + if (bin_op.rhs.toInterned()) |fill_val| { + if (ip.isUndef(fill_val)) switch (air_tag) { + else => unreachable, + .memset => break :air_tag if (air.next()) |next_air_tag| continue :air_tag next_air_tag, + .memset_safe => break :fill_byte .{ .constant = 0xaa }, + }; if (try isel.hasRepeatedByteRepr(.fromInterned(fill_val))) |fill_byte| break :fill_byte .{ .constant = fill_byte }; + } switch (dst_ty.elemType2(zcu).abiSize(zcu)) { 0 => unreachable, 1 => break :fill_byte .{ .value = bin_op.rhs }, @@ -6121,8 +6383,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void { .c => unreachable, } - if (air.next()) |next_air_tag| continue :air_tag next_air_tag; - break :air_tag; + break :air_tag if (air.next()) |next_air_tag| continue :air_tag next_air_tag; }, else => return isel.fail("too big {s} {f}", .{ @tagName(air_tag), isel.fmtType(dst_ty) }), } @@ -6133,7 +6394,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void { try call.prepareCallee(isel); try isel.global_relocs.append(gpa, .{ - .global = "memset", + .name = "memset", .reloc = .{ .label = @intCast(isel.instructions.items.len) }, }); try isel.emit(.bl(0)); @@ -6179,7 +6440,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void { try call.prepareCallee(isel); try isel.global_relocs.append(gpa, .{ - .global = @tagName(air_tag), + .name = @tagName(air_tag), .reloc = .{ .label = @intCast(isel.instructions.items.len) }, }); try isel.emit(.bl(0)); @@ -6268,6 +6529,72 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void { if (air.next()) |next_air_tag| continue :air_tag next_air_tag; }, + .error_name => { + if (isel.live_values.fetchRemove(air.inst_index)) |name_vi| unused: { + defer name_vi.value.deref(isel); + var ptr_part_it = name_vi.value.field(.slice_const_u8_sentinel_0, 0, 8); + const ptr_part_vi = try ptr_part_it.only(isel); + const ptr_part_ra = try ptr_part_vi.?.defReg(isel); + var len_part_it = name_vi.value.field(.slice_const_u8_sentinel_0, 8, 8); + const len_part_vi = try len_part_it.only(isel); + const len_part_ra = try len_part_vi.?.defReg(isel); + if (ptr_part_ra == null and len_part_ra == null) break :unused; + + const un_op = air.data(air.inst_index).un_op; + const err_vi = try isel.use(un_op); + const err_mat = try err_vi.matReg(isel); + const ptr_ra = try isel.allocIntReg(); + defer isel.freeReg(ptr_ra); + const start_ra, const end_ra = range_ras: { + const name_lock: RegLock = if (len_part_ra != null) if (ptr_part_ra) |name_ptr_ra| + isel.tryLockReg(name_ptr_ra) + else + .empty else .empty; + defer name_lock.unlock(isel); + break :range_ras .{ try isel.allocIntReg(), try isel.allocIntReg() }; + }; + defer { + isel.freeReg(start_ra); + isel.freeReg(end_ra); + } + if (len_part_ra) |name_len_ra| try isel.emit(.sub( + name_len_ra.w(), + end_ra.w(), + .{ .register = start_ra.w() }, + )); + if (ptr_part_ra) |name_ptr_ra| try isel.emit(.add( + name_ptr_ra.x(), + ptr_ra.x(), + .{ .extended_register = .{ + .register = start_ra.w(), + .extend = .{ .uxtw = 0 }, + } }, + )); + if (len_part_ra) |_| try isel.emit(.sub(end_ra.w(), end_ra.w(), .{ .immediate = 1 })); + try isel.emit(.ldp(start_ra.w(), end_ra.w(), .{ .base = start_ra.x() })); + try isel.emit(.add(start_ra.x(), ptr_ra.x(), .{ .extended_register = .{ + .register = err_mat.ra.w(), + .extend = switch (zcu.errorSetBits()) { + else => unreachable, + 1...8 => .{ .uxtb = 2 }, + 9...16 => .{ .uxth = 2 }, + 17...32 => .{ .uxtw = 2 }, + }, + } })); + try isel.lazy_relocs.append(gpa, .{ + .symbol = .{ .kind = .const_data, .ty = .anyerror_type }, + .reloc = .{ .label = @intCast(isel.instructions.items.len) }, + }); + try isel.emit(.add(ptr_ra.x(), ptr_ra.x(), .{ .immediate = 0 })); + try isel.lazy_relocs.append(gpa, .{ + .symbol = .{ .kind = .const_data, .ty = .anyerror_type }, + .reloc = .{ .label = @intCast(isel.instructions.items.len) }, + }); + try isel.emit(.adrp(ptr_ra.x(), 0)); + try err_mat.finish(isel); + } + if (air.next()) |next_air_tag| continue :air_tag next_air_tag; + }, .aggregate_init => { if (isel.live_values.fetchRemove(air.inst_index)) |agg_vi| { defer agg_vi.value.deref(isel); @@ -6362,7 +6689,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void { try call.prepareCallee(isel); try isel.global_relocs.append(gpa, .{ - .global = "memcpy", + .name = "memcpy", .reloc = .{ .label = @intCast(isel.instructions.items.len) }, }); try isel.emit(.bl(0)); @@ -6478,7 +6805,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void { try call.prepareCallee(isel); try isel.global_relocs.append(gpa, .{ - .global = switch (bits) { + .name = switch (bits) { else => unreachable, 16 => "__fmah", 32 => "fmaf", @@ -6559,6 +6886,32 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void { } if (air.next()) |next_air_tag| continue :air_tag next_air_tag; }, + .cmp_lt_errors_len => { + if (isel.live_values.fetchRemove(air.inst_index)) |is_vi| unused: { + defer is_vi.value.deref(isel); + const is_ra = try is_vi.value.defReg(isel) orelse break :unused; + try isel.emit(.csinc(is_ra.w(), .wzr, .wzr, .invert(.ls))); + + const un_op = air.data(air.inst_index).un_op; + const err_vi = try isel.use(un_op); + const err_mat = try err_vi.matReg(isel); + const ptr_ra = try isel.allocIntReg(); + defer isel.freeReg(ptr_ra); + try isel.emit(.subs(.wzr, err_mat.ra.w(), .{ .register = ptr_ra.w() })); + try isel.lazy_relocs.append(gpa, .{ + .symbol = .{ .kind = .const_data, .ty = .anyerror_type }, + .reloc = .{ .label = @intCast(isel.instructions.items.len) }, + }); + try isel.emit(.ldr(ptr_ra.w(), .{ .base = ptr_ra.x() })); + try isel.lazy_relocs.append(gpa, .{ + .symbol = .{ .kind = .const_data, .ty = .anyerror_type }, + .reloc = .{ .label = @intCast(isel.instructions.items.len) }, + }); + try isel.emit(.adrp(ptr_ra.x(), 0)); + try err_mat.finish(isel); + } + if (air.next()) |next_air_tag| continue :air_tag next_air_tag; + }, .runtime_nav_ptr => { if (isel.live_values.fetchRemove(air.inst_index)) |ptr_vi| unused: { defer ptr_vi.value.deref(isel); @@ -6567,19 +6920,19 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void { const ty_nav = air.data(air.inst_index).ty_nav; if (ZigType.fromInterned(ip.getNav(ty_nav.nav).typeOf(ip)).isFnOrHasRuntimeBits(zcu)) switch (true) { false => { - try isel.nav_relocs.append(zcu.gpa, .{ + try isel.nav_relocs.append(gpa, .{ .nav = ty_nav.nav, .reloc = .{ .label = @intCast(isel.instructions.items.len) }, }); try isel.emit(.adr(ptr_ra.x(), 0)); }, true => { - try isel.nav_relocs.append(zcu.gpa, .{ + try isel.nav_relocs.append(gpa, .{ .nav = ty_nav.nav, .reloc = .{ .label = @intCast(isel.instructions.items.len) }, }); try isel.emit(.add(ptr_ra.x(), ptr_ra.x(), .{ .immediate = 0 })); - try isel.nav_relocs.append(zcu.gpa, .{ + try isel.nav_relocs.append(gpa, .{ .nav = ty_nav.nav, .reloc = .{ .label = @intCast(isel.instructions.items.len) }, }); @@ -6589,9 +6942,6 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void { } if (air.next()) |next_air_tag| continue :air_tag next_air_tag; }, - .add_safe, - .sub_safe, - .mul_safe, .inferred_alloc, .inferred_alloc_comptime, .int_from_float_safe, @@ -6822,6 +7172,9 @@ pub fn layout( saves_len += 1; saves_size += 8; deferred_gr = null; + } else switch (@as(u1, @truncate(saved_gra_len))) { + 0 => {}, + 1 => saves_size += 8, } save_ra = if (mod.strip) incoming.ngrn else CallAbiIterator.ngrn_start; while (save_ra != if (have_va) CallAbiIterator.ngrn_end else incoming.ngrn) : (save_ra = @enumFromInt(@intFromEnum(save_ra) + 1)) { @@ -6844,42 +7197,42 @@ pub fn layout( { wip_mir_log.debug("{f}:", .{nav.fqn.fmt(ip)}); var save_index: usize = 0; - while (save_index < saves.len) { - if (save_index + 2 <= saves.len and saves[save_index + 0].class == saves[save_index + 1].class and - saves[save_index + 0].offset + saves[save_index + 0].size == saves[save_index + 1].offset) - { - try isel.emit(.stp( - saves[save_index + 0].register, - saves[save_index + 1].register, - switch (saves[save_index + 0].offset) { - 0 => .{ .pre_index = .{ - .base = .sp, - .index = @intCast(-@as(i11, saves_size)), - } }, - else => |offset| .{ .signed_offset = .{ - .base = .sp, - .offset = @intCast(offset), - } }, - }, - )); - save_index += 2; - } else { - try isel.emit(.str( - saves[save_index].register, - switch (saves[save_index].offset) { - 0 => .{ .pre_index = .{ - .base = .sp, - .index = @intCast(-@as(i11, saves_size)), - } }, - else => |offset| .{ .unsigned_offset = .{ - .base = .sp, - .offset = @intCast(offset), - } }, - }, - )); - save_index += 1; - } - } + while (save_index < saves.len) if (save_index + 2 <= saves.len and + saves[save_index + 0].class == saves[save_index + 1].class and + saves[save_index + 0].size == saves[save_index + 1].size and + saves[save_index + 0].offset + saves[save_index + 0].size == saves[save_index + 1].offset) + { + try isel.emit(.stp( + saves[save_index + 0].register, + saves[save_index + 1].register, + switch (saves[save_index + 0].offset) { + 0 => .{ .pre_index = .{ + .base = .sp, + .index = @intCast(-@as(i11, saves_size)), + } }, + else => |offset| .{ .signed_offset = .{ + .base = .sp, + .offset = @intCast(offset), + } }, + }, + )); + save_index += 2; + } else { + try isel.emit(.str( + saves[save_index].register, + switch (saves[save_index].offset) { + 0 => .{ .pre_index = .{ + .base = .sp, + .index = @intCast(-@as(i11, saves_size)), + } }, + else => |offset| .{ .unsigned_offset = .{ + .base = .sp, + .offset = @intCast(offset), + } }, + }, + )); + save_index += 1; + }; try isel.emit(.add(.fp, .sp, .{ .immediate = frame_record_offset })); const scratch_reg: Register = if (isel.stack_align == .@"16") @@ -7053,11 +7406,43 @@ fn fmtConstant(isel: *Select, constant: Constant) @typeInfo(@TypeOf(Constant.fmt return constant.fmtValue(isel.pt); } +fn block( + isel: *Select, + air_inst_index: Air.Inst.Index, + res_ty: ZigType, + air_body: []const Air.Inst.Index, +) !void { + if (res_ty.toIntern() != .noreturn_type) { + isel.blocks.putAssumeCapacityNoClobber(air_inst_index, .{ + .live_registers = isel.live_registers, + .target_label = @intCast(isel.instructions.items.len), + }); + } + try isel.body(air_body); + if (res_ty.toIntern() != .noreturn_type) { + const block_entry = isel.blocks.pop().?; + assert(block_entry.key == air_inst_index); + if (isel.live_values.fetchRemove(air_inst_index)) |result_vi| result_vi.value.deref(isel); + } +} + fn emit(isel: *Select, instruction: codegen.aarch64.encoding.Instruction) !void { wip_mir_log.debug(" | {f}", .{instruction}); try isel.instructions.append(isel.pt.zcu.gpa, instruction); } +fn emitPanic(isel: *Select, panic_id: Zcu.SimplePanicId) !void { + const zcu = isel.pt.zcu; + try isel.nav_relocs.append(zcu.gpa, .{ + .nav = switch (zcu.intern_pool.indexToKey(zcu.builtin_decl_values.get(panic_id.toBuiltin()))) { + else => unreachable, + inline .@"extern", .func => |func| func.owner_nav, + }, + .reloc = .{ .label = @intCast(isel.instructions.items.len) }, + }); + try isel.emit(.bl(0)); +} + fn emitLiteral(isel: *Select, bytes: []const u8) !void { const words: []align(1) const u32 = @ptrCast(bytes); const literals = try isel.literals.addManyAsSlice(isel.pt.zcu.gpa, words.len); @@ -8104,6 +8489,32 @@ pub const Value = struct { } } + const AddOrSubtractOptions = struct { + overflow: Overflow, + + const Overflow = union(enum) { + @"unreachable", + panic: Zcu.SimplePanicId, + wrap, + ra: Register.Alias, + + fn defCond(overflow: Overflow, isel: *Select, cond: codegen.aarch64.encoding.ConditionCode) !void { + switch (overflow) { + .@"unreachable" => unreachable, + .panic => |panic_id| { + const skip_label = isel.instructions.items.len; + try isel.emitPanic(panic_id); + try isel.emit(.@"b."( + cond.invert(), + @intCast((isel.instructions.items.len + 1 - skip_label) << 2), + )); + }, + .wrap => {}, + .ra => |overflow_ra| try isel.emit(.csinc(overflow_ra.w(), .wzr, .wzr, cond.invert())), + } + } + }; + }; fn addOrSubtract( res_vi: Value.Index, isel: *Select, @@ -8111,19 +8522,21 @@ pub const Value = struct { lhs_vi: Value.Index, op: codegen.aarch64.encoding.Instruction.AddSubtractOp, rhs_vi: Value.Index, - opts: struct { - wrap: bool, - overflow_ra: Register.Alias = .zr, - }, + opts: AddOrSubtractOptions, ) !void { - assert(opts.wrap or opts.overflow_ra == .zr); const zcu = isel.pt.zcu; if (!ty.isAbiInt(zcu)) return isel.fail("bad {s} {f}", .{ @tagName(op), isel.fmtType(ty) }); const int_info = ty.intInfo(zcu); if (int_info.bits > 128) return isel.fail("too big {s} {f}", .{ @tagName(op), isel.fmtType(ty) }); var part_offset = res_vi.size(isel); - var need_wrap = opts.wrap; - var need_carry = opts.overflow_ra != .zr; + var need_wrap = switch (opts.overflow) { + .@"unreachable" => false, + .panic, .wrap, .ra => true, + }; + var need_carry = switch (opts.overflow) { + .@"unreachable", .wrap => false, + .panic, .ra => true, + }; while (part_offset > 0) : (need_wrap = false) { const part_size = @min(part_offset, 8); part_offset -= part_size; @@ -8133,48 +8546,87 @@ pub const Value = struct { const unwrapped_res_part_ra = unwrapped_res_part_ra: { if (!need_wrap) break :unwrapped_res_part_ra wrapped_res_part_ra; if (int_info.bits % 32 == 0) { - if (opts.overflow_ra != .zr) try isel.emit(.csinc(opts.overflow_ra.w(), .wzr, .wzr, .invert(switch (int_info.signedness) { + try opts.overflow.defCond(isel, switch (int_info.signedness) { .signed => .vs, .unsigned => switch (op) { .add => .cs, .sub => .cc, }, - }))); + }); break :unwrapped_res_part_ra wrapped_res_part_ra; } - const wrapped_part_ra, const unwrapped_part_ra = if (opts.overflow_ra != .zr) part_ra: { - switch (op) { - .add => {}, - .sub => switch (int_info.signedness) { - .signed => {}, - .unsigned => { - try isel.emit(.csinc(opts.overflow_ra.w(), .wzr, .wzr, .invert(.cc))); - break :part_ra .{ wrapped_res_part_ra, wrapped_res_part_ra }; - }, + need_carry = false; + const wrapped_part_ra, const unwrapped_part_ra = part_ra: switch (opts.overflow) { + .@"unreachable" => unreachable, + .panic, .ra => switch (int_info.signedness) { + .signed => { + try opts.overflow.defCond(isel, .ne); + const wrapped_part_ra = switch (wrapped_res_part_ra) { + else => |res_part_ra| res_part_ra, + .zr => try isel.allocIntReg(), + }; + errdefer if (wrapped_part_ra != wrapped_res_part_ra) isel.freeReg(wrapped_part_ra); + const unwrapped_part_ra = unwrapped_part_ra: { + const wrapped_res_part_lock: RegLock = switch (wrapped_res_part_ra) { + else => |res_part_ra| isel.lockReg(res_part_ra), + .zr => .empty, + }; + defer wrapped_res_part_lock.unlock(isel); + break :unwrapped_part_ra try isel.allocIntReg(); + }; + errdefer isel.freeReg(unwrapped_part_ra); + switch (part_size) { + else => unreachable, + 1...4 => try isel.emit(.subs(.wzr, wrapped_part_ra.w(), .{ .register = unwrapped_part_ra.w() })), + 5...8 => try isel.emit(.subs(.xzr, wrapped_part_ra.x(), .{ .register = unwrapped_part_ra.x() })), + } + break :part_ra .{ wrapped_part_ra, unwrapped_part_ra }; }, - } - try isel.emit(.csinc(opts.overflow_ra.w(), .wzr, .wzr, .invert(.ne))); - const wrapped_part_ra = switch (wrapped_res_part_ra) { - else => |res_part_ra| res_part_ra, - .zr => try isel.allocIntReg(), - }; - errdefer if (wrapped_part_ra != wrapped_res_part_ra) isel.freeReg(wrapped_part_ra); - const unwrapped_part_ra = unwrapped_part_ra: { - const wrapped_res_part_lock: RegLock = switch (wrapped_res_part_ra) { - else => |res_part_ra| isel.lockReg(res_part_ra), - .zr => .empty, - }; - defer wrapped_res_part_lock.unlock(isel); - break :unwrapped_part_ra try isel.allocIntReg(); - }; - errdefer isel.freeReg(unwrapped_part_ra); - switch (part_size) { - else => unreachable, - 1...4 => try isel.emit(.subs(.wzr, wrapped_part_ra.w(), .{ .register = unwrapped_part_ra.w() })), - 5...8 => try isel.emit(.subs(.xzr, wrapped_part_ra.x(), .{ .register = unwrapped_part_ra.x() })), - } - break :part_ra .{ wrapped_part_ra, unwrapped_part_ra }; - } else .{ wrapped_res_part_ra, wrapped_res_part_ra }; + .unsigned => { + const unwrapped_part_ra = unwrapped_part_ra: { + const wrapped_res_part_lock: RegLock = switch (wrapped_res_part_ra) { + else => |res_part_ra| isel.lockReg(res_part_ra), + .zr => .empty, + }; + defer wrapped_res_part_lock.unlock(isel); + break :unwrapped_part_ra try isel.allocIntReg(); + }; + errdefer isel.freeReg(unwrapped_part_ra); + const bit: u6 = @truncate(int_info.bits); + switch (opts.overflow) { + .@"unreachable", .wrap => unreachable, + .panic => |panic_id| { + const skip_label = isel.instructions.items.len; + try isel.emitPanic(panic_id); + try isel.emit(.tbz( + switch (bit) { + 0, 32 => unreachable, + 1...31 => unwrapped_part_ra.w(), + 33...63 => unwrapped_part_ra.x(), + }, + bit, + @intCast((isel.instructions.items.len + 1 - skip_label) << 2), + )); + }, + .ra => |overflow_ra| try isel.emit(switch (bit) { + 0, 32 => unreachable, + 1...31 => .ubfm(overflow_ra.w(), unwrapped_part_ra.w(), .{ + .N = .word, + .immr = bit, + .imms = bit, + }), + 33...63 => .ubfm(overflow_ra.x(), unwrapped_part_ra.x(), .{ + .N = .doubleword, + .immr = bit, + .imms = bit, + }), + }), + } + break :part_ra .{ wrapped_res_part_ra, unwrapped_part_ra }; + }, + }, + .wrap => .{ wrapped_res_part_ra, wrapped_res_part_ra }, + }; defer if (wrapped_part_ra != wrapped_res_part_ra) isel.freeReg(wrapped_part_ra); errdefer if (unwrapped_part_ra != wrapped_res_part_ra) isel.freeReg(unwrapped_part_ra); if (wrapped_part_ra != .zr) try isel.emit(switch (part_size) { @@ -8650,41 +9102,15 @@ pub const Value = struct { expected_live_registers: *const LiveRegisters, ) !void { try vi.liveIn(isel, src_ra, expected_live_registers); - const offset_from_parent: i65, const parent_vi = vi.valueParent(isel); + const offset_from_parent, const parent_vi = vi.valueParent(isel); switch (parent_vi.parent(isel)) { .unallocated => {}, - .stack_slot => |stack_slot| { - const offset = stack_slot.offset + offset_from_parent; - try isel.emit(switch (vi.size(isel)) { - else => unreachable, - 1 => if (src_ra.isVector()) .str(src_ra.b(), .{ .unsigned_offset = .{ - .base = stack_slot.base.x(), - .offset = @intCast(offset), - } }) else .strb(src_ra.w(), .{ .unsigned_offset = .{ - .base = stack_slot.base.x(), - .offset = @intCast(offset), - } }), - 2 => if (src_ra.isVector()) .str(src_ra.h(), .{ .unsigned_offset = .{ - .base = stack_slot.base.x(), - .offset = @intCast(offset), - } }) else .strh(src_ra.w(), .{ .unsigned_offset = .{ - .base = stack_slot.base.x(), - .offset = @intCast(offset), - } }), - 4 => .str(if (src_ra.isVector()) src_ra.s() else src_ra.w(), .{ .unsigned_offset = .{ - .base = stack_slot.base.x(), - .offset = @intCast(offset), - } }), - 8 => .str(if (src_ra.isVector()) src_ra.d() else src_ra.x(), .{ .unsigned_offset = .{ - .base = stack_slot.base.x(), - .offset = @intCast(offset), - } }), - 16 => .str(src_ra.q(), .{ .unsigned_offset = .{ - .base = stack_slot.base.x(), - .offset = @intCast(offset), - } }), - }); - }, + .stack_slot => |stack_slot| if (stack_slot.base != Register.Alias.fp) try isel.storeReg( + src_ra, + vi.size(isel), + stack_slot.base, + @as(i65, stack_slot.offset) + offset_from_parent, + ), else => unreachable, } try vi.spillReg(isel, src_ra, 0, expected_live_registers); @@ -9631,14 +10057,18 @@ pub const Value = struct { var base_ptr = ip.indexToKey(base).ptr; const eu_ty = ip.indexToKey(base_ptr.ty).ptr_type.child; const payload_ty = ip.indexToKey(eu_ty).error_union_type.payload_type; - base_ptr.byte_offset += codegen.errUnionPayloadOffset(.fromInterned(payload_ty), zcu); + base_ptr.byte_offset += codegen.errUnionPayloadOffset(.fromInterned(payload_ty), zcu) + ptr.byte_offset; + continue :constant_key .{ .ptr = base_ptr }; + }, + .opt_payload => |base| { + var base_ptr = ip.indexToKey(base).ptr; + base_ptr.byte_offset += ptr.byte_offset; continue :constant_key .{ .ptr = base_ptr }; }, - .opt_payload => |base| continue :constant_key .{ .ptr = ip.indexToKey(base).ptr }, .field => |field| { var base_ptr = ip.indexToKey(field.base).ptr; const agg_ty: ZigType = .fromInterned(ip.indexToKey(base_ptr.ty).ptr_type.child); - base_ptr.byte_offset += agg_ty.structFieldOffset(@intCast(field.index), zcu); + base_ptr.byte_offset += agg_ty.structFieldOffset(@intCast(field.index), zcu) + ptr.byte_offset; continue :constant_key .{ .ptr = base_ptr }; }, .comptime_alloc, .comptime_field, .arr_elem => unreachable, diff --git a/src/codegen/aarch64/instructions.zon b/src/codegen/aarch64/instructions.zon index 85de196050..48b8eaa21f 100644 --- a/src/codegen/aarch64/instructions.zon +++ b/src/codegen/aarch64/instructions.zon @@ -213,6 +213,63 @@ }, .encode = .{ .ands, .Xd, .Xn, .{ .shifted_register_explicit = .{ .register = .Xm, .shift = .shift, .amount = .amount } } }, }, + // C6.2.16 ASR (register) + .{ + .pattern = "ASR , , ", + .symbols = .{ + .Wd = .{ .reg = .{ .format = .{ .integer = .word } } }, + .Wn = .{ .reg = .{ .format = .{ .integer = .word } } }, + .Wm = .{ .reg = .{ .format = .{ .integer = .word } } }, + }, + .encode = .{ .asrv, .Wd, .Wn, .Wm }, + }, + .{ + .pattern = "ASR , , ", + .symbols = .{ + .Xd = .{ .reg = .{ .format = .{ .integer = .doubleword } } }, + .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword } } }, + .Xm = .{ .reg = .{ .format = .{ .integer = .doubleword } } }, + }, + .encode = .{ .asrv, .Xd, .Xn, .Xm }, + }, + // C6.2.17 ASR (immediate) + .{ + .pattern = "ASR , , #", + .symbols = .{ + .Wd = .{ .reg = .{ .format = .{ .integer = .word } } }, + .Wn = .{ .reg = .{ .format = .{ .integer = .word } } }, + .shift = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 5 } } }, + }, + .encode = .{ .sbfm, .Wd, .Wn, .{ .N = .word, .immr = .shift, .imms = 31 } }, + }, + .{ + .pattern = "ASR , , #", + .symbols = .{ + .Xd = .{ .reg = .{ .format = .{ .integer = .doubleword } } }, + .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword } } }, + .shift = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 6 } } }, + }, + .encode = .{ .sbfm, .Xd, .Xn, .{ .N = .doubleword, .immr = .shift, .imms = 63 } }, + }, + // C6.2.18 ASRV + .{ + .pattern = "ASRV , , ", + .symbols = .{ + .Wd = .{ .reg = .{ .format = .{ .integer = .word } } }, + .Wn = .{ .reg = .{ .format = .{ .integer = .word } } }, + .Wm = .{ .reg = .{ .format = .{ .integer = .word } } }, + }, + .encode = .{ .asrv, .Wd, .Wn, .Wm }, + }, + .{ + .pattern = "ASRV , , ", + .symbols = .{ + .Xd = .{ .reg = .{ .format = .{ .integer = .doubleword } } }, + .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword } } }, + .Xm = .{ .reg = .{ .format = .{ .integer = .doubleword } } }, + }, + .encode = .{ .asrv, .Xd, .Xn, .Xm }, + }, // C6.2.35 BLR .{ .pattern = "BLR ", @@ -681,6 +738,82 @@ }, .encode = .{ .ldr, .Xt, .{ .unsigned_offset = .{ .base = .Xn, .offset = .pimm } } }, }, + // C6.2.212 LSL (register) + .{ + .pattern = "LSL , , ", + .symbols = .{ + .Wd = .{ .reg = .{ .format = .{ .integer = .word } } }, + .Wn = .{ .reg = .{ .format = .{ .integer = .word } } }, + .Wm = .{ .reg = .{ .format = .{ .integer = .word } } }, + }, + .encode = .{ .lslv, .Wd, .Wn, .Wm }, + }, + .{ + .pattern = "LSL , , ", + .symbols = .{ + .Xd = .{ .reg = .{ .format = .{ .integer = .doubleword } } }, + .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword } } }, + .Xm = .{ .reg = .{ .format = .{ .integer = .doubleword } } }, + }, + .encode = .{ .lslv, .Xd, .Xn, .Xm }, + }, + // C6.2.214 LSLV + .{ + .pattern = "LSLV , , ", + .symbols = .{ + .Wd = .{ .reg = .{ .format = .{ .integer = .word } } }, + .Wn = .{ .reg = .{ .format = .{ .integer = .word } } }, + .Wm = .{ .reg = .{ .format = .{ .integer = .word } } }, + }, + .encode = .{ .lslv, .Wd, .Wn, .Wm }, + }, + .{ + .pattern = "LSLV , , ", + .symbols = .{ + .Xd = .{ .reg = .{ .format = .{ .integer = .doubleword } } }, + .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword } } }, + .Xm = .{ .reg = .{ .format = .{ .integer = .doubleword } } }, + }, + .encode = .{ .lslv, .Xd, .Xn, .Xm }, + }, + // C6.2.215 LSR (register) + .{ + .pattern = "LSR , , ", + .symbols = .{ + .Wd = .{ .reg = .{ .format = .{ .integer = .word } } }, + .Wn = .{ .reg = .{ .format = .{ .integer = .word } } }, + .Wm = .{ .reg = .{ .format = .{ .integer = .word } } }, + }, + .encode = .{ .lsrv, .Wd, .Wn, .Wm }, + }, + .{ + .pattern = "LSR , , ", + .symbols = .{ + .Xd = .{ .reg = .{ .format = .{ .integer = .doubleword } } }, + .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword } } }, + .Xm = .{ .reg = .{ .format = .{ .integer = .doubleword } } }, + }, + .encode = .{ .lsrv, .Xd, .Xn, .Xm }, + }, + // C6.2.217 LSRV + .{ + .pattern = "LSRV , , ", + .symbols = .{ + .Wd = .{ .reg = .{ .format = .{ .integer = .word } } }, + .Wn = .{ .reg = .{ .format = .{ .integer = .word } } }, + .Wm = .{ .reg = .{ .format = .{ .integer = .word } } }, + }, + .encode = .{ .lsrv, .Wd, .Wn, .Wm }, + }, + .{ + .pattern = "LSRV , , ", + .symbols = .{ + .Xd = .{ .reg = .{ .format = .{ .integer = .doubleword } } }, + .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword } } }, + .Xm = .{ .reg = .{ .format = .{ .integer = .doubleword } } }, + }, + .encode = .{ .lsrv, .Xd, .Xn, .Xm }, + }, // C6.2.220 MOV (to/from SP) .{ .pattern = "MOV WSP, ", @@ -964,6 +1097,63 @@ }, .encode = .{ .ret, .Xn }, }, + // C6.2.261 ROR (immediate) + .{ + .pattern = "ROR , , #", + .symbols = .{ + .Wd = .{ .reg = .{ .format = .{ .integer = .word } } }, + .Ws = .{ .reg = .{ .format = .{ .integer = .word } } }, + .shift = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 5 } } }, + }, + .encode = .{ .extr, .Wd, .Ws, .Ws, .shift }, + }, + .{ + .pattern = "ROR , , #", + .symbols = .{ + .Xd = .{ .reg = .{ .format = .{ .integer = .doubleword } } }, + .Xs = .{ .reg = .{ .format = .{ .integer = .doubleword } } }, + .shift = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 6 } } }, + }, + .encode = .{ .extr, .Xd, .Xs, .Xs, .shift }, + }, + // C6.2.262 ROR (register) + .{ + .pattern = "ROR , , ", + .symbols = .{ + .Wd = .{ .reg = .{ .format = .{ .integer = .word } } }, + .Wn = .{ .reg = .{ .format = .{ .integer = .word } } }, + .Wm = .{ .reg = .{ .format = .{ .integer = .word } } }, + }, + .encode = .{ .rorv, .Wd, .Wn, .Wm }, + }, + .{ + .pattern = "ROR , , ", + .symbols = .{ + .Xd = .{ .reg = .{ .format = .{ .integer = .doubleword } } }, + .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword } } }, + .Xm = .{ .reg = .{ .format = .{ .integer = .doubleword } } }, + }, + .encode = .{ .rorv, .Xd, .Xn, .Xm }, + }, + // C6.2.263 RORV + .{ + .pattern = "RORV , , ", + .symbols = .{ + .Wd = .{ .reg = .{ .format = .{ .integer = .word } } }, + .Wn = .{ .reg = .{ .format = .{ .integer = .word } } }, + .Wm = .{ .reg = .{ .format = .{ .integer = .word } } }, + }, + .encode = .{ .rorv, .Wd, .Wn, .Wm }, + }, + .{ + .pattern = "RORV , , ", + .symbols = .{ + .Xd = .{ .reg = .{ .format = .{ .integer = .doubleword } } }, + .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword } } }, + .Xm = .{ .reg = .{ .format = .{ .integer = .doubleword } } }, + }, + .encode = .{ .rorv, .Xd, .Xn, .Xm }, + }, // C6.2.268 SBFM .{ .pattern = "SBFM , , #, #", diff --git a/src/target.zig b/src/target.zig index 5896af7b2a..ad83414c23 100644 --- a/src/target.zig +++ b/src/target.zig @@ -351,7 +351,7 @@ pub fn defaultCompilerRtOptimizeMode(target: *const std.Target) std.builtin.Opti } } -pub fn canBuildLibCompilerRt(target: *const std.Target, use_llvm: bool, comptime have_llvm: bool) bool { +pub fn canBuildLibCompilerRt(target: *const std.Target, use_llvm: bool, have_llvm: bool) bool { switch (target.os.tag) { .plan9 => return false, else => {}, @@ -373,7 +373,7 @@ pub fn canBuildLibCompilerRt(target: *const std.Target, use_llvm: bool, comptime }; } -pub fn canBuildLibUbsanRt(target: *const std.Target, use_llvm: bool, comptime have_llvm: bool) bool { +pub fn canBuildLibUbsanRt(target: *const std.Target, use_llvm: bool, have_llvm: bool) bool { switch (target.cpu.arch) { .spirv32, .spirv64 => return false, // Remove this once https://github.com/ziglang/zig/issues/23715 is fixed @@ -382,6 +382,7 @@ pub fn canBuildLibUbsanRt(target: *const std.Target, use_llvm: bool, comptime ha } return switch (zigBackend(target, use_llvm)) { .stage2_llvm => true, + .stage2_wasm => false, .stage2_x86_64 => switch (target.ofmt) { .elf, .macho => true, else => have_llvm, @@ -860,6 +861,7 @@ pub fn zigBackend(target: *const std.Target, use_llvm: bool) std.builtin.Compile pub inline fn backendSupportsFeature(backend: std.builtin.CompilerBackend, comptime feature: Feature) bool { return switch (feature) { .panic_fn => switch (backend) { + .stage2_aarch64, .stage2_c, .stage2_llvm, .stage2_x86_64, diff --git a/test/behavior/error.zig b/test/behavior/error.zig index eff2cf855f..4665178808 100644 --- a/test/behavior/error.zig +++ b/test/behavior/error.zig @@ -590,7 +590,6 @@ test "error union comptime caching" { } test "@errorName" { - if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; @@ -605,7 +604,6 @@ fn gimmeItBroke() anyerror { } test "@errorName sentinel length matches slice length" { - if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; @@ -883,7 +881,6 @@ test "catch within a function that calls no errorable functions" { } test "error from comptime string" { - 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/return_address.zig b/test/behavior/return_address.zig index ba342956b3..d7fb76d3b0 100644 --- a/test/behavior/return_address.zig +++ b/test/behavior/return_address.zig @@ -6,7 +6,6 @@ fn retAddr() usize { } test "return address" { - 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/cases/array_in_anon_struct.zig b/test/cases/array_in_anon_struct.zig index 5961b3f723..8c4f5ea051 100644 --- a/test/cases/array_in_anon_struct.zig +++ b/test/cases/array_in_anon_struct.zig @@ -19,4 +19,4 @@ pub fn main() !void { // run // backend=stage2,llvm -// target=native +// target=x86_64-linux,aarch64-linux diff --git a/test/cases/compile_errors/callconv_interrupt_on_unsupported_platform.zig b/test/cases/compile_errors/callconv_interrupt_on_unsupported_platform.zig index 8bbc3154a1..5f42b7d9af 100644 --- a/test/cases/compile_errors/callconv_interrupt_on_unsupported_platform.zig +++ b/test/cases/compile_errors/callconv_interrupt_on_unsupported_platform.zig @@ -7,5 +7,5 @@ export fn entry3() callconv(.avr_interrupt) void {} // target=aarch64-linux-none // // :1:30: error: calling convention 'x86_64_interrupt' only available on architectures 'x86_64' -// :1:30: error: calling convention 'x86_interrupt' only available on architectures 'x86' -// :1:30: error: calling convention 'avr_interrupt' only available on architectures 'avr' +// :2:30: error: calling convention 'x86_interrupt' only available on architectures 'x86' +// :3:30: error: calling convention 'avr_interrupt' only available on architectures 'avr' diff --git a/test/cases/compile_errors/error_set_membership.zig b/test/cases/compile_errors/error_set_membership.zig index 67826f4db9..a146bd39ba 100644 --- a/test/cases/compile_errors/error_set_membership.zig +++ b/test/cases/compile_errors/error_set_membership.zig @@ -25,7 +25,7 @@ pub fn main() Error!void { // error // backend=stage2 -// target=native +// target=x86_64-linux // // :23:29: error: expected type 'error{InvalidCharacter}', found '@typeInfo(@typeInfo(@TypeOf(tmp.fooey)).@"fn".return_type.?).error_union.error_set' // :23:29: note: 'error.InvalidDirection' not a member of destination error set diff --git a/test/cases/compile_errors/function_ptr_alignment.zig b/test/cases/compile_errors/function_ptr_alignment.zig index cf97e61f40..fd8aec06d0 100644 --- a/test/cases/compile_errors/function_ptr_alignment.zig +++ b/test/cases/compile_errors/function_ptr_alignment.zig @@ -10,7 +10,7 @@ comptime { // error // backend=stage2 -// target=native +// target=x86_64-linux // // :8:41: error: expected type '*align(2) const fn () void', found '*const fn () void' // :8:41: note: pointer alignment '1' cannot cast into pointer alignment '2' diff --git a/test/cases/compile_errors/issue_15572_break_on_inline_while.zig b/test/cases/compile_errors/issue_15572_break_on_inline_while.zig index f264e695c0..69d5c11eab 100644 --- a/test/cases/compile_errors/issue_15572_break_on_inline_while.zig +++ b/test/cases/compile_errors/issue_15572_break_on_inline_while.zig @@ -15,6 +15,6 @@ pub fn main() void { // error // backend=stage2 -// target=native +// target=x86_64-linux // // :9:28: error: incompatible types: 'builtin.Type.EnumField' and 'void' diff --git a/test/cases/compile_errors/switch_on_non_err_union.zig b/test/cases/compile_errors/switch_on_non_err_union.zig index 87624b21dc..e79a181e62 100644 --- a/test/cases/compile_errors/switch_on_non_err_union.zig +++ b/test/cases/compile_errors/switch_on_non_err_union.zig @@ -6,6 +6,6 @@ pub fn main() void { // error // backend=stage2 -// target=native +// target=x86_64-linux // // :2:23: error: expected error union type, found 'bool' diff --git a/test/cases/pic_freestanding.zig b/test/cases/pic_freestanding.zig index 86e37662e2..eda1399887 100644 --- a/test/cases/pic_freestanding.zig +++ b/test/cases/pic_freestanding.zig @@ -1,7 +1,7 @@ const builtin = @import("builtin"); const std = @import("std"); -fn _start() callconv(.naked) void {} +pub fn _start() callconv(.naked) void {} comptime { @export(&_start, .{ .name = if (builtin.cpu.arch.isMIPS()) "__start" else "_start" }); diff --git a/test/cases/safety/@alignCast misaligned.zig b/test/cases/safety/@alignCast misaligned.zig index e523a9d120..017c46a98d 100644 --- a/test/cases/safety/@alignCast misaligned.zig +++ b/test/cases/safety/@alignCast misaligned.zig @@ -22,4 +22,4 @@ fn foo(bytes: []u8) u32 { } // run // backend=stage2,llvm -// target=native +// target=x86_64-linux,aarch64-linux diff --git a/test/cases/safety/@enumFromInt - no matching tag value.zig b/test/cases/safety/@enumFromInt - no matching tag value.zig index 0021a4d397..7953b93358 100644 --- a/test/cases/safety/@enumFromInt - no matching tag value.zig +++ b/test/cases/safety/@enumFromInt - no matching tag value.zig @@ -23,4 +23,4 @@ fn baz(_: Foo) void {} // run // backend=stage2,llvm -// target=native +// target=x86_64-linux diff --git a/test/cases/safety/@enumFromInt truncated bits - exhaustive.zig b/test/cases/safety/@enumFromInt truncated bits - exhaustive.zig index 92065c4892..ace1e08d11 100644 --- a/test/cases/safety/@enumFromInt truncated bits - exhaustive.zig +++ b/test/cases/safety/@enumFromInt truncated bits - exhaustive.zig @@ -20,4 +20,4 @@ pub fn main() u8 { // run // backend=stage2,llvm -// target=native +// target=x86_64-linux diff --git a/test/cases/safety/@enumFromInt truncated bits - nonexhaustive.zig b/test/cases/safety/@enumFromInt truncated bits - nonexhaustive.zig index 25959c9ffd..8f20081610 100644 --- a/test/cases/safety/@enumFromInt truncated bits - nonexhaustive.zig +++ b/test/cases/safety/@enumFromInt truncated bits - nonexhaustive.zig @@ -20,4 +20,4 @@ pub fn main() u8 { // run // backend=stage2,llvm -// target=native +// target=x86_64-linux diff --git a/test/cases/safety/@errorCast error not present in destination.zig b/test/cases/safety/@errorCast error not present in destination.zig index 74e81f2a60..a121d3e6e8 100644 --- a/test/cases/safety/@errorCast error not present in destination.zig +++ b/test/cases/safety/@errorCast error not present in destination.zig @@ -18,4 +18,4 @@ fn foo(set1: Set1) Set2 { } // run // backend=stage2,llvm -// target=native +// target=x86_64-linux diff --git a/test/cases/safety/@errorCast error union casted to disjoint set.zig b/test/cases/safety/@errorCast error union casted to disjoint set.zig index 2696a037c7..a84f61d8e5 100644 --- a/test/cases/safety/@errorCast error union casted to disjoint set.zig +++ b/test/cases/safety/@errorCast error union casted to disjoint set.zig @@ -17,4 +17,4 @@ fn foo() anyerror!i32 { } // run // backend=stage2,llvm -// target=native +// target=x86_64-linux diff --git a/test/cases/safety/@intCast to u0.zig b/test/cases/safety/@intCast to u0.zig index 4394f63f54..219f42f213 100644 --- a/test/cases/safety/@intCast to u0.zig +++ b/test/cases/safety/@intCast to u0.zig @@ -19,4 +19,4 @@ fn bar(one: u1, not_zero: i32) void { } // run // backend=stage2,llvm -// target=native +// target=x86_64-linux,aarch64-linux diff --git a/test/cases/safety/@intFromFloat cannot fit - boundary case - i0 max.zig b/test/cases/safety/@intFromFloat cannot fit - boundary case - i0 max.zig index 38ec595b45..70f0cebb93 100644 --- a/test/cases/safety/@intFromFloat cannot fit - boundary case - i0 max.zig +++ b/test/cases/safety/@intFromFloat cannot fit - boundary case - i0 max.zig @@ -13,4 +13,4 @@ pub fn main() !void { } // run // backend=stage2,llvm -// target=native +// target=x86_64-linux,aarch64-linux diff --git a/test/cases/safety/@intFromFloat cannot fit - boundary case - i0 min.zig b/test/cases/safety/@intFromFloat cannot fit - boundary case - i0 min.zig index 97a651855b..bc35aa6e23 100644 --- a/test/cases/safety/@intFromFloat cannot fit - boundary case - i0 min.zig +++ b/test/cases/safety/@intFromFloat cannot fit - boundary case - i0 min.zig @@ -13,4 +13,4 @@ pub fn main() !void { } // run // backend=stage2,llvm -// target=native +// target=x86_64-linux,aarch64-linux diff --git a/test/cases/safety/@intFromFloat cannot fit - boundary case - signed max.zig b/test/cases/safety/@intFromFloat cannot fit - boundary case - signed max.zig index cc19ee84ff..56e87423a1 100644 --- a/test/cases/safety/@intFromFloat cannot fit - boundary case - signed max.zig +++ b/test/cases/safety/@intFromFloat cannot fit - boundary case - signed max.zig @@ -13,4 +13,4 @@ pub fn main() !void { } // run // backend=stage2,llvm -// target=native +// target=x86_64-linux diff --git a/test/cases/safety/@intFromFloat cannot fit - boundary case - signed min.zig b/test/cases/safety/@intFromFloat cannot fit - boundary case - signed min.zig index abc95e396a..61704a8733 100644 --- a/test/cases/safety/@intFromFloat cannot fit - boundary case - signed min.zig +++ b/test/cases/safety/@intFromFloat cannot fit - boundary case - signed min.zig @@ -13,4 +13,4 @@ pub fn main() !void { } // run // backend=stage2,llvm -// target=native +// target=x86_64-linux diff --git a/test/cases/safety/@intFromFloat cannot fit - boundary case - u0 max.zig b/test/cases/safety/@intFromFloat cannot fit - boundary case - u0 max.zig index f488d0291f..361a528498 100644 --- a/test/cases/safety/@intFromFloat cannot fit - boundary case - u0 max.zig +++ b/test/cases/safety/@intFromFloat cannot fit - boundary case - u0 max.zig @@ -13,4 +13,4 @@ pub fn main() !void { } // run // backend=stage2,llvm -// target=native +// target=x86_64-linux,aarch64-linux diff --git a/test/cases/safety/@intFromFloat cannot fit - boundary case - u0 min.zig b/test/cases/safety/@intFromFloat cannot fit - boundary case - u0 min.zig index 8d459e1a5c..5706d192d5 100644 --- a/test/cases/safety/@intFromFloat cannot fit - boundary case - u0 min.zig +++ b/test/cases/safety/@intFromFloat cannot fit - boundary case - u0 min.zig @@ -13,4 +13,4 @@ pub fn main() !void { } // run // backend=stage2,llvm -// target=native +// target=x86_64-linux,aarch64-linux diff --git a/test/cases/safety/@intFromFloat cannot fit - boundary case - unsigned max.zig b/test/cases/safety/@intFromFloat cannot fit - boundary case - unsigned max.zig index 95122abc8c..842aaaa1de 100644 --- a/test/cases/safety/@intFromFloat cannot fit - boundary case - unsigned max.zig +++ b/test/cases/safety/@intFromFloat cannot fit - boundary case - unsigned max.zig @@ -13,4 +13,4 @@ pub fn main() !void { } // run // backend=stage2,llvm -// target=native +// target=x86_64-linux diff --git a/test/cases/safety/@intFromFloat cannot fit - boundary case - unsigned min.zig b/test/cases/safety/@intFromFloat cannot fit - boundary case - unsigned min.zig index fbc7cf18ac..c1e8af2f5e 100644 --- a/test/cases/safety/@intFromFloat cannot fit - boundary case - unsigned min.zig +++ b/test/cases/safety/@intFromFloat cannot fit - boundary case - unsigned min.zig @@ -13,4 +13,4 @@ pub fn main() !void { } // run // backend=stage2,llvm -// target=native +// target=x86_64-linux diff --git a/test/cases/safety/@intFromFloat cannot fit - boundary case - vector max.zig b/test/cases/safety/@intFromFloat cannot fit - boundary case - vector max.zig index 35b4c91509..96e1c5594e 100644 --- a/test/cases/safety/@intFromFloat cannot fit - boundary case - vector max.zig +++ b/test/cases/safety/@intFromFloat cannot fit - boundary case - vector max.zig @@ -13,4 +13,4 @@ pub fn main() !void { } // run // backend=stage2,llvm -// target=native +// target=x86_64-linux diff --git a/test/cases/safety/@intFromFloat cannot fit - boundary case - vector min.zig b/test/cases/safety/@intFromFloat cannot fit - boundary case - vector min.zig index 94ad509772..cf17014d3f 100644 --- a/test/cases/safety/@intFromFloat cannot fit - boundary case - vector min.zig +++ b/test/cases/safety/@intFromFloat cannot fit - boundary case - vector min.zig @@ -13,4 +13,4 @@ pub fn main() !void { } // run // backend=stage2,llvm -// target=native +// target=x86_64-linux diff --git a/test/cases/safety/@intFromFloat cannot fit - negative out of range.zig b/test/cases/safety/@intFromFloat cannot fit - negative out of range.zig index 80edbdfd3c..23d9f87ac1 100644 --- a/test/cases/safety/@intFromFloat cannot fit - negative out of range.zig +++ b/test/cases/safety/@intFromFloat cannot fit - negative out of range.zig @@ -17,4 +17,4 @@ fn bar(a: f32) i8 { fn baz(_: i8) void {} // run // backend=stage2,llvm -// target=native +// target=x86_64-linux diff --git a/test/cases/safety/@intFromFloat cannot fit - negative to unsigned.zig b/test/cases/safety/@intFromFloat cannot fit - negative to unsigned.zig index ee0c040273..9d28ee0aaa 100644 --- a/test/cases/safety/@intFromFloat cannot fit - negative to unsigned.zig +++ b/test/cases/safety/@intFromFloat cannot fit - negative to unsigned.zig @@ -17,4 +17,4 @@ fn bar(a: f32) u8 { fn baz(_: u8) void {} // run // backend=stage2,llvm -// target=native +// target=x86_64-linux diff --git a/test/cases/safety/@intFromFloat cannot fit - positive out of range.zig b/test/cases/safety/@intFromFloat cannot fit - positive out of range.zig index c526a70047..2e76a9b253 100644 --- a/test/cases/safety/@intFromFloat cannot fit - positive out of range.zig +++ b/test/cases/safety/@intFromFloat cannot fit - positive out of range.zig @@ -17,4 +17,4 @@ fn bar(a: f32) u8 { fn baz(_: u8) void {} // run // backend=stage2,llvm -// target=native +// target=x86_64-linux diff --git a/test/cases/safety/@ptrFromInt address zero to non-optional byte-aligned pointer.zig b/test/cases/safety/@ptrFromInt address zero to non-optional byte-aligned pointer.zig index 4944a239e2..eb45f357dd 100644 --- a/test/cases/safety/@ptrFromInt address zero to non-optional byte-aligned pointer.zig +++ b/test/cases/safety/@ptrFromInt address zero to non-optional byte-aligned pointer.zig @@ -16,4 +16,4 @@ pub fn main() !void { } // run // backend=stage2,llvm -// target=native +// target=x86_64-linux,aarch64-linux diff --git a/test/cases/safety/@ptrFromInt address zero to non-optional pointer.zig b/test/cases/safety/@ptrFromInt address zero to non-optional pointer.zig index a217de3073..308f97ad12 100644 --- a/test/cases/safety/@ptrFromInt address zero to non-optional pointer.zig +++ b/test/cases/safety/@ptrFromInt address zero to non-optional pointer.zig @@ -16,4 +16,4 @@ pub fn main() !void { } // run // backend=stage2,llvm -// target=native +// target=x86_64-linux,aarch64-linux diff --git a/test/cases/safety/@ptrFromInt with misaligned address.zig b/test/cases/safety/@ptrFromInt with misaligned address.zig index b95c1b320f..1383a4c3c3 100644 --- a/test/cases/safety/@ptrFromInt with misaligned address.zig +++ b/test/cases/safety/@ptrFromInt with misaligned address.zig @@ -16,4 +16,4 @@ pub fn main() !void { } // run // backend=stage2,llvm -// target=native +// target=x86_64-linux,aarch64-linux diff --git a/test/cases/safety/@tagName on corrupted enum value.zig b/test/cases/safety/@tagName on corrupted enum value.zig index df6a3f45e0..450d0ee2e0 100644 --- a/test/cases/safety/@tagName on corrupted enum value.zig +++ b/test/cases/safety/@tagName on corrupted enum value.zig @@ -23,4 +23,4 @@ pub fn main() !void { // run // backend=stage2,llvm -// target=native +// target=x86_64-linux diff --git a/test/cases/safety/@tagName on corrupted union value.zig b/test/cases/safety/@tagName on corrupted union value.zig index 7b856e57b9..b61a72420e 100644 --- a/test/cases/safety/@tagName on corrupted union value.zig +++ b/test/cases/safety/@tagName on corrupted union value.zig @@ -24,4 +24,4 @@ pub fn main() !void { // run // backend=stage2,llvm -// target=native +// target=x86_64-linux diff --git a/test/cases/safety/array slice sentinel mismatch vector.zig b/test/cases/safety/array slice sentinel mismatch vector.zig index 55ff4b3e39..f374f1b9d5 100644 --- a/test/cases/safety/array slice sentinel mismatch vector.zig +++ b/test/cases/safety/array slice sentinel mismatch vector.zig @@ -16,4 +16,4 @@ pub fn main() !void { } // run // backend=stage2,llvm -// target=native +// target=x86_64-linux diff --git a/test/cases/safety/array slice sentinel mismatch.zig b/test/cases/safety/array slice sentinel mismatch.zig index ab7a513b39..deb43250ec 100644 --- a/test/cases/safety/array slice sentinel mismatch.zig +++ b/test/cases/safety/array slice sentinel mismatch.zig @@ -16,4 +16,4 @@ pub fn main() !void { } // run // backend=stage2,llvm -// target=native +// target=x86_64-linux,aarch64-linux diff --git a/test/cases/safety/bad union field access.zig b/test/cases/safety/bad union field access.zig index 14ebb1f344..a2778237c4 100644 --- a/test/cases/safety/bad union field access.zig +++ b/test/cases/safety/bad union field access.zig @@ -24,4 +24,4 @@ fn bar(f: *Foo) void { } // run // backend=stage2,llvm -// target=native +// target=x86_64-linux diff --git a/test/cases/safety/calling panic.zig b/test/cases/safety/calling panic.zig index 7b8a478be3..7ac512eadc 100644 --- a/test/cases/safety/calling panic.zig +++ b/test/cases/safety/calling panic.zig @@ -13,4 +13,4 @@ pub fn main() !void { } // run // backend=stage2,llvm -// target=native +// target=x86_64-linux,aarch64-linux diff --git a/test/cases/safety/cast []u8 to bigger slice of wrong size.zig b/test/cases/safety/cast []u8 to bigger slice of wrong size.zig index b6b8e89bf9..65dda78751 100644 --- a/test/cases/safety/cast []u8 to bigger slice of wrong size.zig +++ b/test/cases/safety/cast []u8 to bigger slice of wrong size.zig @@ -18,4 +18,4 @@ fn widenSlice(slice: []align(1) const u8) []align(1) const i32 { } // run // backend=stage2,llvm -// target=native +// target=x86_64-linux,aarch64-linux diff --git a/test/cases/safety/cast integer to global error and no code matches.zig b/test/cases/safety/cast integer to global error and no code matches.zig index fa0474a88c..2b9cadf811 100644 --- a/test/cases/safety/cast integer to global error and no code matches.zig +++ b/test/cases/safety/cast integer to global error and no code matches.zig @@ -16,4 +16,4 @@ fn bar(x: u16) anyerror { } // run // backend=stage2,llvm -// target=native +// target=x86_64-linux,aarch64-linux diff --git a/test/cases/safety/empty slice with sentinel out of bounds.zig b/test/cases/safety/empty slice with sentinel out of bounds.zig index 51846f894f..2d9494826d 100644 --- a/test/cases/safety/empty slice with sentinel out of bounds.zig +++ b/test/cases/safety/empty slice with sentinel out of bounds.zig @@ -18,4 +18,4 @@ pub fn main() !void { // run // backend=stage2,llvm -// target=native +// target=x86_64-linux,aarch64-linux diff --git a/test/cases/safety/exact division failure - vectors.zig b/test/cases/safety/exact division failure - vectors.zig index 30d5dcf11a..398ae7a4cd 100644 --- a/test/cases/safety/exact division failure - vectors.zig +++ b/test/cases/safety/exact division failure - vectors.zig @@ -20,4 +20,4 @@ fn divExact(a: @Vector(4, i32), b: @Vector(4, i32)) @Vector(4, i32) { } // run // backend=stage2,llvm -// target=native +// target=x86_64-linux diff --git a/test/cases/safety/exact division failure.zig b/test/cases/safety/exact division failure.zig index be86853c77..0831bb4e09 100644 --- a/test/cases/safety/exact division failure.zig +++ b/test/cases/safety/exact division failure.zig @@ -18,4 +18,4 @@ fn divExact(a: i32, b: i32) i32 { } // run // backend=stage2,llvm -// target=native +// target=x86_64-linux,aarch64-linux diff --git a/test/cases/safety/for_len_mismatch.zig b/test/cases/safety/for_len_mismatch.zig index 8841f11aa7..55bb7bf8b5 100644 --- a/test/cases/safety/for_len_mismatch.zig +++ b/test/cases/safety/for_len_mismatch.zig @@ -22,4 +22,4 @@ pub fn main() !void { } // run // backend=stage2,llvm -// target=native +// target=x86_64-linux,aarch64-linux diff --git a/test/cases/safety/for_len_mismatch_three.zig b/test/cases/safety/for_len_mismatch_three.zig index 4efe18d3cd..b4256b0eee 100644 --- a/test/cases/safety/for_len_mismatch_three.zig +++ b/test/cases/safety/for_len_mismatch_three.zig @@ -21,4 +21,4 @@ pub fn main() !void { } // run // backend=stage2,llvm -// target=native +// target=x86_64-linux,aarch64-linux diff --git a/test/cases/safety/ignored expression integer overflow.zig b/test/cases/safety/ignored expression integer overflow.zig index 1089010854..859c615e42 100644 --- a/test/cases/safety/ignored expression integer overflow.zig +++ b/test/cases/safety/ignored expression integer overflow.zig @@ -18,4 +18,4 @@ pub fn main() !void { // run // backend=stage2,llvm -// target=native +// target=x86_64-linux diff --git a/test/cases/safety/integer addition overflow.zig b/test/cases/safety/integer addition overflow.zig index 499e8b1015..119800c686 100644 --- a/test/cases/safety/integer addition overflow.zig +++ b/test/cases/safety/integer addition overflow.zig @@ -20,4 +20,4 @@ fn add(a: u16, b: u16) u16 { // run // backend=stage2,llvm -// target=native +// target=x86_64-linux,aarch64-linux diff --git a/test/cases/safety/integer division by zero - vectors.zig b/test/cases/safety/integer division by zero - vectors.zig index 63e77a0dd4..d3ddfa06c6 100644 --- a/test/cases/safety/integer division by zero - vectors.zig +++ b/test/cases/safety/integer division by zero - vectors.zig @@ -19,4 +19,4 @@ fn div0(a: @Vector(4, i32), b: @Vector(4, i32)) @Vector(4, i32) { } // run // backend=stage2,llvm -// target=native +// target=x86_64-linux diff --git a/test/cases/safety/integer division by zero.zig b/test/cases/safety/integer division by zero.zig index e8eba5c4f0..dc12dde343 100644 --- a/test/cases/safety/integer division by zero.zig +++ b/test/cases/safety/integer division by zero.zig @@ -17,4 +17,4 @@ fn div0(a: i32, b: i32) i32 { } // run // backend=stage2,llvm -// target=native +// target=x86_64-linux,aarch64-linux diff --git a/test/cases/safety/integer multiplication overflow.zig b/test/cases/safety/integer multiplication overflow.zig index f7f4148a15..4380ec6d51 100644 --- a/test/cases/safety/integer multiplication overflow.zig +++ b/test/cases/safety/integer multiplication overflow.zig @@ -18,4 +18,4 @@ fn mul(a: u16, b: u16) u16 { } // run // backend=stage2,llvm -// target=native +// target=x86_64-linux,aarch64-linux diff --git a/test/cases/safety/integer negation overflow.zig b/test/cases/safety/integer negation overflow.zig index cfdfed0429..1c6610ae6f 100644 --- a/test/cases/safety/integer negation overflow.zig +++ b/test/cases/safety/integer negation overflow.zig @@ -18,4 +18,4 @@ fn neg(a: i16) i16 { } // run // backend=stage2,llvm -// target=native +// target=x86_64-linux,aarch64-linux diff --git a/test/cases/safety/integer subtraction overflow.zig b/test/cases/safety/integer subtraction overflow.zig index 14e9131c3b..9211c877e4 100644 --- a/test/cases/safety/integer subtraction overflow.zig +++ b/test/cases/safety/integer subtraction overflow.zig @@ -18,4 +18,4 @@ fn sub(a: u16, b: u16) u16 { } // run // backend=stage2,llvm -// target=native +// target=x86_64-linux,aarch64-linux diff --git a/test/cases/safety/memcpy_alias.zig b/test/cases/safety/memcpy_alias.zig index f7a1a16024..62c30ec459 100644 --- a/test/cases/safety/memcpy_alias.zig +++ b/test/cases/safety/memcpy_alias.zig @@ -16,4 +16,4 @@ pub fn main() !void { } // run // backend=stage2,llvm -// target=native +// target=x86_64-linux,aarch64-linux diff --git a/test/cases/safety/memcpy_len_mismatch.zig b/test/cases/safety/memcpy_len_mismatch.zig index 0ef22b959c..aa9b3fd63f 100644 --- a/test/cases/safety/memcpy_len_mismatch.zig +++ b/test/cases/safety/memcpy_len_mismatch.zig @@ -16,4 +16,4 @@ pub fn main() !void { } // run // backend=stage2,llvm -// target=native +// target=x86_64-linux,aarch64-linux diff --git a/test/cases/safety/memmove_len_mismatch.zig b/test/cases/safety/memmove_len_mismatch.zig index 881af9f336..fa22597122 100644 --- a/test/cases/safety/memmove_len_mismatch.zig +++ b/test/cases/safety/memmove_len_mismatch.zig @@ -16,4 +16,4 @@ pub fn main() !void { } // run // backend=stage2,llvm -// target=native +// target=x86_64-linux,aarch64-linux diff --git a/test/cases/safety/memset_array_undefined_bytes.zig b/test/cases/safety/memset_array_undefined_bytes.zig index 20a65d65d6..47865a8def 100644 --- a/test/cases/safety/memset_array_undefined_bytes.zig +++ b/test/cases/safety/memset_array_undefined_bytes.zig @@ -15,4 +15,4 @@ pub fn main() !void { } // run // backend=stage2,llvm -// target=native +// target=x86_64-linux,aarch64-linux diff --git a/test/cases/safety/memset_array_undefined_large.zig b/test/cases/safety/memset_array_undefined_large.zig index a52bfecbf0..10f57521cf 100644 --- a/test/cases/safety/memset_array_undefined_large.zig +++ b/test/cases/safety/memset_array_undefined_large.zig @@ -15,4 +15,4 @@ pub fn main() !void { } // run // backend=stage2,llvm -// target=native +// target=x86_64-linux,aarch64-linux diff --git a/test/cases/safety/memset_slice_undefined_bytes.zig b/test/cases/safety/memset_slice_undefined_bytes.zig index fb67999306..4d76bbc414 100644 --- a/test/cases/safety/memset_slice_undefined_bytes.zig +++ b/test/cases/safety/memset_slice_undefined_bytes.zig @@ -17,4 +17,4 @@ pub fn main() !void { } // run // backend=stage2,llvm -// target=native +// target=x86_64-linux,aarch64-linux diff --git a/test/cases/safety/memset_slice_undefined_large.zig b/test/cases/safety/memset_slice_undefined_large.zig index 166557240c..e404e35226 100644 --- a/test/cases/safety/memset_slice_undefined_large.zig +++ b/test/cases/safety/memset_slice_undefined_large.zig @@ -17,4 +17,4 @@ pub fn main() !void { } // run // backend=stage2,llvm -// target=native +// target=x86_64-linux,aarch64-linux diff --git a/test/cases/safety/modrem by zero.zig b/test/cases/safety/modrem by zero.zig index 35b7e37e3a..fac10065ed 100644 --- a/test/cases/safety/modrem by zero.zig +++ b/test/cases/safety/modrem by zero.zig @@ -17,4 +17,4 @@ fn div0(a: u32, b: u32) u32 { } // run // backend=stage2,llvm -// target=native +// target=x86_64-linux,aarch64-linux diff --git a/test/cases/safety/modulus by zero.zig b/test/cases/safety/modulus by zero.zig index cdeab00dbc..1c0c8ba3a9 100644 --- a/test/cases/safety/modulus by zero.zig +++ b/test/cases/safety/modulus by zero.zig @@ -17,4 +17,4 @@ fn mod0(a: i32, b: i32) i32 { } // run // backend=stage2,llvm -// target=native +// target=x86_64-linux diff --git a/test/cases/safety/noreturn returned.zig b/test/cases/safety/noreturn returned.zig index c92fb08e62..b91a6def49 100644 --- a/test/cases/safety/noreturn returned.zig +++ b/test/cases/safety/noreturn returned.zig @@ -20,4 +20,4 @@ pub fn main() void { } // run // backend=stage2,llvm -// target=native +// target=x86_64-linux,aarch64-linux diff --git a/test/cases/safety/optional unwrap operator on C pointer.zig b/test/cases/safety/optional unwrap operator on C pointer.zig index 98135cfae4..4deb62bc25 100644 --- a/test/cases/safety/optional unwrap operator on C pointer.zig +++ b/test/cases/safety/optional unwrap operator on C pointer.zig @@ -16,4 +16,4 @@ pub fn main() !void { } // run // backend=stage2,llvm -// target=native +// target=x86_64-linux,aarch64-linux diff --git a/test/cases/safety/optional unwrap operator on null pointer.zig b/test/cases/safety/optional unwrap operator on null pointer.zig index 6ac54e6bd0..97d07626f5 100644 --- a/test/cases/safety/optional unwrap operator on null pointer.zig +++ b/test/cases/safety/optional unwrap operator on null pointer.zig @@ -16,4 +16,4 @@ pub fn main() !void { } // run // backend=stage2,llvm -// target=native +// target=x86_64-linux,aarch64-linux diff --git a/test/cases/safety/optional_empty_error_set.zig b/test/cases/safety/optional_empty_error_set.zig index dbe39d00c3..1ee1690d51 100644 --- a/test/cases/safety/optional_empty_error_set.zig +++ b/test/cases/safety/optional_empty_error_set.zig @@ -19,4 +19,4 @@ fn foo() !void { } // run // backend=stage2,llvm -// target=native +// target=x86_64-linux,aarch64-linux diff --git a/test/cases/safety/out of bounds array slice by length.zig b/test/cases/safety/out of bounds array slice by length.zig index 325749a5eb..df613b1d53 100644 --- a/test/cases/safety/out of bounds array slice by length.zig +++ b/test/cases/safety/out of bounds array slice by length.zig @@ -17,4 +17,4 @@ fn foo(a: u32) u32 { } // run // backend=stage2,llvm -// target=native +// target=x86_64-linux,aarch64-linux diff --git a/test/cases/safety/out of bounds slice access.zig b/test/cases/safety/out of bounds slice access.zig index f4f34a203f..d5ebf6d531 100644 --- a/test/cases/safety/out of bounds slice access.zig +++ b/test/cases/safety/out of bounds slice access.zig @@ -18,4 +18,4 @@ fn bar(a: []const i32) i32 { fn baz(_: i32) void {} // run // backend=stage2,llvm -// target=native +// target=x86_64-linux,aarch64-linux diff --git a/test/cases/safety/pointer casting null to non-optional pointer.zig b/test/cases/safety/pointer casting null to non-optional pointer.zig index 33da071e73..ef61f162b4 100644 --- a/test/cases/safety/pointer casting null to non-optional pointer.zig +++ b/test/cases/safety/pointer casting null to non-optional pointer.zig @@ -18,4 +18,4 @@ pub fn main() !void { // run // backend=stage2,llvm -// target=native +// target=x86_64-linux,aarch64-linux diff --git a/test/cases/safety/pointer casting to null function pointer.zig b/test/cases/safety/pointer casting to null function pointer.zig index a57e71cb8f..1ce1ebc266 100644 --- a/test/cases/safety/pointer casting to null function pointer.zig +++ b/test/cases/safety/pointer casting to null function pointer.zig @@ -20,4 +20,4 @@ pub fn main() !void { // run // backend=stage2,llvm -// target=native +// target=x86_64-linux,aarch64-linux diff --git a/test/cases/safety/pointer slice sentinel mismatch.zig b/test/cases/safety/pointer slice sentinel mismatch.zig index 519b04b916..a400c0bc35 100644 --- a/test/cases/safety/pointer slice sentinel mismatch.zig +++ b/test/cases/safety/pointer slice sentinel mismatch.zig @@ -18,4 +18,4 @@ pub fn main() !void { // run // backend=stage2,llvm -// target=native +// target=x86_64-linux,aarch64-linux diff --git a/test/cases/safety/remainder division by zero.zig b/test/cases/safety/remainder division by zero.zig index 2d938a2fd6..3749c3d5d7 100644 --- a/test/cases/safety/remainder division by zero.zig +++ b/test/cases/safety/remainder division by zero.zig @@ -17,4 +17,4 @@ fn rem0(a: i32, b: i32) i32 { } // run // backend=stage2,llvm -// target=native +// target=x86_64-linux,aarch64-linux diff --git a/test/cases/safety/shift left by huge amount.zig b/test/cases/safety/shift left by huge amount.zig index 374b03d123..b6b88ba870 100644 --- a/test/cases/safety/shift left by huge amount.zig +++ b/test/cases/safety/shift left by huge amount.zig @@ -19,4 +19,4 @@ pub fn main() !void { // run // backend=stage2,llvm -// target=native +// target=x86_64-linux,aarch64-linux diff --git a/test/cases/safety/shift right by huge amount.zig b/test/cases/safety/shift right by huge amount.zig index 173e6fcd7e..664e2b5473 100644 --- a/test/cases/safety/shift right by huge amount.zig +++ b/test/cases/safety/shift right by huge amount.zig @@ -19,4 +19,4 @@ pub fn main() !void { // run // backend=stage2,llvm -// target=native +// target=x86_64-linux,aarch64-linux diff --git a/test/cases/safety/signed integer division overflow - vectors.zig b/test/cases/safety/signed integer division overflow - vectors.zig index 0de062094d..7a696c4b4d 100644 --- a/test/cases/safety/signed integer division overflow - vectors.zig +++ b/test/cases/safety/signed integer division overflow - vectors.zig @@ -20,4 +20,4 @@ fn div(a: @Vector(4, i16), b: @Vector(4, i16)) @Vector(4, i16) { } // run // backend=stage2,llvm -// target=native +// target=x86_64-linux diff --git a/test/cases/safety/signed integer division overflow.zig b/test/cases/safety/signed integer division overflow.zig index 0d67f72649..acbb3d4e16 100644 --- a/test/cases/safety/signed integer division overflow.zig +++ b/test/cases/safety/signed integer division overflow.zig @@ -18,4 +18,4 @@ fn div(a: i16, b: i16) i16 { } // run // backend=stage2,llvm -// target=native +// target=x86_64-linux,aarch64-linux diff --git a/test/cases/safety/signed integer not fitting in cast to unsigned integer - widening.zig b/test/cases/safety/signed integer not fitting in cast to unsigned integer - widening.zig index fa0eec94c0..f47083d4df 100644 --- a/test/cases/safety/signed integer not fitting in cast to unsigned integer - widening.zig +++ b/test/cases/safety/signed integer not fitting in cast to unsigned integer - widening.zig @@ -16,4 +16,4 @@ pub fn main() !void { } // run // backend=stage2,llvm -// target=native +// target=x86_64-linux diff --git a/test/cases/safety/signed integer not fitting in cast to unsigned integer.zig b/test/cases/safety/signed integer not fitting in cast to unsigned integer.zig index 6ce662cdc7..881b3c1631 100644 --- a/test/cases/safety/signed integer not fitting in cast to unsigned integer.zig +++ b/test/cases/safety/signed integer not fitting in cast to unsigned integer.zig @@ -17,4 +17,4 @@ fn unsigned_cast(x: i32) u32 { } // run // backend=stage2,llvm -// target=native +// target=x86_64-linux,aarch64-linux diff --git a/test/cases/safety/signed shift left overflow.zig b/test/cases/safety/signed shift left overflow.zig index 54a51e0ccd..0cab01ca02 100644 --- a/test/cases/safety/signed shift left overflow.zig +++ b/test/cases/safety/signed shift left overflow.zig @@ -18,4 +18,4 @@ fn shl(a: i16, b: u4) i16 { } // run // backend=stage2,llvm -// target=native +// target=x86_64-linux diff --git a/test/cases/safety/signed shift right overflow.zig b/test/cases/safety/signed shift right overflow.zig index 1a0c5973c9..9fe3fe7873 100644 --- a/test/cases/safety/signed shift right overflow.zig +++ b/test/cases/safety/signed shift right overflow.zig @@ -18,4 +18,4 @@ fn shr(a: i16, b: u4) i16 { } // run // backend=stage2,llvm -// target=native +// target=x86_64-linux,aarch64-linux diff --git a/test/cases/safety/signed-unsigned vector cast.zig b/test/cases/safety/signed-unsigned vector cast.zig index 919562b06c..22d4073694 100644 --- a/test/cases/safety/signed-unsigned vector cast.zig +++ b/test/cases/safety/signed-unsigned vector cast.zig @@ -18,4 +18,4 @@ pub fn main() !void { // run // backend=stage2,llvm -// target=native +// target=x86_64-linux diff --git a/test/cases/safety/slice by length sentinel mismatch on lhs.zig b/test/cases/safety/slice by length sentinel mismatch on lhs.zig index c66a968d4b..85785ce769 100644 --- a/test/cases/safety/slice by length sentinel mismatch on lhs.zig +++ b/test/cases/safety/slice by length sentinel mismatch on lhs.zig @@ -15,4 +15,4 @@ pub fn main() !void { } // run // backend=stage2,llvm -// target=native +// target=x86_64-linux,aarch64-linux diff --git a/test/cases/safety/slice by length sentinel mismatch on rhs.zig b/test/cases/safety/slice by length sentinel mismatch on rhs.zig index a4a2189a9c..64fe818d1e 100644 --- a/test/cases/safety/slice by length sentinel mismatch on rhs.zig +++ b/test/cases/safety/slice by length sentinel mismatch on rhs.zig @@ -15,4 +15,4 @@ pub fn main() !void { } // run // backend=stage2,llvm -// target=native +// target=x86_64-linux,aarch64-linux diff --git a/test/cases/safety/slice sentinel mismatch - floats.zig b/test/cases/safety/slice sentinel mismatch - floats.zig index be63272f0c..b31855ab42 100644 --- a/test/cases/safety/slice sentinel mismatch - floats.zig +++ b/test/cases/safety/slice sentinel mismatch - floats.zig @@ -17,4 +17,4 @@ pub fn main() !void { // run // backend=stage2,llvm -// target=native +// target=x86_64-linux diff --git a/test/cases/safety/slice sentinel mismatch - optional pointers.zig b/test/cases/safety/slice sentinel mismatch - optional pointers.zig index 38ab78b2c1..4337fe448d 100644 --- a/test/cases/safety/slice sentinel mismatch - optional pointers.zig +++ b/test/cases/safety/slice sentinel mismatch - optional pointers.zig @@ -17,4 +17,4 @@ pub fn main() !void { // run // backend=stage2,llvm -// target=native +// target=x86_64-linux,aarch64-linux diff --git a/test/cases/safety/slice slice sentinel mismatch.zig b/test/cases/safety/slice slice sentinel mismatch.zig index 51d4c16596..76224f966d 100644 --- a/test/cases/safety/slice slice sentinel mismatch.zig +++ b/test/cases/safety/slice slice sentinel mismatch.zig @@ -16,4 +16,4 @@ pub fn main() !void { } // run // backend=stage2,llvm -// target=native +// target=x86_64-linux,aarch64-linux diff --git a/test/cases/safety/slice start index greater than end index.zig b/test/cases/safety/slice start index greater than end index.zig index a6dde3ac63..684020b8a7 100644 --- a/test/cases/safety/slice start index greater than end index.zig +++ b/test/cases/safety/slice start index greater than end index.zig @@ -21,4 +21,4 @@ pub fn main() !void { // run // backend=stage2,llvm -// target=native +// target=x86_64-linux,aarch64-linux diff --git a/test/cases/safety/slice with sentinel out of bounds - runtime len.zig b/test/cases/safety/slice with sentinel out of bounds - runtime len.zig index 7039f541e3..b9ef281144 100644 --- a/test/cases/safety/slice with sentinel out of bounds - runtime len.zig +++ b/test/cases/safety/slice with sentinel out of bounds - runtime len.zig @@ -20,4 +20,4 @@ pub fn main() !void { // run // backend=stage2,llvm -// target=native +// target=x86_64-linux,aarch64-linux diff --git a/test/cases/safety/slice with sentinel out of bounds.zig b/test/cases/safety/slice with sentinel out of bounds.zig index 8439e8c737..f07d393a0e 100644 --- a/test/cases/safety/slice with sentinel out of bounds.zig +++ b/test/cases/safety/slice with sentinel out of bounds.zig @@ -18,4 +18,4 @@ pub fn main() !void { // run // backend=stage2,llvm -// target=native +// target=x86_64-linux,aarch64-linux diff --git a/test/cases/safety/slice_cast_change_len_0.zig b/test/cases/safety/slice_cast_change_len_0.zig index d32bdfc920..96d94cfad5 100644 --- a/test/cases/safety/slice_cast_change_len_0.zig +++ b/test/cases/safety/slice_cast_change_len_0.zig @@ -24,4 +24,4 @@ const std = @import("std"); // run // backend=stage2,llvm -// target=x86_64-linux +// target=x86_64-linux,aarch64-linux diff --git a/test/cases/safety/slice_cast_change_len_1.zig b/test/cases/safety/slice_cast_change_len_1.zig index 5d3728bcdc..21a1d69558 100644 --- a/test/cases/safety/slice_cast_change_len_1.zig +++ b/test/cases/safety/slice_cast_change_len_1.zig @@ -24,4 +24,4 @@ const std = @import("std"); // run // backend=stage2,llvm -// target=x86_64-linux +// target=x86_64-linux,aarch64-linux diff --git a/test/cases/safety/slice_cast_change_len_2.zig b/test/cases/safety/slice_cast_change_len_2.zig index 3a25d27504..5da254e903 100644 --- a/test/cases/safety/slice_cast_change_len_2.zig +++ b/test/cases/safety/slice_cast_change_len_2.zig @@ -24,4 +24,4 @@ const std = @import("std"); // run // backend=stage2,llvm -// target=x86_64-linux +// target=x86_64-linux,aarch64-linux diff --git a/test/cases/safety/slicing null C pointer - runtime len.zig b/test/cases/safety/slicing null C pointer - runtime len.zig index 763553b04a..831224edee 100644 --- a/test/cases/safety/slicing null C pointer - runtime len.zig +++ b/test/cases/safety/slicing null C pointer - runtime len.zig @@ -18,4 +18,4 @@ pub fn main() !void { } // run // backend=stage2,llvm -// target=native +// target=x86_64-linux,aarch64-linux diff --git a/test/cases/safety/slicing null C pointer.zig b/test/cases/safety/slicing null C pointer.zig index a928fd585f..53da877c59 100644 --- a/test/cases/safety/slicing null C pointer.zig +++ b/test/cases/safety/slicing null C pointer.zig @@ -17,4 +17,4 @@ pub fn main() !void { } // run // backend=stage2,llvm -// target=native +// target=x86_64-linux,aarch64-linux diff --git a/test/cases/safety/switch else on corrupt enum value - one prong.zig b/test/cases/safety/switch else on corrupt enum value - one prong.zig index 73f6ed9dc8..b2ef933080 100644 --- a/test/cases/safety/switch else on corrupt enum value - one prong.zig +++ b/test/cases/safety/switch else on corrupt enum value - one prong.zig @@ -21,4 +21,4 @@ pub fn main() !void { } // run // backend=stage2,llvm -// target=native +// target=x86_64-linux diff --git a/test/cases/safety/switch else on corrupt enum value - union.zig b/test/cases/safety/switch else on corrupt enum value - union.zig index 77dacd86c6..933f7995a5 100644 --- a/test/cases/safety/switch else on corrupt enum value - union.zig +++ b/test/cases/safety/switch else on corrupt enum value - union.zig @@ -26,4 +26,4 @@ pub fn main() !void { } // run // backend=stage2,llvm -// target=native +// target=x86_64-linux diff --git a/test/cases/safety/switch else on corrupt enum value.zig b/test/cases/safety/switch else on corrupt enum value.zig index 228e3c70ec..300de27e93 100644 --- a/test/cases/safety/switch else on corrupt enum value.zig +++ b/test/cases/safety/switch else on corrupt enum value.zig @@ -20,4 +20,4 @@ pub fn main() !void { } // run // backend=stage2,llvm -// target=native +// target=x86_64-linux diff --git a/test/cases/safety/switch on corrupted enum value.zig b/test/cases/safety/switch on corrupted enum value.zig index 4d46d2e7a7..74ec3a4057 100644 --- a/test/cases/safety/switch on corrupted enum value.zig +++ b/test/cases/safety/switch on corrupted enum value.zig @@ -24,4 +24,4 @@ pub fn main() !void { // run // backend=stage2,llvm -// target=native +// target=x86_64-linux,aarch64-linux diff --git a/test/cases/safety/switch on corrupted union value.zig b/test/cases/safety/switch on corrupted union value.zig index 0f622dcbd8..cede4feb04 100644 --- a/test/cases/safety/switch on corrupted union value.zig +++ b/test/cases/safety/switch on corrupted union value.zig @@ -24,4 +24,4 @@ pub fn main() !void { // run // backend=stage2,llvm -// target=native +// target=x86_64-linux diff --git a/test/cases/safety/truncating vector cast.zig b/test/cases/safety/truncating vector cast.zig index 9b222e6918..f6271a094e 100644 --- a/test/cases/safety/truncating vector cast.zig +++ b/test/cases/safety/truncating vector cast.zig @@ -18,4 +18,4 @@ pub fn main() !void { // run // backend=stage2,llvm -// target=native +// target=x86_64-linux diff --git a/test/cases/safety/unreachable.zig b/test/cases/safety/unreachable.zig index fc1e886540..1094123cba 100644 --- a/test/cases/safety/unreachable.zig +++ b/test/cases/safety/unreachable.zig @@ -12,4 +12,4 @@ pub fn main() !void { } // run // backend=stage2,llvm -// target=native +// target=x86_64-linux,aarch64-linux diff --git a/test/cases/safety/unsigned integer not fitting in cast to signed integer - same bit count.zig b/test/cases/safety/unsigned integer not fitting in cast to signed integer - same bit count.zig index 185cde9973..7f27c5fcd5 100644 --- a/test/cases/safety/unsigned integer not fitting in cast to signed integer - same bit count.zig +++ b/test/cases/safety/unsigned integer not fitting in cast to signed integer - same bit count.zig @@ -16,4 +16,4 @@ pub fn main() !void { } // run // backend=stage2,llvm -// target=native +// target=x86_64-linux diff --git a/test/cases/safety/unsigned shift left overflow.zig b/test/cases/safety/unsigned shift left overflow.zig index e2f58f0f3b..1098a80c8e 100644 --- a/test/cases/safety/unsigned shift left overflow.zig +++ b/test/cases/safety/unsigned shift left overflow.zig @@ -18,4 +18,4 @@ fn shl(a: u16, b: u4) u16 { } // run // backend=stage2,llvm -// target=native +// target=x86_64-linux diff --git a/test/cases/safety/unsigned shift right overflow.zig b/test/cases/safety/unsigned shift right overflow.zig index 6ded52098d..e9ad8571b6 100644 --- a/test/cases/safety/unsigned shift right overflow.zig +++ b/test/cases/safety/unsigned shift right overflow.zig @@ -18,4 +18,4 @@ fn shr(a: u16, b: u4) u16 { } // run // backend=stage2,llvm -// target=native +// target=x86_64-linux,aarch64-linux diff --git a/test/cases/safety/unsigned-signed vector cast.zig b/test/cases/safety/unsigned-signed vector cast.zig index 6501643b36..5b3b58d928 100644 --- a/test/cases/safety/unsigned-signed vector cast.zig +++ b/test/cases/safety/unsigned-signed vector cast.zig @@ -18,4 +18,4 @@ pub fn main() !void { // run // backend=stage2,llvm -// target=native +// target=x86_64-linux diff --git a/test/cases/safety/unwrap error switch.zig b/test/cases/safety/unwrap error switch.zig index b3194bd2e0..a1a148cfd9 100644 --- a/test/cases/safety/unwrap error switch.zig +++ b/test/cases/safety/unwrap error switch.zig @@ -18,4 +18,4 @@ fn bar() !void { } // run // backend=stage2,llvm -// target=native +// target=x86_64-linux,aarch64-linux diff --git a/test/cases/safety/unwrap error.zig b/test/cases/safety/unwrap error.zig index 9fe7d437bc..dd157c8721 100644 --- a/test/cases/safety/unwrap error.zig +++ b/test/cases/safety/unwrap error.zig @@ -16,4 +16,4 @@ fn bar() !void { } // run // backend=stage2,llvm -// target=native +// target=x86_64-linux,aarch64-linux diff --git a/test/cases/safety/value does not fit in shortening cast - u0.zig b/test/cases/safety/value does not fit in shortening cast - u0.zig index f29df8d8af..9d77b3f1c8 100644 --- a/test/cases/safety/value does not fit in shortening cast - u0.zig +++ b/test/cases/safety/value does not fit in shortening cast - u0.zig @@ -18,4 +18,4 @@ fn shorten_cast(x: u8) u0 { } // run // backend=stage2,llvm -// target=native +// target=x86_64-linux,aarch64-linux diff --git a/test/cases/safety/value does not fit in shortening cast.zig b/test/cases/safety/value does not fit in shortening cast.zig index 415ac95dbb..9b6af39967 100644 --- a/test/cases/safety/value does not fit in shortening cast.zig +++ b/test/cases/safety/value does not fit in shortening cast.zig @@ -18,4 +18,4 @@ fn shorten_cast(x: i32) i8 { } // run // backend=stage2,llvm -// target=native +// target=x86_64-linux,aarch64-linux diff --git a/test/cases/safety/vector integer addition overflow.zig b/test/cases/safety/vector integer addition overflow.zig index db08d8b241..64f6e238e0 100644 --- a/test/cases/safety/vector integer addition overflow.zig +++ b/test/cases/safety/vector integer addition overflow.zig @@ -19,4 +19,4 @@ fn add(a: @Vector(4, i32), b: @Vector(4, i32)) @Vector(4, i32) { } // run // backend=stage2,llvm -// target=native +// target=x86_64-linux diff --git a/test/cases/safety/vector integer multiplication overflow.zig b/test/cases/safety/vector integer multiplication overflow.zig index 61176fd482..69d0dde16d 100644 --- a/test/cases/safety/vector integer multiplication overflow.zig +++ b/test/cases/safety/vector integer multiplication overflow.zig @@ -19,4 +19,4 @@ fn mul(a: @Vector(4, u8), b: @Vector(4, u8)) @Vector(4, u8) { } // run // backend=stage2,llvm -// target=native +// target=x86_64-linux diff --git a/test/cases/safety/vector integer negation overflow.zig b/test/cases/safety/vector integer negation overflow.zig index f1f36ff294..72182cfdfc 100644 --- a/test/cases/safety/vector integer negation overflow.zig +++ b/test/cases/safety/vector integer negation overflow.zig @@ -19,4 +19,4 @@ fn neg(a: @Vector(4, i16)) @Vector(4, i16) { } // run // backend=stage2,llvm -// target=native +// target=x86_64-linux diff --git a/test/cases/safety/vector integer subtraction overflow.zig b/test/cases/safety/vector integer subtraction overflow.zig index 9ba942469c..8ac2c6d756 100644 --- a/test/cases/safety/vector integer subtraction overflow.zig +++ b/test/cases/safety/vector integer subtraction overflow.zig @@ -19,4 +19,4 @@ fn sub(a: @Vector(4, u32), b: @Vector(4, u32)) @Vector(4, u32) { } // run // backend=stage2,llvm -// target=native +// target=x86_64-linux diff --git a/test/cases/safety/zero casted to error.zig b/test/cases/safety/zero casted to error.zig index 1ffa995260..7a02ec2b71 100644 --- a/test/cases/safety/zero casted to error.zig +++ b/test/cases/safety/zero casted to error.zig @@ -16,4 +16,4 @@ fn bar(x: u16) anyerror { } // run // backend=stage2,llvm -// target=native +// target=x86_64-linux,aarch64-linux diff --git a/test/cases/taking_pointer_of_global_tagged_union.zig b/test/cases/taking_pointer_of_global_tagged_union.zig index accb22667d..adc71d81c0 100644 --- a/test/cases/taking_pointer_of_global_tagged_union.zig +++ b/test/cases/taking_pointer_of_global_tagged_union.zig @@ -23,4 +23,4 @@ pub fn main() !void { // run // backend=stage2,llvm -// target=native +// target=x86_64-linux diff --git a/test/src/Cases.zig b/test/src/Cases.zig index bd93599171..60a564bc16 100644 --- a/test/src/Cases.zig +++ b/test/src/Cases.zig @@ -436,7 +436,7 @@ fn addFromDirInner( const target = &resolved_target.result; for (backends) |backend| { if (backend == .stage2 and - target.cpu.arch != .wasm32 and target.cpu.arch != .x86_64 and target.cpu.arch != .spirv64) + target.cpu.arch != .aarch64 and target.cpu.arch != .wasm32 and target.cpu.arch != .x86_64 and target.cpu.arch != .spirv64) { // Other backends don't support new liveness format continue; @@ -447,10 +447,6 @@ fn addFromDirInner( // Rosetta has issues with ZLD continue; } - if (backend == .stage2 and target.ofmt == .coff) { - // COFF linker has bitrotted - continue; - } const next = ctx.cases.items.len; try ctx.cases.append(.{ -- cgit v1.2.3 From 771523c67534fc47800608eb720886e9f53da7b4 Mon Sep 17 00:00:00 2001 From: Jacob Young Date: Sun, 27 Jul 2025 06:50:20 -0400 Subject: aarch64: implement var args --- src/codegen/aarch64.zig | 52 ++-- src/codegen/aarch64/Select.zig | 495 +++++++++++++++++++++++++++++++-------- src/codegen/aarch64/encoding.zig | 40 ++-- test/behavior/var_args.zig | 4 - 4 files changed, 451 insertions(+), 140 deletions(-) (limited to 'src/codegen/aarch64.zig') diff --git a/src/codegen/aarch64.zig b/src/codegen/aarch64.zig index 4cb3e8ecc8..2904d36b7f 100644 --- a/src/codegen/aarch64.zig +++ b/src/codegen/aarch64.zig @@ -19,8 +19,12 @@ pub fn generate( ) !Mir { const zcu = pt.zcu; const gpa = zcu.gpa; + const ip = &zcu.intern_pool; const func = zcu.funcInfo(func_index); - const func_type = zcu.intern_pool.indexToKey(func.ty).func_type; + const func_zir = func.zir_body_inst.resolveFull(ip).?; + const file = zcu.fileByIndex(func_zir.file); + const named_params_len = file.zir.?.getParamBody(func_zir.inst).len; + const func_type = ip.indexToKey(func.ty).func_type; assert(liveness.* == null); const mod = zcu.navFileScope(func.owner_nav).mod.?; @@ -61,23 +65,32 @@ pub fn generate( .values = .empty, }; defer isel.deinit(); + const is_sysv = !isel.target.os.tag.isDarwin() and isel.target.os.tag != .windows; + const is_sysv_var_args = is_sysv and func_type.is_var_args; const air_main_body = air.getMainBody(); var param_it: Select.CallAbiIterator = .init; const air_args = for (air_main_body, 0..) |air_inst_index, body_index| { if (air.instructions.items(.tag)[@intFromEnum(air_inst_index)] != .arg) break air_main_body[0..body_index]; - const param_ty = air.instructions.items(.data)[@intFromEnum(air_inst_index)].arg.ty.toType(); - const param_vi = try param_it.param(&isel, param_ty); + const arg = air.instructions.items(.data)[@intFromEnum(air_inst_index)].arg; + const param_ty = arg.ty.toType(); + const param_vi = param_vi: { + if (arg.zir_param_index >= named_params_len) { + assert(func_type.is_var_args); + if (!is_sysv) break :param_vi try param_it.nonSysvVarArg(&isel, param_ty); + } + break :param_vi try param_it.param(&isel, param_ty); + }; tracking_log.debug("${d} <- %{d}", .{ @intFromEnum(param_vi.?), @intFromEnum(air_inst_index) }); try isel.live_values.putNoClobber(gpa, air_inst_index, param_vi.?); } else unreachable; const saved_gra_start = if (mod.strip) param_it.ngrn else Select.CallAbiIterator.ngrn_start; - const saved_gra_end = if (func_type.is_var_args) Select.CallAbiIterator.ngrn_end else param_it.ngrn; + const saved_gra_end = if (is_sysv_var_args) Select.CallAbiIterator.ngrn_end else param_it.ngrn; const saved_gra_len = @intFromEnum(saved_gra_end) - @intFromEnum(saved_gra_start); const saved_vra_start = if (mod.strip) param_it.nsrn else Select.CallAbiIterator.nsrn_start; - const saved_vra_end = if (func_type.is_var_args) Select.CallAbiIterator.nsrn_end else param_it.nsrn; + const saved_vra_end = if (is_sysv_var_args) Select.CallAbiIterator.nsrn_end else param_it.nsrn; const saved_vra_len = @intFromEnum(saved_vra_end) - @intFromEnum(saved_vra_start); const frame_record = 2; @@ -85,11 +98,16 @@ pub fn generate( .base = .fp, .offset = 8 * std.mem.alignForward(u7, frame_record + saved_gra_len, 2), }; - isel.va_list = .{ - .__stack = named_stack_args.withOffset(param_it.nsaa), - .__gr_top = named_stack_args, - .__vr_top = .{ .base = .fp, .offset = 0 }, - }; + const stack_var_args = named_stack_args.withOffset(param_it.nsaa); + const gr_top = named_stack_args; + const vr_top: Select.Value.Indirect = .{ .base = .fp, .offset = 0 }; + isel.va_list = if (is_sysv) .{ .sysv = .{ + .__stack = stack_var_args, + .__gr_top = gr_top, + .__vr_top = vr_top, + .__gr_offs = @as(i32, @intFromEnum(Select.CallAbiIterator.ngrn_end) - @intFromEnum(param_it.ngrn)) * -8, + .__vr_offs = @as(i32, @intFromEnum(Select.CallAbiIterator.nsrn_end) - @intFromEnum(param_it.nsrn)) * -16, + } } else .{ .other = stack_var_args }; // translate arg locations from caller-based to callee-based for (air_args) |air_inst_index| { @@ -106,11 +124,9 @@ pub fn generate( const first_passed_part_vi = part_it.next().?; const hint_ra = first_passed_part_vi.hint(&isel).?; passed_vi.setParent(&isel, .{ .stack_slot = if (hint_ra.isVector()) - isel.va_list.__vr_top.withOffset(@as(i8, -16) * - (@intFromEnum(saved_vra_end) - @intFromEnum(hint_ra))) + vr_top.withOffset(@as(i8, -16) * (@intFromEnum(saved_vra_end) - @intFromEnum(hint_ra))) else - isel.va_list.__gr_top.withOffset(@as(i8, -8) * - (@intFromEnum(saved_gra_end) - @intFromEnum(hint_ra))) }); + gr_top.withOffset(@as(i8, -8) * (@intFromEnum(saved_gra_end) - @intFromEnum(hint_ra))) }); }, .stack_slot => |stack_slot| { assert(stack_slot.base == .sp); @@ -152,13 +168,7 @@ pub fn generate( isel.verify(true); const prologue = isel.instructions.items.len; - const epilogue = try isel.layout( - param_it, - func_type.is_var_args, - saved_gra_len, - saved_vra_len, - mod, - ); + const epilogue = try isel.layout(param_it, is_sysv_var_args, saved_gra_len, saved_vra_len, mod); const instructions = try isel.instructions.toOwnedSlice(gpa); var mir: Mir = .{ diff --git a/src/codegen/aarch64/Select.zig b/src/codegen/aarch64/Select.zig index f84088624a..0b60f26b02 100644 --- a/src/codegen/aarch64/Select.zig +++ b/src/codegen/aarch64/Select.zig @@ -28,10 +28,15 @@ literal_relocs: std.ArrayListUnmanaged(codegen.aarch64.Mir.Reloc.Literal), // Stack Frame returns: bool, -va_list: struct { - __stack: Value.Indirect, - __gr_top: Value.Indirect, - __vr_top: Value.Indirect, +va_list: union(enum) { + other: Value.Indirect, + sysv: struct { + __stack: Value.Indirect, + __gr_top: Value.Indirect, + __vr_top: Value.Indirect, + __gr_offs: i32, + __vr_offs: i32, + }, }, stack_size: u24, stack_align: InternPool.Alignment, @@ -408,13 +413,7 @@ pub fn analyze(isel: *Select, air_body: []const Air.Inst.Index) !void { air_body_index += 1; }, - .breakpoint, - .dbg_stmt, - .dbg_empty_stmt, - .dbg_var_ptr, - .dbg_var_val, - .dbg_arg_inline, - => { + .breakpoint, .dbg_stmt, .dbg_empty_stmt, .dbg_var_ptr, .dbg_var_val, .dbg_arg_inline, .c_va_end => { air_body_index += 1; air_inst_index = air_body[air_body_index]; continue :air_tag air_tags[@intFromEnum(air_inst_index)]; @@ -428,23 +427,43 @@ pub fn analyze(isel: *Select, air_body: []const Air.Inst.Index) !void { const extra = isel.air.extraData(Air.Call, pl_op.payload); const args: []const Air.Inst.Ref = @ptrCast(isel.air.extra.items[extra.end..][0..extra.data.args_len]); isel.saved_registers.insert(.lr); + const callee_ty = isel.air.typeOf(pl_op.operand, ip); + const func_info = switch (ip.indexToKey(callee_ty.toIntern())) { + else => unreachable, + .func_type => |func_type| func_type, + .ptr_type => |ptr_type| ip.indexToKey(ptr_type.child).func_type, + }; try isel.analyzeUse(pl_op.operand); var param_it: CallAbiIterator = .init; - for (args) |arg| { + for (args, 0..) |arg, arg_index| { const restore_values_len = isel.values.items.len; defer isel.values.shrinkRetainingCapacity(restore_values_len); - const param_vi = try param_it.param(isel, isel.air.typeOf(arg, ip)) orelse continue; - const param_parent = param_vi.parent(isel); - switch (switch (param_parent) { - .unallocated, .stack_slot => param_parent, + const param_vi = param_vi: { + const param_ty = isel.air.typeOf(arg, ip); + if (arg_index >= func_info.param_types.len) { + assert(func_info.is_var_args); + switch (isel.va_list) { + .other => break :param_vi try param_it.nonSysvVarArg(isel, param_ty), + .sysv => {}, + } + } + break :param_vi try param_it.param(isel, param_ty); + } orelse continue; + defer param_vi.deref(isel); + const passed_vi = switch (param_vi.parent(isel)) { + .unallocated, .stack_slot => param_vi, .value, .constant => unreachable, - .address => |address_vi| address_vi.parent(isel), - }) { + .address => |address_vi| address_vi, + }; + switch (passed_vi.parent(isel)) { .unallocated => {}, .stack_slot => |stack_slot| { assert(stack_slot.base == .sp); - isel.stack_size = @max(isel.stack_size, stack_slot.offset); + isel.stack_size = @max( + isel.stack_size, + stack_slot.offset + @as(u24, @intCast(passed_vi.size(isel))), + ); }, .value, .constant, .address => unreachable, } @@ -802,7 +821,7 @@ pub fn analyze(isel: *Select, air_body: []const Air.Inst.Index) !void { air_inst_index = air_body[air_body_index]; continue :air_tag air_tags[@intFromEnum(air_inst_index)]; }, - .set_err_return_trace, .c_va_end => { + .set_err_return_trace => { const un_op = air_data[@intFromEnum(air_inst_index)].un_op; try isel.analyzeUse(un_op); @@ -2474,6 +2493,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory, } if (air.next()) |next_air_tag| continue :air_tag next_air_tag; }, + .inferred_alloc, .inferred_alloc_comptime => unreachable, .assembly => { const ty_pl = air.data(air.inst_index).ty_pl; const extra = isel.air.extraData(Air.Asm, ty_pl.payload); @@ -3389,6 +3409,12 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory, const pl_op = air.data(air.inst_index).pl_op; const extra = isel.air.extraData(Air.Call, pl_op.payload); const args: []const Air.Inst.Ref = @ptrCast(isel.air.extra.items[extra.end..][0..extra.data.args_len]); + const callee_ty = isel.air.typeOf(pl_op.operand, ip); + const func_info = switch (ip.indexToKey(callee_ty.toIntern())) { + else => unreachable, + .func_type => |func_type| func_type, + .ptr_type => |ptr_type| ip.indexToKey(ptr_type.child).func_type, + }; try call.prepareReturn(isel); const maybe_def_ret_vi = isel.live_values.fetchRemove(air.inst_index); @@ -3455,41 +3481,50 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory, ret_addr_vi.hint(isel).?, ); var param_it: CallAbiIterator = .init; - for (args) |arg| { - const param_vi = try param_it.param(isel, isel.air.typeOf(arg, ip)) orelse continue; + for (args, 0..) |arg, arg_index| { + const param_ty = isel.air.typeOf(arg, ip); + const param_vi = param_vi: { + if (arg_index >= func_info.param_types.len) { + assert(func_info.is_var_args); + switch (isel.va_list) { + .other => break :param_vi try param_it.nonSysvVarArg(isel, param_ty), + .sysv => {}, + } + } + break :param_vi try param_it.param(isel, param_ty); + } orelse continue; defer param_vi.deref(isel); const arg_vi = try isel.use(arg); - const passed_vi = switch (param_vi.parent(isel)) { - .unallocated, .stack_slot => param_vi, - .value, .constant => unreachable, - .address => |address_vi| { - try call.paramAddress(isel, arg_vi, address_vi.hint(isel).?); - continue; + switch (param_vi.parent(isel)) { + .unallocated => if (param_vi.hint(isel)) |param_ra| { + try call.paramLiveOut(isel, arg_vi, param_ra); + } else { + var param_part_it = param_vi.parts(isel); + var arg_part_it = arg_vi.parts(isel); + if (arg_part_it.only()) |_| { + try isel.values.ensureUnusedCapacity(gpa, param_part_it.remaining); + arg_vi.setParts(isel, param_part_it.remaining); + while (param_part_it.next()) |param_part_vi| _ = arg_vi.addPart( + isel, + param_part_vi.get(isel).offset_from_parent, + param_part_vi.size(isel), + ); + param_part_it = param_vi.parts(isel); + arg_part_it = arg_vi.parts(isel); + } + while (param_part_it.next()) |param_part_vi| { + const arg_part_vi = arg_part_it.next().?; + assert(arg_part_vi.get(isel).offset_from_parent == + param_part_vi.get(isel).offset_from_parent); + assert(arg_part_vi.size(isel) == param_part_vi.size(isel)); + try call.paramLiveOut(isel, arg_part_vi, param_part_vi.hint(isel).?); + } }, - }; - if (passed_vi.hint(isel)) |param_ra| { - try call.paramLiveOut(isel, arg_vi, param_ra); - } else { - var param_part_it = passed_vi.parts(isel); - var arg_part_it = arg_vi.parts(isel); - if (arg_part_it.only()) |_| { - try isel.values.ensureUnusedCapacity(gpa, param_part_it.remaining); - arg_vi.setParts(isel, param_part_it.remaining); - while (param_part_it.next()) |param_part_vi| _ = arg_vi.addPart( - isel, - param_part_vi.get(isel).offset_from_parent, - param_part_vi.size(isel), - ); - param_part_it = passed_vi.parts(isel); - arg_part_it = arg_vi.parts(isel); - } - while (param_part_it.next()) |param_part_vi| { - const arg_part_vi = arg_part_it.next().?; - assert(arg_part_vi.get(isel).offset_from_parent == - param_part_vi.get(isel).offset_from_parent); - assert(arg_part_vi.size(isel) == param_part_vi.size(isel)); - try call.paramLiveOut(isel, arg_part_vi, param_part_vi.hint(isel).?); - } + .stack_slot => |stack_slot| try arg_vi.store(isel, param_ty, stack_slot.base, .{ + .offset = @intCast(stack_slot.offset), + }), + .value, .constant => unreachable, + .address => |address_vi| try call.paramAddress(isel, arg_vi, address_vi.hint(isel).?), } } try call.finishParams(isel); @@ -4828,9 +4863,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory, if (air.next()) |next_air_tag| continue :air_tag next_air_tag; }, - .dbg_stmt => { - if (air.next()) |next_air_tag| continue :air_tag next_air_tag; - }, + .dbg_stmt => if (air.next()) |next_air_tag| continue :air_tag next_air_tag, .dbg_empty_stmt => { try isel.emit(.nop()); if (air.next()) |next_air_tag| continue :air_tag next_air_tag; @@ -7079,6 +7112,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory, } if (air.next()) |next_air_tag| continue :air_tag next_air_tag; }, + .wasm_memory_size, .wasm_memory_grow => unreachable, .cmp_lt_errors_len => { if (isel.live_values.fetchRemove(air.inst_index)) |is_vi| unused: { defer is_vi.value.deref(isel); @@ -7135,16 +7169,266 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory, } if (air.next()) |next_air_tag| continue :air_tag next_air_tag; }, - .inferred_alloc, - .inferred_alloc_comptime, - .int_from_float_safe, - .int_from_float_optimized_safe, - .wasm_memory_size, - .wasm_memory_grow, - .work_item_id, - .work_group_size, - .work_group_id, - => unreachable, + .c_va_arg => { + const maybe_arg_vi = isel.live_values.fetchRemove(air.inst_index); + defer if (maybe_arg_vi) |arg_vi| arg_vi.value.deref(isel); + const ty_op = air.data(air.inst_index).ty_op; + const ty = ty_op.ty.toType(); + var param_it: CallAbiIterator = .init; + const param_vi = try param_it.param(isel, ty); + defer param_vi.?.deref(isel); + const passed_vi = switch (param_vi.?.parent(isel)) { + .unallocated => param_vi.?, + .stack_slot, .value, .constant => unreachable, + .address => |address_vi| address_vi, + }; + const passed_size: u5 = @intCast(passed_vi.alignment(isel).forward(passed_vi.size(isel))); + const passed_is_vector = passed_vi.isVector(isel); + + const va_list_ptr_vi = try isel.use(ty_op.operand); + const va_list_ptr_mat = try va_list_ptr_vi.matReg(isel); + const offs_ra = try isel.allocIntReg(); + defer isel.freeReg(offs_ra); + const stack_ra = try isel.allocIntReg(); + defer isel.freeReg(stack_ra); + + var part_vis: [2]Value.Index = undefined; + var arg_part_ras: [2]?Register.Alias = @splat(null); + const parts_len = parts_len: { + var parts_len: u2 = 0; + var part_it = passed_vi.parts(isel); + while (part_it.next()) |part_vi| : (parts_len += 1) { + part_vis[parts_len] = part_vi; + const arg_vi = maybe_arg_vi orelse continue; + const part_offset, const part_size = part_vi.position(isel); + var arg_part_it = arg_vi.value.field(ty, part_offset, part_size); + const arg_part_vi = try arg_part_it.only(isel); + arg_part_ras[parts_len] = try arg_part_vi.?.defReg(isel); + } + break :parts_len parts_len; + }; + + const done_label = isel.instructions.items.len; + try isel.emit(.str(stack_ra.x(), .{ .unsigned_offset = .{ + .base = va_list_ptr_mat.ra.x(), + .offset = 0, + } })); + try isel.emit(switch (parts_len) { + else => unreachable, + 1 => if (arg_part_ras[0]) |arg_part_ra| switch (part_vis[0].size(isel)) { + else => unreachable, + 1 => if (arg_part_ra.isVector()) .ldr(arg_part_ra.b(), .{ .post_index = .{ + .base = stack_ra.x(), + .index = passed_size, + } }) else switch (part_vis[0].signedness(isel)) { + .signed => .ldrsb(arg_part_ra.w(), .{ .post_index = .{ + .base = stack_ra.x(), + .index = passed_size, + } }), + .unsigned => .ldrb(arg_part_ra.w(), .{ .post_index = .{ + .base = stack_ra.x(), + .index = passed_size, + } }), + }, + 2 => if (arg_part_ra.isVector()) .ldr(arg_part_ra.h(), .{ .post_index = .{ + .base = stack_ra.x(), + .index = passed_size, + } }) else switch (part_vis[0].signedness(isel)) { + .signed => .ldrsh(arg_part_ra.w(), .{ .post_index = .{ + .base = stack_ra.x(), + .index = passed_size, + } }), + .unsigned => .ldrh(arg_part_ra.w(), .{ .post_index = .{ + .base = stack_ra.x(), + .index = passed_size, + } }), + }, + 4 => .ldr(if (arg_part_ra.isVector()) arg_part_ra.s() else arg_part_ra.w(), .{ .post_index = .{ + .base = stack_ra.x(), + .index = passed_size, + } }), + 8 => .ldr(if (arg_part_ra.isVector()) arg_part_ra.d() else arg_part_ra.x(), .{ .post_index = .{ + .base = stack_ra.x(), + .index = passed_size, + } }), + 16 => .ldr(arg_part_ra.q(), .{ .post_index = .{ + .base = stack_ra.x(), + .index = passed_size, + } }), + } else .add(stack_ra.x(), stack_ra.x(), .{ .immediate = passed_size }), + 2 => if (arg_part_ras[0] != null or arg_part_ras[1] != null) .ldp( + @as(Register.Alias, arg_part_ras[0] orelse .zr).x(), + @as(Register.Alias, arg_part_ras[1] orelse .zr).x(), + .{ .post_index = .{ + .base = stack_ra.x(), + .index = passed_size, + } }, + ) else .add(stack_ra.x(), stack_ra.x(), .{ .immediate = passed_size }), + }); + try isel.emit(.ldr(stack_ra.x(), .{ .unsigned_offset = .{ + .base = va_list_ptr_mat.ra.x(), + .offset = 0, + } })); + switch (isel.va_list) { + .other => {}, + .sysv => { + const stack_label = isel.instructions.items.len; + try isel.emit(.b( + @intCast((isel.instructions.items.len + 1 - done_label) << 2), + )); + switch (parts_len) { + else => unreachable, + 1 => if (arg_part_ras[0]) |arg_part_ra| try isel.emit(switch (part_vis[0].size(isel)) { + else => unreachable, + 1 => if (arg_part_ra.isVector()) .ldr(arg_part_ra.b(), .{ .extended_register = .{ + .base = stack_ra.x(), + .index = offs_ra.w(), + .extend = .{ .sxtw = 0 }, + } }) else switch (part_vis[0].signedness(isel)) { + .signed => .ldrsb(arg_part_ra.w(), .{ .extended_register = .{ + .base = stack_ra.x(), + .index = offs_ra.w(), + .extend = .{ .sxtw = 0 }, + } }), + .unsigned => .ldrb(arg_part_ra.w(), .{ .extended_register = .{ + .base = stack_ra.x(), + .index = offs_ra.w(), + .extend = .{ .sxtw = 0 }, + } }), + }, + 2 => if (arg_part_ra.isVector()) .ldr(arg_part_ra.h(), .{ .extended_register = .{ + .base = stack_ra.x(), + .index = offs_ra.w(), + .extend = .{ .sxtw = 0 }, + } }) else switch (part_vis[0].signedness(isel)) { + .signed => .ldrsh(arg_part_ra.w(), .{ .extended_register = .{ + .base = stack_ra.x(), + .index = offs_ra.w(), + .extend = .{ .sxtw = 0 }, + } }), + .unsigned => .ldrh(arg_part_ra.w(), .{ .extended_register = .{ + .base = stack_ra.x(), + .index = offs_ra.w(), + .extend = .{ .sxtw = 0 }, + } }), + }, + 4 => .ldr(if (arg_part_ra.isVector()) arg_part_ra.s() else arg_part_ra.w(), .{ .extended_register = .{ + .base = stack_ra.x(), + .index = offs_ra.w(), + .extend = .{ .sxtw = 0 }, + } }), + 8 => .ldr(if (arg_part_ra.isVector()) arg_part_ra.d() else arg_part_ra.x(), .{ .extended_register = .{ + .base = stack_ra.x(), + .index = offs_ra.w(), + .extend = .{ .sxtw = 0 }, + } }), + 16 => .ldr(arg_part_ra.q(), .{ .extended_register = .{ + .base = stack_ra.x(), + .index = offs_ra.w(), + .extend = .{ .sxtw = 0 }, + } }), + }), + 2 => if (arg_part_ras[0] != null or arg_part_ras[1] != null) { + try isel.emit(.ldp( + @as(Register.Alias, arg_part_ras[0] orelse .zr).x(), + @as(Register.Alias, arg_part_ras[1] orelse .zr).x(), + .{ .base = stack_ra.x() }, + )); + try isel.emit(.add(stack_ra.x(), stack_ra.x(), .{ .extended_register = .{ + .register = offs_ra.w(), + .extend = .{ .sxtw = 0 }, + } })); + }, + } + try isel.emit(.ldr(stack_ra.x(), .{ .unsigned_offset = .{ + .base = va_list_ptr_mat.ra.x(), + .offset = if (passed_is_vector) 16 else 8, + } })); + try isel.emit(.@"b."( + .gt, + @intCast((isel.instructions.items.len + 1 - stack_label) << 2), + )); + try isel.emit(.str(stack_ra.w(), .{ .unsigned_offset = .{ + .base = va_list_ptr_mat.ra.x(), + .offset = if (passed_is_vector) 28 else 24, + } })); + try isel.emit(.adds(stack_ra.w(), offs_ra.w(), .{ .immediate = passed_size })); + try isel.emit(.tbz( + offs_ra.w(), + 31, + @intCast((isel.instructions.items.len + 1 - stack_label) << 2), + )); + try isel.emit(.ldr(offs_ra.w(), .{ .unsigned_offset = .{ + .base = va_list_ptr_mat.ra.x(), + .offset = if (passed_is_vector) 28 else 24, + } })); + }, + } + try va_list_ptr_mat.finish(isel); + if (air.next()) |next_air_tag| continue :air_tag next_air_tag; + }, + .c_va_copy => { + if (isel.live_values.fetchRemove(air.inst_index)) |va_list_vi| { + defer va_list_vi.value.deref(isel); + const ty_op = air.data(air.inst_index).ty_op; + const va_list_ptr_vi = try isel.use(ty_op.operand); + const va_list_ptr_mat = try va_list_ptr_vi.matReg(isel); + _ = try va_list_vi.value.load(isel, ty_op.ty.toType(), va_list_ptr_mat.ra, .{}); + try va_list_ptr_mat.finish(isel); + } + if (air.next()) |next_air_tag| continue :air_tag next_air_tag; + }, + .c_va_end => if (air.next()) |next_air_tag| continue :air_tag next_air_tag, + .c_va_start => { + if (isel.live_values.fetchRemove(air.inst_index)) |va_list_vi| { + defer va_list_vi.value.deref(isel); + const ty = air.data(air.inst_index).ty; + switch (isel.va_list) { + .other => |va_list| if (try va_list_vi.value.defReg(isel)) |va_list_ra| try isel.emit(.add( + va_list_ra.x(), + va_list.base.x(), + .{ .immediate = @intCast(va_list.offset) }, + )), + .sysv => |va_list| { + var vr_offs_it = va_list_vi.value.field(ty, 28, 4); + const vr_offs_vi = try vr_offs_it.only(isel); + if (try vr_offs_vi.?.defReg(isel)) |vr_offs_ra| try isel.movImmediate( + vr_offs_ra.w(), + @as(u32, @bitCast(va_list.__vr_offs)), + ); + var gr_offs_it = va_list_vi.value.field(ty, 24, 4); + const gr_offs_vi = try gr_offs_it.only(isel); + if (try gr_offs_vi.?.defReg(isel)) |gr_offs_ra| try isel.movImmediate( + gr_offs_ra.w(), + @as(u32, @bitCast(va_list.__gr_offs)), + ); + var vr_top_it = va_list_vi.value.field(ty, 16, 8); + const vr_top_vi = try vr_top_it.only(isel); + if (try vr_top_vi.?.defReg(isel)) |vr_top_ra| try isel.emit(.add( + vr_top_ra.x(), + va_list.__vr_top.base.x(), + .{ .immediate = @intCast(va_list.__vr_top.offset) }, + )); + var gr_top_it = va_list_vi.value.field(ty, 8, 8); + const gr_top_vi = try gr_top_it.only(isel); + if (try gr_top_vi.?.defReg(isel)) |gr_top_ra| try isel.emit(.add( + gr_top_ra.x(), + va_list.__gr_top.base.x(), + .{ .immediate = @intCast(va_list.__gr_top.offset) }, + )); + var stack_it = va_list_vi.value.field(ty, 0, 8); + const stack_vi = try stack_it.only(isel); + if (try stack_vi.?.defReg(isel)) |stack_ra| try isel.emit(.add( + stack_ra.x(), + va_list.__stack.base.x(), + .{ .immediate = @intCast(va_list.__stack.offset) }, + )); + }, + } + } + if (air.next()) |next_air_tag| continue :air_tag next_air_tag; + }, + .work_item_id, .work_group_size, .work_group_id => unreachable, } assert(air.body_index == 0); } @@ -7225,7 +7509,7 @@ pub fn verify(isel: *Select, check_values: bool) void { pub fn layout( isel: *Select, incoming: CallAbiIterator, - have_va: bool, + is_sysv_var_args: bool, saved_gra_len: u7, saved_vra_len: u7, mod: *const Package.Module, @@ -7236,8 +7520,6 @@ pub fn layout( wip_mir_log.debug("{f}:\n", .{nav.fqn.fmt(ip)}); const stack_size: u24 = @intCast(InternPool.Alignment.@"16".forward(isel.stack_size)); - const stack_size_lo: u12 = @truncate(stack_size >> 0); - const stack_size_hi: u12 = @truncate(stack_size >> 12); var saves_buf: [10 + 8 + 8 + 2 + 8]struct { class: enum { integer, vector }, @@ -7315,7 +7597,7 @@ pub fn layout( // incoming vr arguments save_ra = if (mod.strip) incoming.nsrn else CallAbiIterator.nsrn_start; - while (save_ra != if (have_va) CallAbiIterator.nsrn_end else incoming.nsrn) : (save_ra = @enumFromInt(@intFromEnum(save_ra) + 1)) { + while (save_ra != if (is_sysv_var_args) CallAbiIterator.nsrn_end else incoming.nsrn) : (save_ra = @enumFromInt(@intFromEnum(save_ra) + 1)) { saves_size = std.mem.alignForward(u10, saves_size, 16); saves_buf[saves_len] = .{ .class = .vector, @@ -7370,7 +7652,7 @@ pub fn layout( 1 => saves_size += 8, } save_ra = if (mod.strip) incoming.ngrn else CallAbiIterator.ngrn_start; - while (save_ra != if (have_va) CallAbiIterator.ngrn_end else incoming.ngrn) : (save_ra = @enumFromInt(@intFromEnum(save_ra) + 1)) { + while (save_ra != if (is_sysv_var_args) CallAbiIterator.ngrn_end else incoming.ngrn) : (save_ra = @enumFromInt(@intFromEnum(save_ra) + 1)) { saves_size = std.mem.alignForward(u10, saves_size, 8); saves_buf[saves_len] = .{ .class = .integer, @@ -7434,6 +7716,8 @@ pub fn layout( .fp else .ip0; + const stack_size_lo: u12 = @truncate(stack_size >> 0); + const stack_size_hi: u12 = @truncate(stack_size >> 12); if (mod.stack_check) { if (stack_size_hi > 2) { try isel.movImmediate(.ip1, stack_size_hi); @@ -7481,6 +7765,7 @@ pub fn layout( if (isel.returns) { try isel.emit(.ret(.lr)); var save_index: usize = 0; + var first_offset: ?u10 = null; while (save_index < saves.len) { if (save_index + 2 <= saves.len and saves[save_index + 1].needs_restore and saves[save_index + 0].class == saves[save_index + 1].class and @@ -7489,46 +7774,51 @@ pub fn layout( try isel.emit(.ldp( saves[save_index + 0].register, saves[save_index + 1].register, - switch (saves[save_index + 0].offset) { - 0 => .{ .post_index = .{ - .base = .sp, - .index = @intCast(saves_size), - } }, - else => |offset| .{ .signed_offset = .{ + if (first_offset) |offset| .{ .signed_offset = .{ + .base = .sp, + .offset = @intCast(saves[save_index + 0].offset - offset), + } } else form: { + first_offset = @intCast(saves[save_index + 0].offset); + break :form .{ .post_index = .{ .base = .sp, - .offset = @intCast(offset), - } }, + .index = @intCast(saves_size - first_offset.?), + } }; }, )); save_index += 2; } else if (saves[save_index].needs_restore) { try isel.emit(.ldr( saves[save_index].register, - switch (saves[save_index].offset) { - 0 => .{ .post_index = .{ - .base = .sp, - .index = @intCast(saves_size), - } }, - else => |offset| .{ .unsigned_offset = .{ + if (first_offset) |offset| .{ .unsigned_offset = .{ + .base = .sp, + .offset = saves[save_index + 0].offset - offset, + } } else form: { + const offset = saves[save_index + 0].offset; + first_offset = offset; + break :form .{ .post_index = .{ .base = .sp, - .offset = @intCast(offset), - } }, + .index = @intCast(saves_size - offset), + } }; }, )); save_index += 1; } else save_index += 1; } - if (isel.stack_align != .@"16" or (stack_size_lo > 0 and stack_size_hi > 0)) { - try isel.emit(switch (frame_record_offset) { - 0 => .add(.sp, .fp, .{ .immediate = 0 }), - else => |offset| .sub(.sp, .fp, .{ .immediate = offset }), - }); + const offset = stack_size + first_offset.?; + const offset_lo: u12 = @truncate(offset >> 0); + const offset_hi: u12 = @truncate(offset >> 12); + if (isel.stack_align != .@"16" or (offset_lo > 0 and offset_hi > 0)) { + const fp_offset = @as(i11, first_offset.?) - frame_record_offset; + try isel.emit(if (fp_offset >= 0) + .add(.sp, .fp, .{ .immediate = @intCast(fp_offset) }) + else + .sub(.sp, .fp, .{ .immediate = @intCast(-fp_offset) })); } else { - if (stack_size_hi > 0) try isel.emit(.add(.sp, .sp, .{ - .shifted_immediate = .{ .immediate = stack_size_hi, .lsl = .@"12" }, + if (offset_hi > 0) try isel.emit(.add(.sp, .sp, .{ + .shifted_immediate = .{ .immediate = offset_hi, .lsl = .@"12" }, })); - if (stack_size_lo > 0) try isel.emit(.add(.sp, .sp, .{ - .immediate = stack_size_lo, + if (offset_lo > 0) try isel.emit(.add(.sp, .sp, .{ + .immediate = offset_lo, })); } wip_mir_log.debug("{f}:\n", .{nav.fqn.fmt(ip)}); @@ -9493,6 +9783,11 @@ pub const Value = struct { return it.vi; } + pub fn peek(it: PartIterator) ?Value.Index { + var it_mut = it; + return it_mut.next(); + } + pub fn only(it: PartIterator) ?Value.Index { return if (it.remaining == 1) it.vi else null; } @@ -11607,6 +11902,16 @@ pub const CallAbiIterator = struct { return wip_vi.ref(isel); } + pub fn nonSysvVarArg(it: *CallAbiIterator, isel: *Select, ty: ZigType) !?Value.Index { + const ngrn = it.ngrn; + defer it.ngrn = ngrn; + it.ngrn = ngrn_end; + const nsrn = it.nsrn; + defer it.nsrn = nsrn; + it.nsrn = nsrn_end; + return it.param(isel, ty); + } + pub fn ret(it: *CallAbiIterator, isel: *Select, ty: ZigType) !?Value.Index { const wip_vi = try it.param(isel, ty) orelse return null; switch (wip_vi.parent(isel)) { diff --git a/src/codegen/aarch64/encoding.zig b/src/codegen/aarch64/encoding.zig index 727b88c729..6ddf46b625 100644 --- a/src/codegen/aarch64/encoding.zig +++ b/src/codegen/aarch64/encoding.zig @@ -10089,26 +10089,26 @@ pub const Instruction = packed union { }, } } } }; }, - .signed_offset => |signed_offset| { - assert(signed_offset.base.format.integer == .doubleword); - return .{ .load_store = .{ .register_pair_offset = .{ .integer = .{ + .pre_index => |pre_index| { + assert(pre_index.base.format.integer == .doubleword); + return .{ .load_store = .{ .register_pair_pre_indexed = .{ .integer = .{ .ldp = .{ .Rt = t1.alias.encode(.{}), - .Rn = signed_offset.base.alias.encode(.{ .sp = true }), + .Rn = pre_index.base.alias.encode(.{ .sp = true }), .Rt2 = t2.alias.encode(.{}), - .imm7 = @intCast(@shrExact(signed_offset.offset, @as(u2, 2) + @intFromEnum(sf))), + .imm7 = @intCast(@shrExact(pre_index.index, @as(u2, 2) + @intFromEnum(sf))), .sf = sf, }, } } } }; }, - .pre_index => |pre_index| { - assert(pre_index.base.format.integer == .doubleword); - return .{ .load_store = .{ .register_pair_pre_indexed = .{ .integer = .{ + .signed_offset => |signed_offset| { + assert(signed_offset.base.format.integer == .doubleword); + return .{ .load_store = .{ .register_pair_offset = .{ .integer = .{ .ldp = .{ .Rt = t1.alias.encode(.{}), - .Rn = pre_index.base.alias.encode(.{ .sp = true }), + .Rn = signed_offset.base.alias.encode(.{ .sp = true }), .Rt2 = t2.alias.encode(.{}), - .imm7 = @intCast(@shrExact(pre_index.index, @as(u2, 2) + @intFromEnum(sf))), + .imm7 = @intCast(@shrExact(signed_offset.offset, @as(u2, 2) + @intFromEnum(sf))), .sf = sf, }, } } } }; @@ -11473,26 +11473,26 @@ pub const Instruction = packed union { }, } } } }; }, - .signed_offset => |signed_offset| { - assert(signed_offset.base.format.integer == .doubleword); - return .{ .load_store = .{ .register_pair_offset = .{ .integer = .{ + .pre_index => |pre_index| { + assert(pre_index.base.format.integer == .doubleword); + return .{ .load_store = .{ .register_pair_pre_indexed = .{ .integer = .{ .stp = .{ .Rt = t1.alias.encode(.{}), - .Rn = signed_offset.base.alias.encode(.{ .sp = true }), + .Rn = pre_index.base.alias.encode(.{ .sp = true }), .Rt2 = t2.alias.encode(.{}), - .imm7 = @intCast(@shrExact(signed_offset.offset, @as(u2, 2) + @intFromEnum(sf))), + .imm7 = @intCast(@shrExact(pre_index.index, @as(u2, 2) + @intFromEnum(sf))), .sf = sf, }, } } } }; }, - .pre_index => |pre_index| { - assert(pre_index.base.format.integer == .doubleword); - return .{ .load_store = .{ .register_pair_pre_indexed = .{ .integer = .{ + .signed_offset => |signed_offset| { + assert(signed_offset.base.format.integer == .doubleword); + return .{ .load_store = .{ .register_pair_offset = .{ .integer = .{ .stp = .{ .Rt = t1.alias.encode(.{}), - .Rn = pre_index.base.alias.encode(.{ .sp = true }), + .Rn = signed_offset.base.alias.encode(.{ .sp = true }), .Rt2 = t2.alias.encode(.{}), - .imm7 = @intCast(@shrExact(pre_index.index, @as(u2, 2) + @intFromEnum(sf))), + .imm7 = @intCast(@shrExact(signed_offset.offset, @as(u2, 2) + @intFromEnum(sf))), .sf = sf, }, } } } }; diff --git a/test/behavior/var_args.zig b/test/behavior/var_args.zig index 36cebd5d77..bd06404149 100644 --- a/test/behavior/var_args.zig +++ b/test/behavior/var_args.zig @@ -92,7 +92,6 @@ fn doNothingWithFirstArg(args: anytype) void { } test "simple variadic function" { - 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; // TODO if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO @@ -154,7 +153,6 @@ test "simple variadic function" { } test "coerce reference to var arg" { - 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; // TODO if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO @@ -234,7 +232,6 @@ test "variadic functions" { } test "copy VaList" { - if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; @@ -269,7 +266,6 @@ test "copy VaList" { } test "unused VaList arg" { - if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; -- cgit v1.2.3