| ... | @@ -21,6 +21,7 @@ const Air = @import("../../Air.zig"); | ... | @@ -21,6 +21,7 @@ const Air = @import("../../Air.zig"); |
| 21 | const Liveness = @import("../../Liveness.zig"); | 21 | const Liveness = @import("../../Liveness.zig"); |
| 22 | const Mir = @import("Mir.zig"); | 22 | const Mir = @import("Mir.zig"); |
| 23 | const Emit = @import("Emit.zig"); | 23 | const Emit = @import("Emit.zig"); |
| | 24 | const abi = @import("abi.zig"); |
| 24 | | 25 | |
| 25 | /// Wasm Value, created when generating an instruction | 26 | /// Wasm Value, created when generating an instruction |
| 26 | const WValue = union(enum) { | 27 | const WValue = union(enum) { |
| ... | @@ -722,18 +723,15 @@ fn typeToValtype(ty: Type, target: std.Target) wasm.Valtype { | ... | @@ -722,18 +723,15 @@ fn typeToValtype(ty: Type, target: std.Target) wasm.Valtype { |
| 722 | const bits = ty.floatBits(target); | 723 | const bits = ty.floatBits(target); |
| 723 | if (bits == 16 or bits == 32) break :blk wasm.Valtype.f32; | 724 | if (bits == 16 or bits == 32) break :blk wasm.Valtype.f32; |
| 724 | if (bits == 64) break :blk wasm.Valtype.f64; | 725 | if (bits == 64) break :blk wasm.Valtype.f64; |
| | 726 | if (bits == 128) break :blk wasm.Valtype.i64; |
| 725 | return wasm.Valtype.i32; // represented as pointer to stack | 727 | return wasm.Valtype.i32; // represented as pointer to stack |
| 726 | }, | 728 | }, |
| 727 | .Int => blk: { | 729 | .Int, .Enum => blk: { |
| 728 | const info = ty.intInfo(target); | 730 | const info = ty.intInfo(target); |
| 729 | if (info.bits <= 32) break :blk wasm.Valtype.i32; | 731 | if (info.bits <= 32) break :blk wasm.Valtype.i32; |
| 730 | if (info.bits > 32 and info.bits <= 64) break :blk wasm.Valtype.i64; | 732 | if (info.bits > 32 and info.bits <= 128) break :blk wasm.Valtype.i64; |
| 731 | break :blk wasm.Valtype.i32; // represented as pointer to stack | 733 | break :blk wasm.Valtype.i32; // represented as pointer to stack |
| 732 | }, | 734 | }, |
| 733 | .Enum => { | | |
| 734 | var buf: Type.Payload.Bits = undefined; | | |
| 735 | return typeToValtype(ty.intTagType(&buf), target); | | |
| 736 | }, | | |
| 737 | else => wasm.Valtype.i32, // all represented as reference/immediate | 735 | else => wasm.Valtype.i32, // all represented as reference/immediate |
| 738 | }; | 736 | }; |
| 739 | } | 737 | } |
| ... | @@ -787,33 +785,46 @@ fn allocLocal(self: *Self, ty: Type) InnerError!WValue { | ... | @@ -787,33 +785,46 @@ fn allocLocal(self: *Self, ty: Type) InnerError!WValue { |
| 787 | | 785 | |
| 788 | /// Generates a `wasm.Type` from a given function type. | 786 | /// Generates a `wasm.Type` from a given function type. |
| 789 | /// Memory is owned by the caller. | 787 | /// Memory is owned by the caller. |
| 790 | fn genFunctype(gpa: Allocator, fn_ty: Type, target: std.Target) !wasm.Type { | 788 | fn genFunctype(gpa: Allocator, fn_info: Type.Payload.Function.Data, target: std.Target) !wasm.Type { |
| 791 | var params = std.ArrayList(wasm.Valtype).init(gpa); | 789 | var params = std.ArrayList(wasm.Valtype).init(gpa); |
| 792 | defer params.deinit(); | 790 | defer params.deinit(); |
| 793 | var returns = std.ArrayList(wasm.Valtype).init(gpa); | 791 | var returns = std.ArrayList(wasm.Valtype).init(gpa); |
| 794 | defer returns.deinit(); | 792 | defer returns.deinit(); |
| 795 | const return_type = fn_ty.fnReturnType(); | | |
| 796 | | | |
| 797 | const want_sret = isByRef(return_type, target); | | |
| 798 | | 793 | |
| 799 | if (want_sret) { | 794 | if (firstParamSRet(fn_info, target)) { |
| 800 | try params.append(typeToValtype(return_type, target)); | 795 | try params.append(typeToValtype(fn_info.return_type, target)); |
| | 796 | } else if (fn_info.return_type.hasRuntimeBitsIgnoreComptime()) { |
| | 797 | if (fn_info.cc == .C) { |
| | 798 | const res_classes = abi.classifyType(fn_info.return_type, target); |
| | 799 | assert(res_classes[0] == .direct and res_classes[1] == .none); |
| | 800 | const scalar_type = abi.scalarType(fn_info.return_type, target); |
| | 801 | try returns.append(typeToValtype(scalar_type, target)); |
| | 802 | } else { |
| | 803 | try returns.append(typeToValtype(fn_info.return_type, target)); |
| | 804 | } |
| 801 | } | 805 | } |
| 802 | | 806 | |
| 803 | // param types | 807 | // param types |
| 804 | if (fn_ty.fnParamLen() != 0) { | 808 | if (fn_info.param_types.len != 0) { |
| 805 | const fn_params = try gpa.alloc(Type, fn_ty.fnParamLen()); | 809 | for (fn_info.param_types) |param_type| { |
| 806 | defer gpa.free(fn_params); | | |
| 807 | fn_ty.fnParamTypes(fn_params); | | |
| 808 | for (fn_params) |param_type| { | | |
| 809 | if (!param_type.hasRuntimeBitsIgnoreComptime()) continue; | 810 | if (!param_type.hasRuntimeBitsIgnoreComptime()) continue; |
| 810 | try params.append(typeToValtype(param_type, target)); | | |
| 811 | } | | |
| 812 | } | | |
| 813 | | 811 | |
| 814 | // return type | 812 | switch (fn_info.cc) { |
| 815 | if (!want_sret and return_type.hasRuntimeBitsIgnoreComptime()) { | 813 | .C => { |
| 816 | try returns.append(typeToValtype(return_type, target)); | 814 | const param_classes = abi.classifyType(param_type, target); |
| | 815 | for (param_classes) |class| { |
| | 816 | if (class == .none) continue; |
| | 817 | if (class == .direct) { |
| | 818 | const scalar_type = abi.scalarType(param_type, target); |
| | 819 | try params.append(typeToValtype(scalar_type, target)); |
| | 820 | } else { |
| | 821 | try params.append(typeToValtype(param_type, target)); |
| | 822 | } |
| | 823 | } |
| | 824 | }, |
| | 825 | else => try params.append(typeToValtype(param_type, target)), |
| | 826 | } |
| | 827 | } |
| 817 | } | 828 | } |
| 818 | | 829 | |
| 819 | return wasm.Type{ | 830 | return wasm.Type{ |
| ... | @@ -857,7 +868,7 @@ pub fn generate( | ... | @@ -857,7 +868,7 @@ pub fn generate( |
| 857 | } | 868 | } |
| 858 | | 869 | |
| 859 | fn genFunc(self: *Self) InnerError!void { | 870 | fn genFunc(self: *Self) InnerError!void { |
| 860 | var func_type = try genFunctype(self.gpa, self.decl.ty, self.target); | 871 | var func_type = try genFunctype(self.gpa, self.decl.ty.fnInfo(), self.target); |
| 861 | defer func_type.deinit(self.gpa); | 872 | defer func_type.deinit(self.gpa); |
| 862 | self.decl.fn_link.wasm.type_index = try self.bin_file.putOrGetFuncType(func_type); | 873 | self.decl.fn_link.wasm.type_index = try self.bin_file.putOrGetFuncType(func_type); |
| 863 | | 874 | |
| ... | @@ -957,21 +968,22 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) InnerError!CallWValu | ... | @@ -957,21 +968,22 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) InnerError!CallWValu |
| 957 | .args = &.{}, | 968 | .args = &.{}, |
| 958 | .return_value = .none, | 969 | .return_value = .none, |
| 959 | }; | 970 | }; |
| | 971 | if (cc == .Naked) return result; |
| | 972 | |
| 960 | var args = std.ArrayList(WValue).init(self.gpa); | 973 | var args = std.ArrayList(WValue).init(self.gpa); |
| 961 | defer args.deinit(); | 974 | defer args.deinit(); |
| 962 | | 975 | |
| 963 | const ret_ty = fn_ty.fnReturnType(); | | |
| 964 | // Check if we store the result as a pointer to the stack rather than | 976 | // Check if we store the result as a pointer to the stack rather than |
| 965 | // by value | 977 | // by value |
| 966 | if (isByRef(ret_ty, self.target)) { | 978 | if (firstParamSRet(fn_ty.fnInfo(), self.target)) { |
| 967 | // the sret arg will be passed as first argument, therefore we | 979 | // the sret arg will be passed as first argument, therefore we |
| 968 | // set the `return_value` before allocating locals for regular args. | 980 | // set the `return_value` before allocating locals for regular args. |
| 969 | result.return_value = .{ .local = self.local_index }; | 981 | result.return_value = .{ .local = self.local_index }; |
| 970 | self.local_index += 1; | 982 | self.local_index += 1; |
| 971 | } | 983 | } |
| | 984 | |
| 972 | switch (cc) { | 985 | switch (cc) { |
| 973 | .Naked => return result, | 986 | .Unspecified => { |
| 974 | .Unspecified, .C => { | | |
| 975 | for (param_types) |ty| { | 987 | for (param_types) |ty| { |
| 976 | if (!ty.hasRuntimeBitsIgnoreComptime()) { | 988 | if (!ty.hasRuntimeBitsIgnoreComptime()) { |
| 977 | continue; | 989 | continue; |
| ... | @@ -981,12 +993,105 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) InnerError!CallWValu | ... | @@ -981,12 +993,105 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) InnerError!CallWValu |
| 981 | self.local_index += 1; | 993 | self.local_index += 1; |
| 982 | } | 994 | } |
| 983 | }, | 995 | }, |
| 984 | else => return self.fail("TODO implement function parameters for cc '{}' on wasm", .{cc}), | 996 | .C => { |
| | 997 | for (param_types) |ty| { |
| | 998 | const ty_classes = abi.classifyType(ty, self.target); |
| | 999 | for (ty_classes) |class| { |
| | 1000 | if (class == .none) continue; |
| | 1001 | try args.append(.{ .local = self.local_index }); |
| | 1002 | self.local_index += 1; |
| | 1003 | } |
| | 1004 | } |
| | 1005 | }, |
| | 1006 | else => return self.fail("calling convention '{s}' not supported for Wasm", .{@tagName(cc)}), |
| 985 | } | 1007 | } |
| 986 | result.args = args.toOwnedSlice(); | 1008 | result.args = args.toOwnedSlice(); |
| 987 | return result; | 1009 | return result; |
| 988 | } | 1010 | } |
| 989 | | 1011 | |
| | 1012 | fn firstParamSRet(fn_info: Type.Payload.Function.Data, target: std.Target) bool { |
| | 1013 | switch (fn_info.cc) { |
| | 1014 | .Unspecified, .Inline => return isByRef(fn_info.return_type, target), |
| | 1015 | .C => { |
| | 1016 | const ty_classes = abi.classifyType(fn_info.return_type, target); |
| | 1017 | if (ty_classes[0] == .indirect) return true; |
| | 1018 | if (ty_classes[0] == .direct and ty_classes[1] == .direct) return true; |
| | 1019 | return false; |
| | 1020 | }, |
| | 1021 | else => return false, |
| | 1022 | } |
| | 1023 | } |
| | 1024 | |
| | 1025 | /// Lowers a Zig type and its value based on a given calling convention to ensure |
| | 1026 | /// it matches the ABI. |
| | 1027 | fn lowerArg(self: *Self, cc: std.builtin.CallingConvention, ty: Type, value: WValue) !void { |
| | 1028 | if (cc != .C) { |
| | 1029 | return self.lowerToStack(value); |
| | 1030 | } |
| | 1031 | |
| | 1032 | const ty_classes = abi.classifyType(ty, self.target); |
| | 1033 | assert(ty_classes[0] != .none); |
| | 1034 | switch (ty.zigTypeTag()) { |
| | 1035 | .Struct, .Union => { |
| | 1036 | if (ty_classes[0] == .indirect) { |
| | 1037 | return self.lowerToStack(value); |
| | 1038 | } |
| | 1039 | assert(ty_classes[0] == .direct); |
| | 1040 | const scalar_type = abi.scalarType(ty, self.target); |
| | 1041 | const abi_size = scalar_type.abiSize(self.target); |
| | 1042 | const opcode = buildOpcode(.{ |
| | 1043 | .op = .load, |
| | 1044 | .width = @intCast(u8, abi_size), |
| | 1045 | .signedness = if (scalar_type.isSignedInt()) .signed else .unsigned, |
| | 1046 | .valtype1 = typeToValtype(scalar_type, self.target), |
| | 1047 | }); |
| | 1048 | try self.emitWValue(value); |
| | 1049 | try self.addMemArg(Mir.Inst.Tag.fromOpcode(opcode), .{ |
| | 1050 | .offset = value.offset(), |
| | 1051 | .alignment = scalar_type.abiAlignment(self.target), |
| | 1052 | }); |
| | 1053 | }, |
| | 1054 | .Int, .Float => { |
| | 1055 | if (ty_classes[1] == .none) { |
| | 1056 | return self.lowerToStack(value); |
| | 1057 | } |
| | 1058 | assert(ty_classes[0] == .direct and ty_classes[1] == .direct); |
| | 1059 | assert(ty.abiSize(self.target) == 16); |
| | 1060 | // in this case we have an integer or float that must be lowered as 2 i64's. |
| | 1061 | try self.emitWValue(value); |
| | 1062 | try self.addMemArg(.i64_load, .{ .offset = value.offset(), .alignment = 16 }); |
| | 1063 | try self.emitWValue(value); |
| | 1064 | try self.addMemArg(.i64_load, .{ .offset = value.offset() + 8, .alignment = 16 }); |
| | 1065 | }, |
| | 1066 | else => return self.lowerToStack(value), |
| | 1067 | } |
| | 1068 | } |
| | 1069 | |
| | 1070 | /// Lowers a `WValue` to the stack. This means when the `value` results in |
| | 1071 | /// `.stack_offset` we calculate the pointer of this offset and use that. |
| | 1072 | /// The value is left on the stack, and not stored in any temporary. |
| | 1073 | fn lowerToStack(self: *Self, value: WValue) !void { |
| | 1074 | switch (value) { |
| | 1075 | .stack_offset => |offset| { |
| | 1076 | try self.emitWValue(value); |
| | 1077 | if (offset > 0) { |
| | 1078 | switch (self.arch()) { |
| | 1079 | .wasm32 => { |
| | 1080 | try self.addImm32(@bitCast(i32, offset)); |
| | 1081 | try self.addTag(.i32_add); |
| | 1082 | }, |
| | 1083 | .wasm64 => { |
| | 1084 | try self.addImm64(offset); |
| | 1085 | try self.addTag(.i64_add); |
| | 1086 | }, |
| | 1087 | else => unreachable, |
| | 1088 | } |
| | 1089 | } |
| | 1090 | }, |
| | 1091 | else => try self.emitWValue(value), |
| | 1092 | } |
| | 1093 | } |
| | 1094 | |
| 990 | /// Creates a local for the initial stack value | 1095 | /// Creates a local for the initial stack value |
| 991 | /// Asserts `initial_stack_value` is `.none` | 1096 | /// Asserts `initial_stack_value` is `.none` |
| 992 | fn initializeStack(self: *Self) !void { | 1097 | fn initializeStack(self: *Self) !void { |
| ... | @@ -1489,11 +1594,31 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { | ... | @@ -1489,11 +1594,31 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 1489 | fn airRet(self: *Self, inst: Air.Inst.Index) InnerError!WValue { | 1594 | fn airRet(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| 1490 | const un_op = self.air.instructions.items(.data)[inst].un_op; | 1595 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| 1491 | const operand = try self.resolveInst(un_op); | 1596 | const operand = try self.resolveInst(un_op); |
| | 1597 | const ret_ty = self.decl.ty.fnReturnType(); |
| 1492 | | 1598 | |
| 1493 | // result must be stored in the stack and we return a pointer | 1599 | // result must be stored in the stack and we return a pointer |
| 1494 | // to the stack instead | 1600 | // to the stack instead |
| 1495 | if (self.return_value != .none) { | 1601 | if (self.return_value != .none) { |
| 1496 | try self.store(self.return_value, operand, self.decl.ty.fnReturnType(), 0); | 1602 | try self.store(self.return_value, operand, self.decl.ty.fnReturnType(), 0); |
| | 1603 | } else if (self.decl.ty.fnInfo().cc == .C and ret_ty.hasRuntimeBitsIgnoreComptime()) { |
| | 1604 | switch (ret_ty.zigTypeTag()) { |
| | 1605 | // Aggregate types can be lowered as a singular value |
| | 1606 | .Struct, .Union => { |
| | 1607 | const scalar_type = abi.scalarType(ret_ty, self.target); |
| | 1608 | try self.emitWValue(operand); |
| | 1609 | const opcode = buildOpcode(.{ |
| | 1610 | .op = .load, |
| | 1611 | .width = @intCast(u8, scalar_type.abiSize(self.target)), |
| | 1612 | .signedness = if (scalar_type.isSignedInt()) .signed else .unsigned, |
| | 1613 | .valtype1 = typeToValtype(scalar_type, self.target), |
| | 1614 | }); |
| | 1615 | try self.addMemArg(Mir.Inst.Tag.fromOpcode(opcode), .{ |
| | 1616 | .offset = operand.offset(), |
| | 1617 | .alignment = scalar_type.abiAlignment(self.target), |
| | 1618 | }); |
| | 1619 | }, |
| | 1620 | else => try self.emitWValue(operand), |
| | 1621 | } |
| 1497 | } else { | 1622 | } else { |
| 1498 | try self.emitWValue(operand); | 1623 | try self.emitWValue(operand); |
| 1499 | } | 1624 | } |
| ... | @@ -1509,9 +1634,10 @@ fn airRetPtr(self: *Self, inst: Air.Inst.Index) InnerError!WValue { | ... | @@ -1509,9 +1634,10 @@ fn airRetPtr(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| 1509 | return self.allocStack(Type.usize); // create pointer to void | 1634 | return self.allocStack(Type.usize); // create pointer to void |
| 1510 | } | 1635 | } |
| 1511 | | 1636 | |
| 1512 | if (isByRef(child_type, self.target)) { | 1637 | if (firstParamSRet(self.decl.ty.fnInfo(), self.target)) { |
| 1513 | return self.return_value; | 1638 | return self.return_value; |
| 1514 | } | 1639 | } |
| | 1640 | |
| 1515 | return self.allocStackPtr(inst); | 1641 | return self.allocStackPtr(inst); |
| 1516 | } | 1642 | } |
| 1517 | | 1643 | |
| ... | @@ -1521,7 +1647,7 @@ fn airRetLoad(self: *Self, inst: Air.Inst.Index) InnerError!WValue { | ... | @@ -1521,7 +1647,7 @@ fn airRetLoad(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| 1521 | const ret_ty = self.air.typeOf(un_op).childType(); | 1647 | const ret_ty = self.air.typeOf(un_op).childType(); |
| 1522 | if (!ret_ty.hasRuntimeBitsIgnoreComptime()) return WValue.none; | 1648 | if (!ret_ty.hasRuntimeBitsIgnoreComptime()) return WValue.none; |
| 1523 | | 1649 | |
| 1524 | if (!isByRef(ret_ty, self.target)) { | 1650 | if (!firstParamSRet(self.decl.ty.fnInfo(), self.target)) { |
| 1525 | const result = try self.load(operand, ret_ty, 0); | 1651 | const result = try self.load(operand, ret_ty, 0); |
| 1526 | try self.emitWValue(result); | 1652 | try self.emitWValue(result); |
| 1527 | } | 1653 | } |
| ... | @@ -1544,7 +1670,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions. | ... | @@ -1544,7 +1670,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions. |
| 1544 | else => unreachable, | 1670 | else => unreachable, |
| 1545 | }; | 1671 | }; |
| 1546 | const ret_ty = fn_ty.fnReturnType(); | 1672 | const ret_ty = fn_ty.fnReturnType(); |
| 1547 | const first_param_sret = isByRef(ret_ty, self.target); | 1673 | const first_param_sret = firstParamSRet(fn_ty.fnInfo(), self.target); |
| 1548 | | 1674 | |
| 1549 | const callee: ?*Decl = blk: { | 1675 | const callee: ?*Decl = blk: { |
| 1550 | const func_val = self.air.value(pl_op.operand) orelse break :blk null; | 1676 | const func_val = self.air.value(pl_op.operand) orelse break :blk null; |
| ... | @@ -1554,7 +1680,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions. | ... | @@ -1554,7 +1680,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions. |
| 1554 | break :blk module.declPtr(func.data.owner_decl); | 1680 | break :blk module.declPtr(func.data.owner_decl); |
| 1555 | } else if (func_val.castTag(.extern_fn)) |extern_fn| { | 1681 | } else if (func_val.castTag(.extern_fn)) |extern_fn| { |
| 1556 | const ext_decl = module.declPtr(extern_fn.data.owner_decl); | 1682 | const ext_decl = module.declPtr(extern_fn.data.owner_decl); |
| 1557 | var func_type = try genFunctype(self.gpa, ext_decl.ty, self.target); | 1683 | var func_type = try genFunctype(self.gpa, ext_decl.ty.fnInfo(), self.target); |
| 1558 | defer func_type.deinit(self.gpa); | 1684 | defer func_type.deinit(self.gpa); |
| 1559 | ext_decl.fn_link.wasm.type_index = try self.bin_file.putOrGetFuncType(func_type); | 1685 | ext_decl.fn_link.wasm.type_index = try self.bin_file.putOrGetFuncType(func_type); |
| 1560 | try self.bin_file.addOrUpdateImport(ext_decl); | 1686 | try self.bin_file.addOrUpdateImport(ext_decl); |
| ... | @@ -1579,10 +1705,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions. | ... | @@ -1579,10 +1705,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions. |
| 1579 | const arg_ty = self.air.typeOf(arg_ref); | 1705 | const arg_ty = self.air.typeOf(arg_ref); |
| 1580 | if (!arg_ty.hasRuntimeBitsIgnoreComptime()) continue; | 1706 | if (!arg_ty.hasRuntimeBitsIgnoreComptime()) continue; |
| 1581 | | 1707 | |
| 1582 | switch (arg_val) { | 1708 | try self.lowerArg(fn_ty.fnInfo().cc, arg_ty, arg_val); |
| 1583 | .stack_offset => try self.emitWValue(try self.buildPointerOffset(arg_val, 0, .new)), | | |
| 1584 | else => try self.emitWValue(arg_val), | | |
| 1585 | } | | |
| 1586 | } | 1709 | } |
| 1587 | | 1710 | |
| 1588 | if (callee) |direct| { | 1711 | if (callee) |direct| { |
| ... | @@ -1594,7 +1717,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions. | ... | @@ -1594,7 +1717,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions. |
| 1594 | const operand = try self.resolveInst(pl_op.operand); | 1717 | const operand = try self.resolveInst(pl_op.operand); |
| 1595 | try self.emitWValue(operand); | 1718 | try self.emitWValue(operand); |
| 1596 | | 1719 | |
| 1597 | var fn_type = try genFunctype(self.gpa, fn_ty, self.target); | 1720 | var fn_type = try genFunctype(self.gpa, fn_ty.fnInfo(), self.target); |
| 1598 | defer fn_type.deinit(self.gpa); | 1721 | defer fn_type.deinit(self.gpa); |
| 1599 | | 1722 | |
| 1600 | const fn_type_index = try self.bin_file.putOrGetFuncType(fn_type); | 1723 | const fn_type_index = try self.bin_file.putOrGetFuncType(fn_type); |
| ... | @@ -1608,6 +1731,14 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions. | ... | @@ -1608,6 +1731,14 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions. |
| 1608 | return WValue.none; | 1731 | return WValue.none; |
| 1609 | } else if (first_param_sret) { | 1732 | } else if (first_param_sret) { |
| 1610 | return sret; | 1733 | return sret; |
| | 1734 | // TODO: Make this less fragile and optimize |
| | 1735 | } else if (fn_ty.fnInfo().cc == .C and ret_ty.zigTypeTag() == .Struct or ret_ty.zigTypeTag() == .Union) { |
| | 1736 | const result_local = try self.allocLocal(ret_ty); |
| | 1737 | try self.addLabel(.local_set, result_local.local); |
| | 1738 | const scalar_type = abi.scalarType(ret_ty, self.target); |
| | 1739 | const result = try self.allocStack(scalar_type); |
| | 1740 | try self.store(result, result_local, scalar_type, 0); |
| | 1741 | return result; |
| 1611 | } else { | 1742 | } else { |
| 1612 | const result_local = try self.allocLocal(ret_ty); | 1743 | const result_local = try self.allocLocal(ret_ty); |
| 1613 | try self.addLabel(.local_set, result_local.local); | 1744 | try self.addLabel(.local_set, result_local.local); |
| ... | @@ -1749,9 +1880,20 @@ fn load(self: *Self, operand: WValue, ty: Type, offset: u32) InnerError!WValue { | ... | @@ -1749,9 +1880,20 @@ fn load(self: *Self, operand: WValue, ty: Type, offset: u32) InnerError!WValue { |
| 1749 | } | 1880 | } |
| 1750 | | 1881 | |
| 1751 | fn airArg(self: *Self, inst: Air.Inst.Index) InnerError!WValue { | 1882 | fn airArg(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| 1752 | _ = inst; | 1883 | const arg = self.args[self.arg_index]; |
| 1753 | defer self.arg_index += 1; | 1884 | const cc = self.decl.ty.fnInfo().cc; |
| 1754 | return self.args[self.arg_index]; | 1885 | if (cc == .C) { |
| | 1886 | const ty = self.air.typeOfIndex(inst); |
| | 1887 | const arg_classes = abi.classifyType(ty, self.target); |
| | 1888 | for (arg_classes) |class| { |
| | 1889 | if (class != .none) { |
| | 1890 | self.arg_index += 1; |
| | 1891 | } |
| | 1892 | } |
| | 1893 | } else { |
| | 1894 | self.arg_index += 1; |
| | 1895 | } |
| | 1896 | return arg; |
| 1755 | } | 1897 | } |
| 1756 | | 1898 | |
| 1757 | fn airBinOp(self: *Self, inst: Air.Inst.Index, op: Op) InnerError!WValue { | 1899 | fn airBinOp(self: *Self, inst: Air.Inst.Index, op: Op) InnerError!WValue { |