| author | |
| committer | |
| log | 18e6d1e81929964e9f1d9780e3d8e8f8ae4fcff0 |
| tree | 07b21d5e7364468b8941d8055cc0e79ac8eb6a74 |
| parent | e0d390463865340adc8055d1e34c0bc7acf4e4c3 |
| parent | dc709fbf48798ae74d5c7763cf99dffeb8143795 |
| signature |
codegen: move common logic for generating typed values from each native backend into codegen.zig14 files changed, 414 insertions(+), 902 deletions(-)
src/arch/aarch64/CodeGen.zig+20-199| ... | @@ -23,7 +23,7 @@ const leb128 = std.leb; | ... | @@ -23,7 +23,7 @@ const leb128 = std.leb; |
| 23 | const log = std.log.scoped(.codegen); | 23 | const log = std.log.scoped(.codegen); |
| 24 | const build_options = @import("build_options"); | 24 | const build_options = @import("build_options"); |
| 25 | 25 | ||
| 26 | const GenerateSymbolError = codegen.GenerateSymbolError; | 26 | const CodeGenError = codegen.CodeGenError; |
| 27 | const Result = codegen.Result; | 27 | const Result = codegen.Result; |
| 28 | const DebugInfoOutput = codegen.DebugInfoOutput; | 28 | const DebugInfoOutput = codegen.DebugInfoOutput; |
| 29 | 29 | ||
| ... | @@ -41,11 +41,7 @@ const c_abi_int_param_regs = abi.c_abi_int_param_regs; | ... | @@ -41,11 +41,7 @@ const c_abi_int_param_regs = abi.c_abi_int_param_regs; |
| 41 | const c_abi_int_return_regs = abi.c_abi_int_return_regs; | 41 | const c_abi_int_return_regs = abi.c_abi_int_return_regs; |
| 42 | const gp = abi.RegisterClass.gp; | 42 | const gp = abi.RegisterClass.gp; |
| 43 | 43 | ||
| 44 | const InnerError = error{ | 44 | const InnerError = CodeGenError || error{OutOfRegisters}; |
| 45 | OutOfMemory, | ||
| 46 | CodegenFail, | ||
| 47 | OutOfRegisters, | ||
| 48 | }; | ||
| 49 | 45 | ||
| 50 | gpa: Allocator, | 46 | gpa: Allocator, |
| 51 | air: Air, | 47 | air: Air, |
| ... | @@ -337,7 +333,7 @@ pub fn generate( | ... | @@ -337,7 +333,7 @@ pub fn generate( |
| 337 | liveness: Liveness, | 333 | liveness: Liveness, |
| 338 | code: *std.ArrayList(u8), | 334 | code: *std.ArrayList(u8), |
| 339 | debug_output: DebugInfoOutput, | 335 | debug_output: DebugInfoOutput, |
| 340 | ) GenerateSymbolError!Result { | 336 | ) CodeGenError!Result { |
| 341 | if (build_options.skip_non_native and builtin.cpu.arch != bin_file.options.target.cpu.arch) { | 337 | if (build_options.skip_non_native and builtin.cpu.arch != bin_file.options.target.cpu.arch) { |
| 342 | @panic("Attempted to compile for architecture that was disabled by build configuration"); | 338 | @panic("Attempted to compile for architecture that was disabled by build configuration"); |
| 343 | } | 339 | } |
| ... | @@ -6137,201 +6133,26 @@ fn getResolvedInstValue(self: *Self, inst: Air.Inst.Index) MCValue { | ... | @@ -6137,201 +6133,26 @@ fn getResolvedInstValue(self: *Self, inst: Air.Inst.Index) MCValue { |
| 6137 | } | 6133 | } |
| 6138 | } | 6134 | } |
| 6139 | 6135 | ||
| 6140 | fn lowerDeclRef(self: *Self, tv: TypedValue, decl_index: Module.Decl.Index) InnerError!MCValue { | ||
| 6141 | const ptr_bits = self.target.cpu.arch.ptrBitWidth(); | ||
| 6142 | const ptr_bytes: u64 = @divExact(ptr_bits, 8); | ||
| 6143 | |||
| 6144 | // TODO this feels clunky. Perhaps we should check for it in `genTypedValue`? | ||
| 6145 | if (tv.ty.zigTypeTag() == .Pointer) blk: { | ||
| 6146 | if (tv.ty.castPtrToFn()) |_| break :blk; | ||
| 6147 | if (!tv.ty.elemType2().hasRuntimeBits()) { | ||
| 6148 | return MCValue.none; | ||
| 6149 | } | ||
| 6150 | } | ||
| 6151 | |||
| 6152 | const mod = self.bin_file.options.module.?; | ||
| 6153 | const decl = mod.declPtr(decl_index); | ||
| 6154 | mod.markDeclAlive(decl); | ||
| 6155 | |||
| 6156 | if (self.bin_file.cast(link.File.Elf)) |elf_file| { | ||
| 6157 | const atom_index = try elf_file.getOrCreateAtomForDecl(decl_index); | ||
| 6158 | const atom = elf_file.getAtom(atom_index); | ||
| 6159 | return MCValue{ .memory = atom.getOffsetTableAddress(elf_file) }; | ||
| 6160 | } else if (self.bin_file.cast(link.File.MachO)) |macho_file| { | ||
| 6161 | const atom = try macho_file.getOrCreateAtomForDecl(decl_index); | ||
| 6162 | const sym_index = macho_file.getAtom(atom).getSymbolIndex().?; | ||
| 6163 | return MCValue{ .linker_load = .{ | ||
| 6164 | .type = .got, | ||
| 6165 | .sym_index = sym_index, | ||
| 6166 | } }; | ||
| 6167 | } else if (self.bin_file.cast(link.File.Coff)) |coff_file| { | ||
| 6168 | const atom_index = try coff_file.getOrCreateAtomForDecl(decl_index); | ||
| 6169 | const sym_index = coff_file.getAtom(atom_index).getSymbolIndex().?; | ||
| 6170 | return MCValue{ .linker_load = .{ | ||
| 6171 | .type = .got, | ||
| 6172 | .sym_index = sym_index, | ||
| 6173 | } }; | ||
| 6174 | } else if (self.bin_file.cast(link.File.Plan9)) |p9| { | ||
| 6175 | const decl_block_index = try p9.seeDecl(decl_index); | ||
| 6176 | const decl_block = p9.getDeclBlock(decl_block_index); | ||
| 6177 | const got_addr = p9.bases.data + decl_block.got_index.? * ptr_bytes; | ||
| 6178 | return MCValue{ .memory = got_addr }; | ||
| 6179 | } else { | ||
| 6180 | return self.fail("TODO codegen non-ELF const Decl pointer", .{}); | ||
| 6181 | } | ||
| 6182 | } | ||
| 6183 | |||
| 6184 | fn lowerUnnamedConst(self: *Self, tv: TypedValue) InnerError!MCValue { | ||
| 6185 | log.debug("lowerUnnamedConst: ty = {}, val = {}", .{ tv.ty.fmtDebug(), tv.val.fmtDebug() }); | ||
| 6186 | const local_sym_index = self.bin_file.lowerUnnamedConst(tv, self.mod_fn.owner_decl) catch |err| { | ||
| 6187 | return self.fail("lowering unnamed constant failed: {s}", .{@errorName(err)}); | ||
| 6188 | }; | ||
| 6189 | if (self.bin_file.cast(link.File.Elf)) |elf_file| { | ||
| 6190 | return MCValue{ .memory = elf_file.getSymbol(local_sym_index).st_value }; | ||
| 6191 | } else if (self.bin_file.cast(link.File.MachO)) |_| { | ||
| 6192 | return MCValue{ .linker_load = .{ | ||
| 6193 | .type = .direct, | ||
| 6194 | .sym_index = local_sym_index, | ||
| 6195 | } }; | ||
| 6196 | } else if (self.bin_file.cast(link.File.Coff)) |_| { | ||
| 6197 | return MCValue{ .linker_load = .{ | ||
| 6198 | .type = .direct, | ||
| 6199 | .sym_index = local_sym_index, | ||
| 6200 | } }; | ||
| 6201 | } else if (self.bin_file.cast(link.File.Plan9)) |_| { | ||
| 6202 | return self.fail("TODO lower unnamed const in Plan9", .{}); | ||
| 6203 | } else { | ||
| 6204 | return self.fail("TODO lower unnamed const", .{}); | ||
| 6205 | } | ||
| 6206 | } | ||
| 6207 | |||
| 6208 | fn genTypedValue(self: *Self, arg_tv: TypedValue) InnerError!MCValue { | 6136 | fn genTypedValue(self: *Self, arg_tv: TypedValue) InnerError!MCValue { |
| 6209 | var typed_value = arg_tv; | 6137 | const mcv: MCValue = switch (try codegen.genTypedValue( |
| 6210 | if (typed_value.val.castTag(.runtime_value)) |rt| { | 6138 | self.bin_file, |
| 6211 | typed_value.val = rt.data; | 6139 | self.src_loc, |
| 6212 | } | 6140 | arg_tv, |
| 6213 | log.debug("genTypedValue: ty = {}, val = {}", .{ typed_value.ty.fmtDebug(), typed_value.val.fmtDebug() }); | 6141 | self.mod_fn.owner_decl, |
| 6214 | if (typed_value.val.isUndef()) | 6142 | )) { |
| 6215 | return MCValue{ .undef = {} }; | 6143 | .mcv => |mcv| switch (mcv) { |
| 6216 | 6144 | .none => .none, | |
| 6217 | if (typed_value.val.castTag(.decl_ref)) |payload| { | 6145 | .undef => .undef, |
| 6218 | return self.lowerDeclRef(typed_value, payload.data); | 6146 | .linker_load => |ll| .{ .linker_load = ll }, |
| 6219 | } | 6147 | .immediate => |imm| .{ .immediate = imm }, |
| 6220 | if (typed_value.val.castTag(.decl_ref_mut)) |payload| { | 6148 | .memory => |addr| .{ .memory = addr }, |
| 6221 | return self.lowerDeclRef(typed_value, payload.data.decl_index); | ||
| 6222 | } | ||
| 6223 | const target = self.target.*; | ||
| 6224 | |||
| 6225 | switch (typed_value.ty.zigTypeTag()) { | ||
| 6226 | .Pointer => switch (typed_value.ty.ptrSize()) { | ||
| 6227 | .Slice => {}, | ||
| 6228 | else => { | ||
| 6229 | switch (typed_value.val.tag()) { | ||
| 6230 | .int_u64 => { | ||
| 6231 | return MCValue{ .immediate = typed_value.val.toUnsignedInt(target) }; | ||
| 6232 | }, | ||
| 6233 | else => {}, | ||
| 6234 | } | ||
| 6235 | }, | ||
| 6236 | }, | ||
| 6237 | .Int => { | ||
| 6238 | const info = typed_value.ty.intInfo(self.target.*); | ||
| 6239 | if (info.bits <= 64) { | ||
| 6240 | const unsigned = switch (info.signedness) { | ||
| 6241 | .signed => blk: { | ||
| 6242 | const signed = typed_value.val.toSignedInt(target); | ||
| 6243 | break :blk @bitCast(u64, signed); | ||
| 6244 | }, | ||
| 6245 | .unsigned => typed_value.val.toUnsignedInt(target), | ||
| 6246 | }; | ||
| 6247 | |||
| 6248 | return MCValue{ .immediate = unsigned }; | ||
| 6249 | } | ||
| 6250 | }, | ||
| 6251 | .Bool => { | ||
| 6252 | return MCValue{ .immediate = @boolToInt(typed_value.val.toBool()) }; | ||
| 6253 | }, | 6149 | }, |
| 6254 | .Optional => { | 6150 | .fail => |msg| { |
| 6255 | if (typed_value.ty.isPtrLikeOptional()) { | 6151 | self.err_msg = msg; |
| 6256 | if (typed_value.val.isNull()) | 6152 | return error.CodegenFail; |
| 6257 | return MCValue{ .immediate = 0 }; | ||
| 6258 | |||
| 6259 | var buf: Type.Payload.ElemType = undefined; | ||
| 6260 | return self.genTypedValue(.{ | ||
| 6261 | .ty = typed_value.ty.optionalChild(&buf), | ||
| 6262 | .val = typed_value.val, | ||
| 6263 | }); | ||
| 6264 | } else if (typed_value.ty.abiSize(self.target.*) == 1) { | ||
| 6265 | return MCValue{ .immediate = @boolToInt(typed_value.val.isNull()) }; | ||
| 6266 | } | ||
| 6267 | }, | ||
| 6268 | .Enum => { | ||
| 6269 | if (typed_value.val.castTag(.enum_field_index)) |field_index| { | ||
| 6270 | switch (typed_value.ty.tag()) { | ||
| 6271 | .enum_simple => { | ||
| 6272 | return MCValue{ .immediate = field_index.data }; | ||
| 6273 | }, | ||
| 6274 | .enum_full, .enum_nonexhaustive => { | ||
| 6275 | const enum_full = typed_value.ty.cast(Type.Payload.EnumFull).?.data; | ||
| 6276 | if (enum_full.values.count() != 0) { | ||
| 6277 | const tag_val = enum_full.values.keys()[field_index.data]; | ||
| 6278 | return self.genTypedValue(.{ .ty = enum_full.tag_ty, .val = tag_val }); | ||
| 6279 | } else { | ||
| 6280 | return MCValue{ .immediate = field_index.data }; | ||
| 6281 | } | ||
| 6282 | }, | ||
| 6283 | else => unreachable, | ||
| 6284 | } | ||
| 6285 | } else { | ||
| 6286 | var int_tag_buffer: Type.Payload.Bits = undefined; | ||
| 6287 | const int_tag_ty = typed_value.ty.intTagType(&int_tag_buffer); | ||
| 6288 | return self.genTypedValue(.{ .ty = int_tag_ty, .val = typed_value.val }); | ||
| 6289 | } | ||
| 6290 | }, | 6153 | }, |
| 6291 | .ErrorSet => { | 6154 | }; |
| 6292 | switch (typed_value.val.tag()) { | 6155 | return mcv; |
| 6293 | .@"error" => { | ||
| 6294 | const err_name = typed_value.val.castTag(.@"error").?.data.name; | ||
| 6295 | const module = self.bin_file.options.module.?; | ||
| 6296 | const global_error_set = module.global_error_set; | ||
| 6297 | const error_index = global_error_set.get(err_name).?; | ||
| 6298 | return MCValue{ .immediate = error_index }; | ||
| 6299 | }, | ||
| 6300 | else => { | ||
| 6301 | // In this case we are rendering an error union which has a 0 bits payload. | ||
| 6302 | return MCValue{ .immediate = 0 }; | ||
| 6303 | }, | ||
| 6304 | } | ||
| 6305 | }, | ||
| 6306 | .ErrorUnion => { | ||
| 6307 | const error_type = typed_value.ty.errorUnionSet(); | ||
| 6308 | const payload_type = typed_value.ty.errorUnionPayload(); | ||
| 6309 | |||
| 6310 | const is_pl = typed_value.val.errorUnionIsPayload(); | ||
| 6311 | |||
| 6312 | if (!payload_type.hasRuntimeBitsIgnoreComptime()) { | ||
| 6313 | // We use the error type directly as the type. | ||
| 6314 | const err_val = if (!is_pl) typed_value.val else Value.initTag(.zero); | ||
| 6315 | return self.genTypedValue(.{ .ty = error_type, .val = err_val }); | ||
| 6316 | } | ||
| 6317 | |||
| 6318 | return self.lowerUnnamedConst(typed_value); | ||
| 6319 | }, | ||
| 6320 | |||
| 6321 | .ComptimeInt => unreachable, // semantic analysis prevents this | ||
| 6322 | .ComptimeFloat => unreachable, // semantic analysis prevents this | ||
| 6323 | .Type => unreachable, | ||
| 6324 | .EnumLiteral => unreachable, | ||
| 6325 | .Void => unreachable, | ||
| 6326 | .NoReturn => unreachable, | ||
| 6327 | .Undefined => unreachable, | ||
| 6328 | .Null => unreachable, | ||
| 6329 | .Opaque => unreachable, | ||
| 6330 | |||
| 6331 | else => {}, | ||
| 6332 | } | ||
| 6333 | |||
| 6334 | return self.lowerUnnamedConst(typed_value); | ||
| 6335 | } | 6156 | } |
| 6336 | 6157 | ||
| 6337 | const CallMCValues = struct { | 6158 | const CallMCValues = struct { |
src/arch/arm/CodeGen.zig+20-176| ... | @@ -24,7 +24,7 @@ const log = std.log.scoped(.codegen); | ... | @@ -24,7 +24,7 @@ const log = std.log.scoped(.codegen); |
| 24 | const build_options = @import("build_options"); | 24 | const build_options = @import("build_options"); |
| 25 | 25 | ||
| 26 | const Result = codegen.Result; | 26 | const Result = codegen.Result; |
| 27 | const GenerateSymbolError = codegen.GenerateSymbolError; | 27 | const CodeGenError = codegen.CodeGenError; |
| 28 | const DebugInfoOutput = codegen.DebugInfoOutput; | 28 | const DebugInfoOutput = codegen.DebugInfoOutput; |
| 29 | 29 | ||
| 30 | const bits = @import("bits.zig"); | 30 | const bits = @import("bits.zig"); |
| ... | @@ -42,11 +42,7 @@ const c_abi_int_param_regs = abi.c_abi_int_param_regs; | ... | @@ -42,11 +42,7 @@ const c_abi_int_param_regs = abi.c_abi_int_param_regs; |
| 42 | const c_abi_int_return_regs = abi.c_abi_int_return_regs; | 42 | const c_abi_int_return_regs = abi.c_abi_int_return_regs; |
| 43 | const gp = abi.RegisterClass.gp; | 43 | const gp = abi.RegisterClass.gp; |
| 44 | 44 | ||
| 45 | const InnerError = error{ | 45 | const InnerError = CodeGenError || error{OutOfRegisters}; |
| 46 | OutOfMemory, | ||
| 47 | CodegenFail, | ||
| 48 | OutOfRegisters, | ||
| 49 | }; | ||
| 50 | 46 | ||
| 51 | gpa: Allocator, | 47 | gpa: Allocator, |
| 52 | air: Air, | 48 | air: Air, |
| ... | @@ -343,7 +339,7 @@ pub fn generate( | ... | @@ -343,7 +339,7 @@ pub fn generate( |
| 343 | liveness: Liveness, | 339 | liveness: Liveness, |
| 344 | code: *std.ArrayList(u8), | 340 | code: *std.ArrayList(u8), |
| 345 | debug_output: DebugInfoOutput, | 341 | debug_output: DebugInfoOutput, |
| 346 | ) GenerateSymbolError!Result { | 342 | ) CodeGenError!Result { |
| 347 | if (build_options.skip_non_native and builtin.cpu.arch != bin_file.options.target.cpu.arch) { | 343 | if (build_options.skip_non_native and builtin.cpu.arch != bin_file.options.target.cpu.arch) { |
| 348 | @panic("Attempted to compile for architecture that was disabled by build configuration"); | 344 | @panic("Attempted to compile for architecture that was disabled by build configuration"); |
| 349 | } | 345 | } |
| ... | @@ -6087,178 +6083,26 @@ fn getResolvedInstValue(self: *Self, inst: Air.Inst.Index) MCValue { | ... | @@ -6087,178 +6083,26 @@ fn getResolvedInstValue(self: *Self, inst: Air.Inst.Index) MCValue { |
| 6087 | } | 6083 | } |
| 6088 | } | 6084 | } |
| 6089 | 6085 | ||
| 6090 | fn lowerDeclRef(self: *Self, tv: TypedValue, decl_index: Module.Decl.Index) InnerError!MCValue { | ||
| 6091 | const ptr_bits = self.target.cpu.arch.ptrBitWidth(); | ||
| 6092 | const ptr_bytes: u64 = @divExact(ptr_bits, 8); | ||
| 6093 | |||
| 6094 | const mod = self.bin_file.options.module.?; | ||
| 6095 | const decl = mod.declPtr(decl_index); | ||
| 6096 | mod.markDeclAlive(decl); | ||
| 6097 | |||
| 6098 | if (self.bin_file.cast(link.File.Elf)) |elf_file| { | ||
| 6099 | const atom_index = try elf_file.getOrCreateAtomForDecl(decl_index); | ||
| 6100 | const atom = elf_file.getAtom(atom_index); | ||
| 6101 | return MCValue{ .memory = atom.getOffsetTableAddress(elf_file) }; | ||
| 6102 | } else if (self.bin_file.cast(link.File.MachO)) |_| { | ||
| 6103 | unreachable; // unsupported architecture for MachO | ||
| 6104 | } else if (self.bin_file.cast(link.File.Coff)) |_| { | ||
| 6105 | return self.fail("TODO codegen COFF const Decl pointer", .{}); | ||
| 6106 | } else if (self.bin_file.cast(link.File.Plan9)) |p9| { | ||
| 6107 | const decl_block_index = try p9.seeDecl(decl_index); | ||
| 6108 | const decl_block = p9.getDeclBlock(decl_block_index); | ||
| 6109 | const got_addr = p9.bases.data + decl_block.got_index.? * ptr_bytes; | ||
| 6110 | return MCValue{ .memory = got_addr }; | ||
| 6111 | } else { | ||
| 6112 | return self.fail("TODO codegen non-ELF const Decl pointer", .{}); | ||
| 6113 | } | ||
| 6114 | |||
| 6115 | _ = tv; | ||
| 6116 | } | ||
| 6117 | |||
| 6118 | fn lowerUnnamedConst(self: *Self, tv: TypedValue) InnerError!MCValue { | ||
| 6119 | const local_sym_index = self.bin_file.lowerUnnamedConst(tv, self.mod_fn.owner_decl) catch |err| { | ||
| 6120 | return self.fail("lowering unnamed constant failed: {s}", .{@errorName(err)}); | ||
| 6121 | }; | ||
| 6122 | if (self.bin_file.cast(link.File.Elf)) |elf_file| { | ||
| 6123 | return MCValue{ .memory = elf_file.getSymbol(local_sym_index).st_value }; | ||
| 6124 | } else if (self.bin_file.cast(link.File.MachO)) |_| { | ||
| 6125 | unreachable; | ||
| 6126 | } else if (self.bin_file.cast(link.File.Coff)) |_| { | ||
| 6127 | return self.fail("TODO lower unnamed const in COFF", .{}); | ||
| 6128 | } else if (self.bin_file.cast(link.File.Plan9)) |_| { | ||
| 6129 | return self.fail("TODO lower unnamed const in Plan9", .{}); | ||
| 6130 | } else { | ||
| 6131 | return self.fail("TODO lower unnamed const", .{}); | ||
| 6132 | } | ||
| 6133 | } | ||
| 6134 | |||
| 6135 | fn genTypedValue(self: *Self, arg_tv: TypedValue) InnerError!MCValue { | 6086 | fn genTypedValue(self: *Self, arg_tv: TypedValue) InnerError!MCValue { |
| 6136 | var typed_value = arg_tv; | 6087 | const mcv: MCValue = switch (try codegen.genTypedValue( |
| 6137 | if (typed_value.val.castTag(.runtime_value)) |rt| { | 6088 | self.bin_file, |
| 6138 | typed_value.val = rt.data; | 6089 | self.src_loc, |
| 6139 | } | 6090 | arg_tv, |
| 6140 | log.debug("genTypedValue: ty = {}, val = {}", .{ typed_value.ty.fmtDebug(), typed_value.val.fmtDebug() }); | 6091 | self.mod_fn.owner_decl, |
| 6141 | if (typed_value.val.isUndef()) | 6092 | )) { |
| 6142 | return MCValue{ .undef = {} }; | 6093 | .mcv => |mcv| switch (mcv) { |
| 6143 | const ptr_bits = self.target.cpu.arch.ptrBitWidth(); | 6094 | .none => .none, |
| 6144 | 6095 | .undef => .undef, | |
| 6145 | if (typed_value.val.castTag(.decl_ref)) |payload| { | 6096 | .linker_load => unreachable, // TODO |
| 6146 | return self.lowerDeclRef(typed_value, payload.data); | 6097 | .immediate => |imm| .{ .immediate = @truncate(u32, imm) }, |
| 6147 | } | 6098 | .memory => |addr| .{ .memory = addr }, |
| 6148 | if (typed_value.val.castTag(.decl_ref_mut)) |payload| { | ||
| 6149 | return self.lowerDeclRef(typed_value, payload.data.decl_index); | ||
| 6150 | } | ||
| 6151 | const target = self.target.*; | ||
| 6152 | |||
| 6153 | switch (typed_value.ty.zigTypeTag()) { | ||
| 6154 | .Pointer => switch (typed_value.ty.ptrSize()) { | ||
| 6155 | .Slice => {}, | ||
| 6156 | else => { | ||
| 6157 | switch (typed_value.val.tag()) { | ||
| 6158 | .int_u64 => { | ||
| 6159 | return MCValue{ .immediate = @intCast(u32, typed_value.val.toUnsignedInt(target)) }; | ||
| 6160 | }, | ||
| 6161 | else => {}, | ||
| 6162 | } | ||
| 6163 | }, | ||
| 6164 | }, | ||
| 6165 | .Int => { | ||
| 6166 | const info = typed_value.ty.intInfo(self.target.*); | ||
| 6167 | if (info.bits <= ptr_bits) { | ||
| 6168 | const unsigned = switch (info.signedness) { | ||
| 6169 | .signed => blk: { | ||
| 6170 | const signed = @intCast(i32, typed_value.val.toSignedInt(target)); | ||
| 6171 | break :blk @bitCast(u32, signed); | ||
| 6172 | }, | ||
| 6173 | .unsigned => @intCast(u32, typed_value.val.toUnsignedInt(target)), | ||
| 6174 | }; | ||
| 6175 | |||
| 6176 | return MCValue{ .immediate = unsigned }; | ||
| 6177 | } else { | ||
| 6178 | return self.lowerUnnamedConst(typed_value); | ||
| 6179 | } | ||
| 6180 | }, | 6099 | }, |
| 6181 | .Bool => { | 6100 | .fail => |msg| { |
| 6182 | return MCValue{ .immediate = @boolToInt(typed_value.val.toBool()) }; | 6101 | self.err_msg = msg; |
| 6183 | }, | 6102 | return error.CodegenFail; |
| 6184 | .Optional => { | ||
| 6185 | if (typed_value.ty.isPtrLikeOptional()) { | ||
| 6186 | if (typed_value.val.isNull()) | ||
| 6187 | return MCValue{ .immediate = 0 }; | ||
| 6188 | |||
| 6189 | var buf: Type.Payload.ElemType = undefined; | ||
| 6190 | return self.genTypedValue(.{ | ||
| 6191 | .ty = typed_value.ty.optionalChild(&buf), | ||
| 6192 | .val = typed_value.val, | ||
| 6193 | }); | ||
| 6194 | } else if (typed_value.ty.abiSize(self.target.*) == 1) { | ||
| 6195 | return MCValue{ .immediate = @boolToInt(typed_value.val.isNull()) }; | ||
| 6196 | } | ||
| 6197 | }, | 6103 | }, |
| 6198 | .Enum => { | 6104 | }; |
| 6199 | if (typed_value.val.castTag(.enum_field_index)) |field_index| { | 6105 | return mcv; |
| 6200 | switch (typed_value.ty.tag()) { | ||
| 6201 | .enum_simple => { | ||
| 6202 | return MCValue{ .immediate = field_index.data }; | ||
| 6203 | }, | ||
| 6204 | .enum_full, .enum_nonexhaustive => { | ||
| 6205 | const enum_full = typed_value.ty.cast(Type.Payload.EnumFull).?.data; | ||
| 6206 | if (enum_full.values.count() != 0) { | ||
| 6207 | const tag_val = enum_full.values.keys()[field_index.data]; | ||
| 6208 | return self.genTypedValue(.{ .ty = enum_full.tag_ty, .val = tag_val }); | ||
| 6209 | } else { | ||
| 6210 | return MCValue{ .immediate = field_index.data }; | ||
| 6211 | } | ||
| 6212 | }, | ||
| 6213 | else => unreachable, | ||
| 6214 | } | ||
| 6215 | } else { | ||
| 6216 | var int_tag_buffer: Type.Payload.Bits = undefined; | ||
| 6217 | const int_tag_ty = typed_value.ty.intTagType(&int_tag_buffer); | ||
| 6218 | return self.genTypedValue(.{ .ty = int_tag_ty, .val = typed_value.val }); | ||
| 6219 | } | ||
| 6220 | }, | ||
| 6221 | .ErrorSet => { | ||
| 6222 | switch (typed_value.val.tag()) { | ||
| 6223 | .@"error" => { | ||
| 6224 | const err_name = typed_value.val.castTag(.@"error").?.data.name; | ||
| 6225 | const module = self.bin_file.options.module.?; | ||
| 6226 | const global_error_set = module.global_error_set; | ||
| 6227 | const error_index = global_error_set.get(err_name).?; | ||
| 6228 | return MCValue{ .immediate = error_index }; | ||
| 6229 | }, | ||
| 6230 | else => { | ||
| 6231 | // In this case we are rendering an error union which has a 0 bits payload. | ||
| 6232 | return MCValue{ .immediate = 0 }; | ||
| 6233 | }, | ||
| 6234 | } | ||
| 6235 | }, | ||
| 6236 | .ErrorUnion => { | ||
| 6237 | const error_type = typed_value.ty.errorUnionSet(); | ||
| 6238 | const payload_type = typed_value.ty.errorUnionPayload(); | ||
| 6239 | const is_pl = typed_value.val.errorUnionIsPayload(); | ||
| 6240 | |||
| 6241 | if (!payload_type.hasRuntimeBitsIgnoreComptime()) { | ||
| 6242 | // We use the error type directly as the type. | ||
| 6243 | const err_val = if (!is_pl) typed_value.val else Value.initTag(.zero); | ||
| 6244 | return self.genTypedValue(.{ .ty = error_type, .val = err_val }); | ||
| 6245 | } | ||
| 6246 | }, | ||
| 6247 | |||
| 6248 | .ComptimeInt => unreachable, // semantic analysis prevents this | ||
| 6249 | .ComptimeFloat => unreachable, // semantic analysis prevents this | ||
| 6250 | .Type => unreachable, | ||
| 6251 | .EnumLiteral => unreachable, | ||
| 6252 | .Void => unreachable, | ||
| 6253 | .NoReturn => unreachable, | ||
| 6254 | .Undefined => unreachable, | ||
| 6255 | .Null => unreachable, | ||
| 6256 | .Opaque => unreachable, | ||
| 6257 | |||
| 6258 | else => {}, | ||
| 6259 | } | ||
| 6260 | |||
| 6261 | return self.lowerUnnamedConst(typed_value); | ||
| 6262 | } | 6106 | } |
| 6263 | 6107 | ||
| 6264 | const CallMCValues = struct { | 6108 | const CallMCValues = struct { |
src/arch/riscv64/CodeGen.zig+23-145| ... | @@ -21,10 +21,11 @@ const DW = std.dwarf; | ... | @@ -21,10 +21,11 @@ const DW = std.dwarf; |
| 21 | const leb128 = std.leb; | 21 | const leb128 = std.leb; |
| 22 | const log = std.log.scoped(.codegen); | 22 | const log = std.log.scoped(.codegen); |
| 23 | const build_options = @import("build_options"); | 23 | const build_options = @import("build_options"); |
| 24 | const codegen = @import("../../codegen.zig"); | ||
| 24 | 25 | ||
| 25 | const Result = @import("../../codegen.zig").Result; | 26 | const CodeGenError = codegen.CodeGenError; |
| 26 | const GenerateSymbolError = @import("../../codegen.zig").GenerateSymbolError; | 27 | const Result = codegen.Result; |
| 27 | const DebugInfoOutput = @import("../../codegen.zig").DebugInfoOutput; | 28 | const DebugInfoOutput = codegen.DebugInfoOutput; |
| 28 | 29 | ||
| 29 | const bits = @import("bits.zig"); | 30 | const bits = @import("bits.zig"); |
| 30 | const abi = @import("abi.zig"); | 31 | const abi = @import("abi.zig"); |
| ... | @@ -35,11 +36,7 @@ const Instruction = abi.Instruction; | ... | @@ -35,11 +36,7 @@ const Instruction = abi.Instruction; |
| 35 | const callee_preserved_regs = abi.callee_preserved_regs; | 36 | const callee_preserved_regs = abi.callee_preserved_regs; |
| 36 | const gp = abi.RegisterClass.gp; | 37 | const gp = abi.RegisterClass.gp; |
| 37 | 38 | ||
| 38 | const InnerError = error{ | 39 | const InnerError = CodeGenError || error{OutOfRegisters}; |
| 39 | OutOfMemory, | ||
| 40 | CodegenFail, | ||
| 41 | OutOfRegisters, | ||
| 42 | }; | ||
| 43 | 40 | ||
| 44 | gpa: Allocator, | 41 | gpa: Allocator, |
| 45 | air: Air, | 42 | air: Air, |
| ... | @@ -225,7 +222,7 @@ pub fn generate( | ... | @@ -225,7 +222,7 @@ pub fn generate( |
| 225 | liveness: Liveness, | 222 | liveness: Liveness, |
| 226 | code: *std.ArrayList(u8), | 223 | code: *std.ArrayList(u8), |
| 227 | debug_output: DebugInfoOutput, | 224 | debug_output: DebugInfoOutput, |
| 228 | ) GenerateSymbolError!Result { | 225 | ) CodeGenError!Result { |
| 229 | if (build_options.skip_non_native and builtin.cpu.arch != bin_file.options.target.cpu.arch) { | 226 | if (build_options.skip_non_native and builtin.cpu.arch != bin_file.options.target.cpu.arch) { |
| 230 | @panic("Attempted to compile for architecture that was disabled by build configuration"); | 227 | @panic("Attempted to compile for architecture that was disabled by build configuration"); |
| 231 | } | 228 | } |
| ... | @@ -2552,145 +2549,26 @@ fn getResolvedInstValue(self: *Self, inst: Air.Inst.Index) MCValue { | ... | @@ -2552,145 +2549,26 @@ fn getResolvedInstValue(self: *Self, inst: Air.Inst.Index) MCValue { |
| 2552 | } | 2549 | } |
| 2553 | } | 2550 | } |
| 2554 | 2551 | ||
| 2555 | fn lowerDeclRef(self: *Self, tv: TypedValue, decl_index: Module.Decl.Index) InnerError!MCValue { | ||
| 2556 | const ptr_bits = self.target.cpu.arch.ptrBitWidth(); | ||
| 2557 | const ptr_bytes: u64 = @divExact(ptr_bits, 8); | ||
| 2558 | const mod = self.bin_file.options.module.?; | ||
| 2559 | const decl = mod.declPtr(decl_index); | ||
| 2560 | mod.markDeclAlive(decl); | ||
| 2561 | if (self.bin_file.cast(link.File.Elf)) |elf_file| { | ||
| 2562 | const atom_index = try elf_file.getOrCreateAtomForDecl(decl_index); | ||
| 2563 | const atom = elf_file.getAtom(atom_index); | ||
| 2564 | return MCValue{ .memory = atom.getOffsetTableAddress(elf_file) }; | ||
| 2565 | } else if (self.bin_file.cast(link.File.MachO)) |_| { | ||
| 2566 | unreachable; | ||
| 2567 | } else if (self.bin_file.cast(link.File.Coff)) |_| { | ||
| 2568 | return self.fail("TODO codegen COFF const Decl pointer", .{}); | ||
| 2569 | } else if (self.bin_file.cast(link.File.Plan9)) |p9| { | ||
| 2570 | const decl_block_index = try p9.seeDecl(decl_index); | ||
| 2571 | const decl_block = p9.getDeclBlock(decl_block_index); | ||
| 2572 | const got_addr = p9.bases.data + decl_block.got_index.? * ptr_bytes; | ||
| 2573 | return MCValue{ .memory = got_addr }; | ||
| 2574 | } else { | ||
| 2575 | return self.fail("TODO codegen non-ELF const Decl pointer", .{}); | ||
| 2576 | } | ||
| 2577 | _ = tv; | ||
| 2578 | } | ||
| 2579 | |||
| 2580 | fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue { | 2552 | fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue { |
| 2581 | if (typed_value.val.isUndef()) | 2553 | const mcv: MCValue = switch (try codegen.genTypedValue( |
| 2582 | return MCValue{ .undef = {} }; | 2554 | self.bin_file, |
| 2583 | 2555 | self.src_loc, | |
| 2584 | if (typed_value.val.castTag(.decl_ref)) |payload| { | 2556 | typed_value, |
| 2585 | return self.lowerDeclRef(typed_value, payload.data); | 2557 | self.mod_fn.owner_decl, |
| 2586 | } | 2558 | )) { |
| 2587 | if (typed_value.val.castTag(.decl_ref_mut)) |payload| { | 2559 | .mcv => |mcv| switch (mcv) { |
| 2588 | return self.lowerDeclRef(typed_value, payload.data.decl_index); | 2560 | .none => .none, |
| 2589 | } | 2561 | .undef => .undef, |
| 2590 | const target = self.target.*; | 2562 | .linker_load => unreachable, // TODO |
| 2591 | const ptr_bits = self.target.cpu.arch.ptrBitWidth(); | 2563 | .immediate => |imm| .{ .immediate = imm }, |
| 2592 | switch (typed_value.ty.zigTypeTag()) { | 2564 | .memory => |addr| .{ .memory = addr }, |
| 2593 | .Pointer => switch (typed_value.ty.ptrSize()) { | ||
| 2594 | .Slice => { | ||
| 2595 | var buf: Type.SlicePtrFieldTypeBuffer = undefined; | ||
| 2596 | const ptr_type = typed_value.ty.slicePtrFieldType(&buf); | ||
| 2597 | const ptr_mcv = try self.genTypedValue(.{ .ty = ptr_type, .val = typed_value.val }); | ||
| 2598 | const mod = self.bin_file.options.module.?; | ||
| 2599 | const slice_len = typed_value.val.sliceLen(mod); | ||
| 2600 | // Codegen can't handle some kinds of indirection. If the wrong union field is accessed here it may mean | ||
| 2601 | // the Sema code needs to use anonymous Decls or alloca instructions to store data. | ||
| 2602 | const ptr_imm = ptr_mcv.memory; | ||
| 2603 | _ = slice_len; | ||
| 2604 | _ = ptr_imm; | ||
| 2605 | // We need more general support for const data being stored in memory to make this work. | ||
| 2606 | return self.fail("TODO codegen for const slices", .{}); | ||
| 2607 | }, | ||
| 2608 | else => { | ||
| 2609 | if (typed_value.val.tag() == .int_u64) { | ||
| 2610 | return MCValue{ .immediate = typed_value.val.toUnsignedInt(target) }; | ||
| 2611 | } | ||
| 2612 | return self.fail("TODO codegen more kinds of const pointers", .{}); | ||
| 2613 | }, | ||
| 2614 | }, | ||
| 2615 | .Int => { | ||
| 2616 | const info = typed_value.ty.intInfo(self.target.*); | ||
| 2617 | if (info.bits > ptr_bits or info.signedness == .signed) { | ||
| 2618 | return self.fail("TODO const int bigger than ptr and signed int", .{}); | ||
| 2619 | } | ||
| 2620 | return MCValue{ .immediate = typed_value.val.toUnsignedInt(target) }; | ||
| 2621 | }, | 2565 | }, |
| 2622 | .Bool => { | 2566 | .fail => |msg| { |
| 2623 | return MCValue{ .immediate = @boolToInt(typed_value.val.toBool()) }; | 2567 | self.err_msg = msg; |
| 2568 | return error.CodegenFail; | ||
| 2624 | }, | 2569 | }, |
| 2625 | .ComptimeInt => unreachable, // semantic analysis prevents this | 2570 | }; |
| 2626 | .ComptimeFloat => unreachable, // semantic analysis prevents this | 2571 | return mcv; |
| 2627 | .Optional => { | ||
| 2628 | if (typed_value.ty.isPtrLikeOptional()) { | ||
| 2629 | if (typed_value.val.isNull()) | ||
| 2630 | return MCValue{ .immediate = 0 }; | ||
| 2631 | |||
| 2632 | var buf: Type.Payload.ElemType = undefined; | ||
| 2633 | return self.genTypedValue(.{ | ||
| 2634 | .ty = typed_value.ty.optionalChild(&buf), | ||
| 2635 | .val = typed_value.val, | ||
| 2636 | }); | ||
| 2637 | } else if (typed_value.ty.abiSize(self.target.*) == 1) { | ||
| 2638 | return MCValue{ .immediate = @boolToInt(typed_value.val.isNull()) }; | ||
| 2639 | } | ||
| 2640 | return self.fail("TODO non pointer optionals", .{}); | ||
| 2641 | }, | ||
| 2642 | .Enum => { | ||
| 2643 | if (typed_value.val.castTag(.enum_field_index)) |field_index| { | ||
| 2644 | switch (typed_value.ty.tag()) { | ||
| 2645 | .enum_simple => { | ||
| 2646 | return MCValue{ .immediate = field_index.data }; | ||
| 2647 | }, | ||
| 2648 | .enum_full, .enum_nonexhaustive => { | ||
| 2649 | const enum_full = typed_value.ty.cast(Type.Payload.EnumFull).?.data; | ||
| 2650 | if (enum_full.values.count() != 0) { | ||
| 2651 | const tag_val = enum_full.values.keys()[field_index.data]; | ||
| 2652 | return self.genTypedValue(.{ .ty = enum_full.tag_ty, .val = tag_val }); | ||
| 2653 | } else { | ||
| 2654 | return MCValue{ .immediate = field_index.data }; | ||
| 2655 | } | ||
| 2656 | }, | ||
| 2657 | else => unreachable, | ||
| 2658 | } | ||
| 2659 | } else { | ||
| 2660 | var int_tag_buffer: Type.Payload.Bits = undefined; | ||
| 2661 | const int_tag_ty = typed_value.ty.intTagType(&int_tag_buffer); | ||
| 2662 | return self.genTypedValue(.{ .ty = int_tag_ty, .val = typed_value.val }); | ||
| 2663 | } | ||
| 2664 | }, | ||
| 2665 | .ErrorSet => { | ||
| 2666 | switch (typed_value.val.tag()) { | ||
| 2667 | .@"error" => { | ||
| 2668 | const err_name = typed_value.val.castTag(.@"error").?.data.name; | ||
| 2669 | const module = self.bin_file.options.module.?; | ||
| 2670 | const global_error_set = module.global_error_set; | ||
| 2671 | const error_index = global_error_set.get(err_name).?; | ||
| 2672 | return MCValue{ .immediate = error_index }; | ||
| 2673 | }, | ||
| 2674 | else => { | ||
| 2675 | // In this case we are rendering an error union which has a 0 bits payload. | ||
| 2676 | return MCValue{ .immediate = 0 }; | ||
| 2677 | }, | ||
| 2678 | } | ||
| 2679 | }, | ||
| 2680 | .ErrorUnion => { | ||
| 2681 | const error_type = typed_value.ty.errorUnionSet(); | ||
| 2682 | const payload_type = typed_value.ty.errorUnionPayload(); | ||
| 2683 | const sub_val = typed_value.val.castTag(.eu_payload).?.data; | ||
| 2684 | |||
| 2685 | if (!payload_type.hasRuntimeBits()) { | ||
| 2686 | // We use the error type directly as the type. | ||
| 2687 | return self.genTypedValue(.{ .ty = error_type, .val = sub_val }); | ||
| 2688 | } | ||
| 2689 | |||
| 2690 | return self.fail("TODO implement error union const of type '{}'", .{typed_value.ty.fmtDebug()}); | ||
| 2691 | }, | ||
| 2692 | else => return self.fail("TODO implement const of type '{}'", .{typed_value.ty.fmtDebug()}), | ||
| 2693 | } | ||
| 2694 | } | 2572 | } |
| 2695 | 2573 | ||
| 2696 | const CallMCValues = struct { | 2574 | const CallMCValues = struct { |
src/arch/sparc64/CodeGen.zig+20-154| ... | @@ -19,7 +19,7 @@ const Mir = @import("Mir.zig"); | ... | @@ -19,7 +19,7 @@ const Mir = @import("Mir.zig"); |
| 19 | const Emit = @import("Emit.zig"); | 19 | const Emit = @import("Emit.zig"); |
| 20 | const Liveness = @import("../../Liveness.zig"); | 20 | const Liveness = @import("../../Liveness.zig"); |
| 21 | const Type = @import("../../type.zig").Type; | 21 | const Type = @import("../../type.zig").Type; |
| 22 | const GenerateSymbolError = @import("../../codegen.zig").GenerateSymbolError; | 22 | const CodeGenError = codegen.CodeGenError; |
| 23 | const Result = @import("../../codegen.zig").Result; | 23 | const Result = @import("../../codegen.zig").Result; |
| 24 | const DebugInfoOutput = @import("../../codegen.zig").DebugInfoOutput; | 24 | const DebugInfoOutput = @import("../../codegen.zig").DebugInfoOutput; |
| 25 | 25 | ||
| ... | @@ -38,11 +38,7 @@ const gp = abi.RegisterClass.gp; | ... | @@ -38,11 +38,7 @@ const gp = abi.RegisterClass.gp; |
| 38 | 38 | ||
| 39 | const Self = @This(); | 39 | const Self = @This(); |
| 40 | 40 | ||
| 41 | const InnerError = error{ | 41 | const InnerError = CodeGenError || error{OutOfRegisters}; |
| 42 | OutOfMemory, | ||
| 43 | CodegenFail, | ||
| 44 | OutOfRegisters, | ||
| 45 | }; | ||
| 46 | 42 | ||
| 47 | const RegisterView = enum(u1) { | 43 | const RegisterView = enum(u1) { |
| 48 | caller, | 44 | caller, |
| ... | @@ -265,7 +261,7 @@ pub fn generate( | ... | @@ -265,7 +261,7 @@ pub fn generate( |
| 265 | liveness: Liveness, | 261 | liveness: Liveness, |
| 266 | code: *std.ArrayList(u8), | 262 | code: *std.ArrayList(u8), |
| 267 | debug_output: DebugInfoOutput, | 263 | debug_output: DebugInfoOutput, |
| 268 | ) GenerateSymbolError!Result { | 264 | ) CodeGenError!Result { |
| 269 | if (build_options.skip_non_native and builtin.cpu.arch != bin_file.options.target.cpu.arch) { | 265 | if (build_options.skip_non_native and builtin.cpu.arch != bin_file.options.target.cpu.arch) { |
| 270 | @panic("Attempted to compile for architecture that was disabled by build configuration"); | 266 | @panic("Attempted to compile for architecture that was disabled by build configuration"); |
| 271 | } | 267 | } |
| ... | @@ -3898,133 +3894,25 @@ fn genStore(self: *Self, value_reg: Register, addr_reg: Register, comptime off_t | ... | @@ -3898,133 +3894,25 @@ fn genStore(self: *Self, value_reg: Register, addr_reg: Register, comptime off_t |
| 3898 | } | 3894 | } |
| 3899 | 3895 | ||
| 3900 | fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue { | 3896 | fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue { |
| 3901 | var tv = typed_value; | 3897 | const mcv: MCValue = switch (try codegen.genTypedValue( |
| 3902 | log.debug("genTypedValue: ty = {}, val = {}", .{ tv.ty.fmtDebug(), tv.val.fmtDebug() }); | 3898 | self.bin_file, |
| 3903 | 3899 | self.src_loc, | |
| 3904 | if (tv.val.castTag(.runtime_value)) |rt| { | 3900 | typed_value, |
| 3905 | tv.val = rt.data; | 3901 | self.mod_fn.owner_decl, |
| 3906 | } | 3902 | )) { |
| 3907 | 3903 | .mcv => |mcv| switch (mcv) { | |
| 3908 | if (tv.val.isUndef()) | 3904 | .none => .none, |
| 3909 | return MCValue{ .undef = {} }; | 3905 | .undef => .undef, |
| 3910 | 3906 | .linker_load => unreachable, // TODO | |
| 3911 | if (tv.val.castTag(.decl_ref)) |payload| { | 3907 | .immediate => |imm| .{ .immediate = imm }, |
| 3912 | return self.lowerDeclRef(tv, payload.data); | 3908 | .memory => |addr| .{ .memory = addr }, |
| 3913 | } | ||
| 3914 | if (tv.val.castTag(.decl_ref_mut)) |payload| { | ||
| 3915 | return self.lowerDeclRef(tv, payload.data.decl_index); | ||
| 3916 | } | ||
| 3917 | const target = self.target.*; | ||
| 3918 | |||
| 3919 | switch (tv.ty.zigTypeTag()) { | ||
| 3920 | .Pointer => switch (tv.ty.ptrSize()) { | ||
| 3921 | .Slice => {}, | ||
| 3922 | else => { | ||
| 3923 | switch (tv.val.tag()) { | ||
| 3924 | .int_u64 => { | ||
| 3925 | return MCValue{ .immediate = tv.val.toUnsignedInt(target) }; | ||
| 3926 | }, | ||
| 3927 | else => {}, | ||
| 3928 | } | ||
| 3929 | }, | ||
| 3930 | }, | ||
| 3931 | .Bool => { | ||
| 3932 | return MCValue{ .immediate = @boolToInt(tv.val.toBool()) }; | ||
| 3933 | }, | ||
| 3934 | .Int => { | ||
| 3935 | const info = tv.ty.intInfo(self.target.*); | ||
| 3936 | if (info.bits <= 64) { | ||
| 3937 | const unsigned = switch (info.signedness) { | ||
| 3938 | .signed => blk: { | ||
| 3939 | const signed = tv.val.toSignedInt(target); | ||
| 3940 | break :blk @bitCast(u64, signed); | ||
| 3941 | }, | ||
| 3942 | .unsigned => tv.val.toUnsignedInt(target), | ||
| 3943 | }; | ||
| 3944 | |||
| 3945 | return MCValue{ .immediate = unsigned }; | ||
| 3946 | } else { | ||
| 3947 | return self.fail("TODO implement int genTypedValue of > 64 bits", .{}); | ||
| 3948 | } | ||
| 3949 | }, | ||
| 3950 | .Optional => { | ||
| 3951 | if (tv.ty.isPtrLikeOptional()) { | ||
| 3952 | if (tv.val.isNull()) | ||
| 3953 | return MCValue{ .immediate = 0 }; | ||
| 3954 | |||
| 3955 | var buf: Type.Payload.ElemType = undefined; | ||
| 3956 | return self.genTypedValue(.{ | ||
| 3957 | .ty = tv.ty.optionalChild(&buf), | ||
| 3958 | .val = tv.val, | ||
| 3959 | }); | ||
| 3960 | } else if (tv.ty.abiSize(self.target.*) == 1) { | ||
| 3961 | return MCValue{ .immediate = @boolToInt(tv.val.isNull()) }; | ||
| 3962 | } | ||
| 3963 | }, | ||
| 3964 | .Enum => { | ||
| 3965 | if (tv.val.castTag(.enum_field_index)) |field_index| { | ||
| 3966 | switch (tv.ty.tag()) { | ||
| 3967 | .enum_simple => { | ||
| 3968 | return MCValue{ .immediate = field_index.data }; | ||
| 3969 | }, | ||
| 3970 | .enum_full, .enum_nonexhaustive => { | ||
| 3971 | const enum_full = tv.ty.cast(Type.Payload.EnumFull).?.data; | ||
| 3972 | if (enum_full.values.count() != 0) { | ||
| 3973 | const tag_val = enum_full.values.keys()[field_index.data]; | ||
| 3974 | return self.genTypedValue(.{ .ty = enum_full.tag_ty, .val = tag_val }); | ||
| 3975 | } else { | ||
| 3976 | return MCValue{ .immediate = field_index.data }; | ||
| 3977 | } | ||
| 3978 | }, | ||
| 3979 | else => unreachable, | ||
| 3980 | } | ||
| 3981 | } else { | ||
| 3982 | var int_tag_buffer: Type.Payload.Bits = undefined; | ||
| 3983 | const int_tag_ty = tv.ty.intTagType(&int_tag_buffer); | ||
| 3984 | return self.genTypedValue(.{ .ty = int_tag_ty, .val = tv.val }); | ||
| 3985 | } | ||
| 3986 | }, | ||
| 3987 | .ErrorSet => { | ||
| 3988 | const err_name = tv.val.castTag(.@"error").?.data.name; | ||
| 3989 | const module = self.bin_file.options.module.?; | ||
| 3990 | const global_error_set = module.global_error_set; | ||
| 3991 | const error_index = global_error_set.get(err_name).?; | ||
| 3992 | return MCValue{ .immediate = error_index }; | ||
| 3993 | }, | 3909 | }, |
| 3994 | .ErrorUnion => { | 3910 | .fail => |msg| { |
| 3995 | const error_type = tv.ty.errorUnionSet(); | 3911 | self.err_msg = msg; |
| 3996 | const payload_type = tv.ty.errorUnionPayload(); | 3912 | return error.CodegenFail; |
| 3997 | |||
| 3998 | if (tv.val.castTag(.eu_payload)) |pl| { | ||
| 3999 | if (!payload_type.hasRuntimeBits()) { | ||
| 4000 | // We use the error type directly as the type. | ||
| 4001 | return MCValue{ .immediate = 0 }; | ||
| 4002 | } | ||
| 4003 | |||
| 4004 | _ = pl; | ||
| 4005 | return self.fail("TODO implement error union const of type '{}' (non-error)", .{tv.ty.fmtDebug()}); | ||
| 4006 | } else { | ||
| 4007 | if (!payload_type.hasRuntimeBits()) { | ||
| 4008 | // We use the error type directly as the type. | ||
| 4009 | return self.genTypedValue(.{ .ty = error_type, .val = tv.val }); | ||
| 4010 | } | ||
| 4011 | |||
| 4012 | return self.fail("TODO implement error union const of type '{}' (error)", .{tv.ty.fmtDebug()}); | ||
| 4013 | } | ||
| 4014 | }, | 3913 | }, |
| 4015 | .ComptimeInt => unreachable, // semantic analysis prevents this | 3914 | }; |
| 4016 | .ComptimeFloat => unreachable, // semantic analysis prevents this | 3915 | return mcv; |
| 4017 | .Type => unreachable, | ||
| 4018 | .EnumLiteral => unreachable, | ||
| 4019 | .Void => unreachable, | ||
| 4020 | .NoReturn => unreachable, | ||
| 4021 | .Undefined => unreachable, | ||
| 4022 | .Null => unreachable, | ||
| 4023 | .Opaque => unreachable, | ||
| 4024 | else => {}, | ||
| 4025 | } | ||
| 4026 | |||
| 4027 | return self.fail("TODO implement const of type '{}'", .{tv.ty.fmtDebug()}); | ||
| 4028 | } | 3916 | } |
| 4029 | 3917 | ||
| 4030 | fn getResolvedInstValue(self: *Self, inst: Air.Inst.Index) MCValue { | 3918 | fn getResolvedInstValue(self: *Self, inst: Air.Inst.Index) MCValue { |
| ... | @@ -4200,28 +4088,6 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo | ... | @@ -4200,28 +4088,6 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo |
| 4200 | } | 4088 | } |
| 4201 | } | 4089 | } |
| 4202 | 4090 | ||
| 4203 | fn lowerDeclRef(self: *Self, tv: TypedValue, decl_index: Module.Decl.Index) InnerError!MCValue { | ||
| 4204 | // TODO this feels clunky. Perhaps we should check for it in `genTypedValue`? | ||
| 4205 | if (tv.ty.zigTypeTag() == .Pointer) blk: { | ||
| 4206 | if (tv.ty.castPtrToFn()) |_| break :blk; | ||
| 4207 | if (!tv.ty.elemType2().hasRuntimeBits()) { | ||
| 4208 | return MCValue.none; | ||
| 4209 | } | ||
| 4210 | } | ||
| 4211 | |||
| 4212 | const mod = self.bin_file.options.module.?; | ||
| 4213 | const decl = mod.declPtr(decl_index); | ||
| 4214 | |||
| 4215 | mod.markDeclAlive(decl); | ||
| 4216 | if (self.bin_file.cast(link.File.Elf)) |elf_file| { | ||
| 4217 | const atom_index = try elf_file.getOrCreateAtomForDecl(decl_index); | ||
| 4218 | const atom = elf_file.getAtom(atom_index); | ||
| 4219 | return MCValue{ .memory = atom.getOffsetTableAddress(elf_file) }; | ||
| 4220 | } else { | ||
| 4221 | return self.fail("TODO codegen non-ELF const Decl pointer", .{}); | ||
| 4222 | } | ||
| 4223 | } | ||
| 4224 | |||
| 4225 | fn minMax( | 4091 | fn minMax( |
| 4226 | self: *Self, | 4092 | self: *Self, |
| 4227 | tag: Air.Inst.Tag, | 4093 | tag: Air.Inst.Tag, |
src/arch/wasm/CodeGen.zig+1-3| ... | @@ -733,8 +733,6 @@ const InnerError = error{ | ... | @@ -733,8 +733,6 @@ const InnerError = error{ |
| 733 | OutOfMemory, | 733 | OutOfMemory, |
| 734 | /// An error occurred when trying to lower AIR to MIR. | 734 | /// An error occurred when trying to lower AIR to MIR. |
| 735 | CodegenFail, | 735 | CodegenFail, |
| 736 | /// Can occur when dereferencing a pointer that points to a `Decl` of which the analysis has failed | ||
| 737 | AnalysisFail, | ||
| 738 | /// Compiler implementation could not handle a large integer. | 736 | /// Compiler implementation could not handle a large integer. |
| 739 | Overflow, | 737 | Overflow, |
| 740 | }; | 738 | }; |
| ... | @@ -1164,7 +1162,7 @@ pub fn generate( | ... | @@ -1164,7 +1162,7 @@ pub fn generate( |
| 1164 | liveness: Liveness, | 1162 | liveness: Liveness, |
| 1165 | code: *std.ArrayList(u8), | 1163 | code: *std.ArrayList(u8), |
| 1166 | debug_output: codegen.DebugInfoOutput, | 1164 | debug_output: codegen.DebugInfoOutput, |
| 1167 | ) codegen.GenerateSymbolError!codegen.Result { | 1165 | ) codegen.CodeGenError!codegen.Result { |
| 1168 | _ = src_loc; | 1166 | _ = src_loc; |
| 1169 | var code_gen: CodeGen = .{ | 1167 | var code_gen: CodeGen = .{ |
| 1170 | .gpa = bin_file.allocator, | 1168 | .gpa = bin_file.allocator, |
src/arch/x86_64/CodeGen.zig+21-199| ... | @@ -12,12 +12,12 @@ const trace = @import("../../tracy.zig").trace; | ... | @@ -12,12 +12,12 @@ const trace = @import("../../tracy.zig").trace; |
| 12 | 12 | ||
| 13 | const Air = @import("../../Air.zig"); | 13 | const Air = @import("../../Air.zig"); |
| 14 | const Allocator = mem.Allocator; | 14 | const Allocator = mem.Allocator; |
| 15 | const CodeGenError = codegen.CodeGenError; | ||
| 15 | const Compilation = @import("../../Compilation.zig"); | 16 | const Compilation = @import("../../Compilation.zig"); |
| 16 | const DebugInfoOutput = codegen.DebugInfoOutput; | 17 | const DebugInfoOutput = codegen.DebugInfoOutput; |
| 17 | const DW = std.dwarf; | 18 | const DW = std.dwarf; |
| 18 | const ErrorMsg = Module.ErrorMsg; | 19 | const ErrorMsg = Module.ErrorMsg; |
| 19 | const Result = codegen.Result; | 20 | const Result = codegen.Result; |
| 20 | const GenerateSymbolError = codegen.GenerateSymbolError; | ||
| 21 | const Emit = @import("Emit.zig"); | 21 | const Emit = @import("Emit.zig"); |
| 22 | const Liveness = @import("../../Liveness.zig"); | 22 | const Liveness = @import("../../Liveness.zig"); |
| 23 | const Mir = @import("Mir.zig"); | 23 | const Mir = @import("Mir.zig"); |
| ... | @@ -40,11 +40,7 @@ const Register = bits.Register; | ... | @@ -40,11 +40,7 @@ const Register = bits.Register; |
| 40 | const gp = abi.RegisterClass.gp; | 40 | const gp = abi.RegisterClass.gp; |
| 41 | const sse = abi.RegisterClass.sse; | 41 | const sse = abi.RegisterClass.sse; |
| 42 | 42 | ||
| 43 | const InnerError = error{ | 43 | const InnerError = CodeGenError || error{OutOfRegisters}; |
| 44 | OutOfMemory, | ||
| 45 | CodegenFail, | ||
| 46 | OutOfRegisters, | ||
| 47 | }; | ||
| 48 | 44 | ||
| 49 | gpa: Allocator, | 45 | gpa: Allocator, |
| 50 | air: Air, | 46 | air: Air, |
| ... | @@ -257,7 +253,7 @@ pub fn generate( | ... | @@ -257,7 +253,7 @@ pub fn generate( |
| 257 | liveness: Liveness, | 253 | liveness: Liveness, |
| 258 | code: *std.ArrayList(u8), | 254 | code: *std.ArrayList(u8), |
| 259 | debug_output: DebugInfoOutput, | 255 | debug_output: DebugInfoOutput, |
| 260 | ) GenerateSymbolError!Result { | 256 | ) CodeGenError!Result { |
| 261 | if (build_options.skip_non_native and builtin.cpu.arch != bin_file.options.target.cpu.arch) { | 257 | if (build_options.skip_non_native and builtin.cpu.arch != bin_file.options.target.cpu.arch) { |
| 262 | @panic("Attempted to compile for architecture that was disabled by build configuration"); | 258 | @panic("Attempted to compile for architecture that was disabled by build configuration"); |
| 263 | } | 259 | } |
| ... | @@ -6683,7 +6679,7 @@ fn airMulAdd(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -6683,7 +6679,7 @@ fn airMulAdd(self: *Self, inst: Air.Inst.Index) !void { |
| 6683 | return self.finishAir(inst, result, .{ extra.lhs, extra.rhs, pl_op.operand }); | 6679 | return self.finishAir(inst, result, .{ extra.lhs, extra.rhs, pl_op.operand }); |
| 6684 | } | 6680 | } |
| 6685 | 6681 | ||
| 6686 | pub fn resolveInst(self: *Self, inst: Air.Inst.Ref) InnerError!MCValue { | 6682 | fn resolveInst(self: *Self, inst: Air.Inst.Ref) InnerError!MCValue { |
| 6687 | // First section of indexes correspond to a set number of constant values. | 6683 | // First section of indexes correspond to a set number of constant values. |
| 6688 | const ref_int = @enumToInt(inst); | 6684 | const ref_int = @enumToInt(inst); |
| 6689 | if (ref_int < Air.Inst.Ref.typed_value_map.len) { | 6685 | 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 | ... | @@ -6752,200 +6748,26 @@ fn limitImmediateType(self: *Self, operand: Air.Inst.Ref, comptime T: type) !MCV |
| 6752 | return mcv; | 6748 | return mcv; |
| 6753 | } | 6749 | } |
| 6754 | 6750 | ||
| 6755 | fn lowerDeclRef(self: *Self, tv: TypedValue, decl_index: Module.Decl.Index) InnerError!MCValue { | ||
| 6756 | log.debug("lowerDeclRef: ty = {}, val = {}", .{ tv.ty.fmtDebug(), tv.val.fmtDebug() }); | ||
| 6757 | const ptr_bits = self.target.cpu.arch.ptrBitWidth(); | ||
| 6758 | const ptr_bytes: u64 = @divExact(ptr_bits, 8); | ||
| 6759 | |||
| 6760 | // TODO this feels clunky. Perhaps we should check for it in `genTypedValue`? | ||
| 6761 | if (tv.ty.zigTypeTag() == .Pointer) blk: { | ||
| 6762 | if (tv.ty.castPtrToFn()) |_| break :blk; | ||
| 6763 | if (!tv.ty.elemType2().hasRuntimeBits()) { | ||
| 6764 | return MCValue.none; | ||
| 6765 | } | ||
| 6766 | } | ||
| 6767 | |||
| 6768 | const module = self.bin_file.options.module.?; | ||
| 6769 | const decl = module.declPtr(decl_index); | ||
| 6770 | module.markDeclAlive(decl); | ||
| 6771 | |||
| 6772 | if (self.bin_file.cast(link.File.Elf)) |elf_file| { | ||
| 6773 | const atom_index = try elf_file.getOrCreateAtomForDecl(decl_index); | ||
| 6774 | const atom = elf_file.getAtom(atom_index); | ||
| 6775 | return MCValue{ .memory = atom.getOffsetTableAddress(elf_file) }; | ||
| 6776 | } else if (self.bin_file.cast(link.File.MachO)) |macho_file| { | ||
| 6777 | const atom_index = try macho_file.getOrCreateAtomForDecl(decl_index); | ||
| 6778 | const sym_index = macho_file.getAtom(atom_index).getSymbolIndex().?; | ||
| 6779 | return MCValue{ .linker_load = .{ | ||
| 6780 | .type = .got, | ||
| 6781 | .sym_index = sym_index, | ||
| 6782 | } }; | ||
| 6783 | } else if (self.bin_file.cast(link.File.Coff)) |coff_file| { | ||
| 6784 | const atom_index = try coff_file.getOrCreateAtomForDecl(decl_index); | ||
| 6785 | const sym_index = coff_file.getAtom(atom_index).getSymbolIndex().?; | ||
| 6786 | return MCValue{ .linker_load = .{ | ||
| 6787 | .type = .got, | ||
| 6788 | .sym_index = sym_index, | ||
| 6789 | } }; | ||
| 6790 | } else if (self.bin_file.cast(link.File.Plan9)) |p9| { | ||
| 6791 | const decl_block_index = try p9.seeDecl(decl_index); | ||
| 6792 | const decl_block = p9.getDeclBlock(decl_block_index); | ||
| 6793 | const got_addr = p9.bases.data + decl_block.got_index.? * ptr_bytes; | ||
| 6794 | return MCValue{ .memory = got_addr }; | ||
| 6795 | } else { | ||
| 6796 | return self.fail("TODO codegen non-ELF const Decl pointer", .{}); | ||
| 6797 | } | ||
| 6798 | } | ||
| 6799 | |||
| 6800 | fn lowerUnnamedConst(self: *Self, tv: TypedValue) InnerError!MCValue { | ||
| 6801 | log.debug("lowerUnnamedConst: ty = {}, val = {}", .{ tv.ty.fmtDebug(), tv.val.fmtDebug() }); | ||
| 6802 | const local_sym_index = self.bin_file.lowerUnnamedConst(tv, self.mod_fn.owner_decl) catch |err| { | ||
| 6803 | return self.fail("lowering unnamed constant failed: {s}", .{@errorName(err)}); | ||
| 6804 | }; | ||
| 6805 | if (self.bin_file.cast(link.File.Elf)) |elf_file| { | ||
| 6806 | return MCValue{ .memory = elf_file.getSymbol(local_sym_index).st_value }; | ||
| 6807 | } else if (self.bin_file.cast(link.File.MachO)) |_| { | ||
| 6808 | return MCValue{ .linker_load = .{ | ||
| 6809 | .type = .direct, | ||
| 6810 | .sym_index = local_sym_index, | ||
| 6811 | } }; | ||
| 6812 | } else if (self.bin_file.cast(link.File.Coff)) |_| { | ||
| 6813 | return MCValue{ .linker_load = .{ | ||
| 6814 | .type = .direct, | ||
| 6815 | .sym_index = local_sym_index, | ||
| 6816 | } }; | ||
| 6817 | } else if (self.bin_file.cast(link.File.Plan9)) |p9| { | ||
| 6818 | const ptr_bits = self.target.cpu.arch.ptrBitWidth(); | ||
| 6819 | const ptr_bytes: u64 = @divExact(ptr_bits, 8); | ||
| 6820 | const got_index = local_sym_index; // the plan9 backend returns the got_index | ||
| 6821 | const got_addr = p9.bases.data + got_index * ptr_bytes; | ||
| 6822 | return MCValue{ .memory = got_addr }; | ||
| 6823 | } else { | ||
| 6824 | return self.fail("TODO lower unnamed const", .{}); | ||
| 6825 | } | ||
| 6826 | } | ||
| 6827 | |||
| 6828 | fn genTypedValue(self: *Self, arg_tv: TypedValue) InnerError!MCValue { | 6751 | fn genTypedValue(self: *Self, arg_tv: TypedValue) InnerError!MCValue { |
| 6829 | var typed_value = arg_tv; | 6752 | const mcv: MCValue = switch (try codegen.genTypedValue( |
| 6830 | if (typed_value.val.castTag(.runtime_value)) |rt| { | 6753 | self.bin_file, |
| 6831 | typed_value.val = rt.data; | 6754 | self.src_loc, |
| 6832 | } | 6755 | arg_tv, |
| 6833 | log.debug("genTypedValue: ty = {}, val = {}", .{ typed_value.ty.fmtDebug(), typed_value.val.fmtDebug() }); | 6756 | self.mod_fn.owner_decl, |
| 6834 | if (typed_value.val.isUndef()) | 6757 | )) { |
| 6835 | return MCValue{ .undef = {} }; | 6758 | .mcv => |mcv| switch (mcv) { |
| 6836 | const ptr_bits = self.target.cpu.arch.ptrBitWidth(); | 6759 | .none => .none, |
| 6837 | 6760 | .undef => .undef, | |
| 6838 | if (typed_value.val.castTag(.decl_ref)) |payload| { | 6761 | .linker_load => |ll| .{ .linker_load = ll }, |
| 6839 | return self.lowerDeclRef(typed_value, payload.data); | 6762 | .immediate => |imm| .{ .immediate = imm }, |
| 6840 | } | 6763 | .memory => |addr| .{ .memory = addr }, |
| 6841 | if (typed_value.val.castTag(.decl_ref_mut)) |payload| { | ||
| 6842 | return self.lowerDeclRef(typed_value, payload.data.decl_index); | ||
| 6843 | } | ||
| 6844 | |||
| 6845 | const target = self.target.*; | ||
| 6846 | |||
| 6847 | switch (typed_value.ty.zigTypeTag()) { | ||
| 6848 | .Void => return MCValue{ .none = {} }, | ||
| 6849 | .Pointer => switch (typed_value.ty.ptrSize()) { | ||
| 6850 | .Slice => {}, | ||
| 6851 | else => { | ||
| 6852 | switch (typed_value.val.tag()) { | ||
| 6853 | .int_u64 => { | ||
| 6854 | return MCValue{ .immediate = typed_value.val.toUnsignedInt(target) }; | ||
| 6855 | }, | ||
| 6856 | else => {}, | ||
| 6857 | } | ||
| 6858 | }, | ||
| 6859 | }, | 6764 | }, |
| 6860 | .Int => { | 6765 | .fail => |msg| { |
| 6861 | const info = typed_value.ty.intInfo(self.target.*); | 6766 | self.err_msg = msg; |
| 6862 | if (info.bits <= ptr_bits and info.signedness == .signed) { | 6767 | return error.CodegenFail; |
| 6863 | return MCValue{ .immediate = @bitCast(u64, typed_value.val.toSignedInt(target)) }; | ||
| 6864 | } | ||
| 6865 | if (!(info.bits > ptr_bits or info.signedness == .signed)) { | ||
| 6866 | return MCValue{ .immediate = typed_value.val.toUnsignedInt(target) }; | ||
| 6867 | } | ||
| 6868 | }, | ||
| 6869 | .Bool => { | ||
| 6870 | return MCValue{ .immediate = @boolToInt(typed_value.val.toBool()) }; | ||
| 6871 | }, | ||
| 6872 | .Optional => { | ||
| 6873 | if (typed_value.ty.isPtrLikeOptional()) { | ||
| 6874 | if (typed_value.val.isNull()) | ||
| 6875 | return MCValue{ .immediate = 0 }; | ||
| 6876 | |||
| 6877 | var buf: Type.Payload.ElemType = undefined; | ||
| 6878 | return self.genTypedValue(.{ | ||
| 6879 | .ty = typed_value.ty.optionalChild(&buf), | ||
| 6880 | .val = typed_value.val, | ||
| 6881 | }); | ||
| 6882 | } else if (typed_value.ty.abiSize(self.target.*) == 1) { | ||
| 6883 | return MCValue{ .immediate = @boolToInt(!typed_value.val.isNull()) }; | ||
| 6884 | } | ||
| 6885 | }, | ||
| 6886 | .Enum => { | ||
| 6887 | if (typed_value.val.castTag(.enum_field_index)) |field_index| { | ||
| 6888 | switch (typed_value.ty.tag()) { | ||
| 6889 | .enum_simple => { | ||
| 6890 | return MCValue{ .immediate = field_index.data }; | ||
| 6891 | }, | ||
| 6892 | .enum_full, .enum_nonexhaustive => { | ||
| 6893 | const enum_full = typed_value.ty.cast(Type.Payload.EnumFull).?.data; | ||
| 6894 | if (enum_full.values.count() != 0) { | ||
| 6895 | const tag_val = enum_full.values.keys()[field_index.data]; | ||
| 6896 | return self.genTypedValue(.{ .ty = enum_full.tag_ty, .val = tag_val }); | ||
| 6897 | } else { | ||
| 6898 | return MCValue{ .immediate = field_index.data }; | ||
| 6899 | } | ||
| 6900 | }, | ||
| 6901 | else => unreachable, | ||
| 6902 | } | ||
| 6903 | } else { | ||
| 6904 | var int_tag_buffer: Type.Payload.Bits = undefined; | ||
| 6905 | const int_tag_ty = typed_value.ty.intTagType(&int_tag_buffer); | ||
| 6906 | return self.genTypedValue(.{ .ty = int_tag_ty, .val = typed_value.val }); | ||
| 6907 | } | ||
| 6908 | }, | 6768 | }, |
| 6909 | .ErrorSet => { | 6769 | }; |
| 6910 | switch (typed_value.val.tag()) { | 6770 | return mcv; |
| 6911 | .@"error" => { | ||
| 6912 | const err_name = typed_value.val.castTag(.@"error").?.data.name; | ||
| 6913 | const module = self.bin_file.options.module.?; | ||
| 6914 | const global_error_set = module.global_error_set; | ||
| 6915 | const error_index = global_error_set.get(err_name).?; | ||
| 6916 | return MCValue{ .immediate = error_index }; | ||
| 6917 | }, | ||
| 6918 | else => { | ||
| 6919 | // In this case we are rendering an error union which has a 0 bits payload. | ||
| 6920 | return MCValue{ .immediate = 0 }; | ||
| 6921 | }, | ||
| 6922 | } | ||
| 6923 | }, | ||
| 6924 | .ErrorUnion => { | ||
| 6925 | const error_type = typed_value.ty.errorUnionSet(); | ||
| 6926 | const payload_type = typed_value.ty.errorUnionPayload(); | ||
| 6927 | const is_pl = typed_value.val.errorUnionIsPayload(); | ||
| 6928 | |||
| 6929 | if (!payload_type.hasRuntimeBitsIgnoreComptime()) { | ||
| 6930 | // We use the error type directly as the type. | ||
| 6931 | const err_val = if (!is_pl) typed_value.val else Value.initTag(.zero); | ||
| 6932 | return self.genTypedValue(.{ .ty = error_type, .val = err_val }); | ||
| 6933 | } | ||
| 6934 | }, | ||
| 6935 | |||
| 6936 | .ComptimeInt => unreachable, | ||
| 6937 | .ComptimeFloat => unreachable, | ||
| 6938 | .Type => unreachable, | ||
| 6939 | .EnumLiteral => unreachable, | ||
| 6940 | .NoReturn => unreachable, | ||
| 6941 | .Undefined => unreachable, | ||
| 6942 | .Null => unreachable, | ||
| 6943 | .Opaque => unreachable, | ||
| 6944 | |||
| 6945 | else => {}, | ||
| 6946 | } | ||
| 6947 | |||
| 6948 | return self.lowerUnnamedConst(typed_value); | ||
| 6949 | } | 6771 | } |
| 6950 | 6772 | ||
| 6951 | const CallMCValues = struct { | 6773 | const CallMCValues = struct { |
src/codegen.zig+287-19| ... | @@ -29,11 +29,10 @@ pub const Result = union(enum) { | ... | @@ -29,11 +29,10 @@ pub const Result = union(enum) { |
| 29 | fail: *ErrorMsg, | 29 | fail: *ErrorMsg, |
| 30 | }; | 30 | }; |
| 31 | 31 | ||
| 32 | pub const GenerateSymbolError = error{ | 32 | pub const CodeGenError = error{ |
| 33 | OutOfMemory, | 33 | OutOfMemory, |
| 34 | Overflow, | 34 | Overflow, |
| 35 | /// A Decl that this symbol depends on had a semantic analysis failure. | 35 | CodegenFail, |
| 36 | AnalysisFail, | ||
| 37 | }; | 36 | }; |
| 38 | 37 | ||
| 39 | pub const DebugInfoOutput = union(enum) { | 38 | pub const DebugInfoOutput = union(enum) { |
| ... | @@ -63,19 +62,6 @@ pub const DebugInfoOutput = union(enum) { | ... | @@ -63,19 +62,6 @@ pub const DebugInfoOutput = union(enum) { |
| 63 | none, | 62 | none, |
| 64 | }; | 63 | }; |
| 65 | 64 | ||
| 66 | /// Helper struct to denote that the value is in memory but requires a linker relocation fixup: | ||
| 67 | /// * got - the value is referenced indirectly via GOT entry index (the linker emits a got-type reloc) | ||
| 68 | /// * direct - the value is referenced directly via symbol index index (the linker emits a displacement reloc) | ||
| 69 | /// * import - the value is referenced indirectly via import entry index (the linker emits an import-type reloc) | ||
| 70 | pub const LinkerLoad = struct { | ||
| 71 | type: enum { | ||
| 72 | got, | ||
| 73 | direct, | ||
| 74 | import, | ||
| 75 | }, | ||
| 76 | sym_index: u32, | ||
| 77 | }; | ||
| 78 | |||
| 79 | pub fn generateFunction( | 65 | pub fn generateFunction( |
| 80 | bin_file: *link.File, | 66 | bin_file: *link.File, |
| 81 | src_loc: Module.SrcLoc, | 67 | src_loc: Module.SrcLoc, |
| ... | @@ -84,7 +70,7 @@ pub fn generateFunction( | ... | @@ -84,7 +70,7 @@ pub fn generateFunction( |
| 84 | liveness: Liveness, | 70 | liveness: Liveness, |
| 85 | code: *std.ArrayList(u8), | 71 | code: *std.ArrayList(u8), |
| 86 | debug_output: DebugInfoOutput, | 72 | debug_output: DebugInfoOutput, |
| 87 | ) GenerateSymbolError!Result { | 73 | ) CodeGenError!Result { |
| 88 | switch (bin_file.options.target.cpu.arch) { | 74 | switch (bin_file.options.target.cpu.arch) { |
| 89 | .arm, | 75 | .arm, |
| 90 | .armeb, | 76 | .armeb, |
| ... | @@ -120,7 +106,7 @@ pub fn generateSymbol( | ... | @@ -120,7 +106,7 @@ pub fn generateSymbol( |
| 120 | code: *std.ArrayList(u8), | 106 | code: *std.ArrayList(u8), |
| 121 | debug_output: DebugInfoOutput, | 107 | debug_output: DebugInfoOutput, |
| 122 | reloc_info: RelocInfo, | 108 | reloc_info: RelocInfo, |
| 123 | ) GenerateSymbolError!Result { | 109 | ) CodeGenError!Result { |
| 124 | const tracy = trace(@src()); | 110 | const tracy = trace(@src()); |
| 125 | defer tracy.end(); | 111 | defer tracy.end(); |
| 126 | 112 | ||
| ... | @@ -823,7 +809,7 @@ fn lowerDeclRef( | ... | @@ -823,7 +809,7 @@ fn lowerDeclRef( |
| 823 | code: *std.ArrayList(u8), | 809 | code: *std.ArrayList(u8), |
| 824 | debug_output: DebugInfoOutput, | 810 | debug_output: DebugInfoOutput, |
| 825 | reloc_info: RelocInfo, | 811 | reloc_info: RelocInfo, |
| 826 | ) GenerateSymbolError!Result { | 812 | ) CodeGenError!Result { |
| 827 | const target = bin_file.options.target; | 813 | const target = bin_file.options.target; |
| 828 | const module = bin_file.options.module.?; | 814 | const module = bin_file.options.module.?; |
| 829 | if (typed_value.ty.isSlice()) { | 815 | if (typed_value.ty.isSlice()) { |
| ... | @@ -880,6 +866,288 @@ fn lowerDeclRef( | ... | @@ -880,6 +866,288 @@ fn lowerDeclRef( |
| 880 | return Result.ok; | 866 | return Result.ok; |
| 881 | } | 867 | } |
| 882 | 868 | ||
| 869 | /// Helper struct to denote that the value is in memory but requires a linker relocation fixup: | ||
| 870 | /// * got - the value is referenced indirectly via GOT entry index (the linker emits a got-type reloc) | ||
| 871 | /// * direct - the value is referenced directly via symbol index index (the linker emits a displacement reloc) | ||
| 872 | /// * import - the value is referenced indirectly via import entry index (the linker emits an import-type reloc) | ||
| 873 | pub const LinkerLoad = struct { | ||
| 874 | type: enum { | ||
| 875 | got, | ||
| 876 | direct, | ||
| 877 | import, | ||
| 878 | }, | ||
| 879 | sym_index: u32, | ||
| 880 | }; | ||
| 881 | |||
| 882 | pub const GenResult = union(enum) { | ||
| 883 | mcv: MCValue, | ||
| 884 | fail: *ErrorMsg, | ||
| 885 | |||
| 886 | const MCValue = union(enum) { | ||
| 887 | none, | ||
| 888 | undef, | ||
| 889 | /// The bit-width of the immediate may be smaller than `u64`. For example, on 32-bit targets | ||
| 890 | /// such as ARM, the immediate will never exceed 32-bits. | ||
| 891 | immediate: u64, | ||
| 892 | linker_load: LinkerLoad, | ||
| 893 | /// Direct by-address reference to memory location. | ||
| 894 | memory: u64, | ||
| 895 | }; | ||
| 896 | |||
| 897 | fn mcv(val: MCValue) GenResult { | ||
| 898 | return .{ .mcv = val }; | ||
| 899 | } | ||
| 900 | |||
| 901 | fn fail( | ||
| 902 | gpa: Allocator, | ||
| 903 | src_loc: Module.SrcLoc, | ||
| 904 | comptime format: []const u8, | ||
| 905 | args: anytype, | ||
| 906 | ) Allocator.Error!GenResult { | ||
| 907 | const msg = try ErrorMsg.create(gpa, src_loc, format, args); | ||
| 908 | return .{ .fail = msg }; | ||
| 909 | } | ||
| 910 | }; | ||
| 911 | |||
| 912 | fn genDeclRef( | ||
| 913 | bin_file: *link.File, | ||
| 914 | src_loc: Module.SrcLoc, | ||
| 915 | tv: TypedValue, | ||
| 916 | decl_index: Module.Decl.Index, | ||
| 917 | ) CodeGenError!GenResult { | ||
| 918 | log.debug("genDeclRef: ty = {}, val = {}", .{ tv.ty.fmtDebug(), tv.val.fmtDebug() }); | ||
| 919 | |||
| 920 | const target = bin_file.options.target; | ||
| 921 | const ptr_bits = target.cpu.arch.ptrBitWidth(); | ||
| 922 | const ptr_bytes: u64 = @divExact(ptr_bits, 8); | ||
| 923 | |||
| 924 | const module = bin_file.options.module.?; | ||
| 925 | const decl = module.declPtr(decl_index); | ||
| 926 | |||
| 927 | if (decl.ty.zigTypeTag() != .Fn and !decl.ty.hasRuntimeBitsIgnoreComptime()) { | ||
| 928 | const imm: u64 = switch (ptr_bytes) { | ||
| 929 | 1 => 0xaa, | ||
| 930 | 2 => 0xaaaa, | ||
| 931 | 4 => 0xaaaaaaaa, | ||
| 932 | 8 => 0xaaaaaaaaaaaaaaaa, | ||
| 933 | else => unreachable, | ||
| 934 | }; | ||
| 935 | return GenResult.mcv(.{ .immediate = imm }); | ||
| 936 | } | ||
| 937 | |||
| 938 | // TODO this feels clunky. Perhaps we should check for it in `genTypedValue`? | ||
| 939 | if (tv.ty.zigTypeTag() == .Pointer) blk: { | ||
| 940 | if (tv.ty.castPtrToFn()) |_| break :blk; | ||
| 941 | if (!tv.ty.elemType2().hasRuntimeBits()) { | ||
| 942 | return GenResult.mcv(.none); | ||
| 943 | } | ||
| 944 | } | ||
| 945 | |||
| 946 | module.markDeclAlive(decl); | ||
| 947 | |||
| 948 | if (bin_file.cast(link.File.Elf)) |elf_file| { | ||
| 949 | const atom_index = try elf_file.getOrCreateAtomForDecl(decl_index); | ||
| 950 | const atom = elf_file.getAtom(atom_index); | ||
| 951 | return GenResult.mcv(.{ .memory = atom.getOffsetTableAddress(elf_file) }); | ||
| 952 | } else if (bin_file.cast(link.File.MachO)) |macho_file| { | ||
| 953 | const atom_index = try macho_file.getOrCreateAtomForDecl(decl_index); | ||
| 954 | const sym_index = macho_file.getAtom(atom_index).getSymbolIndex().?; | ||
| 955 | return GenResult.mcv(.{ .linker_load = .{ | ||
| 956 | .type = .got, | ||
| 957 | .sym_index = sym_index, | ||
| 958 | } }); | ||
| 959 | } else if (bin_file.cast(link.File.Coff)) |coff_file| { | ||
| 960 | const atom_index = try coff_file.getOrCreateAtomForDecl(decl_index); | ||
| 961 | const sym_index = coff_file.getAtom(atom_index).getSymbolIndex().?; | ||
| 962 | return GenResult.mcv(.{ .linker_load = .{ | ||
| 963 | .type = .got, | ||
| 964 | .sym_index = sym_index, | ||
| 965 | } }); | ||
| 966 | } else if (bin_file.cast(link.File.Plan9)) |p9| { | ||
| 967 | const decl_block_index = try p9.seeDecl(decl_index); | ||
| 968 | const decl_block = p9.getDeclBlock(decl_block_index); | ||
| 969 | const got_addr = p9.bases.data + decl_block.got_index.? * ptr_bytes; | ||
| 970 | return GenResult.mcv(.{ .memory = got_addr }); | ||
| 971 | } else { | ||
| 972 | return GenResult.fail(bin_file.allocator, src_loc, "TODO genDeclRef for target {}", .{target}); | ||
| 973 | } | ||
| 974 | } | ||
| 975 | |||
| 976 | fn genUnnamedConst( | ||
| 977 | bin_file: *link.File, | ||
| 978 | src_loc: Module.SrcLoc, | ||
| 979 | tv: TypedValue, | ||
| 980 | owner_decl_index: Module.Decl.Index, | ||
| 981 | ) CodeGenError!GenResult { | ||
| 982 | log.debug("genUnnamedConst: ty = {}, val = {}", .{ tv.ty.fmtDebug(), tv.val.fmtDebug() }); | ||
| 983 | |||
| 984 | const target = bin_file.options.target; | ||
| 985 | const local_sym_index = bin_file.lowerUnnamedConst(tv, owner_decl_index) catch |err| { | ||
| 986 | return GenResult.fail(bin_file.allocator, src_loc, "lowering unnamed constant failed: {s}", .{@errorName(err)}); | ||
| 987 | }; | ||
| 988 | if (bin_file.cast(link.File.Elf)) |elf_file| { | ||
| 989 | return GenResult.mcv(.{ .memory = elf_file.getSymbol(local_sym_index).st_value }); | ||
| 990 | } else if (bin_file.cast(link.File.MachO)) |_| { | ||
| 991 | return GenResult.mcv(.{ .linker_load = .{ | ||
| 992 | .type = .direct, | ||
| 993 | .sym_index = local_sym_index, | ||
| 994 | } }); | ||
| 995 | } else if (bin_file.cast(link.File.Coff)) |_| { | ||
| 996 | return GenResult.mcv(.{ .linker_load = .{ | ||
| 997 | .type = .direct, | ||
| 998 | .sym_index = local_sym_index, | ||
| 999 | } }); | ||
| 1000 | } else if (bin_file.cast(link.File.Plan9)) |p9| { | ||
| 1001 | const ptr_bits = target.cpu.arch.ptrBitWidth(); | ||
| 1002 | const ptr_bytes: u64 = @divExact(ptr_bits, 8); | ||
| 1003 | const got_index = local_sym_index; // the plan9 backend returns the got_index | ||
| 1004 | const got_addr = p9.bases.data + got_index * ptr_bytes; | ||
| 1005 | return GenResult.mcv(.{ .memory = got_addr }); | ||
| 1006 | } else { | ||
| 1007 | return GenResult.fail(bin_file.allocator, src_loc, "TODO genUnnamedConst for target {}", .{target}); | ||
| 1008 | } | ||
| 1009 | } | ||
| 1010 | |||
| 1011 | pub fn genTypedValue( | ||
| 1012 | bin_file: *link.File, | ||
| 1013 | src_loc: Module.SrcLoc, | ||
| 1014 | arg_tv: TypedValue, | ||
| 1015 | owner_decl_index: Module.Decl.Index, | ||
| 1016 | ) CodeGenError!GenResult { | ||
| 1017 | var typed_value = arg_tv; | ||
| 1018 | if (typed_value.val.castTag(.runtime_value)) |rt| { | ||
| 1019 | typed_value.val = rt.data; | ||
| 1020 | } | ||
| 1021 | |||
| 1022 | log.debug("genTypedValue: ty = {}, val = {}", .{ typed_value.ty.fmtDebug(), typed_value.val.fmtDebug() }); | ||
| 1023 | |||
| 1024 | if (typed_value.val.isUndef()) | ||
| 1025 | return GenResult.mcv(.undef); | ||
| 1026 | |||
| 1027 | const target = bin_file.options.target; | ||
| 1028 | const ptr_bits = target.cpu.arch.ptrBitWidth(); | ||
| 1029 | |||
| 1030 | if (typed_value.val.castTag(.decl_ref)) |payload| { | ||
| 1031 | return genDeclRef(bin_file, src_loc, typed_value, payload.data); | ||
| 1032 | } | ||
| 1033 | if (typed_value.val.castTag(.decl_ref_mut)) |payload| { | ||
| 1034 | return genDeclRef(bin_file, src_loc, typed_value, payload.data.decl_index); | ||
| 1035 | } | ||
| 1036 | |||
| 1037 | switch (typed_value.ty.zigTypeTag()) { | ||
| 1038 | .Void => return GenResult.mcv(.none), | ||
| 1039 | .Pointer => switch (typed_value.ty.ptrSize()) { | ||
| 1040 | .Slice => {}, | ||
| 1041 | else => { | ||
| 1042 | switch (typed_value.val.tag()) { | ||
| 1043 | .int_u64 => { | ||
| 1044 | return GenResult.mcv(.{ .immediate = typed_value.val.toUnsignedInt(target) }); | ||
| 1045 | }, | ||
| 1046 | else => {}, | ||
| 1047 | } | ||
| 1048 | }, | ||
| 1049 | }, | ||
| 1050 | .Int => { | ||
| 1051 | const info = typed_value.ty.intInfo(target); | ||
| 1052 | if (info.bits <= ptr_bits) { | ||
| 1053 | const unsigned = switch (info.signedness) { | ||
| 1054 | .signed => @bitCast(u64, typed_value.val.toSignedInt(target)), | ||
| 1055 | .unsigned => typed_value.val.toUnsignedInt(target), | ||
| 1056 | }; | ||
| 1057 | return GenResult.mcv(.{ .immediate = unsigned }); | ||
| 1058 | } | ||
| 1059 | }, | ||
| 1060 | .Bool => { | ||
| 1061 | return GenResult.mcv(.{ .immediate = @boolToInt(typed_value.val.toBool()) }); | ||
| 1062 | }, | ||
| 1063 | .Optional => { | ||
| 1064 | if (typed_value.ty.isPtrLikeOptional()) { | ||
| 1065 | if (typed_value.val.isNull()) | ||
| 1066 | return GenResult.mcv(.{ .immediate = 0 }); | ||
| 1067 | |||
| 1068 | var buf: Type.Payload.ElemType = undefined; | ||
| 1069 | return genTypedValue(bin_file, src_loc, .{ | ||
| 1070 | .ty = typed_value.ty.optionalChild(&buf), | ||
| 1071 | .val = typed_value.val, | ||
| 1072 | }, owner_decl_index); | ||
| 1073 | } else if (typed_value.ty.abiSize(target) == 1) { | ||
| 1074 | return GenResult.mcv(.{ .immediate = @boolToInt(!typed_value.val.isNull()) }); | ||
| 1075 | } | ||
| 1076 | }, | ||
| 1077 | .Enum => { | ||
| 1078 | if (typed_value.val.castTag(.enum_field_index)) |field_index| { | ||
| 1079 | switch (typed_value.ty.tag()) { | ||
| 1080 | .enum_simple => { | ||
| 1081 | return GenResult.mcv(.{ .immediate = field_index.data }); | ||
| 1082 | }, | ||
| 1083 | .enum_full, .enum_nonexhaustive => { | ||
| 1084 | const enum_full = typed_value.ty.cast(Type.Payload.EnumFull).?.data; | ||
| 1085 | if (enum_full.values.count() != 0) { | ||
| 1086 | const tag_val = enum_full.values.keys()[field_index.data]; | ||
| 1087 | return genTypedValue(bin_file, src_loc, .{ | ||
| 1088 | .ty = enum_full.tag_ty, | ||
| 1089 | .val = tag_val, | ||
| 1090 | }, owner_decl_index); | ||
| 1091 | } else { | ||
| 1092 | return GenResult.mcv(.{ .immediate = field_index.data }); | ||
| 1093 | } | ||
| 1094 | }, | ||
| 1095 | else => unreachable, | ||
| 1096 | } | ||
| 1097 | } else { | ||
| 1098 | var int_tag_buffer: Type.Payload.Bits = undefined; | ||
| 1099 | const int_tag_ty = typed_value.ty.intTagType(&int_tag_buffer); | ||
| 1100 | return genTypedValue(bin_file, src_loc, .{ | ||
| 1101 | .ty = int_tag_ty, | ||
| 1102 | .val = typed_value.val, | ||
| 1103 | }, owner_decl_index); | ||
| 1104 | } | ||
| 1105 | }, | ||
| 1106 | .ErrorSet => { | ||
| 1107 | switch (typed_value.val.tag()) { | ||
| 1108 | .@"error" => { | ||
| 1109 | const err_name = typed_value.val.castTag(.@"error").?.data.name; | ||
| 1110 | const module = bin_file.options.module.?; | ||
| 1111 | const global_error_set = module.global_error_set; | ||
| 1112 | const error_index = global_error_set.get(err_name).?; | ||
| 1113 | return GenResult.mcv(.{ .immediate = error_index }); | ||
| 1114 | }, | ||
| 1115 | else => { | ||
| 1116 | // In this case we are rendering an error union which has a 0 bits payload. | ||
| 1117 | return GenResult.mcv(.{ .immediate = 0 }); | ||
| 1118 | }, | ||
| 1119 | } | ||
| 1120 | }, | ||
| 1121 | .ErrorUnion => { | ||
| 1122 | const error_type = typed_value.ty.errorUnionSet(); | ||
| 1123 | const payload_type = typed_value.ty.errorUnionPayload(); | ||
| 1124 | const is_pl = typed_value.val.errorUnionIsPayload(); | ||
| 1125 | |||
| 1126 | if (!payload_type.hasRuntimeBitsIgnoreComptime()) { | ||
| 1127 | // We use the error type directly as the type. | ||
| 1128 | const err_val = if (!is_pl) typed_value.val else Value.initTag(.zero); | ||
| 1129 | return genTypedValue(bin_file, src_loc, .{ | ||
| 1130 | .ty = error_type, | ||
| 1131 | .val = err_val, | ||
| 1132 | }, owner_decl_index); | ||
| 1133 | } | ||
| 1134 | }, | ||
| 1135 | |||
| 1136 | .ComptimeInt => unreachable, | ||
| 1137 | .ComptimeFloat => unreachable, | ||
| 1138 | .Type => unreachable, | ||
| 1139 | .EnumLiteral => unreachable, | ||
| 1140 | .NoReturn => unreachable, | ||
| 1141 | .Undefined => unreachable, | ||
| 1142 | .Null => unreachable, | ||
| 1143 | .Opaque => unreachable, | ||
| 1144 | |||
| 1145 | else => {}, | ||
| 1146 | } | ||
| 1147 | |||
| 1148 | return genUnnamedConst(bin_file, src_loc, typed_value, owner_decl_index); | ||
| 1149 | } | ||
| 1150 | |||
| 883 | pub fn errUnionPayloadOffset(payload_ty: Type, target: std.Target) u64 { | 1151 | pub fn errUnionPayloadOffset(payload_ty: Type, target: std.Target) u64 { |
| 884 | const payload_align = payload_ty.abiAlignment(target); | 1152 | const payload_align = payload_ty.abiAlignment(target); |
| 885 | const error_align = Type.anyerror.abiAlignment(target); | 1153 | const error_align = Type.anyerror.abiAlignment(target); |
src/link/Coff.zig+1-1| ... | @@ -1060,7 +1060,7 @@ pub fn lowerUnnamedConst(self: *Coff, tv: TypedValue, decl_index: Module.Decl.In | ... | @@ -1060,7 +1060,7 @@ pub fn lowerUnnamedConst(self: *Coff, tv: TypedValue, decl_index: Module.Decl.In |
| 1060 | decl.analysis = .codegen_failure; | 1060 | decl.analysis = .codegen_failure; |
| 1061 | try mod.failed_decls.put(mod.gpa, decl_index, em); | 1061 | try mod.failed_decls.put(mod.gpa, decl_index, em); |
| 1062 | log.err("{s}", .{em.msg}); | 1062 | log.err("{s}", .{em.msg}); |
| 1063 | return error.AnalysisFail; | 1063 | return error.CodegenFail; |
| 1064 | }, | 1064 | }, |
| 1065 | }; | 1065 | }; |
| 1066 | 1066 |
src/link/Elf.zig+10-3| ... | @@ -2097,9 +2097,16 @@ fn freeAtom(self: *Elf, atom_index: Atom.Index) void { | ... | @@ -2097,9 +2097,16 @@ fn freeAtom(self: *Elf, atom_index: Atom.Index) void { |
| 2097 | // Appending to free lists is allowed to fail because the free lists are heuristics based anyway. | 2097 | // Appending to free lists is allowed to fail because the free lists are heuristics based anyway. |
| 2098 | const local_sym_index = atom.getSymbolIndex().?; | 2098 | const local_sym_index = atom.getSymbolIndex().?; |
| 2099 | 2099 | ||
| 2100 | log.debug("adding %{d} to local symbols free list", .{local_sym_index}); | ||
| 2100 | self.local_symbol_free_list.append(gpa, local_sym_index) catch {}; | 2101 | self.local_symbol_free_list.append(gpa, local_sym_index) catch {}; |
| 2101 | self.local_symbols.items[local_sym_index].st_info = 0; | 2102 | self.local_symbols.items[local_sym_index] = .{ |
| 2102 | self.local_symbols.items[local_sym_index].st_shndx = 0; | 2103 | .st_name = 0, |
| 2104 | .st_info = 0, | ||
| 2105 | .st_other = 0, | ||
| 2106 | .st_shndx = 0, | ||
| 2107 | .st_value = 0, | ||
| 2108 | .st_size = 0, | ||
| 2109 | }; | ||
| 2103 | _ = self.atom_by_index_table.remove(local_sym_index); | 2110 | _ = self.atom_by_index_table.remove(local_sym_index); |
| 2104 | self.getAtomPtr(atom_index).local_sym_index = 0; | 2111 | self.getAtomPtr(atom_index).local_sym_index = 0; |
| 2105 | 2112 | ||
| ... | @@ -2618,7 +2625,7 @@ pub fn lowerUnnamedConst(self: *Elf, typed_value: TypedValue, decl_index: Module | ... | @@ -2618,7 +2625,7 @@ pub fn lowerUnnamedConst(self: *Elf, typed_value: TypedValue, decl_index: Module |
| 2618 | decl.analysis = .codegen_failure; | 2625 | decl.analysis = .codegen_failure; |
| 2619 | try mod.failed_decls.put(mod.gpa, decl_index, em); | 2626 | try mod.failed_decls.put(mod.gpa, decl_index, em); |
| 2620 | log.err("{s}", .{em.msg}); | 2627 | log.err("{s}", .{em.msg}); |
| 2621 | return error.AnalysisFail; | 2628 | return error.CodegenFail; |
| 2622 | }, | 2629 | }, |
| 2623 | }; | 2630 | }; |
| 2624 | 2631 |
src/link/MachO.zig+1-1| ... | @@ -2089,7 +2089,7 @@ pub fn lowerUnnamedConst(self: *MachO, typed_value: TypedValue, decl_index: Modu | ... | @@ -2089,7 +2089,7 @@ pub fn lowerUnnamedConst(self: *MachO, typed_value: TypedValue, decl_index: Modu |
| 2089 | decl.analysis = .codegen_failure; | 2089 | decl.analysis = .codegen_failure; |
| 2090 | try module.failed_decls.put(module.gpa, decl_index, em); | 2090 | try module.failed_decls.put(module.gpa, decl_index, em); |
| 2091 | log.err("{s}", .{em.msg}); | 2091 | log.err("{s}", .{em.msg}); |
| 2092 | return error.AnalysisFail; | 2092 | return error.CodegenFail; |
| 2093 | }, | 2093 | }, |
| 2094 | }; | 2094 | }; |
| 2095 | 2095 |
src/link/Plan9.zig+1-1| ... | @@ -377,7 +377,7 @@ pub fn lowerUnnamedConst(self: *Plan9, tv: TypedValue, decl_index: Module.Decl.I | ... | @@ -377,7 +377,7 @@ pub fn lowerUnnamedConst(self: *Plan9, tv: TypedValue, decl_index: Module.Decl.I |
| 377 | decl.analysis = .codegen_failure; | 377 | decl.analysis = .codegen_failure; |
| 378 | try mod.failed_decls.put(mod.gpa, decl_index, em); | 378 | try mod.failed_decls.put(mod.gpa, decl_index, em); |
| 379 | log.err("{s}", .{em.msg}); | 379 | log.err("{s}", .{em.msg}); |
| 380 | return error.AnalysisFail; | 380 | return error.CodegenFail; |
| 381 | }, | 381 | }, |
| 382 | }; | 382 | }; |
| 383 | // duped_code is freed when the unnamed const is freed | 383 | // duped_code is freed when the unnamed const is freed |
src/link/Wasm.zig+1-1| ... | @@ -1265,7 +1265,7 @@ pub fn lowerUnnamedConst(wasm: *Wasm, tv: TypedValue, decl_index: Module.Decl.In | ... | @@ -1265,7 +1265,7 @@ pub fn lowerUnnamedConst(wasm: *Wasm, tv: TypedValue, decl_index: Module.Decl.In |
| 1265 | .fail => |em| { | 1265 | .fail => |em| { |
| 1266 | decl.analysis = .codegen_failure; | 1266 | decl.analysis = .codegen_failure; |
| 1267 | try mod.failed_decls.put(mod.gpa, decl_index, em); | 1267 | try mod.failed_decls.put(mod.gpa, decl_index, em); |
| 1268 | return error.AnalysisFail; | 1268 | return error.CodegenFail; |
| 1269 | }, | 1269 | }, |
| 1270 | }; | 1270 | }; |
| 1271 | }; | 1271 | }; |
src/register_manager.zig+3| ... | @@ -19,6 +19,9 @@ pub const AllocateRegistersError = error{ | ... | @@ -19,6 +19,9 @@ pub const AllocateRegistersError = error{ |
| 19 | /// Can happen when spilling an instruction in codegen runs out of | 19 | /// Can happen when spilling an instruction in codegen runs out of |
| 20 | /// memory, so we propagate that error | 20 | /// memory, so we propagate that error |
| 21 | OutOfMemory, | 21 | OutOfMemory, |
| 22 | /// Can happen when spilling an instruction in codegen triggers integer | ||
| 23 | /// overflow, so we propagate that error | ||
| 24 | Overflow, | ||
| 22 | /// Can happen when spilling an instruction triggers a codegen | 25 | /// Can happen when spilling an instruction triggers a codegen |
| 23 | /// error, so we propagate that error | 26 | /// error, so we propagate that error |
| 24 | CodegenFail, | 27 | CodegenFail, |
test/behavior/field_parent_ptr.zig+5| ... | @@ -3,6 +3,7 @@ const builtin = @import("builtin"); | ... | @@ -3,6 +3,7 @@ const builtin = @import("builtin"); |
| 3 | 3 | ||
| 4 | test "@fieldParentPtr non-first field" { | 4 | test "@fieldParentPtr non-first field" { |
| 5 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; | 5 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; |
| 6 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | ||
| 6 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | 7 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 7 | try testParentFieldPtr(&foo.c); | 8 | try testParentFieldPtr(&foo.c); |
| 8 | comptime try testParentFieldPtr(&foo.c); | 9 | comptime try testParentFieldPtr(&foo.c); |
| ... | @@ -10,6 +11,7 @@ test "@fieldParentPtr non-first field" { | ... | @@ -10,6 +11,7 @@ test "@fieldParentPtr non-first field" { |
| 10 | 11 | ||
| 11 | test "@fieldParentPtr first field" { | 12 | test "@fieldParentPtr first field" { |
| 12 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; | 13 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; |
| 14 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | ||
| 13 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | 15 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 14 | try testParentFieldPtrFirst(&foo.a); | 16 | try testParentFieldPtrFirst(&foo.a); |
| 15 | comptime try testParentFieldPtrFirst(&foo.a); | 17 | comptime try testParentFieldPtrFirst(&foo.a); |
| ... | @@ -47,6 +49,7 @@ fn testParentFieldPtrFirst(a: *const bool) !void { | ... | @@ -47,6 +49,7 @@ fn testParentFieldPtrFirst(a: *const bool) !void { |
| 47 | 49 | ||
| 48 | test "@fieldParentPtr untagged union" { | 50 | test "@fieldParentPtr untagged union" { |
| 49 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; | 51 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; |
| 52 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | ||
| 50 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | 53 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 51 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | 54 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 52 | 55 | ||
| ... | @@ -73,6 +76,7 @@ fn testFieldParentPtrUnion(c: *const i32) !void { | ... | @@ -73,6 +76,7 @@ fn testFieldParentPtrUnion(c: *const i32) !void { |
| 73 | 76 | ||
| 74 | test "@fieldParentPtr tagged union" { | 77 | test "@fieldParentPtr tagged union" { |
| 75 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; | 78 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; |
| 79 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | ||
| 76 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | 80 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 77 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | 81 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 78 | 82 | ||
| ... | @@ -99,6 +103,7 @@ fn testFieldParentPtrTaggedUnion(c: *const i32) !void { | ... | @@ -99,6 +103,7 @@ fn testFieldParentPtrTaggedUnion(c: *const i32) !void { |
| 99 | 103 | ||
| 100 | test "@fieldParentPtr extern union" { | 104 | test "@fieldParentPtr extern union" { |
| 101 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; | 105 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; |
| 106 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | ||
| 102 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | 107 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 103 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | 108 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 104 | 109 |