| ... | @@ -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,7 +41,7 @@ const c_abi_int_param_regs = abi.c_abi_int_param_regs; | ... | @@ -41,7 +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 = codegen.CodeGenError || error{OutOfRegisters}; | 44 | const InnerError = CodeGenError || error{OutOfRegisters}; |
| 45 | | 45 | |
| 46 | gpa: Allocator, | 46 | gpa: Allocator, |
| 47 | air: Air, | 47 | air: Air, |
| ... | @@ -333,7 +333,7 @@ pub fn generate( | ... | @@ -333,7 +333,7 @@ pub fn generate( |
| 333 | liveness: Liveness, | 333 | liveness: Liveness, |
| 334 | code: *std.ArrayList(u8), | 334 | code: *std.ArrayList(u8), |
| 335 | debug_output: DebugInfoOutput, | 335 | debug_output: DebugInfoOutput, |
| 336 | ) GenerateSymbolError!Result { | 336 | ) CodeGenError!Result { |
| 337 | 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) { |
| 338 | @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"); |
| 339 | } | 339 | } |
| ... | @@ -6133,201 +6133,26 @@ fn getResolvedInstValue(self: *Self, inst: Air.Inst.Index) MCValue { | ... | @@ -6133,201 +6133,26 @@ fn getResolvedInstValue(self: *Self, inst: Air.Inst.Index) MCValue { |
| 6133 | } | 6133 | } |
| 6134 | } | 6134 | } |
| 6135 | | 6135 | |
| 6136 | fn lowerDeclRef(self: *Self, tv: TypedValue, decl_index: Module.Decl.Index) InnerError!MCValue { | | |
| 6137 | const ptr_bits = self.target.cpu.arch.ptrBitWidth(); | | |
| 6138 | const ptr_bytes: u64 = @divExact(ptr_bits, 8); | | |
| 6139 | | | |
| 6140 | // TODO this feels clunky. Perhaps we should check for it in `genTypedValue`? | | |
| 6141 | if (tv.ty.zigTypeTag() == .Pointer) blk: { | | |
| 6142 | if (tv.ty.castPtrToFn()) |_| break :blk; | | |
| 6143 | if (!tv.ty.elemType2().hasRuntimeBits()) { | | |
| 6144 | return MCValue.none; | | |
| 6145 | } | | |
| 6146 | } | | |
| 6147 | | | |
| 6148 | const mod = self.bin_file.options.module.?; | | |
| 6149 | const decl = mod.declPtr(decl_index); | | |
| 6150 | mod.markDeclAlive(decl); | | |
| 6151 | | | |
| 6152 | if (self.bin_file.cast(link.File.Elf)) |elf_file| { | | |
| 6153 | const atom_index = try elf_file.getOrCreateAtomForDecl(decl_index); | | |
| 6154 | const atom = elf_file.getAtom(atom_index); | | |
| 6155 | return MCValue{ .memory = atom.getOffsetTableAddress(elf_file) }; | | |
| 6156 | } else if (self.bin_file.cast(link.File.MachO)) |macho_file| { | | |
| 6157 | const atom = try macho_file.getOrCreateAtomForDecl(decl_index); | | |
| 6158 | const sym_index = macho_file.getAtom(atom).getSymbolIndex().?; | | |
| 6159 | return MCValue{ .linker_load = .{ | | |
| 6160 | .type = .got, | | |
| 6161 | .sym_index = sym_index, | | |
| 6162 | } }; | | |
| 6163 | } else if (self.bin_file.cast(link.File.Coff)) |coff_file| { | | |
| 6164 | const atom_index = try coff_file.getOrCreateAtomForDecl(decl_index); | | |
| 6165 | const sym_index = coff_file.getAtom(atom_index).getSymbolIndex().?; | | |
| 6166 | return MCValue{ .linker_load = .{ | | |
| 6167 | .type = .got, | | |
| 6168 | .sym_index = sym_index, | | |
| 6169 | } }; | | |
| 6170 | } else if (self.bin_file.cast(link.File.Plan9)) |p9| { | | |
| 6171 | const decl_block_index = try p9.seeDecl(decl_index); | | |
| 6172 | const decl_block = p9.getDeclBlock(decl_block_index); | | |
| 6173 | const got_addr = p9.bases.data + decl_block.got_index.? * ptr_bytes; | | |
| 6174 | return MCValue{ .memory = got_addr }; | | |
| 6175 | } else { | | |
| 6176 | return self.fail("TODO codegen non-ELF const Decl pointer", .{}); | | |
| 6177 | } | | |
| 6178 | } | | |
| 6179 | | | |
| 6180 | fn lowerUnnamedConst(self: *Self, tv: TypedValue) InnerError!MCValue { | | |
| 6181 | log.debug("lowerUnnamedConst: ty = {}, val = {}", .{ tv.ty.fmtDebug(), tv.val.fmtDebug() }); | | |
| 6182 | const local_sym_index = self.bin_file.lowerUnnamedConst(tv, self.mod_fn.owner_decl) catch |err| { | | |
| 6183 | return self.fail("lowering unnamed constant failed: {s}", .{@errorName(err)}); | | |
| 6184 | }; | | |
| 6185 | if (self.bin_file.cast(link.File.Elf)) |elf_file| { | | |
| 6186 | return MCValue{ .memory = elf_file.getSymbol(local_sym_index).st_value }; | | |
| 6187 | } else if (self.bin_file.cast(link.File.MachO)) |_| { | | |
| 6188 | return MCValue{ .linker_load = .{ | | |
| 6189 | .type = .direct, | | |
| 6190 | .sym_index = local_sym_index, | | |
| 6191 | } }; | | |
| 6192 | } else if (self.bin_file.cast(link.File.Coff)) |_| { | | |
| 6193 | return MCValue{ .linker_load = .{ | | |
| 6194 | .type = .direct, | | |
| 6195 | .sym_index = local_sym_index, | | |
| 6196 | } }; | | |
| 6197 | } else if (self.bin_file.cast(link.File.Plan9)) |_| { | | |
| 6198 | return self.fail("TODO lower unnamed const in Plan9", .{}); | | |
| 6199 | } else { | | |
| 6200 | return self.fail("TODO lower unnamed const", .{}); | | |
| 6201 | } | | |
| 6202 | } | | |
| 6203 | | | |
| 6204 | fn genTypedValue(self: *Self, arg_tv: TypedValue) InnerError!MCValue { | 6136 | fn genTypedValue(self: *Self, arg_tv: TypedValue) InnerError!MCValue { |
| 6205 | var typed_value = arg_tv; | 6137 | const mcv: MCValue = switch (try codegen.genTypedValue( |
| 6206 | if (typed_value.val.castTag(.runtime_value)) |rt| { | 6138 | self.bin_file, |
| 6207 | typed_value.val = rt.data; | 6139 | self.src_loc, |
| 6208 | } | 6140 | arg_tv, |
| 6209 | log.debug("genTypedValue: ty = {}, val = {}", .{ typed_value.ty.fmtDebug(), typed_value.val.fmtDebug() }); | 6141 | self.mod_fn.owner_decl, |
| 6210 | if (typed_value.val.isUndef()) | 6142 | )) { |
| 6211 | return MCValue{ .undef = {} }; | 6143 | .mcv => |mcv| switch (mcv) { |
| 6212 | | 6144 | .none => .none, |
| 6213 | if (typed_value.val.castTag(.decl_ref)) |payload| { | 6145 | .undef => .undef, |
| 6214 | return self.lowerDeclRef(typed_value, payload.data); | 6146 | .linker_load => |ll| .{ .linker_load = ll }, |
| 6215 | } | 6147 | .immediate => |imm| .{ .immediate = imm }, |
| 6216 | if (typed_value.val.castTag(.decl_ref_mut)) |payload| { | 6148 | .memory => |addr| .{ .memory = addr }, |
| 6217 | return self.lowerDeclRef(typed_value, payload.data.decl_index); | | |
| 6218 | } | | |
| 6219 | const target = self.target.*; | | |
| 6220 | | | |
| 6221 | switch (typed_value.ty.zigTypeTag()) { | | |
| 6222 | .Pointer => switch (typed_value.ty.ptrSize()) { | | |
| 6223 | .Slice => {}, | | |
| 6224 | else => { | | |
| 6225 | switch (typed_value.val.tag()) { | | |
| 6226 | .int_u64 => { | | |
| 6227 | return MCValue{ .immediate = typed_value.val.toUnsignedInt(target) }; | | |
| 6228 | }, | | |
| 6229 | else => {}, | | |
| 6230 | } | | |
| 6231 | }, | | |
| 6232 | }, | 6149 | }, |
| 6233 | .Int => { | 6150 | .fail => |msg| { |
| 6234 | const info = typed_value.ty.intInfo(self.target.*); | 6151 | self.err_msg = msg; |
| 6235 | if (info.bits <= 64) { | 6152 | return error.CodegenFail; |
| 6236 | const unsigned = switch (info.signedness) { | | |
| 6237 | .signed => blk: { | | |
| 6238 | const signed = typed_value.val.toSignedInt(target); | | |
| 6239 | break :blk @bitCast(u64, signed); | | |
| 6240 | }, | | |
| 6241 | .unsigned => typed_value.val.toUnsignedInt(target), | | |
| 6242 | }; | | |
| 6243 | | | |
| 6244 | return MCValue{ .immediate = unsigned }; | | |
| 6245 | } | | |
| 6246 | }, | 6153 | }, |
| 6247 | .Bool => { | 6154 | }; |
| 6248 | return MCValue{ .immediate = @boolToInt(typed_value.val.toBool()) }; | 6155 | return mcv; |
| 6249 | }, | | |
| 6250 | .Optional => { | | |
| 6251 | if (typed_value.ty.isPtrLikeOptional()) { | | |
| 6252 | if (typed_value.val.isNull()) | | |
| 6253 | return MCValue{ .immediate = 0 }; | | |
| 6254 | | | |
| 6255 | var buf: Type.Payload.ElemType = undefined; | | |
| 6256 | return self.genTypedValue(.{ | | |
| 6257 | .ty = typed_value.ty.optionalChild(&buf), | | |
| 6258 | .val = typed_value.val, | | |
| 6259 | }); | | |
| 6260 | } else if (typed_value.ty.abiSize(self.target.*) == 1) { | | |
| 6261 | return MCValue{ .immediate = @boolToInt(typed_value.val.isNull()) }; | | |
| 6262 | } | | |
| 6263 | }, | | |
| 6264 | .Enum => { | | |
| 6265 | if (typed_value.val.castTag(.enum_field_index)) |field_index| { | | |
| 6266 | switch (typed_value.ty.tag()) { | | |
| 6267 | .enum_simple => { | | |
| 6268 | return MCValue{ .immediate = field_index.data }; | | |
| 6269 | }, | | |
| 6270 | .enum_full, .enum_nonexhaustive => { | | |
| 6271 | const enum_full = typed_value.ty.cast(Type.Payload.EnumFull).?.data; | | |
| 6272 | if (enum_full.values.count() != 0) { | | |
| 6273 | const tag_val = enum_full.values.keys()[field_index.data]; | | |
| 6274 | return self.genTypedValue(.{ .ty = enum_full.tag_ty, .val = tag_val }); | | |
| 6275 | } else { | | |
| 6276 | return MCValue{ .immediate = field_index.data }; | | |
| 6277 | } | | |
| 6278 | }, | | |
| 6279 | else => unreachable, | | |
| 6280 | } | | |
| 6281 | } else { | | |
| 6282 | var int_tag_buffer: Type.Payload.Bits = undefined; | | |
| 6283 | const int_tag_ty = typed_value.ty.intTagType(&int_tag_buffer); | | |
| 6284 | return self.genTypedValue(.{ .ty = int_tag_ty, .val = typed_value.val }); | | |
| 6285 | } | | |
| 6286 | }, | | |
| 6287 | .ErrorSet => { | | |
| 6288 | switch (typed_value.val.tag()) { | | |
| 6289 | .@"error" => { | | |
| 6290 | const err_name = typed_value.val.castTag(.@"error").?.data.name; | | |
| 6291 | const module = self.bin_file.options.module.?; | | |
| 6292 | const global_error_set = module.global_error_set; | | |
| 6293 | const error_index = global_error_set.get(err_name).?; | | |
| 6294 | return MCValue{ .immediate = error_index }; | | |
| 6295 | }, | | |
| 6296 | else => { | | |
| 6297 | // In this case we are rendering an error union which has a 0 bits payload. | | |
| 6298 | return MCValue{ .immediate = 0 }; | | |
| 6299 | }, | | |
| 6300 | } | | |
| 6301 | }, | | |
| 6302 | .ErrorUnion => { | | |
| 6303 | const error_type = typed_value.ty.errorUnionSet(); | | |
| 6304 | const payload_type = typed_value.ty.errorUnionPayload(); | | |
| 6305 | | | |
| 6306 | const is_pl = typed_value.val.errorUnionIsPayload(); | | |
| 6307 | | | |
| 6308 | if (!payload_type.hasRuntimeBitsIgnoreComptime()) { | | |
| 6309 | // We use the error type directly as the type. | | |
| 6310 | const err_val = if (!is_pl) typed_value.val else Value.initTag(.zero); | | |
| 6311 | return self.genTypedValue(.{ .ty = error_type, .val = err_val }); | | |
| 6312 | } | | |
| 6313 | | | |
| 6314 | return self.lowerUnnamedConst(typed_value); | | |
| 6315 | }, | | |
| 6316 | | | |
| 6317 | .ComptimeInt => unreachable, // semantic analysis prevents this | | |
| 6318 | .ComptimeFloat => unreachable, // semantic analysis prevents this | | |
| 6319 | .Type => unreachable, | | |
| 6320 | .EnumLiteral => unreachable, | | |
| 6321 | .Void => unreachable, | | |
| 6322 | .NoReturn => unreachable, | | |
| 6323 | .Undefined => unreachable, | | |
| 6324 | .Null => unreachable, | | |
| 6325 | .Opaque => unreachable, | | |
| 6326 | | | |
| 6327 | else => {}, | | |
| 6328 | } | | |
| 6329 | | | |
| 6330 | return self.lowerUnnamedConst(typed_value); | | |
| 6331 | } | 6156 | } |
| 6332 | | 6157 | |
| 6333 | const CallMCValues = struct { | 6158 | const CallMCValues = struct { |