| ... | ... | @@ -573,17 +573,21 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 573 | 573 | // sub sp, sp, #reloc |
| 574 | 574 | mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.push(.al, .{ .fp, .lr }).toU32()); |
| 575 | 575 | mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.mov(.al, .fp, Instruction.Operand.reg(.sp, Instruction.Operand.Shift.none)).toU32()); |
| 576 | | // TODO: prepare stack for local variables |
| 577 | | // const backpatch_reloc = try self.code.addManyAsArray(4); |
| 576 | const backpatch_reloc = self.code.items.len; |
| 577 | try self.code.resize(backpatch_reloc + 4); |
| 578 | 578 | |
| 579 | 579 | try self.dbgSetPrologueEnd(); |
| 580 | 580 | |
| 581 | 581 | try self.genBody(self.mod_fn.analysis.success); |
| 582 | 582 | |
| 583 | 583 | // Backpatch stack offset |
| 584 | | // const stack_end = self.max_end_stack; |
| 585 | | // const aligned_stack_end = mem.alignForward(stack_end, self.stack_align); |
| 586 | | // mem.writeIntLittle(u32, backpatch_reloc, Instruction.sub(.al, .sp, .sp, Instruction.Operand.imm())); |
| 584 | const stack_end = self.max_end_stack; |
| 585 | const aligned_stack_end = mem.alignForward(stack_end, self.stack_align); |
| 586 | if (Instruction.Operand.fromU32(@intCast(u32, aligned_stack_end))) |op| { |
| 587 | mem.writeIntLittle(u32, self.code.items[backpatch_reloc..][0..4], Instruction.sub(.al, .sp, .sp, op).toU32()); |
| 588 | } else { |
| 589 | return self.fail(self.src, "TODO ARM: allow larger stacks", .{}); |
| 590 | } |
| 587 | 591 | |
| 588 | 592 | try self.dbgSetEpilogueBegin(); |
| 589 | 593 | |
| ... | ... | @@ -2196,6 +2200,58 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 2196 | 2200 | |
| 2197 | 2201 | fn genSetStack(self: *Self, src: usize, ty: Type, stack_offset: u32, mcv: MCValue) InnerError!void { |
| 2198 | 2202 | switch (arch) { |
| 2203 | .arm => switch (mcv) { |
| 2204 | .dead => unreachable, |
| 2205 | .ptr_stack_offset => unreachable, |
| 2206 | .ptr_embedded_in_code => unreachable, |
| 2207 | .unreach, .none => return, // Nothing to do. |
| 2208 | .undef => { |
| 2209 | if (!self.wantSafety()) |
| 2210 | return; // The already existing value will do just fine. |
| 2211 | // TODO Upgrade this to a memset call when we have that available. |
| 2212 | switch (ty.abiSize(self.target.*)) { |
| 2213 | 1 => return self.genSetStack(src, ty, stack_offset, .{ .immediate = 0xaa }), |
| 2214 | 2 => return self.genSetStack(src, ty, stack_offset, .{ .immediate = 0xaaaa }), |
| 2215 | 4 => return self.genSetStack(src, ty, stack_offset, .{ .immediate = 0xaaaaaaaa }), |
| 2216 | 8 => return self.genSetStack(src, ty, stack_offset, .{ .immediate = 0xaaaaaaaaaaaaaaaa }), |
| 2217 | else => return self.fail(src, "TODO implement memset", .{}), |
| 2218 | } |
| 2219 | }, |
| 2220 | .compare_flags_unsigned => |op| { |
| 2221 | return self.fail(src, "TODO implement set stack variable with compare flags value (unsigned)", .{}); |
| 2222 | }, |
| 2223 | .compare_flags_signed => |op| { |
| 2224 | return self.fail(src, "TODO implement set stack variable with compare flags value (signed)", .{}); |
| 2225 | }, |
| 2226 | .immediate => { |
| 2227 | const reg = try self.copyToTmpRegister(src, mcv); |
| 2228 | return self.genSetStack(src, ty, stack_offset, MCValue{ .register = reg }); |
| 2229 | }, |
| 2230 | .embedded_in_code => |code_offset| { |
| 2231 | return self.fail(src, "TODO implement set stack variable from embedded_in_code", .{}); |
| 2232 | }, |
| 2233 | .register => |reg| { |
| 2234 | // TODO: strb, strh |
| 2235 | if (stack_offset <= math.maxInt(u12)) { |
| 2236 | mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.str(.al, reg, .fp, .{ |
| 2237 | .offset = Instruction.Offset.imm(@intCast(u12, stack_offset)), |
| 2238 | .positive = false, |
| 2239 | }).toU32()); |
| 2240 | } else { |
| 2241 | return self.fail(src, "TODO genSetStack with larger offsets", .{}); |
| 2242 | } |
| 2243 | }, |
| 2244 | .memory => |vaddr| { |
| 2245 | return self.fail(src, "TODO implement set stack variable from memory vaddr", .{}); |
| 2246 | }, |
| 2247 | .stack_offset => |off| { |
| 2248 | if (stack_offset == off) |
| 2249 | return; // Copy stack variable to itself; nothing to do. |
| 2250 | |
| 2251 | const reg = try self.copyToTmpRegister(src, mcv); |
| 2252 | return self.genSetStack(src, ty, stack_offset, MCValue{ .register = reg }); |
| 2253 | }, |
| 2254 | }, |
| 2199 | 2255 | .x86_64 => switch (mcv) { |
| 2200 | 2256 | .dead => unreachable, |
| 2201 | 2257 | .ptr_stack_offset => unreachable, |
| ... | ... | @@ -2352,6 +2408,18 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 2352 | 2408 | try self.genSetReg(src, reg, .{ .immediate = addr }); |
| 2353 | 2409 | mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.ldr(.al, reg, reg, .{ .offset = Instruction.Offset.none }).toU32()); |
| 2354 | 2410 | }, |
| 2411 | .stack_offset => |unadjusted_off| { |
| 2412 | // TODO: ldrb, ldrh |
| 2413 | // TODO: maybe addressing from sp instead of fp |
| 2414 | if (unadjusted_off <= math.maxInt(u12)) { |
| 2415 | mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.ldr(.al, reg, .fp, .{ |
| 2416 | .offset = Instruction.Offset.imm(@intCast(u12, unadjusted_off)), |
| 2417 | .positive = false, |
| 2418 | }).toU32()); |
| 2419 | } else { |
| 2420 | return self.fail(src, "TODO genSetReg with larger stack offset", .{}); |
| 2421 | } |
| 2422 | }, |
| 2355 | 2423 | else => return self.fail(src, "TODO implement getSetReg for arm {}", .{mcv}), |
| 2356 | 2424 | }, |
| 2357 | 2425 | .riscv64 => switch (mcv) { |