diff options
| author | Andrew Kelley <andrew@ziglang.org> | 2021-07-08 02:04:53 -0400 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2021-07-08 02:04:53 -0400 |
| commit | 62d27fcfb687e3ab1f10c72513e19529d8ffceed (patch) | |
| tree | 2885da99ca325959e40f417346aca63ddef4fb31 /src/codegen.zig | |
| parent | 7935e83b1d5d29cca058597ebdac6dfd012a790a (diff) | |
| parent | c2e66d9bab396a69514ec7c3c41fb0404e542f21 (diff) | |
| download | zig-62d27fcfb687e3ab1f10c72513e19529d8ffceed.tar.gz zig-62d27fcfb687e3ab1f10c72513e19529d8ffceed.zip | |
Merge pull request #9325 from ziglang/stage2-inferred-error-sets
Stage2 inferred error sets and `@panic`
Diffstat (limited to 'src/codegen.zig')
| -rw-r--r-- | src/codegen.zig | 226 |
1 files changed, 141 insertions, 85 deletions
diff --git a/src/codegen.zig b/src/codegen.zig index 0b63222242..6b9bd633d0 100644 --- a/src/codegen.zig +++ b/src/codegen.zig @@ -142,40 +142,52 @@ pub fn generateSymbol( ), }; }, - .Pointer => { - // TODO populate .debug_info for the pointer - if (typed_value.val.castTag(.decl_ref)) |payload| { - const decl = payload.data; - if (decl.analysis != .complete) return error.AnalysisFail; - // TODO handle the dependency of this symbol on the decl's vaddr. - // If the decl changes vaddr, then this symbol needs to get regenerated. - const vaddr = bin_file.getDeclVAddr(decl); - const endian = bin_file.options.target.cpu.arch.endian(); - switch (bin_file.options.target.cpu.arch.ptrBitWidth()) { - 16 => { - try code.resize(2); - mem.writeInt(u16, code.items[0..2], @intCast(u16, vaddr), endian); - }, - 32 => { - try code.resize(4); - mem.writeInt(u32, code.items[0..4], @intCast(u32, vaddr), endian); - }, - 64 => { - try code.resize(8); - mem.writeInt(u64, code.items[0..8], vaddr, endian); - }, - else => unreachable, + .Pointer => switch (typed_value.ty.ptrSize()) { + .Slice => { + return Result{ + .fail = try ErrorMsg.create( + bin_file.allocator, + src_loc, + "TODO implement generateSymbol for slice {}", + .{typed_value.val}, + ), + }; + }, + else => { + // TODO populate .debug_info for the pointer + if (typed_value.val.castTag(.decl_ref)) |payload| { + const decl = payload.data; + if (decl.analysis != .complete) return error.AnalysisFail; + // TODO handle the dependency of this symbol on the decl's vaddr. + // If the decl changes vaddr, then this symbol needs to get regenerated. + const vaddr = bin_file.getDeclVAddr(decl); + const endian = bin_file.options.target.cpu.arch.endian(); + switch (bin_file.options.target.cpu.arch.ptrBitWidth()) { + 16 => { + try code.resize(2); + mem.writeInt(u16, code.items[0..2], @intCast(u16, vaddr), endian); + }, + 32 => { + try code.resize(4); + mem.writeInt(u32, code.items[0..4], @intCast(u32, vaddr), endian); + }, + 64 => { + try code.resize(8); + mem.writeInt(u64, code.items[0..8], vaddr, endian); + }, + else => unreachable, + } + return Result{ .appended = {} }; } - return Result{ .appended = {} }; - } - return Result{ - .fail = try ErrorMsg.create( - bin_file.allocator, - src_loc, - "TODO implement generateSymbol for pointer {}", - .{typed_value.val}, - ), - }; + return Result{ + .fail = try ErrorMsg.create( + bin_file.allocator, + src_loc, + "TODO implement generateSymbol for pointer {}", + .{typed_value.val}, + ), + }; + }, }, .Int => { // TODO populate .debug_info for the integer @@ -847,6 +859,8 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { .is_non_null_ptr => return self.genIsNonNullPtr(inst.castTag(.is_non_null_ptr).?), .is_null => return self.genIsNull(inst.castTag(.is_null).?), .is_null_ptr => return self.genIsNullPtr(inst.castTag(.is_null_ptr).?), + .is_non_err => return self.genIsNonErr(inst.castTag(.is_non_err).?), + .is_non_err_ptr => return self.genIsNonErrPtr(inst.castTag(.is_non_err_ptr).?), .is_err => return self.genIsErr(inst.castTag(.is_err).?), .is_err_ptr => return self.genIsErrPtr(inst.castTag(.is_err_ptr).?), .load => return self.genLoad(inst.castTag(.load).?), @@ -2244,10 +2258,10 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { try self.register_manager.getReg(reg, null); try self.genSetReg(arg.src, arg.ty, reg, arg_mcv); }, - .stack_offset => { + .stack_offset => |off| { // Here we need to emit instructions like this: // mov qword ptr [rsp + stack_offset], x - return self.fail(inst.base.src, "TODO implement calling with parameters in memory", .{}); + try self.genSetStack(arg.src, arg.ty, off, arg_mcv); }, .ptr_stack_offset => { return self.fail(inst.base.src, "TODO implement calling with MCValue.ptr_stack_offset arg", .{}); @@ -2960,6 +2974,16 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { return self.fail(inst.base.src, "TODO load the operand and call genIsErr", .{}); } + fn genIsNonErr(self: *Self, inst: *ir.Inst.UnOp) !MCValue { + switch (arch) { + else => return self.fail(inst.base.src, "TODO implement is_non_err for {}", .{self.target.cpu.arch}), + } + } + + fn genIsNonErrPtr(self: *Self, inst: *ir.Inst.UnOp) !MCValue { + return self.fail(inst.base.src, "TODO load the operand and call genIsNonErr", .{}); + } + fn genLoop(self: *Self, inst: *ir.Inst.Loop) !MCValue { // A loop is a setup to be able to jump back to the beginning. const start_index = self.code.items.len; @@ -3444,9 +3468,11 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { }, } }, - .embedded_in_code => |code_offset| { - _ = code_offset; - return self.fail(src, "TODO implement set stack variable from embedded_in_code", .{}); + .embedded_in_code => { + // TODO this and `.stack_offset` below need to get improved to support types greater than + // register size, and do general memcpy + const reg = try self.copyToTmpRegister(src, ty, mcv); + return self.genSetStack(src, ty, stack_offset, MCValue{ .register = reg }); }, .register => |reg| { try self.genX8664ModRMRegToStack(src, ty, stack_offset, reg, 0x89); @@ -3456,6 +3482,9 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { return self.fail(src, "TODO implement set stack variable from memory vaddr", .{}); }, .stack_offset => |off| { + // TODO this and `.embedded_in_code` above need to get improved to support types greater than + // register size, and do general memcpy + if (stack_offset == off) return; // Copy stack variable to itself; nothing to do. @@ -4161,33 +4190,48 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { const ptr_bits = self.target.cpu.arch.ptrBitWidth(); const ptr_bytes: u64 = @divExact(ptr_bits, 8); switch (typed_value.ty.zigTypeTag()) { - .Pointer => { - if (typed_value.val.castTag(.decl_ref)) |payload| { - if (self.bin_file.cast(link.File.Elf)) |elf_file| { - const decl = payload.data; - const got = &elf_file.program_headers.items[elf_file.phdr_got_index.?]; - const got_addr = got.p_vaddr + decl.link.elf.offset_table_index * ptr_bytes; - return MCValue{ .memory = got_addr }; - } else if (self.bin_file.cast(link.File.MachO)) |macho_file| { - const decl = payload.data; - const got_addr = blk: { - const seg = macho_file.load_commands.items[macho_file.data_const_segment_cmd_index.?].Segment; - const got = seg.sections.items[macho_file.got_section_index.?]; - break :blk got.addr + decl.link.macho.offset_table_index * ptr_bytes; - }; - return MCValue{ .memory = got_addr }; - } else if (self.bin_file.cast(link.File.Coff)) |coff_file| { - const decl = payload.data; - const got_addr = coff_file.offset_table_virtual_address + decl.link.coff.offset_table_index * ptr_bytes; - return MCValue{ .memory = got_addr }; - } else { - return self.fail(src, "TODO codegen non-ELF const Decl pointer", .{}); + .Pointer => switch (typed_value.ty.ptrSize()) { + .Slice => { + var buf: Type.Payload.ElemType = undefined; + const ptr_type = typed_value.ty.slicePtrFieldType(&buf); + const ptr_mcv = try self.genTypedValue(src, .{ .ty = ptr_type, .val = typed_value.val }); + const slice_len = typed_value.val.sliceLen(); + // Codegen can't handle some kinds of indirection. If the wrong union field is accessed here it may mean + // the Sema code needs to use anonymous Decls or alloca instructions to store data. + const ptr_imm = ptr_mcv.memory; + _ = slice_len; + _ = ptr_imm; + // We need more general support for const data being stored in memory to make this work. + return self.fail(src, "TODO codegen for const slices", .{}); + }, + else => { + if (typed_value.val.castTag(.decl_ref)) |payload| { + if (self.bin_file.cast(link.File.Elf)) |elf_file| { + const decl = payload.data; + const got = &elf_file.program_headers.items[elf_file.phdr_got_index.?]; + const got_addr = got.p_vaddr + decl.link.elf.offset_table_index * ptr_bytes; + return MCValue{ .memory = got_addr }; + } else if (self.bin_file.cast(link.File.MachO)) |macho_file| { + const decl = payload.data; + const got_addr = blk: { + const seg = macho_file.load_commands.items[macho_file.data_const_segment_cmd_index.?].Segment; + const got = seg.sections.items[macho_file.got_section_index.?]; + break :blk got.addr + decl.link.macho.offset_table_index * ptr_bytes; + }; + return MCValue{ .memory = got_addr }; + } else if (self.bin_file.cast(link.File.Coff)) |coff_file| { + const decl = payload.data; + const got_addr = coff_file.offset_table_virtual_address + decl.link.coff.offset_table_index * ptr_bytes; + return MCValue{ .memory = got_addr }; + } else { + return self.fail(src, "TODO codegen non-ELF const Decl pointer", .{}); + } } - } - if (typed_value.val.tag() == .int_u64) { - return MCValue{ .immediate = typed_value.val.toUnsignedInt() }; - } - return self.fail(src, "TODO codegen more kinds of const pointers", .{}); + if (typed_value.val.tag() == .int_u64) { + return MCValue{ .immediate = typed_value.val.toUnsignedInt() }; + } + return self.fail(src, "TODO codegen more kinds of const pointers", .{}); + }, }, .Int => { const info = typed_value.ty.intInfo(self.target.*); @@ -4264,27 +4308,39 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { var next_stack_offset: u32 = 0; for (param_types) |ty, i| { - switch (ty.zigTypeTag()) { - .Bool, .Int => { - if (!ty.hasCodeGenBits()) { - assert(cc != .C); - result.args[i] = .{ .none = {} }; - } else { - const param_size = @intCast(u32, ty.abiSize(self.target.*)); - if (next_int_reg >= c_abi_int_param_regs.len) { - result.args[i] = .{ .stack_offset = next_stack_offset }; - next_stack_offset += param_size; - } else { - const aliased_reg = registerAlias( - c_abi_int_param_regs[next_int_reg], - param_size, - ); - result.args[i] = .{ .register = aliased_reg }; - next_int_reg += 1; - } - } - }, - else => return self.fail(src, "TODO implement function parameters of type {s}", .{@tagName(ty.zigTypeTag())}), + if (!ty.hasCodeGenBits()) { + assert(cc != .C); + result.args[i] = .{ .none = {} }; + continue; + } + const param_size = @intCast(u32, ty.abiSize(self.target.*)); + const pass_in_reg = switch (ty.zigTypeTag()) { + .Bool => true, + .Int => param_size <= 8, + .Pointer => ty.ptrSize() != .Slice, + .Optional => ty.isPtrLikeOptional(), + else => false, + }; + if (pass_in_reg) { + if (next_int_reg >= c_abi_int_param_regs.len) { + result.args[i] = .{ .stack_offset = next_stack_offset }; + next_stack_offset += param_size; + } else { + const aliased_reg = registerAlias( + c_abi_int_param_regs[next_int_reg], + param_size, + ); + result.args[i] = .{ .register = aliased_reg }; + next_int_reg += 1; + } + } else { + // For simplicity of codegen, slices and other types are always pushed onto the stack. + // TODO: look into optimizing this by passing things as registers sometimes, + // such as ptr and len of slices as separate registers. + // TODO: also we need to honor the C ABI for relevant types rather than passing on + // the stack here. + result.args[i] = .{ .stack_offset = next_stack_offset }; + next_stack_offset += param_size; } } result.stack_byte_count = next_stack_offset; |
