| ... | @@ -166,10 +166,12 @@ const MCValue = union(enum) { | ... | @@ -166,10 +166,12 @@ const MCValue = union(enum) { |
| 166 | /// the type is u1) or true (if the type in bool) iff the | 166 | /// the type is u1) or true (if the type in bool) iff the |
| 167 | /// specified condition is true. | 167 | /// specified condition is true. |
| 168 | condition_flags: Condition, | 168 | condition_flags: Condition, |
| | 169 | /// The value is a function argument passed via the stack. |
| | 170 | stack_argument_offset: u32, |
| 169 | | 171 | |
| 170 | fn isMemory(mcv: MCValue) bool { | 172 | fn isMemory(mcv: MCValue) bool { |
| 171 | return switch (mcv) { | 173 | return switch (mcv) { |
| 172 | .memory, .stack_offset => true, | 174 | .memory, .stack_offset, .stack_argument_offset => true, |
| 173 | else => false, | 175 | else => false, |
| 174 | }; | 176 | }; |
| 175 | } | 177 | } |
| ... | @@ -192,6 +194,7 @@ const MCValue = union(enum) { | ... | @@ -192,6 +194,7 @@ const MCValue = union(enum) { |
| 192 | .condition_flags, | 194 | .condition_flags, |
| 193 | .ptr_stack_offset, | 195 | .ptr_stack_offset, |
| 194 | .undef, | 196 | .undef, |
| | 197 | .stack_argument_offset, |
| 195 | => false, | 198 | => false, |
| 196 | | 199 | |
| 197 | .register, | 200 | .register, |
| ... | @@ -337,6 +340,7 @@ pub fn generate( | ... | @@ -337,6 +340,7 @@ pub fn generate( |
| 337 | .prev_di_line = module_fn.lbrace_line, | 340 | .prev_di_line = module_fn.lbrace_line, |
| 338 | .prev_di_column = module_fn.lbrace_column, | 341 | .prev_di_column = module_fn.lbrace_column, |
| 339 | .stack_size = mem.alignForwardGeneric(u32, function.max_end_stack, function.stack_align), | 342 | .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, |
| 340 | }; | 344 | }; |
| 341 | defer emit.deinit(); | 345 | defer emit.deinit(); |
| 342 | | 346 | |
| ... | @@ -2726,6 +2730,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo | ... | @@ -2726,6 +2730,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo |
| 2726 | }, | 2730 | }, |
| 2727 | .memory, | 2731 | .memory, |
| 2728 | .stack_offset, | 2732 | .stack_offset, |
| | 2733 | .stack_argument_offset, |
| 2729 | .got_load, | 2734 | .got_load, |
| 2730 | .direct_load, | 2735 | .direct_load, |
| 2731 | => { | 2736 | => { |
| ... | @@ -2927,6 +2932,7 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type | ... | @@ -2927,6 +2932,7 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type |
| 2927 | }, | 2932 | }, |
| 2928 | .memory, | 2933 | .memory, |
| 2929 | .stack_offset, | 2934 | .stack_offset, |
| | 2935 | .stack_argument_offset, |
| 2930 | .got_load, | 2936 | .got_load, |
| 2931 | .direct_load, | 2937 | .direct_load, |
| 2932 | => { | 2938 | => { |
| ... | @@ -3009,6 +3015,9 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -3009,6 +3015,9 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void { |
| 3009 | | 3015 | |
| 3010 | switch (mcv) { | 3016 | switch (mcv) { |
| 3011 | .dead, .unreach => unreachable, | 3017 | .dead, .unreach => unreachable, |
| | 3018 | .stack_argument_offset => |off| { |
| | 3019 | break :result MCValue{ .stack_argument_offset = off - struct_field_offset }; |
| | 3020 | }, |
| 3012 | .stack_offset => |off| { | 3021 | .stack_offset => |off| { |
| 3013 | break :result MCValue{ .stack_offset = off - struct_field_offset }; | 3022 | break :result MCValue{ .stack_offset = off - struct_field_offset }; |
| 3014 | }, | 3023 | }, |
| ... | @@ -3152,12 +3161,12 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions. | ... | @@ -3152,12 +3161,12 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions. |
| 3152 | try self.register_manager.getReg(reg, null); | 3161 | try self.register_manager.getReg(reg, null); |
| 3153 | try self.genSetReg(arg_ty, reg, arg_mcv); | 3162 | try self.genSetReg(arg_ty, reg, arg_mcv); |
| 3154 | }, | 3163 | }, |
| 3155 | .stack_offset => { | 3164 | .stack_offset => unreachable, |
| 3156 | return self.fail("TODO implement calling with parameters in memory", .{}); | 3165 | .stack_argument_offset => |offset| try self.genSetStackArgument( |
| 3157 | }, | 3166 | arg_ty, |
| 3158 | .ptr_stack_offset => { | 3167 | info.stack_byte_count - offset, |
| 3159 | return self.fail("TODO implement calling with MCValue.ptr_stack_offset arg", .{}); | 3168 | arg_mcv, |
| 3160 | }, | 3169 | ), |
| 3161 | else => unreachable, | 3170 | else => unreachable, |
| 3162 | } | 3171 | } |
| 3163 | } | 3172 | } |
| ... | @@ -3884,7 +3893,7 @@ fn br(self: *Self, block: Air.Inst.Index, operand: Air.Inst.Ref) !void { | ... | @@ -3884,7 +3893,7 @@ fn br(self: *Self, block: Air.Inst.Index, operand: Air.Inst.Ref) !void { |
| 3884 | block_data.mcv = switch (operand_mcv) { | 3893 | block_data.mcv = switch (operand_mcv) { |
| 3885 | .none, .dead, .unreach => unreachable, | 3894 | .none, .dead, .unreach => unreachable, |
| 3886 | .register, .stack_offset, .memory => operand_mcv, | 3895 | .register, .stack_offset, .memory => operand_mcv, |
| 3887 | .immediate, .condition_flags => blk: { | 3896 | .immediate, .stack_argument_offset, .condition_flags => blk: { |
| 3888 | const new_mcv = try self.allocRegOrMem(block, true); | 3897 | const new_mcv = try self.allocRegOrMem(block, true); |
| 3889 | try self.setRegOrMem(self.air.typeOfIndex(block), new_mcv, operand_mcv); | 3898 | try self.setRegOrMem(self.air.typeOfIndex(block), new_mcv, operand_mcv); |
| 3890 | break :blk new_mcv; | 3899 | break :blk new_mcv; |
| ... | @@ -4126,6 +4135,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro | ... | @@ -4126,6 +4135,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro |
| 4126 | .got_load, | 4135 | .got_load, |
| 4127 | .direct_load, | 4136 | .direct_load, |
| 4128 | .memory, | 4137 | .memory, |
| | 4138 | .stack_argument_offset, |
| 4129 | .stack_offset, | 4139 | .stack_offset, |
| 4130 | => { | 4140 | => { |
| 4131 | switch (mcv) { | 4141 | switch (mcv) { |
| ... | @@ -4328,6 +4338,188 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void | ... | @@ -4328,6 +4338,188 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void |
| 4328 | else => unreachable, | 4338 | else => unreachable, |
| 4329 | } | 4339 | } |
| 4330 | }, | 4340 | }, |
| | 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 | |
| | 4368 | fn 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 | }, |
| 4331 | } | 4523 | } |
| 4332 | } | 4524 | } |
| 4333 | | 4525 | |
| ... | @@ -4835,8 +5027,8 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues { | ... | @@ -4835,8 +5027,8 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues { |
| 4835 | } | 5027 | } |
| 4836 | } | 5028 | } |
| 4837 | | 5029 | |
| 4838 | result.args[i] = .{ .stack_offset = nsaa }; | | |
| 4839 | nsaa += param_size; | 5030 | nsaa += param_size; |
| | 5031 | result.args[i] = .{ .stack_argument_offset = nsaa }; |
| 4840 | } | 5032 | } |
| 4841 | } | 5033 | } |
| 4842 | | 5034 | |