| author | |
| committer | |
| log | ff8a49448c70ffe73826c7987522ed63fddd654f |
| tree | 36107c8b3539051f4539836d09145e231f260293 |
| parent | 2cb52235b91f7e4bf5a4ebf77a5008adfc30c8b9 |
5 files changed, 2751 insertions(+), 902 deletions(-)
src/Module.zig+4-8| ... | ... | @@ -835,10 +835,6 @@ pub const Decl = struct { |
| 835 | 835 | assert(decl.has_tv); |
| 836 | 836 | return @as(u32, @intCast(decl.alignment.toByteUnitsOptional() orelse decl.ty.abiAlignment(mod))); |
| 837 | 837 | } |
| 838 | ||
| 839 | pub fn intern(decl: *Decl, mod: *Module) Allocator.Error!void { | |
| 840 | decl.val = (try decl.val.intern(decl.ty, mod)).toValue(); | |
| 841 | } | |
| 842 | 838 | }; |
| 843 | 839 | |
| 844 | 840 | /// This state is attached to every Decl when Module emit_h is non-null. |
| ... | ... | @@ -4204,7 +4200,7 @@ pub fn semaFile(mod: *Module, file: *File) SemaError!void { |
| 4204 | 4200 | try wip_captures.finalize(); |
| 4205 | 4201 | for (comptime_mutable_decls.items) |decl_index| { |
| 4206 | 4202 | const decl = mod.declPtr(decl_index); |
| 4207 | try decl.intern(mod); | |
| 4203 | _ = try decl.internValue(mod); | |
| 4208 | 4204 | } |
| 4209 | 4205 | new_decl.analysis = .complete; |
| 4210 | 4206 | } else |err| switch (err) { |
| ... | ... | @@ -4315,7 +4311,7 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool { |
| 4315 | 4311 | try wip_captures.finalize(); |
| 4316 | 4312 | for (comptime_mutable_decls.items) |ct_decl_index| { |
| 4317 | 4313 | const ct_decl = mod.declPtr(ct_decl_index); |
| 4318 | try ct_decl.intern(mod); | |
| 4314 | _ = try ct_decl.internValue(mod); | |
| 4319 | 4315 | } |
| 4320 | 4316 | const align_src: LazySrcLoc = .{ .node_offset_var_decl_align = 0 }; |
| 4321 | 4317 | const section_src: LazySrcLoc = .{ .node_offset_var_decl_section = 0 }; |
| ... | ... | @@ -5362,7 +5358,7 @@ pub fn analyzeFnBody(mod: *Module, func_index: InternPool.Index, arena: Allocato |
| 5362 | 5358 | try wip_captures.finalize(); |
| 5363 | 5359 | for (comptime_mutable_decls.items) |ct_decl_index| { |
| 5364 | 5360 | const ct_decl = mod.declPtr(ct_decl_index); |
| 5365 | try ct_decl.intern(mod); | |
| 5361 | _ = try ct_decl.internValue(mod); | |
| 5366 | 5362 | } |
| 5367 | 5363 | |
| 5368 | 5364 | // Copy the block into place and mark that as the main block. |
| ... | ... | @@ -6369,7 +6365,7 @@ pub fn markDeclAlive(mod: *Module, decl: *Decl) Allocator.Error!void { |
| 6369 | 6365 | if (decl.alive) return; |
| 6370 | 6366 | decl.alive = true; |
| 6371 | 6367 | |
| 6372 | try decl.intern(mod); | |
| 6368 | _ = try decl.internValue(mod); | |
| 6373 | 6369 | |
| 6374 | 6370 | // This is the first time we are marking this Decl alive. We must |
| 6375 | 6371 | // therefore recurse into its value and mark any Decl it references |
src/Sema.zig+4-4| ... | ... | @@ -3899,7 +3899,7 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com |
| 3899 | 3899 | try mod.declareDeclDependency(sema.owner_decl_index, decl_index); |
| 3900 | 3900 | |
| 3901 | 3901 | const decl = mod.declPtr(decl_index); |
| 3902 | if (iac.is_const) try decl.intern(mod); | |
| 3902 | if (iac.is_const) _ = try decl.internValue(mod); | |
| 3903 | 3903 | const final_elem_ty = decl.ty; |
| 3904 | 3904 | const final_ptr_ty = try mod.ptrType(.{ |
| 3905 | 3905 | .child = final_elem_ty.toIntern(), |
| ... | ... | @@ -33577,7 +33577,7 @@ fn semaBackingIntType(mod: *Module, struct_obj: *Module.Struct) CompileError!voi |
| 33577 | 33577 | try wip_captures.finalize(); |
| 33578 | 33578 | for (comptime_mutable_decls.items) |ct_decl_index| { |
| 33579 | 33579 | const ct_decl = mod.declPtr(ct_decl_index); |
| 33580 | try ct_decl.intern(mod); | |
| 33580 | _ = try ct_decl.internValue(mod); | |
| 33581 | 33581 | } |
| 33582 | 33582 | } else { |
| 33583 | 33583 | if (fields_bit_sum > std.math.maxInt(u16)) { |
| ... | ... | @@ -34645,7 +34645,7 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void |
| 34645 | 34645 | try wip_captures.finalize(); |
| 34646 | 34646 | for (comptime_mutable_decls.items) |ct_decl_index| { |
| 34647 | 34647 | const ct_decl = mod.declPtr(ct_decl_index); |
| 34648 | try ct_decl.intern(mod); | |
| 34648 | _ = try ct_decl.internValue(mod); | |
| 34649 | 34649 | } |
| 34650 | 34650 | |
| 34651 | 34651 | struct_obj.have_field_inits = true; |
| ... | ... | @@ -34744,7 +34744,7 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void { |
| 34744 | 34744 | try wip_captures.finalize(); |
| 34745 | 34745 | for (comptime_mutable_decls.items) |ct_decl_index| { |
| 34746 | 34746 | const ct_decl = mod.declPtr(ct_decl_index); |
| 34747 | try ct_decl.intern(mod); | |
| 34747 | _ = try ct_decl.internValue(mod); | |
| 34748 | 34748 | } |
| 34749 | 34749 | |
| 34750 | 34750 | try union_obj.fields.ensureTotalCapacity(mod.tmp_hack_arena.allocator(), fields_len); |
src/codegen/llvm.zig+814-703| ... | ... | @@ -579,7 +579,7 @@ pub const Object = struct { |
| 579 | 579 | /// The LLVM global table which holds the names corresponding to Zig errors. |
| 580 | 580 | /// Note that the values are not added until flushModule, when all errors in |
| 581 | 581 | /// the compilation are known. |
| 582 | error_name_table: ?*llvm.Value, | |
| 582 | error_name_table: Builder.Variable.Index, | |
| 583 | 583 | /// This map is usually very close to empty. It tracks only the cases when a |
| 584 | 584 | /// second extern Decl could not be emitted with the correct name due to a |
| 585 | 585 | /// name collision. |
| ... | ... | @@ -763,7 +763,7 @@ pub const Object = struct { |
| 763 | 763 | .named_enum_map = .{}, |
| 764 | 764 | .type_map = .{}, |
| 765 | 765 | .di_type_map = .{}, |
| 766 | .error_name_table = null, | |
| 766 | .error_name_table = .none, | |
| 767 | 767 | .extern_collisions = .{}, |
| 768 | 768 | .null_opt_addr = null, |
| 769 | 769 | }; |
| ... | ... | @@ -803,51 +803,85 @@ pub const Object = struct { |
| 803 | 803 | return slice.ptr; |
| 804 | 804 | } |
| 805 | 805 | |
| 806 | fn genErrorNameTable(o: *Object) !void { | |
| 806 | fn genErrorNameTable(o: *Object) Allocator.Error!void { | |
| 807 | 807 | // If o.error_name_table is null, there was no instruction that actually referenced the error table. |
| 808 | const error_name_table_ptr_global = o.error_name_table orelse return; | |
| 808 | const error_name_table_ptr_global = o.error_name_table; | |
| 809 | if (error_name_table_ptr_global == .none) return; | |
| 809 | 810 | |
| 810 | 811 | const mod = o.module; |
| 811 | 812 | |
| 813 | const error_name_list = mod.global_error_set.keys(); | |
| 814 | const llvm_errors = try mod.gpa.alloc(Builder.Constant, error_name_list.len); | |
| 815 | defer mod.gpa.free(llvm_errors); | |
| 816 | ||
| 812 | 817 | // TODO: Address space |
| 813 | const llvm_usize_ty = try o.lowerType(Type.usize); | |
| 814 | const llvm_slice_ty = (try o.builder.structType(.normal, &.{ .ptr, llvm_usize_ty })).toLlvm(&o.builder); | |
| 815 | 818 | const slice_ty = Type.slice_const_u8_sentinel_0; |
| 816 | 819 | const slice_alignment = slice_ty.abiAlignment(mod); |
| 820 | const llvm_usize_ty = try o.lowerType(Type.usize); | |
| 821 | const llvm_slice_ty = try o.lowerType(slice_ty); | |
| 822 | const llvm_table_ty = try o.builder.arrayType(error_name_list.len, llvm_slice_ty); | |
| 817 | 823 | |
| 818 | const error_name_list = mod.global_error_set.keys(); | |
| 819 | const llvm_errors = try mod.gpa.alloc(*llvm.Value, error_name_list.len); | |
| 820 | defer mod.gpa.free(llvm_errors); | |
| 821 | ||
| 822 | llvm_errors[0] = llvm_slice_ty.getUndef(); | |
| 824 | llvm_errors[0] = try o.builder.undefConst(llvm_slice_ty); | |
| 823 | 825 | for (llvm_errors[1..], error_name_list[1..]) |*llvm_error, name_nts| { |
| 824 | const name = mod.intern_pool.stringToSlice(name_nts); | |
| 825 | const str_init = o.context.constString(name.ptr, @as(c_uint, @intCast(name.len)), .False); | |
| 826 | const str_global = o.llvm_module.addGlobal(str_init.typeOf(), ""); | |
| 827 | str_global.setInitializer(str_init); | |
| 826 | const name = try o.builder.string(mod.intern_pool.stringToSlice(name_nts)); | |
| 827 | const str_init = try o.builder.stringNullConst(name); | |
| 828 | const str_ty = str_init.typeOf(&o.builder); | |
| 829 | const str_global = o.llvm_module.addGlobal(str_ty.toLlvm(&o.builder), ""); | |
| 830 | str_global.setInitializer(str_init.toLlvm(&o.builder)); | |
| 828 | 831 | str_global.setLinkage(.Private); |
| 829 | 832 | str_global.setGlobalConstant(.True); |
| 830 | 833 | str_global.setUnnamedAddr(.True); |
| 831 | 834 | str_global.setAlignment(1); |
| 832 | 835 | |
| 833 | const slice_fields = [_]*llvm.Value{ | |
| 834 | str_global, | |
| 835 | (try o.builder.intConst(llvm_usize_ty, name.len)).toLlvm(&o.builder), | |
| 836 | var global = Builder.Global{ | |
| 837 | .linkage = .private, | |
| 838 | .unnamed_addr = .unnamed_addr, | |
| 839 | .type = str_ty, | |
| 840 | .alignment = comptime Builder.Alignment.fromByteUnits(1), | |
| 841 | .kind = .{ .variable = @enumFromInt(o.builder.variables.items.len) }, | |
| 836 | 842 | }; |
| 837 | llvm_error.* = llvm_slice_ty.constNamedStruct(&slice_fields, slice_fields.len); | |
| 838 | } | |
| 843 | var variable = Builder.Variable{ | |
| 844 | .global = @enumFromInt(o.builder.globals.count()), | |
| 845 | .mutability = .constant, | |
| 846 | .init = str_init, | |
| 847 | }; | |
| 848 | try o.builder.llvm_globals.append(o.gpa, str_global); | |
| 849 | const str_global_index = try o.builder.addGlobal(.none, global); | |
| 850 | try o.builder.variables.append(o.gpa, variable); | |
| 839 | 851 | |
| 840 | const error_name_table_init = llvm_slice_ty.constArray(llvm_errors.ptr, @as(c_uint, @intCast(error_name_list.len))); | |
| 852 | llvm_error.* = try o.builder.structConst(llvm_slice_ty, &.{ | |
| 853 | str_global_index.toConst(), | |
| 854 | try o.builder.intConst(llvm_usize_ty, name.toSlice(&o.builder).?.len), | |
| 855 | }); | |
| 856 | } | |
| 841 | 857 | |
| 842 | const error_name_table_global = o.llvm_module.addGlobal(error_name_table_init.typeOf(), ""); | |
| 843 | error_name_table_global.setInitializer(error_name_table_init); | |
| 858 | const error_name_table_init = try o.builder.arrayConst(llvm_table_ty, llvm_errors); | |
| 859 | const error_name_table_global = o.llvm_module.addGlobal(llvm_table_ty.toLlvm(&o.builder), ""); | |
| 860 | error_name_table_global.setInitializer(error_name_table_init.toLlvm(&o.builder)); | |
| 844 | 861 | error_name_table_global.setLinkage(.Private); |
| 845 | 862 | error_name_table_global.setGlobalConstant(.True); |
| 846 | 863 | error_name_table_global.setUnnamedAddr(.True); |
| 847 | 864 | error_name_table_global.setAlignment(slice_alignment); // TODO: Dont hardcode |
| 848 | 865 | |
| 866 | var global = Builder.Global{ | |
| 867 | .linkage = .private, | |
| 868 | .unnamed_addr = .unnamed_addr, | |
| 869 | .type = llvm_table_ty, | |
| 870 | .alignment = Builder.Alignment.fromByteUnits(slice_alignment), | |
| 871 | .kind = .{ .variable = @enumFromInt(o.builder.variables.items.len) }, | |
| 872 | }; | |
| 873 | var variable = Builder.Variable{ | |
| 874 | .global = @enumFromInt(o.builder.globals.count()), | |
| 875 | .mutability = .constant, | |
| 876 | .init = error_name_table_init, | |
| 877 | }; | |
| 878 | try o.builder.llvm_globals.append(o.gpa, error_name_table_global); | |
| 879 | _ = try o.builder.addGlobal(.none, global); | |
| 880 | try o.builder.variables.append(o.gpa, variable); | |
| 881 | ||
| 849 | 882 | const error_name_table_ptr = error_name_table_global; |
| 850 | error_name_table_ptr_global.setInitializer(error_name_table_ptr); | |
| 883 | error_name_table_ptr_global.ptr(&o.builder).init = variable.global.toConst(); | |
| 884 | error_name_table_ptr_global.toLlvm(&o.builder).setInitializer(error_name_table_ptr); | |
| 851 | 885 | } |
| 852 | 886 | |
| 853 | 887 | fn genCmpLtErrorsLenFunction(object: *Object) !void { |
| ... | ... | @@ -1116,9 +1150,9 @@ pub const Object = struct { |
| 1116 | 1150 | .err_msg = null, |
| 1117 | 1151 | }; |
| 1118 | 1152 | |
| 1119 | const function_index = try o.resolveLlvmFunction(decl_index); | |
| 1120 | const function = function_index.ptr(&o.builder); | |
| 1121 | const llvm_func = function.global.toLlvm(&o.builder); | |
| 1153 | const function = try o.resolveLlvmFunction(decl_index); | |
| 1154 | const global = function.ptrConst(&o.builder).global; | |
| 1155 | const llvm_func = global.toLlvm(&o.builder); | |
| 1122 | 1156 | |
| 1123 | 1157 | if (func.analysis(ip).is_noinline) { |
| 1124 | 1158 | o.addFnAttr(llvm_func, "noinline"); |
| ... | ... | @@ -1155,8 +1189,10 @@ pub const Object = struct { |
| 1155 | 1189 | o.addFnAttrString(llvm_func, "no-stack-arg-probe", ""); |
| 1156 | 1190 | } |
| 1157 | 1191 | |
| 1158 | if (ip.stringToSliceUnwrap(decl.@"linksection")) |section| | |
| 1192 | if (ip.stringToSliceUnwrap(decl.@"linksection")) |section| { | |
| 1193 | global.ptr(&o.builder).section = try o.builder.string(section); | |
| 1159 | 1194 | llvm_func.setSection(section); |
| 1195 | } | |
| 1160 | 1196 | |
| 1161 | 1197 | // Remove all the basic blocks of a function in order to start over, generating |
| 1162 | 1198 | // LLVM IR from an empty function body. |
| ... | ... | @@ -1166,7 +1202,7 @@ pub const Object = struct { |
| 1166 | 1202 | |
| 1167 | 1203 | const builder = o.context.createBuilder(); |
| 1168 | 1204 | |
| 1169 | function.body = {}; | |
| 1205 | function.ptr(&o.builder).body = {}; | |
| 1170 | 1206 | const entry_block = o.context.appendBasicBlock(llvm_func, "Entry"); |
| 1171 | 1207 | builder.positionBuilderAtEnd(entry_block); |
| 1172 | 1208 | |
| ... | ... | @@ -1487,8 +1523,8 @@ pub const Object = struct { |
| 1487 | 1523 | const gpa = mod.gpa; |
| 1488 | 1524 | // If the module does not already have the function, we ignore this function call |
| 1489 | 1525 | // because we call `updateDeclExports` at the end of `updateFunc` and `updateDecl`. |
| 1490 | const global_index = self.decl_map.get(decl_index) orelse return; | |
| 1491 | const llvm_global = global_index.toLlvm(&self.builder); | |
| 1526 | const global = self.decl_map.get(decl_index) orelse return; | |
| 1527 | const llvm_global = global.toLlvm(&self.builder); | |
| 1492 | 1528 | const decl = mod.declPtr(decl_index); |
| 1493 | 1529 | if (decl.isExtern(mod)) { |
| 1494 | 1530 | const decl_name = decl_name: { |
| ... | ... | @@ -1511,18 +1547,17 @@ pub const Object = struct { |
| 1511 | 1547 | } |
| 1512 | 1548 | } |
| 1513 | 1549 | |
| 1514 | try global_index.rename(&self.builder, decl_name); | |
| 1515 | const decl_name_slice = decl_name.toSlice(&self.builder).?; | |
| 1516 | const global = global_index.ptr(&self.builder); | |
| 1517 | global.unnamed_addr = .default; | |
| 1550 | try global.rename(&self.builder, decl_name); | |
| 1551 | global.ptr(&self.builder).unnamed_addr = .default; | |
| 1518 | 1552 | llvm_global.setUnnamedAddr(.False); |
| 1519 | global.linkage = .external; | |
| 1553 | global.ptr(&self.builder).linkage = .external; | |
| 1520 | 1554 | llvm_global.setLinkage(.External); |
| 1521 | 1555 | if (mod.wantDllExports()) { |
| 1522 | global.dll_storage_class = .default; | |
| 1556 | global.ptr(&self.builder).dll_storage_class = .default; | |
| 1523 | 1557 | llvm_global.setDLLStorageClass(.Default); |
| 1524 | 1558 | } |
| 1525 | 1559 | if (self.di_map.get(decl)) |di_node| { |
| 1560 | const decl_name_slice = decl_name.toSlice(&self.builder).?; | |
| 1526 | 1561 | if (try decl.isFunction(mod)) { |
| 1527 | 1562 | const di_func = @as(*llvm.DISubprogram, @ptrCast(di_node)); |
| 1528 | 1563 | const linkage_name = llvm.MDString.get(self.context, decl_name_slice.ptr, decl_name_slice.len); |
| ... | ... | @@ -1533,21 +1568,31 @@ pub const Object = struct { |
| 1533 | 1568 | di_global.replaceLinkageName(linkage_name); |
| 1534 | 1569 | } |
| 1535 | 1570 | } |
| 1536 | if (decl.val.getVariable(mod)) |variable| { | |
| 1537 | if (variable.is_threadlocal) { | |
| 1571 | if (decl.val.getVariable(mod)) |decl_var| { | |
| 1572 | if (decl_var.is_threadlocal) { | |
| 1573 | global.ptrConst(&self.builder).kind.variable.ptr(&self.builder).thread_local = | |
| 1574 | .generaldynamic; | |
| 1538 | 1575 | llvm_global.setThreadLocalMode(.GeneralDynamicTLSModel); |
| 1539 | 1576 | } else { |
| 1577 | global.ptrConst(&self.builder).kind.variable.ptr(&self.builder).thread_local = | |
| 1578 | .default; | |
| 1540 | 1579 | llvm_global.setThreadLocalMode(.NotThreadLocal); |
| 1541 | 1580 | } |
| 1542 | if (variable.is_weak_linkage) { | |
| 1581 | if (decl_var.is_weak_linkage) { | |
| 1582 | global.ptr(&self.builder).linkage = .extern_weak; | |
| 1543 | 1583 | llvm_global.setLinkage(.ExternalWeak); |
| 1544 | 1584 | } |
| 1545 | 1585 | } |
| 1586 | global.ptr(&self.builder).updateAttributes(); | |
| 1546 | 1587 | } else if (exports.len != 0) { |
| 1547 | 1588 | const exp_name = try self.builder.string(mod.intern_pool.stringToSlice(exports[0].opts.name)); |
| 1548 | try global_index.rename(&self.builder, exp_name); | |
| 1589 | try global.rename(&self.builder, exp_name); | |
| 1590 | global.ptr(&self.builder).unnamed_addr = .default; | |
| 1549 | 1591 | llvm_global.setUnnamedAddr(.False); |
| 1550 | if (mod.wantDllExports()) llvm_global.setDLLStorageClass(.DLLExport); | |
| 1592 | if (mod.wantDllExports()) { | |
| 1593 | global.ptr(&self.builder).dll_storage_class = .dllexport; | |
| 1594 | llvm_global.setDLLStorageClass(.DLLExport); | |
| 1595 | } | |
| 1551 | 1596 | if (self.di_map.get(decl)) |di_node| { |
| 1552 | 1597 | const exp_name_slice = exp_name.toSlice(&self.builder).?; |
| 1553 | 1598 | if (try decl.isFunction(mod)) { |
| ... | ... | @@ -1562,23 +1607,45 @@ pub const Object = struct { |
| 1562 | 1607 | } |
| 1563 | 1608 | switch (exports[0].opts.linkage) { |
| 1564 | 1609 | .Internal => unreachable, |
| 1565 | .Strong => llvm_global.setLinkage(.External), | |
| 1566 | .Weak => llvm_global.setLinkage(.WeakODR), | |
| 1567 | .LinkOnce => llvm_global.setLinkage(.LinkOnceODR), | |
| 1610 | .Strong => { | |
| 1611 | global.ptr(&self.builder).linkage = .external; | |
| 1612 | llvm_global.setLinkage(.External); | |
| 1613 | }, | |
| 1614 | .Weak => { | |
| 1615 | global.ptr(&self.builder).linkage = .weak_odr; | |
| 1616 | llvm_global.setLinkage(.WeakODR); | |
| 1617 | }, | |
| 1618 | .LinkOnce => { | |
| 1619 | global.ptr(&self.builder).linkage = .linkonce_odr; | |
| 1620 | llvm_global.setLinkage(.LinkOnceODR); | |
| 1621 | }, | |
| 1568 | 1622 | } |
| 1569 | 1623 | switch (exports[0].opts.visibility) { |
| 1570 | .default => llvm_global.setVisibility(.Default), | |
| 1571 | .hidden => llvm_global.setVisibility(.Hidden), | |
| 1572 | .protected => llvm_global.setVisibility(.Protected), | |
| 1624 | .default => { | |
| 1625 | global.ptr(&self.builder).visibility = .default; | |
| 1626 | llvm_global.setVisibility(.Default); | |
| 1627 | }, | |
| 1628 | .hidden => { | |
| 1629 | global.ptr(&self.builder).visibility = .hidden; | |
| 1630 | llvm_global.setVisibility(.Hidden); | |
| 1631 | }, | |
| 1632 | .protected => { | |
| 1633 | global.ptr(&self.builder).visibility = .protected; | |
| 1634 | llvm_global.setVisibility(.Protected); | |
| 1635 | }, | |
| 1573 | 1636 | } |
| 1574 | 1637 | if (mod.intern_pool.stringToSliceUnwrap(exports[0].opts.section)) |section| { |
| 1638 | global.ptr(&self.builder).section = try self.builder.string(section); | |
| 1575 | 1639 | llvm_global.setSection(section); |
| 1576 | 1640 | } |
| 1577 | if (decl.val.getVariable(mod)) |variable| { | |
| 1578 | if (variable.is_threadlocal) { | |
| 1641 | if (decl.val.getVariable(mod)) |decl_var| { | |
| 1642 | if (decl_var.is_threadlocal) { | |
| 1643 | global.ptrConst(&self.builder).kind.variable.ptr(&self.builder).thread_local = | |
| 1644 | .generaldynamic; | |
| 1579 | 1645 | llvm_global.setThreadLocalMode(.GeneralDynamicTLSModel); |
| 1580 | 1646 | } |
| 1581 | 1647 | } |
| 1648 | global.ptr(&self.builder).updateAttributes(); | |
| 1582 | 1649 | |
| 1583 | 1650 | // If a Decl is exported more than one time (which is rare), |
| 1584 | 1651 | // we add aliases for all but the first export. |
| ... | ... | @@ -1602,18 +1669,28 @@ pub const Object = struct { |
| 1602 | 1669 | } |
| 1603 | 1670 | } else { |
| 1604 | 1671 | const fqn = try self.builder.string(mod.intern_pool.stringToSlice(try decl.getFullyQualifiedName(mod))); |
| 1605 | try global_index.rename(&self.builder, fqn); | |
| 1672 | try global.rename(&self.builder, fqn); | |
| 1673 | global.ptr(&self.builder).linkage = .internal; | |
| 1606 | 1674 | llvm_global.setLinkage(.Internal); |
| 1607 | if (mod.wantDllExports()) llvm_global.setDLLStorageClass(.Default); | |
| 1675 | if (mod.wantDllExports()) { | |
| 1676 | global.ptr(&self.builder).dll_storage_class = .default; | |
| 1677 | llvm_global.setDLLStorageClass(.Default); | |
| 1678 | } | |
| 1679 | global.ptr(&self.builder).unnamed_addr = .unnamed_addr; | |
| 1608 | 1680 | llvm_global.setUnnamedAddr(.True); |
| 1609 | if (decl.val.getVariable(mod)) |variable| { | |
| 1681 | if (decl.val.getVariable(mod)) |decl_var| { | |
| 1610 | 1682 | const single_threaded = mod.comp.bin_file.options.single_threaded; |
| 1611 | if (variable.is_threadlocal and !single_threaded) { | |
| 1683 | if (decl_var.is_threadlocal and !single_threaded) { | |
| 1684 | global.ptrConst(&self.builder).kind.variable.ptr(&self.builder).thread_local = | |
| 1685 | .generaldynamic; | |
| 1612 | 1686 | llvm_global.setThreadLocalMode(.GeneralDynamicTLSModel); |
| 1613 | 1687 | } else { |
| 1688 | global.ptrConst(&self.builder).kind.variable.ptr(&self.builder).thread_local = | |
| 1689 | .default; | |
| 1614 | 1690 | llvm_global.setThreadLocalMode(.NotThreadLocal); |
| 1615 | 1691 | } |
| 1616 | 1692 | } |
| 1693 | global.ptr(&self.builder).updateAttributes(); | |
| 1617 | 1694 | } |
| 1618 | 1695 | } |
| 1619 | 1696 | |
| ... | ... | @@ -2658,31 +2735,44 @@ pub const Object = struct { |
| 2658 | 2735 | const mod = o.module; |
| 2659 | 2736 | const target = mod.getTarget(); |
| 2660 | 2737 | const ty = try mod.intern(.{ .opt_type = .usize_type }); |
| 2661 | const null_opt_usize = try mod.intern(.{ .opt = .{ | |
| 2738 | ||
| 2739 | const llvm_init = try o.lowerValue(try mod.intern(.{ .opt = .{ | |
| 2662 | 2740 | .ty = ty, |
| 2663 | 2741 | .val = .none, |
| 2664 | } }); | |
| 2665 | ||
| 2666 | const llvm_init = try o.lowerValue(.{ | |
| 2667 | .ty = ty.toType(), | |
| 2668 | .val = null_opt_usize.toValue(), | |
| 2669 | }); | |
| 2742 | } })); | |
| 2743 | const llvm_ty = llvm_init.typeOf(&o.builder); | |
| 2670 | 2744 | const llvm_wanted_addrspace = toLlvmAddressSpace(.generic, target); |
| 2671 | 2745 | const llvm_actual_addrspace = toLlvmGlobalAddressSpace(.generic, target); |
| 2672 | const global = o.llvm_module.addGlobalInAddressSpace( | |
| 2673 | llvm_init.typeOf(), | |
| 2746 | const llvm_alignment = ty.toType().abiAlignment(mod); | |
| 2747 | const llvm_global = o.llvm_module.addGlobalInAddressSpace( | |
| 2748 | llvm_ty.toLlvm(&o.builder), | |
| 2674 | 2749 | "", |
| 2675 | 2750 | @intFromEnum(llvm_actual_addrspace), |
| 2676 | 2751 | ); |
| 2677 | global.setLinkage(.Internal); | |
| 2678 | global.setUnnamedAddr(.True); | |
| 2679 | global.setAlignment(ty.toType().abiAlignment(mod)); | |
| 2680 | global.setInitializer(llvm_init); | |
| 2752 | llvm_global.setLinkage(.Internal); | |
| 2753 | llvm_global.setUnnamedAddr(.True); | |
| 2754 | llvm_global.setAlignment(llvm_alignment); | |
| 2755 | llvm_global.setInitializer(llvm_init.toLlvm(&o.builder)); | |
| 2756 | ||
| 2757 | var global = Builder.Global{ | |
| 2758 | .linkage = .internal, | |
| 2759 | .unnamed_addr = .unnamed_addr, | |
| 2760 | .type = llvm_ty, | |
| 2761 | .alignment = Builder.Alignment.fromByteUnits(llvm_alignment), | |
| 2762 | .kind = .{ .variable = @enumFromInt(o.builder.variables.items.len) }, | |
| 2763 | }; | |
| 2764 | var variable = Builder.Variable{ | |
| 2765 | .global = @enumFromInt(o.builder.globals.count()), | |
| 2766 | .init = llvm_init, | |
| 2767 | }; | |
| 2768 | try o.builder.llvm_globals.append(o.gpa, llvm_global); | |
| 2769 | _ = try o.builder.addGlobal(.none, global); | |
| 2770 | try o.builder.variables.append(o.gpa, variable); | |
| 2681 | 2771 | |
| 2682 | 2772 | const addrspace_casted_global = if (llvm_wanted_addrspace != llvm_actual_addrspace) |
| 2683 | global.constAddrSpaceCast(o.context.pointerType(@intFromEnum(llvm_wanted_addrspace))) | |
| 2773 | llvm_global.constAddrSpaceCast((try o.builder.ptrType(llvm_wanted_addrspace)).toLlvm(&o.builder)) | |
| 2684 | 2774 | else |
| 2685 | global; | |
| 2775 | llvm_global; | |
| 2686 | 2776 | |
| 2687 | 2777 | o.null_opt_addr = addrspace_casted_global; |
| 2688 | 2778 | return addrspace_casted_global; |
| ... | ... | @@ -2691,7 +2781,7 @@ pub const Object = struct { |
| 2691 | 2781 | /// If the llvm function does not exist, create it. |
| 2692 | 2782 | /// Note that this can be called before the function's semantic analysis has |
| 2693 | 2783 | /// completed, so if any attributes rely on that, they must be done in updateFunc, not here. |
| 2694 | fn resolveLlvmFunction(o: *Object, decl_index: Module.Decl.Index) !Builder.Function.Index { | |
| 2784 | fn resolveLlvmFunction(o: *Object, decl_index: Module.Decl.Index) Allocator.Error!Builder.Function.Index { | |
| 2695 | 2785 | const mod = o.module; |
| 2696 | 2786 | const gpa = o.gpa; |
| 2697 | 2787 | const decl = mod.declPtr(decl_index); |
| ... | ... | @@ -2722,7 +2812,9 @@ pub const Object = struct { |
| 2722 | 2812 | |
| 2723 | 2813 | const is_extern = decl.isExtern(mod); |
| 2724 | 2814 | if (!is_extern) { |
| 2815 | global.linkage = .internal; | |
| 2725 | 2816 | llvm_fn.setLinkage(.Internal); |
| 2817 | global.unnamed_addr = .unnamed_addr; | |
| 2726 | 2818 | llvm_fn.setUnnamedAddr(.True); |
| 2727 | 2819 | } else { |
| 2728 | 2820 | if (target.isWasm()) { |
| ... | ... | @@ -2767,7 +2859,8 @@ pub const Object = struct { |
| 2767 | 2859 | } |
| 2768 | 2860 | |
| 2769 | 2861 | if (fn_info.alignment.toByteUnitsOptional()) |a| { |
| 2770 | llvm_fn.setAlignment(@as(c_uint, @intCast(a))); | |
| 2862 | global.alignment = Builder.Alignment.fromByteUnits(a); | |
| 2863 | llvm_fn.setAlignment(@intCast(a)); | |
| 2771 | 2864 | } |
| 2772 | 2865 | |
| 2773 | 2866 | // Function attributes that are independent of analysis results of the function body. |
| ... | ... | @@ -2864,9 +2957,9 @@ pub const Object = struct { |
| 2864 | 2957 | } |
| 2865 | 2958 | } |
| 2866 | 2959 | |
| 2867 | fn resolveGlobalDecl(o: *Object, decl_index: Module.Decl.Index) Error!Builder.Object.Index { | |
| 2960 | fn resolveGlobalDecl(o: *Object, decl_index: Module.Decl.Index) Allocator.Error!Builder.Variable.Index { | |
| 2868 | 2961 | const gop = try o.decl_map.getOrPut(o.gpa, decl_index); |
| 2869 | if (gop.found_existing) return gop.value_ptr.ptr(&o.builder).kind.object; | |
| 2962 | if (gop.found_existing) return gop.value_ptr.ptr(&o.builder).kind.variable; | |
| 2870 | 2963 | errdefer assert(o.decl_map.remove(decl_index)); |
| 2871 | 2964 | |
| 2872 | 2965 | const mod = o.module; |
| ... | ... | @@ -2880,9 +2973,9 @@ pub const Object = struct { |
| 2880 | 2973 | var global = Builder.Global{ |
| 2881 | 2974 | .addr_space = toLlvmGlobalAddressSpace(decl.@"addrspace", target), |
| 2882 | 2975 | .type = try o.lowerType(decl.ty), |
| 2883 | .kind = .{ .object = @enumFromInt(o.builder.objects.items.len) }, | |
| 2976 | .kind = .{ .variable = @enumFromInt(o.builder.variables.items.len) }, | |
| 2884 | 2977 | }; |
| 2885 | var object = Builder.Object{ | |
| 2978 | var variable = Builder.Variable{ | |
| 2886 | 2979 | .global = @enumFromInt(o.builder.globals.count()), |
| 2887 | 2980 | }; |
| 2888 | 2981 | |
| ... | ... | @@ -2903,16 +2996,16 @@ pub const Object = struct { |
| 2903 | 2996 | llvm_global.setUnnamedAddr(.False); |
| 2904 | 2997 | global.linkage = .external; |
| 2905 | 2998 | llvm_global.setLinkage(.External); |
| 2906 | if (decl.val.getVariable(mod)) |variable| { | |
| 2999 | if (decl.val.getVariable(mod)) |decl_var| { | |
| 2907 | 3000 | const single_threaded = mod.comp.bin_file.options.single_threaded; |
| 2908 | if (variable.is_threadlocal and !single_threaded) { | |
| 2909 | object.thread_local = .generaldynamic; | |
| 3001 | if (decl_var.is_threadlocal and !single_threaded) { | |
| 3002 | variable.thread_local = .generaldynamic; | |
| 2910 | 3003 | llvm_global.setThreadLocalMode(.GeneralDynamicTLSModel); |
| 2911 | 3004 | } else { |
| 2912 | object.thread_local = .default; | |
| 3005 | variable.thread_local = .default; | |
| 2913 | 3006 | llvm_global.setThreadLocalMode(.NotThreadLocal); |
| 2914 | 3007 | } |
| 2915 | if (variable.is_weak_linkage) { | |
| 3008 | if (decl_var.is_weak_linkage) { | |
| 2916 | 3009 | global.linkage = .extern_weak; |
| 2917 | 3010 | llvm_global.setLinkage(.ExternalWeak); |
| 2918 | 3011 | } |
| ... | ... | @@ -2926,17 +3019,8 @@ pub const Object = struct { |
| 2926 | 3019 | |
| 2927 | 3020 | try o.builder.llvm_globals.append(o.gpa, llvm_global); |
| 2928 | 3021 | gop.value_ptr.* = try o.builder.addGlobal(name, global); |
| 2929 | try o.builder.objects.append(o.gpa, object); | |
| 2930 | return global.kind.object; | |
| 2931 | } | |
| 2932 | ||
| 2933 | fn isUnnamedType(o: *Object, ty: Type, val: *llvm.Value) bool { | |
| 2934 | // Once `lowerType` succeeds, successive calls to it with the same Zig type | |
| 2935 | // are guaranteed to succeed. So if a call to `lowerType` fails here it means | |
| 2936 | // it is the first time lowering the type, which means the value can't possible | |
| 2937 | // have that type. | |
| 2938 | const llvm_ty = (o.lowerType(ty) catch return true).toLlvm(&o.builder); | |
| 2939 | return val.typeOf() != llvm_ty; | |
| 3022 | try o.builder.variables.append(o.gpa, variable); | |
| 3023 | return global.kind.variable; | |
| 2940 | 3024 | } |
| 2941 | 3025 | |
| 2942 | 3026 | fn lowerType(o: *Object, t: Type) Allocator.Error!Builder.Type { |
| ... | ... | @@ -3069,14 +3153,17 @@ pub const Object = struct { |
| 3069 | 3153 | => unreachable, |
| 3070 | 3154 | else => switch (mod.intern_pool.indexToKey(t.toIntern())) { |
| 3071 | 3155 | .int_type => |int_type| try o.builder.intType(int_type.bits), |
| 3072 | .ptr_type => |ptr_type| switch (ptr_type.flags.size) { | |
| 3073 | .One, .Many, .C => try o.builder.ptrType( | |
| 3156 | .ptr_type => |ptr_type| type: { | |
| 3157 | const ptr_ty = try o.builder.ptrType( | |
| 3074 | 3158 | toLlvmAddressSpace(ptr_type.flags.address_space, target), |
| 3075 | ), | |
| 3076 | .Slice => try o.builder.structType(.normal, &.{ | |
| 3077 | .ptr, | |
| 3078 | try o.lowerType(Type.usize), | |
| 3079 | }), | |
| 3159 | ); | |
| 3160 | break :type switch (ptr_type.flags.size) { | |
| 3161 | .One, .Many, .C => ptr_ty, | |
| 3162 | .Slice => try o.builder.structType(.normal, &.{ | |
| 3163 | ptr_ty, | |
| 3164 | try o.lowerType(Type.usize), | |
| 3165 | }), | |
| 3166 | }; | |
| 3080 | 3167 | }, |
| 3081 | 3168 | .array_type => |array_type| o.builder.arrayType( |
| 3082 | 3169 | array_type.len + @intFromBool(array_type.sentinel != .none), |
| ... | ... | @@ -3094,13 +3181,16 @@ pub const Object = struct { |
| 3094 | 3181 | if (t.optionalReprIsPayload(mod)) return payload_ty; |
| 3095 | 3182 | |
| 3096 | 3183 | comptime assert(optional_layout_version == 3); |
| 3097 | var fields_buf: [3]Builder.Type = .{ payload_ty, .i8, .none }; | |
| 3184 | var fields: [3]Builder.Type = .{ payload_ty, .i8, undefined }; | |
| 3185 | var fields_len: usize = 2; | |
| 3098 | 3186 | const offset = child_ty.toType().abiSize(mod) + 1; |
| 3099 | 3187 | const abi_size = t.abiSize(mod); |
| 3100 | const padding = abi_size - offset; | |
| 3101 | if (padding == 0) return o.builder.structType(.normal, fields_buf[0..2]); | |
| 3102 | fields_buf[2] = try o.builder.arrayType(padding, .i8); | |
| 3103 | return o.builder.structType(.normal, fields_buf[0..3]); | |
| 3188 | const padding_len = abi_size - offset; | |
| 3189 | if (padding_len > 0) { | |
| 3190 | fields[2] = try o.builder.arrayType(padding_len, .i8); | |
| 3191 | fields_len = 3; | |
| 3192 | } | |
| 3193 | return o.builder.structType(.normal, fields[0..fields_len]); | |
| 3104 | 3194 | }, |
| 3105 | 3195 | .anyframe_type => @panic("TODO implement lowerType for AnyFrame types"), |
| 3106 | 3196 | .error_union_type => |error_union_type| { |
| ... | ... | @@ -3115,30 +3205,30 @@ pub const Object = struct { |
| 3115 | 3205 | const payload_size = error_union_type.payload_type.toType().abiSize(mod); |
| 3116 | 3206 | const error_size = Type.err_int.abiSize(mod); |
| 3117 | 3207 | |
| 3118 | var fields_buf: [3]Builder.Type = undefined; | |
| 3119 | if (error_align > payload_align) { | |
| 3120 | fields_buf[0] = error_type; | |
| 3121 | fields_buf[1] = payload_type; | |
| 3208 | var fields: [3]Builder.Type = undefined; | |
| 3209 | var fields_len: usize = 2; | |
| 3210 | const padding_len = if (error_align > payload_align) pad: { | |
| 3211 | fields[0] = error_type; | |
| 3212 | fields[1] = payload_type; | |
| 3122 | 3213 | const payload_end = |
| 3123 | 3214 | std.mem.alignForward(u64, error_size, payload_align) + |
| 3124 | 3215 | payload_size; |
| 3125 | 3216 | const abi_size = std.mem.alignForward(u64, payload_end, error_align); |
| 3126 | const padding = abi_size - payload_end; | |
| 3127 | if (padding == 0) return o.builder.structType(.normal, fields_buf[0..2]); | |
| 3128 | fields_buf[2] = try o.builder.arrayType(padding, .i8); | |
| 3129 | return o.builder.structType(.normal, fields_buf[0..3]); | |
| 3130 | } else { | |
| 3131 | fields_buf[0] = payload_type; | |
| 3132 | fields_buf[1] = error_type; | |
| 3217 | break :pad abi_size - payload_end; | |
| 3218 | } else pad: { | |
| 3219 | fields[0] = payload_type; | |
| 3220 | fields[1] = error_type; | |
| 3133 | 3221 | const error_end = |
| 3134 | 3222 | std.mem.alignForward(u64, payload_size, error_align) + |
| 3135 | 3223 | error_size; |
| 3136 | 3224 | const abi_size = std.mem.alignForward(u64, error_end, payload_align); |
| 3137 | const padding = abi_size - error_end; | |
| 3138 | if (padding == 0) return o.builder.structType(.normal, fields_buf[0..2]); | |
| 3139 | fields_buf[2] = try o.builder.arrayType(padding, .i8); | |
| 3140 | return o.builder.structType(.normal, fields_buf[0..3]); | |
| 3225 | break :pad abi_size - error_end; | |
| 3226 | }; | |
| 3227 | if (padding_len > 0) { | |
| 3228 | fields[2] = try o.builder.arrayType(padding_len, .i8); | |
| 3229 | fields_len = 3; | |
| 3141 | 3230 | } |
| 3231 | return o.builder.structType(.normal, fields[0..fields_len]); | |
| 3142 | 3232 | }, |
| 3143 | 3233 | .simple_type => unreachable, |
| 3144 | 3234 | .struct_type => |struct_type| { |
| ... | ... | @@ -3371,6 +3461,7 @@ pub const Object = struct { |
| 3371 | 3461 | fn lowerTypeFn(o: *Object, fn_info: InternPool.Key.FuncType) Allocator.Error!Builder.Type { |
| 3372 | 3462 | const mod = o.module; |
| 3373 | 3463 | const ip = &mod.intern_pool; |
| 3464 | const target = mod.getTarget(); | |
| 3374 | 3465 | const ret_ty = try lowerFnRetTy(o, fn_info); |
| 3375 | 3466 | |
| 3376 | 3467 | var llvm_params = std.ArrayListUnmanaged(Builder.Type){}; |
| ... | ... | @@ -3404,7 +3495,11 @@ pub const Object = struct { |
| 3404 | 3495 | )); |
| 3405 | 3496 | }, |
| 3406 | 3497 | .slice => { |
| 3407 | try llvm_params.appendSlice(o.gpa, &.{ .ptr, try o.lowerType(Type.usize) }); | |
| 3498 | const param_ty = fn_info.param_types.get(ip)[it.zig_index - 1].toType(); | |
| 3499 | try llvm_params.appendSlice(o.gpa, &.{ | |
| 3500 | try o.builder.ptrType(toLlvmAddressSpace(param_ty.ptrAddressSpace(mod), target)), | |
| 3501 | try o.lowerType(Type.usize), | |
| 3502 | }); | |
| 3408 | 3503 | }, |
| 3409 | 3504 | .multiple_llvm_types => { |
| 3410 | 3505 | try llvm_params.appendSlice(o.gpa, it.types_buffer[0..it.types_len]); |
| ... | ... | @@ -3433,20 +3528,23 @@ pub const Object = struct { |
| 3433 | 3528 | ); |
| 3434 | 3529 | } |
| 3435 | 3530 | |
| 3436 | fn lowerValue(o: *Object, arg_tv: TypedValue) Error!*llvm.Value { | |
| 3531 | fn lowerValue(o: *Object, arg_val: InternPool.Index) Error!Builder.Constant { | |
| 3437 | 3532 | const mod = o.module; |
| 3438 | const gpa = o.gpa; | |
| 3439 | 3533 | const target = mod.getTarget(); |
| 3440 | var tv = arg_tv; | |
| 3441 | switch (mod.intern_pool.indexToKey(tv.val.toIntern())) { | |
| 3442 | .runtime_value => |rt| tv.val = rt.val.toValue(), | |
| 3534 | ||
| 3535 | var val = arg_val.toValue(); | |
| 3536 | const arg_val_key = mod.intern_pool.indexToKey(arg_val); | |
| 3537 | switch (arg_val_key) { | |
| 3538 | .runtime_value => |rt| val = rt.val.toValue(), | |
| 3443 | 3539 | else => {}, |
| 3444 | 3540 | } |
| 3445 | if (tv.val.isUndefDeep(mod)) { | |
| 3446 | return (try o.lowerType(tv.ty)).toLlvm(&o.builder).getUndef(); | |
| 3541 | if (val.isUndefDeep(mod)) { | |
| 3542 | return o.builder.undefConst(try o.lowerType(arg_val_key.typeOf().toType())); | |
| 3447 | 3543 | } |
| 3448 | 3544 | |
| 3449 | switch (mod.intern_pool.indexToKey(tv.val.toIntern())) { | |
| 3545 | const val_key = mod.intern_pool.indexToKey(val.toIntern()); | |
| 3546 | const ty = val_key.typeOf().toType(); | |
| 3547 | return switch (val_key) { | |
| 3450 | 3548 | .int_type, |
| 3451 | 3549 | .ptr_type, |
| 3452 | 3550 | .array_type, |
| ... | ... | @@ -3474,8 +3572,8 @@ pub const Object = struct { |
| 3474 | 3572 | .@"unreachable", |
| 3475 | 3573 | .generic_poison, |
| 3476 | 3574 | => unreachable, // non-runtime values |
| 3477 | .false => return Builder.Constant.false.toLlvm(&o.builder), | |
| 3478 | .true => return Builder.Constant.true.toLlvm(&o.builder), | |
| 3575 | .false => .false, | |
| 3576 | .true => .true, | |
| 3479 | 3577 | }, |
| 3480 | 3578 | .variable, |
| 3481 | 3579 | .enum_literal, |
| ... | ... | @@ -3486,259 +3584,266 @@ pub const Object = struct { |
| 3486 | 3584 | const fn_decl = mod.declPtr(fn_decl_index); |
| 3487 | 3585 | try mod.markDeclAlive(fn_decl); |
| 3488 | 3586 | const function_index = try o.resolveLlvmFunction(fn_decl_index); |
| 3489 | return function_index.toLlvm(&o.builder); | |
| 3587 | return function_index.ptrConst(&o.builder).global.toConst(); | |
| 3490 | 3588 | }, |
| 3491 | 3589 | .func => |func| { |
| 3492 | 3590 | const fn_decl_index = func.owner_decl; |
| 3493 | 3591 | const fn_decl = mod.declPtr(fn_decl_index); |
| 3494 | 3592 | try mod.markDeclAlive(fn_decl); |
| 3495 | 3593 | const function_index = try o.resolveLlvmFunction(fn_decl_index); |
| 3496 | return function_index.toLlvm(&o.builder); | |
| 3594 | return function_index.ptrConst(&o.builder).global.toConst(); | |
| 3497 | 3595 | }, |
| 3498 | 3596 | .int => { |
| 3499 | 3597 | var bigint_space: Value.BigIntSpace = undefined; |
| 3500 | const bigint = tv.val.toBigInt(&bigint_space, mod); | |
| 3501 | return lowerBigInt(o, tv.ty, bigint); | |
| 3598 | const bigint = val.toBigInt(&bigint_space, mod); | |
| 3599 | return lowerBigInt(o, ty, bigint); | |
| 3502 | 3600 | }, |
| 3503 | 3601 | .err => |err| { |
| 3504 | 3602 | const int = try mod.getErrorValue(err.name); |
| 3505 | 3603 | const llvm_int = try o.builder.intConst(Builder.Type.err_int, int); |
| 3506 | return llvm_int.toLlvm(&o.builder); | |
| 3604 | return llvm_int; | |
| 3507 | 3605 | }, |
| 3508 | 3606 | .error_union => |error_union| { |
| 3509 | const err_tv: TypedValue = switch (error_union.val) { | |
| 3510 | .err_name => |err_name| .{ | |
| 3511 | .ty = tv.ty.errorUnionSet(mod), | |
| 3512 | .val = (try mod.intern(.{ .err = .{ | |
| 3513 | .ty = tv.ty.errorUnionSet(mod).toIntern(), | |
| 3514 | .name = err_name, | |
| 3515 | } })).toValue(), | |
| 3516 | }, | |
| 3517 | .payload => .{ | |
| 3518 | .ty = Type.err_int, | |
| 3519 | .val = try mod.intValue(Type.err_int, 0), | |
| 3520 | }, | |
| 3607 | const err_val = switch (error_union.val) { | |
| 3608 | .err_name => |err_name| try mod.intern(.{ .err = .{ | |
| 3609 | .ty = ty.errorUnionSet(mod).toIntern(), | |
| 3610 | .name = err_name, | |
| 3611 | } }), | |
| 3612 | .payload => (try mod.intValue(Type.err_int, 0)).toIntern(), | |
| 3521 | 3613 | }; |
| 3522 | const payload_type = tv.ty.errorUnionPayload(mod); | |
| 3614 | const payload_type = ty.errorUnionPayload(mod); | |
| 3523 | 3615 | if (!payload_type.hasRuntimeBitsIgnoreComptime(mod)) { |
| 3524 | 3616 | // We use the error type directly as the type. |
| 3525 | return o.lowerValue(err_tv); | |
| 3617 | return o.lowerValue(err_val); | |
| 3526 | 3618 | } |
| 3527 | 3619 | |
| 3528 | 3620 | const payload_align = payload_type.abiAlignment(mod); |
| 3529 | const error_align = err_tv.ty.abiAlignment(mod); | |
| 3530 | const llvm_error_value = try o.lowerValue(err_tv); | |
| 3531 | const llvm_payload_value = try o.lowerValue(.{ | |
| 3532 | .ty = payload_type, | |
| 3533 | .val = switch (error_union.val) { | |
| 3534 | .err_name => try mod.intern(.{ .undef = payload_type.toIntern() }), | |
| 3535 | .payload => |payload| payload, | |
| 3536 | }.toValue(), | |
| 3621 | const error_align = Type.err_int.abiAlignment(mod); | |
| 3622 | const llvm_error_value = try o.lowerValue(err_val); | |
| 3623 | const llvm_payload_value = try o.lowerValue(switch (error_union.val) { | |
| 3624 | .err_name => try mod.intern(.{ .undef = payload_type.toIntern() }), | |
| 3625 | .payload => |payload| payload, | |
| 3537 | 3626 | }); |
| 3538 | var fields_buf: [3]*llvm.Value = undefined; | |
| 3539 | ||
| 3540 | const llvm_ty = (try o.lowerType(tv.ty)).toLlvm(&o.builder); | |
| 3541 | const llvm_field_count = llvm_ty.countStructElementTypes(); | |
| 3542 | if (llvm_field_count > 2) { | |
| 3543 | assert(llvm_field_count == 3); | |
| 3544 | fields_buf[2] = llvm_ty.structGetTypeAtIndex(2).getUndef(); | |
| 3545 | } | |
| 3546 | 3627 | |
| 3628 | var fields: [3]Builder.Type = undefined; | |
| 3629 | var vals: [3]Builder.Constant = undefined; | |
| 3547 | 3630 | if (error_align > payload_align) { |
| 3548 | fields_buf[0] = llvm_error_value; | |
| 3549 | fields_buf[1] = llvm_payload_value; | |
| 3550 | return o.context.constStruct(&fields_buf, llvm_field_count, .False); | |
| 3631 | vals[0] = llvm_error_value; | |
| 3632 | vals[1] = llvm_payload_value; | |
| 3551 | 3633 | } else { |
| 3552 | fields_buf[0] = llvm_payload_value; | |
| 3553 | fields_buf[1] = llvm_error_value; | |
| 3554 | return o.context.constStruct(&fields_buf, llvm_field_count, .False); | |
| 3634 | vals[0] = llvm_payload_value; | |
| 3635 | vals[1] = llvm_error_value; | |
| 3636 | } | |
| 3637 | fields[0] = vals[0].typeOf(&o.builder); | |
| 3638 | fields[1] = vals[1].typeOf(&o.builder); | |
| 3639 | ||
| 3640 | const llvm_ty = try o.lowerType(ty); | |
| 3641 | const llvm_ty_fields = llvm_ty.structFields(&o.builder); | |
| 3642 | if (llvm_ty_fields.len > 2) { | |
| 3643 | assert(llvm_ty_fields.len == 3); | |
| 3644 | fields[2] = llvm_ty_fields[2]; | |
| 3645 | vals[2] = try o.builder.undefConst(fields[2]); | |
| 3555 | 3646 | } |
| 3647 | return o.builder.structConst(try o.builder.structType( | |
| 3648 | llvm_ty.structKind(&o.builder), | |
| 3649 | fields[0..llvm_ty_fields.len], | |
| 3650 | ), vals[0..llvm_ty_fields.len]); | |
| 3556 | 3651 | }, |
| 3557 | .enum_tag => |enum_tag| return o.lowerValue(.{ | |
| 3558 | .ty = mod.intern_pool.typeOf(enum_tag.int).toType(), | |
| 3559 | .val = enum_tag.int.toValue(), | |
| 3560 | }), | |
| 3561 | .float => return switch (tv.ty.floatBits(target)) { | |
| 3562 | 16 => int: { | |
| 3563 | const repr: i16 = @bitCast(tv.val.toFloat(f16, mod)); | |
| 3564 | break :int try o.builder.intConst(.i16, repr); | |
| 3565 | }, | |
| 3566 | 32 => int: { | |
| 3567 | const repr: i32 = @bitCast(tv.val.toFloat(f32, mod)); | |
| 3568 | break :int try o.builder.intConst(.i32, repr); | |
| 3569 | }, | |
| 3570 | 64 => int: { | |
| 3571 | const repr: i64 = @bitCast(tv.val.toFloat(f64, mod)); | |
| 3572 | break :int try o.builder.intConst(.i64, repr); | |
| 3573 | }, | |
| 3574 | 80 => int: { | |
| 3575 | const repr: i80 = @bitCast(tv.val.toFloat(f80, mod)); | |
| 3576 | break :int try o.builder.intConst(.i80, repr); | |
| 3577 | }, | |
| 3578 | 128 => int: { | |
| 3579 | const repr: i128 = @bitCast(tv.val.toFloat(f128, mod)); | |
| 3580 | break :int try o.builder.intConst(.i128, repr); | |
| 3581 | }, | |
| 3652 | .enum_tag => |enum_tag| o.lowerValue(enum_tag.int), | |
| 3653 | .float => switch (ty.floatBits(target)) { | |
| 3654 | 16 => if (backendSupportsF16(target)) | |
| 3655 | try o.builder.halfConst(val.toFloat(f16, mod)) | |
| 3656 | else | |
| 3657 | try o.builder.intConst(.i16, @as(i16, @bitCast(val.toFloat(f16, mod)))), | |
| 3658 | 32 => try o.builder.floatConst(val.toFloat(f32, mod)), | |
| 3659 | 64 => try o.builder.doubleConst(val.toFloat(f64, mod)), | |
| 3660 | 80 => if (backendSupportsF80(target)) | |
| 3661 | try o.builder.x86_fp80Const(val.toFloat(f80, mod)) | |
| 3662 | else | |
| 3663 | try o.builder.intConst(.i80, @as(i80, @bitCast(val.toFloat(f80, mod)))), | |
| 3664 | 128 => try o.builder.fp128Const(val.toFloat(f128, mod)), | |
| 3582 | 3665 | else => unreachable, |
| 3583 | }.toLlvm(&o.builder).constBitCast((try o.lowerType(tv.ty)).toLlvm(&o.builder)), | |
| 3666 | }, | |
| 3584 | 3667 | .ptr => |ptr| { |
| 3585 | const ptr_tv: TypedValue = switch (ptr.len) { | |
| 3586 | .none => tv, | |
| 3587 | else => .{ .ty = tv.ty.slicePtrFieldType(mod), .val = tv.val.slicePtr(mod) }, | |
| 3668 | const ptr_ty = switch (ptr.len) { | |
| 3669 | .none => ty, | |
| 3670 | else => ty.slicePtrFieldType(mod), | |
| 3588 | 3671 | }; |
| 3589 | const llvm_ptr_val = switch (ptr.addr) { | |
| 3590 | .decl => |decl| try o.lowerDeclRefValue(ptr_tv, decl), | |
| 3591 | .mut_decl => |mut_decl| try o.lowerDeclRefValue(ptr_tv, mut_decl.decl), | |
| 3592 | .int => |int| try o.lowerIntAsPtr(int.toValue()), | |
| 3672 | const ptr_val = switch (ptr.addr) { | |
| 3673 | .decl => |decl| try o.lowerDeclRefValue(ptr_ty, decl), | |
| 3674 | .mut_decl => |mut_decl| try o.lowerDeclRefValue(ptr_ty, mut_decl.decl), | |
| 3675 | .int => |int| try o.lowerIntAsPtr(int), | |
| 3593 | 3676 | .eu_payload, |
| 3594 | 3677 | .opt_payload, |
| 3595 | 3678 | .elem, |
| 3596 | 3679 | .field, |
| 3597 | => try o.lowerParentPtr(ptr_tv.val, ptr_tv.ty.ptrInfo(mod).packed_offset.bit_offset % 8 == 0), | |
| 3680 | => try o.lowerParentPtr(val, ty.ptrInfo(mod).packed_offset.bit_offset % 8 == 0), | |
| 3598 | 3681 | .comptime_field => unreachable, |
| 3599 | 3682 | }; |
| 3600 | 3683 | switch (ptr.len) { |
| 3601 | .none => return llvm_ptr_val, | |
| 3602 | else => { | |
| 3603 | const fields: [2]*llvm.Value = .{ | |
| 3604 | llvm_ptr_val, | |
| 3605 | try o.lowerValue(.{ .ty = Type.usize, .val = ptr.len.toValue() }), | |
| 3606 | }; | |
| 3607 | return o.context.constStruct(&fields, fields.len, .False); | |
| 3608 | }, | |
| 3684 | .none => return ptr_val, | |
| 3685 | else => return o.builder.structConst(try o.lowerType(ty), &.{ | |
| 3686 | ptr_val, try o.lowerValue(ptr.len), | |
| 3687 | }), | |
| 3609 | 3688 | } |
| 3610 | 3689 | }, |
| 3611 | 3690 | .opt => |opt| { |
| 3612 | 3691 | comptime assert(optional_layout_version == 3); |
| 3613 | const payload_ty = tv.ty.optionalChild(mod); | |
| 3692 | const payload_ty = ty.optionalChild(mod); | |
| 3614 | 3693 | |
| 3615 | const non_null_bit = (try o.builder.intConst(.i8, @intFromBool(opt.val != .none))).toLlvm(&o.builder); | |
| 3694 | const non_null_bit = try o.builder.intConst(.i8, @intFromBool(opt.val != .none)); | |
| 3616 | 3695 | if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) { |
| 3617 | 3696 | return non_null_bit; |
| 3618 | 3697 | } |
| 3619 | const llvm_ty = (try o.lowerType(tv.ty)).toLlvm(&o.builder); | |
| 3620 | if (tv.ty.optionalReprIsPayload(mod)) return switch (opt.val) { | |
| 3621 | .none => llvm_ty.constNull(), | |
| 3622 | else => |payload| o.lowerValue(.{ .ty = payload_ty, .val = payload.toValue() }), | |
| 3698 | const llvm_ty = try o.lowerType(ty); | |
| 3699 | if (ty.optionalReprIsPayload(mod)) return switch (opt.val) { | |
| 3700 | .none => switch (llvm_ty.tag(&o.builder)) { | |
| 3701 | .integer => try o.builder.intConst(llvm_ty, 0), | |
| 3702 | .pointer => try o.builder.nullConst(llvm_ty), | |
| 3703 | .structure => try o.builder.zeroInitConst(llvm_ty), | |
| 3704 | else => unreachable, | |
| 3705 | }, | |
| 3706 | else => |payload| try o.lowerValue(payload), | |
| 3623 | 3707 | }; |
| 3624 | 3708 | assert(payload_ty.zigTypeTag(mod) != .Fn); |
| 3625 | 3709 | |
| 3626 | const llvm_field_count = llvm_ty.countStructElementTypes(); | |
| 3627 | var fields_buf: [3]*llvm.Value = undefined; | |
| 3628 | fields_buf[0] = try o.lowerValue(.{ | |
| 3629 | .ty = payload_ty, | |
| 3630 | .val = switch (opt.val) { | |
| 3631 | .none => try mod.intern(.{ .undef = payload_ty.toIntern() }), | |
| 3632 | else => |payload| payload, | |
| 3633 | }.toValue(), | |
| 3710 | var fields: [3]Builder.Type = undefined; | |
| 3711 | var vals: [3]Builder.Constant = undefined; | |
| 3712 | vals[0] = try o.lowerValue(switch (opt.val) { | |
| 3713 | .none => try mod.intern(.{ .undef = payload_ty.toIntern() }), | |
| 3714 | else => |payload| payload, | |
| 3634 | 3715 | }); |
| 3635 | fields_buf[1] = non_null_bit; | |
| 3636 | if (llvm_field_count > 2) { | |
| 3637 | assert(llvm_field_count == 3); | |
| 3638 | fields_buf[2] = llvm_ty.structGetTypeAtIndex(2).getUndef(); | |
| 3716 | vals[1] = non_null_bit; | |
| 3717 | fields[0] = vals[0].typeOf(&o.builder); | |
| 3718 | fields[1] = vals[1].typeOf(&o.builder); | |
| 3719 | ||
| 3720 | const llvm_ty_fields = llvm_ty.structFields(&o.builder); | |
| 3721 | if (llvm_ty_fields.len > 2) { | |
| 3722 | assert(llvm_ty_fields.len == 3); | |
| 3723 | fields[2] = llvm_ty_fields[2]; | |
| 3724 | vals[2] = try o.builder.undefConst(fields[2]); | |
| 3639 | 3725 | } |
| 3640 | return o.context.constStruct(&fields_buf, llvm_field_count, .False); | |
| 3726 | return o.builder.structConst(try o.builder.structType( | |
| 3727 | llvm_ty.structKind(&o.builder), | |
| 3728 | fields[0..llvm_ty_fields.len], | |
| 3729 | ), vals[0..llvm_ty_fields.len]); | |
| 3641 | 3730 | }, |
| 3642 | .aggregate => |aggregate| switch (mod.intern_pool.indexToKey(tv.ty.toIntern())) { | |
| 3643 | .array_type => switch (aggregate.storage) { | |
| 3644 | .bytes => |bytes| return o.context.constString( | |
| 3645 | bytes.ptr, | |
| 3646 | @as(c_uint, @intCast(tv.ty.arrayLenIncludingSentinel(mod))), | |
| 3647 | .True, // Don't null terminate. Bytes has the sentinel, if any. | |
| 3648 | ), | |
| 3649 | .elems => |elem_vals| { | |
| 3650 | const elem_ty = tv.ty.childType(mod); | |
| 3651 | const llvm_elems = try gpa.alloc(*llvm.Value, elem_vals.len); | |
| 3652 | defer gpa.free(llvm_elems); | |
| 3731 | .aggregate => |aggregate| switch (mod.intern_pool.indexToKey(ty.toIntern())) { | |
| 3732 | .array_type => |array_type| switch (aggregate.storage) { | |
| 3733 | .bytes => |bytes| try o.builder.stringConst(try o.builder.string(bytes)), | |
| 3734 | .elems => |elems| { | |
| 3735 | const array_ty = try o.lowerType(ty); | |
| 3736 | const elem_ty = array_ty.childType(&o.builder); | |
| 3737 | assert(elems.len == array_ty.aggregateLen(&o.builder)); | |
| 3738 | ||
| 3739 | const ExpectedContents = extern struct { | |
| 3740 | vals: [Builder.expected_fields_len]Builder.Constant, | |
| 3741 | fields: [Builder.expected_fields_len]Builder.Type, | |
| 3742 | }; | |
| 3743 | var stack align(@max( | |
| 3744 | @alignOf(std.heap.StackFallbackAllocator(0)), | |
| 3745 | @alignOf(ExpectedContents), | |
| 3746 | )) = std.heap.stackFallback(@sizeOf(ExpectedContents), o.gpa); | |
| 3747 | const allocator = stack.get(); | |
| 3748 | const vals = try allocator.alloc(Builder.Constant, elems.len); | |
| 3749 | defer allocator.free(vals); | |
| 3750 | const fields = try allocator.alloc(Builder.Type, elems.len); | |
| 3751 | defer allocator.free(fields); | |
| 3752 | ||
| 3653 | 3753 | var need_unnamed = false; |
| 3654 | for (elem_vals, 0..) |elem_val, i| { | |
| 3655 | llvm_elems[i] = try o.lowerValue(.{ .ty = elem_ty, .val = elem_val.toValue() }); | |
| 3656 | need_unnamed = need_unnamed or o.isUnnamedType(elem_ty, llvm_elems[i]); | |
| 3657 | } | |
| 3658 | if (need_unnamed) { | |
| 3659 | return o.context.constStruct( | |
| 3660 | llvm_elems.ptr, | |
| 3661 | @as(c_uint, @intCast(llvm_elems.len)), | |
| 3662 | .True, | |
| 3663 | ); | |
| 3664 | } else { | |
| 3665 | const llvm_elem_ty = (try o.lowerType(elem_ty)).toLlvm(&o.builder); | |
| 3666 | return llvm_elem_ty.constArray( | |
| 3667 | llvm_elems.ptr, | |
| 3668 | @as(c_uint, @intCast(llvm_elems.len)), | |
| 3669 | ); | |
| 3754 | for (vals, fields, elems) |*result_val, *result_field, elem| { | |
| 3755 | result_val.* = try o.lowerValue(elem); | |
| 3756 | result_field.* = result_val.typeOf(&o.builder); | |
| 3757 | if (result_field.* != elem_ty) need_unnamed = true; | |
| 3670 | 3758 | } |
| 3759 | return if (need_unnamed) try o.builder.structConst( | |
| 3760 | try o.builder.structType(.normal, fields), | |
| 3761 | vals, | |
| 3762 | ) else try o.builder.arrayConst(array_ty, vals); | |
| 3671 | 3763 | }, |
| 3672 | .repeated_elem => |val| { | |
| 3673 | const elem_ty = tv.ty.childType(mod); | |
| 3674 | const sentinel = tv.ty.sentinel(mod); | |
| 3675 | const len = @as(usize, @intCast(tv.ty.arrayLen(mod))); | |
| 3676 | const len_including_sent = len + @intFromBool(sentinel != null); | |
| 3677 | const llvm_elems = try gpa.alloc(*llvm.Value, len_including_sent); | |
| 3678 | defer gpa.free(llvm_elems); | |
| 3764 | .repeated_elem => |elem| { | |
| 3765 | const len: usize = @intCast(array_type.len); | |
| 3766 | const len_including_sentinel: usize = | |
| 3767 | @intCast(len + @intFromBool(array_type.sentinel != .none)); | |
| 3768 | const array_ty = try o.lowerType(ty); | |
| 3769 | const elem_ty = array_ty.childType(&o.builder); | |
| 3770 | ||
| 3771 | const ExpectedContents = extern struct { | |
| 3772 | vals: [Builder.expected_fields_len]Builder.Constant, | |
| 3773 | fields: [Builder.expected_fields_len]Builder.Type, | |
| 3774 | }; | |
| 3775 | var stack align(@max( | |
| 3776 | @alignOf(std.heap.StackFallbackAllocator(0)), | |
| 3777 | @alignOf(ExpectedContents), | |
| 3778 | )) = std.heap.stackFallback(@sizeOf(ExpectedContents), o.gpa); | |
| 3779 | const allocator = stack.get(); | |
| 3780 | const vals = try allocator.alloc(Builder.Constant, len_including_sentinel); | |
| 3781 | defer allocator.free(vals); | |
| 3782 | const fields = try allocator.alloc(Builder.Type, len_including_sentinel); | |
| 3783 | defer allocator.free(fields); | |
| 3679 | 3784 | |
| 3680 | 3785 | var need_unnamed = false; |
| 3681 | if (len != 0) { | |
| 3682 | for (llvm_elems[0..len]) |*elem| { | |
| 3683 | elem.* = try o.lowerValue(.{ .ty = elem_ty, .val = val.toValue() }); | |
| 3684 | } | |
| 3685 | need_unnamed = need_unnamed or o.isUnnamedType(elem_ty, llvm_elems[0]); | |
| 3686 | } | |
| 3687 | ||
| 3688 | if (sentinel) |sent| { | |
| 3689 | llvm_elems[len] = try o.lowerValue(.{ .ty = elem_ty, .val = sent }); | |
| 3690 | need_unnamed = need_unnamed or o.isUnnamedType(elem_ty, llvm_elems[len]); | |
| 3786 | @memset(vals[0..len], try o.lowerValue(elem)); | |
| 3787 | @memset(fields[0..len], vals[0].typeOf(&o.builder)); | |
| 3788 | if (fields[0] != elem_ty) need_unnamed = true; | |
| 3789 | ||
| 3790 | if (array_type.sentinel != .none) { | |
| 3791 | vals[len] = try o.lowerValue(array_type.sentinel); | |
| 3792 | fields[len] = vals[len].typeOf(&o.builder); | |
| 3793 | if (fields[len] != elem_ty) need_unnamed = true; | |
| 3691 | 3794 | } |
| 3692 | 3795 | |
| 3693 | if (need_unnamed) { | |
| 3694 | return o.context.constStruct( | |
| 3695 | llvm_elems.ptr, | |
| 3696 | @as(c_uint, @intCast(llvm_elems.len)), | |
| 3697 | .True, | |
| 3698 | ); | |
| 3699 | } else { | |
| 3700 | const llvm_elem_ty = (try o.lowerType(elem_ty)).toLlvm(&o.builder); | |
| 3701 | return llvm_elem_ty.constArray( | |
| 3702 | llvm_elems.ptr, | |
| 3703 | @as(c_uint, @intCast(llvm_elems.len)), | |
| 3704 | ); | |
| 3705 | } | |
| 3796 | return if (need_unnamed) try o.builder.structConst( | |
| 3797 | try o.builder.structType(.@"packed", fields), | |
| 3798 | vals, | |
| 3799 | ) else try o.builder.arrayConst(array_ty, vals); | |
| 3706 | 3800 | }, |
| 3707 | 3801 | }, |
| 3708 | 3802 | .vector_type => |vector_type| { |
| 3709 | const elem_ty = vector_type.child.toType(); | |
| 3710 | const llvm_elems = try gpa.alloc(*llvm.Value, vector_type.len); | |
| 3711 | defer gpa.free(llvm_elems); | |
| 3712 | for (llvm_elems, 0..) |*llvm_elem, i| { | |
| 3713 | llvm_elem.* = switch (aggregate.storage) { | |
| 3714 | .bytes => |bytes| (try o.builder.intConst(.i8, bytes[i])).toLlvm(&o.builder), | |
| 3715 | .elems => |elems| try o.lowerValue(.{ | |
| 3716 | .ty = elem_ty, | |
| 3717 | .val = elems[i].toValue(), | |
| 3718 | }), | |
| 3719 | .repeated_elem => |elem| try o.lowerValue(.{ | |
| 3720 | .ty = elem_ty, | |
| 3721 | .val = elem.toValue(), | |
| 3722 | }), | |
| 3723 | }; | |
| 3803 | const ExpectedContents = [Builder.expected_fields_len]Builder.Constant; | |
| 3804 | var stack align(@max( | |
| 3805 | @alignOf(std.heap.StackFallbackAllocator(0)), | |
| 3806 | @alignOf(ExpectedContents), | |
| 3807 | )) = std.heap.stackFallback(@sizeOf(ExpectedContents), o.gpa); | |
| 3808 | const allocator = stack.get(); | |
| 3809 | const vals = try allocator.alloc(Builder.Constant, vector_type.len); | |
| 3810 | defer allocator.free(vals); | |
| 3811 | ||
| 3812 | switch (aggregate.storage) { | |
| 3813 | .bytes => |bytes| for (vals, bytes) |*result_val, byte| { | |
| 3814 | result_val.* = try o.builder.intConst(.i8, byte); | |
| 3815 | }, | |
| 3816 | .elems => |elems| for (vals, elems) |*result_val, elem| { | |
| 3817 | result_val.* = try o.lowerValue(elem); | |
| 3818 | }, | |
| 3819 | .repeated_elem => |elem| @memset(vals, try o.lowerValue(elem)), | |
| 3724 | 3820 | } |
| 3725 | return llvm.constVector( | |
| 3726 | llvm_elems.ptr, | |
| 3727 | @as(c_uint, @intCast(llvm_elems.len)), | |
| 3728 | ); | |
| 3821 | return o.builder.vectorConst(try o.lowerType(ty), vals); | |
| 3729 | 3822 | }, |
| 3730 | 3823 | .anon_struct_type => |tuple| { |
| 3731 | var llvm_fields: std.ArrayListUnmanaged(*llvm.Value) = .{}; | |
| 3732 | defer llvm_fields.deinit(gpa); | |
| 3824 | const struct_ty = try o.lowerType(ty); | |
| 3825 | const llvm_len = struct_ty.aggregateLen(&o.builder); | |
| 3733 | 3826 | |
| 3734 | try llvm_fields.ensureUnusedCapacity(gpa, tuple.types.len); | |
| 3827 | const ExpectedContents = extern struct { | |
| 3828 | vals: [Builder.expected_fields_len]Builder.Constant, | |
| 3829 | fields: [Builder.expected_fields_len]Builder.Type, | |
| 3830 | }; | |
| 3831 | var stack align(@max( | |
| 3832 | @alignOf(std.heap.StackFallbackAllocator(0)), | |
| 3833 | @alignOf(ExpectedContents), | |
| 3834 | )) = std.heap.stackFallback(@sizeOf(ExpectedContents), o.gpa); | |
| 3835 | const allocator = stack.get(); | |
| 3836 | const vals = try allocator.alloc(Builder.Constant, llvm_len); | |
| 3837 | defer allocator.free(vals); | |
| 3838 | const fields = try allocator.alloc(Builder.Type, llvm_len); | |
| 3839 | defer allocator.free(fields); | |
| 3735 | 3840 | |
| 3736 | 3841 | comptime assert(struct_layout_version == 2); |
| 3842 | var llvm_index: usize = 0; | |
| 3737 | 3843 | var offset: u64 = 0; |
| 3738 | 3844 | var big_align: u32 = 0; |
| 3739 | 3845 | var need_unnamed = false; |
| 3740 | ||
| 3741 | for (tuple.types, tuple.values, 0..) |field_ty, field_val, i| { | |
| 3846 | for (tuple.types, tuple.values, 0..) |field_ty, field_val, field_index| { | |
| 3742 | 3847 | if (field_val != .none) continue; |
| 3743 | 3848 | if (!field_ty.toType().hasRuntimeBitsIgnoreComptime(mod)) continue; |
| 3744 | 3849 | |
| ... | ... | @@ -3749,20 +3854,20 @@ pub const Object = struct { |
| 3749 | 3854 | |
| 3750 | 3855 | const padding_len = offset - prev_offset; |
| 3751 | 3856 | if (padding_len > 0) { |
| 3752 | const llvm_array_ty = try o.builder.arrayType(padding_len, .i8); | |
| 3753 | 3857 | // TODO make this and all other padding elsewhere in debug |
| 3754 | 3858 | // builds be 0xaa not undef. |
| 3755 | llvm_fields.appendAssumeCapacity(llvm_array_ty.toLlvm(&o.builder).getUndef()); | |
| 3859 | fields[llvm_index] = try o.builder.arrayType(padding_len, .i8); | |
| 3860 | vals[llvm_index] = try o.builder.undefConst(fields[llvm_index]); | |
| 3861 | assert(fields[llvm_index] == struct_ty.structFields(&o.builder)[llvm_index]); | |
| 3862 | llvm_index += 1; | |
| 3756 | 3863 | } |
| 3757 | 3864 | |
| 3758 | const field_llvm_val = try o.lowerValue(.{ | |
| 3759 | .ty = field_ty.toType(), | |
| 3760 | .val = try tv.val.fieldValue(mod, i), | |
| 3761 | }); | |
| 3762 | ||
| 3763 | need_unnamed = need_unnamed or o.isUnnamedType(field_ty.toType(), field_llvm_val); | |
| 3764 | ||
| 3765 | llvm_fields.appendAssumeCapacity(field_llvm_val); | |
| 3865 | vals[llvm_index] = | |
| 3866 | try o.lowerValue((try val.fieldValue(mod, field_index)).toIntern()); | |
| 3867 | fields[llvm_index] = vals[llvm_index].typeOf(&o.builder); | |
| 3868 | if (fields[llvm_index] != struct_ty.structFields(&o.builder)[llvm_index]) | |
| 3869 | need_unnamed = true; | |
| 3870 | llvm_index += 1; | |
| 3766 | 3871 | |
| 3767 | 3872 | offset += field_ty.toType().abiSize(mod); |
| 3768 | 3873 | } |
| ... | ... | @@ -3771,73 +3876,71 @@ pub const Object = struct { |
| 3771 | 3876 | offset = std.mem.alignForward(u64, offset, big_align); |
| 3772 | 3877 | const padding_len = offset - prev_offset; |
| 3773 | 3878 | if (padding_len > 0) { |
| 3774 | const llvm_array_ty = try o.builder.arrayType(padding_len, .i8); | |
| 3775 | llvm_fields.appendAssumeCapacity(llvm_array_ty.toLlvm(&o.builder).getUndef()); | |
| 3879 | fields[llvm_index] = try o.builder.arrayType(padding_len, .i8); | |
| 3880 | vals[llvm_index] = try o.builder.undefConst(fields[llvm_index]); | |
| 3881 | assert(fields[llvm_index] == struct_ty.structFields(&o.builder)[llvm_index]); | |
| 3882 | llvm_index += 1; | |
| 3776 | 3883 | } |
| 3777 | 3884 | } |
| 3885 | assert(llvm_index == llvm_len); | |
| 3778 | 3886 | |
| 3779 | if (need_unnamed) { | |
| 3780 | return o.context.constStruct( | |
| 3781 | llvm_fields.items.ptr, | |
| 3782 | @as(c_uint, @intCast(llvm_fields.items.len)), | |
| 3783 | .False, | |
| 3784 | ); | |
| 3785 | } else { | |
| 3786 | const llvm_struct_ty = (try o.lowerType(tv.ty)).toLlvm(&o.builder); | |
| 3787 | return llvm_struct_ty.constNamedStruct( | |
| 3788 | llvm_fields.items.ptr, | |
| 3789 | @as(c_uint, @intCast(llvm_fields.items.len)), | |
| 3790 | ); | |
| 3791 | } | |
| 3887 | return try o.builder.structConst(if (need_unnamed) | |
| 3888 | try o.builder.structType(struct_ty.structKind(&o.builder), fields) | |
| 3889 | else | |
| 3890 | struct_ty, vals); | |
| 3792 | 3891 | }, |
| 3793 | 3892 | .struct_type => |struct_type| { |
| 3794 | 3893 | const struct_obj = mod.structPtrUnwrap(struct_type.index).?; |
| 3795 | const llvm_struct_ty = (try o.lowerType(tv.ty)).toLlvm(&o.builder); | |
| 3796 | ||
| 3894 | assert(struct_obj.haveLayout()); | |
| 3895 | const struct_ty = try o.lowerType(ty); | |
| 3797 | 3896 | if (struct_obj.layout == .Packed) { |
| 3798 | assert(struct_obj.haveLayout()); | |
| 3799 | const big_bits = struct_obj.backing_int_ty.bitSize(mod); | |
| 3800 | const int_llvm_ty = try o.builder.intType(@intCast(big_bits)); | |
| 3801 | const fields = struct_obj.fields.values(); | |
| 3802 | 3897 | comptime assert(Type.packed_struct_layout_version == 2); |
| 3803 | var running_int = (try o.builder.intConst(int_llvm_ty, 0)).toLlvm(&o.builder); | |
| 3898 | var running_int = try o.builder.intConst(struct_ty, 0); | |
| 3804 | 3899 | var running_bits: u16 = 0; |
| 3805 | for (fields, 0..) |field, i| { | |
| 3900 | for (struct_obj.fields.values(), 0..) |field, field_index| { | |
| 3806 | 3901 | if (!field.ty.hasRuntimeBitsIgnoreComptime(mod)) continue; |
| 3807 | 3902 | |
| 3808 | const non_int_val = try o.lowerValue(.{ | |
| 3809 | .ty = field.ty, | |
| 3810 | .val = try tv.val.fieldValue(mod, i), | |
| 3811 | }); | |
| 3812 | const ty_bit_size = @as(u16, @intCast(field.ty.bitSize(mod))); | |
| 3813 | const small_int_ty = (try o.builder.intType(@intCast(ty_bit_size))).toLlvm(&o.builder); | |
| 3814 | const small_int_val = if (field.ty.isPtrAtRuntime(mod)) | |
| 3815 | non_int_val.constPtrToInt(small_int_ty) | |
| 3816 | else | |
| 3817 | non_int_val.constBitCast(small_int_ty); | |
| 3818 | const shift_rhs = (try o.builder.intConst(int_llvm_ty, running_bits)).toLlvm(&o.builder); | |
| 3819 | // If the field is as large as the entire packed struct, this | |
| 3820 | // zext would go from, e.g. i16 to i16. This is legal with | |
| 3821 | // constZExtOrBitCast but not legal with constZExt. | |
| 3822 | const extended_int_val = small_int_val.constZExtOrBitCast(int_llvm_ty.toLlvm(&o.builder)); | |
| 3823 | const shifted = extended_int_val.constShl(shift_rhs); | |
| 3824 | running_int = running_int.constOr(shifted); | |
| 3903 | const non_int_val = | |
| 3904 | try o.lowerValue((try val.fieldValue(mod, field_index)).toIntern()); | |
| 3905 | const ty_bit_size: u16 = @intCast(field.ty.bitSize(mod)); | |
| 3906 | const small_int_ty = try o.builder.intType(ty_bit_size); | |
| 3907 | const small_int_val = try o.builder.castConst( | |
| 3908 | if (field.ty.isPtrAtRuntime(mod)) .ptrtoint else .bitcast, | |
| 3909 | non_int_val, | |
| 3910 | small_int_ty, | |
| 3911 | ); | |
| 3912 | const shift_rhs = try o.builder.intConst(struct_ty, running_bits); | |
| 3913 | const extended_int_val = | |
| 3914 | try o.builder.convConst(.unsigned, small_int_val, struct_ty); | |
| 3915 | const shifted = try o.builder.binConst(.shl, extended_int_val, shift_rhs); | |
| 3916 | running_int = try o.builder.binConst(.@"or", running_int, shifted); | |
| 3825 | 3917 | running_bits += ty_bit_size; |
| 3826 | 3918 | } |
| 3827 | 3919 | return running_int; |
| 3828 | 3920 | } |
| 3921 | const llvm_len = struct_ty.aggregateLen(&o.builder); | |
| 3829 | 3922 | |
| 3830 | const llvm_field_count = llvm_struct_ty.countStructElementTypes(); | |
| 3831 | var llvm_fields = try std.ArrayListUnmanaged(*llvm.Value).initCapacity(gpa, llvm_field_count); | |
| 3832 | defer llvm_fields.deinit(gpa); | |
| 3923 | const ExpectedContents = extern struct { | |
| 3924 | vals: [Builder.expected_fields_len]Builder.Constant, | |
| 3925 | fields: [Builder.expected_fields_len]Builder.Type, | |
| 3926 | }; | |
| 3927 | var stack align(@max( | |
| 3928 | @alignOf(std.heap.StackFallbackAllocator(0)), | |
| 3929 | @alignOf(ExpectedContents), | |
| 3930 | )) = std.heap.stackFallback(@sizeOf(ExpectedContents), o.gpa); | |
| 3931 | const allocator = stack.get(); | |
| 3932 | const vals = try allocator.alloc(Builder.Constant, llvm_len); | |
| 3933 | defer allocator.free(vals); | |
| 3934 | const fields = try allocator.alloc(Builder.Type, llvm_len); | |
| 3935 | defer allocator.free(fields); | |
| 3833 | 3936 | |
| 3834 | 3937 | comptime assert(struct_layout_version == 2); |
| 3938 | var llvm_index: usize = 0; | |
| 3835 | 3939 | var offset: u64 = 0; |
| 3836 | 3940 | var big_align: u32 = 0; |
| 3837 | 3941 | var need_unnamed = false; |
| 3838 | ||
| 3839 | var it = struct_obj.runtimeFieldIterator(mod); | |
| 3840 | while (it.next()) |field_and_index| { | |
| 3942 | var field_it = struct_obj.runtimeFieldIterator(mod); | |
| 3943 | while (field_it.next()) |field_and_index| { | |
| 3841 | 3944 | const field = field_and_index.field; |
| 3842 | 3945 | const field_align = field.alignment(mod, struct_obj.layout); |
| 3843 | 3946 | big_align = @max(big_align, field_align); |
| ... | ... | @@ -3846,20 +3949,22 @@ pub const Object = struct { |
| 3846 | 3949 | |
| 3847 | 3950 | const padding_len = offset - prev_offset; |
| 3848 | 3951 | if (padding_len > 0) { |
| 3849 | const llvm_array_ty = try o.builder.arrayType(padding_len, .i8); | |
| 3850 | 3952 | // TODO make this and all other padding elsewhere in debug |
| 3851 | 3953 | // builds be 0xaa not undef. |
| 3852 | llvm_fields.appendAssumeCapacity(llvm_array_ty.toLlvm(&o.builder).getUndef()); | |
| 3954 | fields[llvm_index] = try o.builder.arrayType(padding_len, .i8); | |
| 3955 | vals[llvm_index] = try o.builder.undefConst(fields[llvm_index]); | |
| 3956 | assert(fields[llvm_index] == | |
| 3957 | struct_ty.structFields(&o.builder)[llvm_index]); | |
| 3958 | llvm_index += 1; | |
| 3853 | 3959 | } |
| 3854 | 3960 | |
| 3855 | const field_llvm_val = try o.lowerValue(.{ | |
| 3856 | .ty = field.ty, | |
| 3857 | .val = try tv.val.fieldValue(mod, field_and_index.index), | |
| 3858 | }); | |
| 3859 | ||
| 3860 | need_unnamed = need_unnamed or o.isUnnamedType(field.ty, field_llvm_val); | |
| 3861 | ||
| 3862 | llvm_fields.appendAssumeCapacity(field_llvm_val); | |
| 3961 | vals[llvm_index] = try o.lowerValue( | |
| 3962 | (try val.fieldValue(mod, field_and_index.index)).toIntern(), | |
| 3963 | ); | |
| 3964 | fields[llvm_index] = vals[llvm_index].typeOf(&o.builder); | |
| 3965 | if (fields[llvm_index] != struct_ty.structFields(&o.builder)[llvm_index]) | |
| 3966 | need_unnamed = true; | |
| 3967 | llvm_index += 1; | |
| 3863 | 3968 | |
| 3864 | 3969 | offset += field.ty.abiSize(mod); |
| 3865 | 3970 | } |
| ... | ... | @@ -3868,135 +3973,118 @@ pub const Object = struct { |
| 3868 | 3973 | offset = std.mem.alignForward(u64, offset, big_align); |
| 3869 | 3974 | const padding_len = offset - prev_offset; |
| 3870 | 3975 | if (padding_len > 0) { |
| 3871 | const llvm_array_ty = try o.builder.arrayType(padding_len, .i8); | |
| 3872 | llvm_fields.appendAssumeCapacity(llvm_array_ty.toLlvm(&o.builder).getUndef()); | |
| 3976 | fields[llvm_index] = try o.builder.arrayType(padding_len, .i8); | |
| 3977 | vals[llvm_index] = try o.builder.undefConst(fields[llvm_index]); | |
| 3978 | assert(fields[llvm_index] == struct_ty.structFields(&o.builder)[llvm_index]); | |
| 3979 | llvm_index += 1; | |
| 3873 | 3980 | } |
| 3874 | 3981 | } |
| 3982 | assert(llvm_index == llvm_len); | |
| 3875 | 3983 | |
| 3876 | if (need_unnamed) { | |
| 3877 | return o.context.constStruct( | |
| 3878 | llvm_fields.items.ptr, | |
| 3879 | @as(c_uint, @intCast(llvm_fields.items.len)), | |
| 3880 | .False, | |
| 3881 | ); | |
| 3882 | } else { | |
| 3883 | return llvm_struct_ty.constNamedStruct( | |
| 3884 | llvm_fields.items.ptr, | |
| 3885 | @as(c_uint, @intCast(llvm_fields.items.len)), | |
| 3886 | ); | |
| 3887 | } | |
| 3984 | return try o.builder.structConst(if (need_unnamed) | |
| 3985 | try o.builder.structType(struct_ty.structKind(&o.builder), fields) | |
| 3986 | else | |
| 3987 | struct_ty, vals); | |
| 3888 | 3988 | }, |
| 3889 | 3989 | else => unreachable, |
| 3890 | 3990 | }, |
| 3891 | .un => { | |
| 3892 | const llvm_union_ty = (try o.lowerType(tv.ty)).toLlvm(&o.builder); | |
| 3893 | const tag_and_val: Value.Payload.Union.Data = switch (tv.val.toIntern()) { | |
| 3894 | .none => tv.val.castTag(.@"union").?.data, | |
| 3895 | else => switch (mod.intern_pool.indexToKey(tv.val.toIntern())) { | |
| 3896 | .un => |un| .{ .tag = un.tag.toValue(), .val = un.val.toValue() }, | |
| 3897 | else => unreachable, | |
| 3898 | }, | |
| 3899 | }; | |
| 3900 | ||
| 3901 | const layout = tv.ty.unionGetLayout(mod); | |
| 3991 | .un => |un| { | |
| 3992 | const union_ty = try o.lowerType(ty); | |
| 3993 | const layout = ty.unionGetLayout(mod); | |
| 3994 | if (layout.payload_size == 0) return o.lowerValue(un.tag); | |
| 3902 | 3995 | |
| 3903 | if (layout.payload_size == 0) { | |
| 3904 | return lowerValue(o, .{ | |
| 3905 | .ty = tv.ty.unionTagTypeSafety(mod).?, | |
| 3906 | .val = tag_and_val.tag, | |
| 3907 | }); | |
| 3908 | } | |
| 3909 | const union_obj = mod.typeToUnion(tv.ty).?; | |
| 3910 | const field_index = tv.ty.unionTagFieldIndex(tag_and_val.tag, o.module).?; | |
| 3996 | const union_obj = mod.typeToUnion(ty).?; | |
| 3997 | const field_index = ty.unionTagFieldIndex(un.tag.toValue(), o.module).?; | |
| 3911 | 3998 | assert(union_obj.haveFieldTypes()); |
| 3912 | 3999 | |
| 3913 | 4000 | const field_ty = union_obj.fields.values()[field_index].ty; |
| 3914 | 4001 | if (union_obj.layout == .Packed) { |
| 3915 | if (!field_ty.hasRuntimeBits(mod)) | |
| 3916 | return llvm_union_ty.constNull(); | |
| 3917 | const non_int_val = try lowerValue(o, .{ .ty = field_ty, .val = tag_and_val.val }); | |
| 3918 | const ty_bit_size = @as(u16, @intCast(field_ty.bitSize(mod))); | |
| 3919 | const small_int_ty = (try o.builder.intType(@intCast(ty_bit_size))).toLlvm(&o.builder); | |
| 3920 | const small_int_val = if (field_ty.isPtrAtRuntime(mod)) | |
| 3921 | non_int_val.constPtrToInt(small_int_ty) | |
| 3922 | else | |
| 3923 | non_int_val.constBitCast(small_int_ty); | |
| 3924 | return small_int_val.constZExtOrBitCast(llvm_union_ty); | |
| 4002 | if (!field_ty.hasRuntimeBits(mod)) return o.builder.intConst(union_ty, 0); | |
| 4003 | const small_int_val = try o.builder.castConst( | |
| 4004 | if (field_ty.isPtrAtRuntime(mod)) .ptrtoint else .bitcast, | |
| 4005 | try o.lowerValue(un.val), | |
| 4006 | try o.builder.intType(@intCast(field_ty.bitSize(mod))), | |
| 4007 | ); | |
| 4008 | return o.builder.convConst(.unsigned, small_int_val, union_ty); | |
| 3925 | 4009 | } |
| 3926 | 4010 | |
| 3927 | 4011 | // Sometimes we must make an unnamed struct because LLVM does |
| 3928 | 4012 | // not support bitcasting our payload struct to the true union payload type. |
| 3929 | 4013 | // Instead we use an unnamed struct and every reference to the global |
| 3930 | 4014 | // must pointer cast to the expected type before accessing the union. |
| 3931 | var need_unnamed: bool = layout.most_aligned_field != field_index; | |
| 4015 | var need_unnamed = layout.most_aligned_field != field_index; | |
| 3932 | 4016 | const payload = p: { |
| 3933 | 4017 | if (!field_ty.hasRuntimeBitsIgnoreComptime(mod)) { |
| 3934 | const padding_len = @as(c_uint, @intCast(layout.payload_size)); | |
| 3935 | break :p (try o.builder.arrayType(padding_len, .i8)).toLlvm(&o.builder).getUndef(); | |
| 4018 | const padding_len = layout.payload_size; | |
| 4019 | break :p try o.builder.undefConst(try o.builder.arrayType(padding_len, .i8)); | |
| 3936 | 4020 | } |
| 3937 | const field = try lowerValue(o, .{ .ty = field_ty, .val = tag_and_val.val }); | |
| 3938 | need_unnamed = need_unnamed or o.isUnnamedType(field_ty, field); | |
| 4021 | const payload = try o.lowerValue(un.val); | |
| 4022 | const payload_ty = payload.typeOf(&o.builder); | |
| 4023 | if (payload_ty != union_ty.structFields(&o.builder)[ | |
| 4024 | @intFromBool(layout.tag_align >= layout.payload_align) | |
| 4025 | ]) need_unnamed = true; | |
| 3939 | 4026 | const field_size = field_ty.abiSize(mod); |
| 3940 | if (field_size == layout.payload_size) { | |
| 3941 | break :p field; | |
| 3942 | } | |
| 3943 | const padding_len = @as(c_uint, @intCast(layout.payload_size - field_size)); | |
| 3944 | const fields: [2]*llvm.Value = .{ | |
| 3945 | field, (try o.builder.arrayType(padding_len, .i8)).toLlvm(&o.builder).getUndef(), | |
| 3946 | }; | |
| 3947 | break :p o.context.constStruct(&fields, fields.len, .True); | |
| 4027 | if (field_size == layout.payload_size) break :p payload; | |
| 4028 | const padding_len = layout.payload_size - field_size; | |
| 4029 | const padding_ty = try o.builder.arrayType(padding_len, .i8); | |
| 4030 | break :p try o.builder.structConst( | |
| 4031 | try o.builder.structType(.@"packed", &.{ payload_ty, padding_ty }), | |
| 4032 | &.{ payload, try o.builder.undefConst(padding_ty) }, | |
| 4033 | ); | |
| 3948 | 4034 | }; |
| 4035 | const payload_ty = payload.typeOf(&o.builder); | |
| 3949 | 4036 | |
| 3950 | if (layout.tag_size == 0) { | |
| 3951 | const fields: [1]*llvm.Value = .{payload}; | |
| 3952 | if (need_unnamed) { | |
| 3953 | return o.context.constStruct(&fields, fields.len, .False); | |
| 3954 | } else { | |
| 3955 | return llvm_union_ty.constNamedStruct(&fields, fields.len); | |
| 3956 | } | |
| 3957 | } | |
| 3958 | const llvm_tag_value = try lowerValue(o, .{ | |
| 3959 | .ty = tv.ty.unionTagTypeSafety(mod).?, | |
| 3960 | .val = tag_and_val.tag, | |
| 3961 | }); | |
| 3962 | var fields: [3]*llvm.Value = undefined; | |
| 3963 | var fields_len: c_uint = 2; | |
| 4037 | if (layout.tag_size == 0) return o.builder.structConst(if (need_unnamed) | |
| 4038 | try o.builder.structType(union_ty.structKind(&o.builder), &.{payload_ty}) | |
| 4039 | else | |
| 4040 | union_ty, &.{payload}); | |
| 4041 | const tag = try o.lowerValue(un.tag); | |
| 4042 | const tag_ty = tag.typeOf(&o.builder); | |
| 4043 | var fields: [3]Builder.Type = undefined; | |
| 4044 | var vals: [3]Builder.Constant = undefined; | |
| 4045 | var len: usize = 2; | |
| 3964 | 4046 | if (layout.tag_align >= layout.payload_align) { |
| 3965 | fields = .{ llvm_tag_value, payload, undefined }; | |
| 4047 | fields = .{ tag_ty, payload_ty, undefined }; | |
| 4048 | vals = .{ tag, payload, undefined }; | |
| 3966 | 4049 | } else { |
| 3967 | fields = .{ payload, llvm_tag_value, undefined }; | |
| 4050 | fields = .{ payload_ty, tag_ty, undefined }; | |
| 4051 | vals = .{ payload, tag, undefined }; | |
| 3968 | 4052 | } |
| 3969 | 4053 | if (layout.padding != 0) { |
| 3970 | fields[2] = (try o.builder.arrayType(layout.padding, .i8)).toLlvm(&o.builder).getUndef(); | |
| 3971 | fields_len = 3; | |
| 3972 | } | |
| 3973 | if (need_unnamed) { | |
| 3974 | return o.context.constStruct(&fields, fields_len, .False); | |
| 3975 | } else { | |
| 3976 | return llvm_union_ty.constNamedStruct(&fields, fields_len); | |
| 4054 | fields[2] = try o.builder.arrayType(layout.padding, .i8); | |
| 4055 | vals[2] = try o.builder.undefConst(fields[2]); | |
| 4056 | len = 3; | |
| 3977 | 4057 | } |
| 4058 | return try o.builder.structConst(if (need_unnamed) | |
| 4059 | try o.builder.structType(union_ty.structKind(&o.builder), fields[0..len]) | |
| 4060 | else | |
| 4061 | union_ty, vals[0..len]); | |
| 3978 | 4062 | }, |
| 3979 | 4063 | .memoized_call => unreachable, |
| 3980 | } | |
| 4064 | }; | |
| 3981 | 4065 | } |
| 3982 | 4066 | |
| 3983 | fn lowerIntAsPtr(o: *Object, val: Value) Allocator.Error!*llvm.Value { | |
| 4067 | fn lowerIntAsPtr(o: *Object, val: InternPool.Index) Allocator.Error!Builder.Constant { | |
| 3984 | 4068 | const mod = o.module; |
| 3985 | switch (mod.intern_pool.indexToKey(val.toIntern())) { | |
| 3986 | .undef => return o.context.pointerType(0).getUndef(), | |
| 4069 | switch (mod.intern_pool.indexToKey(val)) { | |
| 4070 | .undef => return o.builder.undefConst(.ptr), | |
| 3987 | 4071 | .int => { |
| 3988 | 4072 | var bigint_space: Value.BigIntSpace = undefined; |
| 3989 | const bigint = val.toBigInt(&bigint_space, mod); | |
| 4073 | const bigint = val.toValue().toBigInt(&bigint_space, mod); | |
| 3990 | 4074 | const llvm_int = try lowerBigInt(o, Type.usize, bigint); |
| 3991 | return llvm_int.constIntToPtr(o.context.pointerType(0)); | |
| 4075 | return o.builder.castConst(.inttoptr, llvm_int, .ptr); | |
| 3992 | 4076 | }, |
| 3993 | 4077 | else => unreachable, |
| 3994 | 4078 | } |
| 3995 | 4079 | } |
| 3996 | 4080 | |
| 3997 | fn lowerBigInt(o: *Object, ty: Type, bigint: std.math.big.int.Const) Allocator.Error!*llvm.Value { | |
| 3998 | return (try o.builder.bigIntConst(try o.builder.intType(ty.intInfo(o.module).bits), bigint)) | |
| 3999 | .toLlvm(&o.builder); | |
| 4081 | fn lowerBigInt( | |
| 4082 | o: *Object, | |
| 4083 | ty: Type, | |
| 4084 | bigint: std.math.big.int.Const, | |
| 4085 | ) Allocator.Error!Builder.Constant { | |
| 4086 | const mod = o.module; | |
| 4087 | return o.builder.bigIntConst(try o.builder.intType(ty.intInfo(mod).bits), bigint); | |
| 4000 | 4088 | } |
| 4001 | 4089 | |
| 4002 | 4090 | const ParentPtr = struct { |
| ... | ... | @@ -4004,45 +4092,41 @@ pub const Object = struct { |
| 4004 | 4092 | llvm_ptr: *llvm.Value, |
| 4005 | 4093 | }; |
| 4006 | 4094 | |
| 4007 | fn lowerParentPtrDecl( | |
| 4008 | o: *Object, | |
| 4009 | ptr_val: Value, | |
| 4010 | decl_index: Module.Decl.Index, | |
| 4011 | ) Error!*llvm.Value { | |
| 4095 | fn lowerParentPtrDecl(o: *Object, decl_index: Module.Decl.Index) Allocator.Error!Builder.Constant { | |
| 4012 | 4096 | const mod = o.module; |
| 4013 | 4097 | const decl = mod.declPtr(decl_index); |
| 4014 | 4098 | try mod.markDeclAlive(decl); |
| 4015 | 4099 | const ptr_ty = try mod.singleMutPtrType(decl.ty); |
| 4016 | return try o.lowerDeclRefValue(.{ .ty = ptr_ty, .val = ptr_val }, decl_index); | |
| 4100 | return o.lowerDeclRefValue(ptr_ty, decl_index); | |
| 4017 | 4101 | } |
| 4018 | 4102 | |
| 4019 | fn lowerParentPtr(o: *Object, ptr_val: Value, byte_aligned: bool) Error!*llvm.Value { | |
| 4103 | fn lowerParentPtr(o: *Object, ptr_val: Value, byte_aligned: bool) Allocator.Error!Builder.Constant { | |
| 4020 | 4104 | const mod = o.module; |
| 4021 | 4105 | return switch (mod.intern_pool.indexToKey(ptr_val.toIntern()).ptr.addr) { |
| 4022 | .decl => |decl| o.lowerParentPtrDecl(ptr_val, decl), | |
| 4023 | .mut_decl => |mut_decl| o.lowerParentPtrDecl(ptr_val, mut_decl.decl), | |
| 4024 | .int => |int| o.lowerIntAsPtr(int.toValue()), | |
| 4106 | .decl => |decl| o.lowerParentPtrDecl(decl), | |
| 4107 | .mut_decl => |mut_decl| o.lowerParentPtrDecl(mut_decl.decl), | |
| 4108 | .int => |int| try o.lowerIntAsPtr(int), | |
| 4025 | 4109 | .eu_payload => |eu_ptr| { |
| 4026 | const parent_llvm_ptr = try o.lowerParentPtr(eu_ptr.toValue(), true); | |
| 4110 | const parent_ptr = try o.lowerParentPtr(eu_ptr.toValue(), true); | |
| 4027 | 4111 | |
| 4028 | 4112 | const eu_ty = mod.intern_pool.typeOf(eu_ptr).toType().childType(mod); |
| 4029 | 4113 | const payload_ty = eu_ty.errorUnionPayload(mod); |
| 4030 | 4114 | if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) { |
| 4031 | 4115 | // In this case, we represent pointer to error union the same as pointer |
| 4032 | 4116 | // to the payload. |
| 4033 | return parent_llvm_ptr; | |
| 4117 | return parent_ptr; | |
| 4034 | 4118 | } |
| 4035 | 4119 | |
| 4036 | const payload_offset: u8 = if (payload_ty.abiAlignment(mod) > Type.anyerror.abiSize(mod)) 2 else 1; | |
| 4037 | const indices: [2]*llvm.Value = .{ | |
| 4038 | (try o.builder.intConst(.i32, 0)).toLlvm(&o.builder), | |
| 4039 | (try o.builder.intConst(.i32, payload_offset)).toLlvm(&o.builder), | |
| 4040 | }; | |
| 4041 | const eu_llvm_ty = (try o.lowerType(eu_ty)).toLlvm(&o.builder); | |
| 4042 | return eu_llvm_ty.constInBoundsGEP(parent_llvm_ptr, &indices, indices.len); | |
| 4120 | return o.builder.gepConst(.inbounds, try o.lowerType(eu_ty), parent_ptr, &.{ | |
| 4121 | try o.builder.intConst(.i32, 0), | |
| 4122 | try o.builder.intConst(.i32, @as( | |
| 4123 | i32, | |
| 4124 | if (payload_ty.abiAlignment(mod) > Type.err_int.abiSize(mod)) 2 else 1, | |
| 4125 | )), | |
| 4126 | }); | |
| 4043 | 4127 | }, |
| 4044 | 4128 | .opt_payload => |opt_ptr| { |
| 4045 | const parent_llvm_ptr = try o.lowerParentPtr(opt_ptr.toValue(), true); | |
| 4129 | const parent_ptr = try o.lowerParentPtr(opt_ptr.toValue(), true); | |
| 4046 | 4130 | |
| 4047 | 4131 | const opt_ty = mod.intern_pool.typeOf(opt_ptr).toType().childType(mod); |
| 4048 | 4132 | const payload_ty = opt_ty.optionalChild(mod); |
| ... | ... | @@ -4051,96 +4135,87 @@ pub const Object = struct { |
| 4051 | 4135 | { |
| 4052 | 4136 | // In this case, we represent pointer to optional the same as pointer |
| 4053 | 4137 | // to the payload. |
| 4054 | return parent_llvm_ptr; | |
| 4138 | return parent_ptr; | |
| 4055 | 4139 | } |
| 4056 | 4140 | |
| 4057 | const indices: [2]*llvm.Value = .{ | |
| 4058 | (try o.builder.intConst(.i32, 0)).toLlvm(&o.builder), | |
| 4059 | } ** 2; | |
| 4060 | const opt_llvm_ty = (try o.lowerType(opt_ty)).toLlvm(&o.builder); | |
| 4061 | return opt_llvm_ty.constInBoundsGEP(parent_llvm_ptr, &indices, indices.len); | |
| 4141 | return o.builder.gepConst(.inbounds, try o.lowerType(opt_ty), parent_ptr, &(.{ | |
| 4142 | try o.builder.intConst(.i32, 0), | |
| 4143 | } ** 2)); | |
| 4062 | 4144 | }, |
| 4063 | 4145 | .comptime_field => unreachable, |
| 4064 | 4146 | .elem => |elem_ptr| { |
| 4065 | const parent_llvm_ptr = try o.lowerParentPtr(elem_ptr.base.toValue(), true); | |
| 4066 | ||
| 4067 | const indices: [1]*llvm.Value = .{ | |
| 4068 | (try o.builder.intConst(try o.lowerType(Type.usize), elem_ptr.index)).toLlvm(&o.builder), | |
| 4069 | }; | |
| 4147 | const parent_ptr = try o.lowerParentPtr(elem_ptr.base.toValue(), true); | |
| 4070 | 4148 | const elem_ty = mod.intern_pool.typeOf(elem_ptr.base).toType().elemType2(mod); |
| 4071 | const elem_llvm_ty = (try o.lowerType(elem_ty)).toLlvm(&o.builder); | |
| 4072 | return elem_llvm_ty.constInBoundsGEP(parent_llvm_ptr, &indices, indices.len); | |
| 4149 | ||
| 4150 | return o.builder.gepConst(.inbounds, try o.lowerType(elem_ty), parent_ptr, &.{ | |
| 4151 | try o.builder.intConst(try o.lowerType(Type.usize), elem_ptr.index), | |
| 4152 | }); | |
| 4073 | 4153 | }, |
| 4074 | 4154 | .field => |field_ptr| { |
| 4075 | const parent_llvm_ptr = try o.lowerParentPtr(field_ptr.base.toValue(), byte_aligned); | |
| 4155 | const parent_ptr = try o.lowerParentPtr(field_ptr.base.toValue(), byte_aligned); | |
| 4076 | 4156 | const parent_ty = mod.intern_pool.typeOf(field_ptr.base).toType().childType(mod); |
| 4077 | 4157 | |
| 4078 | const field_index = @as(u32, @intCast(field_ptr.index)); | |
| 4158 | const field_index: u32 = @intCast(field_ptr.index); | |
| 4079 | 4159 | switch (parent_ty.zigTypeTag(mod)) { |
| 4080 | 4160 | .Union => { |
| 4081 | 4161 | if (parent_ty.containerLayout(mod) == .Packed) { |
| 4082 | return parent_llvm_ptr; | |
| 4162 | return parent_ptr; | |
| 4083 | 4163 | } |
| 4084 | 4164 | |
| 4085 | 4165 | const layout = parent_ty.unionGetLayout(mod); |
| 4086 | 4166 | if (layout.payload_size == 0) { |
| 4087 | 4167 | // In this case a pointer to the union and a pointer to any |
| 4088 | 4168 | // (void) payload is the same. |
| 4089 | return parent_llvm_ptr; | |
| 4169 | return parent_ptr; | |
| 4090 | 4170 | } |
| 4091 | const llvm_pl_index = if (layout.tag_size == 0) | |
| 4092 | 0 | |
| 4093 | else | |
| 4094 | @intFromBool(layout.tag_align >= layout.payload_align); | |
| 4095 | const indices: [2]*llvm.Value = .{ | |
| 4096 | (try o.builder.intConst(.i32, 0)).toLlvm(&o.builder), | |
| 4097 | (try o.builder.intConst(.i32, llvm_pl_index)).toLlvm(&o.builder), | |
| 4098 | }; | |
| 4099 | const parent_llvm_ty = (try o.lowerType(parent_ty)).toLlvm(&o.builder); | |
| 4100 | return parent_llvm_ty.constInBoundsGEP(parent_llvm_ptr, &indices, indices.len); | |
| 4171 | ||
| 4172 | return o.builder.gepConst(.inbounds, try o.lowerType(parent_ty), parent_ptr, &.{ | |
| 4173 | try o.builder.intConst(.i32, 0), | |
| 4174 | try o.builder.intConst(.i32, @intFromBool( | |
| 4175 | layout.tag_size > 0 and layout.tag_align >= layout.payload_align, | |
| 4176 | )), | |
| 4177 | }); | |
| 4101 | 4178 | }, |
| 4102 | 4179 | .Struct => { |
| 4103 | 4180 | if (parent_ty.containerLayout(mod) == .Packed) { |
| 4104 | if (!byte_aligned) return parent_llvm_ptr; | |
| 4181 | if (!byte_aligned) return parent_ptr; | |
| 4105 | 4182 | const llvm_usize = try o.lowerType(Type.usize); |
| 4106 | const base_addr = parent_llvm_ptr.constPtrToInt(llvm_usize.toLlvm(&o.builder)); | |
| 4183 | const base_addr = | |
| 4184 | try o.builder.castConst(.ptrtoint, parent_ptr, llvm_usize); | |
| 4107 | 4185 | // count bits of fields before this one |
| 4108 | 4186 | const prev_bits = b: { |
| 4109 | 4187 | var b: usize = 0; |
| 4110 | 4188 | for (parent_ty.structFields(mod).values()[0..field_index]) |field| { |
| 4111 | 4189 | if (field.is_comptime or !field.ty.hasRuntimeBitsIgnoreComptime(mod)) continue; |
| 4112 | b += @as(usize, @intCast(field.ty.bitSize(mod))); | |
| 4190 | b += @intCast(field.ty.bitSize(mod)); | |
| 4113 | 4191 | } |
| 4114 | 4192 | break :b b; |
| 4115 | 4193 | }; |
| 4116 | const byte_offset = (try o.builder.intConst(llvm_usize, prev_bits / 8)).toLlvm(&o.builder); | |
| 4117 | const field_addr = base_addr.constAdd(byte_offset); | |
| 4118 | const final_llvm_ty = o.context.pointerType(0); | |
| 4119 | return field_addr.constIntToPtr(final_llvm_ty); | |
| 4194 | const byte_offset = try o.builder.intConst(llvm_usize, prev_bits / 8); | |
| 4195 | const field_addr = try o.builder.binConst(.add, base_addr, byte_offset); | |
| 4196 | return o.builder.castConst(.inttoptr, field_addr, .ptr); | |
| 4120 | 4197 | } |
| 4121 | 4198 | |
| 4122 | const parent_llvm_ty = (try o.lowerType(parent_ty)).toLlvm(&o.builder); | |
| 4123 | if (llvmField(parent_ty, field_index, mod)) |llvm_field| { | |
| 4124 | const indices: [2]*llvm.Value = .{ | |
| 4125 | (try o.builder.intConst(.i32, 0)).toLlvm(&o.builder), | |
| 4126 | (try o.builder.intConst(.i32, llvm_field.index)).toLlvm(&o.builder), | |
| 4127 | }; | |
| 4128 | return parent_llvm_ty.constInBoundsGEP(parent_llvm_ptr, &indices, indices.len); | |
| 4129 | } else { | |
| 4130 | const indices: [1]*llvm.Value = .{ | |
| 4131 | (try o.builder.intConst(.i32, @intFromBool(parent_ty.hasRuntimeBitsIgnoreComptime(mod)))).toLlvm(&o.builder), | |
| 4132 | }; | |
| 4133 | return parent_llvm_ty.constInBoundsGEP(parent_llvm_ptr, &indices, indices.len); | |
| 4134 | } | |
| 4199 | return o.builder.gepConst( | |
| 4200 | .inbounds, | |
| 4201 | try o.lowerType(parent_ty), | |
| 4202 | parent_ptr, | |
| 4203 | if (llvmField(parent_ty, field_index, mod)) |llvm_field| &.{ | |
| 4204 | try o.builder.intConst(.i32, 0), | |
| 4205 | try o.builder.intConst(.i32, llvm_field.index), | |
| 4206 | } else &.{ | |
| 4207 | try o.builder.intConst(.i32, @intFromBool( | |
| 4208 | parent_ty.hasRuntimeBitsIgnoreComptime(mod), | |
| 4209 | )), | |
| 4210 | }, | |
| 4211 | ); | |
| 4135 | 4212 | }, |
| 4136 | 4213 | .Pointer => { |
| 4137 | 4214 | assert(parent_ty.isSlice(mod)); |
| 4138 | const indices: [2]*llvm.Value = .{ | |
| 4139 | (try o.builder.intConst(.i32, 0)).toLlvm(&o.builder), | |
| 4140 | (try o.builder.intConst(.i32, field_index)).toLlvm(&o.builder), | |
| 4141 | }; | |
| 4142 | const parent_llvm_ty = (try o.lowerType(parent_ty)).toLlvm(&o.builder); | |
| 4143 | return parent_llvm_ty.constInBoundsGEP(parent_llvm_ptr, &indices, indices.len); | |
| 4215 | return o.builder.gepConst(.inbounds, try o.lowerType(parent_ty), parent_ptr, &.{ | |
| 4216 | try o.builder.intConst(.i32, 0), | |
| 4217 | try o.builder.intConst(.i32, field_index), | |
| 4218 | }); | |
| 4144 | 4219 | }, |
| 4145 | 4220 | else => unreachable, |
| 4146 | 4221 | } |
| ... | ... | @@ -4148,11 +4223,7 @@ pub const Object = struct { |
| 4148 | 4223 | }; |
| 4149 | 4224 | } |
| 4150 | 4225 | |
| 4151 | fn lowerDeclRefValue( | |
| 4152 | o: *Object, | |
| 4153 | tv: TypedValue, | |
| 4154 | decl_index: Module.Decl.Index, | |
| 4155 | ) Error!*llvm.Value { | |
| 4226 | fn lowerDeclRefValue(o: *Object, ty: Type, decl_index: Module.Decl.Index) Allocator.Error!Builder.Constant { | |
| 4156 | 4227 | const mod = o.module; |
| 4157 | 4228 | |
| 4158 | 4229 | // In the case of something like: |
| ... | ... | @@ -4163,69 +4234,63 @@ pub const Object = struct { |
| 4163 | 4234 | const decl = mod.declPtr(decl_index); |
| 4164 | 4235 | if (decl.val.getFunction(mod)) |func| { |
| 4165 | 4236 | if (func.owner_decl != decl_index) { |
| 4166 | return o.lowerDeclRefValue(tv, func.owner_decl); | |
| 4237 | return o.lowerDeclRefValue(ty, func.owner_decl); | |
| 4167 | 4238 | } |
| 4168 | 4239 | } else if (decl.val.getExternFunc(mod)) |func| { |
| 4169 | 4240 | if (func.decl != decl_index) { |
| 4170 | return o.lowerDeclRefValue(tv, func.decl); | |
| 4241 | return o.lowerDeclRefValue(ty, func.decl); | |
| 4171 | 4242 | } |
| 4172 | 4243 | } |
| 4173 | 4244 | |
| 4174 | 4245 | const is_fn_body = decl.ty.zigTypeTag(mod) == .Fn; |
| 4175 | 4246 | if ((!is_fn_body and !decl.ty.hasRuntimeBits(mod)) or |
| 4176 | 4247 | (is_fn_body and mod.typeToFunc(decl.ty).?.is_generic)) |
| 4177 | { | |
| 4178 | return o.lowerPtrToVoid(tv.ty); | |
| 4179 | } | |
| 4248 | return o.lowerPtrToVoid(ty); | |
| 4180 | 4249 | |
| 4181 | 4250 | try mod.markDeclAlive(decl); |
| 4182 | 4251 | |
| 4183 | const llvm_decl_val = if (is_fn_body) | |
| 4184 | (try o.resolveLlvmFunction(decl_index)).toLlvm(&o.builder) | |
| 4252 | const llvm_global = if (is_fn_body) | |
| 4253 | (try o.resolveLlvmFunction(decl_index)).ptrConst(&o.builder).global | |
| 4185 | 4254 | else |
| 4186 | (try o.resolveGlobalDecl(decl_index)).toLlvm(&o.builder); | |
| 4255 | (try o.resolveGlobalDecl(decl_index)).ptrConst(&o.builder).global; | |
| 4187 | 4256 | |
| 4188 | 4257 | const target = mod.getTarget(); |
| 4189 | 4258 | const llvm_wanted_addrspace = toLlvmAddressSpace(decl.@"addrspace", target); |
| 4190 | 4259 | const llvm_actual_addrspace = toLlvmGlobalAddressSpace(decl.@"addrspace", target); |
| 4191 | const llvm_val = if (llvm_wanted_addrspace != llvm_actual_addrspace) blk: { | |
| 4192 | const llvm_decl_wanted_ptr_ty = o.context.pointerType(@intFromEnum(llvm_wanted_addrspace)); | |
| 4193 | break :blk llvm_decl_val.constAddrSpaceCast(llvm_decl_wanted_ptr_ty); | |
| 4194 | } else llvm_decl_val; | |
| 4195 | ||
| 4196 | const llvm_type = (try o.lowerType(tv.ty)).toLlvm(&o.builder); | |
| 4197 | if (tv.ty.zigTypeTag(mod) == .Int) { | |
| 4198 | return llvm_val.constPtrToInt(llvm_type); | |
| 4199 | } else { | |
| 4200 | return llvm_val.constBitCast(llvm_type); | |
| 4201 | } | |
| 4260 | const llvm_val = if (llvm_wanted_addrspace != llvm_actual_addrspace) try o.builder.castConst( | |
| 4261 | .addrspacecast, | |
| 4262 | llvm_global.toConst(), | |
| 4263 | try o.builder.ptrType(llvm_wanted_addrspace), | |
| 4264 | ) else llvm_global.toConst(); | |
| 4265 | ||
| 4266 | return o.builder.convConst(if (ty.isAbiInt(mod)) switch (ty.intInfo(mod).signedness) { | |
| 4267 | .signed => .signed, | |
| 4268 | .unsigned => .unsigned, | |
| 4269 | } else .unneeded, llvm_val, try o.lowerType(ty)); | |
| 4202 | 4270 | } |
| 4203 | 4271 | |
| 4204 | fn lowerPtrToVoid(o: *Object, ptr_ty: Type) !*llvm.Value { | |
| 4272 | fn lowerPtrToVoid(o: *Object, ptr_ty: Type) Allocator.Error!Builder.Constant { | |
| 4205 | 4273 | const mod = o.module; |
| 4206 | 4274 | // Even though we are pointing at something which has zero bits (e.g. `void`), |
| 4207 | 4275 | // Pointers are defined to have bits. So we must return something here. |
| 4208 | 4276 | // The value cannot be undefined, because we use the `nonnull` annotation |
| 4209 | 4277 | // for non-optional pointers. We also need to respect the alignment, even though |
| 4210 | 4278 | // the address will never be dereferenced. |
| 4211 | const llvm_usize = try o.lowerType(Type.usize); | |
| 4212 | const llvm_ptr_ty = (try o.lowerType(ptr_ty)).toLlvm(&o.builder); | |
| 4213 | if (ptr_ty.ptrInfo(mod).flags.alignment.toByteUnitsOptional()) |alignment| { | |
| 4214 | return (try o.builder.intConst(llvm_usize, alignment)).toLlvm(&o.builder).constIntToPtr(llvm_ptr_ty); | |
| 4215 | } | |
| 4216 | // Note that these 0xaa values are appropriate even in release-optimized builds | |
| 4217 | // because we need a well-defined value that is not null, and LLVM does not | |
| 4218 | // have an "undef_but_not_null" attribute. As an example, if this `alloc` AIR | |
| 4219 | // instruction is followed by a `wrap_optional`, it will return this value | |
| 4220 | // verbatim, and the result should test as non-null. | |
| 4221 | const target = mod.getTarget(); | |
| 4222 | const int = try o.builder.intConst(llvm_usize, @as(u64, switch (target.ptrBitWidth()) { | |
| 4279 | const int: u64 = ptr_ty.ptrInfo(mod).flags.alignment.toByteUnitsOptional() orelse | |
| 4280 | // Note that these 0xaa values are appropriate even in release-optimized builds | |
| 4281 | // because we need a well-defined value that is not null, and LLVM does not | |
| 4282 | // have an "undef_but_not_null" attribute. As an example, if this `alloc` AIR | |
| 4283 | // instruction is followed by a `wrap_optional`, it will return this value | |
| 4284 | // verbatim, and the result should test as non-null. | |
| 4285 | switch (mod.getTarget().ptrBitWidth()) { | |
| 4223 | 4286 | 16 => 0xaaaa, |
| 4224 | 4287 | 32 => 0xaaaaaaaa, |
| 4225 | 4288 | 64 => 0xaaaaaaaa_aaaaaaaa, |
| 4226 | 4289 | else => unreachable, |
| 4227 | })); | |
| 4228 | return int.toLlvm(&o.builder).constIntToPtr(llvm_ptr_ty); | |
| 4290 | }; | |
| 4291 | const llvm_usize = try o.lowerType(Type.usize); | |
| 4292 | const llvm_ptr_ty = try o.lowerType(ptr_ty); | |
| 4293 | return o.builder.castConst(.inttoptr, try o.builder.intConst(llvm_usize, int), llvm_ptr_ty); | |
| 4229 | 4294 | } |
| 4230 | 4295 | |
| 4231 | 4296 | fn addAttr(o: *Object, val: *llvm.Value, index: llvm.AttributeIndex, name: []const u8) void { |
| ... | ... | @@ -4436,26 +4501,29 @@ pub const DeclGen = struct { |
| 4436 | 4501 | _ = try o.resolveLlvmFunction(extern_func.decl); |
| 4437 | 4502 | } else { |
| 4438 | 4503 | const target = mod.getTarget(); |
| 4439 | const object_index = try o.resolveGlobalDecl(decl_index); | |
| 4440 | const object = object_index.ptr(&o.builder); | |
| 4441 | const global = object.global.ptr(&o.builder); | |
| 4442 | var llvm_global = object.global.toLlvm(&o.builder); | |
| 4443 | global.alignment = Builder.Alignment.fromByteUnits(decl.getAlignment(mod)); | |
| 4504 | const object = try o.resolveGlobalDecl(decl_index); | |
| 4505 | const global = object.ptrConst(&o.builder).global; | |
| 4506 | var llvm_global = global.toLlvm(&o.builder); | |
| 4507 | global.ptr(&o.builder).alignment = Builder.Alignment.fromByteUnits(decl.getAlignment(mod)); | |
| 4444 | 4508 | llvm_global.setAlignment(decl.getAlignment(mod)); |
| 4445 | if (mod.intern_pool.stringToSliceUnwrap(decl.@"linksection")) |s| llvm_global.setSection(s); | |
| 4509 | if (mod.intern_pool.stringToSliceUnwrap(decl.@"linksection")) |section| { | |
| 4510 | global.ptr(&o.builder).section = try o.builder.string(section); | |
| 4511 | llvm_global.setSection(section); | |
| 4512 | } | |
| 4446 | 4513 | assert(decl.has_tv); |
| 4447 | const init_val = if (decl.val.getVariable(mod)) |variable| init_val: { | |
| 4448 | object.mutability = .global; | |
| 4449 | break :init_val variable.init; | |
| 4514 | const init_val = if (decl.val.getVariable(mod)) |decl_var| init_val: { | |
| 4515 | object.ptr(&o.builder).mutability = .global; | |
| 4516 | break :init_val decl_var.init; | |
| 4450 | 4517 | } else init_val: { |
| 4451 | object.mutability = .constant; | |
| 4518 | object.ptr(&o.builder).mutability = .constant; | |
| 4452 | 4519 | llvm_global.setGlobalConstant(.True); |
| 4453 | 4520 | break :init_val decl.val.toIntern(); |
| 4454 | 4521 | }; |
| 4455 | 4522 | if (init_val != .none) { |
| 4456 | const llvm_init = try o.lowerValue(.{ .ty = decl.ty, .val = init_val.toValue() }); | |
| 4457 | if (llvm_global.globalGetValueType() == llvm_init.typeOf()) { | |
| 4458 | llvm_global.setInitializer(llvm_init); | |
| 4523 | const llvm_init = try o.lowerValue(init_val); | |
| 4524 | if (llvm_global.globalGetValueType() == llvm_init.typeOf(&o.builder).toLlvm(&o.builder)) { | |
| 4525 | object.ptr(&o.builder).init = llvm_init; | |
| 4526 | llvm_global.setInitializer(llvm_init.toLlvm(&o.builder)); | |
| 4459 | 4527 | } else { |
| 4460 | 4528 | // LLVM does not allow us to change the type of globals. So we must |
| 4461 | 4529 | // create a new global with the correct type, copy all its attributes, |
| ... | ... | @@ -4472,20 +4540,21 @@ pub const DeclGen = struct { |
| 4472 | 4540 | // Related: https://github.com/ziglang/zig/issues/13265 |
| 4473 | 4541 | const llvm_global_addrspace = toLlvmGlobalAddressSpace(decl.@"addrspace", target); |
| 4474 | 4542 | const new_global = o.llvm_module.addGlobalInAddressSpace( |
| 4475 | llvm_init.typeOf(), | |
| 4543 | llvm_init.typeOf(&o.builder).toLlvm(&o.builder), | |
| 4476 | 4544 | "", |
| 4477 | 4545 | @intFromEnum(llvm_global_addrspace), |
| 4478 | 4546 | ); |
| 4479 | 4547 | new_global.setLinkage(llvm_global.getLinkage()); |
| 4480 | 4548 | new_global.setUnnamedAddr(llvm_global.getUnnamedAddress()); |
| 4481 | 4549 | new_global.setAlignment(llvm_global.getAlignment()); |
| 4482 | if (mod.intern_pool.stringToSliceUnwrap(decl.@"linksection")) |s| | |
| 4483 | new_global.setSection(s); | |
| 4484 | new_global.setInitializer(llvm_init); | |
| 4550 | if (mod.intern_pool.stringToSliceUnwrap(decl.@"linksection")) |section| | |
| 4551 | new_global.setSection(section); | |
| 4552 | new_global.setInitializer(llvm_init.toLlvm(&o.builder)); | |
| 4485 | 4553 | // TODO: How should this work then the address space of a global changed? |
| 4486 | 4554 | llvm_global.replaceAllUsesWith(new_global); |
| 4487 | 4555 | new_global.takeName(llvm_global); |
| 4488 | o.builder.llvm_globals.items[@intFromEnum(object.global)] = new_global; | |
| 4556 | o.builder.llvm_globals.items[@intFromEnum(object.ptrConst(&o.builder).global)] = | |
| 4557 | new_global; | |
| 4489 | 4558 | llvm_global.deleteGlobal(); |
| 4490 | 4559 | llvm_global = new_global; |
| 4491 | 4560 | } |
| ... | ... | @@ -4601,24 +4670,45 @@ pub const FuncGen = struct { |
| 4601 | 4670 | fn resolveValue(self: *FuncGen, tv: TypedValue) !*llvm.Value { |
| 4602 | 4671 | const o = self.dg.object; |
| 4603 | 4672 | const mod = o.module; |
| 4604 | const llvm_val = try o.lowerValue(tv); | |
| 4605 | if (!isByRef(tv.ty, mod)) return llvm_val; | |
| 4673 | const llvm_val = try o.lowerValue(tv.val.toIntern()); | |
| 4674 | if (!isByRef(tv.ty, mod)) return llvm_val.toLlvm(&o.builder); | |
| 4606 | 4675 | |
| 4607 | 4676 | // We have an LLVM value but we need to create a global constant and |
| 4608 | 4677 | // set the value as its initializer, and then return a pointer to the global. |
| 4609 | 4678 | const target = mod.getTarget(); |
| 4610 | 4679 | const llvm_wanted_addrspace = toLlvmAddressSpace(.generic, target); |
| 4611 | 4680 | const llvm_actual_addrspace = toLlvmGlobalAddressSpace(.generic, target); |
| 4612 | const global = o.llvm_module.addGlobalInAddressSpace(llvm_val.typeOf(), "", @intFromEnum(llvm_actual_addrspace)); | |
| 4613 | global.setInitializer(llvm_val); | |
| 4614 | global.setLinkage(.Private); | |
| 4615 | global.setGlobalConstant(.True); | |
| 4616 | global.setUnnamedAddr(.True); | |
| 4617 | global.setAlignment(tv.ty.abiAlignment(mod)); | |
| 4681 | const llvm_ty = llvm_val.typeOf(&o.builder); | |
| 4682 | const llvm_alignment = tv.ty.abiAlignment(mod); | |
| 4683 | const llvm_global = o.llvm_module.addGlobalInAddressSpace(llvm_ty.toLlvm(&o.builder), "", @intFromEnum(llvm_actual_addrspace)); | |
| 4684 | llvm_global.setInitializer(llvm_val.toLlvm(&o.builder)); | |
| 4685 | llvm_global.setLinkage(.Private); | |
| 4686 | llvm_global.setGlobalConstant(.True); | |
| 4687 | llvm_global.setUnnamedAddr(.True); | |
| 4688 | llvm_global.setAlignment(llvm_alignment); | |
| 4689 | ||
| 4690 | var global = Builder.Global{ | |
| 4691 | .linkage = .private, | |
| 4692 | .unnamed_addr = .unnamed_addr, | |
| 4693 | .type = llvm_ty, | |
| 4694 | .alignment = Builder.Alignment.fromByteUnits(llvm_alignment), | |
| 4695 | .kind = .{ .variable = @enumFromInt(o.builder.variables.items.len) }, | |
| 4696 | }; | |
| 4697 | var variable = Builder.Variable{ | |
| 4698 | .global = @enumFromInt(o.builder.globals.count()), | |
| 4699 | .mutability = .constant, | |
| 4700 | .init = llvm_val, | |
| 4701 | }; | |
| 4702 | try o.builder.llvm_globals.append(o.gpa, llvm_global); | |
| 4703 | _ = try o.builder.addGlobal(.none, global); | |
| 4704 | try o.builder.variables.append(o.gpa, variable); | |
| 4705 | ||
| 4618 | 4706 | const addrspace_casted_ptr = if (llvm_actual_addrspace != llvm_wanted_addrspace) |
| 4619 | global.constAddrSpaceCast(self.context.pointerType(@intFromEnum(llvm_wanted_addrspace))) | |
| 4707 | llvm_global.constAddrSpaceCast( | |
| 4708 | (try o.builder.ptrType(llvm_wanted_addrspace)).toLlvm(&o.builder), | |
| 4709 | ) | |
| 4620 | 4710 | else |
| 4621 | global; | |
| 4711 | llvm_global; | |
| 4622 | 4712 | return addrspace_casted_ptr; |
| 4623 | 4713 | } |
| 4624 | 4714 | |
| ... | ... | @@ -5197,10 +5287,7 @@ pub const FuncGen = struct { |
| 5197 | 5287 | const msg_decl_index = mod.panic_messages[@intFromEnum(panic_id)].unwrap().?; |
| 5198 | 5288 | const msg_decl = mod.declPtr(msg_decl_index); |
| 5199 | 5289 | const msg_len = msg_decl.ty.childType(mod).arrayLen(mod); |
| 5200 | const msg_ptr = try o.lowerValue(.{ | |
| 5201 | .ty = msg_decl.ty, | |
| 5202 | .val = msg_decl.val, | |
| 5203 | }); | |
| 5290 | const msg_ptr = try o.lowerValue(try msg_decl.internValue(mod)); | |
| 5204 | 5291 | const null_opt_addr_global = try o.getNullOptAddr(); |
| 5205 | 5292 | const target = mod.getTarget(); |
| 5206 | 5293 | const llvm_usize = try o.lowerType(Type.usize); |
| ... | ... | @@ -5212,9 +5299,9 @@ pub const FuncGen = struct { |
| 5212 | 5299 | // ptr @2, ; addr (null ?usize) |
| 5213 | 5300 | // ) |
| 5214 | 5301 | const args = [4]*llvm.Value{ |
| 5215 | msg_ptr, | |
| 5302 | msg_ptr.toLlvm(&o.builder), | |
| 5216 | 5303 | (try o.builder.intConst(llvm_usize, msg_len)).toLlvm(&o.builder), |
| 5217 | fg.context.pointerType(0).constNull(), | |
| 5304 | (try o.builder.nullConst(.ptr)).toLlvm(&o.builder), | |
| 5218 | 5305 | null_opt_addr_global, |
| 5219 | 5306 | }; |
| 5220 | 5307 | const panic_func = mod.funcInfo(mod.panic_func_index); |
| ... | ... | @@ -5672,8 +5759,8 @@ pub const FuncGen = struct { |
| 5672 | 5759 | |
| 5673 | 5760 | if (!err_union_ty.errorUnionSet(mod).errorSetIsEmpty(mod)) { |
| 5674 | 5761 | const is_err = err: { |
| 5675 | const err_set_ty = (try o.lowerType(Type.anyerror)).toLlvm(&o.builder); | |
| 5676 | const zero = err_set_ty.constNull(); | |
| 5762 | const err_set_ty = Builder.Type.err_int.toLlvm(&o.builder); | |
| 5763 | const zero = (try o.builder.intConst(Builder.Type.err_int, 0)).toLlvm(&o.builder); | |
| 5677 | 5764 | if (!payload_has_bits) { |
| 5678 | 5765 | // TODO add alignment to this load |
| 5679 | 5766 | const loaded = if (operand_is_ptr) |
| ... | ... | @@ -6034,7 +6121,10 @@ pub const FuncGen = struct { |
| 6034 | 6121 | const array_llvm_ty = (try o.lowerType(array_ty)).toLlvm(&o.builder); |
| 6035 | 6122 | const elem_ty = array_ty.childType(mod); |
| 6036 | 6123 | if (isByRef(array_ty, mod)) { |
| 6037 | const indices: [2]*llvm.Value = .{ Builder.Type.i32.toLlvm(&o.builder).constNull(), rhs }; | |
| 6124 | const indices: [2]*llvm.Value = .{ | |
| 6125 | (try o.builder.intConst(.i32, 0)).toLlvm(&o.builder), | |
| 6126 | rhs, | |
| 6127 | }; | |
| 6038 | 6128 | if (isByRef(elem_ty, mod)) { |
| 6039 | 6129 | const elem_ptr = self.builder.buildInBoundsGEP(array_llvm_ty, array_llvm_val, &indices, indices.len, ""); |
| 6040 | 6130 | if (canElideLoad(self, body_tail)) |
| ... | ... | @@ -6082,7 +6172,10 @@ pub const FuncGen = struct { |
| 6082 | 6172 | // TODO: when we go fully opaque pointers in LLVM 16 we can remove this branch |
| 6083 | 6173 | const ptr = if (ptr_ty.isSinglePointer(mod)) ptr: { |
| 6084 | 6174 | // If this is a single-item pointer to an array, we need another index in the GEP. |
| 6085 | const indices: [2]*llvm.Value = .{ Builder.Type.i32.toLlvm(&o.builder).constNull(), rhs }; | |
| 6175 | const indices: [2]*llvm.Value = .{ | |
| 6176 | (try o.builder.intConst(.i32, 0)).toLlvm(&o.builder), | |
| 6177 | rhs, | |
| 6178 | }; | |
| 6086 | 6179 | break :ptr self.builder.buildInBoundsGEP(llvm_elem_ty, base_ptr, &indices, indices.len, ""); |
| 6087 | 6180 | } else ptr: { |
| 6088 | 6181 | const indices: [1]*llvm.Value = .{rhs}; |
| ... | ... | @@ -6105,7 +6198,8 @@ pub const FuncGen = struct { |
| 6105 | 6198 | const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data; |
| 6106 | 6199 | const ptr_ty = self.typeOf(bin_op.lhs); |
| 6107 | 6200 | const elem_ty = ptr_ty.childType(mod); |
| 6108 | if (!elem_ty.hasRuntimeBitsIgnoreComptime(mod)) return o.lowerPtrToVoid(ptr_ty); | |
| 6201 | if (!elem_ty.hasRuntimeBitsIgnoreComptime(mod)) | |
| 6202 | return (try o.lowerPtrToVoid(ptr_ty)).toLlvm(&o.builder); | |
| 6109 | 6203 | |
| 6110 | 6204 | const base_ptr = try self.resolveInst(bin_op.lhs); |
| 6111 | 6205 | const rhs = try self.resolveInst(bin_op.rhs); |
| ... | ... | @@ -6116,7 +6210,10 @@ pub const FuncGen = struct { |
| 6116 | 6210 | const llvm_elem_ty = (try o.lowerPtrElemTy(elem_ty)).toLlvm(&o.builder); |
| 6117 | 6211 | if (ptr_ty.isSinglePointer(mod)) { |
| 6118 | 6212 | // If this is a single-item pointer to an array, we need another index in the GEP. |
| 6119 | const indices: [2]*llvm.Value = .{ Builder.Type.i32.toLlvm(&o.builder).constNull(), rhs }; | |
| 6213 | const indices: [2]*llvm.Value = .{ | |
| 6214 | (try o.builder.intConst(.i32, 0)).toLlvm(&o.builder), | |
| 6215 | rhs, | |
| 6216 | }; | |
| 6120 | 6217 | return self.builder.buildInBoundsGEP(llvm_elem_ty, base_ptr, &indices, indices.len, ""); |
| 6121 | 6218 | } else { |
| 6122 | 6219 | const indices: [1]*llvm.Value = .{rhs}; |
| ... | ... | @@ -6829,8 +6926,11 @@ pub const FuncGen = struct { |
| 6829 | 6926 | operand; |
| 6830 | 6927 | if (payload_ty.isSlice(mod)) { |
| 6831 | 6928 | const slice_ptr = self.builder.buildExtractValue(loaded, 0, ""); |
| 6832 | const ptr_ty = (try o.lowerType(payload_ty.slicePtrFieldType(mod))).toLlvm(&o.builder); | |
| 6833 | return self.builder.buildICmp(pred, slice_ptr, ptr_ty.constNull(), ""); | |
| 6929 | const ptr_ty = try o.builder.ptrType(toLlvmAddressSpace( | |
| 6930 | payload_ty.ptrAddressSpace(mod), | |
| 6931 | mod.getTarget(), | |
| 6932 | )); | |
| 6933 | return self.builder.buildICmp(pred, slice_ptr, (try o.builder.nullConst(ptr_ty)).toLlvm(&o.builder), ""); | |
| 6834 | 6934 | } |
| 6835 | 6935 | return self.builder.buildICmp(pred, loaded, optional_llvm_ty.constNull(), ""); |
| 6836 | 6936 | } |
| ... | ... | @@ -6867,8 +6967,7 @@ pub const FuncGen = struct { |
| 6867 | 6967 | const operand_ty = self.typeOf(un_op); |
| 6868 | 6968 | const err_union_ty = if (operand_is_ptr) operand_ty.childType(mod) else operand_ty; |
| 6869 | 6969 | const payload_ty = err_union_ty.errorUnionPayload(mod); |
| 6870 | const err_set_ty = (try o.lowerType(Type.anyerror)).toLlvm(&o.builder); | |
| 6871 | const zero = err_set_ty.constNull(); | |
| 6970 | const zero = (try o.builder.intConst(Builder.Type.err_int, 0)).toLlvm(&o.builder); | |
| 6872 | 6971 | |
| 6873 | 6972 | if (err_union_ty.errorUnionSet(mod).errorSetIsEmpty(mod)) { |
| 6874 | 6973 | const val: Builder.Constant = switch (op) { |
| ... | ... | @@ -6892,7 +6991,7 @@ pub const FuncGen = struct { |
| 6892 | 6991 | if (operand_is_ptr or isByRef(err_union_ty, mod)) { |
| 6893 | 6992 | const err_union_llvm_ty = (try o.lowerType(err_union_ty)).toLlvm(&o.builder); |
| 6894 | 6993 | const err_field_ptr = self.builder.buildStructGEP(err_union_llvm_ty, operand, err_field_index, ""); |
| 6895 | const loaded = self.builder.buildLoad(err_set_ty, err_field_ptr, ""); | |
| 6994 | const loaded = self.builder.buildLoad(Builder.Type.err_int.toLlvm(&o.builder), err_field_ptr, ""); | |
| 6896 | 6995 | return self.builder.buildICmp(op, loaded, zero, ""); |
| 6897 | 6996 | } |
| 6898 | 6997 | |
| ... | ... | @@ -7057,9 +7156,9 @@ pub const FuncGen = struct { |
| 7057 | 7156 | const err_union_ty = self.typeOf(ty_op.operand).childType(mod); |
| 7058 | 7157 | |
| 7059 | 7158 | const payload_ty = err_union_ty.errorUnionPayload(mod); |
| 7060 | const non_error_val = try o.lowerValue(.{ .ty = Type.anyerror, .val = try mod.intValue(Type.err_int, 0) }); | |
| 7159 | const non_error_val = try o.lowerValue((try mod.intValue(Type.err_int, 0)).toIntern()); | |
| 7061 | 7160 | if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) { |
| 7062 | _ = self.builder.buildStore(non_error_val, operand); | |
| 7161 | _ = self.builder.buildStore(non_error_val.toLlvm(&o.builder), operand); | |
| 7063 | 7162 | return operand; |
| 7064 | 7163 | } |
| 7065 | 7164 | const err_union_llvm_ty = (try o.lowerType(err_union_ty)).toLlvm(&o.builder); |
| ... | ... | @@ -7067,7 +7166,7 @@ pub const FuncGen = struct { |
| 7067 | 7166 | const error_offset = errUnionErrorOffset(payload_ty, mod); |
| 7068 | 7167 | // First set the non-error value. |
| 7069 | 7168 | const non_null_ptr = self.builder.buildStructGEP(err_union_llvm_ty, operand, error_offset, ""); |
| 7070 | const store_inst = self.builder.buildStore(non_error_val, non_null_ptr); | |
| 7169 | const store_inst = self.builder.buildStore(non_error_val.toLlvm(&o.builder), non_null_ptr); | |
| 7071 | 7170 | store_inst.setAlignment(Type.anyerror.abiAlignment(mod)); |
| 7072 | 7171 | } |
| 7073 | 7172 | // Then return the payload pointer (only if it is used). |
| ... | ... | @@ -7146,7 +7245,7 @@ pub const FuncGen = struct { |
| 7146 | 7245 | if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) { |
| 7147 | 7246 | return operand; |
| 7148 | 7247 | } |
| 7149 | const ok_err_code = (try o.lowerType(Type.anyerror)).toLlvm(&o.builder).constNull(); | |
| 7248 | const ok_err_code = (try o.builder.intConst(Builder.Type.err_int, 0)).toLlvm(&o.builder); | |
| 7150 | 7249 | const err_un_llvm_ty = (try o.lowerType(err_un_ty)).toLlvm(&o.builder); |
| 7151 | 7250 | |
| 7152 | 7251 | const payload_offset = errUnionPayloadOffset(payload_ty, mod); |
| ... | ... | @@ -7606,7 +7705,10 @@ pub const FuncGen = struct { |
| 7606 | 7705 | switch (ptr_ty.ptrSize(mod)) { |
| 7607 | 7706 | .One => { |
| 7608 | 7707 | // It's a pointer to an array, so according to LLVM we need an extra GEP index. |
| 7609 | const indices: [2]*llvm.Value = .{ Builder.Type.i32.toLlvm(&o.builder).constNull(), offset }; | |
| 7708 | const indices: [2]*llvm.Value = .{ | |
| 7709 | (try o.builder.intConst(.i32, 0)).toLlvm(&o.builder), | |
| 7710 | offset, | |
| 7711 | }; | |
| 7610 | 7712 | return self.builder.buildInBoundsGEP(llvm_elem_ty, ptr, &indices, indices.len, ""); |
| 7611 | 7713 | }, |
| 7612 | 7714 | .C, .Many => { |
| ... | ... | @@ -7635,7 +7737,8 @@ pub const FuncGen = struct { |
| 7635 | 7737 | .One => { |
| 7636 | 7738 | // It's a pointer to an array, so according to LLVM we need an extra GEP index. |
| 7637 | 7739 | const indices: [2]*llvm.Value = .{ |
| 7638 | Builder.Type.i32.toLlvm(&o.builder).constNull(), negative_offset, | |
| 7740 | (try o.builder.intConst(.i32, 0)).toLlvm(&o.builder), | |
| 7741 | negative_offset, | |
| 7639 | 7742 | }; |
| 7640 | 7743 | return self.builder.buildInBoundsGEP(llvm_elem_ty, ptr, &indices, indices.len, ""); |
| 7641 | 7744 | }, |
| ... | ... | @@ -8448,7 +8551,7 @@ pub const FuncGen = struct { |
| 8448 | 8551 | const ptr_ty = self.typeOfIndex(inst); |
| 8449 | 8552 | const pointee_type = ptr_ty.childType(mod); |
| 8450 | 8553 | if (!pointee_type.isFnOrHasRuntimeBitsIgnoreComptime(mod)) |
| 8451 | return o.lowerPtrToVoid(ptr_ty); | |
| 8554 | return (try o.lowerPtrToVoid(ptr_ty)).toLlvm(&o.builder); | |
| 8452 | 8555 | |
| 8453 | 8556 | const pointee_llvm_ty = (try o.lowerType(pointee_type)).toLlvm(&o.builder); |
| 8454 | 8557 | const alignment = ptr_ty.ptrAlignment(mod); |
| ... | ... | @@ -8460,7 +8563,8 @@ pub const FuncGen = struct { |
| 8460 | 8563 | const mod = o.module; |
| 8461 | 8564 | const ptr_ty = self.typeOfIndex(inst); |
| 8462 | 8565 | const ret_ty = ptr_ty.childType(mod); |
| 8463 | if (!ret_ty.isFnOrHasRuntimeBitsIgnoreComptime(mod)) return o.lowerPtrToVoid(ptr_ty); | |
| 8566 | if (!ret_ty.isFnOrHasRuntimeBitsIgnoreComptime(mod)) | |
| 8567 | return (try o.lowerPtrToVoid(ptr_ty)).toLlvm(&o.builder); | |
| 8464 | 8568 | if (self.ret_ptr) |ret_ptr| return ret_ptr; |
| 8465 | 8569 | const ret_llvm_ty = (try o.lowerType(ret_ty)).toLlvm(&o.builder); |
| 8466 | 8570 | return self.buildAlloca(ret_llvm_ty, ptr_ty.ptrAlignment(mod)); |
| ... | ... | @@ -8566,18 +8670,19 @@ pub const FuncGen = struct { |
| 8566 | 8670 | _ = inst; |
| 8567 | 8671 | const o = self.dg.object; |
| 8568 | 8672 | const mod = o.module; |
| 8569 | const llvm_usize = (try o.lowerType(Type.usize)).toLlvm(&o.builder); | |
| 8673 | const llvm_usize = try o.lowerType(Type.usize); | |
| 8570 | 8674 | const target = mod.getTarget(); |
| 8571 | 8675 | if (!target_util.supportsReturnAddress(target)) { |
| 8572 | 8676 | // https://github.com/ziglang/zig/issues/11946 |
| 8573 | return llvm_usize.constNull(); | |
| 8677 | return (try o.builder.intConst(llvm_usize, 0)).toLlvm(&o.builder); | |
| 8574 | 8678 | } |
| 8575 | 8679 | |
| 8576 | const llvm_i32 = Builder.Type.i32.toLlvm(&o.builder); | |
| 8577 | 8680 | const llvm_fn = try self.getIntrinsic("llvm.returnaddress", &.{}); |
| 8578 | const params = [_]*llvm.Value{llvm_i32.constNull()}; | |
| 8681 | const params = [_]*llvm.Value{ | |
| 8682 | (try o.builder.intConst(.i32, 0)).toLlvm(&o.builder), | |
| 8683 | }; | |
| 8579 | 8684 | const ptr_val = self.builder.buildCall(llvm_fn.globalGetValueType(), llvm_fn, &params, params.len, .Fast, .Auto, ""); |
| 8580 | return self.builder.buildPtrToInt(ptr_val, llvm_usize, ""); | |
| 8685 | return self.builder.buildPtrToInt(ptr_val, llvm_usize.toLlvm(&o.builder), ""); | |
| 8581 | 8686 | } |
| 8582 | 8687 | |
| 8583 | 8688 | fn airFrameAddress(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { |
| ... | ... | @@ -8589,7 +8694,9 @@ pub const FuncGen = struct { |
| 8589 | 8694 | break :blk o.llvm_module.addFunction(llvm_fn_name, fn_type.toLlvm(&o.builder)); |
| 8590 | 8695 | }; |
| 8591 | 8696 | |
| 8592 | const params = [_]*llvm.Value{Builder.Type.i32.toLlvm(&o.builder).constNull()}; | |
| 8697 | const params = [_]*llvm.Value{ | |
| 8698 | (try o.builder.intConst(.i32, 0)).toLlvm(&o.builder), | |
| 8699 | }; | |
| 8593 | 8700 | const ptr_val = self.builder.buildCall(llvm_fn.globalGetValueType(), llvm_fn, &params, params.len, .Fast, .Auto, ""); |
| 8594 | 8701 | const llvm_usize = (try o.lowerType(Type.usize)).toLlvm(&o.builder); |
| 8595 | 8702 | return self.builder.buildPtrToInt(ptr_val, llvm_usize, ""); |
| ... | ... | @@ -9060,10 +9167,9 @@ pub const FuncGen = struct { |
| 9060 | 9167 | const operand_ty = self.typeOf(ty_op.operand); |
| 9061 | 9168 | const operand = try self.resolveInst(ty_op.operand); |
| 9062 | 9169 | |
| 9063 | const llvm_i1 = Builder.Type.i1.toLlvm(&o.builder); | |
| 9064 | 9170 | const fn_val = try self.getIntrinsic(llvm_fn_name, &.{try o.lowerType(operand_ty)}); |
| 9065 | 9171 | |
| 9066 | const params = [_]*llvm.Value{ operand, llvm_i1.constNull() }; | |
| 9172 | const params = [_]*llvm.Value{ operand, Builder.Constant.false.toLlvm(&o.builder) }; | |
| 9067 | 9173 | const wrong_size_result = self.builder.buildCall(fn_val.globalGetValueType(), fn_val, &params, params.len, .C, .Auto, ""); |
| 9068 | 9174 | const result_ty = self.typeOfIndex(inst); |
| 9069 | 9175 | const result_llvm_ty = (try o.lowerType(result_ty)).toLlvm(&o.builder); |
| ... | ... | @@ -9170,11 +9276,9 @@ pub const FuncGen = struct { |
| 9170 | 9276 | |
| 9171 | 9277 | for (names) |name| { |
| 9172 | 9278 | const err_int = @as(Module.ErrorInt, @intCast(mod.global_error_set.getIndex(name).?)); |
| 9173 | const this_tag_int_value = try o.lowerValue(.{ | |
| 9174 | .ty = Type.err_int, | |
| 9175 | .val = try mod.intValue(Type.err_int, err_int), | |
| 9176 | }); | |
| 9177 | switch_instr.addCase(this_tag_int_value, valid_block); | |
| 9279 | const this_tag_int_value = | |
| 9280 | try o.lowerValue((try mod.intValue(Type.err_int, err_int)).toIntern()); | |
| 9281 | switch_instr.addCase(this_tag_int_value.toLlvm(&o.builder), valid_block); | |
| 9178 | 9282 | } |
| 9179 | 9283 | self.builder.positionBuilderAtEnd(valid_block); |
| 9180 | 9284 | _ = self.builder.buildBr(end_block); |
| ... | ... | @@ -9258,13 +9362,9 @@ pub const FuncGen = struct { |
| 9258 | 9362 | |
| 9259 | 9363 | for (enum_type.names, 0..) |_, field_index_usize| { |
| 9260 | 9364 | const field_index = @as(u32, @intCast(field_index_usize)); |
| 9261 | const this_tag_int_value = int: { | |
| 9262 | break :int try o.lowerValue(.{ | |
| 9263 | .ty = enum_ty, | |
| 9264 | .val = try mod.enumValueFieldIndex(enum_ty, field_index), | |
| 9265 | }); | |
| 9266 | }; | |
| 9267 | switch_instr.addCase(this_tag_int_value, named_block); | |
| 9365 | const this_tag_int_value = | |
| 9366 | try o.lowerValue((try mod.enumValueFieldIndex(enum_ty, field_index)).toIntern()); | |
| 9367 | switch_instr.addCase(this_tag_int_value.toLlvm(&o.builder), named_block); | |
| 9268 | 9368 | } |
| 9269 | 9369 | self.builder.positionBuilderAtEnd(named_block); |
| 9270 | 9370 | _ = self.builder.buildRet(Builder.Constant.true.toLlvm(&o.builder)); |
| ... | ... | @@ -9371,11 +9471,9 @@ pub const FuncGen = struct { |
| 9371 | 9471 | slice_global.setAlignment(slice_alignment); |
| 9372 | 9472 | |
| 9373 | 9473 | const return_block = self.context.appendBasicBlock(fn_val, "Name"); |
| 9374 | const this_tag_int_value = try o.lowerValue(.{ | |
| 9375 | .ty = enum_ty, | |
| 9376 | .val = try mod.enumValueFieldIndex(enum_ty, field_index), | |
| 9377 | }); | |
| 9378 | switch_instr.addCase(this_tag_int_value, return_block); | |
| 9474 | const this_tag_int_value = | |
| 9475 | try o.lowerValue((try mod.enumValueFieldIndex(enum_ty, field_index)).toIntern()); | |
| 9476 | switch_instr.addCase(this_tag_int_value.toLlvm(&o.builder), return_block); | |
| 9379 | 9477 | |
| 9380 | 9478 | self.builder.positionBuilderAtEnd(return_block); |
| 9381 | 9479 | const loaded = self.builder.buildLoad(llvm_ret_ty, slice_global, ""); |
| ... | ... | @@ -9404,7 +9502,12 @@ pub const FuncGen = struct { |
| 9404 | 9502 | const fn_type = try o.builder.fnType(.i1, &.{Builder.Type.err_int}, .normal); |
| 9405 | 9503 | const llvm_fn = o.llvm_module.addFunction(lt_errors_fn_name, fn_type.toLlvm(&o.builder)); |
| 9406 | 9504 | |
| 9505 | llvm_fn.setLinkage(.Internal); | |
| 9506 | llvm_fn.setFunctionCallConv(.Fast); | |
| 9507 | o.addCommonFnAttributes(llvm_fn); | |
| 9508 | ||
| 9407 | 9509 | var global = Builder.Global{ |
| 9510 | .linkage = .internal, | |
| 9408 | 9511 | .type = fn_type, |
| 9409 | 9512 | .kind = .{ .function = @enumFromInt(o.builder.functions.items.len) }, |
| 9410 | 9513 | }; |
| ... | ... | @@ -9412,10 +9515,6 @@ pub const FuncGen = struct { |
| 9412 | 9515 | .global = @enumFromInt(o.builder.globals.count()), |
| 9413 | 9516 | }; |
| 9414 | 9517 | |
| 9415 | llvm_fn.setLinkage(.Internal); | |
| 9416 | llvm_fn.setFunctionCallConv(.Fast); | |
| 9417 | o.addCommonFnAttributes(llvm_fn); | |
| 9418 | ||
| 9419 | 9518 | try o.builder.llvm_globals.append(self.gpa, llvm_fn); |
| 9420 | 9519 | _ = try o.builder.addGlobal(try o.builder.string(lt_errors_fn_name), global); |
| 9421 | 9520 | try o.builder.functions.append(self.gpa, function); |
| ... | ... | @@ -9431,7 +9530,7 @@ pub const FuncGen = struct { |
| 9431 | 9530 | |
| 9432 | 9531 | const error_name_table_ptr = try self.getErrorNameTable(); |
| 9433 | 9532 | const ptr_slice_llvm_ty = self.context.pointerType(0); |
| 9434 | const error_name_table = self.builder.buildLoad(ptr_slice_llvm_ty, error_name_table_ptr, ""); | |
| 9533 | const error_name_table = self.builder.buildLoad(ptr_slice_llvm_ty, error_name_table_ptr.toLlvm(&o.builder), ""); | |
| 9435 | 9534 | const indices = [_]*llvm.Value{operand}; |
| 9436 | 9535 | const error_name_ptr = self.builder.buildInBoundsGEP(slice_llvm_ty, error_name_table, &indices, indices.len, ""); |
| 9437 | 9536 | return self.builder.buildLoad(slice_llvm_ty, error_name_ptr, ""); |
| ... | ... | @@ -9588,18 +9687,18 @@ pub const FuncGen = struct { |
| 9588 | 9687 | .Add => switch (scalar_ty.zigTypeTag(mod)) { |
| 9589 | 9688 | .Int => return self.builder.buildAddReduce(operand), |
| 9590 | 9689 | .Float => if (intrinsicsAllowed(scalar_ty, target)) { |
| 9591 | const scalar_llvm_ty = (try o.lowerType(scalar_ty)).toLlvm(&o.builder); | |
| 9592 | const neutral_value = scalar_llvm_ty.constReal(-0.0); | |
| 9593 | return self.builder.buildFPAddReduce(neutral_value, operand); | |
| 9690 | const scalar_llvm_ty = try o.lowerType(scalar_ty); | |
| 9691 | const neutral_value = try o.builder.fpConst(scalar_llvm_ty, -0.0); | |
| 9692 | return self.builder.buildFPAddReduce(neutral_value.toLlvm(&o.builder), operand); | |
| 9594 | 9693 | }, |
| 9595 | 9694 | else => unreachable, |
| 9596 | 9695 | }, |
| 9597 | 9696 | .Mul => switch (scalar_ty.zigTypeTag(mod)) { |
| 9598 | 9697 | .Int => return self.builder.buildMulReduce(operand), |
| 9599 | 9698 | .Float => if (intrinsicsAllowed(scalar_ty, target)) { |
| 9600 | const scalar_llvm_ty = (try o.lowerType(scalar_ty)).toLlvm(&o.builder); | |
| 9601 | const neutral_value = scalar_llvm_ty.constReal(1.0); | |
| 9602 | return self.builder.buildFPMulReduce(neutral_value, operand); | |
| 9699 | const scalar_llvm_ty = try o.lowerType(scalar_ty); | |
| 9700 | const neutral_value = try o.builder.fpConst(scalar_llvm_ty, 1.0); | |
| 9701 | return self.builder.buildFPMulReduce(neutral_value.toLlvm(&o.builder), operand); | |
| 9603 | 9702 | }, |
| 9604 | 9703 | else => unreachable, |
| 9605 | 9704 | }, |
| ... | ... | @@ -9626,17 +9725,14 @@ pub const FuncGen = struct { |
| 9626 | 9725 | |
| 9627 | 9726 | const param_llvm_ty = try o.lowerType(scalar_ty); |
| 9628 | 9727 | const libc_fn = try self.getLibcFunction(fn_name, &(.{param_llvm_ty} ** 2), param_llvm_ty); |
| 9629 | const init_value = try o.lowerValue(.{ | |
| 9630 | .ty = scalar_ty, | |
| 9631 | .val = try mod.floatValue(scalar_ty, switch (reduce.operation) { | |
| 9632 | .Min => std.math.nan(f32), | |
| 9633 | .Max => std.math.nan(f32), | |
| 9634 | .Add => -0.0, | |
| 9635 | .Mul => 1.0, | |
| 9636 | else => unreachable, | |
| 9637 | }), | |
| 9638 | }); | |
| 9639 | return self.buildReducedCall(libc_fn, operand, operand_ty.vectorLen(mod), init_value); | |
| 9728 | const init_value = try o.lowerValue((try mod.floatValue(scalar_ty, switch (reduce.operation) { | |
| 9729 | .Min => std.math.nan(f32), | |
| 9730 | .Max => std.math.nan(f32), | |
| 9731 | .Add => -0.0, | |
| 9732 | .Mul => 1.0, | |
| 9733 | else => unreachable, | |
| 9734 | })).toIntern()); | |
| 9735 | return self.buildReducedCall(libc_fn, operand, operand_ty.vectorLen(mod), init_value.toLlvm(&o.builder)); | |
| 9640 | 9736 | } |
| 9641 | 9737 | |
| 9642 | 9738 | fn airAggregateInit(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { |
| ... | ... | @@ -10030,26 +10126,42 @@ pub const FuncGen = struct { |
| 10030 | 10126 | return self.amdgcnWorkIntrinsic(dimension, 0, "llvm.amdgcn.workgroup.id"); |
| 10031 | 10127 | } |
| 10032 | 10128 | |
| 10033 | fn getErrorNameTable(self: *FuncGen) !*llvm.Value { | |
| 10129 | fn getErrorNameTable(self: *FuncGen) Allocator.Error!Builder.Variable.Index { | |
| 10034 | 10130 | const o = self.dg.object; |
| 10035 | if (o.error_name_table) |table| { | |
| 10036 | return table; | |
| 10037 | } | |
| 10131 | const table = o.error_name_table; | |
| 10132 | if (table != .none) return table; | |
| 10038 | 10133 | |
| 10039 | 10134 | const mod = o.module; |
| 10040 | 10135 | const slice_ty = Type.slice_const_u8_sentinel_0; |
| 10041 | 10136 | const slice_alignment = slice_ty.abiAlignment(mod); |
| 10042 | const llvm_slice_ptr_ty = self.context.pointerType(0); // TODO: Address space | |
| 10137 | const undef_init = try o.builder.undefConst(.ptr); // TODO: Address space | |
| 10043 | 10138 | |
| 10044 | const error_name_table_global = o.llvm_module.addGlobal(llvm_slice_ptr_ty, "__zig_err_name_table"); | |
| 10045 | error_name_table_global.setInitializer(llvm_slice_ptr_ty.getUndef()); | |
| 10139 | const name = try o.builder.string("__zig_err_name_table"); | |
| 10140 | const error_name_table_global = o.llvm_module.addGlobal(Builder.Type.ptr.toLlvm(&o.builder), name.toSlice(&o.builder).?); | |
| 10141 | error_name_table_global.setInitializer(undef_init.toLlvm(&o.builder)); | |
| 10046 | 10142 | error_name_table_global.setLinkage(.Private); |
| 10047 | 10143 | error_name_table_global.setGlobalConstant(.True); |
| 10048 | 10144 | error_name_table_global.setUnnamedAddr(.True); |
| 10049 | 10145 | error_name_table_global.setAlignment(slice_alignment); |
| 10050 | 10146 | |
| 10051 | o.error_name_table = error_name_table_global; | |
| 10052 | return error_name_table_global; | |
| 10147 | var global = Builder.Global{ | |
| 10148 | .linkage = .private, | |
| 10149 | .unnamed_addr = .unnamed_addr, | |
| 10150 | .type = .ptr, | |
| 10151 | .alignment = Builder.Alignment.fromByteUnits(slice_alignment), | |
| 10152 | .kind = .{ .variable = @enumFromInt(o.builder.variables.items.len) }, | |
| 10153 | }; | |
| 10154 | var variable = Builder.Variable{ | |
| 10155 | .global = @enumFromInt(o.builder.globals.count()), | |
| 10156 | .mutability = .constant, | |
| 10157 | .init = undef_init, | |
| 10158 | }; | |
| 10159 | try o.builder.llvm_globals.append(o.gpa, error_name_table_global); | |
| 10160 | _ = try o.builder.addGlobal(name, global); | |
| 10161 | try o.builder.variables.append(o.gpa, variable); | |
| 10162 | ||
| 10163 | o.error_name_table = global.kind.variable; | |
| 10164 | return global.kind.variable; | |
| 10053 | 10165 | } |
| 10054 | 10166 | |
| 10055 | 10167 | /// Assumes the optional is not pointer-like and payload has bits. |
| ... | ... | @@ -10273,14 +10385,14 @@ pub const FuncGen = struct { |
| 10273 | 10385 | return llvm_inst; |
| 10274 | 10386 | } |
| 10275 | 10387 | |
| 10276 | const int_elem_ty = (try o.builder.intType(@intCast(info.packed_offset.host_size * 8))).toLlvm(&o.builder); | |
| 10277 | const containing_int = self.builder.buildLoad(int_elem_ty, ptr, ""); | |
| 10388 | const containing_int_ty = try o.builder.intType(@intCast(info.packed_offset.host_size * 8)); | |
| 10389 | const containing_int = self.builder.buildLoad(containing_int_ty.toLlvm(&o.builder), ptr, ""); | |
| 10278 | 10390 | containing_int.setAlignment(ptr_alignment); |
| 10279 | 10391 | containing_int.setVolatile(ptr_volatile); |
| 10280 | 10392 | |
| 10281 | 10393 | const elem_bits = @as(c_uint, @intCast(ptr_ty.childType(mod).bitSize(mod))); |
| 10282 | const shift_amt = containing_int.typeOf().constInt(info.packed_offset.bit_offset, .False); | |
| 10283 | const shifted_value = self.builder.buildLShr(containing_int, shift_amt, ""); | |
| 10394 | const shift_amt = try o.builder.intConst(containing_int_ty, info.packed_offset.bit_offset); | |
| 10395 | const shifted_value = self.builder.buildLShr(containing_int, shift_amt.toLlvm(&o.builder), ""); | |
| 10284 | 10396 | const elem_llvm_ty = (try o.lowerType(elem_ty)).toLlvm(&o.builder); |
| 10285 | 10397 | |
| 10286 | 10398 | if (isByRef(elem_ty, mod)) { |
| ... | ... | @@ -10346,30 +10458,29 @@ pub const FuncGen = struct { |
| 10346 | 10458 | } |
| 10347 | 10459 | |
| 10348 | 10460 | if (info.packed_offset.host_size != 0) { |
| 10349 | const int_elem_ty = (try o.builder.intType(@intCast(info.packed_offset.host_size * 8))).toLlvm(&o.builder); | |
| 10350 | const containing_int = self.builder.buildLoad(int_elem_ty, ptr, ""); | |
| 10461 | const containing_int_ty = try o.builder.intType(@intCast(info.packed_offset.host_size * 8)); | |
| 10462 | const containing_int = self.builder.buildLoad(containing_int_ty.toLlvm(&o.builder), ptr, ""); | |
| 10351 | 10463 | assert(ordering == .NotAtomic); |
| 10352 | 10464 | containing_int.setAlignment(ptr_alignment); |
| 10353 | 10465 | containing_int.setVolatile(ptr_volatile); |
| 10354 | 10466 | const elem_bits = @as(c_uint, @intCast(ptr_ty.childType(mod).bitSize(mod))); |
| 10355 | const containing_int_ty = containing_int.typeOf(); | |
| 10356 | const shift_amt = containing_int_ty.constInt(info.packed_offset.bit_offset, .False); | |
| 10467 | const shift_amt = try o.builder.intConst(containing_int_ty, info.packed_offset.bit_offset); | |
| 10357 | 10468 | // Convert to equally-sized integer type in order to perform the bit |
| 10358 | 10469 | // operations on the value to store |
| 10359 | const value_bits_type = (try o.builder.intType(@intCast(elem_bits))).toLlvm(&o.builder); | |
| 10470 | const value_bits_type = try o.builder.intType(@intCast(elem_bits)); | |
| 10360 | 10471 | const value_bits = if (elem_ty.isPtrAtRuntime(mod)) |
| 10361 | self.builder.buildPtrToInt(elem, value_bits_type, "") | |
| 10472 | self.builder.buildPtrToInt(elem, value_bits_type.toLlvm(&o.builder), "") | |
| 10362 | 10473 | else |
| 10363 | self.builder.buildBitCast(elem, value_bits_type, ""); | |
| 10474 | self.builder.buildBitCast(elem, value_bits_type.toLlvm(&o.builder), ""); | |
| 10364 | 10475 | |
| 10365 | var mask_val = value_bits_type.constAllOnes(); | |
| 10366 | mask_val = mask_val.constZExt(containing_int_ty); | |
| 10367 | mask_val = mask_val.constShl(shift_amt); | |
| 10476 | var mask_val = (try o.builder.intConst(value_bits_type, -1)).toLlvm(&o.builder); | |
| 10477 | mask_val = mask_val.constZExt(containing_int_ty.toLlvm(&o.builder)); | |
| 10478 | mask_val = mask_val.constShl(shift_amt.toLlvm(&o.builder)); | |
| 10368 | 10479 | mask_val = mask_val.constNot(); |
| 10369 | 10480 | |
| 10370 | 10481 | const anded_containing_int = self.builder.buildAnd(containing_int, mask_val, ""); |
| 10371 | const extended_value = self.builder.buildZExt(value_bits, containing_int_ty, ""); | |
| 10372 | const shifted_value = self.builder.buildShl(extended_value, shift_amt, ""); | |
| 10482 | const extended_value = self.builder.buildZExt(value_bits, containing_int_ty.toLlvm(&o.builder), ""); | |
| 10483 | const shifted_value = self.builder.buildShl(extended_value, shift_amt.toLlvm(&o.builder), ""); | |
| 10373 | 10484 | const ored_value = self.builder.buildOr(shifted_value, anded_containing_int, ""); |
| 10374 | 10485 | |
| 10375 | 10486 | const store_inst = self.builder.buildStore(ored_value, ptr); |
src/codegen/llvm/Builder.zig+1865-176| ... | ... | @@ -27,7 +27,7 @@ globals: std.AutoArrayHashMapUnmanaged(String, Global) = .{}, |
| 27 | 27 | next_unnamed_global: String = @enumFromInt(0), |
| 28 | 28 | next_unique_global_id: std.AutoHashMapUnmanaged(String, u32) = .{}, |
| 29 | 29 | aliases: std.ArrayListUnmanaged(Alias) = .{}, |
| 30 | objects: std.ArrayListUnmanaged(Object) = .{}, | |
| 30 | variables: std.ArrayListUnmanaged(Variable) = .{}, | |
| 31 | 31 | functions: std.ArrayListUnmanaged(Function) = .{}, |
| 32 | 32 | |
| 33 | 33 | constant_map: std.AutoArrayHashMapUnmanaged(void, void) = .{}, |
| ... | ... | @@ -35,10 +35,12 @@ constant_items: std.MultiArrayList(Constant.Item) = .{}, |
| 35 | 35 | constant_extra: std.ArrayListUnmanaged(u32) = .{}, |
| 36 | 36 | constant_limbs: std.ArrayListUnmanaged(std.math.big.Limb) = .{}, |
| 37 | 37 | |
| 38 | pub const expected_fields_len = 32; | |
| 39 | pub const expected_gep_indices_len = 8; | |
| 40 | ||
| 38 | 41 | pub const String = enum(u32) { |
| 39 | 42 | none = std.math.maxInt(u31), |
| 40 | 43 | empty, |
| 41 | debugme, | |
| 42 | 44 | _, |
| 43 | 45 | |
| 44 | 46 | pub fn toSlice(self: String, b: *const Builder) ?[:0]const u8 { |
| ... | ... | @@ -58,22 +60,23 @@ pub const String = enum(u32) { |
| 58 | 60 | _: std.fmt.FormatOptions, |
| 59 | 61 | writer: anytype, |
| 60 | 62 | ) @TypeOf(writer).Error!void { |
| 63 | if (comptime std.mem.indexOfNone(u8, fmt_str, "@\"")) |_| | |
| 64 | @compileError("invalid format string: '" ++ fmt_str ++ "'"); | |
| 61 | 65 | assert(data.string != .none); |
| 62 | 66 | const slice = data.string.toSlice(data.builder) orelse |
| 63 | 67 | return writer.print("{d}", .{@intFromEnum(data.string)}); |
| 64 | const need_quotes = if (comptime std.mem.eql(u8, fmt_str, "")) | |
| 65 | !isValidIdentifier(slice) | |
| 66 | else if (comptime std.mem.eql(u8, fmt_str, "\"")) | |
| 67 | true | |
| 68 | else | |
| 69 | @compileError("invalid format string: '" ++ fmt_str ++ "'"); | |
| 70 | if (need_quotes) try writer.writeByte('\"'); | |
| 71 | for (slice) |character| switch (character) { | |
| 68 | const full_slice = slice[0 .. slice.len + comptime @intFromBool( | |
| 69 | std.mem.indexOfScalar(u8, fmt_str, '@') != null, | |
| 70 | )]; | |
| 71 | const need_quotes = (comptime std.mem.indexOfScalar(u8, fmt_str, '"') != null) or | |
| 72 | !isValidIdentifier(full_slice); | |
| 73 | if (need_quotes) try writer.writeByte('"'); | |
| 74 | for (full_slice) |character| switch (character) { | |
| 72 | 75 | '\\' => try writer.writeAll("\\\\"), |
| 73 | 76 | ' '...'"' - 1, '"' + 1...'\\' - 1, '\\' + 1...'~' => try writer.writeByte(character), |
| 74 | 77 | else => try writer.print("\\{X:0>2}", .{character}), |
| 75 | 78 | }; |
| 76 | if (need_quotes) try writer.writeByte('\"'); | |
| 79 | if (need_quotes) try writer.writeByte('"'); | |
| 77 | 80 | } |
| 78 | 81 | pub fn fmt(self: String, builder: *const Builder) std.fmt.Formatter(format) { |
| 79 | 82 | return .{ .data = .{ .string = self, .builder = builder } }; |
| ... | ... | @@ -92,8 +95,8 @@ pub const String = enum(u32) { |
| 92 | 95 | pub fn hash(_: Adapter, key: []const u8) u32 { |
| 93 | 96 | return @truncate(std.hash.Wyhash.hash(0, key)); |
| 94 | 97 | } |
| 95 | pub fn eql(ctx: Adapter, lhs: []const u8, _: void, rhs_index: usize) bool { | |
| 96 | return std.mem.eql(u8, lhs, String.fromIndex(rhs_index).toSlice(ctx.builder).?); | |
| 98 | pub fn eql(ctx: Adapter, lhs_key: []const u8, _: void, rhs_index: usize) bool { | |
| 99 | return std.mem.eql(u8, lhs_key, String.fromIndex(rhs_index).toSlice(ctx.builder).?); | |
| 97 | 100 | } |
| 98 | 101 | }; |
| 99 | 102 | }; |
| ... | ... | @@ -204,9 +207,167 @@ pub const Type = enum(u32) { |
| 204 | 207 | pub const Item = packed struct(u32) { |
| 205 | 208 | tag: Tag, |
| 206 | 209 | data: ExtraIndex, |
| 210 | ||
| 211 | pub const ExtraIndex = u28; | |
| 207 | 212 | }; |
| 208 | 213 | |
| 209 | pub const ExtraIndex = u28; | |
| 214 | pub fn tag(self: Type, builder: *const Builder) Tag { | |
| 215 | return builder.type_items.items[@intFromEnum(self)].tag; | |
| 216 | } | |
| 217 | ||
| 218 | pub fn unnamedTag(self: Type, builder: *const Builder) Tag { | |
| 219 | const item = builder.type_items.items[@intFromEnum(self)]; | |
| 220 | return switch (item.tag) { | |
| 221 | .named_structure => builder.typeExtraData(Type.NamedStructure, item.data).body | |
| 222 | .unnamedTag(builder), | |
| 223 | else => item.tag, | |
| 224 | }; | |
| 225 | } | |
| 226 | ||
| 227 | pub fn scalarTag(self: Type, builder: *const Builder) Tag { | |
| 228 | const item = builder.type_items.items[@intFromEnum(self)]; | |
| 229 | return switch (item.tag) { | |
| 230 | .vector, .scalable_vector => builder.typeExtraData(Type.Vector, item.data) | |
| 231 | .child.tag(builder), | |
| 232 | else => item.tag, | |
| 233 | }; | |
| 234 | } | |
| 235 | ||
| 236 | pub fn isFn(self: Type, builder: *const Builder) bool { | |
| 237 | return switch (self.tag(builder)) { | |
| 238 | .function, .vararg_function => true, | |
| 239 | else => false, | |
| 240 | }; | |
| 241 | } | |
| 242 | ||
| 243 | pub fn fnKind(self: Type, builder: *const Builder) Type.Function.Kind { | |
| 244 | return switch (self.tag(builder)) { | |
| 245 | .function => .normal, | |
| 246 | .vararg_function => .vararg, | |
| 247 | else => unreachable, | |
| 248 | }; | |
| 249 | } | |
| 250 | ||
| 251 | pub fn isVector(self: Type, builder: *const Builder) bool { | |
| 252 | return switch (self.tag(builder)) { | |
| 253 | .vector, .scalable_vector => true, | |
| 254 | else => false, | |
| 255 | }; | |
| 256 | } | |
| 257 | ||
| 258 | pub fn vectorKind(self: Type, builder: *const Builder) Type.Vector.Kind { | |
| 259 | return switch (self.tag(builder)) { | |
| 260 | .vector => .normal, | |
| 261 | .scalable_vector => .scalable, | |
| 262 | else => unreachable, | |
| 263 | }; | |
| 264 | } | |
| 265 | ||
| 266 | pub fn isStruct(self: Type, builder: *const Builder) bool { | |
| 267 | return switch (self.tag(builder)) { | |
| 268 | .structure, .packed_structure, .named_structure => true, | |
| 269 | else => false, | |
| 270 | }; | |
| 271 | } | |
| 272 | ||
| 273 | pub fn structKind(self: Type, builder: *const Builder) Type.Structure.Kind { | |
| 274 | return switch (self.unnamedTag(builder)) { | |
| 275 | .structure => .normal, | |
| 276 | .packed_structure => .@"packed", | |
| 277 | else => unreachable, | |
| 278 | }; | |
| 279 | } | |
| 280 | ||
| 281 | pub fn scalarBits(self: Type, builder: *const Builder) u24 { | |
| 282 | return switch (self) { | |
| 283 | .void, .label, .token, .metadata, .none, .x86_amx => unreachable, | |
| 284 | .i1 => 1, | |
| 285 | .i8 => 8, | |
| 286 | .half, .bfloat, .i16 => 16, | |
| 287 | .i29 => 29, | |
| 288 | .float, .i32 => 32, | |
| 289 | .double, .i64, .x86_mmx => 64, | |
| 290 | .x86_fp80, .i80 => 80, | |
| 291 | .fp128, .ppc_fp128, .i128 => 128, | |
| 292 | .ptr => @panic("TODO: query data layout"), | |
| 293 | _ => { | |
| 294 | const item = builder.type_items.items[@intFromEnum(self)]; | |
| 295 | return switch (item.tag) { | |
| 296 | .simple, | |
| 297 | .function, | |
| 298 | .vararg_function, | |
| 299 | => unreachable, | |
| 300 | .integer => @intCast(item.data), | |
| 301 | .pointer => @panic("TODO: query data layout"), | |
| 302 | .target => unreachable, | |
| 303 | .vector, | |
| 304 | .scalable_vector, | |
| 305 | => builder.typeExtraData(Type.Vector, item.data).child.scalarBits(builder), | |
| 306 | .small_array, | |
| 307 | .array, | |
| 308 | .structure, | |
| 309 | .packed_structure, | |
| 310 | .named_structure, | |
| 311 | => unreachable, | |
| 312 | }; | |
| 313 | }, | |
| 314 | }; | |
| 315 | } | |
| 316 | ||
| 317 | pub fn childType(self: Type, builder: *const Builder) Type { | |
| 318 | const item = builder.type_items.items[@intFromEnum(self)]; | |
| 319 | return switch (item.tag) { | |
| 320 | .vector, | |
| 321 | .scalable_vector, | |
| 322 | .small_array, | |
| 323 | => builder.typeExtraData(Type.Vector, item.data).child, | |
| 324 | .array => builder.typeExtraData(Type.Array, item.data).child, | |
| 325 | .named_structure => builder.typeExtraData(Type.NamedStructure, item.data).body, | |
| 326 | else => unreachable, | |
| 327 | }; | |
| 328 | } | |
| 329 | ||
| 330 | pub fn vectorLen(self: Type, builder: *const Builder) u32 { | |
| 331 | const item = builder.type_items.items[@intFromEnum(self)]; | |
| 332 | return switch (item.tag) { | |
| 333 | .vector, | |
| 334 | .scalable_vector, | |
| 335 | => builder.typeExtraData(Type.Vector, item.data).len, | |
| 336 | else => unreachable, | |
| 337 | }; | |
| 338 | } | |
| 339 | ||
| 340 | pub fn aggregateLen(self: Type, builder: *const Builder) u64 { | |
| 341 | const item = builder.type_items.items[@intFromEnum(self)]; | |
| 342 | return switch (item.tag) { | |
| 343 | .vector, | |
| 344 | .scalable_vector, | |
| 345 | .small_array, | |
| 346 | => builder.typeExtraData(Type.Vector, item.data).len, | |
| 347 | .array => builder.typeExtraData(Type.Array, item.data).len(), | |
| 348 | .structure, | |
| 349 | .packed_structure, | |
| 350 | => builder.typeExtraData(Type.Structure, item.data).fields_len, | |
| 351 | .named_structure => builder.typeExtraData(Type.NamedStructure, item.data).body | |
| 352 | .aggregateLen(builder), | |
| 353 | else => unreachable, | |
| 354 | }; | |
| 355 | } | |
| 356 | ||
| 357 | pub fn structFields(self: Type, builder: *const Builder) []const Type { | |
| 358 | const item = builder.type_items.items[@intFromEnum(self)]; | |
| 359 | switch (item.tag) { | |
| 360 | .structure, | |
| 361 | .packed_structure, | |
| 362 | => { | |
| 363 | const extra = builder.typeExtraDataTrail(Type.Structure, item.data); | |
| 364 | return @ptrCast(builder.type_extra.items[extra.end..][0..extra.data.fields_len]); | |
| 365 | }, | |
| 366 | .named_structure => return builder.typeExtraData(Type.NamedStructure, item.data).body | |
| 367 | .structFields(builder), | |
| 368 | else => unreachable, | |
| 369 | } | |
| 370 | } | |
| 210 | 371 | |
| 211 | 372 | pub const FormatData = struct { |
| 212 | 373 | type: Type, |
| ... | ... | @@ -220,11 +381,11 @@ pub const Type = enum(u32) { |
| 220 | 381 | ) @TypeOf(writer).Error!void { |
| 221 | 382 | assert(data.type != .none); |
| 222 | 383 | if (std.enums.tagName(Type, data.type)) |name| return writer.writeAll(name); |
| 223 | const type_item = data.builder.type_items.items[@intFromEnum(data.type)]; | |
| 224 | switch (type_item.tag) { | |
| 384 | const item = data.builder.type_items.items[@intFromEnum(data.type)]; | |
| 385 | switch (item.tag) { | |
| 225 | 386 | .simple => unreachable, |
| 226 | 387 | .function, .vararg_function => { |
| 227 | const extra = data.builder.typeExtraDataTrail(Type.Function, type_item.data); | |
| 388 | const extra = data.builder.typeExtraDataTrail(Type.Function, item.data); | |
| 228 | 389 | const params: []const Type = |
| 229 | 390 | @ptrCast(data.builder.type_extra.items[extra.end..][0..extra.data.params_len]); |
| 230 | 391 | if (!comptime std.mem.eql(u8, fmt_str, ">")) |
| ... | ... | @@ -235,7 +396,7 @@ pub const Type = enum(u32) { |
| 235 | 396 | if (index > 0) try writer.writeAll(", "); |
| 236 | 397 | try writer.print("{%}", .{param.fmt(data.builder)}); |
| 237 | 398 | } |
| 238 | switch (type_item.tag) { | |
| 399 | switch (item.tag) { | |
| 239 | 400 | .function => {}, |
| 240 | 401 | .vararg_function => { |
| 241 | 402 | if (params.len > 0) try writer.writeAll(", "); |
| ... | ... | @@ -246,10 +407,10 @@ pub const Type = enum(u32) { |
| 246 | 407 | try writer.writeByte(')'); |
| 247 | 408 | } |
| 248 | 409 | }, |
| 249 | .integer => try writer.print("i{d}", .{type_item.data}), | |
| 250 | .pointer => try writer.print("ptr{}", .{@as(AddrSpace, @enumFromInt(type_item.data))}), | |
| 410 | .integer => try writer.print("i{d}", .{item.data}), | |
| 411 | .pointer => try writer.print("ptr{}", .{@as(AddrSpace, @enumFromInt(item.data))}), | |
| 251 | 412 | .target => { |
| 252 | const extra = data.builder.typeExtraDataTrail(Type.Target, type_item.data); | |
| 413 | const extra = data.builder.typeExtraDataTrail(Type.Target, item.data); | |
| 253 | 414 | const types: []const Type = |
| 254 | 415 | @ptrCast(data.builder.type_extra.items[extra.end..][0..extra.data.types_len]); |
| 255 | 416 | const ints: []const u32 = @ptrCast(data.builder.type_extra.items[extra.end + |
| ... | ... | @@ -262,26 +423,28 @@ pub const Type = enum(u32) { |
| 262 | 423 | try writer.writeByte(')'); |
| 263 | 424 | }, |
| 264 | 425 | .vector => { |
| 265 | const extra = data.builder.typeExtraData(Type.Vector, type_item.data); | |
| 426 | const extra = data.builder.typeExtraData(Type.Vector, item.data); | |
| 266 | 427 | try writer.print("<{d} x {%}>", .{ extra.len, extra.child.fmt(data.builder) }); |
| 267 | 428 | }, |
| 268 | 429 | .scalable_vector => { |
| 269 | const extra = data.builder.typeExtraData(Type.Vector, type_item.data); | |
| 430 | const extra = data.builder.typeExtraData(Type.Vector, item.data); | |
| 270 | 431 | try writer.print("<vscale x {d} x {%}>", .{ extra.len, extra.child.fmt(data.builder) }); |
| 271 | 432 | }, |
| 272 | 433 | .small_array => { |
| 273 | const extra = data.builder.typeExtraData(Type.Vector, type_item.data); | |
| 434 | const extra = data.builder.typeExtraData(Type.Vector, item.data); | |
| 274 | 435 | try writer.print("[{d} x {%}]", .{ extra.len, extra.child.fmt(data.builder) }); |
| 275 | 436 | }, |
| 276 | 437 | .array => { |
| 277 | const extra = data.builder.typeExtraData(Type.Array, type_item.data); | |
| 438 | const extra = data.builder.typeExtraData(Type.Array, item.data); | |
| 278 | 439 | try writer.print("[{d} x {%}]", .{ extra.len(), extra.child.fmt(data.builder) }); |
| 279 | 440 | }, |
| 280 | .structure, .packed_structure => { | |
| 281 | const extra = data.builder.typeExtraDataTrail(Type.Structure, type_item.data); | |
| 441 | .structure, | |
| 442 | .packed_structure, | |
| 443 | => { | |
| 444 | const extra = data.builder.typeExtraDataTrail(Type.Structure, item.data); | |
| 282 | 445 | const fields: []const Type = |
| 283 | 446 | @ptrCast(data.builder.type_extra.items[extra.end..][0..extra.data.fields_len]); |
| 284 | switch (type_item.tag) { | |
| 447 | switch (item.tag) { | |
| 285 | 448 | .structure => {}, |
| 286 | 449 | .packed_structure => try writer.writeByte('<'), |
| 287 | 450 | else => unreachable, |
| ... | ... | @@ -292,14 +455,14 @@ pub const Type = enum(u32) { |
| 292 | 455 | try writer.print("{%}", .{field.fmt(data.builder)}); |
| 293 | 456 | } |
| 294 | 457 | try writer.writeAll(" }"); |
| 295 | switch (type_item.tag) { | |
| 458 | switch (item.tag) { | |
| 296 | 459 | .structure => {}, |
| 297 | 460 | .packed_structure => try writer.writeByte('>'), |
| 298 | 461 | else => unreachable, |
| 299 | 462 | } |
| 300 | 463 | }, |
| 301 | 464 | .named_structure => { |
| 302 | const extra = data.builder.typeExtraData(Type.NamedStructure, type_item.data); | |
| 465 | const extra = data.builder.typeExtraData(Type.NamedStructure, item.data); | |
| 303 | 466 | if (comptime std.mem.eql(u8, fmt_str, "%")) try writer.print("%{}", .{ |
| 304 | 467 | extra.id.fmt(data.builder), |
| 305 | 468 | }) else switch (extra.body) { |
| ... | ... | @@ -323,7 +486,7 @@ pub const Type = enum(u32) { |
| 323 | 486 | }; |
| 324 | 487 | |
| 325 | 488 | pub const Linkage = enum { |
| 326 | default, | |
| 489 | external, | |
| 327 | 490 | private, |
| 328 | 491 | internal, |
| 329 | 492 | available_externally, |
| ... | ... | @@ -334,7 +497,6 @@ pub const Linkage = enum { |
| 334 | 497 | extern_weak, |
| 335 | 498 | linkonce_odr, |
| 336 | 499 | weak_odr, |
| 337 | external, | |
| 338 | 500 | |
| 339 | 501 | pub fn format( |
| 340 | 502 | self: Linkage, |
| ... | ... | @@ -342,14 +504,14 @@ pub const Linkage = enum { |
| 342 | 504 | _: std.fmt.FormatOptions, |
| 343 | 505 | writer: anytype, |
| 344 | 506 | ) @TypeOf(writer).Error!void { |
| 345 | if (self != .default) try writer.print(" {s}", .{@tagName(self)}); | |
| 507 | if (self != .external) try writer.print(" {s}", .{@tagName(self)}); | |
| 346 | 508 | } |
| 347 | 509 | }; |
| 348 | 510 | |
| 349 | 511 | pub const Preemption = enum { |
| 350 | default, | |
| 351 | 512 | dso_preemptable, |
| 352 | 513 | dso_local, |
| 514 | implicit_dso_local, | |
| 353 | 515 | |
| 354 | 516 | pub fn format( |
| 355 | 517 | self: Preemption, |
| ... | ... | @@ -357,7 +519,7 @@ pub const Preemption = enum { |
| 357 | 519 | _: std.fmt.FormatOptions, |
| 358 | 520 | writer: anytype, |
| 359 | 521 | ) @TypeOf(writer).Error!void { |
| 360 | if (self != .default) try writer.print(" {s}", .{@tagName(self)}); | |
| 522 | if (self == .dso_local) try writer.print(" {s}", .{@tagName(self)}); | |
| 361 | 523 | } |
| 362 | 524 | }; |
| 363 | 525 | |
| ... | ... | @@ -554,22 +716,25 @@ pub const Alignment = enum(u6) { |
| 554 | 716 | }; |
| 555 | 717 | |
| 556 | 718 | pub const Global = struct { |
| 557 | linkage: Linkage = .default, | |
| 558 | preemption: Preemption = .default, | |
| 719 | linkage: Linkage = .external, | |
| 720 | preemption: Preemption = .dso_preemptable, | |
| 559 | 721 | visibility: Visibility = .default, |
| 560 | 722 | dll_storage_class: DllStorageClass = .default, |
| 561 | 723 | unnamed_addr: UnnamedAddr = .default, |
| 562 | 724 | addr_space: AddrSpace = .default, |
| 563 | 725 | externally_initialized: ExternallyInitialized = .default, |
| 564 | 726 | type: Type, |
| 727 | section: String = .none, | |
| 728 | partition: String = .none, | |
| 565 | 729 | alignment: Alignment = .default, |
| 566 | 730 | kind: union(enum) { |
| 567 | 731 | alias: Alias.Index, |
| 568 | object: Object.Index, | |
| 732 | variable: Variable.Index, | |
| 569 | 733 | function: Function.Index, |
| 570 | 734 | }, |
| 571 | 735 | |
| 572 | 736 | pub const Index = enum(u32) { |
| 737 | none = std.math.maxInt(u32), | |
| 573 | 738 | _, |
| 574 | 739 | |
| 575 | 740 | pub fn ptr(self: Index, builder: *Builder) *Global { |
| ... | ... | @@ -580,11 +745,33 @@ pub const Global = struct { |
| 580 | 745 | return &builder.globals.values()[@intFromEnum(self)]; |
| 581 | 746 | } |
| 582 | 747 | |
| 748 | pub fn toConst(self: Index) Constant { | |
| 749 | return @enumFromInt(@intFromEnum(Constant.first_global) + @intFromEnum(self)); | |
| 750 | } | |
| 751 | ||
| 583 | 752 | pub fn toLlvm(self: Index, builder: *const Builder) *llvm.Value { |
| 584 | 753 | assert(builder.useLibLlvm()); |
| 585 | 754 | return builder.llvm_globals.items[@intFromEnum(self)]; |
| 586 | 755 | } |
| 587 | 756 | |
| 757 | const FormatData = struct { | |
| 758 | global: Index, | |
| 759 | builder: *const Builder, | |
| 760 | }; | |
| 761 | fn format( | |
| 762 | data: FormatData, | |
| 763 | comptime _: []const u8, | |
| 764 | _: std.fmt.FormatOptions, | |
| 765 | writer: anytype, | |
| 766 | ) @TypeOf(writer).Error!void { | |
| 767 | try writer.print("@{}", .{ | |
| 768 | data.builder.globals.keys()[@intFromEnum(data.global)].fmt(data.builder), | |
| 769 | }); | |
| 770 | } | |
| 771 | pub fn fmt(self: Index, builder: *const Builder) std.fmt.Formatter(format) { | |
| 772 | return .{ .data = .{ .global = self, .builder = builder } }; | |
| 773 | } | |
| 774 | ||
| 588 | 775 | pub fn rename(self: Index, builder: *Builder, name: String) Allocator.Error!void { |
| 589 | 776 | try builder.ensureUnusedCapacityGlobal(name); |
| 590 | 777 | self.renameAssumeCapacity(builder, name); |
| ... | ... | @@ -618,12 +805,32 @@ pub const Global = struct { |
| 618 | 805 | builder.llvm_globals.items[index].setValueName2(slice.ptr, slice.len); |
| 619 | 806 | } |
| 620 | 807 | }; |
| 808 | ||
| 809 | pub fn updateAttributes(self: *Global) void { | |
| 810 | switch (self.linkage) { | |
| 811 | .private, .internal => { | |
| 812 | self.visibility = .default; | |
| 813 | self.dll_storage_class = .default; | |
| 814 | self.preemption = .implicit_dso_local; | |
| 815 | }, | |
| 816 | .extern_weak => if (self.preemption == .implicit_dso_local) { | |
| 817 | self.preemption = .dso_local; | |
| 818 | }, | |
| 819 | else => switch (self.visibility) { | |
| 820 | .default => if (self.preemption == .implicit_dso_local) { | |
| 821 | self.preemption = .dso_local; | |
| 822 | }, | |
| 823 | else => self.preemption = .implicit_dso_local, | |
| 824 | }, | |
| 825 | } | |
| 826 | } | |
| 621 | 827 | }; |
| 622 | 828 | |
| 623 | 829 | pub const Alias = struct { |
| 624 | 830 | global: Global.Index, |
| 625 | 831 | |
| 626 | 832 | pub const Index = enum(u32) { |
| 833 | none = std.math.maxInt(u32), | |
| 627 | 834 | _, |
| 628 | 835 | |
| 629 | 836 | pub fn ptr(self: Index, builder: *Builder) *Alias { |
| ... | ... | @@ -640,21 +847,22 @@ pub const Alias = struct { |
| 640 | 847 | }; |
| 641 | 848 | }; |
| 642 | 849 | |
| 643 | pub const Object = struct { | |
| 850 | pub const Variable = struct { | |
| 644 | 851 | global: Global.Index, |
| 645 | 852 | thread_local: ThreadLocal = .default, |
| 646 | 853 | mutability: enum { global, constant } = .global, |
| 647 | 854 | init: Constant = .no_init, |
| 648 | 855 | |
| 649 | 856 | pub const Index = enum(u32) { |
| 857 | none = std.math.maxInt(u32), | |
| 650 | 858 | _, |
| 651 | 859 | |
| 652 | pub fn ptr(self: Index, builder: *Builder) *Object { | |
| 653 | return &builder.objects.items[@intFromEnum(self)]; | |
| 860 | pub fn ptr(self: Index, builder: *Builder) *Variable { | |
| 861 | return &builder.variables.items[@intFromEnum(self)]; | |
| 654 | 862 | } |
| 655 | 863 | |
| 656 | pub fn ptrConst(self: Index, builder: *const Builder) *const Object { | |
| 657 | return &builder.objects.items[@intFromEnum(self)]; | |
| 864 | pub fn ptrConst(self: Index, builder: *const Builder) *const Variable { | |
| 865 | return &builder.variables.items[@intFromEnum(self)]; | |
| 658 | 866 | } |
| 659 | 867 | |
| 660 | 868 | pub fn toLlvm(self: Index, builder: *const Builder) *llvm.Value { |
| ... | ... | @@ -670,6 +878,7 @@ pub const Function = struct { |
| 670 | 878 | blocks: std.ArrayListUnmanaged(Block) = .{}, |
| 671 | 879 | |
| 672 | 880 | pub const Index = enum(u32) { |
| 881 | none = std.math.maxInt(u32), | |
| 673 | 882 | _, |
| 674 | 883 | |
| 675 | 884 | pub fn ptr(self: Index, builder: *Builder) *Function { |
| ... | ... | @@ -693,13 +902,13 @@ pub const Function = struct { |
| 693 | 902 | block, |
| 694 | 903 | }; |
| 695 | 904 | |
| 696 | pub const Index = enum(u31) { _ }; | |
| 905 | pub const Index = enum(u32) { _ }; | |
| 697 | 906 | }; |
| 698 | 907 | |
| 699 | 908 | pub const Block = struct { |
| 700 | 909 | body: std.ArrayListUnmanaged(Instruction.Index) = .{}, |
| 701 | 910 | |
| 702 | pub const Index = enum(u31) { _ }; | |
| 911 | pub const Index = enum(u32) { _ }; | |
| 703 | 912 | }; |
| 704 | 913 | |
| 705 | 914 | pub fn deinit(self: *Function, gpa: Allocator) void { |
| ... | ... | @@ -709,6 +918,36 @@ pub const Function = struct { |
| 709 | 918 | } |
| 710 | 919 | }; |
| 711 | 920 | |
| 921 | pub const FloatCondition = enum(u4) { | |
| 922 | oeq = 1, | |
| 923 | ogt = 2, | |
| 924 | oge = 3, | |
| 925 | olt = 4, | |
| 926 | ole = 5, | |
| 927 | one = 6, | |
| 928 | ord = 7, | |
| 929 | uno = 8, | |
| 930 | ueq = 9, | |
| 931 | ugt = 10, | |
| 932 | uge = 11, | |
| 933 | ult = 12, | |
| 934 | ule = 13, | |
| 935 | une = 14, | |
| 936 | }; | |
| 937 | ||
| 938 | pub const IntegerCondition = enum(u6) { | |
| 939 | eq = 32, | |
| 940 | ne = 33, | |
| 941 | ugt = 34, | |
| 942 | uge = 35, | |
| 943 | ult = 36, | |
| 944 | ule = 37, | |
| 945 | sgt = 38, | |
| 946 | sge = 39, | |
| 947 | slt = 40, | |
| 948 | sle = 41, | |
| 949 | }; | |
| 950 | ||
| 712 | 951 | pub const Constant = enum(u32) { |
| 713 | 952 | false, |
| 714 | 953 | true, |
| ... | ... | @@ -719,15 +958,24 @@ pub const Constant = enum(u32) { |
| 719 | 958 | const first_global: Constant = @enumFromInt(1 << 30); |
| 720 | 959 | |
| 721 | 960 | pub const Tag = enum(u6) { |
| 722 | integer_positive, | |
| 723 | integer_negative, | |
| 961 | positive_integer, | |
| 962 | negative_integer, | |
| 963 | half, | |
| 964 | bfloat, | |
| 965 | float, | |
| 966 | double, | |
| 967 | fp128, | |
| 968 | x86_fp80, | |
| 969 | ppc_fp128, | |
| 724 | 970 | null, |
| 725 | 971 | none, |
| 726 | 972 | structure, |
| 973 | packed_structure, | |
| 727 | 974 | array, |
| 975 | string, | |
| 976 | string_null, | |
| 728 | 977 | vector, |
| 729 | 978 | zeroinitializer, |
| 730 | global, | |
| 731 | 979 | undef, |
| 732 | 980 | poison, |
| 733 | 981 | blockaddress, |
| ... | ... | @@ -747,6 +995,7 @@ pub const Constant = enum(u32) { |
| 747 | 995 | bitcast, |
| 748 | 996 | addrspacecast, |
| 749 | 997 | getelementptr, |
| 998 | @"getelementptr inbounds", | |
| 750 | 999 | icmp, |
| 751 | 1000 | fcmp, |
| 752 | 1001 | extractelement, |
| ... | ... | @@ -765,7 +1014,9 @@ pub const Constant = enum(u32) { |
| 765 | 1014 | |
| 766 | 1015 | pub const Item = struct { |
| 767 | 1016 | tag: Tag, |
| 768 | data: u32, | |
| 1017 | data: ExtraIndex, | |
| 1018 | ||
| 1019 | const ExtraIndex = u32; | |
| 769 | 1020 | }; |
| 770 | 1021 | |
| 771 | 1022 | pub const Integer = packed struct(u64) { |
| ... | ... | @@ -775,6 +1026,80 @@ pub const Constant = enum(u32) { |
| 775 | 1026 | pub const limbs = @divExact(@bitSizeOf(Integer), @bitSizeOf(std.math.big.Limb)); |
| 776 | 1027 | }; |
| 777 | 1028 | |
| 1029 | pub const Double = struct { | |
| 1030 | lo: u32, | |
| 1031 | hi: u32, | |
| 1032 | }; | |
| 1033 | ||
| 1034 | pub const Fp80 = struct { | |
| 1035 | lo_lo: u32, | |
| 1036 | lo_hi: u32, | |
| 1037 | hi: u32, | |
| 1038 | }; | |
| 1039 | ||
| 1040 | pub const Fp128 = struct { | |
| 1041 | lo_lo: u32, | |
| 1042 | lo_hi: u32, | |
| 1043 | hi_lo: u32, | |
| 1044 | hi_hi: u32, | |
| 1045 | }; | |
| 1046 | ||
| 1047 | pub const Aggregate = struct { | |
| 1048 | type: Type, | |
| 1049 | }; | |
| 1050 | ||
| 1051 | pub const BlockAddress = extern struct { | |
| 1052 | function: Function.Index, | |
| 1053 | block: Function.Block.Index, | |
| 1054 | }; | |
| 1055 | ||
| 1056 | pub const FunctionReference = struct { | |
| 1057 | function: Function.Index, | |
| 1058 | }; | |
| 1059 | ||
| 1060 | pub const Cast = extern struct { | |
| 1061 | arg: Constant, | |
| 1062 | type: Type, | |
| 1063 | ||
| 1064 | pub const Signedness = enum { unsigned, signed, unneeded }; | |
| 1065 | }; | |
| 1066 | ||
| 1067 | pub const GetElementPtr = struct { | |
| 1068 | type: Type, | |
| 1069 | base: Constant, | |
| 1070 | indices_len: u32, | |
| 1071 | ||
| 1072 | pub const Kind = enum { normal, inbounds }; | |
| 1073 | }; | |
| 1074 | ||
| 1075 | pub const Compare = struct { | |
| 1076 | cond: u32, | |
| 1077 | lhs: Constant, | |
| 1078 | rhs: Constant, | |
| 1079 | }; | |
| 1080 | ||
| 1081 | pub const ExtractElement = struct { | |
| 1082 | arg: Constant, | |
| 1083 | index: Constant, | |
| 1084 | }; | |
| 1085 | ||
| 1086 | pub const InsertElement = struct { | |
| 1087 | arg: Constant, | |
| 1088 | elem: Constant, | |
| 1089 | index: Constant, | |
| 1090 | }; | |
| 1091 | ||
| 1092 | pub const ShuffleVector = struct { | |
| 1093 | lhs: Constant, | |
| 1094 | rhs: Constant, | |
| 1095 | mask: Constant, | |
| 1096 | }; | |
| 1097 | ||
| 1098 | pub const Binary = extern struct { | |
| 1099 | lhs: Constant, | |
| 1100 | rhs: Constant, | |
| 1101 | }; | |
| 1102 | ||
| 778 | 1103 | pub fn unwrap(self: Constant) union(enum) { |
| 779 | 1104 | constant: u30, |
| 780 | 1105 | global: Global.Index, |
| ... | ... | @@ -785,6 +1110,307 @@ pub const Constant = enum(u32) { |
| 785 | 1110 | .{ .global = @enumFromInt(@intFromEnum(self) - @intFromEnum(first_global)) }; |
| 786 | 1111 | } |
| 787 | 1112 | |
| 1113 | pub fn typeOf(self: Constant, builder: *Builder) Type { | |
| 1114 | switch (self.unwrap()) { | |
| 1115 | .constant => |constant| { | |
| 1116 | const item = builder.constant_items.get(constant); | |
| 1117 | return switch (item.tag) { | |
| 1118 | .positive_integer, | |
| 1119 | .negative_integer, | |
| 1120 | => @as( | |
| 1121 | *align(@alignOf(std.math.big.Limb)) Integer, | |
| 1122 | @ptrCast(builder.constant_limbs.items[item.data..][0..Integer.limbs]), | |
| 1123 | ).type, | |
| 1124 | .half => .half, | |
| 1125 | .bfloat => .bfloat, | |
| 1126 | .float => .float, | |
| 1127 | .double => .double, | |
| 1128 | .fp128 => .fp128, | |
| 1129 | .x86_fp80 => .x86_fp80, | |
| 1130 | .ppc_fp128 => .ppc_fp128, | |
| 1131 | .null, | |
| 1132 | .none, | |
| 1133 | .zeroinitializer, | |
| 1134 | .undef, | |
| 1135 | .poison, | |
| 1136 | => @enumFromInt(item.data), | |
| 1137 | .structure, | |
| 1138 | .packed_structure, | |
| 1139 | .array, | |
| 1140 | .vector, | |
| 1141 | => builder.constantExtraData(Aggregate, item.data).type, | |
| 1142 | .string, | |
| 1143 | .string_null, | |
| 1144 | => builder.arrayTypeAssumeCapacity( | |
| 1145 | @as(String, @enumFromInt(item.data)).toSlice(builder).?.len + | |
| 1146 | @intFromBool(item.tag == .string_null), | |
| 1147 | .i8, | |
| 1148 | ), | |
| 1149 | .blockaddress => builder.ptrTypeAssumeCapacity( | |
| 1150 | builder.constantExtraData(BlockAddress, item.data) | |
| 1151 | .function.ptrConst(builder).global.ptrConst(builder).addr_space, | |
| 1152 | ), | |
| 1153 | .dso_local_equivalent, | |
| 1154 | .no_cfi, | |
| 1155 | => builder.ptrTypeAssumeCapacity( | |
| 1156 | builder.constantExtraData(FunctionReference, item.data) | |
| 1157 | .function.ptrConst(builder).global.ptrConst(builder).addr_space, | |
| 1158 | ), | |
| 1159 | .trunc, | |
| 1160 | .zext, | |
| 1161 | .sext, | |
| 1162 | .fptrunc, | |
| 1163 | .fpext, | |
| 1164 | .fptoui, | |
| 1165 | .fptosi, | |
| 1166 | .uitofp, | |
| 1167 | .sitofp, | |
| 1168 | .ptrtoint, | |
| 1169 | .inttoptr, | |
| 1170 | .bitcast, | |
| 1171 | .addrspacecast, | |
| 1172 | => builder.constantExtraData(Cast, item.data).type, | |
| 1173 | .getelementptr, | |
| 1174 | .@"getelementptr inbounds", | |
| 1175 | => { | |
| 1176 | const extra = builder.constantExtraDataTrail(GetElementPtr, item.data); | |
| 1177 | const indices: []const Constant = @ptrCast(builder.constant_extra | |
| 1178 | .items[extra.end..][0..extra.data.indices_len]); | |
| 1179 | const base_ty = extra.data.base.typeOf(builder); | |
| 1180 | if (!base_ty.isVector(builder)) for (indices) |index| { | |
| 1181 | const index_ty = index.typeOf(builder); | |
| 1182 | if (!index_ty.isVector(builder)) continue; | |
| 1183 | switch (index_ty.vectorKind(builder)) { | |
| 1184 | inline else => |kind| return builder.vectorTypeAssumeCapacity( | |
| 1185 | kind, | |
| 1186 | index_ty.vectorLen(builder), | |
| 1187 | base_ty, | |
| 1188 | ), | |
| 1189 | } | |
| 1190 | }; | |
| 1191 | return base_ty; | |
| 1192 | }, | |
| 1193 | .icmp, .fcmp => { | |
| 1194 | const ty = builder.constantExtraData(Compare, item.data).lhs.typeOf(builder); | |
| 1195 | return switch (ty) { | |
| 1196 | .half, | |
| 1197 | .bfloat, | |
| 1198 | .float, | |
| 1199 | .double, | |
| 1200 | .fp128, | |
| 1201 | .x86_fp80, | |
| 1202 | .ppc_fp128, | |
| 1203 | .i1, | |
| 1204 | .i8, | |
| 1205 | .i16, | |
| 1206 | .i29, | |
| 1207 | .i32, | |
| 1208 | .i64, | |
| 1209 | .i80, | |
| 1210 | .i128, | |
| 1211 | => ty, | |
| 1212 | else => if (ty.isVector(builder)) switch (ty.vectorKind(builder)) { | |
| 1213 | inline else => |kind| builder | |
| 1214 | .vectorTypeAssumeCapacity(kind, ty.vectorLen(builder), .i1), | |
| 1215 | } else ty, | |
| 1216 | }; | |
| 1217 | }, | |
| 1218 | .extractelement => builder.constantExtraData(ExtractElement, item.data) | |
| 1219 | .arg.typeOf(builder).childType(builder), | |
| 1220 | .insertelement => builder.constantExtraData(InsertElement, item.data) | |
| 1221 | .arg.typeOf(builder), | |
| 1222 | .shufflevector => { | |
| 1223 | const extra = builder.constantExtraData(ShuffleVector, item.data); | |
| 1224 | const ty = extra.lhs.typeOf(builder); | |
| 1225 | return switch (ty.vectorKind(builder)) { | |
| 1226 | inline else => |kind| builder.vectorTypeAssumeCapacity( | |
| 1227 | kind, | |
| 1228 | extra.mask.typeOf(builder).vectorLen(builder), | |
| 1229 | ty.childType(builder), | |
| 1230 | ), | |
| 1231 | }; | |
| 1232 | }, | |
| 1233 | .add, | |
| 1234 | .sub, | |
| 1235 | .mul, | |
| 1236 | .shl, | |
| 1237 | .lshr, | |
| 1238 | .ashr, | |
| 1239 | .@"and", | |
| 1240 | .@"or", | |
| 1241 | .xor, | |
| 1242 | => builder.constantExtraData(Binary, item.data).lhs.typeOf(builder), | |
| 1243 | }; | |
| 1244 | }, | |
| 1245 | .global => |global| return builder.ptrTypeAssumeCapacity( | |
| 1246 | global.ptrConst(builder).addr_space, | |
| 1247 | ), | |
| 1248 | } | |
| 1249 | } | |
| 1250 | ||
| 1251 | pub fn isZeroInit(self: Constant, builder: *const Builder) bool { | |
| 1252 | switch (self.unwrap()) { | |
| 1253 | .constant => |constant| { | |
| 1254 | const item = builder.constant_items.get(constant); | |
| 1255 | return switch (item.tag) { | |
| 1256 | .positive_integer => { | |
| 1257 | const extra: *align(@alignOf(std.math.big.Limb)) Integer = | |
| 1258 | @ptrCast(builder.constant_limbs.items[item.data..][0..Integer.limbs]); | |
| 1259 | const limbs = builder.constant_limbs | |
| 1260 | .items[item.data + Integer.limbs ..][0..extra.limbs_len]; | |
| 1261 | return std.mem.eql(std.math.big.Limb, limbs, &.{0}); | |
| 1262 | }, | |
| 1263 | .half, .bfloat, .float => item.data == 0, | |
| 1264 | .double => { | |
| 1265 | const extra = builder.constantExtraData(Constant.Double, item.data); | |
| 1266 | return extra.lo == 0 and extra.hi == 0; | |
| 1267 | }, | |
| 1268 | .fp128, .ppc_fp128 => { | |
| 1269 | const extra = builder.constantExtraData(Constant.Fp128, item.data); | |
| 1270 | return extra.lo_lo == 0 and extra.lo_hi == 0 and | |
| 1271 | extra.hi_lo == 0 and extra.hi_hi == 0; | |
| 1272 | }, | |
| 1273 | .x86_fp80 => { | |
| 1274 | const extra = builder.constantExtraData(Constant.Fp80, item.data); | |
| 1275 | return extra.lo_lo == 0 and extra.lo_hi == 0 and extra.hi == 0; | |
| 1276 | }, | |
| 1277 | .vector => { | |
| 1278 | const extra = builder.constantExtraDataTrail(Aggregate, item.data); | |
| 1279 | const len = extra.data.type.aggregateLen(builder); | |
| 1280 | const vals: []const Constant = | |
| 1281 | @ptrCast(builder.constant_extra.items[extra.end..][0..len]); | |
| 1282 | for (vals) |val| if (!val.isZeroInit(builder)) return false; | |
| 1283 | return true; | |
| 1284 | }, | |
| 1285 | .null, .zeroinitializer => true, | |
| 1286 | else => false, | |
| 1287 | }; | |
| 1288 | }, | |
| 1289 | .global => return false, | |
| 1290 | } | |
| 1291 | } | |
| 1292 | ||
| 1293 | pub const FormatData = struct { | |
| 1294 | constant: Constant, | |
| 1295 | builder: *Builder, | |
| 1296 | }; | |
| 1297 | fn format( | |
| 1298 | data: FormatData, | |
| 1299 | comptime fmt_str: []const u8, | |
| 1300 | _: std.fmt.FormatOptions, | |
| 1301 | writer: anytype, | |
| 1302 | ) @TypeOf(writer).Error!void { | |
| 1303 | if (comptime std.mem.eql(u8, fmt_str, "%")) { | |
| 1304 | try writer.print("{%} ", .{data.constant.typeOf(data.builder).fmt(data.builder)}); | |
| 1305 | } else if (comptime std.mem.eql(u8, fmt_str, " ")) { | |
| 1306 | if (data.constant == .no_init) return; | |
| 1307 | try writer.writeByte(' '); | |
| 1308 | } | |
| 1309 | assert(data.constant != .no_init); | |
| 1310 | if (std.enums.tagName(Constant, data.constant)) |name| return writer.writeAll(name); | |
| 1311 | switch (data.constant.unwrap()) { | |
| 1312 | .constant => |constant| { | |
| 1313 | const item = data.builder.constant_items.get(constant); | |
| 1314 | switch (item.tag) { | |
| 1315 | .positive_integer, | |
| 1316 | .negative_integer, | |
| 1317 | => { | |
| 1318 | const extra: *align(@alignOf(std.math.big.Limb)) Integer = | |
| 1319 | @ptrCast(data.builder.constant_limbs.items[item.data..][0..Integer.limbs]); | |
| 1320 | const limbs = data.builder.constant_limbs | |
| 1321 | .items[item.data + Integer.limbs ..][0..extra.limbs_len]; | |
| 1322 | const bigint = std.math.big.int.Const{ | |
| 1323 | .limbs = limbs, | |
| 1324 | .positive = item.tag == .positive_integer, | |
| 1325 | }; | |
| 1326 | const ExpectedContents = extern struct { | |
| 1327 | string: [(64 * 8 / std.math.log2(10)) + 2]u8, | |
| 1328 | limbs: [ | |
| 1329 | std.math.big.int.calcToStringLimbsBufferLen( | |
| 1330 | 64 / @sizeOf(std.math.big.Limb), | |
| 1331 | 10, | |
| 1332 | ) | |
| 1333 | ]std.math.big.Limb, | |
| 1334 | }; | |
| 1335 | var stack align(@alignOf(ExpectedContents)) = | |
| 1336 | std.heap.stackFallback(@sizeOf(ExpectedContents), data.builder.gpa); | |
| 1337 | const allocator = stack.get(); | |
| 1338 | const str = bigint.toStringAlloc(allocator, 10, undefined) catch | |
| 1339 | return writer.writeAll("..."); | |
| 1340 | defer allocator.free(str); | |
| 1341 | try writer.writeAll(str); | |
| 1342 | }, | |
| 1343 | .null, | |
| 1344 | .none, | |
| 1345 | .zeroinitializer, | |
| 1346 | .undef, | |
| 1347 | .poison, | |
| 1348 | => try writer.writeAll(@tagName(item.tag)), | |
| 1349 | .structure, | |
| 1350 | .packed_structure, | |
| 1351 | .array, | |
| 1352 | .vector, | |
| 1353 | => { | |
| 1354 | const extra = data.builder.constantExtraDataTrail(Aggregate, item.data); | |
| 1355 | const len = extra.data.type.aggregateLen(data.builder); | |
| 1356 | const vals: []const Constant = | |
| 1357 | @ptrCast(data.builder.constant_extra.items[extra.end..][0..len]); | |
| 1358 | ||
| 1359 | try writer.writeAll(switch (item.tag) { | |
| 1360 | .structure => "{ ", | |
| 1361 | .packed_structure => "<{ ", | |
| 1362 | .array => "[", | |
| 1363 | .vector => "<", | |
| 1364 | else => unreachable, | |
| 1365 | }); | |
| 1366 | for (vals, 0..) |val, index| { | |
| 1367 | if (index > 0) try writer.writeAll(", "); | |
| 1368 | try writer.print("{%}", .{val.fmt(data.builder)}); | |
| 1369 | } | |
| 1370 | try writer.writeAll(switch (item.tag) { | |
| 1371 | .structure => " }", | |
| 1372 | .packed_structure => " }>", | |
| 1373 | .array => "]", | |
| 1374 | .vector => ">", | |
| 1375 | else => unreachable, | |
| 1376 | }); | |
| 1377 | }, | |
| 1378 | .string => try writer.print( | |
| 1379 | \\c{"} | |
| 1380 | , .{@as(String, @enumFromInt(item.data)).fmt(data.builder)}), | |
| 1381 | .string_null => try writer.print( | |
| 1382 | \\c{"@} | |
| 1383 | , .{@as(String, @enumFromInt(item.data)).fmt(data.builder)}), | |
| 1384 | .blockaddress => { | |
| 1385 | const extra = data.builder.constantExtraData(BlockAddress, item.data); | |
| 1386 | const function = extra.function.ptrConst(data.builder); | |
| 1387 | try writer.print("{s}({}, %{d})", .{ | |
| 1388 | @tagName(item.tag), | |
| 1389 | function.global.fmt(data.builder), | |
| 1390 | @intFromEnum(extra.block), // TODO | |
| 1391 | }); | |
| 1392 | }, | |
| 1393 | .dso_local_equivalent, | |
| 1394 | .no_cfi, | |
| 1395 | => { | |
| 1396 | const extra = data.builder.constantExtraData(FunctionReference, item.data); | |
| 1397 | try writer.print("{s} {}", .{ | |
| 1398 | @tagName(item.tag), | |
| 1399 | extra.function.ptrConst(data.builder).global.fmt(data.builder), | |
| 1400 | }); | |
| 1401 | }, | |
| 1402 | else => try writer.print("<{s}:0x{X}>", .{ | |
| 1403 | @tagName(item.tag), @intFromEnum(data.constant), | |
| 1404 | }), | |
| 1405 | } | |
| 1406 | }, | |
| 1407 | .global => |global| try writer.print("{}", .{global.fmt(data.builder)}), | |
| 1408 | } | |
| 1409 | } | |
| 1410 | pub fn fmt(self: Constant, builder: *Builder) std.fmt.Formatter(format) { | |
| 1411 | return .{ .data = .{ .constant = self, .builder = builder } }; | |
| 1412 | } | |
| 1413 | ||
| 788 | 1414 | pub fn toLlvm(self: Constant, builder: *const Builder) *llvm.Value { |
| 789 | 1415 | assert(builder.useLibLlvm()); |
| 790 | 1416 | return switch (self.unwrap()) { |
| ... | ... | @@ -813,7 +1439,6 @@ pub const Value = enum(u32) { |
| 813 | 1439 | pub fn init(self: *Builder) Allocator.Error!void { |
| 814 | 1440 | try self.string_indices.append(self.gpa, 0); |
| 815 | 1441 | assert(try self.string("") == .empty); |
| 816 | assert(try self.string("debugme") == .debugme); | |
| 817 | 1442 | |
| 818 | 1443 | { |
| 819 | 1444 | const static_len = @typeInfo(Type).Enum.fields.len - 1; |
| ... | ... | @@ -821,10 +1446,9 @@ pub fn init(self: *Builder) Allocator.Error!void { |
| 821 | 1446 | try self.type_items.ensureTotalCapacity(self.gpa, static_len); |
| 822 | 1447 | if (self.useLibLlvm()) try self.llvm_types.ensureTotalCapacity(self.gpa, static_len); |
| 823 | 1448 | inline for (@typeInfo(Type.Simple).Enum.fields) |simple_field| { |
| 824 | const result = self.typeNoExtraAssumeCapacity(.{ | |
| 825 | .tag = .simple, | |
| 826 | .data = simple_field.value, | |
| 827 | }); | |
| 1449 | const result = self.getOrPutTypeNoExtraAssumeCapacity( | |
| 1450 | .{ .tag = .simple, .data = simple_field.value }, | |
| 1451 | ); | |
| 828 | 1452 | assert(result.new and result.type == @field(Type, simple_field.name)); |
| 829 | 1453 | if (self.useLibLlvm()) self.llvm_types.appendAssumeCapacity( |
| 830 | 1454 | @field(llvm.Context, simple_field.name ++ "Type")(self.llvm_context), |
| ... | ... | @@ -838,6 +1462,7 @@ pub fn init(self: *Builder) Allocator.Error!void { |
| 838 | 1462 | |
| 839 | 1463 | assert(try self.intConst(.i1, 0) == .false); |
| 840 | 1464 | assert(try self.intConst(.i1, 1) == .true); |
| 1465 | assert(try self.noneConst(.token) == .none); | |
| 841 | 1466 | } |
| 842 | 1467 | |
| 843 | 1468 | pub fn deinit(self: *Builder) void { |
| ... | ... | @@ -858,7 +1483,7 @@ pub fn deinit(self: *Builder) void { |
| 858 | 1483 | self.globals.deinit(self.gpa); |
| 859 | 1484 | self.next_unique_global_id.deinit(self.gpa); |
| 860 | 1485 | self.aliases.deinit(self.gpa); |
| 861 | self.objects.deinit(self.gpa); | |
| 1486 | self.variables.deinit(self.gpa); | |
| 862 | 1487 | for (self.functions.items) |*function| function.deinit(self.gpa); |
| 863 | 1488 | self.functions.deinit(self.gpa); |
| 864 | 1489 | |
| ... | ... | @@ -1110,19 +1735,19 @@ pub fn fnType( |
| 1110 | 1735 | params: []const Type, |
| 1111 | 1736 | kind: Type.Function.Kind, |
| 1112 | 1737 | ) Allocator.Error!Type { |
| 1113 | try self.ensureUnusedCapacityTypes(1, Type.Function, params.len); | |
| 1738 | try self.ensureUnusedTypeCapacity(1, Type.Function, params.len); | |
| 1114 | 1739 | return switch (kind) { |
| 1115 | 1740 | inline else => |comptime_kind| self.fnTypeAssumeCapacity(ret, params, comptime_kind), |
| 1116 | 1741 | }; |
| 1117 | 1742 | } |
| 1118 | 1743 | |
| 1119 | 1744 | pub fn intType(self: *Builder, bits: u24) Allocator.Error!Type { |
| 1120 | try self.ensureUnusedCapacityTypes(1, null, 0); | |
| 1745 | try self.ensureUnusedTypeCapacity(1, null, 0); | |
| 1121 | 1746 | return self.intTypeAssumeCapacity(bits); |
| 1122 | 1747 | } |
| 1123 | 1748 | |
| 1124 | 1749 | pub fn ptrType(self: *Builder, addr_space: AddrSpace) Allocator.Error!Type { |
| 1125 | try self.ensureUnusedCapacityTypes(1, null, 0); | |
| 1750 | try self.ensureUnusedTypeCapacity(1, null, 0); | |
| 1126 | 1751 | return self.ptrTypeAssumeCapacity(addr_space); |
| 1127 | 1752 | } |
| 1128 | 1753 | |
| ... | ... | @@ -1132,7 +1757,7 @@ pub fn vectorType( |
| 1132 | 1757 | len: u32, |
| 1133 | 1758 | child: Type, |
| 1134 | 1759 | ) Allocator.Error!Type { |
| 1135 | try self.ensureUnusedCapacityTypes(1, Type.Vector, 0); | |
| 1760 | try self.ensureUnusedTypeCapacity(1, Type.Vector, 0); | |
| 1136 | 1761 | return switch (kind) { |
| 1137 | 1762 | inline else => |comptime_kind| self.vectorTypeAssumeCapacity(comptime_kind, len, child), |
| 1138 | 1763 | }; |
| ... | ... | @@ -1140,7 +1765,7 @@ pub fn vectorType( |
| 1140 | 1765 | |
| 1141 | 1766 | pub fn arrayType(self: *Builder, len: u64, child: Type) Allocator.Error!Type { |
| 1142 | 1767 | comptime assert(@sizeOf(Type.Array) >= @sizeOf(Type.Vector)); |
| 1143 | try self.ensureUnusedCapacityTypes(1, Type.Array, 0); | |
| 1768 | try self.ensureUnusedTypeCapacity(1, Type.Array, 0); | |
| 1144 | 1769 | return self.arrayTypeAssumeCapacity(len, child); |
| 1145 | 1770 | } |
| 1146 | 1771 | |
| ... | ... | @@ -1149,7 +1774,7 @@ pub fn structType( |
| 1149 | 1774 | kind: Type.Structure.Kind, |
| 1150 | 1775 | fields: []const Type, |
| 1151 | 1776 | ) Allocator.Error!Type { |
| 1152 | try self.ensureUnusedCapacityTypes(1, Type.Structure, fields.len); | |
| 1777 | try self.ensureUnusedTypeCapacity(1, Type.Structure, fields.len); | |
| 1153 | 1778 | return switch (kind) { |
| 1154 | 1779 | inline else => |comptime_kind| self.structTypeAssumeCapacity(comptime_kind, fields), |
| 1155 | 1780 | }; |
| ... | ... | @@ -1162,7 +1787,7 @@ pub fn opaqueType(self: *Builder, name: String) Allocator.Error!Type { |
| 1162 | 1787 | try self.string_indices.ensureUnusedCapacity(self.gpa, 1); |
| 1163 | 1788 | try self.types.ensureUnusedCapacity(self.gpa, 1); |
| 1164 | 1789 | try self.next_unique_type_id.ensureUnusedCapacity(self.gpa, 1); |
| 1165 | try self.ensureUnusedCapacityTypes(1, Type.NamedStructure, 0); | |
| 1790 | try self.ensureUnusedTypeCapacity(1, Type.NamedStructure, 0); | |
| 1166 | 1791 | return self.opaqueTypeAssumeCapacity(name); |
| 1167 | 1792 | } |
| 1168 | 1793 | |
| ... | ... | @@ -1181,8 +1806,7 @@ pub fn namedTypeSetBody( |
| 1181 | 1806 | @ptrCast(self.type_extra.items[body_extra.end..][0..body_extra.data.fields_len]); |
| 1182 | 1807 | const llvm_fields = try self.gpa.alloc(*llvm.Type, body_fields.len); |
| 1183 | 1808 | defer self.gpa.free(llvm_fields); |
| 1184 | for (llvm_fields, body_fields) |*llvm_field, body_field| | |
| 1185 | llvm_field.* = self.llvm_types.items[@intFromEnum(body_field)]; | |
| 1809 | for (llvm_fields, body_fields) |*llvm_field, body_field| llvm_field.* = body_field.toLlvm(self); | |
| 1186 | 1810 | self.llvm_types.items[@intFromEnum(named_type)].structSetBody( |
| 1187 | 1811 | llvm_fields.ptr, |
| 1188 | 1812 | @intCast(llvm_fields.len), |
| ... | ... | @@ -1196,11 +1820,13 @@ pub fn namedTypeSetBody( |
| 1196 | 1820 | } |
| 1197 | 1821 | |
| 1198 | 1822 | pub fn addGlobal(self: *Builder, name: String, global: Global) Allocator.Error!Global.Index { |
| 1823 | try self.ensureUnusedTypeCapacity(1, null, 0); | |
| 1199 | 1824 | try self.ensureUnusedCapacityGlobal(name); |
| 1200 | 1825 | return self.addGlobalAssumeCapacity(name, global); |
| 1201 | 1826 | } |
| 1202 | 1827 | |
| 1203 | 1828 | pub fn addGlobalAssumeCapacity(self: *Builder, name: String, global: Global) Global.Index { |
| 1829 | _ = self.ptrTypeAssumeCapacity(global.addr_space); | |
| 1204 | 1830 | var id = name; |
| 1205 | 1831 | if (id == .none) { |
| 1206 | 1832 | id = self.next_unnamed_global; |
| ... | ... | @@ -1210,6 +1836,7 @@ pub fn addGlobalAssumeCapacity(self: *Builder, name: String, global: Global) Glo |
| 1210 | 1836 | const global_gop = self.globals.getOrPutAssumeCapacity(id); |
| 1211 | 1837 | if (!global_gop.found_existing) { |
| 1212 | 1838 | global_gop.value_ptr.* = global; |
| 1839 | global_gop.value_ptr.updateAttributes(); | |
| 1213 | 1840 | const index: Global.Index = @enumFromInt(global_gop.index); |
| 1214 | 1841 | index.updateName(self); |
| 1215 | 1842 | return index; |
| ... | ... | @@ -1246,6 +1873,207 @@ pub fn bigIntConst(self: *Builder, ty: Type, value: std.math.big.int.Const) Allo |
| 1246 | 1873 | return self.bigIntConstAssumeCapacity(ty, value); |
| 1247 | 1874 | } |
| 1248 | 1875 | |
| 1876 | pub fn fpConst(self: *Builder, ty: Type, comptime val: comptime_float) Allocator.Error!Constant { | |
| 1877 | return switch (ty) { | |
| 1878 | .half => try self.halfConst(val), | |
| 1879 | .bfloat => try self.bfloatConst(val), | |
| 1880 | .float => try self.floatConst(val), | |
| 1881 | .double => try self.doubleConst(val), | |
| 1882 | .fp128 => try self.fp128Const(val), | |
| 1883 | .x86_fp80 => try self.x86_fp80Const(val), | |
| 1884 | .ppc_fp128 => try self.ppc_fp128Const(.{ val, 0 }), | |
| 1885 | else => unreachable, | |
| 1886 | }; | |
| 1887 | } | |
| 1888 | ||
| 1889 | pub fn halfConst(self: *Builder, val: f16) Allocator.Error!Constant { | |
| 1890 | try self.ensureUnusedConstantCapacity(1, null, 0); | |
| 1891 | return self.halfConstAssumeCapacity(val); | |
| 1892 | } | |
| 1893 | ||
| 1894 | pub fn bfloatConst(self: *Builder, val: f32) Allocator.Error!Constant { | |
| 1895 | try self.ensureUnusedConstantCapacity(1, null, 0); | |
| 1896 | return self.bfloatConstAssumeCapacity(val); | |
| 1897 | } | |
| 1898 | ||
| 1899 | pub fn floatConst(self: *Builder, val: f32) Allocator.Error!Constant { | |
| 1900 | try self.ensureUnusedConstantCapacity(1, null, 0); | |
| 1901 | return self.floatConstAssumeCapacity(val); | |
| 1902 | } | |
| 1903 | ||
| 1904 | pub fn doubleConst(self: *Builder, val: f64) Allocator.Error!Constant { | |
| 1905 | try self.ensureUnusedConstantCapacity(1, Constant.Double, 0); | |
| 1906 | return self.doubleConstAssumeCapacity(val); | |
| 1907 | } | |
| 1908 | ||
| 1909 | pub fn fp128Const(self: *Builder, val: f128) Allocator.Error!Constant { | |
| 1910 | try self.ensureUnusedConstantCapacity(1, Constant.Fp128, 0); | |
| 1911 | return self.fp128ConstAssumeCapacity(val); | |
| 1912 | } | |
| 1913 | ||
| 1914 | pub fn x86_fp80Const(self: *Builder, val: f80) Allocator.Error!Constant { | |
| 1915 | try self.ensureUnusedConstantCapacity(1, Constant.Fp80, 0); | |
| 1916 | return self.x86_fp80ConstAssumeCapacity(val); | |
| 1917 | } | |
| 1918 | ||
| 1919 | pub fn ppc_fp128Const(self: *Builder, val: [2]f64) Allocator.Error!Constant { | |
| 1920 | try self.ensureUnusedConstantCapacity(1, Constant.Fp128, 0); | |
| 1921 | return self.ppc_fp128ConstAssumeCapacity(val); | |
| 1922 | } | |
| 1923 | ||
| 1924 | pub fn nullConst(self: *Builder, ty: Type) Allocator.Error!Constant { | |
| 1925 | try self.ensureUnusedConstantCapacity(1, null, 0); | |
| 1926 | return self.nullConstAssumeCapacity(ty); | |
| 1927 | } | |
| 1928 | ||
| 1929 | pub fn noneConst(self: *Builder, ty: Type) Allocator.Error!Constant { | |
| 1930 | try self.ensureUnusedConstantCapacity(1, null, 0); | |
| 1931 | return self.noneConstAssumeCapacity(ty); | |
| 1932 | } | |
| 1933 | ||
| 1934 | pub fn structConst(self: *Builder, ty: Type, vals: []const Constant) Allocator.Error!Constant { | |
| 1935 | try self.ensureUnusedConstantCapacity(1, Constant.Aggregate, vals.len); | |
| 1936 | return self.structConstAssumeCapacity(ty, vals); | |
| 1937 | } | |
| 1938 | ||
| 1939 | pub fn arrayConst(self: *Builder, ty: Type, vals: []const Constant) Allocator.Error!Constant { | |
| 1940 | try self.ensureUnusedConstantCapacity(1, Constant.Aggregate, vals.len); | |
| 1941 | return self.arrayConstAssumeCapacity(ty, vals); | |
| 1942 | } | |
| 1943 | ||
| 1944 | pub fn stringConst(self: *Builder, val: String) Allocator.Error!Constant { | |
| 1945 | try self.ensureUnusedTypeCapacity(1, Type.Array, 0); | |
| 1946 | try self.ensureUnusedConstantCapacity(1, null, 0); | |
| 1947 | return self.stringConstAssumeCapacity(val); | |
| 1948 | } | |
| 1949 | ||
| 1950 | pub fn stringNullConst(self: *Builder, val: String) Allocator.Error!Constant { | |
| 1951 | try self.ensureUnusedTypeCapacity(1, Type.Array, 0); | |
| 1952 | try self.ensureUnusedConstantCapacity(1, null, 0); | |
| 1953 | return self.stringNullConstAssumeCapacity(val); | |
| 1954 | } | |
| 1955 | ||
| 1956 | pub fn vectorConst(self: *Builder, ty: Type, vals: []const Constant) Allocator.Error!Constant { | |
| 1957 | try self.ensureUnusedConstantCapacity(1, Constant.Aggregate, vals.len); | |
| 1958 | return self.vectorConstAssumeCapacity(ty, vals); | |
| 1959 | } | |
| 1960 | ||
| 1961 | pub fn zeroInitConst(self: *Builder, ty: Type) Allocator.Error!Constant { | |
| 1962 | try self.ensureUnusedConstantCapacity(1, null, 0); | |
| 1963 | return self.zeroInitConstAssumeCapacity(ty); | |
| 1964 | } | |
| 1965 | ||
| 1966 | pub fn undefConst(self: *Builder, ty: Type) Allocator.Error!Constant { | |
| 1967 | try self.ensureUnusedConstantCapacity(1, null, 0); | |
| 1968 | return self.undefConstAssumeCapacity(ty); | |
| 1969 | } | |
| 1970 | ||
| 1971 | pub fn poisonConst(self: *Builder, ty: Type) Allocator.Error!Constant { | |
| 1972 | try self.ensureUnusedConstantCapacity(1, null, 0); | |
| 1973 | return self.poisonConstAssumeCapacity(ty); | |
| 1974 | } | |
| 1975 | ||
| 1976 | pub fn blockAddrConst( | |
| 1977 | self: *Builder, | |
| 1978 | function: Function.Index, | |
| 1979 | block: Function.Block.Index, | |
| 1980 | ) Allocator.Error!Constant { | |
| 1981 | try self.ensureUnusedConstantCapacity(1, Constant.BlockAddress, 0); | |
| 1982 | return self.blockAddrConstAssumeCapacity(function, block); | |
| 1983 | } | |
| 1984 | ||
| 1985 | pub fn dsoLocalEquivalentConst(self: *Builder, function: Function.Index) Allocator.Error!Constant { | |
| 1986 | try self.ensureUnusedConstantCapacity(1, Constant.FunctionReference, 0); | |
| 1987 | return self.dsoLocalEquivalentConstAssumeCapacity(function); | |
| 1988 | } | |
| 1989 | ||
| 1990 | pub fn noCfiConst(self: *Builder, function: Function.Index) Allocator.Error!Constant { | |
| 1991 | try self.ensureUnusedConstantCapacity(1, Constant.FunctionReference, 0); | |
| 1992 | return self.noCfiConstAssumeCapacity(function); | |
| 1993 | } | |
| 1994 | ||
| 1995 | pub fn convConst( | |
| 1996 | self: *Builder, | |
| 1997 | signedness: Constant.Cast.Signedness, | |
| 1998 | arg: Constant, | |
| 1999 | ty: Type, | |
| 2000 | ) Allocator.Error!Constant { | |
| 2001 | try self.ensureUnusedConstantCapacity(1, Constant.Cast, 0); | |
| 2002 | return self.convConstAssumeCapacity(signedness, arg, ty); | |
| 2003 | } | |
| 2004 | ||
| 2005 | pub fn castConst(self: *Builder, tag: Constant.Tag, arg: Constant, ty: Type) Allocator.Error!Constant { | |
| 2006 | try self.ensureUnusedConstantCapacity(1, Constant.Cast, 0); | |
| 2007 | return self.castConstAssumeCapacity(tag, arg, ty); | |
| 2008 | } | |
| 2009 | ||
| 2010 | pub fn gepConst( | |
| 2011 | self: *Builder, | |
| 2012 | comptime kind: Constant.GetElementPtr.Kind, | |
| 2013 | ty: Type, | |
| 2014 | base: Constant, | |
| 2015 | indices: []const Constant, | |
| 2016 | ) Allocator.Error!Constant { | |
| 2017 | try self.ensureUnusedTypeCapacity(1, Type.Vector, 0); | |
| 2018 | try self.ensureUnusedConstantCapacity(1, Constant.GetElementPtr, indices.len); | |
| 2019 | return self.gepConstAssumeCapacity(kind, ty, base, indices); | |
| 2020 | } | |
| 2021 | ||
| 2022 | pub fn icmpConst( | |
| 2023 | self: *Builder, | |
| 2024 | cond: IntegerCondition, | |
| 2025 | lhs: Constant, | |
| 2026 | rhs: Constant, | |
| 2027 | ) Allocator.Error!Constant { | |
| 2028 | try self.ensureUnusedConstantCapacity(1, Constant.Compare, 0); | |
| 2029 | return self.icmpConstAssumeCapacity(cond, lhs, rhs); | |
| 2030 | } | |
| 2031 | ||
| 2032 | pub fn fcmpConst( | |
| 2033 | self: *Builder, | |
| 2034 | cond: FloatCondition, | |
| 2035 | lhs: Constant, | |
| 2036 | rhs: Constant, | |
| 2037 | ) Allocator.Error!Constant { | |
| 2038 | try self.ensureUnusedConstantCapacity(1, Constant.Compare, 0); | |
| 2039 | return self.icmpConstAssumeCapacity(cond, lhs, rhs); | |
| 2040 | } | |
| 2041 | ||
| 2042 | pub fn extractElementConst(self: *Builder, arg: Constant, index: Constant) Allocator.Error!Constant { | |
| 2043 | try self.ensureUnusedConstantCapacity(1, Constant.ExtractElement, 0); | |
| 2044 | return self.extractElementConstAssumeCapacity(arg, index); | |
| 2045 | } | |
| 2046 | ||
| 2047 | pub fn insertElementConst( | |
| 2048 | self: *Builder, | |
| 2049 | arg: Constant, | |
| 2050 | elem: Constant, | |
| 2051 | index: Constant, | |
| 2052 | ) Allocator.Error!Constant { | |
| 2053 | try self.ensureUnusedConstantCapacity(1, Constant.InsertElement, 0); | |
| 2054 | return self.insertElementConstAssumeCapacity(arg, elem, index); | |
| 2055 | } | |
| 2056 | ||
| 2057 | pub fn shuffleVectorConst( | |
| 2058 | self: *Builder, | |
| 2059 | lhs: Constant, | |
| 2060 | rhs: Constant, | |
| 2061 | mask: Constant, | |
| 2062 | ) Allocator.Error!Constant { | |
| 2063 | try self.ensureUnusedConstantCapacity(1, Constant.ShuffleVector, 0); | |
| 2064 | return self.shuffleVectorConstAssumeCapacity(lhs, rhs, mask); | |
| 2065 | } | |
| 2066 | ||
| 2067 | pub fn binConst( | |
| 2068 | self: *Builder, | |
| 2069 | tag: Constant.Tag, | |
| 2070 | lhs: Constant, | |
| 2071 | rhs: Constant, | |
| 2072 | ) Allocator.Error!Constant { | |
| 2073 | try self.ensureUnusedConstantCapacity(1, Constant.Binary, 0); | |
| 2074 | return self.binConstAssumeCapacity(tag, lhs, rhs); | |
| 2075 | } | |
| 2076 | ||
| 1249 | 2077 | pub fn dump(self: *Builder, writer: anytype) @TypeOf(writer).Error!void { |
| 1250 | 2078 | if (self.source_filename != .none) try writer.print( |
| 1251 | 2079 | \\; ModuleID = '{s}' |
| ... | ... | @@ -1266,43 +2094,44 @@ pub fn dump(self: *Builder, writer: anytype) @TypeOf(writer).Error!void { |
| 1266 | 2094 | \\ |
| 1267 | 2095 | , .{ id.fmt(self), ty.fmt(self) }); |
| 1268 | 2096 | try writer.writeByte('\n'); |
| 1269 | for (self.objects.items) |object| { | |
| 1270 | const global = self.globals.entries.get(@intFromEnum(object.global)); | |
| 2097 | for (self.variables.items) |variable| { | |
| 2098 | const global = self.globals.values()[@intFromEnum(variable.global)]; | |
| 1271 | 2099 | try writer.print( |
| 1272 | \\@{} ={}{}{}{}{}{}{}{} {s} {%}{,} | |
| 2100 | \\{} ={}{}{}{}{}{}{}{} {s} {%}{ }{,} | |
| 1273 | 2101 | \\ |
| 1274 | 2102 | , .{ |
| 1275 | global.key.fmt(self), | |
| 1276 | global.value.linkage, | |
| 1277 | global.value.preemption, | |
| 1278 | global.value.visibility, | |
| 1279 | global.value.dll_storage_class, | |
| 1280 | object.thread_local, | |
| 1281 | global.value.unnamed_addr, | |
| 1282 | global.value.addr_space, | |
| 1283 | global.value.externally_initialized, | |
| 1284 | @tagName(object.mutability), | |
| 1285 | global.value.type.fmt(self), | |
| 1286 | global.value.alignment, | |
| 2103 | variable.global.fmt(self), | |
| 2104 | global.linkage, | |
| 2105 | global.preemption, | |
| 2106 | global.visibility, | |
| 2107 | global.dll_storage_class, | |
| 2108 | variable.thread_local, | |
| 2109 | global.unnamed_addr, | |
| 2110 | global.addr_space, | |
| 2111 | global.externally_initialized, | |
| 2112 | @tagName(variable.mutability), | |
| 2113 | global.type.fmt(self), | |
| 2114 | variable.init.fmt(self), | |
| 2115 | global.alignment, | |
| 1287 | 2116 | }); |
| 1288 | 2117 | } |
| 1289 | 2118 | try writer.writeByte('\n'); |
| 1290 | 2119 | for (self.functions.items) |function| { |
| 1291 | const global = self.globals.entries.get(@intFromEnum(function.global)); | |
| 1292 | const item = self.type_items.items[@intFromEnum(global.value.type)]; | |
| 2120 | const global = self.globals.values()[@intFromEnum(function.global)]; | |
| 2121 | const item = self.type_items.items[@intFromEnum(global.type)]; | |
| 1293 | 2122 | const extra = self.typeExtraDataTrail(Type.Function, item.data); |
| 1294 | 2123 | const params: []const Type = |
| 1295 | 2124 | @ptrCast(self.type_extra.items[extra.end..][0..extra.data.params_len]); |
| 1296 | 2125 | try writer.print( |
| 1297 | \\{s} {}{}{}{}{} @{}( | |
| 2126 | \\{s}{}{}{}{} {} {}( | |
| 1298 | 2127 | , .{ |
| 1299 | 2128 | if (function.body) |_| "define" else "declare", |
| 1300 | global.value.linkage, | |
| 1301 | global.value.preemption, | |
| 1302 | global.value.visibility, | |
| 1303 | global.value.dll_storage_class, | |
| 2129 | global.linkage, | |
| 2130 | global.preemption, | |
| 2131 | global.visibility, | |
| 2132 | global.dll_storage_class, | |
| 1304 | 2133 | extra.data.ret.fmt(self), |
| 1305 | global.key.fmt(self), | |
| 2134 | function.global.fmt(self), | |
| 1306 | 2135 | }); |
| 1307 | 2136 | for (params, 0..) |param, index| { |
| 1308 | 2137 | if (index > 0) try writer.writeAll(", "); |
| ... | ... | @@ -1316,65 +2145,36 @@ pub fn dump(self: *Builder, writer: anytype) @TypeOf(writer).Error!void { |
| 1316 | 2145 | }, |
| 1317 | 2146 | else => unreachable, |
| 1318 | 2147 | } |
| 1319 | try writer.print(") {}{}", .{ | |
| 1320 | global.value.unnamed_addr, | |
| 1321 | global.value.alignment, | |
| 1322 | }); | |
| 2148 | try writer.print(") {}{}", .{ global.unnamed_addr, global.alignment }); | |
| 1323 | 2149 | if (function.body) |_| try writer.print( |
| 1324 | 2150 | \\{{ |
| 1325 | 2151 | \\ ret {%} |
| 1326 | 2152 | \\}} |
| 1327 | 2153 | \\ |
| 1328 | , .{ | |
| 1329 | extra.data.ret.fmt(self), | |
| 1330 | }); | |
| 2154 | , .{extra.data.ret.fmt(self)}); | |
| 1331 | 2155 | try writer.writeByte('\n'); |
| 1332 | 2156 | } |
| 1333 | 2157 | } |
| 1334 | 2158 | |
| 2159 | fn isValidIdentifier(id: []const u8) bool { | |
| 2160 | for (id, 0..) |character, index| switch (character) { | |
| 2161 | '$', '-', '.', 'A'...'Z', '_', 'a'...'z' => {}, | |
| 2162 | '0'...'9' => if (index == 0) return false, | |
| 2163 | else => return false, | |
| 2164 | }; | |
| 2165 | return true; | |
| 2166 | } | |
| 2167 | ||
| 1335 | 2168 | fn ensureUnusedCapacityGlobal(self: *Builder, name: String) Allocator.Error!void { |
| 1336 | 2169 | if (self.useLibLlvm()) try self.llvm_globals.ensureUnusedCapacity(self.gpa, 1); |
| 1337 | 2170 | try self.string_map.ensureUnusedCapacity(self.gpa, 1); |
| 1338 | try self.string_bytes.ensureUnusedCapacity(self.gpa, name.toSlice(self).?.len + | |
| 2171 | if (name.toSlice(self)) |id| try self.string_bytes.ensureUnusedCapacity(self.gpa, id.len + | |
| 1339 | 2172 | comptime std.fmt.count("{d}" ++ .{0}, .{std.math.maxInt(u32)})); |
| 1340 | 2173 | try self.string_indices.ensureUnusedCapacity(self.gpa, 1); |
| 1341 | 2174 | try self.globals.ensureUnusedCapacity(self.gpa, 1); |
| 1342 | 2175 | try self.next_unique_global_id.ensureUnusedCapacity(self.gpa, 1); |
| 1343 | 2176 | } |
| 1344 | 2177 | |
| 1345 | fn addTypeExtraAssumeCapacity(self: *Builder, extra: anytype) Type.ExtraIndex { | |
| 1346 | const result: Type.ExtraIndex = @intCast(self.type_extra.items.len); | |
| 1347 | inline for (@typeInfo(@TypeOf(extra)).Struct.fields) |field| { | |
| 1348 | const value = @field(extra, field.name); | |
| 1349 | self.type_extra.appendAssumeCapacity(switch (field.type) { | |
| 1350 | u32 => value, | |
| 1351 | String, Type => @intFromEnum(value), | |
| 1352 | else => @compileError("bad field type: " ++ @typeName(field.type)), | |
| 1353 | }); | |
| 1354 | } | |
| 1355 | return result; | |
| 1356 | } | |
| 1357 | ||
| 1358 | fn typeExtraDataTrail( | |
| 1359 | self: *const Builder, | |
| 1360 | comptime T: type, | |
| 1361 | index: Type.ExtraIndex, | |
| 1362 | ) struct { data: T, end: Type.ExtraIndex } { | |
| 1363 | var result: T = undefined; | |
| 1364 | const fields = @typeInfo(T).Struct.fields; | |
| 1365 | inline for (fields, self.type_extra.items[index..][0..fields.len]) |field, data| | |
| 1366 | @field(result, field.name) = switch (field.type) { | |
| 1367 | u32 => data, | |
| 1368 | String, Type => @enumFromInt(data), | |
| 1369 | else => @compileError("bad field type: " ++ @typeName(field.type)), | |
| 1370 | }; | |
| 1371 | return .{ .data = result, .end = index + @as(Type.ExtraIndex, @intCast(fields.len)) }; | |
| 1372 | } | |
| 1373 | ||
| 1374 | fn typeExtraData(self: *const Builder, comptime T: type, index: Type.ExtraIndex) T { | |
| 1375 | return self.typeExtraDataTrail(T, index).data; | |
| 1376 | } | |
| 1377 | ||
| 1378 | 2178 | fn fnTypeAssumeCapacity( |
| 1379 | 2179 | self: *Builder, |
| 1380 | 2180 | ret: Type, |
| ... | ... | @@ -1394,17 +2194,19 @@ fn fnTypeAssumeCapacity( |
| 1394 | 2194 | hasher.update(std.mem.sliceAsBytes(key.params)); |
| 1395 | 2195 | return @truncate(hasher.final()); |
| 1396 | 2196 | } |
| 1397 | pub fn eql(ctx: @This(), lhs: Key, _: void, rhs_index: usize) bool { | |
| 2197 | pub fn eql(ctx: @This(), lhs_key: Key, _: void, rhs_index: usize) bool { | |
| 1398 | 2198 | const rhs_data = ctx.builder.type_items.items[rhs_index]; |
| 1399 | 2199 | const rhs_extra = ctx.builder.typeExtraDataTrail(Type.Function, rhs_data.data); |
| 1400 | 2200 | const rhs_params: []const Type = |
| 1401 | 2201 | @ptrCast(ctx.builder.type_extra.items[rhs_extra.end..][0..rhs_extra.data.params_len]); |
| 1402 | return rhs_data.tag == tag and lhs.ret == rhs_extra.data.ret and | |
| 1403 | std.mem.eql(Type, lhs.params, rhs_params); | |
| 2202 | return rhs_data.tag == tag and lhs_key.ret == rhs_extra.data.ret and | |
| 2203 | std.mem.eql(Type, lhs_key.params, rhs_params); | |
| 1404 | 2204 | } |
| 1405 | 2205 | }; |
| 1406 | const data = Key{ .ret = ret, .params = params }; | |
| 1407 | const gop = self.type_map.getOrPutAssumeCapacityAdapted(data, Adapter{ .builder = self }); | |
| 2206 | const gop = self.type_map.getOrPutAssumeCapacityAdapted( | |
| 2207 | Key{ .ret = ret, .params = params }, | |
| 2208 | Adapter{ .builder = self }, | |
| 2209 | ); | |
| 1408 | 2210 | if (!gop.found_existing) { |
| 1409 | 2211 | gop.key_ptr.* = {}; |
| 1410 | 2212 | gop.value_ptr.* = {}; |
| ... | ... | @@ -1436,17 +2238,16 @@ fn fnTypeAssumeCapacity( |
| 1436 | 2238 | |
| 1437 | 2239 | fn intTypeAssumeCapacity(self: *Builder, bits: u24) Type { |
| 1438 | 2240 | assert(bits > 0); |
| 1439 | const result = self.typeNoExtraAssumeCapacity(.{ .tag = .integer, .data = bits }); | |
| 2241 | const result = self.getOrPutTypeNoExtraAssumeCapacity(.{ .tag = .integer, .data = bits }); | |
| 1440 | 2242 | if (self.useLibLlvm() and result.new) |
| 1441 | 2243 | self.llvm_types.appendAssumeCapacity(self.llvm_context.intType(bits)); |
| 1442 | 2244 | return result.type; |
| 1443 | 2245 | } |
| 1444 | 2246 | |
| 1445 | 2247 | fn ptrTypeAssumeCapacity(self: *Builder, addr_space: AddrSpace) Type { |
| 1446 | const result = self.typeNoExtraAssumeCapacity(.{ | |
| 1447 | .tag = .pointer, | |
| 1448 | .data = @intFromEnum(addr_space), | |
| 1449 | }); | |
| 2248 | const result = self.getOrPutTypeNoExtraAssumeCapacity( | |
| 2249 | .{ .tag = .pointer, .data = @intFromEnum(addr_space) }, | |
| 2250 | ); | |
| 1450 | 2251 | if (self.useLibLlvm() and result.new) |
| 1451 | 2252 | self.llvm_types.appendAssumeCapacity(self.llvm_context.pointerType(@intFromEnum(addr_space))); |
| 1452 | 2253 | return result.type; |
| ... | ... | @@ -1470,10 +2271,10 @@ fn vectorTypeAssumeCapacity( |
| 1470 | 2271 | std.mem.asBytes(&key), |
| 1471 | 2272 | )); |
| 1472 | 2273 | } |
| 1473 | pub fn eql(ctx: @This(), lhs: Type.Vector, _: void, rhs_index: usize) bool { | |
| 2274 | pub fn eql(ctx: @This(), lhs_key: Type.Vector, _: void, rhs_index: usize) bool { | |
| 1474 | 2275 | const rhs_data = ctx.builder.type_items.items[rhs_index]; |
| 1475 | 2276 | return rhs_data.tag == tag and |
| 1476 | std.meta.eql(lhs, ctx.builder.typeExtraData(Type.Vector, rhs_data.data)); | |
| 2277 | std.meta.eql(lhs_key, ctx.builder.typeExtraData(Type.Vector, rhs_data.data)); | |
| 1477 | 2278 | } |
| 1478 | 2279 | }; |
| 1479 | 2280 | const data = Type.Vector{ .len = len, .child = child }; |
| ... | ... | @@ -1503,10 +2304,10 @@ fn arrayTypeAssumeCapacity(self: *Builder, len: u64, child: Type) Type { |
| 1503 | 2304 | std.mem.asBytes(&key), |
| 1504 | 2305 | )); |
| 1505 | 2306 | } |
| 1506 | pub fn eql(ctx: @This(), lhs: Type.Vector, _: void, rhs_index: usize) bool { | |
| 2307 | pub fn eql(ctx: @This(), lhs_key: Type.Vector, _: void, rhs_index: usize) bool { | |
| 1507 | 2308 | const rhs_data = ctx.builder.type_items.items[rhs_index]; |
| 1508 | 2309 | return rhs_data.tag == .small_array and |
| 1509 | std.meta.eql(lhs, ctx.builder.typeExtraData(Type.Vector, rhs_data.data)); | |
| 2310 | std.meta.eql(lhs_key, ctx.builder.typeExtraData(Type.Vector, rhs_data.data)); | |
| 1510 | 2311 | } |
| 1511 | 2312 | }; |
| 1512 | 2313 | const data = Type.Vector{ .len = small_len, .child = child }; |
| ... | ... | @@ -1532,10 +2333,10 @@ fn arrayTypeAssumeCapacity(self: *Builder, len: u64, child: Type) Type { |
| 1532 | 2333 | std.mem.asBytes(&key), |
| 1533 | 2334 | )); |
| 1534 | 2335 | } |
| 1535 | pub fn eql(ctx: @This(), lhs: Type.Array, _: void, rhs_index: usize) bool { | |
| 2336 | pub fn eql(ctx: @This(), lhs_key: Type.Array, _: void, rhs_index: usize) bool { | |
| 1536 | 2337 | const rhs_data = ctx.builder.type_items.items[rhs_index]; |
| 1537 | 2338 | return rhs_data.tag == .array and |
| 1538 | std.meta.eql(lhs, ctx.builder.typeExtraData(Type.Array, rhs_data.data)); | |
| 2339 | std.meta.eql(lhs_key, ctx.builder.typeExtraData(Type.Array, rhs_data.data)); | |
| 1539 | 2340 | } |
| 1540 | 2341 | }; |
| 1541 | 2342 | const data = Type.Array{ |
| ... | ... | @@ -1576,12 +2377,12 @@ fn structTypeAssumeCapacity( |
| 1576 | 2377 | std.mem.sliceAsBytes(key), |
| 1577 | 2378 | )); |
| 1578 | 2379 | } |
| 1579 | pub fn eql(ctx: @This(), lhs: []const Type, _: void, rhs_index: usize) bool { | |
| 2380 | pub fn eql(ctx: @This(), lhs_key: []const Type, _: void, rhs_index: usize) bool { | |
| 1580 | 2381 | const rhs_data = ctx.builder.type_items.items[rhs_index]; |
| 1581 | 2382 | const rhs_extra = ctx.builder.typeExtraDataTrail(Type.Structure, rhs_data.data); |
| 1582 | 2383 | const rhs_fields: []const Type = |
| 1583 | 2384 | @ptrCast(ctx.builder.type_extra.items[rhs_extra.end..][0..rhs_extra.data.fields_len]); |
| 1584 | return rhs_data.tag == tag and std.mem.eql(Type, lhs, rhs_fields); | |
| 2385 | return rhs_data.tag == tag and std.mem.eql(Type, lhs_key, rhs_fields); | |
| 1585 | 2386 | } |
| 1586 | 2387 | }; |
| 1587 | 2388 | const gop = self.type_map.getOrPutAssumeCapacityAdapted(fields, Adapter{ .builder = self }); |
| ... | ... | @@ -1596,15 +2397,14 @@ fn structTypeAssumeCapacity( |
| 1596 | 2397 | }); |
| 1597 | 2398 | self.type_extra.appendSliceAssumeCapacity(@ptrCast(fields)); |
| 1598 | 2399 | if (self.useLibLlvm()) { |
| 1599 | const ExpectedContents = [32]*llvm.Type; | |
| 2400 | const ExpectedContents = [expected_fields_len]*llvm.Type; | |
| 1600 | 2401 | var stack align(@alignOf(ExpectedContents)) = |
| 1601 | 2402 | std.heap.stackFallback(@sizeOf(ExpectedContents), self.gpa); |
| 1602 | 2403 | const allocator = stack.get(); |
| 1603 | 2404 | |
| 1604 | 2405 | const llvm_fields = try allocator.alloc(*llvm.Type, fields.len); |
| 1605 | 2406 | defer allocator.free(llvm_fields); |
| 1606 | for (llvm_fields, fields) |*llvm_field, field| | |
| 1607 | llvm_field.* = self.llvm_types.items[@intFromEnum(field)]; | |
| 2407 | for (llvm_fields, fields) |*llvm_field, field| llvm_field.* = field.toLlvm(self); | |
| 1608 | 2408 | |
| 1609 | 2409 | self.llvm_types.appendAssumeCapacity(self.llvm_context.structType( |
| 1610 | 2410 | llvm_fields.ptr, |
| ... | ... | @@ -1628,10 +2428,10 @@ fn opaqueTypeAssumeCapacity(self: *Builder, name: String) Type { |
| 1628 | 2428 | std.mem.asBytes(&key), |
| 1629 | 2429 | )); |
| 1630 | 2430 | } |
| 1631 | pub fn eql(ctx: @This(), lhs: String, _: void, rhs_index: usize) bool { | |
| 2431 | pub fn eql(ctx: @This(), lhs_key: String, _: void, rhs_index: usize) bool { | |
| 1632 | 2432 | const rhs_data = ctx.builder.type_items.items[rhs_index]; |
| 1633 | 2433 | return rhs_data.tag == .named_structure and |
| 1634 | lhs == ctx.builder.typeExtraData(Type.NamedStructure, rhs_data.data).id; | |
| 2434 | lhs_key == ctx.builder.typeExtraData(Type.NamedStructure, rhs_data.data).id; | |
| 1635 | 2435 | } |
| 1636 | 2436 | }; |
| 1637 | 2437 | var id = name; |
| ... | ... | @@ -1669,7 +2469,7 @@ fn opaqueTypeAssumeCapacity(self: *Builder, name: String) Type { |
| 1669 | 2469 | } |
| 1670 | 2470 | } |
| 1671 | 2471 | |
| 1672 | fn ensureUnusedCapacityTypes( | |
| 2472 | fn ensureUnusedTypeCapacity( | |
| 1673 | 2473 | self: *Builder, |
| 1674 | 2474 | count: usize, |
| 1675 | 2475 | comptime Extra: ?type, |
| ... | ... | @@ -1680,11 +2480,11 @@ fn ensureUnusedCapacityTypes( |
| 1680 | 2480 | if (Extra) |E| try self.type_extra.ensureUnusedCapacity( |
| 1681 | 2481 | self.gpa, |
| 1682 | 2482 | count * (@typeInfo(E).Struct.fields.len + trail_len), |
| 1683 | ); | |
| 2483 | ) else assert(trail_len == 0); | |
| 1684 | 2484 | if (self.useLibLlvm()) try self.llvm_types.ensureUnusedCapacity(self.gpa, count); |
| 1685 | 2485 | } |
| 1686 | 2486 | |
| 1687 | fn typeNoExtraAssumeCapacity(self: *Builder, item: Type.Item) struct { new: bool, type: Type } { | |
| 2487 | fn getOrPutTypeNoExtraAssumeCapacity(self: *Builder, item: Type.Item) struct { new: bool, type: Type } { | |
| 1688 | 2488 | const Adapter = struct { |
| 1689 | 2489 | builder: *const Builder, |
| 1690 | 2490 | pub fn hash(_: @This(), key: Type.Item) u32 { |
| ... | ... | @@ -1693,8 +2493,8 @@ fn typeNoExtraAssumeCapacity(self: *Builder, item: Type.Item) struct { new: bool |
| 1693 | 2493 | std.mem.asBytes(&key), |
| 1694 | 2494 | )); |
| 1695 | 2495 | } |
| 1696 | pub fn eql(ctx: @This(), lhs: Type.Item, _: void, rhs_index: usize) bool { | |
| 1697 | const lhs_bits: u32 = @bitCast(lhs); | |
| 2496 | pub fn eql(ctx: @This(), lhs_key: Type.Item, _: void, rhs_index: usize) bool { | |
| 2497 | const lhs_bits: u32 = @bitCast(lhs_key); | |
| 1698 | 2498 | const rhs_bits: u32 = @bitCast(ctx.builder.type_items.items[rhs_index]); |
| 1699 | 2499 | return lhs_bits == rhs_bits; |
| 1700 | 2500 | } |
| ... | ... | @@ -1708,13 +2508,37 @@ fn typeNoExtraAssumeCapacity(self: *Builder, item: Type.Item) struct { new: bool |
| 1708 | 2508 | return .{ .new = !gop.found_existing, .type = @enumFromInt(gop.index) }; |
| 1709 | 2509 | } |
| 1710 | 2510 | |
| 1711 | fn isValidIdentifier(id: []const u8) bool { | |
| 1712 | for (id, 0..) |character, index| switch (character) { | |
| 1713 | '$', '-', '.', 'A'...'Z', '_', 'a'...'z' => {}, | |
| 1714 | '0'...'9' => if (index == 0) return false, | |
| 1715 | else => return false, | |
| 1716 | }; | |
| 1717 | return true; | |
| 2511 | fn addTypeExtraAssumeCapacity(self: *Builder, extra: anytype) Type.Item.ExtraIndex { | |
| 2512 | const result: Type.Item.ExtraIndex = @intCast(self.type_extra.items.len); | |
| 2513 | inline for (@typeInfo(@TypeOf(extra)).Struct.fields) |field| { | |
| 2514 | const value = @field(extra, field.name); | |
| 2515 | self.type_extra.appendAssumeCapacity(switch (field.type) { | |
| 2516 | u32 => value, | |
| 2517 | String, Type => @intFromEnum(value), | |
| 2518 | else => @compileError("bad field type: " ++ @typeName(field.type)), | |
| 2519 | }); | |
| 2520 | } | |
| 2521 | return result; | |
| 2522 | } | |
| 2523 | ||
| 2524 | fn typeExtraDataTrail( | |
| 2525 | self: *const Builder, | |
| 2526 | comptime T: type, | |
| 2527 | index: Type.Item.ExtraIndex, | |
| 2528 | ) struct { data: T, end: Type.Item.ExtraIndex } { | |
| 2529 | var result: T = undefined; | |
| 2530 | const fields = @typeInfo(T).Struct.fields; | |
| 2531 | inline for (fields, self.type_extra.items[index..][0..fields.len]) |field, data| | |
| 2532 | @field(result, field.name) = switch (field.type) { | |
| 2533 | u32 => data, | |
| 2534 | String, Type => @enumFromInt(data), | |
| 2535 | else => @compileError("bad field type: " ++ @typeName(field.type)), | |
| 2536 | }; | |
| 2537 | return .{ .data = result, .end = index + @as(Type.Item.ExtraIndex, @intCast(fields.len)) }; | |
| 2538 | } | |
| 2539 | ||
| 2540 | fn typeExtraData(self: *const Builder, comptime T: type, index: Type.Item.ExtraIndex) T { | |
| 2541 | return self.typeExtraDataTrail(T, index).data; | |
| 1718 | 2542 | } |
| 1719 | 2543 | |
| 1720 | 2544 | fn bigIntConstAssumeCapacity( |
| ... | ... | @@ -1748,8 +2572,8 @@ fn bigIntConstAssumeCapacity( |
| 1748 | 2572 | const ExtraPtr = *align(@alignOf(std.math.big.Limb)) Constant.Integer; |
| 1749 | 2573 | const Key = struct { tag: Constant.Tag, type: Type, limbs: []const std.math.big.Limb }; |
| 1750 | 2574 | const tag: Constant.Tag = switch (canonical_value.positive) { |
| 1751 | true => .integer_positive, | |
| 1752 | false => .integer_negative, | |
| 2575 | true => .positive_integer, | |
| 2576 | false => .negative_integer, | |
| 1753 | 2577 | }; |
| 1754 | 2578 | const Adapter = struct { |
| 1755 | 2579 | builder: *const Builder, |
| ... | ... | @@ -1759,20 +2583,22 @@ fn bigIntConstAssumeCapacity( |
| 1759 | 2583 | hasher.update(std.mem.sliceAsBytes(key.limbs)); |
| 1760 | 2584 | return @truncate(hasher.final()); |
| 1761 | 2585 | } |
| 1762 | pub fn eql(ctx: @This(), lhs: Key, _: void, rhs_index: usize) bool { | |
| 1763 | if (lhs.tag != ctx.builder.constant_items.items(.tag)[rhs_index]) return false; | |
| 2586 | pub fn eql(ctx: @This(), lhs_key: Key, _: void, rhs_index: usize) bool { | |
| 2587 | if (lhs_key.tag != ctx.builder.constant_items.items(.tag)[rhs_index]) return false; | |
| 1764 | 2588 | const rhs_data = ctx.builder.constant_items.items(.data)[rhs_index]; |
| 1765 | const rhs_extra: ExtraPtr = @ptrCast( | |
| 1766 | ctx.builder.constant_limbs.items[rhs_data..][0..Constant.Integer.limbs], | |
| 1767 | ); | |
| 2589 | const rhs_extra: ExtraPtr = | |
| 2590 | @ptrCast(ctx.builder.constant_limbs.items[rhs_data..][0..Constant.Integer.limbs]); | |
| 1768 | 2591 | const rhs_limbs = ctx.builder.constant_limbs |
| 1769 | 2592 | .items[rhs_data + Constant.Integer.limbs ..][0..rhs_extra.limbs_len]; |
| 1770 | return lhs.type == rhs_extra.type and std.mem.eql(std.math.big.Limb, lhs.limbs, rhs_limbs); | |
| 2593 | return lhs_key.type == rhs_extra.type and | |
| 2594 | std.mem.eql(std.math.big.Limb, lhs_key.limbs, rhs_limbs); | |
| 1771 | 2595 | } |
| 1772 | 2596 | }; |
| 1773 | 2597 | |
| 1774 | const data = Key{ .tag = tag, .type = ty, .limbs = canonical_value.limbs }; | |
| 1775 | const gop = self.constant_map.getOrPutAssumeCapacityAdapted(data, Adapter{ .builder = self }); | |
| 2598 | const gop = self.constant_map.getOrPutAssumeCapacityAdapted( | |
| 2599 | Key{ .tag = tag, .type = ty, .limbs = canonical_value.limbs }, | |
| 2600 | Adapter{ .builder = self }, | |
| 2601 | ); | |
| 1776 | 2602 | if (!gop.found_existing) { |
| 1777 | 2603 | gop.key_ptr.* = {}; |
| 1778 | 2604 | gop.value_ptr.* = {}; |
| ... | ... | @@ -1780,9 +2606,8 @@ fn bigIntConstAssumeCapacity( |
| 1780 | 2606 | .tag = tag, |
| 1781 | 2607 | .data = @intCast(self.constant_limbs.items.len), |
| 1782 | 2608 | }); |
| 1783 | const extra: ExtraPtr = @ptrCast( | |
| 1784 | self.constant_limbs.addManyAsArrayAssumeCapacity(Constant.Integer.limbs), | |
| 1785 | ); | |
| 2609 | const extra: ExtraPtr = | |
| 2610 | @ptrCast(self.constant_limbs.addManyAsArrayAssumeCapacity(Constant.Integer.limbs)); | |
| 1786 | 2611 | extra.* = .{ .type = ty, .limbs_len = @intCast(canonical_value.limbs.len) }; |
| 1787 | 2612 | self.constant_limbs.appendSliceAssumeCapacity(canonical_value.limbs); |
| 1788 | 2613 | if (self.useLibLlvm()) { |
| ... | ... | @@ -1827,6 +2652,870 @@ fn bigIntConstAssumeCapacity( |
| 1827 | 2652 | return @enumFromInt(gop.index); |
| 1828 | 2653 | } |
| 1829 | 2654 | |
| 2655 | fn halfConstAssumeCapacity(self: *Builder, val: f16) Constant { | |
| 2656 | const result = self.getOrPutConstantNoExtraAssumeCapacity( | |
| 2657 | .{ .tag = .half, .data = @as(u16, @bitCast(val)) }, | |
| 2658 | ); | |
| 2659 | if (self.useLibLlvm() and result.new) self.llvm_constants.appendAssumeCapacity( | |
| 2660 | if (std.math.isSignalNan(val)) | |
| 2661 | Type.i16.toLlvm(self).constInt(@as(u16, @bitCast(val)), .False) | |
| 2662 | .constBitCast(Type.half.toLlvm(self)) | |
| 2663 | else | |
| 2664 | Type.half.toLlvm(self).constReal(val), | |
| 2665 | ); | |
| 2666 | return result.constant; | |
| 2667 | } | |
| 2668 | ||
| 2669 | fn bfloatConstAssumeCapacity(self: *Builder, val: f32) Constant { | |
| 2670 | assert(@as(u16, @truncate(@as(u32, @bitCast(val)))) == 0); | |
| 2671 | const result = self.getOrPutConstantNoExtraAssumeCapacity( | |
| 2672 | .{ .tag = .bfloat, .data = @bitCast(val) }, | |
| 2673 | ); | |
| 2674 | if (self.useLibLlvm() and result.new) self.llvm_constants.appendAssumeCapacity( | |
| 2675 | if (std.math.isSignalNan(val)) | |
| 2676 | Type.i16.toLlvm(self).constInt(@as(u32, @bitCast(val)) >> 16, .False) | |
| 2677 | .constBitCast(Type.bfloat.toLlvm(self)) | |
| 2678 | else | |
| 2679 | Type.bfloat.toLlvm(self).constReal(val), | |
| 2680 | ); | |
| 2681 | ||
| 2682 | if (self.useLibLlvm() and result.new) | |
| 2683 | self.llvm_constants.appendAssumeCapacity(Type.bfloat.toLlvm(self).constReal(val)); | |
| 2684 | return result.constant; | |
| 2685 | } | |
| 2686 | ||
| 2687 | fn floatConstAssumeCapacity(self: *Builder, val: f32) Constant { | |
| 2688 | const result = self.getOrPutConstantNoExtraAssumeCapacity( | |
| 2689 | .{ .tag = .float, .data = @bitCast(val) }, | |
| 2690 | ); | |
| 2691 | if (self.useLibLlvm() and result.new) self.llvm_constants.appendAssumeCapacity( | |
| 2692 | if (std.math.isSignalNan(val)) | |
| 2693 | Type.i32.toLlvm(self).constInt(@as(u32, @bitCast(val)), .False) | |
| 2694 | .constBitCast(Type.float.toLlvm(self)) | |
| 2695 | else | |
| 2696 | Type.float.toLlvm(self).constReal(val), | |
| 2697 | ); | |
| 2698 | return result.constant; | |
| 2699 | } | |
| 2700 | ||
| 2701 | fn doubleConstAssumeCapacity(self: *Builder, val: f64) Constant { | |
| 2702 | const Adapter = struct { | |
| 2703 | builder: *const Builder, | |
| 2704 | pub fn hash(_: @This(), key: f64) u32 { | |
| 2705 | return @truncate(std.hash.Wyhash.hash( | |
| 2706 | comptime std.hash.uint32(@intFromEnum(Constant.Tag.double)), | |
| 2707 | std.mem.asBytes(&key), | |
| 2708 | )); | |
| 2709 | } | |
| 2710 | pub fn eql(ctx: @This(), lhs_key: f64, _: void, rhs_index: usize) bool { | |
| 2711 | if (ctx.builder.constant_items.items(.tag)[rhs_index] != .double) return false; | |
| 2712 | const rhs_data = ctx.builder.constant_items.items(.data)[rhs_index]; | |
| 2713 | const rhs_extra = ctx.builder.constantExtraData(Constant.Double, rhs_data); | |
| 2714 | return @as(u64, @bitCast(lhs_key)) == @as(u64, rhs_extra.hi) << 32 | rhs_extra.lo; | |
| 2715 | } | |
| 2716 | }; | |
| 2717 | const gop = self.constant_map.getOrPutAssumeCapacityAdapted(val, Adapter{ .builder = self }); | |
| 2718 | if (!gop.found_existing) { | |
| 2719 | gop.key_ptr.* = {}; | |
| 2720 | gop.value_ptr.* = {}; | |
| 2721 | self.constant_items.appendAssumeCapacity(.{ | |
| 2722 | .tag = .double, | |
| 2723 | .data = self.addConstantExtraAssumeCapacity(Constant.Double{ | |
| 2724 | .lo = @intCast(@as(u64, @bitCast(val)) >> 32), | |
| 2725 | .hi = @truncate(@as(u64, @bitCast(val))), | |
| 2726 | }), | |
| 2727 | }); | |
| 2728 | if (self.useLibLlvm()) self.llvm_constants.appendAssumeCapacity( | |
| 2729 | if (std.math.isSignalNan(val)) | |
| 2730 | Type.i64.toLlvm(self).constInt(@as(u64, @bitCast(val)), .False) | |
| 2731 | .constBitCast(Type.double.toLlvm(self)) | |
| 2732 | else | |
| 2733 | Type.double.toLlvm(self).constReal(val), | |
| 2734 | ); | |
| 2735 | } | |
| 2736 | return @enumFromInt(gop.index); | |
| 2737 | } | |
| 2738 | ||
| 2739 | fn fp128ConstAssumeCapacity(self: *Builder, val: f128) Constant { | |
| 2740 | const Adapter = struct { | |
| 2741 | builder: *const Builder, | |
| 2742 | pub fn hash(_: @This(), key: f128) u32 { | |
| 2743 | return @truncate(std.hash.Wyhash.hash( | |
| 2744 | comptime std.hash.uint32(@intFromEnum(Constant.Tag.fp128)), | |
| 2745 | std.mem.asBytes(&key), | |
| 2746 | )); | |
| 2747 | } | |
| 2748 | pub fn eql(ctx: @This(), lhs_key: f128, _: void, rhs_index: usize) bool { | |
| 2749 | if (ctx.builder.constant_items.items(.tag)[rhs_index] != .fp128) return false; | |
| 2750 | const rhs_data = ctx.builder.constant_items.items(.data)[rhs_index]; | |
| 2751 | const rhs_extra = ctx.builder.constantExtraData(Constant.Fp128, rhs_data); | |
| 2752 | return @as(u128, @bitCast(lhs_key)) == @as(u128, rhs_extra.hi_hi) << 96 | | |
| 2753 | @as(u128, rhs_extra.hi_lo) << 64 | @as(u128, rhs_extra.lo_hi) << 32 | rhs_extra.lo_lo; | |
| 2754 | } | |
| 2755 | }; | |
| 2756 | const gop = self.constant_map.getOrPutAssumeCapacityAdapted(val, Adapter{ .builder = self }); | |
| 2757 | if (!gop.found_existing) { | |
| 2758 | gop.key_ptr.* = {}; | |
| 2759 | gop.value_ptr.* = {}; | |
| 2760 | self.constant_items.appendAssumeCapacity(.{ | |
| 2761 | .tag = .fp128, | |
| 2762 | .data = self.addConstantExtraAssumeCapacity(Constant.Fp128{ | |
| 2763 | .lo_lo = @truncate(@as(u128, @bitCast(val))), | |
| 2764 | .lo_hi = @truncate(@as(u128, @bitCast(val)) >> 32), | |
| 2765 | .hi_lo = @truncate(@as(u128, @bitCast(val)) >> 64), | |
| 2766 | .hi_hi = @intCast(@as(u128, @bitCast(val)) >> 96), | |
| 2767 | }), | |
| 2768 | }); | |
| 2769 | if (self.useLibLlvm()) { | |
| 2770 | const llvm_limbs = [_]u64{ | |
| 2771 | @truncate(@as(u128, @bitCast(val))), | |
| 2772 | @intCast(@as(u128, @bitCast(val)) >> 64), | |
| 2773 | }; | |
| 2774 | self.llvm_constants.appendAssumeCapacity( | |
| 2775 | Type.i128.toLlvm(self) | |
| 2776 | .constIntOfArbitraryPrecision(@intCast(llvm_limbs.len), &llvm_limbs) | |
| 2777 | .constBitCast(Type.fp128.toLlvm(self)), | |
| 2778 | ); | |
| 2779 | } | |
| 2780 | } | |
| 2781 | return @enumFromInt(gop.index); | |
| 2782 | } | |
| 2783 | ||
| 2784 | fn x86_fp80ConstAssumeCapacity(self: *Builder, val: f80) Constant { | |
| 2785 | const Adapter = struct { | |
| 2786 | builder: *const Builder, | |
| 2787 | pub fn hash(_: @This(), key: f80) u32 { | |
| 2788 | return @truncate(std.hash.Wyhash.hash( | |
| 2789 | comptime std.hash.uint32(@intFromEnum(Constant.Tag.x86_fp80)), | |
| 2790 | std.mem.asBytes(&key)[0..10], | |
| 2791 | )); | |
| 2792 | } | |
| 2793 | pub fn eql(ctx: @This(), lhs_key: f80, _: void, rhs_index: usize) bool { | |
| 2794 | if (ctx.builder.constant_items.items(.tag)[rhs_index] != .x86_fp80) return false; | |
| 2795 | const rhs_data = ctx.builder.constant_items.items(.data)[rhs_index]; | |
| 2796 | const rhs_extra = ctx.builder.constantExtraData(Constant.Fp80, rhs_data); | |
| 2797 | return @as(u80, @bitCast(lhs_key)) == @as(u80, rhs_extra.hi) << 64 | | |
| 2798 | @as(u80, rhs_extra.lo_hi) << 32 | rhs_extra.lo_lo; | |
| 2799 | } | |
| 2800 | }; | |
| 2801 | const gop = self.constant_map.getOrPutAssumeCapacityAdapted(val, Adapter{ .builder = self }); | |
| 2802 | if (!gop.found_existing) { | |
| 2803 | gop.key_ptr.* = {}; | |
| 2804 | gop.value_ptr.* = {}; | |
| 2805 | self.constant_items.appendAssumeCapacity(.{ | |
| 2806 | .tag = .x86_fp80, | |
| 2807 | .data = self.addConstantExtraAssumeCapacity(Constant.Fp80{ | |
| 2808 | .lo_lo = @truncate(@as(u80, @bitCast(val))), | |
| 2809 | .lo_hi = @truncate(@as(u80, @bitCast(val)) >> 32), | |
| 2810 | .hi = @intCast(@as(u80, @bitCast(val)) >> 64), | |
| 2811 | }), | |
| 2812 | }); | |
| 2813 | if (self.useLibLlvm()) { | |
| 2814 | const llvm_limbs = [_]u64{ | |
| 2815 | @truncate(@as(u80, @bitCast(val))), | |
| 2816 | @intCast(@as(u80, @bitCast(val)) >> 64), | |
| 2817 | }; | |
| 2818 | self.llvm_constants.appendAssumeCapacity( | |
| 2819 | Type.i80.toLlvm(self) | |
| 2820 | .constIntOfArbitraryPrecision(@intCast(llvm_limbs.len), &llvm_limbs) | |
| 2821 | .constBitCast(Type.x86_fp80.toLlvm(self)), | |
| 2822 | ); | |
| 2823 | } | |
| 2824 | } | |
| 2825 | return @enumFromInt(gop.index); | |
| 2826 | } | |
| 2827 | ||
| 2828 | fn ppc_fp128ConstAssumeCapacity(self: *Builder, val: [2]f64) Constant { | |
| 2829 | const Adapter = struct { | |
| 2830 | builder: *const Builder, | |
| 2831 | pub fn hash(_: @This(), key: [2]f64) u32 { | |
| 2832 | return @truncate(std.hash.Wyhash.hash( | |
| 2833 | comptime std.hash.uint32(@intFromEnum(Constant.Tag.ppc_fp128)), | |
| 2834 | std.mem.asBytes(&key), | |
| 2835 | )); | |
| 2836 | } | |
| 2837 | pub fn eql(ctx: @This(), lhs_key: [2]f64, _: void, rhs_index: usize) bool { | |
| 2838 | if (ctx.builder.constant_items.items(.tag)[rhs_index] != .ppc_fp128) return false; | |
| 2839 | const rhs_data = ctx.builder.constant_items.items(.data)[rhs_index]; | |
| 2840 | const rhs_extra = ctx.builder.constantExtraData(Constant.Fp128, rhs_data); | |
| 2841 | return @as(u64, @bitCast(lhs_key[0])) == @as(u64, rhs_extra.lo_hi) << 32 | rhs_extra.lo_lo and | |
| 2842 | @as(u64, @bitCast(lhs_key[1])) == @as(u64, rhs_extra.hi_hi) << 32 | rhs_extra.hi_lo; | |
| 2843 | } | |
| 2844 | }; | |
| 2845 | const gop = self.constant_map.getOrPutAssumeCapacityAdapted(val, Adapter{ .builder = self }); | |
| 2846 | if (!gop.found_existing) { | |
| 2847 | gop.key_ptr.* = {}; | |
| 2848 | gop.value_ptr.* = {}; | |
| 2849 | self.constant_items.appendAssumeCapacity(.{ | |
| 2850 | .tag = .ppc_fp128, | |
| 2851 | .data = self.addConstantExtraAssumeCapacity(Constant.Fp128{ | |
| 2852 | .lo_lo = @truncate(@as(u64, @bitCast(val[0]))), | |
| 2853 | .lo_hi = @intCast(@as(u64, @bitCast(val[0])) >> 32), | |
| 2854 | .hi_lo = @truncate(@as(u64, @bitCast(val[1]))), | |
| 2855 | .hi_hi = @intCast(@as(u64, @bitCast(val[1])) >> 32), | |
| 2856 | }), | |
| 2857 | }); | |
| 2858 | if (self.useLibLlvm()) { | |
| 2859 | const llvm_limbs: *const [2]u64 = @ptrCast(&val); | |
| 2860 | self.llvm_constants.appendAssumeCapacity( | |
| 2861 | Type.i128.toLlvm(self) | |
| 2862 | .constIntOfArbitraryPrecision(@intCast(llvm_limbs.len), llvm_limbs) | |
| 2863 | .constBitCast(Type.ppc_fp128.toLlvm(self)), | |
| 2864 | ); | |
| 2865 | } | |
| 2866 | } | |
| 2867 | return @enumFromInt(gop.index); | |
| 2868 | } | |
| 2869 | ||
| 2870 | fn nullConstAssumeCapacity(self: *Builder, ty: Type) Constant { | |
| 2871 | assert(self.type_items.items[@intFromEnum(ty)].tag == .pointer); | |
| 2872 | const result = self.getOrPutConstantNoExtraAssumeCapacity( | |
| 2873 | .{ .tag = .null, .data = @intFromEnum(ty) }, | |
| 2874 | ); | |
| 2875 | if (self.useLibLlvm() and result.new) | |
| 2876 | self.llvm_constants.appendAssumeCapacity(ty.toLlvm(self).constNull()); | |
| 2877 | return result.constant; | |
| 2878 | } | |
| 2879 | ||
| 2880 | fn noneConstAssumeCapacity(self: *Builder, ty: Type) Constant { | |
| 2881 | assert(ty == .token); | |
| 2882 | const result = self.getOrPutConstantNoExtraAssumeCapacity( | |
| 2883 | .{ .tag = .none, .data = @intFromEnum(ty) }, | |
| 2884 | ); | |
| 2885 | if (self.useLibLlvm() and result.new) | |
| 2886 | self.llvm_constants.appendAssumeCapacity(ty.toLlvm(self).constNull()); | |
| 2887 | return result.constant; | |
| 2888 | } | |
| 2889 | ||
| 2890 | fn structConstAssumeCapacity( | |
| 2891 | self: *Builder, | |
| 2892 | ty: Type, | |
| 2893 | vals: []const Constant, | |
| 2894 | ) if (build_options.have_llvm) Allocator.Error!Constant else Constant { | |
| 2895 | const type_item = self.type_items.items[@intFromEnum(ty)]; | |
| 2896 | const extra = self.typeExtraDataTrail(Type.Structure, switch (type_item.tag) { | |
| 2897 | .structure, .packed_structure => type_item.data, | |
| 2898 | .named_structure => data: { | |
| 2899 | const body_ty = self.typeExtraData(Type.NamedStructure, type_item.data).body; | |
| 2900 | const body_item = self.type_items.items[@intFromEnum(body_ty)]; | |
| 2901 | switch (body_item.tag) { | |
| 2902 | .structure, .packed_structure => break :data body_item.data, | |
| 2903 | else => unreachable, | |
| 2904 | } | |
| 2905 | }, | |
| 2906 | else => unreachable, | |
| 2907 | }); | |
| 2908 | const fields: []const Type = | |
| 2909 | @ptrCast(self.type_extra.items[extra.end..][0..extra.data.fields_len]); | |
| 2910 | for (fields, vals) |field, val| assert(field == val.typeOf(self)); | |
| 2911 | ||
| 2912 | for (vals) |val| { | |
| 2913 | if (!val.isZeroInit(self)) break; | |
| 2914 | } else return self.zeroInitConstAssumeCapacity(ty); | |
| 2915 | ||
| 2916 | const tag: Constant.Tag = switch (ty.unnamedTag(self)) { | |
| 2917 | .structure => .structure, | |
| 2918 | .packed_structure => .packed_structure, | |
| 2919 | else => unreachable, | |
| 2920 | }; | |
| 2921 | const result = self.getOrPutConstantAggregateAssumeCapacity(tag, ty, vals); | |
| 2922 | if (self.useLibLlvm() and result.new) { | |
| 2923 | const ExpectedContents = [expected_fields_len]*llvm.Value; | |
| 2924 | var stack align(@alignOf(ExpectedContents)) = | |
| 2925 | std.heap.stackFallback(@sizeOf(ExpectedContents), self.gpa); | |
| 2926 | const allocator = stack.get(); | |
| 2927 | ||
| 2928 | const llvm_vals = try allocator.alloc(*llvm.Value, vals.len); | |
| 2929 | defer allocator.free(llvm_vals); | |
| 2930 | for (llvm_vals, vals) |*llvm_val, val| llvm_val.* = val.toLlvm(self); | |
| 2931 | ||
| 2932 | self.llvm_constants.appendAssumeCapacity( | |
| 2933 | ty.toLlvm(self).constNamedStruct(llvm_vals.ptr, @intCast(llvm_vals.len)), | |
| 2934 | ); | |
| 2935 | } | |
| 2936 | return result.constant; | |
| 2937 | } | |
| 2938 | ||
| 2939 | fn arrayConstAssumeCapacity( | |
| 2940 | self: *Builder, | |
| 2941 | ty: Type, | |
| 2942 | vals: []const Constant, | |
| 2943 | ) if (build_options.have_llvm) Allocator.Error!Constant else Constant { | |
| 2944 | const type_item = self.type_items.items[@intFromEnum(ty)]; | |
| 2945 | const type_extra: struct { len: u64, child: Type } = switch (type_item.tag) { | |
| 2946 | .small_array => extra: { | |
| 2947 | const extra = self.typeExtraData(Type.Vector, type_item.data); | |
| 2948 | break :extra .{ .len = extra.len, .child = extra.child }; | |
| 2949 | }, | |
| 2950 | .array => extra: { | |
| 2951 | const extra = self.typeExtraData(Type.Array, type_item.data); | |
| 2952 | break :extra .{ .len = extra.len(), .child = extra.child }; | |
| 2953 | }, | |
| 2954 | else => unreachable, | |
| 2955 | }; | |
| 2956 | assert(type_extra.len == vals.len); | |
| 2957 | for (vals) |val| assert(type_extra.child == val.typeOf(self)); | |
| 2958 | ||
| 2959 | for (vals) |val| { | |
| 2960 | if (!val.isZeroInit(self)) break; | |
| 2961 | } else return self.zeroInitConstAssumeCapacity(ty); | |
| 2962 | ||
| 2963 | const result = self.getOrPutConstantAggregateAssumeCapacity(.array, ty, vals); | |
| 2964 | if (self.useLibLlvm() and result.new) { | |
| 2965 | const ExpectedContents = [expected_fields_len]*llvm.Value; | |
| 2966 | var stack align(@alignOf(ExpectedContents)) = | |
| 2967 | std.heap.stackFallback(@sizeOf(ExpectedContents), self.gpa); | |
| 2968 | const allocator = stack.get(); | |
| 2969 | ||
| 2970 | const llvm_vals = try allocator.alloc(*llvm.Value, vals.len); | |
| 2971 | defer allocator.free(llvm_vals); | |
| 2972 | for (llvm_vals, vals) |*llvm_val, val| llvm_val.* = val.toLlvm(self); | |
| 2973 | ||
| 2974 | self.llvm_constants.appendAssumeCapacity( | |
| 2975 | type_extra.child.toLlvm(self).constArray(llvm_vals.ptr, @intCast(llvm_vals.len)), | |
| 2976 | ); | |
| 2977 | } | |
| 2978 | return result.constant; | |
| 2979 | } | |
| 2980 | ||
| 2981 | fn stringConstAssumeCapacity(self: *Builder, val: String) Constant { | |
| 2982 | const slice = val.toSlice(self).?; | |
| 2983 | const ty = self.arrayTypeAssumeCapacity(slice.len, .i8); | |
| 2984 | if (std.mem.allEqual(u8, slice, 0)) return self.zeroInitConstAssumeCapacity(ty); | |
| 2985 | const result = self.getOrPutConstantNoExtraAssumeCapacity( | |
| 2986 | .{ .tag = .string, .data = @intFromEnum(val) }, | |
| 2987 | ); | |
| 2988 | if (self.useLibLlvm() and result.new) self.llvm_constants.appendAssumeCapacity( | |
| 2989 | self.llvm_context.constString(slice.ptr, @intCast(slice.len), .True), | |
| 2990 | ); | |
| 2991 | return result.constant; | |
| 2992 | } | |
| 2993 | ||
| 2994 | fn stringNullConstAssumeCapacity(self: *Builder, val: String) Constant { | |
| 2995 | const slice = val.toSlice(self).?; | |
| 2996 | const ty = self.arrayTypeAssumeCapacity(slice.len + 1, .i8); | |
| 2997 | if (std.mem.allEqual(u8, slice, 0)) return self.zeroInitConstAssumeCapacity(ty); | |
| 2998 | const result = self.getOrPutConstantNoExtraAssumeCapacity( | |
| 2999 | .{ .tag = .string_null, .data = @intFromEnum(val) }, | |
| 3000 | ); | |
| 3001 | if (self.useLibLlvm() and result.new) self.llvm_constants.appendAssumeCapacity( | |
| 3002 | self.llvm_context.constString(slice.ptr, @intCast(slice.len + 1), .True), | |
| 3003 | ); | |
| 3004 | return result.constant; | |
| 3005 | } | |
| 3006 | ||
| 3007 | fn vectorConstAssumeCapacity( | |
| 3008 | self: *Builder, | |
| 3009 | ty: Type, | |
| 3010 | vals: []const Constant, | |
| 3011 | ) if (build_options.have_llvm) Allocator.Error!Constant else Constant { | |
| 3012 | if (std.debug.runtime_safety) { | |
| 3013 | const type_item = self.type_items.items[@intFromEnum(ty)]; | |
| 3014 | assert(type_item.tag == .vector); | |
| 3015 | const extra = self.typeExtraData(Type.Vector, type_item.data); | |
| 3016 | assert(extra.len == vals.len); | |
| 3017 | for (vals) |val| assert(extra.child == val.typeOf(self)); | |
| 3018 | } | |
| 3019 | ||
| 3020 | for (vals) |val| { | |
| 3021 | if (!val.isZeroInit(self)) break; | |
| 3022 | } else return self.zeroInitConstAssumeCapacity(ty); | |
| 3023 | ||
| 3024 | const result = self.getOrPutConstantAggregateAssumeCapacity(.vector, ty, vals); | |
| 3025 | if (self.useLibLlvm() and result.new) { | |
| 3026 | const ExpectedContents = [expected_fields_len]*llvm.Value; | |
| 3027 | var stack align(@alignOf(ExpectedContents)) = | |
| 3028 | std.heap.stackFallback(@sizeOf(ExpectedContents), self.gpa); | |
| 3029 | const allocator = stack.get(); | |
| 3030 | ||
| 3031 | const llvm_vals = try allocator.alloc(*llvm.Value, vals.len); | |
| 3032 | defer allocator.free(llvm_vals); | |
| 3033 | for (llvm_vals, vals) |*llvm_val, val| llvm_val.* = val.toLlvm(self); | |
| 3034 | ||
| 3035 | self.llvm_constants.appendAssumeCapacity( | |
| 3036 | llvm.constVector(llvm_vals.ptr, @intCast(llvm_vals.len)), | |
| 3037 | ); | |
| 3038 | } | |
| 3039 | return result.constant; | |
| 3040 | } | |
| 3041 | ||
| 3042 | fn zeroInitConstAssumeCapacity(self: *Builder, ty: Type) Constant { | |
| 3043 | switch (self.type_items.items[@intFromEnum(ty)].tag) { | |
| 3044 | .simple, | |
| 3045 | .function, | |
| 3046 | .vararg_function, | |
| 3047 | .integer, | |
| 3048 | .pointer, | |
| 3049 | => unreachable, | |
| 3050 | .target, | |
| 3051 | .vector, | |
| 3052 | .scalable_vector, | |
| 3053 | .small_array, | |
| 3054 | .array, | |
| 3055 | .structure, | |
| 3056 | .packed_structure, | |
| 3057 | .named_structure, | |
| 3058 | => {}, | |
| 3059 | } | |
| 3060 | const result = self.getOrPutConstantNoExtraAssumeCapacity( | |
| 3061 | .{ .tag = .zeroinitializer, .data = @intFromEnum(ty) }, | |
| 3062 | ); | |
| 3063 | if (self.useLibLlvm() and result.new) | |
| 3064 | self.llvm_constants.appendAssumeCapacity(ty.toLlvm(self).constNull()); | |
| 3065 | return result.constant; | |
| 3066 | } | |
| 3067 | ||
| 3068 | fn undefConstAssumeCapacity(self: *Builder, ty: Type) Constant { | |
| 3069 | switch (self.type_items.items[@intFromEnum(ty)].tag) { | |
| 3070 | .simple => switch (ty) { | |
| 3071 | .void, .label => unreachable, | |
| 3072 | else => {}, | |
| 3073 | }, | |
| 3074 | .function, .vararg_function => unreachable, | |
| 3075 | else => {}, | |
| 3076 | } | |
| 3077 | const result = self.getOrPutConstantNoExtraAssumeCapacity( | |
| 3078 | .{ .tag = .undef, .data = @intFromEnum(ty) }, | |
| 3079 | ); | |
| 3080 | if (self.useLibLlvm() and result.new) | |
| 3081 | self.llvm_constants.appendAssumeCapacity(ty.toLlvm(self).getUndef()); | |
| 3082 | return result.constant; | |
| 3083 | } | |
| 3084 | ||
| 3085 | fn poisonConstAssumeCapacity(self: *Builder, ty: Type) Constant { | |
| 3086 | switch (self.type_items.items[@intFromEnum(ty)].tag) { | |
| 3087 | .simple => switch (ty) { | |
| 3088 | .void, .label => unreachable, | |
| 3089 | else => {}, | |
| 3090 | }, | |
| 3091 | .function, .vararg_function => unreachable, | |
| 3092 | else => {}, | |
| 3093 | } | |
| 3094 | const result = self.getOrPutConstantNoExtraAssumeCapacity( | |
| 3095 | .{ .tag = .poison, .data = @intFromEnum(ty) }, | |
| 3096 | ); | |
| 3097 | if (self.useLibLlvm() and result.new) | |
| 3098 | self.llvm_constants.appendAssumeCapacity(ty.toLlvm(self).getUndef()); | |
| 3099 | return result.constant; | |
| 3100 | } | |
| 3101 | ||
| 3102 | fn blockAddrConstAssumeCapacity( | |
| 3103 | self: *Builder, | |
| 3104 | function: Function.Index, | |
| 3105 | block: Function.Block.Index, | |
| 3106 | ) Constant { | |
| 3107 | const Adapter = struct { | |
| 3108 | builder: *const Builder, | |
| 3109 | pub fn hash(_: @This(), key: Constant.BlockAddress) u32 { | |
| 3110 | return @truncate(std.hash.Wyhash.hash( | |
| 3111 | comptime std.hash.uint32(@intFromEnum(Constant.Tag.blockaddress)), | |
| 3112 | std.mem.asBytes(&key), | |
| 3113 | )); | |
| 3114 | } | |
| 3115 | pub fn eql(ctx: @This(), lhs_key: Constant.BlockAddress, _: void, rhs_index: usize) bool { | |
| 3116 | if (ctx.builder.constant_items.items(.tag)[rhs_index] != .blockaddress) return false; | |
| 3117 | const rhs_data = ctx.builder.constant_items.items(.data)[rhs_index]; | |
| 3118 | const rhs_extra = ctx.builder.constantExtraData(Constant.BlockAddress, rhs_data); | |
| 3119 | return std.meta.eql(lhs_key, rhs_extra); | |
| 3120 | } | |
| 3121 | }; | |
| 3122 | const data = Constant.BlockAddress{ .function = function, .block = block }; | |
| 3123 | const gop = self.constant_map.getOrPutAssumeCapacityAdapted(data, Adapter{ .builder = self }); | |
| 3124 | if (!gop.found_existing) { | |
| 3125 | gop.key_ptr.* = {}; | |
| 3126 | gop.value_ptr.* = {}; | |
| 3127 | self.constant_items.appendAssumeCapacity(.{ | |
| 3128 | .tag = .blockaddress, | |
| 3129 | .data = self.addConstantExtraAssumeCapacity(data), | |
| 3130 | }); | |
| 3131 | if (self.useLibLlvm()) self.llvm_constants.appendAssumeCapacity( | |
| 3132 | function.toLlvm(self).blockAddress(block.toValue(self, function).toLlvm(self, function)), | |
| 3133 | ); | |
| 3134 | } | |
| 3135 | return @enumFromInt(gop.index); | |
| 3136 | } | |
| 3137 | ||
| 3138 | fn dsoLocalEquivalentConstAssumeCapacity(self: *Builder, function: Function.Index) Constant { | |
| 3139 | const result = self.getOrPutConstantNoExtraAssumeCapacity( | |
| 3140 | .{ .tag = .dso_local_equivalent, .data = @intFromEnum(function) }, | |
| 3141 | ); | |
| 3142 | if (self.useLibLlvm() and result.new) self.llvm_constants.appendAssumeCapacity(undefined); | |
| 3143 | return result.constant; | |
| 3144 | } | |
| 3145 | ||
| 3146 | fn noCfiConstAssumeCapacity(self: *Builder, function: Function.Index) Constant { | |
| 3147 | const result = self.getOrPutConstantNoExtraAssumeCapacity( | |
| 3148 | .{ .tag = .no_cfi, .data = @intFromEnum(function) }, | |
| 3149 | ); | |
| 3150 | if (self.useLibLlvm() and result.new) self.llvm_constants.appendAssumeCapacity(undefined); | |
| 3151 | return result.constant; | |
| 3152 | } | |
| 3153 | ||
| 3154 | fn convConstAssumeCapacity( | |
| 3155 | self: *Builder, | |
| 3156 | signedness: Constant.Cast.Signedness, | |
| 3157 | arg: Constant, | |
| 3158 | ty: Type, | |
| 3159 | ) Constant { | |
| 3160 | const arg_ty = arg.typeOf(self); | |
| 3161 | if (arg_ty == ty) return arg; | |
| 3162 | return self.castConstAssumeCapacity(switch (arg_ty.scalarTag(self)) { | |
| 3163 | .simple => switch (ty.scalarTag(self)) { | |
| 3164 | .simple => switch (std.math.order(arg_ty.scalarBits(self), ty.scalarBits(self))) { | |
| 3165 | .lt => .fpext, | |
| 3166 | .eq => unreachable, | |
| 3167 | .gt => .fptrunc, | |
| 3168 | }, | |
| 3169 | .integer => switch (signedness) { | |
| 3170 | .unsigned => .fptoui, | |
| 3171 | .signed => .fptosi, | |
| 3172 | .unneeded => unreachable, | |
| 3173 | }, | |
| 3174 | else => unreachable, | |
| 3175 | }, | |
| 3176 | .integer => switch (ty.tag(self)) { | |
| 3177 | .simple => switch (signedness) { | |
| 3178 | .unsigned => .uitofp, | |
| 3179 | .signed => .sitofp, | |
| 3180 | .unneeded => unreachable, | |
| 3181 | }, | |
| 3182 | .integer => switch (std.math.order(arg_ty.scalarBits(self), ty.scalarBits(self))) { | |
| 3183 | .lt => switch (signedness) { | |
| 3184 | .unsigned => .zext, | |
| 3185 | .signed => .sext, | |
| 3186 | .unneeded => unreachable, | |
| 3187 | }, | |
| 3188 | .eq => unreachable, | |
| 3189 | .gt => .trunc, | |
| 3190 | }, | |
| 3191 | .pointer => .inttoptr, | |
| 3192 | else => unreachable, | |
| 3193 | }, | |
| 3194 | .pointer => switch (ty.tag(self)) { | |
| 3195 | .integer => .ptrtoint, | |
| 3196 | .pointer => .addrspacecast, | |
| 3197 | else => unreachable, | |
| 3198 | }, | |
| 3199 | else => unreachable, | |
| 3200 | }, arg, ty); | |
| 3201 | } | |
| 3202 | ||
| 3203 | fn castConstAssumeCapacity(self: *Builder, tag: Constant.Tag, arg: Constant, ty: Type) Constant { | |
| 3204 | const Key = struct { tag: Constant.Tag, cast: Constant.Cast }; | |
| 3205 | const Adapter = struct { | |
| 3206 | builder: *const Builder, | |
| 3207 | pub fn hash(_: @This(), key: Key) u32 { | |
| 3208 | return @truncate(std.hash.Wyhash.hash( | |
| 3209 | std.hash.uint32(@intFromEnum(key.tag)), | |
| 3210 | std.mem.asBytes(&key.cast), | |
| 3211 | )); | |
| 3212 | } | |
| 3213 | pub fn eql(ctx: @This(), lhs_key: Key, _: void, rhs_index: usize) bool { | |
| 3214 | if (lhs_key.tag != ctx.builder.constant_items.items(.tag)[rhs_index]) return false; | |
| 3215 | const rhs_data = ctx.builder.constant_items.items(.data)[rhs_index]; | |
| 3216 | const rhs_extra = ctx.builder.constantExtraData(Constant.Cast, rhs_data); | |
| 3217 | return std.meta.eql(lhs_key.cast, rhs_extra); | |
| 3218 | } | |
| 3219 | }; | |
| 3220 | const data = Key{ .tag = tag, .cast = .{ .arg = arg, .type = ty } }; | |
| 3221 | const gop = self.constant_map.getOrPutAssumeCapacityAdapted(data, Adapter{ .builder = self }); | |
| 3222 | if (!gop.found_existing) { | |
| 3223 | gop.key_ptr.* = {}; | |
| 3224 | gop.value_ptr.* = {}; | |
| 3225 | self.constant_items.appendAssumeCapacity(.{ | |
| 3226 | .tag = tag, | |
| 3227 | .data = self.addConstantExtraAssumeCapacity(data.cast), | |
| 3228 | }); | |
| 3229 | if (self.useLibLlvm()) self.llvm_constants.appendAssumeCapacity(switch (tag) { | |
| 3230 | .trunc => &llvm.Value.constTrunc, | |
| 3231 | .zext => &llvm.Value.constZExt, | |
| 3232 | .sext => &llvm.Value.constSExt, | |
| 3233 | .fptrunc => &llvm.Value.constFPTrunc, | |
| 3234 | .fpext => &llvm.Value.constFPExt, | |
| 3235 | .fptoui => &llvm.Value.constFPToUI, | |
| 3236 | .fptosi => &llvm.Value.constFPToSI, | |
| 3237 | .uitofp => &llvm.Value.constUIToFP, | |
| 3238 | .sitofp => &llvm.Value.constSIToFP, | |
| 3239 | .ptrtoint => &llvm.Value.constPtrToInt, | |
| 3240 | .inttoptr => &llvm.Value.constIntToPtr, | |
| 3241 | .bitcast => &llvm.Value.constBitCast, | |
| 3242 | else => unreachable, | |
| 3243 | }(arg.toLlvm(self), ty.toLlvm(self))); | |
| 3244 | } | |
| 3245 | return @enumFromInt(gop.index); | |
| 3246 | } | |
| 3247 | ||
| 3248 | fn gepConstAssumeCapacity( | |
| 3249 | self: *Builder, | |
| 3250 | comptime kind: Constant.GetElementPtr.Kind, | |
| 3251 | ty: Type, | |
| 3252 | base: Constant, | |
| 3253 | indices: []const Constant, | |
| 3254 | ) if (build_options.have_llvm) Allocator.Error!Constant else Constant { | |
| 3255 | const tag: Constant.Tag = switch (kind) { | |
| 3256 | .normal => .getelementptr, | |
| 3257 | .inbounds => .@"getelementptr inbounds", | |
| 3258 | }; | |
| 3259 | const base_ty = base.typeOf(self); | |
| 3260 | const base_is_vector = base_ty.isVector(self); | |
| 3261 | ||
| 3262 | const VectorInfo = struct { | |
| 3263 | kind: Type.Vector.Kind, | |
| 3264 | len: u32, | |
| 3265 | ||
| 3266 | fn init(vector_ty: Type, builder: *const Builder) @This() { | |
| 3267 | return .{ .kind = vector_ty.vectorKind(builder), .len = vector_ty.vectorLen(builder) }; | |
| 3268 | } | |
| 3269 | }; | |
| 3270 | var vector_info: ?VectorInfo = if (base_is_vector) VectorInfo.init(base_ty, self) else null; | |
| 3271 | for (indices) |index| { | |
| 3272 | const index_ty = index.typeOf(self); | |
| 3273 | switch (index_ty.tag(self)) { | |
| 3274 | .integer => {}, | |
| 3275 | .vector, .scalable_vector => { | |
| 3276 | const index_info = VectorInfo.init(index_ty, self); | |
| 3277 | if (vector_info) |info| | |
| 3278 | assert(std.meta.eql(info, index_info)) | |
| 3279 | else | |
| 3280 | vector_info = index_info; | |
| 3281 | }, | |
| 3282 | else => unreachable, | |
| 3283 | } | |
| 3284 | } | |
| 3285 | if (!base_is_vector) if (vector_info) |info| switch (info.kind) { | |
| 3286 | inline else => |vector_kind| _ = self.vectorTypeAssumeCapacity(vector_kind, info.len, base_ty), | |
| 3287 | }; | |
| 3288 | ||
| 3289 | const Key = struct { type: Type, base: Constant, indices: []const Constant }; | |
| 3290 | const Adapter = struct { | |
| 3291 | builder: *const Builder, | |
| 3292 | pub fn hash(_: @This(), key: Key) u32 { | |
| 3293 | var hasher = std.hash.Wyhash.init(comptime std.hash.uint32(@intFromEnum(tag))); | |
| 3294 | hasher.update(std.mem.asBytes(&key.type)); | |
| 3295 | hasher.update(std.mem.asBytes(&key.base)); | |
| 3296 | hasher.update(std.mem.sliceAsBytes(key.indices)); | |
| 3297 | return @truncate(hasher.final()); | |
| 3298 | } | |
| 3299 | pub fn eql(ctx: @This(), lhs_key: Key, _: void, rhs_index: usize) bool { | |
| 3300 | if (ctx.builder.constant_items.items(.tag)[rhs_index] != tag) return false; | |
| 3301 | const rhs_data = ctx.builder.constant_items.items(.data)[rhs_index]; | |
| 3302 | const rhs_extra = ctx.builder.constantExtraDataTrail(Constant.GetElementPtr, rhs_data); | |
| 3303 | const rhs_indices: []const Constant = @ptrCast(ctx.builder.constant_extra | |
| 3304 | .items[rhs_extra.end..][0..rhs_extra.data.indices_len]); | |
| 3305 | return lhs_key.type == rhs_extra.data.type and lhs_key.base == rhs_extra.data.base and | |
| 3306 | std.mem.eql(Constant, lhs_key.indices, rhs_indices); | |
| 3307 | } | |
| 3308 | }; | |
| 3309 | const data = Key{ .type = ty, .base = base, .indices = indices }; | |
| 3310 | const gop = self.constant_map.getOrPutAssumeCapacityAdapted(data, Adapter{ .builder = self }); | |
| 3311 | if (!gop.found_existing) { | |
| 3312 | gop.key_ptr.* = {}; | |
| 3313 | gop.value_ptr.* = {}; | |
| 3314 | self.constant_items.appendAssumeCapacity(.{ | |
| 3315 | .tag = tag, | |
| 3316 | .data = self.addConstantExtraAssumeCapacity(Constant.GetElementPtr{ | |
| 3317 | .type = ty, | |
| 3318 | .base = base, | |
| 3319 | .indices_len = @intCast(indices.len), | |
| 3320 | }), | |
| 3321 | }); | |
| 3322 | self.constant_extra.appendSliceAssumeCapacity(@ptrCast(indices)); | |
| 3323 | if (self.useLibLlvm()) { | |
| 3324 | const ExpectedContents = [expected_gep_indices_len]*llvm.Value; | |
| 3325 | var stack align(@alignOf(ExpectedContents)) = | |
| 3326 | std.heap.stackFallback(@sizeOf(ExpectedContents), self.gpa); | |
| 3327 | const allocator = stack.get(); | |
| 3328 | ||
| 3329 | const llvm_indices = try allocator.alloc(*llvm.Value, indices.len); | |
| 3330 | defer allocator.free(llvm_indices); | |
| 3331 | for (llvm_indices, indices) |*llvm_index, index| llvm_index.* = index.toLlvm(self); | |
| 3332 | ||
| 3333 | self.llvm_constants.appendAssumeCapacity(switch (kind) { | |
| 3334 | .normal => &llvm.Type.constGEP, | |
| 3335 | .inbounds => &llvm.Type.constInBoundsGEP, | |
| 3336 | }(ty.toLlvm(self), base.toLlvm(self), llvm_indices.ptr, @intCast(indices.len))); | |
| 3337 | } | |
| 3338 | } | |
| 3339 | return @enumFromInt(gop.index); | |
| 3340 | } | |
| 3341 | ||
| 3342 | fn binConstAssumeCapacity( | |
| 3343 | self: *Builder, | |
| 3344 | tag: Constant.Tag, | |
| 3345 | lhs: Constant, | |
| 3346 | rhs: Constant, | |
| 3347 | ) Constant { | |
| 3348 | switch (tag) { | |
| 3349 | .add, .sub, .mul, .shl, .lshr, .ashr, .@"and", .@"or", .xor => {}, | |
| 3350 | else => unreachable, | |
| 3351 | } | |
| 3352 | const Key = struct { tag: Constant.Tag, bin: Constant.Binary }; | |
| 3353 | const Adapter = struct { | |
| 3354 | builder: *const Builder, | |
| 3355 | pub fn hash(_: @This(), key: Key) u32 { | |
| 3356 | return @truncate(std.hash.Wyhash.hash( | |
| 3357 | std.hash.uint32(@intFromEnum(key.tag)), | |
| 3358 | std.mem.asBytes(&key.bin), | |
| 3359 | )); | |
| 3360 | } | |
| 3361 | pub fn eql(ctx: @This(), lhs_key: Key, _: void, rhs_index: usize) bool { | |
| 3362 | if (lhs_key.tag != ctx.builder.constant_items.items(.tag)[rhs_index]) return false; | |
| 3363 | const rhs_data = ctx.builder.constant_items.items(.data)[rhs_index]; | |
| 3364 | const rhs_extra = ctx.builder.constantExtraData(Constant.Binary, rhs_data); | |
| 3365 | return std.meta.eql(lhs_key.bin, rhs_extra); | |
| 3366 | } | |
| 3367 | }; | |
| 3368 | const data = Key{ .tag = tag, .bin = .{ .lhs = lhs, .rhs = rhs } }; | |
| 3369 | const gop = self.constant_map.getOrPutAssumeCapacityAdapted(data, Adapter{ .builder = self }); | |
| 3370 | if (!gop.found_existing) { | |
| 3371 | gop.key_ptr.* = {}; | |
| 3372 | gop.value_ptr.* = {}; | |
| 3373 | self.constant_items.appendAssumeCapacity(.{ | |
| 3374 | .tag = tag, | |
| 3375 | .data = self.addConstantExtraAssumeCapacity(data.bin), | |
| 3376 | }); | |
| 3377 | if (self.useLibLlvm()) self.llvm_constants.appendAssumeCapacity(switch (tag) { | |
| 3378 | .add => &llvm.Value.constAdd, | |
| 3379 | .sub => &llvm.Value.constSub, | |
| 3380 | .mul => &llvm.Value.constMul, | |
| 3381 | .shl => &llvm.Value.constShl, | |
| 3382 | .lshr => &llvm.Value.constLShr, | |
| 3383 | .ashr => &llvm.Value.constAShr, | |
| 3384 | .@"and" => &llvm.Value.constAnd, | |
| 3385 | .@"or" => &llvm.Value.constOr, | |
| 3386 | .xor => &llvm.Value.constXor, | |
| 3387 | else => unreachable, | |
| 3388 | }(lhs.toLlvm(self), rhs.toLlvm(self))); | |
| 3389 | } | |
| 3390 | return @enumFromInt(gop.index); | |
| 3391 | } | |
| 3392 | ||
| 3393 | fn ensureUnusedConstantCapacity( | |
| 3394 | self: *Builder, | |
| 3395 | count: usize, | |
| 3396 | comptime Extra: ?type, | |
| 3397 | trail_len: usize, | |
| 3398 | ) Allocator.Error!void { | |
| 3399 | try self.constant_map.ensureUnusedCapacity(self.gpa, count); | |
| 3400 | try self.constant_items.ensureUnusedCapacity(self.gpa, count); | |
| 3401 | if (Extra) |E| try self.constant_extra.ensureUnusedCapacity( | |
| 3402 | self.gpa, | |
| 3403 | count * (@typeInfo(E).Struct.fields.len + trail_len), | |
| 3404 | ) else assert(trail_len == 0); | |
| 3405 | if (self.useLibLlvm()) try self.llvm_constants.ensureUnusedCapacity(self.gpa, count); | |
| 3406 | } | |
| 3407 | ||
| 3408 | fn getOrPutConstantNoExtraAssumeCapacity( | |
| 3409 | self: *Builder, | |
| 3410 | item: Constant.Item, | |
| 3411 | ) struct { new: bool, constant: Constant } { | |
| 3412 | const Adapter = struct { | |
| 3413 | builder: *const Builder, | |
| 3414 | pub fn hash(_: @This(), key: Constant.Item) u32 { | |
| 3415 | return @truncate(std.hash.Wyhash.hash( | |
| 3416 | std.hash.uint32(@intFromEnum(key.tag)), | |
| 3417 | std.mem.asBytes(&key.data), | |
| 3418 | )); | |
| 3419 | } | |
| 3420 | pub fn eql(ctx: @This(), lhs_key: Constant.Item, _: void, rhs_index: usize) bool { | |
| 3421 | return std.meta.eql(lhs_key, ctx.builder.constant_items.get(rhs_index)); | |
| 3422 | } | |
| 3423 | }; | |
| 3424 | const gop = self.constant_map.getOrPutAssumeCapacityAdapted(item, Adapter{ .builder = self }); | |
| 3425 | if (!gop.found_existing) { | |
| 3426 | gop.key_ptr.* = {}; | |
| 3427 | gop.value_ptr.* = {}; | |
| 3428 | self.constant_items.appendAssumeCapacity(item); | |
| 3429 | } | |
| 3430 | return .{ .new = !gop.found_existing, .constant = @enumFromInt(gop.index) }; | |
| 3431 | } | |
| 3432 | ||
| 3433 | fn getOrPutConstantAggregateAssumeCapacity( | |
| 3434 | self: *Builder, | |
| 3435 | tag: Constant.Tag, | |
| 3436 | ty: Type, | |
| 3437 | vals: []const Constant, | |
| 3438 | ) struct { new: bool, constant: Constant } { | |
| 3439 | switch (tag) { | |
| 3440 | .structure, .packed_structure, .array, .vector => {}, | |
| 3441 | else => unreachable, | |
| 3442 | } | |
| 3443 | const Key = struct { tag: Constant.Tag, type: Type, vals: []const Constant }; | |
| 3444 | const Adapter = struct { | |
| 3445 | builder: *const Builder, | |
| 3446 | pub fn hash(_: @This(), key: Key) u32 { | |
| 3447 | var hasher = std.hash.Wyhash.init(std.hash.uint32(@intFromEnum(key.tag))); | |
| 3448 | hasher.update(std.mem.asBytes(&key.type)); | |
| 3449 | hasher.update(std.mem.sliceAsBytes(key.vals)); | |
| 3450 | return @truncate(hasher.final()); | |
| 3451 | } | |
| 3452 | pub fn eql(ctx: @This(), lhs_key: Key, _: void, rhs_index: usize) bool { | |
| 3453 | if (lhs_key.tag != ctx.builder.constant_items.items(.tag)[rhs_index]) return false; | |
| 3454 | const rhs_data = ctx.builder.constant_items.items(.data)[rhs_index]; | |
| 3455 | const rhs_extra = ctx.builder.constantExtraDataTrail(Constant.Aggregate, rhs_data); | |
| 3456 | if (lhs_key.type != rhs_extra.data.type) return false; | |
| 3457 | const rhs_vals: []const Constant = | |
| 3458 | @ptrCast(ctx.builder.constant_extra.items[rhs_extra.end..][0..lhs_key.vals.len]); | |
| 3459 | return std.mem.eql(Constant, lhs_key.vals, rhs_vals); | |
| 3460 | } | |
| 3461 | }; | |
| 3462 | const gop = self.constant_map.getOrPutAssumeCapacityAdapted( | |
| 3463 | Key{ .tag = tag, .type = ty, .vals = vals }, | |
| 3464 | Adapter{ .builder = self }, | |
| 3465 | ); | |
| 3466 | if (!gop.found_existing) { | |
| 3467 | gop.key_ptr.* = {}; | |
| 3468 | gop.value_ptr.* = {}; | |
| 3469 | self.constant_items.appendAssumeCapacity(.{ | |
| 3470 | .tag = tag, | |
| 3471 | .data = self.addConstantExtraAssumeCapacity(Constant.Aggregate{ .type = ty }), | |
| 3472 | }); | |
| 3473 | self.constant_extra.appendSliceAssumeCapacity(@ptrCast(vals)); | |
| 3474 | } | |
| 3475 | return .{ .new = !gop.found_existing, .constant = @enumFromInt(gop.index) }; | |
| 3476 | } | |
| 3477 | ||
| 3478 | fn addConstantExtraAssumeCapacity(self: *Builder, extra: anytype) Constant.Item.ExtraIndex { | |
| 3479 | const result: Constant.Item.ExtraIndex = @intCast(self.constant_extra.items.len); | |
| 3480 | inline for (@typeInfo(@TypeOf(extra)).Struct.fields) |field| { | |
| 3481 | const value = @field(extra, field.name); | |
| 3482 | self.constant_extra.appendAssumeCapacity(switch (field.type) { | |
| 3483 | u32 => value, | |
| 3484 | Type, | |
| 3485 | Constant, | |
| 3486 | Function.Index, | |
| 3487 | Function.Block.Index, | |
| 3488 | => @intFromEnum(value), | |
| 3489 | else => @compileError("bad field type: " ++ @typeName(field.type)), | |
| 3490 | }); | |
| 3491 | } | |
| 3492 | return result; | |
| 3493 | } | |
| 3494 | ||
| 3495 | fn constantExtraDataTrail( | |
| 3496 | self: *const Builder, | |
| 3497 | comptime T: type, | |
| 3498 | index: Constant.Item.ExtraIndex, | |
| 3499 | ) struct { data: T, end: Constant.Item.ExtraIndex } { | |
| 3500 | var result: T = undefined; | |
| 3501 | const fields = @typeInfo(T).Struct.fields; | |
| 3502 | inline for (fields, self.constant_extra.items[index..][0..fields.len]) |field, data| | |
| 3503 | @field(result, field.name) = switch (field.type) { | |
| 3504 | u32 => data, | |
| 3505 | Type, | |
| 3506 | Constant, | |
| 3507 | Function.Index, | |
| 3508 | Function.Block.Index, | |
| 3509 | => @enumFromInt(data), | |
| 3510 | else => @compileError("bad field type: " ++ @typeName(field.type)), | |
| 3511 | }; | |
| 3512 | return .{ .data = result, .end = index + @as(Constant.Item.ExtraIndex, @intCast(fields.len)) }; | |
| 3513 | } | |
| 3514 | ||
| 3515 | fn constantExtraData(self: *const Builder, comptime T: type, index: Constant.Item.ExtraIndex) T { | |
| 3516 | return self.constantExtraDataTrail(T, index).data; | |
| 3517 | } | |
| 3518 | ||
| 1830 | 3519 | inline fn useLibLlvm(self: *const Builder) bool { |
| 1831 | 3520 | return build_options.have_llvm and self.use_lib_llvm; |
| 1832 | 3521 | } |
src/codegen/llvm/bindings.zig+64-11| ... | ... | @@ -168,23 +168,41 @@ pub const Value = opaque { |
| 168 | 168 | pub const setAliasee = LLVMAliasSetAliasee; |
| 169 | 169 | extern fn LLVMAliasSetAliasee(Alias: *Value, Aliasee: *Value) void; |
| 170 | 170 | |
| 171 | pub const constBitCast = LLVMConstBitCast; | |
| 172 | extern fn LLVMConstBitCast(ConstantVal: *Value, ToType: *Type) *Value; | |
| 171 | pub const constTrunc = LLVMConstTrunc; | |
| 172 | extern fn LLVMConstTrunc(ConstantVal: *Value, ToType: *Type) *Value; | |
| 173 | 173 | |
| 174 | pub const constIntToPtr = LLVMConstIntToPtr; | |
| 175 | extern fn LLVMConstIntToPtr(ConstantVal: *Value, ToType: *Type) *Value; | |
| 174 | pub const constSExt = LLVMConstSExt; | |
| 175 | extern fn LLVMConstSExt(ConstantVal: *Value, ToType: *Type) *Value; | |
| 176 | ||
| 177 | pub const constZExt = LLVMConstZExt; | |
| 178 | extern fn LLVMConstZExt(ConstantVal: *Value, ToType: *Type) *Value; | |
| 179 | ||
| 180 | pub const constFPTrunc = LLVMConstFPTrunc; | |
| 181 | extern fn LLVMConstFPTrunc(ConstantVal: *Value, ToType: *Type) *Value; | |
| 182 | ||
| 183 | pub const constFPExt = LLVMConstFPExt; | |
| 184 | extern fn LLVMConstFPExt(ConstantVal: *Value, ToType: *Type) *Value; | |
| 185 | ||
| 186 | pub const constUIToFP = LLVMConstUIToFP; | |
| 187 | extern fn LLVMConstUIToFP(ConstantVal: *Value, ToType: *Type) *Value; | |
| 188 | ||
| 189 | pub const constSIToFP = LLVMConstSIToFP; | |
| 190 | extern fn LLVMConstSIToFP(ConstantVal: *Value, ToType: *Type) *Value; | |
| 191 | ||
| 192 | pub const constFPToUI = LLVMConstFPToUI; | |
| 193 | extern fn LLVMConstFPToUI(ConstantVal: *Value, ToType: *Type) *Value; | |
| 194 | ||
| 195 | pub const constFPToSI = LLVMConstFPToSI; | |
| 196 | extern fn LLVMConstFPToSI(ConstantVal: *Value, ToType: *Type) *Value; | |
| 176 | 197 | |
| 177 | 198 | pub const constPtrToInt = LLVMConstPtrToInt; |
| 178 | 199 | extern fn LLVMConstPtrToInt(ConstantVal: *Value, ToType: *Type) *Value; |
| 179 | 200 | |
| 180 | pub const constShl = LLVMConstShl; | |
| 181 | extern fn LLVMConstShl(LHSConstant: *Value, RHSConstant: *Value) *Value; | |
| 182 | ||
| 183 | pub const constOr = LLVMConstOr; | |
| 184 | extern fn LLVMConstOr(LHSConstant: *Value, RHSConstant: *Value) *Value; | |
| 201 | pub const constIntToPtr = LLVMConstIntToPtr; | |
| 202 | extern fn LLVMConstIntToPtr(ConstantVal: *Value, ToType: *Type) *Value; | |
| 185 | 203 | |
| 186 | pub const constZExt = LLVMConstZExt; | |
| 187 | extern fn LLVMConstZExt(ConstantVal: *Value, ToType: *Type) *Value; | |
| 204 | pub const constBitCast = LLVMConstBitCast; | |
| 205 | extern fn LLVMConstBitCast(ConstantVal: *Value, ToType: *Type) *Value; | |
| 188 | 206 | |
| 189 | 207 | pub const constZExtOrBitCast = LLVMConstZExtOrBitCast; |
| 190 | 208 | extern fn LLVMConstZExtOrBitCast(ConstantVal: *Value, ToType: *Type) *Value; |
| ... | ... | @@ -195,6 +213,30 @@ pub const Value = opaque { |
| 195 | 213 | pub const constAdd = LLVMConstAdd; |
| 196 | 214 | extern fn LLVMConstAdd(LHSConstant: *Value, RHSConstant: *Value) *Value; |
| 197 | 215 | |
| 216 | pub const constSub = LLVMConstSub; | |
| 217 | extern fn LLVMConstSub(LHSConstant: *Value, RHSConstant: *Value) *Value; | |
| 218 | ||
| 219 | pub const constMul = LLVMConstMul; | |
| 220 | extern fn LLVMConstMul(LHSConstant: *Value, RHSConstant: *Value) *Value; | |
| 221 | ||
| 222 | pub const constAnd = LLVMConstAnd; | |
| 223 | extern fn LLVMConstAnd(LHSConstant: *Value, RHSConstant: *Value) *Value; | |
| 224 | ||
| 225 | pub const constOr = LLVMConstOr; | |
| 226 | extern fn LLVMConstOr(LHSConstant: *Value, RHSConstant: *Value) *Value; | |
| 227 | ||
| 228 | pub const constXor = LLVMConstXor; | |
| 229 | extern fn LLVMConstXor(LHSConstant: *Value, RHSConstant: *Value) *Value; | |
| 230 | ||
| 231 | pub const constShl = LLVMConstShl; | |
| 232 | extern fn LLVMConstShl(LHSConstant: *Value, RHSConstant: *Value) *Value; | |
| 233 | ||
| 234 | pub const constLShr = LLVMConstLShr; | |
| 235 | extern fn LLVMConstLShr(LHSConstant: *Value, RHSConstant: *Value) *Value; | |
| 236 | ||
| 237 | pub const constAShr = LLVMConstAShr; | |
| 238 | extern fn LLVMConstAShr(LHSConstant: *Value, RHSConstant: *Value) *Value; | |
| 239 | ||
| 198 | 240 | pub const constAddrSpaceCast = LLVMConstAddrSpaceCast; |
| 199 | 241 | extern fn LLVMConstAddrSpaceCast(ConstantVal: *Value, ToType: *Type) *Value; |
| 200 | 242 | |
| ... | ... | @@ -281,6 +323,9 @@ pub const Value = opaque { |
| 281 | 323 | pub const attachMetaData = ZigLLVMAttachMetaData; |
| 282 | 324 | extern fn ZigLLVMAttachMetaData(GlobalVar: *Value, DIG: *DIGlobalVariableExpression) void; |
| 283 | 325 | |
| 326 | pub const blockAddress = LLVMBlockAddress; | |
| 327 | extern fn LLVMBlockAddress(F: *Value, BB: *BasicBlock) *Value; | |
| 328 | ||
| 284 | 329 | pub const dump = LLVMDumpValue; |
| 285 | 330 | extern fn LLVMDumpValue(Val: *Value) void; |
| 286 | 331 | }; |
| ... | ... | @@ -349,6 +394,14 @@ pub const Type = opaque { |
| 349 | 394 | pub const isSized = LLVMTypeIsSized; |
| 350 | 395 | extern fn LLVMTypeIsSized(Ty: *Type) Bool; |
| 351 | 396 | |
| 397 | pub const constGEP = LLVMConstGEP2; | |
| 398 | extern fn LLVMConstGEP2( | |
| 399 | Ty: *Type, | |
| 400 | ConstantVal: *Value, | |
| 401 | ConstantIndices: [*]const *Value, | |
| 402 | NumIndices: c_uint, | |
| 403 | ) *Value; | |
| 404 | ||
| 352 | 405 | pub const constInBoundsGEP = LLVMConstInBoundsGEP2; |
| 353 | 406 | extern fn LLVMConstInBoundsGEP2( |
| 354 | 407 | Ty: *Type, |