authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2024-12-07 19:47:22-08:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-01-15 15:11:35-08:00
logbf20a4aa9eeca3c1911709bf48a8c476106042dc
tree18a54587b6ffdc8a93562ab56ac1ecbe9269b300
parentc443a7a57fab7118a9793b7f77b7ab817235a896

wasm: use call_intrinsic MIR instruction


3 files changed, 471 insertions(+), 174 deletions(-)

src/arch/wasm/CodeGen.zig+244-168
...@@ -18,7 +18,6 @@ const Compilation = @import("../../Compilation.zig");...@@ -18,7 +18,6 @@ const Compilation = @import("../../Compilation.zig");
18const link = @import("../../link.zig");18const link = @import("../../link.zig");
19const Air = @import("../../Air.zig");19const Air = @import("../../Air.zig");
20const Liveness = @import("../../Liveness.zig");20const Liveness = @import("../../Liveness.zig");
21const target_util = @import("../../target.zig");
22const Mir = @import("Mir.zig");21const Mir = @import("Mir.zig");
23const Emit = @import("Emit.zig");22const Emit = @import("Emit.zig");
24const abi = @import("abi.zig");23const abi = @import("abi.zig");
...@@ -27,6 +26,12 @@ const errUnionPayloadOffset = codegen.errUnionPayloadOffset;...@@ -27,6 +26,12 @@ const errUnionPayloadOffset = codegen.errUnionPayloadOffset;
27const errUnionErrorOffset = codegen.errUnionErrorOffset;26const errUnionErrorOffset = codegen.errUnionErrorOffset;
28const Wasm = link.File.Wasm;27const Wasm = link.File.Wasm;
2928
29const target_util = @import("../../target.zig");
30const libcFloatPrefix = target_util.libcFloatPrefix;
31const libcFloatSuffix = target_util.libcFloatSuffix;
32const compilerRtFloatAbbrev = target_util.compilerRtFloatAbbrev;
33const compilerRtIntAbbrev = target_util.compilerRtIntAbbrev;
34
30/// Reference to the function declaration the code35/// Reference to the function declaration the code
31/// section belongs to36/// section belongs to
32owner_nav: InternPool.Nav.Index,37owner_nav: InternPool.Nav.Index,
...@@ -854,7 +859,6 @@ fn processDeath(cg: *CodeGen, ref: Air.Inst.Ref) void {...@@ -854,7 +859,6 @@ fn processDeath(cg: *CodeGen, ref: Air.Inst.Ref) void {
854 }859 }
855}860}
856861
857/// Appends a MIR instruction and returns its index within the list of instructions
858fn addInst(cg: *CodeGen, inst: Mir.Inst) error{OutOfMemory}!void {862fn addInst(cg: *CodeGen, inst: Mir.Inst) error{OutOfMemory}!void {
859 try cg.mir_instructions.append(cg.gpa, inst);863 try cg.mir_instructions.append(cg.gpa, inst);
860}864}
...@@ -873,14 +877,6 @@ fn addLabel(cg: *CodeGen, tag: Mir.Inst.Tag, label: u32) error{OutOfMemory}!void...@@ -873,14 +877,6 @@ fn addLabel(cg: *CodeGen, tag: Mir.Inst.Tag, label: u32) error{OutOfMemory}!void
873 try cg.addInst(.{ .tag = tag, .data = .{ .label = label } });877 try cg.addInst(.{ .tag = tag, .data = .{ .label = label } });
874}878}
875879
876fn addIpIndex(cg: *CodeGen, tag: Mir.Inst.Tag, i: InternPool.Index) Allocator.Error!void {
877 try cg.addInst(.{ .tag = tag, .data = .{ .ip_index = i } });
878}
879
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 } });
882}
883
884/// Accepts an unsigned 32bit integer rather than a signed integer to880/// Accepts an unsigned 32bit integer rather than a signed integer to
885/// prevent us from having to bitcast multiple times as most values881/// prevent us from having to bitcast multiple times as most values
886/// within codegen are represented as unsigned rather than signed.882/// within codegen are represented as unsigned rather than signed.
...@@ -1887,8 +1883,8 @@ fn genInst(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -1887,8 +1883,8 @@ fn genInst(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
1887 .shl_sat => cg.airShlSat(inst),1883 .shl_sat => cg.airShlSat(inst),
1888 .shr, .shr_exact => cg.airBinOp(inst, .shr),1884 .shr, .shr_exact => cg.airBinOp(inst, .shr),
1889 .xor => cg.airBinOp(inst, .xor),1885 .xor => cg.airBinOp(inst, .xor),
1890 .max => cg.airMaxMin(inst, .max),1886 .max => cg.airMaxMin(inst, .fmax, .gt),
1891 .min => cg.airMaxMin(inst, .min),1887 .min => cg.airMaxMin(inst, .fmin, .lt),
1892 .mul_add => cg.airMulAdd(inst),1888 .mul_add => cg.airMulAdd(inst),
18931889
1894 .sqrt => cg.airUnaryFloatOp(inst, .sqrt),1890 .sqrt => cg.airUnaryFloatOp(inst, .sqrt),
...@@ -2263,7 +2259,7 @@ fn airCall(cg: *CodeGen, inst: Air.Inst.Index, modifier: std.builtin.CallModifie...@@ -2263,7 +2259,7 @@ fn airCall(cg: *CodeGen, inst: Air.Inst.Index, modifier: std.builtin.CallModifie
2263 }2259 }
22642260
2265 if (callee) |nav_index| {2261 if (callee) |nav_index| {
2266 try cg.addNav(.call_nav, nav_index);2262 try cg.addInst(.{ .tag = .call_nav, .data = .{ .nav_index = nav_index } });
2267 } else {2263 } else {
2268 // in this case we call a function pointer2264 // in this case we call a function pointer
2269 // so load its value onto the stack2265 // so load its value onto the stack
...@@ -2669,20 +2665,20 @@ fn binOpBigInt(cg: *CodeGen, lhs: WValue, rhs: WValue, ty: Type, op: Op) InnerEr...@@ -2669,20 +2665,20 @@ fn binOpBigInt(cg: *CodeGen, lhs: WValue, rhs: WValue, ty: Type, op: Op) InnerEr
2669 }2665 }
26702666
2671 switch (op) {2667 switch (op) {
2672 .mul => return cg.callIntrinsic("__multi3", &.{ ty.toIntern(), ty.toIntern() }, ty, &.{ lhs, rhs }),2668 .mul => return cg.callIntrinsic(.__multi3, &.{ ty.toIntern(), ty.toIntern() }, ty, &.{ lhs, rhs }),
2673 .div => switch (int_info.signedness) {2669 .div => switch (int_info.signedness) {
2674 .signed => return cg.callIntrinsic("__divti3", &.{ ty.toIntern(), ty.toIntern() }, ty, &.{ lhs, rhs }),2670 .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 }),2671 .unsigned => return cg.callIntrinsic(.__udivti3, &.{ ty.toIntern(), ty.toIntern() }, ty, &.{ lhs, rhs }),
2676 },2672 },
2677 .rem => switch (int_info.signedness) {2673 .rem => switch (int_info.signedness) {
2678 .signed => return cg.callIntrinsic("__modti3", &.{ ty.toIntern(), ty.toIntern() }, ty, &.{ lhs, rhs }),2674 .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 }),2675 .unsigned => return cg.callIntrinsic(.__umodti3, &.{ ty.toIntern(), ty.toIntern() }, ty, &.{ lhs, rhs }),
2680 },2676 },
2681 .shr => switch (int_info.signedness) {2677 .shr => switch (int_info.signedness) {
2682 .signed => return cg.callIntrinsic("__ashrti3", &.{ ty.toIntern(), .i32_type }, ty, &.{ lhs, rhs }),2678 .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 }),2679 .unsigned => return cg.callIntrinsic(.__lshrti3, &.{ ty.toIntern(), .i32_type }, ty, &.{ lhs, rhs }),
2684 },2680 },
2685 .shl => return cg.callIntrinsic("__ashlti3", &.{ ty.toIntern(), .i32_type }, ty, &.{ lhs, rhs }),2681 .shl => return cg.callIntrinsic(.__ashlti3, &.{ ty.toIntern(), .i32_type }, ty, &.{ lhs, rhs }),
2686 .@"and", .@"or", .xor => {2682 .@"and", .@"or", .xor => {
2687 const result = try cg.allocStack(ty);2683 const result = try cg.allocStack(ty);
2688 try cg.emitWValue(result);2684 try cg.emitWValue(result);
...@@ -2802,6 +2798,46 @@ const FloatOp = enum {...@@ -2802,6 +2798,46 @@ const FloatOp = enum {
2802 => null,2798 => null,
2803 };2799 };
2804 }2800 }
2801
2802 fn intrinsic(op: FloatOp, bits: u16) Mir.Intrinsic {
2803 return switch (op) {
2804 inline .add, .sub, .div, .mul => |ct_op| switch (bits) {
2805 inline 16, 80, 128 => |ct_bits| @field(
2806 Mir.Intrinsic,
2807 "__" ++ @tagName(ct_op) ++ compilerRtFloatAbbrev(ct_bits) ++ "f3",
2808 ),
2809 else => unreachable,
2810 },
2811
2812 inline .ceil,
2813 .cos,
2814 .exp,
2815 .exp2,
2816 .fabs,
2817 .floor,
2818 .fma,
2819 .fmax,
2820 .fmin,
2821 .fmod,
2822 .log,
2823 .log10,
2824 .log2,
2825 .round,
2826 .sin,
2827 .sqrt,
2828 .tan,
2829 .trunc,
2830 => |ct_op| switch (bits) {
2831 inline 16, 80, 128 => |ct_bits| @field(
2832 Mir.Intrinsic,
2833 libcFloatPrefix(ct_bits) ++ @tagName(ct_op) ++ libcFloatSuffix(ct_bits),
2834 ),
2835 else => unreachable,
2836 },
2837
2838 .neg => unreachable,
2839 };
2840 }
2805};2841};
28062842
2807fn airAbs(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {2843fn airAbs(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
...@@ -2919,44 +2955,12 @@ fn floatOp(cg: *CodeGen, float_op: FloatOp, ty: Type, args: []const WValue) Inne...@@ -2919,44 +2955,12 @@ fn floatOp(cg: *CodeGen, float_op: FloatOp, ty: Type, args: []const WValue) Inne
2919 }2955 }
2920 }2956 }
29212957
2922 var fn_name_buf: [64]u8 = undefined;2958 const intrinsic = float_op.intrinsic(float_bits);
2923 const fn_name = switch (float_op) {
2924 .add,
2925 .sub,
2926 .div,
2927 .mul,
2928 => std.fmt.bufPrint(&fn_name_buf, "__{s}{s}f3", .{
2929 @tagName(float_op), target_util.compilerRtFloatAbbrev(float_bits),
2930 }) catch unreachable,
2931
2932 .ceil,
2933 .cos,
2934 .exp,
2935 .exp2,
2936 .fabs,
2937 .floor,
2938 .fma,
2939 .fmax,
2940 .fmin,
2941 .fmod,
2942 .log,
2943 .log10,
2944 .log2,
2945 .round,
2946 .sin,
2947 .sqrt,
2948 .tan,
2949 .trunc,
2950 => std.fmt.bufPrint(&fn_name_buf, "{s}{s}{s}", .{
2951 target_util.libcFloatPrefix(float_bits), @tagName(float_op), target_util.libcFloatSuffix(float_bits),
2952 }) catch unreachable,
2953 .neg => unreachable, // handled above
2954 };
29552959
2956 // fma requires three operands2960 // fma requires three operands
2957 var param_types_buffer: [3]InternPool.Index = .{ ty.ip_index, ty.ip_index, ty.ip_index };2961 var param_types_buffer: [3]InternPool.Index = .{ ty.ip_index, ty.ip_index, ty.ip_index };
2958 const param_types = param_types_buffer[0..args.len];2962 const param_types = param_types_buffer[0..args.len];
2959 return cg.callIntrinsic(fn_name, param_types, ty, args);2963 return cg.callIntrinsic(intrinsic, param_types, ty, args);
2960}2964}
29612965
2962/// NOTE: The result value remains on top of the stack.2966/// NOTE: The result value remains on top of the stack.
...@@ -3605,12 +3609,8 @@ fn cmpFloat(cg: *CodeGen, ty: Type, lhs: WValue, rhs: WValue, cmp_op: std.math.C...@@ -3605,12 +3609,8 @@ fn cmpFloat(cg: *CodeGen, ty: Type, lhs: WValue, rhs: WValue, cmp_op: std.math.C
3605 return .stack;3609 return .stack;
3606 },3610 },
3607 80, 128 => {3611 80, 128 => {
3608 var fn_name_buf: [32]u8 = undefined;3612 const intrinsic = floatCmpIntrinsic(cmp_op, float_bits);
3609 const fn_name = std.fmt.bufPrint(&fn_name_buf, "__{s}{s}f2", .{3613 const result = try cg.callIntrinsic(intrinsic, &.{ ty.ip_index, ty.ip_index }, Type.bool, &.{ lhs, rhs });
3610 @tagName(op), target_util.compilerRtFloatAbbrev(float_bits),
3611 }) catch unreachable;
3612
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);3614 return cg.cmp(result, .{ .imm32 = 0 }, Type.i32, cmp_op);
3615 },3615 },
3616 else => unreachable,3616 else => unreachable,
...@@ -5001,19 +5001,26 @@ fn airIntFromFloat(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -5001,19 +5001,26 @@ fn airIntFromFloat(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
5001 }5001 }
50025002
5003 if ((op_bits != 32 and op_bits != 64) or dest_info.bits > 64) {5003 if ((op_bits != 32 and op_bits != 64) or dest_info.bits > 64) {
5004 const dest_bitsize = if (dest_info.bits <= 16) 16 else std.math.ceilPowerOfTwoAssert(u16, dest_info.bits);5004 const dest_bitsize = if (dest_info.bits <= 32) 32 else std.math.ceilPowerOfTwoAssert(u16, dest_info.bits);
50055005
5006 var fn_name_buf: [16]u8 = undefined;5006 const intrinsic = switch (dest_info.signedness) {
5007 const fn_name = std.fmt.bufPrint(&fn_name_buf, "__fix{s}{s}f{s}i", .{5007 inline .signed, .unsigned => |ct_s| switch (op_bits) {
5008 switch (dest_info.signedness) {5008 inline 16, 32, 64, 80, 128 => |ct_op_bits| switch (dest_bitsize) {
5009 .signed => "",5009 inline 32, 64, 128 => |ct_dest_bits| @field(
5010 .unsigned => "uns",5010 Mir.Intrinsic,
5011 "__fix" ++ switch (ct_s) {
5012 .signed => "",
5013 .unsigned => "uns",
5014 } ++
5015 compilerRtFloatAbbrev(ct_op_bits) ++ "f" ++
5016 compilerRtIntAbbrev(ct_dest_bits) ++ "i",
5017 ),
5018 else => unreachable,
5019 },
5020 else => unreachable,
5011 },5021 },
5012 target_util.compilerRtFloatAbbrev(op_bits),5022 };
5013 target_util.compilerRtIntAbbrev(dest_bitsize),5023 const result = try cg.callIntrinsic(intrinsic, &.{op_ty.ip_index}, dest_ty, &.{operand});
5014 }) catch unreachable;
5015
5016 const result = try cg.callIntrinsic(fn_name, &.{op_ty.ip_index}, dest_ty, &.{operand});
5017 return cg.finishAir(inst, result, &.{ty_op.operand});5024 return cg.finishAir(inst, result, &.{ty_op.operand});
5018 }5025 }
50195026
...@@ -5046,19 +5053,27 @@ fn airFloatFromInt(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -5046,19 +5053,27 @@ fn airFloatFromInt(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
5046 }5053 }
50475054
5048 if (op_info.bits > 64 or (dest_bits > 64 or dest_bits < 32)) {5055 if (op_info.bits > 64 or (dest_bits > 64 or dest_bits < 32)) {
5049 const op_bitsize = if (op_info.bits <= 16) 16 else std.math.ceilPowerOfTwoAssert(u16, op_info.bits);5056 const op_bitsize = if (op_info.bits <= 32) 32 else std.math.ceilPowerOfTwoAssert(u16, op_info.bits);
50505057
5051 var fn_name_buf: [16]u8 = undefined;5058 const intrinsic = switch (op_info.signedness) {
5052 const fn_name = std.fmt.bufPrint(&fn_name_buf, "__float{s}{s}i{s}f", .{5059 inline .signed, .unsigned => |ct_s| switch (op_bitsize) {
5053 switch (op_info.signedness) {5060 inline 32, 64, 128 => |ct_int_bits| switch (dest_bits) {
5054 .signed => "",5061 inline 16, 32, 64, 80, 128 => |ct_float_bits| @field(
5055 .unsigned => "un",5062 Mir.Intrinsic,
5063 "__float" ++ switch (ct_s) {
5064 .signed => "",
5065 .unsigned => "un",
5066 } ++
5067 compilerRtIntAbbrev(ct_int_bits) ++ "i" ++
5068 compilerRtFloatAbbrev(ct_float_bits) ++ "f",
5069 ),
5070 else => unreachable,
5071 },
5072 else => unreachable,
5056 },5073 },
5057 target_util.compilerRtIntAbbrev(op_bitsize),5074 };
5058 target_util.compilerRtFloatAbbrev(dest_bits),
5059 }) catch unreachable;
50605075
5061 const result = try cg.callIntrinsic(fn_name, &.{op_ty.ip_index}, dest_ty, &.{operand});5076 const result = try cg.callIntrinsic(intrinsic, &.{op_ty.ip_index}, dest_ty, &.{operand});
5062 return cg.finishAir(inst, result, &.{ty_op.operand});5077 return cg.finishAir(inst, result, &.{ty_op.operand});
5063 }5078 }
50645079
...@@ -5577,39 +5592,49 @@ fn airFpext(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -5577,39 +5592,49 @@ fn airFpext(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
5577 return cg.finishAir(inst, result, &.{ty_op.operand});5592 return cg.finishAir(inst, result, &.{ty_op.operand});
5578}5593}
55795594
5580/// Extends a float from a given `Type` to a larger wanted `Type`5595/// Extends a float from a given `Type` to a larger wanted `Type`, leaving the
5581/// NOTE: Leaves the result on the stack5596/// result on the stack.
5582fn fpext(cg: *CodeGen, operand: WValue, given: Type, wanted: Type) InnerError!WValue {5597fn fpext(cg: *CodeGen, operand: WValue, given: Type, wanted: Type) InnerError!WValue {
5583 const given_bits = given.floatBits(cg.target.*);5598 const given_bits = given.floatBits(cg.target.*);
5584 const wanted_bits = wanted.floatBits(cg.target.*);5599 const wanted_bits = wanted.floatBits(cg.target.*);
55855600
5586 if (wanted_bits == 64 and given_bits == 32) {5601 const intrinsic: Mir.Intrinsic = switch (given_bits) {
5587 try cg.emitWValue(operand);5602 16 => switch (wanted_bits) {
5588 try cg.addTag(.f64_promote_f32);5603 32 => {
5589 return .stack;5604 assert(.stack == try cg.callIntrinsic(.__extendhfsf2, &.{.f16_type}, Type.f32, &.{operand}));
5590 } else if (given_bits == 16 and wanted_bits <= 64) {5605 return .stack;
5591 // call __extendhfsf2(f16) f325606 },
5592 const f32_result = try cg.callIntrinsic(5607 64 => {
5593 "__extendhfsf2",5608 assert(.stack == try cg.callIntrinsic(.__extendhfsf2, &.{.f16_type}, Type.f32, &.{operand}));
5594 &.{.f16_type},5609 try cg.addTag(.f64_promote_f32);
5595 Type.f32,5610 return .stack;
5596 &.{operand},5611 },
5597 );5612 80 => .__extendhfxf2,
5598 assert(f32_result == .stack);5613 128 => .__extendhftf2,
55995614 else => unreachable,
5600 if (wanted_bits == 64) {5615 },
5601 try cg.addTag(.f64_promote_f32);5616 32 => switch (wanted_bits) {
5602 }5617 64 => {
5603 return .stack;5618 try cg.emitWValue(operand);
5604 }5619 try cg.addTag(.f64_promote_f32);
56055620 return .stack;
5606 var fn_name_buf: [13]u8 = undefined;5621 },
5607 const fn_name = std.fmt.bufPrint(&fn_name_buf, "__extend{s}f{s}f2", .{5622 80 => .__extendsfxf2,
5608 target_util.compilerRtFloatAbbrev(given_bits),5623 128 => .__extendsftf2,
5609 target_util.compilerRtFloatAbbrev(wanted_bits),5624 else => unreachable,
5610 }) catch unreachable;5625 },
56115626 64 => switch (wanted_bits) {
5612 return cg.callIntrinsic(fn_name, &.{given.ip_index}, wanted, &.{operand});5627 80 => .__extenddfxf2,
5628 128 => .__extenddftf2,
5629 else => unreachable,
5630 },
5631 80 => switch (wanted_bits) {
5632 128 => .__extendxftf2,
5633 else => unreachable,
5634 },
5635 else => unreachable,
5636 };
5637 return cg.callIntrinsic(intrinsic, &.{given.ip_index}, wanted, &.{operand});
5613}5638}
56145639
5615fn airFptrunc(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {5640fn airFptrunc(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
...@@ -5621,34 +5646,48 @@ fn airFptrunc(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -5621,34 +5646,48 @@ fn airFptrunc(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
5621 return cg.finishAir(inst, result, &.{ty_op.operand});5646 return cg.finishAir(inst, result, &.{ty_op.operand});
5622}5647}
56235648
5624/// Truncates a float from a given `Type` to its wanted `Type`5649/// Truncates a float from a given `Type` to its wanted `Type`, leaving the
5625/// NOTE: The result value remains on the stack5650/// result on the stack.
5626fn fptrunc(cg: *CodeGen, operand: WValue, given: Type, wanted: Type) InnerError!WValue {5651fn fptrunc(cg: *CodeGen, operand: WValue, given: Type, wanted: Type) InnerError!WValue {
5627 const given_bits = given.floatBits(cg.target.*);5652 const given_bits = given.floatBits(cg.target.*);
5628 const wanted_bits = wanted.floatBits(cg.target.*);5653 const wanted_bits = wanted.floatBits(cg.target.*);
56295654
5630 if (wanted_bits == 32 and given_bits == 64) {5655 const intrinsic: Mir.Intrinsic = switch (given_bits) {
5631 try cg.emitWValue(operand);5656 32 => switch (wanted_bits) {
5632 try cg.addTag(.f32_demote_f64);5657 16 => {
5633 return .stack;5658 return cg.callIntrinsic(.__truncsfhf2, &.{.f32_type}, Type.f16, &.{operand});
5634 } else if (wanted_bits == 16 and given_bits <= 64) {5659 },
5635 const op: WValue = if (given_bits == 64) blk: {5660 else => unreachable,
5636 try cg.emitWValue(operand);5661 },
5637 try cg.addTag(.f32_demote_f64);5662 64 => switch (wanted_bits) {
5638 break :blk .stack;5663 16 => {
5639 } else operand;5664 try cg.emitWValue(operand);
56405665 try cg.addTag(.f32_demote_f64);
5641 // call __truncsfhf2(f32) f165666 return cg.callIntrinsic(.__truncsfhf2, &.{.f32_type}, Type.f16, &.{.stack});
5642 return cg.callIntrinsic("__truncsfhf2", &.{.f32_type}, Type.f16, &.{op});5667 },
5643 }5668 32 => {
56445669 try cg.emitWValue(operand);
5645 var fn_name_buf: [12]u8 = undefined;5670 try cg.addTag(.f32_demote_f64);
5646 const fn_name = std.fmt.bufPrint(&fn_name_buf, "__trunc{s}f{s}f2", .{5671 return .stack;
5647 target_util.compilerRtFloatAbbrev(given_bits),5672 },
5648 target_util.compilerRtFloatAbbrev(wanted_bits),5673 else => unreachable,
5649 }) catch unreachable;5674 },
56505675 80 => switch (wanted_bits) {
5651 return cg.callIntrinsic(fn_name, &.{given.ip_index}, wanted, &.{operand});5676 16 => .__truncxfhf2,
5677 32 => .__truncxfsf2,
5678 64 => .__truncxfdf2,
5679 else => unreachable,
5680 },
5681 128 => switch (wanted_bits) {
5682 16 => .__trunctfhf2,
5683 32 => .__trunctfsf2,
5684 64 => .__trunctfdf2,
5685 80 => .__trunctfxf2,
5686 else => unreachable,
5687 },
5688 else => unreachable,
5689 };
5690 return cg.callIntrinsic(intrinsic, &.{given.ip_index}, wanted, &.{operand});
5652}5691}
56535692
5654fn airErrUnionPayloadPtrSet(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {5693fn airErrUnionPayloadPtrSet(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
...@@ -5823,7 +5862,7 @@ fn airBitReverse(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -5823,7 +5862,7 @@ fn airBitReverse(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
5823 switch (wasm_bits) {5862 switch (wasm_bits) {
5824 32 => {5863 32 => {
5825 const intrin_ret = try cg.callIntrinsic(5864 const intrin_ret = try cg.callIntrinsic(
5826 "__bitreversesi2",5865 .__bitreversesi2,
5827 &.{.u32_type},5866 &.{.u32_type},
5828 Type.u32,5867 Type.u32,
5829 &.{operand},5868 &.{operand},
...@@ -5836,7 +5875,7 @@ fn airBitReverse(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -5836,7 +5875,7 @@ fn airBitReverse(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
5836 },5875 },
5837 64 => {5876 64 => {
5838 const intrin_ret = try cg.callIntrinsic(5877 const intrin_ret = try cg.callIntrinsic(
5839 "__bitreversedi2",5878 .__bitreversedi2,
5840 &.{.u64_type},5879 &.{.u64_type},
5841 Type.u64,5880 Type.u64,
5842 &.{operand},5881 &.{operand},
...@@ -5853,7 +5892,7 @@ fn airBitReverse(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -5853,7 +5892,7 @@ fn airBitReverse(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
5853 try cg.emitWValue(result);5892 try cg.emitWValue(result);
5854 const first_half = try cg.load(operand, Type.u64, 8);5893 const first_half = try cg.load(operand, Type.u64, 8);
5855 const intrin_ret_first = try cg.callIntrinsic(5894 const intrin_ret_first = try cg.callIntrinsic(
5856 "__bitreversedi2",5895 .__bitreversedi2,
5857 &.{.u64_type},5896 &.{.u64_type},
5858 Type.u64,5897 Type.u64,
5859 &.{first_half},5898 &.{first_half},
...@@ -5866,7 +5905,7 @@ fn airBitReverse(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -5866,7 +5905,7 @@ fn airBitReverse(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
5866 try cg.emitWValue(result);5905 try cg.emitWValue(result);
5867 const second_half = try cg.load(operand, Type.u64, 0);5906 const second_half = try cg.load(operand, Type.u64, 0);
5868 const intrin_ret_second = try cg.callIntrinsic(5907 const intrin_ret_second = try cg.callIntrinsic(
5869 "__bitreversedi2",5908 .__bitreversedi2,
5870 &.{.u64_type},5909 &.{.u64_type},
5871 Type.u64,5910 Type.u64,
5872 &.{second_half},5911 &.{second_half},
...@@ -6114,19 +6153,19 @@ fn airMulWithOverflow(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -6114,19 +6153,19 @@ fn airMulWithOverflow(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
6114 defer rhs_msb.free(cg);6153 defer rhs_msb.free(cg);
61156154
6116 const cross_1 = try cg.callIntrinsic(6155 const cross_1 = try cg.callIntrinsic(
6117 "__multi3",6156 .__multi3,
6118 &[_]InternPool.Index{.i64_type} ** 4,6157 &[_]InternPool.Index{.i64_type} ** 4,
6119 Type.i128,6158 Type.i128,
6120 &.{ lhs_msb, zero, rhs_lsb, zero },6159 &.{ lhs_msb, zero, rhs_lsb, zero },
6121 );6160 );
6122 const cross_2 = try cg.callIntrinsic(6161 const cross_2 = try cg.callIntrinsic(
6123 "__multi3",6162 .__multi3,
6124 &[_]InternPool.Index{.i64_type} ** 4,6163 &[_]InternPool.Index{.i64_type} ** 4,
6125 Type.i128,6164 Type.i128,
6126 &.{ rhs_msb, zero, lhs_lsb, zero },6165 &.{ rhs_msb, zero, lhs_lsb, zero },
6127 );6166 );
6128 const mul_lsb = try cg.callIntrinsic(6167 const mul_lsb = try cg.callIntrinsic(
6129 "__multi3",6168 .__multi3,
6130 &[_]InternPool.Index{.i64_type} ** 4,6169 &[_]InternPool.Index{.i64_type} ** 4,
6131 Type.i128,6170 Type.i128,
6132 &.{ rhs_lsb, zero, lhs_lsb, zero },6171 &.{ rhs_lsb, zero, lhs_lsb, zero },
...@@ -6165,7 +6204,7 @@ fn airMulWithOverflow(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -6165,7 +6204,7 @@ fn airMulWithOverflow(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
6165 } else if (int_info.bits == 128 and int_info.signedness == .signed) blk: {6204 } else if (int_info.bits == 128 and int_info.signedness == .signed) blk: {
6166 const overflow_ret = try cg.allocStack(Type.i32);6205 const overflow_ret = try cg.allocStack(Type.i32);
6167 const res = try cg.callIntrinsic(6206 const res = try cg.callIntrinsic(
6168 "__muloti4",6207 .__muloti4,
6169 &[_]InternPool.Index{ .i128_type, .i128_type, .usize_type },6208 &[_]InternPool.Index{ .i128_type, .i128_type, .usize_type },
6170 Type.i128,6209 Type.i128,
6171 &.{ lhs, rhs, overflow_ret },6210 &.{ lhs, rhs, overflow_ret },
...@@ -6185,8 +6224,12 @@ fn airMulWithOverflow(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -6185,8 +6224,12 @@ fn airMulWithOverflow(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
6185 return cg.finishAir(inst, result, &.{ extra.lhs, extra.rhs });6224 return cg.finishAir(inst, result, &.{ extra.lhs, extra.rhs });
6186}6225}
61876226
6188fn airMaxMin(cg: *CodeGen, inst: Air.Inst.Index, op: Op) InnerError!void {6227fn airMaxMin(
6189 assert(op == .max or op == .min);6228 cg: *CodeGen,
6229 inst: Air.Inst.Index,
6230 op: enum { fmax, fmin },
6231 cmp_op: std.math.CompareOperator,
6232) InnerError!void {
6190 const pt = cg.pt;6233 const pt = cg.pt;
6191 const zcu = pt.zcu;6234 const zcu = pt.zcu;
6192 const bin_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;6235 const bin_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
...@@ -6204,20 +6247,22 @@ fn airMaxMin(cg: *CodeGen, inst: Air.Inst.Index, op: Op) InnerError!void {...@@ -6204,20 +6247,22 @@ fn airMaxMin(cg: *CodeGen, inst: Air.Inst.Index, op: Op) InnerError!void {
6204 const rhs = try cg.resolveInst(bin_op.rhs);6247 const rhs = try cg.resolveInst(bin_op.rhs);
62056248
6206 if (ty.zigTypeTag(zcu) == .float) {6249 if (ty.zigTypeTag(zcu) == .float) {
6207 var fn_name_buf: [64]u8 = undefined;6250 const intrinsic = switch (op) {
6208 const float_bits = ty.floatBits(cg.target.*);6251 inline .fmin, .fmax => |ct_op| switch (ty.floatBits(cg.target.*)) {
6209 const fn_name = std.fmt.bufPrint(&fn_name_buf, "{s}f{s}{s}", .{6252 inline 16, 32, 64, 80, 128 => |bits| @field(
6210 target_util.libcFloatPrefix(float_bits),6253 Mir.Intrinsic,
6211 @tagName(op),6254 libcFloatPrefix(bits) ++ @tagName(ct_op) ++ libcFloatSuffix(bits),
6212 target_util.libcFloatSuffix(float_bits),6255 ),
6213 }) catch unreachable;6256 else => unreachable,
6214 const result = try cg.callIntrinsic(fn_name, &.{ ty.ip_index, ty.ip_index }, ty, &.{ lhs, rhs });6257 },
6258 };
6259 const result = try cg.callIntrinsic(intrinsic, &.{ ty.ip_index, ty.ip_index }, ty, &.{ lhs, rhs });
6215 try cg.lowerToStack(result);6260 try cg.lowerToStack(result);
6216 } else {6261 } else {
6217 // operands to select from6262 // operands to select from
6218 try cg.lowerToStack(lhs);6263 try cg.lowerToStack(lhs);
6219 try cg.lowerToStack(rhs);6264 try cg.lowerToStack(rhs);
6220 _ = try cg.cmp(lhs, rhs, ty, if (op == .max) .gt else .lt);6265 _ = try cg.cmp(lhs, rhs, ty, cmp_op);
62216266
6222 // based on the result from comparison, return operand 0 or 1.6267 // based on the result from comparison, return operand 0 or 1.
6223 try cg.addTag(.select);6268 try cg.addTag(.select);
...@@ -6247,7 +6292,7 @@ fn airMulAdd(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -6247,7 +6292,7 @@ fn airMulAdd(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
6247 const addend_ext = try cg.fpext(addend, ty, Type.f32);6292 const addend_ext = try cg.fpext(addend, ty, Type.f32);
6248 // call to compiler-rt `fn fmaf(f32, f32, f32) f32`6293 // call to compiler-rt `fn fmaf(f32, f32, f32) f32`
6249 const result = try cg.callIntrinsic(6294 const result = try cg.callIntrinsic(
6250 "fmaf",6295 .fmaf,
6251 &.{ .f32_type, .f32_type, .f32_type },6296 &.{ .f32_type, .f32_type, .f32_type },
6252 Type.f32,6297 Type.f32,
6253 &.{ rhs_ext, lhs_ext, addend_ext },6298 &.{ rhs_ext, lhs_ext, addend_ext },
...@@ -6508,7 +6553,7 @@ fn airByteSwap(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -6508,7 +6553,7 @@ fn airByteSwap(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
6508 switch (wasm_bits) {6553 switch (wasm_bits) {
6509 32 => {6554 32 => {
6510 const intrin_ret = try cg.callIntrinsic(6555 const intrin_ret = try cg.callIntrinsic(
6511 "__bswapsi2",6556 .__bswapsi2,
6512 &.{.u32_type},6557 &.{.u32_type},
6513 Type.u32,6558 Type.u32,
6514 &.{operand},6559 &.{operand},
...@@ -6520,7 +6565,7 @@ fn airByteSwap(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -6520,7 +6565,7 @@ fn airByteSwap(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
6520 },6565 },
6521 64 => {6566 64 => {
6522 const intrin_ret = try cg.callIntrinsic(6567 const intrin_ret = try cg.callIntrinsic(
6523 "__bswapdi2",6568 .__bswapdi2,
6524 &.{.u64_type},6569 &.{.u64_type},
6525 Type.u64,6570 Type.u64,
6526 &.{operand},6571 &.{operand},
...@@ -6777,7 +6822,7 @@ fn airSatMul(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -6777,7 +6822,7 @@ fn airSatMul(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
6777 }6822 }
6778 const overflow_ret = try cg.allocStack(Type.i32);6823 const overflow_ret = try cg.allocStack(Type.i32);
6779 _ = try cg.callIntrinsic(6824 _ = try cg.callIntrinsic(
6780 "__mulodi4",6825 .__mulodi4,
6781 &[_]InternPool.Index{ .i64_type, .i64_type, .usize_type },6826 &[_]InternPool.Index{ .i64_type, .i64_type, .usize_type },
6782 Type.i64,6827 Type.i64,
6783 &.{ lhs, rhs, overflow_ret },6828 &.{ lhs, rhs, overflow_ret },
...@@ -6795,7 +6840,7 @@ fn airSatMul(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -6795,7 +6840,7 @@ fn airSatMul(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
6795 }6840 }
6796 const overflow_ret = try cg.allocStack(Type.i32);6841 const overflow_ret = try cg.allocStack(Type.i32);
6797 const ret = try cg.callIntrinsic(6842 const ret = try cg.callIntrinsic(
6798 "__muloti4",6843 .__muloti4,
6799 &[_]InternPool.Index{ .i128_type, .i128_type, .usize_type },6844 &[_]InternPool.Index{ .i128_type, .i128_type, .usize_type },
6800 Type.i128,6845 Type.i128,
6801 &.{ lhs, rhs, overflow_ret },6846 &.{ lhs, rhs, overflow_ret },
...@@ -7044,17 +7089,14 @@ fn airShlSat(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -7044,17 +7089,14 @@ fn airShlSat(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
7044/// May leave the return value on the stack.7089/// May leave the return value on the stack.
7045fn callIntrinsic(7090fn callIntrinsic(
7046 cg: *CodeGen,7091 cg: *CodeGen,
7047 name: []const u8,7092 intrinsic: Mir.Intrinsic,
7048 param_types: []const InternPool.Index,7093 param_types: []const InternPool.Index,
7049 return_type: Type,7094 return_type: Type,
7050 args: []const WValue,7095 args: []const WValue,
7051) InnerError!WValue {7096) InnerError!WValue {
7052 assert(param_types.len == args.len);7097 assert(param_types.len == args.len);
7053 const wasm = cg.wasm;
7054 const pt = cg.pt;7098 const pt = cg.pt;
7055 const zcu = pt.zcu;7099 const zcu = pt.zcu;
7056 const func_type_index = try genFunctype(wasm, .{ .wasm_watc = .{} }, param_types, return_type, pt, cg.target);
7057 const func_index = wasm.getOutputFunction(try wasm.internString(name), func_type_index);
70587100
7059 // Always pass over C-ABI7101 // Always pass over C-ABI
70607102
...@@ -7074,8 +7116,7 @@ fn callIntrinsic(...@@ -7074,8 +7116,7 @@ fn callIntrinsic(
7074 try cg.lowerArg(.{ .wasm_watc = .{} }, Type.fromInterned(param_types[arg_i]), arg);7116 try cg.lowerArg(.{ .wasm_watc = .{} }, Type.fromInterned(param_types[arg_i]), arg);
7075 }7117 }
70767118
7077 // Actually call our intrinsic7119 try cg.addInst(.{ .tag = .call_intrinsic, .data = .{ .intrinsic = intrinsic } });
7078 try cg.addLabel(.call_func, func_index);
70797120
7080 if (!return_type.hasRuntimeBitsIgnoreComptime(zcu)) {7121 if (!return_type.hasRuntimeBitsIgnoreComptime(zcu)) {
7081 return .none;7122 return .none;
...@@ -7097,7 +7138,7 @@ fn airTagName(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -7097,7 +7138,7 @@ fn airTagName(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
7097 const result_ptr = try cg.allocStack(cg.typeOfIndex(inst));7138 const result_ptr = try cg.allocStack(cg.typeOfIndex(inst));
7098 try cg.lowerToStack(result_ptr);7139 try cg.lowerToStack(result_ptr);
7099 try cg.emitWValue(operand);7140 try cg.emitWValue(operand);
7100 try cg.addIpIndex(.call_tag_name, enum_ty.toIntern());7141 try cg.addInst(.{ .tag = .call_tag_name, .data = .{ .ip_index = enum_ty.toIntern() } });
71017142
7102 return cg.finishAir(inst, result_ptr, &.{un_op});7143 return cg.finishAir(inst, result_ptr, &.{un_op});
7103}7144}
...@@ -7514,3 +7555,38 @@ fn typeOfIndex(cg: *CodeGen, inst: Air.Inst.Index) Type {...@@ -7514,3 +7555,38 @@ fn typeOfIndex(cg: *CodeGen, inst: Air.Inst.Index) Type {
7514 const zcu = pt.zcu;7555 const zcu = pt.zcu;
7515 return cg.air.typeOfIndex(inst, &zcu.intern_pool);7556 return cg.air.typeOfIndex(inst, &zcu.intern_pool);
7516}7557}
7558
7559fn floatCmpIntrinsic(op: std.math.CompareOperator, bits: u16) Mir.Intrinsic {
7560 return switch (op) {
7561 .lt => switch (bits) {
7562 80 => .__ltxf2,
7563 128 => .__lttf2,
7564 else => unreachable,
7565 },
7566 .lte => switch (bits) {
7567 80 => .__lexf2,
7568 128 => .__letf2,
7569 else => unreachable,
7570 },
7571 .eq => switch (bits) {
7572 80 => .__eqxf2,
7573 128 => .__eqtf2,
7574 else => unreachable,
7575 },
7576 .neq => switch (bits) {
7577 80 => .__nexf2,
7578 128 => .__netf2,
7579 else => unreachable,
7580 },
7581 .gte => switch (bits) {
7582 80 => .__gexf2,
7583 128 => .__getf2,
7584 else => unreachable,
7585 },
7586 .gt => switch (bits) {
7587 80 => .__gtxf2,
7588 128 => .__gttf2,
7589 else => unreachable,
7590 },
7591 };
7592}
src/arch/wasm/Emit.zig+45
...@@ -178,6 +178,51 @@ pub fn lowerToCode(emit: *Emit) Error!void {...@@ -178,6 +178,51 @@ pub fn lowerToCode(emit: *Emit) Error!void {
178 continue :loop tags[inst];178 continue :loop tags[inst];
179 },179 },
180180
181 .call_tag_name => {
182 try code.ensureUnusedCapacity(gpa, 6);
183 code.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.call));
184 if (is_obj) {
185 try wasm.out_relocs.append(gpa, .{
186 .offset = @intCast(code.items.len),
187 .index = try wasm.tagNameSymbolIndex(datas[inst].ip_index),
188 .tag = .FUNCTION_INDEX_LEB,
189 .addend = 0,
190 });
191 code.appendNTimesAssumeCapacity(0, 5);
192 } else {
193 const func_index = try wasm.tagNameFunctionIndex(datas[inst].ip_index);
194 leb.writeUleb128(code.fixedWriter(), @intFromEnum(func_index)) catch unreachable;
195 }
196
197 inst += 1;
198 continue :loop tags[inst];
199 },
200
201 .call_intrinsic => {
202 // Although this currently uses `wasm.internString`, note that it
203 // *could* be changed to directly index into a preloaded strings
204 // table initialized based on the `Mir.Intrinsic` enum.
205 const symbol_name = try wasm.internString(@tagName(datas[inst].intrinsic));
206
207 try code.ensureUnusedCapacity(gpa, 6);
208 code.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.call));
209 if (is_obj) {
210 try wasm.out_relocs.append(gpa, .{
211 .offset = @intCast(code.items.len),
212 .index = try wasm.symbolNameIndex(symbol_name),
213 .tag = .FUNCTION_INDEX_LEB,
214 .addend = 0,
215 });
216 code.appendNTimesAssumeCapacity(0, 5);
217 } else {
218 const func_index = try wasm.symbolNameFunctionIndex(symbol_name);
219 leb.writeUleb128(code.fixedWriter(), @intFromEnum(func_index)) catch unreachable;
220 }
221
222 inst += 1;
223 continue :loop tags[inst];
224 },
225
181 .global_set => {226 .global_set => {
182 try code.ensureUnusedCapacity(gpa, 6);227 try code.ensureUnusedCapacity(gpa, 6);
183 code.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.global_set));228 code.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.global_set));
src/arch/wasm/Mir.zig+182-6
...@@ -110,7 +110,7 @@ pub const Inst = struct {...@@ -110,7 +110,7 @@ pub const Inst = struct {
110 /// represents the label to jump to.110 /// represents the label to jump to.
111 ///111 ///
112 /// Data is extra of which the Payload's type is `JumpTable`112 /// Data is extra of which the Payload's type is `JumpTable`
113 br_table = 0x0E,113 br_table,
114 /// Returns from the function114 /// Returns from the function
115 ///115 ///
116 /// Uses `tag`.116 /// Uses `tag`.
...@@ -121,15 +121,14 @@ pub const Inst = struct {...@@ -121,15 +121,14 @@ pub const Inst = struct {
121 /// and index into the function table.121 /// and index into the function table.
122 ///122 ///
123 /// Uses `func_ty`123 /// Uses `func_ty`
124 call_indirect = 0x11,124 call_indirect,
125 /// Calls a function using `func_index`.
126 call_func,
127 /// Calls a function by its index.125 /// Calls a function by its index.
128 ///126 ///
129 /// The function is the auto-generated tag name function for the type127 /// The function is the auto-generated tag name function for the type
130 /// provided in `ip_index`.128 /// provided in `ip_index`.
131 call_tag_name,129 call_tag_name,
132130 /// Lowers to a `call` instruction, using `intrinsic`.
131 call_intrinsic,
133 /// Pops three values from the stack and pushes132 /// Pops three values from the stack and pushes
134 /// the first or second value dependent on the third value.133 /// the first or second value dependent on the third value.
135 /// Uses `tag`134 /// Uses `tag`
...@@ -609,8 +608,8 @@ pub const Inst = struct {...@@ -609,8 +608,8 @@ pub const Inst = struct {
609608
610 ip_index: InternPool.Index,609 ip_index: InternPool.Index,
611 nav_index: InternPool.Nav.Index,610 nav_index: InternPool.Nav.Index,
612 func_index: Wasm.FunctionIndex,
613 func_ty: Wasm.FunctionType.Index,611 func_ty: Wasm.FunctionType.Index,
612 intrinsic: Intrinsic,
614613
615 comptime {614 comptime {
616 switch (builtin.mode) {615 switch (builtin.mode) {
...@@ -700,3 +699,180 @@ pub const DbgLineColumn = struct {...@@ -700,3 +699,180 @@ pub const DbgLineColumn = struct {
700 line: u32,699 line: u32,
701 column: u32,700 column: u32,
702};701};
702
703/// Tag names exactly match the corresponding symbol name.
704pub const Intrinsic = enum(u32) {
705 __addhf3,
706 __addtf3,
707 __addxf3,
708 __ashlti3,
709 __ashrti3,
710 __bitreversedi2,
711 __bitreversesi2,
712 __bswapdi2,
713 __bswapsi2,
714 __ceilh,
715 __ceilx,
716 __cosh,
717 __cosx,
718 __divhf3,
719 __divtf3,
720 __divti3,
721 __divxf3,
722 __eqtf2,
723 __eqxf2,
724 __exp2h,
725 __exp2x,
726 __exph,
727 __expx,
728 __extenddftf2,
729 __extenddfxf2,
730 __extendhfsf2,
731 __extendhftf2,
732 __extendhfxf2,
733 __extendsftf2,
734 __extendsfxf2,
735 __extendxftf2,
736 __fabsh,
737 __fabsx,
738 __fixdfdi,
739 __fixdfsi,
740 __fixdfti,
741 __fixhfdi,
742 __fixhfsi,
743 __fixhfti,
744 __fixsfdi,
745 __fixsfsi,
746 __fixsfti,
747 __fixtfdi,
748 __fixtfsi,
749 __fixtfti,
750 __fixunsdfdi,
751 __fixunsdfsi,
752 __fixunsdfti,
753 __fixunshfdi,
754 __fixunshfsi,
755 __fixunshfti,
756 __fixunssfdi,
757 __fixunssfsi,
758 __fixunssfti,
759 __fixunstfdi,
760 __fixunstfsi,
761 __fixunstfti,
762 __fixunsxfdi,
763 __fixunsxfsi,
764 __fixunsxfti,
765 __fixxfdi,
766 __fixxfsi,
767 __fixxfti,
768 __floatdidf,
769 __floatdihf,
770 __floatdisf,
771 __floatditf,
772 __floatdixf,
773 __floatsidf,
774 __floatsihf,
775 __floatsisf,
776 __floatsitf,
777 __floatsixf,
778 __floattidf,
779 __floattihf,
780 __floattisf,
781 __floattitf,
782 __floattixf,
783 __floatundidf,
784 __floatundihf,
785 __floatundisf,
786 __floatunditf,
787 __floatundixf,
788 __floatunsidf,
789 __floatunsihf,
790 __floatunsisf,
791 __floatunsitf,
792 __floatunsixf,
793 __floatuntidf,
794 __floatuntihf,
795 __floatuntisf,
796 __floatuntitf,
797 __floatuntixf,
798 __floorh,
799 __floorx,
800 __fmah,
801 __fmax,
802 __fmaxh,
803 __fmaxx,
804 __fminh,
805 __fminx,
806 __fmodh,
807 __fmodx,
808 __getf2,
809 __gexf2,
810 __gttf2,
811 __gtxf2,
812 __letf2,
813 __lexf2,
814 __log10h,
815 __log10x,
816 __log2h,
817 __log2x,
818 __logh,
819 __logx,
820 __lshrti3,
821 __lttf2,
822 __ltxf2,
823 __modti3,
824 __mulhf3,
825 __mulodi4,
826 __muloti4,
827 __multf3,
828 __multi3,
829 __mulxf3,
830 __netf2,
831 __nexf2,
832 __roundh,
833 __roundx,
834 __sinh,
835 __sinx,
836 __sqrth,
837 __sqrtx,
838 __subhf3,
839 __subtf3,
840 __subxf3,
841 __tanh,
842 __tanx,
843 __trunch,
844 __truncsfhf2,
845 __trunctfdf2,
846 __trunctfhf2,
847 __trunctfsf2,
848 __trunctfxf2,
849 __truncx,
850 __truncxfdf2,
851 __truncxfhf2,
852 __truncxfsf2,
853 __udivti3,
854 __umodti3,
855 ceilq,
856 cosq,
857 exp2q,
858 expq,
859 fabsq,
860 floorq,
861 fmaf,
862 fmaq,
863 fmax,
864 fmaxf,
865 fmaxq,
866 fmin,
867 fminf,
868 fminq,
869 fmodq,
870 log10q,
871 log2q,
872 logq,
873 roundq,
874 sinq,
875 sqrtq,
876 tanq,
877 truncq,
878};