Skip to content

Commit d234237

Browse files
Merge pull request #12438 from joachimschmidt557/stage2-arm
stage2 ARM: misc improvements
2 parents 7e07f3d + c9d9fd5 commit d234237

File tree

2 files changed

+183
-68
lines changed

2 files changed

+183
-68
lines changed

src/arch/arm/CodeGen.zig

Lines changed: 164 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -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

3378+
fn 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+
3410+
fn 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.
33523476
fn addDbgInfoTypeReloc(self: *Self, ty: Type) error{OutOfMemory}!void {
@@ -3369,9 +3493,7 @@ fn addDbgInfoTypeReloc(self: *Self, ty: Type) error{OutOfMemory}!void {
33693493
}
33703494
}
33713495

3372-
fn 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-
3496+
fn 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
}

0 commit comments

Comments
 (0)