authorgravatar for joachim.schmidt557@outlook.comJoachim Schmidt <joachim.schmidt557@outlook.com> 2022-08-13 20:32:18+00:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2022-08-13 20:32:18+00:00
logd2342370fe85491cb8216ccce9cc8fb5259376e2
tree477bd5ea0405caa3f6f3e2fbfcd44951e1c78b73
parent7e07f3d4f95f9e7a0d95ee7b9335798eccb470c7
parentc9d9fd53a61cbc656f543a3fa778ac4c72a58701
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #12438 from joachimschmidt557/stage2-arm

stage2 ARM: misc improvements

2 files changed, 183 insertions(+), 68 deletions(-)

src/arch/arm/CodeGen.zig+164-30
......@@ -247,6 +247,31 @@ const BigTomb = struct {
247247 log.debug("%{d} => {}", .{ bt.inst, result });
248248 const branch = &bt.function.branch_stack.items[bt.function.branch_stack.items.len - 1];
249249 branch.inst_table.putAssumeCapacityNoClobber(bt.inst, result);
250
251 switch (result) {
252 .register => |reg| {
253 // In some cases (such as bitcast), an operand
254 // may be the same MCValue as the result. If
255 // that operand died and was a register, it
256 // was freed by processDeath. We have to
257 // "re-allocate" the register.
258 if (bt.function.register_manager.isRegFree(reg)) {
259 bt.function.register_manager.getRegAssumeFree(reg, bt.inst);
260 }
261 },
262 .register_c_flag,
263 .register_v_flag,
264 => |reg| {
265 if (bt.function.register_manager.isRegFree(reg)) {
266 bt.function.register_manager.getRegAssumeFree(reg, bt.inst);
267 }
268 bt.function.cpsr_flags_inst = bt.inst;
269 },
270 .cpsr_flags => {
271 bt.function.cpsr_flags_inst = bt.inst;
272 },
273 else => {},
274 }
250275 }
251276 bt.function.finishAirBookkeeping();
252277 }
......@@ -332,7 +357,7 @@ pub fn generate(
332357 };
333358
334359 for (function.dbg_arg_relocs.items) |reloc| {
335 try function.genArgDbgInfo(reloc.inst, reloc.index, call_info.stack_byte_count);
360 try function.genArgDbgInfo(reloc.inst, reloc.index);
336361 }
337362
338363 var mir = Mir{
......@@ -351,7 +376,8 @@ pub fn generate(
351376 .prev_di_pc = 0,
352377 .prev_di_line = module_fn.lbrace_line,
353378 .prev_di_column = module_fn.lbrace_column,
354 .prologue_stack_space = call_info.stack_byte_count + function.saved_regs_stack_space,
379 .stack_size = function.max_end_stack,
380 .saved_regs_stack_space = function.saved_regs_stack_space,
355381 };
356382 defer emit.deinit();
357383
......@@ -464,6 +490,7 @@ fn gen(self: *Self) !void {
464490 const total_stack_size = self.max_end_stack + self.saved_regs_stack_space;
465491 const aligned_total_stack_end = mem.alignForwardGeneric(u32, total_stack_size, self.stack_align);
466492 const stack_size = aligned_total_stack_end - self.saved_regs_stack_space;
493 self.max_end_stack = stack_size;
467494 if (Instruction.Operand.fromU32(stack_size)) |op| {
468495 self.mir_instructions.set(sub_reloc, .{
469496 .tag = .sub,
......@@ -1812,7 +1839,7 @@ fn errUnionErr(self: *Self, error_union_mcv: MCValue, error_union_ty: Type) !MCV
18121839 switch (error_union_mcv) {
18131840 .register => return self.fail("TODO errUnionErr for registers", .{}),
18141841 .stack_argument_offset => |off| {
1815 return MCValue{ .stack_argument_offset = off - err_offset };
1842 return MCValue{ .stack_argument_offset = off + err_offset };
18161843 },
18171844 .stack_offset => |off| {
18181845 return MCValue{ .stack_offset = off - err_offset };
......@@ -1849,7 +1876,7 @@ fn errUnionPayload(self: *Self, error_union_mcv: MCValue, error_union_ty: Type)
18491876 switch (error_union_mcv) {
18501877 .register => return self.fail("TODO errUnionPayload for registers", .{}),
18511878 .stack_argument_offset => |off| {
1852 return MCValue{ .stack_argument_offset = off - payload_offset };
1879 return MCValue{ .stack_argument_offset = off + payload_offset };
18531880 },
18541881 .stack_offset => |off| {
18551882 return MCValue{ .stack_offset = off - payload_offset };
......@@ -1983,7 +2010,7 @@ fn airSliceLen(self: *Self, inst: Air.Inst.Index) !void {
19832010 .dead, .unreach => unreachable,
19842011 .register => unreachable, // a slice doesn't fit in one register
19852012 .stack_argument_offset => |off| {
1986 break :result MCValue{ .stack_argument_offset = off - 4 };
2013 break :result MCValue{ .stack_argument_offset = off + 4 };
19872014 },
19882015 .stack_offset => |off| {
19892016 break :result MCValue{ .stack_offset = off - 4 };
......@@ -2259,16 +2286,17 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo
22592286 .register_c_flag,
22602287 .register_v_flag,
22612288 => unreachable, // cannot hold an address
2262 .immediate => |imm| try self.setRegOrMem(elem_ty, dst_mcv, .{ .memory = imm }),
2263 .ptr_stack_offset => |off| try self.setRegOrMem(elem_ty, dst_mcv, .{ .stack_offset = off }),
2289 .immediate => |imm| {
2290 try self.setRegOrMem(elem_ty, dst_mcv, .{ .memory = imm });
2291 },
2292 .ptr_stack_offset => |off| {
2293 try self.setRegOrMem(elem_ty, dst_mcv, .{ .stack_offset = off });
2294 },
22642295 .register => |reg| {
22652296 const reg_lock = self.register_manager.lockReg(reg);
22662297 defer if (reg_lock) |reg_locked| self.register_manager.unlockReg(reg_locked);
22672298
22682299 switch (dst_mcv) {
2269 .dead => unreachable,
2270 .undef => unreachable,
2271 .cpsr_flags => unreachable,
22722300 .register => |dst_reg| {
22732301 try self.genLdrRegister(dst_reg, reg, elem_ty);
22742302 },
......@@ -2304,7 +2332,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo
23042332 try self.genInlineMemcpy(src_reg, dst_reg, len_reg, count_reg, tmp_reg);
23052333 }
23062334 },
2307 else => return self.fail("TODO load from register into {}", .{dst_mcv}),
2335 else => unreachable, // attempting to load into non-register or non-stack MCValue
23082336 }
23092337 },
23102338 .memory,
......@@ -2401,7 +2429,7 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type
24012429 // sub src_reg, fp, #off
24022430 try self.genSetReg(ptr_ty, src_reg, .{ .ptr_stack_offset = off });
24032431 },
2404 .memory => |addr| try self.genSetReg(Type.usize, src_reg, .{ .immediate = @intCast(u32, addr) }),
2432 .memory => |addr| try self.genSetReg(ptr_ty, src_reg, .{ .immediate = @intCast(u32, addr) }),
24052433 .stack_argument_offset => |off| {
24062434 _ = try self.addInst(.{
24072435 .tag = .ldr_ptr_stack_argument,
......@@ -2507,7 +2535,7 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {
25072535 switch (mcv) {
25082536 .dead, .unreach => unreachable,
25092537 .stack_argument_offset => |off| {
2510 break :result MCValue{ .stack_argument_offset = off - struct_field_offset };
2538 break :result MCValue{ .stack_argument_offset = off + struct_field_offset };
25112539 },
25122540 .stack_offset => |off| {
25132541 break :result MCValue{ .stack_offset = off - struct_field_offset };
......@@ -3347,6 +3375,102 @@ fn genInlineMemcpy(
33473375 // end:
33483376}
33493377
3378fn genInlineMemset(
3379 self: *Self,
3380 dst: MCValue,
3381 val: MCValue,
3382 len: MCValue,
3383) !void {
3384 const dst_reg = switch (dst) {
3385 .register => |r| r,
3386 else => try self.copyToTmpRegister(Type.initTag(.manyptr_u8), dst),
3387 };
3388 const dst_reg_lock = self.register_manager.lockReg(dst_reg);
3389 defer if (dst_reg_lock) |lock| self.register_manager.unlockReg(lock);
3390
3391 const val_reg = switch (val) {
3392 .register => |r| r,
3393 else => try self.copyToTmpRegister(Type.initTag(.u8), val),
3394 };
3395 const val_reg_lock = self.register_manager.lockReg(val_reg);
3396 defer if (val_reg_lock) |lock| self.register_manager.unlockReg(lock);
3397
3398 const len_reg = switch (len) {
3399 .register => |r| r,
3400 else => try self.copyToTmpRegister(Type.usize, len),
3401 };
3402 const len_reg_lock = self.register_manager.lockReg(len_reg);
3403 defer if (len_reg_lock) |lock| self.register_manager.unlockReg(lock);
3404
3405 const count_reg = try self.register_manager.allocReg(null, gp);
3406
3407 try self.genInlineMemsetCode(dst_reg, val_reg, len_reg, count_reg);
3408}
3409
3410fn genInlineMemsetCode(
3411 self: *Self,
3412 dst: Register,
3413 val: Register,
3414 len: Register,
3415 count: Register,
3416) !void {
3417 // mov count, #0
3418 _ = try self.addInst(.{
3419 .tag = .mov,
3420 .data = .{ .rr_op = .{
3421 .rd = count,
3422 .rn = .r0,
3423 .op = Instruction.Operand.imm(0, 0),
3424 } },
3425 });
3426
3427 // loop:
3428 // cmp count, len
3429 _ = try self.addInst(.{
3430 .tag = .cmp,
3431 .data = .{ .rr_op = .{
3432 .rd = .r0,
3433 .rn = count,
3434 .op = Instruction.Operand.reg(len, Instruction.Operand.Shift.none),
3435 } },
3436 });
3437
3438 // bge end
3439 _ = try self.addInst(.{
3440 .tag = .b,
3441 .cond = .ge,
3442 .data = .{ .inst = @intCast(u32, self.mir_instructions.len + 4) },
3443 });
3444
3445 // strb val, [src, count]
3446 _ = try self.addInst(.{
3447 .tag = .strb,
3448 .data = .{ .rr_offset = .{
3449 .rt = val,
3450 .rn = dst,
3451 .offset = .{ .offset = Instruction.Offset.reg(count, .none) },
3452 } },
3453 });
3454
3455 // add count, count, #1
3456 _ = try self.addInst(.{
3457 .tag = .add,
3458 .data = .{ .rr_op = .{
3459 .rd = count,
3460 .rn = count,
3461 .op = Instruction.Operand.imm(1, 0),
3462 } },
3463 });
3464
3465 // b loop
3466 _ = try self.addInst(.{
3467 .tag = .b,
3468 .data = .{ .inst = @intCast(u32, self.mir_instructions.len - 4) },
3469 });
3470
3471 // end:
3472}
3473
33503474/// Adds a Type to the .debug_info at the current position. The bytes will be populated later,
33513475/// after codegen for this symbol is done.
33523476fn addDbgInfoTypeReloc(self: *Self, ty: Type) error{OutOfMemory}!void {
......@@ -3369,9 +3493,7 @@ fn addDbgInfoTypeReloc(self: *Self, ty: Type) error{OutOfMemory}!void {
33693493 }
33703494}
33713495
3372fn genArgDbgInfo(self: *Self, inst: Air.Inst.Index, arg_index: u32, stack_byte_count: u32) error{OutOfMemory}!void {
3373 const prologue_stack_space = stack_byte_count + self.saved_regs_stack_space;
3374
3496fn genArgDbgInfo(self: *Self, inst: Air.Inst.Index, arg_index: u32) error{OutOfMemory}!void {
33753497 const mcv = self.args[arg_index];
33763498 const ty = self.air.instructions.items(.data)[inst].ty;
33773499 const name = self.mod_fn.getParamName(self.bin_file.options.module.?, arg_index);
......@@ -3404,7 +3526,7 @@ fn genArgDbgInfo(self: *Self, inst: Air.Inst.Index, arg_index: u32, stack_byte_c
34043526 // const abi_size = @intCast(u32, ty.abiSize(self.target.*));
34053527 const adjusted_stack_offset = switch (mcv) {
34063528 .stack_offset => |offset| -@intCast(i32, offset),
3407 .stack_argument_offset => |offset| @intCast(i32, prologue_stack_space - offset),
3529 .stack_argument_offset => |offset| @intCast(i32, self.saved_regs_stack_space + offset),
34083530 else => unreachable,
34093531 };
34103532
......@@ -3524,7 +3646,10 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions.
35243646 try self.register_manager.getReg(reg, null);
35253647 }
35263648
3527 if (info.return_value == .stack_offset) {
3649 // If returning by reference, r0 will contain the address of where
3650 // to put the result into. In that case, make sure that r0 remains
3651 // untouched by the parameter passing code
3652 const r0_lock: ?RegisterLock = if (info.return_value == .stack_offset) blk: {
35283653 log.debug("airCall: return by reference", .{});
35293654 const ret_ty = fn_ty.fnReturnType();
35303655 const ret_abi_size = @intCast(u32, ret_ty.abiSize(self.target.*));
......@@ -3540,7 +3665,10 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions.
35403665 try self.genSetReg(ptr_ty, .r0, .{ .ptr_stack_offset = stack_offset });
35413666
35423667 info.return_value = .{ .stack_offset = stack_offset };
3543 }
3668
3669 break :blk self.register_manager.lockRegAssumeUnused(.r0);
3670 } else null;
3671 defer if (r0_lock) |reg| self.register_manager.unlockReg(reg);
35443672
35453673 // Make space for the arguments passed via the stack
35463674 self.max_end_stack += info.stack_byte_count;
......@@ -3559,7 +3687,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions.
35593687 .stack_offset => unreachable,
35603688 .stack_argument_offset => |offset| try self.genSetStackArgument(
35613689 arg_ty,
3562 info.stack_byte_count - offset,
3690 offset,
35633691 arg_mcv,
35643692 ),
35653693 else => unreachable,
......@@ -4621,11 +4749,15 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro
46214749 if (!self.wantSafety())
46224750 return; // The already existing value will do just fine.
46234751 // TODO Upgrade this to a memset call when we have that available.
4624 switch (ty.abiSize(self.target.*)) {
4625 1 => return self.genSetStack(ty, stack_offset, .{ .immediate = 0xaa }),
4626 2 => return self.genSetStack(ty, stack_offset, .{ .immediate = 0xaaaa }),
4627 4 => return self.genSetStack(ty, stack_offset, .{ .immediate = 0xaaaaaaaa }),
4628 else => return self.fail("TODO implement memset", .{}),
4752 switch (abi_size) {
4753 1 => try self.genSetStack(ty, stack_offset, .{ .immediate = 0xaa }),
4754 2 => try self.genSetStack(ty, stack_offset, .{ .immediate = 0xaaaa }),
4755 4 => try self.genSetStack(ty, stack_offset, .{ .immediate = 0xaaaaaaaa }),
4756 else => try self.genInlineMemset(
4757 .{ .ptr_stack_offset = stack_offset },
4758 .{ .immediate = 0xaa },
4759 .{ .immediate = abi_size },
4760 ),
46294761 }
46304762 },
46314763 .cpsr_flags,
......@@ -5037,9 +5169,9 @@ fn genSetStackArgument(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) I
50375169 return; // The already existing value will do just fine.
50385170 // TODO Upgrade this to a memset call when we have that available.
50395171 switch (abi_size) {
5040 1 => return self.genSetStackArgument(ty, stack_offset, .{ .immediate = 0xaa }),
5041 2 => return self.genSetStackArgument(ty, stack_offset, .{ .immediate = 0xaaaa }),
5042 4 => return self.genSetStackArgument(ty, stack_offset, .{ .immediate = 0xaaaaaaaa }),
5172 1 => try self.genSetStackArgument(ty, stack_offset, .{ .immediate = 0xaa }),
5173 2 => try self.genSetStackArgument(ty, stack_offset, .{ .immediate = 0xaaaa }),
5174 4 => try self.genSetStackArgument(ty, stack_offset, .{ .immediate = 0xaaaaaaaa }),
50435175 else => return self.fail("TODO implement memset", .{}),
50445176 }
50455177 },
......@@ -5653,8 +5785,8 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues {
56535785 if (ty.abiAlignment(self.target.*) == 8)
56545786 nsaa = std.mem.alignForwardGeneric(u32, nsaa, 8);
56555787
5656 nsaa += param_size;
56575788 result.args[i] = .{ .stack_argument_offset = nsaa };
5789 nsaa += param_size;
56585790 }
56595791 }
56605792
......@@ -5687,9 +5819,11 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues {
56875819 for (param_types) |ty, i| {
56885820 if (ty.abiSize(self.target.*) > 0) {
56895821 const param_size = @intCast(u32, ty.abiSize(self.target.*));
5822 const param_alignment = ty.abiAlignment(self.target.*);
56905823
5691 stack_offset = std.mem.alignForwardGeneric(u32, stack_offset, ty.abiAlignment(self.target.*)) + param_size;
5824 stack_offset = std.mem.alignForwardGeneric(u32, stack_offset, param_alignment);
56925825 result.args[i] = .{ .stack_argument_offset = stack_offset };
5826 stack_offset += param_size;
56935827 } else {
56945828 result.args[i] = .{ .none = {} };
56955829 }
src/arch/arm/Emit.zig+19-38
......@@ -33,9 +33,13 @@ prev_di_column: u32,
3333/// Relative to the beginning of `code`.
3434prev_di_pc: usize,
3535
36/// The amount of stack space consumed by all stack arguments as well
37/// as the saved callee-saved registers
38prologue_stack_space: u32,
36/// The amount of stack space consumed by the saved callee-saved
37/// registers in bytes
38saved_regs_stack_space: u32,
39
40/// The final stack frame size of the function (already aligned to the
41/// respective stack alignment). Does not include prologue stack space.
42stack_size: u32,
3943
4044/// The branch type of every branch
4145branch_types: std.AutoHashMapUnmanaged(Mir.Inst.Index, BranchType) = .{},
......@@ -500,14 +504,15 @@ fn mirLoadStackArgument(emit: *Emit, inst: Mir.Inst.Index) !void {
500504 const tag = emit.mir.instructions.items(.tag)[inst];
501505 const cond = emit.mir.instructions.items(.cond)[inst];
502506 const r_stack_offset = emit.mir.instructions.items(.data)[inst].r_stack_offset;
507 const rt = r_stack_offset.rt;
503508
504 const raw_offset = emit.prologue_stack_space - r_stack_offset.stack_offset;
509 const raw_offset = emit.stack_size + emit.saved_regs_stack_space + r_stack_offset.stack_offset;
505510 switch (tag) {
506511 .ldr_ptr_stack_argument => {
507512 const operand = Instruction.Operand.fromU32(raw_offset) orelse
508513 return emit.fail("TODO mirLoadStack larger offsets", .{});
509514
510 try emit.writeInstruction(Instruction.add(cond, r_stack_offset.rt, .fp, operand));
515 try emit.writeInstruction(Instruction.add(cond, rt, .sp, operand));
511516 },
512517 .ldr_stack_argument,
513518 .ldrb_stack_argument,
......@@ -516,23 +521,11 @@ fn mirLoadStackArgument(emit: *Emit, inst: Mir.Inst.Index) !void {
516521 break :blk Instruction.Offset.imm(@intCast(u12, raw_offset));
517522 } else return emit.fail("TODO mirLoadStack larger offsets", .{});
518523
519 const ldr = switch (tag) {
520 .ldr_stack_argument => &Instruction.ldr,
521 .ldrb_stack_argument => &Instruction.ldrb,
524 switch (tag) {
525 .ldr_stack_argument => try emit.writeInstruction(Instruction.ldr(cond, rt, .sp, .{ .offset = offset })),
526 .ldrb_stack_argument => try emit.writeInstruction(Instruction.ldrb(cond, rt, .sp, .{ .offset = offset })),
522527 else => unreachable,
523 };
524
525 const ldr_workaround = switch (builtin.zig_backend) {
526 .stage1 => ldr.*,
527 else => ldr,
528 };
529
530 try emit.writeInstruction(ldr_workaround(
531 cond,
532 r_stack_offset.rt,
533 .fp,
534 .{ .offset = offset },
535 ));
528 }
536529 },
537530 .ldrh_stack_argument,
538531 .ldrsb_stack_argument,
......@@ -542,24 +535,12 @@ fn mirLoadStackArgument(emit: *Emit, inst: Mir.Inst.Index) !void {
542535 break :blk Instruction.ExtraLoadStoreOffset.imm(@intCast(u8, raw_offset));
543536 } else return emit.fail("TODO mirLoadStack larger offsets", .{});
544537
545 const ldr = switch (tag) {
546 .ldrh_stack_argument => &Instruction.ldrh,
547 .ldrsb_stack_argument => &Instruction.ldrsb,
548 .ldrsh_stack_argument => &Instruction.ldrsh,
538 switch (tag) {
539 .ldrh_stack_argument => try emit.writeInstruction(Instruction.ldrh(cond, rt, .sp, .{ .offset = offset })),
540 .ldrsb_stack_argument => try emit.writeInstruction(Instruction.ldrsb(cond, rt, .sp, .{ .offset = offset })),
541 .ldrsh_stack_argument => try emit.writeInstruction(Instruction.ldrsh(cond, rt, .sp, .{ .offset = offset })),
549542 else => unreachable,
550 };
551
552 const ldr_workaround = switch (builtin.zig_backend) {
553 .stage1 => ldr.*,
554 else => ldr,
555 };
556
557 try emit.writeInstruction(ldr_workaround(
558 cond,
559 r_stack_offset.rt,
560 .fp,
561 .{ .offset = offset },
562 ));
543 }
563544 },
564545 else => unreachable,
565546 }