authorgravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2023-07-10 10:52:17-04:00
committergravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2023-07-19 23:38:40-04:00
logff8a49448c70ffe73826c7987522ed63fddd654f
tree36107c8b3539051f4539836d09145e231f260293
parent2cb52235b91f7e4bf5a4ebf77a5008adfc30c8b9

llvm: finish converting `lowerValue`


5 files changed, 2751 insertions(+), 902 deletions(-)

src/Module.zig+4-8
...@@ -835,10 +835,6 @@ pub const Decl = struct {...@@ -835,10 +835,6 @@ pub const Decl = struct {
835 assert(decl.has_tv);835 assert(decl.has_tv);
836 return @as(u32, @intCast(decl.alignment.toByteUnitsOptional() orelse decl.ty.abiAlignment(mod)));836 return @as(u32, @intCast(decl.alignment.toByteUnitsOptional() orelse decl.ty.abiAlignment(mod)));
837 }837 }
838
839 pub fn intern(decl: *Decl, mod: *Module) Allocator.Error!void {
840 decl.val = (try decl.val.intern(decl.ty, mod)).toValue();
841 }
842};838};
843839
844/// This state is attached to every Decl when Module emit_h is non-null.840/// This state is attached to every Decl when Module emit_h is non-null.
...@@ -4204,7 +4200,7 @@ pub fn semaFile(mod: *Module, file: *File) SemaError!void {...@@ -4204,7 +4200,7 @@ pub fn semaFile(mod: *Module, file: *File) SemaError!void {
4204 try wip_captures.finalize();4200 try wip_captures.finalize();
4205 for (comptime_mutable_decls.items) |decl_index| {4201 for (comptime_mutable_decls.items) |decl_index| {
4206 const decl = mod.declPtr(decl_index);4202 const decl = mod.declPtr(decl_index);
4207 try decl.intern(mod);4203 _ = try decl.internValue(mod);
4208 }4204 }
4209 new_decl.analysis = .complete;4205 new_decl.analysis = .complete;
4210 } else |err| switch (err) {4206 } else |err| switch (err) {
...@@ -4315,7 +4311,7 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool {...@@ -4315,7 +4311,7 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool {
4315 try wip_captures.finalize();4311 try wip_captures.finalize();
4316 for (comptime_mutable_decls.items) |ct_decl_index| {4312 for (comptime_mutable_decls.items) |ct_decl_index| {
4317 const ct_decl = mod.declPtr(ct_decl_index);4313 const ct_decl = mod.declPtr(ct_decl_index);
4318 try ct_decl.intern(mod);4314 _ = try ct_decl.internValue(mod);
4319 }4315 }
4320 const align_src: LazySrcLoc = .{ .node_offset_var_decl_align = 0 };4316 const align_src: LazySrcLoc = .{ .node_offset_var_decl_align = 0 };
4321 const section_src: LazySrcLoc = .{ .node_offset_var_decl_section = 0 };4317 const section_src: LazySrcLoc = .{ .node_offset_var_decl_section = 0 };
...@@ -5362,7 +5358,7 @@ pub fn analyzeFnBody(mod: *Module, func_index: InternPool.Index, arena: Allocato...@@ -5362,7 +5358,7 @@ pub fn analyzeFnBody(mod: *Module, func_index: InternPool.Index, arena: Allocato
5362 try wip_captures.finalize();5358 try wip_captures.finalize();
5363 for (comptime_mutable_decls.items) |ct_decl_index| {5359 for (comptime_mutable_decls.items) |ct_decl_index| {
5364 const ct_decl = mod.declPtr(ct_decl_index);5360 const ct_decl = mod.declPtr(ct_decl_index);
5365 try ct_decl.intern(mod);5361 _ = try ct_decl.internValue(mod);
5366 }5362 }
53675363
5368 // Copy the block into place and mark that as the main block.5364 // Copy the block into place and mark that as the main block.
...@@ -6369,7 +6365,7 @@ pub fn markDeclAlive(mod: *Module, decl: *Decl) Allocator.Error!void {...@@ -6369,7 +6365,7 @@ pub fn markDeclAlive(mod: *Module, decl: *Decl) Allocator.Error!void {
6369 if (decl.alive) return;6365 if (decl.alive) return;
6370 decl.alive = true;6366 decl.alive = true;
63716367
6372 try decl.intern(mod);6368 _ = try decl.internValue(mod);
63736369
6374 // This is the first time we are marking this Decl alive. We must6370 // This is the first time we are marking this Decl alive. We must
6375 // therefore recurse into its value and mark any Decl it references6371 // therefore recurse into its value and mark any Decl it references
src/Sema.zig+4-4
...@@ -3899,7 +3899,7 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com...@@ -3899,7 +3899,7 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com
3899 try mod.declareDeclDependency(sema.owner_decl_index, decl_index);3899 try mod.declareDeclDependency(sema.owner_decl_index, decl_index);
39003900
3901 const decl = mod.declPtr(decl_index);3901 const decl = mod.declPtr(decl_index);
3902 if (iac.is_const) try decl.intern(mod);3902 if (iac.is_const) _ = try decl.internValue(mod);
3903 const final_elem_ty = decl.ty;3903 const final_elem_ty = decl.ty;
3904 const final_ptr_ty = try mod.ptrType(.{3904 const final_ptr_ty = try mod.ptrType(.{
3905 .child = final_elem_ty.toIntern(),3905 .child = final_elem_ty.toIntern(),
...@@ -33577,7 +33577,7 @@ fn semaBackingIntType(mod: *Module, struct_obj: *Module.Struct) CompileError!voi...@@ -33577,7 +33577,7 @@ fn semaBackingIntType(mod: *Module, struct_obj: *Module.Struct) CompileError!voi
33577 try wip_captures.finalize();33577 try wip_captures.finalize();
33578 for (comptime_mutable_decls.items) |ct_decl_index| {33578 for (comptime_mutable_decls.items) |ct_decl_index| {
33579 const ct_decl = mod.declPtr(ct_decl_index);33579 const ct_decl = mod.declPtr(ct_decl_index);
33580 try ct_decl.intern(mod);33580 _ = try ct_decl.internValue(mod);
33581 }33581 }
33582 } else {33582 } else {
33583 if (fields_bit_sum > std.math.maxInt(u16)) {33583 if (fields_bit_sum > std.math.maxInt(u16)) {
...@@ -34645,7 +34645,7 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void...@@ -34645,7 +34645,7 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void
34645 try wip_captures.finalize();34645 try wip_captures.finalize();
34646 for (comptime_mutable_decls.items) |ct_decl_index| {34646 for (comptime_mutable_decls.items) |ct_decl_index| {
34647 const ct_decl = mod.declPtr(ct_decl_index);34647 const ct_decl = mod.declPtr(ct_decl_index);
34648 try ct_decl.intern(mod);34648 _ = try ct_decl.internValue(mod);
34649 }34649 }
3465034650
34651 struct_obj.have_field_inits = true;34651 struct_obj.have_field_inits = true;
...@@ -34744,7 +34744,7 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void {...@@ -34744,7 +34744,7 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void {
34744 try wip_captures.finalize();34744 try wip_captures.finalize();
34745 for (comptime_mutable_decls.items) |ct_decl_index| {34745 for (comptime_mutable_decls.items) |ct_decl_index| {
34746 const ct_decl = mod.declPtr(ct_decl_index);34746 const ct_decl = mod.declPtr(ct_decl_index);
34747 try ct_decl.intern(mod);34747 _ = try ct_decl.internValue(mod);
34748 }34748 }
3474934749
34750 try union_obj.fields.ensureTotalCapacity(mod.tmp_hack_arena.allocator(), fields_len);34750 try union_obj.fields.ensureTotalCapacity(mod.tmp_hack_arena.allocator(), fields_len);
src/codegen/llvm.zig+814-703
...@@ -579,7 +579,7 @@ pub const Object = struct {...@@ -579,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 in580 /// 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 a583 /// 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 a584 /// 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 }
805805
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;
809810
810 const mod = o.module;811 const mod = o.module;
811812
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 space817 // 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);
817823
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);
832835
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);
839851
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 }
841857
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 hardcode864 error_name_table_global.setAlignment(slice_alignment); // TODO: Dont hardcode
848865
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 }
852886
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 };
11181152
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);
11221156
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 }
11571191
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 }
11601196
1161 // Remove all the basic blocks of a function in order to start over, generating1197 // 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 {
11661202
1167 const builder = o.context.createBuilder();1203 const builder = o.context.createBuilder();
11681204
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);
11721208
...@@ -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 call1524 // 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 }
15131549
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();
15821649
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 }
16191696
...@@ -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 } }));
26652743 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);
26812771
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 else2774 else
2685 global;2775 llvm_global;
26862776
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 has2782 /// 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 {
27222812
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 }
27682860
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 }
27722865
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 }
28662959
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));
28712964
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 };
28882981
...@@ -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 {
29263019
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 }
29413025
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;
30953182
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);
31173207
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);
33753466
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 }
34353530
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 }
34483544
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 values3574 => 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 }
35273619
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 }
35463627
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);
36143693
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);
36253709
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);
36793784
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);
36873792 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 }
36923795
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);
37333826
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);
37353840
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;
37403846 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;
37443849
...@@ -3749,20 +3854,20 @@ pub const Object = struct {...@@ -3749,20 +3854,20 @@ pub const Object = struct {
37493854
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 debug3857 // 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 }
37573864
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])
37623869 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);
37663871
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);
37783886
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());
37963895 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;
38073902
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 else3911 );
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, this3914 try o.builder.convConst(.unsigned, small_int_val, struct_ty);
3820 // zext would go from, e.g. i16 to i16. This is legal with3915 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);
38293922
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);
38333936
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;
38383942 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 {
38463949
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 debug3952 // 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 }
38543960
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);
38593965 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;
38613967 llvm_index += 1;
3862 llvm_fields.appendAssumeCapacity(field_llvm_val);
38633968
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);
38753983
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);
39023995
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());
39123999
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 }
39264010
3927 // Sometimes we must make an unnamed struct because LLVM does4011 // 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 global4013 // 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);
39494036
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 }
39824066
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 }
39964080
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 }
40014089
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 };
40064094
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 }
40184102
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);
40274111
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 pointer4115 // 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 }
40354119
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);
40464130
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 pointer4136 // 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 }
40564140
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);
40774157
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 }
40844164
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 any4167 // 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 04172 return o.builder.gepConst(.inbounds, try o.lowerType(parent_ty), parent_ptr, &.{
4093 else4173 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 one4185 // 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 }
41214198
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 }
41504225
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;
41574228
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 }
41734244
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)) or4246 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 }
41804249
4181 try mod.markDeclAlive(decl);4250 try mod.markDeclAlive(decl);
41824251
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 else4254 else
4186 (try o.resolveGlobalDecl(decl_index)).toLlvm(&o.builder);4255 (try o.resolveGlobalDecl(decl_index)).ptrConst(&o.builder).global;
41874256
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),
41954264 ) 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 }
42034271
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` annotation4276 // The value cannot be undefined, because we use the `nonnull` annotation
4209 // for non-optional pointers. We also need to respect the alignment, even though4277 // 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 builds4284 // verbatim, and the result should test as non-null.
4217 // because we need a well-defined value that is not null, and LLVM does not4285 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 }
42304295
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 must4528 // 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/132654540 // 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);
46064675
4607 // We have an LLVM value but we need to create a global constant and4676 // 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 else4710 else
4621 global;4711 llvm_global;
4622 return addrspace_casted_ptr;4712 return addrspace_casted_ptr;
4623 }4713 }
46244714
...@@ -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 {
56725759
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 load5765 // 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 branch6172 // 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);
61096203
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();
68726971
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 }
68986997
...@@ -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);
70587157
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);
71517250
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);
84528555
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/119468676 // 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 }
85758679
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 }
85828687
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 };
85918696
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);
90629169
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)});
90659171
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 {
91709276
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 {
92589362
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);
93729472
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);
93799477
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));
94069504
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 };
94149517
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 {
94319530
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 {
96269725
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 }
96419737
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 }
1003210128
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 }
1003810133
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 space10137 const undef_init = try o.builder.undefConst(.ptr); // TODO: Address space
1004310138
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);
1005010146
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 }
1005410166
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 }
1027510387
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);
1028010392
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);
1028510397
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 }
1034710459
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 bit10468 // Convert to equally-sized integer type in order to perform the bit
10358 // operations on the value to store10469 // 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 else10473 else
10363 self.builder.buildBitCast(elem, value_bits_type, "");10474 self.builder.buildBitCast(elem, value_bits_type.toLlvm(&o.builder), "");
1036410475
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();
1036910480
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, "");
1037410485
10375 const store_inst = self.builder.buildStore(ored_value, ptr);10486 const store_inst = self.builder.buildStore(ored_value, ptr);
src/codegen/llvm/Builder.zig+1865-176
...@@ -27,7 +27,7 @@ globals: std.AutoArrayHashMapUnmanaged(String, Global) = .{},...@@ -27,7 +27,7 @@ globals: std.AutoArrayHashMapUnmanaged(String, Global) = .{},
27next_unnamed_global: String = @enumFromInt(0),27next_unnamed_global: String = @enumFromInt(0),
28next_unique_global_id: std.AutoHashMapUnmanaged(String, u32) = .{},28next_unique_global_id: std.AutoHashMapUnmanaged(String, u32) = .{},
29aliases: std.ArrayListUnmanaged(Alias) = .{},29aliases: std.ArrayListUnmanaged(Alias) = .{},
30objects: std.ArrayListUnmanaged(Object) = .{},30variables: std.ArrayListUnmanaged(Variable) = .{},
31functions: std.ArrayListUnmanaged(Function) = .{},31functions: std.ArrayListUnmanaged(Function) = .{},
3232
33constant_map: std.AutoArrayHashMapUnmanaged(void, void) = .{},33constant_map: std.AutoArrayHashMapUnmanaged(void, void) = .{},
...@@ -35,10 +35,12 @@ constant_items: std.MultiArrayList(Constant.Item) = .{},...@@ -35,10 +35,12 @@ constant_items: std.MultiArrayList(Constant.Item) = .{},
35constant_extra: std.ArrayListUnmanaged(u32) = .{},35constant_extra: std.ArrayListUnmanaged(u32) = .{},
36constant_limbs: std.ArrayListUnmanaged(std.math.big.Limb) = .{},36constant_limbs: std.ArrayListUnmanaged(std.math.big.Limb) = .{},
3737
38pub const expected_fields_len = 32;
39pub const expected_gep_indices_len = 8;
40
38pub const String = enum(u32) {41pub const String = enum(u32) {
39 none = std.math.maxInt(u31),42 none = std.math.maxInt(u31),
40 empty,43 empty,
41 debugme,
42 _,44 _,
4345
44 pub fn toSlice(self: String, b: *const Builder) ?[:0]const u8 {46 pub fn toSlice(self: String, b: *const Builder) ?[:0]const u8 {
...@@ -58,22 +60,23 @@ pub const String = enum(u32) {...@@ -58,22 +60,23 @@ pub const String = enum(u32) {
58 _: std.fmt.FormatOptions,60 _: std.fmt.FormatOptions,
59 writer: anytype,61 writer: anytype,
60 ) @TypeOf(writer).Error!void {62 ) @TypeOf(writer).Error!void {
63 if (comptime std.mem.indexOfNone(u8, fmt_str, "@\"")) |_|
64 @compileError("invalid format string: '" ++ fmt_str ++ "'");
61 assert(data.string != .none);65 assert(data.string != .none);
62 const slice = data.string.toSlice(data.builder) orelse66 const slice = data.string.toSlice(data.builder) orelse
63 return writer.print("{d}", .{@intFromEnum(data.string)});67 return writer.print("{d}", .{@intFromEnum(data.string)});
64 const need_quotes = if (comptime std.mem.eql(u8, fmt_str, ""))68 const full_slice = slice[0 .. slice.len + comptime @intFromBool(
65 !isValidIdentifier(slice)69 std.mem.indexOfScalar(u8, fmt_str, '@') != null,
66 else if (comptime std.mem.eql(u8, fmt_str, "\""))70 )];
67 true71 const need_quotes = (comptime std.mem.indexOfScalar(u8, fmt_str, '"') != null) or
68 else72 !isValidIdentifier(full_slice);
69 @compileError("invalid format string: '" ++ fmt_str ++ "'");73 if (need_quotes) try writer.writeByte('"');
70 if (need_quotes) try writer.writeByte('\"');74 for (full_slice) |character| switch (character) {
71 for (slice) |character| switch (character) {
72 '\\' => try writer.writeAll("\\\\"),75 '\\' => try writer.writeAll("\\\\"),
73 ' '...'"' - 1, '"' + 1...'\\' - 1, '\\' + 1...'~' => try writer.writeByte(character),76 ' '...'"' - 1, '"' + 1...'\\' - 1, '\\' + 1...'~' => try writer.writeByte(character),
74 else => try writer.print("\\{X:0>2}", .{character}),77 else => try writer.print("\\{X:0>2}", .{character}),
75 };78 };
76 if (need_quotes) try writer.writeByte('\"');79 if (need_quotes) try writer.writeByte('"');
77 }80 }
78 pub fn fmt(self: String, builder: *const Builder) std.fmt.Formatter(format) {81 pub fn fmt(self: String, builder: *const Builder) std.fmt.Formatter(format) {
79 return .{ .data = .{ .string = self, .builder = builder } };82 return .{ .data = .{ .string = self, .builder = builder } };
...@@ -92,8 +95,8 @@ pub const String = enum(u32) {...@@ -92,8 +95,8 @@ pub const String = enum(u32) {
92 pub fn hash(_: Adapter, key: []const u8) u32 {95 pub fn hash(_: Adapter, key: []const u8) u32 {
93 return @truncate(std.hash.Wyhash.hash(0, key));96 return @truncate(std.hash.Wyhash.hash(0, key));
94 }97 }
95 pub fn eql(ctx: Adapter, lhs: []const u8, _: void, rhs_index: usize) bool {98 pub fn eql(ctx: Adapter, lhs_key: []const u8, _: void, rhs_index: usize) bool {
96 return std.mem.eql(u8, lhs, String.fromIndex(rhs_index).toSlice(ctx.builder).?);99 return std.mem.eql(u8, lhs_key, String.fromIndex(rhs_index).toSlice(ctx.builder).?);
97 }100 }
98 };101 };
99};102};
...@@ -204,9 +207,167 @@ pub const Type = enum(u32) {...@@ -204,9 +207,167 @@ pub const Type = enum(u32) {
204 pub const Item = packed struct(u32) {207 pub const Item = packed struct(u32) {
205 tag: Tag,208 tag: Tag,
206 data: ExtraIndex,209 data: ExtraIndex,
210
211 pub const ExtraIndex = u28;
207 };212 };
208213
209 pub const ExtraIndex = u28;214 pub fn tag(self: Type, builder: *const Builder) Tag {
215 return builder.type_items.items[@intFromEnum(self)].tag;
216 }
217
218 pub fn unnamedTag(self: Type, builder: *const Builder) Tag {
219 const item = builder.type_items.items[@intFromEnum(self)];
220 return switch (item.tag) {
221 .named_structure => builder.typeExtraData(Type.NamedStructure, item.data).body
222 .unnamedTag(builder),
223 else => item.tag,
224 };
225 }
226
227 pub fn scalarTag(self: Type, builder: *const Builder) Tag {
228 const item = builder.type_items.items[@intFromEnum(self)];
229 return switch (item.tag) {
230 .vector, .scalable_vector => builder.typeExtraData(Type.Vector, item.data)
231 .child.tag(builder),
232 else => item.tag,
233 };
234 }
235
236 pub fn isFn(self: Type, builder: *const Builder) bool {
237 return switch (self.tag(builder)) {
238 .function, .vararg_function => true,
239 else => false,
240 };
241 }
242
243 pub fn fnKind(self: Type, builder: *const Builder) Type.Function.Kind {
244 return switch (self.tag(builder)) {
245 .function => .normal,
246 .vararg_function => .vararg,
247 else => unreachable,
248 };
249 }
250
251 pub fn isVector(self: Type, builder: *const Builder) bool {
252 return switch (self.tag(builder)) {
253 .vector, .scalable_vector => true,
254 else => false,
255 };
256 }
257
258 pub fn vectorKind(self: Type, builder: *const Builder) Type.Vector.Kind {
259 return switch (self.tag(builder)) {
260 .vector => .normal,
261 .scalable_vector => .scalable,
262 else => unreachable,
263 };
264 }
265
266 pub fn isStruct(self: Type, builder: *const Builder) bool {
267 return switch (self.tag(builder)) {
268 .structure, .packed_structure, .named_structure => true,
269 else => false,
270 };
271 }
272
273 pub fn structKind(self: Type, builder: *const Builder) Type.Structure.Kind {
274 return switch (self.unnamedTag(builder)) {
275 .structure => .normal,
276 .packed_structure => .@"packed",
277 else => unreachable,
278 };
279 }
280
281 pub fn scalarBits(self: Type, builder: *const Builder) u24 {
282 return switch (self) {
283 .void, .label, .token, .metadata, .none, .x86_amx => unreachable,
284 .i1 => 1,
285 .i8 => 8,
286 .half, .bfloat, .i16 => 16,
287 .i29 => 29,
288 .float, .i32 => 32,
289 .double, .i64, .x86_mmx => 64,
290 .x86_fp80, .i80 => 80,
291 .fp128, .ppc_fp128, .i128 => 128,
292 .ptr => @panic("TODO: query data layout"),
293 _ => {
294 const item = builder.type_items.items[@intFromEnum(self)];
295 return switch (item.tag) {
296 .simple,
297 .function,
298 .vararg_function,
299 => unreachable,
300 .integer => @intCast(item.data),
301 .pointer => @panic("TODO: query data layout"),
302 .target => unreachable,
303 .vector,
304 .scalable_vector,
305 => builder.typeExtraData(Type.Vector, item.data).child.scalarBits(builder),
306 .small_array,
307 .array,
308 .structure,
309 .packed_structure,
310 .named_structure,
311 => unreachable,
312 };
313 },
314 };
315 }
316
317 pub fn childType(self: Type, builder: *const Builder) Type {
318 const item = builder.type_items.items[@intFromEnum(self)];
319 return switch (item.tag) {
320 .vector,
321 .scalable_vector,
322 .small_array,
323 => builder.typeExtraData(Type.Vector, item.data).child,
324 .array => builder.typeExtraData(Type.Array, item.data).child,
325 .named_structure => builder.typeExtraData(Type.NamedStructure, item.data).body,
326 else => unreachable,
327 };
328 }
329
330 pub fn vectorLen(self: Type, builder: *const Builder) u32 {
331 const item = builder.type_items.items[@intFromEnum(self)];
332 return switch (item.tag) {
333 .vector,
334 .scalable_vector,
335 => builder.typeExtraData(Type.Vector, item.data).len,
336 else => unreachable,
337 };
338 }
339
340 pub fn aggregateLen(self: Type, builder: *const Builder) u64 {
341 const item = builder.type_items.items[@intFromEnum(self)];
342 return switch (item.tag) {
343 .vector,
344 .scalable_vector,
345 .small_array,
346 => builder.typeExtraData(Type.Vector, item.data).len,
347 .array => builder.typeExtraData(Type.Array, item.data).len(),
348 .structure,
349 .packed_structure,
350 => builder.typeExtraData(Type.Structure, item.data).fields_len,
351 .named_structure => builder.typeExtraData(Type.NamedStructure, item.data).body
352 .aggregateLen(builder),
353 else => unreachable,
354 };
355 }
356
357 pub fn structFields(self: Type, builder: *const Builder) []const Type {
358 const item = builder.type_items.items[@intFromEnum(self)];
359 switch (item.tag) {
360 .structure,
361 .packed_structure,
362 => {
363 const extra = builder.typeExtraDataTrail(Type.Structure, item.data);
364 return @ptrCast(builder.type_extra.items[extra.end..][0..extra.data.fields_len]);
365 },
366 .named_structure => return builder.typeExtraData(Type.NamedStructure, item.data).body
367 .structFields(builder),
368 else => unreachable,
369 }
370 }
210371
211 pub const FormatData = struct {372 pub const FormatData = struct {
212 type: Type,373 type: Type,
...@@ -220,11 +381,11 @@ pub const Type = enum(u32) {...@@ -220,11 +381,11 @@ pub const Type = enum(u32) {
220 ) @TypeOf(writer).Error!void {381 ) @TypeOf(writer).Error!void {
221 assert(data.type != .none);382 assert(data.type != .none);
222 if (std.enums.tagName(Type, data.type)) |name| return writer.writeAll(name);383 if (std.enums.tagName(Type, data.type)) |name| return writer.writeAll(name);
223 const type_item = data.builder.type_items.items[@intFromEnum(data.type)];384 const item = data.builder.type_items.items[@intFromEnum(data.type)];
224 switch (type_item.tag) {385 switch (item.tag) {
225 .simple => unreachable,386 .simple => unreachable,
226 .function, .vararg_function => {387 .function, .vararg_function => {
227 const extra = data.builder.typeExtraDataTrail(Type.Function, type_item.data);388 const extra = data.builder.typeExtraDataTrail(Type.Function, item.data);
228 const params: []const Type =389 const params: []const Type =
229 @ptrCast(data.builder.type_extra.items[extra.end..][0..extra.data.params_len]);390 @ptrCast(data.builder.type_extra.items[extra.end..][0..extra.data.params_len]);
230 if (!comptime std.mem.eql(u8, fmt_str, ">"))391 if (!comptime std.mem.eql(u8, fmt_str, ">"))
...@@ -235,7 +396,7 @@ pub const Type = enum(u32) {...@@ -235,7 +396,7 @@ pub const Type = enum(u32) {
235 if (index > 0) try writer.writeAll(", ");396 if (index > 0) try writer.writeAll(", ");
236 try writer.print("{%}", .{param.fmt(data.builder)});397 try writer.print("{%}", .{param.fmt(data.builder)});
237 }398 }
238 switch (type_item.tag) {399 switch (item.tag) {
239 .function => {},400 .function => {},
240 .vararg_function => {401 .vararg_function => {
241 if (params.len > 0) try writer.writeAll(", ");402 if (params.len > 0) try writer.writeAll(", ");
...@@ -246,10 +407,10 @@ pub const Type = enum(u32) {...@@ -246,10 +407,10 @@ pub const Type = enum(u32) {
246 try writer.writeByte(')');407 try writer.writeByte(')');
247 }408 }
248 },409 },
249 .integer => try writer.print("i{d}", .{type_item.data}),410 .integer => try writer.print("i{d}", .{item.data}),
250 .pointer => try writer.print("ptr{}", .{@as(AddrSpace, @enumFromInt(type_item.data))}),411 .pointer => try writer.print("ptr{}", .{@as(AddrSpace, @enumFromInt(item.data))}),
251 .target => {412 .target => {
252 const extra = data.builder.typeExtraDataTrail(Type.Target, type_item.data);413 const extra = data.builder.typeExtraDataTrail(Type.Target, item.data);
253 const types: []const Type =414 const types: []const Type =
254 @ptrCast(data.builder.type_extra.items[extra.end..][0..extra.data.types_len]);415 @ptrCast(data.builder.type_extra.items[extra.end..][0..extra.data.types_len]);
255 const ints: []const u32 = @ptrCast(data.builder.type_extra.items[extra.end +416 const ints: []const u32 = @ptrCast(data.builder.type_extra.items[extra.end +
...@@ -262,26 +423,28 @@ pub const Type = enum(u32) {...@@ -262,26 +423,28 @@ pub const Type = enum(u32) {
262 try writer.writeByte(')');423 try writer.writeByte(')');
263 },424 },
264 .vector => {425 .vector => {
265 const extra = data.builder.typeExtraData(Type.Vector, type_item.data);426 const extra = data.builder.typeExtraData(Type.Vector, item.data);
266 try writer.print("<{d} x {%}>", .{ extra.len, extra.child.fmt(data.builder) });427 try writer.print("<{d} x {%}>", .{ extra.len, extra.child.fmt(data.builder) });
267 },428 },
268 .scalable_vector => {429 .scalable_vector => {
269 const extra = data.builder.typeExtraData(Type.Vector, type_item.data);430 const extra = data.builder.typeExtraData(Type.Vector, item.data);
270 try writer.print("<vscale x {d} x {%}>", .{ extra.len, extra.child.fmt(data.builder) });431 try writer.print("<vscale x {d} x {%}>", .{ extra.len, extra.child.fmt(data.builder) });
271 },432 },
272 .small_array => {433 .small_array => {
273 const extra = data.builder.typeExtraData(Type.Vector, type_item.data);434 const extra = data.builder.typeExtraData(Type.Vector, item.data);
274 try writer.print("[{d} x {%}]", .{ extra.len, extra.child.fmt(data.builder) });435 try writer.print("[{d} x {%}]", .{ extra.len, extra.child.fmt(data.builder) });
275 },436 },
276 .array => {437 .array => {
277 const extra = data.builder.typeExtraData(Type.Array, type_item.data);438 const extra = data.builder.typeExtraData(Type.Array, item.data);
278 try writer.print("[{d} x {%}]", .{ extra.len(), extra.child.fmt(data.builder) });439 try writer.print("[{d} x {%}]", .{ extra.len(), extra.child.fmt(data.builder) });
279 },440 },
280 .structure, .packed_structure => {441 .structure,
281 const extra = data.builder.typeExtraDataTrail(Type.Structure, type_item.data);442 .packed_structure,
443 => {
444 const extra = data.builder.typeExtraDataTrail(Type.Structure, item.data);
282 const fields: []const Type =445 const fields: []const Type =
283 @ptrCast(data.builder.type_extra.items[extra.end..][0..extra.data.fields_len]);446 @ptrCast(data.builder.type_extra.items[extra.end..][0..extra.data.fields_len]);
284 switch (type_item.tag) {447 switch (item.tag) {
285 .structure => {},448 .structure => {},
286 .packed_structure => try writer.writeByte('<'),449 .packed_structure => try writer.writeByte('<'),
287 else => unreachable,450 else => unreachable,
...@@ -292,14 +455,14 @@ pub const Type = enum(u32) {...@@ -292,14 +455,14 @@ pub const Type = enum(u32) {
292 try writer.print("{%}", .{field.fmt(data.builder)});455 try writer.print("{%}", .{field.fmt(data.builder)});
293 }456 }
294 try writer.writeAll(" }");457 try writer.writeAll(" }");
295 switch (type_item.tag) {458 switch (item.tag) {
296 .structure => {},459 .structure => {},
297 .packed_structure => try writer.writeByte('>'),460 .packed_structure => try writer.writeByte('>'),
298 else => unreachable,461 else => unreachable,
299 }462 }
300 },463 },
301 .named_structure => {464 .named_structure => {
302 const extra = data.builder.typeExtraData(Type.NamedStructure, type_item.data);465 const extra = data.builder.typeExtraData(Type.NamedStructure, item.data);
303 if (comptime std.mem.eql(u8, fmt_str, "%")) try writer.print("%{}", .{466 if (comptime std.mem.eql(u8, fmt_str, "%")) try writer.print("%{}", .{
304 extra.id.fmt(data.builder),467 extra.id.fmt(data.builder),
305 }) else switch (extra.body) {468 }) else switch (extra.body) {
...@@ -323,7 +486,7 @@ pub const Type = enum(u32) {...@@ -323,7 +486,7 @@ pub const Type = enum(u32) {
323};486};
324487
325pub const Linkage = enum {488pub const Linkage = enum {
326 default,489 external,
327 private,490 private,
328 internal,491 internal,
329 available_externally,492 available_externally,
...@@ -334,7 +497,6 @@ pub const Linkage = enum {...@@ -334,7 +497,6 @@ pub const Linkage = enum {
334 extern_weak,497 extern_weak,
335 linkonce_odr,498 linkonce_odr,
336 weak_odr,499 weak_odr,
337 external,
338500
339 pub fn format(501 pub fn format(
340 self: Linkage,502 self: Linkage,
...@@ -342,14 +504,14 @@ pub const Linkage = enum {...@@ -342,14 +504,14 @@ pub const Linkage = enum {
342 _: std.fmt.FormatOptions,504 _: std.fmt.FormatOptions,
343 writer: anytype,505 writer: anytype,
344 ) @TypeOf(writer).Error!void {506 ) @TypeOf(writer).Error!void {
345 if (self != .default) try writer.print(" {s}", .{@tagName(self)});507 if (self != .external) try writer.print(" {s}", .{@tagName(self)});
346 }508 }
347};509};
348510
349pub const Preemption = enum {511pub const Preemption = enum {
350 default,
351 dso_preemptable,512 dso_preemptable,
352 dso_local,513 dso_local,
514 implicit_dso_local,
353515
354 pub fn format(516 pub fn format(
355 self: Preemption,517 self: Preemption,
...@@ -357,7 +519,7 @@ pub const Preemption = enum {...@@ -357,7 +519,7 @@ pub const Preemption = enum {
357 _: std.fmt.FormatOptions,519 _: std.fmt.FormatOptions,
358 writer: anytype,520 writer: anytype,
359 ) @TypeOf(writer).Error!void {521 ) @TypeOf(writer).Error!void {
360 if (self != .default) try writer.print(" {s}", .{@tagName(self)});522 if (self == .dso_local) try writer.print(" {s}", .{@tagName(self)});
361 }523 }
362};524};
363525
...@@ -554,22 +716,25 @@ pub const Alignment = enum(u6) {...@@ -554,22 +716,25 @@ pub const Alignment = enum(u6) {
554};716};
555717
556pub const Global = struct {718pub const Global = struct {
557 linkage: Linkage = .default,719 linkage: Linkage = .external,
558 preemption: Preemption = .default,720 preemption: Preemption = .dso_preemptable,
559 visibility: Visibility = .default,721 visibility: Visibility = .default,
560 dll_storage_class: DllStorageClass = .default,722 dll_storage_class: DllStorageClass = .default,
561 unnamed_addr: UnnamedAddr = .default,723 unnamed_addr: UnnamedAddr = .default,
562 addr_space: AddrSpace = .default,724 addr_space: AddrSpace = .default,
563 externally_initialized: ExternallyInitialized = .default,725 externally_initialized: ExternallyInitialized = .default,
564 type: Type,726 type: Type,
727 section: String = .none,
728 partition: String = .none,
565 alignment: Alignment = .default,729 alignment: Alignment = .default,
566 kind: union(enum) {730 kind: union(enum) {
567 alias: Alias.Index,731 alias: Alias.Index,
568 object: Object.Index,732 variable: Variable.Index,
569 function: Function.Index,733 function: Function.Index,
570 },734 },
571735
572 pub const Index = enum(u32) {736 pub const Index = enum(u32) {
737 none = std.math.maxInt(u32),
573 _,738 _,
574739
575 pub fn ptr(self: Index, builder: *Builder) *Global {740 pub fn ptr(self: Index, builder: *Builder) *Global {
...@@ -580,11 +745,33 @@ pub const Global = struct {...@@ -580,11 +745,33 @@ pub const Global = struct {
580 return &builder.globals.values()[@intFromEnum(self)];745 return &builder.globals.values()[@intFromEnum(self)];
581 }746 }
582747
748 pub fn toConst(self: Index) Constant {
749 return @enumFromInt(@intFromEnum(Constant.first_global) + @intFromEnum(self));
750 }
751
583 pub fn toLlvm(self: Index, builder: *const Builder) *llvm.Value {752 pub fn toLlvm(self: Index, builder: *const Builder) *llvm.Value {
584 assert(builder.useLibLlvm());753 assert(builder.useLibLlvm());
585 return builder.llvm_globals.items[@intFromEnum(self)];754 return builder.llvm_globals.items[@intFromEnum(self)];
586 }755 }
587756
757 const FormatData = struct {
758 global: Index,
759 builder: *const Builder,
760 };
761 fn format(
762 data: FormatData,
763 comptime _: []const u8,
764 _: std.fmt.FormatOptions,
765 writer: anytype,
766 ) @TypeOf(writer).Error!void {
767 try writer.print("@{}", .{
768 data.builder.globals.keys()[@intFromEnum(data.global)].fmt(data.builder),
769 });
770 }
771 pub fn fmt(self: Index, builder: *const Builder) std.fmt.Formatter(format) {
772 return .{ .data = .{ .global = self, .builder = builder } };
773 }
774
588 pub fn rename(self: Index, builder: *Builder, name: String) Allocator.Error!void {775 pub fn rename(self: Index, builder: *Builder, name: String) Allocator.Error!void {
589 try builder.ensureUnusedCapacityGlobal(name);776 try builder.ensureUnusedCapacityGlobal(name);
590 self.renameAssumeCapacity(builder, name);777 self.renameAssumeCapacity(builder, name);
...@@ -618,12 +805,32 @@ pub const Global = struct {...@@ -618,12 +805,32 @@ pub const Global = struct {
618 builder.llvm_globals.items[index].setValueName2(slice.ptr, slice.len);805 builder.llvm_globals.items[index].setValueName2(slice.ptr, slice.len);
619 }806 }
620 };807 };
808
809 pub fn updateAttributes(self: *Global) void {
810 switch (self.linkage) {
811 .private, .internal => {
812 self.visibility = .default;
813 self.dll_storage_class = .default;
814 self.preemption = .implicit_dso_local;
815 },
816 .extern_weak => if (self.preemption == .implicit_dso_local) {
817 self.preemption = .dso_local;
818 },
819 else => switch (self.visibility) {
820 .default => if (self.preemption == .implicit_dso_local) {
821 self.preemption = .dso_local;
822 },
823 else => self.preemption = .implicit_dso_local,
824 },
825 }
826 }
621};827};
622828
623pub const Alias = struct {829pub const Alias = struct {
624 global: Global.Index,830 global: Global.Index,
625831
626 pub const Index = enum(u32) {832 pub const Index = enum(u32) {
833 none = std.math.maxInt(u32),
627 _,834 _,
628835
629 pub fn ptr(self: Index, builder: *Builder) *Alias {836 pub fn ptr(self: Index, builder: *Builder) *Alias {
...@@ -640,21 +847,22 @@ pub const Alias = struct {...@@ -640,21 +847,22 @@ pub const Alias = struct {
640 };847 };
641};848};
642849
643pub const Object = struct {850pub const Variable = struct {
644 global: Global.Index,851 global: Global.Index,
645 thread_local: ThreadLocal = .default,852 thread_local: ThreadLocal = .default,
646 mutability: enum { global, constant } = .global,853 mutability: enum { global, constant } = .global,
647 init: Constant = .no_init,854 init: Constant = .no_init,
648855
649 pub const Index = enum(u32) {856 pub const Index = enum(u32) {
857 none = std.math.maxInt(u32),
650 _,858 _,
651859
652 pub fn ptr(self: Index, builder: *Builder) *Object {860 pub fn ptr(self: Index, builder: *Builder) *Variable {
653 return &builder.objects.items[@intFromEnum(self)];861 return &builder.variables.items[@intFromEnum(self)];
654 }862 }
655863
656 pub fn ptrConst(self: Index, builder: *const Builder) *const Object {864 pub fn ptrConst(self: Index, builder: *const Builder) *const Variable {
657 return &builder.objects.items[@intFromEnum(self)];865 return &builder.variables.items[@intFromEnum(self)];
658 }866 }
659867
660 pub fn toLlvm(self: Index, builder: *const Builder) *llvm.Value {868 pub fn toLlvm(self: Index, builder: *const Builder) *llvm.Value {
...@@ -670,6 +878,7 @@ pub const Function = struct {...@@ -670,6 +878,7 @@ pub const Function = struct {
670 blocks: std.ArrayListUnmanaged(Block) = .{},878 blocks: std.ArrayListUnmanaged(Block) = .{},
671879
672 pub const Index = enum(u32) {880 pub const Index = enum(u32) {
881 none = std.math.maxInt(u32),
673 _,882 _,
674883
675 pub fn ptr(self: Index, builder: *Builder) *Function {884 pub fn ptr(self: Index, builder: *Builder) *Function {
...@@ -693,13 +902,13 @@ pub const Function = struct {...@@ -693,13 +902,13 @@ pub const Function = struct {
693 block,902 block,
694 };903 };
695904
696 pub const Index = enum(u31) { _ };905 pub const Index = enum(u32) { _ };
697 };906 };
698907
699 pub const Block = struct {908 pub const Block = struct {
700 body: std.ArrayListUnmanaged(Instruction.Index) = .{},909 body: std.ArrayListUnmanaged(Instruction.Index) = .{},
701910
702 pub const Index = enum(u31) { _ };911 pub const Index = enum(u32) { _ };
703 };912 };
704913
705 pub fn deinit(self: *Function, gpa: Allocator) void {914 pub fn deinit(self: *Function, gpa: Allocator) void {
...@@ -709,6 +918,36 @@ pub const Function = struct {...@@ -709,6 +918,36 @@ pub const Function = struct {
709 }918 }
710};919};
711920
921pub const FloatCondition = enum(u4) {
922 oeq = 1,
923 ogt = 2,
924 oge = 3,
925 olt = 4,
926 ole = 5,
927 one = 6,
928 ord = 7,
929 uno = 8,
930 ueq = 9,
931 ugt = 10,
932 uge = 11,
933 ult = 12,
934 ule = 13,
935 une = 14,
936};
937
938pub const IntegerCondition = enum(u6) {
939 eq = 32,
940 ne = 33,
941 ugt = 34,
942 uge = 35,
943 ult = 36,
944 ule = 37,
945 sgt = 38,
946 sge = 39,
947 slt = 40,
948 sle = 41,
949};
950
712pub const Constant = enum(u32) {951pub const Constant = enum(u32) {
713 false,952 false,
714 true,953 true,
...@@ -719,15 +958,24 @@ pub const Constant = enum(u32) {...@@ -719,15 +958,24 @@ pub const Constant = enum(u32) {
719 const first_global: Constant = @enumFromInt(1 << 30);958 const first_global: Constant = @enumFromInt(1 << 30);
720959
721 pub const Tag = enum(u6) {960 pub const Tag = enum(u6) {
722 integer_positive,961 positive_integer,
723 integer_negative,962 negative_integer,
963 half,
964 bfloat,
965 float,
966 double,
967 fp128,
968 x86_fp80,
969 ppc_fp128,
724 null,970 null,
725 none,971 none,
726 structure,972 structure,
973 packed_structure,
727 array,974 array,
975 string,
976 string_null,
728 vector,977 vector,
729 zeroinitializer,978 zeroinitializer,
730 global,
731 undef,979 undef,
732 poison,980 poison,
733 blockaddress,981 blockaddress,
...@@ -747,6 +995,7 @@ pub const Constant = enum(u32) {...@@ -747,6 +995,7 @@ pub const Constant = enum(u32) {
747 bitcast,995 bitcast,
748 addrspacecast,996 addrspacecast,
749 getelementptr,997 getelementptr,
998 @"getelementptr inbounds",
750 icmp,999 icmp,
751 fcmp,1000 fcmp,
752 extractelement,1001 extractelement,
...@@ -765,7 +1014,9 @@ pub const Constant = enum(u32) {...@@ -765,7 +1014,9 @@ pub const Constant = enum(u32) {
7651014
766 pub const Item = struct {1015 pub const Item = struct {
767 tag: Tag,1016 tag: Tag,
768 data: u32,1017 data: ExtraIndex,
1018
1019 const ExtraIndex = u32;
769 };1020 };
7701021
771 pub const Integer = packed struct(u64) {1022 pub const Integer = packed struct(u64) {
...@@ -775,6 +1026,80 @@ pub const Constant = enum(u32) {...@@ -775,6 +1026,80 @@ pub const Constant = enum(u32) {
775 pub const limbs = @divExact(@bitSizeOf(Integer), @bitSizeOf(std.math.big.Limb));1026 pub const limbs = @divExact(@bitSizeOf(Integer), @bitSizeOf(std.math.big.Limb));
776 };1027 };
7771028
1029 pub const Double = struct {
1030 lo: u32,
1031 hi: u32,
1032 };
1033
1034 pub const Fp80 = struct {
1035 lo_lo: u32,
1036 lo_hi: u32,
1037 hi: u32,
1038 };
1039
1040 pub const Fp128 = struct {
1041 lo_lo: u32,
1042 lo_hi: u32,
1043 hi_lo: u32,
1044 hi_hi: u32,
1045 };
1046
1047 pub const Aggregate = struct {
1048 type: Type,
1049 };
1050
1051 pub const BlockAddress = extern struct {
1052 function: Function.Index,
1053 block: Function.Block.Index,
1054 };
1055
1056 pub const FunctionReference = struct {
1057 function: Function.Index,
1058 };
1059
1060 pub const Cast = extern struct {
1061 arg: Constant,
1062 type: Type,
1063
1064 pub const Signedness = enum { unsigned, signed, unneeded };
1065 };
1066
1067 pub const GetElementPtr = struct {
1068 type: Type,
1069 base: Constant,
1070 indices_len: u32,
1071
1072 pub const Kind = enum { normal, inbounds };
1073 };
1074
1075 pub const Compare = struct {
1076 cond: u32,
1077 lhs: Constant,
1078 rhs: Constant,
1079 };
1080
1081 pub const ExtractElement = struct {
1082 arg: Constant,
1083 index: Constant,
1084 };
1085
1086 pub const InsertElement = struct {
1087 arg: Constant,
1088 elem: Constant,
1089 index: Constant,
1090 };
1091
1092 pub const ShuffleVector = struct {
1093 lhs: Constant,
1094 rhs: Constant,
1095 mask: Constant,
1096 };
1097
1098 pub const Binary = extern struct {
1099 lhs: Constant,
1100 rhs: Constant,
1101 };
1102
778 pub fn unwrap(self: Constant) union(enum) {1103 pub fn unwrap(self: Constant) union(enum) {
779 constant: u30,1104 constant: u30,
780 global: Global.Index,1105 global: Global.Index,
...@@ -785,6 +1110,307 @@ pub const Constant = enum(u32) {...@@ -785,6 +1110,307 @@ pub const Constant = enum(u32) {
785 .{ .global = @enumFromInt(@intFromEnum(self) - @intFromEnum(first_global)) };1110 .{ .global = @enumFromInt(@intFromEnum(self) - @intFromEnum(first_global)) };
786 }1111 }
7871112
1113 pub fn typeOf(self: Constant, builder: *Builder) Type {
1114 switch (self.unwrap()) {
1115 .constant => |constant| {
1116 const item = builder.constant_items.get(constant);
1117 return switch (item.tag) {
1118 .positive_integer,
1119 .negative_integer,
1120 => @as(
1121 *align(@alignOf(std.math.big.Limb)) Integer,
1122 @ptrCast(builder.constant_limbs.items[item.data..][0..Integer.limbs]),
1123 ).type,
1124 .half => .half,
1125 .bfloat => .bfloat,
1126 .float => .float,
1127 .double => .double,
1128 .fp128 => .fp128,
1129 .x86_fp80 => .x86_fp80,
1130 .ppc_fp128 => .ppc_fp128,
1131 .null,
1132 .none,
1133 .zeroinitializer,
1134 .undef,
1135 .poison,
1136 => @enumFromInt(item.data),
1137 .structure,
1138 .packed_structure,
1139 .array,
1140 .vector,
1141 => builder.constantExtraData(Aggregate, item.data).type,
1142 .string,
1143 .string_null,
1144 => builder.arrayTypeAssumeCapacity(
1145 @as(String, @enumFromInt(item.data)).toSlice(builder).?.len +
1146 @intFromBool(item.tag == .string_null),
1147 .i8,
1148 ),
1149 .blockaddress => builder.ptrTypeAssumeCapacity(
1150 builder.constantExtraData(BlockAddress, item.data)
1151 .function.ptrConst(builder).global.ptrConst(builder).addr_space,
1152 ),
1153 .dso_local_equivalent,
1154 .no_cfi,
1155 => builder.ptrTypeAssumeCapacity(
1156 builder.constantExtraData(FunctionReference, item.data)
1157 .function.ptrConst(builder).global.ptrConst(builder).addr_space,
1158 ),
1159 .trunc,
1160 .zext,
1161 .sext,
1162 .fptrunc,
1163 .fpext,
1164 .fptoui,
1165 .fptosi,
1166 .uitofp,
1167 .sitofp,
1168 .ptrtoint,
1169 .inttoptr,
1170 .bitcast,
1171 .addrspacecast,
1172 => builder.constantExtraData(Cast, item.data).type,
1173 .getelementptr,
1174 .@"getelementptr inbounds",
1175 => {
1176 const extra = builder.constantExtraDataTrail(GetElementPtr, item.data);
1177 const indices: []const Constant = @ptrCast(builder.constant_extra
1178 .items[extra.end..][0..extra.data.indices_len]);
1179 const base_ty = extra.data.base.typeOf(builder);
1180 if (!base_ty.isVector(builder)) for (indices) |index| {
1181 const index_ty = index.typeOf(builder);
1182 if (!index_ty.isVector(builder)) continue;
1183 switch (index_ty.vectorKind(builder)) {
1184 inline else => |kind| return builder.vectorTypeAssumeCapacity(
1185 kind,
1186 index_ty.vectorLen(builder),
1187 base_ty,
1188 ),
1189 }
1190 };
1191 return base_ty;
1192 },
1193 .icmp, .fcmp => {
1194 const ty = builder.constantExtraData(Compare, item.data).lhs.typeOf(builder);
1195 return switch (ty) {
1196 .half,
1197 .bfloat,
1198 .float,
1199 .double,
1200 .fp128,
1201 .x86_fp80,
1202 .ppc_fp128,
1203 .i1,
1204 .i8,
1205 .i16,
1206 .i29,
1207 .i32,
1208 .i64,
1209 .i80,
1210 .i128,
1211 => ty,
1212 else => if (ty.isVector(builder)) switch (ty.vectorKind(builder)) {
1213 inline else => |kind| builder
1214 .vectorTypeAssumeCapacity(kind, ty.vectorLen(builder), .i1),
1215 } else ty,
1216 };
1217 },
1218 .extractelement => builder.constantExtraData(ExtractElement, item.data)
1219 .arg.typeOf(builder).childType(builder),
1220 .insertelement => builder.constantExtraData(InsertElement, item.data)
1221 .arg.typeOf(builder),
1222 .shufflevector => {
1223 const extra = builder.constantExtraData(ShuffleVector, item.data);
1224 const ty = extra.lhs.typeOf(builder);
1225 return switch (ty.vectorKind(builder)) {
1226 inline else => |kind| builder.vectorTypeAssumeCapacity(
1227 kind,
1228 extra.mask.typeOf(builder).vectorLen(builder),
1229 ty.childType(builder),
1230 ),
1231 };
1232 },
1233 .add,
1234 .sub,
1235 .mul,
1236 .shl,
1237 .lshr,
1238 .ashr,
1239 .@"and",
1240 .@"or",
1241 .xor,
1242 => builder.constantExtraData(Binary, item.data).lhs.typeOf(builder),
1243 };
1244 },
1245 .global => |global| return builder.ptrTypeAssumeCapacity(
1246 global.ptrConst(builder).addr_space,
1247 ),
1248 }
1249 }
1250
1251 pub fn isZeroInit(self: Constant, builder: *const Builder) bool {
1252 switch (self.unwrap()) {
1253 .constant => |constant| {
1254 const item = builder.constant_items.get(constant);
1255 return switch (item.tag) {
1256 .positive_integer => {
1257 const extra: *align(@alignOf(std.math.big.Limb)) Integer =
1258 @ptrCast(builder.constant_limbs.items[item.data..][0..Integer.limbs]);
1259 const limbs = builder.constant_limbs
1260 .items[item.data + Integer.limbs ..][0..extra.limbs_len];
1261 return std.mem.eql(std.math.big.Limb, limbs, &.{0});
1262 },
1263 .half, .bfloat, .float => item.data == 0,
1264 .double => {
1265 const extra = builder.constantExtraData(Constant.Double, item.data);
1266 return extra.lo == 0 and extra.hi == 0;
1267 },
1268 .fp128, .ppc_fp128 => {
1269 const extra = builder.constantExtraData(Constant.Fp128, item.data);
1270 return extra.lo_lo == 0 and extra.lo_hi == 0 and
1271 extra.hi_lo == 0 and extra.hi_hi == 0;
1272 },
1273 .x86_fp80 => {
1274 const extra = builder.constantExtraData(Constant.Fp80, item.data);
1275 return extra.lo_lo == 0 and extra.lo_hi == 0 and extra.hi == 0;
1276 },
1277 .vector => {
1278 const extra = builder.constantExtraDataTrail(Aggregate, item.data);
1279 const len = extra.data.type.aggregateLen(builder);
1280 const vals: []const Constant =
1281 @ptrCast(builder.constant_extra.items[extra.end..][0..len]);
1282 for (vals) |val| if (!val.isZeroInit(builder)) return false;
1283 return true;
1284 },
1285 .null, .zeroinitializer => true,
1286 else => false,
1287 };
1288 },
1289 .global => return false,
1290 }
1291 }
1292
1293 pub const FormatData = struct {
1294 constant: Constant,
1295 builder: *Builder,
1296 };
1297 fn format(
1298 data: FormatData,
1299 comptime fmt_str: []const u8,
1300 _: std.fmt.FormatOptions,
1301 writer: anytype,
1302 ) @TypeOf(writer).Error!void {
1303 if (comptime std.mem.eql(u8, fmt_str, "%")) {
1304 try writer.print("{%} ", .{data.constant.typeOf(data.builder).fmt(data.builder)});
1305 } else if (comptime std.mem.eql(u8, fmt_str, " ")) {
1306 if (data.constant == .no_init) return;
1307 try writer.writeByte(' ');
1308 }
1309 assert(data.constant != .no_init);
1310 if (std.enums.tagName(Constant, data.constant)) |name| return writer.writeAll(name);
1311 switch (data.constant.unwrap()) {
1312 .constant => |constant| {
1313 const item = data.builder.constant_items.get(constant);
1314 switch (item.tag) {
1315 .positive_integer,
1316 .negative_integer,
1317 => {
1318 const extra: *align(@alignOf(std.math.big.Limb)) Integer =
1319 @ptrCast(data.builder.constant_limbs.items[item.data..][0..Integer.limbs]);
1320 const limbs = data.builder.constant_limbs
1321 .items[item.data + Integer.limbs ..][0..extra.limbs_len];
1322 const bigint = std.math.big.int.Const{
1323 .limbs = limbs,
1324 .positive = item.tag == .positive_integer,
1325 };
1326 const ExpectedContents = extern struct {
1327 string: [(64 * 8 / std.math.log2(10)) + 2]u8,
1328 limbs: [
1329 std.math.big.int.calcToStringLimbsBufferLen(
1330 64 / @sizeOf(std.math.big.Limb),
1331 10,
1332 )
1333 ]std.math.big.Limb,
1334 };
1335 var stack align(@alignOf(ExpectedContents)) =
1336 std.heap.stackFallback(@sizeOf(ExpectedContents), data.builder.gpa);
1337 const allocator = stack.get();
1338 const str = bigint.toStringAlloc(allocator, 10, undefined) catch
1339 return writer.writeAll("...");
1340 defer allocator.free(str);
1341 try writer.writeAll(str);
1342 },
1343 .null,
1344 .none,
1345 .zeroinitializer,
1346 .undef,
1347 .poison,
1348 => try writer.writeAll(@tagName(item.tag)),
1349 .structure,
1350 .packed_structure,
1351 .array,
1352 .vector,
1353 => {
1354 const extra = data.builder.constantExtraDataTrail(Aggregate, item.data);
1355 const len = extra.data.type.aggregateLen(data.builder);
1356 const vals: []const Constant =
1357 @ptrCast(data.builder.constant_extra.items[extra.end..][0..len]);
1358
1359 try writer.writeAll(switch (item.tag) {
1360 .structure => "{ ",
1361 .packed_structure => "<{ ",
1362 .array => "[",
1363 .vector => "<",
1364 else => unreachable,
1365 });
1366 for (vals, 0..) |val, index| {
1367 if (index > 0) try writer.writeAll(", ");
1368 try writer.print("{%}", .{val.fmt(data.builder)});
1369 }
1370 try writer.writeAll(switch (item.tag) {
1371 .structure => " }",
1372 .packed_structure => " }>",
1373 .array => "]",
1374 .vector => ">",
1375 else => unreachable,
1376 });
1377 },
1378 .string => try writer.print(
1379 \\c{"}
1380 , .{@as(String, @enumFromInt(item.data)).fmt(data.builder)}),
1381 .string_null => try writer.print(
1382 \\c{"@}
1383 , .{@as(String, @enumFromInt(item.data)).fmt(data.builder)}),
1384 .blockaddress => {
1385 const extra = data.builder.constantExtraData(BlockAddress, item.data);
1386 const function = extra.function.ptrConst(data.builder);
1387 try writer.print("{s}({}, %{d})", .{
1388 @tagName(item.tag),
1389 function.global.fmt(data.builder),
1390 @intFromEnum(extra.block), // TODO
1391 });
1392 },
1393 .dso_local_equivalent,
1394 .no_cfi,
1395 => {
1396 const extra = data.builder.constantExtraData(FunctionReference, item.data);
1397 try writer.print("{s} {}", .{
1398 @tagName(item.tag),
1399 extra.function.ptrConst(data.builder).global.fmt(data.builder),
1400 });
1401 },
1402 else => try writer.print("<{s}:0x{X}>", .{
1403 @tagName(item.tag), @intFromEnum(data.constant),
1404 }),
1405 }
1406 },
1407 .global => |global| try writer.print("{}", .{global.fmt(data.builder)}),
1408 }
1409 }
1410 pub fn fmt(self: Constant, builder: *Builder) std.fmt.Formatter(format) {
1411 return .{ .data = .{ .constant = self, .builder = builder } };
1412 }
1413
788 pub fn toLlvm(self: Constant, builder: *const Builder) *llvm.Value {1414 pub fn toLlvm(self: Constant, builder: *const Builder) *llvm.Value {
789 assert(builder.useLibLlvm());1415 assert(builder.useLibLlvm());
790 return switch (self.unwrap()) {1416 return switch (self.unwrap()) {
...@@ -813,7 +1439,6 @@ pub const Value = enum(u32) {...@@ -813,7 +1439,6 @@ pub const Value = enum(u32) {
813pub fn init(self: *Builder) Allocator.Error!void {1439pub fn init(self: *Builder) Allocator.Error!void {
814 try self.string_indices.append(self.gpa, 0);1440 try self.string_indices.append(self.gpa, 0);
815 assert(try self.string("") == .empty);1441 assert(try self.string("") == .empty);
816 assert(try self.string("debugme") == .debugme);
8171442
818 {1443 {
819 const static_len = @typeInfo(Type).Enum.fields.len - 1;1444 const static_len = @typeInfo(Type).Enum.fields.len - 1;
...@@ -821,10 +1446,9 @@ pub fn init(self: *Builder) Allocator.Error!void {...@@ -821,10 +1446,9 @@ pub fn init(self: *Builder) Allocator.Error!void {
821 try self.type_items.ensureTotalCapacity(self.gpa, static_len);1446 try self.type_items.ensureTotalCapacity(self.gpa, static_len);
822 if (self.useLibLlvm()) try self.llvm_types.ensureTotalCapacity(self.gpa, static_len);1447 if (self.useLibLlvm()) try self.llvm_types.ensureTotalCapacity(self.gpa, static_len);
823 inline for (@typeInfo(Type.Simple).Enum.fields) |simple_field| {1448 inline for (@typeInfo(Type.Simple).Enum.fields) |simple_field| {
824 const result = self.typeNoExtraAssumeCapacity(.{1449 const result = self.getOrPutTypeNoExtraAssumeCapacity(
825 .tag = .simple,1450 .{ .tag = .simple, .data = simple_field.value },
826 .data = simple_field.value,1451 );
827 });
828 assert(result.new and result.type == @field(Type, simple_field.name));1452 assert(result.new and result.type == @field(Type, simple_field.name));
829 if (self.useLibLlvm()) self.llvm_types.appendAssumeCapacity(1453 if (self.useLibLlvm()) self.llvm_types.appendAssumeCapacity(
830 @field(llvm.Context, simple_field.name ++ "Type")(self.llvm_context),1454 @field(llvm.Context, simple_field.name ++ "Type")(self.llvm_context),
...@@ -838,6 +1462,7 @@ pub fn init(self: *Builder) Allocator.Error!void {...@@ -838,6 +1462,7 @@ pub fn init(self: *Builder) Allocator.Error!void {
8381462
839 assert(try self.intConst(.i1, 0) == .false);1463 assert(try self.intConst(.i1, 0) == .false);
840 assert(try self.intConst(.i1, 1) == .true);1464 assert(try self.intConst(.i1, 1) == .true);
1465 assert(try self.noneConst(.token) == .none);
841}1466}
8421467
843pub fn deinit(self: *Builder) void {1468pub fn deinit(self: *Builder) void {
...@@ -858,7 +1483,7 @@ pub fn deinit(self: *Builder) void {...@@ -858,7 +1483,7 @@ pub fn deinit(self: *Builder) void {
858 self.globals.deinit(self.gpa);1483 self.globals.deinit(self.gpa);
859 self.next_unique_global_id.deinit(self.gpa);1484 self.next_unique_global_id.deinit(self.gpa);
860 self.aliases.deinit(self.gpa);1485 self.aliases.deinit(self.gpa);
861 self.objects.deinit(self.gpa);1486 self.variables.deinit(self.gpa);
862 for (self.functions.items) |*function| function.deinit(self.gpa);1487 for (self.functions.items) |*function| function.deinit(self.gpa);
863 self.functions.deinit(self.gpa);1488 self.functions.deinit(self.gpa);
8641489
...@@ -1110,19 +1735,19 @@ pub fn fnType(...@@ -1110,19 +1735,19 @@ pub fn fnType(
1110 params: []const Type,1735 params: []const Type,
1111 kind: Type.Function.Kind,1736 kind: Type.Function.Kind,
1112) Allocator.Error!Type {1737) Allocator.Error!Type {
1113 try self.ensureUnusedCapacityTypes(1, Type.Function, params.len);1738 try self.ensureUnusedTypeCapacity(1, Type.Function, params.len);
1114 return switch (kind) {1739 return switch (kind) {
1115 inline else => |comptime_kind| self.fnTypeAssumeCapacity(ret, params, comptime_kind),1740 inline else => |comptime_kind| self.fnTypeAssumeCapacity(ret, params, comptime_kind),
1116 };1741 };
1117}1742}
11181743
1119pub fn intType(self: *Builder, bits: u24) Allocator.Error!Type {1744pub fn intType(self: *Builder, bits: u24) Allocator.Error!Type {
1120 try self.ensureUnusedCapacityTypes(1, null, 0);1745 try self.ensureUnusedTypeCapacity(1, null, 0);
1121 return self.intTypeAssumeCapacity(bits);1746 return self.intTypeAssumeCapacity(bits);
1122}1747}
11231748
1124pub fn ptrType(self: *Builder, addr_space: AddrSpace) Allocator.Error!Type {1749pub fn ptrType(self: *Builder, addr_space: AddrSpace) Allocator.Error!Type {
1125 try self.ensureUnusedCapacityTypes(1, null, 0);1750 try self.ensureUnusedTypeCapacity(1, null, 0);
1126 return self.ptrTypeAssumeCapacity(addr_space);1751 return self.ptrTypeAssumeCapacity(addr_space);
1127}1752}
11281753
...@@ -1132,7 +1757,7 @@ pub fn vectorType(...@@ -1132,7 +1757,7 @@ pub fn vectorType(
1132 len: u32,1757 len: u32,
1133 child: Type,1758 child: Type,
1134) Allocator.Error!Type {1759) Allocator.Error!Type {
1135 try self.ensureUnusedCapacityTypes(1, Type.Vector, 0);1760 try self.ensureUnusedTypeCapacity(1, Type.Vector, 0);
1136 return switch (kind) {1761 return switch (kind) {
1137 inline else => |comptime_kind| self.vectorTypeAssumeCapacity(comptime_kind, len, child),1762 inline else => |comptime_kind| self.vectorTypeAssumeCapacity(comptime_kind, len, child),
1138 };1763 };
...@@ -1140,7 +1765,7 @@ pub fn vectorType(...@@ -1140,7 +1765,7 @@ pub fn vectorType(
11401765
1141pub fn arrayType(self: *Builder, len: u64, child: Type) Allocator.Error!Type {1766pub fn arrayType(self: *Builder, len: u64, child: Type) Allocator.Error!Type {
1142 comptime assert(@sizeOf(Type.Array) >= @sizeOf(Type.Vector));1767 comptime assert(@sizeOf(Type.Array) >= @sizeOf(Type.Vector));
1143 try self.ensureUnusedCapacityTypes(1, Type.Array, 0);1768 try self.ensureUnusedTypeCapacity(1, Type.Array, 0);
1144 return self.arrayTypeAssumeCapacity(len, child);1769 return self.arrayTypeAssumeCapacity(len, child);
1145}1770}
11461771
...@@ -1149,7 +1774,7 @@ pub fn structType(...@@ -1149,7 +1774,7 @@ pub fn structType(
1149 kind: Type.Structure.Kind,1774 kind: Type.Structure.Kind,
1150 fields: []const Type,1775 fields: []const Type,
1151) Allocator.Error!Type {1776) Allocator.Error!Type {
1152 try self.ensureUnusedCapacityTypes(1, Type.Structure, fields.len);1777 try self.ensureUnusedTypeCapacity(1, Type.Structure, fields.len);
1153 return switch (kind) {1778 return switch (kind) {
1154 inline else => |comptime_kind| self.structTypeAssumeCapacity(comptime_kind, fields),1779 inline else => |comptime_kind| self.structTypeAssumeCapacity(comptime_kind, fields),
1155 };1780 };
...@@ -1162,7 +1787,7 @@ pub fn opaqueType(self: *Builder, name: String) Allocator.Error!Type {...@@ -1162,7 +1787,7 @@ pub fn opaqueType(self: *Builder, name: String) Allocator.Error!Type {
1162 try self.string_indices.ensureUnusedCapacity(self.gpa, 1);1787 try self.string_indices.ensureUnusedCapacity(self.gpa, 1);
1163 try self.types.ensureUnusedCapacity(self.gpa, 1);1788 try self.types.ensureUnusedCapacity(self.gpa, 1);
1164 try self.next_unique_type_id.ensureUnusedCapacity(self.gpa, 1);1789 try self.next_unique_type_id.ensureUnusedCapacity(self.gpa, 1);
1165 try self.ensureUnusedCapacityTypes(1, Type.NamedStructure, 0);1790 try self.ensureUnusedTypeCapacity(1, Type.NamedStructure, 0);
1166 return self.opaqueTypeAssumeCapacity(name);1791 return self.opaqueTypeAssumeCapacity(name);
1167}1792}
11681793
...@@ -1181,8 +1806,7 @@ pub fn namedTypeSetBody(...@@ -1181,8 +1806,7 @@ pub fn namedTypeSetBody(
1181 @ptrCast(self.type_extra.items[body_extra.end..][0..body_extra.data.fields_len]);1806 @ptrCast(self.type_extra.items[body_extra.end..][0..body_extra.data.fields_len]);
1182 const llvm_fields = try self.gpa.alloc(*llvm.Type, body_fields.len);1807 const llvm_fields = try self.gpa.alloc(*llvm.Type, body_fields.len);
1183 defer self.gpa.free(llvm_fields);1808 defer self.gpa.free(llvm_fields);
1184 for (llvm_fields, body_fields) |*llvm_field, body_field|1809 for (llvm_fields, body_fields) |*llvm_field, body_field| llvm_field.* = body_field.toLlvm(self);
1185 llvm_field.* = self.llvm_types.items[@intFromEnum(body_field)];
1186 self.llvm_types.items[@intFromEnum(named_type)].structSetBody(1810 self.llvm_types.items[@intFromEnum(named_type)].structSetBody(
1187 llvm_fields.ptr,1811 llvm_fields.ptr,
1188 @intCast(llvm_fields.len),1812 @intCast(llvm_fields.len),
...@@ -1196,11 +1820,13 @@ pub fn namedTypeSetBody(...@@ -1196,11 +1820,13 @@ pub fn namedTypeSetBody(
1196}1820}
11971821
1198pub fn addGlobal(self: *Builder, name: String, global: Global) Allocator.Error!Global.Index {1822pub fn addGlobal(self: *Builder, name: String, global: Global) Allocator.Error!Global.Index {
1823 try self.ensureUnusedTypeCapacity(1, null, 0);
1199 try self.ensureUnusedCapacityGlobal(name);1824 try self.ensureUnusedCapacityGlobal(name);
1200 return self.addGlobalAssumeCapacity(name, global);1825 return self.addGlobalAssumeCapacity(name, global);
1201}1826}
12021827
1203pub fn addGlobalAssumeCapacity(self: *Builder, name: String, global: Global) Global.Index {1828pub fn addGlobalAssumeCapacity(self: *Builder, name: String, global: Global) Global.Index {
1829 _ = self.ptrTypeAssumeCapacity(global.addr_space);
1204 var id = name;1830 var id = name;
1205 if (id == .none) {1831 if (id == .none) {
1206 id = self.next_unnamed_global;1832 id = self.next_unnamed_global;
...@@ -1210,6 +1836,7 @@ pub fn addGlobalAssumeCapacity(self: *Builder, name: String, global: Global) Glo...@@ -1210,6 +1836,7 @@ pub fn addGlobalAssumeCapacity(self: *Builder, name: String, global: Global) Glo
1210 const global_gop = self.globals.getOrPutAssumeCapacity(id);1836 const global_gop = self.globals.getOrPutAssumeCapacity(id);
1211 if (!global_gop.found_existing) {1837 if (!global_gop.found_existing) {
1212 global_gop.value_ptr.* = global;1838 global_gop.value_ptr.* = global;
1839 global_gop.value_ptr.updateAttributes();
1213 const index: Global.Index = @enumFromInt(global_gop.index);1840 const index: Global.Index = @enumFromInt(global_gop.index);
1214 index.updateName(self);1841 index.updateName(self);
1215 return index;1842 return index;
...@@ -1246,6 +1873,207 @@ pub fn bigIntConst(self: *Builder, ty: Type, value: std.math.big.int.Const) Allo...@@ -1246,6 +1873,207 @@ pub fn bigIntConst(self: *Builder, ty: Type, value: std.math.big.int.Const) Allo
1246 return self.bigIntConstAssumeCapacity(ty, value);1873 return self.bigIntConstAssumeCapacity(ty, value);
1247}1874}
12481875
1876pub fn fpConst(self: *Builder, ty: Type, comptime val: comptime_float) Allocator.Error!Constant {
1877 return switch (ty) {
1878 .half => try self.halfConst(val),
1879 .bfloat => try self.bfloatConst(val),
1880 .float => try self.floatConst(val),
1881 .double => try self.doubleConst(val),
1882 .fp128 => try self.fp128Const(val),
1883 .x86_fp80 => try self.x86_fp80Const(val),
1884 .ppc_fp128 => try self.ppc_fp128Const(.{ val, 0 }),
1885 else => unreachable,
1886 };
1887}
1888
1889pub fn halfConst(self: *Builder, val: f16) Allocator.Error!Constant {
1890 try self.ensureUnusedConstantCapacity(1, null, 0);
1891 return self.halfConstAssumeCapacity(val);
1892}
1893
1894pub fn bfloatConst(self: *Builder, val: f32) Allocator.Error!Constant {
1895 try self.ensureUnusedConstantCapacity(1, null, 0);
1896 return self.bfloatConstAssumeCapacity(val);
1897}
1898
1899pub fn floatConst(self: *Builder, val: f32) Allocator.Error!Constant {
1900 try self.ensureUnusedConstantCapacity(1, null, 0);
1901 return self.floatConstAssumeCapacity(val);
1902}
1903
1904pub fn doubleConst(self: *Builder, val: f64) Allocator.Error!Constant {
1905 try self.ensureUnusedConstantCapacity(1, Constant.Double, 0);
1906 return self.doubleConstAssumeCapacity(val);
1907}
1908
1909pub fn fp128Const(self: *Builder, val: f128) Allocator.Error!Constant {
1910 try self.ensureUnusedConstantCapacity(1, Constant.Fp128, 0);
1911 return self.fp128ConstAssumeCapacity(val);
1912}
1913
1914pub fn x86_fp80Const(self: *Builder, val: f80) Allocator.Error!Constant {
1915 try self.ensureUnusedConstantCapacity(1, Constant.Fp80, 0);
1916 return self.x86_fp80ConstAssumeCapacity(val);
1917}
1918
1919pub fn ppc_fp128Const(self: *Builder, val: [2]f64) Allocator.Error!Constant {
1920 try self.ensureUnusedConstantCapacity(1, Constant.Fp128, 0);
1921 return self.ppc_fp128ConstAssumeCapacity(val);
1922}
1923
1924pub fn nullConst(self: *Builder, ty: Type) Allocator.Error!Constant {
1925 try self.ensureUnusedConstantCapacity(1, null, 0);
1926 return self.nullConstAssumeCapacity(ty);
1927}
1928
1929pub fn noneConst(self: *Builder, ty: Type) Allocator.Error!Constant {
1930 try self.ensureUnusedConstantCapacity(1, null, 0);
1931 return self.noneConstAssumeCapacity(ty);
1932}
1933
1934pub fn structConst(self: *Builder, ty: Type, vals: []const Constant) Allocator.Error!Constant {
1935 try self.ensureUnusedConstantCapacity(1, Constant.Aggregate, vals.len);
1936 return self.structConstAssumeCapacity(ty, vals);
1937}
1938
1939pub fn arrayConst(self: *Builder, ty: Type, vals: []const Constant) Allocator.Error!Constant {
1940 try self.ensureUnusedConstantCapacity(1, Constant.Aggregate, vals.len);
1941 return self.arrayConstAssumeCapacity(ty, vals);
1942}
1943
1944pub fn stringConst(self: *Builder, val: String) Allocator.Error!Constant {
1945 try self.ensureUnusedTypeCapacity(1, Type.Array, 0);
1946 try self.ensureUnusedConstantCapacity(1, null, 0);
1947 return self.stringConstAssumeCapacity(val);
1948}
1949
1950pub fn stringNullConst(self: *Builder, val: String) Allocator.Error!Constant {
1951 try self.ensureUnusedTypeCapacity(1, Type.Array, 0);
1952 try self.ensureUnusedConstantCapacity(1, null, 0);
1953 return self.stringNullConstAssumeCapacity(val);
1954}
1955
1956pub fn vectorConst(self: *Builder, ty: Type, vals: []const Constant) Allocator.Error!Constant {
1957 try self.ensureUnusedConstantCapacity(1, Constant.Aggregate, vals.len);
1958 return self.vectorConstAssumeCapacity(ty, vals);
1959}
1960
1961pub fn zeroInitConst(self: *Builder, ty: Type) Allocator.Error!Constant {
1962 try self.ensureUnusedConstantCapacity(1, null, 0);
1963 return self.zeroInitConstAssumeCapacity(ty);
1964}
1965
1966pub fn undefConst(self: *Builder, ty: Type) Allocator.Error!Constant {
1967 try self.ensureUnusedConstantCapacity(1, null, 0);
1968 return self.undefConstAssumeCapacity(ty);
1969}
1970
1971pub fn poisonConst(self: *Builder, ty: Type) Allocator.Error!Constant {
1972 try self.ensureUnusedConstantCapacity(1, null, 0);
1973 return self.poisonConstAssumeCapacity(ty);
1974}
1975
1976pub fn blockAddrConst(
1977 self: *Builder,
1978 function: Function.Index,
1979 block: Function.Block.Index,
1980) Allocator.Error!Constant {
1981 try self.ensureUnusedConstantCapacity(1, Constant.BlockAddress, 0);
1982 return self.blockAddrConstAssumeCapacity(function, block);
1983}
1984
1985pub fn dsoLocalEquivalentConst(self: *Builder, function: Function.Index) Allocator.Error!Constant {
1986 try self.ensureUnusedConstantCapacity(1, Constant.FunctionReference, 0);
1987 return self.dsoLocalEquivalentConstAssumeCapacity(function);
1988}
1989
1990pub fn noCfiConst(self: *Builder, function: Function.Index) Allocator.Error!Constant {
1991 try self.ensureUnusedConstantCapacity(1, Constant.FunctionReference, 0);
1992 return self.noCfiConstAssumeCapacity(function);
1993}
1994
1995pub fn convConst(
1996 self: *Builder,
1997 signedness: Constant.Cast.Signedness,
1998 arg: Constant,
1999 ty: Type,
2000) Allocator.Error!Constant {
2001 try self.ensureUnusedConstantCapacity(1, Constant.Cast, 0);
2002 return self.convConstAssumeCapacity(signedness, arg, ty);
2003}
2004
2005pub fn castConst(self: *Builder, tag: Constant.Tag, arg: Constant, ty: Type) Allocator.Error!Constant {
2006 try self.ensureUnusedConstantCapacity(1, Constant.Cast, 0);
2007 return self.castConstAssumeCapacity(tag, arg, ty);
2008}
2009
2010pub fn gepConst(
2011 self: *Builder,
2012 comptime kind: Constant.GetElementPtr.Kind,
2013 ty: Type,
2014 base: Constant,
2015 indices: []const Constant,
2016) Allocator.Error!Constant {
2017 try self.ensureUnusedTypeCapacity(1, Type.Vector, 0);
2018 try self.ensureUnusedConstantCapacity(1, Constant.GetElementPtr, indices.len);
2019 return self.gepConstAssumeCapacity(kind, ty, base, indices);
2020}
2021
2022pub fn icmpConst(
2023 self: *Builder,
2024 cond: IntegerCondition,
2025 lhs: Constant,
2026 rhs: Constant,
2027) Allocator.Error!Constant {
2028 try self.ensureUnusedConstantCapacity(1, Constant.Compare, 0);
2029 return self.icmpConstAssumeCapacity(cond, lhs, rhs);
2030}
2031
2032pub fn fcmpConst(
2033 self: *Builder,
2034 cond: FloatCondition,
2035 lhs: Constant,
2036 rhs: Constant,
2037) Allocator.Error!Constant {
2038 try self.ensureUnusedConstantCapacity(1, Constant.Compare, 0);
2039 return self.icmpConstAssumeCapacity(cond, lhs, rhs);
2040}
2041
2042pub fn extractElementConst(self: *Builder, arg: Constant, index: Constant) Allocator.Error!Constant {
2043 try self.ensureUnusedConstantCapacity(1, Constant.ExtractElement, 0);
2044 return self.extractElementConstAssumeCapacity(arg, index);
2045}
2046
2047pub fn insertElementConst(
2048 self: *Builder,
2049 arg: Constant,
2050 elem: Constant,
2051 index: Constant,
2052) Allocator.Error!Constant {
2053 try self.ensureUnusedConstantCapacity(1, Constant.InsertElement, 0);
2054 return self.insertElementConstAssumeCapacity(arg, elem, index);
2055}
2056
2057pub fn shuffleVectorConst(
2058 self: *Builder,
2059 lhs: Constant,
2060 rhs: Constant,
2061 mask: Constant,
2062) Allocator.Error!Constant {
2063 try self.ensureUnusedConstantCapacity(1, Constant.ShuffleVector, 0);
2064 return self.shuffleVectorConstAssumeCapacity(lhs, rhs, mask);
2065}
2066
2067pub fn binConst(
2068 self: *Builder,
2069 tag: Constant.Tag,
2070 lhs: Constant,
2071 rhs: Constant,
2072) Allocator.Error!Constant {
2073 try self.ensureUnusedConstantCapacity(1, Constant.Binary, 0);
2074 return self.binConstAssumeCapacity(tag, lhs, rhs);
2075}
2076
1249pub fn dump(self: *Builder, writer: anytype) @TypeOf(writer).Error!void {2077pub fn dump(self: *Builder, writer: anytype) @TypeOf(writer).Error!void {
1250 if (self.source_filename != .none) try writer.print(2078 if (self.source_filename != .none) try writer.print(
1251 \\; ModuleID = '{s}'2079 \\; ModuleID = '{s}'
...@@ -1266,43 +2094,44 @@ pub fn dump(self: *Builder, writer: anytype) @TypeOf(writer).Error!void {...@@ -1266,43 +2094,44 @@ pub fn dump(self: *Builder, writer: anytype) @TypeOf(writer).Error!void {
1266 \\2094 \\
1267 , .{ id.fmt(self), ty.fmt(self) });2095 , .{ id.fmt(self), ty.fmt(self) });
1268 try writer.writeByte('\n');2096 try writer.writeByte('\n');
1269 for (self.objects.items) |object| {2097 for (self.variables.items) |variable| {
1270 const global = self.globals.entries.get(@intFromEnum(object.global));2098 const global = self.globals.values()[@intFromEnum(variable.global)];
1271 try writer.print(2099 try writer.print(
1272 \\@{} ={}{}{}{}{}{}{}{} {s} {%}{,}2100 \\{} ={}{}{}{}{}{}{}{} {s} {%}{ }{,}
1273 \\2101 \\
1274 , .{2102 , .{
1275 global.key.fmt(self),2103 variable.global.fmt(self),
1276 global.value.linkage,2104 global.linkage,
1277 global.value.preemption,2105 global.preemption,
1278 global.value.visibility,2106 global.visibility,
1279 global.value.dll_storage_class,2107 global.dll_storage_class,
1280 object.thread_local,2108 variable.thread_local,
1281 global.value.unnamed_addr,2109 global.unnamed_addr,
1282 global.value.addr_space,2110 global.addr_space,
1283 global.value.externally_initialized,2111 global.externally_initialized,
1284 @tagName(object.mutability),2112 @tagName(variable.mutability),
1285 global.value.type.fmt(self),2113 global.type.fmt(self),
1286 global.value.alignment,2114 variable.init.fmt(self),
2115 global.alignment,
1287 });2116 });
1288 }2117 }
1289 try writer.writeByte('\n');2118 try writer.writeByte('\n');
1290 for (self.functions.items) |function| {2119 for (self.functions.items) |function| {
1291 const global = self.globals.entries.get(@intFromEnum(function.global));2120 const global = self.globals.values()[@intFromEnum(function.global)];
1292 const item = self.type_items.items[@intFromEnum(global.value.type)];2121 const item = self.type_items.items[@intFromEnum(global.type)];
1293 const extra = self.typeExtraDataTrail(Type.Function, item.data);2122 const extra = self.typeExtraDataTrail(Type.Function, item.data);
1294 const params: []const Type =2123 const params: []const Type =
1295 @ptrCast(self.type_extra.items[extra.end..][0..extra.data.params_len]);2124 @ptrCast(self.type_extra.items[extra.end..][0..extra.data.params_len]);
1296 try writer.print(2125 try writer.print(
1297 \\{s} {}{}{}{}{} @{}(2126 \\{s}{}{}{}{} {} {}(
1298 , .{2127 , .{
1299 if (function.body) |_| "define" else "declare",2128 if (function.body) |_| "define" else "declare",
1300 global.value.linkage,2129 global.linkage,
1301 global.value.preemption,2130 global.preemption,
1302 global.value.visibility,2131 global.visibility,
1303 global.value.dll_storage_class,2132 global.dll_storage_class,
1304 extra.data.ret.fmt(self),2133 extra.data.ret.fmt(self),
1305 global.key.fmt(self),2134 function.global.fmt(self),
1306 });2135 });
1307 for (params, 0..) |param, index| {2136 for (params, 0..) |param, index| {
1308 if (index > 0) try writer.writeAll(", ");2137 if (index > 0) try writer.writeAll(", ");
...@@ -1316,65 +2145,36 @@ pub fn dump(self: *Builder, writer: anytype) @TypeOf(writer).Error!void {...@@ -1316,65 +2145,36 @@ pub fn dump(self: *Builder, writer: anytype) @TypeOf(writer).Error!void {
1316 },2145 },
1317 else => unreachable,2146 else => unreachable,
1318 }2147 }
1319 try writer.print(") {}{}", .{2148 try writer.print(") {}{}", .{ global.unnamed_addr, global.alignment });
1320 global.value.unnamed_addr,
1321 global.value.alignment,
1322 });
1323 if (function.body) |_| try writer.print(2149 if (function.body) |_| try writer.print(
1324 \\{{2150 \\{{
1325 \\ ret {%}2151 \\ ret {%}
1326 \\}}2152 \\}}
1327 \\2153 \\
1328 , .{2154 , .{extra.data.ret.fmt(self)});
1329 extra.data.ret.fmt(self),
1330 });
1331 try writer.writeByte('\n');2155 try writer.writeByte('\n');
1332 }2156 }
1333}2157}
13342158
2159fn isValidIdentifier(id: []const u8) bool {
2160 for (id, 0..) |character, index| switch (character) {
2161 '$', '-', '.', 'A'...'Z', '_', 'a'...'z' => {},
2162 '0'...'9' => if (index == 0) return false,
2163 else => return false,
2164 };
2165 return true;
2166}
2167
1335fn ensureUnusedCapacityGlobal(self: *Builder, name: String) Allocator.Error!void {2168fn ensureUnusedCapacityGlobal(self: *Builder, name: String) Allocator.Error!void {
1336 if (self.useLibLlvm()) try self.llvm_globals.ensureUnusedCapacity(self.gpa, 1);2169 if (self.useLibLlvm()) try self.llvm_globals.ensureUnusedCapacity(self.gpa, 1);
1337 try self.string_map.ensureUnusedCapacity(self.gpa, 1);2170 try self.string_map.ensureUnusedCapacity(self.gpa, 1);
1338 try self.string_bytes.ensureUnusedCapacity(self.gpa, name.toSlice(self).?.len +2171 if (name.toSlice(self)) |id| try self.string_bytes.ensureUnusedCapacity(self.gpa, id.len +
1339 comptime std.fmt.count("{d}" ++ .{0}, .{std.math.maxInt(u32)}));2172 comptime std.fmt.count("{d}" ++ .{0}, .{std.math.maxInt(u32)}));
1340 try self.string_indices.ensureUnusedCapacity(self.gpa, 1);2173 try self.string_indices.ensureUnusedCapacity(self.gpa, 1);
1341 try self.globals.ensureUnusedCapacity(self.gpa, 1);2174 try self.globals.ensureUnusedCapacity(self.gpa, 1);
1342 try self.next_unique_global_id.ensureUnusedCapacity(self.gpa, 1);2175 try self.next_unique_global_id.ensureUnusedCapacity(self.gpa, 1);
1343}2176}
13442177
1345fn addTypeExtraAssumeCapacity(self: *Builder, extra: anytype) Type.ExtraIndex {
1346 const result: Type.ExtraIndex = @intCast(self.type_extra.items.len);
1347 inline for (@typeInfo(@TypeOf(extra)).Struct.fields) |field| {
1348 const value = @field(extra, field.name);
1349 self.type_extra.appendAssumeCapacity(switch (field.type) {
1350 u32 => value,
1351 String, Type => @intFromEnum(value),
1352 else => @compileError("bad field type: " ++ @typeName(field.type)),
1353 });
1354 }
1355 return result;
1356}
1357
1358fn typeExtraDataTrail(
1359 self: *const Builder,
1360 comptime T: type,
1361 index: Type.ExtraIndex,
1362) struct { data: T, end: Type.ExtraIndex } {
1363 var result: T = undefined;
1364 const fields = @typeInfo(T).Struct.fields;
1365 inline for (fields, self.type_extra.items[index..][0..fields.len]) |field, data|
1366 @field(result, field.name) = switch (field.type) {
1367 u32 => data,
1368 String, Type => @enumFromInt(data),
1369 else => @compileError("bad field type: " ++ @typeName(field.type)),
1370 };
1371 return .{ .data = result, .end = index + @as(Type.ExtraIndex, @intCast(fields.len)) };
1372}
1373
1374fn typeExtraData(self: *const Builder, comptime T: type, index: Type.ExtraIndex) T {
1375 return self.typeExtraDataTrail(T, index).data;
1376}
1377
1378fn fnTypeAssumeCapacity(2178fn fnTypeAssumeCapacity(
1379 self: *Builder,2179 self: *Builder,
1380 ret: Type,2180 ret: Type,
...@@ -1394,17 +2194,19 @@ fn fnTypeAssumeCapacity(...@@ -1394,17 +2194,19 @@ fn fnTypeAssumeCapacity(
1394 hasher.update(std.mem.sliceAsBytes(key.params));2194 hasher.update(std.mem.sliceAsBytes(key.params));
1395 return @truncate(hasher.final());2195 return @truncate(hasher.final());
1396 }2196 }
1397 pub fn eql(ctx: @This(), lhs: Key, _: void, rhs_index: usize) bool {2197 pub fn eql(ctx: @This(), lhs_key: Key, _: void, rhs_index: usize) bool {
1398 const rhs_data = ctx.builder.type_items.items[rhs_index];2198 const rhs_data = ctx.builder.type_items.items[rhs_index];
1399 const rhs_extra = ctx.builder.typeExtraDataTrail(Type.Function, rhs_data.data);2199 const rhs_extra = ctx.builder.typeExtraDataTrail(Type.Function, rhs_data.data);
1400 const rhs_params: []const Type =2200 const rhs_params: []const Type =
1401 @ptrCast(ctx.builder.type_extra.items[rhs_extra.end..][0..rhs_extra.data.params_len]);2201 @ptrCast(ctx.builder.type_extra.items[rhs_extra.end..][0..rhs_extra.data.params_len]);
1402 return rhs_data.tag == tag and lhs.ret == rhs_extra.data.ret and2202 return rhs_data.tag == tag and lhs_key.ret == rhs_extra.data.ret and
1403 std.mem.eql(Type, lhs.params, rhs_params);2203 std.mem.eql(Type, lhs_key.params, rhs_params);
1404 }2204 }
1405 };2205 };
1406 const data = Key{ .ret = ret, .params = params };2206 const gop = self.type_map.getOrPutAssumeCapacityAdapted(
1407 const gop = self.type_map.getOrPutAssumeCapacityAdapted(data, Adapter{ .builder = self });2207 Key{ .ret = ret, .params = params },
2208 Adapter{ .builder = self },
2209 );
1408 if (!gop.found_existing) {2210 if (!gop.found_existing) {
1409 gop.key_ptr.* = {};2211 gop.key_ptr.* = {};
1410 gop.value_ptr.* = {};2212 gop.value_ptr.* = {};
...@@ -1436,17 +2238,16 @@ fn fnTypeAssumeCapacity(...@@ -1436,17 +2238,16 @@ fn fnTypeAssumeCapacity(
14362238
1437fn intTypeAssumeCapacity(self: *Builder, bits: u24) Type {2239fn intTypeAssumeCapacity(self: *Builder, bits: u24) Type {
1438 assert(bits > 0);2240 assert(bits > 0);
1439 const result = self.typeNoExtraAssumeCapacity(.{ .tag = .integer, .data = bits });2241 const result = self.getOrPutTypeNoExtraAssumeCapacity(.{ .tag = .integer, .data = bits });
1440 if (self.useLibLlvm() and result.new)2242 if (self.useLibLlvm() and result.new)
1441 self.llvm_types.appendAssumeCapacity(self.llvm_context.intType(bits));2243 self.llvm_types.appendAssumeCapacity(self.llvm_context.intType(bits));
1442 return result.type;2244 return result.type;
1443}2245}
14442246
1445fn ptrTypeAssumeCapacity(self: *Builder, addr_space: AddrSpace) Type {2247fn ptrTypeAssumeCapacity(self: *Builder, addr_space: AddrSpace) Type {
1446 const result = self.typeNoExtraAssumeCapacity(.{2248 const result = self.getOrPutTypeNoExtraAssumeCapacity(
1447 .tag = .pointer,2249 .{ .tag = .pointer, .data = @intFromEnum(addr_space) },
1448 .data = @intFromEnum(addr_space),2250 );
1449 });
1450 if (self.useLibLlvm() and result.new)2251 if (self.useLibLlvm() and result.new)
1451 self.llvm_types.appendAssumeCapacity(self.llvm_context.pointerType(@intFromEnum(addr_space)));2252 self.llvm_types.appendAssumeCapacity(self.llvm_context.pointerType(@intFromEnum(addr_space)));
1452 return result.type;2253 return result.type;
...@@ -1470,10 +2271,10 @@ fn vectorTypeAssumeCapacity(...@@ -1470,10 +2271,10 @@ fn vectorTypeAssumeCapacity(
1470 std.mem.asBytes(&key),2271 std.mem.asBytes(&key),
1471 ));2272 ));
1472 }2273 }
1473 pub fn eql(ctx: @This(), lhs: Type.Vector, _: void, rhs_index: usize) bool {2274 pub fn eql(ctx: @This(), lhs_key: Type.Vector, _: void, rhs_index: usize) bool {
1474 const rhs_data = ctx.builder.type_items.items[rhs_index];2275 const rhs_data = ctx.builder.type_items.items[rhs_index];
1475 return rhs_data.tag == tag and2276 return rhs_data.tag == tag and
1476 std.meta.eql(lhs, ctx.builder.typeExtraData(Type.Vector, rhs_data.data));2277 std.meta.eql(lhs_key, ctx.builder.typeExtraData(Type.Vector, rhs_data.data));
1477 }2278 }
1478 };2279 };
1479 const data = Type.Vector{ .len = len, .child = child };2280 const data = Type.Vector{ .len = len, .child = child };
...@@ -1503,10 +2304,10 @@ fn arrayTypeAssumeCapacity(self: *Builder, len: u64, child: Type) Type {...@@ -1503,10 +2304,10 @@ fn arrayTypeAssumeCapacity(self: *Builder, len: u64, child: Type) Type {
1503 std.mem.asBytes(&key),2304 std.mem.asBytes(&key),
1504 ));2305 ));
1505 }2306 }
1506 pub fn eql(ctx: @This(), lhs: Type.Vector, _: void, rhs_index: usize) bool {2307 pub fn eql(ctx: @This(), lhs_key: Type.Vector, _: void, rhs_index: usize) bool {
1507 const rhs_data = ctx.builder.type_items.items[rhs_index];2308 const rhs_data = ctx.builder.type_items.items[rhs_index];
1508 return rhs_data.tag == .small_array and2309 return rhs_data.tag == .small_array and
1509 std.meta.eql(lhs, ctx.builder.typeExtraData(Type.Vector, rhs_data.data));2310 std.meta.eql(lhs_key, ctx.builder.typeExtraData(Type.Vector, rhs_data.data));
1510 }2311 }
1511 };2312 };
1512 const data = Type.Vector{ .len = small_len, .child = child };2313 const data = Type.Vector{ .len = small_len, .child = child };
...@@ -1532,10 +2333,10 @@ fn arrayTypeAssumeCapacity(self: *Builder, len: u64, child: Type) Type {...@@ -1532,10 +2333,10 @@ fn arrayTypeAssumeCapacity(self: *Builder, len: u64, child: Type) Type {
1532 std.mem.asBytes(&key),2333 std.mem.asBytes(&key),
1533 ));2334 ));
1534 }2335 }
1535 pub fn eql(ctx: @This(), lhs: Type.Array, _: void, rhs_index: usize) bool {2336 pub fn eql(ctx: @This(), lhs_key: Type.Array, _: void, rhs_index: usize) bool {
1536 const rhs_data = ctx.builder.type_items.items[rhs_index];2337 const rhs_data = ctx.builder.type_items.items[rhs_index];
1537 return rhs_data.tag == .array and2338 return rhs_data.tag == .array and
1538 std.meta.eql(lhs, ctx.builder.typeExtraData(Type.Array, rhs_data.data));2339 std.meta.eql(lhs_key, ctx.builder.typeExtraData(Type.Array, rhs_data.data));
1539 }2340 }
1540 };2341 };
1541 const data = Type.Array{2342 const data = Type.Array{
...@@ -1576,12 +2377,12 @@ fn structTypeAssumeCapacity(...@@ -1576,12 +2377,12 @@ fn structTypeAssumeCapacity(
1576 std.mem.sliceAsBytes(key),2377 std.mem.sliceAsBytes(key),
1577 ));2378 ));
1578 }2379 }
1579 pub fn eql(ctx: @This(), lhs: []const Type, _: void, rhs_index: usize) bool {2380 pub fn eql(ctx: @This(), lhs_key: []const Type, _: void, rhs_index: usize) bool {
1580 const rhs_data = ctx.builder.type_items.items[rhs_index];2381 const rhs_data = ctx.builder.type_items.items[rhs_index];
1581 const rhs_extra = ctx.builder.typeExtraDataTrail(Type.Structure, rhs_data.data);2382 const rhs_extra = ctx.builder.typeExtraDataTrail(Type.Structure, rhs_data.data);
1582 const rhs_fields: []const Type =2383 const rhs_fields: []const Type =
1583 @ptrCast(ctx.builder.type_extra.items[rhs_extra.end..][0..rhs_extra.data.fields_len]);2384 @ptrCast(ctx.builder.type_extra.items[rhs_extra.end..][0..rhs_extra.data.fields_len]);
1584 return rhs_data.tag == tag and std.mem.eql(Type, lhs, rhs_fields);2385 return rhs_data.tag == tag and std.mem.eql(Type, lhs_key, rhs_fields);
1585 }2386 }
1586 };2387 };
1587 const gop = self.type_map.getOrPutAssumeCapacityAdapted(fields, Adapter{ .builder = self });2388 const gop = self.type_map.getOrPutAssumeCapacityAdapted(fields, Adapter{ .builder = self });
...@@ -1596,15 +2397,14 @@ fn structTypeAssumeCapacity(...@@ -1596,15 +2397,14 @@ fn structTypeAssumeCapacity(
1596 });2397 });
1597 self.type_extra.appendSliceAssumeCapacity(@ptrCast(fields));2398 self.type_extra.appendSliceAssumeCapacity(@ptrCast(fields));
1598 if (self.useLibLlvm()) {2399 if (self.useLibLlvm()) {
1599 const ExpectedContents = [32]*llvm.Type;2400 const ExpectedContents = [expected_fields_len]*llvm.Type;
1600 var stack align(@alignOf(ExpectedContents)) =2401 var stack align(@alignOf(ExpectedContents)) =
1601 std.heap.stackFallback(@sizeOf(ExpectedContents), self.gpa);2402 std.heap.stackFallback(@sizeOf(ExpectedContents), self.gpa);
1602 const allocator = stack.get();2403 const allocator = stack.get();
16032404
1604 const llvm_fields = try allocator.alloc(*llvm.Type, fields.len);2405 const llvm_fields = try allocator.alloc(*llvm.Type, fields.len);
1605 defer allocator.free(llvm_fields);2406 defer allocator.free(llvm_fields);
1606 for (llvm_fields, fields) |*llvm_field, field|2407 for (llvm_fields, fields) |*llvm_field, field| llvm_field.* = field.toLlvm(self);
1607 llvm_field.* = self.llvm_types.items[@intFromEnum(field)];
16082408
1609 self.llvm_types.appendAssumeCapacity(self.llvm_context.structType(2409 self.llvm_types.appendAssumeCapacity(self.llvm_context.structType(
1610 llvm_fields.ptr,2410 llvm_fields.ptr,
...@@ -1628,10 +2428,10 @@ fn opaqueTypeAssumeCapacity(self: *Builder, name: String) Type {...@@ -1628,10 +2428,10 @@ fn opaqueTypeAssumeCapacity(self: *Builder, name: String) Type {
1628 std.mem.asBytes(&key),2428 std.mem.asBytes(&key),
1629 ));2429 ));
1630 }2430 }
1631 pub fn eql(ctx: @This(), lhs: String, _: void, rhs_index: usize) bool {2431 pub fn eql(ctx: @This(), lhs_key: String, _: void, rhs_index: usize) bool {
1632 const rhs_data = ctx.builder.type_items.items[rhs_index];2432 const rhs_data = ctx.builder.type_items.items[rhs_index];
1633 return rhs_data.tag == .named_structure and2433 return rhs_data.tag == .named_structure and
1634 lhs == ctx.builder.typeExtraData(Type.NamedStructure, rhs_data.data).id;2434 lhs_key == ctx.builder.typeExtraData(Type.NamedStructure, rhs_data.data).id;
1635 }2435 }
1636 };2436 };
1637 var id = name;2437 var id = name;
...@@ -1669,7 +2469,7 @@ fn opaqueTypeAssumeCapacity(self: *Builder, name: String) Type {...@@ -1669,7 +2469,7 @@ fn opaqueTypeAssumeCapacity(self: *Builder, name: String) Type {
1669 }2469 }
1670}2470}
16712471
1672fn ensureUnusedCapacityTypes(2472fn ensureUnusedTypeCapacity(
1673 self: *Builder,2473 self: *Builder,
1674 count: usize,2474 count: usize,
1675 comptime Extra: ?type,2475 comptime Extra: ?type,
...@@ -1680,11 +2480,11 @@ fn ensureUnusedCapacityTypes(...@@ -1680,11 +2480,11 @@ fn ensureUnusedCapacityTypes(
1680 if (Extra) |E| try self.type_extra.ensureUnusedCapacity(2480 if (Extra) |E| try self.type_extra.ensureUnusedCapacity(
1681 self.gpa,2481 self.gpa,
1682 count * (@typeInfo(E).Struct.fields.len + trail_len),2482 count * (@typeInfo(E).Struct.fields.len + trail_len),
1683 );2483 ) else assert(trail_len == 0);
1684 if (self.useLibLlvm()) try self.llvm_types.ensureUnusedCapacity(self.gpa, count);2484 if (self.useLibLlvm()) try self.llvm_types.ensureUnusedCapacity(self.gpa, count);
1685}2485}
16862486
1687fn typeNoExtraAssumeCapacity(self: *Builder, item: Type.Item) struct { new: bool, type: Type } {2487fn getOrPutTypeNoExtraAssumeCapacity(self: *Builder, item: Type.Item) struct { new: bool, type: Type } {
1688 const Adapter = struct {2488 const Adapter = struct {
1689 builder: *const Builder,2489 builder: *const Builder,
1690 pub fn hash(_: @This(), key: Type.Item) u32 {2490 pub fn hash(_: @This(), key: Type.Item) u32 {
...@@ -1693,8 +2493,8 @@ fn typeNoExtraAssumeCapacity(self: *Builder, item: Type.Item) struct { new: bool...@@ -1693,8 +2493,8 @@ fn typeNoExtraAssumeCapacity(self: *Builder, item: Type.Item) struct { new: bool
1693 std.mem.asBytes(&key),2493 std.mem.asBytes(&key),
1694 ));2494 ));
1695 }2495 }
1696 pub fn eql(ctx: @This(), lhs: Type.Item, _: void, rhs_index: usize) bool {2496 pub fn eql(ctx: @This(), lhs_key: Type.Item, _: void, rhs_index: usize) bool {
1697 const lhs_bits: u32 = @bitCast(lhs);2497 const lhs_bits: u32 = @bitCast(lhs_key);
1698 const rhs_bits: u32 = @bitCast(ctx.builder.type_items.items[rhs_index]);2498 const rhs_bits: u32 = @bitCast(ctx.builder.type_items.items[rhs_index]);
1699 return lhs_bits == rhs_bits;2499 return lhs_bits == rhs_bits;
1700 }2500 }
...@@ -1708,13 +2508,37 @@ fn typeNoExtraAssumeCapacity(self: *Builder, item: Type.Item) struct { new: bool...@@ -1708,13 +2508,37 @@ fn typeNoExtraAssumeCapacity(self: *Builder, item: Type.Item) struct { new: bool
1708 return .{ .new = !gop.found_existing, .type = @enumFromInt(gop.index) };2508 return .{ .new = !gop.found_existing, .type = @enumFromInt(gop.index) };
1709}2509}
17102510
1711fn isValidIdentifier(id: []const u8) bool {2511fn addTypeExtraAssumeCapacity(self: *Builder, extra: anytype) Type.Item.ExtraIndex {
1712 for (id, 0..) |character, index| switch (character) {2512 const result: Type.Item.ExtraIndex = @intCast(self.type_extra.items.len);
1713 '$', '-', '.', 'A'...'Z', '_', 'a'...'z' => {},2513 inline for (@typeInfo(@TypeOf(extra)).Struct.fields) |field| {
1714 '0'...'9' => if (index == 0) return false,2514 const value = @field(extra, field.name);
1715 else => return false,2515 self.type_extra.appendAssumeCapacity(switch (field.type) {
1716 };2516 u32 => value,
1717 return true;2517 String, Type => @intFromEnum(value),
2518 else => @compileError("bad field type: " ++ @typeName(field.type)),
2519 });
2520 }
2521 return result;
2522}
2523
2524fn typeExtraDataTrail(
2525 self: *const Builder,
2526 comptime T: type,
2527 index: Type.Item.ExtraIndex,
2528) struct { data: T, end: Type.Item.ExtraIndex } {
2529 var result: T = undefined;
2530 const fields = @typeInfo(T).Struct.fields;
2531 inline for (fields, self.type_extra.items[index..][0..fields.len]) |field, data|
2532 @field(result, field.name) = switch (field.type) {
2533 u32 => data,
2534 String, Type => @enumFromInt(data),
2535 else => @compileError("bad field type: " ++ @typeName(field.type)),
2536 };
2537 return .{ .data = result, .end = index + @as(Type.Item.ExtraIndex, @intCast(fields.len)) };
2538}
2539
2540fn typeExtraData(self: *const Builder, comptime T: type, index: Type.Item.ExtraIndex) T {
2541 return self.typeExtraDataTrail(T, index).data;
1718}2542}
17192543
1720fn bigIntConstAssumeCapacity(2544fn bigIntConstAssumeCapacity(
...@@ -1748,8 +2572,8 @@ fn bigIntConstAssumeCapacity(...@@ -1748,8 +2572,8 @@ fn bigIntConstAssumeCapacity(
1748 const ExtraPtr = *align(@alignOf(std.math.big.Limb)) Constant.Integer;2572 const ExtraPtr = *align(@alignOf(std.math.big.Limb)) Constant.Integer;
1749 const Key = struct { tag: Constant.Tag, type: Type, limbs: []const std.math.big.Limb };2573 const Key = struct { tag: Constant.Tag, type: Type, limbs: []const std.math.big.Limb };
1750 const tag: Constant.Tag = switch (canonical_value.positive) {2574 const tag: Constant.Tag = switch (canonical_value.positive) {
1751 true => .integer_positive,2575 true => .positive_integer,
1752 false => .integer_negative,2576 false => .negative_integer,
1753 };2577 };
1754 const Adapter = struct {2578 const Adapter = struct {
1755 builder: *const Builder,2579 builder: *const Builder,
...@@ -1759,20 +2583,22 @@ fn bigIntConstAssumeCapacity(...@@ -1759,20 +2583,22 @@ fn bigIntConstAssumeCapacity(
1759 hasher.update(std.mem.sliceAsBytes(key.limbs));2583 hasher.update(std.mem.sliceAsBytes(key.limbs));
1760 return @truncate(hasher.final());2584 return @truncate(hasher.final());
1761 }2585 }
1762 pub fn eql(ctx: @This(), lhs: Key, _: void, rhs_index: usize) bool {2586 pub fn eql(ctx: @This(), lhs_key: Key, _: void, rhs_index: usize) bool {
1763 if (lhs.tag != ctx.builder.constant_items.items(.tag)[rhs_index]) return false;2587 if (lhs_key.tag != ctx.builder.constant_items.items(.tag)[rhs_index]) return false;
1764 const rhs_data = ctx.builder.constant_items.items(.data)[rhs_index];2588 const rhs_data = ctx.builder.constant_items.items(.data)[rhs_index];
1765 const rhs_extra: ExtraPtr = @ptrCast(2589 const rhs_extra: ExtraPtr =
1766 ctx.builder.constant_limbs.items[rhs_data..][0..Constant.Integer.limbs],2590 @ptrCast(ctx.builder.constant_limbs.items[rhs_data..][0..Constant.Integer.limbs]);
1767 );
1768 const rhs_limbs = ctx.builder.constant_limbs2591 const rhs_limbs = ctx.builder.constant_limbs
1769 .items[rhs_data + Constant.Integer.limbs ..][0..rhs_extra.limbs_len];2592 .items[rhs_data + Constant.Integer.limbs ..][0..rhs_extra.limbs_len];
1770 return lhs.type == rhs_extra.type and std.mem.eql(std.math.big.Limb, lhs.limbs, rhs_limbs);2593 return lhs_key.type == rhs_extra.type and
2594 std.mem.eql(std.math.big.Limb, lhs_key.limbs, rhs_limbs);
1771 }2595 }
1772 };2596 };
17732597
1774 const data = Key{ .tag = tag, .type = ty, .limbs = canonical_value.limbs };2598 const gop = self.constant_map.getOrPutAssumeCapacityAdapted(
1775 const gop = self.constant_map.getOrPutAssumeCapacityAdapted(data, Adapter{ .builder = self });2599 Key{ .tag = tag, .type = ty, .limbs = canonical_value.limbs },
2600 Adapter{ .builder = self },
2601 );
1776 if (!gop.found_existing) {2602 if (!gop.found_existing) {
1777 gop.key_ptr.* = {};2603 gop.key_ptr.* = {};
1778 gop.value_ptr.* = {};2604 gop.value_ptr.* = {};
...@@ -1780,9 +2606,8 @@ fn bigIntConstAssumeCapacity(...@@ -1780,9 +2606,8 @@ fn bigIntConstAssumeCapacity(
1780 .tag = tag,2606 .tag = tag,
1781 .data = @intCast(self.constant_limbs.items.len),2607 .data = @intCast(self.constant_limbs.items.len),
1782 });2608 });
1783 const extra: ExtraPtr = @ptrCast(2609 const extra: ExtraPtr =
1784 self.constant_limbs.addManyAsArrayAssumeCapacity(Constant.Integer.limbs),2610 @ptrCast(self.constant_limbs.addManyAsArrayAssumeCapacity(Constant.Integer.limbs));
1785 );
1786 extra.* = .{ .type = ty, .limbs_len = @intCast(canonical_value.limbs.len) };2611 extra.* = .{ .type = ty, .limbs_len = @intCast(canonical_value.limbs.len) };
1787 self.constant_limbs.appendSliceAssumeCapacity(canonical_value.limbs);2612 self.constant_limbs.appendSliceAssumeCapacity(canonical_value.limbs);
1788 if (self.useLibLlvm()) {2613 if (self.useLibLlvm()) {
...@@ -1827,6 +2652,870 @@ fn bigIntConstAssumeCapacity(...@@ -1827,6 +2652,870 @@ fn bigIntConstAssumeCapacity(
1827 return @enumFromInt(gop.index);2652 return @enumFromInt(gop.index);
1828}2653}
18292654
2655fn halfConstAssumeCapacity(self: *Builder, val: f16) Constant {
2656 const result = self.getOrPutConstantNoExtraAssumeCapacity(
2657 .{ .tag = .half, .data = @as(u16, @bitCast(val)) },
2658 );
2659 if (self.useLibLlvm() and result.new) self.llvm_constants.appendAssumeCapacity(
2660 if (std.math.isSignalNan(val))
2661 Type.i16.toLlvm(self).constInt(@as(u16, @bitCast(val)), .False)
2662 .constBitCast(Type.half.toLlvm(self))
2663 else
2664 Type.half.toLlvm(self).constReal(val),
2665 );
2666 return result.constant;
2667}
2668
2669fn bfloatConstAssumeCapacity(self: *Builder, val: f32) Constant {
2670 assert(@as(u16, @truncate(@as(u32, @bitCast(val)))) == 0);
2671 const result = self.getOrPutConstantNoExtraAssumeCapacity(
2672 .{ .tag = .bfloat, .data = @bitCast(val) },
2673 );
2674 if (self.useLibLlvm() and result.new) self.llvm_constants.appendAssumeCapacity(
2675 if (std.math.isSignalNan(val))
2676 Type.i16.toLlvm(self).constInt(@as(u32, @bitCast(val)) >> 16, .False)
2677 .constBitCast(Type.bfloat.toLlvm(self))
2678 else
2679 Type.bfloat.toLlvm(self).constReal(val),
2680 );
2681
2682 if (self.useLibLlvm() and result.new)
2683 self.llvm_constants.appendAssumeCapacity(Type.bfloat.toLlvm(self).constReal(val));
2684 return result.constant;
2685}
2686
2687fn floatConstAssumeCapacity(self: *Builder, val: f32) Constant {
2688 const result = self.getOrPutConstantNoExtraAssumeCapacity(
2689 .{ .tag = .float, .data = @bitCast(val) },
2690 );
2691 if (self.useLibLlvm() and result.new) self.llvm_constants.appendAssumeCapacity(
2692 if (std.math.isSignalNan(val))
2693 Type.i32.toLlvm(self).constInt(@as(u32, @bitCast(val)), .False)
2694 .constBitCast(Type.float.toLlvm(self))
2695 else
2696 Type.float.toLlvm(self).constReal(val),
2697 );
2698 return result.constant;
2699}
2700
2701fn doubleConstAssumeCapacity(self: *Builder, val: f64) Constant {
2702 const Adapter = struct {
2703 builder: *const Builder,
2704 pub fn hash(_: @This(), key: f64) u32 {
2705 return @truncate(std.hash.Wyhash.hash(
2706 comptime std.hash.uint32(@intFromEnum(Constant.Tag.double)),
2707 std.mem.asBytes(&key),
2708 ));
2709 }
2710 pub fn eql(ctx: @This(), lhs_key: f64, _: void, rhs_index: usize) bool {
2711 if (ctx.builder.constant_items.items(.tag)[rhs_index] != .double) return false;
2712 const rhs_data = ctx.builder.constant_items.items(.data)[rhs_index];
2713 const rhs_extra = ctx.builder.constantExtraData(Constant.Double, rhs_data);
2714 return @as(u64, @bitCast(lhs_key)) == @as(u64, rhs_extra.hi) << 32 | rhs_extra.lo;
2715 }
2716 };
2717 const gop = self.constant_map.getOrPutAssumeCapacityAdapted(val, Adapter{ .builder = self });
2718 if (!gop.found_existing) {
2719 gop.key_ptr.* = {};
2720 gop.value_ptr.* = {};
2721 self.constant_items.appendAssumeCapacity(.{
2722 .tag = .double,
2723 .data = self.addConstantExtraAssumeCapacity(Constant.Double{
2724 .lo = @intCast(@as(u64, @bitCast(val)) >> 32),
2725 .hi = @truncate(@as(u64, @bitCast(val))),
2726 }),
2727 });
2728 if (self.useLibLlvm()) self.llvm_constants.appendAssumeCapacity(
2729 if (std.math.isSignalNan(val))
2730 Type.i64.toLlvm(self).constInt(@as(u64, @bitCast(val)), .False)
2731 .constBitCast(Type.double.toLlvm(self))
2732 else
2733 Type.double.toLlvm(self).constReal(val),
2734 );
2735 }
2736 return @enumFromInt(gop.index);
2737}
2738
2739fn fp128ConstAssumeCapacity(self: *Builder, val: f128) Constant {
2740 const Adapter = struct {
2741 builder: *const Builder,
2742 pub fn hash(_: @This(), key: f128) u32 {
2743 return @truncate(std.hash.Wyhash.hash(
2744 comptime std.hash.uint32(@intFromEnum(Constant.Tag.fp128)),
2745 std.mem.asBytes(&key),
2746 ));
2747 }
2748 pub fn eql(ctx: @This(), lhs_key: f128, _: void, rhs_index: usize) bool {
2749 if (ctx.builder.constant_items.items(.tag)[rhs_index] != .fp128) return false;
2750 const rhs_data = ctx.builder.constant_items.items(.data)[rhs_index];
2751 const rhs_extra = ctx.builder.constantExtraData(Constant.Fp128, rhs_data);
2752 return @as(u128, @bitCast(lhs_key)) == @as(u128, rhs_extra.hi_hi) << 96 |
2753 @as(u128, rhs_extra.hi_lo) << 64 | @as(u128, rhs_extra.lo_hi) << 32 | rhs_extra.lo_lo;
2754 }
2755 };
2756 const gop = self.constant_map.getOrPutAssumeCapacityAdapted(val, Adapter{ .builder = self });
2757 if (!gop.found_existing) {
2758 gop.key_ptr.* = {};
2759 gop.value_ptr.* = {};
2760 self.constant_items.appendAssumeCapacity(.{
2761 .tag = .fp128,
2762 .data = self.addConstantExtraAssumeCapacity(Constant.Fp128{
2763 .lo_lo = @truncate(@as(u128, @bitCast(val))),
2764 .lo_hi = @truncate(@as(u128, @bitCast(val)) >> 32),
2765 .hi_lo = @truncate(@as(u128, @bitCast(val)) >> 64),
2766 .hi_hi = @intCast(@as(u128, @bitCast(val)) >> 96),
2767 }),
2768 });
2769 if (self.useLibLlvm()) {
2770 const llvm_limbs = [_]u64{
2771 @truncate(@as(u128, @bitCast(val))),
2772 @intCast(@as(u128, @bitCast(val)) >> 64),
2773 };
2774 self.llvm_constants.appendAssumeCapacity(
2775 Type.i128.toLlvm(self)
2776 .constIntOfArbitraryPrecision(@intCast(llvm_limbs.len), &llvm_limbs)
2777 .constBitCast(Type.fp128.toLlvm(self)),
2778 );
2779 }
2780 }
2781 return @enumFromInt(gop.index);
2782}
2783
2784fn x86_fp80ConstAssumeCapacity(self: *Builder, val: f80) Constant {
2785 const Adapter = struct {
2786 builder: *const Builder,
2787 pub fn hash(_: @This(), key: f80) u32 {
2788 return @truncate(std.hash.Wyhash.hash(
2789 comptime std.hash.uint32(@intFromEnum(Constant.Tag.x86_fp80)),
2790 std.mem.asBytes(&key)[0..10],
2791 ));
2792 }
2793 pub fn eql(ctx: @This(), lhs_key: f80, _: void, rhs_index: usize) bool {
2794 if (ctx.builder.constant_items.items(.tag)[rhs_index] != .x86_fp80) return false;
2795 const rhs_data = ctx.builder.constant_items.items(.data)[rhs_index];
2796 const rhs_extra = ctx.builder.constantExtraData(Constant.Fp80, rhs_data);
2797 return @as(u80, @bitCast(lhs_key)) == @as(u80, rhs_extra.hi) << 64 |
2798 @as(u80, rhs_extra.lo_hi) << 32 | rhs_extra.lo_lo;
2799 }
2800 };
2801 const gop = self.constant_map.getOrPutAssumeCapacityAdapted(val, Adapter{ .builder = self });
2802 if (!gop.found_existing) {
2803 gop.key_ptr.* = {};
2804 gop.value_ptr.* = {};
2805 self.constant_items.appendAssumeCapacity(.{
2806 .tag = .x86_fp80,
2807 .data = self.addConstantExtraAssumeCapacity(Constant.Fp80{
2808 .lo_lo = @truncate(@as(u80, @bitCast(val))),
2809 .lo_hi = @truncate(@as(u80, @bitCast(val)) >> 32),
2810 .hi = @intCast(@as(u80, @bitCast(val)) >> 64),
2811 }),
2812 });
2813 if (self.useLibLlvm()) {
2814 const llvm_limbs = [_]u64{
2815 @truncate(@as(u80, @bitCast(val))),
2816 @intCast(@as(u80, @bitCast(val)) >> 64),
2817 };
2818 self.llvm_constants.appendAssumeCapacity(
2819 Type.i80.toLlvm(self)
2820 .constIntOfArbitraryPrecision(@intCast(llvm_limbs.len), &llvm_limbs)
2821 .constBitCast(Type.x86_fp80.toLlvm(self)),
2822 );
2823 }
2824 }
2825 return @enumFromInt(gop.index);
2826}
2827
2828fn ppc_fp128ConstAssumeCapacity(self: *Builder, val: [2]f64) Constant {
2829 const Adapter = struct {
2830 builder: *const Builder,
2831 pub fn hash(_: @This(), key: [2]f64) u32 {
2832 return @truncate(std.hash.Wyhash.hash(
2833 comptime std.hash.uint32(@intFromEnum(Constant.Tag.ppc_fp128)),
2834 std.mem.asBytes(&key),
2835 ));
2836 }
2837 pub fn eql(ctx: @This(), lhs_key: [2]f64, _: void, rhs_index: usize) bool {
2838 if (ctx.builder.constant_items.items(.tag)[rhs_index] != .ppc_fp128) return false;
2839 const rhs_data = ctx.builder.constant_items.items(.data)[rhs_index];
2840 const rhs_extra = ctx.builder.constantExtraData(Constant.Fp128, rhs_data);
2841 return @as(u64, @bitCast(lhs_key[0])) == @as(u64, rhs_extra.lo_hi) << 32 | rhs_extra.lo_lo and
2842 @as(u64, @bitCast(lhs_key[1])) == @as(u64, rhs_extra.hi_hi) << 32 | rhs_extra.hi_lo;
2843 }
2844 };
2845 const gop = self.constant_map.getOrPutAssumeCapacityAdapted(val, Adapter{ .builder = self });
2846 if (!gop.found_existing) {
2847 gop.key_ptr.* = {};
2848 gop.value_ptr.* = {};
2849 self.constant_items.appendAssumeCapacity(.{
2850 .tag = .ppc_fp128,
2851 .data = self.addConstantExtraAssumeCapacity(Constant.Fp128{
2852 .lo_lo = @truncate(@as(u64, @bitCast(val[0]))),
2853 .lo_hi = @intCast(@as(u64, @bitCast(val[0])) >> 32),
2854 .hi_lo = @truncate(@as(u64, @bitCast(val[1]))),
2855 .hi_hi = @intCast(@as(u64, @bitCast(val[1])) >> 32),
2856 }),
2857 });
2858 if (self.useLibLlvm()) {
2859 const llvm_limbs: *const [2]u64 = @ptrCast(&val);
2860 self.llvm_constants.appendAssumeCapacity(
2861 Type.i128.toLlvm(self)
2862 .constIntOfArbitraryPrecision(@intCast(llvm_limbs.len), llvm_limbs)
2863 .constBitCast(Type.ppc_fp128.toLlvm(self)),
2864 );
2865 }
2866 }
2867 return @enumFromInt(gop.index);
2868}
2869
2870fn nullConstAssumeCapacity(self: *Builder, ty: Type) Constant {
2871 assert(self.type_items.items[@intFromEnum(ty)].tag == .pointer);
2872 const result = self.getOrPutConstantNoExtraAssumeCapacity(
2873 .{ .tag = .null, .data = @intFromEnum(ty) },
2874 );
2875 if (self.useLibLlvm() and result.new)
2876 self.llvm_constants.appendAssumeCapacity(ty.toLlvm(self).constNull());
2877 return result.constant;
2878}
2879
2880fn noneConstAssumeCapacity(self: *Builder, ty: Type) Constant {
2881 assert(ty == .token);
2882 const result = self.getOrPutConstantNoExtraAssumeCapacity(
2883 .{ .tag = .none, .data = @intFromEnum(ty) },
2884 );
2885 if (self.useLibLlvm() and result.new)
2886 self.llvm_constants.appendAssumeCapacity(ty.toLlvm(self).constNull());
2887 return result.constant;
2888}
2889
2890fn structConstAssumeCapacity(
2891 self: *Builder,
2892 ty: Type,
2893 vals: []const Constant,
2894) if (build_options.have_llvm) Allocator.Error!Constant else Constant {
2895 const type_item = self.type_items.items[@intFromEnum(ty)];
2896 const extra = self.typeExtraDataTrail(Type.Structure, switch (type_item.tag) {
2897 .structure, .packed_structure => type_item.data,
2898 .named_structure => data: {
2899 const body_ty = self.typeExtraData(Type.NamedStructure, type_item.data).body;
2900 const body_item = self.type_items.items[@intFromEnum(body_ty)];
2901 switch (body_item.tag) {
2902 .structure, .packed_structure => break :data body_item.data,
2903 else => unreachable,
2904 }
2905 },
2906 else => unreachable,
2907 });
2908 const fields: []const Type =
2909 @ptrCast(self.type_extra.items[extra.end..][0..extra.data.fields_len]);
2910 for (fields, vals) |field, val| assert(field == val.typeOf(self));
2911
2912 for (vals) |val| {
2913 if (!val.isZeroInit(self)) break;
2914 } else return self.zeroInitConstAssumeCapacity(ty);
2915
2916 const tag: Constant.Tag = switch (ty.unnamedTag(self)) {
2917 .structure => .structure,
2918 .packed_structure => .packed_structure,
2919 else => unreachable,
2920 };
2921 const result = self.getOrPutConstantAggregateAssumeCapacity(tag, ty, vals);
2922 if (self.useLibLlvm() and result.new) {
2923 const ExpectedContents = [expected_fields_len]*llvm.Value;
2924 var stack align(@alignOf(ExpectedContents)) =
2925 std.heap.stackFallback(@sizeOf(ExpectedContents), self.gpa);
2926 const allocator = stack.get();
2927
2928 const llvm_vals = try allocator.alloc(*llvm.Value, vals.len);
2929 defer allocator.free(llvm_vals);
2930 for (llvm_vals, vals) |*llvm_val, val| llvm_val.* = val.toLlvm(self);
2931
2932 self.llvm_constants.appendAssumeCapacity(
2933 ty.toLlvm(self).constNamedStruct(llvm_vals.ptr, @intCast(llvm_vals.len)),
2934 );
2935 }
2936 return result.constant;
2937}
2938
2939fn arrayConstAssumeCapacity(
2940 self: *Builder,
2941 ty: Type,
2942 vals: []const Constant,
2943) if (build_options.have_llvm) Allocator.Error!Constant else Constant {
2944 const type_item = self.type_items.items[@intFromEnum(ty)];
2945 const type_extra: struct { len: u64, child: Type } = switch (type_item.tag) {
2946 .small_array => extra: {
2947 const extra = self.typeExtraData(Type.Vector, type_item.data);
2948 break :extra .{ .len = extra.len, .child = extra.child };
2949 },
2950 .array => extra: {
2951 const extra = self.typeExtraData(Type.Array, type_item.data);
2952 break :extra .{ .len = extra.len(), .child = extra.child };
2953 },
2954 else => unreachable,
2955 };
2956 assert(type_extra.len == vals.len);
2957 for (vals) |val| assert(type_extra.child == val.typeOf(self));
2958
2959 for (vals) |val| {
2960 if (!val.isZeroInit(self)) break;
2961 } else return self.zeroInitConstAssumeCapacity(ty);
2962
2963 const result = self.getOrPutConstantAggregateAssumeCapacity(.array, ty, vals);
2964 if (self.useLibLlvm() and result.new) {
2965 const ExpectedContents = [expected_fields_len]*llvm.Value;
2966 var stack align(@alignOf(ExpectedContents)) =
2967 std.heap.stackFallback(@sizeOf(ExpectedContents), self.gpa);
2968 const allocator = stack.get();
2969
2970 const llvm_vals = try allocator.alloc(*llvm.Value, vals.len);
2971 defer allocator.free(llvm_vals);
2972 for (llvm_vals, vals) |*llvm_val, val| llvm_val.* = val.toLlvm(self);
2973
2974 self.llvm_constants.appendAssumeCapacity(
2975 type_extra.child.toLlvm(self).constArray(llvm_vals.ptr, @intCast(llvm_vals.len)),
2976 );
2977 }
2978 return result.constant;
2979}
2980
2981fn stringConstAssumeCapacity(self: *Builder, val: String) Constant {
2982 const slice = val.toSlice(self).?;
2983 const ty = self.arrayTypeAssumeCapacity(slice.len, .i8);
2984 if (std.mem.allEqual(u8, slice, 0)) return self.zeroInitConstAssumeCapacity(ty);
2985 const result = self.getOrPutConstantNoExtraAssumeCapacity(
2986 .{ .tag = .string, .data = @intFromEnum(val) },
2987 );
2988 if (self.useLibLlvm() and result.new) self.llvm_constants.appendAssumeCapacity(
2989 self.llvm_context.constString(slice.ptr, @intCast(slice.len), .True),
2990 );
2991 return result.constant;
2992}
2993
2994fn stringNullConstAssumeCapacity(self: *Builder, val: String) Constant {
2995 const slice = val.toSlice(self).?;
2996 const ty = self.arrayTypeAssumeCapacity(slice.len + 1, .i8);
2997 if (std.mem.allEqual(u8, slice, 0)) return self.zeroInitConstAssumeCapacity(ty);
2998 const result = self.getOrPutConstantNoExtraAssumeCapacity(
2999 .{ .tag = .string_null, .data = @intFromEnum(val) },
3000 );
3001 if (self.useLibLlvm() and result.new) self.llvm_constants.appendAssumeCapacity(
3002 self.llvm_context.constString(slice.ptr, @intCast(slice.len + 1), .True),
3003 );
3004 return result.constant;
3005}
3006
3007fn vectorConstAssumeCapacity(
3008 self: *Builder,
3009 ty: Type,
3010 vals: []const Constant,
3011) if (build_options.have_llvm) Allocator.Error!Constant else Constant {
3012 if (std.debug.runtime_safety) {
3013 const type_item = self.type_items.items[@intFromEnum(ty)];
3014 assert(type_item.tag == .vector);
3015 const extra = self.typeExtraData(Type.Vector, type_item.data);
3016 assert(extra.len == vals.len);
3017 for (vals) |val| assert(extra.child == val.typeOf(self));
3018 }
3019
3020 for (vals) |val| {
3021 if (!val.isZeroInit(self)) break;
3022 } else return self.zeroInitConstAssumeCapacity(ty);
3023
3024 const result = self.getOrPutConstantAggregateAssumeCapacity(.vector, ty, vals);
3025 if (self.useLibLlvm() and result.new) {
3026 const ExpectedContents = [expected_fields_len]*llvm.Value;
3027 var stack align(@alignOf(ExpectedContents)) =
3028 std.heap.stackFallback(@sizeOf(ExpectedContents), self.gpa);
3029 const allocator = stack.get();
3030
3031 const llvm_vals = try allocator.alloc(*llvm.Value, vals.len);
3032 defer allocator.free(llvm_vals);
3033 for (llvm_vals, vals) |*llvm_val, val| llvm_val.* = val.toLlvm(self);
3034
3035 self.llvm_constants.appendAssumeCapacity(
3036 llvm.constVector(llvm_vals.ptr, @intCast(llvm_vals.len)),
3037 );
3038 }
3039 return result.constant;
3040}
3041
3042fn zeroInitConstAssumeCapacity(self: *Builder, ty: Type) Constant {
3043 switch (self.type_items.items[@intFromEnum(ty)].tag) {
3044 .simple,
3045 .function,
3046 .vararg_function,
3047 .integer,
3048 .pointer,
3049 => unreachable,
3050 .target,
3051 .vector,
3052 .scalable_vector,
3053 .small_array,
3054 .array,
3055 .structure,
3056 .packed_structure,
3057 .named_structure,
3058 => {},
3059 }
3060 const result = self.getOrPutConstantNoExtraAssumeCapacity(
3061 .{ .tag = .zeroinitializer, .data = @intFromEnum(ty) },
3062 );
3063 if (self.useLibLlvm() and result.new)
3064 self.llvm_constants.appendAssumeCapacity(ty.toLlvm(self).constNull());
3065 return result.constant;
3066}
3067
3068fn undefConstAssumeCapacity(self: *Builder, ty: Type) Constant {
3069 switch (self.type_items.items[@intFromEnum(ty)].tag) {
3070 .simple => switch (ty) {
3071 .void, .label => unreachable,
3072 else => {},
3073 },
3074 .function, .vararg_function => unreachable,
3075 else => {},
3076 }
3077 const result = self.getOrPutConstantNoExtraAssumeCapacity(
3078 .{ .tag = .undef, .data = @intFromEnum(ty) },
3079 );
3080 if (self.useLibLlvm() and result.new)
3081 self.llvm_constants.appendAssumeCapacity(ty.toLlvm(self).getUndef());
3082 return result.constant;
3083}
3084
3085fn poisonConstAssumeCapacity(self: *Builder, ty: Type) Constant {
3086 switch (self.type_items.items[@intFromEnum(ty)].tag) {
3087 .simple => switch (ty) {
3088 .void, .label => unreachable,
3089 else => {},
3090 },
3091 .function, .vararg_function => unreachable,
3092 else => {},
3093 }
3094 const result = self.getOrPutConstantNoExtraAssumeCapacity(
3095 .{ .tag = .poison, .data = @intFromEnum(ty) },
3096 );
3097 if (self.useLibLlvm() and result.new)
3098 self.llvm_constants.appendAssumeCapacity(ty.toLlvm(self).getUndef());
3099 return result.constant;
3100}
3101
3102fn blockAddrConstAssumeCapacity(
3103 self: *Builder,
3104 function: Function.Index,
3105 block: Function.Block.Index,
3106) Constant {
3107 const Adapter = struct {
3108 builder: *const Builder,
3109 pub fn hash(_: @This(), key: Constant.BlockAddress) u32 {
3110 return @truncate(std.hash.Wyhash.hash(
3111 comptime std.hash.uint32(@intFromEnum(Constant.Tag.blockaddress)),
3112 std.mem.asBytes(&key),
3113 ));
3114 }
3115 pub fn eql(ctx: @This(), lhs_key: Constant.BlockAddress, _: void, rhs_index: usize) bool {
3116 if (ctx.builder.constant_items.items(.tag)[rhs_index] != .blockaddress) return false;
3117 const rhs_data = ctx.builder.constant_items.items(.data)[rhs_index];
3118 const rhs_extra = ctx.builder.constantExtraData(Constant.BlockAddress, rhs_data);
3119 return std.meta.eql(lhs_key, rhs_extra);
3120 }
3121 };
3122 const data = Constant.BlockAddress{ .function = function, .block = block };
3123 const gop = self.constant_map.getOrPutAssumeCapacityAdapted(data, Adapter{ .builder = self });
3124 if (!gop.found_existing) {
3125 gop.key_ptr.* = {};
3126 gop.value_ptr.* = {};
3127 self.constant_items.appendAssumeCapacity(.{
3128 .tag = .blockaddress,
3129 .data = self.addConstantExtraAssumeCapacity(data),
3130 });
3131 if (self.useLibLlvm()) self.llvm_constants.appendAssumeCapacity(
3132 function.toLlvm(self).blockAddress(block.toValue(self, function).toLlvm(self, function)),
3133 );
3134 }
3135 return @enumFromInt(gop.index);
3136}
3137
3138fn dsoLocalEquivalentConstAssumeCapacity(self: *Builder, function: Function.Index) Constant {
3139 const result = self.getOrPutConstantNoExtraAssumeCapacity(
3140 .{ .tag = .dso_local_equivalent, .data = @intFromEnum(function) },
3141 );
3142 if (self.useLibLlvm() and result.new) self.llvm_constants.appendAssumeCapacity(undefined);
3143 return result.constant;
3144}
3145
3146fn noCfiConstAssumeCapacity(self: *Builder, function: Function.Index) Constant {
3147 const result = self.getOrPutConstantNoExtraAssumeCapacity(
3148 .{ .tag = .no_cfi, .data = @intFromEnum(function) },
3149 );
3150 if (self.useLibLlvm() and result.new) self.llvm_constants.appendAssumeCapacity(undefined);
3151 return result.constant;
3152}
3153
3154fn convConstAssumeCapacity(
3155 self: *Builder,
3156 signedness: Constant.Cast.Signedness,
3157 arg: Constant,
3158 ty: Type,
3159) Constant {
3160 const arg_ty = arg.typeOf(self);
3161 if (arg_ty == ty) return arg;
3162 return self.castConstAssumeCapacity(switch (arg_ty.scalarTag(self)) {
3163 .simple => switch (ty.scalarTag(self)) {
3164 .simple => switch (std.math.order(arg_ty.scalarBits(self), ty.scalarBits(self))) {
3165 .lt => .fpext,
3166 .eq => unreachable,
3167 .gt => .fptrunc,
3168 },
3169 .integer => switch (signedness) {
3170 .unsigned => .fptoui,
3171 .signed => .fptosi,
3172 .unneeded => unreachable,
3173 },
3174 else => unreachable,
3175 },
3176 .integer => switch (ty.tag(self)) {
3177 .simple => switch (signedness) {
3178 .unsigned => .uitofp,
3179 .signed => .sitofp,
3180 .unneeded => unreachable,
3181 },
3182 .integer => switch (std.math.order(arg_ty.scalarBits(self), ty.scalarBits(self))) {
3183 .lt => switch (signedness) {
3184 .unsigned => .zext,
3185 .signed => .sext,
3186 .unneeded => unreachable,
3187 },
3188 .eq => unreachable,
3189 .gt => .trunc,
3190 },
3191 .pointer => .inttoptr,
3192 else => unreachable,
3193 },
3194 .pointer => switch (ty.tag(self)) {
3195 .integer => .ptrtoint,
3196 .pointer => .addrspacecast,
3197 else => unreachable,
3198 },
3199 else => unreachable,
3200 }, arg, ty);
3201}
3202
3203fn castConstAssumeCapacity(self: *Builder, tag: Constant.Tag, arg: Constant, ty: Type) Constant {
3204 const Key = struct { tag: Constant.Tag, cast: Constant.Cast };
3205 const Adapter = struct {
3206 builder: *const Builder,
3207 pub fn hash(_: @This(), key: Key) u32 {
3208 return @truncate(std.hash.Wyhash.hash(
3209 std.hash.uint32(@intFromEnum(key.tag)),
3210 std.mem.asBytes(&key.cast),
3211 ));
3212 }
3213 pub fn eql(ctx: @This(), lhs_key: Key, _: void, rhs_index: usize) bool {
3214 if (lhs_key.tag != ctx.builder.constant_items.items(.tag)[rhs_index]) return false;
3215 const rhs_data = ctx.builder.constant_items.items(.data)[rhs_index];
3216 const rhs_extra = ctx.builder.constantExtraData(Constant.Cast, rhs_data);
3217 return std.meta.eql(lhs_key.cast, rhs_extra);
3218 }
3219 };
3220 const data = Key{ .tag = tag, .cast = .{ .arg = arg, .type = ty } };
3221 const gop = self.constant_map.getOrPutAssumeCapacityAdapted(data, Adapter{ .builder = self });
3222 if (!gop.found_existing) {
3223 gop.key_ptr.* = {};
3224 gop.value_ptr.* = {};
3225 self.constant_items.appendAssumeCapacity(.{
3226 .tag = tag,
3227 .data = self.addConstantExtraAssumeCapacity(data.cast),
3228 });
3229 if (self.useLibLlvm()) self.llvm_constants.appendAssumeCapacity(switch (tag) {
3230 .trunc => &llvm.Value.constTrunc,
3231 .zext => &llvm.Value.constZExt,
3232 .sext => &llvm.Value.constSExt,
3233 .fptrunc => &llvm.Value.constFPTrunc,
3234 .fpext => &llvm.Value.constFPExt,
3235 .fptoui => &llvm.Value.constFPToUI,
3236 .fptosi => &llvm.Value.constFPToSI,
3237 .uitofp => &llvm.Value.constUIToFP,
3238 .sitofp => &llvm.Value.constSIToFP,
3239 .ptrtoint => &llvm.Value.constPtrToInt,
3240 .inttoptr => &llvm.Value.constIntToPtr,
3241 .bitcast => &llvm.Value.constBitCast,
3242 else => unreachable,
3243 }(arg.toLlvm(self), ty.toLlvm(self)));
3244 }
3245 return @enumFromInt(gop.index);
3246}
3247
3248fn gepConstAssumeCapacity(
3249 self: *Builder,
3250 comptime kind: Constant.GetElementPtr.Kind,
3251 ty: Type,
3252 base: Constant,
3253 indices: []const Constant,
3254) if (build_options.have_llvm) Allocator.Error!Constant else Constant {
3255 const tag: Constant.Tag = switch (kind) {
3256 .normal => .getelementptr,
3257 .inbounds => .@"getelementptr inbounds",
3258 };
3259 const base_ty = base.typeOf(self);
3260 const base_is_vector = base_ty.isVector(self);
3261
3262 const VectorInfo = struct {
3263 kind: Type.Vector.Kind,
3264 len: u32,
3265
3266 fn init(vector_ty: Type, builder: *const Builder) @This() {
3267 return .{ .kind = vector_ty.vectorKind(builder), .len = vector_ty.vectorLen(builder) };
3268 }
3269 };
3270 var vector_info: ?VectorInfo = if (base_is_vector) VectorInfo.init(base_ty, self) else null;
3271 for (indices) |index| {
3272 const index_ty = index.typeOf(self);
3273 switch (index_ty.tag(self)) {
3274 .integer => {},
3275 .vector, .scalable_vector => {
3276 const index_info = VectorInfo.init(index_ty, self);
3277 if (vector_info) |info|
3278 assert(std.meta.eql(info, index_info))
3279 else
3280 vector_info = index_info;
3281 },
3282 else => unreachable,
3283 }
3284 }
3285 if (!base_is_vector) if (vector_info) |info| switch (info.kind) {
3286 inline else => |vector_kind| _ = self.vectorTypeAssumeCapacity(vector_kind, info.len, base_ty),
3287 };
3288
3289 const Key = struct { type: Type, base: Constant, indices: []const Constant };
3290 const Adapter = struct {
3291 builder: *const Builder,
3292 pub fn hash(_: @This(), key: Key) u32 {
3293 var hasher = std.hash.Wyhash.init(comptime std.hash.uint32(@intFromEnum(tag)));
3294 hasher.update(std.mem.asBytes(&key.type));
3295 hasher.update(std.mem.asBytes(&key.base));
3296 hasher.update(std.mem.sliceAsBytes(key.indices));
3297 return @truncate(hasher.final());
3298 }
3299 pub fn eql(ctx: @This(), lhs_key: Key, _: void, rhs_index: usize) bool {
3300 if (ctx.builder.constant_items.items(.tag)[rhs_index] != tag) return false;
3301 const rhs_data = ctx.builder.constant_items.items(.data)[rhs_index];
3302 const rhs_extra = ctx.builder.constantExtraDataTrail(Constant.GetElementPtr, rhs_data);
3303 const rhs_indices: []const Constant = @ptrCast(ctx.builder.constant_extra
3304 .items[rhs_extra.end..][0..rhs_extra.data.indices_len]);
3305 return lhs_key.type == rhs_extra.data.type and lhs_key.base == rhs_extra.data.base and
3306 std.mem.eql(Constant, lhs_key.indices, rhs_indices);
3307 }
3308 };
3309 const data = Key{ .type = ty, .base = base, .indices = indices };
3310 const gop = self.constant_map.getOrPutAssumeCapacityAdapted(data, Adapter{ .builder = self });
3311 if (!gop.found_existing) {
3312 gop.key_ptr.* = {};
3313 gop.value_ptr.* = {};
3314 self.constant_items.appendAssumeCapacity(.{
3315 .tag = tag,
3316 .data = self.addConstantExtraAssumeCapacity(Constant.GetElementPtr{
3317 .type = ty,
3318 .base = base,
3319 .indices_len = @intCast(indices.len),
3320 }),
3321 });
3322 self.constant_extra.appendSliceAssumeCapacity(@ptrCast(indices));
3323 if (self.useLibLlvm()) {
3324 const ExpectedContents = [expected_gep_indices_len]*llvm.Value;
3325 var stack align(@alignOf(ExpectedContents)) =
3326 std.heap.stackFallback(@sizeOf(ExpectedContents), self.gpa);
3327 const allocator = stack.get();
3328
3329 const llvm_indices = try allocator.alloc(*llvm.Value, indices.len);
3330 defer allocator.free(llvm_indices);
3331 for (llvm_indices, indices) |*llvm_index, index| llvm_index.* = index.toLlvm(self);
3332
3333 self.llvm_constants.appendAssumeCapacity(switch (kind) {
3334 .normal => &llvm.Type.constGEP,
3335 .inbounds => &llvm.Type.constInBoundsGEP,
3336 }(ty.toLlvm(self), base.toLlvm(self), llvm_indices.ptr, @intCast(indices.len)));
3337 }
3338 }
3339 return @enumFromInt(gop.index);
3340}
3341
3342fn binConstAssumeCapacity(
3343 self: *Builder,
3344 tag: Constant.Tag,
3345 lhs: Constant,
3346 rhs: Constant,
3347) Constant {
3348 switch (tag) {
3349 .add, .sub, .mul, .shl, .lshr, .ashr, .@"and", .@"or", .xor => {},
3350 else => unreachable,
3351 }
3352 const Key = struct { tag: Constant.Tag, bin: Constant.Binary };
3353 const Adapter = struct {
3354 builder: *const Builder,
3355 pub fn hash(_: @This(), key: Key) u32 {
3356 return @truncate(std.hash.Wyhash.hash(
3357 std.hash.uint32(@intFromEnum(key.tag)),
3358 std.mem.asBytes(&key.bin),
3359 ));
3360 }
3361 pub fn eql(ctx: @This(), lhs_key: Key, _: void, rhs_index: usize) bool {
3362 if (lhs_key.tag != ctx.builder.constant_items.items(.tag)[rhs_index]) return false;
3363 const rhs_data = ctx.builder.constant_items.items(.data)[rhs_index];
3364 const rhs_extra = ctx.builder.constantExtraData(Constant.Binary, rhs_data);
3365 return std.meta.eql(lhs_key.bin, rhs_extra);
3366 }
3367 };
3368 const data = Key{ .tag = tag, .bin = .{ .lhs = lhs, .rhs = rhs } };
3369 const gop = self.constant_map.getOrPutAssumeCapacityAdapted(data, Adapter{ .builder = self });
3370 if (!gop.found_existing) {
3371 gop.key_ptr.* = {};
3372 gop.value_ptr.* = {};
3373 self.constant_items.appendAssumeCapacity(.{
3374 .tag = tag,
3375 .data = self.addConstantExtraAssumeCapacity(data.bin),
3376 });
3377 if (self.useLibLlvm()) self.llvm_constants.appendAssumeCapacity(switch (tag) {
3378 .add => &llvm.Value.constAdd,
3379 .sub => &llvm.Value.constSub,
3380 .mul => &llvm.Value.constMul,
3381 .shl => &llvm.Value.constShl,
3382 .lshr => &llvm.Value.constLShr,
3383 .ashr => &llvm.Value.constAShr,
3384 .@"and" => &llvm.Value.constAnd,
3385 .@"or" => &llvm.Value.constOr,
3386 .xor => &llvm.Value.constXor,
3387 else => unreachable,
3388 }(lhs.toLlvm(self), rhs.toLlvm(self)));
3389 }
3390 return @enumFromInt(gop.index);
3391}
3392
3393fn ensureUnusedConstantCapacity(
3394 self: *Builder,
3395 count: usize,
3396 comptime Extra: ?type,
3397 trail_len: usize,
3398) Allocator.Error!void {
3399 try self.constant_map.ensureUnusedCapacity(self.gpa, count);
3400 try self.constant_items.ensureUnusedCapacity(self.gpa, count);
3401 if (Extra) |E| try self.constant_extra.ensureUnusedCapacity(
3402 self.gpa,
3403 count * (@typeInfo(E).Struct.fields.len + trail_len),
3404 ) else assert(trail_len == 0);
3405 if (self.useLibLlvm()) try self.llvm_constants.ensureUnusedCapacity(self.gpa, count);
3406}
3407
3408fn getOrPutConstantNoExtraAssumeCapacity(
3409 self: *Builder,
3410 item: Constant.Item,
3411) struct { new: bool, constant: Constant } {
3412 const Adapter = struct {
3413 builder: *const Builder,
3414 pub fn hash(_: @This(), key: Constant.Item) u32 {
3415 return @truncate(std.hash.Wyhash.hash(
3416 std.hash.uint32(@intFromEnum(key.tag)),
3417 std.mem.asBytes(&key.data),
3418 ));
3419 }
3420 pub fn eql(ctx: @This(), lhs_key: Constant.Item, _: void, rhs_index: usize) bool {
3421 return std.meta.eql(lhs_key, ctx.builder.constant_items.get(rhs_index));
3422 }
3423 };
3424 const gop = self.constant_map.getOrPutAssumeCapacityAdapted(item, Adapter{ .builder = self });
3425 if (!gop.found_existing) {
3426 gop.key_ptr.* = {};
3427 gop.value_ptr.* = {};
3428 self.constant_items.appendAssumeCapacity(item);
3429 }
3430 return .{ .new = !gop.found_existing, .constant = @enumFromInt(gop.index) };
3431}
3432
3433fn getOrPutConstantAggregateAssumeCapacity(
3434 self: *Builder,
3435 tag: Constant.Tag,
3436 ty: Type,
3437 vals: []const Constant,
3438) struct { new: bool, constant: Constant } {
3439 switch (tag) {
3440 .structure, .packed_structure, .array, .vector => {},
3441 else => unreachable,
3442 }
3443 const Key = struct { tag: Constant.Tag, type: Type, vals: []const Constant };
3444 const Adapter = struct {
3445 builder: *const Builder,
3446 pub fn hash(_: @This(), key: Key) u32 {
3447 var hasher = std.hash.Wyhash.init(std.hash.uint32(@intFromEnum(key.tag)));
3448 hasher.update(std.mem.asBytes(&key.type));
3449 hasher.update(std.mem.sliceAsBytes(key.vals));
3450 return @truncate(hasher.final());
3451 }
3452 pub fn eql(ctx: @This(), lhs_key: Key, _: void, rhs_index: usize) bool {
3453 if (lhs_key.tag != ctx.builder.constant_items.items(.tag)[rhs_index]) return false;
3454 const rhs_data = ctx.builder.constant_items.items(.data)[rhs_index];
3455 const rhs_extra = ctx.builder.constantExtraDataTrail(Constant.Aggregate, rhs_data);
3456 if (lhs_key.type != rhs_extra.data.type) return false;
3457 const rhs_vals: []const Constant =
3458 @ptrCast(ctx.builder.constant_extra.items[rhs_extra.end..][0..lhs_key.vals.len]);
3459 return std.mem.eql(Constant, lhs_key.vals, rhs_vals);
3460 }
3461 };
3462 const gop = self.constant_map.getOrPutAssumeCapacityAdapted(
3463 Key{ .tag = tag, .type = ty, .vals = vals },
3464 Adapter{ .builder = self },
3465 );
3466 if (!gop.found_existing) {
3467 gop.key_ptr.* = {};
3468 gop.value_ptr.* = {};
3469 self.constant_items.appendAssumeCapacity(.{
3470 .tag = tag,
3471 .data = self.addConstantExtraAssumeCapacity(Constant.Aggregate{ .type = ty }),
3472 });
3473 self.constant_extra.appendSliceAssumeCapacity(@ptrCast(vals));
3474 }
3475 return .{ .new = !gop.found_existing, .constant = @enumFromInt(gop.index) };
3476}
3477
3478fn addConstantExtraAssumeCapacity(self: *Builder, extra: anytype) Constant.Item.ExtraIndex {
3479 const result: Constant.Item.ExtraIndex = @intCast(self.constant_extra.items.len);
3480 inline for (@typeInfo(@TypeOf(extra)).Struct.fields) |field| {
3481 const value = @field(extra, field.name);
3482 self.constant_extra.appendAssumeCapacity(switch (field.type) {
3483 u32 => value,
3484 Type,
3485 Constant,
3486 Function.Index,
3487 Function.Block.Index,
3488 => @intFromEnum(value),
3489 else => @compileError("bad field type: " ++ @typeName(field.type)),
3490 });
3491 }
3492 return result;
3493}
3494
3495fn constantExtraDataTrail(
3496 self: *const Builder,
3497 comptime T: type,
3498 index: Constant.Item.ExtraIndex,
3499) struct { data: T, end: Constant.Item.ExtraIndex } {
3500 var result: T = undefined;
3501 const fields = @typeInfo(T).Struct.fields;
3502 inline for (fields, self.constant_extra.items[index..][0..fields.len]) |field, data|
3503 @field(result, field.name) = switch (field.type) {
3504 u32 => data,
3505 Type,
3506 Constant,
3507 Function.Index,
3508 Function.Block.Index,
3509 => @enumFromInt(data),
3510 else => @compileError("bad field type: " ++ @typeName(field.type)),
3511 };
3512 return .{ .data = result, .end = index + @as(Constant.Item.ExtraIndex, @intCast(fields.len)) };
3513}
3514
3515fn constantExtraData(self: *const Builder, comptime T: type, index: Constant.Item.ExtraIndex) T {
3516 return self.constantExtraDataTrail(T, index).data;
3517}
3518
1830inline fn useLibLlvm(self: *const Builder) bool {3519inline fn useLibLlvm(self: *const Builder) bool {
1831 return build_options.have_llvm and self.use_lib_llvm;3520 return build_options.have_llvm and self.use_lib_llvm;
1832}3521}
src/codegen/llvm/bindings.zig+64-11
...@@ -168,23 +168,41 @@ pub const Value = opaque {...@@ -168,23 +168,41 @@ pub const Value = opaque {
168 pub const setAliasee = LLVMAliasSetAliasee;168 pub const setAliasee = LLVMAliasSetAliasee;
169 extern fn LLVMAliasSetAliasee(Alias: *Value, Aliasee: *Value) void;169 extern fn LLVMAliasSetAliasee(Alias: *Value, Aliasee: *Value) void;
170170
171 pub const constBitCast = LLVMConstBitCast;171 pub const constTrunc = LLVMConstTrunc;
172 extern fn LLVMConstBitCast(ConstantVal: *Value, ToType: *Type) *Value;172 extern fn LLVMConstTrunc(ConstantVal: *Value, ToType: *Type) *Value;
173173
174 pub const constIntToPtr = LLVMConstIntToPtr;174 pub const constSExt = LLVMConstSExt;
175 extern fn LLVMConstIntToPtr(ConstantVal: *Value, ToType: *Type) *Value;175 extern fn LLVMConstSExt(ConstantVal: *Value, ToType: *Type) *Value;
176
177 pub const constZExt = LLVMConstZExt;
178 extern fn LLVMConstZExt(ConstantVal: *Value, ToType: *Type) *Value;
179
180 pub const constFPTrunc = LLVMConstFPTrunc;
181 extern fn LLVMConstFPTrunc(ConstantVal: *Value, ToType: *Type) *Value;
182
183 pub const constFPExt = LLVMConstFPExt;
184 extern fn LLVMConstFPExt(ConstantVal: *Value, ToType: *Type) *Value;
185
186 pub const constUIToFP = LLVMConstUIToFP;
187 extern fn LLVMConstUIToFP(ConstantVal: *Value, ToType: *Type) *Value;
188
189 pub const constSIToFP = LLVMConstSIToFP;
190 extern fn LLVMConstSIToFP(ConstantVal: *Value, ToType: *Type) *Value;
191
192 pub const constFPToUI = LLVMConstFPToUI;
193 extern fn LLVMConstFPToUI(ConstantVal: *Value, ToType: *Type) *Value;
194
195 pub const constFPToSI = LLVMConstFPToSI;
196 extern fn LLVMConstFPToSI(ConstantVal: *Value, ToType: *Type) *Value;
176197
177 pub const constPtrToInt = LLVMConstPtrToInt;198 pub const constPtrToInt = LLVMConstPtrToInt;
178 extern fn LLVMConstPtrToInt(ConstantVal: *Value, ToType: *Type) *Value;199 extern fn LLVMConstPtrToInt(ConstantVal: *Value, ToType: *Type) *Value;
179200
180 pub const constShl = LLVMConstShl;201 pub const constIntToPtr = LLVMConstIntToPtr;
181 extern fn LLVMConstShl(LHSConstant: *Value, RHSConstant: *Value) *Value;202 extern fn LLVMConstIntToPtr(ConstantVal: *Value, ToType: *Type) *Value;
182
183 pub const constOr = LLVMConstOr;
184 extern fn LLVMConstOr(LHSConstant: *Value, RHSConstant: *Value) *Value;
185203
186 pub const constZExt = LLVMConstZExt;204 pub const constBitCast = LLVMConstBitCast;
187 extern fn LLVMConstZExt(ConstantVal: *Value, ToType: *Type) *Value;205 extern fn LLVMConstBitCast(ConstantVal: *Value, ToType: *Type) *Value;
188206
189 pub const constZExtOrBitCast = LLVMConstZExtOrBitCast;207 pub const constZExtOrBitCast = LLVMConstZExtOrBitCast;
190 extern fn LLVMConstZExtOrBitCast(ConstantVal: *Value, ToType: *Type) *Value;208 extern fn LLVMConstZExtOrBitCast(ConstantVal: *Value, ToType: *Type) *Value;
...@@ -195,6 +213,30 @@ pub const Value = opaque {...@@ -195,6 +213,30 @@ pub const Value = opaque {
195 pub const constAdd = LLVMConstAdd;213 pub const constAdd = LLVMConstAdd;
196 extern fn LLVMConstAdd(LHSConstant: *Value, RHSConstant: *Value) *Value;214 extern fn LLVMConstAdd(LHSConstant: *Value, RHSConstant: *Value) *Value;
197215
216 pub const constSub = LLVMConstSub;
217 extern fn LLVMConstSub(LHSConstant: *Value, RHSConstant: *Value) *Value;
218
219 pub const constMul = LLVMConstMul;
220 extern fn LLVMConstMul(LHSConstant: *Value, RHSConstant: *Value) *Value;
221
222 pub const constAnd = LLVMConstAnd;
223 extern fn LLVMConstAnd(LHSConstant: *Value, RHSConstant: *Value) *Value;
224
225 pub const constOr = LLVMConstOr;
226 extern fn LLVMConstOr(LHSConstant: *Value, RHSConstant: *Value) *Value;
227
228 pub const constXor = LLVMConstXor;
229 extern fn LLVMConstXor(LHSConstant: *Value, RHSConstant: *Value) *Value;
230
231 pub const constShl = LLVMConstShl;
232 extern fn LLVMConstShl(LHSConstant: *Value, RHSConstant: *Value) *Value;
233
234 pub const constLShr = LLVMConstLShr;
235 extern fn LLVMConstLShr(LHSConstant: *Value, RHSConstant: *Value) *Value;
236
237 pub const constAShr = LLVMConstAShr;
238 extern fn LLVMConstAShr(LHSConstant: *Value, RHSConstant: *Value) *Value;
239
198 pub const constAddrSpaceCast = LLVMConstAddrSpaceCast;240 pub const constAddrSpaceCast = LLVMConstAddrSpaceCast;
199 extern fn LLVMConstAddrSpaceCast(ConstantVal: *Value, ToType: *Type) *Value;241 extern fn LLVMConstAddrSpaceCast(ConstantVal: *Value, ToType: *Type) *Value;
200242
...@@ -281,6 +323,9 @@ pub const Value = opaque {...@@ -281,6 +323,9 @@ pub const Value = opaque {
281 pub const attachMetaData = ZigLLVMAttachMetaData;323 pub const attachMetaData = ZigLLVMAttachMetaData;
282 extern fn ZigLLVMAttachMetaData(GlobalVar: *Value, DIG: *DIGlobalVariableExpression) void;324 extern fn ZigLLVMAttachMetaData(GlobalVar: *Value, DIG: *DIGlobalVariableExpression) void;
283325
326 pub const blockAddress = LLVMBlockAddress;
327 extern fn LLVMBlockAddress(F: *Value, BB: *BasicBlock) *Value;
328
284 pub const dump = LLVMDumpValue;329 pub const dump = LLVMDumpValue;
285 extern fn LLVMDumpValue(Val: *Value) void;330 extern fn LLVMDumpValue(Val: *Value) void;
286};331};
...@@ -349,6 +394,14 @@ pub const Type = opaque {...@@ -349,6 +394,14 @@ pub const Type = opaque {
349 pub const isSized = LLVMTypeIsSized;394 pub const isSized = LLVMTypeIsSized;
350 extern fn LLVMTypeIsSized(Ty: *Type) Bool;395 extern fn LLVMTypeIsSized(Ty: *Type) Bool;
351396
397 pub const constGEP = LLVMConstGEP2;
398 extern fn LLVMConstGEP2(
399 Ty: *Type,
400 ConstantVal: *Value,
401 ConstantIndices: [*]const *Value,
402 NumIndices: c_uint,
403 ) *Value;
404
352 pub const constInBoundsGEP = LLVMConstInBoundsGEP2;405 pub const constInBoundsGEP = LLVMConstInBoundsGEP2;
353 extern fn LLVMConstInBoundsGEP2(406 extern fn LLVMConstInBoundsGEP2(
354 Ty: *Type,407 Ty: *Type,