authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-05-31 18:25:57-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-05-31 18:25:57-07:00
log2f9533f639311f680f3080747aa03b411ca63100
tree6ea7b61114cdbdfab7b87069810e624e834183a9
parent356a865b871db458149f70bc103a3971780d6962

LLVM: pass slices as ptr/len combo

LLVM optimization passes handle this better, and it allows Zig to specify pointer parameter attributes such as readonly, nonnull, noalias, and alignment. closes #561

1 files changed, 63 insertions(+), 7 deletions(-)

src/codegen/llvm.zig+63-7
...@@ -712,6 +712,7 @@ pub const Object = struct {...@@ -712,6 +712,7 @@ pub const Object = struct {
712 .byval => {712 .byval => {
713 const param_ty = fn_info.param_types[it.zig_index - 1];713 const param_ty = fn_info.param_types[it.zig_index - 1];
714 const param = llvm_func.getParam(llvm_arg_i);714 const param = llvm_func.getParam(llvm_arg_i);
715 try args.ensureUnusedCapacity(1);
715716
716 if (isByRef(param_ty)) {717 if (isByRef(param_ty)) {
717 const alignment = param_ty.abiAlignment(target);718 const alignment = param_ty.abiAlignment(target);
...@@ -720,9 +721,9 @@ pub const Object = struct {...@@ -720,9 +721,9 @@ pub const Object = struct {
720 arg_ptr.setAlignment(alignment);721 arg_ptr.setAlignment(alignment);
721 const store_inst = builder.buildStore(param, arg_ptr);722 const store_inst = builder.buildStore(param, arg_ptr);
722 store_inst.setAlignment(alignment);723 store_inst.setAlignment(alignment);
723 try args.append(arg_ptr);724 args.appendAssumeCapacity(arg_ptr);
724 } else {725 } else {
725 try args.append(param);726 args.appendAssumeCapacity(param);
726727
727 if (param_ty.isPtrAtRuntime()) {728 if (param_ty.isPtrAtRuntime()) {
728 const ptr_info = param_ty.ptrInfo().data;729 const ptr_info = param_ty.ptrInfo().data;
...@@ -756,13 +757,15 @@ pub const Object = struct {...@@ -756,13 +757,15 @@ pub const Object = struct {
756757
757 llvm_arg_i += 1;758 llvm_arg_i += 1;
758759
760 try args.ensureUnusedCapacity(1);
761
759 if (isByRef(param_ty)) {762 if (isByRef(param_ty)) {
760 try args.append(param);763 args.appendAssumeCapacity(param);
761 } else {764 } else {
762 const alignment = param_ty.abiAlignment(target);765 const alignment = param_ty.abiAlignment(target);
763 const load_inst = builder.buildLoad(param, "");766 const load_inst = builder.buildLoad(param, "");
764 load_inst.setAlignment(alignment);767 load_inst.setAlignment(alignment);
765 try args.append(load_inst);768 args.appendAssumeCapacity(load_inst);
766 }769 }
767 },770 },
768 .abi_sized_int => {771 .abi_sized_int => {
...@@ -784,14 +787,44 @@ pub const Object = struct {...@@ -784,14 +787,44 @@ pub const Object = struct {
784 const store_inst = builder.buildStore(param, casted_ptr);787 const store_inst = builder.buildStore(param, casted_ptr);
785 store_inst.setAlignment(alignment);788 store_inst.setAlignment(alignment);
786789
790 try args.ensureUnusedCapacity(1);
791
787 if (isByRef(param_ty)) {792 if (isByRef(param_ty)) {
788 try args.append(arg_ptr);793 args.appendAssumeCapacity(arg_ptr);
789 } else {794 } else {
790 const load_inst = builder.buildLoad(arg_ptr, "");795 const load_inst = builder.buildLoad(arg_ptr, "");
791 load_inst.setAlignment(alignment);796 load_inst.setAlignment(alignment);
792 try args.append(load_inst);797 args.appendAssumeCapacity(load_inst);
793 }798 }
794 },799 },
800 .slice => {
801 const param_ty = fn_info.param_types[it.zig_index - 1];
802 const ptr_info = param_ty.ptrInfo().data;
803
804 if (math.cast(u5, it.zig_index - 1)) |i| {
805 if (@truncate(u1, fn_info.noalias_bits >> i) != 0) {
806 dg.addArgAttr(llvm_func, llvm_arg_i, "noalias");
807 }
808 }
809 dg.addArgAttr(llvm_func, llvm_arg_i, "nonnull");
810 if (!ptr_info.mutable) {
811 dg.addArgAttr(llvm_func, llvm_arg_i, "readonly");
812 }
813 if (ptr_info.@"align" != 0) {
814 dg.addArgAttrInt(llvm_func, llvm_arg_i, "align", ptr_info.@"align");
815 } else {
816 dg.addArgAttrInt(llvm_func, llvm_arg_i, "align", ptr_info.pointee_type.abiAlignment(target));
817 }
818 const ptr_param = llvm_func.getParam(llvm_arg_i);
819 llvm_arg_i += 1;
820 const len_param = llvm_func.getParam(llvm_arg_i);
821 llvm_arg_i += 1;
822
823 const slice_llvm_ty = try dg.lowerType(param_ty);
824 const partial = builder.buildInsertValue(slice_llvm_ty.getUndef(), ptr_param, 0, "");
825 const aggregate = builder.buildInsertValue(partial, len_param, 1, "");
826 try args.append(aggregate);
827 },
795 .multiple_llvm_ints => {828 .multiple_llvm_ints => {
796 const param_ty = fn_info.param_types[it.zig_index - 1];829 const param_ty = fn_info.param_types[it.zig_index - 1];
797 const llvm_ints = it.llvm_types_buffer[0..it.llvm_types_len];830 const llvm_ints = it.llvm_types_buffer[0..it.llvm_types_len];
...@@ -2743,6 +2776,17 @@ pub const DeclGen = struct {...@@ -2743,6 +2776,17 @@ pub const DeclGen = struct {
2743 const abi_size = @intCast(c_uint, param_ty.abiSize(target));2776 const abi_size = @intCast(c_uint, param_ty.abiSize(target));
2744 try llvm_params.append(dg.context.intType(abi_size * 8));2777 try llvm_params.append(dg.context.intType(abi_size * 8));
2745 },2778 },
2779 .slice => {
2780 const param_ty = fn_info.param_types[it.zig_index - 1];
2781 var buf: Type.SlicePtrFieldTypeBuffer = undefined;
2782 const ptr_ty = param_ty.slicePtrFieldType(&buf);
2783 const ptr_llvm_ty = try dg.lowerType(ptr_ty);
2784 const len_llvm_ty = try dg.lowerType(Type.usize);
2785
2786 try llvm_params.ensureUnusedCapacity(2);
2787 llvm_params.appendAssumeCapacity(ptr_llvm_ty);
2788 llvm_params.appendAssumeCapacity(len_llvm_ty);
2789 },
2746 .multiple_llvm_ints => {2790 .multiple_llvm_ints => {
2747 const param_ty = fn_info.param_types[it.zig_index - 1];2791 const param_ty = fn_info.param_types[it.zig_index - 1];
2748 const llvm_ints = it.llvm_types_buffer[0..it.llvm_types_len];2792 const llvm_ints = it.llvm_types_buffer[0..it.llvm_types_len];
...@@ -4205,6 +4249,15 @@ pub const FuncGen = struct {...@@ -4205,6 +4249,15 @@ pub const FuncGen = struct {
4205 try llvm_args.append(load_inst);4249 try llvm_args.append(load_inst);
4206 }4250 }
4207 },4251 },
4252 .slice => {
4253 const arg = args[it.zig_index - 1];
4254 const llvm_arg = try self.resolveInst(arg);
4255 const ptr = self.builder.buildExtractValue(llvm_arg, 0, "");
4256 const len = self.builder.buildExtractValue(llvm_arg, 1, "");
4257 try llvm_args.ensureUnusedCapacity(2);
4258 llvm_args.appendAssumeCapacity(ptr);
4259 llvm_args.appendAssumeCapacity(len);
4260 },
4208 .multiple_llvm_ints => {4261 .multiple_llvm_ints => {
4209 const arg = args[it.zig_index - 1];4262 const arg = args[it.zig_index - 1];
4210 const param_ty = self.air.typeOf(arg);4263 const param_ty = self.air.typeOf(arg);
...@@ -8811,6 +8864,7 @@ const ParamTypeIterator = struct {...@@ -8811,6 +8864,7 @@ const ParamTypeIterator = struct {
8811 byref,8864 byref,
8812 abi_sized_int,8865 abi_sized_int,
8813 multiple_llvm_ints,8866 multiple_llvm_ints,
8867 slice,
8814 };8868 };
88158869
8816 fn next(it: *ParamTypeIterator) ?Lowering {8870 fn next(it: *ParamTypeIterator) ?Lowering {
...@@ -8826,7 +8880,9 @@ const ParamTypeIterator = struct {...@@ -8826,7 +8880,9 @@ const ParamTypeIterator = struct {
8826 .Unspecified, .Inline => {8880 .Unspecified, .Inline => {
8827 it.zig_index += 1;8881 it.zig_index += 1;
8828 it.llvm_index += 1;8882 it.llvm_index += 1;
8829 if (isByRef(ty)) {8883 if (ty.isSlice()) {
8884 return .slice;
8885 } else if (isByRef(ty)) {
8830 return .byref;8886 return .byref;
8831 } else {8887 } else {
8832 return .byval;8888 return .byval;