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