| ... | @@ -794,7 +794,7 @@ fn genFunctype(gpa: Allocator, fn_info: Type.Payload.Function.Data, target: std. | ... | @@ -794,7 +794,7 @@ fn genFunctype(gpa: Allocator, fn_info: Type.Payload.Function.Data, target: std. |
| 794 | defer returns.deinit(); | 794 | defer returns.deinit(); |
| 795 | | 795 | |
| 796 | if (firstParamSRet(fn_info, target)) { | 796 | if (firstParamSRet(fn_info, target)) { |
| 797 | try params.append(typeToValtype(fn_info.return_type, target)); | 797 | try params.append(.i32); // memory address is always a 32-bit handle |
| 798 | } else if (fn_info.return_type.hasRuntimeBitsIgnoreComptime()) { | 798 | } else if (fn_info.return_type.hasRuntimeBitsIgnoreComptime()) { |
| 799 | if (fn_info.cc == .C) { | 799 | if (fn_info.cc == .C) { |
| 800 | const res_classes = abi.classifyType(fn_info.return_type, target); | 800 | const res_classes = abi.classifyType(fn_info.return_type, target); |
| ... | @@ -824,7 +824,10 @@ fn genFunctype(gpa: Allocator, fn_info: Type.Payload.Function.Data, target: std. | ... | @@ -824,7 +824,10 @@ fn genFunctype(gpa: Allocator, fn_info: Type.Payload.Function.Data, target: std. |
| 824 | } | 824 | } |
| 825 | } | 825 | } |
| 826 | }, | 826 | }, |
| 827 | else => try params.append(typeToValtype(param_type, target)), | 827 | else => if (isByRef(param_type, target)) |
| | 828 | try params.append(.i32) |
| | 829 | else |
| | 830 | try params.append(typeToValtype(param_type, target)), |
| 828 | } | 831 | } |
| 829 | } | 832 | } |
| 830 | } | 833 | } |
| ... | @@ -844,7 +847,6 @@ pub fn generate( | ... | @@ -844,7 +847,6 @@ pub fn generate( |
| 844 | code: *std.ArrayList(u8), | 847 | code: *std.ArrayList(u8), |
| 845 | debug_output: codegen.DebugInfoOutput, | 848 | debug_output: codegen.DebugInfoOutput, |
| 846 | ) codegen.GenerateSymbolError!codegen.FnResult { | 849 | ) codegen.GenerateSymbolError!codegen.FnResult { |
| 847 | _ = debug_output; // TODO | | |
| 848 | _ = src_loc; | 850 | _ = src_loc; |
| 849 | var code_gen: Self = .{ | 851 | var code_gen: Self = .{ |
| 850 | .gpa = bin_file.allocator, | 852 | .gpa = bin_file.allocator, |
| ... | @@ -1088,9 +1090,9 @@ fn lowerArg(self: *Self, cc: std.builtin.CallingConvention, ty: Type, value: WVa | ... | @@ -1088,9 +1090,9 @@ fn lowerArg(self: *Self, cc: std.builtin.CallingConvention, ty: Type, value: WVa |
| 1088 | assert(ty.abiSize(self.target) == 16); | 1090 | assert(ty.abiSize(self.target) == 16); |
| 1089 | // in this case we have an integer or float that must be lowered as 2 i64's. | 1091 | // in this case we have an integer or float that must be lowered as 2 i64's. |
| 1090 | try self.emitWValue(value); | 1092 | try self.emitWValue(value); |
| 1091 | try self.addMemArg(.i64_load, .{ .offset = value.offset(), .alignment = 16 }); | 1093 | try self.addMemArg(.i64_load, .{ .offset = value.offset(), .alignment = 8 }); |
| 1092 | try self.emitWValue(value); | 1094 | try self.emitWValue(value); |
| 1093 | try self.addMemArg(.i64_load, .{ .offset = value.offset() + 8, .alignment = 16 }); | 1095 | try self.addMemArg(.i64_load, .{ .offset = value.offset() + 8, .alignment = 8 }); |
| 1094 | }, | 1096 | }, |
| 1095 | else => return self.lowerToStack(value), | 1097 | else => return self.lowerToStack(value), |
| 1096 | } | 1098 | } |
| ... | @@ -1221,14 +1223,8 @@ fn memcpy(self: *Self, dst: WValue, src: WValue, len: WValue) !void { | ... | @@ -1221,14 +1223,8 @@ fn memcpy(self: *Self, dst: WValue, src: WValue, len: WValue) !void { |
| 1221 | // When bulk_memory is enabled, we lower it to wasm's memcpy instruction. | 1223 | // When bulk_memory is enabled, we lower it to wasm's memcpy instruction. |
| 1222 | // If not, we lower it ourselves manually | 1224 | // If not, we lower it ourselves manually |
| 1223 | if (std.Target.wasm.featureSetHas(self.target.cpu.features, .bulk_memory)) { | 1225 | if (std.Target.wasm.featureSetHas(self.target.cpu.features, .bulk_memory)) { |
| 1224 | switch (dst) { | 1226 | try self.lowerToStack(dst); |
| 1225 | .stack_offset => try self.emitWValue(try self.buildPointerOffset(dst, 0, .new)), | 1227 | try self.lowerToStack(src); |
| 1226 | else => try self.emitWValue(dst), | | |
| 1227 | } | | |
| 1228 | switch (src) { | | |
| 1229 | .stack_offset => try self.emitWValue(try self.buildPointerOffset(src, 0, .new)), | | |
| 1230 | else => try self.emitWValue(src), | | |
| 1231 | } | | |
| 1232 | try self.emitWValue(len); | 1228 | try self.emitWValue(len); |
| 1233 | try self.addExtended(.memory_copy); | 1229 | try self.addExtended(.memory_copy); |
| 1234 | return; | 1230 | return; |
| ... | @@ -1792,7 +1788,7 @@ fn airStore(self: *Self, inst: Air.Inst.Index) InnerError!WValue { | ... | @@ -1792,7 +1788,7 @@ fn airStore(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| 1792 | const ty = self.air.typeOf(bin_op.lhs).childType(); | 1788 | const ty = self.air.typeOf(bin_op.lhs).childType(); |
| 1793 | | 1789 | |
| 1794 | try self.store(lhs, rhs, ty, 0); | 1790 | try self.store(lhs, rhs, ty, 0); |
| 1795 | return .none; | 1791 | return WValue{ .none = {} }; |
| 1796 | } | 1792 | } |
| 1797 | | 1793 | |
| 1798 | fn store(self: *Self, lhs: WValue, rhs: WValue, ty: Type, offset: u32) InnerError!void { | 1794 | fn store(self: *Self, lhs: WValue, rhs: WValue, ty: Type, offset: u32) InnerError!void { |
| ... | @@ -1848,11 +1844,8 @@ fn store(self: *Self, lhs: WValue, rhs: WValue, ty: Type, offset: u32) InnerErro | ... | @@ -1848,11 +1844,8 @@ fn store(self: *Self, lhs: WValue, rhs: WValue, ty: Type, offset: u32) InnerErro |
| 1848 | try self.emitWValue(lhs); | 1844 | try self.emitWValue(lhs); |
| 1849 | // In this case we're actually interested in storing the stack position | 1845 | // In this case we're actually interested in storing the stack position |
| 1850 | // into lhs, so we calculate that and emit that instead | 1846 | // into lhs, so we calculate that and emit that instead |
| 1851 | if (rhs == .stack_offset) { | 1847 | try self.lowerToStack(rhs); |
| 1852 | try self.emitWValue(try self.buildPointerOffset(rhs, 0, .new)); | 1848 | |
| 1853 | } else { | | |
| 1854 | try self.emitWValue(rhs); | | |
| 1855 | } | | |
| 1856 | const valtype = typeToValtype(ty, self.target); | 1849 | const valtype = typeToValtype(ty, self.target); |
| 1857 | const abi_size = @intCast(u8, ty.abiSize(self.target)); | 1850 | const abi_size = @intCast(u8, ty.abiSize(self.target)); |
| 1858 | | 1851 | |
| ... | @@ -1912,14 +1905,29 @@ fn airArg(self: *Self, inst: Air.Inst.Index) InnerError!WValue { | ... | @@ -1912,14 +1905,29 @@ fn airArg(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| 1912 | const arg_index = self.arg_index; | 1905 | const arg_index = self.arg_index; |
| 1913 | const arg = self.args[arg_index]; | 1906 | const arg = self.args[arg_index]; |
| 1914 | const cc = self.decl.ty.fnInfo().cc; | 1907 | const cc = self.decl.ty.fnInfo().cc; |
| | 1908 | const arg_ty = self.air.typeOfIndex(inst); |
| 1915 | if (cc == .C) { | 1909 | if (cc == .C) { |
| 1916 | const ty = self.air.typeOfIndex(inst); | 1910 | const arg_classes = abi.classifyType(arg_ty, self.target); |
| 1917 | const arg_classes = abi.classifyType(ty, self.target); | | |
| 1918 | for (arg_classes) |class| { | 1911 | for (arg_classes) |class| { |
| 1919 | if (class != .none) { | 1912 | if (class != .none) { |
| 1920 | self.arg_index += 1; | 1913 | self.arg_index += 1; |
| 1921 | } | 1914 | } |
| 1922 | } | 1915 | } |
| | 1916 | |
| | 1917 | // When we have an argument that's passed using more than a single parameter, |
| | 1918 | // we combine them into a single stack value |
| | 1919 | if (arg_classes[0] == .direct and arg_classes[1] == .direct) { |
| | 1920 | if (arg_ty.zigTypeTag() != .Int) { |
| | 1921 | return self.fail( |
| | 1922 | "TODO: Implement C-ABI argument for type '{}'", |
| | 1923 | .{arg_ty.fmt(self.bin_file.base.options.module.?)}, |
| | 1924 | ); |
| | 1925 | } |
| | 1926 | const result = try self.allocStack(arg_ty); |
| | 1927 | try self.store(result, arg, Type.u64, 0); |
| | 1928 | try self.store(result, self.args[arg_index + 1], Type.u64, 8); |
| | 1929 | return result; |
| | 1930 | } |
| 1923 | } else { | 1931 | } else { |
| 1924 | self.arg_index += 1; | 1932 | self.arg_index += 1; |
| 1925 | } | 1933 | } |
| ... | @@ -1943,7 +1951,7 @@ fn airArg(self: *Self, inst: Air.Inst.Index) InnerError!WValue { | ... | @@ -1943,7 +1951,7 @@ fn airArg(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| 1943 | std.dwarf.OP.WASM_local, | 1951 | std.dwarf.OP.WASM_local, |
| 1944 | }); | 1952 | }); |
| 1945 | leb.writeULEB128(dbg_info.writer(), arg.local) catch unreachable; | 1953 | leb.writeULEB128(dbg_info.writer(), arg.local) catch unreachable; |
| 1946 | try self.addDbgInfoTypeReloc(self.air.typeOfIndex(inst)); | 1954 | try self.addDbgInfoTypeReloc(arg_ty); |
| 1947 | dbg_info.appendSliceAssumeCapacity(name); | 1955 | dbg_info.appendSliceAssumeCapacity(name); |
| 1948 | dbg_info.appendAssumeCapacity(0); | 1956 | dbg_info.appendAssumeCapacity(0); |
| 1949 | }, | 1957 | }, |
| ... | @@ -2503,14 +2511,8 @@ fn cmp(self: *Self, lhs: WValue, rhs: WValue, ty: Type, op: std.math.CompareOper | ... | @@ -2503,14 +2511,8 @@ fn cmp(self: *Self, lhs: WValue, rhs: WValue, ty: Type, op: std.math.CompareOper |
| 2503 | | 2511 | |
| 2504 | // ensure that when we compare pointers, we emit | 2512 | // ensure that when we compare pointers, we emit |
| 2505 | // the true pointer of a stack value, rather than the stack pointer. | 2513 | // the true pointer of a stack value, rather than the stack pointer. |
| 2506 | switch (lhs) { | 2514 | try self.lowerToStack(lhs); |
| 2507 | .stack_offset => try self.emitWValue(try self.buildPointerOffset(lhs, 0, .new)), | 2515 | try self.lowerToStack(rhs); |
| 2508 | else => try self.emitWValue(lhs), | | |
| 2509 | } | | |
| 2510 | switch (rhs) { | | |
| 2511 | .stack_offset => try self.emitWValue(try self.buildPointerOffset(rhs, 0, .new)), | | |
| 2512 | else => try self.emitWValue(rhs), | | |
| 2513 | } | | |
| 2514 | | 2516 | |
| 2515 | const signedness: std.builtin.Signedness = blk: { | 2517 | const signedness: std.builtin.Signedness = blk: { |
| 2516 | // by default we tell the operand type is unsigned (i.e. bools and enum values) | 2518 | // by default we tell the operand type is unsigned (i.e. bools and enum values) |
| ... | @@ -2560,11 +2562,7 @@ fn airBr(self: *Self, inst: Air.Inst.Index) InnerError!WValue { | ... | @@ -2560,11 +2562,7 @@ fn airBr(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| 2560 | // if operand has codegen bits we should break with a value | 2562 | // if operand has codegen bits we should break with a value |
| 2561 | if (self.air.typeOf(br.operand).hasRuntimeBitsIgnoreComptime()) { | 2563 | if (self.air.typeOf(br.operand).hasRuntimeBitsIgnoreComptime()) { |
| 2562 | const operand = try self.resolveInst(br.operand); | 2564 | const operand = try self.resolveInst(br.operand); |
| 2563 | const op = switch (operand) { | 2565 | try self.lowerToStack(operand); |
| 2564 | .stack_offset => try self.buildPointerOffset(operand, 0, .new), | | |
| 2565 | else => operand, | | |
| 2566 | }; | | |
| 2567 | try self.emitWValue(op); | | |
| 2568 | | 2566 | |
| 2569 | if (block.value != .none) { | 2567 | if (block.value != .none) { |
| 2570 | try self.addLabel(.local_set, block.value.local); | 2568 | try self.addLabel(.local_set, block.value.local); |
| ... | @@ -3295,11 +3293,7 @@ fn airPtrElemVal(self: *Self, inst: Air.Inst.Index) InnerError!WValue { | ... | @@ -3295,11 +3293,7 @@ fn airPtrElemVal(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| 3295 | const ptr_local = try self.load(ptr, Type.usize, 0); | 3293 | const ptr_local = try self.load(ptr, Type.usize, 0); |
| 3296 | try self.addLabel(.local_get, ptr_local.local); | 3294 | try self.addLabel(.local_get, ptr_local.local); |
| 3297 | } else { | 3295 | } else { |
| 3298 | const pointer = switch (ptr) { | 3296 | try self.lowerToStack(ptr); |
| 3299 | .stack_offset => try self.buildPointerOffset(ptr, 0, .new), | | |
| 3300 | else => ptr, | | |
| 3301 | }; | | |
| 3302 | try self.emitWValue(pointer); | | |
| 3303 | } | 3297 | } |
| 3304 | | 3298 | |
| 3305 | // calculate index into slice | 3299 | // calculate index into slice |
| ... | @@ -3332,11 +3326,7 @@ fn airPtrElemPtr(self: *Self, inst: Air.Inst.Index) InnerError!WValue { | ... | @@ -3332,11 +3326,7 @@ fn airPtrElemPtr(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| 3332 | const ptr_local = try self.load(ptr, Type.usize, 0); | 3326 | const ptr_local = try self.load(ptr, Type.usize, 0); |
| 3333 | try self.addLabel(.local_get, ptr_local.local); | 3327 | try self.addLabel(.local_get, ptr_local.local); |
| 3334 | } else { | 3328 | } else { |
| 3335 | const pointer = switch (ptr) { | 3329 | try self.lowerToStack(ptr); |
| 3336 | .stack_offset => try self.buildPointerOffset(ptr, 0, .new), | | |
| 3337 | else => ptr, | | |
| 3338 | }; | | |
| 3339 | try self.emitWValue(pointer); | | |
| 3340 | } | 3330 | } |
| 3341 | | 3331 | |
| 3342 | // calculate index into ptr | 3332 | // calculate index into ptr |
| ... | @@ -3365,11 +3355,7 @@ fn airPtrBinOp(self: *Self, inst: Air.Inst.Index, op: Op) InnerError!WValue { | ... | @@ -3365,11 +3355,7 @@ fn airPtrBinOp(self: *Self, inst: Air.Inst.Index, op: Op) InnerError!WValue { |
| 3365 | const mul_opcode = buildOpcode(.{ .valtype1 = valtype, .op = .mul }); | 3355 | const mul_opcode = buildOpcode(.{ .valtype1 = valtype, .op = .mul }); |
| 3366 | const bin_opcode = buildOpcode(.{ .valtype1 = valtype, .op = op }); | 3356 | const bin_opcode = buildOpcode(.{ .valtype1 = valtype, .op = op }); |
| 3367 | | 3357 | |
| 3368 | const pointer = switch (ptr) { | 3358 | try self.lowerToStack(ptr); |
| 3369 | .stack_offset => try self.buildPointerOffset(ptr, 0, .new), | | |
| 3370 | else => ptr, | | |
| 3371 | }; | | |
| 3372 | try self.emitWValue(pointer); | | |
| 3373 | try self.emitWValue(offset); | 3359 | try self.emitWValue(offset); |
| 3374 | try self.addImm32(@bitCast(i32, @intCast(u32, pointee_ty.abiSize(self.target)))); | 3360 | try self.addImm32(@bitCast(i32, @intCast(u32, pointee_ty.abiSize(self.target)))); |
| 3375 | try self.addTag(Mir.Inst.Tag.fromOpcode(mul_opcode)); | 3361 | try self.addTag(Mir.Inst.Tag.fromOpcode(mul_opcode)); |
| ... | @@ -3400,10 +3386,7 @@ fn memset(self: *Self, ptr: WValue, len: WValue, value: WValue) InnerError!void | ... | @@ -3400,10 +3386,7 @@ fn memset(self: *Self, ptr: WValue, len: WValue, value: WValue) InnerError!void |
| 3400 | // When bulk_memory is enabled, we lower it to wasm's memset instruction. | 3386 | // When bulk_memory is enabled, we lower it to wasm's memset instruction. |
| 3401 | // If not, we lower it ourselves | 3387 | // If not, we lower it ourselves |
| 3402 | if (std.Target.wasm.featureSetHas(self.target.cpu.features, .bulk_memory)) { | 3388 | if (std.Target.wasm.featureSetHas(self.target.cpu.features, .bulk_memory)) { |
| 3403 | switch (ptr) { | 3389 | try self.lowerToStack(ptr); |
| 3404 | .stack_offset => try self.emitWValue(try self.buildPointerOffset(ptr, 0, .new)), | | |
| 3405 | else => try self.emitWValue(ptr), | | |
| 3406 | } | | |
| 3407 | try self.emitWValue(value); | 3390 | try self.emitWValue(value); |
| 3408 | try self.emitWValue(len); | 3391 | try self.emitWValue(len); |
| 3409 | try self.addExtended(.memory_fill); | 3392 | try self.addExtended(.memory_fill); |
| ... | @@ -3490,12 +3473,7 @@ fn airArrayElemVal(self: *Self, inst: Air.Inst.Index) InnerError!WValue { | ... | @@ -3490,12 +3473,7 @@ fn airArrayElemVal(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| 3490 | const elem_ty = array_ty.childType(); | 3473 | const elem_ty = array_ty.childType(); |
| 3491 | const elem_size = elem_ty.abiSize(self.target); | 3474 | const elem_size = elem_ty.abiSize(self.target); |
| 3492 | | 3475 | |
| 3493 | const array_ptr = switch (array) { | 3476 | try self.lowerToStack(array); |
| 3494 | .stack_offset => try self.buildPointerOffset(array, 0, .new), | | |
| 3495 | else => array, | | |
| 3496 | }; | | |
| 3497 | | | |
| 3498 | try self.emitWValue(array_ptr); | | |
| 3499 | try self.emitWValue(index); | 3477 | try self.emitWValue(index); |
| 3500 | try self.addImm32(@bitCast(i32, @intCast(u32, elem_size))); | 3478 | try self.addImm32(@bitCast(i32, @intCast(u32, elem_size))); |
| 3501 | try self.addTag(.i32_mul); | 3479 | try self.addTag(.i32_mul); |
| ... | @@ -3518,6 +3496,10 @@ fn airFloatToInt(self: *Self, inst: Air.Inst.Index) InnerError!WValue { | ... | @@ -3518,6 +3496,10 @@ fn airFloatToInt(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| 3518 | const dest_ty = self.air.typeOfIndex(inst); | 3496 | const dest_ty = self.air.typeOfIndex(inst); |
| 3519 | const op_ty = self.air.typeOf(ty_op.operand); | 3497 | const op_ty = self.air.typeOf(ty_op.operand); |
| 3520 | | 3498 | |
| | 3499 | if (op_ty.abiSize(self.target) > 8) { |
| | 3500 | return self.fail("TODO: floatToInt for integers/floats with bitsize larger than 64 bits", .{}); |
| | 3501 | } |
| | 3502 | |
| 3521 | try self.emitWValue(operand); | 3503 | try self.emitWValue(operand); |
| 3522 | const op = buildOpcode(.{ | 3504 | const op = buildOpcode(.{ |
| 3523 | .op = .trunc, | 3505 | .op = .trunc, |
| ... | @@ -3541,6 +3523,10 @@ fn airIntToFloat(self: *Self, inst: Air.Inst.Index) InnerError!WValue { | ... | @@ -3541,6 +3523,10 @@ fn airIntToFloat(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| 3541 | const dest_ty = self.air.typeOfIndex(inst); | 3523 | const dest_ty = self.air.typeOfIndex(inst); |
| 3542 | const op_ty = self.air.typeOf(ty_op.operand); | 3524 | const op_ty = self.air.typeOf(ty_op.operand); |
| 3543 | | 3525 | |
| | 3526 | if (op_ty.abiSize(self.target) > 8) { |
| | 3527 | return self.fail("TODO: intToFloat for integers/floats with bitsize larger than 64 bits", .{}); |
| | 3528 | } |
| | 3529 | |
| 3544 | try self.emitWValue(operand); | 3530 | try self.emitWValue(operand); |
| 3545 | const op = buildOpcode(.{ | 3531 | const op = buildOpcode(.{ |
| 3546 | .op = .convert, | 3532 | .op = .convert, |