| ... | @@ -6776,8 +6776,9 @@ pub const FuncGen = struct { | ... | @@ -6776,8 +6776,9 @@ pub const FuncGen = struct { |
| 6776 | const max_return_count = outputs.len; | 6776 | const max_return_count = outputs.len; |
| 6777 | const llvm_ret_types = try arena.alloc(Builder.Type, max_return_count); | 6777 | const llvm_ret_types = try arena.alloc(Builder.Type, max_return_count); |
| 6778 | const llvm_ret_indirect = try arena.alloc(bool, max_return_count); | 6778 | const llvm_ret_indirect = try arena.alloc(bool, max_return_count); |
| | 6779 | const llvm_rw_vals = try arena.alloc(Builder.Value, max_return_count); |
| 6779 | | 6780 | |
| 6780 | const max_param_count = inputs.len + outputs.len; | 6781 | const max_param_count = max_return_count + inputs.len + outputs.len; |
| 6781 | const llvm_param_types = try arena.alloc(Builder.Type, max_param_count); | 6782 | const llvm_param_types = try arena.alloc(Builder.Type, max_param_count); |
| 6782 | const llvm_param_values = try arena.alloc(Builder.Value, max_param_count); | 6783 | const llvm_param_values = try arena.alloc(Builder.Value, max_param_count); |
| 6783 | // This stores whether we need to add an elementtype attribute and | 6784 | // This stores whether we need to add an elementtype attribute and |
| ... | @@ -6793,7 +6794,8 @@ pub const FuncGen = struct { | ... | @@ -6793,7 +6794,8 @@ pub const FuncGen = struct { |
| 6793 | var name_map: std.StringArrayHashMapUnmanaged(u16) = .{}; | 6794 | var name_map: std.StringArrayHashMapUnmanaged(u16) = .{}; |
| 6794 | try name_map.ensureUnusedCapacity(arena, max_param_count); | 6795 | try name_map.ensureUnusedCapacity(arena, max_param_count); |
| 6795 | | 6796 | |
| 6796 | for (outputs, 0..) |output, i| { | 6797 | var rw_extra_i = extra_i; |
| | 6798 | for (outputs, llvm_ret_indirect, llvm_rw_vals) |output, *is_indirect, *llvm_rw_val| { |
| 6797 | const extra_bytes = std.mem.sliceAsBytes(self.air.extra[extra_i..]); | 6799 | const extra_bytes = std.mem.sliceAsBytes(self.air.extra[extra_i..]); |
| 6798 | const constraint = std.mem.sliceTo(std.mem.sliceAsBytes(self.air.extra[extra_i..]), 0); | 6800 | const constraint = std.mem.sliceTo(std.mem.sliceAsBytes(self.air.extra[extra_i..]), 0); |
| 6799 | const name = std.mem.sliceTo(extra_bytes[constraint.len + 1 ..], 0); | 6801 | const name = std.mem.sliceTo(extra_bytes[constraint.len + 1 ..], 0); |
| ... | @@ -6808,14 +6810,22 @@ pub const FuncGen = struct { | ... | @@ -6808,14 +6810,22 @@ pub const FuncGen = struct { |
| 6808 | llvm_constraints.appendAssumeCapacity('='); | 6810 | llvm_constraints.appendAssumeCapacity('='); |
| 6809 | | 6811 | |
| 6810 | // Pass any non-return outputs indirectly, if the constraint accepts a memory location | 6812 | // Pass any non-return outputs indirectly, if the constraint accepts a memory location |
| 6811 | llvm_ret_indirect[i] = (output != .none) and constraintAllowsMemory(constraint); | 6813 | is_indirect.* = (output != .none) and constraintAllowsMemory(constraint); |
| 6812 | if (output != .none) { | 6814 | if (output != .none) { |
| 6813 | const output_inst = try self.resolveInst(output); | 6815 | const output_inst = try self.resolveInst(output); |
| 6814 | const output_ty = self.typeOf(output); | 6816 | const output_ty = self.typeOf(output); |
| 6815 | assert(output_ty.zigTypeTag(mod) == .Pointer); | 6817 | assert(output_ty.zigTypeTag(mod) == .Pointer); |
| 6816 | const elem_llvm_ty = try o.lowerPtrElemTy(output_ty.childType(mod)); | 6818 | const elem_llvm_ty = try o.lowerPtrElemTy(output_ty.childType(mod)); |
| 6817 | | 6819 | |
| 6818 | if (llvm_ret_indirect[i]) { | 6820 | switch (constraint[0]) { |
| | 6821 | '=' => {}, |
| | 6822 | '+' => llvm_rw_val.* = output_inst, |
| | 6823 | else => return self.todo("unsupported output constraint on output type '{c}'", .{ |
| | 6824 | constraint[0], |
| | 6825 | }), |
| | 6826 | } |
| | 6827 | |
| | 6828 | if (is_indirect.*) { |
| 6819 | // Pass the result by reference as an indirect output (e.g. "=*m") | 6829 | // Pass the result by reference as an indirect output (e.g. "=*m") |
| 6820 | llvm_constraints.appendAssumeCapacity('*'); | 6830 | llvm_constraints.appendAssumeCapacity('*'); |
| 6821 | | 6831 | |
| ... | @@ -6829,6 +6839,13 @@ pub const FuncGen = struct { | ... | @@ -6829,6 +6839,13 @@ pub const FuncGen = struct { |
| 6829 | llvm_ret_i += 1; | 6839 | llvm_ret_i += 1; |
| 6830 | } | 6840 | } |
| 6831 | } else { | 6841 | } else { |
| | 6842 | switch (constraint[0]) { |
| | 6843 | '=' => {}, |
| | 6844 | else => return self.todo("unsupported output constraint on result type '{c}'", .{ |
| | 6845 | constraint[0], |
| | 6846 | }), |
| | 6847 | } |
| | 6848 | |
| 6832 | const ret_ty = self.typeOfIndex(inst); | 6849 | const ret_ty = self.typeOfIndex(inst); |
| 6833 | llvm_ret_types[llvm_ret_i] = try o.lowerType(ret_ty); | 6850 | llvm_ret_types[llvm_ret_i] = try o.lowerType(ret_ty); |
| 6834 | llvm_ret_i += 1; | 6851 | llvm_ret_i += 1; |
| ... | @@ -6865,9 +6882,8 @@ pub const FuncGen = struct { | ... | @@ -6865,9 +6882,8 @@ pub const FuncGen = struct { |
| 6865 | | 6882 | |
| 6866 | const arg_llvm_value = try self.resolveInst(input); | 6883 | const arg_llvm_value = try self.resolveInst(input); |
| 6867 | const arg_ty = self.typeOf(input); | 6884 | const arg_ty = self.typeOf(input); |
| 6868 | var llvm_elem_ty: Builder.Type = .none; | 6885 | const is_by_ref = isByRef(arg_ty, mod); |
| 6869 | if (isByRef(arg_ty, mod)) { | 6886 | if (is_by_ref) { |
| 6870 | llvm_elem_ty = try o.lowerPtrElemTy(arg_ty); | | |
| 6871 | if (constraintAllowsMemory(constraint)) { | 6887 | if (constraintAllowsMemory(constraint)) { |
| 6872 | llvm_param_values[llvm_param_i] = arg_llvm_value; | 6888 | llvm_param_values[llvm_param_i] = arg_llvm_value; |
| 6873 | llvm_param_types[llvm_param_i] = arg_llvm_value.typeOfWip(&self.wip); | 6889 | llvm_param_types[llvm_param_i] = arg_llvm_value.typeOfWip(&self.wip); |
| ... | @@ -6911,15 +6927,43 @@ pub const FuncGen = struct { | ... | @@ -6911,15 +6927,43 @@ pub const FuncGen = struct { |
| 6911 | | 6927 | |
| 6912 | // In the case of indirect inputs, LLVM requires the callsite to have | 6928 | // In the case of indirect inputs, LLVM requires the callsite to have |
| 6913 | // an elementtype(<ty>) attribute. | 6929 | // an elementtype(<ty>) attribute. |
| 6914 | if (constraint[0] == '*') { | 6930 | llvm_param_attrs[llvm_param_i] = if (constraint[0] == '*') |
| 6915 | llvm_param_attrs[llvm_param_i] = if (llvm_elem_ty != .none) | 6931 | try o.lowerPtrElemTy(if (is_by_ref) arg_ty else arg_ty.childType(mod)) |
| 6916 | llvm_elem_ty | 6932 | else |
| 6917 | else | 6933 | .none; |
| 6918 | try o.lowerPtrElemTy(arg_ty.childType(mod)); | 6934 | |
| | 6935 | llvm_param_i += 1; |
| | 6936 | total_i += 1; |
| | 6937 | } |
| | 6938 | |
| | 6939 | for (outputs, llvm_ret_indirect, llvm_rw_vals, 0..) |output, is_indirect, llvm_rw_val, output_index| { |
| | 6940 | const extra_bytes = std.mem.sliceAsBytes(self.air.extra[rw_extra_i..]); |
| | 6941 | const constraint = std.mem.sliceTo(std.mem.sliceAsBytes(self.air.extra[rw_extra_i..]), 0); |
| | 6942 | const name = std.mem.sliceTo(extra_bytes[constraint.len + 1 ..], 0); |
| | 6943 | // This equation accounts for the fact that even if we have exactly 4 bytes |
| | 6944 | // for the string, we still use the next u32 for the null terminator. |
| | 6945 | rw_extra_i += (constraint.len + name.len + (2 + 3)) / 4; |
| | 6946 | |
| | 6947 | if (constraint[0] != '+') continue; |
| | 6948 | |
| | 6949 | const rw_ty = self.typeOf(output); |
| | 6950 | const llvm_elem_ty = try o.lowerPtrElemTy(rw_ty.childType(mod)); |
| | 6951 | if (is_indirect) { |
| | 6952 | llvm_param_values[llvm_param_i] = llvm_rw_val; |
| | 6953 | llvm_param_types[llvm_param_i] = llvm_rw_val.typeOfWip(&self.wip); |
| 6919 | } else { | 6954 | } else { |
| 6920 | llvm_param_attrs[llvm_param_i] = .none; | 6955 | const alignment = Builder.Alignment.fromByteUnits(rw_ty.abiAlignment(mod)); |
| | 6956 | const loaded = try self.wip.load(.normal, llvm_elem_ty, llvm_rw_val, alignment, ""); |
| | 6957 | llvm_param_values[llvm_param_i] = loaded; |
| | 6958 | llvm_param_types[llvm_param_i] = llvm_elem_ty; |
| 6921 | } | 6959 | } |
| 6922 | | 6960 | |
| | 6961 | try llvm_constraints.writer(self.gpa).print(",{d}", .{output_index}); |
| | 6962 | |
| | 6963 | // In the case of indirect inputs, LLVM requires the callsite to have |
| | 6964 | // an elementtype(<ty>) attribute. |
| | 6965 | llvm_param_attrs[llvm_param_i] = if (is_indirect) llvm_elem_ty else .none; |
| | 6966 | |
| 6923 | llvm_param_i += 1; | 6967 | llvm_param_i += 1; |
| 6924 | total_i += 1; | 6968 | total_i += 1; |
| 6925 | } | 6969 | } |