| ... | @@ -28,10 +28,15 @@ literal_relocs: std.ArrayListUnmanaged(codegen.aarch64.Mir.Reloc.Literal), | ... | @@ -28,10 +28,15 @@ literal_relocs: std.ArrayListUnmanaged(codegen.aarch64.Mir.Reloc.Literal), |
| 28 | | 28 | |
| 29 | // Stack Frame | 29 | // Stack Frame |
| 30 | returns: bool, | 30 | returns: bool, |
| 31 | va_list: struct { | 31 | va_list: union(enum) { |
| 32 | __stack: Value.Indirect, | 32 | other: Value.Indirect, |
| 33 | __gr_top: Value.Indirect, | 33 | sysv: struct { |
| 34 | __vr_top: Value.Indirect, | 34 | __stack: Value.Indirect, |
| | 35 | __gr_top: Value.Indirect, |
| | 36 | __vr_top: Value.Indirect, |
| | 37 | __gr_offs: i32, |
| | 38 | __vr_offs: i32, |
| | 39 | }, |
| 35 | }, | 40 | }, |
| 36 | stack_size: u24, | 41 | stack_size: u24, |
| 37 | stack_align: InternPool.Alignment, | 42 | stack_align: InternPool.Alignment, |
| ... | @@ -408,13 +413,7 @@ pub fn analyze(isel: *Select, air_body: []const Air.Inst.Index) !void { | ... | @@ -408,13 +413,7 @@ pub fn analyze(isel: *Select, air_body: []const Air.Inst.Index) !void { |
| 408 | | 413 | |
| 409 | air_body_index += 1; | 414 | air_body_index += 1; |
| 410 | }, | 415 | }, |
| 411 | .breakpoint, | 416 | .breakpoint, .dbg_stmt, .dbg_empty_stmt, .dbg_var_ptr, .dbg_var_val, .dbg_arg_inline, .c_va_end => { |
| 412 | .dbg_stmt, | | |
| 413 | .dbg_empty_stmt, | | |
| 414 | .dbg_var_ptr, | | |
| 415 | .dbg_var_val, | | |
| 416 | .dbg_arg_inline, | | |
| 417 | => { | | |
| 418 | air_body_index += 1; | 417 | air_body_index += 1; |
| 419 | air_inst_index = air_body[air_body_index]; | 418 | air_inst_index = air_body[air_body_index]; |
| 420 | continue :air_tag air_tags[@intFromEnum(air_inst_index)]; | 419 | 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 { | ... | @@ -428,23 +427,43 @@ pub fn analyze(isel: *Select, air_body: []const Air.Inst.Index) !void { |
| 428 | const extra = isel.air.extraData(Air.Call, pl_op.payload); | 427 | const extra = isel.air.extraData(Air.Call, pl_op.payload); |
| 429 | const args: []const Air.Inst.Ref = @ptrCast(isel.air.extra.items[extra.end..][0..extra.data.args_len]); | 428 | const args: []const Air.Inst.Ref = @ptrCast(isel.air.extra.items[extra.end..][0..extra.data.args_len]); |
| 430 | isel.saved_registers.insert(.lr); | 429 | isel.saved_registers.insert(.lr); |
| | 430 | const callee_ty = isel.air.typeOf(pl_op.operand, ip); |
| | 431 | const func_info = switch (ip.indexToKey(callee_ty.toIntern())) { |
| | 432 | else => unreachable, |
| | 433 | .func_type => |func_type| func_type, |
| | 434 | .ptr_type => |ptr_type| ip.indexToKey(ptr_type.child).func_type, |
| | 435 | }; |
| 431 | | 436 | |
| 432 | try isel.analyzeUse(pl_op.operand); | 437 | try isel.analyzeUse(pl_op.operand); |
| 433 | var param_it: CallAbiIterator = .init; | 438 | var param_it: CallAbiIterator = .init; |
| 434 | for (args) |arg| { | 439 | for (args, 0..) |arg, arg_index| { |
| 435 | const restore_values_len = isel.values.items.len; | 440 | const restore_values_len = isel.values.items.len; |
| 436 | defer isel.values.shrinkRetainingCapacity(restore_values_len); | 441 | defer isel.values.shrinkRetainingCapacity(restore_values_len); |
| 437 | const param_vi = try param_it.param(isel, isel.air.typeOf(arg, ip)) orelse continue; | 442 | const param_vi = param_vi: { |
| 438 | const param_parent = param_vi.parent(isel); | 443 | const param_ty = isel.air.typeOf(arg, ip); |
| 439 | switch (switch (param_parent) { | 444 | if (arg_index >= func_info.param_types.len) { |
| 440 | .unallocated, .stack_slot => param_parent, | 445 | assert(func_info.is_var_args); |
| | 446 | switch (isel.va_list) { |
| | 447 | .other => break :param_vi try param_it.nonSysvVarArg(isel, param_ty), |
| | 448 | .sysv => {}, |
| | 449 | } |
| | 450 | } |
| | 451 | break :param_vi try param_it.param(isel, param_ty); |
| | 452 | } orelse continue; |
| | 453 | defer param_vi.deref(isel); |
| | 454 | const passed_vi = switch (param_vi.parent(isel)) { |
| | 455 | .unallocated, .stack_slot => param_vi, |
| 441 | .value, .constant => unreachable, | 456 | .value, .constant => unreachable, |
| 442 | .address => |address_vi| address_vi.parent(isel), | 457 | .address => |address_vi| address_vi, |
| 443 | }) { | 458 | }; |
| | 459 | switch (passed_vi.parent(isel)) { |
| 444 | .unallocated => {}, | 460 | .unallocated => {}, |
| 445 | .stack_slot => |stack_slot| { | 461 | .stack_slot => |stack_slot| { |
| 446 | assert(stack_slot.base == .sp); | 462 | assert(stack_slot.base == .sp); |
| 447 | isel.stack_size = @max(isel.stack_size, stack_slot.offset); | 463 | isel.stack_size = @max( |
| | 464 | isel.stack_size, |
| | 465 | stack_slot.offset + @as(u24, @intCast(passed_vi.size(isel))), |
| | 466 | ); |
| 448 | }, | 467 | }, |
| 449 | .value, .constant, .address => unreachable, | 468 | .value, .constant, .address => unreachable, |
| 450 | } | 469 | } |
| ... | @@ -802,7 +821,7 @@ pub fn analyze(isel: *Select, air_body: []const Air.Inst.Index) !void { | ... | @@ -802,7 +821,7 @@ pub fn analyze(isel: *Select, air_body: []const Air.Inst.Index) !void { |
| 802 | air_inst_index = air_body[air_body_index]; | 821 | air_inst_index = air_body[air_body_index]; |
| 803 | continue :air_tag air_tags[@intFromEnum(air_inst_index)]; | 822 | continue :air_tag air_tags[@intFromEnum(air_inst_index)]; |
| 804 | }, | 823 | }, |
| 805 | .set_err_return_trace, .c_va_end => { | 824 | .set_err_return_trace => { |
| 806 | const un_op = air_data[@intFromEnum(air_inst_index)].un_op; | 825 | const un_op = air_data[@intFromEnum(air_inst_index)].un_op; |
| 807 | | 826 | |
| 808 | try isel.analyzeUse(un_op); | 827 | try isel.analyzeUse(un_op); |
| ... | @@ -2474,6 +2493,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory, | ... | @@ -2474,6 +2493,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory, |
| 2474 | } | 2493 | } |
| 2475 | if (air.next()) |next_air_tag| continue :air_tag next_air_tag; | 2494 | if (air.next()) |next_air_tag| continue :air_tag next_air_tag; |
| 2476 | }, | 2495 | }, |
| | 2496 | .inferred_alloc, .inferred_alloc_comptime => unreachable, |
| 2477 | .assembly => { | 2497 | .assembly => { |
| 2478 | const ty_pl = air.data(air.inst_index).ty_pl; | 2498 | const ty_pl = air.data(air.inst_index).ty_pl; |
| 2479 | const extra = isel.air.extraData(Air.Asm, ty_pl.payload); | 2499 | 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, | ... | @@ -3389,6 +3409,12 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory, |
| 3389 | const pl_op = air.data(air.inst_index).pl_op; | 3409 | const pl_op = air.data(air.inst_index).pl_op; |
| 3390 | const extra = isel.air.extraData(Air.Call, pl_op.payload); | 3410 | const extra = isel.air.extraData(Air.Call, pl_op.payload); |
| 3391 | const args: []const Air.Inst.Ref = @ptrCast(isel.air.extra.items[extra.end..][0..extra.data.args_len]); | 3411 | const args: []const Air.Inst.Ref = @ptrCast(isel.air.extra.items[extra.end..][0..extra.data.args_len]); |
| | 3412 | const callee_ty = isel.air.typeOf(pl_op.operand, ip); |
| | 3413 | const func_info = switch (ip.indexToKey(callee_ty.toIntern())) { |
| | 3414 | else => unreachable, |
| | 3415 | .func_type => |func_type| func_type, |
| | 3416 | .ptr_type => |ptr_type| ip.indexToKey(ptr_type.child).func_type, |
| | 3417 | }; |
| 3392 | | 3418 | |
| 3393 | try call.prepareReturn(isel); | 3419 | try call.prepareReturn(isel); |
| 3394 | const maybe_def_ret_vi = isel.live_values.fetchRemove(air.inst_index); | 3420 | 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, | ... | @@ -3455,41 +3481,50 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory, |
| 3455 | ret_addr_vi.hint(isel).?, | 3481 | ret_addr_vi.hint(isel).?, |
| 3456 | ); | 3482 | ); |
| 3457 | var param_it: CallAbiIterator = .init; | 3483 | var param_it: CallAbiIterator = .init; |
| 3458 | for (args) |arg| { | 3484 | for (args, 0..) |arg, arg_index| { |
| 3459 | const param_vi = try param_it.param(isel, isel.air.typeOf(arg, ip)) orelse continue; | 3485 | const param_ty = isel.air.typeOf(arg, ip); |
| | 3486 | const param_vi = param_vi: { |
| | 3487 | if (arg_index >= func_info.param_types.len) { |
| | 3488 | assert(func_info.is_var_args); |
| | 3489 | switch (isel.va_list) { |
| | 3490 | .other => break :param_vi try param_it.nonSysvVarArg(isel, param_ty), |
| | 3491 | .sysv => {}, |
| | 3492 | } |
| | 3493 | } |
| | 3494 | break :param_vi try param_it.param(isel, param_ty); |
| | 3495 | } orelse continue; |
| 3460 | defer param_vi.deref(isel); | 3496 | defer param_vi.deref(isel); |
| 3461 | const arg_vi = try isel.use(arg); | 3497 | const arg_vi = try isel.use(arg); |
| 3462 | const passed_vi = switch (param_vi.parent(isel)) { | 3498 | switch (param_vi.parent(isel)) { |
| 3463 | .unallocated, .stack_slot => param_vi, | 3499 | .unallocated => if (param_vi.hint(isel)) |param_ra| { |
| 3464 | .value, .constant => unreachable, | 3500 | try call.paramLiveOut(isel, arg_vi, param_ra); |
| 3465 | .address => |address_vi| { | 3501 | } else { |
| 3466 | try call.paramAddress(isel, arg_vi, address_vi.hint(isel).?); | 3502 | var param_part_it = param_vi.parts(isel); |
| 3467 | continue; | 3503 | var arg_part_it = arg_vi.parts(isel); |
| | 3504 | if (arg_part_it.only()) |_| { |
| | 3505 | try isel.values.ensureUnusedCapacity(gpa, param_part_it.remaining); |
| | 3506 | arg_vi.setParts(isel, param_part_it.remaining); |
| | 3507 | while (param_part_it.next()) |param_part_vi| _ = arg_vi.addPart( |
| | 3508 | isel, |
| | 3509 | param_part_vi.get(isel).offset_from_parent, |
| | 3510 | param_part_vi.size(isel), |
| | 3511 | ); |
| | 3512 | param_part_it = param_vi.parts(isel); |
| | 3513 | arg_part_it = arg_vi.parts(isel); |
| | 3514 | } |
| | 3515 | while (param_part_it.next()) |param_part_vi| { |
| | 3516 | const arg_part_vi = arg_part_it.next().?; |
| | 3517 | assert(arg_part_vi.get(isel).offset_from_parent == |
| | 3518 | param_part_vi.get(isel).offset_from_parent); |
| | 3519 | assert(arg_part_vi.size(isel) == param_part_vi.size(isel)); |
| | 3520 | try call.paramLiveOut(isel, arg_part_vi, param_part_vi.hint(isel).?); |
| | 3521 | } |
| 3468 | }, | 3522 | }, |
| 3469 | }; | 3523 | .stack_slot => |stack_slot| try arg_vi.store(isel, param_ty, stack_slot.base, .{ |
| 3470 | if (passed_vi.hint(isel)) |param_ra| { | 3524 | .offset = @intCast(stack_slot.offset), |
| 3471 | try call.paramLiveOut(isel, arg_vi, param_ra); | 3525 | }), |
| 3472 | } else { | 3526 | .value, .constant => unreachable, |
| 3473 | var param_part_it = passed_vi.parts(isel); | 3527 | .address => |address_vi| try call.paramAddress(isel, arg_vi, address_vi.hint(isel).?), |
| 3474 | var arg_part_it = arg_vi.parts(isel); | | |
| 3475 | if (arg_part_it.only()) |_| { | | |
| 3476 | try isel.values.ensureUnusedCapacity(gpa, param_part_it.remaining); | | |
| 3477 | arg_vi.setParts(isel, param_part_it.remaining); | | |
| 3478 | while (param_part_it.next()) |param_part_vi| _ = arg_vi.addPart( | | |
| 3479 | isel, | | |
| 3480 | param_part_vi.get(isel).offset_from_parent, | | |
| 3481 | param_part_vi.size(isel), | | |
| 3482 | ); | | |
| 3483 | param_part_it = passed_vi.parts(isel); | | |
| 3484 | arg_part_it = arg_vi.parts(isel); | | |
| 3485 | } | | |
| 3486 | while (param_part_it.next()) |param_part_vi| { | | |
| 3487 | const arg_part_vi = arg_part_it.next().?; | | |
| 3488 | assert(arg_part_vi.get(isel).offset_from_parent == | | |
| 3489 | param_part_vi.get(isel).offset_from_parent); | | |
| 3490 | assert(arg_part_vi.size(isel) == param_part_vi.size(isel)); | | |
| 3491 | try call.paramLiveOut(isel, arg_part_vi, param_part_vi.hint(isel).?); | | |
| 3492 | } | | |
| 3493 | } | 3528 | } |
| 3494 | } | 3529 | } |
| 3495 | try call.finishParams(isel); | 3530 | try call.finishParams(isel); |
| ... | @@ -4828,9 +4863,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory, | ... | @@ -4828,9 +4863,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory, |
| 4828 | | 4863 | |
| 4829 | if (air.next()) |next_air_tag| continue :air_tag next_air_tag; | 4864 | if (air.next()) |next_air_tag| continue :air_tag next_air_tag; |
| 4830 | }, | 4865 | }, |
| 4831 | .dbg_stmt => { | 4866 | .dbg_stmt => if (air.next()) |next_air_tag| continue :air_tag next_air_tag, |
| 4832 | if (air.next()) |next_air_tag| continue :air_tag next_air_tag; | | |
| 4833 | }, | | |
| 4834 | .dbg_empty_stmt => { | 4867 | .dbg_empty_stmt => { |
| 4835 | try isel.emit(.nop()); | 4868 | try isel.emit(.nop()); |
| 4836 | if (air.next()) |next_air_tag| continue :air_tag next_air_tag; | 4869 | 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, | ... | @@ -7079,6 +7112,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory, |
| 7079 | } | 7112 | } |
| 7080 | if (air.next()) |next_air_tag| continue :air_tag next_air_tag; | 7113 | if (air.next()) |next_air_tag| continue :air_tag next_air_tag; |
| 7081 | }, | 7114 | }, |
| | 7115 | .wasm_memory_size, .wasm_memory_grow => unreachable, |
| 7082 | .cmp_lt_errors_len => { | 7116 | .cmp_lt_errors_len => { |
| 7083 | if (isel.live_values.fetchRemove(air.inst_index)) |is_vi| unused: { | 7117 | if (isel.live_values.fetchRemove(air.inst_index)) |is_vi| unused: { |
| 7084 | defer is_vi.value.deref(isel); | 7118 | defer is_vi.value.deref(isel); |
| ... | @@ -7135,16 +7169,266 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory, | ... | @@ -7135,16 +7169,266 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory, |
| 7135 | } | 7169 | } |
| 7136 | if (air.next()) |next_air_tag| continue :air_tag next_air_tag; | 7170 | if (air.next()) |next_air_tag| continue :air_tag next_air_tag; |
| 7137 | }, | 7171 | }, |
| 7138 | .inferred_alloc, | 7172 | .c_va_arg => { |
| 7139 | .inferred_alloc_comptime, | 7173 | const maybe_arg_vi = isel.live_values.fetchRemove(air.inst_index); |
| 7140 | .int_from_float_safe, | 7174 | defer if (maybe_arg_vi) |arg_vi| arg_vi.value.deref(isel); |
| 7141 | .int_from_float_optimized_safe, | 7175 | const ty_op = air.data(air.inst_index).ty_op; |
| 7142 | .wasm_memory_size, | 7176 | const ty = ty_op.ty.toType(); |
| 7143 | .wasm_memory_grow, | 7177 | var param_it: CallAbiIterator = .init; |
| 7144 | .work_item_id, | 7178 | const param_vi = try param_it.param(isel, ty); |
| 7145 | .work_group_size, | 7179 | defer param_vi.?.deref(isel); |
| 7146 | .work_group_id, | 7180 | const passed_vi = switch (param_vi.?.parent(isel)) { |
| 7147 | => unreachable, | 7181 | .unallocated => param_vi.?, |
| | 7182 | .stack_slot, .value, .constant => unreachable, |
| | 7183 | .address => |address_vi| address_vi, |
| | 7184 | }; |
| | 7185 | const passed_size: u5 = @intCast(passed_vi.alignment(isel).forward(passed_vi.size(isel))); |
| | 7186 | const passed_is_vector = passed_vi.isVector(isel); |
| | 7187 | |
| | 7188 | const va_list_ptr_vi = try isel.use(ty_op.operand); |
| | 7189 | const va_list_ptr_mat = try va_list_ptr_vi.matReg(isel); |
| | 7190 | const offs_ra = try isel.allocIntReg(); |
| | 7191 | defer isel.freeReg(offs_ra); |
| | 7192 | const stack_ra = try isel.allocIntReg(); |
| | 7193 | defer isel.freeReg(stack_ra); |
| | 7194 | |
| | 7195 | var part_vis: [2]Value.Index = undefined; |
| | 7196 | var arg_part_ras: [2]?Register.Alias = @splat(null); |
| | 7197 | const parts_len = parts_len: { |
| | 7198 | var parts_len: u2 = 0; |
| | 7199 | var part_it = passed_vi.parts(isel); |
| | 7200 | while (part_it.next()) |part_vi| : (parts_len += 1) { |
| | 7201 | part_vis[parts_len] = part_vi; |
| | 7202 | const arg_vi = maybe_arg_vi orelse continue; |
| | 7203 | const part_offset, const part_size = part_vi.position(isel); |
| | 7204 | var arg_part_it = arg_vi.value.field(ty, part_offset, part_size); |
| | 7205 | const arg_part_vi = try arg_part_it.only(isel); |
| | 7206 | arg_part_ras[parts_len] = try arg_part_vi.?.defReg(isel); |
| | 7207 | } |
| | 7208 | break :parts_len parts_len; |
| | 7209 | }; |
| | 7210 | |
| | 7211 | const done_label = isel.instructions.items.len; |
| | 7212 | try isel.emit(.str(stack_ra.x(), .{ .unsigned_offset = .{ |
| | 7213 | .base = va_list_ptr_mat.ra.x(), |
| | 7214 | .offset = 0, |
| | 7215 | } })); |
| | 7216 | try isel.emit(switch (parts_len) { |
| | 7217 | else => unreachable, |
| | 7218 | 1 => if (arg_part_ras[0]) |arg_part_ra| switch (part_vis[0].size(isel)) { |
| | 7219 | else => unreachable, |
| | 7220 | 1 => if (arg_part_ra.isVector()) .ldr(arg_part_ra.b(), .{ .post_index = .{ |
| | 7221 | .base = stack_ra.x(), |
| | 7222 | .index = passed_size, |
| | 7223 | } }) else switch (part_vis[0].signedness(isel)) { |
| | 7224 | .signed => .ldrsb(arg_part_ra.w(), .{ .post_index = .{ |
| | 7225 | .base = stack_ra.x(), |
| | 7226 | .index = passed_size, |
| | 7227 | } }), |
| | 7228 | .unsigned => .ldrb(arg_part_ra.w(), .{ .post_index = .{ |
| | 7229 | .base = stack_ra.x(), |
| | 7230 | .index = passed_size, |
| | 7231 | } }), |
| | 7232 | }, |
| | 7233 | 2 => if (arg_part_ra.isVector()) .ldr(arg_part_ra.h(), .{ .post_index = .{ |
| | 7234 | .base = stack_ra.x(), |
| | 7235 | .index = passed_size, |
| | 7236 | } }) else switch (part_vis[0].signedness(isel)) { |
| | 7237 | .signed => .ldrsh(arg_part_ra.w(), .{ .post_index = .{ |
| | 7238 | .base = stack_ra.x(), |
| | 7239 | .index = passed_size, |
| | 7240 | } }), |
| | 7241 | .unsigned => .ldrh(arg_part_ra.w(), .{ .post_index = .{ |
| | 7242 | .base = stack_ra.x(), |
| | 7243 | .index = passed_size, |
| | 7244 | } }), |
| | 7245 | }, |
| | 7246 | 4 => .ldr(if (arg_part_ra.isVector()) arg_part_ra.s() else arg_part_ra.w(), .{ .post_index = .{ |
| | 7247 | .base = stack_ra.x(), |
| | 7248 | .index = passed_size, |
| | 7249 | } }), |
| | 7250 | 8 => .ldr(if (arg_part_ra.isVector()) arg_part_ra.d() else arg_part_ra.x(), .{ .post_index = .{ |
| | 7251 | .base = stack_ra.x(), |
| | 7252 | .index = passed_size, |
| | 7253 | } }), |
| | 7254 | 16 => .ldr(arg_part_ra.q(), .{ .post_index = .{ |
| | 7255 | .base = stack_ra.x(), |
| | 7256 | .index = passed_size, |
| | 7257 | } }), |
| | 7258 | } else .add(stack_ra.x(), stack_ra.x(), .{ .immediate = passed_size }), |
| | 7259 | 2 => if (arg_part_ras[0] != null or arg_part_ras[1] != null) .ldp( |
| | 7260 | @as(Register.Alias, arg_part_ras[0] orelse .zr).x(), |
| | 7261 | @as(Register.Alias, arg_part_ras[1] orelse .zr).x(), |
| | 7262 | .{ .post_index = .{ |
| | 7263 | .base = stack_ra.x(), |
| | 7264 | .index = passed_size, |
| | 7265 | } }, |
| | 7266 | ) else .add(stack_ra.x(), stack_ra.x(), .{ .immediate = passed_size }), |
| | 7267 | }); |
| | 7268 | try isel.emit(.ldr(stack_ra.x(), .{ .unsigned_offset = .{ |
| | 7269 | .base = va_list_ptr_mat.ra.x(), |
| | 7270 | .offset = 0, |
| | 7271 | } })); |
| | 7272 | switch (isel.va_list) { |
| | 7273 | .other => {}, |
| | 7274 | .sysv => { |
| | 7275 | const stack_label = isel.instructions.items.len; |
| | 7276 | try isel.emit(.b( |
| | 7277 | @intCast((isel.instructions.items.len + 1 - done_label) << 2), |
| | 7278 | )); |
| | 7279 | switch (parts_len) { |
| | 7280 | else => unreachable, |
| | 7281 | 1 => if (arg_part_ras[0]) |arg_part_ra| try isel.emit(switch (part_vis[0].size(isel)) { |
| | 7282 | else => unreachable, |
| | 7283 | 1 => if (arg_part_ra.isVector()) .ldr(arg_part_ra.b(), .{ .extended_register = .{ |
| | 7284 | .base = stack_ra.x(), |
| | 7285 | .index = offs_ra.w(), |
| | 7286 | .extend = .{ .sxtw = 0 }, |
| | 7287 | } }) else switch (part_vis[0].signedness(isel)) { |
| | 7288 | .signed => .ldrsb(arg_part_ra.w(), .{ .extended_register = .{ |
| | 7289 | .base = stack_ra.x(), |
| | 7290 | .index = offs_ra.w(), |
| | 7291 | .extend = .{ .sxtw = 0 }, |
| | 7292 | } }), |
| | 7293 | .unsigned => .ldrb(arg_part_ra.w(), .{ .extended_register = .{ |
| | 7294 | .base = stack_ra.x(), |
| | 7295 | .index = offs_ra.w(), |
| | 7296 | .extend = .{ .sxtw = 0 }, |
| | 7297 | } }), |
| | 7298 | }, |
| | 7299 | 2 => if (arg_part_ra.isVector()) .ldr(arg_part_ra.h(), .{ .extended_register = .{ |
| | 7300 | .base = stack_ra.x(), |
| | 7301 | .index = offs_ra.w(), |
| | 7302 | .extend = .{ .sxtw = 0 }, |
| | 7303 | } }) else switch (part_vis[0].signedness(isel)) { |
| | 7304 | .signed => .ldrsh(arg_part_ra.w(), .{ .extended_register = .{ |
| | 7305 | .base = stack_ra.x(), |
| | 7306 | .index = offs_ra.w(), |
| | 7307 | .extend = .{ .sxtw = 0 }, |
| | 7308 | } }), |
| | 7309 | .unsigned => .ldrh(arg_part_ra.w(), .{ .extended_register = .{ |
| | 7310 | .base = stack_ra.x(), |
| | 7311 | .index = offs_ra.w(), |
| | 7312 | .extend = .{ .sxtw = 0 }, |
| | 7313 | } }), |
| | 7314 | }, |
| | 7315 | 4 => .ldr(if (arg_part_ra.isVector()) arg_part_ra.s() else arg_part_ra.w(), .{ .extended_register = .{ |
| | 7316 | .base = stack_ra.x(), |
| | 7317 | .index = offs_ra.w(), |
| | 7318 | .extend = .{ .sxtw = 0 }, |
| | 7319 | } }), |
| | 7320 | 8 => .ldr(if (arg_part_ra.isVector()) arg_part_ra.d() else arg_part_ra.x(), .{ .extended_register = .{ |
| | 7321 | .base = stack_ra.x(), |
| | 7322 | .index = offs_ra.w(), |
| | 7323 | .extend = .{ .sxtw = 0 }, |
| | 7324 | } }), |
| | 7325 | 16 => .ldr(arg_part_ra.q(), .{ .extended_register = .{ |
| | 7326 | .base = stack_ra.x(), |
| | 7327 | .index = offs_ra.w(), |
| | 7328 | .extend = .{ .sxtw = 0 }, |
| | 7329 | } }), |
| | 7330 | }), |
| | 7331 | 2 => if (arg_part_ras[0] != null or arg_part_ras[1] != null) { |
| | 7332 | try isel.emit(.ldp( |
| | 7333 | @as(Register.Alias, arg_part_ras[0] orelse .zr).x(), |
| | 7334 | @as(Register.Alias, arg_part_ras[1] orelse .zr).x(), |
| | 7335 | .{ .base = stack_ra.x() }, |
| | 7336 | )); |
| | 7337 | try isel.emit(.add(stack_ra.x(), stack_ra.x(), .{ .extended_register = .{ |
| | 7338 | .register = offs_ra.w(), |
| | 7339 | .extend = .{ .sxtw = 0 }, |
| | 7340 | } })); |
| | 7341 | }, |
| | 7342 | } |
| | 7343 | try isel.emit(.ldr(stack_ra.x(), .{ .unsigned_offset = .{ |
| | 7344 | .base = va_list_ptr_mat.ra.x(), |
| | 7345 | .offset = if (passed_is_vector) 16 else 8, |
| | 7346 | } })); |
| | 7347 | try isel.emit(.@"b."( |
| | 7348 | .gt, |
| | 7349 | @intCast((isel.instructions.items.len + 1 - stack_label) << 2), |
| | 7350 | )); |
| | 7351 | try isel.emit(.str(stack_ra.w(), .{ .unsigned_offset = .{ |
| | 7352 | .base = va_list_ptr_mat.ra.x(), |
| | 7353 | .offset = if (passed_is_vector) 28 else 24, |
| | 7354 | } })); |
| | 7355 | try isel.emit(.adds(stack_ra.w(), offs_ra.w(), .{ .immediate = passed_size })); |
| | 7356 | try isel.emit(.tbz( |
| | 7357 | offs_ra.w(), |
| | 7358 | 31, |
| | 7359 | @intCast((isel.instructions.items.len + 1 - stack_label) << 2), |
| | 7360 | )); |
| | 7361 | try isel.emit(.ldr(offs_ra.w(), .{ .unsigned_offset = .{ |
| | 7362 | .base = va_list_ptr_mat.ra.x(), |
| | 7363 | .offset = if (passed_is_vector) 28 else 24, |
| | 7364 | } })); |
| | 7365 | }, |
| | 7366 | } |
| | 7367 | try va_list_ptr_mat.finish(isel); |
| | 7368 | if (air.next()) |next_air_tag| continue :air_tag next_air_tag; |
| | 7369 | }, |
| | 7370 | .c_va_copy => { |
| | 7371 | if (isel.live_values.fetchRemove(air.inst_index)) |va_list_vi| { |
| | 7372 | defer va_list_vi.value.deref(isel); |
| | 7373 | const ty_op = air.data(air.inst_index).ty_op; |
| | 7374 | const va_list_ptr_vi = try isel.use(ty_op.operand); |
| | 7375 | const va_list_ptr_mat = try va_list_ptr_vi.matReg(isel); |
| | 7376 | _ = try va_list_vi.value.load(isel, ty_op.ty.toType(), va_list_ptr_mat.ra, .{}); |
| | 7377 | try va_list_ptr_mat.finish(isel); |
| | 7378 | } |
| | 7379 | if (air.next()) |next_air_tag| continue :air_tag next_air_tag; |
| | 7380 | }, |
| | 7381 | .c_va_end => if (air.next()) |next_air_tag| continue :air_tag next_air_tag, |
| | 7382 | .c_va_start => { |
| | 7383 | if (isel.live_values.fetchRemove(air.inst_index)) |va_list_vi| { |
| | 7384 | defer va_list_vi.value.deref(isel); |
| | 7385 | const ty = air.data(air.inst_index).ty; |
| | 7386 | switch (isel.va_list) { |
| | 7387 | .other => |va_list| if (try va_list_vi.value.defReg(isel)) |va_list_ra| try isel.emit(.add( |
| | 7388 | va_list_ra.x(), |
| | 7389 | va_list.base.x(), |
| | 7390 | .{ .immediate = @intCast(va_list.offset) }, |
| | 7391 | )), |
| | 7392 | .sysv => |va_list| { |
| | 7393 | var vr_offs_it = va_list_vi.value.field(ty, 28, 4); |
| | 7394 | const vr_offs_vi = try vr_offs_it.only(isel); |
| | 7395 | if (try vr_offs_vi.?.defReg(isel)) |vr_offs_ra| try isel.movImmediate( |
| | 7396 | vr_offs_ra.w(), |
| | 7397 | @as(u32, @bitCast(va_list.__vr_offs)), |
| | 7398 | ); |
| | 7399 | var gr_offs_it = va_list_vi.value.field(ty, 24, 4); |
| | 7400 | const gr_offs_vi = try gr_offs_it.only(isel); |
| | 7401 | if (try gr_offs_vi.?.defReg(isel)) |gr_offs_ra| try isel.movImmediate( |
| | 7402 | gr_offs_ra.w(), |
| | 7403 | @as(u32, @bitCast(va_list.__gr_offs)), |
| | 7404 | ); |
| | 7405 | var vr_top_it = va_list_vi.value.field(ty, 16, 8); |
| | 7406 | const vr_top_vi = try vr_top_it.only(isel); |
| | 7407 | if (try vr_top_vi.?.defReg(isel)) |vr_top_ra| try isel.emit(.add( |
| | 7408 | vr_top_ra.x(), |
| | 7409 | va_list.__vr_top.base.x(), |
| | 7410 | .{ .immediate = @intCast(va_list.__vr_top.offset) }, |
| | 7411 | )); |
| | 7412 | var gr_top_it = va_list_vi.value.field(ty, 8, 8); |
| | 7413 | const gr_top_vi = try gr_top_it.only(isel); |
| | 7414 | if (try gr_top_vi.?.defReg(isel)) |gr_top_ra| try isel.emit(.add( |
| | 7415 | gr_top_ra.x(), |
| | 7416 | va_list.__gr_top.base.x(), |
| | 7417 | .{ .immediate = @intCast(va_list.__gr_top.offset) }, |
| | 7418 | )); |
| | 7419 | var stack_it = va_list_vi.value.field(ty, 0, 8); |
| | 7420 | const stack_vi = try stack_it.only(isel); |
| | 7421 | if (try stack_vi.?.defReg(isel)) |stack_ra| try isel.emit(.add( |
| | 7422 | stack_ra.x(), |
| | 7423 | va_list.__stack.base.x(), |
| | 7424 | .{ .immediate = @intCast(va_list.__stack.offset) }, |
| | 7425 | )); |
| | 7426 | }, |
| | 7427 | } |
| | 7428 | } |
| | 7429 | if (air.next()) |next_air_tag| continue :air_tag next_air_tag; |
| | 7430 | }, |
| | 7431 | .work_item_id, .work_group_size, .work_group_id => unreachable, |
| 7148 | } | 7432 | } |
| 7149 | assert(air.body_index == 0); | 7433 | assert(air.body_index == 0); |
| 7150 | } | 7434 | } |
| ... | @@ -7225,7 +7509,7 @@ pub fn verify(isel: *Select, check_values: bool) void { | ... | @@ -7225,7 +7509,7 @@ pub fn verify(isel: *Select, check_values: bool) void { |
| 7225 | pub fn layout( | 7509 | pub fn layout( |
| 7226 | isel: *Select, | 7510 | isel: *Select, |
| 7227 | incoming: CallAbiIterator, | 7511 | incoming: CallAbiIterator, |
| 7228 | have_va: bool, | 7512 | is_sysv_var_args: bool, |
| 7229 | saved_gra_len: u7, | 7513 | saved_gra_len: u7, |
| 7230 | saved_vra_len: u7, | 7514 | saved_vra_len: u7, |
| 7231 | mod: *const Package.Module, | 7515 | mod: *const Package.Module, |
| ... | @@ -7236,8 +7520,6 @@ pub fn layout( | ... | @@ -7236,8 +7520,6 @@ pub fn layout( |
| 7236 | wip_mir_log.debug("{f}<body>:\n", .{nav.fqn.fmt(ip)}); | 7520 | wip_mir_log.debug("{f}<body>:\n", .{nav.fqn.fmt(ip)}); |
| 7237 | | 7521 | |
| 7238 | const stack_size: u24 = @intCast(InternPool.Alignment.@"16".forward(isel.stack_size)); | 7522 | const stack_size: u24 = @intCast(InternPool.Alignment.@"16".forward(isel.stack_size)); |
| 7239 | const stack_size_lo: u12 = @truncate(stack_size >> 0); | | |
| 7240 | const stack_size_hi: u12 = @truncate(stack_size >> 12); | | |
| 7241 | | 7523 | |
| 7242 | var saves_buf: [10 + 8 + 8 + 2 + 8]struct { | 7524 | var saves_buf: [10 + 8 + 8 + 2 + 8]struct { |
| 7243 | class: enum { integer, vector }, | 7525 | class: enum { integer, vector }, |
| ... | @@ -7315,7 +7597,7 @@ pub fn layout( | ... | @@ -7315,7 +7597,7 @@ pub fn layout( |
| 7315 | | 7597 | |
| 7316 | // incoming vr arguments | 7598 | // incoming vr arguments |
| 7317 | save_ra = if (mod.strip) incoming.nsrn else CallAbiIterator.nsrn_start; | 7599 | save_ra = if (mod.strip) incoming.nsrn else CallAbiIterator.nsrn_start; |
| 7318 | while (save_ra != if (have_va) CallAbiIterator.nsrn_end else incoming.nsrn) : (save_ra = @enumFromInt(@intFromEnum(save_ra) + 1)) { | 7600 | while (save_ra != if (is_sysv_var_args) CallAbiIterator.nsrn_end else incoming.nsrn) : (save_ra = @enumFromInt(@intFromEnum(save_ra) + 1)) { |
| 7319 | saves_size = std.mem.alignForward(u10, saves_size, 16); | 7601 | saves_size = std.mem.alignForward(u10, saves_size, 16); |
| 7320 | saves_buf[saves_len] = .{ | 7602 | saves_buf[saves_len] = .{ |
| 7321 | .class = .vector, | 7603 | .class = .vector, |
| ... | @@ -7370,7 +7652,7 @@ pub fn layout( | ... | @@ -7370,7 +7652,7 @@ pub fn layout( |
| 7370 | 1 => saves_size += 8, | 7652 | 1 => saves_size += 8, |
| 7371 | } | 7653 | } |
| 7372 | save_ra = if (mod.strip) incoming.ngrn else CallAbiIterator.ngrn_start; | 7654 | save_ra = if (mod.strip) incoming.ngrn else CallAbiIterator.ngrn_start; |
| 7373 | while (save_ra != if (have_va) CallAbiIterator.ngrn_end else incoming.ngrn) : (save_ra = @enumFromInt(@intFromEnum(save_ra) + 1)) { | 7655 | while (save_ra != if (is_sysv_var_args) CallAbiIterator.ngrn_end else incoming.ngrn) : (save_ra = @enumFromInt(@intFromEnum(save_ra) + 1)) { |
| 7374 | saves_size = std.mem.alignForward(u10, saves_size, 8); | 7656 | saves_size = std.mem.alignForward(u10, saves_size, 8); |
| 7375 | saves_buf[saves_len] = .{ | 7657 | saves_buf[saves_len] = .{ |
| 7376 | .class = .integer, | 7658 | .class = .integer, |
| ... | @@ -7434,6 +7716,8 @@ pub fn layout( | ... | @@ -7434,6 +7716,8 @@ pub fn layout( |
| 7434 | .fp | 7716 | .fp |
| 7435 | else | 7717 | else |
| 7436 | .ip0; | 7718 | .ip0; |
| | 7719 | const stack_size_lo: u12 = @truncate(stack_size >> 0); |
| | 7720 | const stack_size_hi: u12 = @truncate(stack_size >> 12); |
| 7437 | if (mod.stack_check) { | 7721 | if (mod.stack_check) { |
| 7438 | if (stack_size_hi > 2) { | 7722 | if (stack_size_hi > 2) { |
| 7439 | try isel.movImmediate(.ip1, stack_size_hi); | 7723 | try isel.movImmediate(.ip1, stack_size_hi); |
| ... | @@ -7481,6 +7765,7 @@ pub fn layout( | ... | @@ -7481,6 +7765,7 @@ pub fn layout( |
| 7481 | if (isel.returns) { | 7765 | if (isel.returns) { |
| 7482 | try isel.emit(.ret(.lr)); | 7766 | try isel.emit(.ret(.lr)); |
| 7483 | var save_index: usize = 0; | 7767 | var save_index: usize = 0; |
| | 7768 | var first_offset: ?u10 = null; |
| 7484 | while (save_index < saves.len) { | 7769 | while (save_index < saves.len) { |
| 7485 | if (save_index + 2 <= saves.len and saves[save_index + 1].needs_restore and | 7770 | if (save_index + 2 <= saves.len and saves[save_index + 1].needs_restore and |
| 7486 | saves[save_index + 0].class == saves[save_index + 1].class and | 7771 | saves[save_index + 0].class == saves[save_index + 1].class and |
| ... | @@ -7489,46 +7774,51 @@ pub fn layout( | ... | @@ -7489,46 +7774,51 @@ pub fn layout( |
| 7489 | try isel.emit(.ldp( | 7774 | try isel.emit(.ldp( |
| 7490 | saves[save_index + 0].register, | 7775 | saves[save_index + 0].register, |
| 7491 | saves[save_index + 1].register, | 7776 | saves[save_index + 1].register, |
| 7492 | switch (saves[save_index + 0].offset) { | 7777 | if (first_offset) |offset| .{ .signed_offset = .{ |
| 7493 | 0 => .{ .post_index = .{ | 7778 | .base = .sp, |
| 7494 | .base = .sp, | 7779 | .offset = @intCast(saves[save_index + 0].offset - offset), |
| 7495 | .index = @intCast(saves_size), | 7780 | } } else form: { |
| 7496 | } }, | 7781 | first_offset = @intCast(saves[save_index + 0].offset); |
| 7497 | else => |offset| .{ .signed_offset = .{ | 7782 | break :form .{ .post_index = .{ |
| 7498 | .base = .sp, | 7783 | .base = .sp, |
| 7499 | .offset = @intCast(offset), | 7784 | .index = @intCast(saves_size - first_offset.?), |
| 7500 | } }, | 7785 | } }; |
| 7501 | }, | 7786 | }, |
| 7502 | )); | 7787 | )); |
| 7503 | save_index += 2; | 7788 | save_index += 2; |
| 7504 | } else if (saves[save_index].needs_restore) { | 7789 | } else if (saves[save_index].needs_restore) { |
| 7505 | try isel.emit(.ldr( | 7790 | try isel.emit(.ldr( |
| 7506 | saves[save_index].register, | 7791 | saves[save_index].register, |
| 7507 | switch (saves[save_index].offset) { | 7792 | if (first_offset) |offset| .{ .unsigned_offset = .{ |
| 7508 | 0 => .{ .post_index = .{ | 7793 | .base = .sp, |
| 7509 | .base = .sp, | 7794 | .offset = saves[save_index + 0].offset - offset, |
| 7510 | .index = @intCast(saves_size), | 7795 | } } else form: { |
| 7511 | } }, | 7796 | const offset = saves[save_index + 0].offset; |
| 7512 | else => |offset| .{ .unsigned_offset = .{ | 7797 | first_offset = offset; |
| | 7798 | break :form .{ .post_index = .{ |
| 7513 | .base = .sp, | 7799 | .base = .sp, |
| 7514 | .offset = @intCast(offset), | 7800 | .index = @intCast(saves_size - offset), |
| 7515 | } }, | 7801 | } }; |
| 7516 | }, | 7802 | }, |
| 7517 | )); | 7803 | )); |
| 7518 | save_index += 1; | 7804 | save_index += 1; |
| 7519 | } else save_index += 1; | 7805 | } else save_index += 1; |
| 7520 | } | 7806 | } |
| 7521 | if (isel.stack_align != .@"16" or (stack_size_lo > 0 and stack_size_hi > 0)) { | 7807 | const offset = stack_size + first_offset.?; |
| 7522 | try isel.emit(switch (frame_record_offset) { | 7808 | const offset_lo: u12 = @truncate(offset >> 0); |
| 7523 | 0 => .add(.sp, .fp, .{ .immediate = 0 }), | 7809 | const offset_hi: u12 = @truncate(offset >> 12); |
| 7524 | else => |offset| .sub(.sp, .fp, .{ .immediate = offset }), | 7810 | if (isel.stack_align != .@"16" or (offset_lo > 0 and offset_hi > 0)) { |
| 7525 | }); | 7811 | const fp_offset = @as(i11, first_offset.?) - frame_record_offset; |
| | 7812 | try isel.emit(if (fp_offset >= 0) |
| | 7813 | .add(.sp, .fp, .{ .immediate = @intCast(fp_offset) }) |
| | 7814 | else |
| | 7815 | .sub(.sp, .fp, .{ .immediate = @intCast(-fp_offset) })); |
| 7526 | } else { | 7816 | } else { |
| 7527 | if (stack_size_hi > 0) try isel.emit(.add(.sp, .sp, .{ | 7817 | if (offset_hi > 0) try isel.emit(.add(.sp, .sp, .{ |
| 7528 | .shifted_immediate = .{ .immediate = stack_size_hi, .lsl = .@"12" }, | 7818 | .shifted_immediate = .{ .immediate = offset_hi, .lsl = .@"12" }, |
| 7529 | })); | 7819 | })); |
| 7530 | if (stack_size_lo > 0) try isel.emit(.add(.sp, .sp, .{ | 7820 | if (offset_lo > 0) try isel.emit(.add(.sp, .sp, .{ |
| 7531 | .immediate = stack_size_lo, | 7821 | .immediate = offset_lo, |
| 7532 | })); | 7822 | })); |
| 7533 | } | 7823 | } |
| 7534 | wip_mir_log.debug("{f}<epilogue>:\n", .{nav.fqn.fmt(ip)}); | 7824 | wip_mir_log.debug("{f}<epilogue>:\n", .{nav.fqn.fmt(ip)}); |
| ... | @@ -9493,6 +9783,11 @@ pub const Value = struct { | ... | @@ -9493,6 +9783,11 @@ pub const Value = struct { |
| 9493 | return it.vi; | 9783 | return it.vi; |
| 9494 | } | 9784 | } |
| 9495 | | 9785 | |
| | 9786 | pub fn peek(it: PartIterator) ?Value.Index { |
| | 9787 | var it_mut = it; |
| | 9788 | return it_mut.next(); |
| | 9789 | } |
| | 9790 | |
| 9496 | pub fn only(it: PartIterator) ?Value.Index { | 9791 | pub fn only(it: PartIterator) ?Value.Index { |
| 9497 | return if (it.remaining == 1) it.vi else null; | 9792 | return if (it.remaining == 1) it.vi else null; |
| 9498 | } | 9793 | } |
| ... | @@ -11607,6 +11902,16 @@ pub const CallAbiIterator = struct { | ... | @@ -11607,6 +11902,16 @@ pub const CallAbiIterator = struct { |
| 11607 | return wip_vi.ref(isel); | 11902 | return wip_vi.ref(isel); |
| 11608 | } | 11903 | } |
| 11609 | | 11904 | |
| | 11905 | pub fn nonSysvVarArg(it: *CallAbiIterator, isel: *Select, ty: ZigType) !?Value.Index { |
| | 11906 | const ngrn = it.ngrn; |
| | 11907 | defer it.ngrn = ngrn; |
| | 11908 | it.ngrn = ngrn_end; |
| | 11909 | const nsrn = it.nsrn; |
| | 11910 | defer it.nsrn = nsrn; |
| | 11911 | it.nsrn = nsrn_end; |
| | 11912 | return it.param(isel, ty); |
| | 11913 | } |
| | 11914 | |
| 11610 | pub fn ret(it: *CallAbiIterator, isel: *Select, ty: ZigType) !?Value.Index { | 11915 | pub fn ret(it: *CallAbiIterator, isel: *Select, ty: ZigType) !?Value.Index { |
| 11611 | const wip_vi = try it.param(isel, ty) orelse return null; | 11916 | const wip_vi = try it.param(isel, ty) orelse return null; |
| 11612 | switch (wip_vi.parent(isel)) { | 11917 | switch (wip_vi.parent(isel)) { |