| ... | ... | @@ -166,10 +166,12 @@ const MCValue = union(enum) { |
| 166 | 166 | /// the type is u1) or true (if the type in bool) iff the |
| 167 | 167 | /// specified condition is true. |
| 168 | 168 | condition_flags: Condition, |
| 169 | /// The value is a function argument passed via the stack. |
| 170 | stack_argument_offset: u32, |
| 169 | 171 | |
| 170 | 172 | fn isMemory(mcv: MCValue) bool { |
| 171 | 173 | return switch (mcv) { |
| 172 | | .memory, .stack_offset => true, |
| 174 | .memory, .stack_offset, .stack_argument_offset => true, |
| 173 | 175 | else => false, |
| 174 | 176 | }; |
| 175 | 177 | } |
| ... | ... | @@ -192,6 +194,7 @@ const MCValue = union(enum) { |
| 192 | 194 | .condition_flags, |
| 193 | 195 | .ptr_stack_offset, |
| 194 | 196 | .undef, |
| 197 | .stack_argument_offset, |
| 195 | 198 | => false, |
| 196 | 199 | |
| 197 | 200 | .register, |
| ... | ... | @@ -337,6 +340,7 @@ pub fn generate( |
| 337 | 340 | .prev_di_line = module_fn.lbrace_line, |
| 338 | 341 | .prev_di_column = module_fn.lbrace_column, |
| 339 | 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 | 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 | 2730 | }, |
| 2727 | 2731 | .memory, |
| 2728 | 2732 | .stack_offset, |
| 2733 | .stack_argument_offset, |
| 2729 | 2734 | .got_load, |
| 2730 | 2735 | .direct_load, |
| 2731 | 2736 | => { |
| ... | ... | @@ -2927,6 +2932,7 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type |
| 2927 | 2932 | }, |
| 2928 | 2933 | .memory, |
| 2929 | 2934 | .stack_offset, |
| 2935 | .stack_argument_offset, |
| 2930 | 2936 | .got_load, |
| 2931 | 2937 | .direct_load, |
| 2932 | 2938 | => { |
| ... | ... | @@ -3009,6 +3015,9 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void { |
| 3009 | 3015 | |
| 3010 | 3016 | switch (mcv) { |
| 3011 | 3017 | .dead, .unreach => unreachable, |
| 3018 | .stack_argument_offset => |off| { |
| 3019 | break :result MCValue{ .stack_argument_offset = off - struct_field_offset }; |
| 3020 | }, |
| 3012 | 3021 | .stack_offset => |off| { |
| 3013 | 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 | 3161 | try self.register_manager.getReg(reg, null); |
| 3153 | 3162 | try self.genSetReg(arg_ty, reg, arg_mcv); |
| 3154 | 3163 | }, |
| 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 | ), |
| 3161 | 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 | 3893 | block_data.mcv = switch (operand_mcv) { |
| 3885 | 3894 | .none, .dead, .unreach => unreachable, |
| 3886 | 3895 | .register, .stack_offset, .memory => operand_mcv, |
| 3887 | | .immediate, .condition_flags => blk: { |
| 3896 | .immediate, .stack_argument_offset, .condition_flags => blk: { |
| 3888 | 3897 | const new_mcv = try self.allocRegOrMem(block, true); |
| 3889 | 3898 | try self.setRegOrMem(self.air.typeOfIndex(block), new_mcv, operand_mcv); |
| 3890 | 3899 | break :blk new_mcv; |
| ... | ... | @@ -4126,6 +4135,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro |
| 4126 | 4135 | .got_load, |
| 4127 | 4136 | .direct_load, |
| 4128 | 4137 | .memory, |
| 4138 | .stack_argument_offset, |
| 4129 | 4139 | .stack_offset, |
| 4130 | 4140 | => { |
| 4131 | 4141 | switch (mcv) { |
| ... | ... | @@ -4328,6 +4338,188 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void |
| 4328 | 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 | 5027 | } |
| 4836 | 5028 | } |
| 4837 | 5029 | |
| 4838 | | result.args[i] = .{ .stack_offset = nsaa }; |
| 4839 | 5030 | nsaa += param_size; |
| 5031 | result.args[i] = .{ .stack_argument_offset = nsaa }; |
| 4840 | 5032 | } |
| 4841 | 5033 | } |
| 4842 | 5034 | |