authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2024-06-19 17:42:08+02:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2024-06-19 17:42:08+02:00
loga154d8da8e39e5d0ed180b4a1e5150349699e5df
tree5874c40fd206987d89d5118e3a49fa08c22552fc
parent1fdf13a14825d6e1bd247754e3677cf546ee4020
parente60c5811473df6c092aa772b63f2cf5d27b7ff46
signaturebadge-check Signed by PGP key B5690EEEBB952194

Merge pull request #20070 from Rexicon226/riscv

more RISC-V backend progress

74 files changed, 4762 insertions(+), 3106 deletions(-)

lib/compiler/test_runner.zig+20-28
......@@ -12,10 +12,8 @@ var cmdline_buffer: [4096]u8 = undefined;
1212var fba = std.heap.FixedBufferAllocator.init(&cmdline_buffer);
1313
1414pub fn main() void {
15 if (builtin.zig_backend == .stage2_riscv64) return mainExtraSimple() catch @panic("test failure");
16
17 if (builtin.zig_backend == .stage2_aarch64) {
18 return mainSimple() catch @panic("test failure");
15 if (builtin.zig_backend == .stage2_riscv64) {
16 return mainSimple() catch @panic("test failure\n");
1917 }
2018
2119 const args = std.process.argsAlloc(fba.allocator()) catch
......@@ -221,20 +219,30 @@ pub fn log(
221219/// Simpler main(), exercising fewer language features, so that
222220/// work-in-progress backends can handle it.
223221pub fn mainSimple() anyerror!void {
224 const enable_print = false;
225 const print_all = false;
222 // is the backend capable of printing to stderr?
223 const enable_print = switch (builtin.zig_backend) {
224 .stage2_riscv64 => true,
225 else => false,
226 };
227 // is the backend capable of using std.fmt.format to print a summary at the end?
228 const print_summary = switch (builtin.zig_backend) {
229 else => false,
230 };
226231
227232 var passed: u64 = 0;
228233 var skipped: u64 = 0;
229234 var failed: u64 = 0;
230 const stderr = if (enable_print) std.io.getStdErr() else {};
235
236 // we don't want to bring in File and Writer if the backend doesn't support it
237 const stderr = if (comptime enable_print) std.io.getStdErr() else {};
238
231239 for (builtin.test_functions) |test_fn| {
232 if (enable_print and print_all) {
240 if (enable_print) {
233241 stderr.writeAll(test_fn.name) catch {};
234242 stderr.writeAll("... ") catch {};
235243 }
236244 test_fn.func() catch |err| {
237 if (enable_print and !print_all) {
245 if (enable_print) {
238246 stderr.writeAll(test_fn.name) catch {};
239247 stderr.writeAll("... ") catch {};
240248 }
......@@ -248,27 +256,11 @@ pub fn mainSimple() anyerror!void {
248256 skipped += 1;
249257 continue;
250258 };
251 if (enable_print and print_all) stderr.writeAll("PASS\n") catch {};
259 if (enable_print) stderr.writeAll("PASS\n") catch {};
252260 passed += 1;
253261 }
254 if (enable_print) {
262 if (enable_print and print_summary) {
255263 stderr.writer().print("{} passed, {} skipped, {} failed\n", .{ passed, skipped, failed }) catch {};
256 if (failed != 0) std.process.exit(1);
257 }
258}
259
260pub fn mainExtraSimple() !void {
261 var fail_count: u8 = 0;
262
263 for (builtin.test_functions) |test_fn| {
264 test_fn.func() catch |err| {
265 if (err != error.SkipZigTest) {
266 fail_count += 1;
267 continue;
268 }
269 continue;
270 };
271264 }
272
273 if (fail_count != 0) std.process.exit(1);
265 if (failed != 0) std.process.exit(1);
274266}
src/arch/riscv64/CodeGen.zig+3599-2270
......@@ -22,6 +22,8 @@ const DW = std.dwarf;
2222const leb128 = std.leb;
2323const log = std.log.scoped(.riscv_codegen);
2424const tracking_log = std.log.scoped(.tracking);
25const verbose_tracking_log = std.log.scoped(.verbose_tracking);
26const wip_mir_log = std.log.scoped(.wip_mir);
2527const build_options = @import("build_options");
2628const codegen = @import("../../codegen.zig");
2729const Alignment = InternPool.Alignment;
......@@ -32,29 +34,17 @@ const DebugInfoOutput = codegen.DebugInfoOutput;
3234
3335const bits = @import("bits.zig");
3436const abi = @import("abi.zig");
37const Lower = @import("Lower.zig");
38
3539const Register = bits.Register;
3640const Immediate = bits.Immediate;
3741const Memory = bits.Memory;
3842const FrameIndex = bits.FrameIndex;
3943const RegisterManager = abi.RegisterManager;
4044const RegisterLock = RegisterManager.RegisterLock;
41const callee_preserved_regs = abi.callee_preserved_regs;
42/// General Purpose
43const gp = abi.RegisterClass.gp;
44/// Function Args
45const fa = abi.RegisterClass.fa;
46/// Function Returns
47const fr = abi.RegisterClass.fr;
48/// Temporary Use
49const tp = abi.RegisterClass.tp;
5045
5146const InnerError = CodeGenError || error{OutOfRegisters};
5247
53const RegisterView = enum(u1) {
54 caller,
55 callee,
56};
57
5848gpa: Allocator,
5949air: Air,
6050mod: *Package.Module,
......@@ -172,6 +162,14 @@ const MCValue = union(enum) {
172162 };
173163 }
174164
165 fn isRegister(mcv: MCValue) bool {
166 return switch (mcv) {
167 .register => true,
168 .register_offset => |reg_off| return reg_off.off == 0,
169 else => false,
170 };
171 }
172
175173 fn isMutable(mcv: MCValue) bool {
176174 return switch (mcv) {
177175 .none => unreachable,
......@@ -295,14 +293,15 @@ const MCValue = union(enum) {
295293const Branch = struct {
296294 inst_table: std.AutoArrayHashMapUnmanaged(Air.Inst.Index, MCValue) = .{},
297295
298 fn deinit(self: *Branch, gpa: Allocator) void {
299 self.inst_table.deinit(gpa);
300 self.* = undefined;
296 fn deinit(func: *Branch, gpa: Allocator) void {
297 func.inst_table.deinit(gpa);
298 func.* = undefined;
301299 }
302300};
303301
304302const InstTrackingMap = std.AutoArrayHashMapUnmanaged(Air.Inst.Index, InstTracking);
305303const ConstTrackingMap = std.AutoArrayHashMapUnmanaged(InternPool.Index, InstTracking);
304
306305const InstTracking = struct {
307306 long: MCValue,
308307 short: MCValue,
......@@ -331,33 +330,37 @@ const InstTracking = struct {
331330 }, .short = result };
332331 }
333332
334 fn getReg(self: InstTracking) ?Register {
335 return self.short.getReg();
333 fn getReg(inst_tracking: InstTracking) ?Register {
334 return inst_tracking.short.getReg();
336335 }
337336
338 fn getRegs(self: *const InstTracking) []const Register {
339 return self.short.getRegs();
337 fn getRegs(inst_tracking: *const InstTracking) []const Register {
338 return inst_tracking.short.getRegs();
340339 }
341340
342 fn spill(self: *InstTracking, function: *Self, inst: Air.Inst.Index) !void {
343 if (std.meta.eql(self.long, self.short)) return; // Already spilled
341 fn spill(inst_tracking: *InstTracking, function: *Func, inst: Air.Inst.Index) !void {
342 if (std.meta.eql(inst_tracking.long, inst_tracking.short)) return; // Already spilled
344343 // Allocate or reuse frame index
345 switch (self.long) {
346 .none => self.long = try function.allocRegOrMem(inst, false),
344 switch (inst_tracking.long) {
345 .none => inst_tracking.long = try function.allocRegOrMem(
346 function.typeOfIndex(inst),
347 inst,
348 false,
349 ),
347350 .load_frame => {},
348 .reserved_frame => |index| self.long = .{ .load_frame = .{ .index = index } },
351 .reserved_frame => |index| inst_tracking.long = .{ .load_frame = .{ .index = index } },
349352 else => unreachable,
350353 }
351 tracking_log.debug("spill %{d} from {} to {}", .{ inst, self.short, self.long });
352 try function.genCopy(function.typeOfIndex(inst), self.long, self.short);
354 tracking_log.debug("spill %{d} from {} to {}", .{ inst, inst_tracking.short, inst_tracking.long });
355 try function.genCopy(function.typeOfIndex(inst), inst_tracking.long, inst_tracking.short);
353356 }
354357
355 fn reuseFrame(self: *InstTracking) void {
356 switch (self.long) {
357 .reserved_frame => |index| self.long = .{ .load_frame = .{ .index = index } },
358 fn reuseFrame(inst_tracking: *InstTracking) void {
359 switch (inst_tracking.long) {
360 .reserved_frame => |index| inst_tracking.long = .{ .load_frame = .{ .index = index } },
358361 else => {},
359362 }
360 self.short = switch (self.long) {
363 inst_tracking.short = switch (inst_tracking.long) {
361364 .none,
362365 .unreach,
363366 .undef,
......@@ -367,7 +370,7 @@ const InstTracking = struct {
367370 .lea_frame,
368371 .load_symbol,
369372 .lea_symbol,
370 => self.long,
373 => inst_tracking.long,
371374 .dead,
372375 .register,
373376 .register_pair,
......@@ -379,14 +382,14 @@ const InstTracking = struct {
379382 };
380383 }
381384
382 fn trackSpill(self: *InstTracking, function: *Self, inst: Air.Inst.Index) !void {
383 try function.freeValue(self.short);
384 self.reuseFrame();
385 tracking_log.debug("%{d} => {} (spilled)", .{ inst, self.* });
385 fn trackSpill(inst_tracking: *InstTracking, function: *Func, inst: Air.Inst.Index) !void {
386 try function.freeValue(inst_tracking.short);
387 inst_tracking.reuseFrame();
388 tracking_log.debug("%{d} => {} (spilled)", .{ inst, inst_tracking.* });
386389 }
387390
388 fn verifyMaterialize(self: InstTracking, target: InstTracking) void {
389 switch (self.long) {
391 fn verifyMaterialize(inst_tracking: InstTracking, target: InstTracking) void {
392 switch (inst_tracking.long) {
390393 .none,
391394 .unreach,
392395 .undef,
......@@ -395,7 +398,7 @@ const InstTracking = struct {
395398 .lea_frame,
396399 .load_symbol,
397400 .lea_symbol,
398 => assert(std.meta.eql(self.long, target.long)),
401 => assert(std.meta.eql(inst_tracking.long, target.long)),
399402 .load_frame,
400403 .reserved_frame,
401404 => switch (target.long) {
......@@ -416,73 +419,73 @@ const InstTracking = struct {
416419 }
417420
418421 fn materialize(
419 self: *InstTracking,
420 function: *Self,
422 inst_tracking: *InstTracking,
423 function: *Func,
421424 inst: Air.Inst.Index,
422425 target: InstTracking,
423426 ) !void {
424 self.verifyMaterialize(target);
425 try self.materializeUnsafe(function, inst, target);
427 inst_tracking.verifyMaterialize(target);
428 try inst_tracking.materializeUnsafe(function, inst, target);
426429 }
427430
428431 fn materializeUnsafe(
429 self: InstTracking,
430 function: *Self,
432 inst_tracking: InstTracking,
433 function: *Func,
431434 inst: Air.Inst.Index,
432435 target: InstTracking,
433436 ) !void {
434437 const ty = function.typeOfIndex(inst);
435 if ((self.long == .none or self.long == .reserved_frame) and target.long == .load_frame)
436 try function.genCopy(ty, target.long, self.short);
437 try function.genCopy(ty, target.short, self.short);
438 if ((inst_tracking.long == .none or inst_tracking.long == .reserved_frame) and target.long == .load_frame)
439 try function.genCopy(ty, target.long, inst_tracking.short);
440 try function.genCopy(ty, target.short, inst_tracking.short);
438441 }
439442
440 fn trackMaterialize(self: *InstTracking, inst: Air.Inst.Index, target: InstTracking) void {
441 self.verifyMaterialize(target);
443 fn trackMaterialize(inst_tracking: *InstTracking, inst: Air.Inst.Index, target: InstTracking) void {
444 inst_tracking.verifyMaterialize(target);
442445 // Don't clobber reserved frame indices
443 self.long = if (target.long == .none) switch (self.long) {
446 inst_tracking.long = if (target.long == .none) switch (inst_tracking.long) {
444447 .load_frame => |addr| .{ .reserved_frame = addr.index },
445 .reserved_frame => self.long,
448 .reserved_frame => inst_tracking.long,
446449 else => target.long,
447450 } else target.long;
448 self.short = target.short;
449 tracking_log.debug("%{d} => {} (materialize)", .{ inst, self.* });
451 inst_tracking.short = target.short;
452 tracking_log.debug("%{d} => {} (materialize)", .{ inst, inst_tracking.* });
450453 }
451454
452 fn resurrect(self: *InstTracking, inst: Air.Inst.Index, scope_generation: u32) void {
453 switch (self.short) {
455 fn resurrect(inst_tracking: *InstTracking, inst: Air.Inst.Index, scope_generation: u32) void {
456 switch (inst_tracking.short) {
454457 .dead => |die_generation| if (die_generation >= scope_generation) {
455 self.reuseFrame();
456 tracking_log.debug("%{d} => {} (resurrect)", .{ inst, self.* });
458 inst_tracking.reuseFrame();
459 tracking_log.debug("%{d} => {} (resurrect)", .{ inst, inst_tracking.* });
457460 },
458461 else => {},
459462 }
460463 }
461464
462 fn die(self: *InstTracking, function: *Self, inst: Air.Inst.Index) !void {
463 if (self.short == .dead) return;
464 try function.freeValue(self.short);
465 self.short = .{ .dead = function.scope_generation };
466 tracking_log.debug("%{d} => {} (death)", .{ inst, self.* });
465 fn die(inst_tracking: *InstTracking, function: *Func, inst: Air.Inst.Index) !void {
466 if (inst_tracking.short == .dead) return;
467 try function.freeValue(inst_tracking.short);
468 inst_tracking.short = .{ .dead = function.scope_generation };
469 tracking_log.debug("%{d} => {} (death)", .{ inst, inst_tracking.* });
467470 }
468471
469472 fn reuse(
470 self: *InstTracking,
471 function: *Self,
473 inst_tracking: *InstTracking,
474 function: *Func,
472475 new_inst: ?Air.Inst.Index,
473476 old_inst: Air.Inst.Index,
474477 ) void {
475 self.short = .{ .dead = function.scope_generation };
478 inst_tracking.short = .{ .dead = function.scope_generation };
476479 if (new_inst) |inst|
477 tracking_log.debug("%{d} => {} (reuse %{d})", .{ inst, self.*, old_inst })
480 tracking_log.debug("%{d} => {} (reuse %{d})", .{ inst, inst_tracking.*, old_inst })
478481 else
479 tracking_log.debug("tmp => {} (reuse %{d})", .{ self.*, old_inst });
482 tracking_log.debug("tmp => {} (reuse %{d})", .{ inst_tracking.*, old_inst });
480483 }
481484
482 fn liveOut(self: *InstTracking, function: *Self, inst: Air.Inst.Index) void {
483 for (self.getRegs()) |reg| {
485 fn liveOut(inst_tracking: *InstTracking, function: *Func, inst: Air.Inst.Index) void {
486 for (inst_tracking.getRegs()) |reg| {
484487 if (function.register_manager.isRegFree(reg)) {
485 tracking_log.debug("%{d} => {} (live-out)", .{ inst, self.* });
488 tracking_log.debug("%{d} => {} (live-out)", .{ inst, inst_tracking.* });
486489 continue;
487490 }
488491
......@@ -509,18 +512,18 @@ const InstTracking = struct {
509512 // Perform side-effects of freeValue manually.
510513 function.register_manager.freeReg(reg);
511514
512 tracking_log.debug("%{d} => {} (live-out %{d})", .{ inst, self.*, tracked_inst });
515 tracking_log.debug("%{d} => {} (live-out %{d})", .{ inst, inst_tracking.*, tracked_inst });
513516 }
514517 }
515518
516519 pub fn format(
517 self: InstTracking,
520 inst_tracking: InstTracking,
518521 comptime _: []const u8,
519522 _: std.fmt.FormatOptions,
520523 writer: anytype,
521524 ) @TypeOf(writer).Error!void {
522 if (!std.meta.eql(self.long, self.short)) try writer.print("|{}| ", .{self.long});
523 try writer.print("{}", .{self.short});
525 if (!std.meta.eql(inst_tracking.long, inst_tracking.short)) try writer.print("|{}| ", .{inst_tracking.long});
526 try writer.print("{}", .{inst_tracking.short});
524527 }
525528};
526529
......@@ -560,19 +563,13 @@ const FrameAlloc = struct {
560563 }
561564};
562565
563const StackAllocation = struct {
564 inst: ?Air.Inst.Index,
565 /// TODO: make the size inferred from the bits of the inst
566 size: u32,
567};
568
569566const BlockData = struct {
570567 relocs: std.ArrayListUnmanaged(Mir.Inst.Index) = .{},
571568 state: State,
572569
573 fn deinit(self: *BlockData, gpa: Allocator) void {
574 self.relocs.deinit(gpa);
575 self.* = undefined;
570 fn deinit(bd: *BlockData, gpa: Allocator) void {
571 bd.relocs.deinit(gpa);
572 bd.* = undefined;
576573 }
577574};
578575
......@@ -584,31 +581,31 @@ const State = struct {
584581 scope_generation: u32,
585582};
586583
587fn initRetroactiveState(self: *Self) State {
584fn initRetroactiveState(func: *Func) State {
588585 var state: State = undefined;
589 state.inst_tracking_len = @intCast(self.inst_tracking.count());
590 state.scope_generation = self.scope_generation;
586 state.inst_tracking_len = @intCast(func.inst_tracking.count());
587 state.scope_generation = func.scope_generation;
591588 return state;
592589}
593590
594fn saveRetroactiveState(self: *Self, state: *State) !void {
595 const free_registers = self.register_manager.free_registers;
591fn saveRetroactiveState(func: *Func, state: *State) !void {
592 const free_registers = func.register_manager.free_registers;
596593 var it = free_registers.iterator(.{ .kind = .unset });
597594 while (it.next()) |index| {
598 const tracked_inst = self.register_manager.registers[index];
595 const tracked_inst = func.register_manager.registers[index];
599596 state.registers[index] = tracked_inst;
600 state.reg_tracking[index] = self.inst_tracking.get(tracked_inst).?;
597 state.reg_tracking[index] = func.inst_tracking.get(tracked_inst).?;
601598 }
602599 state.free_registers = free_registers;
603600}
604601
605fn saveState(self: *Self) !State {
606 var state = self.initRetroactiveState();
607 try self.saveRetroactiveState(&state);
602fn saveState(func: *Func) !State {
603 var state = func.initRetroactiveState();
604 try func.saveRetroactiveState(&state);
608605 return state;
609606}
610607
611fn restoreState(self: *Self, state: State, deaths: []const Air.Inst.Index, comptime opts: struct {
608fn restoreState(func: *Func, state: State, deaths: []const Air.Inst.Index, comptime opts: struct {
612609 emit_instructions: bool,
613610 update_tracking: bool,
614611 resurrect: bool,
......@@ -616,80 +613,81 @@ fn restoreState(self: *Self, state: State, deaths: []const Air.Inst.Index, compt
616613}) !void {
617614 if (opts.close_scope) {
618615 for (
619 self.inst_tracking.keys()[state.inst_tracking_len..],
620 self.inst_tracking.values()[state.inst_tracking_len..],
621 ) |inst, *tracking| try tracking.die(self, inst);
622 self.inst_tracking.shrinkRetainingCapacity(state.inst_tracking_len);
616 func.inst_tracking.keys()[state.inst_tracking_len..],
617 func.inst_tracking.values()[state.inst_tracking_len..],
618 ) |inst, *tracking| try tracking.die(func, inst);
619 func.inst_tracking.shrinkRetainingCapacity(state.inst_tracking_len);
623620 }
624621
625622 if (opts.resurrect) for (
626 self.inst_tracking.keys()[0..state.inst_tracking_len],
627 self.inst_tracking.values()[0..state.inst_tracking_len],
623 func.inst_tracking.keys()[0..state.inst_tracking_len],
624 func.inst_tracking.values()[0..state.inst_tracking_len],
628625 ) |inst, *tracking| tracking.resurrect(inst, state.scope_generation);
629 for (deaths) |death| try self.processDeath(death);
626 for (deaths) |death| try func.processDeath(death);
630627
631628 const ExpectedContents = [@typeInfo(RegisterManager.TrackedRegisters).Array.len]RegisterLock;
632629 var stack align(@max(@alignOf(ExpectedContents), @alignOf(std.heap.StackFallbackAllocator(0)))) =
633630 if (opts.update_tracking)
634 {} else std.heap.stackFallback(@sizeOf(ExpectedContents), self.gpa);
631 {} else std.heap.stackFallback(@sizeOf(ExpectedContents), func.gpa);
635632
636633 var reg_locks = if (opts.update_tracking) {} else try std.ArrayList(RegisterLock).initCapacity(
637634 stack.get(),
638635 @typeInfo(ExpectedContents).Array.len,
639636 );
640637 defer if (!opts.update_tracking) {
641 for (reg_locks.items) |lock| self.register_manager.unlockReg(lock);
638 for (reg_locks.items) |lock| func.register_manager.unlockReg(lock);
642639 reg_locks.deinit();
643640 };
644641
645642 for (0..state.registers.len) |index| {
646 const current_maybe_inst = if (self.register_manager.free_registers.isSet(index))
643 const current_maybe_inst = if (func.register_manager.free_registers.isSet(index))
647644 null
648645 else
649 self.register_manager.registers[index];
646 func.register_manager.registers[index];
650647 const target_maybe_inst = if (state.free_registers.isSet(index))
651648 null
652649 else
653650 state.registers[index];
654651 if (std.debug.runtime_safety) if (target_maybe_inst) |target_inst|
655 assert(self.inst_tracking.getIndex(target_inst).? < state.inst_tracking_len);
652 assert(func.inst_tracking.getIndex(target_inst).? < state.inst_tracking_len);
656653 if (opts.emit_instructions) {
657654 if (current_maybe_inst) |current_inst| {
658 try self.inst_tracking.getPtr(current_inst).?.spill(self, current_inst);
655 try func.inst_tracking.getPtr(current_inst).?.spill(func, current_inst);
659656 }
660657 if (target_maybe_inst) |target_inst| {
661 const target_tracking = self.inst_tracking.getPtr(target_inst).?;
662 try target_tracking.materialize(self, target_inst, state.reg_tracking[index]);
658 const target_tracking = func.inst_tracking.getPtr(target_inst).?;
659 try target_tracking.materialize(func, target_inst, state.reg_tracking[index]);
663660 }
664661 }
665662 if (opts.update_tracking) {
666663 if (current_maybe_inst) |current_inst| {
667 try self.inst_tracking.getPtr(current_inst).?.trackSpill(self, current_inst);
664 try func.inst_tracking.getPtr(current_inst).?.trackSpill(func, current_inst);
668665 }
669 {
666 blk: {
667 const inst = target_maybe_inst orelse break :blk;
670668 const reg = RegisterManager.regAtTrackedIndex(@intCast(index));
671 self.register_manager.freeReg(reg);
672 self.register_manager.getRegAssumeFree(reg, target_maybe_inst);
669 func.register_manager.freeReg(reg);
670 func.register_manager.getRegAssumeFree(reg, inst);
673671 }
674672 if (target_maybe_inst) |target_inst| {
675 self.inst_tracking.getPtr(target_inst).?.trackMaterialize(
673 func.inst_tracking.getPtr(target_inst).?.trackMaterialize(
676674 target_inst,
677675 state.reg_tracking[index],
678676 );
679677 }
680678 } else if (target_maybe_inst) |_|
681 try reg_locks.append(self.register_manager.lockRegIndexAssumeUnused(@intCast(index)));
679 try reg_locks.append(func.register_manager.lockRegIndexAssumeUnused(@intCast(index)));
682680 }
683681
684682 if (opts.update_tracking and std.debug.runtime_safety) {
685 assert(self.register_manager.free_registers.eql(state.free_registers));
683 assert(func.register_manager.free_registers.eql(state.free_registers));
686684 var used_reg_it = state.free_registers.iterator(.{ .kind = .unset });
687685 while (used_reg_it.next()) |index|
688 assert(self.register_manager.registers[index] == state.registers[index]);
686 assert(func.register_manager.registers[index] == state.registers[index]);
689687 }
690688}
691689
692const Self = @This();
690const Func = @This();
693691
694692const CallView = enum(u1) {
695693 callee,
......@@ -725,7 +723,7 @@ pub fn generate(
725723 }
726724 try branch_stack.append(.{});
727725
728 var function = Self{
726 var function = Func{
729727 .gpa = gpa,
730728 .air = air,
731729 .mod = mod,
......@@ -760,6 +758,8 @@ pub fn generate(
760758 function.mir_extra.deinit(gpa);
761759 }
762760
761 wip_mir_log.debug("{}:", .{function.fmtDecl(func.owner_decl)});
762
763763 try function.frame_allocs.resize(gpa, FrameIndex.named_count);
764764 function.frame_allocs.set(
765765 @intFromEnum(FrameIndex.stack_frame),
......@@ -774,7 +774,7 @@ pub fn generate(
774774 );
775775
776776 const fn_info = zcu.typeToFunc(fn_type).?;
777 var call_info = function.resolveCallingConventionValues(fn_info) catch |err| switch (err) {
777 var call_info = function.resolveCallingConventionValues(fn_info, &.{}) catch |err| switch (err) {
778778 error.CodegenFail => return Result{ .fail = function.err_msg.? },
779779 error.OutOfRegisters => return Result{
780780 .fail = try ErrorMsg.create(gpa, src_loc, "CodeGen ran out of registers. This is a bug in the Zig compiler.", .{}),
......@@ -865,51 +865,171 @@ pub fn generate(
865865 }
866866}
867867
868fn addInst(self: *Self, inst: Mir.Inst) error{OutOfMemory}!Mir.Inst.Index {
869 const gpa = self.gpa;
868const FormatWipMirData = struct {
869 func: *Func,
870 inst: Mir.Inst.Index,
871};
872fn formatWipMir(
873 data: FormatWipMirData,
874 comptime _: []const u8,
875 _: std.fmt.FormatOptions,
876 writer: anytype,
877) @TypeOf(writer).Error!void {
878 const comp = data.func.bin_file.comp;
879 const mod = comp.root_mod;
880 var lower = Lower{
881 .bin_file = data.func.bin_file,
882 .allocator = data.func.gpa,
883 .mir = .{
884 .instructions = data.func.mir_instructions.slice(),
885 .extra = data.func.mir_extra.items,
886 .frame_locs = data.func.frame_locs.slice(),
887 },
888 .cc = .Unspecified,
889 .src_loc = data.func.src_loc,
890 .output_mode = comp.config.output_mode,
891 .link_mode = comp.config.link_mode,
892 .pic = mod.pic,
893 };
894 var first = true;
895 for ((lower.lowerMir(data.inst) catch |err| switch (err) {
896 error.LowerFail => {
897 defer {
898 lower.err_msg.?.deinit(data.func.gpa);
899 lower.err_msg = null;
900 }
901 try writer.writeAll(lower.err_msg.?.msg);
902 return;
903 },
904 error.OutOfMemory, error.InvalidInstruction => |e| {
905 try writer.writeAll(switch (e) {
906 error.OutOfMemory => "Out of memory",
907 error.InvalidInstruction => "CodeGen failed to find a viable instruction.",
908 });
909 return;
910 },
911 else => |e| return e,
912 }).insts) |lowered_inst| {
913 if (!first) try writer.writeAll("\ndebug(wip_mir): ");
914 try writer.print(" | {}", .{lowered_inst});
915 first = false;
916 }
917}
918fn fmtWipMir(func: *Func, inst: Mir.Inst.Index) std.fmt.Formatter(formatWipMir) {
919 return .{ .data = .{ .func = func, .inst = inst } };
920}
870921
871 try self.mir_instructions.ensureUnusedCapacity(gpa, 1);
922const FormatDeclData = struct {
923 mod: *Module,
924 decl_index: InternPool.DeclIndex,
925};
926fn formatDecl(
927 data: FormatDeclData,
928 comptime _: []const u8,
929 _: std.fmt.FormatOptions,
930 writer: anytype,
931) @TypeOf(writer).Error!void {
932 try data.mod.declPtr(data.decl_index).renderFullyQualifiedName(data.mod, writer);
933}
934fn fmtDecl(func: *Func, decl_index: InternPool.DeclIndex) std.fmt.Formatter(formatDecl) {
935 return .{ .data = .{
936 .mod = func.bin_file.comp.module.?,
937 .decl_index = decl_index,
938 } };
939}
940
941const FormatAirData = struct {
942 func: *Func,
943 inst: Air.Inst.Index,
944};
945fn formatAir(
946 data: FormatAirData,
947 comptime _: []const u8,
948 _: std.fmt.FormatOptions,
949 writer: anytype,
950) @TypeOf(writer).Error!void {
951 @import("../../print_air.zig").dumpInst(
952 data.inst,
953 data.func.bin_file.comp.module.?,
954 data.func.air,
955 data.func.liveness,
956 );
957}
958fn fmtAir(func: *Func, inst: Air.Inst.Index) std.fmt.Formatter(formatAir) {
959 return .{ .data = .{ .func = func, .inst = inst } };
960}
872961
873 const result_index: Mir.Inst.Index = @intCast(self.mir_instructions.len);
874 self.mir_instructions.appendAssumeCapacity(inst);
962const FormatTrackingData = struct {
963 func: *Func,
964};
965fn formatTracking(
966 data: FormatTrackingData,
967 comptime _: []const u8,
968 _: std.fmt.FormatOptions,
969 writer: anytype,
970) @TypeOf(writer).Error!void {
971 var it = data.func.inst_tracking.iterator();
972 while (it.next()) |entry| try writer.print("\n%{d} = {}", .{ entry.key_ptr.*, entry.value_ptr.* });
973}
974fn fmtTracking(func: *Func) std.fmt.Formatter(formatTracking) {
975 return .{ .data = .{ .func = func } };
976}
977
978fn addInst(func: *Func, inst: Mir.Inst) error{OutOfMemory}!Mir.Inst.Index {
979 const gpa = func.gpa;
980 try func.mir_instructions.ensureUnusedCapacity(gpa, 1);
981 const result_index: Mir.Inst.Index = @intCast(func.mir_instructions.len);
982 func.mir_instructions.appendAssumeCapacity(inst);
983 if (inst.tag != .pseudo or switch (inst.ops) {
984 else => true,
985 .pseudo_dbg_prologue_end,
986 .pseudo_dbg_line_column,
987 .pseudo_dbg_epilogue_begin,
988 .pseudo_store_rm,
989 .pseudo_load_rm,
990 .pseudo_lea_rm,
991 .pseudo_mv,
992 .pseudo_dead,
993 => false,
994 }) wip_mir_log.debug("{}", .{func.fmtWipMir(result_index)}) else wip_mir_log.debug(" | uses-mem", .{});
875995 return result_index;
876996}
877997
878fn addNop(self: *Self) error{OutOfMemory}!Mir.Inst.Index {
879 return self.addInst(.{
998fn addNop(func: *Func) error{OutOfMemory}!Mir.Inst.Index {
999 return func.addInst(.{
8801000 .tag = .nop,
8811001 .ops = .none,
8821002 .data = undefined,
8831003 });
8841004}
8851005
886fn addPseudoNone(self: *Self, ops: Mir.Inst.Ops) !void {
887 _ = try self.addInst(.{
1006fn addPseudoNone(func: *Func, ops: Mir.Inst.Ops) !void {
1007 _ = try func.addInst(.{
8881008 .tag = .pseudo,
8891009 .ops = ops,
8901010 .data = undefined,
8911011 });
8921012}
8931013
894fn addPseudo(self: *Self, ops: Mir.Inst.Ops) !Mir.Inst.Index {
895 return self.addInst(.{
1014fn addPseudo(func: *Func, ops: Mir.Inst.Ops) !Mir.Inst.Index {
1015 return func.addInst(.{
8961016 .tag = .pseudo,
8971017 .ops = ops,
8981018 .data = undefined,
8991019 });
9001020}
9011021
902pub fn addExtra(self: *Self, extra: anytype) Allocator.Error!u32 {
1022pub fn addExtra(func: *Func, extra: anytype) Allocator.Error!u32 {
9031023 const fields = std.meta.fields(@TypeOf(extra));
904 try self.mir_extra.ensureUnusedCapacity(self.gpa, fields.len);
905 return self.addExtraAssumeCapacity(extra);
1024 try func.mir_extra.ensureUnusedCapacity(func.gpa, fields.len);
1025 return func.addExtraAssumeCapacity(extra);
9061026}
9071027
908pub fn addExtraAssumeCapacity(self: *Self, extra: anytype) u32 {
1028pub fn addExtraAssumeCapacity(func: *Func, extra: anytype) u32 {
9091029 const fields = std.meta.fields(@TypeOf(extra));
910 const result: u32 = @intCast(self.mir_extra.items.len);
1030 const result: u32 = @intCast(func.mir_extra.items.len);
9111031 inline for (fields) |field| {
912 self.mir_extra.appendAssumeCapacity(switch (field.type) {
1032 func.mir_extra.appendAssumeCapacity(switch (field.type) {
9131033 u32 => @field(extra, field.name),
9141034 i32 => @bitCast(@field(extra, field.name)),
9151035 else => @compileError("bad field type"),
......@@ -918,38 +1038,71 @@ pub fn addExtraAssumeCapacity(self: *Self, extra: anytype) u32 {
9181038 return result;
9191039}
9201040
921fn gen(self: *Self) !void {
922 const mod = self.bin_file.comp.module.?;
923 const fn_info = mod.typeToFunc(self.fn_type).?;
1041const required_features = [_]Target.riscv.Feature{
1042 .d,
1043 .m,
1044};
1045
1046fn gen(func: *Func) !void {
1047 const mod = func.bin_file.comp.module.?;
1048 const fn_info = mod.typeToFunc(func.fn_type).?;
9241049
925 if (fn_info.cc != .Naked) {
926 try self.addPseudoNone(.pseudo_dbg_prologue_end);
1050 inline for (required_features) |feature| {
1051 if (!func.hasFeature(feature)) {
1052 return func.fail(
1053 "target missing required feature {s}",
1054 .{@tagName(feature)},
1055 );
1056 }
1057 }
9271058
928 const backpatch_stack_alloc = try self.addPseudo(.pseudo_dead);
929 const backpatch_ra_spill = try self.addPseudo(.pseudo_dead);
930 const backpatch_fp_spill = try self.addPseudo(.pseudo_dead);
931 const backpatch_fp_add = try self.addPseudo(.pseudo_dead);
932 const backpatch_spill_callee_preserved_regs = try self.addPseudo(.pseudo_dead);
1059 if (fn_info.cc != .Naked) {
1060 try func.addPseudoNone(.pseudo_dbg_prologue_end);
1061
1062 const backpatch_stack_alloc = try func.addPseudo(.pseudo_dead);
1063 const backpatch_ra_spill = try func.addPseudo(.pseudo_dead);
1064 const backpatch_fp_spill = try func.addPseudo(.pseudo_dead);
1065 const backpatch_fp_add = try func.addPseudo(.pseudo_dead);
1066 const backpatch_spill_callee_preserved_regs = try func.addPseudo(.pseudo_dead);
1067
1068 switch (func.ret_mcv.long) {
1069 .none, .unreach => {},
1070 .indirect => {
1071 // The address where to store the return value for the caller is in a
1072 // register which the callee is free to clobber. Therefore, we purposely
1073 // spill it to stack immediately.
1074 const frame_index = try func.allocFrameIndex(FrameAlloc.initSpill(Type.usize, mod));
1075 try func.genSetMem(
1076 .{ .frame = frame_index },
1077 0,
1078 Type.usize,
1079 func.ret_mcv.long.address().offset(-func.ret_mcv.short.indirect.off),
1080 );
1081 func.ret_mcv.long = .{ .load_frame = .{ .index = frame_index } };
1082 tracking_log.debug("spill {} to {}", .{ func.ret_mcv.long, frame_index });
1083 },
1084 else => unreachable,
1085 }
9331086
934 try self.genBody(self.air.getMainBody());
1087 try func.genBody(func.air.getMainBody());
9351088
936 for (self.exitlude_jump_relocs.items) |jmp_reloc| {
937 self.mir_instructions.items(.data)[jmp_reloc].inst =
938 @intCast(self.mir_instructions.len);
1089 for (func.exitlude_jump_relocs.items) |jmp_reloc| {
1090 func.mir_instructions.items(.data)[jmp_reloc].inst =
1091 @intCast(func.mir_instructions.len);
9391092 }
9401093
941 try self.addPseudoNone(.pseudo_dbg_epilogue_begin);
1094 try func.addPseudoNone(.pseudo_dbg_epilogue_begin);
9421095
943 const backpatch_restore_callee_preserved_regs = try self.addPseudo(.pseudo_dead);
944 const backpatch_ra_restore = try self.addPseudo(.pseudo_dead);
945 const backpatch_fp_restore = try self.addPseudo(.pseudo_dead);
946 const backpatch_stack_alloc_restore = try self.addPseudo(.pseudo_dead);
947 try self.addPseudoNone(.pseudo_ret);
1096 const backpatch_restore_callee_preserved_regs = try func.addPseudo(.pseudo_dead);
1097 const backpatch_ra_restore = try func.addPseudo(.pseudo_dead);
1098 const backpatch_fp_restore = try func.addPseudo(.pseudo_dead);
1099 const backpatch_stack_alloc_restore = try func.addPseudo(.pseudo_dead);
1100 try func.addPseudoNone(.pseudo_ret);
9481101
949 const frame_layout = try self.computeFrameLayout();
1102 const frame_layout = try func.computeFrameLayout();
9501103 const need_save_reg = frame_layout.save_reg_list.count() > 0;
9511104
952 self.mir_instructions.set(backpatch_stack_alloc, .{
1105 func.mir_instructions.set(backpatch_stack_alloc, .{
9531106 .tag = .addi,
9541107 .ops = .rri,
9551108 .data = .{ .i_type = .{
......@@ -958,51 +1111,51 @@ fn gen(self: *Self) !void {
9581111 .imm12 = Immediate.s(-@as(i32, @intCast(frame_layout.stack_adjust))),
9591112 } },
9601113 });
961 self.mir_instructions.set(backpatch_ra_spill, .{
1114 func.mir_instructions.set(backpatch_ra_spill, .{
9621115 .tag = .pseudo,
9631116 .ops = .pseudo_store_rm,
9641117 .data = .{ .rm = .{
9651118 .r = .ra,
9661119 .m = .{
9671120 .base = .{ .frame = .ret_addr },
968 .mod = .{ .rm = .{ .size = .dword } },
1121 .mod = .{ .size = .dword, .unsigned = false },
9691122 },
9701123 } },
9711124 });
972 self.mir_instructions.set(backpatch_ra_restore, .{
1125 func.mir_instructions.set(backpatch_ra_restore, .{
9731126 .tag = .pseudo,
9741127 .ops = .pseudo_load_rm,
9751128 .data = .{ .rm = .{
9761129 .r = .ra,
9771130 .m = .{
9781131 .base = .{ .frame = .ret_addr },
979 .mod = .{ .rm = .{ .size = .dword } },
1132 .mod = .{ .size = .dword, .unsigned = false },
9801133 },
9811134 } },
9821135 });
983 self.mir_instructions.set(backpatch_fp_spill, .{
1136 func.mir_instructions.set(backpatch_fp_spill, .{
9841137 .tag = .pseudo,
9851138 .ops = .pseudo_store_rm,
9861139 .data = .{ .rm = .{
9871140 .r = .s0,
9881141 .m = .{
9891142 .base = .{ .frame = .base_ptr },
990 .mod = .{ .rm = .{ .size = .dword } },
1143 .mod = .{ .size = .dword, .unsigned = false },
9911144 },
9921145 } },
9931146 });
994 self.mir_instructions.set(backpatch_fp_restore, .{
1147 func.mir_instructions.set(backpatch_fp_restore, .{
9951148 .tag = .pseudo,
9961149 .ops = .pseudo_load_rm,
9971150 .data = .{ .rm = .{
9981151 .r = .s0,
9991152 .m = .{
10001153 .base = .{ .frame = .base_ptr },
1001 .mod = .{ .rm = .{ .size = .dword } },
1154 .mod = .{ .size = .dword, .unsigned = false },
10021155 },
10031156 } },
10041157 });
1005 self.mir_instructions.set(backpatch_fp_add, .{
1158 func.mir_instructions.set(backpatch_fp_add, .{
10061159 .tag = .addi,
10071160 .ops = .rri,
10081161 .data = .{ .i_type = .{
......@@ -1011,7 +1164,7 @@ fn gen(self: *Self) !void {
10111164 .imm12 = Immediate.s(@intCast(frame_layout.stack_adjust)),
10121165 } },
10131166 });
1014 self.mir_instructions.set(backpatch_stack_alloc_restore, .{
1167 func.mir_instructions.set(backpatch_stack_alloc_restore, .{
10151168 .tag = .addi,
10161169 .ops = .rri,
10171170 .data = .{ .i_type = .{
......@@ -1022,72 +1175,83 @@ fn gen(self: *Self) !void {
10221175 });
10231176
10241177 if (need_save_reg) {
1025 self.mir_instructions.set(backpatch_spill_callee_preserved_regs, .{
1178 func.mir_instructions.set(backpatch_spill_callee_preserved_regs, .{
10261179 .tag = .pseudo,
10271180 .ops = .pseudo_spill_regs,
10281181 .data = .{ .reg_list = frame_layout.save_reg_list },
10291182 });
10301183
1031 self.mir_instructions.set(backpatch_restore_callee_preserved_regs, .{
1184 func.mir_instructions.set(backpatch_restore_callee_preserved_regs, .{
10321185 .tag = .pseudo,
10331186 .ops = .pseudo_restore_regs,
10341187 .data = .{ .reg_list = frame_layout.save_reg_list },
10351188 });
10361189 }
10371190 } else {
1038 try self.addPseudoNone(.pseudo_dbg_prologue_end);
1039 try self.genBody(self.air.getMainBody());
1040 try self.addPseudoNone(.pseudo_dbg_epilogue_begin);
1191 try func.addPseudoNone(.pseudo_dbg_prologue_end);
1192 try func.genBody(func.air.getMainBody());
1193 try func.addPseudoNone(.pseudo_dbg_epilogue_begin);
10411194 }
10421195
10431196 // Drop them off at the rbrace.
1044 _ = try self.addInst(.{
1197 _ = try func.addInst(.{
10451198 .tag = .pseudo,
10461199 .ops = .pseudo_dbg_line_column,
10471200 .data = .{ .pseudo_dbg_line_column = .{
1048 .line = self.end_di_line,
1049 .column = self.end_di_column,
1201 .line = func.end_di_line,
1202 .column = func.end_di_column,
10501203 } },
10511204 });
10521205}
10531206
1054fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
1055 const zcu = self.bin_file.comp.module.?;
1207fn genBody(func: *Func, body: []const Air.Inst.Index) InnerError!void {
1208 const zcu = func.bin_file.comp.module.?;
10561209 const ip = &zcu.intern_pool;
1057 const air_tags = self.air.instructions.items(.tag);
1210 const air_tags = func.air.instructions.items(.tag);
10581211
10591212 for (body) |inst| {
1060 if (self.liveness.isUnused(inst) and !self.air.mustLower(inst, ip)) continue;
1061
1062 const old_air_bookkeeping = self.air_bookkeeping;
1063 try self.inst_tracking.ensureUnusedCapacity(self.gpa, 1);
1064 switch (air_tags[@intFromEnum(inst)]) {
1213 if (func.liveness.isUnused(inst) and !func.air.mustLower(inst, ip)) continue;
1214 wip_mir_log.debug("{}", .{func.fmtAir(inst)});
1215 verbose_tracking_log.debug("{}", .{func.fmtTracking()});
1216
1217 const old_air_bookkeeping = func.air_bookkeeping;
1218 try func.inst_tracking.ensureUnusedCapacity(func.gpa, 1);
1219 const tag: Air.Inst.Tag = air_tags[@intFromEnum(inst)];
1220 switch (tag) {
10651221 // zig fmt: off
1066 .ptr_add => try self.airPtrArithmetic(inst, .ptr_add),
1067 .ptr_sub => try self.airPtrArithmetic(inst, .ptr_sub),
1222 .add,
1223 .add_wrap,
1224 .sub,
1225 .sub_wrap,
10681226
1069 .add => try self.airBinOp(inst, .add),
1070 .sub => try self.airBinOp(inst, .sub),
1227 .mul,
1228 .mul_wrap,
1229 .div_trunc,
10711230
1072 .add_safe,
1073 .sub_safe,
1074 .mul_safe,
1075 => return self.fail("TODO implement safety_checked_instructions", .{}),
1076
1077 .add_wrap => try self.airAddWrap(inst),
1078 .add_sat => try self.airAddSat(inst),
1079 .sub_wrap => try self.airSubWrap(inst),
1080 .sub_sat => try self.airSubSat(inst),
1081 .mul => try self.airMul(inst),
1082 .mul_wrap => try self.airMulWrap(inst),
1083 .mul_sat => try self.airMulSat(inst),
1084 .rem => try self.airRem(inst),
1085 .mod => try self.airMod(inst),
1086 .shl, .shl_exact => try self.airShl(inst),
1087 .shl_sat => try self.airShlSat(inst),
1088 .min => try self.airMinMax(inst, .min),
1089 .max => try self.airMinMax(inst, .max),
1090 .slice => try self.airSlice(inst),
1231 .shl, .shl_exact,
1232 .shr, .shr_exact,
1233
1234 .bool_and,
1235 .bool_or,
1236 .bit_and,
1237 .bit_or,
1238
1239 .xor,
1240
1241 .min,
1242 .max,
1243 => try func.airBinOp(inst, tag),
1244
1245
1246 .ptr_add,
1247 .ptr_sub => try func.airPtrArithmetic(inst, tag),
1248
1249 .rem,
1250 .mod,
1251 .div_float,
1252 .div_floor,
1253 .div_exact,
1254 => return func.fail("TODO: {s}", .{@tagName(tag)}),
10911255
10921256 .sqrt,
10931257 .sin,
......@@ -1103,157 +1267,164 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
11031267 .round,
11041268 .trunc_float,
11051269 .neg,
1106 => try self.airUnaryMath(inst),
1107
1108 .add_with_overflow => try self.airAddWithOverflow(inst),
1109 .sub_with_overflow => try self.airSubWithOverflow(inst),
1110 .mul_with_overflow => try self.airMulWithOverflow(inst),
1111 .shl_with_overflow => try self.airShlWithOverflow(inst),
1112
1113 .div_float, .div_trunc, .div_floor, .div_exact => try self.airDiv(inst),
1114
1115 .cmp_lt => try self.airCmp(inst),
1116 .cmp_lte => try self.airCmp(inst),
1117 .cmp_eq => try self.airCmp(inst),
1118 .cmp_gte => try self.airCmp(inst),
1119 .cmp_gt => try self.airCmp(inst),
1120 .cmp_neq => try self.airCmp(inst),
1121
1122 .cmp_vector => try self.airCmpVector(inst),
1123 .cmp_lt_errors_len => try self.airCmpLtErrorsLen(inst),
1124
1125 .bool_and => try self.airBoolOp(inst),
1126 .bool_or => try self.airBoolOp(inst),
1127 .bit_and => try self.airBitAnd(inst),
1128 .bit_or => try self.airBitOr(inst),
1129 .xor => try self.airXor(inst),
1130 .shr, .shr_exact => try self.airShr(inst),
1131
1132 .alloc => try self.airAlloc(inst),
1133 .ret_ptr => try self.airRetPtr(inst),
1134 .arg => try self.airArg(inst),
1135 .assembly => try self.airAsm(inst),
1136 .bitcast => try self.airBitCast(inst),
1137 .block => try self.airBlock(inst),
1138 .br => try self.airBr(inst),
1139 .trap => try self.airTrap(),
1140 .breakpoint => try self.airBreakpoint(),
1141 .ret_addr => try self.airRetAddr(inst),
1142 .frame_addr => try self.airFrameAddress(inst),
1143 .fence => try self.airFence(),
1144 .cond_br => try self.airCondBr(inst),
1145 .dbg_stmt => try self.airDbgStmt(inst),
1146 .fptrunc => try self.airFptrunc(inst),
1147 .fpext => try self.airFpext(inst),
1148 .intcast => try self.airIntCast(inst),
1149 .trunc => try self.airTrunc(inst),
1150 .int_from_bool => try self.airIntFromBool(inst),
1151 .is_non_null => try self.airIsNonNull(inst),
1152 .is_non_null_ptr => try self.airIsNonNullPtr(inst),
1153 .is_null => try self.airIsNull(inst),
1154 .is_null_ptr => try self.airIsNullPtr(inst),
1155 .is_non_err => try self.airIsNonErr(inst),
1156 .is_non_err_ptr => try self.airIsNonErrPtr(inst),
1157 .is_err => try self.airIsErr(inst),
1158 .is_err_ptr => try self.airIsErrPtr(inst),
1159 .load => try self.airLoad(inst),
1160 .loop => try self.airLoop(inst),
1161 .not => try self.airNot(inst),
1162 .int_from_ptr => try self.airIntFromPtr(inst),
1163 .ret => try self.airRet(inst, false),
1164 .ret_safe => try self.airRet(inst, true),
1165 .ret_load => try self.airRetLoad(inst),
1166 .store => try self.airStore(inst, false),
1167 .store_safe => try self.airStore(inst, true),
1168 .struct_field_ptr=> try self.airStructFieldPtr(inst),
1169 .struct_field_val=> try self.airStructFieldVal(inst),
1170 .array_to_slice => try self.airArrayToSlice(inst),
1171 .float_from_int => try self.airFloatFromInt(inst),
1172 .int_from_float => try self.airIntFromFloat(inst),
1173 .cmpxchg_strong => try self.airCmpxchg(inst),
1174 .cmpxchg_weak => try self.airCmpxchg(inst),
1175 .atomic_rmw => try self.airAtomicRmw(inst),
1176 .atomic_load => try self.airAtomicLoad(inst),
1177 .memcpy => try self.airMemcpy(inst),
1178 .memset => try self.airMemset(inst, false),
1179 .memset_safe => try self.airMemset(inst, true),
1180 .set_union_tag => try self.airSetUnionTag(inst),
1181 .get_union_tag => try self.airGetUnionTag(inst),
1182 .clz => try self.airClz(inst),
1183 .ctz => try self.airCtz(inst),
1184 .popcount => try self.airPopcount(inst),
1185 .abs => try self.airAbs(inst),
1186 .byte_swap => try self.airByteSwap(inst),
1187 .bit_reverse => try self.airBitReverse(inst),
1188 .tag_name => try self.airTagName(inst),
1189 .error_name => try self.airErrorName(inst),
1190 .splat => try self.airSplat(inst),
1191 .select => try self.airSelect(inst),
1192 .shuffle => try self.airShuffle(inst),
1193 .reduce => try self.airReduce(inst),
1194 .aggregate_init => try self.airAggregateInit(inst),
1195 .union_init => try self.airUnionInit(inst),
1196 .prefetch => try self.airPrefetch(inst),
1197 .mul_add => try self.airMulAdd(inst),
1198 .addrspace_cast => return self.fail("TODO: addrspace_cast", .{}),
1199
1200 .@"try" => try self.airTry(inst),
1201 .try_ptr => return self.fail("TODO: try_ptr", .{}),
1270 => try func.airUnaryMath(inst),
1271
1272 .add_with_overflow => try func.airAddWithOverflow(inst),
1273 .sub_with_overflow => try func.airSubWithOverflow(inst),
1274 .mul_with_overflow => try func.airMulWithOverflow(inst),
1275 .shl_with_overflow => try func.airShlWithOverflow(inst),
1276
1277
1278 .add_sat => try func.airAddSat(inst),
1279 .sub_sat => try func.airSubSat(inst),
1280 .mul_sat => try func.airMulSat(inst),
1281 .shl_sat => try func.airShlSat(inst),
1282
1283 .add_safe,
1284 .sub_safe,
1285 .mul_safe,
1286 => return func.fail("TODO implement safety_checked_instructions", .{}),
1287
1288 .cmp_lt,
1289 .cmp_lte,
1290 .cmp_eq,
1291 .cmp_gte,
1292 .cmp_gt,
1293 .cmp_neq,
1294 => try func.airCmp(inst, tag),
1295
1296 .cmp_vector => try func.airCmpVector(inst),
1297 .cmp_lt_errors_len => try func.airCmpLtErrorsLen(inst),
1298
1299 .slice => try func.airSlice(inst),
1300 .array_to_slice => try func.airArrayToSlice(inst),
1301
1302 .slice_ptr => try func.airSlicePtr(inst),
1303 .slice_len => try func.airSliceLen(inst),
1304
1305 .alloc => try func.airAlloc(inst),
1306 .ret_ptr => try func.airRetPtr(inst),
1307 .arg => try func.airArg(inst),
1308 .assembly => try func.airAsm(inst),
1309 .bitcast => try func.airBitCast(inst),
1310 .block => try func.airBlock(inst),
1311 .br => try func.airBr(inst),
1312 .trap => try func.airTrap(),
1313 .breakpoint => try func.airBreakpoint(),
1314 .ret_addr => try func.airRetAddr(inst),
1315 .frame_addr => try func.airFrameAddress(inst),
1316 .fence => try func.airFence(),
1317 .cond_br => try func.airCondBr(inst),
1318 .dbg_stmt => try func.airDbgStmt(inst),
1319 .fptrunc => try func.airFptrunc(inst),
1320 .fpext => try func.airFpext(inst),
1321 .intcast => try func.airIntCast(inst),
1322 .trunc => try func.airTrunc(inst),
1323 .int_from_bool => try func.airIntFromBool(inst),
1324 .is_non_null => try func.airIsNonNull(inst),
1325 .is_non_null_ptr => try func.airIsNonNullPtr(inst),
1326 .is_null => try func.airIsNull(inst),
1327 .is_null_ptr => try func.airIsNullPtr(inst),
1328 .is_non_err => try func.airIsNonErr(inst),
1329 .is_non_err_ptr => try func.airIsNonErrPtr(inst),
1330 .is_err => try func.airIsErr(inst),
1331 .is_err_ptr => try func.airIsErrPtr(inst),
1332 .load => try func.airLoad(inst),
1333 .loop => try func.airLoop(inst),
1334 .not => try func.airNot(inst),
1335 .int_from_ptr => try func.airIntFromPtr(inst),
1336 .ret => try func.airRet(inst, false),
1337 .ret_safe => try func.airRet(inst, true),
1338 .ret_load => try func.airRetLoad(inst),
1339 .store => try func.airStore(inst, false),
1340 .store_safe => try func.airStore(inst, true),
1341 .struct_field_ptr=> try func.airStructFieldPtr(inst),
1342 .struct_field_val=> try func.airStructFieldVal(inst),
1343 .float_from_int => try func.airFloatFromInt(inst),
1344 .int_from_float => try func.airIntFromFloat(inst),
1345 .cmpxchg_strong => try func.airCmpxchg(inst),
1346 .cmpxchg_weak => try func.airCmpxchg(inst),
1347 .atomic_rmw => try func.airAtomicRmw(inst),
1348 .atomic_load => try func.airAtomicLoad(inst),
1349 .memcpy => try func.airMemcpy(inst),
1350 .memset => try func.airMemset(inst, false),
1351 .memset_safe => try func.airMemset(inst, true),
1352 .set_union_tag => try func.airSetUnionTag(inst),
1353 .get_union_tag => try func.airGetUnionTag(inst),
1354 .clz => try func.airClz(inst),
1355 .ctz => try func.airCtz(inst),
1356 .popcount => try func.airPopcount(inst),
1357 .abs => try func.airAbs(inst),
1358 .byte_swap => try func.airByteSwap(inst),
1359 .bit_reverse => try func.airBitReverse(inst),
1360 .tag_name => try func.airTagName(inst),
1361 .error_name => try func.airErrorName(inst),
1362 .splat => try func.airSplat(inst),
1363 .select => try func.airSelect(inst),
1364 .shuffle => try func.airShuffle(inst),
1365 .reduce => try func.airReduce(inst),
1366 .aggregate_init => try func.airAggregateInit(inst),
1367 .union_init => try func.airUnionInit(inst),
1368 .prefetch => try func.airPrefetch(inst),
1369 .mul_add => try func.airMulAdd(inst),
1370 .addrspace_cast => return func.fail("TODO: addrspace_cast", .{}),
1371
1372 .@"try" => try func.airTry(inst),
1373 .try_ptr => return func.fail("TODO: try_ptr", .{}),
12021374
12031375 .dbg_var_ptr,
12041376 .dbg_var_val,
1205 => try self.airDbgVar(inst),
1377 => try func.airDbgVar(inst),
12061378
1207 .dbg_inline_block => try self.airDbgInlineBlock(inst),
1379 .dbg_inline_block => try func.airDbgInlineBlock(inst),
12081380
1209 .call => try self.airCall(inst, .auto),
1210 .call_always_tail => try self.airCall(inst, .always_tail),
1211 .call_never_tail => try self.airCall(inst, .never_tail),
1212 .call_never_inline => try self.airCall(inst, .never_inline),
1381 .call => try func.airCall(inst, .auto),
1382 .call_always_tail => try func.airCall(inst, .always_tail),
1383 .call_never_tail => try func.airCall(inst, .never_tail),
1384 .call_never_inline => try func.airCall(inst, .never_inline),
12131385
1214 .atomic_store_unordered => try self.airAtomicStore(inst, .unordered),
1215 .atomic_store_monotonic => try self.airAtomicStore(inst, .monotonic),
1216 .atomic_store_release => try self.airAtomicStore(inst, .release),
1217 .atomic_store_seq_cst => try self.airAtomicStore(inst, .seq_cst),
1386 .atomic_store_unordered => try func.airAtomicStore(inst, .unordered),
1387 .atomic_store_monotonic => try func.airAtomicStore(inst, .monotonic),
1388 .atomic_store_release => try func.airAtomicStore(inst, .release),
1389 .atomic_store_seq_cst => try func.airAtomicStore(inst, .seq_cst),
1390 .struct_field_ptr_index_0 => try func.airStructFieldPtrIndex(inst, 0),
1391 .struct_field_ptr_index_1 => try func.airStructFieldPtrIndex(inst, 1),
1392 .struct_field_ptr_index_2 => try func.airStructFieldPtrIndex(inst, 2),
1393 .struct_field_ptr_index_3 => try func.airStructFieldPtrIndex(inst, 3),
12181394
1219 .struct_field_ptr_index_0 => try self.airStructFieldPtrIndex(inst, 0),
1220 .struct_field_ptr_index_1 => try self.airStructFieldPtrIndex(inst, 1),
1221 .struct_field_ptr_index_2 => try self.airStructFieldPtrIndex(inst, 2),
1222 .struct_field_ptr_index_3 => try self.airStructFieldPtrIndex(inst, 3),
1395 .field_parent_ptr => try func.airFieldParentPtr(inst),
12231396
1224 .field_parent_ptr => try self.airFieldParentPtr(inst),
1397 .switch_br => try func.airSwitchBr(inst),
12251398
1226 .switch_br => try self.airSwitch(inst),
1227 .slice_ptr => try self.airSlicePtr(inst),
1228 .slice_len => try self.airSliceLen(inst),
1399 .ptr_slice_len_ptr => try func.airPtrSliceLenPtr(inst),
1400 .ptr_slice_ptr_ptr => try func.airPtrSlicePtrPtr(inst),
12291401
1230 .ptr_slice_len_ptr => try self.airPtrSliceLenPtr(inst),
1231 .ptr_slice_ptr_ptr => try self.airPtrSlicePtrPtr(inst),
1402 .array_elem_val => try func.airArrayElemVal(inst),
1403
1404 .slice_elem_val => try func.airSliceElemVal(inst),
1405 .slice_elem_ptr => try func.airSliceElemPtr(inst),
12321406
1233 .array_elem_val => try self.airArrayElemVal(inst),
1234 .slice_elem_val => try self.airSliceElemVal(inst),
1235 .slice_elem_ptr => try self.airSliceElemPtr(inst),
1236 .ptr_elem_val => try self.airPtrElemVal(inst),
1237 .ptr_elem_ptr => try self.airPtrElemPtr(inst),
1407 .ptr_elem_val => try func.airPtrElemVal(inst),
1408 .ptr_elem_ptr => try func.airPtrElemPtr(inst),
12381409
12391410 .inferred_alloc, .inferred_alloc_comptime => unreachable,
1240 .unreach => self.finishAirBookkeeping(),
1241
1242 .optional_payload => try self.airOptionalPayload(inst),
1243 .optional_payload_ptr => try self.airOptionalPayloadPtr(inst),
1244 .optional_payload_ptr_set => try self.airOptionalPayloadPtrSet(inst),
1245 .unwrap_errunion_err => try self.airUnwrapErrErr(inst),
1246 .unwrap_errunion_payload => try self.airUnwrapErrPayload(inst),
1247 .unwrap_errunion_err_ptr => try self.airUnwrapErrErrPtr(inst),
1248 .unwrap_errunion_payload_ptr=> try self.airUnwrapErrPayloadPtr(inst),
1249 .errunion_payload_ptr_set => try self.airErrUnionPayloadPtrSet(inst),
1250 .err_return_trace => try self.airErrReturnTrace(inst),
1251 .set_err_return_trace => try self.airSetErrReturnTrace(inst),
1252 .save_err_return_trace_index=> try self.airSaveErrReturnTraceIndex(inst),
1253
1254 .wrap_optional => try self.airWrapOptional(inst),
1255 .wrap_errunion_payload => try self.airWrapErrUnionPayload(inst),
1256 .wrap_errunion_err => try self.airWrapErrUnionErr(inst),
1411 .unreach => func.finishAirBookkeeping(),
1412
1413 .optional_payload => try func.airOptionalPayload(inst),
1414 .optional_payload_ptr => try func.airOptionalPayloadPtr(inst),
1415 .optional_payload_ptr_set => try func.airOptionalPayloadPtrSet(inst),
1416 .unwrap_errunion_err => try func.airUnwrapErrErr(inst),
1417 .unwrap_errunion_payload => try func.airUnwrapErrPayload(inst),
1418 .unwrap_errunion_err_ptr => try func.airUnwrapErrErrPtr(inst),
1419 .unwrap_errunion_payload_ptr=> try func.airUnwrapErrPayloadPtr(inst),
1420 .errunion_payload_ptr_set => try func.airErrUnionPayloadPtrSet(inst),
1421 .err_return_trace => try func.airErrReturnTrace(inst),
1422 .set_err_return_trace => try func.airSetErrReturnTrace(inst),
1423 .save_err_return_trace_index=> try func.airSaveErrReturnTraceIndex(inst),
1424
1425 .wrap_optional => try func.airWrapOptional(inst),
1426 .wrap_errunion_payload => try func.airWrapErrUnionPayload(inst),
1427 .wrap_errunion_err => try func.airWrapErrUnionErr(inst),
12571428
12581429 .add_optimized,
12591430 .sub_optimized,
......@@ -1274,16 +1445,16 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
12741445 .cmp_vector_optimized,
12751446 .reduce_optimized,
12761447 .int_from_float_optimized,
1277 => return self.fail("TODO implement optimized float mode", .{}),
1448 => return func.fail("TODO implement optimized float mode", .{}),
12781449
1279 .is_named_enum_value => return self.fail("TODO implement is_named_enum_value", .{}),
1280 .error_set_has_value => return self.fail("TODO implement error_set_has_value", .{}),
1281 .vector_store_elem => return self.fail("TODO implement vector_store_elem", .{}),
1450 .is_named_enum_value => return func.fail("TODO implement is_named_enum_value", .{}),
1451 .error_set_has_value => return func.fail("TODO implement error_set_has_value", .{}),
1452 .vector_store_elem => return func.fail("TODO implement vector_store_elem", .{}),
12821453
1283 .c_va_arg => return self.fail("TODO implement c_va_arg", .{}),
1284 .c_va_copy => return self.fail("TODO implement c_va_copy", .{}),
1285 .c_va_end => return self.fail("TODO implement c_va_end", .{}),
1286 .c_va_start => return self.fail("TODO implement c_va_start", .{}),
1454 .c_va_arg => return func.fail("TODO implement c_va_arg", .{}),
1455 .c_va_copy => return func.fail("TODO implement c_va_copy", .{}),
1456 .c_va_end => return func.fail("TODO implement c_va_end", .{}),
1457 .c_va_start => return func.fail("TODO implement c_va_start", .{}),
12871458
12881459 .wasm_memory_size => unreachable,
12891460 .wasm_memory_grow => unreachable,
......@@ -1294,95 +1465,97 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
12941465 // zig fmt: on
12951466 }
12961467
1297 assert(!self.register_manager.lockedRegsExist());
1468 assert(!func.register_manager.lockedRegsExist());
12981469
12991470 if (std.debug.runtime_safety) {
1300 if (self.air_bookkeeping < old_air_bookkeeping + 1) {
1471 if (func.air_bookkeeping < old_air_bookkeeping + 1) {
13011472 std.debug.panic("in codegen.zig, handling of AIR instruction %{d} ('{}') did not do proper bookkeeping. Look for a missing call to finishAir.", .{ inst, air_tags[@intFromEnum(inst)] });
13021473 }
13031474
13041475 { // check consistency of tracked registers
1305 var it = self.register_manager.free_registers.iterator(.{ .kind = .unset });
1476 var it = func.register_manager.free_registers.iterator(.{ .kind = .unset });
13061477 while (it.next()) |index| {
1307 const tracked_inst = self.register_manager.registers[index];
1308 const tracking = self.getResolvedInstValue(tracked_inst);
1478 const tracked_inst = func.register_manager.registers[index];
1479 tracking_log.debug("tracked inst: {}", .{tracked_inst});
1480 const tracking = func.getResolvedInstValue(tracked_inst);
13091481 for (tracking.getRegs()) |reg| {
13101482 if (RegisterManager.indexOfRegIntoTracked(reg).? == index) break;
1311 } else return self.fail(
1312 \\%{} takes up these regs: {any}, however those regs don't use it
1313 , .{ index, tracking.getRegs() });
1483 } else return std.debug.panic(
1484 \\%{} takes up these regs: {any}, however these regs {any}, don't use it
1485 , .{ tracked_inst, tracking.getRegs(), RegisterManager.regAtTrackedIndex(@intCast(index)) });
13141486 }
13151487 }
13161488 }
13171489 }
1490 verbose_tracking_log.debug("{}", .{func.fmtTracking()});
13181491}
13191492
1320fn getValue(self: *Self, value: MCValue, inst: ?Air.Inst.Index) !void {
1321 for (value.getRegs()) |reg| try self.register_manager.getReg(reg, inst);
1493fn getValue(func: *Func, value: MCValue, inst: ?Air.Inst.Index) !void {
1494 for (value.getRegs()) |reg| try func.register_manager.getReg(reg, inst);
13221495}
13231496
1324fn getValueIfFree(self: *Self, value: MCValue, inst: ?Air.Inst.Index) void {
1325 for (value.getRegs()) |reg| if (self.register_manager.isRegFree(reg))
1326 self.register_manager.getRegAssumeFree(reg, inst);
1497fn getValueIfFree(func: *Func, value: MCValue, inst: ?Air.Inst.Index) void {
1498 for (value.getRegs()) |reg| if (func.register_manager.isRegFree(reg))
1499 func.register_manager.getRegAssumeFree(reg, inst);
13271500}
13281501
1329fn freeValue(self: *Self, value: MCValue) !void {
1502fn freeValue(func: *Func, value: MCValue) !void {
13301503 switch (value) {
1331 .register => |reg| self.register_manager.freeReg(reg),
1332 .register_pair => |regs| for (regs) |reg| self.register_manager.freeReg(reg),
1333 .register_offset => |reg_off| self.register_manager.freeReg(reg_off.reg),
1504 .register => |reg| func.register_manager.freeReg(reg),
1505 .register_pair => |regs| for (regs) |reg| func.register_manager.freeReg(reg),
1506 .register_offset => |reg_off| func.register_manager.freeReg(reg_off.reg),
13341507 else => {}, // TODO process stack allocation death
13351508 }
13361509}
13371510
1338fn feed(self: *Self, bt: *Liveness.BigTomb, operand: Air.Inst.Ref) !void {
1511fn feed(func: *Func, bt: *Liveness.BigTomb, operand: Air.Inst.Ref) !void {
13391512 if (bt.feed()) if (operand.toIndex()) |inst| {
13401513 log.debug("feed inst: %{}", .{inst});
1341 try self.processDeath(inst);
1514 try func.processDeath(inst);
13421515 };
13431516}
13441517
13451518/// Asserts there is already capacity to insert into top branch inst_table.
1346fn processDeath(self: *Self, inst: Air.Inst.Index) !void {
1347 try self.inst_tracking.getPtr(inst).?.die(self, inst);
1519fn processDeath(func: *Func, inst: Air.Inst.Index) !void {
1520 try func.inst_tracking.getPtr(inst).?.die(func, inst);
13481521}
13491522
13501523/// Called when there are no operands, and the instruction is always unreferenced.
1351fn finishAirBookkeeping(self: *Self) void {
1524fn finishAirBookkeeping(func: *Func) void {
13521525 if (std.debug.runtime_safety) {
1353 self.air_bookkeeping += 1;
1526 func.air_bookkeeping += 1;
13541527 }
13551528}
13561529
1357fn finishAirResult(self: *Self, inst: Air.Inst.Index, result: MCValue) void {
1358 if (self.liveness.isUnused(inst)) switch (result) {
1530fn finishAirResult(func: *Func, inst: Air.Inst.Index, result: MCValue) void {
1531 if (func.liveness.isUnused(inst)) switch (result) {
13591532 .none, .dead, .unreach => {},
13601533 else => unreachable, // Why didn't the result die?
13611534 } else {
13621535 tracking_log.debug("%{d} => {} (birth)", .{ inst, result });
1363 self.inst_tracking.putAssumeCapacityNoClobber(inst, InstTracking.init(result));
1536 func.inst_tracking.putAssumeCapacityNoClobber(inst, InstTracking.init(result));
13641537 // In some cases, an operand may be reused as the result.
13651538 // If that operand died and was a register, it was freed by
13661539 // processDeath, so we have to "re-allocate" the register.
1367 self.getValueIfFree(result, inst);
1540 func.getValueIfFree(result, inst);
13681541 }
1369 self.finishAirBookkeeping();
1542 func.finishAirBookkeeping();
13701543}
13711544
13721545fn finishAir(
1373 self: *Self,
1546 func: *Func,
13741547 inst: Air.Inst.Index,
13751548 result: MCValue,
13761549 operands: [Liveness.bpi - 1]Air.Inst.Ref,
13771550) !void {
1378 var tomb_bits = self.liveness.getTombBits(inst);
1551 var tomb_bits = func.liveness.getTombBits(inst);
13791552 for (operands) |op| {
13801553 const dies = @as(u1, @truncate(tomb_bits)) != 0;
13811554 tomb_bits >>= 1;
13821555 if (!dies) continue;
1383 try self.processDeath(op.toIndexAllowNone() orelse continue);
1556 try func.processDeath(op.toIndexAllowNone() orelse continue);
13841557 }
1385 self.finishAirResult(inst, result);
1558 func.finishAirResult(inst, result);
13861559}
13871560
13881561const FrameLayout = struct {
......@@ -1391,7 +1564,7 @@ const FrameLayout = struct {
13911564};
13921565
13931566fn setFrameLoc(
1394 self: *Self,
1567 func: *Func,
13951568 frame_index: FrameIndex,
13961569 base: Register,
13971570 offset: *i32,
......@@ -1399,24 +1572,24 @@ fn setFrameLoc(
13991572) void {
14001573 const frame_i = @intFromEnum(frame_index);
14011574 if (aligned) {
1402 const alignment: InternPool.Alignment = self.frame_allocs.items(.abi_align)[frame_i];
1575 const alignment: InternPool.Alignment = func.frame_allocs.items(.abi_align)[frame_i];
14031576 offset.* = if (math.sign(offset.*) < 0)
14041577 -1 * @as(i32, @intCast(alignment.backward(@intCast(@abs(offset.*)))))
14051578 else
14061579 @intCast(alignment.forward(@intCast(@abs(offset.*))));
14071580 }
1408 self.frame_locs.set(frame_i, .{ .base = base, .disp = offset.* });
1409 offset.* += self.frame_allocs.items(.abi_size)[frame_i];
1581 func.frame_locs.set(frame_i, .{ .base = base, .disp = offset.* });
1582 offset.* += func.frame_allocs.items(.abi_size)[frame_i];
14101583}
14111584
1412fn computeFrameLayout(self: *Self) !FrameLayout {
1413 const frame_allocs_len = self.frame_allocs.len;
1414 try self.frame_locs.resize(self.gpa, frame_allocs_len);
1415 const stack_frame_order = try self.gpa.alloc(FrameIndex, frame_allocs_len - FrameIndex.named_count);
1416 defer self.gpa.free(stack_frame_order);
1585fn computeFrameLayout(func: *Func) !FrameLayout {
1586 const frame_allocs_len = func.frame_allocs.len;
1587 try func.frame_locs.resize(func.gpa, frame_allocs_len);
1588 const stack_frame_order = try func.gpa.alloc(FrameIndex, frame_allocs_len - FrameIndex.named_count);
1589 defer func.gpa.free(stack_frame_order);
14171590
1418 const frame_size = self.frame_allocs.items(.abi_size);
1419 const frame_align = self.frame_allocs.items(.abi_align);
1591 const frame_size = func.frame_allocs.items(.abi_size);
1592 const frame_align = func.frame_allocs.items(.abi_align);
14201593
14211594 for (stack_frame_order, FrameIndex.named_count..) |*frame_order, frame_index|
14221595 frame_order.* = @enumFromInt(frame_index);
......@@ -1433,9 +1606,9 @@ fn computeFrameLayout(self: *Self) !FrameLayout {
14331606 }
14341607
14351608 var save_reg_list = Mir.RegisterList{};
1436 for (callee_preserved_regs) |reg| {
1437 if (self.register_manager.isRegAllocated(reg)) {
1438 save_reg_list.push(&callee_preserved_regs, reg);
1609 for (abi.Registers.all_preserved) |reg| {
1610 if (func.register_manager.isRegAllocated(reg)) {
1611 save_reg_list.push(&abi.Registers.all_preserved, reg);
14391612 }
14401613 }
14411614
......@@ -1468,11 +1641,11 @@ fn computeFrameLayout(self: *Self) !FrameLayout {
14681641
14691642 // store the ra at total_size - 8, so it's the very first thing in the stack
14701643 // relative to the fp
1471 self.frame_locs.set(
1644 func.frame_locs.set(
14721645 @intFromEnum(FrameIndex.ret_addr),
14731646 .{ .base = .sp, .disp = acc_frame_size - 8 },
14741647 );
1475 self.frame_locs.set(
1648 func.frame_locs.set(
14761649 @intFromEnum(FrameIndex.base_ptr),
14771650 .{ .base = .sp, .disp = acc_frame_size - 16 },
14781651 );
......@@ -1481,11 +1654,11 @@ fn computeFrameLayout(self: *Self) !FrameLayout {
14811654 // not need to know the size of the first allocation. Stack offsets point at the "bottom"
14821655 // of variables.
14831656 var s0_offset: i32 = -acc_frame_size;
1484 self.setFrameLoc(.stack_frame, .s0, &s0_offset, true);
1485 for (stack_frame_order) |frame_index| self.setFrameLoc(frame_index, .s0, &s0_offset, true);
1486 self.setFrameLoc(.args_frame, .s0, &s0_offset, true);
1487 self.setFrameLoc(.call_frame, .s0, &s0_offset, true);
1488 self.setFrameLoc(.spill_frame, .s0, &s0_offset, true);
1657 func.setFrameLoc(.stack_frame, .s0, &s0_offset, true);
1658 for (stack_frame_order) |frame_index| func.setFrameLoc(frame_index, .s0, &s0_offset, true);
1659 func.setFrameLoc(.args_frame, .s0, &s0_offset, true);
1660 func.setFrameLoc(.call_frame, .s0, &s0_offset, true);
1661 func.setFrameLoc(.spill_frame, .s0, &s0_offset, true);
14891662
14901663 return .{
14911664 .stack_adjust = @intCast(acc_frame_size),
......@@ -1493,21 +1666,21 @@ fn computeFrameLayout(self: *Self) !FrameLayout {
14931666 };
14941667}
14951668
1496fn ensureProcessDeathCapacity(self: *Self, additional_count: usize) !void {
1497 const table = &self.branch_stack.items[self.branch_stack.items.len - 1].inst_table;
1498 try table.ensureUnusedCapacity(self.gpa, additional_count);
1669fn ensureProcessDeathCapacity(func: *Func, additional_count: usize) !void {
1670 const table = &func.branch_stack.items[func.branch_stack.items.len - 1].inst_table;
1671 try table.ensureUnusedCapacity(func.gpa, additional_count);
14991672}
15001673
1501fn memSize(self: *Self, ty: Type) Memory.Size {
1502 const mod = self.bin_file.comp.module.?;
1674fn memSize(func: *Func, ty: Type) Memory.Size {
1675 const mod = func.bin_file.comp.module.?;
15031676 return switch (ty.zigTypeTag(mod)) {
1504 .Float => Memory.Size.fromBitSize(ty.floatBits(self.target.*)),
1677 .Float => Memory.Size.fromBitSize(ty.floatBits(func.target.*)),
15051678 else => Memory.Size.fromByteSize(ty.abiSize(mod)),
15061679 };
15071680}
15081681
1509fn splitType(self: *Self, ty: Type) ![2]Type {
1510 const zcu = self.bin_file.comp.module.?;
1682fn splitType(func: *Func, ty: Type) ![2]Type {
1683 const zcu = func.bin_file.comp.module.?;
15111684 const classes = mem.sliceTo(&abi.classifySystem(ty, zcu), .none);
15121685 var parts: [2]Type = undefined;
15131686 if (classes.len == 2) for (&parts, classes, 0..) |*part, class, part_i| {
......@@ -1524,186 +1697,317 @@ fn splitType(self: *Self, ty: Type) ![2]Type {
15241697 },
15251698 else => unreachable,
15261699 },
1527 else => return self.fail("TODO: splitType class {}", .{class}),
1700 else => return func.fail("TODO: splitType class {}", .{class}),
15281701 };
15291702 } else if (parts[0].abiSize(zcu) + parts[1].abiSize(zcu) == ty.abiSize(zcu)) return parts;
1530 return self.fail("TODO implement splitType for {}", .{ty.fmt(zcu)});
1703 return func.fail("TODO implement splitType for {}", .{ty.fmt(zcu)});
1704}
1705
1706/// Truncates the value in the register in place.
1707/// Clobbers any remaining bits.
1708fn truncateRegister(func: *Func, ty: Type, reg: Register) !void {
1709 const mod = func.bin_file.comp.module.?;
1710 const int_info = if (ty.isAbiInt(mod)) ty.intInfo(mod) else std.builtin.Type.Int{
1711 .signedness = .unsigned,
1712 .bits = @intCast(ty.bitSize(mod)),
1713 };
1714 const shift = math.cast(u6, 64 - int_info.bits % 64) orelse return;
1715 switch (int_info.signedness) {
1716 .signed => {
1717 _ = try func.addInst(.{
1718 .tag = .slli,
1719 .ops = .rri,
1720 .data = .{
1721 .i_type = .{
1722 .rd = reg,
1723 .rs1 = reg,
1724 .imm12 = Immediate.u(shift),
1725 },
1726 },
1727 });
1728 _ = try func.addInst(.{
1729 .tag = .srai,
1730 .ops = .rri,
1731 .data = .{
1732 .i_type = .{
1733 .rd = reg,
1734 .rs1 = reg,
1735 .imm12 = Immediate.u(shift),
1736 },
1737 },
1738 });
1739 },
1740 .unsigned => {
1741 const mask = ~@as(u64, 0) >> shift;
1742 if (mask < 256) {
1743 _ = try func.addInst(.{
1744 .tag = .andi,
1745 .ops = .rri,
1746 .data = .{
1747 .i_type = .{
1748 .rd = reg,
1749 .rs1 = reg,
1750 .imm12 = Immediate.u(@intCast(mask)),
1751 },
1752 },
1753 });
1754 } else {
1755 _ = try func.addInst(.{
1756 .tag = .slli,
1757 .ops = .rri,
1758 .data = .{
1759 .i_type = .{
1760 .rd = reg,
1761 .rs1 = reg,
1762 .imm12 = Immediate.u(shift),
1763 },
1764 },
1765 });
1766 _ = try func.addInst(.{
1767 .tag = .srli,
1768 .ops = .rri,
1769 .data = .{
1770 .i_type = .{
1771 .rd = reg,
1772 .rs1 = reg,
1773 .imm12 = Immediate.u(shift),
1774 },
1775 },
1776 });
1777 }
1778 },
1779 }
15311780}
15321781
1533fn symbolIndex(self: *Self) !u32 {
1534 const zcu = self.bin_file.comp.module.?;
1535 const decl_index = zcu.funcOwnerDeclIndex(self.func_index);
1536 return switch (self.bin_file.tag) {
1782fn symbolIndex(func: *Func) !u32 {
1783 const zcu = func.bin_file.comp.module.?;
1784 const decl_index = zcu.funcOwnerDeclIndex(func.func_index);
1785 return switch (func.bin_file.tag) {
15371786 .elf => blk: {
1538 const elf_file = self.bin_file.cast(link.File.Elf).?;
1787 const elf_file = func.bin_file.cast(link.File.Elf).?;
15391788 const atom_index = try elf_file.zigObjectPtr().?.getOrCreateMetadataForDecl(elf_file, decl_index);
15401789 break :blk atom_index;
15411790 },
1542 else => return self.fail("TODO genSetReg load_symbol for {s}", .{@tagName(self.bin_file.tag)}),
1791 else => return func.fail("TODO symbolIndex {s}", .{@tagName(func.bin_file.tag)}),
15431792 };
15441793}
15451794
1546fn allocFrameIndex(self: *Self, alloc: FrameAlloc) !FrameIndex {
1547 const frame_allocs_slice = self.frame_allocs.slice();
1795fn allocFrameIndex(func: *Func, alloc: FrameAlloc) !FrameIndex {
1796 const frame_allocs_slice = func.frame_allocs.slice();
15481797 const frame_size = frame_allocs_slice.items(.abi_size);
15491798 const frame_align = frame_allocs_slice.items(.abi_align);
15501799
15511800 const stack_frame_align = &frame_align[@intFromEnum(FrameIndex.stack_frame)];
15521801 stack_frame_align.* = stack_frame_align.max(alloc.abi_align);
15531802
1554 for (self.free_frame_indices.keys(), 0..) |frame_index, free_i| {
1803 for (func.free_frame_indices.keys(), 0..) |frame_index, free_i| {
15551804 const abi_size = frame_size[@intFromEnum(frame_index)];
15561805 if (abi_size != alloc.abi_size) continue;
15571806 const abi_align = &frame_align[@intFromEnum(frame_index)];
15581807 abi_align.* = abi_align.max(alloc.abi_align);
15591808
1560 _ = self.free_frame_indices.swapRemoveAt(free_i);
1809 _ = func.free_frame_indices.swapRemoveAt(free_i);
15611810 return frame_index;
15621811 }
1563 const frame_index: FrameIndex = @enumFromInt(self.frame_allocs.len);
1564 try self.frame_allocs.append(self.gpa, alloc);
1812 const frame_index: FrameIndex = @enumFromInt(func.frame_allocs.len);
1813 try func.frame_allocs.append(func.gpa, alloc);
15651814 log.debug("allocated frame {}", .{frame_index});
15661815 return frame_index;
15671816}
15681817
15691818/// Use a pointer instruction as the basis for allocating stack memory.
1570fn allocMemPtr(self: *Self, inst: Air.Inst.Index) !FrameIndex {
1571 const zcu = self.bin_file.comp.module.?;
1572 const ptr_ty = self.typeOfIndex(inst);
1819fn allocMemPtr(func: *Func, inst: Air.Inst.Index) !FrameIndex {
1820 const zcu = func.bin_file.comp.module.?;
1821 const ptr_ty = func.typeOfIndex(inst);
15731822 const val_ty = ptr_ty.childType(zcu);
1574 return self.allocFrameIndex(FrameAlloc.init(.{
1823 return func.allocFrameIndex(FrameAlloc.init(.{
15751824 .size = math.cast(u32, val_ty.abiSize(zcu)) orelse {
1576 return self.fail("type '{}' too big to fit into stack frame", .{val_ty.fmt(zcu)});
1825 return func.fail("type '{}' too big to fit into stack frame", .{val_ty.fmt(zcu)});
15771826 },
15781827 .alignment = ptr_ty.ptrAlignment(zcu).max(.@"1"),
15791828 }));
15801829}
15811830
1582fn allocRegOrMem(self: *Self, inst: Air.Inst.Index, reg_ok: bool) !MCValue {
1583 const zcu = self.bin_file.comp.module.?;
1584 const elem_ty = self.typeOfIndex(inst);
1831fn typeRegClass(func: *Func, ty: Type) abi.RegisterClass {
1832 const zcu = func.bin_file.comp.module.?;
1833 return switch (ty.zigTypeTag(zcu)) {
1834 .Float => .float,
1835 .Vector => @panic("TODO: typeRegClass for Vectors"),
1836 inline else => .int,
1837 };
1838}
1839
1840fn regGeneralClassForType(func: *Func, ty: Type) RegisterManager.RegisterBitSet {
1841 const zcu = func.bin_file.comp.module.?;
1842 return switch (ty.zigTypeTag(zcu)) {
1843 .Float => abi.Registers.Float.general_purpose,
1844 .Vector => @panic("TODO: regGeneralClassForType for Vectors"),
1845 else => abi.Registers.Integer.general_purpose,
1846 };
1847}
1848
1849fn regTempClassForType(func: *Func, ty: Type) RegisterManager.RegisterBitSet {
1850 const zcu = func.bin_file.comp.module.?;
1851 return switch (ty.zigTypeTag(zcu)) {
1852 .Float => abi.Registers.Float.temporary,
1853 .Vector => @panic("TODO: regTempClassForType for Vectors"),
1854 else => abi.Registers.Integer.temporary,
1855 };
1856}
1857
1858fn allocRegOrMem(func: *Func, elem_ty: Type, inst: ?Air.Inst.Index, reg_ok: bool) !MCValue {
1859 const zcu = func.bin_file.comp.module.?;
15851860
15861861 const abi_size = math.cast(u32, elem_ty.abiSize(zcu)) orelse {
1587 return self.fail("type '{}' too big to fit into stack frame", .{elem_ty.fmt(zcu)});
1862 return func.fail("type '{}' too big to fit into stack frame", .{elem_ty.fmt(zcu)});
15881863 };
15891864
1590 if (reg_ok) {
1591 // Make sure the type can fit in a register before we try to allocate one.
1592 const ptr_bits = self.target.ptrBitWidth();
1593 const ptr_bytes: u64 = @divExact(ptr_bits, 8);
1594 if (abi_size <= ptr_bytes) {
1595 if (self.register_manager.tryAllocReg(inst, gp)) |reg| {
1596 return .{ .register = reg };
1597 }
1865 const min_size: u32 = switch (elem_ty.zigTypeTag(zcu)) {
1866 .Float => 4,
1867 .Vector => @panic("allocRegOrMem Vector"),
1868 else => 8,
1869 };
1870
1871 if (reg_ok and abi_size <= min_size) {
1872 if (func.register_manager.tryAllocReg(inst, func.regGeneralClassForType(elem_ty))) |reg| {
1873 return .{ .register = reg };
15981874 }
15991875 }
16001876
1601 const frame_index = try self.allocFrameIndex(FrameAlloc.initSpill(elem_ty, zcu));
1877 const frame_index = try func.allocFrameIndex(FrameAlloc.initSpill(elem_ty, zcu));
16021878 return .{ .load_frame = .{ .index = frame_index } };
16031879}
16041880
16051881/// Allocates a register from the general purpose set and returns the Register and the Lock.
16061882///
1607/// Up to the user to unlock the register later.
1608fn allocReg(self: *Self) !struct { Register, RegisterLock } {
1609 const reg = try self.register_manager.allocReg(null, gp);
1610 const lock = self.register_manager.lockRegAssumeUnused(reg);
1883/// Up to the caller to unlock the register later.
1884fn allocReg(func: *Func, reg_class: abi.RegisterClass) !struct { Register, RegisterLock } {
1885 if (reg_class == .float and !func.hasFeature(.f))
1886 std.debug.panic("allocReg class == float where F isn't enabled", .{});
1887
1888 const class = switch (reg_class) {
1889 .int => abi.Registers.Integer.general_purpose,
1890 .float => abi.Registers.Float.general_purpose,
1891 };
1892
1893 const reg = try func.register_manager.allocReg(null, class);
1894 const lock = func.register_manager.lockRegAssumeUnused(reg);
16111895 return .{ reg, lock };
16121896}
16131897
1614fn elemOffset(self: *Self, index_ty: Type, index: MCValue, elem_size: u64) !Register {
1898/// Similar to `allocReg` but will copy the MCValue into the Register unless `operand` is already
1899/// a register, in which case it will return a possible lock to that register.
1900fn promoteReg(func: *Func, ty: Type, operand: MCValue) !struct { Register, ?RegisterLock } {
1901 if (operand == .register) {
1902 const op_reg = operand.register;
1903 return .{ op_reg, func.register_manager.lockReg(operand.register) };
1904 }
1905
1906 const reg, const lock = try func.allocReg(func.typeRegClass(ty));
1907 try func.genSetReg(ty, reg, operand);
1908 return .{ reg, lock };
1909}
1910
1911fn elemOffset(func: *Func, index_ty: Type, index: MCValue, elem_size: u64) !Register {
16151912 const reg: Register = blk: {
16161913 switch (index) {
16171914 .immediate => |imm| {
16181915 // Optimisation: if index MCValue is an immediate, we can multiply in `comptime`
16191916 // and set the register directly to the scaled offset as an immediate.
1620 const reg = try self.register_manager.allocReg(null, gp);
1621 try self.genSetReg(index_ty, reg, .{ .immediate = imm * elem_size });
1917 const reg = try func.register_manager.allocReg(null, func.regGeneralClassForType(index_ty));
1918 try func.genSetReg(index_ty, reg, .{ .immediate = imm * elem_size });
16221919 break :blk reg;
16231920 },
16241921 else => {
1625 const reg = try self.copyToTmpRegister(index_ty, index);
1626 const lock = self.register_manager.lockRegAssumeUnused(reg);
1627 defer self.register_manager.unlockReg(lock);
1922 const reg = try func.copyToTmpRegister(index_ty, index);
1923 const lock = func.register_manager.lockRegAssumeUnused(reg);
1924 defer func.register_manager.unlockReg(lock);
1925
1926 const result_reg, const result_lock = try func.allocReg(.int);
1927 defer func.register_manager.unlockReg(result_lock);
16281928
1629 const result = try self.binOp(
1929 try func.genBinOp(
16301930 .mul,
16311931 .{ .register = reg },
16321932 index_ty,
16331933 .{ .immediate = elem_size },
16341934 index_ty,
1935 result_reg,
16351936 );
1636 break :blk result.register;
1937
1938 break :blk result_reg;
16371939 },
16381940 }
16391941 };
16401942 return reg;
16411943}
16421944
1643pub fn spillInstruction(self: *Self, reg: Register, inst: Air.Inst.Index) !void {
1644 const tracking = self.inst_tracking.getPtr(inst) orelse return;
1945pub fn spillInstruction(func: *Func, reg: Register, inst: Air.Inst.Index) !void {
1946 const tracking = func.inst_tracking.getPtr(inst) orelse return;
16451947 for (tracking.getRegs()) |tracked_reg| {
16461948 if (tracked_reg.id() == reg.id()) break;
16471949 } else unreachable; // spilled reg not tracked with spilled instruciton
1648 try tracking.spill(self, inst);
1649 try tracking.trackSpill(self, inst);
1950 try tracking.spill(func, inst);
1951 try tracking.trackSpill(func, inst);
16501952}
16511953
16521954/// Copies a value to a register without tracking the register. The register is not considered
16531955/// allocated. A second call to `copyToTmpRegister` may return the same register.
16541956/// This can have a side effect of spilling instructions to the stack to free up a register.
1655fn copyToTmpRegister(self: *Self, ty: Type, mcv: MCValue) !Register {
1656 const reg = try self.register_manager.allocReg(null, tp);
1657 try self.genSetReg(ty, reg, mcv);
1957fn copyToTmpRegister(func: *Func, ty: Type, mcv: MCValue) !Register {
1958 log.debug("copyToTmpRegister ty: {}", .{ty.fmt(func.bin_file.comp.module.?)});
1959 const reg = try func.register_manager.allocReg(null, func.regTempClassForType(ty));
1960 try func.genSetReg(ty, reg, mcv);
16581961 return reg;
16591962}
16601963
16611964/// Allocates a new register and copies `mcv` into it.
16621965/// `reg_owner` is the instruction that gets associated with the register in the register table.
16631966/// This can have a side effect of spilling instructions to the stack to free up a register.
1664fn copyToNewRegister(self: *Self, reg_owner: Air.Inst.Index, mcv: MCValue) !MCValue {
1665 const reg = try self.register_manager.allocReg(reg_owner, gp);
1666 try self.genSetReg(self.typeOfIndex(reg_owner), reg, mcv);
1967fn copyToNewRegister(func: *Func, reg_owner: Air.Inst.Index, mcv: MCValue) !MCValue {
1968 const ty = func.typeOfIndex(reg_owner);
1969 const reg = try func.register_manager.allocReg(reg_owner, func.regGeneralClassForType(ty));
1970 try func.genSetReg(func.typeOfIndex(reg_owner), reg, mcv);
16671971 return MCValue{ .register = reg };
16681972}
16691973
1670fn airAlloc(self: *Self, inst: Air.Inst.Index) !void {
1671 const result = MCValue{ .lea_frame = .{ .index = try self.allocMemPtr(inst) } };
1672 return self.finishAir(inst, result, .{ .none, .none, .none });
1974fn airAlloc(func: *Func, inst: Air.Inst.Index) !void {
1975 const result = MCValue{ .lea_frame = .{ .index = try func.allocMemPtr(inst) } };
1976 return func.finishAir(inst, result, .{ .none, .none, .none });
16731977}
16741978
1675fn airRetPtr(self: *Self, inst: Air.Inst.Index) !void {
1676 const result: MCValue = switch (self.ret_mcv.long) {
1677 .none => .{ .lea_frame = .{ .index = try self.allocMemPtr(inst) } },
1979fn airRetPtr(func: *Func, inst: Air.Inst.Index) !void {
1980 const result: MCValue = switch (func.ret_mcv.long) {
1981 .none => .{ .lea_frame = .{ .index = try func.allocMemPtr(inst) } },
16781982 .load_frame => .{ .register_offset = .{
1679 .reg = (try self.copyToNewRegister(
1983 .reg = (try func.copyToNewRegister(
16801984 inst,
1681 self.ret_mcv.long,
1985 func.ret_mcv.long,
16821986 )).register,
1683 .off = self.ret_mcv.short.indirect.off,
1987 .off = func.ret_mcv.short.indirect.off,
16841988 } },
1685 else => |t| return self.fail("TODO: airRetPtr {s}", .{@tagName(t)}),
1989 else => |t| return func.fail("TODO: airRetPtr {s}", .{@tagName(t)}),
16861990 };
1687 return self.finishAir(inst, result, .{ .none, .none, .none });
1991 return func.finishAir(inst, result, .{ .none, .none, .none });
16881992}
16891993
1690fn airFptrunc(self: *Self, inst: Air.Inst.Index) !void {
1691 const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
1692 const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else return self.fail("TODO implement airFptrunc for {}", .{self.target.cpu.arch});
1693 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
1994fn airFptrunc(func: *Func, inst: Air.Inst.Index) !void {
1995 const ty_op = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
1996 const result: MCValue = if (func.liveness.isUnused(inst)) .unreach else return func.fail("TODO implement airFptrunc for {}", .{func.target.cpu.arch});
1997 return func.finishAir(inst, result, .{ ty_op.operand, .none, .none });
16941998}
16951999
1696fn airFpext(self: *Self, inst: Air.Inst.Index) !void {
1697 const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
1698 const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else return self.fail("TODO implement airFpext for {}", .{self.target.cpu.arch});
1699 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
2000fn airFpext(func: *Func, inst: Air.Inst.Index) !void {
2001 const ty_op = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
2002 const result: MCValue = if (func.liveness.isUnused(inst)) .unreach else return func.fail("TODO implement airFpext for {}", .{func.target.cpu.arch});
2003 return func.finishAir(inst, result, .{ ty_op.operand, .none, .none });
17002004}
17012005
1702fn airIntCast(self: *Self, inst: Air.Inst.Index) !void {
1703 const zcu = self.bin_file.comp.module.?;
1704 const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
1705 const src_ty = self.typeOf(ty_op.operand);
1706 const dst_ty = self.typeOfIndex(inst);
2006fn airIntCast(func: *Func, inst: Air.Inst.Index) !void {
2007 const zcu = func.bin_file.comp.module.?;
2008 const ty_op = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
2009 const src_ty = func.typeOf(ty_op.operand);
2010 const dst_ty = func.typeOfIndex(inst);
17072011
17082012 const result: MCValue = result: {
17092013 const src_int_info = src_ty.intInfo(zcu);
......@@ -1711,20 +2015,20 @@ fn airIntCast(self: *Self, inst: Air.Inst.Index) !void {
17112015
17122016 const min_ty = if (dst_int_info.bits < src_int_info.bits) dst_ty else src_ty;
17132017
1714 const src_mcv = try self.resolveInst(ty_op.operand);
2018 const src_mcv = try func.resolveInst(ty_op.operand);
17152019
17162020 const src_storage_bits: u16 = switch (src_mcv) {
17172021 .register => 64,
17182022 .load_frame => src_int_info.bits,
1719 else => return self.fail("airIntCast from {s}", .{@tagName(src_mcv)}),
2023 else => return func.fail("airIntCast from {s}", .{@tagName(src_mcv)}),
17202024 };
17212025
17222026 const dst_mcv = if (dst_int_info.bits <= src_storage_bits and
17232027 math.divCeil(u16, dst_int_info.bits, 64) catch unreachable ==
17242028 math.divCeil(u32, src_storage_bits, 64) catch unreachable and
1725 self.reuseOperand(inst, ty_op.operand, 0, src_mcv)) src_mcv else dst: {
1726 const dst_mcv = try self.allocRegOrMem(inst, true);
1727 try self.genCopy(min_ty, dst_mcv, src_mcv);
2029 func.reuseOperand(inst, ty_op.operand, 0, src_mcv)) src_mcv else dst: {
2030 const dst_mcv = try func.allocRegOrMem(dst_ty, inst, true);
2031 try func.genCopy(min_ty, dst_mcv, src_mcv);
17282032 break :dst dst_mcv;
17292033 };
17302034
......@@ -1735,53 +2039,53 @@ fn airIntCast(self: *Self, inst: Air.Inst.Index) !void {
17352039 break :result null; // TODO
17362040
17372041 break :result dst_mcv;
1738 } orelse return self.fail("TODO implement airIntCast from {} to {}", .{
2042 } orelse return func.fail("TODO: implement airIntCast from {} to {}", .{
17392043 src_ty.fmt(zcu), dst_ty.fmt(zcu),
17402044 });
17412045
1742 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
2046 return func.finishAir(inst, result, .{ ty_op.operand, .none, .none });
17432047}
17442048
1745fn airTrunc(self: *Self, inst: Air.Inst.Index) !void {
1746 const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
1747 if (self.liveness.isUnused(inst))
1748 return self.finishAir(inst, .unreach, .{ ty_op.operand, .none, .none });
2049fn airTrunc(func: *Func, inst: Air.Inst.Index) !void {
2050 const ty_op = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
2051 if (func.liveness.isUnused(inst))
2052 return func.finishAir(inst, .unreach, .{ ty_op.operand, .none, .none });
17492053
1750 const operand = try self.resolveInst(ty_op.operand);
2054 const operand = try func.resolveInst(ty_op.operand);
17512055 _ = operand;
1752 return self.fail("TODO implement trunc for {}", .{self.target.cpu.arch});
1753 // return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
2056 return func.fail("TODO implement trunc for {}", .{func.target.cpu.arch});
2057 // return func.finishAir(inst, result, .{ ty_op.operand, .none, .none });
17542058}
17552059
1756fn airIntFromBool(self: *Self, inst: Air.Inst.Index) !void {
1757 const un_op = self.air.instructions.items(.data)[@intFromEnum(inst)].un_op;
1758 const operand = try self.resolveInst(un_op);
1759 const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else operand;
1760 return self.finishAir(inst, result, .{ un_op, .none, .none });
2060fn airIntFromBool(func: *Func, inst: Air.Inst.Index) !void {
2061 const un_op = func.air.instructions.items(.data)[@intFromEnum(inst)].un_op;
2062 const operand = try func.resolveInst(un_op);
2063 const result: MCValue = if (func.liveness.isUnused(inst)) .unreach else operand;
2064 return func.finishAir(inst, result, .{ un_op, .none, .none });
17612065}
17622066
1763fn airNot(self: *Self, inst: Air.Inst.Index) !void {
1764 const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
1765 const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else result: {
1766 const zcu = self.bin_file.comp.module.?;
2067fn airNot(func: *Func, inst: Air.Inst.Index) !void {
2068 const ty_op = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
2069 const result: MCValue = if (func.liveness.isUnused(inst)) .unreach else result: {
2070 const zcu = func.bin_file.comp.module.?;
17672071
1768 const operand = try self.resolveInst(ty_op.operand);
1769 const ty = self.typeOf(ty_op.operand);
2072 const operand = try func.resolveInst(ty_op.operand);
2073 const ty = func.typeOf(ty_op.operand);
17702074
17712075 switch (ty.zigTypeTag(zcu)) {
17722076 .Bool => {
17732077 const operand_reg = blk: {
17742078 if (operand == .register) break :blk operand.register;
1775 break :blk try self.copyToTmpRegister(ty, operand);
2079 break :blk try func.copyToTmpRegister(ty, operand);
17762080 };
17772081
17782082 const dst_reg: Register =
1779 if (self.reuseOperand(inst, ty_op.operand, 0, operand) and operand == .register)
2083 if (func.reuseOperand(inst, ty_op.operand, 0, operand) and operand == .register)
17802084 operand.register
17812085 else
1782 try self.register_manager.allocReg(inst, gp);
2086 (try func.allocRegOrMem(func.typeOfIndex(inst), inst, true)).register;
17832087
1784 _ = try self.addInst(.{
2088 _ = try func.addInst(.{
17852089 .tag = .pseudo,
17862090 .ops = .pseudo_not,
17872091 .data = .{
......@@ -1794,718 +2098,906 @@ fn airNot(self: *Self, inst: Air.Inst.Index) !void {
17942098
17952099 break :result .{ .register = dst_reg };
17962100 },
1797 .Int => return self.fail("TODO: airNot ints", .{}),
2101 .Int => return func.fail("TODO: airNot ints", .{}),
17982102 else => unreachable,
17992103 }
18002104 };
1801 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
2105 return func.finishAir(inst, result, .{ ty_op.operand, .none, .none });
18022106}
18032107
1804fn airMinMax(
1805 self: *Self,
1806 inst: Air.Inst.Index,
1807 comptime tag: enum {
1808 max,
1809 min,
1810 },
1811) !void {
1812 const zcu = self.bin_file.comp.module.?;
1813 const bin_op = self.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
1814
1815 const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else result: {
1816 const lhs = try self.resolveInst(bin_op.lhs);
1817 const rhs = try self.resolveInst(bin_op.rhs);
1818 const lhs_ty = self.typeOf(bin_op.lhs);
1819 const rhs_ty = self.typeOf(bin_op.rhs);
1820
1821 const int_info = lhs_ty.intInfo(zcu);
2108fn airSlice(func: *Func, inst: Air.Inst.Index) !void {
2109 const zcu = func.bin_file.comp.module.?;
2110 const ty_pl = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
2111 const bin_op = func.air.extraData(Air.Bin, ty_pl.payload).data;
18222112
1823 if (int_info.bits > 64) return self.fail("TODO: > 64 bit @min", .{});
2113 const slice_ty = func.typeOfIndex(inst);
2114 const frame_index = try func.allocFrameIndex(FrameAlloc.initSpill(slice_ty, zcu));
18242115
1825 const lhs_reg, const lhs_lock = blk: {
1826 if (lhs == .register) break :blk .{ lhs.register, null };
2116 const ptr_ty = func.typeOf(bin_op.lhs);
2117 try func.genSetMem(.{ .frame = frame_index }, 0, ptr_ty, .{ .air_ref = bin_op.lhs });
18272118
1828 const lhs_reg, const lhs_lock = try self.allocReg();
1829 try self.genSetReg(lhs_ty, lhs_reg, lhs);
1830 break :blk .{ lhs_reg, lhs_lock };
1831 };
1832 defer if (lhs_lock) |lock| self.register_manager.unlockReg(lock);
2119 const len_ty = func.typeOf(bin_op.rhs);
2120 try func.genSetMem(
2121 .{ .frame = frame_index },
2122 @intCast(ptr_ty.abiSize(zcu)),
2123 len_ty,
2124 .{ .air_ref = bin_op.rhs },
2125 );
18332126
1834 const rhs_reg, const rhs_lock = blk: {
1835 if (rhs == .register) break :blk .{ rhs.register, null };
2127 const result = MCValue{ .load_frame = .{ .index = frame_index } };
2128 return func.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
2129}
18362130
1837 const rhs_reg, const rhs_lock = try self.allocReg();
1838 try self.genSetReg(rhs_ty, rhs_reg, rhs);
1839 break :blk .{ rhs_reg, rhs_lock };
1840 };
1841 defer if (rhs_lock) |lock| self.register_manager.unlockReg(lock);
2131fn airBinOp(func: *Func, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void {
2132 const zcu = func.bin_file.comp.module.?;
2133 const bin_op = func.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
2134 const dst_mcv = try func.binOp(inst, tag, bin_op.lhs, bin_op.rhs);
18422135
1843 const mask_reg, const mask_lock = try self.allocReg();
1844 defer self.register_manager.unlockReg(mask_lock);
2136 const dst_ty = func.typeOfIndex(inst);
2137 if (dst_ty.isAbiInt(zcu)) {
2138 const abi_size: u32 = @intCast(dst_ty.abiSize(zcu));
2139 const bit_size: u32 = @intCast(dst_ty.bitSize(zcu));
2140 if (abi_size * 8 > bit_size) {
2141 const dst_lock = switch (dst_mcv) {
2142 .register => |dst_reg| func.register_manager.lockRegAssumeUnused(dst_reg),
2143 else => null,
2144 };
2145 defer if (dst_lock) |lock| func.register_manager.unlockReg(lock);
18452146
1846 const result_reg, const result_lock = try self.allocReg();
1847 defer self.register_manager.unlockReg(result_lock);
2147 if (dst_mcv.isRegister()) {
2148 try func.truncateRegister(dst_ty, dst_mcv.getReg().?);
2149 } else {
2150 const tmp_reg, const tmp_lock = try func.allocReg(.int);
2151 defer func.register_manager.unlockReg(tmp_lock);
2152
2153 const hi_ty = try zcu.intType(.unsigned, @intCast((dst_ty.bitSize(zcu) - 1) % 64 + 1));
2154 const hi_mcv = dst_mcv.address().offset(@intCast(bit_size / 64 * 8)).deref();
2155 try func.genSetReg(hi_ty, tmp_reg, hi_mcv);
2156 try func.truncateRegister(dst_ty, tmp_reg);
2157 try func.genCopy(hi_ty, hi_mcv, .{ .register = tmp_reg });
2158 }
2159 }
2160 }
18482161
1849 _ = try self.addInst(.{
1850 .tag = if (int_info.signedness == .unsigned) .sltu else .slt,
1851 .ops = .rrr,
1852 .data = .{ .r_type = .{
1853 .rd = mask_reg,
1854 .rs1 = lhs_reg,
1855 .rs2 = rhs_reg,
1856 } },
1857 });
2162 return func.finishAir(inst, dst_mcv, .{ bin_op.lhs, bin_op.rhs, .none });
2163}
18582164
1859 _ = try self.addInst(.{
1860 .tag = .sub,
1861 .ops = .rrr,
1862 .data = .{ .r_type = .{
1863 .rd = mask_reg,
1864 .rs1 = .zero,
1865 .rs2 = mask_reg,
1866 } },
1867 });
2165fn binOp(
2166 func: *Func,
2167 maybe_inst: ?Air.Inst.Index,
2168 air_tag: Air.Inst.Tag,
2169 lhs_air: Air.Inst.Ref,
2170 rhs_air: Air.Inst.Ref,
2171) !MCValue {
2172 _ = maybe_inst;
2173 const zcu = func.bin_file.comp.module.?;
2174 const lhs_ty = func.typeOf(lhs_air);
2175 const rhs_ty = func.typeOf(rhs_air);
2176
2177 if (lhs_ty.isRuntimeFloat()) libcall: {
2178 const float_bits = lhs_ty.floatBits(func.target.*);
2179 const type_needs_libcall = switch (float_bits) {
2180 16 => true,
2181 32, 64 => false,
2182 80, 128 => true,
2183 else => unreachable,
2184 };
2185 switch (air_tag) {
2186 .rem, .mod => {},
2187 else => if (!type_needs_libcall) break :libcall,
2188 }
2189 return func.fail("binOp libcall runtime-float ops", .{});
2190 }
18682191
1869 _ = try self.addInst(.{
1870 .tag = .xor,
1871 .ops = .rrr,
1872 .data = .{ .r_type = .{
1873 .rd = result_reg,
1874 .rs1 = lhs_reg,
1875 .rs2 = rhs_reg,
1876 } },
1877 });
2192 if (lhs_ty.bitSize(zcu) > 64) return func.fail("TODO: binOp >= 64 bits", .{});
18782193
1879 _ = try self.addInst(.{
1880 .tag = .@"and",
1881 .ops = .rrr,
1882 .data = .{ .r_type = .{
1883 .rd = mask_reg,
1884 .rs1 = result_reg,
1885 .rs2 = mask_reg,
1886 } },
1887 });
2194 const lhs_mcv = try func.resolveInst(lhs_air);
2195 const rhs_mcv = try func.resolveInst(rhs_air);
18882196
1889 _ = try self.addInst(.{
1890 .tag = .xor,
1891 .ops = .rrr,
1892 .data = .{ .r_type = .{
1893 .rd = result_reg,
1894 .rs1 = if (tag == .min) rhs_reg else lhs_reg,
1895 .rs2 = mask_reg,
1896 } },
1897 });
2197 const class_for_dst_ty: abi.RegisterClass = switch (air_tag) {
2198 // will always return int register no matter the input
2199 .cmp_eq,
2200 .cmp_neq,
2201 .cmp_lt,
2202 .cmp_lte,
2203 .cmp_gt,
2204 .cmp_gte,
2205 => .int,
18982206
1899 break :result .{ .register = result_reg };
2207 else => func.typeRegClass(lhs_ty),
19002208 };
1901 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
1902}
19032209
1904fn airSlice(self: *Self, inst: Air.Inst.Index) !void {
1905 const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
1906 const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data;
1907 const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else return self.fail("TODO implement slice for {}", .{self.target.cpu.arch});
1908 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
1909}
2210 const dst_reg, const dst_lock = try func.allocReg(class_for_dst_ty);
2211 defer func.register_manager.unlockReg(dst_lock);
19102212
1911fn airBinOp(self: *Self, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void {
1912 const bin_op = self.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
1913 const lhs = try self.resolveInst(bin_op.lhs);
1914 const rhs = try self.resolveInst(bin_op.rhs);
1915 const lhs_ty = self.typeOf(bin_op.lhs);
1916 const rhs_ty = self.typeOf(bin_op.rhs);
2213 try func.genBinOp(
2214 air_tag,
2215 lhs_mcv,
2216 lhs_ty,
2217 rhs_mcv,
2218 rhs_ty,
2219 dst_reg,
2220 );
19172221
1918 const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else result: {
1919 break :result try self.binOp(tag, lhs, lhs_ty, rhs, rhs_ty);
1920 };
1921 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
2222 return .{ .register = dst_reg };
19222223}
19232224
1924/// For all your binary operation needs, this function will generate
1925/// the corresponding Mir instruction(s). Returns the location of the
1926/// result.
1927///
1928/// If the binary operation itself happens to be an Air instruction,
1929/// pass the corresponding index in the inst parameter. That helps
1930/// this function do stuff like reusing operands.
2225/// Does the same thing as binOp however is meant to be used internally to the backend.
19312226///
1932/// This function does not do any lowering to Mir itself, but instead
1933/// looks at the lhs and rhs and determines which kind of lowering
1934/// would be best suitable and then delegates the lowering to other
1935/// functions.
2227/// The `dst_reg` argument is meant to be caller-locked. Asserts that the binOp result can be
2228/// fit into the register.
19362229///
1937/// `maybe_inst` **needs** to be a bin_op, make sure of that.
1938fn binOp(
1939 self: *Self,
2230/// Assumes that the `dst_reg` class is correct.
2231fn genBinOp(
2232 func: *Func,
19402233 tag: Air.Inst.Tag,
1941 lhs: MCValue,
2234 lhs_mcv: MCValue,
19422235 lhs_ty: Type,
1943 rhs: MCValue,
2236 rhs_mcv: MCValue,
19442237 rhs_ty: Type,
1945) InnerError!MCValue {
1946 const zcu = self.bin_file.comp.module.?;
2238 dst_reg: Register,
2239) !void {
2240 const zcu = func.bin_file.comp.module.?;
2241 const bit_size = lhs_ty.bitSize(zcu);
2242 assert(bit_size <= 64);
2243
2244 const is_unsigned = lhs_ty.isUnsignedInt(zcu);
2245
2246 const lhs_reg, const maybe_lhs_lock = try func.promoteReg(lhs_ty, lhs_mcv);
2247 const rhs_reg, const maybe_rhs_lock = try func.promoteReg(rhs_ty, rhs_mcv);
2248
2249 defer if (maybe_lhs_lock) |lock| func.register_manager.unlockReg(lock);
2250 defer if (maybe_rhs_lock) |lock| func.register_manager.unlockReg(lock);
19472251
19482252 switch (tag) {
1949 // Arithmetic operations on integers and floats
19502253 .add,
2254 .add_wrap,
19512255 .sub,
2256 .sub_wrap,
19522257 .mul,
1953 .cmp_eq,
1954 .cmp_neq,
1955 .cmp_gt,
1956 .cmp_gte,
1957 .cmp_lt,
1958 .cmp_lte,
2258 .mul_wrap,
19592259 => {
2260 if (!math.isPowerOfTwo(bit_size))
2261 return func.fail(
2262 "TODO: genBinOp {s} non-pow 2, found {}",
2263 .{ @tagName(tag), bit_size },
2264 );
2265
19602266 switch (lhs_ty.zigTypeTag(zcu)) {
1961 .Float => return self.fail("TODO binary operations on floats", .{}),
1962 .Vector => return self.fail("TODO binary operations on vectors", .{}),
19632267 .Int => {
1964 assert(lhs_ty.eql(rhs_ty, zcu));
1965 const int_info = lhs_ty.intInfo(zcu);
1966 if (int_info.bits <= 64) {
1967 return self.binOpRegister(tag, lhs, lhs_ty, rhs, rhs_ty);
1968 } else {
1969 return self.fail("TODO binary operations on int with bits > 64", .{});
2268 const mir_tag: Mir.Inst.Tag = switch (tag) {
2269 .add, .add_wrap => switch (bit_size) {
2270 8, 16, 64 => .add,
2271 32 => .addw,
2272 else => unreachable,
2273 },
2274 .sub, .sub_wrap => switch (bit_size) {
2275 8, 16, 32 => .subw,
2276 64 => .sub,
2277 else => unreachable,
2278 },
2279 .mul, .mul_wrap => switch (bit_size) {
2280 8, 16, 64 => .mul,
2281 32 => .mulw,
2282 else => unreachable,
2283 },
2284 else => unreachable,
2285 };
2286
2287 _ = try func.addInst(.{
2288 .tag = mir_tag,
2289 .ops = .rrr,
2290 .data = .{
2291 .r_type = .{
2292 .rd = dst_reg,
2293 .rs1 = lhs_reg,
2294 .rs2 = rhs_reg,
2295 },
2296 },
2297 });
2298
2299 // truncate when the instruction is larger than the bit size.
2300 switch (bit_size) {
2301 8, 16 => try func.truncateRegister(lhs_ty, dst_reg),
2302 32 => {}, // addw/subw affects the first 32-bits
2303 64 => {}, // add/sub affects the entire register
2304 else => unreachable,
19702305 }
19712306 },
1972 else => |x| return self.fail("TOOD: binOp {s}", .{@tagName(x)}),
2307 .Float => {
2308 const mir_tag: Mir.Inst.Tag = switch (tag) {
2309 .add => switch (bit_size) {
2310 32 => .fadds,
2311 64 => .faddd,
2312 else => unreachable,
2313 },
2314 .sub => switch (bit_size) {
2315 32 => .fsubs,
2316 64 => .fsubd,
2317 else => unreachable,
2318 },
2319 .mul => switch (bit_size) {
2320 32 => .fmuls,
2321 64 => .fmuld,
2322 else => unreachable,
2323 },
2324 else => unreachable,
2325 };
2326
2327 _ = try func.addInst(.{
2328 .tag = mir_tag,
2329 .ops = .rrr,
2330 .data = .{
2331 .r_type = .{
2332 .rd = dst_reg,
2333 .rs1 = lhs_reg,
2334 .rs2 = rhs_reg,
2335 },
2336 },
2337 });
2338 },
2339 else => unreachable,
19732340 }
19742341 },
19752342
19762343 .ptr_add,
19772344 .ptr_sub,
19782345 => {
1979 switch (lhs_ty.zigTypeTag(zcu)) {
1980 .Pointer => {
1981 const ptr_ty = lhs_ty;
1982 const elem_ty = switch (ptr_ty.ptrSize(zcu)) {
1983 .One => ptr_ty.childType(zcu).childType(zcu), // ptr to array, so get array element type
1984 else => ptr_ty.childType(zcu),
1985 };
1986 const elem_size = elem_ty.abiSize(zcu);
1987
1988 if (elem_size == 1) {
1989 const base_tag: Air.Inst.Tag = switch (tag) {
1990 .ptr_add => .add,
1991 .ptr_sub => .sub,
1992 else => unreachable,
1993 };
2346 const tmp_reg = try func.copyToTmpRegister(rhs_ty, .{ .register = rhs_reg });
2347 const tmp_mcv = MCValue{ .register = tmp_reg };
2348 const tmp_lock = func.register_manager.lockRegAssumeUnused(tmp_reg);
2349 defer func.register_manager.unlockReg(tmp_lock);
2350
2351 // RISC-V has no immediate mul, so we copy the size to a temporary register
2352 const elem_size = lhs_ty.elemType2(zcu).abiSize(zcu);
2353 const elem_size_reg = try func.copyToTmpRegister(Type.usize, .{ .immediate = elem_size });
2354
2355 try func.genBinOp(
2356 .mul,
2357 tmp_mcv,
2358 rhs_ty,
2359 .{ .register = elem_size_reg },
2360 Type.usize,
2361 tmp_reg,
2362 );
19942363
1995 return try self.binOpRegister(base_tag, lhs, lhs_ty, rhs, rhs_ty);
1996 } else {
1997 const offset = try self.binOp(
1998 .mul,
1999 rhs,
2000 Type.usize,
2001 .{ .immediate = elem_size },
2002 Type.usize,
2003 );
2364 try func.genBinOp(
2365 switch (tag) {
2366 .ptr_add => .add,
2367 .ptr_sub => .sub,
2368 else => unreachable,
2369 },
2370 lhs_mcv,
2371 Type.usize, // we know it's a pointer, so it'll be usize.
2372 tmp_mcv,
2373 Type.usize,
2374 dst_reg,
2375 );
2376 },
20042377
2005 const addr = try self.binOp(
2006 tag,
2007 lhs,
2008 Type.manyptr_u8,
2009 offset,
2010 Type.usize,
2011 );
2012 return addr;
2013 }
2378 .bit_and,
2379 .bit_or,
2380 .bool_and,
2381 .bool_or,
2382 => {
2383 _ = try func.addInst(.{
2384 .tag = switch (tag) {
2385 .bit_and, .bool_and => .@"and",
2386 .bit_or, .bool_or => .@"or",
2387 else => unreachable,
20142388 },
2015 else => unreachable,
2389 .ops = .rrr,
2390 .data = .{
2391 .r_type = .{
2392 .rd = dst_reg,
2393 .rs1 = lhs_reg,
2394 .rs2 = rhs_reg,
2395 },
2396 },
2397 });
2398
2399 switch (tag) {
2400 .bool_and,
2401 .bool_or,
2402 => try func.truncateRegister(Type.bool, dst_reg),
2403 else => {},
20162404 }
20172405 },
20182406
2019 // These instructions have unsymteric bit sizes on RHS and LHS.
2020 .shr,
2021 .shl,
2407 .div_trunc,
20222408 => {
2023 switch (lhs_ty.zigTypeTag(zcu)) {
2024 .Float => return self.fail("TODO binary operations on floats", .{}),
2025 .Vector => return self.fail("TODO binary operations on vectors", .{}),
2026 .Int => {
2027 const int_info = lhs_ty.intInfo(zcu);
2028 if (int_info.bits <= 64) {
2029 return self.binOpRegister(tag, lhs, lhs_ty, rhs, rhs_ty);
2030 } else {
2031 return self.fail("TODO binary operations on int with bits > 64", .{});
2032 }
2409 if (!math.isPowerOfTwo(bit_size))
2410 return func.fail(
2411 "TODO: genBinOp {s} non-pow 2, found {}",
2412 .{ @tagName(tag), bit_size },
2413 );
2414
2415 const mir_tag: Mir.Inst.Tag = switch (tag) {
2416 .div_trunc => switch (bit_size) {
2417 8, 16, 32 => if (is_unsigned) .divuw else .divw,
2418 64 => if (is_unsigned) .divu else .div,
2419 else => unreachable,
20332420 },
20342421 else => unreachable,
2035 }
2036 },
2037 else => return self.fail("TODO binOp {}", .{tag}),
2038 }
2039}
2040/// Don't call this function directly. Use binOp instead.
2041///
2042/// Calling this function signals an intention to generate a Mir
2043/// instruction of the form
2044///
2045/// op dest, lhs, rhs
2046///
2047/// Asserts that generating an instruction of that form is possible.
2048fn binOpRegister(
2049 self: *Self,
2050 tag: Air.Inst.Tag,
2051 lhs: MCValue,
2052 lhs_ty: Type,
2053 rhs: MCValue,
2054 rhs_ty: Type,
2055) !MCValue {
2056 const lhs_reg, const lhs_lock = blk: {
2057 if (lhs == .register) break :blk .{ lhs.register, null };
2058
2059 const lhs_reg, const lhs_lock = try self.allocReg();
2060 try self.genSetReg(lhs_ty, lhs_reg, lhs);
2061 break :blk .{ lhs_reg, lhs_lock };
2062 };
2063 defer if (lhs_lock) |lock| self.register_manager.unlockReg(lock);
2064
2065 const rhs_reg, const rhs_lock = blk: {
2066 if (rhs == .register) break :blk .{ rhs.register, null };
2067
2068 const rhs_reg, const rhs_lock = try self.allocReg();
2069 try self.genSetReg(rhs_ty, rhs_reg, rhs);
2070 break :blk .{ rhs_reg, rhs_lock };
2071 };
2072 defer if (rhs_lock) |lock| self.register_manager.unlockReg(lock);
2073
2074 const dest_reg, const dest_lock = try self.allocReg();
2075 defer self.register_manager.unlockReg(dest_lock);
2076
2077 const mir_tag: Mir.Inst.Tag = switch (tag) {
2078 .add => .add,
2079 .sub => .sub,
2080 .mul => .mul,
2081
2082 .shl => .sllw,
2083 .shr => .srlw,
2084
2085 .cmp_eq,
2086 .cmp_neq,
2087 .cmp_gt,
2088 .cmp_gte,
2089 .cmp_lt,
2090 .cmp_lte,
2091 => .pseudo,
2092
2093 else => return self.fail("TODO: binOpRegister {s}", .{@tagName(tag)}),
2094 };
2422 };
20952423
2096 switch (mir_tag) {
2097 .add,
2098 .sub,
2099 .mul,
2100 .sllw,
2101 .srlw,
2102 => {
2103 _ = try self.addInst(.{
2424 _ = try func.addInst(.{
21042425 .tag = mir_tag,
21052426 .ops = .rrr,
21062427 .data = .{
21072428 .r_type = .{
2108 .rd = dest_reg,
2429 .rd = dst_reg,
21092430 .rs1 = lhs_reg,
21102431 .rs2 = rhs_reg,
21112432 },
21122433 },
21132434 });
2435
2436 if (!is_unsigned) {
2437 // truncate when the instruction is larger than the bit size.
2438 switch (bit_size) {
2439 8, 16 => try func.truncateRegister(lhs_ty, dst_reg),
2440 32 => {}, // divw affects the first 32-bits
2441 64 => {}, // div affects the entire register
2442 else => unreachable,
2443 }
2444 }
21142445 },
21152446
2116 .pseudo => {
2117 const pseudo_op = switch (tag) {
2118 .cmp_eq,
2119 .cmp_neq,
2120 .cmp_gt,
2121 .cmp_gte,
2122 .cmp_lt,
2123 .cmp_lte,
2124 => .pseudo_compare,
2447 .shr,
2448 .shr_exact,
2449 .shl,
2450 .shl_exact,
2451 => {
2452 if (!math.isPowerOfTwo(bit_size))
2453 return func.fail(
2454 "TODO: genBinOp {s} non-pow 2, found {}",
2455 .{ @tagName(tag), bit_size },
2456 );
2457
2458 // it's important that the shift amount is exact
2459 try func.truncateRegister(rhs_ty, rhs_reg);
2460
2461 const mir_tag: Mir.Inst.Tag = switch (tag) {
2462 .shl, .shl_exact => switch (bit_size) {
2463 8, 16, 64 => .sll,
2464 32 => .sllw,
2465 else => unreachable,
2466 },
2467 .shr, .shr_exact => switch (bit_size) {
2468 8, 16, 64 => .srl,
2469 32 => .srlw,
2470 else => unreachable,
2471 },
21252472 else => unreachable,
21262473 };
21272474
2128 _ = try self.addInst(.{
2475 _ = try func.addInst(.{
2476 .tag = mir_tag,
2477 .ops = .rrr,
2478 .data = .{ .r_type = .{
2479 .rd = dst_reg,
2480 .rs1 = lhs_reg,
2481 .rs2 = rhs_reg,
2482 } },
2483 });
2484
2485 switch (bit_size) {
2486 8, 16 => try func.truncateRegister(lhs_ty, dst_reg),
2487 32 => {},
2488 64 => {},
2489 else => unreachable,
2490 }
2491 },
2492
2493 // TODO: move the isel logic out of lower and into here.
2494 .cmp_eq,
2495 .cmp_neq,
2496 .cmp_lt,
2497 .cmp_lte,
2498 .cmp_gt,
2499 .cmp_gte,
2500 => {
2501 _ = try func.addInst(.{
21292502 .tag = .pseudo,
2130 .ops = pseudo_op,
2503 .ops = .pseudo_compare,
21312504 .data = .{
21322505 .compare = .{
2133 .rd = dest_reg,
2134 .rs1 = lhs_reg,
2135 .rs2 = rhs_reg,
21362506 .op = switch (tag) {
21372507 .cmp_eq => .eq,
21382508 .cmp_neq => .neq,
2139 .cmp_gt => .gt,
2140 .cmp_gte => .gte,
21412509 .cmp_lt => .lt,
21422510 .cmp_lte => .lte,
2511 .cmp_gt => .gt,
2512 .cmp_gte => .gte,
21432513 else => unreachable,
21442514 },
2515 .rd = dst_reg,
2516 .rs1 = lhs_reg,
2517 .rs2 = rhs_reg,
2518 .ty = lhs_ty,
21452519 },
21462520 },
21472521 });
21482522 },
21492523
2150 else => unreachable,
2151 }
2152
2153 // generate the struct for OF checks
2154
2155 return MCValue{ .register = dest_reg };
2156}
2157
2158fn airPtrArithmetic(self: *Self, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void {
2159 const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
2160 const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data;
2161 const lhs = try self.resolveInst(bin_op.lhs);
2162 const rhs = try self.resolveInst(bin_op.rhs);
2163 const lhs_ty = self.typeOf(bin_op.lhs);
2164 const rhs_ty = self.typeOf(bin_op.rhs);
2165
2166 const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else result: {
2167 break :result try self.binOp(tag, lhs, lhs_ty, rhs, rhs_ty);
2168 };
2169 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
2170}
2171
2172fn airAddWrap(self: *Self, inst: Air.Inst.Index) !void {
2173 const bin_op = self.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
2174 const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else return self.fail("TODO implement addwrap for {}", .{self.target.cpu.arch});
2175 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
2176}
2177
2178fn airAddSat(self: *Self, inst: Air.Inst.Index) !void {
2179 const bin_op = self.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
2180 const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else return self.fail("TODO implement add_sat for {}", .{self.target.cpu.arch});
2181 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
2182}
2183
2184fn airSubWrap(self: *Self, inst: Air.Inst.Index) !void {
2185 const bin_op = self.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
2186 const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else result: {
2187 // RISCV arthemtic instructions already wrap, so this is simply a sub binOp with
2188 // no overflow checks.
2189 const lhs = try self.resolveInst(bin_op.lhs);
2190 const rhs = try self.resolveInst(bin_op.rhs);
2191 const lhs_ty = self.typeOf(bin_op.lhs);
2192 const rhs_ty = self.typeOf(bin_op.rhs);
2524 // A branchless @min/@max sequence.
2525 //
2526 // Assume that a0 and a1 are the lhs and rhs respectively.
2527 // Also assume that a2 is the destination register.
2528 //
2529 // Algorithm:
2530 // slt s0, a0, a1
2531 // sub s0, zero, s0
2532 // xor a2, a0, a1
2533 // and s0, a2, s0
2534 // xor a2, a0, s0 # a0 is @min, a1 is @max
2535 //
2536 // "slt s0, a0, a1" will set s0 to 1 if a0 is less than a1, and 1 otherwise.
2537 //
2538 // "sub s0, zero, s0" will set all the bits of s0 to 1 if it was 1, otherwise it'll remain at 0.
2539 //
2540 // "xor a2, a0, a1" stores the bitwise XOR of a0 and a1 in a2. Effectively getting the difference between them.
2541 //
2542 // "and a0, a2, s0" here we mask the result of the XOR with the negated s0. If a0 < a1, s0 is -1, which
2543 // doesn't change the bits of a2. If a0 >= a1, s0 is 0, nullifying a2.
2544 //
2545 // "xor a2, a0, s0" the final XOR operation adjusts a2 to be the minimum value of a0 and a1. If a0 was less than
2546 // a1, s0 was -1, flipping all the bits in a2 and effectively restoring a0. If a0 was greater than or equal to a1,
2547 // s0 was 0, leaving a2 unchanged as a0.
2548 .min, .max => {
2549 const int_info = lhs_ty.intInfo(zcu);
2550
2551 const mask_reg, const mask_lock = try func.allocReg(.int);
2552 defer func.register_manager.unlockReg(mask_lock);
2553
2554 _ = try func.addInst(.{
2555 .tag = if (int_info.signedness == .unsigned) .sltu else .slt,
2556 .ops = .rrr,
2557 .data = .{ .r_type = .{
2558 .rd = mask_reg,
2559 .rs1 = lhs_reg,
2560 .rs2 = rhs_reg,
2561 } },
2562 });
21932563
2194 break :result try self.binOp(.sub, lhs, lhs_ty, rhs, rhs_ty);
2195 };
2196 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
2197}
2564 _ = try func.addInst(.{
2565 .tag = .sub,
2566 .ops = .rrr,
2567 .data = .{ .r_type = .{
2568 .rd = mask_reg,
2569 .rs1 = .zero,
2570 .rs2 = mask_reg,
2571 } },
2572 });
21982573
2199fn airSubSat(self: *Self, inst: Air.Inst.Index) !void {
2200 const bin_op = self.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
2201 const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else return self.fail("TODO implement sub_sat for {}", .{self.target.cpu.arch});
2202 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
2203}
2574 _ = try func.addInst(.{
2575 .tag = .xor,
2576 .ops = .rrr,
2577 .data = .{ .r_type = .{
2578 .rd = dst_reg,
2579 .rs1 = lhs_reg,
2580 .rs2 = rhs_reg,
2581 } },
2582 });
22042583
2205fn airMul(self: *Self, inst: Air.Inst.Index) !void {
2206 const bin_op = self.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
2207 const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else return self.fail("TODO implement mul for {}", .{self.target.cpu.arch});
2208 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
2209}
2584 _ = try func.addInst(.{
2585 .tag = .@"and",
2586 .ops = .rrr,
2587 .data = .{ .r_type = .{
2588 .rd = mask_reg,
2589 .rs1 = dst_reg,
2590 .rs2 = mask_reg,
2591 } },
2592 });
22102593
2211fn airMulWrap(self: *Self, inst: Air.Inst.Index) !void {
2212 const bin_op = self.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
2213 const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else return self.fail("TODO implement mulwrap for {}", .{self.target.cpu.arch});
2214 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
2594 _ = try func.addInst(.{
2595 .tag = .xor,
2596 .ops = .rrr,
2597 .data = .{ .r_type = .{
2598 .rd = dst_reg,
2599 .rs1 = if (tag == .min) rhs_reg else lhs_reg,
2600 .rs2 = mask_reg,
2601 } },
2602 });
2603 },
2604 else => return func.fail("TODO: genBinOp {}", .{tag}),
2605 }
22152606}
22162607
2217fn airMulSat(self: *Self, inst: Air.Inst.Index) !void {
2218 const bin_op = self.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
2219 const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else return self.fail("TODO implement mul_sat for {}", .{self.target.cpu.arch});
2220 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
2608fn airPtrArithmetic(func: *Func, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void {
2609 const ty_pl = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
2610 const bin_op = func.air.extraData(Air.Bin, ty_pl.payload).data;
2611 const dst_mcv = try func.binOp(inst, tag, bin_op.lhs, bin_op.rhs);
2612 return func.finishAir(inst, dst_mcv, .{ bin_op.lhs, bin_op.rhs, .none });
22212613}
22222614
2223fn airAddWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
2224 const zcu = self.bin_file.comp.module.?;
2225 const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
2226 const extra = self.air.extraData(Air.Bin, ty_pl.payload).data;
2615fn airAddWithOverflow(func: *Func, inst: Air.Inst.Index) !void {
2616 const zcu = func.bin_file.comp.module.?;
2617 const ty_pl = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
2618 const extra = func.air.extraData(Air.Bin, ty_pl.payload).data;
22272619
2228 const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else result: {
2229 const lhs = try self.resolveInst(extra.lhs);
2230 const rhs = try self.resolveInst(extra.rhs);
2231 const lhs_ty = self.typeOf(extra.lhs);
2232 const rhs_ty = self.typeOf(extra.rhs);
2620 const result: MCValue = if (func.liveness.isUnused(inst)) .unreach else result: {
2621 const lhs_ty = func.typeOf(extra.lhs);
22332622
22342623 const int_info = lhs_ty.intInfo(zcu);
22352624
2236 const tuple_ty = self.typeOfIndex(inst);
2237 const result_mcv = try self.allocRegOrMem(inst, false);
2625 const tuple_ty = func.typeOfIndex(inst);
2626 const result_mcv = try func.allocRegOrMem(tuple_ty, inst, false);
22382627 const offset = result_mcv.load_frame;
22392628
22402629 if (int_info.bits >= 8 and math.isPowerOfTwo(int_info.bits)) {
2241 const add_result = try self.binOp(.add, lhs, lhs_ty, rhs, rhs_ty);
2242 const add_result_reg = try self.copyToTmpRegister(lhs_ty, add_result);
2243 const add_result_reg_lock = self.register_manager.lockRegAssumeUnused(add_result_reg);
2244 defer self.register_manager.unlockReg(add_result_reg_lock);
2630 const add_result = try func.binOp(null, .add, extra.lhs, extra.rhs);
2631 const add_result_reg = try func.copyToTmpRegister(lhs_ty, add_result);
2632 const add_result_reg_lock = func.register_manager.lockRegAssumeUnused(add_result_reg);
2633 defer func.register_manager.unlockReg(add_result_reg_lock);
22452634
22462635 const shift_amount: u6 = @intCast(Type.usize.bitSize(zcu) - int_info.bits);
22472636
2248 const shift_reg, const shift_lock = try self.allocReg();
2249 defer self.register_manager.unlockReg(shift_lock);
2637 const shift_reg, const shift_lock = try func.allocReg(.int);
2638 defer func.register_manager.unlockReg(shift_lock);
22502639
2251 _ = try self.addInst(.{
2640 _ = try func.addInst(.{
22522641 .tag = .slli,
22532642 .ops = .rri,
22542643 .data = .{
22552644 .i_type = .{
22562645 .rd = shift_reg,
22572646 .rs1 = add_result_reg,
2258 .imm12 = Immediate.s(shift_amount),
2647 .imm12 = Immediate.u(shift_amount),
22592648 },
22602649 },
22612650 });
22622651
2263 _ = try self.addInst(.{
2652 _ = try func.addInst(.{
22642653 .tag = if (int_info.signedness == .unsigned) .srli else .srai,
22652654 .ops = .rri,
22662655 .data = .{
22672656 .i_type = .{
22682657 .rd = shift_reg,
22692658 .rs1 = shift_reg,
2270 .imm12 = Immediate.s(shift_amount),
2659 .imm12 = Immediate.u(shift_amount),
22712660 },
22722661 },
22732662 });
22742663
2275 const add_result_frame: FrameAddr = .{
2276 .index = offset.index,
2277 .off = offset.off + @as(i32, @intCast(tuple_ty.structFieldOffset(0, zcu))),
2278 };
2279 try self.genSetStack(
2664 try func.genSetMem(
2665 .{ .frame = offset.index },
2666 offset.off + @as(i32, @intCast(tuple_ty.structFieldOffset(0, zcu))),
22802667 lhs_ty,
2281 add_result_frame,
22822668 add_result,
22832669 );
22842670
2285 const overflow_mcv = try self.binOp(
2671 const overflow_reg, const overflow_lock = try func.allocReg(.int);
2672 defer func.register_manager.unlockReg(overflow_lock);
2673
2674 try func.genBinOp(
22862675 .cmp_neq,
22872676 .{ .register = shift_reg },
22882677 lhs_ty,
22892678 .{ .register = add_result_reg },
22902679 lhs_ty,
2680 overflow_reg,
22912681 );
22922682
2293 const overflow_frame: FrameAddr = .{
2294 .index = offset.index,
2295 .off = offset.off + @as(i32, @intCast(tuple_ty.structFieldOffset(1, zcu))),
2296 };
2297 try self.genSetStack(
2683 try func.genSetMem(
2684 .{ .frame = offset.index },
2685 offset.off + @as(i32, @intCast(tuple_ty.structFieldOffset(1, zcu))),
22982686 Type.u1,
2299 overflow_frame,
2300 overflow_mcv,
2687 .{ .register = overflow_reg },
23012688 );
23022689
23032690 break :result result_mcv;
23042691 } else {
2305 return self.fail("TODO: less than 8 bit or non-pow 2 addition", .{});
2692 return func.fail("TODO: less than 8 bit or non-pow 2 addition", .{});
23062693 }
23072694 };
23082695
2309 return self.finishAir(inst, result, .{ extra.lhs, extra.rhs, .none });
2696 return func.finishAir(inst, result, .{ extra.lhs, extra.rhs, .none });
23102697}
23112698
2312fn airSubWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
2313 _ = inst;
2314 return self.fail("TODO implement airSubWithOverflow for {}", .{self.target.cpu.arch});
2699fn airSubWithOverflow(func: *Func, inst: Air.Inst.Index) !void {
2700 const zcu = func.bin_file.comp.module.?;
2701 const ty_pl = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
2702 const extra = func.air.extraData(Air.Bin, ty_pl.payload).data;
2703
2704 const result: MCValue = if (func.liveness.isUnused(inst)) .unreach else result: {
2705 const lhs = try func.resolveInst(extra.lhs);
2706 const rhs = try func.resolveInst(extra.rhs);
2707 const lhs_ty = func.typeOf(extra.lhs);
2708 const rhs_ty = func.typeOf(extra.rhs);
2709
2710 const int_info = lhs_ty.intInfo(zcu);
2711
2712 if (!math.isPowerOfTwo(int_info.bits) or int_info.bits < 8) {
2713 return func.fail("TODO: airSubWithOverflow non-power of 2 and less than 8 bits", .{});
2714 }
2715
2716 if (int_info.bits > 64) {
2717 return func.fail("TODO: airSubWithOverflow > 64 bits", .{});
2718 }
2719
2720 const tuple_ty = func.typeOfIndex(inst);
2721 const result_mcv = try func.allocRegOrMem(tuple_ty, inst, false);
2722 const offset = result_mcv.load_frame;
2723
2724 const dest_mcv = try func.binOp(null, .sub, extra.lhs, extra.rhs);
2725 assert(dest_mcv == .register);
2726 const dest_reg = dest_mcv.register;
2727
2728 try func.genSetMem(
2729 .{ .frame = offset.index },
2730 offset.off + @as(i32, @intCast(tuple_ty.structFieldOffset(0, zcu))),
2731 lhs_ty,
2732 .{ .register = dest_reg },
2733 );
2734
2735 const lhs_reg, const lhs_lock = try func.promoteReg(lhs_ty, lhs);
2736 defer if (lhs_lock) |lock| func.register_manager.unlockReg(lock);
2737
2738 const rhs_reg, const rhs_lock = try func.promoteReg(rhs_ty, rhs);
2739 defer if (rhs_lock) |lock| func.register_manager.unlockReg(lock);
2740
2741 const overflow_reg = try func.copyToTmpRegister(Type.usize, .{ .immediate = 0 });
2742
2743 const overflow_lock = func.register_manager.lockRegAssumeUnused(overflow_reg);
2744 defer func.register_manager.unlockReg(overflow_lock);
2745
2746 switch (int_info.signedness) {
2747 .unsigned => {
2748 _ = try func.addInst(.{
2749 .tag = .sltu,
2750 .ops = .rrr,
2751 .data = .{ .r_type = .{
2752 .rd = overflow_reg,
2753 .rs1 = lhs_reg,
2754 .rs2 = rhs_reg,
2755 } },
2756 });
2757
2758 try func.genSetMem(
2759 .{ .frame = offset.index },
2760 offset.off + @as(i32, @intCast(tuple_ty.structFieldOffset(1, zcu))),
2761 Type.u1,
2762 .{ .register = overflow_reg },
2763 );
2764
2765 break :result result_mcv;
2766 },
2767 .signed => {
2768 switch (int_info.bits) {
2769 64 => {
2770 _ = try func.addInst(.{
2771 .tag = .slt,
2772 .ops = .rrr,
2773 .data = .{ .r_type = .{
2774 .rd = overflow_reg,
2775 .rs1 = overflow_reg,
2776 .rs2 = rhs_reg,
2777 } },
2778 });
2779
2780 _ = try func.addInst(.{
2781 .tag = .slt,
2782 .ops = .rrr,
2783 .data = .{ .r_type = .{
2784 .rd = rhs_reg,
2785 .rs1 = rhs_reg,
2786 .rs2 = lhs_reg,
2787 } },
2788 });
2789
2790 _ = try func.addInst(.{
2791 .tag = .xor,
2792 .ops = .rrr,
2793 .data = .{ .r_type = .{
2794 .rd = lhs_reg,
2795 .rs1 = overflow_reg,
2796 .rs2 = rhs_reg,
2797 } },
2798 });
2799
2800 try func.genBinOp(
2801 .cmp_neq,
2802 .{ .register = overflow_reg },
2803 Type.usize,
2804 .{ .register = rhs_reg },
2805 Type.usize,
2806 overflow_reg,
2807 );
2808
2809 try func.genSetMem(
2810 .{ .frame = offset.index },
2811 offset.off + @as(i32, @intCast(tuple_ty.structFieldOffset(1, zcu))),
2812 Type.u1,
2813 .{ .register = overflow_reg },
2814 );
2815
2816 break :result result_mcv;
2817 },
2818 else => |int_bits| return func.fail("TODO: airSubWithOverflow signed {}", .{int_bits}),
2819 }
2820 },
2821 }
2822 };
2823
2824 return func.finishAir(inst, result, .{ extra.lhs, extra.rhs, .none });
23152825}
23162826
2317fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
2318 //const tag = self.air.instructions.items(.tag)[@intFromEnum(inst)];
2319 const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
2320 const extra = self.air.extraData(Air.Bin, ty_pl.payload).data;
2321 const zcu = self.bin_file.comp.module.?;
2322 const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else result: {
2323 const lhs = try self.resolveInst(extra.lhs);
2324 const rhs = try self.resolveInst(extra.rhs);
2325 const lhs_ty = self.typeOf(extra.lhs);
2326 const rhs_ty = self.typeOf(extra.rhs);
2827fn airMulWithOverflow(func: *Func, inst: Air.Inst.Index) !void {
2828 const zcu = func.bin_file.comp.module.?;
2829 const ty_pl = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
2830 const extra = func.air.extraData(Air.Bin, ty_pl.payload).data;
2831
2832 const result: MCValue = if (func.liveness.isUnused(inst)) .unreach else result: {
2833 const lhs = try func.resolveInst(extra.lhs);
2834 const rhs = try func.resolveInst(extra.rhs);
2835 const lhs_ty = func.typeOf(extra.lhs);
2836 const rhs_ty = func.typeOf(extra.rhs);
2837
2838 const tuple_ty = func.typeOfIndex(inst);
2839
2840 // genSetReg needs to support register_offset src_mcv for this to be true.
2841 const result_mcv = try func.allocRegOrMem(tuple_ty, inst, false);
2842
2843 const result_off: i32 = @intCast(tuple_ty.structFieldOffset(0, zcu));
2844 const overflow_off: i32 = @intCast(tuple_ty.structFieldOffset(1, zcu));
2845
2846 const dest_reg, const dest_lock = try func.allocReg(.int);
2847 defer func.register_manager.unlockReg(dest_lock);
2848
2849 try func.genBinOp(
2850 .mul,
2851 lhs,
2852 lhs_ty,
2853 rhs,
2854 rhs_ty,
2855 dest_reg,
2856 );
2857
2858 try func.genCopy(
2859 lhs_ty,
2860 result_mcv.offset(result_off),
2861 .{ .register = dest_reg },
2862 );
23272863
23282864 switch (lhs_ty.zigTypeTag(zcu)) {
2329 else => |x| return self.fail("TODO: airMulWithOverflow {s}", .{@tagName(x)}),
2865 else => |x| return func.fail("TODO: airMulWithOverflow {s}", .{@tagName(x)}),
23302866 .Int => {
23312867 assert(lhs_ty.eql(rhs_ty, zcu));
23322868 const int_info = lhs_ty.intInfo(zcu);
23332869 switch (int_info.bits) {
23342870 1...32 => {
2335 if (self.hasFeature(.m)) {
2336 const dest = try self.binOp(.mul, lhs, lhs_ty, rhs, rhs_ty);
2337
2338 const add_result_lock = self.register_manager.lockRegAssumeUnused(dest.register);
2339 defer self.register_manager.unlockReg(add_result_lock);
2340
2341 const tuple_ty = self.typeOfIndex(inst);
2342
2343 // TODO: optimization, set this to true. needs the other struct access stuff to support
2344 // accessing registers.
2345 const result_mcv = try self.allocRegOrMem(inst, false);
2346
2347 const result_off: i32 = @intCast(tuple_ty.structFieldOffset(0, zcu));
2348 const overflow_off: i32 = @intCast(tuple_ty.structFieldOffset(1, zcu));
2349
2350 try self.genSetStack(lhs_ty, result_mcv.offset(result_off).load_frame, dest);
2351
2352 if (int_info.bits >= 8 and math.isPowerOfTwo(int_info.bits)) {
2353 if (int_info.signedness == .unsigned) {
2354 switch (int_info.bits) {
2355 1...8 => {
2356 const max_val = std.math.pow(u16, 2, int_info.bits) - 1;
2357
2358 const overflow_reg, const overflow_lock = try self.allocReg();
2359 defer self.register_manager.unlockReg(overflow_lock);
2360
2361 const add_reg, const add_lock = blk: {
2362 if (dest == .register) break :blk .{ dest.register, null };
2363
2364 const add_reg, const add_lock = try self.allocReg();
2365 try self.genSetReg(lhs_ty, add_reg, dest);
2366 break :blk .{ add_reg, add_lock };
2367 };
2368 defer if (add_lock) |lock| self.register_manager.unlockReg(lock);
2369
2370 _ = try self.addInst(.{
2371 .tag = .andi,
2372 .ops = .rri,
2373 .data = .{ .i_type = .{
2374 .rd = overflow_reg,
2375 .rs1 = add_reg,
2376 .imm12 = Immediate.s(max_val),
2377 } },
2378 });
2379
2380 const overflow_mcv = try self.binOp(
2381 .cmp_neq,
2382 .{ .register = overflow_reg },
2383 lhs_ty,
2384 .{ .register = add_reg },
2385 lhs_ty,
2386 );
2387
2388 try self.genSetStack(
2389 lhs_ty,
2390 result_mcv.offset(overflow_off).load_frame,
2391 overflow_mcv,
2392 );
2393
2394 break :result result_mcv;
2395 },
2396
2397 else => return self.fail("TODO: airMulWithOverflow check for size {d}", .{int_info.bits}),
2398 }
2399 } else {
2400 return self.fail("TODO: airMulWithOverflow calculate carry for signed addition", .{});
2871 if (int_info.bits >= 8 and math.isPowerOfTwo(int_info.bits)) {
2872 if (int_info.signedness == .unsigned) {
2873 switch (int_info.bits) {
2874 1...8 => {
2875 const max_val = std.math.pow(u16, 2, int_info.bits) - 1;
2876
2877 const add_reg, const add_lock = try func.promoteReg(lhs_ty, lhs);
2878 defer if (add_lock) |lock| func.register_manager.unlockReg(lock);
2879
2880 const overflow_reg, const overflow_lock = try func.allocReg(.int);
2881 defer func.register_manager.unlockReg(overflow_lock);
2882
2883 _ = try func.addInst(.{
2884 .tag = .andi,
2885 .ops = .rri,
2886 .data = .{ .i_type = .{
2887 .rd = overflow_reg,
2888 .rs1 = add_reg,
2889 .imm12 = Immediate.s(max_val),
2890 } },
2891 });
2892
2893 try func.genBinOp(
2894 .cmp_neq,
2895 .{ .register = overflow_reg },
2896 lhs_ty,
2897 .{ .register = add_reg },
2898 lhs_ty,
2899 overflow_reg,
2900 );
2901
2902 try func.genCopy(
2903 lhs_ty,
2904 result_mcv.offset(overflow_off),
2905 .{ .register = overflow_reg },
2906 );
2907
2908 break :result result_mcv;
2909 },
2910
2911 else => return func.fail("TODO: airMulWithOverflow check for size {d}", .{int_info.bits}),
24012912 }
24022913 } else {
2403 return self.fail("TODO: airMulWithOverflow with < 8 bits or non-pow of 2", .{});
2914 return func.fail("TODO: airMulWithOverflow calculate carry for signed addition", .{});
24042915 }
24052916 } else {
2406 return self.fail("TODO: emulate mul for targets without M feature", .{});
2917 return func.fail("TODO: airMulWithOverflow with < 8 bits or non-pow of 2", .{});
24072918 }
24082919 },
2409 else => return self.fail("TODO: airMulWithOverflow larger than 32-bit mul", .{}),
2920 else => return func.fail("TODO: airMulWithOverflow larger than 32-bit mul", .{}),
24102921 }
24112922 },
24122923 }
24132924 };
24142925
2415 return self.finishAir(inst, result, .{ extra.lhs, extra.rhs, .none });
2926 return func.finishAir(inst, result, .{ extra.lhs, extra.rhs, .none });
24162927}
24172928
2418fn airShlWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
2419 _ = inst;
2420 return self.fail("TODO implement airShlWithOverflow for {}", .{self.target.cpu.arch});
2421}
2422
2423fn airDiv(self: *Self, inst: Air.Inst.Index) !void {
2424 const bin_op = self.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
2425 const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else return self.fail("TODO implement div for {}", .{self.target.cpu.arch});
2426 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
2427}
2428
2429fn airRem(self: *Self, inst: Air.Inst.Index) !void {
2430 const bin_op = self.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
2431 const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else return self.fail("TODO implement rem for {}", .{self.target.cpu.arch});
2432 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
2929fn airShlWithOverflow(func: *Func, inst: Air.Inst.Index) !void {
2930 const bin_op = func.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
2931 const result: MCValue = if (func.liveness.isUnused(inst)) .unreach else return func.fail("TODO implement airShlWithOverflow", .{});
2932 return func.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
24332933}
24342934
2435fn airMod(self: *Self, inst: Air.Inst.Index) !void {
2436 const bin_op = self.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
2437 const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else return self.fail("TODO implement zcu for {}", .{self.target.cpu.arch});
2438 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
2935fn airAddSat(func: *Func, inst: Air.Inst.Index) !void {
2936 const bin_op = func.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
2937 const result: MCValue = if (func.liveness.isUnused(inst)) .unreach else return func.fail("TODO implement airAddSat", .{});
2938 return func.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
24392939}
24402940
2441fn airBitAnd(self: *Self, inst: Air.Inst.Index) !void {
2442 const bin_op = self.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
2443 const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else return self.fail("TODO implement bitwise and for {}", .{self.target.cpu.arch});
2444 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
2941fn airSubSat(func: *Func, inst: Air.Inst.Index) !void {
2942 const bin_op = func.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
2943 const result: MCValue = if (func.liveness.isUnused(inst)) .unreach else return func.fail("TODO implement airSubSat", .{});
2944 return func.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
24452945}
24462946
2447fn airBitOr(self: *Self, inst: Air.Inst.Index) !void {
2448 const bin_op = self.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
2449 const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else return self.fail("TODO implement bitwise or for {}", .{self.target.cpu.arch});
2450 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
2947fn airMulSat(func: *Func, inst: Air.Inst.Index) !void {
2948 const bin_op = func.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
2949 const result: MCValue = if (func.liveness.isUnused(inst)) .unreach else return func.fail("TODO implement airMulSat", .{});
2950 return func.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
24512951}
24522952
2453fn airXor(self: *Self, inst: Air.Inst.Index) !void {
2454 const bin_op = self.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
2455 const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else return self.fail("TODO implement xor for {}", .{self.target.cpu.arch});
2456 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
2953fn airShlSat(func: *Func, inst: Air.Inst.Index) !void {
2954 const bin_op = func.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
2955 const result: MCValue = if (func.liveness.isUnused(inst)) .unreach else return func.fail("TODO implement airShlSat", .{});
2956 return func.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
24572957}
24582958
2459fn airShl(self: *Self, inst: Air.Inst.Index) !void {
2460 const bin_op = self.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
2461 const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else result: {
2462 const lhs = try self.resolveInst(bin_op.lhs);
2463 const rhs = try self.resolveInst(bin_op.rhs);
2464 const lhs_ty = self.typeOf(bin_op.lhs);
2465 const rhs_ty = self.typeOf(bin_op.rhs);
2959fn airOptionalPayload(func: *Func, inst: Air.Inst.Index) !void {
2960 const zcu = func.bin_file.comp.module.?;
2961 const ty_op = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
2962 const result: MCValue = result: {
2963 const pl_ty = func.typeOfIndex(inst);
2964 if (!pl_ty.hasRuntimeBitsIgnoreComptime(zcu)) break :result .none;
2965
2966 const opt_mcv = try func.resolveInst(ty_op.operand);
2967 if (func.reuseOperand(inst, ty_op.operand, 0, opt_mcv)) {
2968 switch (opt_mcv) {
2969 .register => |pl_reg| try func.truncateRegister(pl_ty, pl_reg),
2970 else => {},
2971 }
2972 break :result opt_mcv;
2973 }
24662974
2467 break :result try self.binOp(.shl, lhs, lhs_ty, rhs, rhs_ty);
2975 const pl_mcv = try func.allocRegOrMem(pl_ty, inst, true);
2976 try func.genCopy(pl_ty, pl_mcv, opt_mcv);
2977 break :result pl_mcv;
24682978 };
2469 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
2470}
2471
2472fn airShlSat(self: *Self, inst: Air.Inst.Index) !void {
2473 const bin_op = self.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
2474 const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else return self.fail("TODO implement shl_sat for {}", .{self.target.cpu.arch});
2475 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
2476}
2477
2478fn airShr(self: *Self, inst: Air.Inst.Index) !void {
2479 const bin_op = self.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
2480 const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else return self.fail("TODO implement shr for {}", .{self.target.cpu.arch});
2481 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
2482}
2483
2484fn airOptionalPayload(self: *Self, inst: Air.Inst.Index) !void {
2485 const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
2486 const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else return self.fail("TODO implement .optional_payload for {}", .{self.target.cpu.arch});
2487 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
2979 return func.finishAir(inst, result, .{ ty_op.operand, .none, .none });
24882980}
24892981
2490fn airOptionalPayloadPtr(self: *Self, inst: Air.Inst.Index) !void {
2491 const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
2492 const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else return self.fail("TODO implement .optional_payload_ptr for {}", .{self.target.cpu.arch});
2493 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
2982fn airOptionalPayloadPtr(func: *Func, inst: Air.Inst.Index) !void {
2983 const ty_op = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
2984 const result: MCValue = if (func.liveness.isUnused(inst)) .unreach else return func.fail("TODO implement .optional_payload_ptr for {}", .{func.target.cpu.arch});
2985 return func.finishAir(inst, result, .{ ty_op.operand, .none, .none });
24942986}
24952987
2496fn airOptionalPayloadPtrSet(self: *Self, inst: Air.Inst.Index) !void {
2497 const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
2498 const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else return self.fail("TODO implement .optional_payload_ptr_set for {}", .{self.target.cpu.arch});
2499 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
2988fn airOptionalPayloadPtrSet(func: *Func, inst: Air.Inst.Index) !void {
2989 const ty_op = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
2990 const result: MCValue = if (func.liveness.isUnused(inst)) .unreach else return func.fail("TODO implement .optional_payload_ptr_set for {}", .{func.target.cpu.arch});
2991 return func.finishAir(inst, result, .{ ty_op.operand, .none, .none });
25002992}
25012993
2502fn airUnwrapErrErr(self: *Self, inst: Air.Inst.Index) !void {
2503 const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
2504 const zcu = self.bin_file.comp.module.?;
2505 const err_union_ty = self.typeOf(ty_op.operand);
2994fn airUnwrapErrErr(func: *Func, inst: Air.Inst.Index) !void {
2995 const ty_op = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
2996 const zcu = func.bin_file.comp.module.?;
2997 const err_union_ty = func.typeOf(ty_op.operand);
25062998 const err_ty = err_union_ty.errorUnionSet(zcu);
25072999 const payload_ty = err_union_ty.errorUnionPayload(zcu);
2508 const operand = try self.resolveInst(ty_op.operand);
3000 const operand = try func.resolveInst(ty_op.operand);
25093001
25103002 const result: MCValue = result: {
25113003 if (err_ty.errorSetIsEmpty(zcu)) {
......@@ -2520,43 +3012,47 @@ fn airUnwrapErrErr(self: *Self, inst: Air.Inst.Index) !void {
25203012
25213013 switch (operand) {
25223014 .register => |reg| {
2523 const eu_lock = self.register_manager.lockReg(reg);
2524 defer if (eu_lock) |lock| self.register_manager.unlockReg(lock);
2525
2526 var result = try self.copyToNewRegister(inst, operand);
3015 const eu_lock = func.register_manager.lockReg(reg);
3016 defer if (eu_lock) |lock| func.register_manager.unlockReg(lock);
25273017
3018 const result = try func.copyToNewRegister(inst, operand);
25283019 if (err_off > 0) {
2529 result = try self.binOp(
3020 try func.genBinOp(
25303021 .shr,
25313022 result,
25323023 err_union_ty,
25333024 .{ .immediate = @as(u6, @intCast(err_off * 8)) },
25343025 Type.u8,
3026 result.register,
25353027 );
25363028 }
25373029 break :result result;
25383030 },
2539 else => return self.fail("TODO implement unwrap_err_err for {}", .{operand}),
3031 .load_frame => |frame_addr| break :result .{ .load_frame = .{
3032 .index = frame_addr.index,
3033 .off = frame_addr.off + @as(i32, @intCast(err_off)),
3034 } },
3035 else => return func.fail("TODO implement unwrap_err_err for {}", .{operand}),
25403036 }
25413037 };
25423038
2543 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
3039 return func.finishAir(inst, result, .{ ty_op.operand, .none, .none });
25443040}
25453041
2546fn airUnwrapErrPayload(self: *Self, inst: Air.Inst.Index) !void {
2547 const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
2548 const operand_ty = self.typeOf(ty_op.operand);
2549 const operand = try self.resolveInst(ty_op.operand);
2550 const result = try self.genUnwrapErrUnionPayloadMir(operand_ty, operand);
2551 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
3042fn airUnwrapErrPayload(func: *Func, inst: Air.Inst.Index) !void {
3043 const ty_op = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
3044 const operand_ty = func.typeOf(ty_op.operand);
3045 const operand = try func.resolveInst(ty_op.operand);
3046 const result = try func.genUnwrapErrUnionPayloadMir(operand_ty, operand);
3047 return func.finishAir(inst, result, .{ ty_op.operand, .none, .none });
25523048}
25533049
25543050fn genUnwrapErrUnionPayloadMir(
2555 self: *Self,
3051 func: *Func,
25563052 err_union_ty: Type,
25573053 err_union: MCValue,
25583054) !MCValue {
2559 const zcu = self.bin_file.comp.module.?;
3055 const zcu = func.bin_file.comp.module.?;
25603056 const payload_ty = err_union_ty.errorUnionPayload(zcu);
25613057
25623058 const result: MCValue = result: {
......@@ -2569,24 +3065,23 @@ fn genUnwrapErrUnionPayloadMir(
25693065 .off = frame_addr.off + payload_off,
25703066 } },
25713067 .register => |reg| {
2572 const eu_lock = self.register_manager.lockReg(reg);
2573 defer if (eu_lock) |lock| self.register_manager.unlockReg(lock);
2574
2575 var result: MCValue = .{ .register = try self.copyToTmpRegister(err_union_ty, err_union) };
3068 const eu_lock = func.register_manager.lockReg(reg);
3069 defer if (eu_lock) |lock| func.register_manager.unlockReg(lock);
25763070
3071 const result_reg = try func.copyToTmpRegister(err_union_ty, err_union);
25773072 if (payload_off > 0) {
2578 result = try self.binOp(
3073 try func.genBinOp(
25793074 .shr,
2580 result,
3075 .{ .register = result_reg },
25813076 err_union_ty,
25823077 .{ .immediate = @as(u6, @intCast(payload_off * 8)) },
25833078 Type.u8,
3079 result_reg,
25843080 );
25853081 }
2586
2587 break :result result;
3082 break :result .{ .register = result_reg };
25883083 },
2589 else => return self.fail("TODO implement genUnwrapErrUnionPayloadMir for {}", .{err_union}),
3084 else => return func.fail("TODO implement genUnwrapErrUnionPayloadMir for {}", .{err_union}),
25903085 }
25913086 };
25923087
......@@ -2594,99 +3089,140 @@ fn genUnwrapErrUnionPayloadMir(
25943089}
25953090
25963091// *(E!T) -> E
2597fn airUnwrapErrErrPtr(self: *Self, inst: Air.Inst.Index) !void {
2598 const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
2599 const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else return self.fail("TODO implement unwrap error union error ptr for {}", .{self.target.cpu.arch});
2600 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
3092fn airUnwrapErrErrPtr(func: *Func, inst: Air.Inst.Index) !void {
3093 const ty_op = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
3094 const result: MCValue = if (func.liveness.isUnused(inst)) .unreach else return func.fail("TODO implement unwrap error union error ptr for {}", .{func.target.cpu.arch});
3095 return func.finishAir(inst, result, .{ ty_op.operand, .none, .none });
26013096}
26023097
26033098// *(E!T) -> *T
2604fn airUnwrapErrPayloadPtr(self: *Self, inst: Air.Inst.Index) !void {
2605 const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
2606 const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else return self.fail("TODO implement unwrap error union payload ptr for {}", .{self.target.cpu.arch});
2607 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
3099fn airUnwrapErrPayloadPtr(func: *Func, inst: Air.Inst.Index) !void {
3100 const ty_op = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
3101 const result: MCValue = if (func.liveness.isUnused(inst)) .unreach else return func.fail("TODO implement unwrap error union payload ptr for {}", .{func.target.cpu.arch});
3102 return func.finishAir(inst, result, .{ ty_op.operand, .none, .none });
26083103}
26093104
2610fn airErrUnionPayloadPtrSet(self: *Self, inst: Air.Inst.Index) !void {
2611 const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
2612 const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else return self.fail("TODO implement .errunion_payload_ptr_set for {}", .{self.target.cpu.arch});
2613 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
3105fn airErrUnionPayloadPtrSet(func: *Func, inst: Air.Inst.Index) !void {
3106 const ty_op = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
3107 const result: MCValue = if (func.liveness.isUnused(inst)) .unreach else return func.fail("TODO implement .errunion_payload_ptr_set for {}", .{func.target.cpu.arch});
3108 return func.finishAir(inst, result, .{ ty_op.operand, .none, .none });
26143109}
26153110
2616fn airErrReturnTrace(self: *Self, inst: Air.Inst.Index) !void {
2617 const result: MCValue = if (self.liveness.isUnused(inst))
3111fn airErrReturnTrace(func: *Func, inst: Air.Inst.Index) !void {
3112 const result: MCValue = if (func.liveness.isUnused(inst))
26183113 .unreach
26193114 else
2620 return self.fail("TODO implement airErrReturnTrace for {}", .{self.target.cpu.arch});
2621 return self.finishAir(inst, result, .{ .none, .none, .none });
3115 return func.fail("TODO implement airErrReturnTrace for {}", .{func.target.cpu.arch});
3116 return func.finishAir(inst, result, .{ .none, .none, .none });
26223117}
26233118
2624fn airSetErrReturnTrace(self: *Self, inst: Air.Inst.Index) !void {
3119fn airSetErrReturnTrace(func: *Func, inst: Air.Inst.Index) !void {
26253120 _ = inst;
2626 return self.fail("TODO implement airSetErrReturnTrace for {}", .{self.target.cpu.arch});
3121 return func.fail("TODO implement airSetErrReturnTrace for {}", .{func.target.cpu.arch});
26273122}
26283123
2629fn airSaveErrReturnTraceIndex(self: *Self, inst: Air.Inst.Index) !void {
3124fn airSaveErrReturnTraceIndex(func: *Func, inst: Air.Inst.Index) !void {
26303125 _ = inst;
2631 return self.fail("TODO implement airSaveErrReturnTraceIndex for {}", .{self.target.cpu.arch});
3126 return func.fail("TODO implement airSaveErrReturnTraceIndex for {}", .{func.target.cpu.arch});
26323127}
26333128
2634fn airWrapOptional(self: *Self, inst: Air.Inst.Index) !void {
2635 const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
2636 const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else result: {
2637 const zcu = self.bin_file.comp.module.?;
2638 const optional_ty = self.typeOfIndex(inst);
3129fn airWrapOptional(func: *Func, inst: Air.Inst.Index) !void {
3130 const zcu = func.bin_file.comp.module.?;
3131 const ty_op = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
3132 const result: MCValue = result: {
3133 const pl_ty = func.typeOf(ty_op.operand);
3134 if (!pl_ty.hasRuntimeBits(zcu)) break :result .{ .immediate = 1 };
3135
3136 const opt_ty = func.typeOfIndex(inst);
3137 const pl_mcv = try func.resolveInst(ty_op.operand);
3138 const same_repr = opt_ty.optionalReprIsPayload(zcu);
3139 if (same_repr and func.reuseOperand(inst, ty_op.operand, 0, pl_mcv)) break :result pl_mcv;
3140
3141 const pl_lock: ?RegisterLock = switch (pl_mcv) {
3142 .register => |reg| func.register_manager.lockRegAssumeUnused(reg),
3143 else => null,
3144 };
3145 defer if (pl_lock) |lock| func.register_manager.unlockReg(lock);
26393146
2640 // Optional with a zero-bit payload type is just a boolean true
2641 if (optional_ty.abiSize(zcu) == 1)
2642 break :result MCValue{ .immediate = 1 };
3147 const opt_mcv = try func.allocRegOrMem(opt_ty, inst, true);
3148 try func.genCopy(pl_ty, opt_mcv, pl_mcv);
26433149
2644 return self.fail("TODO implement wrap optional for {}", .{self.target.cpu.arch});
3150 if (!same_repr) {
3151 const pl_abi_size: i32 = @intCast(pl_ty.abiSize(zcu));
3152 switch (opt_mcv) {
3153 .load_frame => |frame_addr| try func.genSetMem(
3154 .{ .frame = frame_addr.index },
3155 frame_addr.off + pl_abi_size,
3156 Type.u8,
3157 .{ .immediate = 1 },
3158 ),
3159 .register => return func.fail("TODO: airWrapOption opt_mcv register", .{}),
3160 else => unreachable,
3161 }
3162 }
3163 break :result opt_mcv;
26453164 };
2646 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
3165 return func.finishAir(inst, result, .{ ty_op.operand, .none, .none });
26473166}
26483167
26493168/// T to E!T
2650fn airWrapErrUnionPayload(self: *Self, inst: Air.Inst.Index) !void {
2651 const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
2652 const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else return self.fail("TODO implement wrap errunion payload for {}", .{self.target.cpu.arch});
2653 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
3169fn airWrapErrUnionPayload(func: *Func, inst: Air.Inst.Index) !void {
3170 const zcu = func.bin_file.comp.module.?;
3171 const ty_op = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
3172
3173 const eu_ty = ty_op.ty.toType();
3174 const pl_ty = eu_ty.errorUnionPayload(zcu);
3175 const err_ty = eu_ty.errorUnionSet(zcu);
3176 const operand = try func.resolveInst(ty_op.operand);
3177
3178 const result: MCValue = result: {
3179 if (!pl_ty.hasRuntimeBitsIgnoreComptime(zcu)) break :result .{ .immediate = 0 };
3180
3181 const frame_index = try func.allocFrameIndex(FrameAlloc.initSpill(eu_ty, zcu));
3182 const pl_off: i32 = @intCast(errUnionPayloadOffset(pl_ty, zcu));
3183 const err_off: i32 = @intCast(errUnionErrorOffset(pl_ty, zcu));
3184 try func.genSetMem(.{ .frame = frame_index }, pl_off, pl_ty, operand);
3185 try func.genSetMem(.{ .frame = frame_index }, err_off, err_ty, .{ .immediate = 0 });
3186 break :result .{ .load_frame = .{ .index = frame_index } };
3187 };
3188
3189 return func.finishAir(inst, result, .{ ty_op.operand, .none, .none });
26543190}
26553191
26563192/// E to E!T
2657fn airWrapErrUnionErr(self: *Self, inst: Air.Inst.Index) !void {
2658 const zcu = self.bin_file.comp.module.?;
2659 const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
3193fn airWrapErrUnionErr(func: *Func, inst: Air.Inst.Index) !void {
3194 const zcu = func.bin_file.comp.module.?;
3195 const ty_op = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
26603196
26613197 const eu_ty = ty_op.ty.toType();
26623198 const pl_ty = eu_ty.errorUnionPayload(zcu);
26633199 const err_ty = eu_ty.errorUnionSet(zcu);
26643200
26653201 const result: MCValue = result: {
2666 if (!pl_ty.hasRuntimeBitsIgnoreComptime(zcu)) break :result try self.resolveInst(ty_op.operand);
3202 if (!pl_ty.hasRuntimeBitsIgnoreComptime(zcu)) break :result try func.resolveInst(ty_op.operand);
26673203
2668 const frame_index = try self.allocFrameIndex(FrameAlloc.initSpill(eu_ty, zcu));
3204 const frame_index = try func.allocFrameIndex(FrameAlloc.initSpill(eu_ty, zcu));
26693205 const pl_off: i32 = @intCast(errUnionPayloadOffset(pl_ty, zcu));
26703206 const err_off: i32 = @intCast(errUnionErrorOffset(pl_ty, zcu));
2671 try self.genSetStack(pl_ty, .{ .index = frame_index, .off = pl_off }, .undef);
2672 const operand = try self.resolveInst(ty_op.operand);
2673 try self.genSetStack(err_ty, .{ .index = frame_index, .off = err_off }, operand);
3207 try func.genSetMem(.{ .frame = frame_index }, pl_off, pl_ty, .undef);
3208 const operand = try func.resolveInst(ty_op.operand);
3209 try func.genSetMem(.{ .frame = frame_index }, err_off, err_ty, operand);
26743210 break :result .{ .load_frame = .{ .index = frame_index } };
26753211 };
2676 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
3212 return func.finishAir(inst, result, .{ ty_op.operand, .none, .none });
26773213}
26783214
2679fn airTry(self: *Self, inst: Air.Inst.Index) !void {
2680 const pl_op = self.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;
2681 const extra = self.air.extraData(Air.Try, pl_op.payload);
2682 const body: []const Air.Inst.Index = @ptrCast(self.air.extra[extra.end..][0..extra.data.body_len]);
2683 const operand_ty = self.typeOf(pl_op.operand);
2684 const result = try self.genTry(inst, pl_op.operand, body, operand_ty, false);
2685 return self.finishAir(inst, result, .{ .none, .none, .none });
3215fn airTry(func: *Func, inst: Air.Inst.Index) !void {
3216 const pl_op = func.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;
3217 const extra = func.air.extraData(Air.Try, pl_op.payload);
3218 const body: []const Air.Inst.Index = @ptrCast(func.air.extra[extra.end..][0..extra.data.body_len]);
3219 const operand_ty = func.typeOf(pl_op.operand);
3220 const result = try func.genTry(inst, pl_op.operand, body, operand_ty, false);
3221 return func.finishAir(inst, result, .{ .none, .none, .none });
26863222}
26873223
26883224fn genTry(
2689 self: *Self,
3225 func: *Func,
26903226 inst: Air.Inst.Index,
26913227 operand: Air.Inst.Ref,
26923228 body: []const Air.Inst.Index,
......@@ -2695,180 +3231,204 @@ fn genTry(
26953231) !MCValue {
26963232 _ = operand_is_ptr;
26973233
2698 const liveness_cond_br = self.liveness.getCondBr(inst);
3234 const liveness_cond_br = func.liveness.getCondBr(inst);
26993235
2700 const operand_mcv = try self.resolveInst(operand);
2701 const is_err_mcv = try self.isErr(null, operand_ty, operand_mcv);
3236 const operand_mcv = try func.resolveInst(operand);
3237 const is_err_mcv = try func.isErr(null, operand_ty, operand_mcv);
27023238
27033239 // A branch to the false section. Uses beq. 1 is the default "true" state.
2704 const reloc = try self.condBr(Type.anyerror, is_err_mcv);
3240 const reloc = try func.condBr(Type.anyerror, is_err_mcv);
27053241
2706 if (self.liveness.operandDies(inst, 0)) {
2707 if (operand.toIndex()) |operand_inst| try self.processDeath(operand_inst);
3242 if (func.liveness.operandDies(inst, 0)) {
3243 if (operand.toIndex()) |operand_inst| try func.processDeath(operand_inst);
27083244 }
27093245
2710 self.scope_generation += 1;
2711 const state = try self.saveState();
3246 func.scope_generation += 1;
3247 const state = try func.saveState();
27123248
2713 for (liveness_cond_br.else_deaths) |death| try self.processDeath(death);
2714 try self.genBody(body);
2715 try self.restoreState(state, &.{}, .{
3249 for (liveness_cond_br.else_deaths) |death| try func.processDeath(death);
3250 try func.genBody(body);
3251 try func.restoreState(state, &.{}, .{
27163252 .emit_instructions = false,
27173253 .update_tracking = true,
27183254 .resurrect = true,
27193255 .close_scope = true,
27203256 });
27213257
2722 self.performReloc(reloc);
3258 func.performReloc(reloc);
27233259
2724 for (liveness_cond_br.then_deaths) |death| try self.processDeath(death);
3260 for (liveness_cond_br.then_deaths) |death| try func.processDeath(death);
27253261
2726 const result = if (self.liveness.isUnused(inst))
3262 const result = if (func.liveness.isUnused(inst))
27273263 .unreach
27283264 else
2729 try self.genUnwrapErrUnionPayloadMir(operand_ty, operand_mcv);
3265 try func.genUnwrapErrUnionPayloadMir(operand_ty, operand_mcv);
27303266
27313267 return result;
27323268}
27333269
2734fn airSlicePtr(self: *Self, inst: Air.Inst.Index) !void {
2735 const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
3270fn airSlicePtr(func: *Func, inst: Air.Inst.Index) !void {
3271 const ty_op = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
27363272 const result = result: {
2737 const src_mcv = try self.resolveInst(ty_op.operand);
2738 if (self.reuseOperand(inst, ty_op.operand, 0, src_mcv)) break :result src_mcv;
3273 const src_mcv = try func.resolveInst(ty_op.operand);
3274 if (func.reuseOperand(inst, ty_op.operand, 0, src_mcv)) break :result src_mcv;
27393275
2740 const dst_mcv = try self.allocRegOrMem(inst, true);
2741 const dst_ty = self.typeOfIndex(inst);
2742 try self.genCopy(dst_ty, dst_mcv, src_mcv);
3276 const dst_mcv = try func.allocRegOrMem(func.typeOfIndex(inst), inst, true);
3277 const dst_ty = func.typeOfIndex(inst);
3278 try func.genCopy(dst_ty, dst_mcv, src_mcv);
27433279 break :result dst_mcv;
27443280 };
2745 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
3281 return func.finishAir(inst, result, .{ ty_op.operand, .none, .none });
27463282}
27473283
2748fn airSliceLen(self: *Self, inst: Air.Inst.Index) !void {
2749 const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
2750 const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else result: {
2751 const src_mcv = try self.resolveInst(ty_op.operand);
3284fn airSliceLen(func: *Func, inst: Air.Inst.Index) !void {
3285 const ty_op = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
3286 const result: MCValue = if (func.liveness.isUnused(inst)) .unreach else result: {
3287 const src_mcv = try func.resolveInst(ty_op.operand);
3288 const ty = func.typeOfIndex(inst);
3289
27523290 switch (src_mcv) {
27533291 .load_frame => |frame_addr| {
27543292 const len_mcv: MCValue = .{ .load_frame = .{
27553293 .index = frame_addr.index,
27563294 .off = frame_addr.off + 8,
27573295 } };
2758 if (self.reuseOperand(inst, ty_op.operand, 0, src_mcv)) break :result len_mcv;
3296 if (func.reuseOperand(inst, ty_op.operand, 0, src_mcv)) break :result len_mcv;
27593297
2760 const dst_mcv = try self.allocRegOrMem(inst, true);
2761 try self.genCopy(Type.usize, dst_mcv, len_mcv);
3298 const dst_mcv = try func.allocRegOrMem(ty, inst, true);
3299 try func.genCopy(Type.usize, dst_mcv, len_mcv);
27623300 break :result dst_mcv;
27633301 },
27643302 .register_pair => |pair| {
27653303 const len_mcv: MCValue = .{ .register = pair[1] };
27663304
2767 if (self.reuseOperand(inst, ty_op.operand, 0, src_mcv)) break :result len_mcv;
3305 if (func.reuseOperand(inst, ty_op.operand, 0, src_mcv)) break :result len_mcv;
27683306
2769 const dst_mcv = try self.allocRegOrMem(inst, true);
2770 try self.genCopy(Type.usize, dst_mcv, len_mcv);
3307 const dst_mcv = try func.allocRegOrMem(ty, inst, true);
3308 try func.genCopy(Type.usize, dst_mcv, len_mcv);
27713309 break :result dst_mcv;
27723310 },
2773 else => return self.fail("TODO airSliceLen for {}", .{src_mcv}),
3311 else => return func.fail("TODO airSliceLen for {}", .{src_mcv}),
27743312 }
27753313 };
2776 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
3314 return func.finishAir(inst, result, .{ ty_op.operand, .none, .none });
27773315}
27783316
2779fn airPtrSliceLenPtr(self: *Self, inst: Air.Inst.Index) !void {
2780 const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
2781 const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else return self.fail("TODO implement ptr_slice_len_ptr for {}", .{self.target.cpu.arch});
2782 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
3317fn airPtrSliceLenPtr(func: *Func, inst: Air.Inst.Index) !void {
3318 const ty_op = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
3319 const result: MCValue = if (func.liveness.isUnused(inst)) .unreach else return func.fail("TODO implement ptr_slice_len_ptr for {}", .{func.target.cpu.arch});
3320 return func.finishAir(inst, result, .{ ty_op.operand, .none, .none });
27833321}
27843322
2785fn airPtrSlicePtrPtr(self: *Self, inst: Air.Inst.Index) !void {
2786 const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
2787 const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else return self.fail("TODO implement ptr_slice_ptr_ptr for {}", .{self.target.cpu.arch});
2788 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
3323fn airPtrSlicePtrPtr(func: *Func, inst: Air.Inst.Index) !void {
3324 const ty_op = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
3325 const result: MCValue = if (func.liveness.isUnused(inst)) .unreach else return func.fail("TODO implement ptr_slice_ptr_ptr for {}", .{func.target.cpu.arch});
3326 return func.finishAir(inst, result, .{ ty_op.operand, .none, .none });
27893327}
27903328
2791fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void {
2792 const zcu = self.bin_file.comp.module.?;
2793 const is_volatile = false; // TODO
2794 const bin_op = self.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
3329fn airSliceElemVal(func: *Func, inst: Air.Inst.Index) !void {
3330 const mod = func.bin_file.comp.module.?;
3331 const bin_op = func.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
27953332
2796 if (!is_volatile and self.liveness.isUnused(inst)) return self.finishAir(
2797 inst,
2798 .unreach,
2799 .{ bin_op.lhs, bin_op.rhs, .none },
2800 );
28013333 const result: MCValue = result: {
2802 const slice_mcv = try self.resolveInst(bin_op.lhs);
2803 const index_mcv = try self.resolveInst(bin_op.rhs);
2804
2805 const slice_ty = self.typeOf(bin_op.lhs);
2806
2807 const slice_ptr_field_type = slice_ty.slicePtrFieldType(zcu);
3334 const elem_ty = func.typeOfIndex(inst);
3335 if (!elem_ty.hasRuntimeBitsIgnoreComptime(mod)) break :result .none;
3336
3337 const slice_ty = func.typeOf(bin_op.lhs);
3338 const slice_ptr_field_type = slice_ty.slicePtrFieldType(mod);
3339 const elem_ptr = try func.genSliceElemPtr(bin_op.lhs, bin_op.rhs);
3340 const dst_mcv = try func.allocRegOrMem(elem_ty, inst, false);
3341 try func.load(dst_mcv, elem_ptr, slice_ptr_field_type);
3342 break :result dst_mcv;
3343 };
3344 return func.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
3345}
28083346
2809 const index_lock: ?RegisterLock = if (index_mcv == .register)
2810 self.register_manager.lockRegAssumeUnused(index_mcv.register)
2811 else
2812 null;
2813 defer if (index_lock) |reg| self.register_manager.unlockReg(reg);
3347fn airSliceElemPtr(func: *Func, inst: Air.Inst.Index) !void {
3348 const ty_pl = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
3349 const extra = func.air.extraData(Air.Bin, ty_pl.payload).data;
3350 const dst_mcv = try func.genSliceElemPtr(extra.lhs, extra.rhs);
3351 return func.finishAir(inst, dst_mcv, .{ extra.lhs, extra.rhs, .none });
3352}
28143353
2815 const base_mcv: MCValue = switch (slice_mcv) {
2816 .load_frame,
2817 .load_symbol,
2818 => .{ .register = try self.copyToTmpRegister(slice_ptr_field_type, slice_mcv) },
2819 else => return self.fail("TODO slice_elem_val when slice is {}", .{slice_mcv}),
2820 };
3354fn genSliceElemPtr(func: *Func, lhs: Air.Inst.Ref, rhs: Air.Inst.Ref) !MCValue {
3355 const zcu = func.bin_file.comp.module.?;
3356 const slice_ty = func.typeOf(lhs);
3357 const slice_mcv = try func.resolveInst(lhs);
3358 const slice_mcv_lock: ?RegisterLock = switch (slice_mcv) {
3359 .register => |reg| func.register_manager.lockRegAssumeUnused(reg),
3360 else => null,
3361 };
3362 defer if (slice_mcv_lock) |lock| func.register_manager.unlockReg(lock);
28213363
2822 const dest = try self.allocRegOrMem(inst, true);
2823 const addr = try self.binOp(.ptr_add, base_mcv, slice_ptr_field_type, index_mcv, Type.usize);
2824 try self.load(dest, addr, slice_ptr_field_type);
3364 const elem_ty = slice_ty.childType(zcu);
3365 const elem_size = elem_ty.abiSize(zcu);
28253366
2826 break :result dest;
3367 const index_ty = func.typeOf(rhs);
3368 const index_mcv = try func.resolveInst(rhs);
3369 const index_mcv_lock: ?RegisterLock = switch (index_mcv) {
3370 .register => |reg| func.register_manager.lockRegAssumeUnused(reg),
3371 else => null,
28273372 };
2828 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
2829}
3373 defer if (index_mcv_lock) |lock| func.register_manager.unlockReg(lock);
3374
3375 const offset_reg = try func.elemOffset(index_ty, index_mcv, elem_size);
3376 const offset_reg_lock = func.register_manager.lockRegAssumeUnused(offset_reg);
3377 defer func.register_manager.unlockReg(offset_reg_lock);
3378
3379 const addr_reg, const addr_lock = try func.allocReg(.int);
3380 defer func.register_manager.unlockReg(addr_lock);
3381 try func.genSetReg(Type.usize, addr_reg, slice_mcv);
3382
3383 _ = try func.addInst(.{
3384 .tag = .add,
3385 .ops = .rrr,
3386 .data = .{ .r_type = .{
3387 .rd = addr_reg,
3388 .rs1 = addr_reg,
3389 .rs2 = offset_reg,
3390 } },
3391 });
28303392
2831fn airSliceElemPtr(self: *Self, inst: Air.Inst.Index) !void {
2832 const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
2833 const extra = self.air.extraData(Air.Bin, ty_pl.payload).data;
2834 const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else return self.fail("TODO implement slice_elem_ptr for {}", .{self.target.cpu.arch});
2835 return self.finishAir(inst, result, .{ extra.lhs, extra.rhs, .none });
3393 return .{ .register = addr_reg };
28363394}
28373395
2838fn airArrayElemVal(self: *Self, inst: Air.Inst.Index) !void {
2839 const zcu = self.bin_file.comp.module.?;
2840 const bin_op = self.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
2841 const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else result: {
2842 const array_ty = self.typeOf(bin_op.lhs);
2843 const array_mcv = try self.resolveInst(bin_op.lhs);
3396fn airArrayElemVal(func: *Func, inst: Air.Inst.Index) !void {
3397 const zcu = func.bin_file.comp.module.?;
3398 const bin_op = func.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
3399 const result: MCValue = if (func.liveness.isUnused(inst)) .unreach else result: {
3400 const result_ty = func.typeOfIndex(inst);
3401
3402 const array_ty = func.typeOf(bin_op.lhs);
3403 const array_mcv = try func.resolveInst(bin_op.lhs);
28443404
2845 const index_mcv = try self.resolveInst(bin_op.rhs);
2846 const index_ty = self.typeOf(bin_op.rhs);
3405 const index_mcv = try func.resolveInst(bin_op.rhs);
3406 const index_ty = func.typeOf(bin_op.rhs);
28473407
28483408 const elem_ty = array_ty.childType(zcu);
28493409 const elem_abi_size = elem_ty.abiSize(zcu);
28503410
2851 const addr_reg, const addr_reg_lock = try self.allocReg();
2852 defer self.register_manager.unlockReg(addr_reg_lock);
3411 const addr_reg, const addr_reg_lock = try func.allocReg(.int);
3412 defer func.register_manager.unlockReg(addr_reg_lock);
28533413
28543414 switch (array_mcv) {
28553415 .register => {
2856 const frame_index = try self.allocFrameIndex(FrameAlloc.initType(array_ty, zcu));
2857 try self.genSetStack(array_ty, .{ .index = frame_index }, array_mcv);
2858 try self.genSetReg(Type.usize, addr_reg, .{ .lea_frame = .{ .index = frame_index } });
3416 const frame_index = try func.allocFrameIndex(FrameAlloc.initType(array_ty, zcu));
3417 try func.genSetMem(.{ .frame = frame_index }, 0, array_ty, array_mcv);
3418 try func.genSetReg(Type.usize, addr_reg, .{ .lea_frame = .{ .index = frame_index } });
28593419 },
28603420 .load_frame => |frame_addr| {
2861 try self.genSetReg(Type.usize, addr_reg, .{ .lea_frame = frame_addr });
3421 try func.genSetReg(Type.usize, addr_reg, .{ .lea_frame = frame_addr });
28623422 },
2863 else => try self.genSetReg(Type.usize, addr_reg, array_mcv.address()),
3423 else => try func.genSetReg(Type.usize, addr_reg, array_mcv.address()),
28643424 }
28653425
2866 const offset_reg = try self.elemOffset(index_ty, index_mcv, elem_abi_size);
2867 const offset_lock = self.register_manager.lockRegAssumeUnused(offset_reg);
2868 defer self.register_manager.unlockReg(offset_lock);
3426 const offset_reg = try func.elemOffset(index_ty, index_mcv, elem_abi_size);
3427 const offset_lock = func.register_manager.lockRegAssumeUnused(offset_reg);
3428 defer func.register_manager.unlockReg(offset_lock);
28693429
2870 const dst_mcv = try self.allocRegOrMem(inst, false);
2871 _ = try self.addInst(.{
3430 const dst_mcv = try func.allocRegOrMem(result_ty, inst, false);
3431 _ = try func.addInst(.{
28723432 .tag = .add,
28733433 .ops = .rrr,
28743434 .data = .{ .r_type = .{
......@@ -2877,163 +3437,225 @@ fn airArrayElemVal(self: *Self, inst: Air.Inst.Index) !void {
28773437 .rs2 = addr_reg,
28783438 } },
28793439 });
2880 try self.genCopy(elem_ty, dst_mcv, .{ .indirect = .{ .reg = addr_reg } });
3440 try func.genCopy(elem_ty, dst_mcv, .{ .indirect = .{ .reg = addr_reg } });
28813441 break :result dst_mcv;
28823442 };
2883 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
3443 return func.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
28843444}
28853445
2886fn airPtrElemVal(self: *Self, inst: Air.Inst.Index) !void {
3446fn airPtrElemVal(func: *Func, inst: Air.Inst.Index) !void {
28873447 const is_volatile = false; // TODO
2888 const bin_op = self.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
2889 const result: MCValue = if (!is_volatile and self.liveness.isUnused(inst)) .unreach else return self.fail("TODO implement ptr_elem_val for {}", .{self.target.cpu.arch});
2890 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
3448 const bin_op = func.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
3449 const result: MCValue = if (!is_volatile and func.liveness.isUnused(inst)) .unreach else return func.fail("TODO implement ptr_elem_val for {}", .{func.target.cpu.arch});
3450 return func.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
28913451}
28923452
2893fn airPtrElemPtr(self: *Self, inst: Air.Inst.Index) !void {
2894 const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
2895 const extra = self.air.extraData(Air.Bin, ty_pl.payload).data;
2896 const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else return self.fail("TODO implement ptr_elem_ptr for {}", .{self.target.cpu.arch});
2897 return self.finishAir(inst, result, .{ extra.lhs, extra.rhs, .none });
2898}
2899
2900fn airSetUnionTag(self: *Self, inst: Air.Inst.Index) !void {
2901 const bin_op = self.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
2902 _ = bin_op;
2903 return self.fail("TODO implement airSetUnionTag for {}", .{self.target.cpu.arch});
2904 // return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
2905}
2906
2907fn airGetUnionTag(self: *Self, inst: Air.Inst.Index) !void {
2908 const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
2909 const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else return self.fail("TODO implement airGetUnionTag for {}", .{self.target.cpu.arch});
2910 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
2911}
2912
2913fn airClz(self: *Self, inst: Air.Inst.Index) !void {
2914 const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
2915 const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else return self.fail("TODO implement airClz for {}", .{self.target.cpu.arch});
2916 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
2917}
2918
2919fn airCtz(self: *Self, inst: Air.Inst.Index) !void {
2920 const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
2921 const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else result: {
2922 const operand = try self.resolveInst(ty_op.operand);
2923 const operand_ty = self.typeOf(ty_op.operand);
3453fn airPtrElemPtr(func: *Func, inst: Air.Inst.Index) !void {
3454 const zcu = func.bin_file.comp.module.?;
3455 const ty_pl = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
3456 const extra = func.air.extraData(Air.Bin, ty_pl.payload).data;
29243457
2925 const dest_reg = try self.register_manager.allocReg(inst, gp);
2926
2927 const source_reg, const source_lock = blk: {
2928 if (operand == .register) break :blk .{ operand.register, null };
3458 const result = result: {
3459 const elem_ptr_ty = func.typeOfIndex(inst);
3460 const base_ptr_ty = func.typeOf(extra.lhs);
29293461
2930 const source_reg, const source_lock = try self.allocReg();
2931 try self.genSetReg(operand_ty, source_reg, operand);
2932 break :blk .{ source_reg, source_lock };
3462 const base_ptr_mcv = try func.resolveInst(extra.lhs);
3463 const base_ptr_lock: ?RegisterLock = switch (base_ptr_mcv) {
3464 .register => |reg| func.register_manager.lockRegAssumeUnused(reg),
3465 else => null,
29333466 };
2934 defer if (source_lock) |lock| self.register_manager.unlockReg(lock);
3467 defer if (base_ptr_lock) |lock| func.register_manager.unlockReg(lock);
29353468
2936 // TODO: the B extension for RISCV should have the ctz instruction, and we should use it.
3469 if (elem_ptr_ty.ptrInfo(zcu).flags.vector_index != .none) {
3470 break :result if (func.reuseOperand(inst, extra.lhs, 0, base_ptr_mcv))
3471 base_ptr_mcv
3472 else
3473 try func.copyToNewRegister(inst, base_ptr_mcv);
3474 }
29373475
2938 try self.ctz(source_reg, dest_reg, operand_ty);
3476 const elem_ty = base_ptr_ty.elemType2(zcu);
3477 const elem_abi_size = elem_ty.abiSize(zcu);
3478 const index_ty = func.typeOf(extra.rhs);
3479 const index_mcv = try func.resolveInst(extra.rhs);
3480 const index_lock: ?RegisterLock = switch (index_mcv) {
3481 .register => |reg| func.register_manager.lockRegAssumeUnused(reg),
3482 else => null,
3483 };
3484 defer if (index_lock) |lock| func.register_manager.unlockReg(lock);
3485
3486 const offset_reg = try func.elemOffset(index_ty, index_mcv, elem_abi_size);
3487 const offset_reg_lock = func.register_manager.lockRegAssumeUnused(offset_reg);
3488 defer func.register_manager.unlockReg(offset_reg_lock);
3489
3490 const result_reg, const result_lock = try func.allocReg(.int);
3491 defer func.register_manager.unlockReg(result_lock);
3492
3493 try func.genBinOp(
3494 .ptr_add,
3495 base_ptr_mcv,
3496 base_ptr_ty,
3497 .{ .register = offset_reg },
3498 Type.usize,
3499 result_reg,
3500 );
29393501
2940 break :result .{ .register = dest_reg };
3502 break :result MCValue{ .register = result_reg };
29413503 };
2942 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
3504 return func.finishAir(inst, result, .{ extra.lhs, extra.rhs, .none });
29433505}
29443506
2945fn ctz(self: *Self, src: Register, dst: Register, ty: Type) !void {
2946 const zcu = self.bin_file.comp.module.?;
2947 const length = (ty.abiSize(zcu) * 8) - 1;
2948
2949 const count_reg, const count_lock = try self.allocReg();
2950 defer self.register_manager.unlockReg(count_lock);
2951
2952 const len_reg, const len_lock = try self.allocReg();
2953 defer self.register_manager.unlockReg(len_lock);
3507fn airSetUnionTag(func: *Func, inst: Air.Inst.Index) !void {
3508 const bin_op = func.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
3509 _ = bin_op;
3510 return func.fail("TODO implement airSetUnionTag for {}", .{func.target.cpu.arch});
3511 // return func.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
3512}
29543513
2955 try self.genSetReg(Type.usize, count_reg, .{ .immediate = 0 });
2956 try self.genSetReg(Type.usize, len_reg, .{ .immediate = length });
3514fn airGetUnionTag(func: *Func, inst: Air.Inst.Index) !void {
3515 const ty_op = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
3516 const result: MCValue = if (func.liveness.isUnused(inst)) .unreach else return func.fail("TODO implement airGetUnionTag for {}", .{func.target.cpu.arch});
3517 return func.finishAir(inst, result, .{ ty_op.operand, .none, .none });
3518}
29573519
2958 _ = src;
2959 _ = dst;
3520fn airClz(func: *Func, inst: Air.Inst.Index) !void {
3521 const ty_op = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
3522 const result: MCValue = if (func.liveness.isUnused(inst)) .unreach else return func.fail("TODO implement airClz for {}", .{func.target.cpu.arch});
3523 return func.finishAir(inst, result, .{ ty_op.operand, .none, .none });
3524}
29603525
2961 return self.fail("TODO: finish ctz", .{});
3526fn airCtz(func: *Func, inst: Air.Inst.Index) !void {
3527 const ty_op = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
3528 _ = ty_op;
3529 return func.fail("TODO: finish ctz", .{});
29623530}
29633531
2964fn airPopcount(self: *Self, inst: Air.Inst.Index) !void {
2965 const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
2966 const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else return self.fail("TODO implement airPopcount for {}", .{self.target.cpu.arch});
2967 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
3532fn airPopcount(func: *Func, inst: Air.Inst.Index) !void {
3533 const ty_op = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
3534 const result: MCValue = if (func.liveness.isUnused(inst)) .unreach else return func.fail("TODO implement airPopcount for {}", .{func.target.cpu.arch});
3535 return func.finishAir(inst, result, .{ ty_op.operand, .none, .none });
29683536}
29693537
2970fn airAbs(self: *Self, inst: Air.Inst.Index) !void {
2971 const zcu = self.bin_file.comp.module.?;
2972 const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
2973 const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else result: {
2974 const ty = self.typeOf(ty_op.operand);
3538fn airAbs(func: *Func, inst: Air.Inst.Index) !void {
3539 const zcu = func.bin_file.comp.module.?;
3540 const ty_op = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
3541 const result: MCValue = if (func.liveness.isUnused(inst)) .unreach else result: {
3542 const ty = func.typeOf(ty_op.operand);
29753543 const scalar_ty = ty.scalarType(zcu);
2976 const operand = try self.resolveInst(ty_op.operand);
3544 const operand = try func.resolveInst(ty_op.operand);
29773545
29783546 switch (scalar_ty.zigTypeTag(zcu)) {
29793547 .Int => if (ty.zigTypeTag(zcu) == .Vector) {
2980 return self.fail("TODO implement airAbs for {}", .{ty.fmt(zcu)});
3548 return func.fail("TODO implement airAbs for {}", .{ty.fmt(zcu)});
29813549 } else {
2982 const int_bits = ty.intInfo(zcu).bits;
3550 const return_mcv = try func.copyToNewRegister(inst, operand);
3551 const operand_reg = return_mcv.register;
3552
3553 const temp_reg, const temp_lock = try func.allocReg(.int);
3554 defer func.register_manager.unlockReg(temp_lock);
3555
3556 _ = try func.addInst(.{
3557 .tag = .srai,
3558 .ops = .rri,
3559 .data = .{ .i_type = .{
3560 .rd = temp_reg,
3561 .rs1 = operand_reg,
3562 .imm12 = Immediate.u(63),
3563 } },
3564 });
29833565
2984 if (int_bits > 32) {
2985 return self.fail("TODO: airAbs for larger than 32 bits", .{});
3566 _ = try func.addInst(.{
3567 .tag = .xor,
3568 .ops = .rrr,
3569 .data = .{ .r_type = .{
3570 .rd = operand_reg,
3571 .rs1 = operand_reg,
3572 .rs2 = temp_reg,
3573 } },
3574 });
3575
3576 _ = try func.addInst(.{
3577 .tag = .sub,
3578 .ops = .rrr,
3579 .data = .{ .r_type = .{
3580 .rd = operand_reg,
3581 .rs1 = operand_reg,
3582 .rs2 = temp_reg,
3583 } },
3584 });
3585
3586 break :result return_mcv;
3587 },
3588 .Float => {
3589 const float_bits = scalar_ty.floatBits(zcu.getTarget());
3590 switch (float_bits) {
3591 16 => return func.fail("TODO: airAbs 16-bit float", .{}),
3592 32 => {},
3593 64 => {},
3594 80 => return func.fail("TODO: airAbs 80-bit float", .{}),
3595 128 => return func.fail("TODO: airAbs 128-bit float", .{}),
3596 else => unreachable,
29863597 }
29873598
2988 // promote the src into a register
2989 const src_mcv = try self.copyToNewRegister(inst, operand);
2990 // temp register for shift
2991 const temp_reg = try self.register_manager.allocReg(inst, gp);
3599 const return_mcv = try func.copyToNewRegister(inst, operand);
3600 const operand_reg = return_mcv.register;
29923601
2993 _ = try self.addInst(.{
2994 .tag = .abs,
2995 .ops = .rri,
3602 assert(operand_reg.class() == .float);
3603
3604 _ = try func.addInst(.{
3605 .tag = .pseudo,
3606 .ops = .pseudo_fabs,
29963607 .data = .{
2997 .i_type = .{
2998 .rs1 = src_mcv.register,
2999 .rd = temp_reg,
3000 .imm12 = Immediate.s(int_bits - 1),
3608 .fabs = .{
3609 .rd = operand_reg,
3610 .rs = operand_reg,
3611 .bits = float_bits,
30013612 },
30023613 },
30033614 });
30043615
3005 break :result src_mcv;
3616 break :result return_mcv;
30063617 },
3007 else => return self.fail("TODO: implement airAbs {}", .{scalar_ty.fmt(zcu)}),
3618 else => return func.fail("TODO: implement airAbs {}", .{scalar_ty.fmt(zcu)}),
30083619 }
3620
3621 break :result .unreach;
30093622 };
3010 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
3623 return func.finishAir(inst, result, .{ ty_op.operand, .none, .none });
30113624}
30123625
3013fn airByteSwap(self: *Self, inst: Air.Inst.Index) !void {
3014 const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
3015 const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else result: {
3016 const zcu = self.bin_file.comp.module.?;
3017 const ty = self.typeOf(ty_op.operand);
3018 const operand = try self.resolveInst(ty_op.operand);
3626fn airByteSwap(func: *Func, inst: Air.Inst.Index) !void {
3627 const ty_op = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
3628 const result: MCValue = if (func.liveness.isUnused(inst)) .unreach else result: {
3629 const zcu = func.bin_file.comp.module.?;
3630 const ty = func.typeOf(ty_op.operand);
3631 const operand = try func.resolveInst(ty_op.operand);
30193632
30203633 const int_bits = ty.intInfo(zcu).bits;
30213634
30223635 // bytes are no-op
3023 if (int_bits == 8 and self.reuseOperand(inst, ty_op.operand, 0, operand)) {
3024 return self.finishAir(inst, operand, .{ ty_op.operand, .none, .none });
3636 if (int_bits == 8 and func.reuseOperand(inst, ty_op.operand, 0, operand)) {
3637 return func.finishAir(inst, operand, .{ ty_op.operand, .none, .none });
30253638 }
30263639
3027 const dest_reg = try self.register_manager.allocReg(null, gp);
3028 try self.genSetReg(ty, dest_reg, operand);
3640 const dest_mcv = try func.copyToNewRegister(inst, operand);
3641 const dest_reg = dest_mcv.register;
3642
3643 switch (int_bits) {
3644 16 => {
3645 const temp_reg, const temp_lock = try func.allocReg(.int);
3646 defer func.register_manager.unlockReg(temp_lock);
30293647
3030 const dest_mcv: MCValue = .{ .register = dest_reg };
3648 _ = try func.addInst(.{
3649 .tag = .srli,
3650 .ops = .rri,
3651 .data = .{ .i_type = .{
3652 .imm12 = Immediate.s(8),
3653 .rd = temp_reg,
3654 .rs1 = dest_reg,
3655 } },
3656 });
30313657
3032 switch (int_bits) {
3033 16 => {
3034 const temp = try self.binOp(.shr, dest_mcv, ty, .{ .immediate = 8 }, Type.u8);
3035 assert(temp == .register);
3036 _ = try self.addInst(.{
3658 _ = try func.addInst(.{
30373659 .tag = .slli,
30383660 .ops = .rri,
30393661 .data = .{ .i_type = .{
......@@ -3042,58 +3664,59 @@ fn airByteSwap(self: *Self, inst: Air.Inst.Index) !void {
30423664 .rs1 = dest_reg,
30433665 } },
30443666 });
3045 _ = try self.addInst(.{
3667 _ = try func.addInst(.{
30463668 .tag = .@"or",
30473669 .ops = .rri,
30483670 .data = .{ .r_type = .{
30493671 .rd = dest_reg,
30503672 .rs1 = dest_reg,
3051 .rs2 = temp.register,
3673 .rs2 = temp_reg,
30523674 } },
30533675 });
30543676 },
3055 else => return self.fail("TODO: {d} bits for airByteSwap", .{int_bits}),
3677 else => return func.fail("TODO: {d} bits for airByteSwap", .{int_bits}),
30563678 }
30573679
30583680 break :result dest_mcv;
30593681 };
3060 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
3682 return func.finishAir(inst, result, .{ ty_op.operand, .none, .none });
30613683}
30623684
3063fn airBitReverse(self: *Self, inst: Air.Inst.Index) !void {
3064 const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
3065 const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else return self.fail("TODO implement airBitReverse for {}", .{self.target.cpu.arch});
3066 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
3685fn airBitReverse(func: *Func, inst: Air.Inst.Index) !void {
3686 const ty_op = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
3687 const result: MCValue = if (func.liveness.isUnused(inst)) .unreach else return func.fail("TODO implement airBitReverse for {}", .{func.target.cpu.arch});
3688 return func.finishAir(inst, result, .{ ty_op.operand, .none, .none });
30673689}
30683690
3069fn airUnaryMath(self: *Self, inst: Air.Inst.Index) !void {
3070 const un_op = self.air.instructions.items(.data)[@intFromEnum(inst)].un_op;
3071 const result: MCValue = if (self.liveness.isUnused(inst))
3691fn airUnaryMath(func: *Func, inst: Air.Inst.Index) !void {
3692 const tag = func.air.instructions.items(.tag)[@intFromEnum(inst)];
3693 const un_op = func.air.instructions.items(.data)[@intFromEnum(inst)].un_op;
3694 const result: MCValue = if (func.liveness.isUnused(inst))
30723695 .unreach
30733696 else
3074 return self.fail("TODO implement airUnaryMath for {}", .{self.target.cpu.arch});
3075 return self.finishAir(inst, result, .{ un_op, .none, .none });
3697 return func.fail("TODO implementairUnaryMath {s} for {}", .{ @tagName(tag), func.target.cpu.arch });
3698 return func.finishAir(inst, result, .{ un_op, .none, .none });
30763699}
30773700
30783701fn reuseOperand(
3079 self: *Self,
3702 func: *Func,
30803703 inst: Air.Inst.Index,
30813704 operand: Air.Inst.Ref,
30823705 op_index: Liveness.OperandInt,
30833706 mcv: MCValue,
30843707) bool {
3085 return self.reuseOperandAdvanced(inst, operand, op_index, mcv, inst);
3708 return func.reuseOperandAdvanced(inst, operand, op_index, mcv, inst);
30863709}
30873710
30883711fn reuseOperandAdvanced(
3089 self: *Self,
3712 func: *Func,
30903713 inst: Air.Inst.Index,
30913714 operand: Air.Inst.Ref,
30923715 op_index: Liveness.OperandInt,
30933716 mcv: MCValue,
30943717 maybe_tracked_inst: ?Air.Inst.Index,
30953718) bool {
3096 if (!self.liveness.operandDies(inst, op_index))
3719 if (!func.liveness.operandDies(inst, op_index))
30973720 return false;
30983721
30993722 switch (mcv) {
......@@ -3103,55 +3726,59 @@ fn reuseOperandAdvanced(
31033726 // If it's in the registers table, need to associate the register(s) with the
31043727 // new instruction.
31053728 if (maybe_tracked_inst) |tracked_inst| {
3106 if (!self.register_manager.isRegFree(reg)) {
3729 if (!func.register_manager.isRegFree(reg)) {
31073730 if (RegisterManager.indexOfRegIntoTracked(reg)) |index| {
3108 self.register_manager.registers[index] = tracked_inst;
3731 func.register_manager.registers[index] = tracked_inst;
31093732 }
31103733 }
3111 } else self.register_manager.freeReg(reg);
3734 } else func.register_manager.freeReg(reg);
31123735 },
31133736 .load_frame => |frame_addr| if (frame_addr.index.isNamed()) return false,
31143737 else => return false,
31153738 }
31163739
31173740 // Prevent the operand deaths processing code from deallocating it.
3118 self.liveness.clearOperandDeath(inst, op_index);
3741 func.liveness.clearOperandDeath(inst, op_index);
31193742 const op_inst = operand.toIndex().?;
3120 self.getResolvedInstValue(op_inst).reuse(self, maybe_tracked_inst, op_inst);
3743 func.getResolvedInstValue(op_inst).reuse(func, maybe_tracked_inst, op_inst);
31213744
31223745 return true;
31233746}
31243747
3125fn airLoad(self: *Self, inst: Air.Inst.Index) !void {
3126 const zcu = self.bin_file.comp.module.?;
3127 const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
3128 const elem_ty = self.typeOfIndex(inst);
3748fn airLoad(func: *Func, inst: Air.Inst.Index) !void {
3749 const zcu = func.bin_file.comp.module.?;
3750 const ty_op = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
3751 const elem_ty = func.typeOfIndex(inst);
3752
31293753 const result: MCValue = result: {
31303754 if (!elem_ty.hasRuntimeBits(zcu))
31313755 break :result .none;
31323756
3133 const ptr = try self.resolveInst(ty_op.operand);
3134 const is_volatile = self.typeOf(ty_op.operand).isVolatilePtr(zcu);
3135 if (self.liveness.isUnused(inst) and !is_volatile)
3757 const ptr = try func.resolveInst(ty_op.operand);
3758 const is_volatile = func.typeOf(ty_op.operand).isVolatilePtr(zcu);
3759 if (func.liveness.isUnused(inst) and !is_volatile)
31363760 break :result .unreach;
31373761
3762 const elem_size = elem_ty.abiSize(zcu);
3763
31383764 const dst_mcv: MCValue = blk: {
3139 if (self.reuseOperand(inst, ty_op.operand, 0, ptr)) {
3765 // Pointer is 8 bytes, and if the element is more than that, we cannot reuse it.
3766 if (elem_size <= 8 and func.reuseOperand(inst, ty_op.operand, 0, ptr)) {
31403767 // The MCValue that holds the pointer can be re-used as the value.
31413768 break :blk ptr;
31423769 } else {
3143 break :blk try self.allocRegOrMem(inst, true);
3770 break :blk try func.allocRegOrMem(elem_ty, inst, true);
31443771 }
31453772 };
31463773
3147 try self.load(dst_mcv, ptr, self.typeOf(ty_op.operand));
3774 try func.load(dst_mcv, ptr, func.typeOf(ty_op.operand));
31483775 break :result dst_mcv;
31493776 };
3150 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
3777 return func.finishAir(inst, result, .{ ty_op.operand, .none, .none });
31513778}
31523779
3153fn load(self: *Self, dst_mcv: MCValue, ptr_mcv: MCValue, ptr_ty: Type) InnerError!void {
3154 const zcu = self.bin_file.comp.module.?;
3780fn load(func: *Func, dst_mcv: MCValue, ptr_mcv: MCValue, ptr_ty: Type) InnerError!void {
3781 const zcu = func.bin_file.comp.module.?;
31553782 const dst_ty = ptr_ty.childType(zcu);
31563783
31573784 log.debug("loading {}:{} into {}", .{ ptr_mcv, ptr_ty.fmt(zcu), dst_mcv });
......@@ -3170,43 +3797,43 @@ fn load(self: *Self, dst_mcv: MCValue, ptr_mcv: MCValue, ptr_ty: Type) InnerErro
31703797 .register_offset,
31713798 .lea_frame,
31723799 .lea_symbol,
3173 => try self.genCopy(dst_ty, dst_mcv, ptr_mcv.deref()),
3800 => try func.genCopy(dst_ty, dst_mcv, ptr_mcv.deref()),
31743801
31753802 .memory,
31763803 .indirect,
31773804 .load_symbol,
31783805 .load_frame,
31793806 => {
3180 const addr_reg = try self.copyToTmpRegister(ptr_ty, ptr_mcv);
3181 const addr_lock = self.register_manager.lockRegAssumeUnused(addr_reg);
3182 defer self.register_manager.unlockReg(addr_lock);
3807 const addr_reg = try func.copyToTmpRegister(ptr_ty, ptr_mcv);
3808 const addr_lock = func.register_manager.lockRegAssumeUnused(addr_reg);
3809 defer func.register_manager.unlockReg(addr_lock);
31833810
3184 try self.genCopy(dst_ty, dst_mcv, .{ .indirect = .{ .reg = addr_reg } });
3811 try func.genCopy(dst_ty, dst_mcv, .{ .indirect = .{ .reg = addr_reg } });
31853812 },
3186 .air_ref => |ptr_ref| try self.load(dst_mcv, try self.resolveInst(ptr_ref), ptr_ty),
3813 .air_ref => |ptr_ref| try func.load(dst_mcv, try func.resolveInst(ptr_ref), ptr_ty),
31873814 }
31883815}
31893816
3190fn airStore(self: *Self, inst: Air.Inst.Index, safety: bool) !void {
3817fn airStore(func: *Func, inst: Air.Inst.Index, safety: bool) !void {
31913818 if (safety) {
31923819 // TODO if the value is undef, write 0xaa bytes to dest
31933820 } else {
31943821 // TODO if the value is undef, don't lower this instruction
31953822 }
3196 const bin_op = self.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
3197 const ptr = try self.resolveInst(bin_op.lhs);
3198 const value = try self.resolveInst(bin_op.rhs);
3199 const ptr_ty = self.typeOf(bin_op.lhs);
3200 const value_ty = self.typeOf(bin_op.rhs);
3823 const bin_op = func.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
3824 const ptr = try func.resolveInst(bin_op.lhs);
3825 const value = try func.resolveInst(bin_op.rhs);
3826 const ptr_ty = func.typeOf(bin_op.lhs);
3827 const value_ty = func.typeOf(bin_op.rhs);
32013828
3202 try self.store(ptr, value, ptr_ty, value_ty);
3829 try func.store(ptr, value, ptr_ty, value_ty);
32033830
3204 return self.finishAir(inst, .none, .{ bin_op.lhs, bin_op.rhs, .none });
3831 return func.finishAir(inst, .none, .{ bin_op.lhs, bin_op.rhs, .none });
32053832}
32063833
32073834/// Loads `value` into the "payload" of `pointer`.
3208fn store(self: *Self, ptr_mcv: MCValue, src_mcv: MCValue, ptr_ty: Type, src_ty: Type) !void {
3209 const zcu = self.bin_file.comp.module.?;
3835fn store(func: *Func, ptr_mcv: MCValue, src_mcv: MCValue, ptr_ty: Type, src_ty: Type) !void {
3836 const zcu = func.bin_file.comp.module.?;
32103837
32113838 log.debug("storing {}:{} in {}:{}", .{ src_mcv, src_ty.fmt(zcu), ptr_mcv, ptr_ty.fmt(zcu) });
32123839
......@@ -3223,40 +3850,40 @@ fn store(self: *Self, ptr_mcv: MCValue, src_mcv: MCValue, ptr_ty: Type, src_ty:
32233850 .register_offset,
32243851 .lea_symbol,
32253852 .lea_frame,
3226 => try self.genCopy(src_ty, ptr_mcv.deref(), src_mcv),
3853 => try func.genCopy(src_ty, ptr_mcv.deref(), src_mcv),
32273854
32283855 .memory,
32293856 .indirect,
32303857 .load_symbol,
32313858 .load_frame,
32323859 => {
3233 const addr_reg = try self.copyToTmpRegister(ptr_ty, ptr_mcv);
3234 const addr_lock = self.register_manager.lockRegAssumeUnused(addr_reg);
3235 defer self.register_manager.unlockReg(addr_lock);
3860 const addr_reg = try func.copyToTmpRegister(ptr_ty, ptr_mcv);
3861 const addr_lock = func.register_manager.lockRegAssumeUnused(addr_reg);
3862 defer func.register_manager.unlockReg(addr_lock);
32363863
3237 try self.genCopy(src_ty, .{ .indirect = .{ .reg = addr_reg } }, src_mcv);
3864 try func.genCopy(src_ty, .{ .indirect = .{ .reg = addr_reg } }, src_mcv);
32383865 },
3239 .air_ref => |ptr_ref| try self.store(try self.resolveInst(ptr_ref), src_mcv, ptr_ty, src_ty),
3866 .air_ref => |ptr_ref| try func.store(try func.resolveInst(ptr_ref), src_mcv, ptr_ty, src_ty),
32403867 }
32413868}
32423869
3243fn airStructFieldPtr(self: *Self, inst: Air.Inst.Index) !void {
3244 const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
3245 const extra = self.air.extraData(Air.StructField, ty_pl.payload).data;
3246 const result = try self.structFieldPtr(inst, extra.struct_operand, extra.field_index);
3247 return self.finishAir(inst, result, .{ extra.struct_operand, .none, .none });
3870fn airStructFieldPtr(func: *Func, inst: Air.Inst.Index) !void {
3871 const ty_pl = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
3872 const extra = func.air.extraData(Air.StructField, ty_pl.payload).data;
3873 const result = try func.structFieldPtr(inst, extra.struct_operand, extra.field_index);
3874 return func.finishAir(inst, result, .{ extra.struct_operand, .none, .none });
32483875}
32493876
3250fn airStructFieldPtrIndex(self: *Self, inst: Air.Inst.Index, index: u8) !void {
3251 const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
3252 const result = try self.structFieldPtr(inst, ty_op.operand, index);
3253 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
3877fn airStructFieldPtrIndex(func: *Func, inst: Air.Inst.Index, index: u8) !void {
3878 const ty_op = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
3879 const result = try func.structFieldPtr(inst, ty_op.operand, index);
3880 return func.finishAir(inst, result, .{ ty_op.operand, .none, .none });
32543881}
32553882
3256fn structFieldPtr(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, index: u32) !MCValue {
3257 const zcu = self.bin_file.comp.module.?;
3258 const ptr_field_ty = self.typeOfIndex(inst);
3259 const ptr_container_ty = self.typeOf(operand);
3883fn structFieldPtr(func: *Func, inst: Air.Inst.Index, operand: Air.Inst.Ref, index: u32) !MCValue {
3884 const zcu = func.bin_file.comp.module.?;
3885 const ptr_field_ty = func.typeOfIndex(inst);
3886 const ptr_container_ty = func.typeOf(operand);
32603887 const ptr_container_ty_info = ptr_container_ty.ptrInfo(zcu);
32613888 const container_ty = ptr_container_ty.childType(zcu);
32623889
......@@ -3269,27 +3896,27 @@ fn structFieldPtr(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, inde
32693896 else
32703897 @intCast(container_ty.structFieldOffset(index, zcu));
32713898
3272 const src_mcv = try self.resolveInst(operand);
3899 const src_mcv = try func.resolveInst(operand);
32733900 const dst_mcv = if (switch (src_mcv) {
32743901 .immediate, .lea_frame => true,
3275 .register, .register_offset => self.reuseOperand(inst, operand, 0, src_mcv),
3902 .register, .register_offset => func.reuseOperand(inst, operand, 0, src_mcv),
32763903 else => false,
3277 }) src_mcv else try self.copyToNewRegister(inst, src_mcv);
3904 }) src_mcv else try func.copyToNewRegister(inst, src_mcv);
32783905 return dst_mcv.offset(field_offset);
32793906}
32803907
3281fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {
3282 const mod = self.bin_file.comp.module.?;
3908fn airStructFieldVal(func: *Func, inst: Air.Inst.Index) !void {
3909 const mod = func.bin_file.comp.module.?;
32833910
3284 const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
3285 const extra = self.air.extraData(Air.StructField, ty_pl.payload).data;
3911 const ty_pl = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
3912 const extra = func.air.extraData(Air.StructField, ty_pl.payload).data;
32863913 const operand = extra.struct_operand;
32873914 const index = extra.field_index;
32883915
3289 const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else result: {
3290 const zcu = self.bin_file.comp.module.?;
3291 const src_mcv = try self.resolveInst(operand);
3292 const struct_ty = self.typeOf(operand);
3916 const result: MCValue = if (func.liveness.isUnused(inst)) .unreach else result: {
3917 const zcu = func.bin_file.comp.module.?;
3918 const src_mcv = try func.resolveInst(operand);
3919 const struct_ty = func.typeOf(operand);
32933920 const field_ty = struct_ty.structFieldType(index, zcu);
32943921 if (!field_ty.hasRuntimeBitsIgnoreComptime(zcu)) break :result .none;
32953922
......@@ -3304,33 +3931,31 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {
33043931 switch (src_mcv) {
33053932 .dead, .unreach => unreachable,
33063933 .register => |src_reg| {
3307 const src_reg_lock = self.register_manager.lockRegAssumeUnused(src_reg);
3308 defer self.register_manager.unlockReg(src_reg_lock);
3934 const src_reg_lock = func.register_manager.lockRegAssumeUnused(src_reg);
3935 defer func.register_manager.unlockReg(src_reg_lock);
33093936
33103937 const dst_reg = if (field_off == 0)
3311 (try self.copyToNewRegister(inst, src_mcv)).register
3938 (try func.copyToNewRegister(inst, src_mcv)).register
33123939 else
3313 try self.copyToTmpRegister(Type.usize, .{ .register = src_reg });
3940 try func.copyToTmpRegister(Type.usize, .{ .register = src_reg });
33143941
33153942 const dst_mcv: MCValue = .{ .register = dst_reg };
3316 const dst_lock = self.register_manager.lockReg(dst_reg);
3317 defer if (dst_lock) |lock| self.register_manager.unlockReg(lock);
3943 const dst_lock = func.register_manager.lockReg(dst_reg);
3944 defer if (dst_lock) |lock| func.register_manager.unlockReg(lock);
33183945
33193946 if (field_off > 0) {
3320 _ = try self.addInst(.{
3947 _ = try func.addInst(.{
33213948 .tag = .srli,
33223949 .ops = .rri,
33233950 .data = .{ .i_type = .{
3324 .imm12 = Immediate.s(@intCast(field_off)),
3951 .imm12 = Immediate.u(@intCast(field_off)),
33253952 .rd = dst_reg,
33263953 .rs1 = dst_reg,
33273954 } },
33283955 });
3329
3330 return self.fail("TODO: airStructFieldVal register with field_off > 0", .{});
33313956 }
33323957
3333 break :result if (field_off == 0) dst_mcv else try self.copyToNewRegister(inst, dst_mcv);
3958 break :result if (field_off == 0) dst_mcv else try func.copyToNewRegister(inst, dst_mcv);
33343959 },
33353960 .load_frame => {
33363961 const field_abi_size: u32 = @intCast(field_ty.abiSize(mod));
......@@ -3345,57 +3970,57 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {
33453970 @intCast(field_bit_size),
33463971 );
33473972
3348 const dst_reg, const dst_lock = try self.allocReg();
3973 const dst_reg, const dst_lock = try func.allocReg(.int);
33493974 const dst_mcv = MCValue{ .register = dst_reg };
3350 defer self.register_manager.unlockReg(dst_lock);
3975 defer func.register_manager.unlockReg(dst_lock);
33513976
3352 try self.genCopy(int_ty, dst_mcv, off_mcv);
3353 break :result try self.copyToNewRegister(inst, dst_mcv);
3977 try func.genCopy(int_ty, dst_mcv, off_mcv);
3978 break :result try func.copyToNewRegister(inst, dst_mcv);
33543979 }
33553980
33563981 const container_abi_size: u32 = @intCast(struct_ty.abiSize(mod));
33573982 const dst_mcv = if (field_byte_off + field_abi_size <= container_abi_size and
3358 self.reuseOperand(inst, operand, 0, src_mcv))
3983 func.reuseOperand(inst, operand, 0, src_mcv))
33593984 off_mcv
33603985 else dst: {
3361 const dst_mcv = try self.allocRegOrMem(inst, true);
3362 try self.genCopy(field_ty, dst_mcv, off_mcv);
3986 const dst_mcv = try func.allocRegOrMem(func.typeOfIndex(inst), inst, true);
3987 try func.genCopy(field_ty, dst_mcv, off_mcv);
33633988 break :dst dst_mcv;
33643989 };
33653990 if (field_abi_size * 8 > field_bit_size and dst_mcv.isMemory()) {
3366 const tmp_reg, const tmp_lock = try self.allocReg();
3367 defer self.register_manager.unlockReg(tmp_lock);
3991 const tmp_reg, const tmp_lock = try func.allocReg(.int);
3992 defer func.register_manager.unlockReg(tmp_lock);
33683993
33693994 const hi_mcv =
33703995 dst_mcv.address().offset(@intCast(field_bit_size / 64 * 8)).deref();
3371 try self.genSetReg(Type.usize, tmp_reg, hi_mcv);
3372 try self.genCopy(Type.usize, hi_mcv, .{ .register = tmp_reg });
3996 try func.genSetReg(Type.usize, tmp_reg, hi_mcv);
3997 try func.genCopy(Type.usize, hi_mcv, .{ .register = tmp_reg });
33733998 }
33743999 break :result dst_mcv;
33754000 }
33764001
3377 return self.fail("TODO: airStructFieldVal load_frame field_off non multiple of 8", .{});
4002 return func.fail("TODO: airStructFieldVal load_frame field_off non multiple of 8", .{});
33784003 },
3379 else => return self.fail("TODO: airStructField {s}", .{@tagName(src_mcv)}),
4004 else => return func.fail("TODO: airStructField {s}", .{@tagName(src_mcv)}),
33804005 }
33814006 };
33824007
3383 return self.finishAir(inst, result, .{ extra.struct_operand, .none, .none });
4008 return func.finishAir(inst, result, .{ extra.struct_operand, .none, .none });
33844009}
33854010
3386fn airFieldParentPtr(self: *Self, inst: Air.Inst.Index) !void {
4011fn airFieldParentPtr(func: *Func, inst: Air.Inst.Index) !void {
33874012 _ = inst;
3388 return self.fail("TODO implement codegen airFieldParentPtr", .{});
4013 return func.fail("TODO implement codegen airFieldParentPtr", .{});
33894014}
33904015
3391fn genArgDbgInfo(self: Self, inst: Air.Inst.Index, mcv: MCValue) !void {
3392 const zcu = self.bin_file.comp.module.?;
3393 const arg = self.air.instructions.items(.data)[@intFromEnum(inst)].arg;
4016fn genArgDbgInfo(func: Func, inst: Air.Inst.Index, mcv: MCValue) !void {
4017 const zcu = func.bin_file.comp.module.?;
4018 const arg = func.air.instructions.items(.data)[@intFromEnum(inst)].arg;
33944019 const ty = arg.ty.toType();
3395 const owner_decl = zcu.funcOwnerDeclIndex(self.func_index);
3396 const name = zcu.getParamName(self.func_index, arg.src_index);
4020 const owner_decl = zcu.funcOwnerDeclIndex(func.func_index);
4021 const name = zcu.getParamName(func.func_index, arg.src_index);
33974022
3398 switch (self.debug_output) {
4023 switch (func.debug_output) {
33994024 .dwarf => |dw| switch (mcv) {
34004025 .register => |reg| try dw.genArgDbgInfo(name, ty, owner_decl, .{
34014026 .register = reg.dwarfLocOp(),
......@@ -3408,119 +4033,100 @@ fn genArgDbgInfo(self: Self, inst: Air.Inst.Index, mcv: MCValue) !void {
34084033 }
34094034}
34104035
3411fn airArg(self: *Self, inst: Air.Inst.Index) !void {
3412 const zcu = self.bin_file.comp.module.?;
3413 var arg_index = self.arg_index;
4036fn airArg(func: *Func, inst: Air.Inst.Index) !void {
4037 var arg_index = func.arg_index;
34144038
34154039 // we skip over args that have no bits
3416 while (self.args[arg_index] == .none) arg_index += 1;
3417 self.arg_index = arg_index + 1;
4040 while (func.args[arg_index] == .none) arg_index += 1;
4041 func.arg_index = arg_index + 1;
34184042
3419 const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else result: {
3420 const src_mcv = self.args[arg_index];
4043 const result: MCValue = if (func.liveness.isUnused(inst)) .unreach else result: {
4044 const src_mcv = func.args[arg_index];
4045 const arg_ty = func.typeOfIndex(inst);
34214046
3422 const arg_ty = self.typeOfIndex(inst);
4047 const dst_mcv = try func.allocRegOrMem(arg_ty, inst, false);
34234048
3424 const dst_mcv = switch (src_mcv) {
3425 .register => dst: {
3426 const frame = try self.allocFrameIndex(FrameAlloc.init(.{
3427 .size = Type.usize.abiSize(zcu),
3428 .alignment = Type.usize.abiAlignment(zcu),
3429 }));
3430 const dst_mcv: MCValue = .{ .load_frame = .{ .index = frame } };
3431 try self.genCopy(Type.usize, dst_mcv, src_mcv);
3432 break :dst dst_mcv;
3433 },
3434 .register_pair => dst: {
3435 const frame = try self.allocFrameIndex(FrameAlloc.init(.{
3436 .size = Type.usize.abiSize(zcu) * 2,
3437 .alignment = Type.usize.abiAlignment(zcu),
3438 }));
3439 const dst_mcv: MCValue = .{ .load_frame = .{ .index = frame } };
3440 try self.genCopy(arg_ty, dst_mcv, src_mcv);
3441 break :dst dst_mcv;
3442 },
3443 .load_frame => src_mcv,
3444 else => return self.fail("TODO: airArg {s}", .{@tagName(src_mcv)}),
3445 };
4049 log.debug("airArg {} -> {}", .{ src_mcv, dst_mcv });
34464050
3447 try self.genArgDbgInfo(inst, src_mcv);
4051 try func.genCopy(arg_ty, dst_mcv, src_mcv);
4052
4053 try func.genArgDbgInfo(inst, src_mcv);
34484054 break :result dst_mcv;
34494055 };
34504056
3451 return self.finishAir(inst, result, .{ .none, .none, .none });
4057 return func.finishAir(inst, result, .{ .none, .none, .none });
34524058}
34534059
3454fn airTrap(self: *Self) !void {
3455 _ = try self.addInst(.{
4060fn airTrap(func: *Func) !void {
4061 _ = try func.addInst(.{
34564062 .tag = .unimp,
34574063 .ops = .none,
34584064 .data = undefined,
34594065 });
3460 return self.finishAirBookkeeping();
4066 return func.finishAirBookkeeping();
34614067}
34624068
3463fn airBreakpoint(self: *Self) !void {
3464 _ = try self.addInst(.{
4069fn airBreakpoint(func: *Func) !void {
4070 _ = try func.addInst(.{
34654071 .tag = .ebreak,
34664072 .ops = .none,
34674073 .data = undefined,
34684074 });
3469 return self.finishAirBookkeeping();
4075 return func.finishAirBookkeeping();
34704076}
34714077
3472fn airRetAddr(self: *Self, inst: Air.Inst.Index) !void {
3473 const dst_mcv = try self.allocRegOrMem(inst, true);
3474 try self.genCopy(Type.usize, dst_mcv, .{ .load_frame = .{ .index = .ret_addr } });
3475 return self.finishAir(inst, dst_mcv, .{ .none, .none, .none });
4078fn airRetAddr(func: *Func, inst: Air.Inst.Index) !void {
4079 const dst_mcv = try func.allocRegOrMem(func.typeOfIndex(inst), inst, true);
4080 try func.genCopy(Type.usize, dst_mcv, .{ .load_frame = .{ .index = .ret_addr } });
4081 return func.finishAir(inst, dst_mcv, .{ .none, .none, .none });
34764082}
34774083
3478fn airFrameAddress(self: *Self, inst: Air.Inst.Index) !void {
3479 const dst_mcv = try self.allocRegOrMem(inst, true);
3480 try self.genCopy(Type.usize, dst_mcv, .{ .lea_frame = .{ .index = .base_ptr } });
3481 return self.finishAir(inst, dst_mcv, .{ .none, .none, .none });
4084fn airFrameAddress(func: *Func, inst: Air.Inst.Index) !void {
4085 const dst_mcv = try func.allocRegOrMem(func.typeOfIndex(inst), inst, true);
4086 try func.genCopy(Type.usize, dst_mcv, .{ .lea_frame = .{ .index = .base_ptr } });
4087 return func.finishAir(inst, dst_mcv, .{ .none, .none, .none });
34824088}
34834089
3484fn airFence(self: *Self) !void {
3485 return self.fail("TODO implement fence() for {}", .{self.target.cpu.arch});
3486 //return self.finishAirBookkeeping();
4090fn airFence(func: *Func) !void {
4091 return func.fail("TODO implement fence() for {}", .{func.target.cpu.arch});
4092 //return func.finishAirBookkeeping();
34874093}
34884094
3489fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier) !void {
3490 if (modifier == .always_tail) return self.fail("TODO implement tail calls for riscv64", .{});
3491 const pl_op = self.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;
4095fn airCall(func: *Func, inst: Air.Inst.Index, modifier: std.builtin.CallModifier) !void {
4096 if (modifier == .always_tail) return func.fail("TODO implement tail calls for riscv64", .{});
4097 const pl_op = func.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;
34924098 const callee = pl_op.operand;
3493 const extra = self.air.extraData(Air.Call, pl_op.payload);
3494 const arg_refs: []const Air.Inst.Ref = @ptrCast(self.air.extra[extra.end..][0..extra.data.args_len]);
4099 const extra = func.air.extraData(Air.Call, pl_op.payload);
4100 const arg_refs: []const Air.Inst.Ref = @ptrCast(func.air.extra[extra.end..][0..extra.data.args_len]);
34954101
34964102 const expected_num_args = 8;
34974103 const ExpectedContents = extern struct {
34984104 vals: [expected_num_args][@sizeOf(MCValue)]u8 align(@alignOf(MCValue)),
34994105 };
35004106 var stack align(@max(@alignOf(ExpectedContents), @alignOf(std.heap.StackFallbackAllocator(0)))) =
3501 std.heap.stackFallback(@sizeOf(ExpectedContents), self.gpa);
4107 std.heap.stackFallback(@sizeOf(ExpectedContents), func.gpa);
35024108 const allocator = stack.get();
35034109
35044110 const arg_tys = try allocator.alloc(Type, arg_refs.len);
35054111 defer allocator.free(arg_tys);
3506 for (arg_tys, arg_refs) |*arg_ty, arg_ref| arg_ty.* = self.typeOf(arg_ref);
4112 for (arg_tys, arg_refs) |*arg_ty, arg_ref| arg_ty.* = func.typeOf(arg_ref);
35074113
35084114 const arg_vals = try allocator.alloc(MCValue, arg_refs.len);
35094115 defer allocator.free(arg_vals);
35104116 for (arg_vals, arg_refs) |*arg_val, arg_ref| arg_val.* = .{ .air_ref = arg_ref };
35114117
3512 const call_ret = try self.genCall(.{ .air = callee }, arg_tys, arg_vals);
4118 const call_ret = try func.genCall(.{ .air = callee }, arg_tys, arg_vals);
35134119
3514 var bt = self.liveness.iterateBigTomb(inst);
3515 try self.feed(&bt, pl_op.operand);
3516 for (arg_refs) |arg_ref| try self.feed(&bt, arg_ref);
4120 var bt = func.liveness.iterateBigTomb(inst);
4121 try func.feed(&bt, pl_op.operand);
4122 for (arg_refs) |arg_ref| try func.feed(&bt, arg_ref);
35174123
3518 const result = if (self.liveness.isUnused(inst)) .unreach else call_ret;
3519 return self.finishAirResult(inst, result);
4124 const result = if (func.liveness.isUnused(inst)) .unreach else call_ret;
4125 return func.finishAirResult(inst, result);
35204126}
35214127
35224128fn genCall(
3523 self: *Self,
4129 func: *Func,
35244130 info: union(enum) {
35254131 air: Air.Inst.Ref,
35264132 lib: struct {
......@@ -3533,11 +4139,11 @@ fn genCall(
35334139 arg_tys: []const Type,
35344140 args: []const MCValue,
35354141) !MCValue {
3536 const zcu = self.bin_file.comp.module.?;
4142 const zcu = func.bin_file.comp.module.?;
35374143
35384144 const fn_ty = switch (info) {
35394145 .air => |callee| fn_info: {
3540 const callee_ty = self.typeOf(callee);
4146 const callee_ty = func.typeOf(callee);
35414147 break :fn_info switch (callee_ty.zigTypeTag(zcu)) {
35424148 .Fn => callee_ty,
35434149 .Pointer => callee_ty.childType(zcu),
......@@ -3552,8 +4158,15 @@ fn genCall(
35524158 };
35534159
35544160 const fn_info = zcu.typeToFunc(fn_ty).?;
3555 var call_info = try self.resolveCallingConventionValues(fn_info);
3556 defer call_info.deinit(self);
4161
4162 const allocator = func.gpa;
4163
4164 const var_args = try allocator.alloc(Type, args.len - fn_info.param_types.len);
4165 defer allocator.free(var_args);
4166 for (var_args, arg_tys[fn_info.param_types.len..]) |*var_arg, arg_ty| var_arg.* = arg_ty;
4167
4168 var call_info = try func.resolveCallingConventionValues(fn_info, var_args);
4169 defer call_info.deinit(func);
35574170
35584171 // We need a properly aligned and sized call frame to be able to call this function.
35594172 {
......@@ -3561,7 +4174,7 @@ fn genCall(
35614174 .size = call_info.stack_byte_count,
35624175 .alignment = call_info.stack_align,
35634176 });
3564 const frame_allocs_slice = self.frame_allocs.slice();
4177 const frame_allocs_slice = func.frame_allocs.slice();
35654178 const stack_frame_size =
35664179 &frame_allocs_slice.items(.abi_size)[@intFromEnum(FrameIndex.call_frame)];
35674180 stack_frame_size.* = @max(stack_frame_size.*, needed_call_frame.abi_size);
......@@ -3570,13 +4183,75 @@ fn genCall(
35704183 stack_frame_align.* = stack_frame_align.max(needed_call_frame.abi_align);
35714184 }
35724185
3573 for (call_info.args, 0..) |mc_arg, arg_i| try self.genCopy(arg_tys[arg_i], mc_arg, args[arg_i]);
4186 var reg_locks = std.ArrayList(?RegisterLock).init(allocator);
4187 defer reg_locks.deinit();
4188 try reg_locks.ensureTotalCapacity(8);
4189 defer for (reg_locks.items) |reg_lock| if (reg_lock) |lock| func.register_manager.unlockReg(lock);
4190
4191 const frame_indices = try allocator.alloc(FrameIndex, args.len);
4192 defer allocator.free(frame_indices);
4193
4194 switch (call_info.return_value.long) {
4195 .none, .unreach => {},
4196 .indirect => |reg_off| try func.register_manager.getReg(reg_off.reg, null),
4197 else => unreachable,
4198 }
4199 for (call_info.args, args, arg_tys, frame_indices) |dst_arg, src_arg, arg_ty, *frame_index| {
4200 switch (dst_arg) {
4201 .none => {},
4202 .register => |reg| {
4203 try func.register_manager.getReg(reg, null);
4204 try reg_locks.append(func.register_manager.lockReg(reg));
4205 },
4206 .register_pair => |regs| {
4207 for (regs) |reg| try func.register_manager.getReg(reg, null);
4208 try reg_locks.appendSlice(&func.register_manager.lockRegs(2, regs));
4209 },
4210 .indirect => |reg_off| {
4211 frame_index.* = try func.allocFrameIndex(FrameAlloc.initType(arg_ty, zcu));
4212 try func.genSetMem(.{ .frame = frame_index.* }, 0, arg_ty, src_arg);
4213 try func.register_manager.getReg(reg_off.reg, null);
4214 try reg_locks.append(func.register_manager.lockReg(reg_off.reg));
4215 },
4216 else => return func.fail("TODO: genCall set arg {s}", .{@tagName(dst_arg)}),
4217 }
4218 }
4219
4220 switch (call_info.return_value.long) {
4221 .none, .unreach => {},
4222 .indirect => |reg_off| {
4223 const ret_ty = Type.fromInterned(fn_info.return_type);
4224 const frame_index = try func.allocFrameIndex(FrameAlloc.initSpill(ret_ty, zcu));
4225 try func.genSetReg(Type.usize, reg_off.reg, .{
4226 .lea_frame = .{ .index = frame_index, .off = -reg_off.off },
4227 });
4228 call_info.return_value.short = .{ .load_frame = .{ .index = frame_index } };
4229 try reg_locks.append(func.register_manager.lockReg(reg_off.reg));
4230 },
4231 else => unreachable,
4232 }
4233
4234 for (call_info.args, arg_tys, args, frame_indices) |dst_arg, arg_ty, src_arg, frame_index| {
4235 switch (dst_arg) {
4236 .none, .load_frame => {},
4237 .register_pair => try func.genCopy(arg_ty, dst_arg, src_arg),
4238 .register => |dst_reg| try func.genSetReg(
4239 arg_ty,
4240 dst_reg,
4241 src_arg,
4242 ),
4243 .indirect => |reg_off| try func.genSetReg(Type.usize, reg_off.reg, .{
4244 .lea_frame = .{ .index = frame_index, .off = -reg_off.off },
4245 }),
4246 else => return func.fail("TODO: genCall actual set {s}", .{@tagName(dst_arg)}),
4247 }
4248 }
35744249
35754250 // Due to incremental compilation, how function calls are generated depends
35764251 // on linking.
35774252 switch (info) {
35784253 .air => |callee| {
3579 if (try self.air.value(callee, zcu)) |func_value| {
4254 if (try func.air.value(callee, zcu)) |func_value| {
35804255 const func_key = zcu.intern_pool.indexToKey(func_value.ip_index);
35814256 switch (switch (func_key) {
35824257 else => func_key,
......@@ -3585,35 +4260,53 @@ fn genCall(
35854260 else => func_key,
35864261 } else func_key,
35874262 }) {
3588 .func => |func| {
3589 if (self.bin_file.cast(link.File.Elf)) |elf_file| {
3590 const sym_index = try elf_file.zigObjectPtr().?.getOrCreateMetadataForDecl(elf_file, func.owner_decl);
4263 .func => |func_val| {
4264 if (func.bin_file.cast(link.File.Elf)) |elf_file| {
4265 const sym_index = try elf_file.zigObjectPtr().?.getOrCreateMetadataForDecl(elf_file, func_val.owner_decl);
35914266 const sym = elf_file.symbol(sym_index);
35924267
3593 _ = try sym.getOrCreateZigGotEntry(sym_index, elf_file);
3594 const got_addr = sym.zigGotAddress(elf_file);
3595 try self.genSetReg(Type.usize, .ra, .{ .memory = @intCast(got_addr) });
3596
3597 _ = try self.addInst(.{
3598 .tag = .jalr,
3599 .ops = .rri,
3600 .data = .{ .i_type = .{
3601 .rd = .ra,
3602 .rs1 = .ra,
3603 .imm12 = Immediate.s(0),
4268 if (func.mod.pic) {
4269 return func.fail("TODO: genCall pic", .{});
4270 } else {
4271 try func.genSetReg(Type.usize, .ra, .{ .load_symbol = .{ .sym = sym.esym_index } });
4272 _ = try func.addInst(.{
4273 .tag = .jalr,
4274 .ops = .rri,
4275 .data = .{ .i_type = .{
4276 .rd = .ra,
4277 .rs1 = .ra,
4278 .imm12 = Immediate.s(0),
4279 } },
4280 });
4281 }
4282 } else unreachable; // not a valid riscv64 format
4283 },
4284 .extern_func => |extern_func| {
4285 const owner_decl = zcu.declPtr(extern_func.decl);
4286 const lib_name = extern_func.lib_name.toSlice(&zcu.intern_pool);
4287 const decl_name = owner_decl.name.toSlice(&zcu.intern_pool);
4288 const atom_index = try func.symbolIndex();
4289
4290 if (func.bin_file.cast(link.File.Elf)) |elf_file| {
4291 _ = try func.addInst(.{
4292 .tag = .pseudo,
4293 .ops = .pseudo_extern_fn_reloc,
4294 .data = .{ .reloc = .{
4295 .atom_index = atom_index,
4296 .sym_index = try elf_file.getGlobalSymbol(decl_name, lib_name),
36044297 } },
36054298 });
3606 } else unreachable;
4299 } else unreachable; // not a valid riscv64 format
36074300 },
3608 .extern_func => return self.fail("TODO: extern func calls", .{}),
3609 else => return self.fail("TODO implement calling bitcasted functions", .{}),
4301 else => return func.fail("TODO implement calling bitcasted functions", .{}),
36104302 }
36114303 } else {
3612 assert(self.typeOf(callee).zigTypeTag(zcu) == .Pointer);
3613 const addr_reg, const addr_lock = try self.allocReg();
3614 defer self.register_manager.unlockReg(addr_lock);
3615 try self.genSetReg(Type.usize, addr_reg, .{ .air_ref = callee });
3616 _ = try self.addInst(.{
4304 assert(func.typeOf(callee).zigTypeTag(zcu) == .Pointer);
4305 const addr_reg, const addr_lock = try func.allocReg(.int);
4306 defer func.register_manager.unlockReg(addr_lock);
4307 try func.genSetReg(Type.usize, addr_reg, .{ .air_ref = callee });
4308
4309 _ = try func.addInst(.{
36174310 .tag = .jalr,
36184311 .ops = .rri,
36194312 .data = .{ .i_type = .{
......@@ -3624,15 +4317,15 @@ fn genCall(
36244317 });
36254318 }
36264319 },
3627 .lib => return self.fail("TODO: lib func calls", .{}),
4320 .lib => return func.fail("TODO: lib func calls", .{}),
36284321 }
36294322
36304323 return call_info.return_value.short;
36314324}
36324325
3633fn airRet(self: *Self, inst: Air.Inst.Index, safety: bool) !void {
3634 const zcu = self.bin_file.comp.module.?;
3635 const un_op = self.air.instructions.items(.data)[@intFromEnum(inst)].un_op;
4326fn airRet(func: *Func, inst: Air.Inst.Index, safety: bool) !void {
4327 const zcu = func.bin_file.comp.module.?;
4328 const un_op = func.air.instructions.items(.data)[@intFromEnum(inst)].un_op;
36364329
36374330 if (safety) {
36384331 // safe
......@@ -3640,123 +4333,138 @@ fn airRet(self: *Self, inst: Air.Inst.Index, safety: bool) !void {
36404333 // not safe
36414334 }
36424335
3643 const ret_ty = self.fn_type.fnReturnType(zcu);
3644 switch (self.ret_mcv.short) {
4336 const ret_ty = func.fn_type.fnReturnType(zcu);
4337 switch (func.ret_mcv.short) {
36454338 .none => {},
36464339 .register,
36474340 .register_pair,
3648 => try self.genCopy(ret_ty, self.ret_mcv.short, .{ .air_ref = un_op }),
4341 => try func.genCopy(ret_ty, func.ret_mcv.short, .{ .air_ref = un_op }),
36494342 .indirect => |reg_off| {
3650 try self.register_manager.getReg(reg_off.reg, null);
3651 const lock = self.register_manager.lockRegAssumeUnused(reg_off.reg);
3652 defer self.register_manager.unlockReg(lock);
3653
3654 try self.genSetReg(Type.usize, reg_off.reg, self.ret_mcv.long);
3655 try self.genCopy(
4343 try func.register_manager.getReg(reg_off.reg, null);
4344 const lock = func.register_manager.lockRegAssumeUnused(reg_off.reg);
4345 defer func.register_manager.unlockReg(lock);
4346
4347 try func.genSetReg(Type.usize, reg_off.reg, func.ret_mcv.long);
4348 try func.genSetMem(
4349 .{ .reg = reg_off.reg },
4350 reg_off.off,
36564351 ret_ty,
3657 .{ .register_offset = reg_off },
36584352 .{ .air_ref = un_op },
36594353 );
36604354 },
36614355 else => unreachable,
36624356 }
36634357
3664 self.ret_mcv.liveOut(self, inst);
3665 try self.finishAir(inst, .unreach, .{ un_op, .none, .none });
4358 func.ret_mcv.liveOut(func, inst);
4359 try func.finishAir(inst, .unreach, .{ un_op, .none, .none });
36664360
36674361 // Just add space for an instruction, reloced this later
3668 const index = try self.addInst(.{
4362 const index = try func.addInst(.{
36694363 .tag = .pseudo,
36704364 .ops = .pseudo_j,
36714365 .data = .{ .inst = undefined },
36724366 });
36734367
3674 try self.exitlude_jump_relocs.append(self.gpa, index);
4368 try func.exitlude_jump_relocs.append(func.gpa, index);
36754369}
36764370
3677fn airRetLoad(self: *Self, inst: Air.Inst.Index) !void {
3678 const un_op = self.air.instructions.items(.data)[@intFromEnum(inst)].un_op;
3679 const ptr = try self.resolveInst(un_op);
4371fn airRetLoad(func: *Func, inst: Air.Inst.Index) !void {
4372 const un_op = func.air.instructions.items(.data)[@intFromEnum(inst)].un_op;
4373 const ptr = try func.resolveInst(un_op);
36804374
3681 const ptr_ty = self.typeOf(un_op);
3682 switch (self.ret_mcv.short) {
4375 const ptr_ty = func.typeOf(un_op);
4376 switch (func.ret_mcv.short) {
36834377 .none => {},
3684 .register, .register_pair => try self.load(self.ret_mcv.short, ptr, ptr_ty),
3685 .indirect => |reg_off| try self.genSetReg(ptr_ty, reg_off.reg, ptr),
4378 .register, .register_pair => try func.load(func.ret_mcv.short, ptr, ptr_ty),
4379 .indirect => |reg_off| try func.genSetReg(ptr_ty, reg_off.reg, ptr),
36864380 else => unreachable,
36874381 }
3688 self.ret_mcv.liveOut(self, inst);
3689 try self.finishAir(inst, .unreach, .{ un_op, .none, .none });
4382 func.ret_mcv.liveOut(func, inst);
4383 try func.finishAir(inst, .unreach, .{ un_op, .none, .none });
36904384
36914385 // Just add space for an instruction, reloced this later
3692 const index = try self.addInst(.{
4386 const index = try func.addInst(.{
36934387 .tag = .pseudo,
36944388 .ops = .pseudo_j,
36954389 .data = .{ .inst = undefined },
36964390 });
36974391
3698 try self.exitlude_jump_relocs.append(self.gpa, index);
3699}
3700
3701fn airCmp(self: *Self, inst: Air.Inst.Index) !void {
3702 const tag = self.air.instructions.items(.tag)[@intFromEnum(inst)];
3703 const bin_op = self.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
3704 const zcu = self.bin_file.comp.module.?;
3705
3706 const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else result: {
3707 const lhs = try self.resolveInst(bin_op.lhs);
3708 const rhs = try self.resolveInst(bin_op.rhs);
3709 const lhs_ty = self.typeOf(bin_op.lhs);
3710
3711 const int_ty = switch (lhs_ty.zigTypeTag(zcu)) {
3712 .Vector => unreachable, // Handled by cmp_vector.
3713 .Enum => lhs_ty.intTagType(zcu),
3714 .Int => lhs_ty,
3715 .Bool => Type.u1,
3716 .Pointer => Type.usize,
3717 .ErrorSet => Type.u16,
3718 .Optional => blk: {
3719 const payload_ty = lhs_ty.optionalChild(zcu);
3720 if (!payload_ty.hasRuntimeBitsIgnoreComptime(zcu)) {
3721 break :blk Type.u1;
3722 } else if (lhs_ty.isPtrLikeOptional(zcu)) {
3723 break :blk Type.usize;
4392 try func.exitlude_jump_relocs.append(func.gpa, index);
4393}
4394
4395fn airCmp(func: *Func, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void {
4396 const bin_op = func.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
4397 const zcu = func.bin_file.comp.module.?;
4398
4399 const result: MCValue = if (func.liveness.isUnused(inst)) .unreach else result: {
4400 const lhs_ty = func.typeOf(bin_op.lhs);
4401
4402 switch (lhs_ty.zigTypeTag(zcu)) {
4403 .Int,
4404 .Enum,
4405 .Bool,
4406 .Pointer,
4407 .ErrorSet,
4408 .Optional,
4409 => {
4410 const int_ty = switch (lhs_ty.zigTypeTag(zcu)) {
4411 .Enum => lhs_ty.intTagType(zcu),
4412 .Int => lhs_ty,
4413 .Bool => Type.u1,
4414 .Pointer => Type.usize,
4415 .ErrorSet => Type.anyerror,
4416 .Optional => blk: {
4417 const payload_ty = lhs_ty.optionalChild(zcu);
4418 if (!payload_ty.hasRuntimeBitsIgnoreComptime(zcu)) {
4419 break :blk Type.u1;
4420 } else if (lhs_ty.isPtrLikeOptional(zcu)) {
4421 break :blk Type.usize;
4422 } else {
4423 return func.fail("TODO riscv cmp non-pointer optionals", .{});
4424 }
4425 },
4426 else => unreachable,
4427 };
4428
4429 const int_info = int_ty.intInfo(zcu);
4430 if (int_info.bits <= 64) {
4431 break :result try func.binOp(inst, tag, bin_op.lhs, bin_op.rhs);
37244432 } else {
3725 return self.fail("TODO riscv cmp non-pointer optionals", .{});
4433 return func.fail("TODO riscv cmp for ints > 64 bits", .{});
4434 }
4435 },
4436 .Float => {
4437 const float_bits = lhs_ty.floatBits(func.target.*);
4438 const float_reg_size: u32 = if (func.hasFeature(.d)) 64 else 32;
4439 if (float_bits > float_reg_size) {
4440 return func.fail("TODO: airCmp float > 64/32 bits", .{});
37264441 }
4442 break :result try func.binOp(inst, tag, bin_op.lhs, bin_op.rhs);
37274443 },
3728 .Float => return self.fail("TODO riscv cmp floats", .{}),
37294444 else => unreachable,
3730 };
3731
3732 const int_info = int_ty.intInfo(zcu);
3733 if (int_info.bits <= 64) {
3734 break :result try self.binOp(tag, lhs, int_ty, rhs, int_ty);
3735 } else {
3736 return self.fail("TODO riscv cmp for ints > 64 bits", .{});
37374445 }
37384446 };
37394447
3740 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
4448 return func.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
37414449}
37424450
3743fn airCmpVector(self: *Self, inst: Air.Inst.Index) !void {
4451fn airCmpVector(func: *Func, inst: Air.Inst.Index) !void {
37444452 _ = inst;
3745 return self.fail("TODO implement airCmpVector for {}", .{self.target.cpu.arch});
4453 return func.fail("TODO implement airCmpVector for {}", .{func.target.cpu.arch});
37464454}
37474455
3748fn airCmpLtErrorsLen(self: *Self, inst: Air.Inst.Index) !void {
3749 const un_op = self.air.instructions.items(.data)[@intFromEnum(inst)].un_op;
3750 const operand = try self.resolveInst(un_op);
4456fn airCmpLtErrorsLen(func: *Func, inst: Air.Inst.Index) !void {
4457 const un_op = func.air.instructions.items(.data)[@intFromEnum(inst)].un_op;
4458 const operand = try func.resolveInst(un_op);
37514459 _ = operand;
3752 const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else return self.fail("TODO implement airCmpLtErrorsLen for {}", .{self.target.cpu.arch});
3753 return self.finishAir(inst, result, .{ un_op, .none, .none });
4460 const result: MCValue = if (func.liveness.isUnused(inst)) .unreach else return func.fail("TODO implement airCmpLtErrorsLen for {}", .{func.target.cpu.arch});
4461 return func.finishAir(inst, result, .{ un_op, .none, .none });
37544462}
37554463
3756fn airDbgStmt(self: *Self, inst: Air.Inst.Index) !void {
3757 const dbg_stmt = self.air.instructions.items(.data)[@intFromEnum(inst)].dbg_stmt;
4464fn airDbgStmt(func: *Func, inst: Air.Inst.Index) !void {
4465 const dbg_stmt = func.air.instructions.items(.data)[@intFromEnum(inst)].dbg_stmt;
37584466
3759 _ = try self.addInst(.{
4467 _ = try func.addInst(.{
37604468 .tag = .pseudo,
37614469 .ops = .pseudo_dbg_line_column,
37624470 .data = .{ .pseudo_dbg_line_column = .{
......@@ -3765,44 +4473,44 @@ fn airDbgStmt(self: *Self, inst: Air.Inst.Index) !void {
37654473 } },
37664474 });
37674475
3768 return self.finishAirBookkeeping();
4476 return func.finishAirBookkeeping();
37694477}
37704478
3771fn airDbgInlineBlock(self: *Self, inst: Air.Inst.Index) !void {
3772 const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
3773 const extra = self.air.extraData(Air.DbgInlineBlock, ty_pl.payload);
3774 try self.lowerBlock(inst, @ptrCast(self.air.extra[extra.end..][0..extra.data.body_len]));
4479fn airDbgInlineBlock(func: *Func, inst: Air.Inst.Index) !void {
4480 const ty_pl = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
4481 const extra = func.air.extraData(Air.DbgInlineBlock, ty_pl.payload);
4482 try func.lowerBlock(inst, @ptrCast(func.air.extra[extra.end..][0..extra.data.body_len]));
37754483}
37764484
3777fn airDbgVar(self: *Self, inst: Air.Inst.Index) !void {
3778 const pl_op = self.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;
4485fn airDbgVar(func: *Func, inst: Air.Inst.Index) !void {
4486 const pl_op = func.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;
37794487 const operand = pl_op.operand;
3780 const ty = self.typeOf(operand);
3781 const mcv = try self.resolveInst(operand);
4488 const ty = func.typeOf(operand);
4489 const mcv = try func.resolveInst(operand);
37824490
3783 const name = self.air.nullTerminatedString(pl_op.payload);
4491 const name = func.air.nullTerminatedString(pl_op.payload);
37844492
3785 const tag = self.air.instructions.items(.tag)[@intFromEnum(inst)];
3786 try self.genVarDbgInfo(tag, ty, mcv, name);
4493 const tag = func.air.instructions.items(.tag)[@intFromEnum(inst)];
4494 try func.genVarDbgInfo(tag, ty, mcv, name);
37874495
3788 return self.finishAir(inst, .unreach, .{ operand, .none, .none });
4496 return func.finishAir(inst, .unreach, .{ operand, .none, .none });
37894497}
37904498
37914499fn genVarDbgInfo(
3792 self: Self,
4500 func: Func,
37934501 tag: Air.Inst.Tag,
37944502 ty: Type,
37954503 mcv: MCValue,
37964504 name: [:0]const u8,
37974505) !void {
3798 const zcu = self.bin_file.comp.module.?;
4506 const zcu = func.bin_file.comp.module.?;
37994507 const is_ptr = switch (tag) {
38004508 .dbg_var_ptr => true,
38014509 .dbg_var_val => false,
38024510 else => unreachable,
38034511 };
38044512
3805 switch (self.debug_output) {
4513 switch (func.debug_output) {
38064514 .dwarf => |dw| {
38074515 const loc: link.File.Dwarf.DeclState.DbgInfoLoc = switch (mcv) {
38084516 .register => |reg| .{ .register = reg.dwarfLocOp() },
......@@ -3819,47 +4527,47 @@ fn genVarDbgInfo(
38194527 break :blk .nop;
38204528 },
38214529 };
3822 try dw.genVarDbgInfo(name, ty, zcu.funcOwnerDeclIndex(self.func_index), is_ptr, loc);
4530 try dw.genVarDbgInfo(name, ty, zcu.funcOwnerDeclIndex(func.func_index), is_ptr, loc);
38234531 },
38244532 .plan9 => {},
38254533 .none => {},
38264534 }
38274535}
38284536
3829fn airCondBr(self: *Self, inst: Air.Inst.Index) !void {
3830 const pl_op = self.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;
3831 const cond = try self.resolveInst(pl_op.operand);
3832 const cond_ty = self.typeOf(pl_op.operand);
3833 const extra = self.air.extraData(Air.CondBr, pl_op.payload);
3834 const then_body: []const Air.Inst.Index = @ptrCast(self.air.extra[extra.end..][0..extra.data.then_body_len]);
3835 const else_body: []const Air.Inst.Index = @ptrCast(self.air.extra[extra.end + then_body.len ..][0..extra.data.else_body_len]);
3836 const liveness_cond_br = self.liveness.getCondBr(inst);
4537fn airCondBr(func: *Func, inst: Air.Inst.Index) !void {
4538 const pl_op = func.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;
4539 const cond = try func.resolveInst(pl_op.operand);
4540 const cond_ty = func.typeOf(pl_op.operand);
4541 const extra = func.air.extraData(Air.CondBr, pl_op.payload);
4542 const then_body: []const Air.Inst.Index = @ptrCast(func.air.extra[extra.end..][0..extra.data.then_body_len]);
4543 const else_body: []const Air.Inst.Index = @ptrCast(func.air.extra[extra.end + then_body.len ..][0..extra.data.else_body_len]);
4544 const liveness_cond_br = func.liveness.getCondBr(inst);
38374545
38384546 // If the condition dies here in this condbr instruction, process
38394547 // that death now instead of later as this has an effect on
38404548 // whether it needs to be spilled in the branches
3841 if (self.liveness.operandDies(inst, 0)) {
3842 if (pl_op.operand.toIndex()) |op_inst| try self.processDeath(op_inst);
4549 if (func.liveness.operandDies(inst, 0)) {
4550 if (pl_op.operand.toIndex()) |op_inst| try func.processDeath(op_inst);
38434551 }
38444552
3845 self.scope_generation += 1;
3846 const state = try self.saveState();
3847 const reloc = try self.condBr(cond_ty, cond);
4553 func.scope_generation += 1;
4554 const state = try func.saveState();
4555 const reloc = try func.condBr(cond_ty, cond);
38484556
3849 for (liveness_cond_br.then_deaths) |death| try self.processDeath(death);
3850 try self.genBody(then_body);
3851 try self.restoreState(state, &.{}, .{
4557 for (liveness_cond_br.then_deaths) |death| try func.processDeath(death);
4558 try func.genBody(then_body);
4559 try func.restoreState(state, &.{}, .{
38524560 .emit_instructions = false,
38534561 .update_tracking = true,
38544562 .resurrect = true,
38554563 .close_scope = true,
38564564 });
38574565
3858 self.performReloc(reloc);
4566 func.performReloc(reloc);
38594567
3860 for (liveness_cond_br.else_deaths) |death| try self.processDeath(death);
3861 try self.genBody(else_body);
3862 try self.restoreState(state, &.{}, .{
4568 for (liveness_cond_br.else_deaths) |death| try func.processDeath(death);
4569 try func.genBody(else_body);
4570 try func.restoreState(state, &.{}, .{
38634571 .emit_instructions = false,
38644572 .update_tracking = true,
38654573 .resurrect = true,
......@@ -3867,13 +4575,13 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void {
38674575 });
38684576
38694577 // We already took care of pl_op.operand earlier, so there's nothing left to do.
3870 self.finishAirBookkeeping();
4578 func.finishAirBookkeeping();
38714579}
38724580
3873fn condBr(self: *Self, cond_ty: Type, condition: MCValue) !Mir.Inst.Index {
3874 const cond_reg = try self.copyToTmpRegister(cond_ty, condition);
4581fn condBr(func: *Func, cond_ty: Type, condition: MCValue) !Mir.Inst.Index {
4582 const cond_reg = try func.copyToTmpRegister(cond_ty, condition);
38754583
3876 return try self.addInst(.{
4584 return try func.addInst(.{
38774585 .tag = .beq,
38784586 .ops = .rr_inst,
38794587 .data = .{
......@@ -3886,168 +4594,249 @@ fn condBr(self: *Self, cond_ty: Type, condition: MCValue) !Mir.Inst.Index {
38864594 });
38874595}
38884596
3889fn airIsNull(self: *Self, inst: Air.Inst.Index) !void {
3890 const un_op = self.air.instructions.items(.data)[@intFromEnum(inst)].un_op;
3891 const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else result: {
3892 const operand = try self.resolveInst(un_op);
3893 break :result try self.isNull(operand);
3894 };
3895 return self.finishAir(inst, result, .{ un_op, .none, .none });
3896}
4597fn isNull(func: *Func, inst: Air.Inst.Index, opt_ty: Type, opt_mcv: MCValue) !MCValue {
4598 const zcu = func.bin_file.comp.module.?;
4599 const pl_ty = opt_ty.optionalChild(zcu);
38974600
3898fn airIsNullPtr(self: *Self, inst: Air.Inst.Index) !void {
3899 const un_op = self.air.instructions.items(.data)[@intFromEnum(inst)].un_op;
3900 const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else result: {
3901 const operand_ptr = try self.resolveInst(un_op);
3902 const operand: MCValue = blk: {
3903 if (self.reuseOperand(inst, un_op, 0, operand_ptr)) {
3904 // The MCValue that holds the pointer can be re-used as the value.
3905 break :blk operand_ptr;
3906 } else {
3907 break :blk try self.allocRegOrMem(inst, true);
4601 const some_info: struct { off: i32, ty: Type } = if (opt_ty.optionalReprIsPayload(zcu))
4602 .{ .off = 0, .ty = if (pl_ty.isSlice(zcu)) pl_ty.slicePtrFieldType(zcu) else pl_ty }
4603 else
4604 .{ .off = @intCast(pl_ty.abiSize(zcu)), .ty = Type.bool };
4605
4606 const return_mcv = try func.allocRegOrMem(func.typeOfIndex(inst), inst, true);
4607 assert(return_mcv == .register); // should not be larger 8 bytes
4608 const return_reg = return_mcv.register;
4609
4610 switch (opt_mcv) {
4611 .none,
4612 .unreach,
4613 .dead,
4614 .undef,
4615 .immediate,
4616 .register_pair,
4617 .register_offset,
4618 .lea_frame,
4619 .lea_symbol,
4620 .reserved_frame,
4621 .air_ref,
4622 => return func.fail("TODO: hmm {}", .{opt_mcv}),
4623
4624 .register => |opt_reg| {
4625 if (some_info.off == 0) {
4626 _ = try func.addInst(.{
4627 .tag = .pseudo,
4628 .ops = .pseudo_compare,
4629 .data = .{
4630 .compare = .{
4631 .op = .eq,
4632 .rd = return_reg,
4633 .rs1 = opt_reg,
4634 .rs2 = try func.copyToTmpRegister(
4635 some_info.ty,
4636 .{ .immediate = 0 },
4637 ),
4638 .ty = Type.bool,
4639 },
4640 },
4641 });
4642 return return_mcv;
39084643 }
3909 };
3910 try self.load(operand, operand_ptr, self.typeOf(un_op));
3911 break :result try self.isNull(operand);
3912 };
3913 return self.finishAir(inst, result, .{ un_op, .none, .none });
4644 assert(some_info.ty.ip_index == .bool_type);
4645 const opt_abi_size: u32 = @intCast(opt_ty.abiSize(zcu));
4646 _ = opt_abi_size;
4647 return func.fail("TODO: isNull some_info.off != 0 register", .{});
4648 },
4649
4650 .load_frame => {
4651 const opt_reg = try func.copyToTmpRegister(
4652 some_info.ty,
4653 opt_mcv.address().offset(some_info.off).deref(),
4654 );
4655 const opt_reg_lock = func.register_manager.lockRegAssumeUnused(opt_reg);
4656 defer func.register_manager.unlockReg(opt_reg_lock);
4657
4658 _ = try func.addInst(.{
4659 .tag = .pseudo,
4660 .ops = .pseudo_compare,
4661 .data = .{
4662 .compare = .{
4663 .op = .eq,
4664 .rd = return_reg,
4665 .rs1 = opt_reg,
4666 .rs2 = try func.copyToTmpRegister(
4667 some_info.ty,
4668 .{ .immediate = 0 },
4669 ),
4670 .ty = Type.bool,
4671 },
4672 },
4673 });
4674 return return_mcv;
4675 },
4676
4677 else => return func.fail("TODO: isNull {}", .{opt_mcv}),
4678 }
4679}
4680
4681fn airIsNull(func: *Func, inst: Air.Inst.Index) !void {
4682 const un_op = func.air.instructions.items(.data)[@intFromEnum(inst)].un_op;
4683 const operand = try func.resolveInst(un_op);
4684 const ty = func.typeOf(un_op);
4685 const result = try func.isNull(inst, ty, operand);
4686 return func.finishAir(inst, result, .{ un_op, .none, .none });
39144687}
39154688
3916fn isNull(self: *Self, operand: MCValue) !MCValue {
4689fn airIsNullPtr(func: *Func, inst: Air.Inst.Index) !void {
4690 const un_op = func.air.instructions.items(.data)[@intFromEnum(inst)].un_op;
4691 const operand = try func.resolveInst(un_op);
39174692 _ = operand;
3918 // Here you can specialize this instruction if it makes sense to, otherwise the default
3919 // will call isNonNull and invert the result.
3920 return self.fail("TODO call isNonNull and invert the result", .{});
4693 const ty = func.typeOf(un_op);
4694 _ = ty;
4695
4696 if (true) return func.fail("TODO: airIsNullPtr", .{});
4697
4698 return func.finishAir(inst, .unreach, .{ un_op, .none, .none });
39214699}
39224700
3923fn airIsNonNull(self: *Self, inst: Air.Inst.Index) !void {
3924 const un_op = self.air.instructions.items(.data)[@intFromEnum(inst)].un_op;
3925 const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else result: {
3926 const operand = try self.resolveInst(un_op);
3927 break :result try self.isNonNull(operand);
3928 };
3929 return self.finishAir(inst, result, .{ un_op, .none, .none });
4701fn airIsNonNull(func: *Func, inst: Air.Inst.Index) !void {
4702 const un_op = func.air.instructions.items(.data)[@intFromEnum(inst)].un_op;
4703 const operand = try func.resolveInst(un_op);
4704 const ty = func.typeOf(un_op);
4705 const result = try func.isNull(inst, ty, operand);
4706 assert(result == .register);
4707
4708 _ = try func.addInst(.{
4709 .tag = .pseudo,
4710 .ops = .pseudo_not,
4711 .data = .{
4712 .rr = .{
4713 .rd = result.register,
4714 .rs = result.register,
4715 },
4716 },
4717 });
4718
4719 return func.finishAir(inst, result, .{ un_op, .none, .none });
39304720}
39314721
3932fn isNonNull(self: *Self, operand: MCValue) !MCValue {
4722fn airIsNonNullPtr(func: *Func, inst: Air.Inst.Index) !void {
4723 const un_op = func.air.instructions.items(.data)[@intFromEnum(inst)].un_op;
4724 const operand = try func.resolveInst(un_op);
39334725 _ = operand;
3934 // Here you can specialize this instruction if it makes sense to, otherwise the default
3935 // will call isNull and invert the result.
3936 return self.fail("TODO call isNull and invert the result", .{});
3937}
4726 const ty = func.typeOf(un_op);
4727 _ = ty;
39384728
3939fn airIsNonNullPtr(self: *Self, inst: Air.Inst.Index) !void {
3940 const un_op = self.air.instructions.items(.data)[@intFromEnum(inst)].un_op;
3941 const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else result: {
3942 const operand_ptr = try self.resolveInst(un_op);
3943 const operand: MCValue = blk: {
3944 if (self.reuseOperand(inst, un_op, 0, operand_ptr)) {
3945 // The MCValue that holds the pointer can be re-used as the value.
3946 break :blk operand_ptr;
3947 } else {
3948 break :blk try self.allocRegOrMem(inst, true);
3949 }
3950 };
3951 try self.load(operand, operand_ptr, self.typeOf(un_op));
3952 break :result try self.isNonNull(operand);
3953 };
3954 return self.finishAir(inst, result, .{ un_op, .none, .none });
4729 if (true) return func.fail("TODO: airIsNonNullPtr", .{});
4730
4731 return func.finishAir(inst, .unreach, .{ un_op, .none, .none });
39554732}
39564733
3957fn airIsErr(self: *Self, inst: Air.Inst.Index) !void {
3958 const un_op = self.air.instructions.items(.data)[@intFromEnum(inst)].un_op;
3959 const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else result: {
3960 const operand = try self.resolveInst(un_op);
3961 const operand_ty = self.typeOf(un_op);
3962 break :result try self.isErr(inst, operand_ty, operand);
4734fn airIsErr(func: *Func, inst: Air.Inst.Index) !void {
4735 const un_op = func.air.instructions.items(.data)[@intFromEnum(inst)].un_op;
4736 const result: MCValue = if (func.liveness.isUnused(inst)) .unreach else result: {
4737 const operand = try func.resolveInst(un_op);
4738 const operand_ty = func.typeOf(un_op);
4739 break :result try func.isErr(inst, operand_ty, operand);
39634740 };
3964 return self.finishAir(inst, result, .{ un_op, .none, .none });
4741 return func.finishAir(inst, result, .{ un_op, .none, .none });
39654742}
39664743
3967fn airIsErrPtr(self: *Self, inst: Air.Inst.Index) !void {
3968 const zcu = self.bin_file.comp.module.?;
3969 const un_op = self.air.instructions.items(.data)[@intFromEnum(inst)].un_op;
3970 const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else result: {
3971 const operand_ptr = try self.resolveInst(un_op);
4744fn airIsErrPtr(func: *Func, inst: Air.Inst.Index) !void {
4745 const zcu = func.bin_file.comp.module.?;
4746 const un_op = func.air.instructions.items(.data)[@intFromEnum(inst)].un_op;
4747 const result: MCValue = if (func.liveness.isUnused(inst)) .unreach else result: {
4748 const operand_ptr = try func.resolveInst(un_op);
39724749 const operand: MCValue = blk: {
3973 if (self.reuseOperand(inst, un_op, 0, operand_ptr)) {
4750 if (func.reuseOperand(inst, un_op, 0, operand_ptr)) {
39744751 // The MCValue that holds the pointer can be re-used as the value.
39754752 break :blk operand_ptr;
39764753 } else {
3977 break :blk try self.allocRegOrMem(inst, true);
4754 break :blk try func.allocRegOrMem(func.typeOfIndex(inst), inst, true);
39784755 }
39794756 };
3980 try self.load(operand, operand_ptr, self.typeOf(un_op));
3981 const operand_ptr_ty = self.typeOf(un_op);
4757 try func.load(operand, operand_ptr, func.typeOf(un_op));
4758 const operand_ptr_ty = func.typeOf(un_op);
39824759 const operand_ty = operand_ptr_ty.childType(zcu);
39834760
3984 break :result try self.isErr(inst, operand_ty, operand);
4761 break :result try func.isErr(inst, operand_ty, operand);
39854762 };
3986 return self.finishAir(inst, result, .{ un_op, .none, .none });
4763 return func.finishAir(inst, result, .{ un_op, .none, .none });
39874764}
39884765
39894766/// Generates a compare instruction which will indicate if `eu_mcv` is an error.
39904767///
39914768/// Result is in the return register.
3992fn isErr(self: *Self, maybe_inst: ?Air.Inst.Index, eu_ty: Type, eu_mcv: MCValue) !MCValue {
3993 const zcu = self.bin_file.comp.module.?;
4769fn isErr(func: *Func, maybe_inst: ?Air.Inst.Index, eu_ty: Type, eu_mcv: MCValue) !MCValue {
4770 _ = maybe_inst;
4771 const zcu = func.bin_file.comp.module.?;
39944772 const err_ty = eu_ty.errorUnionSet(zcu);
39954773 if (err_ty.errorSetIsEmpty(zcu)) return MCValue{ .immediate = 0 }; // always false
4774 const err_off: u31 = @intCast(errUnionErrorOffset(eu_ty.errorUnionPayload(zcu), zcu));
39964775
3997 _ = maybe_inst;
3998
3999 const err_off = errUnionErrorOffset(eu_ty.errorUnionPayload(zcu), zcu);
4776 const return_reg, const return_lock = try func.allocReg(.int);
4777 defer func.register_manager.unlockReg(return_lock);
40004778
40014779 switch (eu_mcv) {
40024780 .register => |reg| {
4003 const eu_lock = self.register_manager.lockReg(reg);
4004 defer if (eu_lock) |lock| self.register_manager.unlockReg(lock);
4005
4006 const return_reg = try self.copyToTmpRegister(eu_ty, eu_mcv);
4007 const return_lock = self.register_manager.lockRegAssumeUnused(return_reg);
4008 defer self.register_manager.unlockReg(return_lock);
4781 const eu_lock = func.register_manager.lockReg(reg);
4782 defer if (eu_lock) |lock| func.register_manager.unlockReg(lock);
40094783
4010 var return_mcv: MCValue = .{ .register = return_reg };
4784 try func.genCopy(eu_ty, .{ .register = return_reg }, eu_mcv);
40114785
40124786 if (err_off > 0) {
4013 return_mcv = try self.binOp(
4787 try func.genBinOp(
40144788 .shr,
4015 return_mcv,
4789 .{ .register = return_reg },
40164790 eu_ty,
40174791 .{ .immediate = @as(u6, @intCast(err_off * 8)) },
40184792 Type.u8,
4793 return_reg,
40194794 );
40204795 }
40214796
4022 return_mcv = try self.binOp(
4797 try func.genBinOp(
40234798 .cmp_neq,
4024 return_mcv,
4025 Type.u16,
4799 .{ .register = return_reg },
4800 Type.anyerror,
40264801 .{ .immediate = 0 },
4027 Type.u16,
4802 Type.u8,
4803 return_reg,
40284804 );
4029
4030 return return_mcv;
40314805 },
4032 else => return self.fail("TODO implement isErr for {}", .{eu_mcv}),
4806 .load_frame => |frame_addr| {
4807 try func.genBinOp(
4808 .cmp_neq,
4809 .{ .load_frame = .{
4810 .index = frame_addr.index,
4811 .off = frame_addr.off + err_off,
4812 } },
4813 Type.anyerror,
4814 .{ .immediate = 0 },
4815 Type.anyerror,
4816 return_reg,
4817 );
4818 },
4819 else => return func.fail("TODO implement isErr for {}", .{eu_mcv}),
40334820 }
4821
4822 return .{ .register = return_reg };
40344823}
40354824
4036fn airIsNonErr(self: *Self, inst: Air.Inst.Index) !void {
4037 const un_op = self.air.instructions.items(.data)[@intFromEnum(inst)].un_op;
4038 const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else result: {
4039 const operand = try self.resolveInst(un_op);
4040 const ty = self.typeOf(un_op);
4041 break :result try self.isNonErr(inst, ty, operand);
4825fn airIsNonErr(func: *Func, inst: Air.Inst.Index) !void {
4826 const un_op = func.air.instructions.items(.data)[@intFromEnum(inst)].un_op;
4827 const result: MCValue = if (func.liveness.isUnused(inst)) .unreach else result: {
4828 const operand = try func.resolveInst(un_op);
4829 const ty = func.typeOf(un_op);
4830 break :result try func.isNonErr(inst, ty, operand);
40424831 };
4043 return self.finishAir(inst, result, .{ un_op, .none, .none });
4832 return func.finishAir(inst, result, .{ un_op, .none, .none });
40444833}
40454834
4046fn isNonErr(self: *Self, inst: Air.Inst.Index, eu_ty: Type, eu_mcv: MCValue) !MCValue {
4047 const is_err_res = try self.isErr(inst, eu_ty, eu_mcv);
4835fn isNonErr(func: *Func, inst: Air.Inst.Index, eu_ty: Type, eu_mcv: MCValue) !MCValue {
4836 const is_err_res = try func.isErr(inst, eu_ty, eu_mcv);
40484837 switch (is_err_res) {
40494838 .register => |reg| {
4050 _ = try self.addInst(.{
4839 _ = try func.addInst(.{
40514840 .tag = .pseudo,
40524841 .ops = .pseudo_not,
40534842 .data = .{
......@@ -4068,53 +4857,53 @@ fn isNonErr(self: *Self, inst: Air.Inst.Index, eu_ty: Type, eu_mcv: MCValue) !MC
40684857 }
40694858}
40704859
4071fn airIsNonErrPtr(self: *Self, inst: Air.Inst.Index) !void {
4072 const zcu = self.bin_file.comp.module.?;
4073 const un_op = self.air.instructions.items(.data)[@intFromEnum(inst)].un_op;
4074 const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else result: {
4075 const operand_ptr = try self.resolveInst(un_op);
4860fn airIsNonErrPtr(func: *Func, inst: Air.Inst.Index) !void {
4861 const zcu = func.bin_file.comp.module.?;
4862 const un_op = func.air.instructions.items(.data)[@intFromEnum(inst)].un_op;
4863 const result: MCValue = if (func.liveness.isUnused(inst)) .unreach else result: {
4864 const operand_ptr = try func.resolveInst(un_op);
40764865 const operand: MCValue = blk: {
4077 if (self.reuseOperand(inst, un_op, 0, operand_ptr)) {
4866 if (func.reuseOperand(inst, un_op, 0, operand_ptr)) {
40784867 // The MCValue that holds the pointer can be re-used as the value.
40794868 break :blk operand_ptr;
40804869 } else {
4081 break :blk try self.allocRegOrMem(inst, true);
4870 break :blk try func.allocRegOrMem(func.typeOfIndex(inst), inst, true);
40824871 }
40834872 };
4084 const operand_ptr_ty = self.typeOf(un_op);
4873 const operand_ptr_ty = func.typeOf(un_op);
40854874 const operand_ty = operand_ptr_ty.childType(zcu);
40864875
4087 try self.load(operand, operand_ptr, self.typeOf(un_op));
4088 break :result try self.isNonErr(inst, operand_ty, operand);
4876 try func.load(operand, operand_ptr, func.typeOf(un_op));
4877 break :result try func.isNonErr(inst, operand_ty, operand);
40894878 };
4090 return self.finishAir(inst, result, .{ un_op, .none, .none });
4879 return func.finishAir(inst, result, .{ un_op, .none, .none });
40914880}
40924881
4093fn airLoop(self: *Self, inst: Air.Inst.Index) !void {
4882fn airLoop(func: *Func, inst: Air.Inst.Index) !void {
40944883 // A loop is a setup to be able to jump back to the beginning.
4095 const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
4096 const loop = self.air.extraData(Air.Block, ty_pl.payload);
4097 const body: []const Air.Inst.Index = @ptrCast(self.air.extra[loop.end..][0..loop.data.body_len]);
4884 const ty_pl = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
4885 const loop = func.air.extraData(Air.Block, ty_pl.payload);
4886 const body: []const Air.Inst.Index = @ptrCast(func.air.extra[loop.end..][0..loop.data.body_len]);
40984887
4099 self.scope_generation += 1;
4100 const state = try self.saveState();
4888 func.scope_generation += 1;
4889 const state = try func.saveState();
41014890
4102 const jmp_target: Mir.Inst.Index = @intCast(self.mir_instructions.len);
4103 try self.genBody(body);
4104 try self.restoreState(state, &.{}, .{
4891 const jmp_target: Mir.Inst.Index = @intCast(func.mir_instructions.len);
4892 try func.genBody(body);
4893 try func.restoreState(state, &.{}, .{
41054894 .emit_instructions = true,
41064895 .update_tracking = false,
41074896 .resurrect = false,
41084897 .close_scope = true,
41094898 });
4110 _ = try self.jump(jmp_target);
4899 _ = try func.jump(jmp_target);
41114900
4112 self.finishAirBookkeeping();
4901 func.finishAirBookkeeping();
41134902}
41144903
4115/// Send control flow to the `index` of `self.code`.
4116fn jump(self: *Self, index: Mir.Inst.Index) !Mir.Inst.Index {
4117 return self.addInst(.{
4904/// Send control flow to the `index` of `func.code`.
4905fn jump(func: *Func, index: Mir.Inst.Index) !Mir.Inst.Index {
4906 return func.addInst(.{
41184907 .tag = .pseudo,
41194908 .ops = .pseudo_j,
41204909 .data = .{
......@@ -4123,113 +4912,200 @@ fn jump(self: *Self, index: Mir.Inst.Index) !Mir.Inst.Index {
41234912 });
41244913}
41254914
4126fn airBlock(self: *Self, inst: Air.Inst.Index) !void {
4127 const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
4128 const extra = self.air.extraData(Air.Block, ty_pl.payload);
4129 try self.lowerBlock(inst, @ptrCast(self.air.extra[extra.end..][0..extra.data.body_len]));
4915fn airBlock(func: *Func, inst: Air.Inst.Index) !void {
4916 const ty_pl = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
4917 const extra = func.air.extraData(Air.Block, ty_pl.payload);
4918 try func.lowerBlock(inst, @ptrCast(func.air.extra[extra.end..][0..extra.data.body_len]));
41304919}
41314920
4132fn lowerBlock(self: *Self, inst: Air.Inst.Index, body: []const Air.Inst.Index) !void {
4921fn lowerBlock(func: *Func, inst: Air.Inst.Index, body: []const Air.Inst.Index) !void {
41334922 // A block is a setup to be able to jump to the end.
4134 const inst_tracking_i = self.inst_tracking.count();
4135 self.inst_tracking.putAssumeCapacityNoClobber(inst, InstTracking.init(.unreach));
4923 const inst_tracking_i = func.inst_tracking.count();
4924 func.inst_tracking.putAssumeCapacityNoClobber(inst, InstTracking.init(.unreach));
41364925
4137 self.scope_generation += 1;
4138 try self.blocks.putNoClobber(self.gpa, inst, .{ .state = self.initRetroactiveState() });
4139 const liveness = self.liveness.getBlock(inst);
4926 func.scope_generation += 1;
4927 try func.blocks.putNoClobber(func.gpa, inst, .{ .state = func.initRetroactiveState() });
4928 const liveness = func.liveness.getBlock(inst);
41404929
41414930 // TODO emit debug info lexical block
4142 try self.genBody(body);
4931 try func.genBody(body);
41434932
4144 var block_data = self.blocks.fetchRemove(inst).?;
4145 defer block_data.value.deinit(self.gpa);
4933 var block_data = func.blocks.fetchRemove(inst).?;
4934 defer block_data.value.deinit(func.gpa);
41464935 if (block_data.value.relocs.items.len > 0) {
4147 try self.restoreState(block_data.value.state, liveness.deaths, .{
4936 try func.restoreState(block_data.value.state, liveness.deaths, .{
41484937 .emit_instructions = false,
41494938 .update_tracking = true,
41504939 .resurrect = true,
41514940 .close_scope = true,
41524941 });
4153 for (block_data.value.relocs.items) |reloc| self.performReloc(reloc);
4942 for (block_data.value.relocs.items) |reloc| func.performReloc(reloc);
41544943 }
41554944
4156 if (std.debug.runtime_safety) assert(self.inst_tracking.getIndex(inst).? == inst_tracking_i);
4157 const tracking = &self.inst_tracking.values()[inst_tracking_i];
4158 if (self.liveness.isUnused(inst)) try tracking.die(self, inst);
4159 self.getValueIfFree(tracking.short, inst);
4160 self.finishAirBookkeeping();
4945 if (std.debug.runtime_safety) assert(func.inst_tracking.getIndex(inst).? == inst_tracking_i);
4946 const tracking = &func.inst_tracking.values()[inst_tracking_i];
4947 if (func.liveness.isUnused(inst)) try tracking.die(func, inst);
4948 func.getValueIfFree(tracking.short, inst);
4949 func.finishAirBookkeeping();
41614950}
41624951
4163fn airSwitch(self: *Self, inst: Air.Inst.Index) !void {
4164 const pl_op = self.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;
4165 const condition = pl_op.operand;
4166 _ = condition;
4167 return self.fail("TODO airSwitch for {}", .{self.target.cpu.arch});
4168 // return self.finishAir(inst, .dead, .{ condition, .none, .none });
4952fn airSwitchBr(func: *Func, inst: Air.Inst.Index) !void {
4953 const pl_op = func.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;
4954 const condition = try func.resolveInst(pl_op.operand);
4955 const condition_ty = func.typeOf(pl_op.operand);
4956 const switch_br = func.air.extraData(Air.SwitchBr, pl_op.payload);
4957 var extra_index: usize = switch_br.end;
4958 var case_i: u32 = 0;
4959 const liveness = try func.liveness.getSwitchBr(func.gpa, inst, switch_br.data.cases_len + 1);
4960 defer func.gpa.free(liveness.deaths);
4961
4962 // If the condition dies here in this switch instruction, process
4963 // that death now instead of later as this has an effect on
4964 // whether it needs to be spilled in the branches
4965 if (func.liveness.operandDies(inst, 0)) {
4966 if (pl_op.operand.toIndex()) |op_inst| try func.processDeath(op_inst);
4967 }
4968
4969 func.scope_generation += 1;
4970 const state = try func.saveState();
4971
4972 while (case_i < switch_br.data.cases_len) : (case_i += 1) {
4973 const case = func.air.extraData(Air.SwitchBr.Case, extra_index);
4974 const items: []const Air.Inst.Ref =
4975 @ptrCast(func.air.extra[case.end..][0..case.data.items_len]);
4976 const case_body: []const Air.Inst.Index =
4977 @ptrCast(func.air.extra[case.end + items.len ..][0..case.data.body_len]);
4978 extra_index = case.end + items.len + case_body.len;
4979
4980 var relocs = try func.gpa.alloc(Mir.Inst.Index, items.len);
4981 defer func.gpa.free(relocs);
4982
4983 for (items, relocs, 0..) |item, *reloc, i| {
4984 // switch branches must be comptime-known, so this is stored in an immediate
4985 const item_mcv = try func.resolveInst(item);
4986
4987 const cmp_reg, const cmp_lock = try func.allocReg(.int);
4988 defer func.register_manager.unlockReg(cmp_lock);
4989
4990 try func.genBinOp(
4991 .cmp_neq,
4992 condition,
4993 condition_ty,
4994 item_mcv,
4995 condition_ty,
4996 cmp_reg,
4997 );
4998
4999 if (!(i < relocs.len - 1)) {
5000 _ = try func.addInst(.{
5001 .tag = .pseudo,
5002 .ops = .pseudo_not,
5003 .data = .{ .rr = .{
5004 .rd = cmp_reg,
5005 .rs = cmp_reg,
5006 } },
5007 });
5008 }
5009
5010 reloc.* = try func.condBr(condition_ty, .{ .register = cmp_reg });
5011 }
5012
5013 for (liveness.deaths[case_i]) |operand| try func.processDeath(operand);
5014
5015 for (relocs[0 .. relocs.len - 1]) |reloc| func.performReloc(reloc);
5016 try func.genBody(case_body);
5017 try func.restoreState(state, &.{}, .{
5018 .emit_instructions = false,
5019 .update_tracking = true,
5020 .resurrect = true,
5021 .close_scope = true,
5022 });
5023
5024 func.performReloc(relocs[relocs.len - 1]);
5025 }
5026
5027 if (switch_br.data.else_body_len > 0) {
5028 const else_body: []const Air.Inst.Index =
5029 @ptrCast(func.air.extra[extra_index..][0..switch_br.data.else_body_len]);
5030
5031 const else_deaths = liveness.deaths.len - 1;
5032 for (liveness.deaths[else_deaths]) |operand| try func.processDeath(operand);
5033
5034 try func.genBody(else_body);
5035 try func.restoreState(state, &.{}, .{
5036 .emit_instructions = false,
5037 .update_tracking = true,
5038 .resurrect = true,
5039 .close_scope = true,
5040 });
5041 }
5042
5043 // We already took care of pl_op.operand earlier, so there's nothing left to do
5044 func.finishAirBookkeeping();
41695045}
41705046
4171fn performReloc(self: *Self, inst: Mir.Inst.Index) void {
4172 const tag = self.mir_instructions.items(.tag)[inst];
4173 const ops = self.mir_instructions.items(.ops)[inst];
4174 const target: Mir.Inst.Index = @intCast(self.mir_instructions.len);
5047fn performReloc(func: *Func, inst: Mir.Inst.Index) void {
5048 const tag = func.mir_instructions.items(.tag)[inst];
5049 const ops = func.mir_instructions.items(.ops)[inst];
5050 const target: Mir.Inst.Index = @intCast(func.mir_instructions.len);
41755051
41765052 switch (tag) {
41775053 .bne,
41785054 .beq,
4179 => self.mir_instructions.items(.data)[inst].b_type.inst = target,
4180 .jal => self.mir_instructions.items(.data)[inst].j_type.inst = target,
5055 => func.mir_instructions.items(.data)[inst].b_type.inst = target,
5056 .jal => func.mir_instructions.items(.data)[inst].j_type.inst = target,
41815057 .pseudo => switch (ops) {
4182 .pseudo_j => self.mir_instructions.items(.data)[inst].inst = target,
5058 .pseudo_j => func.mir_instructions.items(.data)[inst].inst = target,
41835059 else => std.debug.panic("TODO: performReloc {s}", .{@tagName(ops)}),
41845060 },
41855061 else => std.debug.panic("TODO: performReloc {s}", .{@tagName(tag)}),
41865062 }
41875063}
41885064
4189fn airBr(self: *Self, inst: Air.Inst.Index) !void {
4190 const mod = self.bin_file.comp.module.?;
4191 const br = self.air.instructions.items(.data)[@intFromEnum(inst)].br;
5065fn airBr(func: *Func, inst: Air.Inst.Index) !void {
5066 const mod = func.bin_file.comp.module.?;
5067 const br = func.air.instructions.items(.data)[@intFromEnum(inst)].br;
41925068
4193 const block_ty = self.typeOfIndex(br.block_inst);
5069 const block_ty = func.typeOfIndex(br.block_inst);
41945070 const block_unused =
4195 !block_ty.hasRuntimeBitsIgnoreComptime(mod) or self.liveness.isUnused(br.block_inst);
4196 const block_tracking = self.inst_tracking.getPtr(br.block_inst).?;
4197 const block_data = self.blocks.getPtr(br.block_inst).?;
5071 !block_ty.hasRuntimeBitsIgnoreComptime(mod) or func.liveness.isUnused(br.block_inst);
5072 const block_tracking = func.inst_tracking.getPtr(br.block_inst).?;
5073 const block_data = func.blocks.getPtr(br.block_inst).?;
41985074 const first_br = block_data.relocs.items.len == 0;
41995075 const block_result = result: {
42005076 if (block_unused) break :result .none;
42015077
4202 if (!first_br) try self.getValue(block_tracking.short, null);
4203 const src_mcv = try self.resolveInst(br.operand);
5078 if (!first_br) try func.getValue(block_tracking.short, null);
5079 const src_mcv = try func.resolveInst(br.operand);
42045080
4205 if (self.reuseOperandAdvanced(inst, br.operand, 0, src_mcv, br.block_inst)) {
5081 if (func.reuseOperandAdvanced(inst, br.operand, 0, src_mcv, br.block_inst)) {
42065082 if (first_br) break :result src_mcv;
42075083
4208 try self.getValue(block_tracking.short, br.block_inst);
5084 try func.getValue(block_tracking.short, br.block_inst);
42095085 // .long = .none to avoid merging operand and block result stack frames.
42105086 const current_tracking: InstTracking = .{ .long = .none, .short = src_mcv };
4211 try current_tracking.materializeUnsafe(self, br.block_inst, block_tracking.*);
4212 for (current_tracking.getRegs()) |src_reg| self.register_manager.freeReg(src_reg);
5087 try current_tracking.materializeUnsafe(func, br.block_inst, block_tracking.*);
5088 for (current_tracking.getRegs()) |src_reg| func.register_manager.freeReg(src_reg);
42135089 break :result block_tracking.short;
42145090 }
42155091
4216 const dst_mcv = if (first_br) try self.allocRegOrMem(br.block_inst, true) else dst: {
4217 try self.getValue(block_tracking.short, br.block_inst);
5092 const dst_mcv = if (first_br) try func.allocRegOrMem(block_ty, br.block_inst, true) else dst: {
5093 try func.getValue(block_tracking.short, br.block_inst);
42185094 break :dst block_tracking.short;
42195095 };
4220 try self.genCopy(block_ty, dst_mcv, try self.resolveInst(br.operand));
5096 try func.genCopy(block_ty, dst_mcv, try func.resolveInst(br.operand));
42215097 break :result dst_mcv;
42225098 };
42235099
42245100 // Process operand death so that it is properly accounted for in the State below.
4225 if (self.liveness.operandDies(inst, 0)) {
4226 if (br.operand.toIndex()) |op_inst| try self.processDeath(op_inst);
5101 if (func.liveness.operandDies(inst, 0)) {
5102 if (br.operand.toIndex()) |op_inst| try func.processDeath(op_inst);
42275103 }
42285104
42295105 if (first_br) {
42305106 block_tracking.* = InstTracking.init(block_result);
4231 try self.saveRetroactiveState(&block_data.state);
4232 } else try self.restoreState(block_data.state, &.{}, .{
5107 try func.saveRetroactiveState(&block_data.state);
5108 } else try func.restoreState(block_data.state, &.{}, .{
42335109 .emit_instructions = true,
42345110 .update_tracking = false,
42355111 .resurrect = false,
......@@ -4238,49 +5114,88 @@ fn airBr(self: *Self, inst: Air.Inst.Index) !void {
42385114
42395115 // Emit a jump with a relocation. It will be patched up after the block ends.
42405116 // Leave the jump offset undefined
4241 const jmp_reloc = try self.jump(undefined);
4242 try block_data.relocs.append(self.gpa, jmp_reloc);
5117 const jmp_reloc = try func.jump(undefined);
5118 try block_data.relocs.append(func.gpa, jmp_reloc);
42435119
42445120 // Stop tracking block result without forgetting tracking info
4245 try self.freeValue(block_tracking.short);
5121 try func.freeValue(block_tracking.short);
42465122
4247 self.finishAirBookkeeping();
5123 func.finishAirBookkeeping();
42485124}
42495125
4250fn airBoolOp(self: *Self, inst: Air.Inst.Index) !void {
4251 const bin_op = self.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
4252 const air_tags = self.air.instructions.items(.tag);
4253 _ = air_tags;
4254 const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else return self.fail("TODO implement boolean operations for {}", .{self.target.cpu.arch});
4255 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
5126fn airBoolOp(func: *Func, inst: Air.Inst.Index) !void {
5127 const bin_op = func.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
5128 const tag: Air.Inst.Tag = func.air.instructions.items(.tag)[@intFromEnum(inst)];
5129
5130 const result: MCValue = if (func.liveness.isUnused(inst)) .unreach else result: {
5131 const lhs = try func.resolveInst(bin_op.lhs);
5132 const rhs = try func.resolveInst(bin_op.rhs);
5133 const lhs_ty = Type.bool;
5134 const rhs_ty = Type.bool;
5135
5136 const lhs_reg, const lhs_lock = try func.promoteReg(lhs_ty, lhs);
5137 defer if (lhs_lock) |lock| func.register_manager.unlockReg(lock);
5138
5139 const rhs_reg, const rhs_lock = try func.promoteReg(rhs_ty, rhs);
5140 defer if (rhs_lock) |lock| func.register_manager.unlockReg(lock);
5141
5142 const result_reg, const result_lock = try func.allocReg(.int);
5143 defer func.register_manager.unlockReg(result_lock);
5144
5145 _ = try func.addInst(.{
5146 .tag = if (tag == .bool_or) .@"or" else .@"and",
5147 .ops = .rrr,
5148 .data = .{ .r_type = .{
5149 .rd = result_reg,
5150 .rs1 = lhs_reg,
5151 .rs2 = rhs_reg,
5152 } },
5153 });
5154
5155 // safety truncate
5156 if (func.wantSafety()) {
5157 _ = try func.addInst(.{
5158 .tag = .andi,
5159 .ops = .rri,
5160 .data = .{ .i_type = .{
5161 .rd = result_reg,
5162 .rs1 = result_reg,
5163 .imm12 = Immediate.s(1),
5164 } },
5165 });
5166 }
5167
5168 break :result .{ .register = result_reg };
5169 };
5170 return func.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
42565171}
42575172
4258fn airAsm(self: *Self, inst: Air.Inst.Index) !void {
4259 const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
4260 const extra = self.air.extraData(Air.Asm, ty_pl.payload);
5173fn airAsm(func: *Func, inst: Air.Inst.Index) !void {
5174 const ty_pl = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
5175 const extra = func.air.extraData(Air.Asm, ty_pl.payload);
42615176 const is_volatile = @as(u1, @truncate(extra.data.flags >> 31)) != 0;
42625177 const clobbers_len: u31 = @truncate(extra.data.flags);
42635178 var extra_i: usize = extra.end;
42645179 const outputs: []const Air.Inst.Ref =
4265 @ptrCast(self.air.extra[extra_i..][0..extra.data.outputs_len]);
5180 @ptrCast(func.air.extra[extra_i..][0..extra.data.outputs_len]);
42665181 extra_i += outputs.len;
4267 const inputs: []const Air.Inst.Ref = @ptrCast(self.air.extra[extra_i..][0..extra.data.inputs_len]);
5182 const inputs: []const Air.Inst.Ref = @ptrCast(func.air.extra[extra_i..][0..extra.data.inputs_len]);
42685183 extra_i += inputs.len;
42695184
42705185 log.debug("airAsm input: {any}", .{inputs});
42715186
4272 const dead = !is_volatile and self.liveness.isUnused(inst);
5187 const dead = !is_volatile and func.liveness.isUnused(inst);
42735188 const result: MCValue = if (dead) .unreach else result: {
42745189 if (outputs.len > 1) {
4275 return self.fail("TODO implement codegen for asm with more than 1 output", .{});
5190 return func.fail("TODO implement codegen for asm with more than 1 output", .{});
42765191 }
42775192
42785193 const output_constraint: ?[]const u8 = for (outputs) |output| {
42795194 if (output != .none) {
4280 return self.fail("TODO implement codegen for non-expr asm", .{});
5195 return func.fail("TODO implement codegen for non-expr asm", .{});
42815196 }
4282 const extra_bytes = std.mem.sliceAsBytes(self.air.extra[extra_i..]);
4283 const constraint = std.mem.sliceTo(std.mem.sliceAsBytes(self.air.extra[extra_i..]), 0);
5197 const extra_bytes = std.mem.sliceAsBytes(func.air.extra[extra_i..]);
5198 const constraint = std.mem.sliceTo(std.mem.sliceAsBytes(func.air.extra[extra_i..]), 0);
42845199 const name = std.mem.sliceTo(extra_bytes[constraint.len + 1 ..], 0);
42855200 // This equation accounts for the fact that even if we have exactly 4 bytes
42865201 // for the string, we still use the next u32 for the null terminator.
......@@ -4290,7 +5205,7 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {
42905205 } else null;
42915206
42925207 for (inputs) |input| {
4293 const input_bytes = std.mem.sliceAsBytes(self.air.extra[extra_i..]);
5208 const input_bytes = std.mem.sliceAsBytes(func.air.extra[extra_i..]);
42945209 const constraint = std.mem.sliceTo(input_bytes, 0);
42955210 const name = std.mem.sliceTo(input_bytes[constraint.len + 1 ..], 0);
42965211 // This equation accounts for the fact that even if we have exactly 4 bytes
......@@ -4298,21 +5213,21 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {
42985213 extra_i += (constraint.len + name.len + (2 + 3)) / 4;
42995214
43005215 if (constraint.len < 3 or constraint[0] != '{' or constraint[constraint.len - 1] != '}') {
4301 return self.fail("unrecognized asm input constraint: '{s}'", .{constraint});
5216 return func.fail("unrecognized asm input constraint: '{s}'", .{constraint});
43025217 }
43035218 const reg_name = constraint[1 .. constraint.len - 1];
43045219 const reg = parseRegName(reg_name) orelse
4305 return self.fail("unrecognized register: '{s}'", .{reg_name});
5220 return func.fail("unrecognized register: '{s}'", .{reg_name});
43065221
4307 const arg_mcv = try self.resolveInst(input);
4308 try self.register_manager.getReg(reg, null);
4309 try self.genSetReg(self.typeOf(input), reg, arg_mcv);
5222 const arg_mcv = try func.resolveInst(input);
5223 try func.register_manager.getReg(reg, null);
5224 try func.genSetReg(func.typeOf(input), reg, arg_mcv);
43105225 }
43115226
43125227 {
43135228 var clobber_i: u32 = 0;
43145229 while (clobber_i < clobbers_len) : (clobber_i += 1) {
4315 const clobber = std.mem.sliceTo(std.mem.sliceAsBytes(self.air.extra[extra_i..]), 0);
5230 const clobber = std.mem.sliceTo(std.mem.sliceAsBytes(func.air.extra[extra_i..]), 0);
43165231 // This equation accounts for the fact that even if we have exactly 4 bytes
43175232 // for the string, we still use the next u32 for the null terminator.
43185233 extra_i += clobber.len / 4 + 1;
......@@ -4320,31 +5235,31 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {
43205235 if (std.mem.eql(u8, clobber, "") or std.mem.eql(u8, clobber, "memory")) {
43215236 // nothing really to do
43225237 } else {
4323 try self.register_manager.getReg(parseRegName(clobber) orelse
4324 return self.fail("invalid clobber: '{s}'", .{clobber}), null);
5238 try func.register_manager.getReg(parseRegName(clobber) orelse
5239 return func.fail("invalid clobber: '{s}'", .{clobber}), null);
43255240 }
43265241 }
43275242 }
43285243
4329 const asm_source = std.mem.sliceAsBytes(self.air.extra[extra_i..])[0..extra.data.source_len];
5244 const asm_source = std.mem.sliceAsBytes(func.air.extra[extra_i..])[0..extra.data.source_len];
43305245
43315246 if (std.meta.stringToEnum(Mir.Inst.Tag, asm_source)) |tag| {
4332 _ = try self.addInst(.{
5247 _ = try func.addInst(.{
43335248 .tag = tag,
43345249 .ops = .none,
43355250 .data = undefined,
43365251 });
43375252 } else {
4338 return self.fail("TODO: asm_source {s}", .{asm_source});
5253 return func.fail("TODO: asm_source {s}", .{asm_source});
43395254 }
43405255
43415256 if (output_constraint) |output| {
43425257 if (output.len < 4 or output[0] != '=' or output[1] != '{' or output[output.len - 1] != '}') {
4343 return self.fail("unrecognized asm output constraint: '{s}'", .{output});
5258 return func.fail("unrecognized asm output constraint: '{s}'", .{output});
43445259 }
43455260 const reg_name = output[2 .. output.len - 1];
43465261 const reg = parseRegName(reg_name) orelse
4347 return self.fail("unrecognized register: '{s}'", .{reg_name});
5262 return func.fail("unrecognized register: '{s}'", .{reg_name});
43485263 break :result .{ .register = reg };
43495264 } else {
43505265 break :result .{ .none = {} };
......@@ -4363,29 +5278,29 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {
43635278 }
43645279 if (buf_index + inputs.len > buf.len) break :simple;
43655280 @memcpy(buf[buf_index..][0..inputs.len], inputs);
4366 return self.finishAir(inst, result, buf);
5281 return func.finishAir(inst, result, buf);
43675282 }
4368 var bt = self.liveness.iterateBigTomb(inst);
4369 for (outputs) |output| if (output != .none) try self.feed(&bt, output);
4370 for (inputs) |input| try self.feed(&bt, input);
4371 return self.finishAirResult(inst, result);
5283 var bt = func.liveness.iterateBigTomb(inst);
5284 for (outputs) |output| if (output != .none) try func.feed(&bt, output);
5285 for (inputs) |input| try func.feed(&bt, input);
5286 return func.finishAirResult(inst, result);
43725287}
43735288
4374/// Sets the value without any modifications to register allocation metadata or stack allocation metadata.
4375fn genCopy(self: *Self, ty: Type, dst_mcv: MCValue, src_mcv: MCValue) !void {
4376 const zcu = self.bin_file.comp.module.?;
5289/// Sets the value of `dst_mcv` to the value of `src_mcv`.
5290fn genCopy(func: *Func, ty: Type, dst_mcv: MCValue, src_mcv: MCValue) !void {
5291 const zcu = func.bin_file.comp.module.?;
43775292
43785293 // There isn't anything to store
43795294 if (dst_mcv == .none) return;
43805295
43815296 if (!dst_mcv.isMutable()) {
43825297 // panic so we can see the trace
4383 return self.fail("tried to genCopy immutable: {s}", .{@tagName(dst_mcv)});
5298 return std.debug.panic("tried to genCopy immutable: {s}", .{@tagName(dst_mcv)});
43845299 }
43855300
43865301 switch (dst_mcv) {
4387 .register => |reg| return self.genSetReg(ty, reg, src_mcv),
4388 .register_offset => |dst_reg_off| try self.genSetReg(ty, dst_reg_off.reg, switch (src_mcv) {
5302 .register => |reg| return func.genSetReg(ty, reg, src_mcv),
5303 .register_offset => |dst_reg_off| try func.genSetReg(ty, dst_reg_off.reg, switch (src_mcv) {
43895304 .none,
43905305 .unreach,
43915306 .dead,
......@@ -4396,167 +5311,85 @@ fn genCopy(self: *Self, ty: Type, dst_mcv: MCValue, src_mcv: MCValue) !void {
43965311 .register_offset,
43975312 => src_mcv.offset(-dst_reg_off.off),
43985313 else => .{ .register_offset = .{
4399 .reg = try self.copyToTmpRegister(ty, src_mcv),
5314 .reg = try func.copyToTmpRegister(ty, src_mcv),
44005315 .off = -dst_reg_off.off,
44015316 } },
44025317 }),
4403 .indirect => |ro| {
4404 const src_reg = try self.copyToTmpRegister(ty, src_mcv);
4405
4406 _ = try self.addInst(.{
4407 .tag = .pseudo,
4408 .ops = .pseudo_store_rm,
4409 .data = .{ .rm = .{
4410 .r = src_reg,
4411 .m = .{
4412 .base = .{ .reg = ro.reg },
4413 .mod = .{ .rm = .{ .disp = ro.off, .size = self.memSize(ty) } },
4414 },
4415 } },
4416 });
4417 },
4418 .load_frame => |frame| return self.genSetStack(ty, frame, src_mcv),
4419 .memory => return self.fail("TODO: genCopy memory", .{}),
5318 .indirect => |reg_off| try func.genSetMem(
5319 .{ .reg = reg_off.reg },
5320 reg_off.off,
5321 ty,
5322 src_mcv,
5323 ),
5324 .load_frame => |frame_addr| try func.genSetMem(
5325 .{ .frame = frame_addr.index },
5326 frame_addr.off,
5327 ty,
5328 src_mcv,
5329 ),
5330 .memory => return func.fail("TODO: genCopy memory", .{}),
44205331 .register_pair => |dst_regs| {
4421 const src_info: ?struct { addr_reg: Register, addr_lock: RegisterLock } = switch (src_mcv) {
5332 const src_info: ?struct { addr_reg: Register, addr_lock: ?RegisterLock } = switch (src_mcv) {
44225333 .register_pair, .memory, .indirect, .load_frame => null,
44235334 .load_symbol => src: {
4424 const src_addr_reg, const src_addr_lock = try self.allocReg();
4425 errdefer self.register_manager.unlockReg(src_addr_lock);
5335 const src_addr_reg, const src_addr_lock = try func.promoteReg(Type.usize, src_mcv.address());
5336 errdefer func.register_manager.unlockReg(src_addr_lock);
44265337
4427 try self.genSetReg(Type.usize, src_addr_reg, src_mcv.address());
44285338 break :src .{ .addr_reg = src_addr_reg, .addr_lock = src_addr_lock };
44295339 },
4430 .air_ref => |src_ref| return self.genCopy(
5340 .air_ref => |src_ref| return func.genCopy(
44315341 ty,
44325342 dst_mcv,
4433 try self.resolveInst(src_ref),
5343 try func.resolveInst(src_ref),
44345344 ),
4435 else => unreachable,
5345 else => return func.fail("genCopy register_pair src: {}", .{src_mcv}),
44365346 };
4437 defer if (src_info) |info| self.register_manager.unlockReg(info.addr_lock);
4438
4439 var part_disp: i32 = 0;
4440 for (dst_regs, try self.splitType(ty), 0..) |dst_reg, dst_ty, part_i| {
4441 try self.genSetReg(dst_ty, dst_reg, switch (src_mcv) {
4442 .register_pair => |src_regs| .{ .register = src_regs[part_i] },
4443 .memory, .indirect, .load_frame => src_mcv.address().offset(part_disp).deref(),
4444 .load_symbol => .{ .indirect = .{
4445 .reg = src_info.?.addr_reg,
4446 .off = part_disp,
4447 } },
4448 else => unreachable,
4449 });
4450 part_disp += @intCast(dst_ty.abiSize(zcu));
4451 }
4452 },
4453 else => return self.fail("TODO: genCopy to {s} from {s}", .{ @tagName(dst_mcv), @tagName(src_mcv) }),
4454 }
4455}
4456
4457fn genSetStack(
4458 self: *Self,
4459 ty: Type,
4460 frame: FrameAddr,
4461 src_mcv: MCValue,
4462) InnerError!void {
4463 const zcu = self.bin_file.comp.module.?;
4464 const abi_size: u32 = @intCast(ty.abiSize(zcu));
4465
4466 switch (src_mcv) {
4467 .none => return,
4468 .dead => unreachable,
4469 .undef => {
4470 if (!self.wantSafety()) return;
4471 try self.genSetStack(ty, frame, .{ .immediate = 0xaaaaaaaaaaaaaaaa });
4472 },
4473 .immediate,
4474 .lea_frame,
4475 => {
4476 // TODO: remove this lock in favor of a copyToTmpRegister when we load 64 bit immediates with
4477 // a register allocation.
4478 const reg, const reg_lock = try self.allocReg();
4479 defer self.register_manager.unlockReg(reg_lock);
44805347
4481 try self.genSetReg(ty, reg, src_mcv);
5348 defer if (src_info) |info| {
5349 if (info.addr_lock) |lock| {
5350 func.register_manager.unlockReg(lock);
5351 }
5352 };
44825353
4483 return self.genSetStack(ty, frame, .{ .register = reg });
4484 },
4485 .register => |reg| {
4486 switch (abi_size) {
4487 1, 2, 4, 8 => {
4488 _ = try self.addInst(.{
4489 .tag = .pseudo,
4490 .ops = .pseudo_store_rm,
4491 .data = .{ .rm = .{
4492 .r = reg,
4493 .m = .{
4494 .base = .{ .frame = frame.index },
4495 .mod = .{
4496 .rm = .{
4497 .size = self.memSize(ty),
4498 .disp = frame.off,
4499 },
4500 },
4501 },
4502 } },
4503 });
4504 },
4505 else => unreachable, // register can hold a max of 8 bytes
4506 }
4507 },
4508 .register_pair => |pair| {
4509 var part_disp: i32 = frame.off;
4510 for (try self.splitType(ty), pair) |src_ty, src_reg| {
4511 try self.genSetStack(
4512 src_ty,
4513 .{ .index = frame.index, .off = part_disp },
4514 .{ .register = src_reg },
4515 );
4516 part_disp += @intCast(src_ty.abiSize(zcu));
4517 }
4518 },
4519 .load_frame,
4520 .indirect,
4521 .load_symbol,
4522 => {
4523 if (abi_size <= 8) {
4524 const reg = try self.copyToTmpRegister(ty, src_mcv);
4525 return self.genSetStack(ty, frame, .{ .register = reg });
5354 var part_disp: i32 = 0;
5355 for (dst_regs, try func.splitType(ty), 0..) |dst_reg, dst_ty, part_i| {
5356 try func.genSetReg(dst_ty, dst_reg, switch (src_mcv) {
5357 .register_pair => |src_regs| .{ .register = src_regs[part_i] },
5358 .memory, .indirect, .load_frame => src_mcv.address().offset(part_disp).deref(),
5359 .load_symbol => .{ .indirect = .{
5360 .reg = src_info.?.addr_reg,
5361 .off = part_disp,
5362 } },
5363 else => unreachable,
5364 });
5365 part_disp += @intCast(dst_ty.abiSize(zcu));
45265366 }
4527
4528 try self.genInlineMemcpy(
4529 .{ .lea_frame = frame },
4530 src_mcv.address(),
4531 .{ .immediate = abi_size },
4532 );
45335367 },
4534 .air_ref => |ref| try self.genSetStack(ty, frame, try self.resolveInst(ref)),
4535 else => return self.fail("TODO: genSetStack {s}", .{@tagName(src_mcv)}),
5368 else => return func.fail("TODO: genCopy to {s} from {s}", .{ @tagName(dst_mcv), @tagName(src_mcv) }),
45365369 }
45375370}
45385371
45395372fn genInlineMemcpy(
4540 self: *Self,
5373 func: *Func,
45415374 dst_ptr: MCValue,
45425375 src_ptr: MCValue,
45435376 len: MCValue,
45445377) !void {
4545 const regs = try self.register_manager.allocRegs(4, .{null} ** 4, tp);
4546 const locks = self.register_manager.lockRegsAssumeUnused(4, regs);
4547 defer for (locks) |lock| self.register_manager.unlockReg(lock);
5378 const regs = try func.register_manager.allocRegs(4, .{null} ** 4, abi.Registers.Integer.temporary);
5379 const locks = func.register_manager.lockRegsAssumeUnused(4, regs);
5380 defer for (locks) |lock| func.register_manager.unlockReg(lock);
45485381
45495382 const count = regs[0];
45505383 const tmp = regs[1];
45515384 const src = regs[2];
45525385 const dst = regs[3];
45535386
4554 try self.genSetReg(Type.usize, count, len);
4555 try self.genSetReg(Type.usize, src, src_ptr);
4556 try self.genSetReg(Type.usize, dst, dst_ptr);
5387 try func.genSetReg(Type.usize, count, len);
5388 try func.genSetReg(Type.usize, src, src_ptr);
5389 try func.genSetReg(Type.usize, dst, dst_ptr);
45575390
45585391 // lb tmp, 0(src)
4559 const first_inst = try self.addInst(.{
5392 const first_inst = try func.addInst(.{
45605393 .tag = .lb,
45615394 .ops = .rri,
45625395 .data = .{
......@@ -4569,7 +5402,7 @@ fn genInlineMemcpy(
45695402 });
45705403
45715404 // sb tmp, 0(dst)
4572 _ = try self.addInst(.{
5405 _ = try func.addInst(.{
45735406 .tag = .sb,
45745407 .ops = .rri,
45755408 .data = .{
......@@ -4582,7 +5415,7 @@ fn genInlineMemcpy(
45825415 });
45835416
45845417 // dec count by 1
4585 _ = try self.addInst(.{
5418 _ = try func.addInst(.{
45865419 .tag = .addi,
45875420 .ops = .rri,
45885421 .data = .{
......@@ -4595,12 +5428,12 @@ fn genInlineMemcpy(
45955428 });
45965429
45975430 // branch if count is 0
4598 _ = try self.addInst(.{
5431 _ = try func.addInst(.{
45995432 .tag = .beq,
46005433 .ops = .rr_inst,
46015434 .data = .{
46025435 .b_type = .{
4603 .inst = @intCast(self.mir_instructions.len + 4), // points after the last inst
5436 .inst = @intCast(func.mir_instructions.len + 4), // points after the last inst
46045437 .rs1 = count,
46055438 .rs2 = .zero,
46065439 },
......@@ -4608,7 +5441,7 @@ fn genInlineMemcpy(
46085441 });
46095442
46105443 // increment the pointers
4611 _ = try self.addInst(.{
5444 _ = try func.addInst(.{
46125445 .tag = .addi,
46135446 .ops = .rri,
46145447 .data = .{
......@@ -4620,7 +5453,85 @@ fn genInlineMemcpy(
46205453 },
46215454 });
46225455
4623 _ = try self.addInst(.{
5456 _ = try func.addInst(.{
5457 .tag = .addi,
5458 .ops = .rri,
5459 .data = .{
5460 .i_type = .{
5461 .rd = dst,
5462 .rs1 = dst,
5463 .imm12 = Immediate.s(1),
5464 },
5465 },
5466 });
5467
5468 // jump back to start of loop
5469 _ = try func.addInst(.{
5470 .tag = .pseudo,
5471 .ops = .pseudo_j,
5472 .data = .{ .inst = first_inst },
5473 });
5474}
5475
5476fn genInlineMemset(
5477 func: *Func,
5478 dst_ptr: MCValue,
5479 src_value: MCValue,
5480 len: MCValue,
5481) !void {
5482 const regs = try func.register_manager.allocRegs(3, .{null} ** 3, abi.Registers.Integer.temporary);
5483 const locks = func.register_manager.lockRegsAssumeUnused(3, regs);
5484 defer for (locks) |lock| func.register_manager.unlockReg(lock);
5485
5486 const count = regs[0];
5487 const src = regs[1];
5488 const dst = regs[2];
5489
5490 try func.genSetReg(Type.usize, count, len);
5491 try func.genSetReg(Type.usize, src, src_value);
5492 try func.genSetReg(Type.usize, dst, dst_ptr);
5493
5494 // sb src, 0(dst)
5495 const first_inst = try func.addInst(.{
5496 .tag = .sb,
5497 .ops = .rri,
5498 .data = .{
5499 .i_type = .{
5500 .rd = dst,
5501 .rs1 = src,
5502 .imm12 = Immediate.s(0),
5503 },
5504 },
5505 });
5506
5507 // dec count by 1
5508 _ = try func.addInst(.{
5509 .tag = .addi,
5510 .ops = .rri,
5511 .data = .{
5512 .i_type = .{
5513 .rd = count,
5514 .rs1 = count,
5515 .imm12 = Immediate.s(-1),
5516 },
5517 },
5518 });
5519
5520 // branch if count is 0
5521 _ = try func.addInst(.{
5522 .tag = .beq,
5523 .ops = .rr_inst,
5524 .data = .{
5525 .b_type = .{
5526 .inst = @intCast(func.mir_instructions.len + 4), // points after the last inst
5527 .rs1 = count,
5528 .rs2 = .zero,
5529 },
5530 },
5531 });
5532
5533 // increment the pointers
5534 _ = try func.addInst(.{
46245535 .tag = .addi,
46255536 .ops = .rri,
46265537 .data = .{
......@@ -4633,7 +5544,7 @@ fn genInlineMemcpy(
46335544 });
46345545
46355546 // jump back to start of loop
4636 _ = try self.addInst(.{
5547 _ = try func.addInst(.{
46375548 .tag = .pseudo,
46385549 .ops = .pseudo_j,
46395550 .data = .{
......@@ -4643,25 +5554,29 @@ fn genInlineMemcpy(
46435554}
46445555
46455556/// Sets the value of `src_mcv` into `reg`. Assumes you have a lock on it.
4646fn genSetReg(self: *Self, ty: Type, reg: Register, src_mcv: MCValue) InnerError!void {
4647 const zcu = self.bin_file.comp.module.?;
5557fn genSetReg(func: *Func, ty: Type, reg: Register, src_mcv: MCValue) InnerError!void {
5558 const zcu = func.bin_file.comp.module.?;
46485559 const abi_size: u32 = @intCast(ty.abiSize(zcu));
46495560
4650 if (abi_size > 8) return self.fail("tried to set reg with size {}", .{abi_size});
5561 if (abi_size > 8) return std.debug.panic("tried to set reg with size {}", .{abi_size});
5562
5563 const dst_reg_class = reg.class();
46515564
46525565 switch (src_mcv) {
46535566 .dead => unreachable,
46545567 .unreach, .none => return, // Nothing to do.
46555568 .undef => {
4656 if (!self.wantSafety())
5569 if (!func.wantSafety())
46575570 return; // The already existing value will do just fine.
46585571 // Write the debug undefined value.
4659 return self.genSetReg(ty, reg, .{ .immediate = 0xaaaaaaaaaaaaaaaa });
5572 return func.genSetReg(ty, reg, .{ .immediate = 0xaaaaaaaaaaaaaaaa });
46605573 },
46615574 .immediate => |unsigned_x| {
5575 assert(dst_reg_class == .int);
5576
46625577 const x: i64 = @bitCast(unsigned_x);
46635578 if (math.minInt(i12) <= x and x <= math.maxInt(i12)) {
4664 _ = try self.addInst(.{
5579 _ = try func.addInst(.{
46655580 .tag = .addi,
46665581 .ops = .rri,
46675582 .data = .{ .i_type = .{
......@@ -4675,7 +5590,7 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, src_mcv: MCValue) InnerError!
46755590 const carry: i32 = if (lo12 < 0) 1 else 0;
46765591 const hi20: i20 = @truncate((x >> 12) +% carry);
46775592
4678 _ = try self.addInst(.{
5593 _ = try func.addInst(.{
46795594 .tag = .lui,
46805595 .ops = .ri,
46815596 .data = .{ .u_type = .{
......@@ -4683,7 +5598,7 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, src_mcv: MCValue) InnerError!
46835598 .imm20 = Immediate.s(hi20),
46845599 } },
46855600 });
4686 _ = try self.addInst(.{
5601 _ = try func.addInst(.{
46875602 .tag = .addi,
46885603 .ops = .rri,
46895604 .data = .{ .i_type = .{
......@@ -4696,27 +5611,27 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, src_mcv: MCValue) InnerError!
46965611 // TODO: use a more advanced myriad seq to do this without a reg.
46975612 // see: https://github.com/llvm/llvm-project/blob/081a66ffacfe85a37ff775addafcf3371e967328/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMatInt.cpp#L224
46985613
4699 const temp, const temp_lock = try self.allocReg();
4700 defer self.register_manager.unlockReg(temp_lock);
5614 const temp, const temp_lock = try func.allocReg(.int);
5615 defer func.register_manager.unlockReg(temp_lock);
47015616
47025617 const lo32: i32 = @truncate(x);
47035618 const carry: i32 = if (lo32 < 0) 1 else 0;
47045619 const hi32: i32 = @truncate((x >> 32) +% carry);
47055620
4706 try self.genSetReg(Type.i32, temp, .{ .immediate = @bitCast(@as(i64, lo32)) });
4707 try self.genSetReg(Type.i32, reg, .{ .immediate = @bitCast(@as(i64, hi32)) });
5621 try func.genSetReg(Type.i32, temp, .{ .immediate = @bitCast(@as(i64, lo32)) });
5622 try func.genSetReg(Type.i32, reg, .{ .immediate = @bitCast(@as(i64, hi32)) });
47085623
4709 _ = try self.addInst(.{
5624 _ = try func.addInst(.{
47105625 .tag = .slli,
47115626 .ops = .rri,
47125627 .data = .{ .i_type = .{
47135628 .rd = reg,
47145629 .rs1 = reg,
4715 .imm12 = Immediate.s(32),
5630 .imm12 = Immediate.u(32),
47165631 } },
47175632 });
47185633
4719 _ = try self.addInst(.{
5634 _ = try func.addInst(.{
47205635 .tag = .add,
47215636 .ops = .rrr,
47225637 .data = .{ .r_type = .{
......@@ -4732,8 +5647,15 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, src_mcv: MCValue) InnerError!
47325647 if (src_reg.id() == reg.id())
47335648 return;
47345649
4735 // mov reg, src_reg
4736 _ = try self.addInst(.{
5650 const src_reg_class = src_reg.class();
5651
5652 if (src_reg_class == .float and dst_reg_class == .int) {
5653 // to move from float -> int, we use FMV.X.W
5654 return func.fail("TODO: genSetReg float -> int", .{});
5655 }
5656
5657 // mv reg, src_reg
5658 _ = try func.addInst(.{
47375659 .tag = .pseudo,
47385660 .ops = .pseudo_mv,
47395661 .data = .{ .rr = .{
......@@ -4742,22 +5664,9 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, src_mcv: MCValue) InnerError!
47425664 } },
47435665 });
47445666 },
4745 .register_pair => |pair| try self.genSetReg(ty, reg, .{ .register = pair[0] }),
4746 .memory => |addr| {
4747 try self.genSetReg(ty, reg, .{ .immediate = addr });
4748
4749 _ = try self.addInst(.{
4750 .tag = .ld,
4751 .ops = .rri,
4752 .data = .{ .i_type = .{
4753 .rd = reg,
4754 .rs1 = reg,
4755 .imm12 = Immediate.s(0),
4756 } },
4757 });
4758 },
5667 .register_pair => return func.fail("genSetReg should we allow reg -> reg_pair?", .{}),
47595668 .load_frame => |frame| {
4760 _ = try self.addInst(.{
5669 _ = try func.addInst(.{
47615670 .tag = .pseudo,
47625671 .ops = .pseudo_load_rm,
47635672 .data = .{ .rm = .{
......@@ -4765,47 +5674,73 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, src_mcv: MCValue) InnerError!
47655674 .m = .{
47665675 .base = .{ .frame = frame.index },
47675676 .mod = .{
4768 .rm = .{
4769 .size = self.memSize(ty),
4770 .disp = frame.off,
4771 },
5677 .size = func.memSize(ty),
5678 .unsigned = ty.isUnsignedInt(zcu),
5679 .disp = frame.off,
47725680 },
47735681 },
47745682 } },
47755683 });
47765684 },
4777 .lea_frame => |frame| {
4778 _ = try self.addInst(.{
5685 .memory => |addr| {
5686 try func.genSetReg(ty, reg, .{ .immediate = addr });
5687
5688 _ = try func.addInst(.{
5689 .tag = .ld,
5690 .ops = .rri,
5691 .data = .{ .i_type = .{
5692 .rd = reg,
5693 .rs1 = reg,
5694 .imm12 = Immediate.u(0),
5695 } },
5696 });
5697 },
5698 .lea_frame, .register_offset => {
5699 _ = try func.addInst(.{
47795700 .tag = .pseudo,
47805701 .ops = .pseudo_lea_rm,
47815702 .data = .{ .rm = .{
47825703 .r = reg,
4783 .m = .{
4784 .base = .{ .frame = frame.index },
4785 .mod = .{
4786 .rm = .{
4787 .size = self.memSize(ty),
5704 .m = switch (src_mcv) {
5705 .register_offset => |reg_off| .{
5706 .base = .{ .reg = reg_off.reg },
5707 .mod = .{
5708 .size = func.memSize(ty),
5709 .disp = reg_off.off,
5710 .unsigned = false,
5711 },
5712 },
5713 .lea_frame => |frame| .{
5714 .base = .{ .frame = frame.index },
5715 .mod = .{
5716 .size = func.memSize(ty),
47885717 .disp = frame.off,
5718 .unsigned = false,
47895719 },
47905720 },
5721 else => unreachable,
47915722 },
47925723 } },
47935724 });
47945725 },
4795 .load_symbol => {
4796 try self.genSetReg(ty, reg, src_mcv.address());
4797 try self.genSetReg(ty, reg, .{ .indirect = .{ .reg = reg } });
4798 },
47995726 .indirect => |reg_off| {
5727 const float_class = dst_reg_class == .float;
5728
48005729 const load_tag: Mir.Inst.Tag = switch (abi_size) {
4801 1 => .lb,
4802 2 => .lh,
4803 4 => .lw,
4804 8 => .ld,
4805 else => return self.fail("TODO: genSetReg for size {d}", .{abi_size}),
5730 1 => if (float_class)
5731 unreachable // Zig does not support 8-bit floats
5732 else
5733 .lb,
5734 2 => if (float_class)
5735 return func.fail("TODO: genSetReg indirect 16-bit float", .{})
5736 else
5737 .lh,
5738 4 => if (float_class) .flw else .lw,
5739 8 => if (float_class) .fld else .ld,
5740 else => return std.debug.panic("TODO: genSetReg for size {d}", .{abi_size}),
48065741 };
48075742
4808 _ = try self.addInst(.{
5743 _ = try func.addInst(.{
48095744 .tag = load_tag,
48105745 .ops = .rri,
48115746 .data = .{ .i_type = .{
......@@ -4818,54 +5753,183 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, src_mcv: MCValue) InnerError!
48185753 .lea_symbol => |sym_off| {
48195754 assert(sym_off.off == 0);
48205755
4821 const atom_index = try self.symbolIndex();
5756 const atom_index = try func.symbolIndex();
48225757
4823 _ = try self.addInst(.{
5758 _ = try func.addInst(.{
48245759 .tag = .pseudo,
48255760 .ops = .pseudo_load_symbol,
4826 .data = .{ .payload = try self.addExtra(Mir.LoadSymbolPayload{
4827 .register = reg.id(),
5761 .data = .{ .payload = try func.addExtra(Mir.LoadSymbolPayload{
5762 .register = reg.encodeId(),
48285763 .atom_index = atom_index,
48295764 .sym_index = sym_off.sym,
48305765 }) },
48315766 });
48325767 },
4833 .air_ref => |ref| try self.genSetReg(ty, reg, try self.resolveInst(ref)),
4834 else => return self.fail("TODO: genSetReg {s}", .{@tagName(src_mcv)}),
5768 .load_symbol => {
5769 const addr_reg, const addr_lock = try func.allocReg(.int);
5770 defer func.register_manager.unlockReg(addr_lock);
5771
5772 try func.genSetReg(ty, addr_reg, src_mcv.address());
5773 try func.genSetReg(ty, reg, .{ .indirect = .{ .reg = addr_reg } });
5774 },
5775 .air_ref => |ref| try func.genSetReg(ty, reg, try func.resolveInst(ref)),
5776 else => return func.fail("TODO: genSetReg {s}", .{@tagName(src_mcv)}),
5777 }
5778}
5779
5780fn genSetMem(
5781 func: *Func,
5782 base: Memory.Base,
5783 disp: i32,
5784 ty: Type,
5785 src_mcv: MCValue,
5786) InnerError!void {
5787 const mod = func.bin_file.comp.module.?;
5788 const abi_size: u32 = @intCast(ty.abiSize(mod));
5789 const dst_ptr_mcv: MCValue = switch (base) {
5790 .reg => |base_reg| .{ .register_offset = .{ .reg = base_reg, .off = disp } },
5791 .frame => |base_frame_index| .{ .lea_frame = .{ .index = base_frame_index, .off = disp } },
5792 .reloc => |base_symbol| .{ .lea_symbol = .{ .sym = base_symbol.sym_index, .off = disp } },
5793 };
5794 switch (src_mcv) {
5795 .none,
5796 .unreach,
5797 .dead,
5798 .reserved_frame,
5799 => unreachable,
5800 .undef => try func.genInlineMemset(
5801 dst_ptr_mcv,
5802 src_mcv,
5803 .{ .immediate = abi_size },
5804 ),
5805 .register_offset,
5806 .memory,
5807 .indirect,
5808 .load_frame,
5809 .lea_frame,
5810 .load_symbol,
5811 .lea_symbol,
5812 => switch (abi_size) {
5813 0 => {},
5814 1, 2, 4, 8 => {
5815 // no matter what type, it should use an integer register
5816 const src_reg = try func.copyToTmpRegister(Type.usize, src_mcv);
5817 const src_lock = func.register_manager.lockRegAssumeUnused(src_reg);
5818 defer func.register_manager.unlockReg(src_lock);
5819
5820 try func.genSetMem(base, disp, ty, .{ .register = src_reg });
5821 },
5822 else => try func.genInlineMemcpy(
5823 dst_ptr_mcv,
5824 src_mcv.address(),
5825 .{ .immediate = abi_size },
5826 ),
5827 },
5828 .register => |reg| {
5829 const mem_size = switch (base) {
5830 .frame => |base_fi| mem_size: {
5831 assert(disp >= 0);
5832 const frame_abi_size = func.frame_allocs.items(.abi_size)[@intFromEnum(base_fi)];
5833 const frame_spill_pad = func.frame_allocs.items(.spill_pad)[@intFromEnum(base_fi)];
5834 assert(frame_abi_size - frame_spill_pad - disp >= abi_size);
5835 break :mem_size if (frame_abi_size - frame_spill_pad - disp == abi_size)
5836 frame_abi_size
5837 else
5838 abi_size;
5839 },
5840 else => abi_size,
5841 };
5842 const src_size = math.ceilPowerOfTwoAssert(u32, abi_size);
5843 const src_align = Alignment.fromNonzeroByteUnits(math.ceilPowerOfTwoAssert(u32, src_size));
5844 if (src_size > mem_size) {
5845 const frame_index = try func.allocFrameIndex(FrameAlloc.init(.{
5846 .size = src_size,
5847 .alignment = src_align,
5848 }));
5849 const frame_mcv: MCValue = .{ .load_frame = .{ .index = frame_index } };
5850 _ = try func.addInst(.{
5851 .tag = .pseudo,
5852 .ops = .pseudo_store_rm,
5853 .data = .{ .rm = .{
5854 .r = reg,
5855 .m = .{
5856 .base = .{ .frame = frame_index },
5857 .mod = .{
5858 .size = Memory.Size.fromByteSize(src_size),
5859 .unsigned = false,
5860 },
5861 },
5862 } },
5863 });
5864 try func.genSetMem(base, disp, ty, frame_mcv);
5865 try func.freeValue(frame_mcv);
5866 } else _ = try func.addInst(.{
5867 .tag = .pseudo,
5868 .ops = .pseudo_store_rm,
5869 .data = .{ .rm = .{
5870 .r = reg,
5871 .m = .{
5872 .base = base,
5873 .mod = .{
5874 .size = func.memSize(ty),
5875 .disp = disp,
5876 .unsigned = false,
5877 },
5878 },
5879 } },
5880 });
5881 },
5882 .register_pair => |src_regs| {
5883 var part_disp: i32 = disp;
5884 for (try func.splitType(ty), src_regs) |src_ty, src_reg| {
5885 try func.genSetMem(base, part_disp, src_ty, .{ .register = src_reg });
5886 part_disp += @intCast(src_ty.abiSize(mod));
5887 }
5888 },
5889 .immediate => {
5890 // TODO: remove this lock in favor of a copyToTmpRegister when we load 64 bit immediates with
5891 // a register allocation.
5892 const reg, const reg_lock = try func.promoteReg(ty, src_mcv);
5893 defer if (reg_lock) |lock| func.register_manager.unlockReg(lock);
5894
5895 return func.genSetMem(base, disp, ty, .{ .register = reg });
5896 },
5897 .air_ref => |src_ref| try func.genSetMem(base, disp, ty, try func.resolveInst(src_ref)),
48355898 }
48365899}
48375900
4838fn airIntFromPtr(self: *Self, inst: Air.Inst.Index) !void {
4839 const un_op = self.air.instructions.items(.data)[@intFromEnum(inst)].un_op;
5901fn airIntFromPtr(func: *Func, inst: Air.Inst.Index) !void {
5902 const un_op = func.air.instructions.items(.data)[@intFromEnum(inst)].un_op;
48405903 const result = result: {
4841 const src_mcv = try self.resolveInst(un_op);
4842 if (self.reuseOperand(inst, un_op, 0, src_mcv)) break :result src_mcv;
5904 const src_mcv = try func.resolveInst(un_op);
5905 const src_ty = func.typeOfIndex(inst);
5906 if (func.reuseOperand(inst, un_op, 0, src_mcv)) break :result src_mcv;
48435907
4844 const dst_mcv = try self.allocRegOrMem(inst, true);
4845 const dst_ty = self.typeOfIndex(inst);
4846 try self.genCopy(dst_ty, dst_mcv, src_mcv);
5908 const dst_mcv = try func.allocRegOrMem(src_ty, inst, true);
5909 const dst_ty = func.typeOfIndex(inst);
5910 try func.genCopy(dst_ty, dst_mcv, src_mcv);
48475911 break :result dst_mcv;
48485912 };
4849 return self.finishAir(inst, result, .{ un_op, .none, .none });
5913 return func.finishAir(inst, result, .{ un_op, .none, .none });
48505914}
48515915
4852fn airBitCast(self: *Self, inst: Air.Inst.Index) !void {
4853 const zcu = self.bin_file.comp.module.?;
5916fn airBitCast(func: *Func, inst: Air.Inst.Index) !void {
5917 const zcu = func.bin_file.comp.module.?;
48545918
4855 const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
4856 const result = if (self.liveness.isUnused(inst)) .unreach else result: {
4857 const src_mcv = try self.resolveInst(ty_op.operand);
5919 const ty_op = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
5920 const result = if (func.liveness.isUnused(inst)) .unreach else result: {
5921 const src_mcv = try func.resolveInst(ty_op.operand);
48585922
4859 const dst_ty = self.typeOfIndex(inst);
4860 const src_ty = self.typeOf(ty_op.operand);
5923 const dst_ty = func.typeOfIndex(inst);
5924 const src_ty = func.typeOf(ty_op.operand);
48615925
4862 const src_lock = if (src_mcv.getReg()) |reg| self.register_manager.lockReg(reg) else null;
4863 defer if (src_lock) |lock| self.register_manager.unlockReg(lock);
5926 const src_lock = if (src_mcv.getReg()) |reg| func.register_manager.lockReg(reg) else null;
5927 defer if (src_lock) |lock| func.register_manager.unlockReg(lock);
48645928
48655929 const dst_mcv = if (dst_ty.abiSize(zcu) <= src_ty.abiSize(zcu) and
4866 self.reuseOperand(inst, ty_op.operand, 0, src_mcv)) src_mcv else dst: {
4867 const dst_mcv = try self.allocRegOrMem(inst, true);
4868 try self.genCopy(switch (math.order(dst_ty.abiSize(zcu), src_ty.abiSize(zcu))) {
5930 func.reuseOperand(inst, ty_op.operand, 0, src_mcv)) src_mcv else dst: {
5931 const dst_mcv = try func.allocRegOrMem(dst_ty, inst, true);
5932 try func.genCopy(switch (math.order(dst_ty.abiSize(zcu), src_ty.abiSize(zcu))) {
48695933 .lt => dst_ty,
48705934 .eq => if (!dst_mcv.isMemory() or src_mcv.isMemory()) dst_ty else src_ty,
48715935 .gt => src_ty,
......@@ -4880,230 +5944,440 @@ fn airBitCast(self: *Self, inst: Air.Inst.Index) !void {
48805944 const bit_size = dst_ty.bitSize(zcu);
48815945 if (abi_size * 8 <= bit_size) break :result dst_mcv;
48825946
4883 return self.fail("TODO: airBitCast {} to {}", .{ src_ty.fmt(zcu), dst_ty.fmt(zcu) });
5947 return func.fail("TODO: airBitCast {} to {}", .{ src_ty.fmt(zcu), dst_ty.fmt(zcu) });
48845948 };
4885 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
4886}
5949 return func.finishAir(inst, result, .{ ty_op.operand, .none, .none });
5950}
5951
5952fn airArrayToSlice(func: *Func, inst: Air.Inst.Index) !void {
5953 const zcu = func.bin_file.comp.module.?;
5954 const ty_op = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
5955
5956 const slice_ty = func.typeOfIndex(inst);
5957 const ptr_ty = func.typeOf(ty_op.operand);
5958 const ptr = try func.resolveInst(ty_op.operand);
5959 const array_ty = ptr_ty.childType(zcu);
5960 const array_len = array_ty.arrayLen(zcu);
5961
5962 const frame_index = try func.allocFrameIndex(FrameAlloc.initSpill(slice_ty, zcu));
5963 try func.genSetMem(.{ .frame = frame_index }, 0, ptr_ty, ptr);
5964 try func.genSetMem(
5965 .{ .frame = frame_index },
5966 @intCast(ptr_ty.abiSize(zcu)),
5967 Type.usize,
5968 .{ .immediate = array_len },
5969 );
48875970
4888fn airArrayToSlice(self: *Self, inst: Air.Inst.Index) !void {
4889 const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
4890 const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else return self.fail("TODO implement airArrayToSlice for {}", .{
4891 self.target.cpu.arch,
4892 });
4893 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
5971 const result = MCValue{ .load_frame = .{ .index = frame_index } };
5972 return func.finishAir(inst, result, .{ ty_op.operand, .none, .none });
48945973}
48955974
4896fn airFloatFromInt(self: *Self, inst: Air.Inst.Index) !void {
4897 const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
4898 const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else return self.fail("TODO implement airFloatFromInt for {}", .{
4899 self.target.cpu.arch,
5975fn airFloatFromInt(func: *Func, inst: Air.Inst.Index) !void {
5976 const ty_op = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
5977 const result: MCValue = if (func.liveness.isUnused(inst)) .unreach else return func.fail("TODO implement airFloatFromInt for {}", .{
5978 func.target.cpu.arch,
49005979 });
4901 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
5980 return func.finishAir(inst, result, .{ ty_op.operand, .none, .none });
49025981}
49035982
4904fn airIntFromFloat(self: *Self, inst: Air.Inst.Index) !void {
4905 const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
4906 const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else return self.fail("TODO implement airIntFromFloat for {}", .{
4907 self.target.cpu.arch,
5983fn airIntFromFloat(func: *Func, inst: Air.Inst.Index) !void {
5984 const ty_op = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
5985 const result: MCValue = if (func.liveness.isUnused(inst)) .unreach else return func.fail("TODO implement airIntFromFloat for {}", .{
5986 func.target.cpu.arch,
49085987 });
4909 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
5988 return func.finishAir(inst, result, .{ ty_op.operand, .none, .none });
49105989}
49115990
4912fn airCmpxchg(self: *Self, inst: Air.Inst.Index) !void {
4913 const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
4914 const extra = self.air.extraData(Air.Block, ty_pl.payload);
5991fn airCmpxchg(func: *Func, inst: Air.Inst.Index) !void {
5992 const ty_pl = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
5993 const extra = func.air.extraData(Air.Block, ty_pl.payload);
49155994 _ = extra;
4916 return self.fail("TODO implement airCmpxchg for {}", .{
4917 self.target.cpu.arch,
5995 return func.fail("TODO implement airCmpxchg for {}", .{
5996 func.target.cpu.arch,
49185997 });
4919 // return self.finishAir(inst, result, .{ extra.ptr, extra.expected_value, extra.new_value });
5998 // return func.finishAir(inst, result, .{ extra.ptr, extra.expected_value, extra.new_value });
49205999}
49216000
4922fn airAtomicRmw(self: *Self, inst: Air.Inst.Index) !void {
6001fn airAtomicRmw(func: *Func, inst: Air.Inst.Index) !void {
49236002 _ = inst;
4924 return self.fail("TODO implement airCmpxchg for {}", .{self.target.cpu.arch});
6003 return func.fail("TODO implement airCmpxchg for {}", .{func.target.cpu.arch});
49256004}
49266005
4927fn airAtomicLoad(self: *Self, inst: Air.Inst.Index) !void {
6006fn airAtomicLoad(func: *Func, inst: Air.Inst.Index) !void {
49286007 _ = inst;
4929 return self.fail("TODO implement airAtomicLoad for {}", .{self.target.cpu.arch});
6008 return func.fail("TODO implement airAtomicLoad for {}", .{func.target.cpu.arch});
49306009}
49316010
4932fn airAtomicStore(self: *Self, inst: Air.Inst.Index, order: std.builtin.AtomicOrder) !void {
6011fn airAtomicStore(func: *Func, inst: Air.Inst.Index, order: std.builtin.AtomicOrder) !void {
49336012 _ = inst;
49346013 _ = order;
4935 return self.fail("TODO implement airAtomicStore for {}", .{self.target.cpu.arch});
6014 return func.fail("TODO implement airAtomicStore for {}", .{func.target.cpu.arch});
49366015}
49376016
4938fn airMemset(self: *Self, inst: Air.Inst.Index, safety: bool) !void {
4939 _ = inst;
4940 if (safety) {
4941 // TODO if the value is undef, write 0xaa bytes to dest
4942 } else {
4943 // TODO if the value is undef, don't lower this instruction
6017fn airMemset(func: *Func, inst: Air.Inst.Index, safety: bool) !void {
6018 const zcu = func.bin_file.comp.module.?;
6019 const bin_op = func.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
6020
6021 result: {
6022 if (!safety and (try func.resolveInst(bin_op.rhs)) == .undef) break :result;
6023
6024 const dst_ptr = try func.resolveInst(bin_op.lhs);
6025 const dst_ptr_ty = func.typeOf(bin_op.lhs);
6026 const dst_ptr_lock: ?RegisterLock = switch (dst_ptr) {
6027 .register => |reg| func.register_manager.lockRegAssumeUnused(reg),
6028 else => null,
6029 };
6030 defer if (dst_ptr_lock) |lock| func.register_manager.unlockReg(lock);
6031
6032 const src_val = try func.resolveInst(bin_op.rhs);
6033 const elem_ty = func.typeOf(bin_op.rhs);
6034 const src_val_lock: ?RegisterLock = switch (src_val) {
6035 .register => |reg| func.register_manager.lockRegAssumeUnused(reg),
6036 else => null,
6037 };
6038 defer if (src_val_lock) |lock| func.register_manager.unlockReg(lock);
6039
6040 const elem_abi_size: u31 = @intCast(elem_ty.abiSize(zcu));
6041
6042 if (elem_abi_size == 1) {
6043 const ptr: MCValue = switch (dst_ptr_ty.ptrSize(zcu)) {
6044 // TODO: this only handles slices stored in the stack
6045 .Slice => dst_ptr,
6046 .One => dst_ptr,
6047 .C, .Many => unreachable,
6048 };
6049 const len: MCValue = switch (dst_ptr_ty.ptrSize(zcu)) {
6050 // TODO: this only handles slices stored in the stack
6051 .Slice => dst_ptr.address().offset(8).deref(),
6052 .One => .{ .immediate = dst_ptr_ty.childType(zcu).arrayLen(zcu) },
6053 .C, .Many => unreachable,
6054 };
6055 const len_lock: ?RegisterLock = switch (len) {
6056 .register => |reg| func.register_manager.lockRegAssumeUnused(reg),
6057 else => null,
6058 };
6059 defer if (len_lock) |lock| func.register_manager.unlockReg(lock);
6060
6061 try func.genInlineMemset(ptr, src_val, len);
6062 break :result;
6063 }
6064
6065 // Store the first element, and then rely on memcpy copying forwards.
6066 // Length zero requires a runtime check - so we handle arrays specially
6067 // here to elide it.
6068 switch (dst_ptr_ty.ptrSize(zcu)) {
6069 .Slice => return func.fail("TODO: airMemset Slices", .{}),
6070 .One => {
6071 const elem_ptr_ty = try zcu.singleMutPtrType(elem_ty);
6072
6073 const len = dst_ptr_ty.childType(zcu).arrayLen(zcu);
6074
6075 assert(len != 0); // prevented by Sema
6076 try func.store(dst_ptr, src_val, elem_ptr_ty, elem_ty);
6077
6078 const second_elem_ptr_reg, const second_elem_ptr_lock = try func.allocReg(.int);
6079 defer func.register_manager.unlockReg(second_elem_ptr_lock);
6080
6081 const second_elem_ptr_mcv: MCValue = .{ .register = second_elem_ptr_reg };
6082
6083 try func.genSetReg(Type.usize, second_elem_ptr_reg, .{ .register_offset = .{
6084 .reg = try func.copyToTmpRegister(Type.usize, dst_ptr),
6085 .off = elem_abi_size,
6086 } });
6087
6088 const bytes_to_copy: MCValue = .{ .immediate = elem_abi_size * (len - 1) };
6089 try func.genInlineMemcpy(second_elem_ptr_mcv, dst_ptr, bytes_to_copy);
6090 },
6091 .C, .Many => unreachable,
6092 }
49446093 }
4945 return self.fail("TODO implement airMemset for {}", .{self.target.cpu.arch});
6094 return func.finishAir(inst, .unreach, .{ bin_op.lhs, bin_op.rhs, .none });
49466095}
49476096
4948fn airMemcpy(self: *Self, inst: Air.Inst.Index) !void {
6097fn airMemcpy(func: *Func, inst: Air.Inst.Index) !void {
49496098 _ = inst;
4950 return self.fail("TODO implement airMemcpy for {}", .{self.target.cpu.arch});
6099 return func.fail("TODO implement airMemcpy for {}", .{func.target.cpu.arch});
49516100}
49526101
4953fn airTagName(self: *Self, inst: Air.Inst.Index) !void {
4954 const un_op = self.air.instructions.items(.data)[@intFromEnum(inst)].un_op;
4955 const operand = try self.resolveInst(un_op);
4956 const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else {
6102fn airTagName(func: *Func, inst: Air.Inst.Index) !void {
6103 const un_op = func.air.instructions.items(.data)[@intFromEnum(inst)].un_op;
6104 const operand = try func.resolveInst(un_op);
6105 const result: MCValue = if (func.liveness.isUnused(inst)) .unreach else {
49576106 _ = operand;
4958 return self.fail("TODO implement airTagName for riscv64", .{});
6107 return func.fail("TODO implement airTagName for riscv64", .{});
49596108 };
4960 return self.finishAir(inst, result, .{ un_op, .none, .none });
6109 return func.finishAir(inst, result, .{ un_op, .none, .none });
49616110}
49626111
4963fn airErrorName(self: *Self, inst: Air.Inst.Index) !void {
4964 const zcu = self.bin_file.comp.module.?;
4965 const un_op = self.air.instructions.items(.data)[@intFromEnum(inst)].un_op;
6112fn airErrorName(func: *Func, inst: Air.Inst.Index) !void {
6113 const zcu = func.bin_file.comp.module.?;
6114 const un_op = func.air.instructions.items(.data)[@intFromEnum(inst)].un_op;
49666115
4967 const err_ty = self.typeOf(un_op);
4968 const err_mcv = try self.resolveInst(un_op);
6116 const err_ty = func.typeOf(un_op);
6117 const err_mcv = try func.resolveInst(un_op);
49696118
4970 const err_reg = try self.copyToTmpRegister(err_ty, err_mcv);
4971 const err_lock = self.register_manager.lockRegAssumeUnused(err_reg);
4972 defer self.register_manager.unlockReg(err_lock);
6119 const err_reg = try func.copyToTmpRegister(err_ty, err_mcv);
6120 const err_lock = func.register_manager.lockRegAssumeUnused(err_reg);
6121 defer func.register_manager.unlockReg(err_lock);
49736122
4974 const addr_reg, const addr_lock = try self.allocReg();
4975 defer self.register_manager.unlockReg(addr_lock);
6123 const addr_reg, const addr_lock = try func.allocReg(.int);
6124 defer func.register_manager.unlockReg(addr_lock);
49766125
6126 // this is now the base address of the error name table
49776127 const lazy_sym = link.File.LazySymbol.initDecl(.const_data, null, zcu);
4978 if (self.bin_file.cast(link.File.Elf)) |elf_file| {
6128 if (func.bin_file.cast(link.File.Elf)) |elf_file| {
49796129 const sym_index = elf_file.zigObjectPtr().?.getOrCreateMetadataForLazySymbol(elf_file, lazy_sym) catch |err|
4980 return self.fail("{s} creating lazy symbol", .{@errorName(err)});
6130 return func.fail("{s} creating lazy symbol", .{@errorName(err)});
49816131 const sym = elf_file.symbol(sym_index);
4982 try self.genSetReg(Type.usize, addr_reg, .{ .load_symbol = .{ .sym = sym.esym_index } });
6132 try func.genSetReg(Type.usize, addr_reg, .{ .load_symbol = .{ .sym = sym.esym_index } });
49836133 } else {
4984 return self.fail("TODO: riscv non-elf", .{});
6134 return func.fail("TODO: riscv non-elf", .{});
49856135 }
49866136
4987 const start_reg, const start_lock = try self.allocReg();
4988 defer self.register_manager.unlockReg(start_lock);
6137 const start_reg, const start_lock = try func.allocReg(.int);
6138 defer func.register_manager.unlockReg(start_lock);
6139
6140 const end_reg, const end_lock = try func.allocReg(.int);
6141 defer func.register_manager.unlockReg(end_lock);
6142
6143 // const tmp_reg, const tmp_lock = try func.allocReg(.int);
6144 // defer func.register_manager.unlockReg(tmp_lock);
6145
6146 // we move the base address forward by the following formula: base + (errno * 8)
6147
6148 // shifting left by 4 is the same as multiplying by 8
6149 _ = try func.addInst(.{
6150 .tag = .slli,
6151 .ops = .rri,
6152 .data = .{ .i_type = .{
6153 .imm12 = Immediate.u(4),
6154 .rd = err_reg,
6155 .rs1 = err_reg,
6156 } },
6157 });
6158
6159 _ = try func.addInst(.{
6160 .tag = .add,
6161 .ops = .rrr,
6162 .data = .{ .r_type = .{
6163 .rd = addr_reg,
6164 .rs1 = addr_reg,
6165 .rs2 = err_reg,
6166 } },
6167 });
6168
6169 _ = try func.addInst(.{
6170 .tag = .pseudo,
6171 .ops = .pseudo_load_rm,
6172 .data = .{
6173 .rm = .{
6174 .r = start_reg,
6175 .m = .{
6176 .base = .{ .reg = addr_reg },
6177 .mod = .{ .size = .dword, .unsigned = true },
6178 },
6179 },
6180 },
6181 });
6182
6183 _ = try func.addInst(.{
6184 .tag = .pseudo,
6185 .ops = .pseudo_load_rm,
6186 .data = .{
6187 .rm = .{
6188 .r = end_reg,
6189 .m = .{
6190 .base = .{ .reg = addr_reg },
6191 .mod = .{ .size = .dword, .unsigned = true },
6192 },
6193 },
6194 },
6195 });
49896196
4990 const end_reg, const end_lock = try self.allocReg();
4991 defer self.register_manager.unlockReg(end_lock);
6197 const dst_mcv = try func.allocRegOrMem(func.typeOfIndex(inst), inst, false);
6198 const frame = dst_mcv.load_frame;
6199 try func.genSetMem(
6200 .{ .frame = frame.index },
6201 frame.off,
6202 Type.usize,
6203 .{ .register = start_reg },
6204 );
49926205
4993 _ = start_reg;
4994 _ = end_reg;
6206 try func.genSetMem(
6207 .{ .frame = frame.index },
6208 frame.off + 8,
6209 Type.usize,
6210 .{ .register = end_reg },
6211 );
49956212
4996 return self.fail("TODO: airErrorName", .{});
6213 return func.finishAir(inst, dst_mcv, .{ un_op, .none, .none });
49976214}
49986215
4999fn airSplat(self: *Self, inst: Air.Inst.Index) !void {
5000 const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
5001 const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else return self.fail("TODO implement airSplat for riscv64", .{});
5002 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
6216fn airSplat(func: *Func, inst: Air.Inst.Index) !void {
6217 const ty_op = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
6218 const result: MCValue = if (func.liveness.isUnused(inst)) .unreach else return func.fail("TODO implement airSplat for riscv64", .{});
6219 return func.finishAir(inst, result, .{ ty_op.operand, .none, .none });
50036220}
50046221
5005fn airSelect(self: *Self, inst: Air.Inst.Index) !void {
5006 const pl_op = self.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;
5007 const extra = self.air.extraData(Air.Bin, pl_op.payload).data;
5008 const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else return self.fail("TODO implement airSelect for riscv64", .{});
5009 return self.finishAir(inst, result, .{ pl_op.operand, extra.lhs, extra.rhs });
6222fn airSelect(func: *Func, inst: Air.Inst.Index) !void {
6223 const pl_op = func.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;
6224 const extra = func.air.extraData(Air.Bin, pl_op.payload).data;
6225 const result: MCValue = if (func.liveness.isUnused(inst)) .unreach else return func.fail("TODO implement airSelect for riscv64", .{});
6226 return func.finishAir(inst, result, .{ pl_op.operand, extra.lhs, extra.rhs });
50106227}
50116228
5012fn airShuffle(self: *Self, inst: Air.Inst.Index) !void {
5013 const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
5014 const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else return self.fail("TODO implement airShuffle for riscv64", .{});
5015 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
6229fn airShuffle(func: *Func, inst: Air.Inst.Index) !void {
6230 const ty_op = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
6231 const result: MCValue = if (func.liveness.isUnused(inst)) .unreach else return func.fail("TODO implement airShuffle for riscv64", .{});
6232 return func.finishAir(inst, result, .{ ty_op.operand, .none, .none });
50166233}
50176234
5018fn airReduce(self: *Self, inst: Air.Inst.Index) !void {
5019 const reduce = self.air.instructions.items(.data)[@intFromEnum(inst)].reduce;
5020 const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else return self.fail("TODO implement airReduce for riscv64", .{});
5021 return self.finishAir(inst, result, .{ reduce.operand, .none, .none });
6235fn airReduce(func: *Func, inst: Air.Inst.Index) !void {
6236 const reduce = func.air.instructions.items(.data)[@intFromEnum(inst)].reduce;
6237 const result: MCValue = if (func.liveness.isUnused(inst)) .unreach else return func.fail("TODO implement airReduce for riscv64", .{});
6238 return func.finishAir(inst, result, .{ reduce.operand, .none, .none });
50226239}
50236240
5024fn airAggregateInit(self: *Self, inst: Air.Inst.Index) !void {
5025 const zcu = self.bin_file.comp.module.?;
5026 const result_ty = self.typeOfIndex(inst);
6241fn airAggregateInit(func: *Func, inst: Air.Inst.Index) !void {
6242 const zcu = func.bin_file.comp.module.?;
6243 const result_ty = func.typeOfIndex(inst);
50276244 const len: usize = @intCast(result_ty.arrayLen(zcu));
5028 const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
5029 const elements: []const Air.Inst.Ref = @ptrCast(self.air.extra[ty_pl.payload..][0..len]);
6245 const ty_pl = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
6246 const elements: []const Air.Inst.Ref = @ptrCast(func.air.extra[ty_pl.payload..][0..len]);
6247
50306248 const result: MCValue = result: {
50316249 switch (result_ty.zigTypeTag(zcu)) {
50326250 .Struct => {
5033 const frame_index = try self.allocFrameIndex(FrameAlloc.initSpill(result_ty, zcu));
6251 const frame_index = try func.allocFrameIndex(FrameAlloc.initSpill(result_ty, zcu));
6252 if (result_ty.containerLayout(zcu) == .@"packed") {
6253 const struct_obj = zcu.typeToStruct(result_ty).?;
6254 try func.genInlineMemset(
6255 .{ .lea_frame = .{ .index = frame_index } },
6256 .{ .immediate = 0 },
6257 .{ .immediate = result_ty.abiSize(zcu) },
6258 );
50346259
5035 if (result_ty.containerLayout(zcu) == .@"packed") {} else for (elements, 0..) |elem, elem_i| {
6260 for (elements, 0..) |elem, elem_i_usize| {
6261 const elem_i: u32 = @intCast(elem_i_usize);
6262 if ((try result_ty.structFieldValueComptime(zcu, elem_i)) != null) continue;
6263
6264 const elem_ty = result_ty.structFieldType(elem_i, zcu);
6265 const elem_bit_size: u32 = @intCast(elem_ty.bitSize(zcu));
6266 if (elem_bit_size > 64) {
6267 return func.fail(
6268 "TODO airAggregateInit implement packed structs with large fields",
6269 .{},
6270 );
6271 }
6272
6273 const elem_abi_size: u32 = @intCast(elem_ty.abiSize(zcu));
6274 const elem_abi_bits = elem_abi_size * 8;
6275 const elem_off = zcu.structPackedFieldBitOffset(struct_obj, elem_i);
6276 const elem_byte_off: i32 = @intCast(elem_off / elem_abi_bits * elem_abi_size);
6277 const elem_bit_off = elem_off % elem_abi_bits;
6278 const elem_mcv = try func.resolveInst(elem);
6279
6280 _ = elem_byte_off;
6281 _ = elem_bit_off;
6282
6283 const elem_lock = switch (elem_mcv) {
6284 .register => |reg| func.register_manager.lockReg(reg),
6285 .immediate => |imm| lock: {
6286 if (imm == 0) continue;
6287 break :lock null;
6288 },
6289 else => null,
6290 };
6291 defer if (elem_lock) |lock| func.register_manager.unlockReg(lock);
6292
6293 return func.fail("TODO: airAggregateInit packed structs", .{});
6294 }
6295 } else for (elements, 0..) |elem, elem_i| {
50366296 if ((try result_ty.structFieldValueComptime(zcu, elem_i)) != null) continue;
50376297
50386298 const elem_ty = result_ty.structFieldType(elem_i, zcu);
50396299 const elem_off: i32 = @intCast(result_ty.structFieldOffset(elem_i, zcu));
5040 const elem_mcv = try self.resolveInst(elem);
5041
5042 const elem_frame: FrameAddr = .{
5043 .index = frame_index,
5044 .off = elem_off,
5045 };
5046 try self.genSetStack(
6300 const elem_mcv = try func.resolveInst(elem);
6301 try func.genSetMem(.{ .frame = frame_index }, elem_off, elem_ty, elem_mcv);
6302 }
6303 break :result .{ .load_frame = .{ .index = frame_index } };
6304 },
6305 .Array => {
6306 const elem_ty = result_ty.childType(zcu);
6307 const frame_index = try func.allocFrameIndex(FrameAlloc.initSpill(result_ty, zcu));
6308 const elem_size: u32 = @intCast(elem_ty.abiSize(zcu));
6309
6310 for (elements, 0..) |elem, elem_i| {
6311 const elem_mcv = try func.resolveInst(elem);
6312 const elem_off: i32 = @intCast(elem_size * elem_i);
6313 try func.genSetMem(
6314 .{ .frame = frame_index },
6315 elem_off,
50476316 elem_ty,
5048 elem_frame,
50496317 elem_mcv,
50506318 );
50516319 }
6320 if (result_ty.sentinel(zcu)) |sentinel| try func.genSetMem(
6321 .{ .frame = frame_index },
6322 @intCast(elem_size * elements.len),
6323 elem_ty,
6324 try func.genTypedValue(sentinel),
6325 );
6326 break :result .{ .load_frame = .{ .index = frame_index } };
50526327 },
5053 else => return self.fail("TODO: airAggregateInit {}", .{result_ty.fmt(zcu)}),
6328 else => return func.fail("TODO: airAggregate {}", .{result_ty.fmt(zcu)}),
50546329 }
5055 break :result .{ .register = .zero };
50566330 };
50576331
50586332 if (elements.len <= Liveness.bpi - 1) {
50596333 var buf = [1]Air.Inst.Ref{.none} ** (Liveness.bpi - 1);
50606334 @memcpy(buf[0..elements.len], elements);
5061 return self.finishAir(inst, result, buf);
6335 return func.finishAir(inst, result, buf);
50626336 }
5063 var bt = self.liveness.iterateBigTomb(inst);
5064 for (elements) |elem| try self.feed(&bt, elem);
5065 return self.finishAirResult(inst, result);
6337 var bt = func.liveness.iterateBigTomb(inst);
6338 for (elements) |elem| try func.feed(&bt, elem);
6339 return func.finishAirResult(inst, result);
50666340}
50676341
5068fn airUnionInit(self: *Self, inst: Air.Inst.Index) !void {
5069 const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
5070 const extra = self.air.extraData(Air.UnionInit, ty_pl.payload).data;
6342fn airUnionInit(func: *Func, inst: Air.Inst.Index) !void {
6343 const ty_pl = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
6344 const extra = func.air.extraData(Air.UnionInit, ty_pl.payload).data;
50716345 _ = extra;
5072 return self.fail("TODO implement airUnionInit for riscv64", .{});
5073 // return self.finishAir(inst, result, .{ extra.ptr, extra.expected_value, extra.new_value });
6346 return func.fail("TODO implement airUnionInit for riscv64", .{});
6347 // return func.finishAir(inst, result, .{ extra.ptr, extra.expected_value, extra.new_value });
50746348}
50756349
5076fn airPrefetch(self: *Self, inst: Air.Inst.Index) !void {
5077 const prefetch = self.air.instructions.items(.data)[@intFromEnum(inst)].prefetch;
6350fn airPrefetch(func: *Func, inst: Air.Inst.Index) !void {
6351 const prefetch = func.air.instructions.items(.data)[@intFromEnum(inst)].prefetch;
50786352 // TODO: RISC-V does have prefetch instruction variants.
50796353 // see here: https://raw.githubusercontent.com/riscv/riscv-CMOs/master/specifications/cmobase-v1.0.1.pdf
5080 return self.finishAir(inst, .unreach, .{ prefetch.ptr, .none, .none });
6354 return func.finishAir(inst, .unreach, .{ prefetch.ptr, .none, .none });
50816355}
50826356
5083fn airMulAdd(self: *Self, inst: Air.Inst.Index) !void {
5084 const pl_op = self.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;
5085 const extra = self.air.extraData(Air.Bin, pl_op.payload).data;
5086 const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else {
5087 return self.fail("TODO implement airMulAdd for riscv64", .{});
6357fn airMulAdd(func: *Func, inst: Air.Inst.Index) !void {
6358 const pl_op = func.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;
6359 const extra = func.air.extraData(Air.Bin, pl_op.payload).data;
6360 const result: MCValue = if (func.liveness.isUnused(inst)) .unreach else {
6361 return func.fail("TODO implement airMulAdd for riscv64", .{});
50886362 };
5089 return self.finishAir(inst, result, .{ extra.lhs, extra.rhs, pl_op.operand });
6363 return func.finishAir(inst, result, .{ extra.lhs, extra.rhs, pl_op.operand });
50906364}
50916365
5092fn resolveInst(self: *Self, ref: Air.Inst.Ref) InnerError!MCValue {
5093 const zcu = self.bin_file.comp.module.?;
6366fn resolveInst(func: *Func, ref: Air.Inst.Ref) InnerError!MCValue {
6367 const zcu = func.bin_file.comp.module.?;
50946368
50956369 // If the type has no codegen bits, no need to store it.
5096 const inst_ty = self.typeOf(ref);
6370 const inst_ty = func.typeOf(ref);
50976371 if (!inst_ty.hasRuntimeBits(zcu))
50986372 return .none;
50996373
51006374 const mcv = if (ref.toIndex()) |inst| mcv: {
5101 break :mcv self.inst_tracking.getPtr(inst).?.short;
6375 break :mcv func.inst_tracking.getPtr(inst).?.short;
51026376 } else mcv: {
51036377 const ip_index = ref.toInterned().?;
5104 const gop = try self.const_tracking.getOrPut(self.gpa, ip_index);
6378 const gop = try func.const_tracking.getOrPut(func.gpa, ip_index);
51056379 if (!gop.found_existing) gop.value_ptr.* = InstTracking.init(
5106 try self.genTypedValue(Value.fromInterned(ip_index)),
6380 try func.genTypedValue(Value.fromInterned(ip_index)),
51076381 );
51086382 break :mcv gop.value_ptr.short;
51096383 };
......@@ -5111,21 +6385,21 @@ fn resolveInst(self: *Self, ref: Air.Inst.Ref) InnerError!MCValue {
51116385 return mcv;
51126386}
51136387
5114fn getResolvedInstValue(self: *Self, inst: Air.Inst.Index) *InstTracking {
5115 const tracking = self.inst_tracking.getPtr(inst).?;
6388fn getResolvedInstValue(func: *Func, inst: Air.Inst.Index) *InstTracking {
6389 const tracking = func.inst_tracking.getPtr(inst).?;
51166390 return switch (tracking.short) {
51176391 .none, .unreach, .dead => unreachable,
51186392 else => tracking,
51196393 };
51206394}
51216395
5122fn genTypedValue(self: *Self, val: Value) InnerError!MCValue {
5123 const zcu = self.bin_file.comp.module.?;
6396fn genTypedValue(func: *Func, val: Value) InnerError!MCValue {
6397 const zcu = func.bin_file.comp.module.?;
51246398 const result = try codegen.genTypedValue(
5125 self.bin_file,
5126 self.src_loc,
6399 func.bin_file,
6400 func.src_loc,
51276401 val,
5128 zcu.funcOwnerDeclIndex(self.func_index),
6402 zcu.funcOwnerDeclIndex(func.func_index),
51296403 );
51306404 const mcv: MCValue = switch (result) {
51316405 .mcv => |mcv| switch (mcv) {
......@@ -5135,11 +6409,11 @@ fn genTypedValue(self: *Self, val: Value) InnerError!MCValue {
51356409 .immediate => |imm| .{ .immediate = imm },
51366410 .memory => |addr| .{ .memory = addr },
51376411 .load_got, .load_direct, .load_tlv => {
5138 return self.fail("TODO: genTypedValue {s}", .{@tagName(mcv)});
6412 return func.fail("TODO: genTypedValue {s}", .{@tagName(mcv)});
51396413 },
51406414 },
51416415 .fail => |msg| {
5142 self.err_msg = msg;
6416 func.err_msg = msg;
51436417 return error.CodegenFail;
51446418 },
51456419 };
......@@ -5152,36 +6426,39 @@ const CallMCValues = struct {
51526426 stack_byte_count: u31,
51536427 stack_align: Alignment,
51546428
5155 fn deinit(self: *CallMCValues, func: *Self) void {
5156 func.gpa.free(self.args);
5157 self.* = undefined;
6429 fn deinit(call: *CallMCValues, func: *Func) void {
6430 func.gpa.free(call.args);
6431 call.* = undefined;
51586432 }
51596433};
51606434
51616435/// Caller must call `CallMCValues.deinit`.
51626436fn resolveCallingConventionValues(
5163 self: *Self,
6437 func: *Func,
51646438 fn_info: InternPool.Key.FuncType,
6439 var_args: []const Type,
51656440) !CallMCValues {
5166 const zcu = self.bin_file.comp.module.?;
6441 const zcu = func.bin_file.comp.module.?;
51676442 const ip = &zcu.intern_pool;
51686443
5169 const param_types = try self.gpa.alloc(Type, fn_info.param_types.len);
5170 defer self.gpa.free(param_types);
6444 const param_types = try func.gpa.alloc(Type, fn_info.param_types.len + var_args.len);
6445 defer func.gpa.free(param_types);
51716446
51726447 for (param_types[0..fn_info.param_types.len], fn_info.param_types.get(ip)) |*dest, src| {
51736448 dest.* = Type.fromInterned(src);
51746449 }
6450 for (param_types[fn_info.param_types.len..], var_args) |*param_ty, arg_ty|
6451 param_ty.* = func.promoteVarArg(arg_ty);
51756452
51766453 const cc = fn_info.cc;
51776454 var result: CallMCValues = .{
5178 .args = try self.gpa.alloc(MCValue, param_types.len),
6455 .args = try func.gpa.alloc(MCValue, param_types.len),
51796456 // These undefined values must be populated before returning from this function.
51806457 .return_value = undefined,
51816458 .stack_byte_count = 0,
51826459 .stack_align = undefined,
51836460 };
5184 errdefer self.gpa.free(result.args);
6461 errdefer func.gpa.free(result.args);
51856462
51866463 const ret_ty = Type.fromInterned(fn_info.return_type);
51876464
......@@ -5193,7 +6470,7 @@ fn resolveCallingConventionValues(
51936470 },
51946471 .C, .Unspecified => {
51956472 if (result.args.len > 8) {
5196 return self.fail("RISC-V calling convention does not support more than 8 arguments", .{});
6473 return func.fail("RISC-V calling convention does not support more than 8 arguments", .{});
51976474 }
51986475
51996476 var ret_int_reg_i: u32 = 0;
......@@ -5209,21 +6486,29 @@ fn resolveCallingConventionValues(
52096486 } else {
52106487 var ret_tracking: [2]InstTracking = undefined;
52116488 var ret_tracking_i: usize = 0;
6489 var ret_float_reg_i: usize = 0;
52126490
52136491 const classes = mem.sliceTo(&abi.classifySystem(ret_ty, zcu), .none);
52146492
52156493 for (classes) |class| switch (class) {
52166494 .integer => {
5217 const ret_int_reg = abi.function_ret_regs[ret_int_reg_i];
6495 const ret_int_reg = abi.Registers.Integer.function_ret_regs[ret_int_reg_i];
52186496 ret_int_reg_i += 1;
52196497
52206498 ret_tracking[ret_tracking_i] = InstTracking.init(.{ .register = ret_int_reg });
52216499 ret_tracking_i += 1;
52226500 },
6501 .float => {
6502 const ret_float_reg = abi.Registers.Float.function_ret_regs[ret_float_reg_i];
6503 ret_float_reg_i += 1;
6504
6505 ret_tracking[ret_tracking_i] = InstTracking.init(.{ .register = ret_float_reg });
6506 ret_tracking_i += 1;
6507 },
52236508 .memory => {
5224 const ret_int_reg = abi.function_ret_regs[ret_int_reg_i];
6509 const ret_int_reg = abi.Registers.Integer.function_ret_regs[ret_int_reg_i];
52256510 ret_int_reg_i += 1;
5226 const ret_indirect_reg = abi.function_arg_regs[param_int_reg_i];
6511 const ret_indirect_reg = abi.Registers.Integer.function_arg_regs[param_int_reg_i];
52276512 param_int_reg_i += 1;
52286513
52296514 ret_tracking[ret_tracking_i] = .{
......@@ -5232,11 +6517,11 @@ fn resolveCallingConventionValues(
52326517 };
52336518 ret_tracking_i += 1;
52346519 },
5235 else => return self.fail("TODO: C calling convention return class {}", .{class}),
6520 else => return func.fail("TODO: C calling convention return class {}", .{class}),
52366521 };
52376522
52386523 result.return_value = switch (ret_tracking_i) {
5239 else => return self.fail("ty {} took {} tracking return indices", .{ ret_ty.fmt(zcu), ret_tracking_i }),
6524 else => return func.fail("ty {} took {} tracking return indices", .{ ret_ty.fmt(zcu), ret_tracking_i }),
52406525 1 => ret_tracking[0],
52416526 2 => InstTracking.init(.{ .register_pair = .{
52426527 ret_tracking[0].short.register, ret_tracking[1].short.register,
......@@ -5244,8 +6529,14 @@ fn resolveCallingConventionValues(
52446529 };
52456530 }
52466531
6532 var param_float_reg_i: usize = 0;
6533
52476534 for (param_types, result.args) |ty, *arg| {
5248 assert(ty.hasRuntimeBitsIgnoreComptime(zcu));
6535 if (!ty.hasRuntimeBitsIgnoreComptime(zcu)) {
6536 assert(cc == .Unspecified);
6537 arg.* = .none;
6538 continue;
6539 }
52496540
52506541 var arg_mcv: [2]MCValue = undefined;
52516542 var arg_mcv_i: usize = 0;
......@@ -5254,7 +6545,7 @@ fn resolveCallingConventionValues(
52546545
52556546 for (classes) |class| switch (class) {
52566547 .integer => {
5257 const param_int_regs = abi.function_arg_regs;
6548 const param_int_regs = abi.Registers.Integer.function_arg_regs;
52586549 if (param_int_reg_i >= param_int_regs.len) break;
52596550
52606551 const param_int_reg = param_int_regs[param_int_reg_i];
......@@ -5263,36 +6554,47 @@ fn resolveCallingConventionValues(
52636554 arg_mcv[arg_mcv_i] = .{ .register = param_int_reg };
52646555 arg_mcv_i += 1;
52656556 },
6557 .float => {
6558 const param_float_regs = abi.Registers.Float.function_arg_regs;
6559 if (param_float_reg_i >= param_float_regs.len) break;
6560
6561 const param_float_reg = param_float_regs[param_float_reg_i];
6562 param_float_reg_i += 1;
6563
6564 arg_mcv[arg_mcv_i] = .{ .register = param_float_reg };
6565 arg_mcv_i += 1;
6566 },
52666567 .memory => {
5267 const param_int_regs = abi.function_arg_regs;
6568 const param_int_regs = abi.Registers.Integer.function_arg_regs;
6569
52686570 const param_int_reg = param_int_regs[param_int_reg_i];
6571 param_int_reg_i += 1;
52696572
52706573 arg_mcv[arg_mcv_i] = .{ .indirect = .{ .reg = param_int_reg } };
52716574 arg_mcv_i += 1;
52726575 },
5273 else => return self.fail("TODO: C calling convention arg class {}", .{class}),
6576 else => return func.fail("TODO: C calling convention arg class {}", .{class}),
52746577 } else {
52756578 arg.* = switch (arg_mcv_i) {
5276 else => return self.fail("ty {} took {} tracking arg indices", .{ ty.fmt(zcu), arg_mcv_i }),
6579 else => return func.fail("ty {} took {} tracking arg indices", .{ ty.fmt(zcu), arg_mcv_i }),
52776580 1 => arg_mcv[0],
52786581 2 => .{ .register_pair = .{ arg_mcv[0].register, arg_mcv[1].register } },
52796582 };
52806583 continue;
52816584 }
52826585
5283 return self.fail("TODO: pass args by stack", .{});
6586 return func.fail("TODO: pass args by stack", .{});
52846587 }
52856588 },
5286 else => return self.fail("TODO implement function parameters for {} on riscv64", .{cc}),
6589 else => return func.fail("TODO implement function parameters for {} on riscv64", .{cc}),
52876590 }
52886591
52896592 result.stack_byte_count = @intCast(result.stack_align.forward(result.stack_byte_count));
52906593 return result;
52916594}
52926595
5293/// TODO support scope overrides. Also note this logic is duplicated with `Module.wantSafety`.
5294fn wantSafety(self: *Self) bool {
5295 return switch (self.bin_file.comp.root_mod.optimize_mode) {
6596fn wantSafety(func: *Func) bool {
6597 return switch (func.mod.optimize_mode) {
52966598 .Debug => true,
52976599 .ReleaseSafe => true,
52986600 .ReleaseFast => false,
......@@ -5300,39 +6602,36 @@ fn wantSafety(self: *Self) bool {
53006602 };
53016603}
53026604
5303fn fail(self: *Self, comptime format: []const u8, args: anytype) InnerError {
6605fn fail(func: *Func, comptime format: []const u8, args: anytype) InnerError {
53046606 @setCold(true);
5305 assert(self.err_msg == null);
5306 self.err_msg = try ErrorMsg.create(self.gpa, self.src_loc, format, args);
6607 assert(func.err_msg == null);
6608 func.err_msg = try ErrorMsg.create(func.gpa, func.src_loc, format, args);
53076609 return error.CodegenFail;
53086610}
53096611
5310fn failSymbol(self: *Self, comptime format: []const u8, args: anytype) InnerError {
6612fn failSymbol(func: *Func, comptime format: []const u8, args: anytype) InnerError {
53116613 @setCold(true);
5312 assert(self.err_msg == null);
5313 self.err_msg = try ErrorMsg.create(self.gpa, self.src_loc, format, args);
6614 assert(func.err_msg == null);
6615 func.err_msg = try ErrorMsg.create(func.gpa, func.src_loc, format, args);
53146616 return error.CodegenFail;
53156617}
53166618
53176619fn parseRegName(name: []const u8) ?Register {
5318 if (@hasDecl(Register, "parseRegName")) {
5319 return Register.parseRegName(name);
5320 }
53216620 return std.meta.stringToEnum(Register, name);
53226621}
53236622
5324fn typeOf(self: *Self, inst: Air.Inst.Ref) Type {
5325 const zcu = self.bin_file.comp.module.?;
5326 return self.air.typeOf(inst, &zcu.intern_pool);
6623fn typeOf(func: *Func, inst: Air.Inst.Ref) Type {
6624 const zcu = func.bin_file.comp.module.?;
6625 return func.air.typeOf(inst, &zcu.intern_pool);
53276626}
53286627
5329fn typeOfIndex(self: *Self, inst: Air.Inst.Index) Type {
5330 const zcu = self.bin_file.comp.module.?;
5331 return self.air.typeOfIndex(inst, &zcu.intern_pool);
6628fn typeOfIndex(func: *Func, inst: Air.Inst.Index) Type {
6629 const zcu = func.bin_file.comp.module.?;
6630 return func.air.typeOfIndex(inst, &zcu.intern_pool);
53326631}
53336632
5334fn hasFeature(self: *Self, feature: Target.riscv.Feature) bool {
5335 return Target.riscv.featureSetHas(self.target.cpu.features, feature);
6633fn hasFeature(func: *Func, feature: Target.riscv.Feature) bool {
6634 return Target.riscv.featureSetHas(func.target.cpu.features, feature);
53366635}
53376636
53386637pub fn errUnionPayloadOffset(payload_ty: Type, zcu: *Module) u64 {
......@@ -5356,3 +6655,33 @@ pub fn errUnionErrorOffset(payload_ty: Type, zcu: *Module) u64 {
53566655 return 0;
53576656 }
53586657}
6658
6659fn promoteInt(func: *Func, ty: Type) Type {
6660 const mod = func.bin_file.comp.module.?;
6661 const int_info: InternPool.Key.IntType = switch (ty.toIntern()) {
6662 .bool_type => .{ .signedness = .unsigned, .bits = 1 },
6663 else => if (ty.isAbiInt(mod)) ty.intInfo(mod) else return ty,
6664 };
6665 for ([_]Type{
6666 Type.c_int, Type.c_uint,
6667 Type.c_long, Type.c_ulong,
6668 Type.c_longlong, Type.c_ulonglong,
6669 }) |promote_ty| {
6670 const promote_info = promote_ty.intInfo(mod);
6671 if (int_info.signedness == .signed and promote_info.signedness == .unsigned) continue;
6672 if (int_info.bits + @intFromBool(int_info.signedness == .unsigned and
6673 promote_info.signedness == .signed) <= promote_info.bits) return promote_ty;
6674 }
6675 return ty;
6676}
6677
6678fn promoteVarArg(func: *Func, ty: Type) Type {
6679 if (!ty.isRuntimeFloat()) return func.promoteInt(ty);
6680 switch (ty.floatBits(func.target.*)) {
6681 32, 64 => return Type.f64,
6682 else => |float_bits| {
6683 assert(float_bits == func.target.c_type_bit_size(.longdouble));
6684 return Type.c_longdouble;
6685 },
6686 }
6687}
src/arch/riscv64/Emit.zig+20-1
......@@ -42,6 +42,12 @@ pub fn emitMir(emit: *Emit) Error!void {
4242 .enc = std.meta.activeTag(lowered_inst.encoding.data),
4343 }),
4444 .load_symbol_reloc => |symbol| {
45 const is_obj_or_static_lib = switch (emit.lower.output_mode) {
46 .Exe => false,
47 .Obj => true,
48 .Lib => emit.lower.link_mode == .static,
49 };
50
4551 if (emit.lower.bin_file.cast(link.File.Elf)) |elf_file| {
4652 const atom_ptr = elf_file.symbol(symbol.atom_index).atom(elf_file).?;
4753 const sym_index = elf_file.zigObjectPtr().?.symbol(symbol.sym_index);
......@@ -50,7 +56,7 @@ pub fn emitMir(emit: *Emit) Error!void {
5056 var hi_r_type: u32 = @intFromEnum(std.elf.R_RISCV.HI20);
5157 var lo_r_type: u32 = @intFromEnum(std.elf.R_RISCV.LO12_I);
5258
53 if (sym.flags.needs_zig_got) {
59 if (sym.flags.needs_zig_got and !is_obj_or_static_lib) {
5460 _ = try sym.getOrCreateZigGotEntry(sym_index, elf_file);
5561
5662 hi_r_type = Elf.R_ZIG_GOT_HI20;
......@@ -70,6 +76,19 @@ pub fn emitMir(emit: *Emit) Error!void {
7076 });
7177 } else return emit.fail("TODO: load_symbol_reloc non-ELF", .{});
7278 },
79 .call_extern_fn_reloc => |symbol| {
80 if (emit.lower.bin_file.cast(link.File.Elf)) |elf_file| {
81 const atom_ptr = elf_file.symbol(symbol.atom_index).atom(elf_file).?;
82
83 const r_type: u32 = @intFromEnum(std.elf.R_RISCV.CALL_PLT);
84
85 try atom_ptr.addReloc(elf_file, .{
86 .r_offset = start_offset,
87 .r_info = (@as(u64, @intCast(symbol.sym_index)) << 32) | r_type,
88 .r_addend = 0,
89 });
90 } else return emit.fail("TODO: call_extern_fn_reloc non-ELF", .{});
91 },
7392 };
7493 }
7594 std.debug.assert(lowered_relocs.len == 0);
src/arch/riscv64/Encoding.zig+477-97
......@@ -1,7 +1,71 @@
11mnemonic: Mnemonic,
22data: Data,
33
4const OpCode = enum(u7) {
5 OP = 0b0110011,
6 OP_IMM = 0b0010011,
7 OP_IMM_32 = 0b0011011,
8 OP_32 = 0b0111011,
9
10 BRANCH = 0b1100011,
11 LOAD = 0b0000011,
12 STORE = 0b0100011,
13 SYSTEM = 0b1110011,
14
15 OP_FP = 0b1010011,
16 LOAD_FP = 0b0000111,
17 STORE_FP = 0b0100111,
18
19 JALR = 0b1100111,
20 AUIPC = 0b0010111,
21 LUI = 0b0110111,
22 JAL = 0b1101111,
23 NONE = 0b0000000,
24};
25
26const Fmt = enum(u2) {
27 /// 32-bit single-precision
28 S = 0b00,
29 /// 64-bit double-precision
30 D = 0b01,
31 _reserved = 0b10,
32 /// 128-bit quad-precision
33 Q = 0b11,
34};
35
36const Enc = struct {
37 opcode: OpCode,
38
39 data: union(enum) {
40 /// funct3 + funct7
41 ff: struct {
42 funct3: u3,
43 funct7: u7,
44 },
45 /// funct5 + rm + fmt
46 fmt: struct {
47 funct5: u5,
48 rm: u3,
49 fmt: Fmt,
50 },
51 /// funct3
52 f: struct {
53 funct3: u3,
54 },
55 /// typ + funct3 + has_5
56 sh: struct {
57 typ: u6,
58 funct3: u3,
59 has_5: bool,
60 },
61 /// U-type
62 none,
63 },
64};
65
466pub const Mnemonic = enum {
67 // base mnemonics
68
569 // I Type
670 ld,
771 lw,
......@@ -10,18 +74,25 @@ pub const Mnemonic = enum {
1074 lhu,
1175 lb,
1276 lbu,
77
1378 sltiu,
1479 xori,
1580 andi,
81
1682 slli,
1783 srli,
1884 srai,
1985
86 slliw,
87 srliw,
88 sraiw,
89
2090 addi,
2191 jalr,
2292
2393 // U Type
2494 lui,
95 auipc,
2596
2697 // S Type
2798 sd,
......@@ -37,64 +108,265 @@ pub const Mnemonic = enum {
37108
38109 // R Type
39110 add,
40 @"and",
111 addw,
41112 sub,
113 subw,
114 @"and",
115 @"or",
42116 slt,
43 mul,
44117 sltu,
45118 xor,
46119
120 sll,
121 srl,
122 sra,
123
124 sllw,
125 srlw,
126 sraw,
127
47128 // System
48129 ecall,
49130 ebreak,
50131 unimp,
51132
133 // M extension
134 mul,
135 mulw,
136
137 mulh,
138 mulhu,
139 mulhsu,
140
141 div,
142 divu,
143
144 divw,
145 divuw,
146
147 rem,
148 remu,
149
150 remw,
151 remuw,
152
153 // F extension (32-bit float)
154 fadds,
155 fsubs,
156 fmuls,
157 fdivs,
158
159 fmins,
160 fmaxs,
161
162 fsqrts,
163
164 flw,
165 fsw,
166
167 feqs,
168 flts,
169 fles,
170
171 fsgnjns,
172 fsgnjxs,
173
174 // D extension (64-bit float)
175 faddd,
176 fsubd,
177 fmuld,
178 fdivd,
179
180 fmind,
181 fmaxd,
182
183 fsqrtd,
184
185 fld,
186 fsd,
187
188 feqd,
189 fltd,
190 fled,
191
192 fsgnjnd,
193 fsgnjxd,
194
52195 pub fn encoding(mnem: Mnemonic) Enc {
53196 return switch (mnem) {
54197 // zig fmt: off
55 .add => .{ .opcode = 0b0110011, .funct3 = 0b000, .funct7 = 0b0000000 },
56 .sltu => .{ .opcode = 0b0110011, .funct3 = 0b011, .funct7 = 0b0000000 },
57 .@"and" => .{ .opcode = 0b0110011, .funct3 = 0b111, .funct7 = 0b0000000 },
58 .sub => .{ .opcode = 0b0110011, .funct3 = 0b000, .funct7 = 0b0100000 },
59198
60 .ld => .{ .opcode = 0b0000011, .funct3 = 0b011, .funct7 = null },
61 .lw => .{ .opcode = 0b0000011, .funct3 = 0b010, .funct7 = null },
62 .lwu => .{ .opcode = 0b0000011, .funct3 = 0b110, .funct7 = null },
63 .lh => .{ .opcode = 0b0000011, .funct3 = 0b001, .funct7 = null },
64 .lhu => .{ .opcode = 0b0000011, .funct3 = 0b101, .funct7 = null },
65 .lb => .{ .opcode = 0b0000011, .funct3 = 0b000, .funct7 = null },
66 .lbu => .{ .opcode = 0b0000011, .funct3 = 0b100, .funct7 = null },
199 // OP
200
201 .add => .{ .opcode = .OP, .data = .{ .ff = .{ .funct3 = 0b000, .funct7 = 0b0000000 } } },
202 .sub => .{ .opcode = .OP, .data = .{ .ff = .{ .funct3 = 0b000, .funct7 = 0b0100000 } } },
203
204 .@"and" => .{ .opcode = .OP, .data = .{ .ff = .{ .funct3 = 0b111, .funct7 = 0b0000000 } } },
205 .@"or" => .{ .opcode = .OP, .data = .{ .ff = .{ .funct3 = 0b110, .funct7 = 0b0000000 } } },
206 .xor => .{ .opcode = .OP, .data = .{ .ff = .{ .funct3 = 0b100, .funct7 = 0b0000000 } } },
207
208 .sltu => .{ .opcode = .OP, .data = .{ .ff = .{ .funct3 = 0b011, .funct7 = 0b0000000 } } },
209 .slt => .{ .opcode = .OP, .data = .{ .ff = .{ .funct3 = 0b010, .funct7 = 0b0000000 } } },
210
211 .mul => .{ .opcode = .OP, .data = .{ .ff = .{ .funct3 = 0b000, .funct7 = 0b0000001 } } },
212 .mulh => .{ .opcode = .OP, .data = .{ .ff = .{ .funct3 = 0b001, .funct7 = 0b0000001 } } },
213 .mulhsu => .{ .opcode = .OP, .data = .{ .ff = .{ .funct3 = 0b010, .funct7 = 0b0000001 } } },
214 .mulhu => .{ .opcode = .OP, .data = .{ .ff = .{ .funct3 = 0b011, .funct7 = 0b0000001 } } },
215
216 .div => .{ .opcode = .OP, .data = .{ .ff = .{ .funct3 = 0b100, .funct7 = 0b0000001 } } },
217 .divu => .{ .opcode = .OP, .data = .{ .ff = .{ .funct3 = 0b101, .funct7 = 0b0000001 } } },
218
219 .rem => .{ .opcode = .OP, .data = .{ .ff = .{ .funct3 = 0b110, .funct7 = 0b0000001 } } },
220 .remu => .{ .opcode = .OP, .data = .{ .ff = .{ .funct3 = 0b111, .funct7 = 0b0000001 } } },
221
222 .sll => .{ .opcode = .OP, .data = .{ .ff = .{ .funct3 = 0b001, .funct7 = 0b0000000 } } },
223 .srl => .{ .opcode = .OP, .data = .{ .ff = .{ .funct3 = 0b101, .funct7 = 0b0000000 } } },
224 .sra => .{ .opcode = .OP, .data = .{ .ff = .{ .funct3 = 0b101, .funct7 = 0b0100000 } } },
225
226
227 // OP_IMM
228
229 .addi => .{ .opcode = .OP_IMM, .data = .{ .f = .{ .funct3 = 0b000 } } },
230 .andi => .{ .opcode = .OP_IMM, .data = .{ .f = .{ .funct3 = 0b111 } } },
231 .xori => .{ .opcode = .OP_IMM, .data = .{ .f = .{ .funct3 = 0b100 } } },
232
233 .sltiu => .{ .opcode = .OP_IMM, .data = .{ .f = .{ .funct3 = 0b011 } } },
234
235 .slli => .{ .opcode = .OP_IMM, .data = .{ .sh = .{ .typ = 0b000000, .funct3 = 0b001, .has_5 = true } } },
236 .srli => .{ .opcode = .OP_IMM, .data = .{ .sh = .{ .typ = 0b000000, .funct3 = 0b101, .has_5 = true } } },
237 .srai => .{ .opcode = .OP_IMM, .data = .{ .sh = .{ .typ = 0b010000, .funct3 = 0b101, .has_5 = true } } },
238
239
240 // OP_IMM_32
241
242 .slliw => .{ .opcode = .OP_IMM_32, .data = .{ .sh = .{ .typ = 0b000000, .funct3 = 0b001, .has_5 = false } } },
243 .srliw => .{ .opcode = .OP_IMM_32, .data = .{ .sh = .{ .typ = 0b000000, .funct3 = 0b101, .has_5 = false } } },
244 .sraiw => .{ .opcode = .OP_IMM_32, .data = .{ .sh = .{ .typ = 0b010000, .funct3 = 0b101, .has_5 = false } } },
245
246
247 // OP_32
248
249 .addw => .{ .opcode = .OP_32, .data = .{ .ff = .{ .funct3 = 0b000, .funct7 = 0b0000000 } } },
250 .subw => .{ .opcode = .OP_32, .data = .{ .ff = .{ .funct3 = 0b000, .funct7 = 0b0100000 } } },
251 .mulw => .{ .opcode = .OP_32, .data = .{ .ff = .{ .funct3 = 0b000, .funct7 = 0b0000001 } } },
252
253 .divw => .{ .opcode = .OP_32, .data = .{ .ff = .{ .funct3 = 0b100, .funct7 = 0b0000001 } } },
254 .divuw => .{ .opcode = .OP_32, .data = .{ .ff = .{ .funct3 = 0b101, .funct7 = 0b0000001 } } },
255
256 .remw => .{ .opcode = .OP_32, .data = .{ .ff = .{ .funct3 = 0b110, .funct7 = 0b0000001 } } },
257 .remuw => .{ .opcode = .OP_32, .data = .{ .ff = .{ .funct3 = 0b111, .funct7 = 0b0000001 } } },
258
259 .sllw => .{ .opcode = .OP_32, .data = .{ .ff = .{ .funct3 = 0b001, .funct7 = 0b0000000 } } },
260 .srlw => .{ .opcode = .OP_32, .data = .{ .ff = .{ .funct3 = 0b101, .funct7 = 0b0000000 } } },
261 .sraw => .{ .opcode = .OP_32, .data = .{ .ff = .{ .funct3 = 0b101, .funct7 = 0b0100000 } } },
262
263
264 // OP_FP
265
266 .fadds => .{ .opcode = .OP_FP, .data = .{ .fmt = .{ .funct5 = 0b00000, .fmt = .S, .rm = 0b111 } } },
267 .faddd => .{ .opcode = .OP_FP, .data = .{ .fmt = .{ .funct5 = 0b00000, .fmt = .D, .rm = 0b111 } } },
268
269 .fsubs => .{ .opcode = .OP_FP, .data = .{ .fmt = .{ .funct5 = 0b00001, .fmt = .S, .rm = 0b111 } } },
270 .fsubd => .{ .opcode = .OP_FP, .data = .{ .fmt = .{ .funct5 = 0b00001, .fmt = .D, .rm = 0b111 } } },
271
272 .fmuls => .{ .opcode = .OP_FP, .data = .{ .fmt = .{ .funct5 = 0b00010, .fmt = .S, .rm = 0b111 } } },
273 .fmuld => .{ .opcode = .OP_FP, .data = .{ .fmt = .{ .funct5 = 0b00010, .fmt = .D, .rm = 0b111 } } },
274
275 .fdivs => .{ .opcode = .OP_FP, .data = .{ .fmt = .{ .funct5 = 0b00011, .fmt = .S, .rm = 0b111 } } },
276 .fdivd => .{ .opcode = .OP_FP, .data = .{ .fmt = .{ .funct5 = 0b00011, .fmt = .D, .rm = 0b111 } } },
277
278 .fmins => .{ .opcode = .OP_FP, .data = .{ .fmt = .{ .funct5 = 0b00101, .fmt = .S, .rm = 0b000 } } },
279 .fmind => .{ .opcode = .OP_FP, .data = .{ .fmt = .{ .funct5 = 0b00101, .fmt = .D, .rm = 0b000 } } },
280
281 .fmaxs => .{ .opcode = .OP_FP, .data = .{ .fmt = .{ .funct5 = 0b00101, .fmt = .S, .rm = 0b001 } } },
282 .fmaxd => .{ .opcode = .OP_FP, .data = .{ .fmt = .{ .funct5 = 0b00101, .fmt = .D, .rm = 0b001 } } },
283
284 .fsqrts => .{ .opcode = .OP_FP, .data = .{ .fmt = .{ .funct5 = 0b01011, .fmt = .S, .rm = 0b111 } } },
285 .fsqrtd => .{ .opcode = .OP_FP, .data = .{ .fmt = .{ .funct5 = 0b01011, .fmt = .D, .rm = 0b111 } } },
286
287 .fles => .{ .opcode = .OP_FP, .data = .{ .fmt = .{ .funct5 = 0b10100, .fmt = .S, .rm = 0b000 } } },
288 .fled => .{ .opcode = .OP_FP, .data = .{ .fmt = .{ .funct5 = 0b10100, .fmt = .D, .rm = 0b000 } } },
289
290 .flts => .{ .opcode = .OP_FP, .data = .{ .fmt = .{ .funct5 = 0b10100, .fmt = .S, .rm = 0b001 } } },
291 .fltd => .{ .opcode = .OP_FP, .data = .{ .fmt = .{ .funct5 = 0b10100, .fmt = .D, .rm = 0b001 } } },
292
293 .feqs => .{ .opcode = .OP_FP, .data = .{ .fmt = .{ .funct5 = 0b10100, .fmt = .S, .rm = 0b010 } } },
294 .feqd => .{ .opcode = .OP_FP, .data = .{ .fmt = .{ .funct5 = 0b10100, .fmt = .D, .rm = 0b010 } } },
295
296 .fsgnjns => .{ .opcode = .OP_FP, .data = .{ .fmt = .{ .funct5 = 0b00100, .fmt = .S, .rm = 0b000 } } },
297 .fsgnjnd => .{ .opcode = .OP_FP, .data = .{ .fmt = .{ .funct5 = 0b00100, .fmt = .D, .rm = 0b000 } } },
298
299 .fsgnjxs => .{ .opcode = .OP_FP, .data = .{ .fmt = .{ .funct5 = 0b00100, .fmt = .S, .rm = 0b0010} } },
300 .fsgnjxd => .{ .opcode = .OP_FP, .data = .{ .fmt = .{ .funct5 = 0b00100, .fmt = .D, .rm = 0b0010} } },
301
302
303 // LOAD
304
305 .lb => .{ .opcode = .LOAD, .data = .{ .f = .{ .funct3 = 0b000 } } },
306 .lh => .{ .opcode = .LOAD, .data = .{ .f = .{ .funct3 = 0b001 } } },
307 .lw => .{ .opcode = .LOAD, .data = .{ .f = .{ .funct3 = 0b010 } } },
308 .ld => .{ .opcode = .LOAD, .data = .{ .f = .{ .funct3 = 0b011 } } },
309 .lbu => .{ .opcode = .LOAD, .data = .{ .f = .{ .funct3 = 0b100 } } },
310 .lhu => .{ .opcode = .LOAD, .data = .{ .f = .{ .funct3 = 0b101 } } },
311 .lwu => .{ .opcode = .LOAD, .data = .{ .f = .{ .funct3 = 0b110 } } },
312
313
314 // STORE
315
316 .sb => .{ .opcode = .STORE, .data = .{ .f = .{ .funct3 = 0b000 } } },
317 .sh => .{ .opcode = .STORE, .data = .{ .f = .{ .funct3 = 0b001 } } },
318 .sw => .{ .opcode = .STORE, .data = .{ .f = .{ .funct3 = 0b010 } } },
319 .sd => .{ .opcode = .STORE, .data = .{ .f = .{ .funct3 = 0b011 } } },
320
321
322 // LOAD_FP
67323
68 .sltiu => .{ .opcode = 0b0010011, .funct3 = 0b011, .funct7 = null },
324 .flw => .{ .opcode = .LOAD_FP, .data = .{ .f = .{ .funct3 = 0b010 } } },
325 .fld => .{ .opcode = .LOAD_FP, .data = .{ .f = .{ .funct3 = 0b011 } } },
326
69327
70 .addi => .{ .opcode = 0b0010011, .funct3 = 0b000, .funct7 = null },
71 .andi => .{ .opcode = 0b0010011, .funct3 = 0b111, .funct7 = null },
72 .xori => .{ .opcode = 0b0010011, .funct3 = 0b100, .funct7 = null },
73 .jalr => .{ .opcode = 0b1100111, .funct3 = 0b000, .funct7 = null },
74 .slli => .{ .opcode = 0b0010011, .funct3 = 0b001, .funct7 = null },
75 .srli => .{ .opcode = 0b0010011, .funct3 = 0b101, .funct7 = null },
76 .srai => .{ .opcode = 0b0010011, .funct3 = 0b101, .funct7 = null, .offset = 1 << 10 },
328 // STORE_FP
77329
78 .lui => .{ .opcode = 0b0110111, .funct3 = null, .funct7 = null },
330 .fsw => .{ .opcode = .STORE_FP, .data = .{ .f = .{ .funct3 = 0b010 } } },
331 .fsd => .{ .opcode = .STORE_FP, .data = .{ .f = .{ .funct3 = 0b011 } } },
79332
80 .sd => .{ .opcode = 0b0100011, .funct3 = 0b011, .funct7 = null },
81 .sw => .{ .opcode = 0b0100011, .funct3 = 0b010, .funct7 = null },
82 .sh => .{ .opcode = 0b0100011, .funct3 = 0b001, .funct7 = null },
83 .sb => .{ .opcode = 0b0100011, .funct3 = 0b000, .funct7 = null },
84333
85 .jal => .{ .opcode = 0b1101111, .funct3 = null, .funct7 = null },
334 // JALR
86335
87 .beq => .{ .opcode = 0b1100011, .funct3 = 0b000, .funct7 = null },
336 .jalr => .{ .opcode = .JALR, .data = .{ .f = .{ .funct3 = 0b000 } } },
88337
89 .slt => .{ .opcode = 0b0110011, .funct3 = 0b010, .funct7 = 0b0000000 },
90338
91 .xor => .{ .opcode = 0b0110011, .funct3 = 0b100, .funct7 = 0b0000000 },
339 // LUI
340
341 .lui => .{ .opcode = .LUI, .data = .{ .none = {} } },
342
343
344 // AUIPC
345
346 .auipc => .{ .opcode = .AUIPC, .data = .{ .none = {} } },
347
348
349 // JAL
350
351 .jal => .{ .opcode = .JAL, .data = .{ .none = {} } },
352
353
354 // BRANCH
355
356 .beq => .{ .opcode = .BRANCH, .data = .{ .f = .{ .funct3 = 0b000 } } },
357
358
359 // SYSTEM
360
361 .ecall => .{ .opcode = .SYSTEM, .data = .{ .f = .{ .funct3 = 0b000 } } },
362 .ebreak => .{ .opcode = .SYSTEM, .data = .{ .f = .{ .funct3 = 0b000 } } },
363
364
365 // NONE
366
367 .unimp => .{ .opcode = .NONE, .data = .{ .f = .{ .funct3 = 0b000 } } },
92368
93 .mul => .{ .opcode = 0b0110011, .funct3 = 0b000, .funct7 = 0b0000001 },
94369
95 .ecall => .{ .opcode = 0b1110011, .funct3 = 0b000, .funct7 = null },
96 .ebreak => .{ .opcode = 0b1110011, .funct3 = 0b000, .funct7 = null },
97 .unimp => .{ .opcode = 0b0000000, .funct3 = 0b000, .funct7 = null },
98370 // zig fmt: on
99371 };
100372 }
......@@ -102,6 +374,7 @@ pub const Mnemonic = enum {
102374
103375pub const InstEnc = enum {
104376 R,
377 R4,
105378 I,
106379 S,
107380 B,
......@@ -114,29 +387,42 @@ pub const InstEnc = enum {
114387 pub fn fromMnemonic(mnem: Mnemonic) InstEnc {
115388 return switch (mnem) {
116389 .addi,
117 .ld,
118 .lw,
119 .lwu,
120 .lh,
121 .lhu,
122 .lb,
123 .lbu,
124390 .jalr,
125391 .sltiu,
126392 .xori,
127393 .andi,
394
128395 .slli,
129396 .srli,
130397 .srai,
398
399 .slliw,
400 .srliw,
401 .sraiw,
402
403 .ld,
404 .lw,
405 .lwu,
406 .lh,
407 .lhu,
408 .lb,
409 .lbu,
410
411 .flw,
412 .fld,
131413 => .I,
132414
133415 .lui,
416 .auipc,
134417 => .U,
135418
136419 .sd,
137420 .sw,
138421 .sh,
139422 .sb,
423
424 .fsd,
425 .fsw,
140426 => .S,
141427
142428 .jal,
......@@ -147,11 +433,76 @@ pub const InstEnc = enum {
147433
148434 .slt,
149435 .sltu,
150 .mul,
436
437 .sll,
438 .srl,
439 .sra,
440
441 .sllw,
442 .srlw,
443 .sraw,
444
445 .div,
446 .divu,
447 .divw,
448 .divuw,
449
450 .rem,
451 .remu,
452 .remw,
453 .remuw,
454
151455 .xor,
456 .@"and",
457 .@"or",
458
152459 .add,
460 .addw,
461
153462 .sub,
154 .@"and",
463 .subw,
464
465 .mul,
466 .mulw,
467 .mulh,
468 .mulhu,
469 .mulhsu,
470
471 .fadds,
472 .faddd,
473
474 .fsubs,
475 .fsubd,
476
477 .fmuls,
478 .fmuld,
479
480 .fdivs,
481 .fdivd,
482
483 .fmins,
484 .fmind,
485
486 .fmaxs,
487 .fmaxd,
488
489 .fsqrts,
490 .fsqrtd,
491
492 .fles,
493 .fled,
494
495 .flts,
496 .fltd,
497
498 .feqs,
499 .feqd,
500
501 .fsgnjns,
502 .fsgnjnd,
503
504 .fsgnjxs,
505 .fsgnjxd,
155506 => .R,
156507
157508 .ecall,
......@@ -161,16 +512,17 @@ pub const InstEnc = enum {
161512 };
162513 }
163514
164 pub fn opsList(enc: InstEnc) [3]std.meta.FieldEnum(Operand) {
515 pub fn opsList(enc: InstEnc) [4]std.meta.FieldEnum(Operand) {
165516 return switch (enc) {
166517 // zig fmt: off
167 .R => .{ .reg, .reg, .reg, },
168 .I => .{ .reg, .reg, .imm, },
169 .S => .{ .reg, .reg, .imm, },
170 .B => .{ .reg, .reg, .imm, },
171 .U => .{ .reg, .imm, .none, },
172 .J => .{ .reg, .imm, .none, },
173 .system => .{ .none, .none, .none, },
518 .R => .{ .reg, .reg, .reg, .none },
519 .R4 => .{ .reg, .reg, .reg, .reg },
520 .I => .{ .reg, .reg, .imm, .none },
521 .S => .{ .reg, .reg, .imm, .none },
522 .B => .{ .reg, .reg, .imm, .none },
523 .U => .{ .reg, .imm, .none, .none },
524 .J => .{ .reg, .imm, .none, .none },
525 .system => .{ .none, .none, .none, .none },
174526 // zig fmt: on
175527 };
176528 }
......@@ -185,6 +537,15 @@ pub const Data = union(InstEnc) {
185537 rs2: u5,
186538 funct7: u7,
187539 },
540 R4: packed struct {
541 opcode: u7,
542 rd: u5,
543 funct3: u3,
544 rs1: u5,
545 rs2: u5,
546 funct2: u2,
547 rs3: u5,
548 },
188549 I: packed struct {
189550 opcode: u7,
190551 rd: u5,
......@@ -227,19 +588,21 @@ pub const Data = union(InstEnc) {
227588
228589 pub fn toU32(self: Data) u32 {
229590 return switch (self) {
230 .R => |v| @as(u32, @bitCast(v)),
231 .I => |v| @as(u32, @bitCast(v)),
232 .S => |v| @as(u32, @bitCast(v)),
233 .B => |v| @as(u32, @intCast(v.opcode)) + (@as(u32, @intCast(v.imm11)) << 7) + (@as(u32, @intCast(v.imm1_4)) << 8) + (@as(u32, @intCast(v.funct3)) << 12) + (@as(u32, @intCast(v.rs1)) << 15) + (@as(u32, @intCast(v.rs2)) << 20) + (@as(u32, @intCast(v.imm5_10)) << 25) + (@as(u32, @intCast(v.imm12)) << 31),
234 .U => |v| @as(u32, @bitCast(v)),
235 .J => |v| @as(u32, @bitCast(v)),
591 // zig fmt: off
592 .R => |v| @bitCast(v),
593 .R4 => |v| @bitCast(v),
594 .I => |v| @bitCast(v),
595 .S => |v| @bitCast(v),
596 .B => |v| @as(u32, @intCast(v.opcode)) + (@as(u32, @intCast(v.imm11)) << 7) + (@as(u32, @intCast(v.imm1_4)) << 8) + (@as(u32, @intCast(v.funct3)) << 12) + (@as(u32, @intCast(v.rs1)) << 15) + (@as(u32, @intCast(v.rs2)) << 20) + (@as(u32, @intCast(v.imm5_10)) << 25) + (@as(u32, @intCast(v.imm12)) << 31),
597 .U => |v| @bitCast(v),
598 .J => |v| @bitCast(v),
236599 .system => unreachable,
600 // zig fmt: on
237601 };
238602 }
239603
240604 pub fn construct(mnem: Mnemonic, ops: []const Operand) !Data {
241605 const inst_enc = InstEnc.fromMnemonic(mnem);
242
243606 const enc = mnem.encoding();
244607
245608 // special mnemonics
......@@ -251,17 +614,17 @@ pub const Data = union(InstEnc) {
251614 assert(ops.len == 0);
252615 return .{
253616 .I = .{
254 .rd = Register.zero.id(),
255 .rs1 = Register.zero.id(),
617 .rd = Register.zero.encodeId(),
618 .rs1 = Register.zero.encodeId(),
256619 .imm0_11 = switch (mnem) {
257620 .ecall => 0x000,
258621 .ebreak => 0x001,
259 .unimp => 0,
622 .unimp => 0x000,
260623 else => unreachable,
261624 },
262625
263 .opcode = enc.opcode,
264 .funct3 = enc.funct3.?,
626 .opcode = @intFromEnum(enc.opcode),
627 .funct3 = enc.data.f.funct3,
265628 },
266629 };
267630 },
......@@ -272,14 +635,26 @@ pub const Data = union(InstEnc) {
272635 .R => {
273636 assert(ops.len == 3);
274637 return .{
275 .R = .{
276 .rd = ops[0].reg.id(),
277 .rs1 = ops[1].reg.id(),
278 .rs2 = ops[2].reg.id(),
279
280 .opcode = enc.opcode,
281 .funct3 = enc.funct3.?,
282 .funct7 = enc.funct7.?,
638 .R = switch (enc.data) {
639 .ff => |ff| .{
640 .rd = ops[0].reg.encodeId(),
641 .rs1 = ops[1].reg.encodeId(),
642 .rs2 = ops[2].reg.encodeId(),
643
644 .opcode = @intFromEnum(enc.opcode),
645 .funct3 = ff.funct3,
646 .funct7 = ff.funct7,
647 },
648 .fmt => |fmt| .{
649 .rd = ops[0].reg.encodeId(),
650 .rs1 = ops[1].reg.encodeId(),
651 .rs2 = ops[2].reg.encodeId(),
652
653 .opcode = @intFromEnum(enc.opcode),
654 .funct3 = fmt.rm,
655 .funct7 = (@as(u7, fmt.funct5) << 2) | @intFromEnum(fmt.fmt),
656 },
657 else => unreachable,
283658 },
284659 };
285660 },
......@@ -290,25 +665,37 @@ pub const Data = union(InstEnc) {
290665 return .{
291666 .S = .{
292667 .imm0_4 = @truncate(umm),
293 .rs1 = ops[0].reg.id(),
294 .rs2 = ops[1].reg.id(),
668 .rs1 = ops[0].reg.encodeId(),
669 .rs2 = ops[1].reg.encodeId(),
295670 .imm5_11 = @truncate(umm >> 5),
296671
297 .opcode = enc.opcode,
298 .funct3 = enc.funct3.?,
672 .opcode = @intFromEnum(enc.opcode),
673 .funct3 = enc.data.f.funct3,
299674 },
300675 };
301676 },
302677 .I => {
303678 assert(ops.len == 3);
304679 return .{
305 .I = .{
306 .rd = ops[0].reg.id(),
307 .rs1 = ops[1].reg.id(),
308 .imm0_11 = ops[2].imm.asBits(u12) + enc.offset,
309
310 .opcode = enc.opcode,
311 .funct3 = enc.funct3.?,
680 .I = switch (enc.data) {
681 .f => |f| .{
682 .rd = ops[0].reg.encodeId(),
683 .rs1 = ops[1].reg.encodeId(),
684 .imm0_11 = ops[2].imm.asBits(u12),
685
686 .opcode = @intFromEnum(enc.opcode),
687 .funct3 = f.funct3,
688 },
689 .sh => |sh| .{
690 .rd = ops[0].reg.encodeId(),
691 .rs1 = ops[1].reg.encodeId(),
692 .imm0_11 = (@as(u12, sh.typ) << 6) |
693 if (sh.has_5) ops[2].imm.asBits(u6) else (@as(u6, 0) | ops[2].imm.asBits(u5)),
694
695 .opcode = @intFromEnum(enc.opcode),
696 .funct3 = sh.funct3,
697 },
698 else => unreachable,
312699 },
313700 };
314701 },
......@@ -316,10 +703,10 @@ pub const Data = union(InstEnc) {
316703 assert(ops.len == 2);
317704 return .{
318705 .U = .{
319 .rd = ops[0].reg.id(),
706 .rd = ops[0].reg.encodeId(),
320707 .imm12_31 = ops[1].imm.asBits(u20),
321708
322 .opcode = enc.opcode,
709 .opcode = @intFromEnum(enc.opcode),
323710 },
324711 };
325712 },
......@@ -331,13 +718,13 @@ pub const Data = union(InstEnc) {
331718
332719 return .{
333720 .J = .{
334 .rd = ops[0].reg.id(),
721 .rd = ops[0].reg.encodeId(),
335722 .imm1_10 = @truncate(umm >> 1),
336723 .imm11 = @truncate(umm >> 11),
337724 .imm12_19 = @truncate(umm >> 12),
338725 .imm20 = @truncate(umm >> 20),
339726
340 .opcode = enc.opcode,
727 .opcode = @intFromEnum(enc.opcode),
341728 },
342729 };
343730 },
......@@ -349,15 +736,15 @@ pub const Data = union(InstEnc) {
349736
350737 return .{
351738 .B = .{
352 .rs1 = ops[0].reg.id(),
353 .rs2 = ops[1].reg.id(),
739 .rs1 = ops[0].reg.encodeId(),
740 .rs2 = ops[1].reg.encodeId(),
354741 .imm1_4 = @truncate(umm >> 1),
355742 .imm5_10 = @truncate(umm >> 5),
356743 .imm11 = @truncate(umm >> 11),
357744 .imm12 = @truncate(umm >> 12),
358745
359 .opcode = enc.opcode,
360 .funct3 = enc.funct3.?,
746 .opcode = @intFromEnum(enc.opcode),
747 .funct3 = enc.data.f.funct3,
361748 },
362749 };
363750 },
......@@ -376,13 +763,6 @@ pub fn findByMnemonic(mnem: Mnemonic, ops: []const Operand) !?Encoding {
376763 };
377764}
378765
379const Enc = struct {
380 opcode: u7,
381 funct3: ?u3,
382 funct7: ?u7,
383 offset: u12 = 0,
384};
385
386766fn verifyOps(mnem: Mnemonic, ops: []const Operand) bool {
387767 const inst_enc = InstEnc.fromMnemonic(mnem);
388768 const list = std.mem.sliceTo(&inst_enc.opsList(), .none);
src/arch/riscv64/Lower.zig+260-93
......@@ -14,7 +14,7 @@ result_relocs_len: u8 = undefined,
1414result_insts: [
1515 @max(
1616 1, // non-pseudo instruction
17 abi.callee_preserved_regs.len, // spill / restore regs,
17 abi.Registers.all_preserved.len, // spill / restore regs,
1818 )
1919]Instruction = undefined,
2020result_relocs: [1]Reloc = undefined,
......@@ -32,8 +32,10 @@ pub const Reloc = struct {
3232 const Target = union(enum) {
3333 inst: Mir.Inst.Index,
3434
35 /// Relocs the lowered_inst_index and the next one.
35 /// Relocs the lowered_inst_index and the next instruction.
3636 load_symbol_reloc: bits.Symbol,
37 /// Relocs the lowered_inst_index and the next instruction.
38 call_extern_fn_reloc: bits.Symbol,
3739 };
3840};
3941
......@@ -42,6 +44,8 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct {
4244 insts: []const Instruction,
4345 relocs: []const Reloc,
4446} {
47 const zcu = lower.bin_file.comp.module.?;
48
4549 lower.result_insts = undefined;
4650 lower.result_relocs = undefined;
4751 errdefer lower.result_insts = undefined;
......@@ -69,11 +73,25 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct {
6973
7074 switch (inst.ops) {
7175 .pseudo_load_rm => {
72 const tag: Encoding.Mnemonic = switch (rm.m.mod.rm.size) {
73 .byte => .lb,
74 .hword => .lh,
75 .word => .lw,
76 .dword => .ld,
76 const dest_reg = rm.r;
77 const dest_reg_class = dest_reg.class();
78 const float = dest_reg_class == .float;
79
80 const src_size = rm.m.mod.size;
81 const unsigned = rm.m.mod.unsigned;
82
83 const tag: Encoding.Mnemonic = if (!float)
84 switch (src_size) {
85 .byte => if (unsigned) .lbu else .lb,
86 .hword => if (unsigned) .lhu else .lh,
87 .word => if (unsigned) .lwu else .lw,
88 .dword => .ld,
89 }
90 else switch (src_size) {
91 .byte => unreachable, // Zig does not support 8-bit floats
92 .hword => return lower.fail("TODO: lowerMir pseudo_load_rm support 16-bit floats", .{}),
93 .word => .flw,
94 .dword => .fld,
7795 };
7896
7997 try lower.emit(tag, &.{
......@@ -83,11 +101,25 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct {
83101 });
84102 },
85103 .pseudo_store_rm => {
86 const tag: Encoding.Mnemonic = switch (rm.m.mod.rm.size) {
87 .byte => .sb,
88 .hword => .sh,
89 .word => .sw,
90 .dword => .sd,
104 const src_reg = rm.r;
105 const src_reg_class = src_reg.class();
106 const float = src_reg_class == .float;
107
108 // TODO: do we actually need this? are all stores not usize?
109 const dest_size = rm.m.mod.size;
110
111 const tag: Encoding.Mnemonic = if (!float)
112 switch (dest_size) {
113 .byte => .sb,
114 .hword => .sh,
115 .word => .sw,
116 .dword => .sd,
117 }
118 else switch (dest_size) {
119 .byte => unreachable, // Zig does not support 8-bit floats
120 .hword => return lower.fail("TODO: lowerMir pseudo_load_rm support 16-bit floats", .{}),
121 .word => .fsw,
122 .dword => .fsd,
91123 };
92124
93125 try lower.emit(tag, &.{
......@@ -103,11 +135,27 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct {
103135 .pseudo_mv => {
104136 const rr = inst.data.rr;
105137
106 try lower.emit(.addi, &.{
107 .{ .reg = rr.rd },
108 .{ .reg = rr.rs },
109 .{ .imm = Immediate.s(0) },
110 });
138 const dst_class = rr.rd.class();
139 const src_class = rr.rs.class();
140
141 assert(dst_class == src_class);
142
143 switch (dst_class) {
144 .float => {
145 try lower.emit(if (lower.hasFeature(.d)) .fsgnjnd else .fsgnjns, &.{
146 .{ .reg = rr.rd },
147 .{ .reg = rr.rs },
148 .{ .reg = rr.rs },
149 });
150 },
151 .int => {
152 try lower.emit(.addi, &.{
153 .{ .reg = rr.rd },
154 .{ .reg = rr.rs },
155 .{ .imm = Immediate.s(0) },
156 });
157 },
158 }
111159 },
112160
113161 .pseudo_ret => {
......@@ -131,25 +179,31 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct {
131179 .pseudo_load_symbol => {
132180 const payload = inst.data.payload;
133181 const data = lower.mir.extraData(Mir.LoadSymbolPayload, payload).data;
182 const dst_reg: bits.Register = @enumFromInt(data.register);
183 assert(dst_reg.class() == .int);
134184
135185 try lower.emit(.lui, &.{
136 .{ .reg = @enumFromInt(data.register) },
137 .{ .imm = lower.reloc(.{ .load_symbol_reloc = .{
138 .atom_index = data.atom_index,
139 .sym_index = data.sym_index,
140 } }) },
186 .{ .reg = dst_reg },
187 .{ .imm = lower.reloc(.{
188 .load_symbol_reloc = .{
189 .atom_index = data.atom_index,
190 .sym_index = data.sym_index,
191 },
192 }) },
141193 });
142194
143195 // the above reloc implies this one
144196 try lower.emit(.addi, &.{
145 .{ .reg = @enumFromInt(data.register) },
146 .{ .reg = @enumFromInt(data.register) },
197 .{ .reg = dst_reg },
198 .{ .reg = dst_reg },
147199 .{ .imm = Immediate.s(0) },
148200 });
149201 },
150202
151203 .pseudo_lea_rm => {
152204 const rm = inst.data.rm;
205 assert(rm.r.class() == .int);
206
153207 const frame = rm.m.toFrameLoc(lower.mir);
154208
155209 try lower.emit(.addi, &.{
......@@ -159,6 +213,26 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct {
159213 });
160214 },
161215
216 .pseudo_fabs => {
217 const fabs = inst.data.fabs;
218 assert(fabs.rs.class() == .float and fabs.rd.class() == .float);
219
220 const mnem: Encoding.Mnemonic = switch (fabs.bits) {
221 16 => return lower.fail("TODO: airAbs Float 16", .{}),
222 32 => .fsgnjxs,
223 64 => .fsgnjxd,
224 80 => return lower.fail("TODO: airAbs Float 80", .{}),
225 128 => return lower.fail("TODO: airAbs Float 128", .{}),
226 else => unreachable,
227 };
228
229 try lower.emit(mnem, &.{
230 .{ .reg = fabs.rs },
231 .{ .reg = fabs.rd },
232 .{ .reg = fabs.rd },
233 });
234 },
235
162236 .pseudo_compare => {
163237 const compare = inst.data.compare;
164238 const op = compare.op;
......@@ -167,78 +241,142 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct {
167241 const rs1 = compare.rs1;
168242 const rs2 = compare.rs2;
169243
170 switch (op) {
171 .eq => {
172 try lower.emit(.xor, &.{
173 .{ .reg = rd },
174 .{ .reg = rs1 },
175 .{ .reg = rs2 },
176 });
177
178 try lower.emit(.sltiu, &.{
179 .{ .reg = rd },
180 .{ .reg = rd },
181 .{ .imm = Immediate.s(1) },
182 });
244 const class = rs1.class();
245 const ty = compare.ty;
246 const size = std.math.ceilPowerOfTwo(u64, ty.bitSize(zcu)) catch {
247 return lower.fail("pseudo_compare size {}", .{ty.bitSize(zcu)});
248 };
249
250 const is_unsigned = ty.isUnsignedInt(zcu);
251
252 const less_than: Encoding.Mnemonic = if (is_unsigned) .sltu else .slt;
253
254 switch (class) {
255 .int => switch (op) {
256 .eq => {
257 try lower.emit(.xor, &.{
258 .{ .reg = rd },
259 .{ .reg = rs1 },
260 .{ .reg = rs2 },
261 });
262
263 try lower.emit(.sltiu, &.{
264 .{ .reg = rd },
265 .{ .reg = rd },
266 .{ .imm = Immediate.s(1) },
267 });
268 },
269 .neq => {
270 try lower.emit(.xor, &.{
271 .{ .reg = rd },
272 .{ .reg = rs1 },
273 .{ .reg = rs2 },
274 });
275
276 try lower.emit(.sltu, &.{
277 .{ .reg = rd },
278 .{ .reg = .zero },
279 .{ .reg = rd },
280 });
281 },
282 .gt => {
283 try lower.emit(less_than, &.{
284 .{ .reg = rd },
285 .{ .reg = rs1 },
286 .{ .reg = rs2 },
287 });
288 },
289 .gte => {
290 try lower.emit(less_than, &.{
291 .{ .reg = rd },
292 .{ .reg = rs1 },
293 .{ .reg = rs2 },
294 });
295
296 try lower.emit(.xori, &.{
297 .{ .reg = rd },
298 .{ .reg = rd },
299 .{ .imm = Immediate.s(1) },
300 });
301 },
302 .lt => {
303 try lower.emit(less_than, &.{
304 .{ .reg = rd },
305 .{ .reg = rs1 },
306 .{ .reg = rs2 },
307 });
308 },
309 .lte => {
310 try lower.emit(less_than, &.{
311 .{ .reg = rd },
312 .{ .reg = rs2 },
313 .{ .reg = rs1 },
314 });
315
316 try lower.emit(.xori, &.{
317 .{ .reg = rd },
318 .{ .reg = rd },
319 .{ .imm = Immediate.s(1) },
320 });
321 },
183322 },
184 .neq => {
185 try lower.emit(.xor, &.{
186 .{ .reg = rd },
187 .{ .reg = rs1 },
188 .{ .reg = rs2 },
189 });
190
191 try lower.emit(.sltu, &.{
192 .{ .reg = rd },
193 .{ .reg = .zero },
194 .{ .reg = rd },
195 });
196 },
197 .gt => {
198 try lower.emit(.sltu, &.{
199 .{ .reg = rd },
200 .{ .reg = rs1 },
201 .{ .reg = rs2 },
202 });
203 },
204 .gte => {
205 try lower.emit(.sltu, &.{
206 .{ .reg = rd },
207 .{ .reg = rs1 },
208 .{ .reg = rs2 },
209 });
210
211 try lower.emit(.xori, &.{
212 .{ .reg = rd },
213 .{ .reg = rd },
214 .{ .imm = Immediate.s(1) },
215 });
216 },
217 .lt => {
218 try lower.emit(.slt, &.{
219 .{ .reg = rd },
220 .{ .reg = rs1 },
221 .{ .reg = rs2 },
222 });
223 },
224 .lte => {
225 try lower.emit(.slt, &.{
226 .{ .reg = rd },
227 .{ .reg = rs2 },
228 .{ .reg = rs1 },
229 });
230
231 try lower.emit(.xori, &.{
232 .{ .reg = rd },
233 .{ .reg = rd },
234 .{ .imm = Immediate.s(1) },
235 });
323 .float => switch (op) {
324 // eq
325 .eq => {
326 try lower.emit(if (size == 64) .feqd else .feqs, &.{
327 .{ .reg = rd },
328 .{ .reg = rs1 },
329 .{ .reg = rs2 },
330 });
331 },
332 // !(eq)
333 .neq => {
334 try lower.emit(if (size == 64) .feqd else .feqs, &.{
335 .{ .reg = rd },
336 .{ .reg = rs1 },
337 .{ .reg = rs2 },
338 });
339 try lower.emit(.xori, &.{
340 .{ .reg = rd },
341 .{ .reg = rd },
342 .{ .imm = Immediate.s(1) },
343 });
344 },
345 .lt => {
346 try lower.emit(if (size == 64) .fltd else .flts, &.{
347 .{ .reg = rd },
348 .{ .reg = rs1 },
349 .{ .reg = rs2 },
350 });
351 },
352 .lte => {
353 try lower.emit(if (size == 64) .fled else .fles, &.{
354 .{ .reg = rd },
355 .{ .reg = rs1 },
356 .{ .reg = rs2 },
357 });
358 },
359 .gt => {
360 try lower.emit(if (size == 64) .fltd else .flts, &.{
361 .{ .reg = rd },
362 .{ .reg = rs2 },
363 .{ .reg = rs1 },
364 });
365 },
366 .gte => {
367 try lower.emit(if (size == 64) .fled else .fles, &.{
368 .{ .reg = rd },
369 .{ .reg = rs2 },
370 .{ .reg = rs1 },
371 });
372 },
236373 },
237374 }
238375 },
239376
240377 .pseudo_not => {
241378 const rr = inst.data.rr;
379 assert(rr.rs.class() == .int and rr.rd.class() == .int);
242380
243381 try lower.emit(.xori, &.{
244382 .{ .reg = rr.rd },
......@@ -247,6 +385,26 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct {
247385 });
248386 },
249387
388 .pseudo_extern_fn_reloc => {
389 const inst_reloc = inst.data.reloc;
390
391 try lower.emit(.auipc, &.{
392 .{ .reg = .ra },
393 .{ .imm = lower.reloc(
394 .{ .call_extern_fn_reloc = .{
395 .atom_index = inst_reloc.atom_index,
396 .sym_index = inst_reloc.sym_index,
397 } },
398 ) },
399 });
400
401 try lower.emit(.jalr, &.{
402 .{ .reg = .ra },
403 .{ .reg = .ra },
404 .{ .imm = Immediate.s(0) },
405 });
406 },
407
250408 else => return lower.fail("TODO lower: psuedo {s}", .{@tagName(inst.ops)}),
251409 },
252410 }
......@@ -314,16 +472,19 @@ fn pushPopRegList(lower: *Lower, comptime spilling: bool, reg_list: Mir.Register
314472 var reg_i: u31 = 0;
315473 while (it.next()) |i| {
316474 const frame = lower.mir.frame_locs.get(@intFromEnum(bits.FrameIndex.spill_frame));
475 const reg = abi.Registers.all_preserved[i];
476 const reg_class = reg.class();
477 const is_float_reg = reg_class == .float;
317478
318479 if (spilling) {
319 try lower.emit(.sd, &.{
480 try lower.emit(if (is_float_reg) .fsd else .sd, &.{
320481 .{ .reg = frame.base },
321 .{ .reg = abi.callee_preserved_regs[i] },
482 .{ .reg = abi.Registers.all_preserved[i] },
322483 .{ .imm = Immediate.s(frame.disp + reg_i) },
323484 });
324485 } else {
325 try lower.emit(.ld, &.{
326 .{ .reg = abi.callee_preserved_regs[i] },
486 try lower.emit(if (is_float_reg) .fld else .ld, &.{
487 .{ .reg = abi.Registers.all_preserved[i] },
327488 .{ .reg = frame.base },
328489 .{ .imm = Immediate.s(frame.disp + reg_i) },
329490 });
......@@ -340,6 +501,12 @@ pub fn fail(lower: *Lower, comptime format: []const u8, args: anytype) Error {
340501 return error.LowerFail;
341502}
342503
504fn hasFeature(lower: *Lower, feature: std.Target.riscv.Feature) bool {
505 const target = lower.bin_file.comp.module.?.getTarget();
506 const features = target.cpu.features;
507 return std.Target.riscv.featureSetHas(features, feature);
508}
509
343510const Lower = @This();
344511
345512const abi = @import("abi.zig");
src/arch/riscv64/Mir.zig+93-47
......@@ -20,90 +20,119 @@ pub const Inst = struct {
2020 pub const Index = u32;
2121
2222 pub const Tag = enum(u16) {
23 /// Add immediate. Uses i_type payload.
24 addi,
2523
26 /// Add immediate and produce a sign-extended result.
27 ///
28 /// Uses i-type payload.
24 // base extension
25 addi,
2926 addiw,
3027
3128 jalr,
3229 lui,
33 mv,
3430
3531 @"and",
32 andi,
33
3634 xor,
35 @"or",
3736
3837 ebreak,
3938 ecall,
4039 unimp,
4140
42 /// OR instruction. Uses r_type payload.
43 @"or",
44
45 /// Addition
4641 add,
47 /// Subtraction
42 addw,
4843 sub,
49 /// Multiply, uses r_type. Needs the M extension.
50 mul,
51
52 /// Absolute Value, uses i_type payload.
53 abs,
44 subw,
5445
5546 sltu,
5647 slt,
5748
58 /// Immediate Logical Right Shift, uses i_type payload
59 srli,
60 /// Immediate Logical Left Shift, uses i_type payload
6149 slli,
62 /// Immediate Arithmetic Right Shift, uses i_type payload.
50 srli,
6351 srai,
64 /// Register Logical Left Shift, uses r_type payload
52
53 slliw,
54 srliw,
55 sraiw,
56
57 sll,
58 srl,
59 sra,
60
6561 sllw,
66 /// Register Logical Right Shit, uses r_type payload
6762 srlw,
63 sraw,
6864
69 /// Jumps, but stores the address of the instruction following the
70 /// jump in `rd`.
71 ///
72 /// Uses j_type payload.
7365 jal,
7466
75 /// Immediate AND, uses i_type payload
76 andi,
77
78 /// Branch if equal, Uses b_type
7967 beq,
80 /// Branch if not equal, Uses b_type
8168 bne,
8269
83 /// Boolean NOT, Uses rr payload
84 not,
85
86 /// Generates a NO-OP, uses nop payload
8770 nop,
8871
89 /// Load double (64 bits), uses i_type payload
9072 ld,
91 /// Load word (32 bits), uses i_type payload
9273 lw,
93 /// Load half (16 bits), uses i_type payload
9474 lh,
95 /// Load byte (8 bits), uses i_type payload
9675 lb,
9776
98 /// Store double (64 bits), uses s_type payload
9977 sd,
100 /// Store word (32 bits), uses s_type payload
10178 sw,
102 /// Store half (16 bits), uses s_type payload
10379 sh,
104 /// Store byte (8 bits), uses s_type payload
10580 sb,
10681
82 // M extension
83 mul,
84 mulw,
85
86 div,
87 divu,
88 divw,
89 divuw,
90
91 rem,
92 remu,
93 remw,
94 remuw,
95
96 // F extension (32-bit float)
97 fadds,
98 fsubs,
99 fmuls,
100 fdivs,
101
102 fabss,
103
104 fmins,
105 fmaxs,
106
107 fsqrts,
108
109 flw,
110 fsw,
111
112 feqs,
113 flts,
114 fles,
115
116 // D extension (64-bit float)
117 faddd,
118 fsubd,
119 fmuld,
120 fdivd,
121
122 fabsd,
123
124 fmind,
125 fmaxd,
126
127 fsqrtd,
128
129 fld,
130 fsd,
131
132 feqd,
133 fltd,
134 fled,
135
107136 /// A pseudo-instruction. Used for anything that isn't 1:1 with an
108137 /// assembly instruction.
109138 pseudo,
......@@ -192,6 +221,12 @@ pub const Inst = struct {
192221 rs: Register,
193222 },
194223
224 fabs: struct {
225 rd: Register,
226 rs: Register,
227 bits: u16,
228 },
229
195230 compare: struct {
196231 rd: Register,
197232 rs1: Register,
......@@ -204,6 +239,12 @@ pub const Inst = struct {
204239 lt,
205240 lte,
206241 },
242 ty: Type,
243 },
244
245 reloc: struct {
246 atom_index: u32,
247 sym_index: u32,
207248 },
208249 };
209250
......@@ -217,10 +258,7 @@ pub const Inst = struct {
217258
218259 /// Two registers + immediate, uses the i_type payload.
219260 rri,
220 /// Two registers + Two Immediates
221 rrii,
222
223 /// Two registers + another instruction.
261 //extern_fn_reloc/ Two registers + another instruction.
224262 rr_inst,
225263
226264 /// Register + Memory
......@@ -268,6 +306,9 @@ pub const Inst = struct {
268306 /// Jumps. Uses `inst` payload.
269307 pseudo_j,
270308
309 /// Floating point absolute value.
310 pseudo_fabs,
311
271312 /// Dead inst, ignored by the emitter.
272313 pseudo_dead,
273314
......@@ -286,6 +327,9 @@ pub const Inst = struct {
286327
287328 pseudo_compare,
288329 pseudo_not,
330
331 /// Generates an auipc + jalr pair, with a R_RISCV_CALL_PLT reloc
332 pseudo_extern_fn_reloc,
289333 };
290334
291335 // Make sure we don't accidentally make instructions bigger than expected.
......@@ -387,6 +431,8 @@ pub const RegisterList = struct {
387431const Mir = @This();
388432const std = @import("std");
389433const builtin = @import("builtin");
434const Type = @import("../../type.zig").Type;
435
390436const assert = std.debug.assert;
391437
392438const bits = @import("bits.zig");
src/arch/riscv64/abi.zig+99-57
......@@ -7,7 +7,7 @@ const InternPool = @import("../../InternPool.zig");
77const Module = @import("../../Module.zig");
88const assert = std.debug.assert;
99
10pub const Class = enum { memory, byval, integer, double_integer, fields, none };
10pub const Class = enum { memory, byval, integer, double_integer, fields };
1111
1212pub fn classifyType(ty: Type, mod: *Module) Class {
1313 const target = mod.getTarget();
......@@ -93,11 +93,13 @@ pub fn classifyType(ty: Type, mod: *Module) Class {
9393 }
9494}
9595
96pub const SystemClass = enum { integer, float, memory, none };
97
9698/// There are a maximum of 8 possible return slots. Returned values are in
9799/// the beginning of the array; unused slots are filled with .none.
98pub fn classifySystem(ty: Type, zcu: *Module) [8]Class {
99 var result = [1]Class{.none} ** 8;
100 const memory_class = [_]Class{
100pub fn classifySystem(ty: Type, zcu: *Module) [8]SystemClass {
101 var result = [1]SystemClass{.none} ** 8;
102 const memory_class = [_]SystemClass{
101103 .memory, .none, .none, .none,
102104 .none, .none, .none, .none,
103105 };
......@@ -123,6 +125,7 @@ pub fn classifySystem(ty: Type, zcu: *Module) [8]Class {
123125 return result;
124126 }
125127 result[0] = .integer;
128 if (ty.optionalChild(zcu).abiSize(zcu) == 0) return result;
126129 result[1] = .integer;
127130 return result;
128131 },
......@@ -139,6 +142,18 @@ pub fn classifySystem(ty: Type, zcu: *Module) [8]Class {
139142 }
140143 unreachable; // support > 128 bit int arguments
141144 },
145 .Float => {
146 const target = zcu.getTarget();
147 const features = target.cpu.features;
148
149 const float_bits = ty.floatBits(zcu.getTarget());
150 const float_reg_size: u32 = if (std.Target.riscv.featureSetHas(features, .d)) 64 else 32;
151 if (float_bits <= float_reg_size) {
152 result[0] = .float;
153 return result;
154 }
155 unreachable; // support split float args
156 },
142157 .ErrorUnion => {
143158 const payload_ty = ty.errorUnionPayload(zcu);
144159 const payload_bits = payload_ty.bitSize(zcu);
......@@ -149,12 +164,7 @@ pub fn classifySystem(ty: Type, zcu: *Module) [8]Class {
149164 // anyerror!void can fit into one register
150165 if (payload_bits == 0) return result;
151166
152 if (payload_bits <= 64) {
153 result[1] = .integer;
154 return result;
155 }
156
157 std.debug.panic("TODO: classifySystem ErrorUnion > 64 bit payload", .{});
167 return memory_class;
158168 },
159169 .Struct => {
160170 const layout = ty.containerLayout(zcu);
......@@ -169,6 +179,19 @@ pub fn classifySystem(ty: Type, zcu: *Module) [8]Class {
169179
170180 return memory_class;
171181 },
182 .Array => {
183 const ty_size = ty.abiSize(zcu);
184 if (ty_size <= 8) {
185 result[0] = .integer;
186 return result;
187 }
188 if (ty_size <= 16) {
189 result[0] = .integer;
190 result[1] = .integer;
191 return result;
192 }
193 return memory_class;
194 },
172195 else => |bad_ty| std.debug.panic("classifySystem {s}", .{@tagName(bad_ty)}),
173196 }
174197}
......@@ -230,62 +253,81 @@ fn classifyStruct(
230253 }
231254}
232255
233pub const callee_preserved_regs = [_]Register{
234 // .s0 is ommited to be used as a frame pointer
235 .s1, .s2, .s3, .s4, .s5, .s6, .s7, .s8, .s9, .s10, .s11,
236};
256const allocatable_registers = Registers.Integer.all_regs ++ Registers.Float.all_regs;
257pub const RegisterManager = RegisterManagerFn(@import("CodeGen.zig"), Register, &allocatable_registers);
237258
238pub const function_arg_regs = [_]Register{
239 .a0, .a1, .a2, .a3, .a4, .a5, .a6, .a7,
240};
259// Register classes
260const RegisterBitSet = RegisterManager.RegisterBitSet;
241261
242pub const function_ret_regs = [_]Register{
243 .a0, .a1,
262pub const RegisterClass = enum {
263 int,
264 float,
244265};
245266
246pub const temporary_regs = [_]Register{
247 .t0, .t1, .t2, .t3, .t4, .t5, .t6,
248};
267pub const Registers = struct {
268 pub const all_preserved = Integer.callee_preserved_regs ++ Float.callee_preserved_regs;
249269
250const allocatable_registers = callee_preserved_regs ++ function_arg_regs ++ temporary_regs;
251pub const RegisterManager = RegisterManagerFn(@import("CodeGen.zig"), Register, &allocatable_registers);
270 pub const Integer = struct {
271 // zig fmt: off
272 pub const general_purpose = initRegBitSet(0, callee_preserved_regs.len);
273 pub const function_arg = initRegBitSet(callee_preserved_regs.len, function_arg_regs.len);
274 pub const function_ret = initRegBitSet(callee_preserved_regs.len, function_ret_regs.len);
275 pub const temporary = initRegBitSet(callee_preserved_regs.len + function_arg_regs.len, temporary_regs.len);
276 // zig fmt: on
252277
253// Register classes
254const RegisterBitSet = RegisterManager.RegisterBitSet;
255pub const RegisterClass = struct {
256 pub const gp: RegisterBitSet = blk: {
257 var set = RegisterBitSet.initEmpty();
258 set.setRangeValue(.{
259 .start = 0,
260 .end = callee_preserved_regs.len,
261 }, true);
262 break :blk set;
263 };
278 pub const callee_preserved_regs = [_]Register{
279 // .s0 is omitted to be used as the frame pointer register
280 .s1, .s2, .s3, .s4, .s5, .s6, .s7, .s8, .s9, .s10, .s11,
281 };
264282
265 pub const fa: RegisterBitSet = blk: {
266 var set = RegisterBitSet.initEmpty();
267 set.setRangeValue(.{
268 .start = callee_preserved_regs.len,
269 .end = callee_preserved_regs.len + function_arg_regs.len,
270 }, true);
271 break :blk set;
272 };
283 pub const function_arg_regs = [_]Register{
284 .a0, .a1, .a2, .a3, .a4, .a5, .a6, .a7,
285 };
286
287 pub const function_ret_regs = [_]Register{
288 .a0, .a1,
289 };
290
291 pub const temporary_regs = [_]Register{
292 .t0, .t1, .t2, .t3, .t4, .t5, .t6,
293 };
273294
274 pub const fr: RegisterBitSet = blk: {
275 var set = RegisterBitSet.initEmpty();
276 set.setRangeValue(.{
277 .start = callee_preserved_regs.len,
278 .end = callee_preserved_regs.len + function_ret_regs.len,
279 }, true);
280 break :blk set;
295 pub const all_regs = callee_preserved_regs ++ function_arg_regs ++ temporary_regs;
281296 };
282297
283 pub const tp: RegisterBitSet = blk: {
284 var set = RegisterBitSet.initEmpty();
285 set.setRangeValue(.{
286 .start = callee_preserved_regs.len + function_arg_regs.len,
287 .end = callee_preserved_regs.len + function_arg_regs.len + temporary_regs.len,
288 }, true);
289 break :blk set;
298 pub const Float = struct {
299 // zig fmt: off
300 pub const general_purpose = initRegBitSet(Integer.all_regs.len, callee_preserved_regs.len);
301 pub const function_arg = initRegBitSet(Integer.all_regs.len + callee_preserved_regs.len, function_arg_regs.len);
302 pub const function_ret = initRegBitSet(Integer.all_regs.len + callee_preserved_regs.len, function_ret_regs.len);
303 pub const temporary = initRegBitSet(Integer.all_regs.len + callee_preserved_regs.len + function_arg_regs.len, temporary_regs.len);
304 // zig fmt: on
305
306 pub const callee_preserved_regs = [_]Register{
307 .fs0, .fs1, .fs2, .fs3, .fs4, .fs5, .fs6, .fs7, .fs8, .fs9, .fs10, .fs11,
308 };
309
310 pub const function_arg_regs = [_]Register{
311 .fa0, .fa1, .fa2, .fa3, .fa4, .fa5, .fa6, .fa7,
312 };
313
314 pub const function_ret_regs = [_]Register{
315 .fa0, .fa1,
316 };
317
318 pub const temporary_regs = [_]Register{
319 .ft0, .ft1, .ft2, .ft3, .ft4, .ft5, .ft6, .ft7, .ft8, .ft9, .ft10, .ft11,
320 };
321
322 pub const all_regs = callee_preserved_regs ++ function_arg_regs ++ temporary_regs;
290323 };
291324};
325
326fn initRegBitSet(start: usize, length: usize) RegisterBitSet {
327 var set = RegisterBitSet.initEmpty();
328 set.setRangeValue(.{
329 .start = start,
330 .end = start + length,
331 }, true);
332 return set;
333}
src/arch/riscv64/bits.zig+86-42
......@@ -2,8 +2,12 @@ const std = @import("std");
22const DW = std.dwarf;
33const assert = std.debug.assert;
44const testing = std.testing;
5const Target = std.Target;
6
7const Module = @import("../../Module.zig");
58const Encoding = @import("Encoding.zig");
69const Mir = @import("Mir.zig");
10const abi = @import("abi.zig");
711
812pub const Memory = struct {
913 base: Base,
......@@ -15,12 +19,10 @@ pub const Memory = struct {
1519 reloc: Symbol,
1620 };
1721
18 pub const Mod = union(enum(u1)) {
19 rm: struct {
20 size: Size,
21 disp: i32 = 0,
22 },
23 off: i32,
22 pub const Mod = struct {
23 size: Size,
24 unsigned: bool,
25 disp: i32 = 0,
2426 };
2527
2628 pub const Size = enum(u4) {
......@@ -35,10 +37,10 @@ pub const Memory = struct {
3537
3638 pub fn fromByteSize(size: u64) Size {
3739 return switch (size) {
38 1 => .byte,
39 2 => .hword,
40 4 => .word,
41 8 => .dword,
40 1...1 => .byte,
41 2...2 => .hword,
42 3...4 => .word,
43 5...8 => .dword,
4244 else => unreachable,
4345 };
4446 }
......@@ -65,10 +67,7 @@ pub const Memory = struct {
6567
6668 /// Asserts `mem` can be represented as a `FrameLoc`.
6769 pub fn toFrameLoc(mem: Memory, mir: Mir) Mir.FrameLoc {
68 const offset: i32 = switch (mem.mod) {
69 .off => |off| off,
70 .rm => |rm| rm.disp,
71 };
70 const offset: i32 = mem.mod.disp;
7271
7372 switch (mem.base) {
7473 .reg => |reg| {
......@@ -91,7 +90,7 @@ pub const Memory = struct {
9190
9291pub const Immediate = union(enum) {
9392 signed: i32,
94 unsigned: u32,
93 unsigned: u64,
9594
9695 pub fn u(x: u64) Immediate {
9796 return .{ .unsigned = x };
......@@ -119,24 +118,6 @@ pub const Immediate = union(enum) {
119118 };
120119 }
121120
122 pub fn asUnsigned(imm: Immediate, bit_size: u64) u64 {
123 return switch (imm) {
124 .signed => |x| switch (bit_size) {
125 1, 8 => @as(u8, @bitCast(@as(i8, @intCast(x)))),
126 16 => @as(u16, @bitCast(@as(i16, @intCast(x)))),
127 32, 64 => @as(u32, @bitCast(x)),
128 else => unreachable,
129 },
130 .unsigned => |x| switch (bit_size) {
131 1, 8 => @as(u8, @intCast(x)),
132 16 => @as(u16, @intCast(x)),
133 32 => @as(u32, @intCast(x)),
134 64 => x,
135 else => unreachable,
136 },
137 };
138 }
139
140121 pub fn asBits(imm: Immediate, comptime T: type) T {
141122 const int_info = @typeInfo(T).Int;
142123 if (int_info.signedness != .unsigned) @compileError("Immediate.asBits needs unsigned T");
......@@ -147,12 +128,10 @@ pub const Immediate = union(enum) {
147128 }
148129};
149130
150pub const Register = enum(u6) {
131pub const Register = enum(u8) {
151132 // zig fmt: off
152 x0, x1, x2, x3, x4, x5, x6, x7,
153 x8, x9, x10, x11, x12, x13, x14, x15,
154 x16, x17, x18, x19, x20, x21, x22, x23,
155 x24, x25, x26, x27, x28, x29, x30, x31,
133
134 // base extension registers
156135
157136 zero, // zero
158137 ra, // return address. caller saved
......@@ -166,17 +145,82 @@ pub const Register = enum(u6) {
166145 a2, a3, a4, a5, a6, a7, // fn args. caller saved.
167146 s2, s3, s4, s5, s6, s7, s8, s9, s10, s11, // saved registers. callee saved.
168147 t3, t4, t5, t6, // caller saved
148
149 x0, x1, x2, x3, x4, x5, x6, x7,
150 x8, x9, x10, x11, x12, x13, x14, x15,
151 x16, x17, x18, x19, x20, x21, x22, x23,
152 x24, x25, x26, x27, x28, x29, x30, x31,
153
154
155 // F extension registers
156
157 ft0, ft1, ft2, ft3, ft4, ft5, ft6, ft7, // float temporaries. caller saved.
158 fs0, fs1, // float saved. callee saved.
159 fa0, fa1, // float arg/ret. caller saved.
160 fa2, fa3, fa4, fa5, fa6, fa7, // float arg. called saved.
161 fs2, fs3, fs4, fs5, fs6, fs7, fs8, fs9, fs10, fs11, // float saved. callee saved.
162 ft8, ft9, ft10, ft11, // foat temporaries. calller saved.
163
164 // this register is accessed only through API instructions instead of directly
165 // fcsr,
166
167 f0, f1, f2, f3, f4, f5, f6, f7,
168 f8, f9, f10, f11, f12, f13, f14, f15,
169 f16, f17, f18, f19, f20, f21, f22, f23,
170 f24, f25, f26, f27, f28, f29, f30, f31,
171
169172 // zig fmt: on
170173
171 /// Returns the unique 5-bit ID of this register which is used in
172 /// the machine code
173 pub fn id(self: Register) u5 {
174 return @as(u5, @truncate(@intFromEnum(self)));
174 /// in RISC-V registers are stored as 5 bit IDs and a register can have
175 /// two names. Example being `zero` and `x0` are the same register and have the
176 /// same ID, but are two different entries in the enum. We store floating point
177 /// registers in the same enum. RISC-V uses the same IDs for `f0` and `x0` by
178 /// infering which register is being talked about given the instruction it's in.
179 ///
180 /// The goal of this function is to return the same ID for `zero` and `x0` but two
181 /// seperate IDs for `x0` and `f0`. We will assume that each register set has 32 registers
182 /// and is repeated twice, once for the named version, once for the number version.
183 pub fn id(reg: Register) u7 {
184 const base = switch (@intFromEnum(reg)) {
185 // zig fmt: off
186 @intFromEnum(Register.zero) ... @intFromEnum(Register.x31) => @intFromEnum(Register.zero),
187 @intFromEnum(Register.ft0) ... @intFromEnum(Register.f31) => @intFromEnum(Register.ft0),
188 else => unreachable,
189 // zig fmt: on
190 };
191
192 return @intCast(base + reg.encodeId());
193 }
194
195 pub fn encodeId(reg: Register) u5 {
196 return @truncate(@intFromEnum(reg));
175197 }
176198
177199 pub fn dwarfLocOp(reg: Register) u8 {
178200 return @as(u8, reg.id());
179201 }
202
203 pub fn bitSize(reg: Register, zcu: *const Module) u32 {
204 const features = zcu.getTarget().cpu.features;
205
206 return switch (@intFromEnum(reg)) {
207 // zig fmt: off
208 @intFromEnum(Register.zero) ... @intFromEnum(Register.x31) => 64,
209 @intFromEnum(Register.ft0) ... @intFromEnum(Register.f31) => if (Target.riscv.featureSetHas(features, .d)) 64 else 32,
210 else => unreachable,
211 // zig fmt: on
212 };
213 }
214
215 pub fn class(reg: Register) abi.RegisterClass {
216 return switch (@intFromEnum(reg)) {
217 // zig fmt: off
218 @intFromEnum(Register.zero) ... @intFromEnum(Register.x31) => .int,
219 @intFromEnum(Register.ft0) ... @intFromEnum(Register.f31) => .float,
220 else => unreachable,
221 // zig fmt: on
222 };
223 }
180224};
181225
182226pub const FrameIndex = enum(u32) {
src/arch/riscv64/encoder.zig+26-2
......@@ -11,12 +11,11 @@ pub const Instruction = struct {
1111
1212 pub fn new(mnemonic: Encoding.Mnemonic, ops: []const Operand) !Instruction {
1313 const encoding = (try Encoding.findByMnemonic(mnemonic, ops)) orelse {
14 std.log.err("no encoding found for: {s} {s} {s} {s} {s}", .{
14 std.log.err("no encoding found for: {s} [{s} {s} {s}]", .{
1515 @tagName(mnemonic),
1616 @tagName(if (ops.len > 0) ops[0] else .none),
1717 @tagName(if (ops.len > 1) ops[1] else .none),
1818 @tagName(if (ops.len > 2) ops[2] else .none),
19 @tagName(if (ops.len > 3) ops[3] else .none),
2019 });
2120 return error.InvalidInstruction;
2221 };
......@@ -33,6 +32,31 @@ pub const Instruction = struct {
3332 pub fn encode(inst: Instruction, writer: anytype) !void {
3433 try writer.writeInt(u32, inst.encoding.data.toU32(), .little);
3534 }
35
36 pub fn format(
37 inst: Instruction,
38 comptime fmt: []const u8,
39 _: std.fmt.FormatOptions,
40 writer: anytype,
41 ) !void {
42 std.debug.assert(fmt.len == 0);
43
44 const encoding = inst.encoding;
45
46 try writer.print("{s} ", .{@tagName(encoding.mnemonic)});
47
48 var i: u32 = 0;
49 while (i < inst.ops.len and inst.ops[i] != .none) : (i += 1) {
50 if (i != inst.ops.len and i != 0) try writer.writeAll(", ");
51
52 switch (@as(Instruction.Operand, inst.ops[i])) {
53 .none => unreachable, // it's sliced out above
54 .reg => |reg| try writer.writeAll(@tagName(reg)),
55 .imm => |imm| try writer.print("{d}", .{imm.asSigned(64)}),
56 .mem => unreachable, // there is no "mem" operand in the actual instructions
57 }
58 }
59 }
3660};
3761
3862const std = @import("std");
src/codegen/llvm.zig-2
......@@ -11151,7 +11151,6 @@ fn lowerFnRetTy(o: *Object, fn_info: InternPool.Key.FuncType) Allocator.Error!Bu
1115111151 }
1115211152 return o.builder.structType(.normal, types[0..types_len]);
1115311153 },
11154 .none => unreachable,
1115511154 }
1115611155 },
1115711156 // TODO investigate C ABI for other architectures
......@@ -11409,7 +11408,6 @@ const ParamTypeIterator = struct {
1140911408 it.llvm_index += it.types_len - 1;
1141011409 return .multiple_llvm_types;
1141111410 },
11412 .none => unreachable,
1141311411 }
1141411412 },
1141511413 // TODO investigate C ABI for other architectures
src/link/Elf.zig+2-1
......@@ -5842,7 +5842,8 @@ pub fn tpAddress(self: *Elf) i64 {
58425842 const addr = switch (self.getTarget().cpu.arch) {
58435843 .x86_64 => mem.alignForward(u64, phdr.p_vaddr + phdr.p_memsz, phdr.p_align),
58445844 .aarch64 => mem.alignBackward(u64, phdr.p_vaddr - 16, phdr.p_align),
5845 else => @panic("TODO implement getTpAddress for this arch"),
5845 .riscv64 => phdr.p_vaddr,
5846 else => |arch| std.debug.panic("TODO implement getTpAddress for {s}", .{@tagName(arch)}),
58465847 };
58475848 return @intCast(addr);
58485849}
src/link/Elf/Atom.zig+46-17
......@@ -1409,11 +1409,11 @@ const x86_64 = struct {
14091409 .GOTPC64 => try cwriter.writeInt(i64, GOT + A, .little),
14101410 .SIZE32 => {
14111411 const size = @as(i64, @intCast(target.elfSym(elf_file).st_size));
1412 try cwriter.writeInt(u32, @as(u32, @bitCast(@as(i32, @intCast(size + A)))), .little);
1412 try cwriter.writeInt(u32, @bitCast(@as(i32, @intCast(size + A))), .little);
14131413 },
14141414 .SIZE64 => {
14151415 const size = @as(i64, @intCast(target.elfSym(elf_file).st_size));
1416 try cwriter.writeInt(i64, @as(i64, @intCast(size + A)), .little);
1416 try cwriter.writeInt(i64, @intCast(size + A), .little);
14171417 },
14181418 else => try atom.reportUnhandledRelocError(rel, elf_file),
14191419 }
......@@ -2001,26 +2001,25 @@ const riscv = struct {
20012001 const r_type: elf.R_RISCV = @enumFromInt(rel.r_type());
20022002
20032003 switch (r_type) {
2004 .@"64" => {
2005 try atom.scanReloc(symbol, rel, dynAbsRelocAction(symbol, elf_file), elf_file);
2006 },
2007
2008 .HI20 => {
2009 try atom.scanReloc(symbol, rel, absRelocAction(symbol, elf_file), elf_file);
2010 },
2004 .@"32" => try atom.scanReloc(symbol, rel, absRelocAction(symbol, elf_file), elf_file),
2005 .@"64" => try atom.scanReloc(symbol, rel, dynAbsRelocAction(symbol, elf_file), elf_file),
2006 .HI20 => try atom.scanReloc(symbol, rel, absRelocAction(symbol, elf_file), elf_file),
20112007
20122008 .CALL_PLT => if (symbol.flags.import) {
20132009 symbol.flags.needs_plt = true;
20142010 },
2011 .GOT_HI20 => symbol.flags.needs_got = true,
20152012
2016 .GOT_HI20 => {
2017 symbol.flags.needs_got = true;
2018 },
2013 .TPREL_HI20,
2014 .TPREL_LO12_I,
2015 .TPREL_LO12_S,
2016 .TPREL_ADD,
20192017
20202018 .PCREL_HI20,
20212019 .PCREL_LO12_I,
20222020 .PCREL_LO12_S,
20232021 .LO12_I,
2022 .LO12_S,
20242023 .ADD32,
20252024 .SUB32,
20262025 => {},
......@@ -2058,6 +2057,8 @@ const riscv = struct {
20582057 switch (r_type) {
20592058 .NONE => unreachable,
20602059
2060 .@"32" => try cwriter.writeInt(u32, @as(u32, @truncate(@as(u64, @intCast(S + A)))), .little),
2061
20612062 .@"64" => {
20622063 try atom.resolveDynAbsReloc(
20632064 target,
......@@ -2076,11 +2077,6 @@ const riscv = struct {
20762077 riscv_util.writeInstU(code[r_offset..][0..4], value);
20772078 },
20782079
2079 .LO12_I => {
2080 const value: u32 = @bitCast(math.cast(i32, S + A) orelse return error.Overflow);
2081 riscv_util.writeInstI(code[r_offset..][0..4], value);
2082 },
2083
20842080 .GOT_HI20 => {
20852081 assert(target.flags.has_got);
20862082 const disp: u32 = @bitCast(math.cast(i32, G + GOT + A - P) orelse return error.Overflow);
......@@ -2143,6 +2139,39 @@ const riscv = struct {
21432139 }
21442140 },
21452141
2142 .LO12_I,
2143 .LO12_S,
2144 => {
2145 const disp: u32 = @bitCast(math.cast(i32, S + A) orelse return error.Overflow);
2146 switch (r_type) {
2147 .LO12_I => riscv_util.writeInstI(code[r_offset..][0..4], disp),
2148 .LO12_S => riscv_util.writeInstS(code[r_offset..][0..4], disp),
2149 else => unreachable,
2150 }
2151 },
2152
2153 .TPREL_HI20 => {
2154 const target_addr: u32 = @intCast(target.address(.{}, elf_file));
2155 const val: i32 = @intCast(S + A - target_addr);
2156 riscv_util.writeInstU(code[r_offset..][0..4], @bitCast(val));
2157 },
2158
2159 .TPREL_LO12_I,
2160 .TPREL_LO12_S,
2161 => {
2162 const target_addr: u32 = @intCast(target.address(.{}, elf_file));
2163 const val: i32 = @intCast(S + A - target_addr);
2164 switch (r_type) {
2165 .TPREL_LO12_I => riscv_util.writeInstI(code[r_offset..][0..4], @bitCast(val)),
2166 .TPREL_LO12_S => riscv_util.writeInstS(code[r_offset..][0..4], @bitCast(val)),
2167 else => unreachable,
2168 }
2169 },
2170
2171 .TPREL_ADD => {
2172 // TODO: annotates an ADD instruction that can be removed when TPREL is relaxed
2173 },
2174
21462175 else => |x| switch (@intFromEnum(x)) {
21472176 // Zig custom relocations
21482177 Elf.R_ZIG_GOT_HI20 => {
src/link/Elf/ZigObject.zig+4-1
......@@ -906,7 +906,9 @@ fn updateDeclCode(
906906
907907 log.debug("updateDeclCode {}{*}", .{ decl_name.fmt(&mod.intern_pool), decl });
908908
909 const required_alignment = decl.getAlignment(mod);
909 const required_alignment = decl.getAlignment(mod).max(
910 target_util.minFunctionAlignment(mod.getTarget()),
911 );
910912
911913 const sym = elf_file.symbol(sym_index);
912914 const esym = &self.local_esyms.items(.elf_sym)[sym.esym_index];
......@@ -1634,6 +1636,7 @@ const log = std.log.scoped(.link);
16341636const mem = std.mem;
16351637const relocation = @import("relocation.zig");
16361638const trace = @import("../../tracy.zig").trace;
1639const target_util = @import("../../target.zig");
16371640const std = @import("std");
16381641
16391642const Air = @import("../../Air.zig");
src/target.zig+17
......@@ -431,6 +431,23 @@ pub fn defaultFunctionAlignment(target: std.Target) Alignment {
431431 };
432432}
433433
434pub fn minFunctionAlignment(target: std.Target) Alignment {
435 return switch (target.cpu.arch) {
436 .arm,
437 .armeb,
438 .aarch64,
439 .aarch64_32,
440 .aarch64_be,
441 .riscv32,
442 .riscv64,
443 .sparc,
444 .sparcel,
445 .sparc64,
446 => .@"2",
447 else => .@"1",
448 };
449}
450
434451pub fn supportsFunctionAlignment(target: std.Target) bool {
435452 return switch (target.cpu.arch) {
436453 .wasm32, .wasm64 => false,
test/behavior/abs.zig+3-5
......@@ -6,7 +6,6 @@ test "@abs integers" {
66 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
77 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
88 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
9 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
109
1110 try comptime testAbsIntegers();
1211 try testAbsIntegers();
......@@ -93,18 +92,17 @@ test "@abs floats" {
9392 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
9493 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
9594 if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest;
96 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
9795
9896 try comptime testAbsFloats(f16);
99 try testAbsFloats(f16);
97 if (builtin.zig_backend != .stage2_riscv64) try testAbsFloats(f16);
10098 try comptime testAbsFloats(f32);
10199 try testAbsFloats(f32);
102100 try comptime testAbsFloats(f64);
103101 try testAbsFloats(f64);
104102 try comptime testAbsFloats(f80);
105 if (builtin.zig_backend != .stage2_wasm and builtin.zig_backend != .stage2_spirv64) try testAbsFloats(f80);
103 if (builtin.zig_backend != .stage2_wasm and builtin.zig_backend != .stage2_spirv64 and builtin.zig_backend != .stage2_riscv64) try testAbsFloats(f80);
106104 try comptime testAbsFloats(f128);
107 if (builtin.zig_backend != .stage2_wasm and builtin.zig_backend != .stage2_spirv64) try testAbsFloats(f128);
105 if (builtin.zig_backend != .stage2_wasm and builtin.zig_backend != .stage2_spirv64 and builtin.zig_backend != .stage2_riscv64) try testAbsFloats(f128);
108106}
109107
110108fn testAbsFloats(comptime T: type) !void {
test/behavior/align.zig-8
......@@ -54,7 +54,6 @@ fn addUnaligned(a: *align(1) const u32, b: *align(1) const u32) u32 {
5454}
5555
5656test "@alignCast pointers" {
57 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO
5857 var x: u32 align(4) = 1;
5958 expectsOnly1(&x);
6059 try expect(x == 2);
......@@ -238,7 +237,6 @@ fn addUnalignedSlice(a: []align(1) const u32, b: []align(1) const u32) u32 {
238237}
239238
240239test "specifying alignment allows pointer cast" {
241 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO
242240 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
243241 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
244242
......@@ -251,7 +249,6 @@ fn testBytesAlign(b: u8) !void {
251249}
252250
253251test "@alignCast slices" {
254 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO
255252 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
256253 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
257254 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
......@@ -312,7 +309,6 @@ test "function alignment" {
312309 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
313310 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
314311 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
315 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
316312
317313 // function alignment is a compile error on wasm32/wasm64
318314 if (native_arch == .wasm32 or native_arch == .wasm64) return error.SkipZigTest;
......@@ -426,7 +422,6 @@ test "function callconv expression depends on generic parameter" {
426422}
427423
428424test "runtime-known array index has best alignment possible" {
429 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO
430425 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
431426
432427 // take full advantage of over-alignment
......@@ -562,7 +557,6 @@ test "align(@alignOf(T)) T does not force resolution of T" {
562557}
563558
564559test "align(N) on functions" {
565 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO
566560 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
567561 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
568562 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
......@@ -608,7 +602,6 @@ test "comptime alloc alignment" {
608602}
609603
610604test "@alignCast null" {
611 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO
612605 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
613606 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
614607
......@@ -624,7 +617,6 @@ test "alignment of slice element" {
624617}
625618
626619test "sub-aligned pointer field access" {
627 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO
628620 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
629621 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
630622 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;
test/behavior/alignof.zig-2
......@@ -29,8 +29,6 @@ test "comparison of @alignOf(T) against zero" {
2929}
3030
3131test "correct alignment for elements and slices of aligned array" {
32 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
33
3432 var buf: [1024]u8 align(64) = undefined;
3533 var start: usize = 1;
3634 var end: usize = undefined;
test/behavior/array.zig-19
......@@ -50,7 +50,6 @@ fn getArrayLen(a: []const u32) usize {
5050test "array concat with undefined" {
5151 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
5252 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
53 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
5453
5554 const S = struct {
5655 fn doTheTest() !void {
......@@ -89,7 +88,6 @@ test "array concat with tuple" {
8988
9089test "array init with concat" {
9190 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
92 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
9391
9492 const a = 'a';
9593 var i: [4]u8 = [2]u8{ a, 'b' } ++ [2]u8{ 'c', 'd' };
......@@ -99,7 +97,6 @@ test "array init with concat" {
9997test "array init with mult" {
10098 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
10199 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
102 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
103100
104101 const a = 'a';
105102 var i: [8]u8 = [2]u8{ a, 'b' } ** 4;
......@@ -231,7 +228,6 @@ test "nested arrays of integers" {
231228test "implicit comptime in array type size" {
232229 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
233230 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
234 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
235231
236232 var arr: [plusOne(10)]bool = undefined;
237233 _ = &arr;
......@@ -245,7 +241,6 @@ fn plusOne(x: u32) u32 {
245241test "single-item pointer to array indexing and slicing" {
246242 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
247243 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
248 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
249244
250245 try testSingleItemPtrArrayIndexSlice();
251246 try comptime testSingleItemPtrArrayIndexSlice();
......@@ -271,7 +266,6 @@ fn doSomeMangling(array: *[4]u8) void {
271266
272267test "implicit cast zero sized array ptr to slice" {
273268 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
274 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
275269
276270 {
277271 var b = "".*;
......@@ -310,7 +304,6 @@ const Str = struct { a: []Sub };
310304test "set global var array via slice embedded in struct" {
311305 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
312306 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
313 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
314307
315308 var s = Str{ .a = s_array[0..] };
316309
......@@ -347,7 +340,6 @@ test "read/write through global variable array of struct fields initialized via
347340test "implicit cast single-item pointer" {
348341 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
349342 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
350 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
351343
352344 try testImplicitCastSingleItemPtr();
353345 try comptime testImplicitCastSingleItemPtr();
......@@ -378,7 +370,6 @@ test "comptime evaluating function that takes array by value" {
378370test "runtime initialize array elem and then implicit cast to slice" {
379371 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
380372 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
381 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
382373
383374 var two: i32 = 2;
384375 _ = &two;
......@@ -389,7 +380,6 @@ test "runtime initialize array elem and then implicit cast to slice" {
389380test "array literal as argument to function" {
390381 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
391382 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
392 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
393383
394384 const S = struct {
395385 fn entry(two: i32) !void {
......@@ -418,7 +408,6 @@ test "double nested array to const slice cast in array literal" {
418408 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
419409 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
420410 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
421 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
422411
423412 const S = struct {
424413 fn entry(two: i32) !void {
......@@ -505,7 +494,6 @@ test "anonymous literal in array" {
505494test "access the null element of a null terminated array" {
506495 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
507496 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
508 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
509497
510498 const S = struct {
511499 fn doTheTest() !void {
......@@ -525,7 +513,6 @@ test "type deduction for array subscript expression" {
525513 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
526514 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
527515 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
528 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
529516
530517 const S = struct {
531518 fn doTheTest() !void {
......@@ -716,7 +703,6 @@ test "array of array agregate init" {
716703 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
717704 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
718705 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
719 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
720706
721707 var a = [1]u32{11} ** 10;
722708 var b = [1][10]u32{a} ** 2;
......@@ -767,7 +753,6 @@ test "slicing array of zero-sized values" {
767753 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
768754 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
769755 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;
770 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
771756 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
772757
773758 var arr: [32]u0 = undefined;
......@@ -778,8 +763,6 @@ test "slicing array of zero-sized values" {
778763}
779764
780765test "array init with no result pointer sets field result types" {
781 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
782
783766 const S = struct {
784767 // A function parameter has a result type, but no result pointer.
785768 fn f(arr: [1]u32) u32 {
......@@ -964,7 +947,6 @@ test "array initialized with string literal" {
964947
965948test "array initialized with array with sentinel" {
966949 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
967 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
968950
969951 const S = struct {
970952 a: u32,
......@@ -1051,7 +1033,6 @@ test "union that needs padding bytes inside an array" {
10511033
10521034test "runtime index of array of zero-bit values" {
10531035 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
1054 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
10551036
10561037 var runtime: struct { array: [1]void, index: usize } = undefined;
10571038 runtime = .{ .array = .{{}}, .index = 0 };
test/behavior/basic.zig-17
......@@ -483,7 +483,6 @@ fn testStructInFn() !void {
483483
484484test "fn call returning scalar optional in equality expression" {
485485 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
486 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
487486 try expect(getNull() == null);
488487}
489488
......@@ -494,7 +493,6 @@ fn getNull() ?*i32 {
494493test "global variable assignment with optional unwrapping with var initialized to undefined" {
495494 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
496495 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
497 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
498496
499497 const S = struct {
500498 var data: i32 = 1234;
......@@ -513,7 +511,6 @@ var global_foo: *i32 = undefined;
513511test "peer result location with typed parent, runtime condition, comptime prongs" {
514512 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
515513 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
516 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
517514
518515 const S = struct {
519516 fn doTheTest(arg: i32) i32 {
......@@ -593,7 +590,6 @@ test "equality compare fn ptrs" {
593590
594591test "self reference through fn ptr field" {
595592 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
596 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
597593
598594 const S = struct {
599595 const A = struct {
......@@ -690,7 +686,6 @@ test "string concatenation" {
690686 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
691687 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
692688 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
693 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
694689
695690 const a = "OK" ++ " IT " ++ "WORKED";
696691 const b = "OK IT WORKED";
......@@ -714,7 +709,6 @@ test "result location is optional inside error union" {
714709 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
715710 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
716711 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
717 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
718712
719713 const x = maybe(true) catch unreachable;
720714 try expect(x.? == 42);
......@@ -730,7 +724,6 @@ fn maybe(x: bool) anyerror!?u32 {
730724test "auto created variables have correct alignment" {
731725 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
732726 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
733 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
734727
735728 const S = struct {
736729 fn foo(str: [*]const u8) u32 {
......@@ -838,7 +831,6 @@ test "labeled block implicitly ends in a break" {
838831test "catch in block has correct result location" {
839832 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
840833 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
841 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
842834
843835 const S = struct {
844836 fn open() error{A}!@This() {
......@@ -870,7 +862,6 @@ test "labeled block with runtime branch forwards its result location type to bre
870862
871863test "try in labeled block doesn't cast to wrong type" {
872864 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
873 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
874865
875866 const S = struct {
876867 a: u32,
......@@ -897,7 +888,6 @@ test "weird array and tuple initializations" {
897888 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
898889 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
899890 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
900 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
901891
902892 const E = enum { a, b };
903893 const S = struct { e: E };
......@@ -1016,7 +1006,6 @@ comptime {
10161006
10171007test "switch inside @as gets correct type" {
10181008 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1019 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
10201009
10211010 var a: u32 = 0;
10221011 _ = &a;
......@@ -1101,8 +1090,6 @@ test "orelse coercion as function argument" {
11011090}
11021091
11031092test "runtime-known globals initialized with undefined" {
1104 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
1105
11061093 const S = struct {
11071094 var array: [10]u32 = [_]u32{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
11081095 var vp: [*]u32 = undefined;
......@@ -1246,8 +1233,6 @@ test "pointer to tuple field can be dereferenced at comptime" {
12461233}
12471234
12481235test "proper value is returned from labeled block" {
1249 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
1250
12511236 const S = struct {
12521237 fn hash(v: *u32, key: anytype) void {
12531238 const Key = @TypeOf(key);
......@@ -1385,8 +1370,6 @@ test "allocation and looping over 3-byte integer" {
13851370}
13861371
13871372test "loading array from struct is not optimized away" {
1388 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
1389
13901373 const S = struct {
13911374 arr: [1]u32 = .{0},
13921375 fn doTheTest(self: *@This()) !void {
test/behavior/bitcast.zig-5
......@@ -250,7 +250,6 @@ test "bitcast packed struct to integer and back" {
250250test "implicit cast to error union by returning" {
251251 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
252252 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
253 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
254253
255254 const S = struct {
256255 fn entry() !void {
......@@ -280,8 +279,6 @@ test "comptime bitcast used in expression has the correct type" {
280279}
281280
282281test "bitcast passed as tuple element" {
283 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
284
285282 const S = struct {
286283 fn foo(args: anytype) !void {
287284 comptime assert(@TypeOf(args[0]) == f32);
......@@ -292,8 +289,6 @@ test "bitcast passed as tuple element" {
292289}
293290
294291test "triple level result location with bitcast sandwich passed as tuple element" {
295 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
296
297292 const S = struct {
298293 fn foo(args: anytype) !void {
299294 comptime assert(@TypeOf(args[0]) == f64);
test/behavior/byteswap.zig+1
......@@ -100,6 +100,7 @@ test "@byteSwap vectors u8" {
100100 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
101101 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
102102 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
103 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
103104
104105 try comptime vector8();
105106 try vector8();
test/behavior/byval_arg_var.zig-1
......@@ -5,7 +5,6 @@ var result: []const u8 = "wrong";
55
66test "pass string literal byvalue to a generic var param" {
77 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
8 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
98 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
109
1110 start();
test/behavior/call.zig-6
......@@ -60,7 +60,6 @@ test "tuple parameters" {
6060 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
6161 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
6262 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
63 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
6463
6564 const add = struct {
6665 fn add(a: i32, b: i32) i32 {
......@@ -94,7 +93,6 @@ test "result location of function call argument through runtime condition and st
9493 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
9594 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
9695 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
97 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
9896
9997 const E = enum { a, b };
10098 const S = struct {
......@@ -411,7 +409,6 @@ test "recursive inline call with comptime known argument" {
411409test "inline while with @call" {
412410 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
413411 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
414 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
415412
416413 const S = struct {
417414 fn inc(a: *u32) void {
......@@ -427,8 +424,6 @@ test "inline while with @call" {
427424}
428425
429426test "method call as parameter type" {
430 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
431
432427 const S = struct {
433428 fn foo(x: anytype, y: @TypeOf(x).Inner()) @TypeOf(y) {
434429 return y;
......@@ -477,7 +472,6 @@ test "argument to generic function has correct result type" {
477472 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
478473 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
479474 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
480 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
481475
482476 const S = struct {
483477 fn foo(_: anytype, e: enum { a, b }) bool {
test/behavior/cast.zig-54
......@@ -57,8 +57,6 @@ test "@intCast to comptime_int" {
5757}
5858
5959test "implicit cast comptime numbers to any type when the value fits" {
60 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
61
6260 const a: u64 = 255;
6361 var b: u8 = a;
6462 _ = &b;
......@@ -188,7 +186,6 @@ fn expectIntFromFloat(comptime F: type, f: F, comptime I: type, i: I) !void {
188186test "implicitly cast indirect pointer to maybe-indirect pointer" {
189187 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
190188 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
191 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
192189
193190 const S = struct {
194191 const Self = @This();
......@@ -249,7 +246,6 @@ test "coerce undefined to optional" {
249246 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
250247 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
251248 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
252 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
253249
254250 try expect(MakeType(void).getNull() == null);
255251 try expect(MakeType(void).getNonNull() != null);
......@@ -270,7 +266,6 @@ fn MakeType(comptime T: type) type {
270266test "implicit cast from *[N]T to [*c]T" {
271267 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
272268 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
273 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
274269
275270 var x: [4]u16 = [4]u16{ 0, 1, 2, 3 };
276271 var y: [*c]u16 = &x;
......@@ -347,7 +342,6 @@ test "array coercion to undefined at runtime" {
347342 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
348343 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
349344 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
350 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
351345
352346 @setRuntimeSafety(true);
353347
......@@ -413,7 +407,6 @@ test "peer type unsigned int to signed" {
413407test "expected [*c]const u8, found [*:0]const u8" {
414408 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
415409 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
416 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
417410
418411 var a: [*:0]const u8 = "hello";
419412 _ = &a;
......@@ -483,7 +476,6 @@ fn castToOptionalTypeError(z: i32) !void {
483476test "implicitly cast from [0]T to anyerror![]T" {
484477 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
485478 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
486 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
487479
488480 try testCastZeroArrayToErrSliceMut();
489481 try comptime testCastZeroArrayToErrSliceMut();
......@@ -501,7 +493,6 @@ test "peer type resolution: [0]u8, []const u8, and anyerror![]u8" {
501493 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
502494 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
503495 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
504 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
505496
506497 const S = struct {
507498 fn doTheTest() anyerror!void {
......@@ -558,7 +549,6 @@ fn testCastConstArrayRefToConstSlice() !void {
558549test "peer type resolution: error and [N]T" {
559550 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
560551 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
561 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
562552
563553 try expect(mem.eql(u8, try testPeerErrorAndArray(0), "OK"));
564554 comptime assert(mem.eql(u8, try testPeerErrorAndArray(0), "OK"));
......@@ -583,7 +573,6 @@ fn testPeerErrorAndArray2(x: u8) anyerror![]const u8 {
583573test "single-item pointer of array to slice to unknown length pointer" {
584574 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
585575 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
586 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
587576
588577 try testCastPtrOfArrayToSliceAndPtr();
589578 try comptime testCastPtrOfArrayToSliceAndPtr();
......@@ -841,7 +830,6 @@ test "peer cast *[0]T to E![]const T" {
841830 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
842831 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
843832 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
844 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
845833
846834 var buffer: [5]u8 = "abcde".*;
847835 const buf: anyerror![]const u8 = buffer[0..];
......@@ -857,7 +845,6 @@ test "peer cast *[0]T to []const T" {
857845 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
858846 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
859847 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
860 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
861848
862849 var buffer: [5]u8 = "abcde".*;
863850 const buf: []const u8 = buffer[0..];
......@@ -881,7 +868,6 @@ test "peer resolution of string literals" {
881868 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
882869 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
883870 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
884 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
885871
886872 const S = struct {
887873 const E = enum { a, b, c, d };
......@@ -903,7 +889,6 @@ test "peer resolution of string literals" {
903889test "peer cast [:x]T to []T" {
904890 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
905891 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
906 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
907892
908893 const S = struct {
909894 fn doTheTest() !void {
......@@ -920,7 +905,6 @@ test "peer cast [:x]T to []T" {
920905test "peer cast [N:x]T to [N]T" {
921906 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
922907 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
923 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
924908
925909 const S = struct {
926910 fn doTheTest() !void {
......@@ -937,7 +921,6 @@ test "peer cast [N:x]T to [N]T" {
937921test "peer cast *[N:x]T to *[N]T" {
938922 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
939923 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
940 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
941924
942925 const S = struct {
943926 fn doTheTest() !void {
......@@ -995,7 +978,6 @@ test "peer cast [:x]T to [*:x]T" {
995978test "peer type resolution implicit cast to return type" {
996979 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
997980 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
998 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
999981
1000982 const S = struct {
1001983 fn doTheTest() !void {
......@@ -1016,7 +998,6 @@ test "peer type resolution implicit cast to return type" {
1016998test "peer type resolution implicit cast to variable type" {
1017999 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
10181000 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1019 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
10201001
10211002 const S = struct {
10221003 fn doTheTest() !void {
......@@ -1060,7 +1041,6 @@ test "cast between C pointer with different but compatible types" {
10601041test "peer type resolve string lit with sentinel-terminated mutable slice" {
10611042 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
10621043 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1063 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
10641044
10651045 var array: [4:0]u8 = undefined;
10661046 array[4] = 0; // TODO remove this when #4372 is solved
......@@ -1127,7 +1107,6 @@ test "implicit cast from [*]T to ?*anyopaque" {
11271107 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
11281108 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
11291109 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1130 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
11311110
11321111 var a = [_]u8{ 3, 2, 1 };
11331112 var runtime_zero: usize = 0;
......@@ -1158,7 +1137,6 @@ fn foobar(func: PFN_void) !void {
11581137
11591138test "cast function with an opaque parameter" {
11601139 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
1161 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
11621140
11631141 if (builtin.zig_backend == .stage2_c) {
11641142 // https://github.com/ziglang/zig/issues/16845
......@@ -1191,7 +1169,6 @@ test "implicit ptr to *anyopaque" {
11911169 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
11921170 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
11931171 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1194 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
11951172
11961173 var a: u32 = 1;
11971174 const ptr: *align(@alignOf(u32)) anyopaque = &a;
......@@ -1205,7 +1182,6 @@ test "implicit ptr to *anyopaque" {
12051182test "return null from fn () anyerror!?&T" {
12061183 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
12071184 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1208 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
12091185
12101186 const a = returnNullFromOptionalTypeErrorRef();
12111187 const b = returnNullLitFromOptionalTypeErrorRef();
......@@ -1296,7 +1272,6 @@ test "implicit cast from *T to ?*anyopaque" {
12961272 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
12971273 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
12981274 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1299 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
13001275
13011276 var a: u8 = 1;
13021277 incrementVoidPtrValue(&a);
......@@ -1310,7 +1285,6 @@ fn incrementVoidPtrValue(value: ?*anyopaque) void {
13101285test "implicit cast *[0]T to E![]const u8" {
13111286 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
13121287 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1313 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
13141288
13151289 var x = @as(anyerror![]const u8, &[0]u8{});
13161290 _ = &x;
......@@ -1332,7 +1306,6 @@ test "*const [N]null u8 to ?[]const u8" {
13321306 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
13331307 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
13341308 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1335 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
13361309
13371310 const S = struct {
13381311 fn doTheTest() !void {
......@@ -1369,7 +1342,6 @@ test "assignment to optional pointer result loc" {
13691342 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
13701343 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
13711344 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1372 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
13731345
13741346 var foo: struct { ptr: ?*anyopaque } = .{ .ptr = &global_struct };
13751347 _ = &foo;
......@@ -1377,7 +1349,6 @@ test "assignment to optional pointer result loc" {
13771349}
13781350
13791351test "cast between *[N]void and []void" {
1380 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
13811352 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
13821353
13831354 var a: [4]void = undefined;
......@@ -1445,7 +1416,6 @@ test "peer type resolution: unreachable, null, slice" {
14451416 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
14461417 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
14471418 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1448 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
14491419
14501420 const S = struct {
14511421 fn doTheTest(num: usize, word: []const u8) !void {
......@@ -1486,7 +1456,6 @@ test "cast compatible optional types" {
14861456 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
14871457 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
14881458 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1489 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
14901459
14911460 var a: ?[:0]const u8 = null;
14921461 _ = &a;
......@@ -1497,7 +1466,6 @@ test "cast compatible optional types" {
14971466test "coerce undefined single-item pointer of array to error union of slice" {
14981467 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
14991468 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1500 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
15011469
15021470 const a = @as([*]u8, undefined)[0..0];
15031471 var b: error{a}![]const u8 = a;
......@@ -1600,7 +1568,6 @@ test "bitcast packed struct with u0" {
16001568
16011569test "optional pointer coerced to optional allowzero pointer" {
16021570 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1603 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
16041571
16051572 var p: ?*u32 = undefined;
16061573 var q: ?*allowzero u32 = undefined;
......@@ -1617,8 +1584,6 @@ test "optional slice coerced to allowzero many pointer" {
16171584}
16181585
16191586test "optional slice passed as parameter coerced to allowzero many pointer" {
1620 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
1621
16221587 const ns = struct {
16231588 const Color = struct {
16241589 r: u8,
......@@ -1638,8 +1603,6 @@ test "optional slice passed as parameter coerced to allowzero many pointer" {
16381603}
16391604
16401605test "single item pointer to pointer to array to slice" {
1641 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
1642
16431606 var x: i32 = 1234;
16441607 try expect(@as([]const i32, @as(*[1]i32, &x))[0] == 1234);
16451608 const z1 = @as([]const i32, @as(*[1]i32, &x));
......@@ -1682,8 +1645,6 @@ test "@volatileCast without a result location" {
16821645}
16831646
16841647test "coercion from single-item pointer to @as to slice" {
1685 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
1686
16871648 var x: u32 = 1;
16881649
16891650 // Why the following line gets a compile error?
......@@ -1696,7 +1657,6 @@ test "peer type resolution: const sentinel slice and mutable non-sentinel slice"
16961657 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
16971658 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
16981659 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1699 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
17001660
17011661 const S = struct {
17021662 fn doTheTest(comptime T: type, comptime s: T) !void {
......@@ -1727,7 +1687,6 @@ test "peer type resolution: float and comptime-known fixed-width integer" {
17271687 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
17281688 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
17291689 if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest;
1730 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
17311690
17321691 const i: u8 = 100;
17331692 var f: f32 = 1.234;
......@@ -1750,7 +1709,6 @@ test "peer type resolution: same array type with sentinel" {
17501709 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
17511710 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
17521711 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1753 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
17541712
17551713 var a: [2:0]u32 = .{ 0, 1 };
17561714 var b: [2:0]u32 = .{ 2, 3 };
......@@ -1773,7 +1731,6 @@ test "peer type resolution: array with sentinel and array without sentinel" {
17731731 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
17741732 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
17751733 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1776 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
17771734
17781735 var a: [2:0]u32 = .{ 0, 1 };
17791736 var b: [2]u32 = .{ 2, 3 };
......@@ -1843,7 +1800,6 @@ test "peer type resolution: error union and optional of same type" {
18431800 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
18441801 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
18451802 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1846 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
18471803
18481804 const E = error{Foo};
18491805 var a: E!*u8 = error.Foo;
......@@ -1867,7 +1823,6 @@ test "peer type resolution: C pointer and @TypeOf(null)" {
18671823 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
18681824 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
18691825 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1870 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
18711826
18721827 var a: [*c]c_int = 0x1000;
18731828 _ = &a;
......@@ -1981,7 +1936,6 @@ test "peer type resolution: array and tuple" {
19811936 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
19821937 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
19831938 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1984 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
19851939
19861940 var arr: [3]i32 = .{ 1, 2, 3 };
19871941 _ = &arr;
......@@ -2116,7 +2070,6 @@ test "peer type resolution: tuple pointer and optional slice" {
21162070 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
21172071 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
21182072 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
2119 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
21202073 // Miscompilation on Intel's OpenCL CPU runtime.
21212074 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; // flaky
21222075
......@@ -2209,7 +2162,6 @@ test "peer type resolution: tuples with comptime fields" {
22092162 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
22102163 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
22112164 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; // TODO
2212 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
22132165
22142166 const a = .{ 1, 2 };
22152167 const b = .{ @as(u32, 3), @as(i16, 4) };
......@@ -2241,7 +2193,6 @@ test "peer type resolution: C pointer and many pointer" {
22412193 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
22422194 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
22432195 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
2244 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
22452196
22462197 var buf = "hello".*;
22472198
......@@ -2309,7 +2260,6 @@ test "peer type resolution: arrays of compatible types" {
23092260 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
23102261 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
23112262 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
2312 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
23132263
23142264 var e0: u8 = 3;
23152265 var e1: u8 = 2;
......@@ -2365,7 +2315,6 @@ test "cast builtins can wrap result in error union" {
23652315 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
23662316 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
23672317 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
2368 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
23692318
23702319 const S = struct {
23712320 const MyEnum = enum(u32) { _ };
......@@ -2404,7 +2353,6 @@ test "cast builtins can wrap result in error union and optional" {
24042353 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
24052354 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
24062355 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
2407 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
24082356
24092357 const S = struct {
24102358 const MyEnum = enum(u32) { _ };
......@@ -2600,7 +2548,6 @@ test "@intFromBool on vector" {
26002548
26012549test "numeric coercions with undefined" {
26022550 if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest;
2603 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
26042551
26052552 const from: i32 = undefined;
26062553 var to: f32 = from;
......@@ -2624,7 +2571,6 @@ test "@as does not corrupt values with incompatible representations" {
26242571 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
26252572 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
26262573 if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest;
2627 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
26282574
26292575 const x: f32 = @as(f16, blk: {
26302576 if (false) {
test/behavior/comptime_memory.zig-4
......@@ -408,8 +408,6 @@ test "mutate entire slice at comptime" {
408408}
409409
410410test "dereference undefined pointer to zero-bit type" {
411 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
412
413411 const p0: *void = undefined;
414412 try testing.expectEqual({}, p0.*);
415413
......@@ -515,7 +513,5 @@ fn fieldPtrTest() u32 {
515513 return a.value;
516514}
517515test "pointer in aggregate field can mutate comptime state" {
518 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
519
520516 try comptime std.testing.expect(fieldPtrTest() == 2);
521517}
test/behavior/defer.zig-3
......@@ -116,7 +116,6 @@ test "errdefer with payload" {
116116 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
117117 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
118118 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
119 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
120119
121120 const S = struct {
122121 fn foo() !i32 {
......@@ -139,7 +138,6 @@ test "reference to errdefer payload" {
139138 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
140139 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
141140 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; // TODO
142 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
143141
144142 const S = struct {
145143 fn foo() !i32 {
......@@ -162,7 +160,6 @@ test "reference to errdefer payload" {
162160test "simple else prong doesn't emit an error for unreachable else prong" {
163161 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
164162 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
165 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
166163
167164 const S = struct {
168165 fn foo() error{Foo}!void {
test/behavior/empty_union.zig-4
......@@ -48,8 +48,6 @@ test "empty extern union" {
4848}
4949
5050test "empty union passed as argument" {
51 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
52
5351 const U = union(enum) {
5452 fn f(u: @This()) void {
5553 switch (u) {}
......@@ -59,8 +57,6 @@ test "empty union passed as argument" {
5957}
6058
6159test "empty enum passed as argument" {
62 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
63
6460 const E = enum {
6561 fn f(e: @This()) void {
6662 switch (e) {}
test/behavior/enum.zig-5
......@@ -610,7 +610,6 @@ fn testEnumWithSpecifiedTagValues(x: MultipleChoice) !void {
610610test "enum with specified tag values" {
611611 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
612612 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
613 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
614613
615614 try testEnumWithSpecifiedTagValues(MultipleChoice.C);
616615 try comptime testEnumWithSpecifiedTagValues(MultipleChoice.C);
......@@ -684,7 +683,6 @@ test "empty non-exhaustive enum" {
684683test "single field non-exhaustive enum" {
685684 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
686685 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
687 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
688686
689687 const S = struct {
690688 const E = enum(u8) { a, _ };
......@@ -749,7 +747,6 @@ test "cast integer literal to enum" {
749747test "enum with specified and unspecified tag values" {
750748 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
751749 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
752 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
753750
754751 try testEnumWithSpecifiedAndUnspecifiedTagValues(MultipleChoice2.D);
755752 try comptime testEnumWithSpecifiedAndUnspecifiedTagValues(MultipleChoice2.D);
......@@ -858,8 +855,6 @@ fn doALoopThing(id: EnumWithOneMember) void {
858855}
859856
860857test "comparison operator on enum with one member is comptime-known" {
861 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
862
863858 doALoopThing(EnumWithOneMember.Eof);
864859}
865860
test/behavior/error.zig+1-25
......@@ -31,7 +31,6 @@ fn shouldBeNotEqual(a: anyerror, b: anyerror) void {
3131
3232test "error binary operator" {
3333 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
34 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
3534
3635 const a = errBinaryOperatorG(true) catch 3;
3736 const b = errBinaryOperatorG(false) catch 3;
......@@ -63,14 +62,12 @@ pub fn baz() anyerror!i32 {
6362
6463test "error wrapping" {
6564 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
66 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
6765
6866 try expect((baz() catch unreachable) == 15);
6967}
7068
7169test "unwrap simple value from error" {
7270 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
73 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
7471
7572 const i = unwrapSimpleValueFromErrorDo() catch unreachable;
7673 try expect(i == 13);
......@@ -81,7 +78,6 @@ fn unwrapSimpleValueFromErrorDo() anyerror!isize {
8178
8279test "error return in assignment" {
8380 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
84 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
8581
8682 doErrReturnInAssignment() catch unreachable;
8783}
......@@ -104,7 +100,6 @@ test "syntax: optional operator in front of error union operator" {
104100test "widen cast integer payload of error union function call" {
105101 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
106102 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
107 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
108103
109104 const S = struct {
110105 fn errorable() !u64 {
......@@ -129,7 +124,6 @@ test "debug info for optional error set" {
129124
130125test "implicit cast to optional to error union to return result loc" {
131126 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
132 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
133127
134128 const S = struct {
135129 fn entry() !void {
......@@ -241,8 +235,6 @@ fn testExplicitErrorSetCast(set1: Set1) !void {
241235}
242236
243237test "@errorCast on error unions" {
244 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
245
246238 const S = struct {
247239 fn doTheTest() !void {
248240 {
......@@ -270,7 +262,6 @@ test "@errorCast on error unions" {
270262
271263test "comptime test error for empty error set" {
272264 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
273 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
274265
275266 try testComptimeTestErrorEmptySet(1234);
276267 try comptime testComptimeTestErrorEmptySet(1234);
......@@ -306,8 +297,6 @@ test "inferred empty error set comptime catch" {
306297}
307298
308299test "error inference with an empty set" {
309 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
310
311300 const S = struct {
312301 const Struct = struct {
313302 pub fn func() (error{})!usize {
......@@ -362,7 +351,6 @@ fn quux_1() !i32 {
362351
363352test "error: Zero sized error set returned with value payload crash" {
364353 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
365 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
366354
367355 _ = try foo3(0);
368356 _ = try comptime foo3(0);
......@@ -376,7 +364,6 @@ fn foo3(b: usize) Error!usize {
376364test "error: Infer error set from literals" {
377365 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
378366 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
379 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
380367
381368 _ = nullLiteral("n") catch |err| handleErrors(err);
382369 _ = floatLiteral("n") catch |err| handleErrors(err);
......@@ -498,7 +485,6 @@ test "optional error set is the same size as error set" {
498485test "nested catch" {
499486 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
500487 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
501 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
502488
503489 const S = struct {
504490 fn entry() !void {
......@@ -524,7 +510,6 @@ test "nested catch" {
524510test "function pointer with return type that is error union with payload which is pointer of parent struct" {
525511 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
526512 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
527 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
528513
529514 const S = struct {
530515 const Foo = struct {
......@@ -582,7 +567,6 @@ test "error payload type is correctly resolved" {
582567 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
583568 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
584569 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
585 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
586570
587571 const MyIntWrapper = struct {
588572 const Self = @This();
......@@ -755,7 +739,6 @@ test "ret_ptr doesn't cause own inferred error set to be resolved" {
755739
756740test "simple else prong allowed even when all errors handled" {
757741 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
758 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
759742
760743 const S = struct {
761744 fn foo() !u8 {
......@@ -873,7 +856,6 @@ test "alignment of wrapping an error union payload" {
873856
874857test "compare error union and error set" {
875858 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
876 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
877859
878860 var a: anyerror = error.Foo;
879861 var b: anyerror!u32 = error.Bar;
......@@ -1039,7 +1021,6 @@ test "function called at runtime is properly analyzed for inferred error set" {
10391021 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
10401022 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
10411023 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1042 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
10431024
10441025 const S = struct {
10451026 fn foo() !void {
......@@ -1063,7 +1044,6 @@ test "generic type constructed from inferred error set of unresolved function" {
10631044 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
10641045 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
10651046 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1066 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
10671047
10681048 const S = struct {
10691049 fn write(_: void, bytes: []const u8) !usize {
......@@ -1079,8 +1059,6 @@ test "generic type constructed from inferred error set of unresolved function" {
10791059}
10801060
10811061test "errorCast to adhoc inferred error set" {
1082 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
1083
10841062 const S = struct {
10851063 inline fn baz() !i32 {
10861064 return @errorCast(err());
......@@ -1093,8 +1071,6 @@ test "errorCast to adhoc inferred error set" {
10931071}
10941072
10951073test "errorCast from error sets to error unions" {
1096 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
1097
10981074 const err_union: Set1!void = @errorCast(error.A);
10991075 try expectError(error.A, err_union);
11001076}
......@@ -1103,8 +1079,8 @@ test "result location initialization of error union with OPV payload" {
11031079 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
11041080 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
11051081 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1106 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
11071082 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
1083 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
11081084
11091085 const S = struct {
11101086 x: u0,
test/behavior/eval.zig-16
......@@ -73,7 +73,6 @@ fn constExprEvalOnSingleExprBlocksFn(x: i32, b: bool) i32 {
7373test "constant expressions" {
7474 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
7575 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
76 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
7776
7877 var array: [array_size]u8 = undefined;
7978 _ = &array;
......@@ -506,7 +505,6 @@ test "comptime shlWithOverflow" {
506505test "const ptr to variable data changes at runtime" {
507506 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
508507 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
509 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
510508
511509 try expect(foo_ref.name[0] == 'a');
512510 foo_ref.name = "b";
......@@ -549,7 +547,6 @@ test "static eval list init" {
549547 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
550548 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
551549 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
552 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
553550
554551 try expect(static_vec3.data[2] == 1.0);
555552 try expect(vec3(0.0, 0.0, 3.0).data[2] == 3.0);
......@@ -721,8 +718,6 @@ fn loopNTimes(comptime n: usize) void {
721718}
722719
723720test "variable inside inline loop that has different types on different iterations" {
724 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
725
726721 try testVarInsideInlineLoop(.{ true, @as(u32, 42) });
727722}
728723
......@@ -746,7 +741,6 @@ test "array concatenation of function calls" {
746741 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
747742 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
748743 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
749 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
750744
751745 var a = oneItem(3) ++ oneItem(4);
752746 try expect(std.mem.eql(i32, &a, &[_]i32{ 3, 4 }));
......@@ -756,7 +750,6 @@ test "array multiplication of function calls" {
756750 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
757751 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
758752 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
759 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
760753
761754 var a = oneItem(3) ** scalar(2);
762755 try expect(std.mem.eql(i32, &a, &[_]i32{ 3, 3 }));
......@@ -774,7 +767,6 @@ test "array concatenation peer resolves element types - value" {
774767 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
775768 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
776769 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
777 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
778770
779771 var a = [2]u3{ 1, 7 };
780772 var b = [3]u8{ 200, 225, 255 };
......@@ -1088,7 +1080,6 @@ test "comptime break operand passing through runtime condition converted to runt
10881080test "comptime break operand passing through runtime switch converted to runtime break" {
10891081 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
10901082 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1091 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
10921083
10931084 const S = struct {
10941085 fn doTheTest(runtime: u8) !void {
......@@ -1556,7 +1547,6 @@ test "non-optional and optional array elements concatenated" {
15561547 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
15571548 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
15581549 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1559 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
15601550
15611551 const array = [1]u8{'A'} ++ [1]?u8{null};
15621552 var index: usize = 0;
......@@ -1631,8 +1621,6 @@ test "struct in comptime false branch is not evaluated" {
16311621}
16321622
16331623test "result of nested switch assigned to variable" {
1634 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
1635
16361624 var zds: u32 = 0;
16371625 zds = switch (zds) {
16381626 0 => switch (zds) {
......@@ -1647,8 +1635,6 @@ test "result of nested switch assigned to variable" {
16471635}
16481636
16491637test "inline for loop of functions returning error unions" {
1650 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
1651
16521638 const T1 = struct {
16531639 fn v() error{}!usize {
16541640 return 1;
......@@ -1667,8 +1653,6 @@ test "inline for loop of functions returning error unions" {
16671653}
16681654
16691655test "if inside a switch" {
1670 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
1671
16721656 var condition = true;
16731657 var wave_type: u32 = 0;
16741658 _ = .{ &condition, &wave_type };
test/behavior/extern.zig-2
......@@ -20,7 +20,6 @@ test "function extern symbol" {
2020 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
2121 if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest;
2222 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
23 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
2423
2524 const a = @extern(*const fn () callconv(.C) i32, .{ .name = "a_mystery_function" });
2625 try expect(a() == 4567);
......@@ -34,7 +33,6 @@ test "function extern symbol matches extern decl" {
3433 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
3534 if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest;
3635 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
37 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
3836
3937 const S = struct {
4038 extern fn another_mystery_function() u32;
test/behavior/floatop.zig-13
......@@ -22,8 +22,6 @@ test "add f16" {
2222}
2323
2424test "add f32/f64" {
25 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
26
2725 try testAdd(f32);
2826 try comptime testAdd(f32);
2927 try testAdd(f64);
......@@ -60,8 +58,6 @@ test "sub f16" {
6058}
6159
6260test "sub f32/f64" {
63 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
64
6561 try testSub(f32);
6662 try comptime testSub(f32);
6763 try testSub(f64);
......@@ -98,8 +94,6 @@ test "mul f16" {
9894}
9995
10096test "mul f32/f64" {
101 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
102
10397 try testMul(f32);
10498 try comptime testMul(f32);
10599 try testMul(f64);
......@@ -1005,7 +999,6 @@ test "@abs f32/f64" {
1005999 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
10061000 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
10071001 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1008 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
10091002
10101003 try testFabs(f32);
10111004 try comptime testFabs(f32);
......@@ -1622,7 +1615,6 @@ test "comptime inf >= runtime 1" {
16221615test "comptime isNan(nan * 1)" {
16231616 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
16241617 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1625 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
16261618
16271619 const nan_times_one = comptime std.math.nan(f64) * 1;
16281620 try std.testing.expect(std.math.isNan(nan_times_one));
......@@ -1630,7 +1622,6 @@ test "comptime isNan(nan * 1)" {
16301622test "runtime isNan(nan * 1)" {
16311623 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
16321624 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1633 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
16341625
16351626 const nan_times_one = std.math.nan(f64) * 1;
16361627 try std.testing.expect(std.math.isNan(nan_times_one));
......@@ -1638,7 +1629,6 @@ test "runtime isNan(nan * 1)" {
16381629test "comptime isNan(nan * 0)" {
16391630 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
16401631 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1641 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
16421632
16431633 const nan_times_zero = comptime std.math.nan(f64) * 0;
16441634 try std.testing.expect(std.math.isNan(nan_times_zero));
......@@ -1648,7 +1638,6 @@ test "comptime isNan(nan * 0)" {
16481638test "runtime isNan(nan * 0)" {
16491639 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
16501640 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1651 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
16521641
16531642 const nan_times_zero = std.math.nan(f64) * 0;
16541643 try std.testing.expect(std.math.isNan(nan_times_zero));
......@@ -1658,7 +1647,6 @@ test "runtime isNan(nan * 0)" {
16581647test "comptime isNan(inf * 0)" {
16591648 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
16601649 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1661 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
16621650
16631651 const inf_times_zero = comptime std.math.inf(f64) * 0;
16641652 try std.testing.expect(std.math.isNan(inf_times_zero));
......@@ -1668,7 +1656,6 @@ test "comptime isNan(inf * 0)" {
16681656test "runtime isNan(inf * 0)" {
16691657 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
16701658 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1671 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
16721659
16731660 const inf_times_zero = std.math.inf(f64) * 0;
16741661 try std.testing.expect(std.math.isNan(inf_times_zero));
test/behavior/fn.zig-19
......@@ -71,7 +71,6 @@ fn outer(y: u32) *const fn (u32) u32 {
7171
7272test "return inner function which references comptime variable of outer function" {
7373 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
74 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
7574
7675 const func = outer(10);
7776 try expect(func(3) == 7);
......@@ -81,7 +80,6 @@ test "discard the result of a function that returns a struct" {
8180 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
8281 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
8382 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
84 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
8583
8684 const S = struct {
8785 fn entry() void {
......@@ -106,7 +104,6 @@ test "inline function call that calls optional function pointer, return pointer
106104 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
107105 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
108106 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
109 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
110107
111108 const S = struct {
112109 field: u32,
......@@ -191,7 +188,6 @@ test "function with complex callconv and return type expressions" {
191188
192189test "pass by non-copying value" {
193190 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
194 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
195191
196192 try expect(addPointCoords(Point{ .x = 1, .y = 2 }) == 3);
197193}
......@@ -207,7 +203,6 @@ fn addPointCoords(pt: Point) i32 {
207203
208204test "pass by non-copying value through var arg" {
209205 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
210 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
211206
212207 try expect((try addPointCoordsVar(Point{ .x = 1, .y = 2 })) == 3);
213208}
......@@ -219,7 +214,6 @@ fn addPointCoordsVar(pt: anytype) !i32 {
219214
220215test "pass by non-copying value as method" {
221216 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
222 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
223217
224218 var pt = Point2{ .x = 1, .y = 2 };
225219 try expect(pt.addPointCoords() == 3);
......@@ -236,7 +230,6 @@ const Point2 = struct {
236230
237231test "pass by non-copying value as method, which is generic" {
238232 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
239 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
240233
241234 var pt = Point3{ .x = 1, .y = 2 };
242235 try expect(pt.addPointCoords(i32) == 3);
......@@ -265,7 +258,6 @@ test "implicit cast fn call result to optional in field result" {
265258 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
266259 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
267260 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
268 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
269261
270262 const S = struct {
271263 fn entry() !void {
......@@ -292,7 +284,6 @@ test "implicit cast fn call result to optional in field result" {
292284test "void parameters" {
293285 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
294286 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
295 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
296287
297288 try voidFun(1, void{}, 2, {});
298289}
......@@ -356,7 +347,6 @@ test "function call with anon list literal" {
356347 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
357348 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
358349 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
359 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
360350
361351 const S = struct {
362352 fn doTheTest() !void {
......@@ -377,7 +367,6 @@ test "function call with anon list literal - 2D" {
377367 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
378368 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
379369 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
380 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
381370
382371 const S = struct {
383372 fn doTheTest() !void {
......@@ -414,8 +403,6 @@ test "ability to give comptime types and non comptime types to same parameter" {
414403}
415404
416405test "function with inferred error set but returning no error" {
417 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
418
419406 const S = struct {
420407 fn foo() !void {}
421408 };
......@@ -426,7 +413,6 @@ test "function with inferred error set but returning no error" {
426413
427414test "import passed byref to function in return type" {
428415 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
429 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
430416
431417 const S = struct {
432418 fn get() @import("std").ArrayListUnmanaged(i32) {
......@@ -485,7 +471,6 @@ test "method call with optional and error union first param" {
485471test "method call with optional pointer first param" {
486472 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
487473 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
488 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
489474
490475 const S = struct {
491476 x: i32 = 1234,
......@@ -505,7 +490,6 @@ test "using @ptrCast on function pointers" {
505490 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
506491 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
507492 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
508 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
509493
510494 const S = struct {
511495 const A = struct { data: [4]u8 };
......@@ -543,7 +527,6 @@ test "function returns function returning type" {
543527
544528test "peer type resolution of inferred error set with non-void payload" {
545529 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
546 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
547530
548531 const S = struct {
549532 fn openDataFile(mode: enum { read, write }) !u32 {
......@@ -586,8 +569,6 @@ test "lazy values passed to anytype parameter" {
586569}
587570
588571test "pass and return comptime-only types" {
589 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
590
591572 const S = struct {
592573 fn returnNull(comptime x: @Type(.Null)) @Type(.Null) {
593574 return x;
test/behavior/fn_delegation.zig-1
......@@ -34,7 +34,6 @@ fn custom(comptime T: type, comptime num: u64) fn (T) u64 {
3434test "fn delegation" {
3535 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
3636 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
37 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
3837
3938 const foo = Foo{};
4039 try expect(foo.one() == 11);
test/behavior/for.zig-14
......@@ -69,7 +69,6 @@ test "basic for loop" {
6969 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
7070 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
7171 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
72 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
7372
7473 const expected_result = [_]u8{ 9, 8, 7, 6, 0, 1, 2, 3 } ** 3;
7574
......@@ -134,7 +133,6 @@ test "for with null and T peer types and inferred result location type" {
134133test "2 break statements and an else" {
135134 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
136135 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
137 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
138136
139137 const S = struct {
140138 fn entry(t: bool, f: bool) !void {
......@@ -183,7 +181,6 @@ fn mangleString(s: []u8) void {
183181test "for copies its payload" {
184182 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
185183 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
186 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
187184
188185 const S = struct {
189186 fn doTheTest() !void {
......@@ -203,7 +200,6 @@ test "for on slice with allowzero ptr" {
203200 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
204201 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
205202 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
206 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
207203
208204 const S = struct {
209205 fn doTheTest(slice: []const u8) !void {
......@@ -219,7 +215,6 @@ test "for on slice with allowzero ptr" {
219215test "else continue outer for" {
220216 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
221217 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
222 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
223218
224219 var i: usize = 6;
225220 var buf: [5]u8 = undefined;
......@@ -283,7 +278,6 @@ test "two counters" {
283278test "1-based counter and ptr to array" {
284279 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
285280 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
286 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
287281
288282 var ok: usize = 0;
289283
......@@ -317,7 +311,6 @@ test "slice and two counters, one is offset and one is runtime" {
317311 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
318312 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
319313 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
320 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
321314
322315 const slice: []const u8 = "blah";
323316 var start: usize = 0;
......@@ -347,7 +340,6 @@ test "two slices, one captured by-ref" {
347340 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
348341 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
349342 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
350 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
351343
352344 var buf: [10]u8 = undefined;
353345 const slice1: []const u8 = "blah";
......@@ -367,7 +359,6 @@ test "raw pointer and slice" {
367359 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
368360 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
369361 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
370 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
371362
372363 var buf: [10]u8 = undefined;
373364 const slice: []const u8 = "blah";
......@@ -387,7 +378,6 @@ test "raw pointer and counter" {
387378 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
388379 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
389380 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
390 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
391381
392382 var buf: [10]u8 = undefined;
393383 const ptr: [*]u8 = &buf;
......@@ -406,7 +396,6 @@ test "inline for with slice as the comptime-known" {
406396 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
407397 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
408398 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
409 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
410399
411400 const comptime_slice = "hello";
412401 var runtime_i: usize = 3;
......@@ -438,7 +427,6 @@ test "inline for with counter as the comptime-known" {
438427 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
439428 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
440429 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
441 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
442430
443431 var runtime_slice = "hello";
444432 var runtime_i: usize = 3;
......@@ -471,7 +459,6 @@ test "inline for on tuple pointer" {
471459 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
472460 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
473461 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
474 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
475462
476463 const S = struct { u32, u32, u32 };
477464 var s: S = .{ 100, 200, 300 };
......@@ -487,7 +474,6 @@ test "ref counter that starts at zero" {
487474 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
488475 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
489476 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
490 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
491477
492478 for ([_]usize{ 0, 1, 2 }, 0..) |i, j| {
493479 try expectEqual(i, j);
test/behavior/generics.zig-10
......@@ -117,7 +117,6 @@ test "function with return type type" {
117117 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
118118 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
119119 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
120 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
121120
122121 var list: List(i32) = undefined;
123122 var list2: List(i32) = undefined;
......@@ -159,7 +158,6 @@ test "generic fn with implicit cast" {
159158 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
160159 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
161160 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
162 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
163161
164162 try expect(getFirstByte(u8, &[_]u8{13}) == 13);
165163 try expect(getFirstByte(u16, &[_]u16{
......@@ -287,7 +285,6 @@ test "generic function instantiation turns into comptime call" {
287285
288286test "generic function with void and comptime parameter" {
289287 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
290 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
291288
292289 const S = struct { x: i32 };
293290 const namespace = struct {
......@@ -304,7 +301,6 @@ test "generic function with void and comptime parameter" {
304301test "anonymous struct return type referencing comptime parameter" {
305302 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
306303 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
307 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
308304
309305 const S = struct {
310306 pub fn extraData(comptime T: type, index: usize) struct { data: T, end: usize } {
......@@ -323,7 +319,6 @@ test "generic function instantiation non-duplicates" {
323319 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
324320 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
325321 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
326 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
327322 if (builtin.os.tag == .wasi) return error.SkipZigTest;
328323
329324 const S = struct {
......@@ -395,7 +390,6 @@ test "extern function used as generic parameter" {
395390
396391test "generic struct as parameter type" {
397392 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
398 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
399393
400394 const S = struct {
401395 fn doTheTest(comptime Int: type, thing: struct { int: Int }) !void {
......@@ -436,7 +430,6 @@ test "null sentinel pointer passed as generic argument" {
436430
437431test "generic function passed as comptime argument" {
438432 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
439 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
440433
441434 const S = struct {
442435 fn doMath(comptime f: fn (type, i32, i32) error{Overflow}!i32, a: i32, b: i32) !void {
......@@ -449,7 +442,6 @@ test "generic function passed as comptime argument" {
449442
450443test "return type of generic function is function pointer" {
451444 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
452 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
453445
454446 const S = struct {
455447 fn b(comptime T: type) ?*const fn () error{}!T {
......@@ -462,7 +454,6 @@ test "return type of generic function is function pointer" {
462454
463455test "coerced function body has inequal value with its uncoerced body" {
464456 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
465 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
466457
467458 const S = struct {
468459 const A = B(i32, c);
......@@ -547,7 +538,6 @@ test "call generic function with from function called by the generic function" {
547538 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
548539 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
549540 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
550 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
551541 if (builtin.zig_backend == .stage2_llvm and
552542 builtin.cpu.arch == .aarch64 and builtin.os.tag == .windows) return error.SkipZigTest;
553543
test/behavior/globals.zig-2
......@@ -7,7 +7,6 @@ test "store to global array" {
77 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;
88 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
99 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
10 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
1110
1211 try expect(pos[1] == 0.0);
1312 pos = [2]f32{ 0.0, 1.0 };
......@@ -30,7 +29,6 @@ test "slices pointing at the same address as global array." {
3029 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
3130 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
3231 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
33 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
3432
3533 const S = struct {
3634 const a = [_]u8{ 1, 2, 3 };
test/behavior/if.zig-2
......@@ -45,7 +45,6 @@ var global_with_err: anyerror!u32 = error.SomeError;
4545
4646test "unwrap mutable global var" {
4747 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
48 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
4948
5049 if (global_with_val) |v| {
5150 try expect(v == 0);
......@@ -139,7 +138,6 @@ test "if-else expression with runtime condition result location is inferred opti
139138 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
140139 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
141140 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
142 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
143141
144142 const A = struct { b: u64, c: u64 };
145143 var d: bool = true;
test/behavior/incomplete_struct_param_tld.zig-1
......@@ -23,7 +23,6 @@ fn foo(a: A) i32 {
2323
2424test "incomplete struct param top level declaration" {
2525 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
26 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
2726
2827 const a = A{
2928 .b = B{
test/behavior/inline_switch.zig-8
......@@ -5,7 +5,6 @@ const builtin = @import("builtin");
55test "inline scalar prongs" {
66 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
77 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
8 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
98
109 var x: usize = 0;
1110 switch (x) {
......@@ -21,7 +20,6 @@ test "inline scalar prongs" {
2120test "inline prong ranges" {
2221 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
2322 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
24 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
2523
2624 var x: usize = 0;
2725 _ = &x;
......@@ -37,7 +35,6 @@ const E = enum { a, b, c, d };
3735test "inline switch enums" {
3836 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
3937 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
40 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
4138
4239 var x: E = .a;
4340 _ = &x;
......@@ -79,7 +76,6 @@ test "inline switch unions" {
7976test "inline else bool" {
8077 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
8178 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
82 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
8379
8480 var a = true;
8581 _ = &a;
......@@ -92,7 +88,6 @@ test "inline else bool" {
9288test "inline else error" {
9389 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
9490 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
95 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
9691
9792 const Err = error{ a, b, c };
9893 var a = Err.a;
......@@ -106,7 +101,6 @@ test "inline else error" {
106101test "inline else enum" {
107102 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
108103 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
109 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
110104
111105 const E2 = enum(u8) { a = 2, b = 3, c = 4, d = 5 };
112106 var a: E2 = .a;
......@@ -120,7 +114,6 @@ test "inline else enum" {
120114test "inline else int with gaps" {
121115 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
122116 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
123 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
124117
125118 var a: u8 = 0;
126119 _ = &a;
......@@ -139,7 +132,6 @@ test "inline else int with gaps" {
139132test "inline else int all values" {
140133 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
141134 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
142 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
143135
144136 var a: u2 = 0;
145137 _ = &a;
test/behavior/ir_block_deps.zig-1
......@@ -21,7 +21,6 @@ test "ir block deps" {
2121 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
2222 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
2323 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
24 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
2524
2625 try expect((foo(1) catch unreachable) == 0);
2726 try expect((foo(2) catch unreachable) == 0);
test/behavior/lower_strlit_to_vector.zig-1
......@@ -6,7 +6,6 @@ test "strlit to vector" {
66 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
77 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
88 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
9 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
109
1110 const strlit = "0123456789abcdef0123456789ABCDEF";
1211 const vec_from_strlit: @Vector(32, u8) = strlit.*;
test/behavior/math.zig-14
......@@ -236,7 +236,6 @@ test "float equality" {
236236 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
237237 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
238238 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
239 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
240239
241240 const x: f64 = 0.012;
242241 const y: f64 = x + 1.0;
......@@ -593,8 +592,6 @@ fn testSignedWrappingEval(x: i32) !void {
593592}
594593
595594test "signed negation wrapping" {
596 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
597
598595 try testSignedNegationWrappingEval(minInt(i16));
599596 try comptime testSignedNegationWrappingEval(minInt(i16));
600597}
......@@ -605,8 +602,6 @@ fn testSignedNegationWrappingEval(x: i16) !void {
605602}
606603
607604test "unsigned negation wrapping" {
608 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
609
610605 try testUnsignedNegationWrappingEval(1);
611606 try comptime testUnsignedNegationWrappingEval(1);
612607}
......@@ -667,8 +662,6 @@ test "bit shift a u1" {
667662}
668663
669664test "truncating shift right" {
670 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
671
672665 try testShrTrunc(maxInt(u16));
673666 try comptime testShrTrunc(maxInt(u16));
674667}
......@@ -1436,8 +1429,6 @@ test "quad hex float literal parsing accurate" {
14361429}
14371430
14381431test "truncating shift left" {
1439 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
1440
14411432 try testShlTrunc(maxInt(u16));
14421433 try comptime testShlTrunc(maxInt(u16));
14431434}
......@@ -1460,8 +1451,6 @@ fn testShlExact(x: u8) !void {
14601451}
14611452
14621453test "exact shift right" {
1463 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
1464
14651454 try testShrExact(0b10110100);
14661455 try comptime testShrExact(0b10110100);
14671456}
......@@ -1471,8 +1460,6 @@ fn testShrExact(x: u8) !void {
14711460}
14721461
14731462test "shift left/right on u0 operand" {
1474 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
1475
14761463 const S = struct {
14771464 fn doTheTest() !void {
14781465 var x: u0 = 0;
......@@ -1821,7 +1808,6 @@ test "absFloat" {
18211808 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
18221809 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
18231810 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1824 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
18251811
18261812 try testAbsFloat();
18271813 try comptime testAbsFloat();
test/behavior/member_func.zig-2
......@@ -31,7 +31,6 @@ test "standard field calls" {
3131 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
3232 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
3333 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
34 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
3534
3635 try expect(HasFuncs.one(0) == 1);
3736 try expect(HasFuncs.two(0) == 2);
......@@ -76,7 +75,6 @@ test "@field field calls" {
7675 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
7776 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
7877 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
79 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
8078
8179 try expect(@field(HasFuncs, "one")(0) == 1);
8280 try expect(@field(HasFuncs, "two")(0) == 2);
test/behavior/memset.zig-5
......@@ -7,7 +7,6 @@ test "@memset on array pointers" {
77 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
88 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;
99 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
10 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
1110
1211 try testMemsetArray();
1312 try comptime testMemsetArray();
......@@ -73,7 +72,6 @@ test "memset with bool element" {
7372 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
7473 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;
7574 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
76 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
7775
7876 var buf: [5]bool = undefined;
7977 @memset(&buf, true);
......@@ -86,7 +84,6 @@ test "memset with 1-byte struct element" {
8684 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
8785 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;
8886 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
89 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
9087
9188 const S = struct { x: bool };
9289 var buf: [5]S = undefined;
......@@ -100,7 +97,6 @@ test "memset with 1-byte array element" {
10097 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
10198 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;
10299 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
103 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
104100
105101 const A = [1]bool;
106102 var buf: [5]A = undefined;
......@@ -170,7 +166,6 @@ test "zero keys with @memset" {
170166 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
171167 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
172168 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
173 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
174169
175170 const Keys = struct {
176171 up: bool,
test/behavior/merge_error_sets.zig-1
......@@ -13,7 +13,6 @@ fn foo() C!void {
1313
1414test "merge error sets" {
1515 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
16 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
1716
1817 if (foo()) {
1918 @panic("unexpected");
test/behavior/nan.zig-1
......@@ -26,7 +26,6 @@ test "nan memory equality" {
2626 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
2727 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
2828 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
29 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
3029
3130 // signaled
3231 try testing.expect(mem.eql(u8, mem.asBytes(&snan_u16), mem.asBytes(&snan_f16)));
test/behavior/null.zig-3
......@@ -85,7 +85,6 @@ fn testTestNullRuntime(x: ?i32) !void {
8585test "optional void" {
8686 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
8787 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
88 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
8988
9089 try optionalVoidImpl();
9190 try comptime optionalVoidImpl();
......@@ -109,7 +108,6 @@ const Empty = struct {};
109108test "optional struct{}" {
110109 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
111110 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
112 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
113111
114112 _ = try optionalEmptyStructImpl();
115113 _ = try comptime optionalEmptyStructImpl();
......@@ -135,7 +133,6 @@ test "null with default unwrap" {
135133
136134test "optional pointer to 0 bit type null value at runtime" {
137135 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
138 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
139136
140137 const EmptyStruct = struct {};
141138 var x: ?*EmptyStruct = null;
test/behavior/optional.zig-10
......@@ -29,7 +29,6 @@ pub const EmptyStruct = struct {};
2929
3030test "optional pointer to size zero struct" {
3131 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
32 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
3332
3433 var e = EmptyStruct{};
3534 const o: ?*EmptyStruct = &e;
......@@ -60,7 +59,6 @@ fn testNullPtrsEql() !void {
6059test "optional with zero-bit type" {
6160 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
6261 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
63 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
6462 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
6563
6664 const S = struct {
......@@ -241,7 +239,6 @@ test "compare optionals with modified payloads" {
241239test "unwrap function call with optional pointer return value" {
242240 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
243241 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
244 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
245242
246243 const S = struct {
247244 fn entry() !void {
......@@ -373,7 +370,6 @@ test "0-bit child type coerced to optional return ptr result location" {
373370test "0-bit child type coerced to optional" {
374371 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
375372 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
376 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
377373
378374 const S = struct {
379375 fn doTheTest() !void {
......@@ -492,7 +488,6 @@ const NoReturn = struct {
492488
493489test "optional of noreturn used with if" {
494490 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
495 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
496491
497492 NoReturn.a = 64;
498493 if (NoReturn.loop()) |_| {
......@@ -504,7 +499,6 @@ test "optional of noreturn used with if" {
504499
505500test "optional of noreturn used with orelse" {
506501 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
507 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
508502
509503 NoReturn.a = 64;
510504 const val = NoReturn.testOrelse();
......@@ -601,7 +595,6 @@ test "cast slice to const slice nested in error union and optional" {
601595 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
602596 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
603597 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
604 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
605598
606599 const S = struct {
607600 fn inner() !?[]u8 {
......@@ -615,8 +608,6 @@ test "cast slice to const slice nested in error union and optional" {
615608}
616609
617610test "variable of optional of noreturn" {
618 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
619
620611 var null_opv: ?noreturn = null;
621612 _ = &null_opv;
622613 try std.testing.expectEqual(@as(?noreturn, null), null_opv);
......@@ -641,7 +632,6 @@ test "result location initialization of optional with OPV payload" {
641632 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
642633 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
643634 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
644 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
645635 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
646636
647637 const S = struct {
test/behavior/packed-struct.zig-4
......@@ -238,7 +238,6 @@ test "regular in irregular packed struct" {
238238 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
239239 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
240240 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
241 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
242241
243242 const Irregular = packed struct {
244243 bar: Regular = Regular{},
......@@ -494,7 +493,6 @@ test "@intFromPtr on a packed struct field" {
494493 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
495494 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
496495 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
497 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
498496 if (native_endian != .little) return error.SkipZigTest;
499497
500498 const S = struct {
......@@ -518,7 +516,6 @@ test "@intFromPtr on a packed struct field unaligned and nested" {
518516 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
519517 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
520518 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
521 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
522519 if (native_endian != .little) return error.SkipZigTest; // Byte aligned packed struct field pointers have not been implemented yet
523520
524521 const S1 = packed struct {
......@@ -1191,7 +1188,6 @@ test "packed struct field pointer aligned properly" {
11911188 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
11921189 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
11931190 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; // TODO
1194 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
11951191
11961192 const Foo = packed struct {
11971193 a: i32,
test/behavior/pointers.zig-6
......@@ -174,7 +174,6 @@ test "implicit cast error unions with non-optional to optional pointer" {
174174 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
175175 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
176176 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
177 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
178177
179178 const S = struct {
180179 fn doTheTest() !void {
......@@ -202,7 +201,6 @@ test "allowzero pointer and slice" {
202201 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
203202 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
204203 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
205 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
206204
207205 var ptr: [*]allowzero i32 = @ptrFromInt(0);
208206 const opt_ptr: ?[*]allowzero i32 = ptr;
......@@ -222,7 +220,6 @@ test "assign null directly to C pointer and test null equality" {
222220 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
223221 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
224222 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
225 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
226223
227224 var x: [*c]i32 = null;
228225 _ = &x;
......@@ -442,7 +439,6 @@ test "indexing array with sentinel returns correct type" {
442439test "element pointer to slice" {
443440 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
444441 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
445 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
446442
447443 const S = struct {
448444 fn doTheTest() !void {
......@@ -490,7 +486,6 @@ test "element pointer arithmetic to slice" {
490486
491487test "array slicing to slice" {
492488 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
493 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
494489
495490 const S = struct {
496491 fn doTheTest() !void {
......@@ -541,7 +536,6 @@ test "pointer alignment and element type include call expression" {
541536
542537test "pointer to array has explicit alignment" {
543538 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
544 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
545539
546540 const S = struct {
547541 const Base = extern struct { a: u8 };
test/behavior/prefetch.zig-1
......@@ -3,7 +3,6 @@ const std = @import("std");
33
44test "@prefetch()" {
55 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
6 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
76
87 var a: [2]u32 = .{ 42, 42 };
98 var a_len = a.len;
test/behavior/ptrcast.zig-3
......@@ -58,7 +58,6 @@ fn testReinterpretStructWrappedBytesAsInteger() !void {
5858test "reinterpret bytes of an array into an extern struct" {
5959 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
6060 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
61 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
6261
6362 try testReinterpretBytesAsExternStruct();
6463 try comptime testReinterpretBytesAsExternStruct();
......@@ -233,7 +232,6 @@ test "implicit optional pointer to optional anyopaque pointer" {
233232 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
234233 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
235234 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
236 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
237235
238236 var buf: [4]u8 = "aoeu".*;
239237 const x: ?[*]u8 = &buf;
......@@ -246,7 +244,6 @@ test "@ptrCast slice to slice" {
246244 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
247245 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
248246 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
249 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
250247
251248 const S = struct {
252249 fn foo(slice: []u32) []i32 {
test/behavior/ptrfromint.zig-5
......@@ -3,8 +3,6 @@ const builtin = @import("builtin");
33const expectEqual = std.testing.expectEqual;
44
55test "casting integer address to function pointer" {
6 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
7
86 addressToFunction();
97 comptime addressToFunction();
108}
......@@ -19,7 +17,6 @@ test "mutate through ptr initialized with constant ptrFromInt value" {
1917 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
2018 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
2119 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
22 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
2320
2421 forceCompilerAnalyzeBranchHardCodedPtrDereference(false);
2522}
......@@ -37,7 +34,6 @@ test "@ptrFromInt creates null pointer" {
3734 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
3835 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
3936 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
40 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
4137
4238 const ptr = @as(?*u32, @ptrFromInt(0));
4339 try expectEqual(@as(?*u32, null), ptr);
......@@ -47,7 +43,6 @@ test "@ptrFromInt creates allowzero zero pointer" {
4743 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
4844 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
4945 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
50 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
5146
5247 const ptr = @as(*allowzero u32, @ptrFromInt(0));
5348 try expectEqual(@as(usize, 0), @intFromPtr(ptr));
test/behavior/ref_var_in_if_after_if_2nd_switch_prong.zig-1
......@@ -8,7 +8,6 @@ test "reference a variable in an if after an if in the 2nd switch prong" {
88 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
99 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1010 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
11 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
1211
1312 try foo(true, Num.Two, false, "aoeu");
1413 try expect(!ok);
test/behavior/return_address.zig-1
......@@ -10,7 +10,6 @@ test "return address" {
1010 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1111 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1212 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
13 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
1413
1514 _ = retAddr();
1615 // TODO: #14938
test/behavior/sizeof_and_typeof.zig-5
......@@ -81,7 +81,6 @@ const P = packed struct {
8181test "@offsetOf" {
8282 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
8383 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
84 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
8584
8685 // Packed structs have fixed memory layout
8786 try expect(@offsetOf(P, "a") == 0);
......@@ -158,7 +157,6 @@ test "@TypeOf() has no runtime side effects" {
158157
159158test "branching logic inside @TypeOf" {
160159 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
161 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
162160
163161 const S = struct {
164162 var data: i32 = 0;
......@@ -273,7 +271,6 @@ test "runtime instructions inside typeof in comptime only scope" {
273271 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
274272 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
275273 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
276 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
277274
278275 {
279276 var y: i8 = 2;
......@@ -330,7 +327,6 @@ test "peer type resolution with @TypeOf doesn't trigger dependency loop check" {
330327 if (builtin.zig_backend == .stage2_x86) return error.SkipZigTest; // TODO
331328 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
332329 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
333 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
334330
335331 const T = struct {
336332 next: @TypeOf(null, @as(*const @This(), undefined)),
......@@ -412,7 +408,6 @@ test "Extern function calls, dereferences and field access in @TypeOf" {
412408 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
413409 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
414410 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
415 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
416411
417412 const Test = struct {
418413 fn test_fn_1(a: c_long) @TypeOf(c_fopen("test", "r").*) {
test/behavior/slice.zig-20
......@@ -67,7 +67,6 @@ test "comptime slice of undefined pointer of length 0" {
6767
6868test "implicitly cast array of size 0 to slice" {
6969 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
70 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
7170
7271 var msg = [_]u8{};
7372 try assertLenIsZero(&msg);
......@@ -124,7 +123,6 @@ test "slice of type" {
124123
125124test "generic malloc free" {
126125 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
127 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
128126
129127 const a = memAlloc(u8, 10) catch unreachable;
130128 memFree(u8, a);
......@@ -186,8 +184,6 @@ test "slicing zero length array" {
186184}
187185
188186test "slicing pointer by length" {
189 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
190
191187 const array = [_]u8{ 1, 2, 3, 4, 5, 6, 7, 8 };
192188 const ptr: [*]const u8 = @as([*]const u8, @ptrCast(&array));
193189 const slice = ptr[1..][0..5];
......@@ -236,7 +232,6 @@ test "runtime safety lets us slice from len..len" {
236232 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
237233 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
238234 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
239 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
240235
241236 var an_array = [_]u8{ 1, 2, 3 };
242237 try expect(mem.eql(u8, sliceFromLenToLen(an_array[0..], 3, 3), ""));
......@@ -249,7 +244,6 @@ fn sliceFromLenToLen(a_slice: []u8, start: usize, end: usize) []u8 {
249244test "C pointer" {
250245 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
251246 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
252 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
253247
254248 var buf: [*c]const u8 = "kjdhfkjdhfdkjhfkfjhdfkjdhfkdjhfdkjhf";
255249 var len: u32 = 10;
......@@ -293,7 +287,6 @@ fn sliceSum(comptime q: []const u8) i32 {
293287test "slice type with custom alignment" {
294288 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
295289 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
296 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
297290
298291 const LazilyResolvedType = struct {
299292 anything: i32,
......@@ -307,7 +300,6 @@ test "slice type with custom alignment" {
307300
308301test "obtaining a null terminated slice" {
309302 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
310 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
311303
312304 // here we have a normal array
313305 var buf: [50]u8 = undefined;
......@@ -352,7 +344,6 @@ test "empty array to slice" {
352344test "@ptrCast slice to pointer" {
353345 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
354346 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
355 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
356347
357348 const S = struct {
358349 fn doTheTest() !void {
......@@ -407,7 +398,6 @@ test "slice syntax resulting in pointer-to-array" {
407398 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
408399 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
409400 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
410 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
411401 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
412402
413403 const S = struct {
......@@ -627,7 +617,6 @@ test "slice syntax resulting in pointer-to-array" {
627617test "slice pointer-to-array null terminated" {
628618 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
629619 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
630 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
631620
632621 comptime {
633622 var array = [5:0]u8{ 1, 2, 3, 4, 5 };
......@@ -646,7 +635,6 @@ test "slice pointer-to-array null terminated" {
646635
647636test "slice pointer-to-array zero length" {
648637 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
649 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
650638
651639 comptime {
652640 {
......@@ -681,7 +669,6 @@ test "type coercion of pointer to anon struct literal to pointer to slice" {
681669 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
682670 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
683671 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
684 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
685672
686673 const S = struct {
687674 const U = union {
......@@ -773,7 +760,6 @@ test "slice sentinel access at comptime" {
773760test "slicing array with sentinel as end index" {
774761 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
775762 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
776 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
777763
778764 const S = struct {
779765 fn do() !void {
......@@ -792,7 +778,6 @@ test "slicing array with sentinel as end index" {
792778test "slicing slice with sentinel as end index" {
793779 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
794780 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
795 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
796781
797782 const S = struct {
798783 fn do() !void {
......@@ -863,7 +848,6 @@ test "global slice field access" {
863848}
864849
865850test "slice of void" {
866 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
867851 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
868852
869853 var n: usize = 10;
......@@ -874,8 +858,6 @@ test "slice of void" {
874858}
875859
876860test "slice with dereferenced value" {
877 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
878
879861 var a: usize = 0;
880862 const idx: *usize = &a;
881863 _ = blk: {
......@@ -989,7 +971,6 @@ test "get address of element of zero-sized slice" {
989971 if (builtin.zig_backend == .stage2_x86) return error.SkipZigTest; // TODO
990972 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
991973 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
992 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
993974 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
994975
995976 const S = struct {
......@@ -1004,7 +985,6 @@ test "sentinel-terminated 0-length slices" {
1004985 if (builtin.zig_backend == .stage2_x86) return error.SkipZigTest; // TODO
1005986 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1006987 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1007 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
1008988
1009989 const u32s: [4]u32 = [_]u32{ 0, 1, 2, 3 };
1010990
test/behavior/struct.zig-40
......@@ -92,7 +92,6 @@ test "structs" {
9292 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
9393 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
9494 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
95 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
9695
9796 var foo: StructFoo = undefined;
9897 @memset(@as([*]u8, @ptrCast(&foo))[0..@sizeOf(StructFoo)], 0);
......@@ -111,7 +110,6 @@ fn testMutation(foo: *StructFoo) void {
111110
112111test "struct byval assign" {
113112 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
114 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
115113
116114 var foo1: StructFoo = undefined;
117115 var foo2: StructFoo = undefined;
......@@ -176,7 +174,6 @@ const MemberFnTestFoo = struct {
176174
177175test "call member function directly" {
178176 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
179 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
180177
181178 const instance = MemberFnTestFoo{ .x = 1234 };
182179 const result = MemberFnTestFoo.member(instance);
......@@ -185,7 +182,6 @@ test "call member function directly" {
185182
186183test "store member function in variable" {
187184 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
188 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
189185
190186 const instance = MemberFnTestFoo{ .x = 1234 };
191187 const memberFn = MemberFnTestFoo.member;
......@@ -207,7 +203,6 @@ const MemberFnRand = struct {
207203test "return struct byval from function" {
208204 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
209205 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
210 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
211206
212207 const Bar = struct {
213208 x: i32,
......@@ -256,7 +251,6 @@ test "usingnamespace within struct scope" {
256251test "struct field init with catch" {
257252 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
258253 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
259 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
260254
261255 const S = struct {
262256 fn doTheTest() !void {
......@@ -300,7 +294,6 @@ const Val = struct {
300294test "struct point to self" {
301295 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
302296 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
303 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
304297
305298 var root: Node = undefined;
306299 root.val.x = 1;
......@@ -355,7 +348,6 @@ test "self-referencing struct via array member" {
355348 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
356349 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
357350 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
358 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
359351
360352 const T = struct {
361353 children: [1]*@This(),
......@@ -403,7 +395,6 @@ test "packed struct" {
403395 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
404396 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
405397 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
406 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
407398
408399 var foo = APackedStruct{
409400 .x = 1,
......@@ -633,7 +624,6 @@ fn getC(data: *const BitField1) u2 {
633624test "default struct initialization fields" {
634625 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
635626 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
636 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
637627
638628 const S = struct {
639629 a: i32 = 1234,
......@@ -809,7 +799,6 @@ test "fn with C calling convention returns struct by value" {
809799 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
810800 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
811801 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
812 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
813802
814803 const S = struct {
815804 fn entry() !void {
......@@ -909,8 +898,6 @@ test "anonymous struct literal syntax" {
909898}
910899
911900test "fully anonymous struct" {
912 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
913
914901 const S = struct {
915902 fn doTheTest() !void {
916903 try dump(.{
......@@ -933,8 +920,6 @@ test "fully anonymous struct" {
933920}
934921
935922test "fully anonymous list literal" {
936 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
937
938923 const S = struct {
939924 fn doTheTest() !void {
940925 try dump(.{ @as(u32, 1234), @as(f64, 12.34), true, "hi" });
......@@ -982,7 +967,6 @@ test "tuple element initialized with fn call" {
982967 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
983968 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
984969 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
985 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
986970
987971 const S = struct {
988972 fn doTheTest() !void {
......@@ -1023,7 +1007,6 @@ test "struct with 0-length union array field" {
10231007 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
10241008 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
10251009 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1026 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
10271010
10281011 const U = union {
10291012 a: u32,
......@@ -1044,7 +1027,6 @@ test "type coercion of anon struct literal to struct" {
10441027 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
10451028 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
10461029 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
1047 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
10481030
10491031 const S = struct {
10501032 const S2 = struct {
......@@ -1084,7 +1066,6 @@ test "type coercion of pointer to anon struct literal to pointer to struct" {
10841066 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
10851067 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
10861068 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
1087 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
10881069
10891070 const S = struct {
10901071 const S2 = struct {
......@@ -1299,7 +1280,6 @@ test "initialize struct with empty literal" {
12991280
13001281test "loading a struct pointer perfoms a copy" {
13011282 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1302 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
13031283
13041284 const S = struct {
13051285 a: i32,
......@@ -1561,7 +1541,6 @@ test "discarded struct initialization works as expected" {
15611541test "function pointer in struct returns the struct" {
15621542 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
15631543 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
1564 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
15651544
15661545 const A = struct {
15671546 const A = @This();
......@@ -1732,7 +1711,6 @@ test "extern struct field pointer has correct alignment" {
17321711 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
17331712 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
17341713 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1735 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
17361714
17371715 const S = struct {
17381716 fn doTheTest() !void {
......@@ -1770,8 +1748,6 @@ test "extern struct field pointer has correct alignment" {
17701748}
17711749
17721750test "packed struct field in anonymous struct" {
1773 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
1774
17751751 const T = packed struct {
17761752 f1: bool = false,
17771753 };
......@@ -1783,8 +1759,6 @@ fn countFields(v: anytype) usize {
17831759}
17841760
17851761test "struct init with no result pointer sets field result types" {
1786 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
1787
17881762 const S = struct {
17891763 // A function parameter has a result type, but no result pointer.
17901764 fn f(s: struct { x: u32 }) u32 {
......@@ -1863,8 +1837,6 @@ test "comptimeness of optional and error union payload is analyzed properly" {
18631837}
18641838
18651839test "initializer uses own alignment" {
1866 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
1867
18681840 const S = struct {
18691841 x: u32 = @alignOf(@This()) + 1,
18701842 };
......@@ -1876,8 +1848,6 @@ test "initializer uses own alignment" {
18761848}
18771849
18781850test "initializer uses own size" {
1879 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
1880
18811851 const S = struct {
18821852 x: u32 = @sizeOf(@This()) + 1,
18831853 };
......@@ -1889,8 +1859,6 @@ test "initializer uses own size" {
18891859}
18901860
18911861test "initializer takes a pointer to a variable inside its struct" {
1892 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
1893
18941862 const namespace = struct {
18951863 const S = struct {
18961864 s: *S = &S.instance,
......@@ -1909,8 +1877,6 @@ test "initializer takes a pointer to a variable inside its struct" {
19091877}
19101878
19111879test "circular dependency through pointer field of a struct" {
1912 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
1913
19141880 const S = struct {
19151881 const StructInner = extern struct {
19161882 outer: StructOuter = std.mem.zeroes(StructOuter),
......@@ -1932,8 +1898,6 @@ test "circular dependency through pointer field of a struct" {
19321898}
19331899
19341900test "field calls do not force struct field init resolution" {
1935 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
1936
19371901 const S = struct {
19381902 x: u32 = blk: {
19391903 _ = @TypeOf(make().dummyFn()); // runtime field call - S not fully resolved - dummyFn call should not force field init resolution
......@@ -2067,7 +2031,6 @@ test "runtime value in nested initializer passed as pointer to function" {
20672031 if (builtin.zig_backend == .stage2_x86) return error.SkipZigTest; // TODO
20682032 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
20692033 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
2070 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
20712034
20722035 const Bar = struct {
20732036 b: u32,
......@@ -2142,7 +2105,6 @@ test "assignment of field with padding" {
21422105 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
21432106 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
21442107 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
2145 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
21462108
21472109 const Mesh = extern struct {
21482110 id: u32,
......@@ -2173,7 +2135,6 @@ test "initiate global variable with runtime value" {
21732135 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
21742136 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
21752137 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
2176 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
21772138
21782139 const S = struct {
21792140 field: i32,
......@@ -2192,7 +2153,6 @@ test "initiate global variable with runtime value" {
21922153test "struct containing optional pointer to array of @This()" {
21932154 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
21942155 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
2195 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
21962156
21972157 const S = struct {
21982158 x: ?*const [1]@This(),
test/behavior/struct_contains_null_ptr_itself.zig-1
......@@ -5,7 +5,6 @@ const builtin = @import("builtin");
55test "struct contains null pointer which contains original struct" {
66 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
77 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
8 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
98
109 var x: ?*NodeLineComment = null;
1110 _ = &x;
test/behavior/struct_contains_slice_of_itself.zig-2
......@@ -13,7 +13,6 @@ const NodeAligned = struct {
1313
1414test "struct contains slice of itself" {
1515 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
16 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
1716
1817 var other_nodes = [_]Node{
1918 Node{
......@@ -54,7 +53,6 @@ test "struct contains slice of itself" {
5453test "struct contains aligned slice of itself" {
5554 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
5655 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
57 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
5856
5957 var other_nodes = [_]NodeAligned{
6058 NodeAligned{
test/behavior/switch.zig+7-34
......@@ -7,7 +7,6 @@ const expectEqual = std.testing.expectEqual;
77
88test "switch with numbers" {
99 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
10 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
1110
1211 try testSwitchWithNumbers(13);
1312}
......@@ -23,7 +22,6 @@ fn testSwitchWithNumbers(x: u32) !void {
2322
2423test "switch with all ranges" {
2524 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
26 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
2725
2826 try expect(testSwitchWithAllRanges(50, 3) == 1);
2927 try expect(testSwitchWithAllRanges(101, 0) == 2);
......@@ -57,27 +55,25 @@ test "implicit comptime switch" {
5755
5856test "switch on enum" {
5957 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
60 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
6158
6259 const fruit = Fruit.Orange;
63 nonConstSwitchOnEnum(fruit);
60 try expect(nonConstSwitchOnEnum(fruit));
6461}
6562const Fruit = enum {
6663 Apple,
6764 Orange,
6865 Banana,
6966};
70fn nonConstSwitchOnEnum(fruit: Fruit) void {
71 switch (fruit) {
72 Fruit.Apple => unreachable,
73 Fruit.Orange => {},
74 Fruit.Banana => unreachable,
75 }
67fn nonConstSwitchOnEnum(fruit: Fruit) bool {
68 return switch (fruit) {
69 Fruit.Apple => false,
70 Fruit.Orange => true,
71 Fruit.Banana => false,
72 };
7673}
7774
7875test "switch statement" {
7976 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
80 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
8177
8278 try nonConstSwitch(SwitchStatementFoo.C);
8379}
......@@ -94,7 +90,6 @@ const SwitchStatementFoo = enum { A, B, C, D };
9490
9591test "switch with multiple expressions" {
9692 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
97 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
9893
9994 const x = switch (returnsFive()) {
10095 1, 2, 3 => 1,
......@@ -123,7 +118,6 @@ fn trueIfBoolFalseOtherwise(comptime T: type) bool {
123118
124119test "switching on booleans" {
125120 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
126 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
127121
128122 try testSwitchOnBools();
129123 try comptime testSwitchOnBools();
......@@ -179,7 +173,6 @@ test "undefined.u0" {
179173
180174test "switch with disjoint range" {
181175 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
182 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
183176
184177 var q: u8 = 0;
185178 _ = &q;
......@@ -191,8 +184,6 @@ test "switch with disjoint range" {
191184}
192185
193186test "switch variable for range and multiple prongs" {
194 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
195
196187 const S = struct {
197188 fn doTheTest() !void {
198189 try doTheSwitch(16);
......@@ -224,7 +215,6 @@ fn poll() void {
224215
225216test "switch on global mutable var isn't constant-folded" {
226217 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
227 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
228218
229219 while (state < 2) {
230220 poll();
......@@ -286,7 +276,6 @@ fn testSwitchEnumPtrCapture() !void {
286276
287277test "switch handles all cases of number" {
288278 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
289 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
290279
291280 try testSwitchHandleAllCases();
292281 try comptime testSwitchHandleAllCases();
......@@ -382,7 +371,6 @@ test "anon enum literal used in switch on union enum" {
382371
383372test "switch all prongs unreachable" {
384373 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
385 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
386374
387375 try testAllProngsUnreachable();
388376 try comptime testAllProngsUnreachable();
......@@ -406,7 +394,6 @@ fn switchWithUnreachable(x: i32) i32 {
406394
407395test "capture value of switch with all unreachable prongs" {
408396 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
409 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
410397
411398 const x = return_a_number() catch |err| switch (err) {
412399 else => unreachable,
......@@ -420,7 +407,6 @@ fn return_a_number() anyerror!i32 {
420407
421408test "switch on integer with else capturing expr" {
422409 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
423 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
424410
425411 const S = struct {
426412 fn doTheTest() !void {
......@@ -442,7 +428,6 @@ test "else prong of switch on error set excludes other cases" {
442428 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
443429 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
444430 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
445 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
446431
447432 const S = struct {
448433 fn doTheTest() !void {
......@@ -478,7 +463,6 @@ test "switch prongs with error set cases make a new error set type for capture v
478463 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
479464 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
480465 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
481 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
482466
483467 const S = struct {
484468 fn doTheTest() !void {
......@@ -513,7 +497,6 @@ test "switch prongs with error set cases make a new error set type for capture v
513497
514498test "return result loc and then switch with range implicit casted to error union" {
515499 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
516 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
517500
518501 const S = struct {
519502 fn doTheTest() !void {
......@@ -662,7 +645,6 @@ test "switch prong pointer capture alignment" {
662645test "switch on pointer type" {
663646 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
664647 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
665 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
666648
667649 const S = struct {
668650 const X = struct {
......@@ -735,7 +717,6 @@ test "switch capture copies its payload" {
735717
736718test "capture of integer forwards the switch condition directly" {
737719 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
738 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
739720
740721 const S = struct {
741722 fn foo(x: u8) !void {
......@@ -757,7 +738,6 @@ test "capture of integer forwards the switch condition directly" {
757738
758739test "enum value without tag name used as switch item" {
759740 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
760 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
761741
762742 const E = enum(u32) {
763743 a = 1,
......@@ -775,8 +755,6 @@ test "enum value without tag name used as switch item" {
775755}
776756
777757test "switch item sizeof" {
778 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
779
780758 const S = struct {
781759 fn doTheTest() !void {
782760 var a: usize = 0;
......@@ -873,8 +851,6 @@ test "switch pointer capture peer type resolution" {
873851}
874852
875853test "inline switch range that includes the maximum value of the switched type" {
876 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
877
878854 const inputs: [3]u8 = .{ 0, 254, 255 };
879855 for (inputs) |input| {
880856 switch (input) {
......@@ -933,7 +909,6 @@ test "peer type resolution on switch captures ignores unused payload bits" {
933909test "switch prong captures range" {
934910 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
935911 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
936 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
937912
938913 const S = struct {
939914 fn a(b: []u3, c: u3) void {
......@@ -970,8 +945,6 @@ test "prong with inline call to unreachable" {
970945}
971946
972947test "block error return trace index is reset between prongs" {
973 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
974
975948 const S = struct {
976949 fn returnError() error{TestFailed} {
977950 return error.TestFailed;
test/behavior/this.zig-1
......@@ -51,7 +51,6 @@ test "this used as optional function parameter" {
5151 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
5252 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
5353 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
54 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
5554
5655 var global: State = undefined;
5756 global.enter = prev;
test/behavior/try.zig-2
......@@ -4,7 +4,6 @@ const expect = std.testing.expect;
44
55test "try on error union" {
66 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
7 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
87
98 try tryOnErrorUnionImpl();
109 try comptime tryOnErrorUnionImpl();
......@@ -52,7 +51,6 @@ test "`try`ing an if/else expression" {
5251 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
5352 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
5453 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
55 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
5654
5755 const S = struct {
5856 fn getError() !void {
test/behavior/tuple.zig-8
......@@ -10,7 +10,6 @@ test "tuple concatenation" {
1010 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1111 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1212 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
13 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
1413
1514 const S = struct {
1615 fn doTheTest() !void {
......@@ -56,7 +55,6 @@ test "more tuple concatenation" {
5655 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
5756 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
5857 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
59 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
6058
6159 const T = struct {
6260 fn consume_tuple(tuple: anytype, len: usize) !void {
......@@ -326,8 +324,6 @@ test "tuple type with void field" {
326324}
327325
328326test "zero sized struct in tuple handled correctly" {
329 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
330
331327 const State = struct {
332328 const Self = @This();
333329 data: @Type(.{
......@@ -369,7 +365,6 @@ test "branching inside tuple literal" {
369365 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
370366 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
371367 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
372 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
373368
374369 const S = struct {
375370 fn foo(a: anytype) !void {
......@@ -474,7 +469,6 @@ test "coerce anon tuple to tuple" {
474469 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
475470 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
476471 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
477 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
478472
479473 var x: u8 = 1;
480474 var y: u16 = 2;
......@@ -579,8 +573,6 @@ test "comptime fields in tuple can be initialized" {
579573}
580574
581575test "tuple default values" {
582 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
583
584576 const T = struct {
585577 usize,
586578 usize = 123,
test/behavior/type.zig-2
......@@ -203,7 +203,6 @@ test "Type.Opaque" {
203203 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
204204 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
205205 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
206 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
207206
208207 const Opaque = @Type(.{
209208 .Opaque = .{
......@@ -261,7 +260,6 @@ test "Type.Struct" {
261260 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
262261 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
263262 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
264 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
265263
266264 const A = @Type(@typeInfo(struct { x: u8, y: u32 }));
267265 const infoA = @typeInfo(A).Struct;
test/behavior/undefined.zig-1
......@@ -91,7 +91,6 @@ test "reslice of undefined global var slice" {
9191 if (builtin.zig_backend == .stage2_x86) return error.SkipZigTest; // TODO
9292 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
9393 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
94 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
9594
9695 var stack_buf: [100]u8 = [_]u8{0} ** 100;
9796 buf = &stack_buf;
test/behavior/underscore.zig-1
......@@ -8,7 +8,6 @@ test "ignore lval with underscore" {
88
99test "ignore lval with underscore (while loop)" {
1010 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
11 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
1211
1312 while (optionalReturnError()) |_| {
1413 while (optionalReturnError()) |_| {
test/behavior/union.zig-8
......@@ -418,7 +418,6 @@ test "tagged union initialization with runtime void" {
418418 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
419419 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
420420 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
421 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
422421
423422 try expect(testTaggedUnionInit({}));
424423}
......@@ -1744,7 +1743,6 @@ test "union with 128 bit integer" {
17441743
17451744test "memset extern union" {
17461745 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
1747 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
17481746
17491747 const U = extern union {
17501748 foo: u8,
......@@ -1766,7 +1764,6 @@ test "memset extern union" {
17661764
17671765test "memset packed union" {
17681766 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
1769 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
17701767
17711768 const U = packed union {
17721769 a: u32,
......@@ -1977,8 +1974,6 @@ test "reinterpret packed union inside packed struct" {
19771974}
19781975
19791976test "inner struct initializer uses union layout" {
1980 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
1981
19821977 const namespace = struct {
19831978 const U = union {
19841979 a: struct {
......@@ -2004,7 +1999,6 @@ test "inner struct initializer uses union layout" {
20041999
20052000test "inner struct initializer uses packed union layout" {
20062001 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
2007 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
20082002
20092003 const namespace = struct {
20102004 const U = packed union {
......@@ -2031,7 +2025,6 @@ test "inner struct initializer uses packed union layout" {
20312025
20322026test "extern union initialized via reintepreted struct field initializer" {
20332027 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
2034 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
20352028
20362029 const bytes = [_]u8{ 0xaa, 0xbb, 0xcc, 0xdd };
20372030
......@@ -2155,7 +2148,6 @@ test "pass register-sized field as non-register-sized union" {
21552148
21562149test "circular dependency through pointer field of a union" {
21572150 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
2158 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
21592151
21602152 const S = struct {
21612153 const UnionInner = extern struct {
test/behavior/var_args.zig-10
......@@ -14,8 +14,6 @@ fn add(args: anytype) i32 {
1414}
1515
1616test "add arbitrary args" {
17 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
18
1917 try expect(add(.{ @as(i32, 1), @as(i32, 2), @as(i32, 3), @as(i32, 4) }) == 10);
2018 try expect(add(.{@as(i32, 1234)}) == 1234);
2119 try expect(add(.{}) == 0);
......@@ -26,15 +24,12 @@ fn readFirstVarArg(args: anytype) void {
2624}
2725
2826test "send void arg to var args" {
29 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
30
3127 readFirstVarArg(.{{}});
3228}
3329
3430test "pass args directly" {
3531 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
3632 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
37 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
3833
3934 try expect(addSomeStuff(.{ @as(i32, 1), @as(i32, 2), @as(i32, 3), @as(i32, 4) }) == 10);
4035 try expect(addSomeStuff(.{@as(i32, 1234)}) == 1234);
......@@ -48,7 +43,6 @@ fn addSomeStuff(args: anytype) i32 {
4843test "runtime parameter before var args" {
4944 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
5045 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
51 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
5246
5347 try expect((try extraFn(10, .{})) == 0);
5448 try expect((try extraFn(10, .{false})) == 1);
......@@ -87,15 +81,11 @@ fn foo2(args: anytype) bool {
8781}
8882
8983test "array of var args functions" {
90 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
91
9284 try expect(foos[0](.{}));
9385 try expect(!foos[1](.{}));
9486}
9587
9688test "pass zero length array to var args param" {
97 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
98
9989 doNothingWithFirstArg(.{""});
10090}
10191
test/behavior/vector.zig+1-1
......@@ -166,7 +166,6 @@ test "array to vector" {
166166 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
167167 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
168168 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
169 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
170169
171170 const S = struct {
172171 fn doTheTest() !void {
......@@ -434,6 +433,7 @@ test "load vector elements via runtime index" {
434433 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
435434 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
436435 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
436 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
437437
438438 const S = struct {
439439 fn doTheTest() !void {
test/behavior/void.zig-1
......@@ -37,7 +37,6 @@ test "void optional" {
3737 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
3838 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
3939 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
40 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
4140
4241 var x: ?void = {};
4342 _ = &x;
test/behavior/while.zig-4
......@@ -258,7 +258,6 @@ fn returnWithImplicitCastFromWhileLoopTest() anyerror!void {
258258
259259test "while on error union with else result follow else prong" {
260260 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
261 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
262261
263262 const result = while (returnError()) |value| {
264263 break value;
......@@ -268,7 +267,6 @@ test "while on error union with else result follow else prong" {
268267
269268test "while on error union with else result follow break prong" {
270269 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
271 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
272270
273271 const result = while (returnSuccess(10)) |value| {
274272 break value;
......@@ -315,7 +313,6 @@ test "while error 2 break statements and an else" {
315313 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
316314 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
317315 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
318 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
319316
320317 const S = struct {
321318 fn entry(opt_t: anyerror!bool, f: bool) !void {
......@@ -382,7 +379,6 @@ test "while loop with comptime true condition needs no else block to return valu
382379test "int returned from switch in while" {
383380 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
384381 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
385 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
386382
387383 var x: u32 = 3;
388384 const val: usize = while (true) switch (x) {
test/behavior/widening.zig-2
......@@ -32,7 +32,6 @@ test "implicit unsigned integer to signed integer" {
3232 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
3333 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
3434 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
35 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
3635
3736 var a: u8 = 250;
3837 var b: i16 = a;
......@@ -80,7 +79,6 @@ test "cast small unsigned to larger signed" {
8079 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
8180 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
8281 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
83 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
8482
8583 try expect(castSmallUnsignedToLargerSigned1(200) == @as(i16, 200));
8684 try expect(castSmallUnsignedToLargerSigned2(9999) == @as(i64, 9999));