| ... | ... | @@ -24,7 +24,7 @@ const log = std.log.scoped(.codegen); |
| 24 | 24 | const build_options = @import("build_options"); |
| 25 | 25 | |
| 26 | 26 | const Result = codegen.Result; |
| 27 | | const GenerateSymbolError = codegen.GenerateSymbolError; |
| 27 | const CodeGenError = codegen.CodeGenError; |
| 28 | 28 | const DebugInfoOutput = codegen.DebugInfoOutput; |
| 29 | 29 | |
| 30 | 30 | const bits = @import("bits.zig"); |
| ... | ... | @@ -42,7 +42,7 @@ const c_abi_int_param_regs = abi.c_abi_int_param_regs; |
| 42 | 42 | const c_abi_int_return_regs = abi.c_abi_int_return_regs; |
| 43 | 43 | const gp = abi.RegisterClass.gp; |
| 44 | 44 | |
| 45 | | const InnerError = codegen.CodeGenError || error{OutOfRegisters}; |
| 45 | const InnerError = CodeGenError || error{OutOfRegisters}; |
| 46 | 46 | |
| 47 | 47 | gpa: Allocator, |
| 48 | 48 | air: Air, |
| ... | ... | @@ -339,7 +339,7 @@ pub fn generate( |
| 339 | 339 | liveness: Liveness, |
| 340 | 340 | code: *std.ArrayList(u8), |
| 341 | 341 | debug_output: DebugInfoOutput, |
| 342 | | ) GenerateSymbolError!Result { |
| 342 | ) CodeGenError!Result { |
| 343 | 343 | if (build_options.skip_non_native and builtin.cpu.arch != bin_file.options.target.cpu.arch) { |
| 344 | 344 | @panic("Attempted to compile for architecture that was disabled by build configuration"); |
| 345 | 345 | } |
| ... | ... | @@ -6083,178 +6083,26 @@ fn getResolvedInstValue(self: *Self, inst: Air.Inst.Index) MCValue { |
| 6083 | 6083 | } |
| 6084 | 6084 | } |
| 6085 | 6085 | |
| 6086 | | fn lowerDeclRef(self: *Self, tv: TypedValue, decl_index: Module.Decl.Index) InnerError!MCValue { |
| 6087 | | const ptr_bits = self.target.cpu.arch.ptrBitWidth(); |
| 6088 | | const ptr_bytes: u64 = @divExact(ptr_bits, 8); |
| 6089 | | |
| 6090 | | const mod = self.bin_file.options.module.?; |
| 6091 | | const decl = mod.declPtr(decl_index); |
| 6092 | | mod.markDeclAlive(decl); |
| 6093 | | |
| 6094 | | if (self.bin_file.cast(link.File.Elf)) |elf_file| { |
| 6095 | | const atom_index = try elf_file.getOrCreateAtomForDecl(decl_index); |
| 6096 | | const atom = elf_file.getAtom(atom_index); |
| 6097 | | return MCValue{ .memory = atom.getOffsetTableAddress(elf_file) }; |
| 6098 | | } else if (self.bin_file.cast(link.File.MachO)) |_| { |
| 6099 | | unreachable; // unsupported architecture for MachO |
| 6100 | | } else if (self.bin_file.cast(link.File.Coff)) |_| { |
| 6101 | | return self.fail("TODO codegen COFF const Decl pointer", .{}); |
| 6102 | | } else if (self.bin_file.cast(link.File.Plan9)) |p9| { |
| 6103 | | const decl_block_index = try p9.seeDecl(decl_index); |
| 6104 | | const decl_block = p9.getDeclBlock(decl_block_index); |
| 6105 | | const got_addr = p9.bases.data + decl_block.got_index.? * ptr_bytes; |
| 6106 | | return MCValue{ .memory = got_addr }; |
| 6107 | | } else { |
| 6108 | | return self.fail("TODO codegen non-ELF const Decl pointer", .{}); |
| 6109 | | } |
| 6110 | | |
| 6111 | | _ = tv; |
| 6112 | | } |
| 6113 | | |
| 6114 | | fn lowerUnnamedConst(self: *Self, tv: TypedValue) InnerError!MCValue { |
| 6115 | | const local_sym_index = self.bin_file.lowerUnnamedConst(tv, self.mod_fn.owner_decl) catch |err| { |
| 6116 | | return self.fail("lowering unnamed constant failed: {s}", .{@errorName(err)}); |
| 6117 | | }; |
| 6118 | | if (self.bin_file.cast(link.File.Elf)) |elf_file| { |
| 6119 | | return MCValue{ .memory = elf_file.getSymbol(local_sym_index).st_value }; |
| 6120 | | } else if (self.bin_file.cast(link.File.MachO)) |_| { |
| 6121 | | unreachable; |
| 6122 | | } else if (self.bin_file.cast(link.File.Coff)) |_| { |
| 6123 | | return self.fail("TODO lower unnamed const in COFF", .{}); |
| 6124 | | } else if (self.bin_file.cast(link.File.Plan9)) |_| { |
| 6125 | | return self.fail("TODO lower unnamed const in Plan9", .{}); |
| 6126 | | } else { |
| 6127 | | return self.fail("TODO lower unnamed const", .{}); |
| 6128 | | } |
| 6129 | | } |
| 6130 | | |
| 6131 | 6086 | fn genTypedValue(self: *Self, arg_tv: TypedValue) InnerError!MCValue { |
| 6132 | | var typed_value = arg_tv; |
| 6133 | | if (typed_value.val.castTag(.runtime_value)) |rt| { |
| 6134 | | typed_value.val = rt.data; |
| 6135 | | } |
| 6136 | | log.debug("genTypedValue: ty = {}, val = {}", .{ typed_value.ty.fmtDebug(), typed_value.val.fmtDebug() }); |
| 6137 | | if (typed_value.val.isUndef()) |
| 6138 | | return MCValue{ .undef = {} }; |
| 6139 | | const ptr_bits = self.target.cpu.arch.ptrBitWidth(); |
| 6140 | | |
| 6141 | | if (typed_value.val.castTag(.decl_ref)) |payload| { |
| 6142 | | return self.lowerDeclRef(typed_value, payload.data); |
| 6143 | | } |
| 6144 | | if (typed_value.val.castTag(.decl_ref_mut)) |payload| { |
| 6145 | | return self.lowerDeclRef(typed_value, payload.data.decl_index); |
| 6146 | | } |
| 6147 | | const target = self.target.*; |
| 6148 | | |
| 6149 | | switch (typed_value.ty.zigTypeTag()) { |
| 6150 | | .Pointer => switch (typed_value.ty.ptrSize()) { |
| 6151 | | .Slice => {}, |
| 6152 | | else => { |
| 6153 | | switch (typed_value.val.tag()) { |
| 6154 | | .int_u64 => { |
| 6155 | | return MCValue{ .immediate = @intCast(u32, typed_value.val.toUnsignedInt(target)) }; |
| 6156 | | }, |
| 6157 | | else => {}, |
| 6158 | | } |
| 6159 | | }, |
| 6087 | const mcv: MCValue = switch (try codegen.genTypedValue( |
| 6088 | self.bin_file, |
| 6089 | self.src_loc, |
| 6090 | arg_tv, |
| 6091 | self.mod_fn.owner_decl, |
| 6092 | )) { |
| 6093 | .mcv => |mcv| switch (mcv) { |
| 6094 | .none => .none, |
| 6095 | .undef => .undef, |
| 6096 | .linker_load => unreachable, // TODO |
| 6097 | .immediate => |imm| .{ .immediate = @truncate(u32, imm) }, |
| 6098 | .memory => |addr| .{ .memory = addr }, |
| 6160 | 6099 | }, |
| 6161 | | .Int => { |
| 6162 | | const info = typed_value.ty.intInfo(self.target.*); |
| 6163 | | if (info.bits <= ptr_bits) { |
| 6164 | | const unsigned = switch (info.signedness) { |
| 6165 | | .signed => blk: { |
| 6166 | | const signed = @intCast(i32, typed_value.val.toSignedInt(target)); |
| 6167 | | break :blk @bitCast(u32, signed); |
| 6168 | | }, |
| 6169 | | .unsigned => @intCast(u32, typed_value.val.toUnsignedInt(target)), |
| 6170 | | }; |
| 6171 | | |
| 6172 | | return MCValue{ .immediate = unsigned }; |
| 6173 | | } else { |
| 6174 | | return self.lowerUnnamedConst(typed_value); |
| 6175 | | } |
| 6176 | | }, |
| 6177 | | .Bool => { |
| 6178 | | return MCValue{ .immediate = @boolToInt(typed_value.val.toBool()) }; |
| 6179 | | }, |
| 6180 | | .Optional => { |
| 6181 | | if (typed_value.ty.isPtrLikeOptional()) { |
| 6182 | | if (typed_value.val.isNull()) |
| 6183 | | return MCValue{ .immediate = 0 }; |
| 6184 | | |
| 6185 | | var buf: Type.Payload.ElemType = undefined; |
| 6186 | | return self.genTypedValue(.{ |
| 6187 | | .ty = typed_value.ty.optionalChild(&buf), |
| 6188 | | .val = typed_value.val, |
| 6189 | | }); |
| 6190 | | } else if (typed_value.ty.abiSize(self.target.*) == 1) { |
| 6191 | | return MCValue{ .immediate = @boolToInt(typed_value.val.isNull()) }; |
| 6192 | | } |
| 6193 | | }, |
| 6194 | | .Enum => { |
| 6195 | | if (typed_value.val.castTag(.enum_field_index)) |field_index| { |
| 6196 | | switch (typed_value.ty.tag()) { |
| 6197 | | .enum_simple => { |
| 6198 | | return MCValue{ .immediate = field_index.data }; |
| 6199 | | }, |
| 6200 | | .enum_full, .enum_nonexhaustive => { |
| 6201 | | const enum_full = typed_value.ty.cast(Type.Payload.EnumFull).?.data; |
| 6202 | | if (enum_full.values.count() != 0) { |
| 6203 | | const tag_val = enum_full.values.keys()[field_index.data]; |
| 6204 | | return self.genTypedValue(.{ .ty = enum_full.tag_ty, .val = tag_val }); |
| 6205 | | } else { |
| 6206 | | return MCValue{ .immediate = field_index.data }; |
| 6207 | | } |
| 6208 | | }, |
| 6209 | | else => unreachable, |
| 6210 | | } |
| 6211 | | } else { |
| 6212 | | var int_tag_buffer: Type.Payload.Bits = undefined; |
| 6213 | | const int_tag_ty = typed_value.ty.intTagType(&int_tag_buffer); |
| 6214 | | return self.genTypedValue(.{ .ty = int_tag_ty, .val = typed_value.val }); |
| 6215 | | } |
| 6216 | | }, |
| 6217 | | .ErrorSet => { |
| 6218 | | switch (typed_value.val.tag()) { |
| 6219 | | .@"error" => { |
| 6220 | | const err_name = typed_value.val.castTag(.@"error").?.data.name; |
| 6221 | | const module = self.bin_file.options.module.?; |
| 6222 | | const global_error_set = module.global_error_set; |
| 6223 | | const error_index = global_error_set.get(err_name).?; |
| 6224 | | return MCValue{ .immediate = error_index }; |
| 6225 | | }, |
| 6226 | | else => { |
| 6227 | | // In this case we are rendering an error union which has a 0 bits payload. |
| 6228 | | return MCValue{ .immediate = 0 }; |
| 6229 | | }, |
| 6230 | | } |
| 6100 | .fail => |msg| { |
| 6101 | self.err_msg = msg; |
| 6102 | return error.CodegenFail; |
| 6231 | 6103 | }, |
| 6232 | | .ErrorUnion => { |
| 6233 | | const error_type = typed_value.ty.errorUnionSet(); |
| 6234 | | const payload_type = typed_value.ty.errorUnionPayload(); |
| 6235 | | const is_pl = typed_value.val.errorUnionIsPayload(); |
| 6236 | | |
| 6237 | | if (!payload_type.hasRuntimeBitsIgnoreComptime()) { |
| 6238 | | // We use the error type directly as the type. |
| 6239 | | const err_val = if (!is_pl) typed_value.val else Value.initTag(.zero); |
| 6240 | | return self.genTypedValue(.{ .ty = error_type, .val = err_val }); |
| 6241 | | } |
| 6242 | | }, |
| 6243 | | |
| 6244 | | .ComptimeInt => unreachable, // semantic analysis prevents this |
| 6245 | | .ComptimeFloat => unreachable, // semantic analysis prevents this |
| 6246 | | .Type => unreachable, |
| 6247 | | .EnumLiteral => unreachable, |
| 6248 | | .Void => unreachable, |
| 6249 | | .NoReturn => unreachable, |
| 6250 | | .Undefined => unreachable, |
| 6251 | | .Null => unreachable, |
| 6252 | | .Opaque => unreachable, |
| 6253 | | |
| 6254 | | else => {}, |
| 6255 | | } |
| 6256 | | |
| 6257 | | return self.lowerUnnamedConst(typed_value); |
| 6104 | }; |
| 6105 | return mcv; |
| 6258 | 6106 | } |
| 6259 | 6107 | |
| 6260 | 6108 | const CallMCValues = struct { |