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 {...@@ -1229,7 +1229,7 @@ pub const VectorCmp = struct {
1229 op: u32,1229 op: u32,
12301230
1231 pub fn compareOperator(self: VectorCmp) std.math.CompareOperator {1231 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)));
1233 }1233 }
12341234
1235 pub fn encodeOp(compare_operator: std.math.CompareOperator) u32 {1235 pub fn encodeOp(compare_operator: std.math.CompareOperator) u32 {
...@@ -1274,11 +1274,11 @@ pub const Cmpxchg = struct {...@@ -1274,11 +1274,11 @@ pub const Cmpxchg = struct {
1274 flags: u32,1274 flags: u32,
12751275
1276 pub fn successOrder(self: Cmpxchg) std.builtin.AtomicOrder {1276 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)));
1278 }1278 }
12791279
1280 pub fn failureOrder(self: Cmpxchg) std.builtin.AtomicOrder {1280 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)));
1282 }1282 }
1283};1283};
12841284
...@@ -1289,11 +1289,11 @@ pub const AtomicRmw = struct {...@@ -1289,11 +1289,11 @@ pub const AtomicRmw = struct {
1289 flags: u32,1289 flags: u32,
12901290
1291 pub fn ordering(self: AtomicRmw) std.builtin.AtomicOrder {1291 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)));
1293 }1293 }
12941294
1295 pub fn op(self: AtomicRmw) std.builtin.AtomicRmwOp {1295 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)));
1297 }1297 }
1298};1298};
12991299
src/arch/x86_64/CodeGen.zig+2105-934
...@@ -135,6 +135,8 @@ const Owner = union(enum) {...@@ -135,6 +135,8 @@ const Owner = union(enum) {
135 }135 }
136};136};
137137
138const MaskKind = enum { sign, all };
139
138pub const MCValue = union(enum) {140pub const MCValue = union(enum) {
139 /// No runtime bits. `void` types, empty structs, u0, enums with 1 tag, etc.141 /// No runtime bits. `void` types, empty structs, u0, enums with 1 tag, etc.
140 /// TODO Look into deleting this tag and using `dead` instead, since every use142 /// TODO Look into deleting this tag and using `dead` instead, since every use
...@@ -156,10 +158,16 @@ pub const MCValue = union(enum) {...@@ -156,10 +158,16 @@ pub const MCValue = union(enum) {
156 register: Register,158 register: Register,
157 /// The value is split across two registers.159 /// The value is split across two registers.
158 register_pair: [2]Register,160 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,
159 /// The value is a constant offset from the value in a register.165 /// The value is a constant offset from the value in a register.
160 register_offset: bits.RegisterOffset,166 register_offset: bits.RegisterOffset,
161 /// The value is a tuple { wrapped, overflow } where wrapped value is stored in the GP register.167 /// The value is a tuple { wrapped, overflow } where wrapped value is stored in the GP register.
162 register_overflow: struct { reg: Register, eflags: Condition },168 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 },
163 /// The value is in memory at a hard-coded address.171 /// The value is in memory at a hard-coded address.
164 /// If the type is a pointer, it means the pointer address is stored at this memory location.172 /// If the type is a pointer, it means the pointer address is stored at this memory location.
165 memory: u64,173 memory: u64,
...@@ -195,7 +203,7 @@ pub const MCValue = union(enum) {...@@ -195,7 +203,7 @@ pub const MCValue = union(enum) {
195 /// Payload is a frame address.203 /// Payload is a frame address.
196 lea_frame: bits.FrameAddr,204 lea_frame: bits.FrameAddr,
197 /// Supports integer_per_element abi205 /// 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 },
199 /// This indicates that we have already allocated a frame index for this instruction,207 /// This indicates that we have already allocated a frame index for this instruction,
200 /// but it has not been spilled there yet in the current control flow.208 /// but it has not been spilled there yet in the current control flow.
201 /// Payload is a frame index.209 /// Payload is a frame index.
...@@ -210,6 +218,7 @@ pub const MCValue = union(enum) {...@@ -210,6 +218,7 @@ pub const MCValue = union(enum) {
210 .undef,218 .undef,
211 .immediate,219 .immediate,
212 .register_offset,220 .register_offset,
221 .register_mask,
213 .eflags,222 .eflags,
214 .register_overflow,223 .register_overflow,
215 .lea_symbol,224 .lea_symbol,
...@@ -223,6 +232,8 @@ pub const MCValue = union(enum) {...@@ -223,6 +232,8 @@ pub const MCValue = union(enum) {
223 => false,232 => false,
224 .register,233 .register,
225 .register_pair,234 .register_pair,
235 .register_triple,
236 .register_quadruple,
226 .memory,237 .memory,
227 .load_symbol,238 .load_symbol,
228 .load_got,239 .load_got,
...@@ -234,13 +245,20 @@ pub const MCValue = union(enum) {...@@ -234,13 +245,20 @@ pub const MCValue = union(enum) {
234 };245 };
235 }246 }
236247
237 fn isMemory(mcv: MCValue) bool {248 fn isBase(mcv: MCValue) bool {
238 return switch (mcv) {249 return switch (mcv) {
239 .memory, .indirect, .load_frame => true,250 .memory, .indirect, .load_frame => true,
240 else => false,251 else => false,
241 };252 };
242 }253 }
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
244 fn isImmediate(mcv: MCValue) bool {262 fn isImmediate(mcv: MCValue) bool {
245 return switch (mcv) {263 return switch (mcv) {
246 .immediate => true,264 .immediate => true,
...@@ -268,16 +286,23 @@ pub const MCValue = union(enum) {...@@ -268,16 +286,23 @@ pub const MCValue = union(enum) {
268 .register => |reg| reg,286 .register => |reg| reg,
269 .register_offset, .indirect => |ro| ro.reg,287 .register_offset, .indirect => |ro| ro.reg,
270 .register_overflow => |ro| ro.reg,288 .register_overflow => |ro| ro.reg,
289 .register_mask => |rm| rm.reg,
271 else => null,290 else => null,
272 };291 };
273 }292 }
274293
275 fn getRegs(mcv: *const MCValue) []const Register {294 fn getRegs(mcv: *const MCValue) []const Register {
276 return switch (mcv.*) {295 return switch (mcv.*) {
277 .register => |*reg| @as(*const [1]Register, reg),296 .register => |*reg| reg[0..1],
278 .register_pair => |*regs| regs,297 inline .register_pair,
279 .register_offset, .indirect => |*ro| @as(*const [1]Register, &ro.reg),298 .register_triple,
280 .register_overflow => |*ro| @as(*const [1]Register, &ro.reg),299 .register_quadruple,
300 => |*regs| regs,
301 inline .register_offset,
302 .indirect,
303 .register_overflow,
304 .register_mask,
305 => |*pl| (&pl.reg)[0..1],
281 else => &.{},306 else => &.{},
282 };307 };
283 }308 }
...@@ -300,8 +325,11 @@ pub const MCValue = union(enum) {...@@ -300,8 +325,11 @@ pub const MCValue = union(enum) {
300 .eflags,325 .eflags,
301 .register,326 .register,
302 .register_pair,327 .register_pair,
328 .register_triple,
329 .register_quadruple,
303 .register_offset,330 .register_offset,
304 .register_overflow,331 .register_overflow,
332 .register_mask,
305 .lea_symbol,333 .lea_symbol,
306 .lea_direct,334 .lea_direct,
307 .lea_got,335 .lea_got,
...@@ -332,7 +360,10 @@ pub const MCValue = union(enum) {...@@ -332,7 +360,10 @@ pub const MCValue = union(enum) {
332 .undef,360 .undef,
333 .eflags,361 .eflags,
334 .register_pair,362 .register_pair,
363 .register_triple,
364 .register_quadruple,
335 .register_overflow,365 .register_overflow,
366 .register_mask,
336 .memory,367 .memory,
337 .indirect,368 .indirect,
338 .load_direct,369 .load_direct,
...@@ -367,7 +398,10 @@ pub const MCValue = union(enum) {...@@ -367,7 +398,10 @@ pub const MCValue = union(enum) {
367 => unreachable, // not valid398 => unreachable, // not valid
368 .eflags,399 .eflags,
369 .register_pair,400 .register_pair,
401 .register_triple,
402 .register_quadruple,
370 .register_overflow,403 .register_overflow,
404 .register_mask,
371 .memory,405 .memory,
372 .indirect,406 .indirect,
373 .load_direct,407 .load_direct,
...@@ -404,8 +438,11 @@ pub const MCValue = union(enum) {...@@ -404,8 +438,11 @@ pub const MCValue = union(enum) {
404 .eflags,438 .eflags,
405 .register,439 .register,
406 .register_pair,440 .register_pair,
441 .register_triple,
442 .register_quadruple,
407 .register_offset,443 .register_offset,
408 .register_overflow,444 .register_overflow,
445 .register_mask,
409 .load_direct,446 .load_direct,
410 .lea_direct,447 .lea_direct,
411 .load_got,448 .load_got,
...@@ -472,10 +509,11 @@ pub const MCValue = union(enum) {...@@ -472,10 +509,11 @@ pub const MCValue = union(enum) {
472 .memory => |pl| try writer.print("[ds:0x{x}]", .{pl}),509 .memory => |pl| try writer.print("[ds:0x{x}]", .{pl}),
473 inline .eflags, .register => |pl| try writer.print("{s}", .{@tagName(pl)}),510 inline .eflags, .register => |pl| try writer.print("{s}", .{@tagName(pl)}),
474 .register_pair => |pl| try writer.print("{s}:{s}", .{ @tagName(pl[1]), @tagName(pl[0]) }),511 .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]) }),
475 .register_offset => |pl| try writer.print("{s} + 0x{x}", .{ @tagName(pl.reg), pl.off }),514 .register_offset => |pl| try writer.print("{s} + 0x{x}", .{ @tagName(pl.reg), pl.off }),
476 .register_overflow => |pl| try writer.print("{s}:{s}", .{515 .register_overflow => |pl| try writer.print("{s}:{s}", .{ @tagName(pl.eflags), @tagName(pl.reg) }),
477 @tagName(pl.eflags), @tagName(pl.reg),516 .register_mask => |pl| try writer.print("mask({s},{}):{s}", .{ @tagName(pl.kind), pl.scalar, @tagName(pl.reg) }),
478 }),
479 .load_symbol => |pl| try writer.print("[sym:{} + 0x{x}]", .{ pl.sym_index, pl.off }),517 .load_symbol => |pl| try writer.print("[sym:{} + 0x{x}]", .{ pl.sym_index, pl.off }),
480 .lea_symbol => |pl| try writer.print("sym:{} + 0x{x}", .{ pl.sym_index, pl.off }),518 .lea_symbol => |pl| try writer.print("sym:{} + 0x{x}", .{ pl.sym_index, pl.off }),
481 .indirect => |pl| try writer.print("[{s} + 0x{x}]", .{ @tagName(pl.reg), pl.off }),519 .indirect => |pl| try writer.print("[{s} + 0x{x}]", .{ @tagName(pl.reg), pl.off }),
...@@ -526,8 +564,11 @@ const InstTracking = struct {...@@ -526,8 +564,11 @@ const InstTracking = struct {
526 .eflags,564 .eflags,
527 .register,565 .register,
528 .register_pair,566 .register_pair,
567 .register_triple,
568 .register_quadruple,
529 .register_offset,569 .register_offset,
530 .register_overflow,570 .register_overflow,
571 .register_mask,
531 .indirect,572 .indirect,
532 => .none,573 => .none,
533 }, .short = result };574 }, .short = result };
...@@ -545,17 +586,17 @@ const InstTracking = struct {...@@ -545,17 +586,17 @@ const InstTracking = struct {
545 return self.short.getCondition();586 return self.short.getCondition();
546 }587 }
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 {
549 if (std.meta.eql(self.long, self.short)) return; // Already spilled590 if (std.meta.eql(self.long, self.short)) return; // Already spilled
550 // Allocate or reuse frame index591 // Allocate or reuse frame index
551 switch (self.long) {592 switch (self.long) {
552 .none => self.long = try function.allocRegOrMem(inst, false),593 .none => self.long = try cg.allocRegOrMem(inst, false),
553 .load_frame => {},594 .load_frame => {},
554 .reserved_frame => |index| self.long = .{ .load_frame = .{ .index = index } },595 .reserved_frame => |index| self.long = .{ .load_frame = .{ .index = index } },
555 else => unreachable,596 else => unreachable,
556 }597 }
557 tracking_log.debug("spill {} from {} to {}", .{ inst, self.short, self.long });598 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, .{});
559 }600 }
560601
561 fn reuseFrame(self: *InstTracking) void {602 fn reuseFrame(self: *InstTracking) void {
...@@ -584,8 +625,11 @@ const InstTracking = struct {...@@ -584,8 +625,11 @@ const InstTracking = struct {
584 .eflags,625 .eflags,
585 .register,626 .register,
586 .register_pair,627 .register_pair,
628 .register_triple,
629 .register_quadruple,
587 .register_offset,630 .register_offset,
588 .register_overflow,631 .register_overflow,
632 .register_mask,
589 .indirect,633 .indirect,
590 .elementwise_regs_then_frame,634 .elementwise_regs_then_frame,
591 .reserved_frame,635 .reserved_frame,
...@@ -630,8 +674,11 @@ const InstTracking = struct {...@@ -630,8 +674,11 @@ const InstTracking = struct {
630 .eflags,674 .eflags,
631 .register,675 .register,
632 .register_pair,676 .register_pair,
677 .register_triple,
678 .register_quadruple,
633 .register_offset,679 .register_offset,
634 .register_overflow,680 .register_overflow,
681 .register_mask,
635 .indirect,682 .indirect,
636 .elementwise_regs_then_frame,683 .elementwise_regs_then_frame,
637 .air_ref,684 .air_ref,
...@@ -735,13 +782,13 @@ const InstTracking = struct {...@@ -735,13 +782,13 @@ const InstTracking = struct {
735 }782 }
736783
737 pub fn format(784 pub fn format(
738 self: InstTracking,785 tracking: InstTracking,
739 comptime _: []const u8,786 comptime _: []const u8,
740 _: std.fmt.FormatOptions,787 _: std.fmt.FormatOptions,
741 writer: anytype,788 writer: anytype,
742 ) @TypeOf(writer).Error!void {789 ) @TypeOf(writer).Error!void {
743 if (!std.meta.eql(self.long, self.short)) try writer.print("|{}| ", .{self.long});790 if (!std.meta.eql(tracking.long, tracking.short)) try writer.print("|{}| ", .{tracking.long});
744 try writer.print("{}", .{self.short});791 try writer.print("{}", .{tracking.short});
745 }792 }
746};793};
747794
...@@ -2259,44 +2306,44 @@ fn genBodyBlock(self: *CodeGen, body: []const Air.Inst.Index) InnerError!void {...@@ -2259,44 +2306,44 @@ fn genBodyBlock(self: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
2259 try self.asmPseudo(.pseudo_dbg_leave_block_none);2306 try self.asmPseudo(.pseudo_dbg_leave_block_none);
2260}2307}
22612308
2262fn genBody(self: *CodeGen, body: []const Air.Inst.Index) InnerError!void {2309fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
2263 const pt = self.pt;2310 const pt = cg.pt;
2264 const zcu = pt.zcu;2311 const zcu = pt.zcu;
2265 const ip = &zcu.intern_pool;2312 const ip = &zcu.intern_pool;
2266 const air_tags = self.air.instructions.items(.tag);2313 const air_tags = cg.air.instructions.items(.tag);
2267 const air_datas = self.air.instructions.items(.data);2314 const air_datas = cg.air.instructions.items(.data);
2268 const use_old = self.target.ofmt == .coff;2315 const use_old = cg.target.ofmt == .coff;
22692316
2270 self.arg_index = 0;2317 cg.arg_index = 0;
2271 for (body) |inst| switch (air_tags[@intFromEnum(inst)]) {2318 for (body) |inst| switch (air_tags[@intFromEnum(inst)]) {
2272 .arg => {2319 .arg => {
2273 wip_mir_log.debug("{}", .{self.fmtAir(inst)});2320 wip_mir_log.debug("{}", .{cg.fmtAir(inst)});
2274 verbose_tracking_log.debug("{}", .{self.fmtTracking()});2321 verbose_tracking_log.debug("{}", .{cg.fmtTracking()});
22752322
2276 self.reused_operands = .initEmpty();2323 cg.reused_operands = .initEmpty();
2277 try self.inst_tracking.ensureUnusedCapacity(self.gpa, 1);2324 try cg.inst_tracking.ensureUnusedCapacity(cg.gpa, 1);
22782325
2279 try self.airArg(inst);2326 try cg.airArg(inst);
22802327
2281 self.resetTemps();2328 cg.resetTemps();
2282 self.checkInvariantsAfterAirInst();2329 cg.checkInvariantsAfterAirInst();
2283 },2330 },
2284 else => break,2331 else => break,
2285 };2332 };
22862333
2287 if (self.arg_index == 0) try self.airDbgVarArgs();2334 if (cg.arg_index == 0) try cg.airDbgVarArgs();
2288 self.arg_index = 0;2335 cg.arg_index = 0;
2289 for (body) |inst| {2336 for (body) |inst| {
2290 if (self.liveness.isUnused(inst) and !self.air.mustLower(inst, ip)) continue;2337 if (cg.liveness.isUnused(inst) and !cg.air.mustLower(inst, ip)) continue;
2291 wip_mir_log.debug("{}", .{self.fmtAir(inst)});2338 wip_mir_log.debug("{}", .{cg.fmtAir(inst)});
2292 verbose_tracking_log.debug("{}", .{self.fmtTracking()});2339 verbose_tracking_log.debug("{}", .{cg.fmtTracking()});
22932340
2294 self.reused_operands = .initEmpty();2341 cg.reused_operands = .initEmpty();
2295 try self.inst_tracking.ensureUnusedCapacity(self.gpa, 1);2342 try cg.inst_tracking.ensureUnusedCapacity(cg.gpa, 1);
2296 switch (air_tags[@intFromEnum(inst)]) {2343 switch (air_tags[@intFromEnum(inst)]) {
2297 // zig fmt: off2344 // zig fmt: off
2298 .not,2345 .not,
2299 => |tag| try self.airUnOp(inst, tag),2346 => |air_tag| try cg.airUnOp(inst, air_tag),
23002347
2301 .add,2348 .add,
2302 .add_wrap,2349 .add_wrap,
...@@ -2306,22 +2353,22 @@ fn genBody(self: *CodeGen, body: []const Air.Inst.Index) InnerError!void {...@@ -2306,22 +2353,22 @@ fn genBody(self: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
2306 .bool_or,2353 .bool_or,
2307 .min,2354 .min,
2308 .max,2355 .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),2360 .shr, .shr_exact => try cg.airShlShrBinOp(inst),
2314 .shl, .shl_exact => try self.airShlShrBinOp(inst),2361 .shl, .shl_exact => try cg.airShlShrBinOp(inst),
23152362
2316 .mul => try self.airMulDivBinOp(inst),2363 .mul => try cg.airMulDivBinOp(inst),
2317 .mul_wrap => try self.airMulDivBinOp(inst),2364 .mul_wrap => try cg.airMulDivBinOp(inst),
2318 .rem => try self.airMulDivBinOp(inst),2365 .rem => try cg.airMulDivBinOp(inst),
2319 .mod => try self.airMulDivBinOp(inst),2366 .mod => try cg.airMulDivBinOp(inst),
23202367
2321 .add_sat => try self.airAddSat(inst),2368 .add_sat => try cg.airAddSat(inst),
2322 .sub_sat => try self.airSubSat(inst),2369 .sub_sat => try cg.airSubSat(inst),
2323 .mul_sat => try self.airMulSat(inst),2370 .mul_sat => try cg.airMulSat(inst),
2324 .shl_sat => try self.airShlSat(inst),2371 .shl_sat => try cg.airShlSat(inst),
23252372
2326 .sin,2373 .sin,
2327 .cos,2374 .cos,
...@@ -2332,98 +2379,97 @@ fn genBody(self: *CodeGen, body: []const Air.Inst.Index) InnerError!void {...@@ -2332,98 +2379,97 @@ fn genBody(self: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
2332 .log2,2379 .log2,
2333 .log10,2380 .log10,
2334 .round,2381 .round,
2335 => |tag| try self.airUnaryMath(inst, tag),2382 => |air_tag| try cg.airUnaryMath(inst, air_tag),
23362383
2337 .floor => try self.airRound(inst, .{ .mode = .down, .precision = .inexact }),2384 .floor => try cg.airRound(inst, .{ .mode = .down, .precision = .inexact }),
2338 .ceil => try self.airRound(inst, .{ .mode = .up, .precision = .inexact }),2385 .ceil => try cg.airRound(inst, .{ .mode = .up, .precision = .inexact }),
2339 .trunc_float => try self.airRound(inst, .{ .mode = .zero, .precision = .inexact }),2386 .trunc_float => try cg.airRound(inst, .{ .mode = .zero, .precision = .inexact }),
2340 .sqrt => try self.airSqrt(inst),2387 .sqrt => try cg.airSqrt(inst),
2341 .neg => try self.airFloatSign(inst),2388 .neg => try cg.airFloatSign(inst),
23422389
2343 .abs => try self.airAbs(inst),2390 .abs => try cg.airAbs(inst),
23442391
2345 .add_with_overflow => try self.airAddSubWithOverflow(inst),2392 .add_with_overflow => try cg.airAddSubWithOverflow(inst),
2346 .sub_with_overflow => try self.airAddSubWithOverflow(inst),2393 .sub_with_overflow => try cg.airAddSubWithOverflow(inst),
2347 .mul_with_overflow => try self.airMulWithOverflow(inst),2394 .mul_with_overflow => try cg.airMulWithOverflow(inst),
2348 .shl_with_overflow => try self.airShlWithOverflow(inst),2395 .shl_with_overflow => try cg.airShlWithOverflow(inst),
23492396
2350 .div_float, .div_trunc, .div_floor, .div_exact => try self.airMulDivBinOp(inst),2397 .div_float, .div_trunc, .div_floor, .div_exact => try cg.airMulDivBinOp(inst),
23512398
2352 .cmp_lt => try self.airCmp(inst, .lt),2399 .cmp_lt => try cg.airCmp(inst, .lt),
2353 .cmp_lte => try self.airCmp(inst, .lte),2400 .cmp_lte => try cg.airCmp(inst, .lte),
2354 .cmp_eq => try self.airCmp(inst, .eq),2401 .cmp_eq => try cg.airCmp(inst, .eq),
2355 .cmp_gte => try self.airCmp(inst, .gte),2402 .cmp_gte => try cg.airCmp(inst, .gte),
2356 .cmp_gt => try self.airCmp(inst, .gt),2403 .cmp_gt => try cg.airCmp(inst, .gt),
2357 .cmp_neq => try self.airCmp(inst, .neq),2404 .cmp_neq => try cg.airCmp(inst, .neq),
23582405
2359 .cmp_vector => try self.airCmpVector(inst),2406 .cmp_lt_errors_len => try cg.airCmpLtErrorsLen(inst),
2360 .cmp_lt_errors_len => try self.airCmpLtErrorsLen(inst),2407
23612408 .bitcast => try cg.airBitCast(inst),
2362 .bitcast => try self.airBitCast(inst),2409 .fptrunc => try cg.airFptrunc(inst),
2363 .fptrunc => try self.airFptrunc(inst),2410 .fpext => try cg.airFpext(inst),
2364 .fpext => try self.airFpext(inst),2411 .intcast => try cg.airIntCast(inst),
2365 .intcast => try self.airIntCast(inst),2412 .trunc => try cg.airTrunc(inst),
2366 .trunc => try self.airTrunc(inst),2413 .is_non_null => try cg.airIsNonNull(inst),
2367 .is_non_null => try self.airIsNonNull(inst),2414 .is_null => try cg.airIsNull(inst),
2368 .is_null => try self.airIsNull(inst),2415 .is_non_err => try cg.airIsNonErr(inst),
2369 .is_non_err => try self.airIsNonErr(inst),2416 .is_err => try cg.airIsErr(inst),
2370 .is_err => try self.airIsErr(inst),2417 .load => try cg.airLoad(inst),
2371 .load => try self.airLoad(inst),2418 .store => try cg.airStore(inst, false),
2372 .store => try self.airStore(inst, false),2419 .store_safe => try cg.airStore(inst, true),
2373 .store_safe => try self.airStore(inst, true),2420 .struct_field_val => try cg.airStructFieldVal(inst),
2374 .struct_field_val => try self.airStructFieldVal(inst),2421 .float_from_int => try cg.airFloatFromInt(inst),
2375 .float_from_int => try self.airFloatFromInt(inst),2422 .int_from_float => try cg.airIntFromFloat(inst),
2376 .int_from_float => try self.airIntFromFloat(inst),2423 .cmpxchg_strong => try cg.airCmpxchg(inst),
2377 .cmpxchg_strong => try self.airCmpxchg(inst),2424 .cmpxchg_weak => try cg.airCmpxchg(inst),
2378 .cmpxchg_weak => try self.airCmpxchg(inst),2425 .atomic_rmw => try cg.airAtomicRmw(inst),
2379 .atomic_rmw => try self.airAtomicRmw(inst),2426 .atomic_load => try cg.airAtomicLoad(inst),
2380 .atomic_load => try self.airAtomicLoad(inst),2427 .memcpy => try cg.airMemcpy(inst),
2381 .memcpy => try self.airMemcpy(inst),2428 .memset => try cg.airMemset(inst, false),
2382 .memset => try self.airMemset(inst, false),2429 .memset_safe => try cg.airMemset(inst, true),
2383 .memset_safe => try self.airMemset(inst, true),2430 .set_union_tag => try cg.airSetUnionTag(inst),
2384 .set_union_tag => try self.airSetUnionTag(inst),2431 .get_union_tag => try cg.airGetUnionTag(inst),
2385 .get_union_tag => try self.airGetUnionTag(inst),2432 .clz => try cg.airClz(inst),
2386 .clz => try self.airClz(inst),2433 .ctz => try cg.airCtz(inst),
2387 .ctz => try self.airCtz(inst),2434 .popcount => try cg.airPopCount(inst),
2388 .popcount => try self.airPopCount(inst),2435 .byte_swap => try cg.airByteSwap(inst),
2389 .byte_swap => try self.airByteSwap(inst),2436 .bit_reverse => try cg.airBitReverse(inst),
2390 .bit_reverse => try self.airBitReverse(inst),2437 .tag_name => try cg.airTagName(inst),
2391 .tag_name => try self.airTagName(inst),2438 .error_name => try cg.airErrorName(inst),
2392 .error_name => try self.airErrorName(inst),2439 .splat => try cg.airSplat(inst),
2393 .splat => try self.airSplat(inst),2440 .select => try cg.airSelect(inst),
2394 .select => try self.airSelect(inst),2441 .shuffle => try cg.airShuffle(inst),
2395 .shuffle => try self.airShuffle(inst),2442 .reduce => try cg.airReduce(inst),
2396 .reduce => try self.airReduce(inst),2443 .aggregate_init => try cg.airAggregateInit(inst),
2397 .aggregate_init => try self.airAggregateInit(inst),2444 .union_init => try cg.airUnionInit(inst),
2398 .union_init => try self.airUnionInit(inst),2445 .prefetch => try cg.airPrefetch(inst),
2399 .prefetch => try self.airPrefetch(inst),2446 .mul_add => try cg.airMulAdd(inst),
2400 .mul_add => try self.airMulAdd(inst),2447
24012448 .atomic_store_unordered => try cg.airAtomicStore(inst, .unordered),
2402 .atomic_store_unordered => try self.airAtomicStore(inst, .unordered),2449 .atomic_store_monotonic => try cg.airAtomicStore(inst, .monotonic),
2403 .atomic_store_monotonic => try self.airAtomicStore(inst, .monotonic),2450 .atomic_store_release => try cg.airAtomicStore(inst, .release),
2404 .atomic_store_release => try self.airAtomicStore(inst, .release),2451 .atomic_store_seq_cst => try cg.airAtomicStore(inst, .seq_cst),
2405 .atomic_store_seq_cst => try self.airAtomicStore(inst, .seq_cst),2452
24062453 .array_elem_val => try cg.airArrayElemVal(inst),
2407 .array_elem_val => try self.airArrayElemVal(inst),2454 .slice_elem_val => try cg.airSliceElemVal(inst),
2408 .slice_elem_val => try self.airSliceElemVal(inst),2455 .ptr_elem_val => try cg.airPtrElemVal(inst),
2409 .ptr_elem_val => try self.airPtrElemVal(inst),2456
24102457 .optional_payload => try cg.airOptionalPayload(inst),
2411 .optional_payload => try self.airOptionalPayload(inst),2458 .unwrap_errunion_err => try cg.airUnwrapErrUnionErr(inst),
2412 .unwrap_errunion_err => try self.airUnwrapErrUnionErr(inst),2459 .unwrap_errunion_payload => try cg.airUnwrapErrUnionPayload(inst),
2413 .unwrap_errunion_payload => try self.airUnwrapErrUnionPayload(inst),2460 .err_return_trace => try cg.airErrReturnTrace(inst),
2414 .err_return_trace => try self.airErrReturnTrace(inst),2461 .set_err_return_trace => try cg.airSetErrReturnTrace(inst),
2415 .set_err_return_trace => try self.airSetErrReturnTrace(inst),2462 .save_err_return_trace_index=> try cg.airSaveErrReturnTraceIndex(inst),
2416 .save_err_return_trace_index=> try self.airSaveErrReturnTraceIndex(inst),2463
24172464 .wrap_optional => try cg.airWrapOptional(inst),
2418 .wrap_optional => try self.airWrapOptional(inst),2465 .wrap_errunion_payload => try cg.airWrapErrUnionPayload(inst),
2419 .wrap_errunion_payload => try self.airWrapErrUnionPayload(inst),2466 .wrap_errunion_err => try cg.airWrapErrUnionErr(inst),
2420 .wrap_errunion_err => try self.airWrapErrUnionErr(inst),
2421 // zig fmt: on2467 // zig fmt: on
24222468
2423 .add_safe,2469 .add_safe,
2424 .sub_safe,2470 .sub_safe,
2425 .mul_safe,2471 .mul_safe,
2426 => return self.fail("TODO implement safety_checked_instructions", .{}),2472 => return cg.fail("TODO implement safety_checked_instructions", .{}),
2427 .add_optimized,2473 .add_optimized,
2428 .sub_optimized,2474 .sub_optimized,
2429 .mul_optimized,2475 .mul_optimized,
...@@ -2440,214 +2486,612 @@ fn genBody(self: *CodeGen, body: []const Air.Inst.Index) InnerError!void {...@@ -2440,214 +2486,612 @@ fn genBody(self: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
2440 .cmp_gte_optimized,2486 .cmp_gte_optimized,
2441 .cmp_gt_optimized,2487 .cmp_gt_optimized,
2442 .cmp_neq_optimized,2488 .cmp_neq_optimized,
2443 .cmp_vector_optimized,
2444 .reduce_optimized,2489 .reduce_optimized,
2445 .int_from_float_optimized,2490 .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),2493 .arg => try cg.airDbgArg(inst),
2449 .alloc => if (use_old) try self.airAlloc(inst) else {2494 .alloc => if (use_old) try cg.airAlloc(inst) else {
2450 var slot = try self.tempFromValue(self.typeOfIndex(inst), .{ .lea_frame = .{2495 var slot = try cg.tempFromValue(cg.typeOfIndex(inst), .{ .lea_frame = .{
2451 .index = try self.allocMemPtr(inst),2496 .index = try cg.allocMemPtr(inst),
2452 } });2497 } });
2453 try slot.moveTo(inst, self);2498 try slot.moveTo(inst, cg);
2454 },2499 },
2455 .inferred_alloc => unreachable,2500 .inferred_alloc => unreachable,
2456 .inferred_alloc_comptime => unreachable,2501 .inferred_alloc_comptime => unreachable,
2457 .ret_ptr => if (use_old) try self.airRetPtr(inst) else {2502 .ret_ptr => if (use_old) try cg.airRetPtr(inst) else {
2458 var slot = switch (self.ret_mcv.long) {2503 var slot = switch (cg.ret_mcv.long) {
2459 else => unreachable,2504 else => unreachable,
2460 .none => try self.tempFromValue(self.typeOfIndex(inst), .{ .lea_frame = .{2505 .none => try cg.tempFromValue(cg.typeOfIndex(inst), .{ .lea_frame = .{
2461 .index = try self.allocMemPtr(inst),2506 .index = try cg.allocMemPtr(inst),
2462 } }),2507 } }),
2463 .load_frame => slot: {2508 .load_frame => slot: {
2464 var slot = try self.tempFromValue(self.typeOfIndex(inst), self.ret_mcv.long);2509 var slot = try cg.tempFromValue(cg.typeOfIndex(inst), cg.ret_mcv.long);
2465 try slot.toOffset(self.ret_mcv.short.indirect.off, self);2510 try slot.toOffset(cg.ret_mcv.short.indirect.off, cg);
2466 break :slot slot;2511 break :slot slot;
2467 },2512 },
2468 };2513 };
2469 try slot.moveTo(inst, self);2514 try slot.moveTo(inst, cg);
2470 },2515 },
2471 .assembly => try self.airAsm(inst),2516 .assembly => try cg.airAsm(inst),
2472 inline .bit_and, .bit_or, .xor => |tag| if (use_old) try self.airBinOp(inst, tag) else {2517 .bit_and, .bit_or, .xor => |air_tag| if (use_old) try cg.airBinOp(inst, air_tag) else {
2473 const bin_op = air_datas[@intFromEnum(inst)].bin_op;2518 const bin_op = air_datas[@intFromEnum(inst)].bin_op;
2474 var ops = try self.tempsFromOperands(inst, .{ bin_op.lhs, bin_op.rhs });2519 var ops = try cg.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 };
2482 var res: [1]Temp = undefined;2520 var res: [1]Temp = undefined;
2483 try self.select(&res, &.{ &ops[0], &ops[1] }, &.{2521 try cg.select(&res, &.{cg.typeOfIndex(inst)}, &ops, pattern_sets: switch (air_tag) {
2484 .{2522 else => unreachable,
2485 .required_features = &.{.avx2},2523 inline .bit_and, .bit_or, .xor => |ct_air_tag| {
2486 .mir_tag = .{ .vp_, mir_tag },2524 const mir_tag: Mir.Inst.Tag = switch (ct_air_tag) {
2487 .patterns = &.{2525 else => unreachable,
2488 .{ .ops = &.{ .ymm, .ymm, .mem } },2526 .bit_and => .@"and",
2489 .{ .ops = &.{ .ymm, .mem, .ymm }, .commute = .{ 1, 2 } },2527 .bit_or => .@"or",
2490 .{ .ops = &.{ .ymm, .ymm, .ymm } },2528 .xor => .xor,
2491 },2529 };
2492 },2530 break :pattern_sets &.{
2493 .{2531 .{
2494 .required_features = &.{.avx},2532 .required_features = &.{.avx2},
2495 .mir_tag = .{ .vp_, mir_tag },2533 .mir_tag = .{ .vp_, mir_tag },
2496 .patterns = &.{2534 .patterns = &.{
2497 .{ .ops = &.{ .xmm, .xmm, .mem } },2535 .{ .ops = &.{ .ymm, .ymm, .mem } },
2498 .{ .ops = &.{ .xmm, .mem, .xmm }, .commute = .{ 1, 2 } },2536 .{ .ops = &.{ .ymm, .mem, .ymm }, .commute = .{ 1, 2 } },
2499 .{ .ops = &.{ .xmm, .xmm, .xmm } },2537 .{ .ops = &.{ .ymm, .ymm, .ymm } },
2500 },2538 },
2501 },2539 },
2502 .{2540 .{
2503 .required_features = &.{.sse2},2541 .required_features = &.{.avx},
2504 .mir_tag = .{ .p_, mir_tag },2542 .mir_tag = .{ .vp_, mir_tag },
2505 .patterns = &.{2543 .patterns = &.{
2506 .{ .ops = &.{ .xmm, .{ .implicit = 0 }, .mem } },2544 .{ .ops = &.{ .xmm, .xmm, .mem } },
2507 .{ .ops = &.{ .xmm, .mem, .{ .implicit = 0 } } },2545 .{ .ops = &.{ .xmm, .mem, .xmm }, .commute = .{ 1, 2 } },
2508 .{ .ops = &.{ .xmm, .{ .implicit = 0 }, .xmm } },2546 .{ .ops = &.{ .xmm, .xmm, .xmm } },
2509 .{ .ops = &.{ .xmm, .xmm, .{ .implicit = 0 } } },2547 },
2510 },2548 },
2511 },2549 .{
2512 .{2550 .required_features = &.{.sse2},
2513 .required_features = &.{.mmx},2551 .mir_tag = .{ .p_, mir_tag },
2514 .mir_tag = .{ .p_, mir_tag },2552 .patterns = &.{
2515 .patterns = &.{2553 .{ .ops = &.{ .xmm, .{ .implicit = 0 }, .mem } },
2516 .{ .ops = &.{ .mm, .{ .implicit = 0 }, .mem } },2554 .{ .ops = &.{ .xmm, .mem, .{ .implicit = 0 } } },
2517 .{ .ops = &.{ .mm, .mem, .{ .implicit = 0 } } },2555 .{ .ops = &.{ .xmm, .{ .implicit = 0 }, .xmm } },
2518 .{ .ops = &.{ .mm, .{ .implicit = 0 }, .mm } },2556 .{ .ops = &.{ .xmm, .xmm, .{ .implicit = 0 } } },
2519 .{ .ops = &.{ .mm, .mm, .{ .implicit = 0 } } },2557 },
2520 },2558 },
2521 },2559 .{
2522 .{2560 .required_features = &.{.mmx},
2523 .mir_tag = .{ ._, mir_tag },2561 .mir_tag = .{ .p_, mir_tag },
2524 .patterns = &.{2562 .patterns = &.{
2525 .{ .ops = &.{ .mem, .{ .implicit = 0 }, .simm32 } },2563 .{ .ops = &.{ .mm, .{ .implicit = 0 }, .mem } },
2526 .{ .ops = &.{ .mem, .simm32, .{ .implicit = 0 } } },2564 .{ .ops = &.{ .mm, .mem, .{ .implicit = 0 } } },
2527 .{ .ops = &.{ .mem, .{ .implicit = 0 }, .gpr } },2565 .{ .ops = &.{ .mm, .{ .implicit = 0 }, .mm } },
2528 .{ .ops = &.{ .mem, .gpr, .{ .implicit = 0 } } },2566 .{ .ops = &.{ .mm, .mm, .{ .implicit = 0 } } },
2529 .{ .ops = &.{ .gpr, .{ .implicit = 0 }, .simm32 } },2567 },
2530 .{ .ops = &.{ .gpr, .simm32, .{ .implicit = 0 } } },2568 },
2531 .{ .ops = &.{ .gpr, .{ .implicit = 0 }, .mem } },2569 .{
2532 .{ .ops = &.{ .gpr, .mem, .{ .implicit = 0 } } },2570 .clobbers = .{ .eflags = true },
2533 .{ .ops = &.{ .gpr, .{ .implicit = 0 }, .gpr } },2571 .mir_tag = .{ ._, mir_tag },
2534 .{ .ops = &.{ .gpr, .gpr, .{ .implicit = 0 } } },2572 .patterns = &.{
2535 },2573 .{ .ops = &.{ .mem, .{ .implicit = 0 }, .simm32 } },
2536 },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 .{2586 .{
2539 .required_features = &.{.avx2},2587 .required_features = &.{.avx2},
2540 .loop = .bitwise,2588 .loop = .bitwise,
2541 .mir_tag = .{ .vp_, mir_tag },2589 .mir_tag = .{ .vp_, mir_tag },
2542 .patterns = &.{2590 .patterns = &.{
2543 .{ .ops = &.{ .ymm_limb, .{ .explicit = 0 }, .mem_limb } },2591 .{ .ops = &.{ .ymm_limb, .{ .explicit = 0 }, .mem_limb } },
2544 .{ .ops = &.{ .ymm_limb, .mem_limb, .{ .explicit = 0 } }, .commute = .{ 1, 2 } },2592 .{ .ops = &.{ .ymm_limb, .mem_limb, .{ .explicit = 0 } }, .commute = .{ 1, 2 } },
2545 .{ .ops = &.{ .ymm_limb, .ymm_limb, .mem_limb } },2593 .{ .ops = &.{ .ymm_limb, .ymm_limb, .mem_limb } },
2546 },2594 .{ .ops = &.{ .ymm_limb, .ymm_limb, .ymm_limb } },
2547 },2595 },
2548 .{2596 },
2549 .required_features = &.{.avx},2597 .{
2550 .loop = .bitwise,2598 .required_features = &.{.avx},
2551 .mir_tag = .{ .vp_, mir_tag },2599 .loop = .bitwise,
2552 .patterns = &.{2600 .mir_tag = .{ .vp_, mir_tag },
2553 .{ .ops = &.{ .xmm_limb, .{ .explicit = 0 }, .mem_limb } },2601 .patterns = &.{
2554 .{ .ops = &.{ .xmm_limb, .mem_limb, .{ .explicit = 0 } }, .commute = .{ 1, 2 } },2602 .{ .ops = &.{ .xmm_limb, .{ .explicit = 0 }, .mem_limb } },
2555 .{ .ops = &.{ .xmm_limb, .xmm_limb, .mem_limb } },2603 .{ .ops = &.{ .xmm_limb, .mem_limb, .{ .explicit = 0 } }, .commute = .{ 1, 2 } },
2556 },2604 .{ .ops = &.{ .xmm_limb, .xmm_limb, .mem_limb } },
2557 },2605 .{ .ops = &.{ .xmm_limb, .xmm_limb, .xmm_limb } },
2558 .{2606 },
2559 .required_features = &.{.sse2},2607 },
2560 .loop = .bitwise,2608 .{
2561 .mir_tag = .{ .p_, mir_tag },2609 .required_features = &.{.sse2},
2562 .patterns = &.{2610 .loop = .bitwise,
2563 .{ .ops = &.{ .xmm_limb, .{ .implicit = 0 }, .mem_limb } },2611 .mir_tag = .{ .p_, mir_tag },
2564 .{ .ops = &.{ .xmm_limb, .mem_limb, .{ .implicit = 0 } } },2612 .patterns = &.{
2565 },2613 .{ .ops = &.{ .xmm_limb, .{ .implicit = 0 }, .mem_limb } },
2566 },2614 .{ .ops = &.{ .xmm_limb, .mem_limb, .{ .implicit = 0 } } },
2567 .{2615 .{ .ops = &.{ .xmm_limb, .{ .implicit = 0 }, .xmm_limb } },
2568 .required_features = &.{.mmx},2616 },
2569 .loop = .bitwise,2617 },
2570 .mir_tag = .{ .p_, mir_tag },2618 .{
2571 .patterns = &.{2619 .required_features = &.{.mmx},
2572 .{ .ops = &.{ .mm_limb, .{ .implicit = 0 }, .mem_limb } },2620 .loop = .bitwise,
2573 .{ .ops = &.{ .mm_limb, .mem_limb, .{ .implicit = 0 } } },2621 .mir_tag = .{ .p_, mir_tag },
2574 },2622 .patterns = &.{
2575 },2623 .{ .ops = &.{ .mm_limb, .{ .implicit = 0 }, .mem_limb } },
2576 .{2624 .{ .ops = &.{ .mm_limb, .mem_limb, .{ .implicit = 0 } } },
2577 .loop = .bitwise,2625 .{ .ops = &.{ .mm_limb, .{ .implicit = 0 }, .mm_limb } },
2578 .mir_tag = .{ ._, mir_tag },2626 },
2579 .patterns = &.{2627 },
2580 .{ .ops = &.{ .mem_limb, .{ .implicit = 0 }, .gpr_limb } },2628 .{
2581 .{ .ops = &.{ .mem_limb, .gpr_limb, .{ .implicit = 0 } } },2629 .clobbers = .{ .eflags = true },
2582 .{ .ops = &.{ .gpr_limb, .{ .implicit = 0 }, .mem_limb } },2630 .loop = .bitwise,
2583 .{ .ops = &.{ .gpr_limb, .mem_limb, .{ .implicit = 0 } } },2631 .mir_tag = .{ ._, mir_tag },
2584 .{ .ops = &.{ .gpr_limb, .{ .implicit = 0 }, .gpr_limb } },2632 .patterns = &.{
2585 },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 };
2586 },2641 },
2587 });2642 }, .{});
2588 if (ops[0].index != res[0].index) try ops[0].die(self);2643 if (ops[0].index != res[0].index) try ops[0].die(cg);
2589 if (ops[1].index != res[0].index) try ops[1].die(self);2644 if (ops[1].index != res[0].index) try ops[1].die(cg);
2590 try res[0].moveTo(inst, self);2645 try res[0].moveTo(inst, cg);
2591 },2646 },
2592 .block => if (use_old) try self.airBlock(inst) else {2647 .block => if (use_old) try cg.airBlock(inst) else {
2593 const ty_pl = air_datas[@intFromEnum(inst)].ty_pl;2648 const ty_pl = air_datas[@intFromEnum(inst)].ty_pl;
2594 const extra = self.air.extraData(Air.Block, ty_pl.payload);2649 const extra = cg.air.extraData(Air.Block, ty_pl.payload);
2595 try self.asmPseudo(.pseudo_dbg_enter_block_none);2650 try cg.asmPseudo(.pseudo_dbg_enter_block_none);
2596 try self.lowerBlock(inst, @ptrCast(self.air.extra[extra.end..][0..extra.data.body_len]));2651 try cg.lowerBlock(inst, @ptrCast(cg.air.extra[extra.end..][0..extra.data.body_len]));
2597 try self.asmPseudo(.pseudo_dbg_leave_block_none);2652 try cg.asmPseudo(.pseudo_dbg_leave_block_none);
2598 },2653 },
2599 .loop => if (use_old) try self.airLoop(inst) else {2654 .loop => if (use_old) try cg.airLoop(inst) else {
2600 const ty_pl = air_datas[@intFromEnum(inst)].ty_pl;2655 const ty_pl = air_datas[@intFromEnum(inst)].ty_pl;
2601 const extra = self.air.extraData(Air.Block, ty_pl.payload);2656 const extra = cg.air.extraData(Air.Block, ty_pl.payload);
2602 self.scope_generation += 1;2657 cg.scope_generation += 1;
2603 try self.loops.putNoClobber(self.gpa, inst, .{2658 try cg.loops.putNoClobber(cg.gpa, inst, .{
2604 .state = try self.saveState(),2659 .state = try cg.saveState(),
2605 .target = @intCast(self.mir_instructions.len),2660 .target = @intCast(cg.mir_instructions.len),
2606 });2661 });
2607 defer assert(self.loops.remove(inst));2662 defer assert(cg.loops.remove(inst));
2608 try self.genBodyBlock(@ptrCast(self.air.extra[extra.end..][0..extra.data.body_len]));2663 try cg.genBodyBlock(@ptrCast(cg.air.extra[extra.end..][0..extra.data.body_len]));
2609 },2664 },
2610 .repeat => if (use_old) try self.airRepeat(inst) else {2665 .repeat => if (use_old) try cg.airRepeat(inst) else {
2611 const repeat = air_datas[@intFromEnum(inst)].repeat;2666 const repeat = air_datas[@intFromEnum(inst)].repeat;
2612 const loop = self.loops.get(repeat.loop_inst).?;2667 const loop = cg.loops.get(repeat.loop_inst).?;
2613 try self.restoreState(loop.state, &.{}, .{2668 try cg.restoreState(loop.state, &.{}, .{
2614 .emit_instructions = true,2669 .emit_instructions = true,
2615 .update_tracking = false,2670 .update_tracking = false,
2616 .resurrect = false,2671 .resurrect = false,
2617 .close_scope = true,2672 .close_scope = true,
2618 });2673 });
2619 _ = try self.asmJmpReloc(loop.target);2674 _ = try cg.asmJmpReloc(loop.target);
2620 },2675 },
2621 .br => try self.airBr(inst),2676 .br => try cg.airBr(inst),
2622 .trap => try self.asmOpOnly(.{ ._, .ud2 }),2677 .trap => try cg.asmOpOnly(.{ ._, .ud2 }),
2623 .breakpoint => try self.asmOpOnly(.{ ._, .int3 }),2678 .breakpoint => try cg.asmOpOnly(.{ ._, .int3 }),
2624 .ret_addr => if (use_old) try self.airRetAddr(inst) else {2679 .ret_addr => if (use_old) try cg.airRetAddr(inst) else {
2625 var slot = try self.tempFromValue(self.typeOfIndex(inst), .{ .load_frame = .{2680 var slot = try cg.tempFromValue(cg.typeOfIndex(inst), .{ .load_frame = .{
2626 .index = .ret_addr,2681 .index = .ret_addr,
2627 } });2682 } });
2628 while (try slot.toAnyReg(self)) {}2683 while (try slot.toAnyReg(cg)) {}
2629 try slot.moveTo(inst, self);2684 try slot.moveTo(inst, cg);
2630 },2685 },
2631 .frame_addr => if (use_old) try self.airFrameAddress(inst) else {2686 .frame_addr => if (use_old) try cg.airFrameAddress(inst) else {
2632 var slot = try self.tempFromValue(self.typeOfIndex(inst), .{ .lea_frame = .{2687 var slot = try cg.tempFromValue(cg.typeOfIndex(inst), .{ .lea_frame = .{
2633 .index = .base_ptr,2688 .index = .base_ptr,
2634 } });2689 } });
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);
2636 },3084 },
2637 .call => try self.airCall(inst, .auto),3085
2638 .call_always_tail => try self.airCall(inst, .always_tail),3086 .cond_br => try cg.airCondBr(inst),
2639 .call_never_tail => try self.airCall(inst, .never_tail),3087 .switch_br => try cg.airSwitchBr(inst),
2640 .call_never_inline => try self.airCall(inst, .never_inline),3088 .loop_switch_br => try cg.airLoopSwitchBr(inst),
26413089 .switch_dispatch => try cg.airSwitchDispatch(inst),
2642 .cond_br => try self.airCondBr(inst),3090 .@"try", .try_cold => try cg.airTry(inst),
2643 .switch_br => try self.airSwitchBr(inst),3091 .try_ptr, .try_ptr_cold => try cg.airTryPtr(inst),
2644 .loop_switch_br => try self.airLoopSwitchBr(inst),3092 .dbg_stmt => if (use_old) try cg.airDbgStmt(inst) else {
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 {
2649 const dbg_stmt = air_datas[@intFromEnum(inst)].dbg_stmt;3093 const dbg_stmt = air_datas[@intFromEnum(inst)].dbg_stmt;
2650 _ = try self.addInst(.{3094 _ = try cg.addInst(.{
2651 .tag = .pseudo,3095 .tag = .pseudo,
2652 .ops = .pseudo_dbg_line_line_column,3096 .ops = .pseudo_dbg_line_line_column,
2653 .data = .{ .line_column = .{3097 .data = .{ .line_column = .{
...@@ -2656,50 +3100,50 @@ fn genBody(self: *CodeGen, body: []const Air.Inst.Index) InnerError!void {...@@ -2656,50 +3100,50 @@ fn genBody(self: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
2656 } },3100 } },
2657 });3101 });
2658 },3102 },
2659 .dbg_empty_stmt => if (use_old) try self.airDbgEmptyStmt() else {3103 .dbg_empty_stmt => if (use_old) try cg.airDbgEmptyStmt() else {
2660 if (self.mir_instructions.len > 0) {3104 if (cg.mir_instructions.len > 0) {
2661 const prev_mir_op = &self.mir_instructions.items(.ops)[self.mir_instructions.len - 1];3105 const prev_mir_op = &cg.mir_instructions.items(.ops)[cg.mir_instructions.len - 1];
2662 if (prev_mir_op.* == .pseudo_dbg_line_stmt_line_column)3106 if (prev_mir_op.* == .pseudo_dbg_line_stmt_line_column)
2663 prev_mir_op.* = .pseudo_dbg_line_line_column;3107 prev_mir_op.* = .pseudo_dbg_line_line_column;
2664 }3108 }
2665 try self.asmOpOnly(.{ ._, .nop });3109 try cg.asmOpOnly(.{ ._, .nop });
2666 },3110 },
2667 .dbg_inline_block => if (use_old) try self.airDbgInlineBlock(inst) else {3111 .dbg_inline_block => if (use_old) try cg.airDbgInlineBlock(inst) else {
2668 const ty_pl = air_datas[@intFromEnum(inst)].ty_pl;3112 const ty_pl = air_datas[@intFromEnum(inst)].ty_pl;
2669 const extra = self.air.extraData(Air.DbgInlineBlock, ty_pl.payload);3113 const extra = cg.air.extraData(Air.DbgInlineBlock, ty_pl.payload);
2670 const old_inline_func = self.inline_func;3114 const old_inline_func = cg.inline_func;
2671 defer self.inline_func = old_inline_func;3115 defer cg.inline_func = old_inline_func;
2672 self.inline_func = extra.data.func;3116 cg.inline_func = extra.data.func;
2673 _ = try self.addInst(.{3117 _ = try cg.addInst(.{
2674 .tag = .pseudo,3118 .tag = .pseudo,
2675 .ops = .pseudo_dbg_enter_inline_func,3119 .ops = .pseudo_dbg_enter_inline_func,
2676 .data = .{ .func = extra.data.func },3120 .data = .{ .func = extra.data.func },
2677 });3121 });
2678 try self.lowerBlock(inst, @ptrCast(self.air.extra[extra.end..][0..extra.data.body_len]));3122 try cg.lowerBlock(inst, @ptrCast(cg.air.extra[extra.end..][0..extra.data.body_len]));
2679 _ = try self.addInst(.{3123 _ = try cg.addInst(.{
2680 .tag = .pseudo,3124 .tag = .pseudo,
2681 .ops = .pseudo_dbg_leave_inline_func,3125 .ops = .pseudo_dbg_leave_inline_func,
2682 .data = .{ .func = old_inline_func },3126 .data = .{ .func = old_inline_func },
2683 });3127 });
2684 },3128 },
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 {
2686 const pl_op = air_datas[@intFromEnum(inst)].pl_op;3130 const pl_op = air_datas[@intFromEnum(inst)].pl_op;
2687 var ops = try self.tempsFromOperands(inst, .{pl_op.operand});3131 var ops = try cg.tempsFromOperands(inst, .{pl_op.operand});
2688 try self.genLocalDebugInfo(inst, ops[0].tracking(self).short);3132 try cg.genLocalDebugInfo(inst, ops[0].tracking(cg).short);
2689 try ops[0].die(self);3133 try ops[0].die(cg);
2690 },3134 },
2691 .is_null_ptr => if (use_old) try self.airIsNullPtr(inst) else {3135 .is_null_ptr => if (use_old) try cg.airIsNullPtr(inst) else {
2692 const un_op = air_datas[@intFromEnum(inst)].un_op;3136 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);
2694 const opt_repr_is_pl = opt_ty.optionalReprIsPayload(zcu);3138 const opt_repr_is_pl = opt_ty.optionalReprIsPayload(zcu);
2695 const opt_child_ty = opt_ty.optionalChild(zcu);3139 const opt_child_ty = opt_ty.optionalChild(zcu);
2696 const opt_child_abi_size: u31 = @intCast(opt_child_ty.abiSize(zcu));3140 const opt_child_abi_size: u31 = @intCast(opt_child_ty.abiSize(zcu));
2697 var ops = try self.tempsFromOperands(inst, .{un_op});3141 var ops = try cg.tempsFromOperands(inst, .{un_op});
2698 if (!opt_repr_is_pl) try ops[0].toOffset(opt_child_abi_size, self);3142 if (!opt_repr_is_pl) try ops[0].toOffset(opt_child_abi_size, cg);
2699 while (try ops[0].toLea(self)) {}3143 while (try ops[0].toLea(cg)) {}
2700 try self.asmMemoryImmediate(3144 try cg.asmMemoryImmediate(
2701 .{ ._, .cmp },3145 .{ ._, .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)
2703 .byte3147 .byte
2704 else if (opt_child_ty.isSlice(zcu))3148 else if (opt_child_ty.isSlice(zcu))
2705 .qword3149 .qword
...@@ -2707,22 +3151,22 @@ fn genBody(self: *CodeGen, body: []const Air.Inst.Index) InnerError!void {...@@ -2707,22 +3151,22 @@ fn genBody(self: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
2707 .fromSize(opt_child_abi_size) }),3151 .fromSize(opt_child_abi_size) }),
2708 .u(0),3152 .u(0),
2709 );3153 );
2710 var is_null = try self.tempFromValue(self.typeOfIndex(inst), .{ .eflags = .e });3154 var is_null = try cg.tempFromValue(cg.typeOfIndex(inst), .{ .eflags = .e });
2711 try ops[0].die(self);3155 try ops[0].die(cg);
2712 try is_null.moveTo(inst, self);3156 try is_null.moveTo(inst, cg);
2713 },3157 },
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 {
2715 const un_op = air_datas[@intFromEnum(inst)].un_op;3159 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);
2717 const opt_repr_is_pl = opt_ty.optionalReprIsPayload(zcu);3161 const opt_repr_is_pl = opt_ty.optionalReprIsPayload(zcu);
2718 const opt_child_ty = opt_ty.optionalChild(zcu);3162 const opt_child_ty = opt_ty.optionalChild(zcu);
2719 const opt_child_abi_size: u31 = @intCast(opt_child_ty.abiSize(zcu));3163 const opt_child_abi_size: u31 = @intCast(opt_child_ty.abiSize(zcu));
2720 var ops = try self.tempsFromOperands(inst, .{un_op});3164 var ops = try cg.tempsFromOperands(inst, .{un_op});
2721 if (!opt_repr_is_pl) try ops[0].toOffset(opt_child_abi_size, self);3165 if (!opt_repr_is_pl) try ops[0].toOffset(opt_child_abi_size, cg);
2722 while (try ops[0].toLea(self)) {}3166 while (try ops[0].toLea(cg)) {}
2723 try self.asmMemoryImmediate(3167 try cg.asmMemoryImmediate(
2724 .{ ._, .cmp },3168 .{ ._, .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)
2726 .byte3170 .byte
2727 else if (opt_child_ty.isSlice(zcu))3171 else if (opt_child_ty.isSlice(zcu))
2728 .qword3172 .qword
...@@ -2730,244 +3174,244 @@ fn genBody(self: *CodeGen, body: []const Air.Inst.Index) InnerError!void {...@@ -2730,244 +3174,244 @@ fn genBody(self: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
2730 .fromSize(opt_child_abi_size) }),3174 .fromSize(opt_child_abi_size) }),
2731 .u(0),3175 .u(0),
2732 );3176 );
2733 var is_non_null = try self.tempFromValue(self.typeOfIndex(inst), .{ .eflags = .ne });3177 var is_non_null = try cg.tempFromValue(cg.typeOfIndex(inst), .{ .eflags = .ne });
2734 try ops[0].die(self);3178 try ops[0].die(cg);
2735 try is_non_null.moveTo(inst, self);3179 try is_non_null.moveTo(inst, cg);
2736 },3180 },
2737 .is_err_ptr => if (use_old) try self.airIsErrPtr(inst) else {3181 .is_err_ptr => if (use_old) try cg.airIsErrPtr(inst) else {
2738 const un_op = air_datas[@intFromEnum(inst)].un_op;3182 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);
2740 const eu_err_ty = eu_ty.errorUnionSet(zcu);3184 const eu_err_ty = eu_ty.errorUnionSet(zcu);
2741 const eu_pl_ty = eu_ty.errorUnionPayload(zcu);3185 const eu_pl_ty = eu_ty.errorUnionPayload(zcu);
2742 const eu_err_off: i32 = @intCast(codegen.errUnionErrorOffset(eu_pl_ty, zcu));3186 const eu_err_off: i32 = @intCast(codegen.errUnionErrorOffset(eu_pl_ty, zcu));
2743 var ops = try self.tempsFromOperands(inst, .{un_op});3187 var ops = try cg.tempsFromOperands(inst, .{un_op});
2744 try ops[0].toOffset(eu_err_off, self);3188 try ops[0].toOffset(eu_err_off, cg);
2745 while (try ops[0].toLea(self)) {}3189 while (try ops[0].toLea(cg)) {}
2746 try self.asmMemoryImmediate(3190 try cg.asmMemoryImmediate(
2747 .{ ._, .cmp },3191 .{ ._, .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) }),
2749 .u(0),3193 .u(0),
2750 );3194 );
2751 var is_err = try self.tempFromValue(self.typeOfIndex(inst), .{ .eflags = .ne });3195 var is_err = try cg.tempFromValue(cg.typeOfIndex(inst), .{ .eflags = .ne });
2752 try ops[0].die(self);3196 try ops[0].die(cg);
2753 try is_err.moveTo(inst, self);3197 try is_err.moveTo(inst, cg);
2754 },3198 },
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 {
2756 const un_op = air_datas[@intFromEnum(inst)].un_op;3200 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);
2758 const eu_err_ty = eu_ty.errorUnionSet(zcu);3202 const eu_err_ty = eu_ty.errorUnionSet(zcu);
2759 const eu_pl_ty = eu_ty.errorUnionPayload(zcu);3203 const eu_pl_ty = eu_ty.errorUnionPayload(zcu);
2760 const eu_err_off: i32 = @intCast(codegen.errUnionErrorOffset(eu_pl_ty, zcu));3204 const eu_err_off: i32 = @intCast(codegen.errUnionErrorOffset(eu_pl_ty, zcu));
2761 var ops = try self.tempsFromOperands(inst, .{un_op});3205 var ops = try cg.tempsFromOperands(inst, .{un_op});
2762 try ops[0].toOffset(eu_err_off, self);3206 try ops[0].toOffset(eu_err_off, cg);
2763 while (try ops[0].toLea(self)) {}3207 while (try ops[0].toLea(cg)) {}
2764 try self.asmMemoryImmediate(3208 try cg.asmMemoryImmediate(
2765 .{ ._, .cmp },3209 .{ ._, .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) }),
2767 .u(0),3211 .u(0),
2768 );3212 );
2769 var is_non_err = try self.tempFromValue(self.typeOfIndex(inst), .{ .eflags = .e });3213 var is_non_err = try cg.tempFromValue(cg.typeOfIndex(inst), .{ .eflags = .e });
2770 try ops[0].die(self);3214 try ops[0].die(cg);
2771 try is_non_err.moveTo(inst, self);3215 try is_non_err.moveTo(inst, cg);
2772 },3216 },
2773 .int_from_ptr => if (use_old) try self.airIntFromPtr(inst) else {3217 .int_from_ptr => if (use_old) try cg.airIntFromPtr(inst) else {
2774 const un_op = air_datas[@intFromEnum(inst)].un_op;3218 const un_op = air_datas[@intFromEnum(inst)].un_op;
2775 var ops = try self.tempsFromOperands(inst, .{un_op});3219 var ops = try cg.tempsFromOperands(inst, .{un_op});
2776 try ops[0].toLimb(0, self);3220 try ops[0].toLimb(0, cg);
2777 try ops[0].moveTo(inst, self);3221 try ops[0].moveTo(inst, cg);
2778 },3222 },
2779 .int_from_bool => if (use_old) try self.airIntFromBool(inst) else {3223 .int_from_bool => if (use_old) try cg.airIntFromBool(inst) else {
2780 const un_op = air_datas[@intFromEnum(inst)].un_op;3224 const un_op = air_datas[@intFromEnum(inst)].un_op;
2781 var ops = try self.tempsFromOperands(inst, .{un_op});3225 var ops = try cg.tempsFromOperands(inst, .{un_op});
2782 try ops[0].moveTo(inst, self);3226 try ops[0].moveTo(inst, cg);
2783 },3227 },
2784 .ret => try self.airRet(inst, false),3228 .ret => try cg.airRet(inst, false),
2785 .ret_safe => try self.airRet(inst, true),3229 .ret_safe => try cg.airRet(inst, true),
2786 .ret_load => try self.airRetLoad(inst),3230 .ret_load => try cg.airRetLoad(inst),
2787 .unreach => {},3231 .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 {
2789 const ty_op = air_datas[@intFromEnum(inst)].ty_op;3233 const ty_op = air_datas[@intFromEnum(inst)].ty_op;
2790 var ops = try self.tempsFromOperands(inst, .{ty_op.operand});3234 var ops = try cg.tempsFromOperands(inst, .{ty_op.operand});
2791 try ops[0].moveTo(inst, self);3235 try ops[0].moveTo(inst, cg);
2792 },3236 },
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 {
2794 const ty_op = air_datas[@intFromEnum(inst)].ty_op;3238 const ty_op = air_datas[@intFromEnum(inst)].ty_op;
2795 const opt_ty = self.typeOf(ty_op.operand).childType(zcu);3239 const opt_ty = cg.typeOf(ty_op.operand).childType(zcu);
2796 var ops = try self.tempsFromOperands(inst, .{ty_op.operand});3240 var ops = try cg.tempsFromOperands(inst, .{ty_op.operand});
2797 if (!opt_ty.optionalReprIsPayload(zcu)) {3241 if (!opt_ty.optionalReprIsPayload(zcu)) {
2798 const opt_child_ty = opt_ty.optionalChild(zcu);3242 const opt_child_ty = opt_ty.optionalChild(zcu);
2799 const opt_child_abi_size: i32 = @intCast(opt_child_ty.abiSize(zcu));3243 const opt_child_abi_size: i32 = @intCast(opt_child_ty.abiSize(zcu));
2800 try ops[0].toOffset(opt_child_abi_size, self);3244 try ops[0].toOffset(opt_child_abi_size, cg);
2801 var has_value = try self.tempFromValue(Type.bool, .{ .immediate = 1 });3245 var has_value = try cg.tempFromValue(Type.bool, .{ .immediate = 1 });
2802 try ops[0].store(&has_value, self);3246 try ops[0].store(&has_value, cg);
2803 try has_value.die(self);3247 try has_value.die(cg);
2804 try ops[0].toOffset(-opt_child_abi_size, self);3248 try ops[0].toOffset(-opt_child_abi_size, cg);
2805 }3249 }
2806 try ops[0].moveTo(inst, self);3250 try ops[0].moveTo(inst, cg);
2807 },3251 },
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 {
2809 const ty_op = air_datas[@intFromEnum(inst)].ty_op;3253 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);
2811 const eu_pl_ty = eu_ty.errorUnionPayload(zcu);3255 const eu_pl_ty = eu_ty.errorUnionPayload(zcu);
2812 const eu_pl_off: i32 = @intCast(codegen.errUnionPayloadOffset(eu_pl_ty, zcu));3256 const eu_pl_off: i32 = @intCast(codegen.errUnionPayloadOffset(eu_pl_ty, zcu));
2813 var ops = try self.tempsFromOperands(inst, .{ty_op.operand});3257 var ops = try cg.tempsFromOperands(inst, .{ty_op.operand});
2814 try ops[0].toOffset(eu_pl_off, self);3258 try ops[0].toOffset(eu_pl_off, cg);
2815 try ops[0].moveTo(inst, self);3259 try ops[0].moveTo(inst, cg);
2816 },3260 },
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 {
2818 const ty_op = air_datas[@intFromEnum(inst)].ty_op;3262 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);
2820 const eu_pl_ty = eu_ty.errorUnionPayload(zcu);3264 const eu_pl_ty = eu_ty.errorUnionPayload(zcu);
2821 const eu_err_off: i32 = @intCast(codegen.errUnionErrorOffset(eu_pl_ty, zcu));3265 const eu_err_off: i32 = @intCast(codegen.errUnionErrorOffset(eu_pl_ty, zcu));
2822 var ops = try self.tempsFromOperands(inst, .{ty_op.operand});3266 var ops = try cg.tempsFromOperands(inst, .{ty_op.operand});
2823 try ops[0].toOffset(eu_err_off, self);3267 try ops[0].toOffset(eu_err_off, cg);
2824 var err = try ops[0].load(eu_ty.errorUnionSet(zcu), self);3268 var err = try ops[0].load(eu_ty.errorUnionSet(zcu), cg);
2825 try ops[0].die(self);3269 try ops[0].die(cg);
2826 try err.moveTo(inst, self);3270 try err.moveTo(inst, cg);
2827 },3271 },
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 {
2829 const ty_op = air_datas[@intFromEnum(inst)].ty_op;3273 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);
2831 const eu_err_ty = eu_ty.errorUnionSet(zcu);3275 const eu_err_ty = eu_ty.errorUnionSet(zcu);
2832 const eu_pl_ty = eu_ty.errorUnionPayload(zcu);3276 const eu_pl_ty = eu_ty.errorUnionPayload(zcu);
2833 const eu_err_off: i32 = @intCast(codegen.errUnionErrorOffset(eu_pl_ty, zcu));3277 const eu_err_off: i32 = @intCast(codegen.errUnionErrorOffset(eu_pl_ty, zcu));
2834 const eu_pl_off: i32 = @intCast(codegen.errUnionPayloadOffset(eu_pl_ty, zcu));3278 const eu_pl_off: i32 = @intCast(codegen.errUnionPayloadOffset(eu_pl_ty, zcu));
2835 var ops = try self.tempsFromOperands(inst, .{ty_op.operand});3279 var ops = try cg.tempsFromOperands(inst, .{ty_op.operand});
2836 try ops[0].toOffset(eu_err_off, self);3280 try ops[0].toOffset(eu_err_off, cg);
2837 var no_err = try self.tempFromValue(eu_err_ty, .{ .immediate = 0 });3281 var no_err = try cg.tempFromValue(eu_err_ty, .{ .immediate = 0 });
2838 try ops[0].store(&no_err, self);3282 try ops[0].store(&no_err, cg);
2839 try no_err.die(self);3283 try no_err.die(cg);
2840 try ops[0].toOffset(eu_pl_off - eu_err_off, self);3284 try ops[0].toOffset(eu_pl_off - eu_err_off, cg);
2841 try ops[0].moveTo(inst, self);3285 try ops[0].moveTo(inst, cg);
2842 },3286 },
2843 .struct_field_ptr => if (use_old) try self.airStructFieldPtr(inst) else {3287 .struct_field_ptr => if (use_old) try cg.airStructFieldPtr(inst) else {
2844 const ty_pl = air_datas[@intFromEnum(inst)].ty_pl;3288 const ty_pl = air_datas[@intFromEnum(inst)].ty_pl;
2845 const extra = self.air.extraData(Air.StructField, ty_pl.payload).data;3289 const extra = cg.air.extraData(Air.StructField, ty_pl.payload).data;
2846 var ops = try self.tempsFromOperands(inst, .{extra.struct_operand});3290 var ops = try cg.tempsFromOperands(inst, .{extra.struct_operand});
2847 try ops[0].toOffset(self.fieldOffset(3291 try ops[0].toOffset(cg.fieldOffset(
2848 self.typeOf(extra.struct_operand),3292 cg.typeOf(extra.struct_operand),
2849 self.typeOfIndex(inst),3293 cg.typeOfIndex(inst),
2850 extra.field_index,3294 extra.field_index,
2851 ), self);3295 ), cg);
2852 try ops[0].moveTo(inst, self);3296 try ops[0].moveTo(inst, cg);
2853 },3297 },
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 {
2855 const ty_op = air_datas[@intFromEnum(inst)].ty_op;3299 const ty_op = air_datas[@intFromEnum(inst)].ty_op;
2856 var ops = try self.tempsFromOperands(inst, .{ty_op.operand});3300 var ops = try cg.tempsFromOperands(inst, .{ty_op.operand});
2857 try ops[0].toOffset(self.fieldOffset(3301 try ops[0].toOffset(cg.fieldOffset(
2858 self.typeOf(ty_op.operand),3302 cg.typeOf(ty_op.operand),
2859 self.typeOfIndex(inst),3303 cg.typeOfIndex(inst),
2860 0,3304 0,
2861 ), self);3305 ), cg);
2862 try ops[0].moveTo(inst, self);3306 try ops[0].moveTo(inst, cg);
2863 },3307 },
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 {
2865 const ty_op = air_datas[@intFromEnum(inst)].ty_op;3309 const ty_op = air_datas[@intFromEnum(inst)].ty_op;
2866 var ops = try self.tempsFromOperands(inst, .{ty_op.operand});3310 var ops = try cg.tempsFromOperands(inst, .{ty_op.operand});
2867 try ops[0].toOffset(self.fieldOffset(3311 try ops[0].toOffset(cg.fieldOffset(
2868 self.typeOf(ty_op.operand),3312 cg.typeOf(ty_op.operand),
2869 self.typeOfIndex(inst),3313 cg.typeOfIndex(inst),
2870 1,3314 1,
2871 ), self);3315 ), cg);
2872 try ops[0].moveTo(inst, self);3316 try ops[0].moveTo(inst, cg);
2873 },3317 },
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 {
2875 const ty_op = air_datas[@intFromEnum(inst)].ty_op;3319 const ty_op = air_datas[@intFromEnum(inst)].ty_op;
2876 var ops = try self.tempsFromOperands(inst, .{ty_op.operand});3320 var ops = try cg.tempsFromOperands(inst, .{ty_op.operand});
2877 try ops[0].toOffset(self.fieldOffset(3321 try ops[0].toOffset(cg.fieldOffset(
2878 self.typeOf(ty_op.operand),3322 cg.typeOf(ty_op.operand),
2879 self.typeOfIndex(inst),3323 cg.typeOfIndex(inst),
2880 2,3324 2,
2881 ), self);3325 ), cg);
2882 try ops[0].moveTo(inst, self);3326 try ops[0].moveTo(inst, cg);
2883 },3327 },
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 {
2885 const ty_op = air_datas[@intFromEnum(inst)].ty_op;3329 const ty_op = air_datas[@intFromEnum(inst)].ty_op;
2886 var ops = try self.tempsFromOperands(inst, .{ty_op.operand});3330 var ops = try cg.tempsFromOperands(inst, .{ty_op.operand});
2887 try ops[0].toOffset(self.fieldOffset(3331 try ops[0].toOffset(cg.fieldOffset(
2888 self.typeOf(ty_op.operand),3332 cg.typeOf(ty_op.operand),
2889 self.typeOfIndex(inst),3333 cg.typeOfIndex(inst),
2890 3,3334 3,
2891 ), self);3335 ), cg);
2892 try ops[0].moveTo(inst, self);3336 try ops[0].moveTo(inst, cg);
2893 },3337 },
2894 .slice => if (use_old) try self.airSlice(inst) else {3338 .slice => if (use_old) try cg.airSlice(inst) else {
2895 const ty_pl = air_datas[@intFromEnum(inst)].ty_pl;3339 const ty_pl = air_datas[@intFromEnum(inst)].ty_pl;
2896 const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data;3340 const bin_op = cg.air.extraData(Air.Bin, ty_pl.payload).data;
2897 var ops = try self.tempsFromOperands(inst, .{ bin_op.lhs, bin_op.rhs });3341 var ops = try cg.tempsFromOperands(inst, .{ bin_op.lhs, bin_op.rhs });
2898 try ops[0].toPair(&ops[1], self);3342 try ops[0].toPair(&ops[1], cg);
2899 try ops[0].moveTo(inst, self);3343 try ops[0].moveTo(inst, cg);
2900 },3344 },
2901 .slice_len => if (use_old) try self.airSliceLen(inst) else {3345 .slice_len => if (use_old) try cg.airSliceLen(inst) else {
2902 const ty_op = air_datas[@intFromEnum(inst)].ty_op;3346 const ty_op = air_datas[@intFromEnum(inst)].ty_op;
2903 var ops = try self.tempsFromOperands(inst, .{ty_op.operand});3347 var ops = try cg.tempsFromOperands(inst, .{ty_op.operand});
2904 try ops[0].toLimb(1, self);3348 try ops[0].toLimb(1, cg);
2905 try ops[0].moveTo(inst, self);3349 try ops[0].moveTo(inst, cg);
2906 },3350 },
2907 .slice_ptr => if (use_old) try self.airSlicePtr(inst) else {3351 .slice_ptr => if (use_old) try cg.airSlicePtr(inst) else {
2908 const ty_op = air_datas[@intFromEnum(inst)].ty_op;3352 const ty_op = air_datas[@intFromEnum(inst)].ty_op;
2909 var ops = try self.tempsFromOperands(inst, .{ty_op.operand});3353 var ops = try cg.tempsFromOperands(inst, .{ty_op.operand});
2910 try ops[0].toLimb(0, self);3354 try ops[0].toLimb(0, cg);
2911 try ops[0].moveTo(inst, self);3355 try ops[0].moveTo(inst, cg);
2912 },3356 },
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 {
2914 const ty_op = air_datas[@intFromEnum(inst)].ty_op;3358 const ty_op = air_datas[@intFromEnum(inst)].ty_op;
2915 var ops = try self.tempsFromOperands(inst, .{ty_op.operand});3359 var ops = try cg.tempsFromOperands(inst, .{ty_op.operand});
2916 try ops[0].toOffset(8, self);3360 try ops[0].toOffset(8, cg);
2917 try ops[0].moveTo(inst, self);3361 try ops[0].moveTo(inst, cg);
2918 },3362 },
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 {
2920 const ty_op = air_datas[@intFromEnum(inst)].ty_op;3364 const ty_op = air_datas[@intFromEnum(inst)].ty_op;
2921 var ops = try self.tempsFromOperands(inst, .{ty_op.operand});3365 var ops = try cg.tempsFromOperands(inst, .{ty_op.operand});
2922 try ops[0].toOffset(0, self);3366 try ops[0].toOffset(0, cg);
2923 try ops[0].moveTo(inst, self);3367 try ops[0].moveTo(inst, cg);
2924 },3368 },
2925 .slice_elem_ptr, .ptr_elem_ptr => |tag| if (use_old) switch (tag) {3369 .slice_elem_ptr, .ptr_elem_ptr => |tag| if (use_old) switch (tag) {
2926 else => unreachable,3370 else => unreachable,
2927 .slice_elem_ptr => try self.airSliceElemPtr(inst),3371 .slice_elem_ptr => try cg.airSliceElemPtr(inst),
2928 .ptr_elem_ptr => try self.airPtrElemPtr(inst),3372 .ptr_elem_ptr => try cg.airPtrElemPtr(inst),
2929 } else {3373 } else {
2930 const ty_pl = air_datas[@intFromEnum(inst)].ty_pl;3374 const ty_pl = air_datas[@intFromEnum(inst)].ty_pl;
2931 const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data;3375 const bin_op = cg.air.extraData(Air.Bin, ty_pl.payload).data;
2932 var ops = try self.tempsFromOperands(inst, .{ bin_op.lhs, bin_op.rhs });3376 var ops = try cg.tempsFromOperands(inst, .{ bin_op.lhs, bin_op.rhs });
2933 switch (tag) {3377 switch (tag) {
2934 else => unreachable,3378 else => unreachable,
2935 .slice_elem_ptr => try ops[0].toLimb(0, self),3379 .slice_elem_ptr => try ops[0].toLimb(0, cg),
2936 .ptr_elem_ptr => {},3380 .ptr_elem_ptr => {},
2937 }3381 }
2938 const dst_ty = self.typeOfIndex(inst);3382 const dst_ty = cg.typeOfIndex(inst);
2939 if (dst_ty.ptrInfo(zcu).flags.vector_index == .none) zero_offset: {3383 if (dst_ty.ptrInfo(zcu).flags.vector_index == .none) zero_offset: {
2940 const elem_size = dst_ty.childType(zcu).abiSize(zcu);3384 const elem_size = dst_ty.childType(zcu).abiSize(zcu);
2941 if (elem_size == 0) break :zero_offset;3385 if (elem_size == 0) break :zero_offset;
2942 while (true) for (&ops) |*op| {3386 while (true) for (&ops) |*op| {
2943 if (try op.toAnyReg(self)) break;3387 if (try op.toAnyReg(cg)) break;
2944 } else break;3388 } else break;
2945 const lhs_reg = ops[0].unwrap(self).temp.tracking(self).short.register.to64();3389 const lhs_reg = ops[0].unwrap(cg).temp.tracking(cg).short.register.to64();
2946 const rhs_reg = ops[1].unwrap(self).temp.tracking(self).short.register.to64();3390 const rhs_reg = ops[1].unwrap(cg).temp.tracking(cg).short.register.to64();
2947 if (!std.math.isPowerOfTwo(elem_size)) {3391 if (!std.math.isPowerOfTwo(elem_size)) {
2948 try self.spillEflagsIfOccupied();3392 try cg.spillEflagsIfOccupied();
2949 try self.asmRegisterRegisterImmediate(3393 try cg.asmRegisterRegisterImmediate(
2950 .{ .i_, .mul },3394 .{ .i_, .mul },
2951 rhs_reg,3395 rhs_reg,
2952 rhs_reg,3396 rhs_reg,
2953 .u(elem_size),3397 .u(elem_size),
2954 );3398 );
2955 try self.asmRegisterMemory(.{ ._, .lea }, lhs_reg, .{3399 try cg.asmRegisterMemory(.{ ._, .lea }, lhs_reg, .{
2956 .base = .{ .reg = lhs_reg },3400 .base = .{ .reg = lhs_reg },
2957 .mod = .{ .rm = .{ .size = .qword, .index = rhs_reg } },3401 .mod = .{ .rm = .{ .size = .qword, .index = rhs_reg } },
2958 });3402 });
2959 } else if (elem_size > 8) {3403 } else if (elem_size > 8) {
2960 try self.spillEflagsIfOccupied();3404 try cg.spillEflagsIfOccupied();
2961 try self.asmRegisterImmediate(3405 try cg.asmRegisterImmediate(
2962 .{ ._l, .sh },3406 .{ ._l, .sh },
2963 rhs_reg,3407 rhs_reg,
2964 .u(std.math.log2_int(u64, elem_size)),3408 .u(std.math.log2_int(u64, elem_size)),
2965 );3409 );
2966 try self.asmRegisterMemory(.{ ._, .lea }, lhs_reg, .{3410 try cg.asmRegisterMemory(.{ ._, .lea }, lhs_reg, .{
2967 .base = .{ .reg = lhs_reg },3411 .base = .{ .reg = lhs_reg },
2968 .mod = .{ .rm = .{ .size = .qword, .index = rhs_reg } },3412 .mod = .{ .rm = .{ .size = .qword, .index = rhs_reg } },
2969 });3413 });
2970 } else try self.asmRegisterMemory(.{ ._, .lea }, lhs_reg, .{3414 } else try cg.asmRegisterMemory(.{ ._, .lea }, lhs_reg, .{
2971 .base = .{ .reg = lhs_reg },3415 .base = .{ .reg = lhs_reg },
2972 .mod = .{ .rm = .{3416 .mod = .{ .rm = .{
2973 .size = .qword,3417 .size = .qword,
...@@ -2976,57 +3420,57 @@ fn genBody(self: *CodeGen, body: []const Air.Inst.Index) InnerError!void {...@@ -2976,57 +3420,57 @@ fn genBody(self: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
2976 } },3420 } },
2977 });3421 });
2978 }3422 }
2979 try ops[1].die(self);3423 try ops[1].die(cg);
2980 try ops[0].moveTo(inst, self);3424 try ops[0].moveTo(inst, cg);
2981 },3425 },
2982 .array_to_slice => if (use_old) try self.airArrayToSlice(inst) else {3426 .array_to_slice => if (use_old) try cg.airArrayToSlice(inst) else {
2983 const ty_op = air_datas[@intFromEnum(inst)].ty_op;3427 const ty_op = air_datas[@intFromEnum(inst)].ty_op;
2984 var ops = try self.tempsFromOperands(inst, .{ty_op.operand});3428 var ops = try cg.tempsFromOperands(inst, .{ty_op.operand});
2985 var len = try self.tempFromValue(Type.usize, .{3429 var len = try cg.tempFromValue(Type.usize, .{
2986 .immediate = self.typeOf(ty_op.operand).childType(zcu).arrayLen(zcu),3430 .immediate = cg.typeOf(ty_op.operand).childType(zcu).arrayLen(zcu),
2987 });3431 });
2988 try ops[0].toPair(&len, self);3432 try ops[0].toPair(&len, cg);
2989 try ops[0].moveTo(inst, self);3433 try ops[0].moveTo(inst, cg);
2990 },3434 },
2991 .error_set_has_value => return self.fail("TODO implement error_set_has_value", .{}),3435 .error_set_has_value => return cg.fail("TODO implement error_set_has_value", .{}),
2992 .field_parent_ptr => if (use_old) try self.airFieldParentPtr(inst) else {3436 .field_parent_ptr => if (use_old) try cg.airFieldParentPtr(inst) else {
2993 const ty_pl = air_datas[@intFromEnum(inst)].ty_pl;3437 const ty_pl = air_datas[@intFromEnum(inst)].ty_pl;
2994 const extra = self.air.extraData(Air.FieldParentPtr, ty_pl.payload).data;3438 const extra = cg.air.extraData(Air.FieldParentPtr, ty_pl.payload).data;
2995 var ops = try self.tempsFromOperands(inst, .{extra.field_ptr});3439 var ops = try cg.tempsFromOperands(inst, .{extra.field_ptr});
2996 try ops[0].toOffset(-self.fieldOffset(3440 try ops[0].toOffset(-cg.fieldOffset(
2997 self.typeOfIndex(inst),3441 cg.typeOfIndex(inst),
2998 self.typeOf(extra.field_ptr),3442 cg.typeOf(extra.field_ptr),
2999 extra.field_index,3443 extra.field_index,
3000 ), self);3444 ), cg);
3001 try ops[0].moveTo(inst, self);3445 try ops[0].moveTo(inst, cg);
3002 },3446 },
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
3006 .wasm_memory_size => unreachable,3450 .wasm_memory_size => unreachable,
3007 .wasm_memory_grow => unreachable,3451 .wasm_memory_grow => unreachable,
30083452
3009 .addrspace_cast => {3453 .addrspace_cast => {
3010 const ty_op = air_datas[@intFromEnum(inst)].ty_op;3454 const ty_op = air_datas[@intFromEnum(inst)].ty_op;
3011 var ops = try self.tempsFromOperands(inst, .{ty_op.operand});3455 var ops = try cg.tempsFromOperands(inst, .{ty_op.operand});
3012 try ops[0].moveTo(inst, self);3456 try ops[0].moveTo(inst, cg);
3013 },3457 },
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),3461 .c_va_arg => try cg.airVaArg(inst),
3018 .c_va_copy => try self.airVaCopy(inst),3462 .c_va_copy => try cg.airVaCopy(inst),
3019 .c_va_end => try self.airVaEnd(inst),3463 .c_va_end => try cg.airVaEnd(inst),
3020 .c_va_start => try self.airVaStart(inst),3464 .c_va_start => try cg.airVaStart(inst),
30213465
3022 .work_item_id => unreachable,3466 .work_item_id => unreachable,
3023 .work_group_size => unreachable,3467 .work_group_size => unreachable,
3024 .work_group_id => unreachable,3468 .work_group_id => unreachable,
3025 }3469 }
3026 self.resetTemps();3470 cg.resetTemps();
3027 self.checkInvariantsAfterAirInst();3471 cg.checkInvariantsAfterAirInst();
3028 }3472 }
3029 verbose_tracking_log.debug("{}", .{self.fmtTracking()});3473 verbose_tracking_log.debug("{}", .{cg.fmtTracking()});
3030}3474}
30313475
3032fn genLazy(self: *CodeGen, lazy_sym: link.File.LazySymbol) InnerError!void {3476fn genLazy(self: *CodeGen, lazy_sym: link.File.LazySymbol) InnerError!void {
...@@ -3117,12 +3561,16 @@ fn freeReg(self: *CodeGen, reg: Register) !void {...@@ -3117,12 +3561,16 @@ fn freeReg(self: *CodeGen, reg: Register) !void {
3117fn freeValue(self: *CodeGen, value: MCValue) !void {3561fn freeValue(self: *CodeGen, value: MCValue) !void {
3118 switch (value) {3562 switch (value) {
3119 .register => |reg| try self.freeReg(reg),3563 .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),
3121 .register_offset, .indirect => |reg_off| try self.freeReg(reg_off.reg),3568 .register_offset, .indirect => |reg_off| try self.freeReg(reg_off.reg),
3122 .register_overflow => |reg_ov| {3569 .register_overflow => |reg_ov| {
3123 try self.freeReg(reg_ov.reg);3570 try self.freeReg(reg_ov.reg);
3124 self.eflags_inst = null;3571 self.eflags_inst = null;
3125 },3572 },
3573 .register_mask => |reg_mask| try self.freeReg(reg_mask.reg),
3126 .eflags => self.eflags_inst = null,3574 .eflags => self.eflags_inst = null,
3127 else => {}, // TODO process stack allocation death3575 else => {}, // TODO process stack allocation death
3128 }3576 }
...@@ -3323,11 +3771,11 @@ fn allocRegOrMemAdvanced(self: *CodeGen, ty: Type, inst: ?Air.Inst.Index, reg_ok...@@ -3323,11 +3771,11 @@ fn allocRegOrMemAdvanced(self: *CodeGen, ty: Type, inst: ?Air.Inst.Index, reg_ok
3323 },3771 },
3324 .vector => switch (ty.childType(zcu).zigTypeTag(zcu)) {3772 .vector => switch (ty.childType(zcu).zigTypeTag(zcu)) {
3325 .float => switch (ty.childType(zcu).floatBits(self.target.*)) {3773 .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),
3327 80 => break :need_mem,3775 80 => break :need_mem,
3328 else => unreachable,3776 else => unreachable,
3329 },3777 },
3330 else => if (self.hasFeature(.avx)) 32 else 16,3778 else => self.vectorSize(.int),
3331 },3779 },
3332 else => 8,3780 else => 8,
3333 })) {3781 })) {
...@@ -3374,6 +3822,28 @@ fn regSetForType(self: *CodeGen, ty: Type) RegisterManager.RegisterBitSet {...@@ -3374,6 +3822,28 @@ fn regSetForType(self: *CodeGen, ty: Type) RegisterManager.RegisterBitSet {
3374 return regSetForRegClass(self.regClassForType(ty));3822 return regSetForRegClass(self.regClassForType(ty));
3375}3823}
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
3377const State = struct {3847const State = struct {
3378 registers: RegisterManager.TrackedRegisters,3848 registers: RegisterManager.TrackedRegisters,
3379 reg_tracking: [RegisterManager.RegisterBitSet.bit_length]InstTracking,3849 reg_tracking: [RegisterManager.RegisterBitSet.bit_length]InstTracking,
...@@ -3639,7 +4109,7 @@ fn airFptrunc(self: *CodeGen, inst: Air.Inst.Index) !void {...@@ -3639,7 +4109,7 @@ fn airFptrunc(self: *CodeGen, inst: Air.Inst.Index) !void {
3639 }4109 }
3640 } else {4110 } else {
3641 assert(src_bits == 64 and dst_bits == 32);4111 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(
3643 .{ .v_ss, .cvtsd2 },4113 .{ .v_ss, .cvtsd2 },
3644 dst_reg,4114 dst_reg,
3645 dst_reg,4115 dst_reg,
...@@ -3652,7 +4122,7 @@ fn airFptrunc(self: *CodeGen, inst: Air.Inst.Index) !void {...@@ -3652,7 +4122,7 @@ fn airFptrunc(self: *CodeGen, inst: Air.Inst.Index) !void {
3652 src_mcv.getReg().?4122 src_mcv.getReg().?
3653 else4123 else
3654 try self.copyToTmpRegister(src_ty, src_mcv)).to128(),4124 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(
3656 .{ ._ss, .cvtsd2 },4126 .{ ._ss, .cvtsd2 },
3657 dst_reg,4127 dst_reg,
3658 try src_mcv.mem(self, .{ .size = .qword }),4128 try src_mcv.mem(self, .{ .size = .qword }),
...@@ -3751,7 +4221,7 @@ fn airFpext(self: *CodeGen, inst: Air.Inst.Index) !void {...@@ -3751,7 +4221,7 @@ fn airFpext(self: *CodeGen, inst: Air.Inst.Index) !void {
3751 } else {4221 } else {
3752 assert(src_bits == 32 and dst_bits == 64);4222 assert(src_bits == 32 and dst_bits == 64);
3753 if (self.hasFeature(.avx)) switch (vec_len) {4223 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(
3755 .{ .v_sd, .cvtss2 },4225 .{ .v_sd, .cvtss2 },
3756 dst_alias,4226 dst_alias,
3757 dst_alias,4227 dst_alias,
...@@ -3765,7 +4235,7 @@ fn airFpext(self: *CodeGen, inst: Air.Inst.Index) !void {...@@ -3765,7 +4235,7 @@ fn airFpext(self: *CodeGen, inst: Air.Inst.Index) !void {
3765 else4235 else
3766 try self.copyToTmpRegister(src_ty, src_mcv), src_abi_size),4236 try self.copyToTmpRegister(src_ty, src_mcv), src_abi_size),
3767 ),4237 ),
3768 2...4 => if (src_mcv.isMemory()) try self.asmRegisterMemory(4238 2...4 => if (src_mcv.isBase()) try self.asmRegisterMemory(
3769 .{ .v_pd, .cvtps2 },4239 .{ .v_pd, .cvtps2 },
3770 dst_alias,4240 dst_alias,
3771 try src_mcv.mem(self, .{ .size = self.memSize(src_ty) }),4241 try src_mcv.mem(self, .{ .size = self.memSize(src_ty) }),
...@@ -3778,7 +4248,7 @@ fn airFpext(self: *CodeGen, inst: Air.Inst.Index) !void {...@@ -3778,7 +4248,7 @@ fn airFpext(self: *CodeGen, inst: Air.Inst.Index) !void {
3778 try self.copyToTmpRegister(src_ty, src_mcv), src_abi_size),4248 try self.copyToTmpRegister(src_ty, src_mcv), src_abi_size),
3779 ),4249 ),
3780 else => break :result null,4250 else => break :result null,
3781 } else if (src_mcv.isMemory()) try self.asmRegisterMemory(4251 } else if (src_mcv.isBase()) try self.asmRegisterMemory(
3782 switch (vec_len) {4252 switch (vec_len) {
3783 1 => .{ ._sd, .cvtss2 },4253 1 => .{ ._sd, .cvtss2 },
3784 2 => .{ ._pd, .cvtps2 },4254 2 => .{ ._pd, .cvtps2 },
...@@ -3827,7 +4297,7 @@ fn airIntCast(self: *CodeGen, inst: Air.Inst.Index) !void {...@@ -3827,7 +4297,7 @@ fn airIntCast(self: *CodeGen, inst: Air.Inst.Index) !void {
3827 if (dst_ty.isVector(zcu)) {4297 if (dst_ty.isVector(zcu)) {
3828 const src_abi_size: u32 = @intCast(src_ty.abiSize(zcu));4298 const src_abi_size: u32 = @intCast(src_ty.abiSize(zcu));
3829 const max_abi_size = @max(dst_abi_size, src_abi_size);4299 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;
3831 const has_avx = self.hasFeature(.avx);4301 const has_avx = self.hasFeature(.avx);
38324302
3833 const dst_elem_abi_size = dst_ty.childType(zcu).abiSize(zcu);4303 const dst_elem_abi_size = dst_ty.childType(zcu).abiSize(zcu);
...@@ -3919,7 +4389,7 @@ fn airIntCast(self: *CodeGen, inst: Air.Inst.Index) !void {...@@ -3919,7 +4389,7 @@ fn airIntCast(self: *CodeGen, inst: Air.Inst.Index) !void {
3919 const dst_reg = dst_mcv.getReg().?;4389 const dst_reg = dst_mcv.getReg().?;
3920 const dst_alias = registerAlias(dst_reg, dst_abi_size);4390 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(
3923 mir_tag,4393 mir_tag,
3924 dst_alias,4394 dst_alias,
3925 try src_mcv.mem(self, .{ .size = self.memSize(src_ty) }),4395 try src_mcv.mem(self, .{ .size = self.memSize(src_ty) }),
...@@ -4017,7 +4487,7 @@ fn airIntCast(self: *CodeGen, inst: Air.Inst.Index) !void {...@@ -4017,7 +4487,7 @@ fn airIntCast(self: *CodeGen, inst: Air.Inst.Index) !void {
4017 const src_limbs_len = std.math.divCeil(u16, src_int_info.bits, 64) catch unreachable;4487 const src_limbs_len = std.math.divCeil(u16, src_int_info.bits, 64) catch unreachable;
4018 const dst_limbs_len = std.math.divCeil(u16, dst_int_info.bits, 64) catch unreachable;4488 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())
4021 dst_mcv.address().offset((src_limbs_len - 1) * 8).deref()4491 dst_mcv.address().offset((src_limbs_len - 1) * 8).deref()
4022 else4492 else
4023 .{ .register = dst_mcv.register_pair[1] };4493 .{ .register = dst_mcv.register_pair[1] };
...@@ -4392,7 +4862,7 @@ fn airMulDivBinOp(self: *CodeGen, inst: Air.Inst.Index) !void {...@@ -4392,7 +4862,7 @@ fn airMulDivBinOp(self: *CodeGen, inst: Air.Inst.Index) !void {
4392 else => null,4862 else => null,
4393 };4863 };
4394 defer if (mat_lhs_lock) |lock| self.register_manager.unlockReg(lock);4864 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(
4396 .{ ._, .mov },4866 .{ ._, .mov },
4397 tmp_reg,4867 tmp_reg,
4398 try mat_lhs_mcv.address().offset(8).deref().mem(self, .{ .size = .qword }),4868 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 {...@@ -4416,7 +4886,7 @@ fn airMulDivBinOp(self: *CodeGen, inst: Air.Inst.Index) !void {
4416 else => null,4886 else => null,
4417 };4887 };
4418 defer if (mat_rhs_lock) |lock| self.register_manager.unlockReg(lock);4888 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(
4420 .{ ._, .xor },4890 .{ ._, .xor },
4421 tmp_reg,4891 tmp_reg,
4422 try mat_rhs_mcv.address().offset(8).deref().mem(self, .{ .size = .qword }),4892 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 {...@@ -4518,7 +4988,7 @@ fn airMulDivBinOp(self: *CodeGen, inst: Air.Inst.Index) !void {
45184988
4519 for (tmp_regs, dst_regs) |tmp_reg, dst_reg|4989 for (tmp_regs, dst_regs) |tmp_reg, dst_reg|
4520 try self.asmRegisterRegister(.{ ._, .mov }, tmp_reg, dst_reg);4990 try self.asmRegisterRegister(.{ ._, .mov }, tmp_reg, dst_reg);
4521 if (mat_rhs_mcv.isMemory()) {4991 if (mat_rhs_mcv.isBase()) {
4522 try self.asmRegisterMemory(4992 try self.asmRegisterMemory(
4523 .{ ._, .add },4993 .{ ._, .add },
4524 tmp_regs[0],4994 tmp_regs[0],
...@@ -4793,7 +5263,7 @@ fn airMulSat(self: *CodeGen, inst: Air.Inst.Index) !void {...@@ -4793,7 +5263,7 @@ fn airMulSat(self: *CodeGen, inst: Air.Inst.Index) !void {
4793 else => null,5263 else => null,
4794 };5264 };
4795 defer if (mat_lhs_lock) |lock| self.register_manager.unlockReg(lock);5265 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(
4797 .{ ._, .mov },5267 .{ ._, .mov },
4798 tmp_reg,5268 tmp_reg,
4799 try mat_lhs_mcv.address().offset(8).deref().mem(self, .{ .size = .qword }),5269 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 {...@@ -4817,7 +5287,7 @@ fn airMulSat(self: *CodeGen, inst: Air.Inst.Index) !void {
4817 else => null,5287 else => null,
4818 };5288 };
4819 defer if (mat_rhs_lock) |lock| self.register_manager.unlockReg(lock);5289 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(
4821 .{ ._, .xor },5291 .{ ._, .xor },
4822 tmp_reg,5292 tmp_reg,
4823 try mat_rhs_mcv.address().offset(8).deref().mem(self, .{ .size = .qword }),5293 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 {...@@ -5348,7 +5818,7 @@ fn airMulWithOverflow(self: *CodeGen, inst: Air.Inst.Index) !void {
5348 };5818 };
5349 defer if (mat_rhs_lock) |lock| self.register_manager.unlockReg(lock);5819 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(
5352 .{ ._, .mov },5822 .{ ._, .mov },
5353 .rax,5823 .rax,
5354 try mat_lhs_mcv.mem(self, .{ .size = .qword }),5824 try mat_lhs_mcv.mem(self, .{ .size = .qword }),
...@@ -5357,7 +5827,7 @@ fn airMulWithOverflow(self: *CodeGen, inst: Air.Inst.Index) !void {...@@ -5357,7 +5827,7 @@ fn airMulWithOverflow(self: *CodeGen, inst: Air.Inst.Index) !void {
5357 .rax,5827 .rax,
5358 mat_lhs_mcv.register_pair[0],5828 mat_lhs_mcv.register_pair[0],
5359 );5829 );
5360 if (mat_rhs_mcv.isMemory()) try self.asmRegisterMemory(5830 if (mat_rhs_mcv.isBase()) try self.asmRegisterMemory(
5361 .{ ._, .mov },5831 .{ ._, .mov },
5362 tmp_regs[0],5832 tmp_regs[0],
5363 try mat_rhs_mcv.address().offset(8).deref().mem(self, .{ .size = .qword }),5833 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 {...@@ -5370,14 +5840,14 @@ fn airMulWithOverflow(self: *CodeGen, inst: Air.Inst.Index) !void {
5370 try self.asmSetccRegister(.nz, tmp_regs[1].to8());5840 try self.asmSetccRegister(.nz, tmp_regs[1].to8());
5371 try self.asmRegisterRegister(.{ .i_, .mul }, tmp_regs[0], .rax);5841 try self.asmRegisterRegister(.{ .i_, .mul }, tmp_regs[0], .rax);
5372 try self.asmSetccRegister(.o, tmp_regs[2].to8());5842 try self.asmSetccRegister(.o, tmp_regs[2].to8());
5373 if (mat_rhs_mcv.isMemory())5843 if (mat_rhs_mcv.isBase())
5374 try self.asmMemory(.{ ._, .mul }, try mat_rhs_mcv.mem(self, .{ .size = .qword }))5844 try self.asmMemory(.{ ._, .mul }, try mat_rhs_mcv.mem(self, .{ .size = .qword }))
5375 else5845 else
5376 try self.asmRegister(.{ ._, .mul }, mat_rhs_mcv.register_pair[0]);5846 try self.asmRegister(.{ ._, .mul }, mat_rhs_mcv.register_pair[0]);
5377 try self.asmRegisterRegister(.{ ._, .add }, .rdx, tmp_regs[0]);5847 try self.asmRegisterRegister(.{ ._, .add }, .rdx, tmp_regs[0]);
5378 try self.asmSetccRegister(.c, tmp_regs[3].to8());5848 try self.asmSetccRegister(.c, tmp_regs[3].to8());
5379 try self.asmRegisterRegister(.{ ._, .@"or" }, tmp_regs[2].to8(), tmp_regs[3].to8());5849 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(
5381 .{ ._, .mov },5851 .{ ._, .mov },
5382 tmp_regs[0],5852 tmp_regs[0],
5383 try mat_lhs_mcv.address().offset(8).deref().mem(self, .{ .size = .qword }),5853 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 {...@@ -5394,7 +5864,7 @@ fn airMulWithOverflow(self: *CodeGen, inst: Air.Inst.Index) !void {
5394 tmp_regs[3].to8(),5864 tmp_regs[3].to8(),
5395 );5865 );
5396 try self.asmRegisterRegister(.{ ._, .@"or" }, tmp_regs[1].to8(), tmp_regs[2].to8());5866 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(
5398 .{ .i_, .mul },5868 .{ .i_, .mul },
5399 tmp_regs[0],5869 tmp_regs[0],
5400 try mat_rhs_mcv.mem(self, .{ .size = .qword }),5870 try mat_rhs_mcv.mem(self, .{ .size = .qword }),
...@@ -6512,7 +6982,7 @@ fn airArrayElemVal(self: *CodeGen, inst: Air.Inst.Index) !void {...@@ -6512,7 +6982,7 @@ fn airArrayElemVal(self: *CodeGen, inst: Air.Inst.Index) !void {
65126982
6513 const index_ty = self.typeOf(bin_op.rhs);6983 const index_ty = self.typeOf(bin_op.rhs);
6514 const index_mcv = try self.resolveInst(bin_op.rhs);6984 const index_mcv = try self.resolveInst(bin_op.rhs);
6515 const index_lock: ?RegisterLock = switch (index_mcv) {6985 const index_lock = switch (index_mcv) {
6516 .register => |reg| self.register_manager.lockRegAssumeUnused(reg),6986 .register => |reg| self.register_manager.lockRegAssumeUnused(reg),
6517 else => null,6987 else => null,
6518 };6988 };
...@@ -6520,48 +6990,102 @@ fn airArrayElemVal(self: *CodeGen, inst: Air.Inst.Index) !void {...@@ -6520,48 +6990,102 @@ fn airArrayElemVal(self: *CodeGen, inst: Air.Inst.Index) !void {
65206990
6521 try self.spillEflagsIfOccupied();6991 try self.spillEflagsIfOccupied();
6522 if (array_ty.isVector(zcu) and elem_ty.bitSize(zcu) == 1) {6992 if (array_ty.isVector(zcu) and elem_ty.bitSize(zcu) == 1) {
6523 const index_reg = switch (index_mcv) {6993 const array_mat_mcv: MCValue = switch (array_mcv) {
6524 .register => |reg| reg,6994 else => array_mcv,
6525 else => try self.copyToTmpRegister(index_ty, index_mcv),6995 .register_mask => .{ .register = try self.copyToTmpRegister(array_ty, array_mcv) },
6526 };6996 };
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) {
6528 .register => |array_reg| switch (array_reg.class()) {7004 .register => |array_reg| switch (array_reg.class()) {
6529 .general_purpose => try self.asmRegisterRegister(7005 .general_purpose => switch (index_mcv) {
6530 .{ ._, .bt },7006 .immediate => |index_imm| try self.asmRegisterImmediate(
6531 array_reg.to64(),7007 .{ ._, .bt },
6532 index_reg.to64(),7008 array_reg.to64(),
6533 ),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 },
6534 .sse => {7020 .sse => {
6535 const frame_index = try self.allocFrameIndex(.initType(array_ty, zcu));7021 const frame_index = try self.allocFrameIndex(.initType(array_ty, zcu));
6536 try self.genSetMem(.{ .frame = frame_index }, 0, array_ty, array_mcv, .{});7022 try self.genSetMem(.{ .frame = frame_index }, 0, array_ty, array_mat_mcv, .{});
6537 try self.asmMemoryRegister(7023 switch (index_mcv) {
6538 .{ ._, .bt },7024 .immediate => |index_imm| try self.asmMemoryImmediate(
6539 .{7025 .{ ._, .bt },
6540 .base = .{ .frame = frame_index },7026 .{
6541 .mod = .{ .rm = .{ .size = .qword } },7027 .base = .{ .frame = frame_index },
6542 },7028 .mod = .{ .rm = .{ .size = .qword } },
6543 index_reg.to64(),7029 },
6544 );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 }
6545 },7044 },
6546 else => unreachable,7045 else => unreachable,
6547 },7046 },
6548 .load_frame => try self.asmMemoryRegister(7047 .load_frame => switch (index_mcv) {
6549 .{ ._, .bt },7048 .immediate => |index_imm| try self.asmMemoryImmediate(
6550 try array_mcv.mem(self, .{ .size = .qword }),7049 .{ ._, .bt },
6551 index_reg.to64(),7050 try array_mat_mcv.mem(self, .{ .size = .qword }),
6552 ),7051 .u(index_imm),
6553 .memory, .load_symbol, .load_direct, .load_got, .load_tlv => try self.asmMemoryRegister(7052 ),
6554 .{ ._, .bt },7053 else => try self.asmMemoryRegister(
6555 .{7054 .{ ._, .bt },
6556 .base = .{7055 try array_mat_mcv.mem(self, .{ .size = .qword }),
6557 .reg = try self.copyToTmpRegister(Type.usize, array_mcv.address()),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 } },
6558 },7070 },
6559 .mod = .{ .rm = .{ .size = .qword } },7071 .u(index_imm),
6560 },7072 ),
6561 index_reg.to64(),7073 else => try self.asmMemoryRegister(
6562 ),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 },
6563 else => return self.fail("TODO airArrayElemVal for {s} of {}", .{7087 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),
6565 }),7089 }),
6566 }7090 }
65677091
...@@ -6856,6 +7380,15 @@ fn airClz(self: *CodeGen, inst: Air.Inst.Index) !void {...@@ -6856,6 +7380,15 @@ fn airClz(self: *CodeGen, inst: Air.Inst.Index) !void {
6856 const src_bits: u31 = @intCast(src_ty.bitSize(zcu));7380 const src_bits: u31 = @intCast(src_ty.bitSize(zcu));
6857 const has_lzcnt = self.hasFeature(.lzcnt);7381 const has_lzcnt = self.hasFeature(.lzcnt);
6858 if (src_bits > @as(u32, if (has_lzcnt) 128 else 64)) {7382 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
6859 const limbs_len = std.math.divCeil(u32, abi_size, 8) catch unreachable;7392 const limbs_len = std.math.divCeil(u32, abi_size, 8) catch unreachable;
6860 const extra_bits = abi_size * 8 - src_bits;7393 const extra_bits = abi_size * 8 - src_bits;
68617394
...@@ -6881,22 +7414,22 @@ fn airClz(self: *CodeGen, inst: Air.Inst.Index) !void {...@@ -6881,22 +7414,22 @@ fn airClz(self: *CodeGen, inst: Air.Inst.Index) !void {
6881 try self.asmRegister(.{ ._, .dec }, index_reg.to32());7414 try self.asmRegister(.{ ._, .dec }, index_reg.to32());
6882 }7415 }
6883 try self.asmMemoryImmediate(.{ ._, .cmp }, .{7416 try self.asmMemoryImmediate(.{ ._, .cmp }, .{
6884 .base = .{ .frame = src_mcv.load_frame.index },7417 .base = .{ .frame = src_frame_addr.index },
6885 .mod = .{ .rm = .{7418 .mod = .{ .rm = .{
6886 .size = .qword,7419 .size = .qword,
6887 .index = index_reg.to64(),7420 .index = index_reg.to64(),
6888 .scale = .@"8",7421 .scale = .@"8",
6889 .disp = src_mcv.load_frame.off,7422 .disp = src_frame_addr.off,
6890 } },7423 } },
6891 }, .u(0));7424 }, .u(0));
6892 _ = try self.asmJccReloc(.e, loop);7425 _ = try self.asmJccReloc(.e, loop);
6893 try self.asmRegisterMemory(.{ ._, .bsr }, dst_reg.to64(), .{7426 try self.asmRegisterMemory(.{ ._, .bsr }, dst_reg.to64(), .{
6894 .base = .{ .frame = src_mcv.load_frame.index },7427 .base = .{ .frame = src_frame_addr.index },
6895 .mod = .{ .rm = .{7428 .mod = .{ .rm = .{
6896 .size = .qword,7429 .size = .qword,
6897 .index = index_reg.to64(),7430 .index = index_reg.to64(),
6898 .scale = .@"8",7431 .scale = .@"8",
6899 .disp = src_mcv.load_frame.off,7432 .disp = src_frame_addr.off,
6900 } },7433 } },
6901 });7434 });
6902 self.performReloc(zero);7435 self.performReloc(zero);
...@@ -6935,7 +7468,7 @@ fn airClz(self: *CodeGen, inst: Air.Inst.Index) !void {...@@ -6935,7 +7468,7 @@ fn airClz(self: *CodeGen, inst: Air.Inst.Index) !void {
6935 .{ ._, .lzcnt },7468 .{ ._, .lzcnt },
6936 Type.u64,7469 Type.u64,
6937 dst_mcv,7470 dst_mcv,
6938 if (mat_src_mcv.isMemory())7471 if (mat_src_mcv.isBase())
6939 mat_src_mcv7472 mat_src_mcv
6940 else7473 else
6941 .{ .register = mat_src_mcv.register_pair[0] },7474 .{ .register = mat_src_mcv.register_pair[0] },
...@@ -6945,7 +7478,7 @@ fn airClz(self: *CodeGen, inst: Air.Inst.Index) !void {...@@ -6945,7 +7478,7 @@ fn airClz(self: *CodeGen, inst: Air.Inst.Index) !void {
6945 .{ ._, .lzcnt },7478 .{ ._, .lzcnt },
6946 Type.u64,7479 Type.u64,
6947 tmp_mcv,7480 tmp_mcv,
6948 if (mat_src_mcv.isMemory())7481 if (mat_src_mcv.isBase())
6949 mat_src_mcv.address().offset(8).deref()7482 mat_src_mcv.address().offset(8).deref()
6950 else7483 else
6951 .{ .register = mat_src_mcv.register_pair[1] },7484 .{ .register = mat_src_mcv.register_pair[1] },
...@@ -7053,6 +7586,15 @@ fn airCtz(self: *CodeGen, inst: Air.Inst.Index) !void {...@@ -7053,6 +7586,15 @@ fn airCtz(self: *CodeGen, inst: Air.Inst.Index) !void {
7053 const src_bits: u31 = @intCast(src_ty.bitSize(zcu));7586 const src_bits: u31 = @intCast(src_ty.bitSize(zcu));
7054 const has_bmi = self.hasFeature(.bmi);7587 const has_bmi = self.hasFeature(.bmi);
7055 if (src_bits > @as(u32, if (has_bmi) 128 else 64)) {7588 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
7056 const limbs_len = std.math.divCeil(u32, abi_size, 8) catch unreachable;7598 const limbs_len = std.math.divCeil(u32, abi_size, 8) catch unreachable;
7057 const extra_bits = abi_size * 8 - src_bits;7599 const extra_bits = abi_size * 8 - src_bits;
70587600
...@@ -7079,22 +7621,22 @@ fn airCtz(self: *CodeGen, inst: Air.Inst.Index) !void {...@@ -7079,22 +7621,22 @@ fn airCtz(self: *CodeGen, inst: Air.Inst.Index) !void {
7079 try self.asmRegisterImmediate(.{ ._, .cmp }, index_reg.to32(), .u(limbs_len));7621 try self.asmRegisterImmediate(.{ ._, .cmp }, index_reg.to32(), .u(limbs_len));
7080 const zero = try self.asmJccReloc(.nb, undefined);7622 const zero = try self.asmJccReloc(.nb, undefined);
7081 try self.asmMemoryImmediate(.{ ._, .cmp }, .{7623 try self.asmMemoryImmediate(.{ ._, .cmp }, .{
7082 .base = .{ .frame = src_mcv.load_frame.index },7624 .base = .{ .frame = src_frame_addr.index },
7083 .mod = .{ .rm = .{7625 .mod = .{ .rm = .{
7084 .size = .qword,7626 .size = .qword,
7085 .index = index_reg.to64(),7627 .index = index_reg.to64(),
7086 .scale = .@"8",7628 .scale = .@"8",
7087 .disp = src_mcv.load_frame.off,7629 .disp = src_frame_addr.off,
7088 } },7630 } },
7089 }, .u(0));7631 }, .u(0));
7090 _ = try self.asmJccReloc(.e, loop);7632 _ = try self.asmJccReloc(.e, loop);
7091 try self.asmRegisterMemory(.{ ._, .bsf }, dst_reg.to64(), .{7633 try self.asmRegisterMemory(.{ ._, .bsf }, dst_reg.to64(), .{
7092 .base = .{ .frame = src_mcv.load_frame.index },7634 .base = .{ .frame = src_frame_addr.index },
7093 .mod = .{ .rm = .{7635 .mod = .{ .rm = .{
7094 .size = .qword,7636 .size = .qword,
7095 .index = index_reg.to64(),7637 .index = index_reg.to64(),
7096 .scale = .@"8",7638 .scale = .@"8",
7097 .disp = src_mcv.load_frame.off,7639 .disp = src_frame_addr.off,
7098 } },7640 } },
7099 });7641 });
7100 self.performReloc(zero);7642 self.performReloc(zero);
...@@ -7131,11 +7673,11 @@ fn airCtz(self: *CodeGen, inst: Air.Inst.Index) !void {...@@ -7131,11 +7673,11 @@ fn airCtz(self: *CodeGen, inst: Air.Inst.Index) !void {
7131 const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);7673 const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);
7132 defer self.register_manager.unlockReg(tmp_lock);7674 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())
7135 mat_src_mcv7677 mat_src_mcv
7136 else7678 else
7137 .{ .register = mat_src_mcv.register_pair[0] };7679 .{ .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())
7139 mat_src_mcv.address().offset(8).deref()7681 mat_src_mcv.address().offset(8).deref()
7140 else7682 else
7141 .{ .register = mat_src_mcv.register_pair[1] };7683 .{ .register = mat_src_mcv.register_pair[1] };
...@@ -7224,13 +7766,13 @@ fn airPopCount(self: *CodeGen, inst: Air.Inst.Index) !void {...@@ -7224,13 +7766,13 @@ fn airPopCount(self: *CodeGen, inst: Air.Inst.Index) !void {
7224 const tmp_locks = self.register_manager.lockRegsAssumeUnused(2, tmp_regs);7766 const tmp_locks = self.register_manager.lockRegsAssumeUnused(2, tmp_regs);
7225 defer for (tmp_locks) |lock| self.register_manager.unlockReg(lock);7767 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())
7228 mat_src_mcv7770 mat_src_mcv
7229 else7771 else
7230 .{ .register = mat_src_mcv.register_pair[0] }, false);7772 .{ .register = mat_src_mcv.register_pair[0] }, false);
7231 const src_info = src_ty.intInfo(zcu);7773 const src_info = src_ty.intInfo(zcu);
7232 const hi_ty = try pt.intType(src_info.signedness, (src_info.bits - 1) % 64 + 1);7774 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())
7234 mat_src_mcv.address().offset(8).deref()7776 mat_src_mcv.address().offset(8).deref()
7235 else7777 else
7236 .{ .register = mat_src_mcv.register_pair[1] }, false);7778 .{ .register = mat_src_mcv.register_pair[1] }, false);
...@@ -7388,7 +7930,7 @@ fn genByteSwap(...@@ -7388,7 +7930,7 @@ fn genByteSwap(
7388 defer for (dst_locks) |lock| self.register_manager.unlockReg(lock);7930 defer for (dst_locks) |lock| self.register_manager.unlockReg(lock);
73897931
7390 for (dst_regs, 0..) |dst_reg, limb_index| {7932 for (dst_regs, 0..) |dst_reg, limb_index| {
7391 if (src_mcv.isMemory()) {7933 if (src_mcv.isBase()) {
7392 try self.asmRegisterMemory(7934 try self.asmRegisterMemory(
7393 .{ ._, if (has_movbe) .movbe else .mov },7935 .{ ._, if (has_movbe) .movbe else .mov },
7394 dst_reg.to64(),7936 dst_reg.to64(),
...@@ -7706,7 +8248,7 @@ fn floatSign(self: *CodeGen, inst: Air.Inst.Index, operand: Air.Inst.Ref, ty: Ty...@@ -7706,7 +8248,7 @@ fn floatSign(self: *CodeGen, inst: Air.Inst.Index, operand: Air.Inst.Ref, ty: Ty
7706 .abs => try vec_ty.maxInt(pt, vec_ty),8248 .abs => try vec_ty.maxInt(pt, vec_ty),
7707 else => unreachable,8249 else => unreachable,
7708 });8250 });
7709 const sign_mem: Memory = if (sign_mcv.isMemory())8251 const sign_mem: Memory = if (sign_mcv.isBase())
7710 try sign_mcv.mem(self, .{ .size = .fromSize(abi_size) })8252 try sign_mcv.mem(self, .{ .size = .fromSize(abi_size) })
7711 else8253 else
7712 .{8254 .{
...@@ -7888,7 +8430,7 @@ fn genRound(self: *CodeGen, ty: Type, dst_reg: Register, src_mcv: MCValue, mode:...@@ -7888,7 +8430,7 @@ fn genRound(self: *CodeGen, ty: Type, dst_reg: Register, src_mcv: MCValue, mode:
7888 const abi_size: u32 = @intCast(ty.abiSize(pt.zcu));8430 const abi_size: u32 = @intCast(ty.abiSize(pt.zcu));
7889 const dst_alias = registerAlias(dst_reg, abi_size);8431 const dst_alias = registerAlias(dst_reg, abi_size);
7890 switch (mir_tag[0]) {8432 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(
7892 mir_tag,8434 mir_tag,
7893 dst_alias,8435 dst_alias,
7894 dst_alias,8436 dst_alias,
...@@ -7904,7 +8446,7 @@ fn genRound(self: *CodeGen, ty: Type, dst_reg: Register, src_mcv: MCValue, mode:...@@ -7904,7 +8446,7 @@ fn genRound(self: *CodeGen, ty: Type, dst_reg: Register, src_mcv: MCValue, mode:
7904 try self.copyToTmpRegister(ty, src_mcv), abi_size),8446 try self.copyToTmpRegister(ty, src_mcv), abi_size),
7905 .u(@as(u5, @bitCast(mode))),8447 .u(@as(u5, @bitCast(mode))),
7906 ),8448 ),
7907 else => if (src_mcv.isMemory()) try self.asmRegisterMemoryImmediate(8449 else => if (src_mcv.isBase()) try self.asmRegisterMemoryImmediate(
7908 mir_tag,8450 mir_tag,
7909 dst_alias,8451 dst_alias,
7910 try src_mcv.mem(self, .{ .size = .fromSize(abi_size) }),8452 try src_mcv.mem(self, .{ .size = .fromSize(abi_size) }),
...@@ -8105,7 +8647,7 @@ fn airAbs(self: *CodeGen, inst: Air.Inst.Index) !void {...@@ -8105,7 +8647,7 @@ fn airAbs(self: *CodeGen, inst: Air.Inst.Index) !void {
8105 else8647 else
8106 try self.register_manager.allocReg(inst, self.regSetForType(ty));8648 try self.register_manager.allocReg(inst, self.regSetForType(ty));
8107 const dst_alias = registerAlias(dst_reg, abi_size);8649 const dst_alias = registerAlias(dst_reg, abi_size);
8108 if (src_mcv.isMemory()) try self.asmRegisterMemory(8650 if (src_mcv.isBase()) try self.asmRegisterMemory(
8109 mir_tag,8651 mir_tag,
8110 dst_alias,8652 dst_alias,
8111 try src_mcv.mem(self, .{ .size = self.memSize(ty) }),8653 try src_mcv.mem(self, .{ .size = self.memSize(ty) }),
...@@ -8212,7 +8754,7 @@ fn airSqrt(self: *CodeGen, inst: Air.Inst.Index) !void {...@@ -8212,7 +8754,7 @@ fn airSqrt(self: *CodeGen, inst: Air.Inst.Index) !void {
8212 },8754 },
8213 2...8 => {8755 2...8 => {
8214 const wide_reg = registerAlias(dst_reg, abi_size * 2);8756 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(
8216 .{ .v_ps, .cvtph2 },8758 .{ .v_ps, .cvtph2 },
8217 wide_reg,8759 wide_reg,
8218 try src_mcv.mem(self, .{ .size = .fromSize(8760 try src_mcv.mem(self, .{ .size = .fromSize(
...@@ -8257,7 +8799,7 @@ fn airSqrt(self: *CodeGen, inst: Air.Inst.Index) !void {...@@ -8257,7 +8799,7 @@ fn airSqrt(self: *CodeGen, inst: Air.Inst.Index) !void {
8257 else => unreachable,8799 else => unreachable,
8258 }) orelse return self.fail("TODO implement airSqrt for {}", .{ty.fmt(pt)});8800 }) orelse return self.fail("TODO implement airSqrt for {}", .{ty.fmt(pt)});
8259 switch (mir_tag[0]) {8801 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(
8261 mir_tag,8803 mir_tag,
8262 dst_reg,8804 dst_reg,
8263 dst_reg,8805 dst_reg,
...@@ -8271,7 +8813,7 @@ fn airSqrt(self: *CodeGen, inst: Air.Inst.Index) !void {...@@ -8271,7 +8813,7 @@ fn airSqrt(self: *CodeGen, inst: Air.Inst.Index) !void {
8271 else8813 else
8272 try self.copyToTmpRegister(ty, src_mcv), abi_size),8814 try self.copyToTmpRegister(ty, src_mcv), abi_size),
8273 ),8815 ),
8274 else => if (src_mcv.isMemory()) try self.asmRegisterMemory(8816 else => if (src_mcv.isBase()) try self.asmRegisterMemory(
8275 mir_tag,8817 mir_tag,
8276 dst_reg,8818 dst_reg,
8277 try src_mcv.mem(self, .{ .size = .fromSize(abi_size) }),8819 try src_mcv.mem(self, .{ .size = .fromSize(abi_size) }),
...@@ -8339,7 +8881,7 @@ fn reuseOperandAdvanced(...@@ -8339,7 +8881,7 @@ fn reuseOperandAdvanced(
8339 return false;8881 return false;
83408882
8341 switch (mcv) {8883 switch (mcv) {
8342 .register, .register_pair, .register_overflow => for (mcv.getRegs()) |reg| {8884 .register, .register_pair, .register_overflow, .register_mask => for (mcv.getRegs()) |reg| {
8343 // If it's in the registers table, need to associate the register(s) with the8885 // If it's in the registers table, need to associate the register(s) with the
8344 // new instruction.8886 // new instruction.
8345 if (maybe_tracked_inst) |tracked_inst| {8887 if (maybe_tracked_inst) |tracked_inst| {
...@@ -8486,7 +9028,10 @@ fn load(self: *CodeGen, dst_mcv: MCValue, ptr_ty: Type, ptr_mcv: MCValue) InnerE...@@ -8486,7 +9028,10 @@ fn load(self: *CodeGen, dst_mcv: MCValue, ptr_ty: Type, ptr_mcv: MCValue) InnerE
8486 .undef,9028 .undef,
8487 .eflags,9029 .eflags,
8488 .register_pair,9030 .register_pair,
9031 .register_triple,
9032 .register_quadruple,
8489 .register_overflow,9033 .register_overflow,
9034 .register_mask,
8490 .elementwise_regs_then_frame,9035 .elementwise_regs_then_frame,
8491 .reserved_frame,9036 .reserved_frame,
8492 => unreachable, // not a valid pointer9037 => unreachable, // not a valid pointer
...@@ -8694,7 +9239,10 @@ fn store(...@@ -8694,7 +9239,10 @@ fn store(
8694 .undef,9239 .undef,
8695 .eflags,9240 .eflags,
8696 .register_pair,9241 .register_pair,
9242 .register_triple,
9243 .register_quadruple,
8697 .register_overflow,9244 .register_overflow,
9245 .register_mask,
8698 .elementwise_regs_then_frame,9246 .elementwise_regs_then_frame,
8699 .reserved_frame,9247 .reserved_frame,
8700 => unreachable, // not a valid pointer9248 => unreachable, // not a valid pointer
...@@ -8986,7 +9534,7 @@ fn airStructFieldVal(self: *CodeGen, inst: Air.Inst.Index) !void {...@@ -8986,7 +9534,7 @@ fn airStructFieldVal(self: *CodeGen, inst: Air.Inst.Index) !void {
8986 try self.genCopy(field_ty, dst_mcv, off_mcv, .{});9534 try self.genCopy(field_ty, dst_mcv, off_mcv, .{});
8987 break :dst dst_mcv;9535 break :dst dst_mcv;
8988 };9536 };
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()) {
8990 const tmp_reg = try self.register_manager.allocReg(null, abi.RegisterClass.gp);9538 const tmp_reg = try self.register_manager.allocReg(null, abi.RegisterClass.gp);
8991 const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);9539 const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);
8992 defer self.register_manager.unlockReg(tmp_lock);9540 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:...@@ -9194,6 +9742,7 @@ fn genUnOpMir(self: *CodeGen, mir_tag: Mir.Inst.FixedTag, dst_ty: Type, dst_mcv:
9194 .register_offset,9742 .register_offset,
9195 .eflags,9743 .eflags,
9196 .register_overflow,9744 .register_overflow,
9745 .register_mask,
9197 .lea_symbol,9746 .lea_symbol,
9198 .lea_direct,9747 .lea_direct,
9199 .lea_got,9748 .lea_got,
...@@ -9204,7 +9753,7 @@ fn genUnOpMir(self: *CodeGen, mir_tag: Mir.Inst.FixedTag, dst_ty: Type, dst_mcv:...@@ -9204,7 +9753,7 @@ fn genUnOpMir(self: *CodeGen, mir_tag: Mir.Inst.FixedTag, dst_ty: Type, dst_mcv:
9204 .air_ref,9753 .air_ref,
9205 => unreachable, // unmodifiable destination9754 => unreachable, // unmodifiable destination
9206 .register => |dst_reg| try self.asmRegister(mir_tag, registerAlias(dst_reg, abi_size)),9755 .register => |dst_reg| try self.asmRegister(mir_tag, registerAlias(dst_reg, abi_size)),
9207 .register_pair => unreachable, // unimplemented9756 .register_pair, .register_triple, .register_quadruple => unreachable, // unimplemented
9208 .memory, .load_symbol, .load_got, .load_direct, .load_tlv => {9757 .memory, .load_symbol, .load_got, .load_direct, .load_tlv => {
9209 const addr_reg = try self.register_manager.allocReg(null, abi.RegisterClass.gp);9758 const addr_reg = try self.register_manager.allocReg(null, abi.RegisterClass.gp);
9210 const addr_reg_lock = self.register_manager.lockRegAssumeUnused(addr_reg);9759 const addr_reg_lock = self.register_manager.lockRegAssumeUnused(addr_reg);
...@@ -9974,27 +10523,27 @@ fn genMulDivBinOp(...@@ -9974,27 +10523,27 @@ fn genMulDivBinOp(
9974 const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);10523 const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);
9975 defer self.register_manager.unlockReg(tmp_lock);10524 defer self.register_manager.unlockReg(tmp_lock);
997610525
9977 if (mat_lhs_mcv.isMemory())10526 if (mat_lhs_mcv.isBase())
9978 try self.asmRegisterMemory(.{ ._, .mov }, .rax, try mat_lhs_mcv.mem(self, .{ .size = .qword }))10527 try self.asmRegisterMemory(.{ ._, .mov }, .rax, try mat_lhs_mcv.mem(self, .{ .size = .qword }))
9979 else10528 else
9980 try self.asmRegisterRegister(.{ ._, .mov }, .rax, mat_lhs_mcv.register_pair[0]);10529 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(
9982 .{ ._, .mov },10531 .{ ._, .mov },
9983 tmp_reg,10532 tmp_reg,
9984 try mat_rhs_mcv.address().offset(8).deref().mem(self, .{ .size = .qword }),10533 try mat_rhs_mcv.address().offset(8).deref().mem(self, .{ .size = .qword }),
9985 ) else try self.asmRegisterRegister(.{ ._, .mov }, tmp_reg, mat_rhs_mcv.register_pair[1]);10534 ) else try self.asmRegisterRegister(.{ ._, .mov }, tmp_reg, mat_rhs_mcv.register_pair[1]);
9986 try self.asmRegisterRegister(.{ .i_, .mul }, tmp_reg, .rax);10535 try self.asmRegisterRegister(.{ .i_, .mul }, tmp_reg, .rax);
9987 if (mat_rhs_mcv.isMemory())10536 if (mat_rhs_mcv.isBase())
9988 try self.asmMemory(.{ ._, .mul }, try mat_rhs_mcv.mem(self, .{ .size = .qword }))10537 try self.asmMemory(.{ ._, .mul }, try mat_rhs_mcv.mem(self, .{ .size = .qword }))
9989 else10538 else
9990 try self.asmRegister(.{ ._, .mul }, mat_rhs_mcv.register_pair[0]);10539 try self.asmRegister(.{ ._, .mul }, mat_rhs_mcv.register_pair[0]);
9991 try self.asmRegisterRegister(.{ ._, .add }, .rdx, tmp_reg);10540 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(
9993 .{ ._, .mov },10542 .{ ._, .mov },
9994 tmp_reg,10543 tmp_reg,
9995 try mat_lhs_mcv.address().offset(8).deref().mem(self, .{ .size = .qword }),10544 try mat_lhs_mcv.address().offset(8).deref().mem(self, .{ .size = .qword }),
9996 ) else try self.asmRegisterRegister(.{ ._, .mov }, tmp_reg, mat_lhs_mcv.register_pair[1]);10545 ) 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())
9998 try self.asmRegisterMemory(.{ .i_, .mul }, tmp_reg, try mat_rhs_mcv.mem(self, .{ .size = .qword }))10547 try self.asmRegisterMemory(.{ .i_, .mul }, tmp_reg, try mat_rhs_mcv.mem(self, .{ .size = .qword }))
9999 else10548 else
10000 try self.asmRegisterRegister(.{ .i_, .mul }, tmp_reg, mat_rhs_mcv.register_pair[0]);10549 try self.asmRegisterRegister(.{ .i_, .mul }, tmp_reg, mat_rhs_mcv.register_pair[0]);
...@@ -10414,7 +10963,7 @@ fn genBinOp(...@@ -10414,7 +10963,7 @@ fn genBinOp(
10414 const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);10963 const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);
10415 defer self.register_manager.unlockReg(tmp_lock);10964 defer self.register_manager.unlockReg(tmp_lock);
1041610965
10417 if (rhs_mcv.isMemory()) try self.asmRegisterRegisterMemoryImmediate(10966 if (rhs_mcv.isBase()) try self.asmRegisterRegisterMemoryImmediate(
10418 .{ .vp_w, .insr },10967 .{ .vp_w, .insr },
10419 dst_reg,10968 dst_reg,
10420 dst_reg,10969 dst_reg,
...@@ -10439,7 +10988,7 @@ fn genBinOp(...@@ -10439,7 +10988,7 @@ fn genBinOp(
10439 64 => .{ .v_sd, .add },10988 64 => .{ .v_sd, .add },
10440 else => unreachable,10989 else => unreachable,
10441 };10990 };
10442 if (src_mcv.isMemory()) try self.asmRegisterRegisterMemory(10991 if (src_mcv.isBase()) try self.asmRegisterRegisterMemory(
10443 mir_tag,10992 mir_tag,
10444 dst_reg,10993 dst_reg,
10445 dst_reg,10994 dst_reg,
...@@ -10459,7 +11008,7 @@ fn genBinOp(...@@ -10459,7 +11008,7 @@ fn genBinOp(
10459 64 => .{ ._sd, .add },11008 64 => .{ ._sd, .add },
10460 else => unreachable,11009 else => unreachable,
10461 };11010 };
10462 if (src_mcv.isMemory()) try self.asmRegisterMemory(11011 if (src_mcv.isBase()) try self.asmRegisterMemory(
10463 mir_tag,11012 mir_tag,
10464 dst_reg,11013 dst_reg,
10465 try src_mcv.mem(self, .{ .size = .fromBitSize(float_bits) }),11014 try src_mcv.mem(self, .{ .size = .fromBitSize(float_bits) }),
...@@ -10514,7 +11063,7 @@ fn genBinOp(...@@ -10514,7 +11063,7 @@ fn genBinOp(
10514 };11063 };
10515 if (sse_op and ((lhs_ty.scalarType(zcu).isRuntimeFloat() and11064 if (sse_op and ((lhs_ty.scalarType(zcu).isRuntimeFloat() and
10516 lhs_ty.scalarType(zcu).floatBits(self.target.*) == 80) or11065 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)))
10518 return self.fail("TODO implement genBinOp for {s} {}", .{ @tagName(air_tag), lhs_ty.fmt(pt) });11067 return self.fail("TODO implement genBinOp for {s} {}", .{ @tagName(air_tag), lhs_ty.fmt(pt) });
1051911068
10520 const maybe_mask_reg = switch (air_tag) {11069 const maybe_mask_reg = switch (air_tag) {
...@@ -10731,7 +11280,7 @@ fn genBinOp(...@@ -10731,7 +11280,7 @@ fn genBinOp(
10731 };11280 };
1073211281
10733 try self.asmRegisterRegister(.{ ._, .mov }, tmp_reg, dst_regs[1]);11282 try self.asmRegisterRegister(.{ ._, .mov }, tmp_reg, dst_regs[1]);
10734 if (src_mcv.isMemory()) {11283 if (src_mcv.isBase()) {
10735 try self.asmRegisterMemory(11284 try self.asmRegisterMemory(
10736 .{ ._, .cmp },11285 .{ ._, .cmp },
10737 dst_regs[0],11286 dst_regs[0],
...@@ -10828,8 +11377,11 @@ fn genBinOp(...@@ -10828,8 +11377,11 @@ fn genBinOp(
10828 .immediate,11377 .immediate,
10829 .eflags,11378 .eflags,
10830 .register_pair,11379 .register_pair,
11380 .register_triple,
11381 .register_quadruple,
10831 .register_offset,11382 .register_offset,
10832 .register_overflow,11383 .register_overflow,
11384 .register_mask,
10833 .load_symbol,11385 .load_symbol,
10834 .lea_symbol,11386 .lea_symbol,
10835 .load_direct,11387 .load_direct,
...@@ -10909,7 +11461,7 @@ fn genBinOp(...@@ -10909,7 +11461,7 @@ fn genBinOp(
10909 const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);11461 const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);
10910 defer self.register_manager.unlockReg(tmp_lock);11462 defer self.register_manager.unlockReg(tmp_lock);
1091111463
10912 if (src_mcv.isMemory()) try self.asmRegisterRegisterMemoryImmediate(11464 if (src_mcv.isBase()) try self.asmRegisterRegisterMemoryImmediate(
10913 .{ .vp_w, .insr },11465 .{ .vp_w, .insr },
10914 dst_reg,11466 dst_reg,
10915 dst_reg,11467 dst_reg,
...@@ -11355,7 +11907,7 @@ fn genBinOp(...@@ -11355,7 +11907,7 @@ fn genBinOp(
11355 const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);11907 const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);
11356 defer self.register_manager.unlockReg(tmp_lock);11908 defer self.register_manager.unlockReg(tmp_lock);
1135711909
11358 if (src_mcv.isMemory()) try self.asmRegisterRegisterMemoryImmediate(11910 if (src_mcv.isBase()) try self.asmRegisterRegisterMemoryImmediate(
11359 .{ .vp_w, .insr },11911 .{ .vp_w, .insr },
11360 dst_reg,11912 dst_reg,
11361 dst_reg,11913 dst_reg,
...@@ -11402,7 +11954,7 @@ fn genBinOp(...@@ -11402,7 +11954,7 @@ fn genBinOp(
11402 const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);11954 const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);
11403 defer self.register_manager.unlockReg(tmp_lock);11955 defer self.register_manager.unlockReg(tmp_lock);
1140411956
11405 if (src_mcv.isMemory()) try self.asmRegisterMemoryImmediate(11957 if (src_mcv.isBase()) try self.asmRegisterMemoryImmediate(
11406 .{ .vp_d, .insr },11958 .{ .vp_d, .insr },
11407 dst_reg,11959 dst_reg,
11408 try src_mcv.mem(self, .{ .size = .dword }),11960 try src_mcv.mem(self, .{ .size = .dword }),
...@@ -11454,7 +12006,7 @@ fn genBinOp(...@@ -11454,7 +12006,7 @@ fn genBinOp(
11454 defer self.register_manager.unlockReg(tmp_lock);12006 defer self.register_manager.unlockReg(tmp_lock);
1145512007
11456 try self.asmRegisterRegister(.{ .v_ps, .cvtph2 }, dst_reg, dst_reg);12008 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(
11458 .{ .v_ps, .cvtph2 },12010 .{ .v_ps, .cvtph2 },
11459 tmp_reg,12011 tmp_reg,
11460 try src_mcv.mem(self, .{ .size = .qword }),12012 try src_mcv.mem(self, .{ .size = .qword }),
...@@ -11497,7 +12049,7 @@ fn genBinOp(...@@ -11497,7 +12049,7 @@ fn genBinOp(
11497 defer self.register_manager.unlockReg(tmp_lock);12049 defer self.register_manager.unlockReg(tmp_lock);
1149812050
11499 try self.asmRegisterRegister(.{ .v_ps, .cvtph2 }, dst_reg.to256(), dst_reg);12051 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(
11501 .{ .v_ps, .cvtph2 },12053 .{ .v_ps, .cvtph2 },
11502 tmp_reg,12054 tmp_reg,
11503 try src_mcv.mem(self, .{ .size = .xword }),12055 try src_mcv.mem(self, .{ .size = .xword }),
...@@ -11659,7 +12211,7 @@ fn genBinOp(...@@ -11659,7 +12211,7 @@ fn genBinOp(
11659 else => if (self.hasFeature(.avx)) {12211 else => if (self.hasFeature(.avx)) {
11660 const lhs_reg =12212 const lhs_reg =
11661 if (copied_to_dst) dst_reg else registerAlias(lhs_mcv.getReg().?, abi_size);12213 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(
11663 mir_tag,12215 mir_tag,
11664 dst_reg,12216 dst_reg,
11665 lhs_reg,12217 lhs_reg,
...@@ -11678,7 +12230,7 @@ fn genBinOp(...@@ -11678,7 +12230,7 @@ fn genBinOp(
11678 );12230 );
11679 } else {12231 } else {
11680 assert(copied_to_dst);12232 assert(copied_to_dst);
11681 if (src_mcv.isMemory()) try self.asmRegisterMemory(12233 if (src_mcv.isBase()) try self.asmRegisterMemory(
11682 mir_tag,12234 mir_tag,
11683 dst_reg,12235 dst_reg,
11684 try src_mcv.mem(self, .{ .size = switch (lhs_ty.zigTypeTag(zcu)) {12236 try src_mcv.mem(self, .{ .size = switch (lhs_ty.zigTypeTag(zcu)) {
...@@ -11705,7 +12257,7 @@ fn genBinOp(...@@ -11705,7 +12257,7 @@ fn genBinOp(
11705 if (self.hasFeature(.avx)) {12257 if (self.hasFeature(.avx)) {
11706 const lhs_reg =12258 const lhs_reg =
11707 if (copied_to_dst) dst_reg else registerAlias(lhs_mcv.getReg().?, abi_size);12259 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(
11709 mir_tag,12261 mir_tag,
11710 dst_reg,12262 dst_reg,
11711 lhs_reg,12263 lhs_reg,
...@@ -11726,7 +12278,7 @@ fn genBinOp(...@@ -11726,7 +12278,7 @@ fn genBinOp(
11726 );12278 );
11727 } else {12279 } else {
11728 assert(copied_to_dst);12280 assert(copied_to_dst);
11729 if (src_mcv.isMemory()) try self.asmRegisterMemoryImmediate(12281 if (src_mcv.isBase()) try self.asmRegisterMemoryImmediate(
11730 mir_tag,12282 mir_tag,
11731 dst_reg,12283 dst_reg,
11732 try src_mcv.mem(self, .{ .size = switch (lhs_ty.zigTypeTag(zcu)) {12284 try src_mcv.mem(self, .{ .size = switch (lhs_ty.zigTypeTag(zcu)) {
...@@ -11937,7 +12489,7 @@ fn genBinOp(...@@ -11937,7 +12489,7 @@ fn genBinOp(
11937 => {12489 => {
11938 const unsigned_ty = try lhs_ty.toUnsigned(pt);12490 const unsigned_ty = try lhs_ty.toUnsigned(pt);
11939 const not_mcv = try self.genTypedValue(try unsigned_ty.maxInt(pt, unsigned_ty));12491 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())
11941 try not_mcv.mem(self, .{ .size = .fromSize(abi_size) })12493 try not_mcv.mem(self, .{ .size = .fromSize(abi_size) })
11942 else12494 else
11943 .{ .base = .{12495 .{ .base = .{
...@@ -12017,6 +12569,7 @@ fn genBinOpMir(...@@ -12017,6 +12569,7 @@ fn genBinOpMir(
12017 .immediate,12569 .immediate,
12018 .eflags,12570 .eflags,
12019 .register_overflow,12571 .register_overflow,
12572 .register_mask,
12020 .lea_direct,12573 .lea_direct,
12021 .lea_got,12574 .lea_got,
12022 .lea_tlv,12575 .lea_tlv,
...@@ -12026,9 +12579,9 @@ fn genBinOpMir(...@@ -12026,9 +12579,9 @@ fn genBinOpMir(
12026 .reserved_frame,12579 .reserved_frame,
12027 .air_ref,12580 .air_ref,
12028 => unreachable, // unmodifiable destination12581 => unreachable, // unmodifiable destination
12029 .register, .register_pair, .register_offset => {12582 .register, .register_pair, .register_triple, .register_quadruple, .register_offset => {
12030 switch (dst_mcv) {12583 switch (dst_mcv) {
12031 .register, .register_pair => {},12584 .register, .register_pair, .register_triple, .register_quadruple => {},
12032 .register_offset => |ro| assert(ro.off == 0),12585 .register_offset => |ro| assert(ro.off == 0),
12033 else => unreachable,12586 else => unreachable,
12034 }12587 }
...@@ -12057,10 +12610,15 @@ fn genBinOpMir(...@@ -12057,10 +12610,15 @@ fn genBinOpMir(
12057 .dead,12610 .dead,
12058 .undef,12611 .undef,
12059 .register_overflow,12612 .register_overflow,
12613 .register_mask,
12060 .elementwise_regs_then_frame,12614 .elementwise_regs_then_frame,
12061 .reserved_frame,12615 .reserved_frame,
12062 => unreachable,12616 => unreachable,
12063 .register, .register_pair => try self.asmRegisterRegister(12617 .register,
12618 .register_pair,
12619 .register_triple,
12620 .register_quadruple,
12621 => try self.asmRegisterRegister(
12064 mir_limb_tag,12622 mir_limb_tag,
12065 dst_alias,12623 dst_alias,
12066 registerAlias(src_mcv.getRegs()[dst_reg_i], limb_abi_size),12624 registerAlias(src_mcv.getRegs()[dst_reg_i], limb_abi_size),
...@@ -12216,6 +12774,7 @@ fn genBinOpMir(...@@ -12216,6 +12774,7 @@ fn genBinOpMir(
12216 .dead,12774 .dead,
12217 .undef,12775 .undef,
12218 .register_overflow,12776 .register_overflow,
12777 .register_mask,
12219 .elementwise_regs_then_frame,12778 .elementwise_regs_then_frame,
12220 .reserved_frame,12779 .reserved_frame,
12221 .air_ref,12780 .air_ref,
...@@ -12224,6 +12783,8 @@ fn genBinOpMir(...@@ -12224,6 +12783,8 @@ fn genBinOpMir(
12224 .eflags,12783 .eflags,
12225 .register,12784 .register,
12226 .register_pair,12785 .register_pair,
12786 .register_triple,
12787 .register_quadruple,
12227 .register_offset,12788 .register_offset,
12228 .indirect,12789 .indirect,
12229 .lea_direct,12790 .lea_direct,
...@@ -12311,6 +12872,7 @@ fn genBinOpMir(...@@ -12311,6 +12872,7 @@ fn genBinOpMir(
12311 .dead,12872 .dead,
12312 .undef,12873 .undef,
12313 .register_overflow,12874 .register_overflow,
12875 .register_mask,
12314 .elementwise_regs_then_frame,12876 .elementwise_regs_then_frame,
12315 .reserved_frame,12877 .reserved_frame,
12316 .air_ref,12878 .air_ref,
...@@ -12364,6 +12926,8 @@ fn genBinOpMir(...@@ -12364,6 +12926,8 @@ fn genBinOpMir(
12364 },12926 },
12365 .register,12927 .register,
12366 .register_pair,12928 .register_pair,
12929 .register_triple,
12930 .register_quadruple,
12367 .register_offset,12931 .register_offset,
12368 .eflags,12932 .eflags,
12369 .memory,12933 .memory,
...@@ -12382,7 +12946,7 @@ fn genBinOpMir(...@@ -12382,7 +12946,7 @@ fn genBinOpMir(
12382 const src_limb_mcv: MCValue = if (src_info) |info| .{12946 const src_limb_mcv: MCValue = if (src_info) |info| .{
12383 .indirect = .{ .reg = info.addr_reg, .off = off },12947 .indirect = .{ .reg = info.addr_reg, .off = off },
12384 } else switch (resolved_src_mcv) {12948 } else switch (resolved_src_mcv) {
12385 .register, .register_pair => .{12949 .register, .register_pair, .register_triple, .register_quadruple => .{
12386 .register = resolved_src_mcv.getRegs()[limb_i],12950 .register = resolved_src_mcv.getRegs()[limb_i],
12387 },12951 },
12388 .eflags,12952 .eflags,
...@@ -12438,6 +13002,7 @@ fn genIntMulComplexOpMir(self: *CodeGen, dst_ty: Type, dst_mcv: MCValue, src_mcv...@@ -12438,6 +13002,7 @@ fn genIntMulComplexOpMir(self: *CodeGen, dst_ty: Type, dst_mcv: MCValue, src_mcv
12438 .eflags,13002 .eflags,
12439 .register_offset,13003 .register_offset,
12440 .register_overflow,13004 .register_overflow,
13005 .register_mask,
12441 .lea_symbol,13006 .lea_symbol,
12442 .lea_direct,13007 .lea_direct,
12443 .lea_got,13008 .lea_got,
...@@ -12462,7 +13027,10 @@ fn genIntMulComplexOpMir(self: *CodeGen, dst_ty: Type, dst_mcv: MCValue, src_mcv...@@ -12462,7 +13027,10 @@ fn genIntMulComplexOpMir(self: *CodeGen, dst_ty: Type, dst_mcv: MCValue, src_mcv
12462 .dead,13027 .dead,
12463 .undef,13028 .undef,
12464 .register_pair,13029 .register_pair,
13030 .register_triple,
13031 .register_quadruple,
12465 .register_overflow,13032 .register_overflow,
13033 .register_mask,
12466 .elementwise_regs_then_frame,13034 .elementwise_regs_then_frame,
12467 .reserved_frame,13035 .reserved_frame,
12468 .air_ref,13036 .air_ref,
...@@ -12539,7 +13107,7 @@ fn genIntMulComplexOpMir(self: *CodeGen, dst_ty: Type, dst_mcv: MCValue, src_mcv...@@ -12539,7 +13107,7 @@ fn genIntMulComplexOpMir(self: *CodeGen, dst_ty: Type, dst_mcv: MCValue, src_mcv
12539 ),13107 ),
12540 }13108 }
12541 },13109 },
12542 .register_pair => unreachable, // unimplemented13110 .register_pair, .register_triple, .register_quadruple => unreachable, // unimplemented
12543 .memory, .indirect, .load_symbol, .load_direct, .load_got, .load_tlv, .load_frame => {13111 .memory, .indirect, .load_symbol, .load_direct, .load_got, .load_tlv, .load_frame => {
12544 const tmp_reg = try self.copyToTmpRegister(dst_ty, dst_mcv);13112 const tmp_reg = try self.copyToTmpRegister(dst_ty, dst_mcv);
12545 const tmp_mcv = MCValue{ .register = tmp_reg };13113 const tmp_mcv = MCValue{ .register = tmp_reg };
...@@ -12892,7 +13460,7 @@ fn genCall(self: *CodeGen, info: union(enum) {...@@ -12892,7 +13460,7 @@ fn genCall(self: *CodeGen, info: union(enum) {
12892 const index_lock = self.register_manager.lockRegAssumeUnused(index_reg);13460 const index_lock = self.register_manager.lockRegAssumeUnused(index_reg);
12893 defer self.register_manager.unlockReg(index_lock);13461 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 .{
12896 .base = .{ .reg = try self.copyToTmpRegister(13464 .base = .{ .reg = try self.copyToTmpRegister(
12897 Type.usize,13465 Type.usize,
12898 switch (src_arg) {13466 switch (src_arg) {
...@@ -12984,7 +13552,7 @@ fn genCall(self: *CodeGen, info: union(enum) {...@@ -12984,7 +13552,7 @@ fn genCall(self: *CodeGen, info: union(enum) {
12984 .lea_frame = .{ .index = frame_index, .off = -reg_off.off },13552 .lea_frame = .{ .index = frame_index, .off = -reg_off.off },
12985 }, .{}),13553 }, .{}),
12986 .elementwise_regs_then_frame => |regs_frame_addr| {13554 .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 .{
12988 .base = .{ .reg = try self.copyToTmpRegister(13556 .base = .{ .reg = try self.copyToTmpRegister(
12989 Type.usize,13557 Type.usize,
12990 switch (src_arg) {13558 switch (src_arg) {
...@@ -13100,6 +13668,8 @@ fn airRet(self: *CodeGen, inst: Air.Inst.Index, safety: bool) !void {...@@ -13100,6 +13668,8 @@ fn airRet(self: *CodeGen, inst: Air.Inst.Index, safety: bool) !void {
13100 .none => {},13668 .none => {},
13101 .register,13669 .register,
13102 .register_pair,13670 .register_pair,
13671 .register_triple,
13672 .register_quadruple,
13103 => try self.genCopy(ret_ty, self.ret_mcv.short, .{ .air_ref = un_op }, .{ .safety = safety }),13673 => try self.genCopy(ret_ty, self.ret_mcv.short, .{ .air_ref = un_op }, .{ .safety = safety }),
13104 .indirect => |reg_off| {13674 .indirect => |reg_off| {
13105 try self.register_manager.getReg(reg_off.reg, null);13675 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...@@ -13226,7 +13796,7 @@ fn airCmp(self: *CodeGen, inst: Air.Inst.Index, op: std.math.CompareOperator) !v
13226 const temp_lhs_lock = self.register_manager.lockRegAssumeUnused(temp_lhs_reg);13796 const temp_lhs_lock = self.register_manager.lockRegAssumeUnused(temp_lhs_reg);
13227 defer self.register_manager.unlockReg(temp_lhs_lock);13797 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(
13230 .{ ._, .mov },13800 .{ ._, .mov },
13231 temp_lhs_reg.to8(),13801 temp_lhs_reg.to8(),
13232 try lhs_mcv.address().offset(payload_abi_size).deref().mem(self, .{ .size = .byte }),13802 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...@@ -13240,7 +13810,7 @@ fn airCmp(self: *CodeGen, inst: Air.Inst.Index, op: std.math.CompareOperator) !v
13240 }13810 }
1324113811
13242 const payload_compare = payload_compare: {13812 const payload_compare = payload_compare: {
13243 if (rhs_mcv.isMemory()) {13813 if (rhs_mcv.isBase()) {
13244 const rhs_mem =13814 const rhs_mem =
13245 try rhs_mcv.address().offset(payload_abi_size).deref().mem(self, .{ .size = .byte });13815 try rhs_mcv.address().offset(payload_abi_size).deref().mem(self, .{ .size = .byte });
13246 try self.asmMemoryRegister(.{ ._, .@"test" }, rhs_mem, temp_lhs_reg.to8());13816 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...@@ -13291,13 +13861,13 @@ fn airCmp(self: *CodeGen, inst: Air.Inst.Index, op: std.math.CompareOperator) !v
13291 } else .may_flip;13861 } else .may_flip;
1329213862
13293 const flipped = switch (may_flip) {13863 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(),
13295 .must_flip => true,13865 .must_flip => true,
13296 .must_not_flip => false,13866 .must_not_flip => false,
13297 };13867 };
13298 const unmat_dst_mcv = if (flipped) rhs_mcv else lhs_mcv;13868 const unmat_dst_mcv = if (flipped) rhs_mcv else lhs_mcv;
13299 const dst_mcv = if (unmat_dst_mcv.isRegister() or13869 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: {
13301 const dst_mcv = try self.allocTempRegOrMem(ty, true);13871 const dst_mcv = try self.allocTempRegOrMem(ty, true);
13302 try self.genCopy(ty, dst_mcv, unmat_dst_mcv, .{});13872 try self.genCopy(ty, dst_mcv, unmat_dst_mcv, .{});
13303 break :dst dst_mcv;13873 break :dst dst_mcv;
...@@ -13335,6 +13905,7 @@ fn airCmp(self: *CodeGen, inst: Air.Inst.Index, op: std.math.CompareOperator) !v...@@ -13335,6 +13905,7 @@ fn airCmp(self: *CodeGen, inst: Air.Inst.Index, op: std.math.CompareOperator) !v
13335 .register,13905 .register,
13336 .register_offset,13906 .register_offset,
13337 .register_overflow,13907 .register_overflow,
13908 .register_mask,
13338 .indirect,13909 .indirect,
13339 .lea_direct,13910 .lea_direct,
13340 .lea_got,13911 .lea_got,
...@@ -13345,7 +13916,7 @@ fn airCmp(self: *CodeGen, inst: Air.Inst.Index, op: std.math.CompareOperator) !v...@@ -13345,7 +13916,7 @@ fn airCmp(self: *CodeGen, inst: Air.Inst.Index, op: std.math.CompareOperator) !v
13345 .reserved_frame,13916 .reserved_frame,
13346 .air_ref,13917 .air_ref,
13347 => unreachable,13918 => unreachable,
13348 .register_pair, .load_frame => null,13919 .register_pair, .register_triple, .register_quadruple, .load_frame => null,
13349 .memory, .load_symbol, .load_got, .load_direct, .load_tlv => dst: {13920 .memory, .load_symbol, .load_got, .load_direct, .load_tlv => dst: {
13350 switch (resolved_dst_mcv) {13921 switch (resolved_dst_mcv) {
13351 .memory => |addr| if (std.math.cast(13922 .memory => |addr| if (std.math.cast(
...@@ -13396,6 +13967,7 @@ fn airCmp(self: *CodeGen, inst: Air.Inst.Index, op: std.math.CompareOperator) !v...@@ -13396,6 +13967,7 @@ fn airCmp(self: *CodeGen, inst: Air.Inst.Index, op: std.math.CompareOperator) !v
13396 .register,13967 .register,
13397 .register_offset,13968 .register_offset,
13398 .register_overflow,13969 .register_overflow,
13970 .register_mask,
13399 .indirect,13971 .indirect,
13400 .lea_symbol,13972 .lea_symbol,
13401 .lea_direct,13973 .lea_direct,
...@@ -13406,7 +13978,7 @@ fn airCmp(self: *CodeGen, inst: Air.Inst.Index, op: std.math.CompareOperator) !v...@@ -13406,7 +13978,7 @@ fn airCmp(self: *CodeGen, inst: Air.Inst.Index, op: std.math.CompareOperator) !v
13406 .reserved_frame,13978 .reserved_frame,
13407 .air_ref,13979 .air_ref,
13408 => unreachable,13980 => unreachable,
13409 .register_pair, .load_frame => null,13981 .register_pair, .register_triple, .register_quadruple, .load_frame => null,
13410 .memory, .load_symbol, .load_got, .load_direct, .load_tlv => src: {13982 .memory, .load_symbol, .load_got, .load_direct, .load_tlv => src: {
13411 switch (resolved_src_mcv) {13983 switch (resolved_src_mcv) {
13412 .memory => |addr| if (std.math.cast(13984 .memory => |addr| if (std.math.cast(
...@@ -13457,7 +14029,10 @@ fn airCmp(self: *CodeGen, inst: Air.Inst.Index, op: std.math.CompareOperator) !v...@@ -13457,7 +14029,10 @@ fn airCmp(self: *CodeGen, inst: Air.Inst.Index, op: std.math.CompareOperator) !v
13457 try self.genSetReg(tmp_reg, Type.usize, if (dst_info) |info| .{14029 try self.genSetReg(tmp_reg, Type.usize, if (dst_info) |info| .{
13458 .indirect = .{ .reg = info.addr_reg, .off = off },14030 .indirect = .{ .reg = info.addr_reg, .off = off },
13459 } else switch (resolved_dst_mcv) {14031 } 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] },
13461 .memory => |dst_addr| .{14036 .memory => |dst_addr| .{
13462 .memory = @bitCast(@as(i64, @bitCast(dst_addr)) + off),14037 .memory = @bitCast(@as(i64, @bitCast(dst_addr)) + off),
13463 },14038 },
...@@ -13479,9 +14054,10 @@ fn airCmp(self: *CodeGen, inst: Air.Inst.Index, op: std.math.CompareOperator) !v...@@ -13479,9 +14054,10 @@ fn airCmp(self: *CodeGen, inst: Air.Inst.Index, op: std.math.CompareOperator) !v
13479 if (src_info) |info| .{14054 if (src_info) |info| .{
13480 .indirect = .{ .reg = info.addr_reg, .off = off },14055 .indirect = .{ .reg = info.addr_reg, .off = off },
13481 } else switch (resolved_src_mcv) {14056 } else switch (resolved_src_mcv) {
13482 .register_pair => |src_regs| .{14057 inline .register_pair,
13483 .register = src_regs[limb_i],14058 .register_triple,
13484 },14059 .register_quadruple,
14060 => |src_regs| .{ .register = src_regs[limb_i] },
13485 .memory => |src_addr| .{14061 .memory => |src_addr| .{
13486 .memory = @bitCast(@as(i64, @bitCast(src_addr)) + off),14062 .memory = @bitCast(@as(i64, @bitCast(src_addr)) + off),
13487 },14063 },
...@@ -13539,7 +14115,7 @@ fn airCmp(self: *CodeGen, inst: Air.Inst.Index, op: std.math.CompareOperator) !v...@@ -13539,7 +14115,7 @@ fn airCmp(self: *CodeGen, inst: Air.Inst.Index, op: std.math.CompareOperator) !v
13539 const tmp2_lock = self.register_manager.lockRegAssumeUnused(tmp2_reg);14115 const tmp2_lock = self.register_manager.lockRegAssumeUnused(tmp2_reg);
13540 defer self.register_manager.unlockReg(tmp2_lock);14116 defer self.register_manager.unlockReg(tmp2_lock);
1354114117
13542 if (src_mcv.isMemory()) try self.asmRegisterRegisterMemoryImmediate(14118 if (src_mcv.isBase()) try self.asmRegisterRegisterMemoryImmediate(
13543 .{ .vp_w, .insr },14119 .{ .vp_w, .insr },
13544 tmp1_reg,14120 tmp1_reg,
13545 dst_reg.to128(),14121 dst_reg.to128(),
...@@ -13840,8 +14416,11 @@ fn isNull(self: *CodeGen, inst: Air.Inst.Index, opt_ty: Type, opt_mcv: MCValue)...@@ -13840,8 +14416,11 @@ fn isNull(self: *CodeGen, inst: Air.Inst.Index, opt_ty: Type, opt_mcv: MCValue)
13840 .undef,14416 .undef,
13841 .immediate,14417 .immediate,
13842 .eflags,14418 .eflags,
14419 .register_triple,
14420 .register_quadruple,
13843 .register_offset,14421 .register_offset,
13844 .register_overflow,14422 .register_overflow,
14423 .register_mask,
13845 .lea_direct,14424 .lea_direct,
13846 .lea_got,14425 .lea_got,
13847 .lea_tlv,14426 .lea_tlv,
...@@ -15481,6 +16060,7 @@ fn genCopy(self: *CodeGen, ty: Type, dst_mcv: MCValue, src_mcv: MCValue, opts: C...@@ -15481,6 +16060,7 @@ fn genCopy(self: *CodeGen, ty: Type, dst_mcv: MCValue, src_mcv: MCValue, opts: C
15481 .immediate,16060 .immediate,
15482 .eflags,16061 .eflags,
15483 .register_overflow,16062 .register_overflow,
16063 .register_mask,
15484 .lea_direct,16064 .lea_direct,
15485 .lea_got,16065 .lea_got,
15486 .lea_tlv,16066 .lea_tlv,
...@@ -15510,7 +16090,7 @@ fn genCopy(self: *CodeGen, ty: Type, dst_mcv: MCValue, src_mcv: MCValue, opts: C...@@ -15510,7 +16090,7 @@ fn genCopy(self: *CodeGen, ty: Type, dst_mcv: MCValue, src_mcv: MCValue, opts: C
15510 .off = -dst_reg_off.off,16090 .off = -dst_reg_off.off,
15511 } },16091 } },
15512 }, opts),16092 }, opts),
15513 .register_pair => |dst_regs| {16093 inline .register_pair, .register_triple, .register_quadruple => |dst_regs| {
15514 const src_info: ?struct { addr_reg: Register, addr_lock: RegisterLock } = switch (src_mcv) {16094 const src_info: ?struct { addr_reg: Register, addr_lock: RegisterLock } = switch (src_mcv) {
15515 .register_pair, .memory, .indirect, .load_frame => null,16095 .register_pair, .memory, .indirect, .load_frame => null,
15516 .load_symbol, .load_direct, .load_got, .load_tlv => src: {16096 .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...@@ -15535,9 +16115,12 @@ fn genCopy(self: *CodeGen, ty: Type, dst_mcv: MCValue, src_mcv: MCValue, opts: C
15535 defer if (src_info) |info| self.register_manager.unlockReg(info.addr_lock);16115 defer if (src_info) |info| self.register_manager.unlockReg(info.addr_lock);
1553616116
15537 var part_disp: i32 = 0;16117 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| {
15539 try self.genSetReg(dst_reg, dst_ty, switch (src_mcv) {16119 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] },
15541 .memory, .indirect, .load_frame => src_mcv.address().offset(part_disp).deref(),16124 .memory, .indirect, .load_frame => src_mcv.address().offset(part_disp).deref(),
15542 .load_symbol, .load_direct, .load_got, .load_tlv => .{ .indirect = .{16125 .load_symbol, .load_direct, .load_got, .load_tlv => .{ .indirect = .{
15543 .reg = src_info.?.addr_reg,16126 .reg = src_info.?.addr_reg,
...@@ -15733,7 +16316,10 @@ fn genSetReg(...@@ -15733,7 +16316,10 @@ fn genSetReg(
15733 },16316 },
15734 .ip => unreachable,16317 .ip => unreachable,
15735 },16318 },
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),
15737 .register_offset,16323 .register_offset,
15738 .indirect,16324 .indirect,
15739 .load_frame,16325 .load_frame,
...@@ -15770,6 +16356,47 @@ fn genSetReg(...@@ -15770,6 +16356,47 @@ fn genSetReg(
15770 },16356 },
15771 else => unreachable,16357 else => unreachable,
15772 }),16358 }),
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 },
15773 .memory, .load_symbol, .load_direct, .load_got, .load_tlv => {16400 .memory, .load_symbol, .load_direct, .load_got, .load_tlv => {
15774 switch (src_mcv) {16401 switch (src_mcv) {
15775 .memory => |addr| if (std.math.cast(i32, @as(i64, @bitCast(addr)))) |small_addr|16402 .memory => |addr| if (std.math.cast(i32, @as(i64, @bitCast(addr)))) |small_addr|
...@@ -15998,9 +16625,9 @@ fn genSetMem(...@@ -15998,9 +16625,9 @@ fn genSetMem(
15998 src_alias,16625 src_alias,
15999 );16626 );
16000 },16627 },
16001 .register_pair => |src_regs| {16628 inline .register_pair, .register_triple, .register_quadruple => |src_regs| {
16002 var part_disp: i32 = disp;16629 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| {
16004 try self.genSetMem(base, part_disp, src_ty, .{ .register = src_reg }, opts);16631 try self.genSetMem(base, part_disp, src_ty, .{ .register = src_reg }, opts);
16005 part_disp += @intCast(src_ty.abiSize(zcu));16632 part_disp += @intCast(src_ty.abiSize(zcu));
16006 }16633 }
...@@ -16065,6 +16692,13 @@ fn genSetMem(...@@ -16065,6 +16692,13 @@ fn genSetMem(
1606516692
16066 try self.genSetMem(base, disp, ty, .{ .register = src_reg }, opts);16693 try self.genSetMem(base, disp, ty, .{ .register = src_reg }, opts);
16067 },16694 },
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 },
16068 .memory,16702 .memory,
16069 .indirect,16703 .indirect,
16070 .load_direct,16704 .load_direct,
...@@ -16283,7 +16917,7 @@ fn airBitCast(self: *CodeGen, inst: Air.Inst.Index) !void {...@@ -16283,7 +16917,7 @@ fn airBitCast(self: *CodeGen, inst: Air.Inst.Index) !void {
16283 const dst_mcv = try self.allocRegOrMem(inst, true);16917 const dst_mcv = try self.allocRegOrMem(inst, true);
16284 try self.genCopy(switch (std.math.order(dst_ty.abiSize(zcu), src_ty.abiSize(zcu))) {16918 try self.genCopy(switch (std.math.order(dst_ty.abiSize(zcu), src_ty.abiSize(zcu))) {
16285 .lt => dst_ty,16919 .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,
16287 .gt => src_ty,16921 .gt => src_ty,
16288 }, dst_mcv, src_mcv, .{});16922 }, dst_mcv, src_mcv, .{});
16289 break :dst dst_mcv;16923 break :dst dst_mcv;
...@@ -16729,7 +17363,7 @@ fn atomicOp(...@@ -16729,7 +17363,7 @@ fn atomicOp(
16729 });17363 });
16730 try self.genSetReg(sse_reg, val_ty, .{ .register = .rax }, .{});17364 try self.genSetReg(sse_reg, val_ty, .{ .register = .rax }, .{});
16731 switch (mir_tag[0]) {17365 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(
16733 mir_tag,17367 mir_tag,
16734 sse_reg.to128(),17368 sse_reg.to128(),
16735 sse_reg.to128(),17369 sse_reg.to128(),
...@@ -16743,7 +17377,7 @@ fn atomicOp(...@@ -16743,7 +17377,7 @@ fn atomicOp(
16743 else17377 else
16744 try self.copyToTmpRegister(val_ty, val_mcv)).to128(),17378 try self.copyToTmpRegister(val_ty, val_mcv)).to128(),
16745 ),17379 ),
16746 ._ss, ._sd => if (val_mcv.isMemory()) try self.asmRegisterMemory(17380 ._ss, ._sd => if (val_mcv.isBase()) try self.asmRegisterMemory(
16747 mir_tag,17381 mir_tag,
16748 sse_reg.to128(),17382 sse_reg.to128(),
16749 try val_mcv.mem(self, .{ .size = self.memSize(val_ty) }),17383 try val_mcv.mem(self, .{ .size = self.memSize(val_ty) }),
...@@ -17443,7 +18077,7 @@ fn airSplat(self: *CodeGen, inst: Air.Inst.Index) !void {...@@ -17443,7 +18077,7 @@ fn airSplat(self: *CodeGen, inst: Air.Inst.Index) !void {
17443 defer self.register_manager.unlockReg(dst_lock);18077 defer self.register_manager.unlockReg(dst_lock);
1744418078
17445 const src_mcv = try self.resolveInst(ty_op.operand);18079 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(
17447 mir_tag,18081 mir_tag,
17448 registerAlias(dst_reg, @intCast(vector_ty.abiSize(zcu))),18082 registerAlias(dst_reg, @intCast(vector_ty.abiSize(zcu))),
17449 try src_mcv.mem(self, .{ .size = self.memSize(scalar_ty) }),18083 try src_mcv.mem(self, .{ .size = self.memSize(scalar_ty) }),
...@@ -17519,7 +18153,7 @@ fn airSplat(self: *CodeGen, inst: Air.Inst.Index) !void {...@@ -17519,7 +18153,7 @@ fn airSplat(self: *CodeGen, inst: Air.Inst.Index) !void {
17519 const src_mcv = try self.resolveInst(ty_op.operand);18153 const src_mcv = try self.resolveInst(ty_op.operand);
17520 if (self.hasFeature(.avx)) {18154 if (self.hasFeature(.avx)) {
17521 const dst_reg = try self.register_manager.allocReg(inst, dst_rc);18155 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(
17523 .{ .v_ss, .broadcast },18157 .{ .v_ss, .broadcast },
17524 dst_reg.to128(),18158 dst_reg.to128(),
17525 try src_mcv.mem(self, .{ .size = .dword }),18159 try src_mcv.mem(self, .{ .size = .dword }),
...@@ -17556,7 +18190,7 @@ fn airSplat(self: *CodeGen, inst: Air.Inst.Index) !void {...@@ -17556,7 +18190,7 @@ fn airSplat(self: *CodeGen, inst: Air.Inst.Index) !void {
17556 5...8 => if (self.hasFeature(.avx)) {18190 5...8 => if (self.hasFeature(.avx)) {
17557 const src_mcv = try self.resolveInst(ty_op.operand);18191 const src_mcv = try self.resolveInst(ty_op.operand);
17558 const dst_reg = try self.register_manager.allocReg(inst, dst_rc);18192 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(
17560 .{ .v_ss, .broadcast },18194 .{ .v_ss, .broadcast },
17561 dst_reg.to256(),18195 dst_reg.to256(),
17562 try src_mcv.mem(self, .{ .size = .dword }),18196 try src_mcv.mem(self, .{ .size = .dword }),
...@@ -17602,7 +18236,7 @@ fn airSplat(self: *CodeGen, inst: Air.Inst.Index) !void {...@@ -17602,7 +18236,7 @@ fn airSplat(self: *CodeGen, inst: Air.Inst.Index) !void {
17602 const src_mcv = try self.resolveInst(ty_op.operand);18236 const src_mcv = try self.resolveInst(ty_op.operand);
17603 const dst_reg = try self.register_manager.allocReg(inst, dst_rc);18237 const dst_reg = try self.register_manager.allocReg(inst, dst_rc);
17604 if (self.hasFeature(.sse3)) {18238 if (self.hasFeature(.sse3)) {
17605 if (src_mcv.isMemory()) try self.asmRegisterMemory(18239 if (src_mcv.isBase()) try self.asmRegisterMemory(
17606 if (self.hasFeature(.avx)) .{ .v_, .movddup } else .{ ._, .movddup },18240 if (self.hasFeature(.avx)) .{ .v_, .movddup } else .{ ._, .movddup },
17607 dst_reg.to128(),18241 dst_reg.to128(),
17608 try src_mcv.mem(self, .{ .size = .qword }),18242 try src_mcv.mem(self, .{ .size = .qword }),
...@@ -17627,7 +18261,7 @@ fn airSplat(self: *CodeGen, inst: Air.Inst.Index) !void {...@@ -17627,7 +18261,7 @@ fn airSplat(self: *CodeGen, inst: Air.Inst.Index) !void {
17627 3...4 => if (self.hasFeature(.avx)) {18261 3...4 => if (self.hasFeature(.avx)) {
17628 const src_mcv = try self.resolveInst(ty_op.operand);18262 const src_mcv = try self.resolveInst(ty_op.operand);
17629 const dst_reg = try self.register_manager.allocReg(inst, dst_rc);18263 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(
17631 .{ .v_sd, .broadcast },18265 .{ .v_sd, .broadcast },
17632 dst_reg.to256(),18266 dst_reg.to256(),
17633 try src_mcv.mem(self, .{ .size = .qword }),18267 try src_mcv.mem(self, .{ .size = .qword }),
...@@ -17670,7 +18304,7 @@ fn airSplat(self: *CodeGen, inst: Air.Inst.Index) !void {...@@ -17670,7 +18304,7 @@ fn airSplat(self: *CodeGen, inst: Air.Inst.Index) !void {
17670 2 => if (self.hasFeature(.avx)) {18304 2 => if (self.hasFeature(.avx)) {
17671 const src_mcv = try self.resolveInst(ty_op.operand);18305 const src_mcv = try self.resolveInst(ty_op.operand);
17672 const dst_reg = try self.register_manager.allocReg(inst, dst_rc);18306 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(
17674 .{ .v_f128, .broadcast },18308 .{ .v_f128, .broadcast },
17675 dst_reg.to256(),18309 dst_reg.to256(),
17676 try src_mcv.mem(self, .{ .size = .xword }),18310 try src_mcv.mem(self, .{ .size = .xword }),
...@@ -17779,7 +18413,7 @@ fn airSelect(self: *CodeGen, inst: Air.Inst.Index) !void {...@@ -17779,7 +18413,7 @@ fn airSelect(self: *CodeGen, inst: Air.Inst.Index) !void {
17779 else => unreachable,18413 else => unreachable,
17780 }, .broadcast },18414 }, .broadcast },
17781 mask_alias,18415 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 .{
17783 .base = .{ .reg = (try self.copyToTmpRegister(18417 .base = .{ .reg = (try self.copyToTmpRegister(
17784 Type.usize,18418 Type.usize,
17785 pred_mcv.address(),18419 pred_mcv.address(),
...@@ -17973,7 +18607,7 @@ fn airSelect(self: *CodeGen, inst: Air.Inst.Index) !void {...@@ -17973,7 +18607,7 @@ fn airSelect(self: *CodeGen, inst: Air.Inst.Index) !void {
17973 try self.genSetReg(dst_reg, ty, rhs_mcv, .{});18607 try self.genSetReg(dst_reg, ty, rhs_mcv, .{});
17974 break :rhs dst_alias;18608 break :rhs dst_alias;
17975 };18609 };
17976 if (lhs_mcv.isMemory()) try self.asmRegisterRegisterMemoryRegister(18610 if (lhs_mcv.isBase()) try self.asmRegisterRegisterMemoryRegister(
17977 mir_tag,18611 mir_tag,
17978 dst_alias,18612 dst_alias,
17979 rhs_alias,18613 rhs_alias,
...@@ -17989,7 +18623,7 @@ fn airSelect(self: *CodeGen, inst: Air.Inst.Index) !void {...@@ -17989,7 +18623,7 @@ fn airSelect(self: *CodeGen, inst: Air.Inst.Index) !void {
17989 try self.copyToTmpRegister(ty, lhs_mcv), abi_size),18623 try self.copyToTmpRegister(ty, lhs_mcv), abi_size),
17990 mask_alias,18624 mask_alias,
17991 );18625 );
17992 } else if (has_blend) if (lhs_mcv.isMemory()) try self.asmRegisterMemoryRegister(18626 } else if (has_blend) if (lhs_mcv.isBase()) try self.asmRegisterMemoryRegister(
17993 mir_tag,18627 mir_tag,
17994 dst_alias,18628 dst_alias,
17995 try lhs_mcv.mem(self, .{ .size = self.memSize(ty) }),18629 try lhs_mcv.mem(self, .{ .size = self.memSize(ty) }),
...@@ -18014,7 +18648,7 @@ fn airSelect(self: *CodeGen, inst: Air.Inst.Index) !void {...@@ -18014,7 +18648,7 @@ fn airSelect(self: *CodeGen, inst: Air.Inst.Index) !void {
18014 },18648 },
18015 }) orelse return self.fail("TODO implement airSelect for {}", .{ty.fmt(pt)});18649 }) orelse return self.fail("TODO implement airSelect for {}", .{ty.fmt(pt)});
18016 try self.asmRegisterRegister(.{ mir_fixes, .@"and" }, dst_alias, mask_alias);18650 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(
18018 .{ mir_fixes, .andn },18652 .{ mir_fixes, .andn },
18019 mask_alias,18653 mask_alias,
18020 try rhs_mcv.mem(self, .{ .size = .fromSize(abi_size) }),18654 try rhs_mcv.mem(self, .{ .size = .fromSize(abi_size) }),
...@@ -18093,10 +18727,7 @@ fn airShuffle(self: *CodeGen, inst: Air.Inst.Index) !void {...@@ -18093,10 +18727,7 @@ fn airShuffle(self: *CodeGen, inst: Air.Inst.Index) !void {
1809318727
18094 for ([_]Mir.Inst.Tag{ .unpckl, .unpckh }) |variant| unpck: {18728 for ([_]Mir.Inst.Tag{ .unpckl, .unpckh }) |variant| unpck: {
18095 if (elem_abi_size > 8) break :unpck;18729 if (elem_abi_size > 8) break :unpck;
18096 if (dst_abi_size > @as(u32, if (if (elem_abi_size >= 4)18730 if (dst_abi_size > self.vectorSize(if (elem_abi_size >= 4) .float else .int)) break :unpck;
18097 has_avx
18098 else
18099 self.hasFeature(.avx2)) 32 else 16)) break :unpck;
1810018731
18101 var sources: [2]?u1 = @splat(null);18732 var sources: [2]?u1 = @splat(null);
18102 for (mask_elems, 0..) |maybe_mask_elem, elem_index| {18733 for (mask_elems, 0..) |maybe_mask_elem, elem_index| {
...@@ -18154,7 +18785,7 @@ fn airShuffle(self: *CodeGen, inst: Air.Inst.Index) !void {...@@ -18154,7 +18785,7 @@ fn airShuffle(self: *CodeGen, inst: Air.Inst.Index) !void {
18154 },18785 },
18155 else => unreachable,18786 else => unreachable,
18156 } };18787 } };
18157 if (has_avx) if (rhs_mcv.isMemory()) try self.asmRegisterRegisterMemory(18788 if (has_avx) if (rhs_mcv.isBase()) try self.asmRegisterRegisterMemory(
18158 mir_tag,18789 mir_tag,
18159 dst_alias,18790 dst_alias,
18160 registerAlias(lhs_mcv.getReg() orelse dst_reg, max_abi_size),18791 registerAlias(lhs_mcv.getReg() orelse dst_reg, max_abi_size),
...@@ -18167,7 +18798,7 @@ fn airShuffle(self: *CodeGen, inst: Air.Inst.Index) !void {...@@ -18167,7 +18798,7 @@ fn airShuffle(self: *CodeGen, inst: Air.Inst.Index) !void {
18167 rhs_mcv.getReg().?18798 rhs_mcv.getReg().?
18168 else18799 else
18169 try self.copyToTmpRegister(operand_tys[sources[1].?], rhs_mcv), max_abi_size),18800 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(
18171 mir_tag,18802 mir_tag,
18172 dst_alias,18803 dst_alias,
18173 try rhs_mcv.mem(self, .{ .size = .fromSize(max_abi_size) }),18804 try rhs_mcv.mem(self, .{ .size = .fromSize(max_abi_size) }),
...@@ -18184,7 +18815,7 @@ fn airShuffle(self: *CodeGen, inst: Air.Inst.Index) !void {...@@ -18184,7 +18815,7 @@ fn airShuffle(self: *CodeGen, inst: Air.Inst.Index) !void {
1818418815
18185 pshufd: {18816 pshufd: {
18186 if (elem_abi_size != 4) break :pshufd;18817 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
18189 var control: u8 = 0b00_00_00_00;18820 var control: u8 = 0b00_00_00_00;
18190 var sources: [1]?u1 = @splat(null);18821 var sources: [1]?u1 = @splat(null);
...@@ -18216,7 +18847,7 @@ fn airShuffle(self: *CodeGen, inst: Air.Inst.Index) !void {...@@ -18216,7 +18847,7 @@ fn airShuffle(self: *CodeGen, inst: Air.Inst.Index) !void {
18216 try self.register_manager.allocReg(inst, abi.RegisterClass.sse);18847 try self.register_manager.allocReg(inst, abi.RegisterClass.sse);
18217 const dst_alias = registerAlias(dst_reg, max_abi_size);18848 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(
18220 .{ if (has_avx) .vp_d else .p_d, .shuf },18851 .{ if (has_avx) .vp_d else .p_d, .shuf },
18221 dst_alias,18852 dst_alias,
18222 try src_mcv.mem(self, .{ .size = .fromSize(max_abi_size) }),18853 try src_mcv.mem(self, .{ .size = .fromSize(max_abi_size) }),
...@@ -18235,7 +18866,7 @@ fn airShuffle(self: *CodeGen, inst: Air.Inst.Index) !void {...@@ -18235,7 +18866,7 @@ fn airShuffle(self: *CodeGen, inst: Air.Inst.Index) !void {
1823518866
18236 shufps: {18867 shufps: {
18237 if (elem_abi_size != 4) break :shufps;18868 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
18240 var control: u8 = 0b00_00_00_00;18871 var control: u8 = 0b00_00_00_00;
18241 var sources: [2]?u1 = @splat(null);18872 var sources: [2]?u1 = @splat(null);
...@@ -18272,7 +18903,7 @@ fn airShuffle(self: *CodeGen, inst: Air.Inst.Index) !void {...@@ -18272,7 +18903,7 @@ fn airShuffle(self: *CodeGen, inst: Air.Inst.Index) !void {
18272 const dst_reg = dst_mcv.getReg().?;18903 const dst_reg = dst_mcv.getReg().?;
18273 const dst_alias = registerAlias(dst_reg, max_abi_size);18904 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(
18276 .{ .v_ps, .shuf },18907 .{ .v_ps, .shuf },
18277 dst_alias,18908 dst_alias,
18278 registerAlias(lhs_mcv.getReg() orelse dst_reg, max_abi_size),18909 registerAlias(lhs_mcv.getReg() orelse dst_reg, max_abi_size),
...@@ -18287,7 +18918,7 @@ fn airShuffle(self: *CodeGen, inst: Air.Inst.Index) !void {...@@ -18287,7 +18918,7 @@ fn airShuffle(self: *CodeGen, inst: Air.Inst.Index) !void {
18287 else18918 else
18288 try self.copyToTmpRegister(operand_tys[sources[1].?], rhs_mcv), max_abi_size),18919 try self.copyToTmpRegister(operand_tys[sources[1].?], rhs_mcv), max_abi_size),
18289 .u(control),18920 .u(control),
18290 ) else if (rhs_mcv.isMemory()) try self.asmRegisterMemoryImmediate(18921 ) else if (rhs_mcv.isBase()) try self.asmRegisterMemoryImmediate(
18291 .{ ._ps, .shuf },18922 .{ ._ps, .shuf },
18292 dst_alias,18923 dst_alias,
18293 try rhs_mcv.mem(self, .{ .size = .fromSize(max_abi_size) }),18924 try rhs_mcv.mem(self, .{ .size = .fromSize(max_abi_size) }),
...@@ -18306,7 +18937,7 @@ fn airShuffle(self: *CodeGen, inst: Air.Inst.Index) !void {...@@ -18306,7 +18937,7 @@ fn airShuffle(self: *CodeGen, inst: Air.Inst.Index) !void {
1830618937
18307 shufpd: {18938 shufpd: {
18308 if (elem_abi_size != 8) break :shufpd;18939 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
18311 var control: u4 = 0b0_0_0_0;18942 var control: u4 = 0b0_0_0_0;
18312 var sources: [2]?u1 = @splat(null);18943 var sources: [2]?u1 = @splat(null);
...@@ -18339,7 +18970,7 @@ fn airShuffle(self: *CodeGen, inst: Air.Inst.Index) !void {...@@ -18339,7 +18970,7 @@ fn airShuffle(self: *CodeGen, inst: Air.Inst.Index) !void {
18339 const dst_reg = dst_mcv.getReg().?;18970 const dst_reg = dst_mcv.getReg().?;
18340 const dst_alias = registerAlias(dst_reg, max_abi_size);18971 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(
18343 .{ .v_pd, .shuf },18974 .{ .v_pd, .shuf },
18344 dst_alias,18975 dst_alias,
18345 registerAlias(lhs_mcv.getReg() orelse dst_reg, max_abi_size),18976 registerAlias(lhs_mcv.getReg() orelse dst_reg, max_abi_size),
...@@ -18354,7 +18985,7 @@ fn airShuffle(self: *CodeGen, inst: Air.Inst.Index) !void {...@@ -18354,7 +18985,7 @@ fn airShuffle(self: *CodeGen, inst: Air.Inst.Index) !void {
18354 else18985 else
18355 try self.copyToTmpRegister(operand_tys[sources[1].?], rhs_mcv), max_abi_size),18986 try self.copyToTmpRegister(operand_tys[sources[1].?], rhs_mcv), max_abi_size),
18356 .u(control),18987 .u(control),
18357 ) else if (rhs_mcv.isMemory()) try self.asmRegisterMemoryImmediate(18988 ) else if (rhs_mcv.isBase()) try self.asmRegisterMemoryImmediate(
18358 .{ ._pd, .shuf },18989 .{ ._pd, .shuf },
18359 dst_alias,18990 dst_alias,
18360 try rhs_mcv.mem(self, .{ .size = .fromSize(max_abi_size) }),18991 try rhs_mcv.mem(self, .{ .size = .fromSize(max_abi_size) }),
...@@ -18373,7 +19004,7 @@ fn airShuffle(self: *CodeGen, inst: Air.Inst.Index) !void {...@@ -18373,7 +19004,7 @@ fn airShuffle(self: *CodeGen, inst: Air.Inst.Index) !void {
1837319004
18374 blend: {19005 blend: {
18375 if (elem_abi_size < 2) break :blend;19006 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;
18377 if (!self.hasFeature(.sse4_1)) break :blend;19008 if (!self.hasFeature(.sse4_1)) break :blend;
1837819009
18379 var control: u8 = 0b0_0_0_0_0_0_0_0;19010 var control: u8 = 0b0_0_0_0_0_0_0_0;
...@@ -18409,7 +19040,7 @@ fn airShuffle(self: *CodeGen, inst: Air.Inst.Index) !void {...@@ -18409,7 +19040,7 @@ fn airShuffle(self: *CodeGen, inst: Air.Inst.Index) !void {
1840919040
18410 const rhs_mcv = try self.resolveInst(extra.b);19041 const rhs_mcv = try self.resolveInst(extra.b);
18411 const dst_reg = try self.register_manager.allocReg(inst, abi.RegisterClass.sse);19042 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(
18413 .{ .vp_d, .blend },19044 .{ .vp_d, .blend },
18414 registerAlias(dst_reg, dst_abi_size),19045 registerAlias(dst_reg, dst_abi_size),
18415 registerAlias(lhs_reg, dst_abi_size),19046 registerAlias(lhs_reg, dst_abi_size),
...@@ -18461,7 +19092,7 @@ fn airShuffle(self: *CodeGen, inst: Air.Inst.Index) !void {...@@ -18461,7 +19092,7 @@ fn airShuffle(self: *CodeGen, inst: Air.Inst.Index) !void {
18461 try self.copyToRegisterWithInstTracking(inst, dst_ty, lhs_mcv);19092 try self.copyToRegisterWithInstTracking(inst, dst_ty, lhs_mcv);
18462 const dst_reg = dst_mcv.getReg().?;19093 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(
18465 .{ .vp_w, .blend },19096 .{ .vp_w, .blend },
18466 registerAlias(dst_reg, dst_abi_size),19097 registerAlias(dst_reg, dst_abi_size),
18467 registerAlias(if (lhs_mcv.isRegister())19098 registerAlias(if (lhs_mcv.isRegister())
...@@ -18482,7 +19113,7 @@ fn airShuffle(self: *CodeGen, inst: Air.Inst.Index) !void {...@@ -18482,7 +19113,7 @@ fn airShuffle(self: *CodeGen, inst: Air.Inst.Index) !void {
18482 else19113 else
18483 try self.copyToTmpRegister(dst_ty, rhs_mcv), dst_abi_size),19114 try self.copyToTmpRegister(dst_ty, rhs_mcv), dst_abi_size),
18484 .u(expanded_control),19115 .u(expanded_control),
18485 ) else if (rhs_mcv.isMemory()) try self.asmRegisterMemoryImmediate(19116 ) else if (rhs_mcv.isBase()) try self.asmRegisterMemoryImmediate(
18486 .{ .p_w, .blend },19117 .{ .p_w, .blend },
18487 registerAlias(dst_reg, dst_abi_size),19118 registerAlias(dst_reg, dst_abi_size),
18488 try rhs_mcv.mem(self, .{ .size = .fromSize(dst_abi_size) }),19119 try rhs_mcv.mem(self, .{ .size = .fromSize(dst_abi_size) }),
...@@ -18518,7 +19149,7 @@ fn airShuffle(self: *CodeGen, inst: Air.Inst.Index) !void {...@@ -18518,7 +19149,7 @@ fn airShuffle(self: *CodeGen, inst: Air.Inst.Index) !void {
18518 try self.copyToRegisterWithInstTracking(inst, dst_ty, lhs_mcv);19149 try self.copyToRegisterWithInstTracking(inst, dst_ty, lhs_mcv);
18519 const dst_reg = dst_mcv.getReg().?;19150 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(
18522 switch (elem_abi_size) {19153 switch (elem_abi_size) {
18523 4 => .{ .v_ps, .blend },19154 4 => .{ .v_ps, .blend },
18524 8, 16 => .{ .v_pd, .blend },19155 8, 16 => .{ .v_pd, .blend },
...@@ -18547,7 +19178,7 @@ fn airShuffle(self: *CodeGen, inst: Air.Inst.Index) !void {...@@ -18547,7 +19178,7 @@ fn airShuffle(self: *CodeGen, inst: Air.Inst.Index) !void {
18547 else19178 else
18548 try self.copyToTmpRegister(dst_ty, rhs_mcv), dst_abi_size),19179 try self.copyToTmpRegister(dst_ty, rhs_mcv), dst_abi_size),
18549 .u(expanded_control),19180 .u(expanded_control),
18550 ) else if (rhs_mcv.isMemory()) try self.asmRegisterMemoryImmediate(19181 ) else if (rhs_mcv.isBase()) try self.asmRegisterMemoryImmediate(
18551 switch (elem_abi_size) {19182 switch (elem_abi_size) {
18552 4 => .{ ._ps, .blend },19183 4 => .{ ._ps, .blend },
18553 8, 16 => .{ ._pd, .blend },19184 8, 16 => .{ ._pd, .blend },
...@@ -18573,10 +19204,7 @@ fn airShuffle(self: *CodeGen, inst: Air.Inst.Index) !void {...@@ -18573,10 +19204,7 @@ fn airShuffle(self: *CodeGen, inst: Air.Inst.Index) !void {
18573 }19204 }
1857419205
18575 blendv: {19206 blendv: {
18576 if (dst_abi_size > @as(u32, if (if (elem_abi_size >= 4)19207 if (dst_abi_size > self.vectorSize(if (elem_abi_size >= 4) .float else .int)) break :blendv;
18577 has_avx
18578 else
18579 self.hasFeature(.avx2)) 32 else 16)) break :blendv;
1858019208
18581 const select_mask_elem_ty = try pt.intType(.unsigned, elem_abi_size * 8);19209 const select_mask_elem_ty = try pt.intType(.unsigned, elem_abi_size * 8);
18582 const select_mask_ty = try pt.vectorType(.{19210 const select_mask_ty = try pt.vectorType(.{
...@@ -18637,7 +19265,7 @@ fn airShuffle(self: *CodeGen, inst: Air.Inst.Index) !void {...@@ -18637,7 +19265,7 @@ fn airShuffle(self: *CodeGen, inst: Air.Inst.Index) !void {
18637 const dst_reg = dst_mcv.getReg().?;19265 const dst_reg = dst_mcv.getReg().?;
18638 const dst_alias = registerAlias(dst_reg, dst_abi_size);19266 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(
18641 mir_tag,19269 mir_tag,
18642 dst_alias,19270 dst_alias,
18643 if (lhs_mcv.isRegister())19271 if (lhs_mcv.isRegister())
...@@ -18658,7 +19286,7 @@ fn airShuffle(self: *CodeGen, inst: Air.Inst.Index) !void {...@@ -18658,7 +19286,7 @@ fn airShuffle(self: *CodeGen, inst: Air.Inst.Index) !void {
18658 else19286 else
18659 try self.copyToTmpRegister(dst_ty, rhs_mcv), dst_abi_size),19287 try self.copyToTmpRegister(dst_ty, rhs_mcv), dst_abi_size),
18660 select_mask_alias,19288 select_mask_alias,
18661 ) else if (rhs_mcv.isMemory()) try self.asmRegisterMemoryRegister(19289 ) else if (rhs_mcv.isBase()) try self.asmRegisterMemoryRegister(
18662 mir_tag,19290 mir_tag,
18663 dst_alias,19291 dst_alias,
18664 try rhs_mcv.mem(self, .{ .size = .fromSize(dst_abi_size) }),19292 try rhs_mcv.mem(self, .{ .size = .fromSize(dst_abi_size) }),
...@@ -18701,7 +19329,7 @@ fn airShuffle(self: *CodeGen, inst: Air.Inst.Index) !void {...@@ -18701,7 +19329,7 @@ fn airShuffle(self: *CodeGen, inst: Air.Inst.Index) !void {
18701 else19329 else
18702 .p_;19330 .p_;
18703 try self.asmRegisterRegister(.{ mir_fixes, .@"and" }, dst_alias, mask_alias);19331 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(
18705 .{ mir_fixes, .andn },19333 .{ mir_fixes, .andn },
18706 mask_alias,19334 mask_alias,
18707 try lhs_mcv.mem(self, .{ .size = .fromSize(dst_abi_size) }),19335 try lhs_mcv.mem(self, .{ .size = .fromSize(dst_abi_size) }),
...@@ -18851,22 +19479,61 @@ fn airReduce(self: *CodeGen, inst: Air.Inst.Index) !void {...@@ -18851,22 +19479,61 @@ fn airReduce(self: *CodeGen, inst: Air.Inst.Index) !void {
18851 if (operand_ty.isVector(zcu) and operand_ty.childType(zcu).toIntern() == .bool_type) {19479 if (operand_ty.isVector(zcu) and operand_ty.childType(zcu).toIntern() == .bool_type) {
18852 try self.spillEflagsIfOccupied();19480 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;
18858 const abi_size: u32 = @intCast(operand_ty.abiSize(zcu));19482 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;
18859 switch (reduce.operation) {19517 switch (reduce.operation) {
18860 .Or => {19518 .Or => {
18861 if (operand_mcv.isMemory()) try self.asmMemoryImmediate(19519 if (operand_mcv.isBase()) try self.asmMemoryImmediate(
18862 .{ ._, .@"test" },19520 .{ ._, .@"test" },
18863 try operand_mcv.mem(self, .{ .size = .fromSize(abi_size) }),19521 try operand_mcv.mem(self, .{ .size = .fromSize(abi_size) }),
18864 .u(mask),19522 if (mask_len < abi_size * 8)
18865 ) else {19523 .u(mask)
18866 const operand_reg = registerAlias(if (operand_mcv.isRegister())
18867 operand_mcv.getReg().?
18868 else19524 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
18870 if (mask_len < abi_size * 8) try self.asmRegisterImmediate(19537 if (mask_len < abi_size * 8) try self.asmRegisterImmediate(
18871 .{ ._, .@"test" },19538 .{ ._, .@"test" },
18872 operand_reg,19539 operand_reg,
...@@ -18880,7 +19547,10 @@ fn airReduce(self: *CodeGen, inst: Air.Inst.Index) !void {...@@ -18880,7 +19547,10 @@ fn airReduce(self: *CodeGen, inst: Air.Inst.Index) !void {
18880 break :result .{ .eflags = .nz };19547 break :result .{ .eflags = .nz };
18881 },19548 },
18882 .And => {19549 .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 );
18884 const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);19554 const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);
18885 defer self.register_manager.unlockReg(tmp_lock);19555 defer self.register_manager.unlockReg(tmp_lock);
1888619556
...@@ -19184,7 +19854,7 @@ fn airMulAdd(self: *CodeGen, inst: Air.Inst.Index) !void {...@@ -19184,7 +19854,7 @@ fn airMulAdd(self: *CodeGen, inst: Air.Inst.Index) !void {
19184 if (unused.isSet(0) and mcv.isRegister() and self.reuseOperand(inst, op, op_index, mcv.*)) {19854 if (unused.isSet(0) and mcv.isRegister() and self.reuseOperand(inst, op, op_index, mcv.*)) {
19185 order[op_index] = 1;19855 order[op_index] = 1;
19186 unused.unset(0);19856 unused.unset(0);
19187 } else if (unused.isSet(2) and mcv.isMemory()) {19857 } else if (unused.isSet(2) and mcv.isBase()) {
19188 order[op_index] = 3;19858 order[op_index] = 3;
19189 unused.unset(2);19859 unused.unset(2);
19190 }19860 }
...@@ -19531,7 +20201,7 @@ fn airVaArg(self: *CodeGen, inst: Air.Inst.Index) !void {...@@ -19531,7 +20201,7 @@ fn airVaArg(self: *CodeGen, inst: Air.Inst.Index) !void {
19531 const dst_lock = self.register_manager.lockReg(dst_reg);20201 const dst_lock = self.register_manager.lockReg(dst_reg);
19532 defer if (dst_lock) |lock| self.register_manager.unlockReg(lock);20202 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(
19535 .{ .v_ss, .cvtsd2 },20205 .{ .v_ss, .cvtsd2 },
19536 dst_reg,20206 dst_reg,
19537 dst_reg,20207 dst_reg,
...@@ -19544,7 +20214,7 @@ fn airVaArg(self: *CodeGen, inst: Air.Inst.Index) !void {...@@ -19544,7 +20214,7 @@ fn airVaArg(self: *CodeGen, inst: Air.Inst.Index) !void {
19544 promote_mcv.getReg().?20214 promote_mcv.getReg().?
19545 else20215 else
19546 try self.copyToTmpRegister(promote_ty, promote_mcv)).to128(),20216 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(
19548 .{ ._ss, .cvtsd2 },20218 .{ ._ss, .cvtsd2 },
19549 dst_reg,20219 dst_reg,
19550 try promote_mcv.mem(self, .{ .size = .qword }),20220 try promote_mcv.mem(self, .{ .size = .qword }),
...@@ -19751,7 +20421,7 @@ fn resolveCallingConventionValues(...@@ -19751,7 +20421,7 @@ fn resolveCallingConventionValues(
19751 // TODO: is this even possible for C calling convention?20421 // TODO: is this even possible for C calling convention?
19752 result.return_value = .init(.none);20422 result.return_value = .init(.none);
19753 } else {20423 } else {
19754 var ret_tracking: [2]InstTracking = undefined;20424 var ret_tracking: [4]InstTracking = undefined;
19755 var ret_tracking_i: usize = 0;20425 var ret_tracking_i: usize = 0;
1975620426
19757 const classes = switch (resolved_cc) {20427 const classes = switch (resolved_cc) {
...@@ -19771,14 +20441,17 @@ fn resolveCallingConventionValues(...@@ -19771,14 +20441,17 @@ fn resolveCallingConventionValues(
19771 ret_tracking_i += 1;20441 ret_tracking_i += 1;
19772 },20442 },
19773 .sse, .float, .float_combine, .win_i128 => {20443 .sse, .float, .float_combine, .win_i128 => {
19774 const ret_sse_reg = registerAlias(20444 const ret_sse_regs = abi.getCAbiSseReturnRegs(resolved_cc);
19775 abi.getCAbiSseReturnRegs(resolved_cc)[ret_sse_reg_i],20445 const abi_size: u32 = @intCast(ret_ty.abiSize(zcu));
19776 @intCast(ret_ty.abiSize(zcu)),20446 const reg_size = @min(abi_size, self.vectorSize(.float));
19777 );20447 var byte_offset: u32 = 0;
19778 ret_sse_reg_i += 1;20448 while (byte_offset < abi_size) : (byte_offset += reg_size) {
1977920449 const ret_sse_reg = registerAlias(ret_sse_regs[ret_sse_reg_i], reg_size);
19780 ret_tracking[ret_tracking_i] = .init(.{ .register = ret_sse_reg });20450 ret_sse_reg_i += 1;
19781 ret_tracking_i += 1;20451
20452 ret_tracking[ret_tracking_i] = .init(.{ .register = ret_sse_reg });
20453 ret_tracking_i += 1;
20454 }
19782 },20455 },
19783 .sseup => assert(ret_tracking[ret_tracking_i - 1].short.register.class() == .sse),20456 .sseup => assert(ret_tracking[ret_tracking_i - 1].short.register.class() == .sse),
19784 .x87 => {20457 .x87 => {
...@@ -19811,6 +20484,17 @@ fn resolveCallingConventionValues(...@@ -19811,6 +20484,17 @@ fn resolveCallingConventionValues(
19811 ret_tracking[0].short.register,20484 ret_tracking[0].short.register,
19812 ret_tracking[1].short.register,20485 ret_tracking[1].short.register,
19813 } }),20486 } }),
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 } }),
19814 };20498 };
19815 }20499 }
1981620500
...@@ -19826,7 +20510,7 @@ fn resolveCallingConventionValues(...@@ -19826,7 +20510,7 @@ fn resolveCallingConventionValues(
19826 else => unreachable,20510 else => unreachable,
19827 }20511 }
1982820512
19829 var arg_mcv: [2]MCValue = undefined;20513 var arg_mcv: [4]MCValue = undefined;
19830 var arg_mcv_i: usize = 0;20514 var arg_mcv_i: usize = 0;
1983120515
19832 const classes = switch (resolved_cc) {20516 const classes = switch (resolved_cc) {
...@@ -19834,15 +20518,13 @@ fn resolveCallingConventionValues(...@@ -19834,15 +20518,13 @@ fn resolveCallingConventionValues(
19834 .x86_64_win => &.{abi.classifyWindows(ty, zcu)},20518 .x86_64_win => &.{abi.classifyWindows(ty, zcu)},
19835 else => unreachable,20519 else => unreachable,
19836 };20520 };
19837 for (classes) |class| switch (class) {20521 classes: for (classes) |class| switch (class) {
19838 .integer => {20522 .integer => {
19839 const param_int_regs = abi.getCAbiIntParamRegs(resolved_cc);20523 const param_int_regs = abi.getCAbiIntParamRegs(resolved_cc);
19840 if (param_int_reg_i >= param_int_regs.len) break;20524 if (param_int_reg_i >= param_int_regs.len) break;
1984120525
19842 const param_int_reg = registerAlias(20526 const param_int_reg =
19843 abi.getCAbiIntParamRegs(resolved_cc)[param_int_reg_i],20527 registerAlias(param_int_regs[param_int_reg_i], @intCast(@min(ty.abiSize(zcu), 8)));
19844 @intCast(@min(ty.abiSize(zcu), 8)),
19845 );
19846 param_int_reg_i += 1;20528 param_int_reg_i += 1;
1984720529
19848 arg_mcv[arg_mcv_i] = .{ .register = param_int_reg };20530 arg_mcv[arg_mcv_i] = .{ .register = param_int_reg };
...@@ -19850,16 +20532,18 @@ fn resolveCallingConventionValues(...@@ -19850,16 +20532,18 @@ fn resolveCallingConventionValues(
19850 },20532 },
19851 .sse, .float, .float_combine => {20533 .sse, .float, .float_combine => {
19852 const param_sse_regs = abi.getCAbiSseParamRegs(resolved_cc);20534 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(20541 const param_sse_reg = registerAlias(param_sse_regs[param_sse_reg_i], reg_size);
19856 abi.getCAbiSseParamRegs(resolved_cc)[param_sse_reg_i],20542 param_sse_reg_i += 1;
19857 @intCast(ty.abiSize(zcu)),
19858 );
19859 param_sse_reg_i += 1;
1986020543
19861 arg_mcv[arg_mcv_i] = .{ .register = param_sse_reg };20544 arg_mcv[arg_mcv_i] = .{ .register = param_sse_reg };
19862 arg_mcv_i += 1;20545 arg_mcv_i += 1;
20546 }
19863 },20547 },
19864 .sseup => assert(arg_mcv[arg_mcv_i - 1].register.class() == .sse),20548 .sseup => assert(arg_mcv[arg_mcv_i - 1].register.class() == .sse),
19865 .x87, .x87up, .complex_x87, .memory, .win_i128 => switch (resolved_cc) {20549 .x87, .x87up, .complex_x87, .memory, .win_i128 => switch (resolved_cc) {
...@@ -19908,7 +20592,21 @@ fn resolveCallingConventionValues(...@@ -19908,7 +20592,21 @@ fn resolveCallingConventionValues(
19908 arg.* = switch (arg_mcv_i) {20592 arg.* = switch (arg_mcv_i) {
19909 else => unreachable,20593 else => unreachable,
19910 1 => arg_mcv[0],20594 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 } },
19912 };20610 };
19913 continue;20611 continue;
19914 }20612 }
...@@ -20052,32 +20750,40 @@ fn memSize(self: *CodeGen, ty: Type) Memory.Size {...@@ -20052,32 +20750,40 @@ fn memSize(self: *CodeGen, ty: Type) Memory.Size {
20052 };20750 };
20053}20751}
2005420752
20055fn splitType(self: *CodeGen, ty: Type) ![2]Type {20753fn splitType(self: *CodeGen, comptime parts_len: usize, ty: Type) ![parts_len]Type {
20056 const pt = self.pt;20754 const pt = self.pt;
20057 const zcu = pt.zcu;20755 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 };
20058 const classes = std.mem.sliceTo(&abi.classifySystemV(ty, zcu, self.target.*, .other), .none);20763 const classes = std.mem.sliceTo(&abi.classifySystemV(ty, zcu, self.target.*, .other), .none);
20059 var parts: [2]Type = undefined;20764 if (classes.len == parts_len) for (&parts, classes, 0..) |*part, class, part_i| {
20060 if (classes.len == 2) for (&parts, classes, 0..) |*part, class, part_i| {
20061 part.* = switch (class) {20765 part.* = switch (class) {
20062 .integer => switch (part_i) {20766 .integer => if (part_i < parts_len - 1)
20063 0 => Type.u64,20767 Type.u64
20064 1 => part: {20768 else part: {
20065 const elem_size = ty.abiAlignment(zcu).minStrict(.@"8").toByteUnits().?;20769 const elem_size = ty.abiAlignment(zcu).minStrict(.@"8").toByteUnits().?;
20066 const elem_ty = try pt.intType(.unsigned, @intCast(elem_size * 8));20770 const elem_ty = try pt.intType(.unsigned, @intCast(elem_size * 8));
20067 break :part switch (@divExact(ty.abiSize(zcu) - 8, elem_size)) {20771 break :part switch (@divExact(ty.abiSize(zcu) - part_i * 8, elem_size)) {
20068 1 => elem_ty,20772 1 => elem_ty,
20069 else => |len| try pt.arrayType(.{ .len = len, .child = elem_ty.toIntern() }),20773 else => |array_len| try pt.arrayType(.{ .len = array_len, .child = elem_ty.toIntern() }),
20070 };20774 };
20071 },
20072 else => unreachable,
20073 },20775 },
20074 .float => Type.f32,20776 .float => Type.f32,
20075 .float_combine => try pt.arrayType(.{ .len = 2, .child = .f32_type }),20777 .float_combine => try pt.arrayType(.{ .len = 2, .child = .f32_type }),
20076 .sse => Type.f64,20778 .sse => Type.f64,
20077 else => break,20779 else => break,
20078 };20780 };
20079 } else if (parts[0].abiSize(zcu) + parts[1].abiSize(zcu) == ty.abiSize(zcu)) return parts;20781 } else {
20080 return self.fail("TODO implement splitType for {}", .{ty.fmt(pt)});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) });
20081}20787}
2008220788
20083/// Truncates the value in the register in place.20789/// Truncates the value in the register in place.
...@@ -20297,6 +21003,7 @@ const Temp = struct {...@@ -20297,6 +21003,7 @@ const Temp = struct {
20297 .immediate,21003 .immediate,
20298 .eflags,21004 .eflags,
20299 .register_offset,21005 .register_offset,
21006 .register_mask,
20300 .memory,21007 .memory,
20301 .load_symbol,21008 .load_symbol,
20302 .lea_symbol,21009 .lea_symbol,
...@@ -20314,6 +21021,8 @@ const Temp = struct {...@@ -20314,6 +21021,8 @@ const Temp = struct {
20314 => false,21021 => false,
20315 .register,21022 .register,
20316 .register_pair,21023 .register_pair,
21024 .register_triple,
21025 .register_quadruple,
20317 .register_overflow,21026 .register_overflow,
20318 => true,21027 => true,
20319 .load_frame => |frame_addr| !frame_addr.index.isNamed(),21028 .load_frame => |frame_addr| !frame_addr.index.isNamed(),
...@@ -20330,7 +21039,7 @@ const Temp = struct {...@@ -20330,7 +21039,7 @@ const Temp = struct {
20330 cg.temp_type[@intFromEnum(new_temp_index)] = Type.usize;21039 cg.temp_type[@intFromEnum(new_temp_index)] = Type.usize;
20331 cg.next_temp_index = @enumFromInt(@intFromEnum(new_temp_index) + 1);21040 cg.next_temp_index = @enumFromInt(@intFromEnum(new_temp_index) + 1);
20332 switch (temp.tracking(cg).short) {21041 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 }),
20334 .register => |reg| {21043 .register => |reg| {
20335 const new_reg =21044 const new_reg =
20336 try cg.register_manager.allocReg(new_temp_index.toIndex(), abi.RegisterClass.gp);21045 try cg.register_manager.allocReg(new_temp_index.toIndex(), abi.RegisterClass.gp);
...@@ -20434,7 +21143,7 @@ const Temp = struct {...@@ -20434,7 +21143,7 @@ const Temp = struct {
20434 const new_temp_index = cg.next_temp_index;21143 const new_temp_index = cg.next_temp_index;
20435 cg.temp_type[@intFromEnum(new_temp_index)] = Type.usize;21144 cg.temp_type[@intFromEnum(new_temp_index)] = Type.usize;
20436 switch (temp.tracking(cg).short) {21145 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 }),
20438 .immediate => |imm| {21147 .immediate => |imm| {
20439 assert(limb_index == 0);21148 assert(limb_index == 0);
20440 new_temp_index.tracking(cg).* = .init(.{ .immediate = imm });21149 new_temp_index.tracking(cg).* = .init(.{ .immediate = imm });
...@@ -20635,6 +21344,17 @@ const Temp = struct {...@@ -20635,6 +21344,17 @@ const Temp = struct {
20635 first_temp.* = result_temp;21344 first_temp.* = result_temp;
20636 }21345 }
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
20638 fn toLea(temp: *Temp, cg: *CodeGen) !bool {21358 fn toLea(temp: *Temp, cg: *CodeGen) !bool {
20639 switch (temp.tracking(cg).short) {21359 switch (temp.tracking(cg).short) {
20640 .none,21360 .none,
...@@ -20643,7 +21363,10 @@ const Temp = struct {...@@ -20643,7 +21363,10 @@ const Temp = struct {
20643 .undef,21363 .undef,
20644 .eflags,21364 .eflags,
20645 .register_pair,21365 .register_pair,
21366 .register_triple,
21367 .register_quadruple,
20646 .register_overflow,21368 .register_overflow,
21369 .register_mask,
20647 .elementwise_regs_then_frame,21370 .elementwise_regs_then_frame,
20648 .reserved_frame,21371 .reserved_frame,
20649 .air_ref,21372 .air_ref,
...@@ -20677,10 +21400,7 @@ const Temp = struct {...@@ -20677,10 +21400,7 @@ const Temp = struct {
2067721400
20678 fn toBase(temp: *Temp, cg: *CodeGen) !bool {21401 fn toBase(temp: *Temp, cg: *CodeGen) !bool {
20679 const temp_tracking = temp.tracking(cg);21402 const temp_tracking = temp.tracking(cg);
20680 switch (temp_tracking.short) {21403 if (temp_tracking.short.isBase()) return false;
20681 else => {},
20682 .indirect, .load_frame => return false,
20683 }
20684 const new_temp_index = cg.next_temp_index;21404 const new_temp_index = cg.next_temp_index;
20685 cg.temp_type[@intFromEnum(new_temp_index)] = temp.typeOf(cg);21405 cg.temp_type[@intFromEnum(new_temp_index)] = temp.typeOf(cg);
20686 const new_reg =21406 const new_reg =
...@@ -20697,7 +21417,7 @@ const Temp = struct {...@@ -20697,7 +21417,7 @@ const Temp = struct {
20697 const val_abi_size: u32 = @intCast(val_ty.abiSize(cg.pt.zcu));21417 const val_abi_size: u32 = @intCast(val_ty.abiSize(cg.pt.zcu));
20698 const val = try cg.tempAlloc(val_ty);21418 const val = try cg.tempAlloc(val_ty);
20699 switch (val.tracking(cg).short) {21419 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 }),
20701 .register => |val_reg| {21421 .register => |val_reg| {
20702 while (try ptr.toLea(cg)) {}21422 while (try ptr.toLea(cg)) {}
20703 switch (val_reg.class()) {21423 switch (val_reg.class()) {
...@@ -20706,7 +21426,7 @@ const Temp = struct {...@@ -20706,7 +21426,7 @@ const Temp = struct {
20706 registerAlias(val_reg, val_abi_size),21426 registerAlias(val_reg, val_abi_size),
20707 try ptr.tracking(cg).short.deref().mem(cg, .{ .size = cg.memSize(val_ty) }),21427 try ptr.tracking(cg).short.deref().mem(cg, .{ .size = cg.memSize(val_ty) }),
20708 ),21428 ),
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 }),
20710 }21430 }
20711 },21431 },
20712 .load_frame => |val_frame_addr| {21432 .load_frame => |val_frame_addr| {
...@@ -20724,7 +21444,7 @@ const Temp = struct {...@@ -20724,7 +21444,7 @@ const Temp = struct {
20724 const val_ty = val.typeOf(cg);21444 const val_ty = val.typeOf(cg);
20725 const val_abi_size: u32 = @intCast(val_ty.abiSize(cg.pt.zcu));21445 const val_abi_size: u32 = @intCast(val_ty.abiSize(cg.pt.zcu));
20726 val: switch (val.tracking(cg).short) {21446 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 }),
20728 .immediate => |imm| if (std.math.cast(i32, imm)) |s| {21448 .immediate => |imm| if (std.math.cast(i32, imm)) |s| {
20729 while (try ptr.toLea(cg)) {}21449 while (try ptr.toLea(cg)) {}
20730 try cg.asmMemoryImmediate(21450 try cg.asmMemoryImmediate(
...@@ -20742,7 +21462,7 @@ const Temp = struct {...@@ -20742,7 +21462,7 @@ const Temp = struct {
20742 try ptr.tracking(cg).short.deref().mem(cg, .{ .size = cg.memSize(val_ty) }),21462 try ptr.tracking(cg).short.deref().mem(cg, .{ .size = cg.memSize(val_ty) }),
20743 registerAlias(val_reg, val_abi_size),21463 registerAlias(val_reg, val_abi_size),
20744 ),21464 ),
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 }),
20746 }21466 }
20747 },21467 },
20748 }21468 }
...@@ -20876,6 +21596,7 @@ fn reuseTemp(...@@ -20876,6 +21596,7 @@ fn reuseTemp(
20876 .register_pair,21596 .register_pair,
20877 .register_offset,21597 .register_offset,
20878 .register_overflow,21598 .register_overflow,
21599 .register_mask,
20879 .indirect,21600 .indirect,
20880 => for (tracking.short.getRegs()) |tracked_reg| {21601 => for (tracking.short.getRegs()) |tracked_reg| {
20881 if (RegisterManager.indexOfRegIntoTracked(tracked_reg)) |tracked_index| {21602 if (RegisterManager.indexOfRegIntoTracked(tracked_reg)) |tracked_index| {
...@@ -20913,6 +21634,26 @@ fn tempAllocReg(cg: *CodeGen, ty: Type, rc: RegisterManager.RegisterBitSet) !Tem...@@ -20913,6 +21634,26 @@ fn tempAllocReg(cg: *CodeGen, ty: Type, rc: RegisterManager.RegisterBitSet) !Tem
20913 return .{ .index = temp_index.toIndex() };21634 return .{ .index = temp_index.toIndex() };
20914}21635}
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
20916fn tempFromValue(cg: *CodeGen, ty: Type, value: MCValue) !Temp {21657fn tempFromValue(cg: *CodeGen, ty: Type, value: MCValue) !Temp {
20917 const temp_index = cg.next_temp_index;21658 const temp_index = cg.next_temp_index;
20918 temp_index.tracking(cg).* = .init(value);21659 temp_index.tracking(cg).* = .init(value);
...@@ -20993,30 +21734,23 @@ const Operand = union(enum) {...@@ -20993,30 +21734,23 @@ const Operand = union(enum) {
20993 inst: Mir.Inst.Index,21734 inst: Mir.Inst.Index,
20994};21735};
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
21014const Pattern = struct {21737const Pattern = struct {
21015 ops: []const Op,21738 ops: []const Op,
21016 commute: struct { u8, u8 } = .{ 0, 0 },21739 commute: struct { u8, u8 } = .{ 0, 0 },
2101721740
21018 const Set = struct {21741 const Set = struct {
21019 required_features: []const std.Target.x86.Feature = &.{},21742 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,
21020 loop: enum {21754 loop: enum {
21021 /// only execute the instruction once21755 /// only execute the instruction once
21022 once,21756 once,
...@@ -21050,6 +21784,18 @@ const Pattern = struct {...@@ -21050,6 +21784,18 @@ const Pattern = struct {
21050 xmm,21784 xmm,
21051 /// any 256-bit sse register21785 /// any 256-bit sse register
21052 ymm,21786 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,
21053 /// any memory21799 /// any memory
21054 mem,21800 mem,
21055 /// a limb stored in a gpr21801 /// a limb stored in a gpr
...@@ -21062,41 +21808,82 @@ const Pattern = struct {...@@ -21062,41 +21808,82 @@ const Pattern = struct {
21062 ymm_limb,21808 ymm_limb,
21063 /// a limb stored in memory21809 /// a limb stored in memory
21064 mem_limb,21810 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,
21065 /// specific immediate21817 /// specific immediate
21066 imm: i8,21818 imm: i8,
21067 /// any immediate signed extended from 32 bits21819 /// any immediate signed extended from 32 bits
21068 simm32,21820 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
21070 fn matches(op: Op, is_mut: bool, temp: Temp, cg: *CodeGen) bool {21830 fn matches(op: Op, is_mut: bool, temp: Temp, cg: *CodeGen) bool {
21071 const abi_size = temp.typeOf(cg).abiSize(cg.pt.zcu);21831 switch (op) {
21072 return switch (op) {
21073 .implicit, .explicit => unreachable,21832 .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,
21074 .gpr => abi_size <= 8 and switch (temp.tracking(cg).short) {21841 .gpr => abi_size <= 8 and switch (temp.tracking(cg).short) {
21075 .register => |reg| reg.class() == .general_purpose,21842 .register => |reg| reg.class() == .general_purpose,
21076 .register_offset => |reg_off| reg_off.reg.class() == .general_purpose and21843 .register_offset => |reg_off| reg_off.reg.class() == .general_purpose and
21077 reg_off.off == 0,21844 reg_off.off == 0,
21078 else => cg.regClassForType(temp.typeOf(cg)) == .general_purpose,21845 else => cg.regClassForType(temp_ty) == .general_purpose,
21079 },21846 },
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) {
21081 .register => |reg| reg.class() == .mmx,21848 .register => |reg| reg.class() == .mmx,
21082 .register_offset => |reg_off| reg_off.reg.class() == .mmx and reg_off.off == 0,21849 .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,
21084 },21851 },
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) {
21086 .register => |reg| reg.class() == .sse,21853 .register => |reg| reg.class() == .sse,
21087 .register_offset => |reg_off| reg_off.reg.class() == .sse and reg_off.off == 0,21854 .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,
21089 },21856 },
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) {
21091 .register => |reg| reg.class() == .sse,21858 .register => |reg| reg.class() == .sse,
21092 .register_offset => |reg_off| reg_off.reg.class() == .sse and reg_off.off == 0,21859 .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,
21094 },21861 },
21095 .mem, .mem_limb => (!is_mut or temp.isMut(cg)) and temp.tracking(cg).short.isMemory(),21862 .mem, .mem_limb => (!is_mut or temp.isMut(cg)) and temp.tracking(cg).short.isMemory(),
21096 .gpr_limb => abi_size > 8,21863 .gpr_limb => abi_size > 8 and switch (temp.tracking(cg).short) {
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,21864 inline .register_pair, .register_triple, .register_quadruple => |regs| for (regs) |reg| {
21098 .xmm_limb => abi_size > 16 and (!is_mut or temp.isMut(cg)) and temp.tracking(cg).short.isMemory(),21865 if (reg.class() != .general_purpose) break false;
21099 .ymm_limb => abi_size > 32 and (!is_mut or temp.isMut(cg)) and temp.tracking(cg).short.isMemory(),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 },
21100 .imm => |specific_imm| if (is_mut) unreachable else switch (temp.tracking(cg).short) {21887 .imm => |specific_imm| if (is_mut) unreachable else switch (temp.tracking(cg).short) {
21101 .immediate => |imm| @as(i64, @bitCast(imm)) == specific_imm,21888 .immediate => |imm| @as(i64, @bitCast(imm)) == specific_imm,
21102 else => false,21889 else => false,
...@@ -21109,78 +21896,176 @@ const Pattern = struct {...@@ -21109,78 +21896,176 @@ const Pattern = struct {
21109 }21896 }
21110 };21897 };
21111};21898};
21112fn select(cg: *CodeGen, dst_temps: []Temp, src_temps: []const *Temp, pattern_sets: []const Pattern.Set) !void {21899const SelectOptions = struct {
21113 var loop: SelectLoop = .{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 } = .{
21114 .element_reloc = undefined,21932 .element_reloc = undefined,
21115 .element_offset = .unused,21933 .element_offset = .unused,
21116 .element_size = null,21934 .element_size = null,
21117 .limb_reloc = undefined,21935 .limb_reloc = undefined,
21118 .limb_offset = .unused,21936 .limb_offset = .unused,
21119 .limb_size = null,21937 .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,
21120 .remaining_size = null,21945 .remaining_size = null,
21121 };21946 };
21122 var extra_temps: [4]?Temp = @splat(null);21947 var extra_temps: [4]?Temp = @splat(null);
21123 pattern_sets: for (pattern_sets) |pattern_set| {21948 pattern_sets: for (pattern_sets) |pattern_set| {
21124 for (pattern_set.required_features) |required_feature| if (!cg.hasFeature(required_feature)) continue :pattern_sets;21949 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 };
21125 patterns: for (pattern_set.patterns) |pattern| {21986 patterns: for (pattern_set.patterns) |pattern| {
21126 for (src_temps, pattern.ops[dst_temps.len..]) |src_temp, src_op| {21987 for (src_temps, pattern.ops[dst_temps.len..]) |src_temp, src_op| {
21127 const ref_src_op, const is_mut = switch (src_op) {21988 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 },
21129 else => .{ src_op, false },21990 else => .{ src_op, false },
21130 };21991 };
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;
21132 }21993 }
21133 while (true) for (src_temps, pattern.ops[dst_temps.len..]) |src_temp, src_op| {21994
21134 if (switch (switch (src_op) {21995 while (true) for (src_temps, pattern.ops[dst_temps.len..]) |*src_temp, src_op| {
21135 .implicit, .explicit => |op_index| pattern.ops[op_index],21996 if (changed: switch (switch (src_op) {
21997 .implicit, .explicit => |linked_index| pattern.ops[linked_index],
21136 else => src_op,21998 else => src_op,
21137 }) {21999 }) {
21138 .implicit, .explicit => unreachable,22000 .implicit, .explicit => unreachable,
21139 .gpr => try src_temp.toRegClass(.general_purpose, cg),22001 .gpr => try src_temp.toRegClass(.general_purpose, cg),
21140 .mm => try src_temp.toRegClass(.mmx, cg),22002 .mm, .mm_mask, .mm_sign_mask => try src_temp.toRegClass(.mmx, cg),
21141 .xmm, .ymm => try src_temp.toRegClass(.sse, cg),22003 .xmm,
21142 .mem, .imm, .simm32 => false,22004 .ymm,
21143 .gpr_limb, .mm_limb, .xmm_limb, .ymm_limb, .mem_limb => switch (src_temp.tracking(cg).short) {22005 .xmm_mask,
21144 .register_pair => false,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,
21145 else => try src_temp.toBase(cg),22019 else => try src_temp.toBase(cg),
21146 },22020 },
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,
21147 }) break;22030 }) break;
21148 } else break;22031 } else break;
22032
22033 var dst_is_linked: std.StaticBitSet(4) = .initEmpty();
21149 var mir_ops_len = dst_temps.len;22034 var mir_ops_len = dst_temps.len;
21150 for (src_temps, pattern.ops[dst_temps.len..]) |src_temp, src_op| {22035 for (src_temps, pattern.ops[dst_temps.len..]) |src_temp, src_op| {
21151 const ref_src_op, const extra_temp = op: switch (src_op) {22036 defer mir_ops_len += @intFromBool(src_op != .implicit);
21152 .implicit => |op_index| {22037 const linked_src_op, const extra_temp = op: switch (src_op) {
21153 dst_temps[op_index] = if (src_temp.isMut(cg))22038 .implicit, .explicit => |linked_index| {
21154 src_temp.*22039 if (src_temp.isMut(cg)) {
21155 else22040 dst_temps[linked_index] = src_temp;
21156 try cg.tempAlloc(src_temp.typeOf(cg));22041 dst_is_linked.set(linked_index);
21157 break :op .{ pattern.ops[op_index], &extra_temps[op_index] };22042 }
21158 },22043 break :op .{ pattern.ops[linked_index], &extra_temps[linked_index] };
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] };
21170 },22044 },
22045 else => .{ src_op, &extra_temps[mir_ops_len] },
21171 };22046 };
21172 const limb_size: u8, const rc = switch (ref_src_op) {22047 const limb_size: u8, const rc = switch (linked_src_op) {
21173 else => continue,22048 else => continue,
21174 .gpr_limb => .{ 8, abi.RegisterClass.gp },22049 .gpr_limb => .{ 8, abi.RegisterClass.gp },
21175 .mm_limb => .{ 8, @panic("TODO") },22050 .mm_limb, .mm_mask_limb => .{ 8, @panic("TODO") },
21176 .xmm_limb => .{ 16, abi.RegisterClass.sse },22051 .xmm_limb, .xmm_mask_limb => .{ 16, abi.RegisterClass.sse },
21177 .ymm_limb => .{ 32, 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 },
21178 };22063 };
21179 assert(loop.limb_size == null or loop.limb_size == limb_size);22064 assert(loop.limb_size == null or loop.limb_size == limb_size);
21180 loop.limb_size = limb_size;22065 loop.limb_size = limb_size;
21181 loop.remaining_size = loop.remaining_size orelse src_temp.typeOf(cg).abiSize(cg.pt.zcu);22066 loop.remaining_size = loop.remaining_size orelse src_temp.typeOf(cg).abiSize(cg.pt.zcu);
21182 switch (src_temp.tracking(cg).short) {22067 switch (src_temp.tracking(cg).short) {
21183 .register_pair => switch (loop.limb_offset) {22068 .register_pair, .register_triple, .register_quadruple => switch (loop.limb_offset) {
21184 .unused, .temp => loop.limb_offset = .{ .known = 0 },22069 .unused, .temp => loop.limb_offset = .{ .known = 0 },
21185 .known => {},22070 .known => {},
21186 },22071 },
...@@ -21189,25 +22074,130 @@ fn select(cg: *CodeGen, dst_temps: []Temp, src_temps: []const *Temp, pattern_set...@@ -21189,25 +22074,130 @@ fn select(cg: *CodeGen, dst_temps: []Temp, src_temps: []const *Temp, pattern_set
21189 .unused => loop.limb_offset = .{ .temp = undefined },22074 .unused => loop.limb_offset = .{ .temp = undefined },
21190 .known, .temp => {},22075 .known, .temp => {},
21191 }22076 }
22077 assert(extra_temp.* == null);
21192 extra_temp.* = try cg.tempAllocReg(Type.usize, rc);22078 extra_temp.* = try cg.tempAllocReg(Type.usize, rc);
21193 },22079 },
21194 }22080 }
21195 }22081 }
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 }
21196 switch (loop.element_offset) {22173 switch (loop.element_offset) {
21197 .unused, .known => {},22174 .unused, .known => {},
21198 .temp => |*element_offset| {22175 .temp => |*element_offset| {
21199 element_offset.* = try cg.tempAllocReg(Type.usize, abi.RegisterClass.gp);22176 element_offset.* = try cg.tempAllocReg(Type.usize, abi.RegisterClass.gp);
21200 const element_offset_reg = element_offset.tracking(cg).short.register;22177 const element_offset_reg = element_offset.tracking(cg).short.register;
22178 try cg.spillEflagsIfOccupied();
21201 try cg.asmRegisterRegister(.{ ._, .xor }, element_offset_reg.to32(), element_offset_reg.to32());22179 try cg.asmRegisterRegister(.{ ._, .xor }, element_offset_reg.to32(), element_offset_reg.to32());
21202 loop.element_reloc = @intCast(cg.mir_instructions.len);22180 loop.element_reloc = @intCast(cg.mir_instructions.len);
21203 },22181 },
21204 }22182 }
22183 switch (loop.limb_offset) {
22184 .unused, .known => {},
22185 .temp => |*limb_offset| limb_offset.* = try cg.tempAllocReg(Type.usize, abi.RegisterClass.gp),
22186 }
21205 while (true) {22187 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 }
21206 switch (loop.limb_offset) {22196 switch (loop.limb_offset) {
21207 .unused, .known => {},22197 .unused, .known => {},
21208 .temp => |*limb_offset| {22198 .temp => |limb_offset| {
21209 limb_offset.* = try cg.tempAllocReg(Type.usize, abi.RegisterClass.gp);22199 const limb_offset_reg = limb_offset.tracking(cg).short.register.to32();
21210 const limb_offset_reg = limb_offset.tracking(cg).short.register;22200 try cg.spillEflagsIfOccupied();
21211 try cg.asmRegisterRegister(.{ ._, .xor }, limb_offset_reg.to32(), limb_offset_reg.to32());22201 try cg.asmRegisterRegister(.{ ._, .xor }, limb_offset_reg.to32(), limb_offset_reg.to32());
21212 loop.limb_reloc = @intCast(cg.mir_instructions.len);22202 loop.limb_reloc = @intCast(cg.mir_instructions.len);
21213 },22203 },
...@@ -21216,56 +22206,67 @@ fn select(cg: *CodeGen, dst_temps: []Temp, src_temps: []const *Temp, pattern_set...@@ -21216,56 +22206,67 @@ fn select(cg: *CodeGen, dst_temps: []Temp, src_temps: []const *Temp, pattern_set
21216 var mir_ops: [4]Operand = @splat(.none);22206 var mir_ops: [4]Operand = @splat(.none);
21217 mir_ops_len = dst_temps.len;22207 mir_ops_len = dst_temps.len;
21218 for (src_temps, pattern.ops[dst_temps.len..]) |src_temp, src_op| {22208 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) {22209 defer mir_ops_len += @intFromBool(src_op != .implicit);
21220 .implicit => |op_index| .{ &mir_ops[op_index], pattern.ops[op_index], &extra_temps[op_index] },22210 const mir_op, const linked_src_op, const extra_temp = switch (src_op) {
21221 .explicit => |op_index| {22211 .implicit => |linked_index| .{ &mir_ops[linked_index], pattern.ops[linked_index], extra_temps[linked_index] },
21222 defer mir_ops_len += 1;22212 .explicit => |linked_index| .{ &mir_ops[mir_ops_len], pattern.ops[linked_index], extra_temps[linked_index] },
21223 break :op .{ &mir_ops[mir_ops_len], pattern.ops[op_index], &extra_temps[mir_ops_len] };22213 else => .{ &mir_ops[mir_ops_len], src_op, 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 },
21229 };22214 };
21230 const src_mcv = src_temp.tracking(cg).short;22215 const src_mcv = switch (linked_src_op) {
21231 switch (ref_src_op) {22216 else => src_temp,
21232 else => {},22217 // src_temp is undefined
21233 .gpr_limb, .mm_limb, .xmm_limb, .ymm_limb => switch (src_mcv) {22218 .umax_gpr, .umax_mm, .umax_xmm, .umax_ymm => extra_temp.?,
21234 .register_pair => {},22219 }.tracking(cg).short;
21235 else => try cg.asmRegisterMemory(22220 copy_limb: switch (src_mcv) {
21236 switch (ref_src_op) {22221 .register_pair, .register_triple, .register_quadruple => {},
21237 else => unreachable,22222 else => try cg.asmRegisterMemory(
21238 .gpr_limb => .{ ._, .mov },22223 switch (linked_src_op) {
21239 .mm_limb => .{ ._q, .mov },22224 else => break :copy_limb,
21240 .xmm_limb, .ymm_limb => .{ if (cg.hasFeature(.avx)) .v_ else ._, .movdqu },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,
21241 },22239 },
21242 registerAlias(extra_temp.*.?.tracking(cg).short.register, loop.limb_size.?),22240 .temp => |limb_offset| .{
21243 try src_mcv.mem(cg, switch (loop.limb_offset) {22241 .size = .fromSize(loop.limb_size.?),
21244 .unused => unreachable,22242 .index = limb_offset.tracking(cg).short.register.to64(),
21245 .known => |limb_offset| .{22243 },
21246 .size = .fromSize(loop.limb_size.?),22244 }),
21247 .disp = limb_offset,22245 ),
21248 },
21249 .temp => |limb_offset| .{
21250 .size = .fromSize(loop.limb_size.?),
21251 .index = limb_offset.tracking(cg).short.register.to64(),
21252 },
21253 }),
21254 ),
21255 },
21256 }22246 }
21257 mir_op.* = switch (ref_src_op) {22247 mir_op.* = switch (linked_src_op) {
21258 .implicit, .explicit => unreachable,22248 .implicit, .explicit => unreachable,
21259 .gpr => .{ .reg = registerAlias(22249 .gpr => .{ .reg = registerAlias(
21260 src_mcv.register,22250 src_mcv.register,
21261 @intCast(src_temp.typeOf(cg).abiSize(cg.pt.zcu)),22251 @intCast(src_temp.typeOf(cg).abiSize(cg.pt.zcu)),
21262 ) },22252 ) },
21263 .mm => .{ .reg = src_mcv.register },22253 .umax_gpr => .{ .reg = src_mcv.register.to64() }, // TODO: use other op size?
21264 .xmm => .{ .reg = src_mcv.register.to128() },22254 .mm, .mm_mask, .mm_sign_mask, .umax_mm => .{ .reg = src_mcv.register },
21265 .ymm => .{ .reg = src_mcv.register.to256() },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() },
21266 .mem => .{ .mem = try src_mcv.mem(cg, .{ .size = cg.memSize(src_temp.typeOf(cg)) }) },22257 .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) {22258 .gpr_limb,
21268 .register_pair => |src_regs| switch (loop.limb_offset) {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) {
21269 .unused => unreachable,22270 .unused => unreachable,
21270 .known => |limb_offset| .{ .reg = registerAlias(22271 .known => |limb_offset| .{ .reg = registerAlias(
21271 src_regs[@divExact(limb_offset, loop.limb_size.?)],22272 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...@@ -21274,12 +22275,12 @@ fn select(cg: *CodeGen, dst_temps: []Temp, src_temps: []const *Temp, pattern_set
21274 .temp => unreachable,22275 .temp => unreachable,
21275 },22276 },
21276 else => .{ .reg = registerAlias(22277 else => .{ .reg = registerAlias(
21277 extra_temp.*.?.tracking(cg).short.register,22278 extra_temp.?.tracking(cg).short.register,
21278 loop.limb_size.?,22279 loop.limb_size.?,
21279 ) },22280 ) },
21280 },22281 },
21281 .mem_limb => .{ .mem = switch (src_mcv) {22282 .mem_limb => .{ .mem = switch (src_mcv) {
21282 .register_pair => unreachable,22283 .register_pair, .register_triple, .register_quadruple => unreachable,
21283 else => switch (loop.limb_offset) {22284 else => switch (loop.limb_offset) {
21284 .unused => unreachable,22285 .unused => unreachable,
21285 .known => |limb_offset| try src_mcv.mem(cg, .{22286 .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...@@ -21309,76 +22310,53 @@ fn select(cg: *CodeGen, dst_temps: []Temp, src_temps: []const *Temp, pattern_set
21309 .u(@as(u32, @intCast(src_mcv.immediate))) },22310 .u(@as(u32, @intCast(src_mcv.immediate))) },
21310 },22311 },
21311 };22312 };
22313 switch (src_op) {
22314 else => {},
22315 .explicit => |linked_index| mir_ops[linked_index] = mir_op.*,
22316 }
21312 }22317 }
21313 for (22318 for (
22319 mir_ops[0..dst_temps.len],
21314 pattern.ops[0..dst_temps.len],22320 pattern.ops[0..dst_temps.len],
21315 dst_temps,22321 dst_temps,
21316 mir_ops[0..dst_temps.len],22322 dst_tys,
21317 extra_temps[0..dst_temps.len],22323 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| {
21319 if (mir_op.* != .none) continue;22325 if (mir_op.* != .none) continue;
21320 const ty = src_temps[0].typeOf(cg);22326 mir_op.* = switch (dst_op) {
21321 switch (dst_op) {
21322 .implicit => unreachable,22327 .implicit => unreachable,
21323 .explicit => |op_index| {22328 .explicit => |linked_index| mir_ops[linked_index],
21324 dst_temp.* = dst_temps[op_index];22329 .gpr => .{ .reg = registerAlias(
21325 mir_op.* = mir_ops[op_index];22330 dst_temp.tracking(cg).short.register,
21326 },22331 @intCast(dst_ty.abiSize(cg.pt.zcu)),
21327 .gpr => {22332 ) },
21328 dst_temp.* = try cg.tempAllocReg(ty, abi.RegisterClass.gp);22333 .mm, .mm_mask, .mm_sign_mask => @panic("TODO"),
21329 mir_op.* = .{ .reg = registerAlias(22334 .xmm, .xmm_mask, .xmm_sign_mask => .{ .reg = dst_temp.tracking(cg).short.register.to128() },
21330 dst_temp.tracking(cg).short.register,22335 .ymm, .ymm_mask, .ymm_sign_mask => .{ .reg = dst_temp.tracking(cg).short.register.to256() },
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 },
21343 .mem => @panic("TODO"),22336 .mem => @panic("TODO"),
21344 .gpr_limb => {22337 .gpr_limb => .{ .reg = extra_temp.?.tracking(cg).short.register.to64() },
21345 dst_temp.* = try cg.tempAlloc(ty);22338 .mm_limb => .{ .reg = extra_temp.?.tracking(cg).short.register },
21346 extra_temp.* = try cg.tempAllocReg(Type.usize, abi.RegisterClass.gp);22339 .xmm_limb => .{ .reg = extra_temp.?.tracking(cg).short.register.to128() },
21347 mir_op.* = .{ .reg = extra_temp.*.?.tracking(cg).short.register.to64() };22340 .ymm_limb => .{ .reg = extra_temp.?.tracking(cg).short.register.to256() },
21348 },22341 .mem_limb => .{ .mem = try dst_temp.tracking(cg).short.mem(cg, switch (loop.limb_offset) {
21349 .mm_limb => {22342 .unused => unreachable,
21350 dst_temp.* = try cg.tempAlloc(ty);22343 .known => |limb_offset| .{
21351 extra_temp.* = try cg.tempAllocReg(Type.usize, @panic("TODO"));22344 .size = .fromSize(loop.limb_size.?),
21352 mir_op.* = .{ .reg = extra_temp.*.?.tracking(cg).short.register };22345 .disp = limb_offset,
21353 },22346 },
21354 .xmm_limb => {22347 .temp => |limb_offset| .{
21355 dst_temp.* = try cg.tempAlloc(ty);22348 .size = .fromSize(loop.limb_size.?),
21356 extra_temp.* = try cg.tempAllocReg(Type.usize, abi.RegisterClass.sse);22349 .index = limb_offset.tracking(cg).short.register.to64(),
21357 mir_op.* = .{ .reg = extra_temp.*.?.tracking(cg).short.register.to128() };22350 },
21358 },22351 }) },
21359 .ymm_limb => {22352 .mm_mask_limb => .{ .reg = extra_temp.?.tracking(cg).short.register },
21360 dst_temp.* = try cg.tempAlloc(ty);22353 .xmm_mask_limb => .{ .reg = extra_temp.?.tracking(cg).short.register.to128() },
21361 extra_temp.* = try cg.tempAllocReg(Type.usize, abi.RegisterClass.sse);22354 .ymm_mask_limb => .{ .reg = extra_temp.?.tracking(cg).short.register.to256() },
21362 mir_op.* = .{ .reg = extra_temp.*.?.tracking(cg).short.register.to256() };22355 .imm, .simm32, .umax_gpr, .umax_mm, .umax_xmm, .umax_ymm => unreachable, // unmodifiable destination
21363 },22356 };
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 }
21380 }22357 }
21381 std.mem.swap(Operand, &mir_ops[pattern.commute[0]], &mir_ops[pattern.commute[1]]);22358 std.mem.swap(Operand, &mir_ops[pattern.commute[0]], &mir_ops[pattern.commute[1]]);
22359 if (pattern_set.clobbers.eflags) try cg.spillEflagsIfOccupied();
21382 cg.asmOps(pattern_set.mir_tag, mir_ops) catch |err| switch (err) {22360 cg.asmOps(pattern_set.mir_tag, mir_ops) catch |err| switch (err) {
21383 error.InvalidInstruction => {22361 error.InvalidInstruction => {
21384 const fixes = @tagName(pattern_set.mir_tag[0]);22362 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...@@ -21398,42 +22376,223 @@ fn select(cg: *CodeGen, dst_temps: []Temp, src_temps: []const *Temp, pattern_set
21398 },22376 },
21399 else => |e| return e,22377 else => |e| return e,
21400 };22378 };
22379 const invert_result = opts.invert_result != pattern_set.invert_result;
21401 for (22380 for (
21402 extra_temps[0..dst_temps.len],22381 extra_temps[0..dst_temps.len],
21403 pattern.ops[0..dst_temps.len],22382 pattern.ops[0..dst_temps.len],
22383 mir_ops[0..dst_temps.len],
21404 dst_temps,22384 dst_temps,
21405 ) |maybe_extra_temp, dst_op, dst_temp| if (maybe_extra_temp) |extra_temp| switch (dst_op) {22385 ) |extra_temp, dst_op, mir_op, dst_temp| switch (dst_op) {
21406 else => {},22386 else => if (invert_result) {
21407 .gpr_limb, .mm_limb, .xmm_limb, .ymm_limb => switch (dst_temp.tracking(cg).short) {22387 try cg.spillEflagsIfOccupied();
21408 .register_pair => |dst_regs| switch (loop.limb_offset) {22388 cg.asmOps(
21409 .unused => unreachable,22389 .{ ._, .not },
21410 .known => |limb_offset| try cg.asmRegisterRegister(22390 .{ mir_op, .none, .none, .none },
21411 .{ ._, .mov },22391 ) catch |err| switch (err) {
21412 dst_regs[@divExact(limb_offset, loop.limb_size.?)].to64(),22392 error.InvalidInstruction => return cg.fail(
21413 extra_temp.tracking(cg).short.register.to64(),22393 "invalid instruction: 'not {s} none none none'",
22394 .{@tagName(mir_op)},
21414 ),22395 ),
21415 .temp => unreachable,22396 else => |e| return e,
21416 },22397 };
21417 else => |dst_mcv| try cg.asmMemoryRegister(22398 },
21418 switch (dst_op) {22399 .mm_mask,
21419 else => unreachable,22400 .xmm_mask,
21420 .gpr_limb => .{ ._, .mov },22401 .ymm_mask,
21421 .mm_limb => .{ ._q, .mov },22402 .mm_sign_mask,
21422 .xmm_limb, .ymm_limb => .{ if (cg.hasFeature(.avx)) .v_ else ._, .movdqu },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,
21423 },22426 },
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) {
21425 .unused => unreachable,22489 .unused => unreachable,
21426 .known => |limb_offset| .{22490 .known => |mask_limb_offset| switch (mask_limb_offset & (loop.mask_store_bit_size.? - 1)) {
21427 .size = .fromSize(loop.limb_size.?),22491 0 => try cg.asmRegisterRegister(.{ ._, .mov }, mask_store_alias, mask_limb_reg),
21428 .disp = limb_offset,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 },
21429 },22498 },
21430 .temp => |limb_offset| .{22499 .temp => |mask_limb_offset| {
21431 .size = .fromSize(loop.limb_size.?),22500 if (cg.hasFeature(.bmi2)) {
21432 .index = limb_offset.tracking(cg).short.register.to64(),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);
21433 },22519 },
21434 }),22520 }
21435 registerAlias(extra_temp.tracking(cg).short.register, loop.limb_size.?),22521 }
21436 ),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 }
21437 },22596 },
21438 };22597 };
21439 switch (pattern_set.loop) {22598 switch (pattern_set.loop) {
...@@ -21442,7 +22601,7 @@ fn select(cg: *CodeGen, dst_temps: []Temp, src_temps: []const *Temp, pattern_set...@@ -21442,7 +22601,7 @@ fn select(cg: *CodeGen, dst_temps: []Temp, src_temps: []const *Temp, pattern_set
21442 .limbwise_carry => @panic("TODO"),22601 .limbwise_carry => @panic("TODO"),
21443 .limbwise_pairs_forward => @panic("TODO"),22602 .limbwise_pairs_forward => @panic("TODO"),
21444 .limbwise_pairs_reverse => @panic("TODO"),22603 .limbwise_pairs_reverse => @panic("TODO"),
21445 .elementwise => @panic("TODO"),22604 .elementwise => {},
21446 }22605 }
21447 switch (loop.limb_offset) {22606 switch (loop.limb_offset) {
21448 .unused => break,22607 .unused => break,
...@@ -21452,6 +22611,11 @@ fn select(cg: *CodeGen, dst_temps: []Temp, src_temps: []const *Temp, pattern_set...@@ -21452,6 +22611,11 @@ fn select(cg: *CodeGen, dst_temps: []Temp, src_temps: []const *Temp, pattern_set
21452 if (loop.remaining_size.? < loop.limb_size.? or22611 if (loop.remaining_size.? < loop.limb_size.? or
21453 (loop.element_size != null and limb_offset.* >= loop.element_size.?))22612 (loop.element_size != null and limb_offset.* >= loop.element_size.?))
21454 {22613 {
22614 switch (loop.mask_limb_offset) {
22615 .unused => {},
22616 .known => |*mask_limb_offset| mask_limb_offset.* = 0,
22617 .temp => unreachable,
22618 }
21455 limb_offset.* = 0;22619 limb_offset.* = 0;
21456 break;22620 break;
21457 }22621 }
...@@ -21465,6 +22629,7 @@ fn select(cg: *CodeGen, dst_temps: []Temp, src_temps: []const *Temp, pattern_set...@@ -21465,6 +22629,7 @@ fn select(cg: *CodeGen, dst_temps: []Temp, src_temps: []const *Temp, pattern_set
21465 .disp = loop.limb_size.?,22629 .disp = loop.limb_size.?,
21466 } },22630 } },
21467 });22631 });
22632 try cg.spillEflagsIfOccupied();
21468 try cg.asmRegisterImmediate(22633 try cg.asmRegisterImmediate(
21469 .{ ._, .cmp },22634 .{ ._, .cmp },
21470 limb_offset_reg.to32(),22635 limb_offset_reg.to32(),
...@@ -21476,6 +22641,12 @@ fn select(cg: *CodeGen, dst_temps: []Temp, src_temps: []const *Temp, pattern_set...@@ -21476,6 +22641,12 @@ fn select(cg: *CodeGen, dst_temps: []Temp, src_temps: []const *Temp, pattern_set
21476 },22641 },
21477 }22642 }
21478 }22643 }
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 }
21479 switch (loop.element_offset) {22650 switch (loop.element_offset) {
21480 .unused => break :pattern_sets,22651 .unused => break :pattern_sets,
21481 .known => |*element_offset| {22652 .known => |*element_offset| {
src/arch/x86_64/Disassembler.zig+1-1
...@@ -223,7 +223,7 @@ pub fn next(dis: *Disassembler) Error!?Instruction {...@@ -223,7 +223,7 @@ pub fn next(dis: *Disassembler) Error!?Instruction {
223 .op3 = op3,223 .op3 = op3,
224 });224 });
225 },225 },
226 .rm0, .vmi, .rvm, .rvmr, .rvmi, .mvr => unreachable, // TODO226 .rm0, .vmi, .rvm, .rvmr, .rvmi, .mvr, .rmv => unreachable, // TODO
227 }227 }
228}228}
229229
src/arch/x86_64/Encoding.zig+7-6
...@@ -177,7 +177,7 @@ pub fn format(...@@ -177,7 +177,7 @@ pub fn format(
177 try writer.print("+{s} ", .{tag});177 try writer.print("+{s} ", .{tag});
178 },178 },
179 .m, .mi, .m1, .mc, .vmi => try writer.print("/{d} ", .{encoding.modRmExt()}),179 .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 "),
181 }181 }
182182
183 switch (encoding.data.op_en) {183 switch (encoding.data.op_en) {
...@@ -202,7 +202,7 @@ pub fn format(...@@ -202,7 +202,7 @@ pub fn format(
202 try writer.print("{s} ", .{tag});202 try writer.print("{s} ", .{tag});
203 },203 },
204 .rvmr => try writer.writeAll("/is4 "),204 .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 => {},
206 }206 }
207207
208 try writer.print("{s} ", .{@tagName(encoding.mnemonic)});208 try writer.print("{s} ", .{@tagName(encoding.mnemonic)});
...@@ -260,10 +260,10 @@ pub const Mnemonic = enum {...@@ -260,10 +260,10 @@ pub const Mnemonic = enum {
260 neg, nop, not,260 neg, nop, not,
261 @"or",261 @"or",
262 pause, pop, popcnt, popfq, push, pushfq,262 pause, pop, popcnt, popfq, push, pushfq,
263 rcl, rcr, ret, rol, ror,263 rcl, rcr, ret, rol, ror, rorx,
264 sal, sar, sbb,264 sal, sar, sarx, sbb,
265 scas, scasb, scasd, scasq, scasw,265 scas, scasb, scasd, scasq, scasw,
266 shl, shld, shr, shrd, sub, syscall,266 shl, shld, shlx, shr, shrd, shrx, sub, syscall,
267 seta, setae, setb, setbe, setc, sete, setg, setge, setl, setle, setna, setnae,267 seta, setae, setb, setbe, setc, sete, setg, setge, setl, setle, setna, setnae,
268 setnb, setnbe, setnc, setne, setng, setnge, setnl, setnle, setno, setnp, setns,268 setnb, setnbe, setnc, setne, setng, setnge, setnl, setnle, setno, setnp, setns,
269 setnz, seto, setp, setpe, setpo, sets, setz,269 setnz, seto, setp, setpe, setpo, sets, setz,
...@@ -444,7 +444,7 @@ pub const OpEn = enum {...@@ -444,7 +444,7 @@ pub const OpEn = enum {
444 fd, td,444 fd, td,
445 m1, mc, mi, mr, rm,445 m1, mc, mi, mr, rm,
446 rmi, mri, mrc,446 rmi, mri, mrc,
447 rm0, vmi, rvm, rvmr, rvmi, mvr,447 rm0, vmi, rvm, rvmr, rvmi, mvr, rmv,
448 // zig fmt: on448 // zig fmt: on
449};449};
450450
...@@ -808,6 +808,7 @@ pub const Feature = enum {...@@ -808,6 +808,7 @@ pub const Feature = enum {
808 avx,808 avx,
809 avx2,809 avx2,
810 bmi,810 bmi,
811 bmi2,
811 f16c,812 f16c,
812 fma,813 fma,
813 lzcnt,814 lzcnt,
src/arch/x86_64/Mir.zig+8
...@@ -29,10 +29,14 @@ pub const Inst = struct {...@@ -29,10 +29,14 @@ pub const Inst = struct {
29 _l,29 _l,
30 /// ___ Left Double30 /// ___ Left Double
31 _ld,31 _ld,
32 /// ___ Left Without Affecting Flags
33 _lx,
32 /// ___ Right34 /// ___ Right
33 _r,35 _r,
34 /// ___ Right Double36 /// ___ Right Double
35 _rd,37 _rd,
38 /// ___ Right Without Affecting Flags
39 _rx,
3640
37 /// ___ Above41 /// ___ Above
38 _a,42 _a,
...@@ -401,9 +405,11 @@ pub const Inst = struct {...@@ -401,9 +405,11 @@ pub const Inst = struct {
401 ret,405 ret,
402 /// Rotate left406 /// Rotate left
403 /// Rotate right407 /// Rotate right
408 /// Rotate right logical without affecting flags
404 ro,409 ro,
405 /// Arithmetic shift left410 /// Arithmetic shift left
406 /// Arithmetic shift right411 /// Arithmetic shift right
412 /// Shift left arithmetic without affecting flags
407 sa,413 sa,
408 /// Integer subtraction with borrow414 /// Integer subtraction with borrow
409 sbb,415 sbb,
...@@ -417,6 +423,8 @@ pub const Inst = struct {...@@ -417,6 +423,8 @@ pub const Inst = struct {
417 /// Double precision shift left423 /// Double precision shift left
418 /// Logical shift right424 /// Logical shift right
419 /// Double precision shift right425 /// Double precision shift right
426 /// Shift left logical without affecting flags
427 /// Shift right logical without affecting flags
420 sh,428 sh,
421 /// Subtract429 /// Subtract
422 /// Subtract packed integers430 /// 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...@@ -242,8 +242,12 @@ pub fn classifySystemV(ty: Type, zcu: *Zcu, target: std.Target, ctx: Context) [8
242 .sse, .sseup, .sseup, .sseup,242 .sse, .sseup, .sseup, .sseup,
243 .sseup, .sseup, .sseup, .none,243 .sseup, .sseup, .sseup, .none,
244 };244 };
245 // LLVM always returns vectors byval245 if (bits <= 512 or (ctx == .ret and bits <= @as(u64, if (std.Target.x86.featureSetHas(target.cpu.features, .avx512f))
246 if (bits <= 512 or ctx == .ret) return .{246 2048
247 else if (std.Target.x86.featureSetHas(target.cpu.features, .avx))
248 1024
249 else
250 512))) return .{
247 .sse, .sseup, .sseup, .sseup,251 .sse, .sseup, .sseup, .sseup,
248 .sseup, .sseup, .sseup, .sseup,252 .sseup, .sseup, .sseup, .sseup,
249 };253 };
...@@ -416,7 +420,7 @@ pub const SysV = struct {...@@ -416,7 +420,7 @@ pub const SysV = struct {
416 pub const c_abi_int_param_regs = [_]Register{ .rdi, .rsi, .rdx, .rcx, .r8, .r9 };420 pub const c_abi_int_param_regs = [_]Register{ .rdi, .rsi, .rdx, .rcx, .r8, .r9 };
417 pub const c_abi_sse_param_regs = sse_avx_regs[0..8].*;421 pub const c_abi_sse_param_regs = sse_avx_regs[0..8].*;
418 pub const c_abi_int_return_regs = [_]Register{ .rax, .rdx };422 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].*;
420};424};
421425
422pub const Win64 = struct {426pub const Win64 = struct {
...@@ -496,7 +500,7 @@ pub fn getCAbiSseReturnRegs(cc: std.builtin.CallingConvention) []const Register...@@ -496,7 +500,7 @@ pub fn getCAbiSseReturnRegs(cc: std.builtin.CallingConvention) []const Register
496}500}
497501
498const gp_regs = [_]Register{502const 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,
500};504};
501const x87_regs = [_]Register{505const x87_regs = [_]Register{
502 .st0, .st1, .st2, .st3, .st4, .st5, .st6, .st7,506 .st0, .st1, .st2, .st3, .st4, .st5, .st6, .st7,
src/arch/x86_64/encoder.zig+10-9
...@@ -403,7 +403,7 @@ pub const Instruction = struct {...@@ -403,7 +403,7 @@ pub const Instruction = struct {
403 else => {403 else => {
404 const mem_op = switch (data.op_en) {404 const mem_op = switch (data.op_en) {
405 .m, .mi, .m1, .mc, .mr, .mri, .mrc, .mvr => inst.ops[0],405 .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],
407 .rvm, .rvmr, .rvmi => inst.ops[2],407 .rvm, .rvmr, .rvmi => inst.ops[2],
408 else => unreachable,408 else => unreachable,
409 };409 };
...@@ -412,7 +412,7 @@ pub const Instruction = struct {...@@ -412,7 +412,7 @@ pub const Instruction = struct {
412 const rm = switch (data.op_en) {412 const rm = switch (data.op_en) {
413 .m, .mi, .m1, .mc, .vmi => enc.modRmExt(),413 .m, .mi, .m1, .mc, .vmi => enc.modRmExt(),
414 .mr, .mri, .mrc => inst.ops[1].reg.lowEnc(),414 .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(),
416 .mvr => inst.ops[2].reg.lowEnc(),416 .mvr => inst.ops[2].reg.lowEnc(),
417 else => unreachable,417 else => unreachable,
418 };418 };
...@@ -422,7 +422,7 @@ pub const Instruction = struct {...@@ -422,7 +422,7 @@ pub const Instruction = struct {
422 const op = switch (data.op_en) {422 const op = switch (data.op_en) {
423 .m, .mi, .m1, .mc, .vmi => .none,423 .m, .mi, .m1, .mc, .vmi => .none,
424 .mr, .mri, .mrc => inst.ops[1],424 .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],
426 .mvr => inst.ops[2],426 .mvr => inst.ops[2],
427 else => unreachable,427 else => unreachable,
428 };428 };
...@@ -493,7 +493,7 @@ pub const Instruction = struct {...@@ -493,7 +493,7 @@ pub const Instruction = struct {
493 }493 }
494 else494 else
495 null,495 null,
496 .vmi, .rvm, .rvmr, .rvmi, .mvr => unreachable,496 .vmi, .rvm, .rvmr, .rvmi, .mvr, .rmv => unreachable,
497 };497 };
498 if (segment_override) |seg| {498 if (segment_override) |seg| {
499 legacy.setSegmentOverride(seg);499 legacy.setSegmentOverride(seg);
...@@ -512,9 +512,9 @@ pub const Instruction = struct {...@@ -512,9 +512,9 @@ pub const Instruction = struct {
512 switch (op_en) {512 switch (op_en) {
513 .zo, .i, .zi, .fd, .td, .d => {},513 .zo, .i, .zi, .fd, .td, .d => {},
514 .o, .oi => rex.b = inst.ops[0].reg.isExtended(),514 .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 => {
516 const r_op = switch (op_en) {516 const r_op = switch (op_en) {
517 .rm, .rmi, .rm0 => inst.ops[0],517 .rm, .rmi, .rm0, .rmv => inst.ops[0],
518 .mr, .mri, .mrc => inst.ops[1],518 .mr, .mri, .mrc => inst.ops[1],
519 else => .none,519 else => .none,
520 };520 };
...@@ -546,9 +546,9 @@ pub const Instruction = struct {...@@ -546,9 +546,9 @@ pub const Instruction = struct {
546 switch (op_en) {546 switch (op_en) {
547 .zo, .i, .zi, .fd, .td, .d => {},547 .zo, .i, .zi, .fd, .td, .d => {},
548 .o, .oi => vex.b = inst.ops[0].reg.isExtended(),548 .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 => {
550 const r_op = switch (op_en) {550 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],
552 .mr, .mri, .mrc => inst.ops[1],552 .mr, .mri, .mrc => inst.ops[1],
553 .mvr => inst.ops[2],553 .mvr => inst.ops[2],
554 .m, .mi, .m1, .mc, .vmi => .none,554 .m, .mi, .m1, .mc, .vmi => .none,
...@@ -557,7 +557,7 @@ pub const Instruction = struct {...@@ -557,7 +557,7 @@ pub const Instruction = struct {
557 vex.r = r_op.isBaseExtended();557 vex.r = r_op.isBaseExtended();
558558
559 const b_x_op = switch (op_en) {559 const b_x_op = switch (op_en) {
560 .rm, .rmi, .rm0, .vmi => inst.ops[1],560 .rm, .rmi, .rm0, .vmi, .rmv => inst.ops[1],
561 .m, .mi, .m1, .mc, .mr, .mri, .mrc, .mvr => inst.ops[0],561 .m, .mi, .m1, .mc, .mr, .mri, .mrc, .mvr => inst.ops[0],
562 .rvm, .rvmr, .rvmi => inst.ops[2],562 .rvm, .rvmr, .rvmi => inst.ops[2],
563 else => unreachable,563 else => unreachable,
...@@ -588,6 +588,7 @@ pub const Instruction = struct {...@@ -588,6 +588,7 @@ pub const Instruction = struct {
588 else => {},588 else => {},
589 .vmi => vex.v = inst.ops[0].reg,589 .vmi => vex.v = inst.ops[0].reg,
590 .rvm, .rvmr, .rvmi => vex.v = inst.ops[1].reg,590 .rvm, .rvmr, .rvmi => vex.v = inst.ops[1].reg,
591 .rmv => vex.v = inst.ops[2].reg,
591 }592 }
592593
593 try encoder.vex(vex);594 try encoder.vex(vex);
src/arch/x86_64/encodings.zig+10
...@@ -1287,6 +1287,16 @@ pub const table = [_]Entry{...@@ -1287,6 +1287,16 @@ pub const table = [_]Entry{
1287 .{ .sha256rnds2, .rm0, &.{ .xmm, .xmm_m128, .xmm0 }, &.{ 0x0f, 0x38, 0xcb }, 0, .none, .sha },1287 .{ .sha256rnds2, .rm0, &.{ .xmm, .xmm_m128, .xmm0 }, &.{ 0x0f, 0x38, 0xcb }, 0, .none, .sha },
12881288
1289 // AVX1289 // 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
1290 .{ .vaddpd, .rvm, &.{ .xmm, .xmm, .xmm_m128 }, &.{ 0x66, 0x0f, 0x58 }, 0, .vex_128_wig, .avx },1300 .{ .vaddpd, .rvm, &.{ .xmm, .xmm, .xmm_m128 }, &.{ 0x66, 0x0f, 0x58 }, 0, .vex_128_wig, .avx },
1291 .{ .vaddpd, .rvm, &.{ .ymm, .ymm, .ymm_m256 }, &.{ 0x66, 0x0f, 0x58 }, 0, .vex_256_wig, .avx },1301 .{ .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(...@@ -112,6 +112,9 @@ pub fn RegisterManager(
112 pub fn indexOfRegIntoTracked(reg: Register) ?TrackedIndex {112 pub fn indexOfRegIntoTracked(reg: Register) ?TrackedIndex {
113 return indexOfReg(tracked_registers, reg);113 return indexOfReg(tracked_registers, reg);
114 }114 }
115 pub inline fn indexOfKnownRegIntoTracked(comptime reg: Register) ?TrackedIndex {
116 return comptime indexOfRegIntoTracked(reg);
117 }
115118
116 pub fn regAtTrackedIndex(tracked_index: TrackedIndex) Register {119 pub fn regAtTrackedIndex(tracked_index: TrackedIndex) Register {
117 return tracked_registers[tracked_index];120 return tracked_registers[tracked_index];
...@@ -124,6 +127,9 @@ pub fn RegisterManager(...@@ -124,6 +127,9 @@ pub fn RegisterManager(
124 pub fn isRegFree(self: Self, reg: Register) bool {127 pub fn isRegFree(self: Self, reg: Register) bool {
125 return self.isRegIndexFree(indexOfRegIntoTracked(reg) orelse return true);128 return self.isRegIndexFree(indexOfRegIntoTracked(reg) orelse return true);
126 }129 }
130 pub fn isKnownRegFree(self: Self, comptime reg: Register) bool {
131 return self.isRegIndexFree(indexOfKnownRegIntoTracked(reg) orelse return true);
132 }
127133
128 /// Returns whether this register was allocated in the course134 /// Returns whether this register was allocated in the course
129 /// of this function.135 /// of this function.
...@@ -143,6 +149,9 @@ pub fn RegisterManager(...@@ -143,6 +149,9 @@ pub fn RegisterManager(
143 pub fn isRegLocked(self: Self, reg: Register) bool {149 pub fn isRegLocked(self: Self, reg: Register) bool {
144 return self.isRegIndexLocked(indexOfRegIntoTracked(reg) orelse return false);150 return self.isRegIndexLocked(indexOfRegIntoTracked(reg) orelse return false);
145 }151 }
152 pub fn isKnownRegLocked(self: Self, comptime reg: Register) bool {
153 return self.isRegIndexLocked(indexOfKnownRegIntoTracked(reg) orelse return false);
154 }
146155
147 pub const RegisterLock = struct { tracked_index: TrackedIndex };156 pub const RegisterLock = struct { tracked_index: TrackedIndex };
148157
...@@ -176,6 +185,9 @@ pub fn RegisterManager(...@@ -176,6 +185,9 @@ pub fn RegisterManager(
176 pub fn lockRegAssumeUnused(self: *Self, reg: Register) RegisterLock {185 pub fn lockRegAssumeUnused(self: *Self, reg: Register) RegisterLock {
177 return self.lockRegIndexAssumeUnused(indexOfRegIntoTracked(reg) orelse unreachable);186 return self.lockRegIndexAssumeUnused(indexOfRegIntoTracked(reg) orelse unreachable);
178 }187 }
188 pub fn lockKnownRegAssumeUnused(self: *Self, comptime reg: Register) RegisterLock {
189 return self.lockRegIndexAssumeUnused(indexOfKnownRegIntoTracked(reg) orelse unreachable);
190 }
179191
180 /// Like `lockReg` but locks multiple registers.192 /// Like `lockReg` but locks multiple registers.
181 pub fn lockRegs(193 pub fn lockRegs(
...@@ -366,7 +378,7 @@ pub fn RegisterManager(...@@ -366,7 +378,7 @@ pub fn RegisterManager(
366 comptime reg: Register,378 comptime reg: Register,
367 inst: ?Air.Inst.Index,379 inst: ?Air.Inst.Index,
368 ) AllocationError!void {380 ) AllocationError!void {
369 return self.getRegIndex((comptime indexOfRegIntoTracked(reg)) orelse return, inst);381 return self.getRegIndex(indexOfKnownRegIntoTracked(reg) orelse return, inst);
370 }382 }
371383
372 /// Allocates the specified register with the specified384 /// Allocates the specified register with the specified
test/behavior.zig+2
...@@ -110,6 +110,8 @@ test {...@@ -110,6 +110,8 @@ test {
110 _ = @import("behavior/widening.zig");110 _ = @import("behavior/widening.zig");
111 _ = @import("behavior/abs.zig");111 _ = @import("behavior/abs.zig");
112112
113 _ = @import("behavior/x86_64.zig");
114
113 if (builtin.cpu.arch == .wasm32) {115 if (builtin.cpu.arch == .wasm32) {
114 _ = @import("behavior/wasm.zig");116 _ = @import("behavior/wasm.zig");
115 }117 }
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}