| ... | @@ -23,6 +23,7 @@ const log = std.log.scoped(.codegen); | ... | @@ -23,6 +23,7 @@ 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 | const codegen = @import("../../codegen.zig"); |
| 25 | | 25 | |
| | 26 | const CodeGenError = codegen.CodeGenError; |
| 26 | const Result = codegen.Result; | 27 | const Result = codegen.Result; |
| 27 | const DebugInfoOutput = codegen.DebugInfoOutput; | 28 | const DebugInfoOutput = codegen.DebugInfoOutput; |
| 28 | | 29 | |
| ... | @@ -35,7 +36,7 @@ const Instruction = abi.Instruction; | ... | @@ -35,7 +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 = codegen.CodeGenError || error{OutOfRegisters}; | 39 | const InnerError = CodeGenError || error{OutOfRegisters}; |
| 39 | | 40 | |
| 40 | gpa: Allocator, | 41 | gpa: Allocator, |
| 41 | air: Air, | 42 | air: Air, |
| ... | @@ -221,7 +222,7 @@ pub fn generate( | ... | @@ -221,7 +222,7 @@ pub fn generate( |
| 221 | liveness: Liveness, | 222 | liveness: Liveness, |
| 222 | code: *std.ArrayList(u8), | 223 | code: *std.ArrayList(u8), |
| 223 | debug_output: DebugInfoOutput, | 224 | debug_output: DebugInfoOutput, |
| 224 | ) codegen.CodeGenError!Result { | 225 | ) CodeGenError!Result { |
| 225 | 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) { |
| 226 | @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"); |
| 227 | } | 228 | } |
| ... | @@ -2548,145 +2549,26 @@ fn getResolvedInstValue(self: *Self, inst: Air.Inst.Index) MCValue { | ... | @@ -2548,145 +2549,26 @@ fn getResolvedInstValue(self: *Self, inst: Air.Inst.Index) MCValue { |
| 2548 | } | 2549 | } |
| 2549 | } | 2550 | } |
| 2550 | | 2551 | |
| 2551 | fn lowerDeclRef(self: *Self, tv: TypedValue, decl_index: Module.Decl.Index) InnerError!MCValue { | | |
| 2552 | const ptr_bits = self.target.cpu.arch.ptrBitWidth(); | | |
| 2553 | const ptr_bytes: u64 = @divExact(ptr_bits, 8); | | |
| 2554 | const mod = self.bin_file.options.module.?; | | |
| 2555 | const decl = mod.declPtr(decl_index); | | |
| 2556 | mod.markDeclAlive(decl); | | |
| 2557 | if (self.bin_file.cast(link.File.Elf)) |elf_file| { | | |
| 2558 | const atom_index = try elf_file.getOrCreateAtomForDecl(decl_index); | | |
| 2559 | const atom = elf_file.getAtom(atom_index); | | |
| 2560 | return MCValue{ .memory = atom.getOffsetTableAddress(elf_file) }; | | |
| 2561 | } else if (self.bin_file.cast(link.File.MachO)) |_| { | | |
| 2562 | unreachable; | | |
| 2563 | } else if (self.bin_file.cast(link.File.Coff)) |_| { | | |
| 2564 | return self.fail("TODO codegen COFF const Decl pointer", .{}); | | |
| 2565 | } else if (self.bin_file.cast(link.File.Plan9)) |p9| { | | |
| 2566 | const decl_block_index = try p9.seeDecl(decl_index); | | |
| 2567 | const decl_block = p9.getDeclBlock(decl_block_index); | | |
| 2568 | const got_addr = p9.bases.data + decl_block.got_index.? * ptr_bytes; | | |
| 2569 | return MCValue{ .memory = got_addr }; | | |
| 2570 | } else { | | |
| 2571 | return self.fail("TODO codegen non-ELF const Decl pointer", .{}); | | |
| 2572 | } | | |
| 2573 | _ = tv; | | |
| 2574 | } | | |
| 2575 | | | |
| 2576 | fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue { | 2552 | fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue { |
| 2577 | if (typed_value.val.isUndef()) | 2553 | const mcv: MCValue = switch (try codegen.genTypedValue( |
| 2578 | return MCValue{ .undef = {} }; | 2554 | self.bin_file, |
| 2579 | | 2555 | self.src_loc, |
| 2580 | if (typed_value.val.castTag(.decl_ref)) |payload| { | 2556 | typed_value, |
| 2581 | return self.lowerDeclRef(typed_value, payload.data); | 2557 | self.mod_fn.owner_decl, |
| 2582 | } | 2558 | )) { |
| 2583 | if (typed_value.val.castTag(.decl_ref_mut)) |payload| { | 2559 | .mcv => |mcv| switch (mcv) { |
| 2584 | return self.lowerDeclRef(typed_value, payload.data.decl_index); | 2560 | .none => .none, |
| 2585 | } | 2561 | .undef => .undef, |
| 2586 | const target = self.target.*; | 2562 | .linker_load => unreachable, // TODO |
| 2587 | const ptr_bits = self.target.cpu.arch.ptrBitWidth(); | 2563 | .immediate => |imm| .{ .immediate = imm }, |
| 2588 | switch (typed_value.ty.zigTypeTag()) { | 2564 | .memory => |addr| .{ .memory = addr }, |
| 2589 | .Pointer => switch (typed_value.ty.ptrSize()) { | | |
| 2590 | .Slice => { | | |
| 2591 | var buf: Type.SlicePtrFieldTypeBuffer = undefined; | | |
| 2592 | const ptr_type = typed_value.ty.slicePtrFieldType(&buf); | | |
| 2593 | const ptr_mcv = try self.genTypedValue(.{ .ty = ptr_type, .val = typed_value.val }); | | |
| 2594 | const mod = self.bin_file.options.module.?; | | |
| 2595 | const slice_len = typed_value.val.sliceLen(mod); | | |
| 2596 | // Codegen can't handle some kinds of indirection. If the wrong union field is accessed here it may mean | | |
| 2597 | // the Sema code needs to use anonymous Decls or alloca instructions to store data. | | |
| 2598 | const ptr_imm = ptr_mcv.memory; | | |
| 2599 | _ = slice_len; | | |
| 2600 | _ = ptr_imm; | | |
| 2601 | // We need more general support for const data being stored in memory to make this work. | | |
| 2602 | return self.fail("TODO codegen for const slices", .{}); | | |
| 2603 | }, | | |
| 2604 | else => { | | |
| 2605 | if (typed_value.val.tag() == .int_u64) { | | |
| 2606 | return MCValue{ .immediate = typed_value.val.toUnsignedInt(target) }; | | |
| 2607 | } | | |
| 2608 | return self.fail("TODO codegen more kinds of const pointers", .{}); | | |
| 2609 | }, | | |
| 2610 | }, | | |
| 2611 | .Int => { | | |
| 2612 | const info = typed_value.ty.intInfo(self.target.*); | | |
| 2613 | if (info.bits > ptr_bits or info.signedness == .signed) { | | |
| 2614 | return self.fail("TODO const int bigger than ptr and signed int", .{}); | | |
| 2615 | } | | |
| 2616 | return MCValue{ .immediate = typed_value.val.toUnsignedInt(target) }; | | |
| 2617 | }, | 2565 | }, |
| 2618 | .Bool => { | 2566 | .fail => |msg| { |
| 2619 | return MCValue{ .immediate = @boolToInt(typed_value.val.toBool()) }; | 2567 | self.err_msg = msg; |
| | 2568 | return error.CodegenFail; |
| 2620 | }, | 2569 | }, |
| 2621 | .ComptimeInt => unreachable, // semantic analysis prevents this | 2570 | }; |
| 2622 | .ComptimeFloat => unreachable, // semantic analysis prevents this | 2571 | return mcv; |
| 2623 | .Optional => { | | |
| 2624 | if (typed_value.ty.isPtrLikeOptional()) { | | |
| 2625 | if (typed_value.val.isNull()) | | |
| 2626 | return MCValue{ .immediate = 0 }; | | |
| 2627 | | | |
| 2628 | var buf: Type.Payload.ElemType = undefined; | | |
| 2629 | return self.genTypedValue(.{ | | |
| 2630 | .ty = typed_value.ty.optionalChild(&buf), | | |
| 2631 | .val = typed_value.val, | | |
| 2632 | }); | | |
| 2633 | } else if (typed_value.ty.abiSize(self.target.*) == 1) { | | |
| 2634 | return MCValue{ .immediate = @boolToInt(typed_value.val.isNull()) }; | | |
| 2635 | } | | |
| 2636 | return self.fail("TODO non pointer optionals", .{}); | | |
| 2637 | }, | | |
| 2638 | .Enum => { | | |
| 2639 | if (typed_value.val.castTag(.enum_field_index)) |field_index| { | | |
| 2640 | switch (typed_value.ty.tag()) { | | |
| 2641 | .enum_simple => { | | |
| 2642 | return MCValue{ .immediate = field_index.data }; | | |
| 2643 | }, | | |
| 2644 | .enum_full, .enum_nonexhaustive => { | | |
| 2645 | const enum_full = typed_value.ty.cast(Type.Payload.EnumFull).?.data; | | |
| 2646 | if (enum_full.values.count() != 0) { | | |
| 2647 | const tag_val = enum_full.values.keys()[field_index.data]; | | |
| 2648 | return self.genTypedValue(.{ .ty = enum_full.tag_ty, .val = tag_val }); | | |
| 2649 | } else { | | |
| 2650 | return MCValue{ .immediate = field_index.data }; | | |
| 2651 | } | | |
| 2652 | }, | | |
| 2653 | else => unreachable, | | |
| 2654 | } | | |
| 2655 | } else { | | |
| 2656 | var int_tag_buffer: Type.Payload.Bits = undefined; | | |
| 2657 | const int_tag_ty = typed_value.ty.intTagType(&int_tag_buffer); | | |
| 2658 | return self.genTypedValue(.{ .ty = int_tag_ty, .val = typed_value.val }); | | |
| 2659 | } | | |
| 2660 | }, | | |
| 2661 | .ErrorSet => { | | |
| 2662 | switch (typed_value.val.tag()) { | | |
| 2663 | .@"error" => { | | |
| 2664 | const err_name = typed_value.val.castTag(.@"error").?.data.name; | | |
| 2665 | const module = self.bin_file.options.module.?; | | |
| 2666 | const global_error_set = module.global_error_set; | | |
| 2667 | const error_index = global_error_set.get(err_name).?; | | |
| 2668 | return MCValue{ .immediate = error_index }; | | |
| 2669 | }, | | |
| 2670 | else => { | | |
| 2671 | // In this case we are rendering an error union which has a 0 bits payload. | | |
| 2672 | return MCValue{ .immediate = 0 }; | | |
| 2673 | }, | | |
| 2674 | } | | |
| 2675 | }, | | |
| 2676 | .ErrorUnion => { | | |
| 2677 | const error_type = typed_value.ty.errorUnionSet(); | | |
| 2678 | const payload_type = typed_value.ty.errorUnionPayload(); | | |
| 2679 | const sub_val = typed_value.val.castTag(.eu_payload).?.data; | | |
| 2680 | | | |
| 2681 | if (!payload_type.hasRuntimeBits()) { | | |
| 2682 | // We use the error type directly as the type. | | |
| 2683 | return self.genTypedValue(.{ .ty = error_type, .val = sub_val }); | | |
| 2684 | } | | |
| 2685 | | | |
| 2686 | return self.fail("TODO implement error union const of type '{}'", .{typed_value.ty.fmtDebug()}); | | |
| 2687 | }, | | |
| 2688 | else => return self.fail("TODO implement const of type '{}'", .{typed_value.ty.fmtDebug()}), | | |
| 2689 | } | | |
| 2690 | } | 2572 | } |
| 2691 | | 2573 | |
| 2692 | const CallMCValues = struct { | 2574 | const CallMCValues = struct { |