| ... | ... | @@ -142,40 +142,52 @@ pub fn generateSymbol( |
| 142 | 142 | ), |
| 143 | 143 | }; |
| 144 | 144 | }, |
| 145 | | .Pointer => { |
| 146 | | // TODO populate .debug_info for the pointer |
| 147 | | if (typed_value.val.castTag(.decl_ref)) |payload| { |
| 148 | | const decl = payload.data; |
| 149 | | if (decl.analysis != .complete) return error.AnalysisFail; |
| 150 | | // TODO handle the dependency of this symbol on the decl's vaddr. |
| 151 | | // If the decl changes vaddr, then this symbol needs to get regenerated. |
| 152 | | const vaddr = bin_file.getDeclVAddr(decl); |
| 153 | | const endian = bin_file.options.target.cpu.arch.endian(); |
| 154 | | switch (bin_file.options.target.cpu.arch.ptrBitWidth()) { |
| 155 | | 16 => { |
| 156 | | try code.resize(2); |
| 157 | | mem.writeInt(u16, code.items[0..2], @intCast(u16, vaddr), endian); |
| 158 | | }, |
| 159 | | 32 => { |
| 160 | | try code.resize(4); |
| 161 | | mem.writeInt(u32, code.items[0..4], @intCast(u32, vaddr), endian); |
| 162 | | }, |
| 163 | | 64 => { |
| 164 | | try code.resize(8); |
| 165 | | mem.writeInt(u64, code.items[0..8], vaddr, endian); |
| 166 | | }, |
| 167 | | else => unreachable, |
| 145 | .Pointer => switch (typed_value.ty.ptrSize()) { |
| 146 | .Slice => { |
| 147 | return Result{ |
| 148 | .fail = try ErrorMsg.create( |
| 149 | bin_file.allocator, |
| 150 | src_loc, |
| 151 | "TODO implement generateSymbol for slice {}", |
| 152 | .{typed_value.val}, |
| 153 | ), |
| 154 | }; |
| 155 | }, |
| 156 | else => { |
| 157 | // TODO populate .debug_info for the pointer |
| 158 | if (typed_value.val.castTag(.decl_ref)) |payload| { |
| 159 | const decl = payload.data; |
| 160 | if (decl.analysis != .complete) return error.AnalysisFail; |
| 161 | // TODO handle the dependency of this symbol on the decl's vaddr. |
| 162 | // If the decl changes vaddr, then this symbol needs to get regenerated. |
| 163 | const vaddr = bin_file.getDeclVAddr(decl); |
| 164 | const endian = bin_file.options.target.cpu.arch.endian(); |
| 165 | switch (bin_file.options.target.cpu.arch.ptrBitWidth()) { |
| 166 | 16 => { |
| 167 | try code.resize(2); |
| 168 | mem.writeInt(u16, code.items[0..2], @intCast(u16, vaddr), endian); |
| 169 | }, |
| 170 | 32 => { |
| 171 | try code.resize(4); |
| 172 | mem.writeInt(u32, code.items[0..4], @intCast(u32, vaddr), endian); |
| 173 | }, |
| 174 | 64 => { |
| 175 | try code.resize(8); |
| 176 | mem.writeInt(u64, code.items[0..8], vaddr, endian); |
| 177 | }, |
| 178 | else => unreachable, |
| 179 | } |
| 180 | return Result{ .appended = {} }; |
| 168 | 181 | } |
| 169 | | return Result{ .appended = {} }; |
| 170 | | } |
| 171 | | return Result{ |
| 172 | | .fail = try ErrorMsg.create( |
| 173 | | bin_file.allocator, |
| 174 | | src_loc, |
| 175 | | "TODO implement generateSymbol for pointer {}", |
| 176 | | .{typed_value.val}, |
| 177 | | ), |
| 178 | | }; |
| 182 | return Result{ |
| 183 | .fail = try ErrorMsg.create( |
| 184 | bin_file.allocator, |
| 185 | src_loc, |
| 186 | "TODO implement generateSymbol for pointer {}", |
| 187 | .{typed_value.val}, |
| 188 | ), |
| 189 | }; |
| 190 | }, |
| 179 | 191 | }, |
| 180 | 192 | .Int => { |
| 181 | 193 | // TODO populate .debug_info for the integer |
| ... | ... | @@ -2244,10 +2256,10 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 2244 | 2256 | try self.register_manager.getReg(reg, null); |
| 2245 | 2257 | try self.genSetReg(arg.src, arg.ty, reg, arg_mcv); |
| 2246 | 2258 | }, |
| 2247 | | .stack_offset => { |
| 2259 | .stack_offset => |off| { |
| 2248 | 2260 | // Here we need to emit instructions like this: |
| 2249 | 2261 | // mov qword ptr [rsp + stack_offset], x |
| 2250 | | return self.fail(inst.base.src, "TODO implement calling with parameters in memory", .{}); |
| 2262 | try self.genSetStack(arg.src, arg.ty, off, arg_mcv); |
| 2251 | 2263 | }, |
| 2252 | 2264 | .ptr_stack_offset => { |
| 2253 | 2265 | return self.fail(inst.base.src, "TODO implement calling with MCValue.ptr_stack_offset arg", .{}); |
| ... | ... | @@ -3444,9 +3456,11 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 3444 | 3456 | }, |
| 3445 | 3457 | } |
| 3446 | 3458 | }, |
| 3447 | | .embedded_in_code => |code_offset| { |
| 3448 | | _ = code_offset; |
| 3449 | | return self.fail(src, "TODO implement set stack variable from embedded_in_code", .{}); |
| 3459 | .embedded_in_code => { |
| 3460 | // TODO this and `.stack_offset` below need to get improved to support types greater than |
| 3461 | // register size, and do general memcpy |
| 3462 | const reg = try self.copyToTmpRegister(src, ty, mcv); |
| 3463 | return self.genSetStack(src, ty, stack_offset, MCValue{ .register = reg }); |
| 3450 | 3464 | }, |
| 3451 | 3465 | .register => |reg| { |
| 3452 | 3466 | try self.genX8664ModRMRegToStack(src, ty, stack_offset, reg, 0x89); |
| ... | ... | @@ -3456,6 +3470,9 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 3456 | 3470 | return self.fail(src, "TODO implement set stack variable from memory vaddr", .{}); |
| 3457 | 3471 | }, |
| 3458 | 3472 | .stack_offset => |off| { |
| 3473 | // TODO this and `.embedded_in_code` above need to get improved to support types greater than |
| 3474 | // register size, and do general memcpy |
| 3475 | |
| 3459 | 3476 | if (stack_offset == off) |
| 3460 | 3477 | return; // Copy stack variable to itself; nothing to do. |
| 3461 | 3478 | |
| ... | ... | @@ -4161,33 +4178,48 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 4161 | 4178 | const ptr_bits = self.target.cpu.arch.ptrBitWidth(); |
| 4162 | 4179 | const ptr_bytes: u64 = @divExact(ptr_bits, 8); |
| 4163 | 4180 | switch (typed_value.ty.zigTypeTag()) { |
| 4164 | | .Pointer => { |
| 4165 | | if (typed_value.val.castTag(.decl_ref)) |payload| { |
| 4166 | | if (self.bin_file.cast(link.File.Elf)) |elf_file| { |
| 4167 | | const decl = payload.data; |
| 4168 | | const got = &elf_file.program_headers.items[elf_file.phdr_got_index.?]; |
| 4169 | | const got_addr = got.p_vaddr + decl.link.elf.offset_table_index * ptr_bytes; |
| 4170 | | return MCValue{ .memory = got_addr }; |
| 4171 | | } else if (self.bin_file.cast(link.File.MachO)) |macho_file| { |
| 4172 | | const decl = payload.data; |
| 4173 | | const got_addr = blk: { |
| 4174 | | const seg = macho_file.load_commands.items[macho_file.data_const_segment_cmd_index.?].Segment; |
| 4175 | | const got = seg.sections.items[macho_file.got_section_index.?]; |
| 4176 | | break :blk got.addr + decl.link.macho.offset_table_index * ptr_bytes; |
| 4177 | | }; |
| 4178 | | return MCValue{ .memory = got_addr }; |
| 4179 | | } else if (self.bin_file.cast(link.File.Coff)) |coff_file| { |
| 4180 | | const decl = payload.data; |
| 4181 | | const got_addr = coff_file.offset_table_virtual_address + decl.link.coff.offset_table_index * ptr_bytes; |
| 4182 | | return MCValue{ .memory = got_addr }; |
| 4183 | | } else { |
| 4184 | | return self.fail(src, "TODO codegen non-ELF const Decl pointer", .{}); |
| 4181 | .Pointer => switch (typed_value.ty.ptrSize()) { |
| 4182 | .Slice => { |
| 4183 | var buf: Type.Payload.ElemType = undefined; |
| 4184 | const ptr_type = typed_value.ty.slicePtrFieldType(&buf); |
| 4185 | const ptr_mcv = try self.genTypedValue(src, .{ .ty = ptr_type, .val = typed_value.val }); |
| 4186 | const slice_len = typed_value.val.sliceLen(); |
| 4187 | // Codegen can't handle some kinds of indirection. If the wrong union field is accessed here it may mean |
| 4188 | // the Sema code needs to use anonymous Decls or alloca instructions to store data. |
| 4189 | const ptr_imm = ptr_mcv.memory; |
| 4190 | _ = slice_len; |
| 4191 | _ = ptr_imm; |
| 4192 | // We need more general support for const data being stored in memory to make this work. |
| 4193 | return self.fail(src, "TODO codegen for const slices", .{}); |
| 4194 | }, |
| 4195 | else => { |
| 4196 | if (typed_value.val.castTag(.decl_ref)) |payload| { |
| 4197 | if (self.bin_file.cast(link.File.Elf)) |elf_file| { |
| 4198 | const decl = payload.data; |
| 4199 | const got = &elf_file.program_headers.items[elf_file.phdr_got_index.?]; |
| 4200 | const got_addr = got.p_vaddr + decl.link.elf.offset_table_index * ptr_bytes; |
| 4201 | return MCValue{ .memory = got_addr }; |
| 4202 | } else if (self.bin_file.cast(link.File.MachO)) |macho_file| { |
| 4203 | const decl = payload.data; |
| 4204 | const got_addr = blk: { |
| 4205 | const seg = macho_file.load_commands.items[macho_file.data_const_segment_cmd_index.?].Segment; |
| 4206 | const got = seg.sections.items[macho_file.got_section_index.?]; |
| 4207 | break :blk got.addr + decl.link.macho.offset_table_index * ptr_bytes; |
| 4208 | }; |
| 4209 | return MCValue{ .memory = got_addr }; |
| 4210 | } else if (self.bin_file.cast(link.File.Coff)) |coff_file| { |
| 4211 | const decl = payload.data; |
| 4212 | const got_addr = coff_file.offset_table_virtual_address + decl.link.coff.offset_table_index * ptr_bytes; |
| 4213 | return MCValue{ .memory = got_addr }; |
| 4214 | } else { |
| 4215 | return self.fail(src, "TODO codegen non-ELF const Decl pointer", .{}); |
| 4216 | } |
| 4185 | 4217 | } |
| 4186 | | } |
| 4187 | | if (typed_value.val.tag() == .int_u64) { |
| 4188 | | return MCValue{ .immediate = typed_value.val.toUnsignedInt() }; |
| 4189 | | } |
| 4190 | | return self.fail(src, "TODO codegen more kinds of const pointers", .{}); |
| 4218 | if (typed_value.val.tag() == .int_u64) { |
| 4219 | return MCValue{ .immediate = typed_value.val.toUnsignedInt() }; |
| 4220 | } |
| 4221 | return self.fail(src, "TODO codegen more kinds of const pointers", .{}); |
| 4222 | }, |
| 4191 | 4223 | }, |
| 4192 | 4224 | .Int => { |
| 4193 | 4225 | const info = typed_value.ty.intInfo(self.target.*); |
| ... | ... | @@ -4264,27 +4296,39 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 4264 | 4296 | var next_stack_offset: u32 = 0; |
| 4265 | 4297 | |
| 4266 | 4298 | for (param_types) |ty, i| { |
| 4267 | | switch (ty.zigTypeTag()) { |
| 4268 | | .Bool, .Int => { |
| 4269 | | if (!ty.hasCodeGenBits()) { |
| 4270 | | assert(cc != .C); |
| 4271 | | result.args[i] = .{ .none = {} }; |
| 4272 | | } else { |
| 4273 | | const param_size = @intCast(u32, ty.abiSize(self.target.*)); |
| 4274 | | if (next_int_reg >= c_abi_int_param_regs.len) { |
| 4275 | | result.args[i] = .{ .stack_offset = next_stack_offset }; |
| 4276 | | next_stack_offset += param_size; |
| 4277 | | } else { |
| 4278 | | const aliased_reg = registerAlias( |
| 4279 | | c_abi_int_param_regs[next_int_reg], |
| 4280 | | param_size, |
| 4281 | | ); |
| 4282 | | result.args[i] = .{ .register = aliased_reg }; |
| 4283 | | next_int_reg += 1; |
| 4284 | | } |
| 4285 | | } |
| 4286 | | }, |
| 4287 | | else => return self.fail(src, "TODO implement function parameters of type {s}", .{@tagName(ty.zigTypeTag())}), |
| 4299 | if (!ty.hasCodeGenBits()) { |
| 4300 | assert(cc != .C); |
| 4301 | result.args[i] = .{ .none = {} }; |
| 4302 | continue; |
| 4303 | } |
| 4304 | const param_size = @intCast(u32, ty.abiSize(self.target.*)); |
| 4305 | const pass_in_reg = switch (ty.zigTypeTag()) { |
| 4306 | .Bool => true, |
| 4307 | .Int => param_size <= 8, |
| 4308 | .Pointer => ty.ptrSize() != .Slice, |
| 4309 | .Optional => ty.isPtrLikeOptional(), |
| 4310 | else => false, |
| 4311 | }; |
| 4312 | if (pass_in_reg) { |
| 4313 | if (next_int_reg >= c_abi_int_param_regs.len) { |
| 4314 | result.args[i] = .{ .stack_offset = next_stack_offset }; |
| 4315 | next_stack_offset += param_size; |
| 4316 | } else { |
| 4317 | const aliased_reg = registerAlias( |
| 4318 | c_abi_int_param_regs[next_int_reg], |
| 4319 | param_size, |
| 4320 | ); |
| 4321 | result.args[i] = .{ .register = aliased_reg }; |
| 4322 | next_int_reg += 1; |
| 4323 | } |
| 4324 | } else { |
| 4325 | // For simplicity of codegen, slices and other types are always pushed onto the stack. |
| 4326 | // TODO: look into optimizing this by passing things as registers sometimes, |
| 4327 | // such as ptr and len of slices as separate registers. |
| 4328 | // TODO: also we need to honor the C ABI for relevant types rather than passing on |
| 4329 | // the stack here. |
| 4330 | result.args[i] = .{ .stack_offset = next_stack_offset }; |
| 4331 | next_stack_offset += param_size; |
| 4288 | 4332 | } |
| 4289 | 4333 | } |
| 4290 | 4334 | result.stack_byte_count = next_stack_offset; |