authorgravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2024-12-01 23:53:22-05:00
committergravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2025-01-16 20:42:08-05:00
logc4b93555b0d2c56cbbd85f77bb387ebb43d23369
treeb5e37f48f0c4e88f9a23c5ad123c8f872305f746
parent7c713251cadf831fb2009ae8908b099f218cf42c

x86_64: testing


12 files changed, 2408 insertions(+), 960 deletions(-)

src/Air.zig+5-5
......@@ -1229,7 +1229,7 @@ pub const VectorCmp = struct {
12291229 op: u32,
12301230
12311231 pub fn compareOperator(self: VectorCmp) std.math.CompareOperator {
1232 return @as(std.math.CompareOperator, @enumFromInt(@as(u3, @truncate(self.op))));
1232 return @enumFromInt(@as(u3, @intCast(self.op)));
12331233 }
12341234
12351235 pub fn encodeOp(compare_operator: std.math.CompareOperator) u32 {
......@@ -1274,11 +1274,11 @@ pub const Cmpxchg = struct {
12741274 flags: u32,
12751275
12761276 pub fn successOrder(self: Cmpxchg) std.builtin.AtomicOrder {
1277 return @as(std.builtin.AtomicOrder, @enumFromInt(@as(u3, @truncate(self.flags))));
1277 return @enumFromInt(@as(u3, @truncate(self.flags)));
12781278 }
12791279
12801280 pub fn failureOrder(self: Cmpxchg) std.builtin.AtomicOrder {
1281 return @as(std.builtin.AtomicOrder, @enumFromInt(@as(u3, @truncate(self.flags >> 3))));
1281 return @enumFromInt(@as(u3, @intCast(self.flags >> 3)));
12821282 }
12831283};
12841284
......@@ -1289,11 +1289,11 @@ pub const AtomicRmw = struct {
12891289 flags: u32,
12901290
12911291 pub fn ordering(self: AtomicRmw) std.builtin.AtomicOrder {
1292 return @as(std.builtin.AtomicOrder, @enumFromInt(@as(u3, @truncate(self.flags))));
1292 return @enumFromInt(@as(u3, @truncate(self.flags)));
12931293 }
12941294
12951295 pub fn op(self: AtomicRmw) std.builtin.AtomicRmwOp {
1296 return @as(std.builtin.AtomicRmwOp, @enumFromInt(@as(u4, @truncate(self.flags >> 3))));
1296 return @enumFromInt(@as(u4, @intCast(self.flags >> 3)));
12971297 }
12981298};
12991299
src/arch/x86_64/CodeGen.zig+2105-934
......@@ -135,6 +135,8 @@ const Owner = union(enum) {
135135 }
136136};
137137
138const MaskKind = enum { sign, all };
139
138140pub const MCValue = union(enum) {
139141 /// No runtime bits. `void` types, empty structs, u0, enums with 1 tag, etc.
140142 /// TODO Look into deleting this tag and using `dead` instead, since every use
......@@ -156,10 +158,16 @@ pub const MCValue = union(enum) {
156158 register: Register,
157159 /// The value is split across two registers.
158160 register_pair: [2]Register,
161 /// The value is split across three registers.
162 register_triple: [3]Register,
163 /// The value is split across four registers.
164 register_quadruple: [4]Register,
159165 /// The value is a constant offset from the value in a register.
160166 register_offset: bits.RegisterOffset,
161167 /// The value is a tuple { wrapped, overflow } where wrapped value is stored in the GP register.
162168 register_overflow: struct { reg: Register, eflags: Condition },
169 /// The value is a bool vector stored in a vector register with a different scalar type.
170 register_mask: struct { reg: Register, kind: MaskKind, inverted: bool, scalar: Memory.Size },
163171 /// The value is in memory at a hard-coded address.
164172 /// If the type is a pointer, it means the pointer address is stored at this memory location.
165173 memory: u64,
......@@ -195,7 +203,7 @@ pub const MCValue = union(enum) {
195203 /// Payload is a frame address.
196204 lea_frame: bits.FrameAddr,
197205 /// Supports integer_per_element abi
198 elementwise_regs_then_frame: packed struct { regs: u3 = 0, frame_off: i29 = 0, frame_index: FrameIndex },
206 elementwise_regs_then_frame: packed struct { regs: u3, frame_off: i29, frame_index: FrameIndex },
199207 /// This indicates that we have already allocated a frame index for this instruction,
200208 /// but it has not been spilled there yet in the current control flow.
201209 /// Payload is a frame index.
......@@ -210,6 +218,7 @@ pub const MCValue = union(enum) {
210218 .undef,
211219 .immediate,
212220 .register_offset,
221 .register_mask,
213222 .eflags,
214223 .register_overflow,
215224 .lea_symbol,
......@@ -223,6 +232,8 @@ pub const MCValue = union(enum) {
223232 => false,
224233 .register,
225234 .register_pair,
235 .register_triple,
236 .register_quadruple,
226237 .memory,
227238 .load_symbol,
228239 .load_got,
......@@ -234,13 +245,20 @@ pub const MCValue = union(enum) {
234245 };
235246 }
236247
237 fn isMemory(mcv: MCValue) bool {
248 fn isBase(mcv: MCValue) bool {
238249 return switch (mcv) {
239250 .memory, .indirect, .load_frame => true,
240251 else => false,
241252 };
242253 }
243254
255 fn isMemory(mcv: MCValue) bool {
256 return switch (mcv) {
257 .memory, .indirect, .load_frame, .load_symbol => true,
258 else => false,
259 };
260 }
261
244262 fn isImmediate(mcv: MCValue) bool {
245263 return switch (mcv) {
246264 .immediate => true,
......@@ -268,16 +286,23 @@ pub const MCValue = union(enum) {
268286 .register => |reg| reg,
269287 .register_offset, .indirect => |ro| ro.reg,
270288 .register_overflow => |ro| ro.reg,
289 .register_mask => |rm| rm.reg,
271290 else => null,
272291 };
273292 }
274293
275294 fn getRegs(mcv: *const MCValue) []const Register {
276295 return switch (mcv.*) {
277 .register => |*reg| @as(*const [1]Register, reg),
278 .register_pair => |*regs| regs,
279 .register_offset, .indirect => |*ro| @as(*const [1]Register, &ro.reg),
280 .register_overflow => |*ro| @as(*const [1]Register, &ro.reg),
296 .register => |*reg| reg[0..1],
297 inline .register_pair,
298 .register_triple,
299 .register_quadruple,
300 => |*regs| regs,
301 inline .register_offset,
302 .indirect,
303 .register_overflow,
304 .register_mask,
305 => |*pl| (&pl.reg)[0..1],
281306 else => &.{},
282307 };
283308 }
......@@ -300,8 +325,11 @@ pub const MCValue = union(enum) {
300325 .eflags,
301326 .register,
302327 .register_pair,
328 .register_triple,
329 .register_quadruple,
303330 .register_offset,
304331 .register_overflow,
332 .register_mask,
305333 .lea_symbol,
306334 .lea_direct,
307335 .lea_got,
......@@ -332,7 +360,10 @@ pub const MCValue = union(enum) {
332360 .undef,
333361 .eflags,
334362 .register_pair,
363 .register_triple,
364 .register_quadruple,
335365 .register_overflow,
366 .register_mask,
336367 .memory,
337368 .indirect,
338369 .load_direct,
......@@ -367,7 +398,10 @@ pub const MCValue = union(enum) {
367398 => unreachable, // not valid
368399 .eflags,
369400 .register_pair,
401 .register_triple,
402 .register_quadruple,
370403 .register_overflow,
404 .register_mask,
371405 .memory,
372406 .indirect,
373407 .load_direct,
......@@ -404,8 +438,11 @@ pub const MCValue = union(enum) {
404438 .eflags,
405439 .register,
406440 .register_pair,
441 .register_triple,
442 .register_quadruple,
407443 .register_offset,
408444 .register_overflow,
445 .register_mask,
409446 .load_direct,
410447 .lea_direct,
411448 .load_got,
......@@ -472,10 +509,11 @@ pub const MCValue = union(enum) {
472509 .memory => |pl| try writer.print("[ds:0x{x}]", .{pl}),
473510 inline .eflags, .register => |pl| try writer.print("{s}", .{@tagName(pl)}),
474511 .register_pair => |pl| try writer.print("{s}:{s}", .{ @tagName(pl[1]), @tagName(pl[0]) }),
512 .register_triple => |pl| try writer.print("{s}:{s}:{s}", .{ @tagName(pl[2]), @tagName(pl[1]), @tagName(pl[0]) }),
513 .register_quadruple => |pl| try writer.print("{s}:{s}:{s}:{s}", .{ @tagName(pl[3]), @tagName(pl[2]), @tagName(pl[1]), @tagName(pl[0]) }),
475514 .register_offset => |pl| try writer.print("{s} + 0x{x}", .{ @tagName(pl.reg), pl.off }),
476 .register_overflow => |pl| try writer.print("{s}:{s}", .{
477 @tagName(pl.eflags), @tagName(pl.reg),
478 }),
515 .register_overflow => |pl| try writer.print("{s}:{s}", .{ @tagName(pl.eflags), @tagName(pl.reg) }),
516 .register_mask => |pl| try writer.print("mask({s},{}):{s}", .{ @tagName(pl.kind), pl.scalar, @tagName(pl.reg) }),
479517 .load_symbol => |pl| try writer.print("[sym:{} + 0x{x}]", .{ pl.sym_index, pl.off }),
480518 .lea_symbol => |pl| try writer.print("sym:{} + 0x{x}", .{ pl.sym_index, pl.off }),
481519 .indirect => |pl| try writer.print("[{s} + 0x{x}]", .{ @tagName(pl.reg), pl.off }),
......@@ -526,8 +564,11 @@ const InstTracking = struct {
526564 .eflags,
527565 .register,
528566 .register_pair,
567 .register_triple,
568 .register_quadruple,
529569 .register_offset,
530570 .register_overflow,
571 .register_mask,
531572 .indirect,
532573 => .none,
533574 }, .short = result };
......@@ -545,17 +586,17 @@ const InstTracking = struct {
545586 return self.short.getCondition();
546587 }
547588
548 fn spill(self: *InstTracking, function: *CodeGen, inst: Air.Inst.Index) !void {
589 fn spill(self: *InstTracking, cg: *CodeGen, inst: Air.Inst.Index) !void {
549590 if (std.meta.eql(self.long, self.short)) return; // Already spilled
550591 // Allocate or reuse frame index
551592 switch (self.long) {
552 .none => self.long = try function.allocRegOrMem(inst, false),
593 .none => self.long = try cg.allocRegOrMem(inst, false),
553594 .load_frame => {},
554595 .reserved_frame => |index| self.long = .{ .load_frame = .{ .index = index } },
555596 else => unreachable,
556597 }
557598 tracking_log.debug("spill {} from {} to {}", .{ inst, self.short, self.long });
558 try function.genCopy(function.typeOfIndex(inst), self.long, self.short, .{});
599 try cg.genCopy(cg.typeOfIndex(inst), self.long, self.short, .{});
559600 }
560601
561602 fn reuseFrame(self: *InstTracking) void {
......@@ -584,8 +625,11 @@ const InstTracking = struct {
584625 .eflags,
585626 .register,
586627 .register_pair,
628 .register_triple,
629 .register_quadruple,
587630 .register_offset,
588631 .register_overflow,
632 .register_mask,
589633 .indirect,
590634 .elementwise_regs_then_frame,
591635 .reserved_frame,
......@@ -630,8 +674,11 @@ const InstTracking = struct {
630674 .eflags,
631675 .register,
632676 .register_pair,
677 .register_triple,
678 .register_quadruple,
633679 .register_offset,
634680 .register_overflow,
681 .register_mask,
635682 .indirect,
636683 .elementwise_regs_then_frame,
637684 .air_ref,
......@@ -735,13 +782,13 @@ const InstTracking = struct {
735782 }
736783
737784 pub fn format(
738 self: InstTracking,
785 tracking: InstTracking,
739786 comptime _: []const u8,
740787 _: std.fmt.FormatOptions,
741788 writer: anytype,
742789 ) @TypeOf(writer).Error!void {
743 if (!std.meta.eql(self.long, self.short)) try writer.print("|{}| ", .{self.long});
744 try writer.print("{}", .{self.short});
790 if (!std.meta.eql(tracking.long, tracking.short)) try writer.print("|{}| ", .{tracking.long});
791 try writer.print("{}", .{tracking.short});
745792 }
746793};
747794
......@@ -2259,44 +2306,44 @@ fn genBodyBlock(self: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
22592306 try self.asmPseudo(.pseudo_dbg_leave_block_none);
22602307}
22612308
2262fn genBody(self: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
2263 const pt = self.pt;
2309fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
2310 const pt = cg.pt;
22642311 const zcu = pt.zcu;
22652312 const ip = &zcu.intern_pool;
2266 const air_tags = self.air.instructions.items(.tag);
2267 const air_datas = self.air.instructions.items(.data);
2268 const use_old = self.target.ofmt == .coff;
2313 const air_tags = cg.air.instructions.items(.tag);
2314 const air_datas = cg.air.instructions.items(.data);
2315 const use_old = cg.target.ofmt == .coff;
22692316
2270 self.arg_index = 0;
2317 cg.arg_index = 0;
22712318 for (body) |inst| switch (air_tags[@intFromEnum(inst)]) {
22722319 .arg => {
2273 wip_mir_log.debug("{}", .{self.fmtAir(inst)});
2274 verbose_tracking_log.debug("{}", .{self.fmtTracking()});
2320 wip_mir_log.debug("{}", .{cg.fmtAir(inst)});
2321 verbose_tracking_log.debug("{}", .{cg.fmtTracking()});
22752322
2276 self.reused_operands = .initEmpty();
2277 try self.inst_tracking.ensureUnusedCapacity(self.gpa, 1);
2323 cg.reused_operands = .initEmpty();
2324 try cg.inst_tracking.ensureUnusedCapacity(cg.gpa, 1);
22782325
2279 try self.airArg(inst);
2326 try cg.airArg(inst);
22802327
2281 self.resetTemps();
2282 self.checkInvariantsAfterAirInst();
2328 cg.resetTemps();
2329 cg.checkInvariantsAfterAirInst();
22832330 },
22842331 else => break,
22852332 };
22862333
2287 if (self.arg_index == 0) try self.airDbgVarArgs();
2288 self.arg_index = 0;
2334 if (cg.arg_index == 0) try cg.airDbgVarArgs();
2335 cg.arg_index = 0;
22892336 for (body) |inst| {
2290 if (self.liveness.isUnused(inst) and !self.air.mustLower(inst, ip)) continue;
2291 wip_mir_log.debug("{}", .{self.fmtAir(inst)});
2292 verbose_tracking_log.debug("{}", .{self.fmtTracking()});
2337 if (cg.liveness.isUnused(inst) and !cg.air.mustLower(inst, ip)) continue;
2338 wip_mir_log.debug("{}", .{cg.fmtAir(inst)});
2339 verbose_tracking_log.debug("{}", .{cg.fmtTracking()});
22932340
2294 self.reused_operands = .initEmpty();
2295 try self.inst_tracking.ensureUnusedCapacity(self.gpa, 1);
2341 cg.reused_operands = .initEmpty();
2342 try cg.inst_tracking.ensureUnusedCapacity(cg.gpa, 1);
22962343 switch (air_tags[@intFromEnum(inst)]) {
22972344 // zig fmt: off
22982345 .not,
2299 => |tag| try self.airUnOp(inst, tag),
2346 => |air_tag| try cg.airUnOp(inst, air_tag),
23002347
23012348 .add,
23022349 .add_wrap,
......@@ -2306,22 +2353,22 @@ fn genBody(self: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
23062353 .bool_or,
23072354 .min,
23082355 .max,
2309 => |tag| try self.airBinOp(inst, tag),
2356 => |air_tag| try cg.airBinOp(inst, air_tag),
23102357
2311 .ptr_add, .ptr_sub => |tag| try self.airPtrArithmetic(inst, tag),
2358 .ptr_add, .ptr_sub => |air_tag| try cg.airPtrArithmetic(inst, air_tag),
23122359
2313 .shr, .shr_exact => try self.airShlShrBinOp(inst),
2314 .shl, .shl_exact => try self.airShlShrBinOp(inst),
2360 .shr, .shr_exact => try cg.airShlShrBinOp(inst),
2361 .shl, .shl_exact => try cg.airShlShrBinOp(inst),
23152362
2316 .mul => try self.airMulDivBinOp(inst),
2317 .mul_wrap => try self.airMulDivBinOp(inst),
2318 .rem => try self.airMulDivBinOp(inst),
2319 .mod => try self.airMulDivBinOp(inst),
2363 .mul => try cg.airMulDivBinOp(inst),
2364 .mul_wrap => try cg.airMulDivBinOp(inst),
2365 .rem => try cg.airMulDivBinOp(inst),
2366 .mod => try cg.airMulDivBinOp(inst),
23202367
2321 .add_sat => try self.airAddSat(inst),
2322 .sub_sat => try self.airSubSat(inst),
2323 .mul_sat => try self.airMulSat(inst),
2324 .shl_sat => try self.airShlSat(inst),
2368 .add_sat => try cg.airAddSat(inst),
2369 .sub_sat => try cg.airSubSat(inst),
2370 .mul_sat => try cg.airMulSat(inst),
2371 .shl_sat => try cg.airShlSat(inst),
23252372
23262373 .sin,
23272374 .cos,
......@@ -2332,98 +2379,97 @@ fn genBody(self: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
23322379 .log2,
23332380 .log10,
23342381 .round,
2335 => |tag| try self.airUnaryMath(inst, tag),
2336
2337 .floor => try self.airRound(inst, .{ .mode = .down, .precision = .inexact }),
2338 .ceil => try self.airRound(inst, .{ .mode = .up, .precision = .inexact }),
2339 .trunc_float => try self.airRound(inst, .{ .mode = .zero, .precision = .inexact }),
2340 .sqrt => try self.airSqrt(inst),
2341 .neg => try self.airFloatSign(inst),
2342
2343 .abs => try self.airAbs(inst),
2344
2345 .add_with_overflow => try self.airAddSubWithOverflow(inst),
2346 .sub_with_overflow => try self.airAddSubWithOverflow(inst),
2347 .mul_with_overflow => try self.airMulWithOverflow(inst),
2348 .shl_with_overflow => try self.airShlWithOverflow(inst),
2349
2350 .div_float, .div_trunc, .div_floor, .div_exact => try self.airMulDivBinOp(inst),
2351
2352 .cmp_lt => try self.airCmp(inst, .lt),
2353 .cmp_lte => try self.airCmp(inst, .lte),
2354 .cmp_eq => try self.airCmp(inst, .eq),
2355 .cmp_gte => try self.airCmp(inst, .gte),
2356 .cmp_gt => try self.airCmp(inst, .gt),
2357 .cmp_neq => try self.airCmp(inst, .neq),
2358
2359 .cmp_vector => try self.airCmpVector(inst),
2360 .cmp_lt_errors_len => try self.airCmpLtErrorsLen(inst),
2361
2362 .bitcast => try self.airBitCast(inst),
2363 .fptrunc => try self.airFptrunc(inst),
2364 .fpext => try self.airFpext(inst),
2365 .intcast => try self.airIntCast(inst),
2366 .trunc => try self.airTrunc(inst),
2367 .is_non_null => try self.airIsNonNull(inst),
2368 .is_null => try self.airIsNull(inst),
2369 .is_non_err => try self.airIsNonErr(inst),
2370 .is_err => try self.airIsErr(inst),
2371 .load => try self.airLoad(inst),
2372 .store => try self.airStore(inst, false),
2373 .store_safe => try self.airStore(inst, true),
2374 .struct_field_val => try self.airStructFieldVal(inst),
2375 .float_from_int => try self.airFloatFromInt(inst),
2376 .int_from_float => try self.airIntFromFloat(inst),
2377 .cmpxchg_strong => try self.airCmpxchg(inst),
2378 .cmpxchg_weak => try self.airCmpxchg(inst),
2379 .atomic_rmw => try self.airAtomicRmw(inst),
2380 .atomic_load => try self.airAtomicLoad(inst),
2381 .memcpy => try self.airMemcpy(inst),
2382 .memset => try self.airMemset(inst, false),
2383 .memset_safe => try self.airMemset(inst, true),
2384 .set_union_tag => try self.airSetUnionTag(inst),
2385 .get_union_tag => try self.airGetUnionTag(inst),
2386 .clz => try self.airClz(inst),
2387 .ctz => try self.airCtz(inst),
2388 .popcount => try self.airPopCount(inst),
2389 .byte_swap => try self.airByteSwap(inst),
2390 .bit_reverse => try self.airBitReverse(inst),
2391 .tag_name => try self.airTagName(inst),
2392 .error_name => try self.airErrorName(inst),
2393 .splat => try self.airSplat(inst),
2394 .select => try self.airSelect(inst),
2395 .shuffle => try self.airShuffle(inst),
2396 .reduce => try self.airReduce(inst),
2397 .aggregate_init => try self.airAggregateInit(inst),
2398 .union_init => try self.airUnionInit(inst),
2399 .prefetch => try self.airPrefetch(inst),
2400 .mul_add => try self.airMulAdd(inst),
2401
2402 .atomic_store_unordered => try self.airAtomicStore(inst, .unordered),
2403 .atomic_store_monotonic => try self.airAtomicStore(inst, .monotonic),
2404 .atomic_store_release => try self.airAtomicStore(inst, .release),
2405 .atomic_store_seq_cst => try self.airAtomicStore(inst, .seq_cst),
2406
2407 .array_elem_val => try self.airArrayElemVal(inst),
2408 .slice_elem_val => try self.airSliceElemVal(inst),
2409 .ptr_elem_val => try self.airPtrElemVal(inst),
2410
2411 .optional_payload => try self.airOptionalPayload(inst),
2412 .unwrap_errunion_err => try self.airUnwrapErrUnionErr(inst),
2413 .unwrap_errunion_payload => try self.airUnwrapErrUnionPayload(inst),
2414 .err_return_trace => try self.airErrReturnTrace(inst),
2415 .set_err_return_trace => try self.airSetErrReturnTrace(inst),
2416 .save_err_return_trace_index=> try self.airSaveErrReturnTraceIndex(inst),
2417
2418 .wrap_optional => try self.airWrapOptional(inst),
2419 .wrap_errunion_payload => try self.airWrapErrUnionPayload(inst),
2420 .wrap_errunion_err => try self.airWrapErrUnionErr(inst),
2382 => |air_tag| try cg.airUnaryMath(inst, air_tag),
2383
2384 .floor => try cg.airRound(inst, .{ .mode = .down, .precision = .inexact }),
2385 .ceil => try cg.airRound(inst, .{ .mode = .up, .precision = .inexact }),
2386 .trunc_float => try cg.airRound(inst, .{ .mode = .zero, .precision = .inexact }),
2387 .sqrt => try cg.airSqrt(inst),
2388 .neg => try cg.airFloatSign(inst),
2389
2390 .abs => try cg.airAbs(inst),
2391
2392 .add_with_overflow => try cg.airAddSubWithOverflow(inst),
2393 .sub_with_overflow => try cg.airAddSubWithOverflow(inst),
2394 .mul_with_overflow => try cg.airMulWithOverflow(inst),
2395 .shl_with_overflow => try cg.airShlWithOverflow(inst),
2396
2397 .div_float, .div_trunc, .div_floor, .div_exact => try cg.airMulDivBinOp(inst),
2398
2399 .cmp_lt => try cg.airCmp(inst, .lt),
2400 .cmp_lte => try cg.airCmp(inst, .lte),
2401 .cmp_eq => try cg.airCmp(inst, .eq),
2402 .cmp_gte => try cg.airCmp(inst, .gte),
2403 .cmp_gt => try cg.airCmp(inst, .gt),
2404 .cmp_neq => try cg.airCmp(inst, .neq),
2405
2406 .cmp_lt_errors_len => try cg.airCmpLtErrorsLen(inst),
2407
2408 .bitcast => try cg.airBitCast(inst),
2409 .fptrunc => try cg.airFptrunc(inst),
2410 .fpext => try cg.airFpext(inst),
2411 .intcast => try cg.airIntCast(inst),
2412 .trunc => try cg.airTrunc(inst),
2413 .is_non_null => try cg.airIsNonNull(inst),
2414 .is_null => try cg.airIsNull(inst),
2415 .is_non_err => try cg.airIsNonErr(inst),
2416 .is_err => try cg.airIsErr(inst),
2417 .load => try cg.airLoad(inst),
2418 .store => try cg.airStore(inst, false),
2419 .store_safe => try cg.airStore(inst, true),
2420 .struct_field_val => try cg.airStructFieldVal(inst),
2421 .float_from_int => try cg.airFloatFromInt(inst),
2422 .int_from_float => try cg.airIntFromFloat(inst),
2423 .cmpxchg_strong => try cg.airCmpxchg(inst),
2424 .cmpxchg_weak => try cg.airCmpxchg(inst),
2425 .atomic_rmw => try cg.airAtomicRmw(inst),
2426 .atomic_load => try cg.airAtomicLoad(inst),
2427 .memcpy => try cg.airMemcpy(inst),
2428 .memset => try cg.airMemset(inst, false),
2429 .memset_safe => try cg.airMemset(inst, true),
2430 .set_union_tag => try cg.airSetUnionTag(inst),
2431 .get_union_tag => try cg.airGetUnionTag(inst),
2432 .clz => try cg.airClz(inst),
2433 .ctz => try cg.airCtz(inst),
2434 .popcount => try cg.airPopCount(inst),
2435 .byte_swap => try cg.airByteSwap(inst),
2436 .bit_reverse => try cg.airBitReverse(inst),
2437 .tag_name => try cg.airTagName(inst),
2438 .error_name => try cg.airErrorName(inst),
2439 .splat => try cg.airSplat(inst),
2440 .select => try cg.airSelect(inst),
2441 .shuffle => try cg.airShuffle(inst),
2442 .reduce => try cg.airReduce(inst),
2443 .aggregate_init => try cg.airAggregateInit(inst),
2444 .union_init => try cg.airUnionInit(inst),
2445 .prefetch => try cg.airPrefetch(inst),
2446 .mul_add => try cg.airMulAdd(inst),
2447
2448 .atomic_store_unordered => try cg.airAtomicStore(inst, .unordered),
2449 .atomic_store_monotonic => try cg.airAtomicStore(inst, .monotonic),
2450 .atomic_store_release => try cg.airAtomicStore(inst, .release),
2451 .atomic_store_seq_cst => try cg.airAtomicStore(inst, .seq_cst),
2452
2453 .array_elem_val => try cg.airArrayElemVal(inst),
2454 .slice_elem_val => try cg.airSliceElemVal(inst),
2455 .ptr_elem_val => try cg.airPtrElemVal(inst),
2456
2457 .optional_payload => try cg.airOptionalPayload(inst),
2458 .unwrap_errunion_err => try cg.airUnwrapErrUnionErr(inst),
2459 .unwrap_errunion_payload => try cg.airUnwrapErrUnionPayload(inst),
2460 .err_return_trace => try cg.airErrReturnTrace(inst),
2461 .set_err_return_trace => try cg.airSetErrReturnTrace(inst),
2462 .save_err_return_trace_index=> try cg.airSaveErrReturnTraceIndex(inst),
2463
2464 .wrap_optional => try cg.airWrapOptional(inst),
2465 .wrap_errunion_payload => try cg.airWrapErrUnionPayload(inst),
2466 .wrap_errunion_err => try cg.airWrapErrUnionErr(inst),
24212467 // zig fmt: on
24222468
24232469 .add_safe,
24242470 .sub_safe,
24252471 .mul_safe,
2426 => return self.fail("TODO implement safety_checked_instructions", .{}),
2472 => return cg.fail("TODO implement safety_checked_instructions", .{}),
24272473 .add_optimized,
24282474 .sub_optimized,
24292475 .mul_optimized,
......@@ -2440,214 +2486,612 @@ fn genBody(self: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
24402486 .cmp_gte_optimized,
24412487 .cmp_gt_optimized,
24422488 .cmp_neq_optimized,
2443 .cmp_vector_optimized,
24442489 .reduce_optimized,
24452490 .int_from_float_optimized,
2446 => return self.fail("TODO implement optimized float mode", .{}),
2491 => return cg.fail("TODO implement optimized float mode", .{}),
24472492
2448 .arg => try self.airDbgArg(inst),
2449 .alloc => if (use_old) try self.airAlloc(inst) else {
2450 var slot = try self.tempFromValue(self.typeOfIndex(inst), .{ .lea_frame = .{
2451 .index = try self.allocMemPtr(inst),
2493 .arg => try cg.airDbgArg(inst),
2494 .alloc => if (use_old) try cg.airAlloc(inst) else {
2495 var slot = try cg.tempFromValue(cg.typeOfIndex(inst), .{ .lea_frame = .{
2496 .index = try cg.allocMemPtr(inst),
24522497 } });
2453 try slot.moveTo(inst, self);
2498 try slot.moveTo(inst, cg);
24542499 },
24552500 .inferred_alloc => unreachable,
24562501 .inferred_alloc_comptime => unreachable,
2457 .ret_ptr => if (use_old) try self.airRetPtr(inst) else {
2458 var slot = switch (self.ret_mcv.long) {
2502 .ret_ptr => if (use_old) try cg.airRetPtr(inst) else {
2503 var slot = switch (cg.ret_mcv.long) {
24592504 else => unreachable,
2460 .none => try self.tempFromValue(self.typeOfIndex(inst), .{ .lea_frame = .{
2461 .index = try self.allocMemPtr(inst),
2505 .none => try cg.tempFromValue(cg.typeOfIndex(inst), .{ .lea_frame = .{
2506 .index = try cg.allocMemPtr(inst),
24622507 } }),
24632508 .load_frame => slot: {
2464 var slot = try self.tempFromValue(self.typeOfIndex(inst), self.ret_mcv.long);
2465 try slot.toOffset(self.ret_mcv.short.indirect.off, self);
2509 var slot = try cg.tempFromValue(cg.typeOfIndex(inst), cg.ret_mcv.long);
2510 try slot.toOffset(cg.ret_mcv.short.indirect.off, cg);
24662511 break :slot slot;
24672512 },
24682513 };
2469 try slot.moveTo(inst, self);
2514 try slot.moveTo(inst, cg);
24702515 },
2471 .assembly => try self.airAsm(inst),
2472 inline .bit_and, .bit_or, .xor => |tag| if (use_old) try self.airBinOp(inst, tag) else {
2516 .assembly => try cg.airAsm(inst),
2517 .bit_and, .bit_or, .xor => |air_tag| if (use_old) try cg.airBinOp(inst, air_tag) else {
24732518 const bin_op = air_datas[@intFromEnum(inst)].bin_op;
2474 var ops = try self.tempsFromOperands(inst, .{ bin_op.lhs, bin_op.rhs });
2475 try self.spillEflagsIfOccupied();
2476 const mir_tag: Mir.Inst.Tag = switch (tag) {
2477 else => unreachable,
2478 .bit_and => .@"and",
2479 .bit_or => .@"or",
2480 .xor => .xor,
2481 };
2519 var ops = try cg.tempsFromOperands(inst, .{ bin_op.lhs, bin_op.rhs });
24822520 var res: [1]Temp = undefined;
2483 try self.select(&res, &.{ &ops[0], &ops[1] }, &.{
2484 .{
2485 .required_features = &.{.avx2},
2486 .mir_tag = .{ .vp_, mir_tag },
2487 .patterns = &.{
2488 .{ .ops = &.{ .ymm, .ymm, .mem } },
2489 .{ .ops = &.{ .ymm, .mem, .ymm }, .commute = .{ 1, 2 } },
2490 .{ .ops = &.{ .ymm, .ymm, .ymm } },
2491 },
2492 },
2493 .{
2494 .required_features = &.{.avx},
2495 .mir_tag = .{ .vp_, mir_tag },
2496 .patterns = &.{
2497 .{ .ops = &.{ .xmm, .xmm, .mem } },
2498 .{ .ops = &.{ .xmm, .mem, .xmm }, .commute = .{ 1, 2 } },
2499 .{ .ops = &.{ .xmm, .xmm, .xmm } },
2500 },
2501 },
2502 .{
2503 .required_features = &.{.sse2},
2504 .mir_tag = .{ .p_, mir_tag },
2505 .patterns = &.{
2506 .{ .ops = &.{ .xmm, .{ .implicit = 0 }, .mem } },
2507 .{ .ops = &.{ .xmm, .mem, .{ .implicit = 0 } } },
2508 .{ .ops = &.{ .xmm, .{ .implicit = 0 }, .xmm } },
2509 .{ .ops = &.{ .xmm, .xmm, .{ .implicit = 0 } } },
2510 },
2511 },
2512 .{
2513 .required_features = &.{.mmx},
2514 .mir_tag = .{ .p_, mir_tag },
2515 .patterns = &.{
2516 .{ .ops = &.{ .mm, .{ .implicit = 0 }, .mem } },
2517 .{ .ops = &.{ .mm, .mem, .{ .implicit = 0 } } },
2518 .{ .ops = &.{ .mm, .{ .implicit = 0 }, .mm } },
2519 .{ .ops = &.{ .mm, .mm, .{ .implicit = 0 } } },
2520 },
2521 },
2522 .{
2523 .mir_tag = .{ ._, mir_tag },
2524 .patterns = &.{
2525 .{ .ops = &.{ .mem, .{ .implicit = 0 }, .simm32 } },
2526 .{ .ops = &.{ .mem, .simm32, .{ .implicit = 0 } } },
2527 .{ .ops = &.{ .mem, .{ .implicit = 0 }, .gpr } },
2528 .{ .ops = &.{ .mem, .gpr, .{ .implicit = 0 } } },
2529 .{ .ops = &.{ .gpr, .{ .implicit = 0 }, .simm32 } },
2530 .{ .ops = &.{ .gpr, .simm32, .{ .implicit = 0 } } },
2531 .{ .ops = &.{ .gpr, .{ .implicit = 0 }, .mem } },
2532 .{ .ops = &.{ .gpr, .mem, .{ .implicit = 0 } } },
2533 .{ .ops = &.{ .gpr, .{ .implicit = 0 }, .gpr } },
2534 .{ .ops = &.{ .gpr, .gpr, .{ .implicit = 0 } } },
2535 },
2536 },
2521 try cg.select(&res, &.{cg.typeOfIndex(inst)}, &ops, pattern_sets: switch (air_tag) {
2522 else => unreachable,
2523 inline .bit_and, .bit_or, .xor => |ct_air_tag| {
2524 const mir_tag: Mir.Inst.Tag = switch (ct_air_tag) {
2525 else => unreachable,
2526 .bit_and => .@"and",
2527 .bit_or => .@"or",
2528 .xor => .xor,
2529 };
2530 break :pattern_sets &.{
2531 .{
2532 .required_features = &.{.avx2},
2533 .mir_tag = .{ .vp_, mir_tag },
2534 .patterns = &.{
2535 .{ .ops = &.{ .ymm, .ymm, .mem } },
2536 .{ .ops = &.{ .ymm, .mem, .ymm }, .commute = .{ 1, 2 } },
2537 .{ .ops = &.{ .ymm, .ymm, .ymm } },
2538 },
2539 },
2540 .{
2541 .required_features = &.{.avx},
2542 .mir_tag = .{ .vp_, mir_tag },
2543 .patterns = &.{
2544 .{ .ops = &.{ .xmm, .xmm, .mem } },
2545 .{ .ops = &.{ .xmm, .mem, .xmm }, .commute = .{ 1, 2 } },
2546 .{ .ops = &.{ .xmm, .xmm, .xmm } },
2547 },
2548 },
2549 .{
2550 .required_features = &.{.sse2},
2551 .mir_tag = .{ .p_, mir_tag },
2552 .patterns = &.{
2553 .{ .ops = &.{ .xmm, .{ .implicit = 0 }, .mem } },
2554 .{ .ops = &.{ .xmm, .mem, .{ .implicit = 0 } } },
2555 .{ .ops = &.{ .xmm, .{ .implicit = 0 }, .xmm } },
2556 .{ .ops = &.{ .xmm, .xmm, .{ .implicit = 0 } } },
2557 },
2558 },
2559 .{
2560 .required_features = &.{.mmx},
2561 .mir_tag = .{ .p_, mir_tag },
2562 .patterns = &.{
2563 .{ .ops = &.{ .mm, .{ .implicit = 0 }, .mem } },
2564 .{ .ops = &.{ .mm, .mem, .{ .implicit = 0 } } },
2565 .{ .ops = &.{ .mm, .{ .implicit = 0 }, .mm } },
2566 .{ .ops = &.{ .mm, .mm, .{ .implicit = 0 } } },
2567 },
2568 },
2569 .{
2570 .clobbers = .{ .eflags = true },
2571 .mir_tag = .{ ._, mir_tag },
2572 .patterns = &.{
2573 .{ .ops = &.{ .mem, .{ .implicit = 0 }, .simm32 } },
2574 .{ .ops = &.{ .mem, .simm32, .{ .implicit = 0 } } },
2575 .{ .ops = &.{ .mem, .{ .implicit = 0 }, .gpr } },
2576 .{ .ops = &.{ .mem, .gpr, .{ .implicit = 0 } } },
2577 .{ .ops = &.{ .gpr, .{ .implicit = 0 }, .simm32 } },
2578 .{ .ops = &.{ .gpr, .simm32, .{ .implicit = 0 } } },
2579 .{ .ops = &.{ .gpr, .{ .implicit = 0 }, .mem } },
2580 .{ .ops = &.{ .gpr, .mem, .{ .implicit = 0 } } },
2581 .{ .ops = &.{ .gpr, .{ .implicit = 0 }, .gpr } },
2582 .{ .ops = &.{ .gpr, .gpr, .{ .implicit = 0 } } },
2583 },
2584 },
25372585
2538 .{
2539 .required_features = &.{.avx2},
2540 .loop = .bitwise,
2541 .mir_tag = .{ .vp_, mir_tag },
2542 .patterns = &.{
2543 .{ .ops = &.{ .ymm_limb, .{ .explicit = 0 }, .mem_limb } },
2544 .{ .ops = &.{ .ymm_limb, .mem_limb, .{ .explicit = 0 } }, .commute = .{ 1, 2 } },
2545 .{ .ops = &.{ .ymm_limb, .ymm_limb, .mem_limb } },
2546 },
2547 },
2548 .{
2549 .required_features = &.{.avx},
2550 .loop = .bitwise,
2551 .mir_tag = .{ .vp_, mir_tag },
2552 .patterns = &.{
2553 .{ .ops = &.{ .xmm_limb, .{ .explicit = 0 }, .mem_limb } },
2554 .{ .ops = &.{ .xmm_limb, .mem_limb, .{ .explicit = 0 } }, .commute = .{ 1, 2 } },
2555 .{ .ops = &.{ .xmm_limb, .xmm_limb, .mem_limb } },
2556 },
2557 },
2558 .{
2559 .required_features = &.{.sse2},
2560 .loop = .bitwise,
2561 .mir_tag = .{ .p_, mir_tag },
2562 .patterns = &.{
2563 .{ .ops = &.{ .xmm_limb, .{ .implicit = 0 }, .mem_limb } },
2564 .{ .ops = &.{ .xmm_limb, .mem_limb, .{ .implicit = 0 } } },
2565 },
2566 },
2567 .{
2568 .required_features = &.{.mmx},
2569 .loop = .bitwise,
2570 .mir_tag = .{ .p_, mir_tag },
2571 .patterns = &.{
2572 .{ .ops = &.{ .mm_limb, .{ .implicit = 0 }, .mem_limb } },
2573 .{ .ops = &.{ .mm_limb, .mem_limb, .{ .implicit = 0 } } },
2574 },
2575 },
2576 .{
2577 .loop = .bitwise,
2578 .mir_tag = .{ ._, mir_tag },
2579 .patterns = &.{
2580 .{ .ops = &.{ .mem_limb, .{ .implicit = 0 }, .gpr_limb } },
2581 .{ .ops = &.{ .mem_limb, .gpr_limb, .{ .implicit = 0 } } },
2582 .{ .ops = &.{ .gpr_limb, .{ .implicit = 0 }, .mem_limb } },
2583 .{ .ops = &.{ .gpr_limb, .mem_limb, .{ .implicit = 0 } } },
2584 .{ .ops = &.{ .gpr_limb, .{ .implicit = 0 }, .gpr_limb } },
2585 },
2586 .{
2587 .required_features = &.{.avx2},
2588 .loop = .bitwise,
2589 .mir_tag = .{ .vp_, mir_tag },
2590 .patterns = &.{
2591 .{ .ops = &.{ .ymm_limb, .{ .explicit = 0 }, .mem_limb } },
2592 .{ .ops = &.{ .ymm_limb, .mem_limb, .{ .explicit = 0 } }, .commute = .{ 1, 2 } },
2593 .{ .ops = &.{ .ymm_limb, .ymm_limb, .mem_limb } },
2594 .{ .ops = &.{ .ymm_limb, .ymm_limb, .ymm_limb } },
2595 },
2596 },
2597 .{
2598 .required_features = &.{.avx},
2599 .loop = .bitwise,
2600 .mir_tag = .{ .vp_, mir_tag },
2601 .patterns = &.{
2602 .{ .ops = &.{ .xmm_limb, .{ .explicit = 0 }, .mem_limb } },
2603 .{ .ops = &.{ .xmm_limb, .mem_limb, .{ .explicit = 0 } }, .commute = .{ 1, 2 } },
2604 .{ .ops = &.{ .xmm_limb, .xmm_limb, .mem_limb } },
2605 .{ .ops = &.{ .xmm_limb, .xmm_limb, .xmm_limb } },
2606 },
2607 },
2608 .{
2609 .required_features = &.{.sse2},
2610 .loop = .bitwise,
2611 .mir_tag = .{ .p_, mir_tag },
2612 .patterns = &.{
2613 .{ .ops = &.{ .xmm_limb, .{ .implicit = 0 }, .mem_limb } },
2614 .{ .ops = &.{ .xmm_limb, .mem_limb, .{ .implicit = 0 } } },
2615 .{ .ops = &.{ .xmm_limb, .{ .implicit = 0 }, .xmm_limb } },
2616 },
2617 },
2618 .{
2619 .required_features = &.{.mmx},
2620 .loop = .bitwise,
2621 .mir_tag = .{ .p_, mir_tag },
2622 .patterns = &.{
2623 .{ .ops = &.{ .mm_limb, .{ .implicit = 0 }, .mem_limb } },
2624 .{ .ops = &.{ .mm_limb, .mem_limb, .{ .implicit = 0 } } },
2625 .{ .ops = &.{ .mm_limb, .{ .implicit = 0 }, .mm_limb } },
2626 },
2627 },
2628 .{
2629 .clobbers = .{ .eflags = true },
2630 .loop = .bitwise,
2631 .mir_tag = .{ ._, mir_tag },
2632 .patterns = &.{
2633 .{ .ops = &.{ .mem_limb, .{ .implicit = 0 }, .gpr_limb } },
2634 .{ .ops = &.{ .mem_limb, .gpr_limb, .{ .implicit = 0 } } },
2635 .{ .ops = &.{ .gpr_limb, .{ .implicit = 0 }, .mem_limb } },
2636 .{ .ops = &.{ .gpr_limb, .mem_limb, .{ .implicit = 0 } } },
2637 .{ .ops = &.{ .gpr_limb, .{ .implicit = 0 }, .gpr_limb } },
2638 },
2639 },
2640 };
25862641 },
2587 });
2588 if (ops[0].index != res[0].index) try ops[0].die(self);
2589 if (ops[1].index != res[0].index) try ops[1].die(self);
2590 try res[0].moveTo(inst, self);
2642 }, .{});
2643 if (ops[0].index != res[0].index) try ops[0].die(cg);
2644 if (ops[1].index != res[0].index) try ops[1].die(cg);
2645 try res[0].moveTo(inst, cg);
25912646 },
2592 .block => if (use_old) try self.airBlock(inst) else {
2647 .block => if (use_old) try cg.airBlock(inst) else {
25932648 const ty_pl = air_datas[@intFromEnum(inst)].ty_pl;
2594 const extra = self.air.extraData(Air.Block, ty_pl.payload);
2595 try self.asmPseudo(.pseudo_dbg_enter_block_none);
2596 try self.lowerBlock(inst, @ptrCast(self.air.extra[extra.end..][0..extra.data.body_len]));
2597 try self.asmPseudo(.pseudo_dbg_leave_block_none);
2649 const extra = cg.air.extraData(Air.Block, ty_pl.payload);
2650 try cg.asmPseudo(.pseudo_dbg_enter_block_none);
2651 try cg.lowerBlock(inst, @ptrCast(cg.air.extra[extra.end..][0..extra.data.body_len]));
2652 try cg.asmPseudo(.pseudo_dbg_leave_block_none);
25982653 },
2599 .loop => if (use_old) try self.airLoop(inst) else {
2654 .loop => if (use_old) try cg.airLoop(inst) else {
26002655 const ty_pl = air_datas[@intFromEnum(inst)].ty_pl;
2601 const extra = self.air.extraData(Air.Block, ty_pl.payload);
2602 self.scope_generation += 1;
2603 try self.loops.putNoClobber(self.gpa, inst, .{
2604 .state = try self.saveState(),
2605 .target = @intCast(self.mir_instructions.len),
2656 const extra = cg.air.extraData(Air.Block, ty_pl.payload);
2657 cg.scope_generation += 1;
2658 try cg.loops.putNoClobber(cg.gpa, inst, .{
2659 .state = try cg.saveState(),
2660 .target = @intCast(cg.mir_instructions.len),
26062661 });
2607 defer assert(self.loops.remove(inst));
2608 try self.genBodyBlock(@ptrCast(self.air.extra[extra.end..][0..extra.data.body_len]));
2662 defer assert(cg.loops.remove(inst));
2663 try cg.genBodyBlock(@ptrCast(cg.air.extra[extra.end..][0..extra.data.body_len]));
26092664 },
2610 .repeat => if (use_old) try self.airRepeat(inst) else {
2665 .repeat => if (use_old) try cg.airRepeat(inst) else {
26112666 const repeat = air_datas[@intFromEnum(inst)].repeat;
2612 const loop = self.loops.get(repeat.loop_inst).?;
2613 try self.restoreState(loop.state, &.{}, .{
2667 const loop = cg.loops.get(repeat.loop_inst).?;
2668 try cg.restoreState(loop.state, &.{}, .{
26142669 .emit_instructions = true,
26152670 .update_tracking = false,
26162671 .resurrect = false,
26172672 .close_scope = true,
26182673 });
2619 _ = try self.asmJmpReloc(loop.target);
2674 _ = try cg.asmJmpReloc(loop.target);
26202675 },
2621 .br => try self.airBr(inst),
2622 .trap => try self.asmOpOnly(.{ ._, .ud2 }),
2623 .breakpoint => try self.asmOpOnly(.{ ._, .int3 }),
2624 .ret_addr => if (use_old) try self.airRetAddr(inst) else {
2625 var slot = try self.tempFromValue(self.typeOfIndex(inst), .{ .load_frame = .{
2676 .br => try cg.airBr(inst),
2677 .trap => try cg.asmOpOnly(.{ ._, .ud2 }),
2678 .breakpoint => try cg.asmOpOnly(.{ ._, .int3 }),
2679 .ret_addr => if (use_old) try cg.airRetAddr(inst) else {
2680 var slot = try cg.tempFromValue(cg.typeOfIndex(inst), .{ .load_frame = .{
26262681 .index = .ret_addr,
26272682 } });
2628 while (try slot.toAnyReg(self)) {}
2629 try slot.moveTo(inst, self);
2683 while (try slot.toAnyReg(cg)) {}
2684 try slot.moveTo(inst, cg);
26302685 },
2631 .frame_addr => if (use_old) try self.airFrameAddress(inst) else {
2632 var slot = try self.tempFromValue(self.typeOfIndex(inst), .{ .lea_frame = .{
2686 .frame_addr => if (use_old) try cg.airFrameAddress(inst) else {
2687 var slot = try cg.tempFromValue(cg.typeOfIndex(inst), .{ .lea_frame = .{
26332688 .index = .base_ptr,
26342689 } });
2635 try slot.moveTo(inst, self);
2690 try slot.moveTo(inst, cg);
2691 },
2692 .call => try cg.airCall(inst, .auto),
2693 .call_always_tail => try cg.airCall(inst, .always_tail),
2694 .call_never_tail => try cg.airCall(inst, .never_tail),
2695 .call_never_inline => try cg.airCall(inst, .never_inline),
2696
2697 .cmp_vector, .cmp_vector_optimized => if (use_old) try cg.airCmpVector(inst) else fallback: {
2698 const ty_pl = air_datas[@intFromEnum(inst)].ty_pl;
2699 const extra = cg.air.extraData(Air.VectorCmp, ty_pl.payload).data;
2700 switch (extra.compareOperator()) {
2701 .eq, .neq => {},
2702 else => break :fallback try cg.airCmpVector(inst),
2703 }
2704 var ops = try cg.tempsFromOperands(inst, .{ extra.lhs, extra.rhs });
2705 var res: [1]Temp = undefined;
2706 switch (extra.compareOperator()) {
2707 .lt => unreachable,
2708 .lte => unreachable,
2709 .eq, .neq => |cmp_op| try cg.select(&res, &.{cg.typeOfIndex(inst)}, &ops, &.{
2710 .{
2711 .required_features = &.{.avx2},
2712 .scalar = .{ .any_int = .byte },
2713 .mir_tag = .{ .vp_b, .cmpeq },
2714 .patterns = &.{
2715 .{ .ops = &.{ .ymm_mask, .ymm, .mem } },
2716 .{ .ops = &.{ .ymm_mask, .mem, .ymm }, .commute = .{ 1, 2 } },
2717 .{ .ops = &.{ .ymm_mask, .ymm, .ymm } },
2718 },
2719 },
2720 .{
2721 .required_features = &.{.avx2},
2722 .scalar = .{ .any_int = .word },
2723 .mir_tag = .{ .vp_w, .cmpeq },
2724 .patterns = &.{
2725 .{ .ops = &.{ .ymm_mask, .ymm, .mem } },
2726 .{ .ops = &.{ .ymm_mask, .mem, .ymm }, .commute = .{ 1, 2 } },
2727 .{ .ops = &.{ .ymm_mask, .ymm, .ymm } },
2728 },
2729 },
2730 .{
2731 .required_features = &.{.avx2},
2732 .scalar = .{ .any_int = .dword },
2733 .mir_tag = .{ .vp_d, .cmpeq },
2734 .patterns = &.{
2735 .{ .ops = &.{ .ymm_mask, .ymm, .mem } },
2736 .{ .ops = &.{ .ymm_mask, .mem, .ymm }, .commute = .{ 1, 2 } },
2737 .{ .ops = &.{ .ymm_mask, .ymm, .ymm } },
2738 },
2739 },
2740 .{
2741 .required_features = &.{.avx2},
2742 .scalar = .{ .any_int = .qword },
2743 .mir_tag = .{ .vp_q, .cmpeq },
2744 .patterns = &.{
2745 .{ .ops = &.{ .ymm_mask, .ymm, .mem } },
2746 .{ .ops = &.{ .ymm_mask, .mem, .ymm }, .commute = .{ 1, 2 } },
2747 .{ .ops = &.{ .ymm_mask, .ymm, .ymm } },
2748 },
2749 },
2750 .{
2751 .required_features = &.{.avx},
2752 .scalar = .{ .any_int = .byte },
2753 .mir_tag = .{ .vp_b, .cmpeq },
2754 .patterns = &.{
2755 .{ .ops = &.{ .xmm_mask, .xmm, .mem } },
2756 .{ .ops = &.{ .xmm_mask, .mem, .xmm }, .commute = .{ 1, 2 } },
2757 .{ .ops = &.{ .xmm_mask, .xmm, .xmm } },
2758 },
2759 },
2760 .{
2761 .required_features = &.{.avx},
2762 .scalar = .{ .any_int = .word },
2763 .mir_tag = .{ .vp_w, .cmpeq },
2764 .patterns = &.{
2765 .{ .ops = &.{ .xmm_mask, .xmm, .mem } },
2766 .{ .ops = &.{ .xmm_mask, .mem, .xmm }, .commute = .{ 1, 2 } },
2767 .{ .ops = &.{ .xmm_mask, .xmm, .xmm } },
2768 },
2769 },
2770 .{
2771 .required_features = &.{.avx},
2772 .scalar = .{ .any_int = .dword },
2773 .mir_tag = .{ .vp_d, .cmpeq },
2774 .patterns = &.{
2775 .{ .ops = &.{ .xmm_mask, .xmm, .mem } },
2776 .{ .ops = &.{ .xmm_mask, .mem, .xmm }, .commute = .{ 1, 2 } },
2777 .{ .ops = &.{ .xmm_mask, .xmm, .xmm } },
2778 },
2779 },
2780 .{
2781 .required_features = &.{.avx},
2782 .scalar = .{ .any_int = .qword },
2783 .mir_tag = .{ .vp_q, .cmpeq },
2784 .patterns = &.{
2785 .{ .ops = &.{ .xmm_mask, .xmm, .mem } },
2786 .{ .ops = &.{ .xmm_mask, .mem, .xmm }, .commute = .{ 1, 2 } },
2787 .{ .ops = &.{ .xmm_mask, .xmm, .xmm } },
2788 },
2789 },
2790 .{
2791 .required_features = &.{.sse2},
2792 .scalar = .{ .any_int = .byte },
2793 .mir_tag = .{ .p_b, .cmpeq },
2794 .patterns = &.{
2795 .{ .ops = &.{ .xmm_mask, .{ .implicit = 0 }, .mem } },
2796 .{ .ops = &.{ .xmm_mask, .mem, .{ .implicit = 0 } } },
2797 .{ .ops = &.{ .xmm_mask, .{ .implicit = 0 }, .xmm } },
2798 .{ .ops = &.{ .xmm_mask, .xmm, .{ .implicit = 0 } } },
2799 },
2800 },
2801 .{
2802 .required_features = &.{.sse2},
2803 .scalar = .{ .any_int = .word },
2804 .mir_tag = .{ .p_w, .cmpeq },
2805 .patterns = &.{
2806 .{ .ops = &.{ .xmm_mask, .{ .implicit = 0 }, .mem } },
2807 .{ .ops = &.{ .xmm_mask, .mem, .{ .implicit = 0 } } },
2808 .{ .ops = &.{ .xmm_mask, .{ .implicit = 0 }, .xmm } },
2809 .{ .ops = &.{ .xmm_mask, .xmm, .{ .implicit = 0 } } },
2810 },
2811 },
2812 .{
2813 .required_features = &.{.sse2},
2814 .scalar = .{ .any_int = .dword },
2815 .mir_tag = .{ .p_d, .cmpeq },
2816 .patterns = &.{
2817 .{ .ops = &.{ .xmm_mask, .{ .implicit = 0 }, .mem } },
2818 .{ .ops = &.{ .xmm_mask, .mem, .{ .implicit = 0 } } },
2819 .{ .ops = &.{ .xmm_mask, .{ .implicit = 0 }, .xmm } },
2820 .{ .ops = &.{ .xmm_mask, .xmm, .{ .implicit = 0 } } },
2821 },
2822 },
2823 .{
2824 .required_features = &.{.sse4_1},
2825 .scalar = .{ .any_int = .qword },
2826 .mir_tag = .{ .p_q, .cmpeq },
2827 .patterns = &.{
2828 .{ .ops = &.{ .xmm_mask, .{ .implicit = 0 }, .mem } },
2829 .{ .ops = &.{ .xmm_mask, .mem, .{ .implicit = 0 } } },
2830 .{ .ops = &.{ .xmm_mask, .{ .implicit = 0 }, .xmm } },
2831 .{ .ops = &.{ .xmm_mask, .xmm, .{ .implicit = 0 } } },
2832 },
2833 },
2834 .{
2835 .required_features = &.{.mmx},
2836 .scalar = .{ .any_int = .byte },
2837 .mir_tag = .{ .p_b, .cmpeq },
2838 .patterns = &.{
2839 .{ .ops = &.{ .mm_mask, .{ .implicit = 0 }, .mem } },
2840 .{ .ops = &.{ .mm_mask, .mem, .{ .implicit = 0 } } },
2841 .{ .ops = &.{ .mm_mask, .{ .implicit = 0 }, .mm } },
2842 .{ .ops = &.{ .mm_mask, .mm, .{ .implicit = 0 } } },
2843 },
2844 },
2845 .{
2846 .required_features = &.{.mmx},
2847 .scalar = .{ .any_int = .word },
2848 .mir_tag = .{ .p_w, .cmpeq },
2849 .patterns = &.{
2850 .{ .ops = &.{ .mm_mask, .{ .implicit = 0 }, .mem } },
2851 .{ .ops = &.{ .mm_mask, .mem, .{ .implicit = 0 } } },
2852 .{ .ops = &.{ .mm_mask, .{ .implicit = 0 }, .mm } },
2853 .{ .ops = &.{ .mm_mask, .mm, .{ .implicit = 0 } } },
2854 },
2855 },
2856 .{
2857 .required_features = &.{.mmx},
2858 .scalar = .{ .any_int = .dword },
2859 .mir_tag = .{ .p_d, .cmpeq },
2860 .patterns = &.{
2861 .{ .ops = &.{ .mm_mask, .{ .implicit = 0 }, .mem } },
2862 .{ .ops = &.{ .mm_mask, .mem, .{ .implicit = 0 } } },
2863 .{ .ops = &.{ .mm_mask, .{ .implicit = 0 }, .mm } },
2864 .{ .ops = &.{ .mm_mask, .mm, .{ .implicit = 0 } } },
2865 },
2866 },
2867 .{
2868 .scalar = .bool,
2869 .clobbers = .{ .eflags = true },
2870 .invert_result = true,
2871 .mir_tag = .{ ._, .xor },
2872 .patterns = &.{
2873 .{ .ops = &.{ .mem, .{ .implicit = 0 }, .simm32 } },
2874 .{ .ops = &.{ .mem, .simm32, .{ .implicit = 0 } } },
2875 .{ .ops = &.{ .mem, .{ .implicit = 0 }, .gpr } },
2876 .{ .ops = &.{ .mem, .gpr, .{ .implicit = 0 } } },
2877 .{ .ops = &.{ .gpr, .{ .implicit = 0 }, .simm32 } },
2878 .{ .ops = &.{ .gpr, .simm32, .{ .implicit = 0 } } },
2879 .{ .ops = &.{ .gpr, .{ .implicit = 0 }, .mem } },
2880 .{ .ops = &.{ .gpr, .mem, .{ .implicit = 0 } } },
2881 .{ .ops = &.{ .gpr, .{ .implicit = 0 }, .gpr } },
2882 .{ .ops = &.{ .gpr, .gpr, .{ .implicit = 0 } } },
2883 },
2884 },
2885
2886 .{
2887 .required_features = &.{.avx2},
2888 .scalar = .{ .any_int = .byte },
2889 .loop = .elementwise,
2890 .mir_tag = .{ .vp_b, .cmpeq },
2891 .patterns = &.{
2892 .{ .ops = &.{ .ymm_mask_limb, .{ .explicit = 0 }, .mem_limb } },
2893 .{ .ops = &.{ .ymm_mask_limb, .mem_limb, .{ .explicit = 0 } }, .commute = .{ 1, 2 } },
2894 .{ .ops = &.{ .ymm_mask_limb, .ymm_limb, .mem_limb } },
2895 .{ .ops = &.{ .ymm_mask_limb, .ymm_limb, .ymm_limb } },
2896 },
2897 },
2898 .{
2899 .required_features = &.{.avx2},
2900 .scalar = .{ .any_int = .word },
2901 .loop = .elementwise,
2902 .mir_tag = .{ .vp_w, .cmpeq },
2903 .patterns = &.{
2904 .{ .ops = &.{ .ymm_mask_limb, .{ .explicit = 0 }, .mem_limb } },
2905 .{ .ops = &.{ .ymm_mask_limb, .mem_limb, .{ .explicit = 0 } }, .commute = .{ 1, 2 } },
2906 .{ .ops = &.{ .ymm_mask_limb, .ymm_limb, .mem_limb } },
2907 .{ .ops = &.{ .ymm_mask_limb, .ymm_limb, .ymm_limb } },
2908 },
2909 },
2910 .{
2911 .required_features = &.{.avx2},
2912 .scalar = .{ .any_int = .dword },
2913 .loop = .elementwise,
2914 .mir_tag = .{ .vp_d, .cmpeq },
2915 .patterns = &.{
2916 .{ .ops = &.{ .ymm_mask_limb, .{ .explicit = 0 }, .mem_limb } },
2917 .{ .ops = &.{ .ymm_mask_limb, .mem_limb, .{ .explicit = 0 } }, .commute = .{ 1, 2 } },
2918 .{ .ops = &.{ .ymm_mask_limb, .ymm_limb, .mem_limb } },
2919 .{ .ops = &.{ .ymm_mask_limb, .ymm_limb, .ymm_limb } },
2920 },
2921 },
2922 .{
2923 .required_features = &.{.avx2},
2924 .scalar = .{ .any_int = .qword },
2925 .loop = .elementwise,
2926 .mir_tag = .{ .vp_q, .cmpeq },
2927 .patterns = &.{
2928 .{ .ops = &.{ .ymm_mask_limb, .{ .explicit = 0 }, .mem_limb } },
2929 .{ .ops = &.{ .ymm_mask_limb, .mem_limb, .{ .explicit = 0 } }, .commute = .{ 1, 2 } },
2930 .{ .ops = &.{ .ymm_mask_limb, .ymm_limb, .mem_limb } },
2931 .{ .ops = &.{ .ymm_mask_limb, .ymm_limb, .ymm_limb } },
2932 },
2933 },
2934 .{
2935 .required_features = &.{.avx},
2936 .scalar = .{ .any_int = .byte },
2937 .loop = .elementwise,
2938 .mir_tag = .{ .vp_b, .cmpeq },
2939 .patterns = &.{
2940 .{ .ops = &.{ .xmm_mask_limb, .{ .explicit = 0 }, .mem_limb } },
2941 .{ .ops = &.{ .xmm_mask_limb, .mem_limb, .{ .explicit = 0 } }, .commute = .{ 1, 2 } },
2942 .{ .ops = &.{ .xmm_mask_limb, .xmm_limb, .mem_limb } },
2943 .{ .ops = &.{ .xmm_mask_limb, .xmm_limb, .xmm_limb } },
2944 },
2945 },
2946 .{
2947 .required_features = &.{.avx},
2948 .scalar = .{ .any_int = .word },
2949 .loop = .elementwise,
2950 .mir_tag = .{ .vp_w, .cmpeq },
2951 .patterns = &.{
2952 .{ .ops = &.{ .xmm_mask_limb, .{ .explicit = 0 }, .mem_limb } },
2953 .{ .ops = &.{ .xmm_mask_limb, .mem_limb, .{ .explicit = 0 } }, .commute = .{ 1, 2 } },
2954 .{ .ops = &.{ .xmm_mask_limb, .xmm_limb, .mem_limb } },
2955 .{ .ops = &.{ .xmm_mask_limb, .xmm_limb, .xmm_limb } },
2956 },
2957 },
2958 .{
2959 .required_features = &.{.avx},
2960 .scalar = .{ .any_int = .dword },
2961 .loop = .elementwise,
2962 .mir_tag = .{ .vp_d, .cmpeq },
2963 .patterns = &.{
2964 .{ .ops = &.{ .xmm_mask_limb, .{ .explicit = 0 }, .mem_limb } },
2965 .{ .ops = &.{ .xmm_mask_limb, .mem_limb, .{ .explicit = 0 } }, .commute = .{ 1, 2 } },
2966 .{ .ops = &.{ .xmm_mask_limb, .xmm_limb, .mem_limb } },
2967 .{ .ops = &.{ .xmm_mask_limb, .xmm_limb, .xmm_limb } },
2968 },
2969 },
2970 .{
2971 .required_features = &.{.avx},
2972 .scalar = .{ .any_int = .qword },
2973 .loop = .elementwise,
2974 .mir_tag = .{ .vp_q, .cmpeq },
2975 .patterns = &.{
2976 .{ .ops = &.{ .xmm_mask_limb, .{ .explicit = 0 }, .mem_limb } },
2977 .{ .ops = &.{ .xmm_mask_limb, .mem_limb, .{ .explicit = 0 } }, .commute = .{ 1, 2 } },
2978 .{ .ops = &.{ .xmm_mask_limb, .xmm_limb, .mem_limb } },
2979 .{ .ops = &.{ .xmm_mask_limb, .xmm_limb, .xmm_limb } },
2980 },
2981 },
2982 .{
2983 .required_features = &.{.sse2},
2984 .scalar = .{ .any_int = .byte },
2985 .loop = .elementwise,
2986 .mir_tag = .{ .p_b, .cmpeq },
2987 .patterns = &.{
2988 .{ .ops = &.{ .xmm_mask_limb, .{ .implicit = 0 }, .mem_limb } },
2989 .{ .ops = &.{ .xmm_mask_limb, .mem_limb, .{ .implicit = 0 } } },
2990 .{ .ops = &.{ .xmm_mask_limb, .{ .implicit = 0 }, .xmm_limb } },
2991 },
2992 },
2993 .{
2994 .required_features = &.{.sse2},
2995 .scalar = .{ .any_int = .word },
2996 .loop = .elementwise,
2997 .mir_tag = .{ .p_w, .cmpeq },
2998 .patterns = &.{
2999 .{ .ops = &.{ .xmm_mask_limb, .{ .implicit = 0 }, .mem_limb } },
3000 .{ .ops = &.{ .xmm_mask_limb, .mem_limb, .{ .implicit = 0 } } },
3001 .{ .ops = &.{ .xmm_mask_limb, .{ .implicit = 0 }, .xmm_limb } },
3002 },
3003 },
3004 .{
3005 .required_features = &.{.sse2},
3006 .scalar = .{ .any_int = .dword },
3007 .loop = .elementwise,
3008 .mir_tag = .{ .p_d, .cmpeq },
3009 .patterns = &.{
3010 .{ .ops = &.{ .xmm_mask_limb, .{ .implicit = 0 }, .mem_limb } },
3011 .{ .ops = &.{ .xmm_mask_limb, .mem_limb, .{ .implicit = 0 } } },
3012 .{ .ops = &.{ .xmm_mask_limb, .{ .implicit = 0 }, .xmm_limb } },
3013 },
3014 },
3015 .{
3016 .required_features = &.{.sse4_1},
3017 .scalar = .{ .any_int = .qword },
3018 .loop = .elementwise,
3019 .mir_tag = .{ .p_q, .cmpeq },
3020 .patterns = &.{
3021 .{ .ops = &.{ .xmm_mask_limb, .{ .implicit = 0 }, .mem_limb } },
3022 .{ .ops = &.{ .xmm_mask_limb, .mem_limb, .{ .implicit = 0 } } },
3023 .{ .ops = &.{ .xmm_mask_limb, .{ .implicit = 0 }, .xmm_limb } },
3024 },
3025 },
3026 .{
3027 .required_features = &.{.mmx},
3028 .scalar = .{ .any_int = .byte },
3029 .loop = .elementwise,
3030 .mir_tag = .{ .p_b, .cmpeq },
3031 .patterns = &.{
3032 .{ .ops = &.{ .mm_mask_limb, .{ .implicit = 0 }, .mem_limb } },
3033 .{ .ops = &.{ .mm_mask_limb, .mem_limb, .{ .implicit = 0 } } },
3034 .{ .ops = &.{ .mm_mask_limb, .{ .implicit = 0 }, .mm_limb } },
3035 },
3036 },
3037 .{
3038 .required_features = &.{.mmx},
3039 .scalar = .{ .any_int = .word },
3040 .loop = .elementwise,
3041 .mir_tag = .{ .p_w, .cmpeq },
3042 .patterns = &.{
3043 .{ .ops = &.{ .mm_mask_limb, .{ .implicit = 0 }, .mem_limb } },
3044 .{ .ops = &.{ .mm_mask_limb, .mem_limb, .{ .implicit = 0 } } },
3045 .{ .ops = &.{ .mm_mask_limb, .{ .implicit = 0 }, .mm_limb } },
3046 },
3047 },
3048 .{
3049 .required_features = &.{.mmx},
3050 .scalar = .{ .any_int = .dword },
3051 .loop = .elementwise,
3052 .mir_tag = .{ .p_d, .cmpeq },
3053 .patterns = &.{
3054 .{ .ops = &.{ .mm_mask_limb, .{ .implicit = 0 }, .mem_limb } },
3055 .{ .ops = &.{ .mm_mask_limb, .mem_limb, .{ .implicit = 0 } } },
3056 .{ .ops = &.{ .mm_mask_limb, .{ .implicit = 0 }, .mm_limb } },
3057 },
3058 },
3059 .{
3060 .scalar = .bool,
3061 .clobbers = .{ .eflags = true },
3062 .invert_result = true,
3063 .loop = .elementwise,
3064 .mir_tag = .{ ._, .xor },
3065 .patterns = &.{
3066 .{ .ops = &.{ .mem_limb, .{ .implicit = 0 }, .gpr_limb } },
3067 .{ .ops = &.{ .mem_limb, .gpr_limb, .{ .implicit = 0 } } },
3068 .{ .ops = &.{ .gpr_limb, .{ .implicit = 0 }, .mem_limb } },
3069 .{ .ops = &.{ .gpr_limb, .mem_limb, .{ .implicit = 0 } } },
3070 .{ .ops = &.{ .gpr_limb, .{ .implicit = 0 }, .gpr_limb } },
3071 },
3072 },
3073 }, .{ .invert_result = switch (cmp_op) {
3074 .eq => false,
3075 .neq => true,
3076 else => unreachable,
3077 } }),
3078 .gte => unreachable,
3079 .gt => unreachable,
3080 }
3081 if (ops[0].index != res[0].index) try ops[0].die(cg);
3082 if (ops[1].index != res[0].index) try ops[1].die(cg);
3083 try res[0].moveTo(inst, cg);
26363084 },
2637 .call => try self.airCall(inst, .auto),
2638 .call_always_tail => try self.airCall(inst, .always_tail),
2639 .call_never_tail => try self.airCall(inst, .never_tail),
2640 .call_never_inline => try self.airCall(inst, .never_inline),
2641
2642 .cond_br => try self.airCondBr(inst),
2643 .switch_br => try self.airSwitchBr(inst),
2644 .loop_switch_br => try self.airLoopSwitchBr(inst),
2645 .switch_dispatch => try self.airSwitchDispatch(inst),
2646 .@"try", .try_cold => try self.airTry(inst),
2647 .try_ptr, .try_ptr_cold => try self.airTryPtr(inst),
2648 .dbg_stmt => if (use_old) try self.airDbgStmt(inst) else {
3085
3086 .cond_br => try cg.airCondBr(inst),
3087 .switch_br => try cg.airSwitchBr(inst),
3088 .loop_switch_br => try cg.airLoopSwitchBr(inst),
3089 .switch_dispatch => try cg.airSwitchDispatch(inst),
3090 .@"try", .try_cold => try cg.airTry(inst),
3091 .try_ptr, .try_ptr_cold => try cg.airTryPtr(inst),
3092 .dbg_stmt => if (use_old) try cg.airDbgStmt(inst) else {
26493093 const dbg_stmt = air_datas[@intFromEnum(inst)].dbg_stmt;
2650 _ = try self.addInst(.{
3094 _ = try cg.addInst(.{
26513095 .tag = .pseudo,
26523096 .ops = .pseudo_dbg_line_line_column,
26533097 .data = .{ .line_column = .{
......@@ -2656,50 +3100,50 @@ fn genBody(self: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
26563100 } },
26573101 });
26583102 },
2659 .dbg_empty_stmt => if (use_old) try self.airDbgEmptyStmt() else {
2660 if (self.mir_instructions.len > 0) {
2661 const prev_mir_op = &self.mir_instructions.items(.ops)[self.mir_instructions.len - 1];
3103 .dbg_empty_stmt => if (use_old) try cg.airDbgEmptyStmt() else {
3104 if (cg.mir_instructions.len > 0) {
3105 const prev_mir_op = &cg.mir_instructions.items(.ops)[cg.mir_instructions.len - 1];
26623106 if (prev_mir_op.* == .pseudo_dbg_line_stmt_line_column)
26633107 prev_mir_op.* = .pseudo_dbg_line_line_column;
26643108 }
2665 try self.asmOpOnly(.{ ._, .nop });
3109 try cg.asmOpOnly(.{ ._, .nop });
26663110 },
2667 .dbg_inline_block => if (use_old) try self.airDbgInlineBlock(inst) else {
3111 .dbg_inline_block => if (use_old) try cg.airDbgInlineBlock(inst) else {
26683112 const ty_pl = air_datas[@intFromEnum(inst)].ty_pl;
2669 const extra = self.air.extraData(Air.DbgInlineBlock, ty_pl.payload);
2670 const old_inline_func = self.inline_func;
2671 defer self.inline_func = old_inline_func;
2672 self.inline_func = extra.data.func;
2673 _ = try self.addInst(.{
3113 const extra = cg.air.extraData(Air.DbgInlineBlock, ty_pl.payload);
3114 const old_inline_func = cg.inline_func;
3115 defer cg.inline_func = old_inline_func;
3116 cg.inline_func = extra.data.func;
3117 _ = try cg.addInst(.{
26743118 .tag = .pseudo,
26753119 .ops = .pseudo_dbg_enter_inline_func,
26763120 .data = .{ .func = extra.data.func },
26773121 });
2678 try self.lowerBlock(inst, @ptrCast(self.air.extra[extra.end..][0..extra.data.body_len]));
2679 _ = try self.addInst(.{
3122 try cg.lowerBlock(inst, @ptrCast(cg.air.extra[extra.end..][0..extra.data.body_len]));
3123 _ = try cg.addInst(.{
26803124 .tag = .pseudo,
26813125 .ops = .pseudo_dbg_leave_inline_func,
26823126 .data = .{ .func = old_inline_func },
26833127 });
26843128 },
2685 .dbg_var_ptr, .dbg_var_val, .dbg_arg_inline => if (use_old) try self.airDbgVar(inst) else {
3129 .dbg_var_ptr, .dbg_var_val, .dbg_arg_inline => if (use_old) try cg.airDbgVar(inst) else {
26863130 const pl_op = air_datas[@intFromEnum(inst)].pl_op;
2687 var ops = try self.tempsFromOperands(inst, .{pl_op.operand});
2688 try self.genLocalDebugInfo(inst, ops[0].tracking(self).short);
2689 try ops[0].die(self);
3131 var ops = try cg.tempsFromOperands(inst, .{pl_op.operand});
3132 try cg.genLocalDebugInfo(inst, ops[0].tracking(cg).short);
3133 try ops[0].die(cg);
26903134 },
2691 .is_null_ptr => if (use_old) try self.airIsNullPtr(inst) else {
3135 .is_null_ptr => if (use_old) try cg.airIsNullPtr(inst) else {
26923136 const un_op = air_datas[@intFromEnum(inst)].un_op;
2693 const opt_ty = self.typeOf(un_op).childType(zcu);
3137 const opt_ty = cg.typeOf(un_op).childType(zcu);
26943138 const opt_repr_is_pl = opt_ty.optionalReprIsPayload(zcu);
26953139 const opt_child_ty = opt_ty.optionalChild(zcu);
26963140 const opt_child_abi_size: u31 = @intCast(opt_child_ty.abiSize(zcu));
2697 var ops = try self.tempsFromOperands(inst, .{un_op});
2698 if (!opt_repr_is_pl) try ops[0].toOffset(opt_child_abi_size, self);
2699 while (try ops[0].toLea(self)) {}
2700 try self.asmMemoryImmediate(
3141 var ops = try cg.tempsFromOperands(inst, .{un_op});
3142 if (!opt_repr_is_pl) try ops[0].toOffset(opt_child_abi_size, cg);
3143 while (try ops[0].toLea(cg)) {}
3144 try cg.asmMemoryImmediate(
27013145 .{ ._, .cmp },
2702 try ops[0].tracking(self).short.deref().mem(self, .{ .size = if (!opt_repr_is_pl)
3146 try ops[0].tracking(cg).short.deref().mem(cg, .{ .size = if (!opt_repr_is_pl)
27033147 .byte
27043148 else if (opt_child_ty.isSlice(zcu))
27053149 .qword
......@@ -2707,22 +3151,22 @@ fn genBody(self: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
27073151 .fromSize(opt_child_abi_size) }),
27083152 .u(0),
27093153 );
2710 var is_null = try self.tempFromValue(self.typeOfIndex(inst), .{ .eflags = .e });
2711 try ops[0].die(self);
2712 try is_null.moveTo(inst, self);
3154 var is_null = try cg.tempFromValue(cg.typeOfIndex(inst), .{ .eflags = .e });
3155 try ops[0].die(cg);
3156 try is_null.moveTo(inst, cg);
27133157 },
2714 .is_non_null_ptr => if (use_old) try self.airIsNonNullPtr(inst) else {
3158 .is_non_null_ptr => if (use_old) try cg.airIsNonNullPtr(inst) else {
27153159 const un_op = air_datas[@intFromEnum(inst)].un_op;
2716 const opt_ty = self.typeOf(un_op).childType(zcu);
3160 const opt_ty = cg.typeOf(un_op).childType(zcu);
27173161 const opt_repr_is_pl = opt_ty.optionalReprIsPayload(zcu);
27183162 const opt_child_ty = opt_ty.optionalChild(zcu);
27193163 const opt_child_abi_size: u31 = @intCast(opt_child_ty.abiSize(zcu));
2720 var ops = try self.tempsFromOperands(inst, .{un_op});
2721 if (!opt_repr_is_pl) try ops[0].toOffset(opt_child_abi_size, self);
2722 while (try ops[0].toLea(self)) {}
2723 try self.asmMemoryImmediate(
3164 var ops = try cg.tempsFromOperands(inst, .{un_op});
3165 if (!opt_repr_is_pl) try ops[0].toOffset(opt_child_abi_size, cg);
3166 while (try ops[0].toLea(cg)) {}
3167 try cg.asmMemoryImmediate(
27243168 .{ ._, .cmp },
2725 try ops[0].tracking(self).short.deref().mem(self, .{ .size = if (!opt_repr_is_pl)
3169 try ops[0].tracking(cg).short.deref().mem(cg, .{ .size = if (!opt_repr_is_pl)
27263170 .byte
27273171 else if (opt_child_ty.isSlice(zcu))
27283172 .qword
......@@ -2730,244 +3174,244 @@ fn genBody(self: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
27303174 .fromSize(opt_child_abi_size) }),
27313175 .u(0),
27323176 );
2733 var is_non_null = try self.tempFromValue(self.typeOfIndex(inst), .{ .eflags = .ne });
2734 try ops[0].die(self);
2735 try is_non_null.moveTo(inst, self);
3177 var is_non_null = try cg.tempFromValue(cg.typeOfIndex(inst), .{ .eflags = .ne });
3178 try ops[0].die(cg);
3179 try is_non_null.moveTo(inst, cg);
27363180 },
2737 .is_err_ptr => if (use_old) try self.airIsErrPtr(inst) else {
3181 .is_err_ptr => if (use_old) try cg.airIsErrPtr(inst) else {
27383182 const un_op = air_datas[@intFromEnum(inst)].un_op;
2739 const eu_ty = self.typeOf(un_op).childType(zcu);
3183 const eu_ty = cg.typeOf(un_op).childType(zcu);
27403184 const eu_err_ty = eu_ty.errorUnionSet(zcu);
27413185 const eu_pl_ty = eu_ty.errorUnionPayload(zcu);
27423186 const eu_err_off: i32 = @intCast(codegen.errUnionErrorOffset(eu_pl_ty, zcu));
2743 var ops = try self.tempsFromOperands(inst, .{un_op});
2744 try ops[0].toOffset(eu_err_off, self);
2745 while (try ops[0].toLea(self)) {}
2746 try self.asmMemoryImmediate(
3187 var ops = try cg.tempsFromOperands(inst, .{un_op});
3188 try ops[0].toOffset(eu_err_off, cg);
3189 while (try ops[0].toLea(cg)) {}
3190 try cg.asmMemoryImmediate(
27473191 .{ ._, .cmp },
2748 try ops[0].tracking(self).short.deref().mem(self, .{ .size = self.memSize(eu_err_ty) }),
3192 try ops[0].tracking(cg).short.deref().mem(cg, .{ .size = cg.memSize(eu_err_ty) }),
27493193 .u(0),
27503194 );
2751 var is_err = try self.tempFromValue(self.typeOfIndex(inst), .{ .eflags = .ne });
2752 try ops[0].die(self);
2753 try is_err.moveTo(inst, self);
3195 var is_err = try cg.tempFromValue(cg.typeOfIndex(inst), .{ .eflags = .ne });
3196 try ops[0].die(cg);
3197 try is_err.moveTo(inst, cg);
27543198 },
2755 .is_non_err_ptr => if (use_old) try self.airIsNonErrPtr(inst) else {
3199 .is_non_err_ptr => if (use_old) try cg.airIsNonErrPtr(inst) else {
27563200 const un_op = air_datas[@intFromEnum(inst)].un_op;
2757 const eu_ty = self.typeOf(un_op).childType(zcu);
3201 const eu_ty = cg.typeOf(un_op).childType(zcu);
27583202 const eu_err_ty = eu_ty.errorUnionSet(zcu);
27593203 const eu_pl_ty = eu_ty.errorUnionPayload(zcu);
27603204 const eu_err_off: i32 = @intCast(codegen.errUnionErrorOffset(eu_pl_ty, zcu));
2761 var ops = try self.tempsFromOperands(inst, .{un_op});
2762 try ops[0].toOffset(eu_err_off, self);
2763 while (try ops[0].toLea(self)) {}
2764 try self.asmMemoryImmediate(
3205 var ops = try cg.tempsFromOperands(inst, .{un_op});
3206 try ops[0].toOffset(eu_err_off, cg);
3207 while (try ops[0].toLea(cg)) {}
3208 try cg.asmMemoryImmediate(
27653209 .{ ._, .cmp },
2766 try ops[0].tracking(self).short.deref().mem(self, .{ .size = self.memSize(eu_err_ty) }),
3210 try ops[0].tracking(cg).short.deref().mem(cg, .{ .size = cg.memSize(eu_err_ty) }),
27673211 .u(0),
27683212 );
2769 var is_non_err = try self.tempFromValue(self.typeOfIndex(inst), .{ .eflags = .e });
2770 try ops[0].die(self);
2771 try is_non_err.moveTo(inst, self);
3213 var is_non_err = try cg.tempFromValue(cg.typeOfIndex(inst), .{ .eflags = .e });
3214 try ops[0].die(cg);
3215 try is_non_err.moveTo(inst, cg);
27723216 },
2773 .int_from_ptr => if (use_old) try self.airIntFromPtr(inst) else {
3217 .int_from_ptr => if (use_old) try cg.airIntFromPtr(inst) else {
27743218 const un_op = air_datas[@intFromEnum(inst)].un_op;
2775 var ops = try self.tempsFromOperands(inst, .{un_op});
2776 try ops[0].toLimb(0, self);
2777 try ops[0].moveTo(inst, self);
3219 var ops = try cg.tempsFromOperands(inst, .{un_op});
3220 try ops[0].toLimb(0, cg);
3221 try ops[0].moveTo(inst, cg);
27783222 },
2779 .int_from_bool => if (use_old) try self.airIntFromBool(inst) else {
3223 .int_from_bool => if (use_old) try cg.airIntFromBool(inst) else {
27803224 const un_op = air_datas[@intFromEnum(inst)].un_op;
2781 var ops = try self.tempsFromOperands(inst, .{un_op});
2782 try ops[0].moveTo(inst, self);
3225 var ops = try cg.tempsFromOperands(inst, .{un_op});
3226 try ops[0].moveTo(inst, cg);
27833227 },
2784 .ret => try self.airRet(inst, false),
2785 .ret_safe => try self.airRet(inst, true),
2786 .ret_load => try self.airRetLoad(inst),
3228 .ret => try cg.airRet(inst, false),
3229 .ret_safe => try cg.airRet(inst, true),
3230 .ret_load => try cg.airRetLoad(inst),
27873231 .unreach => {},
2788 .optional_payload_ptr => if (use_old) try self.airOptionalPayloadPtr(inst) else {
3232 .optional_payload_ptr => if (use_old) try cg.airOptionalPayloadPtr(inst) else {
27893233 const ty_op = air_datas[@intFromEnum(inst)].ty_op;
2790 var ops = try self.tempsFromOperands(inst, .{ty_op.operand});
2791 try ops[0].moveTo(inst, self);
3234 var ops = try cg.tempsFromOperands(inst, .{ty_op.operand});
3235 try ops[0].moveTo(inst, cg);
27923236 },
2793 .optional_payload_ptr_set => if (use_old) try self.airOptionalPayloadPtrSet(inst) else {
3237 .optional_payload_ptr_set => if (use_old) try cg.airOptionalPayloadPtrSet(inst) else {
27943238 const ty_op = air_datas[@intFromEnum(inst)].ty_op;
2795 const opt_ty = self.typeOf(ty_op.operand).childType(zcu);
2796 var ops = try self.tempsFromOperands(inst, .{ty_op.operand});
3239 const opt_ty = cg.typeOf(ty_op.operand).childType(zcu);
3240 var ops = try cg.tempsFromOperands(inst, .{ty_op.operand});
27973241 if (!opt_ty.optionalReprIsPayload(zcu)) {
27983242 const opt_child_ty = opt_ty.optionalChild(zcu);
27993243 const opt_child_abi_size: i32 = @intCast(opt_child_ty.abiSize(zcu));
2800 try ops[0].toOffset(opt_child_abi_size, self);
2801 var has_value = try self.tempFromValue(Type.bool, .{ .immediate = 1 });
2802 try ops[0].store(&has_value, self);
2803 try has_value.die(self);
2804 try ops[0].toOffset(-opt_child_abi_size, self);
3244 try ops[0].toOffset(opt_child_abi_size, cg);
3245 var has_value = try cg.tempFromValue(Type.bool, .{ .immediate = 1 });
3246 try ops[0].store(&has_value, cg);
3247 try has_value.die(cg);
3248 try ops[0].toOffset(-opt_child_abi_size, cg);
28053249 }
2806 try ops[0].moveTo(inst, self);
3250 try ops[0].moveTo(inst, cg);
28073251 },
2808 .unwrap_errunion_payload_ptr => if (use_old) try self.airUnwrapErrUnionPayloadPtr(inst) else {
3252 .unwrap_errunion_payload_ptr => if (use_old) try cg.airUnwrapErrUnionPayloadPtr(inst) else {
28093253 const ty_op = air_datas[@intFromEnum(inst)].ty_op;
2810 const eu_ty = self.typeOf(ty_op.operand).childType(zcu);
3254 const eu_ty = cg.typeOf(ty_op.operand).childType(zcu);
28113255 const eu_pl_ty = eu_ty.errorUnionPayload(zcu);
28123256 const eu_pl_off: i32 = @intCast(codegen.errUnionPayloadOffset(eu_pl_ty, zcu));
2813 var ops = try self.tempsFromOperands(inst, .{ty_op.operand});
2814 try ops[0].toOffset(eu_pl_off, self);
2815 try ops[0].moveTo(inst, self);
3257 var ops = try cg.tempsFromOperands(inst, .{ty_op.operand});
3258 try ops[0].toOffset(eu_pl_off, cg);
3259 try ops[0].moveTo(inst, cg);
28163260 },
2817 .unwrap_errunion_err_ptr => if (use_old) try self.airUnwrapErrUnionErrPtr(inst) else {
3261 .unwrap_errunion_err_ptr => if (use_old) try cg.airUnwrapErrUnionErrPtr(inst) else {
28183262 const ty_op = air_datas[@intFromEnum(inst)].ty_op;
2819 const eu_ty = self.typeOf(ty_op.operand).childType(zcu);
3263 const eu_ty = cg.typeOf(ty_op.operand).childType(zcu);
28203264 const eu_pl_ty = eu_ty.errorUnionPayload(zcu);
28213265 const eu_err_off: i32 = @intCast(codegen.errUnionErrorOffset(eu_pl_ty, zcu));
2822 var ops = try self.tempsFromOperands(inst, .{ty_op.operand});
2823 try ops[0].toOffset(eu_err_off, self);
2824 var err = try ops[0].load(eu_ty.errorUnionSet(zcu), self);
2825 try ops[0].die(self);
2826 try err.moveTo(inst, self);
3266 var ops = try cg.tempsFromOperands(inst, .{ty_op.operand});
3267 try ops[0].toOffset(eu_err_off, cg);
3268 var err = try ops[0].load(eu_ty.errorUnionSet(zcu), cg);
3269 try ops[0].die(cg);
3270 try err.moveTo(inst, cg);
28273271 },
2828 .errunion_payload_ptr_set => if (use_old) try self.airErrUnionPayloadPtrSet(inst) else {
3272 .errunion_payload_ptr_set => if (use_old) try cg.airErrUnionPayloadPtrSet(inst) else {
28293273 const ty_op = air_datas[@intFromEnum(inst)].ty_op;
2830 const eu_ty = self.typeOf(ty_op.operand).childType(zcu);
3274 const eu_ty = cg.typeOf(ty_op.operand).childType(zcu);
28313275 const eu_err_ty = eu_ty.errorUnionSet(zcu);
28323276 const eu_pl_ty = eu_ty.errorUnionPayload(zcu);
28333277 const eu_err_off: i32 = @intCast(codegen.errUnionErrorOffset(eu_pl_ty, zcu));
28343278 const eu_pl_off: i32 = @intCast(codegen.errUnionPayloadOffset(eu_pl_ty, zcu));
2835 var ops = try self.tempsFromOperands(inst, .{ty_op.operand});
2836 try ops[0].toOffset(eu_err_off, self);
2837 var no_err = try self.tempFromValue(eu_err_ty, .{ .immediate = 0 });
2838 try ops[0].store(&no_err, self);
2839 try no_err.die(self);
2840 try ops[0].toOffset(eu_pl_off - eu_err_off, self);
2841 try ops[0].moveTo(inst, self);
3279 var ops = try cg.tempsFromOperands(inst, .{ty_op.operand});
3280 try ops[0].toOffset(eu_err_off, cg);
3281 var no_err = try cg.tempFromValue(eu_err_ty, .{ .immediate = 0 });
3282 try ops[0].store(&no_err, cg);
3283 try no_err.die(cg);
3284 try ops[0].toOffset(eu_pl_off - eu_err_off, cg);
3285 try ops[0].moveTo(inst, cg);
28423286 },
2843 .struct_field_ptr => if (use_old) try self.airStructFieldPtr(inst) else {
3287 .struct_field_ptr => if (use_old) try cg.airStructFieldPtr(inst) else {
28443288 const ty_pl = air_datas[@intFromEnum(inst)].ty_pl;
2845 const extra = self.air.extraData(Air.StructField, ty_pl.payload).data;
2846 var ops = try self.tempsFromOperands(inst, .{extra.struct_operand});
2847 try ops[0].toOffset(self.fieldOffset(
2848 self.typeOf(extra.struct_operand),
2849 self.typeOfIndex(inst),
3289 const extra = cg.air.extraData(Air.StructField, ty_pl.payload).data;
3290 var ops = try cg.tempsFromOperands(inst, .{extra.struct_operand});
3291 try ops[0].toOffset(cg.fieldOffset(
3292 cg.typeOf(extra.struct_operand),
3293 cg.typeOfIndex(inst),
28503294 extra.field_index,
2851 ), self);
2852 try ops[0].moveTo(inst, self);
3295 ), cg);
3296 try ops[0].moveTo(inst, cg);
28533297 },
2854 .struct_field_ptr_index_0 => if (use_old) try self.airStructFieldPtrIndex(inst, 0) else {
3298 .struct_field_ptr_index_0 => if (use_old) try cg.airStructFieldPtrIndex(inst, 0) else {
28553299 const ty_op = air_datas[@intFromEnum(inst)].ty_op;
2856 var ops = try self.tempsFromOperands(inst, .{ty_op.operand});
2857 try ops[0].toOffset(self.fieldOffset(
2858 self.typeOf(ty_op.operand),
2859 self.typeOfIndex(inst),
3300 var ops = try cg.tempsFromOperands(inst, .{ty_op.operand});
3301 try ops[0].toOffset(cg.fieldOffset(
3302 cg.typeOf(ty_op.operand),
3303 cg.typeOfIndex(inst),
28603304 0,
2861 ), self);
2862 try ops[0].moveTo(inst, self);
3305 ), cg);
3306 try ops[0].moveTo(inst, cg);
28633307 },
2864 .struct_field_ptr_index_1 => if (use_old) try self.airStructFieldPtrIndex(inst, 1) else {
3308 .struct_field_ptr_index_1 => if (use_old) try cg.airStructFieldPtrIndex(inst, 1) else {
28653309 const ty_op = air_datas[@intFromEnum(inst)].ty_op;
2866 var ops = try self.tempsFromOperands(inst, .{ty_op.operand});
2867 try ops[0].toOffset(self.fieldOffset(
2868 self.typeOf(ty_op.operand),
2869 self.typeOfIndex(inst),
3310 var ops = try cg.tempsFromOperands(inst, .{ty_op.operand});
3311 try ops[0].toOffset(cg.fieldOffset(
3312 cg.typeOf(ty_op.operand),
3313 cg.typeOfIndex(inst),
28703314 1,
2871 ), self);
2872 try ops[0].moveTo(inst, self);
3315 ), cg);
3316 try ops[0].moveTo(inst, cg);
28733317 },
2874 .struct_field_ptr_index_2 => if (use_old) try self.airStructFieldPtrIndex(inst, 2) else {
3318 .struct_field_ptr_index_2 => if (use_old) try cg.airStructFieldPtrIndex(inst, 2) else {
28753319 const ty_op = air_datas[@intFromEnum(inst)].ty_op;
2876 var ops = try self.tempsFromOperands(inst, .{ty_op.operand});
2877 try ops[0].toOffset(self.fieldOffset(
2878 self.typeOf(ty_op.operand),
2879 self.typeOfIndex(inst),
3320 var ops = try cg.tempsFromOperands(inst, .{ty_op.operand});
3321 try ops[0].toOffset(cg.fieldOffset(
3322 cg.typeOf(ty_op.operand),
3323 cg.typeOfIndex(inst),
28803324 2,
2881 ), self);
2882 try ops[0].moveTo(inst, self);
3325 ), cg);
3326 try ops[0].moveTo(inst, cg);
28833327 },
2884 .struct_field_ptr_index_3 => if (use_old) try self.airStructFieldPtrIndex(inst, 3) else {
3328 .struct_field_ptr_index_3 => if (use_old) try cg.airStructFieldPtrIndex(inst, 3) else {
28853329 const ty_op = air_datas[@intFromEnum(inst)].ty_op;
2886 var ops = try self.tempsFromOperands(inst, .{ty_op.operand});
2887 try ops[0].toOffset(self.fieldOffset(
2888 self.typeOf(ty_op.operand),
2889 self.typeOfIndex(inst),
3330 var ops = try cg.tempsFromOperands(inst, .{ty_op.operand});
3331 try ops[0].toOffset(cg.fieldOffset(
3332 cg.typeOf(ty_op.operand),
3333 cg.typeOfIndex(inst),
28903334 3,
2891 ), self);
2892 try ops[0].moveTo(inst, self);
3335 ), cg);
3336 try ops[0].moveTo(inst, cg);
28933337 },
2894 .slice => if (use_old) try self.airSlice(inst) else {
3338 .slice => if (use_old) try cg.airSlice(inst) else {
28953339 const ty_pl = air_datas[@intFromEnum(inst)].ty_pl;
2896 const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data;
2897 var ops = try self.tempsFromOperands(inst, .{ bin_op.lhs, bin_op.rhs });
2898 try ops[0].toPair(&ops[1], self);
2899 try ops[0].moveTo(inst, self);
3340 const bin_op = cg.air.extraData(Air.Bin, ty_pl.payload).data;
3341 var ops = try cg.tempsFromOperands(inst, .{ bin_op.lhs, bin_op.rhs });
3342 try ops[0].toPair(&ops[1], cg);
3343 try ops[0].moveTo(inst, cg);
29003344 },
2901 .slice_len => if (use_old) try self.airSliceLen(inst) else {
3345 .slice_len => if (use_old) try cg.airSliceLen(inst) else {
29023346 const ty_op = air_datas[@intFromEnum(inst)].ty_op;
2903 var ops = try self.tempsFromOperands(inst, .{ty_op.operand});
2904 try ops[0].toLimb(1, self);
2905 try ops[0].moveTo(inst, self);
3347 var ops = try cg.tempsFromOperands(inst, .{ty_op.operand});
3348 try ops[0].toLimb(1, cg);
3349 try ops[0].moveTo(inst, cg);
29063350 },
2907 .slice_ptr => if (use_old) try self.airSlicePtr(inst) else {
3351 .slice_ptr => if (use_old) try cg.airSlicePtr(inst) else {
29083352 const ty_op = air_datas[@intFromEnum(inst)].ty_op;
2909 var ops = try self.tempsFromOperands(inst, .{ty_op.operand});
2910 try ops[0].toLimb(0, self);
2911 try ops[0].moveTo(inst, self);
3353 var ops = try cg.tempsFromOperands(inst, .{ty_op.operand});
3354 try ops[0].toLimb(0, cg);
3355 try ops[0].moveTo(inst, cg);
29123356 },
2913 .ptr_slice_len_ptr => if (use_old) try self.airPtrSliceLenPtr(inst) else {
3357 .ptr_slice_len_ptr => if (use_old) try cg.airPtrSliceLenPtr(inst) else {
29143358 const ty_op = air_datas[@intFromEnum(inst)].ty_op;
2915 var ops = try self.tempsFromOperands(inst, .{ty_op.operand});
2916 try ops[0].toOffset(8, self);
2917 try ops[0].moveTo(inst, self);
3359 var ops = try cg.tempsFromOperands(inst, .{ty_op.operand});
3360 try ops[0].toOffset(8, cg);
3361 try ops[0].moveTo(inst, cg);
29183362 },
2919 .ptr_slice_ptr_ptr => if (use_old) try self.airPtrSlicePtrPtr(inst) else {
3363 .ptr_slice_ptr_ptr => if (use_old) try cg.airPtrSlicePtrPtr(inst) else {
29203364 const ty_op = air_datas[@intFromEnum(inst)].ty_op;
2921 var ops = try self.tempsFromOperands(inst, .{ty_op.operand});
2922 try ops[0].toOffset(0, self);
2923 try ops[0].moveTo(inst, self);
3365 var ops = try cg.tempsFromOperands(inst, .{ty_op.operand});
3366 try ops[0].toOffset(0, cg);
3367 try ops[0].moveTo(inst, cg);
29243368 },
29253369 .slice_elem_ptr, .ptr_elem_ptr => |tag| if (use_old) switch (tag) {
29263370 else => unreachable,
2927 .slice_elem_ptr => try self.airSliceElemPtr(inst),
2928 .ptr_elem_ptr => try self.airPtrElemPtr(inst),
3371 .slice_elem_ptr => try cg.airSliceElemPtr(inst),
3372 .ptr_elem_ptr => try cg.airPtrElemPtr(inst),
29293373 } else {
29303374 const ty_pl = air_datas[@intFromEnum(inst)].ty_pl;
2931 const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data;
2932 var ops = try self.tempsFromOperands(inst, .{ bin_op.lhs, bin_op.rhs });
3375 const bin_op = cg.air.extraData(Air.Bin, ty_pl.payload).data;
3376 var ops = try cg.tempsFromOperands(inst, .{ bin_op.lhs, bin_op.rhs });
29333377 switch (tag) {
29343378 else => unreachable,
2935 .slice_elem_ptr => try ops[0].toLimb(0, self),
3379 .slice_elem_ptr => try ops[0].toLimb(0, cg),
29363380 .ptr_elem_ptr => {},
29373381 }
2938 const dst_ty = self.typeOfIndex(inst);
3382 const dst_ty = cg.typeOfIndex(inst);
29393383 if (dst_ty.ptrInfo(zcu).flags.vector_index == .none) zero_offset: {
29403384 const elem_size = dst_ty.childType(zcu).abiSize(zcu);
29413385 if (elem_size == 0) break :zero_offset;
29423386 while (true) for (&ops) |*op| {
2943 if (try op.toAnyReg(self)) break;
3387 if (try op.toAnyReg(cg)) break;
29443388 } else break;
2945 const lhs_reg = ops[0].unwrap(self).temp.tracking(self).short.register.to64();
2946 const rhs_reg = ops[1].unwrap(self).temp.tracking(self).short.register.to64();
3389 const lhs_reg = ops[0].unwrap(cg).temp.tracking(cg).short.register.to64();
3390 const rhs_reg = ops[1].unwrap(cg).temp.tracking(cg).short.register.to64();
29473391 if (!std.math.isPowerOfTwo(elem_size)) {
2948 try self.spillEflagsIfOccupied();
2949 try self.asmRegisterRegisterImmediate(
3392 try cg.spillEflagsIfOccupied();
3393 try cg.asmRegisterRegisterImmediate(
29503394 .{ .i_, .mul },
29513395 rhs_reg,
29523396 rhs_reg,
29533397 .u(elem_size),
29543398 );
2955 try self.asmRegisterMemory(.{ ._, .lea }, lhs_reg, .{
3399 try cg.asmRegisterMemory(.{ ._, .lea }, lhs_reg, .{
29563400 .base = .{ .reg = lhs_reg },
29573401 .mod = .{ .rm = .{ .size = .qword, .index = rhs_reg } },
29583402 });
29593403 } else if (elem_size > 8) {
2960 try self.spillEflagsIfOccupied();
2961 try self.asmRegisterImmediate(
3404 try cg.spillEflagsIfOccupied();
3405 try cg.asmRegisterImmediate(
29623406 .{ ._l, .sh },
29633407 rhs_reg,
29643408 .u(std.math.log2_int(u64, elem_size)),
29653409 );
2966 try self.asmRegisterMemory(.{ ._, .lea }, lhs_reg, .{
3410 try cg.asmRegisterMemory(.{ ._, .lea }, lhs_reg, .{
29673411 .base = .{ .reg = lhs_reg },
29683412 .mod = .{ .rm = .{ .size = .qword, .index = rhs_reg } },
29693413 });
2970 } else try self.asmRegisterMemory(.{ ._, .lea }, lhs_reg, .{
3414 } else try cg.asmRegisterMemory(.{ ._, .lea }, lhs_reg, .{
29713415 .base = .{ .reg = lhs_reg },
29723416 .mod = .{ .rm = .{
29733417 .size = .qword,
......@@ -2976,57 +3420,57 @@ fn genBody(self: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
29763420 } },
29773421 });
29783422 }
2979 try ops[1].die(self);
2980 try ops[0].moveTo(inst, self);
3423 try ops[1].die(cg);
3424 try ops[0].moveTo(inst, cg);
29813425 },
2982 .array_to_slice => if (use_old) try self.airArrayToSlice(inst) else {
3426 .array_to_slice => if (use_old) try cg.airArrayToSlice(inst) else {
29833427 const ty_op = air_datas[@intFromEnum(inst)].ty_op;
2984 var ops = try self.tempsFromOperands(inst, .{ty_op.operand});
2985 var len = try self.tempFromValue(Type.usize, .{
2986 .immediate = self.typeOf(ty_op.operand).childType(zcu).arrayLen(zcu),
3428 var ops = try cg.tempsFromOperands(inst, .{ty_op.operand});
3429 var len = try cg.tempFromValue(Type.usize, .{
3430 .immediate = cg.typeOf(ty_op.operand).childType(zcu).arrayLen(zcu),
29873431 });
2988 try ops[0].toPair(&len, self);
2989 try ops[0].moveTo(inst, self);
3432 try ops[0].toPair(&len, cg);
3433 try ops[0].moveTo(inst, cg);
29903434 },
2991 .error_set_has_value => return self.fail("TODO implement error_set_has_value", .{}),
2992 .field_parent_ptr => if (use_old) try self.airFieldParentPtr(inst) else {
3435 .error_set_has_value => return cg.fail("TODO implement error_set_has_value", .{}),
3436 .field_parent_ptr => if (use_old) try cg.airFieldParentPtr(inst) else {
29933437 const ty_pl = air_datas[@intFromEnum(inst)].ty_pl;
2994 const extra = self.air.extraData(Air.FieldParentPtr, ty_pl.payload).data;
2995 var ops = try self.tempsFromOperands(inst, .{extra.field_ptr});
2996 try ops[0].toOffset(-self.fieldOffset(
2997 self.typeOfIndex(inst),
2998 self.typeOf(extra.field_ptr),
3438 const extra = cg.air.extraData(Air.FieldParentPtr, ty_pl.payload).data;
3439 var ops = try cg.tempsFromOperands(inst, .{extra.field_ptr});
3440 try ops[0].toOffset(-cg.fieldOffset(
3441 cg.typeOfIndex(inst),
3442 cg.typeOf(extra.field_ptr),
29993443 extra.field_index,
3000 ), self);
3001 try ops[0].moveTo(inst, self);
3444 ), cg);
3445 try ops[0].moveTo(inst, cg);
30023446 },
30033447
3004 .is_named_enum_value => return self.fail("TODO implement is_named_enum_value", .{}),
3448 .is_named_enum_value => return cg.fail("TODO implement is_named_enum_value", .{}),
30053449
30063450 .wasm_memory_size => unreachable,
30073451 .wasm_memory_grow => unreachable,
30083452
30093453 .addrspace_cast => {
30103454 const ty_op = air_datas[@intFromEnum(inst)].ty_op;
3011 var ops = try self.tempsFromOperands(inst, .{ty_op.operand});
3012 try ops[0].moveTo(inst, self);
3455 var ops = try cg.tempsFromOperands(inst, .{ty_op.operand});
3456 try ops[0].moveTo(inst, cg);
30133457 },
30143458
3015 .vector_store_elem => return self.fail("TODO implement vector_store_elem", .{}),
3459 .vector_store_elem => return cg.fail("TODO implement vector_store_elem", .{}),
30163460
3017 .c_va_arg => try self.airVaArg(inst),
3018 .c_va_copy => try self.airVaCopy(inst),
3019 .c_va_end => try self.airVaEnd(inst),
3020 .c_va_start => try self.airVaStart(inst),
3461 .c_va_arg => try cg.airVaArg(inst),
3462 .c_va_copy => try cg.airVaCopy(inst),
3463 .c_va_end => try cg.airVaEnd(inst),
3464 .c_va_start => try cg.airVaStart(inst),
30213465
30223466 .work_item_id => unreachable,
30233467 .work_group_size => unreachable,
30243468 .work_group_id => unreachable,
30253469 }
3026 self.resetTemps();
3027 self.checkInvariantsAfterAirInst();
3470 cg.resetTemps();
3471 cg.checkInvariantsAfterAirInst();
30283472 }
3029 verbose_tracking_log.debug("{}", .{self.fmtTracking()});
3473 verbose_tracking_log.debug("{}", .{cg.fmtTracking()});
30303474}
30313475
30323476fn genLazy(self: *CodeGen, lazy_sym: link.File.LazySymbol) InnerError!void {
......@@ -3117,12 +3561,16 @@ fn freeReg(self: *CodeGen, reg: Register) !void {
31173561fn freeValue(self: *CodeGen, value: MCValue) !void {
31183562 switch (value) {
31193563 .register => |reg| try self.freeReg(reg),
3120 .register_pair => |regs| for (regs) |reg| try self.freeReg(reg),
3564 inline .register_pair,
3565 .register_triple,
3566 .register_quadruple,
3567 => |regs| for (regs) |reg| try self.freeReg(reg),
31213568 .register_offset, .indirect => |reg_off| try self.freeReg(reg_off.reg),
31223569 .register_overflow => |reg_ov| {
31233570 try self.freeReg(reg_ov.reg);
31243571 self.eflags_inst = null;
31253572 },
3573 .register_mask => |reg_mask| try self.freeReg(reg_mask.reg),
31263574 .eflags => self.eflags_inst = null,
31273575 else => {}, // TODO process stack allocation death
31283576 }
......@@ -3323,11 +3771,11 @@ fn allocRegOrMemAdvanced(self: *CodeGen, ty: Type, inst: ?Air.Inst.Index, reg_ok
33233771 },
33243772 .vector => switch (ty.childType(zcu).zigTypeTag(zcu)) {
33253773 .float => switch (ty.childType(zcu).floatBits(self.target.*)) {
3326 16, 32, 64, 128 => if (self.hasFeature(.avx)) 32 else 16,
3774 16, 32, 64, 128 => self.vectorSize(.float),
33273775 80 => break :need_mem,
33283776 else => unreachable,
33293777 },
3330 else => if (self.hasFeature(.avx)) 32 else 16,
3778 else => self.vectorSize(.int),
33313779 },
33323780 else => 8,
33333781 })) {
......@@ -3374,6 +3822,28 @@ fn regSetForType(self: *CodeGen, ty: Type) RegisterManager.RegisterBitSet {
33743822 return regSetForRegClass(self.regClassForType(ty));
33753823}
33763824
3825fn vectorSize(cg: *CodeGen, kind: enum { int, float }) u6 {
3826 return if (cg.hasFeature(switch (kind) {
3827 .int => .avx2,
3828 .float => .avx,
3829 })) 32 else if (cg.hasFeature(.sse)) 16 else 8;
3830}
3831
3832fn limbType(cg: *CodeGen, ty: Type) Type {
3833 const pt = cg.pt;
3834 const zcu = pt.zcu;
3835 const vector_size = cg.vectorSize(if (ty.isRuntimeFloat()) .float else .int);
3836 const scalar_ty, const scalar_size = scalar: {
3837 const scalar_ty = ty.scalarType(zcu);
3838 const scalar_size = scalar_ty.abiSize(zcu);
3839 if (scalar_size <= vector_size) break :scalar .{ scalar_ty, scalar_size };
3840 };
3841 pt.vectorType(.{
3842 .len = @divExact(vector_size, scalar_size),
3843 .child = scalar_ty.toIntern(),
3844 });
3845}
3846
33773847const State = struct {
33783848 registers: RegisterManager.TrackedRegisters,
33793849 reg_tracking: [RegisterManager.RegisterBitSet.bit_length]InstTracking,
......@@ -3639,7 +4109,7 @@ fn airFptrunc(self: *CodeGen, inst: Air.Inst.Index) !void {
36394109 }
36404110 } else {
36414111 assert(src_bits == 64 and dst_bits == 32);
3642 if (self.hasFeature(.avx)) if (src_mcv.isMemory()) try self.asmRegisterRegisterMemory(
4112 if (self.hasFeature(.avx)) if (src_mcv.isBase()) try self.asmRegisterRegisterMemory(
36434113 .{ .v_ss, .cvtsd2 },
36444114 dst_reg,
36454115 dst_reg,
......@@ -3652,7 +4122,7 @@ fn airFptrunc(self: *CodeGen, inst: Air.Inst.Index) !void {
36524122 src_mcv.getReg().?
36534123 else
36544124 try self.copyToTmpRegister(src_ty, src_mcv)).to128(),
3655 ) else if (src_mcv.isMemory()) try self.asmRegisterMemory(
4125 ) else if (src_mcv.isBase()) try self.asmRegisterMemory(
36564126 .{ ._ss, .cvtsd2 },
36574127 dst_reg,
36584128 try src_mcv.mem(self, .{ .size = .qword }),
......@@ -3751,7 +4221,7 @@ fn airFpext(self: *CodeGen, inst: Air.Inst.Index) !void {
37514221 } else {
37524222 assert(src_bits == 32 and dst_bits == 64);
37534223 if (self.hasFeature(.avx)) switch (vec_len) {
3754 1 => if (src_mcv.isMemory()) try self.asmRegisterRegisterMemory(
4224 1 => if (src_mcv.isBase()) try self.asmRegisterRegisterMemory(
37554225 .{ .v_sd, .cvtss2 },
37564226 dst_alias,
37574227 dst_alias,
......@@ -3765,7 +4235,7 @@ fn airFpext(self: *CodeGen, inst: Air.Inst.Index) !void {
37654235 else
37664236 try self.copyToTmpRegister(src_ty, src_mcv), src_abi_size),
37674237 ),
3768 2...4 => if (src_mcv.isMemory()) try self.asmRegisterMemory(
4238 2...4 => if (src_mcv.isBase()) try self.asmRegisterMemory(
37694239 .{ .v_pd, .cvtps2 },
37704240 dst_alias,
37714241 try src_mcv.mem(self, .{ .size = self.memSize(src_ty) }),
......@@ -3778,7 +4248,7 @@ fn airFpext(self: *CodeGen, inst: Air.Inst.Index) !void {
37784248 try self.copyToTmpRegister(src_ty, src_mcv), src_abi_size),
37794249 ),
37804250 else => break :result null,
3781 } else if (src_mcv.isMemory()) try self.asmRegisterMemory(
4251 } else if (src_mcv.isBase()) try self.asmRegisterMemory(
37824252 switch (vec_len) {
37834253 1 => .{ ._sd, .cvtss2 },
37844254 2 => .{ ._pd, .cvtps2 },
......@@ -3827,7 +4297,7 @@ fn airIntCast(self: *CodeGen, inst: Air.Inst.Index) !void {
38274297 if (dst_ty.isVector(zcu)) {
38284298 const src_abi_size: u32 = @intCast(src_ty.abiSize(zcu));
38294299 const max_abi_size = @max(dst_abi_size, src_abi_size);
3830 if (max_abi_size > @as(u32, if (self.hasFeature(.avx2)) 32 else 16)) break :result null;
4300 if (max_abi_size > self.vectorSize(.int)) break :result null;
38314301 const has_avx = self.hasFeature(.avx);
38324302
38334303 const dst_elem_abi_size = dst_ty.childType(zcu).abiSize(zcu);
......@@ -3919,7 +4389,7 @@ fn airIntCast(self: *CodeGen, inst: Air.Inst.Index) !void {
39194389 const dst_reg = dst_mcv.getReg().?;
39204390 const dst_alias = registerAlias(dst_reg, dst_abi_size);
39214391
3922 if (src_mcv.isMemory()) try self.asmRegisterMemory(
4392 if (src_mcv.isBase()) try self.asmRegisterMemory(
39234393 mir_tag,
39244394 dst_alias,
39254395 try src_mcv.mem(self, .{ .size = self.memSize(src_ty) }),
......@@ -4017,7 +4487,7 @@ fn airIntCast(self: *CodeGen, inst: Air.Inst.Index) !void {
40174487 const src_limbs_len = std.math.divCeil(u16, src_int_info.bits, 64) catch unreachable;
40184488 const dst_limbs_len = std.math.divCeil(u16, dst_int_info.bits, 64) catch unreachable;
40194489
4020 const high_mcv: MCValue = if (dst_mcv.isMemory())
4490 const high_mcv: MCValue = if (dst_mcv.isBase())
40214491 dst_mcv.address().offset((src_limbs_len - 1) * 8).deref()
40224492 else
40234493 .{ .register = dst_mcv.register_pair[1] };
......@@ -4392,7 +4862,7 @@ fn airMulDivBinOp(self: *CodeGen, inst: Air.Inst.Index) !void {
43924862 else => null,
43934863 };
43944864 defer if (mat_lhs_lock) |lock| self.register_manager.unlockReg(lock);
4395 if (mat_lhs_mcv.isMemory()) try self.asmRegisterMemory(
4865 if (mat_lhs_mcv.isBase()) try self.asmRegisterMemory(
43964866 .{ ._, .mov },
43974867 tmp_reg,
43984868 try mat_lhs_mcv.address().offset(8).deref().mem(self, .{ .size = .qword }),
......@@ -4416,7 +4886,7 @@ fn airMulDivBinOp(self: *CodeGen, inst: Air.Inst.Index) !void {
44164886 else => null,
44174887 };
44184888 defer if (mat_rhs_lock) |lock| self.register_manager.unlockReg(lock);
4419 if (mat_rhs_mcv.isMemory()) try self.asmRegisterMemory(
4889 if (mat_rhs_mcv.isBase()) try self.asmRegisterMemory(
44204890 .{ ._, .xor },
44214891 tmp_reg,
44224892 try mat_rhs_mcv.address().offset(8).deref().mem(self, .{ .size = .qword }),
......@@ -4518,7 +4988,7 @@ fn airMulDivBinOp(self: *CodeGen, inst: Air.Inst.Index) !void {
45184988
45194989 for (tmp_regs, dst_regs) |tmp_reg, dst_reg|
45204990 try self.asmRegisterRegister(.{ ._, .mov }, tmp_reg, dst_reg);
4521 if (mat_rhs_mcv.isMemory()) {
4991 if (mat_rhs_mcv.isBase()) {
45224992 try self.asmRegisterMemory(
45234993 .{ ._, .add },
45244994 tmp_regs[0],
......@@ -4793,7 +5263,7 @@ fn airMulSat(self: *CodeGen, inst: Air.Inst.Index) !void {
47935263 else => null,
47945264 };
47955265 defer if (mat_lhs_lock) |lock| self.register_manager.unlockReg(lock);
4796 if (mat_lhs_mcv.isMemory()) try self.asmRegisterMemory(
5266 if (mat_lhs_mcv.isBase()) try self.asmRegisterMemory(
47975267 .{ ._, .mov },
47985268 tmp_reg,
47995269 try mat_lhs_mcv.address().offset(8).deref().mem(self, .{ .size = .qword }),
......@@ -4817,7 +5287,7 @@ fn airMulSat(self: *CodeGen, inst: Air.Inst.Index) !void {
48175287 else => null,
48185288 };
48195289 defer if (mat_rhs_lock) |lock| self.register_manager.unlockReg(lock);
4820 if (mat_rhs_mcv.isMemory()) try self.asmRegisterMemory(
5290 if (mat_rhs_mcv.isBase()) try self.asmRegisterMemory(
48215291 .{ ._, .xor },
48225292 tmp_reg,
48235293 try mat_rhs_mcv.address().offset(8).deref().mem(self, .{ .size = .qword }),
......@@ -5348,7 +5818,7 @@ fn airMulWithOverflow(self: *CodeGen, inst: Air.Inst.Index) !void {
53485818 };
53495819 defer if (mat_rhs_lock) |lock| self.register_manager.unlockReg(lock);
53505820
5351 if (mat_lhs_mcv.isMemory()) try self.asmRegisterMemory(
5821 if (mat_lhs_mcv.isBase()) try self.asmRegisterMemory(
53525822 .{ ._, .mov },
53535823 .rax,
53545824 try mat_lhs_mcv.mem(self, .{ .size = .qword }),
......@@ -5357,7 +5827,7 @@ fn airMulWithOverflow(self: *CodeGen, inst: Air.Inst.Index) !void {
53575827 .rax,
53585828 mat_lhs_mcv.register_pair[0],
53595829 );
5360 if (mat_rhs_mcv.isMemory()) try self.asmRegisterMemory(
5830 if (mat_rhs_mcv.isBase()) try self.asmRegisterMemory(
53615831 .{ ._, .mov },
53625832 tmp_regs[0],
53635833 try mat_rhs_mcv.address().offset(8).deref().mem(self, .{ .size = .qword }),
......@@ -5370,14 +5840,14 @@ fn airMulWithOverflow(self: *CodeGen, inst: Air.Inst.Index) !void {
53705840 try self.asmSetccRegister(.nz, tmp_regs[1].to8());
53715841 try self.asmRegisterRegister(.{ .i_, .mul }, tmp_regs[0], .rax);
53725842 try self.asmSetccRegister(.o, tmp_regs[2].to8());
5373 if (mat_rhs_mcv.isMemory())
5843 if (mat_rhs_mcv.isBase())
53745844 try self.asmMemory(.{ ._, .mul }, try mat_rhs_mcv.mem(self, .{ .size = .qword }))
53755845 else
53765846 try self.asmRegister(.{ ._, .mul }, mat_rhs_mcv.register_pair[0]);
53775847 try self.asmRegisterRegister(.{ ._, .add }, .rdx, tmp_regs[0]);
53785848 try self.asmSetccRegister(.c, tmp_regs[3].to8());
53795849 try self.asmRegisterRegister(.{ ._, .@"or" }, tmp_regs[2].to8(), tmp_regs[3].to8());
5380 if (mat_lhs_mcv.isMemory()) try self.asmRegisterMemory(
5850 if (mat_lhs_mcv.isBase()) try self.asmRegisterMemory(
53815851 .{ ._, .mov },
53825852 tmp_regs[0],
53835853 try mat_lhs_mcv.address().offset(8).deref().mem(self, .{ .size = .qword }),
......@@ -5394,7 +5864,7 @@ fn airMulWithOverflow(self: *CodeGen, inst: Air.Inst.Index) !void {
53945864 tmp_regs[3].to8(),
53955865 );
53965866 try self.asmRegisterRegister(.{ ._, .@"or" }, tmp_regs[1].to8(), tmp_regs[2].to8());
5397 if (mat_rhs_mcv.isMemory()) try self.asmRegisterMemory(
5867 if (mat_rhs_mcv.isBase()) try self.asmRegisterMemory(
53985868 .{ .i_, .mul },
53995869 tmp_regs[0],
54005870 try mat_rhs_mcv.mem(self, .{ .size = .qword }),
......@@ -6512,7 +6982,7 @@ fn airArrayElemVal(self: *CodeGen, inst: Air.Inst.Index) !void {
65126982
65136983 const index_ty = self.typeOf(bin_op.rhs);
65146984 const index_mcv = try self.resolveInst(bin_op.rhs);
6515 const index_lock: ?RegisterLock = switch (index_mcv) {
6985 const index_lock = switch (index_mcv) {
65166986 .register => |reg| self.register_manager.lockRegAssumeUnused(reg),
65176987 else => null,
65186988 };
......@@ -6520,48 +6990,102 @@ fn airArrayElemVal(self: *CodeGen, inst: Air.Inst.Index) !void {
65206990
65216991 try self.spillEflagsIfOccupied();
65226992 if (array_ty.isVector(zcu) and elem_ty.bitSize(zcu) == 1) {
6523 const index_reg = switch (index_mcv) {
6524 .register => |reg| reg,
6525 else => try self.copyToTmpRegister(index_ty, index_mcv),
6993 const array_mat_mcv: MCValue = switch (array_mcv) {
6994 else => array_mcv,
6995 .register_mask => .{ .register = try self.copyToTmpRegister(array_ty, array_mcv) },
65266996 };
6527 switch (array_mcv) {
6997 const array_mat_lock = switch (array_mat_mcv) {
6998 .register => |reg| self.register_manager.lockReg(reg),
6999 else => null,
7000 };
7001 defer if (array_mat_lock) |lock| self.register_manager.unlockReg(lock);
7002
7003 switch (array_mat_mcv) {
65287004 .register => |array_reg| switch (array_reg.class()) {
6529 .general_purpose => try self.asmRegisterRegister(
6530 .{ ._, .bt },
6531 array_reg.to64(),
6532 index_reg.to64(),
6533 ),
7005 .general_purpose => switch (index_mcv) {
7006 .immediate => |index_imm| try self.asmRegisterImmediate(
7007 .{ ._, .bt },
7008 array_reg.to64(),
7009 .u(index_imm),
7010 ),
7011 else => try self.asmRegisterRegister(
7012 .{ ._, .bt },
7013 array_reg.to64(),
7014 switch (index_mcv) {
7015 .register => |index_reg| index_reg,
7016 else => try self.copyToTmpRegister(index_ty, index_mcv),
7017 }.to64(),
7018 ),
7019 },
65347020 .sse => {
65357021 const frame_index = try self.allocFrameIndex(.initType(array_ty, zcu));
6536 try self.genSetMem(.{ .frame = frame_index }, 0, array_ty, array_mcv, .{});
6537 try self.asmMemoryRegister(
6538 .{ ._, .bt },
6539 .{
6540 .base = .{ .frame = frame_index },
6541 .mod = .{ .rm = .{ .size = .qword } },
6542 },
6543 index_reg.to64(),
6544 );
7022 try self.genSetMem(.{ .frame = frame_index }, 0, array_ty, array_mat_mcv, .{});
7023 switch (index_mcv) {
7024 .immediate => |index_imm| try self.asmMemoryImmediate(
7025 .{ ._, .bt },
7026 .{
7027 .base = .{ .frame = frame_index },
7028 .mod = .{ .rm = .{ .size = .qword } },
7029 },
7030 .u(index_imm),
7031 ),
7032 else => try self.asmMemoryRegister(
7033 .{ ._, .bt },
7034 .{
7035 .base = .{ .frame = frame_index },
7036 .mod = .{ .rm = .{ .size = .qword } },
7037 },
7038 switch (index_mcv) {
7039 .register => |index_reg| index_reg,
7040 else => try self.copyToTmpRegister(index_ty, index_mcv),
7041 }.to64(),
7042 ),
7043 }
65457044 },
65467045 else => unreachable,
65477046 },
6548 .load_frame => try self.asmMemoryRegister(
6549 .{ ._, .bt },
6550 try array_mcv.mem(self, .{ .size = .qword }),
6551 index_reg.to64(),
6552 ),
6553 .memory, .load_symbol, .load_direct, .load_got, .load_tlv => try self.asmMemoryRegister(
6554 .{ ._, .bt },
6555 .{
6556 .base = .{
6557 .reg = try self.copyToTmpRegister(Type.usize, array_mcv.address()),
7047 .load_frame => switch (index_mcv) {
7048 .immediate => |index_imm| try self.asmMemoryImmediate(
7049 .{ ._, .bt },
7050 try array_mat_mcv.mem(self, .{ .size = .qword }),
7051 .u(index_imm),
7052 ),
7053 else => try self.asmMemoryRegister(
7054 .{ ._, .bt },
7055 try array_mat_mcv.mem(self, .{ .size = .qword }),
7056 switch (index_mcv) {
7057 .register => |index_reg| index_reg,
7058 else => try self.copyToTmpRegister(index_ty, index_mcv),
7059 }.to64(),
7060 ),
7061 },
7062 .memory, .load_symbol, .load_direct, .load_got, .load_tlv => switch (index_mcv) {
7063 .immediate => |index_imm| try self.asmMemoryImmediate(
7064 .{ ._, .bt },
7065 .{
7066 .base = .{
7067 .reg = try self.copyToTmpRegister(Type.usize, array_mat_mcv.address()),
7068 },
7069 .mod = .{ .rm = .{ .size = .qword } },
65587070 },
6559 .mod = .{ .rm = .{ .size = .qword } },
6560 },
6561 index_reg.to64(),
6562 ),
7071 .u(index_imm),
7072 ),
7073 else => try self.asmMemoryRegister(
7074 .{ ._, .bt },
7075 .{
7076 .base = .{
7077 .reg = try self.copyToTmpRegister(Type.usize, array_mat_mcv.address()),
7078 },
7079 .mod = .{ .rm = .{ .size = .qword } },
7080 },
7081 switch (index_mcv) {
7082 .register => |index_reg| index_reg,
7083 else => try self.copyToTmpRegister(index_ty, index_mcv),
7084 }.to64(),
7085 ),
7086 },
65637087 else => return self.fail("TODO airArrayElemVal for {s} of {}", .{
6564 @tagName(array_mcv), array_ty.fmt(pt),
7088 @tagName(array_mat_mcv), array_ty.fmt(pt),
65657089 }),
65667090 }
65677091
......@@ -6856,6 +7380,15 @@ fn airClz(self: *CodeGen, inst: Air.Inst.Index) !void {
68567380 const src_bits: u31 = @intCast(src_ty.bitSize(zcu));
68577381 const has_lzcnt = self.hasFeature(.lzcnt);
68587382 if (src_bits > @as(u32, if (has_lzcnt) 128 else 64)) {
7383 const src_frame_addr: bits.FrameAddr = src_frame_addr: switch (src_mcv) {
7384 .load_frame => |src_frame_addr| src_frame_addr,
7385 else => {
7386 const src_frame_addr = try self.allocFrameIndex(.initSpill(src_ty, zcu));
7387 try self.genSetMem(.{ .frame = src_frame_addr }, 0, src_ty, src_mcv, .{});
7388 break :src_frame_addr .{ .index = src_frame_addr };
7389 },
7390 };
7391
68597392 const limbs_len = std.math.divCeil(u32, abi_size, 8) catch unreachable;
68607393 const extra_bits = abi_size * 8 - src_bits;
68617394
......@@ -6881,22 +7414,22 @@ fn airClz(self: *CodeGen, inst: Air.Inst.Index) !void {
68817414 try self.asmRegister(.{ ._, .dec }, index_reg.to32());
68827415 }
68837416 try self.asmMemoryImmediate(.{ ._, .cmp }, .{
6884 .base = .{ .frame = src_mcv.load_frame.index },
7417 .base = .{ .frame = src_frame_addr.index },
68857418 .mod = .{ .rm = .{
68867419 .size = .qword,
68877420 .index = index_reg.to64(),
68887421 .scale = .@"8",
6889 .disp = src_mcv.load_frame.off,
7422 .disp = src_frame_addr.off,
68907423 } },
68917424 }, .u(0));
68927425 _ = try self.asmJccReloc(.e, loop);
68937426 try self.asmRegisterMemory(.{ ._, .bsr }, dst_reg.to64(), .{
6894 .base = .{ .frame = src_mcv.load_frame.index },
7427 .base = .{ .frame = src_frame_addr.index },
68957428 .mod = .{ .rm = .{
68967429 .size = .qword,
68977430 .index = index_reg.to64(),
68987431 .scale = .@"8",
6899 .disp = src_mcv.load_frame.off,
7432 .disp = src_frame_addr.off,
69007433 } },
69017434 });
69027435 self.performReloc(zero);
......@@ -6935,7 +7468,7 @@ fn airClz(self: *CodeGen, inst: Air.Inst.Index) !void {
69357468 .{ ._, .lzcnt },
69367469 Type.u64,
69377470 dst_mcv,
6938 if (mat_src_mcv.isMemory())
7471 if (mat_src_mcv.isBase())
69397472 mat_src_mcv
69407473 else
69417474 .{ .register = mat_src_mcv.register_pair[0] },
......@@ -6945,7 +7478,7 @@ fn airClz(self: *CodeGen, inst: Air.Inst.Index) !void {
69457478 .{ ._, .lzcnt },
69467479 Type.u64,
69477480 tmp_mcv,
6948 if (mat_src_mcv.isMemory())
7481 if (mat_src_mcv.isBase())
69497482 mat_src_mcv.address().offset(8).deref()
69507483 else
69517484 .{ .register = mat_src_mcv.register_pair[1] },
......@@ -7053,6 +7586,15 @@ fn airCtz(self: *CodeGen, inst: Air.Inst.Index) !void {
70537586 const src_bits: u31 = @intCast(src_ty.bitSize(zcu));
70547587 const has_bmi = self.hasFeature(.bmi);
70557588 if (src_bits > @as(u32, if (has_bmi) 128 else 64)) {
7589 const src_frame_addr: bits.FrameAddr = src_frame_addr: switch (src_mcv) {
7590 .load_frame => |src_frame_addr| src_frame_addr,
7591 else => {
7592 const src_frame_addr = try self.allocFrameIndex(.initSpill(src_ty, zcu));
7593 try self.genSetMem(.{ .frame = src_frame_addr }, 0, src_ty, src_mcv, .{});
7594 break :src_frame_addr .{ .index = src_frame_addr };
7595 },
7596 };
7597
70567598 const limbs_len = std.math.divCeil(u32, abi_size, 8) catch unreachable;
70577599 const extra_bits = abi_size * 8 - src_bits;
70587600
......@@ -7079,22 +7621,22 @@ fn airCtz(self: *CodeGen, inst: Air.Inst.Index) !void {
70797621 try self.asmRegisterImmediate(.{ ._, .cmp }, index_reg.to32(), .u(limbs_len));
70807622 const zero = try self.asmJccReloc(.nb, undefined);
70817623 try self.asmMemoryImmediate(.{ ._, .cmp }, .{
7082 .base = .{ .frame = src_mcv.load_frame.index },
7624 .base = .{ .frame = src_frame_addr.index },
70837625 .mod = .{ .rm = .{
70847626 .size = .qword,
70857627 .index = index_reg.to64(),
70867628 .scale = .@"8",
7087 .disp = src_mcv.load_frame.off,
7629 .disp = src_frame_addr.off,
70887630 } },
70897631 }, .u(0));
70907632 _ = try self.asmJccReloc(.e, loop);
70917633 try self.asmRegisterMemory(.{ ._, .bsf }, dst_reg.to64(), .{
7092 .base = .{ .frame = src_mcv.load_frame.index },
7634 .base = .{ .frame = src_frame_addr.index },
70937635 .mod = .{ .rm = .{
70947636 .size = .qword,
70957637 .index = index_reg.to64(),
70967638 .scale = .@"8",
7097 .disp = src_mcv.load_frame.off,
7639 .disp = src_frame_addr.off,
70987640 } },
70997641 });
71007642 self.performReloc(zero);
......@@ -7131,11 +7673,11 @@ fn airCtz(self: *CodeGen, inst: Air.Inst.Index) !void {
71317673 const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);
71327674 defer self.register_manager.unlockReg(tmp_lock);
71337675
7134 const lo_mat_src_mcv: MCValue = if (mat_src_mcv.isMemory())
7676 const lo_mat_src_mcv: MCValue = if (mat_src_mcv.isBase())
71357677 mat_src_mcv
71367678 else
71377679 .{ .register = mat_src_mcv.register_pair[0] };
7138 const hi_mat_src_mcv: MCValue = if (mat_src_mcv.isMemory())
7680 const hi_mat_src_mcv: MCValue = if (mat_src_mcv.isBase())
71397681 mat_src_mcv.address().offset(8).deref()
71407682 else
71417683 .{ .register = mat_src_mcv.register_pair[1] };
......@@ -7224,13 +7766,13 @@ fn airPopCount(self: *CodeGen, inst: Air.Inst.Index) !void {
72247766 const tmp_locks = self.register_manager.lockRegsAssumeUnused(2, tmp_regs);
72257767 defer for (tmp_locks) |lock| self.register_manager.unlockReg(lock);
72267768
7227 try self.genPopCount(tmp_regs[0], Type.usize, if (mat_src_mcv.isMemory())
7769 try self.genPopCount(tmp_regs[0], Type.usize, if (mat_src_mcv.isBase())
72287770 mat_src_mcv
72297771 else
72307772 .{ .register = mat_src_mcv.register_pair[0] }, false);
72317773 const src_info = src_ty.intInfo(zcu);
72327774 const hi_ty = try pt.intType(src_info.signedness, (src_info.bits - 1) % 64 + 1);
7233 try self.genPopCount(tmp_regs[1], hi_ty, if (mat_src_mcv.isMemory())
7775 try self.genPopCount(tmp_regs[1], hi_ty, if (mat_src_mcv.isBase())
72347776 mat_src_mcv.address().offset(8).deref()
72357777 else
72367778 .{ .register = mat_src_mcv.register_pair[1] }, false);
......@@ -7388,7 +7930,7 @@ fn genByteSwap(
73887930 defer for (dst_locks) |lock| self.register_manager.unlockReg(lock);
73897931
73907932 for (dst_regs, 0..) |dst_reg, limb_index| {
7391 if (src_mcv.isMemory()) {
7933 if (src_mcv.isBase()) {
73927934 try self.asmRegisterMemory(
73937935 .{ ._, if (has_movbe) .movbe else .mov },
73947936 dst_reg.to64(),
......@@ -7706,7 +8248,7 @@ fn floatSign(self: *CodeGen, inst: Air.Inst.Index, operand: Air.Inst.Ref, ty: Ty
77068248 .abs => try vec_ty.maxInt(pt, vec_ty),
77078249 else => unreachable,
77088250 });
7709 const sign_mem: Memory = if (sign_mcv.isMemory())
8251 const sign_mem: Memory = if (sign_mcv.isBase())
77108252 try sign_mcv.mem(self, .{ .size = .fromSize(abi_size) })
77118253 else
77128254 .{
......@@ -7888,7 +8430,7 @@ fn genRound(self: *CodeGen, ty: Type, dst_reg: Register, src_mcv: MCValue, mode:
78888430 const abi_size: u32 = @intCast(ty.abiSize(pt.zcu));
78898431 const dst_alias = registerAlias(dst_reg, abi_size);
78908432 switch (mir_tag[0]) {
7891 .v_ss, .v_sd => if (src_mcv.isMemory()) try self.asmRegisterRegisterMemoryImmediate(
8433 .v_ss, .v_sd => if (src_mcv.isBase()) try self.asmRegisterRegisterMemoryImmediate(
78928434 mir_tag,
78938435 dst_alias,
78948436 dst_alias,
......@@ -7904,7 +8446,7 @@ fn genRound(self: *CodeGen, ty: Type, dst_reg: Register, src_mcv: MCValue, mode:
79048446 try self.copyToTmpRegister(ty, src_mcv), abi_size),
79058447 .u(@as(u5, @bitCast(mode))),
79068448 ),
7907 else => if (src_mcv.isMemory()) try self.asmRegisterMemoryImmediate(
8449 else => if (src_mcv.isBase()) try self.asmRegisterMemoryImmediate(
79088450 mir_tag,
79098451 dst_alias,
79108452 try src_mcv.mem(self, .{ .size = .fromSize(abi_size) }),
......@@ -8105,7 +8647,7 @@ fn airAbs(self: *CodeGen, inst: Air.Inst.Index) !void {
81058647 else
81068648 try self.register_manager.allocReg(inst, self.regSetForType(ty));
81078649 const dst_alias = registerAlias(dst_reg, abi_size);
8108 if (src_mcv.isMemory()) try self.asmRegisterMemory(
8650 if (src_mcv.isBase()) try self.asmRegisterMemory(
81098651 mir_tag,
81108652 dst_alias,
81118653 try src_mcv.mem(self, .{ .size = self.memSize(ty) }),
......@@ -8212,7 +8754,7 @@ fn airSqrt(self: *CodeGen, inst: Air.Inst.Index) !void {
82128754 },
82138755 2...8 => {
82148756 const wide_reg = registerAlias(dst_reg, abi_size * 2);
8215 if (src_mcv.isMemory()) try self.asmRegisterMemory(
8757 if (src_mcv.isBase()) try self.asmRegisterMemory(
82168758 .{ .v_ps, .cvtph2 },
82178759 wide_reg,
82188760 try src_mcv.mem(self, .{ .size = .fromSize(
......@@ -8257,7 +8799,7 @@ fn airSqrt(self: *CodeGen, inst: Air.Inst.Index) !void {
82578799 else => unreachable,
82588800 }) orelse return self.fail("TODO implement airSqrt for {}", .{ty.fmt(pt)});
82598801 switch (mir_tag[0]) {
8260 .v_ss, .v_sd => if (src_mcv.isMemory()) try self.asmRegisterRegisterMemory(
8802 .v_ss, .v_sd => if (src_mcv.isBase()) try self.asmRegisterRegisterMemory(
82618803 mir_tag,
82628804 dst_reg,
82638805 dst_reg,
......@@ -8271,7 +8813,7 @@ fn airSqrt(self: *CodeGen, inst: Air.Inst.Index) !void {
82718813 else
82728814 try self.copyToTmpRegister(ty, src_mcv), abi_size),
82738815 ),
8274 else => if (src_mcv.isMemory()) try self.asmRegisterMemory(
8816 else => if (src_mcv.isBase()) try self.asmRegisterMemory(
82758817 mir_tag,
82768818 dst_reg,
82778819 try src_mcv.mem(self, .{ .size = .fromSize(abi_size) }),
......@@ -8339,7 +8881,7 @@ fn reuseOperandAdvanced(
83398881 return false;
83408882
83418883 switch (mcv) {
8342 .register, .register_pair, .register_overflow => for (mcv.getRegs()) |reg| {
8884 .register, .register_pair, .register_overflow, .register_mask => for (mcv.getRegs()) |reg| {
83438885 // If it's in the registers table, need to associate the register(s) with the
83448886 // new instruction.
83458887 if (maybe_tracked_inst) |tracked_inst| {
......@@ -8486,7 +9028,10 @@ fn load(self: *CodeGen, dst_mcv: MCValue, ptr_ty: Type, ptr_mcv: MCValue) InnerE
84869028 .undef,
84879029 .eflags,
84889030 .register_pair,
9031 .register_triple,
9032 .register_quadruple,
84899033 .register_overflow,
9034 .register_mask,
84909035 .elementwise_regs_then_frame,
84919036 .reserved_frame,
84929037 => unreachable, // not a valid pointer
......@@ -8694,7 +9239,10 @@ fn store(
86949239 .undef,
86959240 .eflags,
86969241 .register_pair,
9242 .register_triple,
9243 .register_quadruple,
86979244 .register_overflow,
9245 .register_mask,
86989246 .elementwise_regs_then_frame,
86999247 .reserved_frame,
87009248 => unreachable, // not a valid pointer
......@@ -8986,7 +9534,7 @@ fn airStructFieldVal(self: *CodeGen, inst: Air.Inst.Index) !void {
89869534 try self.genCopy(field_ty, dst_mcv, off_mcv, .{});
89879535 break :dst dst_mcv;
89889536 };
8989 if (field_abi_size * 8 > field_bit_size and dst_mcv.isMemory()) {
9537 if (field_abi_size * 8 > field_bit_size and dst_mcv.isBase()) {
89909538 const tmp_reg = try self.register_manager.allocReg(null, abi.RegisterClass.gp);
89919539 const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);
89929540 defer self.register_manager.unlockReg(tmp_lock);
......@@ -9194,6 +9742,7 @@ fn genUnOpMir(self: *CodeGen, mir_tag: Mir.Inst.FixedTag, dst_ty: Type, dst_mcv:
91949742 .register_offset,
91959743 .eflags,
91969744 .register_overflow,
9745 .register_mask,
91979746 .lea_symbol,
91989747 .lea_direct,
91999748 .lea_got,
......@@ -9204,7 +9753,7 @@ fn genUnOpMir(self: *CodeGen, mir_tag: Mir.Inst.FixedTag, dst_ty: Type, dst_mcv:
92049753 .air_ref,
92059754 => unreachable, // unmodifiable destination
92069755 .register => |dst_reg| try self.asmRegister(mir_tag, registerAlias(dst_reg, abi_size)),
9207 .register_pair => unreachable, // unimplemented
9756 .register_pair, .register_triple, .register_quadruple => unreachable, // unimplemented
92089757 .memory, .load_symbol, .load_got, .load_direct, .load_tlv => {
92099758 const addr_reg = try self.register_manager.allocReg(null, abi.RegisterClass.gp);
92109759 const addr_reg_lock = self.register_manager.lockRegAssumeUnused(addr_reg);
......@@ -9974,27 +10523,27 @@ fn genMulDivBinOp(
997410523 const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);
997510524 defer self.register_manager.unlockReg(tmp_lock);
997610525
9977 if (mat_lhs_mcv.isMemory())
10526 if (mat_lhs_mcv.isBase())
997810527 try self.asmRegisterMemory(.{ ._, .mov }, .rax, try mat_lhs_mcv.mem(self, .{ .size = .qword }))
997910528 else
998010529 try self.asmRegisterRegister(.{ ._, .mov }, .rax, mat_lhs_mcv.register_pair[0]);
9981 if (mat_rhs_mcv.isMemory()) try self.asmRegisterMemory(
10530 if (mat_rhs_mcv.isBase()) try self.asmRegisterMemory(
998210531 .{ ._, .mov },
998310532 tmp_reg,
998410533 try mat_rhs_mcv.address().offset(8).deref().mem(self, .{ .size = .qword }),
998510534 ) else try self.asmRegisterRegister(.{ ._, .mov }, tmp_reg, mat_rhs_mcv.register_pair[1]);
998610535 try self.asmRegisterRegister(.{ .i_, .mul }, tmp_reg, .rax);
9987 if (mat_rhs_mcv.isMemory())
10536 if (mat_rhs_mcv.isBase())
998810537 try self.asmMemory(.{ ._, .mul }, try mat_rhs_mcv.mem(self, .{ .size = .qword }))
998910538 else
999010539 try self.asmRegister(.{ ._, .mul }, mat_rhs_mcv.register_pair[0]);
999110540 try self.asmRegisterRegister(.{ ._, .add }, .rdx, tmp_reg);
9992 if (mat_lhs_mcv.isMemory()) try self.asmRegisterMemory(
10541 if (mat_lhs_mcv.isBase()) try self.asmRegisterMemory(
999310542 .{ ._, .mov },
999410543 tmp_reg,
999510544 try mat_lhs_mcv.address().offset(8).deref().mem(self, .{ .size = .qword }),
999610545 ) else try self.asmRegisterRegister(.{ ._, .mov }, tmp_reg, mat_lhs_mcv.register_pair[1]);
9997 if (mat_rhs_mcv.isMemory())
10546 if (mat_rhs_mcv.isBase())
999810547 try self.asmRegisterMemory(.{ .i_, .mul }, tmp_reg, try mat_rhs_mcv.mem(self, .{ .size = .qword }))
999910548 else
1000010549 try self.asmRegisterRegister(.{ .i_, .mul }, tmp_reg, mat_rhs_mcv.register_pair[0]);
......@@ -10414,7 +10963,7 @@ fn genBinOp(
1041410963 const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);
1041510964 defer self.register_manager.unlockReg(tmp_lock);
1041610965
10417 if (rhs_mcv.isMemory()) try self.asmRegisterRegisterMemoryImmediate(
10966 if (rhs_mcv.isBase()) try self.asmRegisterRegisterMemoryImmediate(
1041810967 .{ .vp_w, .insr },
1041910968 dst_reg,
1042010969 dst_reg,
......@@ -10439,7 +10988,7 @@ fn genBinOp(
1043910988 64 => .{ .v_sd, .add },
1044010989 else => unreachable,
1044110990 };
10442 if (src_mcv.isMemory()) try self.asmRegisterRegisterMemory(
10991 if (src_mcv.isBase()) try self.asmRegisterRegisterMemory(
1044310992 mir_tag,
1044410993 dst_reg,
1044510994 dst_reg,
......@@ -10459,7 +11008,7 @@ fn genBinOp(
1045911008 64 => .{ ._sd, .add },
1046011009 else => unreachable,
1046111010 };
10462 if (src_mcv.isMemory()) try self.asmRegisterMemory(
11011 if (src_mcv.isBase()) try self.asmRegisterMemory(
1046311012 mir_tag,
1046411013 dst_reg,
1046511014 try src_mcv.mem(self, .{ .size = .fromBitSize(float_bits) }),
......@@ -10514,7 +11063,7 @@ fn genBinOp(
1051411063 };
1051511064 if (sse_op and ((lhs_ty.scalarType(zcu).isRuntimeFloat() and
1051611065 lhs_ty.scalarType(zcu).floatBits(self.target.*) == 80) or
10517 lhs_ty.abiSize(zcu) > @as(u6, if (self.hasFeature(.avx)) 32 else 16)))
11066 lhs_ty.abiSize(zcu) > self.vectorSize(.float)))
1051811067 return self.fail("TODO implement genBinOp for {s} {}", .{ @tagName(air_tag), lhs_ty.fmt(pt) });
1051911068
1052011069 const maybe_mask_reg = switch (air_tag) {
......@@ -10731,7 +11280,7 @@ fn genBinOp(
1073111280 };
1073211281
1073311282 try self.asmRegisterRegister(.{ ._, .mov }, tmp_reg, dst_regs[1]);
10734 if (src_mcv.isMemory()) {
11283 if (src_mcv.isBase()) {
1073511284 try self.asmRegisterMemory(
1073611285 .{ ._, .cmp },
1073711286 dst_regs[0],
......@@ -10828,8 +11377,11 @@ fn genBinOp(
1082811377 .immediate,
1082911378 .eflags,
1083011379 .register_pair,
11380 .register_triple,
11381 .register_quadruple,
1083111382 .register_offset,
1083211383 .register_overflow,
11384 .register_mask,
1083311385 .load_symbol,
1083411386 .lea_symbol,
1083511387 .load_direct,
......@@ -10909,7 +11461,7 @@ fn genBinOp(
1090911461 const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);
1091011462 defer self.register_manager.unlockReg(tmp_lock);
1091111463
10912 if (src_mcv.isMemory()) try self.asmRegisterRegisterMemoryImmediate(
11464 if (src_mcv.isBase()) try self.asmRegisterRegisterMemoryImmediate(
1091311465 .{ .vp_w, .insr },
1091411466 dst_reg,
1091511467 dst_reg,
......@@ -11355,7 +11907,7 @@ fn genBinOp(
1135511907 const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);
1135611908 defer self.register_manager.unlockReg(tmp_lock);
1135711909
11358 if (src_mcv.isMemory()) try self.asmRegisterRegisterMemoryImmediate(
11910 if (src_mcv.isBase()) try self.asmRegisterRegisterMemoryImmediate(
1135911911 .{ .vp_w, .insr },
1136011912 dst_reg,
1136111913 dst_reg,
......@@ -11402,7 +11954,7 @@ fn genBinOp(
1140211954 const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);
1140311955 defer self.register_manager.unlockReg(tmp_lock);
1140411956
11405 if (src_mcv.isMemory()) try self.asmRegisterMemoryImmediate(
11957 if (src_mcv.isBase()) try self.asmRegisterMemoryImmediate(
1140611958 .{ .vp_d, .insr },
1140711959 dst_reg,
1140811960 try src_mcv.mem(self, .{ .size = .dword }),
......@@ -11454,7 +12006,7 @@ fn genBinOp(
1145412006 defer self.register_manager.unlockReg(tmp_lock);
1145512007
1145612008 try self.asmRegisterRegister(.{ .v_ps, .cvtph2 }, dst_reg, dst_reg);
11457 if (src_mcv.isMemory()) try self.asmRegisterMemory(
12009 if (src_mcv.isBase()) try self.asmRegisterMemory(
1145812010 .{ .v_ps, .cvtph2 },
1145912011 tmp_reg,
1146012012 try src_mcv.mem(self, .{ .size = .qword }),
......@@ -11497,7 +12049,7 @@ fn genBinOp(
1149712049 defer self.register_manager.unlockReg(tmp_lock);
1149812050
1149912051 try self.asmRegisterRegister(.{ .v_ps, .cvtph2 }, dst_reg.to256(), dst_reg);
11500 if (src_mcv.isMemory()) try self.asmRegisterMemory(
12052 if (src_mcv.isBase()) try self.asmRegisterMemory(
1150112053 .{ .v_ps, .cvtph2 },
1150212054 tmp_reg,
1150312055 try src_mcv.mem(self, .{ .size = .xword }),
......@@ -11659,7 +12211,7 @@ fn genBinOp(
1165912211 else => if (self.hasFeature(.avx)) {
1166012212 const lhs_reg =
1166112213 if (copied_to_dst) dst_reg else registerAlias(lhs_mcv.getReg().?, abi_size);
11662 if (src_mcv.isMemory()) try self.asmRegisterRegisterMemory(
12214 if (src_mcv.isBase()) try self.asmRegisterRegisterMemory(
1166312215 mir_tag,
1166412216 dst_reg,
1166512217 lhs_reg,
......@@ -11678,7 +12230,7 @@ fn genBinOp(
1167812230 );
1167912231 } else {
1168012232 assert(copied_to_dst);
11681 if (src_mcv.isMemory()) try self.asmRegisterMemory(
12233 if (src_mcv.isBase()) try self.asmRegisterMemory(
1168212234 mir_tag,
1168312235 dst_reg,
1168412236 try src_mcv.mem(self, .{ .size = switch (lhs_ty.zigTypeTag(zcu)) {
......@@ -11705,7 +12257,7 @@ fn genBinOp(
1170512257 if (self.hasFeature(.avx)) {
1170612258 const lhs_reg =
1170712259 if (copied_to_dst) dst_reg else registerAlias(lhs_mcv.getReg().?, abi_size);
11708 if (src_mcv.isMemory()) try self.asmRegisterRegisterMemoryImmediate(
12260 if (src_mcv.isBase()) try self.asmRegisterRegisterMemoryImmediate(
1170912261 mir_tag,
1171012262 dst_reg,
1171112263 lhs_reg,
......@@ -11726,7 +12278,7 @@ fn genBinOp(
1172612278 );
1172712279 } else {
1172812280 assert(copied_to_dst);
11729 if (src_mcv.isMemory()) try self.asmRegisterMemoryImmediate(
12281 if (src_mcv.isBase()) try self.asmRegisterMemoryImmediate(
1173012282 mir_tag,
1173112283 dst_reg,
1173212284 try src_mcv.mem(self, .{ .size = switch (lhs_ty.zigTypeTag(zcu)) {
......@@ -11937,7 +12489,7 @@ fn genBinOp(
1193712489 => {
1193812490 const unsigned_ty = try lhs_ty.toUnsigned(pt);
1193912491 const not_mcv = try self.genTypedValue(try unsigned_ty.maxInt(pt, unsigned_ty));
11940 const not_mem: Memory = if (not_mcv.isMemory())
12492 const not_mem: Memory = if (not_mcv.isBase())
1194112493 try not_mcv.mem(self, .{ .size = .fromSize(abi_size) })
1194212494 else
1194312495 .{ .base = .{
......@@ -12017,6 +12569,7 @@ fn genBinOpMir(
1201712569 .immediate,
1201812570 .eflags,
1201912571 .register_overflow,
12572 .register_mask,
1202012573 .lea_direct,
1202112574 .lea_got,
1202212575 .lea_tlv,
......@@ -12026,9 +12579,9 @@ fn genBinOpMir(
1202612579 .reserved_frame,
1202712580 .air_ref,
1202812581 => unreachable, // unmodifiable destination
12029 .register, .register_pair, .register_offset => {
12582 .register, .register_pair, .register_triple, .register_quadruple, .register_offset => {
1203012583 switch (dst_mcv) {
12031 .register, .register_pair => {},
12584 .register, .register_pair, .register_triple, .register_quadruple => {},
1203212585 .register_offset => |ro| assert(ro.off == 0),
1203312586 else => unreachable,
1203412587 }
......@@ -12057,10 +12610,15 @@ fn genBinOpMir(
1205712610 .dead,
1205812611 .undef,
1205912612 .register_overflow,
12613 .register_mask,
1206012614 .elementwise_regs_then_frame,
1206112615 .reserved_frame,
1206212616 => unreachable,
12063 .register, .register_pair => try self.asmRegisterRegister(
12617 .register,
12618 .register_pair,
12619 .register_triple,
12620 .register_quadruple,
12621 => try self.asmRegisterRegister(
1206412622 mir_limb_tag,
1206512623 dst_alias,
1206612624 registerAlias(src_mcv.getRegs()[dst_reg_i], limb_abi_size),
......@@ -12216,6 +12774,7 @@ fn genBinOpMir(
1221612774 .dead,
1221712775 .undef,
1221812776 .register_overflow,
12777 .register_mask,
1221912778 .elementwise_regs_then_frame,
1222012779 .reserved_frame,
1222112780 .air_ref,
......@@ -12224,6 +12783,8 @@ fn genBinOpMir(
1222412783 .eflags,
1222512784 .register,
1222612785 .register_pair,
12786 .register_triple,
12787 .register_quadruple,
1222712788 .register_offset,
1222812789 .indirect,
1222912790 .lea_direct,
......@@ -12311,6 +12872,7 @@ fn genBinOpMir(
1231112872 .dead,
1231212873 .undef,
1231312874 .register_overflow,
12875 .register_mask,
1231412876 .elementwise_regs_then_frame,
1231512877 .reserved_frame,
1231612878 .air_ref,
......@@ -12364,6 +12926,8 @@ fn genBinOpMir(
1236412926 },
1236512927 .register,
1236612928 .register_pair,
12929 .register_triple,
12930 .register_quadruple,
1236712931 .register_offset,
1236812932 .eflags,
1236912933 .memory,
......@@ -12382,7 +12946,7 @@ fn genBinOpMir(
1238212946 const src_limb_mcv: MCValue = if (src_info) |info| .{
1238312947 .indirect = .{ .reg = info.addr_reg, .off = off },
1238412948 } else switch (resolved_src_mcv) {
12385 .register, .register_pair => .{
12949 .register, .register_pair, .register_triple, .register_quadruple => .{
1238612950 .register = resolved_src_mcv.getRegs()[limb_i],
1238712951 },
1238812952 .eflags,
......@@ -12438,6 +13002,7 @@ fn genIntMulComplexOpMir(self: *CodeGen, dst_ty: Type, dst_mcv: MCValue, src_mcv
1243813002 .eflags,
1243913003 .register_offset,
1244013004 .register_overflow,
13005 .register_mask,
1244113006 .lea_symbol,
1244213007 .lea_direct,
1244313008 .lea_got,
......@@ -12462,7 +13027,10 @@ fn genIntMulComplexOpMir(self: *CodeGen, dst_ty: Type, dst_mcv: MCValue, src_mcv
1246213027 .dead,
1246313028 .undef,
1246413029 .register_pair,
13030 .register_triple,
13031 .register_quadruple,
1246513032 .register_overflow,
13033 .register_mask,
1246613034 .elementwise_regs_then_frame,
1246713035 .reserved_frame,
1246813036 .air_ref,
......@@ -12539,7 +13107,7 @@ fn genIntMulComplexOpMir(self: *CodeGen, dst_ty: Type, dst_mcv: MCValue, src_mcv
1253913107 ),
1254013108 }
1254113109 },
12542 .register_pair => unreachable, // unimplemented
13110 .register_pair, .register_triple, .register_quadruple => unreachable, // unimplemented
1254313111 .memory, .indirect, .load_symbol, .load_direct, .load_got, .load_tlv, .load_frame => {
1254413112 const tmp_reg = try self.copyToTmpRegister(dst_ty, dst_mcv);
1254513113 const tmp_mcv = MCValue{ .register = tmp_reg };
......@@ -12892,7 +13460,7 @@ fn genCall(self: *CodeGen, info: union(enum) {
1289213460 const index_lock = self.register_manager.lockRegAssumeUnused(index_reg);
1289313461 defer self.register_manager.unlockReg(index_lock);
1289413462
12895 const src_mem: Memory = if (src_arg.isMemory()) try src_arg.mem(self, .{ .size = .dword }) else .{
13463 const src_mem: Memory = if (src_arg.isBase()) try src_arg.mem(self, .{ .size = .dword }) else .{
1289613464 .base = .{ .reg = try self.copyToTmpRegister(
1289713465 Type.usize,
1289813466 switch (src_arg) {
......@@ -12984,7 +13552,7 @@ fn genCall(self: *CodeGen, info: union(enum) {
1298413552 .lea_frame = .{ .index = frame_index, .off = -reg_off.off },
1298513553 }, .{}),
1298613554 .elementwise_regs_then_frame => |regs_frame_addr| {
12987 const src_mem: Memory = if (src_arg.isMemory()) try src_arg.mem(self, .{ .size = .dword }) else .{
13555 const src_mem: Memory = if (src_arg.isBase()) try src_arg.mem(self, .{ .size = .dword }) else .{
1298813556 .base = .{ .reg = try self.copyToTmpRegister(
1298913557 Type.usize,
1299013558 switch (src_arg) {
......@@ -13100,6 +13668,8 @@ fn airRet(self: *CodeGen, inst: Air.Inst.Index, safety: bool) !void {
1310013668 .none => {},
1310113669 .register,
1310213670 .register_pair,
13671 .register_triple,
13672 .register_quadruple,
1310313673 => try self.genCopy(ret_ty, self.ret_mcv.short, .{ .air_ref = un_op }, .{ .safety = safety }),
1310413674 .indirect => |reg_off| {
1310513675 try self.register_manager.getReg(reg_off.reg, null);
......@@ -13226,7 +13796,7 @@ fn airCmp(self: *CodeGen, inst: Air.Inst.Index, op: std.math.CompareOperator) !v
1322613796 const temp_lhs_lock = self.register_manager.lockRegAssumeUnused(temp_lhs_reg);
1322713797 defer self.register_manager.unlockReg(temp_lhs_lock);
1322813798
13229 if (lhs_mcv.isMemory()) try self.asmRegisterMemory(
13799 if (lhs_mcv.isBase()) try self.asmRegisterMemory(
1323013800 .{ ._, .mov },
1323113801 temp_lhs_reg.to8(),
1323213802 try lhs_mcv.address().offset(payload_abi_size).deref().mem(self, .{ .size = .byte }),
......@@ -13240,7 +13810,7 @@ fn airCmp(self: *CodeGen, inst: Air.Inst.Index, op: std.math.CompareOperator) !v
1324013810 }
1324113811
1324213812 const payload_compare = payload_compare: {
13243 if (rhs_mcv.isMemory()) {
13813 if (rhs_mcv.isBase()) {
1324413814 const rhs_mem =
1324513815 try rhs_mcv.address().offset(payload_abi_size).deref().mem(self, .{ .size = .byte });
1324613816 try self.asmMemoryRegister(.{ ._, .@"test" }, rhs_mem, temp_lhs_reg.to8());
......@@ -13291,13 +13861,13 @@ fn airCmp(self: *CodeGen, inst: Air.Inst.Index, op: std.math.CompareOperator) !v
1329113861 } else .may_flip;
1329213862
1329313863 const flipped = switch (may_flip) {
13294 .may_flip => !lhs_mcv.isRegister() and !lhs_mcv.isMemory(),
13864 .may_flip => !lhs_mcv.isRegister() and !lhs_mcv.isBase(),
1329513865 .must_flip => true,
1329613866 .must_not_flip => false,
1329713867 };
1329813868 const unmat_dst_mcv = if (flipped) rhs_mcv else lhs_mcv;
1329913869 const dst_mcv = if (unmat_dst_mcv.isRegister() or
13300 (abi_size <= 8 and unmat_dst_mcv.isMemory())) unmat_dst_mcv else dst: {
13870 (abi_size <= 8 and unmat_dst_mcv.isBase())) unmat_dst_mcv else dst: {
1330113871 const dst_mcv = try self.allocTempRegOrMem(ty, true);
1330213872 try self.genCopy(ty, dst_mcv, unmat_dst_mcv, .{});
1330313873 break :dst dst_mcv;
......@@ -13335,6 +13905,7 @@ fn airCmp(self: *CodeGen, inst: Air.Inst.Index, op: std.math.CompareOperator) !v
1333513905 .register,
1333613906 .register_offset,
1333713907 .register_overflow,
13908 .register_mask,
1333813909 .indirect,
1333913910 .lea_direct,
1334013911 .lea_got,
......@@ -13345,7 +13916,7 @@ fn airCmp(self: *CodeGen, inst: Air.Inst.Index, op: std.math.CompareOperator) !v
1334513916 .reserved_frame,
1334613917 .air_ref,
1334713918 => unreachable,
13348 .register_pair, .load_frame => null,
13919 .register_pair, .register_triple, .register_quadruple, .load_frame => null,
1334913920 .memory, .load_symbol, .load_got, .load_direct, .load_tlv => dst: {
1335013921 switch (resolved_dst_mcv) {
1335113922 .memory => |addr| if (std.math.cast(
......@@ -13396,6 +13967,7 @@ fn airCmp(self: *CodeGen, inst: Air.Inst.Index, op: std.math.CompareOperator) !v
1339613967 .register,
1339713968 .register_offset,
1339813969 .register_overflow,
13970 .register_mask,
1339913971 .indirect,
1340013972 .lea_symbol,
1340113973 .lea_direct,
......@@ -13406,7 +13978,7 @@ fn airCmp(self: *CodeGen, inst: Air.Inst.Index, op: std.math.CompareOperator) !v
1340613978 .reserved_frame,
1340713979 .air_ref,
1340813980 => unreachable,
13409 .register_pair, .load_frame => null,
13981 .register_pair, .register_triple, .register_quadruple, .load_frame => null,
1341013982 .memory, .load_symbol, .load_got, .load_direct, .load_tlv => src: {
1341113983 switch (resolved_src_mcv) {
1341213984 .memory => |addr| if (std.math.cast(
......@@ -13457,7 +14029,10 @@ fn airCmp(self: *CodeGen, inst: Air.Inst.Index, op: std.math.CompareOperator) !v
1345714029 try self.genSetReg(tmp_reg, Type.usize, if (dst_info) |info| .{
1345814030 .indirect = .{ .reg = info.addr_reg, .off = off },
1345914031 } else switch (resolved_dst_mcv) {
13460 .register_pair => |dst_regs| .{ .register = dst_regs[limb_i] },
14032 inline .register_pair,
14033 .register_triple,
14034 .register_quadruple,
14035 => |dst_regs| .{ .register = dst_regs[limb_i] },
1346114036 .memory => |dst_addr| .{
1346214037 .memory = @bitCast(@as(i64, @bitCast(dst_addr)) + off),
1346314038 },
......@@ -13479,9 +14054,10 @@ fn airCmp(self: *CodeGen, inst: Air.Inst.Index, op: std.math.CompareOperator) !v
1347914054 if (src_info) |info| .{
1348014055 .indirect = .{ .reg = info.addr_reg, .off = off },
1348114056 } else switch (resolved_src_mcv) {
13482 .register_pair => |src_regs| .{
13483 .register = src_regs[limb_i],
13484 },
14057 inline .register_pair,
14058 .register_triple,
14059 .register_quadruple,
14060 => |src_regs| .{ .register = src_regs[limb_i] },
1348514061 .memory => |src_addr| .{
1348614062 .memory = @bitCast(@as(i64, @bitCast(src_addr)) + off),
1348714063 },
......@@ -13539,7 +14115,7 @@ fn airCmp(self: *CodeGen, inst: Air.Inst.Index, op: std.math.CompareOperator) !v
1353914115 const tmp2_lock = self.register_manager.lockRegAssumeUnused(tmp2_reg);
1354014116 defer self.register_manager.unlockReg(tmp2_lock);
1354114117
13542 if (src_mcv.isMemory()) try self.asmRegisterRegisterMemoryImmediate(
14118 if (src_mcv.isBase()) try self.asmRegisterRegisterMemoryImmediate(
1354314119 .{ .vp_w, .insr },
1354414120 tmp1_reg,
1354514121 dst_reg.to128(),
......@@ -13840,8 +14416,11 @@ fn isNull(self: *CodeGen, inst: Air.Inst.Index, opt_ty: Type, opt_mcv: MCValue)
1384014416 .undef,
1384114417 .immediate,
1384214418 .eflags,
14419 .register_triple,
14420 .register_quadruple,
1384314421 .register_offset,
1384414422 .register_overflow,
14423 .register_mask,
1384514424 .lea_direct,
1384614425 .lea_got,
1384714426 .lea_tlv,
......@@ -15481,6 +16060,7 @@ fn genCopy(self: *CodeGen, ty: Type, dst_mcv: MCValue, src_mcv: MCValue, opts: C
1548116060 .immediate,
1548216061 .eflags,
1548316062 .register_overflow,
16063 .register_mask,
1548416064 .lea_direct,
1548516065 .lea_got,
1548616066 .lea_tlv,
......@@ -15510,7 +16090,7 @@ fn genCopy(self: *CodeGen, ty: Type, dst_mcv: MCValue, src_mcv: MCValue, opts: C
1551016090 .off = -dst_reg_off.off,
1551116091 } },
1551216092 }, opts),
15513 .register_pair => |dst_regs| {
16093 inline .register_pair, .register_triple, .register_quadruple => |dst_regs| {
1551416094 const src_info: ?struct { addr_reg: Register, addr_lock: RegisterLock } = switch (src_mcv) {
1551516095 .register_pair, .memory, .indirect, .load_frame => null,
1551616096 .load_symbol, .load_direct, .load_got, .load_tlv => src: {
......@@ -15535,9 +16115,12 @@ fn genCopy(self: *CodeGen, ty: Type, dst_mcv: MCValue, src_mcv: MCValue, opts: C
1553516115 defer if (src_info) |info| self.register_manager.unlockReg(info.addr_lock);
1553616116
1553716117 var part_disp: i32 = 0;
15538 for (dst_regs, try self.splitType(ty), 0..) |dst_reg, dst_ty, part_i| {
16118 for (dst_regs, try self.splitType(dst_regs.len, ty), 0..) |dst_reg, dst_ty, part_i| {
1553916119 try self.genSetReg(dst_reg, dst_ty, switch (src_mcv) {
15540 .register_pair => |src_regs| .{ .register = src_regs[part_i] },
16120 inline .register_pair,
16121 .register_triple,
16122 .register_quadruple,
16123 => |src_regs| .{ .register = src_regs[part_i] },
1554116124 .memory, .indirect, .load_frame => src_mcv.address().offset(part_disp).deref(),
1554216125 .load_symbol, .load_direct, .load_got, .load_tlv => .{ .indirect = .{
1554316126 .reg = src_info.?.addr_reg,
......@@ -15733,7 +16316,10 @@ fn genSetReg(
1573316316 },
1573416317 .ip => unreachable,
1573516318 },
15736 .register_pair => |src_regs| try self.genSetReg(dst_reg, ty, .{ .register = src_regs[0] }, opts),
16319 inline .register_pair,
16320 .register_triple,
16321 .register_quadruple,
16322 => |src_regs| try self.genSetReg(dst_reg, ty, .{ .register = src_regs[0] }, opts),
1573716323 .register_offset,
1573816324 .indirect,
1573916325 .load_frame,
......@@ -15770,6 +16356,47 @@ fn genSetReg(
1577016356 },
1577116357 else => unreachable,
1577216358 }),
16359 .register_mask => |src_reg_mask| {
16360 assert(src_reg_mask.reg.class() == .sse);
16361 const has_avx = self.hasFeature(.avx);
16362 const bits_reg = switch (dst_reg.class()) {
16363 .general_purpose => dst_reg,
16364 else => try self.register_manager.allocReg(null, abi.RegisterClass.gp),
16365 };
16366 const bits_lock = self.register_manager.lockReg(bits_reg);
16367 defer if (bits_lock) |lock| self.register_manager.unlockReg(lock);
16368
16369 const pack_reg = switch (src_reg_mask.scalar) {
16370 else => src_reg_mask.reg,
16371 .word => try self.register_manager.allocReg(null, abi.RegisterClass.sse),
16372 };
16373 const pack_lock = self.register_manager.lockReg(pack_reg);
16374 defer if (pack_lock) |lock| self.register_manager.unlockReg(lock);
16375
16376 var mask_size: u32 = @intCast(ty.vectorLen(zcu) * @divExact(src_reg_mask.scalar.bitSize(), 8));
16377 switch (src_reg_mask.scalar) {
16378 else => {},
16379 .word => {
16380 const src_alias = registerAlias(src_reg_mask.reg, mask_size);
16381 const pack_alias = registerAlias(pack_reg, mask_size);
16382 if (has_avx) {
16383 try self.asmRegisterRegisterRegister(.{ .vp_b, .ackssw }, pack_alias, src_alias, src_alias);
16384 } else {
16385 try self.asmRegisterRegister(.{ ._, .movdqa }, pack_alias, src_alias);
16386 try self.asmRegisterRegister(.{ .p_b, .ackssw }, pack_alias, pack_alias);
16387 }
16388 mask_size = std.math.divCeil(u32, mask_size, 2) catch unreachable;
16389 },
16390 }
16391 try self.asmRegisterRegister(.{ switch (src_reg_mask.scalar) {
16392 .byte, .word => if (has_avx) .vp_b else .p_b,
16393 .dword => if (has_avx) .v_ps else ._ps,
16394 .qword => if (has_avx) .v_pd else ._pd,
16395 else => unreachable,
16396 }, .movmsk }, bits_reg.to32(), registerAlias(pack_reg, mask_size));
16397 if (src_reg_mask.inverted) try self.asmRegister(.{ ._, .not }, registerAlias(bits_reg, abi_size));
16398 try self.genSetReg(dst_reg, ty, .{ .register = bits_reg }, .{});
16399 },
1577316400 .memory, .load_symbol, .load_direct, .load_got, .load_tlv => {
1577416401 switch (src_mcv) {
1577516402 .memory => |addr| if (std.math.cast(i32, @as(i64, @bitCast(addr)))) |small_addr|
......@@ -15998,9 +16625,9 @@ fn genSetMem(
1599816625 src_alias,
1599916626 );
1600016627 },
16001 .register_pair => |src_regs| {
16628 inline .register_pair, .register_triple, .register_quadruple => |src_regs| {
1600216629 var part_disp: i32 = disp;
16003 for (try self.splitType(ty), src_regs) |src_ty, src_reg| {
16630 for (try self.splitType(src_regs.len, ty), src_regs) |src_ty, src_reg| {
1600416631 try self.genSetMem(base, part_disp, src_ty, .{ .register = src_reg }, opts);
1600516632 part_disp += @intCast(src_ty.abiSize(zcu));
1600616633 }
......@@ -16065,6 +16692,13 @@ fn genSetMem(
1606516692
1606616693 try self.genSetMem(base, disp, ty, .{ .register = src_reg }, opts);
1606716694 },
16695 .register_mask => {
16696 const src_reg = try self.copyToTmpRegister(ty, src_mcv);
16697 const src_lock = self.register_manager.lockRegAssumeUnused(src_reg);
16698 defer self.register_manager.unlockReg(src_lock);
16699
16700 try self.genSetMem(base, disp, ty, .{ .register = src_reg }, opts);
16701 },
1606816702 .memory,
1606916703 .indirect,
1607016704 .load_direct,
......@@ -16283,7 +16917,7 @@ fn airBitCast(self: *CodeGen, inst: Air.Inst.Index) !void {
1628316917 const dst_mcv = try self.allocRegOrMem(inst, true);
1628416918 try self.genCopy(switch (std.math.order(dst_ty.abiSize(zcu), src_ty.abiSize(zcu))) {
1628516919 .lt => dst_ty,
16286 .eq => if (!dst_mcv.isMemory() or src_mcv.isMemory()) dst_ty else src_ty,
16920 .eq => if (!dst_mcv.isBase() or src_mcv.isBase()) dst_ty else src_ty,
1628716921 .gt => src_ty,
1628816922 }, dst_mcv, src_mcv, .{});
1628916923 break :dst dst_mcv;
......@@ -16729,7 +17363,7 @@ fn atomicOp(
1672917363 });
1673017364 try self.genSetReg(sse_reg, val_ty, .{ .register = .rax }, .{});
1673117365 switch (mir_tag[0]) {
16732 .v_ss, .v_sd => if (val_mcv.isMemory()) try self.asmRegisterRegisterMemory(
17366 .v_ss, .v_sd => if (val_mcv.isBase()) try self.asmRegisterRegisterMemory(
1673317367 mir_tag,
1673417368 sse_reg.to128(),
1673517369 sse_reg.to128(),
......@@ -16743,7 +17377,7 @@ fn atomicOp(
1674317377 else
1674417378 try self.copyToTmpRegister(val_ty, val_mcv)).to128(),
1674517379 ),
16746 ._ss, ._sd => if (val_mcv.isMemory()) try self.asmRegisterMemory(
17380 ._ss, ._sd => if (val_mcv.isBase()) try self.asmRegisterMemory(
1674717381 mir_tag,
1674817382 sse_reg.to128(),
1674917383 try val_mcv.mem(self, .{ .size = self.memSize(val_ty) }),
......@@ -17443,7 +18077,7 @@ fn airSplat(self: *CodeGen, inst: Air.Inst.Index) !void {
1744318077 defer self.register_manager.unlockReg(dst_lock);
1744418078
1744518079 const src_mcv = try self.resolveInst(ty_op.operand);
17446 if (src_mcv.isMemory()) try self.asmRegisterMemory(
18080 if (src_mcv.isBase()) try self.asmRegisterMemory(
1744718081 mir_tag,
1744818082 registerAlias(dst_reg, @intCast(vector_ty.abiSize(zcu))),
1744918083 try src_mcv.mem(self, .{ .size = self.memSize(scalar_ty) }),
......@@ -17519,7 +18153,7 @@ fn airSplat(self: *CodeGen, inst: Air.Inst.Index) !void {
1751918153 const src_mcv = try self.resolveInst(ty_op.operand);
1752018154 if (self.hasFeature(.avx)) {
1752118155 const dst_reg = try self.register_manager.allocReg(inst, dst_rc);
17522 if (src_mcv.isMemory()) try self.asmRegisterMemory(
18156 if (src_mcv.isBase()) try self.asmRegisterMemory(
1752318157 .{ .v_ss, .broadcast },
1752418158 dst_reg.to128(),
1752518159 try src_mcv.mem(self, .{ .size = .dword }),
......@@ -17556,7 +18190,7 @@ fn airSplat(self: *CodeGen, inst: Air.Inst.Index) !void {
1755618190 5...8 => if (self.hasFeature(.avx)) {
1755718191 const src_mcv = try self.resolveInst(ty_op.operand);
1755818192 const dst_reg = try self.register_manager.allocReg(inst, dst_rc);
17559 if (src_mcv.isMemory()) try self.asmRegisterMemory(
18193 if (src_mcv.isBase()) try self.asmRegisterMemory(
1756018194 .{ .v_ss, .broadcast },
1756118195 dst_reg.to256(),
1756218196 try src_mcv.mem(self, .{ .size = .dword }),
......@@ -17602,7 +18236,7 @@ fn airSplat(self: *CodeGen, inst: Air.Inst.Index) !void {
1760218236 const src_mcv = try self.resolveInst(ty_op.operand);
1760318237 const dst_reg = try self.register_manager.allocReg(inst, dst_rc);
1760418238 if (self.hasFeature(.sse3)) {
17605 if (src_mcv.isMemory()) try self.asmRegisterMemory(
18239 if (src_mcv.isBase()) try self.asmRegisterMemory(
1760618240 if (self.hasFeature(.avx)) .{ .v_, .movddup } else .{ ._, .movddup },
1760718241 dst_reg.to128(),
1760818242 try src_mcv.mem(self, .{ .size = .qword }),
......@@ -17627,7 +18261,7 @@ fn airSplat(self: *CodeGen, inst: Air.Inst.Index) !void {
1762718261 3...4 => if (self.hasFeature(.avx)) {
1762818262 const src_mcv = try self.resolveInst(ty_op.operand);
1762918263 const dst_reg = try self.register_manager.allocReg(inst, dst_rc);
17630 if (src_mcv.isMemory()) try self.asmRegisterMemory(
18264 if (src_mcv.isBase()) try self.asmRegisterMemory(
1763118265 .{ .v_sd, .broadcast },
1763218266 dst_reg.to256(),
1763318267 try src_mcv.mem(self, .{ .size = .qword }),
......@@ -17670,7 +18304,7 @@ fn airSplat(self: *CodeGen, inst: Air.Inst.Index) !void {
1767018304 2 => if (self.hasFeature(.avx)) {
1767118305 const src_mcv = try self.resolveInst(ty_op.operand);
1767218306 const dst_reg = try self.register_manager.allocReg(inst, dst_rc);
17673 if (src_mcv.isMemory()) try self.asmRegisterMemory(
18307 if (src_mcv.isBase()) try self.asmRegisterMemory(
1767418308 .{ .v_f128, .broadcast },
1767518309 dst_reg.to256(),
1767618310 try src_mcv.mem(self, .{ .size = .xword }),
......@@ -17779,7 +18413,7 @@ fn airSelect(self: *CodeGen, inst: Air.Inst.Index) !void {
1777918413 else => unreachable,
1778018414 }, .broadcast },
1778118415 mask_alias,
17782 if (pred_mcv.isMemory()) try pred_mcv.mem(self, .{ .size = .byte }) else .{
18416 if (pred_mcv.isBase()) try pred_mcv.mem(self, .{ .size = .byte }) else .{
1778318417 .base = .{ .reg = (try self.copyToTmpRegister(
1778418418 Type.usize,
1778518419 pred_mcv.address(),
......@@ -17973,7 +18607,7 @@ fn airSelect(self: *CodeGen, inst: Air.Inst.Index) !void {
1797318607 try self.genSetReg(dst_reg, ty, rhs_mcv, .{});
1797418608 break :rhs dst_alias;
1797518609 };
17976 if (lhs_mcv.isMemory()) try self.asmRegisterRegisterMemoryRegister(
18610 if (lhs_mcv.isBase()) try self.asmRegisterRegisterMemoryRegister(
1797718611 mir_tag,
1797818612 dst_alias,
1797918613 rhs_alias,
......@@ -17989,7 +18623,7 @@ fn airSelect(self: *CodeGen, inst: Air.Inst.Index) !void {
1798918623 try self.copyToTmpRegister(ty, lhs_mcv), abi_size),
1799018624 mask_alias,
1799118625 );
17992 } else if (has_blend) if (lhs_mcv.isMemory()) try self.asmRegisterMemoryRegister(
18626 } else if (has_blend) if (lhs_mcv.isBase()) try self.asmRegisterMemoryRegister(
1799318627 mir_tag,
1799418628 dst_alias,
1799518629 try lhs_mcv.mem(self, .{ .size = self.memSize(ty) }),
......@@ -18014,7 +18648,7 @@ fn airSelect(self: *CodeGen, inst: Air.Inst.Index) !void {
1801418648 },
1801518649 }) orelse return self.fail("TODO implement airSelect for {}", .{ty.fmt(pt)});
1801618650 try self.asmRegisterRegister(.{ mir_fixes, .@"and" }, dst_alias, mask_alias);
18017 if (rhs_mcv.isMemory()) try self.asmRegisterMemory(
18651 if (rhs_mcv.isBase()) try self.asmRegisterMemory(
1801818652 .{ mir_fixes, .andn },
1801918653 mask_alias,
1802018654 try rhs_mcv.mem(self, .{ .size = .fromSize(abi_size) }),
......@@ -18093,10 +18727,7 @@ fn airShuffle(self: *CodeGen, inst: Air.Inst.Index) !void {
1809318727
1809418728 for ([_]Mir.Inst.Tag{ .unpckl, .unpckh }) |variant| unpck: {
1809518729 if (elem_abi_size > 8) break :unpck;
18096 if (dst_abi_size > @as(u32, if (if (elem_abi_size >= 4)
18097 has_avx
18098 else
18099 self.hasFeature(.avx2)) 32 else 16)) break :unpck;
18730 if (dst_abi_size > self.vectorSize(if (elem_abi_size >= 4) .float else .int)) break :unpck;
1810018731
1810118732 var sources: [2]?u1 = @splat(null);
1810218733 for (mask_elems, 0..) |maybe_mask_elem, elem_index| {
......@@ -18154,7 +18785,7 @@ fn airShuffle(self: *CodeGen, inst: Air.Inst.Index) !void {
1815418785 },
1815518786 else => unreachable,
1815618787 } };
18157 if (has_avx) if (rhs_mcv.isMemory()) try self.asmRegisterRegisterMemory(
18788 if (has_avx) if (rhs_mcv.isBase()) try self.asmRegisterRegisterMemory(
1815818789 mir_tag,
1815918790 dst_alias,
1816018791 registerAlias(lhs_mcv.getReg() orelse dst_reg, max_abi_size),
......@@ -18167,7 +18798,7 @@ fn airShuffle(self: *CodeGen, inst: Air.Inst.Index) !void {
1816718798 rhs_mcv.getReg().?
1816818799 else
1816918800 try self.copyToTmpRegister(operand_tys[sources[1].?], rhs_mcv), max_abi_size),
18170 ) else if (rhs_mcv.isMemory()) try self.asmRegisterMemory(
18801 ) else if (rhs_mcv.isBase()) try self.asmRegisterMemory(
1817118802 mir_tag,
1817218803 dst_alias,
1817318804 try rhs_mcv.mem(self, .{ .size = .fromSize(max_abi_size) }),
......@@ -18184,7 +18815,7 @@ fn airShuffle(self: *CodeGen, inst: Air.Inst.Index) !void {
1818418815
1818518816 pshufd: {
1818618817 if (elem_abi_size != 4) break :pshufd;
18187 if (max_abi_size > @as(u32, if (has_avx) 32 else 16)) break :pshufd;
18818 if (max_abi_size > self.vectorSize(.float)) break :pshufd;
1818818819
1818918820 var control: u8 = 0b00_00_00_00;
1819018821 var sources: [1]?u1 = @splat(null);
......@@ -18216,7 +18847,7 @@ fn airShuffle(self: *CodeGen, inst: Air.Inst.Index) !void {
1821618847 try self.register_manager.allocReg(inst, abi.RegisterClass.sse);
1821718848 const dst_alias = registerAlias(dst_reg, max_abi_size);
1821818849
18219 if (src_mcv.isMemory()) try self.asmRegisterMemoryImmediate(
18850 if (src_mcv.isBase()) try self.asmRegisterMemoryImmediate(
1822018851 .{ if (has_avx) .vp_d else .p_d, .shuf },
1822118852 dst_alias,
1822218853 try src_mcv.mem(self, .{ .size = .fromSize(max_abi_size) }),
......@@ -18235,7 +18866,7 @@ fn airShuffle(self: *CodeGen, inst: Air.Inst.Index) !void {
1823518866
1823618867 shufps: {
1823718868 if (elem_abi_size != 4) break :shufps;
18238 if (max_abi_size > @as(u32, if (has_avx) 32 else 16)) break :shufps;
18869 if (max_abi_size > self.vectorSize(.float)) break :shufps;
1823918870
1824018871 var control: u8 = 0b00_00_00_00;
1824118872 var sources: [2]?u1 = @splat(null);
......@@ -18272,7 +18903,7 @@ fn airShuffle(self: *CodeGen, inst: Air.Inst.Index) !void {
1827218903 const dst_reg = dst_mcv.getReg().?;
1827318904 const dst_alias = registerAlias(dst_reg, max_abi_size);
1827418905
18275 if (has_avx) if (rhs_mcv.isMemory()) try self.asmRegisterRegisterMemoryImmediate(
18906 if (has_avx) if (rhs_mcv.isBase()) try self.asmRegisterRegisterMemoryImmediate(
1827618907 .{ .v_ps, .shuf },
1827718908 dst_alias,
1827818909 registerAlias(lhs_mcv.getReg() orelse dst_reg, max_abi_size),
......@@ -18287,7 +18918,7 @@ fn airShuffle(self: *CodeGen, inst: Air.Inst.Index) !void {
1828718918 else
1828818919 try self.copyToTmpRegister(operand_tys[sources[1].?], rhs_mcv), max_abi_size),
1828918920 .u(control),
18290 ) else if (rhs_mcv.isMemory()) try self.asmRegisterMemoryImmediate(
18921 ) else if (rhs_mcv.isBase()) try self.asmRegisterMemoryImmediate(
1829118922 .{ ._ps, .shuf },
1829218923 dst_alias,
1829318924 try rhs_mcv.mem(self, .{ .size = .fromSize(max_abi_size) }),
......@@ -18306,7 +18937,7 @@ fn airShuffle(self: *CodeGen, inst: Air.Inst.Index) !void {
1830618937
1830718938 shufpd: {
1830818939 if (elem_abi_size != 8) break :shufpd;
18309 if (max_abi_size > @as(u32, if (has_avx) 32 else 16)) break :shufpd;
18940 if (max_abi_size > self.vectorSize(.float)) break :shufpd;
1831018941
1831118942 var control: u4 = 0b0_0_0_0;
1831218943 var sources: [2]?u1 = @splat(null);
......@@ -18339,7 +18970,7 @@ fn airShuffle(self: *CodeGen, inst: Air.Inst.Index) !void {
1833918970 const dst_reg = dst_mcv.getReg().?;
1834018971 const dst_alias = registerAlias(dst_reg, max_abi_size);
1834118972
18342 if (has_avx) if (rhs_mcv.isMemory()) try self.asmRegisterRegisterMemoryImmediate(
18973 if (has_avx) if (rhs_mcv.isBase()) try self.asmRegisterRegisterMemoryImmediate(
1834318974 .{ .v_pd, .shuf },
1834418975 dst_alias,
1834518976 registerAlias(lhs_mcv.getReg() orelse dst_reg, max_abi_size),
......@@ -18354,7 +18985,7 @@ fn airShuffle(self: *CodeGen, inst: Air.Inst.Index) !void {
1835418985 else
1835518986 try self.copyToTmpRegister(operand_tys[sources[1].?], rhs_mcv), max_abi_size),
1835618987 .u(control),
18357 ) else if (rhs_mcv.isMemory()) try self.asmRegisterMemoryImmediate(
18988 ) else if (rhs_mcv.isBase()) try self.asmRegisterMemoryImmediate(
1835818989 .{ ._pd, .shuf },
1835918990 dst_alias,
1836018991 try rhs_mcv.mem(self, .{ .size = .fromSize(max_abi_size) }),
......@@ -18373,7 +19004,7 @@ fn airShuffle(self: *CodeGen, inst: Air.Inst.Index) !void {
1837319004
1837419005 blend: {
1837519006 if (elem_abi_size < 2) break :blend;
18376 if (dst_abi_size > @as(u32, if (has_avx) 32 else 16)) break :blend;
19007 if (dst_abi_size > self.vectorSize(.float)) break :blend;
1837719008 if (!self.hasFeature(.sse4_1)) break :blend;
1837819009
1837919010 var control: u8 = 0b0_0_0_0_0_0_0_0;
......@@ -18409,7 +19040,7 @@ fn airShuffle(self: *CodeGen, inst: Air.Inst.Index) !void {
1840919040
1841019041 const rhs_mcv = try self.resolveInst(extra.b);
1841119042 const dst_reg = try self.register_manager.allocReg(inst, abi.RegisterClass.sse);
18412 if (rhs_mcv.isMemory()) try self.asmRegisterRegisterMemoryImmediate(
19043 if (rhs_mcv.isBase()) try self.asmRegisterRegisterMemoryImmediate(
1841319044 .{ .vp_d, .blend },
1841419045 registerAlias(dst_reg, dst_abi_size),
1841519046 registerAlias(lhs_reg, dst_abi_size),
......@@ -18461,7 +19092,7 @@ fn airShuffle(self: *CodeGen, inst: Air.Inst.Index) !void {
1846119092 try self.copyToRegisterWithInstTracking(inst, dst_ty, lhs_mcv);
1846219093 const dst_reg = dst_mcv.getReg().?;
1846319094
18464 if (has_avx) if (rhs_mcv.isMemory()) try self.asmRegisterRegisterMemoryImmediate(
19095 if (has_avx) if (rhs_mcv.isBase()) try self.asmRegisterRegisterMemoryImmediate(
1846519096 .{ .vp_w, .blend },
1846619097 registerAlias(dst_reg, dst_abi_size),
1846719098 registerAlias(if (lhs_mcv.isRegister())
......@@ -18482,7 +19113,7 @@ fn airShuffle(self: *CodeGen, inst: Air.Inst.Index) !void {
1848219113 else
1848319114 try self.copyToTmpRegister(dst_ty, rhs_mcv), dst_abi_size),
1848419115 .u(expanded_control),
18485 ) else if (rhs_mcv.isMemory()) try self.asmRegisterMemoryImmediate(
19116 ) else if (rhs_mcv.isBase()) try self.asmRegisterMemoryImmediate(
1848619117 .{ .p_w, .blend },
1848719118 registerAlias(dst_reg, dst_abi_size),
1848819119 try rhs_mcv.mem(self, .{ .size = .fromSize(dst_abi_size) }),
......@@ -18518,7 +19149,7 @@ fn airShuffle(self: *CodeGen, inst: Air.Inst.Index) !void {
1851819149 try self.copyToRegisterWithInstTracking(inst, dst_ty, lhs_mcv);
1851919150 const dst_reg = dst_mcv.getReg().?;
1852019151
18521 if (has_avx) if (rhs_mcv.isMemory()) try self.asmRegisterRegisterMemoryImmediate(
19152 if (has_avx) if (rhs_mcv.isBase()) try self.asmRegisterRegisterMemoryImmediate(
1852219153 switch (elem_abi_size) {
1852319154 4 => .{ .v_ps, .blend },
1852419155 8, 16 => .{ .v_pd, .blend },
......@@ -18547,7 +19178,7 @@ fn airShuffle(self: *CodeGen, inst: Air.Inst.Index) !void {
1854719178 else
1854819179 try self.copyToTmpRegister(dst_ty, rhs_mcv), dst_abi_size),
1854919180 .u(expanded_control),
18550 ) else if (rhs_mcv.isMemory()) try self.asmRegisterMemoryImmediate(
19181 ) else if (rhs_mcv.isBase()) try self.asmRegisterMemoryImmediate(
1855119182 switch (elem_abi_size) {
1855219183 4 => .{ ._ps, .blend },
1855319184 8, 16 => .{ ._pd, .blend },
......@@ -18573,10 +19204,7 @@ fn airShuffle(self: *CodeGen, inst: Air.Inst.Index) !void {
1857319204 }
1857419205
1857519206 blendv: {
18576 if (dst_abi_size > @as(u32, if (if (elem_abi_size >= 4)
18577 has_avx
18578 else
18579 self.hasFeature(.avx2)) 32 else 16)) break :blendv;
19207 if (dst_abi_size > self.vectorSize(if (elem_abi_size >= 4) .float else .int)) break :blendv;
1858019208
1858119209 const select_mask_elem_ty = try pt.intType(.unsigned, elem_abi_size * 8);
1858219210 const select_mask_ty = try pt.vectorType(.{
......@@ -18637,7 +19265,7 @@ fn airShuffle(self: *CodeGen, inst: Air.Inst.Index) !void {
1863719265 const dst_reg = dst_mcv.getReg().?;
1863819266 const dst_alias = registerAlias(dst_reg, dst_abi_size);
1863919267
18640 if (has_avx) if (rhs_mcv.isMemory()) try self.asmRegisterRegisterMemoryRegister(
19268 if (has_avx) if (rhs_mcv.isBase()) try self.asmRegisterRegisterMemoryRegister(
1864119269 mir_tag,
1864219270 dst_alias,
1864319271 if (lhs_mcv.isRegister())
......@@ -18658,7 +19286,7 @@ fn airShuffle(self: *CodeGen, inst: Air.Inst.Index) !void {
1865819286 else
1865919287 try self.copyToTmpRegister(dst_ty, rhs_mcv), dst_abi_size),
1866019288 select_mask_alias,
18661 ) else if (rhs_mcv.isMemory()) try self.asmRegisterMemoryRegister(
19289 ) else if (rhs_mcv.isBase()) try self.asmRegisterMemoryRegister(
1866219290 mir_tag,
1866319291 dst_alias,
1866419292 try rhs_mcv.mem(self, .{ .size = .fromSize(dst_abi_size) }),
......@@ -18701,7 +19329,7 @@ fn airShuffle(self: *CodeGen, inst: Air.Inst.Index) !void {
1870119329 else
1870219330 .p_;
1870319331 try self.asmRegisterRegister(.{ mir_fixes, .@"and" }, dst_alias, mask_alias);
18704 if (lhs_mcv.isMemory()) try self.asmRegisterMemory(
19332 if (lhs_mcv.isBase()) try self.asmRegisterMemory(
1870519333 .{ mir_fixes, .andn },
1870619334 mask_alias,
1870719335 try lhs_mcv.mem(self, .{ .size = .fromSize(dst_abi_size) }),
......@@ -18851,22 +19479,61 @@ fn airReduce(self: *CodeGen, inst: Air.Inst.Index) !void {
1885119479 if (operand_ty.isVector(zcu) and operand_ty.childType(zcu).toIntern() == .bool_type) {
1885219480 try self.spillEflagsIfOccupied();
1885319481
18854 const operand_mcv = try self.resolveInst(reduce.operand);
18855 const mask_len = (std.math.cast(u6, operand_ty.vectorLen(zcu)) orelse
18856 return self.fail("TODO implement airReduce for {}", .{operand_ty.fmt(pt)}));
18857 const mask = (@as(u64, 1) << mask_len) - 1;
1885819482 const abi_size: u32 = @intCast(operand_ty.abiSize(zcu));
19483 const operand_mcv = try self.resolveInst(reduce.operand);
19484 const mask_len = operand_ty.vectorLen(zcu);
19485 const mask_len_minus_one = (std.math.cast(u6, mask_len - 1) orelse {
19486 const acc_reg = try self.register_manager.allocReg(null, abi.RegisterClass.gp);
19487 const acc_lock = self.register_manager.lockRegAssumeUnused(acc_reg);
19488 defer self.register_manager.unlockReg(acc_lock);
19489 var limb_offset: i31 = 0;
19490 while (limb_offset < abi_size) : (limb_offset += 8) {
19491 try self.asmRegisterMemory(
19492 .{ ._, if (limb_offset == 0) .mov else switch (reduce.operation) {
19493 .Or => .@"or",
19494 .And => .@"and",
19495 else => return self.fail("TODO implement airReduce for {}", .{operand_ty.fmt(pt)}),
19496 } },
19497 acc_reg.to64(),
19498 try operand_mcv.mem(self, .{
19499 .size = .qword,
19500 .disp = limb_offset,
19501 }),
19502 );
19503 }
19504 switch (reduce.operation) {
19505 .Or => {
19506 try self.asmRegisterRegister(.{ ._, .@"test" }, acc_reg.to64(), acc_reg.to64());
19507 break :result .{ .eflags = .nz };
19508 },
19509 .And => {
19510 try self.asmRegisterImmediate(.{ ._, .cmp }, acc_reg.to64(), .s(-1));
19511 break :result .{ .eflags = .z };
19512 },
19513 else => unreachable,
19514 }
19515 });
19516 const mask = @as(u64, std.math.maxInt(u64)) >> ~mask_len_minus_one;
1885919517 switch (reduce.operation) {
1886019518 .Or => {
18861 if (operand_mcv.isMemory()) try self.asmMemoryImmediate(
19519 if (operand_mcv.isBase()) try self.asmMemoryImmediate(
1886219520 .{ ._, .@"test" },
1886319521 try operand_mcv.mem(self, .{ .size = .fromSize(abi_size) }),
18864 .u(mask),
18865 ) else {
18866 const operand_reg = registerAlias(if (operand_mcv.isRegister())
18867 operand_mcv.getReg().?
19522 if (mask_len < abi_size * 8)
19523 .u(mask)
1886819524 else
18869 try self.copyToTmpRegister(operand_ty, operand_mcv), abi_size);
19525 .s(-1),
19526 ) else {
19527 const operand_reg = registerAlias(operand_reg: {
19528 if (operand_mcv.isRegister()) {
19529 const operand_reg = operand_mcv.getReg().?;
19530 if (operand_reg.class() == .general_purpose) break :operand_reg operand_reg;
19531 }
19532 break :operand_reg try self.copyToTmpRegister(operand_ty, operand_mcv);
19533 }, abi_size);
19534 const operand_lock = self.register_manager.lockReg(operand_reg);
19535 defer if (operand_lock) |lock| self.register_manager.unlockReg(lock);
19536
1887019537 if (mask_len < abi_size * 8) try self.asmRegisterImmediate(
1887119538 .{ ._, .@"test" },
1887219539 operand_reg,
......@@ -18880,7 +19547,10 @@ fn airReduce(self: *CodeGen, inst: Air.Inst.Index) !void {
1888019547 break :result .{ .eflags = .nz };
1888119548 },
1888219549 .And => {
18883 const tmp_reg = try self.copyToTmpRegister(operand_ty, operand_mcv);
19550 const tmp_reg = registerAlias(
19551 try self.copyToTmpRegister(operand_ty, operand_mcv),
19552 abi_size,
19553 );
1888419554 const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);
1888519555 defer self.register_manager.unlockReg(tmp_lock);
1888619556
......@@ -19184,7 +19854,7 @@ fn airMulAdd(self: *CodeGen, inst: Air.Inst.Index) !void {
1918419854 if (unused.isSet(0) and mcv.isRegister() and self.reuseOperand(inst, op, op_index, mcv.*)) {
1918519855 order[op_index] = 1;
1918619856 unused.unset(0);
19187 } else if (unused.isSet(2) and mcv.isMemory()) {
19857 } else if (unused.isSet(2) and mcv.isBase()) {
1918819858 order[op_index] = 3;
1918919859 unused.unset(2);
1919019860 }
......@@ -19531,7 +20201,7 @@ fn airVaArg(self: *CodeGen, inst: Air.Inst.Index) !void {
1953120201 const dst_lock = self.register_manager.lockReg(dst_reg);
1953220202 defer if (dst_lock) |lock| self.register_manager.unlockReg(lock);
1953320203
19534 if (self.hasFeature(.avx)) if (promote_mcv.isMemory()) try self.asmRegisterRegisterMemory(
20204 if (self.hasFeature(.avx)) if (promote_mcv.isBase()) try self.asmRegisterRegisterMemory(
1953520205 .{ .v_ss, .cvtsd2 },
1953620206 dst_reg,
1953720207 dst_reg,
......@@ -19544,7 +20214,7 @@ fn airVaArg(self: *CodeGen, inst: Air.Inst.Index) !void {
1954420214 promote_mcv.getReg().?
1954520215 else
1954620216 try self.copyToTmpRegister(promote_ty, promote_mcv)).to128(),
19547 ) else if (promote_mcv.isMemory()) try self.asmRegisterMemory(
20217 ) else if (promote_mcv.isBase()) try self.asmRegisterMemory(
1954820218 .{ ._ss, .cvtsd2 },
1954920219 dst_reg,
1955020220 try promote_mcv.mem(self, .{ .size = .qword }),
......@@ -19751,7 +20421,7 @@ fn resolveCallingConventionValues(
1975120421 // TODO: is this even possible for C calling convention?
1975220422 result.return_value = .init(.none);
1975320423 } else {
19754 var ret_tracking: [2]InstTracking = undefined;
20424 var ret_tracking: [4]InstTracking = undefined;
1975520425 var ret_tracking_i: usize = 0;
1975620426
1975720427 const classes = switch (resolved_cc) {
......@@ -19771,14 +20441,17 @@ fn resolveCallingConventionValues(
1977120441 ret_tracking_i += 1;
1977220442 },
1977320443 .sse, .float, .float_combine, .win_i128 => {
19774 const ret_sse_reg = registerAlias(
19775 abi.getCAbiSseReturnRegs(resolved_cc)[ret_sse_reg_i],
19776 @intCast(ret_ty.abiSize(zcu)),
19777 );
19778 ret_sse_reg_i += 1;
19779
19780 ret_tracking[ret_tracking_i] = .init(.{ .register = ret_sse_reg });
19781 ret_tracking_i += 1;
20444 const ret_sse_regs = abi.getCAbiSseReturnRegs(resolved_cc);
20445 const abi_size: u32 = @intCast(ret_ty.abiSize(zcu));
20446 const reg_size = @min(abi_size, self.vectorSize(.float));
20447 var byte_offset: u32 = 0;
20448 while (byte_offset < abi_size) : (byte_offset += reg_size) {
20449 const ret_sse_reg = registerAlias(ret_sse_regs[ret_sse_reg_i], reg_size);
20450 ret_sse_reg_i += 1;
20451
20452 ret_tracking[ret_tracking_i] = .init(.{ .register = ret_sse_reg });
20453 ret_tracking_i += 1;
20454 }
1978220455 },
1978320456 .sseup => assert(ret_tracking[ret_tracking_i - 1].short.register.class() == .sse),
1978420457 .x87 => {
......@@ -19811,6 +20484,17 @@ fn resolveCallingConventionValues(
1981120484 ret_tracking[0].short.register,
1981220485 ret_tracking[1].short.register,
1981320486 } }),
20487 3 => .init(.{ .register_triple = .{
20488 ret_tracking[0].short.register,
20489 ret_tracking[1].short.register,
20490 ret_tracking[2].short.register,
20491 } }),
20492 4 => .init(.{ .register_quadruple = .{
20493 ret_tracking[0].short.register,
20494 ret_tracking[1].short.register,
20495 ret_tracking[2].short.register,
20496 ret_tracking[3].short.register,
20497 } }),
1981420498 };
1981520499 }
1981620500
......@@ -19826,7 +20510,7 @@ fn resolveCallingConventionValues(
1982620510 else => unreachable,
1982720511 }
1982820512
19829 var arg_mcv: [2]MCValue = undefined;
20513 var arg_mcv: [4]MCValue = undefined;
1983020514 var arg_mcv_i: usize = 0;
1983120515
1983220516 const classes = switch (resolved_cc) {
......@@ -19834,15 +20518,13 @@ fn resolveCallingConventionValues(
1983420518 .x86_64_win => &.{abi.classifyWindows(ty, zcu)},
1983520519 else => unreachable,
1983620520 };
19837 for (classes) |class| switch (class) {
20521 classes: for (classes) |class| switch (class) {
1983820522 .integer => {
1983920523 const param_int_regs = abi.getCAbiIntParamRegs(resolved_cc);
1984020524 if (param_int_reg_i >= param_int_regs.len) break;
1984120525
19842 const param_int_reg = registerAlias(
19843 abi.getCAbiIntParamRegs(resolved_cc)[param_int_reg_i],
19844 @intCast(@min(ty.abiSize(zcu), 8)),
19845 );
20526 const param_int_reg =
20527 registerAlias(param_int_regs[param_int_reg_i], @intCast(@min(ty.abiSize(zcu), 8)));
1984620528 param_int_reg_i += 1;
1984720529
1984820530 arg_mcv[arg_mcv_i] = .{ .register = param_int_reg };
......@@ -19850,16 +20532,18 @@ fn resolveCallingConventionValues(
1985020532 },
1985120533 .sse, .float, .float_combine => {
1985220534 const param_sse_regs = abi.getCAbiSseParamRegs(resolved_cc);
19853 if (param_sse_reg_i >= param_sse_regs.len) break;
20535 const abi_size: u32 = @intCast(ty.abiSize(zcu));
20536 const reg_size = @min(abi_size, self.vectorSize(.float));
20537 var byte_offset: u32 = 0;
20538 while (byte_offset < abi_size) : (byte_offset += reg_size) {
20539 if (param_sse_reg_i >= param_sse_regs.len) break :classes;
1985420540
19855 const param_sse_reg = registerAlias(
19856 abi.getCAbiSseParamRegs(resolved_cc)[param_sse_reg_i],
19857 @intCast(ty.abiSize(zcu)),
19858 );
19859 param_sse_reg_i += 1;
20541 const param_sse_reg = registerAlias(param_sse_regs[param_sse_reg_i], reg_size);
20542 param_sse_reg_i += 1;
1986020543
19861 arg_mcv[arg_mcv_i] = .{ .register = param_sse_reg };
19862 arg_mcv_i += 1;
20544 arg_mcv[arg_mcv_i] = .{ .register = param_sse_reg };
20545 arg_mcv_i += 1;
20546 }
1986320547 },
1986420548 .sseup => assert(arg_mcv[arg_mcv_i - 1].register.class() == .sse),
1986520549 .x87, .x87up, .complex_x87, .memory, .win_i128 => switch (resolved_cc) {
......@@ -19908,7 +20592,21 @@ fn resolveCallingConventionValues(
1990820592 arg.* = switch (arg_mcv_i) {
1990920593 else => unreachable,
1991020594 1 => arg_mcv[0],
19911 2 => .{ .register_pair = .{ arg_mcv[0].register, arg_mcv[1].register } },
20595 2 => .{ .register_pair = .{
20596 arg_mcv[0].register,
20597 arg_mcv[1].register,
20598 } },
20599 3 => .{ .register_triple = .{
20600 arg_mcv[0].register,
20601 arg_mcv[1].register,
20602 arg_mcv[2].register,
20603 } },
20604 4 => .{ .register_quadruple = .{
20605 arg_mcv[0].register,
20606 arg_mcv[1].register,
20607 arg_mcv[2].register,
20608 arg_mcv[3].register,
20609 } },
1991220610 };
1991320611 continue;
1991420612 }
......@@ -20052,32 +20750,40 @@ fn memSize(self: *CodeGen, ty: Type) Memory.Size {
2005220750 };
2005320751}
2005420752
20055fn splitType(self: *CodeGen, ty: Type) ![2]Type {
20753fn splitType(self: *CodeGen, comptime parts_len: usize, ty: Type) ![parts_len]Type {
2005620754 const pt = self.pt;
2005720755 const zcu = pt.zcu;
20756 var parts: [parts_len]Type = undefined;
20757 if (ty.isVector(zcu)) if (std.math.divExact(u32, ty.vectorLen(zcu), parts_len)) |vec_len| return .{
20758 try pt.vectorType(.{ .len = vec_len, .child = ty.scalarType(zcu).toIntern() }),
20759 } ** parts_len else |err| switch (err) {
20760 error.DivisionByZero => unreachable,
20761 error.UnexpectedRemainder => {},
20762 };
2005820763 const classes = std.mem.sliceTo(&abi.classifySystemV(ty, zcu, self.target.*, .other), .none);
20059 var parts: [2]Type = undefined;
20060 if (classes.len == 2) for (&parts, classes, 0..) |*part, class, part_i| {
20764 if (classes.len == parts_len) for (&parts, classes, 0..) |*part, class, part_i| {
2006120765 part.* = switch (class) {
20062 .integer => switch (part_i) {
20063 0 => Type.u64,
20064 1 => part: {
20065 const elem_size = ty.abiAlignment(zcu).minStrict(.@"8").toByteUnits().?;
20066 const elem_ty = try pt.intType(.unsigned, @intCast(elem_size * 8));
20067 break :part switch (@divExact(ty.abiSize(zcu) - 8, elem_size)) {
20068 1 => elem_ty,
20069 else => |len| try pt.arrayType(.{ .len = len, .child = elem_ty.toIntern() }),
20070 };
20071 },
20072 else => unreachable,
20766 .integer => if (part_i < parts_len - 1)
20767 Type.u64
20768 else part: {
20769 const elem_size = ty.abiAlignment(zcu).minStrict(.@"8").toByteUnits().?;
20770 const elem_ty = try pt.intType(.unsigned, @intCast(elem_size * 8));
20771 break :part switch (@divExact(ty.abiSize(zcu) - part_i * 8, elem_size)) {
20772 1 => elem_ty,
20773 else => |array_len| try pt.arrayType(.{ .len = array_len, .child = elem_ty.toIntern() }),
20774 };
2007320775 },
2007420776 .float => Type.f32,
2007520777 .float_combine => try pt.arrayType(.{ .len = 2, .child = .f32_type }),
2007620778 .sse => Type.f64,
2007720779 else => break,
2007820780 };
20079 } else if (parts[0].abiSize(zcu) + parts[1].abiSize(zcu) == ty.abiSize(zcu)) return parts;
20080 return self.fail("TODO implement splitType for {}", .{ty.fmt(pt)});
20781 } else {
20782 var part_sizes: u64 = 0;
20783 for (parts) |part| part_sizes += part.abiSize(zcu);
20784 if (part_sizes == ty.abiSize(zcu)) return parts;
20785 };
20786 return self.fail("TODO implement splitType({d}, {})", .{ parts_len, ty.fmt(pt) });
2008120787}
2008220788
2008320789/// Truncates the value in the register in place.
......@@ -20297,6 +21003,7 @@ const Temp = struct {
2029721003 .immediate,
2029821004 .eflags,
2029921005 .register_offset,
21006 .register_mask,
2030021007 .memory,
2030121008 .load_symbol,
2030221009 .lea_symbol,
......@@ -20314,6 +21021,8 @@ const Temp = struct {
2031421021 => false,
2031521022 .register,
2031621023 .register_pair,
21024 .register_triple,
21025 .register_quadruple,
2031721026 .register_overflow,
2031821027 => true,
2031921028 .load_frame => |frame_addr| !frame_addr.index.isNamed(),
......@@ -20330,7 +21039,7 @@ const Temp = struct {
2033021039 cg.temp_type[@intFromEnum(new_temp_index)] = Type.usize;
2033121040 cg.next_temp_index = @enumFromInt(@intFromEnum(new_temp_index) + 1);
2033221041 switch (temp.tracking(cg).short) {
20333 else => |tag| std.debug.panic("{s}: {any}\n", .{ @src().fn_name, tag }),
21042 else => |mcv| std.debug.panic("{s}: {}\n", .{ @src().fn_name, mcv }),
2033421043 .register => |reg| {
2033521044 const new_reg =
2033621045 try cg.register_manager.allocReg(new_temp_index.toIndex(), abi.RegisterClass.gp);
......@@ -20434,7 +21143,7 @@ const Temp = struct {
2043421143 const new_temp_index = cg.next_temp_index;
2043521144 cg.temp_type[@intFromEnum(new_temp_index)] = Type.usize;
2043621145 switch (temp.tracking(cg).short) {
20437 else => |tag| std.debug.panic("{s}: {any}\n", .{ @src().fn_name, tag }),
21146 else => |mcv| std.debug.panic("{s}: {}\n", .{ @src().fn_name, mcv }),
2043821147 .immediate => |imm| {
2043921148 assert(limb_index == 0);
2044021149 new_temp_index.tracking(cg).* = .init(.{ .immediate = imm });
......@@ -20635,6 +21344,17 @@ const Temp = struct {
2063521344 first_temp.* = result_temp;
2063621345 }
2063721346
21347 fn asMask(temp: Temp, kind: MaskKind, inverted: bool, scalar: Memory.Size, cg: *CodeGen) void {
21348 assert(scalar != .none);
21349 const mcv = &temp.unwrap(cg).temp.tracking(cg).short;
21350 mcv.* = .{ .register_mask = .{
21351 .reg = mcv.register,
21352 .kind = kind,
21353 .inverted = inverted,
21354 .scalar = scalar,
21355 } };
21356 }
21357
2063821358 fn toLea(temp: *Temp, cg: *CodeGen) !bool {
2063921359 switch (temp.tracking(cg).short) {
2064021360 .none,
......@@ -20643,7 +21363,10 @@ const Temp = struct {
2064321363 .undef,
2064421364 .eflags,
2064521365 .register_pair,
21366 .register_triple,
21367 .register_quadruple,
2064621368 .register_overflow,
21369 .register_mask,
2064721370 .elementwise_regs_then_frame,
2064821371 .reserved_frame,
2064921372 .air_ref,
......@@ -20677,10 +21400,7 @@ const Temp = struct {
2067721400
2067821401 fn toBase(temp: *Temp, cg: *CodeGen) !bool {
2067921402 const temp_tracking = temp.tracking(cg);
20680 switch (temp_tracking.short) {
20681 else => {},
20682 .indirect, .load_frame => return false,
20683 }
21403 if (temp_tracking.short.isBase()) return false;
2068421404 const new_temp_index = cg.next_temp_index;
2068521405 cg.temp_type[@intFromEnum(new_temp_index)] = temp.typeOf(cg);
2068621406 const new_reg =
......@@ -20697,7 +21417,7 @@ const Temp = struct {
2069721417 const val_abi_size: u32 = @intCast(val_ty.abiSize(cg.pt.zcu));
2069821418 const val = try cg.tempAlloc(val_ty);
2069921419 switch (val.tracking(cg).short) {
20700 else => |tag| std.debug.panic("{s}: {any}\n", .{ @src().fn_name, tag }),
21420 else => |mcv| std.debug.panic("{s}: {}\n", .{ @src().fn_name, mcv }),
2070121421 .register => |val_reg| {
2070221422 while (try ptr.toLea(cg)) {}
2070321423 switch (val_reg.class()) {
......@@ -20706,7 +21426,7 @@ const Temp = struct {
2070621426 registerAlias(val_reg, val_abi_size),
2070721427 try ptr.tracking(cg).short.deref().mem(cg, .{ .size = cg.memSize(val_ty) }),
2070821428 ),
20709 else => |tag| std.debug.panic("{s}: {any}\n", .{ @src().fn_name, tag }),
21429 else => |mcv| std.debug.panic("{s}: {}\n", .{ @src().fn_name, mcv }),
2071021430 }
2071121431 },
2071221432 .load_frame => |val_frame_addr| {
......@@ -20724,7 +21444,7 @@ const Temp = struct {
2072421444 const val_ty = val.typeOf(cg);
2072521445 const val_abi_size: u32 = @intCast(val_ty.abiSize(cg.pt.zcu));
2072621446 val: switch (val.tracking(cg).short) {
20727 else => |tag| std.debug.panic("{s}: {any}\n", .{ @src().fn_name, tag }),
21447 else => |mcv| std.debug.panic("{s}: {}\n", .{ @src().fn_name, mcv }),
2072821448 .immediate => |imm| if (std.math.cast(i32, imm)) |s| {
2072921449 while (try ptr.toLea(cg)) {}
2073021450 try cg.asmMemoryImmediate(
......@@ -20742,7 +21462,7 @@ const Temp = struct {
2074221462 try ptr.tracking(cg).short.deref().mem(cg, .{ .size = cg.memSize(val_ty) }),
2074321463 registerAlias(val_reg, val_abi_size),
2074421464 ),
20745 else => |tag| std.debug.panic("{s}: {any}\n", .{ @src().fn_name, tag }),
21465 else => |mcv| std.debug.panic("{s}: {}\n", .{ @src().fn_name, mcv }),
2074621466 }
2074721467 },
2074821468 }
......@@ -20876,6 +21596,7 @@ fn reuseTemp(
2087621596 .register_pair,
2087721597 .register_offset,
2087821598 .register_overflow,
21599 .register_mask,
2087921600 .indirect,
2088021601 => for (tracking.short.getRegs()) |tracked_reg| {
2088121602 if (RegisterManager.indexOfRegIntoTracked(tracked_reg)) |tracked_index| {
......@@ -20913,6 +21634,26 @@ fn tempAllocReg(cg: *CodeGen, ty: Type, rc: RegisterManager.RegisterBitSet) !Tem
2091321634 return .{ .index = temp_index.toIndex() };
2091421635}
2091521636
21637fn tempAllocRegPair(cg: *CodeGen, ty: Type, rc: RegisterManager.RegisterBitSet) !Temp {
21638 const temp_index = cg.next_temp_index;
21639 temp_index.tracking(cg).* = .init(
21640 .{ .register_pair = try cg.register_manager.allocRegs(2, temp_index.toIndex(), rc) },
21641 );
21642 cg.temp_type[@intFromEnum(temp_index)] = ty;
21643 cg.next_temp_index = @enumFromInt(@intFromEnum(temp_index) + 1);
21644 return .{ .index = temp_index.toIndex() };
21645}
21646
21647fn tempAllocMem(cg: *CodeGen, ty: Type) !Temp {
21648 const temp_index = cg.next_temp_index;
21649 temp_index.tracking(cg).* = .init(
21650 try cg.allocRegOrMemAdvanced(ty, temp_index.toIndex(), false),
21651 );
21652 cg.temp_type[@intFromEnum(temp_index)] = ty;
21653 cg.next_temp_index = @enumFromInt(@intFromEnum(temp_index) + 1);
21654 return .{ .index = temp_index.toIndex() };
21655}
21656
2091621657fn tempFromValue(cg: *CodeGen, ty: Type, value: MCValue) !Temp {
2091721658 const temp_index = cg.next_temp_index;
2091821659 temp_index.tracking(cg).* = .init(value);
......@@ -20993,30 +21734,23 @@ const Operand = union(enum) {
2099321734 inst: Mir.Inst.Index,
2099421735};
2099521736
20996const SelectLoop = struct {
20997 element_reloc: Mir.Inst.Index,
20998 element_offset: union(enum) {
20999 unused,
21000 known: u31,
21001 temp: Temp,
21002 },
21003 element_size: ?u13,
21004 limb_reloc: Mir.Inst.Index,
21005 limb_offset: union(enum) {
21006 unused,
21007 known: u31,
21008 temp: Temp,
21009 },
21010 limb_size: ?u8,
21011 remaining_size: ?u64,
21012};
21013
2101421737const Pattern = struct {
2101521738 ops: []const Op,
2101621739 commute: struct { u8, u8 } = .{ 0, 0 },
2101721740
2101821741 const Set = struct {
2101921742 required_features: []const std.Target.x86.Feature = &.{},
21743 scalar: union(enum) {
21744 any,
21745 bool,
21746 float: Memory.Size,
21747 any_int: Memory.Size,
21748 signed_int: Memory.Size,
21749 unsigned_int: Memory.Size,
21750 any_float_or_int: Memory.Size,
21751 } = .any,
21752 clobbers: struct { eflags: bool = false } = .{},
21753 invert_result: bool = false,
2102021754 loop: enum {
2102121755 /// only execute the instruction once
2102221756 once,
......@@ -21050,6 +21784,18 @@ const Pattern = struct {
2105021784 xmm,
2105121785 /// any 256-bit sse register
2105221786 ymm,
21787 /// a 64-bit mmx register mask
21788 mm_mask,
21789 /// a 128-bit sse register mask
21790 xmm_mask,
21791 /// a 256-bit sse register mask
21792 ymm_mask,
21793 /// a 64-bit mmx register sign mask
21794 mm_sign_mask,
21795 /// a 128-bit sse register sign mask
21796 xmm_sign_mask,
21797 /// a 256-bit sse register sign mask
21798 ymm_sign_mask,
2105321799 /// any memory
2105421800 mem,
2105521801 /// a limb stored in a gpr
......@@ -21062,41 +21808,82 @@ const Pattern = struct {
2106221808 ymm_limb,
2106321809 /// a limb stored in memory
2106421810 mem_limb,
21811 /// a limb stored in a 64-bit mmx register mask
21812 mm_mask_limb,
21813 /// a limb stored in a 128-bit sse register masuk
21814 xmm_mask_limb,
21815 /// a limb stored in a 256-bit sse register masuk
21816 ymm_mask_limb,
2106521817 /// specific immediate
2106621818 imm: i8,
2106721819 /// any immediate signed extended from 32 bits
2106821820 simm32,
21821 /// a temp general purpose register containing all ones
21822 umax_gpr,
21823 /// a temp 64-bit mmx register containing all ones
21824 umax_mm,
21825 /// a temp 128-bit sse register containing all ones
21826 umax_xmm,
21827 /// a temp 256-bit sse register containing all ones
21828 umax_ymm,
2106921829
2107021830 fn matches(op: Op, is_mut: bool, temp: Temp, cg: *CodeGen) bool {
21071 const abi_size = temp.typeOf(cg).abiSize(cg.pt.zcu);
21072 return switch (op) {
21831 switch (op) {
2107321832 .implicit, .explicit => unreachable,
21833 else => {},
21834 // temp is undefined
21835 .umax_gpr, .umax_mm, .umax_xmm, .umax_ymm => return true,
21836 }
21837 const temp_ty = temp.typeOf(cg);
21838 const abi_size = temp_ty.abiSize(cg.pt.zcu);
21839 return switch (op) {
21840 .implicit, .explicit, .umax_gpr, .umax_mm, .umax_xmm, .umax_ymm => unreachable,
2107421841 .gpr => abi_size <= 8 and switch (temp.tracking(cg).short) {
2107521842 .register => |reg| reg.class() == .general_purpose,
2107621843 .register_offset => |reg_off| reg_off.reg.class() == .general_purpose and
2107721844 reg_off.off == 0,
21078 else => cg.regClassForType(temp.typeOf(cg)) == .general_purpose,
21845 else => cg.regClassForType(temp_ty) == .general_purpose,
2107921846 },
21080 .mm => abi_size <= 8 and switch (temp.tracking(cg).short) {
21847 .mm, .mm_mask, .mm_sign_mask => abi_size <= 8 and switch (temp.tracking(cg).short) {
2108121848 .register => |reg| reg.class() == .mmx,
2108221849 .register_offset => |reg_off| reg_off.reg.class() == .mmx and reg_off.off == 0,
21083 else => cg.regClassForType(temp.typeOf(cg)) == .mmx,
21850 else => cg.regClassForType(temp_ty) == .mmx,
2108421851 },
21085 .xmm => abi_size > 8 and abi_size <= 16 and switch (temp.tracking(cg).short) {
21852 .xmm, .xmm_mask, .xmm_sign_mask => abi_size > 8 and abi_size <= 16 and switch (temp.tracking(cg).short) {
2108621853 .register => |reg| reg.class() == .sse,
2108721854 .register_offset => |reg_off| reg_off.reg.class() == .sse and reg_off.off == 0,
21088 else => cg.regClassForType(temp.typeOf(cg)) == .sse,
21855 else => cg.regClassForType(temp_ty) == .sse,
2108921856 },
21090 .ymm => abi_size > 16 and abi_size <= 32 and switch (temp.tracking(cg).short) {
21857 .ymm, .ymm_mask, .ymm_sign_mask => abi_size > 16 and abi_size <= 32 and switch (temp.tracking(cg).short) {
2109121858 .register => |reg| reg.class() == .sse,
2109221859 .register_offset => |reg_off| reg_off.reg.class() == .sse and reg_off.off == 0,
21093 else => cg.regClassForType(temp.typeOf(cg)) == .sse,
21860 else => cg.regClassForType(temp_ty) == .sse,
2109421861 },
2109521862 .mem, .mem_limb => (!is_mut or temp.isMut(cg)) and temp.tracking(cg).short.isMemory(),
21096 .gpr_limb => abi_size > 8,
21097 .mm_limb => abi_size > 8 and (!is_mut or temp.isMut(cg)) and temp.tracking(cg).short.isMemory() and cg.regClassForType(temp.typeOf(cg)) == .mmx,
21098 .xmm_limb => abi_size > 16 and (!is_mut or temp.isMut(cg)) and temp.tracking(cg).short.isMemory(),
21099 .ymm_limb => abi_size > 32 and (!is_mut or temp.isMut(cg)) and temp.tracking(cg).short.isMemory(),
21863 .gpr_limb => abi_size > 8 and switch (temp.tracking(cg).short) {
21864 inline .register_pair, .register_triple, .register_quadruple => |regs| for (regs) |reg| {
21865 if (reg.class() != .general_purpose) break false;
21866 } else true,
21867 else => |mcv| mcv.isMemory(),
21868 },
21869 .mm_limb, .mm_mask_limb => abi_size > 8 and switch (temp.tracking(cg).short) {
21870 inline .register_pair, .register_triple, .register_quadruple => |regs| for (regs) |reg| {
21871 if (reg.class() != .mmx) break false;
21872 } else true,
21873 else => |mcv| mcv.isMemory() and cg.regClassForType(temp_ty) == .mmx,
21874 },
21875 .xmm_limb, .xmm_mask_limb => abi_size > 16 and switch (temp.tracking(cg).short) {
21876 inline .register_pair, .register_triple, .register_quadruple => |regs| for (regs) |reg| {
21877 if (reg.class() != .sse) break false;
21878 } else true,
21879 else => |mcv| mcv.isMemory(),
21880 },
21881 .ymm_limb, .ymm_mask_limb => abi_size > 32 and switch (temp.tracking(cg).short) {
21882 inline .register_pair, .register_triple, .register_quadruple => |regs| for (regs) |reg| {
21883 if (reg.class() != .sse) break false;
21884 } else true,
21885 else => |mcv| mcv.isMemory(),
21886 },
2110021887 .imm => |specific_imm| if (is_mut) unreachable else switch (temp.tracking(cg).short) {
2110121888 .immediate => |imm| @as(i64, @bitCast(imm)) == specific_imm,
2110221889 else => false,
......@@ -21109,78 +21896,176 @@ const Pattern = struct {
2110921896 }
2111021897 };
2111121898};
21112fn select(cg: *CodeGen, dst_temps: []Temp, src_temps: []const *Temp, pattern_sets: []const Pattern.Set) !void {
21113 var loop: SelectLoop = .{
21899const SelectOptions = struct {
21900 invert_result: bool = false,
21901};
21902fn select(
21903 cg: *CodeGen,
21904 dst_temps: []Temp,
21905 dst_tys: []const Type,
21906 src_temps: []Temp,
21907 pattern_sets: []const Pattern.Set,
21908 opts: SelectOptions,
21909) !void {
21910 var loop: struct {
21911 element_reloc: Mir.Inst.Index,
21912 element_offset: Offset,
21913 element_size: ?u13,
21914 limb_reloc: Mir.Inst.Index,
21915 limb_offset: Offset,
21916 limb_size: ?u8,
21917 mask_limb_temp: ?Temp,
21918 mask_limb_offset: Offset,
21919 mask_limb_offset_lock: ?RegisterLock,
21920 mask_limb_bit_size: ?u7,
21921 mask_store_temp: ?Temp,
21922 mask_store_reg: ?Register,
21923 mask_store_bit_size: ?u7,
21924 remaining_size: ?u64,
21925
21926 const Offset = union(enum) {
21927 unused,
21928 known: u31,
21929 temp: Temp,
21930 };
21931 } = .{
2111421932 .element_reloc = undefined,
2111521933 .element_offset = .unused,
2111621934 .element_size = null,
2111721935 .limb_reloc = undefined,
2111821936 .limb_offset = .unused,
2111921937 .limb_size = null,
21938 .mask_limb_temp = null,
21939 .mask_limb_offset = .unused,
21940 .mask_limb_offset_lock = null,
21941 .mask_limb_bit_size = null,
21942 .mask_store_temp = null,
21943 .mask_store_reg = null,
21944 .mask_store_bit_size = null,
2112021945 .remaining_size = null,
2112121946 };
2112221947 var extra_temps: [4]?Temp = @splat(null);
2112321948 pattern_sets: for (pattern_sets) |pattern_set| {
2112421949 for (pattern_set.required_features) |required_feature| if (!cg.hasFeature(required_feature)) continue :pattern_sets;
21950 for (src_temps) |src_temp| switch (pattern_set.scalar) {
21951 .any => {},
21952 .bool => if (src_temp.typeOf(cg).scalarType(cg.pt.zcu).toIntern() != .bool_type) continue :pattern_sets,
21953 .float => |size| {
21954 const scalar_ty = src_temp.typeOf(cg).scalarType(cg.pt.zcu);
21955 if (!scalar_ty.isRuntimeFloat()) continue :pattern_sets;
21956 if (scalar_ty.floatBits(cg.target.*) != size.bitSize()) continue :pattern_sets;
21957 },
21958 .any_int => |size| {
21959 const scalar_ty = src_temp.typeOf(cg).scalarType(cg.pt.zcu);
21960 if (!scalar_ty.isAbiInt(cg.pt.zcu)) continue :pattern_sets;
21961 if (scalar_ty.intInfo(cg.pt.zcu).bits > size.bitSize()) continue :pattern_sets;
21962 },
21963 .signed_int => |size| {
21964 const scalar_ty = src_temp.typeOf(cg).scalarType(cg.pt.zcu);
21965 if (!scalar_ty.isAbiInt(cg.pt.zcu)) continue :pattern_sets;
21966 const scalar_info = scalar_ty.intInfo(cg.pt.zcu);
21967 if (scalar_info.signedness != .signed) continue :pattern_sets;
21968 if (scalar_info.bits > size.bitSize()) continue :pattern_sets;
21969 },
21970 .unsigned_int => |size| {
21971 const scalar_ty = src_temp.typeOf(cg).scalarType(cg.pt.zcu);
21972 if (!scalar_ty.isAbiInt(cg.pt.zcu)) continue :pattern_sets;
21973 const scalar_info = scalar_ty.intInfo(cg.pt.zcu);
21974 if (scalar_info.signedness != .unsigned) continue :pattern_sets;
21975 if (scalar_info.bits > size.bitSize()) continue :pattern_sets;
21976 },
21977 .any_float_or_int => |size| {
21978 const scalar_ty = src_temp.typeOf(cg).scalarType(cg.pt.zcu);
21979 if (scalar_ty.isRuntimeFloat()) {
21980 if (scalar_ty.floatBits(cg.target.*) != size.bitSize()) continue :pattern_sets;
21981 } else if (scalar_ty.isAbiInt(cg.pt.zcu)) {
21982 if (scalar_ty.intInfo(cg.pt.zcu).bits > size.bitSize()) continue :pattern_sets;
21983 } else continue :pattern_sets;
21984 },
21985 };
2112521986 patterns: for (pattern_set.patterns) |pattern| {
2112621987 for (src_temps, pattern.ops[dst_temps.len..]) |src_temp, src_op| {
2112721988 const ref_src_op, const is_mut = switch (src_op) {
21128 .implicit, .explicit => |op_index| .{ pattern.ops[op_index], true },
21989 .implicit, .explicit => |linked_index| .{ pattern.ops[linked_index], true },
2112921990 else => .{ src_op, false },
2113021991 };
21131 if (!ref_src_op.matches(is_mut, src_temp.*, cg)) continue :patterns;
21992 if (!ref_src_op.matches(is_mut, src_temp, cg)) continue :patterns;
2113221993 }
21133 while (true) for (src_temps, pattern.ops[dst_temps.len..]) |src_temp, src_op| {
21134 if (switch (switch (src_op) {
21135 .implicit, .explicit => |op_index| pattern.ops[op_index],
21994
21995 while (true) for (src_temps, pattern.ops[dst_temps.len..]) |*src_temp, src_op| {
21996 if (changed: switch (switch (src_op) {
21997 .implicit, .explicit => |linked_index| pattern.ops[linked_index],
2113621998 else => src_op,
2113721999 }) {
2113822000 .implicit, .explicit => unreachable,
2113922001 .gpr => try src_temp.toRegClass(.general_purpose, cg),
21140 .mm => try src_temp.toRegClass(.mmx, cg),
21141 .xmm, .ymm => try src_temp.toRegClass(.sse, cg),
21142 .mem, .imm, .simm32 => false,
21143 .gpr_limb, .mm_limb, .xmm_limb, .ymm_limb, .mem_limb => switch (src_temp.tracking(cg).short) {
21144 .register_pair => false,
22002 .mm, .mm_mask, .mm_sign_mask => try src_temp.toRegClass(.mmx, cg),
22003 .xmm,
22004 .ymm,
22005 .xmm_mask,
22006 .ymm_mask,
22007 .xmm_sign_mask,
22008 .ymm_sign_mask,
22009 => try src_temp.toRegClass(.sse, cg),
22010 .mem => try src_temp.toBase(cg),
22011 .imm, .simm32 => false,
22012 .gpr_limb,
22013 .mm_limb,
22014 .xmm_limb,
22015 .ymm_limb,
22016 .mem_limb,
22017 => switch (src_temp.tracking(cg).short) {
22018 .register_pair, .register_triple, .register_quadruple => false,
2114522019 else => try src_temp.toBase(cg),
2114622020 },
22021 .mm_mask_limb,
22022 .xmm_mask_limb,
22023 .ymm_mask_limb,
22024 => if (!cg.hasFeature(.bmi2) and !cg.register_manager.isKnownRegFree(.rcx)) {
22025 try cg.register_manager.getKnownReg(.rcx, null);
22026 loop.mask_limb_offset_lock = cg.register_manager.lockKnownRegAssumeUnused(.rcx);
22027 break :changed true;
22028 } else false,
22029 .umax_gpr, .umax_mm, .umax_xmm, .umax_ymm => false,
2114722030 }) break;
2114822031 } else break;
22032
22033 var dst_is_linked: std.StaticBitSet(4) = .initEmpty();
2114922034 var mir_ops_len = dst_temps.len;
2115022035 for (src_temps, pattern.ops[dst_temps.len..]) |src_temp, src_op| {
21151 const ref_src_op, const extra_temp = op: switch (src_op) {
21152 .implicit => |op_index| {
21153 dst_temps[op_index] = if (src_temp.isMut(cg))
21154 src_temp.*
21155 else
21156 try cg.tempAlloc(src_temp.typeOf(cg));
21157 break :op .{ pattern.ops[op_index], &extra_temps[op_index] };
21158 },
21159 .explicit => |op_index| {
21160 dst_temps[op_index] = if (src_temp.isMut(cg))
21161 src_temp.*
21162 else
21163 try cg.tempAlloc(src_temp.typeOf(cg));
21164 defer mir_ops_len += 1;
21165 break :op .{ pattern.ops[op_index], &extra_temps[mir_ops_len] };
21166 },
21167 else => {
21168 defer mir_ops_len += 1;
21169 break :op .{ src_op, &extra_temps[mir_ops_len] };
22036 defer mir_ops_len += @intFromBool(src_op != .implicit);
22037 const linked_src_op, const extra_temp = op: switch (src_op) {
22038 .implicit, .explicit => |linked_index| {
22039 if (src_temp.isMut(cg)) {
22040 dst_temps[linked_index] = src_temp;
22041 dst_is_linked.set(linked_index);
22042 }
22043 break :op .{ pattern.ops[linked_index], &extra_temps[linked_index] };
2117022044 },
22045 else => .{ src_op, &extra_temps[mir_ops_len] },
2117122046 };
21172 const limb_size: u8, const rc = switch (ref_src_op) {
22047 const limb_size: u8, const rc = switch (linked_src_op) {
2117322048 else => continue,
2117422049 .gpr_limb => .{ 8, abi.RegisterClass.gp },
21175 .mm_limb => .{ 8, @panic("TODO") },
21176 .xmm_limb => .{ 16, abi.RegisterClass.sse },
21177 .ymm_limb => .{ 32, abi.RegisterClass.sse },
22050 .mm_limb, .mm_mask_limb => .{ 8, @panic("TODO") },
22051 .xmm_limb, .xmm_mask_limb => .{ 16, abi.RegisterClass.sse },
22052 .ymm_limb, .ymm_mask_limb => .{ 32, abi.RegisterClass.sse },
22053 .umax_gpr, .umax_mm, .umax_xmm, .umax_ymm => {
22054 assert(extra_temp.* == null);
22055 extra_temp.* = try cg.tempAllocReg(Type.usize, switch (linked_src_op) {
22056 else => unreachable,
22057 .umax_gpr => abi.RegisterClass.gp,
22058 .umax_mm => @panic("TODO"),
22059 .umax_xmm, .umax_ymm => abi.RegisterClass.sse,
22060 });
22061 continue;
22062 },
2117822063 };
2117922064 assert(loop.limb_size == null or loop.limb_size == limb_size);
2118022065 loop.limb_size = limb_size;
2118122066 loop.remaining_size = loop.remaining_size orelse src_temp.typeOf(cg).abiSize(cg.pt.zcu);
2118222067 switch (src_temp.tracking(cg).short) {
21183 .register_pair => switch (loop.limb_offset) {
22068 .register_pair, .register_triple, .register_quadruple => switch (loop.limb_offset) {
2118422069 .unused, .temp => loop.limb_offset = .{ .known = 0 },
2118522070 .known => {},
2118622071 },
......@@ -21189,25 +22074,130 @@ fn select(cg: *CodeGen, dst_temps: []Temp, src_temps: []const *Temp, pattern_set
2118922074 .unused => loop.limb_offset = .{ .temp = undefined },
2119022075 .known, .temp => {},
2119122076 }
22077 assert(extra_temp.* == null);
2119222078 extra_temp.* = try cg.tempAllocReg(Type.usize, rc);
2119322079 },
2119422080 }
2119522081 }
22082 for (
22083 0..,
22084 dst_temps,
22085 pattern.ops[0..dst_temps.len],
22086 dst_tys,
22087 extra_temps[0..dst_temps.len],
22088 ) |dst_index, *dst_temp, dst_op, dst_ty, *extra_temp| switch (dst_op) {
22089 else => if (!dst_is_linked.isSet(dst_index)) {
22090 dst_temp.* = dst_temp: switch (dst_op) {
22091 .implicit => unreachable,
22092 .explicit => |linked_index| dst_temps[linked_index],
22093 .gpr => try cg.tempAllocReg(dst_ty, abi.RegisterClass.gp),
22094 .mm, .mm_mask, .mm_sign_mask => @panic("TODO"),
22095 .xmm, .xmm_mask, .xmm_sign_mask => try cg.tempAllocReg(dst_ty, abi.RegisterClass.sse),
22096 .ymm, .ymm_mask, .ymm_sign_mask => try cg.tempAllocReg(dst_ty, abi.RegisterClass.sse),
22097 .mem => @panic("TODO"),
22098 .gpr_limb, .mm_limb, .xmm_limb, .ymm_limb => {
22099 if (extra_temp.* == null) extra_temp.* = try cg.tempAllocReg(Type.usize, switch (dst_op) {
22100 else => unreachable,
22101 .gpr_limb => abi.RegisterClass.gp,
22102 .mm_limb => @panic("TODO"),
22103 .xmm_limb, .ymm_limb => abi.RegisterClass.sse,
22104 });
22105 break :dst_temp try cg.tempAlloc(dst_ty);
22106 },
22107 .mem_limb => try cg.tempAlloc(dst_ty),
22108 .mm_mask_limb, .xmm_mask_limb, .ymm_mask_limb => unreachable, // already checked
22109 .imm, .simm32, .umax_gpr, .umax_mm, .umax_xmm, .umax_ymm => unreachable, // unmodifiable destination
22110 };
22111 },
22112 .mm_mask_limb, .xmm_mask_limb, .ymm_mask_limb => {
22113 const scalar_size = @divExact(switch (pattern_set.scalar) {
22114 .any, .bool => unreachable,
22115 .float, .any_int, .signed_int, .unsigned_int, .any_float_or_int => |size| size,
22116 }.bitSize(), 8);
22117 const mask_bit_size = @divExact(loop.remaining_size.?, scalar_size);
22118 const mask_limb_bit_size: u7 = @intCast(@divExact(loop.limb_size.?, scalar_size));
22119 assert(loop.mask_limb_bit_size == null or loop.mask_limb_bit_size == mask_limb_bit_size);
22120 loop.mask_limb_bit_size = mask_limb_bit_size;
22121 const mask_store_bit_size = mask_store_bit_size: {
22122 // Try to match limb size so that no shifting will be needed.
22123 if (mask_limb_bit_size % 8 == 0) break :mask_store_bit_size mask_limb_bit_size;
22124 // If abi size <= 8 the entire value can be stored at once,
22125 // enabling store forwarding and minimizing store buffer usage.
22126 // Otherwise, we will be performing shifts that need to wrap at
22127 // store size, which for x86 requires 32 or 64, so just pick 64
22128 // for the same reasons as above.
22129 break :mask_store_bit_size @min(mask_bit_size, 64);
22130 };
22131 assert(loop.mask_store_bit_size == null or loop.mask_store_bit_size == mask_store_bit_size);
22132 loop.mask_store_bit_size = mask_store_bit_size;
22133 loop.mask_limb_offset = loop.limb_offset;
22134 if (extra_temp.* == null) extra_temp.* = try cg.tempAllocReg(Type.usize, switch (dst_op) {
22135 else => unreachable,
22136 .mm_mask_limb => @panic("TODO"),
22137 .xmm_mask_limb, .ymm_mask_limb => abi.RegisterClass.sse,
22138 });
22139 if (loop.mask_limb_temp == null) loop.mask_limb_temp = try cg.tempAllocReg(Type.usize, abi.RegisterClass.gp);
22140 if (mask_limb_bit_size < mask_store_bit_size and loop.mask_store_reg == null) {
22141 loop.mask_store_temp = try cg.tempAllocReg(Type.usize, abi.RegisterClass.gp);
22142 loop.mask_store_reg = loop.mask_store_temp.?.tracking(cg).short.register;
22143 }
22144 dst_temp.* = if (mask_store_bit_size < mask_bit_size)
22145 try cg.tempAllocMem(dst_ty)
22146 else if (loop.mask_store_temp) |mask_store_temp| dst_temp: {
22147 loop.mask_store_temp = null;
22148 break :dst_temp mask_store_temp;
22149 } else try cg.tempAlloc(dst_ty);
22150 },
22151 };
22152 switch (loop.mask_limb_offset) {
22153 .unused, .known => {},
22154 .temp => |*mask_limb_offset| {
22155 if (cg.hasFeature(.bmi2)) {
22156 assert(loop.mask_limb_offset_lock == null);
22157 mask_limb_offset.* = try cg.tempAllocReg(Type.usize, abi.RegisterClass.gp);
22158 } else {
22159 if (loop.mask_limb_offset_lock) |lock| cg.register_manager.unlockReg(lock);
22160 loop.mask_limb_offset_lock = null;
22161 mask_limb_offset.* = try cg.tempFromValue(Type.usize, .{ .register = .rcx });
22162 }
22163 if (loop.mask_store_reg) |mask_store_reg| {
22164 const mask_store_alias = registerAlias(
22165 mask_store_reg,
22166 @min(std.math.divCeil(u7, loop.mask_store_bit_size.?, 8) catch unreachable, 4),
22167 );
22168 try cg.spillEflagsIfOccupied();
22169 try cg.asmRegisterRegister(.{ ._, .xor }, mask_store_alias, mask_store_alias);
22170 }
22171 },
22172 }
2119622173 switch (loop.element_offset) {
2119722174 .unused, .known => {},
2119822175 .temp => |*element_offset| {
2119922176 element_offset.* = try cg.tempAllocReg(Type.usize, abi.RegisterClass.gp);
2120022177 const element_offset_reg = element_offset.tracking(cg).short.register;
22178 try cg.spillEflagsIfOccupied();
2120122179 try cg.asmRegisterRegister(.{ ._, .xor }, element_offset_reg.to32(), element_offset_reg.to32());
2120222180 loop.element_reloc = @intCast(cg.mir_instructions.len);
2120322181 },
2120422182 }
22183 switch (loop.limb_offset) {
22184 .unused, .known => {},
22185 .temp => |*limb_offset| limb_offset.* = try cg.tempAllocReg(Type.usize, abi.RegisterClass.gp),
22186 }
2120522187 while (true) {
22188 switch (loop.mask_limb_offset) {
22189 .unused, .known => {},
22190 .temp => |mask_limb_offset| {
22191 const mask_limb_offset_reg = mask_limb_offset.tracking(cg).short.register.to32();
22192 try cg.spillEflagsIfOccupied();
22193 try cg.asmRegisterRegister(.{ ._, .xor }, mask_limb_offset_reg, mask_limb_offset_reg);
22194 },
22195 }
2120622196 switch (loop.limb_offset) {
2120722197 .unused, .known => {},
21208 .temp => |*limb_offset| {
21209 limb_offset.* = try cg.tempAllocReg(Type.usize, abi.RegisterClass.gp);
21210 const limb_offset_reg = limb_offset.tracking(cg).short.register;
22198 .temp => |limb_offset| {
22199 const limb_offset_reg = limb_offset.tracking(cg).short.register.to32();
22200 try cg.spillEflagsIfOccupied();
2121122201 try cg.asmRegisterRegister(.{ ._, .xor }, limb_offset_reg.to32(), limb_offset_reg.to32());
2121222202 loop.limb_reloc = @intCast(cg.mir_instructions.len);
2121322203 },
......@@ -21216,56 +22206,67 @@ fn select(cg: *CodeGen, dst_temps: []Temp, src_temps: []const *Temp, pattern_set
2121622206 var mir_ops: [4]Operand = @splat(.none);
2121722207 mir_ops_len = dst_temps.len;
2121822208 for (src_temps, pattern.ops[dst_temps.len..]) |src_temp, src_op| {
21219 const mir_op, const ref_src_op, const extra_temp = op: switch (src_op) {
21220 .implicit => |op_index| .{ &mir_ops[op_index], pattern.ops[op_index], &extra_temps[op_index] },
21221 .explicit => |op_index| {
21222 defer mir_ops_len += 1;
21223 break :op .{ &mir_ops[mir_ops_len], pattern.ops[op_index], &extra_temps[mir_ops_len] };
21224 },
21225 else => {
21226 defer mir_ops_len += 1;
21227 break :op .{ &mir_ops[mir_ops_len], src_op, &extra_temps[mir_ops_len] };
21228 },
22209 defer mir_ops_len += @intFromBool(src_op != .implicit);
22210 const mir_op, const linked_src_op, const extra_temp = switch (src_op) {
22211 .implicit => |linked_index| .{ &mir_ops[linked_index], pattern.ops[linked_index], extra_temps[linked_index] },
22212 .explicit => |linked_index| .{ &mir_ops[mir_ops_len], pattern.ops[linked_index], extra_temps[linked_index] },
22213 else => .{ &mir_ops[mir_ops_len], src_op, extra_temps[mir_ops_len] },
2122922214 };
21230 const src_mcv = src_temp.tracking(cg).short;
21231 switch (ref_src_op) {
21232 else => {},
21233 .gpr_limb, .mm_limb, .xmm_limb, .ymm_limb => switch (src_mcv) {
21234 .register_pair => {},
21235 else => try cg.asmRegisterMemory(
21236 switch (ref_src_op) {
21237 else => unreachable,
21238 .gpr_limb => .{ ._, .mov },
21239 .mm_limb => .{ ._q, .mov },
21240 .xmm_limb, .ymm_limb => .{ if (cg.hasFeature(.avx)) .v_ else ._, .movdqu },
22215 const src_mcv = switch (linked_src_op) {
22216 else => src_temp,
22217 // src_temp is undefined
22218 .umax_gpr, .umax_mm, .umax_xmm, .umax_ymm => extra_temp.?,
22219 }.tracking(cg).short;
22220 copy_limb: switch (src_mcv) {
22221 .register_pair, .register_triple, .register_quadruple => {},
22222 else => try cg.asmRegisterMemory(
22223 switch (linked_src_op) {
22224 else => break :copy_limb,
22225 .gpr_limb => .{ ._, .mov },
22226 .mm_limb, .mm_mask_limb => .{ ._q, .mov },
22227 .xmm_limb,
22228 .ymm_limb,
22229 .xmm_mask_limb,
22230 .ymm_mask_limb,
22231 => .{ if (cg.hasFeature(.avx)) .v_ else ._, .movdqu },
22232 },
22233 registerAlias(extra_temp.?.tracking(cg).short.register, loop.limb_size.?),
22234 try src_mcv.mem(cg, switch (loop.limb_offset) {
22235 .unused => unreachable,
22236 .known => |limb_offset| .{
22237 .size = .fromSize(loop.limb_size.?),
22238 .disp = limb_offset,
2124122239 },
21242 registerAlias(extra_temp.*.?.tracking(cg).short.register, loop.limb_size.?),
21243 try src_mcv.mem(cg, switch (loop.limb_offset) {
21244 .unused => unreachable,
21245 .known => |limb_offset| .{
21246 .size = .fromSize(loop.limb_size.?),
21247 .disp = limb_offset,
21248 },
21249 .temp => |limb_offset| .{
21250 .size = .fromSize(loop.limb_size.?),
21251 .index = limb_offset.tracking(cg).short.register.to64(),
21252 },
21253 }),
21254 ),
21255 },
22240 .temp => |limb_offset| .{
22241 .size = .fromSize(loop.limb_size.?),
22242 .index = limb_offset.tracking(cg).short.register.to64(),
22243 },
22244 }),
22245 ),
2125622246 }
21257 mir_op.* = switch (ref_src_op) {
22247 mir_op.* = switch (linked_src_op) {
2125822248 .implicit, .explicit => unreachable,
2125922249 .gpr => .{ .reg = registerAlias(
2126022250 src_mcv.register,
2126122251 @intCast(src_temp.typeOf(cg).abiSize(cg.pt.zcu)),
2126222252 ) },
21263 .mm => .{ .reg = src_mcv.register },
21264 .xmm => .{ .reg = src_mcv.register.to128() },
21265 .ymm => .{ .reg = src_mcv.register.to256() },
22253 .umax_gpr => .{ .reg = src_mcv.register.to64() }, // TODO: use other op size?
22254 .mm, .mm_mask, .mm_sign_mask, .umax_mm => .{ .reg = src_mcv.register },
22255 .xmm, .xmm_mask, .xmm_sign_mask, .umax_xmm => .{ .reg = src_mcv.register.to128() },
22256 .ymm, .ymm_mask, .ymm_sign_mask, .umax_ymm => .{ .reg = src_mcv.register.to256() },
2126622257 .mem => .{ .mem = try src_mcv.mem(cg, .{ .size = cg.memSize(src_temp.typeOf(cg)) }) },
21267 .gpr_limb, .mm_limb, .xmm_limb, .ymm_limb => switch (src_mcv) {
21268 .register_pair => |src_regs| switch (loop.limb_offset) {
22258 .gpr_limb,
22259 .mm_limb,
22260 .xmm_limb,
22261 .ymm_limb,
22262 .mm_mask_limb,
22263 .xmm_mask_limb,
22264 .ymm_mask_limb,
22265 => switch (src_mcv) {
22266 inline .register_pair,
22267 .register_triple,
22268 .register_quadruple,
22269 => |src_regs| switch (loop.limb_offset) {
2126922270 .unused => unreachable,
2127022271 .known => |limb_offset| .{ .reg = registerAlias(
2127122272 src_regs[@divExact(limb_offset, loop.limb_size.?)],
......@@ -21274,12 +22275,12 @@ fn select(cg: *CodeGen, dst_temps: []Temp, src_temps: []const *Temp, pattern_set
2127422275 .temp => unreachable,
2127522276 },
2127622277 else => .{ .reg = registerAlias(
21277 extra_temp.*.?.tracking(cg).short.register,
22278 extra_temp.?.tracking(cg).short.register,
2127822279 loop.limb_size.?,
2127922280 ) },
2128022281 },
2128122282 .mem_limb => .{ .mem = switch (src_mcv) {
21282 .register_pair => unreachable,
22283 .register_pair, .register_triple, .register_quadruple => unreachable,
2128322284 else => switch (loop.limb_offset) {
2128422285 .unused => unreachable,
2128522286 .known => |limb_offset| try src_mcv.mem(cg, .{
......@@ -21309,76 +22310,53 @@ fn select(cg: *CodeGen, dst_temps: []Temp, src_temps: []const *Temp, pattern_set
2130922310 .u(@as(u32, @intCast(src_mcv.immediate))) },
2131022311 },
2131122312 };
22313 switch (src_op) {
22314 else => {},
22315 .explicit => |linked_index| mir_ops[linked_index] = mir_op.*,
22316 }
2131222317 }
2131322318 for (
22319 mir_ops[0..dst_temps.len],
2131422320 pattern.ops[0..dst_temps.len],
2131522321 dst_temps,
21316 mir_ops[0..dst_temps.len],
22322 dst_tys,
2131722323 extra_temps[0..dst_temps.len],
21318 ) |dst_op, *dst_temp, *mir_op, *extra_temp| {
22324 ) |*mir_op, dst_op, dst_temp, dst_ty, extra_temp| {
2131922325 if (mir_op.* != .none) continue;
21320 const ty = src_temps[0].typeOf(cg);
21321 switch (dst_op) {
22326 mir_op.* = switch (dst_op) {
2132222327 .implicit => unreachable,
21323 .explicit => |op_index| {
21324 dst_temp.* = dst_temps[op_index];
21325 mir_op.* = mir_ops[op_index];
21326 },
21327 .gpr => {
21328 dst_temp.* = try cg.tempAllocReg(ty, abi.RegisterClass.gp);
21329 mir_op.* = .{ .reg = registerAlias(
21330 dst_temp.tracking(cg).short.register,
21331 @intCast(ty.abiSize(cg.pt.zcu)),
21332 ) };
21333 },
21334 .mm => @panic("TODO"),
21335 .xmm => {
21336 dst_temp.* = try cg.tempAllocReg(ty, abi.RegisterClass.sse);
21337 mir_op.* = .{ .reg = dst_temp.tracking(cg).short.register.to128() };
21338 },
21339 .ymm => {
21340 dst_temp.* = try cg.tempAllocReg(ty, abi.RegisterClass.sse);
21341 mir_op.* = .{ .reg = dst_temp.tracking(cg).short.register.to256() };
21342 },
22328 .explicit => |linked_index| mir_ops[linked_index],
22329 .gpr => .{ .reg = registerAlias(
22330 dst_temp.tracking(cg).short.register,
22331 @intCast(dst_ty.abiSize(cg.pt.zcu)),
22332 ) },
22333 .mm, .mm_mask, .mm_sign_mask => @panic("TODO"),
22334 .xmm, .xmm_mask, .xmm_sign_mask => .{ .reg = dst_temp.tracking(cg).short.register.to128() },
22335 .ymm, .ymm_mask, .ymm_sign_mask => .{ .reg = dst_temp.tracking(cg).short.register.to256() },
2134322336 .mem => @panic("TODO"),
21344 .gpr_limb => {
21345 dst_temp.* = try cg.tempAlloc(ty);
21346 extra_temp.* = try cg.tempAllocReg(Type.usize, abi.RegisterClass.gp);
21347 mir_op.* = .{ .reg = extra_temp.*.?.tracking(cg).short.register.to64() };
21348 },
21349 .mm_limb => {
21350 dst_temp.* = try cg.tempAlloc(ty);
21351 extra_temp.* = try cg.tempAllocReg(Type.usize, @panic("TODO"));
21352 mir_op.* = .{ .reg = extra_temp.*.?.tracking(cg).short.register };
21353 },
21354 .xmm_limb => {
21355 dst_temp.* = try cg.tempAlloc(ty);
21356 extra_temp.* = try cg.tempAllocReg(Type.usize, abi.RegisterClass.sse);
21357 mir_op.* = .{ .reg = extra_temp.*.?.tracking(cg).short.register.to128() };
21358 },
21359 .ymm_limb => {
21360 dst_temp.* = try cg.tempAlloc(ty);
21361 extra_temp.* = try cg.tempAllocReg(Type.usize, abi.RegisterClass.sse);
21362 mir_op.* = .{ .reg = extra_temp.*.?.tracking(cg).short.register.to256() };
21363 },
21364 .mem_limb => {
21365 dst_temp.* = try cg.tempAlloc(ty);
21366 mir_op.* = .{ .mem = try dst_temp.tracking(cg).short.mem(cg, switch (loop.limb_offset) {
21367 .unused => unreachable,
21368 .known => |limb_offset| .{
21369 .size = .fromSize(loop.limb_size.?),
21370 .disp = limb_offset,
21371 },
21372 .temp => |limb_offset| .{
21373 .size = .fromSize(loop.limb_size.?),
21374 .index = limb_offset.tracking(cg).short.register.to64(),
21375 },
21376 }) };
21377 },
21378 .imm, .simm32 => unreachable, // unmodifiable destination
21379 }
22337 .gpr_limb => .{ .reg = extra_temp.?.tracking(cg).short.register.to64() },
22338 .mm_limb => .{ .reg = extra_temp.?.tracking(cg).short.register },
22339 .xmm_limb => .{ .reg = extra_temp.?.tracking(cg).short.register.to128() },
22340 .ymm_limb => .{ .reg = extra_temp.?.tracking(cg).short.register.to256() },
22341 .mem_limb => .{ .mem = try dst_temp.tracking(cg).short.mem(cg, switch (loop.limb_offset) {
22342 .unused => unreachable,
22343 .known => |limb_offset| .{
22344 .size = .fromSize(loop.limb_size.?),
22345 .disp = limb_offset,
22346 },
22347 .temp => |limb_offset| .{
22348 .size = .fromSize(loop.limb_size.?),
22349 .index = limb_offset.tracking(cg).short.register.to64(),
22350 },
22351 }) },
22352 .mm_mask_limb => .{ .reg = extra_temp.?.tracking(cg).short.register },
22353 .xmm_mask_limb => .{ .reg = extra_temp.?.tracking(cg).short.register.to128() },
22354 .ymm_mask_limb => .{ .reg = extra_temp.?.tracking(cg).short.register.to256() },
22355 .imm, .simm32, .umax_gpr, .umax_mm, .umax_xmm, .umax_ymm => unreachable, // unmodifiable destination
22356 };
2138022357 }
2138122358 std.mem.swap(Operand, &mir_ops[pattern.commute[0]], &mir_ops[pattern.commute[1]]);
22359 if (pattern_set.clobbers.eflags) try cg.spillEflagsIfOccupied();
2138222360 cg.asmOps(pattern_set.mir_tag, mir_ops) catch |err| switch (err) {
2138322361 error.InvalidInstruction => {
2138422362 const fixes = @tagName(pattern_set.mir_tag[0]);
......@@ -21398,42 +22376,223 @@ fn select(cg: *CodeGen, dst_temps: []Temp, src_temps: []const *Temp, pattern_set
2139822376 },
2139922377 else => |e| return e,
2140022378 };
22379 const invert_result = opts.invert_result != pattern_set.invert_result;
2140122380 for (
2140222381 extra_temps[0..dst_temps.len],
2140322382 pattern.ops[0..dst_temps.len],
22383 mir_ops[0..dst_temps.len],
2140422384 dst_temps,
21405 ) |maybe_extra_temp, dst_op, dst_temp| if (maybe_extra_temp) |extra_temp| switch (dst_op) {
21406 else => {},
21407 .gpr_limb, .mm_limb, .xmm_limb, .ymm_limb => switch (dst_temp.tracking(cg).short) {
21408 .register_pair => |dst_regs| switch (loop.limb_offset) {
21409 .unused => unreachable,
21410 .known => |limb_offset| try cg.asmRegisterRegister(
21411 .{ ._, .mov },
21412 dst_regs[@divExact(limb_offset, loop.limb_size.?)].to64(),
21413 extra_temp.tracking(cg).short.register.to64(),
22385 ) |extra_temp, dst_op, mir_op, dst_temp| switch (dst_op) {
22386 else => if (invert_result) {
22387 try cg.spillEflagsIfOccupied();
22388 cg.asmOps(
22389 .{ ._, .not },
22390 .{ mir_op, .none, .none, .none },
22391 ) catch |err| switch (err) {
22392 error.InvalidInstruction => return cg.fail(
22393 "invalid instruction: 'not {s} none none none'",
22394 .{@tagName(mir_op)},
2141422395 ),
21415 .temp => unreachable,
21416 },
21417 else => |dst_mcv| try cg.asmMemoryRegister(
21418 switch (dst_op) {
21419 else => unreachable,
21420 .gpr_limb => .{ ._, .mov },
21421 .mm_limb => .{ ._q, .mov },
21422 .xmm_limb, .ymm_limb => .{ if (cg.hasFeature(.avx)) .v_ else ._, .movdqu },
22396 else => |e| return e,
22397 };
22398 },
22399 .mm_mask,
22400 .xmm_mask,
22401 .ymm_mask,
22402 .mm_sign_mask,
22403 .xmm_sign_mask,
22404 .ymm_sign_mask,
22405 => dst_temp.asMask(switch (dst_op) {
22406 else => unreachable,
22407 .mm_mask, .xmm_mask, .ymm_mask => .all,
22408 .mm_sign_mask, .xmm_sign_mask, .ymm_sign_mask => .sign,
22409 }, invert_result, switch (pattern_set.scalar) {
22410 .any, .bool => unreachable,
22411 .float, .any_int, .signed_int, .unsigned_int, .any_float_or_int => |size| size,
22412 }, cg),
22413 .gpr_limb, .mm_limb, .xmm_limb, .ymm_limb => if (extra_temp) |limb_temp|
22414 switch (dst_temp.tracking(cg).short) {
22415 inline .register_pair,
22416 .register_triple,
22417 .register_quadruple,
22418 => |dst_regs| switch (loop.limb_offset) {
22419 .unused => unreachable,
22420 .known => |limb_offset| try cg.asmRegisterRegister(
22421 .{ ._, .mov },
22422 dst_regs[@divExact(limb_offset, loop.limb_size.?)].to64(),
22423 limb_temp.tracking(cg).short.register.to64(),
22424 ),
22425 .temp => unreachable,
2142322426 },
21424 try dst_mcv.mem(cg, switch (loop.limb_offset) {
22427 else => |dst_mcv| try cg.asmMemoryRegister(
22428 switch (dst_op) {
22429 else => unreachable,
22430 .gpr_limb => .{ ._, .mov },
22431 .mm_limb => .{ ._q, .mov },
22432 .xmm_limb, .ymm_limb => .{ if (cg.hasFeature(.avx)) .v_ else ._, .movdqu },
22433 },
22434 try dst_mcv.mem(cg, switch (loop.limb_offset) {
22435 .unused => unreachable,
22436 .known => |limb_offset| .{
22437 .size = .fromSize(loop.limb_size.?),
22438 .disp = limb_offset,
22439 },
22440 .temp => |limb_offset| .{
22441 .size = .fromSize(loop.limb_size.?),
22442 .index = limb_offset.tracking(cg).short.register.to64(),
22443 },
22444 }),
22445 registerAlias(limb_temp.tracking(cg).short.register, loop.limb_size.?),
22446 ),
22447 },
22448 .mm_mask_limb, .xmm_mask_limb, .ymm_mask_limb => {
22449 const scalar_size = switch (pattern_set.scalar) {
22450 .any, .bool => unreachable,
22451 .float, .any_int, .signed_int, .unsigned_int, .any_float_or_int => |size| size,
22452 };
22453 switch (scalar_size) {
22454 else => {},
22455 .word => if (cg.hasFeature(.avx)) try cg.asmRegisterRegisterRegister(
22456 .{ .vp_b, .ackssw },
22457 mir_op.reg,
22458 mir_op.reg,
22459 mir_op.reg,
22460 ) else try cg.asmRegisterRegister(
22461 .{ .p_b, .ackssw },
22462 mir_op.reg,
22463 mir_op.reg,
22464 ),
22465 }
22466 const mask_store_size: u4 =
22467 @intCast(std.math.divCeil(u7, loop.mask_store_bit_size.?, 8) catch unreachable);
22468 const mask_limb_reg = registerAlias(
22469 loop.mask_limb_temp.?.tracking(cg).short.register,
22470 mask_store_size,
22471 );
22472 try cg.asmRegisterRegister(switch (scalar_size) {
22473 else => unreachable,
22474 .byte, .word => .{ if (cg.hasFeature(.avx)) .vp_b else .p_b, .movmsk },
22475 .dword => .{ if (cg.hasFeature(.avx)) .v_ps else ._ps, .movmsk },
22476 .qword => .{ if (cg.hasFeature(.avx)) .v_pd else ._pd, .movmsk },
22477 }, mask_limb_reg.to32(), mir_op.reg);
22478 if (invert_result) if (loop.mask_store_reg) |_| {
22479 try cg.spillEflagsIfOccupied();
22480 try cg.asmRegisterImmediate(
22481 .{ ._, .xor },
22482 registerAlias(mask_limb_reg, @min(mask_store_size, 4)),
22483 .u((@as(u32, 1) << @intCast(loop.mask_limb_bit_size.?)) - 1),
22484 );
22485 } else try cg.asmRegister(.{ ._, .not }, mask_limb_reg);
22486 if (loop.mask_store_reg) |mask_store_reg| {
22487 const mask_store_alias = registerAlias(mask_store_reg, mask_store_size);
22488 switch (loop.mask_limb_offset) {
2142522489 .unused => unreachable,
21426 .known => |limb_offset| .{
21427 .size = .fromSize(loop.limb_size.?),
21428 .disp = limb_offset,
22490 .known => |mask_limb_offset| switch (mask_limb_offset & (loop.mask_store_bit_size.? - 1)) {
22491 0 => try cg.asmRegisterRegister(.{ ._, .mov }, mask_store_alias, mask_limb_reg),
22492 else => |shl_count| {
22493 try cg.spillEflagsIfOccupied();
22494 try cg.asmRegisterImmediate(.{ ._l, .sh }, mask_limb_reg, .u(shl_count));
22495 try cg.spillEflagsIfOccupied();
22496 try cg.asmRegisterRegister(.{ ._, .@"or" }, mask_store_alias, mask_limb_reg);
22497 },
2142922498 },
21430 .temp => |limb_offset| .{
21431 .size = .fromSize(loop.limb_size.?),
21432 .index = limb_offset.tracking(cg).short.register.to64(),
22499 .temp => |mask_limb_offset| {
22500 if (cg.hasFeature(.bmi2)) {
22501 const shlx_size = @max(mask_store_size, 4);
22502 const shlx_mask_limb_reg = registerAlias(mask_limb_reg, shlx_size);
22503 try cg.asmRegisterRegisterRegister(
22504 .{ ._lx, .sh },
22505 shlx_mask_limb_reg,
22506 shlx_mask_limb_reg,
22507 registerAlias(mask_limb_offset.tracking(cg).short.register, shlx_size),
22508 );
22509 } else {
22510 try cg.spillEflagsIfOccupied();
22511 try cg.asmRegisterRegister(
22512 .{ ._l, .sh },
22513 mask_limb_reg,
22514 mask_limb_offset.tracking(cg).short.register.to8(),
22515 );
22516 }
22517 try cg.spillEflagsIfOccupied();
22518 try cg.asmRegisterRegister(.{ ._, .@"or" }, mask_store_alias, mask_limb_reg);
2143322519 },
21434 }),
21435 registerAlias(extra_temp.tracking(cg).short.register, loop.limb_size.?),
21436 ),
22520 }
22521 }
22522 const dst_mcv = dst_temp.tracking(cg).short;
22523 switch (loop.mask_limb_offset) {
22524 .unused => unreachable,
22525 .known => |*mask_limb_offset| {
22526 mask_limb_offset.* += loop.mask_limb_bit_size.?;
22527 if (mask_limb_offset.* & (loop.mask_store_bit_size.? - 1) == 0) {
22528 switch (dst_mcv) {
22529 .register => {},
22530 else => try cg.asmMemoryRegister(
22531 .{ ._, .mov },
22532 try dst_mcv.mem(cg, .{
22533 .size = .fromSize(mask_store_size),
22534 .disp = @divExact(mask_limb_offset.*, 8) - mask_store_size,
22535 }),
22536 registerAlias(loop.mask_store_reg orelse mask_limb_reg, mask_store_size),
22537 ),
22538 }
22539 if (loop.mask_store_reg) |mask_store_reg| {
22540 const mask_store_alias = registerAlias(mask_store_reg, @min(mask_store_size, 4));
22541 try cg.asmRegisterRegister(.{ ._, .xor }, mask_store_alias, mask_store_alias);
22542 }
22543 }
22544 },
22545 .temp => |mask_limb_offset| {
22546 const mask_limb_offset_reg = mask_limb_offset.tracking(cg).short.register.to32();
22547 if (loop.mask_store_reg) |mask_store_reg| {
22548 try cg.asmRegisterMemory(.{ ._, .lea }, mask_limb_offset_reg, .{
22549 .base = .{ .reg = mask_limb_offset_reg.to64() },
22550 .mod = .{ .rm = .{
22551 .size = .qword,
22552 .disp = loop.mask_limb_bit_size.?,
22553 } },
22554 });
22555 switch (dst_mcv) {
22556 .register => {},
22557 else => {
22558 try cg.spillEflagsIfOccupied();
22559 try cg.asmRegisterImmediate(
22560 .{ ._, .@"test" },
22561 mask_limb_offset_reg,
22562 .u(loop.mask_store_bit_size.? - 1),
22563 );
22564 const skip_store_reloc = try cg.asmJccReloc(.nz, undefined);
22565 const mask_store_offset_reg = mask_limb_reg.to32();
22566 try cg.asmRegisterRegister(.{ ._, .mov }, mask_store_offset_reg, mask_limb_offset_reg);
22567 try cg.asmRegisterImmediate(.{ ._r, .sh }, mask_store_offset_reg, .u(3));
22568 try cg.asmMemoryRegister(.{ ._, .mov }, try dst_mcv.mem(cg, .{
22569 .size = .fromSize(mask_store_size),
22570 .index = mask_store_offset_reg.to64(),
22571 .disp = -@as(i8, mask_store_size),
22572 }), registerAlias(mask_store_reg, mask_store_size));
22573 const mask_store_alias = registerAlias(mask_store_reg, @min(mask_store_size, 4));
22574 try cg.asmRegisterRegister(.{ ._, .xor }, mask_store_alias, mask_store_alias);
22575 cg.performReloc(skip_store_reloc);
22576 },
22577 }
22578 } else {
22579 switch (dst_mcv) {
22580 .register => {},
22581 else => try cg.asmMemoryRegister(.{ ._, .mov }, try dst_mcv.mem(cg, .{
22582 .size = .fromSize(mask_store_size),
22583 .index = mask_limb_offset_reg.to64(),
22584 }), mask_limb_reg),
22585 }
22586 try cg.asmRegisterMemory(.{ ._, .lea }, mask_limb_offset_reg, .{
22587 .base = .{ .reg = mask_limb_offset_reg.to64() },
22588 .mod = .{ .rm = .{
22589 .size = .qword,
22590 .disp = mask_store_size,
22591 } },
22592 });
22593 }
22594 },
22595 }
2143722596 },
2143822597 };
2143922598 switch (pattern_set.loop) {
......@@ -21442,7 +22601,7 @@ fn select(cg: *CodeGen, dst_temps: []Temp, src_temps: []const *Temp, pattern_set
2144222601 .limbwise_carry => @panic("TODO"),
2144322602 .limbwise_pairs_forward => @panic("TODO"),
2144422603 .limbwise_pairs_reverse => @panic("TODO"),
21445 .elementwise => @panic("TODO"),
22604 .elementwise => {},
2144622605 }
2144722606 switch (loop.limb_offset) {
2144822607 .unused => break,
......@@ -21452,6 +22611,11 @@ fn select(cg: *CodeGen, dst_temps: []Temp, src_temps: []const *Temp, pattern_set
2145222611 if (loop.remaining_size.? < loop.limb_size.? or
2145322612 (loop.element_size != null and limb_offset.* >= loop.element_size.?))
2145422613 {
22614 switch (loop.mask_limb_offset) {
22615 .unused => {},
22616 .known => |*mask_limb_offset| mask_limb_offset.* = 0,
22617 .temp => unreachable,
22618 }
2145522619 limb_offset.* = 0;
2145622620 break;
2145722621 }
......@@ -21465,6 +22629,7 @@ fn select(cg: *CodeGen, dst_temps: []Temp, src_temps: []const *Temp, pattern_set
2146522629 .disp = loop.limb_size.?,
2146622630 } },
2146722631 });
22632 try cg.spillEflagsIfOccupied();
2146822633 try cg.asmRegisterImmediate(
2146922634 .{ ._, .cmp },
2147022635 limb_offset_reg.to32(),
......@@ -21476,6 +22641,12 @@ fn select(cg: *CodeGen, dst_temps: []Temp, src_temps: []const *Temp, pattern_set
2147622641 },
2147722642 }
2147822643 }
22644 if (loop.mask_limb_temp) |mask_limb_temp| try mask_limb_temp.die(cg);
22645 if (loop.mask_store_temp) |mask_store_temp| try mask_store_temp.die(cg);
22646 switch (loop.mask_limb_offset) {
22647 .unused, .known => {},
22648 .temp => |mask_limb_offset| try mask_limb_offset.die(cg),
22649 }
2147922650 switch (loop.element_offset) {
2148022651 .unused => break :pattern_sets,
2148122652 .known => |*element_offset| {
src/arch/x86_64/Disassembler.zig+1-1
......@@ -223,7 +223,7 @@ pub fn next(dis: *Disassembler) Error!?Instruction {
223223 .op3 = op3,
224224 });
225225 },
226 .rm0, .vmi, .rvm, .rvmr, .rvmi, .mvr => unreachable, // TODO
226 .rm0, .vmi, .rvm, .rvmr, .rvmi, .mvr, .rmv => unreachable, // TODO
227227 }
228228}
229229
src/arch/x86_64/Encoding.zig+7-6
......@@ -177,7 +177,7 @@ pub fn format(
177177 try writer.print("+{s} ", .{tag});
178178 },
179179 .m, .mi, .m1, .mc, .vmi => try writer.print("/{d} ", .{encoding.modRmExt()}),
180 .mr, .rm, .rmi, .mri, .mrc, .rm0, .rvm, .rvmr, .rvmi, .mvr => try writer.writeAll("/r "),
180 .mr, .rm, .rmi, .mri, .mrc, .rm0, .rvm, .rvmr, .rvmi, .mvr, .rmv => try writer.writeAll("/r "),
181181 }
182182
183183 switch (encoding.data.op_en) {
......@@ -202,7 +202,7 @@ pub fn format(
202202 try writer.print("{s} ", .{tag});
203203 },
204204 .rvmr => try writer.writeAll("/is4 "),
205 .zo, .fd, .td, .o, .m, .m1, .mc, .mr, .rm, .mrc, .rm0, .rvm, .mvr => {},
205 .zo, .fd, .td, .o, .m, .m1, .mc, .mr, .rm, .mrc, .rm0, .rvm, .mvr, .rmv => {},
206206 }
207207
208208 try writer.print("{s} ", .{@tagName(encoding.mnemonic)});
......@@ -260,10 +260,10 @@ pub const Mnemonic = enum {
260260 neg, nop, not,
261261 @"or",
262262 pause, pop, popcnt, popfq, push, pushfq,
263 rcl, rcr, ret, rol, ror,
264 sal, sar, sbb,
263 rcl, rcr, ret, rol, ror, rorx,
264 sal, sar, sarx, sbb,
265265 scas, scasb, scasd, scasq, scasw,
266 shl, shld, shr, shrd, sub, syscall,
266 shl, shld, shlx, shr, shrd, shrx, sub, syscall,
267267 seta, setae, setb, setbe, setc, sete, setg, setge, setl, setle, setna, setnae,
268268 setnb, setnbe, setnc, setne, setng, setnge, setnl, setnle, setno, setnp, setns,
269269 setnz, seto, setp, setpe, setpo, sets, setz,
......@@ -444,7 +444,7 @@ pub const OpEn = enum {
444444 fd, td,
445445 m1, mc, mi, mr, rm,
446446 rmi, mri, mrc,
447 rm0, vmi, rvm, rvmr, rvmi, mvr,
447 rm0, vmi, rvm, rvmr, rvmi, mvr, rmv,
448448 // zig fmt: on
449449};
450450
......@@ -808,6 +808,7 @@ pub const Feature = enum {
808808 avx,
809809 avx2,
810810 bmi,
811 bmi2,
811812 f16c,
812813 fma,
813814 lzcnt,
src/arch/x86_64/Mir.zig+8
......@@ -29,10 +29,14 @@ pub const Inst = struct {
2929 _l,
3030 /// ___ Left Double
3131 _ld,
32 /// ___ Left Without Affecting Flags
33 _lx,
3234 /// ___ Right
3335 _r,
3436 /// ___ Right Double
3537 _rd,
38 /// ___ Right Without Affecting Flags
39 _rx,
3640
3741 /// ___ Above
3842 _a,
......@@ -401,9 +405,11 @@ pub const Inst = struct {
401405 ret,
402406 /// Rotate left
403407 /// Rotate right
408 /// Rotate right logical without affecting flags
404409 ro,
405410 /// Arithmetic shift left
406411 /// Arithmetic shift right
412 /// Shift left arithmetic without affecting flags
407413 sa,
408414 /// Integer subtraction with borrow
409415 sbb,
......@@ -417,6 +423,8 @@ pub const Inst = struct {
417423 /// Double precision shift left
418424 /// Logical shift right
419425 /// Double precision shift right
426 /// Shift left logical without affecting flags
427 /// Shift right logical without affecting flags
420428 sh,
421429 /// Subtract
422430 /// Subtract packed integers
src/arch/x86_64/abi.zig+8-4
......@@ -242,8 +242,12 @@ pub fn classifySystemV(ty: Type, zcu: *Zcu, target: std.Target, ctx: Context) [8
242242 .sse, .sseup, .sseup, .sseup,
243243 .sseup, .sseup, .sseup, .none,
244244 };
245 // LLVM always returns vectors byval
246 if (bits <= 512 or ctx == .ret) return .{
245 if (bits <= 512 or (ctx == .ret and bits <= @as(u64, if (std.Target.x86.featureSetHas(target.cpu.features, .avx512f))
246 2048
247 else if (std.Target.x86.featureSetHas(target.cpu.features, .avx))
248 1024
249 else
250 512))) return .{
247251 .sse, .sseup, .sseup, .sseup,
248252 .sseup, .sseup, .sseup, .sseup,
249253 };
......@@ -416,7 +420,7 @@ pub const SysV = struct {
416420 pub const c_abi_int_param_regs = [_]Register{ .rdi, .rsi, .rdx, .rcx, .r8, .r9 };
417421 pub const c_abi_sse_param_regs = sse_avx_regs[0..8].*;
418422 pub const c_abi_int_return_regs = [_]Register{ .rax, .rdx };
419 pub const c_abi_sse_return_regs = sse_avx_regs[0..2].*;
423 pub const c_abi_sse_return_regs = sse_avx_regs[0..4].*;
420424};
421425
422426pub const Win64 = struct {
......@@ -496,7 +500,7 @@ pub fn getCAbiSseReturnRegs(cc: std.builtin.CallingConvention) []const Register
496500}
497501
498502const gp_regs = [_]Register{
499 .rax, .rcx, .rdx, .rbx, .rsi, .rdi, .r8, .r9, .r10, .r11, .r12, .r13, .r14, .r15,
503 .rax, .rdx, .rbx, .rcx, .rsi, .rdi, .r8, .r9, .r10, .r11, .r12, .r13, .r14, .r15,
500504};
501505const x87_regs = [_]Register{
502506 .st0, .st1, .st2, .st3, .st4, .st5, .st6, .st7,
src/arch/x86_64/encoder.zig+10-9
......@@ -403,7 +403,7 @@ pub const Instruction = struct {
403403 else => {
404404 const mem_op = switch (data.op_en) {
405405 .m, .mi, .m1, .mc, .mr, .mri, .mrc, .mvr => inst.ops[0],
406 .rm, .rmi, .rm0, .vmi => inst.ops[1],
406 .rm, .rmi, .rm0, .vmi, .rmv => inst.ops[1],
407407 .rvm, .rvmr, .rvmi => inst.ops[2],
408408 else => unreachable,
409409 };
......@@ -412,7 +412,7 @@ pub const Instruction = struct {
412412 const rm = switch (data.op_en) {
413413 .m, .mi, .m1, .mc, .vmi => enc.modRmExt(),
414414 .mr, .mri, .mrc => inst.ops[1].reg.lowEnc(),
415 .rm, .rmi, .rm0, .rvm, .rvmr, .rvmi => inst.ops[0].reg.lowEnc(),
415 .rm, .rmi, .rm0, .rvm, .rvmr, .rvmi, .rmv => inst.ops[0].reg.lowEnc(),
416416 .mvr => inst.ops[2].reg.lowEnc(),
417417 else => unreachable,
418418 };
......@@ -422,7 +422,7 @@ pub const Instruction = struct {
422422 const op = switch (data.op_en) {
423423 .m, .mi, .m1, .mc, .vmi => .none,
424424 .mr, .mri, .mrc => inst.ops[1],
425 .rm, .rmi, .rm0, .rvm, .rvmr, .rvmi => inst.ops[0],
425 .rm, .rmi, .rm0, .rvm, .rvmr, .rvmi, .rmv => inst.ops[0],
426426 .mvr => inst.ops[2],
427427 else => unreachable,
428428 };
......@@ -493,7 +493,7 @@ pub const Instruction = struct {
493493 }
494494 else
495495 null,
496 .vmi, .rvm, .rvmr, .rvmi, .mvr => unreachable,
496 .vmi, .rvm, .rvmr, .rvmi, .mvr, .rmv => unreachable,
497497 };
498498 if (segment_override) |seg| {
499499 legacy.setSegmentOverride(seg);
......@@ -512,9 +512,9 @@ pub const Instruction = struct {
512512 switch (op_en) {
513513 .zo, .i, .zi, .fd, .td, .d => {},
514514 .o, .oi => rex.b = inst.ops[0].reg.isExtended(),
515 .m, .mi, .m1, .mc, .mr, .rm, .rmi, .mri, .mrc, .rm0 => {
515 .m, .mi, .m1, .mc, .mr, .rm, .rmi, .mri, .mrc, .rm0, .rmv => {
516516 const r_op = switch (op_en) {
517 .rm, .rmi, .rm0 => inst.ops[0],
517 .rm, .rmi, .rm0, .rmv => inst.ops[0],
518518 .mr, .mri, .mrc => inst.ops[1],
519519 else => .none,
520520 };
......@@ -546,9 +546,9 @@ pub const Instruction = struct {
546546 switch (op_en) {
547547 .zo, .i, .zi, .fd, .td, .d => {},
548548 .o, .oi => vex.b = inst.ops[0].reg.isExtended(),
549 .m, .mi, .m1, .mc, .mr, .rm, .rmi, .mri, .mrc, .rm0, .vmi, .rvm, .rvmr, .rvmi, .mvr => {
549 .m, .mi, .m1, .mc, .mr, .rm, .rmi, .mri, .mrc, .rm0, .vmi, .rvm, .rvmr, .rvmi, .mvr, .rmv => {
550550 const r_op = switch (op_en) {
551 .rm, .rmi, .rm0, .rvm, .rvmr, .rvmi => inst.ops[0],
551 .rm, .rmi, .rm0, .rvm, .rvmr, .rvmi, .rmv => inst.ops[0],
552552 .mr, .mri, .mrc => inst.ops[1],
553553 .mvr => inst.ops[2],
554554 .m, .mi, .m1, .mc, .vmi => .none,
......@@ -557,7 +557,7 @@ pub const Instruction = struct {
557557 vex.r = r_op.isBaseExtended();
558558
559559 const b_x_op = switch (op_en) {
560 .rm, .rmi, .rm0, .vmi => inst.ops[1],
560 .rm, .rmi, .rm0, .vmi, .rmv => inst.ops[1],
561561 .m, .mi, .m1, .mc, .mr, .mri, .mrc, .mvr => inst.ops[0],
562562 .rvm, .rvmr, .rvmi => inst.ops[2],
563563 else => unreachable,
......@@ -588,6 +588,7 @@ pub const Instruction = struct {
588588 else => {},
589589 .vmi => vex.v = inst.ops[0].reg,
590590 .rvm, .rvmr, .rvmi => vex.v = inst.ops[1].reg,
591 .rmv => vex.v = inst.ops[2].reg,
591592 }
592593
593594 try encoder.vex(vex);
src/arch/x86_64/encodings.zig+10
......@@ -1287,6 +1287,16 @@ pub const table = [_]Entry{
12871287 .{ .sha256rnds2, .rm0, &.{ .xmm, .xmm_m128, .xmm0 }, &.{ 0x0f, 0x38, 0xcb }, 0, .none, .sha },
12881288
12891289 // AVX
1290 .{ .rorx, .rmi, &.{ .r32, .rm32, .imm8 }, &.{ 0xf2, 0x0f, 0x3a }, 0, .vex_lz_w0, .bmi2 },
1291 .{ .rorx, .rmi, &.{ .r64, .rm64, .imm8 }, &.{ 0xf2, 0x0f, 0x3a }, 0, .vex_lz_w1, .bmi2 },
1292
1293 .{ .sarx, .rmv, &.{ .r32, .rm32, .r32 }, &.{ 0xf3, 0x0f, 0x38, 0xf7 }, 0, .vex_lz_w0, .bmi2 },
1294 .{ .shlx, .rmv, &.{ .r32, .rm32, .r32 }, &.{ 0x66, 0x0f, 0x38, 0xf7 }, 0, .vex_lz_w0, .bmi2 },
1295 .{ .shrx, .rmv, &.{ .r32, .rm32, .r32 }, &.{ 0xf2, 0x0f, 0x38, 0xf7 }, 0, .vex_lz_w0, .bmi2 },
1296 .{ .sarx, .rmv, &.{ .r64, .rm64, .r64 }, &.{ 0xf3, 0x0f, 0x38, 0xf7 }, 0, .vex_lz_w1, .bmi2 },
1297 .{ .shlx, .rmv, &.{ .r64, .rm64, .r64 }, &.{ 0x66, 0x0f, 0x38, 0xf7 }, 0, .vex_lz_w1, .bmi2 },
1298 .{ .shrx, .rmv, &.{ .r64, .rm64, .r64 }, &.{ 0xf2, 0x0f, 0x38, 0xf7 }, 0, .vex_lz_w1, .bmi2 },
1299
12901300 .{ .vaddpd, .rvm, &.{ .xmm, .xmm, .xmm_m128 }, &.{ 0x66, 0x0f, 0x58 }, 0, .vex_128_wig, .avx },
12911301 .{ .vaddpd, .rvm, &.{ .ymm, .ymm, .ymm_m256 }, &.{ 0x66, 0x0f, 0x58 }, 0, .vex_256_wig, .avx },
12921302
src/register_manager.zig+13-1
......@@ -112,6 +112,9 @@ pub fn RegisterManager(
112112 pub fn indexOfRegIntoTracked(reg: Register) ?TrackedIndex {
113113 return indexOfReg(tracked_registers, reg);
114114 }
115 pub inline fn indexOfKnownRegIntoTracked(comptime reg: Register) ?TrackedIndex {
116 return comptime indexOfRegIntoTracked(reg);
117 }
115118
116119 pub fn regAtTrackedIndex(tracked_index: TrackedIndex) Register {
117120 return tracked_registers[tracked_index];
......@@ -124,6 +127,9 @@ pub fn RegisterManager(
124127 pub fn isRegFree(self: Self, reg: Register) bool {
125128 return self.isRegIndexFree(indexOfRegIntoTracked(reg) orelse return true);
126129 }
130 pub fn isKnownRegFree(self: Self, comptime reg: Register) bool {
131 return self.isRegIndexFree(indexOfKnownRegIntoTracked(reg) orelse return true);
132 }
127133
128134 /// Returns whether this register was allocated in the course
129135 /// of this function.
......@@ -143,6 +149,9 @@ pub fn RegisterManager(
143149 pub fn isRegLocked(self: Self, reg: Register) bool {
144150 return self.isRegIndexLocked(indexOfRegIntoTracked(reg) orelse return false);
145151 }
152 pub fn isKnownRegLocked(self: Self, comptime reg: Register) bool {
153 return self.isRegIndexLocked(indexOfKnownRegIntoTracked(reg) orelse return false);
154 }
146155
147156 pub const RegisterLock = struct { tracked_index: TrackedIndex };
148157
......@@ -176,6 +185,9 @@ pub fn RegisterManager(
176185 pub fn lockRegAssumeUnused(self: *Self, reg: Register) RegisterLock {
177186 return self.lockRegIndexAssumeUnused(indexOfRegIntoTracked(reg) orelse unreachable);
178187 }
188 pub fn lockKnownRegAssumeUnused(self: *Self, comptime reg: Register) RegisterLock {
189 return self.lockRegIndexAssumeUnused(indexOfKnownRegIntoTracked(reg) orelse unreachable);
190 }
179191
180192 /// Like `lockReg` but locks multiple registers.
181193 pub fn lockRegs(
......@@ -366,7 +378,7 @@ pub fn RegisterManager(
366378 comptime reg: Register,
367379 inst: ?Air.Inst.Index,
368380 ) AllocationError!void {
369 return self.getRegIndex((comptime indexOfRegIntoTracked(reg)) orelse return, inst);
381 return self.getRegIndex(indexOfKnownRegIntoTracked(reg) orelse return, inst);
370382 }
371383
372384 /// Allocates the specified register with the specified
test/behavior.zig+2
......@@ -110,6 +110,8 @@ test {
110110 _ = @import("behavior/widening.zig");
111111 _ = @import("behavior/abs.zig");
112112
113 _ = @import("behavior/x86_64.zig");
114
113115 if (builtin.cpu.arch == .wasm32) {
114116 _ = @import("behavior/wasm.zig");
115117 }
test/behavior/x86_64.zig created+9
......@@ -0,0 +1,9 @@
1//! CodeGen tests for the x86_64 backend.
2
3const builtin = @import("builtin");
4
5test {
6 if (builtin.zig_backend != .stage2_x86_64) return error.SkipZigTest;
7 if (builtin.object_format == .coff) return error.SkipZigTest;
8 _ = @import("x86_64/math.zig");
9}
test/behavior/x86_64/math.zig created+230
......@@ -0,0 +1,230 @@
1fn testBinary(comptime op: anytype) !void {
2 const testType = struct {
3 fn testType(comptime Type: type, comptime imm_lhs: Type, comptime imm_rhs: Type) !void {
4 const expected = op(Type, imm_lhs, imm_rhs);
5 try struct {
6 fn testOne(actual: @TypeOf(expected)) !void {
7 if (switch (@typeInfo(@TypeOf(expected))) {
8 else => actual != expected,
9 .vector => @reduce(.Or, actual != expected),
10 }) return error.Unexpected;
11 }
12 noinline fn testOps(mem_lhs: Type, mem_rhs: Type) !void {
13 var reg_lhs = mem_lhs;
14 var reg_rhs = mem_rhs;
15 _ = .{ &reg_lhs, &reg_rhs };
16 try testOne(op(Type, reg_lhs, reg_rhs));
17 try testOne(op(Type, reg_lhs, mem_rhs));
18 try testOne(op(Type, reg_lhs, imm_rhs));
19 try testOne(op(Type, mem_lhs, reg_rhs));
20 try testOne(op(Type, mem_lhs, mem_rhs));
21 try testOne(op(Type, mem_lhs, imm_rhs));
22 try testOne(op(Type, imm_lhs, reg_rhs));
23 try testOne(op(Type, imm_lhs, mem_rhs));
24 }
25 }.testOps(imm_lhs, imm_rhs);
26 }
27 }.testType;
28
29 try testType(u8, 0xbb, 0x43);
30 try testType(u16, 0xb8bf, 0x626d);
31 try testType(u32, 0x80d7a2c6, 0xbff6a402);
32 try testType(u64, 0x71138bc6b4a38898, 0x1bc4043de9438c7b);
33 try testType(u128, 0xe05fc132ef2cd8affee00a907f0a851f, 0x29f912a72cfc6a7c6973426a9636da9a);
34
35 try testType(@Vector(16, u8), .{
36 0xea, 0x80, 0xbb, 0xe8, 0x74, 0x81, 0xc8, 0x66, 0x7b, 0x41, 0x90, 0xcb, 0x30, 0x70, 0x4b, 0x0f,
37 }, .{
38 0x61, 0x26, 0xbe, 0x47, 0x00, 0x9c, 0x55, 0xa5, 0x59, 0xf0, 0xb2, 0x20, 0x30, 0xaf, 0x82, 0x3e,
39 });
40 try testType(@Vector(32, u8), .{
41 0xa1, 0x88, 0xc4, 0xf4, 0x77, 0x0b, 0xf5, 0xbb, 0x09, 0x03, 0xbf, 0xf5, 0xcc, 0x7f, 0x6b, 0x2a,
42 0x4c, 0x05, 0x37, 0xc9, 0x8a, 0xcb, 0x91, 0x23, 0x09, 0x5f, 0xb8, 0x99, 0x4a, 0x75, 0x26, 0xe4,
43 }, .{
44 0xff, 0x0f, 0x99, 0x49, 0xa6, 0x25, 0xa7, 0xd4, 0xc9, 0x2f, 0x97, 0x6a, 0x01, 0xd6, 0x6e, 0x41,
45 0xa4, 0xb5, 0x3c, 0x03, 0xea, 0x82, 0x9c, 0x5f, 0xac, 0x07, 0x16, 0x15, 0x1c, 0x64, 0x25, 0x2f,
46 });
47 try testType(@Vector(64, u8), .{
48 0xaa, 0x08, 0xeb, 0xb2, 0xd7, 0x89, 0x0f, 0x98, 0xda, 0x9f, 0xa6, 0x4e, 0x3c, 0xce, 0x1b, 0x1b,
49 0x9e, 0x5f, 0x2b, 0xd6, 0x59, 0x26, 0x47, 0x05, 0x2a, 0xb7, 0xd1, 0x10, 0xde, 0xd9, 0x84, 0x00,
50 0x07, 0xc0, 0xaa, 0x6e, 0xfa, 0x3b, 0x97, 0x85, 0xa8, 0x42, 0xd7, 0xa5, 0x90, 0xe6, 0x10, 0x1a,
51 0x47, 0x84, 0xe1, 0x3e, 0xb0, 0x70, 0x26, 0x3f, 0xea, 0x24, 0xb8, 0x5f, 0xe3, 0xe3, 0x4c, 0xed,
52 }, .{
53 0x3b, 0xc5, 0xe0, 0x3d, 0x4f, 0x2e, 0x1d, 0xa9, 0xf7, 0x7b, 0xc7, 0xc1, 0x48, 0xc6, 0xe5, 0x9e,
54 0x4d, 0xa8, 0x21, 0x37, 0xa1, 0x1a, 0x95, 0x69, 0x89, 0x2f, 0x15, 0x07, 0x3d, 0x7b, 0x69, 0x89,
55 0xea, 0x87, 0xf0, 0x94, 0x67, 0xf2, 0x3d, 0x04, 0x96, 0x8a, 0xd6, 0x70, 0x7c, 0x16, 0xe7, 0x62,
56 0xf0, 0x8d, 0x96, 0x65, 0xd1, 0x4a, 0x35, 0x3e, 0x7a, 0x67, 0xa6, 0x1f, 0x37, 0x66, 0xe3, 0x45,
57 });
58 try testType(@Vector(128, u8), .{
59 0xa1, 0xd0, 0x7b, 0xf9, 0x7b, 0x77, 0x7b, 0x3d, 0x2d, 0x68, 0xc2, 0x7b, 0xb0, 0xb8, 0xd4, 0x7c,
60 0x1a, 0x1f, 0xd2, 0x92, 0x3e, 0xcb, 0xc1, 0x6b, 0xb9, 0x4d, 0xf1, 0x67, 0x58, 0x8e, 0x77, 0xa6,
61 0xb9, 0xdf, 0x10, 0x6f, 0xbe, 0xe3, 0x33, 0xb6, 0x93, 0x77, 0x80, 0xef, 0x09, 0x9d, 0x61, 0x40,
62 0xa2, 0xf4, 0x52, 0x18, 0x9d, 0xe4, 0xb0, 0xaf, 0x0a, 0xa7, 0x0b, 0x09, 0x67, 0x38, 0x71, 0x04,
63 0x72, 0xa1, 0xd2, 0xfd, 0xf8, 0xf0, 0xa7, 0x23, 0x24, 0x5b, 0x7d, 0xfb, 0x43, 0xba, 0x6c, 0xc4,
64 0x83, 0x46, 0x0e, 0x4d, 0x6c, 0x92, 0xab, 0x4f, 0xd2, 0x70, 0x9d, 0xfe, 0xce, 0xf8, 0x05, 0x9f,
65 0x98, 0x36, 0x9c, 0x90, 0x9a, 0xd0, 0xb5, 0x76, 0x16, 0xe8, 0x25, 0xc2, 0xbd, 0x91, 0xab, 0xf9,
66 0x6f, 0x6c, 0xc5, 0x60, 0xe5, 0x30, 0xf2, 0xb7, 0x59, 0xc4, 0x9c, 0xdd, 0xdf, 0x04, 0x65, 0xd9,
67 }, .{
68 0xed, 0xe1, 0x8a, 0xf6, 0xf3, 0x8b, 0xfd, 0x1d, 0x3c, 0x87, 0xbf, 0xfe, 0x04, 0x52, 0x15, 0x82,
69 0x0b, 0xb0, 0xcf, 0xcf, 0xf8, 0x03, 0x9c, 0xef, 0xc1, 0x76, 0x7e, 0xe3, 0xe9, 0xa8, 0x18, 0x90,
70 0xd4, 0xc4, 0x91, 0x15, 0x68, 0x7f, 0x65, 0xd8, 0xe1, 0xb3, 0x23, 0xc2, 0x7d, 0x84, 0x3b, 0xaf,
71 0x74, 0x69, 0x07, 0x2a, 0x1b, 0x5f, 0x0e, 0x44, 0x0d, 0x2b, 0x9c, 0x82, 0x41, 0xf9, 0x7f, 0xb5,
72 0xc4, 0xd9, 0xcb, 0xd3, 0xc5, 0x31, 0x8b, 0x5f, 0xda, 0x09, 0x9b, 0x29, 0xa3, 0xb7, 0x13, 0x0d,
73 0x55, 0x9b, 0x59, 0x33, 0x2a, 0x59, 0x3a, 0x44, 0x1f, 0xd3, 0x40, 0x4e, 0xde, 0x2c, 0xe4, 0x16,
74 0xfd, 0xc3, 0x02, 0x74, 0xaa, 0x65, 0xfd, 0xc8, 0x2a, 0x8a, 0xdb, 0xae, 0x44, 0x28, 0x62, 0xa4,
75 0x56, 0x4f, 0xf1, 0xaa, 0x0a, 0x0f, 0xdb, 0x1b, 0xc8, 0x45, 0x9b, 0x12, 0xb4, 0x1a, 0xe4, 0xa3,
76 });
77
78 try testType(@Vector(8, u16), .{
79 0xcf61, 0xb121, 0x3cf1, 0x3e9f, 0x43a7, 0x8d69, 0x96f5, 0xc11e,
80 }, .{
81 0xee30, 0x82f0, 0x270b, 0x1498, 0x4c60, 0x6e72, 0x0b64, 0x02d4,
82 });
83 try testType(@Vector(16, u16), .{
84 0x9191, 0xd23e, 0xf844, 0xd84a, 0xe907, 0xf1e8, 0x712d, 0x90af,
85 0x6541, 0x3fa6, 0x92eb, 0xe35a, 0xc0c9, 0xcb47, 0xb790, 0x4453,
86 }, .{
87 0x21c3, 0x4039, 0x9b71, 0x60bd, 0xcd7f, 0x2ec8, 0x50ba, 0xe810,
88 0xebd4, 0x06e5, 0xed18, 0x2f66, 0x7e31, 0xe282, 0xad63, 0xb25e,
89 });
90 try testType(@Vector(32, u16), .{
91 0x6b6a, 0x30a9, 0xc267, 0x2231, 0xbf4c, 0x00bc, 0x9c2c, 0x2928,
92 0xecad, 0x82df, 0xcfb0, 0xa4e5, 0x909b, 0x1b05, 0xaf40, 0x1fd9,
93 0xcec6, 0xd8dc, 0xd4b5, 0x6d59, 0x8e3f, 0x4d8a, 0xb83a, 0x808e,
94 0x47e2, 0x5782, 0x59bf, 0xcefc, 0x5179, 0x3f48, 0x93dc, 0x66d2,
95 }, .{
96 0x1be8, 0xe98c, 0xf9b3, 0xb008, 0x2f8d, 0xf087, 0xc9b9, 0x75aa,
97 0xbd16, 0x9540, 0xc5bd, 0x2b2c, 0xd43f, 0x9394, 0x3e1d, 0xf695,
98 0x167d, 0xff7a, 0xf09d, 0xdff8, 0xdfa2, 0xc779, 0x70b7, 0x01bd,
99 0x46b3, 0x995a, 0xb7bc, 0xa79d, 0x5542, 0x961e, 0x37cd, 0x9c2a,
100 });
101 try testType(@Vector(64, u16), .{
102 0x6b87, 0xfd84, 0x436b, 0xe345, 0xfb82, 0x81fc, 0x0992, 0x45f9,
103 0x5527, 0x1f6d, 0xda46, 0x6a16, 0xf6e1, 0x8fb7, 0x3619, 0xdfe3,
104 0x64ce, 0x8ac6, 0x3ae8, 0x30e3, 0xec3b, 0x4ba7, 0x02a4, 0xa694,
105 0x8e68, 0x8f0c, 0x5e30, 0x0e55, 0x6538, 0x9852, 0xea35, 0x7be2,
106 0xdabd, 0x57e6, 0x5b38, 0x0fb2, 0x2604, 0x85e7, 0x6595, 0x8de9,
107 0x49b1, 0xe9a2, 0x3758, 0xa4d9, 0x505b, 0xc9d3, 0xddc5, 0x9a43,
108 0xfd44, 0x50f5, 0x379e, 0x03b6, 0x6375, 0x692f, 0x5586, 0xc717,
109 0x94dd, 0xee06, 0xb32d, 0x0bb9, 0x0e35, 0x5f8f, 0x0ba4, 0x19a8,
110 }, .{
111 0xbeeb, 0x3e54, 0x6486, 0x5167, 0xe432, 0x57cf, 0x9cac, 0x922e,
112 0xd2f8, 0x5614, 0x2e7f, 0x19cf, 0x9a07, 0x0524, 0x168f, 0x4464,
113 0x4def, 0x83ce, 0x97b4, 0xf269, 0xda5f, 0x28c1, 0x9cc3, 0xfa7c,
114 0x25a0, 0x912d, 0x25b2, 0xd60d, 0xcd82, 0x0e03, 0x40cc, 0xc9dc,
115 0x18eb, 0xc609, 0xb06d, 0x29e0, 0xf3c7, 0x997b, 0x8ca2, 0xa750,
116 0xc9bc, 0x8f0e, 0x3916, 0xd905, 0x94f8, 0x397f, 0x98b5, 0xc61d,
117 0x05db, 0x3e7a, 0xf750, 0xe8de, 0x3225, 0x81d9, 0x612e, 0x0a7e,
118 0x2c02, 0xff5b, 0x19ca, 0xbbf5, 0x870e, 0xc9ca, 0x47bb, 0xcfcc,
119 });
120
121 try testType(@Vector(4, u32), .{
122 0x234d576e, 0x4151cc9c, 0x39f558e4, 0xba935a32,
123 }, .{
124 0x398f2a9d, 0x4540f093, 0x9225551c, 0x3bac865b,
125 });
126 try testType(@Vector(8, u32), .{
127 0xb8336635, 0x2fc3182c, 0x27a00123, 0x71587fbe,
128 0x9cbc65d2, 0x6f4bb0e6, 0x362594ce, 0x9971df38,
129 }, .{
130 0x5727e734, 0x972b0313, 0xff25f5dc, 0x924f8e55,
131 0x04920a61, 0xa1c3b334, 0xf52df4b6, 0x5ef72ecc,
132 });
133 try testType(@Vector(16, u32), .{
134 0xfb566f9e, 0x9ad4691a, 0x5b5f9ec0, 0x5a572d2a,
135 0x8f2f226b, 0x2dfc7e33, 0x9fb07e32, 0x9d672a2e,
136 0xbedc3cee, 0x6872428d, 0xbc73a9fd, 0xd4d5f055,
137 0x69c1e9ee, 0x65038deb, 0x1449061a, 0x48412ec2,
138 }, .{
139 0x96cbe946, 0x3f24f60b, 0xaeacdc53, 0x7611a8b4,
140 0x031a67a8, 0x52a26828, 0x75646f4b, 0xb75902c3,
141 0x1f881f08, 0x834e02a4, 0x5e5b40eb, 0xc75c264d,
142 0xa8251e09, 0x28e46bbd, 0x12cb1f31, 0x9a2af615,
143 });
144 try testType(@Vector(32, u32), .{
145 0x131bbb7b, 0xa7311026, 0x9d5e59a0, 0x99b090d6,
146 0xfe969e2e, 0x04547697, 0x357d3250, 0x43be6d7a,
147 0x16ecf5c5, 0xf60febcc, 0x1d1e2602, 0x138a96d2,
148 0x9117ba72, 0x9f185b32, 0xc10e23fd, 0x3e6b7fd8,
149 0x4dc9be70, 0x2ee30047, 0xaffeab60, 0x7172d362,
150 0x6154bfcf, 0x5388dc3e, 0xd6e5a76e, 0x8b782f2d,
151 0xacbef4a2, 0x843aca71, 0x25d8ab5c, 0xe1a63a39,
152 0xc26212e5, 0x0847b84b, 0xb53541e5, 0x0c8e44db,
153 }, .{
154 0x4ad92822, 0x715b623f, 0xa5bed8a7, 0x937447a9,
155 0x7ecb38eb, 0x0a2f3dfc, 0x96f467a2, 0xec882793,
156 0x41a8707f, 0xf7310656, 0x76217b80, 0x2058e5fc,
157 0x26682154, 0x87313e31, 0x4bdc480a, 0x193572ff,
158 0x60b03c75, 0x0fe45908, 0x56c73703, 0xdb86554c,
159 0xdda2dd7d, 0x34371b27, 0xe4e6ad50, 0x422d1828,
160 0x1de3801b, 0xdce268d3, 0x20af9ec8, 0x188a591f,
161 0xf080e943, 0xc8718d14, 0x3f920382, 0x18d101b5,
162 });
163
164 // TODO: implement fallback for pcmpeqq
165 if (!comptime @import("std").Target.x86.featureSetHas(@import("builtin").cpu.features, .sse4_1)) return;
166
167 try testType(@Vector(2, u64), .{
168 0x4cd89a317b03d430, 0x28998f61842f63a9,
169 }, .{
170 0x6c34db64af0e217e, 0x57aa5d02cd45dceb,
171 });
172 try testType(@Vector(4, u64), .{
173 0x946cf7e7484691c9, 0xf4fc5be2a762fcbf,
174 0x71cc83bc25abaf14, 0xc69cef44c6f833a1,
175 }, .{
176 0x9f90cbd6c3ce1d4e, 0x182f65295dff4e84,
177 0x4dfe62c59fed0040, 0x18402347c1db1999,
178 });
179 try testType(@Vector(8, u64), .{
180 0x92c6281333943e2c, 0xa97750504668efb5,
181 0x234be51057c0181f, 0xefbc1f407f3df4fb,
182 0x8da6cc7c39cebb94, 0xb408f7e56feee497,
183 0x2363f1f8821592ed, 0x01716e800c0619e1,
184 }, .{
185 0xa617426684147e7e, 0x7542da7ebe093a7b,
186 0x3f21d99ac57606b7, 0x65cd36d697d22de4,
187 0xed23d6bdf176c844, 0x2d4573f100ff7b58,
188 0x4968f4d21b49f8ab, 0xf5d9a205d453e933,
189 });
190 try testType(@Vector(16, u64), .{
191 0x2f61a4ee66177b4a, 0xf13b286b279f6a93,
192 0x36b46beb63665318, 0x74294dbde0da98d2,
193 0x3aa872ba60b936eb, 0xe8f698b36e62600b,
194 0x9e8930c21a6a1a76, 0x876998b09b8eb03c,
195 0xa0244771a2ec0adb, 0xb4c72bff3d3ac1a2,
196 0xd70677210830eced, 0x6622abc1734dd72d,
197 0x157e2bb0d57d6596, 0x2aac8192fb7ef973,
198 0xc4a0ca92f34d7b13, 0x04300f8ad1845246,
199 }, .{
200 0xeaf71dcf0eb76f5d, 0x0e84b1b63dc97139,
201 0x0f64cc38d23c94a1, 0x12775cf0816349b7,
202 0xfdcf13387ba48d54, 0xf8d3c672cacd8779,
203 0xe728c1f5eb56ab1e, 0x05931a34877f7a69,
204 0x1861a763c8dafd1f, 0x4ac97573ecd5739f,
205 0x3384414c9bf77b8c, 0x32c15bbd04a5ddc4,
206 0xbfd88aee1d82ed32, 0x20e91c15b701059a,
207 0xed533d18f8657f3f, 0x1ddd7cd7f6bab957,
208 });
209}
210
211inline fn bitAnd(comptime Type: type, lhs: Type, rhs: Type) @TypeOf(lhs & rhs) {
212 return lhs & rhs;
213}
214test bitAnd {
215 try testBinary(bitAnd);
216}
217
218inline fn bitOr(comptime Type: type, lhs: Type, rhs: Type) @TypeOf(lhs | rhs) {
219 return lhs | rhs;
220}
221test bitOr {
222 try testBinary(bitOr);
223}
224
225inline fn bitXor(comptime Type: type, lhs: Type, rhs: Type) @TypeOf(lhs ^ rhs) {
226 return lhs ^ rhs;
227}
228test bitXor {
229 try testBinary(bitXor);
230}