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{
700700 Overflow,
701701} || link.File.UpdateDebugInfoError;
702702
703pub fn deinit(func: *CodeGen) void {
704 // in case of an error and we still have branches
705 for (func.branches.items) |*branch| {
706 branch.deinit(func.gpa);
707 }
708 func.branches.deinit(func.gpa);
709 func.blocks.deinit(func.gpa);
710 func.loops.deinit(func.gpa);
711 func.locals.deinit(func.gpa);
712 func.simd_immediates.deinit(func.gpa);
713 func.free_locals_i32.deinit(func.gpa);
714 func.free_locals_i64.deinit(func.gpa);
715 func.free_locals_f32.deinit(func.gpa);
716 func.free_locals_f64.deinit(func.gpa);
717 func.free_locals_v128.deinit(func.gpa);
718 func.* = undefined;
703pub fn deinit(cg: *CodeGen) void {
704 const gpa = cg.gpa;
705 for (cg.branches.items) |*branch| branch.deinit(gpa);
706 cg.branches.deinit(gpa);
707 cg.blocks.deinit(gpa);
708 cg.loops.deinit(gpa);
709 cg.locals.deinit(gpa);
710 cg.simd_immediates.deinit(gpa);
711 cg.free_locals_i32.deinit(gpa);
712 cg.free_locals_i64.deinit(gpa);
713 cg.free_locals_f32.deinit(gpa);
714 cg.free_locals_f64.deinit(gpa);
715 cg.free_locals_v128.deinit(gpa);
716 cg.* = undefined;
719717}
720718
721719fn 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
726724
727725/// Resolves the `WValue` for the given instruction `inst`
728726/// When the given instruction has a `Value`, it returns a constant instead
729fn resolveInst(func: *CodeGen, ref: Air.Inst.Ref) InnerError!WValue {
730 var branch_index = func.branches.items.len;
727fn resolveInst(cg: *CodeGen, ref: Air.Inst.Ref) InnerError!WValue {
728 var branch_index = cg.branches.items.len;
731729 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];
733731 if (branch.values.get(ref)) |value| {
734732 return value;
735733 }
......@@ -739,13 +737,13 @@ fn resolveInst(func: *CodeGen, ref: Air.Inst.Ref) InnerError!WValue {
739737 // means we must generate it from a constant.
740738 // We always store constants in the most outer branch as they must never
741739 // 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);
743741 assert(!gop.found_existing);
744742
745 const pt = func.pt;
743 const pt = cg.pt;
746744 const zcu = pt.zcu;
747 const val = (try func.air.value(ref, pt)).?;
748 const ty = func.typeOf(ref);
745 const val = (try cg.air.value(ref, pt)).?;
746 const ty = cg.typeOf(ref);
749747 if (!ty.hasRuntimeBitsIgnoreComptime(zcu) and !ty.isInt(zcu) and !ty.isError(zcu)) {
750748 gop.value_ptr.* = .none;
751749 return .none;
......@@ -757,24 +755,24 @@ fn resolveInst(func: *CodeGen, ref: Air.Inst.Ref) InnerError!WValue {
757755 //
758756 // In the other cases, we will simply lower the constant to a value that fits
759757 // 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))
761759 .{ .uav_ref = .{ .ip_index = val.toIntern() } }
762760 else
763 try func.lowerConstant(val, ty);
761 try cg.lowerConstant(val, ty);
764762
765763 gop.value_ptr.* = result;
766764 return result;
767765}
768766
769767/// 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 {
771769 assert(operands.len <= Liveness.bpi - 1);
772 var tomb_bits = func.liveness.getTombBits(inst);
770 var tomb_bits = cg.liveness.getTombBits(inst);
773771 for (operands) |operand| {
774772 const dies = @as(u1, @truncate(tomb_bits)) != 0;
775773 tomb_bits >>= 1;
776774 if (!dies) continue;
777 processDeath(func, operand);
775 processDeath(cg, operand);
778776 }
779777
780778 // results of `none` can never be referenced.
......@@ -782,13 +780,13 @@ fn finishAir(func: *CodeGen, inst: Air.Inst.Index, result: WValue, operands: []c
782780 const trackable_result = if (result != .stack)
783781 result
784782 else
785 try result.toLocal(func, func.typeOfIndex(inst));
786 const branch = func.currentBranch();
783 try result.toLocal(cg, cg.typeOfIndex(inst));
784 const branch = cg.currentBranch();
787785 branch.values.putAssumeCapacityNoClobber(inst.toRef(), trackable_result);
788786 }
789787
790788 if (std.debug.runtime_safety) {
791 func.air_bookkeeping += 1;
789 cg.air_bookkeeping += 1;
792790 }
793791}
794792
......@@ -801,8 +799,8 @@ const Branch = struct {
801799 }
802800};
803801
804inline fn currentBranch(func: *CodeGen) *Branch {
805 return &func.branches.items[func.branches.items.len - 1];
802inline fn currentBranch(cg: *CodeGen) *Branch {
803 return &cg.branches.items[cg.branches.items.len - 1];
806804}
807805
808806const BigTomb = struct {
......@@ -829,126 +827,126 @@ const BigTomb = struct {
829827 }
830828};
831829
832fn iterateBigTomb(func: *CodeGen, inst: Air.Inst.Index, operand_count: usize) !BigTomb {
833 try func.currentBranch().values.ensureUnusedCapacity(func.gpa, operand_count + 1);
830fn iterateBigTomb(cg: *CodeGen, inst: Air.Inst.Index, operand_count: usize) !BigTomb {
831 try cg.currentBranch().values.ensureUnusedCapacity(cg.gpa, operand_count + 1);
834832 return BigTomb{
835 .gen = func,
833 .gen = cg,
836834 .inst = inst,
837 .lbt = func.liveness.iterateBigTomb(inst),
835 .lbt = cg.liveness.iterateBigTomb(inst),
838836 };
839837}
840838
841fn processDeath(func: *CodeGen, ref: Air.Inst.Ref) void {
839fn processDeath(cg: *CodeGen, ref: Air.Inst.Ref) void {
842840 if (ref.toIndex() == null) return;
843841 // Branches are currently only allowed to free locals allocated
844842 // within their own branch.
845843 // 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;
847845 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);
849847 if (value.local.value < reserved_indexes) {
850848 return; // function arguments can never be re-used
851849 }
852850 log.debug("Decreasing reference for ref: %{d}, using local '{d}'", .{ @intFromEnum(ref.toIndex().?), value.local.value });
853851 value.local.references -= 1; // if this panics, a call to `reuseOperand` was forgotten by the developer
854852 if (value.local.references == 0) {
855 value.free(func);
853 value.free(cg);
856854 }
857855}
858856
859857/// Appends a MIR instruction and returns its index within the list of instructions
860fn addInst(func: *CodeGen, inst: Mir.Inst) error{OutOfMemory}!void {
861 try func.mir_instructions.append(func.gpa, inst);
858fn addInst(cg: *CodeGen, inst: Mir.Inst) error{OutOfMemory}!void {
859 try cg.mir_instructions.append(cg.gpa, inst);
862860}
863861
864fn addTag(func: *CodeGen, tag: Mir.Inst.Tag) error{OutOfMemory}!void {
865 try func.addInst(.{ .tag = tag, .data = .{ .tag = {} } });
862fn addTag(cg: *CodeGen, tag: Mir.Inst.Tag) error{OutOfMemory}!void {
863 try cg.addInst(.{ .tag = tag, .data = .{ .tag = {} } });
866864}
867865
868fn addExtended(func: *CodeGen, opcode: std.wasm.MiscOpcode) error{OutOfMemory}!void {
869 const extra_index = @as(u32, @intCast(func.mir_extra.items.len));
870 try func.mir_extra.append(func.gpa, @intFromEnum(opcode));
871 try func.addInst(.{ .tag = .misc_prefix, .data = .{ .payload = extra_index } });
866fn addExtended(cg: *CodeGen, opcode: std.wasm.MiscOpcode) error{OutOfMemory}!void {
867 const extra_index = @as(u32, @intCast(cg.mir_extra.items.len));
868 try cg.mir_extra.append(cg.gpa, @intFromEnum(opcode));
869 try cg.addInst(.{ .tag = .misc_prefix, .data = .{ .payload = extra_index } });
872870}
873871
874fn addLabel(func: *CodeGen, tag: Mir.Inst.Tag, label: u32) error{OutOfMemory}!void {
875 try func.addInst(.{ .tag = tag, .data = .{ .label = label } });
872fn addLabel(cg: *CodeGen, tag: Mir.Inst.Tag, label: u32) error{OutOfMemory}!void {
873 try cg.addInst(.{ .tag = tag, .data = .{ .label = label } });
876874}
877875
878fn addIpIndex(func: *CodeGen, tag: Mir.Inst.Tag, i: InternPool.Index) Allocator.Error!void {
879 try func.addInst(.{ .tag = tag, .data = .{ .ip_index = i } });
876fn addIpIndex(cg: *CodeGen, tag: Mir.Inst.Tag, i: InternPool.Index) Allocator.Error!void {
877 try cg.addInst(.{ .tag = tag, .data = .{ .ip_index = i } });
880878}
881879
882fn addNav(func: *CodeGen, tag: Mir.Inst.Tag, i: InternPool.Nav.Index) Allocator.Error!void {
883 try func.addInst(.{ .tag = tag, .data = .{ .nav_index = i } });
880fn addNav(cg: *CodeGen, tag: Mir.Inst.Tag, i: InternPool.Nav.Index) Allocator.Error!void {
881 try cg.addInst(.{ .tag = tag, .data = .{ .nav_index = i } });
884882}
885883
886884/// Accepts an unsigned 32bit integer rather than a signed integer to
887885/// prevent us from having to bitcast multiple times as most values
888886/// within codegen are represented as unsigned rather than signed.
889fn addImm32(func: *CodeGen, imm: u32) error{OutOfMemory}!void {
890 try func.addInst(.{ .tag = .i32_const, .data = .{ .imm32 = @bitCast(imm) } });
887fn addImm32(cg: *CodeGen, imm: u32) error{OutOfMemory}!void {
888 try cg.addInst(.{ .tag = .i32_const, .data = .{ .imm32 = @bitCast(imm) } });
891889}
892890
893891/// Accepts an unsigned 64bit integer rather than a signed integer to
894892/// prevent us from having to bitcast multiple times as most values
895893/// within codegen are represented as unsigned rather than signed.
896fn addImm64(func: *CodeGen, imm: u64) error{OutOfMemory}!void {
897 const extra_index = try func.addExtra(Mir.Imm64.init(imm));
898 try func.addInst(.{ .tag = .i64_const, .data = .{ .payload = extra_index } });
894fn addImm64(cg: *CodeGen, imm: u64) error{OutOfMemory}!void {
895 const extra_index = try cg.addExtra(Mir.Imm64.init(imm));
896 try cg.addInst(.{ .tag = .i64_const, .data = .{ .payload = extra_index } });
899897}
900898
901899/// Accepts the index into the list of 128bit-immediates
902fn addImm128(func: *CodeGen, index: u32) error{OutOfMemory}!void {
903 const simd_values = func.simd_immediates.items[index];
904 const extra_index = @as(u32, @intCast(func.mir_extra.items.len));
900fn addImm128(cg: *CodeGen, index: u32) error{OutOfMemory}!void {
901 const simd_values = cg.simd_immediates.items[index];
902 const extra_index = @as(u32, @intCast(cg.mir_extra.items.len));
905903 // tag + 128bit value
906 try func.mir_extra.ensureUnusedCapacity(func.gpa, 5);
907 func.mir_extra.appendAssumeCapacity(@intFromEnum(std.wasm.SimdOpcode.v128_const));
908 func.mir_extra.appendSliceAssumeCapacity(@alignCast(mem.bytesAsSlice(u32, &simd_values)));
909 try func.addInst(.{ .tag = .simd_prefix, .data = .{ .payload = extra_index } });
904 try cg.mir_extra.ensureUnusedCapacity(cg.gpa, 5);
905 cg.mir_extra.appendAssumeCapacity(@intFromEnum(std.wasm.SimdOpcode.v128_const));
906 cg.mir_extra.appendSliceAssumeCapacity(@alignCast(mem.bytesAsSlice(u32, &simd_values)));
907 try cg.addInst(.{ .tag = .simd_prefix, .data = .{ .payload = extra_index } });
910908}
911909
912fn addFloat64(func: *CodeGen, float: f64) error{OutOfMemory}!void {
913 const extra_index = try func.addExtra(Mir.Float64.init(float));
914 try func.addInst(.{ .tag = .f64_const, .data = .{ .payload = extra_index } });
910fn addFloat64(cg: *CodeGen, float: f64) error{OutOfMemory}!void {
911 const extra_index = try cg.addExtra(Mir.Float64.init(float));
912 try cg.addInst(.{ .tag = .f64_const, .data = .{ .payload = extra_index } });
915913}
916914
917915/// 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 {
919 const extra_index = try func.addExtra(mem_arg);
920 try func.addInst(.{ .tag = tag, .data = .{ .payload = extra_index } });
916fn addMemArg(cg: *CodeGen, tag: Mir.Inst.Tag, mem_arg: Mir.MemArg) error{OutOfMemory}!void {
917 const extra_index = try cg.addExtra(mem_arg);
918 try cg.addInst(.{ .tag = tag, .data = .{ .payload = extra_index } });
921919}
922920
923921/// Inserts an instruction from the 'atomics' feature which accesses wasm's linear memory dependent on the
924922/// given `tag`.
925fn addAtomicMemArg(func: *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) }));
927 _ = try func.addExtra(mem_arg);
928 try func.addInst(.{ .tag = .atomics_prefix, .data = .{ .payload = extra_index } });
923fn addAtomicMemArg(cg: *CodeGen, tag: std.wasm.AtomicsOpcode, mem_arg: Mir.MemArg) error{OutOfMemory}!void {
924 const extra_index = try cg.addExtra(@as(struct { val: u32 }, .{ .val = @intFromEnum(tag) }));
925 _ = try cg.addExtra(mem_arg);
926 try cg.addInst(.{ .tag = .atomics_prefix, .data = .{ .payload = extra_index } });
929927}
930928
931929/// Helper function to emit atomic mir opcodes.
932fn addAtomicTag(func: *CodeGen, tag: std.wasm.AtomicsOpcode) error{OutOfMemory}!void {
933 const extra_index = try func.addExtra(@as(struct { val: u32 }, .{ .val = @intFromEnum(tag) }));
934 try func.addInst(.{ .tag = .atomics_prefix, .data = .{ .payload = extra_index } });
930fn addAtomicTag(cg: *CodeGen, tag: std.wasm.AtomicsOpcode) error{OutOfMemory}!void {
931 const extra_index = try cg.addExtra(@as(struct { val: u32 }, .{ .val = @intFromEnum(tag) }));
932 try cg.addInst(.{ .tag = .atomics_prefix, .data = .{ .payload = extra_index } });
935933}
936934
937935/// Appends entries to `mir_extra` based on the type of `extra`.
938936/// Returns the index into `mir_extra`
939fn addExtra(func: *CodeGen, extra: anytype) error{OutOfMemory}!u32 {
937fn addExtra(cg: *CodeGen, extra: anytype) error{OutOfMemory}!u32 {
940938 const fields = std.meta.fields(@TypeOf(extra));
941 try func.mir_extra.ensureUnusedCapacity(func.gpa, fields.len);
942 return func.addExtraAssumeCapacity(extra);
939 try cg.mir_extra.ensureUnusedCapacity(cg.gpa, fields.len);
940 return cg.addExtraAssumeCapacity(extra);
943941}
944942
945943/// Appends entries to `mir_extra` based on the type of `extra`.
946944/// Returns the index into `mir_extra`
947fn addExtraAssumeCapacity(func: *CodeGen, extra: anytype) error{OutOfMemory}!u32 {
945fn addExtraAssumeCapacity(cg: *CodeGen, extra: anytype) error{OutOfMemory}!u32 {
948946 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));
950948 inline for (fields) |field| {
951 func.mir_extra.appendAssumeCapacity(switch (field.type) {
949 cg.mir_extra.appendAssumeCapacity(switch (field.type) {
952950 u32 => @field(extra, field.name),
953951 i32 => @bitCast(@field(extra, field.name)),
954952 InternPool.Index => @intFromEnum(@field(extra, field.name)),
......@@ -1015,24 +1013,24 @@ fn genBlockType(ty: Type, pt: Zcu.PerThread, target: *const std.Target) u8 {
10151013}
10161014
10171015/// 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 {
10191017 switch (value) {
10201018 .dead => unreachable, // reference to free'd `WValue` (missing reuseOperand?)
10211019 .none, .stack => {}, // no-op
1022 .local => |idx| try func.addLabel(.local_get, idx.value),
1023 .imm32 => |val| try func.addImm32(val),
1024 .imm64 => |val| try func.addImm64(val),
1025 .imm128 => |val| try func.addImm128(val),
1026 .float32 => |val| try func.addInst(.{ .tag = .f32_const, .data = .{ .float32 = val } }),
1027 .float64 => |val| try func.addFloat64(val),
1020 .local => |idx| try cg.addLabel(.local_get, idx.value),
1021 .imm32 => |val| try cg.addImm32(val),
1022 .imm64 => |val| try cg.addImm64(val),
1023 .imm128 => |val| try cg.addImm128(val),
1024 .float32 => |val| try cg.addInst(.{ .tag = .f32_const, .data = .{ .float32 = val } }),
1025 .float64 => |val| try cg.addFloat64(val),
10281026 .nav_ref => |nav_ref| {
10291027 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 } });
10311029 } else {
1032 try func.addInst(.{
1030 try cg.addInst(.{
10331031 .tag = .nav_ref_off,
10341032 .data = .{
1035 .payload = try func.addExtra(Mir.NavRefOff{
1033 .payload = try cg.addExtra(Mir.NavRefOff{
10361034 .nav_index = nav_ref.nav_index,
10371035 .offset = nav_ref.offset,
10381036 }),
......@@ -1042,12 +1040,12 @@ fn emitWValue(func: *CodeGen, value: WValue) InnerError!void {
10421040 },
10431041 .uav_ref => |uav| {
10441042 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 } });
10461044 } else {
1047 try func.addInst(.{
1045 try cg.addInst(.{
10481046 .tag = .uav_ref_off,
10491047 .data = .{
1050 .payload = try func.addExtra(Mir.UavRefOff{
1048 .payload = try cg.addExtra(Mir.UavRefOff{
10511049 .ip_index = uav.ip_index,
10521050 .offset = uav.offset,
10531051 }),
......@@ -1055,7 +1053,7 @@ fn emitWValue(func: *CodeGen, value: WValue) InnerError!void {
10551053 });
10561054 }
10571055 },
1058 .stack_offset => try func.addLabel(.local_get, func.bottom_stack_value.local.value), // caller must ensure to address the offset
1056 .stack_offset => try cg.addLabel(.local_get, cg.bottom_stack_value.local.value), // caller must ensure to address the offset
10591057 }
10601058}
10611059
......@@ -1063,7 +1061,7 @@ fn emitWValue(func: *CodeGen, value: WValue) InnerError!void {
10631061/// The old `WValue` found at instruction `ref` is then replaced by the
10641062/// modified `WValue` and returned. When given a non-local or non-stack-offset,
10651063/// 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 {
10671065 if (operand != .local and operand != .stack_offset) return operand;
10681066 var new_value = operand;
10691067 switch (new_value) {
......@@ -1071,17 +1069,17 @@ fn reuseOperand(func: *CodeGen, ref: Air.Inst.Ref, operand: WValue) WValue {
10711069 .stack_offset => |*stack_offset| stack_offset.references += 1,
10721070 else => unreachable,
10731071 }
1074 const old_value = func.getResolvedInst(ref);
1072 const old_value = cg.getResolvedInst(ref);
10751073 old_value.* = new_value;
10761074 return new_value;
10771075}
10781076
10791077/// From a reference, returns its resolved `WValue`.
10801078/// It's illegal to provide a `Air.Inst.Ref` that hasn't been resolved yet.
1081fn getResolvedInst(func: *CodeGen, ref: Air.Inst.Ref) *WValue {
1082 var index = func.branches.items.len;
1079fn getResolvedInst(cg: *CodeGen, ref: Air.Inst.Ref) *WValue {
1080 var index = cg.branches.items.len;
10831081 while (index > 0) : (index -= 1) {
1084 const branch = func.branches.items[index - 1];
1082 const branch = cg.branches.items[index - 1];
10851083 if (branch.values.getPtr(ref)) |value| {
10861084 return value;
10871085 }
......@@ -1091,31 +1089,31 @@ fn getResolvedInst(func: *CodeGen, ref: Air.Inst.Ref) *WValue {
10911089
10921090/// Creates one locals for a given `Type`.
10931091/// Returns a corresponding `Wvalue` with `local` as active tag
1094fn allocLocal(func: *CodeGen, ty: Type) InnerError!WValue {
1095 const pt = func.pt;
1096 const valtype = typeToValtype(ty, pt, func.target);
1092fn allocLocal(cg: *CodeGen, ty: Type) InnerError!WValue {
1093 const pt = cg.pt;
1094 const valtype = typeToValtype(ty, pt, cg.target);
10971095 const index_or_null = switch (valtype) {
1098 .i32 => func.free_locals_i32.popOrNull(),
1099 .i64 => func.free_locals_i64.popOrNull(),
1100 .f32 => func.free_locals_f32.popOrNull(),
1101 .f64 => func.free_locals_f64.popOrNull(),
1102 .v128 => func.free_locals_v128.popOrNull(),
1096 .i32 => cg.free_locals_i32.popOrNull(),
1097 .i64 => cg.free_locals_i64.popOrNull(),
1098 .f32 => cg.free_locals_f32.popOrNull(),
1099 .f64 => cg.free_locals_f64.popOrNull(),
1100 .v128 => cg.free_locals_v128.popOrNull(),
11031101 };
11041102 if (index_or_null) |index| {
11051103 log.debug("reusing local ({d}) of type {}", .{ index, valtype });
11061104 return .{ .local = .{ .value = index, .references = 1 } };
11071105 }
11081106 log.debug("new local of type {}", .{valtype});
1109 return func.ensureAllocLocal(ty);
1107 return cg.ensureAllocLocal(ty);
11101108}
11111109
11121110/// Ensures a new local will be created. This is useful when it's useful
11131111/// to use a zero-initialized local.
1114fn ensureAllocLocal(func: *CodeGen, ty: Type) InnerError!WValue {
1115 const pt = func.pt;
1116 try func.locals.append(func.gpa, genValtype(ty, pt, func.target));
1117 const initial_index = func.local_index;
1118 func.local_index += 1;
1112fn ensureAllocLocal(cg: *CodeGen, ty: Type) InnerError!WValue {
1113 const pt = cg.pt;
1114 try cg.locals.append(cg.gpa, genValtype(ty, pt, cg.target));
1115 const initial_index = cg.local_index;
1116 cg.local_index += 1;
11191117 return .{ .local = .{ .value = initial_index, .references = 1 } };
11201118}
11211119
......@@ -1291,10 +1289,10 @@ pub fn function(
12911289) Error!Function {
12921290 const zcu = pt.zcu;
12931291 const gpa = zcu.gpa;
1294 const func = zcu.funcInfo(func_index);
1295 const file_scope = zcu.navFileScope(func.owner_nav);
1292 const cg = zcu.funcInfo(func_index);
1293 const file_scope = zcu.navFileScope(cg.owner_nav);
12961294 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);
12981296 const fn_info = zcu.typeToFunc(fn_ty).?;
12991297 const ip = &zcu.intern_pool;
13001298 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(
13091307 .pt = pt,
13101308 .air = air,
13111309 .liveness = liveness,
1312 .owner_nav = func.owner_nav,
1310 .owner_nav = cg.owner_nav,
13131311 .target = target,
13141312 .ptr_size = switch (target.cpu.arch) {
13151313 .wasm32 => .wasm32,
......@@ -1470,89 +1468,89 @@ fn firstParamSRet(
14701468
14711469/// Lowers a Zig type and its value based on a given calling convention to ensure
14721470/// 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 {
14741472 if (cc != .wasm_watc) {
1475 return func.lowerToStack(value);
1473 return cg.lowerToStack(value);
14761474 }
14771475
1478 const pt = func.pt;
1476 const pt = cg.pt;
14791477 const zcu = pt.zcu;
14801478 const ty_classes = abi.classifyType(ty, zcu);
14811479 assert(ty_classes[0] != .none);
14821480 switch (ty.zigTypeTag(zcu)) {
14831481 .@"struct", .@"union" => {
14841482 if (ty_classes[0] == .indirect) {
1485 return func.lowerToStack(value);
1483 return cg.lowerToStack(value);
14861484 }
14871485 assert(ty_classes[0] == .direct);
14881486 const scalar_type = abi.scalarType(ty, zcu);
14891487 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),
14911489 .dead => unreachable,
1492 else => try func.emitWValue(value),
1490 else => try cg.emitWValue(value),
14931491 }
14941492 },
14951493 .int, .float => {
14961494 if (ty_classes[1] == .none) {
1497 return func.lowerToStack(value);
1495 return cg.lowerToStack(value);
14981496 }
14991497 assert(ty_classes[0] == .direct and ty_classes[1] == .direct);
15001498 assert(ty.abiSize(zcu) == 16);
15011499 // in this case we have an integer or float that must be lowered as 2 i64's.
1502 try func.emitWValue(value);
1503 try func.addMemArg(.i64_load, .{ .offset = value.offset(), .alignment = 8 });
1504 try func.emitWValue(value);
1505 try func.addMemArg(.i64_load, .{ .offset = value.offset() + 8, .alignment = 8 });
1500 try cg.emitWValue(value);
1501 try cg.addMemArg(.i64_load, .{ .offset = value.offset(), .alignment = 8 });
1502 try cg.emitWValue(value);
1503 try cg.addMemArg(.i64_load, .{ .offset = value.offset() + 8, .alignment = 8 });
15061504 },
1507 else => return func.lowerToStack(value),
1505 else => return cg.lowerToStack(value),
15081506 }
15091507}
15101508
15111509/// Lowers a `WValue` to the stack. This means when the `value` results in
15121510/// `.stack_offset` we calculate the pointer of this offset and use that.
15131511/// 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 {
15151513 switch (value) {
15161514 .stack_offset => |offset| {
1517 try func.emitWValue(value);
1515 try cg.emitWValue(value);
15181516 if (offset.value > 0) {
1519 switch (func.ptr_size) {
1517 switch (cg.ptr_size) {
15201518 .wasm32 => {
1521 try func.addImm32(offset.value);
1522 try func.addTag(.i32_add);
1519 try cg.addImm32(offset.value);
1520 try cg.addTag(.i32_add);
15231521 },
15241522 .wasm64 => {
1525 try func.addImm64(offset.value);
1526 try func.addTag(.i64_add);
1523 try cg.addImm64(offset.value);
1524 try cg.addTag(.i64_add);
15271525 },
15281526 }
15291527 }
15301528 },
1531 else => try func.emitWValue(value),
1529 else => try cg.emitWValue(value),
15321530 }
15331531}
15341532
15351533/// Creates a local for the initial stack value
15361534/// Asserts `initial_stack_value` is `.none`
1537fn initializeStack(func: *CodeGen) !void {
1538 assert(func.initial_stack_value == .none);
1535fn initializeStack(cg: *CodeGen) !void {
1536 assert(cg.initial_stack_value == .none);
15391537 // Reserve a local to store the current stack pointer
15401538 // We can later use this local to set the stack pointer back to the value
15411539 // we have stored here.
1542 func.initial_stack_value = try func.ensureAllocLocal(Type.usize);
1540 cg.initial_stack_value = try cg.ensureAllocLocal(Type.usize);
15431541 // 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);
15451543}
15461544
15471545/// Reads the stack pointer from `Context.initial_stack_value` and writes it
15481546/// to the global stack pointer variable
1549fn restoreStackPointer(func: *CodeGen) !void {
1547fn restoreStackPointer(cg: *CodeGen) !void {
15501548 // only restore the pointer if it was initialized
1551 if (func.initial_stack_value == .none) return;
1549 if (cg.initial_stack_value == .none) return;
15521550 // 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);
15561554}
15571555
15581556/// 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 {
15611559/// moveStack unless a local was already created to store the pointer.
15621560///
15631561/// Asserts Type has codegenbits
1564fn allocStack(func: *CodeGen, ty: Type) !WValue {
1565 const zcu = func.pt.zcu;
1562fn allocStack(cg: *CodeGen, ty: Type) !WValue {
1563 const zcu = cg.pt.zcu;
15661564 assert(ty.hasRuntimeBitsIgnoreComptime(zcu));
1567 if (func.initial_stack_value == .none) {
1568 try func.initializeStack();
1565 if (cg.initial_stack_value == .none) {
1566 try cg.initializeStack();
15691567 }
15701568
15711569 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", .{
1573 ty.fmt(func.pt), ty.abiSize(zcu),
1570 return cg.fail("Type {} with ABI size of {d} exceeds stack frame size", .{
1571 ty.fmt(cg.pt), ty.abiSize(zcu),
15741572 });
15751573 };
15761574 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));
1581 defer func.stack_size = offset + abi_size;
1578 const offset: u32 = @intCast(abi_align.forward(cg.stack_size));
1579 defer cg.stack_size = offset + abi_size;
15821580
15831581 return .{ .stack_offset = .{ .value = offset, .references = 1 } };
15841582}
......@@ -1587,30 +1585,30 @@ fn allocStack(func: *CodeGen, ty: Type) !WValue {
15871585/// the value of its type will live.
15881586/// This is different from allocStack where this will use the pointer's alignment
15891587/// if it is set, to ensure the stack alignment will be set correctly.
1590fn allocStackPtr(func: *CodeGen, inst: Air.Inst.Index) !WValue {
1591 const pt = func.pt;
1588fn allocStackPtr(cg: *CodeGen, inst: Air.Inst.Index) !WValue {
1589 const pt = cg.pt;
15921590 const zcu = pt.zcu;
1593 const ptr_ty = func.typeOfIndex(inst);
1591 const ptr_ty = cg.typeOfIndex(inst);
15941592 const pointee_ty = ptr_ty.childType(zcu);
15951593
1596 if (func.initial_stack_value == .none) {
1597 try func.initializeStack();
1594 if (cg.initial_stack_value == .none) {
1595 try cg.initializeStack();
15981596 }
15991597
16001598 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.
16021600 }
16031601
16041602 const abi_alignment = ptr_ty.ptrAlignment(zcu);
16051603 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", .{
16071605 pointee_ty.fmt(pt), pointee_ty.abiSize(zcu),
16081606 });
16091607 };
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));
1613 defer func.stack_size = offset + abi_size;
1610 const offset: u32 = @intCast(abi_alignment.forward(cg.stack_size));
1611 defer cg.stack_size = offset + abi_size;
16141612
16151613 return .{ .stack_offset = .{ .value = offset, .references = 1 } };
16161614}
......@@ -1624,14 +1622,14 @@ fn toWasmBits(bits: u16) ?u16 {
16241622
16251623/// Performs a copy of bytes for a given type. Copying all bytes
16261624/// 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 {
16281626 // When bulk_memory is enabled, we lower it to wasm's memcpy instruction.
16291627 // If not, we lower it ourselves manually
1630 if (std.Target.wasm.featureSetHas(func.target.cpu.features, .bulk_memory)) {
1631 try func.lowerToStack(dst);
1632 try func.lowerToStack(src);
1633 try func.emitWValue(len);
1634 try func.addExtended(.memory_copy);
1628 if (std.Target.wasm.featureSetHas(cg.target.cpu.features, .bulk_memory)) {
1629 try cg.lowerToStack(dst);
1630 try cg.lowerToStack(src);
1631 try cg.emitWValue(len);
1632 try cg.addExtended(.memory_copy);
16351633 return;
16361634 }
16371635
......@@ -1652,17 +1650,17 @@ fn memcpy(func: *CodeGen, dst: WValue, src: WValue, len: WValue) !void {
16521650 const rhs_base = src.offset();
16531651 while (offset < length) : (offset += 1) {
16541652 // get dst's address to store the result
1655 try func.emitWValue(dst);
1653 try cg.emitWValue(dst);
16561654 // load byte from src's address
1657 try func.emitWValue(src);
1658 switch (func.ptr_size) {
1655 try cg.emitWValue(src);
1656 switch (cg.ptr_size) {
16591657 .wasm32 => {
1660 try func.addMemArg(.i32_load8_u, .{ .offset = rhs_base + offset, .alignment = 1 });
1661 try func.addMemArg(.i32_store8, .{ .offset = lhs_base + offset, .alignment = 1 });
1658 try cg.addMemArg(.i32_load8_u, .{ .offset = rhs_base + offset, .alignment = 1 });
1659 try cg.addMemArg(.i32_store8, .{ .offset = lhs_base + offset, .alignment = 1 });
16621660 },
16631661 .wasm64 => {
1664 try func.addMemArg(.i64_load8_u, .{ .offset = rhs_base + offset, .alignment = 1 });
1665 try func.addMemArg(.i64_store8, .{ .offset = lhs_base + offset, .alignment = 1 });
1662 try cg.addMemArg(.i64_load8_u, .{ .offset = rhs_base + offset, .alignment = 1 });
1663 try cg.addMemArg(.i64_store8, .{ .offset = lhs_base + offset, .alignment = 1 });
16661664 },
16671665 }
16681666 }
......@@ -1673,79 +1671,79 @@ fn memcpy(func: *CodeGen, dst: WValue, src: WValue, len: WValue) !void {
16731671
16741672 // allocate a local for the offset, and set it to 0.
16751673 // This to ensure that inside loops we correctly re-set the counter.
1676 var offset = try func.allocLocal(Type.usize); // local for counter
1677 defer offset.free(func);
1678 switch (func.ptr_size) {
1679 .wasm32 => try func.addImm32(0),
1680 .wasm64 => try func.addImm64(0),
1674 var offset = try cg.allocLocal(Type.usize); // local for counter
1675 defer offset.free(cg);
1676 switch (cg.ptr_size) {
1677 .wasm32 => try cg.addImm32(0),
1678 .wasm64 => try cg.addImm64(0),
16811679 }
1682 try func.addLabel(.local_set, offset.local.value);
1680 try cg.addLabel(.local_set, offset.local.value);
16831681
16841682 // outer block to jump to when loop is done
1685 try func.startBlock(.block, std.wasm.block_empty);
1686 try func.startBlock(.loop, std.wasm.block_empty);
1683 try cg.startBlock(.block, std.wasm.block_empty);
1684 try cg.startBlock(.loop, std.wasm.block_empty);
16871685
16881686 // loop condition (offset == length -> break)
16891687 {
1690 try func.emitWValue(offset);
1691 try func.emitWValue(len);
1692 switch (func.ptr_size) {
1693 .wasm32 => try func.addTag(.i32_eq),
1694 .wasm64 => try func.addTag(.i64_eq),
1688 try cg.emitWValue(offset);
1689 try cg.emitWValue(len);
1690 switch (cg.ptr_size) {
1691 .wasm32 => try cg.addTag(.i32_eq),
1692 .wasm64 => try cg.addTag(.i64_eq),
16951693 }
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)
16971695 }
16981696
16991697 // get dst ptr
17001698 {
1701 try func.emitWValue(dst);
1702 try func.emitWValue(offset);
1703 switch (func.ptr_size) {
1704 .wasm32 => try func.addTag(.i32_add),
1705 .wasm64 => try func.addTag(.i64_add),
1699 try cg.emitWValue(dst);
1700 try cg.emitWValue(offset);
1701 switch (cg.ptr_size) {
1702 .wasm32 => try cg.addTag(.i32_add),
1703 .wasm64 => try cg.addTag(.i64_add),
17061704 }
17071705 }
17081706
17091707 // get src value and also store in dst
17101708 {
1711 try func.emitWValue(src);
1712 try func.emitWValue(offset);
1713 switch (func.ptr_size) {
1709 try cg.emitWValue(src);
1710 try cg.emitWValue(offset);
1711 switch (cg.ptr_size) {
17141712 .wasm32 => {
1715 try func.addTag(.i32_add);
1716 try func.addMemArg(.i32_load8_u, .{ .offset = src.offset(), .alignment = 1 });
1717 try func.addMemArg(.i32_store8, .{ .offset = dst.offset(), .alignment = 1 });
1713 try cg.addTag(.i32_add);
1714 try cg.addMemArg(.i32_load8_u, .{ .offset = src.offset(), .alignment = 1 });
1715 try cg.addMemArg(.i32_store8, .{ .offset = dst.offset(), .alignment = 1 });
17181716 },
17191717 .wasm64 => {
1720 try func.addTag(.i64_add);
1721 try func.addMemArg(.i64_load8_u, .{ .offset = src.offset(), .alignment = 1 });
1722 try func.addMemArg(.i64_store8, .{ .offset = dst.offset(), .alignment = 1 });
1718 try cg.addTag(.i64_add);
1719 try cg.addMemArg(.i64_load8_u, .{ .offset = src.offset(), .alignment = 1 });
1720 try cg.addMemArg(.i64_store8, .{ .offset = dst.offset(), .alignment = 1 });
17231721 },
17241722 }
17251723 }
17261724
17271725 // increment loop counter
17281726 {
1729 try func.emitWValue(offset);
1730 switch (func.ptr_size) {
1727 try cg.emitWValue(offset);
1728 switch (cg.ptr_size) {
17311729 .wasm32 => {
1732 try func.addImm32(1);
1733 try func.addTag(.i32_add);
1730 try cg.addImm32(1);
1731 try cg.addTag(.i32_add);
17341732 },
17351733 .wasm64 => {
1736 try func.addImm64(1);
1737 try func.addTag(.i64_add);
1734 try cg.addImm64(1);
1735 try cg.addTag(.i64_add);
17381736 },
17391737 }
1740 try func.addLabel(.local_set, offset.local.value);
1741 try func.addLabel(.br, 0); // jump to start of loop
1738 try cg.addLabel(.local_set, offset.local.value);
1739 try cg.addLabel(.br, 0); // jump to start of loop
17421740 }
1743 try func.endBlock(); // close off loop block
1744 try func.endBlock(); // close off outer block
1741 try cg.endBlock(); // close off loop block
1742 try cg.endBlock(); // close off outer block
17451743}
17461744
1747fn ptrSize(func: *const CodeGen) u16 {
1748 return @divExact(func.target.ptrBitWidth(), 8);
1745fn ptrSize(cg: *const CodeGen) u16 {
1746 return @divExact(cg.target.ptrBitWidth(), 8);
17491747}
17501748
17511749/// 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
18371835/// This can be used to get a pointer to a struct field, error payload, etc.
18381836/// By providing `modify` as action, it will modify the given `ptr_value` instead of making a new
18391837/// 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 {
18411839 // do not perform arithmetic when offset is 0.
18421840 if (offset == 0 and ptr_value.offset() == 0 and action == .modify) return ptr_value;
18431841 const result_ptr: WValue = switch (action) {
1844 .new => try func.ensureAllocLocal(Type.usize),
1842 .new => try cg.ensureAllocLocal(Type.usize),
18451843 .modify => ptr_value,
18461844 };
1847 try func.emitWValue(ptr_value);
1845 try cg.emitWValue(ptr_value);
18481846 if (offset + ptr_value.offset() > 0) {
1849 switch (func.ptr_size) {
1847 switch (cg.ptr_size) {
18501848 .wasm32 => {
1851 try func.addImm32(@intCast(offset + ptr_value.offset()));
1852 try func.addTag(.i32_add);
1849 try cg.addImm32(@intCast(offset + ptr_value.offset()));
1850 try cg.addTag(.i32_add);
18531851 },
18541852 .wasm64 => {
1855 try func.addImm64(offset + ptr_value.offset());
1856 try func.addTag(.i64_add);
1853 try cg.addImm64(offset + ptr_value.offset());
1854 try cg.addTag(.i64_add);
18571855 },
18581856 }
18591857 }
1860 try func.addLabel(.local_set, result_ptr.local.value);
1858 try cg.addLabel(.local_set, result_ptr.local.value);
18611859 return result_ptr;
18621860}
18631861
1864fn genInst(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
1865 const air_tags = func.air.instructions.items(.tag);
1862fn genInst(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
1863 const air_tags = cg.air.instructions.items(.tag);
18661864 return switch (air_tags[@intFromEnum(inst)]) {
18671865 .inferred_alloc, .inferred_alloc_comptime => unreachable,
18681866
1869 .add => func.airBinOp(inst, .add),
1870 .add_sat => func.airSatBinOp(inst, .add),
1871 .add_wrap => func.airWrapBinOp(inst, .add),
1872 .sub => func.airBinOp(inst, .sub),
1873 .sub_sat => func.airSatBinOp(inst, .sub),
1874 .sub_wrap => func.airWrapBinOp(inst, .sub),
1875 .mul => func.airBinOp(inst, .mul),
1876 .mul_sat => func.airSatMul(inst),
1877 .mul_wrap => func.airWrapBinOp(inst, .mul),
1878 .div_float, .div_exact => func.airDiv(inst),
1879 .div_trunc => func.airDivTrunc(inst),
1880 .div_floor => func.airDivFloor(inst),
1881 .bit_and => func.airBinOp(inst, .@"and"),
1882 .bit_or => func.airBinOp(inst, .@"or"),
1883 .bool_and => func.airBinOp(inst, .@"and"),
1884 .bool_or => func.airBinOp(inst, .@"or"),
1885 .rem => func.airRem(inst),
1886 .mod => func.airMod(inst),
1887 .shl => func.airWrapBinOp(inst, .shl),
1888 .shl_exact => func.airBinOp(inst, .shl),
1889 .shl_sat => func.airShlSat(inst),
1890 .shr, .shr_exact => func.airBinOp(inst, .shr),
1891 .xor => func.airBinOp(inst, .xor),
1892 .max => func.airMaxMin(inst, .max),
1893 .min => func.airMaxMin(inst, .min),
1894 .mul_add => func.airMulAdd(inst),
1895
1896 .sqrt => func.airUnaryFloatOp(inst, .sqrt),
1897 .sin => func.airUnaryFloatOp(inst, .sin),
1898 .cos => func.airUnaryFloatOp(inst, .cos),
1899 .tan => func.airUnaryFloatOp(inst, .tan),
1900 .exp => func.airUnaryFloatOp(inst, .exp),
1901 .exp2 => func.airUnaryFloatOp(inst, .exp2),
1902 .log => func.airUnaryFloatOp(inst, .log),
1903 .log2 => func.airUnaryFloatOp(inst, .log2),
1904 .log10 => func.airUnaryFloatOp(inst, .log10),
1905 .floor => func.airUnaryFloatOp(inst, .floor),
1906 .ceil => func.airUnaryFloatOp(inst, .ceil),
1907 .round => func.airUnaryFloatOp(inst, .round),
1908 .trunc_float => func.airUnaryFloatOp(inst, .trunc),
1909 .neg => func.airUnaryFloatOp(inst, .neg),
1910
1911 .abs => func.airAbs(inst),
1912
1913 .add_with_overflow => func.airAddSubWithOverflow(inst, .add),
1914 .sub_with_overflow => func.airAddSubWithOverflow(inst, .sub),
1915 .shl_with_overflow => func.airShlWithOverflow(inst),
1916 .mul_with_overflow => func.airMulWithOverflow(inst),
1917
1918 .clz => func.airClz(inst),
1919 .ctz => func.airCtz(inst),
1920
1921 .cmp_eq => func.airCmp(inst, .eq),
1922 .cmp_gte => func.airCmp(inst, .gte),
1923 .cmp_gt => func.airCmp(inst, .gt),
1924 .cmp_lte => func.airCmp(inst, .lte),
1925 .cmp_lt => func.airCmp(inst, .lt),
1926 .cmp_neq => func.airCmp(inst, .neq),
1927
1928 .cmp_vector => func.airCmpVector(inst),
1929 .cmp_lt_errors_len => func.airCmpLtErrorsLen(inst),
1930
1931 .array_elem_val => func.airArrayElemVal(inst),
1932 .array_to_slice => func.airArrayToSlice(inst),
1933 .alloc => func.airAlloc(inst),
1934 .arg => func.airArg(inst),
1935 .bitcast => func.airBitcast(inst),
1936 .block => func.airBlock(inst),
1937 .trap => func.airTrap(inst),
1938 .breakpoint => func.airBreakpoint(inst),
1939 .br => func.airBr(inst),
1940 .repeat => func.airRepeat(inst),
1941 .switch_dispatch => return func.fail("TODO implement `switch_dispatch`", .{}),
1942 .int_from_bool => func.airIntFromBool(inst),
1943 .cond_br => func.airCondBr(inst),
1944 .intcast => func.airIntcast(inst),
1945 .fptrunc => func.airFptrunc(inst),
1946 .fpext => func.airFpext(inst),
1947 .int_from_float => func.airIntFromFloat(inst),
1948 .float_from_int => func.airFloatFromInt(inst),
1949 .get_union_tag => func.airGetUnionTag(inst),
1950
1951 .@"try" => func.airTry(inst),
1952 .try_cold => func.airTry(inst),
1953 .try_ptr => func.airTryPtr(inst),
1954 .try_ptr_cold => func.airTryPtr(inst),
1955
1956 .dbg_stmt => func.airDbgStmt(inst),
1957 .dbg_empty_stmt => try func.finishAir(inst, .none, &.{}),
1958 .dbg_inline_block => func.airDbgInlineBlock(inst),
1959 .dbg_var_ptr => func.airDbgVar(inst, .local_var, true),
1960 .dbg_var_val => func.airDbgVar(inst, .local_var, false),
1961 .dbg_arg_inline => func.airDbgVar(inst, .local_arg, false),
1962
1963 .call => func.airCall(inst, .auto),
1964 .call_always_tail => func.airCall(inst, .always_tail),
1965 .call_never_tail => func.airCall(inst, .never_tail),
1966 .call_never_inline => func.airCall(inst, .never_inline),
1967
1968 .is_err => func.airIsErr(inst, .i32_ne),
1969 .is_non_err => func.airIsErr(inst, .i32_eq),
1970
1971 .is_null => func.airIsNull(inst, .i32_eq, .value),
1972 .is_non_null => func.airIsNull(inst, .i32_ne, .value),
1973 .is_null_ptr => func.airIsNull(inst, .i32_eq, .ptr),
1974 .is_non_null_ptr => func.airIsNull(inst, .i32_ne, .ptr),
1975
1976 .load => func.airLoad(inst),
1977 .loop => func.airLoop(inst),
1978 .memset => func.airMemset(inst, false),
1979 .memset_safe => func.airMemset(inst, true),
1980 .not => func.airNot(inst),
1981 .optional_payload => func.airOptionalPayload(inst),
1982 .optional_payload_ptr => func.airOptionalPayloadPtr(inst),
1983 .optional_payload_ptr_set => func.airOptionalPayloadPtrSet(inst),
1984 .ptr_add => func.airPtrBinOp(inst, .add),
1985 .ptr_sub => func.airPtrBinOp(inst, .sub),
1986 .ptr_elem_ptr => func.airPtrElemPtr(inst),
1987 .ptr_elem_val => func.airPtrElemVal(inst),
1988 .int_from_ptr => func.airIntFromPtr(inst),
1989 .ret => func.airRet(inst),
1990 .ret_safe => func.airRet(inst), // TODO
1991 .ret_ptr => func.airRetPtr(inst),
1992 .ret_load => func.airRetLoad(inst),
1993 .splat => func.airSplat(inst),
1994 .select => func.airSelect(inst),
1995 .shuffle => func.airShuffle(inst),
1996 .reduce => func.airReduce(inst),
1997 .aggregate_init => func.airAggregateInit(inst),
1998 .union_init => func.airUnionInit(inst),
1999 .prefetch => func.airPrefetch(inst),
2000 .popcount => func.airPopcount(inst),
2001 .byte_swap => func.airByteSwap(inst),
2002 .bit_reverse => func.airBitReverse(inst),
2003
2004 .slice => func.airSlice(inst),
2005 .slice_len => func.airSliceLen(inst),
2006 .slice_elem_val => func.airSliceElemVal(inst),
2007 .slice_elem_ptr => func.airSliceElemPtr(inst),
2008 .slice_ptr => func.airSlicePtr(inst),
2009 .ptr_slice_len_ptr => func.airPtrSliceFieldPtr(inst, func.ptrSize()),
2010 .ptr_slice_ptr_ptr => func.airPtrSliceFieldPtr(inst, 0),
2011 .store => func.airStore(inst, false),
2012 .store_safe => func.airStore(inst, true),
2013
2014 .set_union_tag => func.airSetUnionTag(inst),
2015 .struct_field_ptr => func.airStructFieldPtr(inst),
2016 .struct_field_ptr_index_0 => func.airStructFieldPtrIndex(inst, 0),
2017 .struct_field_ptr_index_1 => func.airStructFieldPtrIndex(inst, 1),
2018 .struct_field_ptr_index_2 => func.airStructFieldPtrIndex(inst, 2),
2019 .struct_field_ptr_index_3 => func.airStructFieldPtrIndex(inst, 3),
2020 .struct_field_val => func.airStructFieldVal(inst),
2021 .field_parent_ptr => func.airFieldParentPtr(inst),
2022
2023 .switch_br => func.airSwitchBr(inst),
2024 .loop_switch_br => return func.fail("TODO implement `loop_switch_br`", .{}),
2025 .trunc => func.airTrunc(inst),
2026 .unreach => func.airUnreachable(inst),
2027
2028 .wrap_optional => func.airWrapOptional(inst),
2029 .unwrap_errunion_payload => func.airUnwrapErrUnionPayload(inst, false),
2030 .unwrap_errunion_payload_ptr => func.airUnwrapErrUnionPayload(inst, true),
2031 .unwrap_errunion_err => func.airUnwrapErrUnionError(inst, false),
2032 .unwrap_errunion_err_ptr => func.airUnwrapErrUnionError(inst, true),
2033 .wrap_errunion_payload => func.airWrapErrUnionPayload(inst),
2034 .wrap_errunion_err => func.airWrapErrUnionErr(inst),
2035 .errunion_payload_ptr_set => func.airErrUnionPayloadPtrSet(inst),
2036 .error_name => func.airErrorName(inst),
2037
2038 .wasm_memory_size => func.airWasmMemorySize(inst),
2039 .wasm_memory_grow => func.airWasmMemoryGrow(inst),
2040
2041 .memcpy => func.airMemcpy(inst),
2042
2043 .ret_addr => func.airRetAddr(inst),
2044 .tag_name => func.airTagName(inst),
2045
2046 .error_set_has_value => func.airErrorSetHasValue(inst),
2047 .frame_addr => func.airFrameAddress(inst),
1867 .add => cg.airBinOp(inst, .add),
1868 .add_sat => cg.airSatBinOp(inst, .add),
1869 .add_wrap => cg.airWrapBinOp(inst, .add),
1870 .sub => cg.airBinOp(inst, .sub),
1871 .sub_sat => cg.airSatBinOp(inst, .sub),
1872 .sub_wrap => cg.airWrapBinOp(inst, .sub),
1873 .mul => cg.airBinOp(inst, .mul),
1874 .mul_sat => cg.airSatMul(inst),
1875 .mul_wrap => cg.airWrapBinOp(inst, .mul),
1876 .div_float, .div_exact => cg.airDiv(inst),
1877 .div_trunc => cg.airDivTrunc(inst),
1878 .div_floor => cg.airDivFloor(inst),
1879 .bit_and => cg.airBinOp(inst, .@"and"),
1880 .bit_or => cg.airBinOp(inst, .@"or"),
1881 .bool_and => cg.airBinOp(inst, .@"and"),
1882 .bool_or => cg.airBinOp(inst, .@"or"),
1883 .rem => cg.airRem(inst),
1884 .mod => cg.airMod(inst),
1885 .shl => cg.airWrapBinOp(inst, .shl),
1886 .shl_exact => cg.airBinOp(inst, .shl),
1887 .shl_sat => cg.airShlSat(inst),
1888 .shr, .shr_exact => cg.airBinOp(inst, .shr),
1889 .xor => cg.airBinOp(inst, .xor),
1890 .max => cg.airMaxMin(inst, .max),
1891 .min => cg.airMaxMin(inst, .min),
1892 .mul_add => cg.airMulAdd(inst),
1893
1894 .sqrt => cg.airUnaryFloatOp(inst, .sqrt),
1895 .sin => cg.airUnaryFloatOp(inst, .sin),
1896 .cos => cg.airUnaryFloatOp(inst, .cos),
1897 .tan => cg.airUnaryFloatOp(inst, .tan),
1898 .exp => cg.airUnaryFloatOp(inst, .exp),
1899 .exp2 => cg.airUnaryFloatOp(inst, .exp2),
1900 .log => cg.airUnaryFloatOp(inst, .log),
1901 .log2 => cg.airUnaryFloatOp(inst, .log2),
1902 .log10 => cg.airUnaryFloatOp(inst, .log10),
1903 .floor => cg.airUnaryFloatOp(inst, .floor),
1904 .ceil => cg.airUnaryFloatOp(inst, .ceil),
1905 .round => cg.airUnaryFloatOp(inst, .round),
1906 .trunc_float => cg.airUnaryFloatOp(inst, .trunc),
1907 .neg => cg.airUnaryFloatOp(inst, .neg),
1908
1909 .abs => cg.airAbs(inst),
1910
1911 .add_with_overflow => cg.airAddSubWithOverflow(inst, .add),
1912 .sub_with_overflow => cg.airAddSubWithOverflow(inst, .sub),
1913 .shl_with_overflow => cg.airShlWithOverflow(inst),
1914 .mul_with_overflow => cg.airMulWithOverflow(inst),
1915
1916 .clz => cg.airClz(inst),
1917 .ctz => cg.airCtz(inst),
1918
1919 .cmp_eq => cg.airCmp(inst, .eq),
1920 .cmp_gte => cg.airCmp(inst, .gte),
1921 .cmp_gt => cg.airCmp(inst, .gt),
1922 .cmp_lte => cg.airCmp(inst, .lte),
1923 .cmp_lt => cg.airCmp(inst, .lt),
1924 .cmp_neq => cg.airCmp(inst, .neq),
1925
1926 .cmp_vector => cg.airCmpVector(inst),
1927 .cmp_lt_errors_len => cg.airCmpLtErrorsLen(inst),
1928
1929 .array_elem_val => cg.airArrayElemVal(inst),
1930 .array_to_slice => cg.airArrayToSlice(inst),
1931 .alloc => cg.airAlloc(inst),
1932 .arg => cg.airArg(inst),
1933 .bitcast => cg.airBitcast(inst),
1934 .block => cg.airBlock(inst),
1935 .trap => cg.airTrap(inst),
1936 .breakpoint => cg.airBreakpoint(inst),
1937 .br => cg.airBr(inst),
1938 .repeat => cg.airRepeat(inst),
1939 .switch_dispatch => return cg.fail("TODO implement `switch_dispatch`", .{}),
1940 .int_from_bool => cg.airIntFromBool(inst),
1941 .cond_br => cg.airCondBr(inst),
1942 .intcast => cg.airIntcast(inst),
1943 .fptrunc => cg.airFptrunc(inst),
1944 .fpext => cg.airFpext(inst),
1945 .int_from_float => cg.airIntFromFloat(inst),
1946 .float_from_int => cg.airFloatFromInt(inst),
1947 .get_union_tag => cg.airGetUnionTag(inst),
1948
1949 .@"try" => cg.airTry(inst),
1950 .try_cold => cg.airTry(inst),
1951 .try_ptr => cg.airTryPtr(inst),
1952 .try_ptr_cold => cg.airTryPtr(inst),
1953
1954 .dbg_stmt => cg.airDbgStmt(inst),
1955 .dbg_empty_stmt => try cg.finishAir(inst, .none, &.{}),
1956 .dbg_inline_block => cg.airDbgInlineBlock(inst),
1957 .dbg_var_ptr => cg.airDbgVar(inst, .local_var, true),
1958 .dbg_var_val => cg.airDbgVar(inst, .local_var, false),
1959 .dbg_arg_inline => cg.airDbgVar(inst, .local_arg, false),
1960
1961 .call => cg.airCall(inst, .auto),
1962 .call_always_tail => cg.airCall(inst, .always_tail),
1963 .call_never_tail => cg.airCall(inst, .never_tail),
1964 .call_never_inline => cg.airCall(inst, .never_inline),
1965
1966 .is_err => cg.airIsErr(inst, .i32_ne),
1967 .is_non_err => cg.airIsErr(inst, .i32_eq),
1968
1969 .is_null => cg.airIsNull(inst, .i32_eq, .value),
1970 .is_non_null => cg.airIsNull(inst, .i32_ne, .value),
1971 .is_null_ptr => cg.airIsNull(inst, .i32_eq, .ptr),
1972 .is_non_null_ptr => cg.airIsNull(inst, .i32_ne, .ptr),
1973
1974 .load => cg.airLoad(inst),
1975 .loop => cg.airLoop(inst),
1976 .memset => cg.airMemset(inst, false),
1977 .memset_safe => cg.airMemset(inst, true),
1978 .not => cg.airNot(inst),
1979 .optional_payload => cg.airOptionalPayload(inst),
1980 .optional_payload_ptr => cg.airOptionalPayloadPtr(inst),
1981 .optional_payload_ptr_set => cg.airOptionalPayloadPtrSet(inst),
1982 .ptr_add => cg.airPtrBinOp(inst, .add),
1983 .ptr_sub => cg.airPtrBinOp(inst, .sub),
1984 .ptr_elem_ptr => cg.airPtrElemPtr(inst),
1985 .ptr_elem_val => cg.airPtrElemVal(inst),
1986 .int_from_ptr => cg.airIntFromPtr(inst),
1987 .ret => cg.airRet(inst),
1988 .ret_safe => cg.airRet(inst), // TODO
1989 .ret_ptr => cg.airRetPtr(inst),
1990 .ret_load => cg.airRetLoad(inst),
1991 .splat => cg.airSplat(inst),
1992 .select => cg.airSelect(inst),
1993 .shuffle => cg.airShuffle(inst),
1994 .reduce => cg.airReduce(inst),
1995 .aggregate_init => cg.airAggregateInit(inst),
1996 .union_init => cg.airUnionInit(inst),
1997 .prefetch => cg.airPrefetch(inst),
1998 .popcount => cg.airPopcount(inst),
1999 .byte_swap => cg.airByteSwap(inst),
2000 .bit_reverse => cg.airBitReverse(inst),
2001
2002 .slice => cg.airSlice(inst),
2003 .slice_len => cg.airSliceLen(inst),
2004 .slice_elem_val => cg.airSliceElemVal(inst),
2005 .slice_elem_ptr => cg.airSliceElemPtr(inst),
2006 .slice_ptr => cg.airSlicePtr(inst),
2007 .ptr_slice_len_ptr => cg.airPtrSliceFieldPtr(inst, cg.ptrSize()),
2008 .ptr_slice_ptr_ptr => cg.airPtrSliceFieldPtr(inst, 0),
2009 .store => cg.airStore(inst, false),
2010 .store_safe => cg.airStore(inst, true),
2011
2012 .set_union_tag => cg.airSetUnionTag(inst),
2013 .struct_field_ptr => cg.airStructFieldPtr(inst),
2014 .struct_field_ptr_index_0 => cg.airStructFieldPtrIndex(inst, 0),
2015 .struct_field_ptr_index_1 => cg.airStructFieldPtrIndex(inst, 1),
2016 .struct_field_ptr_index_2 => cg.airStructFieldPtrIndex(inst, 2),
2017 .struct_field_ptr_index_3 => cg.airStructFieldPtrIndex(inst, 3),
2018 .struct_field_val => cg.airStructFieldVal(inst),
2019 .field_parent_ptr => cg.airFieldParentPtr(inst),
2020
2021 .switch_br => cg.airSwitchBr(inst),
2022 .loop_switch_br => return cg.fail("TODO implement `loop_switch_br`", .{}),
2023 .trunc => cg.airTrunc(inst),
2024 .unreach => cg.airUnreachable(inst),
2025
2026 .wrap_optional => cg.airWrapOptional(inst),
2027 .unwrap_errunion_payload => cg.airUnwrapErrUnionPayload(inst, false),
2028 .unwrap_errunion_payload_ptr => cg.airUnwrapErrUnionPayload(inst, true),
2029 .unwrap_errunion_err => cg.airUnwrapErrUnionError(inst, false),
2030 .unwrap_errunion_err_ptr => cg.airUnwrapErrUnionError(inst, true),
2031 .wrap_errunion_payload => cg.airWrapErrUnionPayload(inst),
2032 .wrap_errunion_err => cg.airWrapErrUnionErr(inst),
2033 .errunion_payload_ptr_set => cg.airErrUnionPayloadPtrSet(inst),
2034 .error_name => cg.airErrorName(inst),
2035
2036 .wasm_memory_size => cg.airWasmMemorySize(inst),
2037 .wasm_memory_grow => cg.airWasmMemoryGrow(inst),
2038
2039 .memcpy => cg.airMemcpy(inst),
2040
2041 .ret_addr => cg.airRetAddr(inst),
2042 .tag_name => cg.airTagName(inst),
2043
2044 .error_set_has_value => cg.airErrorSetHasValue(inst),
2045 .frame_addr => cg.airFrameAddress(inst),
20482046
20492047 .assembly,
20502048 .is_err_ptr,
......@@ -2060,18 +2058,18 @@ fn genInst(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
20602058 .c_va_copy,
20612059 .c_va_end,
20622060 .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),
20662064 .atomic_store_unordered,
20672065 .atomic_store_monotonic,
20682066 .atomic_store_release,
20692067 .atomic_store_seq_cst,
20702068 // in WebAssembly, all atomic instructions are sequentially ordered.
2071 => func.airAtomicStore(inst),
2072 .atomic_rmw => func.airAtomicRmw(inst),
2073 .cmpxchg_weak => func.airCmpxchg(inst),
2074 .cmpxchg_strong => func.airCmpxchg(inst),
2069 => cg.airAtomicStore(inst),
2070 .atomic_rmw => cg.airAtomicRmw(inst),
2071 .cmpxchg_weak => cg.airCmpxchg(inst),
2072 .cmpxchg_strong => cg.airCmpxchg(inst),
20752073
20762074 .add_optimized,
20772075 .sub_optimized,
......@@ -2092,12 +2090,12 @@ fn genInst(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
20922090 .cmp_vector_optimized,
20932091 .reduce_optimized,
20942092 .int_from_float_optimized,
2095 => return func.fail("TODO implement optimized float mode", .{}),
2093 => return cg.fail("TODO implement optimized float mode", .{}),
20962094
20972095 .add_safe,
20982096 .sub_safe,
20992097 .mul_safe,
2100 => return func.fail("TODO implement safety_checked_instructions", .{}),
2098 => return cg.fail("TODO implement safety_checked_instructions", .{}),
21012099
21022100 .work_item_id,
21032101 .work_group_size,
......@@ -2106,124 +2104,124 @@ fn genInst(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
21062104 };
21072105}
21082106
2109fn genBody(func: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
2110 const pt = func.pt;
2107fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
2108 const pt = cg.pt;
21112109 const zcu = pt.zcu;
21122110 const ip = &zcu.intern_pool;
21132111
21142112 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)) {
21162114 continue;
21172115 }
2118 const old_bookkeeping_value = func.air_bookkeeping;
2119 try func.currentBranch().values.ensureUnusedCapacity(func.gpa, Liveness.bpi);
2120 try func.genInst(inst);
2116 const old_bookkeeping_value = cg.air_bookkeeping;
2117 try cg.currentBranch().values.ensureUnusedCapacity(cg.gpa, Liveness.bpi);
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) {
21232121 std.debug.panic("Missing call to `finishAir` in AIR instruction %{d} ('{}')", .{
21242122 inst,
2125 func.air.instructions.items(.tag)[@intFromEnum(inst)],
2123 cg.air.instructions.items(.tag)[@intFromEnum(inst)],
21262124 });
21272125 }
21282126 }
21292127}
21302128
2131fn airRet(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
2132 const pt = func.pt;
2129fn airRet(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
2130 const pt = cg.pt;
21332131 const zcu = pt.zcu;
2134 const un_op = func.air.instructions.items(.data)[@intFromEnum(inst)].un_op;
2135 const operand = try func.resolveInst(un_op);
2136 const fn_info = zcu.typeToFunc(zcu.navValue(func.owner_nav).typeOf(zcu)).?;
2132 const un_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].un_op;
2133 const operand = try cg.resolveInst(un_op);
2134 const fn_info = zcu.typeToFunc(zcu.navValue(cg.owner_nav).typeOf(zcu)).?;
21372135 const ret_ty = Type.fromInterned(fn_info.return_type);
21382136
21392137 // result must be stored in the stack and we return a pointer
21402138 // to the stack instead
2141 if (func.return_value != .none) {
2142 try func.store(func.return_value, operand, ret_ty, 0);
2139 if (cg.return_value != .none) {
2140 try cg.store(cg.return_value, operand, ret_ty, 0);
21432141 } else if (fn_info.cc == .wasm_watc and ret_ty.hasRuntimeBitsIgnoreComptime(zcu)) {
21442142 switch (ret_ty.zigTypeTag(zcu)) {
21452143 // Aggregate types can be lowered as a singular value
21462144 .@"struct", .@"union" => {
21472145 const scalar_type = abi.scalarType(ret_ty, zcu);
2148 try func.emitWValue(operand);
2146 try cg.emitWValue(operand);
21492147 const opcode = buildOpcode(.{
21502148 .op = .load,
21512149 .width = @as(u8, @intCast(scalar_type.abiSize(zcu) * 8)),
21522150 .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),
21542152 });
2155 try func.addMemArg(Mir.Inst.Tag.fromOpcode(opcode), .{
2153 try cg.addMemArg(Mir.Inst.Tag.fromOpcode(opcode), .{
21562154 .offset = operand.offset(),
21572155 .alignment = @intCast(scalar_type.abiAlignment(zcu).toByteUnits().?),
21582156 });
21592157 },
2160 else => try func.emitWValue(operand),
2158 else => try cg.emitWValue(operand),
21612159 }
21622160 } else {
21632161 if (!ret_ty.hasRuntimeBitsIgnoreComptime(zcu) and ret_ty.isError(zcu)) {
2164 try func.addImm32(0);
2162 try cg.addImm32(0);
21652163 } else {
2166 try func.emitWValue(operand);
2164 try cg.emitWValue(operand);
21672165 }
21682166 }
2169 try func.restoreStackPointer();
2170 try func.addTag(.@"return");
2167 try cg.restoreStackPointer();
2168 try cg.addTag(.@"return");
21712169
2172 return func.finishAir(inst, .none, &.{un_op});
2170 return cg.finishAir(inst, .none, &.{un_op});
21732171}
21742172
2175fn airRetPtr(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
2176 const pt = func.pt;
2173fn airRetPtr(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
2174 const pt = cg.pt;
21772175 const zcu = pt.zcu;
2178 const child_type = func.typeOfIndex(inst).childType(zcu);
2176 const child_type = cg.typeOfIndex(inst).childType(zcu);
21792177
21802178 const result = result: {
21812179 if (!child_type.isFnOrHasRuntimeBitsIgnoreComptime(zcu)) {
2182 break :result try func.allocStack(Type.usize); // create pointer to void
2180 break :result try cg.allocStack(Type.usize); // create pointer to void
21832181 }
21842182
2185 const fn_info = zcu.typeToFunc(zcu.navValue(func.owner_nav).typeOf(zcu)).?;
2186 if (firstParamSRet(fn_info.cc, Type.fromInterned(fn_info.return_type), pt, func.target)) {
2187 break :result func.return_value;
2183 const fn_info = zcu.typeToFunc(zcu.navValue(cg.owner_nav).typeOf(zcu)).?;
2184 if (firstParamSRet(fn_info.cc, Type.fromInterned(fn_info.return_type), pt, cg.target)) {
2185 break :result cg.return_value;
21882186 }
21892187
2190 break :result try func.allocStackPtr(inst);
2188 break :result try cg.allocStackPtr(inst);
21912189 };
21922190
2193 return func.finishAir(inst, result, &.{});
2191 return cg.finishAir(inst, result, &.{});
21942192}
21952193
2196fn airRetLoad(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
2197 const pt = func.pt;
2194fn airRetLoad(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
2195 const pt = cg.pt;
21982196 const zcu = pt.zcu;
2199 const un_op = func.air.instructions.items(.data)[@intFromEnum(inst)].un_op;
2200 const operand = try func.resolveInst(un_op);
2201 const ret_ty = func.typeOf(un_op).childType(zcu);
2197 const un_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].un_op;
2198 const operand = try cg.resolveInst(un_op);
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)).?;
22042202 if (!ret_ty.hasRuntimeBitsIgnoreComptime(zcu)) {
22052203 if (ret_ty.isError(zcu)) {
2206 try func.addImm32(0);
2204 try cg.addImm32(0);
22072205 }
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)) {
22092207 // leave on the stack
2210 _ = try func.load(operand, ret_ty, 0);
2208 _ = try cg.load(operand, ret_ty, 0);
22112209 }
22122210
2213 try func.restoreStackPointer();
2214 try func.addTag(.@"return");
2215 return func.finishAir(inst, .none, &.{un_op});
2211 try cg.restoreStackPointer();
2212 try cg.addTag(.@"return");
2213 return cg.finishAir(inst, .none, &.{un_op});
22162214}
22172215
2218fn airCall(func: *CodeGen, inst: Air.Inst.Index, modifier: std.builtin.CallModifier) InnerError!void {
2219 const wasm = func.wasm;
2220 if (modifier == .always_tail) return func.fail("TODO implement tail calls for wasm", .{});
2221 const pl_op = func.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;
2222 const extra = func.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]);
2224 const ty = func.typeOf(pl_op.operand);
2216fn airCall(cg: *CodeGen, inst: Air.Inst.Index, modifier: std.builtin.CallModifier) InnerError!void {
2217 const wasm = cg.wasm;
2218 if (modifier == .always_tail) return cg.fail("TODO implement tail calls for wasm", .{});
2219 const pl_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;
2220 const extra = cg.air.extraData(Air.Call, pl_op.payload);
2221 const args: []const Air.Inst.Ref = @ptrCast(cg.air.extra[extra.end..][0..extra.data.args_len]);
2222 const ty = cg.typeOf(pl_op.operand);
22252223
2226 const pt = func.pt;
2224 const pt = cg.pt;
22272225 const zcu = pt.zcu;
22282226 const ip = &zcu.intern_pool;
22292227 const fn_ty = switch (ty.zigTypeTag(zcu)) {
......@@ -2233,10 +2231,10 @@ fn airCall(func: *CodeGen, inst: Air.Inst.Index, modifier: std.builtin.CallModif
22332231 };
22342232 const ret_ty = fn_ty.fnReturnType(zcu);
22352233 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
22382236 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
22412239 switch (ip.indexToKey(func_val.toIntern())) {
22422240 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
22462244 },
22472245 else => {},
22482246 }
2249 return func.fail("unable to lower callee to a function index", .{});
2247 return cg.fail("unable to lower callee to a function index", .{});
22502248 };
22512249
22522250 const sret: WValue = if (first_param_sret) blk: {
2253 const sret_local = try func.allocStack(ret_ty);
2254 try func.lowerToStack(sret_local);
2251 const sret_local = try cg.allocStack(ret_ty);
2252 try cg.lowerToStack(sret_local);
22552253 break :blk sret_local;
22562254 } else .none;
22572255
22582256 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);
22622260 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);
22652263 }
22662264
22672265 if (callee) |nav_index| {
2268 try func.addNav(.call_nav, nav_index);
2266 try cg.addNav(.call_nav, nav_index);
22692267 } else {
22702268 // in this case we call a function pointer
22712269 // so load its value onto the stack
22722270 assert(ty.zigTypeTag(zcu) == .pointer);
2273 const operand = try func.resolveInst(pl_op.operand);
2274 try func.emitWValue(operand);
2271 const operand = try cg.resolveInst(pl_op.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);
2277 try func.addLabel(.call_indirect, @intFromEnum(fn_type_index));
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);
2275 try cg.addLabel(.call_indirect, @intFromEnum(fn_type_index));
22782276 }
22792277
22802278 const result_value = result_value: {
22812279 if (!ret_ty.hasRuntimeBitsIgnoreComptime(zcu) and !ret_ty.isError(zcu)) {
22822280 break :result_value .none;
22832281 } else if (ret_ty.isNoReturn(zcu)) {
2284 try func.addTag(.@"unreachable");
2282 try cg.addTag(.@"unreachable");
22852283 break :result_value .none;
22862284 } else if (first_param_sret) {
22872285 break :result_value sret;
22882286 // TODO: Make this less fragile and optimize
22892287 } 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);
2291 try func.addLabel(.local_set, result_local.local.value);
2288 const result_local = try cg.allocLocal(ret_ty);
2289 try cg.addLabel(.local_set, result_local.local.value);
22922290 const scalar_type = abi.scalarType(ret_ty, zcu);
2293 const result = try func.allocStack(scalar_type);
2294 try func.store(result, result_local, scalar_type, 0);
2291 const result = try cg.allocStack(scalar_type);
2292 try cg.store(result, result_local, scalar_type, 0);
22952293 break :result_value result;
22962294 } else {
2297 const result_local = try func.allocLocal(ret_ty);
2298 try func.addLabel(.local_set, result_local.local.value);
2295 const result_local = try cg.allocLocal(ret_ty);
2296 try cg.addLabel(.local_set, result_local.local.value);
22992297 break :result_value result_local;
23002298 }
23012299 };
23022300
2303 var bt = try func.iterateBigTomb(inst, 1 + args.len);
2301 var bt = try cg.iterateBigTomb(inst, 1 + args.len);
23042302 bt.feed(pl_op.operand);
23052303 for (args) |arg| bt.feed(arg);
23062304 return bt.finishAir(result_value);
23072305}
23082306
2309fn airAlloc(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
2310 const value = try func.allocStackPtr(inst);
2311 return func.finishAir(inst, value, &.{});
2307fn airAlloc(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
2308 const value = try cg.allocStackPtr(inst);
2309 return cg.finishAir(inst, value, &.{});
23122310}
23132311
2314fn airStore(func: *CodeGen, inst: Air.Inst.Index, safety: bool) InnerError!void {
2315 const pt = func.pt;
2312fn airStore(cg: *CodeGen, inst: Air.Inst.Index, safety: bool) InnerError!void {
2313 const pt = cg.pt;
23162314 const zcu = pt.zcu;
23172315 if (safety) {
23182316 // TODO if the value is undef, write 0xaa bytes to dest
23192317 } else {
23202318 // TODO if the value is undef, don't lower this instruction
23212319 }
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);
2325 const rhs = try func.resolveInst(bin_op.rhs);
2326 const ptr_ty = func.typeOf(bin_op.lhs);
2322 const lhs = try cg.resolveInst(bin_op.lhs);
2323 const rhs = try cg.resolveInst(bin_op.rhs);
2324 const ptr_ty = cg.typeOf(bin_op.lhs);
23272325 const ptr_info = ptr_ty.ptrInfo(zcu);
23282326 const ty = ptr_ty.childType(zcu);
23292327
23302328 if (ptr_info.packed_offset.host_size == 0) {
2331 try func.store(lhs, rhs, ty, 0);
2329 try cg.store(lhs, rhs, ty, 0);
23322330 } else {
23332331 // at this point we have a non-natural alignment, we must
23342332 // load the value, and then shift+or the rhs into the result location.
23352333 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)) {
2338 return func.fail("TODO: airStore for pointers to bitfields with backing type larger than 64bits", .{});
2335 if (isByRef(int_elem_ty, pt, cg.target)) {
2336 return cg.fail("TODO: airStore for pointers to bitfields with backing type larger than 64bits", .{});
23392337 }
23402338
23412339 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
23542352 else
23552353 .{ .imm64 = ~@as(u64, 0) >> @intCast(64 - ty.bitSize(zcu)) };
23562354
2357 try func.emitWValue(lhs);
2358 const loaded = try func.load(lhs, int_elem_ty, 0);
2359 const anded = try func.binOp(loaded, mask_val, int_elem_ty, .@"and");
2360 const extended_value = try func.intcast(rhs, ty, int_elem_ty);
2361 const masked_value = try func.binOp(extended_value, wrap_mask_val, int_elem_ty, .@"and");
2355 try cg.emitWValue(lhs);
2356 const loaded = try cg.load(lhs, int_elem_ty, 0);
2357 const anded = try cg.binOp(loaded, mask_val, int_elem_ty, .@"and");
2358 const extended_value = try cg.intcast(rhs, ty, int_elem_ty);
2359 const masked_value = try cg.binOp(extended_value, wrap_mask_val, int_elem_ty, .@"and");
23622360 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);
23642362 } 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");
23662364 // 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());
23682366 }
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 });
23712369}
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 {
23742372 assert(!(lhs != .stack and rhs == .stack));
2375 const pt = func.pt;
2373 const pt = cg.pt;
23762374 const zcu = pt.zcu;
23772375 const abi_size = ty.abiSize(zcu);
23782376 switch (ty.zigTypeTag(zcu)) {
23792377 .error_union => {
23802378 const pl_ty = ty.errorUnionPayload(zcu);
23812379 if (!pl_ty.hasRuntimeBitsIgnoreComptime(zcu)) {
2382 return func.store(lhs, rhs, Type.anyerror, 0);
2380 return cg.store(lhs, rhs, Type.anyerror, 0);
23832381 }
23842382
23852383 const len = @as(u32, @intCast(abi_size));
2386 return func.memcpy(lhs, rhs, .{ .imm32 = len });
2384 return cg.memcpy(lhs, rhs, .{ .imm32 = len });
23872385 },
23882386 .optional => {
23892387 if (ty.isPtrLikeOptional(zcu)) {
2390 return func.store(lhs, rhs, Type.usize, 0);
2388 return cg.store(lhs, rhs, Type.usize, 0);
23912389 }
23922390 const pl_ty = ty.optionalChild(zcu);
23932391 if (!pl_ty.hasRuntimeBitsIgnoreComptime(zcu)) {
2394 return func.store(lhs, rhs, Type.u8, 0);
2392 return cg.store(lhs, rhs, Type.u8, 0);
23952393 }
23962394 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);
23982396 }
23992397
24002398 const len = @as(u32, @intCast(abi_size));
2401 return func.memcpy(lhs, rhs, .{ .imm32 = len });
2399 return cg.memcpy(lhs, rhs, .{ .imm32 = len });
24022400 },
2403 .@"struct", .array, .@"union" => if (isByRef(ty, pt, func.target)) {
2401 .@"struct", .array, .@"union" => if (isByRef(ty, pt, cg.target)) {
24042402 const len = @as(u32, @intCast(abi_size));
2405 return func.memcpy(lhs, rhs, .{ .imm32 = len });
2403 return cg.memcpy(lhs, rhs, .{ .imm32 = len });
24062404 },
2407 .vector => switch (determineSimdStoreStrategy(ty, zcu, func.target)) {
2405 .vector => switch (determineSimdStoreStrategy(ty, zcu, cg.target)) {
24082406 .unrolled => {
24092407 const len: u32 = @intCast(abi_size);
2410 return func.memcpy(lhs, rhs, .{ .imm32 = len });
2408 return cg.memcpy(lhs, rhs, .{ .imm32 = len });
24112409 },
24122410 .direct => {
2413 try func.emitWValue(lhs);
2414 try func.lowerToStack(rhs);
2411 try cg.emitWValue(lhs);
2412 try cg.lowerToStack(rhs);
24152413 // 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);
24172415 // 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{
24192417 @intFromEnum(std.wasm.SimdOpcode.v128_store),
24202418 offset + lhs.offset(),
24212419 @intCast(ty.abiAlignment(zcu).toByteUnits() orelse 0),
24222420 });
2423 return func.addInst(.{ .tag = .simd_prefix, .data = .{ .payload = extra_index } });
2421 return cg.addInst(.{ .tag = .simd_prefix, .data = .{ .payload = extra_index } });
24242422 },
24252423 },
24262424 .pointer => {
24272425 if (ty.isSlice(zcu)) {
24282426 // store pointer first
24292427 // lower it to the stack so we do not have to store rhs into a local first
2430 try func.emitWValue(lhs);
2431 const ptr_local = try func.load(rhs, Type.usize, 0);
2432 try func.store(.stack, ptr_local, Type.usize, 0 + lhs.offset());
2428 try cg.emitWValue(lhs);
2429 const ptr_local = try cg.load(rhs, Type.usize, 0);
2430 try cg.store(.stack, ptr_local, Type.usize, 0 + lhs.offset());
24332431
24342432 // retrieve length from rhs, and store that alongside lhs as well
2435 try func.emitWValue(lhs);
2436 const len_local = try func.load(rhs, Type.usize, func.ptrSize());
2437 try func.store(.stack, len_local, Type.usize, func.ptrSize() + lhs.offset());
2433 try cg.emitWValue(lhs);
2434 const len_local = try cg.load(rhs, Type.usize, cg.ptrSize());
2435 try cg.store(.stack, len_local, Type.usize, cg.ptrSize() + lhs.offset());
24382436 return;
24392437 }
24402438 },
24412439 .int, .@"enum", .float => if (abi_size > 8 and abi_size <= 16) {
2442 try func.emitWValue(lhs);
2443 const lsb = try func.load(rhs, Type.u64, 0);
2444 try func.store(.stack, lsb, Type.u64, 0 + lhs.offset());
2440 try cg.emitWValue(lhs);
2441 const lsb = try cg.load(rhs, Type.u64, 0);
2442 try cg.store(.stack, lsb, Type.u64, 0 + lhs.offset());
24452443
2446 try func.emitWValue(lhs);
2447 const msb = try func.load(rhs, Type.u64, 8);
2448 try func.store(.stack, msb, Type.u64, 8 + lhs.offset());
2444 try cg.emitWValue(lhs);
2445 const msb = try cg.load(rhs, Type.u64, 8);
2446 try cg.store(.stack, msb, Type.u64, 8 + lhs.offset());
24492447 return;
24502448 } 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))) });
24522450 },
24532451 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}`", .{
24552453 ty.fmt(pt),
24562454 abi_size,
24572455 });
24582456 },
24592457 }
2460 try func.emitWValue(lhs);
2458 try cg.emitWValue(lhs);
24612459 // In this case we're actually interested in storing the stack position
24622460 // 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);
24662464 const opcode = buildOpcode(.{
24672465 .valtype1 = valtype,
24682466 .width = @as(u8, @intCast(abi_size * 8)),
......@@ -2470,7 +2468,7 @@ fn store(func: *CodeGen, lhs: WValue, rhs: WValue, ty: Type, offset: u32) InnerE
24702468 });
24712469
24722470 // store rhs value at stack pointer's location in memory
2473 try func.addMemArg(
2471 try cg.addMemArg(
24742472 Mir.Inst.Tag.fromOpcode(opcode),
24752473 .{
24762474 .offset = offset + lhs.offset(),
......@@ -2479,26 +2477,26 @@ fn store(func: *CodeGen, lhs: WValue, rhs: WValue, ty: Type, offset: u32) InnerE
24792477 );
24802478}
24812479
2482fn airLoad(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
2483 const pt = func.pt;
2480fn airLoad(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
2481 const pt = cg.pt;
24842482 const zcu = pt.zcu;
2485 const ty_op = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
2486 const operand = try func.resolveInst(ty_op.operand);
2483 const ty_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
2484 const operand = try cg.resolveInst(ty_op.operand);
24872485 const ty = ty_op.ty.toType();
2488 const ptr_ty = func.typeOf(ty_op.operand);
2486 const ptr_ty = cg.typeOf(ty_op.operand);
24892487 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
24932491 const result = result: {
2494 if (isByRef(ty, pt, func.target)) {
2495 const new_local = try func.allocStack(ty);
2496 try func.store(new_local, operand, ty, 0);
2492 if (isByRef(ty, pt, cg.target)) {
2493 const new_local = try cg.allocStack(ty);
2494 try cg.store(new_local, operand, ty, 0);
24972495 break :result new_local;
24982496 }
24992497
25002498 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);
25022500 }
25032501
25042502 // 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 {
25092507 else if (ptr_info.packed_offset.host_size <= 8)
25102508 .{ .imm64 = ptr_info.packed_offset.bit_offset }
25112509 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);
2515 const shifted = try func.binOp(stack_loaded, shift_val, int_elem_ty, .shr);
2516 break :result try func.trunc(shifted, ty, int_elem_ty);
2512 const stack_loaded = try cg.load(operand, int_elem_ty, 0);
2513 const shifted = try cg.binOp(stack_loaded, shift_val, int_elem_ty, .shr);
2514 break :result try cg.trunc(shifted, ty, int_elem_ty);
25172515 };
2518 return func.finishAir(inst, result, &.{ty_op.operand});
2516 return cg.finishAir(inst, result, &.{ty_op.operand});
25192517}
25202518
25212519/// Loads an operand from the linear memory section.
25222520/// NOTE: Leaves the value on the stack.
2523fn load(func: *CodeGen, operand: WValue, ty: Type, offset: u32) InnerError!WValue {
2524 const pt = func.pt;
2521fn load(cg: *CodeGen, operand: WValue, ty: Type, offset: u32) InnerError!WValue {
2522 const pt = cg.pt;
25252523 const zcu = pt.zcu;
25262524 // load local's value from memory by its stack position
2527 try func.emitWValue(operand);
2525 try cg.emitWValue(operand);
25282526
25292527 if (ty.zigTypeTag(zcu) == .vector) {
25302528 // 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));
25322530 // 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{
25342532 @intFromEnum(std.wasm.SimdOpcode.v128_load),
25352533 offset + operand.offset(),
25362534 @intCast(ty.abiAlignment(zcu).toByteUnits().?),
25372535 });
2538 try func.addInst(.{ .tag = .simd_prefix, .data = .{ .payload = extra_index } });
2536 try cg.addInst(.{ .tag = .simd_prefix, .data = .{ .payload = extra_index } });
25392537 return .stack;
25402538 }
25412539
25422540 const abi_size: u8 = @intCast(ty.abiSize(zcu));
25432541 const opcode = buildOpcode(.{
2544 .valtype1 = typeToValtype(ty, pt, func.target),
2542 .valtype1 = typeToValtype(ty, pt, cg.target),
25452543 .width = abi_size * 8,
25462544 .op = .load,
25472545 .signedness = if (ty.isSignedInt(zcu)) .signed else .unsigned,
25482546 });
25492547
2550 try func.addMemArg(
2548 try cg.addMemArg(
25512549 Mir.Inst.Tag.fromOpcode(opcode),
25522550 .{
25532551 .offset = offset + operand.offset(),
......@@ -2558,18 +2556,18 @@ fn load(func: *CodeGen, operand: WValue, ty: Type, offset: u32) InnerError!WValu
25582556 return .stack;
25592557}
25602558
2561fn airArg(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
2562 const pt = func.pt;
2559fn airArg(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
2560 const pt = cg.pt;
25632561 const zcu = pt.zcu;
2564 const arg_index = func.arg_index;
2565 const arg = func.args[arg_index];
2566 const cc = zcu.typeToFunc(zcu.navValue(func.owner_nav).typeOf(zcu)).?.cc;
2567 const arg_ty = func.typeOfIndex(inst);
2562 const arg_index = cg.arg_index;
2563 const arg = cg.args[arg_index];
2564 const cc = zcu.typeToFunc(zcu.navValue(cg.owner_nav).typeOf(zcu)).?.cc;
2565 const arg_ty = cg.typeOfIndex(inst);
25682566 if (cc == .wasm_watc) {
25692567 const arg_classes = abi.classifyType(arg_ty, zcu);
25702568 for (arg_classes) |class| {
25712569 if (class != .none) {
2572 func.arg_index += 1;
2570 cg.arg_index += 1;
25732571 }
25742572 }
25752573
......@@ -2577,31 +2575,31 @@ fn airArg(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
25772575 // we combine them into a single stack value
25782576 if (arg_classes[0] == .direct and arg_classes[1] == .direct) {
25792577 if (arg_ty.zigTypeTag(zcu) != .int and arg_ty.zigTypeTag(zcu) != .float) {
2580 return func.fail(
2578 return cg.fail(
25812579 "TODO: Implement C-ABI argument for type '{}'",
25822580 .{arg_ty.fmt(pt)},
25832581 );
25842582 }
2585 const result = try func.allocStack(arg_ty);
2586 try func.store(result, arg, Type.u64, 0);
2587 try func.store(result, func.args[arg_index + 1], Type.u64, 8);
2588 return func.finishAir(inst, result, &.{});
2583 const result = try cg.allocStack(arg_ty);
2584 try cg.store(result, arg, Type.u64, 0);
2585 try cg.store(result, cg.args[arg_index + 1], Type.u64, 8);
2586 return cg.finishAir(inst, result, &.{});
25892587 }
25902588 } else {
2591 func.arg_index += 1;
2589 cg.arg_index += 1;
25922590 }
25932591
2594 return func.finishAir(inst, arg, &.{});
2592 return cg.finishAir(inst, arg, &.{});
25952593}
25962594
2597fn airBinOp(func: *CodeGen, inst: Air.Inst.Index, op: Op) InnerError!void {
2598 const pt = func.pt;
2595fn airBinOp(cg: *CodeGen, inst: Air.Inst.Index, op: Op) InnerError!void {
2596 const pt = cg.pt;
25992597 const zcu = pt.zcu;
2600 const bin_op = func.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
2601 const lhs = try func.resolveInst(bin_op.lhs);
2602 const rhs = try func.resolveInst(bin_op.rhs);
2603 const lhs_ty = func.typeOf(bin_op.lhs);
2604 const rhs_ty = func.typeOf(bin_op.rhs);
2598 const bin_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
2599 const lhs = try cg.resolveInst(bin_op.lhs);
2600 const rhs = try cg.resolveInst(bin_op.rhs);
2601 const lhs_ty = cg.typeOf(bin_op.lhs);
2602 const rhs_ty = cg.typeOf(bin_op.rhs);
26052603
26062604 // For certain operations, such as shifting, the types are different.
26072605 // 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 {
26112609 const result = switch (op) {
26122610 .shr, .shl => result: {
26132611 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)});
26152613 };
26162614 const rhs_wasm_bits = toWasmBits(@intCast(rhs_ty.bitSize(zcu))).?;
26172615 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)
26192617 else
26202618 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);
26222620 },
2623 else => try func.binOp(lhs, rhs, lhs_ty, op),
2621 else => try cg.binOp(lhs, rhs, lhs_ty, op),
26242622 };
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 });
26272625}
26282626
26292627/// Performs a binary operation on the given `WValue`'s
26302628/// NOTE: THis leaves the value on top of the stack.
2631fn binOp(func: *CodeGen, lhs: WValue, rhs: WValue, ty: Type, op: Op) InnerError!WValue {
2632 const pt = func.pt;
2629fn binOp(cg: *CodeGen, lhs: WValue, rhs: WValue, ty: Type, op: Op) InnerError!WValue {
2630 const pt = cg.pt;
26332631 const zcu = pt.zcu;
26342632 assert(!(lhs != .stack and rhs == .stack));
26352633
26362634 if (ty.isAnyFloat()) {
26372635 const float_op = FloatOp.fromOp(op);
2638 return func.floatOp(float_op, ty, &.{ lhs, rhs });
2636 return cg.floatOp(float_op, ty, &.{ lhs, rhs });
26392637 }
26402638
2641 if (isByRef(ty, pt, func.target)) {
2639 if (isByRef(ty, pt, cg.target)) {
26422640 if (ty.zigTypeTag(zcu) == .int) {
2643 return func.binOpBigInt(lhs, rhs, ty, op);
2641 return cg.binOpBigInt(lhs, rhs, ty, op);
26442642 } else {
2645 return func.fail(
2643 return cg.fail(
26462644 "TODO: Implement binary operation for type: {}",
26472645 .{ty.fmt(pt)},
26482646 );
......@@ -2651,82 +2649,82 @@ fn binOp(func: *CodeGen, lhs: WValue, rhs: WValue, ty: Type, op: Op) InnerError!
26512649
26522650 const opcode: std.wasm.Opcode = buildOpcode(.{
26532651 .op = op,
2654 .valtype1 = typeToValtype(ty, pt, func.target),
2652 .valtype1 = typeToValtype(ty, pt, cg.target),
26552653 .signedness = if (ty.isSignedInt(zcu)) .signed else .unsigned,
26562654 });
2657 try func.emitWValue(lhs);
2658 try func.emitWValue(rhs);
2655 try cg.emitWValue(lhs);
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
26622660 return .stack;
26632661}
26642662
2665fn binOpBigInt(func: *CodeGen, lhs: WValue, rhs: WValue, ty: Type, op: Op) InnerError!WValue {
2666 const pt = func.pt;
2663fn binOpBigInt(cg: *CodeGen, lhs: WValue, rhs: WValue, ty: Type, op: Op) InnerError!WValue {
2664 const pt = cg.pt;
26672665 const zcu = pt.zcu;
26682666 const int_info = ty.intInfo(zcu);
26692667 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", .{});
26712669 }
26722670
26732671 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 }),
26752673 .div => switch (int_info.signedness) {
2676 .signed => return func.callIntrinsic("__divti3", &.{ ty.toIntern(), ty.toIntern() }, ty, &.{ lhs, rhs }),
2677 .unsigned => return func.callIntrinsic("__udivti3", &.{ ty.toIntern(), ty.toIntern() }, ty, &.{ lhs, rhs }),
2674 .signed => return cg.callIntrinsic("__divti3", &.{ ty.toIntern(), ty.toIntern() }, ty, &.{ lhs, rhs }),
2675 .unsigned => return cg.callIntrinsic("__udivti3", &.{ ty.toIntern(), ty.toIntern() }, ty, &.{ lhs, rhs }),
26782676 },
26792677 .rem => switch (int_info.signedness) {
2680 .signed => return func.callIntrinsic("__modti3", &.{ ty.toIntern(), ty.toIntern() }, ty, &.{ lhs, rhs }),
2681 .unsigned => return func.callIntrinsic("__umodti3", &.{ ty.toIntern(), ty.toIntern() }, ty, &.{ lhs, rhs }),
2678 .signed => return cg.callIntrinsic("__modti3", &.{ ty.toIntern(), ty.toIntern() }, ty, &.{ lhs, rhs }),
2679 .unsigned => return cg.callIntrinsic("__umodti3", &.{ ty.toIntern(), ty.toIntern() }, ty, &.{ lhs, rhs }),
26822680 },
26832681 .shr => switch (int_info.signedness) {
2684 .signed => return func.callIntrinsic("__ashrti3", &.{ ty.toIntern(), .i32_type }, ty, &.{ lhs, rhs }),
2685 .unsigned => return func.callIntrinsic("__lshrti3", &.{ ty.toIntern(), .i32_type }, ty, &.{ lhs, rhs }),
2682 .signed => return cg.callIntrinsic("__ashrti3", &.{ ty.toIntern(), .i32_type }, ty, &.{ lhs, rhs }),
2683 .unsigned => return cg.callIntrinsic("__lshrti3", &.{ ty.toIntern(), .i32_type }, ty, &.{ lhs, rhs }),
26862684 },
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 }),
26882686 .@"and", .@"or", .xor => {
2689 const result = try func.allocStack(ty);
2690 try func.emitWValue(result);
2691 const lhs_lsb = try func.load(lhs, Type.u64, 0);
2692 const rhs_lsb = try func.load(rhs, Type.u64, 0);
2693 const op_lsb = try func.binOp(lhs_lsb, rhs_lsb, Type.u64, op);
2694 try func.store(.stack, op_lsb, Type.u64, result.offset());
2695
2696 try func.emitWValue(result);
2697 const lhs_msb = try func.load(lhs, Type.u64, 8);
2698 const rhs_msb = try func.load(rhs, Type.u64, 8);
2699 const op_msb = try func.binOp(lhs_msb, rhs_msb, Type.u64, op);
2700 try func.store(.stack, op_msb, Type.u64, result.offset() + 8);
2687 const result = try cg.allocStack(ty);
2688 try cg.emitWValue(result);
2689 const lhs_lsb = try cg.load(lhs, Type.u64, 0);
2690 const rhs_lsb = try cg.load(rhs, Type.u64, 0);
2691 const op_lsb = try cg.binOp(lhs_lsb, rhs_lsb, Type.u64, op);
2692 try cg.store(.stack, op_lsb, Type.u64, result.offset());
2693
2694 try cg.emitWValue(result);
2695 const lhs_msb = try cg.load(lhs, Type.u64, 8);
2696 const rhs_msb = try cg.load(rhs, Type.u64, 8);
2697 const op_msb = try cg.binOp(lhs_msb, rhs_msb, Type.u64, op);
2698 try cg.store(.stack, op_msb, Type.u64, result.offset() + 8);
27012699 return result;
27022700 },
27032701 .add, .sub => {
2704 const result = try func.allocStack(ty);
2705 var lhs_lsb = try (try func.load(lhs, Type.u64, 0)).toLocal(func, Type.u64);
2706 defer lhs_lsb.free(func);
2707 var rhs_lsb = try (try func.load(rhs, Type.u64, 0)).toLocal(func, Type.u64);
2708 defer rhs_lsb.free(func);
2709 var op_lsb = try (try func.binOp(lhs_lsb, rhs_lsb, Type.u64, op)).toLocal(func, Type.u64);
2710 defer op_lsb.free(func);
2711
2712 const lhs_msb = try func.load(lhs, Type.u64, 8);
2713 const rhs_msb = try func.load(rhs, Type.u64, 8);
2714 const op_msb = try func.binOp(lhs_msb, rhs_msb, Type.u64, op);
2702 const result = try cg.allocStack(ty);
2703 var lhs_lsb = try (try cg.load(lhs, Type.u64, 0)).toLocal(cg, Type.u64);
2704 defer lhs_lsb.free(cg);
2705 var rhs_lsb = try (try cg.load(rhs, Type.u64, 0)).toLocal(cg, Type.u64);
2706 defer rhs_lsb.free(cg);
2707 var op_lsb = try (try cg.binOp(lhs_lsb, rhs_lsb, Type.u64, op)).toLocal(cg, Type.u64);
2708 defer op_lsb.free(cg);
2709
2710 const lhs_msb = try cg.load(lhs, Type.u64, 8);
2711 const rhs_msb = try cg.load(rhs, Type.u64, 8);
2712 const op_msb = try cg.binOp(lhs_msb, rhs_msb, Type.u64, op);
27152713
27162714 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);
27182716 } 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);
27202718 } else unreachable;
2721 const tmp = try func.intcast(lt, Type.u32, Type.u64);
2722 var tmp_op = try (try func.binOp(op_msb, tmp, Type.u64, op)).toLocal(func, Type.u64);
2723 defer tmp_op.free(func);
2719 const tmp = try cg.intcast(lt, Type.u32, Type.u64);
2720 var tmp_op = try (try cg.binOp(op_msb, tmp, Type.u64, op)).toLocal(cg, Type.u64);
2721 defer tmp_op.free(cg);
27242722
2725 try func.store(result, op_lsb, Type.u64, 0);
2726 try func.store(result, tmp_op, Type.u64, 8);
2723 try cg.store(result, op_lsb, Type.u64, 0);
2724 try cg.store(result, tmp_op, Type.u64, 8);
27272725 return result;
27282726 },
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)}),
27302728 }
27312729}
27322730
......@@ -2806,117 +2804,117 @@ const FloatOp = enum {
28062804 }
28072805};
28082806
2809fn airAbs(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
2810 const pt = func.pt;
2807fn airAbs(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
2808 const pt = cg.pt;
28112809 const zcu = pt.zcu;
2812 const ty_op = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
2813 const operand = try func.resolveInst(ty_op.operand);
2814 const ty = func.typeOf(ty_op.operand);
2810 const ty_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
2811 const operand = try cg.resolveInst(ty_op.operand);
2812 const ty = cg.typeOf(ty_op.operand);
28152813 const scalar_ty = ty.scalarType(zcu);
28162814
28172815 switch (scalar_ty.zigTypeTag(zcu)) {
28182816 .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)});
28202818 } else {
28212819 const int_bits = ty.intInfo(zcu).bits;
28222820 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});
28242822 };
28252823
28262824 switch (wasm_bits) {
28272825 32 => {
2828 try func.emitWValue(operand);
2826 try cg.emitWValue(operand);
28292827
2830 try func.addImm32(31);
2831 try func.addTag(.i32_shr_s);
2828 try cg.addImm32(31);
2829 try cg.addTag(.i32_shr_s);
28322830
2833 var tmp = try func.allocLocal(ty);
2834 defer tmp.free(func);
2835 try func.addLabel(.local_tee, tmp.local.value);
2831 var tmp = try cg.allocLocal(ty);
2832 defer tmp.free(cg);
2833 try cg.addLabel(.local_tee, tmp.local.value);
28362834
2837 try func.emitWValue(operand);
2838 try func.addTag(.i32_xor);
2839 try func.emitWValue(tmp);
2840 try func.addTag(.i32_sub);
2841 return func.finishAir(inst, .stack, &.{ty_op.operand});
2835 try cg.emitWValue(operand);
2836 try cg.addTag(.i32_xor);
2837 try cg.emitWValue(tmp);
2838 try cg.addTag(.i32_sub);
2839 return cg.finishAir(inst, .stack, &.{ty_op.operand});
28422840 },
28432841 64 => {
2844 try func.emitWValue(operand);
2842 try cg.emitWValue(operand);
28452843
2846 try func.addImm64(63);
2847 try func.addTag(.i64_shr_s);
2844 try cg.addImm64(63);
2845 try cg.addTag(.i64_shr_s);
28482846
2849 var tmp = try func.allocLocal(ty);
2850 defer tmp.free(func);
2851 try func.addLabel(.local_tee, tmp.local.value);
2847 var tmp = try cg.allocLocal(ty);
2848 defer tmp.free(cg);
2849 try cg.addLabel(.local_tee, tmp.local.value);
28522850
2853 try func.emitWValue(operand);
2854 try func.addTag(.i64_xor);
2855 try func.emitWValue(tmp);
2856 try func.addTag(.i64_sub);
2857 return func.finishAir(inst, .stack, &.{ty_op.operand});
2851 try cg.emitWValue(operand);
2852 try cg.addTag(.i64_xor);
2853 try cg.emitWValue(tmp);
2854 try cg.addTag(.i64_sub);
2855 return cg.finishAir(inst, .stack, &.{ty_op.operand});
28582856 },
28592857 128 => {
2860 const mask = try func.allocStack(Type.u128);
2861 try func.emitWValue(mask);
2862 try func.emitWValue(mask);
2858 const mask = try cg.allocStack(Type.u128);
2859 try cg.emitWValue(mask);
2860 try cg.emitWValue(mask);
28632861
2864 _ = try func.load(operand, Type.u64, 8);
2865 try func.addImm64(63);
2866 try func.addTag(.i64_shr_s);
2862 _ = try cg.load(operand, Type.u64, 8);
2863 try cg.addImm64(63);
2864 try cg.addTag(.i64_shr_s);
28672865
2868 var tmp = try func.allocLocal(Type.u64);
2869 defer tmp.free(func);
2870 try func.addLabel(.local_tee, tmp.local.value);
2871 try func.store(.stack, .stack, Type.u64, mask.offset() + 0);
2872 try func.emitWValue(tmp);
2873 try func.store(.stack, .stack, Type.u64, mask.offset() + 8);
2866 var tmp = try cg.allocLocal(Type.u64);
2867 defer tmp.free(cg);
2868 try cg.addLabel(.local_tee, tmp.local.value);
2869 try cg.store(.stack, .stack, Type.u64, mask.offset() + 0);
2870 try cg.emitWValue(tmp);
2871 try cg.store(.stack, .stack, Type.u64, mask.offset() + 8);
28742872
2875 const a = try func.binOpBigInt(operand, mask, Type.u128, .xor);
2876 const b = try func.binOpBigInt(a, mask, Type.u128, .sub);
2873 const a = try cg.binOpBigInt(operand, mask, Type.u128, .xor);
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});
28792877 },
28802878 else => unreachable,
28812879 }
28822880 },
28832881 .float => {
2884 const result = try func.floatOp(.fabs, ty, &.{operand});
2885 return func.finishAir(inst, result, &.{ty_op.operand});
2882 const result = try cg.floatOp(.fabs, ty, &.{operand});
2883 return cg.finishAir(inst, result, &.{ty_op.operand});
28862884 },
28872885 else => unreachable,
28882886 }
28892887}
28902888
2891fn airUnaryFloatOp(func: *CodeGen, inst: Air.Inst.Index, op: FloatOp) InnerError!void {
2892 const un_op = func.air.instructions.items(.data)[@intFromEnum(inst)].un_op;
2893 const operand = try func.resolveInst(un_op);
2894 const ty = func.typeOf(un_op);
2889fn airUnaryFloatOp(cg: *CodeGen, inst: Air.Inst.Index, op: FloatOp) InnerError!void {
2890 const un_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].un_op;
2891 const operand = try cg.resolveInst(un_op);
2892 const ty = cg.typeOf(un_op);
28952893
2896 const result = try func.floatOp(op, ty, &.{operand});
2897 return func.finishAir(inst, result, &.{un_op});
2894 const result = try cg.floatOp(op, ty, &.{operand});
2895 return cg.finishAir(inst, result, &.{un_op});
28982896}
28992897
2900fn floatOp(func: *CodeGen, float_op: FloatOp, ty: Type, args: []const WValue) InnerError!WValue {
2901 const pt = func.pt;
2898fn floatOp(cg: *CodeGen, float_op: FloatOp, ty: Type, args: []const WValue) InnerError!WValue {
2899 const pt = cg.pt;
29022900 const zcu = pt.zcu;
29032901 if (ty.zigTypeTag(zcu) == .vector) {
2904 return func.fail("TODO: Implement floatOps for vectors", .{});
2902 return cg.fail("TODO: Implement floatOps for vectors", .{});
29052903 }
29062904
2907 const float_bits = ty.floatBits(func.target.*);
2905 const float_bits = ty.floatBits(cg.target.*);
29082906
29092907 if (float_op == .neg) {
2910 return func.floatNeg(ty, args[0]);
2908 return cg.floatNeg(ty, args[0]);
29112909 }
29122910
29132911 if (float_bits == 32 or float_bits == 64) {
29142912 if (float_op.toOp()) |op| {
29152913 for (args) |operand| {
2916 try func.emitWValue(operand);
2914 try cg.emitWValue(operand);
29172915 }
2918 const opcode = buildOpcode(.{ .op = op, .valtype1 = typeToValtype(ty, pt, func.target) });
2919 try func.addTag(Mir.Inst.Tag.fromOpcode(opcode));
2916 const opcode = buildOpcode(.{ .op = op, .valtype1 = typeToValtype(ty, pt, cg.target) });
2917 try cg.addTag(Mir.Inst.Tag.fromOpcode(opcode));
29202918 return .stack;
29212919 }
29222920 }
......@@ -2958,45 +2956,45 @@ fn floatOp(func: *CodeGen, float_op: FloatOp, ty: Type, args: []const WValue) In
29582956 // fma requires three operands
29592957 var param_types_buffer: [3]InternPool.Index = .{ ty.ip_index, ty.ip_index, ty.ip_index };
29602958 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);
29622960}
29632961
29642962/// NOTE: The result value remains on top of the stack.
2965fn floatNeg(func: *CodeGen, ty: Type, arg: WValue) InnerError!WValue {
2966 const float_bits = ty.floatBits(func.target.*);
2963fn floatNeg(cg: *CodeGen, ty: Type, arg: WValue) InnerError!WValue {
2964 const float_bits = ty.floatBits(cg.target.*);
29672965 switch (float_bits) {
29682966 16 => {
2969 try func.emitWValue(arg);
2970 try func.addImm32(0x8000);
2971 try func.addTag(.i32_xor);
2967 try cg.emitWValue(arg);
2968 try cg.addImm32(0x8000);
2969 try cg.addTag(.i32_xor);
29722970 return .stack;
29732971 },
29742972 32, 64 => {
2975 try func.emitWValue(arg);
2973 try cg.emitWValue(arg);
29762974 const val_type: std.wasm.Valtype = if (float_bits == 32) .f32 else .f64;
29772975 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));
29792977 return .stack;
29802978 },
29812979 80, 128 => {
2982 const result = try func.allocStack(ty);
2983 try func.emitWValue(result);
2984 try func.emitWValue(arg);
2985 try func.addMemArg(.i64_load, .{ .offset = 0 + arg.offset(), .alignment = 2 });
2986 try func.addMemArg(.i64_store, .{ .offset = 0 + result.offset(), .alignment = 2 });
2980 const result = try cg.allocStack(ty);
2981 try cg.emitWValue(result);
2982 try cg.emitWValue(arg);
2983 try cg.addMemArg(.i64_load, .{ .offset = 0 + arg.offset(), .alignment = 2 });
2984 try cg.addMemArg(.i64_store, .{ .offset = 0 + result.offset(), .alignment = 2 });
29872985
2988 try func.emitWValue(result);
2989 try func.emitWValue(arg);
2990 try func.addMemArg(.i64_load, .{ .offset = 8 + arg.offset(), .alignment = 2 });
2986 try cg.emitWValue(result);
2987 try cg.emitWValue(arg);
2988 try cg.addMemArg(.i64_load, .{ .offset = 8 + arg.offset(), .alignment = 2 });
29912989
29922990 if (float_bits == 80) {
2993 try func.addImm64(0x8000);
2994 try func.addTag(.i64_xor);
2995 try func.addMemArg(.i64_store16, .{ .offset = 8 + result.offset(), .alignment = 2 });
2991 try cg.addImm64(0x8000);
2992 try cg.addTag(.i64_xor);
2993 try cg.addMemArg(.i64_store16, .{ .offset = 8 + result.offset(), .alignment = 2 });
29962994 } else {
2997 try func.addImm64(0x8000000000000000);
2998 try func.addTag(.i64_xor);
2999 try func.addMemArg(.i64_store, .{ .offset = 8 + result.offset(), .alignment = 2 });
2995 try cg.addImm64(0x8000000000000000);
2996 try cg.addTag(.i64_xor);
2997 try cg.addMemArg(.i64_store, .{ .offset = 8 + result.offset(), .alignment = 2 });
30002998 }
30012999 return result;
30023000 },
......@@ -3004,18 +3002,18 @@ fn floatNeg(func: *CodeGen, ty: Type, arg: WValue) InnerError!WValue {
30043002 }
30053003}
30063004
3007fn airWrapBinOp(func: *CodeGen, inst: Air.Inst.Index, op: Op) InnerError!void {
3008 const pt = func.pt;
3005fn airWrapBinOp(cg: *CodeGen, inst: Air.Inst.Index, op: Op) InnerError!void {
3006 const pt = cg.pt;
30093007 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);
3013 const rhs = try func.resolveInst(bin_op.rhs);
3014 const lhs_ty = func.typeOf(bin_op.lhs);
3015 const rhs_ty = func.typeOf(bin_op.rhs);
3010 const lhs = try cg.resolveInst(bin_op.lhs);
3011 const rhs = try cg.resolveInst(bin_op.rhs);
3012 const lhs_ty = cg.typeOf(bin_op.lhs);
3013 const rhs_ty = cg.typeOf(bin_op.rhs);
30163014
30173015 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", .{});
30193017 }
30203018
30213019 // 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 {
30263024 const result = switch (op) {
30273025 .shr, .shl => result: {
30283026 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)});
30303028 };
30313029 const rhs_wasm_bits = toWasmBits(@intCast(rhs_ty.bitSize(zcu))).?;
30323030 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)
30343032 else
30353033 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);
30373035 },
3038 else => try func.wrapBinOp(lhs, rhs, lhs_ty, op),
3036 else => try cg.wrapBinOp(lhs, rhs, lhs_ty, op),
30393037 };
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 });
30423040}
30433041
30443042/// Performs a wrapping binary operation.
30453043/// Asserts rhs is not a stack value when lhs also isn't.
30463044/// 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 {
3048 const bin_local = try func.binOp(lhs, rhs, ty, op);
3049 return func.wrapOperand(bin_local, ty);
3045fn wrapBinOp(cg: *CodeGen, lhs: WValue, rhs: WValue, ty: Type, op: Op) InnerError!WValue {
3046 const bin_local = try cg.binOp(lhs, rhs, ty, op);
3047 return cg.wrapOperand(bin_local, ty);
30503048}
30513049
30523050/// Wraps an operand based on a given type's bitsize.
30533051/// Asserts `Type` is <= 128 bits.
30543052/// 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 {
3056 const pt = func.pt;
3053fn wrapOperand(cg: *CodeGen, operand: WValue, ty: Type) InnerError!WValue {
3054 const pt = cg.pt;
30573055 const zcu = pt.zcu;
30583056 assert(ty.abiSize(zcu) <= 16);
30593057 const int_bits: u16 = @intCast(ty.bitSize(zcu)); // TODO use ty.intInfo(zcu).bits
30603058 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});
30623060 };
30633061
30643062 if (wasm_bits == int_bits) return operand;
30653063
30663064 switch (wasm_bits) {
30673065 32 => {
3068 try func.emitWValue(operand);
3066 try cg.emitWValue(operand);
30693067 if (ty.isSignedInt(zcu)) {
3070 try func.addImm32(32 - int_bits);
3071 try func.addTag(.i32_shl);
3072 try func.addImm32(32 - int_bits);
3073 try func.addTag(.i32_shr_s);
3068 try cg.addImm32(32 - int_bits);
3069 try cg.addTag(.i32_shl);
3070 try cg.addImm32(32 - int_bits);
3071 try cg.addTag(.i32_shr_s);
30743072 } else {
3075 try func.addImm32(~@as(u32, 0) >> @intCast(32 - int_bits));
3076 try func.addTag(.i32_and);
3073 try cg.addImm32(~@as(u32, 0) >> @intCast(32 - int_bits));
3074 try cg.addTag(.i32_and);
30773075 }
30783076 return .stack;
30793077 },
30803078 64 => {
3081 try func.emitWValue(operand);
3079 try cg.emitWValue(operand);
30823080 if (ty.isSignedInt(zcu)) {
3083 try func.addImm64(64 - int_bits);
3084 try func.addTag(.i64_shl);
3085 try func.addImm64(64 - int_bits);
3086 try func.addTag(.i64_shr_s);
3081 try cg.addImm64(64 - int_bits);
3082 try cg.addTag(.i64_shl);
3083 try cg.addImm64(64 - int_bits);
3084 try cg.addTag(.i64_shr_s);
30873085 } else {
3088 try func.addImm64(~@as(u64, 0) >> @intCast(64 - int_bits));
3089 try func.addTag(.i64_and);
3086 try cg.addImm64(~@as(u64, 0) >> @intCast(64 - int_bits));
3087 try cg.addTag(.i64_and);
30903088 }
30913089 return .stack;
30923090 },
30933091 128 => {
30943092 assert(operand != .stack);
3095 const result = try func.allocStack(ty);
3093 const result = try cg.allocStack(ty);
30963094
3097 try func.emitWValue(result);
3098 _ = try func.load(operand, Type.u64, 0);
3099 try func.store(.stack, .stack, Type.u64, result.offset());
3095 try cg.emitWValue(result);
3096 _ = try cg.load(operand, Type.u64, 0);
3097 try cg.store(.stack, .stack, Type.u64, result.offset());
31003098
3101 try func.emitWValue(result);
3102 _ = try func.load(operand, Type.u64, 8);
3099 try cg.emitWValue(result);
3100 _ = try cg.load(operand, Type.u64, 8);
31033101 if (ty.isSignedInt(zcu)) {
3104 try func.addImm64(128 - int_bits);
3105 try func.addTag(.i64_shl);
3106 try func.addImm64(128 - int_bits);
3107 try func.addTag(.i64_shr_s);
3102 try cg.addImm64(128 - int_bits);
3103 try cg.addTag(.i64_shl);
3104 try cg.addImm64(128 - int_bits);
3105 try cg.addTag(.i64_shr_s);
31083106 } else {
3109 try func.addImm64(~@as(u64, 0) >> @intCast(128 - int_bits));
3110 try func.addTag(.i64_and);
3107 try cg.addImm64(~@as(u64, 0) >> @intCast(128 - int_bits));
3108 try cg.addTag(.i64_and);
31113109 }
3112 try func.store(.stack, .stack, Type.u64, result.offset() + 8);
3110 try cg.store(.stack, .stack, Type.u64, result.offset() + 8);
31133111
31143112 return result;
31153113 },
......@@ -3117,17 +3115,17 @@ fn wrapOperand(func: *CodeGen, operand: WValue, ty: Type) InnerError!WValue {
31173115 }
31183116}
31193117
3120fn lowerPtr(func: *CodeGen, ptr_val: InternPool.Index, prev_offset: u64) InnerError!WValue {
3121 const pt = func.pt;
3118fn lowerPtr(cg: *CodeGen, ptr_val: InternPool.Index, prev_offset: u64) InnerError!WValue {
3119 const pt = cg.pt;
31223120 const zcu = pt.zcu;
31233121 const ptr = zcu.intern_pool.indexToKey(ptr_val).ptr;
31243122 const offset: u64 = prev_offset + ptr.byte_offset;
31253123 return switch (ptr.base_addr) {
31263124 .nav => |nav| return .{ .nav_ref = .{ .nav_index = zcu.chaseNav(nav), .offset = @intCast(offset) } },
31273125 .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),
3129 .eu_payload => return func.fail("Wasm TODO: lower error union payload pointer", .{}),
3130 .opt_payload => |opt_ptr| return func.lowerPtr(opt_ptr, offset),
3126 .int => return cg.lowerConstant(try pt.intValue(Type.usize, offset), Type.usize),
3127 .eu_payload => return cg.fail("Wasm TODO: lower error union payload pointer", .{}),
3128 .opt_payload => |opt_ptr| return cg.lowerPtr(opt_ptr, offset),
31313129 .field => |field| {
31323130 const base_ptr = Value.fromInterned(field.base);
31333131 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
31363134 assert(base_ty.isSlice(zcu));
31373135 break :off switch (field.index) {
31383136 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),
31403138 else => unreachable,
31413139 };
31423140 },
......@@ -3162,19 +3160,19 @@ fn lowerPtr(func: *CodeGen, ptr_val: InternPool.Index, prev_offset: u64) InnerEr
31623160 },
31633161 else => unreachable,
31643162 };
3165 return func.lowerPtr(field.base, offset + field_off);
3163 return cg.lowerPtr(field.base, offset + field_off);
31663164 },
31673165 .arr_elem, .comptime_field, .comptime_alloc => unreachable,
31683166 };
31693167}
31703168
31713169/// Asserts that `isByRef` returns `false` for `ty`.
3172fn lowerConstant(func: *CodeGen, val: Value, ty: Type) InnerError!WValue {
3173 const pt = func.pt;
3170fn lowerConstant(cg: *CodeGen, val: Value, ty: Type) InnerError!WValue {
3171 const pt = cg.pt;
31743172 const zcu = pt.zcu;
3175 assert(!isByRef(ty, pt, func.target));
3173 assert(!isByRef(ty, pt, cg.target));
31763174 const ip = &zcu.intern_pool;
3177 if (val.isUndefDeep(zcu)) return func.emitUndefined(ty);
3175 if (val.isUndefDeep(zcu)) return cg.emitUndefined(ty);
31783176
31793177 switch (ip.indexToKey(val.ip_index)) {
31803178 .int_type,
......@@ -3253,14 +3251,14 @@ fn lowerConstant(func: *CodeGen, val: Value, ty: Type) InnerError!WValue {
32533251 const payload_type = ty.errorUnionPayload(zcu);
32543252 if (!payload_type.hasRuntimeBitsIgnoreComptime(zcu)) {
32553253 // 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);
32573255 }
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", .{});
32603258 },
32613259 .enum_tag => |enum_tag| {
32623260 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));
32643262 },
32653263 .float => |float| switch (float.storage) {
32663264 .f16 => |f16_val| return .{ .imm32 = @as(u16, @bitCast(f16_val)) },
......@@ -3269,11 +3267,11 @@ fn lowerConstant(func: *CodeGen, val: Value, ty: Type) InnerError!WValue {
32693267 else => unreachable,
32703268 },
32713269 .slice => unreachable, // isByRef == true
3272 .ptr => return func.lowerPtr(val.toIntern(), 0),
3270 .ptr => return cg.lowerPtr(val.toIntern(), 0),
32733271 .opt => if (ty.optionalReprIsPayload(zcu)) {
32743272 const pl_ty = ty.optionalChild(zcu);
32753273 if (val.optionalValue(zcu)) |payload| {
3276 return func.lowerConstant(payload, pl_ty);
3274 return cg.lowerConstant(payload, pl_ty);
32773275 } else {
32783276 return .{ .imm32 = 0 };
32793277 }
......@@ -3281,12 +3279,12 @@ fn lowerConstant(func: *CodeGen, val: Value, ty: Type) InnerError!WValue {
32813279 return .{ .imm32 = @intFromBool(!val.isNull(zcu)) };
32823280 },
32833281 .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)}),
32853283 .vector_type => {
3286 assert(determineSimdStoreStrategy(ty, zcu, func.target) == .direct);
3284 assert(determineSimdStoreStrategy(ty, zcu, cg.target) == .direct);
32873285 var buf: [16]u8 = undefined;
32883286 val.writeToMemory(pt, &buf) catch unreachable;
3289 return func.storeSimdImmd(buf);
3287 return cg.storeSimdImmd(buf);
32903288 },
32913289 .struct_type => {
32923290 const struct_type = ip.loadStructType(ty.toIntern());
......@@ -3300,7 +3298,7 @@ fn lowerConstant(func: *CodeGen, val: Value, ty: Type) InnerError!WValue {
33003298 backing_int_ty,
33013299 mem.readInt(u64, &buf, .little),
33023300 );
3303 return func.lowerConstant(int_val, backing_int_ty);
3301 return cg.lowerConstant(int_val, backing_int_ty);
33043302 },
33053303 else => unreachable,
33063304 },
......@@ -3313,7 +3311,7 @@ fn lowerConstant(func: *CodeGen, val: Value, ty: Type) InnerError!WValue {
33133311 const field_index = zcu.unionTagFieldIndex(union_obj, Value.fromInterned(un.tag)).?;
33143312 break :field_ty Type.fromInterned(union_obj.field_types.get(ip)[field_index]);
33153313 };
3316 return func.lowerConstant(Value.fromInterned(un.val), constant_ty);
3314 return cg.lowerConstant(Value.fromInterned(un.val), constant_ty);
33173315 },
33183316 .memoized_call => unreachable,
33193317 }
......@@ -3321,14 +3319,14 @@ fn lowerConstant(func: *CodeGen, val: Value, ty: Type) InnerError!WValue {
33213319
33223320/// Stores the value as a 128bit-immediate value by storing it inside
33233321/// the list and returning the index into this list as `WValue`.
3324fn storeSimdImmd(func: *CodeGen, value: [16]u8) !WValue {
3325 const index = @as(u32, @intCast(func.simd_immediates.items.len));
3326 try func.simd_immediates.append(func.gpa, value);
3322fn storeSimdImmd(cg: *CodeGen, value: [16]u8) !WValue {
3323 const index = @as(u32, @intCast(cg.simd_immediates.items.len));
3324 try cg.simd_immediates.append(cg.gpa, value);
33273325 return .{ .imm128 = index };
33283326}
33293327
3330fn emitUndefined(func: *CodeGen, ty: Type) InnerError!WValue {
3331 const pt = func.pt;
3328fn emitUndefined(cg: *CodeGen, ty: Type) InnerError!WValue {
3329 const pt = cg.pt;
33323330 const zcu = pt.zcu;
33333331 const ip = &zcu.intern_pool;
33343332 switch (ty.zigTypeTag(zcu)) {
......@@ -3338,20 +3336,20 @@ fn emitUndefined(func: *CodeGen, ty: Type) InnerError!WValue {
33383336 33...64 => return .{ .imm64 = 0xaaaaaaaaaaaaaaaa },
33393337 else => unreachable,
33403338 },
3341 .float => switch (ty.floatBits(func.target.*)) {
3339 .float => switch (ty.floatBits(cg.target.*)) {
33423340 16 => return .{ .imm32 = 0xaaaaaaaa },
33433341 32 => return .{ .float32 = @as(f32, @bitCast(@as(u32, 0xaaaaaaaa))) },
33443342 64 => return .{ .float64 = @as(f64, @bitCast(@as(u64, 0xaaaaaaaaaaaaaaaa))) },
33453343 else => unreachable,
33463344 },
3347 .pointer => switch (func.ptr_size) {
3345 .pointer => switch (cg.ptr_size) {
33483346 .wasm32 => return .{ .imm32 = 0xaaaaaaaa },
33493347 .wasm64 => return .{ .imm64 = 0xaaaaaaaaaaaaaaaa },
33503348 },
33513349 .optional => {
33523350 const pl_ty = ty.optionalChild(zcu);
33533351 if (ty.optionalReprIsPayload(zcu)) {
3354 return func.emitUndefined(pl_ty);
3352 return cg.emitUndefined(pl_ty);
33553353 }
33563354 return .{ .imm32 = 0xaaaaaaaa };
33573355 },
......@@ -3360,17 +3358,17 @@ fn emitUndefined(func: *CodeGen, ty: Type) InnerError!WValue {
33603358 },
33613359 .@"struct" => {
33623360 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)));
33643362 },
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)}),
33663364 }
33673365}
33683366
33693367/// Returns a `Value` as a signed 32 bit value.
33703368/// It's illegal to provide a value with a type that cannot be represented
33713369/// as an integer value.
3372fn valueAsI32(func: *const CodeGen, val: Value) i32 {
3373 const pt = func.pt;
3370fn valueAsI32(cg: *const CodeGen, val: Value) i32 {
3371 const pt = cg.pt;
33743372 const zcu = pt.zcu;
33753373 const ip = &zcu.intern_pool;
33763374
......@@ -3405,132 +3403,132 @@ fn intStorageAsI32(storage: InternPool.Key.Int.Storage, pt: Zcu.PerThread) i32 {
34053403 };
34063404}
34073405
3408fn airBlock(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
3409 const ty_pl = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
3410 const extra = func.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]));
3406fn airBlock(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
3407 const ty_pl = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
3408 const extra = cg.air.extraData(Air.Block, ty_pl.payload);
3409 try cg.lowerBlock(inst, ty_pl.ty.toType(), @ptrCast(cg.air.extra[extra.end..][0..extra.data.body_len]));
34123410}
34133411
3414fn lowerBlock(func: *CodeGen, inst: Air.Inst.Index, block_ty: Type, body: []const Air.Inst.Index) InnerError!void {
3415 const pt = func.pt;
3416 const wasm_block_ty = genBlockType(block_ty, pt, func.target);
3412fn lowerBlock(cg: *CodeGen, inst: Air.Inst.Index, block_ty: Type, body: []const Air.Inst.Index) InnerError!void {
3413 const pt = cg.pt;
3414 const wasm_block_ty = genBlockType(block_ty, pt, cg.target);
34173415
34183416 // if wasm_block_ty is non-empty, we create a register to store the temporary value
34193417 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;
3421 break :blk try func.ensureAllocLocal(ty); // make sure it's a clean local as it may never get overwritten
3418 const ty: Type = if (isByRef(block_ty, pt, cg.target)) Type.u32 else block_ty;
3419 break :blk try cg.ensureAllocLocal(ty); // make sure it's a clean local as it may never get overwritten
34223420 } else .none;
34233421
3424 try func.startBlock(.block, std.wasm.block_empty);
3422 try cg.startBlock(.block, std.wasm.block_empty);
34253423 // Here we set the current block idx, so breaks know the depth to jump
34263424 // to when breaking out.
3427 try func.blocks.putNoClobber(func.gpa, inst, .{
3428 .label = func.block_depth,
3425 try cg.blocks.putNoClobber(cg.gpa, inst, .{
3426 .label = cg.block_depth,
34293427 .value = block_result,
34303428 });
34313429
3432 try func.genBody(body);
3433 try func.endBlock();
3430 try cg.genBody(body);
3431 try cg.endBlock();
34343432
3435 const liveness = func.liveness.getBlock(inst);
3436 try func.currentBranch().values.ensureUnusedCapacity(func.gpa, liveness.deaths.len);
3433 const liveness = cg.liveness.getBlock(inst);
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, &.{});
34393437}
34403438
34413439/// 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 {
3443 func.block_depth += 1;
3444 try func.addInst(.{
3440fn startBlock(cg: *CodeGen, block_tag: std.wasm.Opcode, valtype: u8) !void {
3441 cg.block_depth += 1;
3442 try cg.addInst(.{
34453443 .tag = Mir.Inst.Tag.fromOpcode(block_tag),
34463444 .data = .{ .block_type = valtype },
34473445 });
34483446}
34493447
34503448/// Ends the current wasm block and decreases the `block_depth` by 1
3451fn endBlock(func: *CodeGen) !void {
3452 try func.addTag(.end);
3453 func.block_depth -= 1;
3449fn endBlock(cg: *CodeGen) !void {
3450 try cg.addTag(.end);
3451 cg.block_depth -= 1;
34543452}
34553453
3456fn airLoop(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
3457 const ty_pl = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
3458 const loop = func.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]);
3454fn airLoop(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
3455 const ty_pl = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
3456 const loop = cg.air.extraData(Air.Block, ty_pl.payload);
3457 const body: []const Air.Inst.Index = @ptrCast(cg.air.extra[loop.end..][0..loop.data.body_len]);
34603458
34613459 // result type of loop is always 'noreturn', meaning we can always
34623460 // 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);
3466 defer assert(func.loops.remove(inst));
3463 try cg.loops.putNoClobber(cg.gpa, inst, cg.block_depth);
3464 defer assert(cg.loops.remove(inst));
34673465
3468 try func.genBody(body);
3469 try func.endBlock();
3466 try cg.genBody(body);
3467 try cg.endBlock();
34703468
3471 return func.finishAir(inst, .none, &.{});
3469 return cg.finishAir(inst, .none, &.{});
34723470}
34733471
3474fn airCondBr(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
3475 const pl_op = func.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;
3476 const condition = try func.resolveInst(pl_op.operand);
3477 const extra = func.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]);
3479 const else_body: []const Air.Inst.Index = @ptrCast(func.air.extra[extra.end + then_body.len ..][0..extra.data.else_body_len]);
3480 const liveness_condbr = func.liveness.getCondBr(inst);
3472fn airCondBr(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
3473 const pl_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;
3474 const condition = try cg.resolveInst(pl_op.operand);
3475 const extra = cg.air.extraData(Air.CondBr, pl_op.payload);
3476 const then_body: []const Air.Inst.Index = @ptrCast(cg.air.extra[extra.end..][0..extra.data.then_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]);
3478 const liveness_condbr = cg.liveness.getCondBr(inst);
34813479
34823480 // 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);
34843482 // emit the conditional value
3485 try func.emitWValue(condition);
3483 try cg.emitWValue(condition);
34863484
34873485 // we inserted the block in front of the condition
34883486 // so now check if condition matches. If not, break outside this block
34893487 // 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);
34933491 {
3494 func.branches.appendAssumeCapacity(.{});
3495 try func.currentBranch().values.ensureUnusedCapacity(func.gpa, @as(u32, @intCast(liveness_condbr.else_deaths.len)));
3492 cg.branches.appendAssumeCapacity(.{});
3493 try cg.currentBranch().values.ensureUnusedCapacity(cg.gpa, @as(u32, @intCast(liveness_condbr.else_deaths.len)));
34963494 defer {
3497 var else_stack = func.branches.pop();
3498 else_stack.deinit(func.gpa);
3495 var else_stack = cg.branches.pop();
3496 else_stack.deinit(cg.gpa);
34993497 }
3500 try func.genBody(else_body);
3501 try func.endBlock();
3498 try cg.genBody(else_body);
3499 try cg.endBlock();
35023500 }
35033501
35043502 // Outer block that matches the condition
35053503 {
3506 func.branches.appendAssumeCapacity(.{});
3507 try func.currentBranch().values.ensureUnusedCapacity(func.gpa, @as(u32, @intCast(liveness_condbr.then_deaths.len)));
3504 cg.branches.appendAssumeCapacity(.{});
3505 try cg.currentBranch().values.ensureUnusedCapacity(cg.gpa, @as(u32, @intCast(liveness_condbr.then_deaths.len)));
35083506 defer {
3509 var then_stack = func.branches.pop();
3510 then_stack.deinit(func.gpa);
3507 var then_stack = cg.branches.pop();
3508 then_stack.deinit(cg.gpa);
35113509 }
3512 try func.genBody(then_body);
3510 try cg.genBody(then_body);
35133511 }
35143512
3515 return func.finishAir(inst, .none, &.{});
3513 return cg.finishAir(inst, .none, &.{});
35163514}
35173515
3518fn airCmp(func: *CodeGen, inst: Air.Inst.Index, op: std.math.CompareOperator) InnerError!void {
3519 const bin_op = func.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
3516fn airCmp(cg: *CodeGen, inst: Air.Inst.Index, op: std.math.CompareOperator) InnerError!void {
3517 const bin_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
35203518
3521 const lhs = try func.resolveInst(bin_op.lhs);
3522 const rhs = try func.resolveInst(bin_op.rhs);
3523 const operand_ty = func.typeOf(bin_op.lhs);
3524 const result = try func.cmp(lhs, rhs, operand_ty, op);
3525 return func.finishAir(inst, result, &.{ bin_op.lhs, bin_op.rhs });
3519 const lhs = try cg.resolveInst(bin_op.lhs);
3520 const rhs = try cg.resolveInst(bin_op.rhs);
3521 const operand_ty = cg.typeOf(bin_op.lhs);
3522 const result = try cg.cmp(lhs, rhs, operand_ty, op);
3523 return cg.finishAir(inst, result, &.{ bin_op.lhs, bin_op.rhs });
35263524}
35273525
35283526/// Compares two operands.
35293527/// Asserts rhs is not a stack value when the lhs isn't a stack value either
35303528/// 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 {
35323530 assert(!(lhs != .stack and rhs == .stack));
3533 const pt = func.pt;
3531 const pt = cg.pt;
35343532 const zcu = pt.zcu;
35353533 if (ty.zigTypeTag(zcu) == .optional and !ty.optionalReprIsPayload(zcu)) {
35363534 const payload_ty = ty.optionalChild(zcu);
......@@ -3538,12 +3536,12 @@ fn cmp(func: *CodeGen, lhs: WValue, rhs: WValue, ty: Type, op: std.math.CompareO
35383536 // When we hit this case, we must check the value of optionals
35393537 // that are not pointers. This means first checking against non-null for
35403538 // 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);
35423540 }
35433541 } else if (ty.isAnyFloat()) {
3544 return func.cmpFloat(ty, lhs, rhs, op);
3545 } else if (isByRef(ty, pt, func.target)) {
3546 return func.cmpBigInt(lhs, rhs, ty, op);
3542 return cg.cmpFloat(ty, lhs, rhs, op);
3543 } else if (isByRef(ty, pt, cg.target)) {
3544 return cg.cmpBigInt(lhs, rhs, ty, op);
35473545 }
35483546
35493547 const signedness: std.builtin.Signedness = blk: {
......@@ -3556,11 +3554,11 @@ fn cmp(func: *CodeGen, lhs: WValue, rhs: WValue, ty: Type, op: std.math.CompareO
35563554
35573555 // ensure that when we compare pointers, we emit
35583556 // the true pointer of a stack value, rather than the stack pointer.
3559 try func.lowerToStack(lhs);
3560 try func.lowerToStack(rhs);
3557 try cg.lowerToStack(lhs);
3558 try cg.lowerToStack(rhs);
35613559
35623560 const opcode: std.wasm.Opcode = buildOpcode(.{
3563 .valtype1 = typeToValtype(ty, pt, func.target),
3561 .valtype1 = typeToValtype(ty, pt, cg.target),
35643562 .op = switch (op) {
35653563 .lt => .lt,
35663564 .lte => .le,
......@@ -3571,15 +3569,15 @@ fn cmp(func: *CodeGen, lhs: WValue, rhs: WValue, ty: Type, op: std.math.CompareO
35713569 },
35723570 .signedness = signedness,
35733571 });
3574 try func.addTag(Mir.Inst.Tag.fromOpcode(opcode));
3572 try cg.addTag(Mir.Inst.Tag.fromOpcode(opcode));
35753573
35763574 return .stack;
35773575}
35783576
35793577/// Compares two floats.
35803578/// 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 {
3582 const float_bits = ty.floatBits(func.target.*);
3579fn cmpFloat(cg: *CodeGen, ty: Type, lhs: WValue, rhs: WValue, cmp_op: std.math.CompareOperator) InnerError!WValue {
3580 const float_bits = ty.floatBits(cg.target.*);
35833581
35843582 const op: Op = switch (cmp_op) {
35853583 .lt => .lt,
......@@ -3592,18 +3590,18 @@ fn cmpFloat(func: *CodeGen, ty: Type, lhs: WValue, rhs: WValue, cmp_op: std.math
35923590
35933591 switch (float_bits) {
35943592 16 => {
3595 _ = try func.fpext(lhs, Type.f16, Type.f32);
3596 _ = try func.fpext(rhs, Type.f16, Type.f32);
3593 _ = try cg.fpext(lhs, Type.f16, Type.f32);
3594 _ = try cg.fpext(rhs, Type.f16, Type.f32);
35973595 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));
35993597 return .stack;
36003598 },
36013599 32, 64 => {
3602 try func.emitWValue(lhs);
3603 try func.emitWValue(rhs);
3600 try cg.emitWValue(lhs);
3601 try cg.emitWValue(rhs);
36043602 const val_type: std.wasm.Valtype = if (float_bits == 32) .f32 else .f64;
36053603 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));
36073605 return .stack;
36083606 },
36093607 80, 128 => {
......@@ -3612,121 +3610,121 @@ fn cmpFloat(func: *CodeGen, ty: Type, lhs: WValue, rhs: WValue, cmp_op: std.math
36123610 @tagName(op), target_util.compilerRtFloatAbbrev(float_bits),
36133611 }) catch unreachable;
36143612
3615 const result = try func.callIntrinsic(fn_name, &.{ ty.ip_index, ty.ip_index }, Type.bool, &.{ lhs, rhs });
3616 return func.cmp(result, .{ .imm32 = 0 }, Type.i32, cmp_op);
3613 const result = try cg.callIntrinsic(fn_name, &.{ ty.ip_index, ty.ip_index }, Type.bool, &.{ lhs, rhs });
3614 return cg.cmp(result, .{ .imm32 = 0 }, Type.i32, cmp_op);
36173615 },
36183616 else => unreachable,
36193617 }
36203618}
36213619
3622fn airCmpVector(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
3620fn airCmpVector(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
36233621 _ = inst;
3624 return func.fail("TODO implement airCmpVector for wasm", .{});
3622 return cg.fail("TODO implement airCmpVector for wasm", .{});
36253623}
36263624
3627fn airCmpLtErrorsLen(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
3628 const un_op = func.air.instructions.items(.data)[@intFromEnum(inst)].un_op;
3629 const operand = try func.resolveInst(un_op);
3625fn airCmpLtErrorsLen(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
3626 const un_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].un_op;
3627 const operand = try cg.resolveInst(un_op);
36303628
3631 try func.emitWValue(operand);
3632 const pt = func.pt;
3629 try cg.emitWValue(operand);
3630 const pt = cg.pt;
36333631 const err_int_ty = try pt.errorIntType();
3634 try func.addTag(.errors_len);
3635 const result = try func.cmp(.stack, .stack, err_int_ty, .lt);
3632 try cg.addTag(.errors_len);
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});
36383636}
36393637
3640fn airBr(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
3641 const zcu = func.pt.zcu;
3642 const br = func.air.instructions.items(.data)[@intFromEnum(inst)].br;
3643 const block = func.blocks.get(br.block_inst).?;
3638fn airBr(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
3639 const zcu = cg.pt.zcu;
3640 const br = cg.air.instructions.items(.data)[@intFromEnum(inst)].br;
3641 const block = cg.blocks.get(br.block_inst).?;
36443642
36453643 // if operand has codegen bits we should break with a value
3646 if (func.typeOf(br.operand).hasRuntimeBitsIgnoreComptime(zcu)) {
3647 const operand = try func.resolveInst(br.operand);
3648 try func.lowerToStack(operand);
3644 if (cg.typeOf(br.operand).hasRuntimeBitsIgnoreComptime(zcu)) {
3645 const operand = try cg.resolveInst(br.operand);
3646 try cg.lowerToStack(operand);
36493647
36503648 if (block.value != .none) {
3651 try func.addLabel(.local_set, block.value.local.value);
3649 try cg.addLabel(.local_set, block.value.local.value);
36523650 }
36533651 }
36543652
36553653 // We map every block to its block index.
36563654 // 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;
3658 try func.addLabel(.br, idx);
3655 const idx: u32 = cg.block_depth - block.label;
3656 try cg.addLabel(.br, idx);
36593657
3660 return func.finishAir(inst, .none, &.{br.operand});
3658 return cg.finishAir(inst, .none, &.{br.operand});
36613659}
36623660
3663fn airRepeat(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
3664 const repeat = func.air.instructions.items(.data)[@intFromEnum(inst)].repeat;
3665 const loop_label = func.loops.get(repeat.loop_inst).?;
3661fn airRepeat(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
3662 const repeat = cg.air.instructions.items(.data)[@intFromEnum(inst)].repeat;
3663 const loop_label = cg.loops.get(repeat.loop_inst).?;
36663664
3667 const idx: u32 = func.block_depth - loop_label;
3668 try func.addLabel(.br, idx);
3665 const idx: u32 = cg.block_depth - loop_label;
3666 try cg.addLabel(.br, idx);
36693667
3670 return func.finishAir(inst, .none, &.{});
3668 return cg.finishAir(inst, .none, &.{});
36713669}
36723670
3673fn airNot(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
3674 const ty_op = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
3671fn airNot(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
3672 const ty_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
36753673
3676 const operand = try func.resolveInst(ty_op.operand);
3677 const operand_ty = func.typeOf(ty_op.operand);
3678 const pt = func.pt;
3674 const operand = try cg.resolveInst(ty_op.operand);
3675 const operand_ty = cg.typeOf(ty_op.operand);
3676 const pt = cg.pt;
36793677 const zcu = pt.zcu;
36803678
36813679 const result = result: {
36823680 if (operand_ty.zigTypeTag(zcu) == .bool) {
3683 try func.emitWValue(operand);
3684 try func.addTag(.i32_eqz);
3685 const not_tmp = try func.allocLocal(operand_ty);
3686 try func.addLabel(.local_set, not_tmp.local.value);
3681 try cg.emitWValue(operand);
3682 try cg.addTag(.i32_eqz);
3683 const not_tmp = try cg.allocLocal(operand_ty);
3684 try cg.addLabel(.local_set, not_tmp.local.value);
36873685 break :result not_tmp;
36883686 } else {
36893687 const int_info = operand_ty.intInfo(zcu);
36903688 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)});
36923690 };
36933691
36943692 switch (wasm_bits) {
36953693 32 => {
3696 try func.emitWValue(operand);
3697 try func.addImm32(switch (int_info.signedness) {
3694 try cg.emitWValue(operand);
3695 try cg.addImm32(switch (int_info.signedness) {
36983696 .unsigned => ~@as(u32, 0) >> @intCast(32 - int_info.bits),
36993697 .signed => ~@as(u32, 0),
37003698 });
3701 try func.addTag(.i32_xor);
3699 try cg.addTag(.i32_xor);
37023700 break :result .stack;
37033701 },
37043702 64 => {
3705 try func.emitWValue(operand);
3706 try func.addImm64(switch (int_info.signedness) {
3703 try cg.emitWValue(operand);
3704 try cg.addImm64(switch (int_info.signedness) {
37073705 .unsigned => ~@as(u64, 0) >> @intCast(64 - int_info.bits),
37083706 .signed => ~@as(u64, 0),
37093707 });
3710 try func.addTag(.i64_xor);
3708 try cg.addTag(.i64_xor);
37113709 break :result .stack;
37123710 },
37133711 128 => {
3714 const ptr = try func.allocStack(operand_ty);
3712 const ptr = try cg.allocStack(operand_ty);
37153713
3716 try func.emitWValue(ptr);
3717 _ = try func.load(operand, Type.u64, 0);
3718 try func.addImm64(~@as(u64, 0));
3719 try func.addTag(.i64_xor);
3720 try func.store(.stack, .stack, Type.u64, ptr.offset());
3714 try cg.emitWValue(ptr);
3715 _ = try cg.load(operand, Type.u64, 0);
3716 try cg.addImm64(~@as(u64, 0));
3717 try cg.addTag(.i64_xor);
3718 try cg.store(.stack, .stack, Type.u64, ptr.offset());
37213719
3722 try func.emitWValue(ptr);
3723 _ = try func.load(operand, Type.u64, 8);
3724 try func.addImm64(switch (int_info.signedness) {
3720 try cg.emitWValue(ptr);
3721 _ = try cg.load(operand, Type.u64, 8);
3722 try cg.addImm64(switch (int_info.signedness) {
37253723 .unsigned => ~@as(u64, 0) >> @intCast(128 - int_info.bits),
37263724 .signed => ~@as(u64, 0),
37273725 });
3728 try func.addTag(.i64_xor);
3729 try func.store(.stack, .stack, Type.u64, ptr.offset() + 8);
3726 try cg.addTag(.i64_xor);
3727 try cg.store(.stack, .stack, Type.u64, ptr.offset() + 8);
37303728
37313729 break :result ptr;
37323730 },
......@@ -3734,33 +3732,33 @@ fn airNot(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
37343732 }
37353733 }
37363734 };
3737 return func.finishAir(inst, result, &.{ty_op.operand});
3735 return cg.finishAir(inst, result, &.{ty_op.operand});
37383736}
37393737
3740fn airTrap(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
3741 try func.addTag(.@"unreachable");
3742 return func.finishAir(inst, .none, &.{});
3738fn airTrap(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
3739 try cg.addTag(.@"unreachable");
3740 return cg.finishAir(inst, .none, &.{});
37433741}
37443742
3745fn airBreakpoint(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
3743fn airBreakpoint(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
37463744 // unsupported by wasm itfunc. Can be implemented once we support DWARF
37473745 // for wasm
3748 try func.addTag(.@"unreachable");
3749 return func.finishAir(inst, .none, &.{});
3746 try cg.addTag(.@"unreachable");
3747 return cg.finishAir(inst, .none, &.{});
37503748}
37513749
3752fn airUnreachable(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
3753 try func.addTag(.@"unreachable");
3754 return func.finishAir(inst, .none, &.{});
3750fn airUnreachable(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
3751 try cg.addTag(.@"unreachable");
3752 return cg.finishAir(inst, .none, &.{});
37553753}
37563754
3757fn airBitcast(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
3758 const pt = func.pt;
3755fn airBitcast(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
3756 const pt = cg.pt;
37593757 const zcu = pt.zcu;
3760 const ty_op = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
3761 const operand = try func.resolveInst(ty_op.operand);
3762 const wanted_ty = func.typeOfIndex(inst);
3763 const given_ty = func.typeOf(ty_op.operand);
3758 const ty_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
3759 const operand = try cg.resolveInst(ty_op.operand);
3760 const wanted_ty = cg.typeOfIndex(inst);
3761 const given_ty = cg.typeOf(ty_op.operand);
37643762
37653763 const bit_size = given_ty.bitSize(zcu);
37663764 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 {
37683766
37693767 const result = result: {
37703768 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);
37723770 }
37733771
3774 if (isByRef(given_ty, pt, func.target) and !isByRef(wanted_ty, pt, func.target)) {
3775 const loaded_memory = try func.load(operand, wanted_ty, 0);
3772 if (isByRef(given_ty, pt, cg.target) and !isByRef(wanted_ty, pt, cg.target)) {
3773 const loaded_memory = try cg.load(operand, wanted_ty, 0);
37763774 if (needs_wrapping) {
3777 break :result try func.wrapOperand(loaded_memory, wanted_ty);
3775 break :result try cg.wrapOperand(loaded_memory, wanted_ty);
37783776 } else {
37793777 break :result loaded_memory;
37803778 }
37813779 }
3782 if (!isByRef(given_ty, pt, func.target) and isByRef(wanted_ty, pt, func.target)) {
3783 const stack_memory = try func.allocStack(wanted_ty);
3784 try func.store(stack_memory, operand, given_ty, 0);
3780 if (!isByRef(given_ty, pt, cg.target) and isByRef(wanted_ty, pt, cg.target)) {
3781 const stack_memory = try cg.allocStack(wanted_ty);
3782 try cg.store(stack_memory, operand, given_ty, 0);
37853783 if (needs_wrapping) {
3786 break :result try func.wrapOperand(stack_memory, wanted_ty);
3784 break :result try cg.wrapOperand(stack_memory, wanted_ty);
37873785 } else {
37883786 break :result stack_memory;
37893787 }
37903788 }
37913789
37923790 if (needs_wrapping) {
3793 break :result try func.wrapOperand(operand, wanted_ty);
3791 break :result try cg.wrapOperand(operand, wanted_ty);
37943792 }
37953793
3796 break :result func.reuseOperand(ty_op.operand, operand);
3794 break :result cg.reuseOperand(ty_op.operand, operand);
37973795 };
3798 return func.finishAir(inst, result, &.{ty_op.operand});
3796 return cg.finishAir(inst, result, &.{ty_op.operand});
37993797}
38003798
3801fn bitcast(func: *CodeGen, wanted_ty: Type, given_ty: Type, operand: WValue) InnerError!WValue {
3802 const pt = func.pt;
3799fn bitcast(cg: *CodeGen, wanted_ty: Type, given_ty: Type, operand: WValue) InnerError!WValue {
3800 const pt = cg.pt;
38033801 const zcu = pt.zcu;
38043802 // if we bitcast a float to or from an integer we must use the 'reinterpret' instruction
38053803 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
38093807
38103808 const opcode = buildOpcode(.{
38113809 .op = .reinterpret,
3812 .valtype1 = typeToValtype(wanted_ty, pt, func.target),
3813 .valtype2 = typeToValtype(given_ty, pt, func.target),
3810 .valtype1 = typeToValtype(wanted_ty, pt, cg.target),
3811 .valtype2 = typeToValtype(given_ty, pt, cg.target),
38143812 });
3815 try func.emitWValue(operand);
3816 try func.addTag(Mir.Inst.Tag.fromOpcode(opcode));
3813 try cg.emitWValue(operand);
3814 try cg.addTag(Mir.Inst.Tag.fromOpcode(opcode));
38173815 return .stack;
38183816}
38193817
3820fn airStructFieldPtr(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
3821 const pt = func.pt;
3818fn airStructFieldPtr(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
3819 const pt = cg.pt;
38223820 const zcu = pt.zcu;
3823 const ty_pl = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
3824 const extra = func.air.extraData(Air.StructField, ty_pl.payload);
3821 const ty_pl = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
3822 const extra = cg.air.extraData(Air.StructField, ty_pl.payload);
38253823
3826 const struct_ptr = try func.resolveInst(extra.data.struct_operand);
3827 const struct_ptr_ty = func.typeOf(extra.data.struct_operand);
3824 const struct_ptr = try cg.resolveInst(extra.data.struct_operand);
3825 const struct_ptr_ty = cg.typeOf(extra.data.struct_operand);
38283826 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);
3830 return func.finishAir(inst, result, &.{extra.data.struct_operand});
3827 const result = try cg.structFieldPtr(inst, extra.data.struct_operand, struct_ptr, struct_ptr_ty, struct_ty, extra.data.field_index);
3828 return cg.finishAir(inst, result, &.{extra.data.struct_operand});
38313829}
38323830
3833fn airStructFieldPtrIndex(func: *CodeGen, inst: Air.Inst.Index, index: u32) InnerError!void {
3834 const pt = func.pt;
3831fn airStructFieldPtrIndex(cg: *CodeGen, inst: Air.Inst.Index, index: u32) InnerError!void {
3832 const pt = cg.pt;
38353833 const zcu = pt.zcu;
3836 const ty_op = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
3837 const struct_ptr = try func.resolveInst(ty_op.operand);
3838 const struct_ptr_ty = func.typeOf(ty_op.operand);
3834 const ty_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
3835 const struct_ptr = try cg.resolveInst(ty_op.operand);
3836 const struct_ptr_ty = cg.typeOf(ty_op.operand);
38393837 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);
3842 return func.finishAir(inst, result, &.{ty_op.operand});
3839 const result = try cg.structFieldPtr(inst, ty_op.operand, struct_ptr, struct_ptr_ty, struct_ty, index);
3840 return cg.finishAir(inst, result, &.{ty_op.operand});
38433841}
38443842
38453843fn structFieldPtr(
3846 func: *CodeGen,
3844 cg: *CodeGen,
38473845 inst: Air.Inst.Index,
38483846 ref: Air.Inst.Ref,
38493847 struct_ptr: WValue,
......@@ -3851,9 +3849,9 @@ fn structFieldPtr(
38513849 struct_ty: Type,
38523850 index: u32,
38533851) InnerError!WValue {
3854 const pt = func.pt;
3852 const pt = cg.pt;
38553853 const zcu = pt.zcu;
3856 const result_ty = func.typeOfIndex(inst);
3854 const result_ty = cg.typeOfIndex(inst);
38573855 const struct_ptr_ty_info = struct_ptr_ty.ptrInfo(zcu);
38583856
38593857 const offset = switch (struct_ty.containerLayout(zcu)) {
......@@ -3872,28 +3870,28 @@ fn structFieldPtr(
38723870 };
38733871 // save a load and store when we can simply reuse the operand
38743872 if (offset == 0) {
3875 return func.reuseOperand(ref, struct_ptr);
3873 return cg.reuseOperand(ref, struct_ptr);
38763874 }
38773875 switch (struct_ptr) {
38783876 .stack_offset => |stack_offset| {
38793877 return .{ .stack_offset = .{ .value = stack_offset.value + @as(u32, @intCast(offset)), .references = 1 } };
38803878 },
3881 else => return func.buildPointerOffset(struct_ptr, offset, .new),
3879 else => return cg.buildPointerOffset(struct_ptr, offset, .new),
38823880 }
38833881}
38843882
3885fn airStructFieldVal(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
3886 const pt = func.pt;
3883fn airStructFieldVal(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
3884 const pt = cg.pt;
38873885 const zcu = pt.zcu;
38883886 const ip = &zcu.intern_pool;
3889 const ty_pl = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
3890 const struct_field = func.air.extraData(Air.StructField, ty_pl.payload).data;
3887 const ty_pl = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
3888 const struct_field = cg.air.extraData(Air.StructField, ty_pl.payload).data;
38913889
3892 const struct_ty = func.typeOf(struct_field.struct_operand);
3893 const operand = try func.resolveInst(struct_field.struct_operand);
3890 const struct_ty = cg.typeOf(struct_field.struct_operand);
3891 const operand = try cg.resolveInst(struct_field.struct_operand);
38943892 const field_index = struct_field.field_index;
38953893 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
38983896 const result: WValue = switch (struct_ty.containerLayout(zcu)) {
38993897 .@"packed" => switch (struct_ty.zigTypeTag(zcu)) {
......@@ -3902,42 +3900,42 @@ fn airStructFieldVal(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
39023900 const offset = pt.structPackedFieldBitOffset(packed_struct, field_index);
39033901 const backing_ty = Type.fromInterned(packed_struct.backingIntTypeUnordered(ip));
39043902 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", .{});
39063904 };
39073905 const const_wvalue: WValue = if (wasm_bits == 32)
39083906 .{ .imm32 = offset }
39093907 else if (wasm_bits == 64)
39103908 .{ .imm64 = offset }
39113909 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
39143912 // for first field we don't require any shifting
39153913 const shifted_value = if (offset == 0)
39163914 operand
39173915 else
3918 try func.binOp(operand, const_wvalue, backing_ty, .shr);
3916 try cg.binOp(operand, const_wvalue, backing_ty, .shr);
39193917
39203918 if (field_ty.zigTypeTag(zcu) == .float) {
39213919 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);
3923 break :result try func.bitcast(field_ty, int_type, truncated);
3920 const truncated = try cg.trunc(shifted_value, int_type, backing_ty);
3921 break :result try cg.bitcast(field_ty, int_type, truncated);
39243922 } else if (field_ty.isPtrAtRuntime(zcu) and packed_struct.field_types.len == 1) {
39253923 // In this case we do not have to perform any transformations,
39263924 // 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);
39283926 } else if (field_ty.isPtrAtRuntime(zcu)) {
39293927 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);
39313929 }
3932 break :result try func.trunc(shifted_value, field_ty, backing_ty);
3930 break :result try cg.trunc(shifted_value, field_ty, backing_ty);
39333931 },
39343932 .@"union" => result: {
3935 if (isByRef(struct_ty, pt, func.target)) {
3936 if (!isByRef(field_ty, pt, func.target)) {
3937 break :result try func.load(operand, field_ty, 0);
3933 if (isByRef(struct_ty, pt, cg.target)) {
3934 if (!isByRef(field_ty, pt, cg.target)) {
3935 break :result try cg.load(operand, field_ty, 0);
39383936 } else {
3939 const new_stack_val = try func.allocStack(field_ty);
3940 try func.store(new_stack_val, operand, field_ty, 0);
3937 const new_stack_val = try cg.allocStack(field_ty);
3938 try cg.store(new_stack_val, operand, field_ty, 0);
39413939 break :result new_stack_val;
39423940 }
39433941 }
......@@ -3945,45 +3943,45 @@ fn airStructFieldVal(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
39453943 const union_int_type = try pt.intType(.unsigned, @as(u16, @intCast(struct_ty.bitSize(zcu))));
39463944 if (field_ty.zigTypeTag(zcu) == .float) {
39473945 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);
3949 break :result try func.bitcast(field_ty, int_type, truncated);
3946 const truncated = try cg.trunc(operand, int_type, union_int_type);
3947 break :result try cg.bitcast(field_ty, int_type, truncated);
39503948 } else if (field_ty.isPtrAtRuntime(zcu)) {
39513949 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);
39533951 }
3954 break :result try func.trunc(operand, field_ty, union_int_type);
3952 break :result try cg.trunc(operand, field_ty, union_int_type);
39553953 },
39563954 else => unreachable,
39573955 },
39583956 else => result: {
39593957 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)});
39613959 };
3962 if (isByRef(field_ty, pt, func.target)) {
3960 if (isByRef(field_ty, pt, cg.target)) {
39633961 switch (operand) {
39643962 .stack_offset => |stack_offset| {
39653963 break :result .{ .stack_offset = .{ .value = stack_offset.value + offset, .references = 1 } };
39663964 },
3967 else => break :result try func.buildPointerOffset(operand, offset, .new),
3965 else => break :result try cg.buildPointerOffset(operand, offset, .new),
39683966 }
39693967 }
3970 break :result try func.load(operand, field_ty, offset);
3968 break :result try cg.load(operand, field_ty, offset);
39713969 },
39723970 };
39733971
3974 return func.finishAir(inst, result, &.{struct_field.struct_operand});
3972 return cg.finishAir(inst, result, &.{struct_field.struct_operand});
39753973}
39763974
3977fn airSwitchBr(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
3978 const pt = func.pt;
3975fn airSwitchBr(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
3976 const pt = cg.pt;
39793977 const zcu = pt.zcu;
39803978 // result type is always 'noreturn'
39813979 const blocktype = std.wasm.block_empty;
3982 const switch_br = func.air.unwrapSwitch(inst);
3983 const target = try func.resolveInst(switch_br.operand);
3984 const target_ty = func.typeOf(switch_br.operand);
3985 const liveness = try func.liveness.getSwitchBr(func.gpa, inst, switch_br.cases_len + 1);
3986 defer func.gpa.free(liveness.deaths);
3980 const switch_br = cg.air.unwrapSwitch(inst);
3981 const target = try cg.resolveInst(switch_br.operand);
3982 const target_ty = cg.typeOf(switch_br.operand);
3983 const liveness = try cg.liveness.getSwitchBr(cg.gpa, inst, switch_br.cases_len + 1);
3984 defer cg.gpa.free(liveness.deaths);
39873985
39883986 // a list that maps each value with its value and body based on the order inside the list.
39893987 const CaseValue = union(enum) {
......@@ -3993,21 +3991,21 @@ fn airSwitchBr(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
39933991 var case_list = try std.ArrayList(struct {
39943992 values: []const CaseValue,
39953993 body: []const Air.Inst.Index,
3996 }).initCapacity(func.gpa, switch_br.cases_len);
3994 }).initCapacity(cg.gpa, switch_br.cases_len);
39973995 defer for (case_list.items) |case| {
3998 func.gpa.free(case.values);
3996 cg.gpa.free(case.values);
39993997 } else case_list.deinit();
40003998
40013999 var lowest_maybe: ?i32 = null;
40024000 var highest_maybe: ?i32 = null;
40034001 var it = switch_br.iterateCases();
40044002 while (it.next()) |case| {
4005 const values = try func.gpa.alloc(CaseValue, case.items.len + case.ranges.len);
4006 errdefer func.gpa.free(values);
4003 const values = try cg.gpa.alloc(CaseValue, case.items.len + case.ranges.len);
4004 errdefer cg.gpa.free(values);
40074005
40084006 for (case.items, 0..) |ref, i| {
4009 const item_val = (try func.air.value(ref, pt)).?;
4010 const int_val = func.valueAsI32(item_val);
4007 const item_val = (try cg.air.value(ref, pt)).?;
4008 const int_val = cg.valueAsI32(item_val);
40114009 if (lowest_maybe == null or int_val < lowest_maybe.?) {
40124010 lowest_maybe = int_val;
40134011 }
......@@ -4018,15 +4016,15 @@ fn airSwitchBr(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
40184016 }
40194017
40204018 for (case.ranges, 0..) |range, i| {
4021 const min_val = (try func.air.value(range[0], pt)).?;
4022 const int_min_val = func.valueAsI32(min_val);
4019 const min_val = (try cg.air.value(range[0], pt)).?;
4020 const int_min_val = cg.valueAsI32(min_val);
40234021
40244022 if (lowest_maybe == null or int_min_val < lowest_maybe.?) {
40254023 lowest_maybe = int_min_val;
40264024 }
40274025
4028 const max_val = (try func.air.value(range[1], pt)).?;
4029 const int_max_val = func.valueAsI32(max_val);
4026 const max_val = (try cg.air.value(range[1], pt)).?;
4027 const int_max_val = cg.valueAsI32(max_val);
40304028
40314029 if (highest_maybe == null or int_max_val > highest_maybe.?) {
40324030 highest_maybe = int_max_val;
......@@ -4041,7 +4039,7 @@ fn airSwitchBr(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
40414039 }
40424040
40434041 case_list.appendAssumeCapacity(.{ .values = values, .body = case.body });
4044 try func.startBlock(.block, blocktype);
4042 try cg.startBlock(.block, blocktype);
40454043 }
40464044
40474045 // 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 {
40574055 const else_body = it.elseBody();
40584056 const has_else_body = else_body.len != 0;
40594057 if (has_else_body) {
4060 try func.startBlock(.block, blocktype);
4058 try cg.startBlock(.block, blocktype);
40614059 }
40624060
40634061 if (!is_sparse) {
......@@ -4065,25 +4063,25 @@ fn airSwitchBr(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
40654063 // The value 'target' represents the index into the table.
40664064 // Each index in the table represents a label to the branch
40674065 // to jump to.
4068 try func.startBlock(.block, blocktype);
4069 try func.emitWValue(target);
4066 try cg.startBlock(.block, blocktype);
4067 try cg.emitWValue(target);
40704068 if (lowest < 0) {
40714069 // since br_table works using indexes, starting from '0', we must ensure all values
40724070 // we put inside, are atleast 0.
4073 try func.addImm32(@bitCast(lowest * -1));
4074 try func.addTag(.i32_add);
4071 try cg.addImm32(@bitCast(lowest * -1));
4072 try cg.addTag(.i32_add);
40754073 } else if (lowest > 0) {
40764074 // make the index start from 0 by substracting the lowest value
4077 try func.addImm32(@bitCast(lowest));
4078 try func.addTag(.i32_sub);
4075 try cg.addImm32(@bitCast(lowest));
4076 try cg.addTag(.i32_sub);
40794077 }
40804078
40814079 // Account for default branch so always add '1'
40824080 const depth = @as(u32, @intCast(highest - lowest + @intFromBool(has_else_body))) + 1;
40834081 const jump_table: Mir.JumpTable = .{ .length = depth };
4084 const table_extra_index = try func.addExtra(jump_table);
4085 try func.addInst(.{ .tag = .br_table, .data = .{ .payload = table_extra_index } });
4086 try func.mir_extra.ensureUnusedCapacity(func.gpa, depth);
4082 const table_extra_index = try cg.addExtra(jump_table);
4083 try cg.addInst(.{ .tag = .br_table, .data = .{ .payload = table_extra_index } });
4084 try cg.mir_extra.ensureUnusedCapacity(cg.gpa, depth);
40874085 var value = lowest;
40884086 while (value <= highest) : (value += 1) {
40894087 // idx represents the branch we jump to
......@@ -4104,78 +4102,78 @@ fn airSwitchBr(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
41044102 // by using a jump table for this instead of if-else chains.
41054103 break :blk if (has_else_body or target_ty.zigTypeTag(zcu) == .error_set) switch_br.cases_len else unreachable;
41064104 };
4107 func.mir_extra.appendAssumeCapacity(idx);
4105 cg.mir_extra.appendAssumeCapacity(idx);
41084106 } else if (has_else_body) {
4109 func.mir_extra.appendAssumeCapacity(switch_br.cases_len); // default branch
4107 cg.mir_extra.appendAssumeCapacity(switch_br.cases_len); // default branch
41104108 }
4111 try func.endBlock();
4109 try cg.endBlock();
41124110 }
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));
41154113 for (case_list.items, 0..) |case, index| {
41164114 // when sparse, we use if/else-chain, so emit conditional checks
41174115 if (is_sparse) {
41184116 // for single value prong we can emit a simple condition
41194117 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);
41214119 // 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);
4123 try func.addLabel(.br_if, 0);
4120 _ = try cg.cmp(target, val, target_ty, .neq);
4121 try cg.addLabel(.br_if, 0);
41244122 } else {
41254123 // 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);
41274125 for (case.values) |value| {
41284126 switch (value) {
41294127 .singular => |single_val| {
4130 const val = try func.lowerConstant(single_val.value, target_ty);
4131 _ = try func.cmp(target, val, target_ty, .eq);
4128 const val = try cg.lowerConstant(single_val.value, target_ty);
4129 _ = try cg.cmp(target, val, target_ty, .eq);
41324130 },
41334131 .range => |range| {
4134 const min_val = try func.lowerConstant(range.min_value, target_ty);
4135 const max_val = try func.lowerConstant(range.max_value, target_ty);
4132 const min_val = try cg.lowerConstant(range.min_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);
4138 const lte = try func.cmp(target, max_val, target_ty, .lte);
4139 _ = try func.binOp(gte, lte, Type.bool, .@"and");
4135 const gte = try cg.cmp(target, min_val, target_ty, .gte);
4136 const lte = try cg.cmp(target, max_val, target_ty, .lte);
4137 _ = try cg.binOp(gte, lte, Type.bool, .@"and");
41404138 },
41414139 }
4142 try func.addLabel(.br_if, 0);
4140 try cg.addLabel(.br_if, 0);
41434141 }
41444142 // value did not match any of the prong values
4145 try func.addLabel(.br, 1);
4146 try func.endBlock();
4143 try cg.addLabel(.br, 1);
4144 try cg.endBlock();
41474145 }
41484146 }
4149 func.branches.appendAssumeCapacity(.{});
4150 try func.currentBranch().values.ensureUnusedCapacity(func.gpa, liveness.deaths[index].len);
4147 cg.branches.appendAssumeCapacity(.{});
4148 try cg.currentBranch().values.ensureUnusedCapacity(cg.gpa, liveness.deaths[index].len);
41514149 defer {
4152 var case_branch = func.branches.pop();
4153 case_branch.deinit(func.gpa);
4150 var case_branch = cg.branches.pop();
4151 case_branch.deinit(cg.gpa);
41544152 }
4155 try func.genBody(case.body);
4156 try func.endBlock();
4153 try cg.genBody(case.body);
4154 try cg.endBlock();
41574155 }
41584156
41594157 if (has_else_body) {
4160 func.branches.appendAssumeCapacity(.{});
4158 cg.branches.appendAssumeCapacity(.{});
41614159 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);
41634161 defer {
4164 var else_branch = func.branches.pop();
4165 else_branch.deinit(func.gpa);
4162 var else_branch = cg.branches.pop();
4163 else_branch.deinit(cg.gpa);
41664164 }
4167 try func.genBody(else_body);
4168 try func.endBlock();
4165 try cg.genBody(else_body);
4166 try cg.endBlock();
41694167 }
4170 return func.finishAir(inst, .none, &.{});
4168 return cg.finishAir(inst, .none, &.{});
41714169}
41724170
4173fn airIsErr(func: *CodeGen, inst: Air.Inst.Index, opcode: std.wasm.Opcode) InnerError!void {
4174 const pt = func.pt;
4171fn airIsErr(cg: *CodeGen, inst: Air.Inst.Index, opcode: std.wasm.Opcode) InnerError!void {
4172 const pt = cg.pt;
41754173 const zcu = pt.zcu;
4176 const un_op = func.air.instructions.items(.data)[@intFromEnum(inst)].un_op;
4177 const operand = try func.resolveInst(un_op);
4178 const err_union_ty = func.typeOf(un_op);
4174 const un_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].un_op;
4175 const operand = try cg.resolveInst(un_op);
4176 const err_union_ty = cg.typeOf(un_op);
41794177 const pl_ty = err_union_ty.errorUnionPayload(zcu);
41804178
41814179 const result: WValue = result: {
......@@ -4187,57 +4185,57 @@ fn airIsErr(func: *CodeGen, inst: Air.Inst.Index, opcode: std.wasm.Opcode) Inner
41874185 }
41884186 }
41894187
4190 try func.emitWValue(operand);
4188 try cg.emitWValue(operand);
41914189 if (pl_ty.hasRuntimeBitsIgnoreComptime(zcu)) {
4192 try func.addMemArg(.i32_load16_u, .{
4190 try cg.addMemArg(.i32_load16_u, .{
41934191 .offset = operand.offset() + @as(u32, @intCast(errUnionErrorOffset(pl_ty, zcu))),
41944192 .alignment = @intCast(Type.anyerror.abiAlignment(zcu).toByteUnits().?),
41954193 });
41964194 }
41974195
41984196 // Compare the error value with '0'
4199 try func.addImm32(0);
4200 try func.addTag(Mir.Inst.Tag.fromOpcode(opcode));
4197 try cg.addImm32(0);
4198 try cg.addTag(Mir.Inst.Tag.fromOpcode(opcode));
42014199 break :result .stack;
42024200 };
4203 return func.finishAir(inst, result, &.{un_op});
4201 return cg.finishAir(inst, result, &.{un_op});
42044202}
42054203
4206fn airUnwrapErrUnionPayload(func: *CodeGen, inst: Air.Inst.Index, op_is_ptr: bool) InnerError!void {
4207 const pt = func.pt;
4204fn airUnwrapErrUnionPayload(cg: *CodeGen, inst: Air.Inst.Index, op_is_ptr: bool) InnerError!void {
4205 const pt = cg.pt;
42084206 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);
4212 const op_ty = func.typeOf(ty_op.operand);
4209 const operand = try cg.resolveInst(ty_op.operand);
4210 const op_ty = cg.typeOf(ty_op.operand);
42134211 const err_ty = if (op_is_ptr) op_ty.childType(zcu) else op_ty;
42144212 const payload_ty = err_ty.errorUnionPayload(zcu);
42154213
42164214 const result: WValue = result: {
42174215 if (!payload_ty.hasRuntimeBitsIgnoreComptime(zcu)) {
42184216 if (op_is_ptr) {
4219 break :result func.reuseOperand(ty_op.operand, operand);
4217 break :result cg.reuseOperand(ty_op.operand, operand);
42204218 }
42214219 break :result .none;
42224220 }
42234221
42244222 const pl_offset = @as(u32, @intCast(errUnionPayloadOffset(payload_ty, zcu)));
4225 if (op_is_ptr or isByRef(payload_ty, pt, func.target)) {
4226 break :result try func.buildPointerOffset(operand, pl_offset, .new);
4223 if (op_is_ptr or isByRef(payload_ty, pt, cg.target)) {
4224 break :result try cg.buildPointerOffset(operand, pl_offset, .new);
42274225 }
42284226
4229 break :result try func.load(operand, payload_ty, pl_offset);
4227 break :result try cg.load(operand, payload_ty, pl_offset);
42304228 };
4231 return func.finishAir(inst, result, &.{ty_op.operand});
4229 return cg.finishAir(inst, result, &.{ty_op.operand});
42324230}
42334231
4234fn airUnwrapErrUnionError(func: *CodeGen, inst: Air.Inst.Index, op_is_ptr: bool) InnerError!void {
4235 const pt = func.pt;
4232fn airUnwrapErrUnionError(cg: *CodeGen, inst: Air.Inst.Index, op_is_ptr: bool) InnerError!void {
4233 const pt = cg.pt;
42364234 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);
4240 const op_ty = func.typeOf(ty_op.operand);
4237 const operand = try cg.resolveInst(ty_op.operand);
4238 const op_ty = cg.typeOf(ty_op.operand);
42414239 const err_ty = if (op_is_ptr) op_ty.childType(zcu) else op_ty;
42424240 const payload_ty = err_ty.errorUnionPayload(zcu);
42434241
......@@ -4247,103 +4245,103 @@ fn airUnwrapErrUnionError(func: *CodeGen, inst: Air.Inst.Index, op_is_ptr: bool)
42474245 }
42484246
42494247 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);
42514249 }
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)));
42544252 };
4255 return func.finishAir(inst, result, &.{ty_op.operand});
4253 return cg.finishAir(inst, result, &.{ty_op.operand});
42564254}
42574255
4258fn airWrapErrUnionPayload(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
4259 const zcu = func.pt.zcu;
4260 const ty_op = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
4256fn airWrapErrUnionPayload(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
4257 const zcu = cg.pt.zcu;
4258 const ty_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
42614259
4262 const operand = try func.resolveInst(ty_op.operand);
4263 const err_ty = func.typeOfIndex(inst);
4260 const operand = try cg.resolveInst(ty_op.operand);
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);
42664264 const result = result: {
42674265 if (!pl_ty.hasRuntimeBitsIgnoreComptime(zcu)) {
4268 break :result func.reuseOperand(ty_op.operand, operand);
4266 break :result cg.reuseOperand(ty_op.operand, operand);
42694267 }
42704268
4271 const err_union = try func.allocStack(err_ty);
4272 const payload_ptr = try func.buildPointerOffset(err_union, @as(u32, @intCast(errUnionPayloadOffset(pl_ty, zcu))), .new);
4273 try func.store(payload_ptr, operand, pl_ty, 0);
4269 const err_union = try cg.allocStack(err_ty);
4270 const payload_ptr = try cg.buildPointerOffset(err_union, @as(u32, @intCast(errUnionPayloadOffset(pl_ty, zcu))), .new);
4271 try cg.store(payload_ptr, operand, pl_ty, 0);
42744272
42754273 // ensure we also write '0' to the error part, so any present stack value gets overwritten by it.
4276 try func.emitWValue(err_union);
4277 try func.addImm32(0);
4274 try cg.emitWValue(err_union);
4275 try cg.addImm32(0);
42784276 const err_val_offset: u32 = @intCast(errUnionErrorOffset(pl_ty, zcu));
4279 try func.addMemArg(.i32_store16, .{
4277 try cg.addMemArg(.i32_store16, .{
42804278 .offset = err_union.offset() + err_val_offset,
42814279 .alignment = 2,
42824280 });
42834281 break :result err_union;
42844282 };
4285 return func.finishAir(inst, result, &.{ty_op.operand});
4283 return cg.finishAir(inst, result, &.{ty_op.operand});
42864284}
42874285
4288fn airWrapErrUnionErr(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
4289 const pt = func.pt;
4286fn airWrapErrUnionErr(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
4287 const pt = cg.pt;
42904288 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);
42944292 const err_ty = ty_op.ty.toType();
42954293 const pl_ty = err_ty.errorUnionPayload(zcu);
42964294
42974295 const result = result: {
42984296 if (!pl_ty.hasRuntimeBitsIgnoreComptime(zcu)) {
4299 break :result func.reuseOperand(ty_op.operand, operand);
4297 break :result cg.reuseOperand(ty_op.operand, operand);
43004298 }
43014299
4302 const err_union = try func.allocStack(err_ty);
4300 const err_union = try cg.allocStack(err_ty);
43034301 // 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
43064304 // 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);
43084306 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
43114309 break :result err_union;
43124310 };
4313 return func.finishAir(inst, result, &.{ty_op.operand});
4311 return cg.finishAir(inst, result, &.{ty_op.operand});
43144312}
43154313
4316fn airIntcast(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
4317 const ty_op = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
4314fn airIntcast(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
4315 const ty_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
43184316
43194317 const ty = ty_op.ty.toType();
4320 const operand = try func.resolveInst(ty_op.operand);
4321 const operand_ty = func.typeOf(ty_op.operand);
4322 const pt = func.pt;
4318 const operand = try cg.resolveInst(ty_op.operand);
4319 const operand_ty = cg.typeOf(ty_op.operand);
4320 const pt = cg.pt;
43234321 const zcu = pt.zcu;
43244322 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", .{});
43264324 }
43274325 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", .{});
43294327 }
43304328
43314329 const op_bits = toWasmBits(@intCast(operand_ty.bitSize(zcu))).?;
43324330 const wanted_bits = toWasmBits(@intCast(ty.bitSize(zcu))).?;
43334331 const result = if (op_bits == wanted_bits)
4334 func.reuseOperand(ty_op.operand, operand)
4332 cg.reuseOperand(ty_op.operand, operand)
43354333 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});
43394337}
43404338
43414339/// Upcasts or downcasts an integer based on the given and wanted types,
43424340/// and stores the result in a new operand.
43434341/// Asserts type's bitsize <= 128
43444342/// NOTE: May leave the result on the top of the stack.
4345fn intcast(func: *CodeGen, operand: WValue, given: Type, wanted: Type) InnerError!WValue {
4346 const pt = func.pt;
4343fn intcast(cg: *CodeGen, operand: WValue, given: Type, wanted: Type) InnerError!WValue {
4344 const pt = cg.pt;
43474345 const zcu = pt.zcu;
43484346 const given_bitsize = @as(u16, @intCast(given.bitSize(zcu)));
43494347 const wanted_bitsize = @as(u16, @intCast(wanted.bitSize(zcu)));
......@@ -4357,469 +4355,469 @@ fn intcast(func: *CodeGen, operand: WValue, given: Type, wanted: Type) InnerErro
43574355 }
43584356
43594357 if (op_bits == 64 and wanted_bits == 32) {
4360 try func.emitWValue(operand);
4361 try func.addTag(.i32_wrap_i64);
4358 try cg.emitWValue(operand);
4359 try cg.addTag(.i32_wrap_i64);
43624360 return .stack;
43634361 } else if (op_bits == 32 and wanted_bits == 64) {
4364 try func.emitWValue(operand);
4365 try func.addTag(if (wanted.isSignedInt(zcu)) .i64_extend_i32_s else .i64_extend_i32_u);
4362 try cg.emitWValue(operand);
4363 try cg.addTag(if (wanted.isSignedInt(zcu)) .i64_extend_i32_s else .i64_extend_i32_u);
43664364 return .stack;
43674365 } else if (wanted_bits == 128) {
43684366 // for 128bit integers we store the integer in the virtual stack, rather than a local
4369 const stack_ptr = try func.allocStack(wanted);
4370 try func.emitWValue(stack_ptr);
4367 const stack_ptr = try cg.allocStack(wanted);
4368 try cg.emitWValue(stack_ptr);
43714369
43724370 // for 32 bit integers, we first coerce the value into a 64 bit integer before storing it
43734371 // meaning less store operations are required.
43744372 const lhs = if (op_bits == 32) blk: {
43754373 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);
43774375 } else operand;
43784376
43794377 // 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
43824380 // For signed integers we shift lsb by 63 (64bit integer - 1 sign bit) and store remaining value
43834381 if (wanted.isSignedInt(zcu)) {
4384 try func.emitWValue(stack_ptr);
4385 const shr = try func.binOp(lhs, .{ .imm64 = 63 }, Type.i64, .shr);
4386 try func.store(.stack, shr, Type.u64, 8 + stack_ptr.offset());
4382 try cg.emitWValue(stack_ptr);
4383 const shr = try cg.binOp(lhs, .{ .imm64 = 63 }, Type.i64, .shr);
4384 try cg.store(.stack, shr, Type.u64, 8 + stack_ptr.offset());
43874385 } else {
43884386 // 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);
43904388 }
43914389 return stack_ptr;
4392 } else return func.load(operand, wanted, 0);
4390 } else return cg.load(operand, wanted, 0);
43934391}
43944392
4395fn airIsNull(func: *CodeGen, inst: Air.Inst.Index, opcode: std.wasm.Opcode, op_kind: enum { value, ptr }) InnerError!void {
4396 const pt = func.pt;
4393fn airIsNull(cg: *CodeGen, inst: Air.Inst.Index, opcode: std.wasm.Opcode, op_kind: enum { value, ptr }) InnerError!void {
4394 const pt = cg.pt;
43974395 const zcu = pt.zcu;
4398 const un_op = func.air.instructions.items(.data)[@intFromEnum(inst)].un_op;
4399 const operand = try func.resolveInst(un_op);
4396 const un_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].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);
44024400 const optional_ty = if (op_kind == .ptr) op_ty.childType(zcu) else op_ty;
4403 const result = try func.isNull(operand, optional_ty, opcode);
4404 return func.finishAir(inst, result, &.{un_op});
4401 const result = try cg.isNull(operand, optional_ty, opcode);
4402 return cg.finishAir(inst, result, &.{un_op});
44054403}
44064404
44074405/// For a given type and operand, checks if it's considered `null`.
44084406/// NOTE: Leaves the result on the stack
4409fn isNull(func: *CodeGen, operand: WValue, optional_ty: Type, opcode: std.wasm.Opcode) InnerError!WValue {
4410 const pt = func.pt;
4407fn isNull(cg: *CodeGen, operand: WValue, optional_ty: Type, opcode: std.wasm.Opcode) InnerError!WValue {
4408 const pt = cg.pt;
44114409 const zcu = pt.zcu;
4412 try func.emitWValue(operand);
4410 try cg.emitWValue(operand);
44134411 const payload_ty = optional_ty.optionalChild(zcu);
44144412 if (!optional_ty.optionalReprIsPayload(zcu)) {
44154413 // When payload is zero-bits, we can treat operand as a value, rather than
44164414 // a pointer to the stack value
44174415 if (payload_ty.hasRuntimeBitsIgnoreComptime(zcu)) {
44184416 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)});
44204418 };
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 });
44224420 }
44234421 } else if (payload_ty.isSlice(zcu)) {
4424 switch (func.ptr_size) {
4425 .wasm32 => try func.addMemArg(.i32_load, .{ .offset = operand.offset(), .alignment = 4 }),
4426 .wasm64 => try func.addMemArg(.i64_load, .{ .offset = operand.offset(), .alignment = 8 }),
4422 switch (cg.ptr_size) {
4423 .wasm32 => try cg.addMemArg(.i32_load, .{ .offset = operand.offset(), .alignment = 4 }),
4424 .wasm64 => try cg.addMemArg(.i64_load, .{ .offset = operand.offset(), .alignment = 8 }),
44274425 }
44284426 }
44294427
44304428 // Compare the null value with '0'
4431 try func.addImm32(0);
4432 try func.addTag(Mir.Inst.Tag.fromOpcode(opcode));
4429 try cg.addImm32(0);
4430 try cg.addTag(Mir.Inst.Tag.fromOpcode(opcode));
44334431
44344432 return .stack;
44354433}
44364434
4437fn airOptionalPayload(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
4438 const pt = func.pt;
4435fn airOptionalPayload(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
4436 const pt = cg.pt;
44394437 const zcu = pt.zcu;
4440 const ty_op = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
4441 const opt_ty = func.typeOf(ty_op.operand);
4442 const payload_ty = func.typeOfIndex(inst);
4438 const ty_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
4439 const opt_ty = cg.typeOf(ty_op.operand);
4440 const payload_ty = cg.typeOfIndex(inst);
44434441 if (!payload_ty.hasRuntimeBitsIgnoreComptime(zcu)) {
4444 return func.finishAir(inst, .none, &.{ty_op.operand});
4442 return cg.finishAir(inst, .none, &.{ty_op.operand});
44454443 }
44464444
44474445 const result = result: {
4448 const operand = try func.resolveInst(ty_op.operand);
4449 if (opt_ty.optionalReprIsPayload(zcu)) break :result func.reuseOperand(ty_op.operand, operand);
4446 const operand = try cg.resolveInst(ty_op.operand);
4447 if (opt_ty.optionalReprIsPayload(zcu)) break :result cg.reuseOperand(ty_op.operand, operand);
44504448
4451 if (isByRef(payload_ty, pt, func.target)) {
4452 break :result try func.buildPointerOffset(operand, 0, .new);
4449 if (isByRef(payload_ty, pt, cg.target)) {
4450 break :result try cg.buildPointerOffset(operand, 0, .new);
44534451 }
44544452
4455 break :result try func.load(operand, payload_ty, 0);
4453 break :result try cg.load(operand, payload_ty, 0);
44564454 };
4457 return func.finishAir(inst, result, &.{ty_op.operand});
4455 return cg.finishAir(inst, result, &.{ty_op.operand});
44584456}
44594457
4460fn airOptionalPayloadPtr(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
4461 const pt = func.pt;
4458fn airOptionalPayloadPtr(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
4459 const pt = cg.pt;
44624460 const zcu = pt.zcu;
4463 const ty_op = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
4464 const operand = try func.resolveInst(ty_op.operand);
4465 const opt_ty = func.typeOf(ty_op.operand).childType(zcu);
4461 const ty_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
4462 const operand = try cg.resolveInst(ty_op.operand);
4463 const opt_ty = cg.typeOf(ty_op.operand).childType(zcu);
44664464
44674465 const result = result: {
44684466 const payload_ty = opt_ty.optionalChild(zcu);
44694467 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);
44714469 }
44724470
4473 break :result try func.buildPointerOffset(operand, 0, .new);
4471 break :result try cg.buildPointerOffset(operand, 0, .new);
44744472 };
4475 return func.finishAir(inst, result, &.{ty_op.operand});
4473 return cg.finishAir(inst, result, &.{ty_op.operand});
44764474}
44774475
4478fn airOptionalPayloadPtrSet(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
4479 const pt = func.pt;
4476fn airOptionalPayloadPtrSet(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
4477 const pt = cg.pt;
44804478 const zcu = pt.zcu;
4481 const ty_op = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
4482 const operand = try func.resolveInst(ty_op.operand);
4483 const opt_ty = func.typeOf(ty_op.operand).childType(zcu);
4479 const ty_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
4480 const operand = try cg.resolveInst(ty_op.operand);
4481 const opt_ty = cg.typeOf(ty_op.operand).childType(zcu);
44844482 const payload_ty = opt_ty.optionalChild(zcu);
44854483 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()});
44874485 }
44884486
44894487 if (opt_ty.optionalReprIsPayload(zcu)) {
4490 return func.finishAir(inst, operand, &.{ty_op.operand});
4488 return cg.finishAir(inst, operand, &.{ty_op.operand});
44914489 }
44924490
44934491 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)});
44954493 };
44964494
4497 try func.emitWValue(operand);
4498 try func.addImm32(1);
4499 try func.addMemArg(.i32_store8, .{ .offset = operand.offset() + offset, .alignment = 1 });
4495 try cg.emitWValue(operand);
4496 try cg.addImm32(1);
4497 try cg.addMemArg(.i32_store8, .{ .offset = operand.offset() + offset, .alignment = 1 });
45004498
4501 const result = try func.buildPointerOffset(operand, 0, .new);
4502 return func.finishAir(inst, result, &.{ty_op.operand});
4499 const result = try cg.buildPointerOffset(operand, 0, .new);
4500 return cg.finishAir(inst, result, &.{ty_op.operand});
45034501}
45044502
4505fn airWrapOptional(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
4506 const ty_op = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
4507 const payload_ty = func.typeOf(ty_op.operand);
4508 const pt = func.pt;
4503fn airWrapOptional(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
4504 const ty_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
4505 const payload_ty = cg.typeOf(ty_op.operand);
4506 const pt = cg.pt;
45094507 const zcu = pt.zcu;
45104508
45114509 const result = result: {
45124510 if (!payload_ty.hasRuntimeBitsIgnoreComptime(zcu)) {
4513 const non_null_bit = try func.allocStack(Type.u1);
4514 try func.emitWValue(non_null_bit);
4515 try func.addImm32(1);
4516 try func.addMemArg(.i32_store8, .{ .offset = non_null_bit.offset(), .alignment = 1 });
4511 const non_null_bit = try cg.allocStack(Type.u1);
4512 try cg.emitWValue(non_null_bit);
4513 try cg.addImm32(1);
4514 try cg.addMemArg(.i32_store8, .{ .offset = non_null_bit.offset(), .alignment = 1 });
45174515 break :result non_null_bit;
45184516 }
45194517
4520 const operand = try func.resolveInst(ty_op.operand);
4521 const op_ty = func.typeOfIndex(inst);
4518 const operand = try cg.resolveInst(ty_op.operand);
4519 const op_ty = cg.typeOfIndex(inst);
45224520 if (op_ty.optionalReprIsPayload(zcu)) {
4523 break :result func.reuseOperand(ty_op.operand, operand);
4521 break :result cg.reuseOperand(ty_op.operand, operand);
45244522 }
45254523 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)});
45274525 };
45284526
45294527 // 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);
4531 try func.emitWValue(result_ptr);
4532 try func.addImm32(1);
4533 try func.addMemArg(.i32_store8, .{ .offset = result_ptr.offset() + offset, .alignment = 1 });
4528 const result_ptr = try cg.allocStack(op_ty);
4529 try cg.emitWValue(result_ptr);
4530 try cg.addImm32(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);
4536 try func.store(payload_ptr, operand, payload_ty, 0);
4533 const payload_ptr = try cg.buildPointerOffset(result_ptr, 0, .new);
4534 try cg.store(payload_ptr, operand, payload_ty, 0);
45374535 break :result result_ptr;
45384536 };
45394537
4540 return func.finishAir(inst, result, &.{ty_op.operand});
4538 return cg.finishAir(inst, result, &.{ty_op.operand});
45414539}
45424540
4543fn airSlice(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
4544 const ty_pl = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
4545 const bin_op = func.air.extraData(Air.Bin, ty_pl.payload).data;
4541fn airSlice(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
4542 const ty_pl = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
4543 const bin_op = cg.air.extraData(Air.Bin, ty_pl.payload).data;
45464544
4547 const lhs = try func.resolveInst(bin_op.lhs);
4548 const rhs = try func.resolveInst(bin_op.rhs);
4549 const slice_ty = func.typeOfIndex(inst);
4545 const lhs = try cg.resolveInst(bin_op.lhs);
4546 const rhs = try cg.resolveInst(bin_op.rhs);
4547 const slice_ty = cg.typeOfIndex(inst);
45504548
4551 const slice = try func.allocStack(slice_ty);
4552 try func.store(slice, lhs, Type.usize, 0);
4553 try func.store(slice, rhs, Type.usize, func.ptrSize());
4549 const slice = try cg.allocStack(slice_ty);
4550 try cg.store(slice, lhs, Type.usize, 0);
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 });
45564554}
45574555
4558fn airSliceLen(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
4559 const ty_op = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
4556fn airSliceLen(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
4557 const ty_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
45604558
4561 const operand = try func.resolveInst(ty_op.operand);
4562 return func.finishAir(inst, try func.sliceLen(operand), &.{ty_op.operand});
4559 const operand = try cg.resolveInst(ty_op.operand);
4560 return cg.finishAir(inst, try cg.sliceLen(operand), &.{ty_op.operand});
45634561}
45644562
4565fn airSliceElemVal(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
4566 const pt = func.pt;
4563fn airSliceElemVal(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
4564 const pt = cg.pt;
45674565 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);
4571 const slice = try func.resolveInst(bin_op.lhs);
4572 const index = try func.resolveInst(bin_op.rhs);
4568 const slice_ty = cg.typeOf(bin_op.lhs);
4569 const slice = try cg.resolveInst(bin_op.lhs);
4570 const index = try cg.resolveInst(bin_op.rhs);
45734571 const elem_ty = slice_ty.childType(zcu);
45744572 const elem_size = elem_ty.abiSize(zcu);
45754573
45764574 // load pointer onto stack
4577 _ = try func.load(slice, Type.usize, 0);
4575 _ = try cg.load(slice, Type.usize, 0);
45784576
45794577 // calculate index into slice
4580 try func.emitWValue(index);
4581 try func.addImm32(@intCast(elem_size));
4582 try func.addTag(.i32_mul);
4583 try func.addTag(.i32_add);
4578 try cg.emitWValue(index);
4579 try cg.addImm32(@intCast(elem_size));
4580 try cg.addTag(.i32_mul);
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))
45864584 .stack
45874585 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 });
45914589}
45924590
4593fn airSliceElemPtr(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
4594 const pt = func.pt;
4591fn airSliceElemPtr(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
4592 const pt = cg.pt;
45954593 const zcu = pt.zcu;
4596 const ty_pl = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
4597 const bin_op = func.air.extraData(Air.Bin, ty_pl.payload).data;
4594 const ty_pl = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
4595 const bin_op = cg.air.extraData(Air.Bin, ty_pl.payload).data;
45984596
45994597 const elem_ty = ty_pl.ty.toType().childType(zcu);
46004598 const elem_size = elem_ty.abiSize(zcu);
46014599
4602 const slice = try func.resolveInst(bin_op.lhs);
4603 const index = try func.resolveInst(bin_op.rhs);
4600 const slice = try cg.resolveInst(bin_op.lhs);
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
46074605 // calculate index into slice
4608 try func.emitWValue(index);
4609 try func.addImm32(@intCast(elem_size));
4610 try func.addTag(.i32_mul);
4611 try func.addTag(.i32_add);
4606 try cg.emitWValue(index);
4607 try cg.addImm32(@intCast(elem_size));
4608 try cg.addTag(.i32_mul);
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 });
46144612}
46154613
4616fn airSlicePtr(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
4617 const ty_op = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
4618 const operand = try func.resolveInst(ty_op.operand);
4619 return func.finishAir(inst, try func.slicePtr(operand), &.{ty_op.operand});
4614fn airSlicePtr(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
4615 const ty_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
4616 const operand = try cg.resolveInst(ty_op.operand);
4617 return cg.finishAir(inst, try cg.slicePtr(operand), &.{ty_op.operand});
46204618}
46214619
4622fn slicePtr(func: *CodeGen, operand: WValue) InnerError!WValue {
4623 const ptr = try func.load(operand, Type.usize, 0);
4624 return ptr.toLocal(func, Type.usize);
4620fn slicePtr(cg: *CodeGen, operand: WValue) InnerError!WValue {
4621 const ptr = try cg.load(operand, Type.usize, 0);
4622 return ptr.toLocal(cg, Type.usize);
46254623}
46264624
4627fn sliceLen(func: *CodeGen, operand: WValue) InnerError!WValue {
4628 const len = try func.load(operand, Type.usize, func.ptrSize());
4629 return len.toLocal(func, Type.usize);
4625fn sliceLen(cg: *CodeGen, operand: WValue) InnerError!WValue {
4626 const len = try cg.load(operand, Type.usize, cg.ptrSize());
4627 return len.toLocal(cg, Type.usize);
46304628}
46314629
4632fn airTrunc(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
4633 const ty_op = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
4630fn airTrunc(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
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);
46364634 const wanted_ty: Type = ty_op.ty.toType();
4637 const op_ty = func.typeOf(ty_op.operand);
4638 const pt = func.pt;
4635 const op_ty = cg.typeOf(ty_op.operand);
4636 const pt = cg.pt;
46394637 const zcu = pt.zcu;
46404638
46414639 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", .{});
46434641 }
46444642
46454643 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)
46474645 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});
46514649}
46524650
46534651/// Truncates a given operand to a given type, discarding any overflown bits.
46544652/// NOTE: Resulting value is left on the stack.
4655fn trunc(func: *CodeGen, operand: WValue, wanted_ty: Type, given_ty: Type) InnerError!WValue {
4656 const pt = func.pt;
4653fn trunc(cg: *CodeGen, operand: WValue, wanted_ty: Type, given_ty: Type) InnerError!WValue {
4654 const pt = cg.pt;
46574655 const zcu = pt.zcu;
46584656 const given_bits = @as(u16, @intCast(given_ty.bitSize(zcu)));
46594657 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});
46614659 }
46624660
4663 var result = try func.intcast(operand, given_ty, wanted_ty);
4661 var result = try cg.intcast(operand, given_ty, wanted_ty);
46644662 const wanted_bits = @as(u16, @intCast(wanted_ty.bitSize(zcu)));
46654663 const wasm_bits = toWasmBits(wanted_bits).?;
46664664 if (wasm_bits != wanted_bits) {
4667 result = try func.wrapOperand(result, wanted_ty);
4665 result = try cg.wrapOperand(result, wanted_ty);
46684666 }
46694667 return result;
46704668}
46714669
4672fn airIntFromBool(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
4673 const un_op = func.air.instructions.items(.data)[@intFromEnum(inst)].un_op;
4674 const operand = try func.resolveInst(un_op);
4675 const result = func.reuseOperand(un_op, operand);
4670fn airIntFromBool(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
4671 const un_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].un_op;
4672 const operand = try cg.resolveInst(un_op);
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});
46784676}
46794677
4680fn airArrayToSlice(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
4681 const pt = func.pt;
4678fn airArrayToSlice(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
4679 const pt = cg.pt;
46824680 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);
4686 const array_ty = func.typeOf(ty_op.operand).childType(zcu);
4683 const operand = try cg.resolveInst(ty_op.operand);
4684 const array_ty = cg.typeOf(ty_op.operand).childType(zcu);
46874685 const slice_ty = ty_op.ty.toType();
46884686
46894687 // 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
46924690 // store the array ptr in the slice
46934691 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);
46954693 }
46964694
46974695 // store the length of the array in the slice
46984696 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});
47024700}
47034701
4704fn airIntFromPtr(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
4705 const pt = func.pt;
4702fn airIntFromPtr(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
4703 const pt = cg.pt;
47064704 const zcu = pt.zcu;
4707 const un_op = func.air.instructions.items(.data)[@intFromEnum(inst)].un_op;
4708 const operand = try func.resolveInst(un_op);
4709 const ptr_ty = func.typeOf(un_op);
4705 const un_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].un_op;
4706 const operand = try cg.resolveInst(un_op);
4707 const ptr_ty = cg.typeOf(un_op);
47104708 const result = if (ptr_ty.isSlice(zcu))
4711 try func.slicePtr(operand)
4709 try cg.slicePtr(operand)
47124710 else switch (operand) {
47134711 // for stack offset, return a pointer to this offset.
4714 .stack_offset => try func.buildPointerOffset(operand, 0, .new),
4715 else => func.reuseOperand(un_op, operand),
4712 .stack_offset => try cg.buildPointerOffset(operand, 0, .new),
4713 else => cg.reuseOperand(un_op, operand),
47164714 };
4717 return func.finishAir(inst, result, &.{un_op});
4715 return cg.finishAir(inst, result, &.{un_op});
47184716}
47194717
4720fn airPtrElemVal(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
4721 const pt = func.pt;
4718fn airPtrElemVal(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
4719 const pt = cg.pt;
47224720 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);
4726 const ptr = try func.resolveInst(bin_op.lhs);
4727 const index = try func.resolveInst(bin_op.rhs);
4723 const ptr_ty = cg.typeOf(bin_op.lhs);
4724 const ptr = try cg.resolveInst(bin_op.lhs);
4725 const index = try cg.resolveInst(bin_op.rhs);
47284726 const elem_ty = ptr_ty.childType(zcu);
47294727 const elem_size = elem_ty.abiSize(zcu);
47304728
47314729 // load pointer onto the stack
47324730 if (ptr_ty.isSlice(zcu)) {
4733 _ = try func.load(ptr, Type.usize, 0);
4731 _ = try cg.load(ptr, Type.usize, 0);
47344732 } else {
4735 try func.lowerToStack(ptr);
4733 try cg.lowerToStack(ptr);
47364734 }
47374735
47384736 // calculate index into slice
4739 try func.emitWValue(index);
4740 try func.addImm32(@intCast(elem_size));
4741 try func.addTag(.i32_mul);
4742 try func.addTag(.i32_add);
4737 try cg.emitWValue(index);
4738 try cg.addImm32(@intCast(elem_size));
4739 try cg.addTag(.i32_mul);
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))
47454743 .stack
47464744 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 });
47504748}
47514749
4752fn airPtrElemPtr(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
4753 const pt = func.pt;
4750fn airPtrElemPtr(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
4751 const pt = cg.pt;
47544752 const zcu = pt.zcu;
4755 const ty_pl = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
4756 const bin_op = func.air.extraData(Air.Bin, ty_pl.payload).data;
4753 const ty_pl = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
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);
47594757 const elem_ty = ty_pl.ty.toType().childType(zcu);
47604758 const elem_size = elem_ty.abiSize(zcu);
47614759
4762 const ptr = try func.resolveInst(bin_op.lhs);
4763 const index = try func.resolveInst(bin_op.rhs);
4760 const ptr = try cg.resolveInst(bin_op.lhs);
4761 const index = try cg.resolveInst(bin_op.rhs);
47644762
47654763 // load pointer onto the stack
47664764 if (ptr_ty.isSlice(zcu)) {
4767 _ = try func.load(ptr, Type.usize, 0);
4765 _ = try cg.load(ptr, Type.usize, 0);
47684766 } else {
4769 try func.lowerToStack(ptr);
4767 try cg.lowerToStack(ptr);
47704768 }
47714769
47724770 // calculate index into ptr
4773 try func.emitWValue(index);
4774 try func.addImm32(@intCast(elem_size));
4775 try func.addTag(.i32_mul);
4776 try func.addTag(.i32_add);
4771 try cg.emitWValue(index);
4772 try cg.addImm32(@intCast(elem_size));
4773 try cg.addTag(.i32_mul);
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 });
47794777}
47804778
4781fn airPtrBinOp(func: *CodeGen, inst: Air.Inst.Index, op: Op) InnerError!void {
4782 const pt = func.pt;
4779fn airPtrBinOp(cg: *CodeGen, inst: Air.Inst.Index, op: Op) InnerError!void {
4780 const pt = cg.pt;
47834781 const zcu = pt.zcu;
4784 const ty_pl = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
4785 const bin_op = func.air.extraData(Air.Bin, ty_pl.payload).data;
4782 const ty_pl = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
4783 const bin_op = cg.air.extraData(Air.Bin, ty_pl.payload).data;
47864784
4787 const ptr = try func.resolveInst(bin_op.lhs);
4788 const offset = try func.resolveInst(bin_op.rhs);
4789 const ptr_ty = func.typeOf(bin_op.lhs);
4785 const ptr = try cg.resolveInst(bin_op.lhs);
4786 const offset = try cg.resolveInst(bin_op.rhs);
4787 const ptr_ty = cg.typeOf(bin_op.lhs);
47904788 const pointee_ty = switch (ptr_ty.ptrSize(zcu)) {
47914789 .One => ptr_ty.childType(zcu).childType(zcu), // ptr to array, so get array element type
47924790 else => ptr_ty.childType(zcu),
47934791 };
47944792
4795 const valtype = typeToValtype(Type.usize, pt, func.target);
4793 const valtype = typeToValtype(Type.usize, pt, cg.target);
47964794 const mul_opcode = buildOpcode(.{ .valtype1 = valtype, .op = .mul });
47974795 const bin_opcode = buildOpcode(.{ .valtype1 = valtype, .op = op });
47984796
4799 try func.lowerToStack(ptr);
4800 try func.emitWValue(offset);
4801 try func.addImm32(@intCast(pointee_ty.abiSize(zcu)));
4802 try func.addTag(Mir.Inst.Tag.fromOpcode(mul_opcode));
4803 try func.addTag(Mir.Inst.Tag.fromOpcode(bin_opcode));
4797 try cg.lowerToStack(ptr);
4798 try cg.emitWValue(offset);
4799 try cg.addImm32(@intCast(pointee_ty.abiSize(zcu)));
4800 try cg.addTag(Mir.Inst.Tag.fromOpcode(mul_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 });
48064804}
48074805
4808fn airMemset(func: *CodeGen, inst: Air.Inst.Index, safety: bool) InnerError!void {
4809 const pt = func.pt;
4806fn airMemset(cg: *CodeGen, inst: Air.Inst.Index, safety: bool) InnerError!void {
4807 const pt = cg.pt;
48104808 const zcu = pt.zcu;
48114809 if (safety) {
48124810 // TODO if the value is undef, write 0xaa bytes to dest
48134811 } else {
48144812 // TODO if the value is undef, don't lower this instruction
48154813 }
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);
4819 const ptr_ty = func.typeOf(bin_op.lhs);
4820 const value = try func.resolveInst(bin_op.rhs);
4816 const ptr = try cg.resolveInst(bin_op.lhs);
4817 const ptr_ty = cg.typeOf(bin_op.lhs);
4818 const value = try cg.resolveInst(bin_op.rhs);
48214819 const len = switch (ptr_ty.ptrSize(zcu)) {
4822 .Slice => try func.sliceLen(ptr),
4820 .Slice => try cg.sliceLen(ptr),
48234821 .One => @as(WValue, .{ .imm32 = @as(u32, @intCast(ptr_ty.childType(zcu).arrayLen(zcu))) }),
48244822 .C, .Many => unreachable,
48254823 };
......@@ -4829,27 +4827,27 @@ fn airMemset(func: *CodeGen, inst: Air.Inst.Index, safety: bool) InnerError!void
48294827 else
48304828 ptr_ty.childType(zcu);
48314829
4832 const dst_ptr = try func.sliceOrArrayPtr(ptr, ptr_ty);
4833 try func.memset(elem_ty, dst_ptr, len, value);
4830 const dst_ptr = try cg.sliceOrArrayPtr(ptr, ptr_ty);
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 });
48364834}
48374835
48384836/// Sets a region of memory at `ptr` to the value of `value`
48394837/// When the user has enabled the bulk_memory feature, we lower
48404838/// this to wasm's memset instruction. When the feature is not present,
48414839/// we implement it manually.
4842fn memset(func: *CodeGen, elem_ty: Type, ptr: WValue, len: WValue, value: WValue) InnerError!void {
4843 const pt = func.pt;
4840fn memset(cg: *CodeGen, elem_ty: Type, ptr: WValue, len: WValue, value: WValue) InnerError!void {
4841 const pt = cg.pt;
48444842 const abi_size = @as(u32, @intCast(elem_ty.abiSize(pt.zcu)));
48454843
48464844 // When bulk_memory is enabled, we lower it to wasm's memset instruction.
48474845 // If not, we lower it ourselves.
4848 if (std.Target.wasm.featureSetHas(func.target.cpu.features, .bulk_memory) and abi_size == 1) {
4849 try func.lowerToStack(ptr);
4850 try func.emitWValue(value);
4851 try func.emitWValue(len);
4852 try func.addExtended(.memory_fill);
4846 if (std.Target.wasm.featureSetHas(cg.target.cpu.features, .bulk_memory) and abi_size == 1) {
4847 try cg.lowerToStack(ptr);
4848 try cg.emitWValue(value);
4849 try cg.emitWValue(len);
4850 try cg.addExtended(.memory_fill);
48534851 return;
48544852 }
48554853
......@@ -4857,90 +4855,90 @@ fn memset(func: *CodeGen, elem_ty: Type, ptr: WValue, len: WValue, value: WValue
48574855 .imm32 => |val| .{ .imm32 = val * abi_size },
48584856 .imm64 => |val| .{ .imm64 = val * abi_size },
48594857 else => if (abi_size != 1) blk: {
4860 const new_len = try func.ensureAllocLocal(Type.usize);
4861 try func.emitWValue(len);
4862 switch (func.ptr_size) {
4858 const new_len = try cg.ensureAllocLocal(Type.usize);
4859 try cg.emitWValue(len);
4860 switch (cg.ptr_size) {
48634861 .wasm32 => {
4864 try func.emitWValue(.{ .imm32 = abi_size });
4865 try func.addTag(.i32_mul);
4862 try cg.emitWValue(.{ .imm32 = abi_size });
4863 try cg.addTag(.i32_mul);
48664864 },
48674865 .wasm64 => {
4868 try func.emitWValue(.{ .imm64 = abi_size });
4869 try func.addTag(.i64_mul);
4866 try cg.emitWValue(.{ .imm64 = abi_size });
4867 try cg.addTag(.i64_mul);
48704868 },
48714869 }
4872 try func.addLabel(.local_set, new_len.local.value);
4870 try cg.addLabel(.local_set, new_len.local.value);
48734871 break :blk new_len;
48744872 } else len,
48754873 };
48764874
4877 var end_ptr = try func.allocLocal(Type.usize);
4878 defer end_ptr.free(func);
4879 var new_ptr = try func.buildPointerOffset(ptr, 0, .new);
4880 defer new_ptr.free(func);
4875 var end_ptr = try cg.allocLocal(Type.usize);
4876 defer end_ptr.free(cg);
4877 var new_ptr = try cg.buildPointerOffset(ptr, 0, .new);
4878 defer new_ptr.free(cg);
48814879
48824880 // get the loop conditional: if current pointer address equals final pointer's address
4883 try func.lowerToStack(ptr);
4884 try func.emitWValue(final_len);
4885 switch (func.ptr_size) {
4886 .wasm32 => try func.addTag(.i32_add),
4887 .wasm64 => try func.addTag(.i64_add),
4881 try cg.lowerToStack(ptr);
4882 try cg.emitWValue(final_len);
4883 switch (cg.ptr_size) {
4884 .wasm32 => try cg.addTag(.i32_add),
4885 .wasm64 => try cg.addTag(.i64_add),
48884886 }
4889 try func.addLabel(.local_set, end_ptr.local.value);
4887 try cg.addLabel(.local_set, end_ptr.local.value);
48904888
48914889 // outer block to jump to when loop is done
4892 try func.startBlock(.block, std.wasm.block_empty);
4893 try func.startBlock(.loop, std.wasm.block_empty);
4890 try cg.startBlock(.block, std.wasm.block_empty);
4891 try cg.startBlock(.loop, std.wasm.block_empty);
48944892
48954893 // check for condition for loop end
4896 try func.emitWValue(new_ptr);
4897 try func.emitWValue(end_ptr);
4898 switch (func.ptr_size) {
4899 .wasm32 => try func.addTag(.i32_eq),
4900 .wasm64 => try func.addTag(.i64_eq),
4894 try cg.emitWValue(new_ptr);
4895 try cg.emitWValue(end_ptr);
4896 switch (cg.ptr_size) {
4897 .wasm32 => try cg.addTag(.i32_eq),
4898 .wasm64 => try cg.addTag(.i64_eq),
49014899 }
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
49044902 // 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
49074905 // move the pointer to the next element
4908 try func.emitWValue(new_ptr);
4909 switch (func.ptr_size) {
4906 try cg.emitWValue(new_ptr);
4907 switch (cg.ptr_size) {
49104908 .wasm32 => {
4911 try func.emitWValue(.{ .imm32 = abi_size });
4912 try func.addTag(.i32_add);
4909 try cg.emitWValue(.{ .imm32 = abi_size });
4910 try cg.addTag(.i32_add);
49134911 },
49144912 .wasm64 => {
4915 try func.emitWValue(.{ .imm64 = abi_size });
4916 try func.addTag(.i64_add);
4913 try cg.emitWValue(.{ .imm64 = abi_size });
4914 try cg.addTag(.i64_add);
49174915 },
49184916 }
4919 try func.addLabel(.local_set, new_ptr.local.value);
4917 try cg.addLabel(.local_set, new_ptr.local.value);
49204918
49214919 // end of loop
4922 try func.addLabel(.br, 0); // jump to start of loop
4923 try func.endBlock();
4924 try func.endBlock();
4920 try cg.addLabel(.br, 0); // jump to start of loop
4921 try cg.endBlock();
4922 try cg.endBlock();
49254923}
49264924
4927fn airArrayElemVal(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
4928 const pt = func.pt;
4925fn airArrayElemVal(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
4926 const pt = cg.pt;
49294927 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);
4933 const array = try func.resolveInst(bin_op.lhs);
4934 const index = try func.resolveInst(bin_op.rhs);
4930 const array_ty = cg.typeOf(bin_op.lhs);
4931 const array = try cg.resolveInst(bin_op.lhs);
4932 const index = try cg.resolveInst(bin_op.rhs);
49354933 const elem_ty = array_ty.childType(zcu);
49364934 const elem_size = elem_ty.abiSize(zcu);
49374935
4938 if (isByRef(array_ty, pt, func.target)) {
4939 try func.lowerToStack(array);
4940 try func.emitWValue(index);
4941 try func.addImm32(@intCast(elem_size));
4942 try func.addTag(.i32_mul);
4943 try func.addTag(.i32_add);
4936 if (isByRef(array_ty, pt, cg.target)) {
4937 try cg.lowerToStack(array);
4938 try cg.emitWValue(index);
4939 try cg.addImm32(@intCast(elem_size));
4940 try cg.addTag(.i32_mul);
4941 try cg.addTag(.i32_add);
49444942 } else {
49454943 assert(array_ty.zigTypeTag(zcu) == .vector);
49464944
......@@ -4956,50 +4954,50 @@ fn airArrayElemVal(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
49564954
49574955 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));
4962 try func.mir_extra.appendSlice(func.gpa, &operands);
4963 try func.addInst(.{ .tag = .simd_prefix, .data = .{ .payload = extra_index } });
4959 const extra_index = @as(u32, @intCast(cg.mir_extra.items.len));
4960 try cg.mir_extra.appendSlice(cg.gpa, &operands);
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 });
49664964 },
49674965 else => {
4968 const stack_vec = try func.allocStack(array_ty);
4969 try func.store(stack_vec, array, array_ty, 0);
4966 const stack_vec = try cg.allocStack(array_ty);
4967 try cg.store(stack_vec, array, array_ty, 0);
49704968
49714969 // Is a non-unrolled vector (v128)
4972 try func.lowerToStack(stack_vec);
4973 try func.emitWValue(index);
4974 try func.addImm32(@intCast(elem_size));
4975 try func.addTag(.i32_mul);
4976 try func.addTag(.i32_add);
4970 try cg.lowerToStack(stack_vec);
4971 try cg.emitWValue(index);
4972 try cg.addImm32(@intCast(elem_size));
4973 try cg.addTag(.i32_mul);
4974 try cg.addTag(.i32_add);
49774975 },
49784976 }
49794977 }
49804978
4981 const elem_result = if (isByRef(elem_ty, pt, func.target))
4979 const elem_result = if (isByRef(elem_ty, pt, cg.target))
49824980 .stack
49834981 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 });
49874985}
49884986
4989fn airIntFromFloat(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
4990 const pt = func.pt;
4987fn airIntFromFloat(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
4988 const pt = cg.pt;
49914989 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);
4995 const op_ty = func.typeOf(ty_op.operand);
4996 const op_bits = op_ty.floatBits(func.target.*);
4992 const operand = try cg.resolveInst(ty_op.operand);
4993 const op_ty = cg.typeOf(ty_op.operand);
4994 const op_bits = op_ty.floatBits(cg.target.*);
49974995
4998 const dest_ty = func.typeOfIndex(inst);
4996 const dest_ty = cg.typeOfIndex(inst);
49994997 const dest_info = dest_ty.intInfo(zcu);
50004998
50014999 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});
50035001 }
50045002
50055003 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 {
50155013 target_util.compilerRtIntAbbrev(dest_bitsize),
50165014 }) catch unreachable;
50175015
5018 const result = try func.callIntrinsic(fn_name, &.{op_ty.ip_index}, dest_ty, &.{operand});
5019 return func.finishAir(inst, result, &.{ty_op.operand});
5016 const result = try cg.callIntrinsic(fn_name, &.{op_ty.ip_index}, dest_ty, &.{operand});
5017 return cg.finishAir(inst, result, &.{ty_op.operand});
50205018 }
50215019
5022 try func.emitWValue(operand);
5020 try cg.emitWValue(operand);
50235021 const op = buildOpcode(.{
50245022 .op = .trunc,
5025 .valtype1 = typeToValtype(dest_ty, pt, func.target),
5026 .valtype2 = typeToValtype(op_ty, pt, func.target),
5023 .valtype1 = typeToValtype(dest_ty, pt, cg.target),
5024 .valtype2 = typeToValtype(op_ty, pt, cg.target),
50275025 .signedness = dest_info.signedness,
50285026 });
5029 try func.addTag(Mir.Inst.Tag.fromOpcode(op));
5030 const result = try func.wrapOperand(.stack, dest_ty);
5031 return func.finishAir(inst, result, &.{ty_op.operand});
5027 try cg.addTag(Mir.Inst.Tag.fromOpcode(op));
5028 const result = try cg.wrapOperand(.stack, dest_ty);
5029 return cg.finishAir(inst, result, &.{ty_op.operand});
50325030}
50335031
5034fn airFloatFromInt(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
5035 const pt = func.pt;
5032fn airFloatFromInt(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
5033 const pt = cg.pt;
50365034 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);
5040 const op_ty = func.typeOf(ty_op.operand);
5037 const operand = try cg.resolveInst(ty_op.operand);
5038 const op_ty = cg.typeOf(ty_op.operand);
50415039 const op_info = op_ty.intInfo(zcu);
50425040
5043 const dest_ty = func.typeOfIndex(inst);
5044 const dest_bits = dest_ty.floatBits(func.target.*);
5041 const dest_ty = cg.typeOfIndex(inst);
5042 const dest_bits = dest_ty.floatBits(cg.target.*);
50455043
50465044 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});
50485046 }
50495047
50505048 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 {
50605058 target_util.compilerRtFloatAbbrev(dest_bits),
50615059 }) catch unreachable;
50625060
5063 const result = try func.callIntrinsic(fn_name, &.{op_ty.ip_index}, dest_ty, &.{operand});
5064 return func.finishAir(inst, result, &.{ty_op.operand});
5061 const result = try cg.callIntrinsic(fn_name, &.{op_ty.ip_index}, dest_ty, &.{operand});
5062 return cg.finishAir(inst, result, &.{ty_op.operand});
50655063 }
50665064
5067 try func.emitWValue(operand);
5065 try cg.emitWValue(operand);
50685066 const op = buildOpcode(.{
50695067 .op = .convert,
5070 .valtype1 = typeToValtype(dest_ty, pt, func.target),
5071 .valtype2 = typeToValtype(op_ty, pt, func.target),
5068 .valtype1 = typeToValtype(dest_ty, pt, cg.target),
5069 .valtype2 = typeToValtype(op_ty, pt, cg.target),
50725070 .signedness = op_info.signedness,
50735071 });
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});
50775075}
50785076
5079fn airSplat(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
5080 const pt = func.pt;
5077fn airSplat(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
5078 const pt = cg.pt;
50815079 const zcu = pt.zcu;
5082 const ty_op = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
5083 const operand = try func.resolveInst(ty_op.operand);
5084 const ty = func.typeOfIndex(inst);
5080 const ty_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
5081 const operand = try cg.resolveInst(ty_op.operand);
5082 const ty = cg.typeOfIndex(inst);
50855083 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: {
50885086 switch (operand) {
50895087 // when the operand lives in the linear memory section, we can directly
50905088 // 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 {
50975095 64 => @intFromEnum(std.wasm.SimdOpcode.v128_load64_splat),
50985096 else => break :blk, // Cannot make use of simd-instructions
50995097 };
5100 try func.emitWValue(operand);
5101 const extra_index: u32 = @intCast(func.mir_extra.items.len);
5098 try cg.emitWValue(operand);
5099 const extra_index: u32 = @intCast(cg.mir_extra.items.len);
51025100 // 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{
51045102 opcode,
51055103 operand.offset(),
51065104 @intCast(elem_ty.abiAlignment(zcu).toByteUnits().?),
51075105 });
5108 try func.addInst(.{ .tag = .simd_prefix, .data = .{ .payload = extra_index } });
5109 return func.finishAir(inst, .stack, &.{ty_op.operand});
5106 try cg.addInst(.{ .tag = .simd_prefix, .data = .{ .payload = extra_index } });
5107 return cg.finishAir(inst, .stack, &.{ty_op.operand});
51105108 },
51115109 .local => {
51125110 const opcode = switch (elem_ty.bitSize(zcu)) {
......@@ -5116,11 +5114,11 @@ fn airSplat(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
51165114 64 => if (elem_ty.isInt(zcu)) @intFromEnum(std.wasm.SimdOpcode.i64x2_splat) else @intFromEnum(std.wasm.SimdOpcode.f64x2_splat),
51175115 else => break :blk, // Cannot make use of simd-instructions
51185116 };
5119 try func.emitWValue(operand);
5120 const extra_index = @as(u32, @intCast(func.mir_extra.items.len));
5121 try func.mir_extra.append(func.gpa, opcode);
5122 try func.addInst(.{ .tag = .simd_prefix, .data = .{ .payload = extra_index } });
5123 return func.finishAir(inst, .stack, &.{ty_op.operand});
5117 try cg.emitWValue(operand);
5118 const extra_index = @as(u32, @intCast(cg.mir_extra.items.len));
5119 try cg.mir_extra.append(cg.gpa, opcode);
5120 try cg.addInst(.{ .tag = .simd_prefix, .data = .{ .payload = extra_index } });
5121 return cg.finishAir(inst, .stack, &.{ty_op.operand});
51245122 },
51255123 else => unreachable,
51265124 }
......@@ -5128,38 +5126,38 @@ fn airSplat(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
51285126 const elem_size = elem_ty.bitSize(zcu);
51295127 const vector_len = @as(usize, @intCast(ty.vectorLen(zcu)));
51305128 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});
51325130 }
51335131
5134 const result = try func.allocStack(ty);
5132 const result = try cg.allocStack(ty);
51355133 const elem_byte_size = @as(u32, @intCast(elem_ty.abiSize(zcu)));
51365134 var index: usize = 0;
51375135 var offset: u32 = 0;
51385136 while (index < vector_len) : (index += 1) {
5139 try func.store(result, operand, elem_ty, offset);
5137 try cg.store(result, operand, elem_ty, offset);
51405138 offset += elem_byte_size;
51415139 }
51425140
5143 return func.finishAir(inst, result, &.{ty_op.operand});
5141 return cg.finishAir(inst, result, &.{ty_op.operand});
51445142}
51455143
5146fn airSelect(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
5147 const pl_op = func.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;
5148 const operand = try func.resolveInst(pl_op.operand);
5144fn airSelect(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
5145 const pl_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;
5146 const operand = try cg.resolveInst(pl_op.operand);
51495147
51505148 _ = operand;
5151 return func.fail("TODO: Implement wasm airSelect", .{});
5149 return cg.fail("TODO: Implement wasm airSelect", .{});
51525150}
51535151
5154fn airShuffle(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
5155 const pt = func.pt;
5152fn airShuffle(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
5153 const pt = cg.pt;
51565154 const zcu = pt.zcu;
5157 const inst_ty = func.typeOfIndex(inst);
5158 const ty_pl = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
5159 const extra = func.air.extraData(Air.Shuffle, ty_pl.payload).data;
5155 const inst_ty = cg.typeOfIndex(inst);
5156 const ty_pl = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
5157 const extra = cg.air.extraData(Air.Shuffle, ty_pl.payload).data;
51605158
5161 const a = try func.resolveInst(extra.a);
5162 const b = try func.resolveInst(extra.b);
5159 const a = try cg.resolveInst(extra.a);
5160 const b = try cg.resolveInst(extra.b);
51635161 const mask = Value.fromInterned(extra.mask);
51645162 const mask_len = extra.mask_len;
51655163
......@@ -5167,23 +5165,23 @@ fn airShuffle(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
51675165 const elem_size = child_ty.abiSize(zcu);
51685166
51695167 // 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)) {
5171 const result = try func.allocStack(inst_ty);
5168 if (isByRef(cg.typeOf(extra.a), pt, cg.target) or isByRef(inst_ty, pt, cg.target)) {
5169 const result = try cg.allocStack(inst_ty);
51725170
51735171 for (0..mask_len) |index| {
51745172 const value = (try mask.elemValue(pt, index)).toSignedInt(zcu);
51755173
5176 try func.emitWValue(result);
5174 try cg.emitWValue(result);
51775175
51785176 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)))
51805178 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)));
51845182 }
51855183
5186 return func.finishAir(inst, result, &.{ extra.a, extra.b });
5184 return cg.finishAir(inst, result, &.{ extra.a, extra.b });
51875185 } else {
51885186 var operands = [_]u32{
51895187 @intFromEnum(std.wasm.SimdOpcode.i8x16_shuffle),
......@@ -5202,91 +5200,91 @@ fn airShuffle(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
52025200 }
52035201 }
52045202
5205 try func.emitWValue(a);
5206 try func.emitWValue(b);
5203 try cg.emitWValue(a);
5204 try cg.emitWValue(b);
52075205
5208 const extra_index = @as(u32, @intCast(func.mir_extra.items.len));
5209 try func.mir_extra.appendSlice(func.gpa, &operands);
5210 try func.addInst(.{ .tag = .simd_prefix, .data = .{ .payload = extra_index } });
5206 const extra_index = @as(u32, @intCast(cg.mir_extra.items.len));
5207 try cg.mir_extra.appendSlice(cg.gpa, &operands);
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 });
52135211 }
52145212}
52155213
5216fn airReduce(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
5217 const reduce = func.air.instructions.items(.data)[@intFromEnum(inst)].reduce;
5218 const operand = try func.resolveInst(reduce.operand);
5214fn airReduce(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
5215 const reduce = cg.air.instructions.items(.data)[@intFromEnum(inst)].reduce;
5216 const operand = try cg.resolveInst(reduce.operand);
52195217
52205218 _ = operand;
5221 return func.fail("TODO: Implement wasm airReduce", .{});
5219 return cg.fail("TODO: Implement wasm airReduce", .{});
52225220}
52235221
5224fn airAggregateInit(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
5225 const pt = func.pt;
5222fn airAggregateInit(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
5223 const pt = cg.pt;
52265224 const zcu = pt.zcu;
52275225 const ip = &zcu.intern_pool;
5228 const ty_pl = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
5229 const result_ty = func.typeOfIndex(inst);
5226 const ty_pl = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
5227 const result_ty = cg.typeOfIndex(inst);
52305228 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
52335231 const result: WValue = result_value: {
52345232 switch (result_ty.zigTypeTag(zcu)) {
52355233 .array => {
5236 const result = try func.allocStack(result_ty);
5234 const result = try cg.allocStack(result_ty);
52375235 const elem_ty = result_ty.childType(zcu);
52385236 const elem_size = @as(u32, @intCast(elem_ty.abiSize(zcu)));
52395237 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);
52415239 } else null;
52425240
52435241 // When the element type is by reference, we must copy the entire
52445242 // value. It is therefore safer to move the offset pointer and store
52455243 // each value individually, instead of using store offsets.
5246 if (isByRef(elem_ty, pt, func.target)) {
5244 if (isByRef(elem_ty, pt, cg.target)) {
52475245 // copy stack pointer into a temporary local, which is
52485246 // 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);
52505248 for (elements, 0..) |elem, elem_index| {
5251 const elem_val = try func.resolveInst(elem);
5252 try func.store(offset, elem_val, elem_ty, 0);
5249 const elem_val = try cg.resolveInst(elem);
5250 try cg.store(offset, elem_val, elem_ty, 0);
52535251
52545252 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);
52565254 }
52575255 }
52585256 if (sentinel) |sent| {
5259 try func.store(offset, sent, elem_ty, 0);
5257 try cg.store(offset, sent, elem_ty, 0);
52605258 }
52615259 } else {
52625260 var offset: u32 = 0;
52635261 for (elements) |elem| {
5264 const elem_val = try func.resolveInst(elem);
5265 try func.store(result, elem_val, elem_ty, offset);
5262 const elem_val = try cg.resolveInst(elem);
5263 try cg.store(result, elem_val, elem_ty, offset);
52665264 offset += elem_size;
52675265 }
52685266 if (sentinel) |sent| {
5269 try func.store(result, sent, elem_ty, offset);
5267 try cg.store(result, sent, elem_ty, offset);
52705268 }
52715269 }
52725270 break :result_value result;
52735271 },
52745272 .@"struct" => switch (result_ty.containerLayout(zcu)) {
52755273 .@"packed" => {
5276 if (isByRef(result_ty, pt, func.target)) {
5277 return func.fail("TODO: airAggregateInit for packed structs larger than 64 bits", .{});
5274 if (isByRef(result_ty, pt, cg.target)) {
5275 return cg.fail("TODO: airAggregateInit for packed structs larger than 64 bits", .{});
52785276 }
52795277 const packed_struct = zcu.typeToPackedStruct(result_ty).?;
52805278 const field_types = packed_struct.field_types;
52815279 const backing_type = Type.fromInterned(packed_struct.backingIntTypeUnordered(ip));
52825280
52835281 // ensure the result is zero'd
5284 const result = try func.allocLocal(backing_type);
5282 const result = try cg.allocLocal(backing_type);
52855283 if (backing_type.bitSize(zcu) <= 32)
5286 try func.addImm32(0)
5284 try cg.addImm32(0)
52875285 else
5288 try func.addImm64(0);
5289 try func.addLabel(.local_set, result.local.value);
5286 try cg.addImm64(0);
5287 try cg.addLabel(.local_set, result.local.value);
52905288
52915289 var current_bit: u16 = 0;
52925290 for (elements, 0..) |elem, elem_index| {
......@@ -5298,46 +5296,46 @@ fn airAggregateInit(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
52985296 else
52995297 .{ .imm64 = current_bit };
53005298
5301 const value = try func.resolveInst(elem);
5299 const value = try cg.resolveInst(elem);
53025300 const value_bit_size: u16 = @intCast(field_ty.bitSize(zcu));
53035301 const int_ty = try pt.intType(.unsigned, value_bit_size);
53045302
53055303 // load our current result on stack so we can perform all transformations
53065304 // using only stack values. Saving the cost of loads and stores.
5307 try func.emitWValue(result);
5308 const bitcasted = try func.bitcast(int_ty, field_ty, value);
5309 const extended_val = try func.intcast(bitcasted, int_ty, backing_type);
5305 try cg.emitWValue(result);
5306 const bitcasted = try cg.bitcast(int_ty, field_ty, value);
5307 const extended_val = try cg.intcast(bitcasted, int_ty, backing_type);
53105308 // no need to shift any values when the current offset is 0
53115309 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);
53135311 } else extended_val;
53145312 // 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");
5316 try func.addLabel(.local_set, result.local.value);
5313 _ = try cg.binOp(.stack, shifted, backing_type, .@"or");
5314 try cg.addLabel(.local_set, result.local.value);
53175315 current_bit += value_bit_size;
53185316 }
53195317 break :result_value result;
53205318 },
53215319 else => {
5322 const result = try func.allocStack(result_ty);
5323 const offset = try func.buildPointerOffset(result, 0, .new); // pointer to offset
5320 const result = try cg.allocStack(result_ty);
5321 const offset = try cg.buildPointerOffset(result, 0, .new); // pointer to offset
53245322 var prev_field_offset: u64 = 0;
53255323 for (elements, 0..) |elem, elem_index| {
53265324 if (try result_ty.structFieldValueComptime(pt, elem_index) != null) continue;
53275325
53285326 const elem_ty = result_ty.fieldType(elem_index, zcu);
53295327 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);
53315329 prev_field_offset = field_offset;
53325330
5333 const value = try func.resolveInst(elem);
5334 try func.store(offset, value, elem_ty, 0);
5331 const value = try cg.resolveInst(elem);
5332 try cg.store(offset, value, elem_ty, 0);
53355333 }
53365334
53375335 break :result_value result;
53385336 },
53395337 },
5340 .vector => return func.fail("TODO: Wasm backend: implement airAggregateInit for vectors", .{}),
5338 .vector => return cg.fail("TODO: Wasm backend: implement airAggregateInit for vectors", .{}),
53415339 else => unreachable,
53425340 }
53435341 };
......@@ -5345,22 +5343,22 @@ fn airAggregateInit(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
53455343 if (elements.len <= Liveness.bpi - 1) {
53465344 var buf = [1]Air.Inst.Ref{.none} ** (Liveness.bpi - 1);
53475345 @memcpy(buf[0..elements.len], elements);
5348 return func.finishAir(inst, result, &buf);
5346 return cg.finishAir(inst, result, &buf);
53495347 }
5350 var bt = try func.iterateBigTomb(inst, elements.len);
5348 var bt = try cg.iterateBigTomb(inst, elements.len);
53515349 for (elements) |arg| bt.feed(arg);
53525350 return bt.finishAir(result);
53535351}
53545352
5355fn airUnionInit(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
5356 const pt = func.pt;
5353fn airUnionInit(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
5354 const pt = cg.pt;
53575355 const zcu = pt.zcu;
53585356 const ip = &zcu.intern_pool;
5359 const ty_pl = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
5360 const extra = func.air.extraData(Air.UnionInit, ty_pl.payload).data;
5357 const ty_pl = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
5358 const extra = cg.air.extraData(Air.UnionInit, ty_pl.payload).data;
53615359
53625360 const result = result: {
5363 const union_ty = func.typeOfIndex(inst);
5361 const union_ty = cg.typeOfIndex(inst);
53645362 const layout = union_ty.unionGetLayout(zcu);
53655363 const union_obj = zcu.typeToUnion(union_ty).?;
53665364 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 {
53705368 const tag_ty = union_ty.unionTagTypeHypothetical(zcu);
53715369 const enum_field_index = tag_ty.enumFieldIndex(field_name, zcu).?;
53725370 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);
53745372 };
53755373 if (layout.payload_size == 0) {
53765374 if (layout.tag_size == 0) {
53775375 break :result .none;
53785376 }
5379 assert(!isByRef(union_ty, pt, func.target));
5377 assert(!isByRef(union_ty, pt, cg.target));
53805378 break :result tag_int;
53815379 }
53825380
5383 if (isByRef(union_ty, pt, func.target)) {
5384 const result_ptr = try func.allocStack(union_ty);
5385 const payload = try func.resolveInst(extra.init);
5381 if (isByRef(union_ty, pt, cg.target)) {
5382 const result_ptr = try cg.allocStack(union_ty);
5383 const payload = try cg.resolveInst(extra.init);
53865384 if (layout.tag_align.compare(.gte, layout.payload_align)) {
5387 if (isByRef(field_ty, pt, func.target)) {
5388 const payload_ptr = try func.buildPointerOffset(result_ptr, layout.tag_size, .new);
5389 try func.store(payload_ptr, payload, field_ty, 0);
5385 if (isByRef(field_ty, pt, cg.target)) {
5386 const payload_ptr = try cg.buildPointerOffset(result_ptr, layout.tag_size, .new);
5387 try cg.store(payload_ptr, payload, field_ty, 0);
53905388 } 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));
53925390 }
53935391
53945392 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);
53965394 }
53975395 } else {
5398 try func.store(result_ptr, payload, field_ty, 0);
5396 try cg.store(result_ptr, payload, field_ty, 0);
53995397 if (layout.tag_size > 0) {
5400 try func.store(
5398 try cg.store(
54015399 result_ptr,
54025400 tag_int,
54035401 Type.fromInterned(union_obj.enum_tag_ty),
......@@ -5407,46 +5405,46 @@ fn airUnionInit(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
54075405 }
54085406 break :result result_ptr;
54095407 } else {
5410 const operand = try func.resolveInst(extra.init);
5408 const operand = try cg.resolveInst(extra.init);
54115409 const union_int_type = try pt.intType(.unsigned, @as(u16, @intCast(union_ty.bitSize(zcu))));
54125410 if (field_ty.zigTypeTag(zcu) == .float) {
54135411 const int_type = try pt.intType(.unsigned, @intCast(field_ty.bitSize(zcu)));
5414 const bitcasted = try func.bitcast(field_ty, int_type, operand);
5415 break :result try func.trunc(bitcasted, int_type, union_int_type);
5412 const bitcasted = try cg.bitcast(field_ty, int_type, operand);
5413 break :result try cg.trunc(bitcasted, int_type, union_int_type);
54165414 } else if (field_ty.isPtrAtRuntime(zcu)) {
54175415 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);
54195417 }
5420 break :result try func.intcast(operand, field_ty, union_int_type);
5418 break :result try cg.intcast(operand, field_ty, union_int_type);
54215419 }
54225420 };
54235421
5424 return func.finishAir(inst, result, &.{extra.init});
5422 return cg.finishAir(inst, result, &.{extra.init});
54255423}
54265424
5427fn airPrefetch(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
5428 const prefetch = func.air.instructions.items(.data)[@intFromEnum(inst)].prefetch;
5429 return func.finishAir(inst, .none, &.{prefetch.ptr});
5425fn airPrefetch(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
5426 const prefetch = cg.air.instructions.items(.data)[@intFromEnum(inst)].prefetch;
5427 return cg.finishAir(inst, .none, &.{prefetch.ptr});
54305428}
54315429
5432fn airWasmMemorySize(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
5433 const pl_op = func.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;
5430fn airWasmMemorySize(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
5431 const pl_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;
54345432
5435 try func.addLabel(.memory_size, pl_op.payload);
5436 return func.finishAir(inst, .stack, &.{pl_op.operand});
5433 try cg.addLabel(.memory_size, pl_op.payload);
5434 return cg.finishAir(inst, .stack, &.{pl_op.operand});
54375435}
54385436
5439fn airWasmMemoryGrow(func: *CodeGen, inst: Air.Inst.Index) !void {
5440 const pl_op = func.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;
5437fn airWasmMemoryGrow(cg: *CodeGen, inst: Air.Inst.Index) !void {
5438 const pl_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;
54415439
5442 const operand = try func.resolveInst(pl_op.operand);
5443 try func.emitWValue(operand);
5444 try func.addLabel(.memory_grow, pl_op.payload);
5445 return func.finishAir(inst, .stack, &.{pl_op.operand});
5440 const operand = try cg.resolveInst(pl_op.operand);
5441 try cg.emitWValue(operand);
5442 try cg.addLabel(.memory_grow, pl_op.payload);
5443 return cg.finishAir(inst, .stack, &.{pl_op.operand});
54465444}
54475445
5448fn cmpOptionals(func: *CodeGen, lhs: WValue, rhs: WValue, operand_ty: Type, op: std.math.CompareOperator) InnerError!WValue {
5449 const pt = func.pt;
5446fn cmpOptionals(cg: *CodeGen, lhs: WValue, rhs: WValue, operand_ty: Type, op: std.math.CompareOperator) InnerError!WValue {
5447 const pt = cg.pt;
54505448 const zcu = pt.zcu;
54515449 assert(operand_ty.hasRuntimeBitsIgnoreComptime(zcu));
54525450 assert(op == .eq or op == .neq);
......@@ -5454,91 +5452,91 @@ fn cmpOptionals(func: *CodeGen, lhs: WValue, rhs: WValue, operand_ty: Type, op:
54545452
54555453 // We store the final result in here that will be validated
54565454 // if the optional is truly equal.
5457 var result = try func.ensureAllocLocal(Type.i32);
5458 defer result.free(func);
5459
5460 try func.startBlock(.block, std.wasm.block_empty);
5461 _ = try func.isNull(lhs, operand_ty, .i32_eq);
5462 _ = try func.isNull(rhs, operand_ty, .i32_eq);
5463 try func.addTag(.i32_ne); // inverse so we can exit early
5464 try func.addLabel(.br_if, 0);
5465
5466 _ = try func.load(lhs, payload_ty, 0);
5467 _ = try func.load(rhs, payload_ty, 0);
5468 const opcode = buildOpcode(.{ .op = .ne, .valtype1 = typeToValtype(payload_ty, pt, func.target) });
5469 try func.addTag(Mir.Inst.Tag.fromOpcode(opcode));
5470 try func.addLabel(.br_if, 0);
5471
5472 try func.addImm32(1);
5473 try func.addLabel(.local_set, result.local.value);
5474 try func.endBlock();
5475
5476 try func.emitWValue(result);
5477 try func.addImm32(0);
5478 try func.addTag(if (op == .eq) .i32_ne else .i32_eq);
5455 var result = try cg.ensureAllocLocal(Type.i32);
5456 defer result.free(cg);
5457
5458 try cg.startBlock(.block, std.wasm.block_empty);
5459 _ = try cg.isNull(lhs, operand_ty, .i32_eq);
5460 _ = try cg.isNull(rhs, operand_ty, .i32_eq);
5461 try cg.addTag(.i32_ne); // inverse so we can exit early
5462 try cg.addLabel(.br_if, 0);
5463
5464 _ = try cg.load(lhs, payload_ty, 0);
5465 _ = try cg.load(rhs, payload_ty, 0);
5466 const opcode = buildOpcode(.{ .op = .ne, .valtype1 = typeToValtype(payload_ty, pt, cg.target) });
5467 try cg.addTag(Mir.Inst.Tag.fromOpcode(opcode));
5468 try cg.addLabel(.br_if, 0);
5469
5470 try cg.addImm32(1);
5471 try cg.addLabel(.local_set, result.local.value);
5472 try cg.endBlock();
5473
5474 try cg.emitWValue(result);
5475 try cg.addImm32(0);
5476 try cg.addTag(if (op == .eq) .i32_ne else .i32_eq);
54795477 return .stack;
54805478}
54815479
54825480/// Compares big integers by checking both its high bits and low bits.
54835481/// NOTE: Leaves the result of the comparison on top of the stack.
54845482/// 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 {
5486 const pt = func.pt;
5483fn cmpBigInt(cg: *CodeGen, lhs: WValue, rhs: WValue, operand_ty: Type, op: std.math.CompareOperator) InnerError!WValue {
5484 const pt = cg.pt;
54875485 const zcu = pt.zcu;
54885486 assert(operand_ty.abiSize(zcu) >= 16);
54895487 assert(!(lhs != .stack and rhs == .stack));
54905488 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)});
54925490 }
54935491
5494 var lhs_msb = try (try func.load(lhs, Type.u64, 8)).toLocal(func, Type.u64);
5495 defer lhs_msb.free(func);
5496 var rhs_msb = try (try func.load(rhs, Type.u64, 8)).toLocal(func, Type.u64);
5497 defer rhs_msb.free(func);
5492 var lhs_msb = try (try cg.load(lhs, Type.u64, 8)).toLocal(cg, Type.u64);
5493 defer lhs_msb.free(cg);
5494 var rhs_msb = try (try cg.load(rhs, Type.u64, 8)).toLocal(cg, Type.u64);
5495 defer rhs_msb.free(cg);
54985496
54995497 switch (op) {
55005498 .eq, .neq => {
5501 const xor_high = try func.binOp(lhs_msb, rhs_msb, Type.u64, .xor);
5502 const lhs_lsb = try func.load(lhs, Type.u64, 0);
5503 const rhs_lsb = try func.load(rhs, Type.u64, 0);
5504 const xor_low = try func.binOp(lhs_lsb, rhs_lsb, Type.u64, .xor);
5505 const or_result = try func.binOp(xor_high, xor_low, Type.u64, .@"or");
5499 const xor_high = try cg.binOp(lhs_msb, rhs_msb, Type.u64, .xor);
5500 const lhs_lsb = try cg.load(lhs, Type.u64, 0);
5501 const rhs_lsb = try cg.load(rhs, Type.u64, 0);
5502 const xor_low = try cg.binOp(lhs_lsb, rhs_lsb, Type.u64, .xor);
5503 const or_result = try cg.binOp(xor_high, xor_low, Type.u64, .@"or");
55065504
55075505 switch (op) {
5508 .eq => return func.cmp(or_result, .{ .imm64 = 0 }, Type.u64, .eq),
5509 .neq => return func.cmp(or_result, .{ .imm64 = 0 }, Type.u64, .neq),
5506 .eq => return cg.cmp(or_result, .{ .imm64 = 0 }, Type.u64, .eq),
5507 .neq => return cg.cmp(or_result, .{ .imm64 = 0 }, Type.u64, .neq),
55105508 else => unreachable,
55115509 }
55125510 },
55135511 else => {
55145512 const ty = if (operand_ty.isSignedInt(zcu)) Type.i64 else Type.u64;
55155513 // leave those value on top of the stack for '.select'
5516 const lhs_lsb = try func.load(lhs, Type.u64, 0);
5517 const rhs_lsb = try func.load(rhs, Type.u64, 0);
5518 _ = try func.cmp(lhs_lsb, rhs_lsb, Type.u64, op);
5519 _ = try func.cmp(lhs_msb, rhs_msb, ty, op);
5520 _ = try func.cmp(lhs_msb, rhs_msb, ty, .eq);
5521 try func.addTag(.select);
5514 const lhs_lsb = try cg.load(lhs, Type.u64, 0);
5515 const rhs_lsb = try cg.load(rhs, Type.u64, 0);
5516 _ = try cg.cmp(lhs_lsb, rhs_lsb, Type.u64, op);
5517 _ = try cg.cmp(lhs_msb, rhs_msb, ty, op);
5518 _ = try cg.cmp(lhs_msb, rhs_msb, ty, .eq);
5519 try cg.addTag(.select);
55225520 },
55235521 }
55245522
55255523 return .stack;
55265524}
55275525
5528fn airSetUnionTag(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
5529 const pt = func.pt;
5526fn airSetUnionTag(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
5527 const pt = cg.pt;
55305528 const zcu = pt.zcu;
5531 const bin_op = func.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
5532 const un_ty = func.typeOf(bin_op.lhs).childType(zcu);
5533 const tag_ty = func.typeOf(bin_op.rhs);
5529 const bin_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
5530 const un_ty = cg.typeOf(bin_op.lhs).childType(zcu);
5531 const tag_ty = cg.typeOf(bin_op.rhs);
55345532 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);
5538 const new_tag = try func.resolveInst(bin_op.rhs);
5535 const union_ptr = try cg.resolveInst(bin_op.lhs);
5536 const new_tag = try cg.resolveInst(bin_op.rhs);
55395537 if (layout.payload_size == 0) {
5540 try func.store(union_ptr, new_tag, tag_ty, 0);
5541 return func.finishAir(inst, .none, &.{ bin_op.lhs, bin_op.rhs });
5538 try cg.store(union_ptr, new_tag, tag_ty, 0);
5539 return cg.finishAir(inst, .none, &.{ bin_op.lhs, bin_op.rhs });
55425540 }
55435541
55445542 // 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 {
55465544 const offset: u32 = if (layout.tag_align.compare(.lt, layout.payload_align)) blk: {
55475545 break :blk @intCast(layout.payload_size);
55485546 } else 0;
5549 try func.store(union_ptr, new_tag, tag_ty, offset);
5550 return func.finishAir(inst, .none, &.{ bin_op.lhs, bin_op.rhs });
5547 try cg.store(union_ptr, new_tag, tag_ty, offset);
5548 return cg.finishAir(inst, .none, &.{ bin_op.lhs, bin_op.rhs });
55515549}
55525550
5553fn airGetUnionTag(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
5554 const zcu = func.pt.zcu;
5555 const ty_op = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
5551fn airGetUnionTag(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
5552 const zcu = cg.pt.zcu;
5553 const ty_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
55565554
5557 const un_ty = func.typeOf(ty_op.operand);
5558 const tag_ty = func.typeOfIndex(inst);
5555 const un_ty = cg.typeOf(ty_op.operand);
5556 const tag_ty = cg.typeOfIndex(inst);
55595557 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);
55635561 // when the tag alignment is smaller than the payload, the field will be stored
55645562 // after the payload.
55655563 const offset: u32 = if (layout.tag_align.compare(.lt, layout.payload_align))
55665564 @intCast(layout.payload_size)
55675565 else
55685566 0;
5569 const result = try func.load(operand, tag_ty, offset);
5570 return func.finishAir(inst, result, &.{ty_op.operand});
5567 const result = try cg.load(operand, tag_ty, offset);
5568 return cg.finishAir(inst, result, &.{ty_op.operand});
55715569}
55725570
5573fn airFpext(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
5574 const ty_op = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
5571fn airFpext(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
5572 const ty_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
55755573
5576 const dest_ty = func.typeOfIndex(inst);
5577 const operand = try func.resolveInst(ty_op.operand);
5578 const result = try func.fpext(operand, func.typeOf(ty_op.operand), dest_ty);
5579 return func.finishAir(inst, result, &.{ty_op.operand});
5574 const dest_ty = cg.typeOfIndex(inst);
5575 const operand = try cg.resolveInst(ty_op.operand);
5576 const result = try cg.fpext(operand, cg.typeOf(ty_op.operand), dest_ty);
5577 return cg.finishAir(inst, result, &.{ty_op.operand});
55805578}
55815579
55825580/// Extends a float from a given `Type` to a larger wanted `Type`
55835581/// NOTE: Leaves the result on the stack
5584fn fpext(func: *CodeGen, operand: WValue, given: Type, wanted: Type) InnerError!WValue {
5585 const given_bits = given.floatBits(func.target.*);
5586 const wanted_bits = wanted.floatBits(func.target.*);
5582fn fpext(cg: *CodeGen, operand: WValue, given: Type, wanted: Type) InnerError!WValue {
5583 const given_bits = given.floatBits(cg.target.*);
5584 const wanted_bits = wanted.floatBits(cg.target.*);
55875585
55885586 if (wanted_bits == 64 and given_bits == 32) {
5589 try func.emitWValue(operand);
5590 try func.addTag(.f64_promote_f32);
5587 try cg.emitWValue(operand);
5588 try cg.addTag(.f64_promote_f32);
55915589 return .stack;
55925590 } else if (given_bits == 16 and wanted_bits <= 64) {
55935591 // call __extendhfsf2(f16) f32
5594 const f32_result = try func.callIntrinsic(
5592 const f32_result = try cg.callIntrinsic(
55955593 "__extendhfsf2",
55965594 &.{.f16_type},
55975595 Type.f32,
......@@ -5600,7 +5598,7 @@ fn fpext(func: *CodeGen, operand: WValue, given: Type, wanted: Type) InnerError!
56005598 assert(f32_result == .stack);
56015599
56025600 if (wanted_bits == 64) {
5603 try func.addTag(.f64_promote_f32);
5601 try cg.addTag(.f64_promote_f32);
56045602 }
56055603 return .stack;
56065604 }
......@@ -5611,37 +5609,37 @@ fn fpext(func: *CodeGen, operand: WValue, given: Type, wanted: Type) InnerError!
56115609 target_util.compilerRtFloatAbbrev(wanted_bits),
56125610 }) 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});
56155613}
56165614
5617fn airFptrunc(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
5618 const ty_op = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
5615fn airFptrunc(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
5616 const ty_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
56195617
5620 const dest_ty = func.typeOfIndex(inst);
5621 const operand = try func.resolveInst(ty_op.operand);
5622 const result = try func.fptrunc(operand, func.typeOf(ty_op.operand), dest_ty);
5623 return func.finishAir(inst, result, &.{ty_op.operand});
5618 const dest_ty = cg.typeOfIndex(inst);
5619 const operand = try cg.resolveInst(ty_op.operand);
5620 const result = try cg.fptrunc(operand, cg.typeOf(ty_op.operand), dest_ty);
5621 return cg.finishAir(inst, result, &.{ty_op.operand});
56245622}
56255623
56265624/// Truncates a float from a given `Type` to its wanted `Type`
56275625/// NOTE: The result value remains on the stack
5628fn fptrunc(func: *CodeGen, operand: WValue, given: Type, wanted: Type) InnerError!WValue {
5629 const given_bits = given.floatBits(func.target.*);
5630 const wanted_bits = wanted.floatBits(func.target.*);
5626fn fptrunc(cg: *CodeGen, operand: WValue, given: Type, wanted: Type) InnerError!WValue {
5627 const given_bits = given.floatBits(cg.target.*);
5628 const wanted_bits = wanted.floatBits(cg.target.*);
56315629
56325630 if (wanted_bits == 32 and given_bits == 64) {
5633 try func.emitWValue(operand);
5634 try func.addTag(.f32_demote_f64);
5631 try cg.emitWValue(operand);
5632 try cg.addTag(.f32_demote_f64);
56355633 return .stack;
56365634 } else if (wanted_bits == 16 and given_bits <= 64) {
56375635 const op: WValue = if (given_bits == 64) blk: {
5638 try func.emitWValue(operand);
5639 try func.addTag(.f32_demote_f64);
5636 try cg.emitWValue(operand);
5637 try cg.addTag(.f32_demote_f64);
56405638 break :blk .stack;
56415639 } else operand;
56425640
56435641 // call __truncsfhf2(f32) f16
5644 return func.callIntrinsic("__truncsfhf2", &.{.f32_type}, Type.f16, &.{op});
5642 return cg.callIntrinsic("__truncsfhf2", &.{.f32_type}, Type.f16, &.{op});
56455643 }
56465644
56475645 var fn_name_buf: [12]u8 = undefined;
......@@ -5650,20 +5648,20 @@ fn fptrunc(func: *CodeGen, operand: WValue, given: Type, wanted: Type) InnerErro
56505648 target_util.compilerRtFloatAbbrev(wanted_bits),
56515649 }) 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});
56545652}
56555653
5656fn airErrUnionPayloadPtrSet(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
5657 const pt = func.pt;
5654fn airErrUnionPayloadPtrSet(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
5655 const pt = cg.pt;
56585656 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);
56625660 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
56655663 // set error-tag to '0' to annotate error union is non-error
5666 try func.store(
5664 try cg.store(
56675665 operand,
56685666 .{ .imm32 = 0 },
56695667 Type.anyerror,
......@@ -5672,63 +5670,63 @@ fn airErrUnionPayloadPtrSet(func: *CodeGen, inst: Air.Inst.Index) InnerError!voi
56725670
56735671 const result = result: {
56745672 if (!payload_ty.hasRuntimeBitsIgnoreComptime(zcu)) {
5675 break :result func.reuseOperand(ty_op.operand, operand);
5673 break :result cg.reuseOperand(ty_op.operand, operand);
56765674 }
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);
56795677 };
5680 return func.finishAir(inst, result, &.{ty_op.operand});
5678 return cg.finishAir(inst, result, &.{ty_op.operand});
56815679}
56825680
5683fn airFieldParentPtr(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
5684 const pt = func.pt;
5681fn airFieldParentPtr(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
5682 const pt = cg.pt;
56855683 const zcu = pt.zcu;
5686 const ty_pl = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
5687 const extra = func.air.extraData(Air.FieldParentPtr, ty_pl.payload).data;
5684 const ty_pl = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
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);
56905688 const parent_ty = ty_pl.ty.toType().childType(zcu);
56915689 const field_offset = parent_ty.structFieldOffset(extra.field_index, zcu);
56925690
56935691 const result = if (field_offset != 0) result: {
5694 const base = try func.buildPointerOffset(field_ptr, 0, .new);
5695 try func.addLabel(.local_get, base.local.value);
5696 try func.addImm32(@intCast(field_offset));
5697 try func.addTag(.i32_sub);
5698 try func.addLabel(.local_set, base.local.value);
5692 const base = try cg.buildPointerOffset(field_ptr, 0, .new);
5693 try cg.addLabel(.local_get, base.local.value);
5694 try cg.addImm32(@intCast(field_offset));
5695 try cg.addTag(.i32_sub);
5696 try cg.addLabel(.local_set, base.local.value);
56995697 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});
57035701}
57045702
5705fn sliceOrArrayPtr(func: *CodeGen, ptr: WValue, ptr_ty: Type) InnerError!WValue {
5706 const pt = func.pt;
5703fn sliceOrArrayPtr(cg: *CodeGen, ptr: WValue, ptr_ty: Type) InnerError!WValue {
5704 const pt = cg.pt;
57075705 const zcu = pt.zcu;
57085706 if (ptr_ty.isSlice(zcu)) {
5709 return func.slicePtr(ptr);
5707 return cg.slicePtr(ptr);
57105708 } else {
57115709 return ptr;
57125710 }
57135711}
57145712
5715fn airMemcpy(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
5716 const pt = func.pt;
5713fn airMemcpy(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
5714 const pt = cg.pt;
57175715 const zcu = pt.zcu;
5718 const bin_op = func.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
5719 const dst = try func.resolveInst(bin_op.lhs);
5720 const dst_ty = func.typeOf(bin_op.lhs);
5716 const bin_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
5717 const dst = try cg.resolveInst(bin_op.lhs);
5718 const dst_ty = cg.typeOf(bin_op.lhs);
57215719 const ptr_elem_ty = dst_ty.childType(zcu);
5722 const src = try func.resolveInst(bin_op.rhs);
5723 const src_ty = func.typeOf(bin_op.rhs);
5720 const src = try cg.resolveInst(bin_op.rhs);
5721 const src_ty = cg.typeOf(bin_op.rhs);
57245722 const len = switch (dst_ty.ptrSize(zcu)) {
57255723 .Slice => blk: {
5726 const slice_len = try func.sliceLen(dst);
5724 const slice_len = try cg.sliceLen(dst);
57275725 if (ptr_elem_ty.abiSize(zcu) != 1) {
5728 try func.emitWValue(slice_len);
5729 try func.emitWValue(.{ .imm32 = @as(u32, @intCast(ptr_elem_ty.abiSize(zcu))) });
5730 try func.addTag(.i32_mul);
5731 try func.addLabel(.local_set, slice_len.local.value);
5726 try cg.emitWValue(slice_len);
5727 try cg.emitWValue(.{ .imm32 = @as(u32, @intCast(ptr_elem_ty.abiSize(zcu))) });
5728 try cg.addTag(.i32_mul);
5729 try cg.addLabel(.local_set, slice_len.local.value);
57325730 }
57335731 break :blk slice_len;
57345732 },
......@@ -5737,94 +5735,94 @@ fn airMemcpy(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
57375735 }),
57385736 .C, .Many => unreachable,
57395737 };
5740 const dst_ptr = try func.sliceOrArrayPtr(dst, dst_ty);
5741 const src_ptr = try func.sliceOrArrayPtr(src, src_ty);
5742 try func.memcpy(dst_ptr, src_ptr, len);
5738 const dst_ptr = try cg.sliceOrArrayPtr(dst, dst_ty);
5739 const src_ptr = try cg.sliceOrArrayPtr(src, src_ty);
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 });
57455743}
57465744
5747fn airRetAddr(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
5745fn airRetAddr(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
57485746 // 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) {
57505748 .wasm32 => .{ .imm32 = 0 },
57515749 .wasm64 => .{ .imm64 = 0 },
57525750 }, &.{});
57535751}
57545752
5755fn airPopcount(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
5756 const pt = func.pt;
5753fn airPopcount(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
5754 const pt = cg.pt;
57575755 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);
5761 const op_ty = func.typeOf(ty_op.operand);
5758 const operand = try cg.resolveInst(ty_op.operand);
5759 const op_ty = cg.typeOf(ty_op.operand);
57625760
57635761 if (op_ty.zigTypeTag(zcu) == .vector) {
5764 return func.fail("TODO: Implement @popCount for vectors", .{});
5762 return cg.fail("TODO: Implement @popCount for vectors", .{});
57655763 }
57665764
57675765 const int_info = op_ty.intInfo(zcu);
57685766 const bits = int_info.bits;
57695767 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});
57715769 };
57725770
57735771 switch (wasm_bits) {
57745772 32 => {
5775 try func.emitWValue(operand);
5773 try cg.emitWValue(operand);
57765774 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));
57785776 }
5779 try func.addTag(.i32_popcnt);
5777 try cg.addTag(.i32_popcnt);
57805778 },
57815779 64 => {
5782 try func.emitWValue(operand);
5780 try cg.emitWValue(operand);
57835781 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));
57855783 }
5786 try func.addTag(.i64_popcnt);
5787 try func.addTag(.i32_wrap_i64);
5788 try func.emitWValue(operand);
5784 try cg.addTag(.i64_popcnt);
5785 try cg.addTag(.i32_wrap_i64);
5786 try cg.emitWValue(operand);
57895787 },
57905788 128 => {
5791 _ = try func.load(operand, Type.u64, 0);
5792 try func.addTag(.i64_popcnt);
5793 _ = try func.load(operand, Type.u64, 8);
5789 _ = try cg.load(operand, Type.u64, 0);
5790 try cg.addTag(.i64_popcnt);
5791 _ = try cg.load(operand, Type.u64, 8);
57945792 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));
57965794 }
5797 try func.addTag(.i64_popcnt);
5798 try func.addTag(.i64_add);
5799 try func.addTag(.i32_wrap_i64);
5795 try cg.addTag(.i64_popcnt);
5796 try cg.addTag(.i64_add);
5797 try cg.addTag(.i32_wrap_i64);
58005798 },
58015799 else => unreachable,
58025800 }
58035801
5804 return func.finishAir(inst, .stack, &.{ty_op.operand});
5802 return cg.finishAir(inst, .stack, &.{ty_op.operand});
58055803}
58065804
5807fn airBitReverse(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
5808 const pt = func.pt;
5805fn airBitReverse(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
5806 const pt = cg.pt;
58095807 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);
5813 const ty = func.typeOf(ty_op.operand);
5810 const operand = try cg.resolveInst(ty_op.operand);
5811 const ty = cg.typeOf(ty_op.operand);
58145812
58155813 if (ty.zigTypeTag(zcu) == .vector) {
5816 return func.fail("TODO: Implement @bitReverse for vectors", .{});
5814 return cg.fail("TODO: Implement @bitReverse for vectors", .{});
58175815 }
58185816
58195817 const int_info = ty.intInfo(zcu);
58205818 const bits = int_info.bits;
58215819 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});
58235821 };
58245822
58255823 switch (wasm_bits) {
58265824 32 => {
5827 const intrin_ret = try func.callIntrinsic(
5825 const intrin_ret = try cg.callIntrinsic(
58285826 "__bitreversesi2",
58295827 &.{.u32_type},
58305828 Type.u32,
......@@ -5833,11 +5831,11 @@ fn airBitReverse(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
58335831 const result = if (bits == 32)
58345832 intrin_ret
58355833 else
5836 try func.binOp(intrin_ret, .{ .imm32 = 32 - bits }, ty, .shr);
5837 return func.finishAir(inst, result, &.{ty_op.operand});
5834 try cg.binOp(intrin_ret, .{ .imm32 = 32 - bits }, ty, .shr);
5835 return cg.finishAir(inst, result, &.{ty_op.operand});
58385836 },
58395837 64 => {
5840 const intrin_ret = try func.callIntrinsic(
5838 const intrin_ret = try cg.callIntrinsic(
58415839 "__bitreversedi2",
58425840 &.{.u64_type},
58435841 Type.u64,
......@@ -5846,64 +5844,64 @@ fn airBitReverse(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
58465844 const result = if (bits == 64)
58475845 intrin_ret
58485846 else
5849 try func.binOp(intrin_ret, .{ .imm64 = 64 - bits }, ty, .shr);
5850 return func.finishAir(inst, result, &.{ty_op.operand});
5847 try cg.binOp(intrin_ret, .{ .imm64 = 64 - bits }, ty, .shr);
5848 return cg.finishAir(inst, result, &.{ty_op.operand});
58515849 },
58525850 128 => {
5853 const result = try func.allocStack(ty);
5851 const result = try cg.allocStack(ty);
58545852
5855 try func.emitWValue(result);
5856 const first_half = try func.load(operand, Type.u64, 8);
5857 const intrin_ret_first = try func.callIntrinsic(
5853 try cg.emitWValue(result);
5854 const first_half = try cg.load(operand, Type.u64, 8);
5855 const intrin_ret_first = try cg.callIntrinsic(
58585856 "__bitreversedi2",
58595857 &.{.u64_type},
58605858 Type.u64,
58615859 &.{first_half},
58625860 );
5863 try func.emitWValue(intrin_ret_first);
5861 try cg.emitWValue(intrin_ret_first);
58645862 if (bits < 128) {
5865 try func.emitWValue(.{ .imm64 = 128 - bits });
5866 try func.addTag(.i64_shr_u);
5863 try cg.emitWValue(.{ .imm64 = 128 - bits });
5864 try cg.addTag(.i64_shr_u);
58675865 }
5868 try func.emitWValue(result);
5869 const second_half = try func.load(operand, Type.u64, 0);
5870 const intrin_ret_second = try func.callIntrinsic(
5866 try cg.emitWValue(result);
5867 const second_half = try cg.load(operand, Type.u64, 0);
5868 const intrin_ret_second = try cg.callIntrinsic(
58715869 "__bitreversedi2",
58725870 &.{.u64_type},
58735871 Type.u64,
58745872 &.{second_half},
58755873 );
5876 try func.emitWValue(intrin_ret_second);
5874 try cg.emitWValue(intrin_ret_second);
58775875 if (bits == 128) {
5878 try func.store(.stack, .stack, Type.u64, result.offset() + 8);
5879 try func.store(.stack, .stack, Type.u64, result.offset());
5876 try cg.store(.stack, .stack, Type.u64, result.offset() + 8);
5877 try cg.store(.stack, .stack, Type.u64, result.offset());
58805878 } else {
5881 var tmp = try func.allocLocal(Type.u64);
5882 defer tmp.free(func);
5883 try func.addLabel(.local_tee, tmp.local.value);
5884 try func.emitWValue(.{ .imm64 = 128 - bits });
5879 var tmp = try cg.allocLocal(Type.u64);
5880 defer tmp.free(cg);
5881 try cg.addLabel(.local_tee, tmp.local.value);
5882 try cg.emitWValue(.{ .imm64 = 128 - bits });
58855883 if (ty.isSignedInt(zcu)) {
5886 try func.addTag(.i64_shr_s);
5884 try cg.addTag(.i64_shr_s);
58875885 } else {
5888 try func.addTag(.i64_shr_u);
5886 try cg.addTag(.i64_shr_u);
58895887 }
5890 try func.store(.stack, .stack, Type.u64, result.offset() + 8);
5891 try func.addLabel(.local_get, tmp.local.value);
5892 try func.emitWValue(.{ .imm64 = bits - 64 });
5893 try func.addTag(.i64_shl);
5894 try func.addTag(.i64_or);
5895 try func.store(.stack, .stack, Type.u64, result.offset());
5888 try cg.store(.stack, .stack, Type.u64, result.offset() + 8);
5889 try cg.addLabel(.local_get, tmp.local.value);
5890 try cg.emitWValue(.{ .imm64 = bits - 64 });
5891 try cg.addTag(.i64_shl);
5892 try cg.addTag(.i64_or);
5893 try cg.store(.stack, .stack, Type.u64, result.offset());
58965894 }
5897 return func.finishAir(inst, result, &.{ty_op.operand});
5895 return cg.finishAir(inst, result, &.{ty_op.operand});
58985896 },
58995897 else => unreachable,
59005898 }
59015899}
59025900
5903fn airErrorName(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
5904 const un_op = func.air.instructions.items(.data)[@intFromEnum(inst)].un_op;
5901fn airErrorName(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
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);
59075905 // First retrieve the symbol index to the error name table
59085906 // that will be used to emit a relocation for the pointer
59095907 // to the error name table.
......@@ -5915,81 +5913,81 @@ fn airErrorName(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
59155913 //
59165914 // As the names are global and the slice elements are constant, we do not have
59175915 // to make a copy of the ptr+value but can point towards them directly.
5918 const pt = func.pt;
5919 const error_table_symbol = try func.wasm.getErrorTableSymbol(pt);
5916 const pt = cg.pt;
5917 const error_table_symbol = try cg.wasm.getErrorTableSymbol(pt);
59205918 const name_ty = Type.slice_const_u8_sentinel_0;
59215919 const abi_size = name_ty.abiSize(pt.zcu);
59225920
59235921 const error_name_value: WValue = .{ .memory = error_table_symbol }; // emitting this will create a relocation
5924 try func.emitWValue(error_name_value);
5925 try func.emitWValue(operand);
5926 switch (func.ptr_size) {
5922 try cg.emitWValue(error_name_value);
5923 try cg.emitWValue(operand);
5924 switch (cg.ptr_size) {
59275925 .wasm32 => {
5928 try func.addImm32(@intCast(abi_size));
5929 try func.addTag(.i32_mul);
5930 try func.addTag(.i32_add);
5926 try cg.addImm32(@intCast(abi_size));
5927 try cg.addTag(.i32_mul);
5928 try cg.addTag(.i32_add);
59315929 },
59325930 .wasm64 => {
5933 try func.addImm64(abi_size);
5934 try func.addTag(.i64_mul);
5935 try func.addTag(.i64_add);
5931 try cg.addImm64(abi_size);
5932 try cg.addTag(.i64_mul);
5933 try cg.addTag(.i64_add);
59365934 },
59375935 }
59385936
5939 return func.finishAir(inst, .stack, &.{un_op});
5937 return cg.finishAir(inst, .stack, &.{un_op});
59405938}
59415939
5942fn airPtrSliceFieldPtr(func: *CodeGen, inst: Air.Inst.Index, offset: u32) InnerError!void {
5943 const ty_op = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
5944 const slice_ptr = try func.resolveInst(ty_op.operand);
5945 const result = try func.buildPointerOffset(slice_ptr, offset, .new);
5946 return func.finishAir(inst, result, &.{ty_op.operand});
5940fn airPtrSliceFieldPtr(cg: *CodeGen, inst: Air.Inst.Index, offset: u32) InnerError!void {
5941 const ty_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
5942 const slice_ptr = try cg.resolveInst(ty_op.operand);
5943 const result = try cg.buildPointerOffset(slice_ptr, offset, .new);
5944 return cg.finishAir(inst, result, &.{ty_op.operand});
59475945}
59485946
59495947/// NOTE: Allocates place for result on virtual stack, when integer size > 64 bits
5950fn intZeroValue(func: *CodeGen, ty: Type) InnerError!WValue {
5951 const zcu = func.wasm.base.comp.zcu.?;
5948fn intZeroValue(cg: *CodeGen, ty: Type) InnerError!WValue {
5949 const zcu = cg.wasm.base.comp.zcu.?;
59525950 const int_info = ty.intInfo(zcu);
59535951 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});
59555953 };
59565954 switch (wasm_bits) {
59575955 32 => return .{ .imm32 = 0 },
59585956 64 => return .{ .imm64 = 0 },
59595957 128 => {
5960 const result = try func.allocStack(ty);
5961 try func.store(result, .{ .imm64 = 0 }, Type.u64, 0);
5962 try func.store(result, .{ .imm64 = 0 }, Type.u64, 8);
5958 const result = try cg.allocStack(ty);
5959 try cg.store(result, .{ .imm64 = 0 }, Type.u64, 0);
5960 try cg.store(result, .{ .imm64 = 0 }, Type.u64, 8);
59635961 return result;
59645962 },
59655963 else => unreachable,
59665964 }
59675965}
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 {
59705968 assert(op == .add or op == .sub);
5971 const ty_pl = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
5972 const extra = func.air.extraData(Air.Bin, ty_pl.payload).data;
5969 const ty_pl = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
5970 const extra = cg.air.extraData(Air.Bin, ty_pl.payload).data;
59735971
5974 const lhs = try func.resolveInst(extra.lhs);
5975 const rhs = try func.resolveInst(extra.rhs);
5976 const ty = func.typeOf(extra.lhs);
5977 const pt = func.pt;
5972 const lhs = try cg.resolveInst(extra.lhs);
5973 const rhs = try cg.resolveInst(extra.rhs);
5974 const ty = cg.typeOf(extra.lhs);
5975 const pt = cg.pt;
59785976 const zcu = pt.zcu;
59795977
59805978 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", .{});
59825980 }
59835981
59845982 const int_info = ty.intInfo(zcu);
59855983 const is_signed = int_info.signedness == .signed;
59865984 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});
59885986 }
59895987
5990 const op_result = try func.wrapBinOp(lhs, rhs, ty, op);
5991 var op_tmp = try op_result.toLocal(func, ty);
5992 defer op_tmp.free(func);
5988 const op_result = try cg.wrapBinOp(lhs, rhs, ty, op);
5989 var op_tmp = try op_result.toLocal(cg, ty);
5990 defer op_tmp.free(cg);
59935991
59945992 const cmp_op: std.math.CompareOperator = switch (op) {
59955993 .add => .lt,
......@@ -5997,40 +5995,40 @@ fn airAddSubWithOverflow(func: *CodeGen, inst: Air.Inst.Index, op: Op) InnerErro
59975995 else => unreachable,
59985996 };
59995997 const overflow_bit = if (is_signed) blk: {
6000 const zero = try intZeroValue(func, ty);
6001 const rhs_is_neg = try func.cmp(rhs, zero, ty, .lt);
6002 const overflow_cmp = try func.cmp(op_tmp, lhs, ty, cmp_op);
6003 break :blk try func.cmp(rhs_is_neg, overflow_cmp, Type.u1, .neq);
6004 } else try func.cmp(op_tmp, lhs, ty, cmp_op);
6005 var bit_tmp = try overflow_bit.toLocal(func, Type.u1);
6006 defer bit_tmp.free(func);
6007
6008 const result = try func.allocStack(func.typeOfIndex(inst));
5998 const zero = try intZeroValue(cg, ty);
5999 const rhs_is_neg = try cg.cmp(rhs, zero, ty, .lt);
6000 const overflow_cmp = try cg.cmp(op_tmp, lhs, ty, cmp_op);
6001 break :blk try cg.cmp(rhs_is_neg, overflow_cmp, Type.u1, .neq);
6002 } else try cg.cmp(op_tmp, lhs, ty, cmp_op);
6003 var bit_tmp = try overflow_bit.toLocal(cg, Type.u1);
6004 defer bit_tmp.free(cg);
6005
6006 const result = try cg.allocStack(cg.typeOfIndex(inst));
60096007 const offset: u32 = @intCast(ty.abiSize(zcu));
6010 try func.store(result, op_tmp, ty, 0);
6011 try func.store(result, bit_tmp, Type.u1, offset);
6008 try cg.store(result, op_tmp, ty, 0);
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 });
60146012}
60156013
6016fn airShlWithOverflow(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
6017 const pt = func.pt;
6014fn airShlWithOverflow(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
6015 const pt = cg.pt;
60186016 const zcu = pt.zcu;
6019 const ty_pl = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
6020 const extra = func.air.extraData(Air.Bin, ty_pl.payload).data;
6017 const ty_pl = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
6018 const extra = cg.air.extraData(Air.Bin, ty_pl.payload).data;
60216019
6022 const lhs = try func.resolveInst(extra.lhs);
6023 const rhs = try func.resolveInst(extra.rhs);
6024 const ty = func.typeOf(extra.lhs);
6025 const rhs_ty = func.typeOf(extra.rhs);
6020 const lhs = try cg.resolveInst(extra.lhs);
6021 const rhs = try cg.resolveInst(extra.rhs);
6022 const ty = cg.typeOf(extra.lhs);
6023 const rhs_ty = cg.typeOf(extra.rhs);
60266024
60276025 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", .{});
60296027 }
60306028
60316029 const int_info = ty.intInfo(zcu);
60326030 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});
60346032 };
60356033
60366034 // 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 {
60386036 const rhs_wasm_bits = toWasmBits(rhs_ty.intInfo(zcu).bits).?;
60396037 // If wasm_bits == 128, compiler-rt expects i32 for shift
60406038 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);
6042 break :blk try rhs_casted.toLocal(func, ty);
6039 const rhs_casted = try cg.intcast(rhs, rhs_ty, ty);
6040 break :blk try rhs_casted.toLocal(cg, ty);
60436041 } else rhs;
60446042
6045 var shl = try (try func.wrapBinOp(lhs, rhs_final, ty, .shl)).toLocal(func, ty);
6046 defer shl.free(func);
6043 var shl = try (try cg.wrapBinOp(lhs, rhs_final, ty, .shl)).toLocal(cg, ty);
6044 defer shl.free(cg);
60476045
60486046 const overflow_bit = blk: {
6049 const shr = try func.binOp(shl, rhs_final, ty, .shr);
6050 break :blk try func.cmp(shr, lhs, ty, .neq);
6047 const shr = try cg.binOp(shl, rhs_final, ty, .shr);
6048 break :blk try cg.cmp(shr, lhs, ty, .neq);
60516049 };
6052 var overflow_local = try overflow_bit.toLocal(func, Type.u1);
6053 defer overflow_local.free(func);
6050 var overflow_local = try overflow_bit.toLocal(cg, Type.u1);
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));
60566054 const offset: u32 = @intCast(ty.abiSize(zcu));
6057 try func.store(result, shl, ty, 0);
6058 try func.store(result, overflow_local, Type.u1, offset);
6055 try cg.store(result, shl, ty, 0);
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 });
60616059}
60626060
6063fn airMulWithOverflow(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
6064 const ty_pl = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
6065 const extra = func.air.extraData(Air.Bin, ty_pl.payload).data;
6061fn airMulWithOverflow(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
6062 const ty_pl = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
6063 const extra = cg.air.extraData(Air.Bin, ty_pl.payload).data;
60666064
6067 const lhs = try func.resolveInst(extra.lhs);
6068 const rhs = try func.resolveInst(extra.rhs);
6069 const ty = func.typeOf(extra.lhs);
6070 const pt = func.pt;
6065 const lhs = try cg.resolveInst(extra.lhs);
6066 const rhs = try cg.resolveInst(extra.rhs);
6067 const ty = cg.typeOf(extra.lhs);
6068 const pt = cg.pt;
60716069 const zcu = pt.zcu;
60726070
60736071 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", .{});
60756073 }
60766074
60776075 // We store the bit if it's overflowed or not in this. As it's zero-initialized
60786076 // we only need to update it if an overflow (or underflow) occurred.
6079 var overflow_bit = try func.ensureAllocLocal(Type.u1);
6080 defer overflow_bit.free(func);
6077 var overflow_bit = try cg.ensureAllocLocal(Type.u1);
6078 defer overflow_bit.free(cg);
60816079
60826080 const int_info = ty.intInfo(zcu);
60836081 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});
60856083 };
60866084
60876085 const zero: WValue = switch (wasm_bits) {
......@@ -6093,248 +6091,248 @@ fn airMulWithOverflow(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
60936091 // for 32 bit integers we upcast it to a 64bit integer
60946092 const mul = if (wasm_bits == 32) blk: {
60956093 const new_ty = if (int_info.signedness == .signed) Type.i64 else Type.u64;
6096 const lhs_upcast = try func.intcast(lhs, ty, new_ty);
6097 const rhs_upcast = try func.intcast(rhs, ty, new_ty);
6098 const bin_op = try (try func.binOp(lhs_upcast, rhs_upcast, new_ty, .mul)).toLocal(func, new_ty);
6099 const res = try (try func.trunc(bin_op, ty, new_ty)).toLocal(func, ty);
6100 const res_upcast = try func.intcast(res, ty, new_ty);
6101 _ = try func.cmp(res_upcast, bin_op, new_ty, .neq);
6102 try func.addLabel(.local_set, overflow_bit.local.value);
6094 const lhs_upcast = try cg.intcast(lhs, ty, new_ty);
6095 const rhs_upcast = try cg.intcast(rhs, ty, new_ty);
6096 const bin_op = try (try cg.binOp(lhs_upcast, rhs_upcast, new_ty, .mul)).toLocal(cg, new_ty);
6097 const res = try (try cg.trunc(bin_op, ty, new_ty)).toLocal(cg, ty);
6098 const res_upcast = try cg.intcast(res, ty, new_ty);
6099 _ = try cg.cmp(res_upcast, bin_op, new_ty, .neq);
6100 try cg.addLabel(.local_set, overflow_bit.local.value);
61036101 break :blk res;
61046102 } else if (wasm_bits == 64) blk: {
61056103 const new_ty = if (int_info.signedness == .signed) Type.i128 else Type.u128;
6106 const lhs_upcast = try func.intcast(lhs, ty, new_ty);
6107 const rhs_upcast = try func.intcast(rhs, ty, new_ty);
6108 const bin_op = try (try func.binOp(lhs_upcast, rhs_upcast, new_ty, .mul)).toLocal(func, new_ty);
6109 const res = try (try func.trunc(bin_op, ty, new_ty)).toLocal(func, ty);
6110 const res_upcast = try func.intcast(res, ty, new_ty);
6111 _ = try func.cmp(res_upcast, bin_op, new_ty, .neq);
6112 try func.addLabel(.local_set, overflow_bit.local.value);
6104 const lhs_upcast = try cg.intcast(lhs, ty, new_ty);
6105 const rhs_upcast = try cg.intcast(rhs, ty, new_ty);
6106 const bin_op = try (try cg.binOp(lhs_upcast, rhs_upcast, new_ty, .mul)).toLocal(cg, new_ty);
6107 const res = try (try cg.trunc(bin_op, ty, new_ty)).toLocal(cg, ty);
6108 const res_upcast = try cg.intcast(res, ty, new_ty);
6109 _ = try cg.cmp(res_upcast, bin_op, new_ty, .neq);
6110 try cg.addLabel(.local_set, overflow_bit.local.value);
61136111 break :blk res;
61146112 } 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);
6116 defer lhs_lsb.free(func);
6117 var lhs_msb = try (try func.load(lhs, Type.u64, 8)).toLocal(func, Type.u64);
6118 defer lhs_msb.free(func);
6119 var rhs_lsb = try (try func.load(rhs, Type.u64, 0)).toLocal(func, Type.u64);
6120 defer rhs_lsb.free(func);
6121 var rhs_msb = try (try func.load(rhs, Type.u64, 8)).toLocal(func, Type.u64);
6122 defer rhs_msb.free(func);
6123
6124 const cross_1 = try func.callIntrinsic(
6113 var lhs_lsb = try (try cg.load(lhs, Type.u64, 0)).toLocal(cg, Type.u64);
6114 defer lhs_lsb.free(cg);
6115 var lhs_msb = try (try cg.load(lhs, Type.u64, 8)).toLocal(cg, Type.u64);
6116 defer lhs_msb.free(cg);
6117 var rhs_lsb = try (try cg.load(rhs, Type.u64, 0)).toLocal(cg, Type.u64);
6118 defer rhs_lsb.free(cg);
6119 var rhs_msb = try (try cg.load(rhs, Type.u64, 8)).toLocal(cg, Type.u64);
6120 defer rhs_msb.free(cg);
6121
6122 const cross_1 = try cg.callIntrinsic(
61256123 "__multi3",
61266124 &[_]InternPool.Index{.i64_type} ** 4,
61276125 Type.i128,
61286126 &.{ lhs_msb, zero, rhs_lsb, zero },
61296127 );
6130 const cross_2 = try func.callIntrinsic(
6128 const cross_2 = try cg.callIntrinsic(
61316129 "__multi3",
61326130 &[_]InternPool.Index{.i64_type} ** 4,
61336131 Type.i128,
61346132 &.{ rhs_msb, zero, lhs_lsb, zero },
61356133 );
6136 const mul_lsb = try func.callIntrinsic(
6134 const mul_lsb = try cg.callIntrinsic(
61376135 "__multi3",
61386136 &[_]InternPool.Index{.i64_type} ** 4,
61396137 Type.i128,
61406138 &.{ rhs_lsb, zero, lhs_lsb, zero },
61416139 );
61426140
6143 const rhs_msb_not_zero = try func.cmp(rhs_msb, zero, Type.u64, .neq);
6144 const lhs_msb_not_zero = try func.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");
6146 const cross_1_msb = try func.load(cross_1, Type.u64, 8);
6147 const cross_1_msb_not_zero = try func.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");
6149 const cross_2_msb = try func.load(cross_2, Type.u64, 8);
6150 const cross_2_msb_not_zero = try func.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");
6152
6153 const cross_1_lsb = try func.load(cross_1, Type.u64, 0);
6154 const cross_2_lsb = try func.load(cross_2, Type.u64, 0);
6155 const cross_add = try func.binOp(cross_1_lsb, cross_2_lsb, Type.u64, .add);
6156
6157 var mul_lsb_msb = try (try func.load(mul_lsb, Type.u64, 8)).toLocal(func, Type.u64);
6158 defer mul_lsb_msb.free(func);
6159 var all_add = try (try func.binOp(cross_add, mul_lsb_msb, Type.u64, .add)).toLocal(func, Type.u64);
6160 defer all_add.free(func);
6161 const add_overflow = try func.cmp(all_add, mul_lsb_msb, Type.u64, .lt);
6141 const rhs_msb_not_zero = try cg.cmp(rhs_msb, zero, Type.u64, .neq);
6142 const lhs_msb_not_zero = try cg.cmp(lhs_msb, zero, Type.u64, .neq);
6143 const both_msb_not_zero = try cg.binOp(rhs_msb_not_zero, lhs_msb_not_zero, Type.bool, .@"and");
6144 const cross_1_msb = try cg.load(cross_1, Type.u64, 8);
6145 const cross_1_msb_not_zero = try cg.cmp(cross_1_msb, zero, Type.u64, .neq);
6146 const cond_1 = try cg.binOp(both_msb_not_zero, cross_1_msb_not_zero, Type.bool, .@"or");
6147 const cross_2_msb = try cg.load(cross_2, Type.u64, 8);
6148 const cross_2_msb_not_zero = try cg.cmp(cross_2_msb, zero, Type.u64, .neq);
6149 const cond_2 = try cg.binOp(cond_1, cross_2_msb_not_zero, Type.bool, .@"or");
6150
6151 const cross_1_lsb = try cg.load(cross_1, Type.u64, 0);
6152 const cross_2_lsb = try cg.load(cross_2, Type.u64, 0);
6153 const cross_add = try cg.binOp(cross_1_lsb, cross_2_lsb, Type.u64, .add);
6154
6155 var mul_lsb_msb = try (try cg.load(mul_lsb, Type.u64, 8)).toLocal(cg, Type.u64);
6156 defer mul_lsb_msb.free(cg);
6157 var all_add = try (try cg.binOp(cross_add, mul_lsb_msb, Type.u64, .add)).toLocal(cg, Type.u64);
6158 defer all_add.free(cg);
6159 const add_overflow = try cg.cmp(all_add, mul_lsb_msb, Type.u64, .lt);
61626160
61636161 // result for overflow bit
6164 _ = try func.binOp(cond_2, add_overflow, Type.bool, .@"or");
6165 try func.addLabel(.local_set, overflow_bit.local.value);
6166
6167 const tmp_result = try func.allocStack(Type.u128);
6168 try func.emitWValue(tmp_result);
6169 const mul_lsb_lsb = try func.load(mul_lsb, Type.u64, 0);
6170 try func.store(.stack, mul_lsb_lsb, Type.u64, tmp_result.offset());
6171 try func.store(tmp_result, all_add, Type.u64, 8);
6162 _ = try cg.binOp(cond_2, add_overflow, Type.bool, .@"or");
6163 try cg.addLabel(.local_set, overflow_bit.local.value);
6164
6165 const tmp_result = try cg.allocStack(Type.u128);
6166 try cg.emitWValue(tmp_result);
6167 const mul_lsb_lsb = try cg.load(mul_lsb, Type.u64, 0);
6168 try cg.store(.stack, mul_lsb_lsb, Type.u64, tmp_result.offset());
6169 try cg.store(tmp_result, all_add, Type.u64, 8);
61726170 break :blk tmp_result;
61736171 } else if (int_info.bits == 128 and int_info.signedness == .signed) blk: {
6174 const overflow_ret = try func.allocStack(Type.i32);
6175 const res = try func.callIntrinsic(
6172 const overflow_ret = try cg.allocStack(Type.i32);
6173 const res = try cg.callIntrinsic(
61766174 "__muloti4",
61776175 &[_]InternPool.Index{ .i128_type, .i128_type, .usize_type },
61786176 Type.i128,
61796177 &.{ lhs, rhs, overflow_ret },
61806178 );
6181 _ = try func.load(overflow_ret, Type.i32, 0);
6182 try func.addLabel(.local_set, overflow_bit.local.value);
6179 _ = try cg.load(overflow_ret, Type.i32, 0);
6180 try cg.addLabel(.local_set, overflow_bit.local.value);
61836181 break :blk res;
6184 } else return func.fail("TODO: @mulWithOverflow for {}", .{ty.fmt(pt)});
6185 var bin_op_local = try mul.toLocal(func, ty);
6186 defer bin_op_local.free(func);
6182 } else return cg.fail("TODO: @mulWithOverflow for {}", .{ty.fmt(pt)});
6183 var bin_op_local = try mul.toLocal(cg, ty);
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));
61896187 const offset: u32 = @intCast(ty.abiSize(zcu));
6190 try func.store(result, bin_op_local, ty, 0);
6191 try func.store(result, overflow_bit, Type.u1, offset);
6188 try cg.store(result, bin_op_local, ty, 0);
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 });
61946192}
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 {
61976195 assert(op == .max or op == .min);
6198 const pt = func.pt;
6196 const pt = cg.pt;
61996197 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);
62036201 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", .{});
62056203 }
62066204
62076205 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", .{});
62096207 }
62106208
6211 const lhs = try func.resolveInst(bin_op.lhs);
6212 const rhs = try func.resolveInst(bin_op.rhs);
6209 const lhs = try cg.resolveInst(bin_op.lhs);
6210 const rhs = try cg.resolveInst(bin_op.rhs);
62136211
62146212 if (ty.zigTypeTag(zcu) == .float) {
62156213 var fn_name_buf: [64]u8 = undefined;
6216 const float_bits = ty.floatBits(func.target.*);
6214 const float_bits = ty.floatBits(cg.target.*);
62176215 const fn_name = std.fmt.bufPrint(&fn_name_buf, "{s}f{s}{s}", .{
62186216 target_util.libcFloatPrefix(float_bits),
62196217 @tagName(op),
62206218 target_util.libcFloatSuffix(float_bits),
62216219 }) catch unreachable;
6222 const result = try func.callIntrinsic(fn_name, &.{ ty.ip_index, ty.ip_index }, ty, &.{ lhs, rhs });
6223 try func.lowerToStack(result);
6220 const result = try cg.callIntrinsic(fn_name, &.{ ty.ip_index, ty.ip_index }, ty, &.{ lhs, rhs });
6221 try cg.lowerToStack(result);
62246222 } else {
62256223 // operands to select from
6226 try func.lowerToStack(lhs);
6227 try func.lowerToStack(rhs);
6228 _ = try func.cmp(lhs, rhs, ty, if (op == .max) .gt else .lt);
6224 try cg.lowerToStack(lhs);
6225 try cg.lowerToStack(rhs);
6226 _ = try cg.cmp(lhs, rhs, ty, if (op == .max) .gt else .lt);
62296227
62306228 // based on the result from comparison, return operand 0 or 1.
6231 try func.addTag(.select);
6229 try cg.addTag(.select);
62326230 }
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 });
62356233}
62366234
6237fn airMulAdd(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
6238 const pt = func.pt;
6235fn airMulAdd(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
6236 const pt = cg.pt;
62396237 const zcu = pt.zcu;
6240 const pl_op = func.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;
6241 const bin_op = func.air.extraData(Air.Bin, pl_op.payload).data;
6238 const pl_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;
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);
62446242 if (ty.zigTypeTag(zcu) == .vector) {
6245 return func.fail("TODO: `@mulAdd` for vectors", .{});
6243 return cg.fail("TODO: `@mulAdd` for vectors", .{});
62466244 }
62476245
6248 const addend = try func.resolveInst(pl_op.operand);
6249 const lhs = try func.resolveInst(bin_op.lhs);
6250 const rhs = try func.resolveInst(bin_op.rhs);
6246 const addend = try cg.resolveInst(pl_op.operand);
6247 const lhs = try cg.resolveInst(bin_op.lhs);
6248 const rhs = try cg.resolveInst(bin_op.rhs);
62516249
6252 const result = if (ty.floatBits(func.target.*) == 16) fl_result: {
6253 const rhs_ext = try func.fpext(rhs, ty, Type.f32);
6254 const lhs_ext = try func.fpext(lhs, ty, Type.f32);
6255 const addend_ext = try func.fpext(addend, ty, Type.f32);
6250 const result = if (ty.floatBits(cg.target.*) == 16) fl_result: {
6251 const rhs_ext = try cg.fpext(rhs, ty, Type.f32);
6252 const lhs_ext = try cg.fpext(lhs, ty, Type.f32);
6253 const addend_ext = try cg.fpext(addend, ty, Type.f32);
62566254 // call to compiler-rt `fn fmaf(f32, f32, f32) f32`
6257 const result = try func.callIntrinsic(
6255 const result = try cg.callIntrinsic(
62586256 "fmaf",
62596257 &.{ .f32_type, .f32_type, .f32_type },
62606258 Type.f32,
62616259 &.{ rhs_ext, lhs_ext, addend_ext },
62626260 );
6263 break :fl_result try func.fptrunc(result, Type.f32, ty);
6261 break :fl_result try cg.fptrunc(result, Type.f32, ty);
62646262 } else result: {
6265 const mul_result = try func.binOp(lhs, rhs, ty, .mul);
6266 break :result try func.binOp(mul_result, addend, ty, .add);
6263 const mul_result = try cg.binOp(lhs, rhs, ty, .mul);
6264 break :result try cg.binOp(mul_result, addend, ty, .add);
62676265 };
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 });
62706268}
62716269
6272fn airClz(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
6273 const pt = func.pt;
6270fn airClz(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
6271 const pt = cg.pt;
62746272 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);
62786276 if (ty.zigTypeTag(zcu) == .vector) {
6279 return func.fail("TODO: `@clz` for vectors", .{});
6277 return cg.fail("TODO: `@clz` for vectors", .{});
62806278 }
62816279
6282 const operand = try func.resolveInst(ty_op.operand);
6280 const operand = try cg.resolveInst(ty_op.operand);
62836281 const int_info = ty.intInfo(zcu);
62846282 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});
62866284 };
62876285
62886286 switch (wasm_bits) {
62896287 32 => {
6290 try func.emitWValue(operand);
6291 try func.addTag(.i32_clz);
6288 try cg.emitWValue(operand);
6289 try cg.addTag(.i32_clz);
62926290 },
62936291 64 => {
6294 try func.emitWValue(operand);
6295 try func.addTag(.i64_clz);
6296 try func.addTag(.i32_wrap_i64);
6292 try cg.emitWValue(operand);
6293 try cg.addTag(.i64_clz);
6294 try cg.addTag(.i32_wrap_i64);
62976295 },
62986296 128 => {
6299 var msb = try (try func.load(operand, Type.u64, 8)).toLocal(func, Type.u64);
6300 defer msb.free(func);
6301
6302 try func.emitWValue(msb);
6303 try func.addTag(.i64_clz);
6304 _ = try func.load(operand, Type.u64, 0);
6305 try func.addTag(.i64_clz);
6306 try func.emitWValue(.{ .imm64 = 64 });
6307 try func.addTag(.i64_add);
6308 _ = try func.cmp(msb, .{ .imm64 = 0 }, Type.u64, .neq);
6309 try func.addTag(.select);
6310 try func.addTag(.i32_wrap_i64);
6297 var msb = try (try cg.load(operand, Type.u64, 8)).toLocal(cg, Type.u64);
6298 defer msb.free(cg);
6299
6300 try cg.emitWValue(msb);
6301 try cg.addTag(.i64_clz);
6302 _ = try cg.load(operand, Type.u64, 0);
6303 try cg.addTag(.i64_clz);
6304 try cg.emitWValue(.{ .imm64 = 64 });
6305 try cg.addTag(.i64_add);
6306 _ = try cg.cmp(msb, .{ .imm64 = 0 }, Type.u64, .neq);
6307 try cg.addTag(.select);
6308 try cg.addTag(.i32_wrap_i64);
63116309 },
63126310 else => unreachable,
63136311 }
63146312
63156313 if (wasm_bits != int_info.bits) {
6316 try func.emitWValue(.{ .imm32 = wasm_bits - int_info.bits });
6317 try func.addTag(.i32_sub);
6314 try cg.emitWValue(.{ .imm32 = wasm_bits - int_info.bits });
6315 try cg.addTag(.i32_sub);
63186316 }
63196317
6320 return func.finishAir(inst, .stack, &.{ty_op.operand});
6318 return cg.finishAir(inst, .stack, &.{ty_op.operand});
63216319}
63226320
6323fn airCtz(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
6324 const pt = func.pt;
6321fn airCtz(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
6322 const pt = cg.pt;
63256323 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
63306328 if (ty.zigTypeTag(zcu) == .vector) {
6331 return func.fail("TODO: `@ctz` for vectors", .{});
6329 return cg.fail("TODO: `@ctz` for vectors", .{});
63326330 }
63336331
6334 const operand = try func.resolveInst(ty_op.operand);
6332 const operand = try cg.resolveInst(ty_op.operand);
63356333 const int_info = ty.intInfo(zcu);
63366334 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});
63386336 };
63396337
63406338 switch (wasm_bits) {
......@@ -6342,110 +6340,110 @@ fn airCtz(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
63426340 if (wasm_bits != int_info.bits) {
63436341 const val: u32 = @as(u32, 1) << @as(u5, @intCast(int_info.bits));
63446342 // leave value on the stack
6345 _ = try func.binOp(operand, .{ .imm32 = val }, ty, .@"or");
6346 } else try func.emitWValue(operand);
6347 try func.addTag(.i32_ctz);
6343 _ = try cg.binOp(operand, .{ .imm32 = val }, ty, .@"or");
6344 } else try cg.emitWValue(operand);
6345 try cg.addTag(.i32_ctz);
63486346 },
63496347 64 => {
63506348 if (wasm_bits != int_info.bits) {
63516349 const val: u64 = @as(u64, 1) << @as(u6, @intCast(int_info.bits));
63526350 // leave value on the stack
6353 _ = try func.binOp(operand, .{ .imm64 = val }, ty, .@"or");
6354 } else try func.emitWValue(operand);
6355 try func.addTag(.i64_ctz);
6356 try func.addTag(.i32_wrap_i64);
6351 _ = try cg.binOp(operand, .{ .imm64 = val }, ty, .@"or");
6352 } else try cg.emitWValue(operand);
6353 try cg.addTag(.i64_ctz);
6354 try cg.addTag(.i32_wrap_i64);
63576355 },
63586356 128 => {
6359 var lsb = try (try func.load(operand, Type.u64, 0)).toLocal(func, Type.u64);
6360 defer lsb.free(func);
6357 var lsb = try (try cg.load(operand, Type.u64, 0)).toLocal(cg, Type.u64);
6358 defer lsb.free(cg);
63616359
6362 try func.emitWValue(lsb);
6363 try func.addTag(.i64_ctz);
6364 _ = try func.load(operand, Type.u64, 8);
6360 try cg.emitWValue(lsb);
6361 try cg.addTag(.i64_ctz);
6362 _ = try cg.load(operand, Type.u64, 8);
63656363 if (wasm_bits != int_info.bits) {
6366 try func.addImm64(@as(u64, 1) << @as(u6, @intCast(int_info.bits - 64)));
6367 try func.addTag(.i64_or);
6364 try cg.addImm64(@as(u64, 1) << @as(u6, @intCast(int_info.bits - 64)));
6365 try cg.addTag(.i64_or);
63686366 }
6369 try func.addTag(.i64_ctz);
6370 try func.addImm64(64);
6367 try cg.addTag(.i64_ctz);
6368 try cg.addImm64(64);
63716369 if (wasm_bits != int_info.bits) {
6372 try func.addTag(.i64_or);
6370 try cg.addTag(.i64_or);
63736371 } else {
6374 try func.addTag(.i64_add);
6372 try cg.addTag(.i64_add);
63756373 }
6376 _ = try func.cmp(lsb, .{ .imm64 = 0 }, Type.u64, .neq);
6377 try func.addTag(.select);
6378 try func.addTag(.i32_wrap_i64);
6374 _ = try cg.cmp(lsb, .{ .imm64 = 0 }, Type.u64, .neq);
6375 try cg.addTag(.select);
6376 try cg.addTag(.i32_wrap_i64);
63796377 },
63806378 else => unreachable,
63816379 }
63826380
6383 return func.finishAir(inst, .stack, &.{ty_op.operand});
6381 return cg.finishAir(inst, .stack, &.{ty_op.operand});
63846382}
63856383
6386fn airDbgStmt(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
6387 const dbg_stmt = func.air.instructions.items(.data)[@intFromEnum(inst)].dbg_stmt;
6388 try func.addInst(.{ .tag = .dbg_line, .data = .{
6389 .payload = try func.addExtra(Mir.DbgLineColumn{
6384fn airDbgStmt(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
6385 const dbg_stmt = cg.air.instructions.items(.data)[@intFromEnum(inst)].dbg_stmt;
6386 try cg.addInst(.{ .tag = .dbg_line, .data = .{
6387 .payload = try cg.addExtra(Mir.DbgLineColumn{
63906388 .line = dbg_stmt.line,
63916389 .column = dbg_stmt.column,
63926390 }),
63936391 } });
6394 return func.finishAir(inst, .none, &.{});
6392 return cg.finishAir(inst, .none, &.{});
63956393}
63966394
6397fn airDbgInlineBlock(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
6398 const ty_pl = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
6399 const extra = func.air.extraData(Air.DbgInlineBlock, ty_pl.payload);
6395fn airDbgInlineBlock(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
6396 const ty_pl = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
6397 const extra = cg.air.extraData(Air.DbgInlineBlock, ty_pl.payload);
64006398 // 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]));
64026400}
64036401
64046402fn airDbgVar(
6405 func: *CodeGen,
6403 cg: *CodeGen,
64066404 inst: Air.Inst.Index,
64076405 local_tag: link.File.Dwarf.WipNav.LocalTag,
64086406 is_ptr: bool,
64096407) InnerError!void {
64106408 _ = is_ptr;
64116409 _ = local_tag;
6412 return func.finishAir(inst, .none, &.{});
6410 return cg.finishAir(inst, .none, &.{});
64136411}
64146412
6415fn airTry(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
6416 const pl_op = func.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;
6417 const err_union = try func.resolveInst(pl_op.operand);
6418 const extra = func.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]);
6420 const err_union_ty = func.typeOf(pl_op.operand);
6421 const result = try lowerTry(func, inst, err_union, body, err_union_ty, false);
6422 return func.finishAir(inst, result, &.{pl_op.operand});
6413fn airTry(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
6414 const pl_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;
6415 const err_union = try cg.resolveInst(pl_op.operand);
6416 const extra = cg.air.extraData(Air.Try, pl_op.payload);
6417 const body: []const Air.Inst.Index = @ptrCast(cg.air.extra[extra.end..][0..extra.data.body_len]);
6418 const err_union_ty = cg.typeOf(pl_op.operand);
6419 const result = try lowerTry(cg, inst, err_union, body, err_union_ty, false);
6420 return cg.finishAir(inst, result, &.{pl_op.operand});
64236421}
64246422
6425fn airTryPtr(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
6426 const pt = func.pt;
6423fn airTryPtr(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
6424 const pt = cg.pt;
64276425 const zcu = pt.zcu;
6428 const ty_pl = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
6429 const extra = func.air.extraData(Air.TryPtr, ty_pl.payload);
6430 const err_union_ptr = try func.resolveInst(extra.data.ptr);
6431 const body: []const Air.Inst.Index = @ptrCast(func.air.extra[extra.end..][0..extra.data.body_len]);
6432 const err_union_ty = func.typeOf(extra.data.ptr).childType(zcu);
6433 const result = try lowerTry(func, inst, err_union_ptr, body, err_union_ty, true);
6434 return func.finishAir(inst, result, &.{extra.data.ptr});
6426 const ty_pl = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
6427 const extra = cg.air.extraData(Air.TryPtr, ty_pl.payload);
6428 const err_union_ptr = try cg.resolveInst(extra.data.ptr);
6429 const body: []const Air.Inst.Index = @ptrCast(cg.air.extra[extra.end..][0..extra.data.body_len]);
6430 const err_union_ty = cg.typeOf(extra.data.ptr).childType(zcu);
6431 const result = try lowerTry(cg, inst, err_union_ptr, body, err_union_ty, true);
6432 return cg.finishAir(inst, result, &.{extra.data.ptr});
64356433}
64366434
64376435fn lowerTry(
6438 func: *CodeGen,
6436 cg: *CodeGen,
64396437 inst: Air.Inst.Index,
64406438 err_union: WValue,
64416439 body: []const Air.Inst.Index,
64426440 err_union_ty: Type,
64436441 operand_is_ptr: bool,
64446442) InnerError!WValue {
6445 const pt = func.pt;
6443 const pt = cg.pt;
64466444 const zcu = pt.zcu;
64476445 if (operand_is_ptr) {
6448 return func.fail("TODO: lowerTry for pointers", .{});
6446 return cg.fail("TODO: lowerTry for pointers", .{});
64496447 }
64506448
64516449 const pl_ty = err_union_ty.errorUnionPayload(zcu);
......@@ -6453,29 +6451,29 @@ fn lowerTry(
64536451
64546452 if (!err_union_ty.errorUnionSet(zcu).errorSetIsEmpty(zcu)) {
64556453 // 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
64586456 // check if the error tag is set for the error union.
6459 try func.emitWValue(err_union);
6457 try cg.emitWValue(err_union);
64606458 if (pl_has_bits) {
64616459 const err_offset: u32 = @intCast(errUnionErrorOffset(pl_ty, zcu));
6462 try func.addMemArg(.i32_load16_u, .{
6460 try cg.addMemArg(.i32_load16_u, .{
64636461 .offset = err_union.offset() + err_offset,
64646462 .alignment = @intCast(Type.anyerror.abiAlignment(zcu).toByteUnits().?),
64656463 });
64666464 }
6467 try func.addTag(.i32_eqz);
6468 try func.addLabel(.br_if, 0); // jump out of block when error is '0'
6465 try cg.addTag(.i32_eqz);
6466 try cg.addLabel(.br_if, 0); // jump out of block when error is '0'
64696467
6470 const liveness = func.liveness.getCondBr(inst);
6471 try func.branches.append(func.gpa, .{});
6472 try func.currentBranch().values.ensureUnusedCapacity(func.gpa, liveness.else_deaths.len + liveness.then_deaths.len);
6468 const liveness = cg.liveness.getCondBr(inst);
6469 try cg.branches.append(cg.gpa, .{});
6470 try cg.currentBranch().values.ensureUnusedCapacity(cg.gpa, liveness.else_deaths.len + liveness.then_deaths.len);
64736471 defer {
6474 var branch = func.branches.pop();
6475 branch.deinit(func.gpa);
6472 var branch = cg.branches.pop();
6473 branch.deinit(cg.gpa);
64766474 }
6477 try func.genBody(body);
6478 try func.endBlock();
6475 try cg.genBody(body);
6476 try cg.endBlock();
64796477 }
64806478
64816479 // if we reach here it means error was not set, and we want the payload
......@@ -6484,38 +6482,38 @@ fn lowerTry(
64846482 }
64856483
64866484 const pl_offset: u32 = @intCast(errUnionPayloadOffset(pl_ty, zcu));
6487 if (isByRef(pl_ty, pt, func.target)) {
6488 return buildPointerOffset(func, err_union, pl_offset, .new);
6485 if (isByRef(pl_ty, pt, cg.target)) {
6486 return buildPointerOffset(cg, err_union, pl_offset, .new);
64896487 }
6490 const payload = try func.load(err_union, pl_ty, pl_offset);
6491 return payload.toLocal(func, pl_ty);
6488 const payload = try cg.load(err_union, pl_ty, pl_offset);
6489 return payload.toLocal(cg, pl_ty);
64926490}
64936491
6494fn airByteSwap(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
6495 const pt = func.pt;
6492fn airByteSwap(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
6493 const pt = cg.pt;
64966494 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);
6500 const operand = try func.resolveInst(ty_op.operand);
6497 const ty = cg.typeOfIndex(inst);
6498 const operand = try cg.resolveInst(ty_op.operand);
65016499
65026500 if (ty.zigTypeTag(zcu) == .vector) {
6503 return func.fail("TODO: @byteSwap for vectors", .{});
6501 return cg.fail("TODO: @byteSwap for vectors", .{});
65046502 }
65056503 const int_info = ty.intInfo(zcu);
65066504 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});
65086506 };
65096507
65106508 // bytes are no-op
65116509 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});
65136511 }
65146512
65156513 const result = result: {
65166514 switch (wasm_bits) {
65176515 32 => {
6518 const intrin_ret = try func.callIntrinsic(
6516 const intrin_ret = try cg.callIntrinsic(
65196517 "__bswapsi2",
65206518 &.{.u32_type},
65216519 Type.u32,
......@@ -6524,10 +6522,10 @@ fn airByteSwap(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
65246522 break :result if (int_info.bits == 32)
65256523 intrin_ret
65266524 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);
65286526 },
65296527 64 => {
6530 const intrin_ret = try func.callIntrinsic(
6528 const intrin_ret = try cg.callIntrinsic(
65316529 "__bswapdi2",
65326530 &.{.u64_type},
65336531 Type.u64,
......@@ -6536,61 +6534,61 @@ fn airByteSwap(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
65366534 break :result if (int_info.bits == 64)
65376535 intrin_ret
65386536 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);
65406538 },
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}),
65426540 }
65436541 };
6544 return func.finishAir(inst, result, &.{ty_op.operand});
6542 return cg.finishAir(inst, result, &.{ty_op.operand});
65456543}
65466544
6547fn airDiv(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
6548 const bin_op = func.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
6545fn airDiv(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
6546 const bin_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
65496547
6550 const ty = func.typeOfIndex(inst);
6551 const lhs = try func.resolveInst(bin_op.lhs);
6552 const rhs = try func.resolveInst(bin_op.rhs);
6548 const ty = cg.typeOfIndex(inst);
6549 const lhs = try cg.resolveInst(bin_op.lhs);
6550 const rhs = try cg.resolveInst(bin_op.rhs);
65536551
6554 const result = try func.binOp(lhs, rhs, ty, .div);
6555 return func.finishAir(inst, result, &.{ bin_op.lhs, bin_op.rhs });
6552 const result = try cg.binOp(lhs, rhs, ty, .div);
6553 return cg.finishAir(inst, result, &.{ bin_op.lhs, bin_op.rhs });
65566554}
65576555
6558fn airDivTrunc(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
6559 const bin_op = func.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
6556fn airDivTrunc(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
6557 const bin_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
65606558
6561 const ty = func.typeOfIndex(inst);
6562 const lhs = try func.resolveInst(bin_op.lhs);
6563 const rhs = try func.resolveInst(bin_op.rhs);
6559 const ty = cg.typeOfIndex(inst);
6560 const lhs = try cg.resolveInst(bin_op.lhs);
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
65676565 if (ty.isAnyFloat()) {
6568 const trunc_result = try func.floatOp(.trunc, ty, &.{div_result});
6569 return func.finishAir(inst, trunc_result, &.{ bin_op.lhs, bin_op.rhs });
6566 const trunc_result = try cg.floatOp(.trunc, ty, &.{div_result});
6567 return cg.finishAir(inst, trunc_result, &.{ bin_op.lhs, bin_op.rhs });
65706568 }
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 });
65736571}
65746572
6575fn airDivFloor(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
6576 const bin_op = func.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
6573fn airDivFloor(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
6574 const bin_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
65776575
6578 const pt = func.pt;
6576 const pt = cg.pt;
65796577 const zcu = pt.zcu;
6580 const ty = func.typeOfIndex(inst);
6581 const lhs = try func.resolveInst(bin_op.lhs);
6582 const rhs = try func.resolveInst(bin_op.rhs);
6578 const ty = cg.typeOfIndex(inst);
6579 const lhs = try cg.resolveInst(bin_op.lhs);
6580 const rhs = try cg.resolveInst(bin_op.rhs);
65836581
65846582 if (ty.isUnsignedInt(zcu)) {
6585 _ = try func.binOp(lhs, rhs, ty, .div);
6583 _ = try cg.binOp(lhs, rhs, ty, .div);
65866584 } else if (ty.isSignedInt(zcu)) {
65876585 const int_bits = ty.intInfo(zcu).bits;
65886586 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});
65906588 };
65916589
65926590 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});
65946592 }
65956593
65966594 const zero: WValue = switch (wasm_bits) {
......@@ -6600,108 +6598,108 @@ fn airDivFloor(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
66006598 };
66016599
66026600 // tee leaves the value on the stack and stores it in a local.
6603 const quotient = try func.allocLocal(ty);
6604 _ = try func.binOp(lhs, rhs, ty, .div);
6605 try func.addLabel(.local_tee, quotient.local.value);
6601 const quotient = try cg.allocLocal(ty);
6602 _ = try cg.binOp(lhs, rhs, ty, .div);
6603 try cg.addLabel(.local_tee, quotient.local.value);
66066604
66076605 // select takes a 32 bit value as the condition, so in the 64 bit case we use eqz to narrow
66086606 // the 64 bit value we want to use as the condition to 32 bits.
66096607 // This also inverts the condition (non 0 => 0, 0 => 1), so we put the adjusted and
66106608 // non-adjusted quotients on the stack in the opposite order for 32 vs 64 bits.
66116609 if (wasm_bits == 64) {
6612 try func.emitWValue(quotient);
6610 try cg.emitWValue(quotient);
66136611 }
66146612
66156613 // 0 if the signs of rhs_wasm and lhs_wasm are the same, 1 otherwise.
6616 _ = try func.binOp(lhs, rhs, ty, .xor);
6617 _ = try func.cmp(.stack, zero, ty, .lt);
6614 _ = try cg.binOp(lhs, rhs, ty, .xor);
6615 _ = try cg.cmp(.stack, zero, ty, .lt);
66186616
66196617 switch (wasm_bits) {
66206618 32 => {
6621 try func.addTag(.i32_sub);
6622 try func.emitWValue(quotient);
6619 try cg.addTag(.i32_sub);
6620 try cg.emitWValue(quotient);
66236621 },
66246622 64 => {
6625 try func.addTag(.i64_extend_i32_u);
6626 try func.addTag(.i64_sub);
6623 try cg.addTag(.i64_extend_i32_u);
6624 try cg.addTag(.i64_sub);
66276625 },
66286626 else => unreachable,
66296627 }
66306628
6631 _ = try func.binOp(lhs, rhs, ty, .rem);
6629 _ = try cg.binOp(lhs, rhs, ty, .rem);
66326630
66336631 if (wasm_bits == 64) {
6634 try func.addTag(.i64_eqz);
6632 try cg.addTag(.i64_eqz);
66356633 }
66366634
6637 try func.addTag(.select);
6635 try cg.addTag(.select);
66386636
66396637 // We need to zero the high bits because N bit comparisons consider all 32 or 64 bits, and
66406638 // expect all but the lowest N bits to be 0.
66416639 // TODO: Should we be zeroing the high bits here or should we be ignoring the high bits
66426640 // when performing comparisons?
66436641 if (int_bits != wasm_bits) {
6644 _ = try func.wrapOperand(.stack, ty);
6642 _ = try cg.wrapOperand(.stack, ty);
66456643 }
66466644 } else {
6647 const float_bits = ty.floatBits(func.target.*);
6645 const float_bits = ty.floatBits(cg.target.*);
66486646 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});
66506648 }
66516649 const is_f16 = float_bits == 16;
66526650
6653 const lhs_wasm = if (is_f16) try func.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;
6651 const lhs_wasm = if (is_f16) try cg.fpext(lhs, Type.f16, Type.f32) else lhs;
6652 const rhs_wasm = if (is_f16) try cg.fpext(rhs, Type.f16, Type.f32) else rhs;
66556653
6656 try func.emitWValue(lhs_wasm);
6657 try func.emitWValue(rhs_wasm);
6654 try cg.emitWValue(lhs_wasm);
6655 try cg.emitWValue(rhs_wasm);
66586656
66596657 switch (float_bits) {
66606658 16, 32 => {
6661 try func.addTag(.f32_div);
6662 try func.addTag(.f32_floor);
6659 try cg.addTag(.f32_div);
6660 try cg.addTag(.f32_floor);
66636661 },
66646662 64 => {
6665 try func.addTag(.f64_div);
6666 try func.addTag(.f64_floor);
6663 try cg.addTag(.f64_div);
6664 try cg.addTag(.f64_floor);
66676665 },
66686666 else => unreachable,
66696667 }
66706668
66716669 if (is_f16) {
6672 _ = try func.fptrunc(.stack, Type.f32, Type.f16);
6670 _ = try cg.fptrunc(.stack, Type.f32, Type.f16);
66736671 }
66746672 }
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 });
66776675}
66786676
6679fn airRem(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
6680 const bin_op = func.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
6677fn airRem(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
6678 const bin_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
66816679
6682 const ty = func.typeOfIndex(inst);
6683 const lhs = try func.resolveInst(bin_op.lhs);
6684 const rhs = try func.resolveInst(bin_op.rhs);
6680 const ty = cg.typeOfIndex(inst);
6681 const lhs = try cg.resolveInst(bin_op.lhs);
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 });
66896687}
66906688
66916689/// Remainder after floor division, defined by:
66926690/// @divFloor(a, b) * b + @mod(a, b) = a
6693fn airMod(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
6694 const bin_op = func.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
6691fn airMod(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
6692 const bin_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
66956693
6696 const pt = func.pt;
6694 const pt = cg.pt;
66976695 const zcu = pt.zcu;
6698 const ty = func.typeOfIndex(inst);
6699 const lhs = try func.resolveInst(bin_op.lhs);
6700 const rhs = try func.resolveInst(bin_op.rhs);
6696 const ty = cg.typeOfIndex(inst);
6697 const lhs = try cg.resolveInst(bin_op.lhs);
6698 const rhs = try cg.resolveInst(bin_op.rhs);
67016699
67026700 const result = result: {
67036701 if (ty.isUnsignedInt(zcu)) {
6704 break :result try func.binOp(lhs, rhs, ty, .rem);
6702 break :result try cg.binOp(lhs, rhs, ty, .rem);
67056703 }
67066704 if (ty.isSignedInt(zcu)) {
67076705 // 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 {
67106708 // @mod(a, b) = @rem(@rem(a, b) + b, b)
67116709 const int_bits = ty.intInfo(zcu).bits;
67126710 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});
67146712 };
67156713
67166714 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});
67186716 }
67196717
6720 _ = try func.binOp(lhs, rhs, ty, .rem);
6721 _ = try func.binOp(.stack, rhs, ty, .add);
6722 break :result try func.binOp(.stack, rhs, ty, .rem);
6718 _ = try cg.binOp(lhs, rhs, ty, .rem);
6719 _ = try cg.binOp(.stack, rhs, ty, .add);
6720 break :result try cg.binOp(.stack, rhs, ty, .rem);
67236721 }
67246722 if (ty.isAnyFloat()) {
6725 const rem = try func.binOp(lhs, rhs, ty, .rem);
6726 const add = try func.binOp(rem, rhs, ty, .add);
6727 break :result try func.binOp(add, rhs, ty, .rem);
6723 const rem = try cg.binOp(lhs, rhs, ty, .rem);
6724 const add = try cg.binOp(rem, rhs, ty, .add);
6725 break :result try cg.binOp(add, rhs, ty, .rem);
67286726 }
6729 return func.fail("TODO: @mod for {}", .{ty.fmt(pt)});
6727 return cg.fail("TODO: @mod for {}", .{ty.fmt(pt)});
67306728 };
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 });
67336731}
67346732
6735fn airSatMul(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
6736 const bin_op = func.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
6733fn airSatMul(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
6734 const bin_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
67376735
6738 const pt = func.pt;
6736 const pt = cg.pt;
67396737 const zcu = pt.zcu;
6740 const ty = func.typeOfIndex(inst);
6738 const ty = cg.typeOfIndex(inst);
67416739 const int_info = ty.intInfo(zcu);
67426740 const is_signed = int_info.signedness == .signed;
67436741
6744 const lhs = try func.resolveInst(bin_op.lhs);
6745 const rhs = try func.resolveInst(bin_op.rhs);
6742 const lhs = try cg.resolveInst(bin_op.lhs);
6743 const rhs = try cg.resolveInst(bin_op.rhs);
67466744 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)});
67486746 };
67496747
67506748 switch (wasm_bits) {
67516749 32 => {
67526750 const upcast_ty: Type = if (is_signed) Type.i64 else Type.u64;
6753 const lhs_up = try func.intcast(lhs, ty, upcast_ty);
6754 const rhs_up = try func.intcast(rhs, ty, upcast_ty);
6755 var mul_res = try (try func.binOp(lhs_up, rhs_up, upcast_ty, .mul)).toLocal(func, upcast_ty);
6756 defer mul_res.free(func);
6751 const lhs_up = try cg.intcast(lhs, ty, upcast_ty);
6752 const rhs_up = try cg.intcast(rhs, ty, upcast_ty);
6753 var mul_res = try (try cg.binOp(lhs_up, rhs_up, upcast_ty, .mul)).toLocal(cg, upcast_ty);
6754 defer mul_res.free(cg);
67576755 if (is_signed) {
67586756 const imm_max: WValue = .{ .imm64 = ~@as(u64, 0) >> @intCast(64 - (int_info.bits - 1)) };
6759 try func.emitWValue(mul_res);
6760 try func.emitWValue(imm_max);
6761 _ = try func.cmp(mul_res, imm_max, upcast_ty, .lt);
6762 try func.addTag(.select);
6757 try cg.emitWValue(mul_res);
6758 try cg.emitWValue(imm_max);
6759 _ = try cg.cmp(mul_res, imm_max, upcast_ty, .lt);
6760 try cg.addTag(.select);
67636761
6764 var tmp = try func.allocLocal(upcast_ty);
6765 defer tmp.free(func);
6766 try func.addLabel(.local_set, tmp.local.value);
6762 var tmp = try cg.allocLocal(upcast_ty);
6763 defer tmp.free(cg);
6764 try cg.addLabel(.local_set, tmp.local.value);
67676765
67686766 const imm_min: WValue = .{ .imm64 = ~@as(u64, 0) << @intCast(int_info.bits - 1) };
6769 try func.emitWValue(tmp);
6770 try func.emitWValue(imm_min);
6771 _ = try func.cmp(tmp, imm_min, upcast_ty, .gt);
6772 try func.addTag(.select);
6767 try cg.emitWValue(tmp);
6768 try cg.emitWValue(imm_min);
6769 _ = try cg.cmp(tmp, imm_min, upcast_ty, .gt);
6770 try cg.addTag(.select);
67736771 } else {
67746772 const imm_max: WValue = .{ .imm64 = ~@as(u64, 0) >> @intCast(64 - int_info.bits) };
6775 try func.emitWValue(mul_res);
6776 try func.emitWValue(imm_max);
6777 _ = try func.cmp(mul_res, imm_max, upcast_ty, .lt);
6778 try func.addTag(.select);
6773 try cg.emitWValue(mul_res);
6774 try cg.emitWValue(imm_max);
6775 _ = try cg.cmp(mul_res, imm_max, upcast_ty, .lt);
6776 try cg.addTag(.select);
67796777 }
6780 try func.addTag(.i32_wrap_i64);
6778 try cg.addTag(.i32_wrap_i64);
67816779 },
67826780 64 => {
67836781 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)});
67856783 }
6786 const overflow_ret = try func.allocStack(Type.i32);
6787 _ = try func.callIntrinsic(
6784 const overflow_ret = try cg.allocStack(Type.i32);
6785 _ = try cg.callIntrinsic(
67886786 "__mulodi4",
67896787 &[_]InternPool.Index{ .i64_type, .i64_type, .usize_type },
67906788 Type.i64,
67916789 &.{ lhs, rhs, overflow_ret },
67926790 );
6793 const xor = try func.binOp(lhs, rhs, Type.i64, .xor);
6794 const sign_v = try func.binOp(xor, .{ .imm64 = 63 }, Type.i64, .shr);
6795 _ = try func.binOp(sign_v, .{ .imm64 = ~@as(u63, 0) }, Type.i64, .xor);
6796 _ = try func.load(overflow_ret, Type.i32, 0);
6797 try func.addTag(.i32_eqz);
6798 try func.addTag(.select);
6791 const xor = try cg.binOp(lhs, rhs, Type.i64, .xor);
6792 const sign_v = try cg.binOp(xor, .{ .imm64 = 63 }, Type.i64, .shr);
6793 _ = try cg.binOp(sign_v, .{ .imm64 = ~@as(u63, 0) }, Type.i64, .xor);
6794 _ = try cg.load(overflow_ret, Type.i32, 0);
6795 try cg.addTag(.i32_eqz);
6796 try cg.addTag(.select);
67996797 },
68006798 128 => {
68016799 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)});
68036801 }
6804 const overflow_ret = try func.allocStack(Type.i32);
6805 const ret = try func.callIntrinsic(
6802 const overflow_ret = try cg.allocStack(Type.i32);
6803 const ret = try cg.callIntrinsic(
68066804 "__muloti4",
68076805 &[_]InternPool.Index{ .i128_type, .i128_type, .usize_type },
68086806 Type.i128,
68096807 &.{ lhs, rhs, overflow_ret },
68106808 );
6811 try func.lowerToStack(ret);
6812 const xor = try func.binOp(lhs, rhs, Type.i128, .xor);
6813 const sign_v = try func.binOp(xor, .{ .imm32 = 127 }, Type.i128, .shr);
6809 try cg.lowerToStack(ret);
6810 const xor = try cg.binOp(lhs, rhs, Type.i128, .xor);
6811 const sign_v = try cg.binOp(xor, .{ .imm32 = 127 }, Type.i128, .shr);
68146812
68156813 // xor ~@as(u127, 0)
6816 try func.emitWValue(sign_v);
6817 const lsb = try func.load(sign_v, Type.u64, 0);
6818 _ = try func.binOp(lsb, .{ .imm64 = ~@as(u64, 0) }, Type.u64, .xor);
6819 try func.store(.stack, .stack, Type.u64, sign_v.offset());
6820 try func.emitWValue(sign_v);
6821 const msb = try func.load(sign_v, Type.u64, 8);
6822 _ = try func.binOp(msb, .{ .imm64 = ~@as(u63, 0) }, Type.u64, .xor);
6823 try func.store(.stack, .stack, Type.u64, sign_v.offset() + 8);
6824
6825 try func.lowerToStack(sign_v);
6826 _ = try func.load(overflow_ret, Type.i32, 0);
6827 try func.addTag(.i32_eqz);
6828 try func.addTag(.select);
6814 try cg.emitWValue(sign_v);
6815 const lsb = try cg.load(sign_v, Type.u64, 0);
6816 _ = try cg.binOp(lsb, .{ .imm64 = ~@as(u64, 0) }, Type.u64, .xor);
6817 try cg.store(.stack, .stack, Type.u64, sign_v.offset());
6818 try cg.emitWValue(sign_v);
6819 const msb = try cg.load(sign_v, Type.u64, 8);
6820 _ = try cg.binOp(msb, .{ .imm64 = ~@as(u63, 0) }, Type.u64, .xor);
6821 try cg.store(.stack, .stack, Type.u64, sign_v.offset() + 8);
6822
6823 try cg.lowerToStack(sign_v);
6824 _ = try cg.load(overflow_ret, Type.i32, 0);
6825 try cg.addTag(.i32_eqz);
6826 try cg.addTag(.select);
68296827 },
68306828 else => unreachable,
68316829 }
6832 return func.finishAir(inst, .stack, &.{ bin_op.lhs, bin_op.rhs });
6830 return cg.finishAir(inst, .stack, &.{ bin_op.lhs, bin_op.rhs });
68336831}
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 {
68366834 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;
68406838 const zcu = pt.zcu;
6841 const ty = func.typeOfIndex(inst);
6842 const lhs = try func.resolveInst(bin_op.lhs);
6843 const rhs = try func.resolveInst(bin_op.rhs);
6839 const ty = cg.typeOfIndex(inst);
6840 const lhs = try cg.resolveInst(bin_op.lhs);
6841 const rhs = try cg.resolveInst(bin_op.rhs);
68446842
68456843 const int_info = ty.intInfo(zcu);
68466844 const is_signed = int_info.signedness == .signed;
68476845
68486846 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});
68506848 }
68516849
68526850 if (is_signed) {
6853 const result = try signedSat(func, lhs, rhs, ty, op);
6854 return func.finishAir(inst, result, &.{ bin_op.lhs, bin_op.rhs });
6851 const result = try signedSat(cg, lhs, rhs, ty, op);
6852 return cg.finishAir(inst, result, &.{ bin_op.lhs, bin_op.rhs });
68556853 }
68566854
68576855 const wasm_bits = toWasmBits(int_info.bits).?;
6858 var bin_result = try (try func.binOp(lhs, rhs, ty, op)).toLocal(func, ty);
6859 defer bin_result.free(func);
6856 var bin_result = try (try cg.binOp(lhs, rhs, ty, op)).toLocal(cg, ty);
6857 defer bin_result.free(cg);
68606858 if (wasm_bits != int_info.bits and op == .add) {
68616859 const val: u64 = @as(u64, @intCast((@as(u65, 1) << @as(u7, @intCast(int_info.bits))) - 1));
68626860 const imm_val: WValue = switch (wasm_bits) {
......@@ -6865,25 +6863,25 @@ fn airSatBinOp(func: *CodeGen, inst: Air.Inst.Index, op: Op) InnerError!void {
68656863 else => unreachable,
68666864 };
68676865
6868 try func.emitWValue(bin_result);
6869 try func.emitWValue(imm_val);
6870 _ = try func.cmp(bin_result, imm_val, ty, .lt);
6866 try cg.emitWValue(bin_result);
6867 try cg.emitWValue(imm_val);
6868 _ = try cg.cmp(bin_result, imm_val, ty, .lt);
68716869 } else {
68726870 switch (wasm_bits) {
6873 32 => try func.addImm32(if (op == .add) std.math.maxInt(u32) else 0),
6874 64 => try func.addImm64(if (op == .add) std.math.maxInt(u64) else 0),
6871 32 => try cg.addImm32(if (op == .add) std.math.maxInt(u32) else 0),
6872 64 => try cg.addImm64(if (op == .add) std.math.maxInt(u64) else 0),
68756873 else => unreachable,
68766874 }
6877 try func.emitWValue(bin_result);
6878 _ = try func.cmp(bin_result, lhs, ty, if (op == .add) .lt else .gt);
6875 try cg.emitWValue(bin_result);
6876 _ = try cg.cmp(bin_result, lhs, ty, if (op == .add) .lt else .gt);
68796877 }
68806878
6881 try func.addTag(.select);
6882 return func.finishAir(inst, .stack, &.{ bin_op.lhs, bin_op.rhs });
6879 try cg.addTag(.select);
6880 return cg.finishAir(inst, .stack, &.{ bin_op.lhs, bin_op.rhs });
68836881}
68846882
6885fn signedSat(func: *CodeGen, lhs: WValue, rhs: WValue, ty: Type, op: Op) InnerError!WValue {
6886 const pt = func.pt;
6883fn signedSat(cg: *CodeGen, lhs: WValue, rhs: WValue, ty: Type, op: Op) InnerError!WValue {
6884 const pt = cg.pt;
68876885 const zcu = pt.zcu;
68886886 const int_info = ty.intInfo(zcu);
68896887 const wasm_bits = toWasmBits(int_info.bits).?;
......@@ -6903,92 +6901,92 @@ fn signedSat(func: *CodeGen, lhs: WValue, rhs: WValue, ty: Type, op: Op) InnerEr
69036901 else => unreachable,
69046902 };
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);
69076905 if (!is_wasm_bits) {
6908 defer bin_result.free(func); // not returned in this branch
6909 try func.emitWValue(bin_result);
6910 try func.emitWValue(max_wvalue);
6911 _ = try func.cmp(bin_result, max_wvalue, ext_ty, .lt);
6912 try func.addTag(.select);
6913 try func.addLabel(.local_set, bin_result.local.value); // re-use local
6914
6915 try func.emitWValue(bin_result);
6916 try func.emitWValue(min_wvalue);
6917 _ = try func.cmp(bin_result, min_wvalue, ext_ty, .gt);
6918 try func.addTag(.select);
6919 try func.addLabel(.local_set, bin_result.local.value); // re-use local
6920 return (try func.wrapOperand(bin_result, ty)).toLocal(func, ty);
6906 defer bin_result.free(cg); // not returned in this branch
6907 try cg.emitWValue(bin_result);
6908 try cg.emitWValue(max_wvalue);
6909 _ = try cg.cmp(bin_result, max_wvalue, ext_ty, .lt);
6910 try cg.addTag(.select);
6911 try cg.addLabel(.local_set, bin_result.local.value); // re-use local
6912
6913 try cg.emitWValue(bin_result);
6914 try cg.emitWValue(min_wvalue);
6915 _ = try cg.cmp(bin_result, min_wvalue, ext_ty, .gt);
6916 try cg.addTag(.select);
6917 try cg.addLabel(.local_set, bin_result.local.value); // re-use local
6918 return (try cg.wrapOperand(bin_result, ty)).toLocal(cg, ty);
69216919 } else {
69226920 const zero: WValue = switch (wasm_bits) {
69236921 32 => .{ .imm32 = 0 },
69246922 64 => .{ .imm64 = 0 },
69256923 else => unreachable,
69266924 };
6927 try func.emitWValue(max_wvalue);
6928 try func.emitWValue(min_wvalue);
6929 _ = try func.cmp(bin_result, zero, ty, .lt);
6930 try func.addTag(.select);
6931 try func.emitWValue(bin_result);
6925 try cg.emitWValue(max_wvalue);
6926 try cg.emitWValue(min_wvalue);
6927 _ = try cg.cmp(bin_result, zero, ty, .lt);
6928 try cg.addTag(.select);
6929 try cg.emitWValue(bin_result);
69326930 // leave on stack
6933 const cmp_zero_result = try func.cmp(rhs, zero, ty, if (op == .add) .lt else .gt);
6934 const cmp_bin_result = try func.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.
6936 try func.addTag(.select);
6937 try func.addLabel(.local_set, bin_result.local.value); // re-use local
6931 const cmp_zero_result = try cg.cmp(rhs, zero, ty, if (op == .add) .lt else .gt);
6932 const cmp_bin_result = try cg.cmp(bin_result, lhs, ty, .lt);
6933 _ = try cg.binOp(cmp_zero_result, cmp_bin_result, Type.u32, .xor); // comparisons always return i32, so provide u32 as type to xor.
6934 try cg.addTag(.select);
6935 try cg.addLabel(.local_set, bin_result.local.value); // re-use local
69386936 return bin_result;
69396937 }
69406938}
69416939
6942fn airShlSat(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
6943 const bin_op = func.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
6940fn airShlSat(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
6941 const bin_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
69446942
6945 const pt = func.pt;
6943 const pt = cg.pt;
69466944 const zcu = pt.zcu;
6947 const ty = func.typeOfIndex(inst);
6945 const ty = cg.typeOfIndex(inst);
69486946 const int_info = ty.intInfo(zcu);
69496947 const is_signed = int_info.signedness == .signed;
69506948 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});
69526950 }
69536951
6954 const lhs = try func.resolveInst(bin_op.lhs);
6955 const rhs = try func.resolveInst(bin_op.rhs);
6952 const lhs = try cg.resolveInst(bin_op.lhs);
6953 const rhs = try cg.resolveInst(bin_op.rhs);
69566954 const wasm_bits = toWasmBits(int_info.bits).?;
6957 const result = try func.allocLocal(ty);
6955 const result = try cg.allocLocal(ty);
69586956
69596957 if (wasm_bits == int_info.bits) {
6960 var shl = try (try func.binOp(lhs, rhs, ty, .shl)).toLocal(func, ty);
6961 defer shl.free(func);
6962 var shr = try (try func.binOp(shl, rhs, ty, .shr)).toLocal(func, ty);
6963 defer shr.free(func);
6958 var shl = try (try cg.binOp(lhs, rhs, ty, .shl)).toLocal(cg, ty);
6959 defer shl.free(cg);
6960 var shr = try (try cg.binOp(shl, rhs, ty, .shr)).toLocal(cg, ty);
6961 defer shr.free(cg);
69646962
69656963 switch (wasm_bits) {
69666964 32 => blk: {
69676965 if (!is_signed) {
6968 try func.addImm32(std.math.maxInt(u32));
6966 try cg.addImm32(std.math.maxInt(u32));
69696967 break :blk;
69706968 }
6971 try func.addImm32(@bitCast(@as(i32, std.math.minInt(i32))));
6972 try func.addImm32(@bitCast(@as(i32, std.math.maxInt(i32))));
6973 _ = try func.cmp(lhs, .{ .imm32 = 0 }, ty, .lt);
6974 try func.addTag(.select);
6969 try cg.addImm32(@bitCast(@as(i32, std.math.minInt(i32))));
6970 try cg.addImm32(@bitCast(@as(i32, std.math.maxInt(i32))));
6971 _ = try cg.cmp(lhs, .{ .imm32 = 0 }, ty, .lt);
6972 try cg.addTag(.select);
69756973 },
69766974 64 => blk: {
69776975 if (!is_signed) {
6978 try func.addImm64(std.math.maxInt(u64));
6976 try cg.addImm64(std.math.maxInt(u64));
69796977 break :blk;
69806978 }
6981 try func.addImm64(@bitCast(@as(i64, std.math.minInt(i64))));
6982 try func.addImm64(@bitCast(@as(i64, std.math.maxInt(i64))));
6983 _ = try func.cmp(lhs, .{ .imm64 = 0 }, ty, .lt);
6984 try func.addTag(.select);
6979 try cg.addImm64(@bitCast(@as(i64, std.math.minInt(i64))));
6980 try cg.addImm64(@bitCast(@as(i64, std.math.maxInt(i64))));
6981 _ = try cg.cmp(lhs, .{ .imm64 = 0 }, ty, .lt);
6982 try cg.addTag(.select);
69856983 },
69866984 else => unreachable,
69876985 }
6988 try func.emitWValue(shl);
6989 _ = try func.cmp(lhs, shr, ty, .neq);
6990 try func.addTag(.select);
6991 try func.addLabel(.local_set, result.local.value);
6986 try cg.emitWValue(shl);
6987 _ = try cg.cmp(lhs, shr, ty, .neq);
6988 try cg.addTag(.select);
6989 try cg.addLabel(.local_set, result.local.value);
69926990 } else {
69936991 const shift_size = wasm_bits - int_info.bits;
69946992 const shift_value: WValue = switch (wasm_bits) {
......@@ -6998,50 +6996,50 @@ fn airShlSat(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
69986996 };
69996997 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);
7002 defer shl_res.free(func);
7003 var shl = try (try func.binOp(shl_res, rhs, ext_ty, .shl)).toLocal(func, ext_ty);
7004 defer shl.free(func);
7005 var shr = try (try func.binOp(shl, rhs, ext_ty, .shr)).toLocal(func, ext_ty);
7006 defer shr.free(func);
6999 var shl_res = try (try cg.binOp(lhs, shift_value, ext_ty, .shl)).toLocal(cg, ext_ty);
7000 defer shl_res.free(cg);
7001 var shl = try (try cg.binOp(shl_res, rhs, ext_ty, .shl)).toLocal(cg, ext_ty);
7002 defer shl.free(cg);
7003 var shr = try (try cg.binOp(shl, rhs, ext_ty, .shr)).toLocal(cg, ext_ty);
7004 defer shr.free(cg);
70077005
70087006 switch (wasm_bits) {
70097007 32 => blk: {
70107008 if (!is_signed) {
7011 try func.addImm32(std.math.maxInt(u32));
7009 try cg.addImm32(std.math.maxInt(u32));
70127010 break :blk;
70137011 }
70147012
7015 try func.addImm32(@bitCast(@as(i32, std.math.minInt(i32))));
7016 try func.addImm32(@bitCast(@as(i32, std.math.maxInt(i32))));
7017 _ = try func.cmp(shl_res, .{ .imm32 = 0 }, ext_ty, .lt);
7018 try func.addTag(.select);
7013 try cg.addImm32(@bitCast(@as(i32, std.math.minInt(i32))));
7014 try cg.addImm32(@bitCast(@as(i32, std.math.maxInt(i32))));
7015 _ = try cg.cmp(shl_res, .{ .imm32 = 0 }, ext_ty, .lt);
7016 try cg.addTag(.select);
70197017 },
70207018 64 => blk: {
70217019 if (!is_signed) {
7022 try func.addImm64(std.math.maxInt(u64));
7020 try cg.addImm64(std.math.maxInt(u64));
70237021 break :blk;
70247022 }
70257023
7026 try func.addImm64(@bitCast(@as(i64, std.math.minInt(i64))));
7027 try func.addImm64(@bitCast(@as(i64, std.math.maxInt(i64))));
7028 _ = try func.cmp(shl_res, .{ .imm64 = 0 }, ext_ty, .lt);
7029 try func.addTag(.select);
7024 try cg.addImm64(@bitCast(@as(i64, std.math.minInt(i64))));
7025 try cg.addImm64(@bitCast(@as(i64, std.math.maxInt(i64))));
7026 _ = try cg.cmp(shl_res, .{ .imm64 = 0 }, ext_ty, .lt);
7027 try cg.addTag(.select);
70307028 },
70317029 else => unreachable,
70327030 }
7033 try func.emitWValue(shl);
7034 _ = try func.cmp(shl_res, shr, ext_ty, .neq);
7035 try func.addTag(.select);
7036 try func.addLabel(.local_set, result.local.value);
7037 var shift_result = try func.binOp(result, shift_value, ext_ty, .shr);
7031 try cg.emitWValue(shl);
7032 _ = try cg.cmp(shl_res, shr, ext_ty, .neq);
7033 try cg.addTag(.select);
7034 try cg.addLabel(.local_set, result.local.value);
7035 var shift_result = try cg.binOp(result, shift_value, ext_ty, .shr);
70387036 if (is_signed) {
7039 shift_result = try func.wrapOperand(shift_result, ty);
7037 shift_result = try cg.wrapOperand(shift_result, ty);
70407038 }
7041 try func.addLabel(.local_set, result.local.value);
7039 try cg.addLabel(.local_set, result.local.value);
70427040 }
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 });
70457043}
70467044
70477045/// Calls a compiler-rt intrinsic by creating an undefined symbol,
......@@ -7051,27 +7049,27 @@ fn airShlSat(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
70517049/// passed as the first parameter.
70527050/// May leave the return value on the stack.
70537051fn callIntrinsic(
7054 func: *CodeGen,
7052 cg: *CodeGen,
70557053 name: []const u8,
70567054 param_types: []const InternPool.Index,
70577055 return_type: Type,
70587056 args: []const WValue,
70597057) InnerError!WValue {
70607058 assert(param_types.len == args.len);
7061 const wasm = func.wasm;
7062 const pt = func.pt;
7059 const wasm = cg.wasm;
7060 const pt = cg.pt;
70637061 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);
70657063 const func_index = wasm.getOutputFunction(try wasm.internString(name), func_type_index);
70667064
70677065 // 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);
70707068 // if we want return as first param, we allocate a pointer to stack,
70717069 // and emit it as our first argument
70727070 const sret = if (want_sret_param) blk: {
7073 const sret_local = try func.allocStack(return_type);
7074 try func.lowerToStack(sret_local);
7071 const sret_local = try cg.allocStack(return_type);
7072 try cg.lowerToStack(sret_local);
70757073 break :blk sret_local;
70767074 } else .none;
70777075
......@@ -7079,16 +7077,16 @@ fn callIntrinsic(
70797077 for (args, 0..) |arg, arg_i| {
70807078 assert(!(want_sret_param and arg == .stack));
70817079 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);
70837081 }
70847082
70857083 // Actually call our intrinsic
7086 try func.addLabel(.call_func, func_index);
7084 try cg.addLabel(.call_func, func_index);
70877085
70887086 if (!return_type.hasRuntimeBitsIgnoreComptime(zcu)) {
70897087 return .none;
70907088 } else if (return_type.isNoReturn(zcu)) {
7091 try func.addTag(.@"unreachable");
7089 try cg.addTag(.@"unreachable");
70927090 return .none;
70937091 } else if (want_sret_param) {
70947092 return sret;
......@@ -7097,31 +7095,31 @@ fn callIntrinsic(
70977095 }
70987096}
70997097
7100fn airTagName(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
7101 const un_op = func.air.instructions.items(.data)[@intFromEnum(inst)].un_op;
7102 const operand = try func.resolveInst(un_op);
7103 const enum_ty = func.typeOf(un_op);
7098fn airTagName(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
7099 const un_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].un_op;
7100 const operand = try cg.resolveInst(un_op);
7101 const enum_ty = cg.typeOf(un_op);
71047102
7105 const result_ptr = try func.allocStack(func.typeOfIndex(inst));
7106 try func.lowerToStack(result_ptr);
7107 try func.emitWValue(operand);
7108 try func.addIpIndex(.call_tag_name, enum_ty.toIntern());
7103 const result_ptr = try cg.allocStack(cg.typeOfIndex(inst));
7104 try cg.lowerToStack(result_ptr);
7105 try cg.emitWValue(operand);
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});
71117109}
71127110
7113fn airErrorSetHasValue(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
7114 const pt = func.pt;
7111fn airErrorSetHasValue(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
7112 const pt = cg.pt;
71157113 const zcu = pt.zcu;
71167114 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);
71207118 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
71237121 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);
71257123 defer values.deinit();
71267124
71277125 var lowest: ?u32 = null;
......@@ -7147,23 +7145,23 @@ fn airErrorSetHasValue(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
71477145 }
71487146
71497147 // start block for 'true' branch
7150 try func.startBlock(.block, std.wasm.block_empty);
7148 try cg.startBlock(.block, std.wasm.block_empty);
71517149 // start block for 'false' branch
7152 try func.startBlock(.block, std.wasm.block_empty);
7150 try cg.startBlock(.block, std.wasm.block_empty);
71537151 // 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
71567154 // lower operand to determine jump table target
7157 try func.emitWValue(operand);
7158 try func.addImm32(lowest.?);
7159 try func.addTag(.i32_sub);
7155 try cg.emitWValue(operand);
7156 try cg.addImm32(lowest.?);
7157 try cg.addTag(.i32_sub);
71607158
71617159 // Account for default branch so always add '1'
71627160 const depth = @as(u32, @intCast(highest.? - lowest.? + 1));
71637161 const jump_table: Mir.JumpTable = .{ .length = depth };
7164 const table_extra_index = try func.addExtra(jump_table);
7165 try func.addInst(.{ .tag = .br_table, .data = .{ .payload = table_extra_index } });
7166 try func.mir_extra.ensureUnusedCapacity(func.gpa, depth);
7162 const table_extra_index = try cg.addExtra(jump_table);
7163 try cg.addInst(.{ .tag = .br_table, .data = .{ .payload = table_extra_index } });
7164 try cg.mir_extra.ensureUnusedCapacity(cg.gpa, depth);
71677165
71687166 var value: u32 = lowest.?;
71697167 while (value <= highest.?) : (value += 1) {
......@@ -7173,201 +7171,201 @@ fn airErrorSetHasValue(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
71737171 }
71747172 break :blk 0;
71757173 };
7176 func.mir_extra.appendAssumeCapacity(idx);
7174 cg.mir_extra.appendAssumeCapacity(idx);
71777175 }
7178 try func.endBlock();
7176 try cg.endBlock();
71797177
71807178 // 'false' branch (i.e. error set does not have value
71817179 // ensure we set local to 0 in case the local was re-used.
7182 try func.addImm32(0);
7183 try func.addLabel(.local_set, result.local.value);
7184 try func.addLabel(.br, 1);
7185 try func.endBlock();
7180 try cg.addImm32(0);
7181 try cg.addLabel(.local_set, result.local.value);
7182 try cg.addLabel(.br, 1);
7183 try cg.endBlock();
71867184
71877185 // 'true' branch
7188 try func.addImm32(1);
7189 try func.addLabel(.local_set, result.local.value);
7190 try func.addLabel(.br, 0);
7191 try func.endBlock();
7186 try cg.addImm32(1);
7187 try cg.addLabel(.local_set, result.local.value);
7188 try cg.addLabel(.br, 0);
7189 try cg.endBlock();
71927190
7193 return func.finishAir(inst, result, &.{ty_op.operand});
7191 return cg.finishAir(inst, result, &.{ty_op.operand});
71947192}
71957193
7196inline fn useAtomicFeature(func: *const CodeGen) bool {
7197 return std.Target.wasm.featureSetHas(func.target.cpu.features, .atomics);
7194inline fn useAtomicFeature(cg: *const CodeGen) bool {
7195 return std.Target.wasm.featureSetHas(cg.target.cpu.features, .atomics);
71987196}
71997197
7200fn airCmpxchg(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
7201 const pt = func.pt;
7198fn airCmpxchg(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
7199 const pt = cg.pt;
72027200 const zcu = pt.zcu;
7203 const ty_pl = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
7204 const extra = func.air.extraData(Air.Cmpxchg, ty_pl.payload).data;
7201 const ty_pl = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
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);
72077205 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);
7211 const expected_val = try func.resolveInst(extra.expected_value);
7212 const new_val = try func.resolveInst(extra.new_value);
7208 const ptr_operand = try cg.resolveInst(extra.ptr);
7209 const expected_val = try cg.resolveInst(extra.expected_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: {
7217 const val_local = try func.allocLocal(ty);
7218 try func.emitWValue(ptr_operand);
7219 try func.lowerToStack(expected_val);
7220 try func.lowerToStack(new_val);
7221 try func.addAtomicMemArg(switch (ty.abiSize(zcu)) {
7214 const ptr_val = if (cg.useAtomicFeature()) val: {
7215 const val_local = try cg.allocLocal(ty);
7216 try cg.emitWValue(ptr_operand);
7217 try cg.lowerToStack(expected_val);
7218 try cg.lowerToStack(new_val);
7219 try cg.addAtomicMemArg(switch (ty.abiSize(zcu)) {
72227220 1 => .i32_atomic_rmw8_cmpxchg_u,
72237221 2 => .i32_atomic_rmw16_cmpxchg_u,
72247222 4 => .i32_atomic_rmw_cmpxchg,
72257223 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}),
72277225 }, .{
72287226 .offset = ptr_operand.offset(),
72297227 .alignment = @intCast(ty.abiAlignment(zcu).toByteUnits().?),
72307228 });
7231 try func.addLabel(.local_tee, val_local.local.value);
7232 _ = try func.cmp(.stack, expected_val, ty, .eq);
7233 try func.addLabel(.local_set, cmp_result.local.value);
7229 try cg.addLabel(.local_tee, val_local.local.value);
7230 _ = try cg.cmp(.stack, expected_val, ty, .eq);
7231 try cg.addLabel(.local_set, cmp_result.local.value);
72347232 break :val val_local;
72357233 } else val: {
72367234 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", .{});
72387236 }
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);
7242 try func.lowerToStack(new_val);
7243 try func.emitWValue(ptr_val);
7244 _ = try func.cmp(ptr_val, expected_val, ty, .eq);
7245 try func.addLabel(.local_tee, cmp_result.local.value);
7246 try func.addTag(.select);
7247 try func.store(.stack, .stack, ty, 0);
7239 try cg.lowerToStack(ptr_operand);
7240 try cg.lowerToStack(new_val);
7241 try cg.emitWValue(ptr_val);
7242 _ = try cg.cmp(ptr_val, expected_val, ty, .eq);
7243 try cg.addLabel(.local_tee, cmp_result.local.value);
7244 try cg.addTag(.select);
7245 try cg.store(.stack, .stack, ty, 0);
72487246
72497247 break :val ptr_val;
72507248 };
72517249
7252 const result = if (isByRef(result_ty, pt, func.target)) val: {
7253 try func.emitWValue(cmp_result);
7254 try func.addImm32(~@as(u32, 0));
7255 try func.addTag(.i32_xor);
7256 try func.addImm32(1);
7257 try func.addTag(.i32_and);
7258 const and_result = try WValue.toLocal(.stack, func, Type.bool);
7259 const result_ptr = try func.allocStack(result_ty);
7260 try func.store(result_ptr, and_result, Type.bool, @as(u32, @intCast(ty.abiSize(zcu))));
7261 try func.store(result_ptr, ptr_val, ty, 0);
7250 const result = if (isByRef(result_ty, pt, cg.target)) val: {
7251 try cg.emitWValue(cmp_result);
7252 try cg.addImm32(~@as(u32, 0));
7253 try cg.addTag(.i32_xor);
7254 try cg.addImm32(1);
7255 try cg.addTag(.i32_and);
7256 const and_result = try WValue.toLocal(.stack, cg, Type.bool);
7257 const result_ptr = try cg.allocStack(result_ty);
7258 try cg.store(result_ptr, and_result, Type.bool, @as(u32, @intCast(ty.abiSize(zcu))));
7259 try cg.store(result_ptr, ptr_val, ty, 0);
72627260 break :val result_ptr;
72637261 } else val: {
7264 try func.addImm32(0);
7265 try func.emitWValue(ptr_val);
7266 try func.emitWValue(cmp_result);
7267 try func.addTag(.select);
7262 try cg.addImm32(0);
7263 try cg.emitWValue(ptr_val);
7264 try cg.emitWValue(cmp_result);
7265 try cg.addTag(.select);
72687266 break :val .stack;
72697267 };
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 });
72727270}
72737271
7274fn airAtomicLoad(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
7275 const pt = func.pt;
7276 const atomic_load = func.air.instructions.items(.data)[@intFromEnum(inst)].atomic_load;
7277 const ptr = try func.resolveInst(atomic_load.ptr);
7278 const ty = func.typeOfIndex(inst);
7272fn airAtomicLoad(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
7273 const pt = cg.pt;
7274 const atomic_load = cg.air.instructions.items(.data)[@intFromEnum(inst)].atomic_load;
7275 const ptr = try cg.resolveInst(atomic_load.ptr);
7276 const ty = cg.typeOfIndex(inst);
72797277
7280 if (func.useAtomicFeature()) {
7278 if (cg.useAtomicFeature()) {
72817279 const tag: std.wasm.AtomicsOpcode = switch (ty.abiSize(pt.zcu)) {
72827280 1 => .i32_atomic_load8_u,
72837281 2 => .i32_atomic_load16_u,
72847282 4 => .i32_atomic_load,
72857283 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}),
72877285 };
7288 try func.emitWValue(ptr);
7289 try func.addAtomicMemArg(tag, .{
7286 try cg.emitWValue(ptr);
7287 try cg.addAtomicMemArg(tag, .{
72907288 .offset = ptr.offset(),
72917289 .alignment = @intCast(ty.abiAlignment(pt.zcu).toByteUnits().?),
72927290 });
72937291 } else {
7294 _ = try func.load(ptr, ty, 0);
7292 _ = try cg.load(ptr, ty, 0);
72957293 }
72967294
7297 return func.finishAir(inst, .stack, &.{atomic_load.ptr});
7295 return cg.finishAir(inst, .stack, &.{atomic_load.ptr});
72987296}
72997297
7300fn airAtomicRmw(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
7301 const pt = func.pt;
7298fn airAtomicRmw(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
7299 const pt = cg.pt;
73027300 const zcu = pt.zcu;
7303 const pl_op = func.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;
7304 const extra = func.air.extraData(Air.AtomicRmw, pl_op.payload).data;
7301 const pl_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;
7302 const extra = cg.air.extraData(Air.AtomicRmw, pl_op.payload).data;
73057303
7306 const ptr = try func.resolveInst(pl_op.operand);
7307 const operand = try func.resolveInst(extra.operand);
7308 const ty = func.typeOfIndex(inst);
7304 const ptr = try cg.resolveInst(pl_op.operand);
7305 const operand = try cg.resolveInst(extra.operand);
7306 const ty = cg.typeOfIndex(inst);
73097307 const op: std.builtin.AtomicRmwOp = extra.op();
73107308
7311 if (func.useAtomicFeature()) {
7309 if (cg.useAtomicFeature()) {
73127310 switch (op) {
73137311 .Max,
73147312 .Min,
73157313 .Nand,
73167314 => {
7317 const tmp = try func.load(ptr, ty, 0);
7318 const value = try tmp.toLocal(func, ty);
7315 const tmp = try cg.load(ptr, ty, 0);
7316 const value = try tmp.toLocal(cg, ty);
73197317
73207318 // 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);
7324 try func.emitWValue(value);
7321 try cg.emitWValue(ptr);
7322 try cg.emitWValue(value);
73257323 if (op == .Nand) {
73267324 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");
73297327 if (wasm_bits == 32)
7330 try func.addImm32(~@as(u32, 0))
7328 try cg.addImm32(~@as(u32, 0))
73317329 else if (wasm_bits == 64)
7332 try func.addImm64(~@as(u64, 0))
7330 try cg.addImm64(~@as(u64, 0))
73337331 else
7334 return func.fail("TODO: `@atomicRmw` with operator `Nand` for types larger than 64 bits", .{});
7335 _ = try func.binOp(and_res, .stack, ty, .xor);
7332 return cg.fail("TODO: `@atomicRmw` with operator `Nand` for types larger than 64 bits", .{});
7333 _ = try cg.binOp(and_res, .stack, ty, .xor);
73367334 } else {
7337 try func.emitWValue(value);
7338 try func.emitWValue(operand);
7339 _ = try func.cmp(value, operand, ty, if (op == .Max) .gt else .lt);
7340 try func.addTag(.select);
7335 try cg.emitWValue(value);
7336 try cg.emitWValue(operand);
7337 _ = try cg.cmp(value, operand, ty, if (op == .Max) .gt else .lt);
7338 try cg.addTag(.select);
73417339 }
7342 try func.addAtomicMemArg(
7340 try cg.addAtomicMemArg(
73437341 switch (ty.abiSize(zcu)) {
73447342 1 => .i32_atomic_rmw8_cmpxchg_u,
73457343 2 => .i32_atomic_rmw16_cmpxchg_u,
73467344 4 => .i32_atomic_rmw_cmpxchg,
73477345 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)}),
73497347 },
73507348 .{
73517349 .offset = ptr.offset(),
73527350 .alignment = @intCast(ty.abiAlignment(zcu).toByteUnits().?),
73537351 },
73547352 );
7355 const select_res = try func.allocLocal(ty);
7356 try func.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_if
7353 const select_res = try cg.allocLocal(ty);
7354 try cg.addLabel(.local_tee, select_res.local.value);
7355 _ = 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);
7360 try func.addLabel(.local_set, value.local.value);
7357 try cg.emitWValue(select_res);
7358 try cg.addLabel(.local_set, value.local.value);
73617359
7362 try func.addLabel(.br_if, 0);
7363 try func.endBlock();
7364 return func.finishAir(inst, value, &.{ pl_op.operand, extra.operand });
7360 try cg.addLabel(.br_if, 0);
7361 try cg.endBlock();
7362 return cg.finishAir(inst, value, &.{ pl_op.operand, extra.operand });
73657363 },
73667364
73677365 // the other operations have their own instructions for Wasm.
73687366 else => {
7369 try func.emitWValue(ptr);
7370 try func.emitWValue(operand);
7367 try cg.emitWValue(ptr);
7368 try cg.emitWValue(operand);
73717369 const tag: std.wasm.AtomicsOpcode = switch (ty.abiSize(zcu)) {
73727370 1 => switch (op) {
73737371 .Xchg => .i32_atomic_rmw8_xchg_u,
......@@ -7405,22 +7403,22 @@ fn airAtomicRmw(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
74057403 .Xor => .i64_atomic_rmw_xor,
74067404 else => unreachable,
74077405 },
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}),
74097407 };
7410 try func.addAtomicMemArg(tag, .{
7408 try cg.addAtomicMemArg(tag, .{
74117409 .offset = ptr.offset(),
74127410 .alignment = @intCast(ty.abiAlignment(zcu).toByteUnits().?),
74137411 });
7414 return func.finishAir(inst, .stack, &.{ pl_op.operand, extra.operand });
7412 return cg.finishAir(inst, .stack, &.{ pl_op.operand, extra.operand });
74157413 },
74167414 }
74177415 } else {
7418 const loaded = try func.load(ptr, ty, 0);
7419 const result = try loaded.toLocal(func, ty);
7416 const loaded = try cg.load(ptr, ty, 0);
7417 const result = try loaded.toLocal(cg, ty);
74207418
74217419 switch (op) {
74227420 .Xchg => {
7423 try func.store(ptr, operand, ty, 0);
7421 try cg.store(ptr, operand, ty, 0);
74247422 },
74257423 .Add,
74267424 .Sub,
......@@ -7428,8 +7426,8 @@ fn airAtomicRmw(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
74287426 .Or,
74297427 .Xor,
74307428 => {
7431 try func.emitWValue(ptr);
7432 _ = try func.binOp(result, operand, ty, switch (op) {
7429 try cg.emitWValue(ptr);
7430 _ = try cg.binOp(result, operand, ty, switch (op) {
74337431 .Add => .add,
74347432 .Sub => .sub,
74357433 .And => .@"and",
......@@ -7438,87 +7436,87 @@ fn airAtomicRmw(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
74387436 else => unreachable,
74397437 });
74407438 if (ty.isInt(zcu) and (op == .Add or op == .Sub)) {
7441 _ = try func.wrapOperand(.stack, ty);
7439 _ = try cg.wrapOperand(.stack, ty);
74427440 }
7443 try func.store(.stack, .stack, ty, ptr.offset());
7441 try cg.store(.stack, .stack, ty, ptr.offset());
74447442 },
74457443 .Max,
74467444 .Min,
74477445 => {
7448 try func.emitWValue(ptr);
7449 try func.emitWValue(result);
7450 try func.emitWValue(operand);
7451 _ = try func.cmp(result, operand, ty, if (op == .Max) .gt else .lt);
7452 try func.addTag(.select);
7453 try func.store(.stack, .stack, ty, ptr.offset());
7446 try cg.emitWValue(ptr);
7447 try cg.emitWValue(result);
7448 try cg.emitWValue(operand);
7449 _ = try cg.cmp(result, operand, ty, if (op == .Max) .gt else .lt);
7450 try cg.addTag(.select);
7451 try cg.store(.stack, .stack, ty, ptr.offset());
74547452 },
74557453 .Nand => {
74567454 const wasm_bits = toWasmBits(@intCast(ty.bitSize(zcu))).?;
74577455
7458 try func.emitWValue(ptr);
7459 const and_res = try func.binOp(result, operand, ty, .@"and");
7456 try cg.emitWValue(ptr);
7457 const and_res = try cg.binOp(result, operand, ty, .@"and");
74607458 if (wasm_bits == 32)
7461 try func.addImm32(~@as(u32, 0))
7459 try cg.addImm32(~@as(u32, 0))
74627460 else if (wasm_bits == 64)
7463 try func.addImm64(~@as(u64, 0))
7461 try cg.addImm64(~@as(u64, 0))
74647462 else
7465 return func.fail("TODO: `@atomicRmw` with operator `Nand` for types larger than 64 bits", .{});
7466 _ = try func.binOp(and_res, .stack, ty, .xor);
7467 try func.store(.stack, .stack, ty, ptr.offset());
7463 return cg.fail("TODO: `@atomicRmw` with operator `Nand` for types larger than 64 bits", .{});
7464 _ = try cg.binOp(and_res, .stack, ty, .xor);
7465 try cg.store(.stack, .stack, ty, ptr.offset());
74687466 },
74697467 }
74707468
7471 return func.finishAir(inst, result, &.{ pl_op.operand, extra.operand });
7469 return cg.finishAir(inst, result, &.{ pl_op.operand, extra.operand });
74727470 }
74737471}
74747472
7475fn airAtomicStore(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
7476 const pt = func.pt;
7473fn airAtomicStore(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
7474 const pt = cg.pt;
74777475 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);
7481 const operand = try func.resolveInst(bin_op.rhs);
7482 const ptr_ty = func.typeOf(bin_op.lhs);
7478 const ptr = try cg.resolveInst(bin_op.lhs);
7479 const operand = try cg.resolveInst(bin_op.rhs);
7480 const ptr_ty = cg.typeOf(bin_op.lhs);
74837481 const ty = ptr_ty.childType(zcu);
74847482
7485 if (func.useAtomicFeature()) {
7483 if (cg.useAtomicFeature()) {
74867484 const tag: std.wasm.AtomicsOpcode = switch (ty.abiSize(zcu)) {
74877485 1 => .i32_atomic_store8,
74887486 2 => .i32_atomic_store16,
74897487 4 => .i32_atomic_store,
74907488 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}),
74927490 };
7493 try func.emitWValue(ptr);
7494 try func.lowerToStack(operand);
7495 try func.addAtomicMemArg(tag, .{
7491 try cg.emitWValue(ptr);
7492 try cg.lowerToStack(operand);
7493 try cg.addAtomicMemArg(tag, .{
74967494 .offset = ptr.offset(),
74977495 .alignment = @intCast(ty.abiAlignment(zcu).toByteUnits().?),
74987496 });
74997497 } else {
7500 try func.store(ptr, operand, ty, 0);
7498 try cg.store(ptr, operand, ty, 0);
75017499 }
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 });
75047502}
75057503
7506fn airFrameAddress(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
7507 if (func.initial_stack_value == .none) {
7508 try func.initializeStack();
7504fn airFrameAddress(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
7505 if (cg.initial_stack_value == .none) {
7506 try cg.initializeStack();
75097507 }
7510 try func.emitWValue(func.bottom_stack_value);
7511 return func.finishAir(inst, .stack, &.{});
7508 try cg.emitWValue(cg.bottom_stack_value);
7509 return cg.finishAir(inst, .stack, &.{});
75127510}
75137511
7514fn typeOf(func: *CodeGen, inst: Air.Inst.Ref) Type {
7515 const pt = func.pt;
7512fn typeOf(cg: *CodeGen, inst: Air.Inst.Ref) Type {
7513 const pt = cg.pt;
75167514 const zcu = pt.zcu;
7517 return func.air.typeOf(inst, &zcu.intern_pool);
7515 return cg.air.typeOf(inst, &zcu.intern_pool);
75187516}
75197517
7520fn typeOfIndex(func: *CodeGen, inst: Air.Inst.Index) Type {
7521 const pt = func.pt;
7518fn typeOfIndex(cg: *CodeGen, inst: Air.Inst.Index) Type {
7519 const pt = cg.pt;
75227520 const zcu = pt.zcu;
7523 return func.air.typeOfIndex(inst, &zcu.intern_pool);
7521 return cg.air.typeOfIndex(inst, &zcu.intern_pool);
75247522}