| ... | @@ -160,6 +160,7 @@ pub fn targetTriple(allocator: Allocator, target: std.Target) ![:0]u8 { | ... | @@ -160,6 +160,7 @@ pub fn targetTriple(allocator: Allocator, target: std.Target) ![:0]u8 { |
| 160 | } | 160 | } |
| 161 | | 161 | |
| 162 | pub const Object = struct { | 162 | pub const Object = struct { |
| | 163 | gpa: Allocator, |
| 163 | llvm_module: *const llvm.Module, | 164 | llvm_module: *const llvm.Module, |
| 164 | di_builder: ?*llvm.DIBuilder, | 165 | di_builder: ?*llvm.DIBuilder, |
| 165 | /// One of these mappings: | 166 | /// One of these mappings: |
| ... | @@ -171,6 +172,7 @@ pub const Object = struct { | ... | @@ -171,6 +172,7 @@ pub const Object = struct { |
| 171 | context: *const llvm.Context, | 172 | context: *const llvm.Context, |
| 172 | target_machine: *const llvm.TargetMachine, | 173 | target_machine: *const llvm.TargetMachine, |
| 173 | target_data: *const llvm.TargetData, | 174 | target_data: *const llvm.TargetData, |
| | 175 | target: std.Target, |
| 174 | /// Ideally we would use `llvm_module.getNamedFunction` to go from *Decl to LLVM function, | 176 | /// Ideally we would use `llvm_module.getNamedFunction` to go from *Decl to LLVM function, |
| 175 | /// but that has some downsides: | 177 | /// but that has some downsides: |
| 176 | /// * we have to compute the fully qualified name every time we want to do the lookup | 178 | /// * we have to compute the fully qualified name every time we want to do the lookup |
| ... | @@ -202,11 +204,13 @@ pub const Object = struct { | ... | @@ -202,11 +204,13 @@ pub const Object = struct { |
| 202 | std.hash_map.default_max_load_percentage, | 204 | std.hash_map.default_max_load_percentage, |
| 203 | ); | 205 | ); |
| 204 | | 206 | |
| 205 | pub const DITypeMap = std.HashMapUnmanaged( | 207 | /// This is an ArrayHashMap as opposed to a HashMap because in `flushModule` we |
| | 208 | /// want to iterate over it while adding entries to it. |
| | 209 | pub const DITypeMap = std.ArrayHashMapUnmanaged( |
| 206 | Type, | 210 | Type, |
| 207 | *llvm.DIType, | 211 | AnnotatedDITypePtr, |
| 208 | Type.HashContext64, | 212 | Type.HashContext32, |
| 209 | std.hash_map.default_max_load_percentage, | 213 | true, |
| 210 | ); | 214 | ); |
| 211 | | 215 | |
| 212 | pub fn create(gpa: Allocator, options: link.Options) !*Object { | 216 | pub fn create(gpa: Allocator, options: link.Options) !*Object { |
| ... | @@ -335,6 +339,7 @@ pub const Object = struct { | ... | @@ -335,6 +339,7 @@ pub const Object = struct { |
| 335 | llvm_module.setModuleDataLayout(target_data); | 339 | llvm_module.setModuleDataLayout(target_data); |
| 336 | | 340 | |
| 337 | return Object{ | 341 | return Object{ |
| | 342 | .gpa = gpa, |
| 338 | .llvm_module = llvm_module, | 343 | .llvm_module = llvm_module, |
| 339 | .di_map = .{}, | 344 | .di_map = .{}, |
| 340 | .di_builder = opt_di_builder, | 345 | .di_builder = opt_di_builder, |
| ... | @@ -342,6 +347,7 @@ pub const Object = struct { | ... | @@ -342,6 +347,7 @@ pub const Object = struct { |
| 342 | .context = context, | 347 | .context = context, |
| 343 | .target_machine = target_machine, | 348 | .target_machine = target_machine, |
| 344 | .target_data = target_data, | 349 | .target_data = target_data, |
| | 350 | .target = options.target, |
| 345 | .decl_map = .{}, | 351 | .decl_map = .{}, |
| 346 | .type_map = .{}, | 352 | .type_map = .{}, |
| 347 | .type_map_arena = std.heap.ArenaAllocator.init(gpa), | 353 | .type_map_arena = std.heap.ArenaAllocator.init(gpa), |
| ... | @@ -437,7 +443,25 @@ pub const Object = struct { | ... | @@ -437,7 +443,25 @@ pub const Object = struct { |
| 437 | pub fn flushModule(self: *Object, comp: *Compilation) !void { | 443 | pub fn flushModule(self: *Object, comp: *Compilation) !void { |
| 438 | try self.genErrorNameTable(comp); | 444 | try self.genErrorNameTable(comp); |
| 439 | | 445 | |
| 440 | if (self.di_builder) |dib| dib.finalize(); | 446 | if (self.di_builder) |dib| { |
| | 447 | // When lowering debug info for pointers, we emitted the element types as |
| | 448 | // forward decls. Now we must go flesh those out. |
| | 449 | // Here we iterate over a hash map while modifying it but it is OK because |
| | 450 | // we never add or remove entries during this loop. |
| | 451 | var i: usize = 0; |
| | 452 | while (i < self.di_type_map.count()) : (i += 1) { |
| | 453 | const value_ptr = &self.di_type_map.values()[i]; |
| | 454 | const annotated = value_ptr.*; |
| | 455 | if (!annotated.isFwdOnly()) continue; |
| | 456 | const entry: Object.DITypeMap.Entry = .{ |
| | 457 | .key_ptr = &self.di_type_map.keys()[i], |
| | 458 | .value_ptr = value_ptr, |
| | 459 | }; |
| | 460 | _ = try self.lowerDebugTypeImpl(entry, .full, annotated.toDIType()); |
| | 461 | } |
| | 462 | |
| | 463 | dib.finalize(); |
| | 464 | } |
| 441 | | 465 | |
| 442 | if (comp.verbose_llvm_ir) { | 466 | if (comp.verbose_llvm_ir) { |
| 443 | self.llvm_module.dump(); | 467 | self.llvm_module.dump(); |
| ... | @@ -503,7 +527,7 @@ pub const Object = struct { | ... | @@ -503,7 +527,7 @@ pub const Object = struct { |
| 503 | } | 527 | } |
| 504 | | 528 | |
| 505 | pub fn updateFunc( | 529 | pub fn updateFunc( |
| 506 | self: *Object, | 530 | o: *Object, |
| 507 | module: *Module, | 531 | module: *Module, |
| 508 | func: *Module.Fn, | 532 | func: *Module.Fn, |
| 509 | air: Air, | 533 | air: Air, |
| ... | @@ -512,8 +536,8 @@ pub const Object = struct { | ... | @@ -512,8 +536,8 @@ pub const Object = struct { |
| 512 | const decl = func.owner_decl; | 536 | const decl = func.owner_decl; |
| 513 | | 537 | |
| 514 | var dg: DeclGen = .{ | 538 | var dg: DeclGen = .{ |
| 515 | .context = self.context, | 539 | .context = o.context, |
| 516 | .object = self, | 540 | .object = o, |
| 517 | .module = module, | 541 | .module = module, |
| 518 | .decl = decl, | 542 | .decl = decl, |
| 519 | .err_msg = null, | 543 | .err_msg = null, |
| ... | @@ -584,7 +608,7 @@ pub const Object = struct { | ... | @@ -584,7 +608,7 @@ pub const Object = struct { |
| 584 | llvm_func.getValueName(), | 608 | llvm_func.getValueName(), |
| 585 | di_file.?, | 609 | di_file.?, |
| 586 | line_number, | 610 | line_number, |
| 587 | try dg.lowerDebugType(decl.ty), | 611 | try o.lowerDebugType(decl.ty, .full), |
| 588 | is_internal_linkage, | 612 | is_internal_linkage, |
| 589 | true, // is definition | 613 | true, // is definition |
| 590 | line_number + func.lbrace_line, // scope line | 614 | line_number + func.lbrace_line, // scope line |
| ... | @@ -631,7 +655,7 @@ pub const Object = struct { | ... | @@ -631,7 +655,7 @@ pub const Object = struct { |
| 631 | }; | 655 | }; |
| 632 | | 656 | |
| 633 | const decl_exports = module.decl_exports.get(decl) orelse &[0]*Module.Export{}; | 657 | const decl_exports = module.decl_exports.get(decl) orelse &[0]*Module.Export{}; |
| 634 | try self.updateDeclExports(module, decl, decl_exports); | 658 | try o.updateDeclExports(module, decl, decl_exports); |
| 635 | } | 659 | } |
| 636 | | 660 | |
| 637 | pub fn updateDecl(self: *Object, module: *Module, decl: *Module.Decl) !void { | 661 | pub fn updateDecl(self: *Object, module: *Module, decl: *Module.Decl) !void { |
| ... | @@ -773,622 +797,811 @@ pub const Object = struct { | ... | @@ -773,622 +797,811 @@ pub const Object = struct { |
| 773 | gop.value_ptr.* = di_file.toNode(); | 797 | gop.value_ptr.* = di_file.toNode(); |
| 774 | return di_file; | 798 | return di_file; |
| 775 | } | 799 | } |
| 776 | }; | | |
| 777 | | 800 | |
| 778 | pub const DeclGen = struct { | 801 | const DebugResolveStatus = enum { fwd, full }; |
| 779 | context: *const llvm.Context, | | |
| 780 | object: *Object, | | |
| 781 | module: *Module, | | |
| 782 | decl: *Module.Decl, | | |
| 783 | gpa: Allocator, | | |
| 784 | err_msg: ?*Module.ErrorMsg, | | |
| 785 | | 802 | |
| 786 | fn todo(self: *DeclGen, comptime format: []const u8, args: anytype) Error { | 803 | /// In the implementation of this function, it is required to store a forward decl |
| 787 | @setCold(true); | 804 | /// into `gop` before making any recursive calls (even directly). |
| 788 | assert(self.err_msg == null); | 805 | fn lowerDebugType( |
| 789 | const src_loc = @as(LazySrcLoc, .{ .node_offset = 0 }).toSrcLoc(self.decl); | 806 | o: *Object, |
| 790 | self.err_msg = try Module.ErrorMsg.create(self.gpa, src_loc, "TODO (LLVM): " ++ format, args); | 807 | ty: Type, |
| 791 | return error.CodegenFail; | 808 | resolve: DebugResolveStatus, |
| 792 | } | 809 | ) Allocator.Error!*llvm.DIType { |
| | 810 | const gpa = o.gpa; |
| | 811 | // Be careful not to reference this `gop` variable after any recursive calls |
| | 812 | // to `lowerDebugType`. |
| | 813 | const gop = try o.di_type_map.getOrPut(gpa, ty); |
| | 814 | if (gop.found_existing) { |
| | 815 | const annotated = gop.value_ptr.*; |
| | 816 | const di_type = annotated.toDIType(); |
| | 817 | if (!annotated.isFwdOnly() or resolve == .fwd) { |
| | 818 | return di_type; |
| | 819 | } |
| | 820 | const entry: Object.DITypeMap.Entry = .{ |
| | 821 | .key_ptr = gop.key_ptr, |
| | 822 | .value_ptr = gop.value_ptr, |
| | 823 | }; |
| | 824 | return o.lowerDebugTypeImpl(entry, resolve, di_type); |
| | 825 | } |
| | 826 | errdefer assert(o.di_type_map.orderedRemove(ty)); |
| | 827 | // The Type memory is ephemeral; since we want to store a longer-lived |
| | 828 | // reference, we need to copy it here. |
| | 829 | gop.key_ptr.* = try ty.copy(o.type_map_arena.allocator()); |
| | 830 | const entry: Object.DITypeMap.Entry = .{ |
| | 831 | .key_ptr = gop.key_ptr, |
| | 832 | .value_ptr = gop.value_ptr, |
| | 833 | }; |
| | 834 | return o.lowerDebugTypeImpl(entry, resolve, null); |
| | 835 | } |
| | 836 | |
| | 837 | /// This is a helper function used by `lowerDebugType`. |
| | 838 | fn lowerDebugTypeImpl( |
| | 839 | o: *Object, |
| | 840 | gop: Object.DITypeMap.Entry, |
| | 841 | resolve: DebugResolveStatus, |
| | 842 | opt_fwd_decl: ?*llvm.DIType, |
| | 843 | ) Allocator.Error!*llvm.DIType { |
| | 844 | const ty = gop.key_ptr.*; |
| | 845 | const gpa = o.gpa; |
| | 846 | const target = o.target; |
| | 847 | const dib = o.di_builder.?; |
| | 848 | switch (ty.zigTypeTag()) { |
| | 849 | .Void, .NoReturn => { |
| | 850 | const di_type = dib.createBasicType("void", 0, DW.ATE.signed); |
| | 851 | gop.value_ptr.* = AnnotatedDITypePtr.initFull(di_type); |
| | 852 | return di_type; |
| | 853 | }, |
| | 854 | .Int => { |
| | 855 | const info = ty.intInfo(target); |
| | 856 | assert(info.bits != 0); |
| | 857 | const name = try ty.nameAlloc(gpa); |
| | 858 | defer gpa.free(name); |
| | 859 | const dwarf_encoding: c_uint = switch (info.signedness) { |
| | 860 | .signed => DW.ATE.signed, |
| | 861 | .unsigned => DW.ATE.unsigned, |
| | 862 | }; |
| | 863 | const di_type = dib.createBasicType(name, info.bits, dwarf_encoding); |
| | 864 | gop.value_ptr.* = AnnotatedDITypePtr.initFull(di_type); |
| | 865 | return di_type; |
| | 866 | }, |
| | 867 | .Enum => { |
| | 868 | const owner_decl = ty.getOwnerDecl(); |
| 793 | | 869 | |
| 794 | fn llvmModule(self: *DeclGen) *const llvm.Module { | 870 | if (!ty.hasRuntimeBitsIgnoreComptime()) { |
| 795 | return self.object.llvm_module; | 871 | const enum_di_ty = try o.makeEmptyNamespaceDIType(owner_decl); |
| 796 | } | 872 | // The recursive call to `lowerDebugType` via `makeEmptyNamespaceDIType` |
| | 873 | // means we can't use `gop` anymore. |
| | 874 | try o.di_type_map.put(gpa, ty, AnnotatedDITypePtr.initFull(enum_di_ty)); |
| | 875 | return enum_di_ty; |
| | 876 | } |
| 797 | | 877 | |
| 798 | fn genDecl(dg: *DeclGen) !void { | 878 | const field_names = ty.enumFields().keys(); |
| 799 | const decl = dg.decl; | | |
| 800 | assert(decl.has_tv); | | |
| 801 | | 879 | |
| 802 | log.debug("gen: {s} type: {}, value: {}", .{ decl.name, decl.ty, decl.val }); | 880 | const enumerators = try gpa.alloc(*llvm.DIEnumerator, field_names.len); |
| | 881 | defer gpa.free(enumerators); |
| 803 | | 882 | |
| 804 | if (decl.val.castTag(.function)) |func_payload| { | 883 | var buf_field_index: Value.Payload.U32 = .{ |
| 805 | _ = func_payload; | 884 | .base = .{ .tag = .enum_field_index }, |
| 806 | @panic("TODO llvm backend genDecl function pointer"); | 885 | .data = undefined, |
| 807 | } else if (decl.val.castTag(.extern_fn)) |extern_fn| { | 886 | }; |
| 808 | _ = try dg.resolveLlvmFunction(extern_fn.data.owner_decl); | 887 | const field_index_val = Value.initPayload(&buf_field_index.base); |
| 809 | } else { | 888 | |
| 810 | const target = dg.module.getTarget(); | 889 | for (field_names) |field_name, i| { |
| 811 | var global = try dg.resolveGlobalDecl(decl); | 890 | const field_name_z = try gpa.dupeZ(u8, field_name); |
| 812 | global.setAlignment(decl.getAlignment(target)); | 891 | defer gpa.free(field_name_z); |
| 813 | assert(decl.has_tv); | 892 | |
| 814 | const init_val = if (decl.val.castTag(.variable)) |payload| init_val: { | 893 | buf_field_index.data = @intCast(u32, i); |
| 815 | const variable = payload.data; | 894 | var buf_u64: Value.Payload.U64 = undefined; |
| 816 | break :init_val variable.init; | 895 | const field_int_val = field_index_val.enumToInt(ty, &buf_u64); |
| 817 | } else init_val: { | 896 | // See https://github.com/ziglang/zig/issues/645 |
| 818 | global.setGlobalConstant(.True); | 897 | const field_int = field_int_val.toSignedInt(); |
| 819 | break :init_val decl.val; | 898 | enumerators[i] = dib.createEnumerator(field_name_z, field_int); |
| 820 | }; | | |
| 821 | if (init_val.tag() != .unreachable_value) { | | |
| 822 | const llvm_init = try dg.genTypedValue(.{ .ty = decl.ty, .val = init_val }); | | |
| 823 | if (global.globalGetValueType() == llvm_init.typeOf()) { | | |
| 824 | global.setInitializer(llvm_init); | | |
| 825 | } else { | | |
| 826 | // LLVM does not allow us to change the type of globals. So we must | | |
| 827 | // create a new global with the correct type, copy all its attributes, | | |
| 828 | // and then update all references to point to the new global, | | |
| 829 | // delete the original, and rename the new one to the old one's name. | | |
| 830 | // This is necessary because LLVM does not support const bitcasting | | |
| 831 | // a struct with padding bytes, which is needed to lower a const union value | | |
| 832 | // to LLVM, when a field other than the most-aligned is active. Instead, | | |
| 833 | // we must lower to an unnamed struct, and pointer cast at usage sites | | |
| 834 | // of the global. Such an unnamed struct is the cause of the global type | | |
| 835 | // mismatch, because we don't have the LLVM type until the *value* is created, | | |
| 836 | // whereas the global needs to be created based on the type alone, because | | |
| 837 | // lowering the value may reference the global as a pointer. | | |
| 838 | const new_global = dg.object.llvm_module.addGlobalInAddressSpace( | | |
| 839 | llvm_init.typeOf(), | | |
| 840 | "", | | |
| 841 | dg.llvmAddressSpace(decl.@"addrspace"), | | |
| 842 | ); | | |
| 843 | new_global.setLinkage(global.getLinkage()); | | |
| 844 | new_global.setUnnamedAddr(global.getUnnamedAddress()); | | |
| 845 | new_global.setAlignment(global.getAlignment()); | | |
| 846 | new_global.setInitializer(llvm_init); | | |
| 847 | // replaceAllUsesWith requires the type to be unchanged. So we bitcast | | |
| 848 | // the new global to the old type and use that as the thing to replace | | |
| 849 | // old uses. | | |
| 850 | const new_global_ptr = new_global.constBitCast(global.typeOf()); | | |
| 851 | global.replaceAllUsesWith(new_global_ptr); | | |
| 852 | dg.object.decl_map.putAssumeCapacity(decl, new_global); | | |
| 853 | new_global.takeName(global); | | |
| 854 | global.deleteGlobal(); | | |
| 855 | global = new_global; | | |
| 856 | } | 899 | } |
| 857 | } | | |
| 858 | | 900 | |
| 859 | if (dg.object.di_builder) |dib| { | 901 | const di_file = try o.getDIFile(gpa, owner_decl.src_namespace.file_scope); |
| 860 | const di_file = try dg.object.getDIFile(dg.gpa, decl.src_namespace.file_scope); | 902 | const di_scope = try o.namespaceToDebugScope(owner_decl.src_namespace); |
| 861 | | 903 | |
| 862 | const line_number = decl.src_line + 1; | 904 | const name = try ty.nameAlloc(gpa); |
| 863 | const is_internal_linkage = !dg.module.decl_exports.contains(decl); | 905 | defer gpa.free(name); |
| 864 | const di_global = dib.createGlobalVariable( | 906 | var buffer: Type.Payload.Bits = undefined; |
| 865 | di_file.toScope(), | 907 | const int_ty = ty.intTagType(&buffer); |
| 866 | decl.name, | 908 | |
| 867 | global.getValueName(), | 909 | const enum_di_ty = dib.createEnumerationType( |
| | 910 | di_scope, |
| | 911 | name, |
| 868 | di_file, | 912 | di_file, |
| 869 | line_number, | 913 | owner_decl.src_node + 1, |
| 870 | try dg.lowerDebugType(decl.ty), | 914 | ty.abiSize(target) * 8, |
| 871 | is_internal_linkage, | 915 | ty.abiAlignment(target) * 8, |
| | 916 | enumerators.ptr, |
| | 917 | @intCast(c_int, enumerators.len), |
| | 918 | try o.lowerDebugType(int_ty, .full), |
| | 919 | "", |
| 872 | ); | 920 | ); |
| | 921 | // The recursive call to `lowerDebugType` means we can't use `gop` anymore. |
| | 922 | try o.di_type_map.put(gpa, ty, AnnotatedDITypePtr.initFull(enum_di_ty)); |
| | 923 | return enum_di_ty; |
| | 924 | }, |
| | 925 | .Float => { |
| | 926 | const bits = ty.floatBits(target); |
| | 927 | const name = try ty.nameAlloc(gpa); |
| | 928 | defer gpa.free(name); |
| | 929 | const di_type = dib.createBasicType(name, bits, DW.ATE.float); |
| | 930 | gop.value_ptr.* = AnnotatedDITypePtr.initFull(di_type); |
| | 931 | return di_type; |
| | 932 | }, |
| | 933 | .Bool => { |
| | 934 | const di_type = dib.createBasicType("bool", 1, DW.ATE.boolean); |
| | 935 | gop.value_ptr.* = AnnotatedDITypePtr.initFull(di_type); |
| | 936 | return di_type; |
| | 937 | }, |
| | 938 | .Pointer => { |
| | 939 | // Normalize everything that the debug info does not represent. |
| | 940 | const ptr_info = ty.ptrInfo().data; |
| 873 | | 941 | |
| 874 | try dg.object.di_map.put(dg.gpa, dg.decl, di_global.toNode()); | 942 | if (ptr_info.sentinel != null or |
| 875 | } | 943 | ptr_info.@"addrspace" != .generic or |
| 876 | } | 944 | ptr_info.bit_offset != 0 or |
| 877 | } | 945 | ptr_info.host_size != 0 or |
| | 946 | ptr_info.@"allowzero" or |
| | 947 | !ptr_info.mutable or |
| | 948 | ptr_info.@"volatile" or |
| | 949 | ptr_info.size == .Many or ptr_info.size == .C or |
| | 950 | !ptr_info.pointee_type.hasRuntimeBitsIgnoreComptime()) |
| | 951 | { |
| | 952 | var payload: Type.Payload.Pointer = .{ |
| | 953 | .data = .{ |
| | 954 | .pointee_type = ptr_info.pointee_type, |
| | 955 | .sentinel = null, |
| | 956 | .@"align" = ptr_info.@"align", |
| | 957 | .@"addrspace" = .generic, |
| | 958 | .bit_offset = 0, |
| | 959 | .host_size = 0, |
| | 960 | .@"allowzero" = false, |
| | 961 | .mutable = true, |
| | 962 | .@"volatile" = false, |
| | 963 | .size = switch (ptr_info.size) { |
| | 964 | .Many, .C, .One => .One, |
| | 965 | .Slice => .Slice, |
| | 966 | }, |
| | 967 | }, |
| | 968 | }; |
| | 969 | if (!ptr_info.pointee_type.hasRuntimeBitsIgnoreComptime()) { |
| | 970 | payload.data.pointee_type = Type.anyopaque; |
| | 971 | } |
| | 972 | const bland_ptr_ty = Type.initPayload(&payload.base); |
| | 973 | const ptr_di_ty = try o.lowerDebugType(bland_ptr_ty, resolve); |
| | 974 | // The recursive call to `lowerDebugType` means we can't use `gop` anymore. |
| | 975 | try o.di_type_map.put(gpa, ty, AnnotatedDITypePtr.initFull(ptr_di_ty)); |
| | 976 | return ptr_di_ty; |
| | 977 | } |
| 878 | | 978 | |
| 879 | /// If the llvm function does not exist, create it. | 979 | if (ty.isSlice()) { |
| 880 | /// Note that this can be called before the function's semantic analysis has | 980 | var buf: Type.SlicePtrFieldTypeBuffer = undefined; |
| 881 | /// completed, so if any attributes rely on that, they must be done in updateFunc, not here. | 981 | const ptr_ty = ty.slicePtrFieldType(&buf); |
| 882 | fn resolveLlvmFunction(dg: *DeclGen, decl: *Module.Decl) !*const llvm.Value { | 982 | const len_ty = Type.usize; |
| 883 | const gop = try dg.object.decl_map.getOrPut(dg.gpa, decl); | | |
| 884 | if (gop.found_existing) return gop.value_ptr.*; | | |
| 885 | | 983 | |
| 886 | assert(decl.has_tv); | 984 | const name = try ty.nameAlloc(gpa); |
| 887 | const zig_fn_type = decl.ty; | 985 | defer gpa.free(name); |
| 888 | const fn_info = zig_fn_type.fnInfo(); | 986 | const di_file: ?*llvm.DIFile = null; |
| 889 | const target = dg.module.getTarget(); | 987 | const line = 0; |
| 890 | const sret = firstParamSRet(fn_info, target); | 988 | const compile_unit_scope = o.di_compile_unit.?.toScope(); |
| 891 | | 989 | |
| 892 | const fn_type = try dg.llvmType(zig_fn_type); | 990 | const fwd_decl = opt_fwd_decl orelse blk: { |
| | 991 | const fwd_decl = dib.createReplaceableCompositeType( |
| | 992 | DW.TAG.structure_type, |
| | 993 | name.ptr, |
| | 994 | compile_unit_scope, |
| | 995 | di_file, |
| | 996 | line, |
| | 997 | ); |
| | 998 | gop.value_ptr.* = AnnotatedDITypePtr.initFwd(fwd_decl); |
| | 999 | if (resolve == .fwd) return fwd_decl; |
| | 1000 | break :blk fwd_decl; |
| | 1001 | }; |
| 893 | | 1002 | |
| 894 | const fqn = try decl.getFullyQualifiedName(dg.gpa); | 1003 | const ptr_size = ptr_ty.abiSize(target); |
| 895 | defer dg.gpa.free(fqn); | 1004 | const ptr_align = ptr_ty.abiAlignment(target); |
| | 1005 | const len_size = len_ty.abiSize(target); |
| | 1006 | const len_align = len_ty.abiAlignment(target); |
| 896 | | 1007 | |
| 897 | const llvm_addrspace = dg.llvmAddressSpace(decl.@"addrspace"); | 1008 | var offset: u64 = 0; |
| 898 | const llvm_fn = dg.llvmModule().addFunctionInAddressSpace(fqn, fn_type, llvm_addrspace); | 1009 | offset += ptr_size; |
| 899 | gop.value_ptr.* = llvm_fn; | 1010 | offset = std.mem.alignForwardGeneric(u64, offset, len_align); |
| | 1011 | const len_offset = offset; |
| 900 | | 1012 | |
| 901 | const is_extern = decl.isExtern(); | 1013 | const fields: [2]*llvm.DIType = .{ |
| 902 | if (!is_extern) { | 1014 | dib.createMemberType( |
| 903 | llvm_fn.setLinkage(.Internal); | 1015 | fwd_decl.toScope(), |
| 904 | llvm_fn.setUnnamedAddr(.True); | 1016 | "ptr", |
| 905 | } else if (dg.module.getTarget().isWasm()) { | 1017 | di_file, |
| 906 | dg.addFnAttrString(llvm_fn, "wasm-import-name", std.mem.sliceTo(decl.name, 0)); | 1018 | line, |
| 907 | if (decl.getExternFn().?.lib_name) |lib_name| { | 1019 | ptr_size * 8, // size in bits |
| 908 | const module_name = std.mem.sliceTo(lib_name, 0); | 1020 | ptr_align * 8, // align in bits |
| 909 | if (!std.mem.eql(u8, module_name, "c")) { | 1021 | 0, // offset in bits |
| 910 | dg.addFnAttrString(llvm_fn, "wasm-import-module", module_name); | 1022 | 0, // flags |
| | 1023 | try o.lowerDebugType(ptr_ty, .full), |
| | 1024 | ), |
| | 1025 | dib.createMemberType( |
| | 1026 | fwd_decl.toScope(), |
| | 1027 | "len", |
| | 1028 | di_file, |
| | 1029 | line, |
| | 1030 | len_size * 8, // size in bits |
| | 1031 | len_align * 8, // align in bits |
| | 1032 | len_offset * 8, // offset in bits |
| | 1033 | 0, // flags |
| | 1034 | try o.lowerDebugType(len_ty, .full), |
| | 1035 | ), |
| | 1036 | }; |
| | 1037 | |
| | 1038 | const full_di_ty = dib.createStructType( |
| | 1039 | compile_unit_scope, |
| | 1040 | name.ptr, |
| | 1041 | di_file, |
| | 1042 | line, |
| | 1043 | ty.abiSize(target) * 8, // size in bits |
| | 1044 | ty.abiAlignment(target) * 8, // align in bits |
| | 1045 | 0, // flags |
| | 1046 | null, // derived from |
| | 1047 | &fields, |
| | 1048 | fields.len, |
| | 1049 | 0, // run time lang |
| | 1050 | null, // vtable holder |
| | 1051 | "", // unique id |
| | 1052 | ); |
| | 1053 | dib.replaceTemporary(fwd_decl, full_di_ty); |
| | 1054 | // The recursive call to `lowerDebugType` means we can't use `gop` anymore. |
| | 1055 | try o.di_type_map.put(gpa, ty, AnnotatedDITypePtr.initFull(full_di_ty)); |
| | 1056 | return full_di_ty; |
| 911 | } | 1057 | } |
| 912 | } | | |
| 913 | } | | |
| 914 | | 1058 | |
| 915 | if (sret) { | 1059 | const elem_di_ty = try o.lowerDebugType(ptr_info.pointee_type, .fwd); |
| 916 | dg.addArgAttr(llvm_fn, 0, "nonnull"); // Sret pointers must not be address 0 | 1060 | const name = try ty.nameAlloc(gpa); |
| 917 | dg.addArgAttr(llvm_fn, 0, "noalias"); | 1061 | defer gpa.free(name); |
| | 1062 | const ptr_di_ty = dib.createPointerType( |
| | 1063 | elem_di_ty, |
| | 1064 | target.cpu.arch.ptrBitWidth(), |
| | 1065 | ty.ptrAlignment(target) * 8, |
| | 1066 | name, |
| | 1067 | ); |
| | 1068 | // The recursive call to `lowerDebugType` means we can't use `gop` anymore. |
| | 1069 | try o.di_type_map.put(gpa, ty, AnnotatedDITypePtr.initFull(ptr_di_ty)); |
| | 1070 | return ptr_di_ty; |
| | 1071 | }, |
| | 1072 | .Opaque => { |
| | 1073 | if (ty.tag() == .anyopaque) { |
| | 1074 | const di_ty = dib.createBasicType("anyopaque", 0, DW.ATE.signed); |
| | 1075 | gop.value_ptr.* = AnnotatedDITypePtr.initFull(di_ty); |
| | 1076 | return di_ty; |
| | 1077 | } |
| | 1078 | const name = try ty.nameAlloc(gpa); |
| | 1079 | defer gpa.free(name); |
| | 1080 | const owner_decl = ty.getOwnerDecl(); |
| | 1081 | const opaque_di_ty = dib.createForwardDeclType( |
| | 1082 | DW.TAG.structure_type, |
| | 1083 | name, |
| | 1084 | try o.namespaceToDebugScope(owner_decl.src_namespace), |
| | 1085 | try o.getDIFile(gpa, owner_decl.src_namespace.file_scope), |
| | 1086 | owner_decl.src_node + 1, |
| | 1087 | ); |
| | 1088 | // The recursive call to `lowerDebugType` va `namespaceToDebugScope` |
| | 1089 | // means we can't use `gop` anymore. |
| | 1090 | try o.di_type_map.put(gpa, ty, AnnotatedDITypePtr.initFull(opaque_di_ty)); |
| | 1091 | return opaque_di_ty; |
| | 1092 | }, |
| | 1093 | .Array => { |
| | 1094 | const array_di_ty = dib.createArrayType( |
| | 1095 | ty.abiSize(target) * 8, |
| | 1096 | ty.abiAlignment(target) * 8, |
| | 1097 | try o.lowerDebugType(ty.childType(), .full), |
| | 1098 | @intCast(c_int, ty.arrayLen()), |
| | 1099 | ); |
| | 1100 | // The recursive call to `lowerDebugType` means we can't use `gop` anymore. |
| | 1101 | try o.di_type_map.put(gpa, ty, AnnotatedDITypePtr.initFull(array_di_ty)); |
| | 1102 | return array_di_ty; |
| | 1103 | }, |
| | 1104 | .Vector => { |
| | 1105 | const vector_di_ty = dib.createVectorType( |
| | 1106 | ty.abiSize(target) * 8, |
| | 1107 | ty.abiAlignment(target) * 8, |
| | 1108 | try o.lowerDebugType(ty.childType(), .full), |
| | 1109 | ty.vectorLen(), |
| | 1110 | ); |
| | 1111 | // The recursive call to `lowerDebugType` means we can't use `gop` anymore. |
| | 1112 | try o.di_type_map.put(gpa, ty, AnnotatedDITypePtr.initFull(vector_di_ty)); |
| | 1113 | return vector_di_ty; |
| | 1114 | }, |
| | 1115 | .Optional => { |
| | 1116 | const name = try ty.nameAlloc(gpa); |
| | 1117 | defer gpa.free(name); |
| | 1118 | var buf: Type.Payload.ElemType = undefined; |
| | 1119 | const child_ty = ty.optionalChild(&buf); |
| | 1120 | if (!child_ty.hasRuntimeBitsIgnoreComptime()) { |
| | 1121 | const di_ty = dib.createBasicType(name, 1, DW.ATE.boolean); |
| | 1122 | gop.value_ptr.* = AnnotatedDITypePtr.initFull(di_ty); |
| | 1123 | return di_ty; |
| | 1124 | } |
| | 1125 | if (ty.isPtrLikeOptional()) { |
| | 1126 | const ptr_di_ty = try o.lowerDebugType(child_ty, resolve); |
| | 1127 | // The recursive call to `lowerDebugType` means we can't use `gop` anymore. |
| | 1128 | try o.di_type_map.put(gpa, ty, AnnotatedDITypePtr.initFull(ptr_di_ty)); |
| | 1129 | return ptr_di_ty; |
| | 1130 | } |
| 918 | | 1131 | |
| 919 | const raw_llvm_ret_ty = try dg.llvmType(fn_info.return_type); | 1132 | const di_file: ?*llvm.DIFile = null; |
| 920 | llvm_fn.addSretAttr(0, raw_llvm_ret_ty); | 1133 | const line = 0; |
| 921 | } | 1134 | const compile_unit_scope = o.di_compile_unit.?.toScope(); |
| | 1135 | const fwd_decl = opt_fwd_decl orelse blk: { |
| | 1136 | const fwd_decl = dib.createReplaceableCompositeType( |
| | 1137 | DW.TAG.structure_type, |
| | 1138 | name.ptr, |
| | 1139 | compile_unit_scope, |
| | 1140 | di_file, |
| | 1141 | line, |
| | 1142 | ); |
| | 1143 | gop.value_ptr.* = AnnotatedDITypePtr.initFwd(fwd_decl); |
| | 1144 | if (resolve == .fwd) return fwd_decl; |
| | 1145 | break :blk fwd_decl; |
| | 1146 | }; |
| 922 | | 1147 | |
| 923 | // Set parameter attributes. | 1148 | const non_null_ty = Type.bool; |
| 924 | var llvm_param_i: c_uint = @boolToInt(sret); | 1149 | const payload_size = child_ty.abiSize(target); |
| 925 | for (fn_info.param_types) |param_ty| { | 1150 | const payload_align = child_ty.abiAlignment(target); |
| 926 | if (!param_ty.hasRuntimeBitsIgnoreComptime()) continue; | 1151 | const non_null_size = non_null_ty.abiSize(target); |
| | 1152 | const non_null_align = non_null_ty.abiAlignment(target); |
| 927 | | 1153 | |
| 928 | if (isByRef(param_ty)) { | 1154 | var offset: u64 = 0; |
| 929 | dg.addArgAttr(llvm_fn, llvm_param_i, "nonnull"); | 1155 | offset += payload_size; |
| 930 | // TODO readonly, noalias, align | 1156 | offset = std.mem.alignForwardGeneric(u64, offset, non_null_align); |
| 931 | } | 1157 | const non_null_offset = offset; |
| 932 | llvm_param_i += 1; | | |
| 933 | } | | |
| 934 | | 1158 | |
| 935 | // TODO: more attributes. see codegen.cpp `make_fn_llvm_value`. | 1159 | const fields: [2]*llvm.DIType = .{ |
| 936 | if (fn_info.cc == .Naked) { | 1160 | dib.createMemberType( |
| 937 | dg.addFnAttr(llvm_fn, "naked"); | 1161 | fwd_decl.toScope(), |
| 938 | } else { | 1162 | "data", |
| 939 | llvm_fn.setFunctionCallConv(toLlvmCallConv(fn_info.cc, target)); | 1163 | di_file, |
| 940 | } | 1164 | line, |
| | 1165 | payload_size * 8, // size in bits |
| | 1166 | payload_align * 8, // align in bits |
| | 1167 | 0, // offset in bits |
| | 1168 | 0, // flags |
| | 1169 | try o.lowerDebugType(child_ty, .full), |
| | 1170 | ), |
| | 1171 | dib.createMemberType( |
| | 1172 | fwd_decl.toScope(), |
| | 1173 | "some", |
| | 1174 | di_file, |
| | 1175 | line, |
| | 1176 | non_null_size * 8, // size in bits |
| | 1177 | non_null_align * 8, // align in bits |
| | 1178 | non_null_offset * 8, // offset in bits |
| | 1179 | 0, // flags |
| | 1180 | try o.lowerDebugType(non_null_ty, .full), |
| | 1181 | ), |
| | 1182 | }; |
| 941 | | 1183 | |
| 942 | if (fn_info.alignment != 0) { | 1184 | const full_di_ty = dib.createStructType( |
| 943 | llvm_fn.setAlignment(fn_info.alignment); | 1185 | compile_unit_scope, |
| 944 | } | 1186 | name.ptr, |
| | 1187 | di_file, |
| | 1188 | line, |
| | 1189 | ty.abiSize(target) * 8, // size in bits |
| | 1190 | ty.abiAlignment(target) * 8, // align in bits |
| | 1191 | 0, // flags |
| | 1192 | null, // derived from |
| | 1193 | &fields, |
| | 1194 | fields.len, |
| | 1195 | 0, // run time lang |
| | 1196 | null, // vtable holder |
| | 1197 | "", // unique id |
| | 1198 | ); |
| | 1199 | dib.replaceTemporary(fwd_decl, full_di_ty); |
| | 1200 | // The recursive call to `lowerDebugType` means we can't use `gop` anymore. |
| | 1201 | try o.di_type_map.put(gpa, ty, AnnotatedDITypePtr.initFull(full_di_ty)); |
| | 1202 | return full_di_ty; |
| | 1203 | }, |
| | 1204 | .ErrorUnion => { |
| | 1205 | const err_set_ty = ty.errorUnionSet(); |
| | 1206 | const payload_ty = ty.errorUnionPayload(); |
| | 1207 | if (!payload_ty.hasRuntimeBitsIgnoreComptime()) { |
| | 1208 | const err_set_di_ty = try o.lowerDebugType(err_set_ty, .full); |
| | 1209 | // The recursive call to `lowerDebugType` means we can't use `gop` anymore. |
| | 1210 | try o.di_type_map.put(gpa, ty, AnnotatedDITypePtr.initFull(err_set_di_ty)); |
| | 1211 | return err_set_di_ty; |
| | 1212 | } |
| | 1213 | const name = try ty.nameAlloc(gpa); |
| | 1214 | defer gpa.free(name); |
| | 1215 | const di_file: ?*llvm.DIFile = null; |
| | 1216 | const line = 0; |
| | 1217 | const compile_unit_scope = o.di_compile_unit.?.toScope(); |
| | 1218 | const fwd_decl = opt_fwd_decl orelse blk: { |
| | 1219 | const fwd_decl = dib.createReplaceableCompositeType( |
| | 1220 | DW.TAG.structure_type, |
| | 1221 | name.ptr, |
| | 1222 | compile_unit_scope, |
| | 1223 | di_file, |
| | 1224 | line, |
| | 1225 | ); |
| | 1226 | gop.value_ptr.* = AnnotatedDITypePtr.initFwd(fwd_decl); |
| | 1227 | if (resolve == .fwd) return fwd_decl; |
| | 1228 | break :blk fwd_decl; |
| | 1229 | }; |
| 945 | | 1230 | |
| 946 | // Function attributes that are independent of analysis results of the function body. | 1231 | const err_set_size = err_set_ty.abiSize(target); |
| 947 | dg.addCommonFnAttributes(llvm_fn); | 1232 | const err_set_align = err_set_ty.abiAlignment(target); |
| | 1233 | const payload_size = payload_ty.abiSize(target); |
| | 1234 | const payload_align = payload_ty.abiAlignment(target); |
| 948 | | 1235 | |
| 949 | if (fn_info.return_type.isNoReturn()) { | 1236 | var offset: u64 = 0; |
| 950 | dg.addFnAttr(llvm_fn, "noreturn"); | 1237 | offset += err_set_size; |
| 951 | } | 1238 | offset = std.mem.alignForwardGeneric(u64, offset, payload_align); |
| | 1239 | const payload_offset = offset; |
| 952 | | 1240 | |
| 953 | return llvm_fn; | 1241 | const fields: [2]*llvm.DIType = .{ |
| 954 | } | 1242 | dib.createMemberType( |
| | 1243 | fwd_decl.toScope(), |
| | 1244 | "tag", |
| | 1245 | di_file, |
| | 1246 | line, |
| | 1247 | err_set_size * 8, // size in bits |
| | 1248 | err_set_align * 8, // align in bits |
| | 1249 | 0, // offset in bits |
| | 1250 | 0, // flags |
| | 1251 | try o.lowerDebugType(err_set_ty, .full), |
| | 1252 | ), |
| | 1253 | dib.createMemberType( |
| | 1254 | fwd_decl.toScope(), |
| | 1255 | "value", |
| | 1256 | di_file, |
| | 1257 | line, |
| | 1258 | payload_size * 8, // size in bits |
| | 1259 | payload_align * 8, // align in bits |
| | 1260 | payload_offset * 8, // offset in bits |
| | 1261 | 0, // flags |
| | 1262 | try o.lowerDebugType(payload_ty, .full), |
| | 1263 | ), |
| | 1264 | }; |
| 955 | | 1265 | |
| 956 | fn addCommonFnAttributes(dg: *DeclGen, llvm_fn: *const llvm.Value) void { | 1266 | const full_di_ty = dib.createStructType( |
| 957 | if (!dg.module.comp.bin_file.options.red_zone) { | 1267 | compile_unit_scope, |
| 958 | dg.addFnAttr(llvm_fn, "noredzone"); | 1268 | name.ptr, |
| 959 | } | 1269 | di_file, |
| 960 | if (dg.module.comp.bin_file.options.omit_frame_pointer) { | 1270 | line, |
| 961 | dg.addFnAttrString(llvm_fn, "frame-pointer", "none"); | 1271 | ty.abiSize(target) * 8, // size in bits |
| 962 | } else { | 1272 | ty.abiAlignment(target) * 8, // align in bits |
| 963 | dg.addFnAttrString(llvm_fn, "frame-pointer", "all"); | 1273 | 0, // flags |
| 964 | } | 1274 | null, // derived from |
| 965 | dg.addFnAttr(llvm_fn, "nounwind"); | 1275 | &fields, |
| 966 | if (dg.module.comp.unwind_tables) { | 1276 | fields.len, |
| 967 | dg.addFnAttr(llvm_fn, "uwtable"); | 1277 | 0, // run time lang |
| 968 | } | 1278 | null, // vtable holder |
| 969 | if (dg.module.comp.bin_file.options.skip_linker_dependencies) { | 1279 | "", // unique id |
| 970 | // The intent here is for compiler-rt and libc functions to not generate | 1280 | ); |
| 971 | // infinite recursion. For example, if we are compiling the memcpy function, | 1281 | dib.replaceTemporary(fwd_decl, full_di_ty); |
| 972 | // and llvm detects that the body is equivalent to memcpy, it may replace the | 1282 | // The recursive call to `lowerDebugType` means we can't use `gop` anymore. |
| 973 | // body of memcpy with a call to memcpy, which would then cause a stack | 1283 | try o.di_type_map.put(gpa, ty, AnnotatedDITypePtr.initFull(full_di_ty)); |
| 974 | // overflow instead of performing memcpy. | 1284 | return full_di_ty; |
| 975 | dg.addFnAttr(llvm_fn, "nobuiltin"); | | |
| 976 | } | | |
| 977 | if (dg.module.comp.bin_file.options.optimize_mode == .ReleaseSmall) { | | |
| 978 | dg.addFnAttr(llvm_fn, "minsize"); | | |
| 979 | dg.addFnAttr(llvm_fn, "optsize"); | | |
| 980 | } | | |
| 981 | if (dg.module.comp.bin_file.options.tsan) { | | |
| 982 | dg.addFnAttr(llvm_fn, "sanitize_thread"); | | |
| 983 | } | | |
| 984 | // TODO add target-cpu and target-features fn attributes | | |
| 985 | } | | |
| 986 | | | |
| 987 | fn resolveGlobalDecl(dg: *DeclGen, decl: *Module.Decl) Error!*const llvm.Value { | | |
| 988 | const gop = try dg.object.decl_map.getOrPut(dg.gpa, decl); | | |
| 989 | if (gop.found_existing) return gop.value_ptr.*; | | |
| 990 | errdefer assert(dg.object.decl_map.remove(decl)); | | |
| 991 | | | |
| 992 | const fqn = try decl.getFullyQualifiedName(dg.gpa); | | |
| 993 | defer dg.gpa.free(fqn); | | |
| 994 | | | |
| 995 | const llvm_type = try dg.llvmType(decl.ty); | | |
| 996 | const llvm_addrspace = dg.llvmAddressSpace(decl.@"addrspace"); | | |
| 997 | const llvm_global = dg.object.llvm_module.addGlobalInAddressSpace(llvm_type, fqn, llvm_addrspace); | | |
| 998 | gop.value_ptr.* = llvm_global; | | |
| 999 | | | |
| 1000 | // This is needed for declarations created by `@extern`. | | |
| 1001 | if (decl.isExtern()) { | | |
| 1002 | llvm_global.setValueName(decl.name); | | |
| 1003 | llvm_global.setUnnamedAddr(.False); | | |
| 1004 | llvm_global.setLinkage(.External); | | |
| 1005 | if (decl.val.castTag(.variable)) |variable| { | | |
| 1006 | const single_threaded = dg.module.comp.bin_file.options.single_threaded; | | |
| 1007 | if (variable.data.is_threadlocal and !single_threaded) { | | |
| 1008 | llvm_global.setThreadLocalMode(.GeneralDynamicTLSModel); | | |
| 1009 | } else { | | |
| 1010 | llvm_global.setThreadLocalMode(.NotThreadLocal); | | |
| 1011 | } | | |
| 1012 | if (variable.data.is_weak_linkage) llvm_global.setLinkage(.ExternalWeak); | | |
| 1013 | } | | |
| 1014 | } else { | | |
| 1015 | llvm_global.setLinkage(.Internal); | | |
| 1016 | llvm_global.setUnnamedAddr(.True); | | |
| 1017 | } | | |
| 1018 | | | |
| 1019 | return llvm_global; | | |
| 1020 | } | | |
| 1021 | | | |
| 1022 | fn llvmAddressSpace(self: DeclGen, address_space: std.builtin.AddressSpace) c_uint { | | |
| 1023 | const target = self.module.getTarget(); | | |
| 1024 | return switch (target.cpu.arch) { | | |
| 1025 | .i386, .x86_64 => switch (address_space) { | | |
| 1026 | .generic => llvm.address_space.default, | | |
| 1027 | .gs => llvm.address_space.x86.gs, | | |
| 1028 | .fs => llvm.address_space.x86.fs, | | |
| 1029 | .ss => llvm.address_space.x86.ss, | | |
| 1030 | else => unreachable, | | |
| 1031 | }, | | |
| 1032 | .nvptx, .nvptx64 => switch (address_space) { | | |
| 1033 | .generic => llvm.address_space.default, | | |
| 1034 | .global => llvm.address_space.nvptx.global, | | |
| 1035 | .constant => llvm.address_space.nvptx.constant, | | |
| 1036 | .param => llvm.address_space.nvptx.param, | | |
| 1037 | .shared => llvm.address_space.nvptx.shared, | | |
| 1038 | .local => llvm.address_space.nvptx.local, | | |
| 1039 | else => unreachable, | | |
| 1040 | }, | | |
| 1041 | else => switch (address_space) { | | |
| 1042 | .generic => llvm.address_space.default, | | |
| 1043 | else => unreachable, | | |
| 1044 | }, | | |
| 1045 | }; | | |
| 1046 | } | | |
| 1047 | | | |
| 1048 | fn isUnnamedType(dg: *DeclGen, ty: Type, val: *const llvm.Value) bool { | | |
| 1049 | // Once `llvmType` succeeds, successive calls to it with the same Zig type | | |
| 1050 | // are guaranteed to succeed. So if a call to `llvmType` fails here it means | | |
| 1051 | // it is the first time lowering the type, which means the value can't possible | | |
| 1052 | // have that type. | | |
| 1053 | const llvm_ty = dg.llvmType(ty) catch return true; | | |
| 1054 | return val.typeOf() != llvm_ty; | | |
| 1055 | } | | |
| 1056 | | | |
| 1057 | fn llvmType(dg: *DeclGen, t: Type) Allocator.Error!*const llvm.Type { | | |
| 1058 | const gpa = dg.gpa; | | |
| 1059 | const target = dg.module.getTarget(); | | |
| 1060 | switch (t.zigTypeTag()) { | | |
| 1061 | .Void, .NoReturn => return dg.context.voidType(), | | |
| 1062 | .Int => { | | |
| 1063 | const info = t.intInfo(target); | | |
| 1064 | assert(info.bits != 0); | | |
| 1065 | return dg.context.intType(info.bits); | | |
| 1066 | }, | | |
| 1067 | .Enum => { | | |
| 1068 | var buffer: Type.Payload.Bits = undefined; | | |
| 1069 | const int_ty = t.intTagType(&buffer); | | |
| 1070 | const bit_count = int_ty.intInfo(target).bits; | | |
| 1071 | assert(bit_count != 0); | | |
| 1072 | return dg.context.intType(bit_count); | | |
| 1073 | }, | | |
| 1074 | .Float => switch (t.floatBits(target)) { | | |
| 1075 | 16 => return dg.context.halfType(), | | |
| 1076 | 32 => return dg.context.floatType(), | | |
| 1077 | 64 => return dg.context.doubleType(), | | |
| 1078 | 80 => return if (backendSupportsF80(target)) dg.context.x86FP80Type() else dg.context.intType(80), | | |
| 1079 | 128 => return dg.context.fp128Type(), | | |
| 1080 | else => unreachable, | | |
| 1081 | }, | 1285 | }, |
| 1082 | .Bool => return dg.context.intType(1), | 1286 | .ErrorSet => { |
| 1083 | .Pointer => { | 1287 | // TODO make this a proper enum with all the error codes in it. |
| 1084 | if (t.isSlice()) { | 1288 | // will need to consider how to take incremental compilation into account. |
| 1085 | var buf: Type.SlicePtrFieldTypeBuffer = undefined; | 1289 | const di_ty = dib.createBasicType("anyerror", 16, DW.ATE.unsigned); |
| 1086 | const ptr_type = t.slicePtrFieldType(&buf); | 1290 | gop.value_ptr.* = AnnotatedDITypePtr.initFull(di_ty); |
| 1087 | | 1291 | return di_ty; |
| 1088 | const fields: [2]*const llvm.Type = .{ | | |
| 1089 | try dg.llvmType(ptr_type), | | |
| 1090 | try dg.llvmType(Type.usize), | | |
| 1091 | }; | | |
| 1092 | return dg.context.structType(&fields, fields.len, .False); | | |
| 1093 | } | | |
| 1094 | const ptr_info = t.ptrInfo().data; | | |
| 1095 | const llvm_addrspace = dg.llvmAddressSpace(ptr_info.@"addrspace"); | | |
| 1096 | if (ptr_info.host_size != 0) { | | |
| 1097 | return dg.context.intType(ptr_info.host_size * 8).pointerType(llvm_addrspace); | | |
| 1098 | } | | |
| 1099 | const elem_ty = ptr_info.pointee_type; | | |
| 1100 | const lower_elem_ty = switch (elem_ty.zigTypeTag()) { | | |
| 1101 | .Opaque, .Fn => true, | | |
| 1102 | .Array => elem_ty.childType().hasRuntimeBitsIgnoreComptime(), | | |
| 1103 | else => elem_ty.hasRuntimeBitsIgnoreComptime(), | | |
| 1104 | }; | | |
| 1105 | const llvm_elem_ty = if (lower_elem_ty) | | |
| 1106 | try dg.llvmType(elem_ty) | | |
| 1107 | else | | |
| 1108 | dg.context.intType(8); | | |
| 1109 | return llvm_elem_ty.pointerType(llvm_addrspace); | | |
| 1110 | }, | 1292 | }, |
| 1111 | .Opaque => switch (t.tag()) { | 1293 | .Struct => { |
| 1112 | .@"opaque" => { | 1294 | const compile_unit_scope = o.di_compile_unit.?.toScope(); |
| 1113 | const gop = try dg.object.type_map.getOrPut(gpa, t); | 1295 | const name = try ty.nameAlloc(gpa); |
| 1114 | if (gop.found_existing) return gop.value_ptr.*; | 1296 | defer gpa.free(name); |
| 1115 | | | |
| 1116 | // The Type memory is ephemeral; since we want to store a longer-lived | | |
| 1117 | // reference, we need to copy it here. | | |
| 1118 | gop.key_ptr.* = try t.copy(dg.object.type_map_arena.allocator()); | | |
| 1119 | | | |
| 1120 | const opaque_obj = t.castTag(.@"opaque").?.data; | | |
| 1121 | const name = try opaque_obj.getFullyQualifiedName(gpa); | | |
| 1122 | defer gpa.free(name); | | |
| 1123 | | 1297 | |
| 1124 | const llvm_struct_ty = dg.context.structCreateNamed(name); | 1298 | if (ty.castTag(.@"struct")) |payload| { |
| 1125 | gop.value_ptr.* = llvm_struct_ty; // must be done before any recursive calls | 1299 | const struct_obj = payload.data; |
| 1126 | return llvm_struct_ty; | 1300 | if (struct_obj.layout == .Packed) { |
| 1127 | }, | 1301 | var buf: Type.Payload.Bits = undefined; |
| 1128 | .anyopaque => return dg.context.intType(8), | 1302 | const info = struct_obj.packedIntegerType(target, &buf).intInfo(target); |
| 1129 | else => unreachable, | 1303 | const dwarf_encoding: c_uint = switch (info.signedness) { |
| 1130 | }, | 1304 | .signed => DW.ATE.signed, |
| 1131 | .Array => { | 1305 | .unsigned => DW.ATE.unsigned, |
| 1132 | const elem_ty = t.childType(); | 1306 | }; |
| 1133 | assert(elem_ty.onePossibleValue() == null); | 1307 | const di_ty = dib.createBasicType(name, info.bits, dwarf_encoding); |
| 1134 | const elem_llvm_ty = try dg.llvmType(elem_ty); | 1308 | gop.value_ptr.* = AnnotatedDITypePtr.initFull(di_ty); |
| 1135 | const total_len = t.arrayLen() + @boolToInt(t.sentinel() != null); | 1309 | return di_ty; |
| 1136 | return elem_llvm_ty.arrayType(@intCast(c_uint, total_len)); | 1310 | } |
| 1137 | }, | | |
| 1138 | .Vector => { | | |
| 1139 | const elem_type = try dg.llvmType(t.childType()); | | |
| 1140 | return elem_type.vectorType(t.vectorLen()); | | |
| 1141 | }, | | |
| 1142 | .Optional => { | | |
| 1143 | var buf: Type.Payload.ElemType = undefined; | | |
| 1144 | const child_ty = t.optionalChild(&buf); | | |
| 1145 | if (!child_ty.hasRuntimeBitsIgnoreComptime()) { | | |
| 1146 | return dg.context.intType(1); | | |
| 1147 | } | | |
| 1148 | const payload_llvm_ty = try dg.llvmType(child_ty); | | |
| 1149 | if (t.isPtrLikeOptional()) { | | |
| 1150 | return payload_llvm_ty; | | |
| 1151 | } | 1311 | } |
| 1152 | | 1312 | |
| 1153 | const fields: [2]*const llvm.Type = .{ | 1313 | const fwd_decl = opt_fwd_decl orelse blk: { |
| 1154 | payload_llvm_ty, dg.context.intType(1), | 1314 | const fwd_decl = dib.createReplaceableCompositeType( |
| | 1315 | DW.TAG.structure_type, |
| | 1316 | name.ptr, |
| | 1317 | compile_unit_scope, |
| | 1318 | null, // file |
| | 1319 | 0, // line |
| | 1320 | ); |
| | 1321 | gop.value_ptr.* = AnnotatedDITypePtr.initFwd(fwd_decl); |
| | 1322 | if (resolve == .fwd) return fwd_decl; |
| | 1323 | break :blk fwd_decl; |
| 1155 | }; | 1324 | }; |
| 1156 | return dg.context.structType(&fields, fields.len, .False); | | |
| 1157 | }, | | |
| 1158 | .ErrorUnion => { | | |
| 1159 | const error_type = t.errorUnionSet(); | | |
| 1160 | const payload_type = t.errorUnionPayload(); | | |
| 1161 | const llvm_error_type = try dg.llvmType(error_type); | | |
| 1162 | if (!payload_type.hasRuntimeBitsIgnoreComptime()) { | | |
| 1163 | return llvm_error_type; | | |
| 1164 | } | | |
| 1165 | const llvm_payload_type = try dg.llvmType(payload_type); | | |
| 1166 | | | |
| 1167 | const fields: [2]*const llvm.Type = .{ llvm_error_type, llvm_payload_type }; | | |
| 1168 | return dg.context.structType(&fields, fields.len, .False); | | |
| 1169 | }, | | |
| 1170 | .ErrorSet => { | | |
| 1171 | return dg.context.intType(16); | | |
| 1172 | }, | | |
| 1173 | .Struct => { | | |
| 1174 | const gop = try dg.object.type_map.getOrPut(gpa, t); | | |
| 1175 | if (gop.found_existing) return gop.value_ptr.*; | | |
| 1176 | | | |
| 1177 | // The Type memory is ephemeral; since we want to store a longer-lived | | |
| 1178 | // reference, we need to copy it here. | | |
| 1179 | gop.key_ptr.* = try t.copy(dg.object.type_map_arena.allocator()); | | |
| 1180 | | 1325 | |
| 1181 | if (t.isTupleOrAnonStruct()) { | 1326 | if (ty.isTupleOrAnonStruct()) { |
| 1182 | const tuple = t.tupleFields(); | 1327 | const tuple = ty.tupleFields(); |
| 1183 | const llvm_struct_ty = dg.context.structCreateNamed(""); | | |
| 1184 | gop.value_ptr.* = llvm_struct_ty; // must be done before any recursive calls | | |
| 1185 | | 1328 | |
| 1186 | var llvm_field_types: std.ArrayListUnmanaged(*const llvm.Type) = .{}; | 1329 | var di_fields: std.ArrayListUnmanaged(*llvm.DIType) = .{}; |
| 1187 | defer llvm_field_types.deinit(gpa); | 1330 | defer di_fields.deinit(gpa); |
| 1188 | | 1331 | |
| 1189 | try llvm_field_types.ensureUnusedCapacity(gpa, tuple.types.len); | 1332 | try di_fields.ensureUnusedCapacity(gpa, tuple.types.len); |
| 1190 | | 1333 | |
| 1191 | comptime assert(struct_layout_version == 2); | 1334 | comptime assert(struct_layout_version == 2); |
| 1192 | var offset: u64 = 0; | 1335 | var offset: u64 = 0; |
| 1193 | var big_align: u32 = 0; | | |
| 1194 | | 1336 | |
| 1195 | for (tuple.types) |field_ty, i| { | 1337 | for (tuple.types) |field_ty, i| { |
| 1196 | const field_val = tuple.values[i]; | 1338 | const field_val = tuple.values[i]; |
| 1197 | if (field_val.tag() != .unreachable_value) continue; | 1339 | if (field_val.tag() != .unreachable_value) continue; |
| 1198 | | 1340 | |
| | 1341 | const field_size = field_ty.abiSize(target); |
| 1199 | const field_align = field_ty.abiAlignment(target); | 1342 | const field_align = field_ty.abiAlignment(target); |
| 1200 | big_align = @maximum(big_align, field_align); | 1343 | const field_offset = std.mem.alignForwardGeneric(u64, offset, field_align); |
| 1201 | const prev_offset = offset; | 1344 | offset = field_offset + field_size; |
| 1202 | offset = std.mem.alignForwardGeneric(u64, offset, field_align); | | |
| 1203 | | | |
| 1204 | const padding_len = offset - prev_offset; | | |
| 1205 | if (padding_len > 0) { | | |
| 1206 | const llvm_array_ty = dg.context.intType(8).arrayType(@intCast(c_uint, padding_len)); | | |
| 1207 | try llvm_field_types.append(gpa, llvm_array_ty); | | |
| 1208 | } | | |
| 1209 | const field_llvm_ty = try dg.llvmType(field_ty); | | |
| 1210 | try llvm_field_types.append(gpa, field_llvm_ty); | | |
| 1211 | | 1345 | |
| 1212 | offset += field_ty.abiSize(target); | 1346 | const field_name = if (ty.castTag(.anon_struct)) |payload| |
| 1213 | } | 1347 | try gpa.dupeZ(u8, payload.data.names[i]) |
| 1214 | { | 1348 | else |
| 1215 | const prev_offset = offset; | 1349 | try std.fmt.allocPrintZ(gpa, "{d}", .{i}); |
| 1216 | offset = std.mem.alignForwardGeneric(u64, offset, big_align); | 1350 | defer gpa.free(field_name); |
| 1217 | const padding_len = offset - prev_offset; | 1351 | |
| 1218 | if (padding_len > 0) { | 1352 | try di_fields.append(gpa, dib.createMemberType( |
| 1219 | const llvm_array_ty = dg.context.intType(8).arrayType(@intCast(c_uint, padding_len)); | 1353 | fwd_decl.toScope(), |
| 1220 | try llvm_field_types.append(gpa, llvm_array_ty); | 1354 | field_name, |
| 1221 | } | 1355 | null, // file |
| | 1356 | 0, // line |
| | 1357 | field_size * 8, // size in bits |
| | 1358 | field_align * 8, // align in bits |
| | 1359 | field_offset * 8, // offset in bits |
| | 1360 | 0, // flags |
| | 1361 | try o.lowerDebugType(field_ty, .full), |
| | 1362 | )); |
| 1222 | } | 1363 | } |
| 1223 | | 1364 | |
| 1224 | llvm_struct_ty.structSetBody( | 1365 | const full_di_ty = dib.createStructType( |
| 1225 | llvm_field_types.items.ptr, | 1366 | compile_unit_scope, |
| 1226 | @intCast(c_uint, llvm_field_types.items.len), | 1367 | name.ptr, |
| 1227 | .False, | 1368 | null, // file |
| | 1369 | 0, // line |
| | 1370 | ty.abiSize(target) * 8, // size in bits |
| | 1371 | ty.abiAlignment(target) * 8, // align in bits |
| | 1372 | 0, // flags |
| | 1373 | null, // derived from |
| | 1374 | di_fields.items.ptr, |
| | 1375 | @intCast(c_int, di_fields.items.len), |
| | 1376 | 0, // run time lang |
| | 1377 | null, // vtable holder |
| | 1378 | "", // unique id |
| 1228 | ); | 1379 | ); |
| 1229 | | 1380 | dib.replaceTemporary(fwd_decl, full_di_ty); |
| 1230 | return llvm_struct_ty; | 1381 | // The recursive call to `lowerDebugType` means we can't use `gop` anymore. |
| | 1382 | try o.di_type_map.put(gpa, ty, AnnotatedDITypePtr.initFull(full_di_ty)); |
| | 1383 | return full_di_ty; |
| 1231 | } | 1384 | } |
| 1232 | | 1385 | |
| 1233 | const struct_obj = t.castTag(.@"struct").?.data; | 1386 | if (ty.castTag(.@"struct")) |payload| { |
| 1234 | | 1387 | const struct_obj = payload.data; |
| 1235 | if (struct_obj.layout == .Packed) { | 1388 | if (!struct_obj.haveFieldTypes()) { |
| 1236 | var buf: Type.Payload.Bits = undefined; | 1389 | // TODO: improve the frontend to populate this struct. |
| 1237 | const int_ty = struct_obj.packedIntegerType(target, &buf); | 1390 | // For now we treat it as a zero bit type. |
| 1238 | const int_llvm_ty = try dg.llvmType(int_ty); | 1391 | const owner_decl = ty.getOwnerDecl(); |
| 1239 | gop.value_ptr.* = int_llvm_ty; | 1392 | const struct_di_ty = try o.makeEmptyNamespaceDIType(owner_decl); |
| 1240 | return int_llvm_ty; | 1393 | dib.replaceTemporary(fwd_decl, struct_di_ty); |
| | 1394 | // The recursive call to `lowerDebugType` via `makeEmptyNamespaceDIType` |
| | 1395 | // means we can't use `gop` anymore. |
| | 1396 | try o.di_type_map.put(gpa, ty, AnnotatedDITypePtr.initFull(struct_di_ty)); |
| | 1397 | return struct_di_ty; |
| | 1398 | } |
| 1241 | } | 1399 | } |
| 1242 | | 1400 | |
| 1243 | const name = try struct_obj.getFullyQualifiedName(gpa); | 1401 | if (!ty.hasRuntimeBitsIgnoreComptime()) { |
| 1244 | defer gpa.free(name); | 1402 | const owner_decl = ty.getOwnerDecl(); |
| 1245 | | 1403 | const struct_di_ty = try o.makeEmptyNamespaceDIType(owner_decl); |
| 1246 | const llvm_struct_ty = dg.context.structCreateNamed(name); | 1404 | dib.replaceTemporary(fwd_decl, struct_di_ty); |
| 1247 | gop.value_ptr.* = llvm_struct_ty; // must be done before any recursive calls | 1405 | // The recursive call to `lowerDebugType` via `makeEmptyNamespaceDIType` |
| | 1406 | // means we can't use `gop` anymore. |
| | 1407 | try o.di_type_map.put(gpa, ty, AnnotatedDITypePtr.initFull(struct_di_ty)); |
| | 1408 | return struct_di_ty; |
| | 1409 | } |
| 1248 | | 1410 | |
| 1249 | assert(struct_obj.haveFieldTypes()); | 1411 | const fields = ty.structFields(); |
| 1250 | | 1412 | |
| 1251 | var llvm_field_types: std.ArrayListUnmanaged(*const llvm.Type) = .{}; | 1413 | var di_fields: std.ArrayListUnmanaged(*llvm.DIType) = .{}; |
| 1252 | defer llvm_field_types.deinit(gpa); | 1414 | defer di_fields.deinit(gpa); |
| 1253 | | 1415 | |
| 1254 | try llvm_field_types.ensureUnusedCapacity(gpa, struct_obj.fields.count()); | 1416 | try di_fields.ensureUnusedCapacity(gpa, fields.count()); |
| 1255 | | 1417 | |
| 1256 | comptime assert(struct_layout_version == 2); | 1418 | comptime assert(struct_layout_version == 2); |
| 1257 | var offset: u64 = 0; | 1419 | var offset: u64 = 0; |
| 1258 | var big_align: u32 = 0; | | |
| 1259 | | 1420 | |
| 1260 | for (struct_obj.fields.values()) |field| { | 1421 | for (fields.values()) |field, i| { |
| 1261 | if (field.is_comptime or !field.ty.hasRuntimeBitsIgnoreComptime()) continue; | 1422 | if (field.is_comptime or !field.ty.hasRuntimeBitsIgnoreComptime()) continue; |
| 1262 | | 1423 | |
| | 1424 | const field_size = field.ty.abiSize(target); |
| 1263 | const field_align = field.normalAlignment(target); | 1425 | const field_align = field.normalAlignment(target); |
| 1264 | big_align = @maximum(big_align, field_align); | 1426 | const field_offset = std.mem.alignForwardGeneric(u64, offset, field_align); |
| 1265 | const prev_offset = offset; | 1427 | offset = field_offset + field_size; |
| 1266 | offset = std.mem.alignForwardGeneric(u64, offset, field_align); | | |
| 1267 | | 1428 | |
| 1268 | const padding_len = offset - prev_offset; | 1429 | const field_name = try gpa.dupeZ(u8, fields.keys()[i]); |
| 1269 | if (padding_len > 0) { | 1430 | defer gpa.free(field_name); |
| 1270 | const llvm_array_ty = dg.context.intType(8).arrayType(@intCast(c_uint, padding_len)); | | |
| 1271 | try llvm_field_types.append(gpa, llvm_array_ty); | | |
| 1272 | } | | |
| 1273 | const field_llvm_ty = try dg.llvmType(field.ty); | | |
| 1274 | try llvm_field_types.append(gpa, field_llvm_ty); | | |
| 1275 | | 1431 | |
| 1276 | offset += field.ty.abiSize(target); | 1432 | try di_fields.append(gpa, dib.createMemberType( |
| 1277 | } | 1433 | fwd_decl.toScope(), |
| 1278 | { | 1434 | field_name, |
| 1279 | const prev_offset = offset; | 1435 | null, // file |
| 1280 | offset = std.mem.alignForwardGeneric(u64, offset, big_align); | 1436 | 0, // line |
| 1281 | const padding_len = offset - prev_offset; | 1437 | field_size * 8, // size in bits |
| 1282 | if (padding_len > 0) { | 1438 | field_align * 8, // align in bits |
| 1283 | const llvm_array_ty = dg.context.intType(8).arrayType(@intCast(c_uint, padding_len)); | 1439 | field_offset * 8, // offset in bits |
| 1284 | try llvm_field_types.append(gpa, llvm_array_ty); | 1440 | 0, // flags |
| 1285 | } | 1441 | try o.lowerDebugType(field.ty, .full), |
| | 1442 | )); |
| 1286 | } | 1443 | } |
| 1287 | | 1444 | |
| 1288 | llvm_struct_ty.structSetBody( | 1445 | const full_di_ty = dib.createStructType( |
| 1289 | llvm_field_types.items.ptr, | 1446 | compile_unit_scope, |
| 1290 | @intCast(c_uint, llvm_field_types.items.len), | 1447 | name.ptr, |
| 1291 | .False, | 1448 | null, // file |
| | 1449 | 0, // line |
| | 1450 | ty.abiSize(target) * 8, // size in bits |
| | 1451 | ty.abiAlignment(target) * 8, // align in bits |
| | 1452 | 0, // flags |
| | 1453 | null, // derived from |
| | 1454 | di_fields.items.ptr, |
| | 1455 | @intCast(c_int, di_fields.items.len), |
| | 1456 | 0, // run time lang |
| | 1457 | null, // vtable holder |
| | 1458 | "", // unique id |
| 1292 | ); | 1459 | ); |
| 1293 | | 1460 | dib.replaceTemporary(fwd_decl, full_di_ty); |
| 1294 | return llvm_struct_ty; | 1461 | // The recursive call to `lowerDebugType` means we can't use `gop` anymore. |
| | 1462 | try o.di_type_map.put(gpa, ty, AnnotatedDITypePtr.initFull(full_di_ty)); |
| | 1463 | return full_di_ty; |
| 1295 | }, | 1464 | }, |
| 1296 | .Union => { | 1465 | .Union => { |
| 1297 | const gop = try dg.object.type_map.getOrPut(gpa, t); | 1466 | const owner_decl = ty.getOwnerDecl(); |
| 1298 | if (gop.found_existing) return gop.value_ptr.*; | | |
| 1299 | | 1467 | |
| 1300 | // The Type memory is ephemeral; since we want to store a longer-lived | 1468 | const name = try ty.nameAlloc(gpa); |
| 1301 | // reference, we need to copy it here. | 1469 | defer gpa.free(name); |
| 1302 | gop.key_ptr.* = try t.copy(dg.object.type_map_arena.allocator()); | | |
| 1303 | | 1470 | |
| 1304 | const layout = t.unionGetLayout(target); | 1471 | const fwd_decl = opt_fwd_decl orelse blk: { |
| 1305 | const union_obj = t.cast(Type.Payload.Union).?.data; | 1472 | const fwd_decl = dib.createReplaceableCompositeType( |
| | 1473 | DW.TAG.structure_type, |
| | 1474 | name.ptr, |
| | 1475 | o.di_compile_unit.?.toScope(), |
| | 1476 | null, // file |
| | 1477 | 0, // line |
| | 1478 | ); |
| | 1479 | gop.value_ptr.* = AnnotatedDITypePtr.initFwd(fwd_decl); |
| | 1480 | if (resolve == .fwd) return fwd_decl; |
| | 1481 | break :blk fwd_decl; |
| | 1482 | }; |
| 1306 | | 1483 | |
| 1307 | if (layout.payload_size == 0) { | 1484 | const TODO_implement_this = true; // TODO |
| 1308 | const enum_tag_llvm_ty = try dg.llvmType(union_obj.tag_ty); | 1485 | if (TODO_implement_this or !ty.hasRuntimeBitsIgnoreComptime()) { |
| 1309 | gop.value_ptr.* = enum_tag_llvm_ty; | 1486 | const union_di_ty = try o.makeEmptyNamespaceDIType(owner_decl); |
| 1310 | return enum_tag_llvm_ty; | 1487 | dib.replaceTemporary(fwd_decl, union_di_ty); |
| | 1488 | // The recursive call to `lowerDebugType` via `makeEmptyNamespaceDIType` |
| | 1489 | // means we can't use `gop` anymore. |
| | 1490 | try o.di_type_map.put(gpa, ty, AnnotatedDITypePtr.initFull(union_di_ty)); |
| | 1491 | return union_di_ty; |
| 1311 | } | 1492 | } |
| 1312 | | 1493 | |
| 1313 | const name = try union_obj.getFullyQualifiedName(gpa); | 1494 | @panic("TODO debug info type for union"); |
| 1314 | defer gpa.free(name); | 1495 | //const gop = try o.type_map.getOrPut(gpa, ty); |
| | 1496 | //if (gop.found_existing) return gop.value_ptr.*; |
| 1315 | | 1497 | |
| 1316 | const llvm_union_ty = dg.context.structCreateNamed(name); | 1498 | //// The Type memory is ephemeral; since we want to store a longer-lived |
| 1317 | gop.value_ptr.* = llvm_union_ty; // must be done before any recursive calls | 1499 | //// reference, we need to copy it here. |
| | 1500 | //gop.key_ptr.* = try ty.copy(o.type_map_arena.allocator()); |
| 1318 | | 1501 | |
| 1319 | const aligned_field = union_obj.fields.values()[layout.most_aligned_field]; | 1502 | //const layout = ty.unionGetLayout(target); |
| 1320 | const llvm_aligned_field_ty = try dg.llvmType(aligned_field.ty); | 1503 | //const union_obj = ty.cast(Type.Payload.Union).?.data; |
| 1321 | | 1504 | |
| 1322 | const llvm_payload_ty = t: { | 1505 | //if (layout.payload_size == 0) { |
| 1323 | if (layout.most_aligned_field_size == layout.payload_size) { | 1506 | // const enum_tag_llvm_ty = try dg.llvmType(union_obj.tag_ty); |
| 1324 | break :t llvm_aligned_field_ty; | 1507 | // gop.value_ptr.* = enum_tag_llvm_ty; |
| 1325 | } | 1508 | // return enum_tag_llvm_ty; |
| 1326 | const padding_len = @intCast(c_uint, layout.payload_size - layout.most_aligned_field_size); | 1509 | //} |
| 1327 | const fields: [2]*const llvm.Type = .{ | | |
| 1328 | llvm_aligned_field_ty, | | |
| 1329 | dg.context.intType(8).arrayType(padding_len), | | |
| 1330 | }; | | |
| 1331 | break :t dg.context.structType(&fields, fields.len, .True); | | |
| 1332 | }; | | |
| 1333 | | 1510 | |
| 1334 | if (layout.tag_size == 0) { | 1511 | //const name = try union_obj.getFullyQualifiedName(gpa); |
| 1335 | var llvm_fields: [1]*const llvm.Type = .{llvm_payload_ty}; | 1512 | //defer gpa.free(name); |
| 1336 | llvm_union_ty.structSetBody(&llvm_fields, llvm_fields.len, .False); | | |
| 1337 | return llvm_union_ty; | | |
| 1338 | } | | |
| 1339 | const enum_tag_llvm_ty = try dg.llvmType(union_obj.tag_ty); | | |
| 1340 | | 1513 | |
| 1341 | // Put the tag before or after the payload depending on which one's | 1514 | //const llvm_union_ty = dg.context.structCreateNamed(name); |
| 1342 | // alignment is greater. | 1515 | //gop.value_ptr.* = llvm_union_ty; // must be done before any recursive calls |
| 1343 | var llvm_fields: [3]*const llvm.Type = undefined; | | |
| 1344 | var llvm_fields_len: c_uint = 2; | | |
| 1345 | | 1516 | |
| 1346 | if (layout.tag_align >= layout.payload_align) { | 1517 | //const aligned_field = union_obj.fields.values()[layout.most_aligned_field]; |
| 1347 | llvm_fields = .{ enum_tag_llvm_ty, llvm_payload_ty, undefined }; | 1518 | //const llvm_aligned_field_ty = try dg.llvmType(aligned_field.ty); |
| 1348 | } else { | | |
| 1349 | llvm_fields = .{ llvm_payload_ty, enum_tag_llvm_ty, undefined }; | | |
| 1350 | } | | |
| 1351 | | 1519 | |
| 1352 | // Insert padding to make the LLVM struct ABI size match the Zig union ABI size. | 1520 | //const llvm_payload_ty = ty: { |
| 1353 | if (layout.padding != 0) { | 1521 | // if (layout.most_aligned_field_size == layout.payload_size) { |
| 1354 | llvm_fields[2] = dg.context.intType(8).arrayType(layout.padding); | 1522 | // break :ty llvm_aligned_field_ty; |
| 1355 | llvm_fields_len = 3; | 1523 | // } |
| 1356 | } | 1524 | // const padding_len = @intCast(c_uint, layout.payload_size - layout.most_aligned_field_size); |
| | 1525 | // const fields: [2]*const llvm.Type = .{ |
| | 1526 | // llvm_aligned_field_ty, |
| | 1527 | // dg.context.intType(8).arrayType(padding_len), |
| | 1528 | // }; |
| | 1529 | // break :ty dg.context.structType(&fields, fields.len, .True); |
| | 1530 | //}; |
| 1357 | | 1531 | |
| 1358 | llvm_union_ty.structSetBody(&llvm_fields, llvm_fields_len, .False); | 1532 | //if (layout.tag_size == 0) { |
| 1359 | return llvm_union_ty; | 1533 | // var llvm_fields: [1]*const llvm.Type = .{llvm_payload_ty}; |
| | 1534 | // llvm_union_ty.structSetBody(&llvm_fields, llvm_fields.len, .False); |
| | 1535 | // return llvm_union_ty; |
| | 1536 | //} |
| | 1537 | //const enum_tag_llvm_ty = try dg.llvmType(union_obj.tag_ty); |
| | 1538 | |
| | 1539 | //// Put the tag before or after the payload depending on which one's |
| | 1540 | //// alignment is greater. |
| | 1541 | //var llvm_fields: [3]*const llvm.Type = undefined; |
| | 1542 | //var llvm_fields_len: c_uint = 2; |
| | 1543 | |
| | 1544 | //if (layout.tag_align >= layout.payload_align) { |
| | 1545 | // llvm_fields = .{ enum_tag_llvm_ty, llvm_payload_ty, undefined }; |
| | 1546 | //} else { |
| | 1547 | // llvm_fields = .{ llvm_payload_ty, enum_tag_llvm_ty, undefined }; |
| | 1548 | //} |
| | 1549 | |
| | 1550 | //// Insert padding to make the LLVM struct ABI size match the Zig union ABI size. |
| | 1551 | //if (layout.padding != 0) { |
| | 1552 | // llvm_fields[2] = dg.context.intType(8).arrayType(layout.padding); |
| | 1553 | // llvm_fields_len = 3; |
| | 1554 | //} |
| | 1555 | |
| | 1556 | //llvm_union_ty.structSetBody(&llvm_fields, llvm_fields_len, .False); |
| | 1557 | //return llvm_union_ty; |
| 1360 | }, | 1558 | }, |
| 1361 | .Fn => { | 1559 | .Fn => { |
| 1362 | const fn_info = t.fnInfo(); | 1560 | const fn_info = ty.fnInfo(); |
| 1363 | const sret = firstParamSRet(fn_info, target); | 1561 | const sret = firstParamSRet(fn_info, target); |
| 1364 | const return_type = fn_info.return_type; | | |
| 1365 | const llvm_sret_ty = if (return_type.hasRuntimeBitsIgnoreComptime()) | | |
| 1366 | try dg.llvmType(return_type) | | |
| 1367 | else | | |
| 1368 | dg.context.voidType(); | | |
| 1369 | const llvm_ret_ty = if (sret) dg.context.voidType() else llvm_sret_ty; | | |
| 1370 | | 1562 | |
| 1371 | var llvm_params = std.ArrayList(*const llvm.Type).init(dg.gpa); | 1563 | var param_di_types = std.ArrayList(*llvm.DIType).init(gpa); |
| 1372 | defer llvm_params.deinit(); | 1564 | defer param_di_types.deinit(); |
| 1373 | | 1565 | |
| 1374 | if (sret) { | 1566 | // Return type goes first. |
| 1375 | try llvm_params.append(llvm_sret_ty.pointerType(0)); | 1567 | const di_ret_ty = if (sret or !fn_info.return_type.hasRuntimeBitsIgnoreComptime()) |
| 1376 | } | 1568 | Type.void |
| | 1569 | else |
| | 1570 | fn_info.return_type; |
| | 1571 | try param_di_types.append(try o.lowerDebugType(di_ret_ty, .full)); |
| 1377 | | 1572 | |
| 1378 | for (fn_info.param_types) |param_ty| { | 1573 | if (sret) { |
| 1379 | if (!param_ty.hasRuntimeBitsIgnoreComptime()) continue; | 1574 | var ptr_ty_payload: Type.Payload.ElemType = .{ |
| | 1575 | .base = .{ .tag = .single_mut_pointer }, |
| | 1576 | .data = fn_info.return_type, |
| | 1577 | }; |
| | 1578 | const ptr_ty = Type.initPayload(&ptr_ty_payload.base); |
| | 1579 | try param_di_types.append(try o.lowerDebugType(ptr_ty, .full)); |
| | 1580 | } |
| 1380 | | 1581 | |
| 1381 | const raw_llvm_ty = try dg.llvmType(param_ty); | 1582 | for (fn_info.param_types) |param_ty| { |
| 1382 | const actual_llvm_ty = if (!isByRef(param_ty)) raw_llvm_ty else raw_llvm_ty.pointerType(0); | 1583 | if (!param_ty.hasRuntimeBitsIgnoreComptime()) continue; |
| 1383 | try llvm_params.append(actual_llvm_ty); | 1584 | |
| | 1585 | if (isByRef(param_ty)) { |
| | 1586 | var ptr_ty_payload: Type.Payload.ElemType = .{ |
| | 1587 | .base = .{ .tag = .single_mut_pointer }, |
| | 1588 | .data = param_ty, |
| | 1589 | }; |
| | 1590 | const ptr_ty = Type.initPayload(&ptr_ty_payload.base); |
| | 1591 | try param_di_types.append(try o.lowerDebugType(ptr_ty, .full)); |
| | 1592 | } else { |
| | 1593 | try param_di_types.append(try o.lowerDebugType(param_ty, .full)); |
| | 1594 | } |
| 1384 | } | 1595 | } |
| 1385 | | 1596 | |
| 1386 | return llvm.functionType( | 1597 | const fn_di_ty = dib.createSubroutineType( |
| 1387 | llvm_ret_ty, | 1598 | param_di_types.items.ptr, |
| 1388 | llvm_params.items.ptr, | 1599 | @intCast(c_int, param_di_types.items.len), |
| 1389 | @intCast(c_uint, llvm_params.items.len), | 1600 | 0, |
| 1390 | llvm.Bool.fromBool(fn_info.is_var_args), | | |
| 1391 | ); | 1601 | ); |
| | 1602 | // The recursive call to `lowerDebugType` means we can't use `gop` anymore. |
| | 1603 | try o.di_type_map.put(gpa, ty, AnnotatedDITypePtr.initFull(fn_di_ty)); |
| | 1604 | return fn_di_ty; |
| 1392 | }, | 1605 | }, |
| 1393 | .ComptimeInt => unreachable, | 1606 | .ComptimeInt => unreachable, |
| 1394 | .ComptimeFloat => unreachable, | 1607 | .ComptimeFloat => unreachable, |
| ... | @@ -1399,1387 +1612,1282 @@ pub const DeclGen = struct { | ... | @@ -1399,1387 +1612,1282 @@ pub const DeclGen = struct { |
| 1399 | | 1612 | |
| 1400 | .BoundFn => @panic("TODO remove BoundFn from the language"), | 1613 | .BoundFn => @panic("TODO remove BoundFn from the language"), |
| 1401 | | 1614 | |
| 1402 | .Frame => @panic("TODO implement llvmType for Frame types"), | 1615 | .Frame => @panic("TODO implement lowerDebugType for Frame types"), |
| 1403 | .AnyFrame => @panic("TODO implement llvmType for AnyFrame types"), | 1616 | .AnyFrame => @panic("TODO implement lowerDebugType for AnyFrame types"), |
| 1404 | } | 1617 | } |
| 1405 | } | 1618 | } |
| 1406 | | 1619 | |
| 1407 | fn genTypedValue(dg: *DeclGen, tv: TypedValue) Error!*const llvm.Value { | 1620 | fn namespaceToDebugScope(o: *Object, namespace: *const Module.Namespace) !*llvm.DIScope { |
| 1408 | if (tv.val.isUndef()) { | 1621 | if (namespace.parent == null) { |
| 1409 | const llvm_type = try dg.llvmType(tv.ty); | 1622 | const di_file = try o.getDIFile(o.gpa, namespace.file_scope); |
| 1410 | return llvm_type.getUndef(); | 1623 | return di_file.toScope(); |
| 1411 | } | 1624 | } |
| | 1625 | const di_type = try o.lowerDebugType(namespace.ty, .fwd); |
| | 1626 | return di_type.toScope(); |
| | 1627 | } |
| 1412 | | 1628 | |
| 1413 | switch (tv.ty.zigTypeTag()) { | 1629 | /// This is to be used instead of void for debug info types, to avoid tripping |
| 1414 | .Bool => { | 1630 | /// Assertion `!isa<DIType>(Scope) && "shouldn't make a namespace scope for a type"' |
| 1415 | const llvm_type = try dg.llvmType(tv.ty); | 1631 | /// when targeting CodeView (Windows). |
| 1416 | return if (tv.val.toBool()) llvm_type.constAllOnes() else llvm_type.constNull(); | 1632 | fn makeEmptyNamespaceDIType(o: *Object, decl: *const Module.Decl) !*llvm.DIType { |
| 1417 | }, | 1633 | const fields: [0]*llvm.DIType = .{}; |
| 1418 | // TODO this duplicates code with Pointer but they should share the handling | 1634 | return o.di_builder.?.createStructType( |
| 1419 | // of the tv.val.tag() and then Int should do extra constPtrToInt on top | 1635 | try o.namespaceToDebugScope(decl.src_namespace), |
| 1420 | .Int => switch (tv.val.tag()) { | 1636 | decl.name, // TODO use fully qualified name |
| 1421 | .decl_ref_mut => return lowerDeclRefValue(dg, tv, tv.val.castTag(.decl_ref_mut).?.data.decl), | 1637 | try o.getDIFile(o.gpa, decl.src_namespace.file_scope), |
| 1422 | .decl_ref => return lowerDeclRefValue(dg, tv, tv.val.castTag(.decl_ref).?.data), | 1638 | decl.src_line + 1, |
| 1423 | else => { | 1639 | 0, // size in bits |
| 1424 | var bigint_space: Value.BigIntSpace = undefined; | 1640 | 0, // align in bits |
| 1425 | const bigint = tv.val.toBigInt(&bigint_space); | 1641 | 0, // flags |
| 1426 | const target = dg.module.getTarget(); | 1642 | null, // derived from |
| 1427 | const int_info = tv.ty.intInfo(target); | 1643 | undefined, // TODO should be able to pass &fields, |
| 1428 | assert(int_info.bits != 0); | 1644 | fields.len, |
| 1429 | const llvm_type = dg.context.intType(int_info.bits); | 1645 | 0, // run time lang |
| | 1646 | null, // vtable holder |
| | 1647 | "", // unique id |
| | 1648 | ); |
| | 1649 | } |
| | 1650 | }; |
| 1430 | | 1651 | |
| 1431 | const unsigned_val = v: { | 1652 | pub const DeclGen = struct { |
| 1432 | if (bigint.limbs.len == 1) { | 1653 | context: *const llvm.Context, |
| 1433 | break :v llvm_type.constInt(bigint.limbs[0], .False); | 1654 | object: *Object, |
| 1434 | } | 1655 | module: *Module, |
| 1435 | if (@sizeOf(usize) == @sizeOf(u64)) { | 1656 | decl: *Module.Decl, |
| 1436 | break :v llvm_type.constIntOfArbitraryPrecision( | 1657 | gpa: Allocator, |
| 1437 | @intCast(c_uint, bigint.limbs.len), | 1658 | err_msg: ?*Module.ErrorMsg, |
| 1438 | bigint.limbs.ptr, | | |
| 1439 | ); | | |
| 1440 | } | | |
| 1441 | @panic("TODO implement bigint to llvm int for 32-bit compiler builds"); | | |
| 1442 | }; | | |
| 1443 | if (!bigint.positive) { | | |
| 1444 | return llvm.constNeg(unsigned_val); | | |
| 1445 | } | | |
| 1446 | return unsigned_val; | | |
| 1447 | }, | | |
| 1448 | }, | | |
| 1449 | .Enum => { | | |
| 1450 | var int_buffer: Value.Payload.U64 = undefined; | | |
| 1451 | const int_val = tv.enumToInt(&int_buffer); | | |
| 1452 | | 1659 | |
| 1453 | var bigint_space: Value.BigIntSpace = undefined; | 1660 | fn todo(self: *DeclGen, comptime format: []const u8, args: anytype) Error { |
| 1454 | const bigint = int_val.toBigInt(&bigint_space); | 1661 | @setCold(true); |
| | 1662 | assert(self.err_msg == null); |
| | 1663 | const src_loc = @as(LazySrcLoc, .{ .node_offset = 0 }).toSrcLoc(self.decl); |
| | 1664 | self.err_msg = try Module.ErrorMsg.create(self.gpa, src_loc, "TODO (LLVM): " ++ format, args); |
| | 1665 | return error.CodegenFail; |
| | 1666 | } |
| 1455 | | 1667 | |
| 1456 | const target = dg.module.getTarget(); | 1668 | fn llvmModule(self: *DeclGen) *const llvm.Module { |
| 1457 | const int_info = tv.ty.intInfo(target); | 1669 | return self.object.llvm_module; |
| 1458 | const llvm_type = dg.context.intType(int_info.bits); | 1670 | } |
| 1459 | | 1671 | |
| 1460 | const unsigned_val = v: { | 1672 | fn genDecl(dg: *DeclGen) !void { |
| 1461 | if (bigint.limbs.len == 1) { | 1673 | const decl = dg.decl; |
| 1462 | break :v llvm_type.constInt(bigint.limbs[0], .False); | 1674 | assert(decl.has_tv); |
| 1463 | } | 1675 | |
| 1464 | if (@sizeOf(usize) == @sizeOf(u64)) { | 1676 | log.debug("gen: {s} type: {}, value: {}", .{ decl.name, decl.ty, decl.val }); |
| 1465 | break :v llvm_type.constIntOfArbitraryPrecision( | 1677 | |
| 1466 | @intCast(c_uint, bigint.limbs.len), | 1678 | if (decl.val.castTag(.function)) |func_payload| { |
| 1467 | bigint.limbs.ptr, | 1679 | _ = func_payload; |
| 1468 | ); | 1680 | @panic("TODO llvm backend genDecl function pointer"); |
| 1469 | } | 1681 | } else if (decl.val.castTag(.extern_fn)) |extern_fn| { |
| 1470 | @panic("TODO implement bigint to llvm int for 32-bit compiler builds"); | 1682 | _ = try dg.resolveLlvmFunction(extern_fn.data.owner_decl); |
| 1471 | }; | 1683 | } else { |
| 1472 | if (!bigint.positive) { | 1684 | const target = dg.module.getTarget(); |
| 1473 | return llvm.constNeg(unsigned_val); | 1685 | var global = try dg.resolveGlobalDecl(decl); |
| 1474 | } | 1686 | global.setAlignment(decl.getAlignment(target)); |
| 1475 | return unsigned_val; | 1687 | assert(decl.has_tv); |
| 1476 | }, | 1688 | const init_val = if (decl.val.castTag(.variable)) |payload| init_val: { |
| 1477 | .Float => { | 1689 | const variable = payload.data; |
| 1478 | const llvm_ty = try dg.llvmType(tv.ty); | 1690 | break :init_val variable.init; |
| 1479 | const target = dg.module.getTarget(); | 1691 | } else init_val: { |
| 1480 | switch (tv.ty.floatBits(target)) { | 1692 | global.setGlobalConstant(.True); |
| 1481 | 16, 32, 64 => return llvm_ty.constReal(tv.val.toFloat(f64)), | 1693 | break :init_val decl.val; |
| 1482 | 80 => { | 1694 | }; |
| 1483 | const float = tv.val.toFloat(f80); | 1695 | if (init_val.tag() != .unreachable_value) { |
| 1484 | const repr = std.math.break_f80(float); | 1696 | const llvm_init = try dg.genTypedValue(.{ .ty = decl.ty, .val = init_val }); |
| 1485 | const llvm_i80 = dg.context.intType(80); | 1697 | if (global.globalGetValueType() == llvm_init.typeOf()) { |
| 1486 | var x = llvm_i80.constInt(repr.exp, .False); | 1698 | global.setInitializer(llvm_init); |
| 1487 | x = x.constShl(llvm_i80.constInt(64, .False)); | 1699 | } else { |
| 1488 | x = x.constOr(llvm_i80.constInt(repr.fraction, .False)); | 1700 | // LLVM does not allow us to change the type of globals. So we must |
| 1489 | if (backendSupportsF80(target)) { | 1701 | // create a new global with the correct type, copy all its attributes, |
| 1490 | return x.constBitCast(llvm_ty); | 1702 | // and then update all references to point to the new global, |
| 1491 | } else { | 1703 | // delete the original, and rename the new one to the old one's name. |
| 1492 | return x; | 1704 | // This is necessary because LLVM does not support const bitcasting |
| 1493 | } | 1705 | // a struct with padding bytes, which is needed to lower a const union value |
| 1494 | }, | 1706 | // to LLVM, when a field other than the most-aligned is active. Instead, |
| 1495 | 128 => { | 1707 | // we must lower to an unnamed struct, and pointer cast at usage sites |
| 1496 | var buf: [2]u64 = @bitCast([2]u64, tv.val.toFloat(f128)); | 1708 | // of the global. Such an unnamed struct is the cause of the global type |
| 1497 | // LLVM seems to require that the lower half of the f128 be placed first | 1709 | // mismatch, because we don't have the LLVM type until the *value* is created, |
| 1498 | // in the buffer. | 1710 | // whereas the global needs to be created based on the type alone, because |
| 1499 | if (native_endian == .Big) { | 1711 | // lowering the value may reference the global as a pointer. |
| 1500 | std.mem.swap(u64, &buf[0], &buf[1]); | 1712 | const new_global = dg.object.llvm_module.addGlobalInAddressSpace( |
| 1501 | } | 1713 | llvm_init.typeOf(), |
| 1502 | const int = dg.context.intType(128).constIntOfArbitraryPrecision(buf.len, &buf); | 1714 | "", |
| 1503 | return int.constBitCast(llvm_ty); | 1715 | dg.llvmAddressSpace(decl.@"addrspace"), |
| 1504 | }, | 1716 | ); |
| 1505 | else => unreachable, | 1717 | new_global.setLinkage(global.getLinkage()); |
| | 1718 | new_global.setUnnamedAddr(global.getUnnamedAddress()); |
| | 1719 | new_global.setAlignment(global.getAlignment()); |
| | 1720 | new_global.setInitializer(llvm_init); |
| | 1721 | // replaceAllUsesWith requires the type to be unchanged. So we bitcast |
| | 1722 | // the new global to the old type and use that as the thing to replace |
| | 1723 | // old uses. |
| | 1724 | const new_global_ptr = new_global.constBitCast(global.typeOf()); |
| | 1725 | global.replaceAllUsesWith(new_global_ptr); |
| | 1726 | dg.object.decl_map.putAssumeCapacity(decl, new_global); |
| | 1727 | new_global.takeName(global); |
| | 1728 | global.deleteGlobal(); |
| | 1729 | global = new_global; |
| 1506 | } | 1730 | } |
| 1507 | }, | 1731 | } |
| 1508 | .Pointer => switch (tv.val.tag()) { | | |
| 1509 | .decl_ref_mut => return lowerDeclRefValue(dg, tv, tv.val.castTag(.decl_ref_mut).?.data.decl), | | |
| 1510 | .decl_ref => return lowerDeclRefValue(dg, tv, tv.val.castTag(.decl_ref).?.data), | | |
| 1511 | .variable => { | | |
| 1512 | const decl = tv.val.castTag(.variable).?.data.owner_decl; | | |
| 1513 | decl.markAlive(); | | |
| 1514 | const val = try dg.resolveGlobalDecl(decl); | | |
| 1515 | const llvm_var_type = try dg.llvmType(tv.ty); | | |
| 1516 | const llvm_addrspace = dg.llvmAddressSpace(decl.@"addrspace"); | | |
| 1517 | const llvm_type = llvm_var_type.pointerType(llvm_addrspace); | | |
| 1518 | return val.constBitCast(llvm_type); | | |
| 1519 | }, | | |
| 1520 | .slice => { | | |
| 1521 | const slice = tv.val.castTag(.slice).?.data; | | |
| 1522 | var buf: Type.SlicePtrFieldTypeBuffer = undefined; | | |
| 1523 | const fields: [2]*const llvm.Value = .{ | | |
| 1524 | try dg.genTypedValue(.{ | | |
| 1525 | .ty = tv.ty.slicePtrFieldType(&buf), | | |
| 1526 | .val = slice.ptr, | | |
| 1527 | }), | | |
| 1528 | try dg.genTypedValue(.{ | | |
| 1529 | .ty = Type.usize, | | |
| 1530 | .val = slice.len, | | |
| 1531 | }), | | |
| 1532 | }; | | |
| 1533 | return dg.context.constStruct(&fields, fields.len, .False); | | |
| 1534 | }, | | |
| 1535 | .int_u64, .one, .int_big_positive => { | | |
| 1536 | const llvm_usize = try dg.llvmType(Type.usize); | | |
| 1537 | const llvm_int = llvm_usize.constInt(tv.val.toUnsignedInt(), .False); | | |
| 1538 | return llvm_int.constIntToPtr(try dg.llvmType(tv.ty)); | | |
| 1539 | }, | | |
| 1540 | .field_ptr, .opt_payload_ptr, .eu_payload_ptr, .elem_ptr => { | | |
| 1541 | return dg.lowerParentPtr(tv.val, tv.ty.childType()); | | |
| 1542 | }, | | |
| 1543 | .null_value, .zero => { | | |
| 1544 | const llvm_type = try dg.llvmType(tv.ty); | | |
| 1545 | return llvm_type.constNull(); | | |
| 1546 | }, | | |
| 1547 | else => |tag| return dg.todo("implement const of pointer type '{}' ({})", .{ tv.ty, tag }), | | |
| 1548 | }, | | |
| 1549 | .Array => switch (tv.val.tag()) { | | |
| 1550 | .bytes => { | | |
| 1551 | const bytes = tv.val.castTag(.bytes).?.data; | | |
| 1552 | return dg.context.constString( | | |
| 1553 | bytes.ptr, | | |
| 1554 | @intCast(c_uint, tv.ty.arrayLenIncludingSentinel()), | | |
| 1555 | .True, // don't null terminate. bytes has the sentinel, if any. | | |
| 1556 | ); | | |
| 1557 | }, | | |
| 1558 | .aggregate => { | | |
| 1559 | const elem_vals = tv.val.castTag(.aggregate).?.data; | | |
| 1560 | const elem_ty = tv.ty.elemType(); | | |
| 1561 | const gpa = dg.gpa; | | |
| 1562 | const len = @intCast(usize, tv.ty.arrayLenIncludingSentinel()); | | |
| 1563 | const llvm_elems = try gpa.alloc(*const llvm.Value, len); | | |
| 1564 | defer gpa.free(llvm_elems); | | |
| 1565 | var need_unnamed = false; | | |
| 1566 | for (elem_vals[0..len]) |elem_val, i| { | | |
| 1567 | llvm_elems[i] = try dg.genTypedValue(.{ .ty = elem_ty, .val = elem_val }); | | |
| 1568 | need_unnamed = need_unnamed or dg.isUnnamedType(elem_ty, llvm_elems[i]); | | |
| 1569 | } | | |
| 1570 | if (need_unnamed) { | | |
| 1571 | return dg.context.constStruct( | | |
| 1572 | llvm_elems.ptr, | | |
| 1573 | @intCast(c_uint, llvm_elems.len), | | |
| 1574 | .True, | | |
| 1575 | ); | | |
| 1576 | } else { | | |
| 1577 | const llvm_elem_ty = try dg.llvmType(elem_ty); | | |
| 1578 | return llvm_elem_ty.constArray( | | |
| 1579 | llvm_elems.ptr, | | |
| 1580 | @intCast(c_uint, llvm_elems.len), | | |
| 1581 | ); | | |
| 1582 | } | | |
| 1583 | }, | | |
| 1584 | .repeated => { | | |
| 1585 | const val = tv.val.castTag(.repeated).?.data; | | |
| 1586 | const elem_ty = tv.ty.elemType(); | | |
| 1587 | const sentinel = tv.ty.sentinel(); | | |
| 1588 | const len = @intCast(usize, tv.ty.arrayLen()); | | |
| 1589 | const len_including_sent = len + @boolToInt(sentinel != null); | | |
| 1590 | const gpa = dg.gpa; | | |
| 1591 | const llvm_elems = try gpa.alloc(*const llvm.Value, len_including_sent); | | |
| 1592 | defer gpa.free(llvm_elems); | | |
| 1593 | | | |
| 1594 | var need_unnamed = false; | | |
| 1595 | if (len != 0) { | | |
| 1596 | for (llvm_elems[0..len]) |*elem| { | | |
| 1597 | elem.* = try dg.genTypedValue(.{ .ty = elem_ty, .val = val }); | | |
| 1598 | } | | |
| 1599 | need_unnamed = need_unnamed or dg.isUnnamedType(elem_ty, llvm_elems[0]); | | |
| 1600 | } | | |
| 1601 | | 1732 | |
| 1602 | if (sentinel) |sent| { | 1733 | if (dg.object.di_builder) |dib| { |
| 1603 | llvm_elems[len] = try dg.genTypedValue(.{ .ty = elem_ty, .val = sent }); | 1734 | const di_file = try dg.object.getDIFile(dg.gpa, decl.src_namespace.file_scope); |
| 1604 | need_unnamed = need_unnamed or dg.isUnnamedType(elem_ty, llvm_elems[len]); | | |
| 1605 | } | | |
| 1606 | | 1735 | |
| 1607 | if (need_unnamed) { | 1736 | const line_number = decl.src_line + 1; |
| 1608 | return dg.context.constStruct( | 1737 | const is_internal_linkage = !dg.module.decl_exports.contains(decl); |
| 1609 | llvm_elems.ptr, | 1738 | const di_global = dib.createGlobalVariable( |
| 1610 | @intCast(c_uint, llvm_elems.len), | 1739 | di_file.toScope(), |
| 1611 | .True, | 1740 | decl.name, |
| 1612 | ); | 1741 | global.getValueName(), |
| 1613 | } else { | 1742 | di_file, |
| 1614 | const llvm_elem_ty = try dg.llvmType(elem_ty); | 1743 | line_number, |
| 1615 | return llvm_elem_ty.constArray( | 1744 | try dg.object.lowerDebugType(decl.ty, .full), |
| 1616 | llvm_elems.ptr, | 1745 | is_internal_linkage, |
| 1617 | @intCast(c_uint, llvm_elems.len), | 1746 | ); |
| 1618 | ); | | |
| 1619 | } | | |
| 1620 | }, | | |
| 1621 | .empty_array_sentinel => { | | |
| 1622 | const elem_ty = tv.ty.elemType(); | | |
| 1623 | const sent_val = tv.ty.sentinel().?; | | |
| 1624 | const sentinel = try dg.genTypedValue(.{ .ty = elem_ty, .val = sent_val }); | | |
| 1625 | const llvm_elems: [1]*const llvm.Value = .{sentinel}; | | |
| 1626 | const need_unnamed = dg.isUnnamedType(elem_ty, llvm_elems[0]); | | |
| 1627 | if (need_unnamed) { | | |
| 1628 | return dg.context.constStruct(&llvm_elems, llvm_elems.len, .True); | | |
| 1629 | } else { | | |
| 1630 | const llvm_elem_ty = try dg.llvmType(elem_ty); | | |
| 1631 | return llvm_elem_ty.constArray(&llvm_elems, llvm_elems.len); | | |
| 1632 | } | | |
| 1633 | }, | | |
| 1634 | else => unreachable, | | |
| 1635 | }, | | |
| 1636 | .Optional => { | | |
| 1637 | var buf: Type.Payload.ElemType = undefined; | | |
| 1638 | const payload_ty = tv.ty.optionalChild(&buf); | | |
| 1639 | const llvm_i1 = dg.context.intType(1); | | |
| 1640 | const is_pl = !tv.val.isNull(); | | |
| 1641 | const non_null_bit = if (is_pl) llvm_i1.constAllOnes() else llvm_i1.constNull(); | | |
| 1642 | if (!payload_ty.hasRuntimeBitsIgnoreComptime()) { | | |
| 1643 | return non_null_bit; | | |
| 1644 | } | | |
| 1645 | if (tv.ty.isPtrLikeOptional()) { | | |
| 1646 | if (tv.val.castTag(.opt_payload)) |payload| { | | |
| 1647 | return dg.genTypedValue(.{ .ty = payload_ty, .val = payload.data }); | | |
| 1648 | } else if (is_pl) { | | |
| 1649 | return dg.genTypedValue(.{ .ty = payload_ty, .val = tv.val }); | | |
| 1650 | } else { | | |
| 1651 | const llvm_ty = try dg.llvmType(tv.ty); | | |
| 1652 | return llvm_ty.constNull(); | | |
| 1653 | } | | |
| 1654 | } | | |
| 1655 | assert(payload_ty.zigTypeTag() != .Fn); | | |
| 1656 | const fields: [2]*const llvm.Value = .{ | | |
| 1657 | try dg.genTypedValue(.{ | | |
| 1658 | .ty = payload_ty, | | |
| 1659 | .val = if (tv.val.castTag(.opt_payload)) |pl| pl.data else Value.initTag(.undef), | | |
| 1660 | }), | | |
| 1661 | non_null_bit, | | |
| 1662 | }; | | |
| 1663 | return dg.context.constStruct(&fields, fields.len, .False); | | |
| 1664 | }, | | |
| 1665 | .Fn => { | | |
| 1666 | const fn_decl = switch (tv.val.tag()) { | | |
| 1667 | .extern_fn => tv.val.castTag(.extern_fn).?.data.owner_decl, | | |
| 1668 | .function => tv.val.castTag(.function).?.data.owner_decl, | | |
| 1669 | else => unreachable, | | |
| 1670 | }; | | |
| 1671 | fn_decl.markAlive(); | | |
| 1672 | return dg.resolveLlvmFunction(fn_decl); | | |
| 1673 | }, | | |
| 1674 | .ErrorSet => { | | |
| 1675 | const llvm_ty = try dg.llvmType(tv.ty); | | |
| 1676 | switch (tv.val.tag()) { | | |
| 1677 | .@"error" => { | | |
| 1678 | const err_name = tv.val.castTag(.@"error").?.data.name; | | |
| 1679 | const kv = try dg.module.getErrorValue(err_name); | | |
| 1680 | return llvm_ty.constInt(kv.value, .False); | | |
| 1681 | }, | | |
| 1682 | else => { | | |
| 1683 | // In this case we are rendering an error union which has a 0 bits payload. | | |
| 1684 | return llvm_ty.constNull(); | | |
| 1685 | }, | | |
| 1686 | } | | |
| 1687 | }, | | |
| 1688 | .ErrorUnion => { | | |
| 1689 | const error_type = tv.ty.errorUnionSet(); | | |
| 1690 | const payload_type = tv.ty.errorUnionPayload(); | | |
| 1691 | const is_pl = tv.val.errorUnionIsPayload(); | | |
| 1692 | | 1747 | |
| 1693 | if (!payload_type.hasRuntimeBitsIgnoreComptime()) { | 1748 | try dg.object.di_map.put(dg.gpa, dg.decl, di_global.toNode()); |
| 1694 | // We use the error type directly as the type. | 1749 | } |
| 1695 | const err_val = if (!is_pl) tv.val else Value.initTag(.zero); | 1750 | } |
| 1696 | return dg.genTypedValue(.{ .ty = error_type, .val = err_val }); | 1751 | } |
| 1697 | } | | |
| 1698 | | 1752 | |
| 1699 | const fields: [2]*const llvm.Value = .{ | 1753 | /// If the llvm function does not exist, create it. |
| 1700 | try dg.genTypedValue(.{ | 1754 | /// Note that this can be called before the function's semantic analysis has |
| 1701 | .ty = error_type, | 1755 | /// completed, so if any attributes rely on that, they must be done in updateFunc, not here. |
| 1702 | .val = if (is_pl) Value.initTag(.zero) else tv.val, | 1756 | fn resolveLlvmFunction(dg: *DeclGen, decl: *Module.Decl) !*const llvm.Value { |
| 1703 | }), | 1757 | const gop = try dg.object.decl_map.getOrPut(dg.gpa, decl); |
| 1704 | try dg.genTypedValue(.{ | 1758 | if (gop.found_existing) return gop.value_ptr.*; |
| 1705 | .ty = payload_type, | | |
| 1706 | .val = if (tv.val.castTag(.eu_payload)) |pl| pl.data else Value.initTag(.undef), | | |
| 1707 | }), | | |
| 1708 | }; | | |
| 1709 | return dg.context.constStruct(&fields, fields.len, .False); | | |
| 1710 | }, | | |
| 1711 | .Struct => { | | |
| 1712 | const llvm_struct_ty = try dg.llvmType(tv.ty); | | |
| 1713 | const field_vals = tv.val.castTag(.aggregate).?.data; | | |
| 1714 | const gpa = dg.gpa; | | |
| 1715 | const target = dg.module.getTarget(); | | |
| 1716 | | 1759 | |
| 1717 | if (tv.ty.isTupleOrAnonStruct()) { | 1760 | assert(decl.has_tv); |
| 1718 | const tuple = tv.ty.tupleFields(); | 1761 | const zig_fn_type = decl.ty; |
| 1719 | var llvm_fields: std.ArrayListUnmanaged(*const llvm.Value) = .{}; | 1762 | const fn_info = zig_fn_type.fnInfo(); |
| 1720 | defer llvm_fields.deinit(gpa); | 1763 | const target = dg.module.getTarget(); |
| | 1764 | const sret = firstParamSRet(fn_info, target); |
| 1721 | | 1765 | |
| 1722 | try llvm_fields.ensureUnusedCapacity(gpa, tuple.types.len); | 1766 | const fn_type = try dg.llvmType(zig_fn_type); |
| 1723 | | 1767 | |
| 1724 | comptime assert(struct_layout_version == 2); | 1768 | const fqn = try decl.getFullyQualifiedName(dg.gpa); |
| 1725 | var offset: u64 = 0; | 1769 | defer dg.gpa.free(fqn); |
| 1726 | var big_align: u32 = 0; | | |
| 1727 | var need_unnamed = false; | | |
| 1728 | | 1770 | |
| 1729 | for (tuple.types) |field_ty, i| { | 1771 | const llvm_addrspace = dg.llvmAddressSpace(decl.@"addrspace"); |
| 1730 | if (tuple.values[i].tag() != .unreachable_value) continue; | 1772 | const llvm_fn = dg.llvmModule().addFunctionInAddressSpace(fqn, fn_type, llvm_addrspace); |
| 1731 | if (!field_ty.hasRuntimeBitsIgnoreComptime()) continue; | 1773 | gop.value_ptr.* = llvm_fn; |
| 1732 | | 1774 | |
| 1733 | const field_align = field_ty.abiAlignment(target); | 1775 | const is_extern = decl.isExtern(); |
| 1734 | big_align = @maximum(big_align, field_align); | 1776 | if (!is_extern) { |
| 1735 | const prev_offset = offset; | 1777 | llvm_fn.setLinkage(.Internal); |
| 1736 | offset = std.mem.alignForwardGeneric(u64, offset, field_align); | 1778 | llvm_fn.setUnnamedAddr(.True); |
| | 1779 | } else if (dg.module.getTarget().isWasm()) { |
| | 1780 | dg.addFnAttrString(llvm_fn, "wasm-import-name", std.mem.sliceTo(decl.name, 0)); |
| | 1781 | if (decl.getExternFn().?.lib_name) |lib_name| { |
| | 1782 | const module_name = std.mem.sliceTo(lib_name, 0); |
| | 1783 | if (!std.mem.eql(u8, module_name, "c")) { |
| | 1784 | dg.addFnAttrString(llvm_fn, "wasm-import-module", module_name); |
| | 1785 | } |
| | 1786 | } |
| | 1787 | } |
| 1737 | | 1788 | |
| 1738 | const padding_len = offset - prev_offset; | 1789 | if (sret) { |
| 1739 | if (padding_len > 0) { | 1790 | dg.addArgAttr(llvm_fn, 0, "nonnull"); // Sret pointers must not be address 0 |
| 1740 | const llvm_array_ty = dg.context.intType(8).arrayType(@intCast(c_uint, padding_len)); | 1791 | dg.addArgAttr(llvm_fn, 0, "noalias"); |
| 1741 | // TODO make this and all other padding elsewhere in debug | | |
| 1742 | // builds be 0xaa not undef. | | |
| 1743 | llvm_fields.appendAssumeCapacity(llvm_array_ty.getUndef()); | | |
| 1744 | } | | |
| 1745 | | 1792 | |
| 1746 | const field_llvm_val = try dg.genTypedValue(.{ | 1793 | const raw_llvm_ret_ty = try dg.llvmType(fn_info.return_type); |
| 1747 | .ty = field_ty, | 1794 | llvm_fn.addSretAttr(0, raw_llvm_ret_ty); |
| 1748 | .val = field_vals[i], | 1795 | } |
| 1749 | }); | | |
| 1750 | | 1796 | |
| 1751 | need_unnamed = need_unnamed or dg.isUnnamedType(field_ty, field_llvm_val); | 1797 | // Set parameter attributes. |
| 1752 | | 1798 | var llvm_param_i: c_uint = @boolToInt(sret); |
| 1753 | llvm_fields.appendAssumeCapacity(field_llvm_val); | 1799 | for (fn_info.param_types) |param_ty| { |
| | 1800 | if (!param_ty.hasRuntimeBitsIgnoreComptime()) continue; |
| 1754 | | 1801 | |
| 1755 | offset += field_ty.abiSize(target); | 1802 | if (isByRef(param_ty)) { |
| 1756 | } | 1803 | dg.addArgAttr(llvm_fn, llvm_param_i, "nonnull"); |
| 1757 | { | 1804 | // TODO readonly, noalias, align |
| 1758 | const prev_offset = offset; | 1805 | } |
| 1759 | offset = std.mem.alignForwardGeneric(u64, offset, big_align); | 1806 | llvm_param_i += 1; |
| 1760 | const padding_len = offset - prev_offset; | 1807 | } |
| 1761 | if (padding_len > 0) { | | |
| 1762 | const llvm_array_ty = dg.context.intType(8).arrayType(@intCast(c_uint, padding_len)); | | |
| 1763 | llvm_fields.appendAssumeCapacity(llvm_array_ty.getUndef()); | | |
| 1764 | } | | |
| 1765 | } | | |
| 1766 | | 1808 | |
| 1767 | if (need_unnamed) { | 1809 | // TODO: more attributes. see codegen.cpp `make_fn_llvm_value`. |
| 1768 | return dg.context.constStruct( | 1810 | if (fn_info.cc == .Naked) { |
| 1769 | llvm_fields.items.ptr, | 1811 | dg.addFnAttr(llvm_fn, "naked"); |
| 1770 | @intCast(c_uint, llvm_fields.items.len), | 1812 | } else { |
| 1771 | .False, | 1813 | llvm_fn.setFunctionCallConv(toLlvmCallConv(fn_info.cc, target)); |
| 1772 | ); | 1814 | } |
| 1773 | } else { | | |
| 1774 | return llvm_struct_ty.constNamedStruct( | | |
| 1775 | llvm_fields.items.ptr, | | |
| 1776 | @intCast(c_uint, llvm_fields.items.len), | | |
| 1777 | ); | | |
| 1778 | } | | |
| 1779 | } | | |
| 1780 | | 1815 | |
| 1781 | const struct_obj = tv.ty.castTag(.@"struct").?.data; | 1816 | if (fn_info.alignment != 0) { |
| | 1817 | llvm_fn.setAlignment(fn_info.alignment); |
| | 1818 | } |
| 1782 | | 1819 | |
| 1783 | if (struct_obj.layout == .Packed) { | 1820 | // Function attributes that are independent of analysis results of the function body. |
| 1784 | const big_bits = struct_obj.packedIntegerBits(target); | 1821 | dg.addCommonFnAttributes(llvm_fn); |
| 1785 | const int_llvm_ty = dg.context.intType(big_bits); | | |
| 1786 | const fields = struct_obj.fields.values(); | | |
| 1787 | comptime assert(Type.packed_struct_layout_version == 2); | | |
| 1788 | var running_int: *const llvm.Value = int_llvm_ty.constNull(); | | |
| 1789 | var running_bits: u16 = 0; | | |
| 1790 | for (field_vals) |field_val, i| { | | |
| 1791 | const field = fields[i]; | | |
| 1792 | if (!field.ty.hasRuntimeBitsIgnoreComptime()) continue; | | |
| 1793 | | 1822 | |
| 1794 | const non_int_val = try dg.genTypedValue(.{ | 1823 | if (fn_info.return_type.isNoReturn()) { |
| 1795 | .ty = field.ty, | 1824 | dg.addFnAttr(llvm_fn, "noreturn"); |
| 1796 | .val = field_val, | 1825 | } |
| 1797 | }); | | |
| 1798 | const ty_bit_size = @intCast(u16, field.ty.bitSize(target)); | | |
| 1799 | const small_int_ty = dg.context.intType(ty_bit_size); | | |
| 1800 | const small_int_val = non_int_val.constBitCast(small_int_ty); | | |
| 1801 | const shift_rhs = int_llvm_ty.constInt(running_bits, .False); | | |
| 1802 | // If the field is as large as the entire packed struct, this | | |
| 1803 | // zext would go from, e.g. i16 to i16. This is legal with | | |
| 1804 | // constZExtOrBitCast but not legal with constZExt. | | |
| 1805 | const extended_int_val = small_int_val.constZExtOrBitCast(int_llvm_ty); | | |
| 1806 | const shifted = extended_int_val.constShl(shift_rhs); | | |
| 1807 | running_int = running_int.constOr(shifted); | | |
| 1808 | running_bits += ty_bit_size; | | |
| 1809 | } | | |
| 1810 | return running_int; | | |
| 1811 | } | | |
| 1812 | | 1826 | |
| 1813 | const llvm_field_count = llvm_struct_ty.countStructElementTypes(); | 1827 | return llvm_fn; |
| 1814 | var llvm_fields = try std.ArrayListUnmanaged(*const llvm.Value).initCapacity(gpa, llvm_field_count); | 1828 | } |
| 1815 | defer llvm_fields.deinit(gpa); | | |
| 1816 | | 1829 | |
| 1817 | comptime assert(struct_layout_version == 2); | 1830 | fn addCommonFnAttributes(dg: *DeclGen, llvm_fn: *const llvm.Value) void { |
| 1818 | var offset: u64 = 0; | 1831 | if (!dg.module.comp.bin_file.options.red_zone) { |
| 1819 | var big_align: u32 = 0; | 1832 | dg.addFnAttr(llvm_fn, "noredzone"); |
| 1820 | var need_unnamed = false; | 1833 | } |
| | 1834 | if (dg.module.comp.bin_file.options.omit_frame_pointer) { |
| | 1835 | dg.addFnAttrString(llvm_fn, "frame-pointer", "none"); |
| | 1836 | } else { |
| | 1837 | dg.addFnAttrString(llvm_fn, "frame-pointer", "all"); |
| | 1838 | } |
| | 1839 | dg.addFnAttr(llvm_fn, "nounwind"); |
| | 1840 | if (dg.module.comp.unwind_tables) { |
| | 1841 | dg.addFnAttr(llvm_fn, "uwtable"); |
| | 1842 | } |
| | 1843 | if (dg.module.comp.bin_file.options.skip_linker_dependencies) { |
| | 1844 | // The intent here is for compiler-rt and libc functions to not generate |
| | 1845 | // infinite recursion. For example, if we are compiling the memcpy function, |
| | 1846 | // and llvm detects that the body is equivalent to memcpy, it may replace the |
| | 1847 | // body of memcpy with a call to memcpy, which would then cause a stack |
| | 1848 | // overflow instead of performing memcpy. |
| | 1849 | dg.addFnAttr(llvm_fn, "nobuiltin"); |
| | 1850 | } |
| | 1851 | if (dg.module.comp.bin_file.options.optimize_mode == .ReleaseSmall) { |
| | 1852 | dg.addFnAttr(llvm_fn, "minsize"); |
| | 1853 | dg.addFnAttr(llvm_fn, "optsize"); |
| | 1854 | } |
| | 1855 | if (dg.module.comp.bin_file.options.tsan) { |
| | 1856 | dg.addFnAttr(llvm_fn, "sanitize_thread"); |
| | 1857 | } |
| | 1858 | // TODO add target-cpu and target-features fn attributes |
| | 1859 | } |
| 1821 | | 1860 | |
| 1822 | for (struct_obj.fields.values()) |field, i| { | 1861 | fn resolveGlobalDecl(dg: *DeclGen, decl: *Module.Decl) Error!*const llvm.Value { |
| 1823 | if (field.is_comptime or !field.ty.hasRuntimeBitsIgnoreComptime()) continue; | 1862 | const gop = try dg.object.decl_map.getOrPut(dg.gpa, decl); |
| | 1863 | if (gop.found_existing) return gop.value_ptr.*; |
| | 1864 | errdefer assert(dg.object.decl_map.remove(decl)); |
| 1824 | | 1865 | |
| 1825 | const field_align = field.normalAlignment(target); | 1866 | const fqn = try decl.getFullyQualifiedName(dg.gpa); |
| 1826 | big_align = @maximum(big_align, field_align); | 1867 | defer dg.gpa.free(fqn); |
| 1827 | const prev_offset = offset; | | |
| 1828 | offset = std.mem.alignForwardGeneric(u64, offset, field_align); | | |
| 1829 | | 1868 | |
| 1830 | const padding_len = offset - prev_offset; | 1869 | const llvm_type = try dg.llvmType(decl.ty); |
| 1831 | if (padding_len > 0) { | 1870 | const llvm_addrspace = dg.llvmAddressSpace(decl.@"addrspace"); |
| 1832 | const llvm_array_ty = dg.context.intType(8).arrayType(@intCast(c_uint, padding_len)); | 1871 | const llvm_global = dg.object.llvm_module.addGlobalInAddressSpace(llvm_type, fqn, llvm_addrspace); |
| 1833 | // TODO make this and all other padding elsewhere in debug | 1872 | gop.value_ptr.* = llvm_global; |
| 1834 | // builds be 0xaa not undef. | | |
| 1835 | llvm_fields.appendAssumeCapacity(llvm_array_ty.getUndef()); | | |
| 1836 | } | | |
| 1837 | | 1873 | |
| 1838 | const field_llvm_val = try dg.genTypedValue(.{ | 1874 | // This is needed for declarations created by `@extern`. |
| 1839 | .ty = field.ty, | 1875 | if (decl.isExtern()) { |
| 1840 | .val = field_vals[i], | 1876 | llvm_global.setValueName(decl.name); |
| 1841 | }); | 1877 | llvm_global.setUnnamedAddr(.False); |
| | 1878 | llvm_global.setLinkage(.External); |
| | 1879 | if (decl.val.castTag(.variable)) |variable| { |
| | 1880 | const single_threaded = dg.module.comp.bin_file.options.single_threaded; |
| | 1881 | if (variable.data.is_threadlocal and !single_threaded) { |
| | 1882 | llvm_global.setThreadLocalMode(.GeneralDynamicTLSModel); |
| | 1883 | } else { |
| | 1884 | llvm_global.setThreadLocalMode(.NotThreadLocal); |
| | 1885 | } |
| | 1886 | if (variable.data.is_weak_linkage) llvm_global.setLinkage(.ExternalWeak); |
| | 1887 | } |
| | 1888 | } else { |
| | 1889 | llvm_global.setLinkage(.Internal); |
| | 1890 | llvm_global.setUnnamedAddr(.True); |
| | 1891 | } |
| 1842 | | 1892 | |
| 1843 | need_unnamed = need_unnamed or dg.isUnnamedType(field.ty, field_llvm_val); | 1893 | return llvm_global; |
| | 1894 | } |
| 1844 | | 1895 | |
| 1845 | llvm_fields.appendAssumeCapacity(field_llvm_val); | 1896 | fn llvmAddressSpace(self: DeclGen, address_space: std.builtin.AddressSpace) c_uint { |
| | 1897 | const target = self.module.getTarget(); |
| | 1898 | return switch (target.cpu.arch) { |
| | 1899 | .i386, .x86_64 => switch (address_space) { |
| | 1900 | .generic => llvm.address_space.default, |
| | 1901 | .gs => llvm.address_space.x86.gs, |
| | 1902 | .fs => llvm.address_space.x86.fs, |
| | 1903 | .ss => llvm.address_space.x86.ss, |
| | 1904 | else => unreachable, |
| | 1905 | }, |
| | 1906 | .nvptx, .nvptx64 => switch (address_space) { |
| | 1907 | .generic => llvm.address_space.default, |
| | 1908 | .global => llvm.address_space.nvptx.global, |
| | 1909 | .constant => llvm.address_space.nvptx.constant, |
| | 1910 | .param => llvm.address_space.nvptx.param, |
| | 1911 | .shared => llvm.address_space.nvptx.shared, |
| | 1912 | .local => llvm.address_space.nvptx.local, |
| | 1913 | else => unreachable, |
| | 1914 | }, |
| | 1915 | else => switch (address_space) { |
| | 1916 | .generic => llvm.address_space.default, |
| | 1917 | else => unreachable, |
| | 1918 | }, |
| | 1919 | }; |
| | 1920 | } |
| 1846 | | 1921 | |
| 1847 | offset += field.ty.abiSize(target); | 1922 | fn isUnnamedType(dg: *DeclGen, ty: Type, val: *const llvm.Value) bool { |
| 1848 | } | 1923 | // Once `llvmType` succeeds, successive calls to it with the same Zig type |
| 1849 | { | 1924 | // are guaranteed to succeed. So if a call to `llvmType` fails here it means |
| 1850 | const prev_offset = offset; | 1925 | // it is the first time lowering the type, which means the value can't possible |
| 1851 | offset = std.mem.alignForwardGeneric(u64, offset, big_align); | 1926 | // have that type. |
| 1852 | const padding_len = offset - prev_offset; | 1927 | const llvm_ty = dg.llvmType(ty) catch return true; |
| 1853 | if (padding_len > 0) { | 1928 | return val.typeOf() != llvm_ty; |
| 1854 | const llvm_array_ty = dg.context.intType(8).arrayType(@intCast(c_uint, padding_len)); | 1929 | } |
| 1855 | llvm_fields.appendAssumeCapacity(llvm_array_ty.getUndef()); | | |
| 1856 | } | | |
| 1857 | } | | |
| 1858 | | 1930 | |
| 1859 | if (need_unnamed) { | 1931 | fn llvmType(dg: *DeclGen, t: Type) Allocator.Error!*const llvm.Type { |
| 1860 | return dg.context.constStruct( | 1932 | const gpa = dg.gpa; |
| 1861 | llvm_fields.items.ptr, | 1933 | const target = dg.module.getTarget(); |
| 1862 | @intCast(c_uint, llvm_fields.items.len), | 1934 | switch (t.zigTypeTag()) { |
| 1863 | .False, | 1935 | .Void, .NoReturn => return dg.context.voidType(), |
| 1864 | ); | 1936 | .Int => { |
| 1865 | } else { | 1937 | const info = t.intInfo(target); |
| 1866 | return llvm_struct_ty.constNamedStruct( | 1938 | assert(info.bits != 0); |
| 1867 | llvm_fields.items.ptr, | 1939 | return dg.context.intType(info.bits); |
| 1868 | @intCast(c_uint, llvm_fields.items.len), | | |
| 1869 | ); | | |
| 1870 | } | | |
| 1871 | }, | 1940 | }, |
| 1872 | .Union => { | 1941 | .Enum => { |
| 1873 | const llvm_union_ty = try dg.llvmType(tv.ty); | 1942 | var buffer: Type.Payload.Bits = undefined; |
| 1874 | const tag_and_val = tv.val.castTag(.@"union").?.data; | 1943 | const int_ty = t.intTagType(&buffer); |
| | 1944 | const bit_count = int_ty.intInfo(target).bits; |
| | 1945 | assert(bit_count != 0); |
| | 1946 | return dg.context.intType(bit_count); |
| | 1947 | }, |
| | 1948 | .Float => switch (t.floatBits(target)) { |
| | 1949 | 16 => return dg.context.halfType(), |
| | 1950 | 32 => return dg.context.floatType(), |
| | 1951 | 64 => return dg.context.doubleType(), |
| | 1952 | 80 => return if (backendSupportsF80(target)) dg.context.x86FP80Type() else dg.context.intType(80), |
| | 1953 | 128 => return dg.context.fp128Type(), |
| | 1954 | else => unreachable, |
| | 1955 | }, |
| | 1956 | .Bool => return dg.context.intType(1), |
| | 1957 | .Pointer => { |
| | 1958 | if (t.isSlice()) { |
| | 1959 | var buf: Type.SlicePtrFieldTypeBuffer = undefined; |
| | 1960 | const ptr_type = t.slicePtrFieldType(&buf); |
| 1875 | | 1961 | |
| 1876 | const target = dg.module.getTarget(); | 1962 | const fields: [2]*const llvm.Type = .{ |
| 1877 | const layout = tv.ty.unionGetLayout(target); | 1963 | try dg.llvmType(ptr_type), |
| 1878 | | 1964 | try dg.llvmType(Type.usize), |
| 1879 | if (layout.payload_size == 0) { | | |
| 1880 | return genTypedValue(dg, .{ | | |
| 1881 | .ty = tv.ty.unionTagType().?, | | |
| 1882 | .val = tag_and_val.tag, | | |
| 1883 | }); | | |
| 1884 | } | | |
| 1885 | const union_obj = tv.ty.cast(Type.Payload.Union).?.data; | | |
| 1886 | const field_index = union_obj.tag_ty.enumTagFieldIndex(tag_and_val.tag).?; | | |
| 1887 | assert(union_obj.haveFieldTypes()); | | |
| 1888 | const field_ty = union_obj.fields.values()[field_index].ty; | | |
| 1889 | const payload = p: { | | |
| 1890 | if (!field_ty.hasRuntimeBitsIgnoreComptime()) { | | |
| 1891 | const padding_len = @intCast(c_uint, layout.payload_size); | | |
| 1892 | break :p dg.context.intType(8).arrayType(padding_len).getUndef(); | | |
| 1893 | } | | |
| 1894 | const field = try genTypedValue(dg, .{ .ty = field_ty, .val = tag_and_val.val }); | | |
| 1895 | const field_size = field_ty.abiSize(target); | | |
| 1896 | if (field_size == layout.payload_size) { | | |
| 1897 | break :p field; | | |
| 1898 | } | | |
| 1899 | const padding_len = @intCast(c_uint, layout.payload_size - field_size); | | |
| 1900 | const fields: [2]*const llvm.Value = .{ | | |
| 1901 | field, dg.context.intType(8).arrayType(padding_len).getUndef(), | | |
| 1902 | }; | 1965 | }; |
| 1903 | break :p dg.context.constStruct(&fields, fields.len, .True); | 1966 | return dg.context.structType(&fields, fields.len, .False); |
| 1904 | }; | | |
| 1905 | | | |
| 1906 | // In this case we must make an unnamed struct because LLVM does | | |
| 1907 | // not support bitcasting our payload struct to the true union payload type. | | |
| 1908 | // Instead we use an unnamed struct and every reference to the global | | |
| 1909 | // must pointer cast to the expected type before accessing the union. | | |
| 1910 | const need_unnamed = layout.most_aligned_field != field_index; | | |
| 1911 | | | |
| 1912 | if (layout.tag_size == 0) { | | |
| 1913 | const fields: [1]*const llvm.Value = .{payload}; | | |
| 1914 | if (need_unnamed) { | | |
| 1915 | return dg.context.constStruct(&fields, fields.len, .False); | | |
| 1916 | } else { | | |
| 1917 | return llvm_union_ty.constNamedStruct(&fields, fields.len); | | |
| 1918 | } | | |
| 1919 | } | | |
| 1920 | const llvm_tag_value = try genTypedValue(dg, .{ | | |
| 1921 | .ty = tv.ty.unionTagType().?, | | |
| 1922 | .val = tag_and_val.tag, | | |
| 1923 | }); | | |
| 1924 | var fields: [3]*const llvm.Value = undefined; | | |
| 1925 | var fields_len: c_uint = 2; | | |
| 1926 | if (layout.tag_align >= layout.payload_align) { | | |
| 1927 | fields = .{ llvm_tag_value, payload, undefined }; | | |
| 1928 | } else { | | |
| 1929 | fields = .{ payload, llvm_tag_value, undefined }; | | |
| 1930 | } | | |
| 1931 | if (layout.padding != 0) { | | |
| 1932 | fields[2] = dg.context.intType(8).arrayType(layout.padding).getUndef(); | | |
| 1933 | fields_len = 3; | | |
| 1934 | } | 1967 | } |
| 1935 | if (need_unnamed) { | 1968 | const ptr_info = t.ptrInfo().data; |
| 1936 | return dg.context.constStruct(&fields, fields_len, .False); | 1969 | const llvm_addrspace = dg.llvmAddressSpace(ptr_info.@"addrspace"); |
| 1937 | } else { | 1970 | if (ptr_info.host_size != 0) { |
| 1938 | return llvm_union_ty.constNamedStruct(&fields, fields_len); | 1971 | return dg.context.intType(ptr_info.host_size * 8).pointerType(llvm_addrspace); |
| 1939 | } | 1972 | } |
| | 1973 | const elem_ty = ptr_info.pointee_type; |
| | 1974 | const lower_elem_ty = switch (elem_ty.zigTypeTag()) { |
| | 1975 | .Opaque, .Fn => true, |
| | 1976 | .Array => elem_ty.childType().hasRuntimeBitsIgnoreComptime(), |
| | 1977 | else => elem_ty.hasRuntimeBitsIgnoreComptime(), |
| | 1978 | }; |
| | 1979 | const llvm_elem_ty = if (lower_elem_ty) |
| | 1980 | try dg.llvmType(elem_ty) |
| | 1981 | else |
| | 1982 | dg.context.intType(8); |
| | 1983 | return llvm_elem_ty.pointerType(llvm_addrspace); |
| 1940 | }, | 1984 | }, |
| 1941 | .Vector => switch (tv.val.tag()) { | 1985 | .Opaque => switch (t.tag()) { |
| 1942 | .bytes => { | 1986 | .@"opaque" => { |
| 1943 | // Note, sentinel is not stored even if the type has a sentinel. | 1987 | const gop = try dg.object.type_map.getOrPut(gpa, t); |
| 1944 | const bytes = tv.val.castTag(.bytes).?.data; | 1988 | if (gop.found_existing) return gop.value_ptr.*; |
| 1945 | const vector_len = @intCast(usize, tv.ty.arrayLen()); | | |
| 1946 | assert(vector_len == bytes.len or vector_len + 1 == bytes.len); | | |
| 1947 | | 1989 | |
| 1948 | const elem_ty = tv.ty.elemType(); | 1990 | // The Type memory is ephemeral; since we want to store a longer-lived |
| 1949 | const llvm_elems = try dg.gpa.alloc(*const llvm.Value, vector_len); | 1991 | // reference, we need to copy it here. |
| 1950 | defer dg.gpa.free(llvm_elems); | 1992 | gop.key_ptr.* = try t.copy(dg.object.type_map_arena.allocator()); |
| 1951 | for (llvm_elems) |*elem, i| { | | |
| 1952 | var byte_payload: Value.Payload.U64 = .{ | | |
| 1953 | .base = .{ .tag = .int_u64 }, | | |
| 1954 | .data = bytes[i], | | |
| 1955 | }; | | |
| 1956 | | 1993 | |
| 1957 | elem.* = try dg.genTypedValue(.{ | 1994 | const opaque_obj = t.castTag(.@"opaque").?.data; |
| 1958 | .ty = elem_ty, | 1995 | const name = try opaque_obj.getFullyQualifiedName(gpa); |
| 1959 | .val = Value.initPayload(&byte_payload.base), | 1996 | defer gpa.free(name); |
| 1960 | }); | 1997 | |
| 1961 | } | 1998 | const llvm_struct_ty = dg.context.structCreateNamed(name); |
| 1962 | return llvm.constVector( | 1999 | gop.value_ptr.* = llvm_struct_ty; // must be done before any recursive calls |
| 1963 | llvm_elems.ptr, | 2000 | return llvm_struct_ty; |
| 1964 | @intCast(c_uint, llvm_elems.len), | | |
| 1965 | ); | | |
| 1966 | }, | | |
| 1967 | .aggregate => { | | |
| 1968 | // Note, sentinel is not stored even if the type has a sentinel. | | |
| 1969 | // The value includes the sentinel in those cases. | | |
| 1970 | const elem_vals = tv.val.castTag(.aggregate).?.data; | | |
| 1971 | const vector_len = @intCast(usize, tv.ty.arrayLen()); | | |
| 1972 | assert(vector_len == elem_vals.len or vector_len + 1 == elem_vals.len); | | |
| 1973 | const elem_ty = tv.ty.elemType(); | | |
| 1974 | const llvm_elems = try dg.gpa.alloc(*const llvm.Value, vector_len); | | |
| 1975 | defer dg.gpa.free(llvm_elems); | | |
| 1976 | for (llvm_elems) |*elem, i| { | | |
| 1977 | elem.* = try dg.genTypedValue(.{ .ty = elem_ty, .val = elem_vals[i] }); | | |
| 1978 | } | | |
| 1979 | return llvm.constVector( | | |
| 1980 | llvm_elems.ptr, | | |
| 1981 | @intCast(c_uint, llvm_elems.len), | | |
| 1982 | ); | | |
| 1983 | }, | | |
| 1984 | .repeated => { | | |
| 1985 | // Note, sentinel is not stored even if the type has a sentinel. | | |
| 1986 | const val = tv.val.castTag(.repeated).?.data; | | |
| 1987 | const elem_ty = tv.ty.elemType(); | | |
| 1988 | const len = @intCast(usize, tv.ty.arrayLen()); | | |
| 1989 | const llvm_elems = try dg.gpa.alloc(*const llvm.Value, len); | | |
| 1990 | defer dg.gpa.free(llvm_elems); | | |
| 1991 | for (llvm_elems) |*elem| { | | |
| 1992 | elem.* = try dg.genTypedValue(.{ .ty = elem_ty, .val = val }); | | |
| 1993 | } | | |
| 1994 | return llvm.constVector( | | |
| 1995 | llvm_elems.ptr, | | |
| 1996 | @intCast(c_uint, llvm_elems.len), | | |
| 1997 | ); | | |
| 1998 | }, | 2001 | }, |
| | 2002 | .anyopaque => return dg.context.intType(8), |
| 1999 | else => unreachable, | 2003 | else => unreachable, |
| 2000 | }, | 2004 | }, |
| | 2005 | .Array => { |
| | 2006 | const elem_ty = t.childType(); |
| | 2007 | assert(elem_ty.onePossibleValue() == null); |
| | 2008 | const elem_llvm_ty = try dg.llvmType(elem_ty); |
| | 2009 | const total_len = t.arrayLen() + @boolToInt(t.sentinel() != null); |
| | 2010 | return elem_llvm_ty.arrayType(@intCast(c_uint, total_len)); |
| | 2011 | }, |
| | 2012 | .Vector => { |
| | 2013 | const elem_type = try dg.llvmType(t.childType()); |
| | 2014 | return elem_type.vectorType(t.vectorLen()); |
| | 2015 | }, |
| | 2016 | .Optional => { |
| | 2017 | var buf: Type.Payload.ElemType = undefined; |
| | 2018 | const child_ty = t.optionalChild(&buf); |
| | 2019 | if (!child_ty.hasRuntimeBitsIgnoreComptime()) { |
| | 2020 | return dg.context.intType(1); |
| | 2021 | } |
| | 2022 | const payload_llvm_ty = try dg.llvmType(child_ty); |
| | 2023 | if (t.isPtrLikeOptional()) { |
| | 2024 | return payload_llvm_ty; |
| | 2025 | } |
| 2001 | | 2026 | |
| 2002 | .ComptimeInt => unreachable, | 2027 | const fields: [2]*const llvm.Type = .{ |
| 2003 | .ComptimeFloat => unreachable, | 2028 | payload_llvm_ty, dg.context.intType(1), |
| 2004 | .Type => unreachable, | 2029 | }; |
| 2005 | .EnumLiteral => unreachable, | 2030 | return dg.context.structType(&fields, fields.len, .False); |
| 2006 | .Void => unreachable, | 2031 | }, |
| 2007 | .NoReturn => unreachable, | 2032 | .ErrorUnion => { |
| 2008 | .Undefined => unreachable, | 2033 | const error_type = t.errorUnionSet(); |
| 2009 | .Null => unreachable, | 2034 | const payload_type = t.errorUnionPayload(); |
| 2010 | .BoundFn => unreachable, | 2035 | const llvm_error_type = try dg.llvmType(error_type); |
| 2011 | .Opaque => unreachable, | 2036 | if (!payload_type.hasRuntimeBitsIgnoreComptime()) { |
| 2012 | | 2037 | return llvm_error_type; |
| 2013 | .Frame, | 2038 | } |
| 2014 | .AnyFrame, | 2039 | const llvm_payload_type = try dg.llvmType(payload_type); |
| 2015 | => return dg.todo("implement const of type '{}'", .{tv.ty}), | | |
| 2016 | } | | |
| 2017 | } | | |
| 2018 | | 2040 | |
| 2019 | fn lowerDebugType(dg: *DeclGen, ty: Type) Allocator.Error!*llvm.DIType { | 2041 | const fields: [2]*const llvm.Type = .{ llvm_error_type, llvm_payload_type }; |
| 2020 | const gpa = dg.gpa; | 2042 | return dg.context.structType(&fields, fields.len, .False); |
| 2021 | // Be careful not to reference this `gop` variable after any recursive calls | | |
| 2022 | // to `lowerDebugType`. | | |
| 2023 | const gop = try dg.object.di_type_map.getOrPut(gpa, ty); | | |
| 2024 | if (gop.found_existing) return gop.value_ptr.*; | | |
| 2025 | errdefer assert(dg.object.di_type_map.remove(ty)); | | |
| 2026 | // The Type memory is ephemeral; since we want to store a longer-lived | | |
| 2027 | // reference, we need to copy it here. | | |
| 2028 | gop.key_ptr.* = try ty.copy(dg.object.type_map_arena.allocator()); | | |
| 2029 | const target = dg.module.getTarget(); | | |
| 2030 | const dib = dg.object.di_builder.?; | | |
| 2031 | switch (ty.zigTypeTag()) { | | |
| 2032 | .Void, .NoReturn => { | | |
| 2033 | gop.value_ptr.* = dib.createBasicType("void", 0, DW.ATE.signed); | | |
| 2034 | return gop.value_ptr.*; | | |
| 2035 | }, | 2043 | }, |
| 2036 | .Int => { | 2044 | .ErrorSet => { |
| 2037 | const info = ty.intInfo(target); | 2045 | return dg.context.intType(16); |
| 2038 | assert(info.bits != 0); | | |
| 2039 | const name = try ty.nameAlloc(gpa); | | |
| 2040 | defer gpa.free(name); | | |
| 2041 | const dwarf_encoding: c_uint = switch (info.signedness) { | | |
| 2042 | .signed => DW.ATE.signed, | | |
| 2043 | .unsigned => DW.ATE.unsigned, | | |
| 2044 | }; | | |
| 2045 | gop.value_ptr.* = dib.createBasicType(name, info.bits, dwarf_encoding); | | |
| 2046 | return gop.value_ptr.*; | | |
| 2047 | }, | 2046 | }, |
| 2048 | .Enum => { | 2047 | .Struct => { |
| 2049 | const owner_decl = ty.getOwnerDecl(); | 2048 | const gop = try dg.object.type_map.getOrPut(gpa, t); |
| | 2049 | if (gop.found_existing) return gop.value_ptr.*; |
| 2050 | | 2050 | |
| 2051 | if (!ty.hasRuntimeBitsIgnoreComptime()) { | 2051 | // The Type memory is ephemeral; since we want to store a longer-lived |
| 2052 | const enum_di_ty = try dg.makeEmptyNamespaceDIType(owner_decl); | 2052 | // reference, we need to copy it here. |
| 2053 | // The recursive call to `lowerDebugType` via `makeEmptyNamespaceDIType` | 2053 | gop.key_ptr.* = try t.copy(dg.object.type_map_arena.allocator()); |
| 2054 | // means we can't use `gop` anymore. | | |
| 2055 | try dg.object.di_type_map.put(gpa, ty, enum_di_ty); | | |
| 2056 | return enum_di_ty; | | |
| 2057 | } | | |
| 2058 | | 2054 | |
| 2059 | const field_names = ty.enumFields().keys(); | 2055 | if (t.isTupleOrAnonStruct()) { |
| | 2056 | const tuple = t.tupleFields(); |
| | 2057 | const llvm_struct_ty = dg.context.structCreateNamed(""); |
| | 2058 | gop.value_ptr.* = llvm_struct_ty; // must be done before any recursive calls |
| 2060 | | 2059 | |
| 2061 | const enumerators = try gpa.alloc(*llvm.DIEnumerator, field_names.len); | 2060 | var llvm_field_types: std.ArrayListUnmanaged(*const llvm.Type) = .{}; |
| 2062 | defer gpa.free(enumerators); | 2061 | defer llvm_field_types.deinit(gpa); |
| 2063 | | 2062 | |
| 2064 | var buf_field_index: Value.Payload.U32 = .{ | 2063 | try llvm_field_types.ensureUnusedCapacity(gpa, tuple.types.len); |
| 2065 | .base = .{ .tag = .enum_field_index }, | | |
| 2066 | .data = undefined, | | |
| 2067 | }; | | |
| 2068 | const field_index_val = Value.initPayload(&buf_field_index.base); | | |
| 2069 | | 2064 | |
| 2070 | for (field_names) |field_name, i| { | 2065 | comptime assert(struct_layout_version == 2); |
| 2071 | const field_name_z = try gpa.dupeZ(u8, field_name); | 2066 | var offset: u64 = 0; |
| 2072 | defer gpa.free(field_name_z); | 2067 | var big_align: u32 = 0; |
| 2073 | | 2068 | |
| 2074 | buf_field_index.data = @intCast(u32, i); | 2069 | for (tuple.types) |field_ty, i| { |
| 2075 | var buf_u64: Value.Payload.U64 = undefined; | 2070 | const field_val = tuple.values[i]; |
| 2076 | const field_int_val = field_index_val.enumToInt(ty, &buf_u64); | 2071 | if (field_val.tag() != .unreachable_value) continue; |
| 2077 | // See https://github.com/ziglang/zig/issues/645 | 2072 | |
| 2078 | const field_int = field_int_val.toSignedInt(); | 2073 | const field_align = field_ty.abiAlignment(target); |
| 2079 | enumerators[i] = dib.createEnumerator(field_name_z, field_int); | 2074 | big_align = @maximum(big_align, field_align); |
| | 2075 | const prev_offset = offset; |
| | 2076 | offset = std.mem.alignForwardGeneric(u64, offset, field_align); |
| | 2077 | |
| | 2078 | const padding_len = offset - prev_offset; |
| | 2079 | if (padding_len > 0) { |
| | 2080 | const llvm_array_ty = dg.context.intType(8).arrayType(@intCast(c_uint, padding_len)); |
| | 2081 | try llvm_field_types.append(gpa, llvm_array_ty); |
| | 2082 | } |
| | 2083 | const field_llvm_ty = try dg.llvmType(field_ty); |
| | 2084 | try llvm_field_types.append(gpa, field_llvm_ty); |
| | 2085 | |
| | 2086 | offset += field_ty.abiSize(target); |
| | 2087 | } |
| | 2088 | { |
| | 2089 | const prev_offset = offset; |
| | 2090 | offset = std.mem.alignForwardGeneric(u64, offset, big_align); |
| | 2091 | const padding_len = offset - prev_offset; |
| | 2092 | if (padding_len > 0) { |
| | 2093 | const llvm_array_ty = dg.context.intType(8).arrayType(@intCast(c_uint, padding_len)); |
| | 2094 | try llvm_field_types.append(gpa, llvm_array_ty); |
| | 2095 | } |
| | 2096 | } |
| | 2097 | |
| | 2098 | llvm_struct_ty.structSetBody( |
| | 2099 | llvm_field_types.items.ptr, |
| | 2100 | @intCast(c_uint, llvm_field_types.items.len), |
| | 2101 | .False, |
| | 2102 | ); |
| | 2103 | |
| | 2104 | return llvm_struct_ty; |
| 2080 | } | 2105 | } |
| 2081 | | 2106 | |
| 2082 | const di_file = try dg.object.getDIFile(gpa, owner_decl.src_namespace.file_scope); | 2107 | const struct_obj = t.castTag(.@"struct").?.data; |
| 2083 | const di_scope = try dg.namespaceToDebugScope(owner_decl.src_namespace); | | |
| 2084 | | 2108 | |
| 2085 | const name = try ty.nameAlloc(gpa); | 2109 | if (struct_obj.layout == .Packed) { |
| 2086 | defer gpa.free(name); | 2110 | var buf: Type.Payload.Bits = undefined; |
| 2087 | var buffer: Type.Payload.Bits = undefined; | 2111 | const int_ty = struct_obj.packedIntegerType(target, &buf); |
| 2088 | const int_ty = ty.intTagType(&buffer); | 2112 | const int_llvm_ty = try dg.llvmType(int_ty); |
| | 2113 | gop.value_ptr.* = int_llvm_ty; |
| | 2114 | return int_llvm_ty; |
| | 2115 | } |
| 2089 | | 2116 | |
| 2090 | const enum_di_ty = dib.createEnumerationType( | 2117 | const name = try struct_obj.getFullyQualifiedName(gpa); |
| 2091 | di_scope, | | |
| 2092 | name, | | |
| 2093 | di_file, | | |
| 2094 | owner_decl.src_node + 1, | | |
| 2095 | ty.abiSize(target) * 8, | | |
| 2096 | ty.abiAlignment(target) * 8, | | |
| 2097 | enumerators.ptr, | | |
| 2098 | @intCast(c_int, enumerators.len), | | |
| 2099 | try lowerDebugType(dg, int_ty), | | |
| 2100 | "", | | |
| 2101 | ); | | |
| 2102 | // The recursive call to `lowerDebugType` means we can't use `gop` anymore. | | |
| 2103 | try dg.object.di_type_map.put(gpa, ty, enum_di_ty); | | |
| 2104 | return enum_di_ty; | | |
| 2105 | }, | | |
| 2106 | .Float => { | | |
| 2107 | const bits = ty.floatBits(target); | | |
| 2108 | const name = try ty.nameAlloc(gpa); | | |
| 2109 | defer gpa.free(name); | 2118 | defer gpa.free(name); |
| 2110 | gop.value_ptr.* = dib.createBasicType(name, bits, DW.ATE.float); | | |
| 2111 | return gop.value_ptr.*; | | |
| 2112 | }, | | |
| 2113 | .Bool => { | | |
| 2114 | gop.value_ptr.* = dib.createBasicType("bool", 1, DW.ATE.boolean); | | |
| 2115 | return gop.value_ptr.*; | | |
| 2116 | }, | | |
| 2117 | .Pointer => { | | |
| 2118 | // Normalize everything that the debug info does not represent. | | |
| 2119 | const ptr_info = ty.ptrInfo().data; | | |
| 2120 | | 2119 | |
| 2121 | if (ptr_info.sentinel != null or | 2120 | const llvm_struct_ty = dg.context.structCreateNamed(name); |
| 2122 | ptr_info.@"addrspace" != .generic or | 2121 | gop.value_ptr.* = llvm_struct_ty; // must be done before any recursive calls |
| 2123 | ptr_info.bit_offset != 0 or | | |
| 2124 | ptr_info.host_size != 0 or | | |
| 2125 | ptr_info.@"allowzero" or | | |
| 2126 | !ptr_info.mutable or | | |
| 2127 | ptr_info.@"volatile" or | | |
| 2128 | ptr_info.size == .Many or ptr_info.size == .C or | | |
| 2129 | !ptr_info.pointee_type.hasRuntimeBitsIgnoreComptime()) | | |
| 2130 | { | | |
| 2131 | var payload: Type.Payload.Pointer = .{ | | |
| 2132 | .data = .{ | | |
| 2133 | .pointee_type = ptr_info.pointee_type, | | |
| 2134 | .sentinel = null, | | |
| 2135 | .@"align" = ptr_info.@"align", | | |
| 2136 | .@"addrspace" = .generic, | | |
| 2137 | .bit_offset = 0, | | |
| 2138 | .host_size = 0, | | |
| 2139 | .@"allowzero" = false, | | |
| 2140 | .mutable = true, | | |
| 2141 | .@"volatile" = false, | | |
| 2142 | .size = switch (ptr_info.size) { | | |
| 2143 | .Many, .C, .One => .One, | | |
| 2144 | .Slice => .Slice, | | |
| 2145 | }, | | |
| 2146 | }, | | |
| 2147 | }; | | |
| 2148 | if (!ptr_info.pointee_type.hasRuntimeBitsIgnoreComptime()) { | | |
| 2149 | payload.data.pointee_type = Type.anyopaque; | | |
| 2150 | } | | |
| 2151 | const bland_ptr_ty = Type.initPayload(&payload.base); | | |
| 2152 | const ptr_di_ty = try dg.lowerDebugType(bland_ptr_ty); | | |
| 2153 | // The recursive call to `lowerDebugType` means we can't use `gop` anymore. | | |
| 2154 | try dg.object.di_type_map.put(gpa, ty, ptr_di_ty); | | |
| 2155 | return ptr_di_ty; | | |
| 2156 | } | | |
| 2157 | | 2122 | |
| 2158 | if (ty.isSlice()) { | 2123 | assert(struct_obj.haveFieldTypes()); |
| 2159 | var buf: Type.SlicePtrFieldTypeBuffer = undefined; | | |
| 2160 | const ptr_ty = ty.slicePtrFieldType(&buf); | | |
| 2161 | const len_ty = Type.usize; | | |
| 2162 | | 2124 | |
| 2163 | const name = try ty.nameAlloc(gpa); | 2125 | var llvm_field_types: std.ArrayListUnmanaged(*const llvm.Type) = .{}; |
| 2164 | defer gpa.free(name); | 2126 | defer llvm_field_types.deinit(gpa); |
| 2165 | const di_file: ?*llvm.DIFile = null; | | |
| 2166 | const line = 0; | | |
| 2167 | const compile_unit_scope = dg.object.di_compile_unit.?.toScope(); | | |
| 2168 | const fwd_decl = dib.createReplaceableCompositeType( | | |
| 2169 | DW.TAG.structure_type, | | |
| 2170 | name.ptr, | | |
| 2171 | compile_unit_scope, | | |
| 2172 | di_file, | | |
| 2173 | line, | | |
| 2174 | ); | | |
| 2175 | gop.value_ptr.* = fwd_decl; | | |
| 2176 | | 2127 | |
| 2177 | const ptr_size = ptr_ty.abiSize(target); | 2128 | try llvm_field_types.ensureUnusedCapacity(gpa, struct_obj.fields.count()); |
| 2178 | const ptr_align = ptr_ty.abiAlignment(target); | | |
| 2179 | const len_size = len_ty.abiSize(target); | | |
| 2180 | const len_align = len_ty.abiAlignment(target); | | |
| 2181 | | 2129 | |
| 2182 | var offset: u64 = 0; | 2130 | comptime assert(struct_layout_version == 2); |
| 2183 | offset += ptr_size; | 2131 | var offset: u64 = 0; |
| 2184 | offset = std.mem.alignForwardGeneric(u64, offset, len_align); | 2132 | var big_align: u32 = 0; |
| 2185 | const len_offset = offset; | | |
| 2186 | | 2133 | |
| 2187 | const fields: [2]*llvm.DIType = .{ | 2134 | for (struct_obj.fields.values()) |field| { |
| 2188 | dib.createMemberType( | 2135 | if (field.is_comptime or !field.ty.hasRuntimeBitsIgnoreComptime()) continue; |
| 2189 | fwd_decl.toScope(), | | |
| 2190 | "ptr", | | |
| 2191 | di_file, | | |
| 2192 | line, | | |
| 2193 | ptr_size * 8, // size in bits | | |
| 2194 | ptr_align * 8, // align in bits | | |
| 2195 | 0, // offset in bits | | |
| 2196 | 0, // flags | | |
| 2197 | try dg.lowerDebugType(ptr_ty), | | |
| 2198 | ), | | |
| 2199 | dib.createMemberType( | | |
| 2200 | fwd_decl.toScope(), | | |
| 2201 | "len", | | |
| 2202 | di_file, | | |
| 2203 | line, | | |
| 2204 | len_size * 8, // size in bits | | |
| 2205 | len_align * 8, // align in bits | | |
| 2206 | len_offset * 8, // offset in bits | | |
| 2207 | 0, // flags | | |
| 2208 | try dg.lowerDebugType(len_ty), | | |
| 2209 | ), | | |
| 2210 | }; | | |
| 2211 | | 2136 | |
| 2212 | const replacement_di_ty = dib.createStructType( | 2137 | const field_align = field.normalAlignment(target); |
| 2213 | compile_unit_scope, | 2138 | big_align = @maximum(big_align, field_align); |
| 2214 | name.ptr, | 2139 | const prev_offset = offset; |
| 2215 | di_file, | 2140 | offset = std.mem.alignForwardGeneric(u64, offset, field_align); |
| 2216 | line, | 2141 | |
| 2217 | ty.abiSize(target) * 8, // size in bits | 2142 | const padding_len = offset - prev_offset; |
| 2218 | ty.abiAlignment(target) * 8, // align in bits | 2143 | if (padding_len > 0) { |
| 2219 | 0, // flags | 2144 | const llvm_array_ty = dg.context.intType(8).arrayType(@intCast(c_uint, padding_len)); |
| 2220 | null, // derived from | 2145 | try llvm_field_types.append(gpa, llvm_array_ty); |
| 2221 | &fields, | 2146 | } |
| 2222 | fields.len, | 2147 | const field_llvm_ty = try dg.llvmType(field.ty); |
| 2223 | 0, // run time lang | 2148 | try llvm_field_types.append(gpa, field_llvm_ty); |
| 2224 | null, // vtable holder | 2149 | |
| 2225 | "", // unique id | 2150 | offset += field.ty.abiSize(target); |
| 2226 | ); | 2151 | } |
| 2227 | dib.replaceTemporary(fwd_decl, replacement_di_ty); | 2152 | { |
| 2228 | // The recursive call to `lowerDebugType` means we can't use `gop` anymore. | 2153 | const prev_offset = offset; |
| 2229 | try dg.object.di_type_map.put(gpa, ty, replacement_di_ty); | 2154 | offset = std.mem.alignForwardGeneric(u64, offset, big_align); |
| 2230 | return replacement_di_ty; | 2155 | const padding_len = offset - prev_offset; |
| | 2156 | if (padding_len > 0) { |
| | 2157 | const llvm_array_ty = dg.context.intType(8).arrayType(@intCast(c_uint, padding_len)); |
| | 2158 | try llvm_field_types.append(gpa, llvm_array_ty); |
| | 2159 | } |
| 2231 | } | 2160 | } |
| 2232 | | 2161 | |
| 2233 | const elem_di_ty = try lowerDebugType(dg, ptr_info.pointee_type); | 2162 | llvm_struct_ty.structSetBody( |
| 2234 | const name = try ty.nameAlloc(gpa); | 2163 | llvm_field_types.items.ptr, |
| 2235 | defer gpa.free(name); | 2164 | @intCast(c_uint, llvm_field_types.items.len), |
| 2236 | const ptr_di_ty = dib.createPointerType( | 2165 | .False, |
| 2237 | elem_di_ty, | | |
| 2238 | target.cpu.arch.ptrBitWidth(), | | |
| 2239 | ty.ptrAlignment(target) * 8, | | |
| 2240 | name, | | |
| 2241 | ); | 2166 | ); |
| 2242 | // The recursive call to `lowerDebugType` means we can't use `gop` anymore. | 2167 | |
| 2243 | try dg.object.di_type_map.put(gpa, ty, ptr_di_ty); | 2168 | return llvm_struct_ty; |
| 2244 | return ptr_di_ty; | | |
| 2245 | }, | 2169 | }, |
| 2246 | .Opaque => { | 2170 | .Union => { |
| 2247 | if (ty.tag() == .anyopaque) { | 2171 | const gop = try dg.object.type_map.getOrPut(gpa, t); |
| 2248 | gop.value_ptr.* = dib.createBasicType("anyopaque", 0, DW.ATE.signed); | 2172 | if (gop.found_existing) return gop.value_ptr.*; |
| 2249 | return gop.value_ptr.*; | 2173 | |
| | 2174 | // The Type memory is ephemeral; since we want to store a longer-lived |
| | 2175 | // reference, we need to copy it here. |
| | 2176 | gop.key_ptr.* = try t.copy(dg.object.type_map_arena.allocator()); |
| | 2177 | |
| | 2178 | const layout = t.unionGetLayout(target); |
| | 2179 | const union_obj = t.cast(Type.Payload.Union).?.data; |
| | 2180 | |
| | 2181 | if (layout.payload_size == 0) { |
| | 2182 | const enum_tag_llvm_ty = try dg.llvmType(union_obj.tag_ty); |
| | 2183 | gop.value_ptr.* = enum_tag_llvm_ty; |
| | 2184 | return enum_tag_llvm_ty; |
| 2250 | } | 2185 | } |
| 2251 | const name = try ty.nameAlloc(gpa); | 2186 | |
| | 2187 | const name = try union_obj.getFullyQualifiedName(gpa); |
| 2252 | defer gpa.free(name); | 2188 | defer gpa.free(name); |
| 2253 | const owner_decl = ty.getOwnerDecl(); | 2189 | |
| 2254 | const opaque_di_ty = dib.createForwardDeclType( | 2190 | const llvm_union_ty = dg.context.structCreateNamed(name); |
| 2255 | DW.TAG.structure_type, | 2191 | gop.value_ptr.* = llvm_union_ty; // must be done before any recursive calls |
| 2256 | name, | 2192 | |
| 2257 | try dg.namespaceToDebugScope(owner_decl.src_namespace), | 2193 | const aligned_field = union_obj.fields.values()[layout.most_aligned_field]; |
| 2258 | try dg.object.getDIFile(gpa, owner_decl.src_namespace.file_scope), | 2194 | const llvm_aligned_field_ty = try dg.llvmType(aligned_field.ty); |
| 2259 | owner_decl.src_node + 1, | 2195 | |
| 2260 | ); | 2196 | const llvm_payload_ty = t: { |
| 2261 | // The recursive call to `lowerDebugType` va `namespaceToDebugScope` | 2197 | if (layout.most_aligned_field_size == layout.payload_size) { |
| 2262 | // means we can't use `gop` anymore. | 2198 | break :t llvm_aligned_field_ty; |
| 2263 | try dg.object.di_type_map.put(gpa, ty, opaque_di_ty); | 2199 | } |
| 2264 | return opaque_di_ty; | 2200 | const padding_len = @intCast(c_uint, layout.payload_size - layout.most_aligned_field_size); |
| 2265 | }, | 2201 | const fields: [2]*const llvm.Type = .{ |
| 2266 | .Array => { | 2202 | llvm_aligned_field_ty, |
| 2267 | const array_di_ty = dib.createArrayType( | 2203 | dg.context.intType(8).arrayType(padding_len), |
| 2268 | ty.abiSize(target) * 8, | 2204 | }; |
| 2269 | ty.abiAlignment(target) * 8, | 2205 | break :t dg.context.structType(&fields, fields.len, .True); |
| 2270 | try lowerDebugType(dg, ty.childType()), | 2206 | }; |
| 2271 | @intCast(c_int, ty.arrayLen()), | 2207 | |
| 2272 | ); | 2208 | if (layout.tag_size == 0) { |
| 2273 | // The recursive call to `lowerDebugType` means we can't use `gop` anymore. | 2209 | var llvm_fields: [1]*const llvm.Type = .{llvm_payload_ty}; |
| 2274 | try dg.object.di_type_map.put(gpa, ty, array_di_ty); | 2210 | llvm_union_ty.structSetBody(&llvm_fields, llvm_fields.len, .False); |
| 2275 | return array_di_ty; | 2211 | return llvm_union_ty; |
| 2276 | }, | 2212 | } |
| 2277 | .Vector => { | 2213 | const enum_tag_llvm_ty = try dg.llvmType(union_obj.tag_ty); |
| 2278 | const vector_di_ty = dib.createVectorType( | 2214 | |
| 2279 | ty.abiSize(target) * 8, | 2215 | // Put the tag before or after the payload depending on which one's |
| 2280 | ty.abiAlignment(target) * 8, | 2216 | // alignment is greater. |
| 2281 | try lowerDebugType(dg, ty.childType()), | 2217 | var llvm_fields: [3]*const llvm.Type = undefined; |
| 2282 | ty.vectorLen(), | 2218 | var llvm_fields_len: c_uint = 2; |
| 2283 | ); | 2219 | |
| 2284 | // The recursive call to `lowerDebugType` means we can't use `gop` anymore. | 2220 | if (layout.tag_align >= layout.payload_align) { |
| 2285 | try dg.object.di_type_map.put(gpa, ty, vector_di_ty); | 2221 | llvm_fields = .{ enum_tag_llvm_ty, llvm_payload_ty, undefined }; |
| 2286 | return vector_di_ty; | 2222 | } else { |
| | 2223 | llvm_fields = .{ llvm_payload_ty, enum_tag_llvm_ty, undefined }; |
| | 2224 | } |
| | 2225 | |
| | 2226 | // Insert padding to make the LLVM struct ABI size match the Zig union ABI size. |
| | 2227 | if (layout.padding != 0) { |
| | 2228 | llvm_fields[2] = dg.context.intType(8).arrayType(layout.padding); |
| | 2229 | llvm_fields_len = 3; |
| | 2230 | } |
| | 2231 | |
| | 2232 | llvm_union_ty.structSetBody(&llvm_fields, llvm_fields_len, .False); |
| | 2233 | return llvm_union_ty; |
| 2287 | }, | 2234 | }, |
| 2288 | .Optional => { | 2235 | .Fn => { |
| 2289 | const name = try ty.nameAlloc(gpa); | 2236 | const fn_info = t.fnInfo(); |
| 2290 | defer gpa.free(name); | 2237 | const sret = firstParamSRet(fn_info, target); |
| 2291 | var buf: Type.Payload.ElemType = undefined; | 2238 | const return_type = fn_info.return_type; |
| 2292 | const child_ty = ty.optionalChild(&buf); | 2239 | const llvm_sret_ty = if (return_type.hasRuntimeBitsIgnoreComptime()) |
| 2293 | if (!child_ty.hasRuntimeBitsIgnoreComptime()) { | 2240 | try dg.llvmType(return_type) |
| 2294 | gop.value_ptr.* = dib.createBasicType(name, 1, DW.ATE.boolean); | 2241 | else |
| 2295 | return gop.value_ptr.*; | 2242 | dg.context.voidType(); |
| | 2243 | const llvm_ret_ty = if (sret) dg.context.voidType() else llvm_sret_ty; |
| | 2244 | |
| | 2245 | var llvm_params = std.ArrayList(*const llvm.Type).init(dg.gpa); |
| | 2246 | defer llvm_params.deinit(); |
| | 2247 | |
| | 2248 | if (sret) { |
| | 2249 | try llvm_params.append(llvm_sret_ty.pointerType(0)); |
| 2296 | } | 2250 | } |
| 2297 | if (ty.isPtrLikeOptional()) { | 2251 | |
| 2298 | const ptr_di_ty = try dg.lowerDebugType(child_ty); | 2252 | for (fn_info.param_types) |param_ty| { |
| 2299 | // The recursive call to `lowerDebugType` means we can't use `gop` anymore. | 2253 | if (!param_ty.hasRuntimeBitsIgnoreComptime()) continue; |
| 2300 | try dg.object.di_type_map.put(gpa, ty, ptr_di_ty); | 2254 | |
| 2301 | return ptr_di_ty; | 2255 | const raw_llvm_ty = try dg.llvmType(param_ty); |
| | 2256 | const actual_llvm_ty = if (!isByRef(param_ty)) raw_llvm_ty else raw_llvm_ty.pointerType(0); |
| | 2257 | try llvm_params.append(actual_llvm_ty); |
| 2302 | } | 2258 | } |
| 2303 | | 2259 | |
| 2304 | const di_file: ?*llvm.DIFile = null; | 2260 | return llvm.functionType( |
| 2305 | const line = 0; | 2261 | llvm_ret_ty, |
| 2306 | const compile_unit_scope = dg.object.di_compile_unit.?.toScope(); | 2262 | llvm_params.items.ptr, |
| 2307 | const fwd_decl = dib.createReplaceableCompositeType( | 2263 | @intCast(c_uint, llvm_params.items.len), |
| 2308 | DW.TAG.structure_type, | 2264 | llvm.Bool.fromBool(fn_info.is_var_args), |
| 2309 | name.ptr, | | |
| 2310 | compile_unit_scope, | | |
| 2311 | di_file, | | |
| 2312 | line, | | |
| 2313 | ); | 2265 | ); |
| 2314 | gop.value_ptr.* = fwd_decl; | 2266 | }, |
| | 2267 | .ComptimeInt => unreachable, |
| | 2268 | .ComptimeFloat => unreachable, |
| | 2269 | .Type => unreachable, |
| | 2270 | .Undefined => unreachable, |
| | 2271 | .Null => unreachable, |
| | 2272 | .EnumLiteral => unreachable, |
| 2315 | | 2273 | |
| 2316 | const non_null_ty = Type.bool; | 2274 | .BoundFn => @panic("TODO remove BoundFn from the language"), |
| 2317 | const payload_size = child_ty.abiSize(target); | | |
| 2318 | const payload_align = child_ty.abiAlignment(target); | | |
| 2319 | const non_null_size = non_null_ty.abiSize(target); | | |
| 2320 | const non_null_align = non_null_ty.abiAlignment(target); | | |
| 2321 | | 2275 | |
| 2322 | var offset: u64 = 0; | 2276 | .Frame => @panic("TODO implement llvmType for Frame types"), |
| 2323 | offset += payload_size; | 2277 | .AnyFrame => @panic("TODO implement llvmType for AnyFrame types"), |
| 2324 | offset = std.mem.alignForwardGeneric(u64, offset, non_null_align); | 2278 | } |
| 2325 | const non_null_offset = offset; | 2279 | } |
| 2326 | | 2280 | |
| 2327 | const fields: [2]*llvm.DIType = .{ | 2281 | fn genTypedValue(dg: *DeclGen, tv: TypedValue) Error!*const llvm.Value { |
| 2328 | dib.createMemberType( | 2282 | if (tv.val.isUndef()) { |
| 2329 | fwd_decl.toScope(), | 2283 | const llvm_type = try dg.llvmType(tv.ty); |
| 2330 | "data", | 2284 | return llvm_type.getUndef(); |
| 2331 | di_file, | 2285 | } |
| 2332 | line, | | |
| 2333 | payload_size * 8, // size in bits | | |
| 2334 | payload_align * 8, // align in bits | | |
| 2335 | 0, // offset in bits | | |
| 2336 | 0, // flags | | |
| 2337 | try dg.lowerDebugType(child_ty), | | |
| 2338 | ), | | |
| 2339 | dib.createMemberType( | | |
| 2340 | fwd_decl.toScope(), | | |
| 2341 | "some", | | |
| 2342 | di_file, | | |
| 2343 | line, | | |
| 2344 | non_null_size * 8, // size in bits | | |
| 2345 | non_null_align * 8, // align in bits | | |
| 2346 | non_null_offset * 8, // offset in bits | | |
| 2347 | 0, // flags | | |
| 2348 | try dg.lowerDebugType(non_null_ty), | | |
| 2349 | ), | | |
| 2350 | }; | | |
| 2351 | | 2286 | |
| 2352 | const replacement_di_ty = dib.createStructType( | 2287 | switch (tv.ty.zigTypeTag()) { |
| 2353 | compile_unit_scope, | 2288 | .Bool => { |
| 2354 | name.ptr, | 2289 | const llvm_type = try dg.llvmType(tv.ty); |
| 2355 | di_file, | 2290 | return if (tv.val.toBool()) llvm_type.constAllOnes() else llvm_type.constNull(); |
| 2356 | line, | | |
| 2357 | ty.abiSize(target) * 8, // size in bits | | |
| 2358 | ty.abiAlignment(target) * 8, // align in bits | | |
| 2359 | 0, // flags | | |
| 2360 | null, // derived from | | |
| 2361 | &fields, | | |
| 2362 | fields.len, | | |
| 2363 | 0, // run time lang | | |
| 2364 | null, // vtable holder | | |
| 2365 | "", // unique id | | |
| 2366 | ); | | |
| 2367 | dib.replaceTemporary(fwd_decl, replacement_di_ty); | | |
| 2368 | // The recursive call to `lowerDebugType` means we can't use `gop` anymore. | | |
| 2369 | try dg.object.di_type_map.put(gpa, ty, replacement_di_ty); | | |
| 2370 | return replacement_di_ty; | | |
| 2371 | }, | 2291 | }, |
| 2372 | .ErrorUnion => { | 2292 | // TODO this duplicates code with Pointer but they should share the handling |
| 2373 | const err_set_ty = ty.errorUnionSet(); | 2293 | // of the tv.val.tag() and then Int should do extra constPtrToInt on top |
| 2374 | const payload_ty = ty.errorUnionPayload(); | 2294 | .Int => switch (tv.val.tag()) { |
| 2375 | if (!payload_ty.hasRuntimeBitsIgnoreComptime()) { | 2295 | .decl_ref_mut => return lowerDeclRefValue(dg, tv, tv.val.castTag(.decl_ref_mut).?.data.decl), |
| 2376 | const err_set_di_ty = try dg.lowerDebugType(err_set_ty); | 2296 | .decl_ref => return lowerDeclRefValue(dg, tv, tv.val.castTag(.decl_ref).?.data), |
| 2377 | // The recursive call to `lowerDebugType` means we can't use `gop` anymore. | 2297 | else => { |
| 2378 | try dg.object.di_type_map.put(gpa, ty, err_set_di_ty); | 2298 | var bigint_space: Value.BigIntSpace = undefined; |
| 2379 | return err_set_di_ty; | 2299 | const bigint = tv.val.toBigInt(&bigint_space); |
| 2380 | } | 2300 | const target = dg.module.getTarget(); |
| 2381 | const name = try ty.nameAlloc(gpa); | 2301 | const int_info = tv.ty.intInfo(target); |
| 2382 | defer gpa.free(name); | 2302 | assert(int_info.bits != 0); |
| 2383 | const di_file: ?*llvm.DIFile = null; | 2303 | const llvm_type = dg.context.intType(int_info.bits); |
| 2384 | const line = 0; | | |
| 2385 | const compile_unit_scope = dg.object.di_compile_unit.?.toScope(); | | |
| 2386 | const fwd_decl = dib.createReplaceableCompositeType( | | |
| 2387 | DW.TAG.structure_type, | | |
| 2388 | name.ptr, | | |
| 2389 | compile_unit_scope, | | |
| 2390 | di_file, | | |
| 2391 | line, | | |
| 2392 | ); | | |
| 2393 | gop.value_ptr.* = fwd_decl; | | |
| 2394 | | 2304 | |
| 2395 | const err_set_size = err_set_ty.abiSize(target); | 2305 | const unsigned_val = v: { |
| 2396 | const err_set_align = err_set_ty.abiAlignment(target); | 2306 | if (bigint.limbs.len == 1) { |
| 2397 | const payload_size = payload_ty.abiSize(target); | 2307 | break :v llvm_type.constInt(bigint.limbs[0], .False); |
| 2398 | const payload_align = payload_ty.abiAlignment(target); | 2308 | } |
| | 2309 | if (@sizeOf(usize) == @sizeOf(u64)) { |
| | 2310 | break :v llvm_type.constIntOfArbitraryPrecision( |
| | 2311 | @intCast(c_uint, bigint.limbs.len), |
| | 2312 | bigint.limbs.ptr, |
| | 2313 | ); |
| | 2314 | } |
| | 2315 | @panic("TODO implement bigint to llvm int for 32-bit compiler builds"); |
| | 2316 | }; |
| | 2317 | if (!bigint.positive) { |
| | 2318 | return llvm.constNeg(unsigned_val); |
| | 2319 | } |
| | 2320 | return unsigned_val; |
| | 2321 | }, |
| | 2322 | }, |
| | 2323 | .Enum => { |
| | 2324 | var int_buffer: Value.Payload.U64 = undefined; |
| | 2325 | const int_val = tv.enumToInt(&int_buffer); |
| 2399 | | 2326 | |
| 2400 | var offset: u64 = 0; | 2327 | var bigint_space: Value.BigIntSpace = undefined; |
| 2401 | offset += err_set_size; | 2328 | const bigint = int_val.toBigInt(&bigint_space); |
| 2402 | offset = std.mem.alignForwardGeneric(u64, offset, payload_align); | | |
| 2403 | const payload_offset = offset; | | |
| 2404 | | 2329 | |
| 2405 | const fields: [2]*llvm.DIType = .{ | 2330 | const target = dg.module.getTarget(); |
| 2406 | dib.createMemberType( | 2331 | const int_info = tv.ty.intInfo(target); |
| 2407 | fwd_decl.toScope(), | 2332 | const llvm_type = dg.context.intType(int_info.bits); |
| 2408 | "tag", | 2333 | |
| 2409 | di_file, | 2334 | const unsigned_val = v: { |
| 2410 | line, | 2335 | if (bigint.limbs.len == 1) { |
| 2411 | err_set_size * 8, // size in bits | 2336 | break :v llvm_type.constInt(bigint.limbs[0], .False); |
| 2412 | err_set_align * 8, // align in bits | 2337 | } |
| 2413 | 0, // offset in bits | 2338 | if (@sizeOf(usize) == @sizeOf(u64)) { |
| 2414 | 0, // flags | 2339 | break :v llvm_type.constIntOfArbitraryPrecision( |
| 2415 | try dg.lowerDebugType(err_set_ty), | 2340 | @intCast(c_uint, bigint.limbs.len), |
| 2416 | ), | 2341 | bigint.limbs.ptr, |
| 2417 | dib.createMemberType( | 2342 | ); |
| 2418 | fwd_decl.toScope(), | 2343 | } |
| 2419 | "value", | 2344 | @panic("TODO implement bigint to llvm int for 32-bit compiler builds"); |
| 2420 | di_file, | | |
| 2421 | line, | | |
| 2422 | payload_size * 8, // size in bits | | |
| 2423 | payload_align * 8, // align in bits | | |
| 2424 | payload_offset * 8, // offset in bits | | |
| 2425 | 0, // flags | | |
| 2426 | try dg.lowerDebugType(payload_ty), | | |
| 2427 | ), | | |
| 2428 | }; | 2345 | }; |
| | 2346 | if (!bigint.positive) { |
| | 2347 | return llvm.constNeg(unsigned_val); |
| | 2348 | } |
| | 2349 | return unsigned_val; |
| | 2350 | }, |
| | 2351 | .Float => { |
| | 2352 | const llvm_ty = try dg.llvmType(tv.ty); |
| | 2353 | const target = dg.module.getTarget(); |
| | 2354 | switch (tv.ty.floatBits(target)) { |
| | 2355 | 16, 32, 64 => return llvm_ty.constReal(tv.val.toFloat(f64)), |
| | 2356 | 80 => { |
| | 2357 | const float = tv.val.toFloat(f80); |
| | 2358 | const repr = std.math.break_f80(float); |
| | 2359 | const llvm_i80 = dg.context.intType(80); |
| | 2360 | var x = llvm_i80.constInt(repr.exp, .False); |
| | 2361 | x = x.constShl(llvm_i80.constInt(64, .False)); |
| | 2362 | x = x.constOr(llvm_i80.constInt(repr.fraction, .False)); |
| | 2363 | if (backendSupportsF80(target)) { |
| | 2364 | return x.constBitCast(llvm_ty); |
| | 2365 | } else { |
| | 2366 | return x; |
| | 2367 | } |
| | 2368 | }, |
| | 2369 | 128 => { |
| | 2370 | var buf: [2]u64 = @bitCast([2]u64, tv.val.toFloat(f128)); |
| | 2371 | // LLVM seems to require that the lower half of the f128 be placed first |
| | 2372 | // in the buffer. |
| | 2373 | if (native_endian == .Big) { |
| | 2374 | std.mem.swap(u64, &buf[0], &buf[1]); |
| | 2375 | } |
| | 2376 | const int = dg.context.intType(128).constIntOfArbitraryPrecision(buf.len, &buf); |
| | 2377 | return int.constBitCast(llvm_ty); |
| | 2378 | }, |
| | 2379 | else => unreachable, |
| | 2380 | } |
| | 2381 | }, |
| | 2382 | .Pointer => switch (tv.val.tag()) { |
| | 2383 | .decl_ref_mut => return lowerDeclRefValue(dg, tv, tv.val.castTag(.decl_ref_mut).?.data.decl), |
| | 2384 | .decl_ref => return lowerDeclRefValue(dg, tv, tv.val.castTag(.decl_ref).?.data), |
| | 2385 | .variable => { |
| | 2386 | const decl = tv.val.castTag(.variable).?.data.owner_decl; |
| | 2387 | decl.markAlive(); |
| | 2388 | const val = try dg.resolveGlobalDecl(decl); |
| | 2389 | const llvm_var_type = try dg.llvmType(tv.ty); |
| | 2390 | const llvm_addrspace = dg.llvmAddressSpace(decl.@"addrspace"); |
| | 2391 | const llvm_type = llvm_var_type.pointerType(llvm_addrspace); |
| | 2392 | return val.constBitCast(llvm_type); |
| | 2393 | }, |
| | 2394 | .slice => { |
| | 2395 | const slice = tv.val.castTag(.slice).?.data; |
| | 2396 | var buf: Type.SlicePtrFieldTypeBuffer = undefined; |
| | 2397 | const fields: [2]*const llvm.Value = .{ |
| | 2398 | try dg.genTypedValue(.{ |
| | 2399 | .ty = tv.ty.slicePtrFieldType(&buf), |
| | 2400 | .val = slice.ptr, |
| | 2401 | }), |
| | 2402 | try dg.genTypedValue(.{ |
| | 2403 | .ty = Type.usize, |
| | 2404 | .val = slice.len, |
| | 2405 | }), |
| | 2406 | }; |
| | 2407 | return dg.context.constStruct(&fields, fields.len, .False); |
| | 2408 | }, |
| | 2409 | .int_u64, .one, .int_big_positive => { |
| | 2410 | const llvm_usize = try dg.llvmType(Type.usize); |
| | 2411 | const llvm_int = llvm_usize.constInt(tv.val.toUnsignedInt(), .False); |
| | 2412 | return llvm_int.constIntToPtr(try dg.llvmType(tv.ty)); |
| | 2413 | }, |
| | 2414 | .field_ptr, .opt_payload_ptr, .eu_payload_ptr, .elem_ptr => { |
| | 2415 | return dg.lowerParentPtr(tv.val, tv.ty.childType()); |
| | 2416 | }, |
| | 2417 | .null_value, .zero => { |
| | 2418 | const llvm_type = try dg.llvmType(tv.ty); |
| | 2419 | return llvm_type.constNull(); |
| | 2420 | }, |
| | 2421 | else => |tag| return dg.todo("implement const of pointer type '{}' ({})", .{ tv.ty, tag }), |
| | 2422 | }, |
| | 2423 | .Array => switch (tv.val.tag()) { |
| | 2424 | .bytes => { |
| | 2425 | const bytes = tv.val.castTag(.bytes).?.data; |
| | 2426 | return dg.context.constString( |
| | 2427 | bytes.ptr, |
| | 2428 | @intCast(c_uint, tv.ty.arrayLenIncludingSentinel()), |
| | 2429 | .True, // don't null terminate. bytes has the sentinel, if any. |
| | 2430 | ); |
| | 2431 | }, |
| | 2432 | .aggregate => { |
| | 2433 | const elem_vals = tv.val.castTag(.aggregate).?.data; |
| | 2434 | const elem_ty = tv.ty.elemType(); |
| | 2435 | const gpa = dg.gpa; |
| | 2436 | const len = @intCast(usize, tv.ty.arrayLenIncludingSentinel()); |
| | 2437 | const llvm_elems = try gpa.alloc(*const llvm.Value, len); |
| | 2438 | defer gpa.free(llvm_elems); |
| | 2439 | var need_unnamed = false; |
| | 2440 | for (elem_vals[0..len]) |elem_val, i| { |
| | 2441 | llvm_elems[i] = try dg.genTypedValue(.{ .ty = elem_ty, .val = elem_val }); |
| | 2442 | need_unnamed = need_unnamed or dg.isUnnamedType(elem_ty, llvm_elems[i]); |
| | 2443 | } |
| | 2444 | if (need_unnamed) { |
| | 2445 | return dg.context.constStruct( |
| | 2446 | llvm_elems.ptr, |
| | 2447 | @intCast(c_uint, llvm_elems.len), |
| | 2448 | .True, |
| | 2449 | ); |
| | 2450 | } else { |
| | 2451 | const llvm_elem_ty = try dg.llvmType(elem_ty); |
| | 2452 | return llvm_elem_ty.constArray( |
| | 2453 | llvm_elems.ptr, |
| | 2454 | @intCast(c_uint, llvm_elems.len), |
| | 2455 | ); |
| | 2456 | } |
| | 2457 | }, |
| | 2458 | .repeated => { |
| | 2459 | const val = tv.val.castTag(.repeated).?.data; |
| | 2460 | const elem_ty = tv.ty.elemType(); |
| | 2461 | const sentinel = tv.ty.sentinel(); |
| | 2462 | const len = @intCast(usize, tv.ty.arrayLen()); |
| | 2463 | const len_including_sent = len + @boolToInt(sentinel != null); |
| | 2464 | const gpa = dg.gpa; |
| | 2465 | const llvm_elems = try gpa.alloc(*const llvm.Value, len_including_sent); |
| | 2466 | defer gpa.free(llvm_elems); |
| 2429 | | 2467 | |
| 2430 | const replacement_di_ty = dib.createStructType( | 2468 | var need_unnamed = false; |
| 2431 | compile_unit_scope, | 2469 | if (len != 0) { |
| 2432 | name.ptr, | 2470 | for (llvm_elems[0..len]) |*elem| { |
| 2433 | di_file, | 2471 | elem.* = try dg.genTypedValue(.{ .ty = elem_ty, .val = val }); |
| 2434 | line, | 2472 | } |
| 2435 | ty.abiSize(target) * 8, // size in bits | 2473 | need_unnamed = need_unnamed or dg.isUnnamedType(elem_ty, llvm_elems[0]); |
| 2436 | ty.abiAlignment(target) * 8, // align in bits | 2474 | } |
| 2437 | 0, // flags | 2475 | |
| 2438 | null, // derived from | 2476 | if (sentinel) |sent| { |
| 2439 | &fields, | 2477 | llvm_elems[len] = try dg.genTypedValue(.{ .ty = elem_ty, .val = sent }); |
| 2440 | fields.len, | 2478 | need_unnamed = need_unnamed or dg.isUnnamedType(elem_ty, llvm_elems[len]); |
| 2441 | 0, // run time lang | 2479 | } |
| 2442 | null, // vtable holder | 2480 | |
| 2443 | "", // unique id | 2481 | if (need_unnamed) { |
| 2444 | ); | 2482 | return dg.context.constStruct( |
| 2445 | dib.replaceTemporary(fwd_decl, replacement_di_ty); | 2483 | llvm_elems.ptr, |
| 2446 | // The recursive call to `lowerDebugType` means we can't use `gop` anymore. | 2484 | @intCast(c_uint, llvm_elems.len), |
| 2447 | try dg.object.di_type_map.put(gpa, ty, replacement_di_ty); | 2485 | .True, |
| 2448 | return replacement_di_ty; | 2486 | ); |
| | 2487 | } else { |
| | 2488 | const llvm_elem_ty = try dg.llvmType(elem_ty); |
| | 2489 | return llvm_elem_ty.constArray( |
| | 2490 | llvm_elems.ptr, |
| | 2491 | @intCast(c_uint, llvm_elems.len), |
| | 2492 | ); |
| | 2493 | } |
| | 2494 | }, |
| | 2495 | .empty_array_sentinel => { |
| | 2496 | const elem_ty = tv.ty.elemType(); |
| | 2497 | const sent_val = tv.ty.sentinel().?; |
| | 2498 | const sentinel = try dg.genTypedValue(.{ .ty = elem_ty, .val = sent_val }); |
| | 2499 | const llvm_elems: [1]*const llvm.Value = .{sentinel}; |
| | 2500 | const need_unnamed = dg.isUnnamedType(elem_ty, llvm_elems[0]); |
| | 2501 | if (need_unnamed) { |
| | 2502 | return dg.context.constStruct(&llvm_elems, llvm_elems.len, .True); |
| | 2503 | } else { |
| | 2504 | const llvm_elem_ty = try dg.llvmType(elem_ty); |
| | 2505 | return llvm_elem_ty.constArray(&llvm_elems, llvm_elems.len); |
| | 2506 | } |
| | 2507 | }, |
| | 2508 | else => unreachable, |
| | 2509 | }, |
| | 2510 | .Optional => { |
| | 2511 | var buf: Type.Payload.ElemType = undefined; |
| | 2512 | const payload_ty = tv.ty.optionalChild(&buf); |
| | 2513 | const llvm_i1 = dg.context.intType(1); |
| | 2514 | const is_pl = !tv.val.isNull(); |
| | 2515 | const non_null_bit = if (is_pl) llvm_i1.constAllOnes() else llvm_i1.constNull(); |
| | 2516 | if (!payload_ty.hasRuntimeBitsIgnoreComptime()) { |
| | 2517 | return non_null_bit; |
| | 2518 | } |
| | 2519 | if (tv.ty.isPtrLikeOptional()) { |
| | 2520 | if (tv.val.castTag(.opt_payload)) |payload| { |
| | 2521 | return dg.genTypedValue(.{ .ty = payload_ty, .val = payload.data }); |
| | 2522 | } else if (is_pl) { |
| | 2523 | return dg.genTypedValue(.{ .ty = payload_ty, .val = tv.val }); |
| | 2524 | } else { |
| | 2525 | const llvm_ty = try dg.llvmType(tv.ty); |
| | 2526 | return llvm_ty.constNull(); |
| | 2527 | } |
| | 2528 | } |
| | 2529 | assert(payload_ty.zigTypeTag() != .Fn); |
| | 2530 | const fields: [2]*const llvm.Value = .{ |
| | 2531 | try dg.genTypedValue(.{ |
| | 2532 | .ty = payload_ty, |
| | 2533 | .val = if (tv.val.castTag(.opt_payload)) |pl| pl.data else Value.initTag(.undef), |
| | 2534 | }), |
| | 2535 | non_null_bit, |
| | 2536 | }; |
| | 2537 | return dg.context.constStruct(&fields, fields.len, .False); |
| | 2538 | }, |
| | 2539 | .Fn => { |
| | 2540 | const fn_decl = switch (tv.val.tag()) { |
| | 2541 | .extern_fn => tv.val.castTag(.extern_fn).?.data.owner_decl, |
| | 2542 | .function => tv.val.castTag(.function).?.data.owner_decl, |
| | 2543 | else => unreachable, |
| | 2544 | }; |
| | 2545 | fn_decl.markAlive(); |
| | 2546 | return dg.resolveLlvmFunction(fn_decl); |
| 2449 | }, | 2547 | }, |
| 2450 | .ErrorSet => { | 2548 | .ErrorSet => { |
| 2451 | // TODO make this a proper enum with all the error codes in it. | 2549 | const llvm_ty = try dg.llvmType(tv.ty); |
| 2452 | // will need to consider how to take incremental compilation into account. | 2550 | switch (tv.val.tag()) { |
| 2453 | gop.value_ptr.* = dib.createBasicType("anyerror", 16, DW.ATE.unsigned); | 2551 | .@"error" => { |
| 2454 | return gop.value_ptr.*; | 2552 | const err_name = tv.val.castTag(.@"error").?.data.name; |
| | 2553 | const kv = try dg.module.getErrorValue(err_name); |
| | 2554 | return llvm_ty.constInt(kv.value, .False); |
| | 2555 | }, |
| | 2556 | else => { |
| | 2557 | // In this case we are rendering an error union which has a 0 bits payload. |
| | 2558 | return llvm_ty.constNull(); |
| | 2559 | }, |
| | 2560 | } |
| 2455 | }, | 2561 | }, |
| 2456 | .Struct => { | 2562 | .ErrorUnion => { |
| 2457 | const compile_unit_scope = dg.object.di_compile_unit.?.toScope(); | 2563 | const error_type = tv.ty.errorUnionSet(); |
| 2458 | const name = try ty.nameAlloc(gpa); | 2564 | const payload_type = tv.ty.errorUnionPayload(); |
| 2459 | defer gpa.free(name); | 2565 | const is_pl = tv.val.errorUnionIsPayload(); |
| 2460 | const fwd_decl = dib.createReplaceableCompositeType( | | |
| 2461 | DW.TAG.structure_type, | | |
| 2462 | name.ptr, | | |
| 2463 | compile_unit_scope, | | |
| 2464 | null, // file | | |
| 2465 | 0, // line | | |
| 2466 | ); | | |
| 2467 | gop.value_ptr.* = fwd_decl; | | |
| 2468 | | 2566 | |
| 2469 | if (ty.isTupleOrAnonStruct()) { | 2567 | if (!payload_type.hasRuntimeBitsIgnoreComptime()) { |
| 2470 | const tuple = ty.tupleFields(); | 2568 | // We use the error type directly as the type. |
| | 2569 | const err_val = if (!is_pl) tv.val else Value.initTag(.zero); |
| | 2570 | return dg.genTypedValue(.{ .ty = error_type, .val = err_val }); |
| | 2571 | } |
| 2471 | | 2572 | |
| 2472 | var di_fields: std.ArrayListUnmanaged(*llvm.DIType) = .{}; | 2573 | const fields: [2]*const llvm.Value = .{ |
| 2473 | defer di_fields.deinit(gpa); | 2574 | try dg.genTypedValue(.{ |
| | 2575 | .ty = error_type, |
| | 2576 | .val = if (is_pl) Value.initTag(.zero) else tv.val, |
| | 2577 | }), |
| | 2578 | try dg.genTypedValue(.{ |
| | 2579 | .ty = payload_type, |
| | 2580 | .val = if (tv.val.castTag(.eu_payload)) |pl| pl.data else Value.initTag(.undef), |
| | 2581 | }), |
| | 2582 | }; |
| | 2583 | return dg.context.constStruct(&fields, fields.len, .False); |
| | 2584 | }, |
| | 2585 | .Struct => { |
| | 2586 | const llvm_struct_ty = try dg.llvmType(tv.ty); |
| | 2587 | const field_vals = tv.val.castTag(.aggregate).?.data; |
| | 2588 | const gpa = dg.gpa; |
| | 2589 | const target = dg.module.getTarget(); |
| 2474 | | 2590 | |
| 2475 | try di_fields.ensureUnusedCapacity(gpa, tuple.types.len); | 2591 | if (tv.ty.isTupleOrAnonStruct()) { |
| | 2592 | const tuple = tv.ty.tupleFields(); |
| | 2593 | var llvm_fields: std.ArrayListUnmanaged(*const llvm.Value) = .{}; |
| | 2594 | defer llvm_fields.deinit(gpa); |
| | 2595 | |
| | 2596 | try llvm_fields.ensureUnusedCapacity(gpa, tuple.types.len); |
| 2476 | | 2597 | |
| 2477 | comptime assert(struct_layout_version == 2); | 2598 | comptime assert(struct_layout_version == 2); |
| 2478 | var offset: u64 = 0; | 2599 | var offset: u64 = 0; |
| | 2600 | var big_align: u32 = 0; |
| | 2601 | var need_unnamed = false; |
| 2479 | | 2602 | |
| 2480 | for (tuple.types) |field_ty, i| { | 2603 | for (tuple.types) |field_ty, i| { |
| 2481 | const field_val = tuple.values[i]; | 2604 | if (tuple.values[i].tag() != .unreachable_value) continue; |
| 2482 | if (field_val.tag() != .unreachable_value) continue; | 2605 | if (!field_ty.hasRuntimeBitsIgnoreComptime()) continue; |
| 2483 | | 2606 | |
| 2484 | const field_size = field_ty.abiSize(target); | | |
| 2485 | const field_align = field_ty.abiAlignment(target); | 2607 | const field_align = field_ty.abiAlignment(target); |
| 2486 | const field_offset = std.mem.alignForwardGeneric(u64, offset, field_align); | 2608 | big_align = @maximum(big_align, field_align); |
| 2487 | offset = field_offset + field_size; | 2609 | const prev_offset = offset; |
| 2488 | | 2610 | offset = std.mem.alignForwardGeneric(u64, offset, field_align); |
| 2489 | const field_name = if (ty.castTag(.anon_struct)) |payload| | | |
| 2490 | try gpa.dupeZ(u8, payload.data.names[i]) | | |
| 2491 | else | | |
| 2492 | try std.fmt.allocPrintZ(gpa, "{d}", .{i}); | | |
| 2493 | defer gpa.free(field_name); | | |
| 2494 | | | |
| 2495 | try di_fields.append(gpa, dib.createMemberType( | | |
| 2496 | fwd_decl.toScope(), | | |
| 2497 | field_name, | | |
| 2498 | null, // file | | |
| 2499 | 0, // line | | |
| 2500 | field_size * 8, // size in bits | | |
| 2501 | field_align * 8, // align in bits | | |
| 2502 | field_offset * 8, // offset in bits | | |
| 2503 | 0, // flags | | |
| 2504 | try dg.lowerDebugType(field_ty), | | |
| 2505 | )); | | |
| 2506 | } | | |
| 2507 | | | |
| 2508 | const replacement_di_ty = dib.createStructType( | | |
| 2509 | compile_unit_scope, | | |
| 2510 | name.ptr, | | |
| 2511 | null, // file | | |
| 2512 | 0, // line | | |
| 2513 | ty.abiSize(target) * 8, // size in bits | | |
| 2514 | ty.abiAlignment(target) * 8, // align in bits | | |
| 2515 | 0, // flags | | |
| 2516 | null, // derived from | | |
| 2517 | di_fields.items.ptr, | | |
| 2518 | @intCast(c_int, di_fields.items.len), | | |
| 2519 | 0, // run time lang | | |
| 2520 | null, // vtable holder | | |
| 2521 | "", // unique id | | |
| 2522 | ); | | |
| 2523 | dib.replaceTemporary(fwd_decl, replacement_di_ty); | | |
| 2524 | // The recursive call to `lowerDebugType` means we can't use `gop` anymore. | | |
| 2525 | try dg.object.di_type_map.put(gpa, ty, replacement_di_ty); | | |
| 2526 | return replacement_di_ty; | | |
| 2527 | } | | |
| 2528 | | | |
| 2529 | const TODO_implement_this = true; // TODO | | |
| 2530 | if (TODO_implement_this or !ty.hasRuntimeBitsIgnoreComptime()) { | | |
| 2531 | const owner_decl = ty.getOwnerDecl(); | | |
| 2532 | const struct_di_ty = try dg.makeEmptyNamespaceDIType(owner_decl); | | |
| 2533 | dib.replaceTemporary(fwd_decl, struct_di_ty); | | |
| 2534 | // The recursive call to `lowerDebugType` via `makeEmptyNamespaceDIType` | | |
| 2535 | // means we can't use `gop` anymore. | | |
| 2536 | try dg.object.di_type_map.put(gpa, ty, struct_di_ty); | | |
| 2537 | return struct_di_ty; | | |
| 2538 | } | | |
| 2539 | @panic("TODO debug info type for struct"); | | |
| 2540 | | | |
| 2541 | //const struct_obj = ty.castTag(.@"struct").?.data; | | |
| 2542 | | | |
| 2543 | //if (struct_obj.layout == .Packed) { | | |
| 2544 | // var buf: Type.Payload.Bits = undefined; | | |
| 2545 | // const int_ty = struct_obj.packedIntegerType(target, &buf); | | |
| 2546 | // const int_llvm_ty = try dg.llvmType(int_ty); | | |
| 2547 | // gop.value_ptr.* = int_llvm_ty; | | |
| 2548 | // return int_llvm_ty; | | |
| 2549 | //} | | |
| 2550 | | | |
| 2551 | //const name = try struct_obj.getFullyQualifiedName(gpa); | | |
| 2552 | //defer gpa.free(name); | | |
| 2553 | | | |
| 2554 | //const llvm_struct_ty = dg.context.structCreateNamed(name); | | |
| 2555 | //gop.value_ptr.* = llvm_struct_ty; // must be done before any recursive calls | | |
| 2556 | | | |
| 2557 | //assert(struct_obj.haveFieldTypes()); | | |
| 2558 | | | |
| 2559 | //var llvm_field_types: std.ArrayListUnmanaged(*const llvm.Type) = .{}; | | |
| 2560 | //defer llvm_field_types.deinit(gpa); | | |
| 2561 | | | |
| 2562 | //try llvm_field_types.ensureUnusedCapacity(gpa, struct_obj.fields.count()); | | |
| 2563 | | | |
| 2564 | //comptime assert(struct_layout_version == 2); | | |
| 2565 | //var offset: u64 = 0; | | |
| 2566 | //var big_align: u32 = 0; | | |
| 2567 | | | |
| 2568 | //for (struct_obj.fields.values()) |field| { | | |
| 2569 | // if (field.is_comptime or !field.ty.hasRuntimeBitsIgnoreComptime()) continue; | | |
| 2570 | | | |
| 2571 | // const field_align = field.normalAlignment(target); | | |
| 2572 | // big_align = @maximum(big_align, field_align); | | |
| 2573 | // const prev_offset = offset; | | |
| 2574 | // offset = std.mem.alignForwardGeneric(u64, offset, field_align); | | |
| 2575 | | 2611 | |
| 2576 | // const padding_len = offset - prev_offset; | 2612 | const padding_len = offset - prev_offset; |
| 2577 | // if (padding_len > 0) { | 2613 | if (padding_len > 0) { |
| 2578 | // const llvm_array_ty = dg.context.intType(8).arrayType(@intCast(c_uint, padding_len)); | 2614 | const llvm_array_ty = dg.context.intType(8).arrayType(@intCast(c_uint, padding_len)); |
| 2579 | // try llvm_field_types.append(gpa, llvm_array_ty); | 2615 | // TODO make this and all other padding elsewhere in debug |
| 2580 | // } | 2616 | // builds be 0xaa not undef. |
| 2581 | // const field_llvm_ty = try dg.llvmType(field.ty); | 2617 | llvm_fields.appendAssumeCapacity(llvm_array_ty.getUndef()); |
| 2582 | // try llvm_field_types.append(gpa, field_llvm_ty); | 2618 | } |
| 2583 | | 2619 | |
| 2584 | // offset += field.ty.abiSize(target); | 2620 | const field_llvm_val = try dg.genTypedValue(.{ |
| 2585 | //} | 2621 | .ty = field_ty, |
| 2586 | //{ | 2622 | .val = field_vals[i], |
| 2587 | // const prev_offset = offset; | 2623 | }); |
| 2588 | // offset = std.mem.alignForwardGeneric(u64, offset, big_align); | | |
| 2589 | // const padding_len = offset - prev_offset; | | |
| 2590 | // if (padding_len > 0) { | | |
| 2591 | // const llvm_array_ty = dg.context.intType(8).arrayType(@intCast(c_uint, padding_len)); | | |
| 2592 | // try llvm_field_types.append(gpa, llvm_array_ty); | | |
| 2593 | // } | | |
| 2594 | //} | | |
| 2595 | | 2624 | |
| 2596 | //llvm_struct_ty.structSetBody( | 2625 | need_unnamed = need_unnamed or dg.isUnnamedType(field_ty, field_llvm_val); |
| 2597 | // llvm_field_types.items.ptr, | | |
| 2598 | // @intCast(c_uint, llvm_field_types.items.len), | | |
| 2599 | // .False, | | |
| 2600 | //); | | |
| 2601 | | 2626 | |
| 2602 | //return llvm_struct_ty; | 2627 | llvm_fields.appendAssumeCapacity(field_llvm_val); |
| 2603 | }, | | |
| 2604 | .Union => { | | |
| 2605 | const owner_decl = ty.getOwnerDecl(); | | |
| 2606 | | 2628 | |
| 2607 | const name = try ty.nameAlloc(gpa); | 2629 | offset += field_ty.abiSize(target); |
| 2608 | defer gpa.free(name); | 2630 | } |
| 2609 | const fwd_decl = dib.createReplaceableCompositeType( | 2631 | { |
| 2610 | DW.TAG.structure_type, | 2632 | const prev_offset = offset; |
| 2611 | name.ptr, | 2633 | offset = std.mem.alignForwardGeneric(u64, offset, big_align); |
| 2612 | dg.object.di_compile_unit.?.toScope(), | 2634 | const padding_len = offset - prev_offset; |
| 2613 | null, // file | 2635 | if (padding_len > 0) { |
| 2614 | 0, // line | 2636 | const llvm_array_ty = dg.context.intType(8).arrayType(@intCast(c_uint, padding_len)); |
| 2615 | ); | 2637 | llvm_fields.appendAssumeCapacity(llvm_array_ty.getUndef()); |
| 2616 | gop.value_ptr.* = fwd_decl; | 2638 | } |
| | 2639 | } |
| 2617 | | 2640 | |
| 2618 | const TODO_implement_this = true; // TODO | 2641 | if (need_unnamed) { |
| 2619 | if (TODO_implement_this or !ty.hasRuntimeBitsIgnoreComptime()) { | 2642 | return dg.context.constStruct( |
| 2620 | const union_di_ty = try dg.makeEmptyNamespaceDIType(owner_decl); | 2643 | llvm_fields.items.ptr, |
| 2621 | dib.replaceTemporary(fwd_decl, union_di_ty); | 2644 | @intCast(c_uint, llvm_fields.items.len), |
| 2622 | // The recursive call to `lowerDebugType` via `makeEmptyNamespaceDIType` | 2645 | .False, |
| 2623 | // means we can't use `gop` anymore. | 2646 | ); |
| 2624 | try dg.object.di_type_map.put(gpa, ty, union_di_ty); | 2647 | } else { |
| 2625 | return union_di_ty; | 2648 | return llvm_struct_ty.constNamedStruct( |
| | 2649 | llvm_fields.items.ptr, |
| | 2650 | @intCast(c_uint, llvm_fields.items.len), |
| | 2651 | ); |
| | 2652 | } |
| 2626 | } | 2653 | } |
| 2627 | | 2654 | |
| 2628 | @panic("TODO debug info type for union"); | 2655 | const struct_obj = tv.ty.castTag(.@"struct").?.data; |
| 2629 | //const gop = try dg.object.type_map.getOrPut(gpa, ty); | | |
| 2630 | //if (gop.found_existing) return gop.value_ptr.*; | | |
| 2631 | | 2656 | |
| 2632 | //// The Type memory is ephemeral; since we want to store a longer-lived | 2657 | if (struct_obj.layout == .Packed) { |
| 2633 | //// reference, we need to copy it here. | 2658 | const big_bits = struct_obj.packedIntegerBits(target); |
| 2634 | //gop.key_ptr.* = try ty.copy(dg.object.type_map_arena.allocator()); | 2659 | const int_llvm_ty = dg.context.intType(big_bits); |
| | 2660 | const fields = struct_obj.fields.values(); |
| | 2661 | comptime assert(Type.packed_struct_layout_version == 2); |
| | 2662 | var running_int: *const llvm.Value = int_llvm_ty.constNull(); |
| | 2663 | var running_bits: u16 = 0; |
| | 2664 | for (field_vals) |field_val, i| { |
| | 2665 | const field = fields[i]; |
| | 2666 | if (!field.ty.hasRuntimeBitsIgnoreComptime()) continue; |
| 2635 | | 2667 | |
| 2636 | //const layout = ty.unionGetLayout(target); | 2668 | const non_int_val = try dg.genTypedValue(.{ |
| 2637 | //const union_obj = ty.cast(Type.Payload.Union).?.data; | 2669 | .ty = field.ty, |
| | 2670 | .val = field_val, |
| | 2671 | }); |
| | 2672 | const ty_bit_size = @intCast(u16, field.ty.bitSize(target)); |
| | 2673 | const small_int_ty = dg.context.intType(ty_bit_size); |
| | 2674 | const small_int_val = non_int_val.constBitCast(small_int_ty); |
| | 2675 | const shift_rhs = int_llvm_ty.constInt(running_bits, .False); |
| | 2676 | // If the field is as large as the entire packed struct, this |
| | 2677 | // zext would go from, e.g. i16 to i16. This is legal with |
| | 2678 | // constZExtOrBitCast but not legal with constZExt. |
| | 2679 | const extended_int_val = small_int_val.constZExtOrBitCast(int_llvm_ty); |
| | 2680 | const shifted = extended_int_val.constShl(shift_rhs); |
| | 2681 | running_int = running_int.constOr(shifted); |
| | 2682 | running_bits += ty_bit_size; |
| | 2683 | } |
| | 2684 | return running_int; |
| | 2685 | } |
| 2638 | | 2686 | |
| 2639 | //if (layout.payload_size == 0) { | 2687 | const llvm_field_count = llvm_struct_ty.countStructElementTypes(); |
| 2640 | // const enum_tag_llvm_ty = try dg.llvmType(union_obj.tag_ty); | 2688 | var llvm_fields = try std.ArrayListUnmanaged(*const llvm.Value).initCapacity(gpa, llvm_field_count); |
| 2641 | // gop.value_ptr.* = enum_tag_llvm_ty; | 2689 | defer llvm_fields.deinit(gpa); |
| 2642 | // return enum_tag_llvm_ty; | | |
| 2643 | //} | | |
| 2644 | | 2690 | |
| 2645 | //const name = try union_obj.getFullyQualifiedName(gpa); | 2691 | comptime assert(struct_layout_version == 2); |
| 2646 | //defer gpa.free(name); | 2692 | var offset: u64 = 0; |
| | 2693 | var big_align: u32 = 0; |
| | 2694 | var need_unnamed = false; |
| 2647 | | 2695 | |
| 2648 | //const llvm_union_ty = dg.context.structCreateNamed(name); | 2696 | for (struct_obj.fields.values()) |field, i| { |
| 2649 | //gop.value_ptr.* = llvm_union_ty; // must be done before any recursive calls | 2697 | if (field.is_comptime or !field.ty.hasRuntimeBitsIgnoreComptime()) continue; |
| 2650 | | 2698 | |
| 2651 | //const aligned_field = union_obj.fields.values()[layout.most_aligned_field]; | 2699 | const field_align = field.normalAlignment(target); |
| 2652 | //const llvm_aligned_field_ty = try dg.llvmType(aligned_field.ty); | 2700 | big_align = @maximum(big_align, field_align); |
| | 2701 | const prev_offset = offset; |
| | 2702 | offset = std.mem.alignForwardGeneric(u64, offset, field_align); |
| 2653 | | 2703 | |
| 2654 | //const llvm_payload_ty = ty: { | 2704 | const padding_len = offset - prev_offset; |
| 2655 | // if (layout.most_aligned_field_size == layout.payload_size) { | 2705 | if (padding_len > 0) { |
| 2656 | // break :ty llvm_aligned_field_ty; | 2706 | const llvm_array_ty = dg.context.intType(8).arrayType(@intCast(c_uint, padding_len)); |
| 2657 | // } | 2707 | // TODO make this and all other padding elsewhere in debug |
| 2658 | // const padding_len = @intCast(c_uint, layout.payload_size - layout.most_aligned_field_size); | 2708 | // builds be 0xaa not undef. |
| 2659 | // const fields: [2]*const llvm.Type = .{ | 2709 | llvm_fields.appendAssumeCapacity(llvm_array_ty.getUndef()); |
| 2660 | // llvm_aligned_field_ty, | 2710 | } |
| 2661 | // dg.context.intType(8).arrayType(padding_len), | | |
| 2662 | // }; | | |
| 2663 | // break :ty dg.context.structType(&fields, fields.len, .True); | | |
| 2664 | //}; | | |
| 2665 | | 2711 | |
| 2666 | //if (layout.tag_size == 0) { | 2712 | const field_llvm_val = try dg.genTypedValue(.{ |
| 2667 | // var llvm_fields: [1]*const llvm.Type = .{llvm_payload_ty}; | 2713 | .ty = field.ty, |
| 2668 | // llvm_union_ty.structSetBody(&llvm_fields, llvm_fields.len, .False); | 2714 | .val = field_vals[i], |
| 2669 | // return llvm_union_ty; | 2715 | }); |
| 2670 | //} | | |
| 2671 | //const enum_tag_llvm_ty = try dg.llvmType(union_obj.tag_ty); | | |
| 2672 | | 2716 | |
| 2673 | //// Put the tag before or after the payload depending on which one's | 2717 | need_unnamed = need_unnamed or dg.isUnnamedType(field.ty, field_llvm_val); |
| 2674 | //// alignment is greater. | | |
| 2675 | //var llvm_fields: [3]*const llvm.Type = undefined; | | |
| 2676 | //var llvm_fields_len: c_uint = 2; | | |
| 2677 | | 2718 | |
| 2678 | //if (layout.tag_align >= layout.payload_align) { | 2719 | llvm_fields.appendAssumeCapacity(field_llvm_val); |
| 2679 | // llvm_fields = .{ enum_tag_llvm_ty, llvm_payload_ty, undefined }; | | |
| 2680 | //} else { | | |
| 2681 | // llvm_fields = .{ llvm_payload_ty, enum_tag_llvm_ty, undefined }; | | |
| 2682 | //} | | |
| 2683 | | 2720 | |
| 2684 | //// Insert padding to make the LLVM struct ABI size match the Zig union ABI size. | 2721 | offset += field.ty.abiSize(target); |
| 2685 | //if (layout.padding != 0) { | 2722 | } |
| 2686 | // llvm_fields[2] = dg.context.intType(8).arrayType(layout.padding); | 2723 | { |
| 2687 | // llvm_fields_len = 3; | 2724 | const prev_offset = offset; |
| 2688 | //} | 2725 | offset = std.mem.alignForwardGeneric(u64, offset, big_align); |
| | 2726 | const padding_len = offset - prev_offset; |
| | 2727 | if (padding_len > 0) { |
| | 2728 | const llvm_array_ty = dg.context.intType(8).arrayType(@intCast(c_uint, padding_len)); |
| | 2729 | llvm_fields.appendAssumeCapacity(llvm_array_ty.getUndef()); |
| | 2730 | } |
| | 2731 | } |
| 2689 | | 2732 | |
| 2690 | //llvm_union_ty.structSetBody(&llvm_fields, llvm_fields_len, .False); | 2733 | if (need_unnamed) { |
| 2691 | //return llvm_union_ty; | 2734 | return dg.context.constStruct( |
| | 2735 | llvm_fields.items.ptr, |
| | 2736 | @intCast(c_uint, llvm_fields.items.len), |
| | 2737 | .False, |
| | 2738 | ); |
| | 2739 | } else { |
| | 2740 | return llvm_struct_ty.constNamedStruct( |
| | 2741 | llvm_fields.items.ptr, |
| | 2742 | @intCast(c_uint, llvm_fields.items.len), |
| | 2743 | ); |
| | 2744 | } |
| 2692 | }, | 2745 | }, |
| 2693 | .Fn => { | 2746 | .Union => { |
| 2694 | const fn_info = ty.fnInfo(); | 2747 | const llvm_union_ty = try dg.llvmType(tv.ty); |
| 2695 | const sret = firstParamSRet(fn_info, target); | 2748 | const tag_and_val = tv.val.castTag(.@"union").?.data; |
| 2696 | | | |
| 2697 | var param_di_types = std.ArrayList(*llvm.DIType).init(dg.gpa); | | |
| 2698 | defer param_di_types.deinit(); | | |
| 2699 | | 2749 | |
| 2700 | // Return type goes first. | 2750 | const target = dg.module.getTarget(); |
| 2701 | const di_ret_ty = if (sret or !fn_info.return_type.hasRuntimeBitsIgnoreComptime()) | 2751 | const layout = tv.ty.unionGetLayout(target); |
| 2702 | Type.void | | |
| 2703 | else | | |
| 2704 | fn_info.return_type; | | |
| 2705 | try param_di_types.append(try dg.lowerDebugType(di_ret_ty)); | | |
| 2706 | | 2752 | |
| 2707 | if (sret) { | 2753 | if (layout.payload_size == 0) { |
| 2708 | var ptr_ty_payload: Type.Payload.ElemType = .{ | 2754 | return genTypedValue(dg, .{ |
| 2709 | .base = .{ .tag = .single_mut_pointer }, | 2755 | .ty = tv.ty.unionTagType().?, |
| 2710 | .data = fn_info.return_type, | 2756 | .val = tag_and_val.tag, |
| 2711 | }; | 2757 | }); |
| 2712 | const ptr_ty = Type.initPayload(&ptr_ty_payload.base); | | |
| 2713 | try param_di_types.append(try dg.lowerDebugType(ptr_ty)); | | |
| 2714 | } | 2758 | } |
| | 2759 | const union_obj = tv.ty.cast(Type.Payload.Union).?.data; |
| | 2760 | const field_index = union_obj.tag_ty.enumTagFieldIndex(tag_and_val.tag).?; |
| | 2761 | assert(union_obj.haveFieldTypes()); |
| | 2762 | const field_ty = union_obj.fields.values()[field_index].ty; |
| | 2763 | const payload = p: { |
| | 2764 | if (!field_ty.hasRuntimeBitsIgnoreComptime()) { |
| | 2765 | const padding_len = @intCast(c_uint, layout.payload_size); |
| | 2766 | break :p dg.context.intType(8).arrayType(padding_len).getUndef(); |
| | 2767 | } |
| | 2768 | const field = try genTypedValue(dg, .{ .ty = field_ty, .val = tag_and_val.val }); |
| | 2769 | const field_size = field_ty.abiSize(target); |
| | 2770 | if (field_size == layout.payload_size) { |
| | 2771 | break :p field; |
| | 2772 | } |
| | 2773 | const padding_len = @intCast(c_uint, layout.payload_size - field_size); |
| | 2774 | const fields: [2]*const llvm.Value = .{ |
| | 2775 | field, dg.context.intType(8).arrayType(padding_len).getUndef(), |
| | 2776 | }; |
| | 2777 | break :p dg.context.constStruct(&fields, fields.len, .True); |
| | 2778 | }; |
| 2715 | | 2779 | |
| 2716 | for (fn_info.param_types) |param_ty| { | 2780 | // In this case we must make an unnamed struct because LLVM does |
| 2717 | if (!param_ty.hasRuntimeBitsIgnoreComptime()) continue; | 2781 | // not support bitcasting our payload struct to the true union payload type. |
| | 2782 | // Instead we use an unnamed struct and every reference to the global |
| | 2783 | // must pointer cast to the expected type before accessing the union. |
| | 2784 | const need_unnamed = layout.most_aligned_field != field_index; |
| 2718 | | 2785 | |
| 2719 | if (isByRef(param_ty)) { | 2786 | if (layout.tag_size == 0) { |
| 2720 | var ptr_ty_payload: Type.Payload.ElemType = .{ | 2787 | const fields: [1]*const llvm.Value = .{payload}; |
| 2721 | .base = .{ .tag = .single_mut_pointer }, | 2788 | if (need_unnamed) { |
| 2722 | .data = param_ty, | 2789 | return dg.context.constStruct(&fields, fields.len, .False); |
| 2723 | }; | | |
| 2724 | const ptr_ty = Type.initPayload(&ptr_ty_payload.base); | | |
| 2725 | try param_di_types.append(try dg.lowerDebugType(ptr_ty)); | | |
| 2726 | } else { | 2790 | } else { |
| 2727 | try param_di_types.append(try dg.lowerDebugType(param_ty)); | 2791 | return llvm_union_ty.constNamedStruct(&fields, fields.len); |
| 2728 | } | 2792 | } |
| 2729 | } | 2793 | } |
| | 2794 | const llvm_tag_value = try genTypedValue(dg, .{ |
| | 2795 | .ty = tv.ty.unionTagType().?, |
| | 2796 | .val = tag_and_val.tag, |
| | 2797 | }); |
| | 2798 | var fields: [3]*const llvm.Value = undefined; |
| | 2799 | var fields_len: c_uint = 2; |
| | 2800 | if (layout.tag_align >= layout.payload_align) { |
| | 2801 | fields = .{ llvm_tag_value, payload, undefined }; |
| | 2802 | } else { |
| | 2803 | fields = .{ payload, llvm_tag_value, undefined }; |
| | 2804 | } |
| | 2805 | if (layout.padding != 0) { |
| | 2806 | fields[2] = dg.context.intType(8).arrayType(layout.padding).getUndef(); |
| | 2807 | fields_len = 3; |
| | 2808 | } |
| | 2809 | if (need_unnamed) { |
| | 2810 | return dg.context.constStruct(&fields, fields_len, .False); |
| | 2811 | } else { |
| | 2812 | return llvm_union_ty.constNamedStruct(&fields, fields_len); |
| | 2813 | } |
| | 2814 | }, |
| | 2815 | .Vector => switch (tv.val.tag()) { |
| | 2816 | .bytes => { |
| | 2817 | // Note, sentinel is not stored even if the type has a sentinel. |
| | 2818 | const bytes = tv.val.castTag(.bytes).?.data; |
| | 2819 | const vector_len = @intCast(usize, tv.ty.arrayLen()); |
| | 2820 | assert(vector_len == bytes.len or vector_len + 1 == bytes.len); |
| 2730 | | 2821 | |
| 2731 | const fn_di_ty = dib.createSubroutineType( | 2822 | const elem_ty = tv.ty.elemType(); |
| 2732 | param_di_types.items.ptr, | 2823 | const llvm_elems = try dg.gpa.alloc(*const llvm.Value, vector_len); |
| 2733 | @intCast(c_int, param_di_types.items.len), | 2824 | defer dg.gpa.free(llvm_elems); |
| 2734 | 0, | 2825 | for (llvm_elems) |*elem, i| { |
| 2735 | ); | 2826 | var byte_payload: Value.Payload.U64 = .{ |
| 2736 | // The recursive call to `lowerDebugType` means we can't use `gop` anymore. | 2827 | .base = .{ .tag = .int_u64 }, |
| 2737 | try dg.object.di_type_map.put(gpa, ty, fn_di_ty); | 2828 | .data = bytes[i], |
| 2738 | return fn_di_ty; | 2829 | }; |
| | 2830 | |
| | 2831 | elem.* = try dg.genTypedValue(.{ |
| | 2832 | .ty = elem_ty, |
| | 2833 | .val = Value.initPayload(&byte_payload.base), |
| | 2834 | }); |
| | 2835 | } |
| | 2836 | return llvm.constVector( |
| | 2837 | llvm_elems.ptr, |
| | 2838 | @intCast(c_uint, llvm_elems.len), |
| | 2839 | ); |
| | 2840 | }, |
| | 2841 | .aggregate => { |
| | 2842 | // Note, sentinel is not stored even if the type has a sentinel. |
| | 2843 | // The value includes the sentinel in those cases. |
| | 2844 | const elem_vals = tv.val.castTag(.aggregate).?.data; |
| | 2845 | const vector_len = @intCast(usize, tv.ty.arrayLen()); |
| | 2846 | assert(vector_len == elem_vals.len or vector_len + 1 == elem_vals.len); |
| | 2847 | const elem_ty = tv.ty.elemType(); |
| | 2848 | const llvm_elems = try dg.gpa.alloc(*const llvm.Value, vector_len); |
| | 2849 | defer dg.gpa.free(llvm_elems); |
| | 2850 | for (llvm_elems) |*elem, i| { |
| | 2851 | elem.* = try dg.genTypedValue(.{ .ty = elem_ty, .val = elem_vals[i] }); |
| | 2852 | } |
| | 2853 | return llvm.constVector( |
| | 2854 | llvm_elems.ptr, |
| | 2855 | @intCast(c_uint, llvm_elems.len), |
| | 2856 | ); |
| | 2857 | }, |
| | 2858 | .repeated => { |
| | 2859 | // Note, sentinel is not stored even if the type has a sentinel. |
| | 2860 | const val = tv.val.castTag(.repeated).?.data; |
| | 2861 | const elem_ty = tv.ty.elemType(); |
| | 2862 | const len = @intCast(usize, tv.ty.arrayLen()); |
| | 2863 | const llvm_elems = try dg.gpa.alloc(*const llvm.Value, len); |
| | 2864 | defer dg.gpa.free(llvm_elems); |
| | 2865 | for (llvm_elems) |*elem| { |
| | 2866 | elem.* = try dg.genTypedValue(.{ .ty = elem_ty, .val = val }); |
| | 2867 | } |
| | 2868 | return llvm.constVector( |
| | 2869 | llvm_elems.ptr, |
| | 2870 | @intCast(c_uint, llvm_elems.len), |
| | 2871 | ); |
| | 2872 | }, |
| | 2873 | else => unreachable, |
| 2739 | }, | 2874 | }, |
| | 2875 | |
| 2740 | .ComptimeInt => unreachable, | 2876 | .ComptimeInt => unreachable, |
| 2741 | .ComptimeFloat => unreachable, | 2877 | .ComptimeFloat => unreachable, |
| 2742 | .Type => unreachable, | 2878 | .Type => unreachable, |
| | 2879 | .EnumLiteral => unreachable, |
| | 2880 | .Void => unreachable, |
| | 2881 | .NoReturn => unreachable, |
| 2743 | .Undefined => unreachable, | 2882 | .Undefined => unreachable, |
| 2744 | .Null => unreachable, | 2883 | .Null => unreachable, |
| 2745 | .EnumLiteral => unreachable, | 2884 | .BoundFn => unreachable, |
| 2746 | | 2885 | .Opaque => unreachable, |
| 2747 | .BoundFn => @panic("TODO remove BoundFn from the language"), | | |
| 2748 | | | |
| 2749 | .Frame => @panic("TODO implement lowerDebugType for Frame types"), | | |
| 2750 | .AnyFrame => @panic("TODO implement lowerDebugType for AnyFrame types"), | | |
| 2751 | } | | |
| 2752 | } | | |
| 2753 | | 2886 | |
| 2754 | fn namespaceToDebugScope(dg: *DeclGen, namespace: *const Module.Namespace) !*llvm.DIScope { | 2887 | .Frame, |
| 2755 | if (namespace.parent == null) { | 2888 | .AnyFrame, |
| 2756 | const di_file = try dg.object.getDIFile(dg.gpa, namespace.file_scope); | 2889 | => return dg.todo("implement const of type '{}'", .{tv.ty}), |
| 2757 | return di_file.toScope(); | | |
| 2758 | } | 2890 | } |
| 2759 | const di_type = try dg.lowerDebugType(namespace.ty); | | |
| 2760 | return di_type.toScope(); | | |
| 2761 | } | | |
| 2762 | | | |
| 2763 | /// This is to be used instead of void for debug info types, to avoid tripping | | |
| 2764 | /// Assertion `!isa<DIType>(Scope) && "shouldn't make a namespace scope for a type"' | | |
| 2765 | /// when targeting CodeView (Windows). | | |
| 2766 | fn makeEmptyNamespaceDIType(dg: *DeclGen, decl: *const Module.Decl) !*llvm.DIType { | | |
| 2767 | const fields: [0]*llvm.DIType = .{}; | | |
| 2768 | return dg.object.di_builder.?.createStructType( | | |
| 2769 | try dg.namespaceToDebugScope(decl.src_namespace), | | |
| 2770 | decl.name, // TODO use fully qualified name | | |
| 2771 | try dg.object.getDIFile(dg.gpa, decl.src_namespace.file_scope), | | |
| 2772 | decl.src_line + 1, | | |
| 2773 | 0, // size in bits | | |
| 2774 | 0, // align in bits | | |
| 2775 | 0, // flags | | |
| 2776 | null, // derived from | | |
| 2777 | undefined, // TODO should be able to pass &fields, | | |
| 2778 | fields.len, | | |
| 2779 | 0, // run time lang | | |
| 2780 | null, // vtable holder | | |
| 2781 | "", // unique id | | |
| 2782 | ); | | |
| 2783 | } | 2891 | } |
| 2784 | | 2892 | |
| 2785 | const ParentPtr = struct { | 2893 | const ParentPtr = struct { |
| ... | @@ -4085,7 +4193,7 @@ pub const FuncGen = struct { | ... | @@ -4085,7 +4193,7 @@ pub const FuncGen = struct { |
| 4085 | name.ptr, | 4193 | name.ptr, |
| 4086 | self.di_file.?, | 4194 | self.di_file.?, |
| 4087 | self.prev_dbg_line, | 4195 | self.prev_dbg_line, |
| 4088 | try self.dg.lowerDebugType(ptr_ty.childType()), | 4196 | try self.dg.object.lowerDebugType(ptr_ty.childType(), .full), |
| 4089 | true, // always preserve | 4197 | true, // always preserve |
| 4090 | 0, // flags | 4198 | 0, // flags |
| 4091 | ); | 4199 | ); |
| ... | @@ -4107,7 +4215,7 @@ pub const FuncGen = struct { | ... | @@ -4107,7 +4215,7 @@ pub const FuncGen = struct { |
| 4107 | name.ptr, | 4215 | name.ptr, |
| 4108 | self.di_file.?, | 4216 | self.di_file.?, |
| 4109 | self.prev_dbg_line, | 4217 | self.prev_dbg_line, |
| 4110 | try self.dg.lowerDebugType(operand_ty), | 4218 | try self.dg.object.lowerDebugType(operand_ty, .full), |
| 4111 | true, // always preserve | 4219 | true, // always preserve |
| 4112 | 0, // flags | 4220 | 0, // flags |
| 4113 | ); | 4221 | ); |
| ... | @@ -5359,7 +5467,7 @@ pub const FuncGen = struct { | ... | @@ -5359,7 +5467,7 @@ pub const FuncGen = struct { |
| 5359 | func.getParamName(src_index).ptr, // TODO test 0 bit args | 5467 | func.getParamName(src_index).ptr, // TODO test 0 bit args |
| 5360 | self.di_file.?, | 5468 | self.di_file.?, |
| 5361 | lbrace_line, | 5469 | lbrace_line, |
| 5362 | try self.dg.lowerDebugType(inst_ty), | 5470 | try self.dg.object.lowerDebugType(inst_ty, .full), |
| 5363 | true, // always preserve | 5471 | true, // always preserve |
| 5364 | 0, // flags | 5472 | 0, // flags |
| 5365 | self.arg_index, // includes +1 because 0 is return type | 5473 | self.arg_index, // includes +1 because 0 is return type |
| ... | @@ -7107,3 +7215,30 @@ fn backendSupportsF80(target: std.Target) bool { | ... | @@ -7107,3 +7215,30 @@ fn backendSupportsF80(target: std.Target) bool { |
| 7107 | /// We can do this because for all types, Zig ABI alignment >= LLVM ABI | 7215 | /// We can do this because for all types, Zig ABI alignment >= LLVM ABI |
| 7108 | /// alignment. | 7216 | /// alignment. |
| 7109 | const struct_layout_version = 2; | 7217 | const struct_layout_version = 2; |
| | 7218 | |
| | 7219 | /// We use the least significant bit of the pointer address to tell us |
| | 7220 | /// whether the type is fully resolved. Types that are only fwd declared |
| | 7221 | /// have the LSB flipped to a 1. |
| | 7222 | const AnnotatedDITypePtr = enum(usize) { |
| | 7223 | _, |
| | 7224 | |
| | 7225 | fn initFwd(di_type: *llvm.DIType) AnnotatedDITypePtr { |
| | 7226 | const addr = @ptrToInt(di_type); |
| | 7227 | assert(@truncate(u1, addr) == 0); |
| | 7228 | return @intToEnum(AnnotatedDITypePtr, addr | 1); |
| | 7229 | } |
| | 7230 | |
| | 7231 | fn initFull(di_type: *llvm.DIType) AnnotatedDITypePtr { |
| | 7232 | const addr = @ptrToInt(di_type); |
| | 7233 | return @intToEnum(AnnotatedDITypePtr, addr); |
| | 7234 | } |
| | 7235 | |
| | 7236 | fn toDIType(self: AnnotatedDITypePtr) *llvm.DIType { |
| | 7237 | const fixed_addr = @enumToInt(self) & ~@as(usize, 1); |
| | 7238 | return @intToPtr(*llvm.DIType, fixed_addr); |
| | 7239 | } |
| | 7240 | |
| | 7241 | fn isFwdOnly(self: AnnotatedDITypePtr) bool { |
| | 7242 | return @truncate(u1, @enumToInt(self)) != 0; |
| | 7243 | } |
| | 7244 | }; |