authorgravatar for joachim.schmidt557@outlook.comJoachim Schmidt <joachim.schmidt557@outlook.com> 2022-07-30 23:17:15+02:00
committergravatar for joachim.schmidt557@outlook.comJoachim Schmidt <joachim.schmidt557@outlook.com> 2022-08-05 20:30:51+02:00
logcf3aaceed9f2a9e1872bdd8b2cccecd1766e2419
treee43969bfb987275c48e8445b36a8d74929f9686a
parent423bef4dfc635a3ca0144cac95384984857a8519
signature Commit is signed but in an unrecognized format.

stage2 AArch64: introduce MCValue.stack_argument_offset

This new MCValue union member shares the same semantics as the MCValue type of the same name in the ARM backend.

3 files changed, 275 insertions(+), 9 deletions(-)

src/arch/aarch64/CodeGen.zig+201-9
......@@ -166,10 +166,12 @@ const MCValue = union(enum) {
166166 /// the type is u1) or true (if the type in bool) iff the
167167 /// specified condition is true.
168168 condition_flags: Condition,
169 /// The value is a function argument passed via the stack.
170 stack_argument_offset: u32,
169171
170172 fn isMemory(mcv: MCValue) bool {
171173 return switch (mcv) {
172 .memory, .stack_offset => true,
174 .memory, .stack_offset, .stack_argument_offset => true,
173175 else => false,
174176 };
175177 }
......@@ -192,6 +194,7 @@ const MCValue = union(enum) {
192194 .condition_flags,
193195 .ptr_stack_offset,
194196 .undef,
197 .stack_argument_offset,
195198 => false,
196199
197200 .register,
......@@ -337,6 +340,7 @@ pub fn generate(
337340 .prev_di_line = module_fn.lbrace_line,
338341 .prev_di_column = module_fn.lbrace_column,
339342 .stack_size = mem.alignForwardGeneric(u32, function.max_end_stack, function.stack_align),
343 .prologue_stack_space = call_info.stack_byte_count + function.saved_regs_stack_space,
340344 };
341345 defer emit.deinit();
342346
......@@ -2726,6 +2730,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo
27262730 },
27272731 .memory,
27282732 .stack_offset,
2733 .stack_argument_offset,
27292734 .got_load,
27302735 .direct_load,
27312736 => {
......@@ -2927,6 +2932,7 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type
29272932 },
29282933 .memory,
29292934 .stack_offset,
2935 .stack_argument_offset,
29302936 .got_load,
29312937 .direct_load,
29322938 => {
......@@ -3009,6 +3015,9 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {
30093015
30103016 switch (mcv) {
30113017 .dead, .unreach => unreachable,
3018 .stack_argument_offset => |off| {
3019 break :result MCValue{ .stack_argument_offset = off - struct_field_offset };
3020 },
30123021 .stack_offset => |off| {
30133022 break :result MCValue{ .stack_offset = off - struct_field_offset };
30143023 },
......@@ -3152,12 +3161,12 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions.
31523161 try self.register_manager.getReg(reg, null);
31533162 try self.genSetReg(arg_ty, reg, arg_mcv);
31543163 },
3155 .stack_offset => {
3156 return self.fail("TODO implement calling with parameters in memory", .{});
3157 },
3158 .ptr_stack_offset => {
3159 return self.fail("TODO implement calling with MCValue.ptr_stack_offset arg", .{});
3160 },
3164 .stack_offset => unreachable,
3165 .stack_argument_offset => |offset| try self.genSetStackArgument(
3166 arg_ty,
3167 info.stack_byte_count - offset,
3168 arg_mcv,
3169 ),
31613170 else => unreachable,
31623171 }
31633172 }
......@@ -3884,7 +3893,7 @@ fn br(self: *Self, block: Air.Inst.Index, operand: Air.Inst.Ref) !void {
38843893 block_data.mcv = switch (operand_mcv) {
38853894 .none, .dead, .unreach => unreachable,
38863895 .register, .stack_offset, .memory => operand_mcv,
3887 .immediate, .condition_flags => blk: {
3896 .immediate, .stack_argument_offset, .condition_flags => blk: {
38883897 const new_mcv = try self.allocRegOrMem(block, true);
38893898 try self.setRegOrMem(self.air.typeOfIndex(block), new_mcv, operand_mcv);
38903899 break :blk new_mcv;
......@@ -4126,6 +4135,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro
41264135 .got_load,
41274136 .direct_load,
41284137 .memory,
4138 .stack_argument_offset,
41294139 .stack_offset,
41304140 => {
41314141 switch (mcv) {
......@@ -4328,6 +4338,188 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
43284338 else => unreachable,
43294339 }
43304340 },
4341 .stack_argument_offset => |off| {
4342 const abi_size = ty.abiSize(self.target.*);
4343
4344 switch (abi_size) {
4345 1, 2, 4, 8 => {
4346 const tag: Mir.Inst.Tag = switch (abi_size) {
4347 1 => if (ty.isSignedInt()) Mir.Inst.Tag.ldrsb_stack_argument else .ldrb_stack_argument,
4348 2 => if (ty.isSignedInt()) Mir.Inst.Tag.ldrsh_stack_argument else .ldrh_stack_argument,
4349 4, 8 => .ldr_stack_argument,
4350 else => unreachable, // unexpected abi size
4351 };
4352
4353 _ = try self.addInst(.{
4354 .tag = tag,
4355 .data = .{ .load_store_stack = .{
4356 .rt = reg,
4357 .offset = @intCast(u32, off),
4358 } },
4359 });
4360 },
4361 3, 5, 6, 7 => return self.fail("TODO implement genSetReg types size {}", .{abi_size}),
4362 else => unreachable,
4363 }
4364 },
4365 }
4366}
4367
4368fn genSetStackArgument(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerError!void {
4369 const abi_size = @intCast(u32, ty.abiSize(self.target.*));
4370 switch (mcv) {
4371 .dead => unreachable,
4372 .none, .unreach => return,
4373 .undef => {
4374 if (!self.wantSafety())
4375 return; // The already existing value will do just fine.
4376 // TODO Upgrade this to a memset call when we have that available.
4377 switch (ty.abiSize(self.target.*)) {
4378 1 => return self.genSetStack(ty, stack_offset, .{ .immediate = 0xaa }),
4379 2 => return self.genSetStack(ty, stack_offset, .{ .immediate = 0xaaaa }),
4380 4 => return self.genSetStack(ty, stack_offset, .{ .immediate = 0xaaaaaaaa }),
4381 8 => return self.genSetStack(ty, stack_offset, .{ .immediate = 0xaaaaaaaaaaaaaaaa }),
4382 else => return self.fail("TODO implement memset", .{}),
4383 }
4384 },
4385 .register => |reg| {
4386 switch (abi_size) {
4387 1, 2, 4, 8 => {
4388 const tag: Mir.Inst.Tag = switch (abi_size) {
4389 1 => .strb_immediate,
4390 2 => .strh_immediate,
4391 4, 8 => .str_immediate,
4392 else => unreachable, // unexpected abi size
4393 };
4394 const rt = registerAlias(reg, abi_size);
4395 const offset = switch (abi_size) {
4396 1 => blk: {
4397 if (math.cast(u12, stack_offset)) |imm| {
4398 break :blk Instruction.LoadStoreOffset.imm(imm);
4399 } else {
4400 return self.fail("TODO genSetStackArgument byte with larger offset", .{});
4401 }
4402 },
4403 2 => blk: {
4404 assert(std.mem.isAlignedGeneric(u32, stack_offset, 2)); // misaligned stack entry
4405 if (math.cast(u12, @divExact(stack_offset, 2))) |imm| {
4406 break :blk Instruction.LoadStoreOffset.imm(imm);
4407 } else {
4408 return self.fail("TODO getSetStackArgument halfword with larger offset", .{});
4409 }
4410 },
4411 4, 8 => blk: {
4412 const alignment = abi_size;
4413 assert(std.mem.isAlignedGeneric(u32, stack_offset, alignment)); // misaligned stack entry
4414 if (math.cast(u12, @divExact(stack_offset, alignment))) |imm| {
4415 break :blk Instruction.LoadStoreOffset.imm(imm);
4416 } else {
4417 return self.fail("TODO genSetStackArgument with larger offset", .{});
4418 }
4419 },
4420 else => unreachable,
4421 };
4422
4423 _ = try self.addInst(.{
4424 .tag = tag,
4425 .data = .{ .load_store_register_immediate = .{
4426 .rt = rt,
4427 .rn = .sp,
4428 .offset = offset.immediate,
4429 } },
4430 });
4431 },
4432 else => return self.fail("TODO genSetStackArgument other types abi_size={}", .{abi_size}),
4433 }
4434 },
4435 .register_with_overflow => {
4436 return self.fail("TODO implement genSetStack {}", .{mcv});
4437 },
4438 .got_load,
4439 .direct_load,
4440 .memory,
4441 .stack_argument_offset,
4442 .stack_offset,
4443 => {
4444 if (abi_size <= 4) {
4445 const reg = try self.copyToTmpRegister(ty, mcv);
4446 return self.genSetStackArgument(ty, stack_offset, MCValue{ .register = reg });
4447 } else {
4448 var ptr_ty_payload: Type.Payload.ElemType = .{
4449 .base = .{ .tag = .single_mut_pointer },
4450 .data = ty,
4451 };
4452 const ptr_ty = Type.initPayload(&ptr_ty_payload.base);
4453
4454 // TODO call extern memcpy
4455 const regs = try self.register_manager.allocRegs(5, .{ null, null, null, null, null }, gp);
4456 const regs_locks = self.register_manager.lockRegsAssumeUnused(5, regs);
4457 defer for (regs_locks) |reg| {
4458 self.register_manager.unlockReg(reg);
4459 };
4460
4461 const src_reg = regs[0];
4462 const dst_reg = regs[1];
4463 const len_reg = regs[2];
4464 const count_reg = regs[3];
4465 const tmp_reg = regs[4];
4466
4467 switch (mcv) {
4468 .stack_offset => |off| {
4469 // sub src_reg, fp, #off
4470 try self.genSetReg(ptr_ty, src_reg, .{ .ptr_stack_offset = off });
4471 },
4472 .memory => |addr| try self.genSetReg(ptr_ty, src_reg, .{ .immediate = @intCast(u32, addr) }),
4473 .got_load,
4474 .direct_load,
4475 => |sym_index| {
4476 const tag: Mir.Inst.Tag = switch (mcv) {
4477 .got_load => .load_memory_ptr_got,
4478 .direct_load => .load_memory_ptr_direct,
4479 else => unreachable,
4480 };
4481 const mod = self.bin_file.options.module.?;
4482 _ = try self.addInst(.{
4483 .tag = tag,
4484 .data = .{
4485 .payload = try self.addExtra(Mir.LoadMemoryPie{
4486 .register = @enumToInt(src_reg),
4487 .atom_index = mod.declPtr(self.mod_fn.owner_decl).link.macho.sym_index,
4488 .sym_index = sym_index,
4489 }),
4490 },
4491 });
4492 },
4493 .stack_argument_offset => return self.fail("TODO load {}", .{mcv}),
4494 else => unreachable,
4495 }
4496
4497 // add dst_reg, sp, #stack_offset
4498 _ = try self.addInst(.{
4499 .tag = .add_immediate,
4500 .data = .{ .rr_imm12_sh = .{
4501 .rd = dst_reg,
4502 .rn = .sp,
4503 .imm12 = math.cast(u12, stack_offset) orelse {
4504 return self.fail("TODO load: set reg to stack offset with all possible offsets", .{});
4505 },
4506 } },
4507 });
4508
4509 // mov len, #abi_size
4510 try self.genSetReg(Type.usize, len_reg, .{ .immediate = abi_size });
4511
4512 // memcpy(src, dst, len)
4513 try self.genInlineMemcpy(src_reg, dst_reg, len_reg, count_reg, tmp_reg);
4514 }
4515 },
4516 .condition_flags,
4517 .immediate,
4518 .ptr_stack_offset,
4519 => {
4520 const reg = try self.copyToTmpRegister(ty, mcv);
4521 return self.genSetStackArgument(ty, stack_offset, MCValue{ .register = reg });
4522 },
43314523 }
43324524}
43334525
......@@ -4835,8 +5027,8 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues {
48355027 }
48365028 }
48375029
4838 result.args[i] = .{ .stack_offset = nsaa };
48395030 nsaa += param_size;
5031 result.args[i] = .{ .stack_argument_offset = nsaa };
48405032 }
48415033 }
48425034
src/arch/aarch64/Emit.zig+64
......@@ -27,14 +27,21 @@ code: *std.ArrayList(u8),
2727
2828prev_di_line: u32,
2929prev_di_column: u32,
30
3031/// Relative to the beginning of `code`.
3132prev_di_pc: usize,
3233
34/// The amount of stack space consumed by all stack arguments as well
35/// as the saved callee-saved registers
36prologue_stack_space: u32,
37
3338/// The branch type of every branch
3439branch_types: std.AutoHashMapUnmanaged(Mir.Inst.Index, BranchType) = .{},
40
3541/// For every forward branch, maps the target instruction to a list of
3642/// branches which branch to this target instruction
3743branch_forward_origins: std.AutoHashMapUnmanaged(Mir.Inst.Index, std.ArrayListUnmanaged(Mir.Inst.Index)) = .{},
44
3845/// For backward branches: stores the code offset of the target
3946/// instruction
4047///
......@@ -42,6 +49,8 @@ branch_forward_origins: std.AutoHashMapUnmanaged(Mir.Inst.Index, std.ArrayListUn
4249/// instruction
4350code_offset_mapping: std.AutoHashMapUnmanaged(Mir.Inst.Index, usize) = .{},
4451
52/// The final stack frame size of the function (already aligned to the
53/// respective stack alignment). Does not include prologue stack space.
4554stack_size: u32,
4655
4756const InnerError = error{
......@@ -148,6 +157,12 @@ pub fn emitMir(
148157 .strb_stack => try emit.mirLoadStoreStack(inst),
149158 .strh_stack => try emit.mirLoadStoreStack(inst),
150159
160 .ldr_stack_argument => try emit.mirLoadStackArgument(inst),
161 .ldrb_stack_argument => try emit.mirLoadStackArgument(inst),
162 .ldrh_stack_argument => try emit.mirLoadStackArgument(inst),
163 .ldrsb_stack_argument => try emit.mirLoadStackArgument(inst),
164 .ldrsh_stack_argument => try emit.mirLoadStackArgument(inst),
165
151166 .ldr_register => try emit.mirLoadStoreRegisterRegister(inst),
152167 .ldrb_register => try emit.mirLoadStoreRegisterRegister(inst),
153168 .ldrh_register => try emit.mirLoadStoreRegisterRegister(inst),
......@@ -920,6 +935,55 @@ fn mirLoadStoreRegisterPair(emit: *Emit, inst: Mir.Inst.Index) !void {
920935 }
921936}
922937
938fn mirLoadStackArgument(emit: *Emit, inst: Mir.Inst.Index) !void {
939 const tag = emit.mir.instructions.items(.tag)[inst];
940 const load_store_stack = emit.mir.instructions.items(.data)[inst].load_store_stack;
941 const rt = load_store_stack.rt;
942
943 const raw_offset = emit.stack_size + emit.prologue_stack_space - load_store_stack.offset;
944 const offset = switch (tag) {
945 .ldrb_stack_argument, .ldrsb_stack_argument => blk: {
946 if (math.cast(u12, raw_offset)) |imm| {
947 break :blk Instruction.LoadStoreOffset.imm(imm);
948 } else {
949 return emit.fail("TODO load stack argument byte with larger offset", .{});
950 }
951 },
952 .ldrh_stack_argument, .ldrsh_stack_argument => blk: {
953 assert(std.mem.isAlignedGeneric(u32, raw_offset, 2)); // misaligned stack entry
954 if (math.cast(u12, @divExact(raw_offset, 2))) |imm| {
955 break :blk Instruction.LoadStoreOffset.imm(imm);
956 } else {
957 return emit.fail("TODO load stack argument halfword with larger offset", .{});
958 }
959 },
960 .ldr_stack_argument => blk: {
961 const alignment: u32 = switch (rt.size()) {
962 32 => 4,
963 64 => 8,
964 else => unreachable,
965 };
966
967 assert(std.mem.isAlignedGeneric(u32, raw_offset, alignment)); // misaligned stack entry
968 if (math.cast(u12, @divExact(raw_offset, alignment))) |imm| {
969 break :blk Instruction.LoadStoreOffset.imm(imm);
970 } else {
971 return emit.fail("TODO load stack argument with larger offset", .{});
972 }
973 },
974 else => unreachable,
975 };
976
977 switch (tag) {
978 .ldr_stack_argument => try emit.writeInstruction(Instruction.ldr(rt, .sp, offset)),
979 .ldrb_stack_argument => try emit.writeInstruction(Instruction.ldrb(rt, .sp, offset)),
980 .ldrh_stack_argument => try emit.writeInstruction(Instruction.ldrh(rt, .sp, offset)),
981 .ldrsb_stack_argument => try emit.writeInstruction(Instruction.ldrsb(rt, .sp, offset)),
982 .ldrsh_stack_argument => try emit.writeInstruction(Instruction.ldrsh(rt, .sp, offset)),
983 else => unreachable,
984 }
985}
986
923987fn mirLoadStoreStack(emit: *Emit, inst: Mir.Inst.Index) !void {
924988 const tag = emit.mir.instructions.items(.tag)[inst];
925989 const load_store_stack = emit.mir.instructions.items(.data)[inst].load_store_stack;
src/arch/aarch64/Mir.zig+10
......@@ -94,18 +94,24 @@ pub const Inst = struct {
9494 ldp,
9595 /// Pseudo-instruction: Load from stack
9696 ldr_stack,
97 /// Pseudo-instruction: Load from stack argument
98 ldr_stack_argument,
9799 /// Load Register (immediate)
98100 ldr_immediate,
99101 /// Load Register (register)
100102 ldr_register,
101103 /// Pseudo-instruction: Load byte from stack
102104 ldrb_stack,
105 /// Pseudo-instruction: Load byte from stack argument
106 ldrb_stack_argument,
103107 /// Load Register Byte (immediate)
104108 ldrb_immediate,
105109 /// Load Register Byte (register)
106110 ldrb_register,
107111 /// Pseudo-instruction: Load halfword from stack
108112 ldrh_stack,
113 /// Pseudo-instruction: Load halfword from stack argument
114 ldrh_stack_argument,
109115 /// Load Register Halfword (immediate)
110116 ldrh_immediate,
111117 /// Load Register Halfword (register)
......@@ -114,10 +120,14 @@ pub const Inst = struct {
114120 ldrsb_immediate,
115121 /// Pseudo-instruction: Load signed byte from stack
116122 ldrsb_stack,
123 /// Pseudo-instruction: Load signed byte from stack argument
124 ldrsb_stack_argument,
117125 /// Load Register Signed Halfword (immediate)
118126 ldrsh_immediate,
119127 /// Pseudo-instruction: Load signed halfword from stack
120128 ldrsh_stack,
129 /// Pseudo-instruction: Load signed halfword from stack argument
130 ldrsh_stack_argument,
121131 /// Load Register Signed Word (immediate)
122132 ldrsw_immediate,
123133 /// Logical Shift Left (immediate)