From c746cbc686c46904a5d381725079a69e38b201cd Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Fri, 3 Mar 2023 18:06:25 +0100 Subject: codegen: move gen logic for typed values, consts and decl ref to common codegen --- src/arch/aarch64/CodeGen.zig | 6 +- src/arch/arm/CodeGen.zig | 6 +- src/arch/riscv64/CodeGen.zig | 14 +- src/arch/sparc64/CodeGen.zig | 6 +- src/arch/wasm/CodeGen.zig | 2 - src/arch/x86_64/CodeGen.zig | 216 +++--------------------------- src/codegen.zig | 307 ++++++++++++++++++++++++++++++++++++++++--- src/link/Coff.zig | 2 +- src/link/Elf.zig | 2 +- src/link/MachO.zig | 2 +- src/link/Plan9.zig | 2 +- src/link/Wasm.zig | 2 +- src/register_manager.zig | 3 + 13 files changed, 323 insertions(+), 247 deletions(-) (limited to 'src') diff --git a/src/arch/aarch64/CodeGen.zig b/src/arch/aarch64/CodeGen.zig index 818b04f890..23f458f910 100644 --- a/src/arch/aarch64/CodeGen.zig +++ b/src/arch/aarch64/CodeGen.zig @@ -41,11 +41,7 @@ const c_abi_int_param_regs = abi.c_abi_int_param_regs; const c_abi_int_return_regs = abi.c_abi_int_return_regs; const gp = abi.RegisterClass.gp; -const InnerError = error{ - OutOfMemory, - CodegenFail, - OutOfRegisters, -}; +const InnerError = codegen.CodeGenError || error{OutOfRegisters}; gpa: Allocator, air: Air, diff --git a/src/arch/arm/CodeGen.zig b/src/arch/arm/CodeGen.zig index ceabe70438..87806223e3 100644 --- a/src/arch/arm/CodeGen.zig +++ b/src/arch/arm/CodeGen.zig @@ -42,11 +42,7 @@ const c_abi_int_param_regs = abi.c_abi_int_param_regs; const c_abi_int_return_regs = abi.c_abi_int_return_regs; const gp = abi.RegisterClass.gp; -const InnerError = error{ - OutOfMemory, - CodegenFail, - OutOfRegisters, -}; +const InnerError = codegen.CodeGenError || error{OutOfRegisters}; gpa: Allocator, air: Air, diff --git a/src/arch/riscv64/CodeGen.zig b/src/arch/riscv64/CodeGen.zig index afcf4b0bb7..fad5482cbc 100644 --- a/src/arch/riscv64/CodeGen.zig +++ b/src/arch/riscv64/CodeGen.zig @@ -21,10 +21,10 @@ const DW = std.dwarf; const leb128 = std.leb; const log = std.log.scoped(.codegen); const build_options = @import("build_options"); +const codegen = @import("../../codegen.zig"); -const Result = @import("../../codegen.zig").Result; -const GenerateSymbolError = @import("../../codegen.zig").GenerateSymbolError; -const DebugInfoOutput = @import("../../codegen.zig").DebugInfoOutput; +const Result = codegen.Result; +const DebugInfoOutput = codegen.DebugInfoOutput; const bits = @import("bits.zig"); const abi = @import("abi.zig"); @@ -35,11 +35,7 @@ const Instruction = abi.Instruction; const callee_preserved_regs = abi.callee_preserved_regs; const gp = abi.RegisterClass.gp; -const InnerError = error{ - OutOfMemory, - CodegenFail, - OutOfRegisters, -}; +const InnerError = codegen.CodeGenError || error{OutOfRegisters}; gpa: Allocator, air: Air, @@ -225,7 +221,7 @@ pub fn generate( liveness: Liveness, code: *std.ArrayList(u8), debug_output: DebugInfoOutput, -) GenerateSymbolError!Result { +) codegen.CodeGenError!Result { if (build_options.skip_non_native and builtin.cpu.arch != bin_file.options.target.cpu.arch) { @panic("Attempted to compile for architecture that was disabled by build configuration"); } diff --git a/src/arch/sparc64/CodeGen.zig b/src/arch/sparc64/CodeGen.zig index c8f77fe702..5a108eca85 100644 --- a/src/arch/sparc64/CodeGen.zig +++ b/src/arch/sparc64/CodeGen.zig @@ -38,11 +38,7 @@ const gp = abi.RegisterClass.gp; const Self = @This(); -const InnerError = error{ - OutOfMemory, - CodegenFail, - OutOfRegisters, -}; +const InnerError = codegen.CodeGenError || error{OutOfRegisters}; const RegisterView = enum(u1) { caller, diff --git a/src/arch/wasm/CodeGen.zig b/src/arch/wasm/CodeGen.zig index 2f191fd834..511a10769e 100644 --- a/src/arch/wasm/CodeGen.zig +++ b/src/arch/wasm/CodeGen.zig @@ -733,8 +733,6 @@ const InnerError = error{ OutOfMemory, /// An error occurred when trying to lower AIR to MIR. CodegenFail, - /// Can occur when dereferencing a pointer that points to a `Decl` of which the analysis has failed - AnalysisFail, /// Compiler implementation could not handle a large integer. Overflow, }; diff --git a/src/arch/x86_64/CodeGen.zig b/src/arch/x86_64/CodeGen.zig index 53d38f520a..2ec1a33619 100644 --- a/src/arch/x86_64/CodeGen.zig +++ b/src/arch/x86_64/CodeGen.zig @@ -40,11 +40,7 @@ const Register = bits.Register; const gp = abi.RegisterClass.gp; const sse = abi.RegisterClass.sse; -const InnerError = error{ - OutOfMemory, - CodegenFail, - OutOfRegisters, -}; +const InnerError = codegen.CodeGenError || error{OutOfRegisters}; gpa: Allocator, air: Air, @@ -6683,7 +6679,7 @@ fn airMulAdd(self: *Self, inst: Air.Inst.Index) !void { return self.finishAir(inst, result, .{ extra.lhs, extra.rhs, pl_op.operand }); } -pub fn resolveInst(self: *Self, inst: Air.Inst.Ref) InnerError!MCValue { +fn resolveInst(self: *Self, inst: Air.Inst.Ref) InnerError!MCValue { // First section of indexes correspond to a set number of constant values. const ref_int = @enumToInt(inst); if (ref_int < Air.Inst.Ref.typed_value_map.len) { @@ -6752,200 +6748,26 @@ fn limitImmediateType(self: *Self, operand: Air.Inst.Ref, comptime T: type) !MCV return mcv; } -fn lowerDeclRef(self: *Self, tv: TypedValue, decl_index: Module.Decl.Index) InnerError!MCValue { - log.debug("lowerDeclRef: ty = {}, val = {}", .{ tv.ty.fmtDebug(), tv.val.fmtDebug() }); - const ptr_bits = self.target.cpu.arch.ptrBitWidth(); - const ptr_bytes: u64 = @divExact(ptr_bits, 8); - - // TODO this feels clunky. Perhaps we should check for it in `genTypedValue`? - if (tv.ty.zigTypeTag() == .Pointer) blk: { - if (tv.ty.castPtrToFn()) |_| break :blk; - if (!tv.ty.elemType2().hasRuntimeBits()) { - return MCValue.none; - } - } - - const module = self.bin_file.options.module.?; - const decl = module.declPtr(decl_index); - module.markDeclAlive(decl); - - if (self.bin_file.cast(link.File.Elf)) |elf_file| { - const atom_index = try elf_file.getOrCreateAtomForDecl(decl_index); - const atom = elf_file.getAtom(atom_index); - return MCValue{ .memory = atom.getOffsetTableAddress(elf_file) }; - } else if (self.bin_file.cast(link.File.MachO)) |macho_file| { - const atom_index = try macho_file.getOrCreateAtomForDecl(decl_index); - const sym_index = macho_file.getAtom(atom_index).getSymbolIndex().?; - return MCValue{ .linker_load = .{ - .type = .got, - .sym_index = sym_index, - } }; - } else if (self.bin_file.cast(link.File.Coff)) |coff_file| { - const atom_index = try coff_file.getOrCreateAtomForDecl(decl_index); - const sym_index = coff_file.getAtom(atom_index).getSymbolIndex().?; - return MCValue{ .linker_load = .{ - .type = .got, - .sym_index = sym_index, - } }; - } else if (self.bin_file.cast(link.File.Plan9)) |p9| { - const decl_block_index = try p9.seeDecl(decl_index); - const decl_block = p9.getDeclBlock(decl_block_index); - const got_addr = p9.bases.data + decl_block.got_index.? * ptr_bytes; - return MCValue{ .memory = got_addr }; - } else { - return self.fail("TODO codegen non-ELF const Decl pointer", .{}); - } -} - -fn lowerUnnamedConst(self: *Self, tv: TypedValue) InnerError!MCValue { - log.debug("lowerUnnamedConst: ty = {}, val = {}", .{ tv.ty.fmtDebug(), tv.val.fmtDebug() }); - const local_sym_index = self.bin_file.lowerUnnamedConst(tv, self.mod_fn.owner_decl) catch |err| { - return self.fail("lowering unnamed constant failed: {s}", .{@errorName(err)}); - }; - if (self.bin_file.cast(link.File.Elf)) |elf_file| { - return MCValue{ .memory = elf_file.getSymbol(local_sym_index).st_value }; - } else if (self.bin_file.cast(link.File.MachO)) |_| { - return MCValue{ .linker_load = .{ - .type = .direct, - .sym_index = local_sym_index, - } }; - } else if (self.bin_file.cast(link.File.Coff)) |_| { - return MCValue{ .linker_load = .{ - .type = .direct, - .sym_index = local_sym_index, - } }; - } else if (self.bin_file.cast(link.File.Plan9)) |p9| { - const ptr_bits = self.target.cpu.arch.ptrBitWidth(); - const ptr_bytes: u64 = @divExact(ptr_bits, 8); - const got_index = local_sym_index; // the plan9 backend returns the got_index - const got_addr = p9.bases.data + got_index * ptr_bytes; - return MCValue{ .memory = got_addr }; - } else { - return self.fail("TODO lower unnamed const", .{}); - } -} - fn genTypedValue(self: *Self, arg_tv: TypedValue) InnerError!MCValue { - var typed_value = arg_tv; - if (typed_value.val.castTag(.runtime_value)) |rt| { - typed_value.val = rt.data; - } - log.debug("genTypedValue: ty = {}, val = {}", .{ typed_value.ty.fmtDebug(), typed_value.val.fmtDebug() }); - if (typed_value.val.isUndef()) - return MCValue{ .undef = {} }; - const ptr_bits = self.target.cpu.arch.ptrBitWidth(); - - if (typed_value.val.castTag(.decl_ref)) |payload| { - return self.lowerDeclRef(typed_value, payload.data); - } - if (typed_value.val.castTag(.decl_ref_mut)) |payload| { - return self.lowerDeclRef(typed_value, payload.data.decl_index); - } - - const target = self.target.*; - - switch (typed_value.ty.zigTypeTag()) { - .Void => return MCValue{ .none = {} }, - .Pointer => switch (typed_value.ty.ptrSize()) { - .Slice => {}, - else => { - switch (typed_value.val.tag()) { - .int_u64 => { - return MCValue{ .immediate = typed_value.val.toUnsignedInt(target) }; - }, - else => {}, - } - }, + const mcv: MCValue = switch (try codegen.genTypedValue( + self.bin_file, + self.src_loc, + arg_tv, + self.mod_fn.owner_decl, + )) { + .mcv => |mcv| switch (mcv) { + .none => .none, + .undef => .undef, + .linker_load => |ll| .{ .linker_load = ll }, + .immediate => |imm| .{ .immediate = imm }, + .memory => |addr| .{ .memory = addr }, }, - .Int => { - const info = typed_value.ty.intInfo(self.target.*); - if (info.bits <= ptr_bits and info.signedness == .signed) { - return MCValue{ .immediate = @bitCast(u64, typed_value.val.toSignedInt(target)) }; - } - if (!(info.bits > ptr_bits or info.signedness == .signed)) { - return MCValue{ .immediate = typed_value.val.toUnsignedInt(target) }; - } - }, - .Bool => { - return MCValue{ .immediate = @boolToInt(typed_value.val.toBool()) }; - }, - .Optional => { - if (typed_value.ty.isPtrLikeOptional()) { - if (typed_value.val.isNull()) - return MCValue{ .immediate = 0 }; - - var buf: Type.Payload.ElemType = undefined; - return self.genTypedValue(.{ - .ty = typed_value.ty.optionalChild(&buf), - .val = typed_value.val, - }); - } else if (typed_value.ty.abiSize(self.target.*) == 1) { - return MCValue{ .immediate = @boolToInt(!typed_value.val.isNull()) }; - } - }, - .Enum => { - if (typed_value.val.castTag(.enum_field_index)) |field_index| { - switch (typed_value.ty.tag()) { - .enum_simple => { - return MCValue{ .immediate = field_index.data }; - }, - .enum_full, .enum_nonexhaustive => { - const enum_full = typed_value.ty.cast(Type.Payload.EnumFull).?.data; - if (enum_full.values.count() != 0) { - const tag_val = enum_full.values.keys()[field_index.data]; - return self.genTypedValue(.{ .ty = enum_full.tag_ty, .val = tag_val }); - } else { - return MCValue{ .immediate = field_index.data }; - } - }, - else => unreachable, - } - } else { - var int_tag_buffer: Type.Payload.Bits = undefined; - const int_tag_ty = typed_value.ty.intTagType(&int_tag_buffer); - return self.genTypedValue(.{ .ty = int_tag_ty, .val = typed_value.val }); - } + .fail => |msg| { + self.err_msg = msg; + return error.CodegenFail; }, - .ErrorSet => { - switch (typed_value.val.tag()) { - .@"error" => { - const err_name = typed_value.val.castTag(.@"error").?.data.name; - const module = self.bin_file.options.module.?; - const global_error_set = module.global_error_set; - const error_index = global_error_set.get(err_name).?; - return MCValue{ .immediate = error_index }; - }, - else => { - // In this case we are rendering an error union which has a 0 bits payload. - return MCValue{ .immediate = 0 }; - }, - } - }, - .ErrorUnion => { - const error_type = typed_value.ty.errorUnionSet(); - const payload_type = typed_value.ty.errorUnionPayload(); - const is_pl = typed_value.val.errorUnionIsPayload(); - - if (!payload_type.hasRuntimeBitsIgnoreComptime()) { - // We use the error type directly as the type. - const err_val = if (!is_pl) typed_value.val else Value.initTag(.zero); - return self.genTypedValue(.{ .ty = error_type, .val = err_val }); - } - }, - - .ComptimeInt => unreachable, - .ComptimeFloat => unreachable, - .Type => unreachable, - .EnumLiteral => unreachable, - .NoReturn => unreachable, - .Undefined => unreachable, - .Null => unreachable, - .Opaque => unreachable, - - else => {}, - } - - return self.lowerUnnamedConst(typed_value); + }; + return mcv; } const CallMCValues = struct { diff --git a/src/codegen.zig b/src/codegen.zig index df7ceff1f0..245745d6f6 100644 --- a/src/codegen.zig +++ b/src/codegen.zig @@ -29,13 +29,14 @@ pub const Result = union(enum) { fail: *ErrorMsg, }; -pub const GenerateSymbolError = error{ +pub const CodeGenError = error{ OutOfMemory, Overflow, - /// A Decl that this symbol depends on had a semantic analysis failure. - AnalysisFail, + CodegenFail, }; +pub const GenerateSymbolError = CodeGenError; + pub const DebugInfoOutput = union(enum) { dwarf: *link.File.Dwarf.DeclState, /// the plan9 debuginfo output is a bytecode with 4 opcodes @@ -63,19 +64,6 @@ pub const DebugInfoOutput = union(enum) { none, }; -/// Helper struct to denote that the value is in memory but requires a linker relocation fixup: -/// * got - the value is referenced indirectly via GOT entry index (the linker emits a got-type reloc) -/// * direct - the value is referenced directly via symbol index index (the linker emits a displacement reloc) -/// * import - the value is referenced indirectly via import entry index (the linker emits an import-type reloc) -pub const LinkerLoad = struct { - type: enum { - got, - direct, - import, - }, - sym_index: u32, -}; - pub fn generateFunction( bin_file: *link.File, src_loc: Module.SrcLoc, @@ -84,7 +72,7 @@ pub fn generateFunction( liveness: Liveness, code: *std.ArrayList(u8), debug_output: DebugInfoOutput, -) GenerateSymbolError!Result { +) CodeGenError!Result { switch (bin_file.options.target.cpu.arch) { .arm, .armeb, @@ -120,7 +108,7 @@ pub fn generateSymbol( code: *std.ArrayList(u8), debug_output: DebugInfoOutput, reloc_info: RelocInfo, -) GenerateSymbolError!Result { +) CodeGenError!Result { const tracy = trace(@src()); defer tracy.end(); @@ -823,7 +811,7 @@ fn lowerDeclRef( code: *std.ArrayList(u8), debug_output: DebugInfoOutput, reloc_info: RelocInfo, -) GenerateSymbolError!Result { +) CodeGenError!Result { const target = bin_file.options.target; const module = bin_file.options.module.?; if (typed_value.ty.isSlice()) { @@ -880,6 +868,287 @@ fn lowerDeclRef( return Result.ok; } +/// Helper struct to denote that the value is in memory but requires a linker relocation fixup: +/// * got - the value is referenced indirectly via GOT entry index (the linker emits a got-type reloc) +/// * direct - the value is referenced directly via symbol index index (the linker emits a displacement reloc) +/// * import - the value is referenced indirectly via import entry index (the linker emits an import-type reloc) +pub const LinkerLoad = struct { + type: enum { + got, + direct, + import, + }, + sym_index: u32, +}; + +pub const GenResult = union(enum) { + mcv: MCValue, + fail: *ErrorMsg, + + const MCValue = union(enum) { + none, + undef, + /// The bit-width of the immediate may be smaller than `u64`. For example, on 32-bit targets + /// such as ARM, the immediate will never exceed 32-bits. + immediate: u64, + linker_load: LinkerLoad, + /// Direct by-address reference to memory location. + memory: u64, + }; + + fn mcv(val: MCValue) GenResult { + return .{ .mcv = val }; + } + + fn fail( + gpa: Allocator, + src_loc: Module.SrcLoc, + comptime format: []const u8, + args: anytype, + ) Allocator.Error!GenResult { + const msg = try ErrorMsg.create(gpa, src_loc, format, args); + return .{ .fail = msg }; + } +}; + +fn genDeclRef( + bin_file: *link.File, + src_loc: Module.SrcLoc, + tv: TypedValue, + decl_index: Module.Decl.Index, +) CodeGenError!GenResult { + log.debug("genDeclRef: ty = {}, val = {}", .{ tv.ty.fmtDebug(), tv.val.fmtDebug() }); + + const target = bin_file.options.target; + const ptr_bits = target.cpu.arch.ptrBitWidth(); + const ptr_bytes: u64 = @divExact(ptr_bits, 8); + + const module = bin_file.options.module.?; + const decl = module.declPtr(decl_index); + + if (decl.ty.zigTypeTag() != .Fn and !decl.ty.hasRuntimeBitsIgnoreComptime()) { + const imm: u64 = switch (ptr_bytes) { + 1 => 0xaa, + 2 => 0xaaaa, + 4 => 0xaaaaaaaa, + 8 => 0xaaaaaaaaaaaaaaaa, + else => unreachable, + }; + return GenResult.mcv(.{ .immediate = imm }); + } + + // TODO this feels clunky. Perhaps we should check for it in `genTypedValue`? + if (tv.ty.zigTypeTag() == .Pointer) blk: { + if (tv.ty.castPtrToFn()) |_| break :blk; + if (!tv.ty.elemType2().hasRuntimeBits()) { + return GenResult.mcv(.none); + } + } + + module.markDeclAlive(decl); + + if (bin_file.cast(link.File.Elf)) |elf_file| { + const atom_index = try elf_file.getOrCreateAtomForDecl(decl_index); + const atom = elf_file.getAtom(atom_index); + return GenResult.mcv(.{ .memory = atom.getOffsetTableAddress(elf_file) }); + } else if (bin_file.cast(link.File.MachO)) |macho_file| { + const atom_index = try macho_file.getOrCreateAtomForDecl(decl_index); + const sym_index = macho_file.getAtom(atom_index).getSymbolIndex().?; + return GenResult.mcv(.{ .linker_load = .{ + .type = .got, + .sym_index = sym_index, + } }); + } else if (bin_file.cast(link.File.Coff)) |coff_file| { + const atom_index = try coff_file.getOrCreateAtomForDecl(decl_index); + const sym_index = coff_file.getAtom(atom_index).getSymbolIndex().?; + return GenResult.mcv(.{ .linker_load = .{ + .type = .got, + .sym_index = sym_index, + } }); + } else if (bin_file.cast(link.File.Plan9)) |p9| { + const decl_block_index = try p9.seeDecl(decl_index); + const decl_block = p9.getDeclBlock(decl_block_index); + const got_addr = p9.bases.data + decl_block.got_index.? * ptr_bytes; + return GenResult.mcv(.{ .memory = got_addr }); + } else { + return GenResult.fail(bin_file.allocator, src_loc, "TODO genDeclRef for target {}", .{target}); + } +} + +fn genUnnamedConst( + bin_file: *link.File, + src_loc: Module.SrcLoc, + tv: TypedValue, + owner_decl_index: Module.Decl.Index, +) CodeGenError!GenResult { + log.debug("genUnnamedConst: ty = {}, val = {}", .{ tv.ty.fmtDebug(), tv.val.fmtDebug() }); + + const target = bin_file.options.target; + const local_sym_index = bin_file.lowerUnnamedConst(tv, owner_decl_index) catch |err| { + return GenResult.fail(bin_file.allocator, src_loc, "lowering unnamed constant failed: {s}", .{@errorName(err)}); + }; + if (bin_file.cast(link.File.Elf)) |elf_file| { + return GenResult.mcv(.{ .memory = elf_file.getSymbol(local_sym_index).st_value }); + } else if (bin_file.cast(link.File.MachO)) |_| { + return GenResult.mcv(.{ .linker_load = .{ + .type = .direct, + .sym_index = local_sym_index, + } }); + } else if (bin_file.cast(link.File.Coff)) |_| { + return GenResult.mcv(.{ .linker_load = .{ + .type = .direct, + .sym_index = local_sym_index, + } }); + } else if (bin_file.cast(link.File.Plan9)) |p9| { + const ptr_bits = target.cpu.arch.ptrBitWidth(); + const ptr_bytes: u64 = @divExact(ptr_bits, 8); + const got_index = local_sym_index; // the plan9 backend returns the got_index + const got_addr = p9.bases.data + got_index * ptr_bytes; + return GenResult.mcv(.{ .memory = got_addr }); + } else { + return GenResult.fail(bin_file.allocator, src_loc, "TODO genUnnamedConst for target {}", .{target}); + } +} + +pub fn genTypedValue( + bin_file: *link.File, + src_loc: Module.SrcLoc, + arg_tv: TypedValue, + owner_decl_index: Module.Decl.Index, +) CodeGenError!GenResult { + var typed_value = arg_tv; + if (typed_value.val.castTag(.runtime_value)) |rt| { + typed_value.val = rt.data; + } + + log.debug("genTypedValue: ty = {}, val = {}", .{ typed_value.ty.fmtDebug(), typed_value.val.fmtDebug() }); + + if (typed_value.val.isUndef()) + return GenResult.mcv(.undef); + + const target = bin_file.options.target; + const ptr_bits = target.cpu.arch.ptrBitWidth(); + + if (typed_value.val.castTag(.decl_ref)) |payload| { + return genDeclRef(bin_file, src_loc, typed_value, payload.data); + } + if (typed_value.val.castTag(.decl_ref_mut)) |payload| { + return genDeclRef(bin_file, src_loc, typed_value, payload.data.decl_index); + } + + switch (typed_value.ty.zigTypeTag()) { + .Void => return GenResult.mcv(.none), + .Pointer => switch (typed_value.ty.ptrSize()) { + .Slice => {}, + else => { + switch (typed_value.val.tag()) { + .int_u64 => { + return GenResult.mcv(.{ .immediate = typed_value.val.toUnsignedInt(target) }); + }, + else => {}, + } + }, + }, + .Int => { + const info = typed_value.ty.intInfo(target); + if (info.bits <= ptr_bits and info.signedness == .signed) { + return GenResult.mcv(.{ .immediate = @bitCast(u64, typed_value.val.toSignedInt(target)) }); + } + if (!(info.bits > ptr_bits or info.signedness == .signed)) { + return GenResult.mcv(.{ .immediate = typed_value.val.toUnsignedInt(target) }); + } + }, + .Bool => { + return GenResult.mcv(.{ .immediate = @boolToInt(typed_value.val.toBool()) }); + }, + .Optional => { + if (typed_value.ty.isPtrLikeOptional()) { + if (typed_value.val.isNull()) + return GenResult.mcv(.{ .immediate = 0 }); + + var buf: Type.Payload.ElemType = undefined; + return genTypedValue(bin_file, src_loc, .{ + .ty = typed_value.ty.optionalChild(&buf), + .val = typed_value.val, + }, owner_decl_index); + } else if (typed_value.ty.abiSize(target) == 1) { + return GenResult.mcv(.{ .immediate = @boolToInt(!typed_value.val.isNull()) }); + } + }, + .Enum => { + if (typed_value.val.castTag(.enum_field_index)) |field_index| { + switch (typed_value.ty.tag()) { + .enum_simple => { + return GenResult.mcv(.{ .immediate = field_index.data }); + }, + .enum_full, .enum_nonexhaustive => { + const enum_full = typed_value.ty.cast(Type.Payload.EnumFull).?.data; + if (enum_full.values.count() != 0) { + const tag_val = enum_full.values.keys()[field_index.data]; + return genTypedValue(bin_file, src_loc, .{ + .ty = enum_full.tag_ty, + .val = tag_val, + }, owner_decl_index); + } else { + return GenResult.mcv(.{ .immediate = field_index.data }); + } + }, + else => unreachable, + } + } else { + var int_tag_buffer: Type.Payload.Bits = undefined; + const int_tag_ty = typed_value.ty.intTagType(&int_tag_buffer); + return genTypedValue(bin_file, src_loc, .{ + .ty = int_tag_ty, + .val = typed_value.val, + }, owner_decl_index); + } + }, + .ErrorSet => { + switch (typed_value.val.tag()) { + .@"error" => { + const err_name = typed_value.val.castTag(.@"error").?.data.name; + const module = bin_file.options.module.?; + const global_error_set = module.global_error_set; + const error_index = global_error_set.get(err_name).?; + return GenResult.mcv(.{ .immediate = error_index }); + }, + else => { + // In this case we are rendering an error union which has a 0 bits payload. + return GenResult.mcv(.{ .immediate = 0 }); + }, + } + }, + .ErrorUnion => { + const error_type = typed_value.ty.errorUnionSet(); + const payload_type = typed_value.ty.errorUnionPayload(); + const is_pl = typed_value.val.errorUnionIsPayload(); + + if (!payload_type.hasRuntimeBitsIgnoreComptime()) { + // We use the error type directly as the type. + const err_val = if (!is_pl) typed_value.val else Value.initTag(.zero); + return genTypedValue(bin_file, src_loc, .{ + .ty = error_type, + .val = err_val, + }, owner_decl_index); + } + }, + + .ComptimeInt => unreachable, + .ComptimeFloat => unreachable, + .Type => unreachable, + .EnumLiteral => unreachable, + .NoReturn => unreachable, + .Undefined => unreachable, + .Null => unreachable, + .Opaque => unreachable, + + else => {}, + } + + return genUnnamedConst(bin_file, src_loc, typed_value, owner_decl_index); +} + pub fn errUnionPayloadOffset(payload_ty: Type, target: std.Target) u64 { const payload_align = payload_ty.abiAlignment(target); const error_align = Type.anyerror.abiAlignment(target); diff --git a/src/link/Coff.zig b/src/link/Coff.zig index c0ac7e0b88..f210f2f2b3 100644 --- a/src/link/Coff.zig +++ b/src/link/Coff.zig @@ -1060,7 +1060,7 @@ pub fn lowerUnnamedConst(self: *Coff, tv: TypedValue, decl_index: Module.Decl.In decl.analysis = .codegen_failure; try mod.failed_decls.put(mod.gpa, decl_index, em); log.err("{s}", .{em.msg}); - return error.AnalysisFail; + return error.CodegenFail; }, }; diff --git a/src/link/Elf.zig b/src/link/Elf.zig index 1a9d594c56..f499a9952a 100644 --- a/src/link/Elf.zig +++ b/src/link/Elf.zig @@ -2618,7 +2618,7 @@ pub fn lowerUnnamedConst(self: *Elf, typed_value: TypedValue, decl_index: Module decl.analysis = .codegen_failure; try mod.failed_decls.put(mod.gpa, decl_index, em); log.err("{s}", .{em.msg}); - return error.AnalysisFail; + return error.CodegenFail; }, }; diff --git a/src/link/MachO.zig b/src/link/MachO.zig index 7c1d4776af..eaf16e4009 100644 --- a/src/link/MachO.zig +++ b/src/link/MachO.zig @@ -2089,7 +2089,7 @@ pub fn lowerUnnamedConst(self: *MachO, typed_value: TypedValue, decl_index: Modu decl.analysis = .codegen_failure; try module.failed_decls.put(module.gpa, decl_index, em); log.err("{s}", .{em.msg}); - return error.AnalysisFail; + return error.CodegenFail; }, }; diff --git a/src/link/Plan9.zig b/src/link/Plan9.zig index 87e3ca5c22..cf6e4f8418 100644 --- a/src/link/Plan9.zig +++ b/src/link/Plan9.zig @@ -377,7 +377,7 @@ pub fn lowerUnnamedConst(self: *Plan9, tv: TypedValue, decl_index: Module.Decl.I decl.analysis = .codegen_failure; try mod.failed_decls.put(mod.gpa, decl_index, em); log.err("{s}", .{em.msg}); - return error.AnalysisFail; + return error.CodegenFail; }, }; // duped_code is freed when the unnamed const is freed diff --git a/src/link/Wasm.zig b/src/link/Wasm.zig index 00a52177f7..ac0c8e9ca5 100644 --- a/src/link/Wasm.zig +++ b/src/link/Wasm.zig @@ -1255,7 +1255,7 @@ pub fn lowerUnnamedConst(wasm: *Wasm, tv: TypedValue, decl_index: Module.Decl.In .fail => |em| { decl.analysis = .codegen_failure; try mod.failed_decls.put(mod.gpa, decl_index, em); - return error.AnalysisFail; + return error.CodegenFail; }, }; }; diff --git a/src/register_manager.zig b/src/register_manager.zig index 2fe0cd2b6a..4d16348c27 100644 --- a/src/register_manager.zig +++ b/src/register_manager.zig @@ -19,6 +19,9 @@ pub const AllocateRegistersError = error{ /// Can happen when spilling an instruction in codegen runs out of /// memory, so we propagate that error OutOfMemory, + /// Can happen when spilling an instruction in codegen triggers integer + /// overflow, so we propagate that error + Overflow, /// Can happen when spilling an instruction triggers a codegen /// error, so we propagate that error CodegenFail, -- cgit v1.2.3 From 1024332adc88928299dfc07426f11624ae8ba18b Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Fri, 3 Mar 2023 18:24:58 +0100 Subject: arm: use common implementation of genTypedValue helper --- src/arch/arm/CodeGen.zig | 192 +++++--------------------------------------- src/arch/x86_64/CodeGen.zig | 6 +- 2 files changed, 23 insertions(+), 175 deletions(-) (limited to 'src') diff --git a/src/arch/arm/CodeGen.zig b/src/arch/arm/CodeGen.zig index 87806223e3..7d8708c44d 100644 --- a/src/arch/arm/CodeGen.zig +++ b/src/arch/arm/CodeGen.zig @@ -24,7 +24,7 @@ const log = std.log.scoped(.codegen); const build_options = @import("build_options"); const Result = codegen.Result; -const GenerateSymbolError = codegen.GenerateSymbolError; +const CodeGenError = codegen.CodeGenError; const DebugInfoOutput = codegen.DebugInfoOutput; const bits = @import("bits.zig"); @@ -42,7 +42,7 @@ const c_abi_int_param_regs = abi.c_abi_int_param_regs; const c_abi_int_return_regs = abi.c_abi_int_return_regs; const gp = abi.RegisterClass.gp; -const InnerError = codegen.CodeGenError || error{OutOfRegisters}; +const InnerError = CodeGenError || error{OutOfRegisters}; gpa: Allocator, air: Air, @@ -339,7 +339,7 @@ pub fn generate( liveness: Liveness, code: *std.ArrayList(u8), debug_output: DebugInfoOutput, -) GenerateSymbolError!Result { +) CodeGenError!Result { if (build_options.skip_non_native and builtin.cpu.arch != bin_file.options.target.cpu.arch) { @panic("Attempted to compile for architecture that was disabled by build configuration"); } @@ -6083,178 +6083,26 @@ fn getResolvedInstValue(self: *Self, inst: Air.Inst.Index) MCValue { } } -fn lowerDeclRef(self: *Self, tv: TypedValue, decl_index: Module.Decl.Index) InnerError!MCValue { - const ptr_bits = self.target.cpu.arch.ptrBitWidth(); - const ptr_bytes: u64 = @divExact(ptr_bits, 8); - - const mod = self.bin_file.options.module.?; - const decl = mod.declPtr(decl_index); - mod.markDeclAlive(decl); - - if (self.bin_file.cast(link.File.Elf)) |elf_file| { - const atom_index = try elf_file.getOrCreateAtomForDecl(decl_index); - const atom = elf_file.getAtom(atom_index); - return MCValue{ .memory = atom.getOffsetTableAddress(elf_file) }; - } else if (self.bin_file.cast(link.File.MachO)) |_| { - unreachable; // unsupported architecture for MachO - } else if (self.bin_file.cast(link.File.Coff)) |_| { - return self.fail("TODO codegen COFF const Decl pointer", .{}); - } else if (self.bin_file.cast(link.File.Plan9)) |p9| { - const decl_block_index = try p9.seeDecl(decl_index); - const decl_block = p9.getDeclBlock(decl_block_index); - const got_addr = p9.bases.data + decl_block.got_index.? * ptr_bytes; - return MCValue{ .memory = got_addr }; - } else { - return self.fail("TODO codegen non-ELF const Decl pointer", .{}); - } - - _ = tv; -} - -fn lowerUnnamedConst(self: *Self, tv: TypedValue) InnerError!MCValue { - const local_sym_index = self.bin_file.lowerUnnamedConst(tv, self.mod_fn.owner_decl) catch |err| { - return self.fail("lowering unnamed constant failed: {s}", .{@errorName(err)}); - }; - if (self.bin_file.cast(link.File.Elf)) |elf_file| { - return MCValue{ .memory = elf_file.getSymbol(local_sym_index).st_value }; - } else if (self.bin_file.cast(link.File.MachO)) |_| { - unreachable; - } else if (self.bin_file.cast(link.File.Coff)) |_| { - return self.fail("TODO lower unnamed const in COFF", .{}); - } else if (self.bin_file.cast(link.File.Plan9)) |_| { - return self.fail("TODO lower unnamed const in Plan9", .{}); - } else { - return self.fail("TODO lower unnamed const", .{}); - } -} - fn genTypedValue(self: *Self, arg_tv: TypedValue) InnerError!MCValue { - var typed_value = arg_tv; - if (typed_value.val.castTag(.runtime_value)) |rt| { - typed_value.val = rt.data; - } - log.debug("genTypedValue: ty = {}, val = {}", .{ typed_value.ty.fmtDebug(), typed_value.val.fmtDebug() }); - if (typed_value.val.isUndef()) - return MCValue{ .undef = {} }; - const ptr_bits = self.target.cpu.arch.ptrBitWidth(); - - if (typed_value.val.castTag(.decl_ref)) |payload| { - return self.lowerDeclRef(typed_value, payload.data); - } - if (typed_value.val.castTag(.decl_ref_mut)) |payload| { - return self.lowerDeclRef(typed_value, payload.data.decl_index); - } - const target = self.target.*; - - switch (typed_value.ty.zigTypeTag()) { - .Pointer => switch (typed_value.ty.ptrSize()) { - .Slice => {}, - else => { - switch (typed_value.val.tag()) { - .int_u64 => { - return MCValue{ .immediate = @intCast(u32, typed_value.val.toUnsignedInt(target)) }; - }, - else => {}, - } - }, + const mcv: MCValue = switch (try codegen.genTypedValue( + self.bin_file, + self.src_loc, + arg_tv, + self.mod_fn.owner_decl, + )) { + .mcv => |mcv| switch (mcv) { + .none => .none, + .undef => .undef, + .linker_load => unreachable, // TODO + .immediate => |imm| .{ .immediate = @truncate(u32, imm) }, + .memory => |addr| .{ .memory = addr }, }, - .Int => { - const info = typed_value.ty.intInfo(self.target.*); - if (info.bits <= ptr_bits) { - const unsigned = switch (info.signedness) { - .signed => blk: { - const signed = @intCast(i32, typed_value.val.toSignedInt(target)); - break :blk @bitCast(u32, signed); - }, - .unsigned => @intCast(u32, typed_value.val.toUnsignedInt(target)), - }; - - return MCValue{ .immediate = unsigned }; - } else { - return self.lowerUnnamedConst(typed_value); - } - }, - .Bool => { - return MCValue{ .immediate = @boolToInt(typed_value.val.toBool()) }; - }, - .Optional => { - if (typed_value.ty.isPtrLikeOptional()) { - if (typed_value.val.isNull()) - return MCValue{ .immediate = 0 }; - - var buf: Type.Payload.ElemType = undefined; - return self.genTypedValue(.{ - .ty = typed_value.ty.optionalChild(&buf), - .val = typed_value.val, - }); - } else if (typed_value.ty.abiSize(self.target.*) == 1) { - return MCValue{ .immediate = @boolToInt(typed_value.val.isNull()) }; - } - }, - .Enum => { - if (typed_value.val.castTag(.enum_field_index)) |field_index| { - switch (typed_value.ty.tag()) { - .enum_simple => { - return MCValue{ .immediate = field_index.data }; - }, - .enum_full, .enum_nonexhaustive => { - const enum_full = typed_value.ty.cast(Type.Payload.EnumFull).?.data; - if (enum_full.values.count() != 0) { - const tag_val = enum_full.values.keys()[field_index.data]; - return self.genTypedValue(.{ .ty = enum_full.tag_ty, .val = tag_val }); - } else { - return MCValue{ .immediate = field_index.data }; - } - }, - else => unreachable, - } - } else { - var int_tag_buffer: Type.Payload.Bits = undefined; - const int_tag_ty = typed_value.ty.intTagType(&int_tag_buffer); - return self.genTypedValue(.{ .ty = int_tag_ty, .val = typed_value.val }); - } - }, - .ErrorSet => { - switch (typed_value.val.tag()) { - .@"error" => { - const err_name = typed_value.val.castTag(.@"error").?.data.name; - const module = self.bin_file.options.module.?; - const global_error_set = module.global_error_set; - const error_index = global_error_set.get(err_name).?; - return MCValue{ .immediate = error_index }; - }, - else => { - // In this case we are rendering an error union which has a 0 bits payload. - return MCValue{ .immediate = 0 }; - }, - } + .fail => |msg| { + self.err_msg = msg; + return error.CodegenFail; }, - .ErrorUnion => { - const error_type = typed_value.ty.errorUnionSet(); - const payload_type = typed_value.ty.errorUnionPayload(); - const is_pl = typed_value.val.errorUnionIsPayload(); - - if (!payload_type.hasRuntimeBitsIgnoreComptime()) { - // We use the error type directly as the type. - const err_val = if (!is_pl) typed_value.val else Value.initTag(.zero); - return self.genTypedValue(.{ .ty = error_type, .val = err_val }); - } - }, - - .ComptimeInt => unreachable, // semantic analysis prevents this - .ComptimeFloat => unreachable, // semantic analysis prevents this - .Type => unreachable, - .EnumLiteral => unreachable, - .Void => unreachable, - .NoReturn => unreachable, - .Undefined => unreachable, - .Null => unreachable, - .Opaque => unreachable, - - else => {}, - } - - return self.lowerUnnamedConst(typed_value); + }; + return mcv; } const CallMCValues = struct { diff --git a/src/arch/x86_64/CodeGen.zig b/src/arch/x86_64/CodeGen.zig index 2ec1a33619..a2c11b332b 100644 --- a/src/arch/x86_64/CodeGen.zig +++ b/src/arch/x86_64/CodeGen.zig @@ -12,12 +12,12 @@ const trace = @import("../../tracy.zig").trace; const Air = @import("../../Air.zig"); const Allocator = mem.Allocator; +const CodeGenError = codegen.CodeGenError; const Compilation = @import("../../Compilation.zig"); const DebugInfoOutput = codegen.DebugInfoOutput; const DW = std.dwarf; const ErrorMsg = Module.ErrorMsg; const Result = codegen.Result; -const GenerateSymbolError = codegen.GenerateSymbolError; const Emit = @import("Emit.zig"); const Liveness = @import("../../Liveness.zig"); const Mir = @import("Mir.zig"); @@ -40,7 +40,7 @@ const Register = bits.Register; const gp = abi.RegisterClass.gp; const sse = abi.RegisterClass.sse; -const InnerError = codegen.CodeGenError || error{OutOfRegisters}; +const InnerError = CodeGenError || error{OutOfRegisters}; gpa: Allocator, air: Air, @@ -253,7 +253,7 @@ pub fn generate( liveness: Liveness, code: *std.ArrayList(u8), debug_output: DebugInfoOutput, -) GenerateSymbolError!Result { +) CodeGenError!Result { if (build_options.skip_non_native and builtin.cpu.arch != bin_file.options.target.cpu.arch) { @panic("Attempted to compile for architecture that was disabled by build configuration"); } -- cgit v1.2.3 From c413ac100fa5a4cece5702d3afb6b0898e9c6214 Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Fri, 3 Mar 2023 18:40:16 +0100 Subject: codegen: refactor generating Int as immediate where appropriate --- src/codegen.zig | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/codegen.zig b/src/codegen.zig index 245745d6f6..7e7f34f992 100644 --- a/src/codegen.zig +++ b/src/codegen.zig @@ -1051,11 +1051,12 @@ pub fn genTypedValue( }, .Int => { const info = typed_value.ty.intInfo(target); - if (info.bits <= ptr_bits and info.signedness == .signed) { - return GenResult.mcv(.{ .immediate = @bitCast(u64, typed_value.val.toSignedInt(target)) }); - } - if (!(info.bits > ptr_bits or info.signedness == .signed)) { - return GenResult.mcv(.{ .immediate = typed_value.val.toUnsignedInt(target) }); + if (info.bits <= ptr_bits) { + const unsigned = switch (info.signedness) { + .signed => @bitCast(u64, typed_value.val.toSignedInt(target)), + .unsigned => typed_value.val.toUnsignedInt(target), + }; + return GenResult.mcv(.{ .immediate = unsigned }); } }, .Bool => { -- cgit v1.2.3 From 0d2c25ca9d0794b1c822a12f3bdf8e57ede4c840 Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Fri, 3 Mar 2023 18:46:08 +0100 Subject: aarch64: use common implementation of genTypedValue --- src/arch/aarch64/CodeGen.zig | 215 ++++--------------------------------------- 1 file changed, 20 insertions(+), 195 deletions(-) (limited to 'src') diff --git a/src/arch/aarch64/CodeGen.zig b/src/arch/aarch64/CodeGen.zig index 23f458f910..28f8370bd9 100644 --- a/src/arch/aarch64/CodeGen.zig +++ b/src/arch/aarch64/CodeGen.zig @@ -23,7 +23,7 @@ const leb128 = std.leb; const log = std.log.scoped(.codegen); const build_options = @import("build_options"); -const GenerateSymbolError = codegen.GenerateSymbolError; +const CodeGenError = codegen.CodeGenError; const Result = codegen.Result; const DebugInfoOutput = codegen.DebugInfoOutput; @@ -41,7 +41,7 @@ const c_abi_int_param_regs = abi.c_abi_int_param_regs; const c_abi_int_return_regs = abi.c_abi_int_return_regs; const gp = abi.RegisterClass.gp; -const InnerError = codegen.CodeGenError || error{OutOfRegisters}; +const InnerError = CodeGenError || error{OutOfRegisters}; gpa: Allocator, air: Air, @@ -333,7 +333,7 @@ pub fn generate( liveness: Liveness, code: *std.ArrayList(u8), debug_output: DebugInfoOutput, -) GenerateSymbolError!Result { +) CodeGenError!Result { if (build_options.skip_non_native and builtin.cpu.arch != bin_file.options.target.cpu.arch) { @panic("Attempted to compile for architecture that was disabled by build configuration"); } @@ -6133,201 +6133,26 @@ fn getResolvedInstValue(self: *Self, inst: Air.Inst.Index) MCValue { } } -fn lowerDeclRef(self: *Self, tv: TypedValue, decl_index: Module.Decl.Index) InnerError!MCValue { - const ptr_bits = self.target.cpu.arch.ptrBitWidth(); - const ptr_bytes: u64 = @divExact(ptr_bits, 8); - - // TODO this feels clunky. Perhaps we should check for it in `genTypedValue`? - if (tv.ty.zigTypeTag() == .Pointer) blk: { - if (tv.ty.castPtrToFn()) |_| break :blk; - if (!tv.ty.elemType2().hasRuntimeBits()) { - return MCValue.none; - } - } - - const mod = self.bin_file.options.module.?; - const decl = mod.declPtr(decl_index); - mod.markDeclAlive(decl); - - if (self.bin_file.cast(link.File.Elf)) |elf_file| { - const atom_index = try elf_file.getOrCreateAtomForDecl(decl_index); - const atom = elf_file.getAtom(atom_index); - return MCValue{ .memory = atom.getOffsetTableAddress(elf_file) }; - } else if (self.bin_file.cast(link.File.MachO)) |macho_file| { - const atom = try macho_file.getOrCreateAtomForDecl(decl_index); - const sym_index = macho_file.getAtom(atom).getSymbolIndex().?; - return MCValue{ .linker_load = .{ - .type = .got, - .sym_index = sym_index, - } }; - } else if (self.bin_file.cast(link.File.Coff)) |coff_file| { - const atom_index = try coff_file.getOrCreateAtomForDecl(decl_index); - const sym_index = coff_file.getAtom(atom_index).getSymbolIndex().?; - return MCValue{ .linker_load = .{ - .type = .got, - .sym_index = sym_index, - } }; - } else if (self.bin_file.cast(link.File.Plan9)) |p9| { - const decl_block_index = try p9.seeDecl(decl_index); - const decl_block = p9.getDeclBlock(decl_block_index); - const got_addr = p9.bases.data + decl_block.got_index.? * ptr_bytes; - return MCValue{ .memory = got_addr }; - } else { - return self.fail("TODO codegen non-ELF const Decl pointer", .{}); - } -} - -fn lowerUnnamedConst(self: *Self, tv: TypedValue) InnerError!MCValue { - log.debug("lowerUnnamedConst: ty = {}, val = {}", .{ tv.ty.fmtDebug(), tv.val.fmtDebug() }); - const local_sym_index = self.bin_file.lowerUnnamedConst(tv, self.mod_fn.owner_decl) catch |err| { - return self.fail("lowering unnamed constant failed: {s}", .{@errorName(err)}); - }; - if (self.bin_file.cast(link.File.Elf)) |elf_file| { - return MCValue{ .memory = elf_file.getSymbol(local_sym_index).st_value }; - } else if (self.bin_file.cast(link.File.MachO)) |_| { - return MCValue{ .linker_load = .{ - .type = .direct, - .sym_index = local_sym_index, - } }; - } else if (self.bin_file.cast(link.File.Coff)) |_| { - return MCValue{ .linker_load = .{ - .type = .direct, - .sym_index = local_sym_index, - } }; - } else if (self.bin_file.cast(link.File.Plan9)) |_| { - return self.fail("TODO lower unnamed const in Plan9", .{}); - } else { - return self.fail("TODO lower unnamed const", .{}); - } -} - fn genTypedValue(self: *Self, arg_tv: TypedValue) InnerError!MCValue { - var typed_value = arg_tv; - if (typed_value.val.castTag(.runtime_value)) |rt| { - typed_value.val = rt.data; - } - log.debug("genTypedValue: ty = {}, val = {}", .{ typed_value.ty.fmtDebug(), typed_value.val.fmtDebug() }); - if (typed_value.val.isUndef()) - return MCValue{ .undef = {} }; - - if (typed_value.val.castTag(.decl_ref)) |payload| { - return self.lowerDeclRef(typed_value, payload.data); - } - if (typed_value.val.castTag(.decl_ref_mut)) |payload| { - return self.lowerDeclRef(typed_value, payload.data.decl_index); - } - const target = self.target.*; - - switch (typed_value.ty.zigTypeTag()) { - .Pointer => switch (typed_value.ty.ptrSize()) { - .Slice => {}, - else => { - switch (typed_value.val.tag()) { - .int_u64 => { - return MCValue{ .immediate = typed_value.val.toUnsignedInt(target) }; - }, - else => {}, - } - }, + const mcv: MCValue = switch (try codegen.genTypedValue( + self.bin_file, + self.src_loc, + arg_tv, + self.mod_fn.owner_decl, + )) { + .mcv => |mcv| switch (mcv) { + .none => .none, + .undef => .undef, + .linker_load => |ll| .{ .linker_load = ll }, + .immediate => |imm| .{ .immediate = imm }, + .memory => |addr| .{ .memory = addr }, }, - .Int => { - const info = typed_value.ty.intInfo(self.target.*); - if (info.bits <= 64) { - const unsigned = switch (info.signedness) { - .signed => blk: { - const signed = typed_value.val.toSignedInt(target); - break :blk @bitCast(u64, signed); - }, - .unsigned => typed_value.val.toUnsignedInt(target), - }; - - return MCValue{ .immediate = unsigned }; - } + .fail => |msg| { + self.err_msg = msg; + return error.CodegenFail; }, - .Bool => { - return MCValue{ .immediate = @boolToInt(typed_value.val.toBool()) }; - }, - .Optional => { - if (typed_value.ty.isPtrLikeOptional()) { - if (typed_value.val.isNull()) - return MCValue{ .immediate = 0 }; - - var buf: Type.Payload.ElemType = undefined; - return self.genTypedValue(.{ - .ty = typed_value.ty.optionalChild(&buf), - .val = typed_value.val, - }); - } else if (typed_value.ty.abiSize(self.target.*) == 1) { - return MCValue{ .immediate = @boolToInt(typed_value.val.isNull()) }; - } - }, - .Enum => { - if (typed_value.val.castTag(.enum_field_index)) |field_index| { - switch (typed_value.ty.tag()) { - .enum_simple => { - return MCValue{ .immediate = field_index.data }; - }, - .enum_full, .enum_nonexhaustive => { - const enum_full = typed_value.ty.cast(Type.Payload.EnumFull).?.data; - if (enum_full.values.count() != 0) { - const tag_val = enum_full.values.keys()[field_index.data]; - return self.genTypedValue(.{ .ty = enum_full.tag_ty, .val = tag_val }); - } else { - return MCValue{ .immediate = field_index.data }; - } - }, - else => unreachable, - } - } else { - var int_tag_buffer: Type.Payload.Bits = undefined; - const int_tag_ty = typed_value.ty.intTagType(&int_tag_buffer); - return self.genTypedValue(.{ .ty = int_tag_ty, .val = typed_value.val }); - } - }, - .ErrorSet => { - switch (typed_value.val.tag()) { - .@"error" => { - const err_name = typed_value.val.castTag(.@"error").?.data.name; - const module = self.bin_file.options.module.?; - const global_error_set = module.global_error_set; - const error_index = global_error_set.get(err_name).?; - return MCValue{ .immediate = error_index }; - }, - else => { - // In this case we are rendering an error union which has a 0 bits payload. - return MCValue{ .immediate = 0 }; - }, - } - }, - .ErrorUnion => { - const error_type = typed_value.ty.errorUnionSet(); - const payload_type = typed_value.ty.errorUnionPayload(); - - const is_pl = typed_value.val.errorUnionIsPayload(); - - if (!payload_type.hasRuntimeBitsIgnoreComptime()) { - // We use the error type directly as the type. - const err_val = if (!is_pl) typed_value.val else Value.initTag(.zero); - return self.genTypedValue(.{ .ty = error_type, .val = err_val }); - } - - return self.lowerUnnamedConst(typed_value); - }, - - .ComptimeInt => unreachable, // semantic analysis prevents this - .ComptimeFloat => unreachable, // semantic analysis prevents this - .Type => unreachable, - .EnumLiteral => unreachable, - .Void => unreachable, - .NoReturn => unreachable, - .Undefined => unreachable, - .Null => unreachable, - .Opaque => unreachable, - - else => {}, - } - - return self.lowerUnnamedConst(typed_value); + }; + return mcv; } const CallMCValues = struct { -- cgit v1.2.3 From 5b3ea49806f5d0b9034e3eacbef9e19428a5db8a Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Fri, 3 Mar 2023 18:53:13 +0100 Subject: riscv64: use common implementation of genTypedValue --- src/arch/riscv64/CodeGen.zig | 158 ++++++------------------------------------- 1 file changed, 20 insertions(+), 138 deletions(-) (limited to 'src') diff --git a/src/arch/riscv64/CodeGen.zig b/src/arch/riscv64/CodeGen.zig index fad5482cbc..c7191145f9 100644 --- a/src/arch/riscv64/CodeGen.zig +++ b/src/arch/riscv64/CodeGen.zig @@ -23,6 +23,7 @@ const log = std.log.scoped(.codegen); const build_options = @import("build_options"); const codegen = @import("../../codegen.zig"); +const CodeGenError = codegen.CodeGenError; const Result = codegen.Result; const DebugInfoOutput = codegen.DebugInfoOutput; @@ -35,7 +36,7 @@ const Instruction = abi.Instruction; const callee_preserved_regs = abi.callee_preserved_regs; const gp = abi.RegisterClass.gp; -const InnerError = codegen.CodeGenError || error{OutOfRegisters}; +const InnerError = CodeGenError || error{OutOfRegisters}; gpa: Allocator, air: Air, @@ -221,7 +222,7 @@ pub fn generate( liveness: Liveness, code: *std.ArrayList(u8), debug_output: DebugInfoOutput, -) codegen.CodeGenError!Result { +) CodeGenError!Result { if (build_options.skip_non_native and builtin.cpu.arch != bin_file.options.target.cpu.arch) { @panic("Attempted to compile for architecture that was disabled by build configuration"); } @@ -2548,145 +2549,26 @@ fn getResolvedInstValue(self: *Self, inst: Air.Inst.Index) MCValue { } } -fn lowerDeclRef(self: *Self, tv: TypedValue, decl_index: Module.Decl.Index) InnerError!MCValue { - const ptr_bits = self.target.cpu.arch.ptrBitWidth(); - const ptr_bytes: u64 = @divExact(ptr_bits, 8); - const mod = self.bin_file.options.module.?; - const decl = mod.declPtr(decl_index); - mod.markDeclAlive(decl); - if (self.bin_file.cast(link.File.Elf)) |elf_file| { - const atom_index = try elf_file.getOrCreateAtomForDecl(decl_index); - const atom = elf_file.getAtom(atom_index); - return MCValue{ .memory = atom.getOffsetTableAddress(elf_file) }; - } else if (self.bin_file.cast(link.File.MachO)) |_| { - unreachable; - } else if (self.bin_file.cast(link.File.Coff)) |_| { - return self.fail("TODO codegen COFF const Decl pointer", .{}); - } else if (self.bin_file.cast(link.File.Plan9)) |p9| { - const decl_block_index = try p9.seeDecl(decl_index); - const decl_block = p9.getDeclBlock(decl_block_index); - const got_addr = p9.bases.data + decl_block.got_index.? * ptr_bytes; - return MCValue{ .memory = got_addr }; - } else { - return self.fail("TODO codegen non-ELF const Decl pointer", .{}); - } - _ = tv; -} - fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue { - if (typed_value.val.isUndef()) - return MCValue{ .undef = {} }; - - if (typed_value.val.castTag(.decl_ref)) |payload| { - return self.lowerDeclRef(typed_value, payload.data); - } - if (typed_value.val.castTag(.decl_ref_mut)) |payload| { - return self.lowerDeclRef(typed_value, payload.data.decl_index); - } - const target = self.target.*; - const ptr_bits = self.target.cpu.arch.ptrBitWidth(); - switch (typed_value.ty.zigTypeTag()) { - .Pointer => switch (typed_value.ty.ptrSize()) { - .Slice => { - var buf: Type.SlicePtrFieldTypeBuffer = undefined; - const ptr_type = typed_value.ty.slicePtrFieldType(&buf); - const ptr_mcv = try self.genTypedValue(.{ .ty = ptr_type, .val = typed_value.val }); - const mod = self.bin_file.options.module.?; - const slice_len = typed_value.val.sliceLen(mod); - // 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("TODO codegen for const slices", .{}); - }, - else => { - if (typed_value.val.tag() == .int_u64) { - return MCValue{ .immediate = typed_value.val.toUnsignedInt(target) }; - } - return self.fail("TODO codegen more kinds of const pointers", .{}); - }, - }, - .Int => { - const info = typed_value.ty.intInfo(self.target.*); - if (info.bits > ptr_bits or info.signedness == .signed) { - return self.fail("TODO const int bigger than ptr and signed int", .{}); - } - return MCValue{ .immediate = typed_value.val.toUnsignedInt(target) }; + const mcv: MCValue = switch (try codegen.genTypedValue( + self.bin_file, + self.src_loc, + typed_value, + self.mod_fn.owner_decl, + )) { + .mcv => |mcv| switch (mcv) { + .none => .none, + .undef => .undef, + .linker_load => unreachable, // TODO + .immediate => |imm| .{ .immediate = imm }, + .memory => |addr| .{ .memory = addr }, }, - .Bool => { - return MCValue{ .immediate = @boolToInt(typed_value.val.toBool()) }; + .fail => |msg| { + self.err_msg = msg; + return error.CodegenFail; }, - .ComptimeInt => unreachable, // semantic analysis prevents this - .ComptimeFloat => unreachable, // semantic analysis prevents this - .Optional => { - if (typed_value.ty.isPtrLikeOptional()) { - if (typed_value.val.isNull()) - return MCValue{ .immediate = 0 }; - - var buf: Type.Payload.ElemType = undefined; - return self.genTypedValue(.{ - .ty = typed_value.ty.optionalChild(&buf), - .val = typed_value.val, - }); - } else if (typed_value.ty.abiSize(self.target.*) == 1) { - return MCValue{ .immediate = @boolToInt(typed_value.val.isNull()) }; - } - return self.fail("TODO non pointer optionals", .{}); - }, - .Enum => { - if (typed_value.val.castTag(.enum_field_index)) |field_index| { - switch (typed_value.ty.tag()) { - .enum_simple => { - return MCValue{ .immediate = field_index.data }; - }, - .enum_full, .enum_nonexhaustive => { - const enum_full = typed_value.ty.cast(Type.Payload.EnumFull).?.data; - if (enum_full.values.count() != 0) { - const tag_val = enum_full.values.keys()[field_index.data]; - return self.genTypedValue(.{ .ty = enum_full.tag_ty, .val = tag_val }); - } else { - return MCValue{ .immediate = field_index.data }; - } - }, - else => unreachable, - } - } else { - var int_tag_buffer: Type.Payload.Bits = undefined; - const int_tag_ty = typed_value.ty.intTagType(&int_tag_buffer); - return self.genTypedValue(.{ .ty = int_tag_ty, .val = typed_value.val }); - } - }, - .ErrorSet => { - switch (typed_value.val.tag()) { - .@"error" => { - const err_name = typed_value.val.castTag(.@"error").?.data.name; - const module = self.bin_file.options.module.?; - const global_error_set = module.global_error_set; - const error_index = global_error_set.get(err_name).?; - return MCValue{ .immediate = error_index }; - }, - else => { - // In this case we are rendering an error union which has a 0 bits payload. - return MCValue{ .immediate = 0 }; - }, - } - }, - .ErrorUnion => { - const error_type = typed_value.ty.errorUnionSet(); - const payload_type = typed_value.ty.errorUnionPayload(); - const sub_val = typed_value.val.castTag(.eu_payload).?.data; - - if (!payload_type.hasRuntimeBits()) { - // We use the error type directly as the type. - return self.genTypedValue(.{ .ty = error_type, .val = sub_val }); - } - - return self.fail("TODO implement error union const of type '{}'", .{typed_value.ty.fmtDebug()}); - }, - else => return self.fail("TODO implement const of type '{}'", .{typed_value.ty.fmtDebug()}), - } + }; + return mcv; } const CallMCValues = struct { -- cgit v1.2.3 From f6eeb6c8ce83af392dc075e3f80846aefc791f42 Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Fri, 3 Mar 2023 18:53:30 +0100 Subject: sparc64: use common implementation of genTypedValue --- src/arch/sparc64/CodeGen.zig | 170 +++++-------------------------------------- 1 file changed, 20 insertions(+), 150 deletions(-) (limited to 'src') diff --git a/src/arch/sparc64/CodeGen.zig b/src/arch/sparc64/CodeGen.zig index 5a108eca85..dc1a450e9a 100644 --- a/src/arch/sparc64/CodeGen.zig +++ b/src/arch/sparc64/CodeGen.zig @@ -19,7 +19,7 @@ const Mir = @import("Mir.zig"); const Emit = @import("Emit.zig"); const Liveness = @import("../../Liveness.zig"); const Type = @import("../../type.zig").Type; -const GenerateSymbolError = @import("../../codegen.zig").GenerateSymbolError; +const CodeGenError = codegen.CodeGenError; const Result = @import("../../codegen.zig").Result; const DebugInfoOutput = @import("../../codegen.zig").DebugInfoOutput; @@ -38,7 +38,7 @@ const gp = abi.RegisterClass.gp; const Self = @This(); -const InnerError = codegen.CodeGenError || error{OutOfRegisters}; +const InnerError = CodeGenError || error{OutOfRegisters}; const RegisterView = enum(u1) { caller, @@ -261,7 +261,7 @@ pub fn generate( liveness: Liveness, code: *std.ArrayList(u8), debug_output: DebugInfoOutput, -) GenerateSymbolError!Result { +) CodeGenError!Result { if (build_options.skip_non_native and builtin.cpu.arch != bin_file.options.target.cpu.arch) { @panic("Attempted to compile for architecture that was disabled by build configuration"); } @@ -3894,133 +3894,25 @@ fn genStore(self: *Self, value_reg: Register, addr_reg: Register, comptime off_t } fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue { - var tv = typed_value; - log.debug("genTypedValue: ty = {}, val = {}", .{ tv.ty.fmtDebug(), tv.val.fmtDebug() }); - - if (tv.val.castTag(.runtime_value)) |rt| { - tv.val = rt.data; - } - - if (tv.val.isUndef()) - return MCValue{ .undef = {} }; - - if (tv.val.castTag(.decl_ref)) |payload| { - return self.lowerDeclRef(tv, payload.data); - } - if (tv.val.castTag(.decl_ref_mut)) |payload| { - return self.lowerDeclRef(tv, payload.data.decl_index); - } - const target = self.target.*; - - switch (tv.ty.zigTypeTag()) { - .Pointer => switch (tv.ty.ptrSize()) { - .Slice => {}, - else => { - switch (tv.val.tag()) { - .int_u64 => { - return MCValue{ .immediate = tv.val.toUnsignedInt(target) }; - }, - else => {}, - } - }, - }, - .Bool => { - return MCValue{ .immediate = @boolToInt(tv.val.toBool()) }; - }, - .Int => { - const info = tv.ty.intInfo(self.target.*); - if (info.bits <= 64) { - const unsigned = switch (info.signedness) { - .signed => blk: { - const signed = tv.val.toSignedInt(target); - break :blk @bitCast(u64, signed); - }, - .unsigned => tv.val.toUnsignedInt(target), - }; - - return MCValue{ .immediate = unsigned }; - } else { - return self.fail("TODO implement int genTypedValue of > 64 bits", .{}); - } + const mcv: MCValue = switch (try codegen.genTypedValue( + self.bin_file, + self.src_loc, + typed_value, + self.mod_fn.owner_decl, + )) { + .mcv => |mcv| switch (mcv) { + .none => .none, + .undef => .undef, + .linker_load => unreachable, // TODO + .immediate => |imm| .{ .immediate = imm }, + .memory => |addr| .{ .memory = addr }, }, - .Optional => { - if (tv.ty.isPtrLikeOptional()) { - if (tv.val.isNull()) - return MCValue{ .immediate = 0 }; - - var buf: Type.Payload.ElemType = undefined; - return self.genTypedValue(.{ - .ty = tv.ty.optionalChild(&buf), - .val = tv.val, - }); - } else if (tv.ty.abiSize(self.target.*) == 1) { - return MCValue{ .immediate = @boolToInt(tv.val.isNull()) }; - } + .fail => |msg| { + self.err_msg = msg; + return error.CodegenFail; }, - .Enum => { - if (tv.val.castTag(.enum_field_index)) |field_index| { - switch (tv.ty.tag()) { - .enum_simple => { - return MCValue{ .immediate = field_index.data }; - }, - .enum_full, .enum_nonexhaustive => { - const enum_full = tv.ty.cast(Type.Payload.EnumFull).?.data; - if (enum_full.values.count() != 0) { - const tag_val = enum_full.values.keys()[field_index.data]; - return self.genTypedValue(.{ .ty = enum_full.tag_ty, .val = tag_val }); - } else { - return MCValue{ .immediate = field_index.data }; - } - }, - else => unreachable, - } - } else { - var int_tag_buffer: Type.Payload.Bits = undefined; - const int_tag_ty = tv.ty.intTagType(&int_tag_buffer); - return self.genTypedValue(.{ .ty = int_tag_ty, .val = tv.val }); - } - }, - .ErrorSet => { - const err_name = tv.val.castTag(.@"error").?.data.name; - const module = self.bin_file.options.module.?; - const global_error_set = module.global_error_set; - const error_index = global_error_set.get(err_name).?; - return MCValue{ .immediate = error_index }; - }, - .ErrorUnion => { - const error_type = tv.ty.errorUnionSet(); - const payload_type = tv.ty.errorUnionPayload(); - - if (tv.val.castTag(.eu_payload)) |pl| { - if (!payload_type.hasRuntimeBits()) { - // We use the error type directly as the type. - return MCValue{ .immediate = 0 }; - } - - _ = pl; - return self.fail("TODO implement error union const of type '{}' (non-error)", .{tv.ty.fmtDebug()}); - } else { - if (!payload_type.hasRuntimeBits()) { - // We use the error type directly as the type. - return self.genTypedValue(.{ .ty = error_type, .val = tv.val }); - } - - return self.fail("TODO implement error union const of type '{}' (error)", .{tv.ty.fmtDebug()}); - } - }, - .ComptimeInt => unreachable, // semantic analysis prevents this - .ComptimeFloat => unreachable, // semantic analysis prevents this - .Type => unreachable, - .EnumLiteral => unreachable, - .Void => unreachable, - .NoReturn => unreachable, - .Undefined => unreachable, - .Null => unreachable, - .Opaque => unreachable, - else => {}, - } - - return self.fail("TODO implement const of type '{}'", .{tv.ty.fmtDebug()}); + }; + return mcv; } fn getResolvedInstValue(self: *Self, inst: Air.Inst.Index) MCValue { @@ -4196,28 +4088,6 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo } } -fn lowerDeclRef(self: *Self, tv: TypedValue, decl_index: Module.Decl.Index) InnerError!MCValue { - // TODO this feels clunky. Perhaps we should check for it in `genTypedValue`? - if (tv.ty.zigTypeTag() == .Pointer) blk: { - if (tv.ty.castPtrToFn()) |_| break :blk; - if (!tv.ty.elemType2().hasRuntimeBits()) { - return MCValue.none; - } - } - - const mod = self.bin_file.options.module.?; - const decl = mod.declPtr(decl_index); - - mod.markDeclAlive(decl); - if (self.bin_file.cast(link.File.Elf)) |elf_file| { - const atom_index = try elf_file.getOrCreateAtomForDecl(decl_index); - const atom = elf_file.getAtom(atom_index); - return MCValue{ .memory = atom.getOffsetTableAddress(elf_file) }; - } else { - return self.fail("TODO codegen non-ELF const Decl pointer", .{}); - } -} - fn minMax( self: *Self, tag: Air.Inst.Tag, -- cgit v1.2.3 From d23472747eb288e4c2332e03f6185c69e864f67d Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Fri, 3 Mar 2023 18:53:47 +0100 Subject: elf: fully zero out symbol when appending to freelist --- src/link/Elf.zig | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/link/Elf.zig b/src/link/Elf.zig index f499a9952a..a91722d072 100644 --- a/src/link/Elf.zig +++ b/src/link/Elf.zig @@ -2097,9 +2097,16 @@ fn freeAtom(self: *Elf, atom_index: Atom.Index) void { // Appending to free lists is allowed to fail because the free lists are heuristics based anyway. const local_sym_index = atom.getSymbolIndex().?; + log.debug("adding %{d} to local symbols free list", .{local_sym_index}); self.local_symbol_free_list.append(gpa, local_sym_index) catch {}; - self.local_symbols.items[local_sym_index].st_info = 0; - self.local_symbols.items[local_sym_index].st_shndx = 0; + self.local_symbols.items[local_sym_index] = .{ + .st_name = 0, + .st_info = 0, + .st_other = 0, + .st_shndx = 0, + .st_value = 0, + .st_size = 0, + }; _ = self.atom_by_index_table.remove(local_sym_index); self.getAtomPtr(atom_index).local_sym_index = 0; -- cgit v1.2.3 From dc709fbf48798ae74d5c7763cf99dffeb8143795 Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Fri, 3 Mar 2023 18:56:57 +0100 Subject: codegen: rename GenerateSymbolError to CodeGenError --- src/arch/wasm/CodeGen.zig | 2 +- src/codegen.zig | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) (limited to 'src') diff --git a/src/arch/wasm/CodeGen.zig b/src/arch/wasm/CodeGen.zig index 511a10769e..5cd6c95690 100644 --- a/src/arch/wasm/CodeGen.zig +++ b/src/arch/wasm/CodeGen.zig @@ -1162,7 +1162,7 @@ pub fn generate( liveness: Liveness, code: *std.ArrayList(u8), debug_output: codegen.DebugInfoOutput, -) codegen.GenerateSymbolError!codegen.Result { +) codegen.CodeGenError!codegen.Result { _ = src_loc; var code_gen: CodeGen = .{ .gpa = bin_file.allocator, diff --git a/src/codegen.zig b/src/codegen.zig index 7e7f34f992..a91795841c 100644 --- a/src/codegen.zig +++ b/src/codegen.zig @@ -35,8 +35,6 @@ pub const CodeGenError = error{ CodegenFail, }; -pub const GenerateSymbolError = CodeGenError; - pub const DebugInfoOutput = union(enum) { dwarf: *link.File.Dwarf.DeclState, /// the plan9 debuginfo output is a bytecode with 4 opcodes -- cgit v1.2.3