authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2024-12-07 14:14:48-08:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-01-15 15:11:35-08:00
logd45e5ac5eb125c0dc69d29e8a0fbb363a18ebeb6
tree298ee2f9758c8487ef2578e8d7e5e75f8fc987b1
parent4a1447d1dbdc5638d94359d731379eba428a016d

wasm codegen: rename func: CodeGen to cg: CodeGen


1 files changed, 2505 insertions(+), 2507 deletions(-)

src/arch/wasm/CodeGen.zig+2505-2507
...@@ -700,22 +700,20 @@ const InnerError = error{...@@ -700,22 +700,20 @@ const InnerError = error{
700 Overflow,700 Overflow,
701} || link.File.UpdateDebugInfoError;701} || link.File.UpdateDebugInfoError;
702702
703pub fn deinit(func: *CodeGen) void {703pub fn deinit(cg: *CodeGen) void {
704 // in case of an error and we still have branches704 const gpa = cg.gpa;
705 for (func.branches.items) |*branch| {705 for (cg.branches.items) |*branch| branch.deinit(gpa);
706 branch.deinit(func.gpa);706 cg.branches.deinit(gpa);
707 }707 cg.blocks.deinit(gpa);
708 func.branches.deinit(func.gpa);708 cg.loops.deinit(gpa);
709 func.blocks.deinit(func.gpa);709 cg.locals.deinit(gpa);
710 func.loops.deinit(func.gpa);710 cg.simd_immediates.deinit(gpa);
711 func.locals.deinit(func.gpa);711 cg.free_locals_i32.deinit(gpa);
712 func.simd_immediates.deinit(func.gpa);712 cg.free_locals_i64.deinit(gpa);
713 func.free_locals_i32.deinit(func.gpa);713 cg.free_locals_f32.deinit(gpa);
714 func.free_locals_i64.deinit(func.gpa);714 cg.free_locals_f64.deinit(gpa);
715 func.free_locals_f32.deinit(func.gpa);715 cg.free_locals_v128.deinit(gpa);
716 func.free_locals_f64.deinit(func.gpa);716 cg.* = undefined;
717 func.free_locals_v128.deinit(func.gpa);
718 func.* = undefined;
719}717}
720718
721fn fail(cg: *CodeGen, comptime fmt: []const u8, args: anytype) error{ OutOfMemory, CodegenFail } {719fn fail(cg: *CodeGen, comptime fmt: []const u8, args: anytype) error{ OutOfMemory, CodegenFail } {
...@@ -726,10 +724,10 @@ fn fail(cg: *CodeGen, comptime fmt: []const u8, args: anytype) error{ OutOfMemor...@@ -726,10 +724,10 @@ fn fail(cg: *CodeGen, comptime fmt: []const u8, args: anytype) error{ OutOfMemor
726724
727/// Resolves the `WValue` for the given instruction `inst`725/// Resolves the `WValue` for the given instruction `inst`
728/// When the given instruction has a `Value`, it returns a constant instead726/// When the given instruction has a `Value`, it returns a constant instead
729fn resolveInst(func: *CodeGen, ref: Air.Inst.Ref) InnerError!WValue {727fn resolveInst(cg: *CodeGen, ref: Air.Inst.Ref) InnerError!WValue {
730 var branch_index = func.branches.items.len;728 var branch_index = cg.branches.items.len;
731 while (branch_index > 0) : (branch_index -= 1) {729 while (branch_index > 0) : (branch_index -= 1) {
732 const branch = func.branches.items[branch_index - 1];730 const branch = cg.branches.items[branch_index - 1];
733 if (branch.values.get(ref)) |value| {731 if (branch.values.get(ref)) |value| {
734 return value;732 return value;
735 }733 }
...@@ -739,13 +737,13 @@ fn resolveInst(func: *CodeGen, ref: Air.Inst.Ref) InnerError!WValue {...@@ -739,13 +737,13 @@ fn resolveInst(func: *CodeGen, ref: Air.Inst.Ref) InnerError!WValue {
739 // means we must generate it from a constant.737 // means we must generate it from a constant.
740 // We always store constants in the most outer branch as they must never738 // We always store constants in the most outer branch as they must never
741 // be removed. The most outer branch is always at index 0.739 // be removed. The most outer branch is always at index 0.
742 const gop = try func.branches.items[0].values.getOrPut(func.gpa, ref);740 const gop = try cg.branches.items[0].values.getOrPut(cg.gpa, ref);
743 assert(!gop.found_existing);741 assert(!gop.found_existing);
744742
745 const pt = func.pt;743 const pt = cg.pt;
746 const zcu = pt.zcu;744 const zcu = pt.zcu;
747 const val = (try func.air.value(ref, pt)).?;745 const val = (try cg.air.value(ref, pt)).?;
748 const ty = func.typeOf(ref);746 const ty = cg.typeOf(ref);
749 if (!ty.hasRuntimeBitsIgnoreComptime(zcu) and !ty.isInt(zcu) and !ty.isError(zcu)) {747 if (!ty.hasRuntimeBitsIgnoreComptime(zcu) and !ty.isInt(zcu) and !ty.isError(zcu)) {
750 gop.value_ptr.* = .none;748 gop.value_ptr.* = .none;
751 return .none;749 return .none;
...@@ -757,24 +755,24 @@ fn resolveInst(func: *CodeGen, ref: Air.Inst.Ref) InnerError!WValue {...@@ -757,24 +755,24 @@ fn resolveInst(func: *CodeGen, ref: Air.Inst.Ref) InnerError!WValue {
757 //755 //
758 // In the other cases, we will simply lower the constant to a value that fits756 // In the other cases, we will simply lower the constant to a value that fits
759 // into a single local (such as a pointer, integer, bool, etc).757 // into a single local (such as a pointer, integer, bool, etc).
760 const result: WValue = if (isByRef(ty, pt, func.target))758 const result: WValue = if (isByRef(ty, pt, cg.target))
761 .{ .uav_ref = .{ .ip_index = val.toIntern() } }759 .{ .uav_ref = .{ .ip_index = val.toIntern() } }
762 else760 else
763 try func.lowerConstant(val, ty);761 try cg.lowerConstant(val, ty);
764762
765 gop.value_ptr.* = result;763 gop.value_ptr.* = result;
766 return result;764 return result;
767}765}
768766
769/// NOTE: if result == .stack, it will be stored in .local767/// NOTE: if result == .stack, it will be stored in .local
770fn finishAir(func: *CodeGen, inst: Air.Inst.Index, result: WValue, operands: []const Air.Inst.Ref) InnerError!void {768fn finishAir(cg: *CodeGen, inst: Air.Inst.Index, result: WValue, operands: []const Air.Inst.Ref) InnerError!void {
771 assert(operands.len <= Liveness.bpi - 1);769 assert(operands.len <= Liveness.bpi - 1);
772 var tomb_bits = func.liveness.getTombBits(inst);770 var tomb_bits = cg.liveness.getTombBits(inst);
773 for (operands) |operand| {771 for (operands) |operand| {
774 const dies = @as(u1, @truncate(tomb_bits)) != 0;772 const dies = @as(u1, @truncate(tomb_bits)) != 0;
775 tomb_bits >>= 1;773 tomb_bits >>= 1;
776 if (!dies) continue;774 if (!dies) continue;
777 processDeath(func, operand);775 processDeath(cg, operand);
778 }776 }
779777
780 // results of `none` can never be referenced.778 // results of `none` can never be referenced.
...@@ -782,13 +780,13 @@ fn finishAir(func: *CodeGen, inst: Air.Inst.Index, result: WValue, operands: []c...@@ -782,13 +780,13 @@ fn finishAir(func: *CodeGen, inst: Air.Inst.Index, result: WValue, operands: []c
782 const trackable_result = if (result != .stack)780 const trackable_result = if (result != .stack)
783 result781 result
784 else782 else
785 try result.toLocal(func, func.typeOfIndex(inst));783 try result.toLocal(cg, cg.typeOfIndex(inst));
786 const branch = func.currentBranch();784 const branch = cg.currentBranch();
787 branch.values.putAssumeCapacityNoClobber(inst.toRef(), trackable_result);785 branch.values.putAssumeCapacityNoClobber(inst.toRef(), trackable_result);
788 }786 }
789787
790 if (std.debug.runtime_safety) {788 if (std.debug.runtime_safety) {
791 func.air_bookkeeping += 1;789 cg.air_bookkeeping += 1;
792 }790 }
793}791}
794792
...@@ -801,8 +799,8 @@ const Branch = struct {...@@ -801,8 +799,8 @@ const Branch = struct {
801 }799 }
802};800};
803801
804inline fn currentBranch(func: *CodeGen) *Branch {802inline fn currentBranch(cg: *CodeGen) *Branch {
805 return &func.branches.items[func.branches.items.len - 1];803 return &cg.branches.items[cg.branches.items.len - 1];
806}804}
807805
808const BigTomb = struct {806const BigTomb = struct {
...@@ -829,126 +827,126 @@ const BigTomb = struct {...@@ -829,126 +827,126 @@ const BigTomb = struct {
829 }827 }
830};828};
831829
832fn iterateBigTomb(func: *CodeGen, inst: Air.Inst.Index, operand_count: usize) !BigTomb {830fn iterateBigTomb(cg: *CodeGen, inst: Air.Inst.Index, operand_count: usize) !BigTomb {
833 try func.currentBranch().values.ensureUnusedCapacity(func.gpa, operand_count + 1);831 try cg.currentBranch().values.ensureUnusedCapacity(cg.gpa, operand_count + 1);
834 return BigTomb{832 return BigTomb{
835 .gen = func,833 .gen = cg,
836 .inst = inst,834 .inst = inst,
837 .lbt = func.liveness.iterateBigTomb(inst),835 .lbt = cg.liveness.iterateBigTomb(inst),
838 };836 };
839}837}
840838
841fn processDeath(func: *CodeGen, ref: Air.Inst.Ref) void {839fn processDeath(cg: *CodeGen, ref: Air.Inst.Ref) void {
842 if (ref.toIndex() == null) return;840 if (ref.toIndex() == null) return;
843 // Branches are currently only allowed to free locals allocated841 // Branches are currently only allowed to free locals allocated
844 // within their own branch.842 // within their own branch.
845 // TODO: Upon branch consolidation free any locals if needed.843 // TODO: Upon branch consolidation free any locals if needed.
846 const value = func.currentBranch().values.getPtr(ref) orelse return;844 const value = cg.currentBranch().values.getPtr(ref) orelse return;
847 if (value.* != .local) return;845 if (value.* != .local) return;
848 const reserved_indexes = func.args.len + @intFromBool(func.return_value != .none);846 const reserved_indexes = cg.args.len + @intFromBool(cg.return_value != .none);
849 if (value.local.value < reserved_indexes) {847 if (value.local.value < reserved_indexes) {
850 return; // function arguments can never be re-used848 return; // function arguments can never be re-used
851 }849 }
852 log.debug("Decreasing reference for ref: %{d}, using local '{d}'", .{ @intFromEnum(ref.toIndex().?), value.local.value });850 log.debug("Decreasing reference for ref: %{d}, using local '{d}'", .{ @intFromEnum(ref.toIndex().?), value.local.value });
853 value.local.references -= 1; // if this panics, a call to `reuseOperand` was forgotten by the developer851 value.local.references -= 1; // if this panics, a call to `reuseOperand` was forgotten by the developer
854 if (value.local.references == 0) {852 if (value.local.references == 0) {
855 value.free(func);853 value.free(cg);
856 }854 }
857}855}
858856
859/// Appends a MIR instruction and returns its index within the list of instructions857/// Appends a MIR instruction and returns its index within the list of instructions
860fn addInst(func: *CodeGen, inst: Mir.Inst) error{OutOfMemory}!void {858fn addInst(cg: *CodeGen, inst: Mir.Inst) error{OutOfMemory}!void {
861 try func.mir_instructions.append(func.gpa, inst);859 try cg.mir_instructions.append(cg.gpa, inst);
862}860}
863861
864fn addTag(func: *CodeGen, tag: Mir.Inst.Tag) error{OutOfMemory}!void {862fn addTag(cg: *CodeGen, tag: Mir.Inst.Tag) error{OutOfMemory}!void {
865 try func.addInst(.{ .tag = tag, .data = .{ .tag = {} } });863 try cg.addInst(.{ .tag = tag, .data = .{ .tag = {} } });
866}864}
867865
868fn addExtended(func: *CodeGen, opcode: std.wasm.MiscOpcode) error{OutOfMemory}!void {866fn addExtended(cg: *CodeGen, opcode: std.wasm.MiscOpcode) error{OutOfMemory}!void {
869 const extra_index = @as(u32, @intCast(func.mir_extra.items.len));867 const extra_index = @as(u32, @intCast(cg.mir_extra.items.len));
870 try func.mir_extra.append(func.gpa, @intFromEnum(opcode));868 try cg.mir_extra.append(cg.gpa, @intFromEnum(opcode));
871 try func.addInst(.{ .tag = .misc_prefix, .data = .{ .payload = extra_index } });869 try cg.addInst(.{ .tag = .misc_prefix, .data = .{ .payload = extra_index } });
872}870}
873871
874fn addLabel(func: *CodeGen, tag: Mir.Inst.Tag, label: u32) error{OutOfMemory}!void {872fn addLabel(cg: *CodeGen, tag: Mir.Inst.Tag, label: u32) error{OutOfMemory}!void {
875 try func.addInst(.{ .tag = tag, .data = .{ .label = label } });873 try cg.addInst(.{ .tag = tag, .data = .{ .label = label } });
876}874}
877875
878fn addIpIndex(func: *CodeGen, tag: Mir.Inst.Tag, i: InternPool.Index) Allocator.Error!void {876fn addIpIndex(cg: *CodeGen, tag: Mir.Inst.Tag, i: InternPool.Index) Allocator.Error!void {
879 try func.addInst(.{ .tag = tag, .data = .{ .ip_index = i } });877 try cg.addInst(.{ .tag = tag, .data = .{ .ip_index = i } });
880}878}
881879
882fn addNav(func: *CodeGen, tag: Mir.Inst.Tag, i: InternPool.Nav.Index) Allocator.Error!void {880fn addNav(cg: *CodeGen, tag: Mir.Inst.Tag, i: InternPool.Nav.Index) Allocator.Error!void {
883 try func.addInst(.{ .tag = tag, .data = .{ .nav_index = i } });881 try cg.addInst(.{ .tag = tag, .data = .{ .nav_index = i } });
884}882}
885883
886/// Accepts an unsigned 32bit integer rather than a signed integer to884/// Accepts an unsigned 32bit integer rather than a signed integer to
887/// prevent us from having to bitcast multiple times as most values885/// prevent us from having to bitcast multiple times as most values
888/// within codegen are represented as unsigned rather than signed.886/// within codegen are represented as unsigned rather than signed.
889fn addImm32(func: *CodeGen, imm: u32) error{OutOfMemory}!void {887fn addImm32(cg: *CodeGen, imm: u32) error{OutOfMemory}!void {
890 try func.addInst(.{ .tag = .i32_const, .data = .{ .imm32 = @bitCast(imm) } });888 try cg.addInst(.{ .tag = .i32_const, .data = .{ .imm32 = @bitCast(imm) } });
891}889}
892890
893/// Accepts an unsigned 64bit integer rather than a signed integer to891/// Accepts an unsigned 64bit integer rather than a signed integer to
894/// prevent us from having to bitcast multiple times as most values892/// prevent us from having to bitcast multiple times as most values
895/// within codegen are represented as unsigned rather than signed.893/// within codegen are represented as unsigned rather than signed.
896fn addImm64(func: *CodeGen, imm: u64) error{OutOfMemory}!void {894fn addImm64(cg: *CodeGen, imm: u64) error{OutOfMemory}!void {
897 const extra_index = try func.addExtra(Mir.Imm64.init(imm));895 const extra_index = try cg.addExtra(Mir.Imm64.init(imm));
898 try func.addInst(.{ .tag = .i64_const, .data = .{ .payload = extra_index } });896 try cg.addInst(.{ .tag = .i64_const, .data = .{ .payload = extra_index } });
899}897}
900898
901/// Accepts the index into the list of 128bit-immediates899/// Accepts the index into the list of 128bit-immediates
902fn addImm128(func: *CodeGen, index: u32) error{OutOfMemory}!void {900fn addImm128(cg: *CodeGen, index: u32) error{OutOfMemory}!void {
903 const simd_values = func.simd_immediates.items[index];901 const simd_values = cg.simd_immediates.items[index];
904 const extra_index = @as(u32, @intCast(func.mir_extra.items.len));902 const extra_index = @as(u32, @intCast(cg.mir_extra.items.len));
905 // tag + 128bit value903 // tag + 128bit value
906 try func.mir_extra.ensureUnusedCapacity(func.gpa, 5);904 try cg.mir_extra.ensureUnusedCapacity(cg.gpa, 5);
907 func.mir_extra.appendAssumeCapacity(@intFromEnum(std.wasm.SimdOpcode.v128_const));905 cg.mir_extra.appendAssumeCapacity(@intFromEnum(std.wasm.SimdOpcode.v128_const));
908 func.mir_extra.appendSliceAssumeCapacity(@alignCast(mem.bytesAsSlice(u32, &simd_values)));906 cg.mir_extra.appendSliceAssumeCapacity(@alignCast(mem.bytesAsSlice(u32, &simd_values)));
909 try func.addInst(.{ .tag = .simd_prefix, .data = .{ .payload = extra_index } });907 try cg.addInst(.{ .tag = .simd_prefix, .data = .{ .payload = extra_index } });
910}908}
911909
912fn addFloat64(func: *CodeGen, float: f64) error{OutOfMemory}!void {910fn addFloat64(cg: *CodeGen, float: f64) error{OutOfMemory}!void {
913 const extra_index = try func.addExtra(Mir.Float64.init(float));911 const extra_index = try cg.addExtra(Mir.Float64.init(float));
914 try func.addInst(.{ .tag = .f64_const, .data = .{ .payload = extra_index } });912 try cg.addInst(.{ .tag = .f64_const, .data = .{ .payload = extra_index } });
915}913}
916914
917/// Inserts an instruction to load/store from/to wasm's linear memory dependent on the given `tag`.915/// Inserts an instruction to load/store from/to wasm's linear memory dependent on the given `tag`.
918fn addMemArg(func: *CodeGen, tag: Mir.Inst.Tag, mem_arg: Mir.MemArg) error{OutOfMemory}!void {916fn addMemArg(cg: *CodeGen, tag: Mir.Inst.Tag, mem_arg: Mir.MemArg) error{OutOfMemory}!void {
919 const extra_index = try func.addExtra(mem_arg);917 const extra_index = try cg.addExtra(mem_arg);
920 try func.addInst(.{ .tag = tag, .data = .{ .payload = extra_index } });918 try cg.addInst(.{ .tag = tag, .data = .{ .payload = extra_index } });
921}919}
922920
923/// Inserts an instruction from the 'atomics' feature which accesses wasm's linear memory dependent on the921/// Inserts an instruction from the 'atomics' feature which accesses wasm's linear memory dependent on the
924/// given `tag`.922/// given `tag`.
925fn addAtomicMemArg(func: *CodeGen, tag: std.wasm.AtomicsOpcode, mem_arg: Mir.MemArg) error{OutOfMemory}!void {923fn addAtomicMemArg(cg: *CodeGen, tag: std.wasm.AtomicsOpcode, mem_arg: Mir.MemArg) error{OutOfMemory}!void {
926 const extra_index = try func.addExtra(@as(struct { val: u32 }, .{ .val = @intFromEnum(tag) }));924 const extra_index = try cg.addExtra(@as(struct { val: u32 }, .{ .val = @intFromEnum(tag) }));
927 _ = try func.addExtra(mem_arg);925 _ = try cg.addExtra(mem_arg);
928 try func.addInst(.{ .tag = .atomics_prefix, .data = .{ .payload = extra_index } });926 try cg.addInst(.{ .tag = .atomics_prefix, .data = .{ .payload = extra_index } });
929}927}
930928
931/// Helper function to emit atomic mir opcodes.929/// Helper function to emit atomic mir opcodes.
932fn addAtomicTag(func: *CodeGen, tag: std.wasm.AtomicsOpcode) error{OutOfMemory}!void {930fn addAtomicTag(cg: *CodeGen, tag: std.wasm.AtomicsOpcode) error{OutOfMemory}!void {
933 const extra_index = try func.addExtra(@as(struct { val: u32 }, .{ .val = @intFromEnum(tag) }));931 const extra_index = try cg.addExtra(@as(struct { val: u32 }, .{ .val = @intFromEnum(tag) }));
934 try func.addInst(.{ .tag = .atomics_prefix, .data = .{ .payload = extra_index } });932 try cg.addInst(.{ .tag = .atomics_prefix, .data = .{ .payload = extra_index } });
935}933}
936934
937/// Appends entries to `mir_extra` based on the type of `extra`.935/// Appends entries to `mir_extra` based on the type of `extra`.
938/// Returns the index into `mir_extra`936/// Returns the index into `mir_extra`
939fn addExtra(func: *CodeGen, extra: anytype) error{OutOfMemory}!u32 {937fn addExtra(cg: *CodeGen, extra: anytype) error{OutOfMemory}!u32 {
940 const fields = std.meta.fields(@TypeOf(extra));938 const fields = std.meta.fields(@TypeOf(extra));
941 try func.mir_extra.ensureUnusedCapacity(func.gpa, fields.len);939 try cg.mir_extra.ensureUnusedCapacity(cg.gpa, fields.len);
942 return func.addExtraAssumeCapacity(extra);940 return cg.addExtraAssumeCapacity(extra);
943}941}
944942
945/// Appends entries to `mir_extra` based on the type of `extra`.943/// Appends entries to `mir_extra` based on the type of `extra`.
946/// Returns the index into `mir_extra`944/// Returns the index into `mir_extra`
947fn addExtraAssumeCapacity(func: *CodeGen, extra: anytype) error{OutOfMemory}!u32 {945fn addExtraAssumeCapacity(cg: *CodeGen, extra: anytype) error{OutOfMemory}!u32 {
948 const fields = std.meta.fields(@TypeOf(extra));946 const fields = std.meta.fields(@TypeOf(extra));
949 const result = @as(u32, @intCast(func.mir_extra.items.len));947 const result = @as(u32, @intCast(cg.mir_extra.items.len));
950 inline for (fields) |field| {948 inline for (fields) |field| {
951 func.mir_extra.appendAssumeCapacity(switch (field.type) {949 cg.mir_extra.appendAssumeCapacity(switch (field.type) {
952 u32 => @field(extra, field.name),950 u32 => @field(extra, field.name),
953 i32 => @bitCast(@field(extra, field.name)),951 i32 => @bitCast(@field(extra, field.name)),
954 InternPool.Index => @intFromEnum(@field(extra, field.name)),952 InternPool.Index => @intFromEnum(@field(extra, field.name)),
...@@ -1015,24 +1013,24 @@ fn genBlockType(ty: Type, pt: Zcu.PerThread, target: *const std.Target) u8 {...@@ -1015,24 +1013,24 @@ fn genBlockType(ty: Type, pt: Zcu.PerThread, target: *const std.Target) u8 {
1015}1013}
10161014
1017/// Writes the bytecode depending on the given `WValue` in `val`1015/// Writes the bytecode depending on the given `WValue` in `val`
1018fn emitWValue(func: *CodeGen, value: WValue) InnerError!void {1016fn emitWValue(cg: *CodeGen, value: WValue) InnerError!void {
1019 switch (value) {1017 switch (value) {
1020 .dead => unreachable, // reference to free'd `WValue` (missing reuseOperand?)1018 .dead => unreachable, // reference to free'd `WValue` (missing reuseOperand?)
1021 .none, .stack => {}, // no-op1019 .none, .stack => {}, // no-op
1022 .local => |idx| try func.addLabel(.local_get, idx.value),1020 .local => |idx| try cg.addLabel(.local_get, idx.value),
1023 .imm32 => |val| try func.addImm32(val),1021 .imm32 => |val| try cg.addImm32(val),
1024 .imm64 => |val| try func.addImm64(val),1022 .imm64 => |val| try cg.addImm64(val),
1025 .imm128 => |val| try func.addImm128(val),1023 .imm128 => |val| try cg.addImm128(val),
1026 .float32 => |val| try func.addInst(.{ .tag = .f32_const, .data = .{ .float32 = val } }),1024 .float32 => |val| try cg.addInst(.{ .tag = .f32_const, .data = .{ .float32 = val } }),
1027 .float64 => |val| try func.addFloat64(val),1025 .float64 => |val| try cg.addFloat64(val),
1028 .nav_ref => |nav_ref| {1026 .nav_ref => |nav_ref| {
1029 if (nav_ref.offset == 0) {1027 if (nav_ref.offset == 0) {
1030 try func.addInst(.{ .tag = .nav_ref, .data = .{ .nav_index = nav_ref.nav_index } });1028 try cg.addInst(.{ .tag = .nav_ref, .data = .{ .nav_index = nav_ref.nav_index } });
1031 } else {1029 } else {
1032 try func.addInst(.{1030 try cg.addInst(.{
1033 .tag = .nav_ref_off,1031 .tag = .nav_ref_off,
1034 .data = .{1032 .data = .{
1035 .payload = try func.addExtra(Mir.NavRefOff{1033 .payload = try cg.addExtra(Mir.NavRefOff{
1036 .nav_index = nav_ref.nav_index,1034 .nav_index = nav_ref.nav_index,
1037 .offset = nav_ref.offset,1035 .offset = nav_ref.offset,
1038 }),1036 }),
...@@ -1042,12 +1040,12 @@ fn emitWValue(func: *CodeGen, value: WValue) InnerError!void {...@@ -1042,12 +1040,12 @@ fn emitWValue(func: *CodeGen, value: WValue) InnerError!void {
1042 },1040 },
1043 .uav_ref => |uav| {1041 .uav_ref => |uav| {
1044 if (uav.offset == 0) {1042 if (uav.offset == 0) {
1045 try func.addInst(.{ .tag = .uav_ref, .data = .{ .ip_index = uav.ip_index } });1043 try cg.addInst(.{ .tag = .uav_ref, .data = .{ .ip_index = uav.ip_index } });
1046 } else {1044 } else {
1047 try func.addInst(.{1045 try cg.addInst(.{
1048 .tag = .uav_ref_off,1046 .tag = .uav_ref_off,
1049 .data = .{1047 .data = .{
1050 .payload = try func.addExtra(Mir.UavRefOff{1048 .payload = try cg.addExtra(Mir.UavRefOff{
1051 .ip_index = uav.ip_index,1049 .ip_index = uav.ip_index,
1052 .offset = uav.offset,1050 .offset = uav.offset,
1053 }),1051 }),
...@@ -1055,7 +1053,7 @@ fn emitWValue(func: *CodeGen, value: WValue) InnerError!void {...@@ -1055,7 +1053,7 @@ fn emitWValue(func: *CodeGen, value: WValue) InnerError!void {
1055 });1053 });
1056 }1054 }
1057 },1055 },
1058 .stack_offset => try func.addLabel(.local_get, func.bottom_stack_value.local.value), // caller must ensure to address the offset1056 .stack_offset => try cg.addLabel(.local_get, cg.bottom_stack_value.local.value), // caller must ensure to address the offset
1059 }1057 }
1060}1058}
10611059
...@@ -1063,7 +1061,7 @@ fn emitWValue(func: *CodeGen, value: WValue) InnerError!void {...@@ -1063,7 +1061,7 @@ fn emitWValue(func: *CodeGen, value: WValue) InnerError!void {
1063/// The old `WValue` found at instruction `ref` is then replaced by the1061/// The old `WValue` found at instruction `ref` is then replaced by the
1064/// modified `WValue` and returned. When given a non-local or non-stack-offset,1062/// modified `WValue` and returned. When given a non-local or non-stack-offset,
1065/// returns the given `operand` itfunc instead.1063/// returns the given `operand` itfunc instead.
1066fn reuseOperand(func: *CodeGen, ref: Air.Inst.Ref, operand: WValue) WValue {1064fn reuseOperand(cg: *CodeGen, ref: Air.Inst.Ref, operand: WValue) WValue {
1067 if (operand != .local and operand != .stack_offset) return operand;1065 if (operand != .local and operand != .stack_offset) return operand;
1068 var new_value = operand;1066 var new_value = operand;
1069 switch (new_value) {1067 switch (new_value) {
...@@ -1071,17 +1069,17 @@ fn reuseOperand(func: *CodeGen, ref: Air.Inst.Ref, operand: WValue) WValue {...@@ -1071,17 +1069,17 @@ fn reuseOperand(func: *CodeGen, ref: Air.Inst.Ref, operand: WValue) WValue {
1071 .stack_offset => |*stack_offset| stack_offset.references += 1,1069 .stack_offset => |*stack_offset| stack_offset.references += 1,
1072 else => unreachable,1070 else => unreachable,
1073 }1071 }
1074 const old_value = func.getResolvedInst(ref);1072 const old_value = cg.getResolvedInst(ref);
1075 old_value.* = new_value;1073 old_value.* = new_value;
1076 return new_value;1074 return new_value;
1077}1075}
10781076
1079/// From a reference, returns its resolved `WValue`.1077/// From a reference, returns its resolved `WValue`.
1080/// It's illegal to provide a `Air.Inst.Ref` that hasn't been resolved yet.1078/// It's illegal to provide a `Air.Inst.Ref` that hasn't been resolved yet.
1081fn getResolvedInst(func: *CodeGen, ref: Air.Inst.Ref) *WValue {1079fn getResolvedInst(cg: *CodeGen, ref: Air.Inst.Ref) *WValue {
1082 var index = func.branches.items.len;1080 var index = cg.branches.items.len;
1083 while (index > 0) : (index -= 1) {1081 while (index > 0) : (index -= 1) {
1084 const branch = func.branches.items[index - 1];1082 const branch = cg.branches.items[index - 1];
1085 if (branch.values.getPtr(ref)) |value| {1083 if (branch.values.getPtr(ref)) |value| {
1086 return value;1084 return value;
1087 }1085 }
...@@ -1091,31 +1089,31 @@ fn getResolvedInst(func: *CodeGen, ref: Air.Inst.Ref) *WValue {...@@ -1091,31 +1089,31 @@ fn getResolvedInst(func: *CodeGen, ref: Air.Inst.Ref) *WValue {
10911089
1092/// Creates one locals for a given `Type`.1090/// Creates one locals for a given `Type`.
1093/// Returns a corresponding `Wvalue` with `local` as active tag1091/// Returns a corresponding `Wvalue` with `local` as active tag
1094fn allocLocal(func: *CodeGen, ty: Type) InnerError!WValue {1092fn allocLocal(cg: *CodeGen, ty: Type) InnerError!WValue {
1095 const pt = func.pt;1093 const pt = cg.pt;
1096 const valtype = typeToValtype(ty, pt, func.target);1094 const valtype = typeToValtype(ty, pt, cg.target);
1097 const index_or_null = switch (valtype) {1095 const index_or_null = switch (valtype) {
1098 .i32 => func.free_locals_i32.popOrNull(),1096 .i32 => cg.free_locals_i32.popOrNull(),
1099 .i64 => func.free_locals_i64.popOrNull(),1097 .i64 => cg.free_locals_i64.popOrNull(),
1100 .f32 => func.free_locals_f32.popOrNull(),1098 .f32 => cg.free_locals_f32.popOrNull(),
1101 .f64 => func.free_locals_f64.popOrNull(),1099 .f64 => cg.free_locals_f64.popOrNull(),
1102 .v128 => func.free_locals_v128.popOrNull(),1100 .v128 => cg.free_locals_v128.popOrNull(),
1103 };1101 };
1104 if (index_or_null) |index| {1102 if (index_or_null) |index| {
1105 log.debug("reusing local ({d}) of type {}", .{ index, valtype });1103 log.debug("reusing local ({d}) of type {}", .{ index, valtype });
1106 return .{ .local = .{ .value = index, .references = 1 } };1104 return .{ .local = .{ .value = index, .references = 1 } };
1107 }1105 }
1108 log.debug("new local of type {}", .{valtype});1106 log.debug("new local of type {}", .{valtype});
1109 return func.ensureAllocLocal(ty);1107 return cg.ensureAllocLocal(ty);
1110}1108}
11111109
1112/// Ensures a new local will be created. This is useful when it's useful1110/// Ensures a new local will be created. This is useful when it's useful
1113/// to use a zero-initialized local.1111/// to use a zero-initialized local.
1114fn ensureAllocLocal(func: *CodeGen, ty: Type) InnerError!WValue {1112fn ensureAllocLocal(cg: *CodeGen, ty: Type) InnerError!WValue {
1115 const pt = func.pt;1113 const pt = cg.pt;
1116 try func.locals.append(func.gpa, genValtype(ty, pt, func.target));1114 try cg.locals.append(cg.gpa, genValtype(ty, pt, cg.target));
1117 const initial_index = func.local_index;1115 const initial_index = cg.local_index;
1118 func.local_index += 1;1116 cg.local_index += 1;
1119 return .{ .local = .{ .value = initial_index, .references = 1 } };1117 return .{ .local = .{ .value = initial_index, .references = 1 } };
1120}1118}
11211119
...@@ -1291,10 +1289,10 @@ pub fn function(...@@ -1291,10 +1289,10 @@ pub fn function(
1291) Error!Function {1289) Error!Function {
1292 const zcu = pt.zcu;1290 const zcu = pt.zcu;
1293 const gpa = zcu.gpa;1291 const gpa = zcu.gpa;
1294 const func = zcu.funcInfo(func_index);1292 const cg = zcu.funcInfo(func_index);
1295 const file_scope = zcu.navFileScope(func.owner_nav);1293 const file_scope = zcu.navFileScope(cg.owner_nav);
1296 const target = &file_scope.mod.resolved_target.result;1294 const target = &file_scope.mod.resolved_target.result;
1297 const fn_ty = zcu.navValue(func.owner_nav).typeOf(zcu);1295 const fn_ty = zcu.navValue(cg.owner_nav).typeOf(zcu);
1298 const fn_info = zcu.typeToFunc(fn_ty).?;1296 const fn_info = zcu.typeToFunc(fn_ty).?;
1299 const ip = &zcu.intern_pool;1297 const ip = &zcu.intern_pool;
1300 const fn_ty_index = try genFunctype(wasm, fn_info.cc, fn_info.param_types.get(ip), Type.fromInterned(fn_info.return_type), pt, target);1298 const fn_ty_index = try genFunctype(wasm, fn_info.cc, fn_info.param_types.get(ip), Type.fromInterned(fn_info.return_type), pt, target);
...@@ -1309,7 +1307,7 @@ pub fn function(...@@ -1309,7 +1307,7 @@ pub fn function(
1309 .pt = pt,1307 .pt = pt,
1310 .air = air,1308 .air = air,
1311 .liveness = liveness,1309 .liveness = liveness,
1312 .owner_nav = func.owner_nav,1310 .owner_nav = cg.owner_nav,
1313 .target = target,1311 .target = target,
1314 .ptr_size = switch (target.cpu.arch) {1312 .ptr_size = switch (target.cpu.arch) {
1315 .wasm32 => .wasm32,1313 .wasm32 => .wasm32,
...@@ -1470,89 +1468,89 @@ fn firstParamSRet(...@@ -1470,89 +1468,89 @@ fn firstParamSRet(
14701468
1471/// Lowers a Zig type and its value based on a given calling convention to ensure1469/// Lowers a Zig type and its value based on a given calling convention to ensure
1472/// it matches the ABI.1470/// it matches the ABI.
1473fn lowerArg(func: *CodeGen, cc: std.builtin.CallingConvention, ty: Type, value: WValue) !void {1471fn lowerArg(cg: *CodeGen, cc: std.builtin.CallingConvention, ty: Type, value: WValue) !void {
1474 if (cc != .wasm_watc) {1472 if (cc != .wasm_watc) {
1475 return func.lowerToStack(value);1473 return cg.lowerToStack(value);
1476 }1474 }
14771475
1478 const pt = func.pt;1476 const pt = cg.pt;
1479 const zcu = pt.zcu;1477 const zcu = pt.zcu;
1480 const ty_classes = abi.classifyType(ty, zcu);1478 const ty_classes = abi.classifyType(ty, zcu);
1481 assert(ty_classes[0] != .none);1479 assert(ty_classes[0] != .none);
1482 switch (ty.zigTypeTag(zcu)) {1480 switch (ty.zigTypeTag(zcu)) {
1483 .@"struct", .@"union" => {1481 .@"struct", .@"union" => {
1484 if (ty_classes[0] == .indirect) {1482 if (ty_classes[0] == .indirect) {
1485 return func.lowerToStack(value);1483 return cg.lowerToStack(value);
1486 }1484 }
1487 assert(ty_classes[0] == .direct);1485 assert(ty_classes[0] == .direct);
1488 const scalar_type = abi.scalarType(ty, zcu);1486 const scalar_type = abi.scalarType(ty, zcu);
1489 switch (value) {1487 switch (value) {
1490 .nav_ref, .stack_offset => _ = try func.load(value, scalar_type, 0),1488 .nav_ref, .stack_offset => _ = try cg.load(value, scalar_type, 0),
1491 .dead => unreachable,1489 .dead => unreachable,
1492 else => try func.emitWValue(value),1490 else => try cg.emitWValue(value),
1493 }1491 }
1494 },1492 },
1495 .int, .float => {1493 .int, .float => {
1496 if (ty_classes[1] == .none) {1494 if (ty_classes[1] == .none) {
1497 return func.lowerToStack(value);1495 return cg.lowerToStack(value);
1498 }1496 }
1499 assert(ty_classes[0] == .direct and ty_classes[1] == .direct);1497 assert(ty_classes[0] == .direct and ty_classes[1] == .direct);
1500 assert(ty.abiSize(zcu) == 16);1498 assert(ty.abiSize(zcu) == 16);
1501 // in this case we have an integer or float that must be lowered as 2 i64's.1499 // in this case we have an integer or float that must be lowered as 2 i64's.
1502 try func.emitWValue(value);1500 try cg.emitWValue(value);
1503 try func.addMemArg(.i64_load, .{ .offset = value.offset(), .alignment = 8 });1501 try cg.addMemArg(.i64_load, .{ .offset = value.offset(), .alignment = 8 });
1504 try func.emitWValue(value);1502 try cg.emitWValue(value);
1505 try func.addMemArg(.i64_load, .{ .offset = value.offset() + 8, .alignment = 8 });1503 try cg.addMemArg(.i64_load, .{ .offset = value.offset() + 8, .alignment = 8 });
1506 },1504 },
1507 else => return func.lowerToStack(value),1505 else => return cg.lowerToStack(value),
1508 }1506 }
1509}1507}
15101508
1511/// Lowers a `WValue` to the stack. This means when the `value` results in1509/// Lowers a `WValue` to the stack. This means when the `value` results in
1512/// `.stack_offset` we calculate the pointer of this offset and use that.1510/// `.stack_offset` we calculate the pointer of this offset and use that.
1513/// The value is left on the stack, and not stored in any temporary.1511/// The value is left on the stack, and not stored in any temporary.
1514fn lowerToStack(func: *CodeGen, value: WValue) !void {1512fn lowerToStack(cg: *CodeGen, value: WValue) !void {
1515 switch (value) {1513 switch (value) {
1516 .stack_offset => |offset| {1514 .stack_offset => |offset| {
1517 try func.emitWValue(value);1515 try cg.emitWValue(value);
1518 if (offset.value > 0) {1516 if (offset.value > 0) {
1519 switch (func.ptr_size) {1517 switch (cg.ptr_size) {
1520 .wasm32 => {1518 .wasm32 => {
1521 try func.addImm32(offset.value);1519 try cg.addImm32(offset.value);
1522 try func.addTag(.i32_add);1520 try cg.addTag(.i32_add);
1523 },1521 },
1524 .wasm64 => {1522 .wasm64 => {
1525 try func.addImm64(offset.value);1523 try cg.addImm64(offset.value);
1526 try func.addTag(.i64_add);1524 try cg.addTag(.i64_add);
1527 },1525 },
1528 }1526 }
1529 }1527 }
1530 },1528 },
1531 else => try func.emitWValue(value),1529 else => try cg.emitWValue(value),
1532 }1530 }
1533}1531}
15341532
1535/// Creates a local for the initial stack value1533/// Creates a local for the initial stack value
1536/// Asserts `initial_stack_value` is `.none`1534/// Asserts `initial_stack_value` is `.none`
1537fn initializeStack(func: *CodeGen) !void {1535fn initializeStack(cg: *CodeGen) !void {
1538 assert(func.initial_stack_value == .none);1536 assert(cg.initial_stack_value == .none);
1539 // Reserve a local to store the current stack pointer1537 // Reserve a local to store the current stack pointer
1540 // We can later use this local to set the stack pointer back to the value1538 // We can later use this local to set the stack pointer back to the value
1541 // we have stored here.1539 // we have stored here.
1542 func.initial_stack_value = try func.ensureAllocLocal(Type.usize);1540 cg.initial_stack_value = try cg.ensureAllocLocal(Type.usize);
1543 // Also reserve a local to store the bottom stack value1541 // Also reserve a local to store the bottom stack value
1544 func.bottom_stack_value = try func.ensureAllocLocal(Type.usize);1542 cg.bottom_stack_value = try cg.ensureAllocLocal(Type.usize);
1545}1543}
15461544
1547/// Reads the stack pointer from `Context.initial_stack_value` and writes it1545/// Reads the stack pointer from `Context.initial_stack_value` and writes it
1548/// to the global stack pointer variable1546/// to the global stack pointer variable
1549fn restoreStackPointer(func: *CodeGen) !void {1547fn restoreStackPointer(cg: *CodeGen) !void {
1550 // only restore the pointer if it was initialized1548 // only restore the pointer if it was initialized
1551 if (func.initial_stack_value == .none) return;1549 if (cg.initial_stack_value == .none) return;
1552 // Get the original stack pointer's value1550 // Get the original stack pointer's value
1553 try func.emitWValue(func.initial_stack_value);1551 try cg.emitWValue(cg.initial_stack_value);
15541552
1555 try func.addTag(.global_set_sp);1553 try cg.addTag(.global_set_sp);
1556}1554}
15571555
1558/// From a given type, will create space on the virtual stack to store the value of such type.1556/// From a given type, will create space on the virtual stack to store the value of such type.
...@@ -1561,24 +1559,24 @@ fn restoreStackPointer(func: *CodeGen) !void {...@@ -1561,24 +1559,24 @@ fn restoreStackPointer(func: *CodeGen) !void {
1561/// moveStack unless a local was already created to store the pointer.1559/// moveStack unless a local was already created to store the pointer.
1562///1560///
1563/// Asserts Type has codegenbits1561/// Asserts Type has codegenbits
1564fn allocStack(func: *CodeGen, ty: Type) !WValue {1562fn allocStack(cg: *CodeGen, ty: Type) !WValue {
1565 const zcu = func.pt.zcu;1563 const zcu = cg.pt.zcu;
1566 assert(ty.hasRuntimeBitsIgnoreComptime(zcu));1564 assert(ty.hasRuntimeBitsIgnoreComptime(zcu));
1567 if (func.initial_stack_value == .none) {1565 if (cg.initial_stack_value == .none) {
1568 try func.initializeStack();1566 try cg.initializeStack();
1569 }1567 }
15701568
1571 const abi_size = std.math.cast(u32, ty.abiSize(zcu)) orelse {1569 const abi_size = std.math.cast(u32, ty.abiSize(zcu)) orelse {
1572 return func.fail("Type {} with ABI size of {d} exceeds stack frame size", .{1570 return cg.fail("Type {} with ABI size of {d} exceeds stack frame size", .{
1573 ty.fmt(func.pt), ty.abiSize(zcu),1571 ty.fmt(cg.pt), ty.abiSize(zcu),
1574 });1572 });
1575 };1573 };
1576 const abi_align = ty.abiAlignment(zcu);1574 const abi_align = ty.abiAlignment(zcu);
15771575
1578 func.stack_alignment = func.stack_alignment.max(abi_align);1576 cg.stack_alignment = cg.stack_alignment.max(abi_align);
15791577
1580 const offset: u32 = @intCast(abi_align.forward(func.stack_size));1578 const offset: u32 = @intCast(abi_align.forward(cg.stack_size));
1581 defer func.stack_size = offset + abi_size;1579 defer cg.stack_size = offset + abi_size;
15821580
1583 return .{ .stack_offset = .{ .value = offset, .references = 1 } };1581 return .{ .stack_offset = .{ .value = offset, .references = 1 } };
1584}1582}
...@@ -1587,30 +1585,30 @@ fn allocStack(func: *CodeGen, ty: Type) !WValue {...@@ -1587,30 +1585,30 @@ fn allocStack(func: *CodeGen, ty: Type) !WValue {
1587/// the value of its type will live.1585/// the value of its type will live.
1588/// This is different from allocStack where this will use the pointer's alignment1586/// This is different from allocStack where this will use the pointer's alignment
1589/// if it is set, to ensure the stack alignment will be set correctly.1587/// if it is set, to ensure the stack alignment will be set correctly.
1590fn allocStackPtr(func: *CodeGen, inst: Air.Inst.Index) !WValue {1588fn allocStackPtr(cg: *CodeGen, inst: Air.Inst.Index) !WValue {
1591 const pt = func.pt;1589 const pt = cg.pt;
1592 const zcu = pt.zcu;1590 const zcu = pt.zcu;
1593 const ptr_ty = func.typeOfIndex(inst);1591 const ptr_ty = cg.typeOfIndex(inst);
1594 const pointee_ty = ptr_ty.childType(zcu);1592 const pointee_ty = ptr_ty.childType(zcu);
15951593
1596 if (func.initial_stack_value == .none) {1594 if (cg.initial_stack_value == .none) {
1597 try func.initializeStack();1595 try cg.initializeStack();
1598 }1596 }
15991597
1600 if (!pointee_ty.hasRuntimeBitsIgnoreComptime(zcu)) {1598 if (!pointee_ty.hasRuntimeBitsIgnoreComptime(zcu)) {
1601 return func.allocStack(Type.usize); // create a value containing just the stack pointer.1599 return cg.allocStack(Type.usize); // create a value containing just the stack pointer.
1602 }1600 }
16031601
1604 const abi_alignment = ptr_ty.ptrAlignment(zcu);1602 const abi_alignment = ptr_ty.ptrAlignment(zcu);
1605 const abi_size = std.math.cast(u32, pointee_ty.abiSize(zcu)) orelse {1603 const abi_size = std.math.cast(u32, pointee_ty.abiSize(zcu)) orelse {
1606 return func.fail("Type {} with ABI size of {d} exceeds stack frame size", .{1604 return cg.fail("Type {} with ABI size of {d} exceeds stack frame size", .{
1607 pointee_ty.fmt(pt), pointee_ty.abiSize(zcu),1605 pointee_ty.fmt(pt), pointee_ty.abiSize(zcu),
1608 });1606 });
1609 };1607 };
1610 func.stack_alignment = func.stack_alignment.max(abi_alignment);1608 cg.stack_alignment = cg.stack_alignment.max(abi_alignment);
16111609
1612 const offset: u32 = @intCast(abi_alignment.forward(func.stack_size));1610 const offset: u32 = @intCast(abi_alignment.forward(cg.stack_size));
1613 defer func.stack_size = offset + abi_size;1611 defer cg.stack_size = offset + abi_size;
16141612
1615 return .{ .stack_offset = .{ .value = offset, .references = 1 } };1613 return .{ .stack_offset = .{ .value = offset, .references = 1 } };
1616}1614}
...@@ -1624,14 +1622,14 @@ fn toWasmBits(bits: u16) ?u16 {...@@ -1624,14 +1622,14 @@ fn toWasmBits(bits: u16) ?u16 {
16241622
1625/// Performs a copy of bytes for a given type. Copying all bytes1623/// Performs a copy of bytes for a given type. Copying all bytes
1626/// from rhs to lhs.1624/// from rhs to lhs.
1627fn memcpy(func: *CodeGen, dst: WValue, src: WValue, len: WValue) !void {1625fn memcpy(cg: *CodeGen, dst: WValue, src: WValue, len: WValue) !void {
1628 // When bulk_memory is enabled, we lower it to wasm's memcpy instruction.1626 // When bulk_memory is enabled, we lower it to wasm's memcpy instruction.
1629 // If not, we lower it ourselves manually1627 // If not, we lower it ourselves manually
1630 if (std.Target.wasm.featureSetHas(func.target.cpu.features, .bulk_memory)) {1628 if (std.Target.wasm.featureSetHas(cg.target.cpu.features, .bulk_memory)) {
1631 try func.lowerToStack(dst);1629 try cg.lowerToStack(dst);
1632 try func.lowerToStack(src);1630 try cg.lowerToStack(src);
1633 try func.emitWValue(len);1631 try cg.emitWValue(len);
1634 try func.addExtended(.memory_copy);1632 try cg.addExtended(.memory_copy);
1635 return;1633 return;
1636 }1634 }
16371635
...@@ -1652,17 +1650,17 @@ fn memcpy(func: *CodeGen, dst: WValue, src: WValue, len: WValue) !void {...@@ -1652,17 +1650,17 @@ fn memcpy(func: *CodeGen, dst: WValue, src: WValue, len: WValue) !void {
1652 const rhs_base = src.offset();1650 const rhs_base = src.offset();
1653 while (offset < length) : (offset += 1) {1651 while (offset < length) : (offset += 1) {
1654 // get dst's address to store the result1652 // get dst's address to store the result
1655 try func.emitWValue(dst);1653 try cg.emitWValue(dst);
1656 // load byte from src's address1654 // load byte from src's address
1657 try func.emitWValue(src);1655 try cg.emitWValue(src);
1658 switch (func.ptr_size) {1656 switch (cg.ptr_size) {
1659 .wasm32 => {1657 .wasm32 => {
1660 try func.addMemArg(.i32_load8_u, .{ .offset = rhs_base + offset, .alignment = 1 });1658 try cg.addMemArg(.i32_load8_u, .{ .offset = rhs_base + offset, .alignment = 1 });
1661 try func.addMemArg(.i32_store8, .{ .offset = lhs_base + offset, .alignment = 1 });1659 try cg.addMemArg(.i32_store8, .{ .offset = lhs_base + offset, .alignment = 1 });
1662 },1660 },
1663 .wasm64 => {1661 .wasm64 => {
1664 try func.addMemArg(.i64_load8_u, .{ .offset = rhs_base + offset, .alignment = 1 });1662 try cg.addMemArg(.i64_load8_u, .{ .offset = rhs_base + offset, .alignment = 1 });
1665 try func.addMemArg(.i64_store8, .{ .offset = lhs_base + offset, .alignment = 1 });1663 try cg.addMemArg(.i64_store8, .{ .offset = lhs_base + offset, .alignment = 1 });
1666 },1664 },
1667 }1665 }
1668 }1666 }
...@@ -1673,79 +1671,79 @@ fn memcpy(func: *CodeGen, dst: WValue, src: WValue, len: WValue) !void {...@@ -1673,79 +1671,79 @@ fn memcpy(func: *CodeGen, dst: WValue, src: WValue, len: WValue) !void {
16731671
1674 // allocate a local for the offset, and set it to 0.1672 // allocate a local for the offset, and set it to 0.
1675 // This to ensure that inside loops we correctly re-set the counter.1673 // This to ensure that inside loops we correctly re-set the counter.
1676 var offset = try func.allocLocal(Type.usize); // local for counter1674 var offset = try cg.allocLocal(Type.usize); // local for counter
1677 defer offset.free(func);1675 defer offset.free(cg);
1678 switch (func.ptr_size) {1676 switch (cg.ptr_size) {
1679 .wasm32 => try func.addImm32(0),1677 .wasm32 => try cg.addImm32(0),
1680 .wasm64 => try func.addImm64(0),1678 .wasm64 => try cg.addImm64(0),
1681 }1679 }
1682 try func.addLabel(.local_set, offset.local.value);1680 try cg.addLabel(.local_set, offset.local.value);
16831681
1684 // outer block to jump to when loop is done1682 // outer block to jump to when loop is done
1685 try func.startBlock(.block, std.wasm.block_empty);1683 try cg.startBlock(.block, std.wasm.block_empty);
1686 try func.startBlock(.loop, std.wasm.block_empty);1684 try cg.startBlock(.loop, std.wasm.block_empty);
16871685
1688 // loop condition (offset == length -> break)1686 // loop condition (offset == length -> break)
1689 {1687 {
1690 try func.emitWValue(offset);1688 try cg.emitWValue(offset);
1691 try func.emitWValue(len);1689 try cg.emitWValue(len);
1692 switch (func.ptr_size) {1690 switch (cg.ptr_size) {
1693 .wasm32 => try func.addTag(.i32_eq),1691 .wasm32 => try cg.addTag(.i32_eq),
1694 .wasm64 => try func.addTag(.i64_eq),1692 .wasm64 => try cg.addTag(.i64_eq),
1695 }1693 }
1696 try func.addLabel(.br_if, 1); // jump out of loop into outer block (finished)1694 try cg.addLabel(.br_if, 1); // jump out of loop into outer block (finished)
1697 }1695 }
16981696
1699 // get dst ptr1697 // get dst ptr
1700 {1698 {
1701 try func.emitWValue(dst);1699 try cg.emitWValue(dst);
1702 try func.emitWValue(offset);1700 try cg.emitWValue(offset);
1703 switch (func.ptr_size) {1701 switch (cg.ptr_size) {
1704 .wasm32 => try func.addTag(.i32_add),1702 .wasm32 => try cg.addTag(.i32_add),
1705 .wasm64 => try func.addTag(.i64_add),1703 .wasm64 => try cg.addTag(.i64_add),
1706 }1704 }
1707 }1705 }
17081706
1709 // get src value and also store in dst1707 // get src value and also store in dst
1710 {1708 {
1711 try func.emitWValue(src);1709 try cg.emitWValue(src);
1712 try func.emitWValue(offset);1710 try cg.emitWValue(offset);
1713 switch (func.ptr_size) {1711 switch (cg.ptr_size) {
1714 .wasm32 => {1712 .wasm32 => {
1715 try func.addTag(.i32_add);1713 try cg.addTag(.i32_add);
1716 try func.addMemArg(.i32_load8_u, .{ .offset = src.offset(), .alignment = 1 });1714 try cg.addMemArg(.i32_load8_u, .{ .offset = src.offset(), .alignment = 1 });
1717 try func.addMemArg(.i32_store8, .{ .offset = dst.offset(), .alignment = 1 });1715 try cg.addMemArg(.i32_store8, .{ .offset = dst.offset(), .alignment = 1 });
1718 },1716 },
1719 .wasm64 => {1717 .wasm64 => {
1720 try func.addTag(.i64_add);1718 try cg.addTag(.i64_add);
1721 try func.addMemArg(.i64_load8_u, .{ .offset = src.offset(), .alignment = 1 });1719 try cg.addMemArg(.i64_load8_u, .{ .offset = src.offset(), .alignment = 1 });
1722 try func.addMemArg(.i64_store8, .{ .offset = dst.offset(), .alignment = 1 });1720 try cg.addMemArg(.i64_store8, .{ .offset = dst.offset(), .alignment = 1 });
1723 },1721 },
1724 }1722 }
1725 }1723 }
17261724
1727 // increment loop counter1725 // increment loop counter
1728 {1726 {
1729 try func.emitWValue(offset);1727 try cg.emitWValue(offset);
1730 switch (func.ptr_size) {1728 switch (cg.ptr_size) {
1731 .wasm32 => {1729 .wasm32 => {
1732 try func.addImm32(1);1730 try cg.addImm32(1);
1733 try func.addTag(.i32_add);1731 try cg.addTag(.i32_add);
1734 },1732 },
1735 .wasm64 => {1733 .wasm64 => {
1736 try func.addImm64(1);1734 try cg.addImm64(1);
1737 try func.addTag(.i64_add);1735 try cg.addTag(.i64_add);
1738 },1736 },
1739 }1737 }
1740 try func.addLabel(.local_set, offset.local.value);1738 try cg.addLabel(.local_set, offset.local.value);
1741 try func.addLabel(.br, 0); // jump to start of loop1739 try cg.addLabel(.br, 0); // jump to start of loop
1742 }1740 }
1743 try func.endBlock(); // close off loop block1741 try cg.endBlock(); // close off loop block
1744 try func.endBlock(); // close off outer block1742 try cg.endBlock(); // close off outer block
1745}1743}
17461744
1747fn ptrSize(func: *const CodeGen) u16 {1745fn ptrSize(cg: *const CodeGen) u16 {
1748 return @divExact(func.target.ptrBitWidth(), 8);1746 return @divExact(cg.target.ptrBitWidth(), 8);
1749}1747}
17501748
1751/// For a given `Type`, will return true when the type will be passed1749/// For a given `Type`, will return true when the type will be passed
...@@ -1837,214 +1835,214 @@ fn determineSimdStoreStrategy(ty: Type, zcu: *Zcu, target: *const std.Target) Si...@@ -1837,214 +1835,214 @@ fn determineSimdStoreStrategy(ty: Type, zcu: *Zcu, target: *const std.Target) Si
1837/// This can be used to get a pointer to a struct field, error payload, etc.1835/// This can be used to get a pointer to a struct field, error payload, etc.
1838/// By providing `modify` as action, it will modify the given `ptr_value` instead of making a new1836/// By providing `modify` as action, it will modify the given `ptr_value` instead of making a new
1839/// local value to store the pointer. This allows for local re-use and improves binary size.1837/// local value to store the pointer. This allows for local re-use and improves binary size.
1840fn buildPointerOffset(func: *CodeGen, ptr_value: WValue, offset: u64, action: enum { modify, new }) InnerError!WValue {1838fn buildPointerOffset(cg: *CodeGen, ptr_value: WValue, offset: u64, action: enum { modify, new }) InnerError!WValue {
1841 // do not perform arithmetic when offset is 0.1839 // do not perform arithmetic when offset is 0.
1842 if (offset == 0 and ptr_value.offset() == 0 and action == .modify) return ptr_value;1840 if (offset == 0 and ptr_value.offset() == 0 and action == .modify) return ptr_value;
1843 const result_ptr: WValue = switch (action) {1841 const result_ptr: WValue = switch (action) {
1844 .new => try func.ensureAllocLocal(Type.usize),1842 .new => try cg.ensureAllocLocal(Type.usize),
1845 .modify => ptr_value,1843 .modify => ptr_value,
1846 };1844 };
1847 try func.emitWValue(ptr_value);1845 try cg.emitWValue(ptr_value);
1848 if (offset + ptr_value.offset() > 0) {1846 if (offset + ptr_value.offset() > 0) {
1849 switch (func.ptr_size) {1847 switch (cg.ptr_size) {
1850 .wasm32 => {1848 .wasm32 => {
1851 try func.addImm32(@intCast(offset + ptr_value.offset()));1849 try cg.addImm32(@intCast(offset + ptr_value.offset()));
1852 try func.addTag(.i32_add);1850 try cg.addTag(.i32_add);
1853 },1851 },
1854 .wasm64 => {1852 .wasm64 => {
1855 try func.addImm64(offset + ptr_value.offset());1853 try cg.addImm64(offset + ptr_value.offset());
1856 try func.addTag(.i64_add);1854 try cg.addTag(.i64_add);
1857 },1855 },
1858 }1856 }
1859 }1857 }
1860 try func.addLabel(.local_set, result_ptr.local.value);1858 try cg.addLabel(.local_set, result_ptr.local.value);
1861 return result_ptr;1859 return result_ptr;
1862}1860}
18631861
1864fn genInst(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {1862fn genInst(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
1865 const air_tags = func.air.instructions.items(.tag);1863 const air_tags = cg.air.instructions.items(.tag);
1866 return switch (air_tags[@intFromEnum(inst)]) {1864 return switch (air_tags[@intFromEnum(inst)]) {
1867 .inferred_alloc, .inferred_alloc_comptime => unreachable,1865 .inferred_alloc, .inferred_alloc_comptime => unreachable,
18681866
1869 .add => func.airBinOp(inst, .add),1867 .add => cg.airBinOp(inst, .add),
1870 .add_sat => func.airSatBinOp(inst, .add),1868 .add_sat => cg.airSatBinOp(inst, .add),
1871 .add_wrap => func.airWrapBinOp(inst, .add),1869 .add_wrap => cg.airWrapBinOp(inst, .add),
1872 .sub => func.airBinOp(inst, .sub),1870 .sub => cg.airBinOp(inst, .sub),
1873 .sub_sat => func.airSatBinOp(inst, .sub),1871 .sub_sat => cg.airSatBinOp(inst, .sub),
1874 .sub_wrap => func.airWrapBinOp(inst, .sub),1872 .sub_wrap => cg.airWrapBinOp(inst, .sub),
1875 .mul => func.airBinOp(inst, .mul),1873 .mul => cg.airBinOp(inst, .mul),
1876 .mul_sat => func.airSatMul(inst),1874 .mul_sat => cg.airSatMul(inst),
1877 .mul_wrap => func.airWrapBinOp(inst, .mul),1875 .mul_wrap => cg.airWrapBinOp(inst, .mul),
1878 .div_float, .div_exact => func.airDiv(inst),1876 .div_float, .div_exact => cg.airDiv(inst),
1879 .div_trunc => func.airDivTrunc(inst),1877 .div_trunc => cg.airDivTrunc(inst),
1880 .div_floor => func.airDivFloor(inst),1878 .div_floor => cg.airDivFloor(inst),
1881 .bit_and => func.airBinOp(inst, .@"and"),1879 .bit_and => cg.airBinOp(inst, .@"and"),
1882 .bit_or => func.airBinOp(inst, .@"or"),1880 .bit_or => cg.airBinOp(inst, .@"or"),
1883 .bool_and => func.airBinOp(inst, .@"and"),1881 .bool_and => cg.airBinOp(inst, .@"and"),
1884 .bool_or => func.airBinOp(inst, .@"or"),1882 .bool_or => cg.airBinOp(inst, .@"or"),
1885 .rem => func.airRem(inst),1883 .rem => cg.airRem(inst),
1886 .mod => func.airMod(inst),1884 .mod => cg.airMod(inst),
1887 .shl => func.airWrapBinOp(inst, .shl),1885 .shl => cg.airWrapBinOp(inst, .shl),
1888 .shl_exact => func.airBinOp(inst, .shl),1886 .shl_exact => cg.airBinOp(inst, .shl),
1889 .shl_sat => func.airShlSat(inst),1887 .shl_sat => cg.airShlSat(inst),
1890 .shr, .shr_exact => func.airBinOp(inst, .shr),1888 .shr, .shr_exact => cg.airBinOp(inst, .shr),
1891 .xor => func.airBinOp(inst, .xor),1889 .xor => cg.airBinOp(inst, .xor),
1892 .max => func.airMaxMin(inst, .max),1890 .max => cg.airMaxMin(inst, .max),
1893 .min => func.airMaxMin(inst, .min),1891 .min => cg.airMaxMin(inst, .min),
1894 .mul_add => func.airMulAdd(inst),1892 .mul_add => cg.airMulAdd(inst),
18951893
1896 .sqrt => func.airUnaryFloatOp(inst, .sqrt),1894 .sqrt => cg.airUnaryFloatOp(inst, .sqrt),
1897 .sin => func.airUnaryFloatOp(inst, .sin),1895 .sin => cg.airUnaryFloatOp(inst, .sin),
1898 .cos => func.airUnaryFloatOp(inst, .cos),1896 .cos => cg.airUnaryFloatOp(inst, .cos),
1899 .tan => func.airUnaryFloatOp(inst, .tan),1897 .tan => cg.airUnaryFloatOp(inst, .tan),
1900 .exp => func.airUnaryFloatOp(inst, .exp),1898 .exp => cg.airUnaryFloatOp(inst, .exp),
1901 .exp2 => func.airUnaryFloatOp(inst, .exp2),1899 .exp2 => cg.airUnaryFloatOp(inst, .exp2),
1902 .log => func.airUnaryFloatOp(inst, .log),1900 .log => cg.airUnaryFloatOp(inst, .log),
1903 .log2 => func.airUnaryFloatOp(inst, .log2),1901 .log2 => cg.airUnaryFloatOp(inst, .log2),
1904 .log10 => func.airUnaryFloatOp(inst, .log10),1902 .log10 => cg.airUnaryFloatOp(inst, .log10),
1905 .floor => func.airUnaryFloatOp(inst, .floor),1903 .floor => cg.airUnaryFloatOp(inst, .floor),
1906 .ceil => func.airUnaryFloatOp(inst, .ceil),1904 .ceil => cg.airUnaryFloatOp(inst, .ceil),
1907 .round => func.airUnaryFloatOp(inst, .round),1905 .round => cg.airUnaryFloatOp(inst, .round),
1908 .trunc_float => func.airUnaryFloatOp(inst, .trunc),1906 .trunc_float => cg.airUnaryFloatOp(inst, .trunc),
1909 .neg => func.airUnaryFloatOp(inst, .neg),1907 .neg => cg.airUnaryFloatOp(inst, .neg),
19101908
1911 .abs => func.airAbs(inst),1909 .abs => cg.airAbs(inst),
19121910
1913 .add_with_overflow => func.airAddSubWithOverflow(inst, .add),1911 .add_with_overflow => cg.airAddSubWithOverflow(inst, .add),
1914 .sub_with_overflow => func.airAddSubWithOverflow(inst, .sub),1912 .sub_with_overflow => cg.airAddSubWithOverflow(inst, .sub),
1915 .shl_with_overflow => func.airShlWithOverflow(inst),1913 .shl_with_overflow => cg.airShlWithOverflow(inst),
1916 .mul_with_overflow => func.airMulWithOverflow(inst),1914 .mul_with_overflow => cg.airMulWithOverflow(inst),
19171915
1918 .clz => func.airClz(inst),1916 .clz => cg.airClz(inst),
1919 .ctz => func.airCtz(inst),1917 .ctz => cg.airCtz(inst),
19201918
1921 .cmp_eq => func.airCmp(inst, .eq),1919 .cmp_eq => cg.airCmp(inst, .eq),
1922 .cmp_gte => func.airCmp(inst, .gte),1920 .cmp_gte => cg.airCmp(inst, .gte),
1923 .cmp_gt => func.airCmp(inst, .gt),1921 .cmp_gt => cg.airCmp(inst, .gt),
1924 .cmp_lte => func.airCmp(inst, .lte),1922 .cmp_lte => cg.airCmp(inst, .lte),
1925 .cmp_lt => func.airCmp(inst, .lt),1923 .cmp_lt => cg.airCmp(inst, .lt),
1926 .cmp_neq => func.airCmp(inst, .neq),1924 .cmp_neq => cg.airCmp(inst, .neq),
19271925
1928 .cmp_vector => func.airCmpVector(inst),1926 .cmp_vector => cg.airCmpVector(inst),
1929 .cmp_lt_errors_len => func.airCmpLtErrorsLen(inst),1927 .cmp_lt_errors_len => cg.airCmpLtErrorsLen(inst),
19301928
1931 .array_elem_val => func.airArrayElemVal(inst),1929 .array_elem_val => cg.airArrayElemVal(inst),
1932 .array_to_slice => func.airArrayToSlice(inst),1930 .array_to_slice => cg.airArrayToSlice(inst),
1933 .alloc => func.airAlloc(inst),1931 .alloc => cg.airAlloc(inst),
1934 .arg => func.airArg(inst),1932 .arg => cg.airArg(inst),
1935 .bitcast => func.airBitcast(inst),1933 .bitcast => cg.airBitcast(inst),
1936 .block => func.airBlock(inst),1934 .block => cg.airBlock(inst),
1937 .trap => func.airTrap(inst),1935 .trap => cg.airTrap(inst),
1938 .breakpoint => func.airBreakpoint(inst),1936 .breakpoint => cg.airBreakpoint(inst),
1939 .br => func.airBr(inst),1937 .br => cg.airBr(inst),
1940 .repeat => func.airRepeat(inst),1938 .repeat => cg.airRepeat(inst),
1941 .switch_dispatch => return func.fail("TODO implement `switch_dispatch`", .{}),1939 .switch_dispatch => return cg.fail("TODO implement `switch_dispatch`", .{}),
1942 .int_from_bool => func.airIntFromBool(inst),1940 .int_from_bool => cg.airIntFromBool(inst),
1943 .cond_br => func.airCondBr(inst),1941 .cond_br => cg.airCondBr(inst),
1944 .intcast => func.airIntcast(inst),1942 .intcast => cg.airIntcast(inst),
1945 .fptrunc => func.airFptrunc(inst),1943 .fptrunc => cg.airFptrunc(inst),
1946 .fpext => func.airFpext(inst),1944 .fpext => cg.airFpext(inst),
1947 .int_from_float => func.airIntFromFloat(inst),1945 .int_from_float => cg.airIntFromFloat(inst),
1948 .float_from_int => func.airFloatFromInt(inst),1946 .float_from_int => cg.airFloatFromInt(inst),
1949 .get_union_tag => func.airGetUnionTag(inst),1947 .get_union_tag => cg.airGetUnionTag(inst),
19501948
1951 .@"try" => func.airTry(inst),1949 .@"try" => cg.airTry(inst),
1952 .try_cold => func.airTry(inst),1950 .try_cold => cg.airTry(inst),
1953 .try_ptr => func.airTryPtr(inst),1951 .try_ptr => cg.airTryPtr(inst),
1954 .try_ptr_cold => func.airTryPtr(inst),1952 .try_ptr_cold => cg.airTryPtr(inst),
19551953
1956 .dbg_stmt => func.airDbgStmt(inst),1954 .dbg_stmt => cg.airDbgStmt(inst),
1957 .dbg_empty_stmt => try func.finishAir(inst, .none, &.{}),1955 .dbg_empty_stmt => try cg.finishAir(inst, .none, &.{}),
1958 .dbg_inline_block => func.airDbgInlineBlock(inst),1956 .dbg_inline_block => cg.airDbgInlineBlock(inst),
1959 .dbg_var_ptr => func.airDbgVar(inst, .local_var, true),1957 .dbg_var_ptr => cg.airDbgVar(inst, .local_var, true),
1960 .dbg_var_val => func.airDbgVar(inst, .local_var, false),1958 .dbg_var_val => cg.airDbgVar(inst, .local_var, false),
1961 .dbg_arg_inline => func.airDbgVar(inst, .local_arg, false),1959 .dbg_arg_inline => cg.airDbgVar(inst, .local_arg, false),
19621960
1963 .call => func.airCall(inst, .auto),1961 .call => cg.airCall(inst, .auto),
1964 .call_always_tail => func.airCall(inst, .always_tail),1962 .call_always_tail => cg.airCall(inst, .always_tail),
1965 .call_never_tail => func.airCall(inst, .never_tail),1963 .call_never_tail => cg.airCall(inst, .never_tail),
1966 .call_never_inline => func.airCall(inst, .never_inline),1964 .call_never_inline => cg.airCall(inst, .never_inline),
19671965
1968 .is_err => func.airIsErr(inst, .i32_ne),1966 .is_err => cg.airIsErr(inst, .i32_ne),
1969 .is_non_err => func.airIsErr(inst, .i32_eq),1967 .is_non_err => cg.airIsErr(inst, .i32_eq),
19701968
1971 .is_null => func.airIsNull(inst, .i32_eq, .value),1969 .is_null => cg.airIsNull(inst, .i32_eq, .value),
1972 .is_non_null => func.airIsNull(inst, .i32_ne, .value),1970 .is_non_null => cg.airIsNull(inst, .i32_ne, .value),
1973 .is_null_ptr => func.airIsNull(inst, .i32_eq, .ptr),1971 .is_null_ptr => cg.airIsNull(inst, .i32_eq, .ptr),
1974 .is_non_null_ptr => func.airIsNull(inst, .i32_ne, .ptr),1972 .is_non_null_ptr => cg.airIsNull(inst, .i32_ne, .ptr),
19751973
1976 .load => func.airLoad(inst),1974 .load => cg.airLoad(inst),
1977 .loop => func.airLoop(inst),1975 .loop => cg.airLoop(inst),
1978 .memset => func.airMemset(inst, false),1976 .memset => cg.airMemset(inst, false),
1979 .memset_safe => func.airMemset(inst, true),1977 .memset_safe => cg.airMemset(inst, true),
1980 .not => func.airNot(inst),1978 .not => cg.airNot(inst),
1981 .optional_payload => func.airOptionalPayload(inst),1979 .optional_payload => cg.airOptionalPayload(inst),
1982 .optional_payload_ptr => func.airOptionalPayloadPtr(inst),1980 .optional_payload_ptr => cg.airOptionalPayloadPtr(inst),
1983 .optional_payload_ptr_set => func.airOptionalPayloadPtrSet(inst),1981 .optional_payload_ptr_set => cg.airOptionalPayloadPtrSet(inst),
1984 .ptr_add => func.airPtrBinOp(inst, .add),1982 .ptr_add => cg.airPtrBinOp(inst, .add),
1985 .ptr_sub => func.airPtrBinOp(inst, .sub),1983 .ptr_sub => cg.airPtrBinOp(inst, .sub),
1986 .ptr_elem_ptr => func.airPtrElemPtr(inst),1984 .ptr_elem_ptr => cg.airPtrElemPtr(inst),
1987 .ptr_elem_val => func.airPtrElemVal(inst),1985 .ptr_elem_val => cg.airPtrElemVal(inst),
1988 .int_from_ptr => func.airIntFromPtr(inst),1986 .int_from_ptr => cg.airIntFromPtr(inst),
1989 .ret => func.airRet(inst),1987 .ret => cg.airRet(inst),
1990 .ret_safe => func.airRet(inst), // TODO1988 .ret_safe => cg.airRet(inst), // TODO
1991 .ret_ptr => func.airRetPtr(inst),1989 .ret_ptr => cg.airRetPtr(inst),
1992 .ret_load => func.airRetLoad(inst),1990 .ret_load => cg.airRetLoad(inst),
1993 .splat => func.airSplat(inst),1991 .splat => cg.airSplat(inst),
1994 .select => func.airSelect(inst),1992 .select => cg.airSelect(inst),
1995 .shuffle => func.airShuffle(inst),1993 .shuffle => cg.airShuffle(inst),
1996 .reduce => func.airReduce(inst),1994 .reduce => cg.airReduce(inst),
1997 .aggregate_init => func.airAggregateInit(inst),1995 .aggregate_init => cg.airAggregateInit(inst),
1998 .union_init => func.airUnionInit(inst),1996 .union_init => cg.airUnionInit(inst),
1999 .prefetch => func.airPrefetch(inst),1997 .prefetch => cg.airPrefetch(inst),
2000 .popcount => func.airPopcount(inst),1998 .popcount => cg.airPopcount(inst),
2001 .byte_swap => func.airByteSwap(inst),1999 .byte_swap => cg.airByteSwap(inst),
2002 .bit_reverse => func.airBitReverse(inst),2000 .bit_reverse => cg.airBitReverse(inst),
20032001
2004 .slice => func.airSlice(inst),2002 .slice => cg.airSlice(inst),
2005 .slice_len => func.airSliceLen(inst),2003 .slice_len => cg.airSliceLen(inst),
2006 .slice_elem_val => func.airSliceElemVal(inst),2004 .slice_elem_val => cg.airSliceElemVal(inst),
2007 .slice_elem_ptr => func.airSliceElemPtr(inst),2005 .slice_elem_ptr => cg.airSliceElemPtr(inst),
2008 .slice_ptr => func.airSlicePtr(inst),2006 .slice_ptr => cg.airSlicePtr(inst),
2009 .ptr_slice_len_ptr => func.airPtrSliceFieldPtr(inst, func.ptrSize()),2007 .ptr_slice_len_ptr => cg.airPtrSliceFieldPtr(inst, cg.ptrSize()),
2010 .ptr_slice_ptr_ptr => func.airPtrSliceFieldPtr(inst, 0),2008 .ptr_slice_ptr_ptr => cg.airPtrSliceFieldPtr(inst, 0),
2011 .store => func.airStore(inst, false),2009 .store => cg.airStore(inst, false),
2012 .store_safe => func.airStore(inst, true),2010 .store_safe => cg.airStore(inst, true),
20132011
2014 .set_union_tag => func.airSetUnionTag(inst),2012 .set_union_tag => cg.airSetUnionTag(inst),
2015 .struct_field_ptr => func.airStructFieldPtr(inst),2013 .struct_field_ptr => cg.airStructFieldPtr(inst),
2016 .struct_field_ptr_index_0 => func.airStructFieldPtrIndex(inst, 0),2014 .struct_field_ptr_index_0 => cg.airStructFieldPtrIndex(inst, 0),
2017 .struct_field_ptr_index_1 => func.airStructFieldPtrIndex(inst, 1),2015 .struct_field_ptr_index_1 => cg.airStructFieldPtrIndex(inst, 1),
2018 .struct_field_ptr_index_2 => func.airStructFieldPtrIndex(inst, 2),2016 .struct_field_ptr_index_2 => cg.airStructFieldPtrIndex(inst, 2),
2019 .struct_field_ptr_index_3 => func.airStructFieldPtrIndex(inst, 3),2017 .struct_field_ptr_index_3 => cg.airStructFieldPtrIndex(inst, 3),
2020 .struct_field_val => func.airStructFieldVal(inst),2018 .struct_field_val => cg.airStructFieldVal(inst),
2021 .field_parent_ptr => func.airFieldParentPtr(inst),2019 .field_parent_ptr => cg.airFieldParentPtr(inst),
20222020
2023 .switch_br => func.airSwitchBr(inst),2021 .switch_br => cg.airSwitchBr(inst),
2024 .loop_switch_br => return func.fail("TODO implement `loop_switch_br`", .{}),2022 .loop_switch_br => return cg.fail("TODO implement `loop_switch_br`", .{}),
2025 .trunc => func.airTrunc(inst),2023 .trunc => cg.airTrunc(inst),
2026 .unreach => func.airUnreachable(inst),2024 .unreach => cg.airUnreachable(inst),
20272025
2028 .wrap_optional => func.airWrapOptional(inst),2026 .wrap_optional => cg.airWrapOptional(inst),
2029 .unwrap_errunion_payload => func.airUnwrapErrUnionPayload(inst, false),2027 .unwrap_errunion_payload => cg.airUnwrapErrUnionPayload(inst, false),
2030 .unwrap_errunion_payload_ptr => func.airUnwrapErrUnionPayload(inst, true),2028 .unwrap_errunion_payload_ptr => cg.airUnwrapErrUnionPayload(inst, true),
2031 .unwrap_errunion_err => func.airUnwrapErrUnionError(inst, false),2029 .unwrap_errunion_err => cg.airUnwrapErrUnionError(inst, false),
2032 .unwrap_errunion_err_ptr => func.airUnwrapErrUnionError(inst, true),2030 .unwrap_errunion_err_ptr => cg.airUnwrapErrUnionError(inst, true),
2033 .wrap_errunion_payload => func.airWrapErrUnionPayload(inst),2031 .wrap_errunion_payload => cg.airWrapErrUnionPayload(inst),
2034 .wrap_errunion_err => func.airWrapErrUnionErr(inst),2032 .wrap_errunion_err => cg.airWrapErrUnionErr(inst),
2035 .errunion_payload_ptr_set => func.airErrUnionPayloadPtrSet(inst),2033 .errunion_payload_ptr_set => cg.airErrUnionPayloadPtrSet(inst),
2036 .error_name => func.airErrorName(inst),2034 .error_name => cg.airErrorName(inst),
20372035
2038 .wasm_memory_size => func.airWasmMemorySize(inst),2036 .wasm_memory_size => cg.airWasmMemorySize(inst),
2039 .wasm_memory_grow => func.airWasmMemoryGrow(inst),2037 .wasm_memory_grow => cg.airWasmMemoryGrow(inst),
20402038
2041 .memcpy => func.airMemcpy(inst),2039 .memcpy => cg.airMemcpy(inst),
20422040
2043 .ret_addr => func.airRetAddr(inst),2041 .ret_addr => cg.airRetAddr(inst),
2044 .tag_name => func.airTagName(inst),2042 .tag_name => cg.airTagName(inst),
20452043
2046 .error_set_has_value => func.airErrorSetHasValue(inst),2044 .error_set_has_value => cg.airErrorSetHasValue(inst),
2047 .frame_addr => func.airFrameAddress(inst),2045 .frame_addr => cg.airFrameAddress(inst),
20482046
2049 .assembly,2047 .assembly,
2050 .is_err_ptr,2048 .is_err_ptr,
...@@ -2060,18 +2058,18 @@ fn genInst(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -2060,18 +2058,18 @@ fn genInst(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
2060 .c_va_copy,2058 .c_va_copy,
2061 .c_va_end,2059 .c_va_end,
2062 .c_va_start,2060 .c_va_start,
2063 => |tag| return func.fail("TODO: Implement wasm inst: {s}", .{@tagName(tag)}),2061 => |tag| return cg.fail("TODO: Implement wasm inst: {s}", .{@tagName(tag)}),
20642062
2065 .atomic_load => func.airAtomicLoad(inst),2063 .atomic_load => cg.airAtomicLoad(inst),
2066 .atomic_store_unordered,2064 .atomic_store_unordered,
2067 .atomic_store_monotonic,2065 .atomic_store_monotonic,
2068 .atomic_store_release,2066 .atomic_store_release,
2069 .atomic_store_seq_cst,2067 .atomic_store_seq_cst,
2070 // in WebAssembly, all atomic instructions are sequentially ordered.2068 // in WebAssembly, all atomic instructions are sequentially ordered.
2071 => func.airAtomicStore(inst),2069 => cg.airAtomicStore(inst),
2072 .atomic_rmw => func.airAtomicRmw(inst),2070 .atomic_rmw => cg.airAtomicRmw(inst),
2073 .cmpxchg_weak => func.airCmpxchg(inst),2071 .cmpxchg_weak => cg.airCmpxchg(inst),
2074 .cmpxchg_strong => func.airCmpxchg(inst),2072 .cmpxchg_strong => cg.airCmpxchg(inst),
20752073
2076 .add_optimized,2074 .add_optimized,
2077 .sub_optimized,2075 .sub_optimized,
...@@ -2092,12 +2090,12 @@ fn genInst(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -2092,12 +2090,12 @@ fn genInst(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
2092 .cmp_vector_optimized,2090 .cmp_vector_optimized,
2093 .reduce_optimized,2091 .reduce_optimized,
2094 .int_from_float_optimized,2092 .int_from_float_optimized,
2095 => return func.fail("TODO implement optimized float mode", .{}),2093 => return cg.fail("TODO implement optimized float mode", .{}),
20962094
2097 .add_safe,2095 .add_safe,
2098 .sub_safe,2096 .sub_safe,
2099 .mul_safe,2097 .mul_safe,
2100 => return func.fail("TODO implement safety_checked_instructions", .{}),2098 => return cg.fail("TODO implement safety_checked_instructions", .{}),
21012099
2102 .work_item_id,2100 .work_item_id,
2103 .work_group_size,2101 .work_group_size,
...@@ -2106,124 +2104,124 @@ fn genInst(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -2106,124 +2104,124 @@ fn genInst(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
2106 };2104 };
2107}2105}
21082106
2109fn genBody(func: *CodeGen, body: []const Air.Inst.Index) InnerError!void {2107fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
2110 const pt = func.pt;2108 const pt = cg.pt;
2111 const zcu = pt.zcu;2109 const zcu = pt.zcu;
2112 const ip = &zcu.intern_pool;2110 const ip = &zcu.intern_pool;
21132111
2114 for (body) |inst| {2112 for (body) |inst| {
2115 if (func.liveness.isUnused(inst) and !func.air.mustLower(inst, ip)) {2113 if (cg.liveness.isUnused(inst) and !cg.air.mustLower(inst, ip)) {
2116 continue;2114 continue;
2117 }2115 }
2118 const old_bookkeeping_value = func.air_bookkeeping;2116 const old_bookkeeping_value = cg.air_bookkeeping;
2119 try func.currentBranch().values.ensureUnusedCapacity(func.gpa, Liveness.bpi);2117 try cg.currentBranch().values.ensureUnusedCapacity(cg.gpa, Liveness.bpi);
2120 try func.genInst(inst);2118 try cg.genInst(inst);
21212119
2122 if (std.debug.runtime_safety and func.air_bookkeeping < old_bookkeeping_value + 1) {2120 if (std.debug.runtime_safety and cg.air_bookkeeping < old_bookkeeping_value + 1) {
2123 std.debug.panic("Missing call to `finishAir` in AIR instruction %{d} ('{}')", .{2121 std.debug.panic("Missing call to `finishAir` in AIR instruction %{d} ('{}')", .{
2124 inst,2122 inst,
2125 func.air.instructions.items(.tag)[@intFromEnum(inst)],2123 cg.air.instructions.items(.tag)[@intFromEnum(inst)],
2126 });2124 });
2127 }2125 }
2128 }2126 }
2129}2127}
21302128
2131fn airRet(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {2129fn airRet(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
2132 const pt = func.pt;2130 const pt = cg.pt;
2133 const zcu = pt.zcu;2131 const zcu = pt.zcu;
2134 const un_op = func.air.instructions.items(.data)[@intFromEnum(inst)].un_op;2132 const un_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].un_op;
2135 const operand = try func.resolveInst(un_op);2133 const operand = try cg.resolveInst(un_op);
2136 const fn_info = zcu.typeToFunc(zcu.navValue(func.owner_nav).typeOf(zcu)).?;2134 const fn_info = zcu.typeToFunc(zcu.navValue(cg.owner_nav).typeOf(zcu)).?;
2137 const ret_ty = Type.fromInterned(fn_info.return_type);2135 const ret_ty = Type.fromInterned(fn_info.return_type);
21382136
2139 // result must be stored in the stack and we return a pointer2137 // result must be stored in the stack and we return a pointer
2140 // to the stack instead2138 // to the stack instead
2141 if (func.return_value != .none) {2139 if (cg.return_value != .none) {
2142 try func.store(func.return_value, operand, ret_ty, 0);2140 try cg.store(cg.return_value, operand, ret_ty, 0);
2143 } else if (fn_info.cc == .wasm_watc and ret_ty.hasRuntimeBitsIgnoreComptime(zcu)) {2141 } else if (fn_info.cc == .wasm_watc and ret_ty.hasRuntimeBitsIgnoreComptime(zcu)) {
2144 switch (ret_ty.zigTypeTag(zcu)) {2142 switch (ret_ty.zigTypeTag(zcu)) {
2145 // Aggregate types can be lowered as a singular value2143 // Aggregate types can be lowered as a singular value
2146 .@"struct", .@"union" => {2144 .@"struct", .@"union" => {
2147 const scalar_type = abi.scalarType(ret_ty, zcu);2145 const scalar_type = abi.scalarType(ret_ty, zcu);
2148 try func.emitWValue(operand);2146 try cg.emitWValue(operand);
2149 const opcode = buildOpcode(.{2147 const opcode = buildOpcode(.{
2150 .op = .load,2148 .op = .load,
2151 .width = @as(u8, @intCast(scalar_type.abiSize(zcu) * 8)),2149 .width = @as(u8, @intCast(scalar_type.abiSize(zcu) * 8)),
2152 .signedness = if (scalar_type.isSignedInt(zcu)) .signed else .unsigned,2150 .signedness = if (scalar_type.isSignedInt(zcu)) .signed else .unsigned,
2153 .valtype1 = typeToValtype(scalar_type, pt, func.target),2151 .valtype1 = typeToValtype(scalar_type, pt, cg.target),
2154 });2152 });
2155 try func.addMemArg(Mir.Inst.Tag.fromOpcode(opcode), .{2153 try cg.addMemArg(Mir.Inst.Tag.fromOpcode(opcode), .{
2156 .offset = operand.offset(),2154 .offset = operand.offset(),
2157 .alignment = @intCast(scalar_type.abiAlignment(zcu).toByteUnits().?),2155 .alignment = @intCast(scalar_type.abiAlignment(zcu).toByteUnits().?),
2158 });2156 });
2159 },2157 },
2160 else => try func.emitWValue(operand),2158 else => try cg.emitWValue(operand),
2161 }2159 }
2162 } else {2160 } else {
2163 if (!ret_ty.hasRuntimeBitsIgnoreComptime(zcu) and ret_ty.isError(zcu)) {2161 if (!ret_ty.hasRuntimeBitsIgnoreComptime(zcu) and ret_ty.isError(zcu)) {
2164 try func.addImm32(0);2162 try cg.addImm32(0);
2165 } else {2163 } else {
2166 try func.emitWValue(operand);2164 try cg.emitWValue(operand);
2167 }2165 }
2168 }2166 }
2169 try func.restoreStackPointer();2167 try cg.restoreStackPointer();
2170 try func.addTag(.@"return");2168 try cg.addTag(.@"return");
21712169
2172 return func.finishAir(inst, .none, &.{un_op});2170 return cg.finishAir(inst, .none, &.{un_op});
2173}2171}
21742172
2175fn airRetPtr(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {2173fn airRetPtr(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
2176 const pt = func.pt;2174 const pt = cg.pt;
2177 const zcu = pt.zcu;2175 const zcu = pt.zcu;
2178 const child_type = func.typeOfIndex(inst).childType(zcu);2176 const child_type = cg.typeOfIndex(inst).childType(zcu);
21792177
2180 const result = result: {2178 const result = result: {
2181 if (!child_type.isFnOrHasRuntimeBitsIgnoreComptime(zcu)) {2179 if (!child_type.isFnOrHasRuntimeBitsIgnoreComptime(zcu)) {
2182 break :result try func.allocStack(Type.usize); // create pointer to void2180 break :result try cg.allocStack(Type.usize); // create pointer to void
2183 }2181 }
21842182
2185 const fn_info = zcu.typeToFunc(zcu.navValue(func.owner_nav).typeOf(zcu)).?;2183 const fn_info = zcu.typeToFunc(zcu.navValue(cg.owner_nav).typeOf(zcu)).?;
2186 if (firstParamSRet(fn_info.cc, Type.fromInterned(fn_info.return_type), pt, func.target)) {2184 if (firstParamSRet(fn_info.cc, Type.fromInterned(fn_info.return_type), pt, cg.target)) {
2187 break :result func.return_value;2185 break :result cg.return_value;
2188 }2186 }
21892187
2190 break :result try func.allocStackPtr(inst);2188 break :result try cg.allocStackPtr(inst);
2191 };2189 };
21922190
2193 return func.finishAir(inst, result, &.{});2191 return cg.finishAir(inst, result, &.{});
2194}2192}
21952193
2196fn airRetLoad(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {2194fn airRetLoad(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
2197 const pt = func.pt;2195 const pt = cg.pt;
2198 const zcu = pt.zcu;2196 const zcu = pt.zcu;
2199 const un_op = func.air.instructions.items(.data)[@intFromEnum(inst)].un_op;2197 const un_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].un_op;
2200 const operand = try func.resolveInst(un_op);2198 const operand = try cg.resolveInst(un_op);
2201 const ret_ty = func.typeOf(un_op).childType(zcu);2199 const ret_ty = cg.typeOf(un_op).childType(zcu);
22022200
2203 const fn_info = zcu.typeToFunc(zcu.navValue(func.owner_nav).typeOf(zcu)).?;2201 const fn_info = zcu.typeToFunc(zcu.navValue(cg.owner_nav).typeOf(zcu)).?;
2204 if (!ret_ty.hasRuntimeBitsIgnoreComptime(zcu)) {2202 if (!ret_ty.hasRuntimeBitsIgnoreComptime(zcu)) {
2205 if (ret_ty.isError(zcu)) {2203 if (ret_ty.isError(zcu)) {
2206 try func.addImm32(0);2204 try cg.addImm32(0);
2207 }2205 }
2208 } else if (!firstParamSRet(fn_info.cc, Type.fromInterned(fn_info.return_type), pt, func.target)) {2206 } else if (!firstParamSRet(fn_info.cc, Type.fromInterned(fn_info.return_type), pt, cg.target)) {
2209 // leave on the stack2207 // leave on the stack
2210 _ = try func.load(operand, ret_ty, 0);2208 _ = try cg.load(operand, ret_ty, 0);
2211 }2209 }
22122210
2213 try func.restoreStackPointer();2211 try cg.restoreStackPointer();
2214 try func.addTag(.@"return");2212 try cg.addTag(.@"return");
2215 return func.finishAir(inst, .none, &.{un_op});2213 return cg.finishAir(inst, .none, &.{un_op});
2216}2214}
22172215
2218fn airCall(func: *CodeGen, inst: Air.Inst.Index, modifier: std.builtin.CallModifier) InnerError!void {2216fn airCall(cg: *CodeGen, inst: Air.Inst.Index, modifier: std.builtin.CallModifier) InnerError!void {
2219 const wasm = func.wasm;2217 const wasm = cg.wasm;
2220 if (modifier == .always_tail) return func.fail("TODO implement tail calls for wasm", .{});2218 if (modifier == .always_tail) return cg.fail("TODO implement tail calls for wasm", .{});
2221 const pl_op = func.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;2219 const pl_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;
2222 const extra = func.air.extraData(Air.Call, pl_op.payload);2220 const extra = cg.air.extraData(Air.Call, pl_op.payload);
2223 const args: []const Air.Inst.Ref = @ptrCast(func.air.extra[extra.end..][0..extra.data.args_len]);2221 const args: []const Air.Inst.Ref = @ptrCast(cg.air.extra[extra.end..][0..extra.data.args_len]);
2224 const ty = func.typeOf(pl_op.operand);2222 const ty = cg.typeOf(pl_op.operand);
22252223
2226 const pt = func.pt;2224 const pt = cg.pt;
2227 const zcu = pt.zcu;2225 const zcu = pt.zcu;
2228 const ip = &zcu.intern_pool;2226 const ip = &zcu.intern_pool;
2229 const fn_ty = switch (ty.zigTypeTag(zcu)) {2227 const fn_ty = switch (ty.zigTypeTag(zcu)) {
...@@ -2233,10 +2231,10 @@ fn airCall(func: *CodeGen, inst: Air.Inst.Index, modifier: std.builtin.CallModif...@@ -2233,10 +2231,10 @@ fn airCall(func: *CodeGen, inst: Air.Inst.Index, modifier: std.builtin.CallModif
2233 };2231 };
2234 const ret_ty = fn_ty.fnReturnType(zcu);2232 const ret_ty = fn_ty.fnReturnType(zcu);
2235 const fn_info = zcu.typeToFunc(fn_ty).?;2233 const fn_info = zcu.typeToFunc(fn_ty).?;
2236 const first_param_sret = firstParamSRet(fn_info.cc, Type.fromInterned(fn_info.return_type), pt, func.target);2234 const first_param_sret = firstParamSRet(fn_info.cc, Type.fromInterned(fn_info.return_type), pt, cg.target);
22372235
2238 const callee: ?InternPool.Nav.Index = blk: {2236 const callee: ?InternPool.Nav.Index = blk: {
2239 const func_val = (try func.air.value(pl_op.operand, pt)) orelse break :blk null;2237 const func_val = (try cg.air.value(pl_op.operand, pt)) orelse break :blk null;
22402238
2241 switch (ip.indexToKey(func_val.toIntern())) {2239 switch (ip.indexToKey(func_val.toIntern())) {
2242 inline .func, .@"extern" => |x| break :blk x.owner_nav,2240 inline .func, .@"extern" => |x| break :blk x.owner_nav,
...@@ -2246,96 +2244,96 @@ fn airCall(func: *CodeGen, inst: Air.Inst.Index, modifier: std.builtin.CallModif...@@ -2246,96 +2244,96 @@ fn airCall(func: *CodeGen, inst: Air.Inst.Index, modifier: std.builtin.CallModif
2246 },2244 },
2247 else => {},2245 else => {},
2248 }2246 }
2249 return func.fail("unable to lower callee to a function index", .{});2247 return cg.fail("unable to lower callee to a function index", .{});
2250 };2248 };
22512249
2252 const sret: WValue = if (first_param_sret) blk: {2250 const sret: WValue = if (first_param_sret) blk: {
2253 const sret_local = try func.allocStack(ret_ty);2251 const sret_local = try cg.allocStack(ret_ty);
2254 try func.lowerToStack(sret_local);2252 try cg.lowerToStack(sret_local);
2255 break :blk sret_local;2253 break :blk sret_local;
2256 } else .none;2254 } else .none;
22572255
2258 for (args) |arg| {2256 for (args) |arg| {
2259 const arg_val = try func.resolveInst(arg);2257 const arg_val = try cg.resolveInst(arg);
22602258
2261 const arg_ty = func.typeOf(arg);2259 const arg_ty = cg.typeOf(arg);
2262 if (!arg_ty.hasRuntimeBitsIgnoreComptime(zcu)) continue;2260 if (!arg_ty.hasRuntimeBitsIgnoreComptime(zcu)) continue;
22632261
2264 try func.lowerArg(zcu.typeToFunc(fn_ty).?.cc, arg_ty, arg_val);2262 try cg.lowerArg(zcu.typeToFunc(fn_ty).?.cc, arg_ty, arg_val);
2265 }2263 }
22662264
2267 if (callee) |nav_index| {2265 if (callee) |nav_index| {
2268 try func.addNav(.call_nav, nav_index);2266 try cg.addNav(.call_nav, nav_index);
2269 } else {2267 } else {
2270 // in this case we call a function pointer2268 // in this case we call a function pointer
2271 // so load its value onto the stack2269 // so load its value onto the stack
2272 assert(ty.zigTypeTag(zcu) == .pointer);2270 assert(ty.zigTypeTag(zcu) == .pointer);
2273 const operand = try func.resolveInst(pl_op.operand);2271 const operand = try cg.resolveInst(pl_op.operand);
2274 try func.emitWValue(operand);2272 try cg.emitWValue(operand);
22752273
2276 const fn_type_index = try genFunctype(wasm, fn_info.cc, fn_info.param_types.get(ip), Type.fromInterned(fn_info.return_type), pt, func.target);2274 const fn_type_index = try genFunctype(wasm, fn_info.cc, fn_info.param_types.get(ip), Type.fromInterned(fn_info.return_type), pt, cg.target);
2277 try func.addLabel(.call_indirect, @intFromEnum(fn_type_index));2275 try cg.addLabel(.call_indirect, @intFromEnum(fn_type_index));
2278 }2276 }
22792277
2280 const result_value = result_value: {2278 const result_value = result_value: {
2281 if (!ret_ty.hasRuntimeBitsIgnoreComptime(zcu) and !ret_ty.isError(zcu)) {2279 if (!ret_ty.hasRuntimeBitsIgnoreComptime(zcu) and !ret_ty.isError(zcu)) {
2282 break :result_value .none;2280 break :result_value .none;
2283 } else if (ret_ty.isNoReturn(zcu)) {2281 } else if (ret_ty.isNoReturn(zcu)) {
2284 try func.addTag(.@"unreachable");2282 try cg.addTag(.@"unreachable");
2285 break :result_value .none;2283 break :result_value .none;
2286 } else if (first_param_sret) {2284 } else if (first_param_sret) {
2287 break :result_value sret;2285 break :result_value sret;
2288 // TODO: Make this less fragile and optimize2286 // TODO: Make this less fragile and optimize
2289 } else if (zcu.typeToFunc(fn_ty).?.cc == .wasm_watc and ret_ty.zigTypeTag(zcu) == .@"struct" or ret_ty.zigTypeTag(zcu) == .@"union") {2287 } else if (zcu.typeToFunc(fn_ty).?.cc == .wasm_watc and ret_ty.zigTypeTag(zcu) == .@"struct" or ret_ty.zigTypeTag(zcu) == .@"union") {
2290 const result_local = try func.allocLocal(ret_ty);2288 const result_local = try cg.allocLocal(ret_ty);
2291 try func.addLabel(.local_set, result_local.local.value);2289 try cg.addLabel(.local_set, result_local.local.value);
2292 const scalar_type = abi.scalarType(ret_ty, zcu);2290 const scalar_type = abi.scalarType(ret_ty, zcu);
2293 const result = try func.allocStack(scalar_type);2291 const result = try cg.allocStack(scalar_type);
2294 try func.store(result, result_local, scalar_type, 0);2292 try cg.store(result, result_local, scalar_type, 0);
2295 break :result_value result;2293 break :result_value result;
2296 } else {2294 } else {
2297 const result_local = try func.allocLocal(ret_ty);2295 const result_local = try cg.allocLocal(ret_ty);
2298 try func.addLabel(.local_set, result_local.local.value);2296 try cg.addLabel(.local_set, result_local.local.value);
2299 break :result_value result_local;2297 break :result_value result_local;
2300 }2298 }
2301 };2299 };
23022300
2303 var bt = try func.iterateBigTomb(inst, 1 + args.len);2301 var bt = try cg.iterateBigTomb(inst, 1 + args.len);
2304 bt.feed(pl_op.operand);2302 bt.feed(pl_op.operand);
2305 for (args) |arg| bt.feed(arg);2303 for (args) |arg| bt.feed(arg);
2306 return bt.finishAir(result_value);2304 return bt.finishAir(result_value);
2307}2305}
23082306
2309fn airAlloc(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {2307fn airAlloc(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
2310 const value = try func.allocStackPtr(inst);2308 const value = try cg.allocStackPtr(inst);
2311 return func.finishAir(inst, value, &.{});2309 return cg.finishAir(inst, value, &.{});
2312}2310}
23132311
2314fn airStore(func: *CodeGen, inst: Air.Inst.Index, safety: bool) InnerError!void {2312fn airStore(cg: *CodeGen, inst: Air.Inst.Index, safety: bool) InnerError!void {
2315 const pt = func.pt;2313 const pt = cg.pt;
2316 const zcu = pt.zcu;2314 const zcu = pt.zcu;
2317 if (safety) {2315 if (safety) {
2318 // TODO if the value is undef, write 0xaa bytes to dest2316 // TODO if the value is undef, write 0xaa bytes to dest
2319 } else {2317 } else {
2320 // TODO if the value is undef, don't lower this instruction2318 // TODO if the value is undef, don't lower this instruction
2321 }2319 }
2322 const bin_op = func.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;2320 const bin_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
23232321
2324 const lhs = try func.resolveInst(bin_op.lhs);2322 const lhs = try cg.resolveInst(bin_op.lhs);
2325 const rhs = try func.resolveInst(bin_op.rhs);2323 const rhs = try cg.resolveInst(bin_op.rhs);
2326 const ptr_ty = func.typeOf(bin_op.lhs);2324 const ptr_ty = cg.typeOf(bin_op.lhs);
2327 const ptr_info = ptr_ty.ptrInfo(zcu);2325 const ptr_info = ptr_ty.ptrInfo(zcu);
2328 const ty = ptr_ty.childType(zcu);2326 const ty = ptr_ty.childType(zcu);
23292327
2330 if (ptr_info.packed_offset.host_size == 0) {2328 if (ptr_info.packed_offset.host_size == 0) {
2331 try func.store(lhs, rhs, ty, 0);2329 try cg.store(lhs, rhs, ty, 0);
2332 } else {2330 } else {
2333 // at this point we have a non-natural alignment, we must2331 // at this point we have a non-natural alignment, we must
2334 // load the value, and then shift+or the rhs into the result location.2332 // load the value, and then shift+or the rhs into the result location.
2335 const int_elem_ty = try pt.intType(.unsigned, ptr_info.packed_offset.host_size * 8);2333 const int_elem_ty = try pt.intType(.unsigned, ptr_info.packed_offset.host_size * 8);
23362334
2337 if (isByRef(int_elem_ty, pt, func.target)) {2335 if (isByRef(int_elem_ty, pt, cg.target)) {
2338 return func.fail("TODO: airStore for pointers to bitfields with backing type larger than 64bits", .{});2336 return cg.fail("TODO: airStore for pointers to bitfields with backing type larger than 64bits", .{});
2339 }2337 }
23402338
2341 var mask = @as(u64, @intCast((@as(u65, 1) << @as(u7, @intCast(ty.bitSize(zcu)))) - 1));2339 var mask = @as(u64, @intCast((@as(u65, 1) << @as(u7, @intCast(ty.bitSize(zcu)))) - 1));
...@@ -2354,115 +2352,115 @@ fn airStore(func: *CodeGen, inst: Air.Inst.Index, safety: bool) InnerError!void...@@ -2354,115 +2352,115 @@ fn airStore(func: *CodeGen, inst: Air.Inst.Index, safety: bool) InnerError!void
2354 else2352 else
2355 .{ .imm64 = ~@as(u64, 0) >> @intCast(64 - ty.bitSize(zcu)) };2353 .{ .imm64 = ~@as(u64, 0) >> @intCast(64 - ty.bitSize(zcu)) };
23562354
2357 try func.emitWValue(lhs);2355 try cg.emitWValue(lhs);
2358 const loaded = try func.load(lhs, int_elem_ty, 0);2356 const loaded = try cg.load(lhs, int_elem_ty, 0);
2359 const anded = try func.binOp(loaded, mask_val, int_elem_ty, .@"and");2357 const anded = try cg.binOp(loaded, mask_val, int_elem_ty, .@"and");
2360 const extended_value = try func.intcast(rhs, ty, int_elem_ty);2358 const extended_value = try cg.intcast(rhs, ty, int_elem_ty);
2361 const masked_value = try func.binOp(extended_value, wrap_mask_val, int_elem_ty, .@"and");2359 const masked_value = try cg.binOp(extended_value, wrap_mask_val, int_elem_ty, .@"and");
2362 const shifted_value = if (ptr_info.packed_offset.bit_offset > 0) shifted: {2360 const shifted_value = if (ptr_info.packed_offset.bit_offset > 0) shifted: {
2363 break :shifted try func.binOp(masked_value, shift_val, int_elem_ty, .shl);2361 break :shifted try cg.binOp(masked_value, shift_val, int_elem_ty, .shl);
2364 } else masked_value;2362 } else masked_value;
2365 const result = try func.binOp(anded, shifted_value, int_elem_ty, .@"or");2363 const result = try cg.binOp(anded, shifted_value, int_elem_ty, .@"or");
2366 // lhs is still on the stack2364 // lhs is still on the stack
2367 try func.store(.stack, result, int_elem_ty, lhs.offset());2365 try cg.store(.stack, result, int_elem_ty, lhs.offset());
2368 }2366 }
23692367
2370 return func.finishAir(inst, .none, &.{ bin_op.lhs, bin_op.rhs });2368 return cg.finishAir(inst, .none, &.{ bin_op.lhs, bin_op.rhs });
2371}2369}
23722370
2373fn store(func: *CodeGen, lhs: WValue, rhs: WValue, ty: Type, offset: u32) InnerError!void {2371fn store(cg: *CodeGen, lhs: WValue, rhs: WValue, ty: Type, offset: u32) InnerError!void {
2374 assert(!(lhs != .stack and rhs == .stack));2372 assert(!(lhs != .stack and rhs == .stack));
2375 const pt = func.pt;2373 const pt = cg.pt;
2376 const zcu = pt.zcu;2374 const zcu = pt.zcu;
2377 const abi_size = ty.abiSize(zcu);2375 const abi_size = ty.abiSize(zcu);
2378 switch (ty.zigTypeTag(zcu)) {2376 switch (ty.zigTypeTag(zcu)) {
2379 .error_union => {2377 .error_union => {
2380 const pl_ty = ty.errorUnionPayload(zcu);2378 const pl_ty = ty.errorUnionPayload(zcu);
2381 if (!pl_ty.hasRuntimeBitsIgnoreComptime(zcu)) {2379 if (!pl_ty.hasRuntimeBitsIgnoreComptime(zcu)) {
2382 return func.store(lhs, rhs, Type.anyerror, 0);2380 return cg.store(lhs, rhs, Type.anyerror, 0);
2383 }2381 }
23842382
2385 const len = @as(u32, @intCast(abi_size));2383 const len = @as(u32, @intCast(abi_size));
2386 return func.memcpy(lhs, rhs, .{ .imm32 = len });2384 return cg.memcpy(lhs, rhs, .{ .imm32 = len });
2387 },2385 },
2388 .optional => {2386 .optional => {
2389 if (ty.isPtrLikeOptional(zcu)) {2387 if (ty.isPtrLikeOptional(zcu)) {
2390 return func.store(lhs, rhs, Type.usize, 0);2388 return cg.store(lhs, rhs, Type.usize, 0);
2391 }2389 }
2392 const pl_ty = ty.optionalChild(zcu);2390 const pl_ty = ty.optionalChild(zcu);
2393 if (!pl_ty.hasRuntimeBitsIgnoreComptime(zcu)) {2391 if (!pl_ty.hasRuntimeBitsIgnoreComptime(zcu)) {
2394 return func.store(lhs, rhs, Type.u8, 0);2392 return cg.store(lhs, rhs, Type.u8, 0);
2395 }2393 }
2396 if (pl_ty.zigTypeTag(zcu) == .error_set) {2394 if (pl_ty.zigTypeTag(zcu) == .error_set) {
2397 return func.store(lhs, rhs, Type.anyerror, 0);2395 return cg.store(lhs, rhs, Type.anyerror, 0);
2398 }2396 }
23992397
2400 const len = @as(u32, @intCast(abi_size));2398 const len = @as(u32, @intCast(abi_size));
2401 return func.memcpy(lhs, rhs, .{ .imm32 = len });2399 return cg.memcpy(lhs, rhs, .{ .imm32 = len });
2402 },2400 },
2403 .@"struct", .array, .@"union" => if (isByRef(ty, pt, func.target)) {2401 .@"struct", .array, .@"union" => if (isByRef(ty, pt, cg.target)) {
2404 const len = @as(u32, @intCast(abi_size));2402 const len = @as(u32, @intCast(abi_size));
2405 return func.memcpy(lhs, rhs, .{ .imm32 = len });2403 return cg.memcpy(lhs, rhs, .{ .imm32 = len });
2406 },2404 },
2407 .vector => switch (determineSimdStoreStrategy(ty, zcu, func.target)) {2405 .vector => switch (determineSimdStoreStrategy(ty, zcu, cg.target)) {
2408 .unrolled => {2406 .unrolled => {
2409 const len: u32 = @intCast(abi_size);2407 const len: u32 = @intCast(abi_size);
2410 return func.memcpy(lhs, rhs, .{ .imm32 = len });2408 return cg.memcpy(lhs, rhs, .{ .imm32 = len });
2411 },2409 },
2412 .direct => {2410 .direct => {
2413 try func.emitWValue(lhs);2411 try cg.emitWValue(lhs);
2414 try func.lowerToStack(rhs);2412 try cg.lowerToStack(rhs);
2415 // TODO: Add helper functions for simd opcodes2413 // TODO: Add helper functions for simd opcodes
2416 const extra_index: u32 = @intCast(func.mir_extra.items.len);2414 const extra_index: u32 = @intCast(cg.mir_extra.items.len);
2417 // stores as := opcode, offset, alignment (opcode::memarg)2415 // stores as := opcode, offset, alignment (opcode::memarg)
2418 try func.mir_extra.appendSlice(func.gpa, &[_]u32{2416 try cg.mir_extra.appendSlice(cg.gpa, &[_]u32{
2419 @intFromEnum(std.wasm.SimdOpcode.v128_store),2417 @intFromEnum(std.wasm.SimdOpcode.v128_store),
2420 offset + lhs.offset(),2418 offset + lhs.offset(),
2421 @intCast(ty.abiAlignment(zcu).toByteUnits() orelse 0),2419 @intCast(ty.abiAlignment(zcu).toByteUnits() orelse 0),
2422 });2420 });
2423 return func.addInst(.{ .tag = .simd_prefix, .data = .{ .payload = extra_index } });2421 return cg.addInst(.{ .tag = .simd_prefix, .data = .{ .payload = extra_index } });
2424 },2422 },
2425 },2423 },
2426 .pointer => {2424 .pointer => {
2427 if (ty.isSlice(zcu)) {2425 if (ty.isSlice(zcu)) {
2428 // store pointer first2426 // store pointer first
2429 // lower it to the stack so we do not have to store rhs into a local first2427 // lower it to the stack so we do not have to store rhs into a local first
2430 try func.emitWValue(lhs);2428 try cg.emitWValue(lhs);
2431 const ptr_local = try func.load(rhs, Type.usize, 0);2429 const ptr_local = try cg.load(rhs, Type.usize, 0);
2432 try func.store(.stack, ptr_local, Type.usize, 0 + lhs.offset());2430 try cg.store(.stack, ptr_local, Type.usize, 0 + lhs.offset());
24332431
2434 // retrieve length from rhs, and store that alongside lhs as well2432 // retrieve length from rhs, and store that alongside lhs as well
2435 try func.emitWValue(lhs);2433 try cg.emitWValue(lhs);
2436 const len_local = try func.load(rhs, Type.usize, func.ptrSize());2434 const len_local = try cg.load(rhs, Type.usize, cg.ptrSize());
2437 try func.store(.stack, len_local, Type.usize, func.ptrSize() + lhs.offset());2435 try cg.store(.stack, len_local, Type.usize, cg.ptrSize() + lhs.offset());
2438 return;2436 return;
2439 }2437 }
2440 },2438 },
2441 .int, .@"enum", .float => if (abi_size > 8 and abi_size <= 16) {2439 .int, .@"enum", .float => if (abi_size > 8 and abi_size <= 16) {
2442 try func.emitWValue(lhs);2440 try cg.emitWValue(lhs);
2443 const lsb = try func.load(rhs, Type.u64, 0);2441 const lsb = try cg.load(rhs, Type.u64, 0);
2444 try func.store(.stack, lsb, Type.u64, 0 + lhs.offset());2442 try cg.store(.stack, lsb, Type.u64, 0 + lhs.offset());
24452443
2446 try func.emitWValue(lhs);2444 try cg.emitWValue(lhs);
2447 const msb = try func.load(rhs, Type.u64, 8);2445 const msb = try cg.load(rhs, Type.u64, 8);
2448 try func.store(.stack, msb, Type.u64, 8 + lhs.offset());2446 try cg.store(.stack, msb, Type.u64, 8 + lhs.offset());
2449 return;2447 return;
2450 } else if (abi_size > 16) {2448 } else if (abi_size > 16) {
2451 try func.memcpy(lhs, rhs, .{ .imm32 = @as(u32, @intCast(ty.abiSize(zcu))) });2449 try cg.memcpy(lhs, rhs, .{ .imm32 = @as(u32, @intCast(ty.abiSize(zcu))) });
2452 },2450 },
2453 else => if (abi_size > 8) {2451 else => if (abi_size > 8) {
2454 return func.fail("TODO: `store` for type `{}` with abisize `{d}`", .{2452 return cg.fail("TODO: `store` for type `{}` with abisize `{d}`", .{
2455 ty.fmt(pt),2453 ty.fmt(pt),
2456 abi_size,2454 abi_size,
2457 });2455 });
2458 },2456 },
2459 }2457 }
2460 try func.emitWValue(lhs);2458 try cg.emitWValue(lhs);
2461 // In this case we're actually interested in storing the stack position2459 // In this case we're actually interested in storing the stack position
2462 // into lhs, so we calculate that and emit that instead2460 // into lhs, so we calculate that and emit that instead
2463 try func.lowerToStack(rhs);2461 try cg.lowerToStack(rhs);
24642462
2465 const valtype = typeToValtype(ty, pt, func.target);2463 const valtype = typeToValtype(ty, pt, cg.target);
2466 const opcode = buildOpcode(.{2464 const opcode = buildOpcode(.{
2467 .valtype1 = valtype,2465 .valtype1 = valtype,
2468 .width = @as(u8, @intCast(abi_size * 8)),2466 .width = @as(u8, @intCast(abi_size * 8)),
...@@ -2470,7 +2468,7 @@ fn store(func: *CodeGen, lhs: WValue, rhs: WValue, ty: Type, offset: u32) InnerE...@@ -2470,7 +2468,7 @@ fn store(func: *CodeGen, lhs: WValue, rhs: WValue, ty: Type, offset: u32) InnerE
2470 });2468 });
24712469
2472 // store rhs value at stack pointer's location in memory2470 // store rhs value at stack pointer's location in memory
2473 try func.addMemArg(2471 try cg.addMemArg(
2474 Mir.Inst.Tag.fromOpcode(opcode),2472 Mir.Inst.Tag.fromOpcode(opcode),
2475 .{2473 .{
2476 .offset = offset + lhs.offset(),2474 .offset = offset + lhs.offset(),
...@@ -2479,26 +2477,26 @@ fn store(func: *CodeGen, lhs: WValue, rhs: WValue, ty: Type, offset: u32) InnerE...@@ -2479,26 +2477,26 @@ fn store(func: *CodeGen, lhs: WValue, rhs: WValue, ty: Type, offset: u32) InnerE
2479 );2477 );
2480}2478}
24812479
2482fn airLoad(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {2480fn airLoad(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
2483 const pt = func.pt;2481 const pt = cg.pt;
2484 const zcu = pt.zcu;2482 const zcu = pt.zcu;
2485 const ty_op = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;2483 const ty_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
2486 const operand = try func.resolveInst(ty_op.operand);2484 const operand = try cg.resolveInst(ty_op.operand);
2487 const ty = ty_op.ty.toType();2485 const ty = ty_op.ty.toType();
2488 const ptr_ty = func.typeOf(ty_op.operand);2486 const ptr_ty = cg.typeOf(ty_op.operand);
2489 const ptr_info = ptr_ty.ptrInfo(zcu);2487 const ptr_info = ptr_ty.ptrInfo(zcu);
24902488
2491 if (!ty.hasRuntimeBitsIgnoreComptime(zcu)) return func.finishAir(inst, .none, &.{ty_op.operand});2489 if (!ty.hasRuntimeBitsIgnoreComptime(zcu)) return cg.finishAir(inst, .none, &.{ty_op.operand});
24922490
2493 const result = result: {2491 const result = result: {
2494 if (isByRef(ty, pt, func.target)) {2492 if (isByRef(ty, pt, cg.target)) {
2495 const new_local = try func.allocStack(ty);2493 const new_local = try cg.allocStack(ty);
2496 try func.store(new_local, operand, ty, 0);2494 try cg.store(new_local, operand, ty, 0);
2497 break :result new_local;2495 break :result new_local;
2498 }2496 }
24992497
2500 if (ptr_info.packed_offset.host_size == 0) {2498 if (ptr_info.packed_offset.host_size == 0) {
2501 break :result try func.load(operand, ty, 0);2499 break :result try cg.load(operand, ty, 0);
2502 }2500 }
25032501
2504 // at this point we have a non-natural alignment, we must2502 // at this point we have a non-natural alignment, we must
...@@ -2509,45 +2507,45 @@ fn airLoad(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -2509,45 +2507,45 @@ fn airLoad(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
2509 else if (ptr_info.packed_offset.host_size <= 8)2507 else if (ptr_info.packed_offset.host_size <= 8)
2510 .{ .imm64 = ptr_info.packed_offset.bit_offset }2508 .{ .imm64 = ptr_info.packed_offset.bit_offset }
2511 else2509 else
2512 return func.fail("TODO: airLoad where ptr to bitfield exceeds 64 bits", .{});2510 return cg.fail("TODO: airLoad where ptr to bitfield exceeds 64 bits", .{});
25132511
2514 const stack_loaded = try func.load(operand, int_elem_ty, 0);2512 const stack_loaded = try cg.load(operand, int_elem_ty, 0);
2515 const shifted = try func.binOp(stack_loaded, shift_val, int_elem_ty, .shr);2513 const shifted = try cg.binOp(stack_loaded, shift_val, int_elem_ty, .shr);
2516 break :result try func.trunc(shifted, ty, int_elem_ty);2514 break :result try cg.trunc(shifted, ty, int_elem_ty);
2517 };2515 };
2518 return func.finishAir(inst, result, &.{ty_op.operand});2516 return cg.finishAir(inst, result, &.{ty_op.operand});
2519}2517}
25202518
2521/// Loads an operand from the linear memory section.2519/// Loads an operand from the linear memory section.
2522/// NOTE: Leaves the value on the stack.2520/// NOTE: Leaves the value on the stack.
2523fn load(func: *CodeGen, operand: WValue, ty: Type, offset: u32) InnerError!WValue {2521fn load(cg: *CodeGen, operand: WValue, ty: Type, offset: u32) InnerError!WValue {
2524 const pt = func.pt;2522 const pt = cg.pt;
2525 const zcu = pt.zcu;2523 const zcu = pt.zcu;
2526 // load local's value from memory by its stack position2524 // load local's value from memory by its stack position
2527 try func.emitWValue(operand);2525 try cg.emitWValue(operand);
25282526
2529 if (ty.zigTypeTag(zcu) == .vector) {2527 if (ty.zigTypeTag(zcu) == .vector) {
2530 // TODO: Add helper functions for simd opcodes2528 // TODO: Add helper functions for simd opcodes
2531 const extra_index = @as(u32, @intCast(func.mir_extra.items.len));2529 const extra_index = @as(u32, @intCast(cg.mir_extra.items.len));
2532 // stores as := opcode, offset, alignment (opcode::memarg)2530 // stores as := opcode, offset, alignment (opcode::memarg)
2533 try func.mir_extra.appendSlice(func.gpa, &[_]u32{2531 try cg.mir_extra.appendSlice(cg.gpa, &[_]u32{
2534 @intFromEnum(std.wasm.SimdOpcode.v128_load),2532 @intFromEnum(std.wasm.SimdOpcode.v128_load),
2535 offset + operand.offset(),2533 offset + operand.offset(),
2536 @intCast(ty.abiAlignment(zcu).toByteUnits().?),2534 @intCast(ty.abiAlignment(zcu).toByteUnits().?),
2537 });2535 });
2538 try func.addInst(.{ .tag = .simd_prefix, .data = .{ .payload = extra_index } });2536 try cg.addInst(.{ .tag = .simd_prefix, .data = .{ .payload = extra_index } });
2539 return .stack;2537 return .stack;
2540 }2538 }
25412539
2542 const abi_size: u8 = @intCast(ty.abiSize(zcu));2540 const abi_size: u8 = @intCast(ty.abiSize(zcu));
2543 const opcode = buildOpcode(.{2541 const opcode = buildOpcode(.{
2544 .valtype1 = typeToValtype(ty, pt, func.target),2542 .valtype1 = typeToValtype(ty, pt, cg.target),
2545 .width = abi_size * 8,2543 .width = abi_size * 8,
2546 .op = .load,2544 .op = .load,
2547 .signedness = if (ty.isSignedInt(zcu)) .signed else .unsigned,2545 .signedness = if (ty.isSignedInt(zcu)) .signed else .unsigned,
2548 });2546 });
25492547
2550 try func.addMemArg(2548 try cg.addMemArg(
2551 Mir.Inst.Tag.fromOpcode(opcode),2549 Mir.Inst.Tag.fromOpcode(opcode),
2552 .{2550 .{
2553 .offset = offset + operand.offset(),2551 .offset = offset + operand.offset(),
...@@ -2558,18 +2556,18 @@ fn load(func: *CodeGen, operand: WValue, ty: Type, offset: u32) InnerError!WValu...@@ -2558,18 +2556,18 @@ fn load(func: *CodeGen, operand: WValue, ty: Type, offset: u32) InnerError!WValu
2558 return .stack;2556 return .stack;
2559}2557}
25602558
2561fn airArg(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {2559fn airArg(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
2562 const pt = func.pt;2560 const pt = cg.pt;
2563 const zcu = pt.zcu;2561 const zcu = pt.zcu;
2564 const arg_index = func.arg_index;2562 const arg_index = cg.arg_index;
2565 const arg = func.args[arg_index];2563 const arg = cg.args[arg_index];
2566 const cc = zcu.typeToFunc(zcu.navValue(func.owner_nav).typeOf(zcu)).?.cc;2564 const cc = zcu.typeToFunc(zcu.navValue(cg.owner_nav).typeOf(zcu)).?.cc;
2567 const arg_ty = func.typeOfIndex(inst);2565 const arg_ty = cg.typeOfIndex(inst);
2568 if (cc == .wasm_watc) {2566 if (cc == .wasm_watc) {
2569 const arg_classes = abi.classifyType(arg_ty, zcu);2567 const arg_classes = abi.classifyType(arg_ty, zcu);
2570 for (arg_classes) |class| {2568 for (arg_classes) |class| {
2571 if (class != .none) {2569 if (class != .none) {
2572 func.arg_index += 1;2570 cg.arg_index += 1;
2573 }2571 }
2574 }2572 }
25752573
...@@ -2577,31 +2575,31 @@ fn airArg(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -2577,31 +2575,31 @@ fn airArg(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
2577 // we combine them into a single stack value2575 // we combine them into a single stack value
2578 if (arg_classes[0] == .direct and arg_classes[1] == .direct) {2576 if (arg_classes[0] == .direct and arg_classes[1] == .direct) {
2579 if (arg_ty.zigTypeTag(zcu) != .int and arg_ty.zigTypeTag(zcu) != .float) {2577 if (arg_ty.zigTypeTag(zcu) != .int and arg_ty.zigTypeTag(zcu) != .float) {
2580 return func.fail(2578 return cg.fail(
2581 "TODO: Implement C-ABI argument for type '{}'",2579 "TODO: Implement C-ABI argument for type '{}'",
2582 .{arg_ty.fmt(pt)},2580 .{arg_ty.fmt(pt)},
2583 );2581 );
2584 }2582 }
2585 const result = try func.allocStack(arg_ty);2583 const result = try cg.allocStack(arg_ty);
2586 try func.store(result, arg, Type.u64, 0);2584 try cg.store(result, arg, Type.u64, 0);
2587 try func.store(result, func.args[arg_index + 1], Type.u64, 8);2585 try cg.store(result, cg.args[arg_index + 1], Type.u64, 8);
2588 return func.finishAir(inst, result, &.{});2586 return cg.finishAir(inst, result, &.{});
2589 }2587 }
2590 } else {2588 } else {
2591 func.arg_index += 1;2589 cg.arg_index += 1;
2592 }2590 }
25932591
2594 return func.finishAir(inst, arg, &.{});2592 return cg.finishAir(inst, arg, &.{});
2595}2593}
25962594
2597fn airBinOp(func: *CodeGen, inst: Air.Inst.Index, op: Op) InnerError!void {2595fn airBinOp(cg: *CodeGen, inst: Air.Inst.Index, op: Op) InnerError!void {
2598 const pt = func.pt;2596 const pt = cg.pt;
2599 const zcu = pt.zcu;2597 const zcu = pt.zcu;
2600 const bin_op = func.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;2598 const bin_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
2601 const lhs = try func.resolveInst(bin_op.lhs);2599 const lhs = try cg.resolveInst(bin_op.lhs);
2602 const rhs = try func.resolveInst(bin_op.rhs);2600 const rhs = try cg.resolveInst(bin_op.rhs);
2603 const lhs_ty = func.typeOf(bin_op.lhs);2601 const lhs_ty = cg.typeOf(bin_op.lhs);
2604 const rhs_ty = func.typeOf(bin_op.rhs);2602 const rhs_ty = cg.typeOf(bin_op.rhs);
26052603
2606 // For certain operations, such as shifting, the types are different.2604 // For certain operations, such as shifting, the types are different.
2607 // When converting this to a WebAssembly type, they *must* match to perform2605 // When converting this to a WebAssembly type, they *must* match to perform
...@@ -2611,38 +2609,38 @@ fn airBinOp(func: *CodeGen, inst: Air.Inst.Index, op: Op) InnerError!void {...@@ -2611,38 +2609,38 @@ fn airBinOp(func: *CodeGen, inst: Air.Inst.Index, op: Op) InnerError!void {
2611 const result = switch (op) {2609 const result = switch (op) {
2612 .shr, .shl => result: {2610 .shr, .shl => result: {
2613 const lhs_wasm_bits = toWasmBits(@intCast(lhs_ty.bitSize(zcu))) orelse {2611 const lhs_wasm_bits = toWasmBits(@intCast(lhs_ty.bitSize(zcu))) orelse {
2614 return func.fail("TODO: implement '{s}' for types larger than 128 bits", .{@tagName(op)});2612 return cg.fail("TODO: implement '{s}' for types larger than 128 bits", .{@tagName(op)});
2615 };2613 };
2616 const rhs_wasm_bits = toWasmBits(@intCast(rhs_ty.bitSize(zcu))).?;2614 const rhs_wasm_bits = toWasmBits(@intCast(rhs_ty.bitSize(zcu))).?;
2617 const new_rhs = if (lhs_wasm_bits != rhs_wasm_bits and lhs_wasm_bits != 128)2615 const new_rhs = if (lhs_wasm_bits != rhs_wasm_bits and lhs_wasm_bits != 128)
2618 try (try func.intcast(rhs, rhs_ty, lhs_ty)).toLocal(func, lhs_ty)2616 try (try cg.intcast(rhs, rhs_ty, lhs_ty)).toLocal(cg, lhs_ty)
2619 else2617 else
2620 rhs;2618 rhs;
2621 break :result try func.binOp(lhs, new_rhs, lhs_ty, op);2619 break :result try cg.binOp(lhs, new_rhs, lhs_ty, op);
2622 },2620 },
2623 else => try func.binOp(lhs, rhs, lhs_ty, op),2621 else => try cg.binOp(lhs, rhs, lhs_ty, op),
2624 };2622 };
26252623
2626 return func.finishAir(inst, result, &.{ bin_op.lhs, bin_op.rhs });2624 return cg.finishAir(inst, result, &.{ bin_op.lhs, bin_op.rhs });
2627}2625}
26282626
2629/// Performs a binary operation on the given `WValue`'s2627/// Performs a binary operation on the given `WValue`'s
2630/// NOTE: THis leaves the value on top of the stack.2628/// NOTE: THis leaves the value on top of the stack.
2631fn binOp(func: *CodeGen, lhs: WValue, rhs: WValue, ty: Type, op: Op) InnerError!WValue {2629fn binOp(cg: *CodeGen, lhs: WValue, rhs: WValue, ty: Type, op: Op) InnerError!WValue {
2632 const pt = func.pt;2630 const pt = cg.pt;
2633 const zcu = pt.zcu;2631 const zcu = pt.zcu;
2634 assert(!(lhs != .stack and rhs == .stack));2632 assert(!(lhs != .stack and rhs == .stack));
26352633
2636 if (ty.isAnyFloat()) {2634 if (ty.isAnyFloat()) {
2637 const float_op = FloatOp.fromOp(op);2635 const float_op = FloatOp.fromOp(op);
2638 return func.floatOp(float_op, ty, &.{ lhs, rhs });2636 return cg.floatOp(float_op, ty, &.{ lhs, rhs });
2639 }2637 }
26402638
2641 if (isByRef(ty, pt, func.target)) {2639 if (isByRef(ty, pt, cg.target)) {
2642 if (ty.zigTypeTag(zcu) == .int) {2640 if (ty.zigTypeTag(zcu) == .int) {
2643 return func.binOpBigInt(lhs, rhs, ty, op);2641 return cg.binOpBigInt(lhs, rhs, ty, op);
2644 } else {2642 } else {
2645 return func.fail(2643 return cg.fail(
2646 "TODO: Implement binary operation for type: {}",2644 "TODO: Implement binary operation for type: {}",
2647 .{ty.fmt(pt)},2645 .{ty.fmt(pt)},
2648 );2646 );
...@@ -2651,82 +2649,82 @@ fn binOp(func: *CodeGen, lhs: WValue, rhs: WValue, ty: Type, op: Op) InnerError!...@@ -2651,82 +2649,82 @@ fn binOp(func: *CodeGen, lhs: WValue, rhs: WValue, ty: Type, op: Op) InnerError!
26512649
2652 const opcode: std.wasm.Opcode = buildOpcode(.{2650 const opcode: std.wasm.Opcode = buildOpcode(.{
2653 .op = op,2651 .op = op,
2654 .valtype1 = typeToValtype(ty, pt, func.target),2652 .valtype1 = typeToValtype(ty, pt, cg.target),
2655 .signedness = if (ty.isSignedInt(zcu)) .signed else .unsigned,2653 .signedness = if (ty.isSignedInt(zcu)) .signed else .unsigned,
2656 });2654 });
2657 try func.emitWValue(lhs);2655 try cg.emitWValue(lhs);
2658 try func.emitWValue(rhs);2656 try cg.emitWValue(rhs);
26592657
2660 try func.addTag(Mir.Inst.Tag.fromOpcode(opcode));2658 try cg.addTag(Mir.Inst.Tag.fromOpcode(opcode));
26612659
2662 return .stack;2660 return .stack;
2663}2661}
26642662
2665fn binOpBigInt(func: *CodeGen, lhs: WValue, rhs: WValue, ty: Type, op: Op) InnerError!WValue {2663fn binOpBigInt(cg: *CodeGen, lhs: WValue, rhs: WValue, ty: Type, op: Op) InnerError!WValue {
2666 const pt = func.pt;2664 const pt = cg.pt;
2667 const zcu = pt.zcu;2665 const zcu = pt.zcu;
2668 const int_info = ty.intInfo(zcu);2666 const int_info = ty.intInfo(zcu);
2669 if (int_info.bits > 128) {2667 if (int_info.bits > 128) {
2670 return func.fail("TODO: Implement binary operation for big integers larger than 128 bits", .{});2668 return cg.fail("TODO: Implement binary operation for big integers larger than 128 bits", .{});
2671 }2669 }
26722670
2673 switch (op) {2671 switch (op) {
2674 .mul => return func.callIntrinsic("__multi3", &.{ ty.toIntern(), ty.toIntern() }, ty, &.{ lhs, rhs }),2672 .mul => return cg.callIntrinsic("__multi3", &.{ ty.toIntern(), ty.toIntern() }, ty, &.{ lhs, rhs }),
2675 .div => switch (int_info.signedness) {2673 .div => switch (int_info.signedness) {
2676 .signed => return func.callIntrinsic("__divti3", &.{ ty.toIntern(), ty.toIntern() }, ty, &.{ lhs, rhs }),2674 .signed => return cg.callIntrinsic("__divti3", &.{ ty.toIntern(), ty.toIntern() }, ty, &.{ lhs, rhs }),
2677 .unsigned => return func.callIntrinsic("__udivti3", &.{ ty.toIntern(), ty.toIntern() }, ty, &.{ lhs, rhs }),2675 .unsigned => return cg.callIntrinsic("__udivti3", &.{ ty.toIntern(), ty.toIntern() }, ty, &.{ lhs, rhs }),
2678 },2676 },
2679 .rem => switch (int_info.signedness) {2677 .rem => switch (int_info.signedness) {
2680 .signed => return func.callIntrinsic("__modti3", &.{ ty.toIntern(), ty.toIntern() }, ty, &.{ lhs, rhs }),2678 .signed => return cg.callIntrinsic("__modti3", &.{ ty.toIntern(), ty.toIntern() }, ty, &.{ lhs, rhs }),
2681 .unsigned => return func.callIntrinsic("__umodti3", &.{ ty.toIntern(), ty.toIntern() }, ty, &.{ lhs, rhs }),2679 .unsigned => return cg.callIntrinsic("__umodti3", &.{ ty.toIntern(), ty.toIntern() }, ty, &.{ lhs, rhs }),
2682 },2680 },
2683 .shr => switch (int_info.signedness) {2681 .shr => switch (int_info.signedness) {
2684 .signed => return func.callIntrinsic("__ashrti3", &.{ ty.toIntern(), .i32_type }, ty, &.{ lhs, rhs }),2682 .signed => return cg.callIntrinsic("__ashrti3", &.{ ty.toIntern(), .i32_type }, ty, &.{ lhs, rhs }),
2685 .unsigned => return func.callIntrinsic("__lshrti3", &.{ ty.toIntern(), .i32_type }, ty, &.{ lhs, rhs }),2683 .unsigned => return cg.callIntrinsic("__lshrti3", &.{ ty.toIntern(), .i32_type }, ty, &.{ lhs, rhs }),
2686 },2684 },
2687 .shl => return func.callIntrinsic("__ashlti3", &.{ ty.toIntern(), .i32_type }, ty, &.{ lhs, rhs }),2685 .shl => return cg.callIntrinsic("__ashlti3", &.{ ty.toIntern(), .i32_type }, ty, &.{ lhs, rhs }),
2688 .@"and", .@"or", .xor => {2686 .@"and", .@"or", .xor => {
2689 const result = try func.allocStack(ty);2687 const result = try cg.allocStack(ty);
2690 try func.emitWValue(result);2688 try cg.emitWValue(result);
2691 const lhs_lsb = try func.load(lhs, Type.u64, 0);2689 const lhs_lsb = try cg.load(lhs, Type.u64, 0);
2692 const rhs_lsb = try func.load(rhs, Type.u64, 0);2690 const rhs_lsb = try cg.load(rhs, Type.u64, 0);
2693 const op_lsb = try func.binOp(lhs_lsb, rhs_lsb, Type.u64, op);2691 const op_lsb = try cg.binOp(lhs_lsb, rhs_lsb, Type.u64, op);
2694 try func.store(.stack, op_lsb, Type.u64, result.offset());2692 try cg.store(.stack, op_lsb, Type.u64, result.offset());
26952693
2696 try func.emitWValue(result);2694 try cg.emitWValue(result);
2697 const lhs_msb = try func.load(lhs, Type.u64, 8);2695 const lhs_msb = try cg.load(lhs, Type.u64, 8);
2698 const rhs_msb = try func.load(rhs, Type.u64, 8);2696 const rhs_msb = try cg.load(rhs, Type.u64, 8);
2699 const op_msb = try func.binOp(lhs_msb, rhs_msb, Type.u64, op);2697 const op_msb = try cg.binOp(lhs_msb, rhs_msb, Type.u64, op);
2700 try func.store(.stack, op_msb, Type.u64, result.offset() + 8);2698 try cg.store(.stack, op_msb, Type.u64, result.offset() + 8);
2701 return result;2699 return result;
2702 },2700 },
2703 .add, .sub => {2701 .add, .sub => {
2704 const result = try func.allocStack(ty);2702 const result = try cg.allocStack(ty);
2705 var lhs_lsb = try (try func.load(lhs, Type.u64, 0)).toLocal(func, Type.u64);2703 var lhs_lsb = try (try cg.load(lhs, Type.u64, 0)).toLocal(cg, Type.u64);
2706 defer lhs_lsb.free(func);2704 defer lhs_lsb.free(cg);
2707 var rhs_lsb = try (try func.load(rhs, Type.u64, 0)).toLocal(func, Type.u64);2705 var rhs_lsb = try (try cg.load(rhs, Type.u64, 0)).toLocal(cg, Type.u64);
2708 defer rhs_lsb.free(func);2706 defer rhs_lsb.free(cg);
2709 var op_lsb = try (try func.binOp(lhs_lsb, rhs_lsb, Type.u64, op)).toLocal(func, Type.u64);2707 var op_lsb = try (try cg.binOp(lhs_lsb, rhs_lsb, Type.u64, op)).toLocal(cg, Type.u64);
2710 defer op_lsb.free(func);2708 defer op_lsb.free(cg);
27112709
2712 const lhs_msb = try func.load(lhs, Type.u64, 8);2710 const lhs_msb = try cg.load(lhs, Type.u64, 8);
2713 const rhs_msb = try func.load(rhs, Type.u64, 8);2711 const rhs_msb = try cg.load(rhs, Type.u64, 8);
2714 const op_msb = try func.binOp(lhs_msb, rhs_msb, Type.u64, op);2712 const op_msb = try cg.binOp(lhs_msb, rhs_msb, Type.u64, op);
27152713
2716 const lt = if (op == .add) blk: {2714 const lt = if (op == .add) blk: {
2717 break :blk try func.cmp(op_lsb, rhs_lsb, Type.u64, .lt);2715 break :blk try cg.cmp(op_lsb, rhs_lsb, Type.u64, .lt);
2718 } else if (op == .sub) blk: {2716 } else if (op == .sub) blk: {
2719 break :blk try func.cmp(lhs_lsb, rhs_lsb, Type.u64, .lt);2717 break :blk try cg.cmp(lhs_lsb, rhs_lsb, Type.u64, .lt);
2720 } else unreachable;2718 } else unreachable;
2721 const tmp = try func.intcast(lt, Type.u32, Type.u64);2719 const tmp = try cg.intcast(lt, Type.u32, Type.u64);
2722 var tmp_op = try (try func.binOp(op_msb, tmp, Type.u64, op)).toLocal(func, Type.u64);2720 var tmp_op = try (try cg.binOp(op_msb, tmp, Type.u64, op)).toLocal(cg, Type.u64);
2723 defer tmp_op.free(func);2721 defer tmp_op.free(cg);
27242722
2725 try func.store(result, op_lsb, Type.u64, 0);2723 try cg.store(result, op_lsb, Type.u64, 0);
2726 try func.store(result, tmp_op, Type.u64, 8);2724 try cg.store(result, tmp_op, Type.u64, 8);
2727 return result;2725 return result;
2728 },2726 },
2729 else => return func.fail("TODO: Implement binary operation for big integers: '{s}'", .{@tagName(op)}),2727 else => return cg.fail("TODO: Implement binary operation for big integers: '{s}'", .{@tagName(op)}),
2730 }2728 }
2731}2729}
27322730
...@@ -2806,117 +2804,117 @@ const FloatOp = enum {...@@ -2806,117 +2804,117 @@ const FloatOp = enum {
2806 }2804 }
2807};2805};
28082806
2809fn airAbs(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {2807fn airAbs(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
2810 const pt = func.pt;2808 const pt = cg.pt;
2811 const zcu = pt.zcu;2809 const zcu = pt.zcu;
2812 const ty_op = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;2810 const ty_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
2813 const operand = try func.resolveInst(ty_op.operand);2811 const operand = try cg.resolveInst(ty_op.operand);
2814 const ty = func.typeOf(ty_op.operand);2812 const ty = cg.typeOf(ty_op.operand);
2815 const scalar_ty = ty.scalarType(zcu);2813 const scalar_ty = ty.scalarType(zcu);
28162814
2817 switch (scalar_ty.zigTypeTag(zcu)) {2815 switch (scalar_ty.zigTypeTag(zcu)) {
2818 .int => if (ty.zigTypeTag(zcu) == .vector) {2816 .int => if (ty.zigTypeTag(zcu) == .vector) {
2819 return func.fail("TODO implement airAbs for {}", .{ty.fmt(pt)});2817 return cg.fail("TODO implement airAbs for {}", .{ty.fmt(pt)});
2820 } else {2818 } else {
2821 const int_bits = ty.intInfo(zcu).bits;2819 const int_bits = ty.intInfo(zcu).bits;
2822 const wasm_bits = toWasmBits(int_bits) orelse {2820 const wasm_bits = toWasmBits(int_bits) orelse {
2823 return func.fail("TODO: airAbs for signed integers larger than '{d}' bits", .{int_bits});2821 return cg.fail("TODO: airAbs for signed integers larger than '{d}' bits", .{int_bits});
2824 };2822 };
28252823
2826 switch (wasm_bits) {2824 switch (wasm_bits) {
2827 32 => {2825 32 => {
2828 try func.emitWValue(operand);2826 try cg.emitWValue(operand);
28292827
2830 try func.addImm32(31);2828 try cg.addImm32(31);
2831 try func.addTag(.i32_shr_s);2829 try cg.addTag(.i32_shr_s);
28322830
2833 var tmp = try func.allocLocal(ty);2831 var tmp = try cg.allocLocal(ty);
2834 defer tmp.free(func);2832 defer tmp.free(cg);
2835 try func.addLabel(.local_tee, tmp.local.value);2833 try cg.addLabel(.local_tee, tmp.local.value);
28362834
2837 try func.emitWValue(operand);2835 try cg.emitWValue(operand);
2838 try func.addTag(.i32_xor);2836 try cg.addTag(.i32_xor);
2839 try func.emitWValue(tmp);2837 try cg.emitWValue(tmp);
2840 try func.addTag(.i32_sub);2838 try cg.addTag(.i32_sub);
2841 return func.finishAir(inst, .stack, &.{ty_op.operand});2839 return cg.finishAir(inst, .stack, &.{ty_op.operand});
2842 },2840 },
2843 64 => {2841 64 => {
2844 try func.emitWValue(operand);2842 try cg.emitWValue(operand);
28452843
2846 try func.addImm64(63);2844 try cg.addImm64(63);
2847 try func.addTag(.i64_shr_s);2845 try cg.addTag(.i64_shr_s);
28482846
2849 var tmp = try func.allocLocal(ty);2847 var tmp = try cg.allocLocal(ty);
2850 defer tmp.free(func);2848 defer tmp.free(cg);
2851 try func.addLabel(.local_tee, tmp.local.value);2849 try cg.addLabel(.local_tee, tmp.local.value);
28522850
2853 try func.emitWValue(operand);2851 try cg.emitWValue(operand);
2854 try func.addTag(.i64_xor);2852 try cg.addTag(.i64_xor);
2855 try func.emitWValue(tmp);2853 try cg.emitWValue(tmp);
2856 try func.addTag(.i64_sub);2854 try cg.addTag(.i64_sub);
2857 return func.finishAir(inst, .stack, &.{ty_op.operand});2855 return cg.finishAir(inst, .stack, &.{ty_op.operand});
2858 },2856 },
2859 128 => {2857 128 => {
2860 const mask = try func.allocStack(Type.u128);2858 const mask = try cg.allocStack(Type.u128);
2861 try func.emitWValue(mask);2859 try cg.emitWValue(mask);
2862 try func.emitWValue(mask);2860 try cg.emitWValue(mask);
28632861
2864 _ = try func.load(operand, Type.u64, 8);2862 _ = try cg.load(operand, Type.u64, 8);
2865 try func.addImm64(63);2863 try cg.addImm64(63);
2866 try func.addTag(.i64_shr_s);2864 try cg.addTag(.i64_shr_s);
28672865
2868 var tmp = try func.allocLocal(Type.u64);2866 var tmp = try cg.allocLocal(Type.u64);
2869 defer tmp.free(func);2867 defer tmp.free(cg);
2870 try func.addLabel(.local_tee, tmp.local.value);2868 try cg.addLabel(.local_tee, tmp.local.value);
2871 try func.store(.stack, .stack, Type.u64, mask.offset() + 0);2869 try cg.store(.stack, .stack, Type.u64, mask.offset() + 0);
2872 try func.emitWValue(tmp);2870 try cg.emitWValue(tmp);
2873 try func.store(.stack, .stack, Type.u64, mask.offset() + 8);2871 try cg.store(.stack, .stack, Type.u64, mask.offset() + 8);
28742872
2875 const a = try func.binOpBigInt(operand, mask, Type.u128, .xor);2873 const a = try cg.binOpBigInt(operand, mask, Type.u128, .xor);
2876 const b = try func.binOpBigInt(a, mask, Type.u128, .sub);2874 const b = try cg.binOpBigInt(a, mask, Type.u128, .sub);
28772875
2878 return func.finishAir(inst, b, &.{ty_op.operand});2876 return cg.finishAir(inst, b, &.{ty_op.operand});
2879 },2877 },
2880 else => unreachable,2878 else => unreachable,
2881 }2879 }
2882 },2880 },
2883 .float => {2881 .float => {
2884 const result = try func.floatOp(.fabs, ty, &.{operand});2882 const result = try cg.floatOp(.fabs, ty, &.{operand});
2885 return func.finishAir(inst, result, &.{ty_op.operand});2883 return cg.finishAir(inst, result, &.{ty_op.operand});
2886 },2884 },
2887 else => unreachable,2885 else => unreachable,
2888 }2886 }
2889}2887}
28902888
2891fn airUnaryFloatOp(func: *CodeGen, inst: Air.Inst.Index, op: FloatOp) InnerError!void {2889fn airUnaryFloatOp(cg: *CodeGen, inst: Air.Inst.Index, op: FloatOp) InnerError!void {
2892 const un_op = func.air.instructions.items(.data)[@intFromEnum(inst)].un_op;2890 const un_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].un_op;
2893 const operand = try func.resolveInst(un_op);2891 const operand = try cg.resolveInst(un_op);
2894 const ty = func.typeOf(un_op);2892 const ty = cg.typeOf(un_op);
28952893
2896 const result = try func.floatOp(op, ty, &.{operand});2894 const result = try cg.floatOp(op, ty, &.{operand});
2897 return func.finishAir(inst, result, &.{un_op});2895 return cg.finishAir(inst, result, &.{un_op});
2898}2896}
28992897
2900fn floatOp(func: *CodeGen, float_op: FloatOp, ty: Type, args: []const WValue) InnerError!WValue {2898fn floatOp(cg: *CodeGen, float_op: FloatOp, ty: Type, args: []const WValue) InnerError!WValue {
2901 const pt = func.pt;2899 const pt = cg.pt;
2902 const zcu = pt.zcu;2900 const zcu = pt.zcu;
2903 if (ty.zigTypeTag(zcu) == .vector) {2901 if (ty.zigTypeTag(zcu) == .vector) {
2904 return func.fail("TODO: Implement floatOps for vectors", .{});2902 return cg.fail("TODO: Implement floatOps for vectors", .{});
2905 }2903 }
29062904
2907 const float_bits = ty.floatBits(func.target.*);2905 const float_bits = ty.floatBits(cg.target.*);
29082906
2909 if (float_op == .neg) {2907 if (float_op == .neg) {
2910 return func.floatNeg(ty, args[0]);2908 return cg.floatNeg(ty, args[0]);
2911 }2909 }
29122910
2913 if (float_bits == 32 or float_bits == 64) {2911 if (float_bits == 32 or float_bits == 64) {
2914 if (float_op.toOp()) |op| {2912 if (float_op.toOp()) |op| {
2915 for (args) |operand| {2913 for (args) |operand| {
2916 try func.emitWValue(operand);2914 try cg.emitWValue(operand);
2917 }2915 }
2918 const opcode = buildOpcode(.{ .op = op, .valtype1 = typeToValtype(ty, pt, func.target) });2916 const opcode = buildOpcode(.{ .op = op, .valtype1 = typeToValtype(ty, pt, cg.target) });
2919 try func.addTag(Mir.Inst.Tag.fromOpcode(opcode));2917 try cg.addTag(Mir.Inst.Tag.fromOpcode(opcode));
2920 return .stack;2918 return .stack;
2921 }2919 }
2922 }2920 }
...@@ -2958,45 +2956,45 @@ fn floatOp(func: *CodeGen, float_op: FloatOp, ty: Type, args: []const WValue) In...@@ -2958,45 +2956,45 @@ fn floatOp(func: *CodeGen, float_op: FloatOp, ty: Type, args: []const WValue) In
2958 // fma requires three operands2956 // fma requires three operands
2959 var param_types_buffer: [3]InternPool.Index = .{ ty.ip_index, ty.ip_index, ty.ip_index };2957 var param_types_buffer: [3]InternPool.Index = .{ ty.ip_index, ty.ip_index, ty.ip_index };
2960 const param_types = param_types_buffer[0..args.len];2958 const param_types = param_types_buffer[0..args.len];
2961 return func.callIntrinsic(fn_name, param_types, ty, args);2959 return cg.callIntrinsic(fn_name, param_types, ty, args);
2962}2960}
29632961
2964/// NOTE: The result value remains on top of the stack.2962/// NOTE: The result value remains on top of the stack.
2965fn floatNeg(func: *CodeGen, ty: Type, arg: WValue) InnerError!WValue {2963fn floatNeg(cg: *CodeGen, ty: Type, arg: WValue) InnerError!WValue {
2966 const float_bits = ty.floatBits(func.target.*);2964 const float_bits = ty.floatBits(cg.target.*);
2967 switch (float_bits) {2965 switch (float_bits) {
2968 16 => {2966 16 => {
2969 try func.emitWValue(arg);2967 try cg.emitWValue(arg);
2970 try func.addImm32(0x8000);2968 try cg.addImm32(0x8000);
2971 try func.addTag(.i32_xor);2969 try cg.addTag(.i32_xor);
2972 return .stack;2970 return .stack;
2973 },2971 },
2974 32, 64 => {2972 32, 64 => {
2975 try func.emitWValue(arg);2973 try cg.emitWValue(arg);
2976 const val_type: std.wasm.Valtype = if (float_bits == 32) .f32 else .f64;2974 const val_type: std.wasm.Valtype = if (float_bits == 32) .f32 else .f64;
2977 const opcode = buildOpcode(.{ .op = .neg, .valtype1 = val_type });2975 const opcode = buildOpcode(.{ .op = .neg, .valtype1 = val_type });
2978 try func.addTag(Mir.Inst.Tag.fromOpcode(opcode));2976 try cg.addTag(Mir.Inst.Tag.fromOpcode(opcode));
2979 return .stack;2977 return .stack;
2980 },2978 },
2981 80, 128 => {2979 80, 128 => {
2982 const result = try func.allocStack(ty);2980 const result = try cg.allocStack(ty);
2983 try func.emitWValue(result);2981 try cg.emitWValue(result);
2984 try func.emitWValue(arg);2982 try cg.emitWValue(arg);
2985 try func.addMemArg(.i64_load, .{ .offset = 0 + arg.offset(), .alignment = 2 });2983 try cg.addMemArg(.i64_load, .{ .offset = 0 + arg.offset(), .alignment = 2 });
2986 try func.addMemArg(.i64_store, .{ .offset = 0 + result.offset(), .alignment = 2 });2984 try cg.addMemArg(.i64_store, .{ .offset = 0 + result.offset(), .alignment = 2 });
29872985
2988 try func.emitWValue(result);2986 try cg.emitWValue(result);
2989 try func.emitWValue(arg);2987 try cg.emitWValue(arg);
2990 try func.addMemArg(.i64_load, .{ .offset = 8 + arg.offset(), .alignment = 2 });2988 try cg.addMemArg(.i64_load, .{ .offset = 8 + arg.offset(), .alignment = 2 });
29912989
2992 if (float_bits == 80) {2990 if (float_bits == 80) {
2993 try func.addImm64(0x8000);2991 try cg.addImm64(0x8000);
2994 try func.addTag(.i64_xor);2992 try cg.addTag(.i64_xor);
2995 try func.addMemArg(.i64_store16, .{ .offset = 8 + result.offset(), .alignment = 2 });2993 try cg.addMemArg(.i64_store16, .{ .offset = 8 + result.offset(), .alignment = 2 });
2996 } else {2994 } else {
2997 try func.addImm64(0x8000000000000000);2995 try cg.addImm64(0x8000000000000000);
2998 try func.addTag(.i64_xor);2996 try cg.addTag(.i64_xor);
2999 try func.addMemArg(.i64_store, .{ .offset = 8 + result.offset(), .alignment = 2 });2997 try cg.addMemArg(.i64_store, .{ .offset = 8 + result.offset(), .alignment = 2 });
3000 }2998 }
3001 return result;2999 return result;
3002 },3000 },
...@@ -3004,18 +3002,18 @@ fn floatNeg(func: *CodeGen, ty: Type, arg: WValue) InnerError!WValue {...@@ -3004,18 +3002,18 @@ fn floatNeg(func: *CodeGen, ty: Type, arg: WValue) InnerError!WValue {
3004 }3002 }
3005}3003}
30063004
3007fn airWrapBinOp(func: *CodeGen, inst: Air.Inst.Index, op: Op) InnerError!void {3005fn airWrapBinOp(cg: *CodeGen, inst: Air.Inst.Index, op: Op) InnerError!void {
3008 const pt = func.pt;3006 const pt = cg.pt;
3009 const zcu = pt.zcu;3007 const zcu = pt.zcu;
3010 const bin_op = func.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;3008 const bin_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
30113009
3012 const lhs = try func.resolveInst(bin_op.lhs);3010 const lhs = try cg.resolveInst(bin_op.lhs);
3013 const rhs = try func.resolveInst(bin_op.rhs);3011 const rhs = try cg.resolveInst(bin_op.rhs);
3014 const lhs_ty = func.typeOf(bin_op.lhs);3012 const lhs_ty = cg.typeOf(bin_op.lhs);
3015 const rhs_ty = func.typeOf(bin_op.rhs);3013 const rhs_ty = cg.typeOf(bin_op.rhs);
30163014
3017 if (lhs_ty.zigTypeTag(zcu) == .vector or rhs_ty.zigTypeTag(zcu) == .vector) {3015 if (lhs_ty.zigTypeTag(zcu) == .vector or rhs_ty.zigTypeTag(zcu) == .vector) {
3018 return func.fail("TODO: Implement wrapping arithmetic for vectors", .{});3016 return cg.fail("TODO: Implement wrapping arithmetic for vectors", .{});
3019 }3017 }
30203018
3021 // For certain operations, such as shifting, the types are different.3019 // For certain operations, such as shifting, the types are different.
...@@ -3026,90 +3024,90 @@ fn airWrapBinOp(func: *CodeGen, inst: Air.Inst.Index, op: Op) InnerError!void {...@@ -3026,90 +3024,90 @@ fn airWrapBinOp(func: *CodeGen, inst: Air.Inst.Index, op: Op) InnerError!void {
3026 const result = switch (op) {3024 const result = switch (op) {
3027 .shr, .shl => result: {3025 .shr, .shl => result: {
3028 const lhs_wasm_bits = toWasmBits(@intCast(lhs_ty.bitSize(zcu))) orelse {3026 const lhs_wasm_bits = toWasmBits(@intCast(lhs_ty.bitSize(zcu))) orelse {
3029 return func.fail("TODO: implement '{s}' for types larger than 128 bits", .{@tagName(op)});3027 return cg.fail("TODO: implement '{s}' for types larger than 128 bits", .{@tagName(op)});
3030 };3028 };
3031 const rhs_wasm_bits = toWasmBits(@intCast(rhs_ty.bitSize(zcu))).?;3029 const rhs_wasm_bits = toWasmBits(@intCast(rhs_ty.bitSize(zcu))).?;
3032 const new_rhs = if (lhs_wasm_bits != rhs_wasm_bits and lhs_wasm_bits != 128)3030 const new_rhs = if (lhs_wasm_bits != rhs_wasm_bits and lhs_wasm_bits != 128)
3033 try (try func.intcast(rhs, rhs_ty, lhs_ty)).toLocal(func, lhs_ty)3031 try (try cg.intcast(rhs, rhs_ty, lhs_ty)).toLocal(cg, lhs_ty)
3034 else3032 else
3035 rhs;3033 rhs;
3036 break :result try func.wrapBinOp(lhs, new_rhs, lhs_ty, op);3034 break :result try cg.wrapBinOp(lhs, new_rhs, lhs_ty, op);
3037 },3035 },
3038 else => try func.wrapBinOp(lhs, rhs, lhs_ty, op),3036 else => try cg.wrapBinOp(lhs, rhs, lhs_ty, op),
3039 };3037 };
30403038
3041 return func.finishAir(inst, result, &.{ bin_op.lhs, bin_op.rhs });3039 return cg.finishAir(inst, result, &.{ bin_op.lhs, bin_op.rhs });
3042}3040}
30433041
3044/// Performs a wrapping binary operation.3042/// Performs a wrapping binary operation.
3045/// Asserts rhs is not a stack value when lhs also isn't.3043/// Asserts rhs is not a stack value when lhs also isn't.
3046/// NOTE: Leaves the result on the stack when its Type is <= 64 bits3044/// NOTE: Leaves the result on the stack when its Type is <= 64 bits
3047fn wrapBinOp(func: *CodeGen, lhs: WValue, rhs: WValue, ty: Type, op: Op) InnerError!WValue {3045fn wrapBinOp(cg: *CodeGen, lhs: WValue, rhs: WValue, ty: Type, op: Op) InnerError!WValue {
3048 const bin_local = try func.binOp(lhs, rhs, ty, op);3046 const bin_local = try cg.binOp(lhs, rhs, ty, op);
3049 return func.wrapOperand(bin_local, ty);3047 return cg.wrapOperand(bin_local, ty);
3050}3048}
30513049
3052/// Wraps an operand based on a given type's bitsize.3050/// Wraps an operand based on a given type's bitsize.
3053/// Asserts `Type` is <= 128 bits.3051/// Asserts `Type` is <= 128 bits.
3054/// NOTE: When the Type is <= 64 bits, leaves the value on top of the stack, if wrapping was needed.3052/// NOTE: When the Type is <= 64 bits, leaves the value on top of the stack, if wrapping was needed.
3055fn wrapOperand(func: *CodeGen, operand: WValue, ty: Type) InnerError!WValue {3053fn wrapOperand(cg: *CodeGen, operand: WValue, ty: Type) InnerError!WValue {
3056 const pt = func.pt;3054 const pt = cg.pt;
3057 const zcu = pt.zcu;3055 const zcu = pt.zcu;
3058 assert(ty.abiSize(zcu) <= 16);3056 assert(ty.abiSize(zcu) <= 16);
3059 const int_bits: u16 = @intCast(ty.bitSize(zcu)); // TODO use ty.intInfo(zcu).bits3057 const int_bits: u16 = @intCast(ty.bitSize(zcu)); // TODO use ty.intInfo(zcu).bits
3060 const wasm_bits = toWasmBits(int_bits) orelse {3058 const wasm_bits = toWasmBits(int_bits) orelse {
3061 return func.fail("TODO: Implement wrapOperand for bitsize '{d}'", .{int_bits});3059 return cg.fail("TODO: Implement wrapOperand for bitsize '{d}'", .{int_bits});
3062 };3060 };
30633061
3064 if (wasm_bits == int_bits) return operand;3062 if (wasm_bits == int_bits) return operand;
30653063
3066 switch (wasm_bits) {3064 switch (wasm_bits) {
3067 32 => {3065 32 => {
3068 try func.emitWValue(operand);3066 try cg.emitWValue(operand);
3069 if (ty.isSignedInt(zcu)) {3067 if (ty.isSignedInt(zcu)) {
3070 try func.addImm32(32 - int_bits);3068 try cg.addImm32(32 - int_bits);
3071 try func.addTag(.i32_shl);3069 try cg.addTag(.i32_shl);
3072 try func.addImm32(32 - int_bits);3070 try cg.addImm32(32 - int_bits);
3073 try func.addTag(.i32_shr_s);3071 try cg.addTag(.i32_shr_s);
3074 } else {3072 } else {
3075 try func.addImm32(~@as(u32, 0) >> @intCast(32 - int_bits));3073 try cg.addImm32(~@as(u32, 0) >> @intCast(32 - int_bits));
3076 try func.addTag(.i32_and);3074 try cg.addTag(.i32_and);
3077 }3075 }
3078 return .stack;3076 return .stack;
3079 },3077 },
3080 64 => {3078 64 => {
3081 try func.emitWValue(operand);3079 try cg.emitWValue(operand);
3082 if (ty.isSignedInt(zcu)) {3080 if (ty.isSignedInt(zcu)) {
3083 try func.addImm64(64 - int_bits);3081 try cg.addImm64(64 - int_bits);
3084 try func.addTag(.i64_shl);3082 try cg.addTag(.i64_shl);
3085 try func.addImm64(64 - int_bits);3083 try cg.addImm64(64 - int_bits);
3086 try func.addTag(.i64_shr_s);3084 try cg.addTag(.i64_shr_s);
3087 } else {3085 } else {
3088 try func.addImm64(~@as(u64, 0) >> @intCast(64 - int_bits));3086 try cg.addImm64(~@as(u64, 0) >> @intCast(64 - int_bits));
3089 try func.addTag(.i64_and);3087 try cg.addTag(.i64_and);
3090 }3088 }
3091 return .stack;3089 return .stack;
3092 },3090 },
3093 128 => {3091 128 => {
3094 assert(operand != .stack);3092 assert(operand != .stack);
3095 const result = try func.allocStack(ty);3093 const result = try cg.allocStack(ty);
30963094
3097 try func.emitWValue(result);3095 try cg.emitWValue(result);
3098 _ = try func.load(operand, Type.u64, 0);3096 _ = try cg.load(operand, Type.u64, 0);
3099 try func.store(.stack, .stack, Type.u64, result.offset());3097 try cg.store(.stack, .stack, Type.u64, result.offset());
31003098
3101 try func.emitWValue(result);3099 try cg.emitWValue(result);
3102 _ = try func.load(operand, Type.u64, 8);3100 _ = try cg.load(operand, Type.u64, 8);
3103 if (ty.isSignedInt(zcu)) {3101 if (ty.isSignedInt(zcu)) {
3104 try func.addImm64(128 - int_bits);3102 try cg.addImm64(128 - int_bits);
3105 try func.addTag(.i64_shl);3103 try cg.addTag(.i64_shl);
3106 try func.addImm64(128 - int_bits);3104 try cg.addImm64(128 - int_bits);
3107 try func.addTag(.i64_shr_s);3105 try cg.addTag(.i64_shr_s);
3108 } else {3106 } else {
3109 try func.addImm64(~@as(u64, 0) >> @intCast(128 - int_bits));3107 try cg.addImm64(~@as(u64, 0) >> @intCast(128 - int_bits));
3110 try func.addTag(.i64_and);3108 try cg.addTag(.i64_and);
3111 }3109 }
3112 try func.store(.stack, .stack, Type.u64, result.offset() + 8);3110 try cg.store(.stack, .stack, Type.u64, result.offset() + 8);
31133111
3114 return result;3112 return result;
3115 },3113 },
...@@ -3117,17 +3115,17 @@ fn wrapOperand(func: *CodeGen, operand: WValue, ty: Type) InnerError!WValue {...@@ -3117,17 +3115,17 @@ fn wrapOperand(func: *CodeGen, operand: WValue, ty: Type) InnerError!WValue {
3117 }3115 }
3118}3116}
31193117
3120fn lowerPtr(func: *CodeGen, ptr_val: InternPool.Index, prev_offset: u64) InnerError!WValue {3118fn lowerPtr(cg: *CodeGen, ptr_val: InternPool.Index, prev_offset: u64) InnerError!WValue {
3121 const pt = func.pt;3119 const pt = cg.pt;
3122 const zcu = pt.zcu;3120 const zcu = pt.zcu;
3123 const ptr = zcu.intern_pool.indexToKey(ptr_val).ptr;3121 const ptr = zcu.intern_pool.indexToKey(ptr_val).ptr;
3124 const offset: u64 = prev_offset + ptr.byte_offset;3122 const offset: u64 = prev_offset + ptr.byte_offset;
3125 return switch (ptr.base_addr) {3123 return switch (ptr.base_addr) {
3126 .nav => |nav| return .{ .nav_ref = .{ .nav_index = zcu.chaseNav(nav), .offset = @intCast(offset) } },3124 .nav => |nav| return .{ .nav_ref = .{ .nav_index = zcu.chaseNav(nav), .offset = @intCast(offset) } },
3127 .uav => |uav| return .{ .uav_ref = .{ .ip_index = uav.val, .offset = @intCast(offset) } },3125 .uav => |uav| return .{ .uav_ref = .{ .ip_index = uav.val, .offset = @intCast(offset) } },
3128 .int => return func.lowerConstant(try pt.intValue(Type.usize, offset), Type.usize),3126 .int => return cg.lowerConstant(try pt.intValue(Type.usize, offset), Type.usize),
3129 .eu_payload => return func.fail("Wasm TODO: lower error union payload pointer", .{}),3127 .eu_payload => return cg.fail("Wasm TODO: lower error union payload pointer", .{}),
3130 .opt_payload => |opt_ptr| return func.lowerPtr(opt_ptr, offset),3128 .opt_payload => |opt_ptr| return cg.lowerPtr(opt_ptr, offset),
3131 .field => |field| {3129 .field => |field| {
3132 const base_ptr = Value.fromInterned(field.base);3130 const base_ptr = Value.fromInterned(field.base);
3133 const base_ty = base_ptr.typeOf(zcu).childType(zcu);3131 const base_ty = base_ptr.typeOf(zcu).childType(zcu);
...@@ -3136,7 +3134,7 @@ fn lowerPtr(func: *CodeGen, ptr_val: InternPool.Index, prev_offset: u64) InnerEr...@@ -3136,7 +3134,7 @@ fn lowerPtr(func: *CodeGen, ptr_val: InternPool.Index, prev_offset: u64) InnerEr
3136 assert(base_ty.isSlice(zcu));3134 assert(base_ty.isSlice(zcu));
3137 break :off switch (field.index) {3135 break :off switch (field.index) {
3138 Value.slice_ptr_index => 0,3136 Value.slice_ptr_index => 0,
3139 Value.slice_len_index => @divExact(func.target.ptrBitWidth(), 8),3137 Value.slice_len_index => @divExact(cg.target.ptrBitWidth(), 8),
3140 else => unreachable,3138 else => unreachable,
3141 };3139 };
3142 },3140 },
...@@ -3162,19 +3160,19 @@ fn lowerPtr(func: *CodeGen, ptr_val: InternPool.Index, prev_offset: u64) InnerEr...@@ -3162,19 +3160,19 @@ fn lowerPtr(func: *CodeGen, ptr_val: InternPool.Index, prev_offset: u64) InnerEr
3162 },3160 },
3163 else => unreachable,3161 else => unreachable,
3164 };3162 };
3165 return func.lowerPtr(field.base, offset + field_off);3163 return cg.lowerPtr(field.base, offset + field_off);
3166 },3164 },
3167 .arr_elem, .comptime_field, .comptime_alloc => unreachable,3165 .arr_elem, .comptime_field, .comptime_alloc => unreachable,
3168 };3166 };
3169}3167}
31703168
3171/// Asserts that `isByRef` returns `false` for `ty`.3169/// Asserts that `isByRef` returns `false` for `ty`.
3172fn lowerConstant(func: *CodeGen, val: Value, ty: Type) InnerError!WValue {3170fn lowerConstant(cg: *CodeGen, val: Value, ty: Type) InnerError!WValue {
3173 const pt = func.pt;3171 const pt = cg.pt;
3174 const zcu = pt.zcu;3172 const zcu = pt.zcu;
3175 assert(!isByRef(ty, pt, func.target));3173 assert(!isByRef(ty, pt, cg.target));
3176 const ip = &zcu.intern_pool;3174 const ip = &zcu.intern_pool;
3177 if (val.isUndefDeep(zcu)) return func.emitUndefined(ty);3175 if (val.isUndefDeep(zcu)) return cg.emitUndefined(ty);
31783176
3179 switch (ip.indexToKey(val.ip_index)) {3177 switch (ip.indexToKey(val.ip_index)) {
3180 .int_type,3178 .int_type,
...@@ -3253,14 +3251,14 @@ fn lowerConstant(func: *CodeGen, val: Value, ty: Type) InnerError!WValue {...@@ -3253,14 +3251,14 @@ fn lowerConstant(func: *CodeGen, val: Value, ty: Type) InnerError!WValue {
3253 const payload_type = ty.errorUnionPayload(zcu);3251 const payload_type = ty.errorUnionPayload(zcu);
3254 if (!payload_type.hasRuntimeBitsIgnoreComptime(zcu)) {3252 if (!payload_type.hasRuntimeBitsIgnoreComptime(zcu)) {
3255 // We use the error type directly as the type.3253 // We use the error type directly as the type.
3256 return func.lowerConstant(err_val, err_ty);3254 return cg.lowerConstant(err_val, err_ty);
3257 }3255 }
32583256
3259 return func.fail("Wasm TODO: lowerConstant error union with non-zero-bit payload type", .{});3257 return cg.fail("Wasm TODO: lowerConstant error union with non-zero-bit payload type", .{});
3260 },3258 },
3261 .enum_tag => |enum_tag| {3259 .enum_tag => |enum_tag| {
3262 const int_tag_ty = ip.typeOf(enum_tag.int);3260 const int_tag_ty = ip.typeOf(enum_tag.int);
3263 return func.lowerConstant(Value.fromInterned(enum_tag.int), Type.fromInterned(int_tag_ty));3261 return cg.lowerConstant(Value.fromInterned(enum_tag.int), Type.fromInterned(int_tag_ty));
3264 },3262 },
3265 .float => |float| switch (float.storage) {3263 .float => |float| switch (float.storage) {
3266 .f16 => |f16_val| return .{ .imm32 = @as(u16, @bitCast(f16_val)) },3264 .f16 => |f16_val| return .{ .imm32 = @as(u16, @bitCast(f16_val)) },
...@@ -3269,11 +3267,11 @@ fn lowerConstant(func: *CodeGen, val: Value, ty: Type) InnerError!WValue {...@@ -3269,11 +3267,11 @@ fn lowerConstant(func: *CodeGen, val: Value, ty: Type) InnerError!WValue {
3269 else => unreachable,3267 else => unreachable,
3270 },3268 },
3271 .slice => unreachable, // isByRef == true3269 .slice => unreachable, // isByRef == true
3272 .ptr => return func.lowerPtr(val.toIntern(), 0),3270 .ptr => return cg.lowerPtr(val.toIntern(), 0),
3273 .opt => if (ty.optionalReprIsPayload(zcu)) {3271 .opt => if (ty.optionalReprIsPayload(zcu)) {
3274 const pl_ty = ty.optionalChild(zcu);3272 const pl_ty = ty.optionalChild(zcu);
3275 if (val.optionalValue(zcu)) |payload| {3273 if (val.optionalValue(zcu)) |payload| {
3276 return func.lowerConstant(payload, pl_ty);3274 return cg.lowerConstant(payload, pl_ty);
3277 } else {3275 } else {
3278 return .{ .imm32 = 0 };3276 return .{ .imm32 = 0 };
3279 }3277 }
...@@ -3281,12 +3279,12 @@ fn lowerConstant(func: *CodeGen, val: Value, ty: Type) InnerError!WValue {...@@ -3281,12 +3279,12 @@ fn lowerConstant(func: *CodeGen, val: Value, ty: Type) InnerError!WValue {
3281 return .{ .imm32 = @intFromBool(!val.isNull(zcu)) };3279 return .{ .imm32 = @intFromBool(!val.isNull(zcu)) };
3282 },3280 },
3283 .aggregate => switch (ip.indexToKey(ty.ip_index)) {3281 .aggregate => switch (ip.indexToKey(ty.ip_index)) {
3284 .array_type => return func.fail("Wasm TODO: LowerConstant for {}", .{ty.fmt(pt)}),3282 .array_type => return cg.fail("Wasm TODO: LowerConstant for {}", .{ty.fmt(pt)}),
3285 .vector_type => {3283 .vector_type => {
3286 assert(determineSimdStoreStrategy(ty, zcu, func.target) == .direct);3284 assert(determineSimdStoreStrategy(ty, zcu, cg.target) == .direct);
3287 var buf: [16]u8 = undefined;3285 var buf: [16]u8 = undefined;
3288 val.writeToMemory(pt, &buf) catch unreachable;3286 val.writeToMemory(pt, &buf) catch unreachable;
3289 return func.storeSimdImmd(buf);3287 return cg.storeSimdImmd(buf);
3290 },3288 },
3291 .struct_type => {3289 .struct_type => {
3292 const struct_type = ip.loadStructType(ty.toIntern());3290 const struct_type = ip.loadStructType(ty.toIntern());
...@@ -3300,7 +3298,7 @@ fn lowerConstant(func: *CodeGen, val: Value, ty: Type) InnerError!WValue {...@@ -3300,7 +3298,7 @@ fn lowerConstant(func: *CodeGen, val: Value, ty: Type) InnerError!WValue {
3300 backing_int_ty,3298 backing_int_ty,
3301 mem.readInt(u64, &buf, .little),3299 mem.readInt(u64, &buf, .little),
3302 );3300 );
3303 return func.lowerConstant(int_val, backing_int_ty);3301 return cg.lowerConstant(int_val, backing_int_ty);
3304 },3302 },
3305 else => unreachable,3303 else => unreachable,
3306 },3304 },
...@@ -3313,7 +3311,7 @@ fn lowerConstant(func: *CodeGen, val: Value, ty: Type) InnerError!WValue {...@@ -3313,7 +3311,7 @@ fn lowerConstant(func: *CodeGen, val: Value, ty: Type) InnerError!WValue {
3313 const field_index = zcu.unionTagFieldIndex(union_obj, Value.fromInterned(un.tag)).?;3311 const field_index = zcu.unionTagFieldIndex(union_obj, Value.fromInterned(un.tag)).?;
3314 break :field_ty Type.fromInterned(union_obj.field_types.get(ip)[field_index]);3312 break :field_ty Type.fromInterned(union_obj.field_types.get(ip)[field_index]);
3315 };3313 };
3316 return func.lowerConstant(Value.fromInterned(un.val), constant_ty);3314 return cg.lowerConstant(Value.fromInterned(un.val), constant_ty);
3317 },3315 },
3318 .memoized_call => unreachable,3316 .memoized_call => unreachable,
3319 }3317 }
...@@ -3321,14 +3319,14 @@ fn lowerConstant(func: *CodeGen, val: Value, ty: Type) InnerError!WValue {...@@ -3321,14 +3319,14 @@ fn lowerConstant(func: *CodeGen, val: Value, ty: Type) InnerError!WValue {
33213319
3322/// Stores the value as a 128bit-immediate value by storing it inside3320/// Stores the value as a 128bit-immediate value by storing it inside
3323/// the list and returning the index into this list as `WValue`.3321/// the list and returning the index into this list as `WValue`.
3324fn storeSimdImmd(func: *CodeGen, value: [16]u8) !WValue {3322fn storeSimdImmd(cg: *CodeGen, value: [16]u8) !WValue {
3325 const index = @as(u32, @intCast(func.simd_immediates.items.len));3323 const index = @as(u32, @intCast(cg.simd_immediates.items.len));
3326 try func.simd_immediates.append(func.gpa, value);3324 try cg.simd_immediates.append(cg.gpa, value);
3327 return .{ .imm128 = index };3325 return .{ .imm128 = index };
3328}3326}
33293327
3330fn emitUndefined(func: *CodeGen, ty: Type) InnerError!WValue {3328fn emitUndefined(cg: *CodeGen, ty: Type) InnerError!WValue {
3331 const pt = func.pt;3329 const pt = cg.pt;
3332 const zcu = pt.zcu;3330 const zcu = pt.zcu;
3333 const ip = &zcu.intern_pool;3331 const ip = &zcu.intern_pool;
3334 switch (ty.zigTypeTag(zcu)) {3332 switch (ty.zigTypeTag(zcu)) {
...@@ -3338,20 +3336,20 @@ fn emitUndefined(func: *CodeGen, ty: Type) InnerError!WValue {...@@ -3338,20 +3336,20 @@ fn emitUndefined(func: *CodeGen, ty: Type) InnerError!WValue {
3338 33...64 => return .{ .imm64 = 0xaaaaaaaaaaaaaaaa },3336 33...64 => return .{ .imm64 = 0xaaaaaaaaaaaaaaaa },
3339 else => unreachable,3337 else => unreachable,
3340 },3338 },
3341 .float => switch (ty.floatBits(func.target.*)) {3339 .float => switch (ty.floatBits(cg.target.*)) {
3342 16 => return .{ .imm32 = 0xaaaaaaaa },3340 16 => return .{ .imm32 = 0xaaaaaaaa },
3343 32 => return .{ .float32 = @as(f32, @bitCast(@as(u32, 0xaaaaaaaa))) },3341 32 => return .{ .float32 = @as(f32, @bitCast(@as(u32, 0xaaaaaaaa))) },
3344 64 => return .{ .float64 = @as(f64, @bitCast(@as(u64, 0xaaaaaaaaaaaaaaaa))) },3342 64 => return .{ .float64 = @as(f64, @bitCast(@as(u64, 0xaaaaaaaaaaaaaaaa))) },
3345 else => unreachable,3343 else => unreachable,
3346 },3344 },
3347 .pointer => switch (func.ptr_size) {3345 .pointer => switch (cg.ptr_size) {
3348 .wasm32 => return .{ .imm32 = 0xaaaaaaaa },3346 .wasm32 => return .{ .imm32 = 0xaaaaaaaa },
3349 .wasm64 => return .{ .imm64 = 0xaaaaaaaaaaaaaaaa },3347 .wasm64 => return .{ .imm64 = 0xaaaaaaaaaaaaaaaa },
3350 },3348 },
3351 .optional => {3349 .optional => {
3352 const pl_ty = ty.optionalChild(zcu);3350 const pl_ty = ty.optionalChild(zcu);
3353 if (ty.optionalReprIsPayload(zcu)) {3351 if (ty.optionalReprIsPayload(zcu)) {
3354 return func.emitUndefined(pl_ty);3352 return cg.emitUndefined(pl_ty);
3355 }3353 }
3356 return .{ .imm32 = 0xaaaaaaaa };3354 return .{ .imm32 = 0xaaaaaaaa };
3357 },3355 },
...@@ -3360,17 +3358,17 @@ fn emitUndefined(func: *CodeGen, ty: Type) InnerError!WValue {...@@ -3360,17 +3358,17 @@ fn emitUndefined(func: *CodeGen, ty: Type) InnerError!WValue {
3360 },3358 },
3361 .@"struct" => {3359 .@"struct" => {
3362 const packed_struct = zcu.typeToPackedStruct(ty).?;3360 const packed_struct = zcu.typeToPackedStruct(ty).?;
3363 return func.emitUndefined(Type.fromInterned(packed_struct.backingIntTypeUnordered(ip)));3361 return cg.emitUndefined(Type.fromInterned(packed_struct.backingIntTypeUnordered(ip)));
3364 },3362 },
3365 else => return func.fail("Wasm TODO: emitUndefined for type: {}\n", .{ty.zigTypeTag(zcu)}),3363 else => return cg.fail("Wasm TODO: emitUndefined for type: {}\n", .{ty.zigTypeTag(zcu)}),
3366 }3364 }
3367}3365}
33683366
3369/// Returns a `Value` as a signed 32 bit value.3367/// Returns a `Value` as a signed 32 bit value.
3370/// It's illegal to provide a value with a type that cannot be represented3368/// It's illegal to provide a value with a type that cannot be represented
3371/// as an integer value.3369/// as an integer value.
3372fn valueAsI32(func: *const CodeGen, val: Value) i32 {3370fn valueAsI32(cg: *const CodeGen, val: Value) i32 {
3373 const pt = func.pt;3371 const pt = cg.pt;
3374 const zcu = pt.zcu;3372 const zcu = pt.zcu;
3375 const ip = &zcu.intern_pool;3373 const ip = &zcu.intern_pool;
33763374
...@@ -3405,132 +3403,132 @@ fn intStorageAsI32(storage: InternPool.Key.Int.Storage, pt: Zcu.PerThread) i32 {...@@ -3405,132 +3403,132 @@ fn intStorageAsI32(storage: InternPool.Key.Int.Storage, pt: Zcu.PerThread) i32 {
3405 };3403 };
3406}3404}
34073405
3408fn airBlock(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {3406fn airBlock(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
3409 const ty_pl = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;3407 const ty_pl = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
3410 const extra = func.air.extraData(Air.Block, ty_pl.payload);3408 const extra = cg.air.extraData(Air.Block, ty_pl.payload);
3411 try func.lowerBlock(inst, ty_pl.ty.toType(), @ptrCast(func.air.extra[extra.end..][0..extra.data.body_len]));3409 try cg.lowerBlock(inst, ty_pl.ty.toType(), @ptrCast(cg.air.extra[extra.end..][0..extra.data.body_len]));
3412}3410}
34133411
3414fn lowerBlock(func: *CodeGen, inst: Air.Inst.Index, block_ty: Type, body: []const Air.Inst.Index) InnerError!void {3412fn lowerBlock(cg: *CodeGen, inst: Air.Inst.Index, block_ty: Type, body: []const Air.Inst.Index) InnerError!void {
3415 const pt = func.pt;3413 const pt = cg.pt;
3416 const wasm_block_ty = genBlockType(block_ty, pt, func.target);3414 const wasm_block_ty = genBlockType(block_ty, pt, cg.target);
34173415
3418 // if wasm_block_ty is non-empty, we create a register to store the temporary value3416 // if wasm_block_ty is non-empty, we create a register to store the temporary value
3419 const block_result: WValue = if (wasm_block_ty != std.wasm.block_empty) blk: {3417 const block_result: WValue = if (wasm_block_ty != std.wasm.block_empty) blk: {
3420 const ty: Type = if (isByRef(block_ty, pt, func.target)) Type.u32 else block_ty;3418 const ty: Type = if (isByRef(block_ty, pt, cg.target)) Type.u32 else block_ty;
3421 break :blk try func.ensureAllocLocal(ty); // make sure it's a clean local as it may never get overwritten3419 break :blk try cg.ensureAllocLocal(ty); // make sure it's a clean local as it may never get overwritten
3422 } else .none;3420 } else .none;
34233421
3424 try func.startBlock(.block, std.wasm.block_empty);3422 try cg.startBlock(.block, std.wasm.block_empty);
3425 // Here we set the current block idx, so breaks know the depth to jump3423 // Here we set the current block idx, so breaks know the depth to jump
3426 // to when breaking out.3424 // to when breaking out.
3427 try func.blocks.putNoClobber(func.gpa, inst, .{3425 try cg.blocks.putNoClobber(cg.gpa, inst, .{
3428 .label = func.block_depth,3426 .label = cg.block_depth,
3429 .value = block_result,3427 .value = block_result,
3430 });3428 });
34313429
3432 try func.genBody(body);3430 try cg.genBody(body);
3433 try func.endBlock();3431 try cg.endBlock();
34343432
3435 const liveness = func.liveness.getBlock(inst);3433 const liveness = cg.liveness.getBlock(inst);
3436 try func.currentBranch().values.ensureUnusedCapacity(func.gpa, liveness.deaths.len);3434 try cg.currentBranch().values.ensureUnusedCapacity(cg.gpa, liveness.deaths.len);
34373435
3438 return func.finishAir(inst, block_result, &.{});3436 return cg.finishAir(inst, block_result, &.{});
3439}3437}
34403438
3441/// appends a new wasm block to the code section and increases the `block_depth` by 13439/// appends a new wasm block to the code section and increases the `block_depth` by 1
3442fn startBlock(func: *CodeGen, block_tag: std.wasm.Opcode, valtype: u8) !void {3440fn startBlock(cg: *CodeGen, block_tag: std.wasm.Opcode, valtype: u8) !void {
3443 func.block_depth += 1;3441 cg.block_depth += 1;
3444 try func.addInst(.{3442 try cg.addInst(.{
3445 .tag = Mir.Inst.Tag.fromOpcode(block_tag),3443 .tag = Mir.Inst.Tag.fromOpcode(block_tag),
3446 .data = .{ .block_type = valtype },3444 .data = .{ .block_type = valtype },
3447 });3445 });
3448}3446}
34493447
3450/// Ends the current wasm block and decreases the `block_depth` by 13448/// Ends the current wasm block and decreases the `block_depth` by 1
3451fn endBlock(func: *CodeGen) !void {3449fn endBlock(cg: *CodeGen) !void {
3452 try func.addTag(.end);3450 try cg.addTag(.end);
3453 func.block_depth -= 1;3451 cg.block_depth -= 1;
3454}3452}
34553453
3456fn airLoop(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {3454fn airLoop(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
3457 const ty_pl = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;3455 const ty_pl = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
3458 const loop = func.air.extraData(Air.Block, ty_pl.payload);3456 const loop = cg.air.extraData(Air.Block, ty_pl.payload);
3459 const body: []const Air.Inst.Index = @ptrCast(func.air.extra[loop.end..][0..loop.data.body_len]);3457 const body: []const Air.Inst.Index = @ptrCast(cg.air.extra[loop.end..][0..loop.data.body_len]);
34603458
3461 // result type of loop is always 'noreturn', meaning we can always3459 // result type of loop is always 'noreturn', meaning we can always
3462 // emit the wasm type 'block_empty'.3460 // emit the wasm type 'block_empty'.
3463 try func.startBlock(.loop, std.wasm.block_empty);3461 try cg.startBlock(.loop, std.wasm.block_empty);
34643462
3465 try func.loops.putNoClobber(func.gpa, inst, func.block_depth);3463 try cg.loops.putNoClobber(cg.gpa, inst, cg.block_depth);
3466 defer assert(func.loops.remove(inst));3464 defer assert(cg.loops.remove(inst));
34673465
3468 try func.genBody(body);3466 try cg.genBody(body);
3469 try func.endBlock();3467 try cg.endBlock();
34703468
3471 return func.finishAir(inst, .none, &.{});3469 return cg.finishAir(inst, .none, &.{});
3472}3470}
34733471
3474fn airCondBr(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {3472fn airCondBr(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
3475 const pl_op = func.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;3473 const pl_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;
3476 const condition = try func.resolveInst(pl_op.operand);3474 const condition = try cg.resolveInst(pl_op.operand);
3477 const extra = func.air.extraData(Air.CondBr, pl_op.payload);3475 const extra = cg.air.extraData(Air.CondBr, pl_op.payload);
3478 const then_body: []const Air.Inst.Index = @ptrCast(func.air.extra[extra.end..][0..extra.data.then_body_len]);3476 const then_body: []const Air.Inst.Index = @ptrCast(cg.air.extra[extra.end..][0..extra.data.then_body_len]);
3479 const else_body: []const Air.Inst.Index = @ptrCast(func.air.extra[extra.end + then_body.len ..][0..extra.data.else_body_len]);3477 const else_body: []const Air.Inst.Index = @ptrCast(cg.air.extra[extra.end + then_body.len ..][0..extra.data.else_body_len]);
3480 const liveness_condbr = func.liveness.getCondBr(inst);3478 const liveness_condbr = cg.liveness.getCondBr(inst);
34813479
3482 // result type is always noreturn, so use `block_empty` as type.3480 // result type is always noreturn, so use `block_empty` as type.
3483 try func.startBlock(.block, std.wasm.block_empty);3481 try cg.startBlock(.block, std.wasm.block_empty);
3484 // emit the conditional value3482 // emit the conditional value
3485 try func.emitWValue(condition);3483 try cg.emitWValue(condition);
34863484
3487 // we inserted the block in front of the condition3485 // we inserted the block in front of the condition
3488 // so now check if condition matches. If not, break outside this block3486 // so now check if condition matches. If not, break outside this block
3489 // and continue with the then codepath3487 // and continue with the then codepath
3490 try func.addLabel(.br_if, 0);3488 try cg.addLabel(.br_if, 0);
34913489
3492 try func.branches.ensureUnusedCapacity(func.gpa, 2);3490 try cg.branches.ensureUnusedCapacity(cg.gpa, 2);
3493 {3491 {
3494 func.branches.appendAssumeCapacity(.{});3492 cg.branches.appendAssumeCapacity(.{});
3495 try func.currentBranch().values.ensureUnusedCapacity(func.gpa, @as(u32, @intCast(liveness_condbr.else_deaths.len)));3493 try cg.currentBranch().values.ensureUnusedCapacity(cg.gpa, @as(u32, @intCast(liveness_condbr.else_deaths.len)));
3496 defer {3494 defer {
3497 var else_stack = func.branches.pop();3495 var else_stack = cg.branches.pop();
3498 else_stack.deinit(func.gpa);3496 else_stack.deinit(cg.gpa);
3499 }3497 }
3500 try func.genBody(else_body);3498 try cg.genBody(else_body);
3501 try func.endBlock();3499 try cg.endBlock();
3502 }3500 }
35033501
3504 // Outer block that matches the condition3502 // Outer block that matches the condition
3505 {3503 {
3506 func.branches.appendAssumeCapacity(.{});3504 cg.branches.appendAssumeCapacity(.{});
3507 try func.currentBranch().values.ensureUnusedCapacity(func.gpa, @as(u32, @intCast(liveness_condbr.then_deaths.len)));3505 try cg.currentBranch().values.ensureUnusedCapacity(cg.gpa, @as(u32, @intCast(liveness_condbr.then_deaths.len)));
3508 defer {3506 defer {
3509 var then_stack = func.branches.pop();3507 var then_stack = cg.branches.pop();
3510 then_stack.deinit(func.gpa);3508 then_stack.deinit(cg.gpa);
3511 }3509 }
3512 try func.genBody(then_body);3510 try cg.genBody(then_body);
3513 }3511 }
35143512
3515 return func.finishAir(inst, .none, &.{});3513 return cg.finishAir(inst, .none, &.{});
3516}3514}
35173515
3518fn airCmp(func: *CodeGen, inst: Air.Inst.Index, op: std.math.CompareOperator) InnerError!void {3516fn airCmp(cg: *CodeGen, inst: Air.Inst.Index, op: std.math.CompareOperator) InnerError!void {
3519 const bin_op = func.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;3517 const bin_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
35203518
3521 const lhs = try func.resolveInst(bin_op.lhs);3519 const lhs = try cg.resolveInst(bin_op.lhs);
3522 const rhs = try func.resolveInst(bin_op.rhs);3520 const rhs = try cg.resolveInst(bin_op.rhs);
3523 const operand_ty = func.typeOf(bin_op.lhs);3521 const operand_ty = cg.typeOf(bin_op.lhs);
3524 const result = try func.cmp(lhs, rhs, operand_ty, op);3522 const result = try cg.cmp(lhs, rhs, operand_ty, op);
3525 return func.finishAir(inst, result, &.{ bin_op.lhs, bin_op.rhs });3523 return cg.finishAir(inst, result, &.{ bin_op.lhs, bin_op.rhs });
3526}3524}
35273525
3528/// Compares two operands.3526/// Compares two operands.
3529/// Asserts rhs is not a stack value when the lhs isn't a stack value either3527/// Asserts rhs is not a stack value when the lhs isn't a stack value either
3530/// NOTE: This leaves the result on top of the stack, rather than a new local.3528/// NOTE: This leaves the result on top of the stack, rather than a new local.
3531fn cmp(func: *CodeGen, lhs: WValue, rhs: WValue, ty: Type, op: std.math.CompareOperator) InnerError!WValue {3529fn cmp(cg: *CodeGen, lhs: WValue, rhs: WValue, ty: Type, op: std.math.CompareOperator) InnerError!WValue {
3532 assert(!(lhs != .stack and rhs == .stack));3530 assert(!(lhs != .stack and rhs == .stack));
3533 const pt = func.pt;3531 const pt = cg.pt;
3534 const zcu = pt.zcu;3532 const zcu = pt.zcu;
3535 if (ty.zigTypeTag(zcu) == .optional and !ty.optionalReprIsPayload(zcu)) {3533 if (ty.zigTypeTag(zcu) == .optional and !ty.optionalReprIsPayload(zcu)) {
3536 const payload_ty = ty.optionalChild(zcu);3534 const payload_ty = ty.optionalChild(zcu);
...@@ -3538,12 +3536,12 @@ fn cmp(func: *CodeGen, lhs: WValue, rhs: WValue, ty: Type, op: std.math.CompareO...@@ -3538,12 +3536,12 @@ fn cmp(func: *CodeGen, lhs: WValue, rhs: WValue, ty: Type, op: std.math.CompareO
3538 // When we hit this case, we must check the value of optionals3536 // When we hit this case, we must check the value of optionals
3539 // that are not pointers. This means first checking against non-null for3537 // that are not pointers. This means first checking against non-null for
3540 // both lhs and rhs, as well as checking the payload are matching of lhs and rhs3538 // both lhs and rhs, as well as checking the payload are matching of lhs and rhs
3541 return func.cmpOptionals(lhs, rhs, ty, op);3539 return cg.cmpOptionals(lhs, rhs, ty, op);
3542 }3540 }
3543 } else if (ty.isAnyFloat()) {3541 } else if (ty.isAnyFloat()) {
3544 return func.cmpFloat(ty, lhs, rhs, op);3542 return cg.cmpFloat(ty, lhs, rhs, op);
3545 } else if (isByRef(ty, pt, func.target)) {3543 } else if (isByRef(ty, pt, cg.target)) {
3546 return func.cmpBigInt(lhs, rhs, ty, op);3544 return cg.cmpBigInt(lhs, rhs, ty, op);
3547 }3545 }
35483546
3549 const signedness: std.builtin.Signedness = blk: {3547 const signedness: std.builtin.Signedness = blk: {
...@@ -3556,11 +3554,11 @@ fn cmp(func: *CodeGen, lhs: WValue, rhs: WValue, ty: Type, op: std.math.CompareO...@@ -3556,11 +3554,11 @@ fn cmp(func: *CodeGen, lhs: WValue, rhs: WValue, ty: Type, op: std.math.CompareO
35563554
3557 // ensure that when we compare pointers, we emit3555 // ensure that when we compare pointers, we emit
3558 // the true pointer of a stack value, rather than the stack pointer.3556 // the true pointer of a stack value, rather than the stack pointer.
3559 try func.lowerToStack(lhs);3557 try cg.lowerToStack(lhs);
3560 try func.lowerToStack(rhs);3558 try cg.lowerToStack(rhs);
35613559
3562 const opcode: std.wasm.Opcode = buildOpcode(.{3560 const opcode: std.wasm.Opcode = buildOpcode(.{
3563 .valtype1 = typeToValtype(ty, pt, func.target),3561 .valtype1 = typeToValtype(ty, pt, cg.target),
3564 .op = switch (op) {3562 .op = switch (op) {
3565 .lt => .lt,3563 .lt => .lt,
3566 .lte => .le,3564 .lte => .le,
...@@ -3571,15 +3569,15 @@ fn cmp(func: *CodeGen, lhs: WValue, rhs: WValue, ty: Type, op: std.math.CompareO...@@ -3571,15 +3569,15 @@ fn cmp(func: *CodeGen, lhs: WValue, rhs: WValue, ty: Type, op: std.math.CompareO
3571 },3569 },
3572 .signedness = signedness,3570 .signedness = signedness,
3573 });3571 });
3574 try func.addTag(Mir.Inst.Tag.fromOpcode(opcode));3572 try cg.addTag(Mir.Inst.Tag.fromOpcode(opcode));
35753573
3576 return .stack;3574 return .stack;
3577}3575}
35783576
3579/// Compares two floats.3577/// Compares two floats.
3580/// NOTE: Leaves the result of the comparison on top of the stack.3578/// NOTE: Leaves the result of the comparison on top of the stack.
3581fn cmpFloat(func: *CodeGen, ty: Type, lhs: WValue, rhs: WValue, cmp_op: std.math.CompareOperator) InnerError!WValue {3579fn cmpFloat(cg: *CodeGen, ty: Type, lhs: WValue, rhs: WValue, cmp_op: std.math.CompareOperator) InnerError!WValue {
3582 const float_bits = ty.floatBits(func.target.*);3580 const float_bits = ty.floatBits(cg.target.*);
35833581
3584 const op: Op = switch (cmp_op) {3582 const op: Op = switch (cmp_op) {
3585 .lt => .lt,3583 .lt => .lt,
...@@ -3592,18 +3590,18 @@ fn cmpFloat(func: *CodeGen, ty: Type, lhs: WValue, rhs: WValue, cmp_op: std.math...@@ -3592,18 +3590,18 @@ fn cmpFloat(func: *CodeGen, ty: Type, lhs: WValue, rhs: WValue, cmp_op: std.math
35923590
3593 switch (float_bits) {3591 switch (float_bits) {
3594 16 => {3592 16 => {
3595 _ = try func.fpext(lhs, Type.f16, Type.f32);3593 _ = try cg.fpext(lhs, Type.f16, Type.f32);
3596 _ = try func.fpext(rhs, Type.f16, Type.f32);3594 _ = try cg.fpext(rhs, Type.f16, Type.f32);
3597 const opcode = buildOpcode(.{ .op = op, .valtype1 = .f32 });3595 const opcode = buildOpcode(.{ .op = op, .valtype1 = .f32 });
3598 try func.addTag(Mir.Inst.Tag.fromOpcode(opcode));3596 try cg.addTag(Mir.Inst.Tag.fromOpcode(opcode));
3599 return .stack;3597 return .stack;
3600 },3598 },
3601 32, 64 => {3599 32, 64 => {
3602 try func.emitWValue(lhs);3600 try cg.emitWValue(lhs);
3603 try func.emitWValue(rhs);3601 try cg.emitWValue(rhs);
3604 const val_type: std.wasm.Valtype = if (float_bits == 32) .f32 else .f64;3602 const val_type: std.wasm.Valtype = if (float_bits == 32) .f32 else .f64;
3605 const opcode = buildOpcode(.{ .op = op, .valtype1 = val_type });3603 const opcode = buildOpcode(.{ .op = op, .valtype1 = val_type });
3606 try func.addTag(Mir.Inst.Tag.fromOpcode(opcode));3604 try cg.addTag(Mir.Inst.Tag.fromOpcode(opcode));
3607 return .stack;3605 return .stack;
3608 },3606 },
3609 80, 128 => {3607 80, 128 => {
...@@ -3612,121 +3610,121 @@ fn cmpFloat(func: *CodeGen, ty: Type, lhs: WValue, rhs: WValue, cmp_op: std.math...@@ -3612,121 +3610,121 @@ fn cmpFloat(func: *CodeGen, ty: Type, lhs: WValue, rhs: WValue, cmp_op: std.math
3612 @tagName(op), target_util.compilerRtFloatAbbrev(float_bits),3610 @tagName(op), target_util.compilerRtFloatAbbrev(float_bits),
3613 }) catch unreachable;3611 }) catch unreachable;
36143612
3615 const result = try func.callIntrinsic(fn_name, &.{ ty.ip_index, ty.ip_index }, Type.bool, &.{ lhs, rhs });3613 const result = try cg.callIntrinsic(fn_name, &.{ ty.ip_index, ty.ip_index }, Type.bool, &.{ lhs, rhs });
3616 return func.cmp(result, .{ .imm32 = 0 }, Type.i32, cmp_op);3614 return cg.cmp(result, .{ .imm32 = 0 }, Type.i32, cmp_op);
3617 },3615 },
3618 else => unreachable,3616 else => unreachable,
3619 }3617 }
3620}3618}
36213619
3622fn airCmpVector(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {3620fn airCmpVector(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
3623 _ = inst;3621 _ = inst;
3624 return func.fail("TODO implement airCmpVector for wasm", .{});3622 return cg.fail("TODO implement airCmpVector for wasm", .{});
3625}3623}
36263624
3627fn airCmpLtErrorsLen(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {3625fn airCmpLtErrorsLen(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
3628 const un_op = func.air.instructions.items(.data)[@intFromEnum(inst)].un_op;3626 const un_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].un_op;
3629 const operand = try func.resolveInst(un_op);3627 const operand = try cg.resolveInst(un_op);
36303628
3631 try func.emitWValue(operand);3629 try cg.emitWValue(operand);
3632 const pt = func.pt;3630 const pt = cg.pt;
3633 const err_int_ty = try pt.errorIntType();3631 const err_int_ty = try pt.errorIntType();
3634 try func.addTag(.errors_len);3632 try cg.addTag(.errors_len);
3635 const result = try func.cmp(.stack, .stack, err_int_ty, .lt);3633 const result = try cg.cmp(.stack, .stack, err_int_ty, .lt);
36363634
3637 return func.finishAir(inst, result, &.{un_op});3635 return cg.finishAir(inst, result, &.{un_op});
3638}3636}
36393637
3640fn airBr(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {3638fn airBr(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
3641 const zcu = func.pt.zcu;3639 const zcu = cg.pt.zcu;
3642 const br = func.air.instructions.items(.data)[@intFromEnum(inst)].br;3640 const br = cg.air.instructions.items(.data)[@intFromEnum(inst)].br;
3643 const block = func.blocks.get(br.block_inst).?;3641 const block = cg.blocks.get(br.block_inst).?;
36443642
3645 // if operand has codegen bits we should break with a value3643 // if operand has codegen bits we should break with a value
3646 if (func.typeOf(br.operand).hasRuntimeBitsIgnoreComptime(zcu)) {3644 if (cg.typeOf(br.operand).hasRuntimeBitsIgnoreComptime(zcu)) {
3647 const operand = try func.resolveInst(br.operand);3645 const operand = try cg.resolveInst(br.operand);
3648 try func.lowerToStack(operand);3646 try cg.lowerToStack(operand);
36493647
3650 if (block.value != .none) {3648 if (block.value != .none) {
3651 try func.addLabel(.local_set, block.value.local.value);3649 try cg.addLabel(.local_set, block.value.local.value);
3652 }3650 }
3653 }3651 }
36543652
3655 // We map every block to its block index.3653 // We map every block to its block index.
3656 // We then determine how far we have to jump to it by subtracting it from current block depth3654 // We then determine how far we have to jump to it by subtracting it from current block depth
3657 const idx: u32 = func.block_depth - block.label;3655 const idx: u32 = cg.block_depth - block.label;
3658 try func.addLabel(.br, idx);3656 try cg.addLabel(.br, idx);
36593657
3660 return func.finishAir(inst, .none, &.{br.operand});3658 return cg.finishAir(inst, .none, &.{br.operand});
3661}3659}
36623660
3663fn airRepeat(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {3661fn airRepeat(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
3664 const repeat = func.air.instructions.items(.data)[@intFromEnum(inst)].repeat;3662 const repeat = cg.air.instructions.items(.data)[@intFromEnum(inst)].repeat;
3665 const loop_label = func.loops.get(repeat.loop_inst).?;3663 const loop_label = cg.loops.get(repeat.loop_inst).?;
36663664
3667 const idx: u32 = func.block_depth - loop_label;3665 const idx: u32 = cg.block_depth - loop_label;
3668 try func.addLabel(.br, idx);3666 try cg.addLabel(.br, idx);
36693667
3670 return func.finishAir(inst, .none, &.{});3668 return cg.finishAir(inst, .none, &.{});
3671}3669}
36723670
3673fn airNot(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {3671fn airNot(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
3674 const ty_op = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;3672 const ty_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
36753673
3676 const operand = try func.resolveInst(ty_op.operand);3674 const operand = try cg.resolveInst(ty_op.operand);
3677 const operand_ty = func.typeOf(ty_op.operand);3675 const operand_ty = cg.typeOf(ty_op.operand);
3678 const pt = func.pt;3676 const pt = cg.pt;
3679 const zcu = pt.zcu;3677 const zcu = pt.zcu;
36803678
3681 const result = result: {3679 const result = result: {
3682 if (operand_ty.zigTypeTag(zcu) == .bool) {3680 if (operand_ty.zigTypeTag(zcu) == .bool) {
3683 try func.emitWValue(operand);3681 try cg.emitWValue(operand);
3684 try func.addTag(.i32_eqz);3682 try cg.addTag(.i32_eqz);
3685 const not_tmp = try func.allocLocal(operand_ty);3683 const not_tmp = try cg.allocLocal(operand_ty);
3686 try func.addLabel(.local_set, not_tmp.local.value);3684 try cg.addLabel(.local_set, not_tmp.local.value);
3687 break :result not_tmp;3685 break :result not_tmp;
3688 } else {3686 } else {
3689 const int_info = operand_ty.intInfo(zcu);3687 const int_info = operand_ty.intInfo(zcu);
3690 const wasm_bits = toWasmBits(int_info.bits) orelse {3688 const wasm_bits = toWasmBits(int_info.bits) orelse {
3691 return func.fail("TODO: Implement binary NOT for {}", .{operand_ty.fmt(pt)});3689 return cg.fail("TODO: Implement binary NOT for {}", .{operand_ty.fmt(pt)});
3692 };3690 };
36933691
3694 switch (wasm_bits) {3692 switch (wasm_bits) {
3695 32 => {3693 32 => {
3696 try func.emitWValue(operand);3694 try cg.emitWValue(operand);
3697 try func.addImm32(switch (int_info.signedness) {3695 try cg.addImm32(switch (int_info.signedness) {
3698 .unsigned => ~@as(u32, 0) >> @intCast(32 - int_info.bits),3696 .unsigned => ~@as(u32, 0) >> @intCast(32 - int_info.bits),
3699 .signed => ~@as(u32, 0),3697 .signed => ~@as(u32, 0),
3700 });3698 });
3701 try func.addTag(.i32_xor);3699 try cg.addTag(.i32_xor);
3702 break :result .stack;3700 break :result .stack;
3703 },3701 },
3704 64 => {3702 64 => {
3705 try func.emitWValue(operand);3703 try cg.emitWValue(operand);
3706 try func.addImm64(switch (int_info.signedness) {3704 try cg.addImm64(switch (int_info.signedness) {
3707 .unsigned => ~@as(u64, 0) >> @intCast(64 - int_info.bits),3705 .unsigned => ~@as(u64, 0) >> @intCast(64 - int_info.bits),
3708 .signed => ~@as(u64, 0),3706 .signed => ~@as(u64, 0),
3709 });3707 });
3710 try func.addTag(.i64_xor);3708 try cg.addTag(.i64_xor);
3711 break :result .stack;3709 break :result .stack;
3712 },3710 },
3713 128 => {3711 128 => {
3714 const ptr = try func.allocStack(operand_ty);3712 const ptr = try cg.allocStack(operand_ty);
37153713
3716 try func.emitWValue(ptr);3714 try cg.emitWValue(ptr);
3717 _ = try func.load(operand, Type.u64, 0);3715 _ = try cg.load(operand, Type.u64, 0);
3718 try func.addImm64(~@as(u64, 0));3716 try cg.addImm64(~@as(u64, 0));
3719 try func.addTag(.i64_xor);3717 try cg.addTag(.i64_xor);
3720 try func.store(.stack, .stack, Type.u64, ptr.offset());3718 try cg.store(.stack, .stack, Type.u64, ptr.offset());
37213719
3722 try func.emitWValue(ptr);3720 try cg.emitWValue(ptr);
3723 _ = try func.load(operand, Type.u64, 8);3721 _ = try cg.load(operand, Type.u64, 8);
3724 try func.addImm64(switch (int_info.signedness) {3722 try cg.addImm64(switch (int_info.signedness) {
3725 .unsigned => ~@as(u64, 0) >> @intCast(128 - int_info.bits),3723 .unsigned => ~@as(u64, 0) >> @intCast(128 - int_info.bits),
3726 .signed => ~@as(u64, 0),3724 .signed => ~@as(u64, 0),
3727 });3725 });
3728 try func.addTag(.i64_xor);3726 try cg.addTag(.i64_xor);
3729 try func.store(.stack, .stack, Type.u64, ptr.offset() + 8);3727 try cg.store(.stack, .stack, Type.u64, ptr.offset() + 8);
37303728
3731 break :result ptr;3729 break :result ptr;
3732 },3730 },
...@@ -3734,33 +3732,33 @@ fn airNot(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -3734,33 +3732,33 @@ fn airNot(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
3734 }3732 }
3735 }3733 }
3736 };3734 };
3737 return func.finishAir(inst, result, &.{ty_op.operand});3735 return cg.finishAir(inst, result, &.{ty_op.operand});
3738}3736}
37393737
3740fn airTrap(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {3738fn airTrap(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
3741 try func.addTag(.@"unreachable");3739 try cg.addTag(.@"unreachable");
3742 return func.finishAir(inst, .none, &.{});3740 return cg.finishAir(inst, .none, &.{});
3743}3741}
37443742
3745fn airBreakpoint(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {3743fn airBreakpoint(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
3746 // unsupported by wasm itfunc. Can be implemented once we support DWARF3744 // unsupported by wasm itfunc. Can be implemented once we support DWARF
3747 // for wasm3745 // for wasm
3748 try func.addTag(.@"unreachable");3746 try cg.addTag(.@"unreachable");
3749 return func.finishAir(inst, .none, &.{});3747 return cg.finishAir(inst, .none, &.{});
3750}3748}
37513749
3752fn airUnreachable(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {3750fn airUnreachable(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
3753 try func.addTag(.@"unreachable");3751 try cg.addTag(.@"unreachable");
3754 return func.finishAir(inst, .none, &.{});3752 return cg.finishAir(inst, .none, &.{});
3755}3753}
37563754
3757fn airBitcast(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {3755fn airBitcast(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
3758 const pt = func.pt;3756 const pt = cg.pt;
3759 const zcu = pt.zcu;3757 const zcu = pt.zcu;
3760 const ty_op = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;3758 const ty_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
3761 const operand = try func.resolveInst(ty_op.operand);3759 const operand = try cg.resolveInst(ty_op.operand);
3762 const wanted_ty = func.typeOfIndex(inst);3760 const wanted_ty = cg.typeOfIndex(inst);
3763 const given_ty = func.typeOf(ty_op.operand);3761 const given_ty = cg.typeOf(ty_op.operand);
37643762
3765 const bit_size = given_ty.bitSize(zcu);3763 const bit_size = given_ty.bitSize(zcu);
3766 const needs_wrapping = (given_ty.isSignedInt(zcu) != wanted_ty.isSignedInt(zcu)) and3764 const needs_wrapping = (given_ty.isSignedInt(zcu) != wanted_ty.isSignedInt(zcu)) and
...@@ -3768,38 +3766,38 @@ fn airBitcast(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -3768,38 +3766,38 @@ fn airBitcast(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
37683766
3769 const result = result: {3767 const result = result: {
3770 if (given_ty.isAnyFloat() or wanted_ty.isAnyFloat()) {3768 if (given_ty.isAnyFloat() or wanted_ty.isAnyFloat()) {
3771 break :result try func.bitcast(wanted_ty, given_ty, operand);3769 break :result try cg.bitcast(wanted_ty, given_ty, operand);
3772 }3770 }
37733771
3774 if (isByRef(given_ty, pt, func.target) and !isByRef(wanted_ty, pt, func.target)) {3772 if (isByRef(given_ty, pt, cg.target) and !isByRef(wanted_ty, pt, cg.target)) {
3775 const loaded_memory = try func.load(operand, wanted_ty, 0);3773 const loaded_memory = try cg.load(operand, wanted_ty, 0);
3776 if (needs_wrapping) {3774 if (needs_wrapping) {
3777 break :result try func.wrapOperand(loaded_memory, wanted_ty);3775 break :result try cg.wrapOperand(loaded_memory, wanted_ty);
3778 } else {3776 } else {
3779 break :result loaded_memory;3777 break :result loaded_memory;
3780 }3778 }
3781 }3779 }
3782 if (!isByRef(given_ty, pt, func.target) and isByRef(wanted_ty, pt, func.target)) {3780 if (!isByRef(given_ty, pt, cg.target) and isByRef(wanted_ty, pt, cg.target)) {
3783 const stack_memory = try func.allocStack(wanted_ty);3781 const stack_memory = try cg.allocStack(wanted_ty);
3784 try func.store(stack_memory, operand, given_ty, 0);3782 try cg.store(stack_memory, operand, given_ty, 0);
3785 if (needs_wrapping) {3783 if (needs_wrapping) {
3786 break :result try func.wrapOperand(stack_memory, wanted_ty);3784 break :result try cg.wrapOperand(stack_memory, wanted_ty);
3787 } else {3785 } else {
3788 break :result stack_memory;3786 break :result stack_memory;
3789 }3787 }
3790 }3788 }
37913789
3792 if (needs_wrapping) {3790 if (needs_wrapping) {
3793 break :result try func.wrapOperand(operand, wanted_ty);3791 break :result try cg.wrapOperand(operand, wanted_ty);
3794 }3792 }
37953793
3796 break :result func.reuseOperand(ty_op.operand, operand);3794 break :result cg.reuseOperand(ty_op.operand, operand);
3797 };3795 };
3798 return func.finishAir(inst, result, &.{ty_op.operand});3796 return cg.finishAir(inst, result, &.{ty_op.operand});
3799}3797}
38003798
3801fn bitcast(func: *CodeGen, wanted_ty: Type, given_ty: Type, operand: WValue) InnerError!WValue {3799fn bitcast(cg: *CodeGen, wanted_ty: Type, given_ty: Type, operand: WValue) InnerError!WValue {
3802 const pt = func.pt;3800 const pt = cg.pt;
3803 const zcu = pt.zcu;3801 const zcu = pt.zcu;
3804 // if we bitcast a float to or from an integer we must use the 'reinterpret' instruction3802 // if we bitcast a float to or from an integer we must use the 'reinterpret' instruction
3805 if (!(wanted_ty.isAnyFloat() or given_ty.isAnyFloat())) return operand;3803 if (!(wanted_ty.isAnyFloat() or given_ty.isAnyFloat())) return operand;
...@@ -3809,41 +3807,41 @@ fn bitcast(func: *CodeGen, wanted_ty: Type, given_ty: Type, operand: WValue) Inn...@@ -3809,41 +3807,41 @@ fn bitcast(func: *CodeGen, wanted_ty: Type, given_ty: Type, operand: WValue) Inn
38093807
3810 const opcode = buildOpcode(.{3808 const opcode = buildOpcode(.{
3811 .op = .reinterpret,3809 .op = .reinterpret,
3812 .valtype1 = typeToValtype(wanted_ty, pt, func.target),3810 .valtype1 = typeToValtype(wanted_ty, pt, cg.target),
3813 .valtype2 = typeToValtype(given_ty, pt, func.target),3811 .valtype2 = typeToValtype(given_ty, pt, cg.target),
3814 });3812 });
3815 try func.emitWValue(operand);3813 try cg.emitWValue(operand);
3816 try func.addTag(Mir.Inst.Tag.fromOpcode(opcode));3814 try cg.addTag(Mir.Inst.Tag.fromOpcode(opcode));
3817 return .stack;3815 return .stack;
3818}3816}
38193817
3820fn airStructFieldPtr(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {3818fn airStructFieldPtr(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
3821 const pt = func.pt;3819 const pt = cg.pt;
3822 const zcu = pt.zcu;3820 const zcu = pt.zcu;
3823 const ty_pl = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;3821 const ty_pl = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
3824 const extra = func.air.extraData(Air.StructField, ty_pl.payload);3822 const extra = cg.air.extraData(Air.StructField, ty_pl.payload);
38253823
3826 const struct_ptr = try func.resolveInst(extra.data.struct_operand);3824 const struct_ptr = try cg.resolveInst(extra.data.struct_operand);
3827 const struct_ptr_ty = func.typeOf(extra.data.struct_operand);3825 const struct_ptr_ty = cg.typeOf(extra.data.struct_operand);
3828 const struct_ty = struct_ptr_ty.childType(zcu);3826 const struct_ty = struct_ptr_ty.childType(zcu);
3829 const result = try func.structFieldPtr(inst, extra.data.struct_operand, struct_ptr, struct_ptr_ty, struct_ty, extra.data.field_index);3827 const result = try cg.structFieldPtr(inst, extra.data.struct_operand, struct_ptr, struct_ptr_ty, struct_ty, extra.data.field_index);
3830 return func.finishAir(inst, result, &.{extra.data.struct_operand});3828 return cg.finishAir(inst, result, &.{extra.data.struct_operand});
3831}3829}
38323830
3833fn airStructFieldPtrIndex(func: *CodeGen, inst: Air.Inst.Index, index: u32) InnerError!void {3831fn airStructFieldPtrIndex(cg: *CodeGen, inst: Air.Inst.Index, index: u32) InnerError!void {
3834 const pt = func.pt;3832 const pt = cg.pt;
3835 const zcu = pt.zcu;3833 const zcu = pt.zcu;
3836 const ty_op = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;3834 const ty_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
3837 const struct_ptr = try func.resolveInst(ty_op.operand);3835 const struct_ptr = try cg.resolveInst(ty_op.operand);
3838 const struct_ptr_ty = func.typeOf(ty_op.operand);3836 const struct_ptr_ty = cg.typeOf(ty_op.operand);
3839 const struct_ty = struct_ptr_ty.childType(zcu);3837 const struct_ty = struct_ptr_ty.childType(zcu);
38403838
3841 const result = try func.structFieldPtr(inst, ty_op.operand, struct_ptr, struct_ptr_ty, struct_ty, index);3839 const result = try cg.structFieldPtr(inst, ty_op.operand, struct_ptr, struct_ptr_ty, struct_ty, index);
3842 return func.finishAir(inst, result, &.{ty_op.operand});3840 return cg.finishAir(inst, result, &.{ty_op.operand});
3843}3841}
38443842
3845fn structFieldPtr(3843fn structFieldPtr(
3846 func: *CodeGen,3844 cg: *CodeGen,
3847 inst: Air.Inst.Index,3845 inst: Air.Inst.Index,
3848 ref: Air.Inst.Ref,3846 ref: Air.Inst.Ref,
3849 struct_ptr: WValue,3847 struct_ptr: WValue,
...@@ -3851,9 +3849,9 @@ fn structFieldPtr(...@@ -3851,9 +3849,9 @@ fn structFieldPtr(
3851 struct_ty: Type,3849 struct_ty: Type,
3852 index: u32,3850 index: u32,
3853) InnerError!WValue {3851) InnerError!WValue {
3854 const pt = func.pt;3852 const pt = cg.pt;
3855 const zcu = pt.zcu;3853 const zcu = pt.zcu;
3856 const result_ty = func.typeOfIndex(inst);3854 const result_ty = cg.typeOfIndex(inst);
3857 const struct_ptr_ty_info = struct_ptr_ty.ptrInfo(zcu);3855 const struct_ptr_ty_info = struct_ptr_ty.ptrInfo(zcu);
38583856
3859 const offset = switch (struct_ty.containerLayout(zcu)) {3857 const offset = switch (struct_ty.containerLayout(zcu)) {
...@@ -3872,28 +3870,28 @@ fn structFieldPtr(...@@ -3872,28 +3870,28 @@ fn structFieldPtr(
3872 };3870 };
3873 // save a load and store when we can simply reuse the operand3871 // save a load and store when we can simply reuse the operand
3874 if (offset == 0) {3872 if (offset == 0) {
3875 return func.reuseOperand(ref, struct_ptr);3873 return cg.reuseOperand(ref, struct_ptr);
3876 }3874 }
3877 switch (struct_ptr) {3875 switch (struct_ptr) {
3878 .stack_offset => |stack_offset| {3876 .stack_offset => |stack_offset| {
3879 return .{ .stack_offset = .{ .value = stack_offset.value + @as(u32, @intCast(offset)), .references = 1 } };3877 return .{ .stack_offset = .{ .value = stack_offset.value + @as(u32, @intCast(offset)), .references = 1 } };
3880 },3878 },
3881 else => return func.buildPointerOffset(struct_ptr, offset, .new),3879 else => return cg.buildPointerOffset(struct_ptr, offset, .new),
3882 }3880 }
3883}3881}
38843882
3885fn airStructFieldVal(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {3883fn airStructFieldVal(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
3886 const pt = func.pt;3884 const pt = cg.pt;
3887 const zcu = pt.zcu;3885 const zcu = pt.zcu;
3888 const ip = &zcu.intern_pool;3886 const ip = &zcu.intern_pool;
3889 const ty_pl = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;3887 const ty_pl = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
3890 const struct_field = func.air.extraData(Air.StructField, ty_pl.payload).data;3888 const struct_field = cg.air.extraData(Air.StructField, ty_pl.payload).data;
38913889
3892 const struct_ty = func.typeOf(struct_field.struct_operand);3890 const struct_ty = cg.typeOf(struct_field.struct_operand);
3893 const operand = try func.resolveInst(struct_field.struct_operand);3891 const operand = try cg.resolveInst(struct_field.struct_operand);
3894 const field_index = struct_field.field_index;3892 const field_index = struct_field.field_index;
3895 const field_ty = struct_ty.fieldType(field_index, zcu);3893 const field_ty = struct_ty.fieldType(field_index, zcu);
3896 if (!field_ty.hasRuntimeBitsIgnoreComptime(zcu)) return func.finishAir(inst, .none, &.{struct_field.struct_operand});3894 if (!field_ty.hasRuntimeBitsIgnoreComptime(zcu)) return cg.finishAir(inst, .none, &.{struct_field.struct_operand});
38973895
3898 const result: WValue = switch (struct_ty.containerLayout(zcu)) {3896 const result: WValue = switch (struct_ty.containerLayout(zcu)) {
3899 .@"packed" => switch (struct_ty.zigTypeTag(zcu)) {3897 .@"packed" => switch (struct_ty.zigTypeTag(zcu)) {
...@@ -3902,42 +3900,42 @@ fn airStructFieldVal(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -3902,42 +3900,42 @@ fn airStructFieldVal(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
3902 const offset = pt.structPackedFieldBitOffset(packed_struct, field_index);3900 const offset = pt.structPackedFieldBitOffset(packed_struct, field_index);
3903 const backing_ty = Type.fromInterned(packed_struct.backingIntTypeUnordered(ip));3901 const backing_ty = Type.fromInterned(packed_struct.backingIntTypeUnordered(ip));
3904 const wasm_bits = toWasmBits(backing_ty.intInfo(zcu).bits) orelse {3902 const wasm_bits = toWasmBits(backing_ty.intInfo(zcu).bits) orelse {
3905 return func.fail("TODO: airStructFieldVal for packed structs larger than 128 bits", .{});3903 return cg.fail("TODO: airStructFieldVal for packed structs larger than 128 bits", .{});
3906 };3904 };
3907 const const_wvalue: WValue = if (wasm_bits == 32)3905 const const_wvalue: WValue = if (wasm_bits == 32)
3908 .{ .imm32 = offset }3906 .{ .imm32 = offset }
3909 else if (wasm_bits == 64)3907 else if (wasm_bits == 64)
3910 .{ .imm64 = offset }3908 .{ .imm64 = offset }
3911 else3909 else
3912 return func.fail("TODO: airStructFieldVal for packed structs larger than 64 bits", .{});3910 return cg.fail("TODO: airStructFieldVal for packed structs larger than 64 bits", .{});
39133911
3914 // for first field we don't require any shifting3912 // for first field we don't require any shifting
3915 const shifted_value = if (offset == 0)3913 const shifted_value = if (offset == 0)
3916 operand3914 operand
3917 else3915 else
3918 try func.binOp(operand, const_wvalue, backing_ty, .shr);3916 try cg.binOp(operand, const_wvalue, backing_ty, .shr);
39193917
3920 if (field_ty.zigTypeTag(zcu) == .float) {3918 if (field_ty.zigTypeTag(zcu) == .float) {
3921 const int_type = try pt.intType(.unsigned, @as(u16, @intCast(field_ty.bitSize(zcu))));3919 const int_type = try pt.intType(.unsigned, @as(u16, @intCast(field_ty.bitSize(zcu))));
3922 const truncated = try func.trunc(shifted_value, int_type, backing_ty);3920 const truncated = try cg.trunc(shifted_value, int_type, backing_ty);
3923 break :result try func.bitcast(field_ty, int_type, truncated);3921 break :result try cg.bitcast(field_ty, int_type, truncated);
3924 } else if (field_ty.isPtrAtRuntime(zcu) and packed_struct.field_types.len == 1) {3922 } else if (field_ty.isPtrAtRuntime(zcu) and packed_struct.field_types.len == 1) {
3925 // In this case we do not have to perform any transformations,3923 // In this case we do not have to perform any transformations,
3926 // we can simply reuse the operand.3924 // we can simply reuse the operand.
3927 break :result func.reuseOperand(struct_field.struct_operand, operand);3925 break :result cg.reuseOperand(struct_field.struct_operand, operand);
3928 } else if (field_ty.isPtrAtRuntime(zcu)) {3926 } else if (field_ty.isPtrAtRuntime(zcu)) {
3929 const int_type = try pt.intType(.unsigned, @as(u16, @intCast(field_ty.bitSize(zcu))));3927 const int_type = try pt.intType(.unsigned, @as(u16, @intCast(field_ty.bitSize(zcu))));
3930 break :result try func.trunc(shifted_value, int_type, backing_ty);3928 break :result try cg.trunc(shifted_value, int_type, backing_ty);
3931 }3929 }
3932 break :result try func.trunc(shifted_value, field_ty, backing_ty);3930 break :result try cg.trunc(shifted_value, field_ty, backing_ty);
3933 },3931 },
3934 .@"union" => result: {3932 .@"union" => result: {
3935 if (isByRef(struct_ty, pt, func.target)) {3933 if (isByRef(struct_ty, pt, cg.target)) {
3936 if (!isByRef(field_ty, pt, func.target)) {3934 if (!isByRef(field_ty, pt, cg.target)) {
3937 break :result try func.load(operand, field_ty, 0);3935 break :result try cg.load(operand, field_ty, 0);
3938 } else {3936 } else {
3939 const new_stack_val = try func.allocStack(field_ty);3937 const new_stack_val = try cg.allocStack(field_ty);
3940 try func.store(new_stack_val, operand, field_ty, 0);3938 try cg.store(new_stack_val, operand, field_ty, 0);
3941 break :result new_stack_val;3939 break :result new_stack_val;
3942 }3940 }
3943 }3941 }
...@@ -3945,45 +3943,45 @@ fn airStructFieldVal(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -3945,45 +3943,45 @@ fn airStructFieldVal(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
3945 const union_int_type = try pt.intType(.unsigned, @as(u16, @intCast(struct_ty.bitSize(zcu))));3943 const union_int_type = try pt.intType(.unsigned, @as(u16, @intCast(struct_ty.bitSize(zcu))));
3946 if (field_ty.zigTypeTag(zcu) == .float) {3944 if (field_ty.zigTypeTag(zcu) == .float) {
3947 const int_type = try pt.intType(.unsigned, @as(u16, @intCast(field_ty.bitSize(zcu))));3945 const int_type = try pt.intType(.unsigned, @as(u16, @intCast(field_ty.bitSize(zcu))));
3948 const truncated = try func.trunc(operand, int_type, union_int_type);3946 const truncated = try cg.trunc(operand, int_type, union_int_type);
3949 break :result try func.bitcast(field_ty, int_type, truncated);3947 break :result try cg.bitcast(field_ty, int_type, truncated);
3950 } else if (field_ty.isPtrAtRuntime(zcu)) {3948 } else if (field_ty.isPtrAtRuntime(zcu)) {
3951 const int_type = try pt.intType(.unsigned, @as(u16, @intCast(field_ty.bitSize(zcu))));3949 const int_type = try pt.intType(.unsigned, @as(u16, @intCast(field_ty.bitSize(zcu))));
3952 break :result try func.trunc(operand, int_type, union_int_type);3950 break :result try cg.trunc(operand, int_type, union_int_type);
3953 }3951 }
3954 break :result try func.trunc(operand, field_ty, union_int_type);3952 break :result try cg.trunc(operand, field_ty, union_int_type);
3955 },3953 },
3956 else => unreachable,3954 else => unreachable,
3957 },3955 },
3958 else => result: {3956 else => result: {
3959 const offset = std.math.cast(u32, struct_ty.structFieldOffset(field_index, zcu)) orelse {3957 const offset = std.math.cast(u32, struct_ty.structFieldOffset(field_index, zcu)) orelse {
3960 return func.fail("Field type '{}' too big to fit into stack frame", .{field_ty.fmt(pt)});3958 return cg.fail("Field type '{}' too big to fit into stack frame", .{field_ty.fmt(pt)});
3961 };3959 };
3962 if (isByRef(field_ty, pt, func.target)) {3960 if (isByRef(field_ty, pt, cg.target)) {
3963 switch (operand) {3961 switch (operand) {
3964 .stack_offset => |stack_offset| {3962 .stack_offset => |stack_offset| {
3965 break :result .{ .stack_offset = .{ .value = stack_offset.value + offset, .references = 1 } };3963 break :result .{ .stack_offset = .{ .value = stack_offset.value + offset, .references = 1 } };
3966 },3964 },
3967 else => break :result try func.buildPointerOffset(operand, offset, .new),3965 else => break :result try cg.buildPointerOffset(operand, offset, .new),
3968 }3966 }
3969 }3967 }
3970 break :result try func.load(operand, field_ty, offset);3968 break :result try cg.load(operand, field_ty, offset);
3971 },3969 },
3972 };3970 };
39733971
3974 return func.finishAir(inst, result, &.{struct_field.struct_operand});3972 return cg.finishAir(inst, result, &.{struct_field.struct_operand});
3975}3973}
39763974
3977fn airSwitchBr(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {3975fn airSwitchBr(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
3978 const pt = func.pt;3976 const pt = cg.pt;
3979 const zcu = pt.zcu;3977 const zcu = pt.zcu;
3980 // result type is always 'noreturn'3978 // result type is always 'noreturn'
3981 const blocktype = std.wasm.block_empty;3979 const blocktype = std.wasm.block_empty;
3982 const switch_br = func.air.unwrapSwitch(inst);3980 const switch_br = cg.air.unwrapSwitch(inst);
3983 const target = try func.resolveInst(switch_br.operand);3981 const target = try cg.resolveInst(switch_br.operand);
3984 const target_ty = func.typeOf(switch_br.operand);3982 const target_ty = cg.typeOf(switch_br.operand);
3985 const liveness = try func.liveness.getSwitchBr(func.gpa, inst, switch_br.cases_len + 1);3983 const liveness = try cg.liveness.getSwitchBr(cg.gpa, inst, switch_br.cases_len + 1);
3986 defer func.gpa.free(liveness.deaths);3984 defer cg.gpa.free(liveness.deaths);
39873985
3988 // a list that maps each value with its value and body based on the order inside the list.3986 // a list that maps each value with its value and body based on the order inside the list.
3989 const CaseValue = union(enum) {3987 const CaseValue = union(enum) {
...@@ -3993,21 +3991,21 @@ fn airSwitchBr(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -3993,21 +3991,21 @@ fn airSwitchBr(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
3993 var case_list = try std.ArrayList(struct {3991 var case_list = try std.ArrayList(struct {
3994 values: []const CaseValue,3992 values: []const CaseValue,
3995 body: []const Air.Inst.Index,3993 body: []const Air.Inst.Index,
3996 }).initCapacity(func.gpa, switch_br.cases_len);3994 }).initCapacity(cg.gpa, switch_br.cases_len);
3997 defer for (case_list.items) |case| {3995 defer for (case_list.items) |case| {
3998 func.gpa.free(case.values);3996 cg.gpa.free(case.values);
3999 } else case_list.deinit();3997 } else case_list.deinit();
40003998
4001 var lowest_maybe: ?i32 = null;3999 var lowest_maybe: ?i32 = null;
4002 var highest_maybe: ?i32 = null;4000 var highest_maybe: ?i32 = null;
4003 var it = switch_br.iterateCases();4001 var it = switch_br.iterateCases();
4004 while (it.next()) |case| {4002 while (it.next()) |case| {
4005 const values = try func.gpa.alloc(CaseValue, case.items.len + case.ranges.len);4003 const values = try cg.gpa.alloc(CaseValue, case.items.len + case.ranges.len);
4006 errdefer func.gpa.free(values);4004 errdefer cg.gpa.free(values);
40074005
4008 for (case.items, 0..) |ref, i| {4006 for (case.items, 0..) |ref, i| {
4009 const item_val = (try func.air.value(ref, pt)).?;4007 const item_val = (try cg.air.value(ref, pt)).?;
4010 const int_val = func.valueAsI32(item_val);4008 const int_val = cg.valueAsI32(item_val);
4011 if (lowest_maybe == null or int_val < lowest_maybe.?) {4009 if (lowest_maybe == null or int_val < lowest_maybe.?) {
4012 lowest_maybe = int_val;4010 lowest_maybe = int_val;
4013 }4011 }
...@@ -4018,15 +4016,15 @@ fn airSwitchBr(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -4018,15 +4016,15 @@ fn airSwitchBr(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
4018 }4016 }
40194017
4020 for (case.ranges, 0..) |range, i| {4018 for (case.ranges, 0..) |range, i| {
4021 const min_val = (try func.air.value(range[0], pt)).?;4019 const min_val = (try cg.air.value(range[0], pt)).?;
4022 const int_min_val = func.valueAsI32(min_val);4020 const int_min_val = cg.valueAsI32(min_val);
40234021
4024 if (lowest_maybe == null or int_min_val < lowest_maybe.?) {4022 if (lowest_maybe == null or int_min_val < lowest_maybe.?) {
4025 lowest_maybe = int_min_val;4023 lowest_maybe = int_min_val;
4026 }4024 }
40274025
4028 const max_val = (try func.air.value(range[1], pt)).?;4026 const max_val = (try cg.air.value(range[1], pt)).?;
4029 const int_max_val = func.valueAsI32(max_val);4027 const int_max_val = cg.valueAsI32(max_val);
40304028
4031 if (highest_maybe == null or int_max_val > highest_maybe.?) {4029 if (highest_maybe == null or int_max_val > highest_maybe.?) {
4032 highest_maybe = int_max_val;4030 highest_maybe = int_max_val;
...@@ -4041,7 +4039,7 @@ fn airSwitchBr(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -4041,7 +4039,7 @@ fn airSwitchBr(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
4041 }4039 }
40424040
4043 case_list.appendAssumeCapacity(.{ .values = values, .body = case.body });4041 case_list.appendAssumeCapacity(.{ .values = values, .body = case.body });
4044 try func.startBlock(.block, blocktype);4042 try cg.startBlock(.block, blocktype);
4045 }4043 }
40464044
4047 // When highest and lowest are null, we have no cases and can use a jump table4045 // When highest and lowest are null, we have no cases and can use a jump table
...@@ -4057,7 +4055,7 @@ fn airSwitchBr(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -4057,7 +4055,7 @@ fn airSwitchBr(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
4057 const else_body = it.elseBody();4055 const else_body = it.elseBody();
4058 const has_else_body = else_body.len != 0;4056 const has_else_body = else_body.len != 0;
4059 if (has_else_body) {4057 if (has_else_body) {
4060 try func.startBlock(.block, blocktype);4058 try cg.startBlock(.block, blocktype);
4061 }4059 }
40624060
4063 if (!is_sparse) {4061 if (!is_sparse) {
...@@ -4065,25 +4063,25 @@ fn airSwitchBr(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -4065,25 +4063,25 @@ fn airSwitchBr(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
4065 // The value 'target' represents the index into the table.4063 // The value 'target' represents the index into the table.
4066 // Each index in the table represents a label to the branch4064 // Each index in the table represents a label to the branch
4067 // to jump to.4065 // to jump to.
4068 try func.startBlock(.block, blocktype);4066 try cg.startBlock(.block, blocktype);
4069 try func.emitWValue(target);4067 try cg.emitWValue(target);
4070 if (lowest < 0) {4068 if (lowest < 0) {
4071 // since br_table works using indexes, starting from '0', we must ensure all values4069 // since br_table works using indexes, starting from '0', we must ensure all values
4072 // we put inside, are atleast 0.4070 // we put inside, are atleast 0.
4073 try func.addImm32(@bitCast(lowest * -1));4071 try cg.addImm32(@bitCast(lowest * -1));
4074 try func.addTag(.i32_add);4072 try cg.addTag(.i32_add);
4075 } else if (lowest > 0) {4073 } else if (lowest > 0) {
4076 // make the index start from 0 by substracting the lowest value4074 // make the index start from 0 by substracting the lowest value
4077 try func.addImm32(@bitCast(lowest));4075 try cg.addImm32(@bitCast(lowest));
4078 try func.addTag(.i32_sub);4076 try cg.addTag(.i32_sub);
4079 }4077 }
40804078
4081 // Account for default branch so always add '1'4079 // Account for default branch so always add '1'
4082 const depth = @as(u32, @intCast(highest - lowest + @intFromBool(has_else_body))) + 1;4080 const depth = @as(u32, @intCast(highest - lowest + @intFromBool(has_else_body))) + 1;
4083 const jump_table: Mir.JumpTable = .{ .length = depth };4081 const jump_table: Mir.JumpTable = .{ .length = depth };
4084 const table_extra_index = try func.addExtra(jump_table);4082 const table_extra_index = try cg.addExtra(jump_table);
4085 try func.addInst(.{ .tag = .br_table, .data = .{ .payload = table_extra_index } });4083 try cg.addInst(.{ .tag = .br_table, .data = .{ .payload = table_extra_index } });
4086 try func.mir_extra.ensureUnusedCapacity(func.gpa, depth);4084 try cg.mir_extra.ensureUnusedCapacity(cg.gpa, depth);
4087 var value = lowest;4085 var value = lowest;
4088 while (value <= highest) : (value += 1) {4086 while (value <= highest) : (value += 1) {
4089 // idx represents the branch we jump to4087 // idx represents the branch we jump to
...@@ -4104,78 +4102,78 @@ fn airSwitchBr(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -4104,78 +4102,78 @@ fn airSwitchBr(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
4104 // by using a jump table for this instead of if-else chains.4102 // by using a jump table for this instead of if-else chains.
4105 break :blk if (has_else_body or target_ty.zigTypeTag(zcu) == .error_set) switch_br.cases_len else unreachable;4103 break :blk if (has_else_body or target_ty.zigTypeTag(zcu) == .error_set) switch_br.cases_len else unreachable;
4106 };4104 };
4107 func.mir_extra.appendAssumeCapacity(idx);4105 cg.mir_extra.appendAssumeCapacity(idx);
4108 } else if (has_else_body) {4106 } else if (has_else_body) {
4109 func.mir_extra.appendAssumeCapacity(switch_br.cases_len); // default branch4107 cg.mir_extra.appendAssumeCapacity(switch_br.cases_len); // default branch
4110 }4108 }
4111 try func.endBlock();4109 try cg.endBlock();
4112 }4110 }
41134111
4114 try func.branches.ensureUnusedCapacity(func.gpa, case_list.items.len + @intFromBool(has_else_body));4112 try cg.branches.ensureUnusedCapacity(cg.gpa, case_list.items.len + @intFromBool(has_else_body));
4115 for (case_list.items, 0..) |case, index| {4113 for (case_list.items, 0..) |case, index| {
4116 // when sparse, we use if/else-chain, so emit conditional checks4114 // when sparse, we use if/else-chain, so emit conditional checks
4117 if (is_sparse) {4115 if (is_sparse) {
4118 // for single value prong we can emit a simple condition4116 // for single value prong we can emit a simple condition
4119 if (case.values.len == 1 and case.values[0] == .singular) {4117 if (case.values.len == 1 and case.values[0] == .singular) {
4120 const val = try func.lowerConstant(case.values[0].singular.value, target_ty);4118 const val = try cg.lowerConstant(case.values[0].singular.value, target_ty);
4121 // not equal, because we want to jump out of this block if it does not match the condition.4119 // not equal, because we want to jump out of this block if it does not match the condition.
4122 _ = try func.cmp(target, val, target_ty, .neq);4120 _ = try cg.cmp(target, val, target_ty, .neq);
4123 try func.addLabel(.br_if, 0);4121 try cg.addLabel(.br_if, 0);
4124 } else {4122 } else {
4125 // in multi-value prongs we must check if any prongs match the target value.4123 // in multi-value prongs we must check if any prongs match the target value.
4126 try func.startBlock(.block, blocktype);4124 try cg.startBlock(.block, blocktype);
4127 for (case.values) |value| {4125 for (case.values) |value| {
4128 switch (value) {4126 switch (value) {
4129 .singular => |single_val| {4127 .singular => |single_val| {
4130 const val = try func.lowerConstant(single_val.value, target_ty);4128 const val = try cg.lowerConstant(single_val.value, target_ty);
4131 _ = try func.cmp(target, val, target_ty, .eq);4129 _ = try cg.cmp(target, val, target_ty, .eq);
4132 },4130 },
4133 .range => |range| {4131 .range => |range| {
4134 const min_val = try func.lowerConstant(range.min_value, target_ty);4132 const min_val = try cg.lowerConstant(range.min_value, target_ty);
4135 const max_val = try func.lowerConstant(range.max_value, target_ty);4133 const max_val = try cg.lowerConstant(range.max_value, target_ty);
41364134
4137 const gte = try func.cmp(target, min_val, target_ty, .gte);4135 const gte = try cg.cmp(target, min_val, target_ty, .gte);
4138 const lte = try func.cmp(target, max_val, target_ty, .lte);4136 const lte = try cg.cmp(target, max_val, target_ty, .lte);
4139 _ = try func.binOp(gte, lte, Type.bool, .@"and");4137 _ = try cg.binOp(gte, lte, Type.bool, .@"and");
4140 },4138 },
4141 }4139 }
4142 try func.addLabel(.br_if, 0);4140 try cg.addLabel(.br_if, 0);
4143 }4141 }
4144 // value did not match any of the prong values4142 // value did not match any of the prong values
4145 try func.addLabel(.br, 1);4143 try cg.addLabel(.br, 1);
4146 try func.endBlock();4144 try cg.endBlock();
4147 }4145 }
4148 }4146 }
4149 func.branches.appendAssumeCapacity(.{});4147 cg.branches.appendAssumeCapacity(.{});
4150 try func.currentBranch().values.ensureUnusedCapacity(func.gpa, liveness.deaths[index].len);4148 try cg.currentBranch().values.ensureUnusedCapacity(cg.gpa, liveness.deaths[index].len);
4151 defer {4149 defer {
4152 var case_branch = func.branches.pop();4150 var case_branch = cg.branches.pop();
4153 case_branch.deinit(func.gpa);4151 case_branch.deinit(cg.gpa);
4154 }4152 }
4155 try func.genBody(case.body);4153 try cg.genBody(case.body);
4156 try func.endBlock();4154 try cg.endBlock();
4157 }4155 }
41584156
4159 if (has_else_body) {4157 if (has_else_body) {
4160 func.branches.appendAssumeCapacity(.{});4158 cg.branches.appendAssumeCapacity(.{});
4161 const else_deaths = liveness.deaths.len - 1;4159 const else_deaths = liveness.deaths.len - 1;
4162 try func.currentBranch().values.ensureUnusedCapacity(func.gpa, liveness.deaths[else_deaths].len);4160 try cg.currentBranch().values.ensureUnusedCapacity(cg.gpa, liveness.deaths[else_deaths].len);
4163 defer {4161 defer {
4164 var else_branch = func.branches.pop();4162 var else_branch = cg.branches.pop();
4165 else_branch.deinit(func.gpa);4163 else_branch.deinit(cg.gpa);
4166 }4164 }
4167 try func.genBody(else_body);4165 try cg.genBody(else_body);
4168 try func.endBlock();4166 try cg.endBlock();
4169 }4167 }
4170 return func.finishAir(inst, .none, &.{});4168 return cg.finishAir(inst, .none, &.{});
4171}4169}
41724170
4173fn airIsErr(func: *CodeGen, inst: Air.Inst.Index, opcode: std.wasm.Opcode) InnerError!void {4171fn airIsErr(cg: *CodeGen, inst: Air.Inst.Index, opcode: std.wasm.Opcode) InnerError!void {
4174 const pt = func.pt;4172 const pt = cg.pt;
4175 const zcu = pt.zcu;4173 const zcu = pt.zcu;
4176 const un_op = func.air.instructions.items(.data)[@intFromEnum(inst)].un_op;4174 const un_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].un_op;
4177 const operand = try func.resolveInst(un_op);4175 const operand = try cg.resolveInst(un_op);
4178 const err_union_ty = func.typeOf(un_op);4176 const err_union_ty = cg.typeOf(un_op);
4179 const pl_ty = err_union_ty.errorUnionPayload(zcu);4177 const pl_ty = err_union_ty.errorUnionPayload(zcu);
41804178
4181 const result: WValue = result: {4179 const result: WValue = result: {
...@@ -4187,57 +4185,57 @@ fn airIsErr(func: *CodeGen, inst: Air.Inst.Index, opcode: std.wasm.Opcode) Inner...@@ -4187,57 +4185,57 @@ fn airIsErr(func: *CodeGen, inst: Air.Inst.Index, opcode: std.wasm.Opcode) Inner
4187 }4185 }
4188 }4186 }
41894187
4190 try func.emitWValue(operand);4188 try cg.emitWValue(operand);
4191 if (pl_ty.hasRuntimeBitsIgnoreComptime(zcu)) {4189 if (pl_ty.hasRuntimeBitsIgnoreComptime(zcu)) {
4192 try func.addMemArg(.i32_load16_u, .{4190 try cg.addMemArg(.i32_load16_u, .{
4193 .offset = operand.offset() + @as(u32, @intCast(errUnionErrorOffset(pl_ty, zcu))),4191 .offset = operand.offset() + @as(u32, @intCast(errUnionErrorOffset(pl_ty, zcu))),
4194 .alignment = @intCast(Type.anyerror.abiAlignment(zcu).toByteUnits().?),4192 .alignment = @intCast(Type.anyerror.abiAlignment(zcu).toByteUnits().?),
4195 });4193 });
4196 }4194 }
41974195
4198 // Compare the error value with '0'4196 // Compare the error value with '0'
4199 try func.addImm32(0);4197 try cg.addImm32(0);
4200 try func.addTag(Mir.Inst.Tag.fromOpcode(opcode));4198 try cg.addTag(Mir.Inst.Tag.fromOpcode(opcode));
4201 break :result .stack;4199 break :result .stack;
4202 };4200 };
4203 return func.finishAir(inst, result, &.{un_op});4201 return cg.finishAir(inst, result, &.{un_op});
4204}4202}
42054203
4206fn airUnwrapErrUnionPayload(func: *CodeGen, inst: Air.Inst.Index, op_is_ptr: bool) InnerError!void {4204fn airUnwrapErrUnionPayload(cg: *CodeGen, inst: Air.Inst.Index, op_is_ptr: bool) InnerError!void {
4207 const pt = func.pt;4205 const pt = cg.pt;
4208 const zcu = pt.zcu;4206 const zcu = pt.zcu;
4209 const ty_op = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;4207 const ty_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
42104208
4211 const operand = try func.resolveInst(ty_op.operand);4209 const operand = try cg.resolveInst(ty_op.operand);
4212 const op_ty = func.typeOf(ty_op.operand);4210 const op_ty = cg.typeOf(ty_op.operand);
4213 const err_ty = if (op_is_ptr) op_ty.childType(zcu) else op_ty;4211 const err_ty = if (op_is_ptr) op_ty.childType(zcu) else op_ty;
4214 const payload_ty = err_ty.errorUnionPayload(zcu);4212 const payload_ty = err_ty.errorUnionPayload(zcu);
42154213
4216 const result: WValue = result: {4214 const result: WValue = result: {
4217 if (!payload_ty.hasRuntimeBitsIgnoreComptime(zcu)) {4215 if (!payload_ty.hasRuntimeBitsIgnoreComptime(zcu)) {
4218 if (op_is_ptr) {4216 if (op_is_ptr) {
4219 break :result func.reuseOperand(ty_op.operand, operand);4217 break :result cg.reuseOperand(ty_op.operand, operand);
4220 }4218 }
4221 break :result .none;4219 break :result .none;
4222 }4220 }
42234221
4224 const pl_offset = @as(u32, @intCast(errUnionPayloadOffset(payload_ty, zcu)));4222 const pl_offset = @as(u32, @intCast(errUnionPayloadOffset(payload_ty, zcu)));
4225 if (op_is_ptr or isByRef(payload_ty, pt, func.target)) {4223 if (op_is_ptr or isByRef(payload_ty, pt, cg.target)) {
4226 break :result try func.buildPointerOffset(operand, pl_offset, .new);4224 break :result try cg.buildPointerOffset(operand, pl_offset, .new);
4227 }4225 }
42284226
4229 break :result try func.load(operand, payload_ty, pl_offset);4227 break :result try cg.load(operand, payload_ty, pl_offset);
4230 };4228 };
4231 return func.finishAir(inst, result, &.{ty_op.operand});4229 return cg.finishAir(inst, result, &.{ty_op.operand});
4232}4230}
42334231
4234fn airUnwrapErrUnionError(func: *CodeGen, inst: Air.Inst.Index, op_is_ptr: bool) InnerError!void {4232fn airUnwrapErrUnionError(cg: *CodeGen, inst: Air.Inst.Index, op_is_ptr: bool) InnerError!void {
4235 const pt = func.pt;4233 const pt = cg.pt;
4236 const zcu = pt.zcu;4234 const zcu = pt.zcu;
4237 const ty_op = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;4235 const ty_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
42384236
4239 const operand = try func.resolveInst(ty_op.operand);4237 const operand = try cg.resolveInst(ty_op.operand);
4240 const op_ty = func.typeOf(ty_op.operand);4238 const op_ty = cg.typeOf(ty_op.operand);
4241 const err_ty = if (op_is_ptr) op_ty.childType(zcu) else op_ty;4239 const err_ty = if (op_is_ptr) op_ty.childType(zcu) else op_ty;
4242 const payload_ty = err_ty.errorUnionPayload(zcu);4240 const payload_ty = err_ty.errorUnionPayload(zcu);
42434241
...@@ -4247,103 +4245,103 @@ fn airUnwrapErrUnionError(func: *CodeGen, inst: Air.Inst.Index, op_is_ptr: bool)...@@ -4247,103 +4245,103 @@ fn airUnwrapErrUnionError(func: *CodeGen, inst: Air.Inst.Index, op_is_ptr: bool)
4247 }4245 }
42484246
4249 if (op_is_ptr or !payload_ty.hasRuntimeBitsIgnoreComptime(zcu)) {4247 if (op_is_ptr or !payload_ty.hasRuntimeBitsIgnoreComptime(zcu)) {
4250 break :result func.reuseOperand(ty_op.operand, operand);4248 break :result cg.reuseOperand(ty_op.operand, operand);
4251 }4249 }
42524250
4253 break :result try func.load(operand, Type.anyerror, @intCast(errUnionErrorOffset(payload_ty, zcu)));4251 break :result try cg.load(operand, Type.anyerror, @intCast(errUnionErrorOffset(payload_ty, zcu)));
4254 };4252 };
4255 return func.finishAir(inst, result, &.{ty_op.operand});4253 return cg.finishAir(inst, result, &.{ty_op.operand});
4256}4254}
42574255
4258fn airWrapErrUnionPayload(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {4256fn airWrapErrUnionPayload(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
4259 const zcu = func.pt.zcu;4257 const zcu = cg.pt.zcu;
4260 const ty_op = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;4258 const ty_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
42614259
4262 const operand = try func.resolveInst(ty_op.operand);4260 const operand = try cg.resolveInst(ty_op.operand);
4263 const err_ty = func.typeOfIndex(inst);4261 const err_ty = cg.typeOfIndex(inst);
42644262
4265 const pl_ty = func.typeOf(ty_op.operand);4263 const pl_ty = cg.typeOf(ty_op.operand);
4266 const result = result: {4264 const result = result: {
4267 if (!pl_ty.hasRuntimeBitsIgnoreComptime(zcu)) {4265 if (!pl_ty.hasRuntimeBitsIgnoreComptime(zcu)) {
4268 break :result func.reuseOperand(ty_op.operand, operand);4266 break :result cg.reuseOperand(ty_op.operand, operand);
4269 }4267 }
42704268
4271 const err_union = try func.allocStack(err_ty);4269 const err_union = try cg.allocStack(err_ty);
4272 const payload_ptr = try func.buildPointerOffset(err_union, @as(u32, @intCast(errUnionPayloadOffset(pl_ty, zcu))), .new);4270 const payload_ptr = try cg.buildPointerOffset(err_union, @as(u32, @intCast(errUnionPayloadOffset(pl_ty, zcu))), .new);
4273 try func.store(payload_ptr, operand, pl_ty, 0);4271 try cg.store(payload_ptr, operand, pl_ty, 0);
42744272
4275 // ensure we also write '0' to the error part, so any present stack value gets overwritten by it.4273 // ensure we also write '0' to the error part, so any present stack value gets overwritten by it.
4276 try func.emitWValue(err_union);4274 try cg.emitWValue(err_union);
4277 try func.addImm32(0);4275 try cg.addImm32(0);
4278 const err_val_offset: u32 = @intCast(errUnionErrorOffset(pl_ty, zcu));4276 const err_val_offset: u32 = @intCast(errUnionErrorOffset(pl_ty, zcu));
4279 try func.addMemArg(.i32_store16, .{4277 try cg.addMemArg(.i32_store16, .{
4280 .offset = err_union.offset() + err_val_offset,4278 .offset = err_union.offset() + err_val_offset,
4281 .alignment = 2,4279 .alignment = 2,
4282 });4280 });
4283 break :result err_union;4281 break :result err_union;
4284 };4282 };
4285 return func.finishAir(inst, result, &.{ty_op.operand});4283 return cg.finishAir(inst, result, &.{ty_op.operand});
4286}4284}
42874285
4288fn airWrapErrUnionErr(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {4286fn airWrapErrUnionErr(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
4289 const pt = func.pt;4287 const pt = cg.pt;
4290 const zcu = pt.zcu;4288 const zcu = pt.zcu;
4291 const ty_op = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;4289 const ty_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
42924290
4293 const operand = try func.resolveInst(ty_op.operand);4291 const operand = try cg.resolveInst(ty_op.operand);
4294 const err_ty = ty_op.ty.toType();4292 const err_ty = ty_op.ty.toType();
4295 const pl_ty = err_ty.errorUnionPayload(zcu);4293 const pl_ty = err_ty.errorUnionPayload(zcu);
42964294
4297 const result = result: {4295 const result = result: {
4298 if (!pl_ty.hasRuntimeBitsIgnoreComptime(zcu)) {4296 if (!pl_ty.hasRuntimeBitsIgnoreComptime(zcu)) {
4299 break :result func.reuseOperand(ty_op.operand, operand);4297 break :result cg.reuseOperand(ty_op.operand, operand);
4300 }4298 }
43014299
4302 const err_union = try func.allocStack(err_ty);4300 const err_union = try cg.allocStack(err_ty);
4303 // store error value4301 // store error value
4304 try func.store(err_union, operand, Type.anyerror, @intCast(errUnionErrorOffset(pl_ty, zcu)));4302 try cg.store(err_union, operand, Type.anyerror, @intCast(errUnionErrorOffset(pl_ty, zcu)));
43054303
4306 // write 'undefined' to the payload4304 // write 'undefined' to the payload
4307 const payload_ptr = try func.buildPointerOffset(err_union, @as(u32, @intCast(errUnionPayloadOffset(pl_ty, zcu))), .new);4305 const payload_ptr = try cg.buildPointerOffset(err_union, @as(u32, @intCast(errUnionPayloadOffset(pl_ty, zcu))), .new);
4308 const len = @as(u32, @intCast(err_ty.errorUnionPayload(zcu).abiSize(zcu)));4306 const len = @as(u32, @intCast(err_ty.errorUnionPayload(zcu).abiSize(zcu)));
4309 try func.memset(Type.u8, payload_ptr, .{ .imm32 = len }, .{ .imm32 = 0xaa });4307 try cg.memset(Type.u8, payload_ptr, .{ .imm32 = len }, .{ .imm32 = 0xaa });
43104308
4311 break :result err_union;4309 break :result err_union;
4312 };4310 };
4313 return func.finishAir(inst, result, &.{ty_op.operand});4311 return cg.finishAir(inst, result, &.{ty_op.operand});
4314}4312}
43154313
4316fn airIntcast(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {4314fn airIntcast(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
4317 const ty_op = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;4315 const ty_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
43184316
4319 const ty = ty_op.ty.toType();4317 const ty = ty_op.ty.toType();
4320 const operand = try func.resolveInst(ty_op.operand);4318 const operand = try cg.resolveInst(ty_op.operand);
4321 const operand_ty = func.typeOf(ty_op.operand);4319 const operand_ty = cg.typeOf(ty_op.operand);
4322 const pt = func.pt;4320 const pt = cg.pt;
4323 const zcu = pt.zcu;4321 const zcu = pt.zcu;
4324 if (ty.zigTypeTag(zcu) == .vector or operand_ty.zigTypeTag(zcu) == .vector) {4322 if (ty.zigTypeTag(zcu) == .vector or operand_ty.zigTypeTag(zcu) == .vector) {
4325 return func.fail("todo Wasm intcast for vectors", .{});4323 return cg.fail("todo Wasm intcast for vectors", .{});
4326 }4324 }
4327 if (ty.abiSize(zcu) > 16 or operand_ty.abiSize(zcu) > 16) {4325 if (ty.abiSize(zcu) > 16 or operand_ty.abiSize(zcu) > 16) {
4328 return func.fail("todo Wasm intcast for bitsize > 128", .{});4326 return cg.fail("todo Wasm intcast for bitsize > 128", .{});
4329 }4327 }
43304328
4331 const op_bits = toWasmBits(@intCast(operand_ty.bitSize(zcu))).?;4329 const op_bits = toWasmBits(@intCast(operand_ty.bitSize(zcu))).?;
4332 const wanted_bits = toWasmBits(@intCast(ty.bitSize(zcu))).?;4330 const wanted_bits = toWasmBits(@intCast(ty.bitSize(zcu))).?;
4333 const result = if (op_bits == wanted_bits)4331 const result = if (op_bits == wanted_bits)
4334 func.reuseOperand(ty_op.operand, operand)4332 cg.reuseOperand(ty_op.operand, operand)
4335 else4333 else
4336 try func.intcast(operand, operand_ty, ty);4334 try cg.intcast(operand, operand_ty, ty);
43374335
4338 return func.finishAir(inst, result, &.{ty_op.operand});4336 return cg.finishAir(inst, result, &.{ty_op.operand});
4339}4337}
43404338
4341/// Upcasts or downcasts an integer based on the given and wanted types,4339/// Upcasts or downcasts an integer based on the given and wanted types,
4342/// and stores the result in a new operand.4340/// and stores the result in a new operand.
4343/// Asserts type's bitsize <= 1284341/// Asserts type's bitsize <= 128
4344/// NOTE: May leave the result on the top of the stack.4342/// NOTE: May leave the result on the top of the stack.
4345fn intcast(func: *CodeGen, operand: WValue, given: Type, wanted: Type) InnerError!WValue {4343fn intcast(cg: *CodeGen, operand: WValue, given: Type, wanted: Type) InnerError!WValue {
4346 const pt = func.pt;4344 const pt = cg.pt;
4347 const zcu = pt.zcu;4345 const zcu = pt.zcu;
4348 const given_bitsize = @as(u16, @intCast(given.bitSize(zcu)));4346 const given_bitsize = @as(u16, @intCast(given.bitSize(zcu)));
4349 const wanted_bitsize = @as(u16, @intCast(wanted.bitSize(zcu)));4347 const wanted_bitsize = @as(u16, @intCast(wanted.bitSize(zcu)));
...@@ -4357,469 +4355,469 @@ fn intcast(func: *CodeGen, operand: WValue, given: Type, wanted: Type) InnerErro...@@ -4357,469 +4355,469 @@ fn intcast(func: *CodeGen, operand: WValue, given: Type, wanted: Type) InnerErro
4357 }4355 }
43584356
4359 if (op_bits == 64 and wanted_bits == 32) {4357 if (op_bits == 64 and wanted_bits == 32) {
4360 try func.emitWValue(operand);4358 try cg.emitWValue(operand);
4361 try func.addTag(.i32_wrap_i64);4359 try cg.addTag(.i32_wrap_i64);
4362 return .stack;4360 return .stack;
4363 } else if (op_bits == 32 and wanted_bits == 64) {4361 } else if (op_bits == 32 and wanted_bits == 64) {
4364 try func.emitWValue(operand);4362 try cg.emitWValue(operand);
4365 try func.addTag(if (wanted.isSignedInt(zcu)) .i64_extend_i32_s else .i64_extend_i32_u);4363 try cg.addTag(if (wanted.isSignedInt(zcu)) .i64_extend_i32_s else .i64_extend_i32_u);
4366 return .stack;4364 return .stack;
4367 } else if (wanted_bits == 128) {4365 } else if (wanted_bits == 128) {
4368 // for 128bit integers we store the integer in the virtual stack, rather than a local4366 // for 128bit integers we store the integer in the virtual stack, rather than a local
4369 const stack_ptr = try func.allocStack(wanted);4367 const stack_ptr = try cg.allocStack(wanted);
4370 try func.emitWValue(stack_ptr);4368 try cg.emitWValue(stack_ptr);
43714369
4372 // for 32 bit integers, we first coerce the value into a 64 bit integer before storing it4370 // for 32 bit integers, we first coerce the value into a 64 bit integer before storing it
4373 // meaning less store operations are required.4371 // meaning less store operations are required.
4374 const lhs = if (op_bits == 32) blk: {4372 const lhs = if (op_bits == 32) blk: {
4375 const sign_ty = if (wanted.isSignedInt(zcu)) Type.i64 else Type.u64;4373 const sign_ty = if (wanted.isSignedInt(zcu)) Type.i64 else Type.u64;
4376 break :blk try (try func.intcast(operand, given, sign_ty)).toLocal(func, sign_ty);4374 break :blk try (try cg.intcast(operand, given, sign_ty)).toLocal(cg, sign_ty);
4377 } else operand;4375 } else operand;
43784376
4379 // store lsb first4377 // store lsb first
4380 try func.store(.stack, lhs, Type.u64, 0 + stack_ptr.offset());4378 try cg.store(.stack, lhs, Type.u64, 0 + stack_ptr.offset());
43814379
4382 // For signed integers we shift lsb by 63 (64bit integer - 1 sign bit) and store remaining value4380 // For signed integers we shift lsb by 63 (64bit integer - 1 sign bit) and store remaining value
4383 if (wanted.isSignedInt(zcu)) {4381 if (wanted.isSignedInt(zcu)) {
4384 try func.emitWValue(stack_ptr);4382 try cg.emitWValue(stack_ptr);
4385 const shr = try func.binOp(lhs, .{ .imm64 = 63 }, Type.i64, .shr);4383 const shr = try cg.binOp(lhs, .{ .imm64 = 63 }, Type.i64, .shr);
4386 try func.store(.stack, shr, Type.u64, 8 + stack_ptr.offset());4384 try cg.store(.stack, shr, Type.u64, 8 + stack_ptr.offset());
4387 } else {4385 } else {
4388 // Ensure memory of msb is zero'd4386 // Ensure memory of msb is zero'd
4389 try func.store(stack_ptr, .{ .imm64 = 0 }, Type.u64, 8);4387 try cg.store(stack_ptr, .{ .imm64 = 0 }, Type.u64, 8);
4390 }4388 }
4391 return stack_ptr;4389 return stack_ptr;
4392 } else return func.load(operand, wanted, 0);4390 } else return cg.load(operand, wanted, 0);
4393}4391}
43944392
4395fn airIsNull(func: *CodeGen, inst: Air.Inst.Index, opcode: std.wasm.Opcode, op_kind: enum { value, ptr }) InnerError!void {4393fn airIsNull(cg: *CodeGen, inst: Air.Inst.Index, opcode: std.wasm.Opcode, op_kind: enum { value, ptr }) InnerError!void {
4396 const pt = func.pt;4394 const pt = cg.pt;
4397 const zcu = pt.zcu;4395 const zcu = pt.zcu;
4398 const un_op = func.air.instructions.items(.data)[@intFromEnum(inst)].un_op;4396 const un_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].un_op;
4399 const operand = try func.resolveInst(un_op);4397 const operand = try cg.resolveInst(un_op);
44004398
4401 const op_ty = func.typeOf(un_op);4399 const op_ty = cg.typeOf(un_op);
4402 const optional_ty = if (op_kind == .ptr) op_ty.childType(zcu) else op_ty;4400 const optional_ty = if (op_kind == .ptr) op_ty.childType(zcu) else op_ty;
4403 const result = try func.isNull(operand, optional_ty, opcode);4401 const result = try cg.isNull(operand, optional_ty, opcode);
4404 return func.finishAir(inst, result, &.{un_op});4402 return cg.finishAir(inst, result, &.{un_op});
4405}4403}
44064404
4407/// For a given type and operand, checks if it's considered `null`.4405/// For a given type and operand, checks if it's considered `null`.
4408/// NOTE: Leaves the result on the stack4406/// NOTE: Leaves the result on the stack
4409fn isNull(func: *CodeGen, operand: WValue, optional_ty: Type, opcode: std.wasm.Opcode) InnerError!WValue {4407fn isNull(cg: *CodeGen, operand: WValue, optional_ty: Type, opcode: std.wasm.Opcode) InnerError!WValue {
4410 const pt = func.pt;4408 const pt = cg.pt;
4411 const zcu = pt.zcu;4409 const zcu = pt.zcu;
4412 try func.emitWValue(operand);4410 try cg.emitWValue(operand);
4413 const payload_ty = optional_ty.optionalChild(zcu);4411 const payload_ty = optional_ty.optionalChild(zcu);
4414 if (!optional_ty.optionalReprIsPayload(zcu)) {4412 if (!optional_ty.optionalReprIsPayload(zcu)) {
4415 // When payload is zero-bits, we can treat operand as a value, rather than4413 // When payload is zero-bits, we can treat operand as a value, rather than
4416 // a pointer to the stack value4414 // a pointer to the stack value
4417 if (payload_ty.hasRuntimeBitsIgnoreComptime(zcu)) {4415 if (payload_ty.hasRuntimeBitsIgnoreComptime(zcu)) {
4418 const offset = std.math.cast(u32, payload_ty.abiSize(zcu)) orelse {4416 const offset = std.math.cast(u32, payload_ty.abiSize(zcu)) orelse {
4419 return func.fail("Optional type {} too big to fit into stack frame", .{optional_ty.fmt(pt)});4417 return cg.fail("Optional type {} too big to fit into stack frame", .{optional_ty.fmt(pt)});
4420 };4418 };
4421 try func.addMemArg(.i32_load8_u, .{ .offset = operand.offset() + offset, .alignment = 1 });4419 try cg.addMemArg(.i32_load8_u, .{ .offset = operand.offset() + offset, .alignment = 1 });
4422 }4420 }
4423 } else if (payload_ty.isSlice(zcu)) {4421 } else if (payload_ty.isSlice(zcu)) {
4424 switch (func.ptr_size) {4422 switch (cg.ptr_size) {
4425 .wasm32 => try func.addMemArg(.i32_load, .{ .offset = operand.offset(), .alignment = 4 }),4423 .wasm32 => try cg.addMemArg(.i32_load, .{ .offset = operand.offset(), .alignment = 4 }),
4426 .wasm64 => try func.addMemArg(.i64_load, .{ .offset = operand.offset(), .alignment = 8 }),4424 .wasm64 => try cg.addMemArg(.i64_load, .{ .offset = operand.offset(), .alignment = 8 }),
4427 }4425 }
4428 }4426 }
44294427
4430 // Compare the null value with '0'4428 // Compare the null value with '0'
4431 try func.addImm32(0);4429 try cg.addImm32(0);
4432 try func.addTag(Mir.Inst.Tag.fromOpcode(opcode));4430 try cg.addTag(Mir.Inst.Tag.fromOpcode(opcode));
44334431
4434 return .stack;4432 return .stack;
4435}4433}
44364434
4437fn airOptionalPayload(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {4435fn airOptionalPayload(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
4438 const pt = func.pt;4436 const pt = cg.pt;
4439 const zcu = pt.zcu;4437 const zcu = pt.zcu;
4440 const ty_op = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;4438 const ty_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
4441 const opt_ty = func.typeOf(ty_op.operand);4439 const opt_ty = cg.typeOf(ty_op.operand);
4442 const payload_ty = func.typeOfIndex(inst);4440 const payload_ty = cg.typeOfIndex(inst);
4443 if (!payload_ty.hasRuntimeBitsIgnoreComptime(zcu)) {4441 if (!payload_ty.hasRuntimeBitsIgnoreComptime(zcu)) {
4444 return func.finishAir(inst, .none, &.{ty_op.operand});4442 return cg.finishAir(inst, .none, &.{ty_op.operand});
4445 }4443 }
44464444
4447 const result = result: {4445 const result = result: {
4448 const operand = try func.resolveInst(ty_op.operand);4446 const operand = try cg.resolveInst(ty_op.operand);
4449 if (opt_ty.optionalReprIsPayload(zcu)) break :result func.reuseOperand(ty_op.operand, operand);4447 if (opt_ty.optionalReprIsPayload(zcu)) break :result cg.reuseOperand(ty_op.operand, operand);
44504448
4451 if (isByRef(payload_ty, pt, func.target)) {4449 if (isByRef(payload_ty, pt, cg.target)) {
4452 break :result try func.buildPointerOffset(operand, 0, .new);4450 break :result try cg.buildPointerOffset(operand, 0, .new);
4453 }4451 }
44544452
4455 break :result try func.load(operand, payload_ty, 0);4453 break :result try cg.load(operand, payload_ty, 0);
4456 };4454 };
4457 return func.finishAir(inst, result, &.{ty_op.operand});4455 return cg.finishAir(inst, result, &.{ty_op.operand});
4458}4456}
44594457
4460fn airOptionalPayloadPtr(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {4458fn airOptionalPayloadPtr(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
4461 const pt = func.pt;4459 const pt = cg.pt;
4462 const zcu = pt.zcu;4460 const zcu = pt.zcu;
4463 const ty_op = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;4461 const ty_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
4464 const operand = try func.resolveInst(ty_op.operand);4462 const operand = try cg.resolveInst(ty_op.operand);
4465 const opt_ty = func.typeOf(ty_op.operand).childType(zcu);4463 const opt_ty = cg.typeOf(ty_op.operand).childType(zcu);
44664464
4467 const result = result: {4465 const result = result: {
4468 const payload_ty = opt_ty.optionalChild(zcu);4466 const payload_ty = opt_ty.optionalChild(zcu);
4469 if (!payload_ty.hasRuntimeBitsIgnoreComptime(zcu) or opt_ty.optionalReprIsPayload(zcu)) {4467 if (!payload_ty.hasRuntimeBitsIgnoreComptime(zcu) or opt_ty.optionalReprIsPayload(zcu)) {
4470 break :result func.reuseOperand(ty_op.operand, operand);4468 break :result cg.reuseOperand(ty_op.operand, operand);
4471 }4469 }
44724470
4473 break :result try func.buildPointerOffset(operand, 0, .new);4471 break :result try cg.buildPointerOffset(operand, 0, .new);
4474 };4472 };
4475 return func.finishAir(inst, result, &.{ty_op.operand});4473 return cg.finishAir(inst, result, &.{ty_op.operand});
4476}4474}
44774475
4478fn airOptionalPayloadPtrSet(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {4476fn airOptionalPayloadPtrSet(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
4479 const pt = func.pt;4477 const pt = cg.pt;
4480 const zcu = pt.zcu;4478 const zcu = pt.zcu;
4481 const ty_op = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;4479 const ty_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
4482 const operand = try func.resolveInst(ty_op.operand);4480 const operand = try cg.resolveInst(ty_op.operand);
4483 const opt_ty = func.typeOf(ty_op.operand).childType(zcu);4481 const opt_ty = cg.typeOf(ty_op.operand).childType(zcu);
4484 const payload_ty = opt_ty.optionalChild(zcu);4482 const payload_ty = opt_ty.optionalChild(zcu);
4485 if (!payload_ty.hasRuntimeBitsIgnoreComptime(zcu)) {4483 if (!payload_ty.hasRuntimeBitsIgnoreComptime(zcu)) {
4486 return func.fail("TODO: Implement OptionalPayloadPtrSet for optional with zero-sized type {}", .{payload_ty.fmtDebug()});4484 return cg.fail("TODO: Implement OptionalPayloadPtrSet for optional with zero-sized type {}", .{payload_ty.fmtDebug()});
4487 }4485 }
44884486
4489 if (opt_ty.optionalReprIsPayload(zcu)) {4487 if (opt_ty.optionalReprIsPayload(zcu)) {
4490 return func.finishAir(inst, operand, &.{ty_op.operand});4488 return cg.finishAir(inst, operand, &.{ty_op.operand});
4491 }4489 }
44924490
4493 const offset = std.math.cast(u32, payload_ty.abiSize(zcu)) orelse {4491 const offset = std.math.cast(u32, payload_ty.abiSize(zcu)) orelse {
4494 return func.fail("Optional type {} too big to fit into stack frame", .{opt_ty.fmt(pt)});4492 return cg.fail("Optional type {} too big to fit into stack frame", .{opt_ty.fmt(pt)});
4495 };4493 };
44964494
4497 try func.emitWValue(operand);4495 try cg.emitWValue(operand);
4498 try func.addImm32(1);4496 try cg.addImm32(1);
4499 try func.addMemArg(.i32_store8, .{ .offset = operand.offset() + offset, .alignment = 1 });4497 try cg.addMemArg(.i32_store8, .{ .offset = operand.offset() + offset, .alignment = 1 });
45004498
4501 const result = try func.buildPointerOffset(operand, 0, .new);4499 const result = try cg.buildPointerOffset(operand, 0, .new);
4502 return func.finishAir(inst, result, &.{ty_op.operand});4500 return cg.finishAir(inst, result, &.{ty_op.operand});
4503}4501}
45044502
4505fn airWrapOptional(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {4503fn airWrapOptional(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
4506 const ty_op = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;4504 const ty_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
4507 const payload_ty = func.typeOf(ty_op.operand);4505 const payload_ty = cg.typeOf(ty_op.operand);
4508 const pt = func.pt;4506 const pt = cg.pt;
4509 const zcu = pt.zcu;4507 const zcu = pt.zcu;
45104508
4511 const result = result: {4509 const result = result: {
4512 if (!payload_ty.hasRuntimeBitsIgnoreComptime(zcu)) {4510 if (!payload_ty.hasRuntimeBitsIgnoreComptime(zcu)) {
4513 const non_null_bit = try func.allocStack(Type.u1);4511 const non_null_bit = try cg.allocStack(Type.u1);
4514 try func.emitWValue(non_null_bit);4512 try cg.emitWValue(non_null_bit);
4515 try func.addImm32(1);4513 try cg.addImm32(1);
4516 try func.addMemArg(.i32_store8, .{ .offset = non_null_bit.offset(), .alignment = 1 });4514 try cg.addMemArg(.i32_store8, .{ .offset = non_null_bit.offset(), .alignment = 1 });
4517 break :result non_null_bit;4515 break :result non_null_bit;
4518 }4516 }
45194517
4520 const operand = try func.resolveInst(ty_op.operand);4518 const operand = try cg.resolveInst(ty_op.operand);
4521 const op_ty = func.typeOfIndex(inst);4519 const op_ty = cg.typeOfIndex(inst);
4522 if (op_ty.optionalReprIsPayload(zcu)) {4520 if (op_ty.optionalReprIsPayload(zcu)) {
4523 break :result func.reuseOperand(ty_op.operand, operand);4521 break :result cg.reuseOperand(ty_op.operand, operand);
4524 }4522 }
4525 const offset = std.math.cast(u32, payload_ty.abiSize(zcu)) orelse {4523 const offset = std.math.cast(u32, payload_ty.abiSize(zcu)) orelse {
4526 return func.fail("Optional type {} too big to fit into stack frame", .{op_ty.fmt(pt)});4524 return cg.fail("Optional type {} too big to fit into stack frame", .{op_ty.fmt(pt)});
4527 };4525 };
45284526
4529 // Create optional type, set the non-null bit, and store the operand inside the optional type4527 // Create optional type, set the non-null bit, and store the operand inside the optional type
4530 const result_ptr = try func.allocStack(op_ty);4528 const result_ptr = try cg.allocStack(op_ty);
4531 try func.emitWValue(result_ptr);4529 try cg.emitWValue(result_ptr);
4532 try func.addImm32(1);4530 try cg.addImm32(1);
4533 try func.addMemArg(.i32_store8, .{ .offset = result_ptr.offset() + offset, .alignment = 1 });4531 try cg.addMemArg(.i32_store8, .{ .offset = result_ptr.offset() + offset, .alignment = 1 });
45344532
4535 const payload_ptr = try func.buildPointerOffset(result_ptr, 0, .new);4533 const payload_ptr = try cg.buildPointerOffset(result_ptr, 0, .new);
4536 try func.store(payload_ptr, operand, payload_ty, 0);4534 try cg.store(payload_ptr, operand, payload_ty, 0);
4537 break :result result_ptr;4535 break :result result_ptr;
4538 };4536 };
45394537
4540 return func.finishAir(inst, result, &.{ty_op.operand});4538 return cg.finishAir(inst, result, &.{ty_op.operand});
4541}4539}
45424540
4543fn airSlice(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {4541fn airSlice(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
4544 const ty_pl = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;4542 const ty_pl = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
4545 const bin_op = func.air.extraData(Air.Bin, ty_pl.payload).data;4543 const bin_op = cg.air.extraData(Air.Bin, ty_pl.payload).data;
45464544
4547 const lhs = try func.resolveInst(bin_op.lhs);4545 const lhs = try cg.resolveInst(bin_op.lhs);
4548 const rhs = try func.resolveInst(bin_op.rhs);4546 const rhs = try cg.resolveInst(bin_op.rhs);
4549 const slice_ty = func.typeOfIndex(inst);4547 const slice_ty = cg.typeOfIndex(inst);
45504548
4551 const slice = try func.allocStack(slice_ty);4549 const slice = try cg.allocStack(slice_ty);
4552 try func.store(slice, lhs, Type.usize, 0);4550 try cg.store(slice, lhs, Type.usize, 0);
4553 try func.store(slice, rhs, Type.usize, func.ptrSize());4551 try cg.store(slice, rhs, Type.usize, cg.ptrSize());
45544552
4555 return func.finishAir(inst, slice, &.{ bin_op.lhs, bin_op.rhs });4553 return cg.finishAir(inst, slice, &.{ bin_op.lhs, bin_op.rhs });
4556}4554}
45574555
4558fn airSliceLen(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {4556fn airSliceLen(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
4559 const ty_op = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;4557 const ty_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
45604558
4561 const operand = try func.resolveInst(ty_op.operand);4559 const operand = try cg.resolveInst(ty_op.operand);
4562 return func.finishAir(inst, try func.sliceLen(operand), &.{ty_op.operand});4560 return cg.finishAir(inst, try cg.sliceLen(operand), &.{ty_op.operand});
4563}4561}
45644562
4565fn airSliceElemVal(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {4563fn airSliceElemVal(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
4566 const pt = func.pt;4564 const pt = cg.pt;
4567 const zcu = pt.zcu;4565 const zcu = pt.zcu;
4568 const bin_op = func.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;4566 const bin_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
45694567
4570 const slice_ty = func.typeOf(bin_op.lhs);4568 const slice_ty = cg.typeOf(bin_op.lhs);
4571 const slice = try func.resolveInst(bin_op.lhs);4569 const slice = try cg.resolveInst(bin_op.lhs);
4572 const index = try func.resolveInst(bin_op.rhs);4570 const index = try cg.resolveInst(bin_op.rhs);
4573 const elem_ty = slice_ty.childType(zcu);4571 const elem_ty = slice_ty.childType(zcu);
4574 const elem_size = elem_ty.abiSize(zcu);4572 const elem_size = elem_ty.abiSize(zcu);
45754573
4576 // load pointer onto stack4574 // load pointer onto stack
4577 _ = try func.load(slice, Type.usize, 0);4575 _ = try cg.load(slice, Type.usize, 0);
45784576
4579 // calculate index into slice4577 // calculate index into slice
4580 try func.emitWValue(index);4578 try cg.emitWValue(index);
4581 try func.addImm32(@intCast(elem_size));4579 try cg.addImm32(@intCast(elem_size));
4582 try func.addTag(.i32_mul);4580 try cg.addTag(.i32_mul);
4583 try func.addTag(.i32_add);4581 try cg.addTag(.i32_add);
45844582
4585 const elem_result = if (isByRef(elem_ty, pt, func.target))4583 const elem_result = if (isByRef(elem_ty, pt, cg.target))
4586 .stack4584 .stack
4587 else4585 else
4588 try func.load(.stack, elem_ty, 0);4586 try cg.load(.stack, elem_ty, 0);
45894587
4590 return func.finishAir(inst, elem_result, &.{ bin_op.lhs, bin_op.rhs });4588 return cg.finishAir(inst, elem_result, &.{ bin_op.lhs, bin_op.rhs });
4591}4589}
45924590
4593fn airSliceElemPtr(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {4591fn airSliceElemPtr(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
4594 const pt = func.pt;4592 const pt = cg.pt;
4595 const zcu = pt.zcu;4593 const zcu = pt.zcu;
4596 const ty_pl = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;4594 const ty_pl = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
4597 const bin_op = func.air.extraData(Air.Bin, ty_pl.payload).data;4595 const bin_op = cg.air.extraData(Air.Bin, ty_pl.payload).data;
45984596
4599 const elem_ty = ty_pl.ty.toType().childType(zcu);4597 const elem_ty = ty_pl.ty.toType().childType(zcu);
4600 const elem_size = elem_ty.abiSize(zcu);4598 const elem_size = elem_ty.abiSize(zcu);
46014599
4602 const slice = try func.resolveInst(bin_op.lhs);4600 const slice = try cg.resolveInst(bin_op.lhs);
4603 const index = try func.resolveInst(bin_op.rhs);4601 const index = try cg.resolveInst(bin_op.rhs);
46044602
4605 _ = try func.load(slice, Type.usize, 0);4603 _ = try cg.load(slice, Type.usize, 0);
46064604
4607 // calculate index into slice4605 // calculate index into slice
4608 try func.emitWValue(index);4606 try cg.emitWValue(index);
4609 try func.addImm32(@intCast(elem_size));4607 try cg.addImm32(@intCast(elem_size));
4610 try func.addTag(.i32_mul);4608 try cg.addTag(.i32_mul);
4611 try func.addTag(.i32_add);4609 try cg.addTag(.i32_add);
46124610
4613 return func.finishAir(inst, .stack, &.{ bin_op.lhs, bin_op.rhs });4611 return cg.finishAir(inst, .stack, &.{ bin_op.lhs, bin_op.rhs });
4614}4612}
46154613
4616fn airSlicePtr(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {4614fn airSlicePtr(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
4617 const ty_op = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;4615 const ty_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
4618 const operand = try func.resolveInst(ty_op.operand);4616 const operand = try cg.resolveInst(ty_op.operand);
4619 return func.finishAir(inst, try func.slicePtr(operand), &.{ty_op.operand});4617 return cg.finishAir(inst, try cg.slicePtr(operand), &.{ty_op.operand});
4620}4618}
46214619
4622fn slicePtr(func: *CodeGen, operand: WValue) InnerError!WValue {4620fn slicePtr(cg: *CodeGen, operand: WValue) InnerError!WValue {
4623 const ptr = try func.load(operand, Type.usize, 0);4621 const ptr = try cg.load(operand, Type.usize, 0);
4624 return ptr.toLocal(func, Type.usize);4622 return ptr.toLocal(cg, Type.usize);
4625}4623}
46264624
4627fn sliceLen(func: *CodeGen, operand: WValue) InnerError!WValue {4625fn sliceLen(cg: *CodeGen, operand: WValue) InnerError!WValue {
4628 const len = try func.load(operand, Type.usize, func.ptrSize());4626 const len = try cg.load(operand, Type.usize, cg.ptrSize());
4629 return len.toLocal(func, Type.usize);4627 return len.toLocal(cg, Type.usize);
4630}4628}
46314629
4632fn airTrunc(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {4630fn airTrunc(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
4633 const ty_op = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;4631 const ty_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
46344632
4635 const operand = try func.resolveInst(ty_op.operand);4633 const operand = try cg.resolveInst(ty_op.operand);
4636 const wanted_ty: Type = ty_op.ty.toType();4634 const wanted_ty: Type = ty_op.ty.toType();
4637 const op_ty = func.typeOf(ty_op.operand);4635 const op_ty = cg.typeOf(ty_op.operand);
4638 const pt = func.pt;4636 const pt = cg.pt;
4639 const zcu = pt.zcu;4637 const zcu = pt.zcu;
46404638
4641 if (wanted_ty.zigTypeTag(zcu) == .vector or op_ty.zigTypeTag(zcu) == .vector) {4639 if (wanted_ty.zigTypeTag(zcu) == .vector or op_ty.zigTypeTag(zcu) == .vector) {
4642 return func.fail("TODO: trunc for vectors", .{});4640 return cg.fail("TODO: trunc for vectors", .{});
4643 }4641 }
46444642
4645 const result = if (op_ty.bitSize(zcu) == wanted_ty.bitSize(zcu))4643 const result = if (op_ty.bitSize(zcu) == wanted_ty.bitSize(zcu))
4646 func.reuseOperand(ty_op.operand, operand)4644 cg.reuseOperand(ty_op.operand, operand)
4647 else4645 else
4648 try func.trunc(operand, wanted_ty, op_ty);4646 try cg.trunc(operand, wanted_ty, op_ty);
46494647
4650 return func.finishAir(inst, result, &.{ty_op.operand});4648 return cg.finishAir(inst, result, &.{ty_op.operand});
4651}4649}
46524650
4653/// Truncates a given operand to a given type, discarding any overflown bits.4651/// Truncates a given operand to a given type, discarding any overflown bits.
4654/// NOTE: Resulting value is left on the stack.4652/// NOTE: Resulting value is left on the stack.
4655fn trunc(func: *CodeGen, operand: WValue, wanted_ty: Type, given_ty: Type) InnerError!WValue {4653fn trunc(cg: *CodeGen, operand: WValue, wanted_ty: Type, given_ty: Type) InnerError!WValue {
4656 const pt = func.pt;4654 const pt = cg.pt;
4657 const zcu = pt.zcu;4655 const zcu = pt.zcu;
4658 const given_bits = @as(u16, @intCast(given_ty.bitSize(zcu)));4656 const given_bits = @as(u16, @intCast(given_ty.bitSize(zcu)));
4659 if (toWasmBits(given_bits) == null) {4657 if (toWasmBits(given_bits) == null) {
4660 return func.fail("TODO: Implement wasm integer truncation for integer bitsize: {d}", .{given_bits});4658 return cg.fail("TODO: Implement wasm integer truncation for integer bitsize: {d}", .{given_bits});
4661 }4659 }
46624660
4663 var result = try func.intcast(operand, given_ty, wanted_ty);4661 var result = try cg.intcast(operand, given_ty, wanted_ty);
4664 const wanted_bits = @as(u16, @intCast(wanted_ty.bitSize(zcu)));4662 const wanted_bits = @as(u16, @intCast(wanted_ty.bitSize(zcu)));
4665 const wasm_bits = toWasmBits(wanted_bits).?;4663 const wasm_bits = toWasmBits(wanted_bits).?;
4666 if (wasm_bits != wanted_bits) {4664 if (wasm_bits != wanted_bits) {
4667 result = try func.wrapOperand(result, wanted_ty);4665 result = try cg.wrapOperand(result, wanted_ty);
4668 }4666 }
4669 return result;4667 return result;
4670}4668}
46714669
4672fn airIntFromBool(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {4670fn airIntFromBool(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
4673 const un_op = func.air.instructions.items(.data)[@intFromEnum(inst)].un_op;4671 const un_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].un_op;
4674 const operand = try func.resolveInst(un_op);4672 const operand = try cg.resolveInst(un_op);
4675 const result = func.reuseOperand(un_op, operand);4673 const result = cg.reuseOperand(un_op, operand);
46764674
4677 return func.finishAir(inst, result, &.{un_op});4675 return cg.finishAir(inst, result, &.{un_op});
4678}4676}
46794677
4680fn airArrayToSlice(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {4678fn airArrayToSlice(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
4681 const pt = func.pt;4679 const pt = cg.pt;
4682 const zcu = pt.zcu;4680 const zcu = pt.zcu;
4683 const ty_op = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;4681 const ty_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
46844682
4685 const operand = try func.resolveInst(ty_op.operand);4683 const operand = try cg.resolveInst(ty_op.operand);
4686 const array_ty = func.typeOf(ty_op.operand).childType(zcu);4684 const array_ty = cg.typeOf(ty_op.operand).childType(zcu);
4687 const slice_ty = ty_op.ty.toType();4685 const slice_ty = ty_op.ty.toType();
46884686
4689 // create a slice on the stack4687 // create a slice on the stack
4690 const slice_local = try func.allocStack(slice_ty);4688 const slice_local = try cg.allocStack(slice_ty);
46914689
4692 // store the array ptr in the slice4690 // store the array ptr in the slice
4693 if (array_ty.hasRuntimeBitsIgnoreComptime(zcu)) {4691 if (array_ty.hasRuntimeBitsIgnoreComptime(zcu)) {
4694 try func.store(slice_local, operand, Type.usize, 0);4692 try cg.store(slice_local, operand, Type.usize, 0);
4695 }4693 }
46964694
4697 // store the length of the array in the slice4695 // store the length of the array in the slice
4698 const array_len: u32 = @intCast(array_ty.arrayLen(zcu));4696 const array_len: u32 = @intCast(array_ty.arrayLen(zcu));
4699 try func.store(slice_local, .{ .imm32 = array_len }, Type.usize, func.ptrSize());4697 try cg.store(slice_local, .{ .imm32 = array_len }, Type.usize, cg.ptrSize());
47004698
4701 return func.finishAir(inst, slice_local, &.{ty_op.operand});4699 return cg.finishAir(inst, slice_local, &.{ty_op.operand});
4702}4700}
47034701
4704fn airIntFromPtr(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {4702fn airIntFromPtr(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
4705 const pt = func.pt;4703 const pt = cg.pt;
4706 const zcu = pt.zcu;4704 const zcu = pt.zcu;
4707 const un_op = func.air.instructions.items(.data)[@intFromEnum(inst)].un_op;4705 const un_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].un_op;
4708 const operand = try func.resolveInst(un_op);4706 const operand = try cg.resolveInst(un_op);
4709 const ptr_ty = func.typeOf(un_op);4707 const ptr_ty = cg.typeOf(un_op);
4710 const result = if (ptr_ty.isSlice(zcu))4708 const result = if (ptr_ty.isSlice(zcu))
4711 try func.slicePtr(operand)4709 try cg.slicePtr(operand)
4712 else switch (operand) {4710 else switch (operand) {
4713 // for stack offset, return a pointer to this offset.4711 // for stack offset, return a pointer to this offset.
4714 .stack_offset => try func.buildPointerOffset(operand, 0, .new),4712 .stack_offset => try cg.buildPointerOffset(operand, 0, .new),
4715 else => func.reuseOperand(un_op, operand),4713 else => cg.reuseOperand(un_op, operand),
4716 };4714 };
4717 return func.finishAir(inst, result, &.{un_op});4715 return cg.finishAir(inst, result, &.{un_op});
4718}4716}
47194717
4720fn airPtrElemVal(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {4718fn airPtrElemVal(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
4721 const pt = func.pt;4719 const pt = cg.pt;
4722 const zcu = pt.zcu;4720 const zcu = pt.zcu;
4723 const bin_op = func.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;4721 const bin_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
47244722
4725 const ptr_ty = func.typeOf(bin_op.lhs);4723 const ptr_ty = cg.typeOf(bin_op.lhs);
4726 const ptr = try func.resolveInst(bin_op.lhs);4724 const ptr = try cg.resolveInst(bin_op.lhs);
4727 const index = try func.resolveInst(bin_op.rhs);4725 const index = try cg.resolveInst(bin_op.rhs);
4728 const elem_ty = ptr_ty.childType(zcu);4726 const elem_ty = ptr_ty.childType(zcu);
4729 const elem_size = elem_ty.abiSize(zcu);4727 const elem_size = elem_ty.abiSize(zcu);
47304728
4731 // load pointer onto the stack4729 // load pointer onto the stack
4732 if (ptr_ty.isSlice(zcu)) {4730 if (ptr_ty.isSlice(zcu)) {
4733 _ = try func.load(ptr, Type.usize, 0);4731 _ = try cg.load(ptr, Type.usize, 0);
4734 } else {4732 } else {
4735 try func.lowerToStack(ptr);4733 try cg.lowerToStack(ptr);
4736 }4734 }
47374735
4738 // calculate index into slice4736 // calculate index into slice
4739 try func.emitWValue(index);4737 try cg.emitWValue(index);
4740 try func.addImm32(@intCast(elem_size));4738 try cg.addImm32(@intCast(elem_size));
4741 try func.addTag(.i32_mul);4739 try cg.addTag(.i32_mul);
4742 try func.addTag(.i32_add);4740 try cg.addTag(.i32_add);
47434741
4744 const elem_result = if (isByRef(elem_ty, pt, func.target))4742 const elem_result = if (isByRef(elem_ty, pt, cg.target))
4745 .stack4743 .stack
4746 else4744 else
4747 try func.load(.stack, elem_ty, 0);4745 try cg.load(.stack, elem_ty, 0);
47484746
4749 return func.finishAir(inst, elem_result, &.{ bin_op.lhs, bin_op.rhs });4747 return cg.finishAir(inst, elem_result, &.{ bin_op.lhs, bin_op.rhs });
4750}4748}
47514749
4752fn airPtrElemPtr(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {4750fn airPtrElemPtr(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
4753 const pt = func.pt;4751 const pt = cg.pt;
4754 const zcu = pt.zcu;4752 const zcu = pt.zcu;
4755 const ty_pl = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;4753 const ty_pl = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
4756 const bin_op = func.air.extraData(Air.Bin, ty_pl.payload).data;4754 const bin_op = cg.air.extraData(Air.Bin, ty_pl.payload).data;
47574755
4758 const ptr_ty = func.typeOf(bin_op.lhs);4756 const ptr_ty = cg.typeOf(bin_op.lhs);
4759 const elem_ty = ty_pl.ty.toType().childType(zcu);4757 const elem_ty = ty_pl.ty.toType().childType(zcu);
4760 const elem_size = elem_ty.abiSize(zcu);4758 const elem_size = elem_ty.abiSize(zcu);
47614759
4762 const ptr = try func.resolveInst(bin_op.lhs);4760 const ptr = try cg.resolveInst(bin_op.lhs);
4763 const index = try func.resolveInst(bin_op.rhs);4761 const index = try cg.resolveInst(bin_op.rhs);
47644762
4765 // load pointer onto the stack4763 // load pointer onto the stack
4766 if (ptr_ty.isSlice(zcu)) {4764 if (ptr_ty.isSlice(zcu)) {
4767 _ = try func.load(ptr, Type.usize, 0);4765 _ = try cg.load(ptr, Type.usize, 0);
4768 } else {4766 } else {
4769 try func.lowerToStack(ptr);4767 try cg.lowerToStack(ptr);
4770 }4768 }
47714769
4772 // calculate index into ptr4770 // calculate index into ptr
4773 try func.emitWValue(index);4771 try cg.emitWValue(index);
4774 try func.addImm32(@intCast(elem_size));4772 try cg.addImm32(@intCast(elem_size));
4775 try func.addTag(.i32_mul);4773 try cg.addTag(.i32_mul);
4776 try func.addTag(.i32_add);4774 try cg.addTag(.i32_add);
47774775
4778 return func.finishAir(inst, .stack, &.{ bin_op.lhs, bin_op.rhs });4776 return cg.finishAir(inst, .stack, &.{ bin_op.lhs, bin_op.rhs });
4779}4777}
47804778
4781fn airPtrBinOp(func: *CodeGen, inst: Air.Inst.Index, op: Op) InnerError!void {4779fn airPtrBinOp(cg: *CodeGen, inst: Air.Inst.Index, op: Op) InnerError!void {
4782 const pt = func.pt;4780 const pt = cg.pt;
4783 const zcu = pt.zcu;4781 const zcu = pt.zcu;
4784 const ty_pl = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;4782 const ty_pl = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
4785 const bin_op = func.air.extraData(Air.Bin, ty_pl.payload).data;4783 const bin_op = cg.air.extraData(Air.Bin, ty_pl.payload).data;
47864784
4787 const ptr = try func.resolveInst(bin_op.lhs);4785 const ptr = try cg.resolveInst(bin_op.lhs);
4788 const offset = try func.resolveInst(bin_op.rhs);4786 const offset = try cg.resolveInst(bin_op.rhs);
4789 const ptr_ty = func.typeOf(bin_op.lhs);4787 const ptr_ty = cg.typeOf(bin_op.lhs);
4790 const pointee_ty = switch (ptr_ty.ptrSize(zcu)) {4788 const pointee_ty = switch (ptr_ty.ptrSize(zcu)) {
4791 .One => ptr_ty.childType(zcu).childType(zcu), // ptr to array, so get array element type4789 .One => ptr_ty.childType(zcu).childType(zcu), // ptr to array, so get array element type
4792 else => ptr_ty.childType(zcu),4790 else => ptr_ty.childType(zcu),
4793 };4791 };
47944792
4795 const valtype = typeToValtype(Type.usize, pt, func.target);4793 const valtype = typeToValtype(Type.usize, pt, cg.target);
4796 const mul_opcode = buildOpcode(.{ .valtype1 = valtype, .op = .mul });4794 const mul_opcode = buildOpcode(.{ .valtype1 = valtype, .op = .mul });
4797 const bin_opcode = buildOpcode(.{ .valtype1 = valtype, .op = op });4795 const bin_opcode = buildOpcode(.{ .valtype1 = valtype, .op = op });
47984796
4799 try func.lowerToStack(ptr);4797 try cg.lowerToStack(ptr);
4800 try func.emitWValue(offset);4798 try cg.emitWValue(offset);
4801 try func.addImm32(@intCast(pointee_ty.abiSize(zcu)));4799 try cg.addImm32(@intCast(pointee_ty.abiSize(zcu)));
4802 try func.addTag(Mir.Inst.Tag.fromOpcode(mul_opcode));4800 try cg.addTag(Mir.Inst.Tag.fromOpcode(mul_opcode));
4803 try func.addTag(Mir.Inst.Tag.fromOpcode(bin_opcode));4801 try cg.addTag(Mir.Inst.Tag.fromOpcode(bin_opcode));
48044802
4805 return func.finishAir(inst, .stack, &.{ bin_op.lhs, bin_op.rhs });4803 return cg.finishAir(inst, .stack, &.{ bin_op.lhs, bin_op.rhs });
4806}4804}
48074805
4808fn airMemset(func: *CodeGen, inst: Air.Inst.Index, safety: bool) InnerError!void {4806fn airMemset(cg: *CodeGen, inst: Air.Inst.Index, safety: bool) InnerError!void {
4809 const pt = func.pt;4807 const pt = cg.pt;
4810 const zcu = pt.zcu;4808 const zcu = pt.zcu;
4811 if (safety) {4809 if (safety) {
4812 // TODO if the value is undef, write 0xaa bytes to dest4810 // TODO if the value is undef, write 0xaa bytes to dest
4813 } else {4811 } else {
4814 // TODO if the value is undef, don't lower this instruction4812 // TODO if the value is undef, don't lower this instruction
4815 }4813 }
4816 const bin_op = func.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;4814 const bin_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
48174815
4818 const ptr = try func.resolveInst(bin_op.lhs);4816 const ptr = try cg.resolveInst(bin_op.lhs);
4819 const ptr_ty = func.typeOf(bin_op.lhs);4817 const ptr_ty = cg.typeOf(bin_op.lhs);
4820 const value = try func.resolveInst(bin_op.rhs);4818 const value = try cg.resolveInst(bin_op.rhs);
4821 const len = switch (ptr_ty.ptrSize(zcu)) {4819 const len = switch (ptr_ty.ptrSize(zcu)) {
4822 .Slice => try func.sliceLen(ptr),4820 .Slice => try cg.sliceLen(ptr),
4823 .One => @as(WValue, .{ .imm32 = @as(u32, @intCast(ptr_ty.childType(zcu).arrayLen(zcu))) }),4821 .One => @as(WValue, .{ .imm32 = @as(u32, @intCast(ptr_ty.childType(zcu).arrayLen(zcu))) }),
4824 .C, .Many => unreachable,4822 .C, .Many => unreachable,
4825 };4823 };
...@@ -4829,27 +4827,27 @@ fn airMemset(func: *CodeGen, inst: Air.Inst.Index, safety: bool) InnerError!void...@@ -4829,27 +4827,27 @@ fn airMemset(func: *CodeGen, inst: Air.Inst.Index, safety: bool) InnerError!void
4829 else4827 else
4830 ptr_ty.childType(zcu);4828 ptr_ty.childType(zcu);
48314829
4832 const dst_ptr = try func.sliceOrArrayPtr(ptr, ptr_ty);4830 const dst_ptr = try cg.sliceOrArrayPtr(ptr, ptr_ty);
4833 try func.memset(elem_ty, dst_ptr, len, value);4831 try cg.memset(elem_ty, dst_ptr, len, value);
48344832
4835 return func.finishAir(inst, .none, &.{ bin_op.lhs, bin_op.rhs });4833 return cg.finishAir(inst, .none, &.{ bin_op.lhs, bin_op.rhs });
4836}4834}
48374835
4838/// Sets a region of memory at `ptr` to the value of `value`4836/// Sets a region of memory at `ptr` to the value of `value`
4839/// When the user has enabled the bulk_memory feature, we lower4837/// When the user has enabled the bulk_memory feature, we lower
4840/// this to wasm's memset instruction. When the feature is not present,4838/// this to wasm's memset instruction. When the feature is not present,
4841/// we implement it manually.4839/// we implement it manually.
4842fn memset(func: *CodeGen, elem_ty: Type, ptr: WValue, len: WValue, value: WValue) InnerError!void {4840fn memset(cg: *CodeGen, elem_ty: Type, ptr: WValue, len: WValue, value: WValue) InnerError!void {
4843 const pt = func.pt;4841 const pt = cg.pt;
4844 const abi_size = @as(u32, @intCast(elem_ty.abiSize(pt.zcu)));4842 const abi_size = @as(u32, @intCast(elem_ty.abiSize(pt.zcu)));
48454843
4846 // When bulk_memory is enabled, we lower it to wasm's memset instruction.4844 // When bulk_memory is enabled, we lower it to wasm's memset instruction.
4847 // If not, we lower it ourselves.4845 // If not, we lower it ourselves.
4848 if (std.Target.wasm.featureSetHas(func.target.cpu.features, .bulk_memory) and abi_size == 1) {4846 if (std.Target.wasm.featureSetHas(cg.target.cpu.features, .bulk_memory) and abi_size == 1) {
4849 try func.lowerToStack(ptr);4847 try cg.lowerToStack(ptr);
4850 try func.emitWValue(value);4848 try cg.emitWValue(value);
4851 try func.emitWValue(len);4849 try cg.emitWValue(len);
4852 try func.addExtended(.memory_fill);4850 try cg.addExtended(.memory_fill);
4853 return;4851 return;
4854 }4852 }
48554853
...@@ -4857,90 +4855,90 @@ fn memset(func: *CodeGen, elem_ty: Type, ptr: WValue, len: WValue, value: WValue...@@ -4857,90 +4855,90 @@ fn memset(func: *CodeGen, elem_ty: Type, ptr: WValue, len: WValue, value: WValue
4857 .imm32 => |val| .{ .imm32 = val * abi_size },4855 .imm32 => |val| .{ .imm32 = val * abi_size },
4858 .imm64 => |val| .{ .imm64 = val * abi_size },4856 .imm64 => |val| .{ .imm64 = val * abi_size },
4859 else => if (abi_size != 1) blk: {4857 else => if (abi_size != 1) blk: {
4860 const new_len = try func.ensureAllocLocal(Type.usize);4858 const new_len = try cg.ensureAllocLocal(Type.usize);
4861 try func.emitWValue(len);4859 try cg.emitWValue(len);
4862 switch (func.ptr_size) {4860 switch (cg.ptr_size) {
4863 .wasm32 => {4861 .wasm32 => {
4864 try func.emitWValue(.{ .imm32 = abi_size });4862 try cg.emitWValue(.{ .imm32 = abi_size });
4865 try func.addTag(.i32_mul);4863 try cg.addTag(.i32_mul);
4866 },4864 },
4867 .wasm64 => {4865 .wasm64 => {
4868 try func.emitWValue(.{ .imm64 = abi_size });4866 try cg.emitWValue(.{ .imm64 = abi_size });
4869 try func.addTag(.i64_mul);4867 try cg.addTag(.i64_mul);
4870 },4868 },
4871 }4869 }
4872 try func.addLabel(.local_set, new_len.local.value);4870 try cg.addLabel(.local_set, new_len.local.value);
4873 break :blk new_len;4871 break :blk new_len;
4874 } else len,4872 } else len,
4875 };4873 };
48764874
4877 var end_ptr = try func.allocLocal(Type.usize);4875 var end_ptr = try cg.allocLocal(Type.usize);
4878 defer end_ptr.free(func);4876 defer end_ptr.free(cg);
4879 var new_ptr = try func.buildPointerOffset(ptr, 0, .new);4877 var new_ptr = try cg.buildPointerOffset(ptr, 0, .new);
4880 defer new_ptr.free(func);4878 defer new_ptr.free(cg);
48814879
4882 // get the loop conditional: if current pointer address equals final pointer's address4880 // get the loop conditional: if current pointer address equals final pointer's address
4883 try func.lowerToStack(ptr);4881 try cg.lowerToStack(ptr);
4884 try func.emitWValue(final_len);4882 try cg.emitWValue(final_len);
4885 switch (func.ptr_size) {4883 switch (cg.ptr_size) {
4886 .wasm32 => try func.addTag(.i32_add),4884 .wasm32 => try cg.addTag(.i32_add),
4887 .wasm64 => try func.addTag(.i64_add),4885 .wasm64 => try cg.addTag(.i64_add),
4888 }4886 }
4889 try func.addLabel(.local_set, end_ptr.local.value);4887 try cg.addLabel(.local_set, end_ptr.local.value);
48904888
4891 // outer block to jump to when loop is done4889 // outer block to jump to when loop is done
4892 try func.startBlock(.block, std.wasm.block_empty);4890 try cg.startBlock(.block, std.wasm.block_empty);
4893 try func.startBlock(.loop, std.wasm.block_empty);4891 try cg.startBlock(.loop, std.wasm.block_empty);
48944892
4895 // check for condition for loop end4893 // check for condition for loop end
4896 try func.emitWValue(new_ptr);4894 try cg.emitWValue(new_ptr);
4897 try func.emitWValue(end_ptr);4895 try cg.emitWValue(end_ptr);
4898 switch (func.ptr_size) {4896 switch (cg.ptr_size) {
4899 .wasm32 => try func.addTag(.i32_eq),4897 .wasm32 => try cg.addTag(.i32_eq),
4900 .wasm64 => try func.addTag(.i64_eq),4898 .wasm64 => try cg.addTag(.i64_eq),
4901 }4899 }
4902 try func.addLabel(.br_if, 1); // jump out of loop into outer block (finished)4900 try cg.addLabel(.br_if, 1); // jump out of loop into outer block (finished)
49034901
4904 // store the value at the current position of the pointer4902 // store the value at the current position of the pointer
4905 try func.store(new_ptr, value, elem_ty, 0);4903 try cg.store(new_ptr, value, elem_ty, 0);
49064904
4907 // move the pointer to the next element4905 // move the pointer to the next element
4908 try func.emitWValue(new_ptr);4906 try cg.emitWValue(new_ptr);
4909 switch (func.ptr_size) {4907 switch (cg.ptr_size) {
4910 .wasm32 => {4908 .wasm32 => {
4911 try func.emitWValue(.{ .imm32 = abi_size });4909 try cg.emitWValue(.{ .imm32 = abi_size });
4912 try func.addTag(.i32_add);4910 try cg.addTag(.i32_add);
4913 },4911 },
4914 .wasm64 => {4912 .wasm64 => {
4915 try func.emitWValue(.{ .imm64 = abi_size });4913 try cg.emitWValue(.{ .imm64 = abi_size });
4916 try func.addTag(.i64_add);4914 try cg.addTag(.i64_add);
4917 },4915 },
4918 }4916 }
4919 try func.addLabel(.local_set, new_ptr.local.value);4917 try cg.addLabel(.local_set, new_ptr.local.value);
49204918
4921 // end of loop4919 // end of loop
4922 try func.addLabel(.br, 0); // jump to start of loop4920 try cg.addLabel(.br, 0); // jump to start of loop
4923 try func.endBlock();4921 try cg.endBlock();
4924 try func.endBlock();4922 try cg.endBlock();
4925}4923}
49264924
4927fn airArrayElemVal(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {4925fn airArrayElemVal(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
4928 const pt = func.pt;4926 const pt = cg.pt;
4929 const zcu = pt.zcu;4927 const zcu = pt.zcu;
4930 const bin_op = func.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;4928 const bin_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
49314929
4932 const array_ty = func.typeOf(bin_op.lhs);4930 const array_ty = cg.typeOf(bin_op.lhs);
4933 const array = try func.resolveInst(bin_op.lhs);4931 const array = try cg.resolveInst(bin_op.lhs);
4934 const index = try func.resolveInst(bin_op.rhs);4932 const index = try cg.resolveInst(bin_op.rhs);
4935 const elem_ty = array_ty.childType(zcu);4933 const elem_ty = array_ty.childType(zcu);
4936 const elem_size = elem_ty.abiSize(zcu);4934 const elem_size = elem_ty.abiSize(zcu);
49374935
4938 if (isByRef(array_ty, pt, func.target)) {4936 if (isByRef(array_ty, pt, cg.target)) {
4939 try func.lowerToStack(array);4937 try cg.lowerToStack(array);
4940 try func.emitWValue(index);4938 try cg.emitWValue(index);
4941 try func.addImm32(@intCast(elem_size));4939 try cg.addImm32(@intCast(elem_size));
4942 try func.addTag(.i32_mul);4940 try cg.addTag(.i32_mul);
4943 try func.addTag(.i32_add);4941 try cg.addTag(.i32_add);
4944 } else {4942 } else {
4945 assert(array_ty.zigTypeTag(zcu) == .vector);4943 assert(array_ty.zigTypeTag(zcu) == .vector);
49464944
...@@ -4956,50 +4954,50 @@ fn airArrayElemVal(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -4956,50 +4954,50 @@ fn airArrayElemVal(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
49564954
4957 var operands = [_]u32{ @intFromEnum(opcode), @as(u8, @intCast(lane)) };4955 var operands = [_]u32{ @intFromEnum(opcode), @as(u8, @intCast(lane)) };
49584956
4959 try func.emitWValue(array);4957 try cg.emitWValue(array);
49604958
4961 const extra_index = @as(u32, @intCast(func.mir_extra.items.len));4959 const extra_index = @as(u32, @intCast(cg.mir_extra.items.len));
4962 try func.mir_extra.appendSlice(func.gpa, &operands);4960 try cg.mir_extra.appendSlice(cg.gpa, &operands);
4963 try func.addInst(.{ .tag = .simd_prefix, .data = .{ .payload = extra_index } });4961 try cg.addInst(.{ .tag = .simd_prefix, .data = .{ .payload = extra_index } });
49644962
4965 return func.finishAir(inst, .stack, &.{ bin_op.lhs, bin_op.rhs });4963 return cg.finishAir(inst, .stack, &.{ bin_op.lhs, bin_op.rhs });
4966 },4964 },
4967 else => {4965 else => {
4968 const stack_vec = try func.allocStack(array_ty);4966 const stack_vec = try cg.allocStack(array_ty);
4969 try func.store(stack_vec, array, array_ty, 0);4967 try cg.store(stack_vec, array, array_ty, 0);
49704968
4971 // Is a non-unrolled vector (v128)4969 // Is a non-unrolled vector (v128)
4972 try func.lowerToStack(stack_vec);4970 try cg.lowerToStack(stack_vec);
4973 try func.emitWValue(index);4971 try cg.emitWValue(index);
4974 try func.addImm32(@intCast(elem_size));4972 try cg.addImm32(@intCast(elem_size));
4975 try func.addTag(.i32_mul);4973 try cg.addTag(.i32_mul);
4976 try func.addTag(.i32_add);4974 try cg.addTag(.i32_add);
4977 },4975 },
4978 }4976 }
4979 }4977 }
49804978
4981 const elem_result = if (isByRef(elem_ty, pt, func.target))4979 const elem_result = if (isByRef(elem_ty, pt, cg.target))
4982 .stack4980 .stack
4983 else4981 else
4984 try func.load(.stack, elem_ty, 0);4982 try cg.load(.stack, elem_ty, 0);
49854983
4986 return func.finishAir(inst, elem_result, &.{ bin_op.lhs, bin_op.rhs });4984 return cg.finishAir(inst, elem_result, &.{ bin_op.lhs, bin_op.rhs });
4987}4985}
49884986
4989fn airIntFromFloat(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {4987fn airIntFromFloat(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
4990 const pt = func.pt;4988 const pt = cg.pt;
4991 const zcu = pt.zcu;4989 const zcu = pt.zcu;
4992 const ty_op = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;4990 const ty_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
49934991
4994 const operand = try func.resolveInst(ty_op.operand);4992 const operand = try cg.resolveInst(ty_op.operand);
4995 const op_ty = func.typeOf(ty_op.operand);4993 const op_ty = cg.typeOf(ty_op.operand);
4996 const op_bits = op_ty.floatBits(func.target.*);4994 const op_bits = op_ty.floatBits(cg.target.*);
49974995
4998 const dest_ty = func.typeOfIndex(inst);4996 const dest_ty = cg.typeOfIndex(inst);
4999 const dest_info = dest_ty.intInfo(zcu);4997 const dest_info = dest_ty.intInfo(zcu);
50004998
5001 if (dest_info.bits > 128) {4999 if (dest_info.bits > 128) {
5002 return func.fail("TODO: intFromFloat for integers/floats with bitsize {}", .{dest_info.bits});5000 return cg.fail("TODO: intFromFloat for integers/floats with bitsize {}", .{dest_info.bits});
5003 }5001 }
50045002
5005 if ((op_bits != 32 and op_bits != 64) or dest_info.bits > 64) {5003 if ((op_bits != 32 and op_bits != 64) or dest_info.bits > 64) {
...@@ -5015,36 +5013,36 @@ fn airIntFromFloat(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -5015,36 +5013,36 @@ fn airIntFromFloat(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
5015 target_util.compilerRtIntAbbrev(dest_bitsize),5013 target_util.compilerRtIntAbbrev(dest_bitsize),
5016 }) catch unreachable;5014 }) catch unreachable;
50175015
5018 const result = try func.callIntrinsic(fn_name, &.{op_ty.ip_index}, dest_ty, &.{operand});5016 const result = try cg.callIntrinsic(fn_name, &.{op_ty.ip_index}, dest_ty, &.{operand});
5019 return func.finishAir(inst, result, &.{ty_op.operand});5017 return cg.finishAir(inst, result, &.{ty_op.operand});
5020 }5018 }
50215019
5022 try func.emitWValue(operand);5020 try cg.emitWValue(operand);
5023 const op = buildOpcode(.{5021 const op = buildOpcode(.{
5024 .op = .trunc,5022 .op = .trunc,
5025 .valtype1 = typeToValtype(dest_ty, pt, func.target),5023 .valtype1 = typeToValtype(dest_ty, pt, cg.target),
5026 .valtype2 = typeToValtype(op_ty, pt, func.target),5024 .valtype2 = typeToValtype(op_ty, pt, cg.target),
5027 .signedness = dest_info.signedness,5025 .signedness = dest_info.signedness,
5028 });5026 });
5029 try func.addTag(Mir.Inst.Tag.fromOpcode(op));5027 try cg.addTag(Mir.Inst.Tag.fromOpcode(op));
5030 const result = try func.wrapOperand(.stack, dest_ty);5028 const result = try cg.wrapOperand(.stack, dest_ty);
5031 return func.finishAir(inst, result, &.{ty_op.operand});5029 return cg.finishAir(inst, result, &.{ty_op.operand});
5032}5030}
50335031
5034fn airFloatFromInt(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {5032fn airFloatFromInt(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
5035 const pt = func.pt;5033 const pt = cg.pt;
5036 const zcu = pt.zcu;5034 const zcu = pt.zcu;
5037 const ty_op = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;5035 const ty_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
50385036
5039 const operand = try func.resolveInst(ty_op.operand);5037 const operand = try cg.resolveInst(ty_op.operand);
5040 const op_ty = func.typeOf(ty_op.operand);5038 const op_ty = cg.typeOf(ty_op.operand);
5041 const op_info = op_ty.intInfo(zcu);5039 const op_info = op_ty.intInfo(zcu);
50425040
5043 const dest_ty = func.typeOfIndex(inst);5041 const dest_ty = cg.typeOfIndex(inst);
5044 const dest_bits = dest_ty.floatBits(func.target.*);5042 const dest_bits = dest_ty.floatBits(cg.target.*);
50455043
5046 if (op_info.bits > 128) {5044 if (op_info.bits > 128) {
5047 return func.fail("TODO: floatFromInt for integers/floats with bitsize {d} bits", .{op_info.bits});5045 return cg.fail("TODO: floatFromInt for integers/floats with bitsize {d} bits", .{op_info.bits});
5048 }5046 }
50495047
5050 if (op_info.bits > 64 or (dest_bits > 64 or dest_bits < 32)) {5048 if (op_info.bits > 64 or (dest_bits > 64 or dest_bits < 32)) {
...@@ -5060,31 +5058,31 @@ fn airFloatFromInt(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -5060,31 +5058,31 @@ fn airFloatFromInt(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
5060 target_util.compilerRtFloatAbbrev(dest_bits),5058 target_util.compilerRtFloatAbbrev(dest_bits),
5061 }) catch unreachable;5059 }) catch unreachable;
50625060
5063 const result = try func.callIntrinsic(fn_name, &.{op_ty.ip_index}, dest_ty, &.{operand});5061 const result = try cg.callIntrinsic(fn_name, &.{op_ty.ip_index}, dest_ty, &.{operand});
5064 return func.finishAir(inst, result, &.{ty_op.operand});5062 return cg.finishAir(inst, result, &.{ty_op.operand});
5065 }5063 }
50665064
5067 try func.emitWValue(operand);5065 try cg.emitWValue(operand);
5068 const op = buildOpcode(.{5066 const op = buildOpcode(.{
5069 .op = .convert,5067 .op = .convert,
5070 .valtype1 = typeToValtype(dest_ty, pt, func.target),5068 .valtype1 = typeToValtype(dest_ty, pt, cg.target),
5071 .valtype2 = typeToValtype(op_ty, pt, func.target),5069 .valtype2 = typeToValtype(op_ty, pt, cg.target),
5072 .signedness = op_info.signedness,5070 .signedness = op_info.signedness,
5073 });5071 });
5074 try func.addTag(Mir.Inst.Tag.fromOpcode(op));5072 try cg.addTag(Mir.Inst.Tag.fromOpcode(op));
50755073
5076 return func.finishAir(inst, .stack, &.{ty_op.operand});5074 return cg.finishAir(inst, .stack, &.{ty_op.operand});
5077}5075}
50785076
5079fn airSplat(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {5077fn airSplat(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
5080 const pt = func.pt;5078 const pt = cg.pt;
5081 const zcu = pt.zcu;5079 const zcu = pt.zcu;
5082 const ty_op = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;5080 const ty_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
5083 const operand = try func.resolveInst(ty_op.operand);5081 const operand = try cg.resolveInst(ty_op.operand);
5084 const ty = func.typeOfIndex(inst);5082 const ty = cg.typeOfIndex(inst);
5085 const elem_ty = ty.childType(zcu);5083 const elem_ty = ty.childType(zcu);
50865084
5087 if (determineSimdStoreStrategy(ty, zcu, func.target) == .direct) blk: {5085 if (determineSimdStoreStrategy(ty, zcu, cg.target) == .direct) blk: {
5088 switch (operand) {5086 switch (operand) {
5089 // when the operand lives in the linear memory section, we can directly5087 // when the operand lives in the linear memory section, we can directly
5090 // load and splat the value at once. Meaning we do not first have to load5088 // load and splat the value at once. Meaning we do not first have to load
...@@ -5097,16 +5095,16 @@ fn airSplat(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -5097,16 +5095,16 @@ fn airSplat(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
5097 64 => @intFromEnum(std.wasm.SimdOpcode.v128_load64_splat),5095 64 => @intFromEnum(std.wasm.SimdOpcode.v128_load64_splat),
5098 else => break :blk, // Cannot make use of simd-instructions5096 else => break :blk, // Cannot make use of simd-instructions
5099 };5097 };
5100 try func.emitWValue(operand);5098 try cg.emitWValue(operand);
5101 const extra_index: u32 = @intCast(func.mir_extra.items.len);5099 const extra_index: u32 = @intCast(cg.mir_extra.items.len);
5102 // stores as := opcode, offset, alignment (opcode::memarg)5100 // stores as := opcode, offset, alignment (opcode::memarg)
5103 try func.mir_extra.appendSlice(func.gpa, &[_]u32{5101 try cg.mir_extra.appendSlice(cg.gpa, &[_]u32{
5104 opcode,5102 opcode,
5105 operand.offset(),5103 operand.offset(),
5106 @intCast(elem_ty.abiAlignment(zcu).toByteUnits().?),5104 @intCast(elem_ty.abiAlignment(zcu).toByteUnits().?),
5107 });5105 });
5108 try func.addInst(.{ .tag = .simd_prefix, .data = .{ .payload = extra_index } });5106 try cg.addInst(.{ .tag = .simd_prefix, .data = .{ .payload = extra_index } });
5109 return func.finishAir(inst, .stack, &.{ty_op.operand});5107 return cg.finishAir(inst, .stack, &.{ty_op.operand});
5110 },5108 },
5111 .local => {5109 .local => {
5112 const opcode = switch (elem_ty.bitSize(zcu)) {5110 const opcode = switch (elem_ty.bitSize(zcu)) {
...@@ -5116,11 +5114,11 @@ fn airSplat(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -5116,11 +5114,11 @@ fn airSplat(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
5116 64 => if (elem_ty.isInt(zcu)) @intFromEnum(std.wasm.SimdOpcode.i64x2_splat) else @intFromEnum(std.wasm.SimdOpcode.f64x2_splat),5114 64 => if (elem_ty.isInt(zcu)) @intFromEnum(std.wasm.SimdOpcode.i64x2_splat) else @intFromEnum(std.wasm.SimdOpcode.f64x2_splat),
5117 else => break :blk, // Cannot make use of simd-instructions5115 else => break :blk, // Cannot make use of simd-instructions
5118 };5116 };
5119 try func.emitWValue(operand);5117 try cg.emitWValue(operand);
5120 const extra_index = @as(u32, @intCast(func.mir_extra.items.len));5118 const extra_index = @as(u32, @intCast(cg.mir_extra.items.len));
5121 try func.mir_extra.append(func.gpa, opcode);5119 try cg.mir_extra.append(cg.gpa, opcode);
5122 try func.addInst(.{ .tag = .simd_prefix, .data = .{ .payload = extra_index } });5120 try cg.addInst(.{ .tag = .simd_prefix, .data = .{ .payload = extra_index } });
5123 return func.finishAir(inst, .stack, &.{ty_op.operand});5121 return cg.finishAir(inst, .stack, &.{ty_op.operand});
5124 },5122 },
5125 else => unreachable,5123 else => unreachable,
5126 }5124 }
...@@ -5128,38 +5126,38 @@ fn airSplat(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -5128,38 +5126,38 @@ fn airSplat(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
5128 const elem_size = elem_ty.bitSize(zcu);5126 const elem_size = elem_ty.bitSize(zcu);
5129 const vector_len = @as(usize, @intCast(ty.vectorLen(zcu)));5127 const vector_len = @as(usize, @intCast(ty.vectorLen(zcu)));
5130 if ((!std.math.isPowerOfTwo(elem_size) or elem_size % 8 != 0) and vector_len > 1) {5128 if ((!std.math.isPowerOfTwo(elem_size) or elem_size % 8 != 0) and vector_len > 1) {
5131 return func.fail("TODO: WebAssembly `@splat` for arbitrary element bitsize {d}", .{elem_size});5129 return cg.fail("TODO: WebAssembly `@splat` for arbitrary element bitsize {d}", .{elem_size});
5132 }5130 }
51335131
5134 const result = try func.allocStack(ty);5132 const result = try cg.allocStack(ty);
5135 const elem_byte_size = @as(u32, @intCast(elem_ty.abiSize(zcu)));5133 const elem_byte_size = @as(u32, @intCast(elem_ty.abiSize(zcu)));
5136 var index: usize = 0;5134 var index: usize = 0;
5137 var offset: u32 = 0;5135 var offset: u32 = 0;
5138 while (index < vector_len) : (index += 1) {5136 while (index < vector_len) : (index += 1) {
5139 try func.store(result, operand, elem_ty, offset);5137 try cg.store(result, operand, elem_ty, offset);
5140 offset += elem_byte_size;5138 offset += elem_byte_size;
5141 }5139 }
51425140
5143 return func.finishAir(inst, result, &.{ty_op.operand});5141 return cg.finishAir(inst, result, &.{ty_op.operand});
5144}5142}
51455143
5146fn airSelect(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {5144fn airSelect(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
5147 const pl_op = func.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;5145 const pl_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;
5148 const operand = try func.resolveInst(pl_op.operand);5146 const operand = try cg.resolveInst(pl_op.operand);
51495147
5150 _ = operand;5148 _ = operand;
5151 return func.fail("TODO: Implement wasm airSelect", .{});5149 return cg.fail("TODO: Implement wasm airSelect", .{});
5152}5150}
51535151
5154fn airShuffle(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {5152fn airShuffle(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
5155 const pt = func.pt;5153 const pt = cg.pt;
5156 const zcu = pt.zcu;5154 const zcu = pt.zcu;
5157 const inst_ty = func.typeOfIndex(inst);5155 const inst_ty = cg.typeOfIndex(inst);
5158 const ty_pl = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;5156 const ty_pl = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
5159 const extra = func.air.extraData(Air.Shuffle, ty_pl.payload).data;5157 const extra = cg.air.extraData(Air.Shuffle, ty_pl.payload).data;
51605158
5161 const a = try func.resolveInst(extra.a);5159 const a = try cg.resolveInst(extra.a);
5162 const b = try func.resolveInst(extra.b);5160 const b = try cg.resolveInst(extra.b);
5163 const mask = Value.fromInterned(extra.mask);5161 const mask = Value.fromInterned(extra.mask);
5164 const mask_len = extra.mask_len;5162 const mask_len = extra.mask_len;
51655163
...@@ -5167,23 +5165,23 @@ fn airShuffle(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -5167,23 +5165,23 @@ fn airShuffle(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
5167 const elem_size = child_ty.abiSize(zcu);5165 const elem_size = child_ty.abiSize(zcu);
51685166
5169 // TODO: One of them could be by ref; handle in loop5167 // TODO: One of them could be by ref; handle in loop
5170 if (isByRef(func.typeOf(extra.a), pt, func.target) or isByRef(inst_ty, pt, func.target)) {5168 if (isByRef(cg.typeOf(extra.a), pt, cg.target) or isByRef(inst_ty, pt, cg.target)) {
5171 const result = try func.allocStack(inst_ty);5169 const result = try cg.allocStack(inst_ty);
51725170
5173 for (0..mask_len) |index| {5171 for (0..mask_len) |index| {
5174 const value = (try mask.elemValue(pt, index)).toSignedInt(zcu);5172 const value = (try mask.elemValue(pt, index)).toSignedInt(zcu);
51755173
5176 try func.emitWValue(result);5174 try cg.emitWValue(result);
51775175
5178 const loaded = if (value >= 0)5176 const loaded = if (value >= 0)
5179 try func.load(a, child_ty, @as(u32, @intCast(@as(i64, @intCast(elem_size)) * value)))5177 try cg.load(a, child_ty, @as(u32, @intCast(@as(i64, @intCast(elem_size)) * value)))
5180 else5178 else
5181 try func.load(b, child_ty, @as(u32, @intCast(@as(i64, @intCast(elem_size)) * ~value)));5179 try cg.load(b, child_ty, @as(u32, @intCast(@as(i64, @intCast(elem_size)) * ~value)));
51825180
5183 try func.store(.stack, loaded, child_ty, result.stack_offset.value + @as(u32, @intCast(elem_size)) * @as(u32, @intCast(index)));5181 try cg.store(.stack, loaded, child_ty, result.stack_offset.value + @as(u32, @intCast(elem_size)) * @as(u32, @intCast(index)));
5184 }5182 }
51855183
5186 return func.finishAir(inst, result, &.{ extra.a, extra.b });5184 return cg.finishAir(inst, result, &.{ extra.a, extra.b });
5187 } else {5185 } else {
5188 var operands = [_]u32{5186 var operands = [_]u32{
5189 @intFromEnum(std.wasm.SimdOpcode.i8x16_shuffle),5187 @intFromEnum(std.wasm.SimdOpcode.i8x16_shuffle),
...@@ -5202,91 +5200,91 @@ fn airShuffle(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -5202,91 +5200,91 @@ fn airShuffle(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
5202 }5200 }
5203 }5201 }
52045202
5205 try func.emitWValue(a);5203 try cg.emitWValue(a);
5206 try func.emitWValue(b);5204 try cg.emitWValue(b);
52075205
5208 const extra_index = @as(u32, @intCast(func.mir_extra.items.len));5206 const extra_index = @as(u32, @intCast(cg.mir_extra.items.len));
5209 try func.mir_extra.appendSlice(func.gpa, &operands);5207 try cg.mir_extra.appendSlice(cg.gpa, &operands);
5210 try func.addInst(.{ .tag = .simd_prefix, .data = .{ .payload = extra_index } });5208 try cg.addInst(.{ .tag = .simd_prefix, .data = .{ .payload = extra_index } });
52115209
5212 return func.finishAir(inst, .stack, &.{ extra.a, extra.b });5210 return cg.finishAir(inst, .stack, &.{ extra.a, extra.b });
5213 }5211 }
5214}5212}
52155213
5216fn airReduce(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {5214fn airReduce(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
5217 const reduce = func.air.instructions.items(.data)[@intFromEnum(inst)].reduce;5215 const reduce = cg.air.instructions.items(.data)[@intFromEnum(inst)].reduce;
5218 const operand = try func.resolveInst(reduce.operand);5216 const operand = try cg.resolveInst(reduce.operand);
52195217
5220 _ = operand;5218 _ = operand;
5221 return func.fail("TODO: Implement wasm airReduce", .{});5219 return cg.fail("TODO: Implement wasm airReduce", .{});
5222}5220}
52235221
5224fn airAggregateInit(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {5222fn airAggregateInit(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
5225 const pt = func.pt;5223 const pt = cg.pt;
5226 const zcu = pt.zcu;5224 const zcu = pt.zcu;
5227 const ip = &zcu.intern_pool;5225 const ip = &zcu.intern_pool;
5228 const ty_pl = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;5226 const ty_pl = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
5229 const result_ty = func.typeOfIndex(inst);5227 const result_ty = cg.typeOfIndex(inst);
5230 const len = @as(usize, @intCast(result_ty.arrayLen(zcu)));5228 const len = @as(usize, @intCast(result_ty.arrayLen(zcu)));
5231 const elements = @as([]const Air.Inst.Ref, @ptrCast(func.air.extra[ty_pl.payload..][0..len]));5229 const elements = @as([]const Air.Inst.Ref, @ptrCast(cg.air.extra[ty_pl.payload..][0..len]));
52325230
5233 const result: WValue = result_value: {5231 const result: WValue = result_value: {
5234 switch (result_ty.zigTypeTag(zcu)) {5232 switch (result_ty.zigTypeTag(zcu)) {
5235 .array => {5233 .array => {
5236 const result = try func.allocStack(result_ty);5234 const result = try cg.allocStack(result_ty);
5237 const elem_ty = result_ty.childType(zcu);5235 const elem_ty = result_ty.childType(zcu);
5238 const elem_size = @as(u32, @intCast(elem_ty.abiSize(zcu)));5236 const elem_size = @as(u32, @intCast(elem_ty.abiSize(zcu)));
5239 const sentinel = if (result_ty.sentinel(zcu)) |sent| blk: {5237 const sentinel = if (result_ty.sentinel(zcu)) |sent| blk: {
5240 break :blk try func.lowerConstant(sent, elem_ty);5238 break :blk try cg.lowerConstant(sent, elem_ty);
5241 } else null;5239 } else null;
52425240
5243 // When the element type is by reference, we must copy the entire5241 // When the element type is by reference, we must copy the entire
5244 // value. It is therefore safer to move the offset pointer and store5242 // value. It is therefore safer to move the offset pointer and store
5245 // each value individually, instead of using store offsets.5243 // each value individually, instead of using store offsets.
5246 if (isByRef(elem_ty, pt, func.target)) {5244 if (isByRef(elem_ty, pt, cg.target)) {
5247 // copy stack pointer into a temporary local, which is5245 // copy stack pointer into a temporary local, which is
5248 // moved for each element to store each value in the right position.5246 // moved for each element to store each value in the right position.
5249 const offset = try func.buildPointerOffset(result, 0, .new);5247 const offset = try cg.buildPointerOffset(result, 0, .new);
5250 for (elements, 0..) |elem, elem_index| {5248 for (elements, 0..) |elem, elem_index| {
5251 const elem_val = try func.resolveInst(elem);5249 const elem_val = try cg.resolveInst(elem);
5252 try func.store(offset, elem_val, elem_ty, 0);5250 try cg.store(offset, elem_val, elem_ty, 0);
52535251
5254 if (elem_index < elements.len - 1 and sentinel == null) {5252 if (elem_index < elements.len - 1 and sentinel == null) {
5255 _ = try func.buildPointerOffset(offset, elem_size, .modify);5253 _ = try cg.buildPointerOffset(offset, elem_size, .modify);
5256 }5254 }
5257 }5255 }
5258 if (sentinel) |sent| {5256 if (sentinel) |sent| {
5259 try func.store(offset, sent, elem_ty, 0);5257 try cg.store(offset, sent, elem_ty, 0);
5260 }5258 }
5261 } else {5259 } else {
5262 var offset: u32 = 0;5260 var offset: u32 = 0;
5263 for (elements) |elem| {5261 for (elements) |elem| {
5264 const elem_val = try func.resolveInst(elem);5262 const elem_val = try cg.resolveInst(elem);
5265 try func.store(result, elem_val, elem_ty, offset);5263 try cg.store(result, elem_val, elem_ty, offset);
5266 offset += elem_size;5264 offset += elem_size;
5267 }5265 }
5268 if (sentinel) |sent| {5266 if (sentinel) |sent| {
5269 try func.store(result, sent, elem_ty, offset);5267 try cg.store(result, sent, elem_ty, offset);
5270 }5268 }
5271 }5269 }
5272 break :result_value result;5270 break :result_value result;
5273 },5271 },
5274 .@"struct" => switch (result_ty.containerLayout(zcu)) {5272 .@"struct" => switch (result_ty.containerLayout(zcu)) {
5275 .@"packed" => {5273 .@"packed" => {
5276 if (isByRef(result_ty, pt, func.target)) {5274 if (isByRef(result_ty, pt, cg.target)) {
5277 return func.fail("TODO: airAggregateInit for packed structs larger than 64 bits", .{});5275 return cg.fail("TODO: airAggregateInit for packed structs larger than 64 bits", .{});
5278 }5276 }
5279 const packed_struct = zcu.typeToPackedStruct(result_ty).?;5277 const packed_struct = zcu.typeToPackedStruct(result_ty).?;
5280 const field_types = packed_struct.field_types;5278 const field_types = packed_struct.field_types;
5281 const backing_type = Type.fromInterned(packed_struct.backingIntTypeUnordered(ip));5279 const backing_type = Type.fromInterned(packed_struct.backingIntTypeUnordered(ip));
52825280
5283 // ensure the result is zero'd5281 // ensure the result is zero'd
5284 const result = try func.allocLocal(backing_type);5282 const result = try cg.allocLocal(backing_type);
5285 if (backing_type.bitSize(zcu) <= 32)5283 if (backing_type.bitSize(zcu) <= 32)
5286 try func.addImm32(0)5284 try cg.addImm32(0)
5287 else5285 else
5288 try func.addImm64(0);5286 try cg.addImm64(0);
5289 try func.addLabel(.local_set, result.local.value);5287 try cg.addLabel(.local_set, result.local.value);
52905288
5291 var current_bit: u16 = 0;5289 var current_bit: u16 = 0;
5292 for (elements, 0..) |elem, elem_index| {5290 for (elements, 0..) |elem, elem_index| {
...@@ -5298,46 +5296,46 @@ fn airAggregateInit(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -5298,46 +5296,46 @@ fn airAggregateInit(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
5298 else5296 else
5299 .{ .imm64 = current_bit };5297 .{ .imm64 = current_bit };
53005298
5301 const value = try func.resolveInst(elem);5299 const value = try cg.resolveInst(elem);
5302 const value_bit_size: u16 = @intCast(field_ty.bitSize(zcu));5300 const value_bit_size: u16 = @intCast(field_ty.bitSize(zcu));
5303 const int_ty = try pt.intType(.unsigned, value_bit_size);5301 const int_ty = try pt.intType(.unsigned, value_bit_size);
53045302
5305 // load our current result on stack so we can perform all transformations5303 // load our current result on stack so we can perform all transformations
5306 // using only stack values. Saving the cost of loads and stores.5304 // using only stack values. Saving the cost of loads and stores.
5307 try func.emitWValue(result);5305 try cg.emitWValue(result);
5308 const bitcasted = try func.bitcast(int_ty, field_ty, value);5306 const bitcasted = try cg.bitcast(int_ty, field_ty, value);
5309 const extended_val = try func.intcast(bitcasted, int_ty, backing_type);5307 const extended_val = try cg.intcast(bitcasted, int_ty, backing_type);
5310 // no need to shift any values when the current offset is 05308 // no need to shift any values when the current offset is 0
5311 const shifted = if (current_bit != 0) shifted: {5309 const shifted = if (current_bit != 0) shifted: {
5312 break :shifted try func.binOp(extended_val, shift_val, backing_type, .shl);5310 break :shifted try cg.binOp(extended_val, shift_val, backing_type, .shl);
5313 } else extended_val;5311 } else extended_val;
5314 // we ignore the result as we keep it on the stack to assign it directly to `result`5312 // we ignore the result as we keep it on the stack to assign it directly to `result`
5315 _ = try func.binOp(.stack, shifted, backing_type, .@"or");5313 _ = try cg.binOp(.stack, shifted, backing_type, .@"or");
5316 try func.addLabel(.local_set, result.local.value);5314 try cg.addLabel(.local_set, result.local.value);
5317 current_bit += value_bit_size;5315 current_bit += value_bit_size;
5318 }5316 }
5319 break :result_value result;5317 break :result_value result;
5320 },5318 },
5321 else => {5319 else => {
5322 const result = try func.allocStack(result_ty);5320 const result = try cg.allocStack(result_ty);
5323 const offset = try func.buildPointerOffset(result, 0, .new); // pointer to offset5321 const offset = try cg.buildPointerOffset(result, 0, .new); // pointer to offset
5324 var prev_field_offset: u64 = 0;5322 var prev_field_offset: u64 = 0;
5325 for (elements, 0..) |elem, elem_index| {5323 for (elements, 0..) |elem, elem_index| {
5326 if (try result_ty.structFieldValueComptime(pt, elem_index) != null) continue;5324 if (try result_ty.structFieldValueComptime(pt, elem_index) != null) continue;
53275325
5328 const elem_ty = result_ty.fieldType(elem_index, zcu);5326 const elem_ty = result_ty.fieldType(elem_index, zcu);
5329 const field_offset = result_ty.structFieldOffset(elem_index, zcu);5327 const field_offset = result_ty.structFieldOffset(elem_index, zcu);
5330 _ = try func.buildPointerOffset(offset, @intCast(field_offset - prev_field_offset), .modify);5328 _ = try cg.buildPointerOffset(offset, @intCast(field_offset - prev_field_offset), .modify);
5331 prev_field_offset = field_offset;5329 prev_field_offset = field_offset;
53325330
5333 const value = try func.resolveInst(elem);5331 const value = try cg.resolveInst(elem);
5334 try func.store(offset, value, elem_ty, 0);5332 try cg.store(offset, value, elem_ty, 0);
5335 }5333 }
53365334
5337 break :result_value result;5335 break :result_value result;
5338 },5336 },
5339 },5337 },
5340 .vector => return func.fail("TODO: Wasm backend: implement airAggregateInit for vectors", .{}),5338 .vector => return cg.fail("TODO: Wasm backend: implement airAggregateInit for vectors", .{}),
5341 else => unreachable,5339 else => unreachable,
5342 }5340 }
5343 };5341 };
...@@ -5345,22 +5343,22 @@ fn airAggregateInit(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -5345,22 +5343,22 @@ fn airAggregateInit(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
5345 if (elements.len <= Liveness.bpi - 1) {5343 if (elements.len <= Liveness.bpi - 1) {
5346 var buf = [1]Air.Inst.Ref{.none} ** (Liveness.bpi - 1);5344 var buf = [1]Air.Inst.Ref{.none} ** (Liveness.bpi - 1);
5347 @memcpy(buf[0..elements.len], elements);5345 @memcpy(buf[0..elements.len], elements);
5348 return func.finishAir(inst, result, &buf);5346 return cg.finishAir(inst, result, &buf);
5349 }5347 }
5350 var bt = try func.iterateBigTomb(inst, elements.len);5348 var bt = try cg.iterateBigTomb(inst, elements.len);
5351 for (elements) |arg| bt.feed(arg);5349 for (elements) |arg| bt.feed(arg);
5352 return bt.finishAir(result);5350 return bt.finishAir(result);
5353}5351}
53545352
5355fn airUnionInit(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {5353fn airUnionInit(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
5356 const pt = func.pt;5354 const pt = cg.pt;
5357 const zcu = pt.zcu;5355 const zcu = pt.zcu;
5358 const ip = &zcu.intern_pool;5356 const ip = &zcu.intern_pool;
5359 const ty_pl = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;5357 const ty_pl = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
5360 const extra = func.air.extraData(Air.UnionInit, ty_pl.payload).data;5358 const extra = cg.air.extraData(Air.UnionInit, ty_pl.payload).data;
53615359
5362 const result = result: {5360 const result = result: {
5363 const union_ty = func.typeOfIndex(inst);5361 const union_ty = cg.typeOfIndex(inst);
5364 const layout = union_ty.unionGetLayout(zcu);5362 const layout = union_ty.unionGetLayout(zcu);
5365 const union_obj = zcu.typeToUnion(union_ty).?;5363 const union_obj = zcu.typeToUnion(union_ty).?;
5366 const field_ty = Type.fromInterned(union_obj.field_types.get(ip)[extra.field_index]);5364 const field_ty = Type.fromInterned(union_obj.field_types.get(ip)[extra.field_index]);
...@@ -5370,34 +5368,34 @@ fn airUnionInit(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -5370,34 +5368,34 @@ fn airUnionInit(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
5370 const tag_ty = union_ty.unionTagTypeHypothetical(zcu);5368 const tag_ty = union_ty.unionTagTypeHypothetical(zcu);
5371 const enum_field_index = tag_ty.enumFieldIndex(field_name, zcu).?;5369 const enum_field_index = tag_ty.enumFieldIndex(field_name, zcu).?;
5372 const tag_val = try pt.enumValueFieldIndex(tag_ty, enum_field_index);5370 const tag_val = try pt.enumValueFieldIndex(tag_ty, enum_field_index);
5373 break :blk try func.lowerConstant(tag_val, tag_ty);5371 break :blk try cg.lowerConstant(tag_val, tag_ty);
5374 };5372 };
5375 if (layout.payload_size == 0) {5373 if (layout.payload_size == 0) {
5376 if (layout.tag_size == 0) {5374 if (layout.tag_size == 0) {
5377 break :result .none;5375 break :result .none;
5378 }5376 }
5379 assert(!isByRef(union_ty, pt, func.target));5377 assert(!isByRef(union_ty, pt, cg.target));
5380 break :result tag_int;5378 break :result tag_int;
5381 }5379 }
53825380
5383 if (isByRef(union_ty, pt, func.target)) {5381 if (isByRef(union_ty, pt, cg.target)) {
5384 const result_ptr = try func.allocStack(union_ty);5382 const result_ptr = try cg.allocStack(union_ty);
5385 const payload = try func.resolveInst(extra.init);5383 const payload = try cg.resolveInst(extra.init);
5386 if (layout.tag_align.compare(.gte, layout.payload_align)) {5384 if (layout.tag_align.compare(.gte, layout.payload_align)) {
5387 if (isByRef(field_ty, pt, func.target)) {5385 if (isByRef(field_ty, pt, cg.target)) {
5388 const payload_ptr = try func.buildPointerOffset(result_ptr, layout.tag_size, .new);5386 const payload_ptr = try cg.buildPointerOffset(result_ptr, layout.tag_size, .new);
5389 try func.store(payload_ptr, payload, field_ty, 0);5387 try cg.store(payload_ptr, payload, field_ty, 0);
5390 } else {5388 } else {
5391 try func.store(result_ptr, payload, field_ty, @intCast(layout.tag_size));5389 try cg.store(result_ptr, payload, field_ty, @intCast(layout.tag_size));
5392 }5390 }
53935391
5394 if (layout.tag_size > 0) {5392 if (layout.tag_size > 0) {
5395 try func.store(result_ptr, tag_int, Type.fromInterned(union_obj.enum_tag_ty), 0);5393 try cg.store(result_ptr, tag_int, Type.fromInterned(union_obj.enum_tag_ty), 0);
5396 }5394 }
5397 } else {5395 } else {
5398 try func.store(result_ptr, payload, field_ty, 0);5396 try cg.store(result_ptr, payload, field_ty, 0);
5399 if (layout.tag_size > 0) {5397 if (layout.tag_size > 0) {
5400 try func.store(5398 try cg.store(
5401 result_ptr,5399 result_ptr,
5402 tag_int,5400 tag_int,
5403 Type.fromInterned(union_obj.enum_tag_ty),5401 Type.fromInterned(union_obj.enum_tag_ty),
...@@ -5407,46 +5405,46 @@ fn airUnionInit(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -5407,46 +5405,46 @@ fn airUnionInit(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
5407 }5405 }
5408 break :result result_ptr;5406 break :result result_ptr;
5409 } else {5407 } else {
5410 const operand = try func.resolveInst(extra.init);5408 const operand = try cg.resolveInst(extra.init);
5411 const union_int_type = try pt.intType(.unsigned, @as(u16, @intCast(union_ty.bitSize(zcu))));5409 const union_int_type = try pt.intType(.unsigned, @as(u16, @intCast(union_ty.bitSize(zcu))));
5412 if (field_ty.zigTypeTag(zcu) == .float) {5410 if (field_ty.zigTypeTag(zcu) == .float) {
5413 const int_type = try pt.intType(.unsigned, @intCast(field_ty.bitSize(zcu)));5411 const int_type = try pt.intType(.unsigned, @intCast(field_ty.bitSize(zcu)));
5414 const bitcasted = try func.bitcast(field_ty, int_type, operand);5412 const bitcasted = try cg.bitcast(field_ty, int_type, operand);
5415 break :result try func.trunc(bitcasted, int_type, union_int_type);5413 break :result try cg.trunc(bitcasted, int_type, union_int_type);
5416 } else if (field_ty.isPtrAtRuntime(zcu)) {5414 } else if (field_ty.isPtrAtRuntime(zcu)) {
5417 const int_type = try pt.intType(.unsigned, @intCast(field_ty.bitSize(zcu)));5415 const int_type = try pt.intType(.unsigned, @intCast(field_ty.bitSize(zcu)));
5418 break :result try func.intcast(operand, int_type, union_int_type);5416 break :result try cg.intcast(operand, int_type, union_int_type);
5419 }5417 }
5420 break :result try func.intcast(operand, field_ty, union_int_type);5418 break :result try cg.intcast(operand, field_ty, union_int_type);
5421 }5419 }
5422 };5420 };
54235421
5424 return func.finishAir(inst, result, &.{extra.init});5422 return cg.finishAir(inst, result, &.{extra.init});
5425}5423}
54265424
5427fn airPrefetch(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {5425fn airPrefetch(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
5428 const prefetch = func.air.instructions.items(.data)[@intFromEnum(inst)].prefetch;5426 const prefetch = cg.air.instructions.items(.data)[@intFromEnum(inst)].prefetch;
5429 return func.finishAir(inst, .none, &.{prefetch.ptr});5427 return cg.finishAir(inst, .none, &.{prefetch.ptr});
5430}5428}
54315429
5432fn airWasmMemorySize(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {5430fn airWasmMemorySize(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
5433 const pl_op = func.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;5431 const pl_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;
54345432
5435 try func.addLabel(.memory_size, pl_op.payload);5433 try cg.addLabel(.memory_size, pl_op.payload);
5436 return func.finishAir(inst, .stack, &.{pl_op.operand});5434 return cg.finishAir(inst, .stack, &.{pl_op.operand});
5437}5435}
54385436
5439fn airWasmMemoryGrow(func: *CodeGen, inst: Air.Inst.Index) !void {5437fn airWasmMemoryGrow(cg: *CodeGen, inst: Air.Inst.Index) !void {
5440 const pl_op = func.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;5438 const pl_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;
54415439
5442 const operand = try func.resolveInst(pl_op.operand);5440 const operand = try cg.resolveInst(pl_op.operand);
5443 try func.emitWValue(operand);5441 try cg.emitWValue(operand);
5444 try func.addLabel(.memory_grow, pl_op.payload);5442 try cg.addLabel(.memory_grow, pl_op.payload);
5445 return func.finishAir(inst, .stack, &.{pl_op.operand});5443 return cg.finishAir(inst, .stack, &.{pl_op.operand});
5446}5444}
54475445
5448fn cmpOptionals(func: *CodeGen, lhs: WValue, rhs: WValue, operand_ty: Type, op: std.math.CompareOperator) InnerError!WValue {5446fn cmpOptionals(cg: *CodeGen, lhs: WValue, rhs: WValue, operand_ty: Type, op: std.math.CompareOperator) InnerError!WValue {
5449 const pt = func.pt;5447 const pt = cg.pt;
5450 const zcu = pt.zcu;5448 const zcu = pt.zcu;
5451 assert(operand_ty.hasRuntimeBitsIgnoreComptime(zcu));5449 assert(operand_ty.hasRuntimeBitsIgnoreComptime(zcu));
5452 assert(op == .eq or op == .neq);5450 assert(op == .eq or op == .neq);
...@@ -5454,91 +5452,91 @@ fn cmpOptionals(func: *CodeGen, lhs: WValue, rhs: WValue, operand_ty: Type, op:...@@ -5454,91 +5452,91 @@ fn cmpOptionals(func: *CodeGen, lhs: WValue, rhs: WValue, operand_ty: Type, op:
54545452
5455 // We store the final result in here that will be validated5453 // We store the final result in here that will be validated
5456 // if the optional is truly equal.5454 // if the optional is truly equal.
5457 var result = try func.ensureAllocLocal(Type.i32);5455 var result = try cg.ensureAllocLocal(Type.i32);
5458 defer result.free(func);5456 defer result.free(cg);
54595457
5460 try func.startBlock(.block, std.wasm.block_empty);5458 try cg.startBlock(.block, std.wasm.block_empty);
5461 _ = try func.isNull(lhs, operand_ty, .i32_eq);5459 _ = try cg.isNull(lhs, operand_ty, .i32_eq);
5462 _ = try func.isNull(rhs, operand_ty, .i32_eq);5460 _ = try cg.isNull(rhs, operand_ty, .i32_eq);
5463 try func.addTag(.i32_ne); // inverse so we can exit early5461 try cg.addTag(.i32_ne); // inverse so we can exit early
5464 try func.addLabel(.br_if, 0);5462 try cg.addLabel(.br_if, 0);
54655463
5466 _ = try func.load(lhs, payload_ty, 0);5464 _ = try cg.load(lhs, payload_ty, 0);
5467 _ = try func.load(rhs, payload_ty, 0);5465 _ = try cg.load(rhs, payload_ty, 0);
5468 const opcode = buildOpcode(.{ .op = .ne, .valtype1 = typeToValtype(payload_ty, pt, func.target) });5466 const opcode = buildOpcode(.{ .op = .ne, .valtype1 = typeToValtype(payload_ty, pt, cg.target) });
5469 try func.addTag(Mir.Inst.Tag.fromOpcode(opcode));5467 try cg.addTag(Mir.Inst.Tag.fromOpcode(opcode));
5470 try func.addLabel(.br_if, 0);5468 try cg.addLabel(.br_if, 0);
54715469
5472 try func.addImm32(1);5470 try cg.addImm32(1);
5473 try func.addLabel(.local_set, result.local.value);5471 try cg.addLabel(.local_set, result.local.value);
5474 try func.endBlock();5472 try cg.endBlock();
54755473
5476 try func.emitWValue(result);5474 try cg.emitWValue(result);
5477 try func.addImm32(0);5475 try cg.addImm32(0);
5478 try func.addTag(if (op == .eq) .i32_ne else .i32_eq);5476 try cg.addTag(if (op == .eq) .i32_ne else .i32_eq);
5479 return .stack;5477 return .stack;
5480}5478}
54815479
5482/// Compares big integers by checking both its high bits and low bits.5480/// Compares big integers by checking both its high bits and low bits.
5483/// NOTE: Leaves the result of the comparison on top of the stack.5481/// NOTE: Leaves the result of the comparison on top of the stack.
5484/// TODO: Lower this to compiler_rt call when bitsize > 1285482/// TODO: Lower this to compiler_rt call when bitsize > 128
5485fn cmpBigInt(func: *CodeGen, lhs: WValue, rhs: WValue, operand_ty: Type, op: std.math.CompareOperator) InnerError!WValue {5483fn cmpBigInt(cg: *CodeGen, lhs: WValue, rhs: WValue, operand_ty: Type, op: std.math.CompareOperator) InnerError!WValue {
5486 const pt = func.pt;5484 const pt = cg.pt;
5487 const zcu = pt.zcu;5485 const zcu = pt.zcu;
5488 assert(operand_ty.abiSize(zcu) >= 16);5486 assert(operand_ty.abiSize(zcu) >= 16);
5489 assert(!(lhs != .stack and rhs == .stack));5487 assert(!(lhs != .stack and rhs == .stack));
5490 if (operand_ty.bitSize(zcu) > 128) {5488 if (operand_ty.bitSize(zcu) > 128) {
5491 return func.fail("TODO: Support cmpBigInt for integer bitsize: '{d}'", .{operand_ty.bitSize(zcu)});5489 return cg.fail("TODO: Support cmpBigInt for integer bitsize: '{d}'", .{operand_ty.bitSize(zcu)});
5492 }5490 }
54935491
5494 var lhs_msb = try (try func.load(lhs, Type.u64, 8)).toLocal(func, Type.u64);5492 var lhs_msb = try (try cg.load(lhs, Type.u64, 8)).toLocal(cg, Type.u64);
5495 defer lhs_msb.free(func);5493 defer lhs_msb.free(cg);
5496 var rhs_msb = try (try func.load(rhs, Type.u64, 8)).toLocal(func, Type.u64);5494 var rhs_msb = try (try cg.load(rhs, Type.u64, 8)).toLocal(cg, Type.u64);
5497 defer rhs_msb.free(func);5495 defer rhs_msb.free(cg);
54985496
5499 switch (op) {5497 switch (op) {
5500 .eq, .neq => {5498 .eq, .neq => {
5501 const xor_high = try func.binOp(lhs_msb, rhs_msb, Type.u64, .xor);5499 const xor_high = try cg.binOp(lhs_msb, rhs_msb, Type.u64, .xor);
5502 const lhs_lsb = try func.load(lhs, Type.u64, 0);5500 const lhs_lsb = try cg.load(lhs, Type.u64, 0);
5503 const rhs_lsb = try func.load(rhs, Type.u64, 0);5501 const rhs_lsb = try cg.load(rhs, Type.u64, 0);
5504 const xor_low = try func.binOp(lhs_lsb, rhs_lsb, Type.u64, .xor);5502 const xor_low = try cg.binOp(lhs_lsb, rhs_lsb, Type.u64, .xor);
5505 const or_result = try func.binOp(xor_high, xor_low, Type.u64, .@"or");5503 const or_result = try cg.binOp(xor_high, xor_low, Type.u64, .@"or");
55065504
5507 switch (op) {5505 switch (op) {
5508 .eq => return func.cmp(or_result, .{ .imm64 = 0 }, Type.u64, .eq),5506 .eq => return cg.cmp(or_result, .{ .imm64 = 0 }, Type.u64, .eq),
5509 .neq => return func.cmp(or_result, .{ .imm64 = 0 }, Type.u64, .neq),5507 .neq => return cg.cmp(or_result, .{ .imm64 = 0 }, Type.u64, .neq),
5510 else => unreachable,5508 else => unreachable,
5511 }5509 }
5512 },5510 },
5513 else => {5511 else => {
5514 const ty = if (operand_ty.isSignedInt(zcu)) Type.i64 else Type.u64;5512 const ty = if (operand_ty.isSignedInt(zcu)) Type.i64 else Type.u64;
5515 // leave those value on top of the stack for '.select'5513 // leave those value on top of the stack for '.select'
5516 const lhs_lsb = try func.load(lhs, Type.u64, 0);5514 const lhs_lsb = try cg.load(lhs, Type.u64, 0);
5517 const rhs_lsb = try func.load(rhs, Type.u64, 0);5515 const rhs_lsb = try cg.load(rhs, Type.u64, 0);
5518 _ = try func.cmp(lhs_lsb, rhs_lsb, Type.u64, op);5516 _ = try cg.cmp(lhs_lsb, rhs_lsb, Type.u64, op);
5519 _ = try func.cmp(lhs_msb, rhs_msb, ty, op);5517 _ = try cg.cmp(lhs_msb, rhs_msb, ty, op);
5520 _ = try func.cmp(lhs_msb, rhs_msb, ty, .eq);5518 _ = try cg.cmp(lhs_msb, rhs_msb, ty, .eq);
5521 try func.addTag(.select);5519 try cg.addTag(.select);
5522 },5520 },
5523 }5521 }
55245522
5525 return .stack;5523 return .stack;
5526}5524}
55275525
5528fn airSetUnionTag(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {5526fn airSetUnionTag(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
5529 const pt = func.pt;5527 const pt = cg.pt;
5530 const zcu = pt.zcu;5528 const zcu = pt.zcu;
5531 const bin_op = func.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;5529 const bin_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
5532 const un_ty = func.typeOf(bin_op.lhs).childType(zcu);5530 const un_ty = cg.typeOf(bin_op.lhs).childType(zcu);
5533 const tag_ty = func.typeOf(bin_op.rhs);5531 const tag_ty = cg.typeOf(bin_op.rhs);
5534 const layout = un_ty.unionGetLayout(zcu);5532 const layout = un_ty.unionGetLayout(zcu);
5535 if (layout.tag_size == 0) return func.finishAir(inst, .none, &.{ bin_op.lhs, bin_op.rhs });5533 if (layout.tag_size == 0) return cg.finishAir(inst, .none, &.{ bin_op.lhs, bin_op.rhs });
55365534
5537 const union_ptr = try func.resolveInst(bin_op.lhs);5535 const union_ptr = try cg.resolveInst(bin_op.lhs);
5538 const new_tag = try func.resolveInst(bin_op.rhs);5536 const new_tag = try cg.resolveInst(bin_op.rhs);
5539 if (layout.payload_size == 0) {5537 if (layout.payload_size == 0) {
5540 try func.store(union_ptr, new_tag, tag_ty, 0);5538 try cg.store(union_ptr, new_tag, tag_ty, 0);
5541 return func.finishAir(inst, .none, &.{ bin_op.lhs, bin_op.rhs });5539 return cg.finishAir(inst, .none, &.{ bin_op.lhs, bin_op.rhs });
5542 }5540 }
55435541
5544 // when the tag alignment is smaller than the payload, the field will be stored5542 // when the tag alignment is smaller than the payload, the field will be stored
...@@ -5546,52 +5544,52 @@ fn airSetUnionTag(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -5546,52 +5544,52 @@ fn airSetUnionTag(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
5546 const offset: u32 = if (layout.tag_align.compare(.lt, layout.payload_align)) blk: {5544 const offset: u32 = if (layout.tag_align.compare(.lt, layout.payload_align)) blk: {
5547 break :blk @intCast(layout.payload_size);5545 break :blk @intCast(layout.payload_size);
5548 } else 0;5546 } else 0;
5549 try func.store(union_ptr, new_tag, tag_ty, offset);5547 try cg.store(union_ptr, new_tag, tag_ty, offset);
5550 return func.finishAir(inst, .none, &.{ bin_op.lhs, bin_op.rhs });5548 return cg.finishAir(inst, .none, &.{ bin_op.lhs, bin_op.rhs });
5551}5549}
55525550
5553fn airGetUnionTag(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {5551fn airGetUnionTag(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
5554 const zcu = func.pt.zcu;5552 const zcu = cg.pt.zcu;
5555 const ty_op = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;5553 const ty_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
55565554
5557 const un_ty = func.typeOf(ty_op.operand);5555 const un_ty = cg.typeOf(ty_op.operand);
5558 const tag_ty = func.typeOfIndex(inst);5556 const tag_ty = cg.typeOfIndex(inst);
5559 const layout = un_ty.unionGetLayout(zcu);5557 const layout = un_ty.unionGetLayout(zcu);
5560 if (layout.tag_size == 0) return func.finishAir(inst, .none, &.{ty_op.operand});5558 if (layout.tag_size == 0) return cg.finishAir(inst, .none, &.{ty_op.operand});
55615559
5562 const operand = try func.resolveInst(ty_op.operand);5560 const operand = try cg.resolveInst(ty_op.operand);
5563 // when the tag alignment is smaller than the payload, the field will be stored5561 // when the tag alignment is smaller than the payload, the field will be stored
5564 // after the payload.5562 // after the payload.
5565 const offset: u32 = if (layout.tag_align.compare(.lt, layout.payload_align))5563 const offset: u32 = if (layout.tag_align.compare(.lt, layout.payload_align))
5566 @intCast(layout.payload_size)5564 @intCast(layout.payload_size)
5567 else5565 else
5568 0;5566 0;
5569 const result = try func.load(operand, tag_ty, offset);5567 const result = try cg.load(operand, tag_ty, offset);
5570 return func.finishAir(inst, result, &.{ty_op.operand});5568 return cg.finishAir(inst, result, &.{ty_op.operand});
5571}5569}
55725570
5573fn airFpext(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {5571fn airFpext(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
5574 const ty_op = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;5572 const ty_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
55755573
5576 const dest_ty = func.typeOfIndex(inst);5574 const dest_ty = cg.typeOfIndex(inst);
5577 const operand = try func.resolveInst(ty_op.operand);5575 const operand = try cg.resolveInst(ty_op.operand);
5578 const result = try func.fpext(operand, func.typeOf(ty_op.operand), dest_ty);5576 const result = try cg.fpext(operand, cg.typeOf(ty_op.operand), dest_ty);
5579 return func.finishAir(inst, result, &.{ty_op.operand});5577 return cg.finishAir(inst, result, &.{ty_op.operand});
5580}5578}
55815579
5582/// Extends a float from a given `Type` to a larger wanted `Type`5580/// Extends a float from a given `Type` to a larger wanted `Type`
5583/// NOTE: Leaves the result on the stack5581/// NOTE: Leaves the result on the stack
5584fn fpext(func: *CodeGen, operand: WValue, given: Type, wanted: Type) InnerError!WValue {5582fn fpext(cg: *CodeGen, operand: WValue, given: Type, wanted: Type) InnerError!WValue {
5585 const given_bits = given.floatBits(func.target.*);5583 const given_bits = given.floatBits(cg.target.*);
5586 const wanted_bits = wanted.floatBits(func.target.*);5584 const wanted_bits = wanted.floatBits(cg.target.*);
55875585
5588 if (wanted_bits == 64 and given_bits == 32) {5586 if (wanted_bits == 64 and given_bits == 32) {
5589 try func.emitWValue(operand);5587 try cg.emitWValue(operand);
5590 try func.addTag(.f64_promote_f32);5588 try cg.addTag(.f64_promote_f32);
5591 return .stack;5589 return .stack;
5592 } else if (given_bits == 16 and wanted_bits <= 64) {5590 } else if (given_bits == 16 and wanted_bits <= 64) {
5593 // call __extendhfsf2(f16) f325591 // call __extendhfsf2(f16) f32
5594 const f32_result = try func.callIntrinsic(5592 const f32_result = try cg.callIntrinsic(
5595 "__extendhfsf2",5593 "__extendhfsf2",
5596 &.{.f16_type},5594 &.{.f16_type},
5597 Type.f32,5595 Type.f32,
...@@ -5600,7 +5598,7 @@ fn fpext(func: *CodeGen, operand: WValue, given: Type, wanted: Type) InnerError!...@@ -5600,7 +5598,7 @@ fn fpext(func: *CodeGen, operand: WValue, given: Type, wanted: Type) InnerError!
5600 assert(f32_result == .stack);5598 assert(f32_result == .stack);
56015599
5602 if (wanted_bits == 64) {5600 if (wanted_bits == 64) {
5603 try func.addTag(.f64_promote_f32);5601 try cg.addTag(.f64_promote_f32);
5604 }5602 }
5605 return .stack;5603 return .stack;
5606 }5604 }
...@@ -5611,37 +5609,37 @@ fn fpext(func: *CodeGen, operand: WValue, given: Type, wanted: Type) InnerError!...@@ -5611,37 +5609,37 @@ fn fpext(func: *CodeGen, operand: WValue, given: Type, wanted: Type) InnerError!
5611 target_util.compilerRtFloatAbbrev(wanted_bits),5609 target_util.compilerRtFloatAbbrev(wanted_bits),
5612 }) catch unreachable;5610 }) catch unreachable;
56135611
5614 return func.callIntrinsic(fn_name, &.{given.ip_index}, wanted, &.{operand});5612 return cg.callIntrinsic(fn_name, &.{given.ip_index}, wanted, &.{operand});
5615}5613}
56165614
5617fn airFptrunc(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {5615fn airFptrunc(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
5618 const ty_op = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;5616 const ty_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
56195617
5620 const dest_ty = func.typeOfIndex(inst);5618 const dest_ty = cg.typeOfIndex(inst);
5621 const operand = try func.resolveInst(ty_op.operand);5619 const operand = try cg.resolveInst(ty_op.operand);
5622 const result = try func.fptrunc(operand, func.typeOf(ty_op.operand), dest_ty);5620 const result = try cg.fptrunc(operand, cg.typeOf(ty_op.operand), dest_ty);
5623 return func.finishAir(inst, result, &.{ty_op.operand});5621 return cg.finishAir(inst, result, &.{ty_op.operand});
5624}5622}
56255623
5626/// Truncates a float from a given `Type` to its wanted `Type`5624/// Truncates a float from a given `Type` to its wanted `Type`
5627/// NOTE: The result value remains on the stack5625/// NOTE: The result value remains on the stack
5628fn fptrunc(func: *CodeGen, operand: WValue, given: Type, wanted: Type) InnerError!WValue {5626fn fptrunc(cg: *CodeGen, operand: WValue, given: Type, wanted: Type) InnerError!WValue {
5629 const given_bits = given.floatBits(func.target.*);5627 const given_bits = given.floatBits(cg.target.*);
5630 const wanted_bits = wanted.floatBits(func.target.*);5628 const wanted_bits = wanted.floatBits(cg.target.*);
56315629
5632 if (wanted_bits == 32 and given_bits == 64) {5630 if (wanted_bits == 32 and given_bits == 64) {
5633 try func.emitWValue(operand);5631 try cg.emitWValue(operand);
5634 try func.addTag(.f32_demote_f64);5632 try cg.addTag(.f32_demote_f64);
5635 return .stack;5633 return .stack;
5636 } else if (wanted_bits == 16 and given_bits <= 64) {5634 } else if (wanted_bits == 16 and given_bits <= 64) {
5637 const op: WValue = if (given_bits == 64) blk: {5635 const op: WValue = if (given_bits == 64) blk: {
5638 try func.emitWValue(operand);5636 try cg.emitWValue(operand);
5639 try func.addTag(.f32_demote_f64);5637 try cg.addTag(.f32_demote_f64);
5640 break :blk .stack;5638 break :blk .stack;
5641 } else operand;5639 } else operand;
56425640
5643 // call __truncsfhf2(f32) f165641 // call __truncsfhf2(f32) f16
5644 return func.callIntrinsic("__truncsfhf2", &.{.f32_type}, Type.f16, &.{op});5642 return cg.callIntrinsic("__truncsfhf2", &.{.f32_type}, Type.f16, &.{op});
5645 }5643 }
56465644
5647 var fn_name_buf: [12]u8 = undefined;5645 var fn_name_buf: [12]u8 = undefined;
...@@ -5650,20 +5648,20 @@ fn fptrunc(func: *CodeGen, operand: WValue, given: Type, wanted: Type) InnerErro...@@ -5650,20 +5648,20 @@ fn fptrunc(func: *CodeGen, operand: WValue, given: Type, wanted: Type) InnerErro
5650 target_util.compilerRtFloatAbbrev(wanted_bits),5648 target_util.compilerRtFloatAbbrev(wanted_bits),
5651 }) catch unreachable;5649 }) catch unreachable;
56525650
5653 return func.callIntrinsic(fn_name, &.{given.ip_index}, wanted, &.{operand});5651 return cg.callIntrinsic(fn_name, &.{given.ip_index}, wanted, &.{operand});
5654}5652}
56555653
5656fn airErrUnionPayloadPtrSet(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {5654fn airErrUnionPayloadPtrSet(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
5657 const pt = func.pt;5655 const pt = cg.pt;
5658 const zcu = pt.zcu;5656 const zcu = pt.zcu;
5659 const ty_op = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;5657 const ty_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
56605658
5661 const err_set_ty = func.typeOf(ty_op.operand).childType(zcu);5659 const err_set_ty = cg.typeOf(ty_op.operand).childType(zcu);
5662 const payload_ty = err_set_ty.errorUnionPayload(zcu);5660 const payload_ty = err_set_ty.errorUnionPayload(zcu);
5663 const operand = try func.resolveInst(ty_op.operand);5661 const operand = try cg.resolveInst(ty_op.operand);
56645662
5665 // set error-tag to '0' to annotate error union is non-error5663 // set error-tag to '0' to annotate error union is non-error
5666 try func.store(5664 try cg.store(
5667 operand,5665 operand,
5668 .{ .imm32 = 0 },5666 .{ .imm32 = 0 },
5669 Type.anyerror,5667 Type.anyerror,
...@@ -5672,63 +5670,63 @@ fn airErrUnionPayloadPtrSet(func: *CodeGen, inst: Air.Inst.Index) InnerError!voi...@@ -5672,63 +5670,63 @@ fn airErrUnionPayloadPtrSet(func: *CodeGen, inst: Air.Inst.Index) InnerError!voi
56725670
5673 const result = result: {5671 const result = result: {
5674 if (!payload_ty.hasRuntimeBitsIgnoreComptime(zcu)) {5672 if (!payload_ty.hasRuntimeBitsIgnoreComptime(zcu)) {
5675 break :result func.reuseOperand(ty_op.operand, operand);5673 break :result cg.reuseOperand(ty_op.operand, operand);
5676 }5674 }
56775675
5678 break :result try func.buildPointerOffset(operand, @as(u32, @intCast(errUnionPayloadOffset(payload_ty, zcu))), .new);5676 break :result try cg.buildPointerOffset(operand, @as(u32, @intCast(errUnionPayloadOffset(payload_ty, zcu))), .new);
5679 };5677 };
5680 return func.finishAir(inst, result, &.{ty_op.operand});5678 return cg.finishAir(inst, result, &.{ty_op.operand});
5681}5679}
56825680
5683fn airFieldParentPtr(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {5681fn airFieldParentPtr(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
5684 const pt = func.pt;5682 const pt = cg.pt;
5685 const zcu = pt.zcu;5683 const zcu = pt.zcu;
5686 const ty_pl = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;5684 const ty_pl = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
5687 const extra = func.air.extraData(Air.FieldParentPtr, ty_pl.payload).data;5685 const extra = cg.air.extraData(Air.FieldParentPtr, ty_pl.payload).data;
56885686
5689 const field_ptr = try func.resolveInst(extra.field_ptr);5687 const field_ptr = try cg.resolveInst(extra.field_ptr);
5690 const parent_ty = ty_pl.ty.toType().childType(zcu);5688 const parent_ty = ty_pl.ty.toType().childType(zcu);
5691 const field_offset = parent_ty.structFieldOffset(extra.field_index, zcu);5689 const field_offset = parent_ty.structFieldOffset(extra.field_index, zcu);
56925690
5693 const result = if (field_offset != 0) result: {5691 const result = if (field_offset != 0) result: {
5694 const base = try func.buildPointerOffset(field_ptr, 0, .new);5692 const base = try cg.buildPointerOffset(field_ptr, 0, .new);
5695 try func.addLabel(.local_get, base.local.value);5693 try cg.addLabel(.local_get, base.local.value);
5696 try func.addImm32(@intCast(field_offset));5694 try cg.addImm32(@intCast(field_offset));
5697 try func.addTag(.i32_sub);5695 try cg.addTag(.i32_sub);
5698 try func.addLabel(.local_set, base.local.value);5696 try cg.addLabel(.local_set, base.local.value);
5699 break :result base;5697 break :result base;
5700 } else func.reuseOperand(extra.field_ptr, field_ptr);5698 } else cg.reuseOperand(extra.field_ptr, field_ptr);
57015699
5702 return func.finishAir(inst, result, &.{extra.field_ptr});5700 return cg.finishAir(inst, result, &.{extra.field_ptr});
5703}5701}
57045702
5705fn sliceOrArrayPtr(func: *CodeGen, ptr: WValue, ptr_ty: Type) InnerError!WValue {5703fn sliceOrArrayPtr(cg: *CodeGen, ptr: WValue, ptr_ty: Type) InnerError!WValue {
5706 const pt = func.pt;5704 const pt = cg.pt;
5707 const zcu = pt.zcu;5705 const zcu = pt.zcu;
5708 if (ptr_ty.isSlice(zcu)) {5706 if (ptr_ty.isSlice(zcu)) {
5709 return func.slicePtr(ptr);5707 return cg.slicePtr(ptr);
5710 } else {5708 } else {
5711 return ptr;5709 return ptr;
5712 }5710 }
5713}5711}
57145712
5715fn airMemcpy(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {5713fn airMemcpy(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
5716 const pt = func.pt;5714 const pt = cg.pt;
5717 const zcu = pt.zcu;5715 const zcu = pt.zcu;
5718 const bin_op = func.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;5716 const bin_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
5719 const dst = try func.resolveInst(bin_op.lhs);5717 const dst = try cg.resolveInst(bin_op.lhs);
5720 const dst_ty = func.typeOf(bin_op.lhs);5718 const dst_ty = cg.typeOf(bin_op.lhs);
5721 const ptr_elem_ty = dst_ty.childType(zcu);5719 const ptr_elem_ty = dst_ty.childType(zcu);
5722 const src = try func.resolveInst(bin_op.rhs);5720 const src = try cg.resolveInst(bin_op.rhs);
5723 const src_ty = func.typeOf(bin_op.rhs);5721 const src_ty = cg.typeOf(bin_op.rhs);
5724 const len = switch (dst_ty.ptrSize(zcu)) {5722 const len = switch (dst_ty.ptrSize(zcu)) {
5725 .Slice => blk: {5723 .Slice => blk: {
5726 const slice_len = try func.sliceLen(dst);5724 const slice_len = try cg.sliceLen(dst);
5727 if (ptr_elem_ty.abiSize(zcu) != 1) {5725 if (ptr_elem_ty.abiSize(zcu) != 1) {
5728 try func.emitWValue(slice_len);5726 try cg.emitWValue(slice_len);
5729 try func.emitWValue(.{ .imm32 = @as(u32, @intCast(ptr_elem_ty.abiSize(zcu))) });5727 try cg.emitWValue(.{ .imm32 = @as(u32, @intCast(ptr_elem_ty.abiSize(zcu))) });
5730 try func.addTag(.i32_mul);5728 try cg.addTag(.i32_mul);
5731 try func.addLabel(.local_set, slice_len.local.value);5729 try cg.addLabel(.local_set, slice_len.local.value);
5732 }5730 }
5733 break :blk slice_len;5731 break :blk slice_len;
5734 },5732 },
...@@ -5737,94 +5735,94 @@ fn airMemcpy(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -5737,94 +5735,94 @@ fn airMemcpy(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
5737 }),5735 }),
5738 .C, .Many => unreachable,5736 .C, .Many => unreachable,
5739 };5737 };
5740 const dst_ptr = try func.sliceOrArrayPtr(dst, dst_ty);5738 const dst_ptr = try cg.sliceOrArrayPtr(dst, dst_ty);
5741 const src_ptr = try func.sliceOrArrayPtr(src, src_ty);5739 const src_ptr = try cg.sliceOrArrayPtr(src, src_ty);
5742 try func.memcpy(dst_ptr, src_ptr, len);5740 try cg.memcpy(dst_ptr, src_ptr, len);
57435741
5744 return func.finishAir(inst, .none, &.{ bin_op.lhs, bin_op.rhs });5742 return cg.finishAir(inst, .none, &.{ bin_op.lhs, bin_op.rhs });
5745}5743}
57465744
5747fn airRetAddr(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {5745fn airRetAddr(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
5748 // TODO: Implement this properly once stack serialization is solved5746 // TODO: Implement this properly once stack serialization is solved
5749 return func.finishAir(inst, switch (func.ptr_size) {5747 return cg.finishAir(inst, switch (cg.ptr_size) {
5750 .wasm32 => .{ .imm32 = 0 },5748 .wasm32 => .{ .imm32 = 0 },
5751 .wasm64 => .{ .imm64 = 0 },5749 .wasm64 => .{ .imm64 = 0 },
5752 }, &.{});5750 }, &.{});
5753}5751}
57545752
5755fn airPopcount(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {5753fn airPopcount(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
5756 const pt = func.pt;5754 const pt = cg.pt;
5757 const zcu = pt.zcu;5755 const zcu = pt.zcu;
5758 const ty_op = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;5756 const ty_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
57595757
5760 const operand = try func.resolveInst(ty_op.operand);5758 const operand = try cg.resolveInst(ty_op.operand);
5761 const op_ty = func.typeOf(ty_op.operand);5759 const op_ty = cg.typeOf(ty_op.operand);
57625760
5763 if (op_ty.zigTypeTag(zcu) == .vector) {5761 if (op_ty.zigTypeTag(zcu) == .vector) {
5764 return func.fail("TODO: Implement @popCount for vectors", .{});5762 return cg.fail("TODO: Implement @popCount for vectors", .{});
5765 }5763 }
57665764
5767 const int_info = op_ty.intInfo(zcu);5765 const int_info = op_ty.intInfo(zcu);
5768 const bits = int_info.bits;5766 const bits = int_info.bits;
5769 const wasm_bits = toWasmBits(bits) orelse {5767 const wasm_bits = toWasmBits(bits) orelse {
5770 return func.fail("TODO: Implement @popCount for integers with bitsize '{d}'", .{bits});5768 return cg.fail("TODO: Implement @popCount for integers with bitsize '{d}'", .{bits});
5771 };5769 };
57725770
5773 switch (wasm_bits) {5771 switch (wasm_bits) {
5774 32 => {5772 32 => {
5775 try func.emitWValue(operand);5773 try cg.emitWValue(operand);
5776 if (op_ty.isSignedInt(zcu) and bits != wasm_bits) {5774 if (op_ty.isSignedInt(zcu) and bits != wasm_bits) {
5777 _ = try func.wrapOperand(.stack, try pt.intType(.unsigned, bits));5775 _ = try cg.wrapOperand(.stack, try pt.intType(.unsigned, bits));
5778 }5776 }
5779 try func.addTag(.i32_popcnt);5777 try cg.addTag(.i32_popcnt);
5780 },5778 },
5781 64 => {5779 64 => {
5782 try func.emitWValue(operand);5780 try cg.emitWValue(operand);
5783 if (op_ty.isSignedInt(zcu) and bits != wasm_bits) {5781 if (op_ty.isSignedInt(zcu) and bits != wasm_bits) {
5784 _ = try func.wrapOperand(.stack, try pt.intType(.unsigned, bits));5782 _ = try cg.wrapOperand(.stack, try pt.intType(.unsigned, bits));
5785 }5783 }
5786 try func.addTag(.i64_popcnt);5784 try cg.addTag(.i64_popcnt);
5787 try func.addTag(.i32_wrap_i64);5785 try cg.addTag(.i32_wrap_i64);
5788 try func.emitWValue(operand);5786 try cg.emitWValue(operand);
5789 },5787 },
5790 128 => {5788 128 => {
5791 _ = try func.load(operand, Type.u64, 0);5789 _ = try cg.load(operand, Type.u64, 0);
5792 try func.addTag(.i64_popcnt);5790 try cg.addTag(.i64_popcnt);
5793 _ = try func.load(operand, Type.u64, 8);5791 _ = try cg.load(operand, Type.u64, 8);
5794 if (op_ty.isSignedInt(zcu) and bits != wasm_bits) {5792 if (op_ty.isSignedInt(zcu) and bits != wasm_bits) {
5795 _ = try func.wrapOperand(.stack, try pt.intType(.unsigned, bits - 64));5793 _ = try cg.wrapOperand(.stack, try pt.intType(.unsigned, bits - 64));
5796 }5794 }
5797 try func.addTag(.i64_popcnt);5795 try cg.addTag(.i64_popcnt);
5798 try func.addTag(.i64_add);5796 try cg.addTag(.i64_add);
5799 try func.addTag(.i32_wrap_i64);5797 try cg.addTag(.i32_wrap_i64);
5800 },5798 },
5801 else => unreachable,5799 else => unreachable,
5802 }5800 }
58035801
5804 return func.finishAir(inst, .stack, &.{ty_op.operand});5802 return cg.finishAir(inst, .stack, &.{ty_op.operand});
5805}5803}
58065804
5807fn airBitReverse(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {5805fn airBitReverse(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
5808 const pt = func.pt;5806 const pt = cg.pt;
5809 const zcu = pt.zcu;5807 const zcu = pt.zcu;
5810 const ty_op = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;5808 const ty_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
58115809
5812 const operand = try func.resolveInst(ty_op.operand);5810 const operand = try cg.resolveInst(ty_op.operand);
5813 const ty = func.typeOf(ty_op.operand);5811 const ty = cg.typeOf(ty_op.operand);
58145812
5815 if (ty.zigTypeTag(zcu) == .vector) {5813 if (ty.zigTypeTag(zcu) == .vector) {
5816 return func.fail("TODO: Implement @bitReverse for vectors", .{});5814 return cg.fail("TODO: Implement @bitReverse for vectors", .{});
5817 }5815 }
58185816
5819 const int_info = ty.intInfo(zcu);5817 const int_info = ty.intInfo(zcu);
5820 const bits = int_info.bits;5818 const bits = int_info.bits;
5821 const wasm_bits = toWasmBits(bits) orelse {5819 const wasm_bits = toWasmBits(bits) orelse {
5822 return func.fail("TODO: Implement @bitReverse for integers with bitsize '{d}'", .{bits});5820 return cg.fail("TODO: Implement @bitReverse for integers with bitsize '{d}'", .{bits});
5823 };5821 };
58245822
5825 switch (wasm_bits) {5823 switch (wasm_bits) {
5826 32 => {5824 32 => {
5827 const intrin_ret = try func.callIntrinsic(5825 const intrin_ret = try cg.callIntrinsic(
5828 "__bitreversesi2",5826 "__bitreversesi2",
5829 &.{.u32_type},5827 &.{.u32_type},
5830 Type.u32,5828 Type.u32,
...@@ -5833,11 +5831,11 @@ fn airBitReverse(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -5833,11 +5831,11 @@ fn airBitReverse(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
5833 const result = if (bits == 32)5831 const result = if (bits == 32)
5834 intrin_ret5832 intrin_ret
5835 else5833 else
5836 try func.binOp(intrin_ret, .{ .imm32 = 32 - bits }, ty, .shr);5834 try cg.binOp(intrin_ret, .{ .imm32 = 32 - bits }, ty, .shr);
5837 return func.finishAir(inst, result, &.{ty_op.operand});5835 return cg.finishAir(inst, result, &.{ty_op.operand});
5838 },5836 },
5839 64 => {5837 64 => {
5840 const intrin_ret = try func.callIntrinsic(5838 const intrin_ret = try cg.callIntrinsic(
5841 "__bitreversedi2",5839 "__bitreversedi2",
5842 &.{.u64_type},5840 &.{.u64_type},
5843 Type.u64,5841 Type.u64,
...@@ -5846,64 +5844,64 @@ fn airBitReverse(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -5846,64 +5844,64 @@ fn airBitReverse(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
5846 const result = if (bits == 64)5844 const result = if (bits == 64)
5847 intrin_ret5845 intrin_ret
5848 else5846 else
5849 try func.binOp(intrin_ret, .{ .imm64 = 64 - bits }, ty, .shr);5847 try cg.binOp(intrin_ret, .{ .imm64 = 64 - bits }, ty, .shr);
5850 return func.finishAir(inst, result, &.{ty_op.operand});5848 return cg.finishAir(inst, result, &.{ty_op.operand});
5851 },5849 },
5852 128 => {5850 128 => {
5853 const result = try func.allocStack(ty);5851 const result = try cg.allocStack(ty);
58545852
5855 try func.emitWValue(result);5853 try cg.emitWValue(result);
5856 const first_half = try func.load(operand, Type.u64, 8);5854 const first_half = try cg.load(operand, Type.u64, 8);
5857 const intrin_ret_first = try func.callIntrinsic(5855 const intrin_ret_first = try cg.callIntrinsic(
5858 "__bitreversedi2",5856 "__bitreversedi2",
5859 &.{.u64_type},5857 &.{.u64_type},
5860 Type.u64,5858 Type.u64,
5861 &.{first_half},5859 &.{first_half},
5862 );5860 );
5863 try func.emitWValue(intrin_ret_first);5861 try cg.emitWValue(intrin_ret_first);
5864 if (bits < 128) {5862 if (bits < 128) {
5865 try func.emitWValue(.{ .imm64 = 128 - bits });5863 try cg.emitWValue(.{ .imm64 = 128 - bits });
5866 try func.addTag(.i64_shr_u);5864 try cg.addTag(.i64_shr_u);
5867 }5865 }
5868 try func.emitWValue(result);5866 try cg.emitWValue(result);
5869 const second_half = try func.load(operand, Type.u64, 0);5867 const second_half = try cg.load(operand, Type.u64, 0);
5870 const intrin_ret_second = try func.callIntrinsic(5868 const intrin_ret_second = try cg.callIntrinsic(
5871 "__bitreversedi2",5869 "__bitreversedi2",
5872 &.{.u64_type},5870 &.{.u64_type},
5873 Type.u64,5871 Type.u64,
5874 &.{second_half},5872 &.{second_half},
5875 );5873 );
5876 try func.emitWValue(intrin_ret_second);5874 try cg.emitWValue(intrin_ret_second);
5877 if (bits == 128) {5875 if (bits == 128) {
5878 try func.store(.stack, .stack, Type.u64, result.offset() + 8);5876 try cg.store(.stack, .stack, Type.u64, result.offset() + 8);
5879 try func.store(.stack, .stack, Type.u64, result.offset());5877 try cg.store(.stack, .stack, Type.u64, result.offset());
5880 } else {5878 } else {
5881 var tmp = try func.allocLocal(Type.u64);5879 var tmp = try cg.allocLocal(Type.u64);
5882 defer tmp.free(func);5880 defer tmp.free(cg);
5883 try func.addLabel(.local_tee, tmp.local.value);5881 try cg.addLabel(.local_tee, tmp.local.value);
5884 try func.emitWValue(.{ .imm64 = 128 - bits });5882 try cg.emitWValue(.{ .imm64 = 128 - bits });
5885 if (ty.isSignedInt(zcu)) {5883 if (ty.isSignedInt(zcu)) {
5886 try func.addTag(.i64_shr_s);5884 try cg.addTag(.i64_shr_s);
5887 } else {5885 } else {
5888 try func.addTag(.i64_shr_u);5886 try cg.addTag(.i64_shr_u);
5889 }5887 }
5890 try func.store(.stack, .stack, Type.u64, result.offset() + 8);5888 try cg.store(.stack, .stack, Type.u64, result.offset() + 8);
5891 try func.addLabel(.local_get, tmp.local.value);5889 try cg.addLabel(.local_get, tmp.local.value);
5892 try func.emitWValue(.{ .imm64 = bits - 64 });5890 try cg.emitWValue(.{ .imm64 = bits - 64 });
5893 try func.addTag(.i64_shl);5891 try cg.addTag(.i64_shl);
5894 try func.addTag(.i64_or);5892 try cg.addTag(.i64_or);
5895 try func.store(.stack, .stack, Type.u64, result.offset());5893 try cg.store(.stack, .stack, Type.u64, result.offset());
5896 }5894 }
5897 return func.finishAir(inst, result, &.{ty_op.operand});5895 return cg.finishAir(inst, result, &.{ty_op.operand});
5898 },5896 },
5899 else => unreachable,5897 else => unreachable,
5900 }5898 }
5901}5899}
59025900
5903fn airErrorName(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {5901fn airErrorName(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
5904 const un_op = func.air.instructions.items(.data)[@intFromEnum(inst)].un_op;5902 const un_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].un_op;
59055903
5906 const operand = try func.resolveInst(un_op);5904 const operand = try cg.resolveInst(un_op);
5907 // First retrieve the symbol index to the error name table5905 // First retrieve the symbol index to the error name table
5908 // that will be used to emit a relocation for the pointer5906 // that will be used to emit a relocation for the pointer
5909 // to the error name table.5907 // to the error name table.
...@@ -5915,81 +5913,81 @@ fn airErrorName(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -5915,81 +5913,81 @@ fn airErrorName(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
5915 //5913 //
5916 // As the names are global and the slice elements are constant, we do not have5914 // As the names are global and the slice elements are constant, we do not have
5917 // to make a copy of the ptr+value but can point towards them directly.5915 // to make a copy of the ptr+value but can point towards them directly.
5918 const pt = func.pt;5916 const pt = cg.pt;
5919 const error_table_symbol = try func.wasm.getErrorTableSymbol(pt);5917 const error_table_symbol = try cg.wasm.getErrorTableSymbol(pt);
5920 const name_ty = Type.slice_const_u8_sentinel_0;5918 const name_ty = Type.slice_const_u8_sentinel_0;
5921 const abi_size = name_ty.abiSize(pt.zcu);5919 const abi_size = name_ty.abiSize(pt.zcu);
59225920
5923 const error_name_value: WValue = .{ .memory = error_table_symbol }; // emitting this will create a relocation5921 const error_name_value: WValue = .{ .memory = error_table_symbol }; // emitting this will create a relocation
5924 try func.emitWValue(error_name_value);5922 try cg.emitWValue(error_name_value);
5925 try func.emitWValue(operand);5923 try cg.emitWValue(operand);
5926 switch (func.ptr_size) {5924 switch (cg.ptr_size) {
5927 .wasm32 => {5925 .wasm32 => {
5928 try func.addImm32(@intCast(abi_size));5926 try cg.addImm32(@intCast(abi_size));
5929 try func.addTag(.i32_mul);5927 try cg.addTag(.i32_mul);
5930 try func.addTag(.i32_add);5928 try cg.addTag(.i32_add);
5931 },5929 },
5932 .wasm64 => {5930 .wasm64 => {
5933 try func.addImm64(abi_size);5931 try cg.addImm64(abi_size);
5934 try func.addTag(.i64_mul);5932 try cg.addTag(.i64_mul);
5935 try func.addTag(.i64_add);5933 try cg.addTag(.i64_add);
5936 },5934 },
5937 }5935 }
59385936
5939 return func.finishAir(inst, .stack, &.{un_op});5937 return cg.finishAir(inst, .stack, &.{un_op});
5940}5938}
59415939
5942fn airPtrSliceFieldPtr(func: *CodeGen, inst: Air.Inst.Index, offset: u32) InnerError!void {5940fn airPtrSliceFieldPtr(cg: *CodeGen, inst: Air.Inst.Index, offset: u32) InnerError!void {
5943 const ty_op = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;5941 const ty_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
5944 const slice_ptr = try func.resolveInst(ty_op.operand);5942 const slice_ptr = try cg.resolveInst(ty_op.operand);
5945 const result = try func.buildPointerOffset(slice_ptr, offset, .new);5943 const result = try cg.buildPointerOffset(slice_ptr, offset, .new);
5946 return func.finishAir(inst, result, &.{ty_op.operand});5944 return cg.finishAir(inst, result, &.{ty_op.operand});
5947}5945}
59485946
5949/// NOTE: Allocates place for result on virtual stack, when integer size > 64 bits5947/// NOTE: Allocates place for result on virtual stack, when integer size > 64 bits
5950fn intZeroValue(func: *CodeGen, ty: Type) InnerError!WValue {5948fn intZeroValue(cg: *CodeGen, ty: Type) InnerError!WValue {
5951 const zcu = func.wasm.base.comp.zcu.?;5949 const zcu = cg.wasm.base.comp.zcu.?;
5952 const int_info = ty.intInfo(zcu);5950 const int_info = ty.intInfo(zcu);
5953 const wasm_bits = toWasmBits(int_info.bits) orelse {5951 const wasm_bits = toWasmBits(int_info.bits) orelse {
5954 return func.fail("TODO: Implement intZeroValue for integer bitsize: {d}", .{int_info.bits});5952 return cg.fail("TODO: Implement intZeroValue for integer bitsize: {d}", .{int_info.bits});
5955 };5953 };
5956 switch (wasm_bits) {5954 switch (wasm_bits) {
5957 32 => return .{ .imm32 = 0 },5955 32 => return .{ .imm32 = 0 },
5958 64 => return .{ .imm64 = 0 },5956 64 => return .{ .imm64 = 0 },
5959 128 => {5957 128 => {
5960 const result = try func.allocStack(ty);5958 const result = try cg.allocStack(ty);
5961 try func.store(result, .{ .imm64 = 0 }, Type.u64, 0);5959 try cg.store(result, .{ .imm64 = 0 }, Type.u64, 0);
5962 try func.store(result, .{ .imm64 = 0 }, Type.u64, 8);5960 try cg.store(result, .{ .imm64 = 0 }, Type.u64, 8);
5963 return result;5961 return result;
5964 },5962 },
5965 else => unreachable,5963 else => unreachable,
5966 }5964 }
5967}5965}
59685966
5969fn airAddSubWithOverflow(func: *CodeGen, inst: Air.Inst.Index, op: Op) InnerError!void {5967fn airAddSubWithOverflow(cg: *CodeGen, inst: Air.Inst.Index, op: Op) InnerError!void {
5970 assert(op == .add or op == .sub);5968 assert(op == .add or op == .sub);
5971 const ty_pl = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;5969 const ty_pl = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
5972 const extra = func.air.extraData(Air.Bin, ty_pl.payload).data;5970 const extra = cg.air.extraData(Air.Bin, ty_pl.payload).data;
59735971
5974 const lhs = try func.resolveInst(extra.lhs);5972 const lhs = try cg.resolveInst(extra.lhs);
5975 const rhs = try func.resolveInst(extra.rhs);5973 const rhs = try cg.resolveInst(extra.rhs);
5976 const ty = func.typeOf(extra.lhs);5974 const ty = cg.typeOf(extra.lhs);
5977 const pt = func.pt;5975 const pt = cg.pt;
5978 const zcu = pt.zcu;5976 const zcu = pt.zcu;
59795977
5980 if (ty.zigTypeTag(zcu) == .vector) {5978 if (ty.zigTypeTag(zcu) == .vector) {
5981 return func.fail("TODO: Implement overflow arithmetic for vectors", .{});5979 return cg.fail("TODO: Implement overflow arithmetic for vectors", .{});
5982 }5980 }
59835981
5984 const int_info = ty.intInfo(zcu);5982 const int_info = ty.intInfo(zcu);
5985 const is_signed = int_info.signedness == .signed;5983 const is_signed = int_info.signedness == .signed;
5986 if (int_info.bits > 128) {5984 if (int_info.bits > 128) {
5987 return func.fail("TODO: Implement {{add/sub}}_with_overflow for integer bitsize: {d}", .{int_info.bits});5985 return cg.fail("TODO: Implement {{add/sub}}_with_overflow for integer bitsize: {d}", .{int_info.bits});
5988 }5986 }
59895987
5990 const op_result = try func.wrapBinOp(lhs, rhs, ty, op);5988 const op_result = try cg.wrapBinOp(lhs, rhs, ty, op);
5991 var op_tmp = try op_result.toLocal(func, ty);5989 var op_tmp = try op_result.toLocal(cg, ty);
5992 defer op_tmp.free(func);5990 defer op_tmp.free(cg);
59935991
5994 const cmp_op: std.math.CompareOperator = switch (op) {5992 const cmp_op: std.math.CompareOperator = switch (op) {
5995 .add => .lt,5993 .add => .lt,
...@@ -5997,40 +5995,40 @@ fn airAddSubWithOverflow(func: *CodeGen, inst: Air.Inst.Index, op: Op) InnerErro...@@ -5997,40 +5995,40 @@ fn airAddSubWithOverflow(func: *CodeGen, inst: Air.Inst.Index, op: Op) InnerErro
5997 else => unreachable,5995 else => unreachable,
5998 };5996 };
5999 const overflow_bit = if (is_signed) blk: {5997 const overflow_bit = if (is_signed) blk: {
6000 const zero = try intZeroValue(func, ty);5998 const zero = try intZeroValue(cg, ty);
6001 const rhs_is_neg = try func.cmp(rhs, zero, ty, .lt);5999 const rhs_is_neg = try cg.cmp(rhs, zero, ty, .lt);
6002 const overflow_cmp = try func.cmp(op_tmp, lhs, ty, cmp_op);6000 const overflow_cmp = try cg.cmp(op_tmp, lhs, ty, cmp_op);
6003 break :blk try func.cmp(rhs_is_neg, overflow_cmp, Type.u1, .neq);6001 break :blk try cg.cmp(rhs_is_neg, overflow_cmp, Type.u1, .neq);
6004 } else try func.cmp(op_tmp, lhs, ty, cmp_op);6002 } else try cg.cmp(op_tmp, lhs, ty, cmp_op);
6005 var bit_tmp = try overflow_bit.toLocal(func, Type.u1);6003 var bit_tmp = try overflow_bit.toLocal(cg, Type.u1);
6006 defer bit_tmp.free(func);6004 defer bit_tmp.free(cg);
60076005
6008 const result = try func.allocStack(func.typeOfIndex(inst));6006 const result = try cg.allocStack(cg.typeOfIndex(inst));
6009 const offset: u32 = @intCast(ty.abiSize(zcu));6007 const offset: u32 = @intCast(ty.abiSize(zcu));
6010 try func.store(result, op_tmp, ty, 0);6008 try cg.store(result, op_tmp, ty, 0);
6011 try func.store(result, bit_tmp, Type.u1, offset);6009 try cg.store(result, bit_tmp, Type.u1, offset);
60126010
6013 return func.finishAir(inst, result, &.{ extra.lhs, extra.rhs });6011 return cg.finishAir(inst, result, &.{ extra.lhs, extra.rhs });
6014}6012}
60156013
6016fn airShlWithOverflow(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {6014fn airShlWithOverflow(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
6017 const pt = func.pt;6015 const pt = cg.pt;
6018 const zcu = pt.zcu;6016 const zcu = pt.zcu;
6019 const ty_pl = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;6017 const ty_pl = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
6020 const extra = func.air.extraData(Air.Bin, ty_pl.payload).data;6018 const extra = cg.air.extraData(Air.Bin, ty_pl.payload).data;
60216019
6022 const lhs = try func.resolveInst(extra.lhs);6020 const lhs = try cg.resolveInst(extra.lhs);
6023 const rhs = try func.resolveInst(extra.rhs);6021 const rhs = try cg.resolveInst(extra.rhs);
6024 const ty = func.typeOf(extra.lhs);6022 const ty = cg.typeOf(extra.lhs);
6025 const rhs_ty = func.typeOf(extra.rhs);6023 const rhs_ty = cg.typeOf(extra.rhs);
60266024
6027 if (ty.zigTypeTag(zcu) == .vector) {6025 if (ty.zigTypeTag(zcu) == .vector) {
6028 return func.fail("TODO: Implement overflow arithmetic for vectors", .{});6026 return cg.fail("TODO: Implement overflow arithmetic for vectors", .{});
6029 }6027 }
60306028
6031 const int_info = ty.intInfo(zcu);6029 const int_info = ty.intInfo(zcu);
6032 const wasm_bits = toWasmBits(int_info.bits) orelse {6030 const wasm_bits = toWasmBits(int_info.bits) orelse {
6033 return func.fail("TODO: Implement shl_with_overflow for integer bitsize: {d}", .{int_info.bits});6031 return cg.fail("TODO: Implement shl_with_overflow for integer bitsize: {d}", .{int_info.bits});
6034 };6032 };
60356033
6036 // Ensure rhs is coerced to lhs as they must have the same WebAssembly types6034 // Ensure rhs is coerced to lhs as they must have the same WebAssembly types
...@@ -6038,50 +6036,50 @@ fn airShlWithOverflow(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -6038,50 +6036,50 @@ fn airShlWithOverflow(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
6038 const rhs_wasm_bits = toWasmBits(rhs_ty.intInfo(zcu).bits).?;6036 const rhs_wasm_bits = toWasmBits(rhs_ty.intInfo(zcu).bits).?;
6039 // If wasm_bits == 128, compiler-rt expects i32 for shift6037 // If wasm_bits == 128, compiler-rt expects i32 for shift
6040 const rhs_final = if (wasm_bits != rhs_wasm_bits and wasm_bits == 64) blk: {6038 const rhs_final = if (wasm_bits != rhs_wasm_bits and wasm_bits == 64) blk: {
6041 const rhs_casted = try func.intcast(rhs, rhs_ty, ty);6039 const rhs_casted = try cg.intcast(rhs, rhs_ty, ty);
6042 break :blk try rhs_casted.toLocal(func, ty);6040 break :blk try rhs_casted.toLocal(cg, ty);
6043 } else rhs;6041 } else rhs;
60446042
6045 var shl = try (try func.wrapBinOp(lhs, rhs_final, ty, .shl)).toLocal(func, ty);6043 var shl = try (try cg.wrapBinOp(lhs, rhs_final, ty, .shl)).toLocal(cg, ty);
6046 defer shl.free(func);6044 defer shl.free(cg);
60476045
6048 const overflow_bit = blk: {6046 const overflow_bit = blk: {
6049 const shr = try func.binOp(shl, rhs_final, ty, .shr);6047 const shr = try cg.binOp(shl, rhs_final, ty, .shr);
6050 break :blk try func.cmp(shr, lhs, ty, .neq);6048 break :blk try cg.cmp(shr, lhs, ty, .neq);
6051 };6049 };
6052 var overflow_local = try overflow_bit.toLocal(func, Type.u1);6050 var overflow_local = try overflow_bit.toLocal(cg, Type.u1);
6053 defer overflow_local.free(func);6051 defer overflow_local.free(cg);
60546052
6055 const result = try func.allocStack(func.typeOfIndex(inst));6053 const result = try cg.allocStack(cg.typeOfIndex(inst));
6056 const offset: u32 = @intCast(ty.abiSize(zcu));6054 const offset: u32 = @intCast(ty.abiSize(zcu));
6057 try func.store(result, shl, ty, 0);6055 try cg.store(result, shl, ty, 0);
6058 try func.store(result, overflow_local, Type.u1, offset);6056 try cg.store(result, overflow_local, Type.u1, offset);
60596057
6060 return func.finishAir(inst, result, &.{ extra.lhs, extra.rhs });6058 return cg.finishAir(inst, result, &.{ extra.lhs, extra.rhs });
6061}6059}
60626060
6063fn airMulWithOverflow(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {6061fn airMulWithOverflow(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
6064 const ty_pl = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;6062 const ty_pl = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
6065 const extra = func.air.extraData(Air.Bin, ty_pl.payload).data;6063 const extra = cg.air.extraData(Air.Bin, ty_pl.payload).data;
60666064
6067 const lhs = try func.resolveInst(extra.lhs);6065 const lhs = try cg.resolveInst(extra.lhs);
6068 const rhs = try func.resolveInst(extra.rhs);6066 const rhs = try cg.resolveInst(extra.rhs);
6069 const ty = func.typeOf(extra.lhs);6067 const ty = cg.typeOf(extra.lhs);
6070 const pt = func.pt;6068 const pt = cg.pt;
6071 const zcu = pt.zcu;6069 const zcu = pt.zcu;
60726070
6073 if (ty.zigTypeTag(zcu) == .vector) {6071 if (ty.zigTypeTag(zcu) == .vector) {
6074 return func.fail("TODO: Implement overflow arithmetic for vectors", .{});6072 return cg.fail("TODO: Implement overflow arithmetic for vectors", .{});
6075 }6073 }
60766074
6077 // We store the bit if it's overflowed or not in this. As it's zero-initialized6075 // We store the bit if it's overflowed or not in this. As it's zero-initialized
6078 // we only need to update it if an overflow (or underflow) occurred.6076 // we only need to update it if an overflow (or underflow) occurred.
6079 var overflow_bit = try func.ensureAllocLocal(Type.u1);6077 var overflow_bit = try cg.ensureAllocLocal(Type.u1);
6080 defer overflow_bit.free(func);6078 defer overflow_bit.free(cg);
60816079
6082 const int_info = ty.intInfo(zcu);6080 const int_info = ty.intInfo(zcu);
6083 const wasm_bits = toWasmBits(int_info.bits) orelse {6081 const wasm_bits = toWasmBits(int_info.bits) orelse {
6084 return func.fail("TODO: Implement `@mulWithOverflow` for integer bitsize: {d}", .{int_info.bits});6082 return cg.fail("TODO: Implement `@mulWithOverflow` for integer bitsize: {d}", .{int_info.bits});
6085 };6083 };
60866084
6087 const zero: WValue = switch (wasm_bits) {6085 const zero: WValue = switch (wasm_bits) {
...@@ -6093,248 +6091,248 @@ fn airMulWithOverflow(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -6093,248 +6091,248 @@ fn airMulWithOverflow(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
6093 // for 32 bit integers we upcast it to a 64bit integer6091 // for 32 bit integers we upcast it to a 64bit integer
6094 const mul = if (wasm_bits == 32) blk: {6092 const mul = if (wasm_bits == 32) blk: {
6095 const new_ty = if (int_info.signedness == .signed) Type.i64 else Type.u64;6093 const new_ty = if (int_info.signedness == .signed) Type.i64 else Type.u64;
6096 const lhs_upcast = try func.intcast(lhs, ty, new_ty);6094 const lhs_upcast = try cg.intcast(lhs, ty, new_ty);
6097 const rhs_upcast = try func.intcast(rhs, ty, new_ty);6095 const rhs_upcast = try cg.intcast(rhs, ty, new_ty);
6098 const bin_op = try (try func.binOp(lhs_upcast, rhs_upcast, new_ty, .mul)).toLocal(func, new_ty);6096 const bin_op = try (try cg.binOp(lhs_upcast, rhs_upcast, new_ty, .mul)).toLocal(cg, new_ty);
6099 const res = try (try func.trunc(bin_op, ty, new_ty)).toLocal(func, ty);6097 const res = try (try cg.trunc(bin_op, ty, new_ty)).toLocal(cg, ty);
6100 const res_upcast = try func.intcast(res, ty, new_ty);6098 const res_upcast = try cg.intcast(res, ty, new_ty);
6101 _ = try func.cmp(res_upcast, bin_op, new_ty, .neq);6099 _ = try cg.cmp(res_upcast, bin_op, new_ty, .neq);
6102 try func.addLabel(.local_set, overflow_bit.local.value);6100 try cg.addLabel(.local_set, overflow_bit.local.value);
6103 break :blk res;6101 break :blk res;
6104 } else if (wasm_bits == 64) blk: {6102 } else if (wasm_bits == 64) blk: {
6105 const new_ty = if (int_info.signedness == .signed) Type.i128 else Type.u128;6103 const new_ty = if (int_info.signedness == .signed) Type.i128 else Type.u128;
6106 const lhs_upcast = try func.intcast(lhs, ty, new_ty);6104 const lhs_upcast = try cg.intcast(lhs, ty, new_ty);
6107 const rhs_upcast = try func.intcast(rhs, ty, new_ty);6105 const rhs_upcast = try cg.intcast(rhs, ty, new_ty);
6108 const bin_op = try (try func.binOp(lhs_upcast, rhs_upcast, new_ty, .mul)).toLocal(func, new_ty);6106 const bin_op = try (try cg.binOp(lhs_upcast, rhs_upcast, new_ty, .mul)).toLocal(cg, new_ty);
6109 const res = try (try func.trunc(bin_op, ty, new_ty)).toLocal(func, ty);6107 const res = try (try cg.trunc(bin_op, ty, new_ty)).toLocal(cg, ty);
6110 const res_upcast = try func.intcast(res, ty, new_ty);6108 const res_upcast = try cg.intcast(res, ty, new_ty);
6111 _ = try func.cmp(res_upcast, bin_op, new_ty, .neq);6109 _ = try cg.cmp(res_upcast, bin_op, new_ty, .neq);
6112 try func.addLabel(.local_set, overflow_bit.local.value);6110 try cg.addLabel(.local_set, overflow_bit.local.value);
6113 break :blk res;6111 break :blk res;
6114 } else if (int_info.bits == 128 and int_info.signedness == .unsigned) blk: {6112 } else if (int_info.bits == 128 and int_info.signedness == .unsigned) blk: {
6115 var lhs_lsb = try (try func.load(lhs, Type.u64, 0)).toLocal(func, Type.u64);6113 var lhs_lsb = try (try cg.load(lhs, Type.u64, 0)).toLocal(cg, Type.u64);
6116 defer lhs_lsb.free(func);6114 defer lhs_lsb.free(cg);
6117 var lhs_msb = try (try func.load(lhs, Type.u64, 8)).toLocal(func, Type.u64);6115 var lhs_msb = try (try cg.load(lhs, Type.u64, 8)).toLocal(cg, Type.u64);
6118 defer lhs_msb.free(func);6116 defer lhs_msb.free(cg);
6119 var rhs_lsb = try (try func.load(rhs, Type.u64, 0)).toLocal(func, Type.u64);6117 var rhs_lsb = try (try cg.load(rhs, Type.u64, 0)).toLocal(cg, Type.u64);
6120 defer rhs_lsb.free(func);6118 defer rhs_lsb.free(cg);
6121 var rhs_msb = try (try func.load(rhs, Type.u64, 8)).toLocal(func, Type.u64);6119 var rhs_msb = try (try cg.load(rhs, Type.u64, 8)).toLocal(cg, Type.u64);
6122 defer rhs_msb.free(func);6120 defer rhs_msb.free(cg);
61236121
6124 const cross_1 = try func.callIntrinsic(6122 const cross_1 = try cg.callIntrinsic(
6125 "__multi3",6123 "__multi3",
6126 &[_]InternPool.Index{.i64_type} ** 4,6124 &[_]InternPool.Index{.i64_type} ** 4,
6127 Type.i128,6125 Type.i128,
6128 &.{ lhs_msb, zero, rhs_lsb, zero },6126 &.{ lhs_msb, zero, rhs_lsb, zero },
6129 );6127 );
6130 const cross_2 = try func.callIntrinsic(6128 const cross_2 = try cg.callIntrinsic(
6131 "__multi3",6129 "__multi3",
6132 &[_]InternPool.Index{.i64_type} ** 4,6130 &[_]InternPool.Index{.i64_type} ** 4,
6133 Type.i128,6131 Type.i128,
6134 &.{ rhs_msb, zero, lhs_lsb, zero },6132 &.{ rhs_msb, zero, lhs_lsb, zero },
6135 );6133 );
6136 const mul_lsb = try func.callIntrinsic(6134 const mul_lsb = try cg.callIntrinsic(
6137 "__multi3",6135 "__multi3",
6138 &[_]InternPool.Index{.i64_type} ** 4,6136 &[_]InternPool.Index{.i64_type} ** 4,
6139 Type.i128,6137 Type.i128,
6140 &.{ rhs_lsb, zero, lhs_lsb, zero },6138 &.{ rhs_lsb, zero, lhs_lsb, zero },
6141 );6139 );
61426140
6143 const rhs_msb_not_zero = try func.cmp(rhs_msb, zero, Type.u64, .neq);6141 const rhs_msb_not_zero = try cg.cmp(rhs_msb, zero, Type.u64, .neq);
6144 const lhs_msb_not_zero = try func.cmp(lhs_msb, zero, Type.u64, .neq);6142 const lhs_msb_not_zero = try cg.cmp(lhs_msb, zero, Type.u64, .neq);
6145 const both_msb_not_zero = try func.binOp(rhs_msb_not_zero, lhs_msb_not_zero, Type.bool, .@"and");6143 const both_msb_not_zero = try cg.binOp(rhs_msb_not_zero, lhs_msb_not_zero, Type.bool, .@"and");
6146 const cross_1_msb = try func.load(cross_1, Type.u64, 8);6144 const cross_1_msb = try cg.load(cross_1, Type.u64, 8);
6147 const cross_1_msb_not_zero = try func.cmp(cross_1_msb, zero, Type.u64, .neq);6145 const cross_1_msb_not_zero = try cg.cmp(cross_1_msb, zero, Type.u64, .neq);
6148 const cond_1 = try func.binOp(both_msb_not_zero, cross_1_msb_not_zero, Type.bool, .@"or");6146 const cond_1 = try cg.binOp(both_msb_not_zero, cross_1_msb_not_zero, Type.bool, .@"or");
6149 const cross_2_msb = try func.load(cross_2, Type.u64, 8);6147 const cross_2_msb = try cg.load(cross_2, Type.u64, 8);
6150 const cross_2_msb_not_zero = try func.cmp(cross_2_msb, zero, Type.u64, .neq);6148 const cross_2_msb_not_zero = try cg.cmp(cross_2_msb, zero, Type.u64, .neq);
6151 const cond_2 = try func.binOp(cond_1, cross_2_msb_not_zero, Type.bool, .@"or");6149 const cond_2 = try cg.binOp(cond_1, cross_2_msb_not_zero, Type.bool, .@"or");
61526150
6153 const cross_1_lsb = try func.load(cross_1, Type.u64, 0);6151 const cross_1_lsb = try cg.load(cross_1, Type.u64, 0);
6154 const cross_2_lsb = try func.load(cross_2, Type.u64, 0);6152 const cross_2_lsb = try cg.load(cross_2, Type.u64, 0);
6155 const cross_add = try func.binOp(cross_1_lsb, cross_2_lsb, Type.u64, .add);6153 const cross_add = try cg.binOp(cross_1_lsb, cross_2_lsb, Type.u64, .add);
61566154
6157 var mul_lsb_msb = try (try func.load(mul_lsb, Type.u64, 8)).toLocal(func, Type.u64);6155 var mul_lsb_msb = try (try cg.load(mul_lsb, Type.u64, 8)).toLocal(cg, Type.u64);
6158 defer mul_lsb_msb.free(func);6156 defer mul_lsb_msb.free(cg);
6159 var all_add = try (try func.binOp(cross_add, mul_lsb_msb, Type.u64, .add)).toLocal(func, Type.u64);6157 var all_add = try (try cg.binOp(cross_add, mul_lsb_msb, Type.u64, .add)).toLocal(cg, Type.u64);
6160 defer all_add.free(func);6158 defer all_add.free(cg);
6161 const add_overflow = try func.cmp(all_add, mul_lsb_msb, Type.u64, .lt);6159 const add_overflow = try cg.cmp(all_add, mul_lsb_msb, Type.u64, .lt);
61626160
6163 // result for overflow bit6161 // result for overflow bit
6164 _ = try func.binOp(cond_2, add_overflow, Type.bool, .@"or");6162 _ = try cg.binOp(cond_2, add_overflow, Type.bool, .@"or");
6165 try func.addLabel(.local_set, overflow_bit.local.value);6163 try cg.addLabel(.local_set, overflow_bit.local.value);
61666164
6167 const tmp_result = try func.allocStack(Type.u128);6165 const tmp_result = try cg.allocStack(Type.u128);
6168 try func.emitWValue(tmp_result);6166 try cg.emitWValue(tmp_result);
6169 const mul_lsb_lsb = try func.load(mul_lsb, Type.u64, 0);6167 const mul_lsb_lsb = try cg.load(mul_lsb, Type.u64, 0);
6170 try func.store(.stack, mul_lsb_lsb, Type.u64, tmp_result.offset());6168 try cg.store(.stack, mul_lsb_lsb, Type.u64, tmp_result.offset());
6171 try func.store(tmp_result, all_add, Type.u64, 8);6169 try cg.store(tmp_result, all_add, Type.u64, 8);
6172 break :blk tmp_result;6170 break :blk tmp_result;
6173 } else if (int_info.bits == 128 and int_info.signedness == .signed) blk: {6171 } else if (int_info.bits == 128 and int_info.signedness == .signed) blk: {
6174 const overflow_ret = try func.allocStack(Type.i32);6172 const overflow_ret = try cg.allocStack(Type.i32);
6175 const res = try func.callIntrinsic(6173 const res = try cg.callIntrinsic(
6176 "__muloti4",6174 "__muloti4",
6177 &[_]InternPool.Index{ .i128_type, .i128_type, .usize_type },6175 &[_]InternPool.Index{ .i128_type, .i128_type, .usize_type },
6178 Type.i128,6176 Type.i128,
6179 &.{ lhs, rhs, overflow_ret },6177 &.{ lhs, rhs, overflow_ret },
6180 );6178 );
6181 _ = try func.load(overflow_ret, Type.i32, 0);6179 _ = try cg.load(overflow_ret, Type.i32, 0);
6182 try func.addLabel(.local_set, overflow_bit.local.value);6180 try cg.addLabel(.local_set, overflow_bit.local.value);
6183 break :blk res;6181 break :blk res;
6184 } else return func.fail("TODO: @mulWithOverflow for {}", .{ty.fmt(pt)});6182 } else return cg.fail("TODO: @mulWithOverflow for {}", .{ty.fmt(pt)});
6185 var bin_op_local = try mul.toLocal(func, ty);6183 var bin_op_local = try mul.toLocal(cg, ty);
6186 defer bin_op_local.free(func);6184 defer bin_op_local.free(cg);
61876185
6188 const result = try func.allocStack(func.typeOfIndex(inst));6186 const result = try cg.allocStack(cg.typeOfIndex(inst));
6189 const offset: u32 = @intCast(ty.abiSize(zcu));6187 const offset: u32 = @intCast(ty.abiSize(zcu));
6190 try func.store(result, bin_op_local, ty, 0);6188 try cg.store(result, bin_op_local, ty, 0);
6191 try func.store(result, overflow_bit, Type.u1, offset);6189 try cg.store(result, overflow_bit, Type.u1, offset);
61926190
6193 return func.finishAir(inst, result, &.{ extra.lhs, extra.rhs });6191 return cg.finishAir(inst, result, &.{ extra.lhs, extra.rhs });
6194}6192}
61956193
6196fn airMaxMin(func: *CodeGen, inst: Air.Inst.Index, op: Op) InnerError!void {6194fn airMaxMin(cg: *CodeGen, inst: Air.Inst.Index, op: Op) InnerError!void {
6197 assert(op == .max or op == .min);6195 assert(op == .max or op == .min);
6198 const pt = func.pt;6196 const pt = cg.pt;
6199 const zcu = pt.zcu;6197 const zcu = pt.zcu;
6200 const bin_op = func.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;6198 const bin_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
62016199
6202 const ty = func.typeOfIndex(inst);6200 const ty = cg.typeOfIndex(inst);
6203 if (ty.zigTypeTag(zcu) == .vector) {6201 if (ty.zigTypeTag(zcu) == .vector) {
6204 return func.fail("TODO: `@maximum` and `@minimum` for vectors", .{});6202 return cg.fail("TODO: `@maximum` and `@minimum` for vectors", .{});
6205 }6203 }
62066204
6207 if (ty.abiSize(zcu) > 16) {6205 if (ty.abiSize(zcu) > 16) {
6208 return func.fail("TODO: `@maximum` and `@minimum` for types larger than 16 bytes", .{});6206 return cg.fail("TODO: `@maximum` and `@minimum` for types larger than 16 bytes", .{});
6209 }6207 }
62106208
6211 const lhs = try func.resolveInst(bin_op.lhs);6209 const lhs = try cg.resolveInst(bin_op.lhs);
6212 const rhs = try func.resolveInst(bin_op.rhs);6210 const rhs = try cg.resolveInst(bin_op.rhs);
62136211
6214 if (ty.zigTypeTag(zcu) == .float) {6212 if (ty.zigTypeTag(zcu) == .float) {
6215 var fn_name_buf: [64]u8 = undefined;6213 var fn_name_buf: [64]u8 = undefined;
6216 const float_bits = ty.floatBits(func.target.*);6214 const float_bits = ty.floatBits(cg.target.*);
6217 const fn_name = std.fmt.bufPrint(&fn_name_buf, "{s}f{s}{s}", .{6215 const fn_name = std.fmt.bufPrint(&fn_name_buf, "{s}f{s}{s}", .{
6218 target_util.libcFloatPrefix(float_bits),6216 target_util.libcFloatPrefix(float_bits),
6219 @tagName(op),6217 @tagName(op),
6220 target_util.libcFloatSuffix(float_bits),6218 target_util.libcFloatSuffix(float_bits),
6221 }) catch unreachable;6219 }) catch unreachable;
6222 const result = try func.callIntrinsic(fn_name, &.{ ty.ip_index, ty.ip_index }, ty, &.{ lhs, rhs });6220 const result = try cg.callIntrinsic(fn_name, &.{ ty.ip_index, ty.ip_index }, ty, &.{ lhs, rhs });
6223 try func.lowerToStack(result);6221 try cg.lowerToStack(result);
6224 } else {6222 } else {
6225 // operands to select from6223 // operands to select from
6226 try func.lowerToStack(lhs);6224 try cg.lowerToStack(lhs);
6227 try func.lowerToStack(rhs);6225 try cg.lowerToStack(rhs);
6228 _ = try func.cmp(lhs, rhs, ty, if (op == .max) .gt else .lt);6226 _ = try cg.cmp(lhs, rhs, ty, if (op == .max) .gt else .lt);
62296227
6230 // based on the result from comparison, return operand 0 or 1.6228 // based on the result from comparison, return operand 0 or 1.
6231 try func.addTag(.select);6229 try cg.addTag(.select);
6232 }6230 }
62336231
6234 return func.finishAir(inst, .stack, &.{ bin_op.lhs, bin_op.rhs });6232 return cg.finishAir(inst, .stack, &.{ bin_op.lhs, bin_op.rhs });
6235}6233}
62366234
6237fn airMulAdd(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {6235fn airMulAdd(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
6238 const pt = func.pt;6236 const pt = cg.pt;
6239 const zcu = pt.zcu;6237 const zcu = pt.zcu;
6240 const pl_op = func.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;6238 const pl_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;
6241 const bin_op = func.air.extraData(Air.Bin, pl_op.payload).data;6239 const bin_op = cg.air.extraData(Air.Bin, pl_op.payload).data;
62426240
6243 const ty = func.typeOfIndex(inst);6241 const ty = cg.typeOfIndex(inst);
6244 if (ty.zigTypeTag(zcu) == .vector) {6242 if (ty.zigTypeTag(zcu) == .vector) {
6245 return func.fail("TODO: `@mulAdd` for vectors", .{});6243 return cg.fail("TODO: `@mulAdd` for vectors", .{});
6246 }6244 }
62476245
6248 const addend = try func.resolveInst(pl_op.operand);6246 const addend = try cg.resolveInst(pl_op.operand);
6249 const lhs = try func.resolveInst(bin_op.lhs);6247 const lhs = try cg.resolveInst(bin_op.lhs);
6250 const rhs = try func.resolveInst(bin_op.rhs);6248 const rhs = try cg.resolveInst(bin_op.rhs);
62516249
6252 const result = if (ty.floatBits(func.target.*) == 16) fl_result: {6250 const result = if (ty.floatBits(cg.target.*) == 16) fl_result: {
6253 const rhs_ext = try func.fpext(rhs, ty, Type.f32);6251 const rhs_ext = try cg.fpext(rhs, ty, Type.f32);
6254 const lhs_ext = try func.fpext(lhs, ty, Type.f32);6252 const lhs_ext = try cg.fpext(lhs, ty, Type.f32);
6255 const addend_ext = try func.fpext(addend, ty, Type.f32);6253 const addend_ext = try cg.fpext(addend, ty, Type.f32);
6256 // call to compiler-rt `fn fmaf(f32, f32, f32) f32`6254 // call to compiler-rt `fn fmaf(f32, f32, f32) f32`
6257 const result = try func.callIntrinsic(6255 const result = try cg.callIntrinsic(
6258 "fmaf",6256 "fmaf",
6259 &.{ .f32_type, .f32_type, .f32_type },6257 &.{ .f32_type, .f32_type, .f32_type },
6260 Type.f32,6258 Type.f32,
6261 &.{ rhs_ext, lhs_ext, addend_ext },6259 &.{ rhs_ext, lhs_ext, addend_ext },
6262 );6260 );
6263 break :fl_result try func.fptrunc(result, Type.f32, ty);6261 break :fl_result try cg.fptrunc(result, Type.f32, ty);
6264 } else result: {6262 } else result: {
6265 const mul_result = try func.binOp(lhs, rhs, ty, .mul);6263 const mul_result = try cg.binOp(lhs, rhs, ty, .mul);
6266 break :result try func.binOp(mul_result, addend, ty, .add);6264 break :result try cg.binOp(mul_result, addend, ty, .add);
6267 };6265 };
62686266
6269 return func.finishAir(inst, result, &.{ bin_op.lhs, bin_op.rhs, pl_op.operand });6267 return cg.finishAir(inst, result, &.{ bin_op.lhs, bin_op.rhs, pl_op.operand });
6270}6268}
62716269
6272fn airClz(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {6270fn airClz(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
6273 const pt = func.pt;6271 const pt = cg.pt;
6274 const zcu = pt.zcu;6272 const zcu = pt.zcu;
6275 const ty_op = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;6273 const ty_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
62766274
6277 const ty = func.typeOf(ty_op.operand);6275 const ty = cg.typeOf(ty_op.operand);
6278 if (ty.zigTypeTag(zcu) == .vector) {6276 if (ty.zigTypeTag(zcu) == .vector) {
6279 return func.fail("TODO: `@clz` for vectors", .{});6277 return cg.fail("TODO: `@clz` for vectors", .{});
6280 }6278 }
62816279
6282 const operand = try func.resolveInst(ty_op.operand);6280 const operand = try cg.resolveInst(ty_op.operand);
6283 const int_info = ty.intInfo(zcu);6281 const int_info = ty.intInfo(zcu);
6284 const wasm_bits = toWasmBits(int_info.bits) orelse {6282 const wasm_bits = toWasmBits(int_info.bits) orelse {
6285 return func.fail("TODO: `@clz` for integers with bitsize '{d}'", .{int_info.bits});6283 return cg.fail("TODO: `@clz` for integers with bitsize '{d}'", .{int_info.bits});
6286 };6284 };
62876285
6288 switch (wasm_bits) {6286 switch (wasm_bits) {
6289 32 => {6287 32 => {
6290 try func.emitWValue(operand);6288 try cg.emitWValue(operand);
6291 try func.addTag(.i32_clz);6289 try cg.addTag(.i32_clz);
6292 },6290 },
6293 64 => {6291 64 => {
6294 try func.emitWValue(operand);6292 try cg.emitWValue(operand);
6295 try func.addTag(.i64_clz);6293 try cg.addTag(.i64_clz);
6296 try func.addTag(.i32_wrap_i64);6294 try cg.addTag(.i32_wrap_i64);
6297 },6295 },
6298 128 => {6296 128 => {
6299 var msb = try (try func.load(operand, Type.u64, 8)).toLocal(func, Type.u64);6297 var msb = try (try cg.load(operand, Type.u64, 8)).toLocal(cg, Type.u64);
6300 defer msb.free(func);6298 defer msb.free(cg);
63016299
6302 try func.emitWValue(msb);6300 try cg.emitWValue(msb);
6303 try func.addTag(.i64_clz);6301 try cg.addTag(.i64_clz);
6304 _ = try func.load(operand, Type.u64, 0);6302 _ = try cg.load(operand, Type.u64, 0);
6305 try func.addTag(.i64_clz);6303 try cg.addTag(.i64_clz);
6306 try func.emitWValue(.{ .imm64 = 64 });6304 try cg.emitWValue(.{ .imm64 = 64 });
6307 try func.addTag(.i64_add);6305 try cg.addTag(.i64_add);
6308 _ = try func.cmp(msb, .{ .imm64 = 0 }, Type.u64, .neq);6306 _ = try cg.cmp(msb, .{ .imm64 = 0 }, Type.u64, .neq);
6309 try func.addTag(.select);6307 try cg.addTag(.select);
6310 try func.addTag(.i32_wrap_i64);6308 try cg.addTag(.i32_wrap_i64);
6311 },6309 },
6312 else => unreachable,6310 else => unreachable,
6313 }6311 }
63146312
6315 if (wasm_bits != int_info.bits) {6313 if (wasm_bits != int_info.bits) {
6316 try func.emitWValue(.{ .imm32 = wasm_bits - int_info.bits });6314 try cg.emitWValue(.{ .imm32 = wasm_bits - int_info.bits });
6317 try func.addTag(.i32_sub);6315 try cg.addTag(.i32_sub);
6318 }6316 }
63196317
6320 return func.finishAir(inst, .stack, &.{ty_op.operand});6318 return cg.finishAir(inst, .stack, &.{ty_op.operand});
6321}6319}
63226320
6323fn airCtz(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {6321fn airCtz(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
6324 const pt = func.pt;6322 const pt = cg.pt;
6325 const zcu = pt.zcu;6323 const zcu = pt.zcu;
6326 const ty_op = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;6324 const ty_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
63276325
6328 const ty = func.typeOf(ty_op.operand);6326 const ty = cg.typeOf(ty_op.operand);
63296327
6330 if (ty.zigTypeTag(zcu) == .vector) {6328 if (ty.zigTypeTag(zcu) == .vector) {
6331 return func.fail("TODO: `@ctz` for vectors", .{});6329 return cg.fail("TODO: `@ctz` for vectors", .{});
6332 }6330 }
63336331
6334 const operand = try func.resolveInst(ty_op.operand);6332 const operand = try cg.resolveInst(ty_op.operand);
6335 const int_info = ty.intInfo(zcu);6333 const int_info = ty.intInfo(zcu);
6336 const wasm_bits = toWasmBits(int_info.bits) orelse {6334 const wasm_bits = toWasmBits(int_info.bits) orelse {
6337 return func.fail("TODO: `@clz` for integers with bitsize '{d}'", .{int_info.bits});6335 return cg.fail("TODO: `@clz` for integers with bitsize '{d}'", .{int_info.bits});
6338 };6336 };
63396337
6340 switch (wasm_bits) {6338 switch (wasm_bits) {
...@@ -6342,110 +6340,110 @@ fn airCtz(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -6342,110 +6340,110 @@ fn airCtz(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
6342 if (wasm_bits != int_info.bits) {6340 if (wasm_bits != int_info.bits) {
6343 const val: u32 = @as(u32, 1) << @as(u5, @intCast(int_info.bits));6341 const val: u32 = @as(u32, 1) << @as(u5, @intCast(int_info.bits));
6344 // leave value on the stack6342 // leave value on the stack
6345 _ = try func.binOp(operand, .{ .imm32 = val }, ty, .@"or");6343 _ = try cg.binOp(operand, .{ .imm32 = val }, ty, .@"or");
6346 } else try func.emitWValue(operand);6344 } else try cg.emitWValue(operand);
6347 try func.addTag(.i32_ctz);6345 try cg.addTag(.i32_ctz);
6348 },6346 },
6349 64 => {6347 64 => {
6350 if (wasm_bits != int_info.bits) {6348 if (wasm_bits != int_info.bits) {
6351 const val: u64 = @as(u64, 1) << @as(u6, @intCast(int_info.bits));6349 const val: u64 = @as(u64, 1) << @as(u6, @intCast(int_info.bits));
6352 // leave value on the stack6350 // leave value on the stack
6353 _ = try func.binOp(operand, .{ .imm64 = val }, ty, .@"or");6351 _ = try cg.binOp(operand, .{ .imm64 = val }, ty, .@"or");
6354 } else try func.emitWValue(operand);6352 } else try cg.emitWValue(operand);
6355 try func.addTag(.i64_ctz);6353 try cg.addTag(.i64_ctz);
6356 try func.addTag(.i32_wrap_i64);6354 try cg.addTag(.i32_wrap_i64);
6357 },6355 },
6358 128 => {6356 128 => {
6359 var lsb = try (try func.load(operand, Type.u64, 0)).toLocal(func, Type.u64);6357 var lsb = try (try cg.load(operand, Type.u64, 0)).toLocal(cg, Type.u64);
6360 defer lsb.free(func);6358 defer lsb.free(cg);
63616359
6362 try func.emitWValue(lsb);6360 try cg.emitWValue(lsb);
6363 try func.addTag(.i64_ctz);6361 try cg.addTag(.i64_ctz);
6364 _ = try func.load(operand, Type.u64, 8);6362 _ = try cg.load(operand, Type.u64, 8);
6365 if (wasm_bits != int_info.bits) {6363 if (wasm_bits != int_info.bits) {
6366 try func.addImm64(@as(u64, 1) << @as(u6, @intCast(int_info.bits - 64)));6364 try cg.addImm64(@as(u64, 1) << @as(u6, @intCast(int_info.bits - 64)));
6367 try func.addTag(.i64_or);6365 try cg.addTag(.i64_or);
6368 }6366 }
6369 try func.addTag(.i64_ctz);6367 try cg.addTag(.i64_ctz);
6370 try func.addImm64(64);6368 try cg.addImm64(64);
6371 if (wasm_bits != int_info.bits) {6369 if (wasm_bits != int_info.bits) {
6372 try func.addTag(.i64_or);6370 try cg.addTag(.i64_or);
6373 } else {6371 } else {
6374 try func.addTag(.i64_add);6372 try cg.addTag(.i64_add);
6375 }6373 }
6376 _ = try func.cmp(lsb, .{ .imm64 = 0 }, Type.u64, .neq);6374 _ = try cg.cmp(lsb, .{ .imm64 = 0 }, Type.u64, .neq);
6377 try func.addTag(.select);6375 try cg.addTag(.select);
6378 try func.addTag(.i32_wrap_i64);6376 try cg.addTag(.i32_wrap_i64);
6379 },6377 },
6380 else => unreachable,6378 else => unreachable,
6381 }6379 }
63826380
6383 return func.finishAir(inst, .stack, &.{ty_op.operand});6381 return cg.finishAir(inst, .stack, &.{ty_op.operand});
6384}6382}
63856383
6386fn airDbgStmt(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {6384fn airDbgStmt(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
6387 const dbg_stmt = func.air.instructions.items(.data)[@intFromEnum(inst)].dbg_stmt;6385 const dbg_stmt = cg.air.instructions.items(.data)[@intFromEnum(inst)].dbg_stmt;
6388 try func.addInst(.{ .tag = .dbg_line, .data = .{6386 try cg.addInst(.{ .tag = .dbg_line, .data = .{
6389 .payload = try func.addExtra(Mir.DbgLineColumn{6387 .payload = try cg.addExtra(Mir.DbgLineColumn{
6390 .line = dbg_stmt.line,6388 .line = dbg_stmt.line,
6391 .column = dbg_stmt.column,6389 .column = dbg_stmt.column,
6392 }),6390 }),
6393 } });6391 } });
6394 return func.finishAir(inst, .none, &.{});6392 return cg.finishAir(inst, .none, &.{});
6395}6393}
63966394
6397fn airDbgInlineBlock(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {6395fn airDbgInlineBlock(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
6398 const ty_pl = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;6396 const ty_pl = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
6399 const extra = func.air.extraData(Air.DbgInlineBlock, ty_pl.payload);6397 const extra = cg.air.extraData(Air.DbgInlineBlock, ty_pl.payload);
6400 // TODO6398 // TODO
6401 try func.lowerBlock(inst, ty_pl.ty.toType(), @ptrCast(func.air.extra[extra.end..][0..extra.data.body_len]));6399 try cg.lowerBlock(inst, ty_pl.ty.toType(), @ptrCast(cg.air.extra[extra.end..][0..extra.data.body_len]));
6402}6400}
64036401
6404fn airDbgVar(6402fn airDbgVar(
6405 func: *CodeGen,6403 cg: *CodeGen,
6406 inst: Air.Inst.Index,6404 inst: Air.Inst.Index,
6407 local_tag: link.File.Dwarf.WipNav.LocalTag,6405 local_tag: link.File.Dwarf.WipNav.LocalTag,
6408 is_ptr: bool,6406 is_ptr: bool,
6409) InnerError!void {6407) InnerError!void {
6410 _ = is_ptr;6408 _ = is_ptr;
6411 _ = local_tag;6409 _ = local_tag;
6412 return func.finishAir(inst, .none, &.{});6410 return cg.finishAir(inst, .none, &.{});
6413}6411}
64146412
6415fn airTry(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {6413fn airTry(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
6416 const pl_op = func.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;6414 const pl_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;
6417 const err_union = try func.resolveInst(pl_op.operand);6415 const err_union = try cg.resolveInst(pl_op.operand);
6418 const extra = func.air.extraData(Air.Try, pl_op.payload);6416 const extra = cg.air.extraData(Air.Try, pl_op.payload);
6419 const body: []const Air.Inst.Index = @ptrCast(func.air.extra[extra.end..][0..extra.data.body_len]);6417 const body: []const Air.Inst.Index = @ptrCast(cg.air.extra[extra.end..][0..extra.data.body_len]);
6420 const err_union_ty = func.typeOf(pl_op.operand);6418 const err_union_ty = cg.typeOf(pl_op.operand);
6421 const result = try lowerTry(func, inst, err_union, body, err_union_ty, false);6419 const result = try lowerTry(cg, inst, err_union, body, err_union_ty, false);
6422 return func.finishAir(inst, result, &.{pl_op.operand});6420 return cg.finishAir(inst, result, &.{pl_op.operand});
6423}6421}
64246422
6425fn airTryPtr(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {6423fn airTryPtr(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
6426 const pt = func.pt;6424 const pt = cg.pt;
6427 const zcu = pt.zcu;6425 const zcu = pt.zcu;
6428 const ty_pl = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;6426 const ty_pl = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
6429 const extra = func.air.extraData(Air.TryPtr, ty_pl.payload);6427 const extra = cg.air.extraData(Air.TryPtr, ty_pl.payload);
6430 const err_union_ptr = try func.resolveInst(extra.data.ptr);6428 const err_union_ptr = try cg.resolveInst(extra.data.ptr);
6431 const body: []const Air.Inst.Index = @ptrCast(func.air.extra[extra.end..][0..extra.data.body_len]);6429 const body: []const Air.Inst.Index = @ptrCast(cg.air.extra[extra.end..][0..extra.data.body_len]);
6432 const err_union_ty = func.typeOf(extra.data.ptr).childType(zcu);6430 const err_union_ty = cg.typeOf(extra.data.ptr).childType(zcu);
6433 const result = try lowerTry(func, inst, err_union_ptr, body, err_union_ty, true);6431 const result = try lowerTry(cg, inst, err_union_ptr, body, err_union_ty, true);
6434 return func.finishAir(inst, result, &.{extra.data.ptr});6432 return cg.finishAir(inst, result, &.{extra.data.ptr});
6435}6433}
64366434
6437fn lowerTry(6435fn lowerTry(
6438 func: *CodeGen,6436 cg: *CodeGen,
6439 inst: Air.Inst.Index,6437 inst: Air.Inst.Index,
6440 err_union: WValue,6438 err_union: WValue,
6441 body: []const Air.Inst.Index,6439 body: []const Air.Inst.Index,
6442 err_union_ty: Type,6440 err_union_ty: Type,
6443 operand_is_ptr: bool,6441 operand_is_ptr: bool,
6444) InnerError!WValue {6442) InnerError!WValue {
6445 const pt = func.pt;6443 const pt = cg.pt;
6446 const zcu = pt.zcu;6444 const zcu = pt.zcu;
6447 if (operand_is_ptr) {6445 if (operand_is_ptr) {
6448 return func.fail("TODO: lowerTry for pointers", .{});6446 return cg.fail("TODO: lowerTry for pointers", .{});
6449 }6447 }
64506448
6451 const pl_ty = err_union_ty.errorUnionPayload(zcu);6449 const pl_ty = err_union_ty.errorUnionPayload(zcu);
...@@ -6453,29 +6451,29 @@ fn lowerTry(...@@ -6453,29 +6451,29 @@ fn lowerTry(
64536451
6454 if (!err_union_ty.errorUnionSet(zcu).errorSetIsEmpty(zcu)) {6452 if (!err_union_ty.errorUnionSet(zcu).errorSetIsEmpty(zcu)) {
6455 // Block we can jump out of when error is not set6453 // Block we can jump out of when error is not set
6456 try func.startBlock(.block, std.wasm.block_empty);6454 try cg.startBlock(.block, std.wasm.block_empty);
64576455
6458 // check if the error tag is set for the error union.6456 // check if the error tag is set for the error union.
6459 try func.emitWValue(err_union);6457 try cg.emitWValue(err_union);
6460 if (pl_has_bits) {6458 if (pl_has_bits) {
6461 const err_offset: u32 = @intCast(errUnionErrorOffset(pl_ty, zcu));6459 const err_offset: u32 = @intCast(errUnionErrorOffset(pl_ty, zcu));
6462 try func.addMemArg(.i32_load16_u, .{6460 try cg.addMemArg(.i32_load16_u, .{
6463 .offset = err_union.offset() + err_offset,6461 .offset = err_union.offset() + err_offset,
6464 .alignment = @intCast(Type.anyerror.abiAlignment(zcu).toByteUnits().?),6462 .alignment = @intCast(Type.anyerror.abiAlignment(zcu).toByteUnits().?),
6465 });6463 });
6466 }6464 }
6467 try func.addTag(.i32_eqz);6465 try cg.addTag(.i32_eqz);
6468 try func.addLabel(.br_if, 0); // jump out of block when error is '0'6466 try cg.addLabel(.br_if, 0); // jump out of block when error is '0'
64696467
6470 const liveness = func.liveness.getCondBr(inst);6468 const liveness = cg.liveness.getCondBr(inst);
6471 try func.branches.append(func.gpa, .{});6469 try cg.branches.append(cg.gpa, .{});
6472 try func.currentBranch().values.ensureUnusedCapacity(func.gpa, liveness.else_deaths.len + liveness.then_deaths.len);6470 try cg.currentBranch().values.ensureUnusedCapacity(cg.gpa, liveness.else_deaths.len + liveness.then_deaths.len);
6473 defer {6471 defer {
6474 var branch = func.branches.pop();6472 var branch = cg.branches.pop();
6475 branch.deinit(func.gpa);6473 branch.deinit(cg.gpa);
6476 }6474 }
6477 try func.genBody(body);6475 try cg.genBody(body);
6478 try func.endBlock();6476 try cg.endBlock();
6479 }6477 }
64806478
6481 // if we reach here it means error was not set, and we want the payload6479 // if we reach here it means error was not set, and we want the payload
...@@ -6484,38 +6482,38 @@ fn lowerTry(...@@ -6484,38 +6482,38 @@ fn lowerTry(
6484 }6482 }
64856483
6486 const pl_offset: u32 = @intCast(errUnionPayloadOffset(pl_ty, zcu));6484 const pl_offset: u32 = @intCast(errUnionPayloadOffset(pl_ty, zcu));
6487 if (isByRef(pl_ty, pt, func.target)) {6485 if (isByRef(pl_ty, pt, cg.target)) {
6488 return buildPointerOffset(func, err_union, pl_offset, .new);6486 return buildPointerOffset(cg, err_union, pl_offset, .new);
6489 }6487 }
6490 const payload = try func.load(err_union, pl_ty, pl_offset);6488 const payload = try cg.load(err_union, pl_ty, pl_offset);
6491 return payload.toLocal(func, pl_ty);6489 return payload.toLocal(cg, pl_ty);
6492}6490}
64936491
6494fn airByteSwap(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {6492fn airByteSwap(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
6495 const pt = func.pt;6493 const pt = cg.pt;
6496 const zcu = pt.zcu;6494 const zcu = pt.zcu;
6497 const ty_op = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;6495 const ty_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
64986496
6499 const ty = func.typeOfIndex(inst);6497 const ty = cg.typeOfIndex(inst);
6500 const operand = try func.resolveInst(ty_op.operand);6498 const operand = try cg.resolveInst(ty_op.operand);
65016499
6502 if (ty.zigTypeTag(zcu) == .vector) {6500 if (ty.zigTypeTag(zcu) == .vector) {
6503 return func.fail("TODO: @byteSwap for vectors", .{});6501 return cg.fail("TODO: @byteSwap for vectors", .{});
6504 }6502 }
6505 const int_info = ty.intInfo(zcu);6503 const int_info = ty.intInfo(zcu);
6506 const wasm_bits = toWasmBits(int_info.bits) orelse {6504 const wasm_bits = toWasmBits(int_info.bits) orelse {
6507 return func.fail("TODO: @byteSwap for integers with bitsize {d}", .{int_info.bits});6505 return cg.fail("TODO: @byteSwap for integers with bitsize {d}", .{int_info.bits});
6508 };6506 };
65096507
6510 // bytes are no-op6508 // bytes are no-op
6511 if (int_info.bits == 8) {6509 if (int_info.bits == 8) {
6512 return func.finishAir(inst, func.reuseOperand(ty_op.operand, operand), &.{ty_op.operand});6510 return cg.finishAir(inst, cg.reuseOperand(ty_op.operand, operand), &.{ty_op.operand});
6513 }6511 }
65146512
6515 const result = result: {6513 const result = result: {
6516 switch (wasm_bits) {6514 switch (wasm_bits) {
6517 32 => {6515 32 => {
6518 const intrin_ret = try func.callIntrinsic(6516 const intrin_ret = try cg.callIntrinsic(
6519 "__bswapsi2",6517 "__bswapsi2",
6520 &.{.u32_type},6518 &.{.u32_type},
6521 Type.u32,6519 Type.u32,
...@@ -6524,10 +6522,10 @@ fn airByteSwap(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -6524,10 +6522,10 @@ fn airByteSwap(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
6524 break :result if (int_info.bits == 32)6522 break :result if (int_info.bits == 32)
6525 intrin_ret6523 intrin_ret
6526 else6524 else
6527 try func.binOp(intrin_ret, .{ .imm32 = 32 - int_info.bits }, ty, .shr);6525 try cg.binOp(intrin_ret, .{ .imm32 = 32 - int_info.bits }, ty, .shr);
6528 },6526 },
6529 64 => {6527 64 => {
6530 const intrin_ret = try func.callIntrinsic(6528 const intrin_ret = try cg.callIntrinsic(
6531 "__bswapdi2",6529 "__bswapdi2",
6532 &.{.u64_type},6530 &.{.u64_type},
6533 Type.u64,6531 Type.u64,
...@@ -6536,61 +6534,61 @@ fn airByteSwap(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -6536,61 +6534,61 @@ fn airByteSwap(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
6536 break :result if (int_info.bits == 64)6534 break :result if (int_info.bits == 64)
6537 intrin_ret6535 intrin_ret
6538 else6536 else
6539 try func.binOp(intrin_ret, .{ .imm64 = 64 - int_info.bits }, ty, .shr);6537 try cg.binOp(intrin_ret, .{ .imm64 = 64 - int_info.bits }, ty, .shr);
6540 },6538 },
6541 else => return func.fail("TODO: @byteSwap for integers with bitsize {d}", .{int_info.bits}),6539 else => return cg.fail("TODO: @byteSwap for integers with bitsize {d}", .{int_info.bits}),
6542 }6540 }
6543 };6541 };
6544 return func.finishAir(inst, result, &.{ty_op.operand});6542 return cg.finishAir(inst, result, &.{ty_op.operand});
6545}6543}
65466544
6547fn airDiv(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {6545fn airDiv(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
6548 const bin_op = func.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;6546 const bin_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
65496547
6550 const ty = func.typeOfIndex(inst);6548 const ty = cg.typeOfIndex(inst);
6551 const lhs = try func.resolveInst(bin_op.lhs);6549 const lhs = try cg.resolveInst(bin_op.lhs);
6552 const rhs = try func.resolveInst(bin_op.rhs);6550 const rhs = try cg.resolveInst(bin_op.rhs);
65536551
6554 const result = try func.binOp(lhs, rhs, ty, .div);6552 const result = try cg.binOp(lhs, rhs, ty, .div);
6555 return func.finishAir(inst, result, &.{ bin_op.lhs, bin_op.rhs });6553 return cg.finishAir(inst, result, &.{ bin_op.lhs, bin_op.rhs });
6556}6554}
65576555
6558fn airDivTrunc(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {6556fn airDivTrunc(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
6559 const bin_op = func.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;6557 const bin_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
65606558
6561 const ty = func.typeOfIndex(inst);6559 const ty = cg.typeOfIndex(inst);
6562 const lhs = try func.resolveInst(bin_op.lhs);6560 const lhs = try cg.resolveInst(bin_op.lhs);
6563 const rhs = try func.resolveInst(bin_op.rhs);6561 const rhs = try cg.resolveInst(bin_op.rhs);
65646562
6565 const div_result = try func.binOp(lhs, rhs, ty, .div);6563 const div_result = try cg.binOp(lhs, rhs, ty, .div);
65666564
6567 if (ty.isAnyFloat()) {6565 if (ty.isAnyFloat()) {
6568 const trunc_result = try func.floatOp(.trunc, ty, &.{div_result});6566 const trunc_result = try cg.floatOp(.trunc, ty, &.{div_result});
6569 return func.finishAir(inst, trunc_result, &.{ bin_op.lhs, bin_op.rhs });6567 return cg.finishAir(inst, trunc_result, &.{ bin_op.lhs, bin_op.rhs });
6570 }6568 }
65716569
6572 return func.finishAir(inst, div_result, &.{ bin_op.lhs, bin_op.rhs });6570 return cg.finishAir(inst, div_result, &.{ bin_op.lhs, bin_op.rhs });
6573}6571}
65746572
6575fn airDivFloor(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {6573fn airDivFloor(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
6576 const bin_op = func.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;6574 const bin_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
65776575
6578 const pt = func.pt;6576 const pt = cg.pt;
6579 const zcu = pt.zcu;6577 const zcu = pt.zcu;
6580 const ty = func.typeOfIndex(inst);6578 const ty = cg.typeOfIndex(inst);
6581 const lhs = try func.resolveInst(bin_op.lhs);6579 const lhs = try cg.resolveInst(bin_op.lhs);
6582 const rhs = try func.resolveInst(bin_op.rhs);6580 const rhs = try cg.resolveInst(bin_op.rhs);
65836581
6584 if (ty.isUnsignedInt(zcu)) {6582 if (ty.isUnsignedInt(zcu)) {
6585 _ = try func.binOp(lhs, rhs, ty, .div);6583 _ = try cg.binOp(lhs, rhs, ty, .div);
6586 } else if (ty.isSignedInt(zcu)) {6584 } else if (ty.isSignedInt(zcu)) {
6587 const int_bits = ty.intInfo(zcu).bits;6585 const int_bits = ty.intInfo(zcu).bits;
6588 const wasm_bits = toWasmBits(int_bits) orelse {6586 const wasm_bits = toWasmBits(int_bits) orelse {
6589 return func.fail("TODO: `@divFloor` for signed integers larger than 64 bits ({d} bits requested)", .{int_bits});6587 return cg.fail("TODO: `@divFloor` for signed integers larger than 64 bits ({d} bits requested)", .{int_bits});
6590 };6588 };
65916589
6592 if (wasm_bits > 64) {6590 if (wasm_bits > 64) {
6593 return func.fail("TODO: `@divFloor` for signed integers larger than 64 bits ({d} bits requested)", .{int_bits});6591 return cg.fail("TODO: `@divFloor` for signed integers larger than 64 bits ({d} bits requested)", .{int_bits});
6594 }6592 }
65956593
6596 const zero: WValue = switch (wasm_bits) {6594 const zero: WValue = switch (wasm_bits) {
...@@ -6600,108 +6598,108 @@ fn airDivFloor(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -6600,108 +6598,108 @@ fn airDivFloor(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
6600 };6598 };
66016599
6602 // tee leaves the value on the stack and stores it in a local.6600 // tee leaves the value on the stack and stores it in a local.
6603 const quotient = try func.allocLocal(ty);6601 const quotient = try cg.allocLocal(ty);
6604 _ = try func.binOp(lhs, rhs, ty, .div);6602 _ = try cg.binOp(lhs, rhs, ty, .div);
6605 try func.addLabel(.local_tee, quotient.local.value);6603 try cg.addLabel(.local_tee, quotient.local.value);
66066604
6607 // select takes a 32 bit value as the condition, so in the 64 bit case we use eqz to narrow6605 // select takes a 32 bit value as the condition, so in the 64 bit case we use eqz to narrow
6608 // the 64 bit value we want to use as the condition to 32 bits.6606 // the 64 bit value we want to use as the condition to 32 bits.
6609 // This also inverts the condition (non 0 => 0, 0 => 1), so we put the adjusted and6607 // This also inverts the condition (non 0 => 0, 0 => 1), so we put the adjusted and
6610 // non-adjusted quotients on the stack in the opposite order for 32 vs 64 bits.6608 // non-adjusted quotients on the stack in the opposite order for 32 vs 64 bits.
6611 if (wasm_bits == 64) {6609 if (wasm_bits == 64) {
6612 try func.emitWValue(quotient);6610 try cg.emitWValue(quotient);
6613 }6611 }
66146612
6615 // 0 if the signs of rhs_wasm and lhs_wasm are the same, 1 otherwise.6613 // 0 if the signs of rhs_wasm and lhs_wasm are the same, 1 otherwise.
6616 _ = try func.binOp(lhs, rhs, ty, .xor);6614 _ = try cg.binOp(lhs, rhs, ty, .xor);
6617 _ = try func.cmp(.stack, zero, ty, .lt);6615 _ = try cg.cmp(.stack, zero, ty, .lt);
66186616
6619 switch (wasm_bits) {6617 switch (wasm_bits) {
6620 32 => {6618 32 => {
6621 try func.addTag(.i32_sub);6619 try cg.addTag(.i32_sub);
6622 try func.emitWValue(quotient);6620 try cg.emitWValue(quotient);
6623 },6621 },
6624 64 => {6622 64 => {
6625 try func.addTag(.i64_extend_i32_u);6623 try cg.addTag(.i64_extend_i32_u);
6626 try func.addTag(.i64_sub);6624 try cg.addTag(.i64_sub);
6627 },6625 },
6628 else => unreachable,6626 else => unreachable,
6629 }6627 }
66306628
6631 _ = try func.binOp(lhs, rhs, ty, .rem);6629 _ = try cg.binOp(lhs, rhs, ty, .rem);
66326630
6633 if (wasm_bits == 64) {6631 if (wasm_bits == 64) {
6634 try func.addTag(.i64_eqz);6632 try cg.addTag(.i64_eqz);
6635 }6633 }
66366634
6637 try func.addTag(.select);6635 try cg.addTag(.select);
66386636
6639 // We need to zero the high bits because N bit comparisons consider all 32 or 64 bits, and6637 // We need to zero the high bits because N bit comparisons consider all 32 or 64 bits, and
6640 // expect all but the lowest N bits to be 0.6638 // expect all but the lowest N bits to be 0.
6641 // TODO: Should we be zeroing the high bits here or should we be ignoring the high bits6639 // TODO: Should we be zeroing the high bits here or should we be ignoring the high bits
6642 // when performing comparisons?6640 // when performing comparisons?
6643 if (int_bits != wasm_bits) {6641 if (int_bits != wasm_bits) {
6644 _ = try func.wrapOperand(.stack, ty);6642 _ = try cg.wrapOperand(.stack, ty);
6645 }6643 }
6646 } else {6644 } else {
6647 const float_bits = ty.floatBits(func.target.*);6645 const float_bits = ty.floatBits(cg.target.*);
6648 if (float_bits > 64) {6646 if (float_bits > 64) {
6649 return func.fail("TODO: `@divFloor` for floats with bitsize: {d}", .{float_bits});6647 return cg.fail("TODO: `@divFloor` for floats with bitsize: {d}", .{float_bits});
6650 }6648 }
6651 const is_f16 = float_bits == 16;6649 const is_f16 = float_bits == 16;
66526650
6653 const lhs_wasm = if (is_f16) try func.fpext(lhs, Type.f16, Type.f32) else lhs;6651 const lhs_wasm = if (is_f16) try cg.fpext(lhs, Type.f16, Type.f32) else lhs;
6654 const rhs_wasm = if (is_f16) try func.fpext(rhs, Type.f16, Type.f32) else rhs;6652 const rhs_wasm = if (is_f16) try cg.fpext(rhs, Type.f16, Type.f32) else rhs;
66556653
6656 try func.emitWValue(lhs_wasm);6654 try cg.emitWValue(lhs_wasm);
6657 try func.emitWValue(rhs_wasm);6655 try cg.emitWValue(rhs_wasm);
66586656
6659 switch (float_bits) {6657 switch (float_bits) {
6660 16, 32 => {6658 16, 32 => {
6661 try func.addTag(.f32_div);6659 try cg.addTag(.f32_div);
6662 try func.addTag(.f32_floor);6660 try cg.addTag(.f32_floor);
6663 },6661 },
6664 64 => {6662 64 => {
6665 try func.addTag(.f64_div);6663 try cg.addTag(.f64_div);
6666 try func.addTag(.f64_floor);6664 try cg.addTag(.f64_floor);
6667 },6665 },
6668 else => unreachable,6666 else => unreachable,
6669 }6667 }
66706668
6671 if (is_f16) {6669 if (is_f16) {
6672 _ = try func.fptrunc(.stack, Type.f32, Type.f16);6670 _ = try cg.fptrunc(.stack, Type.f32, Type.f16);
6673 }6671 }
6674 }6672 }
66756673
6676 return func.finishAir(inst, .stack, &.{ bin_op.lhs, bin_op.rhs });6674 return cg.finishAir(inst, .stack, &.{ bin_op.lhs, bin_op.rhs });
6677}6675}
66786676
6679fn airRem(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {6677fn airRem(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
6680 const bin_op = func.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;6678 const bin_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
66816679
6682 const ty = func.typeOfIndex(inst);6680 const ty = cg.typeOfIndex(inst);
6683 const lhs = try func.resolveInst(bin_op.lhs);6681 const lhs = try cg.resolveInst(bin_op.lhs);
6684 const rhs = try func.resolveInst(bin_op.rhs);6682 const rhs = try cg.resolveInst(bin_op.rhs);
66856683
6686 const result = try func.binOp(lhs, rhs, ty, .rem);6684 const result = try cg.binOp(lhs, rhs, ty, .rem);
66876685
6688 return func.finishAir(inst, result, &.{ bin_op.lhs, bin_op.rhs });6686 return cg.finishAir(inst, result, &.{ bin_op.lhs, bin_op.rhs });
6689}6687}
66906688
6691/// Remainder after floor division, defined by:6689/// Remainder after floor division, defined by:
6692/// @divFloor(a, b) * b + @mod(a, b) = a6690/// @divFloor(a, b) * b + @mod(a, b) = a
6693fn airMod(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {6691fn airMod(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
6694 const bin_op = func.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;6692 const bin_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
66956693
6696 const pt = func.pt;6694 const pt = cg.pt;
6697 const zcu = pt.zcu;6695 const zcu = pt.zcu;
6698 const ty = func.typeOfIndex(inst);6696 const ty = cg.typeOfIndex(inst);
6699 const lhs = try func.resolveInst(bin_op.lhs);6697 const lhs = try cg.resolveInst(bin_op.lhs);
6700 const rhs = try func.resolveInst(bin_op.rhs);6698 const rhs = try cg.resolveInst(bin_op.rhs);
67016699
6702 const result = result: {6700 const result = result: {
6703 if (ty.isUnsignedInt(zcu)) {6701 if (ty.isUnsignedInt(zcu)) {
6704 break :result try func.binOp(lhs, rhs, ty, .rem);6702 break :result try cg.binOp(lhs, rhs, ty, .rem);
6705 }6703 }
6706 if (ty.isSignedInt(zcu)) {6704 if (ty.isSignedInt(zcu)) {
6707 // The wasm rem instruction gives the remainder after truncating division (rounding towards6705 // The wasm rem instruction gives the remainder after truncating division (rounding towards
...@@ -6710,153 +6708,153 @@ fn airMod(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -6710,153 +6708,153 @@ fn airMod(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
6710 // @mod(a, b) = @rem(@rem(a, b) + b, b)6708 // @mod(a, b) = @rem(@rem(a, b) + b, b)
6711 const int_bits = ty.intInfo(zcu).bits;6709 const int_bits = ty.intInfo(zcu).bits;
6712 const wasm_bits = toWasmBits(int_bits) orelse {6710 const wasm_bits = toWasmBits(int_bits) orelse {
6713 return func.fail("TODO: `@mod` for signed integers larger than 64 bits ({d} bits requested)", .{int_bits});6711 return cg.fail("TODO: `@mod` for signed integers larger than 64 bits ({d} bits requested)", .{int_bits});
6714 };6712 };
67156713
6716 if (wasm_bits > 64) {6714 if (wasm_bits > 64) {
6717 return func.fail("TODO: `@mod` for signed integers larger than 64 bits ({d} bits requested)", .{int_bits});6715 return cg.fail("TODO: `@mod` for signed integers larger than 64 bits ({d} bits requested)", .{int_bits});
6718 }6716 }
67196717
6720 _ = try func.binOp(lhs, rhs, ty, .rem);6718 _ = try cg.binOp(lhs, rhs, ty, .rem);
6721 _ = try func.binOp(.stack, rhs, ty, .add);6719 _ = try cg.binOp(.stack, rhs, ty, .add);
6722 break :result try func.binOp(.stack, rhs, ty, .rem);6720 break :result try cg.binOp(.stack, rhs, ty, .rem);
6723 }6721 }
6724 if (ty.isAnyFloat()) {6722 if (ty.isAnyFloat()) {
6725 const rem = try func.binOp(lhs, rhs, ty, .rem);6723 const rem = try cg.binOp(lhs, rhs, ty, .rem);
6726 const add = try func.binOp(rem, rhs, ty, .add);6724 const add = try cg.binOp(rem, rhs, ty, .add);
6727 break :result try func.binOp(add, rhs, ty, .rem);6725 break :result try cg.binOp(add, rhs, ty, .rem);
6728 }6726 }
6729 return func.fail("TODO: @mod for {}", .{ty.fmt(pt)});6727 return cg.fail("TODO: @mod for {}", .{ty.fmt(pt)});
6730 };6728 };
67316729
6732 return func.finishAir(inst, result, &.{ bin_op.lhs, bin_op.rhs });6730 return cg.finishAir(inst, result, &.{ bin_op.lhs, bin_op.rhs });
6733}6731}
67346732
6735fn airSatMul(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {6733fn airSatMul(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
6736 const bin_op = func.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;6734 const bin_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
67376735
6738 const pt = func.pt;6736 const pt = cg.pt;
6739 const zcu = pt.zcu;6737 const zcu = pt.zcu;
6740 const ty = func.typeOfIndex(inst);6738 const ty = cg.typeOfIndex(inst);
6741 const int_info = ty.intInfo(zcu);6739 const int_info = ty.intInfo(zcu);
6742 const is_signed = int_info.signedness == .signed;6740 const is_signed = int_info.signedness == .signed;
67436741
6744 const lhs = try func.resolveInst(bin_op.lhs);6742 const lhs = try cg.resolveInst(bin_op.lhs);
6745 const rhs = try func.resolveInst(bin_op.rhs);6743 const rhs = try cg.resolveInst(bin_op.rhs);
6746 const wasm_bits = toWasmBits(int_info.bits) orelse {6744 const wasm_bits = toWasmBits(int_info.bits) orelse {
6747 return func.fail("TODO: mul_sat for {}", .{ty.fmt(pt)});6745 return cg.fail("TODO: mul_sat for {}", .{ty.fmt(pt)});
6748 };6746 };
67496747
6750 switch (wasm_bits) {6748 switch (wasm_bits) {
6751 32 => {6749 32 => {
6752 const upcast_ty: Type = if (is_signed) Type.i64 else Type.u64;6750 const upcast_ty: Type = if (is_signed) Type.i64 else Type.u64;
6753 const lhs_up = try func.intcast(lhs, ty, upcast_ty);6751 const lhs_up = try cg.intcast(lhs, ty, upcast_ty);
6754 const rhs_up = try func.intcast(rhs, ty, upcast_ty);6752 const rhs_up = try cg.intcast(rhs, ty, upcast_ty);
6755 var mul_res = try (try func.binOp(lhs_up, rhs_up, upcast_ty, .mul)).toLocal(func, upcast_ty);6753 var mul_res = try (try cg.binOp(lhs_up, rhs_up, upcast_ty, .mul)).toLocal(cg, upcast_ty);
6756 defer mul_res.free(func);6754 defer mul_res.free(cg);
6757 if (is_signed) {6755 if (is_signed) {
6758 const imm_max: WValue = .{ .imm64 = ~@as(u64, 0) >> @intCast(64 - (int_info.bits - 1)) };6756 const imm_max: WValue = .{ .imm64 = ~@as(u64, 0) >> @intCast(64 - (int_info.bits - 1)) };
6759 try func.emitWValue(mul_res);6757 try cg.emitWValue(mul_res);
6760 try func.emitWValue(imm_max);6758 try cg.emitWValue(imm_max);
6761 _ = try func.cmp(mul_res, imm_max, upcast_ty, .lt);6759 _ = try cg.cmp(mul_res, imm_max, upcast_ty, .lt);
6762 try func.addTag(.select);6760 try cg.addTag(.select);
67636761
6764 var tmp = try func.allocLocal(upcast_ty);6762 var tmp = try cg.allocLocal(upcast_ty);
6765 defer tmp.free(func);6763 defer tmp.free(cg);
6766 try func.addLabel(.local_set, tmp.local.value);6764 try cg.addLabel(.local_set, tmp.local.value);
67676765
6768 const imm_min: WValue = .{ .imm64 = ~@as(u64, 0) << @intCast(int_info.bits - 1) };6766 const imm_min: WValue = .{ .imm64 = ~@as(u64, 0) << @intCast(int_info.bits - 1) };
6769 try func.emitWValue(tmp);6767 try cg.emitWValue(tmp);
6770 try func.emitWValue(imm_min);6768 try cg.emitWValue(imm_min);
6771 _ = try func.cmp(tmp, imm_min, upcast_ty, .gt);6769 _ = try cg.cmp(tmp, imm_min, upcast_ty, .gt);
6772 try func.addTag(.select);6770 try cg.addTag(.select);
6773 } else {6771 } else {
6774 const imm_max: WValue = .{ .imm64 = ~@as(u64, 0) >> @intCast(64 - int_info.bits) };6772 const imm_max: WValue = .{ .imm64 = ~@as(u64, 0) >> @intCast(64 - int_info.bits) };
6775 try func.emitWValue(mul_res);6773 try cg.emitWValue(mul_res);
6776 try func.emitWValue(imm_max);6774 try cg.emitWValue(imm_max);
6777 _ = try func.cmp(mul_res, imm_max, upcast_ty, .lt);6775 _ = try cg.cmp(mul_res, imm_max, upcast_ty, .lt);
6778 try func.addTag(.select);6776 try cg.addTag(.select);
6779 }6777 }
6780 try func.addTag(.i32_wrap_i64);6778 try cg.addTag(.i32_wrap_i64);
6781 },6779 },
6782 64 => {6780 64 => {
6783 if (!(int_info.bits == 64 and int_info.signedness == .signed)) {6781 if (!(int_info.bits == 64 and int_info.signedness == .signed)) {
6784 return func.fail("TODO: mul_sat for {}", .{ty.fmt(pt)});6782 return cg.fail("TODO: mul_sat for {}", .{ty.fmt(pt)});
6785 }6783 }
6786 const overflow_ret = try func.allocStack(Type.i32);6784 const overflow_ret = try cg.allocStack(Type.i32);
6787 _ = try func.callIntrinsic(6785 _ = try cg.callIntrinsic(
6788 "__mulodi4",6786 "__mulodi4",
6789 &[_]InternPool.Index{ .i64_type, .i64_type, .usize_type },6787 &[_]InternPool.Index{ .i64_type, .i64_type, .usize_type },
6790 Type.i64,6788 Type.i64,
6791 &.{ lhs, rhs, overflow_ret },6789 &.{ lhs, rhs, overflow_ret },
6792 );6790 );
6793 const xor = try func.binOp(lhs, rhs, Type.i64, .xor);6791 const xor = try cg.binOp(lhs, rhs, Type.i64, .xor);
6794 const sign_v = try func.binOp(xor, .{ .imm64 = 63 }, Type.i64, .shr);6792 const sign_v = try cg.binOp(xor, .{ .imm64 = 63 }, Type.i64, .shr);
6795 _ = try func.binOp(sign_v, .{ .imm64 = ~@as(u63, 0) }, Type.i64, .xor);6793 _ = try cg.binOp(sign_v, .{ .imm64 = ~@as(u63, 0) }, Type.i64, .xor);
6796 _ = try func.load(overflow_ret, Type.i32, 0);6794 _ = try cg.load(overflow_ret, Type.i32, 0);
6797 try func.addTag(.i32_eqz);6795 try cg.addTag(.i32_eqz);
6798 try func.addTag(.select);6796 try cg.addTag(.select);
6799 },6797 },
6800 128 => {6798 128 => {
6801 if (!(int_info.bits == 128 and int_info.signedness == .signed)) {6799 if (!(int_info.bits == 128 and int_info.signedness == .signed)) {
6802 return func.fail("TODO: mul_sat for {}", .{ty.fmt(pt)});6800 return cg.fail("TODO: mul_sat for {}", .{ty.fmt(pt)});
6803 }6801 }
6804 const overflow_ret = try func.allocStack(Type.i32);6802 const overflow_ret = try cg.allocStack(Type.i32);
6805 const ret = try func.callIntrinsic(6803 const ret = try cg.callIntrinsic(
6806 "__muloti4",6804 "__muloti4",
6807 &[_]InternPool.Index{ .i128_type, .i128_type, .usize_type },6805 &[_]InternPool.Index{ .i128_type, .i128_type, .usize_type },
6808 Type.i128,6806 Type.i128,
6809 &.{ lhs, rhs, overflow_ret },6807 &.{ lhs, rhs, overflow_ret },
6810 );6808 );
6811 try func.lowerToStack(ret);6809 try cg.lowerToStack(ret);
6812 const xor = try func.binOp(lhs, rhs, Type.i128, .xor);6810 const xor = try cg.binOp(lhs, rhs, Type.i128, .xor);
6813 const sign_v = try func.binOp(xor, .{ .imm32 = 127 }, Type.i128, .shr);6811 const sign_v = try cg.binOp(xor, .{ .imm32 = 127 }, Type.i128, .shr);
68146812
6815 // xor ~@as(u127, 0)6813 // xor ~@as(u127, 0)
6816 try func.emitWValue(sign_v);6814 try cg.emitWValue(sign_v);
6817 const lsb = try func.load(sign_v, Type.u64, 0);6815 const lsb = try cg.load(sign_v, Type.u64, 0);
6818 _ = try func.binOp(lsb, .{ .imm64 = ~@as(u64, 0) }, Type.u64, .xor);6816 _ = try cg.binOp(lsb, .{ .imm64 = ~@as(u64, 0) }, Type.u64, .xor);
6819 try func.store(.stack, .stack, Type.u64, sign_v.offset());6817 try cg.store(.stack, .stack, Type.u64, sign_v.offset());
6820 try func.emitWValue(sign_v);6818 try cg.emitWValue(sign_v);
6821 const msb = try func.load(sign_v, Type.u64, 8);6819 const msb = try cg.load(sign_v, Type.u64, 8);
6822 _ = try func.binOp(msb, .{ .imm64 = ~@as(u63, 0) }, Type.u64, .xor);6820 _ = try cg.binOp(msb, .{ .imm64 = ~@as(u63, 0) }, Type.u64, .xor);
6823 try func.store(.stack, .stack, Type.u64, sign_v.offset() + 8);6821 try cg.store(.stack, .stack, Type.u64, sign_v.offset() + 8);
68246822
6825 try func.lowerToStack(sign_v);6823 try cg.lowerToStack(sign_v);
6826 _ = try func.load(overflow_ret, Type.i32, 0);6824 _ = try cg.load(overflow_ret, Type.i32, 0);
6827 try func.addTag(.i32_eqz);6825 try cg.addTag(.i32_eqz);
6828 try func.addTag(.select);6826 try cg.addTag(.select);
6829 },6827 },
6830 else => unreachable,6828 else => unreachable,
6831 }6829 }
6832 return func.finishAir(inst, .stack, &.{ bin_op.lhs, bin_op.rhs });6830 return cg.finishAir(inst, .stack, &.{ bin_op.lhs, bin_op.rhs });
6833}6831}
68346832
6835fn airSatBinOp(func: *CodeGen, inst: Air.Inst.Index, op: Op) InnerError!void {6833fn airSatBinOp(cg: *CodeGen, inst: Air.Inst.Index, op: Op) InnerError!void {
6836 assert(op == .add or op == .sub);6834 assert(op == .add or op == .sub);
6837 const bin_op = func.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;6835 const bin_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
68386836
6839 const pt = func.pt;6837 const pt = cg.pt;
6840 const zcu = pt.zcu;6838 const zcu = pt.zcu;
6841 const ty = func.typeOfIndex(inst);6839 const ty = cg.typeOfIndex(inst);
6842 const lhs = try func.resolveInst(bin_op.lhs);6840 const lhs = try cg.resolveInst(bin_op.lhs);
6843 const rhs = try func.resolveInst(bin_op.rhs);6841 const rhs = try cg.resolveInst(bin_op.rhs);
68446842
6845 const int_info = ty.intInfo(zcu);6843 const int_info = ty.intInfo(zcu);
6846 const is_signed = int_info.signedness == .signed;6844 const is_signed = int_info.signedness == .signed;
68476845
6848 if (int_info.bits > 64) {6846 if (int_info.bits > 64) {
6849 return func.fail("TODO: saturating arithmetic for integers with bitsize '{d}'", .{int_info.bits});6847 return cg.fail("TODO: saturating arithmetic for integers with bitsize '{d}'", .{int_info.bits});
6850 }6848 }
68516849
6852 if (is_signed) {6850 if (is_signed) {
6853 const result = try signedSat(func, lhs, rhs, ty, op);6851 const result = try signedSat(cg, lhs, rhs, ty, op);
6854 return func.finishAir(inst, result, &.{ bin_op.lhs, bin_op.rhs });6852 return cg.finishAir(inst, result, &.{ bin_op.lhs, bin_op.rhs });
6855 }6853 }
68566854
6857 const wasm_bits = toWasmBits(int_info.bits).?;6855 const wasm_bits = toWasmBits(int_info.bits).?;
6858 var bin_result = try (try func.binOp(lhs, rhs, ty, op)).toLocal(func, ty);6856 var bin_result = try (try cg.binOp(lhs, rhs, ty, op)).toLocal(cg, ty);
6859 defer bin_result.free(func);6857 defer bin_result.free(cg);
6860 if (wasm_bits != int_info.bits and op == .add) {6858 if (wasm_bits != int_info.bits and op == .add) {
6861 const val: u64 = @as(u64, @intCast((@as(u65, 1) << @as(u7, @intCast(int_info.bits))) - 1));6859 const val: u64 = @as(u64, @intCast((@as(u65, 1) << @as(u7, @intCast(int_info.bits))) - 1));
6862 const imm_val: WValue = switch (wasm_bits) {6860 const imm_val: WValue = switch (wasm_bits) {
...@@ -6865,25 +6863,25 @@ fn airSatBinOp(func: *CodeGen, inst: Air.Inst.Index, op: Op) InnerError!void {...@@ -6865,25 +6863,25 @@ fn airSatBinOp(func: *CodeGen, inst: Air.Inst.Index, op: Op) InnerError!void {
6865 else => unreachable,6863 else => unreachable,
6866 };6864 };
68676865
6868 try func.emitWValue(bin_result);6866 try cg.emitWValue(bin_result);
6869 try func.emitWValue(imm_val);6867 try cg.emitWValue(imm_val);
6870 _ = try func.cmp(bin_result, imm_val, ty, .lt);6868 _ = try cg.cmp(bin_result, imm_val, ty, .lt);
6871 } else {6869 } else {
6872 switch (wasm_bits) {6870 switch (wasm_bits) {
6873 32 => try func.addImm32(if (op == .add) std.math.maxInt(u32) else 0),6871 32 => try cg.addImm32(if (op == .add) std.math.maxInt(u32) else 0),
6874 64 => try func.addImm64(if (op == .add) std.math.maxInt(u64) else 0),6872 64 => try cg.addImm64(if (op == .add) std.math.maxInt(u64) else 0),
6875 else => unreachable,6873 else => unreachable,
6876 }6874 }
6877 try func.emitWValue(bin_result);6875 try cg.emitWValue(bin_result);
6878 _ = try func.cmp(bin_result, lhs, ty, if (op == .add) .lt else .gt);6876 _ = try cg.cmp(bin_result, lhs, ty, if (op == .add) .lt else .gt);
6879 }6877 }
68806878
6881 try func.addTag(.select);6879 try cg.addTag(.select);
6882 return func.finishAir(inst, .stack, &.{ bin_op.lhs, bin_op.rhs });6880 return cg.finishAir(inst, .stack, &.{ bin_op.lhs, bin_op.rhs });
6883}6881}
68846882
6885fn signedSat(func: *CodeGen, lhs: WValue, rhs: WValue, ty: Type, op: Op) InnerError!WValue {6883fn signedSat(cg: *CodeGen, lhs: WValue, rhs: WValue, ty: Type, op: Op) InnerError!WValue {
6886 const pt = func.pt;6884 const pt = cg.pt;
6887 const zcu = pt.zcu;6885 const zcu = pt.zcu;
6888 const int_info = ty.intInfo(zcu);6886 const int_info = ty.intInfo(zcu);
6889 const wasm_bits = toWasmBits(int_info.bits).?;6887 const wasm_bits = toWasmBits(int_info.bits).?;
...@@ -6903,92 +6901,92 @@ fn signedSat(func: *CodeGen, lhs: WValue, rhs: WValue, ty: Type, op: Op) InnerEr...@@ -6903,92 +6901,92 @@ fn signedSat(func: *CodeGen, lhs: WValue, rhs: WValue, ty: Type, op: Op) InnerEr
6903 else => unreachable,6901 else => unreachable,
6904 };6902 };
69056903
6906 var bin_result = try (try func.binOp(lhs, rhs, ext_ty, op)).toLocal(func, ext_ty);6904 var bin_result = try (try cg.binOp(lhs, rhs, ext_ty, op)).toLocal(cg, ext_ty);
6907 if (!is_wasm_bits) {6905 if (!is_wasm_bits) {
6908 defer bin_result.free(func); // not returned in this branch6906 defer bin_result.free(cg); // not returned in this branch
6909 try func.emitWValue(bin_result);6907 try cg.emitWValue(bin_result);
6910 try func.emitWValue(max_wvalue);6908 try cg.emitWValue(max_wvalue);
6911 _ = try func.cmp(bin_result, max_wvalue, ext_ty, .lt);6909 _ = try cg.cmp(bin_result, max_wvalue, ext_ty, .lt);
6912 try func.addTag(.select);6910 try cg.addTag(.select);
6913 try func.addLabel(.local_set, bin_result.local.value); // re-use local6911 try cg.addLabel(.local_set, bin_result.local.value); // re-use local
69146912
6915 try func.emitWValue(bin_result);6913 try cg.emitWValue(bin_result);
6916 try func.emitWValue(min_wvalue);6914 try cg.emitWValue(min_wvalue);
6917 _ = try func.cmp(bin_result, min_wvalue, ext_ty, .gt);6915 _ = try cg.cmp(bin_result, min_wvalue, ext_ty, .gt);
6918 try func.addTag(.select);6916 try cg.addTag(.select);
6919 try func.addLabel(.local_set, bin_result.local.value); // re-use local6917 try cg.addLabel(.local_set, bin_result.local.value); // re-use local
6920 return (try func.wrapOperand(bin_result, ty)).toLocal(func, ty);6918 return (try cg.wrapOperand(bin_result, ty)).toLocal(cg, ty);
6921 } else {6919 } else {
6922 const zero: WValue = switch (wasm_bits) {6920 const zero: WValue = switch (wasm_bits) {
6923 32 => .{ .imm32 = 0 },6921 32 => .{ .imm32 = 0 },
6924 64 => .{ .imm64 = 0 },6922 64 => .{ .imm64 = 0 },
6925 else => unreachable,6923 else => unreachable,
6926 };6924 };
6927 try func.emitWValue(max_wvalue);6925 try cg.emitWValue(max_wvalue);
6928 try func.emitWValue(min_wvalue);6926 try cg.emitWValue(min_wvalue);
6929 _ = try func.cmp(bin_result, zero, ty, .lt);6927 _ = try cg.cmp(bin_result, zero, ty, .lt);
6930 try func.addTag(.select);6928 try cg.addTag(.select);
6931 try func.emitWValue(bin_result);6929 try cg.emitWValue(bin_result);
6932 // leave on stack6930 // leave on stack
6933 const cmp_zero_result = try func.cmp(rhs, zero, ty, if (op == .add) .lt else .gt);6931 const cmp_zero_result = try cg.cmp(rhs, zero, ty, if (op == .add) .lt else .gt);
6934 const cmp_bin_result = try func.cmp(bin_result, lhs, ty, .lt);6932 const cmp_bin_result = try cg.cmp(bin_result, lhs, ty, .lt);
6935 _ = try func.binOp(cmp_zero_result, cmp_bin_result, Type.u32, .xor); // comparisons always return i32, so provide u32 as type to xor.6933 _ = try cg.binOp(cmp_zero_result, cmp_bin_result, Type.u32, .xor); // comparisons always return i32, so provide u32 as type to xor.
6936 try func.addTag(.select);6934 try cg.addTag(.select);
6937 try func.addLabel(.local_set, bin_result.local.value); // re-use local6935 try cg.addLabel(.local_set, bin_result.local.value); // re-use local
6938 return bin_result;6936 return bin_result;
6939 }6937 }
6940}6938}
69416939
6942fn airShlSat(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {6940fn airShlSat(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
6943 const bin_op = func.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;6941 const bin_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
69446942
6945 const pt = func.pt;6943 const pt = cg.pt;
6946 const zcu = pt.zcu;6944 const zcu = pt.zcu;
6947 const ty = func.typeOfIndex(inst);6945 const ty = cg.typeOfIndex(inst);
6948 const int_info = ty.intInfo(zcu);6946 const int_info = ty.intInfo(zcu);
6949 const is_signed = int_info.signedness == .signed;6947 const is_signed = int_info.signedness == .signed;
6950 if (int_info.bits > 64) {6948 if (int_info.bits > 64) {
6951 return func.fail("TODO: Saturating shifting left for integers with bitsize '{d}'", .{int_info.bits});6949 return cg.fail("TODO: Saturating shifting left for integers with bitsize '{d}'", .{int_info.bits});
6952 }6950 }
69536951
6954 const lhs = try func.resolveInst(bin_op.lhs);6952 const lhs = try cg.resolveInst(bin_op.lhs);
6955 const rhs = try func.resolveInst(bin_op.rhs);6953 const rhs = try cg.resolveInst(bin_op.rhs);
6956 const wasm_bits = toWasmBits(int_info.bits).?;6954 const wasm_bits = toWasmBits(int_info.bits).?;
6957 const result = try func.allocLocal(ty);6955 const result = try cg.allocLocal(ty);
69586956
6959 if (wasm_bits == int_info.bits) {6957 if (wasm_bits == int_info.bits) {
6960 var shl = try (try func.binOp(lhs, rhs, ty, .shl)).toLocal(func, ty);6958 var shl = try (try cg.binOp(lhs, rhs, ty, .shl)).toLocal(cg, ty);
6961 defer shl.free(func);6959 defer shl.free(cg);
6962 var shr = try (try func.binOp(shl, rhs, ty, .shr)).toLocal(func, ty);6960 var shr = try (try cg.binOp(shl, rhs, ty, .shr)).toLocal(cg, ty);
6963 defer shr.free(func);6961 defer shr.free(cg);
69646962
6965 switch (wasm_bits) {6963 switch (wasm_bits) {
6966 32 => blk: {6964 32 => blk: {
6967 if (!is_signed) {6965 if (!is_signed) {
6968 try func.addImm32(std.math.maxInt(u32));6966 try cg.addImm32(std.math.maxInt(u32));
6969 break :blk;6967 break :blk;
6970 }6968 }
6971 try func.addImm32(@bitCast(@as(i32, std.math.minInt(i32))));6969 try cg.addImm32(@bitCast(@as(i32, std.math.minInt(i32))));
6972 try func.addImm32(@bitCast(@as(i32, std.math.maxInt(i32))));6970 try cg.addImm32(@bitCast(@as(i32, std.math.maxInt(i32))));
6973 _ = try func.cmp(lhs, .{ .imm32 = 0 }, ty, .lt);6971 _ = try cg.cmp(lhs, .{ .imm32 = 0 }, ty, .lt);
6974 try func.addTag(.select);6972 try cg.addTag(.select);
6975 },6973 },
6976 64 => blk: {6974 64 => blk: {
6977 if (!is_signed) {6975 if (!is_signed) {
6978 try func.addImm64(std.math.maxInt(u64));6976 try cg.addImm64(std.math.maxInt(u64));
6979 break :blk;6977 break :blk;
6980 }6978 }
6981 try func.addImm64(@bitCast(@as(i64, std.math.minInt(i64))));6979 try cg.addImm64(@bitCast(@as(i64, std.math.minInt(i64))));
6982 try func.addImm64(@bitCast(@as(i64, std.math.maxInt(i64))));6980 try cg.addImm64(@bitCast(@as(i64, std.math.maxInt(i64))));
6983 _ = try func.cmp(lhs, .{ .imm64 = 0 }, ty, .lt);6981 _ = try cg.cmp(lhs, .{ .imm64 = 0 }, ty, .lt);
6984 try func.addTag(.select);6982 try cg.addTag(.select);
6985 },6983 },
6986 else => unreachable,6984 else => unreachable,
6987 }6985 }
6988 try func.emitWValue(shl);6986 try cg.emitWValue(shl);
6989 _ = try func.cmp(lhs, shr, ty, .neq);6987 _ = try cg.cmp(lhs, shr, ty, .neq);
6990 try func.addTag(.select);6988 try cg.addTag(.select);
6991 try func.addLabel(.local_set, result.local.value);6989 try cg.addLabel(.local_set, result.local.value);
6992 } else {6990 } else {
6993 const shift_size = wasm_bits - int_info.bits;6991 const shift_size = wasm_bits - int_info.bits;
6994 const shift_value: WValue = switch (wasm_bits) {6992 const shift_value: WValue = switch (wasm_bits) {
...@@ -6998,50 +6996,50 @@ fn airShlSat(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -6998,50 +6996,50 @@ fn airShlSat(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
6998 };6996 };
6999 const ext_ty = try pt.intType(int_info.signedness, wasm_bits);6997 const ext_ty = try pt.intType(int_info.signedness, wasm_bits);
70006998
7001 var shl_res = try (try func.binOp(lhs, shift_value, ext_ty, .shl)).toLocal(func, ext_ty);6999 var shl_res = try (try cg.binOp(lhs, shift_value, ext_ty, .shl)).toLocal(cg, ext_ty);
7002 defer shl_res.free(func);7000 defer shl_res.free(cg);
7003 var shl = try (try func.binOp(shl_res, rhs, ext_ty, .shl)).toLocal(func, ext_ty);7001 var shl = try (try cg.binOp(shl_res, rhs, ext_ty, .shl)).toLocal(cg, ext_ty);
7004 defer shl.free(func);7002 defer shl.free(cg);
7005 var shr = try (try func.binOp(shl, rhs, ext_ty, .shr)).toLocal(func, ext_ty);7003 var shr = try (try cg.binOp(shl, rhs, ext_ty, .shr)).toLocal(cg, ext_ty);
7006 defer shr.free(func);7004 defer shr.free(cg);
70077005
7008 switch (wasm_bits) {7006 switch (wasm_bits) {
7009 32 => blk: {7007 32 => blk: {
7010 if (!is_signed) {7008 if (!is_signed) {
7011 try func.addImm32(std.math.maxInt(u32));7009 try cg.addImm32(std.math.maxInt(u32));
7012 break :blk;7010 break :blk;
7013 }7011 }
70147012
7015 try func.addImm32(@bitCast(@as(i32, std.math.minInt(i32))));7013 try cg.addImm32(@bitCast(@as(i32, std.math.minInt(i32))));
7016 try func.addImm32(@bitCast(@as(i32, std.math.maxInt(i32))));7014 try cg.addImm32(@bitCast(@as(i32, std.math.maxInt(i32))));
7017 _ = try func.cmp(shl_res, .{ .imm32 = 0 }, ext_ty, .lt);7015 _ = try cg.cmp(shl_res, .{ .imm32 = 0 }, ext_ty, .lt);
7018 try func.addTag(.select);7016 try cg.addTag(.select);
7019 },7017 },
7020 64 => blk: {7018 64 => blk: {
7021 if (!is_signed) {7019 if (!is_signed) {
7022 try func.addImm64(std.math.maxInt(u64));7020 try cg.addImm64(std.math.maxInt(u64));
7023 break :blk;7021 break :blk;
7024 }7022 }
70257023
7026 try func.addImm64(@bitCast(@as(i64, std.math.minInt(i64))));7024 try cg.addImm64(@bitCast(@as(i64, std.math.minInt(i64))));
7027 try func.addImm64(@bitCast(@as(i64, std.math.maxInt(i64))));7025 try cg.addImm64(@bitCast(@as(i64, std.math.maxInt(i64))));
7028 _ = try func.cmp(shl_res, .{ .imm64 = 0 }, ext_ty, .lt);7026 _ = try cg.cmp(shl_res, .{ .imm64 = 0 }, ext_ty, .lt);
7029 try func.addTag(.select);7027 try cg.addTag(.select);
7030 },7028 },
7031 else => unreachable,7029 else => unreachable,
7032 }7030 }
7033 try func.emitWValue(shl);7031 try cg.emitWValue(shl);
7034 _ = try func.cmp(shl_res, shr, ext_ty, .neq);7032 _ = try cg.cmp(shl_res, shr, ext_ty, .neq);
7035 try func.addTag(.select);7033 try cg.addTag(.select);
7036 try func.addLabel(.local_set, result.local.value);7034 try cg.addLabel(.local_set, result.local.value);
7037 var shift_result = try func.binOp(result, shift_value, ext_ty, .shr);7035 var shift_result = try cg.binOp(result, shift_value, ext_ty, .shr);
7038 if (is_signed) {7036 if (is_signed) {
7039 shift_result = try func.wrapOperand(shift_result, ty);7037 shift_result = try cg.wrapOperand(shift_result, ty);
7040 }7038 }
7041 try func.addLabel(.local_set, result.local.value);7039 try cg.addLabel(.local_set, result.local.value);
7042 }7040 }
70437041
7044 return func.finishAir(inst, result, &.{ bin_op.lhs, bin_op.rhs });7042 return cg.finishAir(inst, result, &.{ bin_op.lhs, bin_op.rhs });
7045}7043}
70467044
7047/// Calls a compiler-rt intrinsic by creating an undefined symbol,7045/// Calls a compiler-rt intrinsic by creating an undefined symbol,
...@@ -7051,27 +7049,27 @@ fn airShlSat(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -7051,27 +7049,27 @@ fn airShlSat(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
7051/// passed as the first parameter.7049/// passed as the first parameter.
7052/// May leave the return value on the stack.7050/// May leave the return value on the stack.
7053fn callIntrinsic(7051fn callIntrinsic(
7054 func: *CodeGen,7052 cg: *CodeGen,
7055 name: []const u8,7053 name: []const u8,
7056 param_types: []const InternPool.Index,7054 param_types: []const InternPool.Index,
7057 return_type: Type,7055 return_type: Type,
7058 args: []const WValue,7056 args: []const WValue,
7059) InnerError!WValue {7057) InnerError!WValue {
7060 assert(param_types.len == args.len);7058 assert(param_types.len == args.len);
7061 const wasm = func.wasm;7059 const wasm = cg.wasm;
7062 const pt = func.pt;7060 const pt = cg.pt;
7063 const zcu = pt.zcu;7061 const zcu = pt.zcu;
7064 const func_type_index = try genFunctype(wasm, .{ .wasm_watc = .{} }, param_types, return_type, pt, func.target);7062 const func_type_index = try genFunctype(wasm, .{ .wasm_watc = .{} }, param_types, return_type, pt, cg.target);
7065 const func_index = wasm.getOutputFunction(try wasm.internString(name), func_type_index);7063 const func_index = wasm.getOutputFunction(try wasm.internString(name), func_type_index);
70667064
7067 // Always pass over C-ABI7065 // Always pass over C-ABI
70687066
7069 const want_sret_param = firstParamSRet(.{ .wasm_watc = .{} }, return_type, pt, func.target);7067 const want_sret_param = firstParamSRet(.{ .wasm_watc = .{} }, return_type, pt, cg.target);
7070 // if we want return as first param, we allocate a pointer to stack,7068 // if we want return as first param, we allocate a pointer to stack,
7071 // and emit it as our first argument7069 // and emit it as our first argument
7072 const sret = if (want_sret_param) blk: {7070 const sret = if (want_sret_param) blk: {
7073 const sret_local = try func.allocStack(return_type);7071 const sret_local = try cg.allocStack(return_type);
7074 try func.lowerToStack(sret_local);7072 try cg.lowerToStack(sret_local);
7075 break :blk sret_local;7073 break :blk sret_local;
7076 } else .none;7074 } else .none;
70777075
...@@ -7079,16 +7077,16 @@ fn callIntrinsic(...@@ -7079,16 +7077,16 @@ fn callIntrinsic(
7079 for (args, 0..) |arg, arg_i| {7077 for (args, 0..) |arg, arg_i| {
7080 assert(!(want_sret_param and arg == .stack));7078 assert(!(want_sret_param and arg == .stack));
7081 assert(Type.fromInterned(param_types[arg_i]).hasRuntimeBitsIgnoreComptime(zcu));7079 assert(Type.fromInterned(param_types[arg_i]).hasRuntimeBitsIgnoreComptime(zcu));
7082 try func.lowerArg(.{ .wasm_watc = .{} }, Type.fromInterned(param_types[arg_i]), arg);7080 try cg.lowerArg(.{ .wasm_watc = .{} }, Type.fromInterned(param_types[arg_i]), arg);
7083 }7081 }
70847082
7085 // Actually call our intrinsic7083 // Actually call our intrinsic
7086 try func.addLabel(.call_func, func_index);7084 try cg.addLabel(.call_func, func_index);
70877085
7088 if (!return_type.hasRuntimeBitsIgnoreComptime(zcu)) {7086 if (!return_type.hasRuntimeBitsIgnoreComptime(zcu)) {
7089 return .none;7087 return .none;
7090 } else if (return_type.isNoReturn(zcu)) {7088 } else if (return_type.isNoReturn(zcu)) {
7091 try func.addTag(.@"unreachable");7089 try cg.addTag(.@"unreachable");
7092 return .none;7090 return .none;
7093 } else if (want_sret_param) {7091 } else if (want_sret_param) {
7094 return sret;7092 return sret;
...@@ -7097,31 +7095,31 @@ fn callIntrinsic(...@@ -7097,31 +7095,31 @@ fn callIntrinsic(
7097 }7095 }
7098}7096}
70997097
7100fn airTagName(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {7098fn airTagName(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
7101 const un_op = func.air.instructions.items(.data)[@intFromEnum(inst)].un_op;7099 const un_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].un_op;
7102 const operand = try func.resolveInst(un_op);7100 const operand = try cg.resolveInst(un_op);
7103 const enum_ty = func.typeOf(un_op);7101 const enum_ty = cg.typeOf(un_op);
71047102
7105 const result_ptr = try func.allocStack(func.typeOfIndex(inst));7103 const result_ptr = try cg.allocStack(cg.typeOfIndex(inst));
7106 try func.lowerToStack(result_ptr);7104 try cg.lowerToStack(result_ptr);
7107 try func.emitWValue(operand);7105 try cg.emitWValue(operand);
7108 try func.addIpIndex(.call_tag_name, enum_ty.toIntern());7106 try cg.addIpIndex(.call_tag_name, enum_ty.toIntern());
71097107
7110 return func.finishAir(inst, result_ptr, &.{un_op});7108 return cg.finishAir(inst, result_ptr, &.{un_op});
7111}7109}
71127110
7113fn airErrorSetHasValue(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {7111fn airErrorSetHasValue(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
7114 const pt = func.pt;7112 const pt = cg.pt;
7115 const zcu = pt.zcu;7113 const zcu = pt.zcu;
7116 const ip = &zcu.intern_pool;7114 const ip = &zcu.intern_pool;
7117 const ty_op = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;7115 const ty_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
71187116
7119 const operand = try func.resolveInst(ty_op.operand);7117 const operand = try cg.resolveInst(ty_op.operand);
7120 const error_set_ty = ty_op.ty.toType();7118 const error_set_ty = ty_op.ty.toType();
7121 const result = try func.allocLocal(Type.bool);7119 const result = try cg.allocLocal(Type.bool);
71227120
7123 const names = error_set_ty.errorSetNames(zcu);7121 const names = error_set_ty.errorSetNames(zcu);
7124 var values = try std.ArrayList(u32).initCapacity(func.gpa, names.len);7122 var values = try std.ArrayList(u32).initCapacity(cg.gpa, names.len);
7125 defer values.deinit();7123 defer values.deinit();
71267124
7127 var lowest: ?u32 = null;7125 var lowest: ?u32 = null;
...@@ -7147,23 +7145,23 @@ fn airErrorSetHasValue(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -7147,23 +7145,23 @@ fn airErrorSetHasValue(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
7147 }7145 }
71487146
7149 // start block for 'true' branch7147 // start block for 'true' branch
7150 try func.startBlock(.block, std.wasm.block_empty);7148 try cg.startBlock(.block, std.wasm.block_empty);
7151 // start block for 'false' branch7149 // start block for 'false' branch
7152 try func.startBlock(.block, std.wasm.block_empty);7150 try cg.startBlock(.block, std.wasm.block_empty);
7153 // block for the jump table itself7151 // block for the jump table itself
7154 try func.startBlock(.block, std.wasm.block_empty);7152 try cg.startBlock(.block, std.wasm.block_empty);
71557153
7156 // lower operand to determine jump table target7154 // lower operand to determine jump table target
7157 try func.emitWValue(operand);7155 try cg.emitWValue(operand);
7158 try func.addImm32(lowest.?);7156 try cg.addImm32(lowest.?);
7159 try func.addTag(.i32_sub);7157 try cg.addTag(.i32_sub);
71607158
7161 // Account for default branch so always add '1'7159 // Account for default branch so always add '1'
7162 const depth = @as(u32, @intCast(highest.? - lowest.? + 1));7160 const depth = @as(u32, @intCast(highest.? - lowest.? + 1));
7163 const jump_table: Mir.JumpTable = .{ .length = depth };7161 const jump_table: Mir.JumpTable = .{ .length = depth };
7164 const table_extra_index = try func.addExtra(jump_table);7162 const table_extra_index = try cg.addExtra(jump_table);
7165 try func.addInst(.{ .tag = .br_table, .data = .{ .payload = table_extra_index } });7163 try cg.addInst(.{ .tag = .br_table, .data = .{ .payload = table_extra_index } });
7166 try func.mir_extra.ensureUnusedCapacity(func.gpa, depth);7164 try cg.mir_extra.ensureUnusedCapacity(cg.gpa, depth);
71677165
7168 var value: u32 = lowest.?;7166 var value: u32 = lowest.?;
7169 while (value <= highest.?) : (value += 1) {7167 while (value <= highest.?) : (value += 1) {
...@@ -7173,201 +7171,201 @@ fn airErrorSetHasValue(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -7173,201 +7171,201 @@ fn airErrorSetHasValue(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
7173 }7171 }
7174 break :blk 0;7172 break :blk 0;
7175 };7173 };
7176 func.mir_extra.appendAssumeCapacity(idx);7174 cg.mir_extra.appendAssumeCapacity(idx);
7177 }7175 }
7178 try func.endBlock();7176 try cg.endBlock();
71797177
7180 // 'false' branch (i.e. error set does not have value7178 // 'false' branch (i.e. error set does not have value
7181 // ensure we set local to 0 in case the local was re-used.7179 // ensure we set local to 0 in case the local was re-used.
7182 try func.addImm32(0);7180 try cg.addImm32(0);
7183 try func.addLabel(.local_set, result.local.value);7181 try cg.addLabel(.local_set, result.local.value);
7184 try func.addLabel(.br, 1);7182 try cg.addLabel(.br, 1);
7185 try func.endBlock();7183 try cg.endBlock();
71867184
7187 // 'true' branch7185 // 'true' branch
7188 try func.addImm32(1);7186 try cg.addImm32(1);
7189 try func.addLabel(.local_set, result.local.value);7187 try cg.addLabel(.local_set, result.local.value);
7190 try func.addLabel(.br, 0);7188 try cg.addLabel(.br, 0);
7191 try func.endBlock();7189 try cg.endBlock();
71927190
7193 return func.finishAir(inst, result, &.{ty_op.operand});7191 return cg.finishAir(inst, result, &.{ty_op.operand});
7194}7192}
71957193
7196inline fn useAtomicFeature(func: *const CodeGen) bool {7194inline fn useAtomicFeature(cg: *const CodeGen) bool {
7197 return std.Target.wasm.featureSetHas(func.target.cpu.features, .atomics);7195 return std.Target.wasm.featureSetHas(cg.target.cpu.features, .atomics);
7198}7196}
71997197
7200fn airCmpxchg(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {7198fn airCmpxchg(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
7201 const pt = func.pt;7199 const pt = cg.pt;
7202 const zcu = pt.zcu;7200 const zcu = pt.zcu;
7203 const ty_pl = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;7201 const ty_pl = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
7204 const extra = func.air.extraData(Air.Cmpxchg, ty_pl.payload).data;7202 const extra = cg.air.extraData(Air.Cmpxchg, ty_pl.payload).data;
72057203
7206 const ptr_ty = func.typeOf(extra.ptr);7204 const ptr_ty = cg.typeOf(extra.ptr);
7207 const ty = ptr_ty.childType(zcu);7205 const ty = ptr_ty.childType(zcu);
7208 const result_ty = func.typeOfIndex(inst);7206 const result_ty = cg.typeOfIndex(inst);
72097207
7210 const ptr_operand = try func.resolveInst(extra.ptr);7208 const ptr_operand = try cg.resolveInst(extra.ptr);
7211 const expected_val = try func.resolveInst(extra.expected_value);7209 const expected_val = try cg.resolveInst(extra.expected_value);
7212 const new_val = try func.resolveInst(extra.new_value);7210 const new_val = try cg.resolveInst(extra.new_value);
72137211
7214 const cmp_result = try func.allocLocal(Type.bool);7212 const cmp_result = try cg.allocLocal(Type.bool);
72157213
7216 const ptr_val = if (func.useAtomicFeature()) val: {7214 const ptr_val = if (cg.useAtomicFeature()) val: {
7217 const val_local = try func.allocLocal(ty);7215 const val_local = try cg.allocLocal(ty);
7218 try func.emitWValue(ptr_operand);7216 try cg.emitWValue(ptr_operand);
7219 try func.lowerToStack(expected_val);7217 try cg.lowerToStack(expected_val);
7220 try func.lowerToStack(new_val);7218 try cg.lowerToStack(new_val);
7221 try func.addAtomicMemArg(switch (ty.abiSize(zcu)) {7219 try cg.addAtomicMemArg(switch (ty.abiSize(zcu)) {
7222 1 => .i32_atomic_rmw8_cmpxchg_u,7220 1 => .i32_atomic_rmw8_cmpxchg_u,
7223 2 => .i32_atomic_rmw16_cmpxchg_u,7221 2 => .i32_atomic_rmw16_cmpxchg_u,
7224 4 => .i32_atomic_rmw_cmpxchg,7222 4 => .i32_atomic_rmw_cmpxchg,
7225 8 => .i32_atomic_rmw_cmpxchg,7223 8 => .i32_atomic_rmw_cmpxchg,
7226 else => |size| return func.fail("TODO: implement `@cmpxchg` for types with abi size '{d}'", .{size}),7224 else => |size| return cg.fail("TODO: implement `@cmpxchg` for types with abi size '{d}'", .{size}),
7227 }, .{7225 }, .{
7228 .offset = ptr_operand.offset(),7226 .offset = ptr_operand.offset(),
7229 .alignment = @intCast(ty.abiAlignment(zcu).toByteUnits().?),7227 .alignment = @intCast(ty.abiAlignment(zcu).toByteUnits().?),
7230 });7228 });
7231 try func.addLabel(.local_tee, val_local.local.value);7229 try cg.addLabel(.local_tee, val_local.local.value);
7232 _ = try func.cmp(.stack, expected_val, ty, .eq);7230 _ = try cg.cmp(.stack, expected_val, ty, .eq);
7233 try func.addLabel(.local_set, cmp_result.local.value);7231 try cg.addLabel(.local_set, cmp_result.local.value);
7234 break :val val_local;7232 break :val val_local;
7235 } else val: {7233 } else val: {
7236 if (ty.abiSize(zcu) > 8) {7234 if (ty.abiSize(zcu) > 8) {
7237 return func.fail("TODO: Implement `@cmpxchg` for types larger than abi size of 8 bytes", .{});7235 return cg.fail("TODO: Implement `@cmpxchg` for types larger than abi size of 8 bytes", .{});
7238 }7236 }
7239 const ptr_val = try WValue.toLocal(try func.load(ptr_operand, ty, 0), func, ty);7237 const ptr_val = try WValue.toLocal(try cg.load(ptr_operand, ty, 0), cg, ty);
72407238
7241 try func.lowerToStack(ptr_operand);7239 try cg.lowerToStack(ptr_operand);
7242 try func.lowerToStack(new_val);7240 try cg.lowerToStack(new_val);
7243 try func.emitWValue(ptr_val);7241 try cg.emitWValue(ptr_val);
7244 _ = try func.cmp(ptr_val, expected_val, ty, .eq);7242 _ = try cg.cmp(ptr_val, expected_val, ty, .eq);
7245 try func.addLabel(.local_tee, cmp_result.local.value);7243 try cg.addLabel(.local_tee, cmp_result.local.value);
7246 try func.addTag(.select);7244 try cg.addTag(.select);
7247 try func.store(.stack, .stack, ty, 0);7245 try cg.store(.stack, .stack, ty, 0);
72487246
7249 break :val ptr_val;7247 break :val ptr_val;
7250 };7248 };
72517249
7252 const result = if (isByRef(result_ty, pt, func.target)) val: {7250 const result = if (isByRef(result_ty, pt, cg.target)) val: {
7253 try func.emitWValue(cmp_result);7251 try cg.emitWValue(cmp_result);
7254 try func.addImm32(~@as(u32, 0));7252 try cg.addImm32(~@as(u32, 0));
7255 try func.addTag(.i32_xor);7253 try cg.addTag(.i32_xor);
7256 try func.addImm32(1);7254 try cg.addImm32(1);
7257 try func.addTag(.i32_and);7255 try cg.addTag(.i32_and);
7258 const and_result = try WValue.toLocal(.stack, func, Type.bool);7256 const and_result = try WValue.toLocal(.stack, cg, Type.bool);
7259 const result_ptr = try func.allocStack(result_ty);7257 const result_ptr = try cg.allocStack(result_ty);
7260 try func.store(result_ptr, and_result, Type.bool, @as(u32, @intCast(ty.abiSize(zcu))));7258 try cg.store(result_ptr, and_result, Type.bool, @as(u32, @intCast(ty.abiSize(zcu))));
7261 try func.store(result_ptr, ptr_val, ty, 0);7259 try cg.store(result_ptr, ptr_val, ty, 0);
7262 break :val result_ptr;7260 break :val result_ptr;
7263 } else val: {7261 } else val: {
7264 try func.addImm32(0);7262 try cg.addImm32(0);
7265 try func.emitWValue(ptr_val);7263 try cg.emitWValue(ptr_val);
7266 try func.emitWValue(cmp_result);7264 try cg.emitWValue(cmp_result);
7267 try func.addTag(.select);7265 try cg.addTag(.select);
7268 break :val .stack;7266 break :val .stack;
7269 };7267 };
72707268
7271 return func.finishAir(inst, result, &.{ extra.ptr, extra.expected_value, extra.new_value });7269 return cg.finishAir(inst, result, &.{ extra.ptr, extra.expected_value, extra.new_value });
7272}7270}
72737271
7274fn airAtomicLoad(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {7272fn airAtomicLoad(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
7275 const pt = func.pt;7273 const pt = cg.pt;
7276 const atomic_load = func.air.instructions.items(.data)[@intFromEnum(inst)].atomic_load;7274 const atomic_load = cg.air.instructions.items(.data)[@intFromEnum(inst)].atomic_load;
7277 const ptr = try func.resolveInst(atomic_load.ptr);7275 const ptr = try cg.resolveInst(atomic_load.ptr);
7278 const ty = func.typeOfIndex(inst);7276 const ty = cg.typeOfIndex(inst);
72797277
7280 if (func.useAtomicFeature()) {7278 if (cg.useAtomicFeature()) {
7281 const tag: std.wasm.AtomicsOpcode = switch (ty.abiSize(pt.zcu)) {7279 const tag: std.wasm.AtomicsOpcode = switch (ty.abiSize(pt.zcu)) {
7282 1 => .i32_atomic_load8_u,7280 1 => .i32_atomic_load8_u,
7283 2 => .i32_atomic_load16_u,7281 2 => .i32_atomic_load16_u,
7284 4 => .i32_atomic_load,7282 4 => .i32_atomic_load,
7285 8 => .i64_atomic_load,7283 8 => .i64_atomic_load,
7286 else => |size| return func.fail("TODO: @atomicLoad for types with abi size {d}", .{size}),7284 else => |size| return cg.fail("TODO: @atomicLoad for types with abi size {d}", .{size}),
7287 };7285 };
7288 try func.emitWValue(ptr);7286 try cg.emitWValue(ptr);
7289 try func.addAtomicMemArg(tag, .{7287 try cg.addAtomicMemArg(tag, .{
7290 .offset = ptr.offset(),7288 .offset = ptr.offset(),
7291 .alignment = @intCast(ty.abiAlignment(pt.zcu).toByteUnits().?),7289 .alignment = @intCast(ty.abiAlignment(pt.zcu).toByteUnits().?),
7292 });7290 });
7293 } else {7291 } else {
7294 _ = try func.load(ptr, ty, 0);7292 _ = try cg.load(ptr, ty, 0);
7295 }7293 }
72967294
7297 return func.finishAir(inst, .stack, &.{atomic_load.ptr});7295 return cg.finishAir(inst, .stack, &.{atomic_load.ptr});
7298}7296}
72997297
7300fn airAtomicRmw(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {7298fn airAtomicRmw(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
7301 const pt = func.pt;7299 const pt = cg.pt;
7302 const zcu = pt.zcu;7300 const zcu = pt.zcu;
7303 const pl_op = func.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;7301 const pl_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;
7304 const extra = func.air.extraData(Air.AtomicRmw, pl_op.payload).data;7302 const extra = cg.air.extraData(Air.AtomicRmw, pl_op.payload).data;
73057303
7306 const ptr = try func.resolveInst(pl_op.operand);7304 const ptr = try cg.resolveInst(pl_op.operand);
7307 const operand = try func.resolveInst(extra.operand);7305 const operand = try cg.resolveInst(extra.operand);
7308 const ty = func.typeOfIndex(inst);7306 const ty = cg.typeOfIndex(inst);
7309 const op: std.builtin.AtomicRmwOp = extra.op();7307 const op: std.builtin.AtomicRmwOp = extra.op();
73107308
7311 if (func.useAtomicFeature()) {7309 if (cg.useAtomicFeature()) {
7312 switch (op) {7310 switch (op) {
7313 .Max,7311 .Max,
7314 .Min,7312 .Min,
7315 .Nand,7313 .Nand,
7316 => {7314 => {
7317 const tmp = try func.load(ptr, ty, 0);7315 const tmp = try cg.load(ptr, ty, 0);
7318 const value = try tmp.toLocal(func, ty);7316 const value = try tmp.toLocal(cg, ty);
73197317
7320 // create a loop to cmpxchg the new value7318 // create a loop to cmpxchg the new value
7321 try func.startBlock(.loop, std.wasm.block_empty);7319 try cg.startBlock(.loop, std.wasm.block_empty);
73227320
7323 try func.emitWValue(ptr);7321 try cg.emitWValue(ptr);
7324 try func.emitWValue(value);7322 try cg.emitWValue(value);
7325 if (op == .Nand) {7323 if (op == .Nand) {
7326 const wasm_bits = toWasmBits(@intCast(ty.bitSize(zcu))).?;7324 const wasm_bits = toWasmBits(@intCast(ty.bitSize(zcu))).?;
73277325
7328 const and_res = try func.binOp(value, operand, ty, .@"and");7326 const and_res = try cg.binOp(value, operand, ty, .@"and");
7329 if (wasm_bits == 32)7327 if (wasm_bits == 32)
7330 try func.addImm32(~@as(u32, 0))7328 try cg.addImm32(~@as(u32, 0))
7331 else if (wasm_bits == 64)7329 else if (wasm_bits == 64)
7332 try func.addImm64(~@as(u64, 0))7330 try cg.addImm64(~@as(u64, 0))
7333 else7331 else
7334 return func.fail("TODO: `@atomicRmw` with operator `Nand` for types larger than 64 bits", .{});7332 return cg.fail("TODO: `@atomicRmw` with operator `Nand` for types larger than 64 bits", .{});
7335 _ = try func.binOp(and_res, .stack, ty, .xor);7333 _ = try cg.binOp(and_res, .stack, ty, .xor);
7336 } else {7334 } else {
7337 try func.emitWValue(value);7335 try cg.emitWValue(value);
7338 try func.emitWValue(operand);7336 try cg.emitWValue(operand);
7339 _ = try func.cmp(value, operand, ty, if (op == .Max) .gt else .lt);7337 _ = try cg.cmp(value, operand, ty, if (op == .Max) .gt else .lt);
7340 try func.addTag(.select);7338 try cg.addTag(.select);
7341 }7339 }
7342 try func.addAtomicMemArg(7340 try cg.addAtomicMemArg(
7343 switch (ty.abiSize(zcu)) {7341 switch (ty.abiSize(zcu)) {
7344 1 => .i32_atomic_rmw8_cmpxchg_u,7342 1 => .i32_atomic_rmw8_cmpxchg_u,
7345 2 => .i32_atomic_rmw16_cmpxchg_u,7343 2 => .i32_atomic_rmw16_cmpxchg_u,
7346 4 => .i32_atomic_rmw_cmpxchg,7344 4 => .i32_atomic_rmw_cmpxchg,
7347 8 => .i64_atomic_rmw_cmpxchg,7345 8 => .i64_atomic_rmw_cmpxchg,
7348 else => return func.fail("TODO: implement `@atomicRmw` with operation `{s}` for types larger than 64 bits", .{@tagName(op)}),7346 else => return cg.fail("TODO: implement `@atomicRmw` with operation `{s}` for types larger than 64 bits", .{@tagName(op)}),
7349 },7347 },
7350 .{7348 .{
7351 .offset = ptr.offset(),7349 .offset = ptr.offset(),
7352 .alignment = @intCast(ty.abiAlignment(zcu).toByteUnits().?),7350 .alignment = @intCast(ty.abiAlignment(zcu).toByteUnits().?),
7353 },7351 },
7354 );7352 );
7355 const select_res = try func.allocLocal(ty);7353 const select_res = try cg.allocLocal(ty);
7356 try func.addLabel(.local_tee, select_res.local.value);7354 try cg.addLabel(.local_tee, select_res.local.value);
7357 _ = try func.cmp(.stack, value, ty, .neq); // leave on stack so we can use it for br_if7355 _ = try cg.cmp(.stack, value, ty, .neq); // leave on stack so we can use it for br_if
73587356
7359 try func.emitWValue(select_res);7357 try cg.emitWValue(select_res);
7360 try func.addLabel(.local_set, value.local.value);7358 try cg.addLabel(.local_set, value.local.value);
73617359
7362 try func.addLabel(.br_if, 0);7360 try cg.addLabel(.br_if, 0);
7363 try func.endBlock();7361 try cg.endBlock();
7364 return func.finishAir(inst, value, &.{ pl_op.operand, extra.operand });7362 return cg.finishAir(inst, value, &.{ pl_op.operand, extra.operand });
7365 },7363 },
73667364
7367 // the other operations have their own instructions for Wasm.7365 // the other operations have their own instructions for Wasm.
7368 else => {7366 else => {
7369 try func.emitWValue(ptr);7367 try cg.emitWValue(ptr);
7370 try func.emitWValue(operand);7368 try cg.emitWValue(operand);
7371 const tag: std.wasm.AtomicsOpcode = switch (ty.abiSize(zcu)) {7369 const tag: std.wasm.AtomicsOpcode = switch (ty.abiSize(zcu)) {
7372 1 => switch (op) {7370 1 => switch (op) {
7373 .Xchg => .i32_atomic_rmw8_xchg_u,7371 .Xchg => .i32_atomic_rmw8_xchg_u,
...@@ -7405,22 +7403,22 @@ fn airAtomicRmw(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -7405,22 +7403,22 @@ fn airAtomicRmw(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
7405 .Xor => .i64_atomic_rmw_xor,7403 .Xor => .i64_atomic_rmw_xor,
7406 else => unreachable,7404 else => unreachable,
7407 },7405 },
7408 else => |size| return func.fail("TODO: Implement `@atomicRmw` for types with abi size {d}", .{size}),7406 else => |size| return cg.fail("TODO: Implement `@atomicRmw` for types with abi size {d}", .{size}),
7409 };7407 };
7410 try func.addAtomicMemArg(tag, .{7408 try cg.addAtomicMemArg(tag, .{
7411 .offset = ptr.offset(),7409 .offset = ptr.offset(),
7412 .alignment = @intCast(ty.abiAlignment(zcu).toByteUnits().?),7410 .alignment = @intCast(ty.abiAlignment(zcu).toByteUnits().?),
7413 });7411 });
7414 return func.finishAir(inst, .stack, &.{ pl_op.operand, extra.operand });7412 return cg.finishAir(inst, .stack, &.{ pl_op.operand, extra.operand });
7415 },7413 },
7416 }7414 }
7417 } else {7415 } else {
7418 const loaded = try func.load(ptr, ty, 0);7416 const loaded = try cg.load(ptr, ty, 0);
7419 const result = try loaded.toLocal(func, ty);7417 const result = try loaded.toLocal(cg, ty);
74207418
7421 switch (op) {7419 switch (op) {
7422 .Xchg => {7420 .Xchg => {
7423 try func.store(ptr, operand, ty, 0);7421 try cg.store(ptr, operand, ty, 0);
7424 },7422 },
7425 .Add,7423 .Add,
7426 .Sub,7424 .Sub,
...@@ -7428,8 +7426,8 @@ fn airAtomicRmw(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -7428,8 +7426,8 @@ fn airAtomicRmw(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
7428 .Or,7426 .Or,
7429 .Xor,7427 .Xor,
7430 => {7428 => {
7431 try func.emitWValue(ptr);7429 try cg.emitWValue(ptr);
7432 _ = try func.binOp(result, operand, ty, switch (op) {7430 _ = try cg.binOp(result, operand, ty, switch (op) {
7433 .Add => .add,7431 .Add => .add,
7434 .Sub => .sub,7432 .Sub => .sub,
7435 .And => .@"and",7433 .And => .@"and",
...@@ -7438,87 +7436,87 @@ fn airAtomicRmw(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -7438,87 +7436,87 @@ fn airAtomicRmw(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
7438 else => unreachable,7436 else => unreachable,
7439 });7437 });
7440 if (ty.isInt(zcu) and (op == .Add or op == .Sub)) {7438 if (ty.isInt(zcu) and (op == .Add or op == .Sub)) {
7441 _ = try func.wrapOperand(.stack, ty);7439 _ = try cg.wrapOperand(.stack, ty);
7442 }7440 }
7443 try func.store(.stack, .stack, ty, ptr.offset());7441 try cg.store(.stack, .stack, ty, ptr.offset());
7444 },7442 },
7445 .Max,7443 .Max,
7446 .Min,7444 .Min,
7447 => {7445 => {
7448 try func.emitWValue(ptr);7446 try cg.emitWValue(ptr);
7449 try func.emitWValue(result);7447 try cg.emitWValue(result);
7450 try func.emitWValue(operand);7448 try cg.emitWValue(operand);
7451 _ = try func.cmp(result, operand, ty, if (op == .Max) .gt else .lt);7449 _ = try cg.cmp(result, operand, ty, if (op == .Max) .gt else .lt);
7452 try func.addTag(.select);7450 try cg.addTag(.select);
7453 try func.store(.stack, .stack, ty, ptr.offset());7451 try cg.store(.stack, .stack, ty, ptr.offset());
7454 },7452 },
7455 .Nand => {7453 .Nand => {
7456 const wasm_bits = toWasmBits(@intCast(ty.bitSize(zcu))).?;7454 const wasm_bits = toWasmBits(@intCast(ty.bitSize(zcu))).?;
74577455
7458 try func.emitWValue(ptr);7456 try cg.emitWValue(ptr);
7459 const and_res = try func.binOp(result, operand, ty, .@"and");7457 const and_res = try cg.binOp(result, operand, ty, .@"and");
7460 if (wasm_bits == 32)7458 if (wasm_bits == 32)
7461 try func.addImm32(~@as(u32, 0))7459 try cg.addImm32(~@as(u32, 0))
7462 else if (wasm_bits == 64)7460 else if (wasm_bits == 64)
7463 try func.addImm64(~@as(u64, 0))7461 try cg.addImm64(~@as(u64, 0))
7464 else7462 else
7465 return func.fail("TODO: `@atomicRmw` with operator `Nand` for types larger than 64 bits", .{});7463 return cg.fail("TODO: `@atomicRmw` with operator `Nand` for types larger than 64 bits", .{});
7466 _ = try func.binOp(and_res, .stack, ty, .xor);7464 _ = try cg.binOp(and_res, .stack, ty, .xor);
7467 try func.store(.stack, .stack, ty, ptr.offset());7465 try cg.store(.stack, .stack, ty, ptr.offset());
7468 },7466 },
7469 }7467 }
74707468
7471 return func.finishAir(inst, result, &.{ pl_op.operand, extra.operand });7469 return cg.finishAir(inst, result, &.{ pl_op.operand, extra.operand });
7472 }7470 }
7473}7471}
74747472
7475fn airAtomicStore(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {7473fn airAtomicStore(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
7476 const pt = func.pt;7474 const pt = cg.pt;
7477 const zcu = pt.zcu;7475 const zcu = pt.zcu;
7478 const bin_op = func.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;7476 const bin_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
74797477
7480 const ptr = try func.resolveInst(bin_op.lhs);7478 const ptr = try cg.resolveInst(bin_op.lhs);
7481 const operand = try func.resolveInst(bin_op.rhs);7479 const operand = try cg.resolveInst(bin_op.rhs);
7482 const ptr_ty = func.typeOf(bin_op.lhs);7480 const ptr_ty = cg.typeOf(bin_op.lhs);
7483 const ty = ptr_ty.childType(zcu);7481 const ty = ptr_ty.childType(zcu);
74847482
7485 if (func.useAtomicFeature()) {7483 if (cg.useAtomicFeature()) {
7486 const tag: std.wasm.AtomicsOpcode = switch (ty.abiSize(zcu)) {7484 const tag: std.wasm.AtomicsOpcode = switch (ty.abiSize(zcu)) {
7487 1 => .i32_atomic_store8,7485 1 => .i32_atomic_store8,
7488 2 => .i32_atomic_store16,7486 2 => .i32_atomic_store16,
7489 4 => .i32_atomic_store,7487 4 => .i32_atomic_store,
7490 8 => .i64_atomic_store,7488 8 => .i64_atomic_store,
7491 else => |size| return func.fail("TODO: @atomicLoad for types with abi size {d}", .{size}),7489 else => |size| return cg.fail("TODO: @atomicLoad for types with abi size {d}", .{size}),
7492 };7490 };
7493 try func.emitWValue(ptr);7491 try cg.emitWValue(ptr);
7494 try func.lowerToStack(operand);7492 try cg.lowerToStack(operand);
7495 try func.addAtomicMemArg(tag, .{7493 try cg.addAtomicMemArg(tag, .{
7496 .offset = ptr.offset(),7494 .offset = ptr.offset(),
7497 .alignment = @intCast(ty.abiAlignment(zcu).toByteUnits().?),7495 .alignment = @intCast(ty.abiAlignment(zcu).toByteUnits().?),
7498 });7496 });
7499 } else {7497 } else {
7500 try func.store(ptr, operand, ty, 0);7498 try cg.store(ptr, operand, ty, 0);
7501 }7499 }
75027500
7503 return func.finishAir(inst, .none, &.{ bin_op.lhs, bin_op.rhs });7501 return cg.finishAir(inst, .none, &.{ bin_op.lhs, bin_op.rhs });
7504}7502}
75057503
7506fn airFrameAddress(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {7504fn airFrameAddress(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
7507 if (func.initial_stack_value == .none) {7505 if (cg.initial_stack_value == .none) {
7508 try func.initializeStack();7506 try cg.initializeStack();
7509 }7507 }
7510 try func.emitWValue(func.bottom_stack_value);7508 try cg.emitWValue(cg.bottom_stack_value);
7511 return func.finishAir(inst, .stack, &.{});7509 return cg.finishAir(inst, .stack, &.{});
7512}7510}
75137511
7514fn typeOf(func: *CodeGen, inst: Air.Inst.Ref) Type {7512fn typeOf(cg: *CodeGen, inst: Air.Inst.Ref) Type {
7515 const pt = func.pt;7513 const pt = cg.pt;
7516 const zcu = pt.zcu;7514 const zcu = pt.zcu;
7517 return func.air.typeOf(inst, &zcu.intern_pool);7515 return cg.air.typeOf(inst, &zcu.intern_pool);
7518}7516}
75197517
7520fn typeOfIndex(func: *CodeGen, inst: Air.Inst.Index) Type {7518fn typeOfIndex(cg: *CodeGen, inst: Air.Inst.Index) Type {
7521 const pt = func.pt;7519 const pt = cg.pt;
7522 const zcu = pt.zcu;7520 const zcu = pt.zcu;
7523 return func.air.typeOfIndex(inst, &zcu.intern_pool);7521 return cg.air.typeOfIndex(inst, &zcu.intern_pool);
7524}7522}