| ... | @@ -579,7 +579,7 @@ pub const Object = struct { | ... | @@ -579,7 +579,7 @@ pub const Object = struct { |
| 579 | /// The LLVM global table which holds the names corresponding to Zig errors. | 579 | /// The LLVM global table which holds the names corresponding to Zig errors. |
| 580 | /// Note that the values are not added until flushModule, when all errors in | 580 | /// Note that the values are not added until flushModule, when all errors in |
| 581 | /// the compilation are known. | 581 | /// the compilation are known. |
| 582 | error_name_table: ?*llvm.Value, | 582 | error_name_table: Builder.Variable.Index, |
| 583 | /// This map is usually very close to empty. It tracks only the cases when a | 583 | /// This map is usually very close to empty. It tracks only the cases when a |
| 584 | /// second extern Decl could not be emitted with the correct name due to a | 584 | /// second extern Decl could not be emitted with the correct name due to a |
| 585 | /// name collision. | 585 | /// name collision. |
| ... | @@ -763,7 +763,7 @@ pub const Object = struct { | ... | @@ -763,7 +763,7 @@ pub const Object = struct { |
| 763 | .named_enum_map = .{}, | 763 | .named_enum_map = .{}, |
| 764 | .type_map = .{}, | 764 | .type_map = .{}, |
| 765 | .di_type_map = .{}, | 765 | .di_type_map = .{}, |
| 766 | .error_name_table = null, | 766 | .error_name_table = .none, |
| 767 | .extern_collisions = .{}, | 767 | .extern_collisions = .{}, |
| 768 | .null_opt_addr = null, | 768 | .null_opt_addr = null, |
| 769 | }; | 769 | }; |
| ... | @@ -803,51 +803,85 @@ pub const Object = struct { | ... | @@ -803,51 +803,85 @@ pub const Object = struct { |
| 803 | return slice.ptr; | 803 | return slice.ptr; |
| 804 | } | 804 | } |
| 805 | | 805 | |
| 806 | fn genErrorNameTable(o: *Object) !void { | 806 | fn genErrorNameTable(o: *Object) Allocator.Error!void { |
| 807 | // If o.error_name_table is null, there was no instruction that actually referenced the error table. | 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 | const mod = o.module; | 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 | // TODO: Address space | 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 | const slice_ty = Type.slice_const_u8_sentinel_0; | 818 | const slice_ty = Type.slice_const_u8_sentinel_0; |
| 816 | const slice_alignment = slice_ty.abiAlignment(mod); | 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(); | 824 | llvm_errors[0] = try o.builder.undefConst(llvm_slice_ty); |
| 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(); | | |
| 823 | for (llvm_errors[1..], error_name_list[1..]) |*llvm_error, name_nts| { | 825 | for (llvm_errors[1..], error_name_list[1..]) |*llvm_error, name_nts| { |
| 824 | const name = mod.intern_pool.stringToSlice(name_nts); | 826 | const name = try o.builder.string(mod.intern_pool.stringToSlice(name_nts)); |
| 825 | const str_init = o.context.constString(name.ptr, @as(c_uint, @intCast(name.len)), .False); | 827 | const str_init = try o.builder.stringNullConst(name); |
| 826 | const str_global = o.llvm_module.addGlobal(str_init.typeOf(), ""); | 828 | const str_ty = str_init.typeOf(&o.builder); |
| 827 | str_global.setInitializer(str_init); | 829 | const str_global = o.llvm_module.addGlobal(str_ty.toLlvm(&o.builder), ""); |
| | 830 | str_global.setInitializer(str_init.toLlvm(&o.builder)); |
| 828 | str_global.setLinkage(.Private); | 831 | str_global.setLinkage(.Private); |
| 829 | str_global.setGlobalConstant(.True); | 832 | str_global.setGlobalConstant(.True); |
| 830 | str_global.setUnnamedAddr(.True); | 833 | str_global.setUnnamedAddr(.True); |
| 831 | str_global.setAlignment(1); | 834 | str_global.setAlignment(1); |
| 832 | | 835 | |
| 833 | const slice_fields = [_]*llvm.Value{ | 836 | var global = Builder.Global{ |
| 834 | str_global, | 837 | .linkage = .private, |
| 835 | (try o.builder.intConst(llvm_usize_ty, name.len)).toLlvm(&o.builder), | 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); | 843 | var variable = Builder.Variable{ |
| 838 | } | 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(), ""); | 858 | const error_name_table_init = try o.builder.arrayConst(llvm_table_ty, llvm_errors); |
| 843 | error_name_table_global.setInitializer(error_name_table_init); | 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 | error_name_table_global.setLinkage(.Private); | 861 | error_name_table_global.setLinkage(.Private); |
| 845 | error_name_table_global.setGlobalConstant(.True); | 862 | error_name_table_global.setGlobalConstant(.True); |
| 846 | error_name_table_global.setUnnamedAddr(.True); | 863 | error_name_table_global.setUnnamedAddr(.True); |
| 847 | error_name_table_global.setAlignment(slice_alignment); // TODO: Dont hardcode | 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 | const error_name_table_ptr = error_name_table_global; | 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 | fn genCmpLtErrorsLenFunction(object: *Object) !void { | 887 | fn genCmpLtErrorsLenFunction(object: *Object) !void { |
| ... | @@ -1116,9 +1150,9 @@ pub const Object = struct { | ... | @@ -1116,9 +1150,9 @@ pub const Object = struct { |
| 1116 | .err_msg = null, | 1150 | .err_msg = null, |
| 1117 | }; | 1151 | }; |
| 1118 | | 1152 | |
| 1119 | const function_index = try o.resolveLlvmFunction(decl_index); | 1153 | const function = try o.resolveLlvmFunction(decl_index); |
| 1120 | const function = function_index.ptr(&o.builder); | 1154 | const global = function.ptrConst(&o.builder).global; |
| 1121 | const llvm_func = function.global.toLlvm(&o.builder); | 1155 | const llvm_func = global.toLlvm(&o.builder); |
| 1122 | | 1156 | |
| 1123 | if (func.analysis(ip).is_noinline) { | 1157 | if (func.analysis(ip).is_noinline) { |
| 1124 | o.addFnAttr(llvm_func, "noinline"); | 1158 | o.addFnAttr(llvm_func, "noinline"); |
| ... | @@ -1155,8 +1189,10 @@ pub const Object = struct { | ... | @@ -1155,8 +1189,10 @@ pub const Object = struct { |
| 1155 | o.addFnAttrString(llvm_func, "no-stack-arg-probe", ""); | 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 | llvm_func.setSection(section); | 1194 | llvm_func.setSection(section); |
| | 1195 | } |
| 1160 | | 1196 | |
| 1161 | // Remove all the basic blocks of a function in order to start over, generating | 1197 | // Remove all the basic blocks of a function in order to start over, generating |
| 1162 | // LLVM IR from an empty function body. | 1198 | // LLVM IR from an empty function body. |
| ... | @@ -1166,7 +1202,7 @@ pub const Object = struct { | ... | @@ -1166,7 +1202,7 @@ pub const Object = struct { |
| 1166 | | 1202 | |
| 1167 | const builder = o.context.createBuilder(); | 1203 | const builder = o.context.createBuilder(); |
| 1168 | | 1204 | |
| 1169 | function.body = {}; | 1205 | function.ptr(&o.builder).body = {}; |
| 1170 | const entry_block = o.context.appendBasicBlock(llvm_func, "Entry"); | 1206 | const entry_block = o.context.appendBasicBlock(llvm_func, "Entry"); |
| 1171 | builder.positionBuilderAtEnd(entry_block); | 1207 | builder.positionBuilderAtEnd(entry_block); |
| 1172 | | 1208 | |
| ... | @@ -1487,8 +1523,8 @@ pub const Object = struct { | ... | @@ -1487,8 +1523,8 @@ pub const Object = struct { |
| 1487 | const gpa = mod.gpa; | 1523 | const gpa = mod.gpa; |
| 1488 | // If the module does not already have the function, we ignore this function call | 1524 | // If the module does not already have the function, we ignore this function call |
| 1489 | // because we call `updateDeclExports` at the end of `updateFunc` and `updateDecl`. | 1525 | // because we call `updateDeclExports` at the end of `updateFunc` and `updateDecl`. |
| 1490 | const global_index = self.decl_map.get(decl_index) orelse return; | 1526 | const global = self.decl_map.get(decl_index) orelse return; |
| 1491 | const llvm_global = global_index.toLlvm(&self.builder); | 1527 | const llvm_global = global.toLlvm(&self.builder); |
| 1492 | const decl = mod.declPtr(decl_index); | 1528 | const decl = mod.declPtr(decl_index); |
| 1493 | if (decl.isExtern(mod)) { | 1529 | if (decl.isExtern(mod)) { |
| 1494 | const decl_name = decl_name: { | 1530 | const decl_name = decl_name: { |
| ... | @@ -1511,18 +1547,17 @@ pub const Object = struct { | ... | @@ -1511,18 +1547,17 @@ pub const Object = struct { |
| 1511 | } | 1547 | } |
| 1512 | } | 1548 | } |
| 1513 | | 1549 | |
| 1514 | try global_index.rename(&self.builder, decl_name); | 1550 | try global.rename(&self.builder, decl_name); |
| 1515 | const decl_name_slice = decl_name.toSlice(&self.builder).?; | 1551 | global.ptr(&self.builder).unnamed_addr = .default; |
| 1516 | const global = global_index.ptr(&self.builder); | | |
| 1517 | global.unnamed_addr = .default; | | |
| 1518 | llvm_global.setUnnamedAddr(.False); | 1552 | llvm_global.setUnnamedAddr(.False); |
| 1519 | global.linkage = .external; | 1553 | global.ptr(&self.builder).linkage = .external; |
| 1520 | llvm_global.setLinkage(.External); | 1554 | llvm_global.setLinkage(.External); |
| 1521 | if (mod.wantDllExports()) { | 1555 | if (mod.wantDllExports()) { |
| 1522 | global.dll_storage_class = .default; | 1556 | global.ptr(&self.builder).dll_storage_class = .default; |
| 1523 | llvm_global.setDLLStorageClass(.Default); | 1557 | llvm_global.setDLLStorageClass(.Default); |
| 1524 | } | 1558 | } |
| 1525 | if (self.di_map.get(decl)) |di_node| { | 1559 | if (self.di_map.get(decl)) |di_node| { |
| | 1560 | const decl_name_slice = decl_name.toSlice(&self.builder).?; |
| 1526 | if (try decl.isFunction(mod)) { | 1561 | if (try decl.isFunction(mod)) { |
| 1527 | const di_func = @as(*llvm.DISubprogram, @ptrCast(di_node)); | 1562 | const di_func = @as(*llvm.DISubprogram, @ptrCast(di_node)); |
| 1528 | const linkage_name = llvm.MDString.get(self.context, decl_name_slice.ptr, decl_name_slice.len); | 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,21 +1568,31 @@ pub const Object = struct { |
| 1533 | di_global.replaceLinkageName(linkage_name); | 1568 | di_global.replaceLinkageName(linkage_name); |
| 1534 | } | 1569 | } |
| 1535 | } | 1570 | } |
| 1536 | if (decl.val.getVariable(mod)) |variable| { | 1571 | if (decl.val.getVariable(mod)) |decl_var| { |
| 1537 | if (variable.is_threadlocal) { | 1572 | if (decl_var.is_threadlocal) { |
| | 1573 | global.ptrConst(&self.builder).kind.variable.ptr(&self.builder).thread_local = |
| | 1574 | .generaldynamic; |
| 1538 | llvm_global.setThreadLocalMode(.GeneralDynamicTLSModel); | 1575 | llvm_global.setThreadLocalMode(.GeneralDynamicTLSModel); |
| 1539 | } else { | 1576 | } else { |
| | 1577 | global.ptrConst(&self.builder).kind.variable.ptr(&self.builder).thread_local = |
| | 1578 | .default; |
| 1540 | llvm_global.setThreadLocalMode(.NotThreadLocal); | 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 | llvm_global.setLinkage(.ExternalWeak); | 1583 | llvm_global.setLinkage(.ExternalWeak); |
| 1544 | } | 1584 | } |
| 1545 | } | 1585 | } |
| | 1586 | global.ptr(&self.builder).updateAttributes(); |
| 1546 | } else if (exports.len != 0) { | 1587 | } else if (exports.len != 0) { |
| 1547 | const exp_name = try self.builder.string(mod.intern_pool.stringToSlice(exports[0].opts.name)); | 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 | llvm_global.setUnnamedAddr(.False); | 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 | if (self.di_map.get(decl)) |di_node| { | 1596 | if (self.di_map.get(decl)) |di_node| { |
| 1552 | const exp_name_slice = exp_name.toSlice(&self.builder).?; | 1597 | const exp_name_slice = exp_name.toSlice(&self.builder).?; |
| 1553 | if (try decl.isFunction(mod)) { | 1598 | if (try decl.isFunction(mod)) { |
| ... | @@ -1562,23 +1607,45 @@ pub const Object = struct { | ... | @@ -1562,23 +1607,45 @@ pub const Object = struct { |
| 1562 | } | 1607 | } |
| 1563 | switch (exports[0].opts.linkage) { | 1608 | switch (exports[0].opts.linkage) { |
| 1564 | .Internal => unreachable, | 1609 | .Internal => unreachable, |
| 1565 | .Strong => llvm_global.setLinkage(.External), | 1610 | .Strong => { |
| 1566 | .Weak => llvm_global.setLinkage(.WeakODR), | 1611 | global.ptr(&self.builder).linkage = .external; |
| 1567 | .LinkOnce => llvm_global.setLinkage(.LinkOnceODR), | 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 | switch (exports[0].opts.visibility) { | 1623 | switch (exports[0].opts.visibility) { |
| 1570 | .default => llvm_global.setVisibility(.Default), | 1624 | .default => { |
| 1571 | .hidden => llvm_global.setVisibility(.Hidden), | 1625 | global.ptr(&self.builder).visibility = .default; |
| 1572 | .protected => llvm_global.setVisibility(.Protected), | 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 | if (mod.intern_pool.stringToSliceUnwrap(exports[0].opts.section)) |section| { | 1637 | if (mod.intern_pool.stringToSliceUnwrap(exports[0].opts.section)) |section| { |
| | 1638 | global.ptr(&self.builder).section = try self.builder.string(section); |
| 1575 | llvm_global.setSection(section); | 1639 | llvm_global.setSection(section); |
| 1576 | } | 1640 | } |
| 1577 | if (decl.val.getVariable(mod)) |variable| { | 1641 | if (decl.val.getVariable(mod)) |decl_var| { |
| 1578 | if (variable.is_threadlocal) { | 1642 | if (decl_var.is_threadlocal) { |
| | 1643 | global.ptrConst(&self.builder).kind.variable.ptr(&self.builder).thread_local = |
| | 1644 | .generaldynamic; |
| 1579 | llvm_global.setThreadLocalMode(.GeneralDynamicTLSModel); | 1645 | llvm_global.setThreadLocalMode(.GeneralDynamicTLSModel); |
| 1580 | } | 1646 | } |
| 1581 | } | 1647 | } |
| | 1648 | global.ptr(&self.builder).updateAttributes(); |
| 1582 | | 1649 | |
| 1583 | // If a Decl is exported more than one time (which is rare), | 1650 | // If a Decl is exported more than one time (which is rare), |
| 1584 | // we add aliases for all but the first export. | 1651 | // we add aliases for all but the first export. |
| ... | @@ -1602,18 +1669,28 @@ pub const Object = struct { | ... | @@ -1602,18 +1669,28 @@ pub const Object = struct { |
| 1602 | } | 1669 | } |
| 1603 | } else { | 1670 | } else { |
| 1604 | const fqn = try self.builder.string(mod.intern_pool.stringToSlice(try decl.getFullyQualifiedName(mod))); | 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 | llvm_global.setLinkage(.Internal); | 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 | llvm_global.setUnnamedAddr(.True); | 1680 | llvm_global.setUnnamedAddr(.True); |
| 1609 | if (decl.val.getVariable(mod)) |variable| { | 1681 | if (decl.val.getVariable(mod)) |decl_var| { |
| 1610 | const single_threaded = mod.comp.bin_file.options.single_threaded; | 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 | llvm_global.setThreadLocalMode(.GeneralDynamicTLSModel); | 1686 | llvm_global.setThreadLocalMode(.GeneralDynamicTLSModel); |
| 1613 | } else { | 1687 | } else { |
| | 1688 | global.ptrConst(&self.builder).kind.variable.ptr(&self.builder).thread_local = |
| | 1689 | .default; |
| 1614 | llvm_global.setThreadLocalMode(.NotThreadLocal); | 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,31 +2735,44 @@ pub const Object = struct { |
| 2658 | const mod = o.module; | 2735 | const mod = o.module; |
| 2659 | const target = mod.getTarget(); | 2736 | const target = mod.getTarget(); |
| 2660 | const ty = try mod.intern(.{ .opt_type = .usize_type }); | 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 | .ty = ty, | 2740 | .ty = ty, |
| 2663 | .val = .none, | 2741 | .val = .none, |
| 2664 | } }); | 2742 | } })); |
| 2665 | | 2743 | const llvm_ty = llvm_init.typeOf(&o.builder); |
| 2666 | const llvm_init = try o.lowerValue(.{ | | |
| 2667 | .ty = ty.toType(), | | |
| 2668 | .val = null_opt_usize.toValue(), | | |
| 2669 | }); | | |
| 2670 | const llvm_wanted_addrspace = toLlvmAddressSpace(.generic, target); | 2744 | const llvm_wanted_addrspace = toLlvmAddressSpace(.generic, target); |
| 2671 | const llvm_actual_addrspace = toLlvmGlobalAddressSpace(.generic, target); | 2745 | const llvm_actual_addrspace = toLlvmGlobalAddressSpace(.generic, target); |
| 2672 | const global = o.llvm_module.addGlobalInAddressSpace( | 2746 | const llvm_alignment = ty.toType().abiAlignment(mod); |
| 2673 | llvm_init.typeOf(), | 2747 | const llvm_global = o.llvm_module.addGlobalInAddressSpace( |
| | 2748 | llvm_ty.toLlvm(&o.builder), |
| 2674 | "", | 2749 | "", |
| 2675 | @intFromEnum(llvm_actual_addrspace), | 2750 | @intFromEnum(llvm_actual_addrspace), |
| 2676 | ); | 2751 | ); |
| 2677 | global.setLinkage(.Internal); | 2752 | llvm_global.setLinkage(.Internal); |
| 2678 | global.setUnnamedAddr(.True); | 2753 | llvm_global.setUnnamedAddr(.True); |
| 2679 | global.setAlignment(ty.toType().abiAlignment(mod)); | 2754 | llvm_global.setAlignment(llvm_alignment); |
| 2680 | global.setInitializer(llvm_init); | 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 | const addrspace_casted_global = if (llvm_wanted_addrspace != llvm_actual_addrspace) | 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 | else | 2774 | else |
| 2685 | global; | 2775 | llvm_global; |
| 2686 | | 2776 | |
| 2687 | o.null_opt_addr = addrspace_casted_global; | 2777 | o.null_opt_addr = addrspace_casted_global; |
| 2688 | return addrspace_casted_global; | 2778 | return addrspace_casted_global; |
| ... | @@ -2691,7 +2781,7 @@ pub const Object = struct { | ... | @@ -2691,7 +2781,7 @@ pub const Object = struct { |
| 2691 | /// If the llvm function does not exist, create it. | 2781 | /// If the llvm function does not exist, create it. |
| 2692 | /// Note that this can be called before the function's semantic analysis has | 2782 | /// Note that this can be called before the function's semantic analysis has |
| 2693 | /// completed, so if any attributes rely on that, they must be done in updateFunc, not here. | 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 | const mod = o.module; | 2785 | const mod = o.module; |
| 2696 | const gpa = o.gpa; | 2786 | const gpa = o.gpa; |
| 2697 | const decl = mod.declPtr(decl_index); | 2787 | const decl = mod.declPtr(decl_index); |
| ... | @@ -2722,7 +2812,9 @@ pub const Object = struct { | ... | @@ -2722,7 +2812,9 @@ pub const Object = struct { |
| 2722 | | 2812 | |
| 2723 | const is_extern = decl.isExtern(mod); | 2813 | const is_extern = decl.isExtern(mod); |
| 2724 | if (!is_extern) { | 2814 | if (!is_extern) { |
| | 2815 | global.linkage = .internal; |
| 2725 | llvm_fn.setLinkage(.Internal); | 2816 | llvm_fn.setLinkage(.Internal); |
| | 2817 | global.unnamed_addr = .unnamed_addr; |
| 2726 | llvm_fn.setUnnamedAddr(.True); | 2818 | llvm_fn.setUnnamedAddr(.True); |
| 2727 | } else { | 2819 | } else { |
| 2728 | if (target.isWasm()) { | 2820 | if (target.isWasm()) { |
| ... | @@ -2767,7 +2859,8 @@ pub const Object = struct { | ... | @@ -2767,7 +2859,8 @@ pub const Object = struct { |
| 2767 | } | 2859 | } |
| 2768 | | 2860 | |
| 2769 | if (fn_info.alignment.toByteUnitsOptional()) |a| { | 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 | // Function attributes that are independent of analysis results of the function body. | 2866 | // Function attributes that are independent of analysis results of the function body. |
| ... | @@ -2864,9 +2957,9 @@ pub const Object = struct { | ... | @@ -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 | const gop = try o.decl_map.getOrPut(o.gpa, decl_index); | 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 | errdefer assert(o.decl_map.remove(decl_index)); | 2963 | errdefer assert(o.decl_map.remove(decl_index)); |
| 2871 | | 2964 | |
| 2872 | const mod = o.module; | 2965 | const mod = o.module; |
| ... | @@ -2880,9 +2973,9 @@ pub const Object = struct { | ... | @@ -2880,9 +2973,9 @@ pub const Object = struct { |
| 2880 | var global = Builder.Global{ | 2973 | var global = Builder.Global{ |
| 2881 | .addr_space = toLlvmGlobalAddressSpace(decl.@"addrspace", target), | 2974 | .addr_space = toLlvmGlobalAddressSpace(decl.@"addrspace", target), |
| 2882 | .type = try o.lowerType(decl.ty), | 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 | .global = @enumFromInt(o.builder.globals.count()), | 2979 | .global = @enumFromInt(o.builder.globals.count()), |
| 2887 | }; | 2980 | }; |
| 2888 | | 2981 | |
| ... | @@ -2903,16 +2996,16 @@ pub const Object = struct { | ... | @@ -2903,16 +2996,16 @@ pub const Object = struct { |
| 2903 | llvm_global.setUnnamedAddr(.False); | 2996 | llvm_global.setUnnamedAddr(.False); |
| 2904 | global.linkage = .external; | 2997 | global.linkage = .external; |
| 2905 | llvm_global.setLinkage(.External); | 2998 | llvm_global.setLinkage(.External); |
| 2906 | if (decl.val.getVariable(mod)) |variable| { | 2999 | if (decl.val.getVariable(mod)) |decl_var| { |
| 2907 | const single_threaded = mod.comp.bin_file.options.single_threaded; | 3000 | const single_threaded = mod.comp.bin_file.options.single_threaded; |
| 2908 | if (variable.is_threadlocal and !single_threaded) { | 3001 | if (decl_var.is_threadlocal and !single_threaded) { |
| 2909 | object.thread_local = .generaldynamic; | 3002 | variable.thread_local = .generaldynamic; |
| 2910 | llvm_global.setThreadLocalMode(.GeneralDynamicTLSModel); | 3003 | llvm_global.setThreadLocalMode(.GeneralDynamicTLSModel); |
| 2911 | } else { | 3004 | } else { |
| 2912 | object.thread_local = .default; | 3005 | variable.thread_local = .default; |
| 2913 | llvm_global.setThreadLocalMode(.NotThreadLocal); | 3006 | llvm_global.setThreadLocalMode(.NotThreadLocal); |
| 2914 | } | 3007 | } |
| 2915 | if (variable.is_weak_linkage) { | 3008 | if (decl_var.is_weak_linkage) { |
| 2916 | global.linkage = .extern_weak; | 3009 | global.linkage = .extern_weak; |
| 2917 | llvm_global.setLinkage(.ExternalWeak); | 3010 | llvm_global.setLinkage(.ExternalWeak); |
| 2918 | } | 3011 | } |
| ... | @@ -2926,17 +3019,8 @@ pub const Object = struct { | ... | @@ -2926,17 +3019,8 @@ pub const Object = struct { |
| 2926 | | 3019 | |
| 2927 | try o.builder.llvm_globals.append(o.gpa, llvm_global); | 3020 | try o.builder.llvm_globals.append(o.gpa, llvm_global); |
| 2928 | gop.value_ptr.* = try o.builder.addGlobal(name, global); | 3021 | gop.value_ptr.* = try o.builder.addGlobal(name, global); |
| 2929 | try o.builder.objects.append(o.gpa, object); | 3022 | try o.builder.variables.append(o.gpa, variable); |
| 2930 | return global.kind.object; | 3023 | return global.kind.variable; |
| 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; | | |
| 2940 | } | 3024 | } |
| 2941 | | 3025 | |
| 2942 | fn lowerType(o: *Object, t: Type) Allocator.Error!Builder.Type { | 3026 | fn lowerType(o: *Object, t: Type) Allocator.Error!Builder.Type { |
| ... | @@ -3069,14 +3153,17 @@ pub const Object = struct { | ... | @@ -3069,14 +3153,17 @@ pub const Object = struct { |
| 3069 | => unreachable, | 3153 | => unreachable, |
| 3070 | else => switch (mod.intern_pool.indexToKey(t.toIntern())) { | 3154 | else => switch (mod.intern_pool.indexToKey(t.toIntern())) { |
| 3071 | .int_type => |int_type| try o.builder.intType(int_type.bits), | 3155 | .int_type => |int_type| try o.builder.intType(int_type.bits), |
| 3072 | .ptr_type => |ptr_type| switch (ptr_type.flags.size) { | 3156 | .ptr_type => |ptr_type| type: { |
| 3073 | .One, .Many, .C => try o.builder.ptrType( | 3157 | const ptr_ty = try o.builder.ptrType( |
| 3074 | toLlvmAddressSpace(ptr_type.flags.address_space, target), | 3158 | toLlvmAddressSpace(ptr_type.flags.address_space, target), |
| 3075 | ), | 3159 | ); |
| 3076 | .Slice => try o.builder.structType(.normal, &.{ | 3160 | break :type switch (ptr_type.flags.size) { |
| 3077 | .ptr, | 3161 | .One, .Many, .C => ptr_ty, |
| 3078 | try o.lowerType(Type.usize), | 3162 | .Slice => try o.builder.structType(.normal, &.{ |
| 3079 | }), | 3163 | ptr_ty, |
| | 3164 | try o.lowerType(Type.usize), |
| | 3165 | }), |
| | 3166 | }; |
| 3080 | }, | 3167 | }, |
| 3081 | .array_type => |array_type| o.builder.arrayType( | 3168 | .array_type => |array_type| o.builder.arrayType( |
| 3082 | array_type.len + @intFromBool(array_type.sentinel != .none), | 3169 | array_type.len + @intFromBool(array_type.sentinel != .none), |
| ... | @@ -3094,13 +3181,16 @@ pub const Object = struct { | ... | @@ -3094,13 +3181,16 @@ pub const Object = struct { |
| 3094 | if (t.optionalReprIsPayload(mod)) return payload_ty; | 3181 | if (t.optionalReprIsPayload(mod)) return payload_ty; |
| 3095 | | 3182 | |
| 3096 | comptime assert(optional_layout_version == 3); | 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 | const offset = child_ty.toType().abiSize(mod) + 1; | 3186 | const offset = child_ty.toType().abiSize(mod) + 1; |
| 3099 | const abi_size = t.abiSize(mod); | 3187 | const abi_size = t.abiSize(mod); |
| 3100 | const padding = abi_size - offset; | 3188 | const padding_len = abi_size - offset; |
| 3101 | if (padding == 0) return o.builder.structType(.normal, fields_buf[0..2]); | 3189 | if (padding_len > 0) { |
| 3102 | fields_buf[2] = try o.builder.arrayType(padding, .i8); | 3190 | fields[2] = try o.builder.arrayType(padding_len, .i8); |
| 3103 | return o.builder.structType(.normal, fields_buf[0..3]); | 3191 | fields_len = 3; |
| | 3192 | } |
| | 3193 | return o.builder.structType(.normal, fields[0..fields_len]); |
| 3104 | }, | 3194 | }, |
| 3105 | .anyframe_type => @panic("TODO implement lowerType for AnyFrame types"), | 3195 | .anyframe_type => @panic("TODO implement lowerType for AnyFrame types"), |
| 3106 | .error_union_type => |error_union_type| { | 3196 | .error_union_type => |error_union_type| { |
| ... | @@ -3115,30 +3205,30 @@ pub const Object = struct { | ... | @@ -3115,30 +3205,30 @@ pub const Object = struct { |
| 3115 | const payload_size = error_union_type.payload_type.toType().abiSize(mod); | 3205 | const payload_size = error_union_type.payload_type.toType().abiSize(mod); |
| 3116 | const error_size = Type.err_int.abiSize(mod); | 3206 | const error_size = Type.err_int.abiSize(mod); |
| 3117 | | 3207 | |
| 3118 | var fields_buf: [3]Builder.Type = undefined; | 3208 | var fields: [3]Builder.Type = undefined; |
| 3119 | if (error_align > payload_align) { | 3209 | var fields_len: usize = 2; |
| 3120 | fields_buf[0] = error_type; | 3210 | const padding_len = if (error_align > payload_align) pad: { |
| 3121 | fields_buf[1] = payload_type; | 3211 | fields[0] = error_type; |
| | 3212 | fields[1] = payload_type; |
| 3122 | const payload_end = | 3213 | const payload_end = |
| 3123 | std.mem.alignForward(u64, error_size, payload_align) + | 3214 | std.mem.alignForward(u64, error_size, payload_align) + |
| 3124 | payload_size; | 3215 | payload_size; |
| 3125 | const abi_size = std.mem.alignForward(u64, payload_end, error_align); | 3216 | const abi_size = std.mem.alignForward(u64, payload_end, error_align); |
| 3126 | const padding = abi_size - payload_end; | 3217 | break :pad abi_size - payload_end; |
| 3127 | if (padding == 0) return o.builder.structType(.normal, fields_buf[0..2]); | 3218 | } else pad: { |
| 3128 | fields_buf[2] = try o.builder.arrayType(padding, .i8); | 3219 | fields[0] = payload_type; |
| 3129 | return o.builder.structType(.normal, fields_buf[0..3]); | 3220 | fields[1] = error_type; |
| 3130 | } else { | | |
| 3131 | fields_buf[0] = payload_type; | | |
| 3132 | fields_buf[1] = error_type; | | |
| 3133 | const error_end = | 3221 | const error_end = |
| 3134 | std.mem.alignForward(u64, payload_size, error_align) + | 3222 | std.mem.alignForward(u64, payload_size, error_align) + |
| 3135 | error_size; | 3223 | error_size; |
| 3136 | const abi_size = std.mem.alignForward(u64, error_end, payload_align); | 3224 | const abi_size = std.mem.alignForward(u64, error_end, payload_align); |
| 3137 | const padding = abi_size - error_end; | 3225 | break :pad abi_size - error_end; |
| 3138 | if (padding == 0) return o.builder.structType(.normal, fields_buf[0..2]); | 3226 | }; |
| 3139 | fields_buf[2] = try o.builder.arrayType(padding, .i8); | 3227 | if (padding_len > 0) { |
| 3140 | return o.builder.structType(.normal, fields_buf[0..3]); | 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 | .simple_type => unreachable, | 3233 | .simple_type => unreachable, |
| 3144 | .struct_type => |struct_type| { | 3234 | .struct_type => |struct_type| { |
| ... | @@ -3371,6 +3461,7 @@ pub const Object = struct { | ... | @@ -3371,6 +3461,7 @@ pub const Object = struct { |
| 3371 | fn lowerTypeFn(o: *Object, fn_info: InternPool.Key.FuncType) Allocator.Error!Builder.Type { | 3461 | fn lowerTypeFn(o: *Object, fn_info: InternPool.Key.FuncType) Allocator.Error!Builder.Type { |
| 3372 | const mod = o.module; | 3462 | const mod = o.module; |
| 3373 | const ip = &mod.intern_pool; | 3463 | const ip = &mod.intern_pool; |
| | 3464 | const target = mod.getTarget(); |
| 3374 | const ret_ty = try lowerFnRetTy(o, fn_info); | 3465 | const ret_ty = try lowerFnRetTy(o, fn_info); |
| 3375 | | 3466 | |
| 3376 | var llvm_params = std.ArrayListUnmanaged(Builder.Type){}; | 3467 | var llvm_params = std.ArrayListUnmanaged(Builder.Type){}; |
| ... | @@ -3404,7 +3495,11 @@ pub const Object = struct { | ... | @@ -3404,7 +3495,11 @@ pub const Object = struct { |
| 3404 | )); | 3495 | )); |
| 3405 | }, | 3496 | }, |
| 3406 | .slice => { | 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 | .multiple_llvm_types => { | 3504 | .multiple_llvm_types => { |
| 3410 | try llvm_params.appendSlice(o.gpa, it.types_buffer[0..it.types_len]); | 3505 | try llvm_params.appendSlice(o.gpa, it.types_buffer[0..it.types_len]); |
| ... | @@ -3433,20 +3528,23 @@ pub const Object = struct { | ... | @@ -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 | const mod = o.module; | 3532 | const mod = o.module; |
| 3438 | const gpa = o.gpa; | | |
| 3439 | const target = mod.getTarget(); | 3533 | const target = mod.getTarget(); |
| 3440 | var tv = arg_tv; | 3534 | |
| 3441 | switch (mod.intern_pool.indexToKey(tv.val.toIntern())) { | 3535 | var val = arg_val.toValue(); |
| 3442 | .runtime_value => |rt| tv.val = rt.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 | else => {}, | 3539 | else => {}, |
| 3444 | } | 3540 | } |
| 3445 | if (tv.val.isUndefDeep(mod)) { | 3541 | if (val.isUndefDeep(mod)) { |
| 3446 | return (try o.lowerType(tv.ty)).toLlvm(&o.builder).getUndef(); | 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 | .int_type, | 3548 | .int_type, |
| 3451 | .ptr_type, | 3549 | .ptr_type, |
| 3452 | .array_type, | 3550 | .array_type, |
| ... | @@ -3474,8 +3572,8 @@ pub const Object = struct { | ... | @@ -3474,8 +3572,8 @@ pub const Object = struct { |
| 3474 | .@"unreachable", | 3572 | .@"unreachable", |
| 3475 | .generic_poison, | 3573 | .generic_poison, |
| 3476 | => unreachable, // non-runtime values | 3574 | => unreachable, // non-runtime values |
| 3477 | .false => return Builder.Constant.false.toLlvm(&o.builder), | 3575 | .false => .false, |
| 3478 | .true => return Builder.Constant.true.toLlvm(&o.builder), | 3576 | .true => .true, |
| 3479 | }, | 3577 | }, |
| 3480 | .variable, | 3578 | .variable, |
| 3481 | .enum_literal, | 3579 | .enum_literal, |
| ... | @@ -3486,259 +3584,266 @@ pub const Object = struct { | ... | @@ -3486,259 +3584,266 @@ pub const Object = struct { |
| 3486 | const fn_decl = mod.declPtr(fn_decl_index); | 3584 | const fn_decl = mod.declPtr(fn_decl_index); |
| 3487 | try mod.markDeclAlive(fn_decl); | 3585 | try mod.markDeclAlive(fn_decl); |
| 3488 | const function_index = try o.resolveLlvmFunction(fn_decl_index); | 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 | .func => |func| { | 3589 | .func => |func| { |
| 3492 | const fn_decl_index = func.owner_decl; | 3590 | const fn_decl_index = func.owner_decl; |
| 3493 | const fn_decl = mod.declPtr(fn_decl_index); | 3591 | const fn_decl = mod.declPtr(fn_decl_index); |
| 3494 | try mod.markDeclAlive(fn_decl); | 3592 | try mod.markDeclAlive(fn_decl); |
| 3495 | const function_index = try o.resolveLlvmFunction(fn_decl_index); | 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 | .int => { | 3596 | .int => { |
| 3499 | var bigint_space: Value.BigIntSpace = undefined; | 3597 | var bigint_space: Value.BigIntSpace = undefined; |
| 3500 | const bigint = tv.val.toBigInt(&bigint_space, mod); | 3598 | const bigint = val.toBigInt(&bigint_space, mod); |
| 3501 | return lowerBigInt(o, tv.ty, bigint); | 3599 | return lowerBigInt(o, ty, bigint); |
| 3502 | }, | 3600 | }, |
| 3503 | .err => |err| { | 3601 | .err => |err| { |
| 3504 | const int = try mod.getErrorValue(err.name); | 3602 | const int = try mod.getErrorValue(err.name); |
| 3505 | const llvm_int = try o.builder.intConst(Builder.Type.err_int, int); | 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 | .error_union => |error_union| { | 3606 | .error_union => |error_union| { |
| 3509 | const err_tv: TypedValue = switch (error_union.val) { | 3607 | const err_val = switch (error_union.val) { |
| 3510 | .err_name => |err_name| .{ | 3608 | .err_name => |err_name| try mod.intern(.{ .err = .{ |
| 3511 | .ty = tv.ty.errorUnionSet(mod), | 3609 | .ty = ty.errorUnionSet(mod).toIntern(), |
| 3512 | .val = (try mod.intern(.{ .err = .{ | 3610 | .name = err_name, |
| 3513 | .ty = tv.ty.errorUnionSet(mod).toIntern(), | 3611 | } }), |
| 3514 | .name = err_name, | 3612 | .payload => (try mod.intValue(Type.err_int, 0)).toIntern(), |
| 3515 | } })).toValue(), | | |
| 3516 | }, | | |
| 3517 | .payload => .{ | | |
| 3518 | .ty = Type.err_int, | | |
| 3519 | .val = try mod.intValue(Type.err_int, 0), | | |
| 3520 | }, | | |
| 3521 | }; | 3613 | }; |
| 3522 | const payload_type = tv.ty.errorUnionPayload(mod); | 3614 | const payload_type = ty.errorUnionPayload(mod); |
| 3523 | if (!payload_type.hasRuntimeBitsIgnoreComptime(mod)) { | 3615 | if (!payload_type.hasRuntimeBitsIgnoreComptime(mod)) { |
| 3524 | // We use the error type directly as the type. | 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 | const payload_align = payload_type.abiAlignment(mod); | 3620 | const payload_align = payload_type.abiAlignment(mod); |
| 3529 | const error_align = err_tv.ty.abiAlignment(mod); | 3621 | const error_align = Type.err_int.abiAlignment(mod); |
| 3530 | const llvm_error_value = try o.lowerValue(err_tv); | 3622 | const llvm_error_value = try o.lowerValue(err_val); |
| 3531 | const llvm_payload_value = try o.lowerValue(.{ | 3623 | const llvm_payload_value = try o.lowerValue(switch (error_union.val) { |
| 3532 | .ty = payload_type, | 3624 | .err_name => try mod.intern(.{ .undef = payload_type.toIntern() }), |
| 3533 | .val = switch (error_union.val) { | 3625 | .payload => |payload| payload, |
| 3534 | .err_name => try mod.intern(.{ .undef = payload_type.toIntern() }), | | |
| 3535 | .payload => |payload| payload, | | |
| 3536 | }.toValue(), | | |
| 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 | if (error_align > payload_align) { | 3630 | if (error_align > payload_align) { |
| 3548 | fields_buf[0] = llvm_error_value; | 3631 | vals[0] = llvm_error_value; |
| 3549 | fields_buf[1] = llvm_payload_value; | 3632 | vals[1] = llvm_payload_value; |
| 3550 | return o.context.constStruct(&fields_buf, llvm_field_count, .False); | | |
| 3551 | } else { | 3633 | } else { |
| 3552 | fields_buf[0] = llvm_payload_value; | 3634 | vals[0] = llvm_payload_value; |
| 3553 | fields_buf[1] = llvm_error_value; | 3635 | vals[1] = llvm_error_value; |
| 3554 | return o.context.constStruct(&fields_buf, llvm_field_count, .False); | 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(.{ | 3652 | .enum_tag => |enum_tag| o.lowerValue(enum_tag.int), |
| 3558 | .ty = mod.intern_pool.typeOf(enum_tag.int).toType(), | 3653 | .float => switch (ty.floatBits(target)) { |
| 3559 | .val = enum_tag.int.toValue(), | 3654 | 16 => if (backendSupportsF16(target)) |
| 3560 | }), | 3655 | try o.builder.halfConst(val.toFloat(f16, mod)) |
| 3561 | .float => return switch (tv.ty.floatBits(target)) { | 3656 | else |
| 3562 | 16 => int: { | 3657 | try o.builder.intConst(.i16, @as(i16, @bitCast(val.toFloat(f16, mod)))), |
| 3563 | const repr: i16 = @bitCast(tv.val.toFloat(f16, mod)); | 3658 | 32 => try o.builder.floatConst(val.toFloat(f32, mod)), |
| 3564 | break :int try o.builder.intConst(.i16, repr); | 3659 | 64 => try o.builder.doubleConst(val.toFloat(f64, mod)), |
| 3565 | }, | 3660 | 80 => if (backendSupportsF80(target)) |
| 3566 | 32 => int: { | 3661 | try o.builder.x86_fp80Const(val.toFloat(f80, mod)) |
| 3567 | const repr: i32 = @bitCast(tv.val.toFloat(f32, mod)); | 3662 | else |
| 3568 | break :int try o.builder.intConst(.i32, repr); | 3663 | try o.builder.intConst(.i80, @as(i80, @bitCast(val.toFloat(f80, mod)))), |
| 3569 | }, | 3664 | 128 => try o.builder.fp128Const(val.toFloat(f128, mod)), |
| 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 | }, | | |
| 3582 | else => unreachable, | 3665 | else => unreachable, |
| 3583 | }.toLlvm(&o.builder).constBitCast((try o.lowerType(tv.ty)).toLlvm(&o.builder)), | 3666 | }, |
| 3584 | .ptr => |ptr| { | 3667 | .ptr => |ptr| { |
| 3585 | const ptr_tv: TypedValue = switch (ptr.len) { | 3668 | const ptr_ty = switch (ptr.len) { |
| 3586 | .none => tv, | 3669 | .none => ty, |
| 3587 | else => .{ .ty = tv.ty.slicePtrFieldType(mod), .val = tv.val.slicePtr(mod) }, | 3670 | else => ty.slicePtrFieldType(mod), |
| 3588 | }; | 3671 | }; |
| 3589 | const llvm_ptr_val = switch (ptr.addr) { | 3672 | const ptr_val = switch (ptr.addr) { |
| 3590 | .decl => |decl| try o.lowerDeclRefValue(ptr_tv, decl), | 3673 | .decl => |decl| try o.lowerDeclRefValue(ptr_ty, decl), |
| 3591 | .mut_decl => |mut_decl| try o.lowerDeclRefValue(ptr_tv, mut_decl.decl), | 3674 | .mut_decl => |mut_decl| try o.lowerDeclRefValue(ptr_ty, mut_decl.decl), |
| 3592 | .int => |int| try o.lowerIntAsPtr(int.toValue()), | 3675 | .int => |int| try o.lowerIntAsPtr(int), |
| 3593 | .eu_payload, | 3676 | .eu_payload, |
| 3594 | .opt_payload, | 3677 | .opt_payload, |
| 3595 | .elem, | 3678 | .elem, |
| 3596 | .field, | 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 | .comptime_field => unreachable, | 3681 | .comptime_field => unreachable, |
| 3599 | }; | 3682 | }; |
| 3600 | switch (ptr.len) { | 3683 | switch (ptr.len) { |
| 3601 | .none => return llvm_ptr_val, | 3684 | .none => return ptr_val, |
| 3602 | else => { | 3685 | else => return o.builder.structConst(try o.lowerType(ty), &.{ |
| 3603 | const fields: [2]*llvm.Value = .{ | 3686 | ptr_val, try o.lowerValue(ptr.len), |
| 3604 | llvm_ptr_val, | 3687 | }), |
| 3605 | try o.lowerValue(.{ .ty = Type.usize, .val = ptr.len.toValue() }), | | |
| 3606 | }; | | |
| 3607 | return o.context.constStruct(&fields, fields.len, .False); | | |
| 3608 | }, | | |
| 3609 | } | 3688 | } |
| 3610 | }, | 3689 | }, |
| 3611 | .opt => |opt| { | 3690 | .opt => |opt| { |
| 3612 | comptime assert(optional_layout_version == 3); | 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 | if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) { | 3695 | if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) { |
| 3617 | return non_null_bit; | 3696 | return non_null_bit; |
| 3618 | } | 3697 | } |
| 3619 | const llvm_ty = (try o.lowerType(tv.ty)).toLlvm(&o.builder); | 3698 | const llvm_ty = try o.lowerType(ty); |
| 3620 | if (tv.ty.optionalReprIsPayload(mod)) return switch (opt.val) { | 3699 | if (ty.optionalReprIsPayload(mod)) return switch (opt.val) { |
| 3621 | .none => llvm_ty.constNull(), | 3700 | .none => switch (llvm_ty.tag(&o.builder)) { |
| 3622 | else => |payload| o.lowerValue(.{ .ty = payload_ty, .val = payload.toValue() }), | 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 | assert(payload_ty.zigTypeTag(mod) != .Fn); | 3708 | assert(payload_ty.zigTypeTag(mod) != .Fn); |
| 3625 | | 3709 | |
| 3626 | const llvm_field_count = llvm_ty.countStructElementTypes(); | 3710 | var fields: [3]Builder.Type = undefined; |
| 3627 | var fields_buf: [3]*llvm.Value = undefined; | 3711 | var vals: [3]Builder.Constant = undefined; |
| 3628 | fields_buf[0] = try o.lowerValue(.{ | 3712 | vals[0] = try o.lowerValue(switch (opt.val) { |
| 3629 | .ty = payload_ty, | 3713 | .none => try mod.intern(.{ .undef = payload_ty.toIntern() }), |
| 3630 | .val = switch (opt.val) { | 3714 | else => |payload| payload, |
| 3631 | .none => try mod.intern(.{ .undef = payload_ty.toIntern() }), | | |
| 3632 | else => |payload| payload, | | |
| 3633 | }.toValue(), | | |
| 3634 | }); | 3715 | }); |
| 3635 | fields_buf[1] = non_null_bit; | 3716 | vals[1] = non_null_bit; |
| 3636 | if (llvm_field_count > 2) { | 3717 | fields[0] = vals[0].typeOf(&o.builder); |
| 3637 | assert(llvm_field_count == 3); | 3718 | fields[1] = vals[1].typeOf(&o.builder); |
| 3638 | fields_buf[2] = llvm_ty.structGetTypeAtIndex(2).getUndef(); | 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())) { | 3731 | .aggregate => |aggregate| switch (mod.intern_pool.indexToKey(ty.toIntern())) { |
| 3643 | .array_type => switch (aggregate.storage) { | 3732 | .array_type => |array_type| switch (aggregate.storage) { |
| 3644 | .bytes => |bytes| return o.context.constString( | 3733 | .bytes => |bytes| try o.builder.stringConst(try o.builder.string(bytes)), |
| 3645 | bytes.ptr, | 3734 | .elems => |elems| { |
| 3646 | @as(c_uint, @intCast(tv.ty.arrayLenIncludingSentinel(mod))), | 3735 | const array_ty = try o.lowerType(ty); |
| 3647 | .True, // Don't null terminate. Bytes has the sentinel, if any. | 3736 | const elem_ty = array_ty.childType(&o.builder); |
| 3648 | ), | 3737 | assert(elems.len == array_ty.aggregateLen(&o.builder)); |
| 3649 | .elems => |elem_vals| { | 3738 | |
| 3650 | const elem_ty = tv.ty.childType(mod); | 3739 | const ExpectedContents = extern struct { |
| 3651 | const llvm_elems = try gpa.alloc(*llvm.Value, elem_vals.len); | 3740 | vals: [Builder.expected_fields_len]Builder.Constant, |
| 3652 | defer gpa.free(llvm_elems); | 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 | var need_unnamed = false; | 3753 | var need_unnamed = false; |
| 3654 | for (elem_vals, 0..) |elem_val, i| { | 3754 | for (vals, fields, elems) |*result_val, *result_field, elem| { |
| 3655 | llvm_elems[i] = try o.lowerValue(.{ .ty = elem_ty, .val = elem_val.toValue() }); | 3755 | result_val.* = try o.lowerValue(elem); |
| 3656 | need_unnamed = need_unnamed or o.isUnnamedType(elem_ty, llvm_elems[i]); | 3756 | result_field.* = result_val.typeOf(&o.builder); |
| 3657 | } | 3757 | if (result_field.* != elem_ty) need_unnamed = true; |
| 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 | ); | | |
| 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| { | 3764 | .repeated_elem => |elem| { |
| 3673 | const elem_ty = tv.ty.childType(mod); | 3765 | const len: usize = @intCast(array_type.len); |
| 3674 | const sentinel = tv.ty.sentinel(mod); | 3766 | const len_including_sentinel: usize = |
| 3675 | const len = @as(usize, @intCast(tv.ty.arrayLen(mod))); | 3767 | @intCast(len + @intFromBool(array_type.sentinel != .none)); |
| 3676 | const len_including_sent = len + @intFromBool(sentinel != null); | 3768 | const array_ty = try o.lowerType(ty); |
| 3677 | const llvm_elems = try gpa.alloc(*llvm.Value, len_including_sent); | 3769 | const elem_ty = array_ty.childType(&o.builder); |
| 3678 | defer gpa.free(llvm_elems); | 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 | var need_unnamed = false; | 3785 | var need_unnamed = false; |
| 3681 | if (len != 0) { | 3786 | @memset(vals[0..len], try o.lowerValue(elem)); |
| 3682 | for (llvm_elems[0..len]) |*elem| { | 3787 | @memset(fields[0..len], vals[0].typeOf(&o.builder)); |
| 3683 | elem.* = try o.lowerValue(.{ .ty = elem_ty, .val = val.toValue() }); | 3788 | if (fields[0] != elem_ty) need_unnamed = true; |
| 3684 | } | 3789 | |
| 3685 | need_unnamed = need_unnamed or o.isUnnamedType(elem_ty, llvm_elems[0]); | 3790 | if (array_type.sentinel != .none) { |
| 3686 | } | 3791 | vals[len] = try o.lowerValue(array_type.sentinel); |
| 3687 | | 3792 | fields[len] = vals[len].typeOf(&o.builder); |
| 3688 | if (sentinel) |sent| { | 3793 | if (fields[len] != elem_ty) need_unnamed = true; |
| 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]); | | |
| 3691 | } | 3794 | } |
| 3692 | | 3795 | |
| 3693 | if (need_unnamed) { | 3796 | return if (need_unnamed) try o.builder.structConst( |
| 3694 | return o.context.constStruct( | 3797 | try o.builder.structType(.@"packed", fields), |
| 3695 | llvm_elems.ptr, | 3798 | vals, |
| 3696 | @as(c_uint, @intCast(llvm_elems.len)), | 3799 | ) else try o.builder.arrayConst(array_ty, vals); |
| 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 | } | | |
| 3706 | }, | 3800 | }, |
| 3707 | }, | 3801 | }, |
| 3708 | .vector_type => |vector_type| { | 3802 | .vector_type => |vector_type| { |
| 3709 | const elem_ty = vector_type.child.toType(); | 3803 | const ExpectedContents = [Builder.expected_fields_len]Builder.Constant; |
| 3710 | const llvm_elems = try gpa.alloc(*llvm.Value, vector_type.len); | 3804 | var stack align(@max( |
| 3711 | defer gpa.free(llvm_elems); | 3805 | @alignOf(std.heap.StackFallbackAllocator(0)), |
| 3712 | for (llvm_elems, 0..) |*llvm_elem, i| { | 3806 | @alignOf(ExpectedContents), |
| 3713 | llvm_elem.* = switch (aggregate.storage) { | 3807 | )) = std.heap.stackFallback(@sizeOf(ExpectedContents), o.gpa); |
| 3714 | .bytes => |bytes| (try o.builder.intConst(.i8, bytes[i])).toLlvm(&o.builder), | 3808 | const allocator = stack.get(); |
| 3715 | .elems => |elems| try o.lowerValue(.{ | 3809 | const vals = try allocator.alloc(Builder.Constant, vector_type.len); |
| 3716 | .ty = elem_ty, | 3810 | defer allocator.free(vals); |
| 3717 | .val = elems[i].toValue(), | 3811 | |
| 3718 | }), | 3812 | switch (aggregate.storage) { |
| 3719 | .repeated_elem => |elem| try o.lowerValue(.{ | 3813 | .bytes => |bytes| for (vals, bytes) |*result_val, byte| { |
| 3720 | .ty = elem_ty, | 3814 | result_val.* = try o.builder.intConst(.i8, byte); |
| 3721 | .val = elem.toValue(), | 3815 | }, |
| 3722 | }), | 3816 | .elems => |elems| for (vals, elems) |*result_val, elem| { |
| 3723 | }; | 3817 | result_val.* = try o.lowerValue(elem); |
| | 3818 | }, |
| | 3819 | .repeated_elem => |elem| @memset(vals, try o.lowerValue(elem)), |
| 3724 | } | 3820 | } |
| 3725 | return llvm.constVector( | 3821 | return o.builder.vectorConst(try o.lowerType(ty), vals); |
| 3726 | llvm_elems.ptr, | | |
| 3727 | @as(c_uint, @intCast(llvm_elems.len)), | | |
| 3728 | ); | | |
| 3729 | }, | 3822 | }, |
| 3730 | .anon_struct_type => |tuple| { | 3823 | .anon_struct_type => |tuple| { |
| 3731 | var llvm_fields: std.ArrayListUnmanaged(*llvm.Value) = .{}; | 3824 | const struct_ty = try o.lowerType(ty); |
| 3732 | defer llvm_fields.deinit(gpa); | 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 | comptime assert(struct_layout_version == 2); | 3841 | comptime assert(struct_layout_version == 2); |
| | 3842 | var llvm_index: usize = 0; |
| 3737 | var offset: u64 = 0; | 3843 | var offset: u64 = 0; |
| 3738 | var big_align: u32 = 0; | 3844 | var big_align: u32 = 0; |
| 3739 | var need_unnamed = false; | 3845 | var need_unnamed = false; |
| 3740 | | 3846 | for (tuple.types, tuple.values, 0..) |field_ty, field_val, field_index| { |
| 3741 | for (tuple.types, tuple.values, 0..) |field_ty, field_val, i| { | | |
| 3742 | if (field_val != .none) continue; | 3847 | if (field_val != .none) continue; |
| 3743 | if (!field_ty.toType().hasRuntimeBitsIgnoreComptime(mod)) continue; | 3848 | if (!field_ty.toType().hasRuntimeBitsIgnoreComptime(mod)) continue; |
| 3744 | | 3849 | |
| ... | @@ -3749,20 +3854,20 @@ pub const Object = struct { | ... | @@ -3749,20 +3854,20 @@ pub const Object = struct { |
| 3749 | | 3854 | |
| 3750 | const padding_len = offset - prev_offset; | 3855 | const padding_len = offset - prev_offset; |
| 3751 | if (padding_len > 0) { | 3856 | if (padding_len > 0) { |
| 3752 | const llvm_array_ty = try o.builder.arrayType(padding_len, .i8); | | |
| 3753 | // TODO make this and all other padding elsewhere in debug | 3857 | // TODO make this and all other padding elsewhere in debug |
| 3754 | // builds be 0xaa not undef. | 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(.{ | 3865 | vals[llvm_index] = |
| 3759 | .ty = field_ty.toType(), | 3866 | try o.lowerValue((try val.fieldValue(mod, field_index)).toIntern()); |
| 3760 | .val = try tv.val.fieldValue(mod, i), | 3867 | fields[llvm_index] = vals[llvm_index].typeOf(&o.builder); |
| 3761 | }); | 3868 | if (fields[llvm_index] != struct_ty.structFields(&o.builder)[llvm_index]) |
| 3762 | | 3869 | need_unnamed = true; |
| 3763 | need_unnamed = need_unnamed or o.isUnnamedType(field_ty.toType(), field_llvm_val); | 3870 | llvm_index += 1; |
| 3764 | | | |
| 3765 | llvm_fields.appendAssumeCapacity(field_llvm_val); | | |
| 3766 | | 3871 | |
| 3767 | offset += field_ty.toType().abiSize(mod); | 3872 | offset += field_ty.toType().abiSize(mod); |
| 3768 | } | 3873 | } |
| ... | @@ -3771,73 +3876,71 @@ pub const Object = struct { | ... | @@ -3771,73 +3876,71 @@ pub const Object = struct { |
| 3771 | offset = std.mem.alignForward(u64, offset, big_align); | 3876 | offset = std.mem.alignForward(u64, offset, big_align); |
| 3772 | const padding_len = offset - prev_offset; | 3877 | const padding_len = offset - prev_offset; |
| 3773 | if (padding_len > 0) { | 3878 | if (padding_len > 0) { |
| 3774 | const llvm_array_ty = try o.builder.arrayType(padding_len, .i8); | 3879 | fields[llvm_index] = try o.builder.arrayType(padding_len, .i8); |
| 3775 | llvm_fields.appendAssumeCapacity(llvm_array_ty.toLlvm(&o.builder).getUndef()); | 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) { | 3887 | return try o.builder.structConst(if (need_unnamed) |
| 3780 | return o.context.constStruct( | 3888 | try o.builder.structType(struct_ty.structKind(&o.builder), fields) |
| 3781 | llvm_fields.items.ptr, | 3889 | else |
| 3782 | @as(c_uint, @intCast(llvm_fields.items.len)), | 3890 | struct_ty, vals); |
| 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 | } | | |
| 3792 | }, | 3891 | }, |
| 3793 | .struct_type => |struct_type| { | 3892 | .struct_type => |struct_type| { |
| 3794 | const struct_obj = mod.structPtrUnwrap(struct_type.index).?; | 3893 | const struct_obj = mod.structPtrUnwrap(struct_type.index).?; |
| 3795 | const llvm_struct_ty = (try o.lowerType(tv.ty)).toLlvm(&o.builder); | 3894 | assert(struct_obj.haveLayout()); |
| 3796 | | 3895 | const struct_ty = try o.lowerType(ty); |
| 3797 | if (struct_obj.layout == .Packed) { | 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 | comptime assert(Type.packed_struct_layout_version == 2); | 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 | var running_bits: u16 = 0; | 3899 | var running_bits: u16 = 0; |
| 3805 | for (fields, 0..) |field, i| { | 3900 | for (struct_obj.fields.values(), 0..) |field, field_index| { |
| 3806 | if (!field.ty.hasRuntimeBitsIgnoreComptime(mod)) continue; | 3901 | if (!field.ty.hasRuntimeBitsIgnoreComptime(mod)) continue; |
| 3807 | | 3902 | |
| 3808 | const non_int_val = try o.lowerValue(.{ | 3903 | const non_int_val = |
| 3809 | .ty = field.ty, | 3904 | try o.lowerValue((try val.fieldValue(mod, field_index)).toIntern()); |
| 3810 | .val = try tv.val.fieldValue(mod, i), | 3905 | const ty_bit_size: u16 = @intCast(field.ty.bitSize(mod)); |
| 3811 | }); | 3906 | const small_int_ty = try o.builder.intType(ty_bit_size); |
| 3812 | const ty_bit_size = @as(u16, @intCast(field.ty.bitSize(mod))); | 3907 | const small_int_val = try o.builder.castConst( |
| 3813 | const small_int_ty = (try o.builder.intType(@intCast(ty_bit_size))).toLlvm(&o.builder); | 3908 | if (field.ty.isPtrAtRuntime(mod)) .ptrtoint else .bitcast, |
| 3814 | const small_int_val = if (field.ty.isPtrAtRuntime(mod)) | 3909 | non_int_val, |
| 3815 | non_int_val.constPtrToInt(small_int_ty) | 3910 | small_int_ty, |
| 3816 | else | 3911 | ); |
| 3817 | non_int_val.constBitCast(small_int_ty); | 3912 | const shift_rhs = try o.builder.intConst(struct_ty, running_bits); |
| 3818 | const shift_rhs = (try o.builder.intConst(int_llvm_ty, running_bits)).toLlvm(&o.builder); | 3913 | const extended_int_val = |
| 3819 | // If the field is as large as the entire packed struct, this | 3914 | try o.builder.convConst(.unsigned, small_int_val, struct_ty); |
| 3820 | // zext would go from, e.g. i16 to i16. This is legal with | 3915 | const shifted = try o.builder.binConst(.shl, extended_int_val, shift_rhs); |
| 3821 | // constZExtOrBitCast but not legal with constZExt. | 3916 | running_int = try o.builder.binConst(.@"or", running_int, shifted); |
| 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); | | |
| 3825 | running_bits += ty_bit_size; | 3917 | running_bits += ty_bit_size; |
| 3826 | } | 3918 | } |
| 3827 | return running_int; | 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(); | 3923 | const ExpectedContents = extern struct { |
| 3831 | var llvm_fields = try std.ArrayListUnmanaged(*llvm.Value).initCapacity(gpa, llvm_field_count); | 3924 | vals: [Builder.expected_fields_len]Builder.Constant, |
| 3832 | defer llvm_fields.deinit(gpa); | 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 | comptime assert(struct_layout_version == 2); | 3937 | comptime assert(struct_layout_version == 2); |
| | 3938 | var llvm_index: usize = 0; |
| 3835 | var offset: u64 = 0; | 3939 | var offset: u64 = 0; |
| 3836 | var big_align: u32 = 0; | 3940 | var big_align: u32 = 0; |
| 3837 | var need_unnamed = false; | 3941 | var need_unnamed = false; |
| 3838 | | 3942 | var field_it = struct_obj.runtimeFieldIterator(mod); |
| 3839 | var it = struct_obj.runtimeFieldIterator(mod); | 3943 | while (field_it.next()) |field_and_index| { |
| 3840 | while (it.next()) |field_and_index| { | | |
| 3841 | const field = field_and_index.field; | 3944 | const field = field_and_index.field; |
| 3842 | const field_align = field.alignment(mod, struct_obj.layout); | 3945 | const field_align = field.alignment(mod, struct_obj.layout); |
| 3843 | big_align = @max(big_align, field_align); | 3946 | big_align = @max(big_align, field_align); |
| ... | @@ -3846,20 +3949,22 @@ pub const Object = struct { | ... | @@ -3846,20 +3949,22 @@ pub const Object = struct { |
| 3846 | | 3949 | |
| 3847 | const padding_len = offset - prev_offset; | 3950 | const padding_len = offset - prev_offset; |
| 3848 | if (padding_len > 0) { | 3951 | if (padding_len > 0) { |
| 3849 | const llvm_array_ty = try o.builder.arrayType(padding_len, .i8); | | |
| 3850 | // TODO make this and all other padding elsewhere in debug | 3952 | // TODO make this and all other padding elsewhere in debug |
| 3851 | // builds be 0xaa not undef. | 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(.{ | 3961 | vals[llvm_index] = try o.lowerValue( |
| 3856 | .ty = field.ty, | 3962 | (try val.fieldValue(mod, field_and_index.index)).toIntern(), |
| 3857 | .val = try tv.val.fieldValue(mod, field_and_index.index), | 3963 | ); |
| 3858 | }); | 3964 | fields[llvm_index] = vals[llvm_index].typeOf(&o.builder); |
| 3859 | | 3965 | if (fields[llvm_index] != struct_ty.structFields(&o.builder)[llvm_index]) |
| 3860 | need_unnamed = need_unnamed or o.isUnnamedType(field.ty, field_llvm_val); | 3966 | need_unnamed = true; |
| 3861 | | 3967 | llvm_index += 1; |
| 3862 | llvm_fields.appendAssumeCapacity(field_llvm_val); | | |
| 3863 | | 3968 | |
| 3864 | offset += field.ty.abiSize(mod); | 3969 | offset += field.ty.abiSize(mod); |
| 3865 | } | 3970 | } |
| ... | @@ -3868,135 +3973,118 @@ pub const Object = struct { | ... | @@ -3868,135 +3973,118 @@ pub const Object = struct { |
| 3868 | offset = std.mem.alignForward(u64, offset, big_align); | 3973 | offset = std.mem.alignForward(u64, offset, big_align); |
| 3869 | const padding_len = offset - prev_offset; | 3974 | const padding_len = offset - prev_offset; |
| 3870 | if (padding_len > 0) { | 3975 | if (padding_len > 0) { |
| 3871 | const llvm_array_ty = try o.builder.arrayType(padding_len, .i8); | 3976 | fields[llvm_index] = try o.builder.arrayType(padding_len, .i8); |
| 3872 | llvm_fields.appendAssumeCapacity(llvm_array_ty.toLlvm(&o.builder).getUndef()); | 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) { | 3984 | return try o.builder.structConst(if (need_unnamed) |
| 3877 | return o.context.constStruct( | 3985 | try o.builder.structType(struct_ty.structKind(&o.builder), fields) |
| 3878 | llvm_fields.items.ptr, | 3986 | else |
| 3879 | @as(c_uint, @intCast(llvm_fields.items.len)), | 3987 | struct_ty, vals); |
| 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 | } | | |
| 3888 | }, | 3988 | }, |
| 3889 | else => unreachable, | 3989 | else => unreachable, |
| 3890 | }, | 3990 | }, |
| 3891 | .un => { | 3991 | .un => |un| { |
| 3892 | const llvm_union_ty = (try o.lowerType(tv.ty)).toLlvm(&o.builder); | 3992 | const union_ty = try o.lowerType(ty); |
| 3893 | const tag_and_val: Value.Payload.Union.Data = switch (tv.val.toIntern()) { | 3993 | const layout = ty.unionGetLayout(mod); |
| 3894 | .none => tv.val.castTag(.@"union").?.data, | 3994 | if (layout.payload_size == 0) return o.lowerValue(un.tag); |
| 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); | | |
| 3902 | | 3995 | |
| 3903 | if (layout.payload_size == 0) { | 3996 | const union_obj = mod.typeToUnion(ty).?; |
| 3904 | return lowerValue(o, .{ | 3997 | const field_index = ty.unionTagFieldIndex(un.tag.toValue(), o.module).?; |
| 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).?; | | |
| 3911 | assert(union_obj.haveFieldTypes()); | 3998 | assert(union_obj.haveFieldTypes()); |
| 3912 | | 3999 | |
| 3913 | const field_ty = union_obj.fields.values()[field_index].ty; | 4000 | const field_ty = union_obj.fields.values()[field_index].ty; |
| 3914 | if (union_obj.layout == .Packed) { | 4001 | if (union_obj.layout == .Packed) { |
| 3915 | if (!field_ty.hasRuntimeBits(mod)) | 4002 | if (!field_ty.hasRuntimeBits(mod)) return o.builder.intConst(union_ty, 0); |
| 3916 | return llvm_union_ty.constNull(); | 4003 | const small_int_val = try o.builder.castConst( |
| 3917 | const non_int_val = try lowerValue(o, .{ .ty = field_ty, .val = tag_and_val.val }); | 4004 | if (field_ty.isPtrAtRuntime(mod)) .ptrtoint else .bitcast, |
| 3918 | const ty_bit_size = @as(u16, @intCast(field_ty.bitSize(mod))); | 4005 | try o.lowerValue(un.val), |
| 3919 | const small_int_ty = (try o.builder.intType(@intCast(ty_bit_size))).toLlvm(&o.builder); | 4006 | try o.builder.intType(@intCast(field_ty.bitSize(mod))), |
| 3920 | const small_int_val = if (field_ty.isPtrAtRuntime(mod)) | 4007 | ); |
| 3921 | non_int_val.constPtrToInt(small_int_ty) | 4008 | return o.builder.convConst(.unsigned, small_int_val, union_ty); |
| 3922 | else | | |
| 3923 | non_int_val.constBitCast(small_int_ty); | | |
| 3924 | return small_int_val.constZExtOrBitCast(llvm_union_ty); | | |
| 3925 | } | 4009 | } |
| 3926 | | 4010 | |
| 3927 | // Sometimes we must make an unnamed struct because LLVM does | 4011 | // Sometimes we must make an unnamed struct because LLVM does |
| 3928 | // not support bitcasting our payload struct to the true union payload type. | 4012 | // not support bitcasting our payload struct to the true union payload type. |
| 3929 | // Instead we use an unnamed struct and every reference to the global | 4013 | // Instead we use an unnamed struct and every reference to the global |
| 3930 | // must pointer cast to the expected type before accessing the union. | 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 | const payload = p: { | 4016 | const payload = p: { |
| 3933 | if (!field_ty.hasRuntimeBitsIgnoreComptime(mod)) { | 4017 | if (!field_ty.hasRuntimeBitsIgnoreComptime(mod)) { |
| 3934 | const padding_len = @as(c_uint, @intCast(layout.payload_size)); | 4018 | const padding_len = layout.payload_size; |
| 3935 | break :p (try o.builder.arrayType(padding_len, .i8)).toLlvm(&o.builder).getUndef(); | 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 }); | 4021 | const payload = try o.lowerValue(un.val); |
| 3938 | need_unnamed = need_unnamed or o.isUnnamedType(field_ty, field); | 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 | const field_size = field_ty.abiSize(mod); | 4026 | const field_size = field_ty.abiSize(mod); |
| 3940 | if (field_size == layout.payload_size) { | 4027 | if (field_size == layout.payload_size) break :p payload; |
| 3941 | break :p field; | 4028 | const padding_len = layout.payload_size - field_size; |
| 3942 | } | 4029 | const padding_ty = try o.builder.arrayType(padding_len, .i8); |
| 3943 | const padding_len = @as(c_uint, @intCast(layout.payload_size - field_size)); | 4030 | break :p try o.builder.structConst( |
| 3944 | const fields: [2]*llvm.Value = .{ | 4031 | try o.builder.structType(.@"packed", &.{ payload_ty, padding_ty }), |
| 3945 | field, (try o.builder.arrayType(padding_len, .i8)).toLlvm(&o.builder).getUndef(), | 4032 | &.{ payload, try o.builder.undefConst(padding_ty) }, |
| 3946 | }; | 4033 | ); |
| 3947 | break :p o.context.constStruct(&fields, fields.len, .True); | | |
| 3948 | }; | 4034 | }; |
| | 4035 | const payload_ty = payload.typeOf(&o.builder); |
| 3949 | | 4036 | |
| 3950 | if (layout.tag_size == 0) { | 4037 | if (layout.tag_size == 0) return o.builder.structConst(if (need_unnamed) |
| 3951 | const fields: [1]*llvm.Value = .{payload}; | 4038 | try o.builder.structType(union_ty.structKind(&o.builder), &.{payload_ty}) |
| 3952 | if (need_unnamed) { | 4039 | else |
| 3953 | return o.context.constStruct(&fields, fields.len, .False); | 4040 | union_ty, &.{payload}); |
| 3954 | } else { | 4041 | const tag = try o.lowerValue(un.tag); |
| 3955 | return llvm_union_ty.constNamedStruct(&fields, fields.len); | 4042 | const tag_ty = tag.typeOf(&o.builder); |
| 3956 | } | 4043 | var fields: [3]Builder.Type = undefined; |
| 3957 | } | 4044 | var vals: [3]Builder.Constant = undefined; |
| 3958 | const llvm_tag_value = try lowerValue(o, .{ | 4045 | var len: usize = 2; |
| 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; | | |
| 3964 | if (layout.tag_align >= layout.payload_align) { | 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 | } else { | 4049 | } else { |
| 3967 | fields = .{ payload, llvm_tag_value, undefined }; | 4050 | fields = .{ payload_ty, tag_ty, undefined }; |
| | 4051 | vals = .{ payload, tag, undefined }; |
| 3968 | } | 4052 | } |
| 3969 | if (layout.padding != 0) { | 4053 | if (layout.padding != 0) { |
| 3970 | fields[2] = (try o.builder.arrayType(layout.padding, .i8)).toLlvm(&o.builder).getUndef(); | 4054 | fields[2] = try o.builder.arrayType(layout.padding, .i8); |
| 3971 | fields_len = 3; | 4055 | vals[2] = try o.builder.undefConst(fields[2]); |
| 3972 | } | 4056 | len = 3; |
| 3973 | if (need_unnamed) { | | |
| 3974 | return o.context.constStruct(&fields, fields_len, .False); | | |
| 3975 | } else { | | |
| 3976 | return llvm_union_ty.constNamedStruct(&fields, fields_len); | | |
| 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 | .memoized_call => unreachable, | 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 | const mod = o.module; | 4068 | const mod = o.module; |
| 3985 | switch (mod.intern_pool.indexToKey(val.toIntern())) { | 4069 | switch (mod.intern_pool.indexToKey(val)) { |
| 3986 | .undef => return o.context.pointerType(0).getUndef(), | 4070 | .undef => return o.builder.undefConst(.ptr), |
| 3987 | .int => { | 4071 | .int => { |
| 3988 | var bigint_space: Value.BigIntSpace = undefined; | 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 | const llvm_int = try lowerBigInt(o, Type.usize, bigint); | 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 | else => unreachable, | 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 { | 4081 | fn lowerBigInt( |
| 3998 | return (try o.builder.bigIntConst(try o.builder.intType(ty.intInfo(o.module).bits), bigint)) | 4082 | o: *Object, |
| 3999 | .toLlvm(&o.builder); | 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 | const ParentPtr = struct { | 4090 | const ParentPtr = struct { |
| ... | @@ -4004,45 +4092,41 @@ pub const Object = struct { | ... | @@ -4004,45 +4092,41 @@ pub const Object = struct { |
| 4004 | llvm_ptr: *llvm.Value, | 4092 | llvm_ptr: *llvm.Value, |
| 4005 | }; | 4093 | }; |
| 4006 | | 4094 | |
| 4007 | fn lowerParentPtrDecl( | 4095 | fn lowerParentPtrDecl(o: *Object, decl_index: Module.Decl.Index) Allocator.Error!Builder.Constant { |
| 4008 | o: *Object, | | |
| 4009 | ptr_val: Value, | | |
| 4010 | decl_index: Module.Decl.Index, | | |
| 4011 | ) Error!*llvm.Value { | | |
| 4012 | const mod = o.module; | 4096 | const mod = o.module; |
| 4013 | const decl = mod.declPtr(decl_index); | 4097 | const decl = mod.declPtr(decl_index); |
| 4014 | try mod.markDeclAlive(decl); | 4098 | try mod.markDeclAlive(decl); |
| 4015 | const ptr_ty = try mod.singleMutPtrType(decl.ty); | 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 | const mod = o.module; | 4104 | const mod = o.module; |
| 4021 | return switch (mod.intern_pool.indexToKey(ptr_val.toIntern()).ptr.addr) { | 4105 | return switch (mod.intern_pool.indexToKey(ptr_val.toIntern()).ptr.addr) { |
| 4022 | .decl => |decl| o.lowerParentPtrDecl(ptr_val, decl), | 4106 | .decl => |decl| o.lowerParentPtrDecl(decl), |
| 4023 | .mut_decl => |mut_decl| o.lowerParentPtrDecl(ptr_val, mut_decl.decl), | 4107 | .mut_decl => |mut_decl| o.lowerParentPtrDecl(mut_decl.decl), |
| 4024 | .int => |int| o.lowerIntAsPtr(int.toValue()), | 4108 | .int => |int| try o.lowerIntAsPtr(int), |
| 4025 | .eu_payload => |eu_ptr| { | 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 | const eu_ty = mod.intern_pool.typeOf(eu_ptr).toType().childType(mod); | 4112 | const eu_ty = mod.intern_pool.typeOf(eu_ptr).toType().childType(mod); |
| 4029 | const payload_ty = eu_ty.errorUnionPayload(mod); | 4113 | const payload_ty = eu_ty.errorUnionPayload(mod); |
| 4030 | if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) { | 4114 | if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) { |
| 4031 | // In this case, we represent pointer to error union the same as pointer | 4115 | // In this case, we represent pointer to error union the same as pointer |
| 4032 | // to the payload. | 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; | 4120 | return o.builder.gepConst(.inbounds, try o.lowerType(eu_ty), parent_ptr, &.{ |
| 4037 | const indices: [2]*llvm.Value = .{ | 4121 | try o.builder.intConst(.i32, 0), |
| 4038 | (try o.builder.intConst(.i32, 0)).toLlvm(&o.builder), | 4122 | try o.builder.intConst(.i32, @as( |
| 4039 | (try o.builder.intConst(.i32, payload_offset)).toLlvm(&o.builder), | 4123 | i32, |
| 4040 | }; | 4124 | if (payload_ty.abiAlignment(mod) > Type.err_int.abiSize(mod)) 2 else 1, |
| 4041 | const eu_llvm_ty = (try o.lowerType(eu_ty)).toLlvm(&o.builder); | 4125 | )), |
| 4042 | return eu_llvm_ty.constInBoundsGEP(parent_llvm_ptr, &indices, indices.len); | 4126 | }); |
| 4043 | }, | 4127 | }, |
| 4044 | .opt_payload => |opt_ptr| { | 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 | const opt_ty = mod.intern_pool.typeOf(opt_ptr).toType().childType(mod); | 4131 | const opt_ty = mod.intern_pool.typeOf(opt_ptr).toType().childType(mod); |
| 4048 | const payload_ty = opt_ty.optionalChild(mod); | 4132 | const payload_ty = opt_ty.optionalChild(mod); |
| ... | @@ -4051,96 +4135,87 @@ pub const Object = struct { | ... | @@ -4051,96 +4135,87 @@ pub const Object = struct { |
| 4051 | { | 4135 | { |
| 4052 | // In this case, we represent pointer to optional the same as pointer | 4136 | // In this case, we represent pointer to optional the same as pointer |
| 4053 | // to the payload. | 4137 | // to the payload. |
| 4054 | return parent_llvm_ptr; | 4138 | return parent_ptr; |
| 4055 | } | 4139 | } |
| 4056 | | 4140 | |
| 4057 | const indices: [2]*llvm.Value = .{ | 4141 | return o.builder.gepConst(.inbounds, try o.lowerType(opt_ty), parent_ptr, &(.{ |
| 4058 | (try o.builder.intConst(.i32, 0)).toLlvm(&o.builder), | 4142 | try o.builder.intConst(.i32, 0), |
| 4059 | } ** 2; | 4143 | } ** 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); | | |
| 4062 | }, | 4144 | }, |
| 4063 | .comptime_field => unreachable, | 4145 | .comptime_field => unreachable, |
| 4064 | .elem => |elem_ptr| { | 4146 | .elem => |elem_ptr| { |
| 4065 | const parent_llvm_ptr = try o.lowerParentPtr(elem_ptr.base.toValue(), true); | 4147 | const parent_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 | }; | | |
| 4070 | const elem_ty = mod.intern_pool.typeOf(elem_ptr.base).toType().elemType2(mod); | 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); | 4149 | |
| 4072 | return elem_llvm_ty.constInBoundsGEP(parent_llvm_ptr, &indices, indices.len); | 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 | .field => |field_ptr| { | 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 | const parent_ty = mod.intern_pool.typeOf(field_ptr.base).toType().childType(mod); | 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 | switch (parent_ty.zigTypeTag(mod)) { | 4159 | switch (parent_ty.zigTypeTag(mod)) { |
| 4080 | .Union => { | 4160 | .Union => { |
| 4081 | if (parent_ty.containerLayout(mod) == .Packed) { | 4161 | if (parent_ty.containerLayout(mod) == .Packed) { |
| 4082 | return parent_llvm_ptr; | 4162 | return parent_ptr; |
| 4083 | } | 4163 | } |
| 4084 | | 4164 | |
| 4085 | const layout = parent_ty.unionGetLayout(mod); | 4165 | const layout = parent_ty.unionGetLayout(mod); |
| 4086 | if (layout.payload_size == 0) { | 4166 | if (layout.payload_size == 0) { |
| 4087 | // In this case a pointer to the union and a pointer to any | 4167 | // In this case a pointer to the union and a pointer to any |
| 4088 | // (void) payload is the same. | 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) | 4171 | |
| 4092 | 0 | 4172 | return o.builder.gepConst(.inbounds, try o.lowerType(parent_ty), parent_ptr, &.{ |
| 4093 | else | 4173 | try o.builder.intConst(.i32, 0), |
| 4094 | @intFromBool(layout.tag_align >= layout.payload_align); | 4174 | try o.builder.intConst(.i32, @intFromBool( |
| 4095 | const indices: [2]*llvm.Value = .{ | 4175 | layout.tag_size > 0 and layout.tag_align >= layout.payload_align, |
| 4096 | (try o.builder.intConst(.i32, 0)).toLlvm(&o.builder), | 4176 | )), |
| 4097 | (try o.builder.intConst(.i32, llvm_pl_index)).toLlvm(&o.builder), | 4177 | }); |
| 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); | | |
| 4101 | }, | 4178 | }, |
| 4102 | .Struct => { | 4179 | .Struct => { |
| 4103 | if (parent_ty.containerLayout(mod) == .Packed) { | 4180 | if (parent_ty.containerLayout(mod) == .Packed) { |
| 4104 | if (!byte_aligned) return parent_llvm_ptr; | 4181 | if (!byte_aligned) return parent_ptr; |
| 4105 | const llvm_usize = try o.lowerType(Type.usize); | 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 | // count bits of fields before this one | 4185 | // count bits of fields before this one |
| 4108 | const prev_bits = b: { | 4186 | const prev_bits = b: { |
| 4109 | var b: usize = 0; | 4187 | var b: usize = 0; |
| 4110 | for (parent_ty.structFields(mod).values()[0..field_index]) |field| { | 4188 | for (parent_ty.structFields(mod).values()[0..field_index]) |field| { |
| 4111 | if (field.is_comptime or !field.ty.hasRuntimeBitsIgnoreComptime(mod)) continue; | 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 | break :b b; | 4192 | break :b b; |
| 4115 | }; | 4193 | }; |
| 4116 | const byte_offset = (try o.builder.intConst(llvm_usize, prev_bits / 8)).toLlvm(&o.builder); | 4194 | const byte_offset = try o.builder.intConst(llvm_usize, prev_bits / 8); |
| 4117 | const field_addr = base_addr.constAdd(byte_offset); | 4195 | const field_addr = try o.builder.binConst(.add, base_addr, byte_offset); |
| 4118 | const final_llvm_ty = o.context.pointerType(0); | 4196 | return o.builder.castConst(.inttoptr, field_addr, .ptr); |
| 4119 | return field_addr.constIntToPtr(final_llvm_ty); | | |
| 4120 | } | 4197 | } |
| 4121 | | 4198 | |
| 4122 | const parent_llvm_ty = (try o.lowerType(parent_ty)).toLlvm(&o.builder); | 4199 | return o.builder.gepConst( |
| 4123 | if (llvmField(parent_ty, field_index, mod)) |llvm_field| { | 4200 | .inbounds, |
| 4124 | const indices: [2]*llvm.Value = .{ | 4201 | try o.lowerType(parent_ty), |
| 4125 | (try o.builder.intConst(.i32, 0)).toLlvm(&o.builder), | 4202 | parent_ptr, |
| 4126 | (try o.builder.intConst(.i32, llvm_field.index)).toLlvm(&o.builder), | 4203 | if (llvmField(parent_ty, field_index, mod)) |llvm_field| &.{ |
| 4127 | }; | 4204 | try o.builder.intConst(.i32, 0), |
| 4128 | return parent_llvm_ty.constInBoundsGEP(parent_llvm_ptr, &indices, indices.len); | 4205 | try o.builder.intConst(.i32, llvm_field.index), |
| 4129 | } else { | 4206 | } else &.{ |
| 4130 | const indices: [1]*llvm.Value = .{ | 4207 | try o.builder.intConst(.i32, @intFromBool( |
| 4131 | (try o.builder.intConst(.i32, @intFromBool(parent_ty.hasRuntimeBitsIgnoreComptime(mod)))).toLlvm(&o.builder), | 4208 | parent_ty.hasRuntimeBitsIgnoreComptime(mod), |
| 4132 | }; | 4209 | )), |
| 4133 | return parent_llvm_ty.constInBoundsGEP(parent_llvm_ptr, &indices, indices.len); | 4210 | }, |
| 4134 | } | 4211 | ); |
| 4135 | }, | 4212 | }, |
| 4136 | .Pointer => { | 4213 | .Pointer => { |
| 4137 | assert(parent_ty.isSlice(mod)); | 4214 | assert(parent_ty.isSlice(mod)); |
| 4138 | const indices: [2]*llvm.Value = .{ | 4215 | return o.builder.gepConst(.inbounds, try o.lowerType(parent_ty), parent_ptr, &.{ |
| 4139 | (try o.builder.intConst(.i32, 0)).toLlvm(&o.builder), | 4216 | try o.builder.intConst(.i32, 0), |
| 4140 | (try o.builder.intConst(.i32, field_index)).toLlvm(&o.builder), | 4217 | try o.builder.intConst(.i32, field_index), |
| 4141 | }; | 4218 | }); |
| 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); | | |
| 4144 | }, | 4219 | }, |
| 4145 | else => unreachable, | 4220 | else => unreachable, |
| 4146 | } | 4221 | } |
| ... | @@ -4148,11 +4223,7 @@ pub const Object = struct { | ... | @@ -4148,11 +4223,7 @@ pub const Object = struct { |
| 4148 | }; | 4223 | }; |
| 4149 | } | 4224 | } |
| 4150 | | 4225 | |
| 4151 | fn lowerDeclRefValue( | 4226 | fn lowerDeclRefValue(o: *Object, ty: Type, decl_index: Module.Decl.Index) Allocator.Error!Builder.Constant { |
| 4152 | o: *Object, | | |
| 4153 | tv: TypedValue, | | |
| 4154 | decl_index: Module.Decl.Index, | | |
| 4155 | ) Error!*llvm.Value { | | |
| 4156 | const mod = o.module; | 4227 | const mod = o.module; |
| 4157 | | 4228 | |
| 4158 | // In the case of something like: | 4229 | // In the case of something like: |
| ... | @@ -4163,69 +4234,63 @@ pub const Object = struct { | ... | @@ -4163,69 +4234,63 @@ pub const Object = struct { |
| 4163 | const decl = mod.declPtr(decl_index); | 4234 | const decl = mod.declPtr(decl_index); |
| 4164 | if (decl.val.getFunction(mod)) |func| { | 4235 | if (decl.val.getFunction(mod)) |func| { |
| 4165 | if (func.owner_decl != decl_index) { | 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 | } else if (decl.val.getExternFunc(mod)) |func| { | 4239 | } else if (decl.val.getExternFunc(mod)) |func| { |
| 4169 | if (func.decl != decl_index) { | 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 | const is_fn_body = decl.ty.zigTypeTag(mod) == .Fn; | 4245 | const is_fn_body = decl.ty.zigTypeTag(mod) == .Fn; |
| 4175 | if ((!is_fn_body and !decl.ty.hasRuntimeBits(mod)) or | 4246 | if ((!is_fn_body and !decl.ty.hasRuntimeBits(mod)) or |
| 4176 | (is_fn_body and mod.typeToFunc(decl.ty).?.is_generic)) | 4247 | (is_fn_body and mod.typeToFunc(decl.ty).?.is_generic)) |
| 4177 | { | 4248 | return o.lowerPtrToVoid(ty); |
| 4178 | return o.lowerPtrToVoid(tv.ty); | | |
| 4179 | } | | |
| 4180 | | 4249 | |
| 4181 | try mod.markDeclAlive(decl); | 4250 | try mod.markDeclAlive(decl); |
| 4182 | | 4251 | |
| 4183 | const llvm_decl_val = if (is_fn_body) | 4252 | const llvm_global = if (is_fn_body) |
| 4184 | (try o.resolveLlvmFunction(decl_index)).toLlvm(&o.builder) | 4253 | (try o.resolveLlvmFunction(decl_index)).ptrConst(&o.builder).global |
| 4185 | else | 4254 | else |
| 4186 | (try o.resolveGlobalDecl(decl_index)).toLlvm(&o.builder); | 4255 | (try o.resolveGlobalDecl(decl_index)).ptrConst(&o.builder).global; |
| 4187 | | 4256 | |
| 4188 | const target = mod.getTarget(); | 4257 | const target = mod.getTarget(); |
| 4189 | const llvm_wanted_addrspace = toLlvmAddressSpace(decl.@"addrspace", target); | 4258 | const llvm_wanted_addrspace = toLlvmAddressSpace(decl.@"addrspace", target); |
| 4190 | const llvm_actual_addrspace = toLlvmGlobalAddressSpace(decl.@"addrspace", target); | 4259 | const llvm_actual_addrspace = toLlvmGlobalAddressSpace(decl.@"addrspace", target); |
| 4191 | const llvm_val = if (llvm_wanted_addrspace != llvm_actual_addrspace) blk: { | 4260 | const llvm_val = if (llvm_wanted_addrspace != llvm_actual_addrspace) try o.builder.castConst( |
| 4192 | const llvm_decl_wanted_ptr_ty = o.context.pointerType(@intFromEnum(llvm_wanted_addrspace)); | 4261 | .addrspacecast, |
| 4193 | break :blk llvm_decl_val.constAddrSpaceCast(llvm_decl_wanted_ptr_ty); | 4262 | llvm_global.toConst(), |
| 4194 | } else llvm_decl_val; | 4263 | try o.builder.ptrType(llvm_wanted_addrspace), |
| 4195 | | 4264 | ) else llvm_global.toConst(); |
| 4196 | const llvm_type = (try o.lowerType(tv.ty)).toLlvm(&o.builder); | 4265 | |
| 4197 | if (tv.ty.zigTypeTag(mod) == .Int) { | 4266 | return o.builder.convConst(if (ty.isAbiInt(mod)) switch (ty.intInfo(mod).signedness) { |
| 4198 | return llvm_val.constPtrToInt(llvm_type); | 4267 | .signed => .signed, |
| 4199 | } else { | 4268 | .unsigned => .unsigned, |
| 4200 | return llvm_val.constBitCast(llvm_type); | 4269 | } else .unneeded, llvm_val, try o.lowerType(ty)); |
| 4201 | } | | |
| 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 | const mod = o.module; | 4273 | const mod = o.module; |
| 4206 | // Even though we are pointing at something which has zero bits (e.g. `void`), | 4274 | // Even though we are pointing at something which has zero bits (e.g. `void`), |
| 4207 | // Pointers are defined to have bits. So we must return something here. | 4275 | // Pointers are defined to have bits. So we must return something here. |
| 4208 | // The value cannot be undefined, because we use the `nonnull` annotation | 4276 | // The value cannot be undefined, because we use the `nonnull` annotation |
| 4209 | // for non-optional pointers. We also need to respect the alignment, even though | 4277 | // for non-optional pointers. We also need to respect the alignment, even though |
| 4210 | // the address will never be dereferenced. | 4278 | // the address will never be dereferenced. |
| 4211 | const llvm_usize = try o.lowerType(Type.usize); | 4279 | const int: u64 = ptr_ty.ptrInfo(mod).flags.alignment.toByteUnitsOptional() orelse |
| 4212 | const llvm_ptr_ty = (try o.lowerType(ptr_ty)).toLlvm(&o.builder); | 4280 | // Note that these 0xaa values are appropriate even in release-optimized builds |
| 4213 | if (ptr_ty.ptrInfo(mod).flags.alignment.toByteUnitsOptional()) |alignment| { | 4281 | // because we need a well-defined value that is not null, and LLVM does not |
| 4214 | return (try o.builder.intConst(llvm_usize, alignment)).toLlvm(&o.builder).constIntToPtr(llvm_ptr_ty); | 4282 | // have an "undef_but_not_null" attribute. As an example, if this `alloc` AIR |
| 4215 | } | 4283 | // instruction is followed by a `wrap_optional`, it will return this value |
| 4216 | // Note that these 0xaa values are appropriate even in release-optimized builds | 4284 | // verbatim, and the result should test as non-null. |
| 4217 | // because we need a well-defined value that is not null, and LLVM does not | 4285 | switch (mod.getTarget().ptrBitWidth()) { |
| 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()) { | | |
| 4223 | 16 => 0xaaaa, | 4286 | 16 => 0xaaaa, |
| 4224 | 32 => 0xaaaaaaaa, | 4287 | 32 => 0xaaaaaaaa, |
| 4225 | 64 => 0xaaaaaaaa_aaaaaaaa, | 4288 | 64 => 0xaaaaaaaa_aaaaaaaa, |
| 4226 | else => unreachable, | 4289 | else => unreachable, |
| 4227 | })); | 4290 | }; |
| 4228 | return int.toLlvm(&o.builder).constIntToPtr(llvm_ptr_ty); | 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 | fn addAttr(o: *Object, val: *llvm.Value, index: llvm.AttributeIndex, name: []const u8) void { | 4296 | fn addAttr(o: *Object, val: *llvm.Value, index: llvm.AttributeIndex, name: []const u8) void { |
| ... | @@ -4436,26 +4501,29 @@ pub const DeclGen = struct { | ... | @@ -4436,26 +4501,29 @@ pub const DeclGen = struct { |
| 4436 | _ = try o.resolveLlvmFunction(extern_func.decl); | 4501 | _ = try o.resolveLlvmFunction(extern_func.decl); |
| 4437 | } else { | 4502 | } else { |
| 4438 | const target = mod.getTarget(); | 4503 | const target = mod.getTarget(); |
| 4439 | const object_index = try o.resolveGlobalDecl(decl_index); | 4504 | const object = try o.resolveGlobalDecl(decl_index); |
| 4440 | const object = object_index.ptr(&o.builder); | 4505 | const global = object.ptrConst(&o.builder).global; |
| 4441 | const global = object.global.ptr(&o.builder); | 4506 | var llvm_global = global.toLlvm(&o.builder); |
| 4442 | var llvm_global = object.global.toLlvm(&o.builder); | 4507 | global.ptr(&o.builder).alignment = Builder.Alignment.fromByteUnits(decl.getAlignment(mod)); |
| 4443 | global.alignment = Builder.Alignment.fromByteUnits(decl.getAlignment(mod)); | | |
| 4444 | llvm_global.setAlignment(decl.getAlignment(mod)); | 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 | assert(decl.has_tv); | 4513 | assert(decl.has_tv); |
| 4447 | const init_val = if (decl.val.getVariable(mod)) |variable| init_val: { | 4514 | const init_val = if (decl.val.getVariable(mod)) |decl_var| init_val: { |
| 4448 | object.mutability = .global; | 4515 | object.ptr(&o.builder).mutability = .global; |
| 4449 | break :init_val variable.init; | 4516 | break :init_val decl_var.init; |
| 4450 | } else init_val: { | 4517 | } else init_val: { |
| 4451 | object.mutability = .constant; | 4518 | object.ptr(&o.builder).mutability = .constant; |
| 4452 | llvm_global.setGlobalConstant(.True); | 4519 | llvm_global.setGlobalConstant(.True); |
| 4453 | break :init_val decl.val.toIntern(); | 4520 | break :init_val decl.val.toIntern(); |
| 4454 | }; | 4521 | }; |
| 4455 | if (init_val != .none) { | 4522 | if (init_val != .none) { |
| 4456 | const llvm_init = try o.lowerValue(.{ .ty = decl.ty, .val = init_val.toValue() }); | 4523 | const llvm_init = try o.lowerValue(init_val); |
| 4457 | if (llvm_global.globalGetValueType() == llvm_init.typeOf()) { | 4524 | if (llvm_global.globalGetValueType() == llvm_init.typeOf(&o.builder).toLlvm(&o.builder)) { |
| 4458 | llvm_global.setInitializer(llvm_init); | 4525 | object.ptr(&o.builder).init = llvm_init; |
| | 4526 | llvm_global.setInitializer(llvm_init.toLlvm(&o.builder)); |
| 4459 | } else { | 4527 | } else { |
| 4460 | // LLVM does not allow us to change the type of globals. So we must | 4528 | // LLVM does not allow us to change the type of globals. So we must |
| 4461 | // create a new global with the correct type, copy all its attributes, | 4529 | // create a new global with the correct type, copy all its attributes, |
| ... | @@ -4472,20 +4540,21 @@ pub const DeclGen = struct { | ... | @@ -4472,20 +4540,21 @@ pub const DeclGen = struct { |
| 4472 | // Related: https://github.com/ziglang/zig/issues/13265 | 4540 | // Related: https://github.com/ziglang/zig/issues/13265 |
| 4473 | const llvm_global_addrspace = toLlvmGlobalAddressSpace(decl.@"addrspace", target); | 4541 | const llvm_global_addrspace = toLlvmGlobalAddressSpace(decl.@"addrspace", target); |
| 4474 | const new_global = o.llvm_module.addGlobalInAddressSpace( | 4542 | const new_global = o.llvm_module.addGlobalInAddressSpace( |
| 4475 | llvm_init.typeOf(), | 4543 | llvm_init.typeOf(&o.builder).toLlvm(&o.builder), |
| 4476 | "", | 4544 | "", |
| 4477 | @intFromEnum(llvm_global_addrspace), | 4545 | @intFromEnum(llvm_global_addrspace), |
| 4478 | ); | 4546 | ); |
| 4479 | new_global.setLinkage(llvm_global.getLinkage()); | 4547 | new_global.setLinkage(llvm_global.getLinkage()); |
| 4480 | new_global.setUnnamedAddr(llvm_global.getUnnamedAddress()); | 4548 | new_global.setUnnamedAddr(llvm_global.getUnnamedAddress()); |
| 4481 | new_global.setAlignment(llvm_global.getAlignment()); | 4549 | new_global.setAlignment(llvm_global.getAlignment()); |
| 4482 | if (mod.intern_pool.stringToSliceUnwrap(decl.@"linksection")) |s| | 4550 | if (mod.intern_pool.stringToSliceUnwrap(decl.@"linksection")) |section| |
| 4483 | new_global.setSection(s); | 4551 | new_global.setSection(section); |
| 4484 | new_global.setInitializer(llvm_init); | 4552 | new_global.setInitializer(llvm_init.toLlvm(&o.builder)); |
| 4485 | // TODO: How should this work then the address space of a global changed? | 4553 | // TODO: How should this work then the address space of a global changed? |
| 4486 | llvm_global.replaceAllUsesWith(new_global); | 4554 | llvm_global.replaceAllUsesWith(new_global); |
| 4487 | new_global.takeName(llvm_global); | 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 | llvm_global.deleteGlobal(); | 4558 | llvm_global.deleteGlobal(); |
| 4490 | llvm_global = new_global; | 4559 | llvm_global = new_global; |
| 4491 | } | 4560 | } |
| ... | @@ -4601,24 +4670,45 @@ pub const FuncGen = struct { | ... | @@ -4601,24 +4670,45 @@ pub const FuncGen = struct { |
| 4601 | fn resolveValue(self: *FuncGen, tv: TypedValue) !*llvm.Value { | 4670 | fn resolveValue(self: *FuncGen, tv: TypedValue) !*llvm.Value { |
| 4602 | const o = self.dg.object; | 4671 | const o = self.dg.object; |
| 4603 | const mod = o.module; | 4672 | const mod = o.module; |
| 4604 | const llvm_val = try o.lowerValue(tv); | 4673 | const llvm_val = try o.lowerValue(tv.val.toIntern()); |
| 4605 | if (!isByRef(tv.ty, mod)) return llvm_val; | 4674 | if (!isByRef(tv.ty, mod)) return llvm_val.toLlvm(&o.builder); |
| 4606 | | 4675 | |
| 4607 | // We have an LLVM value but we need to create a global constant and | 4676 | // We have an LLVM value but we need to create a global constant and |
| 4608 | // set the value as its initializer, and then return a pointer to the global. | 4677 | // set the value as its initializer, and then return a pointer to the global. |
| 4609 | const target = mod.getTarget(); | 4678 | const target = mod.getTarget(); |
| 4610 | const llvm_wanted_addrspace = toLlvmAddressSpace(.generic, target); | 4679 | const llvm_wanted_addrspace = toLlvmAddressSpace(.generic, target); |
| 4611 | const llvm_actual_addrspace = toLlvmGlobalAddressSpace(.generic, target); | 4680 | const llvm_actual_addrspace = toLlvmGlobalAddressSpace(.generic, target); |
| 4612 | const global = o.llvm_module.addGlobalInAddressSpace(llvm_val.typeOf(), "", @intFromEnum(llvm_actual_addrspace)); | 4681 | const llvm_ty = llvm_val.typeOf(&o.builder); |
| 4613 | global.setInitializer(llvm_val); | 4682 | const llvm_alignment = tv.ty.abiAlignment(mod); |
| 4614 | global.setLinkage(.Private); | 4683 | const llvm_global = o.llvm_module.addGlobalInAddressSpace(llvm_ty.toLlvm(&o.builder), "", @intFromEnum(llvm_actual_addrspace)); |
| 4615 | global.setGlobalConstant(.True); | 4684 | llvm_global.setInitializer(llvm_val.toLlvm(&o.builder)); |
| 4616 | global.setUnnamedAddr(.True); | 4685 | llvm_global.setLinkage(.Private); |
| 4617 | global.setAlignment(tv.ty.abiAlignment(mod)); | 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 | const addrspace_casted_ptr = if (llvm_actual_addrspace != llvm_wanted_addrspace) | 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 | else | 4710 | else |
| 4621 | global; | 4711 | llvm_global; |
| 4622 | return addrspace_casted_ptr; | 4712 | return addrspace_casted_ptr; |
| 4623 | } | 4713 | } |
| 4624 | | 4714 | |
| ... | @@ -5197,10 +5287,7 @@ pub const FuncGen = struct { | ... | @@ -5197,10 +5287,7 @@ pub const FuncGen = struct { |
| 5197 | const msg_decl_index = mod.panic_messages[@intFromEnum(panic_id)].unwrap().?; | 5287 | const msg_decl_index = mod.panic_messages[@intFromEnum(panic_id)].unwrap().?; |
| 5198 | const msg_decl = mod.declPtr(msg_decl_index); | 5288 | const msg_decl = mod.declPtr(msg_decl_index); |
| 5199 | const msg_len = msg_decl.ty.childType(mod).arrayLen(mod); | 5289 | const msg_len = msg_decl.ty.childType(mod).arrayLen(mod); |
| 5200 | const msg_ptr = try o.lowerValue(.{ | 5290 | const msg_ptr = try o.lowerValue(try msg_decl.internValue(mod)); |
| 5201 | .ty = msg_decl.ty, | | |
| 5202 | .val = msg_decl.val, | | |
| 5203 | }); | | |
| 5204 | const null_opt_addr_global = try o.getNullOptAddr(); | 5291 | const null_opt_addr_global = try o.getNullOptAddr(); |
| 5205 | const target = mod.getTarget(); | 5292 | const target = mod.getTarget(); |
| 5206 | const llvm_usize = try o.lowerType(Type.usize); | 5293 | const llvm_usize = try o.lowerType(Type.usize); |
| ... | @@ -5212,9 +5299,9 @@ pub const FuncGen = struct { | ... | @@ -5212,9 +5299,9 @@ pub const FuncGen = struct { |
| 5212 | // ptr @2, ; addr (null ?usize) | 5299 | // ptr @2, ; addr (null ?usize) |
| 5213 | // ) | 5300 | // ) |
| 5214 | const args = [4]*llvm.Value{ | 5301 | const args = [4]*llvm.Value{ |
| 5215 | msg_ptr, | 5302 | msg_ptr.toLlvm(&o.builder), |
| 5216 | (try o.builder.intConst(llvm_usize, msg_len)).toLlvm(&o.builder), | 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 | null_opt_addr_global, | 5305 | null_opt_addr_global, |
| 5219 | }; | 5306 | }; |
| 5220 | const panic_func = mod.funcInfo(mod.panic_func_index); | 5307 | const panic_func = mod.funcInfo(mod.panic_func_index); |
| ... | @@ -5672,8 +5759,8 @@ pub const FuncGen = struct { | ... | @@ -5672,8 +5759,8 @@ pub const FuncGen = struct { |
| 5672 | | 5759 | |
| 5673 | if (!err_union_ty.errorUnionSet(mod).errorSetIsEmpty(mod)) { | 5760 | if (!err_union_ty.errorUnionSet(mod).errorSetIsEmpty(mod)) { |
| 5674 | const is_err = err: { | 5761 | const is_err = err: { |
| 5675 | const err_set_ty = (try o.lowerType(Type.anyerror)).toLlvm(&o.builder); | 5762 | const err_set_ty = Builder.Type.err_int.toLlvm(&o.builder); |
| 5676 | const zero = err_set_ty.constNull(); | 5763 | const zero = (try o.builder.intConst(Builder.Type.err_int, 0)).toLlvm(&o.builder); |
| 5677 | if (!payload_has_bits) { | 5764 | if (!payload_has_bits) { |
| 5678 | // TODO add alignment to this load | 5765 | // TODO add alignment to this load |
| 5679 | const loaded = if (operand_is_ptr) | 5766 | const loaded = if (operand_is_ptr) |
| ... | @@ -6034,7 +6121,10 @@ pub const FuncGen = struct { | ... | @@ -6034,7 +6121,10 @@ pub const FuncGen = struct { |
| 6034 | const array_llvm_ty = (try o.lowerType(array_ty)).toLlvm(&o.builder); | 6121 | const array_llvm_ty = (try o.lowerType(array_ty)).toLlvm(&o.builder); |
| 6035 | const elem_ty = array_ty.childType(mod); | 6122 | const elem_ty = array_ty.childType(mod); |
| 6036 | if (isByRef(array_ty, mod)) { | 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 | if (isByRef(elem_ty, mod)) { | 6128 | if (isByRef(elem_ty, mod)) { |
| 6039 | const elem_ptr = self.builder.buildInBoundsGEP(array_llvm_ty, array_llvm_val, &indices, indices.len, ""); | 6129 | const elem_ptr = self.builder.buildInBoundsGEP(array_llvm_ty, array_llvm_val, &indices, indices.len, ""); |
| 6040 | if (canElideLoad(self, body_tail)) | 6130 | if (canElideLoad(self, body_tail)) |
| ... | @@ -6082,7 +6172,10 @@ pub const FuncGen = struct { | ... | @@ -6082,7 +6172,10 @@ pub const FuncGen = struct { |
| 6082 | // TODO: when we go fully opaque pointers in LLVM 16 we can remove this branch | 6172 | // TODO: when we go fully opaque pointers in LLVM 16 we can remove this branch |
| 6083 | const ptr = if (ptr_ty.isSinglePointer(mod)) ptr: { | 6173 | const ptr = if (ptr_ty.isSinglePointer(mod)) ptr: { |
| 6084 | // If this is a single-item pointer to an array, we need another index in the GEP. | 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 | break :ptr self.builder.buildInBoundsGEP(llvm_elem_ty, base_ptr, &indices, indices.len, ""); | 6179 | break :ptr self.builder.buildInBoundsGEP(llvm_elem_ty, base_ptr, &indices, indices.len, ""); |
| 6087 | } else ptr: { | 6180 | } else ptr: { |
| 6088 | const indices: [1]*llvm.Value = .{rhs}; | 6181 | const indices: [1]*llvm.Value = .{rhs}; |
| ... | @@ -6105,7 +6198,8 @@ pub const FuncGen = struct { | ... | @@ -6105,7 +6198,8 @@ pub const FuncGen = struct { |
| 6105 | const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data; | 6198 | const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data; |
| 6106 | const ptr_ty = self.typeOf(bin_op.lhs); | 6199 | const ptr_ty = self.typeOf(bin_op.lhs); |
| 6107 | const elem_ty = ptr_ty.childType(mod); | 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 | const base_ptr = try self.resolveInst(bin_op.lhs); | 6204 | const base_ptr = try self.resolveInst(bin_op.lhs); |
| 6111 | const rhs = try self.resolveInst(bin_op.rhs); | 6205 | const rhs = try self.resolveInst(bin_op.rhs); |
| ... | @@ -6116,7 +6210,10 @@ pub const FuncGen = struct { | ... | @@ -6116,7 +6210,10 @@ pub const FuncGen = struct { |
| 6116 | const llvm_elem_ty = (try o.lowerPtrElemTy(elem_ty)).toLlvm(&o.builder); | 6210 | const llvm_elem_ty = (try o.lowerPtrElemTy(elem_ty)).toLlvm(&o.builder); |
| 6117 | if (ptr_ty.isSinglePointer(mod)) { | 6211 | if (ptr_ty.isSinglePointer(mod)) { |
| 6118 | // If this is a single-item pointer to an array, we need another index in the GEP. | 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 | return self.builder.buildInBoundsGEP(llvm_elem_ty, base_ptr, &indices, indices.len, ""); | 6217 | return self.builder.buildInBoundsGEP(llvm_elem_ty, base_ptr, &indices, indices.len, ""); |
| 6121 | } else { | 6218 | } else { |
| 6122 | const indices: [1]*llvm.Value = .{rhs}; | 6219 | const indices: [1]*llvm.Value = .{rhs}; |
| ... | @@ -6829,8 +6926,11 @@ pub const FuncGen = struct { | ... | @@ -6829,8 +6926,11 @@ pub const FuncGen = struct { |
| 6829 | operand; | 6926 | operand; |
| 6830 | if (payload_ty.isSlice(mod)) { | 6927 | if (payload_ty.isSlice(mod)) { |
| 6831 | const slice_ptr = self.builder.buildExtractValue(loaded, 0, ""); | 6928 | const slice_ptr = self.builder.buildExtractValue(loaded, 0, ""); |
| 6832 | const ptr_ty = (try o.lowerType(payload_ty.slicePtrFieldType(mod))).toLlvm(&o.builder); | 6929 | const ptr_ty = try o.builder.ptrType(toLlvmAddressSpace( |
| 6833 | return self.builder.buildICmp(pred, slice_ptr, ptr_ty.constNull(), ""); | 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 | return self.builder.buildICmp(pred, loaded, optional_llvm_ty.constNull(), ""); | 6935 | return self.builder.buildICmp(pred, loaded, optional_llvm_ty.constNull(), ""); |
| 6836 | } | 6936 | } |
| ... | @@ -6867,8 +6967,7 @@ pub const FuncGen = struct { | ... | @@ -6867,8 +6967,7 @@ pub const FuncGen = struct { |
| 6867 | const operand_ty = self.typeOf(un_op); | 6967 | const operand_ty = self.typeOf(un_op); |
| 6868 | const err_union_ty = if (operand_is_ptr) operand_ty.childType(mod) else operand_ty; | 6968 | const err_union_ty = if (operand_is_ptr) operand_ty.childType(mod) else operand_ty; |
| 6869 | const payload_ty = err_union_ty.errorUnionPayload(mod); | 6969 | const payload_ty = err_union_ty.errorUnionPayload(mod); |
| 6870 | const err_set_ty = (try o.lowerType(Type.anyerror)).toLlvm(&o.builder); | 6970 | const zero = (try o.builder.intConst(Builder.Type.err_int, 0)).toLlvm(&o.builder); |
| 6871 | const zero = err_set_ty.constNull(); | | |
| 6872 | | 6971 | |
| 6873 | if (err_union_ty.errorUnionSet(mod).errorSetIsEmpty(mod)) { | 6972 | if (err_union_ty.errorUnionSet(mod).errorSetIsEmpty(mod)) { |
| 6874 | const val: Builder.Constant = switch (op) { | 6973 | const val: Builder.Constant = switch (op) { |
| ... | @@ -6892,7 +6991,7 @@ pub const FuncGen = struct { | ... | @@ -6892,7 +6991,7 @@ pub const FuncGen = struct { |
| 6892 | if (operand_is_ptr or isByRef(err_union_ty, mod)) { | 6991 | if (operand_is_ptr or isByRef(err_union_ty, mod)) { |
| 6893 | const err_union_llvm_ty = (try o.lowerType(err_union_ty)).toLlvm(&o.builder); | 6992 | const err_union_llvm_ty = (try o.lowerType(err_union_ty)).toLlvm(&o.builder); |
| 6894 | const err_field_ptr = self.builder.buildStructGEP(err_union_llvm_ty, operand, err_field_index, ""); | 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 | return self.builder.buildICmp(op, loaded, zero, ""); | 6995 | return self.builder.buildICmp(op, loaded, zero, ""); |
| 6897 | } | 6996 | } |
| 6898 | | 6997 | |
| ... | @@ -7057,9 +7156,9 @@ pub const FuncGen = struct { | ... | @@ -7057,9 +7156,9 @@ pub const FuncGen = struct { |
| 7057 | const err_union_ty = self.typeOf(ty_op.operand).childType(mod); | 7156 | const err_union_ty = self.typeOf(ty_op.operand).childType(mod); |
| 7058 | | 7157 | |
| 7059 | const payload_ty = err_union_ty.errorUnionPayload(mod); | 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 | if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) { | 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 | return operand; | 7162 | return operand; |
| 7064 | } | 7163 | } |
| 7065 | const err_union_llvm_ty = (try o.lowerType(err_union_ty)).toLlvm(&o.builder); | 7164 | const err_union_llvm_ty = (try o.lowerType(err_union_ty)).toLlvm(&o.builder); |
| ... | @@ -7067,7 +7166,7 @@ pub const FuncGen = struct { | ... | @@ -7067,7 +7166,7 @@ pub const FuncGen = struct { |
| 7067 | const error_offset = errUnionErrorOffset(payload_ty, mod); | 7166 | const error_offset = errUnionErrorOffset(payload_ty, mod); |
| 7068 | // First set the non-error value. | 7167 | // First set the non-error value. |
| 7069 | const non_null_ptr = self.builder.buildStructGEP(err_union_llvm_ty, operand, error_offset, ""); | 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 | store_inst.setAlignment(Type.anyerror.abiAlignment(mod)); | 7170 | store_inst.setAlignment(Type.anyerror.abiAlignment(mod)); |
| 7072 | } | 7171 | } |
| 7073 | // Then return the payload pointer (only if it is used). | 7172 | // Then return the payload pointer (only if it is used). |
| ... | @@ -7146,7 +7245,7 @@ pub const FuncGen = struct { | ... | @@ -7146,7 +7245,7 @@ pub const FuncGen = struct { |
| 7146 | if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) { | 7245 | if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) { |
| 7147 | return operand; | 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 | const err_un_llvm_ty = (try o.lowerType(err_un_ty)).toLlvm(&o.builder); | 7249 | const err_un_llvm_ty = (try o.lowerType(err_un_ty)).toLlvm(&o.builder); |
| 7151 | | 7250 | |
| 7152 | const payload_offset = errUnionPayloadOffset(payload_ty, mod); | 7251 | const payload_offset = errUnionPayloadOffset(payload_ty, mod); |
| ... | @@ -7606,7 +7705,10 @@ pub const FuncGen = struct { | ... | @@ -7606,7 +7705,10 @@ pub const FuncGen = struct { |
| 7606 | switch (ptr_ty.ptrSize(mod)) { | 7705 | switch (ptr_ty.ptrSize(mod)) { |
| 7607 | .One => { | 7706 | .One => { |
| 7608 | // It's a pointer to an array, so according to LLVM we need an extra GEP index. | 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 | return self.builder.buildInBoundsGEP(llvm_elem_ty, ptr, &indices, indices.len, ""); | 7712 | return self.builder.buildInBoundsGEP(llvm_elem_ty, ptr, &indices, indices.len, ""); |
| 7611 | }, | 7713 | }, |
| 7612 | .C, .Many => { | 7714 | .C, .Many => { |
| ... | @@ -7635,7 +7737,8 @@ pub const FuncGen = struct { | ... | @@ -7635,7 +7737,8 @@ pub const FuncGen = struct { |
| 7635 | .One => { | 7737 | .One => { |
| 7636 | // It's a pointer to an array, so according to LLVM we need an extra GEP index. | 7738 | // It's a pointer to an array, so according to LLVM we need an extra GEP index. |
| 7637 | const indices: [2]*llvm.Value = .{ | 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 | return self.builder.buildInBoundsGEP(llvm_elem_ty, ptr, &indices, indices.len, ""); | 7743 | return self.builder.buildInBoundsGEP(llvm_elem_ty, ptr, &indices, indices.len, ""); |
| 7641 | }, | 7744 | }, |
| ... | @@ -8448,7 +8551,7 @@ pub const FuncGen = struct { | ... | @@ -8448,7 +8551,7 @@ pub const FuncGen = struct { |
| 8448 | const ptr_ty = self.typeOfIndex(inst); | 8551 | const ptr_ty = self.typeOfIndex(inst); |
| 8449 | const pointee_type = ptr_ty.childType(mod); | 8552 | const pointee_type = ptr_ty.childType(mod); |
| 8450 | if (!pointee_type.isFnOrHasRuntimeBitsIgnoreComptime(mod)) | 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 | const pointee_llvm_ty = (try o.lowerType(pointee_type)).toLlvm(&o.builder); | 8556 | const pointee_llvm_ty = (try o.lowerType(pointee_type)).toLlvm(&o.builder); |
| 8454 | const alignment = ptr_ty.ptrAlignment(mod); | 8557 | const alignment = ptr_ty.ptrAlignment(mod); |
| ... | @@ -8460,7 +8563,8 @@ pub const FuncGen = struct { | ... | @@ -8460,7 +8563,8 @@ pub const FuncGen = struct { |
| 8460 | const mod = o.module; | 8563 | const mod = o.module; |
| 8461 | const ptr_ty = self.typeOfIndex(inst); | 8564 | const ptr_ty = self.typeOfIndex(inst); |
| 8462 | const ret_ty = ptr_ty.childType(mod); | 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 | if (self.ret_ptr) |ret_ptr| return ret_ptr; | 8568 | if (self.ret_ptr) |ret_ptr| return ret_ptr; |
| 8465 | const ret_llvm_ty = (try o.lowerType(ret_ty)).toLlvm(&o.builder); | 8569 | const ret_llvm_ty = (try o.lowerType(ret_ty)).toLlvm(&o.builder); |
| 8466 | return self.buildAlloca(ret_llvm_ty, ptr_ty.ptrAlignment(mod)); | 8570 | return self.buildAlloca(ret_llvm_ty, ptr_ty.ptrAlignment(mod)); |
| ... | @@ -8566,18 +8670,19 @@ pub const FuncGen = struct { | ... | @@ -8566,18 +8670,19 @@ pub const FuncGen = struct { |
| 8566 | _ = inst; | 8670 | _ = inst; |
| 8567 | const o = self.dg.object; | 8671 | const o = self.dg.object; |
| 8568 | const mod = o.module; | 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 | const target = mod.getTarget(); | 8674 | const target = mod.getTarget(); |
| 8571 | if (!target_util.supportsReturnAddress(target)) { | 8675 | if (!target_util.supportsReturnAddress(target)) { |
| 8572 | // https://github.com/ziglang/zig/issues/11946 | 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 | const llvm_fn = try self.getIntrinsic("llvm.returnaddress", &.{}); | 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 | const ptr_val = self.builder.buildCall(llvm_fn.globalGetValueType(), llvm_fn, &params, params.len, .Fast, .Auto, ""); | 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 | fn airFrameAddress(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { | 8688 | fn airFrameAddress(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { |
| ... | @@ -8589,7 +8694,9 @@ pub const FuncGen = struct { | ... | @@ -8589,7 +8694,9 @@ pub const FuncGen = struct { |
| 8589 | break :blk o.llvm_module.addFunction(llvm_fn_name, fn_type.toLlvm(&o.builder)); | 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 | const ptr_val = self.builder.buildCall(llvm_fn.globalGetValueType(), llvm_fn, &params, params.len, .Fast, .Auto, ""); | 8700 | const ptr_val = self.builder.buildCall(llvm_fn.globalGetValueType(), llvm_fn, &params, params.len, .Fast, .Auto, ""); |
| 8594 | const llvm_usize = (try o.lowerType(Type.usize)).toLlvm(&o.builder); | 8701 | const llvm_usize = (try o.lowerType(Type.usize)).toLlvm(&o.builder); |
| 8595 | return self.builder.buildPtrToInt(ptr_val, llvm_usize, ""); | 8702 | return self.builder.buildPtrToInt(ptr_val, llvm_usize, ""); |
| ... | @@ -9060,10 +9167,9 @@ pub const FuncGen = struct { | ... | @@ -9060,10 +9167,9 @@ pub const FuncGen = struct { |
| 9060 | const operand_ty = self.typeOf(ty_op.operand); | 9167 | const operand_ty = self.typeOf(ty_op.operand); |
| 9061 | const operand = try self.resolveInst(ty_op.operand); | 9168 | const operand = try self.resolveInst(ty_op.operand); |
| 9062 | | 9169 | |
| 9063 | const llvm_i1 = Builder.Type.i1.toLlvm(&o.builder); | | |
| 9064 | const fn_val = try self.getIntrinsic(llvm_fn_name, &.{try o.lowerType(operand_ty)}); | 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 | const wrong_size_result = self.builder.buildCall(fn_val.globalGetValueType(), fn_val, &params, params.len, .C, .Auto, ""); | 9173 | const wrong_size_result = self.builder.buildCall(fn_val.globalGetValueType(), fn_val, &params, params.len, .C, .Auto, ""); |
| 9068 | const result_ty = self.typeOfIndex(inst); | 9174 | const result_ty = self.typeOfIndex(inst); |
| 9069 | const result_llvm_ty = (try o.lowerType(result_ty)).toLlvm(&o.builder); | 9175 | const result_llvm_ty = (try o.lowerType(result_ty)).toLlvm(&o.builder); |
| ... | @@ -9170,11 +9276,9 @@ pub const FuncGen = struct { | ... | @@ -9170,11 +9276,9 @@ pub const FuncGen = struct { |
| 9170 | | 9276 | |
| 9171 | for (names) |name| { | 9277 | for (names) |name| { |
| 9172 | const err_int = @as(Module.ErrorInt, @intCast(mod.global_error_set.getIndex(name).?)); | 9278 | const err_int = @as(Module.ErrorInt, @intCast(mod.global_error_set.getIndex(name).?)); |
| 9173 | const this_tag_int_value = try o.lowerValue(.{ | 9279 | const this_tag_int_value = |
| 9174 | .ty = Type.err_int, | 9280 | try o.lowerValue((try mod.intValue(Type.err_int, err_int)).toIntern()); |
| 9175 | .val = try mod.intValue(Type.err_int, err_int), | 9281 | switch_instr.addCase(this_tag_int_value.toLlvm(&o.builder), valid_block); |
| 9176 | }); | | |
| 9177 | switch_instr.addCase(this_tag_int_value, valid_block); | | |
| 9178 | } | 9282 | } |
| 9179 | self.builder.positionBuilderAtEnd(valid_block); | 9283 | self.builder.positionBuilderAtEnd(valid_block); |
| 9180 | _ = self.builder.buildBr(end_block); | 9284 | _ = self.builder.buildBr(end_block); |
| ... | @@ -9258,13 +9362,9 @@ pub const FuncGen = struct { | ... | @@ -9258,13 +9362,9 @@ pub const FuncGen = struct { |
| 9258 | | 9362 | |
| 9259 | for (enum_type.names, 0..) |_, field_index_usize| { | 9363 | for (enum_type.names, 0..) |_, field_index_usize| { |
| 9260 | const field_index = @as(u32, @intCast(field_index_usize)); | 9364 | const field_index = @as(u32, @intCast(field_index_usize)); |
| 9261 | const this_tag_int_value = int: { | 9365 | const this_tag_int_value = |
| 9262 | break :int try o.lowerValue(.{ | 9366 | try o.lowerValue((try mod.enumValueFieldIndex(enum_ty, field_index)).toIntern()); |
| 9263 | .ty = enum_ty, | 9367 | switch_instr.addCase(this_tag_int_value.toLlvm(&o.builder), named_block); |
| 9264 | .val = try mod.enumValueFieldIndex(enum_ty, field_index), | | |
| 9265 | }); | | |
| 9266 | }; | | |
| 9267 | switch_instr.addCase(this_tag_int_value, named_block); | | |
| 9268 | } | 9368 | } |
| 9269 | self.builder.positionBuilderAtEnd(named_block); | 9369 | self.builder.positionBuilderAtEnd(named_block); |
| 9270 | _ = self.builder.buildRet(Builder.Constant.true.toLlvm(&o.builder)); | 9370 | _ = self.builder.buildRet(Builder.Constant.true.toLlvm(&o.builder)); |
| ... | @@ -9371,11 +9471,9 @@ pub const FuncGen = struct { | ... | @@ -9371,11 +9471,9 @@ pub const FuncGen = struct { |
| 9371 | slice_global.setAlignment(slice_alignment); | 9471 | slice_global.setAlignment(slice_alignment); |
| 9372 | | 9472 | |
| 9373 | const return_block = self.context.appendBasicBlock(fn_val, "Name"); | 9473 | const return_block = self.context.appendBasicBlock(fn_val, "Name"); |
| 9374 | const this_tag_int_value = try o.lowerValue(.{ | 9474 | const this_tag_int_value = |
| 9375 | .ty = enum_ty, | 9475 | try o.lowerValue((try mod.enumValueFieldIndex(enum_ty, field_index)).toIntern()); |
| 9376 | .val = try mod.enumValueFieldIndex(enum_ty, field_index), | 9476 | switch_instr.addCase(this_tag_int_value.toLlvm(&o.builder), return_block); |
| 9377 | }); | | |
| 9378 | switch_instr.addCase(this_tag_int_value, return_block); | | |
| 9379 | | 9477 | |
| 9380 | self.builder.positionBuilderAtEnd(return_block); | 9478 | self.builder.positionBuilderAtEnd(return_block); |
| 9381 | const loaded = self.builder.buildLoad(llvm_ret_ty, slice_global, ""); | 9479 | const loaded = self.builder.buildLoad(llvm_ret_ty, slice_global, ""); |
| ... | @@ -9404,7 +9502,12 @@ pub const FuncGen = struct { | ... | @@ -9404,7 +9502,12 @@ pub const FuncGen = struct { |
| 9404 | const fn_type = try o.builder.fnType(.i1, &.{Builder.Type.err_int}, .normal); | 9502 | const fn_type = try o.builder.fnType(.i1, &.{Builder.Type.err_int}, .normal); |
| 9405 | const llvm_fn = o.llvm_module.addFunction(lt_errors_fn_name, fn_type.toLlvm(&o.builder)); | 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 | var global = Builder.Global{ | 9509 | var global = Builder.Global{ |
| | 9510 | .linkage = .internal, |
| 9408 | .type = fn_type, | 9511 | .type = fn_type, |
| 9409 | .kind = .{ .function = @enumFromInt(o.builder.functions.items.len) }, | 9512 | .kind = .{ .function = @enumFromInt(o.builder.functions.items.len) }, |
| 9410 | }; | 9513 | }; |
| ... | @@ -9412,10 +9515,6 @@ pub const FuncGen = struct { | ... | @@ -9412,10 +9515,6 @@ pub const FuncGen = struct { |
| 9412 | .global = @enumFromInt(o.builder.globals.count()), | 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 | try o.builder.llvm_globals.append(self.gpa, llvm_fn); | 9518 | try o.builder.llvm_globals.append(self.gpa, llvm_fn); |
| 9420 | _ = try o.builder.addGlobal(try o.builder.string(lt_errors_fn_name), global); | 9519 | _ = try o.builder.addGlobal(try o.builder.string(lt_errors_fn_name), global); |
| 9421 | try o.builder.functions.append(self.gpa, function); | 9520 | try o.builder.functions.append(self.gpa, function); |
| ... | @@ -9431,7 +9530,7 @@ pub const FuncGen = struct { | ... | @@ -9431,7 +9530,7 @@ pub const FuncGen = struct { |
| 9431 | | 9530 | |
| 9432 | const error_name_table_ptr = try self.getErrorNameTable(); | 9531 | const error_name_table_ptr = try self.getErrorNameTable(); |
| 9433 | const ptr_slice_llvm_ty = self.context.pointerType(0); | 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 | const indices = [_]*llvm.Value{operand}; | 9534 | const indices = [_]*llvm.Value{operand}; |
| 9436 | const error_name_ptr = self.builder.buildInBoundsGEP(slice_llvm_ty, error_name_table, &indices, indices.len, ""); | 9535 | const error_name_ptr = self.builder.buildInBoundsGEP(slice_llvm_ty, error_name_table, &indices, indices.len, ""); |
| 9437 | return self.builder.buildLoad(slice_llvm_ty, error_name_ptr, ""); | 9536 | return self.builder.buildLoad(slice_llvm_ty, error_name_ptr, ""); |
| ... | @@ -9588,18 +9687,18 @@ pub const FuncGen = struct { | ... | @@ -9588,18 +9687,18 @@ pub const FuncGen = struct { |
| 9588 | .Add => switch (scalar_ty.zigTypeTag(mod)) { | 9687 | .Add => switch (scalar_ty.zigTypeTag(mod)) { |
| 9589 | .Int => return self.builder.buildAddReduce(operand), | 9688 | .Int => return self.builder.buildAddReduce(operand), |
| 9590 | .Float => if (intrinsicsAllowed(scalar_ty, target)) { | 9689 | .Float => if (intrinsicsAllowed(scalar_ty, target)) { |
| 9591 | const scalar_llvm_ty = (try o.lowerType(scalar_ty)).toLlvm(&o.builder); | 9690 | const scalar_llvm_ty = try o.lowerType(scalar_ty); |
| 9592 | const neutral_value = scalar_llvm_ty.constReal(-0.0); | 9691 | const neutral_value = try o.builder.fpConst(scalar_llvm_ty, -0.0); |
| 9593 | return self.builder.buildFPAddReduce(neutral_value, operand); | 9692 | return self.builder.buildFPAddReduce(neutral_value.toLlvm(&o.builder), operand); |
| 9594 | }, | 9693 | }, |
| 9595 | else => unreachable, | 9694 | else => unreachable, |
| 9596 | }, | 9695 | }, |
| 9597 | .Mul => switch (scalar_ty.zigTypeTag(mod)) { | 9696 | .Mul => switch (scalar_ty.zigTypeTag(mod)) { |
| 9598 | .Int => return self.builder.buildMulReduce(operand), | 9697 | .Int => return self.builder.buildMulReduce(operand), |
| 9599 | .Float => if (intrinsicsAllowed(scalar_ty, target)) { | 9698 | .Float => if (intrinsicsAllowed(scalar_ty, target)) { |
| 9600 | const scalar_llvm_ty = (try o.lowerType(scalar_ty)).toLlvm(&o.builder); | 9699 | const scalar_llvm_ty = try o.lowerType(scalar_ty); |
| 9601 | const neutral_value = scalar_llvm_ty.constReal(1.0); | 9700 | const neutral_value = try o.builder.fpConst(scalar_llvm_ty, 1.0); |
| 9602 | return self.builder.buildFPMulReduce(neutral_value, operand); | 9701 | return self.builder.buildFPMulReduce(neutral_value.toLlvm(&o.builder), operand); |
| 9603 | }, | 9702 | }, |
| 9604 | else => unreachable, | 9703 | else => unreachable, |
| 9605 | }, | 9704 | }, |
| ... | @@ -9626,17 +9725,14 @@ pub const FuncGen = struct { | ... | @@ -9626,17 +9725,14 @@ pub const FuncGen = struct { |
| 9626 | | 9725 | |
| 9627 | const param_llvm_ty = try o.lowerType(scalar_ty); | 9726 | const param_llvm_ty = try o.lowerType(scalar_ty); |
| 9628 | const libc_fn = try self.getLibcFunction(fn_name, &(.{param_llvm_ty} ** 2), param_llvm_ty); | 9727 | const libc_fn = try self.getLibcFunction(fn_name, &(.{param_llvm_ty} ** 2), param_llvm_ty); |
| 9629 | const init_value = try o.lowerValue(.{ | 9728 | const init_value = try o.lowerValue((try mod.floatValue(scalar_ty, switch (reduce.operation) { |
| 9630 | .ty = scalar_ty, | 9729 | .Min => std.math.nan(f32), |
| 9631 | .val = try mod.floatValue(scalar_ty, switch (reduce.operation) { | 9730 | .Max => std.math.nan(f32), |
| 9632 | .Min => std.math.nan(f32), | 9731 | .Add => -0.0, |
| 9633 | .Max => std.math.nan(f32), | 9732 | .Mul => 1.0, |
| 9634 | .Add => -0.0, | 9733 | else => unreachable, |
| 9635 | .Mul => 1.0, | 9734 | })).toIntern()); |
| 9636 | else => unreachable, | 9735 | return self.buildReducedCall(libc_fn, operand, operand_ty.vectorLen(mod), init_value.toLlvm(&o.builder)); |
| 9637 | }), | | |
| 9638 | }); | | |
| 9639 | return self.buildReducedCall(libc_fn, operand, operand_ty.vectorLen(mod), init_value); | | |
| 9640 | } | 9736 | } |
| 9641 | | 9737 | |
| 9642 | fn airAggregateInit(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { | 9738 | fn airAggregateInit(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { |
| ... | @@ -10030,26 +10126,42 @@ pub const FuncGen = struct { | ... | @@ -10030,26 +10126,42 @@ pub const FuncGen = struct { |
| 10030 | return self.amdgcnWorkIntrinsic(dimension, 0, "llvm.amdgcn.workgroup.id"); | 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 | const o = self.dg.object; | 10130 | const o = self.dg.object; |
| 10035 | if (o.error_name_table) |table| { | 10131 | const table = o.error_name_table; |
| 10036 | return table; | 10132 | if (table != .none) return table; |
| 10037 | } | | |
| 10038 | | 10133 | |
| 10039 | const mod = o.module; | 10134 | const mod = o.module; |
| 10040 | const slice_ty = Type.slice_const_u8_sentinel_0; | 10135 | const slice_ty = Type.slice_const_u8_sentinel_0; |
| 10041 | const slice_alignment = slice_ty.abiAlignment(mod); | 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"); | 10139 | const name = try o.builder.string("__zig_err_name_table"); |
| 10045 | error_name_table_global.setInitializer(llvm_slice_ptr_ty.getUndef()); | 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 | error_name_table_global.setLinkage(.Private); | 10142 | error_name_table_global.setLinkage(.Private); |
| 10047 | error_name_table_global.setGlobalConstant(.True); | 10143 | error_name_table_global.setGlobalConstant(.True); |
| 10048 | error_name_table_global.setUnnamedAddr(.True); | 10144 | error_name_table_global.setUnnamedAddr(.True); |
| 10049 | error_name_table_global.setAlignment(slice_alignment); | 10145 | error_name_table_global.setAlignment(slice_alignment); |
| 10050 | | 10146 | |
| 10051 | o.error_name_table = error_name_table_global; | 10147 | var global = Builder.Global{ |
| 10052 | return error_name_table_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 | /// Assumes the optional is not pointer-like and payload has bits. | 10167 | /// Assumes the optional is not pointer-like and payload has bits. |
| ... | @@ -10273,14 +10385,14 @@ pub const FuncGen = struct { | ... | @@ -10273,14 +10385,14 @@ pub const FuncGen = struct { |
| 10273 | return llvm_inst; | 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); | 10388 | const containing_int_ty = try o.builder.intType(@intCast(info.packed_offset.host_size * 8)); |
| 10277 | const containing_int = self.builder.buildLoad(int_elem_ty, ptr, ""); | 10389 | const containing_int = self.builder.buildLoad(containing_int_ty.toLlvm(&o.builder), ptr, ""); |
| 10278 | containing_int.setAlignment(ptr_alignment); | 10390 | containing_int.setAlignment(ptr_alignment); |
| 10279 | containing_int.setVolatile(ptr_volatile); | 10391 | containing_int.setVolatile(ptr_volatile); |
| 10280 | | 10392 | |
| 10281 | const elem_bits = @as(c_uint, @intCast(ptr_ty.childType(mod).bitSize(mod))); | 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); | 10394 | const shift_amt = try o.builder.intConst(containing_int_ty, info.packed_offset.bit_offset); |
| 10283 | const shifted_value = self.builder.buildLShr(containing_int, shift_amt, ""); | 10395 | const shifted_value = self.builder.buildLShr(containing_int, shift_amt.toLlvm(&o.builder), ""); |
| 10284 | const elem_llvm_ty = (try o.lowerType(elem_ty)).toLlvm(&o.builder); | 10396 | const elem_llvm_ty = (try o.lowerType(elem_ty)).toLlvm(&o.builder); |
| 10285 | | 10397 | |
| 10286 | if (isByRef(elem_ty, mod)) { | 10398 | if (isByRef(elem_ty, mod)) { |
| ... | @@ -10346,30 +10458,29 @@ pub const FuncGen = struct { | ... | @@ -10346,30 +10458,29 @@ pub const FuncGen = struct { |
| 10346 | } | 10458 | } |
| 10347 | | 10459 | |
| 10348 | if (info.packed_offset.host_size != 0) { | 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); | 10461 | const containing_int_ty = try o.builder.intType(@intCast(info.packed_offset.host_size * 8)); |
| 10350 | const containing_int = self.builder.buildLoad(int_elem_ty, ptr, ""); | 10462 | const containing_int = self.builder.buildLoad(containing_int_ty.toLlvm(&o.builder), ptr, ""); |
| 10351 | assert(ordering == .NotAtomic); | 10463 | assert(ordering == .NotAtomic); |
| 10352 | containing_int.setAlignment(ptr_alignment); | 10464 | containing_int.setAlignment(ptr_alignment); |
| 10353 | containing_int.setVolatile(ptr_volatile); | 10465 | containing_int.setVolatile(ptr_volatile); |
| 10354 | const elem_bits = @as(c_uint, @intCast(ptr_ty.childType(mod).bitSize(mod))); | 10466 | const elem_bits = @as(c_uint, @intCast(ptr_ty.childType(mod).bitSize(mod))); |
| 10355 | const containing_int_ty = containing_int.typeOf(); | 10467 | const shift_amt = try o.builder.intConst(containing_int_ty, info.packed_offset.bit_offset); |
| 10356 | const shift_amt = containing_int_ty.constInt(info.packed_offset.bit_offset, .False); | | |
| 10357 | // Convert to equally-sized integer type in order to perform the bit | 10468 | // Convert to equally-sized integer type in order to perform the bit |
| 10358 | // operations on the value to store | 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 | const value_bits = if (elem_ty.isPtrAtRuntime(mod)) | 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 | else | 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(); | 10476 | var mask_val = (try o.builder.intConst(value_bits_type, -1)).toLlvm(&o.builder); |
| 10366 | mask_val = mask_val.constZExt(containing_int_ty); | 10477 | mask_val = mask_val.constZExt(containing_int_ty.toLlvm(&o.builder)); |
| 10367 | mask_val = mask_val.constShl(shift_amt); | 10478 | mask_val = mask_val.constShl(shift_amt.toLlvm(&o.builder)); |
| 10368 | mask_val = mask_val.constNot(); | 10479 | mask_val = mask_val.constNot(); |
| 10369 | | 10480 | |
| 10370 | const anded_containing_int = self.builder.buildAnd(containing_int, mask_val, ""); | 10481 | const anded_containing_int = self.builder.buildAnd(containing_int, mask_val, ""); |
| 10371 | const extended_value = self.builder.buildZExt(value_bits, containing_int_ty, ""); | 10482 | const extended_value = self.builder.buildZExt(value_bits, containing_int_ty.toLlvm(&o.builder), ""); |
| 10372 | const shifted_value = self.builder.buildShl(extended_value, shift_amt, ""); | 10483 | const shifted_value = self.builder.buildShl(extended_value, shift_amt.toLlvm(&o.builder), ""); |
| 10373 | const ored_value = self.builder.buildOr(shifted_value, anded_containing_int, ""); | 10484 | const ored_value = self.builder.buildOr(shifted_value, anded_containing_int, ""); |
| 10374 | | 10485 | |
| 10375 | const store_inst = self.builder.buildStore(ored_value, ptr); | 10486 | const store_inst = self.builder.buildStore(ored_value, ptr); |