| ... | ... | @@ -1547,6 +1547,27 @@ fn asmRegisterRegisterMemory( |
| 1547 | 1547 | }); |
| 1548 | 1548 | } |
| 1549 | 1549 | |
| 1550 | fn asmRegisterRegisterMemoryRegister( |
| 1551 | self: *Self, |
| 1552 | tag: Mir.Inst.FixedTag, |
| 1553 | reg1: Register, |
| 1554 | reg2: Register, |
| 1555 | m: Memory, |
| 1556 | reg3: Register, |
| 1557 | ) !void { |
| 1558 | _ = try self.addInst(.{ |
| 1559 | .tag = tag[1], |
| 1560 | .ops = .rrmr, |
| 1561 | .data = .{ .rrrx = .{ |
| 1562 | .fixes = tag[0], |
| 1563 | .r1 = reg1, |
| 1564 | .r2 = reg2, |
| 1565 | .r3 = reg3, |
| 1566 | .payload = try self.addExtra(Mir.Memory.encode(m)), |
| 1567 | } }, |
| 1568 | }); |
| 1569 | } |
| 1570 | |
| 1550 | 1571 | fn asmMemory(self: *Self, tag: Mir.Inst.FixedTag, m: Memory) !void { |
| 1551 | 1572 | _ = try self.addInst(.{ |
| 1552 | 1573 | .tag = tag[1], |
| ... | ... | @@ -1570,6 +1591,25 @@ fn asmRegisterMemory(self: *Self, tag: Mir.Inst.FixedTag, reg: Register, m: Memo |
| 1570 | 1591 | }); |
| 1571 | 1592 | } |
| 1572 | 1593 | |
| 1594 | fn asmRegisterMemoryRegister( |
| 1595 | self: *Self, |
| 1596 | tag: Mir.Inst.FixedTag, |
| 1597 | reg1: Register, |
| 1598 | m: Memory, |
| 1599 | reg2: Register, |
| 1600 | ) !void { |
| 1601 | _ = try self.addInst(.{ |
| 1602 | .tag = tag[1], |
| 1603 | .ops = .rmr, |
| 1604 | .data = .{ .rrx = .{ |
| 1605 | .fixes = tag[0], |
| 1606 | .r1 = reg1, |
| 1607 | .r2 = reg2, |
| 1608 | .payload = try self.addExtra(Mir.Memory.encode(m)), |
| 1609 | } }, |
| 1610 | }); |
| 1611 | } |
| 1612 | |
| 1573 | 1613 | fn asmRegisterMemoryImmediate( |
| 1574 | 1614 | self: *Self, |
| 1575 | 1615 | tag: Mir.Inst.FixedTag, |
| ... | ... | @@ -2570,7 +2610,8 @@ fn restoreState(self: *Self, state: State, deaths: []const Air.Inst.Index, compt |
| 2570 | 2610 | |
| 2571 | 2611 | const ExpectedContents = [@typeInfo(RegisterManager.TrackedRegisters).Array.len]RegisterLock; |
| 2572 | 2612 | var stack align(@max(@alignOf(ExpectedContents), @alignOf(std.heap.StackFallbackAllocator(0)))) = |
| 2573 | | if (opts.update_tracking) ({}) else std.heap.stackFallback(@sizeOf(ExpectedContents), self.gpa); |
| 2613 | if (opts.update_tracking) |
| 2614 | {} else std.heap.stackFallback(@sizeOf(ExpectedContents), self.gpa); |
| 2574 | 2615 | |
| 2575 | 2616 | var reg_locks = if (opts.update_tracking) {} else try std.ArrayList(RegisterLock).initCapacity( |
| 2576 | 2617 | stack.get(), |
| ... | ... | @@ -2812,11 +2853,14 @@ fn airFptrunc(self: *Self, inst: Air.Inst.Index) !void { |
| 2812 | 2853 | } |
| 2813 | 2854 | |
| 2814 | 2855 | fn airFpext(self: *Self, inst: Air.Inst.Index) !void { |
| 2856 | const mod = self.bin_file.comp.module.?; |
| 2815 | 2857 | const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; |
| 2816 | 2858 | const dst_ty = self.typeOfIndex(inst); |
| 2817 | | const dst_bits = dst_ty.floatBits(self.target.*); |
| 2859 | const dst_scalar_ty = dst_ty.scalarType(mod); |
| 2860 | const dst_bits = dst_scalar_ty.floatBits(self.target.*); |
| 2818 | 2861 | const src_ty = self.typeOf(ty_op.operand); |
| 2819 | | const src_bits = src_ty.floatBits(self.target.*); |
| 2862 | const src_scalar_ty = src_ty.scalarType(mod); |
| 2863 | const src_bits = src_scalar_ty.floatBits(self.target.*); |
| 2820 | 2864 | |
| 2821 | 2865 | const result = result: { |
| 2822 | 2866 | if (switch (src_bits) { |
| ... | ... | @@ -2840,94 +2884,290 @@ fn airFpext(self: *Self, inst: Air.Inst.Index) !void { |
| 2840 | 2884 | }, |
| 2841 | 2885 | else => unreachable, |
| 2842 | 2886 | }) { |
| 2887 | if (dst_ty.isVector(mod)) break :result null; |
| 2843 | 2888 | var callee_buf: ["__extend?f?f2".len]u8 = undefined; |
| 2844 | 2889 | break :result try self.genCall(.{ .lib = .{ |
| 2845 | | .return_type = self.floatCompilerRtAbiType(dst_ty, src_ty).toIntern(), |
| 2846 | | .param_types = &.{self.floatCompilerRtAbiType(src_ty, dst_ty).toIntern()}, |
| 2890 | .return_type = self.floatCompilerRtAbiType(dst_scalar_ty, src_scalar_ty).toIntern(), |
| 2891 | .param_types = &.{self.floatCompilerRtAbiType(src_scalar_ty, dst_scalar_ty).toIntern()}, |
| 2847 | 2892 | .callee = std.fmt.bufPrint(&callee_buf, "__extend{c}f{c}f2", .{ |
| 2848 | 2893 | floatCompilerRtAbiName(src_bits), |
| 2849 | 2894 | floatCompilerRtAbiName(dst_bits), |
| 2850 | 2895 | }) catch unreachable, |
| 2851 | | } }, &.{src_ty}, &.{.{ .air_ref = ty_op.operand }}); |
| 2896 | } }, &.{src_scalar_ty}, &.{.{ .air_ref = ty_op.operand }}); |
| 2852 | 2897 | } |
| 2853 | 2898 | |
| 2899 | const src_abi_size: u32 = @intCast(src_ty.abiSize(mod)); |
| 2854 | 2900 | const src_mcv = try self.resolveInst(ty_op.operand); |
| 2855 | 2901 | const dst_mcv = if (src_mcv.isRegister() and self.reuseOperand(inst, ty_op.operand, 0, src_mcv)) |
| 2856 | 2902 | src_mcv |
| 2857 | 2903 | else |
| 2858 | 2904 | try self.copyToRegisterWithInstTracking(inst, dst_ty, src_mcv); |
| 2859 | | const dst_reg = dst_mcv.getReg().?.to128(); |
| 2905 | const dst_reg = dst_mcv.getReg().?; |
| 2906 | const dst_alias = registerAlias(dst_reg, @intCast(@max(dst_ty.abiSize(mod), 16))); |
| 2860 | 2907 | const dst_lock = self.register_manager.lockReg(dst_reg); |
| 2861 | 2908 | defer if (dst_lock) |lock| self.register_manager.unlockReg(lock); |
| 2862 | 2909 | |
| 2910 | const vec_len = if (dst_ty.isVector(mod)) dst_ty.vectorLen(mod) else 1; |
| 2863 | 2911 | if (src_bits == 16) { |
| 2864 | 2912 | assert(self.hasFeature(.f16c)); |
| 2865 | 2913 | const mat_src_reg = if (src_mcv.isRegister()) |
| 2866 | 2914 | src_mcv.getReg().? |
| 2867 | 2915 | else |
| 2868 | 2916 | try self.copyToTmpRegister(src_ty, src_mcv); |
| 2869 | | try self.asmRegisterRegister(.{ .v_ps, .cvtph2 }, dst_reg, mat_src_reg.to128()); |
| 2917 | try self.asmRegisterRegister( |
| 2918 | .{ .v_ps, .cvtph2 }, |
| 2919 | dst_alias, |
| 2920 | registerAlias(mat_src_reg, src_abi_size), |
| 2921 | ); |
| 2870 | 2922 | switch (dst_bits) { |
| 2871 | 2923 | 32 => {}, |
| 2872 | 2924 | 64 => try self.asmRegisterRegisterRegister( |
| 2873 | 2925 | .{ .v_sd, .cvtss2 }, |
| 2874 | | dst_reg, |
| 2875 | | dst_reg, |
| 2876 | | dst_reg, |
| 2926 | dst_alias, |
| 2927 | dst_alias, |
| 2928 | dst_alias, |
| 2877 | 2929 | ), |
| 2878 | 2930 | else => unreachable, |
| 2879 | 2931 | } |
| 2880 | 2932 | } else { |
| 2881 | 2933 | assert(src_bits == 32 and dst_bits == 64); |
| 2882 | | if (self.hasFeature(.avx)) if (src_mcv.isMemory()) try self.asmRegisterRegisterMemory( |
| 2883 | | .{ .v_sd, .cvtss2 }, |
| 2884 | | dst_reg, |
| 2885 | | dst_reg, |
| 2886 | | try src_mcv.mem(self, .dword), |
| 2887 | | ) else try self.asmRegisterRegisterRegister( |
| 2888 | | .{ .v_sd, .cvtss2 }, |
| 2889 | | dst_reg, |
| 2890 | | dst_reg, |
| 2891 | | (if (src_mcv.isRegister()) |
| 2892 | | src_mcv.getReg().? |
| 2893 | | else |
| 2894 | | try self.copyToTmpRegister(src_ty, src_mcv)).to128(), |
| 2895 | | ) else if (src_mcv.isMemory()) try self.asmRegisterMemory( |
| 2896 | | .{ ._sd, .cvtss2 }, |
| 2897 | | dst_reg, |
| 2898 | | try src_mcv.mem(self, .dword), |
| 2934 | if (self.hasFeature(.avx)) switch (vec_len) { |
| 2935 | 1 => if (src_mcv.isMemory()) try self.asmRegisterRegisterMemory( |
| 2936 | .{ .v_sd, .cvtss2 }, |
| 2937 | dst_alias, |
| 2938 | dst_alias, |
| 2939 | try src_mcv.mem(self, self.memSize(src_ty)), |
| 2940 | ) else try self.asmRegisterRegisterRegister( |
| 2941 | .{ .v_sd, .cvtss2 }, |
| 2942 | dst_alias, |
| 2943 | dst_alias, |
| 2944 | registerAlias(if (src_mcv.isRegister()) |
| 2945 | src_mcv.getReg().? |
| 2946 | else |
| 2947 | try self.copyToTmpRegister(src_ty, src_mcv), src_abi_size), |
| 2948 | ), |
| 2949 | 2...4 => if (src_mcv.isMemory()) try self.asmRegisterMemory( |
| 2950 | .{ .v_pd, .cvtps2 }, |
| 2951 | dst_alias, |
| 2952 | try src_mcv.mem(self, self.memSize(src_ty)), |
| 2953 | ) else try self.asmRegisterRegister( |
| 2954 | .{ .v_pd, .cvtps2 }, |
| 2955 | dst_alias, |
| 2956 | registerAlias(if (src_mcv.isRegister()) |
| 2957 | src_mcv.getReg().? |
| 2958 | else |
| 2959 | try self.copyToTmpRegister(src_ty, src_mcv), src_abi_size), |
| 2960 | ), |
| 2961 | else => break :result null, |
| 2962 | } else if (src_mcv.isMemory()) try self.asmRegisterMemory( |
| 2963 | switch (vec_len) { |
| 2964 | 1 => .{ ._sd, .cvtss2 }, |
| 2965 | 2 => .{ ._pd, .cvtps2 }, |
| 2966 | else => break :result null, |
| 2967 | }, |
| 2968 | dst_alias, |
| 2969 | try src_mcv.mem(self, self.memSize(src_ty)), |
| 2899 | 2970 | ) else try self.asmRegisterRegister( |
| 2900 | | .{ ._sd, .cvtss2 }, |
| 2901 | | dst_reg, |
| 2902 | | (if (src_mcv.isRegister()) |
| 2971 | switch (vec_len) { |
| 2972 | 1 => .{ ._sd, .cvtss2 }, |
| 2973 | 2 => .{ ._pd, .cvtps2 }, |
| 2974 | else => break :result null, |
| 2975 | }, |
| 2976 | dst_alias, |
| 2977 | registerAlias(if (src_mcv.isRegister()) |
| 2903 | 2978 | src_mcv.getReg().? |
| 2904 | 2979 | else |
| 2905 | | try self.copyToTmpRegister(src_ty, src_mcv)).to128(), |
| 2980 | try self.copyToTmpRegister(src_ty, src_mcv), src_abi_size), |
| 2906 | 2981 | ); |
| 2907 | 2982 | } |
| 2908 | 2983 | break :result dst_mcv; |
| 2909 | | }; |
| 2984 | } orelse return self.fail("TODO implement airFpext from {} to {}", .{ |
| 2985 | src_ty.fmt(mod), dst_ty.fmt(mod), |
| 2986 | }); |
| 2910 | 2987 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| 2911 | 2988 | } |
| 2912 | 2989 | |
| 2913 | 2990 | fn airIntCast(self: *Self, inst: Air.Inst.Index) !void { |
| 2914 | 2991 | const mod = self.bin_file.comp.module.?; |
| 2915 | 2992 | const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; |
| 2916 | | const result: MCValue = result: { |
| 2917 | | const src_ty = self.typeOf(ty_op.operand); |
| 2918 | | const src_int_info = src_ty.intInfo(mod); |
| 2993 | const src_ty = self.typeOf(ty_op.operand); |
| 2994 | const dst_ty = self.typeOfIndex(inst); |
| 2919 | 2995 | |
| 2920 | | const dst_ty = self.typeOfIndex(inst); |
| 2921 | | const dst_int_info = dst_ty.intInfo(mod); |
| 2922 | | const abi_size: u32 = @intCast(dst_ty.abiSize(mod)); |
| 2996 | const result = @as(?MCValue, result: { |
| 2997 | const dst_abi_size: u32 = @intCast(dst_ty.abiSize(mod)); |
| 2923 | 2998 | |
| 2924 | | const min_ty = if (dst_int_info.bits < src_int_info.bits) dst_ty else src_ty; |
| 2999 | const src_int_info = src_ty.intInfo(mod); |
| 3000 | const dst_int_info = dst_ty.intInfo(mod); |
| 2925 | 3001 | const extend = switch (src_int_info.signedness) { |
| 2926 | 3002 | .signed => dst_int_info, |
| 2927 | 3003 | .unsigned => src_int_info, |
| 2928 | 3004 | }.signedness; |
| 2929 | 3005 | |
| 2930 | 3006 | const src_mcv = try self.resolveInst(ty_op.operand); |
| 3007 | if (dst_ty.isVector(mod)) { |
| 3008 | const src_abi_size: u32 = @intCast(src_ty.abiSize(mod)); |
| 3009 | const max_abi_size = @max(dst_abi_size, src_abi_size); |
| 3010 | if (max_abi_size > @as(u32, if (self.hasFeature(.avx2)) 32 else 16)) break :result null; |
| 3011 | const has_avx = self.hasFeature(.avx); |
| 3012 | |
| 3013 | const dst_elem_abi_size = dst_ty.childType(mod).abiSize(mod); |
| 3014 | const src_elem_abi_size = src_ty.childType(mod).abiSize(mod); |
| 3015 | switch (math.order(dst_elem_abi_size, src_elem_abi_size)) { |
| 3016 | .lt => { |
| 3017 | const mir_tag: Mir.Inst.FixedTag = switch (dst_elem_abi_size) { |
| 3018 | else => break :result null, |
| 3019 | 1 => switch (src_elem_abi_size) { |
| 3020 | else => break :result null, |
| 3021 | 2 => switch (dst_int_info.signedness) { |
| 3022 | .signed => if (has_avx) .{ .vp_b, .ackssw } else .{ .p_b, .ackssw }, |
| 3023 | .unsigned => if (has_avx) .{ .vp_b, .ackusw } else .{ .p_b, .ackusw }, |
| 3024 | }, |
| 3025 | }, |
| 3026 | 2 => switch (src_elem_abi_size) { |
| 3027 | else => break :result null, |
| 3028 | 4 => switch (dst_int_info.signedness) { |
| 3029 | .signed => if (has_avx) .{ .vp_w, .ackssd } else .{ .p_w, .ackssd }, |
| 3030 | .unsigned => if (has_avx) |
| 3031 | .{ .vp_w, .ackusd } |
| 3032 | else if (self.hasFeature(.sse4_1)) |
| 3033 | .{ .p_w, .ackusd } |
| 3034 | else |
| 3035 | break :result null, |
| 3036 | }, |
| 3037 | }, |
| 3038 | }; |
| 3039 | |
| 3040 | const dst_mcv: MCValue = if (src_mcv.isRegister() and |
| 3041 | self.reuseOperand(inst, ty_op.operand, 0, src_mcv)) |
| 3042 | src_mcv |
| 3043 | else if (has_avx and src_mcv.isRegister()) |
| 3044 | .{ .register = try self.register_manager.allocReg(inst, abi.RegisterClass.sse) } |
| 3045 | else |
| 3046 | try self.copyToRegisterWithInstTracking(inst, src_ty, src_mcv); |
| 3047 | const dst_reg = dst_mcv.getReg().?; |
| 3048 | const dst_alias = registerAlias(dst_reg, dst_abi_size); |
| 3049 | |
| 3050 | if (has_avx) try self.asmRegisterRegisterRegister( |
| 3051 | mir_tag, |
| 3052 | dst_alias, |
| 3053 | registerAlias(if (src_mcv.isRegister()) |
| 3054 | src_mcv.getReg().? |
| 3055 | else |
| 3056 | dst_reg, src_abi_size), |
| 3057 | dst_alias, |
| 3058 | ) else try self.asmRegisterRegister( |
| 3059 | mir_tag, |
| 3060 | dst_alias, |
| 3061 | dst_alias, |
| 3062 | ); |
| 3063 | break :result dst_mcv; |
| 3064 | }, |
| 3065 | .eq => if (self.reuseOperand(inst, ty_op.operand, 0, src_mcv)) |
| 3066 | break :result src_mcv |
| 3067 | else { |
| 3068 | const dst_mcv = try self.allocRegOrMem(inst, true); |
| 3069 | try self.genCopy(dst_ty, dst_mcv, src_mcv, .{}); |
| 3070 | break :result dst_mcv; |
| 3071 | }, |
| 3072 | .gt => if (self.hasFeature(.sse4_1)) { |
| 3073 | const mir_tag: Mir.Inst.FixedTag = .{ switch (dst_elem_abi_size) { |
| 3074 | else => break :result null, |
| 3075 | 2 => if (has_avx) .vp_w else .p_w, |
| 3076 | 4 => if (has_avx) .vp_d else .p_d, |
| 3077 | 8 => if (has_avx) .vp_q else .p_q, |
| 3078 | }, switch (src_elem_abi_size) { |
| 3079 | else => break :result null, |
| 3080 | 1 => switch (extend) { |
| 3081 | .signed => .movsxb, |
| 3082 | .unsigned => .movzxb, |
| 3083 | }, |
| 3084 | 2 => switch (extend) { |
| 3085 | .signed => .movsxw, |
| 3086 | .unsigned => .movzxw, |
| 3087 | }, |
| 3088 | 4 => switch (extend) { |
| 3089 | .signed => .movsxd, |
| 3090 | .unsigned => .movzxd, |
| 3091 | }, |
| 3092 | } }; |
| 3093 | |
| 3094 | const dst_mcv: MCValue = if (src_mcv.isRegister() and |
| 3095 | self.reuseOperand(inst, ty_op.operand, 0, src_mcv)) |
| 3096 | src_mcv |
| 3097 | else |
| 3098 | .{ .register = try self.register_manager.allocReg(inst, abi.RegisterClass.sse) }; |
| 3099 | const dst_reg = dst_mcv.getReg().?; |
| 3100 | const dst_alias = registerAlias(dst_reg, dst_abi_size); |
| 3101 | |
| 3102 | if (src_mcv.isMemory()) try self.asmRegisterMemory( |
| 3103 | mir_tag, |
| 3104 | dst_alias, |
| 3105 | try src_mcv.mem(self, self.memSize(src_ty)), |
| 3106 | ) else try self.asmRegisterRegister( |
| 3107 | mir_tag, |
| 3108 | dst_alias, |
| 3109 | registerAlias(if (src_mcv.isRegister()) |
| 3110 | src_mcv.getReg().? |
| 3111 | else |
| 3112 | try self.copyToTmpRegister(src_ty, src_mcv), src_abi_size), |
| 3113 | ); |
| 3114 | break :result dst_mcv; |
| 3115 | } else { |
| 3116 | const mir_tag: Mir.Inst.FixedTag = switch (dst_elem_abi_size) { |
| 3117 | else => break :result null, |
| 3118 | 2 => switch (src_elem_abi_size) { |
| 3119 | else => break :result null, |
| 3120 | 1 => .{ .p_, .unpcklbw }, |
| 3121 | }, |
| 3122 | 4 => switch (src_elem_abi_size) { |
| 3123 | else => break :result null, |
| 3124 | 2 => .{ .p_, .unpcklwd }, |
| 3125 | }, |
| 3126 | 8 => switch (src_elem_abi_size) { |
| 3127 | else => break :result null, |
| 3128 | 2 => .{ .p_, .unpckldq }, |
| 3129 | }, |
| 3130 | }; |
| 3131 | |
| 3132 | const dst_mcv: MCValue = if (src_mcv.isRegister() and |
| 3133 | self.reuseOperand(inst, ty_op.operand, 0, src_mcv)) |
| 3134 | src_mcv |
| 3135 | else |
| 3136 | try self.copyToRegisterWithInstTracking(inst, dst_ty, src_mcv); |
| 3137 | const dst_reg = dst_mcv.getReg().?; |
| 3138 | |
| 3139 | const ext_reg = try self.register_manager.allocReg(null, abi.RegisterClass.sse); |
| 3140 | const ext_alias = registerAlias(ext_reg, src_abi_size); |
| 3141 | const ext_lock = self.register_manager.lockRegAssumeUnused(ext_reg); |
| 3142 | defer self.register_manager.unlockReg(ext_lock); |
| 3143 | |
| 3144 | try self.asmRegisterRegister(.{ .p_, .xor }, ext_alias, ext_alias); |
| 3145 | switch (extend) { |
| 3146 | .signed => try self.asmRegisterRegister( |
| 3147 | .{ switch (src_elem_abi_size) { |
| 3148 | else => unreachable, |
| 3149 | 1 => .p_b, |
| 3150 | 2 => .p_w, |
| 3151 | 4 => .p_d, |
| 3152 | }, .cmpgt }, |
| 3153 | ext_alias, |
| 3154 | registerAlias(dst_reg, src_abi_size), |
| 3155 | ), |
| 3156 | .unsigned => {}, |
| 3157 | } |
| 3158 | try self.asmRegisterRegister( |
| 3159 | mir_tag, |
| 3160 | registerAlias(dst_reg, dst_abi_size), |
| 3161 | registerAlias(ext_reg, dst_abi_size), |
| 3162 | ); |
| 3163 | break :result dst_mcv; |
| 3164 | }, |
| 3165 | } |
| 3166 | @compileError("unreachable"); |
| 3167 | } |
| 3168 | |
| 3169 | const min_ty = if (dst_int_info.bits < src_int_info.bits) dst_ty else src_ty; |
| 3170 | |
| 2931 | 3171 | const src_storage_bits: u16 = switch (src_mcv) { |
| 2932 | 3172 | .register, .register_offset => 64, |
| 2933 | 3173 | .register_pair => 128, |
| ... | ... | @@ -2945,13 +3185,13 @@ fn airIntCast(self: *Self, inst: Air.Inst.Index) !void { |
| 2945 | 3185 | }; |
| 2946 | 3186 | |
| 2947 | 3187 | if (dst_int_info.bits <= src_int_info.bits) break :result if (dst_mcv.isRegister()) |
| 2948 | | .{ .register = registerAlias(dst_mcv.getReg().?, abi_size) } |
| 3188 | .{ .register = registerAlias(dst_mcv.getReg().?, dst_abi_size) } |
| 2949 | 3189 | else |
| 2950 | 3190 | dst_mcv; |
| 2951 | 3191 | |
| 2952 | 3192 | if (dst_mcv.isRegister()) { |
| 2953 | 3193 | try self.truncateRegister(src_ty, dst_mcv.getReg().?); |
| 2954 | | break :result .{ .register = registerAlias(dst_mcv.getReg().?, abi_size) }; |
| 3194 | break :result .{ .register = registerAlias(dst_mcv.getReg().?, dst_abi_size) }; |
| 2955 | 3195 | } |
| 2956 | 3196 | |
| 2957 | 3197 | const src_limbs_len = math.divCeil(u16, src_int_info.bits, 64) catch unreachable; |
| ... | ... | @@ -2999,7 +3239,9 @@ fn airIntCast(self: *Self, inst: Air.Inst.Index) !void { |
| 2999 | 3239 | ); |
| 3000 | 3240 | |
| 3001 | 3241 | break :result dst_mcv; |
| 3002 | | }; |
| 3242 | }) orelse return self.fail("TODO implement airIntCast from {} to {}", .{ |
| 3243 | src_ty.fmt(mod), dst_ty.fmt(mod), |
| 3244 | }); |
| 3003 | 3245 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| 3004 | 3246 | } |
| 3005 | 3247 | |
| ... | ... | @@ -3022,7 +3264,7 @@ fn airTrunc(self: *Self, inst: Air.Inst.Index) !void { |
| 3022 | 3264 | src_mcv |
| 3023 | 3265 | else if (dst_abi_size <= 8) |
| 3024 | 3266 | try self.copyToRegisterWithInstTracking(inst, dst_ty, src_mcv) |
| 3025 | | else if (dst_abi_size <= 16) dst: { |
| 3267 | else if (dst_abi_size <= 16 and !dst_ty.isVector(mod)) dst: { |
| 3026 | 3268 | const dst_regs = |
| 3027 | 3269 | try self.register_manager.allocRegs(2, .{ inst, inst }, abi.RegisterClass.gp); |
| 3028 | 3270 | const dst_mcv: MCValue = .{ .register_pair = dst_regs }; |
| ... | ... | @@ -3032,26 +3274,29 @@ fn airTrunc(self: *Self, inst: Air.Inst.Index) !void { |
| 3032 | 3274 | try self.genCopy(dst_ty, dst_mcv, src_mcv, .{}); |
| 3033 | 3275 | break :dst dst_mcv; |
| 3034 | 3276 | } else dst: { |
| 3035 | | const dst_mcv = try self.allocRegOrMem(inst, true); |
| 3036 | | try self.genCopy(dst_ty, dst_mcv, src_mcv, .{}); |
| 3277 | const dst_mcv = try self.allocRegOrMemAdvanced(src_ty, inst, true); |
| 3278 | try self.genCopy(src_ty, dst_mcv, src_mcv, .{}); |
| 3037 | 3279 | break :dst dst_mcv; |
| 3038 | 3280 | }; |
| 3039 | 3281 | |
| 3040 | 3282 | if (dst_ty.zigTypeTag(mod) == .Vector) { |
| 3041 | 3283 | assert(src_ty.zigTypeTag(mod) == .Vector and dst_ty.vectorLen(mod) == src_ty.vectorLen(mod)); |
| 3042 | | const dst_info = dst_ty.childType(mod).intInfo(mod); |
| 3043 | | const src_info = src_ty.childType(mod).intInfo(mod); |
| 3044 | | const mir_tag = @as(?Mir.Inst.FixedTag, switch (dst_info.bits) { |
| 3045 | | 8 => switch (src_info.bits) { |
| 3046 | | 16 => switch (dst_ty.vectorLen(mod)) { |
| 3284 | const dst_elem_ty = dst_ty.childType(mod); |
| 3285 | const dst_elem_abi_size: u32 = @intCast(dst_elem_ty.abiSize(mod)); |
| 3286 | const src_elem_ty = src_ty.childType(mod); |
| 3287 | const src_elem_abi_size: u32 = @intCast(src_elem_ty.abiSize(mod)); |
| 3288 | |
| 3289 | const mir_tag = @as(?Mir.Inst.FixedTag, switch (dst_elem_abi_size) { |
| 3290 | 1 => switch (src_elem_abi_size) { |
| 3291 | 2 => switch (dst_ty.vectorLen(mod)) { |
| 3047 | 3292 | 1...8 => if (self.hasFeature(.avx)) .{ .vp_b, .ackusw } else .{ .p_b, .ackusw }, |
| 3048 | 3293 | 9...16 => if (self.hasFeature(.avx2)) .{ .vp_b, .ackusw } else null, |
| 3049 | 3294 | else => null, |
| 3050 | 3295 | }, |
| 3051 | 3296 | else => null, |
| 3052 | 3297 | }, |
| 3053 | | 16 => switch (src_info.bits) { |
| 3054 | | 32 => switch (dst_ty.vectorLen(mod)) { |
| 3298 | 2 => switch (src_elem_abi_size) { |
| 3299 | 4 => switch (dst_ty.vectorLen(mod)) { |
| 3055 | 3300 | 1...4 => if (self.hasFeature(.avx)) |
| 3056 | 3301 | .{ .vp_w, .ackusd } |
| 3057 | 3302 | else if (self.hasFeature(.sse4_1)) |
| ... | ... | @@ -3066,12 +3311,14 @@ fn airTrunc(self: *Self, inst: Air.Inst.Index) !void { |
| 3066 | 3311 | else => null, |
| 3067 | 3312 | }) orelse return self.fail("TODO implement airTrunc for {}", .{dst_ty.fmt(mod)}); |
| 3068 | 3313 | |
| 3069 | | const elem_ty = src_ty.childType(mod); |
| 3070 | | const mask_val = try mod.intValue(elem_ty, @as(u64, math.maxInt(u64)) >> @intCast(64 - dst_info.bits)); |
| 3314 | const dst_info = dst_elem_ty.intInfo(mod); |
| 3315 | const src_info = src_elem_ty.intInfo(mod); |
| 3316 | |
| 3317 | const mask_val = try mod.intValue(src_elem_ty, @as(u64, math.maxInt(u64)) >> @intCast(64 - dst_info.bits)); |
| 3071 | 3318 | |
| 3072 | 3319 | const splat_ty = try mod.vectorType(.{ |
| 3073 | 3320 | .len = @intCast(@divExact(@as(u64, if (src_abi_size > 16) 256 else 128), src_info.bits)), |
| 3074 | | .child = elem_ty.ip_index, |
| 3321 | .child = src_elem_ty.ip_index, |
| 3075 | 3322 | }); |
| 3076 | 3323 | const splat_abi_size: u32 = @intCast(splat_ty.abiSize(mod)); |
| 3077 | 3324 | |
| ... | ... | @@ -3086,22 +3333,40 @@ fn airTrunc(self: *Self, inst: Air.Inst.Index) !void { |
| 3086 | 3333 | else => .{ .register = try self.copyToTmpRegister(Type.usize, splat_mcv.address()) }, |
| 3087 | 3334 | }; |
| 3088 | 3335 | |
| 3089 | | const dst_reg = registerAlias(dst_mcv.getReg().?, src_abi_size); |
| 3336 | const dst_reg = dst_mcv.getReg().?; |
| 3337 | const dst_alias = registerAlias(dst_reg, src_abi_size); |
| 3090 | 3338 | if (self.hasFeature(.avx)) { |
| 3091 | 3339 | try self.asmRegisterRegisterMemory( |
| 3092 | 3340 | .{ .vp_, .@"and" }, |
| 3093 | | dst_reg, |
| 3094 | | dst_reg, |
| 3341 | dst_alias, |
| 3342 | dst_alias, |
| 3095 | 3343 | try splat_addr_mcv.deref().mem(self, Memory.Size.fromSize(splat_abi_size)), |
| 3096 | 3344 | ); |
| 3097 | | try self.asmRegisterRegisterRegister(mir_tag, dst_reg, dst_reg, dst_reg); |
| 3345 | if (src_abi_size > 16) { |
| 3346 | const temp_reg = try self.register_manager.allocReg(null, abi.RegisterClass.sse); |
| 3347 | const temp_lock = self.register_manager.lockRegAssumeUnused(temp_reg); |
| 3348 | defer self.register_manager.unlockReg(temp_lock); |
| 3349 | |
| 3350 | try self.asmRegisterRegisterImmediate( |
| 3351 | .{ if (self.hasFeature(.avx2)) .v_i128 else .v_f128, .extract }, |
| 3352 | registerAlias(temp_reg, dst_abi_size), |
| 3353 | dst_alias, |
| 3354 | Immediate.u(1), |
| 3355 | ); |
| 3356 | try self.asmRegisterRegisterRegister( |
| 3357 | mir_tag, |
| 3358 | registerAlias(dst_reg, dst_abi_size), |
| 3359 | registerAlias(dst_reg, dst_abi_size), |
| 3360 | registerAlias(temp_reg, dst_abi_size), |
| 3361 | ); |
| 3362 | } else try self.asmRegisterRegisterRegister(mir_tag, dst_alias, dst_alias, dst_alias); |
| 3098 | 3363 | } else { |
| 3099 | 3364 | try self.asmRegisterMemory( |
| 3100 | 3365 | .{ .p_, .@"and" }, |
| 3101 | | dst_reg, |
| 3366 | dst_alias, |
| 3102 | 3367 | try splat_addr_mcv.deref().mem(self, Memory.Size.fromSize(splat_abi_size)), |
| 3103 | 3368 | ); |
| 3104 | | try self.asmRegisterRegister(mir_tag, dst_reg, dst_reg); |
| 3369 | try self.asmRegisterRegister(mir_tag, dst_alias, dst_alias); |
| 3105 | 3370 | } |
| 3106 | 3371 | break :result dst_mcv; |
| 3107 | 3372 | } |
| ... | ... | @@ -4045,7 +4310,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 4045 | 4310 | if (dst_info.bits > 128 and dst_info.signedness == .unsigned) { |
| 4046 | 4311 | const slow_inc = self.hasFeature(.slow_incdec); |
| 4047 | 4312 | const abi_size: u32 = @intCast(dst_ty.abiSize(mod)); |
| 4048 | | const limb_len = std.math.divCeil(u32, abi_size, 8) catch unreachable; |
| 4313 | const limb_len = math.divCeil(u32, abi_size, 8) catch unreachable; |
| 4049 | 4314 | |
| 4050 | 4315 | try self.spillRegisters(&.{ .rax, .rcx, .rdx }); |
| 4051 | 4316 | const reg_locks = self.register_manager.lockRegsAssumeUnused(3, .{ .rax, .rcx, .rdx }); |
| ... | ... | @@ -4534,7 +4799,7 @@ fn airShlShrBinOp(self: *Self, inst: Air.Inst.Index) !void { |
| 4534 | 4799 | switch (lhs_ty.zigTypeTag(mod)) { |
| 4535 | 4800 | .Int => { |
| 4536 | 4801 | try self.spillRegisters(&.{.rcx}); |
| 4537 | | try self.register_manager.getReg(.rcx, null); |
| 4802 | try self.register_manager.getKnownReg(.rcx, null); |
| 4538 | 4803 | const lhs_mcv = try self.resolveInst(bin_op.lhs); |
| 4539 | 4804 | const rhs_mcv = try self.resolveInst(bin_op.rhs); |
| 4540 | 4805 | |
| ... | ... | @@ -6560,7 +6825,7 @@ fn floatSign(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, ty: Type) |
| 6560 | 6825 | |
| 6561 | 6826 | const dst_mcv: MCValue = .{ .register = .st0 }; |
| 6562 | 6827 | if (!std.meta.eql(src_mcv, dst_mcv) or !self.reuseOperand(inst, operand, 0, src_mcv)) |
| 6563 | | try self.register_manager.getReg(.st0, inst); |
| 6828 | try self.register_manager.getKnownReg(.st0, inst); |
| 6564 | 6829 | |
| 6565 | 6830 | try self.genCopy(ty, dst_mcv, src_mcv, .{}); |
| 6566 | 6831 | switch (tag) { |
| ... | ... | @@ -6894,7 +7159,7 @@ fn airAbs(self: *Self, inst: Air.Inst.Index) !void { |
| 6894 | 7159 | }, |
| 6895 | 7160 | else => { |
| 6896 | 7161 | const abi_size: u31 = @intCast(ty.abiSize(mod)); |
| 6897 | | const limb_len = std.math.divCeil(u31, abi_size, 8) catch unreachable; |
| 7162 | const limb_len = math.divCeil(u31, abi_size, 8) catch unreachable; |
| 6898 | 7163 | |
| 6899 | 7164 | const tmp_regs = |
| 6900 | 7165 | try self.register_manager.allocRegs(3, .{null} ** 3, abi.RegisterClass.gp); |
| ... | ... | @@ -8181,7 +8446,7 @@ fn genShiftBinOpMir( |
| 8181 | 8446 | try self.asmRegisterImmediate( |
| 8182 | 8447 | .{ ._, .@"and" }, |
| 8183 | 8448 | .cl, |
| 8184 | | Immediate.u(std.math.maxInt(u6)), |
| 8449 | Immediate.u(math.maxInt(u6)), |
| 8185 | 8450 | ); |
| 8186 | 8451 | try self.asmRegisterImmediate( |
| 8187 | 8452 | .{ ._r, .sh }, |
| ... | ... | @@ -8218,7 +8483,7 @@ fn genShiftBinOpMir( |
| 8218 | 8483 | try self.asmRegisterImmediate( |
| 8219 | 8484 | .{ ._, .@"and" }, |
| 8220 | 8485 | .cl, |
| 8221 | | Immediate.u(std.math.maxInt(u6)), |
| 8486 | Immediate.u(math.maxInt(u6)), |
| 8222 | 8487 | ); |
| 8223 | 8488 | try self.asmRegisterImmediate( |
| 8224 | 8489 | .{ ._r, .sh }, |
| ... | ... | @@ -8283,7 +8548,7 @@ fn genShiftBinOpMir( |
| 8283 | 8548 | }, .sh }, |
| 8284 | 8549 | temp_regs[2].to64(), |
| 8285 | 8550 | temp_regs[3].to64(), |
| 8286 | | Immediate.u(shift_imm & std.math.maxInt(u6)), |
| 8551 | Immediate.u(shift_imm & math.maxInt(u6)), |
| 8287 | 8552 | ), |
| 8288 | 8553 | else => try self.asmRegisterRegisterRegister(.{ switch (tag[0]) { |
| 8289 | 8554 | ._l => ._ld, |
| ... | ... | @@ -8338,7 +8603,7 @@ fn genShiftBinOpMir( |
| 8338 | 8603 | .immediate => |shift_imm| try self.asmRegisterImmediate( |
| 8339 | 8604 | tag, |
| 8340 | 8605 | temp_regs[2].to64(), |
| 8341 | | Immediate.u(shift_imm & std.math.maxInt(u6)), |
| 8606 | Immediate.u(shift_imm & math.maxInt(u6)), |
| 8342 | 8607 | ), |
| 8343 | 8608 | else => try self.asmRegisterRegister(tag, temp_regs[2].to64(), .cl), |
| 8344 | 8609 | } |
| ... | ... | @@ -8794,7 +9059,7 @@ fn genShiftBinOp( |
| 8794 | 9059 | lhs_ty.fmt(mod), |
| 8795 | 9060 | }); |
| 8796 | 9061 | |
| 8797 | | try self.register_manager.getReg(.rcx, null); |
| 9062 | try self.register_manager.getKnownReg(.rcx, null); |
| 8798 | 9063 | const rcx_lock = self.register_manager.lockReg(.rcx); |
| 8799 | 9064 | defer if (rcx_lock) |lock| self.register_manager.unlockReg(lock); |
| 8800 | 9065 | |
| ... | ... | @@ -8933,7 +9198,7 @@ fn genMulDivBinOp( |
| 8933 | 9198 | switch (tag) { |
| 8934 | 9199 | .mul, .mul_wrap => { |
| 8935 | 9200 | const slow_inc = self.hasFeature(.slow_incdec); |
| 8936 | | const limb_len = std.math.divCeil(u32, src_abi_size, 8) catch unreachable; |
| 9201 | const limb_len = math.divCeil(u32, src_abi_size, 8) catch unreachable; |
| 8937 | 9202 | |
| 8938 | 9203 | try self.spillRegisters(&.{ .rax, .rcx, .rdx }); |
| 8939 | 9204 | const reg_locks = self.register_manager.lockRegs(3, .{ .rax, .rcx, .rdx }); |
| ... | ... | @@ -9117,8 +9382,8 @@ fn genMulDivBinOp( |
| 9117 | 9382 | .rem => maybe_inst, |
| 9118 | 9383 | else => null, |
| 9119 | 9384 | }; |
| 9120 | | try self.register_manager.getReg(.rax, track_inst_rax); |
| 9121 | | try self.register_manager.getReg(.rdx, track_inst_rdx); |
| 9385 | try self.register_manager.getKnownReg(.rax, track_inst_rax); |
| 9386 | try self.register_manager.getKnownReg(.rdx, track_inst_rdx); |
| 9122 | 9387 | |
| 9123 | 9388 | try self.genIntMulDivOpMir(switch (signedness) { |
| 9124 | 9389 | .signed => switch (tag) { |
| ... | ... | @@ -9158,8 +9423,11 @@ fn genMulDivBinOp( |
| 9158 | 9423 | }, |
| 9159 | 9424 | |
| 9160 | 9425 | .mod => { |
| 9161 | | try self.register_manager.getReg(.rax, null); |
| 9162 | | try self.register_manager.getReg(.rdx, if (signedness == .unsigned) maybe_inst else null); |
| 9426 | try self.register_manager.getKnownReg(.rax, null); |
| 9427 | try self.register_manager.getKnownReg( |
| 9428 | .rdx, |
| 9429 | if (signedness == .unsigned) maybe_inst else null, |
| 9430 | ); |
| 9163 | 9431 | |
| 9164 | 9432 | switch (signedness) { |
| 9165 | 9433 | .signed => { |
| ... | ... | @@ -9200,8 +9468,11 @@ fn genMulDivBinOp( |
| 9200 | 9468 | }, |
| 9201 | 9469 | |
| 9202 | 9470 | .div_floor => { |
| 9203 | | try self.register_manager.getReg(.rax, if (signedness == .unsigned) maybe_inst else null); |
| 9204 | | try self.register_manager.getReg(.rdx, null); |
| 9471 | try self.register_manager.getKnownReg( |
| 9472 | .rax, |
| 9473 | if (signedness == .unsigned) maybe_inst else null, |
| 9474 | ); |
| 9475 | try self.register_manager.getKnownReg(.rdx, null); |
| 9205 | 9476 | |
| 9206 | 9477 | const lhs_lock: ?RegisterLock = switch (lhs_mcv) { |
| 9207 | 9478 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), |
| ... | ... | @@ -9445,7 +9716,7 @@ fn genBinOp( |
| 9445 | 9716 | .rem, .mod => unreachable, |
| 9446 | 9717 | .max, .min => if (lhs_ty.scalarType(mod).isRuntimeFloat()) registerAlias( |
| 9447 | 9718 | if (!self.hasFeature(.avx) and self.hasFeature(.sse4_1)) mask: { |
| 9448 | | try self.register_manager.getReg(.xmm0, null); |
| 9719 | try self.register_manager.getKnownReg(.xmm0, null); |
| 9449 | 9720 | break :mask .xmm0; |
| 9450 | 9721 | } else try self.register_manager.allocReg(null, abi.RegisterClass.sse), |
| 9451 | 9722 | abi_size, |
| ... | ... | @@ -10820,96 +11091,35 @@ fn genBinOp( |
| 10820 | 11091 | lhs_copy_reg.?, |
| 10821 | 11092 | mask_reg, |
| 10822 | 11093 | ) else { |
| 10823 | | try self.asmRegisterRegister( |
| 10824 | | @as(?Mir.Inst.FixedTag, switch (lhs_ty.zigTypeTag(mod)) { |
| 10825 | | .Float => switch (lhs_ty.floatBits(self.target.*)) { |
| 10826 | | 32 => .{ ._ps, .@"and" }, |
| 10827 | | 64 => .{ ._pd, .@"and" }, |
| 10828 | | 16, 80, 128 => null, |
| 10829 | | else => unreachable, |
| 10830 | | }, |
| 10831 | | .Vector => switch (lhs_ty.childType(mod).zigTypeTag(mod)) { |
| 10832 | | .Float => switch (lhs_ty.childType(mod).floatBits(self.target.*)) { |
| 10833 | | 32 => switch (lhs_ty.vectorLen(mod)) { |
| 10834 | | 1...4 => .{ ._ps, .@"and" }, |
| 10835 | | else => null, |
| 10836 | | }, |
| 10837 | | 64 => switch (lhs_ty.vectorLen(mod)) { |
| 10838 | | 1...2 => .{ ._pd, .@"and" }, |
| 10839 | | else => null, |
| 10840 | | }, |
| 10841 | | 16, 80, 128 => null, |
| 10842 | | else => unreachable, |
| 10843 | | }, |
| 10844 | | else => unreachable, |
| 10845 | | }, |
| 11094 | const mir_fixes = @as(?Mir.Inst.Fixes, switch (lhs_ty.zigTypeTag(mod)) { |
| 11095 | .Float => switch (lhs_ty.floatBits(self.target.*)) { |
| 11096 | 32 => ._ps, |
| 11097 | 64 => ._pd, |
| 11098 | 16, 80, 128 => null, |
| 10846 | 11099 | else => unreachable, |
| 10847 | | }) orelse return self.fail("TODO implement genBinOp for {s} {}", .{ |
| 10848 | | @tagName(air_tag), lhs_ty.fmt(mod), |
| 10849 | | }), |
| 10850 | | dst_reg, |
| 10851 | | mask_reg, |
| 10852 | | ); |
| 10853 | | try self.asmRegisterRegister( |
| 10854 | | @as(?Mir.Inst.FixedTag, switch (lhs_ty.zigTypeTag(mod)) { |
| 10855 | | .Float => switch (lhs_ty.floatBits(self.target.*)) { |
| 10856 | | 32 => .{ ._ps, .andn }, |
| 10857 | | 64 => .{ ._pd, .andn }, |
| 10858 | | 16, 80, 128 => null, |
| 10859 | | else => unreachable, |
| 10860 | | }, |
| 10861 | | .Vector => switch (lhs_ty.childType(mod).zigTypeTag(mod)) { |
| 10862 | | .Float => switch (lhs_ty.childType(mod).floatBits(self.target.*)) { |
| 10863 | | 32 => switch (lhs_ty.vectorLen(mod)) { |
| 10864 | | 1...4 => .{ ._ps, .andn }, |
| 10865 | | else => null, |
| 10866 | | }, |
| 10867 | | 64 => switch (lhs_ty.vectorLen(mod)) { |
| 10868 | | 1...2 => .{ ._pd, .andn }, |
| 10869 | | else => null, |
| 10870 | | }, |
| 10871 | | 16, 80, 128 => null, |
| 10872 | | else => unreachable, |
| 11100 | }, |
| 11101 | .Vector => switch (lhs_ty.childType(mod).zigTypeTag(mod)) { |
| 11102 | .Float => switch (lhs_ty.childType(mod).floatBits(self.target.*)) { |
| 11103 | 32 => switch (lhs_ty.vectorLen(mod)) { |
| 11104 | 1...4 => ._ps, |
| 11105 | else => null, |
| 10873 | 11106 | }, |
| 10874 | | else => unreachable, |
| 10875 | | }, |
| 10876 | | else => unreachable, |
| 10877 | | }) orelse return self.fail("TODO implement genBinOp for {s} {}", .{ |
| 10878 | | @tagName(air_tag), lhs_ty.fmt(mod), |
| 10879 | | }), |
| 10880 | | mask_reg, |
| 10881 | | lhs_copy_reg.?, |
| 10882 | | ); |
| 10883 | | try self.asmRegisterRegister( |
| 10884 | | @as(?Mir.Inst.FixedTag, switch (lhs_ty.zigTypeTag(mod)) { |
| 10885 | | .Float => switch (lhs_ty.floatBits(self.target.*)) { |
| 10886 | | 32 => .{ ._ps, .@"or" }, |
| 10887 | | 64 => .{ ._pd, .@"or" }, |
| 10888 | | 16, 80, 128 => null, |
| 10889 | | else => unreachable, |
| 10890 | | }, |
| 10891 | | .Vector => switch (lhs_ty.childType(mod).zigTypeTag(mod)) { |
| 10892 | | .Float => switch (lhs_ty.childType(mod).floatBits(self.target.*)) { |
| 10893 | | 32 => switch (lhs_ty.vectorLen(mod)) { |
| 10894 | | 1...4 => .{ ._ps, .@"or" }, |
| 10895 | | else => null, |
| 10896 | | }, |
| 10897 | | 64 => switch (lhs_ty.vectorLen(mod)) { |
| 10898 | | 1...2 => .{ ._pd, .@"or" }, |
| 10899 | | else => null, |
| 10900 | | }, |
| 10901 | | 16, 80, 128 => null, |
| 10902 | | else => unreachable, |
| 11107 | 64 => switch (lhs_ty.vectorLen(mod)) { |
| 11108 | 1...2 => ._pd, |
| 11109 | else => null, |
| 10903 | 11110 | }, |
| 11111 | 16, 80, 128 => null, |
| 10904 | 11112 | else => unreachable, |
| 10905 | 11113 | }, |
| 10906 | 11114 | else => unreachable, |
| 10907 | | }) orelse return self.fail("TODO implement genBinOp for {s} {}", .{ |
| 10908 | | @tagName(air_tag), lhs_ty.fmt(mod), |
| 10909 | | }), |
| 10910 | | dst_reg, |
| 10911 | | mask_reg, |
| 10912 | | ); |
| 11115 | }, |
| 11116 | else => unreachable, |
| 11117 | }) orelse return self.fail("TODO implement genBinOp for {s} {}", .{ |
| 11118 | @tagName(air_tag), lhs_ty.fmt(mod), |
| 11119 | }); |
| 11120 | try self.asmRegisterRegister(.{ mir_fixes, .@"and" }, dst_reg, mask_reg); |
| 11121 | try self.asmRegisterRegister(.{ mir_fixes, .andn }, mask_reg, lhs_copy_reg.?); |
| 11122 | try self.asmRegisterRegister(.{ mir_fixes, .@"or" }, dst_reg, mask_reg); |
| 10913 | 11123 | } |
| 10914 | 11124 | }, |
| 10915 | 11125 | .cmp_lt, .cmp_lte, .cmp_eq, .cmp_gte, .cmp_gt, .cmp_neq => { |
| ... | ... | @@ -12192,48 +12402,10 @@ fn airRetLoad(self: *Self, inst: Air.Inst.Index) !void { |
| 12192 | 12402 | fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void { |
| 12193 | 12403 | const mod = self.bin_file.comp.module.?; |
| 12194 | 12404 | const bin_op = self.air.instructions.items(.data)[@intFromEnum(inst)].bin_op; |
| 12195 | | const ty = self.typeOf(bin_op.lhs); |
| 12405 | var ty = self.typeOf(bin_op.lhs); |
| 12406 | var null_compare: ?Mir.Inst.Index = null; |
| 12196 | 12407 | |
| 12197 | 12408 | const result: Condition = result: { |
| 12198 | | switch (ty.zigTypeTag(mod)) { |
| 12199 | | .Float => { |
| 12200 | | const float_bits = ty.floatBits(self.target.*); |
| 12201 | | if (switch (float_bits) { |
| 12202 | | 16 => !self.hasFeature(.f16c), |
| 12203 | | 32, 64 => false, |
| 12204 | | 80, 128 => true, |
| 12205 | | else => unreachable, |
| 12206 | | }) { |
| 12207 | | var callee_buf: ["__???f2".len]u8 = undefined; |
| 12208 | | const ret = try self.genCall(.{ .lib = .{ |
| 12209 | | .return_type = .i32_type, |
| 12210 | | .param_types = &.{ ty.toIntern(), ty.toIntern() }, |
| 12211 | | .callee = std.fmt.bufPrint(&callee_buf, "__{s}{c}f2", .{ |
| 12212 | | switch (op) { |
| 12213 | | .eq => "eq", |
| 12214 | | .neq => "ne", |
| 12215 | | .lt => "lt", |
| 12216 | | .lte => "le", |
| 12217 | | .gt => "gt", |
| 12218 | | .gte => "ge", |
| 12219 | | }, |
| 12220 | | floatCompilerRtAbiName(float_bits), |
| 12221 | | }) catch unreachable, |
| 12222 | | } }, &.{ ty, ty }, &.{ .{ .air_ref = bin_op.lhs }, .{ .air_ref = bin_op.rhs } }); |
| 12223 | | try self.genBinOpMir(.{ ._, .@"test" }, Type.i32, ret, ret); |
| 12224 | | break :result switch (op) { |
| 12225 | | .eq => .e, |
| 12226 | | .neq => .ne, |
| 12227 | | .lt => .l, |
| 12228 | | .lte => .le, |
| 12229 | | .gt => .g, |
| 12230 | | .gte => .ge, |
| 12231 | | }; |
| 12232 | | } |
| 12233 | | }, |
| 12234 | | else => {}, |
| 12235 | | } |
| 12236 | | |
| 12237 | 12409 | try self.spillEflagsIfOccupied(); |
| 12238 | 12410 | |
| 12239 | 12411 | const lhs_mcv = try self.resolveInst(bin_op.lhs); |
| ... | ... | @@ -12260,6 +12432,103 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void { |
| 12260 | 12432 | }; |
| 12261 | 12433 | defer for (rhs_locks) |rhs_lock| if (rhs_lock) |lock| self.register_manager.unlockReg(lock); |
| 12262 | 12434 | |
| 12435 | switch (ty.zigTypeTag(mod)) { |
| 12436 | .Float => { |
| 12437 | const float_bits = ty.floatBits(self.target.*); |
| 12438 | if (switch (float_bits) { |
| 12439 | 16 => !self.hasFeature(.f16c), |
| 12440 | 32, 64 => false, |
| 12441 | 80, 128 => true, |
| 12442 | else => unreachable, |
| 12443 | }) { |
| 12444 | var callee_buf: ["__???f2".len]u8 = undefined; |
| 12445 | const ret = try self.genCall(.{ .lib = .{ |
| 12446 | .return_type = .i32_type, |
| 12447 | .param_types = &.{ ty.toIntern(), ty.toIntern() }, |
| 12448 | .callee = std.fmt.bufPrint(&callee_buf, "__{s}{c}f2", .{ |
| 12449 | switch (op) { |
| 12450 | .eq => "eq", |
| 12451 | .neq => "ne", |
| 12452 | .lt => "lt", |
| 12453 | .lte => "le", |
| 12454 | .gt => "gt", |
| 12455 | .gte => "ge", |
| 12456 | }, |
| 12457 | floatCompilerRtAbiName(float_bits), |
| 12458 | }) catch unreachable, |
| 12459 | } }, &.{ ty, ty }, &.{ .{ .air_ref = bin_op.lhs }, .{ .air_ref = bin_op.rhs } }); |
| 12460 | try self.genBinOpMir(.{ ._, .@"test" }, Type.i32, ret, ret); |
| 12461 | break :result switch (op) { |
| 12462 | .eq => .e, |
| 12463 | .neq => .ne, |
| 12464 | .lt => .l, |
| 12465 | .lte => .le, |
| 12466 | .gt => .g, |
| 12467 | .gte => .ge, |
| 12468 | }; |
| 12469 | } |
| 12470 | }, |
| 12471 | .Optional => if (!ty.optionalReprIsPayload(mod)) { |
| 12472 | const opt_ty = ty; |
| 12473 | const opt_abi_size: u31 = @intCast(opt_ty.abiSize(mod)); |
| 12474 | ty = opt_ty.optionalChild(mod); |
| 12475 | const payload_abi_size: u31 = @intCast(ty.abiSize(mod)); |
| 12476 | |
| 12477 | const temp_lhs_reg = try self.register_manager.allocReg(null, abi.RegisterClass.gp); |
| 12478 | const temp_lhs_lock = self.register_manager.lockRegAssumeUnused(temp_lhs_reg); |
| 12479 | defer self.register_manager.unlockReg(temp_lhs_lock); |
| 12480 | |
| 12481 | if (lhs_mcv.isMemory()) try self.asmRegisterMemory( |
| 12482 | .{ ._, .mov }, |
| 12483 | temp_lhs_reg.to8(), |
| 12484 | try lhs_mcv.address().offset(payload_abi_size).deref().mem(self, .byte), |
| 12485 | ) else { |
| 12486 | try self.genSetReg(temp_lhs_reg, opt_ty, lhs_mcv, .{}); |
| 12487 | try self.asmRegisterImmediate( |
| 12488 | .{ ._r, .sh }, |
| 12489 | registerAlias(temp_lhs_reg, opt_abi_size), |
| 12490 | Immediate.u(payload_abi_size * 8), |
| 12491 | ); |
| 12492 | } |
| 12493 | |
| 12494 | const payload_compare = payload_compare: { |
| 12495 | if (rhs_mcv.isMemory()) { |
| 12496 | const rhs_mem = |
| 12497 | try rhs_mcv.address().offset(payload_abi_size).deref().mem(self, .byte); |
| 12498 | try self.asmMemoryRegister(.{ ._, .@"test" }, rhs_mem, temp_lhs_reg.to8()); |
| 12499 | const payload_compare = try self.asmJccReloc(.nz, undefined); |
| 12500 | try self.asmRegisterMemory(.{ ._, .cmp }, temp_lhs_reg.to8(), rhs_mem); |
| 12501 | break :payload_compare payload_compare; |
| 12502 | } |
| 12503 | |
| 12504 | const temp_rhs_reg = try self.copyToTmpRegister(opt_ty, rhs_mcv); |
| 12505 | const temp_rhs_lock = self.register_manager.lockRegAssumeUnused(temp_rhs_reg); |
| 12506 | defer self.register_manager.unlockReg(temp_rhs_lock); |
| 12507 | |
| 12508 | try self.asmRegisterImmediate( |
| 12509 | .{ ._r, .sh }, |
| 12510 | registerAlias(temp_rhs_reg, opt_abi_size), |
| 12511 | Immediate.u(payload_abi_size * 8), |
| 12512 | ); |
| 12513 | try self.asmRegisterRegister( |
| 12514 | .{ ._, .@"test" }, |
| 12515 | temp_lhs_reg.to8(), |
| 12516 | temp_rhs_reg.to8(), |
| 12517 | ); |
| 12518 | const payload_compare = try self.asmJccReloc(.nz, undefined); |
| 12519 | try self.asmRegisterRegister( |
| 12520 | .{ ._, .cmp }, |
| 12521 | temp_lhs_reg.to8(), |
| 12522 | temp_rhs_reg.to8(), |
| 12523 | ); |
| 12524 | break :payload_compare payload_compare; |
| 12525 | }; |
| 12526 | null_compare = try self.asmJmpReloc(undefined); |
| 12527 | self.performReloc(payload_compare); |
| 12528 | }, |
| 12529 | else => {}, |
| 12530 | } |
| 12531 | |
| 12263 | 12532 | switch (ty.zigTypeTag(mod)) { |
| 12264 | 12533 | else => { |
| 12265 | 12534 | const abi_size: u16 = @intCast(ty.abiSize(mod)); |
| ... | ... | @@ -12571,6 +12840,7 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void { |
| 12571 | 12840 | } |
| 12572 | 12841 | }; |
| 12573 | 12842 | |
| 12843 | if (null_compare) |reloc| self.performReloc(reloc); |
| 12574 | 12844 | self.eflags_inst = inst; |
| 12575 | 12845 | return self.finishAir(inst, .{ .eflags = result }, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 12576 | 12846 | } |
| ... | ... | @@ -13521,6 +13791,7 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void { |
| 13521 | 13791 | } else if (constraint.len == 1 and std.ascii.isDigit(constraint[0])) arg: { |
| 13522 | 13792 | const index = std.fmt.charToDigit(constraint[0], 10) catch unreachable; |
| 13523 | 13793 | if (index >= args.items.len) return self.fail("constraint out of bounds: '{s}'", .{constraint}); |
| 13794 | try self.genCopy(ty, args.items[index], input_mcv, .{}); |
| 13524 | 13795 | break :arg args.items[index]; |
| 13525 | 13796 | } else return self.fail("invalid constraint: '{s}'", .{constraint}); |
| 13526 | 13797 | if (arg_mcv.getReg()) |reg| if (RegisterManager.indexOfRegIntoTracked(reg)) |_| { |
| ... | ... | @@ -13619,25 +13890,26 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void { |
| 13619 | 13890 | label_gop.value_ptr.target = @intCast(self.mir_instructions.len); |
| 13620 | 13891 | } else continue; |
| 13621 | 13892 | |
| 13622 | | var mnem_size: ?Memory.Size = null; |
| 13623 | | const mnem_tag = mnem: { |
| 13624 | | mnem_size = if (mem.endsWith(u8, mnem_str, "b")) |
| 13625 | | .byte |
| 13626 | | else if (mem.endsWith(u8, mnem_str, "w")) |
| 13627 | | .word |
| 13628 | | else if (mem.endsWith(u8, mnem_str, "l")) |
| 13629 | | .dword |
| 13630 | | else if (mem.endsWith(u8, mnem_str, "q")) |
| 13631 | | .qword |
| 13632 | | else if (mem.endsWith(u8, mnem_str, "t")) |
| 13633 | | .tbyte |
| 13634 | | else |
| 13635 | | break :mnem null; |
| 13636 | | break :mnem std.meta.stringToEnum(Instruction.Mnemonic, mnem_str[0 .. mnem_str.len - 1]); |
| 13637 | | } orelse mnem: { |
| 13893 | var mnem_size: ?Memory.Size = if (mem.endsWith(u8, mnem_str, "b")) |
| 13894 | .byte |
| 13895 | else if (mem.endsWith(u8, mnem_str, "w")) |
| 13896 | .word |
| 13897 | else if (mem.endsWith(u8, mnem_str, "l")) |
| 13898 | .dword |
| 13899 | else if (mem.endsWith(u8, mnem_str, "q") and |
| 13900 | (std.mem.indexOfScalar(u8, "vp", mnem_str[0]) == null or !mem.endsWith(u8, mnem_str, "dq"))) |
| 13901 | .qword |
| 13902 | else if (mem.endsWith(u8, mnem_str, "t")) |
| 13903 | .tbyte |
| 13904 | else |
| 13905 | null; |
| 13906 | const mnem_tag = while (true) break std.meta.stringToEnum( |
| 13907 | Instruction.Mnemonic, |
| 13908 | mnem_str[0 .. mnem_str.len - @intFromBool(mnem_size != null)], |
| 13909 | ) orelse if (mnem_size) |_| { |
| 13638 | 13910 | mnem_size = null; |
| 13639 | | break :mnem std.meta.stringToEnum(Instruction.Mnemonic, mnem_str); |
| 13640 | | } orelse return self.fail("invalid mnemonic: '{s}'", .{mnem_str}); |
| 13911 | continue; |
| 13912 | } else return self.fail("invalid mnemonic: '{s}'", .{mnem_str}); |
| 13641 | 13913 | if (@as(?Memory.Size, switch (mnem_tag) { |
| 13642 | 13914 | .clflush => .byte, |
| 13643 | 13915 | .fldenv, .fnstenv, .fstenv => .none, |
| ... | ... | @@ -14135,30 +14407,8 @@ fn moveStrategy(self: *Self, ty: Type, class: Register.Class, aligned: bool) !Mo |
| 14135 | 14407 | else => {}, |
| 14136 | 14408 | }, |
| 14137 | 14409 | .Int => switch (ty.childType(mod).intInfo(mod).bits) { |
| 14138 | | 8 => switch (ty.vectorLen(mod)) { |
| 14139 | | 1 => if (self.hasFeature(.avx)) return .{ .vex_insert_extract = .{ |
| 14140 | | .insert = .{ .vp_b, .insr }, |
| 14141 | | .extract = .{ .vp_b, .extr }, |
| 14142 | | } } else if (self.hasFeature(.sse4_2)) return .{ .insert_extract = .{ |
| 14143 | | .insert = .{ .p_b, .insr }, |
| 14144 | | .extract = .{ .p_b, .extr }, |
| 14145 | | } }, |
| 14146 | | 2 => return if (self.hasFeature(.avx)) .{ .vex_insert_extract = .{ |
| 14147 | | .insert = .{ .vp_w, .insr }, |
| 14148 | | .extract = .{ .vp_w, .extr }, |
| 14149 | | } } else .{ .insert_extract = .{ |
| 14150 | | .insert = .{ .p_w, .insr }, |
| 14151 | | .extract = .{ .p_w, .extr }, |
| 14152 | | } }, |
| 14153 | | 3...4 => return .{ .move = if (self.hasFeature(.avx)) |
| 14154 | | .{ .v_d, .mov } |
| 14155 | | else |
| 14156 | | .{ ._d, .mov } }, |
| 14157 | | 5...8 => return .{ .move = if (self.hasFeature(.avx)) |
| 14158 | | .{ .v_q, .mov } |
| 14159 | | else |
| 14160 | | .{ ._q, .mov } }, |
| 14161 | | 9...16 => return .{ .move = if (self.hasFeature(.avx)) |
| 14410 | 1...8 => switch (ty.vectorLen(mod)) { |
| 14411 | 1...16 => return .{ .move = if (self.hasFeature(.avx)) |
| 14162 | 14412 | if (aligned) .{ .v_, .movdqa } else .{ .v_, .movdqu } |
| 14163 | 14413 | else if (aligned) .{ ._, .movdqa } else .{ ._, .movdqu } }, |
| 14164 | 14414 | 17...32 => if (self.hasFeature(.avx)) |
| ... | ... | @@ -14168,23 +14418,8 @@ fn moveStrategy(self: *Self, ty: Type, class: Register.Class, aligned: bool) !Mo |
| 14168 | 14418 | .{ .v_, .movdqu } }, |
| 14169 | 14419 | else => {}, |
| 14170 | 14420 | }, |
| 14171 | | 16 => switch (ty.vectorLen(mod)) { |
| 14172 | | 1 => return if (self.hasFeature(.avx)) .{ .vex_insert_extract = .{ |
| 14173 | | .insert = .{ .vp_w, .insr }, |
| 14174 | | .extract = .{ .vp_w, .extr }, |
| 14175 | | } } else .{ .insert_extract = .{ |
| 14176 | | .insert = .{ .p_w, .insr }, |
| 14177 | | .extract = .{ .p_w, .extr }, |
| 14178 | | } }, |
| 14179 | | 2 => return .{ .move = if (self.hasFeature(.avx)) |
| 14180 | | .{ .v_d, .mov } |
| 14181 | | else |
| 14182 | | .{ ._d, .mov } }, |
| 14183 | | 3...4 => return .{ .move = if (self.hasFeature(.avx)) |
| 14184 | | .{ .v_q, .mov } |
| 14185 | | else |
| 14186 | | .{ ._q, .mov } }, |
| 14187 | | 5...8 => return .{ .move = if (self.hasFeature(.avx)) |
| 14421 | 9...16 => switch (ty.vectorLen(mod)) { |
| 14422 | 1...8 => return .{ .move = if (self.hasFeature(.avx)) |
| 14188 | 14423 | if (aligned) .{ .v_, .movdqa } else .{ .v_, .movdqu } |
| 14189 | 14424 | else if (aligned) .{ ._, .movdqa } else .{ ._, .movdqu } }, |
| 14190 | 14425 | 9...16 => if (self.hasFeature(.avx)) |
| ... | ... | @@ -14194,16 +14429,8 @@ fn moveStrategy(self: *Self, ty: Type, class: Register.Class, aligned: bool) !Mo |
| 14194 | 14429 | .{ .v_, .movdqu } }, |
| 14195 | 14430 | else => {}, |
| 14196 | 14431 | }, |
| 14197 | | 32 => switch (ty.vectorLen(mod)) { |
| 14198 | | 1 => return .{ .move = if (self.hasFeature(.avx)) |
| 14199 | | .{ .v_d, .mov } |
| 14200 | | else |
| 14201 | | .{ ._d, .mov } }, |
| 14202 | | 2 => return .{ .move = if (self.hasFeature(.avx)) |
| 14203 | | .{ .v_q, .mov } |
| 14204 | | else |
| 14205 | | .{ ._q, .mov } }, |
| 14206 | | 3...4 => return .{ .move = if (self.hasFeature(.avx)) |
| 14432 | 17...32 => switch (ty.vectorLen(mod)) { |
| 14433 | 1...4 => return .{ .move = if (self.hasFeature(.avx)) |
| 14207 | 14434 | if (aligned) .{ .v_, .movdqa } else .{ .v_, .movdqu } |
| 14208 | 14435 | else if (aligned) .{ ._, .movdqa } else .{ ._, .movdqu } }, |
| 14209 | 14436 | 5...8 => if (self.hasFeature(.avx)) |
| ... | ... | @@ -14213,12 +14440,8 @@ fn moveStrategy(self: *Self, ty: Type, class: Register.Class, aligned: bool) !Mo |
| 14213 | 14440 | .{ .v_, .movdqu } }, |
| 14214 | 14441 | else => {}, |
| 14215 | 14442 | }, |
| 14216 | | 64 => switch (ty.vectorLen(mod)) { |
| 14217 | | 1 => return .{ .move = if (self.hasFeature(.avx)) |
| 14218 | | .{ .v_q, .mov } |
| 14219 | | else |
| 14220 | | .{ ._q, .mov } }, |
| 14221 | | 2 => return .{ .move = if (self.hasFeature(.avx)) |
| 14443 | 33...64 => switch (ty.vectorLen(mod)) { |
| 14444 | 1...2 => return .{ .move = if (self.hasFeature(.avx)) |
| 14222 | 14445 | if (aligned) .{ .v_, .movdqa } else .{ .v_, .movdqu } |
| 14223 | 14446 | else if (aligned) .{ ._, .movdqa } else .{ ._, .movdqu } }, |
| 14224 | 14447 | 3...4 => if (self.hasFeature(.avx)) |
| ... | ... | @@ -14228,7 +14451,7 @@ fn moveStrategy(self: *Self, ty: Type, class: Register.Class, aligned: bool) !Mo |
| 14228 | 14451 | .{ .v_, .movdqu } }, |
| 14229 | 14452 | else => {}, |
| 14230 | 14453 | }, |
| 14231 | | 128 => switch (ty.vectorLen(mod)) { |
| 14454 | 65...128 => switch (ty.vectorLen(mod)) { |
| 14232 | 14455 | 1 => return .{ .move = if (self.hasFeature(.avx)) |
| 14233 | 14456 | if (aligned) .{ .v_, .movdqa } else .{ .v_, .movdqu } |
| 14234 | 14457 | else if (aligned) .{ ._, .movdqa } else .{ ._, .movdqu } }, |
| ... | ... | @@ -14239,7 +14462,7 @@ fn moveStrategy(self: *Self, ty: Type, class: Register.Class, aligned: bool) !Mo |
| 14239 | 14462 | .{ .v_, .movdqu } }, |
| 14240 | 14463 | else => {}, |
| 14241 | 14464 | }, |
| 14242 | | 256 => switch (ty.vectorLen(mod)) { |
| 14465 | 129...256 => switch (ty.vectorLen(mod)) { |
| 14243 | 14466 | 1 => if (self.hasFeature(.avx)) |
| 14244 | 14467 | return .{ .move = if (aligned) |
| 14245 | 14468 | .{ .v_, .movdqa } |
| ... | ... | @@ -14251,11 +14474,7 @@ fn moveStrategy(self: *Self, ty: Type, class: Register.Class, aligned: bool) !Mo |
| 14251 | 14474 | }, |
| 14252 | 14475 | .Pointer, .Optional => if (ty.childType(mod).isPtrAtRuntime(mod)) |
| 14253 | 14476 | switch (ty.vectorLen(mod)) { |
| 14254 | | 1 => return .{ .move = if (self.hasFeature(.avx)) |
| 14255 | | .{ .v_q, .mov } |
| 14256 | | else |
| 14257 | | .{ ._q, .mov } }, |
| 14258 | | 2 => return .{ .move = if (self.hasFeature(.avx)) |
| 14477 | 1...2 => return .{ .move = if (self.hasFeature(.avx)) |
| 14259 | 14478 | if (aligned) .{ .v_, .movdqa } else .{ .v_, .movdqu } |
| 14260 | 14479 | else if (aligned) .{ ._, .movdqa } else .{ ._, .movdqu } }, |
| 14261 | 14480 | 3...4 => if (self.hasFeature(.avx)) |
| ... | ... | @@ -14269,22 +14488,7 @@ fn moveStrategy(self: *Self, ty: Type, class: Register.Class, aligned: bool) !Mo |
| 14269 | 14488 | unreachable, |
| 14270 | 14489 | .Float => switch (ty.childType(mod).floatBits(self.target.*)) { |
| 14271 | 14490 | 16 => switch (ty.vectorLen(mod)) { |
| 14272 | | 1 => return if (self.hasFeature(.avx)) .{ .vex_insert_extract = .{ |
| 14273 | | .insert = .{ .vp_w, .insr }, |
| 14274 | | .extract = .{ .vp_w, .extr }, |
| 14275 | | } } else .{ .insert_extract = .{ |
| 14276 | | .insert = .{ .p_w, .insr }, |
| 14277 | | .extract = .{ .p_w, .extr }, |
| 14278 | | } }, |
| 14279 | | 2 => return .{ .move = if (self.hasFeature(.avx)) |
| 14280 | | .{ .v_d, .mov } |
| 14281 | | else |
| 14282 | | .{ ._d, .mov } }, |
| 14283 | | 3...4 => return .{ .move = if (self.hasFeature(.avx)) |
| 14284 | | .{ .v_q, .mov } |
| 14285 | | else |
| 14286 | | .{ ._q, .mov } }, |
| 14287 | | 5...8 => return .{ .move = if (self.hasFeature(.avx)) |
| 14491 | 1...8 => return .{ .move = if (self.hasFeature(.avx)) |
| 14288 | 14492 | if (aligned) .{ .v_, .movdqa } else .{ .v_, .movdqu } |
| 14289 | 14493 | else if (aligned) .{ ._, .movdqa } else .{ ._, .movdqu } }, |
| 14290 | 14494 | 9...16 => if (self.hasFeature(.avx)) |
| ... | ... | @@ -14295,15 +14499,7 @@ fn moveStrategy(self: *Self, ty: Type, class: Register.Class, aligned: bool) !Mo |
| 14295 | 14499 | else => {}, |
| 14296 | 14500 | }, |
| 14297 | 14501 | 32 => switch (ty.vectorLen(mod)) { |
| 14298 | | 1 => return .{ .move = if (self.hasFeature(.avx)) |
| 14299 | | .{ .v_ss, .mov } |
| 14300 | | else |
| 14301 | | .{ ._ss, .mov } }, |
| 14302 | | 2 => return .{ .move = if (self.hasFeature(.avx)) |
| 14303 | | .{ .v_sd, .mov } |
| 14304 | | else |
| 14305 | | .{ ._sd, .mov } }, |
| 14306 | | 3...4 => return .{ .move = if (self.hasFeature(.avx)) |
| 14502 | 1...4 => return .{ .move = if (self.hasFeature(.avx)) |
| 14307 | 14503 | if (aligned) .{ .v_ps, .mova } else .{ .v_ps, .movu } |
| 14308 | 14504 | else if (aligned) .{ ._ps, .mova } else .{ ._ps, .movu } }, |
| 14309 | 14505 | 5...8 => if (self.hasFeature(.avx)) |
| ... | ... | @@ -14314,11 +14510,7 @@ fn moveStrategy(self: *Self, ty: Type, class: Register.Class, aligned: bool) !Mo |
| 14314 | 14510 | else => {}, |
| 14315 | 14511 | }, |
| 14316 | 14512 | 64 => switch (ty.vectorLen(mod)) { |
| 14317 | | 1 => return .{ .move = if (self.hasFeature(.avx)) |
| 14318 | | .{ .v_sd, .mov } |
| 14319 | | else |
| 14320 | | .{ ._sd, .mov } }, |
| 14321 | | 2 => return .{ .move = if (self.hasFeature(.avx)) |
| 14513 | 1...2 => return .{ .move = if (self.hasFeature(.avx)) |
| 14322 | 14514 | if (aligned) .{ .v_pd, .mova } else .{ .v_pd, .movu } |
| 14323 | 14515 | else if (aligned) .{ ._pd, .mova } else .{ ._pd, .movu } }, |
| 14324 | 14516 | 3...4 => if (self.hasFeature(.avx)) |
| ... | ... | @@ -14633,7 +14825,7 @@ fn genSetReg( |
| 14633 | 14825 | ty, |
| 14634 | 14826 | dst_reg.class(), |
| 14635 | 14827 | self.getFrameAddrAlignment(frame_addr).compare(.gte, Alignment.fromLog2Units( |
| 14636 | | std.math.log2_int_ceil(u10, @divExact(dst_reg.bitSize(), 8)), |
| 14828 | math.log2_int_ceil(u10, @divExact(dst_reg.bitSize(), 8)), |
| 14637 | 14829 | )), |
| 14638 | 14830 | ), |
| 14639 | 14831 | .lea_frame => .{ .move = .{ ._, .lea } }, |
| ... | ... | @@ -16296,7 +16488,7 @@ fn airSplat(self: *Self, inst: Air.Inst.Index) !void { |
| 16296 | 16488 | }, |
| 16297 | 16489 | 65...128 => switch (vector_len) { |
| 16298 | 16490 | else => null, |
| 16299 | | 1...2 => .{ .vp_i128, .broadcast }, |
| 16491 | 1...2 => .{ .v_i128, .broadcast }, |
| 16300 | 16492 | }, |
| 16301 | 16493 | }) orelse break :avx2; |
| 16302 | 16494 | |
| ... | ... | @@ -16310,7 +16502,7 @@ fn airSplat(self: *Self, inst: Air.Inst.Index) !void { |
| 16310 | 16502 | registerAlias(dst_reg, @intCast(vector_ty.abiSize(mod))), |
| 16311 | 16503 | try src_mcv.mem(self, self.memSize(scalar_ty)), |
| 16312 | 16504 | ) else { |
| 16313 | | if (mir_tag[0] == .vp_i128) break :avx2; |
| 16505 | if (mir_tag[0] == .v_i128) break :avx2; |
| 16314 | 16506 | try self.genSetReg(dst_reg, scalar_ty, src_mcv, .{}); |
| 16315 | 16507 | try self.asmRegisterRegister( |
| 16316 | 16508 | mir_tag, |
| ... | ... | @@ -16352,7 +16544,7 @@ fn airSplat(self: *Self, inst: Air.Inst.Index) !void { |
| 16352 | 16544 | .{ if (self.hasFeature(.avx)) .vp_w else .p_w, .shufl }, |
| 16353 | 16545 | dst_alias, |
| 16354 | 16546 | dst_alias, |
| 16355 | | Immediate.u(0), |
| 16547 | Immediate.u(0b00_00_00_00), |
| 16356 | 16548 | ); |
| 16357 | 16549 | if (switch (scalar_bits) { |
| 16358 | 16550 | 1...8 => vector_len > 4, |
| ... | ... | @@ -16563,18 +16755,1158 @@ fn airSplat(self: *Self, inst: Air.Inst.Index) !void { |
| 16563 | 16755 | } |
| 16564 | 16756 | |
| 16565 | 16757 | fn airSelect(self: *Self, inst: Air.Inst.Index) !void { |
| 16758 | const mod = self.bin_file.comp.module.?; |
| 16566 | 16759 | const pl_op = self.air.instructions.items(.data)[@intFromEnum(inst)].pl_op; |
| 16567 | 16760 | const extra = self.air.extraData(Air.Bin, pl_op.payload).data; |
| 16568 | | _ = extra; |
| 16569 | | return self.fail("TODO implement airSelect for x86_64", .{}); |
| 16570 | | //return self.finishAir(inst, result, .{ pl_op.operand, extra.lhs, extra.rhs }); |
| 16761 | const ty = self.typeOfIndex(inst); |
| 16762 | const vec_len = ty.vectorLen(mod); |
| 16763 | const elem_ty = ty.childType(mod); |
| 16764 | const elem_abi_size: u32 = @intCast(elem_ty.abiSize(mod)); |
| 16765 | const abi_size: u32 = @intCast(ty.abiSize(mod)); |
| 16766 | const pred_ty = self.typeOf(pl_op.operand); |
| 16767 | |
| 16768 | const result = result: { |
| 16769 | const has_blend = self.hasFeature(.sse4_1); |
| 16770 | const has_avx = self.hasFeature(.avx); |
| 16771 | const need_xmm0 = has_blend and !has_avx; |
| 16772 | const pred_mcv = try self.resolveInst(pl_op.operand); |
| 16773 | const mask_reg = mask: { |
| 16774 | switch (pred_mcv) { |
| 16775 | .register => |pred_reg| switch (pred_reg.class()) { |
| 16776 | .general_purpose => {}, |
| 16777 | .sse => if (need_xmm0 and pred_reg.id() != comptime Register.xmm0.id()) { |
| 16778 | try self.register_manager.getKnownReg(.xmm0, null); |
| 16779 | try self.genSetReg(.xmm0, pred_ty, pred_mcv, .{}); |
| 16780 | break :mask .xmm0; |
| 16781 | } else break :mask if (has_blend) |
| 16782 | pred_reg |
| 16783 | else |
| 16784 | try self.copyToTmpRegister(pred_ty, pred_mcv), |
| 16785 | else => unreachable, |
| 16786 | }, |
| 16787 | else => {}, |
| 16788 | } |
| 16789 | const mask_reg: Register = if (need_xmm0) mask_reg: { |
| 16790 | try self.register_manager.getKnownReg(.xmm0, null); |
| 16791 | break :mask_reg .xmm0; |
| 16792 | } else try self.register_manager.allocReg(null, abi.RegisterClass.sse); |
| 16793 | const mask_alias = registerAlias(mask_reg, abi_size); |
| 16794 | const mask_lock = self.register_manager.lockRegAssumeUnused(mask_reg); |
| 16795 | defer self.register_manager.unlockReg(mask_lock); |
| 16796 | |
| 16797 | const pred_fits_in_elem = vec_len <= elem_abi_size; |
| 16798 | if (self.hasFeature(.avx2) and abi_size <= 32) { |
| 16799 | if (pred_mcv.isRegister()) broadcast: { |
| 16800 | try self.asmRegisterRegister( |
| 16801 | .{ .v_d, .mov }, |
| 16802 | mask_reg.to128(), |
| 16803 | pred_mcv.getReg().?.to32(), |
| 16804 | ); |
| 16805 | if (pred_fits_in_elem and vec_len > 1) try self.asmRegisterRegister( |
| 16806 | .{ switch (elem_abi_size) { |
| 16807 | 1 => .vp_b, |
| 16808 | 2 => .vp_w, |
| 16809 | 3...4 => .vp_d, |
| 16810 | 5...8 => .vp_q, |
| 16811 | 9...16 => { |
| 16812 | try self.asmRegisterRegisterRegisterImmediate( |
| 16813 | .{ .v_f128, .insert }, |
| 16814 | mask_alias, |
| 16815 | mask_alias, |
| 16816 | mask_reg.to128(), |
| 16817 | Immediate.u(1), |
| 16818 | ); |
| 16819 | break :broadcast; |
| 16820 | }, |
| 16821 | 17...32 => break :broadcast, |
| 16822 | else => unreachable, |
| 16823 | }, .broadcast }, |
| 16824 | mask_alias, |
| 16825 | mask_reg.to128(), |
| 16826 | ); |
| 16827 | } else try self.asmRegisterMemory( |
| 16828 | .{ switch (vec_len) { |
| 16829 | 1...8 => .vp_b, |
| 16830 | 9...16 => .vp_w, |
| 16831 | 17...32 => .vp_d, |
| 16832 | else => unreachable, |
| 16833 | }, .broadcast }, |
| 16834 | mask_alias, |
| 16835 | if (pred_mcv.isMemory()) try pred_mcv.mem(self, .byte) else .{ |
| 16836 | .base = .{ .reg = (try self.copyToTmpRegister( |
| 16837 | Type.usize, |
| 16838 | pred_mcv.address(), |
| 16839 | )).to64() }, |
| 16840 | .mod = .{ .rm = .{ .size = .byte } }, |
| 16841 | }, |
| 16842 | ); |
| 16843 | } else if (abi_size <= 16) broadcast: { |
| 16844 | try self.asmRegisterRegister( |
| 16845 | .{ if (has_avx) .v_d else ._d, .mov }, |
| 16846 | mask_alias, |
| 16847 | (if (pred_mcv.isRegister()) |
| 16848 | pred_mcv.getReg().? |
| 16849 | else |
| 16850 | try self.copyToTmpRegister(pred_ty, pred_mcv.address())).to32(), |
| 16851 | ); |
| 16852 | if (!pred_fits_in_elem or vec_len == 1) break :broadcast; |
| 16853 | if (elem_abi_size <= 1) { |
| 16854 | if (has_avx) try self.asmRegisterRegisterRegister( |
| 16855 | .{ .vp_, .unpcklbw }, |
| 16856 | mask_alias, |
| 16857 | mask_alias, |
| 16858 | mask_alias, |
| 16859 | ) else try self.asmRegisterRegister( |
| 16860 | .{ .p_, .unpcklbw }, |
| 16861 | mask_alias, |
| 16862 | mask_alias, |
| 16863 | ); |
| 16864 | if (abi_size <= 2) break :broadcast; |
| 16865 | } |
| 16866 | if (elem_abi_size <= 2) { |
| 16867 | try self.asmRegisterRegisterImmediate( |
| 16868 | .{ if (has_avx) .vp_w else .p_w, .shufl }, |
| 16869 | mask_alias, |
| 16870 | mask_alias, |
| 16871 | Immediate.u(0b00_00_00_00), |
| 16872 | ); |
| 16873 | if (abi_size <= 8) break :broadcast; |
| 16874 | } |
| 16875 | try self.asmRegisterRegisterImmediate( |
| 16876 | .{ if (has_avx) .vp_d else .p_d, .shuf }, |
| 16877 | mask_alias, |
| 16878 | mask_alias, |
| 16879 | Immediate.u(switch (elem_abi_size) { |
| 16880 | 1...2, 5...8 => 0b01_00_01_00, |
| 16881 | 3...4 => 0b00_00_00_00, |
| 16882 | else => unreachable, |
| 16883 | }), |
| 16884 | ); |
| 16885 | } else return self.fail("TODO implement airSelect for {}", .{ty.fmt(mod)}); |
| 16886 | const elem_bits: u16 = @intCast(elem_abi_size * 8); |
| 16887 | const mask_elem_ty = try mod.intType(.unsigned, elem_bits); |
| 16888 | const mask_ty = try mod.vectorType(.{ .len = vec_len, .child = mask_elem_ty.toIntern() }); |
| 16889 | if (!pred_fits_in_elem) if (self.hasFeature(.ssse3)) { |
| 16890 | var mask_elems: [32]InternPool.Index = undefined; |
| 16891 | for (mask_elems[0..vec_len], 0..) |*elem, bit| elem.* = try mod.intern(.{ .int = .{ |
| 16892 | .ty = mask_elem_ty.toIntern(), |
| 16893 | .storage = .{ .u64 = bit / elem_bits }, |
| 16894 | } }); |
| 16895 | const mask_mcv = try self.genTypedValue(.{ |
| 16896 | .ty = mask_ty, |
| 16897 | .val = Value.fromInterned(try mod.intern(.{ .aggregate = .{ |
| 16898 | .ty = mask_ty.toIntern(), |
| 16899 | .storage = .{ .elems = mask_elems[0..vec_len] }, |
| 16900 | } })), |
| 16901 | }); |
| 16902 | const mask_mem: Memory = .{ |
| 16903 | .base = .{ .reg = try self.copyToTmpRegister(Type.usize, mask_mcv.address()) }, |
| 16904 | .mod = .{ .rm = .{ .size = self.memSize(ty) } }, |
| 16905 | }; |
| 16906 | if (has_avx) try self.asmRegisterRegisterMemory( |
| 16907 | .{ .vp_b, .shuf }, |
| 16908 | mask_alias, |
| 16909 | mask_alias, |
| 16910 | mask_mem, |
| 16911 | ) else try self.asmRegisterMemory( |
| 16912 | .{ .p_b, .shuf }, |
| 16913 | mask_alias, |
| 16914 | mask_mem, |
| 16915 | ); |
| 16916 | } else return self.fail("TODO implement airSelect for {}", .{ty.fmt(mod)}); |
| 16917 | { |
| 16918 | var mask_elems: [32]InternPool.Index = undefined; |
| 16919 | for (mask_elems[0..vec_len], 0..) |*elem, bit| elem.* = try mod.intern(.{ .int = .{ |
| 16920 | .ty = mask_elem_ty.toIntern(), |
| 16921 | .storage = .{ .u64 = @as(u32, 1) << @intCast(bit & (elem_bits - 1)) }, |
| 16922 | } }); |
| 16923 | const mask_mcv = try self.genTypedValue(.{ |
| 16924 | .ty = mask_ty, |
| 16925 | .val = Value.fromInterned(try mod.intern(.{ .aggregate = .{ |
| 16926 | .ty = mask_ty.toIntern(), |
| 16927 | .storage = .{ .elems = mask_elems[0..vec_len] }, |
| 16928 | } })), |
| 16929 | }); |
| 16930 | const mask_mem: Memory = .{ |
| 16931 | .base = .{ .reg = try self.copyToTmpRegister(Type.usize, mask_mcv.address()) }, |
| 16932 | .mod = .{ .rm = .{ .size = self.memSize(ty) } }, |
| 16933 | }; |
| 16934 | if (has_avx) { |
| 16935 | try self.asmRegisterRegisterMemory( |
| 16936 | .{ .vp_, .@"and" }, |
| 16937 | mask_alias, |
| 16938 | mask_alias, |
| 16939 | mask_mem, |
| 16940 | ); |
| 16941 | try self.asmRegisterRegisterMemory( |
| 16942 | .{ .vp_d, .cmpeq }, |
| 16943 | mask_alias, |
| 16944 | mask_alias, |
| 16945 | mask_mem, |
| 16946 | ); |
| 16947 | } else { |
| 16948 | try self.asmRegisterMemory( |
| 16949 | .{ .p_, .@"and" }, |
| 16950 | mask_alias, |
| 16951 | mask_mem, |
| 16952 | ); |
| 16953 | try self.asmRegisterMemory( |
| 16954 | .{ .p_d, .cmpeq }, |
| 16955 | mask_alias, |
| 16956 | mask_mem, |
| 16957 | ); |
| 16958 | } |
| 16959 | } |
| 16960 | break :mask mask_reg; |
| 16961 | }; |
| 16962 | const mask_alias = registerAlias(mask_reg, abi_size); |
| 16963 | const mask_lock = self.register_manager.lockRegAssumeUnused(mask_reg); |
| 16964 | defer self.register_manager.unlockReg(mask_lock); |
| 16965 | |
| 16966 | const lhs_mcv = try self.resolveInst(extra.lhs); |
| 16967 | const lhs_lock = switch (lhs_mcv) { |
| 16968 | .register => |lhs_reg| self.register_manager.lockRegAssumeUnused(lhs_reg), |
| 16969 | else => null, |
| 16970 | }; |
| 16971 | defer if (lhs_lock) |lock| self.register_manager.unlockReg(lock); |
| 16972 | |
| 16973 | const rhs_mcv = try self.resolveInst(extra.rhs); |
| 16974 | const rhs_lock = switch (rhs_mcv) { |
| 16975 | .register => |rhs_reg| self.register_manager.lockReg(rhs_reg), |
| 16976 | else => null, |
| 16977 | }; |
| 16978 | defer if (rhs_lock) |lock| self.register_manager.unlockReg(lock); |
| 16979 | |
| 16980 | const reuse_mcv = if (has_blend) rhs_mcv else lhs_mcv; |
| 16981 | const dst_mcv: MCValue = if (reuse_mcv.isRegister() and self.reuseOperand( |
| 16982 | inst, |
| 16983 | if (has_blend) extra.rhs else extra.lhs, |
| 16984 | @intFromBool(has_blend), |
| 16985 | reuse_mcv, |
| 16986 | )) reuse_mcv else if (has_avx) |
| 16987 | .{ .register = try self.register_manager.allocReg(inst, abi.RegisterClass.sse) } |
| 16988 | else |
| 16989 | try self.copyToRegisterWithInstTracking(inst, ty, reuse_mcv); |
| 16990 | const dst_reg = dst_mcv.getReg().?; |
| 16991 | const dst_alias = registerAlias(dst_reg, abi_size); |
| 16992 | const dst_lock = self.register_manager.lockReg(dst_reg); |
| 16993 | defer if (dst_lock) |lock| self.register_manager.unlockReg(lock); |
| 16994 | |
| 16995 | const mir_tag = @as(?Mir.Inst.FixedTag, switch (ty.childType(mod).zigTypeTag(mod)) { |
| 16996 | else => null, |
| 16997 | .Int => switch (abi_size) { |
| 16998 | 0 => unreachable, |
| 16999 | 1...16 => if (has_avx) |
| 17000 | .{ .vp_b, .blendv } |
| 17001 | else if (has_blend) |
| 17002 | .{ .p_b, .blendv } |
| 17003 | else |
| 17004 | .{ .p_, undefined }, |
| 17005 | 17...32 => if (self.hasFeature(.avx2)) |
| 17006 | .{ .vp_b, .blendv } |
| 17007 | else |
| 17008 | null, |
| 17009 | else => null, |
| 17010 | }, |
| 17011 | .Float => switch (ty.childType(mod).floatBits(self.target.*)) { |
| 17012 | else => unreachable, |
| 17013 | 16, 80, 128 => null, |
| 17014 | 32 => switch (vec_len) { |
| 17015 | 0 => unreachable, |
| 17016 | 1...4 => if (has_avx) .{ .v_ps, .blendv } else .{ ._ps, .blendv }, |
| 17017 | 5...8 => if (has_avx) .{ .v_ps, .blendv } else null, |
| 17018 | else => null, |
| 17019 | }, |
| 17020 | 64 => switch (vec_len) { |
| 17021 | 0 => unreachable, |
| 17022 | 1...2 => if (has_avx) .{ .v_pd, .blendv } else .{ ._pd, .blendv }, |
| 17023 | 3...4 => if (has_avx) .{ .v_pd, .blendv } else null, |
| 17024 | else => null, |
| 17025 | }, |
| 17026 | }, |
| 17027 | }) orelse return self.fail("TODO implement airSelect for {}", .{ty.fmt(mod)}); |
| 17028 | if (has_avx) { |
| 17029 | const rhs_alias = if (rhs_mcv.isRegister()) |
| 17030 | registerAlias(rhs_mcv.getReg().?, abi_size) |
| 17031 | else rhs: { |
| 17032 | try self.genSetReg(dst_reg, ty, rhs_mcv, .{}); |
| 17033 | break :rhs dst_alias; |
| 17034 | }; |
| 17035 | if (lhs_mcv.isMemory()) try self.asmRegisterRegisterMemoryRegister( |
| 17036 | mir_tag, |
| 17037 | dst_alias, |
| 17038 | rhs_alias, |
| 17039 | try lhs_mcv.mem(self, self.memSize(ty)), |
| 17040 | mask_alias, |
| 17041 | ) else try self.asmRegisterRegisterRegisterRegister( |
| 17042 | mir_tag, |
| 17043 | dst_alias, |
| 17044 | rhs_alias, |
| 17045 | registerAlias(if (lhs_mcv.isRegister()) |
| 17046 | lhs_mcv.getReg().? |
| 17047 | else |
| 17048 | try self.copyToTmpRegister(ty, lhs_mcv), abi_size), |
| 17049 | mask_alias, |
| 17050 | ); |
| 17051 | } else if (has_blend) if (lhs_mcv.isMemory()) try self.asmRegisterMemoryRegister( |
| 17052 | mir_tag, |
| 17053 | dst_alias, |
| 17054 | try lhs_mcv.mem(self, self.memSize(ty)), |
| 17055 | mask_alias, |
| 17056 | ) else try self.asmRegisterRegisterRegister( |
| 17057 | mir_tag, |
| 17058 | dst_alias, |
| 17059 | registerAlias(if (lhs_mcv.isRegister()) |
| 17060 | lhs_mcv.getReg().? |
| 17061 | else |
| 17062 | try self.copyToTmpRegister(ty, lhs_mcv), abi_size), |
| 17063 | mask_alias, |
| 17064 | ) else { |
| 17065 | const mir_fixes = @as(?Mir.Inst.Fixes, switch (elem_ty.zigTypeTag(mod)) { |
| 17066 | else => null, |
| 17067 | .Int => .p_, |
| 17068 | .Float => switch (elem_ty.floatBits(self.target.*)) { |
| 17069 | 32 => ._ps, |
| 17070 | 64 => ._pd, |
| 17071 | 16, 80, 128 => null, |
| 17072 | else => unreachable, |
| 17073 | }, |
| 17074 | }) orelse return self.fail("TODO implement airSelect for {}", .{ty.fmt(mod)}); |
| 17075 | try self.asmRegisterRegister(.{ mir_fixes, .@"and" }, dst_alias, mask_alias); |
| 17076 | if (rhs_mcv.isMemory()) try self.asmRegisterMemory( |
| 17077 | .{ mir_fixes, .andn }, |
| 17078 | mask_alias, |
| 17079 | try rhs_mcv.mem(self, Memory.Size.fromSize(abi_size)), |
| 17080 | ) else try self.asmRegisterRegister( |
| 17081 | .{ mir_fixes, .andn }, |
| 17082 | mask_alias, |
| 17083 | if (rhs_mcv.isRegister()) |
| 17084 | rhs_mcv.getReg().? |
| 17085 | else |
| 17086 | try self.copyToTmpRegister(ty, rhs_mcv), |
| 17087 | ); |
| 17088 | try self.asmRegisterRegister(.{ mir_fixes, .@"or" }, dst_alias, mask_alias); |
| 17089 | } |
| 17090 | break :result dst_mcv; |
| 17091 | }; |
| 17092 | return self.finishAir(inst, result, .{ pl_op.operand, extra.lhs, extra.rhs }); |
| 16571 | 17093 | } |
| 16572 | 17094 | |
| 16573 | 17095 | fn airShuffle(self: *Self, inst: Air.Inst.Index) !void { |
| 17096 | const mod = self.bin_file.comp.module.?; |
| 16574 | 17097 | const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl; |
| 16575 | | _ = ty_pl; |
| 16576 | | return self.fail("TODO implement airShuffle for x86_64", .{}); |
| 16577 | | //return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| 17098 | const extra = self.air.extraData(Air.Shuffle, ty_pl.payload).data; |
| 17099 | |
| 17100 | const dst_ty = self.typeOfIndex(inst); |
| 17101 | const elem_ty = dst_ty.childType(mod); |
| 17102 | const elem_abi_size: u16 = @intCast(elem_ty.abiSize(mod)); |
| 17103 | const dst_abi_size: u32 = @intCast(dst_ty.abiSize(mod)); |
| 17104 | const lhs_ty = self.typeOf(extra.a); |
| 17105 | const lhs_abi_size: u32 = @intCast(lhs_ty.abiSize(mod)); |
| 17106 | const rhs_ty = self.typeOf(extra.b); |
| 17107 | const rhs_abi_size: u32 = @intCast(rhs_ty.abiSize(mod)); |
| 17108 | const max_abi_size = @max(dst_abi_size, lhs_abi_size, rhs_abi_size); |
| 17109 | |
| 17110 | const ExpectedContents = [32]?i32; |
| 17111 | var stack align(@max(@alignOf(ExpectedContents), @alignOf(std.heap.StackFallbackAllocator(0)))) = |
| 17112 | std.heap.stackFallback(@sizeOf(ExpectedContents), self.gpa); |
| 17113 | const allocator = stack.get(); |
| 17114 | |
| 17115 | const mask_elems = try allocator.alloc(?i32, extra.mask_len); |
| 17116 | defer allocator.free(mask_elems); |
| 17117 | for (mask_elems, 0..) |*mask_elem, elem_index| { |
| 17118 | const mask_elem_val = |
| 17119 | Value.fromInterned(extra.mask).elemValue(mod, elem_index) catch unreachable; |
| 17120 | mask_elem.* = if (mask_elem_val.isUndef(mod)) |
| 17121 | null |
| 17122 | else |
| 17123 | @intCast(mask_elem_val.toSignedInt(mod)); |
| 17124 | } |
| 17125 | |
| 17126 | const has_avx = self.hasFeature(.avx); |
| 17127 | const result = @as(?MCValue, result: { |
| 17128 | for (mask_elems) |mask_elem| { |
| 17129 | if (mask_elem) |_| break; |
| 17130 | } else break :result try self.allocRegOrMem(inst, true); |
| 17131 | |
| 17132 | for (mask_elems, 0..) |mask_elem, elem_index| { |
| 17133 | if (mask_elem orelse continue != elem_index) break; |
| 17134 | } else { |
| 17135 | const lhs_mcv = try self.resolveInst(extra.a); |
| 17136 | if (self.reuseOperand(inst, extra.a, 0, lhs_mcv)) break :result lhs_mcv; |
| 17137 | const dst_mcv = try self.allocRegOrMem(inst, true); |
| 17138 | try self.genCopy(dst_ty, dst_mcv, lhs_mcv, .{}); |
| 17139 | break :result dst_mcv; |
| 17140 | } |
| 17141 | |
| 17142 | for (mask_elems, 0..) |mask_elem, elem_index| { |
| 17143 | if (~(mask_elem orelse continue) != elem_index) break; |
| 17144 | } else { |
| 17145 | const rhs_mcv = try self.resolveInst(extra.b); |
| 17146 | if (self.reuseOperand(inst, extra.b, 1, rhs_mcv)) break :result rhs_mcv; |
| 17147 | const dst_mcv = try self.allocRegOrMem(inst, true); |
| 17148 | try self.genCopy(dst_ty, dst_mcv, rhs_mcv, .{}); |
| 17149 | break :result dst_mcv; |
| 17150 | } |
| 17151 | |
| 17152 | for ([_]Mir.Inst.Tag{ .unpckl, .unpckh }) |variant| unpck: { |
| 17153 | if (elem_abi_size > 8) break :unpck; |
| 17154 | if (dst_abi_size > @as(u32, if (if (elem_abi_size >= 4) |
| 17155 | has_avx |
| 17156 | else |
| 17157 | self.hasFeature(.avx2)) 32 else 16)) break :unpck; |
| 17158 | |
| 17159 | var sources = [1]?u1{null} ** 2; |
| 17160 | for (mask_elems, 0..) |maybe_mask_elem, elem_index| { |
| 17161 | const mask_elem = maybe_mask_elem orelse continue; |
| 17162 | const mask_elem_index = |
| 17163 | math.cast(u5, if (mask_elem < 0) ~mask_elem else mask_elem) orelse break :unpck; |
| 17164 | const elem_byte = (elem_index >> 1) * elem_abi_size; |
| 17165 | if (mask_elem_index * elem_abi_size != (elem_byte & 0b0111) | @as(u4, switch (variant) { |
| 17166 | .unpckl => 0b0000, |
| 17167 | .unpckh => 0b1000, |
| 17168 | else => unreachable, |
| 17169 | }) | (elem_byte << 1 & 0b10000)) break :unpck; |
| 17170 | |
| 17171 | const source = @intFromBool(mask_elem < 0); |
| 17172 | if (sources[elem_index & 0b00001]) |prev_source| { |
| 17173 | if (source != prev_source) break :unpck; |
| 17174 | } else sources[elem_index & 0b00001] = source; |
| 17175 | } |
| 17176 | if (sources[0] orelse break :unpck == sources[1] orelse break :unpck) break :unpck; |
| 17177 | |
| 17178 | const operands = [2]Air.Inst.Ref{ extra.a, extra.b }; |
| 17179 | const operand_tys = [2]Type{ lhs_ty, rhs_ty }; |
| 17180 | const lhs_mcv = try self.resolveInst(operands[sources[0].?]); |
| 17181 | const rhs_mcv = try self.resolveInst(operands[sources[1].?]); |
| 17182 | |
| 17183 | const dst_mcv: MCValue = if (lhs_mcv.isRegister() and |
| 17184 | self.reuseOperand(inst, operands[sources[0].?], sources[0].?, lhs_mcv)) |
| 17185 | lhs_mcv |
| 17186 | else if (has_avx and lhs_mcv.isRegister()) |
| 17187 | .{ .register = try self.register_manager.allocReg(inst, abi.RegisterClass.sse) } |
| 17188 | else |
| 17189 | try self.copyToRegisterWithInstTracking(inst, operand_tys[sources[0].?], lhs_mcv); |
| 17190 | const dst_reg = dst_mcv.getReg().?; |
| 17191 | const dst_alias = registerAlias(dst_reg, max_abi_size); |
| 17192 | |
| 17193 | const mir_tag: Mir.Inst.FixedTag = if ((elem_abi_size >= 4 and elem_ty.isRuntimeFloat()) or |
| 17194 | (dst_abi_size > 16 and !self.hasFeature(.avx2))) .{ switch (elem_abi_size) { |
| 17195 | 4 => if (has_avx) .v_ps else ._ps, |
| 17196 | 8 => if (has_avx) .v_pd else ._pd, |
| 17197 | else => unreachable, |
| 17198 | }, variant } else .{ if (has_avx) .vp_ else .p_, switch (variant) { |
| 17199 | .unpckl => switch (elem_abi_size) { |
| 17200 | 1 => .unpcklbw, |
| 17201 | 2 => .unpcklwd, |
| 17202 | 4 => .unpckldq, |
| 17203 | 8 => .unpcklqdq, |
| 17204 | else => unreachable, |
| 17205 | }, |
| 17206 | .unpckh => switch (elem_abi_size) { |
| 17207 | 1 => .unpckhbw, |
| 17208 | 2 => .unpckhwd, |
| 17209 | 4 => .unpckhdq, |
| 17210 | 8 => .unpckhqdq, |
| 17211 | else => unreachable, |
| 17212 | }, |
| 17213 | else => unreachable, |
| 17214 | } }; |
| 17215 | if (has_avx) if (rhs_mcv.isMemory()) try self.asmRegisterRegisterMemory( |
| 17216 | mir_tag, |
| 17217 | dst_alias, |
| 17218 | registerAlias(lhs_mcv.getReg() orelse dst_reg, max_abi_size), |
| 17219 | try rhs_mcv.mem(self, Memory.Size.fromSize(max_abi_size)), |
| 17220 | ) else try self.asmRegisterRegisterRegister( |
| 17221 | mir_tag, |
| 17222 | dst_alias, |
| 17223 | registerAlias(lhs_mcv.getReg() orelse dst_reg, max_abi_size), |
| 17224 | registerAlias(if (rhs_mcv.isRegister()) |
| 17225 | rhs_mcv.getReg().? |
| 17226 | else |
| 17227 | try self.copyToTmpRegister(operand_tys[sources[1].?], rhs_mcv), max_abi_size), |
| 17228 | ) else if (rhs_mcv.isMemory()) try self.asmRegisterMemory( |
| 17229 | mir_tag, |
| 17230 | dst_alias, |
| 17231 | try rhs_mcv.mem(self, Memory.Size.fromSize(max_abi_size)), |
| 17232 | ) else try self.asmRegisterRegister( |
| 17233 | mir_tag, |
| 17234 | dst_alias, |
| 17235 | registerAlias(if (rhs_mcv.isRegister()) |
| 17236 | rhs_mcv.getReg().? |
| 17237 | else |
| 17238 | try self.copyToTmpRegister(operand_tys[sources[1].?], rhs_mcv), max_abi_size), |
| 17239 | ); |
| 17240 | break :result dst_mcv; |
| 17241 | } |
| 17242 | |
| 17243 | pshufd: { |
| 17244 | if (elem_abi_size != 4) break :pshufd; |
| 17245 | if (max_abi_size > @as(u32, if (has_avx) 32 else 16)) break :pshufd; |
| 17246 | |
| 17247 | var control: u8 = 0b00_00_00_00; |
| 17248 | var sources = [1]?u1{null} ** 1; |
| 17249 | for (mask_elems, 0..) |maybe_mask_elem, elem_index| { |
| 17250 | const mask_elem = maybe_mask_elem orelse continue; |
| 17251 | const mask_elem_index: u3 = @intCast(if (mask_elem < 0) ~mask_elem else mask_elem); |
| 17252 | if (mask_elem_index & 0b100 != elem_index & 0b100) break :pshufd; |
| 17253 | |
| 17254 | const source = @intFromBool(mask_elem < 0); |
| 17255 | if (sources[0]) |prev_source| { |
| 17256 | if (source != prev_source) break :pshufd; |
| 17257 | } else sources[(elem_index & 0b010) >> 1] = source; |
| 17258 | |
| 17259 | const select_bit: u3 = @intCast((elem_index & 0b011) << 1); |
| 17260 | const select = @as(u8, @intCast(mask_elem_index & 0b011)) << select_bit; |
| 17261 | if (elem_index & 0b100 == 0) |
| 17262 | control |= select |
| 17263 | else if (control & @as(u8, 0b11) << select_bit != select) break :pshufd; |
| 17264 | } |
| 17265 | |
| 17266 | const operands = [2]Air.Inst.Ref{ extra.a, extra.b }; |
| 17267 | const operand_tys = [2]Type{ lhs_ty, rhs_ty }; |
| 17268 | const src_mcv = try self.resolveInst(operands[sources[0] orelse break :pshufd]); |
| 17269 | |
| 17270 | const dst_reg = if (src_mcv.isRegister() and |
| 17271 | self.reuseOperand(inst, operands[sources[0].?], sources[0].?, src_mcv)) |
| 17272 | src_mcv.getReg().? |
| 17273 | else |
| 17274 | try self.register_manager.allocReg(inst, abi.RegisterClass.sse); |
| 17275 | const dst_alias = registerAlias(dst_reg, max_abi_size); |
| 17276 | |
| 17277 | if (src_mcv.isMemory()) try self.asmRegisterMemoryImmediate( |
| 17278 | .{ if (has_avx) .vp_d else .p_d, .shuf }, |
| 17279 | dst_alias, |
| 17280 | try src_mcv.mem(self, Memory.Size.fromSize(max_abi_size)), |
| 17281 | Immediate.u(control), |
| 17282 | ) else try self.asmRegisterRegisterImmediate( |
| 17283 | .{ if (has_avx) .vp_d else .p_d, .shuf }, |
| 17284 | dst_alias, |
| 17285 | registerAlias(if (src_mcv.isRegister()) |
| 17286 | src_mcv.getReg().? |
| 17287 | else |
| 17288 | try self.copyToTmpRegister(operand_tys[sources[0].?], src_mcv), max_abi_size), |
| 17289 | Immediate.u(control), |
| 17290 | ); |
| 17291 | break :result .{ .register = dst_reg }; |
| 17292 | } |
| 17293 | |
| 17294 | shufps: { |
| 17295 | if (elem_abi_size != 4) break :shufps; |
| 17296 | if (max_abi_size > @as(u32, if (has_avx) 32 else 16)) break :shufps; |
| 17297 | |
| 17298 | var control: u8 = 0b00_00_00_00; |
| 17299 | var sources = [1]?u1{null} ** 2; |
| 17300 | for (mask_elems, 0..) |maybe_mask_elem, elem_index| { |
| 17301 | const mask_elem = maybe_mask_elem orelse continue; |
| 17302 | const mask_elem_index: u3 = @intCast(if (mask_elem < 0) ~mask_elem else mask_elem); |
| 17303 | if (mask_elem_index & 0b100 != elem_index & 0b100) break :shufps; |
| 17304 | |
| 17305 | const source = @intFromBool(mask_elem < 0); |
| 17306 | if (sources[(elem_index & 0b010) >> 1]) |prev_source| { |
| 17307 | if (source != prev_source) break :shufps; |
| 17308 | } else sources[(elem_index & 0b010) >> 1] = source; |
| 17309 | |
| 17310 | const select_bit: u3 = @intCast((elem_index & 0b011) << 1); |
| 17311 | const select = @as(u8, @intCast(mask_elem_index & 0b011)) << select_bit; |
| 17312 | if (elem_index & 0b100 == 0) |
| 17313 | control |= select |
| 17314 | else if (control & @as(u8, 0b11) << select_bit != select) break :shufps; |
| 17315 | } |
| 17316 | if (sources[0] orelse break :shufps == sources[1] orelse break :shufps) break :shufps; |
| 17317 | |
| 17318 | const operands = [2]Air.Inst.Ref{ extra.a, extra.b }; |
| 17319 | const operand_tys = [2]Type{ lhs_ty, rhs_ty }; |
| 17320 | const lhs_mcv = try self.resolveInst(operands[sources[0].?]); |
| 17321 | const rhs_mcv = try self.resolveInst(operands[sources[1].?]); |
| 17322 | |
| 17323 | const dst_mcv: MCValue = if (lhs_mcv.isRegister() and |
| 17324 | self.reuseOperand(inst, operands[sources[0].?], sources[0].?, lhs_mcv)) |
| 17325 | lhs_mcv |
| 17326 | else if (has_avx and lhs_mcv.isRegister()) |
| 17327 | .{ .register = try self.register_manager.allocReg(inst, abi.RegisterClass.sse) } |
| 17328 | else |
| 17329 | try self.copyToRegisterWithInstTracking(inst, operand_tys[sources[0].?], lhs_mcv); |
| 17330 | const dst_reg = dst_mcv.getReg().?; |
| 17331 | const dst_alias = registerAlias(dst_reg, max_abi_size); |
| 17332 | |
| 17333 | if (has_avx) if (rhs_mcv.isMemory()) try self.asmRegisterRegisterMemoryImmediate( |
| 17334 | .{ .v_ps, .shuf }, |
| 17335 | dst_alias, |
| 17336 | registerAlias(lhs_mcv.getReg() orelse dst_reg, max_abi_size), |
| 17337 | try rhs_mcv.mem(self, Memory.Size.fromSize(max_abi_size)), |
| 17338 | Immediate.u(control), |
| 17339 | ) else try self.asmRegisterRegisterRegisterImmediate( |
| 17340 | .{ .v_ps, .shuf }, |
| 17341 | dst_alias, |
| 17342 | registerAlias(lhs_mcv.getReg() orelse dst_reg, max_abi_size), |
| 17343 | registerAlias(if (rhs_mcv.isRegister()) |
| 17344 | rhs_mcv.getReg().? |
| 17345 | else |
| 17346 | try self.copyToTmpRegister(operand_tys[sources[1].?], rhs_mcv), max_abi_size), |
| 17347 | Immediate.u(control), |
| 17348 | ) else if (rhs_mcv.isMemory()) try self.asmRegisterMemoryImmediate( |
| 17349 | .{ ._ps, .shuf }, |
| 17350 | dst_alias, |
| 17351 | try rhs_mcv.mem(self, Memory.Size.fromSize(max_abi_size)), |
| 17352 | Immediate.u(control), |
| 17353 | ) else try self.asmRegisterRegisterImmediate( |
| 17354 | .{ ._ps, .shuf }, |
| 17355 | dst_alias, |
| 17356 | registerAlias(if (rhs_mcv.isRegister()) |
| 17357 | rhs_mcv.getReg().? |
| 17358 | else |
| 17359 | try self.copyToTmpRegister(operand_tys[sources[1].?], rhs_mcv), max_abi_size), |
| 17360 | Immediate.u(control), |
| 17361 | ); |
| 17362 | break :result dst_mcv; |
| 17363 | } |
| 17364 | |
| 17365 | shufpd: { |
| 17366 | if (elem_abi_size != 8) break :shufpd; |
| 17367 | if (max_abi_size > @as(u32, if (has_avx) 32 else 16)) break :shufpd; |
| 17368 | |
| 17369 | var control: u4 = 0b0_0_0_0; |
| 17370 | var sources = [1]?u1{null} ** 2; |
| 17371 | for (mask_elems, 0..) |maybe_mask_elem, elem_index| { |
| 17372 | const mask_elem = maybe_mask_elem orelse continue; |
| 17373 | const mask_elem_index: u2 = @intCast(if (mask_elem < 0) ~mask_elem else mask_elem); |
| 17374 | if (mask_elem_index & 0b10 != elem_index & 0b10) break :shufpd; |
| 17375 | |
| 17376 | const source = @intFromBool(mask_elem < 0); |
| 17377 | if (sources[elem_index & 0b01]) |prev_source| { |
| 17378 | if (source != prev_source) break :shufpd; |
| 17379 | } else sources[elem_index & 0b01] = source; |
| 17380 | |
| 17381 | control |= @as(u4, @intCast(mask_elem_index & 0b01)) << @intCast(elem_index); |
| 17382 | } |
| 17383 | if (sources[0] orelse break :shufpd == sources[1] orelse break :shufpd) break :shufpd; |
| 17384 | |
| 17385 | const operands: [2]Air.Inst.Ref = .{ extra.a, extra.b }; |
| 17386 | const operand_tys: [2]Type = .{ lhs_ty, rhs_ty }; |
| 17387 | const lhs_mcv = try self.resolveInst(operands[sources[0].?]); |
| 17388 | const rhs_mcv = try self.resolveInst(operands[sources[1].?]); |
| 17389 | |
| 17390 | const dst_mcv: MCValue = if (lhs_mcv.isRegister() and |
| 17391 | self.reuseOperand(inst, operands[sources[0].?], sources[0].?, lhs_mcv)) |
| 17392 | lhs_mcv |
| 17393 | else if (has_avx and lhs_mcv.isRegister()) |
| 17394 | .{ .register = try self.register_manager.allocReg(inst, abi.RegisterClass.sse) } |
| 17395 | else |
| 17396 | try self.copyToRegisterWithInstTracking(inst, operand_tys[sources[0].?], lhs_mcv); |
| 17397 | const dst_reg = dst_mcv.getReg().?; |
| 17398 | const dst_alias = registerAlias(dst_reg, max_abi_size); |
| 17399 | |
| 17400 | if (has_avx) if (rhs_mcv.isMemory()) try self.asmRegisterRegisterMemoryImmediate( |
| 17401 | .{ .v_pd, .shuf }, |
| 17402 | dst_alias, |
| 17403 | registerAlias(lhs_mcv.getReg() orelse dst_reg, max_abi_size), |
| 17404 | try rhs_mcv.mem(self, Memory.Size.fromSize(max_abi_size)), |
| 17405 | Immediate.u(control), |
| 17406 | ) else try self.asmRegisterRegisterRegisterImmediate( |
| 17407 | .{ .v_pd, .shuf }, |
| 17408 | dst_alias, |
| 17409 | registerAlias(lhs_mcv.getReg() orelse dst_reg, max_abi_size), |
| 17410 | registerAlias(if (rhs_mcv.isRegister()) |
| 17411 | rhs_mcv.getReg().? |
| 17412 | else |
| 17413 | try self.copyToTmpRegister(operand_tys[sources[1].?], rhs_mcv), max_abi_size), |
| 17414 | Immediate.u(control), |
| 17415 | ) else if (rhs_mcv.isMemory()) try self.asmRegisterMemoryImmediate( |
| 17416 | .{ ._pd, .shuf }, |
| 17417 | dst_alias, |
| 17418 | try rhs_mcv.mem(self, Memory.Size.fromSize(max_abi_size)), |
| 17419 | Immediate.u(control), |
| 17420 | ) else try self.asmRegisterRegisterImmediate( |
| 17421 | .{ ._pd, .shuf }, |
| 17422 | dst_alias, |
| 17423 | registerAlias(if (rhs_mcv.isRegister()) |
| 17424 | rhs_mcv.getReg().? |
| 17425 | else |
| 17426 | try self.copyToTmpRegister(operand_tys[sources[1].?], rhs_mcv), max_abi_size), |
| 17427 | Immediate.u(control), |
| 17428 | ); |
| 17429 | break :result dst_mcv; |
| 17430 | } |
| 17431 | |
| 17432 | blend: { |
| 17433 | if (elem_abi_size < 2) break :blend; |
| 17434 | if (dst_abi_size > @as(u32, if (has_avx) 32 else 16)) break :blend; |
| 17435 | if (!self.hasFeature(.sse4_1)) break :blend; |
| 17436 | |
| 17437 | var control: u8 = 0b0_0_0_0_0_0_0_0; |
| 17438 | for (mask_elems, 0..) |maybe_mask_elem, elem_index| { |
| 17439 | const mask_elem = maybe_mask_elem orelse continue; |
| 17440 | const mask_elem_index = |
| 17441 | math.cast(u4, if (mask_elem < 0) ~mask_elem else mask_elem) orelse break :blend; |
| 17442 | if (mask_elem_index != elem_index) break :blend; |
| 17443 | |
| 17444 | const select = @as(u8, @intFromBool(mask_elem < 0)) << @truncate(elem_index); |
| 17445 | if (elem_index & 0b1000 == 0) |
| 17446 | control |= select |
| 17447 | else if (control & @as(u8, 0b1) << @truncate(elem_index) != select) break :blend; |
| 17448 | } |
| 17449 | |
| 17450 | if (!elem_ty.isRuntimeFloat() and self.hasFeature(.avx2)) vpblendd: { |
| 17451 | const expanded_control = switch (elem_abi_size) { |
| 17452 | 4 => control, |
| 17453 | 8 => @as(u8, if (control & 0b0001 != 0) 0b00_00_00_11 else 0b00_00_00_00) | |
| 17454 | @as(u8, if (control & 0b0010 != 0) 0b00_00_11_00 else 0b00_00_00_00) | |
| 17455 | @as(u8, if (control & 0b0100 != 0) 0b00_11_00_00 else 0b00_00_00_00) | |
| 17456 | @as(u8, if (control & 0b1000 != 0) 0b11_00_00_00 else 0b00_00_00_00), |
| 17457 | else => break :vpblendd, |
| 17458 | }; |
| 17459 | |
| 17460 | const lhs_mcv = try self.resolveInst(extra.a); |
| 17461 | const lhs_reg = if (lhs_mcv.isRegister()) |
| 17462 | lhs_mcv.getReg().? |
| 17463 | else |
| 17464 | try self.copyToTmpRegister(dst_ty, lhs_mcv); |
| 17465 | const lhs_lock = self.register_manager.lockReg(lhs_reg); |
| 17466 | defer if (lhs_lock) |lock| self.register_manager.unlockReg(lock); |
| 17467 | |
| 17468 | const rhs_mcv = try self.resolveInst(extra.b); |
| 17469 | const dst_reg = try self.register_manager.allocReg(inst, abi.RegisterClass.sse); |
| 17470 | if (rhs_mcv.isMemory()) try self.asmRegisterRegisterMemoryImmediate( |
| 17471 | .{ .vp_d, .blend }, |
| 17472 | registerAlias(dst_reg, dst_abi_size), |
| 17473 | registerAlias(lhs_reg, dst_abi_size), |
| 17474 | try rhs_mcv.mem(self, Memory.Size.fromSize(dst_abi_size)), |
| 17475 | Immediate.u(expanded_control), |
| 17476 | ) else try self.asmRegisterRegisterRegisterImmediate( |
| 17477 | .{ .vp_d, .blend }, |
| 17478 | registerAlias(dst_reg, dst_abi_size), |
| 17479 | registerAlias(lhs_reg, dst_abi_size), |
| 17480 | registerAlias(if (rhs_mcv.isRegister()) |
| 17481 | rhs_mcv.getReg().? |
| 17482 | else |
| 17483 | try self.copyToTmpRegister(dst_ty, rhs_mcv), dst_abi_size), |
| 17484 | Immediate.u(expanded_control), |
| 17485 | ); |
| 17486 | break :result .{ .register = dst_reg }; |
| 17487 | } |
| 17488 | |
| 17489 | if (!elem_ty.isRuntimeFloat() or elem_abi_size == 2) pblendw: { |
| 17490 | const expanded_control = switch (elem_abi_size) { |
| 17491 | 2 => control, |
| 17492 | 4 => if (dst_abi_size <= 16 or |
| 17493 | @as(u4, @intCast(control >> 4)) == @as(u4, @truncate(control >> 0))) |
| 17494 | @as(u8, if (control & 0b0001 != 0) 0b00_00_00_11 else 0b00_00_00_00) | |
| 17495 | @as(u8, if (control & 0b0010 != 0) 0b00_00_11_00 else 0b00_00_00_00) | |
| 17496 | @as(u8, if (control & 0b0100 != 0) 0b00_11_00_00 else 0b00_00_00_00) | |
| 17497 | @as(u8, if (control & 0b1000 != 0) 0b11_00_00_00 else 0b00_00_00_00) |
| 17498 | else |
| 17499 | break :pblendw, |
| 17500 | 8 => if (dst_abi_size <= 16 or |
| 17501 | @as(u2, @intCast(control >> 2)) == @as(u2, @truncate(control >> 0))) |
| 17502 | @as(u8, if (control & 0b01 != 0) 0b0000_1111 else 0b0000_0000) | |
| 17503 | @as(u8, if (control & 0b10 != 0) 0b1111_0000 else 0b0000_0000) |
| 17504 | else |
| 17505 | break :pblendw, |
| 17506 | 16 => break :pblendw, |
| 17507 | else => unreachable, |
| 17508 | }; |
| 17509 | |
| 17510 | const lhs_mcv = try self.resolveInst(extra.a); |
| 17511 | const rhs_mcv = try self.resolveInst(extra.b); |
| 17512 | |
| 17513 | const dst_mcv: MCValue = if (lhs_mcv.isRegister() and |
| 17514 | self.reuseOperand(inst, extra.a, 0, lhs_mcv)) |
| 17515 | lhs_mcv |
| 17516 | else if (has_avx and lhs_mcv.isRegister()) |
| 17517 | .{ .register = try self.register_manager.allocReg(inst, abi.RegisterClass.sse) } |
| 17518 | else |
| 17519 | try self.copyToRegisterWithInstTracking(inst, dst_ty, lhs_mcv); |
| 17520 | const dst_reg = dst_mcv.getReg().?; |
| 17521 | |
| 17522 | if (has_avx) if (rhs_mcv.isMemory()) try self.asmRegisterRegisterMemoryImmediate( |
| 17523 | .{ .vp_w, .blend }, |
| 17524 | registerAlias(dst_reg, dst_abi_size), |
| 17525 | registerAlias(if (lhs_mcv.isRegister()) |
| 17526 | lhs_mcv.getReg().? |
| 17527 | else |
| 17528 | dst_reg, dst_abi_size), |
| 17529 | try rhs_mcv.mem(self, Memory.Size.fromSize(dst_abi_size)), |
| 17530 | Immediate.u(expanded_control), |
| 17531 | ) else try self.asmRegisterRegisterRegisterImmediate( |
| 17532 | .{ .vp_w, .blend }, |
| 17533 | registerAlias(dst_reg, dst_abi_size), |
| 17534 | registerAlias(if (lhs_mcv.isRegister()) |
| 17535 | lhs_mcv.getReg().? |
| 17536 | else |
| 17537 | dst_reg, dst_abi_size), |
| 17538 | registerAlias(if (rhs_mcv.isRegister()) |
| 17539 | rhs_mcv.getReg().? |
| 17540 | else |
| 17541 | try self.copyToTmpRegister(dst_ty, rhs_mcv), dst_abi_size), |
| 17542 | Immediate.u(expanded_control), |
| 17543 | ) else if (rhs_mcv.isMemory()) try self.asmRegisterMemoryImmediate( |
| 17544 | .{ .p_w, .blend }, |
| 17545 | registerAlias(dst_reg, dst_abi_size), |
| 17546 | try rhs_mcv.mem(self, Memory.Size.fromSize(dst_abi_size)), |
| 17547 | Immediate.u(expanded_control), |
| 17548 | ) else try self.asmRegisterRegisterImmediate( |
| 17549 | .{ .p_w, .blend }, |
| 17550 | registerAlias(dst_reg, dst_abi_size), |
| 17551 | registerAlias(if (rhs_mcv.isRegister()) |
| 17552 | rhs_mcv.getReg().? |
| 17553 | else |
| 17554 | try self.copyToTmpRegister(dst_ty, rhs_mcv), dst_abi_size), |
| 17555 | Immediate.u(expanded_control), |
| 17556 | ); |
| 17557 | break :result .{ .register = dst_reg }; |
| 17558 | } |
| 17559 | |
| 17560 | const expanded_control = switch (elem_abi_size) { |
| 17561 | 4, 8 => control, |
| 17562 | 16 => @as(u4, if (control & 0b01 != 0) 0b00_11 else 0b00_00) | |
| 17563 | @as(u4, if (control & 0b10 != 0) 0b11_00 else 0b00_00), |
| 17564 | else => unreachable, |
| 17565 | }; |
| 17566 | |
| 17567 | const lhs_mcv = try self.resolveInst(extra.a); |
| 17568 | const rhs_mcv = try self.resolveInst(extra.b); |
| 17569 | |
| 17570 | const dst_mcv: MCValue = if (lhs_mcv.isRegister() and |
| 17571 | self.reuseOperand(inst, extra.a, 0, lhs_mcv)) |
| 17572 | lhs_mcv |
| 17573 | else if (has_avx and lhs_mcv.isRegister()) |
| 17574 | .{ .register = try self.register_manager.allocReg(inst, abi.RegisterClass.sse) } |
| 17575 | else |
| 17576 | try self.copyToRegisterWithInstTracking(inst, dst_ty, lhs_mcv); |
| 17577 | const dst_reg = dst_mcv.getReg().?; |
| 17578 | |
| 17579 | if (has_avx) if (rhs_mcv.isMemory()) try self.asmRegisterRegisterMemoryImmediate( |
| 17580 | switch (elem_abi_size) { |
| 17581 | 4 => .{ .v_ps, .blend }, |
| 17582 | 8, 16 => .{ .v_pd, .blend }, |
| 17583 | else => unreachable, |
| 17584 | }, |
| 17585 | registerAlias(dst_reg, dst_abi_size), |
| 17586 | registerAlias(if (lhs_mcv.isRegister()) |
| 17587 | lhs_mcv.getReg().? |
| 17588 | else |
| 17589 | dst_reg, dst_abi_size), |
| 17590 | try rhs_mcv.mem(self, Memory.Size.fromSize(dst_abi_size)), |
| 17591 | Immediate.u(expanded_control), |
| 17592 | ) else try self.asmRegisterRegisterRegisterImmediate( |
| 17593 | switch (elem_abi_size) { |
| 17594 | 4 => .{ .v_ps, .blend }, |
| 17595 | 8, 16 => .{ .v_pd, .blend }, |
| 17596 | else => unreachable, |
| 17597 | }, |
| 17598 | registerAlias(dst_reg, dst_abi_size), |
| 17599 | registerAlias(if (lhs_mcv.isRegister()) |
| 17600 | lhs_mcv.getReg().? |
| 17601 | else |
| 17602 | dst_reg, dst_abi_size), |
| 17603 | registerAlias(if (rhs_mcv.isRegister()) |
| 17604 | rhs_mcv.getReg().? |
| 17605 | else |
| 17606 | try self.copyToTmpRegister(dst_ty, rhs_mcv), dst_abi_size), |
| 17607 | Immediate.u(expanded_control), |
| 17608 | ) else if (rhs_mcv.isMemory()) try self.asmRegisterMemoryImmediate( |
| 17609 | switch (elem_abi_size) { |
| 17610 | 4 => .{ ._ps, .blend }, |
| 17611 | 8, 16 => .{ ._pd, .blend }, |
| 17612 | else => unreachable, |
| 17613 | }, |
| 17614 | registerAlias(dst_reg, dst_abi_size), |
| 17615 | try rhs_mcv.mem(self, Memory.Size.fromSize(dst_abi_size)), |
| 17616 | Immediate.u(expanded_control), |
| 17617 | ) else try self.asmRegisterRegisterImmediate( |
| 17618 | switch (elem_abi_size) { |
| 17619 | 4 => .{ ._ps, .blend }, |
| 17620 | 8, 16 => .{ ._pd, .blend }, |
| 17621 | else => unreachable, |
| 17622 | }, |
| 17623 | registerAlias(dst_reg, dst_abi_size), |
| 17624 | registerAlias(if (rhs_mcv.isRegister()) |
| 17625 | rhs_mcv.getReg().? |
| 17626 | else |
| 17627 | try self.copyToTmpRegister(dst_ty, rhs_mcv), dst_abi_size), |
| 17628 | Immediate.u(expanded_control), |
| 17629 | ); |
| 17630 | break :result .{ .register = dst_reg }; |
| 17631 | } |
| 17632 | |
| 17633 | blendv: { |
| 17634 | if (dst_abi_size > @as(u32, if (if (elem_abi_size >= 4) |
| 17635 | has_avx |
| 17636 | else |
| 17637 | self.hasFeature(.avx2)) 32 else 16)) break :blendv; |
| 17638 | |
| 17639 | const select_mask_elem_ty = try mod.intType(.unsigned, elem_abi_size * 8); |
| 17640 | const select_mask_ty = try mod.vectorType(.{ |
| 17641 | .len = @intCast(mask_elems.len), |
| 17642 | .child = select_mask_elem_ty.toIntern(), |
| 17643 | }); |
| 17644 | var select_mask_elems: [32]InternPool.Index = undefined; |
| 17645 | for ( |
| 17646 | select_mask_elems[0..mask_elems.len], |
| 17647 | mask_elems, |
| 17648 | 0.., |
| 17649 | ) |*select_mask_elem, maybe_mask_elem, elem_index| { |
| 17650 | const mask_elem = maybe_mask_elem orelse continue; |
| 17651 | const mask_elem_index = |
| 17652 | math.cast(u5, if (mask_elem < 0) ~mask_elem else mask_elem) orelse break :blendv; |
| 17653 | if (mask_elem_index != elem_index) break :blendv; |
| 17654 | |
| 17655 | select_mask_elem.* = (if (mask_elem < 0) |
| 17656 | try select_mask_elem_ty.maxIntScalar(mod, select_mask_elem_ty) |
| 17657 | else |
| 17658 | try select_mask_elem_ty.minIntScalar(mod, select_mask_elem_ty)).toIntern(); |
| 17659 | } |
| 17660 | const select_mask_mcv = try self.genTypedValue(.{ |
| 17661 | .ty = select_mask_ty, |
| 17662 | .val = Value.fromInterned(try mod.intern(.{ .aggregate = .{ |
| 17663 | .ty = select_mask_ty.toIntern(), |
| 17664 | .storage = .{ .elems = select_mask_elems[0..mask_elems.len] }, |
| 17665 | } })), |
| 17666 | }); |
| 17667 | |
| 17668 | if (self.hasFeature(.sse4_1)) { |
| 17669 | const mir_tag: Mir.Inst.FixedTag = .{ |
| 17670 | if ((elem_abi_size >= 4 and elem_ty.isRuntimeFloat()) or |
| 17671 | (dst_abi_size > 16 and !self.hasFeature(.avx2))) switch (elem_abi_size) { |
| 17672 | 4 => if (has_avx) .v_ps else ._ps, |
| 17673 | 8 => if (has_avx) .v_pd else ._pd, |
| 17674 | else => unreachable, |
| 17675 | } else if (has_avx) .vp_b else .p_b, |
| 17676 | .blendv, |
| 17677 | }; |
| 17678 | |
| 17679 | const select_mask_reg = if (!has_avx) reg: { |
| 17680 | try self.register_manager.getKnownReg(.xmm0, null); |
| 17681 | try self.genSetReg(.xmm0, select_mask_elem_ty, select_mask_mcv, .{}); |
| 17682 | break :reg .xmm0; |
| 17683 | } else try self.copyToTmpRegister(select_mask_ty, select_mask_mcv); |
| 17684 | const select_mask_alias = registerAlias(select_mask_reg, dst_abi_size); |
| 17685 | const select_mask_lock = self.register_manager.lockRegAssumeUnused(select_mask_reg); |
| 17686 | defer self.register_manager.unlockReg(select_mask_lock); |
| 17687 | |
| 17688 | const lhs_mcv = try self.resolveInst(extra.a); |
| 17689 | const rhs_mcv = try self.resolveInst(extra.b); |
| 17690 | |
| 17691 | const dst_mcv: MCValue = if (lhs_mcv.isRegister() and |
| 17692 | self.reuseOperand(inst, extra.a, 0, lhs_mcv)) |
| 17693 | lhs_mcv |
| 17694 | else if (has_avx and lhs_mcv.isRegister()) |
| 17695 | .{ .register = try self.register_manager.allocReg(inst, abi.RegisterClass.sse) } |
| 17696 | else |
| 17697 | try self.copyToRegisterWithInstTracking(inst, dst_ty, lhs_mcv); |
| 17698 | const dst_reg = dst_mcv.getReg().?; |
| 17699 | const dst_alias = registerAlias(dst_reg, dst_abi_size); |
| 17700 | |
| 17701 | if (has_avx) if (rhs_mcv.isMemory()) try self.asmRegisterRegisterMemoryRegister( |
| 17702 | mir_tag, |
| 17703 | dst_alias, |
| 17704 | if (lhs_mcv.isRegister()) |
| 17705 | registerAlias(lhs_mcv.getReg().?, dst_abi_size) |
| 17706 | else |
| 17707 | dst_alias, |
| 17708 | try rhs_mcv.mem(self, Memory.Size.fromSize(dst_abi_size)), |
| 17709 | select_mask_alias, |
| 17710 | ) else try self.asmRegisterRegisterRegisterRegister( |
| 17711 | mir_tag, |
| 17712 | dst_alias, |
| 17713 | if (lhs_mcv.isRegister()) |
| 17714 | registerAlias(lhs_mcv.getReg().?, dst_abi_size) |
| 17715 | else |
| 17716 | dst_alias, |
| 17717 | registerAlias(if (rhs_mcv.isRegister()) |
| 17718 | rhs_mcv.getReg().? |
| 17719 | else |
| 17720 | try self.copyToTmpRegister(dst_ty, rhs_mcv), dst_abi_size), |
| 17721 | select_mask_alias, |
| 17722 | ) else if (rhs_mcv.isMemory()) try self.asmRegisterMemoryRegister( |
| 17723 | mir_tag, |
| 17724 | dst_alias, |
| 17725 | try rhs_mcv.mem(self, Memory.Size.fromSize(dst_abi_size)), |
| 17726 | select_mask_alias, |
| 17727 | ) else try self.asmRegisterRegisterRegister( |
| 17728 | mir_tag, |
| 17729 | dst_alias, |
| 17730 | registerAlias(if (rhs_mcv.isRegister()) |
| 17731 | rhs_mcv.getReg().? |
| 17732 | else |
| 17733 | try self.copyToTmpRegister(dst_ty, rhs_mcv), dst_abi_size), |
| 17734 | select_mask_alias, |
| 17735 | ); |
| 17736 | break :result dst_mcv; |
| 17737 | } |
| 17738 | |
| 17739 | const lhs_mcv = try self.resolveInst(extra.a); |
| 17740 | const rhs_mcv = try self.resolveInst(extra.b); |
| 17741 | |
| 17742 | const dst_mcv: MCValue = if (rhs_mcv.isRegister() and |
| 17743 | self.reuseOperand(inst, extra.b, 1, rhs_mcv)) |
| 17744 | rhs_mcv |
| 17745 | else |
| 17746 | try self.copyToRegisterWithInstTracking(inst, dst_ty, rhs_mcv); |
| 17747 | const dst_reg = dst_mcv.getReg().?; |
| 17748 | const dst_alias = registerAlias(dst_reg, dst_abi_size); |
| 17749 | |
| 17750 | const mask_reg = try self.copyToTmpRegister(select_mask_ty, select_mask_mcv); |
| 17751 | const mask_alias = registerAlias(mask_reg, dst_abi_size); |
| 17752 | const mask_lock = self.register_manager.lockRegAssumeUnused(mask_reg); |
| 17753 | defer self.register_manager.unlockReg(mask_lock); |
| 17754 | |
| 17755 | const mir_fixes: Mir.Inst.Fixes = if (elem_ty.isRuntimeFloat()) |
| 17756 | switch (elem_ty.floatBits(self.target.*)) { |
| 17757 | 16, 80, 128 => .p_, |
| 17758 | 32 => ._ps, |
| 17759 | 64 => ._pd, |
| 17760 | else => unreachable, |
| 17761 | } |
| 17762 | else |
| 17763 | .p_; |
| 17764 | try self.asmRegisterRegister(.{ mir_fixes, .@"and" }, dst_alias, mask_alias); |
| 17765 | if (lhs_mcv.isMemory()) try self.asmRegisterMemory( |
| 17766 | .{ mir_fixes, .andn }, |
| 17767 | mask_alias, |
| 17768 | try lhs_mcv.mem(self, Memory.Size.fromSize(dst_abi_size)), |
| 17769 | ) else try self.asmRegisterRegister( |
| 17770 | .{ mir_fixes, .andn }, |
| 17771 | mask_alias, |
| 17772 | if (lhs_mcv.isRegister()) |
| 17773 | lhs_mcv.getReg().? |
| 17774 | else |
| 17775 | try self.copyToTmpRegister(dst_ty, lhs_mcv), |
| 17776 | ); |
| 17777 | try self.asmRegisterRegister(.{ mir_fixes, .@"or" }, dst_alias, mask_alias); |
| 17778 | break :result dst_mcv; |
| 17779 | } |
| 17780 | |
| 17781 | pshufb: { |
| 17782 | if (max_abi_size > 16) break :pshufb; |
| 17783 | if (!self.hasFeature(.ssse3)) break :pshufb; |
| 17784 | |
| 17785 | const temp_regs = |
| 17786 | try self.register_manager.allocRegs(2, .{ inst, null }, abi.RegisterClass.sse); |
| 17787 | const temp_locks = self.register_manager.lockRegsAssumeUnused(2, temp_regs); |
| 17788 | defer for (temp_locks) |lock| self.register_manager.unlockReg(lock); |
| 17789 | |
| 17790 | const lhs_temp_alias = registerAlias(temp_regs[0], max_abi_size); |
| 17791 | try self.genSetReg(temp_regs[0], lhs_ty, .{ .air_ref = extra.a }, .{}); |
| 17792 | |
| 17793 | const rhs_temp_alias = registerAlias(temp_regs[1], max_abi_size); |
| 17794 | try self.genSetReg(temp_regs[1], rhs_ty, .{ .air_ref = extra.b }, .{}); |
| 17795 | |
| 17796 | var lhs_mask_elems: [16]InternPool.Index = undefined; |
| 17797 | for (lhs_mask_elems[0..max_abi_size], 0..) |*lhs_mask_elem, byte_index| { |
| 17798 | const elem_index = byte_index / elem_abi_size; |
| 17799 | lhs_mask_elem.* = try mod.intern(.{ .int = .{ |
| 17800 | .ty = .u8_type, |
| 17801 | .storage = .{ .u64 = if (elem_index >= mask_elems.len) 0b1_00_00000 else elem: { |
| 17802 | const mask_elem = mask_elems[elem_index] orelse break :elem 0b1_00_00000; |
| 17803 | if (mask_elem < 0) break :elem 0b1_00_00000; |
| 17804 | const mask_elem_index: u31 = @intCast(mask_elem); |
| 17805 | const byte_off: u32 = @intCast(byte_index % elem_abi_size); |
| 17806 | break :elem @intCast(mask_elem_index * elem_abi_size + byte_off); |
| 17807 | } }, |
| 17808 | } }); |
| 17809 | } |
| 17810 | const lhs_mask_ty = try mod.vectorType(.{ .len = max_abi_size, .child = .u8_type }); |
| 17811 | const lhs_mask_mcv = try self.genTypedValue(.{ |
| 17812 | .ty = lhs_mask_ty, |
| 17813 | .val = Value.fromInterned(try mod.intern(.{ .aggregate = .{ |
| 17814 | .ty = lhs_mask_ty.toIntern(), |
| 17815 | .storage = .{ .elems = lhs_mask_elems[0..max_abi_size] }, |
| 17816 | } })), |
| 17817 | }); |
| 17818 | const lhs_mask_mem: Memory = .{ |
| 17819 | .base = .{ .reg = try self.copyToTmpRegister(Type.usize, lhs_mask_mcv.address()) }, |
| 17820 | .mod = .{ .rm = .{ .size = Memory.Size.fromSize(@max(max_abi_size, 16)) } }, |
| 17821 | }; |
| 17822 | if (has_avx) try self.asmRegisterRegisterMemory( |
| 17823 | .{ .vp_b, .shuf }, |
| 17824 | lhs_temp_alias, |
| 17825 | lhs_temp_alias, |
| 17826 | lhs_mask_mem, |
| 17827 | ) else try self.asmRegisterMemory( |
| 17828 | .{ .p_b, .shuf }, |
| 17829 | lhs_temp_alias, |
| 17830 | lhs_mask_mem, |
| 17831 | ); |
| 17832 | |
| 17833 | var rhs_mask_elems: [16]InternPool.Index = undefined; |
| 17834 | for (rhs_mask_elems[0..max_abi_size], 0..) |*rhs_mask_elem, byte_index| { |
| 17835 | const elem_index = byte_index / elem_abi_size; |
| 17836 | rhs_mask_elem.* = try mod.intern(.{ .int = .{ |
| 17837 | .ty = .u8_type, |
| 17838 | .storage = .{ .u64 = if (elem_index >= mask_elems.len) 0b1_00_00000 else elem: { |
| 17839 | const mask_elem = mask_elems[elem_index] orelse break :elem 0b1_00_00000; |
| 17840 | if (mask_elem >= 0) break :elem 0b1_00_00000; |
| 17841 | const mask_elem_index: u31 = @intCast(~mask_elem); |
| 17842 | const byte_off: u32 = @intCast(byte_index % elem_abi_size); |
| 17843 | break :elem @intCast(mask_elem_index * elem_abi_size + byte_off); |
| 17844 | } }, |
| 17845 | } }); |
| 17846 | } |
| 17847 | const rhs_mask_ty = try mod.vectorType(.{ .len = max_abi_size, .child = .u8_type }); |
| 17848 | const rhs_mask_mcv = try self.genTypedValue(.{ |
| 17849 | .ty = rhs_mask_ty, |
| 17850 | .val = Value.fromInterned(try mod.intern(.{ .aggregate = .{ |
| 17851 | .ty = rhs_mask_ty.toIntern(), |
| 17852 | .storage = .{ .elems = rhs_mask_elems[0..max_abi_size] }, |
| 17853 | } })), |
| 17854 | }); |
| 17855 | const rhs_mask_mem: Memory = .{ |
| 17856 | .base = .{ .reg = try self.copyToTmpRegister(Type.usize, rhs_mask_mcv.address()) }, |
| 17857 | .mod = .{ .rm = .{ .size = Memory.Size.fromSize(@max(max_abi_size, 16)) } }, |
| 17858 | }; |
| 17859 | if (has_avx) try self.asmRegisterRegisterMemory( |
| 17860 | .{ .vp_b, .shuf }, |
| 17861 | rhs_temp_alias, |
| 17862 | rhs_temp_alias, |
| 17863 | rhs_mask_mem, |
| 17864 | ) else try self.asmRegisterMemory( |
| 17865 | .{ .p_b, .shuf }, |
| 17866 | rhs_temp_alias, |
| 17867 | rhs_mask_mem, |
| 17868 | ); |
| 17869 | |
| 17870 | if (has_avx) try self.asmRegisterRegisterRegister( |
| 17871 | .{ switch (elem_ty.zigTypeTag(mod)) { |
| 17872 | else => break :result null, |
| 17873 | .Int => .vp_, |
| 17874 | .Float => switch (elem_ty.floatBits(self.target.*)) { |
| 17875 | 32 => .v_ps, |
| 17876 | 64 => .v_pd, |
| 17877 | 16, 80, 128 => break :result null, |
| 17878 | else => unreachable, |
| 17879 | }, |
| 17880 | }, .@"or" }, |
| 17881 | lhs_temp_alias, |
| 17882 | lhs_temp_alias, |
| 17883 | rhs_temp_alias, |
| 17884 | ) else try self.asmRegisterRegister( |
| 17885 | .{ switch (elem_ty.zigTypeTag(mod)) { |
| 17886 | else => break :result null, |
| 17887 | .Int => .p_, |
| 17888 | .Float => switch (elem_ty.floatBits(self.target.*)) { |
| 17889 | 32 => ._ps, |
| 17890 | 64 => ._pd, |
| 17891 | 16, 80, 128 => break :result null, |
| 17892 | else => unreachable, |
| 17893 | }, |
| 17894 | }, .@"or" }, |
| 17895 | lhs_temp_alias, |
| 17896 | rhs_temp_alias, |
| 17897 | ); |
| 17898 | break :result .{ .register = temp_regs[0] }; |
| 17899 | } |
| 17900 | |
| 17901 | break :result null; |
| 17902 | }) orelse return self.fail("TODO implement airShuffle from {} and {} to {} with {}", .{ |
| 17903 | lhs_ty.fmt(mod), rhs_ty.fmt(mod), dst_ty.fmt(mod), |
| 17904 | Value.fromInterned(extra.mask).fmtValue( |
| 17905 | Type.fromInterned(mod.intern_pool.typeOf(extra.mask)), |
| 17906 | mod, |
| 17907 | ), |
| 17908 | }); |
| 17909 | return self.finishAir(inst, result, .{ extra.a, extra.b, .none }); |
| 16578 | 17910 | } |
| 16579 | 17911 | |
| 16580 | 17912 | fn airReduce(self: *Self, inst: Air.Inst.Index) !void { |
| ... | ... | @@ -16751,7 +18083,7 @@ fn airAggregateInit(self: *Self, inst: Air.Inst.Index) !void { |
| 16751 | 18083 | }, |
| 16752 | 18084 | .Array, .Vector => { |
| 16753 | 18085 | const elem_ty = result_ty.childType(mod); |
| 16754 | | if (result_ty.isVector(mod) and elem_ty.bitSize(mod) == 1) { |
| 18086 | if (result_ty.isVector(mod) and elem_ty.toIntern() == .bool_type) { |
| 16755 | 18087 | const result_size: u32 = @intCast(result_ty.abiSize(mod)); |
| 16756 | 18088 | const dst_reg = try self.register_manager.allocReg(inst, abi.RegisterClass.gp); |
| 16757 | 18089 | try self.asmRegisterRegister( |
| ... | ... | @@ -17801,7 +19133,7 @@ fn splitType(self: *Self, ty: Type) ![2]Type { |
| 17801 | 19133 | else => unreachable, |
| 17802 | 19134 | }, |
| 17803 | 19135 | .float => Type.f32, |
| 17804 | | .float_combine => try mod.vectorType(.{ .len = 2, .child = .f32_type }), |
| 19136 | .float_combine => try mod.arrayType(.{ .len = 2, .child = .f32_type }), |
| 17805 | 19137 | .sse => Type.f64, |
| 17806 | 19138 | else => break, |
| 17807 | 19139 | }; |