authorgravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2023-07-11 23:02:18-04:00
committergravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2023-07-19 23:38:40-04:00
log8fde3a8f04e393b05879aff7afb9b09aadb4f2e1
tree2628676ca535e6d436b012419809fb5d36103475
parent1f8407c356b5cdc9eca0f2403a85d863744cf279

llvm: finish converting constants


2 files changed, 333 insertions(+), 255 deletions(-)

src/codegen/llvm.zig+159-200
...@@ -8,7 +8,10 @@ const native_endian = builtin.cpu.arch.endian();...@@ -8,7 +8,10 @@ const native_endian = builtin.cpu.arch.endian();
8const DW = std.dwarf;8const DW = std.dwarf;
99
10const Builder = @import("llvm/Builder.zig");10const Builder = @import("llvm/Builder.zig");
11const llvm = @import("llvm/bindings.zig");11const llvm = if (build_options.have_llvm)
12 @import("llvm/bindings.zig")
13else
14 @compileError("LLVM unavailable");
12const link = @import("../link.zig");15const link = @import("../link.zig");
13const Compilation = @import("../Compilation.zig");16const Compilation = @import("../Compilation.zig");
14const build_options = @import("build_options");17const build_options = @import("build_options");
...@@ -577,7 +580,7 @@ pub const Object = struct {...@@ -577,7 +580,7 @@ pub const Object = struct {
577 extern_collisions: std.AutoArrayHashMapUnmanaged(Module.Decl.Index, void),580 extern_collisions: std.AutoArrayHashMapUnmanaged(Module.Decl.Index, void),
578581
579 /// Memoizes a null `?usize` value.582 /// Memoizes a null `?usize` value.
580 null_opt_addr: ?*llvm.Value,583 null_opt_usize: Builder.Constant,
581584
582 pub const TypeMap = std.AutoHashMapUnmanaged(InternPool.Index, Builder.Type);585 pub const TypeMap = std.AutoHashMapUnmanaged(InternPool.Index, Builder.Type);
583586
...@@ -733,7 +736,7 @@ pub const Object = struct {...@@ -733,7 +736,7 @@ pub const Object = struct {
733 .di_type_map = .{},736 .di_type_map = .{},
734 .error_name_table = .none,737 .error_name_table = .none,
735 .extern_collisions = .{},738 .extern_collisions = .{},
736 .null_opt_addr = null,739 .null_opt_usize = .no_init,
737 };740 };
738 }741 }
739742
...@@ -789,31 +792,31 @@ pub const Object = struct {...@@ -789,31 +792,31 @@ pub const Object = struct {
789 const name = try o.builder.string(mod.intern_pool.stringToSlice(name_nts));792 const name = try o.builder.string(mod.intern_pool.stringToSlice(name_nts));
790 const str_init = try o.builder.stringNullConst(name);793 const str_init = try o.builder.stringNullConst(name);
791 const str_ty = str_init.typeOf(&o.builder);794 const str_ty = str_init.typeOf(&o.builder);
792 const str_global = o.llvm_module.addGlobal(str_ty.toLlvm(&o.builder), "");795 const str_llvm_global = o.llvm_module.addGlobal(str_ty.toLlvm(&o.builder), "");
793 str_global.setInitializer(str_init.toLlvm(&o.builder));796 str_llvm_global.setInitializer(str_init.toLlvm(&o.builder));
794 str_global.setLinkage(.Private);797 str_llvm_global.setLinkage(.Private);
795 str_global.setGlobalConstant(.True);798 str_llvm_global.setGlobalConstant(.True);
796 str_global.setUnnamedAddr(.True);799 str_llvm_global.setUnnamedAddr(.True);
797 str_global.setAlignment(1);800 str_llvm_global.setAlignment(1);
798801
799 var global = Builder.Global{802 var str_global = Builder.Global{
800 .linkage = .private,803 .linkage = .private,
801 .unnamed_addr = .unnamed_addr,804 .unnamed_addr = .unnamed_addr,
802 .type = str_ty,805 .type = str_ty,
803 .alignment = comptime Builder.Alignment.fromByteUnits(1),806 .alignment = comptime Builder.Alignment.fromByteUnits(1),
804 .kind = .{ .variable = @enumFromInt(o.builder.variables.items.len) },807 .kind = .{ .variable = @enumFromInt(o.builder.variables.items.len) },
805 };808 };
806 var variable = Builder.Variable{809 var str_variable = Builder.Variable{
807 .global = @enumFromInt(o.builder.globals.count()),810 .global = @enumFromInt(o.builder.globals.count()),
808 .mutability = .constant,811 .mutability = .constant,
809 .init = str_init,812 .init = str_init,
810 };813 };
811 try o.builder.llvm.globals.append(o.gpa, str_global);814 try o.builder.llvm.globals.append(o.gpa, str_llvm_global);
812 const str_global_index = try o.builder.addGlobal(.empty, global);815 const global_index = try o.builder.addGlobal(.empty, str_global);
813 try o.builder.variables.append(o.gpa, variable);816 try o.builder.variables.append(o.gpa, str_variable);
814817
815 llvm_error.* = try o.builder.structConst(llvm_slice_ty, &.{818 llvm_error.* = try o.builder.structConst(llvm_slice_ty, &.{
816 str_global_index.toConst(),819 global_index.toConst(),
817 try o.builder.intConst(llvm_usize_ty, name.toSlice(&o.builder).?.len),820 try o.builder.intConst(llvm_usize_ty, name.toSlice(&o.builder).?.len),
818 });821 });
819 }822 }
...@@ -2684,55 +2687,6 @@ pub const Object = struct {...@@ -2684,55 +2687,6 @@ pub const Object = struct {
2684 return buffer.toOwnedSliceSentinel(0);2687 return buffer.toOwnedSliceSentinel(0);
2685 }2688 }
26862689
2687 fn getNullOptAddr(o: *Object) !*llvm.Value {
2688 if (o.null_opt_addr) |global| return global;
2689
2690 const mod = o.module;
2691 const target = mod.getTarget();
2692 const ty = try mod.intern(.{ .opt_type = .usize_type });
2693
2694 const llvm_init = try o.lowerValue(try mod.intern(.{ .opt = .{
2695 .ty = ty,
2696 .val = .none,
2697 } }));
2698 const llvm_ty = llvm_init.typeOf(&o.builder);
2699 const llvm_wanted_addrspace = toLlvmAddressSpace(.generic, target);
2700 const llvm_actual_addrspace = toLlvmGlobalAddressSpace(.generic, target);
2701 const llvm_alignment = ty.toType().abiAlignment(mod);
2702 const llvm_global = o.llvm_module.addGlobalInAddressSpace(
2703 llvm_ty.toLlvm(&o.builder),
2704 "",
2705 @intFromEnum(llvm_actual_addrspace),
2706 );
2707 llvm_global.setLinkage(.Internal);
2708 llvm_global.setUnnamedAddr(.True);
2709 llvm_global.setAlignment(llvm_alignment);
2710 llvm_global.setInitializer(llvm_init.toLlvm(&o.builder));
2711
2712 var global = Builder.Global{
2713 .linkage = .internal,
2714 .unnamed_addr = .unnamed_addr,
2715 .type = llvm_ty,
2716 .alignment = Builder.Alignment.fromByteUnits(llvm_alignment),
2717 .kind = .{ .variable = @enumFromInt(o.builder.variables.items.len) },
2718 };
2719 var variable = Builder.Variable{
2720 .global = @enumFromInt(o.builder.globals.count()),
2721 .init = llvm_init,
2722 };
2723 try o.builder.llvm.globals.append(o.gpa, llvm_global);
2724 _ = try o.builder.addGlobal(.empty, global);
2725 try o.builder.variables.append(o.gpa, variable);
2726
2727 const addrspace_casted_global = if (llvm_wanted_addrspace != llvm_actual_addrspace)
2728 llvm_global.constAddrSpaceCast((try o.builder.ptrType(llvm_wanted_addrspace)).toLlvm(&o.builder))
2729 else
2730 llvm_global;
2731
2732 o.null_opt_addr = addrspace_casted_global;
2733 return addrspace_casted_global;
2734 }
2735
2736 /// If the llvm function does not exist, create it.2690 /// If the llvm function does not exist, create it.
2737 /// Note that this can be called before the function's semantic analysis has2691 /// Note that this can be called before the function's semantic analysis has
2738 /// completed, so if any attributes rely on that, they must be done in updateFunc, not here.2692 /// completed, so if any attributes rely on that, they must be done in updateFunc, not here.
...@@ -3755,25 +3709,34 @@ pub const Object = struct {...@@ -3755,25 +3709,34 @@ pub const Object = struct {
3755 },3709 },
3756 },3710 },
3757 .vector_type => |vector_type| {3711 .vector_type => |vector_type| {
3758 const ExpectedContents = [Builder.expected_fields_len]Builder.Constant;3712 const vector_ty = try o.lowerType(ty);
3759 var stack align(@max(
3760 @alignOf(std.heap.StackFallbackAllocator(0)),
3761 @alignOf(ExpectedContents),
3762 )) = std.heap.stackFallback(@sizeOf(ExpectedContents), o.gpa);
3763 const allocator = stack.get();
3764 const vals = try allocator.alloc(Builder.Constant, vector_type.len);
3765 defer allocator.free(vals);
3766
3767 switch (aggregate.storage) {3713 switch (aggregate.storage) {
3768 .bytes => |bytes| for (vals, bytes) |*result_val, byte| {3714 .bytes, .elems => {
3769 result_val.* = try o.builder.intConst(.i8, byte);3715 const ExpectedContents = [Builder.expected_fields_len]Builder.Constant;
3770 },3716 var stack align(@max(
3771 .elems => |elems| for (vals, elems) |*result_val, elem| {3717 @alignOf(std.heap.StackFallbackAllocator(0)),
3772 result_val.* = try o.lowerValue(elem);3718 @alignOf(ExpectedContents),
3719 )) = std.heap.stackFallback(@sizeOf(ExpectedContents), o.gpa);
3720 const allocator = stack.get();
3721 const vals = try allocator.alloc(Builder.Constant, vector_type.len);
3722 defer allocator.free(vals);
3723
3724 switch (aggregate.storage) {
3725 .bytes => |bytes| for (vals, bytes) |*result_val, byte| {
3726 result_val.* = try o.builder.intConst(.i8, byte);
3727 },
3728 .elems => |elems| for (vals, elems) |*result_val, elem| {
3729 result_val.* = try o.lowerValue(elem);
3730 },
3731 .repeated_elem => unreachable,
3732 }
3733 return o.builder.vectorConst(vector_ty, vals);
3773 },3734 },
3774 .repeated_elem => |elem| @memset(vals, try o.lowerValue(elem)),3735 .repeated_elem => |elem| return o.builder.splatConst(
3736 vector_ty,
3737 try o.lowerValue(elem),
3738 ),
3775 }3739 }
3776 return o.builder.vectorConst(try o.lowerType(ty), vals);
3777 },3740 },
3778 .anon_struct_type => |tuple| {3741 .anon_struct_type => |tuple| {
3779 const struct_ty = try o.lowerType(ty);3742 const struct_ty = try o.lowerType(ty);
...@@ -4209,14 +4172,11 @@ pub const Object = struct {...@@ -4209,14 +4172,11 @@ pub const Object = struct {
4209 else4172 else
4210 (try o.resolveGlobalDecl(decl_index)).ptrConst(&o.builder).global;4173 (try o.resolveGlobalDecl(decl_index)).ptrConst(&o.builder).global;
42114174
4212 const target = mod.getTarget();4175 const llvm_val = try o.builder.convConst(
4213 const llvm_wanted_addrspace = toLlvmAddressSpace(decl.@"addrspace", target);4176 .unneeded,
4214 const llvm_actual_addrspace = toLlvmGlobalAddressSpace(decl.@"addrspace", target);
4215 const llvm_val = if (llvm_wanted_addrspace != llvm_actual_addrspace) try o.builder.castConst(
4216 .addrspacecast,
4217 llvm_global.toConst(),4177 llvm_global.toConst(),
4218 try o.builder.ptrType(llvm_wanted_addrspace),4178 try o.builder.ptrType(toLlvmAddressSpace(decl.@"addrspace", mod.getTarget())),
4219 ) else llvm_global.toConst();4179 );
42204180
4221 return o.builder.convConst(if (ty.isAbiInt(mod)) switch (ty.intInfo(mod).signedness) {4181 return o.builder.convConst(if (ty.isAbiInt(mod)) switch (ty.intInfo(mod).signedness) {
4222 .signed => .signed,4182 .signed => .signed,
...@@ -4618,15 +4578,15 @@ pub const FuncGen = struct {...@@ -4618,15 +4578,15 @@ pub const FuncGen = struct {
4618 .ty = self.typeOf(inst),4578 .ty = self.typeOf(inst),
4619 .val = (try self.air.value(inst, mod)).?,4579 .val = (try self.air.value(inst, mod)).?,
4620 });4580 });
4621 gop.value_ptr.* = llvm_val;4581 gop.value_ptr.* = llvm_val.toLlvm(&o.builder);
4622 return llvm_val;4582 return gop.value_ptr.*;
4623 }4583 }
46244584
4625 fn resolveValue(self: *FuncGen, tv: TypedValue) !*llvm.Value {4585 fn resolveValue(self: *FuncGen, tv: TypedValue) Error!Builder.Constant {
4626 const o = self.dg.object;4586 const o = self.dg.object;
4627 const mod = o.module;4587 const mod = o.module;
4628 const llvm_val = try o.lowerValue(tv.val.toIntern());4588 const llvm_val = try o.lowerValue(tv.val.toIntern());
4629 if (!isByRef(tv.ty, mod)) return llvm_val.toLlvm(&o.builder);4589 if (!isByRef(tv.ty, mod)) return llvm_val;
46304590
4631 // We have an LLVM value but we need to create a global constant and4591 // We have an LLVM value but we need to create a global constant and
4632 // set the value as its initializer, and then return a pointer to the global.4592 // set the value as its initializer, and then return a pointer to the global.
...@@ -4645,6 +4605,7 @@ pub const FuncGen = struct {...@@ -4645,6 +4605,7 @@ pub const FuncGen = struct {
4645 var global = Builder.Global{4605 var global = Builder.Global{
4646 .linkage = .private,4606 .linkage = .private,
4647 .unnamed_addr = .unnamed_addr,4607 .unnamed_addr = .unnamed_addr,
4608 .addr_space = llvm_actual_addrspace,
4648 .type = llvm_ty,4609 .type = llvm_ty,
4649 .alignment = Builder.Alignment.fromByteUnits(llvm_alignment),4610 .alignment = Builder.Alignment.fromByteUnits(llvm_alignment),
4650 .kind = .{ .variable = @enumFromInt(o.builder.variables.items.len) },4611 .kind = .{ .variable = @enumFromInt(o.builder.variables.items.len) },
...@@ -4655,16 +4616,27 @@ pub const FuncGen = struct {...@@ -4655,16 +4616,27 @@ pub const FuncGen = struct {
4655 .init = llvm_val,4616 .init = llvm_val,
4656 };4617 };
4657 try o.builder.llvm.globals.append(o.gpa, llvm_global);4618 try o.builder.llvm.globals.append(o.gpa, llvm_global);
4658 _ = try o.builder.addGlobal(.empty, global);4619 const global_index = try o.builder.addGlobal(.empty, global);
4659 try o.builder.variables.append(o.gpa, variable);4620 try o.builder.variables.append(o.gpa, variable);
46604621
4661 const addrspace_casted_ptr = if (llvm_actual_addrspace != llvm_wanted_addrspace)4622 return try o.builder.convConst(
4662 llvm_global.constAddrSpaceCast(4623 .unneeded,
4663 (try o.builder.ptrType(llvm_wanted_addrspace)).toLlvm(&o.builder),4624 global_index.toConst(),
4664 )4625 try o.builder.ptrType(llvm_wanted_addrspace),
4665 else4626 );
4666 llvm_global;4627 }
4667 return addrspace_casted_ptr;4628
4629 fn resolveNullOptUsize(self: *FuncGen) Error!Builder.Constant {
4630 const o = self.dg.object;
4631 const mod = o.module;
4632 if (o.null_opt_usize == .no_init) {
4633 const ty = try mod.intern(.{ .opt_type = .usize_type });
4634 o.null_opt_usize = try self.resolveValue(.{
4635 .ty = ty.toType(),
4636 .val = (try mod.intern(.{ .opt = .{ .ty = ty, .val = .none } })).toValue(),
4637 });
4638 }
4639 return o.null_opt_usize;
4668 }4640 }
46694641
4670 fn genBody(self: *FuncGen, body: []const Air.Inst.Index) Error!void {4642 fn genBody(self: *FuncGen, body: []const Air.Inst.Index) Error!void {
...@@ -5243,7 +5215,7 @@ pub const FuncGen = struct {...@@ -5243,7 +5215,7 @@ pub const FuncGen = struct {
5243 const msg_decl = mod.declPtr(msg_decl_index);5215 const msg_decl = mod.declPtr(msg_decl_index);
5244 const msg_len = msg_decl.ty.childType(mod).arrayLen(mod);5216 const msg_len = msg_decl.ty.childType(mod).arrayLen(mod);
5245 const msg_ptr = try o.lowerValue(try msg_decl.internValue(mod));5217 const msg_ptr = try o.lowerValue(try msg_decl.internValue(mod));
5246 const null_opt_addr_global = try o.getNullOptAddr();5218 const null_opt_addr_global = try fg.resolveNullOptUsize();
5247 const target = mod.getTarget();5219 const target = mod.getTarget();
5248 const llvm_usize = try o.lowerType(Type.usize);5220 const llvm_usize = try o.lowerType(Type.usize);
5249 // example:5221 // example:
...@@ -5257,7 +5229,7 @@ pub const FuncGen = struct {...@@ -5257,7 +5229,7 @@ pub const FuncGen = struct {
5257 msg_ptr.toLlvm(&o.builder),5229 msg_ptr.toLlvm(&o.builder),
5258 (try o.builder.intConst(llvm_usize, msg_len)).toLlvm(&o.builder),5230 (try o.builder.intConst(llvm_usize, msg_len)).toLlvm(&o.builder),
5259 (try o.builder.nullConst(.ptr)).toLlvm(&o.builder),5231 (try o.builder.nullConst(.ptr)).toLlvm(&o.builder),
5260 null_opt_addr_global,5232 null_opt_addr_global.toLlvm(&o.builder),
5261 };5233 };
5262 const panic_func = mod.funcInfo(mod.panic_func_index);5234 const panic_func = mod.funcInfo(mod.panic_func_index);
5263 const panic_decl = mod.declPtr(panic_func.owner_decl);5235 const panic_decl = mod.declPtr(panic_func.owner_decl);
...@@ -6872,11 +6844,11 @@ pub const FuncGen = struct {...@@ -6872,11 +6844,11 @@ pub const FuncGen = struct {
6872 const operand = try self.resolveInst(un_op);6844 const operand = try self.resolveInst(un_op);
6873 const operand_ty = self.typeOf(un_op);6845 const operand_ty = self.typeOf(un_op);
6874 const optional_ty = if (operand_is_ptr) operand_ty.childType(mod) else operand_ty;6846 const optional_ty = if (operand_is_ptr) operand_ty.childType(mod) else operand_ty;
6875 const optional_llvm_ty = (try o.lowerType(optional_ty)).toLlvm(&o.builder);6847 const optional_llvm_ty = try o.lowerType(optional_ty);
6876 const payload_ty = optional_ty.optionalChild(mod);6848 const payload_ty = optional_ty.optionalChild(mod);
6877 if (optional_ty.optionalReprIsPayload(mod)) {6849 if (optional_ty.optionalReprIsPayload(mod)) {
6878 const loaded = if (operand_is_ptr)6850 const loaded = if (operand_is_ptr)
6879 self.builder.buildLoad(optional_llvm_ty, operand, "")6851 self.builder.buildLoad(optional_llvm_ty.toLlvm(&o.builder), operand, "")
6880 else6852 else
6881 operand;6853 operand;
6882 if (payload_ty.isSlice(mod)) {6854 if (payload_ty.isSlice(mod)) {
...@@ -6887,21 +6859,21 @@ pub const FuncGen = struct {...@@ -6887,21 +6859,21 @@ pub const FuncGen = struct {
6887 ));6859 ));
6888 return self.builder.buildICmp(pred, slice_ptr, (try o.builder.nullConst(ptr_ty)).toLlvm(&o.builder), "");6860 return self.builder.buildICmp(pred, slice_ptr, (try o.builder.nullConst(ptr_ty)).toLlvm(&o.builder), "");
6889 }6861 }
6890 return self.builder.buildICmp(pred, loaded, optional_llvm_ty.constNull(), "");6862 return self.builder.buildICmp(pred, loaded, (try o.builder.zeroInitConst(optional_llvm_ty)).toLlvm(&o.builder), "");
6891 }6863 }
68926864
6893 comptime assert(optional_layout_version == 3);6865 comptime assert(optional_layout_version == 3);
68946866
6895 if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) {6867 if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) {
6896 const loaded = if (operand_is_ptr)6868 const loaded = if (operand_is_ptr)
6897 self.builder.buildLoad(optional_llvm_ty, operand, "")6869 self.builder.buildLoad(optional_llvm_ty.toLlvm(&o.builder), operand, "")
6898 else6870 else
6899 operand;6871 operand;
6900 return self.builder.buildICmp(pred, loaded, (try o.builder.intConst(.i8, 0)).toLlvm(&o.builder), "");6872 return self.builder.buildICmp(pred, loaded, (try o.builder.intConst(.i8, 0)).toLlvm(&o.builder), "");
6901 }6873 }
69026874
6903 const is_by_ref = operand_is_ptr or isByRef(optional_ty, mod);6875 const is_by_ref = operand_is_ptr or isByRef(optional_ty, mod);
6904 const non_null_bit = try self.optIsNonNull(optional_llvm_ty, operand, is_by_ref);6876 const non_null_bit = try self.optIsNonNull(optional_llvm_ty.toLlvm(&o.builder), operand, is_by_ref);
6905 if (pred == .EQ) {6877 if (pred == .EQ) {
6906 return self.builder.buildNot(non_null_bit, "");6878 return self.builder.buildNot(non_null_bit, "");
6907 } else {6879 } else {
...@@ -7549,24 +7521,18 @@ pub const FuncGen = struct {...@@ -7549,24 +7521,18 @@ pub const FuncGen = struct {
7549 }7521 }
7550 if (scalar_ty.isSignedInt(mod)) {7522 if (scalar_ty.isSignedInt(mod)) {
7551 const inst_llvm_ty = try o.lowerType(inst_ty);7523 const inst_llvm_ty = try o.lowerType(inst_ty);
7552 const scalar_bit_size_minus_one = scalar_ty.bitSize(mod) - 1;7524 const bit_size_minus_one = try o.builder.splatConst(inst_llvm_ty, try o.builder.intConst(
7553 const bit_size_minus_one = if (inst_ty.zigTypeTag(mod) == .Vector) const_vector: {7525 inst_llvm_ty.scalarType(&o.builder),
7554 const vec_len = inst_ty.vectorLen(mod);7526 inst_llvm_ty.scalarBits(&o.builder) - 1,
75557527 ));
7556 const shifts = try self.gpa.alloc(*llvm.Value, vec_len);
7557 defer self.gpa.free(shifts);
7558
7559 @memset(shifts, (try o.builder.intConst(try o.lowerType(scalar_ty), scalar_bit_size_minus_one)).toLlvm(&o.builder));
7560 break :const_vector llvm.constVector(shifts.ptr, vec_len);
7561 } else (try o.builder.intConst(inst_llvm_ty, scalar_bit_size_minus_one)).toLlvm(&o.builder);
75627528
7563 const div = self.builder.buildSDiv(lhs, rhs, "");7529 const div = self.builder.buildSDiv(lhs, rhs, "");
7564 const rem = self.builder.buildSRem(lhs, rhs, "");7530 const rem = self.builder.buildSRem(lhs, rhs, "");
7565 const div_sign = self.builder.buildXor(lhs, rhs, "");7531 const div_sign = self.builder.buildXor(lhs, rhs, "");
7566 const div_sign_mask = self.builder.buildAShr(div_sign, bit_size_minus_one, "");7532 const div_sign_mask = self.builder.buildAShr(div_sign, bit_size_minus_one.toLlvm(&o.builder), "");
7567 const zero = inst_llvm_ty.toLlvm(&o.builder).constNull();7533 const zero = try o.builder.zeroInitConst(inst_llvm_ty);
7568 const rem_nonzero = self.builder.buildICmp(.NE, rem, zero, "");7534 const rem_nonzero = self.builder.buildICmp(.NE, rem, zero.toLlvm(&o.builder), "");
7569 const correction = self.builder.buildSelect(rem_nonzero, div_sign_mask, zero, "");7535 const correction = self.builder.buildSelect(rem_nonzero, div_sign_mask, zero.toLlvm(&o.builder), "");
7570 return self.builder.buildNSWAdd(div, correction, "");7536 return self.builder.buildNSWAdd(div, correction, "");
7571 }7537 }
7572 return self.builder.buildUDiv(lhs, rhs, "");7538 return self.builder.buildUDiv(lhs, rhs, "");
...@@ -7620,29 +7586,23 @@ pub const FuncGen = struct {...@@ -7620,29 +7586,23 @@ pub const FuncGen = struct {
7620 const a = try self.buildFloatOp(.fmod, inst_ty, 2, .{ lhs, rhs });7586 const a = try self.buildFloatOp(.fmod, inst_ty, 2, .{ lhs, rhs });
7621 const b = try self.buildFloatOp(.add, inst_ty, 2, .{ a, rhs });7587 const b = try self.buildFloatOp(.add, inst_ty, 2, .{ a, rhs });
7622 const c = try self.buildFloatOp(.fmod, inst_ty, 2, .{ b, rhs });7588 const c = try self.buildFloatOp(.fmod, inst_ty, 2, .{ b, rhs });
7623 const zero = inst_llvm_ty.toLlvm(&o.builder).constNull();7589 const zero = try o.builder.zeroInitConst(inst_llvm_ty);
7624 const ltz = try self.buildFloatCmp(.lt, inst_ty, .{ lhs, zero });7590 const ltz = try self.buildFloatCmp(.lt, inst_ty, .{ lhs, zero.toLlvm(&o.builder) });
7625 return self.builder.buildSelect(ltz, c, a, "");7591 return self.builder.buildSelect(ltz, c, a, "");
7626 }7592 }
7627 if (scalar_ty.isSignedInt(mod)) {7593 if (scalar_ty.isSignedInt(mod)) {
7628 const scalar_bit_size_minus_one = scalar_ty.bitSize(mod) - 1;7594 const bit_size_minus_one = try o.builder.splatConst(inst_llvm_ty, try o.builder.intConst(
7629 const bit_size_minus_one = if (inst_ty.zigTypeTag(mod) == .Vector) const_vector: {7595 inst_llvm_ty.scalarType(&o.builder),
7630 const vec_len = inst_ty.vectorLen(mod);7596 inst_llvm_ty.scalarBits(&o.builder) - 1,
76317597 ));
7632 const shifts = try self.gpa.alloc(*llvm.Value, vec_len);
7633 defer self.gpa.free(shifts);
7634
7635 @memset(shifts, (try o.builder.intConst(try o.lowerType(scalar_ty), scalar_bit_size_minus_one)).toLlvm(&o.builder));
7636 break :const_vector llvm.constVector(shifts.ptr, vec_len);
7637 } else (try o.builder.intConst(inst_llvm_ty, scalar_bit_size_minus_one)).toLlvm(&o.builder);
76387598
7639 const rem = self.builder.buildSRem(lhs, rhs, "");7599 const rem = self.builder.buildSRem(lhs, rhs, "");
7640 const div_sign = self.builder.buildXor(lhs, rhs, "");7600 const div_sign = self.builder.buildXor(lhs, rhs, "");
7641 const div_sign_mask = self.builder.buildAShr(div_sign, bit_size_minus_one, "");7601 const div_sign_mask = self.builder.buildAShr(div_sign, bit_size_minus_one.toLlvm(&o.builder), "");
7642 const rhs_masked = self.builder.buildAnd(rhs, div_sign_mask, "");7602 const rhs_masked = self.builder.buildAnd(rhs, div_sign_mask, "");
7643 const zero = inst_llvm_ty.toLlvm(&o.builder).constNull();7603 const zero = try o.builder.zeroInitConst(inst_llvm_ty);
7644 const rem_nonzero = self.builder.buildICmp(.NE, rem, zero, "");7604 const rem_nonzero = self.builder.buildICmp(.NE, rem, zero.toLlvm(&o.builder), "");
7645 const correction = self.builder.buildSelect(rem_nonzero, rhs_masked, zero, "");7605 const correction = self.builder.buildSelect(rem_nonzero, rhs_masked, zero.toLlvm(&o.builder), "");
7646 return self.builder.buildNSWAdd(rem, correction, "");7606 return self.builder.buildNSWAdd(rem, correction, "");
7647 }7607 }
7648 return self.builder.buildURem(lhs, rhs, "");7608 return self.builder.buildURem(lhs, rhs, "");
...@@ -7953,17 +7913,17 @@ pub const FuncGen = struct {...@@ -7953,17 +7913,17 @@ pub const FuncGen = struct {
7953 // In this case we can generate a softfloat negation by XORing the7913 // In this case we can generate a softfloat negation by XORing the
7954 // bits with a constant.7914 // bits with a constant.
7955 const int_ty = try o.builder.intType(@intCast(float_bits));7915 const int_ty = try o.builder.intType(@intCast(float_bits));
7956 const one = (try o.builder.intConst(int_ty, 1)).toLlvm(&o.builder);7916 const one = try o.builder.intConst(int_ty, 1);
7957 const shift_amt = try o.builder.intConst(int_ty, float_bits - 1);7917 const shift_amt = try o.builder.intConst(int_ty, float_bits - 1);
7958 const sign_mask = one.constShl(shift_amt.toLlvm(&o.builder));7918 const sign_mask = try o.builder.binConst(.shl, one, shift_amt);
7959 const result = if (ty.zigTypeTag(mod) == .Vector) blk: {7919 const result = if (ty.zigTypeTag(mod) == .Vector) blk: {
7960 const splat_sign_mask = self.builder.buildVectorSplat(ty.vectorLen(mod), sign_mask, "");7920 const splat_sign_mask = self.builder.buildVectorSplat(ty.vectorLen(mod), sign_mask.toLlvm(&o.builder), "");
7961 const cast_ty = try o.builder.vectorType(.normal, ty.vectorLen(mod), int_ty);7921 const cast_ty = try o.builder.vectorType(.normal, ty.vectorLen(mod), int_ty);
7962 const bitcasted_operand = self.builder.buildBitCast(params[0], cast_ty.toLlvm(&o.builder), "");7922 const bitcasted_operand = self.builder.buildBitCast(params[0], cast_ty.toLlvm(&o.builder), "");
7963 break :blk self.builder.buildXor(bitcasted_operand, splat_sign_mask, "");7923 break :blk self.builder.buildXor(bitcasted_operand, splat_sign_mask, "");
7964 } else blk: {7924 } else blk: {
7965 const bitcasted_operand = self.builder.buildBitCast(params[0], int_ty.toLlvm(&o.builder), "");7925 const bitcasted_operand = self.builder.buildBitCast(params[0], int_ty.toLlvm(&o.builder), "");
7966 break :blk self.builder.buildXor(bitcasted_operand, sign_mask, "");7926 break :blk self.builder.buildXor(bitcasted_operand, sign_mask.toLlvm(&o.builder), "");
7967 };7927 };
7968 return self.builder.buildBitCast(result, llvm_ty.toLlvm(&o.builder), "");7928 return self.builder.buildBitCast(result, llvm_ty.toLlvm(&o.builder), "");
7969 },7929 },
...@@ -8886,9 +8846,9 @@ pub const FuncGen = struct {...@@ -8886,9 +8846,9 @@ pub const FuncGen = struct {
8886 const len = try self.sliceOrArrayLenInBytes(dest_slice, ptr_ty);8846 const len = try self.sliceOrArrayLenInBytes(dest_slice, ptr_ty);
88878847
8888 if (intrinsic_len0_traps) {8848 if (intrinsic_len0_traps) {
8889 try self.safeWasmMemset(dest_ptr, fill_byte, len, dest_ptr_align, is_volatile);8849 try self.safeWasmMemset(dest_ptr, fill_byte.toLlvm(&o.builder), len, dest_ptr_align, is_volatile);
8890 } else {8850 } else {
8891 _ = self.builder.buildMemSet(dest_ptr, fill_byte, len, dest_ptr_align, is_volatile);8851 _ = self.builder.buildMemSet(dest_ptr, fill_byte.toLlvm(&o.builder), len, dest_ptr_align, is_volatile);
8892 }8852 }
8893 return null;8853 return null;
8894 }8854 }
...@@ -8987,8 +8947,9 @@ pub const FuncGen = struct {...@@ -8987,8 +8947,9 @@ pub const FuncGen = struct {
8987 dest_ptr_align: u32,8947 dest_ptr_align: u32,
8988 is_volatile: bool,8948 is_volatile: bool,
8989 ) !void {8949 ) !void {
8990 const llvm_usize_ty = self.context.intType(self.dg.object.target.ptrBitWidth());8950 const o = self.dg.object;
8991 const cond = try self.cmp(len, llvm_usize_ty.constInt(0, .False), Type.usize, .neq);8951 const llvm_usize_ty = try o.lowerType(Type.usize);
8952 const cond = try self.cmp(len, (try o.builder.intConst(llvm_usize_ty, 0)).toLlvm(&o.builder), Type.usize, .neq);
8992 const memset_block = self.context.appendBasicBlock(self.llvm_func, "MemsetTrapSkip");8953 const memset_block = self.context.appendBasicBlock(self.llvm_func, "MemsetTrapSkip");
8993 const end_block = self.context.appendBasicBlock(self.llvm_func, "MemsetTrapEnd");8954 const end_block = self.context.appendBasicBlock(self.llvm_func, "MemsetTrapEnd");
8994 _ = self.builder.buildCondBr(cond, memset_block, end_block);8955 _ = self.builder.buildCondBr(cond, memset_block, end_block);
...@@ -9020,8 +8981,8 @@ pub const FuncGen = struct {...@@ -9020,8 +8981,8 @@ pub const FuncGen = struct {
9020 std.Target.wasm.featureSetHas(o.target.cpu.features, .bulk_memory) and8981 std.Target.wasm.featureSetHas(o.target.cpu.features, .bulk_memory) and
9021 dest_ptr_ty.isSlice(mod))8982 dest_ptr_ty.isSlice(mod))
9022 {8983 {
9023 const llvm_usize_ty = self.context.intType(self.dg.object.target.ptrBitWidth());8984 const llvm_usize_ty = try o.lowerType(Type.usize);
9024 const cond = try self.cmp(len, llvm_usize_ty.constInt(0, .False), Type.usize, .neq);8985 const cond = try self.cmp(len, (try o.builder.intConst(llvm_usize_ty, 0)).toLlvm(&o.builder), Type.usize, .neq);
9025 const memcpy_block = self.context.appendBasicBlock(self.llvm_func, "MemcpyTrapSkip");8986 const memcpy_block = self.context.appendBasicBlock(self.llvm_func, "MemcpyTrapSkip");
9026 const end_block = self.context.appendBasicBlock(self.llvm_func, "MemcpyTrapEnd");8987 const end_block = self.context.appendBasicBlock(self.llvm_func, "MemcpyTrapEnd");
9027 _ = self.builder.buildCondBr(cond, memcpy_block, end_block);8988 _ = self.builder.buildCondBr(cond, memcpy_block, end_block);
...@@ -9183,19 +9144,13 @@ pub const FuncGen = struct {...@@ -9183,19 +9144,13 @@ pub const FuncGen = struct {
9183 if (operand_ty.zigTypeTag(mod) == .Vector) {9144 if (operand_ty.zigTypeTag(mod) == .Vector) {
9184 const vec_len = operand_ty.vectorLen(mod);9145 const vec_len = operand_ty.vectorLen(mod);
9185 operand_llvm_ty = try o.builder.vectorType(.normal, vec_len, scalar_ty);9146 operand_llvm_ty = try o.builder.vectorType(.normal, vec_len, scalar_ty);
9147 } else operand_llvm_ty = scalar_ty;
91869148
9187 const shifts = try self.gpa.alloc(*llvm.Value, vec_len);9149 const shift_amt =
9188 defer self.gpa.free(shifts);9150 try o.builder.splatConst(operand_llvm_ty, try o.builder.intConst(scalar_ty, 8));
9189 @memset(shifts, (try o.builder.intConst(scalar_ty, 8)).toLlvm(&o.builder));9151 const extended = self.builder.buildZExt(operand, operand_llvm_ty.toLlvm(&o.builder), "");
9190 const shift_vec = llvm.constVector(shifts.ptr, vec_len);9152 operand = self.builder.buildShl(extended, shift_amt.toLlvm(&o.builder), "");
91919153
9192 const extended = self.builder.buildZExt(operand, operand_llvm_ty.toLlvm(&o.builder), "");
9193 operand = self.builder.buildShl(extended, shift_vec, "");
9194 } else {
9195 const extended = self.builder.buildZExt(operand, scalar_ty.toLlvm(&o.builder), "");
9196 operand = self.builder.buildShl(extended, (try o.builder.intConst(scalar_ty, 8)).toLlvm(&o.builder), "");
9197 operand_llvm_ty = scalar_ty;
9198 }
9199 bits = bits + 8;9154 bits = bits + 8;
9200 }9155 }
92019156
...@@ -9358,11 +9313,8 @@ pub const FuncGen = struct {...@@ -9358,11 +9313,8 @@ pub const FuncGen = struct {
9358 const fqn = try mod.declPtr(enum_type.decl).getFullyQualifiedName(mod);9313 const fqn = try mod.declPtr(enum_type.decl).getFullyQualifiedName(mod);
9359 const llvm_fn_name = try o.builder.fmt("__zig_tag_name_{}", .{fqn.fmt(&mod.intern_pool)});9314 const llvm_fn_name = try o.builder.fmt("__zig_tag_name_{}", .{fqn.fmt(&mod.intern_pool)});
93609315
9361 const slice_ty = Type.slice_const_u8_sentinel_0;9316 const ret_ty = try o.lowerType(Type.slice_const_u8_sentinel_0);
9362 const ret_ty = try o.lowerType(slice_ty);
9363 const llvm_ret_ty = ret_ty.toLlvm(&o.builder);
9364 const usize_ty = try o.lowerType(Type.usize);9317 const usize_ty = try o.lowerType(Type.usize);
9365 const slice_alignment = slice_ty.abiAlignment(mod);
93669318
9367 const fn_type = try o.builder.fnType(ret_ty, &.{9319 const fn_type = try o.builder.fnType(ret_ty, &.{
9368 try o.lowerType(enum_type.tag_ty.toType()),9320 try o.lowerType(enum_type.tag_ty.toType()),
...@@ -9399,33 +9351,38 @@ pub const FuncGen = struct {...@@ -9399,33 +9351,38 @@ pub const FuncGen = struct {
9399 const tag_int_value = fn_val.getParam(0);9351 const tag_int_value = fn_val.getParam(0);
9400 const switch_instr = self.builder.buildSwitch(tag_int_value, bad_value_block, @as(c_uint, @intCast(enum_type.names.len)));9352 const switch_instr = self.builder.buildSwitch(tag_int_value, bad_value_block, @as(c_uint, @intCast(enum_type.names.len)));
94019353
9402 const array_ptr_indices: [2]*llvm.Value = .{
9403 (try o.builder.intConst(usize_ty, 0)).toLlvm(&o.builder),
9404 } ** 2;
9405
9406 for (enum_type.names, 0..) |name_ip, field_index_usize| {9354 for (enum_type.names, 0..) |name_ip, field_index_usize| {
9407 const field_index = @as(u32, @intCast(field_index_usize));9355 const field_index = @as(u32, @intCast(field_index_usize));
9408 const name = mod.intern_pool.stringToSlice(name_ip);9356 const name = try o.builder.string(mod.intern_pool.stringToSlice(name_ip));
9409 const str_init = self.context.constString(name.ptr, @as(c_uint, @intCast(name.len)), .False);9357 const str_init = try o.builder.stringNullConst(name);
9410 const str_init_llvm_ty = str_init.typeOf();9358 const str_ty = str_init.typeOf(&o.builder);
9411 const str_global = o.llvm_module.addGlobal(str_init_llvm_ty, "");9359 const str_llvm_global = o.llvm_module.addGlobal(str_ty.toLlvm(&o.builder), "");
9412 str_global.setInitializer(str_init);9360 str_llvm_global.setInitializer(str_init.toLlvm(&o.builder));
9413 str_global.setLinkage(.Private);9361 str_llvm_global.setLinkage(.Private);
9414 str_global.setGlobalConstant(.True);9362 str_llvm_global.setGlobalConstant(.True);
9415 str_global.setUnnamedAddr(.True);9363 str_llvm_global.setUnnamedAddr(.True);
9416 str_global.setAlignment(1);9364 str_llvm_global.setAlignment(1);
94179365
9418 const slice_fields = [_]*llvm.Value{9366 var str_global = Builder.Global{
9419 str_init_llvm_ty.constInBoundsGEP(str_global, &array_ptr_indices, array_ptr_indices.len),9367 .linkage = .private,
9420 (try o.builder.intConst(usize_ty, name.len)).toLlvm(&o.builder),9368 .unnamed_addr = .unnamed_addr,
9369 .type = str_ty,
9370 .alignment = comptime Builder.Alignment.fromByteUnits(1),
9371 .kind = .{ .variable = @enumFromInt(o.builder.variables.items.len) },
9421 };9372 };
9422 const slice_init = llvm_ret_ty.constNamedStruct(&slice_fields, slice_fields.len);9373 var str_variable = Builder.Variable{
9423 const slice_global = o.llvm_module.addGlobal(slice_init.typeOf(), "");9374 .global = @enumFromInt(o.builder.globals.count()),
9424 slice_global.setInitializer(slice_init);9375 .mutability = .constant,
9425 slice_global.setLinkage(.Private);9376 .init = str_init,
9426 slice_global.setGlobalConstant(.True);9377 };
9427 slice_global.setUnnamedAddr(.True);9378 try o.builder.llvm.globals.append(o.gpa, str_llvm_global);
9428 slice_global.setAlignment(slice_alignment);9379 const global_index = try o.builder.addGlobal(.empty, str_global);
9380 try o.builder.variables.append(o.gpa, str_variable);
9381
9382 const slice_val = try o.builder.structConst(ret_ty, &.{
9383 global_index.toConst(),
9384 try o.builder.intConst(usize_ty, name.toSlice(&o.builder).?.len),
9385 });
94299386
9430 const return_block = self.context.appendBasicBlock(fn_val, "Name");9387 const return_block = self.context.appendBasicBlock(fn_val, "Name");
9431 const this_tag_int_value =9388 const this_tag_int_value =
...@@ -9433,9 +9390,7 @@ pub const FuncGen = struct {...@@ -9433,9 +9390,7 @@ pub const FuncGen = struct {
9433 switch_instr.addCase(this_tag_int_value.toLlvm(&o.builder), return_block);9390 switch_instr.addCase(this_tag_int_value.toLlvm(&o.builder), return_block);
94349391
9435 self.builder.positionBuilderAtEnd(return_block);9392 self.builder.positionBuilderAtEnd(return_block);
9436 const loaded = self.builder.buildLoad(llvm_ret_ty, slice_global, "");9393 _ = self.builder.buildRet(slice_val.toLlvm(&o.builder));
9437 loaded.setAlignment(slice_alignment);
9438 _ = self.builder.buildRet(loaded);
9439 }9394 }
94409395
9441 self.builder.positionBuilderAtEnd(bad_value_block);9396 self.builder.positionBuilderAtEnd(bad_value_block);
...@@ -9530,22 +9485,25 @@ pub const FuncGen = struct {...@@ -9530,22 +9485,25 @@ pub const FuncGen = struct {
9530 // when changing code, so Zig uses negative numbers to index the9485 // when changing code, so Zig uses negative numbers to index the
9531 // second vector. These start at -1 and go down, and are easiest to use9486 // second vector. These start at -1 and go down, and are easiest to use
9532 // with the ~ operator. Here we convert between the two formats.9487 // with the ~ operator. Here we convert between the two formats.
9533 const values = try self.gpa.alloc(*llvm.Value, mask_len);9488 const values = try self.gpa.alloc(Builder.Constant, mask_len);
9534 defer self.gpa.free(values);9489 defer self.gpa.free(values);
95359490
9536 for (values, 0..) |*val, i| {9491 for (values, 0..) |*val, i| {
9537 const elem = try mask.elemValue(mod, i);9492 const elem = try mask.elemValue(mod, i);
9538 if (elem.isUndef(mod)) {9493 if (elem.isUndef(mod)) {
9539 val.* = Builder.Type.i32.toLlvm(&o.builder).getUndef();9494 val.* = try o.builder.undefConst(.i32);
9540 } else {9495 } else {
9541 const int = elem.toSignedInt(mod);9496 const int = elem.toSignedInt(mod);
9542 const unsigned = if (int >= 0) @as(u32, @intCast(int)) else @as(u32, @intCast(~int + a_len));9497 const unsigned = if (int >= 0) @as(u32, @intCast(int)) else @as(u32, @intCast(~int + a_len));
9543 val.* = (try o.builder.intConst(.i32, unsigned)).toLlvm(&o.builder);9498 val.* = try o.builder.intConst(.i32, unsigned);
9544 }9499 }
9545 }9500 }
95469501
9547 const llvm_mask_value = llvm.constVector(values.ptr, mask_len);9502 const llvm_mask_value = try o.builder.vectorConst(
9548 return self.builder.buildShuffleVector(a, b, llvm_mask_value, "");9503 try o.builder.vectorType(.normal, mask_len, .i32),
9504 values,
9505 );
9506 return self.builder.buildShuffleVector(a, b, llvm_mask_value.toLlvm(&o.builder), "");
9549 }9507 }
95509508
9551 /// Reduce a vector by repeatedly applying `llvm_fn` to produce an accumulated result.9509 /// Reduce a vector by repeatedly applying `llvm_fn` to produce an accumulated result.
...@@ -9816,7 +9774,7 @@ pub const FuncGen = struct {...@@ -9816,7 +9774,7 @@ pub const FuncGen = struct {
9816 .val = sent_val,9774 .val = sent_val,
9817 });9775 });
98189776
9819 try self.store(elem_ptr, elem_ptr_ty, llvm_elem, .NotAtomic);9777 try self.store(elem_ptr, elem_ptr_ty, llvm_elem.toLlvm(&o.builder), .NotAtomic);
9820 }9778 }
98219779
9822 return alloca_inst;9780 return alloca_inst;
...@@ -10431,12 +10389,13 @@ pub const FuncGen = struct {...@@ -10431,12 +10389,13 @@ pub const FuncGen = struct {
10431 else10389 else
10432 self.builder.buildBitCast(elem, value_bits_type.toLlvm(&o.builder), "");10390 self.builder.buildBitCast(elem, value_bits_type.toLlvm(&o.builder), "");
1043310391
10434 var mask_val = (try o.builder.intConst(value_bits_type, -1)).toLlvm(&o.builder);10392 var mask_val = try o.builder.intConst(value_bits_type, -1);
10435 mask_val = mask_val.constZExt(containing_int_ty.toLlvm(&o.builder));10393 mask_val = try o.builder.castConst(.zext, mask_val, containing_int_ty);
10436 mask_val = mask_val.constShl(shift_amt.toLlvm(&o.builder));10394 mask_val = try o.builder.binConst(.shl, mask_val, shift_amt);
10437 mask_val = mask_val.constNot();10395 mask_val =
10396 try o.builder.binConst(.xor, mask_val, try o.builder.intConst(containing_int_ty, -1));
1043810397
10439 const anded_containing_int = self.builder.buildAnd(containing_int, mask_val, "");10398 const anded_containing_int = self.builder.buildAnd(containing_int, mask_val.toLlvm(&o.builder), "");
10440 const extended_value = self.builder.buildZExt(value_bits, containing_int_ty.toLlvm(&o.builder), "");10399 const extended_value = self.builder.buildZExt(value_bits, containing_int_ty.toLlvm(&o.builder), "");
10441 const shifted_value = self.builder.buildShl(extended_value, shift_amt.toLlvm(&o.builder), "");10400 const shifted_value = self.builder.buildShl(extended_value, shift_amt.toLlvm(&o.builder), "");
10442 const ored_value = self.builder.buildOr(shifted_value, anded_containing_int, "");10401 const ored_value = self.builder.buildOr(shifted_value, anded_containing_int, "");
src/codegen/llvm/Builder.zig+174-55
...@@ -251,14 +251,41 @@ pub const Type = enum(u32) {...@@ -251,14 +251,41 @@ pub const Type = enum(u32) {
251 };251 };
252 }252 }
253253
254 pub fn isFn(self: Type, builder: *const Builder) bool {254 pub fn isFloatingPoint(self: Type) bool {
255 return switch (self) {
256 .half, .bfloat, .float, .double, .fp128, .x86_fp80, .ppc_fp128 => true,
257 else => false,
258 };
259 }
260
261 pub fn isInteger(self: Type, builder: *const Builder) bool {
262 return switch (self) {
263 .i1, .i8, .i16, .i29, .i32, .i64, .i80, .i128 => true,
264 else => switch (self.tag(builder)) {
265 .integer => true,
266 else => false,
267 },
268 };
269 }
270
271 pub fn isPointer(self: Type, builder: *const Builder) bool {
272 return switch (self) {
273 .ptr => true,
274 else => switch (self.tag(builder)) {
275 .pointer => true,
276 else => false,
277 },
278 };
279 }
280
281 pub fn isFunction(self: Type, builder: *const Builder) bool {
255 return switch (self.tag(builder)) {282 return switch (self.tag(builder)) {
256 .function, .vararg_function => true,283 .function, .vararg_function => true,
257 else => false,284 else => false,
258 };285 };
259 }286 }
260287
261 pub fn fnKind(self: Type, builder: *const Builder) Type.Function.Kind {288 pub fn functionKind(self: Type, builder: *const Builder) Type.Function.Kind {
262 return switch (self.tag(builder)) {289 return switch (self.tag(builder)) {
263 .function => .normal,290 .function => .normal,
264 .vararg_function => .vararg,291 .vararg_function => .vararg,
...@@ -345,6 +372,20 @@ pub const Type = enum(u32) {...@@ -345,6 +372,20 @@ pub const Type = enum(u32) {
345 };372 };
346 }373 }
347374
375 pub fn scalarType(self: Type, builder: *const Builder) Type {
376 if (self.isFloatingPoint()) return self;
377 const item = builder.type_items.items[@intFromEnum(self)];
378 return switch (item.tag) {
379 .integer,
380 .pointer,
381 => self,
382 .vector,
383 .scalable_vector,
384 => builder.typeExtraData(Type.Vector, item.data).child,
385 else => unreachable,
386 };
387 }
388
348 pub fn vectorLen(self: Type, builder: *const Builder) u32 {389 pub fn vectorLen(self: Type, builder: *const Builder) u32 {
349 const item = builder.type_items.items[@intFromEnum(self)];390 const item = builder.type_items.items[@intFromEnum(self)];
350 return switch (item.tag) {391 return switch (item.tag) {
...@@ -809,17 +850,17 @@ pub const Global = struct {...@@ -809,17 +850,17 @@ pub const Global = struct {
809 }850 }
810851
811 pub fn rename(self: Index, new_name: String, builder: *Builder) Allocator.Error!void {852 pub fn rename(self: Index, new_name: String, builder: *Builder) Allocator.Error!void {
812 try builder.ensureUnusedCapacityGlobal(new_name);853 try builder.ensureUnusedGlobalCapacity(new_name);
813 self.renameAssumeCapacity(new_name, builder);854 self.renameAssumeCapacity(new_name, builder);
814 }855 }
815856
816 pub fn takeName(self: Index, other: Index, builder: *Builder) Allocator.Error!void {857 pub fn takeName(self: Index, other: Index, builder: *Builder) Allocator.Error!void {
817 try builder.ensureUnusedCapacityGlobal(.empty);858 try builder.ensureUnusedGlobalCapacity(.empty);
818 self.takeNameAssumeCapacity(other, builder);859 self.takeNameAssumeCapacity(other, builder);
819 }860 }
820861
821 pub fn replace(self: Index, other: Index, builder: *Builder) Allocator.Error!void {862 pub fn replace(self: Index, other: Index, builder: *Builder) Allocator.Error!void {
822 try builder.ensureUnusedCapacityGlobal(.empty);863 try builder.ensureUnusedGlobalCapacity(.empty);
823 self.replaceAssumeCapacity(other, builder);864 self.replaceAssumeCapacity(other, builder);
824 }865 }
825866
...@@ -1047,6 +1088,7 @@ pub const Constant = enum(u32) {...@@ -1047,6 +1088,7 @@ pub const Constant = enum(u32) {
1047 string,1088 string,
1048 string_null,1089 string_null,
1049 vector,1090 vector,
1091 splat,
1050 zeroinitializer,1092 zeroinitializer,
1051 undef,1093 undef,
1052 poison,1094 poison,
...@@ -1126,6 +1168,11 @@ pub const Constant = enum(u32) {...@@ -1126,6 +1168,11 @@ pub const Constant = enum(u32) {
1126 type: Type,1168 type: Type,
1127 };1169 };
11281170
1171 pub const Splat = extern struct {
1172 type: Type,
1173 value: Constant,
1174 };
1175
1129 pub const BlockAddress = extern struct {1176 pub const BlockAddress = extern struct {
1130 function: Function.Index,1177 function: Function.Index,
1131 block: Function.Block.Index,1178 block: Function.Block.Index,
...@@ -1217,6 +1264,7 @@ pub const Constant = enum(u32) {...@@ -1217,6 +1264,7 @@ pub const Constant = enum(u32) {
1217 .array,1264 .array,
1218 .vector,1265 .vector,
1219 => builder.constantExtraData(Aggregate, item.data).type,1266 => builder.constantExtraData(Aggregate, item.data).type,
1267 .splat => builder.constantExtraData(Splat, item.data).type,
1220 .string,1268 .string,
1221 .string_null,1269 .string_null,
1222 => builder.arrayTypeAssumeCapacity(1270 => builder.arrayTypeAssumeCapacity(
...@@ -1270,28 +1318,10 @@ pub const Constant = enum(u32) {...@@ -1270,28 +1318,10 @@ pub const Constant = enum(u32) {
1270 },1318 },
1271 .icmp, .fcmp => {1319 .icmp, .fcmp => {
1272 const ty = builder.constantExtraData(Compare, item.data).lhs.typeOf(builder);1320 const ty = builder.constantExtraData(Compare, item.data).lhs.typeOf(builder);
1273 return switch (ty) {1321 return if (ty.isVector(builder)) switch (ty.vectorKind(builder)) {
1274 .half,1322 inline else => |kind| builder
1275 .bfloat,1323 .vectorTypeAssumeCapacity(kind, ty.vectorLen(builder), .i1),
1276 .float,1324 } else ty;
1277 .double,
1278 .fp128,
1279 .x86_fp80,
1280 .ppc_fp128,
1281 .i1,
1282 .i8,
1283 .i16,
1284 .i29,
1285 .i32,
1286 .i64,
1287 .i80,
1288 .i128,
1289 => ty,
1290 else => if (ty.isVector(builder)) switch (ty.vectorKind(builder)) {
1291 inline else => |kind| builder
1292 .vectorTypeAssumeCapacity(kind, ty.vectorLen(builder), .i1),
1293 } else ty,
1294 };
1295 },1325 },
1296 .extractelement => builder.constantExtraData(ExtractElement, item.data)1326 .extractelement => builder.constantExtraData(ExtractElement, item.data)
1297 .arg.typeOf(builder).childType(builder),1327 .arg.typeOf(builder).childType(builder),
...@@ -1479,7 +1509,6 @@ pub const Constant = enum(u32) {...@@ -1479,7 +1509,6 @@ pub const Constant = enum(u32) {
1479 const len = extra.data.type.aggregateLen(data.builder);1509 const len = extra.data.type.aggregateLen(data.builder);
1480 const vals: []const Constant =1510 const vals: []const Constant =
1481 @ptrCast(data.builder.constant_extra.items[extra.end..][0..len]);1511 @ptrCast(data.builder.constant_extra.items[extra.end..][0..len]);
1482
1483 try writer.writeAll(switch (tag) {1512 try writer.writeAll(switch (tag) {
1484 .structure => "{ ",1513 .structure => "{ ",
1485 .packed_structure => "<{ ",1514 .packed_structure => "<{ ",
...@@ -1499,6 +1528,16 @@ pub const Constant = enum(u32) {...@@ -1499,6 +1528,16 @@ pub const Constant = enum(u32) {
1499 else => unreachable,1528 else => unreachable,
1500 });1529 });
1501 },1530 },
1531 .splat => {
1532 const extra = data.builder.constantExtraData(Splat, item.data);
1533 const len = extra.type.vectorLen(data.builder);
1534 try writer.writeByte('<');
1535 for (0..len) |index| {
1536 if (index > 0) try writer.writeAll(", ");
1537 try writer.print("{%}", .{extra.value.fmt(data.builder)});
1538 }
1539 try writer.writeByte('>');
1540 },
1502 inline .string,1541 inline .string,
1503 .string_null,1542 .string_null,
1504 => |tag| try writer.print("c{\"" ++ switch (tag) {1543 => |tag| try writer.print("c{\"" ++ switch (tag) {
...@@ -2093,7 +2132,7 @@ pub fn namedTypeSetBody(...@@ -2093,7 +2132,7 @@ pub fn namedTypeSetBody(
2093pub fn addGlobal(self: *Builder, name: String, global: Global) Allocator.Error!Global.Index {2132pub fn addGlobal(self: *Builder, name: String, global: Global) Allocator.Error!Global.Index {
2094 assert(!name.isAnon());2133 assert(!name.isAnon());
2095 try self.ensureUnusedTypeCapacity(1, null, 0);2134 try self.ensureUnusedTypeCapacity(1, null, 0);
2096 try self.ensureUnusedCapacityGlobal(name);2135 try self.ensureUnusedGlobalCapacity(name);
2097 return self.addGlobalAssumeCapacity(name, global);2136 return self.addGlobalAssumeCapacity(name, global);
2098}2137}
20992138
...@@ -2231,8 +2270,17 @@ pub fn vectorConst(self: *Builder, ty: Type, vals: []const Constant) Allocator.E...@@ -2231,8 +2270,17 @@ pub fn vectorConst(self: *Builder, ty: Type, vals: []const Constant) Allocator.E
2231 return self.vectorConstAssumeCapacity(ty, vals);2270 return self.vectorConstAssumeCapacity(ty, vals);
2232}2271}
22332272
2273pub fn splatConst(self: *Builder, ty: Type, val: Constant) Allocator.Error!Constant {
2274 try self.ensureUnusedConstantCapacity(1, Constant.Splat, 0);
2275 return self.splatConstAssumeCapacity(ty, val);
2276}
2277
2234pub fn zeroInitConst(self: *Builder, ty: Type) Allocator.Error!Constant {2278pub fn zeroInitConst(self: *Builder, ty: Type) Allocator.Error!Constant {
2235 try self.ensureUnusedConstantCapacity(1, null, 0);2279 try self.ensureUnusedConstantCapacity(1, Constant.Fp128, 0);
2280 try self.constant_limbs.ensureUnusedCapacity(
2281 self.gpa,
2282 Constant.Integer.limbs + comptime std.math.big.int.calcLimbLen(0),
2283 );
2236 return self.zeroInitConstAssumeCapacity(ty);2284 return self.zeroInitConstAssumeCapacity(ty);
2237}2285}
22382286
...@@ -2477,7 +2525,7 @@ fn isValidIdentifier(id: []const u8) bool {...@@ -2477,7 +2525,7 @@ fn isValidIdentifier(id: []const u8) bool {
2477 return true;2525 return true;
2478}2526}
24792527
2480fn ensureUnusedCapacityGlobal(self: *Builder, name: String) Allocator.Error!void {2528fn ensureUnusedGlobalCapacity(self: *Builder, name: String) Allocator.Error!void {
2481 if (self.useLibLlvm()) try self.llvm.globals.ensureUnusedCapacity(self.gpa, 1);2529 if (self.useLibLlvm()) try self.llvm.globals.ensureUnusedCapacity(self.gpa, 1);
2482 try self.string_map.ensureUnusedCapacity(self.gpa, 1);2530 try self.string_map.ensureUnusedCapacity(self.gpa, 1);
2483 if (name.toSlice(self)) |id| try self.string_bytes.ensureUnusedCapacity(self.gpa, id.len +2531 if (name.toSlice(self)) |id| try self.string_bytes.ensureUnusedCapacity(self.gpa, id.len +
...@@ -2571,6 +2619,7 @@ fn vectorTypeAssumeCapacity(...@@ -2571,6 +2619,7 @@ fn vectorTypeAssumeCapacity(
2571 len: u32,2619 len: u32,
2572 child: Type,2620 child: Type,
2573) Type {2621) Type {
2622 assert(child.isFloatingPoint() or child.isInteger(self) or child.isPointer(self));
2574 const tag: Type.Tag = switch (kind) {2623 const tag: Type.Tag = switch (kind) {
2575 .normal => .vector,2624 .normal => .vector,
2576 .scalable => .scalable_vector,2625 .scalable => .scalable_vector,
...@@ -3321,14 +3370,13 @@ fn vectorConstAssumeCapacity(...@@ -3321,14 +3370,13 @@ fn vectorConstAssumeCapacity(
3321 ty: Type,3370 ty: Type,
3322 vals: []const Constant,3371 vals: []const Constant,
3323) if (build_options.have_llvm) Allocator.Error!Constant else Constant {3372) if (build_options.have_llvm) Allocator.Error!Constant else Constant {
3324 if (std.debug.runtime_safety) {3373 assert(ty.isVector(self));
3325 const type_item = self.type_items.items[@intFromEnum(ty)];3374 assert(ty.vectorLen(self) == vals.len);
3326 assert(type_item.tag == .vector);3375 for (vals) |val| assert(ty.childType(self) == val.typeOf(self));
3327 const extra = self.typeExtraData(Type.Vector, type_item.data);
3328 assert(extra.len == vals.len);
3329 for (vals) |val| assert(extra.child == val.typeOf(self));
3330 }
33313376
3377 for (vals[1..]) |val| {
3378 if (vals[0] != val) break;
3379 } else return self.splatConstAssumeCapacity(ty, vals[0]);
3332 for (vals) |val| {3380 for (vals) |val| {
3333 if (!val.isZeroInit(self)) break;3381 if (!val.isZeroInit(self)) break;
3334 } else return self.zeroInitConstAssumeCapacity(ty);3382 } else return self.zeroInitConstAssumeCapacity(ty);
...@@ -3351,23 +3399,91 @@ fn vectorConstAssumeCapacity(...@@ -3351,23 +3399,91 @@ fn vectorConstAssumeCapacity(
3351 return result.constant;3399 return result.constant;
3352}3400}
33533401
3402fn splatConstAssumeCapacity(
3403 self: *Builder,
3404 ty: Type,
3405 val: Constant,
3406) if (build_options.have_llvm) Allocator.Error!Constant else Constant {
3407 assert(ty.scalarType(self) == val.typeOf(self));
3408
3409 if (!ty.isVector(self)) return val;
3410 if (val.isZeroInit(self)) return self.zeroInitConstAssumeCapacity(ty);
3411
3412 const Adapter = struct {
3413 builder: *const Builder,
3414 pub fn hash(_: @This(), key: Constant.Splat) u32 {
3415 return @truncate(std.hash.Wyhash.hash(
3416 comptime std.hash.uint32(@intFromEnum(Constant.Tag.splat)),
3417 std.mem.asBytes(&key),
3418 ));
3419 }
3420 pub fn eql(ctx: @This(), lhs_key: Constant.Splat, _: void, rhs_index: usize) bool {
3421 if (ctx.builder.constant_items.items(.tag)[rhs_index] != .splat) return false;
3422 const rhs_data = ctx.builder.constant_items.items(.data)[rhs_index];
3423 const rhs_extra = ctx.builder.constantExtraData(Constant.Splat, rhs_data);
3424 return std.meta.eql(lhs_key, rhs_extra);
3425 }
3426 };
3427 const data = Constant.Splat{ .type = ty, .value = val };
3428 const gop = self.constant_map.getOrPutAssumeCapacityAdapted(data, Adapter{ .builder = self });
3429 if (!gop.found_existing) {
3430 gop.key_ptr.* = {};
3431 gop.value_ptr.* = {};
3432 self.constant_items.appendAssumeCapacity(.{
3433 .tag = .splat,
3434 .data = self.addConstantExtraAssumeCapacity(data),
3435 });
3436 if (self.useLibLlvm()) {
3437 const ExpectedContents = [expected_fields_len]*llvm.Value;
3438 var stack align(@alignOf(ExpectedContents)) =
3439 std.heap.stackFallback(@sizeOf(ExpectedContents), self.gpa);
3440 const allocator = stack.get();
3441
3442 const llvm_vals = try allocator.alloc(*llvm.Value, ty.vectorLen(self));
3443 defer allocator.free(llvm_vals);
3444 @memset(llvm_vals, val.toLlvm(self));
3445
3446 self.llvm.constants.appendAssumeCapacity(
3447 llvm.constVector(llvm_vals.ptr, @intCast(llvm_vals.len)),
3448 );
3449 }
3450 }
3451 return @enumFromInt(gop.index);
3452}
3453
3354fn zeroInitConstAssumeCapacity(self: *Builder, ty: Type) Constant {3454fn zeroInitConstAssumeCapacity(self: *Builder, ty: Type) Constant {
3355 switch (self.type_items.items[@intFromEnum(ty)].tag) {3455 switch (ty) {
3356 .simple,3456 inline .half,
3357 .function,3457 .bfloat,
3358 .vararg_function,3458 .float,
3359 .integer,3459 .double,
3360 .pointer,3460 .fp128,
3361 => unreachable,3461 .x86_fp80,
3362 .target,3462 => |tag| return @field(Builder, @tagName(tag) ++ "ConstAssumeCapacity")(self, 0.0),
3363 .vector,3463 .ppc_fp128 => return self.ppc_fp128ConstAssumeCapacity(.{ 0.0, 0.0 }),
3364 .scalable_vector,3464 .token => return .none,
3365 .small_array,3465 .i1 => return .false,
3366 .array,3466 else => switch (self.type_items.items[@intFromEnum(ty)].tag) {
3367 .structure,3467 .simple,
3368 .packed_structure,3468 .function,
3369 .named_structure,3469 .vararg_function,
3370 => {},3470 => unreachable,
3471 .integer => {
3472 var limbs: [std.math.big.int.calcLimbLen(0)]std.math.big.Limb = undefined;
3473 const bigint = std.math.big.int.Mutable.init(&limbs, 0);
3474 return self.bigIntConstAssumeCapacity(ty, bigint.toConst()) catch unreachable;
3475 },
3476 .pointer => return self.nullConstAssumeCapacity(ty),
3477 .target,
3478 .vector,
3479 .scalable_vector,
3480 .small_array,
3481 .array,
3482 .structure,
3483 .packed_structure,
3484 .named_structure,
3485 => {},
3486 },
3371 }3487 }
3372 const result = self.getOrPutConstantNoExtraAssumeCapacity(3488 const result = self.getOrPutConstantNoExtraAssumeCapacity(
3373 .{ .tag = .zeroinitializer, .data = @intFromEnum(ty) },3489 .{ .tag = .zeroinitializer, .data = @intFromEnum(ty) },
...@@ -4034,7 +4150,10 @@ pub inline fn useLibLlvm(self: *const Builder) bool {...@@ -4034,7 +4150,10 @@ pub inline fn useLibLlvm(self: *const Builder) bool {
4034const assert = std.debug.assert;4150const assert = std.debug.assert;
4035const build_options = @import("build_options");4151const build_options = @import("build_options");
4036const builtin = @import("builtin");4152const builtin = @import("builtin");
4037const llvm = @import("bindings.zig");4153const llvm = if (build_options.have_llvm)
4154 @import("bindings.zig")
4155else
4156 @compileError("LLVM unavailable");
4038const log = std.log.scoped(.llvm);4157const log = std.log.scoped(.llvm);
4039const std = @import("std");4158const std = @import("std");
40404159