| ... | ... | @@ -23,6 +23,7 @@ const log = std.log.scoped(.codegen); |
| 23 | 23 | const build_options = @import("build_options"); |
| 24 | 24 | const codegen = @import("../../codegen.zig"); |
| 25 | 25 | |
| 26 | const CodeGenError = codegen.CodeGenError; |
| 26 | 27 | const Result = codegen.Result; |
| 27 | 28 | const DebugInfoOutput = codegen.DebugInfoOutput; |
| 28 | 29 | |
| ... | ... | @@ -35,7 +36,7 @@ const Instruction = abi.Instruction; |
| 35 | 36 | const callee_preserved_regs = abi.callee_preserved_regs; |
| 36 | 37 | const gp = abi.RegisterClass.gp; |
| 37 | 38 | |
| 38 | | const InnerError = codegen.CodeGenError || error{OutOfRegisters}; |
| 39 | const InnerError = CodeGenError || error{OutOfRegisters}; |
| 39 | 40 | |
| 40 | 41 | gpa: Allocator, |
| 41 | 42 | air: Air, |
| ... | ... | @@ -221,7 +222,7 @@ pub fn generate( |
| 221 | 222 | liveness: Liveness, |
| 222 | 223 | code: *std.ArrayList(u8), |
| 223 | 224 | debug_output: DebugInfoOutput, |
| 224 | | ) codegen.CodeGenError!Result { |
| 225 | ) CodeGenError!Result { |
| 225 | 226 | if (build_options.skip_non_native and builtin.cpu.arch != bin_file.options.target.cpu.arch) { |
| 226 | 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 | 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 | 2552 | fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue { |
| 2577 | | if (typed_value.val.isUndef()) |
| 2578 | | return MCValue{ .undef = {} }; |
| 2579 | | |
| 2580 | | if (typed_value.val.castTag(.decl_ref)) |payload| { |
| 2581 | | return self.lowerDeclRef(typed_value, payload.data); |
| 2582 | | } |
| 2583 | | if (typed_value.val.castTag(.decl_ref_mut)) |payload| { |
| 2584 | | return self.lowerDeclRef(typed_value, payload.data.decl_index); |
| 2585 | | } |
| 2586 | | const target = self.target.*; |
| 2587 | | const ptr_bits = self.target.cpu.arch.ptrBitWidth(); |
| 2588 | | switch (typed_value.ty.zigTypeTag()) { |
| 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) }; |
| 2553 | const mcv: MCValue = switch (try codegen.genTypedValue( |
| 2554 | self.bin_file, |
| 2555 | self.src_loc, |
| 2556 | typed_value, |
| 2557 | self.mod_fn.owner_decl, |
| 2558 | )) { |
| 2559 | .mcv => |mcv| switch (mcv) { |
| 2560 | .none => .none, |
| 2561 | .undef => .undef, |
| 2562 | .linker_load => unreachable, // TODO |
| 2563 | .immediate => |imm| .{ .immediate = imm }, |
| 2564 | .memory => |addr| .{ .memory = addr }, |
| 2617 | 2565 | }, |
| 2618 | | .Bool => { |
| 2619 | | return MCValue{ .immediate = @boolToInt(typed_value.val.toBool()) }; |
| 2566 | .fail => |msg| { |
| 2567 | self.err_msg = msg; |
| 2568 | return error.CodegenFail; |
| 2620 | 2569 | }, |
| 2621 | | .ComptimeInt => unreachable, // semantic analysis prevents this |
| 2622 | | .ComptimeFloat => unreachable, // semantic analysis prevents this |
| 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 | | } |
| 2570 | }; |
| 2571 | return mcv; |
| 2690 | 2572 | } |
| 2691 | 2573 | |
| 2692 | 2574 | const CallMCValues = struct { |