| ... | ... | @@ -8,7 +8,10 @@ const native_endian = builtin.cpu.arch.endian(); |
| 8 | 8 | const DW = std.dwarf; |
| 9 | 9 | |
| 10 | 10 | const Builder = @import("llvm/Builder.zig"); |
| 11 | | const llvm = @import("llvm/bindings.zig"); |
| 11 | const llvm = if (build_options.have_llvm) |
| 12 | @import("llvm/bindings.zig") |
| 13 | else |
| 14 | @compileError("LLVM unavailable"); |
| 12 | 15 | const link = @import("../link.zig"); |
| 13 | 16 | const Compilation = @import("../Compilation.zig"); |
| 14 | 17 | const build_options = @import("build_options"); |
| ... | ... | @@ -577,7 +580,7 @@ pub const Object = struct { |
| 577 | 580 | extern_collisions: std.AutoArrayHashMapUnmanaged(Module.Decl.Index, void), |
| 578 | 581 | |
| 579 | 582 | /// Memoizes a null `?usize` value. |
| 580 | | null_opt_addr: ?*llvm.Value, |
| 583 | null_opt_usize: Builder.Constant, |
| 581 | 584 | |
| 582 | 585 | pub const TypeMap = std.AutoHashMapUnmanaged(InternPool.Index, Builder.Type); |
| 583 | 586 | |
| ... | ... | @@ -733,7 +736,7 @@ pub const Object = struct { |
| 733 | 736 | .di_type_map = .{}, |
| 734 | 737 | .error_name_table = .none, |
| 735 | 738 | .extern_collisions = .{}, |
| 736 | | .null_opt_addr = null, |
| 739 | .null_opt_usize = .no_init, |
| 737 | 740 | }; |
| 738 | 741 | } |
| 739 | 742 | |
| ... | ... | @@ -789,31 +792,31 @@ pub const Object = struct { |
| 789 | 792 | const name = try o.builder.string(mod.intern_pool.stringToSlice(name_nts)); |
| 790 | 793 | const str_init = try o.builder.stringNullConst(name); |
| 791 | 794 | const str_ty = str_init.typeOf(&o.builder); |
| 792 | | const str_global = o.llvm_module.addGlobal(str_ty.toLlvm(&o.builder), ""); |
| 793 | | str_global.setInitializer(str_init.toLlvm(&o.builder)); |
| 794 | | str_global.setLinkage(.Private); |
| 795 | | str_global.setGlobalConstant(.True); |
| 796 | | str_global.setUnnamedAddr(.True); |
| 797 | | str_global.setAlignment(1); |
| 798 | | |
| 799 | | var global = Builder.Global{ |
| 795 | const str_llvm_global = o.llvm_module.addGlobal(str_ty.toLlvm(&o.builder), ""); |
| 796 | str_llvm_global.setInitializer(str_init.toLlvm(&o.builder)); |
| 797 | str_llvm_global.setLinkage(.Private); |
| 798 | str_llvm_global.setGlobalConstant(.True); |
| 799 | str_llvm_global.setUnnamedAddr(.True); |
| 800 | str_llvm_global.setAlignment(1); |
| 801 | |
| 802 | var str_global = Builder.Global{ |
| 800 | 803 | .linkage = .private, |
| 801 | 804 | .unnamed_addr = .unnamed_addr, |
| 802 | 805 | .type = str_ty, |
| 803 | 806 | .alignment = comptime Builder.Alignment.fromByteUnits(1), |
| 804 | 807 | .kind = .{ .variable = @enumFromInt(o.builder.variables.items.len) }, |
| 805 | 808 | }; |
| 806 | | var variable = Builder.Variable{ |
| 809 | var str_variable = Builder.Variable{ |
| 807 | 810 | .global = @enumFromInt(o.builder.globals.count()), |
| 808 | 811 | .mutability = .constant, |
| 809 | 812 | .init = str_init, |
| 810 | 813 | }; |
| 811 | | try o.builder.llvm.globals.append(o.gpa, str_global); |
| 812 | | const str_global_index = try o.builder.addGlobal(.empty, global); |
| 813 | | try o.builder.variables.append(o.gpa, variable); |
| 814 | try o.builder.llvm.globals.append(o.gpa, str_llvm_global); |
| 815 | const global_index = try o.builder.addGlobal(.empty, str_global); |
| 816 | try o.builder.variables.append(o.gpa, str_variable); |
| 814 | 817 | |
| 815 | 818 | llvm_error.* = try o.builder.structConst(llvm_slice_ty, &.{ |
| 816 | | str_global_index.toConst(), |
| 819 | global_index.toConst(), |
| 817 | 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 | 2687 | return buffer.toOwnedSliceSentinel(0); |
| 2685 | 2688 | } |
| 2686 | 2689 | |
| 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 | 2690 | /// If the llvm function does not exist, create it. |
| 2737 | 2691 | /// Note that this can be called before the function's semantic analysis has |
| 2738 | 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 | 3709 | }, |
| 3756 | 3710 | }, |
| 3757 | 3711 | .vector_type => |vector_type| { |
| 3758 | | const ExpectedContents = [Builder.expected_fields_len]Builder.Constant; |
| 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 | | |
| 3712 | const vector_ty = try o.lowerType(ty); |
| 3767 | 3713 | switch (aggregate.storage) { |
| 3768 | | .bytes => |bytes| for (vals, bytes) |*result_val, byte| { |
| 3769 | | result_val.* = try o.builder.intConst(.i8, byte); |
| 3770 | | }, |
| 3771 | | .elems => |elems| for (vals, elems) |*result_val, elem| { |
| 3772 | | result_val.* = try o.lowerValue(elem); |
| 3714 | .bytes, .elems => { |
| 3715 | const ExpectedContents = [Builder.expected_fields_len]Builder.Constant; |
| 3716 | var stack align(@max( |
| 3717 | @alignOf(std.heap.StackFallbackAllocator(0)), |
| 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 | 3741 | .anon_struct_type => |tuple| { |
| 3779 | 3742 | const struct_ty = try o.lowerType(ty); |
| ... | ... | @@ -4209,14 +4172,11 @@ pub const Object = struct { |
| 4209 | 4172 | else |
| 4210 | 4173 | (try o.resolveGlobalDecl(decl_index)).ptrConst(&o.builder).global; |
| 4211 | 4174 | |
| 4212 | | const target = mod.getTarget(); |
| 4213 | | const llvm_wanted_addrspace = toLlvmAddressSpace(decl.@"addrspace", target); |
| 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, |
| 4175 | const llvm_val = try o.builder.convConst( |
| 4176 | .unneeded, |
| 4217 | 4177 | llvm_global.toConst(), |
| 4218 | | try o.builder.ptrType(llvm_wanted_addrspace), |
| 4219 | | ) else llvm_global.toConst(); |
| 4178 | try o.builder.ptrType(toLlvmAddressSpace(decl.@"addrspace", mod.getTarget())), |
| 4179 | ); |
| 4220 | 4180 | |
| 4221 | 4181 | return o.builder.convConst(if (ty.isAbiInt(mod)) switch (ty.intInfo(mod).signedness) { |
| 4222 | 4182 | .signed => .signed, |
| ... | ... | @@ -4618,15 +4578,15 @@ pub const FuncGen = struct { |
| 4618 | 4578 | .ty = self.typeOf(inst), |
| 4619 | 4579 | .val = (try self.air.value(inst, mod)).?, |
| 4620 | 4580 | }); |
| 4621 | | gop.value_ptr.* = llvm_val; |
| 4622 | | return llvm_val; |
| 4581 | gop.value_ptr.* = llvm_val.toLlvm(&o.builder); |
| 4582 | return gop.value_ptr.*; |
| 4623 | 4583 | } |
| 4624 | 4584 | |
| 4625 | | fn resolveValue(self: *FuncGen, tv: TypedValue) !*llvm.Value { |
| 4585 | fn resolveValue(self: *FuncGen, tv: TypedValue) Error!Builder.Constant { |
| 4626 | 4586 | const o = self.dg.object; |
| 4627 | 4587 | const mod = o.module; |
| 4628 | 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; |
| 4630 | 4590 | |
| 4631 | 4591 | // We have an LLVM value but we need to create a global constant and |
| 4632 | 4592 | // set the value as its initializer, and then return a pointer to the global. |
| ... | ... | @@ -4645,6 +4605,7 @@ pub const FuncGen = struct { |
| 4645 | 4605 | var global = Builder.Global{ |
| 4646 | 4606 | .linkage = .private, |
| 4647 | 4607 | .unnamed_addr = .unnamed_addr, |
| 4608 | .addr_space = llvm_actual_addrspace, |
| 4648 | 4609 | .type = llvm_ty, |
| 4649 | 4610 | .alignment = Builder.Alignment.fromByteUnits(llvm_alignment), |
| 4650 | 4611 | .kind = .{ .variable = @enumFromInt(o.builder.variables.items.len) }, |
| ... | ... | @@ -4655,16 +4616,27 @@ pub const FuncGen = struct { |
| 4655 | 4616 | .init = llvm_val, |
| 4656 | 4617 | }; |
| 4657 | 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 | 4620 | try o.builder.variables.append(o.gpa, variable); |
| 4660 | 4621 | |
| 4661 | | const addrspace_casted_ptr = if (llvm_actual_addrspace != llvm_wanted_addrspace) |
| 4662 | | llvm_global.constAddrSpaceCast( |
| 4663 | | (try o.builder.ptrType(llvm_wanted_addrspace)).toLlvm(&o.builder), |
| 4664 | | ) |
| 4665 | | else |
| 4666 | | llvm_global; |
| 4667 | | return addrspace_casted_ptr; |
| 4622 | return try o.builder.convConst( |
| 4623 | .unneeded, |
| 4624 | global_index.toConst(), |
| 4625 | try o.builder.ptrType(llvm_wanted_addrspace), |
| 4626 | ); |
| 4627 | } |
| 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 | } |
| 4669 | 4641 | |
| 4670 | 4642 | fn genBody(self: *FuncGen, body: []const Air.Inst.Index) Error!void { |
| ... | ... | @@ -5243,7 +5215,7 @@ pub const FuncGen = struct { |
| 5243 | 5215 | const msg_decl = mod.declPtr(msg_decl_index); |
| 5244 | 5216 | const msg_len = msg_decl.ty.childType(mod).arrayLen(mod); |
| 5245 | 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 | 5219 | const target = mod.getTarget(); |
| 5248 | 5220 | const llvm_usize = try o.lowerType(Type.usize); |
| 5249 | 5221 | // example: |
| ... | ... | @@ -5257,7 +5229,7 @@ pub const FuncGen = struct { |
| 5257 | 5229 | msg_ptr.toLlvm(&o.builder), |
| 5258 | 5230 | (try o.builder.intConst(llvm_usize, msg_len)).toLlvm(&o.builder), |
| 5259 | 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 | 5234 | const panic_func = mod.funcInfo(mod.panic_func_index); |
| 5263 | 5235 | const panic_decl = mod.declPtr(panic_func.owner_decl); |
| ... | ... | @@ -6872,11 +6844,11 @@ pub const FuncGen = struct { |
| 6872 | 6844 | const operand = try self.resolveInst(un_op); |
| 6873 | 6845 | const operand_ty = self.typeOf(un_op); |
| 6874 | 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 | 6848 | const payload_ty = optional_ty.optionalChild(mod); |
| 6877 | 6849 | if (optional_ty.optionalReprIsPayload(mod)) { |
| 6878 | 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 | 6852 | else |
| 6881 | 6853 | operand; |
| 6882 | 6854 | if (payload_ty.isSlice(mod)) { |
| ... | ... | @@ -6887,21 +6859,21 @@ pub const FuncGen = struct { |
| 6887 | 6859 | )); |
| 6888 | 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 | } |
| 6892 | 6864 | |
| 6893 | 6865 | comptime assert(optional_layout_version == 3); |
| 6894 | 6866 | |
| 6895 | 6867 | if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) { |
| 6896 | 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 | 6870 | else |
| 6899 | 6871 | operand; |
| 6900 | 6872 | return self.builder.buildICmp(pred, loaded, (try o.builder.intConst(.i8, 0)).toLlvm(&o.builder), ""); |
| 6901 | 6873 | } |
| 6902 | 6874 | |
| 6903 | 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 | 6877 | if (pred == .EQ) { |
| 6906 | 6878 | return self.builder.buildNot(non_null_bit, ""); |
| 6907 | 6879 | } else { |
| ... | ... | @@ -7549,24 +7521,18 @@ pub const FuncGen = struct { |
| 7549 | 7521 | } |
| 7550 | 7522 | if (scalar_ty.isSignedInt(mod)) { |
| 7551 | 7523 | const inst_llvm_ty = try o.lowerType(inst_ty); |
| 7552 | | const scalar_bit_size_minus_one = scalar_ty.bitSize(mod) - 1; |
| 7553 | | const bit_size_minus_one = if (inst_ty.zigTypeTag(mod) == .Vector) const_vector: { |
| 7554 | | const vec_len = inst_ty.vectorLen(mod); |
| 7555 | | |
| 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); |
| 7524 | const bit_size_minus_one = try o.builder.splatConst(inst_llvm_ty, try o.builder.intConst( |
| 7525 | inst_llvm_ty.scalarType(&o.builder), |
| 7526 | inst_llvm_ty.scalarBits(&o.builder) - 1, |
| 7527 | )); |
| 7562 | 7528 | |
| 7563 | 7529 | const div = self.builder.buildSDiv(lhs, rhs, ""); |
| 7564 | 7530 | const rem = self.builder.buildSRem(lhs, rhs, ""); |
| 7565 | 7531 | const div_sign = self.builder.buildXor(lhs, rhs, ""); |
| 7566 | | const div_sign_mask = self.builder.buildAShr(div_sign, bit_size_minus_one, ""); |
| 7567 | | const zero = inst_llvm_ty.toLlvm(&o.builder).constNull(); |
| 7568 | | const rem_nonzero = self.builder.buildICmp(.NE, rem, zero, ""); |
| 7569 | | const correction = self.builder.buildSelect(rem_nonzero, div_sign_mask, zero, ""); |
| 7532 | const div_sign_mask = self.builder.buildAShr(div_sign, bit_size_minus_one.toLlvm(&o.builder), ""); |
| 7533 | const zero = try o.builder.zeroInitConst(inst_llvm_ty); |
| 7534 | const rem_nonzero = self.builder.buildICmp(.NE, rem, zero.toLlvm(&o.builder), ""); |
| 7535 | const correction = self.builder.buildSelect(rem_nonzero, div_sign_mask, zero.toLlvm(&o.builder), ""); |
| 7570 | 7536 | return self.builder.buildNSWAdd(div, correction, ""); |
| 7571 | 7537 | } |
| 7572 | 7538 | return self.builder.buildUDiv(lhs, rhs, ""); |
| ... | ... | @@ -7620,29 +7586,23 @@ pub const FuncGen = struct { |
| 7620 | 7586 | const a = try self.buildFloatOp(.fmod, inst_ty, 2, .{ lhs, rhs }); |
| 7621 | 7587 | const b = try self.buildFloatOp(.add, inst_ty, 2, .{ a, rhs }); |
| 7622 | 7588 | const c = try self.buildFloatOp(.fmod, inst_ty, 2, .{ b, rhs }); |
| 7623 | | const zero = inst_llvm_ty.toLlvm(&o.builder).constNull(); |
| 7624 | | const ltz = try self.buildFloatCmp(.lt, inst_ty, .{ lhs, zero }); |
| 7589 | const zero = try o.builder.zeroInitConst(inst_llvm_ty); |
| 7590 | const ltz = try self.buildFloatCmp(.lt, inst_ty, .{ lhs, zero.toLlvm(&o.builder) }); |
| 7625 | 7591 | return self.builder.buildSelect(ltz, c, a, ""); |
| 7626 | 7592 | } |
| 7627 | 7593 | if (scalar_ty.isSignedInt(mod)) { |
| 7628 | | const scalar_bit_size_minus_one = scalar_ty.bitSize(mod) - 1; |
| 7629 | | const bit_size_minus_one = if (inst_ty.zigTypeTag(mod) == .Vector) const_vector: { |
| 7630 | | const vec_len = inst_ty.vectorLen(mod); |
| 7631 | | |
| 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); |
| 7594 | const bit_size_minus_one = try o.builder.splatConst(inst_llvm_ty, try o.builder.intConst( |
| 7595 | inst_llvm_ty.scalarType(&o.builder), |
| 7596 | inst_llvm_ty.scalarBits(&o.builder) - 1, |
| 7597 | )); |
| 7638 | 7598 | |
| 7639 | 7599 | const rem = self.builder.buildSRem(lhs, rhs, ""); |
| 7640 | 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 | 7602 | const rhs_masked = self.builder.buildAnd(rhs, div_sign_mask, ""); |
| 7643 | | const zero = inst_llvm_ty.toLlvm(&o.builder).constNull(); |
| 7644 | | const rem_nonzero = self.builder.buildICmp(.NE, rem, zero, ""); |
| 7645 | | const correction = self.builder.buildSelect(rem_nonzero, rhs_masked, zero, ""); |
| 7603 | const zero = try o.builder.zeroInitConst(inst_llvm_ty); |
| 7604 | const rem_nonzero = self.builder.buildICmp(.NE, rem, zero.toLlvm(&o.builder), ""); |
| 7605 | const correction = self.builder.buildSelect(rem_nonzero, rhs_masked, zero.toLlvm(&o.builder), ""); |
| 7646 | 7606 | return self.builder.buildNSWAdd(rem, correction, ""); |
| 7647 | 7607 | } |
| 7648 | 7608 | return self.builder.buildURem(lhs, rhs, ""); |
| ... | ... | @@ -7953,17 +7913,17 @@ pub const FuncGen = struct { |
| 7953 | 7913 | // In this case we can generate a softfloat negation by XORing the |
| 7954 | 7914 | // bits with a constant. |
| 7955 | 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 | 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 | 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 | 7921 | const cast_ty = try o.builder.vectorType(.normal, ty.vectorLen(mod), int_ty); |
| 7962 | 7922 | const bitcasted_operand = self.builder.buildBitCast(params[0], cast_ty.toLlvm(&o.builder), ""); |
| 7963 | 7923 | break :blk self.builder.buildXor(bitcasted_operand, splat_sign_mask, ""); |
| 7964 | 7924 | } else blk: { |
| 7965 | 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 | 7928 | return self.builder.buildBitCast(result, llvm_ty.toLlvm(&o.builder), ""); |
| 7969 | 7929 | }, |
| ... | ... | @@ -8886,9 +8846,9 @@ pub const FuncGen = struct { |
| 8886 | 8846 | const len = try self.sliceOrArrayLenInBytes(dest_slice, ptr_ty); |
| 8887 | 8847 | |
| 8888 | 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 | 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 | 8853 | return null; |
| 8894 | 8854 | } |
| ... | ... | @@ -8987,8 +8947,9 @@ pub const FuncGen = struct { |
| 8987 | 8947 | dest_ptr_align: u32, |
| 8988 | 8948 | is_volatile: bool, |
| 8989 | 8949 | ) !void { |
| 8990 | | const llvm_usize_ty = self.context.intType(self.dg.object.target.ptrBitWidth()); |
| 8991 | | const cond = try self.cmp(len, llvm_usize_ty.constInt(0, .False), Type.usize, .neq); |
| 8950 | const o = self.dg.object; |
| 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 | 8953 | const memset_block = self.context.appendBasicBlock(self.llvm_func, "MemsetTrapSkip"); |
| 8993 | 8954 | const end_block = self.context.appendBasicBlock(self.llvm_func, "MemsetTrapEnd"); |
| 8994 | 8955 | _ = self.builder.buildCondBr(cond, memset_block, end_block); |
| ... | ... | @@ -9020,8 +8981,8 @@ pub const FuncGen = struct { |
| 9020 | 8981 | std.Target.wasm.featureSetHas(o.target.cpu.features, .bulk_memory) and |
| 9021 | 8982 | dest_ptr_ty.isSlice(mod)) |
| 9022 | 8983 | { |
| 9023 | | const llvm_usize_ty = self.context.intType(self.dg.object.target.ptrBitWidth()); |
| 9024 | | const cond = try self.cmp(len, llvm_usize_ty.constInt(0, .False), Type.usize, .neq); |
| 8984 | const llvm_usize_ty = try o.lowerType(Type.usize); |
| 8985 | const cond = try self.cmp(len, (try o.builder.intConst(llvm_usize_ty, 0)).toLlvm(&o.builder), Type.usize, .neq); |
| 9025 | 8986 | const memcpy_block = self.context.appendBasicBlock(self.llvm_func, "MemcpyTrapSkip"); |
| 9026 | 8987 | const end_block = self.context.appendBasicBlock(self.llvm_func, "MemcpyTrapEnd"); |
| 9027 | 8988 | _ = self.builder.buildCondBr(cond, memcpy_block, end_block); |
| ... | ... | @@ -9183,19 +9144,13 @@ pub const FuncGen = struct { |
| 9183 | 9144 | if (operand_ty.zigTypeTag(mod) == .Vector) { |
| 9184 | 9145 | const vec_len = operand_ty.vectorLen(mod); |
| 9185 | 9146 | operand_llvm_ty = try o.builder.vectorType(.normal, vec_len, scalar_ty); |
| 9147 | } else operand_llvm_ty = scalar_ty; |
| 9186 | 9148 | |
| 9187 | | const shifts = try self.gpa.alloc(*llvm.Value, vec_len); |
| 9188 | | defer self.gpa.free(shifts); |
| 9189 | | @memset(shifts, (try o.builder.intConst(scalar_ty, 8)).toLlvm(&o.builder)); |
| 9190 | | const shift_vec = llvm.constVector(shifts.ptr, vec_len); |
| 9149 | const shift_amt = |
| 9150 | try o.builder.splatConst(operand_llvm_ty, try o.builder.intConst(scalar_ty, 8)); |
| 9151 | const extended = self.builder.buildZExt(operand, operand_llvm_ty.toLlvm(&o.builder), ""); |
| 9152 | operand = self.builder.buildShl(extended, shift_amt.toLlvm(&o.builder), ""); |
| 9191 | 9153 | |
| 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 | 9154 | bits = bits + 8; |
| 9200 | 9155 | } |
| 9201 | 9156 | |
| ... | ... | @@ -9358,11 +9313,8 @@ pub const FuncGen = struct { |
| 9358 | 9313 | const fqn = try mod.declPtr(enum_type.decl).getFullyQualifiedName(mod); |
| 9359 | 9314 | const llvm_fn_name = try o.builder.fmt("__zig_tag_name_{}", .{fqn.fmt(&mod.intern_pool)}); |
| 9360 | 9315 | |
| 9361 | | const slice_ty = 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); |
| 9316 | const ret_ty = try o.lowerType(Type.slice_const_u8_sentinel_0); |
| 9364 | 9317 | const usize_ty = try o.lowerType(Type.usize); |
| 9365 | | const slice_alignment = slice_ty.abiAlignment(mod); |
| 9366 | 9318 | |
| 9367 | 9319 | const fn_type = try o.builder.fnType(ret_ty, &.{ |
| 9368 | 9320 | try o.lowerType(enum_type.tag_ty.toType()), |
| ... | ... | @@ -9399,33 +9351,38 @@ pub const FuncGen = struct { |
| 9399 | 9351 | const tag_int_value = fn_val.getParam(0); |
| 9400 | 9352 | const switch_instr = self.builder.buildSwitch(tag_int_value, bad_value_block, @as(c_uint, @intCast(enum_type.names.len))); |
| 9401 | 9353 | |
| 9402 | | const array_ptr_indices: [2]*llvm.Value = .{ |
| 9403 | | (try o.builder.intConst(usize_ty, 0)).toLlvm(&o.builder), |
| 9404 | | } ** 2; |
| 9405 | | |
| 9406 | 9354 | for (enum_type.names, 0..) |name_ip, field_index_usize| { |
| 9407 | 9355 | const field_index = @as(u32, @intCast(field_index_usize)); |
| 9408 | | const name = mod.intern_pool.stringToSlice(name_ip); |
| 9409 | | const str_init = self.context.constString(name.ptr, @as(c_uint, @intCast(name.len)), .False); |
| 9410 | | const str_init_llvm_ty = str_init.typeOf(); |
| 9411 | | const str_global = o.llvm_module.addGlobal(str_init_llvm_ty, ""); |
| 9412 | | str_global.setInitializer(str_init); |
| 9413 | | str_global.setLinkage(.Private); |
| 9414 | | str_global.setGlobalConstant(.True); |
| 9415 | | str_global.setUnnamedAddr(.True); |
| 9416 | | str_global.setAlignment(1); |
| 9417 | | |
| 9418 | | const slice_fields = [_]*llvm.Value{ |
| 9419 | | str_init_llvm_ty.constInBoundsGEP(str_global, &array_ptr_indices, array_ptr_indices.len), |
| 9420 | | (try o.builder.intConst(usize_ty, name.len)).toLlvm(&o.builder), |
| 9356 | const name = try o.builder.string(mod.intern_pool.stringToSlice(name_ip)); |
| 9357 | const str_init = try o.builder.stringNullConst(name); |
| 9358 | const str_ty = str_init.typeOf(&o.builder); |
| 9359 | const str_llvm_global = o.llvm_module.addGlobal(str_ty.toLlvm(&o.builder), ""); |
| 9360 | str_llvm_global.setInitializer(str_init.toLlvm(&o.builder)); |
| 9361 | str_llvm_global.setLinkage(.Private); |
| 9362 | str_llvm_global.setGlobalConstant(.True); |
| 9363 | str_llvm_global.setUnnamedAddr(.True); |
| 9364 | str_llvm_global.setAlignment(1); |
| 9365 | |
| 9366 | var str_global = Builder.Global{ |
| 9367 | .linkage = .private, |
| 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); |
| 9423 | | const slice_global = o.llvm_module.addGlobal(slice_init.typeOf(), ""); |
| 9424 | | slice_global.setInitializer(slice_init); |
| 9425 | | slice_global.setLinkage(.Private); |
| 9426 | | slice_global.setGlobalConstant(.True); |
| 9427 | | slice_global.setUnnamedAddr(.True); |
| 9428 | | slice_global.setAlignment(slice_alignment); |
| 9373 | var str_variable = Builder.Variable{ |
| 9374 | .global = @enumFromInt(o.builder.globals.count()), |
| 9375 | .mutability = .constant, |
| 9376 | .init = str_init, |
| 9377 | }; |
| 9378 | try o.builder.llvm.globals.append(o.gpa, str_llvm_global); |
| 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 | }); |
| 9429 | 9386 | |
| 9430 | 9387 | const return_block = self.context.appendBasicBlock(fn_val, "Name"); |
| 9431 | 9388 | const this_tag_int_value = |
| ... | ... | @@ -9433,9 +9390,7 @@ pub const FuncGen = struct { |
| 9433 | 9390 | switch_instr.addCase(this_tag_int_value.toLlvm(&o.builder), return_block); |
| 9434 | 9391 | |
| 9435 | 9392 | self.builder.positionBuilderAtEnd(return_block); |
| 9436 | | const loaded = self.builder.buildLoad(llvm_ret_ty, slice_global, ""); |
| 9437 | | loaded.setAlignment(slice_alignment); |
| 9438 | | _ = self.builder.buildRet(loaded); |
| 9393 | _ = self.builder.buildRet(slice_val.toLlvm(&o.builder)); |
| 9439 | 9394 | } |
| 9440 | 9395 | |
| 9441 | 9396 | self.builder.positionBuilderAtEnd(bad_value_block); |
| ... | ... | @@ -9530,22 +9485,25 @@ pub const FuncGen = struct { |
| 9530 | 9485 | // when changing code, so Zig uses negative numbers to index the |
| 9531 | 9486 | // second vector. These start at -1 and go down, and are easiest to use |
| 9532 | 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 | 9489 | defer self.gpa.free(values); |
| 9535 | 9490 | |
| 9536 | 9491 | for (values, 0..) |*val, i| { |
| 9537 | 9492 | const elem = try mask.elemValue(mod, i); |
| 9538 | 9493 | if (elem.isUndef(mod)) { |
| 9539 | | val.* = Builder.Type.i32.toLlvm(&o.builder).getUndef(); |
| 9494 | val.* = try o.builder.undefConst(.i32); |
| 9540 | 9495 | } else { |
| 9541 | 9496 | const int = elem.toSignedInt(mod); |
| 9542 | 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 | } |
| 9546 | 9501 | |
| 9547 | | const llvm_mask_value = llvm.constVector(values.ptr, mask_len); |
| 9548 | | return self.builder.buildShuffleVector(a, b, llvm_mask_value, ""); |
| 9502 | const llvm_mask_value = try o.builder.vectorConst( |
| 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 | } |
| 9550 | 9508 | |
| 9551 | 9509 | /// Reduce a vector by repeatedly applying `llvm_fn` to produce an accumulated result. |
| ... | ... | @@ -9816,7 +9774,7 @@ pub const FuncGen = struct { |
| 9816 | 9774 | .val = sent_val, |
| 9817 | 9775 | }); |
| 9818 | 9776 | |
| 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 | } |
| 9821 | 9779 | |
| 9822 | 9780 | return alloca_inst; |
| ... | ... | @@ -10431,12 +10389,13 @@ pub const FuncGen = struct { |
| 10431 | 10389 | else |
| 10432 | 10390 | self.builder.buildBitCast(elem, value_bits_type.toLlvm(&o.builder), ""); |
| 10433 | 10391 | |
| 10434 | | var mask_val = (try o.builder.intConst(value_bits_type, -1)).toLlvm(&o.builder); |
| 10435 | | mask_val = mask_val.constZExt(containing_int_ty.toLlvm(&o.builder)); |
| 10436 | | mask_val = mask_val.constShl(shift_amt.toLlvm(&o.builder)); |
| 10437 | | mask_val = mask_val.constNot(); |
| 10392 | var mask_val = try o.builder.intConst(value_bits_type, -1); |
| 10393 | mask_val = try o.builder.castConst(.zext, mask_val, containing_int_ty); |
| 10394 | mask_val = try o.builder.binConst(.shl, mask_val, shift_amt); |
| 10395 | mask_val = |
| 10396 | try o.builder.binConst(.xor, mask_val, try o.builder.intConst(containing_int_ty, -1)); |
| 10438 | 10397 | |
| 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 | 10399 | const extended_value = self.builder.buildZExt(value_bits, containing_int_ty.toLlvm(&o.builder), ""); |
| 10441 | 10400 | const shifted_value = self.builder.buildShl(extended_value, shift_amt.toLlvm(&o.builder), ""); |
| 10442 | 10401 | const ored_value = self.builder.buildOr(shifted_value, anded_containing_int, ""); |