| ... | @@ -795,7 +795,7 @@ fn genFunctype(gpa: Allocator, fn_info: Type.Payload.Function.Data, target: std. | ... | @@ -795,7 +795,7 @@ fn genFunctype(gpa: Allocator, fn_info: Type.Payload.Function.Data, target: std. |
| 795 | var returns = std.ArrayList(wasm.Valtype).init(gpa); | 795 | var returns = std.ArrayList(wasm.Valtype).init(gpa); |
| 796 | defer returns.deinit(); | 796 | defer returns.deinit(); |
| 797 | | 797 | |
| 798 | if (firstParamSRet(fn_info, target)) { | 798 | if (firstParamSRet(fn_info.cc, fn_info.return_type, target)) { |
| 799 | try params.append(.i32); // memory address is always a 32-bit handle | 799 | try params.append(.i32); // memory address is always a 32-bit handle |
| 800 | } else if (fn_info.return_type.hasRuntimeBitsIgnoreComptime()) { | 800 | } else if (fn_info.return_type.hasRuntimeBitsIgnoreComptime()) { |
| 801 | if (fn_info.cc == .C) { | 801 | if (fn_info.cc == .C) { |
| ... | @@ -993,7 +993,8 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) InnerError!CallWValu | ... | @@ -993,7 +993,8 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) InnerError!CallWValu |
| 993 | | 993 | |
| 994 | // Check if we store the result as a pointer to the stack rather than | 994 | // Check if we store the result as a pointer to the stack rather than |
| 995 | // by value | 995 | // by value |
| 996 | if (firstParamSRet(fn_ty.fnInfo(), self.target)) { | 996 | const fn_info = fn_ty.fnInfo(); |
| | 997 | if (firstParamSRet(fn_info.cc, fn_info.return_type, self.target)) { |
| 997 | // the sret arg will be passed as first argument, therefore we | 998 | // the sret arg will be passed as first argument, therefore we |
| 998 | // set the `return_value` before allocating locals for regular args. | 999 | // set the `return_value` before allocating locals for regular args. |
| 999 | result.return_value = .{ .local = self.local_index }; | 1000 | result.return_value = .{ .local = self.local_index }; |
| ... | @@ -1027,11 +1028,11 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) InnerError!CallWValu | ... | @@ -1027,11 +1028,11 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) InnerError!CallWValu |
| 1027 | return result; | 1028 | return result; |
| 1028 | } | 1029 | } |
| 1029 | | 1030 | |
| 1030 | fn firstParamSRet(fn_info: Type.Payload.Function.Data, target: std.Target) bool { | 1031 | fn firstParamSRet(cc: std.builtin.CallingConvention, return_type: Type, target: std.Target) bool { |
| 1031 | switch (fn_info.cc) { | 1032 | switch (cc) { |
| 1032 | .Unspecified, .Inline => return isByRef(fn_info.return_type, target), | 1033 | .Unspecified, .Inline => return isByRef(return_type, target), |
| 1033 | .C => { | 1034 | .C => { |
| 1034 | const ty_classes = abi.classifyType(fn_info.return_type, target); | 1035 | const ty_classes = abi.classifyType(return_type, target); |
| 1035 | if (ty_classes[0] == .indirect) return true; | 1036 | if (ty_classes[0] == .indirect) return true; |
| 1036 | if (ty_classes[0] == .direct and ty_classes[1] == .direct) return true; | 1037 | if (ty_classes[0] == .direct and ty_classes[1] == .direct) return true; |
| 1037 | return false; | 1038 | return false; |
| ... | @@ -1678,7 +1679,8 @@ fn airRetPtr(self: *Self, inst: Air.Inst.Index) InnerError!WValue { | ... | @@ -1678,7 +1679,8 @@ fn airRetPtr(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| 1678 | return self.allocStack(Type.usize); // create pointer to void | 1679 | return self.allocStack(Type.usize); // create pointer to void |
| 1679 | } | 1680 | } |
| 1680 | | 1681 | |
| 1681 | if (firstParamSRet(self.decl.ty.fnInfo(), self.target)) { | 1682 | const fn_info = self.decl.ty.fnInfo(); |
| | 1683 | if (firstParamSRet(fn_info.cc, fn_info.return_type, self.target)) { |
| 1682 | return self.return_value; | 1684 | return self.return_value; |
| 1683 | } | 1685 | } |
| 1684 | | 1686 | |
| ... | @@ -1697,7 +1699,8 @@ fn airRetLoad(self: *Self, inst: Air.Inst.Index) InnerError!WValue { | ... | @@ -1697,7 +1699,8 @@ fn airRetLoad(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| 1697 | } | 1699 | } |
| 1698 | } | 1700 | } |
| 1699 | | 1701 | |
| 1700 | if (!firstParamSRet(self.decl.ty.fnInfo(), self.target)) { | 1702 | const fn_info = self.decl.ty.fnInfo(); |
| | 1703 | if (!firstParamSRet(fn_info.cc, fn_info.return_type, self.target)) { |
| 1701 | const result = try self.load(operand, ret_ty, 0); | 1704 | const result = try self.load(operand, ret_ty, 0); |
| 1702 | try self.emitWValue(result); | 1705 | try self.emitWValue(result); |
| 1703 | } | 1706 | } |
| ... | @@ -1720,7 +1723,8 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions. | ... | @@ -1720,7 +1723,8 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions. |
| 1720 | else => unreachable, | 1723 | else => unreachable, |
| 1721 | }; | 1724 | }; |
| 1722 | const ret_ty = fn_ty.fnReturnType(); | 1725 | const ret_ty = fn_ty.fnReturnType(); |
| 1723 | const first_param_sret = firstParamSRet(fn_ty.fnInfo(), self.target); | 1726 | const fn_info = fn_ty.fnInfo(); |
| | 1727 | const first_param_sret = firstParamSRet(fn_info.cc, fn_info.return_type, self.target); |
| 1724 | | 1728 | |
| 1725 | const callee: ?*Decl = blk: { | 1729 | const callee: ?*Decl = blk: { |
| 1726 | const func_val = self.air.value(pl_op.operand) orelse break :blk null; | 1730 | const func_val = self.air.value(pl_op.operand) orelse break :blk null; |
| ... | @@ -5091,3 +5095,65 @@ fn airShlSat(self: *Self, inst: Air.Inst.Index) InnerError!WValue { | ... | @@ -5091,3 +5095,65 @@ fn airShlSat(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| 5091 | return shift_result; | 5095 | return shift_result; |
| 5092 | } | 5096 | } |
| 5093 | } | 5097 | } |
| | 5098 | |
| | 5099 | /// Calls a compiler-rt intrinsic by creating an undefined symbol, |
| | 5100 | /// then lowering the arguments and calling the symbol as a function call. |
| | 5101 | /// This function call assumes the C-ABI. |
| | 5102 | fn callIntrinsic( |
| | 5103 | self: *Self, |
| | 5104 | name: []const u8, |
| | 5105 | param_types: []const Type, |
| | 5106 | return_type: Type, |
| | 5107 | args: []const WValue, |
| | 5108 | ) InnerError!WValue { |
| | 5109 | assert(param_types.len == args.len); |
| | 5110 | const symbol_index = @intCast(u32, try self.bin_file.getIntrinsicSymbol(name)); |
| | 5111 | var pt_tmp = try self.gpa.dupe(Type, param_types); |
| | 5112 | defer self.gpa.free(pt_tmp); |
| | 5113 | |
| | 5114 | // TODO: have genFunctype accept individual params so we don't, |
| | 5115 | // need to initialize a fake Fn.Data instance. |
| | 5116 | const func_type = try genFunctype(self.base.allocator, .{ |
| | 5117 | .param_types = pt_tmp, |
| | 5118 | .comptime_params = undefined, |
| | 5119 | .return_type = return_type, |
| | 5120 | .alignment = 0, |
| | 5121 | .cc = .C, |
| | 5122 | .is_var_args = false, |
| | 5123 | .is_generic = false, |
| | 5124 | }, self.target); |
| | 5125 | defer func_type.deinit(self.base.allocator); |
| | 5126 | const func_type_index = try self.bin_file.putOrGetFuncType(func_type); |
| | 5127 | try self.bin_file.addOrUpdateImport(symbol_index, func_type_index); |
| | 5128 | |
| | 5129 | const want_sret_param = firstParamSRet(.C, return_type, self.target); |
| | 5130 | // if we want return as first param, we allocate a pointer to stack, |
| | 5131 | // and emit it as our first argument |
| | 5132 | const sret = if (want_sret_param) blk: { |
| | 5133 | const sret_local = try self.allocStack(return_type); |
| | 5134 | try self.lowerToStack(sret_local); |
| | 5135 | break :blk sret_local; |
| | 5136 | } else WValue{ .none = {} }; |
| | 5137 | |
| | 5138 | // Lower all arguments to the stack before we call our function |
| | 5139 | for (args) |arg, arg_i| { |
| | 5140 | assert(param_types[arg_i].hasRuntimeBitsIgnoreComptime()); |
| | 5141 | try self.lowerArg(.C, param_types[arg_i], arg); |
| | 5142 | } |
| | 5143 | |
| | 5144 | // Actually call our intrinsic |
| | 5145 | try self.addLabel(.call, symbol_index); |
| | 5146 | |
| | 5147 | if (!return_type.hasRuntimeBitsIgnoreComptime()) { |
| | 5148 | return WValue.none; |
| | 5149 | } else if (return_type.isNoReturn()) { |
| | 5150 | try self.addTag(.@"unreachable"); |
| | 5151 | return WValue.none; |
| | 5152 | } else if (want_sret_param) { |
| | 5153 | return sret; |
| | 5154 | } else { |
| | 5155 | const result_local = try self.allocLocal(return_type); |
| | 5156 | try self.addLabel(.local_set, result_local.local); |
| | 5157 | return result_local; |
| | 5158 | } |
| | 5159 | } |